@cestoliv/wt 0.3.0-pr14.g2b25fef → 0.4.0-pr16.gca5d1db

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 CHANGED
@@ -123,6 +123,7 @@ Edit with `wt config` (`wt config --path` prints the file location —
123
123
  | `base_branch` | `"origin/main"` | Branch new worktrees are created from |
124
124
  | `worktree_path` | `"../"` | Where worktrees are placed (relative to repo) |
125
125
  | `setup_commands` | `[]` | Commands to run in new worktrees |
126
+ | `teardown_commands` | `[]` | Commands to run in a worktree just before it is deleted (e.g. `["docker compose down -v"]`) |
126
127
  | `agent_command` | `"claude --permission-mode plan"` | Base command; `--permission-mode` replaced by `--mode` option, then prompt appended |
127
128
  | `agent_trigger_chord` | `"ctrl-shift-cmd-c"` | Zed keymap chord `wt agent` installs and presses |
128
129
  | `repo_overrides` | `{}` | Per-repo overrides for any key above |
package/SKILL.md CHANGED
@@ -67,6 +67,13 @@ for you to grant it and confirm, then retries automatically. On other platforms
67
67
  (or when `ide` is not `zed`) the worktree is still created and opened, but the
68
68
  agent is not auto-started.
69
69
 
70
+ Over SSH it still works, provided the same user has an active graphical login on
71
+ the Mac: the keystroke is run inside the GUI session via Launch Services
72
+ (`open -a Terminal` briefly flashes a Terminal window). Grant Accessibility to
73
+ Terminal (not Zed) the first time. With no one logged in graphically there is
74
+ nothing to drive, so it falls back to the manual "press the chord in Zed"
75
+ message.
76
+
70
77
  If the worktree path already exists, `wt agent` prompts you to **open it in the
71
78
  IDE**, **open it and start the agent**, or **quit** — instead of erroring. (In a
72
79
  non-interactive shell it errors with a non-zero exit instead of prompting.)
@@ -95,6 +102,7 @@ Config is stored as JSON. Get the path with `wt config --path`.
95
102
  | `worktree_path` | `string` | `"../"` | Where to place new worktrees, relative to the repo root |
96
103
  | `base_branch` | `string` | `"origin/main"` | Branch to base new worktrees on |
97
104
  | `setup_commands` | `string[]` | `[]` | Commands to run in a new worktree after creation (e.g. `["npm install"]`) |
105
+ | `teardown_commands` | `string[]` | `[]` | Commands to run in a worktree just before it is deleted (e.g. `["docker compose down -v"]`); on failure you are prompted whether to delete anyway |
98
106
  | `ide` | `string` | `"zed"` | IDE command to open worktrees with |
99
107
  | `ide_open_args` | `string[]` | `["-n"]` | Arguments passed to the IDE command |
100
108
  | `agent_command` | `string` | `"claude --permission-mode plan"` | Base command `wt agent` runs in Zed; any `--permission-mode` flag is replaced by the `--mode` option (defaults to `plan`), then `<plan_prompt>` is appended single-quoted |
@@ -104,7 +112,7 @@ Config is stored as JSON. Get the path with `wt config --path`.
104
112
 
105
113
  ### Per-repo overrides
106
114
 
107
- Override any field (`worktree_path`, `base_branch`, `setup_commands`, `ide`, `ide_open_args`, `agent_command`, `agent_trigger_chord`) for a specific repo:
115
+ Override any field (`worktree_path`, `base_branch`, `setup_commands`, `teardown_commands`, `ide`, `ide_open_args`, `agent_command`, `agent_trigger_chord`) for a specific repo:
108
116
 
109
117
  ```json
110
118
  {
@@ -3,9 +3,9 @@ import {
3
3
  openConfiguredIde,
4
4
  prepareWorktree,
5
5
  promptExistingWorktree
6
- } from "./chunk-HWLB5I4T.js";
7
- import "./chunk-HQANH3IS.js";
8
- import "./chunk-F4DNLDG7.js";
6
+ } from "./chunk-ASVHQXDJ.js";
7
+ import "./chunk-E2IOE23G.js";
8
+ import "./chunk-FNAMNRUH.js";
9
9
 
10
10
  // src/commands/agent.ts
11
11
  import * as clack from "@clack/prompts";
@@ -14,14 +14,16 @@ import pc from "picocolors";
14
14
  // src/lib/zed.ts
15
15
  import { spawn } from "child_process";
16
16
  import {
17
+ chmodSync,
17
18
  existsSync,
18
19
  mkdirSync,
20
+ mkdtempSync,
19
21
  readdirSync,
20
22
  readFileSync,
21
23
  rmSync,
22
24
  writeFileSync
23
25
  } from "fs";
24
- import { homedir } from "os";
26
+ import { homedir, tmpdir } from "os";
25
27
  import { dirname, join } from "path";
26
28
  import { applyEdits, modify, parse } from "jsonc-parser";
27
29
  var AGENT_TASK_LABEL = "wt: agent";
@@ -278,19 +280,109 @@ Note: "${chord}" is already bound in ${keymapPath}; wt's agent binding will take
278
280
  return true;
279
281
  }
280
282
  var ACCESSIBILITY_SETTINGS_URL = "x-apple.systempreferences:com.apple.preference.security?Privacy_Accessibility";
281
- function defaultRunner(script) {
283
+ function isHeadlessSession(env = process.env) {
284
+ return Boolean(env.SSH_CONNECTION || env.SSH_TTY || env.SSH_CLIENT);
285
+ }
286
+ function buildGuiHelperScript(scriptPath, resultPath) {
287
+ const q = (s) => `'${s.replace(/'/g, "'\\''")}'`;
288
+ return [
289
+ "#!/bin/sh",
290
+ `out=$(osascript ${q(scriptPath)} 2>&1)`,
291
+ "code=$?",
292
+ `printf '%s\\n%s' "$code" "$out" > ${q(`${resultPath}.tmp`)} && mv ${q(`${resultPath}.tmp`)} ${q(resultPath)}`,
293
+ `osascript -e 'tell application "Terminal" to close front window' >/dev/null 2>&1 &`,
294
+ ""
295
+ ].join("\n");
296
+ }
297
+ function parseGuiResult(content) {
298
+ const newline = content.indexOf("\n");
299
+ const codeStr = (newline === -1 ? content : content.slice(0, newline)).trim();
300
+ const stderr = newline === -1 ? "" : content.slice(newline + 1);
301
+ const code = Number.parseInt(codeStr, 10);
302
+ if (Number.isNaN(code)) {
303
+ return {
304
+ code: null,
305
+ stderr: stderr || `unexpected result format (first line: ${JSON.stringify(codeStr)})`
306
+ };
307
+ }
308
+ return { code, stderr };
309
+ }
310
+ var OSASCRIPT_TIMEOUT_MS = 3e4;
311
+ var sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
312
+ function spawnOpen(helperPath) {
313
+ return new Promise((resolve, reject) => {
314
+ const child = spawn("open", ["-a", "Terminal", helperPath], {
315
+ stdio: "ignore"
316
+ });
317
+ child.on("error", reject);
318
+ child.on("close", () => resolve());
319
+ });
320
+ }
321
+ async function pollFile(path, timeoutMs) {
322
+ const deadline = Date.now() + timeoutMs;
323
+ while (Date.now() < deadline) {
324
+ if (existsSync(path)) return readFileSync(path, "utf8");
325
+ await sleep(200);
326
+ }
327
+ return null;
328
+ }
329
+ async function runViaGuiHelper(script) {
330
+ const dir = mkdtempSync(join(tmpdir(), "wt-agent-"));
331
+ const scriptPath = join(dir, "chord.applescript");
332
+ const helperPath = join(dir, "run.command");
333
+ const resultPath = join(dir, "result");
334
+ try {
335
+ writeFileSync(scriptPath, script);
336
+ writeFileSync(helperPath, buildGuiHelperScript(scriptPath, resultPath));
337
+ chmodSync(helperPath, 493);
338
+ await spawnOpen(helperPath);
339
+ const content = await pollFile(resultPath, OSASCRIPT_TIMEOUT_MS);
340
+ if (content === null) {
341
+ return {
342
+ code: null,
343
+ stderr: "Timed out waiting for the keystroke \u2014 is a user logged into the Mac's graphical session?"
344
+ };
345
+ }
346
+ return parseGuiResult(content);
347
+ } catch (err) {
348
+ return {
349
+ code: null,
350
+ stderr: err instanceof Error ? err.message : String(err)
351
+ };
352
+ } finally {
353
+ rmSync(dir, { recursive: true, force: true });
354
+ }
355
+ }
356
+ function runOsascriptDirect(script) {
282
357
  return new Promise((resolve) => {
283
358
  const child = spawn("osascript", ["-e", script], {
284
359
  stdio: ["ignore", "ignore", "pipe"]
285
360
  });
286
361
  let stderr = "";
362
+ let settled = false;
363
+ const finish = (result) => {
364
+ if (settled) return;
365
+ settled = true;
366
+ clearTimeout(timer);
367
+ resolve(result);
368
+ };
369
+ const timer = setTimeout(() => {
370
+ child.kill();
371
+ finish({
372
+ code: null,
373
+ stderr: "osascript timed out \u2014 is a user logged into the Mac's graphical session?"
374
+ });
375
+ }, OSASCRIPT_TIMEOUT_MS);
287
376
  child.stderr?.on("data", (d) => {
288
377
  stderr += d.toString();
289
378
  });
290
- child.on("error", (err) => resolve({ code: null, stderr: err.message }));
291
- child.on("close", (code) => resolve({ code, stderr }));
379
+ child.on("error", (err) => finish({ code: null, stderr: err.message }));
380
+ child.on("close", (code) => finish({ code, stderr }));
292
381
  });
293
382
  }
383
+ function defaultRunner(script) {
384
+ return isHeadlessSession() ? runViaGuiHelper(script) : runOsascriptDirect(script);
385
+ }
294
386
  function isAccessibilityError(stderr) {
295
387
  return /\b1002\b/.test(stderr) || /-1719\b/.test(stderr) || /not allowed to send keystrokes/i.test(stderr) || /not allowed assistive access/i.test(stderr);
296
388
  }
@@ -404,8 +496,9 @@ async function startAgentInWorktree(config, worktreePath, planPrompt, mode) {
404
496
  )
405
497
  );
406
498
  openAccessibilitySettings();
499
+ const grantee = isHeadlessSession() ? "Terminal" : "the app running wt (e.g. Zed)";
407
500
  const proceed = await clack.confirm({
408
- message: "Grant Accessibility to the app running wt (e.g. Zed) in the panel that opened, then confirm to retry. (If that app was already running, you may need to quit and reopen it for the grant to take effect.)"
501
+ message: `Grant Accessibility to ${grantee} in the panel that opened, then confirm to retry. (If that app was already running, you may need to quit and reopen it for the grant to take effect.)`
409
502
  });
410
503
  if (clack.isCancel(proceed) || !proceed) break;
411
504
  result = await triggerChord(config.agent_trigger_chord, {
@@ -440,7 +533,7 @@ function reportTriggerFailure(result, chord) {
440
533
  }
441
534
  console.warn(
442
535
  pc.yellow(
443
- `\u26A0 Could not auto-start the agent${result.message ? `: ${result.message}` : ""}. In Zed, press ${chord} to start it manually.`
536
+ `\u26A0 Could not auto-start the agent${result.message ? `: ${result.message}` : ""}. In Zed, press ${chord} to start it manually. (Over SSH, this needs the same user logged into the Mac's graphical session.)`
444
537
  )
445
538
  );
446
539
  }
@@ -10,47 +10,19 @@ import {
10
10
  registerRepo,
11
11
  resolveWorktreePath,
12
12
  runBranchInput,
13
+ runCommands,
13
14
  runRepoPicker,
14
15
  setUpstreamTracking
15
- } from "./chunk-HQANH3IS.js";
16
+ } from "./chunk-E2IOE23G.js";
16
17
  import {
17
18
  createStore,
18
19
  getEffectiveConfig
19
- } from "./chunk-F4DNLDG7.js";
20
+ } from "./chunk-FNAMNRUH.js";
20
21
 
21
22
  // src/commands/create.ts
22
23
  import { existsSync } from "fs";
23
24
  import * as clack from "@clack/prompts";
24
25
  import pc from "picocolors";
25
-
26
- // src/lib/setup.ts
27
- import { spawn } from "child_process";
28
- async function runSetupCommands(commands, cwd) {
29
- for (const command of commands) {
30
- const result = await runCommand(command, cwd);
31
- if (!result.success) {
32
- return {
33
- success: false,
34
- failedCommand: command,
35
- exitCode: result.exitCode
36
- };
37
- }
38
- }
39
- return { success: true };
40
- }
41
- function runCommand(command, cwd) {
42
- return new Promise((resolve) => {
43
- const child = spawn(command, { cwd, stdio: "inherit", shell: true });
44
- child.on("error", () => {
45
- resolve({ success: false, exitCode: void 0 });
46
- });
47
- child.on("close", (code) => {
48
- resolve({ success: code === 0, exitCode: code ?? void 0 });
49
- });
50
- });
51
- }
52
-
53
- // src/commands/create.ts
54
26
  async function prepareWorktree(branch, options = {}) {
55
27
  const {
56
28
  cwd = process.cwd(),
@@ -141,7 +113,7 @@ async function prepareWorktree(branch, options = {}) {
141
113
  console.log(pc.green(`\u2713 Created worktree at ${worktreePath}`));
142
114
  if (config.setup_commands.length > 0) {
143
115
  console.log(pc.dim("Running setup commands..."));
144
- const result = await runSetupCommands(config.setup_commands, worktreePath);
116
+ const result = await runCommands(config.setup_commands, worktreePath);
145
117
  if (!result.success) {
146
118
  console.error(
147
119
  pc.red(
@@ -2,7 +2,7 @@
2
2
  import {
3
3
  createStore,
4
4
  getGlobalConfig
5
- } from "./chunk-F4DNLDG7.js";
5
+ } from "./chunk-FNAMNRUH.js";
6
6
 
7
7
  // src/lib/git.ts
8
8
  import { execFileSync } from "child_process";
@@ -11,11 +11,13 @@ import path from "path";
11
11
  function getRepoRoot(cwd = process.cwd()) {
12
12
  try {
13
13
  const realCwd = realpathSync(cwd);
14
- return execFileSync("git", ["rev-parse", "--show-toplevel"], {
14
+ const output = execFileSync("git", ["worktree", "list", "--porcelain"], {
15
15
  cwd: realCwd,
16
16
  encoding: "utf8",
17
17
  stdio: "pipe"
18
- }).trim();
18
+ });
19
+ const firstLine = output.trim().split("\n")[0];
20
+ return realpathSync(firstLine.slice("worktree ".length));
19
21
  } catch {
20
22
  throw new Error("Not in a git repository");
21
23
  }
@@ -197,6 +199,33 @@ function getRegisteredRepos(store = createStore()) {
197
199
  return getGlobalConfig(store).repos;
198
200
  }
199
201
 
202
+ // src/lib/setup.ts
203
+ import { spawn as spawn2 } from "child_process";
204
+ async function runCommands(commands, cwd) {
205
+ for (const command of commands) {
206
+ const result = await runCommand(command, cwd);
207
+ if (!result.success) {
208
+ return {
209
+ success: false,
210
+ failedCommand: command,
211
+ exitCode: result.exitCode
212
+ };
213
+ }
214
+ }
215
+ return { success: true };
216
+ }
217
+ function runCommand(command, cwd) {
218
+ return new Promise((resolve) => {
219
+ const child = spawn2(command, { cwd, stdio: "inherit", shell: true });
220
+ child.on("error", () => {
221
+ resolve({ success: false, exitCode: void 0 });
222
+ });
223
+ child.on("close", (code) => {
224
+ resolve({ success: code === 0, exitCode: code ?? void 0 });
225
+ });
226
+ });
227
+ }
228
+
200
229
  // src/lib/tui.ts
201
230
  import path2 from "path";
202
231
  import Fuse from "fuse.js";
@@ -514,6 +543,7 @@ export {
514
543
  openIde,
515
544
  registerRepo,
516
545
  getRegisteredRepos,
546
+ runCommands,
517
547
  runRepoPicker,
518
548
  runBranchInput,
519
549
  runInteractiveList
@@ -65,6 +65,7 @@ var DEFAULT_CONFIG = {
65
65
  worktree_path: "../",
66
66
  base_branch: "origin/main",
67
67
  setup_commands: [],
68
+ teardown_commands: [],
68
69
  ide: "zed",
69
70
  ide_open_args: ["-n"],
70
71
  agent_command: "claude --permission-mode plan",
package/dist/cli.js CHANGED
@@ -3,12 +3,12 @@
3
3
  // src/cli.ts
4
4
  import { Command } from "commander";
5
5
  var program = new Command();
6
- program.name("wt").description("Git worktree manager").version("0.3.0-pr14.g2b25fef").action(async () => {
7
- const { runList } = await import("./list-VPPPO26E.js");
6
+ program.name("wt").description("Git worktree manager").version("0.4.0-pr16.gca5d1db").action(async () => {
7
+ const { runList } = await import("./list-HIKXMDHJ.js");
8
8
  await runList();
9
9
  });
10
10
  program.command("create [branch]").description("Create a new worktree").action(async (branch) => {
11
- const { createWorktree } = await import("./create-RWGSJRM5.js");
11
+ const { createWorktree } = await import("./create-YBHDJOP5.js");
12
12
  await createWorktree(branch);
13
13
  });
14
14
  program.command("agent <branch> <plan_prompt>").description("Create a worktree and auto-start an AI agent in Zed (macOS)").option(
@@ -17,21 +17,21 @@ program.command("agent <branch> <plan_prompt>").description("Create a worktree a
17
17
  "plan"
18
18
  ).action(
19
19
  async (branch, planPrompt, options) => {
20
- const { createAgentWorktree } = await import("./agent-OJLJFW64.js");
20
+ const { createAgentWorktree } = await import("./agent-WO3XIT4H.js");
21
21
  await createAgentWorktree(branch, planPrompt, { mode: options.mode });
22
22
  }
23
23
  );
24
24
  program.command("config").description("Open the config file in $EDITOR").option("--path", "Print the config file path and exit").action(async (options) => {
25
25
  if (options.path) {
26
- const { printConfigPath } = await import("./config-7QMKGWCX.js");
26
+ const { printConfigPath } = await import("./config-DBM7HJE4.js");
27
27
  printConfigPath();
28
28
  } else {
29
- const { openConfig } = await import("./config-7QMKGWCX.js");
29
+ const { openConfig } = await import("./config-DBM7HJE4.js");
30
30
  openConfig();
31
31
  }
32
32
  });
33
33
  program.command("skill").description("Print the wt skill file to stdout").action(async () => {
34
- const { printSkill } = await import("./skill-CODYQJWN.js");
34
+ const { printSkill } = await import("./skill-FEUVQMK6.js");
35
35
  printSkill();
36
36
  });
37
37
  await program.parseAsync(process.argv);
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  getConfigFilePath
4
- } from "./chunk-F4DNLDG7.js";
4
+ } from "./chunk-FNAMNRUH.js";
5
5
 
6
6
  // src/commands/config.ts
7
7
  import { spawn } from "child_process";
@@ -4,9 +4,9 @@ import {
4
4
  openConfiguredIde,
5
5
  prepareWorktree,
6
6
  promptExistingWorktree
7
- } from "./chunk-HWLB5I4T.js";
8
- import "./chunk-HQANH3IS.js";
9
- import "./chunk-F4DNLDG7.js";
7
+ } from "./chunk-ASVHQXDJ.js";
8
+ import "./chunk-E2IOE23G.js";
9
+ import "./chunk-FNAMNRUH.js";
10
10
  export {
11
11
  createWorktree,
12
12
  openConfiguredIde,
@@ -7,12 +7,13 @@ import {
7
7
  openIde,
8
8
  registerRepo,
9
9
  removeWorktree,
10
+ runCommands,
10
11
  runInteractiveList
11
- } from "./chunk-HQANH3IS.js";
12
+ } from "./chunk-E2IOE23G.js";
12
13
  import {
13
14
  createStore,
14
15
  getEffectiveConfig
15
- } from "./chunk-F4DNLDG7.js";
16
+ } from "./chunk-FNAMNRUH.js";
16
17
 
17
18
  // src/commands/list.ts
18
19
  import * as clack from "@clack/prompts";
@@ -60,6 +61,20 @@ async function runList(options = {}) {
60
61
  message: `Remove worktree ${pc.bold(item.branch)}? This cannot be undone.`
61
62
  });
62
63
  if (clack.isCancel(confirmed) || !confirmed) return false;
64
+ const config = getEffectiveConfig(item.repoRoot, store);
65
+ if (config.teardown_commands.length > 0) {
66
+ console.log(pc.dim("Running teardown commands..."));
67
+ const result = await runCommands(config.teardown_commands, item.path);
68
+ if (!result.success) {
69
+ clack.log.warn(
70
+ `Teardown command failed: ${result.failedCommand} (exit code ${result.exitCode})`
71
+ );
72
+ const proceed = await clack.confirm({
73
+ message: `Delete ${pc.bold(item.branch)} anyway?`
74
+ });
75
+ if (clack.isCancel(proceed) || !proceed) return false;
76
+ }
77
+ }
63
78
  try {
64
79
  removeWorktree(item.repoRoot, item.path);
65
80
  console.log(pc.green(`\u2713 Removed ${item.branch}`));
@@ -110,7 +125,7 @@ ${dirty.map((f) => ` ${f}`).join("\n")}`
110
125
  },
111
126
  onCreate: async () => {
112
127
  if (repoRoot) {
113
- const { createWorktree } = await import("./create-RWGSJRM5.js");
128
+ const { createWorktree } = await import("./create-YBHDJOP5.js");
114
129
  await createWorktree(void 0, { cwd: repoRoot, store });
115
130
  }
116
131
  }
@@ -0,0 +1,9 @@
1
+ #!/usr/bin/env node
2
+
3
+ // src/commands/skill.ts
4
+ function printSkill() {
5
+ console.log('---\nname: wt-worktree-manager\ndescription: Use the wt CLI to create, browse, open, and delete git worktrees across repos. Use when the user asks to manage worktrees, create isolated branches, or configure worktree defaults.\n---\n\n# wt \u2014 Git Worktree Manager\n\n`wt` is a CLI for managing git worktrees. It provides an interactive TUI to browse, create, open in your IDE, and delete worktrees across multiple repos.\n\n## Commands\n\n### `wt` (no subcommand)\n\nLaunch the interactive TUI. Shows worktrees for the current repo (repo mode) or all registered repos (global mode, when run outside a repo).\n\n**Keybindings in the TUI:**\n\n- Arrow keys / `j`/`k` \u2014 navigate\n- `Enter` \u2014 open worktree in IDE\n- `d` \u2014 delete worktree\n- `c` \u2014 create new worktree (repo mode only)\n- `/` \u2014 search\n- `q` / `Esc` \u2014 quit\n\n### `wt create [branch]`\n\nCreate a new worktree. If `branch` is omitted, prompts interactively.\n\nThe worktree is created as a sibling directory to the repo: `<parent>/<repo-name>-<branch-name>`.\n\nAfter creation, `wt` runs any configured `setup_commands` and opens the worktree in your IDE.\n\nIf the worktree path already exists, `wt create` doesn\'t error \u2014 it prompts you\nto **open it in the IDE** or **quit**. (In a non-interactive shell it errors\nwith a non-zero exit instead of prompting.)\n\n### `wt agent <branch> <plan_prompt> [--mode <mode>]`\n\nCreate a worktree (same as `wt create`) **and** auto-start an AI agent in Zed\'s\nintegrated terminal, pre-filled with `<plan_prompt>` and left interactive for\nyou to take over.\n\n```bash\nwt agent feature/login \'Read the codebase, then propose a plan for login.\'\nwt agent feature/fix \'Fix the bug in payment processing\' --mode auto\nwt agent refactor/api \'Refactor the API layer\' --mode default\n```\n\nThe `--mode` flag sets Claude Code\'s permission mode (defaults to `plan`):\n\n- `default` \u2014 Standard interactive mode with approval for each action\n- `acceptEdits` \u2014 Allow file changes but keep command execution controlled\n- `plan` \u2014 Architecture-first mode with no surprise mutations (default)\n- `auto` \u2014 Claude\'s safety model makes decisions instead of prompting\n- `dontAsk` \u2014 Minimal interruptions in trusted environments\n- `bypassPermissions` \u2014 Skip all permission checks (dangerous, CI/sandbox only)\n\nIt writes a temporary `.zed/tasks.json` running\n`<agent_command> --permission-mode <mode> \'<plan_prompt>\'`, ensures a global Zed keymap chord\n(`agent_trigger_chord`) spawns that task, opens Zed, presses the chord via\n`osascript`, then removes the temporary task so the repo is left clean.\n\n**macOS + Zed only.** Requires Accessibility permission for the app that runs\n`wt` (Zed itself, when run from its integrated terminal). If it isn\'t granted,\n`wt agent` opens the _Privacy & Security \u2192 Accessibility_ settings pane and waits\nfor you to grant it and confirm, then retries automatically. On other platforms\n(or when `ide` is not `zed`) the worktree is still created and opened, but the\nagent is not auto-started.\n\nOver SSH it still works, provided the same user has an active graphical login on\nthe Mac: the keystroke is run inside the GUI session via Launch Services\n(`open -a Terminal` briefly flashes a Terminal window). Grant Accessibility to\nTerminal (not Zed) the first time. With no one logged in graphically there is\nnothing to drive, so it falls back to the manual "press the chord in Zed"\nmessage.\n\nIf the worktree path already exists, `wt agent` prompts you to **open it in the\nIDE**, **open it and start the agent**, or **quit** \u2014 instead of erroring. (In a\nnon-interactive shell it errors with a non-zero exit instead of prompting.)\n\n### `wt config`\n\nOpen the global config file in `$EDITOR` (defaults to `nano`).\n\n```bash\nwt config # open in editor\nwt config --path # print config file path only\n```\n\n### `wt skill`\n\nPrint this skill file to stdout. Useful for piping to agents or copying to a project.\n\n## Configuration\n\nConfig is stored as JSON. Get the path with `wt config --path`.\n\n### Schema\n\n| Key | Type | Default | Description |\n| --------------------- | ---------- | --------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |\n| `worktree_path` | `string` | `"../"` | Where to place new worktrees, relative to the repo root |\n| `base_branch` | `string` | `"origin/main"` | Branch to base new worktrees on |\n| `setup_commands` | `string[]` | `[]` | Commands to run in a new worktree after creation (e.g. `["npm install"]`) |\n| `teardown_commands` | `string[]` | `[]` | Commands to run in a worktree just before it is deleted (e.g. `["docker compose down -v"]`); on failure you are prompted whether to delete anyway |\n| `ide` | `string` | `"zed"` | IDE command to open worktrees with |\n| `ide_open_args` | `string[]` | `["-n"]` | Arguments passed to the IDE command |\n| `agent_command` | `string` | `"claude --permission-mode plan"` | Base command `wt agent` runs in Zed; any `--permission-mode` flag is replaced by the `--mode` option (defaults to `plan`), then `<plan_prompt>` is appended single-quoted |\n| `agent_trigger_chord` | `string` | `"ctrl-shift-cmd-c"` | Zed keymap chord `wt agent` installs/presses to spawn the agent task |\n| `repos` | `string[]` | `[]` | Registered repo paths (auto-populated on first use) |\n| `repo_overrides` | `object` | `{}` | Per-repo config overrides (see below) |\n\n### Per-repo overrides\n\nOverride any field (`worktree_path`, `base_branch`, `setup_commands`, `teardown_commands`, `ide`, `ide_open_args`, `agent_command`, `agent_trigger_chord`) for a specific repo:\n\n```json\n{\n "base_branch": "origin/main",\n "ide": "zed",\n "repo_overrides": {\n "/path/to/my-repo": {\n "base_branch": "origin/develop",\n "setup_commands": ["npm install", "npm run build"]\n }\n }\n}\n```\n\n## Common workflows\n\n### Create a worktree for a new feature\n\n```bash\ncd /path/to/repo\nwt create feature/my-branch\n```\n\n### Configure setup commands for a repo\n\n```bash\nwt config\n# Then add to the JSON:\n# "repo_overrides": {\n# "/path/to/repo": {\n# "setup_commands": ["npm install"]\n# }\n# }\n```\n\n### Browse all worktrees across repos\n\nRun `wt` from any directory outside a git repo to see worktrees from all registered repos.\n');
6
+ }
7
+ export {
8
+ printSkill
9
+ };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cestoliv/wt",
3
- "version": "0.3.0-pr14.g2b25fef",
3
+ "version": "0.4.0-pr16.gca5d1db",
4
4
  "description": "Fast, interactive TUI to browse, create, open, and delete git worktrees across repos.",
5
5
  "repository": {
6
6
  "type": "git",
@@ -1,9 +0,0 @@
1
- #!/usr/bin/env node
2
-
3
- // src/commands/skill.ts
4
- function printSkill() {
5
- console.log('---\nname: wt-worktree-manager\ndescription: Use the wt CLI to create, browse, open, and delete git worktrees across repos. Use when the user asks to manage worktrees, create isolated branches, or configure worktree defaults.\n---\n\n# wt \u2014 Git Worktree Manager\n\n`wt` is a CLI for managing git worktrees. It provides an interactive TUI to browse, create, open in your IDE, and delete worktrees across multiple repos.\n\n## Commands\n\n### `wt` (no subcommand)\n\nLaunch the interactive TUI. Shows worktrees for the current repo (repo mode) or all registered repos (global mode, when run outside a repo).\n\n**Keybindings in the TUI:**\n\n- Arrow keys / `j`/`k` \u2014 navigate\n- `Enter` \u2014 open worktree in IDE\n- `d` \u2014 delete worktree\n- `c` \u2014 create new worktree (repo mode only)\n- `/` \u2014 search\n- `q` / `Esc` \u2014 quit\n\n### `wt create [branch]`\n\nCreate a new worktree. If `branch` is omitted, prompts interactively.\n\nThe worktree is created as a sibling directory to the repo: `<parent>/<repo-name>-<branch-name>`.\n\nAfter creation, `wt` runs any configured `setup_commands` and opens the worktree in your IDE.\n\nIf the worktree path already exists, `wt create` doesn\'t error \u2014 it prompts you\nto **open it in the IDE** or **quit**. (In a non-interactive shell it errors\nwith a non-zero exit instead of prompting.)\n\n### `wt agent <branch> <plan_prompt> [--mode <mode>]`\n\nCreate a worktree (same as `wt create`) **and** auto-start an AI agent in Zed\'s\nintegrated terminal, pre-filled with `<plan_prompt>` and left interactive for\nyou to take over.\n\n```bash\nwt agent feature/login \'Read the codebase, then propose a plan for login.\'\nwt agent feature/fix \'Fix the bug in payment processing\' --mode auto\nwt agent refactor/api \'Refactor the API layer\' --mode default\n```\n\nThe `--mode` flag sets Claude Code\'s permission mode (defaults to `plan`):\n\n- `default` \u2014 Standard interactive mode with approval for each action\n- `acceptEdits` \u2014 Allow file changes but keep command execution controlled\n- `plan` \u2014 Architecture-first mode with no surprise mutations (default)\n- `auto` \u2014 Claude\'s safety model makes decisions instead of prompting\n- `dontAsk` \u2014 Minimal interruptions in trusted environments\n- `bypassPermissions` \u2014 Skip all permission checks (dangerous, CI/sandbox only)\n\nIt writes a temporary `.zed/tasks.json` running\n`<agent_command> --permission-mode <mode> \'<plan_prompt>\'`, ensures a global Zed keymap chord\n(`agent_trigger_chord`) spawns that task, opens Zed, presses the chord via\n`osascript`, then removes the temporary task so the repo is left clean.\n\n**macOS + Zed only.** Requires Accessibility permission for the app that runs\n`wt` (Zed itself, when run from its integrated terminal). If it isn\'t granted,\n`wt agent` opens the _Privacy & Security \u2192 Accessibility_ settings pane and waits\nfor you to grant it and confirm, then retries automatically. On other platforms\n(or when `ide` is not `zed`) the worktree is still created and opened, but the\nagent is not auto-started.\n\nIf the worktree path already exists, `wt agent` prompts you to **open it in the\nIDE**, **open it and start the agent**, or **quit** \u2014 instead of erroring. (In a\nnon-interactive shell it errors with a non-zero exit instead of prompting.)\n\n### `wt config`\n\nOpen the global config file in `$EDITOR` (defaults to `nano`).\n\n```bash\nwt config # open in editor\nwt config --path # print config file path only\n```\n\n### `wt skill`\n\nPrint this skill file to stdout. Useful for piping to agents or copying to a project.\n\n## Configuration\n\nConfig is stored as JSON. Get the path with `wt config --path`.\n\n### Schema\n\n| Key | Type | Default | Description |\n| --------------------- | ---------- | --------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |\n| `worktree_path` | `string` | `"../"` | Where to place new worktrees, relative to the repo root |\n| `base_branch` | `string` | `"origin/main"` | Branch to base new worktrees on |\n| `setup_commands` | `string[]` | `[]` | Commands to run in a new worktree after creation (e.g. `["npm install"]`) |\n| `ide` | `string` | `"zed"` | IDE command to open worktrees with |\n| `ide_open_args` | `string[]` | `["-n"]` | Arguments passed to the IDE command |\n| `agent_command` | `string` | `"claude --permission-mode plan"` | Base command `wt agent` runs in Zed; any `--permission-mode` flag is replaced by the `--mode` option (defaults to `plan`), then `<plan_prompt>` is appended single-quoted |\n| `agent_trigger_chord` | `string` | `"ctrl-shift-cmd-c"` | Zed keymap chord `wt agent` installs/presses to spawn the agent task |\n| `repos` | `string[]` | `[]` | Registered repo paths (auto-populated on first use) |\n| `repo_overrides` | `object` | `{}` | Per-repo config overrides (see below) |\n\n### Per-repo overrides\n\nOverride any field (`worktree_path`, `base_branch`, `setup_commands`, `ide`, `ide_open_args`, `agent_command`, `agent_trigger_chord`) for a specific repo:\n\n```json\n{\n "base_branch": "origin/main",\n "ide": "zed",\n "repo_overrides": {\n "/path/to/my-repo": {\n "base_branch": "origin/develop",\n "setup_commands": ["npm install", "npm run build"]\n }\n }\n}\n```\n\n## Common workflows\n\n### Create a worktree for a new feature\n\n```bash\ncd /path/to/repo\nwt create feature/my-branch\n```\n\n### Configure setup commands for a repo\n\n```bash\nwt config\n# Then add to the JSON:\n# "repo_overrides": {\n# "/path/to/repo": {\n# "setup_commands": ["npm install"]\n# }\n# }\n```\n\n### Browse all worktrees across repos\n\nRun `wt` from any directory outside a git repo to see worktrees from all registered repos.\n');
6
- }
7
- export {
8
- printSkill
9
- };