sync-worktrees 3.1.0 → 3.2.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 +106 -66
- package/dist/index.js.map +4 -4
- package/dist/mcp-server.js +123 -70
- package/dist/mcp-server.js.map +4 -4
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -1978,6 +1978,43 @@ import * as fs4 from "fs/promises";
|
|
|
1978
1978
|
import * as path4 from "path";
|
|
1979
1979
|
import simpleGit3 from "simple-git";
|
|
1980
1980
|
|
|
1981
|
+
// src/errors/index.ts
|
|
1982
|
+
var SyncWorktreesError = class extends Error {
|
|
1983
|
+
constructor(message, code, cause) {
|
|
1984
|
+
super(message);
|
|
1985
|
+
this.code = code;
|
|
1986
|
+
this.cause = cause;
|
|
1987
|
+
this.name = this.constructor.name;
|
|
1988
|
+
Object.setPrototypeOf(this, new.target.prototype);
|
|
1989
|
+
if (cause && cause.stack) {
|
|
1990
|
+
this.stack = `${this.stack}
|
|
1991
|
+
Caused by: ${cause.stack}`;
|
|
1992
|
+
}
|
|
1993
|
+
}
|
|
1994
|
+
};
|
|
1995
|
+
var GitError = class extends SyncWorktreesError {
|
|
1996
|
+
constructor(message, code, cause) {
|
|
1997
|
+
super(message, `GIT_${code}`, cause);
|
|
1998
|
+
}
|
|
1999
|
+
};
|
|
2000
|
+
var GitOperationError = class extends GitError {
|
|
2001
|
+
constructor(operation, details, cause) {
|
|
2002
|
+
super(`Git operation '${operation}' failed: ${details}`, "OPERATION_FAILED", cause);
|
|
2003
|
+
}
|
|
2004
|
+
};
|
|
2005
|
+
var WorktreeError = class extends SyncWorktreesError {
|
|
2006
|
+
constructor(message, code, cause) {
|
|
2007
|
+
super(message, `WORKTREE_${code}`, cause);
|
|
2008
|
+
}
|
|
2009
|
+
};
|
|
2010
|
+
var WorktreeNotCleanError = class extends WorktreeError {
|
|
2011
|
+
constructor(path12, reasons) {
|
|
2012
|
+
super(`Worktree at '${path12}' is not clean: ${reasons.join(", ")}`, "NOT_CLEAN");
|
|
2013
|
+
this.path = path12;
|
|
2014
|
+
this.reasons = reasons;
|
|
2015
|
+
}
|
|
2016
|
+
};
|
|
2017
|
+
|
|
1981
2018
|
// src/utils/git-url.ts
|
|
1982
2019
|
function extractRepoNameFromUrl(gitUrl) {
|
|
1983
2020
|
const url = gitUrl.trim();
|
|
@@ -2375,45 +2412,6 @@ var WorktreeMetadataService = class {
|
|
|
2375
2412
|
import * as fs3 from "fs/promises";
|
|
2376
2413
|
import * as path3 from "path";
|
|
2377
2414
|
import simpleGit2 from "simple-git";
|
|
2378
|
-
|
|
2379
|
-
// src/errors/index.ts
|
|
2380
|
-
var SyncWorktreesError = class extends Error {
|
|
2381
|
-
constructor(message, code, cause) {
|
|
2382
|
-
super(message);
|
|
2383
|
-
this.code = code;
|
|
2384
|
-
this.cause = cause;
|
|
2385
|
-
this.name = this.constructor.name;
|
|
2386
|
-
Object.setPrototypeOf(this, new.target.prototype);
|
|
2387
|
-
if (cause && cause.stack) {
|
|
2388
|
-
this.stack = `${this.stack}
|
|
2389
|
-
Caused by: ${cause.stack}`;
|
|
2390
|
-
}
|
|
2391
|
-
}
|
|
2392
|
-
};
|
|
2393
|
-
var GitError = class extends SyncWorktreesError {
|
|
2394
|
-
constructor(message, code, cause) {
|
|
2395
|
-
super(message, `GIT_${code}`, cause);
|
|
2396
|
-
}
|
|
2397
|
-
};
|
|
2398
|
-
var GitOperationError = class extends GitError {
|
|
2399
|
-
constructor(operation, details, cause) {
|
|
2400
|
-
super(`Git operation '${operation}' failed: ${details}`, "OPERATION_FAILED", cause);
|
|
2401
|
-
}
|
|
2402
|
-
};
|
|
2403
|
-
var WorktreeError = class extends SyncWorktreesError {
|
|
2404
|
-
constructor(message, code, cause) {
|
|
2405
|
-
super(message, `WORKTREE_${code}`, cause);
|
|
2406
|
-
}
|
|
2407
|
-
};
|
|
2408
|
-
var WorktreeNotCleanError = class extends WorktreeError {
|
|
2409
|
-
constructor(path12, reasons) {
|
|
2410
|
-
super(`Worktree at '${path12}' is not clean: ${reasons.join(", ")}`, "NOT_CLEAN");
|
|
2411
|
-
this.path = path12;
|
|
2412
|
-
this.reasons = reasons;
|
|
2413
|
-
}
|
|
2414
|
-
};
|
|
2415
|
-
|
|
2416
|
-
// src/services/worktree-status.service.ts
|
|
2417
2415
|
var OPERATION_FILES = [
|
|
2418
2416
|
{ file: GIT_OPERATIONS.MERGE_HEAD, type: "merge" },
|
|
2419
2417
|
{ file: GIT_OPERATIONS.CHERRY_PICK_HEAD, type: "cherry-pick" },
|
|
@@ -3029,24 +3027,19 @@ var GitService = class {
|
|
|
3029
3027
|
} catch {
|
|
3030
3028
|
}
|
|
3031
3029
|
try {
|
|
3032
|
-
const
|
|
3033
|
-
|
|
3034
|
-
|
|
3035
|
-
|
|
3036
|
-
|
|
3037
|
-
|
|
3030
|
+
const { local: localBranchExists, remote: remoteBranchExists } = await this.branchExists(branchName);
|
|
3031
|
+
await this.runWorktreeAddByMatrix(
|
|
3032
|
+
bareGit,
|
|
3033
|
+
branchName,
|
|
3034
|
+
absoluteWorktreePath,
|
|
3035
|
+
localBranchExists,
|
|
3036
|
+
remoteBranchExists
|
|
3037
|
+
);
|
|
3038
|
+
if (localBranchExists && !remoteBranchExists) {
|
|
3039
|
+
this.logger.info(` - Created worktree for '${branchName}' (no remote yet \u2014 push to set upstream)`);
|
|
3038
3040
|
} else {
|
|
3039
|
-
|
|
3040
|
-
"worktree",
|
|
3041
|
-
"add",
|
|
3042
|
-
"--track",
|
|
3043
|
-
"-b",
|
|
3044
|
-
branchName,
|
|
3045
|
-
absoluteWorktreePath,
|
|
3046
|
-
`origin/${branchName}`
|
|
3047
|
-
]);
|
|
3041
|
+
this.logger.info(` - Created worktree for '${branchName}' with tracking to origin/${branchName}`);
|
|
3048
3042
|
}
|
|
3049
|
-
this.logger.info(` - Created worktree for '${branchName}' with tracking to origin/${branchName}`);
|
|
3050
3043
|
if (!this.isLfsSkipEnabled()) {
|
|
3051
3044
|
await this.verifyLfsFilesDownloaded(absoluteWorktreePath, branchName);
|
|
3052
3045
|
}
|
|
@@ -3062,6 +3055,9 @@ var GitService = class {
|
|
|
3062
3055
|
}
|
|
3063
3056
|
} catch (error) {
|
|
3064
3057
|
const errorMessage = getErrorMessage(error);
|
|
3058
|
+
if (error?.isUpstreamSetupFailure) {
|
|
3059
|
+
throw error;
|
|
3060
|
+
}
|
|
3065
3061
|
if (errorMessage.includes("Metadata creation failed")) {
|
|
3066
3062
|
throw error;
|
|
3067
3063
|
}
|
|
@@ -3079,15 +3075,14 @@ var GitService = class {
|
|
|
3079
3075
|
} catch {
|
|
3080
3076
|
}
|
|
3081
3077
|
try {
|
|
3082
|
-
await
|
|
3083
|
-
|
|
3084
|
-
|
|
3085
|
-
"--track",
|
|
3086
|
-
"-b",
|
|
3078
|
+
const { local: localBranchExists, remote: remoteBranchExists } = await this.branchExists(branchName);
|
|
3079
|
+
await this.runWorktreeAddByMatrix(
|
|
3080
|
+
bareGit,
|
|
3087
3081
|
branchName,
|
|
3088
3082
|
absoluteWorktreePath,
|
|
3089
|
-
|
|
3090
|
-
|
|
3083
|
+
localBranchExists,
|
|
3084
|
+
remoteBranchExists
|
|
3085
|
+
);
|
|
3091
3086
|
this.logger.info(` - Created worktree for '${branchName}' after pruning`);
|
|
3092
3087
|
if (!this.isLfsSkipEnabled()) {
|
|
3093
3088
|
await this.verifyLfsFilesDownloaded(absoluteWorktreePath, branchName);
|
|
@@ -3156,6 +3151,43 @@ var GitService = class {
|
|
|
3156
3151
|
}
|
|
3157
3152
|
}
|
|
3158
3153
|
}
|
|
3154
|
+
async runWorktreeAddByMatrix(bareGit, branchName, absoluteWorktreePath, localExists, remoteExists) {
|
|
3155
|
+
if (localExists && remoteExists) {
|
|
3156
|
+
await bareGit.raw(["worktree", "add", absoluteWorktreePath, branchName]);
|
|
3157
|
+
try {
|
|
3158
|
+
const worktreeGit = this.getCachedGit(absoluteWorktreePath, this.isLfsSkipEnabled());
|
|
3159
|
+
await worktreeGit.branch(["--set-upstream-to", `origin/${branchName}`, branchName]);
|
|
3160
|
+
} catch (error) {
|
|
3161
|
+
let rollbackFailed = false;
|
|
3162
|
+
try {
|
|
3163
|
+
await bareGit.raw(["worktree", "remove", "--force", absoluteWorktreePath]);
|
|
3164
|
+
} catch (rollbackError) {
|
|
3165
|
+
rollbackFailed = true;
|
|
3166
|
+
this.logger.warn(
|
|
3167
|
+
` - Rollback failed for '${branchName}' at '${absoluteWorktreePath}' after upstream setup error: ${getErrorMessage(rollbackError)}`
|
|
3168
|
+
);
|
|
3169
|
+
}
|
|
3170
|
+
const detail = getErrorMessage(error);
|
|
3171
|
+
const suffix = rollbackFailed ? " (rollback failed; partial worktree may remain)" : "";
|
|
3172
|
+
const wrapped = new Error(`Failed to set upstream for '${branchName}': ${detail}${suffix}`);
|
|
3173
|
+
wrapped.isUpstreamSetupFailure = true;
|
|
3174
|
+
throw wrapped;
|
|
3175
|
+
}
|
|
3176
|
+
return;
|
|
3177
|
+
}
|
|
3178
|
+
if (localExists) {
|
|
3179
|
+
await bareGit.raw(["worktree", "add", absoluteWorktreePath, branchName]);
|
|
3180
|
+
return;
|
|
3181
|
+
}
|
|
3182
|
+
if (remoteExists) {
|
|
3183
|
+
await bareGit.raw(["worktree", "add", "--track", "-b", branchName, absoluteWorktreePath, `origin/${branchName}`]);
|
|
3184
|
+
return;
|
|
3185
|
+
}
|
|
3186
|
+
throw new WorktreeError(
|
|
3187
|
+
`Branch '${branchName}' does not exist locally or on origin; create it first`,
|
|
3188
|
+
"BRANCH_NOT_FOUND"
|
|
3189
|
+
);
|
|
3190
|
+
}
|
|
3159
3191
|
async removeWorktree(worktreePath) {
|
|
3160
3192
|
const bareGit = this.getCachedGit(this.bareRepoPath);
|
|
3161
3193
|
await bareGit.raw(["worktree", "remove", worktreePath, "--force"]);
|
|
@@ -3349,10 +3381,18 @@ var GitService = class {
|
|
|
3349
3381
|
}
|
|
3350
3382
|
async branchExists(branchName) {
|
|
3351
3383
|
const bareGit = this.getCachedGit(this.bareRepoPath);
|
|
3352
|
-
const
|
|
3353
|
-
|
|
3354
|
-
|
|
3355
|
-
|
|
3384
|
+
const checkRef = async (ref) => {
|
|
3385
|
+
try {
|
|
3386
|
+
await bareGit.raw(["show-ref", "--verify", "--quiet", ref]);
|
|
3387
|
+
return true;
|
|
3388
|
+
} catch {
|
|
3389
|
+
return false;
|
|
3390
|
+
}
|
|
3391
|
+
};
|
|
3392
|
+
const [local, remote] = await Promise.all([
|
|
3393
|
+
checkRef(`${GIT_CONSTANTS.REFS.HEADS}${branchName}`),
|
|
3394
|
+
checkRef(`${GIT_CONSTANTS.REFS.REMOTES}/${branchName}`)
|
|
3395
|
+
]);
|
|
3356
3396
|
return { local, remote };
|
|
3357
3397
|
}
|
|
3358
3398
|
async getLocalBranches() {
|