@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
package/src/utils/flow.ts
CHANGED
|
@@ -1,6 +1,89 @@
|
|
|
1
1
|
import * as fs from 'fs';
|
|
2
2
|
import * as path from 'path';
|
|
3
3
|
import { safeJoin } from './path';
|
|
4
|
+
import { FlowInfo, FlowStatus } from '../types/flow';
|
|
5
|
+
import { CursorFlowConfig } from './config';
|
|
6
|
+
import { TaskService } from './task-service';
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* List all flows in a directory
|
|
10
|
+
*/
|
|
11
|
+
export function listFlows(flowsDir: string): FlowInfo[] {
|
|
12
|
+
if (!fs.existsSync(flowsDir)) {
|
|
13
|
+
return [];
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
const dirs = fs.readdirSync(flowsDir)
|
|
17
|
+
.filter(name => {
|
|
18
|
+
const dirPath = safeJoin(flowsDir, name);
|
|
19
|
+
try {
|
|
20
|
+
return fs.statSync(dirPath).isDirectory() && !name.startsWith('.');
|
|
21
|
+
} catch {
|
|
22
|
+
return false;
|
|
23
|
+
}
|
|
24
|
+
})
|
|
25
|
+
.sort((a, b) => b.localeCompare(a)); // Most recent first
|
|
26
|
+
|
|
27
|
+
return dirs.map(name => {
|
|
28
|
+
const flowPath = safeJoin(flowsDir, name);
|
|
29
|
+
const metaPath = safeJoin(flowPath, 'flow.meta.json');
|
|
30
|
+
|
|
31
|
+
let meta: any = null;
|
|
32
|
+
try {
|
|
33
|
+
if (fs.existsSync(metaPath)) {
|
|
34
|
+
meta = JSON.parse(fs.readFileSync(metaPath, 'utf-8'));
|
|
35
|
+
}
|
|
36
|
+
} catch {}
|
|
37
|
+
|
|
38
|
+
// Parse flow name from directory (e.g., "001_TestFeature" -> "TestFeature")
|
|
39
|
+
const match = name.match(/^(\d+)_(.+)$/);
|
|
40
|
+
const id = match ? match[1] : name;
|
|
41
|
+
const flowName = match ? match[2] : name;
|
|
42
|
+
|
|
43
|
+
// Get lane files
|
|
44
|
+
const laneFiles = fs.readdirSync(flowPath)
|
|
45
|
+
.filter(f => f.endsWith('.json') && f !== 'flow.meta.json')
|
|
46
|
+
.map(f => {
|
|
47
|
+
const laneMatch = f.match(/^\d+-([^.]+)\.json$/);
|
|
48
|
+
return laneMatch ? laneMatch[1] : f.replace('.json', '');
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
return {
|
|
52
|
+
id,
|
|
53
|
+
name: flowName,
|
|
54
|
+
path: flowPath,
|
|
55
|
+
timestamp: meta?.createdAt ? new Date(meta.createdAt) : new Date(fs.statSync(flowPath).mtime),
|
|
56
|
+
lanes: laneFiles,
|
|
57
|
+
status: (meta?.status as FlowStatus) || 'pending',
|
|
58
|
+
meta: meta || undefined,
|
|
59
|
+
};
|
|
60
|
+
});
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* Find the most recently created flow or legacy task directory
|
|
65
|
+
*/
|
|
66
|
+
export function findLatestFlowOrTask(config: CursorFlowConfig): string | null {
|
|
67
|
+
const flowsDir = safeJoin(config.projectRoot, config.flowsDir);
|
|
68
|
+
const tasksDir = safeJoin(config.projectRoot, config.tasksDir);
|
|
69
|
+
|
|
70
|
+
const flows = listFlows(flowsDir);
|
|
71
|
+
|
|
72
|
+
const taskService = new TaskService(tasksDir);
|
|
73
|
+
const tasks = taskService.listTaskDirs();
|
|
74
|
+
|
|
75
|
+
const latestFlow = flows.length > 0 ? flows[0] : null;
|
|
76
|
+
const latestTask = tasks.length > 0 ? tasks[0] : null;
|
|
77
|
+
|
|
78
|
+
if (!latestFlow && !latestTask) return null;
|
|
79
|
+
if (!latestFlow) return latestTask!.path;
|
|
80
|
+
if (!latestTask) return latestFlow!.path;
|
|
81
|
+
|
|
82
|
+
// Compare by timestamp to find the truly latest
|
|
83
|
+
return latestFlow.timestamp.getTime() >= latestTask.timestamp.getTime()
|
|
84
|
+
? latestFlow.path
|
|
85
|
+
: latestTask.path;
|
|
86
|
+
}
|
|
4
87
|
|
|
5
88
|
/**
|
|
6
89
|
* Find flow directory by name in the flows directory.
|
|
@@ -40,3 +123,4 @@ export function findFlowDir(flowsDir: string, flowName: string): string | null {
|
|
|
40
123
|
}
|
|
41
124
|
|
|
42
125
|
|
|
126
|
+
|
package/src/utils/git.ts
CHANGED
|
@@ -265,7 +265,7 @@ export function isGitRepo(cwd?: string): boolean {
|
|
|
265
265
|
}
|
|
266
266
|
|
|
267
267
|
/**
|
|
268
|
-
* Check if worktree exists
|
|
268
|
+
* Check if worktree exists in Git's worktree list
|
|
269
269
|
*/
|
|
270
270
|
export function worktreeExists(worktreePath: string, cwd?: string): boolean {
|
|
271
271
|
const result = runGitResult(['worktree', 'list'], { cwd });
|
|
@@ -274,6 +274,64 @@ export function worktreeExists(worktreePath: string, cwd?: string): boolean {
|
|
|
274
274
|
return result.stdout.includes(worktreePath);
|
|
275
275
|
}
|
|
276
276
|
|
|
277
|
+
/**
|
|
278
|
+
* Check if a directory is a valid Git worktree (not just a regular directory)
|
|
279
|
+
* This prevents accidental checkout in the main repository when the worktree
|
|
280
|
+
* directory exists but is not properly registered as a worktree.
|
|
281
|
+
*/
|
|
282
|
+
export function isValidWorktree(dirPath: string): boolean {
|
|
283
|
+
// 1. Directory must exist
|
|
284
|
+
if (!fs.existsSync(dirPath)) {
|
|
285
|
+
return false;
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
// 2. Check if Git recognizes this as a worktree by checking .git file
|
|
289
|
+
// In a worktree, .git is a file (not a directory) pointing to the main repo's .git/worktrees/
|
|
290
|
+
const dotGitPath = path.join(dirPath, '.git');
|
|
291
|
+
if (!fs.existsSync(dotGitPath)) {
|
|
292
|
+
return false;
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
try {
|
|
296
|
+
const stat = fs.statSync(dotGitPath);
|
|
297
|
+
|
|
298
|
+
// In worktrees, .git is a FILE containing "gitdir: /path/to/.git/worktrees/..."
|
|
299
|
+
// In the main repo, .git is a DIRECTORY
|
|
300
|
+
if (stat.isDirectory()) {
|
|
301
|
+
// This is the main repository, not a worktree
|
|
302
|
+
return false;
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
// Read the .git file to verify it points to a valid worktree
|
|
306
|
+
const content = fs.readFileSync(dotGitPath, 'utf8').trim();
|
|
307
|
+
if (!content.startsWith('gitdir:')) {
|
|
308
|
+
return false;
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
// Verify the gitdir path exists
|
|
312
|
+
const gitdirPath = content.replace('gitdir:', '').trim();
|
|
313
|
+
return fs.existsSync(gitdirPath);
|
|
314
|
+
} catch {
|
|
315
|
+
return false;
|
|
316
|
+
}
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
/**
|
|
320
|
+
* Remove a directory that was supposed to be a worktree but isn't valid
|
|
321
|
+
* Used to clean up orphaned/corrupted worktree directories before recreation
|
|
322
|
+
*/
|
|
323
|
+
export function cleanupInvalidWorktreeDir(dirPath: string): void {
|
|
324
|
+
if (!fs.existsSync(dirPath)) return;
|
|
325
|
+
|
|
326
|
+
// Only remove if it's NOT a valid worktree (safety check)
|
|
327
|
+
if (isValidWorktree(dirPath)) {
|
|
328
|
+
throw new Error(`Cannot cleanup: ${dirPath} is a valid worktree`);
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
// Remove the directory recursively
|
|
332
|
+
fs.rmSync(dirPath, { recursive: true, force: true });
|
|
333
|
+
}
|
|
334
|
+
|
|
277
335
|
/**
|
|
278
336
|
* Create worktree
|
|
279
337
|
*/
|
|
@@ -1,13 +1,14 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Utility for formatting log messages for console display
|
|
3
3
|
*
|
|
4
|
-
* Format: [HH:MM:SS] [
|
|
4
|
+
* Format: [HH:MM:SS] [MAIN] or [SUB:<id>] ICON TYPE content
|
|
5
|
+
* (labels are padded to keep alignment consistent)
|
|
5
6
|
*
|
|
6
7
|
* Rules:
|
|
7
8
|
* - Box format only for: user, assistant, system, result
|
|
8
9
|
* - Compact format for: tool, tool_result, thinking (gray/dim)
|
|
9
10
|
* - Tool names simplified: ShellToolCall → Shell
|
|
10
|
-
* - Lane labels
|
|
11
|
+
* - Lane labels fixed 20 chars: [1-1-backend ]
|
|
11
12
|
*/
|
|
12
13
|
|
|
13
14
|
import { COLORS } from './log-constants';
|
|
@@ -44,17 +45,12 @@ export function formatMessageForConsole(
|
|
|
44
45
|
const ts = includeTimestamp ? new Date(msg.timestamp).toLocaleTimeString('en-US', { hour12: false }) : '';
|
|
45
46
|
const tsPrefix = ts ? `${COLORS.gray}[${ts}]${COLORS.reset} ` : '';
|
|
46
47
|
|
|
47
|
-
// Handle context (e.g. from logger.info) -
|
|
48
|
-
// Format: [1-1-
|
|
49
|
-
let effectiveLaneLabel = laneLabel || (context ? `[${context.substring(0,
|
|
48
|
+
// Handle context (e.g. from logger.info) - keep labels compact
|
|
49
|
+
// Format: [1-1-refactor] without fixed width padding
|
|
50
|
+
let effectiveLaneLabel = laneLabel || (context ? `[${context.substring(0, 12)}]` : '');
|
|
50
51
|
|
|
51
|
-
//
|
|
52
|
-
|
|
53
|
-
effectiveLaneLabel = effectiveLaneLabel.substring(0, 19) + ']';
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
// Fixed width 20 chars for consistent alignment
|
|
57
|
-
const labelPrefix = effectiveLaneLabel ? `${COLORS.magenta}${effectiveLaneLabel.padEnd(20)}${COLORS.reset} ` : '';
|
|
52
|
+
// Compact label with color
|
|
53
|
+
const labelPrefix = effectiveLaneLabel ? `${COLORS.magenta}${effectiveLaneLabel}${COLORS.reset} ` : '';
|
|
58
54
|
|
|
59
55
|
let typePrefix = '';
|
|
60
56
|
let content = msg.content;
|
|
@@ -156,6 +152,9 @@ export function formatMessageForConsole(
|
|
|
156
152
|
case 'error':
|
|
157
153
|
typePrefix = `${COLORS.red}❌ ERR${COLORS.reset}`;
|
|
158
154
|
break;
|
|
155
|
+
case 'raw':
|
|
156
|
+
// Raw type means the content is already fully formatted - return as-is
|
|
157
|
+
return content;
|
|
159
158
|
}
|
|
160
159
|
|
|
161
160
|
if (!typePrefix) return `${tsPrefix}${labelPrefix}${content}`;
|
package/src/utils/logger.ts
CHANGED
|
@@ -3,14 +3,47 @@
|
|
|
3
3
|
*
|
|
4
4
|
* 통일된 로그 형식: [HH:MM:SS] emoji TYPE message
|
|
5
5
|
* 컨텍스트 포함 시: [HH:MM:SS] [context] emoji TYPE message
|
|
6
|
+
*
|
|
7
|
+
* Main process logs are optionally mirrored to a dedicated file to keep
|
|
8
|
+
* orchestration logs separate from lane/subprocess logs.
|
|
6
9
|
*/
|
|
7
10
|
|
|
11
|
+
import * as fs from 'fs';
|
|
12
|
+
import * as path from 'path';
|
|
8
13
|
import { COLORS, LogLevel } from './log-constants';
|
|
9
14
|
import { formatMessageForConsole } from './log-formatter';
|
|
10
15
|
|
|
11
16
|
export { COLORS, LogLevel };
|
|
12
17
|
|
|
13
18
|
let currentLogLevel: number = LogLevel.info;
|
|
19
|
+
let defaultContext: string | null = null;
|
|
20
|
+
let logFileStream: fs.WriteStream | null = null;
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Set default context label for logs (e.g., MAIN).
|
|
24
|
+
*/
|
|
25
|
+
export function setDefaultContext(context?: string | null): void {
|
|
26
|
+
defaultContext = context ?? null;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Mirror main process logs to a file (raw console output with ANSI codes).
|
|
31
|
+
*/
|
|
32
|
+
export function setLogFile(logPath?: string | null): void {
|
|
33
|
+
if (logFileStream) {
|
|
34
|
+
try {
|
|
35
|
+
logFileStream.end();
|
|
36
|
+
} catch {
|
|
37
|
+
// Ignore stream close errors
|
|
38
|
+
}
|
|
39
|
+
logFileStream = null;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
if (!logPath) return;
|
|
43
|
+
|
|
44
|
+
fs.mkdirSync(path.dirname(logPath), { recursive: true });
|
|
45
|
+
logFileStream = fs.createWriteStream(logPath, { flags: 'a' });
|
|
46
|
+
}
|
|
14
47
|
|
|
15
48
|
/**
|
|
16
49
|
* Set log level
|
|
@@ -66,11 +99,14 @@ function logInternal(
|
|
|
66
99
|
timestamp: Date.now(),
|
|
67
100
|
}, {
|
|
68
101
|
includeTimestamp: !options.noTimestamp,
|
|
69
|
-
context: options.context,
|
|
102
|
+
context: options.context ?? defaultContext ?? undefined,
|
|
70
103
|
compact: !options.box
|
|
71
104
|
});
|
|
72
105
|
|
|
73
106
|
console.log(formatted);
|
|
107
|
+
if (logFileStream) {
|
|
108
|
+
logFileStream.write(`${formatted}\n`);
|
|
109
|
+
}
|
|
74
110
|
}
|
|
75
111
|
|
|
76
112
|
// ============================================================================
|
|
@@ -144,10 +180,14 @@ export function withContext(context: string) {
|
|
|
144
180
|
*/
|
|
145
181
|
export function section(message: string): void {
|
|
146
182
|
console.log('');
|
|
147
|
-
|
|
183
|
+
const divider = `${COLORS.cyan}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${COLORS.reset}`;
|
|
184
|
+
console.log(divider);
|
|
148
185
|
console.log(`${COLORS.cyan} ${message}${COLORS.reset}`);
|
|
149
|
-
console.log(
|
|
186
|
+
console.log(divider);
|
|
150
187
|
console.log('');
|
|
188
|
+
if (logFileStream) {
|
|
189
|
+
logFileStream.write(`\n${divider}\n${COLORS.cyan} ${message}${COLORS.reset}\n${divider}\n\n`);
|
|
190
|
+
}
|
|
151
191
|
}
|
|
152
192
|
|
|
153
193
|
/**
|
|
@@ -155,6 +195,9 @@ export function section(message: string): void {
|
|
|
155
195
|
*/
|
|
156
196
|
export function raw(message: string): void {
|
|
157
197
|
process.stdout.write(message);
|
|
198
|
+
if (logFileStream) {
|
|
199
|
+
logFileStream.write(message);
|
|
200
|
+
}
|
|
158
201
|
}
|
|
159
202
|
|
|
160
203
|
/**
|
|
@@ -162,6 +205,9 @@ export function raw(message: string): void {
|
|
|
162
205
|
*/
|
|
163
206
|
export function log(message: string): void {
|
|
164
207
|
console.log(message);
|
|
208
|
+
if (logFileStream) {
|
|
209
|
+
logFileStream.write(`${message}\n`);
|
|
210
|
+
}
|
|
165
211
|
}
|
|
166
212
|
|
|
167
213
|
// ============================================================================
|
|
@@ -11,7 +11,6 @@ async function testThinkingLogs() {
|
|
|
11
11
|
|
|
12
12
|
console.log('--- Initializing Log Manager ---');
|
|
13
13
|
const manager = createLogManager(testDir, 'test-lane-thinking', {
|
|
14
|
-
writeJsonLog: true,
|
|
15
14
|
keepRawLogs: true
|
|
16
15
|
});
|
|
17
16
|
|
|
@@ -35,20 +34,6 @@ async function testThinkingLogs() {
|
|
|
35
34
|
console.log('\n--- Verifying terminal-readable.log ---');
|
|
36
35
|
const readableLog = fs.readFileSync(path.join(testDir, 'terminal-readable.log'), 'utf8');
|
|
37
36
|
console.log(readableLog);
|
|
38
|
-
|
|
39
|
-
console.log('\n--- Verifying terminal.jsonl (last 3 entries) ---');
|
|
40
|
-
const jsonlLog = fs.readFileSync(path.join(testDir, 'terminal.jsonl'), 'utf8');
|
|
41
|
-
const lines = jsonlLog.trim().split('\n');
|
|
42
|
-
for (const line of lines.slice(-3)) {
|
|
43
|
-
const parsed = JSON.parse(line);
|
|
44
|
-
console.log(JSON.stringify({
|
|
45
|
-
level: parsed.level,
|
|
46
|
-
message: parsed.message.substring(0, 50) + '...',
|
|
47
|
-
hasMetadata: !!parsed.metadata,
|
|
48
|
-
metadataType: parsed.metadata?.type
|
|
49
|
-
}, null, 2));
|
|
50
|
-
}
|
|
51
37
|
}
|
|
52
38
|
|
|
53
39
|
testThinkingLogs().catch(console.error);
|
|
54
|
-
|
package/src/utils/run-service.ts
CHANGED
|
@@ -183,7 +183,7 @@ export class RunService {
|
|
|
183
183
|
const statuses = lanes.map(l => l.status);
|
|
184
184
|
|
|
185
185
|
// If any lane is running, the run is running
|
|
186
|
-
if (statuses.some(s => s === 'running'
|
|
186
|
+
if (statuses.some(s => s === 'running')) {
|
|
187
187
|
return 'running';
|
|
188
188
|
}
|
|
189
189
|
|
|
@@ -1,71 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Log File Writer - Write logs to files with rotation
|
|
3
|
-
*
|
|
4
|
-
* Manages log file writing with support for multiple formats.
|
|
5
|
-
*/
|
|
6
|
-
import { Transform, TransformCallback } from 'stream';
|
|
7
|
-
import { LogSession, ParsedMessage } from '../../types/logging';
|
|
8
|
-
import { EnhancedLogConfig } from '../../types/config';
|
|
9
|
-
export declare const DEFAULT_LOG_CONFIG: EnhancedLogConfig;
|
|
10
|
-
/**
|
|
11
|
-
* Transform stream for clean log output
|
|
12
|
-
*/
|
|
13
|
-
export declare class CleanLogTransform extends Transform {
|
|
14
|
-
private config;
|
|
15
|
-
private session;
|
|
16
|
-
private buffer;
|
|
17
|
-
constructor(config: EnhancedLogConfig, session: LogSession);
|
|
18
|
-
_transform(chunk: Buffer, _encoding: BufferEncoding, callback: TransformCallback): void;
|
|
19
|
-
_flush(callback: TransformCallback): void;
|
|
20
|
-
private hasTimestamp;
|
|
21
|
-
}
|
|
22
|
-
/**
|
|
23
|
-
* Enhanced Log Manager - Handles all log file operations
|
|
24
|
-
*/
|
|
25
|
-
export declare class EnhancedLogManager {
|
|
26
|
-
private config;
|
|
27
|
-
private session;
|
|
28
|
-
private logDir;
|
|
29
|
-
private cleanLogPath;
|
|
30
|
-
private rawLogPath;
|
|
31
|
-
private jsonLogPath;
|
|
32
|
-
private readableLogPath;
|
|
33
|
-
private cleanLogFd;
|
|
34
|
-
private rawLogFd;
|
|
35
|
-
private jsonLogFd;
|
|
36
|
-
private readableLogFd;
|
|
37
|
-
private cleanLogSize;
|
|
38
|
-
private rawLogSize;
|
|
39
|
-
private cleanTransform;
|
|
40
|
-
private streamingParser;
|
|
41
|
-
private lineBuffer;
|
|
42
|
-
private onParsedMessage?;
|
|
43
|
-
constructor(logDir: string, session: LogSession, config?: Partial<EnhancedLogConfig>, onParsedMessage?: (msg: ParsedMessage) => void);
|
|
44
|
-
private initLogFiles;
|
|
45
|
-
private writeSessionHeader;
|
|
46
|
-
private writeReadableMessage;
|
|
47
|
-
private rotateIfNeeded;
|
|
48
|
-
private rotateLog;
|
|
49
|
-
private writeToCleanLog;
|
|
50
|
-
private writeToRawLog;
|
|
51
|
-
private writeJsonEntry;
|
|
52
|
-
writeStdout(data: Buffer | string): void;
|
|
53
|
-
writeStderr(data: Buffer | string): void;
|
|
54
|
-
log(level: 'info' | 'error' | 'debug', message: string, metadata?: Record<string, any>): void;
|
|
55
|
-
section(title: string): void;
|
|
56
|
-
setTask(taskName: string, model?: string): void;
|
|
57
|
-
private isNoise;
|
|
58
|
-
getLogPaths(): {
|
|
59
|
-
clean: string;
|
|
60
|
-
raw?: string;
|
|
61
|
-
json?: string;
|
|
62
|
-
readable: string;
|
|
63
|
-
};
|
|
64
|
-
getFileDescriptors(): {
|
|
65
|
-
stdout: number;
|
|
66
|
-
stderr: number;
|
|
67
|
-
};
|
|
68
|
-
close(): void;
|
|
69
|
-
private formatDuration;
|
|
70
|
-
}
|
|
71
|
-
export declare function createLogManager(laneRunDir: string, laneName: string, config?: Partial<EnhancedLogConfig>, onParsedMessage?: (msg: ParsedMessage) => void): EnhancedLogManager;
|