agileflow 2.94.1 → 2.95.0
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 +15 -0
- package/lib/colors.generated.js +117 -0
- package/lib/colors.js +59 -109
- package/lib/generator-factory.js +333 -0
- package/lib/path-utils.js +49 -0
- package/lib/session-registry.js +25 -15
- package/lib/smart-json-file.js +40 -32
- package/lib/state-machine.js +286 -0
- package/package.json +1 -1
- package/scripts/agileflow-configure.js +7 -6
- package/scripts/archive-completed-stories.sh +86 -11
- package/scripts/babysit-context-restore.js +89 -0
- package/scripts/claude-tmux.sh +111 -5
- package/scripts/damage-control/bash-tool-damage-control.js +11 -247
- package/scripts/damage-control/edit-tool-damage-control.js +9 -249
- package/scripts/damage-control/write-tool-damage-control.js +9 -244
- package/scripts/generate-colors.js +314 -0
- package/scripts/lib/colors.generated.sh +82 -0
- package/scripts/lib/colors.sh +10 -70
- package/scripts/lib/configure-features.js +401 -0
- package/scripts/lib/context-loader.js +181 -52
- package/scripts/precompact-context.sh +54 -17
- package/scripts/session-coordinator.sh +2 -2
- package/scripts/session-manager.js +653 -10
- package/src/core/commands/audit.md +93 -0
- package/src/core/commands/auto.md +73 -0
- package/src/core/commands/babysit.md +169 -13
- package/src/core/commands/baseline.md +73 -0
- package/src/core/commands/batch.md +64 -0
- package/src/core/commands/blockers.md +60 -0
- package/src/core/commands/board.md +66 -0
- package/src/core/commands/choose.md +77 -0
- package/src/core/commands/ci.md +77 -0
- package/src/core/commands/compress.md +27 -1
- package/src/core/commands/configure.md +126 -10
- package/src/core/commands/council.md +74 -0
- package/src/core/commands/debt.md +72 -0
- package/src/core/commands/deploy.md +73 -0
- package/src/core/commands/deps.md +68 -0
- package/src/core/commands/docs.md +60 -0
- package/src/core/commands/feedback.md +68 -0
- package/src/core/commands/ideate.md +74 -0
- package/src/core/commands/impact.md +74 -0
- package/src/core/commands/install.md +529 -0
- package/src/core/commands/maintain.md +558 -0
- package/src/core/commands/metrics.md +75 -0
- package/src/core/commands/multi-expert.md +74 -0
- package/src/core/commands/packages.md +69 -0
- package/src/core/commands/readme-sync.md +64 -0
- package/src/core/commands/research/analyze.md +285 -121
- package/src/core/commands/research/import.md +281 -109
- package/src/core/commands/retro.md +76 -0
- package/src/core/commands/review.md +72 -0
- package/src/core/commands/rlm.md +83 -0
- package/src/core/commands/rpi.md +90 -0
- package/src/core/commands/session/cleanup.md +214 -12
- package/src/core/commands/session/end.md +155 -17
- package/src/core/commands/sprint.md +72 -0
- package/src/core/commands/story-validate.md +68 -0
- package/src/core/commands/template.md +69 -0
- package/src/core/commands/tests.md +83 -0
- package/src/core/commands/update.md +59 -0
- package/src/core/commands/validate-expertise.md +76 -0
- package/src/core/commands/velocity.md +74 -0
- package/src/core/commands/verify.md +91 -0
- package/src/core/commands/whats-new.md +69 -0
- package/src/core/commands/workflow.md +88 -0
- package/src/core/templates/command-documentation.md +187 -0
- package/tools/cli/commands/session.js +1171 -0
- package/tools/cli/commands/setup.js +2 -81
- package/tools/cli/installers/core/installer.js +0 -5
- package/tools/cli/installers/ide/claude-code.js +6 -0
- package/tools/cli/lib/config-manager.js +42 -5
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* path-utils.js - Unified Path Utilities Module
|
|
3
|
+
*
|
|
4
|
+
* This module consolidates all path-related utilities for AgileFlow CLI.
|
|
5
|
+
* It re-exports from validate-paths.js for backwards compatibility and
|
|
6
|
+
* discoverability, while adding path resolution helpers from path-resolver.js.
|
|
7
|
+
*
|
|
8
|
+
* US-0194: Consolidate Path Matching and Validation Logic
|
|
9
|
+
*
|
|
10
|
+
* Features:
|
|
11
|
+
* - Path traversal prevention (validatePath, hasUnsafePathPatterns)
|
|
12
|
+
* - Symlink chain validation (checkSymlinkChainDepth)
|
|
13
|
+
* - Filename sanitization (sanitizeFilename)
|
|
14
|
+
* - Path resolution with project root detection (PathResolver)
|
|
15
|
+
*
|
|
16
|
+
* Usage:
|
|
17
|
+
* const { validatePath, PathResolver } = require('./path-utils');
|
|
18
|
+
*
|
|
19
|
+
* // Validate a path is safe and within base directory
|
|
20
|
+
* const result = validatePath('./config.yaml', '/project/root', { allowSymlinks: false });
|
|
21
|
+
*
|
|
22
|
+
* // Use PathResolver for project-aware path operations
|
|
23
|
+
* const resolver = new PathResolver('/project/root');
|
|
24
|
+
* const docsPath = resolver.getDocsDir();
|
|
25
|
+
*/
|
|
26
|
+
|
|
27
|
+
// Re-export all path validation utilities from validate-paths.js
|
|
28
|
+
const validatePaths = require('./validate-paths');
|
|
29
|
+
|
|
30
|
+
// Re-export PathResolver for convenient access
|
|
31
|
+
const { PathResolver, getDefaultResolver, getAllPaths } = require('./path-resolver');
|
|
32
|
+
|
|
33
|
+
module.exports = {
|
|
34
|
+
// Path validation (from validate-paths.js)
|
|
35
|
+
PathValidationError: validatePaths.PathValidationError,
|
|
36
|
+
checkSymlinkChainDepth: validatePaths.checkSymlinkChainDepth,
|
|
37
|
+
validatePath: validatePaths.validatePath,
|
|
38
|
+
validatePathSync: validatePaths.validatePathSync,
|
|
39
|
+
hasUnsafePathPatterns: validatePaths.hasUnsafePathPatterns,
|
|
40
|
+
sanitizeFilename: validatePaths.sanitizeFilename,
|
|
41
|
+
|
|
42
|
+
// Path resolution (from path-resolver.js)
|
|
43
|
+
PathResolver,
|
|
44
|
+
getDefaultResolver,
|
|
45
|
+
getAllPaths,
|
|
46
|
+
|
|
47
|
+
// Convenience: full module access for advanced usage
|
|
48
|
+
paths: validatePaths,
|
|
49
|
+
};
|
package/lib/session-registry.js
CHANGED
|
@@ -32,6 +32,7 @@ const EventEmitter = require('events');
|
|
|
32
32
|
const fs = require('fs');
|
|
33
33
|
const path = require('path');
|
|
34
34
|
const SmartJsonFile = require('./smart-json-file');
|
|
35
|
+
const { success, failure, failureFromError } = require('./result-schema');
|
|
35
36
|
|
|
36
37
|
/**
|
|
37
38
|
* Session Registry Event Bus
|
|
@@ -286,13 +287,13 @@ class SessionRegistry extends EventEmitter {
|
|
|
286
287
|
/**
|
|
287
288
|
* Unregister a session
|
|
288
289
|
* @param {number|string} sessionId - Session ID
|
|
289
|
-
* @returns {Promise<{
|
|
290
|
+
* @returns {Promise<Result<{found: boolean}>>}
|
|
290
291
|
*/
|
|
291
292
|
async unregisterSession(sessionId) {
|
|
292
293
|
const registry = await this.load(true);
|
|
293
294
|
|
|
294
295
|
if (!registry.sessions || !registry.sessions[sessionId]) {
|
|
295
|
-
return {
|
|
296
|
+
return success({ found: false });
|
|
296
297
|
}
|
|
297
298
|
|
|
298
299
|
delete registry.sessions[sessionId];
|
|
@@ -301,23 +302,25 @@ class SessionRegistry extends EventEmitter {
|
|
|
301
302
|
if (result.ok) {
|
|
302
303
|
this._auditLog('unregister', { sessionId });
|
|
303
304
|
this.emit('unregistered', { sessionId });
|
|
304
|
-
return {
|
|
305
|
+
return success({ found: true });
|
|
305
306
|
}
|
|
306
307
|
|
|
307
|
-
return
|
|
308
|
+
return failure('EUNKNOWN', result.error || 'Failed to save registry', {
|
|
309
|
+
context: { found: true },
|
|
310
|
+
});
|
|
308
311
|
}
|
|
309
312
|
|
|
310
313
|
/**
|
|
311
314
|
* Update a session
|
|
312
315
|
* @param {number|string} sessionId - Session ID
|
|
313
316
|
* @param {Object} updates - Fields to update
|
|
314
|
-
* @returns {Promise<{
|
|
317
|
+
* @returns {Promise<Result<{found: boolean}>>}
|
|
315
318
|
*/
|
|
316
319
|
async updateSession(sessionId, updates) {
|
|
317
320
|
const registry = await this.load(true);
|
|
318
321
|
|
|
319
322
|
if (!registry.sessions || !registry.sessions[sessionId]) {
|
|
320
|
-
return
|
|
323
|
+
return failure('ENOENT', `Session ${sessionId} not found`, { context: { found: false } });
|
|
321
324
|
}
|
|
322
325
|
|
|
323
326
|
registry.sessions[sessionId] = {
|
|
@@ -331,10 +334,12 @@ class SessionRegistry extends EventEmitter {
|
|
|
331
334
|
if (result.ok) {
|
|
332
335
|
this._auditLog('update', { sessionId, updates });
|
|
333
336
|
this.emit('updated', { sessionId, changes: updates });
|
|
334
|
-
return {
|
|
337
|
+
return success({ found: true });
|
|
335
338
|
}
|
|
336
339
|
|
|
337
|
-
return
|
|
340
|
+
return failure('EUNKNOWN', result.error || 'Failed to save registry', {
|
|
341
|
+
context: { found: true },
|
|
342
|
+
});
|
|
338
343
|
}
|
|
339
344
|
|
|
340
345
|
/**
|
|
@@ -359,11 +364,11 @@ class SessionRegistry extends EventEmitter {
|
|
|
359
364
|
|
|
360
365
|
/**
|
|
361
366
|
* Commit all batched changes in one write
|
|
362
|
-
* @returns {Promise<{
|
|
367
|
+
* @returns {Promise<Result<{applied: number}>>}
|
|
363
368
|
*/
|
|
364
369
|
async commitBatch() {
|
|
365
370
|
if (!this._batchMode) {
|
|
366
|
-
return
|
|
371
|
+
return failure('EINVAL', 'Not in batch mode', { context: { applied: 0 } });
|
|
367
372
|
}
|
|
368
373
|
|
|
369
374
|
const registry = await this.load(true);
|
|
@@ -415,10 +420,10 @@ class SessionRegistry extends EventEmitter {
|
|
|
415
420
|
|
|
416
421
|
if (result.ok) {
|
|
417
422
|
this._auditLog('batch', { applied });
|
|
418
|
-
return {
|
|
423
|
+
return success({ applied });
|
|
419
424
|
}
|
|
420
425
|
|
|
421
|
-
return
|
|
426
|
+
return failure('EUNKNOWN', result.error || 'Failed to save registry', { context: { applied } });
|
|
422
427
|
}
|
|
423
428
|
|
|
424
429
|
/**
|
|
@@ -447,7 +452,7 @@ class SessionRegistry extends EventEmitter {
|
|
|
447
452
|
/**
|
|
448
453
|
* Clean up stale sessions
|
|
449
454
|
* @param {Function} isAlive - Function to check if session is alive (sessionId) => boolean
|
|
450
|
-
* @returns {Promise<{
|
|
455
|
+
* @returns {Promise<Result<{cleaned: number}>>}
|
|
451
456
|
*/
|
|
452
457
|
async cleanupStaleSessions(isAlive) {
|
|
453
458
|
const registry = await this.load(true);
|
|
@@ -464,10 +469,15 @@ class SessionRegistry extends EventEmitter {
|
|
|
464
469
|
|
|
465
470
|
if (cleaned > 0) {
|
|
466
471
|
const result = await this.save(registry);
|
|
467
|
-
|
|
472
|
+
if (!result.ok) {
|
|
473
|
+
return failure('EUNKNOWN', result.error || 'Failed to save registry', {
|
|
474
|
+
context: { cleaned },
|
|
475
|
+
});
|
|
476
|
+
}
|
|
477
|
+
return success({ cleaned });
|
|
468
478
|
}
|
|
469
479
|
|
|
470
|
-
return {
|
|
480
|
+
return success({ cleaned: 0 });
|
|
471
481
|
}
|
|
472
482
|
}
|
|
473
483
|
|
package/lib/smart-json-file.js
CHANGED
|
@@ -31,6 +31,7 @@
|
|
|
31
31
|
const fs = require('fs');
|
|
32
32
|
const path = require('path');
|
|
33
33
|
const { createTypedError, getErrorCodeFromError, ErrorCodes } = require('./error-codes');
|
|
34
|
+
const { success, failure, failureFromError } = require('./result-schema');
|
|
34
35
|
|
|
35
36
|
// Debug logging
|
|
36
37
|
const DEBUG = process.env.AGILEFLOW_DEBUG === '1';
|
|
@@ -54,7 +55,7 @@ const SECURE_FILE_MODE = 0o600;
|
|
|
54
55
|
function checkFilePermissions(mode) {
|
|
55
56
|
// Skip permission checks on Windows (different permission model)
|
|
56
57
|
if (process.platform === 'win32') {
|
|
57
|
-
return
|
|
58
|
+
return success(undefined);
|
|
58
59
|
}
|
|
59
60
|
|
|
60
61
|
// Extract permission bits (last 9 bits)
|
|
@@ -106,7 +107,7 @@ function checkFilePermissions(mode) {
|
|
|
106
107
|
};
|
|
107
108
|
}
|
|
108
109
|
|
|
109
|
-
return
|
|
110
|
+
return success(undefined);
|
|
110
111
|
}
|
|
111
112
|
|
|
112
113
|
/**
|
|
@@ -117,13 +118,13 @@ function checkFilePermissions(mode) {
|
|
|
117
118
|
function setSecurePermissions(filePath) {
|
|
118
119
|
// Skip on Windows
|
|
119
120
|
if (process.platform === 'win32') {
|
|
120
|
-
return
|
|
121
|
+
return success(undefined);
|
|
121
122
|
}
|
|
122
123
|
|
|
123
124
|
try {
|
|
124
125
|
fs.chmodSync(filePath, SECURE_FILE_MODE);
|
|
125
126
|
debugLog('setSecurePermissions', { filePath, mode: SECURE_FILE_MODE.toString(8) });
|
|
126
|
-
return
|
|
127
|
+
return success(undefined);
|
|
127
128
|
} catch (err) {
|
|
128
129
|
const error = createTypedError(
|
|
129
130
|
`Failed to set secure permissions on ${filePath}: ${err.message}`,
|
|
@@ -133,7 +134,7 @@ function setSecurePermissions(filePath) {
|
|
|
133
134
|
context: { filePath, mode: SECURE_FILE_MODE },
|
|
134
135
|
}
|
|
135
136
|
);
|
|
136
|
-
return
|
|
137
|
+
return failureFromError(error);
|
|
137
138
|
}
|
|
138
139
|
}
|
|
139
140
|
|
|
@@ -221,12 +222,12 @@ class SmartJsonFile {
|
|
|
221
222
|
if (!fs.existsSync(this.filePath)) {
|
|
222
223
|
if (this.defaultValue !== undefined) {
|
|
223
224
|
debugLog('read', { status: 'using default value' });
|
|
224
|
-
return
|
|
225
|
+
return success(this.defaultValue);
|
|
225
226
|
}
|
|
226
227
|
const error = createTypedError(`File not found: ${this.filePath}`, 'ENOENT', {
|
|
227
228
|
context: { filePath: this.filePath },
|
|
228
229
|
});
|
|
229
|
-
return
|
|
230
|
+
return failureFromError(error);
|
|
230
231
|
}
|
|
231
232
|
|
|
232
233
|
// Read file
|
|
@@ -257,7 +258,7 @@ class SmartJsonFile {
|
|
|
257
258
|
'EPARSE',
|
|
258
259
|
{ cause: parseError, context: { filePath: this.filePath } }
|
|
259
260
|
);
|
|
260
|
-
return
|
|
261
|
+
return failureFromError(error);
|
|
261
262
|
}
|
|
262
263
|
|
|
263
264
|
// Validate schema if provided
|
|
@@ -270,12 +271,12 @@ class SmartJsonFile {
|
|
|
270
271
|
'ESCHEMA',
|
|
271
272
|
{ cause: schemaError, context: { filePath: this.filePath } }
|
|
272
273
|
);
|
|
273
|
-
return
|
|
274
|
+
return failureFromError(error);
|
|
274
275
|
}
|
|
275
276
|
}
|
|
276
277
|
|
|
277
278
|
debugLog('read', { status: 'success' });
|
|
278
|
-
return
|
|
279
|
+
return success(data);
|
|
279
280
|
} catch (err) {
|
|
280
281
|
lastError = err;
|
|
281
282
|
debugLog('read', { status: 'error', error: err.message, attempt });
|
|
@@ -288,7 +289,7 @@ class SmartJsonFile {
|
|
|
288
289
|
cause: err,
|
|
289
290
|
context: { filePath: this.filePath },
|
|
290
291
|
});
|
|
291
|
-
return
|
|
292
|
+
return failureFromError(error);
|
|
292
293
|
}
|
|
293
294
|
|
|
294
295
|
// Wait before retrying
|
|
@@ -308,7 +309,7 @@ class SmartJsonFile {
|
|
|
308
309
|
'EUNKNOWN',
|
|
309
310
|
{ cause: lastError, context: { filePath: this.filePath, attempts: this.retries + 1 } }
|
|
310
311
|
);
|
|
311
|
-
return
|
|
312
|
+
return failureFromError(error);
|
|
312
313
|
}
|
|
313
314
|
|
|
314
315
|
/**
|
|
@@ -330,7 +331,7 @@ class SmartJsonFile {
|
|
|
330
331
|
'ESCHEMA',
|
|
331
332
|
{ cause: schemaError, context: { filePath: this.filePath } }
|
|
332
333
|
);
|
|
333
|
-
return
|
|
334
|
+
return failureFromError(error);
|
|
334
335
|
}
|
|
335
336
|
}
|
|
336
337
|
|
|
@@ -368,7 +369,7 @@ class SmartJsonFile {
|
|
|
368
369
|
|
|
369
370
|
debugLog('write', { status: 'success' });
|
|
370
371
|
|
|
371
|
-
return
|
|
372
|
+
return success(undefined);
|
|
372
373
|
} catch (err) {
|
|
373
374
|
lastError = err;
|
|
374
375
|
debugLog('write', { status: 'error', error: err.message, attempt });
|
|
@@ -394,7 +395,7 @@ class SmartJsonFile {
|
|
|
394
395
|
errorCode.code,
|
|
395
396
|
{ cause: err, context: { filePath: this.filePath } }
|
|
396
397
|
);
|
|
397
|
-
return
|
|
398
|
+
return failureFromError(error);
|
|
398
399
|
}
|
|
399
400
|
|
|
400
401
|
// Wait before retrying
|
|
@@ -414,7 +415,7 @@ class SmartJsonFile {
|
|
|
414
415
|
'EUNKNOWN',
|
|
415
416
|
{ cause: lastError, context: { filePath: this.filePath, attempts: this.retries + 1 } }
|
|
416
417
|
);
|
|
417
|
-
return
|
|
418
|
+
return failureFromError(error);
|
|
418
419
|
}
|
|
419
420
|
|
|
420
421
|
/**
|
|
@@ -447,7 +448,7 @@ class SmartJsonFile {
|
|
|
447
448
|
cause: modifyError,
|
|
448
449
|
context: { filePath: this.filePath },
|
|
449
450
|
});
|
|
450
|
-
return
|
|
451
|
+
return failureFromError(error);
|
|
451
452
|
}
|
|
452
453
|
|
|
453
454
|
// Write modified data
|
|
@@ -456,7 +457,7 @@ class SmartJsonFile {
|
|
|
456
457
|
return writeResult;
|
|
457
458
|
}
|
|
458
459
|
|
|
459
|
-
return
|
|
460
|
+
return success(newData);
|
|
460
461
|
}
|
|
461
462
|
|
|
462
463
|
/**
|
|
@@ -474,12 +475,12 @@ class SmartJsonFile {
|
|
|
474
475
|
async delete() {
|
|
475
476
|
try {
|
|
476
477
|
if (!fs.existsSync(this.filePath)) {
|
|
477
|
-
return
|
|
478
|
+
return success(undefined); // Already doesn't exist
|
|
478
479
|
}
|
|
479
480
|
|
|
480
481
|
fs.unlinkSync(this.filePath);
|
|
481
482
|
debugLog('delete', { filePath: this.filePath, status: 'success' });
|
|
482
|
-
return
|
|
483
|
+
return success(undefined);
|
|
483
484
|
} catch (err) {
|
|
484
485
|
const errorCode = getErrorCodeFromError(err);
|
|
485
486
|
const error = createTypedError(
|
|
@@ -487,7 +488,7 @@ class SmartJsonFile {
|
|
|
487
488
|
errorCode.code,
|
|
488
489
|
{ cause: err, context: { filePath: this.filePath } }
|
|
489
490
|
);
|
|
490
|
-
return
|
|
491
|
+
return failureFromError(error);
|
|
491
492
|
}
|
|
492
493
|
}
|
|
493
494
|
|
|
@@ -499,12 +500,12 @@ class SmartJsonFile {
|
|
|
499
500
|
try {
|
|
500
501
|
if (!fs.existsSync(this.filePath)) {
|
|
501
502
|
if (this.defaultValue !== undefined) {
|
|
502
|
-
return
|
|
503
|
+
return success(this.defaultValue);
|
|
503
504
|
}
|
|
504
505
|
const error = createTypedError(`File not found: ${this.filePath}`, 'ENOENT', {
|
|
505
506
|
context: { filePath: this.filePath },
|
|
506
507
|
});
|
|
507
|
-
return
|
|
508
|
+
return failureFromError(error);
|
|
508
509
|
}
|
|
509
510
|
|
|
510
511
|
const content = fs.readFileSync(this.filePath, 'utf8');
|
|
@@ -514,7 +515,7 @@ class SmartJsonFile {
|
|
|
514
515
|
this.schema(data);
|
|
515
516
|
}
|
|
516
517
|
|
|
517
|
-
return
|
|
518
|
+
return success(data);
|
|
518
519
|
} catch (err) {
|
|
519
520
|
const errorCode = getErrorCodeFromError(err);
|
|
520
521
|
const error = createTypedError(
|
|
@@ -522,7 +523,7 @@ class SmartJsonFile {
|
|
|
522
523
|
errorCode.code,
|
|
523
524
|
{ cause: err, context: { filePath: this.filePath } }
|
|
524
525
|
);
|
|
525
|
-
return
|
|
526
|
+
return failureFromError(error);
|
|
526
527
|
}
|
|
527
528
|
}
|
|
528
529
|
|
|
@@ -559,7 +560,7 @@ class SmartJsonFile {
|
|
|
559
560
|
}
|
|
560
561
|
}
|
|
561
562
|
|
|
562
|
-
return
|
|
563
|
+
return success(undefined);
|
|
563
564
|
} catch (err) {
|
|
564
565
|
// Clean up temp file
|
|
565
566
|
try {
|
|
@@ -576,7 +577,7 @@ class SmartJsonFile {
|
|
|
576
577
|
errorCode.code,
|
|
577
578
|
{ cause: err, context: { filePath: this.filePath } }
|
|
578
579
|
);
|
|
579
|
-
return
|
|
580
|
+
return failureFromError(error);
|
|
580
581
|
}
|
|
581
582
|
}
|
|
582
583
|
}
|
|
@@ -594,7 +595,7 @@ const DEFAULT_TEMP_MAX_AGE_MS = 24 * 60 * 60 * 1000;
|
|
|
594
595
|
* @param {Object} [options={}] - Cleanup options
|
|
595
596
|
* @param {number} [options.maxAgeMs=86400000] - Max age in ms (default: 24 hours)
|
|
596
597
|
* @param {boolean} [options.dryRun=false] - Don't delete, just report
|
|
597
|
-
* @returns {{
|
|
598
|
+
* @returns {Result<{cleaned: string[], errors: string[]}>}
|
|
598
599
|
*/
|
|
599
600
|
function cleanupTempFiles(directory, options = {}) {
|
|
600
601
|
const { maxAgeMs = DEFAULT_TEMP_MAX_AGE_MS, dryRun = false } = options;
|
|
@@ -604,7 +605,7 @@ function cleanupTempFiles(directory, options = {}) {
|
|
|
604
605
|
|
|
605
606
|
try {
|
|
606
607
|
if (!fs.existsSync(directory)) {
|
|
607
|
-
return {
|
|
608
|
+
return success({ cleaned, errors });
|
|
608
609
|
}
|
|
609
610
|
|
|
610
611
|
const now = Date.now();
|
|
@@ -646,10 +647,17 @@ function cleanupTempFiles(directory, options = {}) {
|
|
|
646
647
|
}
|
|
647
648
|
}
|
|
648
649
|
|
|
649
|
-
|
|
650
|
+
if (errors.length > 0) {
|
|
651
|
+
return failure('EUNKNOWN', 'Some temp files could not be cleaned', {
|
|
652
|
+
context: { cleaned, errors },
|
|
653
|
+
});
|
|
654
|
+
}
|
|
655
|
+
return success({ cleaned, errors });
|
|
650
656
|
} catch (err) {
|
|
651
657
|
errors.push(`Directory read error: ${err.message}`);
|
|
652
|
-
return
|
|
658
|
+
return failure('EUNKNOWN', `Directory read error: ${err.message}`, {
|
|
659
|
+
context: { cleaned, errors },
|
|
660
|
+
});
|
|
653
661
|
}
|
|
654
662
|
}
|
|
655
663
|
|
|
@@ -658,7 +666,7 @@ function cleanupTempFiles(directory, options = {}) {
|
|
|
658
666
|
*
|
|
659
667
|
* @param {string} filePath - Path to the JSON file
|
|
660
668
|
* @param {Object} [options={}] - Cleanup options
|
|
661
|
-
* @returns {{
|
|
669
|
+
* @returns {Result<{cleaned: string[], errors: string[]}>}
|
|
662
670
|
*/
|
|
663
671
|
function cleanupTempFilesFor(filePath, options = {}) {
|
|
664
672
|
const directory = path.dirname(filePath);
|