profclaw 0.0.1-beta.3 → 2.0.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 +21 -38
- package/CONTRIBUTING.md +3 -5
- package/README.md +128 -63
- package/dist/chat/execution/tools/index.d.ts +1 -1
- package/dist/chat/execution/tools/index.js +41 -2
- package/dist/chat/providers/slack/index.d.ts +2 -2
- package/dist/cli/commands/models.js +39 -26
- package/dist/cli/commands/onboard.js +64 -79
- package/dist/cli/commands/setup.js +293 -90
- package/dist/cli/index.js +0 -6
- package/dist/cli/providers.d.ts +15 -0
- package/dist/cli/providers.js +41 -0
- package/dist/core/deployment.js +2 -0
- package/dist/providers/ai-sdk.js +26 -6
- package/dist/routes/channels.d.ts +12 -0
- package/dist/routes/channels.js +166 -0
- package/dist/server/route-loader.js +1 -0
- package/dist/server.js +115 -109
- package/package.json +1 -1
- package/skills/git-workflow/SKILL.md +3 -3
- package/ui/dist/assets/{ActivityView-DIPQSJ_d.js → ActivityView-BeshZXmE.js} +1 -1
- package/ui/dist/assets/{AgentList-CqyaYrcq.js → AgentList-QVHeldPi.js} +1 -1
- package/ui/dist/assets/{AnalyticsDashboard-C-mjuGHT.js → AnalyticsDashboard-C9R97dXE.js} +1 -1
- package/ui/dist/assets/{AreaChart-CfYWmbtr.js → AreaChart-B73gaiVQ.js} +1 -1
- package/ui/dist/assets/{CartesianChart-BaQ3It0c.js → CartesianChart-CXYL2R-A.js} +1 -1
- package/ui/dist/assets/{ChatView-DxxQy6pl.js → ChatView-qjZErlrp.js} +1 -1
- package/ui/dist/assets/{CostsDashboard-CDBBcGkg.js → CostsDashboard-O4DCLy1i.js} +1 -1
- package/ui/dist/assets/{EstimateSelect-CDjf5qKl.js → EstimateSelect-1hQf4Osk.js} +1 -1
- package/ui/dist/assets/{FloatingChatbot-CZHjvJIe.js → FloatingChatbot-BZBzrJxd.js} +1 -1
- package/ui/dist/assets/{InviteCodeManagement-DTm-IPTm.js → InviteCodeManagement-LEoGqYeA.js} +1 -1
- package/ui/dist/assets/{ProjectDetail-DlYUcOss.js → ProjectDetail--gPfvATB.js} +1 -1
- package/ui/dist/assets/{ProjectIcon-BMRpnM04.js → ProjectIcon-Chd_ofsw.js} +1 -1
- package/ui/dist/assets/{ProjectList-D85TN0i0.js → ProjectList-BvUfVB6c.js} +1 -1
- package/ui/dist/assets/{Settings-CgPqzUvj.js → Settings-1kaf7VHE.js} +1 -1
- package/ui/dist/assets/{StatusIndicator-yig0uZEA.js → StatusIndicator-pRfkNcdV.js} +1 -1
- package/ui/dist/assets/{SummaryDetail-CwLAfHgJ.js → SummaryDetail-DV3AmONk.js} +1 -1
- package/ui/dist/assets/{SummaryList-BvS5Idnu.js → SummaryList-B6kXiTxL.js} +1 -1
- package/ui/dist/assets/{TaskDetail-zarC1fOt.js → TaskDetail-CV6CzbOS.js} +1 -1
- package/ui/dist/assets/{TaskList-CyJq3ANE.js → TaskList-DL7brQKd.js} +1 -1
- package/ui/dist/assets/{TicketBoard-BlWr3-iH.js → TicketBoard-CrkkFj7C.js} +1 -1
- package/ui/dist/assets/{TicketDetail-DmqWKj2W.js → TicketDetail-hnnYclpD.js} +1 -1
- package/ui/dist/assets/{TicketList-Scj4pMWa.js → TicketList-CsDAyQCL.js} +1 -1
- package/ui/dist/assets/{UserManagement-BH7uG7dw.js → UserManagement-BGFQyTSr.js} +1 -1
- package/ui/dist/assets/{ViewSwitcher-3HzZUdWn.js → ViewSwitcher-CnL0OqA8.js} +1 -1
- package/ui/dist/assets/{alert-dialog-DWPb2IfQ.js → alert-dialog-SKM6Gjz4.js} +1 -1
- package/ui/dist/assets/{archive-CGck7gxR.js → archive-BsLa7brF.js} +1 -1
- package/ui/dist/assets/{badge-DEmc3Z_l.js → badge-CVHH1a-v.js} +1 -1
- package/ui/dist/assets/{brain-CfFdLVqb.js → brain-6o_RHVpe.js} +1 -1
- package/ui/dist/assets/{bug-DqSGPUUE.js → bug-CmZI7jqM.js} +1 -1
- package/ui/dist/assets/{calendar-BuZ4zbPW.js → calendar-Bf0t2B82.js} +1 -1
- package/ui/dist/assets/{chevron-up-DcJ4LL_N.js → chevron-up-CoUsOvZj.js} +1 -1
- package/ui/dist/assets/{circle-x-C78PNZjF.js → circle-x-Dgw11LgT.js} +1 -1
- package/ui/dist/assets/{constants-DhDjZe4P.js → constants-Q5Zivl-a.js} +1 -1
- package/ui/dist/assets/{cpu-Ck6AoG8c.js → cpu-DiPMQICV.js} +1 -1
- package/ui/dist/assets/{database-CA2w8Lvt.js → database-BwTfupDi.js} +1 -1
- package/ui/dist/assets/{dialog-BOdGWhgE.js → dialog-BUqN9Psj.js} +1 -1
- package/ui/dist/assets/{ellipsis-FhHKRbfl.js → ellipsis-UJx4Xnf6.js} +1 -1
- package/ui/dist/assets/{ellipsis-vertical-CO0UqE4-.js → ellipsis-vertical-DoULYEKn.js} +1 -1
- package/ui/dist/assets/{file-code-ChnhYYj1.js → file-code-B2UrJLwi.js} +1 -1
- package/ui/dist/assets/{folder-open-CHwA1-ve.js → folder-open-BJi577JH.js} +1 -1
- package/ui/dist/assets/{funnel-ByEjRFNB.js → funnel-PkaD_HSR.js} +1 -1
- package/ui/dist/assets/{git-branch-GTOPQgU4.js → git-branch-C_K30am0.js} +1 -1
- package/ui/dist/assets/{git-commit-horizontal-F5M84Kut.js → git-commit-horizontal-IT6ecxWQ.js} +1 -1
- package/ui/dist/assets/{globe-CQWfr7hT.js → globe-f-jjCa_g.js} +1 -1
- package/ui/dist/assets/{hash-nKC9gtLg.js → hash-DNEv8Elo.js} +1 -1
- package/ui/dist/assets/{history-DfFSA9xJ.js → history-BQSBo_1Q.js} +1 -1
- package/ui/dist/assets/{index-DHGvP9mp.js → index-BUmnwPQr.js} +1 -1
- package/ui/dist/assets/{index-Z4-RtZcs.js → index-BfF5G4Cw.js} +1 -1
- package/ui/dist/assets/{index-DeI8lKRR.js → index-C8N375c2.js} +1 -1
- package/ui/dist/assets/index-CuxnqVVz.css +1 -0
- package/ui/dist/assets/{index-Ca3vk7Gq.js → index-CzMM3QOk.js} +1 -1
- package/ui/dist/assets/{index--JkIxVXb.js → index-lJlNPFVJ.js} +3 -3
- package/ui/dist/assets/{index-a4Fxq0Hb.js → index-nS3EErDg.js} +1 -1
- package/ui/dist/assets/{layers-DFeLExSa.js → layers-jFqVrWMD.js} +1 -1
- package/ui/dist/assets/{layout-dashboard-WmgjMhWF.js → layout-dashboard-CcKt1hXw.js} +1 -1
- package/ui/dist/assets/{lightbulb-Bo8hEr7B.js → lightbulb-Jhp7FvbU.js} +1 -1
- package/ui/dist/assets/{link-2-YqrpQXBH.js → link-2-DdO7ostF.js} +1 -1
- package/ui/dist/assets/{markdown-renderer-Croje6Xe.js → markdown-renderer-n1ToC4XQ.js} +1 -1
- package/ui/dist/assets/{message-square-CD0H5hot.js → message-square-CBgH65X7.js} +1 -1
- package/ui/dist/assets/{pencil-DpFnj5dn.js → pencil-CYXCEPQh.js} +1 -1
- package/ui/dist/assets/{play-DVgea_jT.js → play-d1ONaH0-.js} +1 -1
- package/ui/dist/assets/{popover-JXecfWG5.js → popover-CrmZgoWu.js} +1 -1
- package/ui/dist/assets/{progress-C1ghf1Fu.js → progress-uv4SPkL5.js} +1 -1
- package/ui/dist/assets/{rocket-BFxPYGx9.js → rocket-DhvUetsk.js} +1 -1
- package/ui/dist/assets/{select-MADP8m6Q.js → select-CeQ8AHGy.js} +1 -1
- package/ui/dist/assets/{send-eYnW_7n-.js → send-P0r5D7td.js} +1 -1
- package/ui/dist/assets/{server-CPMaysH8.js → server-CVHTZB72.js} +1 -1
- package/ui/dist/assets/{settings-2-scXUOuE_.js → settings-2-ocj5uHGx.js} +1 -1
- package/ui/dist/assets/{sheet-r6NSOxi-.js → sheet-DuQExSho.js} +1 -1
- package/ui/dist/assets/{shield-check-PEr7nmVw.js → shield-check-DfVdE34l.js} +1 -1
- package/ui/dist/assets/{shield-off-CLtXio62.js → shield-off-8l0J6R-8.js} +1 -1
- package/ui/dist/assets/{skeleton-C9oEzNlU.js → skeleton-TFiFJ3nB.js} +1 -1
- package/ui/dist/assets/{smartphone-DusFfY0U.js → smartphone-77_g3SQn.js} +1 -1
- package/ui/dist/assets/{square-e1yxB2eR.js → square-Ckzsr3Rn.js} +1 -1
- package/ui/dist/assets/{switch-tNs0n-kz.js → switch-CAePkd6k.js} +1 -1
- package/ui/dist/assets/{table-CXxtLicg.js → table-ZjAZ7hkt.js} +1 -1
- package/ui/dist/assets/{tag-tAwMmQ9G.js → tag-C35mgoEv.js} +1 -1
- package/ui/dist/assets/{textarea-BjiEeIWh.js → textarea-DsVPnSgR.js} +1 -1
- package/ui/dist/assets/{timer-Vel1N3RP.js → timer-DHJBS2w1.js} +1 -1
- package/ui/dist/assets/{tooltip-ZMwtfr1J.js → tooltip-BYmQ331W.js} +1 -1
- package/ui/dist/assets/{trash-2-eM-CNwsZ.js → trash-2-keO5tKPE.js} +1 -1
- package/ui/dist/assets/{trending-up-BGafmjRo.js → trending-up-BBv8KbrY.js} +1 -1
- package/ui/dist/assets/{wand-sparkles-DPvcd9Pi.js → wand-sparkles-BusQ52ZK.js} +1 -1
- package/ui/dist/assets/{wrench-B8s3zYVV.js → wrench-02YaOSiK.js} +1 -1
- package/ui/dist/index.html +2 -2
- package/dist/chat/auto-reply.d.ts +0 -90
- package/dist/chat/auto-reply.js +0 -272
- package/dist/chat/execution/pty.d.ts +0 -92
- package/dist/chat/execution/pty.js +0 -285
- package/dist/chat/execution/tools/glinr-ops.d.ts +0 -202
- package/dist/chat/execution/tools/glinr-ops.js +0 -694
- package/dist/cli/commands/browser.d.ts +0 -3
- package/dist/cli/commands/browser.js +0 -138
- package/dist/cli/commands/canvas.d.ts +0 -3
- package/dist/cli/commands/canvas.js +0 -155
- package/dist/cli/commands/nodes.d.ts +0 -3
- package/dist/cli/commands/nodes.js +0 -193
- package/dist/diagnostics/exporters.d.ts +0 -21
- package/dist/diagnostics/exporters.js +0 -138
- package/dist/diagnostics/index.d.ts +0 -10
- package/dist/diagnostics/index.js +0 -9
- package/dist/diagnostics/middleware.d.ts +0 -12
- package/dist/diagnostics/middleware.js +0 -58
- package/dist/diagnostics/tracer.d.ts +0 -133
- package/dist/diagnostics/tracer.js +0 -257
- package/dist/discovery/index.d.ts +0 -8
- package/dist/discovery/index.js +0 -7
- package/dist/discovery/mdns.d.ts +0 -40
- package/dist/discovery/mdns.js +0 -249
- package/dist/plugins/registry.d.ts +0 -122
- package/dist/plugins/registry.js +0 -352
- package/dist/plugins/sandbox.d.ts +0 -77
- package/dist/plugins/sandbox.js +0 -287
- package/dist/plugins/search/brave.d.ts +0 -9
- package/dist/plugins/search/brave.js +0 -157
- package/dist/plugins/search/duckduckgo.d.ts +0 -9
- package/dist/plugins/search/duckduckgo.js +0 -171
- package/dist/plugins/search/index.d.ts +0 -13
- package/dist/plugins/search/index.js +0 -23
- package/dist/plugins/search/searxng.d.ts +0 -9
- package/dist/plugins/search/searxng.js +0 -170
- package/dist/plugins/search/serper.d.ts +0 -9
- package/dist/plugins/search/serper.js +0 -135
- package/dist/plugins/search/tavily.d.ts +0 -9
- package/dist/plugins/search/tavily.js +0 -146
- package/dist/providers/adapters/anthropic.d.ts +0 -26
- package/dist/providers/adapters/anthropic.js +0 -306
- package/dist/providers/adapters/base.d.ts +0 -53
- package/dist/providers/adapters/base.js +0 -99
- package/dist/providers/adapters/ollama.d.ts +0 -30
- package/dist/providers/adapters/ollama.js +0 -292
- package/dist/utils/ai-cache.d.ts +0 -72
- package/dist/utils/ai-cache.js +0 -204
- package/dist/utils/file-lock.d.ts +0 -85
- package/dist/utils/file-lock.js +0 -204
- package/ui/dist/assets/index-WclMPci1.css +0 -1
|
@@ -1,85 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* File Locking Utilities
|
|
3
|
-
*
|
|
4
|
-
* Provides safe concurrent access to config and data files
|
|
5
|
-
* using proper-lockfile for cross-process synchronization.
|
|
6
|
-
*
|
|
7
|
-
* Features:
|
|
8
|
-
* - Automatic retry with backoff on lock contention
|
|
9
|
-
* - Stale lock detection and recovery
|
|
10
|
-
* - Clean async/await API
|
|
11
|
-
* - TypeScript-safe with generics
|
|
12
|
-
*/
|
|
13
|
-
/**
|
|
14
|
-
* Lock options
|
|
15
|
-
*/
|
|
16
|
-
export interface LockOptions {
|
|
17
|
-
/** Time to wait before declaring lock stale (ms) */
|
|
18
|
-
stale?: number;
|
|
19
|
-
/** Retry interval (ms) */
|
|
20
|
-
retries?: number | {
|
|
21
|
-
retries: number;
|
|
22
|
-
factor?: number;
|
|
23
|
-
minTimeout?: number;
|
|
24
|
-
maxTimeout?: number;
|
|
25
|
-
};
|
|
26
|
-
/** Whether to wait for lock */
|
|
27
|
-
wait?: boolean;
|
|
28
|
-
/** Update interval for lock freshness (ms) */
|
|
29
|
-
update?: number;
|
|
30
|
-
}
|
|
31
|
-
/**
|
|
32
|
-
* Acquire a lock on a file
|
|
33
|
-
* Returns a release function that must be called when done
|
|
34
|
-
*/
|
|
35
|
-
export declare function acquireLock(filePath: string, options?: LockOptions): Promise<() => Promise<void>>;
|
|
36
|
-
/**
|
|
37
|
-
* Check if a file is currently locked
|
|
38
|
-
*/
|
|
39
|
-
export declare function isLocked(filePath: string): Promise<boolean>;
|
|
40
|
-
/**
|
|
41
|
-
* Execute a function while holding a file lock
|
|
42
|
-
* Automatically releases the lock when done or on error
|
|
43
|
-
*/
|
|
44
|
-
export declare function withLock<T>(filePath: string, fn: () => Promise<T>, options?: LockOptions): Promise<T>;
|
|
45
|
-
/**
|
|
46
|
-
* Read a JSON file with locking
|
|
47
|
-
*/
|
|
48
|
-
export declare function readJsonWithLock<T>(filePath: string, options?: LockOptions): Promise<T | null>;
|
|
49
|
-
/**
|
|
50
|
-
* Write a JSON file with locking
|
|
51
|
-
*/
|
|
52
|
-
export declare function writeJsonWithLock<T>(filePath: string, data: T, options?: LockOptions): Promise<void>;
|
|
53
|
-
/**
|
|
54
|
-
* Update a JSON file atomically with locking
|
|
55
|
-
* Reads current value, applies updater, writes result
|
|
56
|
-
*/
|
|
57
|
-
export declare function updateJsonWithLock<T>(filePath: string, updater: (current: T | null) => T, options?: LockOptions): Promise<T>;
|
|
58
|
-
/**
|
|
59
|
-
* Multi-file lock for transactions spanning multiple files
|
|
60
|
-
* All files are locked in a deterministic order to prevent deadlocks
|
|
61
|
-
*/
|
|
62
|
-
export declare function withMultiLock<T>(filePaths: string[], fn: () => Promise<T>, options?: LockOptions): Promise<T>;
|
|
63
|
-
/**
|
|
64
|
-
* Lock file path for a given config file
|
|
65
|
-
* Uses a .lock suffix by default
|
|
66
|
-
*/
|
|
67
|
-
export declare function getLockFilePath(filePath: string): string;
|
|
68
|
-
/**
|
|
69
|
-
* Clean up stale lock files
|
|
70
|
-
* Use with caution - only for recovery scenarios
|
|
71
|
-
*/
|
|
72
|
-
export declare function cleanupStaleLock(filePath: string): Promise<boolean>;
|
|
73
|
-
/**
|
|
74
|
-
* Wrapper for settings file operations
|
|
75
|
-
*/
|
|
76
|
-
export declare class LockedConfigFile<T> {
|
|
77
|
-
private filePath;
|
|
78
|
-
private options?;
|
|
79
|
-
constructor(filePath: string, options?: LockOptions | undefined);
|
|
80
|
-
read(): Promise<T | null>;
|
|
81
|
-
write(data: T): Promise<void>;
|
|
82
|
-
update(updater: (current: T | null) => T): Promise<T>;
|
|
83
|
-
isLocked(): Promise<boolean>;
|
|
84
|
-
}
|
|
85
|
-
//# sourceMappingURL=file-lock.d.ts.map
|
package/dist/utils/file-lock.js
DELETED
|
@@ -1,204 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* File Locking Utilities
|
|
3
|
-
*
|
|
4
|
-
* Provides safe concurrent access to config and data files
|
|
5
|
-
* using proper-lockfile for cross-process synchronization.
|
|
6
|
-
*
|
|
7
|
-
* Features:
|
|
8
|
-
* - Automatic retry with backoff on lock contention
|
|
9
|
-
* - Stale lock detection and recovery
|
|
10
|
-
* - Clean async/await API
|
|
11
|
-
* - TypeScript-safe with generics
|
|
12
|
-
*/
|
|
13
|
-
import lockfile from 'proper-lockfile';
|
|
14
|
-
import { existsSync, writeFileSync, mkdirSync } from 'fs';
|
|
15
|
-
import { dirname } from 'path';
|
|
16
|
-
const DEFAULT_LOCK_OPTIONS = {
|
|
17
|
-
stale: 10000, // 10 seconds
|
|
18
|
-
retries: {
|
|
19
|
-
retries: 5,
|
|
20
|
-
factor: 1.5,
|
|
21
|
-
minTimeout: 100,
|
|
22
|
-
maxTimeout: 2000,
|
|
23
|
-
},
|
|
24
|
-
update: 5000, // 5 seconds
|
|
25
|
-
};
|
|
26
|
-
/**
|
|
27
|
-
* Ensure file exists before locking
|
|
28
|
-
* (proper-lockfile requires the file to exist)
|
|
29
|
-
*/
|
|
30
|
-
function ensureFileExists(filePath) {
|
|
31
|
-
if (!existsSync(filePath)) {
|
|
32
|
-
const dir = dirname(filePath);
|
|
33
|
-
if (!existsSync(dir)) {
|
|
34
|
-
mkdirSync(dir, { recursive: true });
|
|
35
|
-
}
|
|
36
|
-
writeFileSync(filePath, '');
|
|
37
|
-
}
|
|
38
|
-
}
|
|
39
|
-
/**
|
|
40
|
-
* Acquire a lock on a file
|
|
41
|
-
* Returns a release function that must be called when done
|
|
42
|
-
*/
|
|
43
|
-
export async function acquireLock(filePath, options) {
|
|
44
|
-
ensureFileExists(filePath);
|
|
45
|
-
const opts = { ...DEFAULT_LOCK_OPTIONS, ...options };
|
|
46
|
-
try {
|
|
47
|
-
const release = await lockfile.lock(filePath, {
|
|
48
|
-
stale: opts.stale,
|
|
49
|
-
retries: opts.retries,
|
|
50
|
-
update: opts.update,
|
|
51
|
-
});
|
|
52
|
-
return release;
|
|
53
|
-
}
|
|
54
|
-
catch (error) {
|
|
55
|
-
if (error.code === 'ELOCKED') {
|
|
56
|
-
throw new Error(`File is locked by another process: ${filePath}`);
|
|
57
|
-
}
|
|
58
|
-
throw error;
|
|
59
|
-
}
|
|
60
|
-
}
|
|
61
|
-
/**
|
|
62
|
-
* Check if a file is currently locked
|
|
63
|
-
*/
|
|
64
|
-
export async function isLocked(filePath) {
|
|
65
|
-
if (!existsSync(filePath)) {
|
|
66
|
-
return false;
|
|
67
|
-
}
|
|
68
|
-
try {
|
|
69
|
-
return await lockfile.check(filePath);
|
|
70
|
-
}
|
|
71
|
-
catch {
|
|
72
|
-
return false;
|
|
73
|
-
}
|
|
74
|
-
}
|
|
75
|
-
/**
|
|
76
|
-
* Execute a function while holding a file lock
|
|
77
|
-
* Automatically releases the lock when done or on error
|
|
78
|
-
*/
|
|
79
|
-
export async function withLock(filePath, fn, options) {
|
|
80
|
-
const release = await acquireLock(filePath, options);
|
|
81
|
-
try {
|
|
82
|
-
return await fn();
|
|
83
|
-
}
|
|
84
|
-
finally {
|
|
85
|
-
await release();
|
|
86
|
-
}
|
|
87
|
-
}
|
|
88
|
-
/**
|
|
89
|
-
* Read a JSON file with locking
|
|
90
|
-
*/
|
|
91
|
-
export async function readJsonWithLock(filePath, options) {
|
|
92
|
-
if (!existsSync(filePath)) {
|
|
93
|
-
return null;
|
|
94
|
-
}
|
|
95
|
-
return withLock(filePath, async () => {
|
|
96
|
-
const { readFileSync } = await import('fs');
|
|
97
|
-
const content = readFileSync(filePath, 'utf-8');
|
|
98
|
-
return JSON.parse(content);
|
|
99
|
-
}, options);
|
|
100
|
-
}
|
|
101
|
-
/**
|
|
102
|
-
* Write a JSON file with locking
|
|
103
|
-
*/
|
|
104
|
-
export async function writeJsonWithLock(filePath, data, options) {
|
|
105
|
-
await withLock(filePath, async () => {
|
|
106
|
-
const { writeFileSync } = await import('fs');
|
|
107
|
-
writeFileSync(filePath, JSON.stringify(data, null, 2));
|
|
108
|
-
}, options);
|
|
109
|
-
}
|
|
110
|
-
/**
|
|
111
|
-
* Update a JSON file atomically with locking
|
|
112
|
-
* Reads current value, applies updater, writes result
|
|
113
|
-
*/
|
|
114
|
-
export async function updateJsonWithLock(filePath, updater, options) {
|
|
115
|
-
return withLock(filePath, async () => {
|
|
116
|
-
const { readFileSync, writeFileSync } = await import('fs');
|
|
117
|
-
let current = null;
|
|
118
|
-
if (existsSync(filePath)) {
|
|
119
|
-
const content = readFileSync(filePath, 'utf-8');
|
|
120
|
-
if (content.trim()) {
|
|
121
|
-
current = JSON.parse(content);
|
|
122
|
-
}
|
|
123
|
-
}
|
|
124
|
-
const updated = updater(current);
|
|
125
|
-
writeFileSync(filePath, JSON.stringify(updated, null, 2));
|
|
126
|
-
return updated;
|
|
127
|
-
}, options);
|
|
128
|
-
}
|
|
129
|
-
/**
|
|
130
|
-
* Multi-file lock for transactions spanning multiple files
|
|
131
|
-
* All files are locked in a deterministic order to prevent deadlocks
|
|
132
|
-
*/
|
|
133
|
-
export async function withMultiLock(filePaths, fn, options) {
|
|
134
|
-
// Sort paths to prevent deadlocks
|
|
135
|
-
const sortedPaths = [...filePaths].sort();
|
|
136
|
-
const releases = [];
|
|
137
|
-
try {
|
|
138
|
-
// Acquire all locks in order
|
|
139
|
-
for (const filePath of sortedPaths) {
|
|
140
|
-
const release = await acquireLock(filePath, options);
|
|
141
|
-
releases.push(release);
|
|
142
|
-
}
|
|
143
|
-
// Execute function
|
|
144
|
-
return await fn();
|
|
145
|
-
}
|
|
146
|
-
finally {
|
|
147
|
-
// Release all locks in reverse order
|
|
148
|
-
for (const release of releases.reverse()) {
|
|
149
|
-
await release().catch(console.error);
|
|
150
|
-
}
|
|
151
|
-
}
|
|
152
|
-
}
|
|
153
|
-
/**
|
|
154
|
-
* Lock file path for a given config file
|
|
155
|
-
* Uses a .lock suffix by default
|
|
156
|
-
*/
|
|
157
|
-
export function getLockFilePath(filePath) {
|
|
158
|
-
return `${filePath}.lock`;
|
|
159
|
-
}
|
|
160
|
-
/**
|
|
161
|
-
* Clean up stale lock files
|
|
162
|
-
* Use with caution - only for recovery scenarios
|
|
163
|
-
*/
|
|
164
|
-
export async function cleanupStaleLock(filePath) {
|
|
165
|
-
try {
|
|
166
|
-
const isStale = await lockfile.check(filePath, { stale: 0 });
|
|
167
|
-
if (!isStale) {
|
|
168
|
-
// Not locked or not stale, nothing to do
|
|
169
|
-
return false;
|
|
170
|
-
}
|
|
171
|
-
// Force unlock
|
|
172
|
-
await lockfile.unlock(filePath, { realpath: false });
|
|
173
|
-
console.log(`[FileLock] Cleaned up stale lock: ${filePath}`);
|
|
174
|
-
return true;
|
|
175
|
-
}
|
|
176
|
-
catch {
|
|
177
|
-
// Lock file might not exist
|
|
178
|
-
return false;
|
|
179
|
-
}
|
|
180
|
-
}
|
|
181
|
-
/**
|
|
182
|
-
* Wrapper for settings file operations
|
|
183
|
-
*/
|
|
184
|
-
export class LockedConfigFile {
|
|
185
|
-
filePath;
|
|
186
|
-
options;
|
|
187
|
-
constructor(filePath, options) {
|
|
188
|
-
this.filePath = filePath;
|
|
189
|
-
this.options = options;
|
|
190
|
-
}
|
|
191
|
-
async read() {
|
|
192
|
-
return readJsonWithLock(this.filePath, this.options);
|
|
193
|
-
}
|
|
194
|
-
async write(data) {
|
|
195
|
-
return writeJsonWithLock(this.filePath, data, this.options);
|
|
196
|
-
}
|
|
197
|
-
async update(updater) {
|
|
198
|
-
return updateJsonWithLock(this.filePath, updater, this.options);
|
|
199
|
-
}
|
|
200
|
-
async isLocked() {
|
|
201
|
-
return isLocked(this.filePath);
|
|
202
|
-
}
|
|
203
|
-
}
|
|
204
|
-
//# sourceMappingURL=file-lock.js.map
|