sync-worktrees 3.3.1 → 3.4.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/dist/index.js +66 -3
- package/dist/index.js.map +2 -2
- package/dist/mcp-server.js +66 -3
- package/dist/mcp-server.js.map +2 -2
- package/package.json +3 -1
package/dist/mcp-server.js
CHANGED
|
@@ -57,7 +57,11 @@ var DEFAULT_CONFIG = {
|
|
|
57
57
|
MAX_SAFE_TOTAL_CONCURRENT_OPS: 100
|
|
58
58
|
},
|
|
59
59
|
UPDATE_EXISTING_WORKTREES: true,
|
|
60
|
-
HOOK_TIMEOUT_MS: 6e4
|
|
60
|
+
HOOK_TIMEOUT_MS: 6e4,
|
|
61
|
+
FETCH_TIMEOUT_MS: 3e5,
|
|
62
|
+
CLONE_TIMEOUT_MS: 9e5,
|
|
63
|
+
LOCK_STALE_MS: 6e5,
|
|
64
|
+
LOCK_UPDATE_MS: 3e4
|
|
61
65
|
};
|
|
62
66
|
var ERROR_MESSAGES = {
|
|
63
67
|
GIT_NOT_INITIALIZED: "Git service not initialized. Call initialize() first.",
|
|
@@ -753,6 +757,7 @@ function defaultConsoleOutput(msg, level) {
|
|
|
753
757
|
import * as fs6 from "fs/promises";
|
|
754
758
|
import * as path7 from "path";
|
|
755
759
|
import pLimit from "p-limit";
|
|
760
|
+
import * as lockfile from "proper-lockfile";
|
|
756
761
|
|
|
757
762
|
// src/utils/date-filter.ts
|
|
758
763
|
function parseDuration(durationStr) {
|
|
@@ -1753,11 +1758,21 @@ var GitService = class {
|
|
|
1753
1758
|
getSparseCheckoutService() {
|
|
1754
1759
|
return this.sparseCheckoutService;
|
|
1755
1760
|
}
|
|
1761
|
+
getFetchTimeoutMs() {
|
|
1762
|
+
if (process.env.NODE_ENV === ENV_CONSTANTS.NODE_ENV_TEST) return 0;
|
|
1763
|
+
return this.config.fetchTimeoutMs ?? DEFAULT_CONFIG.FETCH_TIMEOUT_MS;
|
|
1764
|
+
}
|
|
1765
|
+
getCloneTimeoutMs() {
|
|
1766
|
+
if (process.env.NODE_ENV === ENV_CONSTANTS.NODE_ENV_TEST) return 0;
|
|
1767
|
+
return this.config.cloneTimeoutMs ?? DEFAULT_CONFIG.CLONE_TIMEOUT_MS;
|
|
1768
|
+
}
|
|
1756
1769
|
getCachedGit(dirPath, useLfsSkip = false) {
|
|
1757
1770
|
const key = `${path5.resolve(dirPath)}::${useLfsSkip ? "1" : "0"}`;
|
|
1758
1771
|
let git = this.gitInstances.get(key);
|
|
1759
1772
|
if (!git) {
|
|
1760
|
-
|
|
1773
|
+
const block = this.getFetchTimeoutMs();
|
|
1774
|
+
const base = block > 0 ? simpleGit4(dirPath, { timeout: { block } }) : simpleGit4(dirPath);
|
|
1775
|
+
git = useLfsSkip ? base.env({ [ENV_CONSTANTS.GIT_LFS_SKIP_SMUDGE]: "1" }) : base;
|
|
1761
1776
|
this.gitInstances.set(key, git);
|
|
1762
1777
|
}
|
|
1763
1778
|
return git;
|
|
@@ -1773,7 +1788,9 @@ var GitService = class {
|
|
|
1773
1788
|
} catch {
|
|
1774
1789
|
this.logger.info(`Cloning from "${repoUrl}" as bare repository into "${this.bareRepoPath}"...`);
|
|
1775
1790
|
await fs4.mkdir(path5.dirname(this.bareRepoPath), { recursive: true });
|
|
1776
|
-
const
|
|
1791
|
+
const cloneBlock = this.getCloneTimeoutMs();
|
|
1792
|
+
const cloneBase = cloneBlock > 0 ? simpleGit4({ timeout: { block: cloneBlock } }) : simpleGit4();
|
|
1793
|
+
const cloneGit = this.isLfsSkipEnabled() ? cloneBase.env({ [ENV_CONSTANTS.GIT_LFS_SKIP_SMUDGE]: "1" }) : cloneBase;
|
|
1777
1794
|
await cloneGit.clone(repoUrl, this.bareRepoPath, ["--bare"]);
|
|
1778
1795
|
this.logger.info("\u2705 Clone successful.");
|
|
1779
1796
|
}
|
|
@@ -1859,6 +1876,9 @@ var GitService = class {
|
|
|
1859
1876
|
getDefaultBranch() {
|
|
1860
1877
|
return this.defaultBranch;
|
|
1861
1878
|
}
|
|
1879
|
+
getBareRepoPath() {
|
|
1880
|
+
return this.bareRepoPath;
|
|
1881
|
+
}
|
|
1862
1882
|
async fetchAll() {
|
|
1863
1883
|
this.assertInitialized();
|
|
1864
1884
|
this.logger.info("Fetching latest data from remote...");
|
|
@@ -2568,6 +2588,11 @@ var WorktreeSyncService = class {
|
|
|
2568
2588
|
this.logger.warn("\u26A0\uFE0F Sync already in progress, skipping...");
|
|
2569
2589
|
return { started: false, reason: "in_progress" };
|
|
2570
2590
|
}
|
|
2591
|
+
const release = await this.acquireBareLock();
|
|
2592
|
+
if (release === null) {
|
|
2593
|
+
this.logger.warn("\u26A0\uFE0F Another process holds the sync lock for this repo, skipping...");
|
|
2594
|
+
return { started: false, reason: "locked" };
|
|
2595
|
+
}
|
|
2571
2596
|
this.syncInProgress = true;
|
|
2572
2597
|
this.logger.info(`[${(/* @__PURE__ */ new Date()).toISOString()}] Starting worktree synchronization...`);
|
|
2573
2598
|
const totalTimer = new Timer();
|
|
@@ -2584,6 +2609,11 @@ var WorktreeSyncService = class {
|
|
|
2584
2609
|
this.gitService.setLfsSkipEnabled(false);
|
|
2585
2610
|
}
|
|
2586
2611
|
this.syncInProgress = false;
|
|
2612
|
+
try {
|
|
2613
|
+
await release();
|
|
2614
|
+
} catch (releaseError) {
|
|
2615
|
+
this.logger.warn(`Failed to release sync lock: ${getErrorMessage(releaseError)}`);
|
|
2616
|
+
}
|
|
2587
2617
|
this.logger.info(`[${(/* @__PURE__ */ new Date()).toISOString()}] Synchronization finished.
|
|
2588
2618
|
`);
|
|
2589
2619
|
if (this.config.debug) {
|
|
@@ -2595,6 +2625,39 @@ var WorktreeSyncService = class {
|
|
|
2595
2625
|
}
|
|
2596
2626
|
return { started: true };
|
|
2597
2627
|
}
|
|
2628
|
+
async acquireBareLock() {
|
|
2629
|
+
if (process.env.NODE_ENV === ENV_CONSTANTS.NODE_ENV_TEST) {
|
|
2630
|
+
return async () => {
|
|
2631
|
+
};
|
|
2632
|
+
}
|
|
2633
|
+
if (typeof this.gitService.getBareRepoPath !== "function") {
|
|
2634
|
+
return async () => {
|
|
2635
|
+
};
|
|
2636
|
+
}
|
|
2637
|
+
const barePath = this.gitService.getBareRepoPath();
|
|
2638
|
+
const lockTarget = path7.join(barePath, "HEAD");
|
|
2639
|
+
try {
|
|
2640
|
+
await fs6.access(lockTarget);
|
|
2641
|
+
} catch {
|
|
2642
|
+
return async () => {
|
|
2643
|
+
};
|
|
2644
|
+
}
|
|
2645
|
+
try {
|
|
2646
|
+
const release = await lockfile.lock(lockTarget, {
|
|
2647
|
+
stale: DEFAULT_CONFIG.LOCK_STALE_MS,
|
|
2648
|
+
update: DEFAULT_CONFIG.LOCK_UPDATE_MS,
|
|
2649
|
+
retries: 0,
|
|
2650
|
+
realpath: false
|
|
2651
|
+
});
|
|
2652
|
+
return release;
|
|
2653
|
+
} catch (error) {
|
|
2654
|
+
const code = error.code;
|
|
2655
|
+
if (code === "ELOCKED") {
|
|
2656
|
+
return null;
|
|
2657
|
+
}
|
|
2658
|
+
throw error;
|
|
2659
|
+
}
|
|
2660
|
+
}
|
|
2598
2661
|
createRetryOptions(syncContext) {
|
|
2599
2662
|
return {
|
|
2600
2663
|
maxAttempts: this.config.retry?.maxAttempts ?? 3,
|