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/index.js
CHANGED
|
@@ -55,7 +55,11 @@ var DEFAULT_CONFIG = {
|
|
|
55
55
|
MAX_SAFE_TOTAL_CONCURRENT_OPS: 100
|
|
56
56
|
},
|
|
57
57
|
UPDATE_EXISTING_WORKTREES: true,
|
|
58
|
-
HOOK_TIMEOUT_MS: 6e4
|
|
58
|
+
HOOK_TIMEOUT_MS: 6e4,
|
|
59
|
+
FETCH_TIMEOUT_MS: 3e5,
|
|
60
|
+
CLONE_TIMEOUT_MS: 9e5,
|
|
61
|
+
LOCK_STALE_MS: 6e5,
|
|
62
|
+
LOCK_UPDATE_MS: 3e4
|
|
59
63
|
};
|
|
60
64
|
var ERROR_MESSAGES = {
|
|
61
65
|
GIT_NOT_INITIALIZED: "Git service not initialized. Call initialize() first.",
|
|
@@ -1947,6 +1951,7 @@ var App_default = App;
|
|
|
1947
1951
|
import * as fs6 from "fs/promises";
|
|
1948
1952
|
import * as path7 from "path";
|
|
1949
1953
|
import pLimit from "p-limit";
|
|
1954
|
+
import * as lockfile from "proper-lockfile";
|
|
1950
1955
|
|
|
1951
1956
|
// src/utils/date-filter.ts
|
|
1952
1957
|
function parseDuration(durationStr) {
|
|
@@ -3024,11 +3029,21 @@ var GitService = class {
|
|
|
3024
3029
|
getSparseCheckoutService() {
|
|
3025
3030
|
return this.sparseCheckoutService;
|
|
3026
3031
|
}
|
|
3032
|
+
getFetchTimeoutMs() {
|
|
3033
|
+
if (process.env.NODE_ENV === ENV_CONSTANTS.NODE_ENV_TEST) return 0;
|
|
3034
|
+
return this.config.fetchTimeoutMs ?? DEFAULT_CONFIG.FETCH_TIMEOUT_MS;
|
|
3035
|
+
}
|
|
3036
|
+
getCloneTimeoutMs() {
|
|
3037
|
+
if (process.env.NODE_ENV === ENV_CONSTANTS.NODE_ENV_TEST) return 0;
|
|
3038
|
+
return this.config.cloneTimeoutMs ?? DEFAULT_CONFIG.CLONE_TIMEOUT_MS;
|
|
3039
|
+
}
|
|
3027
3040
|
getCachedGit(dirPath, useLfsSkip = false) {
|
|
3028
3041
|
const key = `${path5.resolve(dirPath)}::${useLfsSkip ? "1" : "0"}`;
|
|
3029
3042
|
let git = this.gitInstances.get(key);
|
|
3030
3043
|
if (!git) {
|
|
3031
|
-
|
|
3044
|
+
const block = this.getFetchTimeoutMs();
|
|
3045
|
+
const base = block > 0 ? simpleGit4(dirPath, { timeout: { block } }) : simpleGit4(dirPath);
|
|
3046
|
+
git = useLfsSkip ? base.env({ [ENV_CONSTANTS.GIT_LFS_SKIP_SMUDGE]: "1" }) : base;
|
|
3032
3047
|
this.gitInstances.set(key, git);
|
|
3033
3048
|
}
|
|
3034
3049
|
return git;
|
|
@@ -3044,7 +3059,9 @@ var GitService = class {
|
|
|
3044
3059
|
} catch {
|
|
3045
3060
|
this.logger.info(`Cloning from "${repoUrl}" as bare repository into "${this.bareRepoPath}"...`);
|
|
3046
3061
|
await fs4.mkdir(path5.dirname(this.bareRepoPath), { recursive: true });
|
|
3047
|
-
const
|
|
3062
|
+
const cloneBlock = this.getCloneTimeoutMs();
|
|
3063
|
+
const cloneBase = cloneBlock > 0 ? simpleGit4({ timeout: { block: cloneBlock } }) : simpleGit4();
|
|
3064
|
+
const cloneGit = this.isLfsSkipEnabled() ? cloneBase.env({ [ENV_CONSTANTS.GIT_LFS_SKIP_SMUDGE]: "1" }) : cloneBase;
|
|
3048
3065
|
await cloneGit.clone(repoUrl, this.bareRepoPath, ["--bare"]);
|
|
3049
3066
|
this.logger.info("\u2705 Clone successful.");
|
|
3050
3067
|
}
|
|
@@ -3130,6 +3147,9 @@ var GitService = class {
|
|
|
3130
3147
|
getDefaultBranch() {
|
|
3131
3148
|
return this.defaultBranch;
|
|
3132
3149
|
}
|
|
3150
|
+
getBareRepoPath() {
|
|
3151
|
+
return this.bareRepoPath;
|
|
3152
|
+
}
|
|
3133
3153
|
async fetchAll() {
|
|
3134
3154
|
this.assertInitialized();
|
|
3135
3155
|
this.logger.info("Fetching latest data from remote...");
|
|
@@ -3839,6 +3859,11 @@ var WorktreeSyncService = class {
|
|
|
3839
3859
|
this.logger.warn("\u26A0\uFE0F Sync already in progress, skipping...");
|
|
3840
3860
|
return { started: false, reason: "in_progress" };
|
|
3841
3861
|
}
|
|
3862
|
+
const release = await this.acquireBareLock();
|
|
3863
|
+
if (release === null) {
|
|
3864
|
+
this.logger.warn("\u26A0\uFE0F Another process holds the sync lock for this repo, skipping...");
|
|
3865
|
+
return { started: false, reason: "locked" };
|
|
3866
|
+
}
|
|
3842
3867
|
this.syncInProgress = true;
|
|
3843
3868
|
this.logger.info(`[${(/* @__PURE__ */ new Date()).toISOString()}] Starting worktree synchronization...`);
|
|
3844
3869
|
const totalTimer = new Timer();
|
|
@@ -3855,6 +3880,11 @@ var WorktreeSyncService = class {
|
|
|
3855
3880
|
this.gitService.setLfsSkipEnabled(false);
|
|
3856
3881
|
}
|
|
3857
3882
|
this.syncInProgress = false;
|
|
3883
|
+
try {
|
|
3884
|
+
await release();
|
|
3885
|
+
} catch (releaseError) {
|
|
3886
|
+
this.logger.warn(`Failed to release sync lock: ${getErrorMessage(releaseError)}`);
|
|
3887
|
+
}
|
|
3858
3888
|
this.logger.info(`[${(/* @__PURE__ */ new Date()).toISOString()}] Synchronization finished.
|
|
3859
3889
|
`);
|
|
3860
3890
|
if (this.config.debug) {
|
|
@@ -3866,6 +3896,39 @@ var WorktreeSyncService = class {
|
|
|
3866
3896
|
}
|
|
3867
3897
|
return { started: true };
|
|
3868
3898
|
}
|
|
3899
|
+
async acquireBareLock() {
|
|
3900
|
+
if (process.env.NODE_ENV === ENV_CONSTANTS.NODE_ENV_TEST) {
|
|
3901
|
+
return async () => {
|
|
3902
|
+
};
|
|
3903
|
+
}
|
|
3904
|
+
if (typeof this.gitService.getBareRepoPath !== "function") {
|
|
3905
|
+
return async () => {
|
|
3906
|
+
};
|
|
3907
|
+
}
|
|
3908
|
+
const barePath = this.gitService.getBareRepoPath();
|
|
3909
|
+
const lockTarget = path7.join(barePath, "HEAD");
|
|
3910
|
+
try {
|
|
3911
|
+
await fs6.access(lockTarget);
|
|
3912
|
+
} catch {
|
|
3913
|
+
return async () => {
|
|
3914
|
+
};
|
|
3915
|
+
}
|
|
3916
|
+
try {
|
|
3917
|
+
const release = await lockfile.lock(lockTarget, {
|
|
3918
|
+
stale: DEFAULT_CONFIG.LOCK_STALE_MS,
|
|
3919
|
+
update: DEFAULT_CONFIG.LOCK_UPDATE_MS,
|
|
3920
|
+
retries: 0,
|
|
3921
|
+
realpath: false
|
|
3922
|
+
});
|
|
3923
|
+
return release;
|
|
3924
|
+
} catch (error) {
|
|
3925
|
+
const code = error.code;
|
|
3926
|
+
if (code === "ELOCKED") {
|
|
3927
|
+
return null;
|
|
3928
|
+
}
|
|
3929
|
+
throw error;
|
|
3930
|
+
}
|
|
3931
|
+
}
|
|
3869
3932
|
createRetryOptions(syncContext) {
|
|
3870
3933
|
return {
|
|
3871
3934
|
maxAttempts: this.config.retry?.maxAttempts ?? 3,
|