sequant 1.2.4 → 1.2.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +18 -0
- package/dist/bin/cli.js +10 -0
- package/dist/bin/cli.js.map +1 -1
- package/dist/src/commands/doctor.d.ts.map +1 -1
- package/dist/src/commands/doctor.js +33 -1
- package/dist/src/commands/doctor.js.map +1 -1
- package/dist/src/commands/doctor.test.js +84 -1
- package/dist/src/commands/doctor.test.js.map +1 -1
- package/dist/src/commands/init.d.ts.map +1 -1
- package/dist/src/commands/init.js +5 -0
- package/dist/src/commands/init.js.map +1 -1
- package/dist/src/commands/logs.d.ts +2 -0
- package/dist/src/commands/logs.d.ts.map +1 -1
- package/dist/src/commands/logs.js +41 -0
- package/dist/src/commands/logs.js.map +1 -1
- package/dist/src/commands/run.js +5 -1
- package/dist/src/commands/run.js.map +1 -1
- package/dist/src/commands/stats.d.ts +16 -0
- package/dist/src/commands/stats.d.ts.map +1 -0
- package/dist/src/commands/stats.js +271 -0
- package/dist/src/commands/stats.js.map +1 -0
- package/dist/src/commands/stats.test.d.ts +7 -0
- package/dist/src/commands/stats.test.d.ts.map +1 -0
- package/dist/src/commands/stats.test.js +218 -0
- package/dist/src/commands/stats.test.js.map +1 -0
- package/dist/src/commands/update.d.ts.map +1 -1
- package/dist/src/commands/update.js +2 -2
- package/dist/src/commands/update.js.map +1 -1
- package/dist/src/lib/settings.d.ts +17 -0
- package/dist/src/lib/settings.d.ts.map +1 -1
- package/dist/src/lib/settings.js +9 -0
- package/dist/src/lib/settings.js.map +1 -1
- package/dist/src/lib/system.d.ts +26 -0
- package/dist/src/lib/system.d.ts.map +1 -1
- package/dist/src/lib/system.js +72 -1
- package/dist/src/lib/system.js.map +1 -1
- package/dist/src/lib/workflow/log-rotation.d.ts +138 -0
- package/dist/src/lib/workflow/log-rotation.d.ts.map +1 -0
- package/dist/src/lib/workflow/log-rotation.js +232 -0
- package/dist/src/lib/workflow/log-rotation.js.map +1 -0
- package/dist/src/lib/workflow/log-rotation.test.d.ts +7 -0
- package/dist/src/lib/workflow/log-rotation.test.d.ts.map +1 -0
- package/dist/src/lib/workflow/log-rotation.test.js +248 -0
- package/dist/src/lib/workflow/log-rotation.test.js.map +1 -0
- package/dist/src/lib/workflow/log-writer.d.ts +6 -0
- package/dist/src/lib/workflow/log-writer.d.ts.map +1 -1
- package/dist/src/lib/workflow/log-writer.js +12 -0
- package/dist/src/lib/workflow/log-writer.js.map +1 -1
- package/dist/src/lib/workflow/log-writer.test.js +4 -1
- package/dist/src/lib/workflow/log-writer.test.js.map +1 -1
- package/package.json +1 -1
- package/templates/skills/exec/SKILL.md +75 -0
- package/templates/skills/qa/SKILL.md +8 -0
|
@@ -0,0 +1,232 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Log rotation management for workflow run logs
|
|
3
|
+
*
|
|
4
|
+
* Implements automatic log rotation based on size and file count thresholds.
|
|
5
|
+
* Deletes oldest logs first until within limits.
|
|
6
|
+
*
|
|
7
|
+
* @example
|
|
8
|
+
* ```typescript
|
|
9
|
+
* import { rotateIfNeeded, getLogStats, manualRotate } from './log-rotation';
|
|
10
|
+
*
|
|
11
|
+
* // Auto-rotate after a run
|
|
12
|
+
* await rotateIfNeeded('.sequant/logs');
|
|
13
|
+
*
|
|
14
|
+
* // Get statistics
|
|
15
|
+
* const stats = await getLogStats('.sequant/logs');
|
|
16
|
+
* console.log(`${stats.fileCount} files, ${stats.totalSizeMB.toFixed(2)}MB`);
|
|
17
|
+
*
|
|
18
|
+
* // Manual rotation with dry-run
|
|
19
|
+
* const result = await manualRotate('.sequant/logs', { dryRun: true });
|
|
20
|
+
* console.log(`Would delete ${result.deletedCount} files`);
|
|
21
|
+
* ```
|
|
22
|
+
*/
|
|
23
|
+
import * as fs from "fs";
|
|
24
|
+
import * as path from "path";
|
|
25
|
+
import * as os from "os";
|
|
26
|
+
/**
|
|
27
|
+
* Default rotation settings
|
|
28
|
+
*/
|
|
29
|
+
export const DEFAULT_ROTATION_SETTINGS = {
|
|
30
|
+
enabled: true,
|
|
31
|
+
maxSizeMB: 10,
|
|
32
|
+
maxFiles: 100,
|
|
33
|
+
};
|
|
34
|
+
/**
|
|
35
|
+
* Resolve a path, replacing ~ with home directory
|
|
36
|
+
*/
|
|
37
|
+
function resolvePath(logPath) {
|
|
38
|
+
return logPath.replace("~", os.homedir());
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Get list of log files with metadata, sorted by modification time (oldest first)
|
|
42
|
+
*/
|
|
43
|
+
export function getLogFiles(logDir) {
|
|
44
|
+
const resolved = resolvePath(logDir);
|
|
45
|
+
if (!fs.existsSync(resolved)) {
|
|
46
|
+
return [];
|
|
47
|
+
}
|
|
48
|
+
const files = fs
|
|
49
|
+
.readdirSync(resolved)
|
|
50
|
+
.filter((f) => f.startsWith("run-") && f.endsWith(".json"));
|
|
51
|
+
const fileInfos = files.map((filename) => {
|
|
52
|
+
const filePath = path.join(resolved, filename);
|
|
53
|
+
const stats = fs.statSync(filePath);
|
|
54
|
+
return {
|
|
55
|
+
filename,
|
|
56
|
+
filePath,
|
|
57
|
+
mtime: stats.mtime,
|
|
58
|
+
size: stats.size,
|
|
59
|
+
};
|
|
60
|
+
});
|
|
61
|
+
// Sort by modification time, oldest first
|
|
62
|
+
return fileInfos.sort((a, b) => a.mtime.getTime() - b.mtime.getTime());
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Get statistics about the log directory
|
|
66
|
+
*
|
|
67
|
+
* @param logDir - Path to log directory
|
|
68
|
+
* @param settings - Rotation settings for threshold comparison
|
|
69
|
+
* @returns Log directory statistics
|
|
70
|
+
*/
|
|
71
|
+
export function getLogStats(logDir, settings = DEFAULT_ROTATION_SETTINGS) {
|
|
72
|
+
const files = getLogFiles(logDir);
|
|
73
|
+
if (files.length === 0) {
|
|
74
|
+
return {
|
|
75
|
+
totalSizeBytes: 0,
|
|
76
|
+
totalSizeMB: 0,
|
|
77
|
+
fileCount: 0,
|
|
78
|
+
oldestFile: null,
|
|
79
|
+
newestFile: null,
|
|
80
|
+
exceedsSizeThreshold: false,
|
|
81
|
+
exceedsCountThreshold: false,
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
const totalSizeBytes = files.reduce((sum, f) => sum + f.size, 0);
|
|
85
|
+
const totalSizeMB = totalSizeBytes / (1024 * 1024);
|
|
86
|
+
return {
|
|
87
|
+
totalSizeBytes,
|
|
88
|
+
totalSizeMB,
|
|
89
|
+
fileCount: files.length,
|
|
90
|
+
oldestFile: files[0].filename,
|
|
91
|
+
newestFile: files[files.length - 1].filename,
|
|
92
|
+
exceedsSizeThreshold: totalSizeMB > settings.maxSizeMB,
|
|
93
|
+
exceedsCountThreshold: files.length > settings.maxFiles,
|
|
94
|
+
};
|
|
95
|
+
}
|
|
96
|
+
/**
|
|
97
|
+
* Calculate which files need to be deleted to meet thresholds
|
|
98
|
+
*
|
|
99
|
+
* Applies a 10% buffer (stops at 90% of threshold) to prevent
|
|
100
|
+
* immediate re-rotation on next run.
|
|
101
|
+
*
|
|
102
|
+
* @param logDir - Path to log directory
|
|
103
|
+
* @param settings - Rotation settings
|
|
104
|
+
* @returns List of files to delete (oldest first)
|
|
105
|
+
*/
|
|
106
|
+
export function getFilesToDelete(logDir, settings) {
|
|
107
|
+
const files = getLogFiles(logDir);
|
|
108
|
+
if (files.length === 0) {
|
|
109
|
+
return [];
|
|
110
|
+
}
|
|
111
|
+
const stats = getLogStats(logDir, settings);
|
|
112
|
+
// Check if rotation is needed
|
|
113
|
+
if (!stats.exceedsSizeThreshold && !stats.exceedsCountThreshold) {
|
|
114
|
+
return [];
|
|
115
|
+
}
|
|
116
|
+
// Target thresholds with 10% buffer (stop at 90%)
|
|
117
|
+
const targetSizeBytes = settings.maxSizeMB * 1024 * 1024 * 0.9;
|
|
118
|
+
const targetCount = Math.floor(settings.maxFiles * 0.9);
|
|
119
|
+
const toDelete = [];
|
|
120
|
+
let currentSize = stats.totalSizeBytes;
|
|
121
|
+
let currentCount = stats.fileCount;
|
|
122
|
+
// Delete oldest files first until under thresholds
|
|
123
|
+
for (const file of files) {
|
|
124
|
+
const sizeOk = currentSize <= targetSizeBytes;
|
|
125
|
+
const countOk = currentCount <= targetCount;
|
|
126
|
+
if (sizeOk && countOk) {
|
|
127
|
+
break;
|
|
128
|
+
}
|
|
129
|
+
toDelete.push(file);
|
|
130
|
+
currentSize -= file.size;
|
|
131
|
+
currentCount--;
|
|
132
|
+
}
|
|
133
|
+
return toDelete;
|
|
134
|
+
}
|
|
135
|
+
/**
|
|
136
|
+
* Rotate logs if needed (automatic rotation)
|
|
137
|
+
*
|
|
138
|
+
* Called after LogWriter.finalize() to clean up old logs.
|
|
139
|
+
*
|
|
140
|
+
* @param logDir - Path to log directory
|
|
141
|
+
* @param settings - Rotation settings
|
|
142
|
+
* @returns Rotation result
|
|
143
|
+
*/
|
|
144
|
+
export function rotateIfNeeded(logDir, settings = DEFAULT_ROTATION_SETTINGS) {
|
|
145
|
+
if (!settings.enabled) {
|
|
146
|
+
return {
|
|
147
|
+
deletedFiles: [],
|
|
148
|
+
deletedCount: 0,
|
|
149
|
+
bytesReclaimed: 0,
|
|
150
|
+
rotated: false,
|
|
151
|
+
};
|
|
152
|
+
}
|
|
153
|
+
const resolved = resolvePath(logDir);
|
|
154
|
+
const toDelete = getFilesToDelete(logDir, settings);
|
|
155
|
+
if (toDelete.length === 0) {
|
|
156
|
+
return {
|
|
157
|
+
deletedFiles: [],
|
|
158
|
+
deletedCount: 0,
|
|
159
|
+
bytesReclaimed: 0,
|
|
160
|
+
rotated: false,
|
|
161
|
+
};
|
|
162
|
+
}
|
|
163
|
+
let bytesReclaimed = 0;
|
|
164
|
+
const deletedFiles = [];
|
|
165
|
+
for (const file of toDelete) {
|
|
166
|
+
try {
|
|
167
|
+
fs.unlinkSync(file.filePath);
|
|
168
|
+
deletedFiles.push(file.filename);
|
|
169
|
+
bytesReclaimed += file.size;
|
|
170
|
+
}
|
|
171
|
+
catch (err) {
|
|
172
|
+
return {
|
|
173
|
+
deletedFiles,
|
|
174
|
+
deletedCount: deletedFiles.length,
|
|
175
|
+
bytesReclaimed,
|
|
176
|
+
rotated: deletedFiles.length > 0,
|
|
177
|
+
error: `Failed to delete ${file.filename}: ${err instanceof Error ? err.message : String(err)}`,
|
|
178
|
+
};
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
return {
|
|
182
|
+
deletedFiles,
|
|
183
|
+
deletedCount: deletedFiles.length,
|
|
184
|
+
bytesReclaimed,
|
|
185
|
+
rotated: true,
|
|
186
|
+
};
|
|
187
|
+
}
|
|
188
|
+
/**
|
|
189
|
+
* Manual rotation triggered by CLI command
|
|
190
|
+
*
|
|
191
|
+
* Supports dry-run mode to preview what would be deleted.
|
|
192
|
+
*
|
|
193
|
+
* @param logDir - Path to log directory
|
|
194
|
+
* @param options - Manual rotation options
|
|
195
|
+
* @returns Rotation result
|
|
196
|
+
*/
|
|
197
|
+
export function manualRotate(logDir, options = {}) {
|
|
198
|
+
const settings = options.settings ?? DEFAULT_ROTATION_SETTINGS;
|
|
199
|
+
const toDelete = getFilesToDelete(logDir, settings);
|
|
200
|
+
if (toDelete.length === 0) {
|
|
201
|
+
return {
|
|
202
|
+
deletedFiles: [],
|
|
203
|
+
deletedCount: 0,
|
|
204
|
+
bytesReclaimed: 0,
|
|
205
|
+
rotated: false,
|
|
206
|
+
};
|
|
207
|
+
}
|
|
208
|
+
// Dry run - just report what would be deleted
|
|
209
|
+
if (options.dryRun) {
|
|
210
|
+
return {
|
|
211
|
+
deletedFiles: toDelete.map((f) => f.filename),
|
|
212
|
+
deletedCount: toDelete.length,
|
|
213
|
+
bytesReclaimed: toDelete.reduce((sum, f) => sum + f.size, 0),
|
|
214
|
+
rotated: false,
|
|
215
|
+
};
|
|
216
|
+
}
|
|
217
|
+
// Actual deletion
|
|
218
|
+
return rotateIfNeeded(logDir, settings);
|
|
219
|
+
}
|
|
220
|
+
/**
|
|
221
|
+
* Format bytes for human-readable display
|
|
222
|
+
*/
|
|
223
|
+
export function formatBytes(bytes) {
|
|
224
|
+
if (bytes < 1024) {
|
|
225
|
+
return `${bytes} B`;
|
|
226
|
+
}
|
|
227
|
+
if (bytes < 1024 * 1024) {
|
|
228
|
+
return `${(bytes / 1024).toFixed(1)} KB`;
|
|
229
|
+
}
|
|
230
|
+
return `${(bytes / (1024 * 1024)).toFixed(2)} MB`;
|
|
231
|
+
}
|
|
232
|
+
//# sourceMappingURL=log-rotation.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"log-rotation.js","sourceRoot":"","sources":["../../../../src/lib/workflow/log-rotation.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"log-rotation.test.d.ts","sourceRoot":"","sources":["../../../../src/lib/workflow/log-rotation.test.ts"],"names":[],"mappings":"AAAA;;;;GAIG"}
|
|
@@ -0,0 +1,248 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Unit tests for log rotation
|
|
3
|
+
*
|
|
4
|
+
* Tests the log rotation system that manages disk space usage.
|
|
5
|
+
*/
|
|
6
|
+
import { describe, it, expect, vi, beforeEach } from "vitest";
|
|
7
|
+
import * as fs from "fs";
|
|
8
|
+
import { getLogFiles, getLogStats, getFilesToDelete, rotateIfNeeded, manualRotate, formatBytes, DEFAULT_ROTATION_SETTINGS, } from "./log-rotation.js";
|
|
9
|
+
// Mock fs module
|
|
10
|
+
vi.mock("fs", () => ({
|
|
11
|
+
existsSync: vi.fn(),
|
|
12
|
+
readdirSync: vi.fn(),
|
|
13
|
+
statSync: vi.fn(),
|
|
14
|
+
unlinkSync: vi.fn(),
|
|
15
|
+
}));
|
|
16
|
+
describe("log-rotation", () => {
|
|
17
|
+
beforeEach(() => {
|
|
18
|
+
vi.clearAllMocks();
|
|
19
|
+
});
|
|
20
|
+
describe("getLogFiles", () => {
|
|
21
|
+
it("should return empty array if directory does not exist", () => {
|
|
22
|
+
fs.existsSync.mockReturnValue(false);
|
|
23
|
+
const result = getLogFiles("/test/logs");
|
|
24
|
+
expect(result).toEqual([]);
|
|
25
|
+
});
|
|
26
|
+
it("should filter for run-*.json files only", () => {
|
|
27
|
+
fs.existsSync.mockReturnValue(true);
|
|
28
|
+
fs.readdirSync.mockReturnValue([
|
|
29
|
+
"run-2024-01-15-abc.json",
|
|
30
|
+
"run-2024-01-16-def.json",
|
|
31
|
+
"other-file.json",
|
|
32
|
+
"run-incomplete",
|
|
33
|
+
"settings.json",
|
|
34
|
+
]);
|
|
35
|
+
fs.statSync.mockImplementation((path) => ({
|
|
36
|
+
mtime: new Date(path.includes("15") ? "2024-01-15" : "2024-01-16"),
|
|
37
|
+
size: 1024,
|
|
38
|
+
}));
|
|
39
|
+
const result = getLogFiles("/test/logs");
|
|
40
|
+
expect(result).toHaveLength(2);
|
|
41
|
+
expect(result[0].filename).toBe("run-2024-01-15-abc.json");
|
|
42
|
+
expect(result[1].filename).toBe("run-2024-01-16-def.json");
|
|
43
|
+
});
|
|
44
|
+
it("should sort files by modification time (oldest first)", () => {
|
|
45
|
+
fs.existsSync.mockReturnValue(true);
|
|
46
|
+
fs.readdirSync.mockReturnValue([
|
|
47
|
+
"run-new.json",
|
|
48
|
+
"run-old.json",
|
|
49
|
+
"run-mid.json",
|
|
50
|
+
]);
|
|
51
|
+
fs.statSync.mockImplementation((path) => {
|
|
52
|
+
if (path.includes("old"))
|
|
53
|
+
return { mtime: new Date("2024-01-01"), size: 1024 };
|
|
54
|
+
if (path.includes("mid"))
|
|
55
|
+
return { mtime: new Date("2024-01-15"), size: 1024 };
|
|
56
|
+
return { mtime: new Date("2024-01-30"), size: 1024 };
|
|
57
|
+
});
|
|
58
|
+
const result = getLogFiles("/test/logs");
|
|
59
|
+
expect(result[0].filename).toBe("run-old.json");
|
|
60
|
+
expect(result[1].filename).toBe("run-mid.json");
|
|
61
|
+
expect(result[2].filename).toBe("run-new.json");
|
|
62
|
+
});
|
|
63
|
+
});
|
|
64
|
+
describe("getLogStats", () => {
|
|
65
|
+
it("should return zero stats for empty directory", () => {
|
|
66
|
+
fs.existsSync.mockReturnValue(true);
|
|
67
|
+
fs.readdirSync.mockReturnValue([]);
|
|
68
|
+
const stats = getLogStats("/test/logs");
|
|
69
|
+
expect(stats).toEqual({
|
|
70
|
+
totalSizeBytes: 0,
|
|
71
|
+
totalSizeMB: 0,
|
|
72
|
+
fileCount: 0,
|
|
73
|
+
oldestFile: null,
|
|
74
|
+
newestFile: null,
|
|
75
|
+
exceedsSizeThreshold: false,
|
|
76
|
+
exceedsCountThreshold: false,
|
|
77
|
+
});
|
|
78
|
+
});
|
|
79
|
+
it("should calculate total size correctly", () => {
|
|
80
|
+
fs.existsSync.mockReturnValue(true);
|
|
81
|
+
fs.readdirSync.mockReturnValue([
|
|
82
|
+
"run-1.json",
|
|
83
|
+
"run-2.json",
|
|
84
|
+
]);
|
|
85
|
+
fs.statSync.mockImplementation((path) => ({
|
|
86
|
+
mtime: new Date(),
|
|
87
|
+
size: path.includes("1") ? 1024 * 1024 : 2 * 1024 * 1024, // 1MB and 2MB
|
|
88
|
+
}));
|
|
89
|
+
const stats = getLogStats("/test/logs");
|
|
90
|
+
expect(stats.totalSizeBytes).toBe(3 * 1024 * 1024);
|
|
91
|
+
expect(stats.totalSizeMB).toBe(3);
|
|
92
|
+
expect(stats.fileCount).toBe(2);
|
|
93
|
+
});
|
|
94
|
+
it("should detect size threshold exceeded", () => {
|
|
95
|
+
fs.existsSync.mockReturnValue(true);
|
|
96
|
+
fs.readdirSync.mockReturnValue([
|
|
97
|
+
"run-1.json",
|
|
98
|
+
]);
|
|
99
|
+
fs.statSync.mockReturnValue({
|
|
100
|
+
mtime: new Date(),
|
|
101
|
+
size: 15 * 1024 * 1024, // 15MB > 10MB threshold
|
|
102
|
+
});
|
|
103
|
+
const stats = getLogStats("/test/logs");
|
|
104
|
+
expect(stats.exceedsSizeThreshold).toBe(true);
|
|
105
|
+
expect(stats.exceedsCountThreshold).toBe(false);
|
|
106
|
+
});
|
|
107
|
+
it("should detect count threshold exceeded", () => {
|
|
108
|
+
fs.existsSync.mockReturnValue(true);
|
|
109
|
+
fs.readdirSync.mockReturnValue(Array.from({ length: 105 }, (_, i) => `run-${i}.json`));
|
|
110
|
+
fs.statSync.mockReturnValue({
|
|
111
|
+
mtime: new Date(),
|
|
112
|
+
size: 1024, // 1KB each = 105KB total (under size limit)
|
|
113
|
+
});
|
|
114
|
+
const stats = getLogStats("/test/logs");
|
|
115
|
+
expect(stats.exceedsSizeThreshold).toBe(false);
|
|
116
|
+
expect(stats.exceedsCountThreshold).toBe(true);
|
|
117
|
+
});
|
|
118
|
+
});
|
|
119
|
+
describe("getFilesToDelete", () => {
|
|
120
|
+
it("should return empty array when under thresholds", () => {
|
|
121
|
+
fs.existsSync.mockReturnValue(true);
|
|
122
|
+
fs.readdirSync.mockReturnValue([
|
|
123
|
+
"run-1.json",
|
|
124
|
+
"run-2.json",
|
|
125
|
+
]);
|
|
126
|
+
fs.statSync.mockReturnValue({
|
|
127
|
+
mtime: new Date(),
|
|
128
|
+
size: 1024,
|
|
129
|
+
});
|
|
130
|
+
const result = getFilesToDelete("/test/logs", DEFAULT_ROTATION_SETTINGS);
|
|
131
|
+
expect(result).toEqual([]);
|
|
132
|
+
});
|
|
133
|
+
it("should select oldest files for deletion when count exceeded", () => {
|
|
134
|
+
fs.existsSync.mockReturnValue(true);
|
|
135
|
+
const files = Array.from({ length: 105 }, (_, i) => `run-${i}.json`);
|
|
136
|
+
fs.readdirSync.mockReturnValue(files);
|
|
137
|
+
fs.statSync.mockImplementation((path) => {
|
|
138
|
+
const match = path.match(/run-(\d+)\.json/);
|
|
139
|
+
const idx = match ? parseInt(match[1]) : 0;
|
|
140
|
+
return {
|
|
141
|
+
mtime: new Date(Date.now() + idx * 1000), // Older files have lower index
|
|
142
|
+
size: 1024,
|
|
143
|
+
};
|
|
144
|
+
});
|
|
145
|
+
const result = getFilesToDelete("/test/logs", DEFAULT_ROTATION_SETTINGS);
|
|
146
|
+
// Should delete enough to get to 90 files (10% buffer = 90)
|
|
147
|
+
// 105 - 90 = 15 files to delete
|
|
148
|
+
expect(result.length).toBe(15);
|
|
149
|
+
// Oldest files should be first
|
|
150
|
+
expect(result[0].filename).toBe("run-0.json");
|
|
151
|
+
});
|
|
152
|
+
it("should delete files when size threshold exceeded", () => {
|
|
153
|
+
fs.existsSync.mockReturnValue(true);
|
|
154
|
+
fs.readdirSync.mockReturnValue([
|
|
155
|
+
"run-old.json",
|
|
156
|
+
"run-new.json",
|
|
157
|
+
]);
|
|
158
|
+
fs.statSync.mockImplementation((path) => ({
|
|
159
|
+
mtime: new Date(path.includes("old") ? "2024-01-01" : "2024-01-30"),
|
|
160
|
+
size: 6 * 1024 * 1024, // 6MB each = 12MB total > 10MB
|
|
161
|
+
}));
|
|
162
|
+
const result = getFilesToDelete("/test/logs", DEFAULT_ROTATION_SETTINGS);
|
|
163
|
+
// Should delete 1 file to get under 9MB threshold
|
|
164
|
+
expect(result.length).toBe(1);
|
|
165
|
+
expect(result[0].filename).toBe("run-old.json");
|
|
166
|
+
});
|
|
167
|
+
});
|
|
168
|
+
describe("rotateIfNeeded", () => {
|
|
169
|
+
it("should not delete when disabled", () => {
|
|
170
|
+
const result = rotateIfNeeded("/test/logs", {
|
|
171
|
+
...DEFAULT_ROTATION_SETTINGS,
|
|
172
|
+
enabled: false,
|
|
173
|
+
});
|
|
174
|
+
expect(result.rotated).toBe(false);
|
|
175
|
+
expect(result.deletedCount).toBe(0);
|
|
176
|
+
expect(fs.unlinkSync).not.toHaveBeenCalled();
|
|
177
|
+
});
|
|
178
|
+
it("should not delete when under thresholds", () => {
|
|
179
|
+
fs.existsSync.mockReturnValue(true);
|
|
180
|
+
fs.readdirSync.mockReturnValue([
|
|
181
|
+
"run-1.json",
|
|
182
|
+
]);
|
|
183
|
+
fs.statSync.mockReturnValue({
|
|
184
|
+
mtime: new Date(),
|
|
185
|
+
size: 1024,
|
|
186
|
+
});
|
|
187
|
+
const result = rotateIfNeeded("/test/logs");
|
|
188
|
+
expect(result.rotated).toBe(false);
|
|
189
|
+
expect(fs.unlinkSync).not.toHaveBeenCalled();
|
|
190
|
+
});
|
|
191
|
+
it("should delete oldest files when threshold exceeded", () => {
|
|
192
|
+
fs.existsSync.mockReturnValue(true);
|
|
193
|
+
fs.readdirSync.mockReturnValue([
|
|
194
|
+
"run-old.json",
|
|
195
|
+
"run-new.json",
|
|
196
|
+
]);
|
|
197
|
+
fs.statSync.mockImplementation((path) => ({
|
|
198
|
+
mtime: new Date(path.includes("old") ? "2024-01-01" : "2024-01-30"),
|
|
199
|
+
size: 6 * 1024 * 1024,
|
|
200
|
+
}));
|
|
201
|
+
const result = rotateIfNeeded("/test/logs");
|
|
202
|
+
expect(result.rotated).toBe(true);
|
|
203
|
+
expect(result.deletedCount).toBe(1);
|
|
204
|
+
expect(fs.unlinkSync).toHaveBeenCalledTimes(1);
|
|
205
|
+
});
|
|
206
|
+
});
|
|
207
|
+
describe("manualRotate", () => {
|
|
208
|
+
it("should support dry-run mode", () => {
|
|
209
|
+
fs.existsSync.mockReturnValue(true);
|
|
210
|
+
fs.readdirSync.mockReturnValue([
|
|
211
|
+
"run-old.json",
|
|
212
|
+
"run-new.json",
|
|
213
|
+
]);
|
|
214
|
+
fs.statSync.mockImplementation((path) => ({
|
|
215
|
+
mtime: new Date(path.includes("old") ? "2024-01-01" : "2024-01-30"),
|
|
216
|
+
size: 6 * 1024 * 1024,
|
|
217
|
+
}));
|
|
218
|
+
const result = manualRotate("/test/logs", { dryRun: true });
|
|
219
|
+
expect(result.deletedCount).toBe(1);
|
|
220
|
+
expect(result.rotated).toBe(false); // dry-run = not actually rotated
|
|
221
|
+
expect(fs.unlinkSync).not.toHaveBeenCalled();
|
|
222
|
+
});
|
|
223
|
+
it("should actually delete in non-dry-run mode", () => {
|
|
224
|
+
fs.existsSync.mockReturnValue(true);
|
|
225
|
+
fs.readdirSync.mockReturnValue([
|
|
226
|
+
"run-old.json",
|
|
227
|
+
"run-new.json",
|
|
228
|
+
]);
|
|
229
|
+
fs.statSync.mockImplementation((path) => ({
|
|
230
|
+
mtime: new Date(path.includes("old") ? "2024-01-01" : "2024-01-30"),
|
|
231
|
+
size: 6 * 1024 * 1024,
|
|
232
|
+
}));
|
|
233
|
+
const result = manualRotate("/test/logs", { dryRun: false });
|
|
234
|
+
expect(result.rotated).toBe(true);
|
|
235
|
+
expect(fs.unlinkSync).toHaveBeenCalled();
|
|
236
|
+
});
|
|
237
|
+
});
|
|
238
|
+
describe("formatBytes", () => {
|
|
239
|
+
it("should format bytes correctly", () => {
|
|
240
|
+
expect(formatBytes(500)).toBe("500 B");
|
|
241
|
+
expect(formatBytes(1024)).toBe("1.0 KB");
|
|
242
|
+
expect(formatBytes(1536)).toBe("1.5 KB");
|
|
243
|
+
expect(formatBytes(1024 * 1024)).toBe("1.00 MB");
|
|
244
|
+
expect(formatBytes(5.5 * 1024 * 1024)).toBe("5.50 MB");
|
|
245
|
+
});
|
|
246
|
+
});
|
|
247
|
+
});
|
|
248
|
+
//# sourceMappingURL=log-rotation.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"log-rotation.test.js","sourceRoot":"","sources":["../../../../src/lib/workflow/log-rotation.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -14,6 +14,7 @@
|
|
|
14
14
|
* ```
|
|
15
15
|
*/
|
|
16
16
|
import { type RunLog, type RunConfig, type PhaseLog, type Phase } from "./run-log-schema.js";
|
|
17
|
+
import { type RotationSettings } from "./log-rotation.js";
|
|
17
18
|
export interface LogWriterOptions {
|
|
18
19
|
/** Path to log directory (default: .sequant/logs in current directory) */
|
|
19
20
|
logPath?: string;
|
|
@@ -21,6 +22,8 @@ export interface LogWriterOptions {
|
|
|
21
22
|
writeToUserLogs?: boolean;
|
|
22
23
|
/** Enable verbose logging */
|
|
23
24
|
verbose?: boolean;
|
|
25
|
+
/** Log rotation settings */
|
|
26
|
+
rotation?: RotationSettings;
|
|
24
27
|
}
|
|
25
28
|
/**
|
|
26
29
|
* Manages writing structured run logs to disk
|
|
@@ -31,6 +34,7 @@ export declare class LogWriter {
|
|
|
31
34
|
private logPath;
|
|
32
35
|
private writeToUserLogs;
|
|
33
36
|
private verbose;
|
|
37
|
+
private rotation;
|
|
34
38
|
constructor(options?: LogWriterOptions);
|
|
35
39
|
/**
|
|
36
40
|
* Initialize a new run log
|
|
@@ -59,6 +63,8 @@ export declare class LogWriter {
|
|
|
59
63
|
/**
|
|
60
64
|
* Finalize the run log and write to disk
|
|
61
65
|
*
|
|
66
|
+
* Automatically rotates old logs if thresholds are exceeded.
|
|
67
|
+
*
|
|
62
68
|
* @returns Path to the written log file
|
|
63
69
|
*/
|
|
64
70
|
finalize(): Promise<string>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"log-writer.d.ts","sourceRoot":"","sources":["../../../../src/lib/workflow/log-writer.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAKH,OAAO,EACL,KAAK,MAAM,EACX,KAAK,SAAS,EAEd,KAAK,QAAQ,EACb,KAAK,KAAK,EAMX,MAAM,qBAAqB,CAAC;
|
|
1
|
+
{"version":3,"file":"log-writer.d.ts","sourceRoot":"","sources":["../../../../src/lib/workflow/log-writer.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAKH,OAAO,EACL,KAAK,MAAM,EACX,KAAK,SAAS,EAEd,KAAK,QAAQ,EACb,KAAK,KAAK,EAMX,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EAEL,KAAK,gBAAgB,EAEtB,MAAM,mBAAmB,CAAC;AAE3B,MAAM,WAAW,gBAAgB;IAC/B,0EAA0E;IAC1E,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,+CAA+C;IAC/C,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B,6BAA6B;IAC7B,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,4BAA4B;IAC5B,QAAQ,CAAC,EAAE,gBAAgB,CAAC;CAC7B;AAED;;GAEG;AACH,qBAAa,SAAS;IACpB,OAAO,CAAC,MAAM,CAAwC;IACtD,OAAO,CAAC,YAAY,CAAkC;IACtD,OAAO,CAAC,OAAO,CAAS;IACxB,OAAO,CAAC,eAAe,CAAU;IACjC,OAAO,CAAC,OAAO,CAAU;IACzB,OAAO,CAAC,QAAQ,CAAmB;gBAEvB,OAAO,GAAE,gBAAqB;IAO1C;;;;OAIG;IACG,UAAU,CAAC,MAAM,EAAE,SAAS,GAAG,OAAO,CAAC,IAAI,CAAC;IAgBlD;;;;;;OAMG;IACH,UAAU,CAAC,WAAW,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,GAAG,IAAI;IAmBtE;;;;OAIG;IACH,QAAQ,CAAC,QAAQ,EAAE,QAAQ,GAAG,IAAI;IAwBlC;;OAEG;IACH,aAAa,IAAI,IAAI;IA+BrB;;;;;;OAMG;IACG,QAAQ,IAAI,OAAO,CAAC,MAAM,CAAC;IA2CjC;;OAEG;IACH,SAAS,IAAI,IAAI,CAAC,MAAM,EAAE,SAAS,CAAC,GAAG,IAAI;IAI3C;;OAEG;IACH,QAAQ,IAAI,MAAM,GAAG,IAAI;IAIzB,OAAO,CAAC,WAAW;YAIL,kBAAkB;YAOlB,YAAY;CAO3B;AAED;;;;GAIG;AACH,wBAAgB,wBAAwB,CACtC,KAAK,EAAE,KAAK,EACZ,WAAW,EAAE,MAAM,EACnB,SAAS,EAAE,IAAI,EACf,OAAO,EAAE,IAAI,EACb,MAAM,EAAE,QAAQ,CAAC,QAAQ,CAAC,EAC1B,OAAO,CAAC,EAAE,OAAO,CACf,IAAI,CACF,QAAQ,EACR,OAAO,GAAG,YAAY,GAAG,eAAe,GAAG,UAAU,GAAG,aAAa,CACtE,CACF,GACA,QAAQ,CAYV"}
|
|
@@ -17,6 +17,7 @@ import * as fs from "fs";
|
|
|
17
17
|
import * as path from "path";
|
|
18
18
|
import * as os from "os";
|
|
19
19
|
import { createEmptyRunLog, finalizeRunLog, generateLogFilename, LOG_PATHS, } from "./run-log-schema.js";
|
|
20
|
+
import { rotateIfNeeded, DEFAULT_ROTATION_SETTINGS, } from "./log-rotation.js";
|
|
20
21
|
/**
|
|
21
22
|
* Manages writing structured run logs to disk
|
|
22
23
|
*/
|
|
@@ -26,10 +27,12 @@ export class LogWriter {
|
|
|
26
27
|
logPath;
|
|
27
28
|
writeToUserLogs;
|
|
28
29
|
verbose;
|
|
30
|
+
rotation;
|
|
29
31
|
constructor(options = {}) {
|
|
30
32
|
this.logPath = options.logPath ?? LOG_PATHS.project;
|
|
31
33
|
this.writeToUserLogs = options.writeToUserLogs ?? false;
|
|
32
34
|
this.verbose = options.verbose ?? false;
|
|
35
|
+
this.rotation = options.rotation ?? DEFAULT_ROTATION_SETTINGS;
|
|
33
36
|
}
|
|
34
37
|
/**
|
|
35
38
|
* Initialize a new run log
|
|
@@ -119,6 +122,8 @@ export class LogWriter {
|
|
|
119
122
|
/**
|
|
120
123
|
* Finalize the run log and write to disk
|
|
121
124
|
*
|
|
125
|
+
* Automatically rotates old logs if thresholds are exceeded.
|
|
126
|
+
*
|
|
122
127
|
* @returns Path to the written log file
|
|
123
128
|
*/
|
|
124
129
|
async finalize() {
|
|
@@ -142,6 +147,13 @@ export class LogWriter {
|
|
|
142
147
|
if (this.verbose) {
|
|
143
148
|
console.log(`📝 Log written: ${projectPath}`);
|
|
144
149
|
}
|
|
150
|
+
// Auto-rotate if needed
|
|
151
|
+
if (this.rotation.enabled) {
|
|
152
|
+
const result = rotateIfNeeded(this.logPath, this.rotation);
|
|
153
|
+
if (result.rotated && this.verbose) {
|
|
154
|
+
console.log(`📝 Rotated ${result.deletedCount} old log(s), reclaimed ${(result.bytesReclaimed / 1024).toFixed(1)} KB`);
|
|
155
|
+
}
|
|
156
|
+
}
|
|
145
157
|
return projectPath;
|
|
146
158
|
}
|
|
147
159
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"log-writer.js","sourceRoot":"","sources":["../../../../src/lib/workflow/log-writer.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH,OAAO,KAAK,EAAE,MAAM,IAAI,CAAC;AACzB,OAAO,KAAK,IAAI,MAAM,MAAM,CAAC;AAC7B,OAAO,KAAK,EAAE,MAAM,IAAI,CAAC;AACzB,OAAO,EAOL,iBAAiB,EACjB,cAAc,EACd,mBAAmB,EACnB,SAAS,GACV,MAAM,qBAAqB,CAAC;
|
|
1
|
+
{"version":3,"file":"log-writer.js","sourceRoot":"","sources":["../../../../src/lib/workflow/log-writer.ts"],"names":[],"mappings":"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"}
|
|
@@ -8,11 +8,14 @@ import * as fs from "fs";
|
|
|
8
8
|
import * as path from "path";
|
|
9
9
|
import * as os from "os";
|
|
10
10
|
import { LogWriter, createPhaseLogFromTiming } from "./log-writer.js";
|
|
11
|
-
// Mock fs module
|
|
11
|
+
// Mock fs module - include all functions needed by log-rotation.ts
|
|
12
12
|
vi.mock("fs", () => ({
|
|
13
13
|
existsSync: vi.fn(),
|
|
14
14
|
mkdirSync: vi.fn(),
|
|
15
15
|
writeFileSync: vi.fn(),
|
|
16
|
+
readdirSync: vi.fn(() => []),
|
|
17
|
+
statSync: vi.fn(() => ({ mtime: new Date(), size: 1024 })),
|
|
18
|
+
unlinkSync: vi.fn(),
|
|
16
19
|
}));
|
|
17
20
|
// Mock crypto.randomUUID for deterministic tests
|
|
18
21
|
const mockUUID = "12345678-1234-1234-1234-123456789abc";
|