workshell 0.5.0 → 0.5.1

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.
Files changed (3) hide show
  1. package/README.md +1 -1
  2. package/dist/index.js +56 -18
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -112,7 +112,7 @@ After cloning, the `main` branch is checked out. Let's say we want to start work
112
112
  $ wk new feat-1
113
113
 
114
114
  ✓ feat-1 (from main)
115
- Opened branch in ephemeral subshell
115
+ Opening branch in ephemeral subshell
116
116
  Type 'wk close' to return.
117
117
  ```
118
118
 
package/dist/index.js CHANGED
@@ -8052,7 +8052,8 @@ function loadGlobalStore() {
8052
8052
  return raw;
8053
8053
  }
8054
8054
  return { repos: {} };
8055
- } catch {
8055
+ } catch (err) {
8056
+ console.error(`Warning: failed to load store: ${err instanceof Error ? err.message : String(err)}`);
8056
8057
  return { repos: {} };
8057
8058
  }
8058
8059
  }
@@ -8116,7 +8117,8 @@ function loadConfig() {
8116
8117
  const content = readFileSync(configPath, "utf-8");
8117
8118
  const parsed = parse(content);
8118
8119
  return parsed;
8119
- } catch {
8120
+ } catch (err) {
8121
+ console.error(`Warning: failed to load ${configPath}: ${err instanceof Error ? err.message : String(err)}`);
8120
8122
  return null;
8121
8123
  }
8122
8124
  }
@@ -8256,7 +8258,8 @@ function getWorktreeForBranch(branch) {
8256
8258
  }
8257
8259
  }
8258
8260
  return null;
8259
- } catch {
8261
+ } catch (err) {
8262
+ console.error(warn(`git worktree list failed: ${err instanceof Error ? err.message : String(err)}`));
8260
8263
  return null;
8261
8264
  }
8262
8265
  }
@@ -8299,7 +8302,8 @@ function removeGitWorktree(path) {
8299
8302
  function pruneWorktrees() {
8300
8303
  try {
8301
8304
  execSync2("git worktree prune", { stdio: "ignore" });
8302
- } catch {
8305
+ } catch (err) {
8306
+ console.error(warn(`git worktree prune failed: ${err instanceof Error ? err.message : String(err)}`));
8303
8307
  }
8304
8308
  }
8305
8309
  function deleteBranch(name) {
@@ -8315,6 +8319,16 @@ function branchHasRemote(name) {
8315
8319
  return false;
8316
8320
  }
8317
8321
  }
8322
+ function branchHasCommitsAheadOf(baseBranch, branch) {
8323
+ try {
8324
+ const count = execSync2(`git rev-list --count "${baseBranch}".."${branch}"`, {
8325
+ encoding: "utf-8"
8326
+ }).trim();
8327
+ return parseInt(count, 10) > 0;
8328
+ } catch {
8329
+ return false;
8330
+ }
8331
+ }
8318
8332
  function canFastForward(baseBranch, targetBranch) {
8319
8333
  try {
8320
8334
  const baseCommit = execSync2(`git rev-parse "${baseBranch}"`, { encoding: "utf-8" }).trim();
@@ -8532,8 +8546,19 @@ var installCmds = {
8532
8546
  pipenv: "pipenv install",
8533
8547
  pdm: "pdm install"
8534
8548
  };
8549
+ var lockfileNames = {
8550
+ npm: "package-lock.json",
8551
+ yarn: "yarn.lock",
8552
+ pnpm: "pnpm-lock.yaml",
8553
+ bun: "bun.lock",
8554
+ uv: "uv.lock",
8555
+ poetry: "poetry.lock",
8556
+ pipenv: "Pipfile.lock",
8557
+ pdm: "pdm.lock"
8558
+ };
8535
8559
  function runPackageManagerInstall(pm, cwd) {
8536
8560
  const cmd2 = installCmds[pm];
8561
+ console.log(dim(`Detected ${lockfileNames[pm]}`));
8537
8562
  console.log(dim(`Running ${cmd2}...`));
8538
8563
  try {
8539
8564
  execSync2(cmd2, { cwd, stdio: "inherit" });
@@ -8590,11 +8615,12 @@ function getIgnoredFiles(repoPath) {
8590
8615
  try {
8591
8616
  const output = execFileSync(
8592
8617
  "git",
8593
- ["ls-files", "--others", "--ignored", "--exclude-standard"],
8594
- { cwd: repoPath, encoding: "utf-8" }
8618
+ ["ls-files", "--others", "--ignored", "--exclude-standard", "--directory"],
8619
+ { cwd: repoPath, encoding: "utf-8", maxBuffer: 10 * 1024 * 1024 }
8595
8620
  );
8596
- return output.split("\n").filter((p) => p.length > 0 && !p.startsWith(".git/"));
8597
- } catch {
8621
+ return output.split("\n").map((p) => p.replace(/\/$/, "")).filter((p) => p.length > 0 && p !== ".git");
8622
+ } catch (err) {
8623
+ console.error(warn(`Failed to list ignored files: ${err instanceof Error ? err.message : String(err)}`));
8598
8624
  return [];
8599
8625
  }
8600
8626
  }
@@ -8626,14 +8652,20 @@ function autoCleanupWorktree(worktreeId, path, store, saveStore2) {
8626
8652
  console.log(" Pruning worktree...");
8627
8653
  try {
8628
8654
  removeGitWorktree(path);
8629
- } catch {
8655
+ } catch (err) {
8656
+ console.error(dim(` git worktree remove failed: ${err instanceof Error ? err.message : String(err)}`));
8630
8657
  }
8631
8658
  pruneWorktrees();
8632
8659
  removeWorktreeMeta(store, worktreeId);
8633
8660
  saveStore2(store);
8634
8661
  const canMergeBranch = branch !== "[missing]" && branch !== "[detached]" && currentBranch !== "HEAD";
8635
8662
  if (!canMergeBranch) {
8636
- console.log(` Pruned '${branch}' worktree`);
8663
+ const branchNote = branch !== "[missing]" && branch !== "[detached]" ? ` Branch '${cyan(branch)}' still exists.` : "";
8664
+ console.log(` Pruned '${branch}' worktree.${branchNote}`);
8665
+ return;
8666
+ }
8667
+ if (!branchHasCommitsAheadOf(currentBranch, branch)) {
8668
+ console.log(` Pruned worktree. Branch '${cyan(branch)}' still exists.`);
8637
8669
  return;
8638
8670
  }
8639
8671
  if (branchHasRemote(branch)) {
@@ -8704,6 +8736,7 @@ function newCommand(branchName, fromBranch) {
8704
8736
  const worktreeId = `${repoName}@${slugify(branch)}`;
8705
8737
  const worktreePath = join3(getWorktreesDir(), worktreeId);
8706
8738
  mkdirSync3(dirname3(worktreePath), { recursive: true });
8739
+ console.log(dim(`Creating worktree for ${cyan(branch)}...`));
8707
8740
  createWorktree(branch, worktreePath, fromBranch);
8708
8741
  initSubmodules(worktreePath);
8709
8742
  const config = loadConfig();
@@ -8719,7 +8752,8 @@ function newCommand(branchName, fromBranch) {
8719
8752
  const parentBranch = getCurrentBranch();
8720
8753
  console.log();
8721
8754
  console.log(success(bold(branch)), dim(`(from ${cyan(baseBranch)})`));
8722
- console.log(dim(`Opened branch in ephemeral subshell`));
8755
+ console.log(dim(worktreePath));
8756
+ console.log(dim(`Opening branch in ephemeral subshell`));
8723
8757
  console.log(dim("Type 'wk close' to return."));
8724
8758
  console.log();
8725
8759
  spawnShell(worktreePath, {
@@ -8776,7 +8810,8 @@ function fetchPRBranch(prRef, prInfo) {
8776
8810
  execSync3(`gh pr checkout ${prRef}`, { stdio: "pipe" });
8777
8811
  execSync3(`git checkout "${currentBranch}"`, { stdio: "pipe" });
8778
8812
  return true;
8779
- } catch {
8813
+ } catch (err) {
8814
+ console.error(`Warning: gh pr checkout failed: ${err instanceof Error ? err.message : String(err)}`);
8780
8815
  try {
8781
8816
  execSync3(`git checkout "${currentBranch}"`, { stdio: "pipe" });
8782
8817
  } catch {
@@ -8835,10 +8870,10 @@ function openBranch(branch, prNumber) {
8835
8870
  console.log();
8836
8871
  if (prNumber) {
8837
8872
  console.log(success(bold(`PR #${prNumber}`)), dim(`branch: ${cyan(branch)}`));
8838
- console.log(dim(`Opened PR in ephemeral subshell`));
8873
+ console.log(dim(`Opening PR in ephemeral subshell`));
8839
8874
  } else {
8840
8875
  console.log(success(bold(branch)));
8841
- console.log(dim(`Opened branch in ephemeral subshell`));
8876
+ console.log(dim(`Opening branch in ephemeral subshell`));
8842
8877
  }
8843
8878
  console.log(dim("Type 'exit' or 'wk close' to return."));
8844
8879
  console.log();
@@ -9785,12 +9820,14 @@ function rmCommand(branch, force = false) {
9785
9820
  try {
9786
9821
  execSync4(`git -C "${worktreePath}" reset --hard HEAD`, { stdio: "ignore" });
9787
9822
  execSync4(`git -C "${worktreePath}" clean -fd`, { stdio: "ignore" });
9788
- } catch {
9823
+ } catch (err) {
9824
+ console.error(warn(`Failed to discard changes: ${err instanceof Error ? err.message : String(err)}`));
9789
9825
  }
9790
9826
  }
9791
9827
  try {
9792
9828
  removeGitWorktree(worktreePath);
9793
- } catch {
9829
+ } catch (err) {
9830
+ console.error(dim(`git worktree remove failed: ${err instanceof Error ? err.message : String(err)}`));
9794
9831
  }
9795
9832
  pruneWorktrees();
9796
9833
  const store = loadStore();
@@ -9887,7 +9924,8 @@ function precloseCommand(force) {
9887
9924
  execSync6("git clean -ffd", { stdio: "ignore" });
9888
9925
  execSync6("git submodule foreach --recursive 'git reset --hard HEAD; git clean -ffd'", { stdio: "ignore" });
9889
9926
  execSync6("git submodule update --init --recursive --force", { stdio: "ignore" });
9890
- } catch {
9927
+ } catch (err) {
9928
+ console.error(`Warning: failed to discard changes: ${err instanceof Error ? err.message : String(err)}`);
9891
9929
  }
9892
9930
  process.exit(0);
9893
9931
  }
@@ -9959,7 +9997,7 @@ function promptChoice() {
9959
9997
  }
9960
9998
 
9961
9999
  // index.ts
9962
- var VERSION = "0.5.0";
10000
+ var VERSION = "0.5.1";
9963
10001
  function printHelp() {
9964
10002
  const dim2 = import_picocolors4.default.dim;
9965
10003
  const cyan2 = import_picocolors4.default.cyan;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "workshell",
3
- "version": "0.5.0",
3
+ "version": "0.5.1",
4
4
  "description": "Agent- and human-friendly Git multitasking, powered by worktrees",
5
5
  "type": "module",
6
6
  "license": "MIT",