sync-worktrees 4.0.0 → 4.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/README.md +2 -0
- package/dist/components/App.d.ts +4 -6
- package/dist/components/App.d.ts.map +1 -1
- package/dist/components/BranchCreationWizard.d.ts.map +1 -1
- package/dist/components/OpenEditorWizard.d.ts.map +1 -1
- package/dist/components/StatusBar.d.ts +4 -0
- package/dist/components/StatusBar.d.ts.map +1 -1
- package/dist/components/WorktreeStatusView.d.ts +3 -6
- package/dist/components/WorktreeStatusView.d.ts.map +1 -1
- package/dist/index.js +347 -88
- package/dist/index.js.map +4 -4
- package/dist/mcp-server.js +68 -36
- package/dist/mcp-server.js.map +4 -4
- package/dist/services/InteractiveUIService.d.ts +6 -6
- package/dist/services/InteractiveUIService.d.ts.map +1 -1
- package/dist/services/git.service.d.ts +3 -1
- package/dist/services/git.service.d.ts.map +1 -1
- package/dist/services/worktree-sync.service.d.ts +5 -2
- package/dist/services/worktree-sync.service.d.ts.map +1 -1
- package/dist/types/index.d.ts +14 -0
- package/dist/types/index.d.ts.map +1 -1
- package/dist/utils/app-events.d.ts +10 -0
- package/dist/utils/app-events.d.ts.map +1 -1
- package/dist/utils/config-generator.d.ts.map +1 -1
- package/dist/utils/git-progress.d.ts +5 -5
- package/package.json +28 -27
package/dist/mcp-server.js
CHANGED
|
@@ -6,7 +6,7 @@ import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js"
|
|
|
6
6
|
// src/mcp/context.ts
|
|
7
7
|
import * as fs10 from "fs/promises";
|
|
8
8
|
import * as path14 from "path";
|
|
9
|
-
import
|
|
9
|
+
import pLimit3 from "p-limit";
|
|
10
10
|
import simpleGit6 from "simple-git";
|
|
11
11
|
|
|
12
12
|
// src/constants.ts
|
|
@@ -127,6 +127,8 @@ var SyncWorktreesError = class extends Error {
|
|
|
127
127
|
Caused by: ${cause.stack}`;
|
|
128
128
|
}
|
|
129
129
|
}
|
|
130
|
+
code;
|
|
131
|
+
cause;
|
|
130
132
|
};
|
|
131
133
|
var GitError = class extends SyncWorktreesError {
|
|
132
134
|
constructor(message, code, cause) {
|
|
@@ -149,6 +151,8 @@ var WorktreeNotCleanError = class extends WorktreeError {
|
|
|
149
151
|
this.path = path16;
|
|
150
152
|
this.reasons = reasons;
|
|
151
153
|
}
|
|
154
|
+
path;
|
|
155
|
+
reasons;
|
|
152
156
|
};
|
|
153
157
|
var ConfigError = class extends SyncWorktreesError {
|
|
154
158
|
constructor(message, code, cause) {
|
|
@@ -161,12 +165,15 @@ var ConfigValidationError = class extends ConfigError {
|
|
|
161
165
|
this.field = field;
|
|
162
166
|
this.reason = reason;
|
|
163
167
|
}
|
|
168
|
+
field;
|
|
169
|
+
reason;
|
|
164
170
|
};
|
|
165
171
|
var ConfigFileNotFoundError = class extends ConfigError {
|
|
166
172
|
constructor(configPath) {
|
|
167
173
|
super(`Config file not found: ${configPath}`, "FILE_NOT_FOUND");
|
|
168
174
|
this.configPath = configPath;
|
|
169
175
|
}
|
|
176
|
+
configPath;
|
|
170
177
|
};
|
|
171
178
|
|
|
172
179
|
// src/utils/branch-filter.ts
|
|
@@ -886,6 +893,9 @@ function defaultConsoleOutput(msg, level) {
|
|
|
886
893
|
else console.log(msg);
|
|
887
894
|
}
|
|
888
895
|
|
|
896
|
+
// src/services/worktree-sync.service.ts
|
|
897
|
+
import pLimit2 from "p-limit";
|
|
898
|
+
|
|
889
899
|
// src/utils/lfs-error.ts
|
|
890
900
|
function getErrorMessage(error) {
|
|
891
901
|
if (error instanceof Error) {
|
|
@@ -1110,7 +1120,7 @@ function makeGitProgressHandler(logger, emitProgress) {
|
|
|
1110
1120
|
lastBucket.set(key, bucket);
|
|
1111
1121
|
const total = event.total > 0 ? `${event.processed}/${event.total}` : `${event.processed}`;
|
|
1112
1122
|
const message = `${event.method} ${event.stage}: ${event.progress}% (${total})`;
|
|
1113
|
-
logger.
|
|
1123
|
+
logger.debug(` \u21B3 ${message}`);
|
|
1114
1124
|
emitProgress?.({
|
|
1115
1125
|
phase: event.method,
|
|
1116
1126
|
message,
|
|
@@ -1316,6 +1326,7 @@ var SyncOutcomeAccumulator = class {
|
|
|
1316
1326
|
constructor(options) {
|
|
1317
1327
|
this.options = options;
|
|
1318
1328
|
}
|
|
1329
|
+
options;
|
|
1319
1330
|
counts = cloneCounts(EMPTY_COUNTS);
|
|
1320
1331
|
actions = [];
|
|
1321
1332
|
add(action) {
|
|
@@ -1402,6 +1413,9 @@ var CloneSyncService = class {
|
|
|
1402
1413
|
this.progressEmitter = options.progressEmitter;
|
|
1403
1414
|
this.onSkip = options.onSkip;
|
|
1404
1415
|
}
|
|
1416
|
+
config;
|
|
1417
|
+
gitService;
|
|
1418
|
+
logger;
|
|
1405
1419
|
initialized = false;
|
|
1406
1420
|
resolvedBranch = null;
|
|
1407
1421
|
branchCreatedActions;
|
|
@@ -2408,6 +2422,7 @@ var WorktreeStatusService = class {
|
|
|
2408
2422
|
this.config = config;
|
|
2409
2423
|
this.logger = logger ?? Logger.createDefault();
|
|
2410
2424
|
}
|
|
2425
|
+
config;
|
|
2411
2426
|
gitInstances = /* @__PURE__ */ new Map();
|
|
2412
2427
|
logger;
|
|
2413
2428
|
async checkWorktreeStatus(worktreePath) {
|
|
@@ -2756,8 +2771,9 @@ function sanitizeGitEnv(env) {
|
|
|
2756
2771
|
return sanitized;
|
|
2757
2772
|
}
|
|
2758
2773
|
var GitService = class {
|
|
2759
|
-
constructor(config, logger) {
|
|
2774
|
+
constructor(config, logger, progressEmitter) {
|
|
2760
2775
|
this.config = config;
|
|
2776
|
+
this.progressEmitter = progressEmitter;
|
|
2761
2777
|
this.logger = logger ?? Logger.createDefault(void 0, config.debug);
|
|
2762
2778
|
this.bareRepoPath = this.config.bareRepoDir || getDefaultBareRepoDir(this.config.repoUrl);
|
|
2763
2779
|
this.mainWorktreePath = path8.join(this.config.worktreeDir, GIT_CONSTANTS.DEFAULT_BRANCH);
|
|
@@ -2765,6 +2781,8 @@ var GitService = class {
|
|
|
2765
2781
|
this.statusService = new WorktreeStatusService({ skipLfs: this.config.skipLfs }, this.logger);
|
|
2766
2782
|
this.sparseCheckoutService = new SparseCheckoutService(this.logger);
|
|
2767
2783
|
}
|
|
2784
|
+
config;
|
|
2785
|
+
progressEmitter;
|
|
2768
2786
|
git = null;
|
|
2769
2787
|
bareRepoPath;
|
|
2770
2788
|
mainWorktreePath;
|
|
@@ -2798,7 +2816,9 @@ var GitService = class {
|
|
|
2798
2816
|
return git;
|
|
2799
2817
|
}
|
|
2800
2818
|
buildSimpleGitOptions(blockMs) {
|
|
2801
|
-
const options = {
|
|
2819
|
+
const options = {
|
|
2820
|
+
progress: makeGitProgressHandler(this.logger, (event) => this.progressEmitter?.(event))
|
|
2821
|
+
};
|
|
2802
2822
|
if (blockMs > 0) options.timeout = { block: blockMs };
|
|
2803
2823
|
return options;
|
|
2804
2824
|
}
|
|
@@ -3657,6 +3677,9 @@ var RepoOperationLock = class {
|
|
|
3657
3677
|
this.gitService = gitService;
|
|
3658
3678
|
this.logger = logger;
|
|
3659
3679
|
}
|
|
3680
|
+
config;
|
|
3681
|
+
gitService;
|
|
3682
|
+
logger;
|
|
3660
3683
|
updateLogger(logger) {
|
|
3661
3684
|
this.logger = logger;
|
|
3662
3685
|
}
|
|
@@ -3718,6 +3741,9 @@ var SyncRetryPolicy = class {
|
|
|
3718
3741
|
this.gitService = gitService;
|
|
3719
3742
|
this.logger = logger;
|
|
3720
3743
|
}
|
|
3744
|
+
config;
|
|
3745
|
+
gitService;
|
|
3746
|
+
logger;
|
|
3721
3747
|
updateLogger(logger) {
|
|
3722
3748
|
this.logger = logger;
|
|
3723
3749
|
}
|
|
@@ -3938,6 +3964,10 @@ var WorktreeModeSyncRunner = class {
|
|
|
3938
3964
|
this.logger = logger;
|
|
3939
3965
|
this.progressEmitter = progressEmitter;
|
|
3940
3966
|
}
|
|
3967
|
+
config;
|
|
3968
|
+
gitService;
|
|
3969
|
+
logger;
|
|
3970
|
+
progressEmitter;
|
|
3941
3971
|
pathResolution = new PathResolutionService();
|
|
3942
3972
|
updateLogger(logger) {
|
|
3943
3973
|
this.logger = logger;
|
|
@@ -4618,7 +4648,7 @@ var WorktreeSyncService = class {
|
|
|
4618
4648
|
constructor(config) {
|
|
4619
4649
|
this.config = config;
|
|
4620
4650
|
this.logger = config.logger ?? Logger.createDefault(void 0, config.debug);
|
|
4621
|
-
this.gitService = new GitService(config, this.logger);
|
|
4651
|
+
this.gitService = new GitService(config, this.logger, (event) => this.emitProgress(event));
|
|
4622
4652
|
this.repoOperationLock = new RepoOperationLock(config, this.gitService, this.logger);
|
|
4623
4653
|
this.retryPolicy = new SyncRetryPolicy(config, this.gitService, this.logger);
|
|
4624
4654
|
this.worktreeModeSyncRunner = new WorktreeModeSyncRunner(
|
|
@@ -4636,10 +4666,15 @@ var WorktreeSyncService = class {
|
|
|
4636
4666
|
});
|
|
4637
4667
|
}
|
|
4638
4668
|
}
|
|
4669
|
+
config;
|
|
4639
4670
|
gitService;
|
|
4640
4671
|
cloneSyncService = null;
|
|
4641
4672
|
logger;
|
|
4642
|
-
|
|
4673
|
+
// In-process FIFO serializer for all bare-repo-mutating operations (sync, init,
|
|
4674
|
+
// interactive create). One per repo. wait:true callers queue behind an in-flight op;
|
|
4675
|
+
// wait:false callers fail fast. The cross-process file lock (RepoOperationLock) is
|
|
4676
|
+
// acquired inside the mutex body for multi-process safety.
|
|
4677
|
+
repoMutex = pLimit2(1);
|
|
4643
4678
|
progressEmitter = new ProgressEmitter();
|
|
4644
4679
|
repoOperationLock;
|
|
4645
4680
|
retryPolicy;
|
|
@@ -4691,7 +4726,7 @@ var WorktreeSyncService = class {
|
|
|
4691
4726
|
return this.gitService.isInitialized();
|
|
4692
4727
|
}
|
|
4693
4728
|
isSyncInProgress() {
|
|
4694
|
-
return this.
|
|
4729
|
+
return this.repoMutex.activeCount + this.repoMutex.pendingCount > 0;
|
|
4695
4730
|
}
|
|
4696
4731
|
getGitService() {
|
|
4697
4732
|
return this.gitService;
|
|
@@ -4707,34 +4742,31 @@ var WorktreeSyncService = class {
|
|
|
4707
4742
|
onProgress(listener) {
|
|
4708
4743
|
return this.progressEmitter.onProgress(listener);
|
|
4709
4744
|
}
|
|
4710
|
-
async runExclusiveRepoOperation(operation) {
|
|
4711
|
-
if (this.
|
|
4745
|
+
async runExclusiveRepoOperation(operation, options = {}) {
|
|
4746
|
+
if (!options.wait && this.repoMutex.activeCount + this.repoMutex.pendingCount > 0) {
|
|
4712
4747
|
this.logger.warn("\u26A0\uFE0F Another repository operation is already in progress, skipping...");
|
|
4713
4748
|
return { started: false, reason: "in_progress" };
|
|
4714
4749
|
}
|
|
4715
|
-
this.
|
|
4716
|
-
|
|
4717
|
-
|
|
4718
|
-
|
|
4719
|
-
|
|
4720
|
-
|
|
4721
|
-
throw error;
|
|
4722
|
-
}
|
|
4723
|
-
if (release === null) {
|
|
4724
|
-
this.syncInProgress = false;
|
|
4725
|
-
this.logger.warn("\u26A0\uFE0F Another process holds the sync lock for this repo, skipping...");
|
|
4726
|
-
return { started: false, reason: "locked" };
|
|
4727
|
-
}
|
|
4728
|
-
try {
|
|
4729
|
-
return { started: true, value: await operation() };
|
|
4730
|
-
} finally {
|
|
4750
|
+
return this.repoMutex(async () => {
|
|
4751
|
+
const release = await this.repoOperationLock.acquire();
|
|
4752
|
+
if (release === null) {
|
|
4753
|
+
this.logger.warn("\u26A0\uFE0F Another process holds the sync lock for this repo, skipping...");
|
|
4754
|
+
return { started: false, reason: "locked" };
|
|
4755
|
+
}
|
|
4731
4756
|
try {
|
|
4732
|
-
await
|
|
4733
|
-
}
|
|
4734
|
-
|
|
4757
|
+
return { started: true, value: await operation() };
|
|
4758
|
+
} finally {
|
|
4759
|
+
try {
|
|
4760
|
+
await release();
|
|
4761
|
+
} catch (releaseError) {
|
|
4762
|
+
this.logger.warn(`Failed to release sync lock: ${getErrorMessage(releaseError)}`);
|
|
4763
|
+
}
|
|
4735
4764
|
}
|
|
4736
|
-
|
|
4737
|
-
|
|
4765
|
+
});
|
|
4766
|
+
}
|
|
4767
|
+
// Interactive variant: queues behind any in-flight sync/op instead of failing fast.
|
|
4768
|
+
async runQueuedRepoOperation(operation) {
|
|
4769
|
+
return this.runExclusiveRepoOperation(operation, { wait: true });
|
|
4738
4770
|
}
|
|
4739
4771
|
emitProgress(event) {
|
|
4740
4772
|
this.progressEmitter.emit(event);
|
|
@@ -5337,7 +5369,7 @@ var RepositoryContext = class {
|
|
|
5337
5369
|
if (!options.detailed) {
|
|
5338
5370
|
return entries.map(buildLean);
|
|
5339
5371
|
}
|
|
5340
|
-
const limit =
|
|
5372
|
+
const limit = pLimit3(DEFAULT_CONFIG.PARALLELISM.MAX_STATUS_CHECKS);
|
|
5341
5373
|
return Promise.all(
|
|
5342
5374
|
entries.map(
|
|
5343
5375
|
(entry) => limit(async () => {
|
|
@@ -5566,7 +5598,7 @@ import { z } from "zod";
|
|
|
5566
5598
|
|
|
5567
5599
|
// src/mcp/handlers.ts
|
|
5568
5600
|
import * as path15 from "path";
|
|
5569
|
-
import
|
|
5601
|
+
import pLimit4 from "p-limit";
|
|
5570
5602
|
|
|
5571
5603
|
// src/utils/disk-space.ts
|
|
5572
5604
|
import fastFolderSize from "fast-folder-size";
|
|
@@ -5813,7 +5845,7 @@ async function handleDetectContext(ctx, params, _extra) {
|
|
|
5813
5845
|
return formatToolResponse(response);
|
|
5814
5846
|
}
|
|
5815
5847
|
const statusService = new WorktreeStatusService();
|
|
5816
|
-
const statusLimit =
|
|
5848
|
+
const statusLimit = pLimit4(DEFAULT_CONFIG.PARALLELISM.MAX_STATUS_CHECKS);
|
|
5817
5849
|
const enriched = await enrichDetectedWorktrees(response.allWorktrees, statusService, statusLimit);
|
|
5818
5850
|
let allWorktreesByRepo = response.allWorktreesByRepo;
|
|
5819
5851
|
if (allWorktreesByRepo) {
|
|
@@ -5849,8 +5881,8 @@ async function enrichDetectedWorktrees(worktrees, statusService, limit) {
|
|
|
5849
5881
|
async function handleListWorktrees(ctx, params, _extra) {
|
|
5850
5882
|
const configuredRepoNames = params.repoName ? [] : ctx.getConfiguredRepositoryNames();
|
|
5851
5883
|
if (configuredRepoNames.length > 0) {
|
|
5852
|
-
const limit =
|
|
5853
|
-
const statusLimit =
|
|
5884
|
+
const limit = pLimit4(DEFAULT_CONFIG.PARALLELISM.MAX_REPOSITORIES);
|
|
5885
|
+
const statusLimit = pLimit4(DEFAULT_CONFIG.PARALLELISM.MAX_STATUS_CHECKS);
|
|
5854
5886
|
const repositories = await Promise.all(
|
|
5855
5887
|
configuredRepoNames.map(
|
|
5856
5888
|
(repoName) => limit(async () => {
|
|
@@ -5878,7 +5910,7 @@ async function handleListWorktrees(ctx, params, _extra) {
|
|
|
5878
5910
|
const results = await listWorktreesForRepo(ctx, params.repoName, params.includeSize);
|
|
5879
5911
|
return formatToolResponse({ worktrees: results });
|
|
5880
5912
|
}
|
|
5881
|
-
async function listWorktreesForRepo(ctx, repoName, includeSize, limit =
|
|
5913
|
+
async function listWorktreesForRepo(ctx, repoName, includeSize, limit = pLimit4(DEFAULT_CONFIG.PARALLELISM.MAX_STATUS_CHECKS)) {
|
|
5882
5914
|
const { discovered, service, git } = await getReadyService(ctx, repoName, {
|
|
5883
5915
|
capability: "listWorktrees",
|
|
5884
5916
|
toolName: "list_worktrees"
|