stashes 0.1.9 → 0.1.11

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/cli.js CHANGED
@@ -312,7 +312,29 @@ class WorktreeManager {
312
312
  await this.git.raw(["worktree", "prune"]);
313
313
  }
314
314
  logger.info("worktree", `creating pool preview: ${stashId}`, { branch, path: previewPath });
315
- await this.git.raw(["worktree", "add", previewPath, branch]);
315
+ try {
316
+ await this.git.raw(["worktree", "add", previewPath, branch]);
317
+ } catch (err) {
318
+ const msg = err instanceof Error ? err.message : String(err);
319
+ if (msg.includes("is already used by worktree")) {
320
+ logger.warn("worktree", `branch ${branch} locked by stale worktree, cleaning up`);
321
+ const staleDir = join3(this.projectPath, ".stashes", "worktrees", stashId);
322
+ const legacyPreview = join3(this.projectPath, ".stashes", "preview");
323
+ for (const dir of [staleDir, legacyPreview]) {
324
+ if (existsSync3(dir)) {
325
+ try {
326
+ await this.git.raw(["worktree", "remove", "--force", dir]);
327
+ } catch {
328
+ rmSync(dir, { recursive: true, force: true });
329
+ }
330
+ }
331
+ }
332
+ await this.git.raw(["worktree", "prune"]);
333
+ await this.git.raw(["worktree", "add", previewPath, branch]);
334
+ } else {
335
+ throw err;
336
+ }
337
+ }
316
338
  this.symlinkDeps(previewPath);
317
339
  logger.info("worktree", `pool preview created: ${stashId}`);
318
340
  return previewPath;
@@ -1407,9 +1429,11 @@ function createWebSocketHandler(projectPath, userDevPort, appProxyPort) {
1407
1429
  break;
1408
1430
  }
1409
1431
  } catch (err) {
1410
- logger.error("ws", `handler failed for ${event.type}`, {
1411
- error: err instanceof Error ? err.message : String(err)
1412
- });
1432
+ const errorMsg = err instanceof Error ? err.message : String(err);
1433
+ logger.error("ws", `handler failed for ${event.type}`, { error: errorMsg });
1434
+ if ("stashId" in event && event.stashId) {
1435
+ broadcast({ type: "stash:error", stashId: event.stashId, error: errorMsg });
1436
+ }
1413
1437
  }
1414
1438
  },
1415
1439
  close(ws) {
package/dist/mcp.js CHANGED
@@ -248,7 +248,29 @@ class WorktreeManager {
248
248
  await this.git.raw(["worktree", "prune"]);
249
249
  }
250
250
  logger.info("worktree", `creating pool preview: ${stashId}`, { branch, path: previewPath });
251
- await this.git.raw(["worktree", "add", previewPath, branch]);
251
+ try {
252
+ await this.git.raw(["worktree", "add", previewPath, branch]);
253
+ } catch (err) {
254
+ const msg = err instanceof Error ? err.message : String(err);
255
+ if (msg.includes("is already used by worktree")) {
256
+ logger.warn("worktree", `branch ${branch} locked by stale worktree, cleaning up`);
257
+ const staleDir = join2(this.projectPath, ".stashes", "worktrees", stashId);
258
+ const legacyPreview = join2(this.projectPath, ".stashes", "preview");
259
+ for (const dir of [staleDir, legacyPreview]) {
260
+ if (existsSync2(dir)) {
261
+ try {
262
+ await this.git.raw(["worktree", "remove", "--force", dir]);
263
+ } catch {
264
+ rmSync(dir, { recursive: true, force: true });
265
+ }
266
+ }
267
+ }
268
+ await this.git.raw(["worktree", "prune"]);
269
+ await this.git.raw(["worktree", "add", previewPath, branch]);
270
+ } else {
271
+ throw err;
272
+ }
273
+ }
252
274
  this.symlinkDeps(previewPath);
253
275
  logger.info("worktree", `pool preview created: ${stashId}`);
254
276
  return previewPath;
@@ -1537,9 +1559,11 @@ function createWebSocketHandler(projectPath, userDevPort, appProxyPort) {
1537
1559
  break;
1538
1560
  }
1539
1561
  } catch (err) {
1540
- logger.error("ws", `handler failed for ${event.type}`, {
1541
- error: err instanceof Error ? err.message : String(err)
1542
- });
1562
+ const errorMsg = err instanceof Error ? err.message : String(err);
1563
+ logger.error("ws", `handler failed for ${event.type}`, { error: errorMsg });
1564
+ if ("stashId" in event && event.stashId) {
1565
+ broadcast({ type: "stash:error", stashId: event.stashId, error: errorMsg });
1566
+ }
1543
1567
  }
1544
1568
  },
1545
1569
  close(ws) {