@defai.digital/ax-cli 4.1.10 → 4.1.14
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/.ax-cli/settings.json +1 -0
- package/README.md +140 -589
- package/dist/agent/dependency-resolver.d.ts +7 -0
- package/dist/agent/dependency-resolver.js +46 -18
- package/dist/agent/dependency-resolver.js.map +1 -1
- package/dist/agent/execution/tool-executor.d.ts +4 -0
- package/dist/agent/execution/tool-executor.js +76 -52
- package/dist/agent/execution/tool-executor.js.map +1 -1
- package/dist/agent/parallel-tools.d.ts +4 -0
- package/dist/agent/parallel-tools.js +65 -24
- package/dist/agent/parallel-tools.js.map +1 -1
- package/dist/agent/planning/plan-executor.d.ts +0 -5
- package/dist/agent/planning/plan-executor.js +23 -6
- package/dist/agent/planning/plan-executor.js.map +1 -1
- package/dist/agent/streaming/stream-handler.js +7 -4
- package/dist/agent/streaming/stream-handler.js.map +1 -1
- package/dist/agent/subagent-orchestrator.d.ts +35 -2
- package/dist/agent/subagent-orchestrator.js +188 -146
- package/dist/agent/subagent-orchestrator.js.map +1 -1
- package/dist/agent/subagent-types.js +3 -1
- package/dist/agent/subagent-types.js.map +1 -1
- package/dist/agent/subagent.d.ts +15 -4
- package/dist/agent/subagent.js +91 -72
- package/dist/agent/subagent.js.map +1 -1
- package/dist/design/figma-alias.d.ts +77 -0
- package/dist/design/figma-alias.js +246 -0
- package/dist/design/figma-alias.js.map +1 -1
- package/dist/design/figma-client.d.ts +4 -0
- package/dist/design/figma-client.js +24 -4
- package/dist/design/figma-client.js.map +1 -1
- package/dist/design/figma-map.js +78 -6
- package/dist/design/figma-map.js.map +1 -1
- package/dist/design/figma-tokens.js +6 -2
- package/dist/design/figma-tokens.js.map +1 -1
- package/dist/design/index.d.ts +1 -1
- package/dist/design/index.js +3 -1
- package/dist/design/index.js.map +1 -1
- package/dist/design/types.d.ts +9 -0
- package/dist/mcp/client-v2.js +4 -0
- package/dist/mcp/client-v2.js.map +1 -1
- package/dist/mcp/config-detector.js +3 -4
- package/dist/mcp/config-detector.js.map +1 -1
- package/dist/mcp/debug.d.ts +207 -0
- package/dist/mcp/debug.js +398 -0
- package/dist/mcp/debug.js.map +1 -0
- package/dist/mcp/index.d.ts +1 -0
- package/dist/mcp/index.js +4 -0
- package/dist/mcp/index.js.map +1 -1
- package/dist/mcp/reconnection.js +6 -3
- package/dist/mcp/reconnection.js.map +1 -1
- package/dist/mcp/validation.js +15 -6
- package/dist/mcp/validation.js.map +1 -1
- package/dist/memory/index.d.ts +1 -0
- package/dist/memory/index.js +2 -0
- package/dist/memory/index.js.map +1 -1
- package/dist/memory/provider-context-store.d.ts +127 -0
- package/dist/memory/provider-context-store.js +385 -0
- package/dist/memory/provider-context-store.js.map +1 -0
- package/dist/sdk/errors.d.ts +2 -0
- package/dist/sdk/errors.js +2 -0
- package/dist/sdk/errors.js.map +1 -1
- package/dist/sdk/index.d.ts +633 -62
- package/dist/sdk/index.js +854 -116
- package/dist/sdk/index.js.map +1 -1
- package/dist/sdk/testing.d.ts +46 -4
- package/dist/sdk/testing.js +58 -6
- package/dist/sdk/testing.js.map +1 -1
- package/dist/sdk/version.d.ts +13 -9
- package/dist/sdk/version.js +13 -9
- package/dist/sdk/version.js.map +1 -1
- package/dist/utils/file-lock.d.ts +141 -0
- package/dist/utils/file-lock.js +559 -0
- package/dist/utils/file-lock.js.map +1 -0
- package/dist/utils/provider-context.d.ts +243 -0
- package/dist/utils/provider-context.js +421 -0
- package/dist/utils/provider-context.js.map +1 -0
- package/dist/utils/provider-file-cache.d.ts +91 -0
- package/dist/utils/provider-file-cache.js +165 -0
- package/dist/utils/provider-file-cache.js.map +1 -0
- package/dist/utils/provider-settings.d.ts +181 -0
- package/dist/utils/provider-settings.js +450 -0
- package/dist/utils/provider-settings.js.map +1 -0
- package/package.json +2 -2
|
@@ -0,0 +1,559 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* File Locking Utility - Cross-process file locking for concurrent access
|
|
3
|
+
*
|
|
4
|
+
* This module provides file-level locking to prevent race conditions when
|
|
5
|
+
* multiple ax-glm and ax-grok instances access the same files.
|
|
6
|
+
*
|
|
7
|
+
* Features:
|
|
8
|
+
* - Cross-process locking using lock files
|
|
9
|
+
* - Automatic stale lock cleanup
|
|
10
|
+
* - Configurable timeouts
|
|
11
|
+
* - Read/write lock semantics
|
|
12
|
+
* - Safe atomic operations
|
|
13
|
+
*
|
|
14
|
+
* @example
|
|
15
|
+
* ```typescript
|
|
16
|
+
* // Exclusive lock for writes
|
|
17
|
+
* await withFileLock('/path/to/file.json', async () => {
|
|
18
|
+
* const data = JSON.parse(fs.readFileSync('/path/to/file.json', 'utf-8'));
|
|
19
|
+
* data.count++;
|
|
20
|
+
* fs.writeFileSync('/path/to/file.json', JSON.stringify(data));
|
|
21
|
+
* });
|
|
22
|
+
*
|
|
23
|
+
* // Read lock (shared)
|
|
24
|
+
* const data = await withFileLock('/path/to/file.json', async () => {
|
|
25
|
+
* return JSON.parse(fs.readFileSync('/path/to/file.json', 'utf-8'));
|
|
26
|
+
* }, { type: 'read' });
|
|
27
|
+
* ```
|
|
28
|
+
*/
|
|
29
|
+
import { existsSync, unlinkSync, writeFileSync, readFileSync, mkdirSync } from 'fs';
|
|
30
|
+
import { dirname, resolve } from 'path';
|
|
31
|
+
import { hostname } from 'os';
|
|
32
|
+
/**
|
|
33
|
+
* Default lock options
|
|
34
|
+
*/
|
|
35
|
+
const DEFAULT_OPTIONS = {
|
|
36
|
+
type: 'write',
|
|
37
|
+
timeout: 10000,
|
|
38
|
+
retryInterval: 50,
|
|
39
|
+
staleThreshold: 30000,
|
|
40
|
+
throwOnTimeout: true,
|
|
41
|
+
};
|
|
42
|
+
/**
|
|
43
|
+
* Get the lock file path for a given file
|
|
44
|
+
*/
|
|
45
|
+
export function getLockPath(filePath) {
|
|
46
|
+
return `${resolve(filePath)}.lock`;
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Get current hostname (cached for performance)
|
|
50
|
+
*/
|
|
51
|
+
let cachedHostname = null;
|
|
52
|
+
function getHostname() {
|
|
53
|
+
if (!cachedHostname) {
|
|
54
|
+
cachedHostname = hostname();
|
|
55
|
+
}
|
|
56
|
+
return cachedHostname;
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Track re-entrant lock count per file (for same process)
|
|
60
|
+
* Key: lockPath, Value: count
|
|
61
|
+
*/
|
|
62
|
+
const reentrantLockCounts = new Map();
|
|
63
|
+
/**
|
|
64
|
+
* Get re-entry count for a lock
|
|
65
|
+
*/
|
|
66
|
+
function getReentryCount(lockPath) {
|
|
67
|
+
return reentrantLockCounts.get(lockPath) || 0;
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* Increment re-entry count
|
|
71
|
+
*/
|
|
72
|
+
function incrementReentryCount(lockPath) {
|
|
73
|
+
const count = getReentryCount(lockPath);
|
|
74
|
+
reentrantLockCounts.set(lockPath, count + 1);
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* Decrement re-entry count, returns true if lock should be released
|
|
78
|
+
*/
|
|
79
|
+
function decrementReentryCount(lockPath) {
|
|
80
|
+
const count = getReentryCount(lockPath);
|
|
81
|
+
if (count <= 1) {
|
|
82
|
+
reentrantLockCounts.delete(lockPath);
|
|
83
|
+
return true; // Should release
|
|
84
|
+
}
|
|
85
|
+
reentrantLockCounts.set(lockPath, count - 1);
|
|
86
|
+
return false; // Don't release yet
|
|
87
|
+
}
|
|
88
|
+
/**
|
|
89
|
+
* Check if a lock is stale (process no longer exists or too old)
|
|
90
|
+
*/
|
|
91
|
+
function isLockStale(lockContent, staleThreshold) {
|
|
92
|
+
const now = Date.now();
|
|
93
|
+
const age = now - lockContent.timestamp;
|
|
94
|
+
// Check if lock is too old
|
|
95
|
+
if (age > staleThreshold) {
|
|
96
|
+
return true;
|
|
97
|
+
}
|
|
98
|
+
// Check if the process that created the lock still exists
|
|
99
|
+
// Only check if it's on the same machine (hostname matches)
|
|
100
|
+
if (lockContent.hostname === getHostname()) {
|
|
101
|
+
try {
|
|
102
|
+
// process.kill with signal 0 checks if process exists without killing it
|
|
103
|
+
process.kill(lockContent.pid, 0);
|
|
104
|
+
return false; // Process exists
|
|
105
|
+
}
|
|
106
|
+
catch {
|
|
107
|
+
return true; // Process doesn't exist
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
// Can't verify cross-machine locks, rely on timestamp
|
|
111
|
+
return age > staleThreshold / 2;
|
|
112
|
+
}
|
|
113
|
+
/**
|
|
114
|
+
* Try to read and parse lock file content
|
|
115
|
+
*/
|
|
116
|
+
function readLockFile(lockPath) {
|
|
117
|
+
try {
|
|
118
|
+
if (!existsSync(lockPath)) {
|
|
119
|
+
return null;
|
|
120
|
+
}
|
|
121
|
+
const content = readFileSync(lockPath, 'utf-8');
|
|
122
|
+
return JSON.parse(content);
|
|
123
|
+
}
|
|
124
|
+
catch {
|
|
125
|
+
return null;
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
/**
|
|
129
|
+
* Create lock file content
|
|
130
|
+
*/
|
|
131
|
+
function createLockContent(type) {
|
|
132
|
+
return {
|
|
133
|
+
pid: process.pid,
|
|
134
|
+
hostname: getHostname(),
|
|
135
|
+
timestamp: Date.now(),
|
|
136
|
+
type,
|
|
137
|
+
provider: process.env.AX_PROVIDER,
|
|
138
|
+
};
|
|
139
|
+
}
|
|
140
|
+
/**
|
|
141
|
+
* Attempt to acquire a lock
|
|
142
|
+
* Uses atomic rename pattern for safety
|
|
143
|
+
*
|
|
144
|
+
* NOTE: All locks are treated as exclusive for simplicity and correctness.
|
|
145
|
+
* Implementing true shared read locks requires OS-level primitives (flock/fcntl)
|
|
146
|
+
* which are not portable across platforms. The 'type' parameter is stored
|
|
147
|
+
* in the lock file for debugging purposes only.
|
|
148
|
+
*/
|
|
149
|
+
function tryAcquireLock(filePath, type, staleThreshold) {
|
|
150
|
+
const lockPath = getLockPath(filePath);
|
|
151
|
+
const tempLockPath = `${lockPath}.${process.pid}.${Date.now()}`;
|
|
152
|
+
try {
|
|
153
|
+
// Ensure directory exists
|
|
154
|
+
const dir = dirname(lockPath);
|
|
155
|
+
if (!existsSync(dir)) {
|
|
156
|
+
mkdirSync(dir, { recursive: true });
|
|
157
|
+
}
|
|
158
|
+
// Check existing lock
|
|
159
|
+
const existingLock = readLockFile(lockPath);
|
|
160
|
+
if (existingLock) {
|
|
161
|
+
// Check if we already own the lock (re-entrant)
|
|
162
|
+
if (existingLock.pid === process.pid &&
|
|
163
|
+
existingLock.hostname === getHostname()) {
|
|
164
|
+
// We already own the lock - update timestamp to prevent staleness
|
|
165
|
+
// and increment re-entry count
|
|
166
|
+
try {
|
|
167
|
+
const updatedContent = createLockContent(type);
|
|
168
|
+
writeFileSync(lockPath, JSON.stringify(updatedContent));
|
|
169
|
+
incrementReentryCount(lockPath);
|
|
170
|
+
}
|
|
171
|
+
catch {
|
|
172
|
+
// Failed to update, but we still own it
|
|
173
|
+
}
|
|
174
|
+
return true;
|
|
175
|
+
}
|
|
176
|
+
// Check if stale
|
|
177
|
+
if (!isLockStale(existingLock, staleThreshold)) {
|
|
178
|
+
// Lock is held by another process - wait
|
|
179
|
+
return false;
|
|
180
|
+
}
|
|
181
|
+
// Stale lock, try to remove it
|
|
182
|
+
try {
|
|
183
|
+
unlinkSync(lockPath);
|
|
184
|
+
}
|
|
185
|
+
catch {
|
|
186
|
+
// Another process might have already removed it
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
// Create temp lock file
|
|
190
|
+
const content = createLockContent(type);
|
|
191
|
+
writeFileSync(tempLockPath, JSON.stringify(content), { flag: 'wx' });
|
|
192
|
+
// Attempt atomic rename
|
|
193
|
+
try {
|
|
194
|
+
const fs = require('fs');
|
|
195
|
+
fs.renameSync(tempLockPath, lockPath);
|
|
196
|
+
incrementReentryCount(lockPath); // Track this as first acquisition
|
|
197
|
+
return true;
|
|
198
|
+
}
|
|
199
|
+
catch {
|
|
200
|
+
// Another process got the lock first
|
|
201
|
+
try {
|
|
202
|
+
unlinkSync(tempLockPath);
|
|
203
|
+
}
|
|
204
|
+
catch {
|
|
205
|
+
// Ignore cleanup errors
|
|
206
|
+
}
|
|
207
|
+
return false;
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
catch {
|
|
211
|
+
// Clean up temp file if it exists
|
|
212
|
+
try {
|
|
213
|
+
if (existsSync(tempLockPath)) {
|
|
214
|
+
unlinkSync(tempLockPath);
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
catch {
|
|
218
|
+
// Ignore cleanup errors
|
|
219
|
+
}
|
|
220
|
+
return false;
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
/**
|
|
224
|
+
* Release a lock
|
|
225
|
+
* Handles re-entrant locks by only releasing when count reaches zero
|
|
226
|
+
*/
|
|
227
|
+
function releaseLock(filePath) {
|
|
228
|
+
const lockPath = getLockPath(filePath);
|
|
229
|
+
try {
|
|
230
|
+
// Check re-entry count - only release when all nested locks are released
|
|
231
|
+
const shouldRelease = decrementReentryCount(lockPath);
|
|
232
|
+
if (!shouldRelease) {
|
|
233
|
+
// Still have nested locks, don't release yet
|
|
234
|
+
return;
|
|
235
|
+
}
|
|
236
|
+
// Verify we own the lock before releasing (check both PID and hostname)
|
|
237
|
+
const lockContent = readLockFile(lockPath);
|
|
238
|
+
if (lockContent &&
|
|
239
|
+
lockContent.pid === process.pid &&
|
|
240
|
+
lockContent.hostname === getHostname()) {
|
|
241
|
+
unlinkSync(lockPath);
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
catch {
|
|
245
|
+
// Ignore errors during release
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
/**
|
|
249
|
+
* Sleep for a specified duration
|
|
250
|
+
*/
|
|
251
|
+
function sleep(ms) {
|
|
252
|
+
return new Promise(resolve => setTimeout(resolve, ms));
|
|
253
|
+
}
|
|
254
|
+
/**
|
|
255
|
+
* Acquire a file lock with retry
|
|
256
|
+
*/
|
|
257
|
+
export async function acquireLock(filePath, options = {}) {
|
|
258
|
+
const opts = { ...DEFAULT_OPTIONS, ...options };
|
|
259
|
+
const startTime = Date.now();
|
|
260
|
+
while (Date.now() - startTime < opts.timeout) {
|
|
261
|
+
if (tryAcquireLock(filePath, opts.type, opts.staleThreshold)) {
|
|
262
|
+
return true;
|
|
263
|
+
}
|
|
264
|
+
await sleep(opts.retryInterval);
|
|
265
|
+
}
|
|
266
|
+
if (opts.throwOnTimeout) {
|
|
267
|
+
throw new Error(`Failed to acquire ${opts.type} lock on ${filePath} after ${opts.timeout}ms`);
|
|
268
|
+
}
|
|
269
|
+
return false;
|
|
270
|
+
}
|
|
271
|
+
/**
|
|
272
|
+
* Synchronous sleep using Atomics.wait (if available) or busy wait fallback
|
|
273
|
+
* This is more efficient than a pure spin loop
|
|
274
|
+
*/
|
|
275
|
+
function sleepSync(ms) {
|
|
276
|
+
// Use Atomics.wait if available (Node.js 8.10+)
|
|
277
|
+
// This properly yields the thread instead of spinning
|
|
278
|
+
try {
|
|
279
|
+
const sharedBuffer = new SharedArrayBuffer(4);
|
|
280
|
+
const int32 = new Int32Array(sharedBuffer);
|
|
281
|
+
Atomics.wait(int32, 0, 0, ms);
|
|
282
|
+
}
|
|
283
|
+
catch {
|
|
284
|
+
// Fallback: spin with occasional Date.now() to allow GC
|
|
285
|
+
const end = Date.now() + ms;
|
|
286
|
+
let i = 0;
|
|
287
|
+
while (Date.now() < end) {
|
|
288
|
+
i++;
|
|
289
|
+
// Occasional check to allow event loop to process (every 1000 iterations)
|
|
290
|
+
if (i % 1000 === 0) {
|
|
291
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-expressions
|
|
292
|
+
Date.now();
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
}
|
|
296
|
+
}
|
|
297
|
+
/**
|
|
298
|
+
* Acquire a file lock synchronously (blocking)
|
|
299
|
+
*/
|
|
300
|
+
export function acquireLockSync(filePath, options = {}) {
|
|
301
|
+
const opts = { ...DEFAULT_OPTIONS, ...options };
|
|
302
|
+
const startTime = Date.now();
|
|
303
|
+
while (Date.now() - startTime < opts.timeout) {
|
|
304
|
+
if (tryAcquireLock(filePath, opts.type, opts.staleThreshold)) {
|
|
305
|
+
return true;
|
|
306
|
+
}
|
|
307
|
+
// Use efficient sync sleep
|
|
308
|
+
sleepSync(opts.retryInterval);
|
|
309
|
+
}
|
|
310
|
+
if (opts.throwOnTimeout) {
|
|
311
|
+
throw new Error(`Failed to acquire ${opts.type} lock on ${filePath} after ${opts.timeout}ms`);
|
|
312
|
+
}
|
|
313
|
+
return false;
|
|
314
|
+
}
|
|
315
|
+
/**
|
|
316
|
+
* Execute a function with an exclusive file lock
|
|
317
|
+
*
|
|
318
|
+
* @example
|
|
319
|
+
* ```typescript
|
|
320
|
+
* await withFileLock('/path/to/config.json', async () => {
|
|
321
|
+
* const config = JSON.parse(fs.readFileSync('/path/to/config.json', 'utf-8'));
|
|
322
|
+
* config.lastAccess = Date.now();
|
|
323
|
+
* fs.writeFileSync('/path/to/config.json', JSON.stringify(config));
|
|
324
|
+
* });
|
|
325
|
+
* ```
|
|
326
|
+
*/
|
|
327
|
+
export async function withFileLock(filePath, fn, options = {}) {
|
|
328
|
+
const acquired = await acquireLock(filePath, options);
|
|
329
|
+
if (!acquired) {
|
|
330
|
+
throw new Error(`Could not acquire lock on ${filePath}`);
|
|
331
|
+
}
|
|
332
|
+
try {
|
|
333
|
+
return await fn();
|
|
334
|
+
}
|
|
335
|
+
finally {
|
|
336
|
+
releaseLock(filePath);
|
|
337
|
+
}
|
|
338
|
+
}
|
|
339
|
+
/**
|
|
340
|
+
* Execute a function with an exclusive file lock (synchronous)
|
|
341
|
+
*/
|
|
342
|
+
export function withFileLockSync(filePath, fn, options = {}) {
|
|
343
|
+
const acquired = acquireLockSync(filePath, options);
|
|
344
|
+
if (!acquired) {
|
|
345
|
+
throw new Error(`Could not acquire lock on ${filePath}`);
|
|
346
|
+
}
|
|
347
|
+
try {
|
|
348
|
+
return fn();
|
|
349
|
+
}
|
|
350
|
+
finally {
|
|
351
|
+
releaseLock(filePath);
|
|
352
|
+
}
|
|
353
|
+
}
|
|
354
|
+
/**
|
|
355
|
+
* Lock guard class for manual lock management
|
|
356
|
+
*
|
|
357
|
+
* @example
|
|
358
|
+
* ```typescript
|
|
359
|
+
* const guard = await LockGuard.acquire('/path/to/file');
|
|
360
|
+
* try {
|
|
361
|
+
* // ... do work ...
|
|
362
|
+
* } finally {
|
|
363
|
+
* guard.release();
|
|
364
|
+
* }
|
|
365
|
+
* ```
|
|
366
|
+
*/
|
|
367
|
+
export class LockGuard {
|
|
368
|
+
filePath;
|
|
369
|
+
type;
|
|
370
|
+
released = false;
|
|
371
|
+
constructor(filePath, type) {
|
|
372
|
+
this.filePath = filePath;
|
|
373
|
+
this.type = type;
|
|
374
|
+
}
|
|
375
|
+
/**
|
|
376
|
+
* Acquire a lock and return a guard
|
|
377
|
+
*/
|
|
378
|
+
static async acquire(filePath, options = {}) {
|
|
379
|
+
const opts = { ...DEFAULT_OPTIONS, ...options };
|
|
380
|
+
await acquireLock(filePath, opts);
|
|
381
|
+
return new LockGuard(filePath, opts.type);
|
|
382
|
+
}
|
|
383
|
+
/**
|
|
384
|
+
* Acquire a lock synchronously and return a guard
|
|
385
|
+
*/
|
|
386
|
+
static acquireSync(filePath, options = {}) {
|
|
387
|
+
const opts = { ...DEFAULT_OPTIONS, ...options };
|
|
388
|
+
acquireLockSync(filePath, opts);
|
|
389
|
+
return new LockGuard(filePath, opts.type);
|
|
390
|
+
}
|
|
391
|
+
/**
|
|
392
|
+
* Release the lock
|
|
393
|
+
*/
|
|
394
|
+
release() {
|
|
395
|
+
if (!this.released) {
|
|
396
|
+
releaseLock(this.filePath);
|
|
397
|
+
this.released = true;
|
|
398
|
+
}
|
|
399
|
+
}
|
|
400
|
+
/**
|
|
401
|
+
* Check if lock has been released
|
|
402
|
+
*/
|
|
403
|
+
get isReleased() {
|
|
404
|
+
return this.released;
|
|
405
|
+
}
|
|
406
|
+
}
|
|
407
|
+
/**
|
|
408
|
+
* Safe JSON file operations with locking
|
|
409
|
+
*/
|
|
410
|
+
export const SafeJsonFile = {
|
|
411
|
+
/**
|
|
412
|
+
* Read a JSON file with lock protection
|
|
413
|
+
*/
|
|
414
|
+
async read(filePath, options = {}) {
|
|
415
|
+
return withFileLock(filePath, () => {
|
|
416
|
+
if (!existsSync(filePath)) {
|
|
417
|
+
return null;
|
|
418
|
+
}
|
|
419
|
+
const content = readFileSync(filePath, 'utf-8');
|
|
420
|
+
return JSON.parse(content);
|
|
421
|
+
}, { ...options, type: 'read' });
|
|
422
|
+
},
|
|
423
|
+
/**
|
|
424
|
+
* Write a JSON file with lock protection
|
|
425
|
+
*/
|
|
426
|
+
async write(filePath, data, options = {}) {
|
|
427
|
+
return withFileLock(filePath, () => {
|
|
428
|
+
const dir = dirname(filePath);
|
|
429
|
+
if (!existsSync(dir)) {
|
|
430
|
+
mkdirSync(dir, { recursive: true });
|
|
431
|
+
}
|
|
432
|
+
// Write to temp file first, then rename (atomic)
|
|
433
|
+
const tempPath = `${filePath}.tmp.${process.pid}.${Date.now()}`;
|
|
434
|
+
try {
|
|
435
|
+
writeFileSync(tempPath, JSON.stringify(data, null, 2));
|
|
436
|
+
require('fs').renameSync(tempPath, filePath);
|
|
437
|
+
}
|
|
438
|
+
catch (error) {
|
|
439
|
+
// Clean up temp file on error
|
|
440
|
+
try {
|
|
441
|
+
if (existsSync(tempPath)) {
|
|
442
|
+
unlinkSync(tempPath);
|
|
443
|
+
}
|
|
444
|
+
}
|
|
445
|
+
catch {
|
|
446
|
+
// Ignore cleanup errors
|
|
447
|
+
}
|
|
448
|
+
throw error;
|
|
449
|
+
}
|
|
450
|
+
}, { ...options, type: 'write' });
|
|
451
|
+
},
|
|
452
|
+
/**
|
|
453
|
+
* Update a JSON file with lock protection
|
|
454
|
+
* Reads, modifies, and writes atomically
|
|
455
|
+
*/
|
|
456
|
+
async update(filePath, updater, options = {}) {
|
|
457
|
+
return withFileLock(filePath, () => {
|
|
458
|
+
let current = null;
|
|
459
|
+
if (existsSync(filePath)) {
|
|
460
|
+
const content = readFileSync(filePath, 'utf-8');
|
|
461
|
+
current = JSON.parse(content);
|
|
462
|
+
}
|
|
463
|
+
const updated = updater(current);
|
|
464
|
+
const dir = dirname(filePath);
|
|
465
|
+
if (!existsSync(dir)) {
|
|
466
|
+
mkdirSync(dir, { recursive: true });
|
|
467
|
+
}
|
|
468
|
+
const tempPath = `${filePath}.tmp.${process.pid}.${Date.now()}`;
|
|
469
|
+
try {
|
|
470
|
+
writeFileSync(tempPath, JSON.stringify(updated, null, 2));
|
|
471
|
+
require('fs').renameSync(tempPath, filePath);
|
|
472
|
+
}
|
|
473
|
+
catch (error) {
|
|
474
|
+
// Clean up temp file on error
|
|
475
|
+
try {
|
|
476
|
+
if (existsSync(tempPath)) {
|
|
477
|
+
unlinkSync(tempPath);
|
|
478
|
+
}
|
|
479
|
+
}
|
|
480
|
+
catch {
|
|
481
|
+
// Ignore cleanup errors
|
|
482
|
+
}
|
|
483
|
+
throw error;
|
|
484
|
+
}
|
|
485
|
+
return updated;
|
|
486
|
+
}, { ...options, type: 'write' });
|
|
487
|
+
},
|
|
488
|
+
/**
|
|
489
|
+
* Synchronous read with lock
|
|
490
|
+
*/
|
|
491
|
+
readSync(filePath, options = {}) {
|
|
492
|
+
return withFileLockSync(filePath, () => {
|
|
493
|
+
if (!existsSync(filePath)) {
|
|
494
|
+
return null;
|
|
495
|
+
}
|
|
496
|
+
const content = readFileSync(filePath, 'utf-8');
|
|
497
|
+
return JSON.parse(content);
|
|
498
|
+
}, { ...options, type: 'read' });
|
|
499
|
+
},
|
|
500
|
+
/**
|
|
501
|
+
* Synchronous write with lock
|
|
502
|
+
*/
|
|
503
|
+
writeSync(filePath, data, options = {}) {
|
|
504
|
+
withFileLockSync(filePath, () => {
|
|
505
|
+
const dir = dirname(filePath);
|
|
506
|
+
if (!existsSync(dir)) {
|
|
507
|
+
mkdirSync(dir, { recursive: true });
|
|
508
|
+
}
|
|
509
|
+
const tempPath = `${filePath}.tmp.${process.pid}.${Date.now()}`;
|
|
510
|
+
try {
|
|
511
|
+
writeFileSync(tempPath, JSON.stringify(data, null, 2));
|
|
512
|
+
require('fs').renameSync(tempPath, filePath);
|
|
513
|
+
}
|
|
514
|
+
catch (error) {
|
|
515
|
+
// Clean up temp file on error
|
|
516
|
+
try {
|
|
517
|
+
if (existsSync(tempPath)) {
|
|
518
|
+
unlinkSync(tempPath);
|
|
519
|
+
}
|
|
520
|
+
}
|
|
521
|
+
catch {
|
|
522
|
+
// Ignore cleanup errors
|
|
523
|
+
}
|
|
524
|
+
throw error;
|
|
525
|
+
}
|
|
526
|
+
}, { ...options, type: 'write' });
|
|
527
|
+
},
|
|
528
|
+
};
|
|
529
|
+
/**
|
|
530
|
+
* Clean up any stale lock files in a directory
|
|
531
|
+
*/
|
|
532
|
+
export function cleanupStaleLocks(directory, staleThreshold = DEFAULT_OPTIONS.staleThreshold) {
|
|
533
|
+
const fs = require('fs');
|
|
534
|
+
const path = require('path');
|
|
535
|
+
let cleaned = 0;
|
|
536
|
+
try {
|
|
537
|
+
const files = fs.readdirSync(directory);
|
|
538
|
+
for (const file of files) {
|
|
539
|
+
if (file.endsWith('.lock')) {
|
|
540
|
+
const lockPath = path.join(directory, file);
|
|
541
|
+
const content = readLockFile(lockPath);
|
|
542
|
+
if (content && isLockStale(content, staleThreshold)) {
|
|
543
|
+
try {
|
|
544
|
+
unlinkSync(lockPath);
|
|
545
|
+
cleaned++;
|
|
546
|
+
}
|
|
547
|
+
catch {
|
|
548
|
+
// Ignore errors
|
|
549
|
+
}
|
|
550
|
+
}
|
|
551
|
+
}
|
|
552
|
+
}
|
|
553
|
+
}
|
|
554
|
+
catch {
|
|
555
|
+
// Directory might not exist
|
|
556
|
+
}
|
|
557
|
+
return cleaned;
|
|
558
|
+
}
|
|
559
|
+
//# sourceMappingURL=file-lock.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"file-lock.js","sourceRoot":"","sources":["../../src/utils/file-lock.ts"],"names":[],"mappings":"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"}
|