workshell 0.0.5 → 0.0.7

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 +41 -36
  2. package/dist/index.js +120 -81
  3. package/package.json +3 -3
package/README.md CHANGED
@@ -20,23 +20,28 @@
20
20
  ## Install
21
21
 
22
22
  ```bash
23
- $ npm i -g workshell
23
+ $ npm i -g workshell # aliases to `wk`
24
+ $ wk --help
25
+ wk v0.0.6 - Open branches in ephemeral subshells
26
+
27
+ Usage: wk <command> [options]
28
+ # ...
24
29
  ```
25
30
 
26
31
  <br/>
27
32
 
28
33
  ## How `workshell` works
29
34
 
30
- There have been many attempts to nail a DX for parallel work in the agentic coding era. Most are thin wrappers over `git worktree`. Instead `wksh` introduces a new paradigm: the *workshell*.
35
+ There have been many attempts to nail a DX for parallel work in the agentic coding era. Most are thin wrappers over `git worktree`. Instead `wk` introduces a new paradigm: the *workshell*.
31
36
 
32
37
  **A _workshell_ is an ephemeral worktree whose lifecycle is bound to a subshell.**
33
38
 
34
39
  Here's how it works (key points in **bold**).
35
40
 
36
- - You open a Git branch with `wksh open <branch>` or create a new one with `wksh new <branch>`.
37
- - An ephemeral worktree is created for this branch (in `.git/workshell/worktrees`) and **opened in a fresh subshell**.
41
+ - You open a Git branch with `wk open <branch>` or create a new one with `wk new <branch>`.
42
+ - An ephemeral worktree is created for this branch (in `~/.workshell/worktrees`) and **opened in a fresh subshell**.
38
43
  - You are now in an fresh checkout of your repo that is isolated on disk. Make changes with your agent/editor of choice and commit them.
39
- - You close the subshell with `wksh close`. **The associated worktree is auto-pruned**.
44
+ - You close the subshell with `wk close`. **The associated worktree is auto-pruned**.
40
45
  - Your changes still exist on the associated branch, as Git commits/branches are shared among all worktrees. The worktree is destroyed—but your commits aren't.
41
46
 
42
47
  <!-- That's it. **Ephemeral worktrees whose lifecycle is bound to a subshell.** When the subshell exits, the worktree is destroyed—but your commits aren't. -->
@@ -44,14 +49,14 @@ Here's how it works (key points in **bold**).
44
49
  <!--
45
50
  ## How does it work
46
51
 
47
- There have been many attempts to nail a DX for parallel work in the agentic coding era. Most are thin wrappers over `git worktree`. That's not what `wksh` is (though worktrees are used internally).
52
+ There have been many attempts to nail a DX for parallel work in the agentic coding era. Most are thin wrappers over `git worktree`. That's not what `wk` is (though worktrees are used internally).
48
53
 
49
54
  Here's how it works (key points in **bold**).
50
55
 
51
- - **A fresh worktree is created** — The `wksh` utility a) creates a new worktree in `.git/workshell/worktrees` and b) opens it in a *subshell*.
56
+ - **A fresh worktree is created** — The `wk` utility a) creates a new worktree in `~/.workshell/worktrees` and b) opens it in a *subshell*.
52
57
  - **Make edits and commit** — From the worksh your preferred IDE/agent.
53
58
  - **Commit your changes** — Though your file system is isolated, Git commit history (including branches) is still shared among all worktrees.
54
- - **Exit the subshell** — Run `wksh close` to exit the subshell. As with `git switch`, `wksh close` won't let you close the subshell if you have unstaged/uncommitted changes.
59
+ - **Exit the subshell** — Run `wk close` to exit the subshell. As with `git switch`, `wk close` won't let you close the subshell if you have unstaged/uncommitted changes.
55
60
  - **The worktree is auto-pruned** — This is key. The lifecycle of the worktree is tied to the subshell. When the subshell is closed, the worktree is destroyed. But *the commits you made inside the subshell* still exist.
56
61
  - **Merge in your changes** — Merge/rebase your branch as you normally would, or push to GitHub to open a PR. -->
57
62
 
@@ -63,15 +68,15 @@ This approach has some nice properties.
63
68
 
64
69
  - 🖥️ **Tab-local workspaces** — Normally a `git checkout`/`git switch` changes your active branch for all terminals. With workshells, you can functionality open branches *in the current tab only*.
65
70
  - 🌳 **Full isolation** — Each workshell is isolated on disk, so the changes you make don't interfere anything else you're doing.
66
- - 🙅‍♂️ **Never stash again** — You can `wksh open` a branch even with uncommitted changes. When you exit the subshell, things will be exactly the same as they were. ☕️
67
- - 🪾 **Consistent with branch semantics** — As with regular `git switch`, `wksh close` won't let you close the subshell if you have unstaged/uncommitted changes. This is a feature, not a bug! Regular worktrees make it easy to lose your work in a forgotten corner of your file system.
71
+ - 🙅‍♂️ **Never stash again** — You can `wk open` a branch even with uncommitted changes. When you exit the subshell, things will be exactly the same as they were. ☕️
72
+ - 🪾 **Consistent with branch semantics** — As with regular `git switch`, `wk close` won't let you close the subshell if you have unstaged/uncommitted changes. This is a feature, not a bug! Regular worktrees make it easy to lose your work in a forgotten corner of your file system.
68
73
  - 🤖 **Agent-ready** — Spin up parallel workshells so multiple agents can work simultaneously without conflicts.
69
74
 
70
75
  <br/>
71
76
 
72
77
  ## Quickstart
73
78
 
74
- This section is entirely linear and self-contained. Try running all these commands in order to get a feel for how `wksh` works. First, install `wksh`.
79
+ This section is entirely linear and self-contained. Try running all these commands in order to get a feel for how `wk` works. First, install `wk`.
75
80
 
76
81
  ```bash
77
82
  $ npm i -g workshell
@@ -79,10 +84,10 @@ $ npm i -g workshell
79
84
 
80
85
  <br/>
81
86
 
82
- This installs the `workshell` CLI. For convenience, it's also aliased to `wksh`. We'll use `wksh` throughout the quickstart.
87
+ This installs the `workshell` CLI. For convenience, it's also aliased to `wk`. We'll use `wk` throughout the quickstart.
83
88
 
84
89
  ```sh
85
- $ wksh status
90
+ $ wk status
86
91
 
87
92
  branch: main (root)
88
93
  worktree: /Users/colinmcd94/Documents/projects/pf
@@ -103,11 +108,11 @@ $ cd zod
103
108
  After cloning, the `main` branch is checked out. Let's say we want to start work on a new feature:
104
109
 
105
110
  ```bash
106
- $ wksh new feat-1
111
+ $ wk new feat-1
107
112
 
108
113
  ✓ feat-1 (from main)
109
- Opened branch in ephemeral subshell at .git/workshell/worktrees/zod@feat-1
110
- Type 'wksh close' to return.
114
+ Opened branch in ephemeral subshell
115
+ Type 'wk close' to return.
111
116
  ```
112
117
 
113
118
  <br/>
@@ -116,7 +121,7 @@ You're now in a workshell. Check where you are:
116
121
 
117
122
  ```bash
118
123
  $ pwd
119
- /Users/colinmcd94/Documents/repos/zod/.git/workshell/worktrees/zod@feat-1
124
+ ~/.workshell/worktrees/{repo-id}/zod@feat-1
120
125
 
121
126
  $ git branch --show-current
122
127
  feat-1
@@ -135,10 +140,10 @@ $ touch a.txt
135
140
  Now let's try to close the workshell.
136
141
 
137
142
  ```bash
138
- $ wksh close
143
+ $ wk close
139
144
  ⚠ Uncommitted changes found. Commit, stash, or reset your changes first.
140
145
  Or use --force/-f to discard changes
141
- wksh close -f
146
+ wk close -f
142
147
  ```
143
148
 
144
149
  <br/>
@@ -151,10 +156,10 @@ $ git add -A && git commit -am "Add a.txt"
151
156
 
152
157
  <br/>
153
158
 
154
- Now we can try closing again. Since our changes can be fast-forwarded from the base branch, `wksh` offers to auto-merge the changes.
159
+ Now we can try closing again. Since our changes can be fast-forwarded from the base branch, `wk` offers to auto-merge the changes.
155
160
 
156
161
  ```bash
157
- $ wksh close
162
+ $ wk close
158
163
  ✓ Back in main
159
164
  Pruned worktree. Your changes are still in the 'feat-1' branch.
160
165
  To merge your changes:
@@ -170,9 +175,9 @@ $ wksh close
170
175
  ## CLI
171
176
 
172
177
  ```sh
173
- wksh v0.x.y - Human- and agent-friendly Git multitasking
178
+ wk v0.x.y - Human- and agent-friendly Git multitasking
174
179
 
175
- Usage: wksh <command> [options]
180
+ Usage: wk <command> [options]
176
181
 
177
182
  Commands:
178
183
  new [branch] Create a branch and open it [--from <branch>]
@@ -192,10 +197,10 @@ Options:
192
197
 
193
198
  ### List orphaned worktrees
194
199
 
195
- Normally the worktree will be auto-pruned when you close its associated workshell. If a worktree is left behind for some reason, you can list them with `wksh ls`.
200
+ Normally the worktree will be auto-pruned when you close its associated workshell. If a worktree is left behind for some reason, you can list them with `wk ls`.
196
201
 
197
202
  ```sh
198
- $ wksh ls
203
+ $ wk ls
199
204
  ┌────────┬───────────┬───────────────┐
200
205
  │ branch │ status │ created │
201
206
  ├────────┼───────────┼───────────────┤
@@ -212,10 +217,10 @@ $ wksh ls
212
217
  You can open any existing Git branch in a workshell.
213
218
 
214
219
  ```sh
215
- $ wksh open feat-1
220
+ $ wk open feat-1
216
221
 
217
222
  ✓ feat-1 (existing worktree)
218
- Type 'wksh close' to return.
223
+ Type 'wk close' to return.
219
224
  ```
220
225
 
221
226
  <br />
@@ -223,7 +228,7 @@ Type 'wksh close' to return.
223
228
  ### Show current branch status
224
229
 
225
230
  ```sh
226
- $ wksh status
231
+ $ wk status
227
232
  branch: main (root)
228
233
  worktree: /path/to/zod
229
234
  status: clean
@@ -236,7 +241,7 @@ status: clean
236
241
  Remove the worktree for a branch (the branch itself is kept):
237
242
 
238
243
  ```sh
239
- $ wksh rm feat-1
244
+ $ wk rm feat-1
240
245
 
241
246
  ✓ Pruned worktree for feat-1
242
247
  ```
@@ -248,7 +253,7 @@ $ wksh rm feat-1
248
253
  This closes the current workshell and auto-prunes the associated worktree. Your changes survive in your branch commits.
249
254
 
250
255
  ```sh
251
- $ wksh close
256
+ $ wk close
252
257
  ✓ Back in main
253
258
  Pruned worktree. Your changes are still in the 'feat-1' branch.
254
259
  To merge your changes:
@@ -268,7 +273,7 @@ If the branch hasn't been pushed to a remote, you'll be prompted to auto-merge:
268
273
  That command will fail if you have unstaged/uncommited changes. Use the `--force`/`-f` flag to force close the workshell; **this will discard uncommitted changes**.
269
274
 
270
275
  ```sh
271
- $ wksh close --force
276
+ $ wk close --force
272
277
  ```
273
278
 
274
279
  <br />
@@ -278,7 +283,7 @@ $ wksh close --force
278
283
  To print or create a config file:
279
284
 
280
285
  ```sh
281
- $ wksh config
286
+ $ wk config
282
287
 
283
288
  ✓ Config file: /path/to/repo/.git/workshell.toml
284
289
 
@@ -290,7 +295,7 @@ setup = "npm install"
290
295
  If no config exists, you'll be prompted to create one.
291
296
 
292
297
  ```sh
293
- $ wksh config
298
+ $ wk config
294
299
 
295
300
  No config file found.
296
301
 
@@ -307,9 +312,9 @@ Choice (1/2): 1
307
312
 
308
313
  ## `workshell.toml`
309
314
 
310
- You can configure `wksh` with a `workshell.toml` file. This is useful for running setup scripts when opening a workshell (e.g., `npm install`).
315
+ You can configure `wk` with a `workshell.toml` file. This is useful for running setup scripts when opening a workshell (e.g., `npm install`).
311
316
 
312
- `wksh` looks for config files in the following order:
317
+ `wk` looks for config files in the following order:
313
318
 
314
319
  | Path | Description |
315
320
  |------|-------------|
@@ -325,6 +330,6 @@ Currently only one setting is supported: `setup`.
325
330
  # the following variable substitutions are supported
326
331
  # `{{ branch }}` — The name of the opened branch, e.g. `feature/auth`
327
332
  # `{{ repo_path }}` — The absolute path to main repo, e.g. `/path/to/repo`
328
- # `{{ worktree_path }}` — The absolute path to worktree, e.g. `/path/to/repo/.git/workshell/worktrees/repo@feat`
333
+ # `{{ worktree_path }}` — The absolute path to worktree, e.g. `~/.workshell/worktrees/.../repo@feat`
329
334
  setup = "npm install && cp {{ repo_path }}/.env {{ worktree_path }}/.env"
330
335
  ```
package/dist/index.js CHANGED
@@ -5785,13 +5785,15 @@ var require_src = __commonJS({
5785
5785
  var import_picocolors4 = __toESM(require_picocolors(), 1);
5786
5786
 
5787
5787
  // commands/new.ts
5788
- import { basename as basename3, dirname as dirname3, join as join3, relative } from "path";
5788
+ import { basename as basename3, dirname as dirname3, join as join3 } from "path";
5789
5789
  import { mkdirSync as mkdirSync3 } from "fs";
5790
5790
 
5791
5791
  // store.ts
5792
5792
  import { execSync } from "child_process";
5793
5793
  import { existsSync, mkdirSync, readFileSync, writeFileSync } from "fs";
5794
5794
  import { basename, dirname, isAbsolute, join } from "path";
5795
+ import { homedir } from "os";
5796
+ import { randomUUID } from "crypto";
5795
5797
 
5796
5798
  // node_modules/.pnpm/smol-toml@1.6.0/node_modules/smol-toml/dist/error.js
5797
5799
  function getLineColFromPtr(string, ptr) {
@@ -6480,6 +6482,25 @@ function parse(toml, { maxDepth = 1e3, integersAsBigInt } = {}) {
6480
6482
 
6481
6483
  // store.ts
6482
6484
  var STORE_FILE = "store.json";
6485
+ function getWorkshellRoot() {
6486
+ const xdgDataHome = process.env.XDG_DATA_HOME;
6487
+ if (xdgDataHome) {
6488
+ return join(xdgDataHome, "workshell");
6489
+ }
6490
+ return join(homedir(), ".workshell");
6491
+ }
6492
+ function getRepoId() {
6493
+ try {
6494
+ const id = execSync("git config --local workshell.id", { encoding: "utf-8" }).trim();
6495
+ if (id) {
6496
+ return id;
6497
+ }
6498
+ } catch {
6499
+ }
6500
+ const newId = randomUUID().replace(/-/g, "").slice(0, 8);
6501
+ execSync(`git config --local workshell.id "${newId}"`, { encoding: "utf-8" });
6502
+ return newId;
6503
+ }
6483
6504
  function getGitRoot() {
6484
6505
  return execSync("git rev-parse --show-toplevel", { encoding: "utf-8" }).trim();
6485
6506
  }
@@ -6494,33 +6515,51 @@ function getMainWorktree() {
6494
6515
  return dirname(getGitCommonDir());
6495
6516
  }
6496
6517
  function getWorktreesDir() {
6497
- return join(getGitCommonDir(), "workshell", "worktrees");
6518
+ return join(getWorkshellRoot(), "worktrees", getRepoId());
6498
6519
  }
6499
6520
  function getStorePath() {
6500
- return join(getGitCommonDir(), "workshell");
6521
+ return getWorkshellRoot();
6501
6522
  }
6502
- function loadStore() {
6523
+ function loadGlobalStore() {
6503
6524
  const storePath = getStorePath();
6504
6525
  const filePath = join(storePath, STORE_FILE);
6505
6526
  if (!existsSync(filePath)) {
6506
- return { worktrees: {} };
6527
+ return { repos: {} };
6507
6528
  }
6508
6529
  try {
6509
6530
  const data = readFileSync(filePath, "utf-8");
6510
6531
  const raw = JSON.parse(data);
6511
- if (Array.isArray(raw.worktrees) || typeof raw.worktrees !== "object") {
6512
- return { worktrees: {}, auto_merge_prompt: raw.auto_merge_prompt };
6532
+ if (raw.repos && typeof raw.repos === "object") {
6533
+ return raw;
6513
6534
  }
6514
- return raw;
6535
+ return { repos: {} };
6515
6536
  } catch {
6516
- return { worktrees: {} };
6537
+ return { repos: {} };
6517
6538
  }
6518
6539
  }
6519
- function saveStore(store) {
6540
+ function saveGlobalStore(globalStore) {
6520
6541
  const storePath = getStorePath();
6521
6542
  mkdirSync(storePath, { recursive: true });
6522
6543
  const filePath = join(storePath, STORE_FILE);
6523
- writeFileSync(filePath, JSON.stringify(store, null, 2));
6544
+ writeFileSync(filePath, JSON.stringify(globalStore, null, 2));
6545
+ }
6546
+ function loadStore() {
6547
+ const globalStore = loadGlobalStore();
6548
+ const repoId = getRepoId();
6549
+ const repoData = globalStore.repos[repoId];
6550
+ if (!repoData) {
6551
+ return { worktrees: {} };
6552
+ }
6553
+ if (Array.isArray(repoData.worktrees) || typeof repoData.worktrees !== "object") {
6554
+ return { worktrees: {}, auto_merge_prompt: repoData.auto_merge_prompt };
6555
+ }
6556
+ return repoData;
6557
+ }
6558
+ function saveStore(store) {
6559
+ const globalStore = loadGlobalStore();
6560
+ const repoId = getRepoId();
6561
+ globalStore.repos[repoId] = store;
6562
+ saveGlobalStore(globalStore);
6524
6563
  }
6525
6564
  function getWorktreeMeta(store, id) {
6526
6565
  return store.worktrees[id];
@@ -6594,7 +6633,7 @@ function getCommandName() {
6594
6633
  }
6595
6634
  const scriptName = basename2(scriptPath, ".js");
6596
6635
  if (scriptName === "index" || scriptName === "dist") {
6597
- return "wksh";
6636
+ return "wk";
6598
6637
  }
6599
6638
  return scriptName;
6600
6639
  }
@@ -6770,7 +6809,7 @@ function generateName() {
6770
6809
  const bytes = new Uint8Array(4);
6771
6810
  crypto.getRandomValues(bytes);
6772
6811
  const hex = Array.from(bytes).map((b) => b.toString(16).padStart(2, "0")).join("");
6773
- return `wksh-${hex}`;
6812
+ return `wk-${hex}`;
6774
6813
  }
6775
6814
  function slugify(name) {
6776
6815
  return name.replace(/[^a-zA-Z0-9-]/g, "-").replace(/-+/g, "-").replace(/^-|-$/g, "");
@@ -6797,9 +6836,9 @@ exit() {
6797
6836
  builtin exit "$@"
6798
6837
  fi
6799
6838
  # Support: exit -f / exit --force (strip before calling builtin exit)
6800
- local wksh_force=""
6839
+ local wk_force=""
6801
6840
  if [[ "\${1:-}" == "-f" || "\${1:-}" == "--force" ]]; then
6802
- wksh_force="\${1:-}"
6841
+ wk_force="\${1:-}"
6803
6842
  shift
6804
6843
  fi
6805
6844
  # Fail open if ${cmd2} not in PATH
@@ -6807,30 +6846,30 @@ exit() {
6807
6846
  builtin exit "$@"
6808
6847
  fi
6809
6848
  # Run preclose - exit code 1 means dirty, block exit
6810
- command ${cmd2} __preclose $wksh_force
6849
+ command ${cmd2} __preclose $wk_force
6811
6850
  if [[ $? -eq 1 ]]; then
6812
6851
  return
6813
6852
  fi
6814
6853
  builtin exit "$@"
6815
6854
  }
6816
6855
 
6817
- __wksh_wrapper() {
6856
+ __wk_wrapper() {
6818
6857
  case "$1" in
6819
6858
  close) shift; exit "$@" ;;
6820
6859
  *) command ${cmd2} "$@" ;;
6821
6860
  esac
6822
6861
  }
6823
- alias wksh='__wksh_wrapper'
6824
- ${cmd2.endsWith("-dev") ? `alias wksh-dev='__wksh_wrapper'` : ""}
6862
+ alias wk='__wk_wrapper'
6863
+ ${cmd2.endsWith("-dev") ? `alias wk-dev='__wk_wrapper'` : ""}
6825
6864
  `;
6826
6865
  const zshScript = `
6827
6866
  exit() {
6828
6867
  if [[ \${ZSH_SUBSHELL:-0} -gt 0 ]]; then
6829
6868
  builtin exit "$@"
6830
6869
  fi
6831
- local wksh_force=""
6870
+ local wk_force=""
6832
6871
  if [[ "\${1:-}" == "-f" || "\${1:-}" == "--force" ]]; then
6833
- wksh_force="\${1:-}"
6872
+ wk_force="\${1:-}"
6834
6873
  shift
6835
6874
  fi
6836
6875
  # Fail open if ${cmd2} not in PATH
@@ -6838,21 +6877,21 @@ exit() {
6838
6877
  builtin exit "$@"
6839
6878
  fi
6840
6879
  # Run preclose - exit code 1 means dirty, block exit
6841
- command ${cmd2} __preclose $wksh_force
6880
+ command ${cmd2} __preclose $wk_force
6842
6881
  if [[ $? -eq 1 ]]; then
6843
6882
  return
6844
6883
  fi
6845
6884
  builtin exit "$@"
6846
6885
  }
6847
6886
 
6848
- __wksh_wrapper() {
6887
+ __wk_wrapper() {
6849
6888
  case "$1" in
6850
6889
  close) shift; exit "$@" ;;
6851
6890
  *) command ${cmd2} "$@" ;;
6852
6891
  esac
6853
6892
  }
6854
- alias wksh='__wksh_wrapper'
6855
- ${cmd2.endsWith("-dev") ? `alias wksh-dev='__wksh_wrapper'` : ""}
6893
+ alias wk='__wk_wrapper'
6894
+ ${cmd2.endsWith("-dev") ? `alias wk-dev='__wk_wrapper'` : ""}
6856
6895
  `;
6857
6896
  const fishScript = `
6858
6897
  function exit --wraps=exit
@@ -6860,11 +6899,11 @@ function exit --wraps=exit
6860
6899
  if not status is-interactive
6861
6900
  builtin exit $argv
6862
6901
  end
6863
- set wksh_force
6902
+ set wk_force
6864
6903
  set args $argv
6865
6904
  if test (count $args) -gt 0
6866
6905
  if test "$args[1]" = "-f"; or test "$args[1]" = "--force"
6867
- set wksh_force $args[1]
6906
+ set wk_force $args[1]
6868
6907
  set -e args[1]
6869
6908
  end
6870
6909
  end
@@ -6873,14 +6912,14 @@ function exit --wraps=exit
6873
6912
  builtin exit $args
6874
6913
  end
6875
6914
  # Run preclose - exit code 1 means dirty, block exit
6876
- command ${cmd2} __preclose $wksh_force
6915
+ command ${cmd2} __preclose $wk_force
6877
6916
  if test $status -eq 1
6878
6917
  return
6879
6918
  end
6880
6919
  builtin exit $args
6881
6920
  end
6882
6921
 
6883
- function __wksh_wrapper
6922
+ function __wk_wrapper
6884
6923
  if test "$argv[1]" = "close"
6885
6924
  set args $argv
6886
6925
  set -e args[1]
@@ -6890,21 +6929,21 @@ function __wksh_wrapper
6890
6929
  end
6891
6930
  end
6892
6931
 
6893
- function wksh --wraps=${cmd2}
6894
- __wksh_wrapper $argv
6932
+ function wk --wraps=${cmd2}
6933
+ __wk_wrapper $argv
6895
6934
  end
6896
6935
  ${cmd2.endsWith("-dev") ? `
6897
- function wksh-dev --wraps=${cmd2}
6898
- __wksh_wrapper $argv
6936
+ function wk-dev --wraps=${cmd2}
6937
+ __wk_wrapper $argv
6899
6938
  end
6900
6939
  ` : ""}
6901
6940
  `;
6902
6941
  const setupSection = setupCommand ? `
6903
- # wksh setup script
6942
+ # wk setup script
6904
6943
  ${setupCommand}
6905
6944
  ` : "";
6906
6945
  if (shell.endsWith("zsh")) {
6907
- const tmpDir = join2(tmpdir(), `wksh-${process.pid}`);
6946
+ const tmpDir = join2(tmpdir(), `wk-${process.pid}`);
6908
6947
  mkdirSync2(tmpDir, { recursive: true });
6909
6948
  try {
6910
6949
  writeFileSync2(join2(tmpDir, ".zshrc"), `[[ -f "$HOME/.zshrc" ]] && source "$HOME/.zshrc"
@@ -6914,7 +6953,7 @@ ${zshScript}${setupSection}`);
6914
6953
  rmSync(tmpDir, { recursive: true, force: true });
6915
6954
  }
6916
6955
  } else if (shell.endsWith("bash")) {
6917
- const tmpDir = join2(tmpdir(), `wksh-${process.pid}`);
6956
+ const tmpDir = join2(tmpdir(), `wk-${process.pid}`);
6918
6957
  mkdirSync2(tmpDir, { recursive: true });
6919
6958
  try {
6920
6959
  const rcFile = join2(tmpDir, ".bashrc");
@@ -6926,12 +6965,12 @@ ${bashScript}${setupSection}`);
6926
6965
  }
6927
6966
  } else if (shell.endsWith("fish")) {
6928
6967
  const fishInit = setupCommand ? `${fishScript}
6929
- # wksh setup script
6968
+ # wk setup script
6930
6969
  ${setupCommand}` : fishScript;
6931
6970
  spawnSync(shell, ["--init-command", fishInit], { cwd, stdio: "inherit" });
6932
6971
  } else {
6933
6972
  console.error(`Error: Unsupported shell '${shell}'`);
6934
- console.error("wksh requires bash, zsh, or fish.");
6973
+ console.error("wk requires bash, zsh, or fish.");
6935
6974
  process.exit(1);
6936
6975
  }
6937
6976
  }
@@ -6949,7 +6988,7 @@ function autoCleanupWorktree(worktreeId, path, store, saveStore2) {
6949
6988
  const status = getWorktreeStatus(path);
6950
6989
  if (status !== "clean") {
6951
6990
  console.log(" " + warn(`Branch '${branch}' has uncommitted changes. Worktree kept.`));
6952
- console.log(dim(` To reopen: `) + cyan(`wksh open ${branch}`));
6991
+ console.log(dim(` To reopen: `) + cyan(`wk open ${branch}`));
6953
6992
  return;
6954
6993
  }
6955
6994
  const currentBranch = getCurrentBranch();
@@ -6970,7 +7009,7 @@ function autoCleanupWorktree(worktreeId, path, store, saveStore2) {
6970
7009
  console.log(` Changes have been pushed to a remote.`);
6971
7010
  console.log(` Pruned worktree. Your changes are still in the '${cyan(branch)}' branch.`);
6972
7011
  console.log(` To check it out again later:`);
6973
- console.log(dim(` `) + cyan(`wksh open ${branch}`));
7012
+ console.log(dim(` `) + cyan(`wk open ${branch}`));
6974
7013
  return;
6975
7014
  }
6976
7015
  console.log(` Pruned worktree. Your changes are still in the '${cyan(branch)}' branch.`);
@@ -7020,12 +7059,12 @@ function newCommand(branchName, fromBranch) {
7020
7059
  const existingWorktree = getWorktreeForBranch(branch);
7021
7060
  if (existingWorktree) {
7022
7061
  console.error(`Error: branch '${branch}' already has an active worktree`);
7023
- console.error(dim(` Try: `) + cyan(`wksh open ${branch}`));
7062
+ console.error(dim(` Try: `) + cyan(`wk open ${branch}`));
7024
7063
  process.exit(1);
7025
7064
  }
7026
7065
  if (branchExists(branch)) {
7027
7066
  console.error(`Error: branch '${branch}' already exists`);
7028
- console.error(dim(` Try: `) + cyan(`wksh open ${branch}`));
7067
+ console.error(dim(` Try: `) + cyan(`wk open ${branch}`));
7029
7068
  process.exit(1);
7030
7069
  }
7031
7070
  const store = loadStore();
@@ -7043,8 +7082,8 @@ function newCommand(branchName, fromBranch) {
7043
7082
  const parentBranch = getCurrentBranch();
7044
7083
  console.log();
7045
7084
  console.log(success(bold(branch)), dim(`(from ${cyan(baseBranch)})`));
7046
- console.log(dim(`Opened branch in ephemeral subshell at ${relative(mainWorktree, worktreePath)}`));
7047
- console.log(dim("Type 'wksh close' to return."));
7085
+ console.log(dim(`Opened branch in ephemeral subshell`));
7086
+ console.log(dim("Type 'wk close' to return."));
7048
7087
  console.log();
7049
7088
  spawnShell(worktreePath, {
7050
7089
  branch,
@@ -7060,7 +7099,7 @@ function newCommand(branchName, fromBranch) {
7060
7099
 
7061
7100
  // commands/open.ts
7062
7101
  import { mkdirSync as mkdirSync4 } from "fs";
7063
- import { basename as basename4, dirname as dirname4, join as join4, relative as relative2 } from "path";
7102
+ import { basename as basename4, dirname as dirname4, join as join4 } from "path";
7064
7103
  function openCommand(branch) {
7065
7104
  if (isInsideWorktree()) {
7066
7105
  const currentBranch = getCurrentBranch();
@@ -7084,7 +7123,7 @@ function openCommand(branch) {
7084
7123
  const mainWorktree2 = getMainWorktree();
7085
7124
  console.log();
7086
7125
  console.log(success(bold(branch)), dim(`(existing worktree)`));
7087
- console.log(dim("Type 'wksh close' to return."));
7126
+ console.log(dim("Type 'wk close' to return."));
7088
7127
  console.log();
7089
7128
  spawnShell(existingWorktreePath, {
7090
7129
  branch,
@@ -7112,8 +7151,8 @@ function openCommand(branch) {
7112
7151
  saveStore(store);
7113
7152
  console.log();
7114
7153
  console.log(success(bold(branch)));
7115
- console.log(dim(`Opened branch in ephemeral subshell at ${relative2(mainWorktree, worktreePath)}`));
7116
- console.log(dim("Type 'exit' or 'wksh close' to return."));
7154
+ console.log(dim(`Opened branch in ephemeral subshell`));
7155
+ console.log(dim("Type 'exit' or 'wk close' to return."));
7117
7156
  console.log();
7118
7157
  spawnShell(worktreePath, {
7119
7158
  branch,
@@ -7995,14 +8034,14 @@ function rmCommand(branch, force = false) {
7995
8034
  const absCwd = resolve2(cwd);
7996
8035
  if (absCwd === absWtPath || absCwd.startsWith(absWtPath + "/")) {
7997
8036
  console.error("Error: cannot remove current worktree");
7998
- console.error(dim(` Try: `) + cyan(`wksh close`));
8037
+ console.error(dim(` Try: `) + cyan(`wk close`));
7999
8038
  process.exit(1);
8000
8039
  }
8001
8040
  const status = getWorktreeStatus(worktreePath);
8002
8041
  const isDirty = status !== "clean" && status !== "";
8003
8042
  if (isDirty && !force) {
8004
8043
  console.error(warn("Uncommitted changes found. Commit, stash, or reset your changes first."));
8005
- console.error(dim(` Or run: `) + cyan(`wksh rm ${branch} -f`));
8044
+ console.error(dim(` Or run: `) + cyan(`wk rm ${branch} -f`));
8006
8045
  process.exit(1);
8007
8046
  }
8008
8047
  if (isDirty && force) {
@@ -8117,7 +8156,7 @@ function precloseCommand(force) {
8117
8156
  }
8118
8157
  console.error(warn("Uncommitted changes found. Commit, stash, or reset your changes first."));
8119
8158
  console.error(dim(" Or use --force/-f to discard changes"));
8120
- console.error(" " + cyan("wksh close -f"));
8159
+ console.error(" " + cyan("wk close -f"));
8121
8160
  process.exit(1);
8122
8161
  }
8123
8162
 
@@ -8183,14 +8222,14 @@ function promptChoice() {
8183
8222
  }
8184
8223
 
8185
8224
  // index.ts
8186
- var VERSION = "0.0.5";
8225
+ var VERSION = "0.0.7";
8187
8226
  function printHelp() {
8188
8227
  const dim2 = import_picocolors4.default.dim;
8189
8228
  const cyan2 = import_picocolors4.default.cyan;
8190
8229
  const green2 = import_picocolors4.default.green;
8191
- console.log(`${import_picocolors4.default.bold("wksh")} ${dim2(`v${VERSION}`)} - Open branches in ephemeral subshells
8230
+ console.log(`${import_picocolors4.default.bold("wk")} ${dim2(`v${VERSION}`)} - Open branches in ephemeral subshells
8192
8231
 
8193
- ${import_picocolors4.default.bold("Usage:")} ${cyan2("wksh")} ${dim2("<command>")} ${dim2("[options]")}
8232
+ ${import_picocolors4.default.bold("Usage:")} ${cyan2("wk")} ${dim2("<command>")} ${dim2("[options]")}
8194
8233
 
8195
8234
  ${import_picocolors4.default.bold("Commands:")}
8196
8235
  ${green2("new")} ${dim2("[branch]")} Create a branch and open it ${dim2("[--from <branch>]")}
@@ -8207,15 +8246,15 @@ ${import_picocolors4.default.bold("Options:")}
8207
8246
 
8208
8247
  ${dim2("\u2500".repeat(60))}
8209
8248
 
8210
- ${import_picocolors4.default.bold("Why wksh?")}
8249
+ ${import_picocolors4.default.bold("Why wk?")}
8211
8250
 
8212
8251
  In agentic development, you often want to spin up isolated workspaces for
8213
- specific tasks\u2014without stashing or committing your current changes. wksh makes
8252
+ specific tasks\u2014without stashing or committing your current changes. wk makes
8214
8253
  this effortless.
8215
8254
 
8216
8255
  Open a new branch in an ephemeral subshell:
8217
8256
 
8218
- ${dim2("$")} ${cyan2("wksh new add-login-button")}
8257
+ ${dim2("$")} ${cyan2("wk new add-login-button")}
8219
8258
 
8220
8259
  This creates a branch and worktree, then drops you into a subshell. Open it
8221
8260
  in your editor or point an AI coding agent at it. Your changes are completely
@@ -8229,24 +8268,24 @@ Or merge directly back into main:
8229
8268
 
8230
8269
  ${dim2("$")} ${cyan2("git checkout main && git merge add-login-button")}
8231
8270
 
8232
- Then just ${cyan2("wksh close")} to return to your main repo. The worktree is ephemeral\u2014
8271
+ Then just ${cyan2("wk close")} to return to your main repo. The worktree is ephemeral\u2014
8233
8272
  it gets cleaned up automatically.
8234
8273
 
8235
- Use ${cyan2("wksh ls")} to see branches with open worktrees, and ${cyan2("wksh open <branch>")} to
8274
+ Use ${cyan2("wk ls")} to see branches with open worktrees, and ${cyan2("wk open <branch>")} to
8236
8275
  reopen one later.`);
8237
8276
  }
8238
8277
  function printVersion() {
8239
- console.log(`wksh v${VERSION}`);
8278
+ console.log(`wk v${VERSION}`);
8240
8279
  }
8241
8280
  function printNewHelp() {
8242
8281
  const dim2 = import_picocolors4.default.dim;
8243
8282
  const cyan2 = import_picocolors4.default.cyan;
8244
- console.log(`${import_picocolors4.default.bold("wksh new")} - Create a branch and open it in an ephemeral subshell
8283
+ console.log(`${import_picocolors4.default.bold("wk new")} - Create a branch and open it in an ephemeral subshell
8245
8284
 
8246
- ${import_picocolors4.default.bold("Usage:")} ${cyan2("wksh new")} ${dim2("[branch]")} ${dim2("[--from <branch>]")}
8285
+ ${import_picocolors4.default.bold("Usage:")} ${cyan2("wk new")} ${dim2("[branch]")} ${dim2("[--from <branch>]")}
8247
8286
 
8248
8287
  ${import_picocolors4.default.bold("Arguments:")}
8249
- ${dim2("[branch]")} Branch name ${dim2('(default: "wksh-[hash]")')}
8288
+ ${dim2("[branch]")} Branch name ${dim2('(default: "wk-[hash]")')}
8250
8289
 
8251
8290
  ${import_picocolors4.default.bold("Options:")}
8252
8291
  ${cyan2("--from")} ${dim2("<branch>")} Base branch to fork from ${dim2("(default: current branch)")}
@@ -8254,14 +8293,14 @@ ${import_picocolors4.default.bold("Options:")}
8254
8293
  ${import_picocolors4.default.bold("Description:")}
8255
8294
  Creates a new Git branch (forked from current or specified branch) and opens
8256
8295
  it in an ephemeral subshell with its own worktree.
8257
- Type 'wksh close' to return.`);
8296
+ Type 'wk close' to return.`);
8258
8297
  }
8259
8298
  function printOpenHelp() {
8260
8299
  const dim2 = import_picocolors4.default.dim;
8261
8300
  const cyan2 = import_picocolors4.default.cyan;
8262
- console.log(`${import_picocolors4.default.bold("wksh open")} - Open a branch in an ephemeral subshell
8301
+ console.log(`${import_picocolors4.default.bold("wk open")} - Open a branch in an ephemeral subshell
8263
8302
 
8264
- ${import_picocolors4.default.bold("Usage:")} ${cyan2("wksh open")} ${dim2("<branch>")}
8303
+ ${import_picocolors4.default.bold("Usage:")} ${cyan2("wk open")} ${dim2("<branch>")}
8265
8304
 
8266
8305
  ${import_picocolors4.default.bold("Arguments:")}
8267
8306
  ${dim2("<branch>")} Branch name ${dim2("(required)")}
@@ -8270,14 +8309,14 @@ ${import_picocolors4.default.bold("Description:")}
8270
8309
  Opens the specified branch in an ephemeral subshell.
8271
8310
  If a worktree already exists for the branch, uses that.
8272
8311
  Otherwise, creates a new worktree automatically.
8273
- Type 'wksh close' to return.`);
8312
+ Type 'wk close' to return.`);
8274
8313
  }
8275
8314
  function printLsHelp() {
8276
8315
  const dim2 = import_picocolors4.default.dim;
8277
8316
  const cyan2 = import_picocolors4.default.cyan;
8278
- console.log(`${import_picocolors4.default.bold("wksh ls")} - List branches with open worktrees
8317
+ console.log(`${import_picocolors4.default.bold("wk ls")} - List branches with open worktrees
8279
8318
 
8280
- ${import_picocolors4.default.bold("Usage:")} ${cyan2("wksh ls")} ${dim2("[options]")}
8319
+ ${import_picocolors4.default.bold("Usage:")} ${cyan2("wk ls")} ${dim2("[options]")}
8281
8320
 
8282
8321
  ${import_picocolors4.default.bold("Options:")}
8283
8322
  ${cyan2("--plain")} Output in plain tab-separated format
@@ -8290,9 +8329,9 @@ ${import_picocolors4.default.bold("Description:")}
8290
8329
  function printRmHelp() {
8291
8330
  const dim2 = import_picocolors4.default.dim;
8292
8331
  const cyan2 = import_picocolors4.default.cyan;
8293
- console.log(`${import_picocolors4.default.bold("wksh rm")} - Remove a branch's worktree
8332
+ console.log(`${import_picocolors4.default.bold("wk rm")} - Remove a branch's worktree
8294
8333
 
8295
- ${import_picocolors4.default.bold("Usage:")} ${cyan2("wksh rm")} ${dim2("<branch>")} ${dim2("[options]")}
8334
+ ${import_picocolors4.default.bold("Usage:")} ${cyan2("wk rm")} ${dim2("<branch>")} ${dim2("[options]")}
8296
8335
 
8297
8336
  ${import_picocolors4.default.bold("Arguments:")}
8298
8337
  ${dim2("<branch>")} Branch whose worktree to remove ${dim2("(required)")}
@@ -8307,9 +8346,9 @@ ${import_picocolors4.default.bold("Description:")}
8307
8346
  }
8308
8347
  function printStatusHelp() {
8309
8348
  const cyan2 = import_picocolors4.default.cyan;
8310
- console.log(`${import_picocolors4.default.bold("wksh status")} - Show current branch status
8349
+ console.log(`${import_picocolors4.default.bold("wk status")} - Show current branch status
8311
8350
 
8312
- ${import_picocolors4.default.bold("Usage:")} ${cyan2("wksh status")}
8351
+ ${import_picocolors4.default.bold("Usage:")} ${cyan2("wk status")}
8313
8352
 
8314
8353
  ${import_picocolors4.default.bold("Description:")}
8315
8354
  Shows the current branch, worktree path, and git status.`);
@@ -8317,9 +8356,9 @@ ${import_picocolors4.default.bold("Description:")}
8317
8356
  function printCloseHelp() {
8318
8357
  const dim2 = import_picocolors4.default.dim;
8319
8358
  const cyan2 = import_picocolors4.default.cyan;
8320
- console.log(`${import_picocolors4.default.bold("wksh close")} - Exit current subshell
8359
+ console.log(`${import_picocolors4.default.bold("wk close")} - Exit current subshell
8321
8360
 
8322
- ${import_picocolors4.default.bold("Usage:")} ${cyan2("wksh close")} ${dim2("[options]")}
8361
+ ${import_picocolors4.default.bold("Usage:")} ${cyan2("wk close")} ${dim2("[options]")}
8323
8362
 
8324
8363
  ${import_picocolors4.default.bold("Options:")}
8325
8364
  ${cyan2("-f")}, ${cyan2("--force")} Discard uncommitted changes and exit
@@ -8338,9 +8377,9 @@ ${import_picocolors4.default.bold("Description:")}
8338
8377
  function printConfigHelp() {
8339
8378
  const dim2 = import_picocolors4.default.dim;
8340
8379
  const cyan2 = import_picocolors4.default.cyan;
8341
- console.log(`${import_picocolors4.default.bold("wksh config")} - Show or create config file
8380
+ console.log(`${import_picocolors4.default.bold("wk config")} - Show or create config file
8342
8381
 
8343
- ${import_picocolors4.default.bold("Usage:")} ${cyan2("wksh config")}
8382
+ ${import_picocolors4.default.bold("Usage:")} ${cyan2("wk config")}
8344
8383
 
8345
8384
  ${import_picocolors4.default.bold("Description:")}
8346
8385
  Shows the path and contents of your workshell config file.
@@ -8391,7 +8430,7 @@ switch (cmd) {
8391
8430
  process.exit(0);
8392
8431
  }
8393
8432
  if (!args[1]) {
8394
- console.error("Usage: wksh open <branch>");
8433
+ console.error("Usage: wk open <branch>");
8395
8434
  process.exit(1);
8396
8435
  }
8397
8436
  openCommand(args[1]);
@@ -8416,7 +8455,7 @@ switch (cmd) {
8416
8455
  process.exit(0);
8417
8456
  }
8418
8457
  if (!args[1]) {
8419
- console.error("Usage: wksh rm <branch>");
8458
+ console.error("Usage: wk rm <branch>");
8420
8459
  process.exit(1);
8421
8460
  }
8422
8461
  rmCommand(args[1], args.includes("-f") || args.includes("--force"));
@@ -8433,7 +8472,7 @@ switch (cmd) {
8433
8472
  printCloseHelp();
8434
8473
  process.exit(0);
8435
8474
  }
8436
- console.error(fail("'wksh close' only works inside a wksh subshell."));
8475
+ console.error(fail("'wk close' only works inside a wk subshell."));
8437
8476
  process.exit(1);
8438
8477
  break;
8439
8478
  case "__preclose":
@@ -8441,7 +8480,7 @@ switch (cmd) {
8441
8480
  break;
8442
8481
  default:
8443
8482
  console.error(`Unknown command: ${cmd}`);
8444
- console.error("Run 'wksh --help' for usage.");
8483
+ console.error("Run 'wk --help' for usage.");
8445
8484
  process.exit(1);
8446
8485
  }
8447
8486
  /*! Bundled license information:
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "workshell",
3
- "version": "0.0.5",
3
+ "version": "0.0.7",
4
4
  "description": "Agent- and human-friendly Git multitasking, powered by worktrees",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -22,7 +22,7 @@
22
22
  "isolation"
23
23
  ],
24
24
  "bin": {
25
- "wksh": "dist/index.js",
25
+ "wk": "dist/index.js",
26
26
  "workshell": "dist/index.js",
27
27
  "git-workshell": "dist/index.js"
28
28
  },
@@ -32,7 +32,7 @@
32
32
  "sideEffects": false,
33
33
  "scripts": {
34
34
  "build": "tsc && node build.ts",
35
- "postbuild": "ln -sf $(pwd)/dist/index.js /usr/local/bin/wksh-dev",
35
+ "postbuild": "ln -sf $(pwd)/dist/index.js /usr/local/bin/wk-dev",
36
36
  "dev": "node build.ts --watch",
37
37
  "prepare": "husky && node build.ts",
38
38
  "typecheck": "tsc",