sync-worktrees 4.1.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.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 +1 -0
- package/dist/components/StatusBar.d.ts.map +1 -1
- package/dist/components/WorktreeStatusView.d.ts.map +1 -1
- package/dist/index.js +156 -69
- package/dist/index.js.map +4 -4
- package/dist/mcp-server.js +61 -32
- package/dist/mcp-server.js.map +4 -4
- package/dist/services/InteractiveUIService.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/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) {
|
|
@@ -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) {
|
|
@@ -2766,6 +2781,8 @@ var GitService = class {
|
|
|
2766
2781
|
this.statusService = new WorktreeStatusService({ skipLfs: this.config.skipLfs }, this.logger);
|
|
2767
2782
|
this.sparseCheckoutService = new SparseCheckoutService(this.logger);
|
|
2768
2783
|
}
|
|
2784
|
+
config;
|
|
2785
|
+
progressEmitter;
|
|
2769
2786
|
git = null;
|
|
2770
2787
|
bareRepoPath;
|
|
2771
2788
|
mainWorktreePath;
|
|
@@ -3660,6 +3677,9 @@ var RepoOperationLock = class {
|
|
|
3660
3677
|
this.gitService = gitService;
|
|
3661
3678
|
this.logger = logger;
|
|
3662
3679
|
}
|
|
3680
|
+
config;
|
|
3681
|
+
gitService;
|
|
3682
|
+
logger;
|
|
3663
3683
|
updateLogger(logger) {
|
|
3664
3684
|
this.logger = logger;
|
|
3665
3685
|
}
|
|
@@ -3721,6 +3741,9 @@ var SyncRetryPolicy = class {
|
|
|
3721
3741
|
this.gitService = gitService;
|
|
3722
3742
|
this.logger = logger;
|
|
3723
3743
|
}
|
|
3744
|
+
config;
|
|
3745
|
+
gitService;
|
|
3746
|
+
logger;
|
|
3724
3747
|
updateLogger(logger) {
|
|
3725
3748
|
this.logger = logger;
|
|
3726
3749
|
}
|
|
@@ -3941,6 +3964,10 @@ var WorktreeModeSyncRunner = class {
|
|
|
3941
3964
|
this.logger = logger;
|
|
3942
3965
|
this.progressEmitter = progressEmitter;
|
|
3943
3966
|
}
|
|
3967
|
+
config;
|
|
3968
|
+
gitService;
|
|
3969
|
+
logger;
|
|
3970
|
+
progressEmitter;
|
|
3944
3971
|
pathResolution = new PathResolutionService();
|
|
3945
3972
|
updateLogger(logger) {
|
|
3946
3973
|
this.logger = logger;
|
|
@@ -4639,10 +4666,15 @@ var WorktreeSyncService = class {
|
|
|
4639
4666
|
});
|
|
4640
4667
|
}
|
|
4641
4668
|
}
|
|
4669
|
+
config;
|
|
4642
4670
|
gitService;
|
|
4643
4671
|
cloneSyncService = null;
|
|
4644
4672
|
logger;
|
|
4645
|
-
|
|
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);
|
|
4646
4678
|
progressEmitter = new ProgressEmitter();
|
|
4647
4679
|
repoOperationLock;
|
|
4648
4680
|
retryPolicy;
|
|
@@ -4694,7 +4726,7 @@ var WorktreeSyncService = class {
|
|
|
4694
4726
|
return this.gitService.isInitialized();
|
|
4695
4727
|
}
|
|
4696
4728
|
isSyncInProgress() {
|
|
4697
|
-
return this.
|
|
4729
|
+
return this.repoMutex.activeCount + this.repoMutex.pendingCount > 0;
|
|
4698
4730
|
}
|
|
4699
4731
|
getGitService() {
|
|
4700
4732
|
return this.gitService;
|
|
@@ -4710,34 +4742,31 @@ var WorktreeSyncService = class {
|
|
|
4710
4742
|
onProgress(listener) {
|
|
4711
4743
|
return this.progressEmitter.onProgress(listener);
|
|
4712
4744
|
}
|
|
4713
|
-
async runExclusiveRepoOperation(operation) {
|
|
4714
|
-
if (this.
|
|
4745
|
+
async runExclusiveRepoOperation(operation, options = {}) {
|
|
4746
|
+
if (!options.wait && this.repoMutex.activeCount + this.repoMutex.pendingCount > 0) {
|
|
4715
4747
|
this.logger.warn("\u26A0\uFE0F Another repository operation is already in progress, skipping...");
|
|
4716
4748
|
return { started: false, reason: "in_progress" };
|
|
4717
4749
|
}
|
|
4718
|
-
this.
|
|
4719
|
-
|
|
4720
|
-
|
|
4721
|
-
|
|
4722
|
-
|
|
4723
|
-
|
|
4724
|
-
throw error;
|
|
4725
|
-
}
|
|
4726
|
-
if (release === null) {
|
|
4727
|
-
this.syncInProgress = false;
|
|
4728
|
-
this.logger.warn("\u26A0\uFE0F Another process holds the sync lock for this repo, skipping...");
|
|
4729
|
-
return { started: false, reason: "locked" };
|
|
4730
|
-
}
|
|
4731
|
-
try {
|
|
4732
|
-
return { started: true, value: await operation() };
|
|
4733
|
-
} 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
|
+
}
|
|
4734
4756
|
try {
|
|
4735
|
-
await
|
|
4736
|
-
}
|
|
4737
|
-
|
|
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
|
+
}
|
|
4738
4764
|
}
|
|
4739
|
-
|
|
4740
|
-
|
|
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 });
|
|
4741
4770
|
}
|
|
4742
4771
|
emitProgress(event) {
|
|
4743
4772
|
this.progressEmitter.emit(event);
|
|
@@ -5340,7 +5369,7 @@ var RepositoryContext = class {
|
|
|
5340
5369
|
if (!options.detailed) {
|
|
5341
5370
|
return entries.map(buildLean);
|
|
5342
5371
|
}
|
|
5343
|
-
const limit =
|
|
5372
|
+
const limit = pLimit3(DEFAULT_CONFIG.PARALLELISM.MAX_STATUS_CHECKS);
|
|
5344
5373
|
return Promise.all(
|
|
5345
5374
|
entries.map(
|
|
5346
5375
|
(entry) => limit(async () => {
|
|
@@ -5569,7 +5598,7 @@ import { z } from "zod";
|
|
|
5569
5598
|
|
|
5570
5599
|
// src/mcp/handlers.ts
|
|
5571
5600
|
import * as path15 from "path";
|
|
5572
|
-
import
|
|
5601
|
+
import pLimit4 from "p-limit";
|
|
5573
5602
|
|
|
5574
5603
|
// src/utils/disk-space.ts
|
|
5575
5604
|
import fastFolderSize from "fast-folder-size";
|
|
@@ -5816,7 +5845,7 @@ async function handleDetectContext(ctx, params, _extra) {
|
|
|
5816
5845
|
return formatToolResponse(response);
|
|
5817
5846
|
}
|
|
5818
5847
|
const statusService = new WorktreeStatusService();
|
|
5819
|
-
const statusLimit =
|
|
5848
|
+
const statusLimit = pLimit4(DEFAULT_CONFIG.PARALLELISM.MAX_STATUS_CHECKS);
|
|
5820
5849
|
const enriched = await enrichDetectedWorktrees(response.allWorktrees, statusService, statusLimit);
|
|
5821
5850
|
let allWorktreesByRepo = response.allWorktreesByRepo;
|
|
5822
5851
|
if (allWorktreesByRepo) {
|
|
@@ -5852,8 +5881,8 @@ async function enrichDetectedWorktrees(worktrees, statusService, limit) {
|
|
|
5852
5881
|
async function handleListWorktrees(ctx, params, _extra) {
|
|
5853
5882
|
const configuredRepoNames = params.repoName ? [] : ctx.getConfiguredRepositoryNames();
|
|
5854
5883
|
if (configuredRepoNames.length > 0) {
|
|
5855
|
-
const limit =
|
|
5856
|
-
const statusLimit =
|
|
5884
|
+
const limit = pLimit4(DEFAULT_CONFIG.PARALLELISM.MAX_REPOSITORIES);
|
|
5885
|
+
const statusLimit = pLimit4(DEFAULT_CONFIG.PARALLELISM.MAX_STATUS_CHECKS);
|
|
5857
5886
|
const repositories = await Promise.all(
|
|
5858
5887
|
configuredRepoNames.map(
|
|
5859
5888
|
(repoName) => limit(async () => {
|
|
@@ -5881,7 +5910,7 @@ async function handleListWorktrees(ctx, params, _extra) {
|
|
|
5881
5910
|
const results = await listWorktreesForRepo(ctx, params.repoName, params.includeSize);
|
|
5882
5911
|
return formatToolResponse({ worktrees: results });
|
|
5883
5912
|
}
|
|
5884
|
-
async function listWorktreesForRepo(ctx, repoName, includeSize, limit =
|
|
5913
|
+
async function listWorktreesForRepo(ctx, repoName, includeSize, limit = pLimit4(DEFAULT_CONFIG.PARALLELISM.MAX_STATUS_CHECKS)) {
|
|
5885
5914
|
const { discovered, service, git } = await getReadyService(ctx, repoName, {
|
|
5886
5915
|
capability: "listWorktrees",
|
|
5887
5916
|
toolName: "list_worktrees"
|