@cestoliv/wt 0.2.1 → 0.3.0-pr13.ge0af7e1

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
@@ -34,30 +34,42 @@ infer from this project. Write the result to the config file (find its path with
34
34
  ## Quick start
35
35
 
36
36
  ```bash
37
- wt # Browse worktrees (interactive TUI)
38
- wt create my-feat # New worktree, opens your IDE
39
- wt agent my-feat "Plan the feature" # New worktree + AI agent in Zed (macOS)
40
- wt config # Edit config in $EDITOR
41
- wt skill # Print the skill file (for AI agents)
37
+ wt # Browse worktrees (interactive TUI)
38
+ wt create my-feat # New worktree, opens your IDE
39
+ wt agent my-feat "Plan the feature" # New worktree + AI agent in Zed (macOS)
40
+ wt agent fix-bug "Fix bug" --mode auto # Use auto mode instead of plan
41
+ wt config # Edit config in $EDITOR
42
+ wt skill # Print the skill file (for AI agents)
42
43
  ```
43
44
 
44
- ## `wt agent <branch> <plan_prompt>` — the standout
45
+ ## `wt agent <branch> <plan_prompt> [--mode <mode>]` — the standout
45
46
 
46
47
  ```bash
47
48
  wt agent feat/login "Read the codebase, then propose a plan for login."
49
+ wt agent fix-bug "Fix the auth bug" --mode auto
50
+ wt agent refactor "Refactor API layer" --mode default
48
51
  ```
49
52
 
50
53
  Creates a worktree exactly like `wt create`, then auto-starts your agent
51
54
  (default `claude --permission-mode plan`) in Zed's integrated terminal —
52
55
  pre-filled with your prompt and left interactive for you to take over.
53
56
 
57
+ **Available modes** (`--mode`, defaults to `plan`):
58
+
59
+ - `default` — Standard interactive mode with approval for each action
60
+ - `acceptEdits` — Allow file changes but keep command execution controlled
61
+ - `plan` — Architecture-first mode with no surprise mutations (default)
62
+ - `auto` — Claude's safety model makes decisions instead of prompting
63
+ - `dontAsk` — Minimal interruptions in trusted environments
64
+ - `bypassPermissions` — Skip all permission checks (dangerous, CI/sandbox only)
65
+
54
66
  Under the hood it writes a temporary `.zed/tasks.json`, installs a global Zed
55
67
  keymap chord, opens Zed and fires the chord via `osascript`, then removes the
56
68
  temp task so the repo stays clean.
57
69
 
58
70
  **Requires** macOS, Zed, and Accessibility permission for the app running `wt`.
59
- Not granted yet? `wt agent` opens *System Settings → Privacy & Security →
60
- Accessibility*, waits while you grant it (you may need to quit and reopen the
71
+ Not granted yet? `wt agent` opens _System Settings → Privacy & Security →
72
+ Accessibility_, waits while you grant it (you may need to quit and reopen the
61
73
  app), then retries automatically. On other platforms — or when `ide` isn't
62
74
  `zed` — the worktree is still created and opened, just without the agent.
63
75
 
@@ -104,16 +116,16 @@ erroring (in a non-interactive shell it exits non-zero).
104
116
  Edit with `wt config` (`wt config --path` prints the file location —
105
117
  `~/Library/Preferences/wt-nodejs/config.json` on macOS).
106
118
 
107
- | Key | Default | Description |
108
- | --------------------- | --------------------------------- | ------------------------------------------------- |
109
- | `ide` | `"zed"` | Editor to open worktrees with |
110
- | `ide_open_args` | `["-n"]` | Extra args passed to the IDE command |
111
- | `base_branch` | `"origin/main"` | Branch new worktrees are created from |
112
- | `worktree_path` | `"../"` | Where worktrees are placed (relative to repo) |
113
- | `setup_commands` | `[]` | Commands to run in new worktrees |
114
- | `agent_command` | `"claude --permission-mode plan"` | What `wt agent` runs in Zed (prompt appended) |
115
- | `agent_trigger_chord` | `"ctrl-shift-cmd-c"` | Zed keymap chord `wt agent` installs and presses |
116
- | `repo_overrides` | `{}` | Per-repo overrides for any key above |
119
+ | Key | Default | Description |
120
+ | --------------------- | --------------------------------- | ----------------------------------------------------------------------------------- |
121
+ | `ide` | `"zed"` | Editor to open worktrees with |
122
+ | `ide_open_args` | `["-n"]` | Extra args passed to the IDE command |
123
+ | `base_branch` | `"origin/main"` | Branch new worktrees are created from |
124
+ | `worktree_path` | `"../"` | Where worktrees are placed (relative to repo) |
125
+ | `setup_commands` | `[]` | Commands to run in new worktrees |
126
+ | `agent_command` | `"claude --permission-mode plan"` | Base command; `--permission-mode` replaced by `--mode` option, then prompt appended |
127
+ | `agent_trigger_chord` | `"ctrl-shift-cmd-c"` | Zed keymap chord `wt agent` installs and presses |
128
+ | `repo_overrides` | `{}` | Per-repo overrides for any key above |
117
129
 
118
130
  Override any key per repo:
119
131
 
package/SKILL.md CHANGED
@@ -34,7 +34,7 @@ If the worktree path already exists, `wt create` doesn't error — it prompts yo
34
34
  to **open it in the IDE** or **quit**. (In a non-interactive shell it errors
35
35
  with a non-zero exit instead of prompting.)
36
36
 
37
- ### `wt agent <branch> <plan_prompt>`
37
+ ### `wt agent <branch> <plan_prompt> [--mode <mode>]`
38
38
 
39
39
  Create a worktree (same as `wt create`) **and** auto-start an AI agent in Zed's
40
40
  integrated terminal, pre-filled with `<plan_prompt>` and left interactive for
@@ -42,20 +42,38 @@ you to take over.
42
42
 
43
43
  ```bash
44
44
  wt agent feature/login 'Read the codebase, then propose a plan for login.'
45
+ wt agent feature/fix 'Fix the bug in payment processing' --mode auto
46
+ wt agent refactor/api 'Refactor the API layer' --mode default
45
47
  ```
46
48
 
49
+ The `--mode` flag sets Claude Code's permission mode (defaults to `plan`):
50
+
51
+ - `default` — Standard interactive mode with approval for each action
52
+ - `acceptEdits` — Allow file changes but keep command execution controlled
53
+ - `plan` — Architecture-first mode with no surprise mutations (default)
54
+ - `auto` — Claude's safety model makes decisions instead of prompting
55
+ - `dontAsk` — Minimal interruptions in trusted environments
56
+ - `bypassPermissions` — Skip all permission checks (dangerous, CI/sandbox only)
57
+
47
58
  It writes a temporary `.zed/tasks.json` running
48
- `<agent_command> '<plan_prompt>'`, ensures a global Zed keymap chord
59
+ `<agent_command> --permission-mode <mode> '<plan_prompt>'`, ensures a global Zed keymap chord
49
60
  (`agent_trigger_chord`) spawns that task, opens Zed, presses the chord via
50
61
  `osascript`, then removes the temporary task so the repo is left clean.
51
62
 
52
63
  **macOS + Zed only.** Requires Accessibility permission for the app that runs
53
64
  `wt` (Zed itself, when run from its integrated terminal). If it isn't granted,
54
- `wt agent` opens the *Privacy & Security → Accessibility* settings pane and waits
65
+ `wt agent` opens the _Privacy & Security → Accessibility_ settings pane and waits
55
66
  for you to grant it and confirm, then retries automatically. On other platforms
56
67
  (or when `ide` is not `zed`) the worktree is still created and opened, but the
57
68
  agent is not auto-started.
58
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
+
59
77
  If the worktree path already exists, `wt agent` prompts you to **open it in the
60
78
  IDE**, **open it and start the agent**, or **quit** — instead of erroring. (In a
61
79
  non-interactive shell it errors with a non-zero exit instead of prompting.)
@@ -79,17 +97,17 @@ Config is stored as JSON. Get the path with `wt config --path`.
79
97
 
80
98
  ### Schema
81
99
 
82
- | Key | Type | Default | Description |
83
- | ---------------- | ---------- | --------------- | ------------------------------------------------------------------------- |
84
- | `worktree_path` | `string` | `"../"` | Where to place new worktrees, relative to the repo root |
85
- | `base_branch` | `string` | `"origin/main"` | Branch to base new worktrees on |
86
- | `setup_commands` | `string[]` | `[]` | Commands to run in a new worktree after creation (e.g. `["npm install"]`) |
87
- | `ide` | `string` | `"zed"` | IDE command to open worktrees with |
88
- | `ide_open_args` | `string[]` | `["-n"]` | Arguments passed to the IDE command |
89
- | `agent_command` | `string` | `"claude --permission-mode plan"` | Command `wt agent` runs in Zed; `<plan_prompt>` is appended single-quoted |
90
- | `agent_trigger_chord` | `string` | `"ctrl-shift-cmd-c"` | Zed keymap chord `wt agent` installs/presses to spawn the agent task |
91
- | `repos` | `string[]` | `[]` | Registered repo paths (auto-populated on first use) |
92
- | `repo_overrides` | `object` | `{}` | Per-repo config overrides (see below) |
100
+ | Key | Type | Default | Description |
101
+ | --------------------- | ---------- | --------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
102
+ | `worktree_path` | `string` | `"../"` | Where to place new worktrees, relative to the repo root |
103
+ | `base_branch` | `string` | `"origin/main"` | Branch to base new worktrees on |
104
+ | `setup_commands` | `string[]` | `[]` | Commands to run in a new worktree after creation (e.g. `["npm install"]`) |
105
+ | `ide` | `string` | `"zed"` | IDE command to open worktrees with |
106
+ | `ide_open_args` | `string[]` | `["-n"]` | Arguments passed to the IDE command |
107
+ | `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 |
108
+ | `agent_trigger_chord` | `string` | `"ctrl-shift-cmd-c"` | Zed keymap chord `wt agent` installs/presses to spawn the agent task |
109
+ | `repos` | `string[]` | `[]` | Registered repo paths (auto-populated on first use) |
110
+ | `repo_overrides` | `object` | `{}` | Per-repo config overrides (see below) |
93
111
 
94
112
  ### Per-repo overrides
95
113
 
@@ -3,9 +3,9 @@ import {
3
3
  openConfiguredIde,
4
4
  prepareWorktree,
5
5
  promptExistingWorktree
6
- } from "./chunk-BYWCGKUP.js";
7
- import "./chunk-FSARWOCW.js";
8
- import "./chunk-IQWENLPW.js";
6
+ } from "./chunk-HWLB5I4T.js";
7
+ import "./chunk-HQANH3IS.js";
8
+ import "./chunk-F4DNLDG7.js";
9
9
 
10
10
  // src/commands/agent.ts
11
11
  import * as clack from "@clack/prompts";
@@ -14,22 +14,29 @@ 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";
28
- function buildAgentTask(agentCommand, prompt, label) {
30
+ function buildAgentTask(agentCommand, prompt, label, mode) {
31
+ let finalCommand = agentCommand;
32
+ if (mode) {
33
+ const baseCommand = agentCommand.replace(/--permission-mode\s+\S+/g, "").replace(/\s+/g, " ").trim();
34
+ finalCommand = `${baseCommand} --permission-mode ${mode}`.trim();
35
+ }
29
36
  const escaped = prompt.replace(/'/g, "'\\''");
30
37
  return {
31
38
  label,
32
- command: `${agentCommand} '${escaped}'`,
39
+ command: `${finalCommand} '${escaped}'`,
33
40
  cwd: "$ZED_WORKTREE_ROOT",
34
41
  use_new_terminal: true,
35
42
  allow_concurrent_runs: false,
@@ -273,19 +280,99 @@ Note: "${chord}" is already bound in ${keymapPath}; wt's agent binding will take
273
280
  return true;
274
281
  }
275
282
  var ACCESSIBILITY_SETTINGS_URL = "x-apple.systempreferences:com.apple.preference.security?Privacy_Accessibility";
276
- 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
+ return [
288
+ "#!/bin/sh",
289
+ `out=$(osascript '${scriptPath}' 2>&1)`,
290
+ "code=$?",
291
+ `printf '%s\\n%s' "$code" "$out" > '${resultPath}.tmp' && mv '${resultPath}.tmp' '${resultPath}'`,
292
+ `osascript -e 'tell application "Terminal" to close front window' >/dev/null 2>&1 &`,
293
+ ""
294
+ ].join("\n");
295
+ }
296
+ function parseGuiResult(content) {
297
+ const newline = content.indexOf("\n");
298
+ const codeStr = (newline === -1 ? content : content.slice(0, newline)).trim();
299
+ const stderr = newline === -1 ? "" : content.slice(newline + 1);
300
+ const code = Number.parseInt(codeStr, 10);
301
+ return { code: Number.isNaN(code) ? null : code, stderr };
302
+ }
303
+ var OSASCRIPT_TIMEOUT_MS = 3e4;
304
+ var sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
305
+ function spawnOpen(helperPath) {
306
+ return new Promise((resolve, reject) => {
307
+ const child = spawn("open", ["-a", "Terminal", helperPath], {
308
+ stdio: "ignore"
309
+ });
310
+ child.on("error", reject);
311
+ child.on("close", () => resolve());
312
+ });
313
+ }
314
+ async function pollFile(path, timeoutMs) {
315
+ const deadline = Date.now() + timeoutMs;
316
+ while (Date.now() < deadline) {
317
+ if (existsSync(path)) return readFileSync(path, "utf8");
318
+ await sleep(200);
319
+ }
320
+ return null;
321
+ }
322
+ async function runViaGuiHelper(script) {
323
+ const dir = mkdtempSync(join(tmpdir(), "wt-agent-"));
324
+ const scriptPath = join(dir, "chord.applescript");
325
+ const helperPath = join(dir, "run.command");
326
+ const resultPath = join(dir, "result");
327
+ try {
328
+ writeFileSync(scriptPath, script);
329
+ writeFileSync(helperPath, buildGuiHelperScript(scriptPath, resultPath));
330
+ chmodSync(helperPath, 493);
331
+ await spawnOpen(helperPath);
332
+ const content = await pollFile(resultPath, OSASCRIPT_TIMEOUT_MS);
333
+ if (content === null) {
334
+ return {
335
+ code: null,
336
+ stderr: "Timed out waiting for the keystroke \u2014 is a user logged into the Mac's graphical session?"
337
+ };
338
+ }
339
+ return parseGuiResult(content);
340
+ } catch (err) {
341
+ return { code: null, stderr: err.message };
342
+ } finally {
343
+ rmSync(dir, { recursive: true, force: true });
344
+ }
345
+ }
346
+ function runOsascriptDirect(script) {
277
347
  return new Promise((resolve) => {
278
348
  const child = spawn("osascript", ["-e", script], {
279
349
  stdio: ["ignore", "ignore", "pipe"]
280
350
  });
281
351
  let stderr = "";
352
+ let settled = false;
353
+ const finish = (result) => {
354
+ if (settled) return;
355
+ settled = true;
356
+ clearTimeout(timer);
357
+ resolve(result);
358
+ };
359
+ const timer = setTimeout(() => {
360
+ child.kill();
361
+ finish({
362
+ code: null,
363
+ stderr: "osascript timed out \u2014 is a user logged into the Mac's graphical session?"
364
+ });
365
+ }, OSASCRIPT_TIMEOUT_MS);
282
366
  child.stderr?.on("data", (d) => {
283
367
  stderr += d.toString();
284
368
  });
285
- child.on("error", (err) => resolve({ code: null, stderr: err.message }));
286
- child.on("close", (code) => resolve({ code, stderr }));
369
+ child.on("error", (err) => finish({ code: null, stderr: err.message }));
370
+ child.on("close", (code) => finish({ code, stderr }));
287
371
  });
288
372
  }
373
+ function defaultRunner(script) {
374
+ return isHeadlessSession() ? runViaGuiHelper(script) : runOsascriptDirect(script);
375
+ }
289
376
  function isAccessibilityError(stderr) {
290
377
  return /\b1002\b/.test(stderr) || /-1719\b/.test(stderr) || /not allowed to send keystrokes/i.test(stderr) || /not allowed assistive access/i.test(stderr);
291
378
  }
@@ -319,9 +406,24 @@ function openAccessibilitySettings(open = defaultOpen) {
319
406
  }
320
407
 
321
408
  // src/commands/agent.ts
409
+ var VALID_MODES = [
410
+ "default",
411
+ "acceptEdits",
412
+ "plan",
413
+ "auto",
414
+ "dontAsk",
415
+ "bypassPermissions"
416
+ ];
322
417
  var CLEANUP_DELAY_MS = 2e4;
323
418
  var delay = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
324
419
  async function createAgentWorktree(branch, planPrompt, options = {}) {
420
+ const mode = options.mode ?? "plan";
421
+ if (!VALID_MODES.includes(mode)) {
422
+ console.error(
423
+ pc.red(`Invalid mode "${mode}". Valid modes: ${VALID_MODES.join(", ")}`)
424
+ );
425
+ process.exit(1);
426
+ }
325
427
  const prepared = await prepareWorktree(branch, options);
326
428
  if (!prepared) return;
327
429
  const { status, config, worktreePath } = prepared;
@@ -334,9 +436,9 @@ async function createAgentWorktree(branch, planPrompt, options = {}) {
334
436
  return;
335
437
  }
336
438
  }
337
- await startAgentInWorktree(config, worktreePath, planPrompt);
439
+ await startAgentInWorktree(config, worktreePath, planPrompt, mode);
338
440
  }
339
- async function startAgentInWorktree(config, worktreePath, planPrompt) {
441
+ async function startAgentInWorktree(config, worktreePath, planPrompt, mode) {
340
442
  if (config.ide !== "zed") {
341
443
  console.warn(
342
444
  pc.yellow(
@@ -356,7 +458,8 @@ async function startAgentInWorktree(config, worktreePath, planPrompt) {
356
458
  const task = buildAgentTask(
357
459
  config.agent_command,
358
460
  planPrompt,
359
- AGENT_TASK_LABEL
461
+ AGENT_TASK_LABEL,
462
+ mode
360
463
  );
361
464
  const created = writeAgentTask(worktreePath, task);
362
465
  const keymapOk = ensureKeymap(config.agent_trigger_chord, AGENT_TASK_LABEL);
@@ -383,8 +486,9 @@ async function startAgentInWorktree(config, worktreePath, planPrompt) {
383
486
  )
384
487
  );
385
488
  openAccessibilitySettings();
489
+ const grantee = isHeadlessSession() ? "Terminal" : "the app running wt (e.g. Zed)";
386
490
  const proceed = await clack.confirm({
387
- 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.)"
491
+ 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.)`
388
492
  });
389
493
  if (clack.isCancel(proceed) || !proceed) break;
390
494
  result = await triggerChord(config.agent_trigger_chord, {
@@ -419,7 +523,7 @@ function reportTriggerFailure(result, chord) {
419
523
  }
420
524
  console.warn(
421
525
  pc.yellow(
422
- `\u26A0 Could not auto-start the agent${result.message ? `: ${result.message}` : ""}. In Zed, press ${chord} to start it manually.`
526
+ `\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.)`
423
527
  )
424
528
  );
425
529
  }
@@ -0,0 +1,114 @@
1
+ #!/usr/bin/env node
2
+
3
+ // src/lib/config.ts
4
+ import path2 from "path";
5
+ import Conf from "conf";
6
+
7
+ // node_modules/env-paths/index.js
8
+ import path from "path";
9
+ import os from "os";
10
+ import process2 from "process";
11
+ var homedir = os.homedir();
12
+ var tmpdir = os.tmpdir();
13
+ var { env } = process2;
14
+ var macos = (name) => {
15
+ const library = path.join(homedir, "Library");
16
+ return {
17
+ data: path.join(library, "Application Support", name),
18
+ config: path.join(library, "Preferences", name),
19
+ cache: path.join(library, "Caches", name),
20
+ log: path.join(library, "Logs", name),
21
+ temp: path.join(tmpdir, name)
22
+ };
23
+ };
24
+ var windows = (name) => {
25
+ const appData = env.APPDATA || path.join(homedir, "AppData", "Roaming");
26
+ const localAppData = env.LOCALAPPDATA || path.join(homedir, "AppData", "Local");
27
+ return {
28
+ // Data/config/cache/log are invented by me as Windows isn't opinionated about this
29
+ data: path.join(localAppData, name, "Data"),
30
+ config: path.join(appData, name, "Config"),
31
+ cache: path.join(localAppData, name, "Cache"),
32
+ log: path.join(localAppData, name, "Log"),
33
+ temp: path.join(tmpdir, name)
34
+ };
35
+ };
36
+ var linux = (name) => {
37
+ const username = path.basename(homedir);
38
+ return {
39
+ data: path.join(env.XDG_DATA_HOME || path.join(homedir, ".local", "share"), name),
40
+ config: path.join(env.XDG_CONFIG_HOME || path.join(homedir, ".config"), name),
41
+ cache: path.join(env.XDG_CACHE_HOME || path.join(homedir, ".cache"), name),
42
+ // https://wiki.debian.org/XDGBaseDirectorySpecification#state
43
+ log: path.join(env.XDG_STATE_HOME || path.join(homedir, ".local", "state"), name),
44
+ temp: path.join(tmpdir, username, name)
45
+ };
46
+ };
47
+ function envPaths(name, { suffix = "nodejs" } = {}) {
48
+ if (typeof name !== "string") {
49
+ throw new TypeError(`Expected a string, got ${typeof name}`);
50
+ }
51
+ if (suffix) {
52
+ name += `-${suffix}`;
53
+ }
54
+ if (process2.platform === "darwin") {
55
+ return macos(name);
56
+ }
57
+ if (process2.platform === "win32") {
58
+ return windows(name);
59
+ }
60
+ return linux(name);
61
+ }
62
+
63
+ // src/lib/config.ts
64
+ var DEFAULT_CONFIG = {
65
+ worktree_path: "../",
66
+ base_branch: "origin/main",
67
+ setup_commands: [],
68
+ ide: "zed",
69
+ ide_open_args: ["-n"],
70
+ agent_command: "claude --permission-mode plan",
71
+ agent_trigger_chord: "ctrl-shift-cmd-c",
72
+ repos: [],
73
+ repo_overrides: {}
74
+ };
75
+ var DEFAULT_CONFIG_DIR = envPaths("wt").config;
76
+ function getConfigFilePath(cwd) {
77
+ const dir = cwd ?? DEFAULT_CONFIG_DIR;
78
+ return path2.join(dir, "config.json");
79
+ }
80
+ function createStore(cwd) {
81
+ try {
82
+ return new Conf({
83
+ projectName: "wt",
84
+ defaults: DEFAULT_CONFIG,
85
+ ...cwd ? { cwd } : {}
86
+ });
87
+ } catch (error) {
88
+ const configPath = getConfigFilePath(cwd);
89
+ console.error(
90
+ `Error reading config file: ${configPath}
91
+ ${error instanceof Error ? error.message : error}`
92
+ );
93
+ process.exit(1);
94
+ }
95
+ }
96
+ function getGlobalConfig(store = createStore()) {
97
+ return store.store;
98
+ }
99
+ function getEffectiveConfig(repoPath, store = createStore()) {
100
+ const {
101
+ repos: _repos,
102
+ repo_overrides,
103
+ ...repoFields
104
+ } = getGlobalConfig(store);
105
+ const override = repo_overrides[repoPath] ?? {};
106
+ return { ...repoFields, ...override };
107
+ }
108
+
109
+ export {
110
+ getConfigFilePath,
111
+ createStore,
112
+ getGlobalConfig,
113
+ getEffectiveConfig
114
+ };
@@ -2,7 +2,7 @@
2
2
  import {
3
3
  createStore,
4
4
  getGlobalConfig
5
- } from "./chunk-IQWENLPW.js";
5
+ } from "./chunk-F4DNLDG7.js";
6
6
 
7
7
  // src/lib/git.ts
8
8
  import { execFileSync } from "child_process";
@@ -124,6 +124,16 @@ function branchExists(repoRoot, branch) {
124
124
  return false;
125
125
  }
126
126
  }
127
+ function setUpstreamTracking(worktreePath, branch, remote = "origin") {
128
+ try {
129
+ execFileSync(
130
+ "git",
131
+ ["branch", "--set-upstream-to", `${remote}/${branch}`, branch],
132
+ { cwd: worktreePath, stdio: "pipe" }
133
+ );
134
+ } catch {
135
+ }
136
+ }
127
137
  function fetchRemote(repoRoot, remote = "origin") {
128
138
  execFileSync("git", ["fetch", remote], {
129
139
  cwd: repoRoot,
@@ -498,6 +508,7 @@ export {
498
508
  removeWorktree,
499
509
  listWorktreeDirtyFiles,
500
510
  branchExists,
511
+ setUpstreamTracking,
501
512
  fetchRemote,
502
513
  resolveWorktreePath,
503
514
  openIde,
@@ -10,12 +10,13 @@ import {
10
10
  registerRepo,
11
11
  resolveWorktreePath,
12
12
  runBranchInput,
13
- runRepoPicker
14
- } from "./chunk-FSARWOCW.js";
13
+ runRepoPicker,
14
+ setUpstreamTracking
15
+ } from "./chunk-HQANH3IS.js";
15
16
  import {
16
17
  createStore,
17
18
  getEffectiveConfig
18
- } from "./chunk-IQWENLPW.js";
19
+ } from "./chunk-F4DNLDG7.js";
19
20
 
20
21
  // src/commands/create.ts
21
22
  import { existsSync } from "fs";
@@ -118,8 +119,8 @@ async function prepareWorktree(branch, options = {}) {
118
119
  return { status: "exists", repoRoot, worktreePath, config };
119
120
  }
120
121
  const parts = config.base_branch.split("/", 2);
122
+ const remote = parts[0] || "origin";
121
123
  if (parts.length === 2) {
122
- const remote = parts[0];
123
124
  try {
124
125
  fetchRemote(repoRoot, remote);
125
126
  } catch (err) {
@@ -136,6 +137,7 @@ async function prepareWorktree(branch, options = {}) {
136
137
  } else {
137
138
  addWorktree(repoRoot, worktreePath, branch, config.base_branch);
138
139
  }
140
+ setUpstreamTracking(worktreePath, branch, remote);
139
141
  console.log(pc.green(`\u2713 Created worktree at ${worktreePath}`));
140
142
  if (config.setup_commands.length > 0) {
141
143
  console.log(pc.dim("Running setup commands..."));
package/dist/cli.js CHANGED
@@ -3,29 +3,35 @@
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.2.1").action(async () => {
7
- const { runList } = await import("./list-5TXRTSIW.js");
6
+ program.name("wt").description("Git worktree manager").version("0.3.0-pr13.ge0af7e1").action(async () => {
7
+ const { runList } = await import("./list-VPPPO26E.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-5J5NGGGM.js");
11
+ const { createWorktree } = await import("./create-RWGSJRM5.js");
12
12
  await createWorktree(branch);
13
13
  });
14
- program.command("agent <branch> <plan_prompt>").description("Create a worktree and auto-start an AI agent in Zed (macOS)").action(async (branch, planPrompt) => {
15
- const { createAgentWorktree } = await import("./agent-PKCZHGN7.js");
16
- await createAgentWorktree(branch, planPrompt);
17
- });
14
+ program.command("agent <branch> <plan_prompt>").description("Create a worktree and auto-start an AI agent in Zed (macOS)").option(
15
+ "--mode <mode>",
16
+ "Claude Code permission mode (default, plan, auto, etc.)",
17
+ "plan"
18
+ ).action(
19
+ async (branch, planPrompt, options) => {
20
+ const { createAgentWorktree } = await import("./agent-FMAIFYSL.js");
21
+ await createAgentWorktree(branch, planPrompt, { mode: options.mode });
22
+ }
23
+ );
18
24
  program.command("config").description("Open the config file in $EDITOR").option("--path", "Print the config file path and exit").action(async (options) => {
19
25
  if (options.path) {
20
- const { printConfigPath } = await import("./config-OSNYQCZL.js");
26
+ const { printConfigPath } = await import("./config-7QMKGWCX.js");
21
27
  printConfigPath();
22
28
  } else {
23
- const { openConfig } = await import("./config-OSNYQCZL.js");
29
+ const { openConfig } = await import("./config-7QMKGWCX.js");
24
30
  openConfig();
25
31
  }
26
32
  });
27
33
  program.command("skill").description("Print the wt skill file to stdout").action(async () => {
28
- const { printSkill } = await import("./skill-RR6MNLWH.js");
34
+ const { printSkill } = await import("./skill-57YMIZPX.js");
29
35
  printSkill();
30
36
  });
31
37
  await program.parseAsync(process.argv);
@@ -1,18 +1,16 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
- createStore
4
- } from "./chunk-IQWENLPW.js";
3
+ getConfigFilePath
4
+ } from "./chunk-F4DNLDG7.js";
5
5
 
6
6
  // src/commands/config.ts
7
7
  import { spawn } from "child_process";
8
- function getConfigPath(store = createStore()) {
9
- return store.path;
8
+ function printConfigPath(cwd) {
9
+ const configPath = getConfigFilePath(cwd);
10
+ console.log(configPath);
10
11
  }
11
- function printConfigPath(store = createStore()) {
12
- console.log(store.path);
13
- }
14
- function openConfig(store = createStore()) {
15
- const configPath = store.path;
12
+ function openConfig(cwd) {
13
+ const configPath = getConfigFilePath(cwd);
16
14
  console.log(`Config: ${configPath}`);
17
15
  const editor = process.env.EDITOR ?? "nano";
18
16
  const child = spawn(editor, [configPath], { stdio: "inherit" });
@@ -23,7 +21,6 @@ function openConfig(store = createStore()) {
23
21
  child.on("close", (code) => process.exit(code ?? 0));
24
22
  }
25
23
  export {
26
- getConfigPath,
27
24
  openConfig,
28
25
  printConfigPath
29
26
  };
@@ -4,9 +4,9 @@ import {
4
4
  openConfiguredIde,
5
5
  prepareWorktree,
6
6
  promptExistingWorktree
7
- } from "./chunk-BYWCGKUP.js";
8
- import "./chunk-FSARWOCW.js";
9
- import "./chunk-IQWENLPW.js";
7
+ } from "./chunk-HWLB5I4T.js";
8
+ import "./chunk-HQANH3IS.js";
9
+ import "./chunk-F4DNLDG7.js";
10
10
  export {
11
11
  createWorktree,
12
12
  openConfiguredIde,
@@ -8,11 +8,11 @@ import {
8
8
  registerRepo,
9
9
  removeWorktree,
10
10
  runInteractiveList
11
- } from "./chunk-FSARWOCW.js";
11
+ } from "./chunk-HQANH3IS.js";
12
12
  import {
13
13
  createStore,
14
14
  getEffectiveConfig
15
- } from "./chunk-IQWENLPW.js";
15
+ } from "./chunk-F4DNLDG7.js";
16
16
 
17
17
  // src/commands/list.ts
18
18
  import * as clack from "@clack/prompts";
@@ -110,7 +110,7 @@ ${dirty.map((f) => ` ${f}`).join("\n")}`
110
110
  },
111
111
  onCreate: async () => {
112
112
  if (repoRoot) {
113
- const { createWorktree } = await import("./create-5J5NGGGM.js");
113
+ const { createWorktree } = await import("./create-RWGSJRM5.js");
114
114
  await createWorktree(void 0, { cwd: repoRoot, store });
115
115
  }
116
116
  }
@@ -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| `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
+ };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cestoliv/wt",
3
- "version": "0.2.1",
3
+ "version": "0.3.0-pr13.ge0af7e1",
4
4
  "description": "Fast, interactive TUI to browse, create, open, and delete git worktrees across repos.",
5
5
  "repository": {
6
6
  "type": "git",
@@ -1,40 +0,0 @@
1
- #!/usr/bin/env node
2
-
3
- // src/lib/config.ts
4
- import Conf from "conf";
5
- var DEFAULT_CONFIG = {
6
- worktree_path: "../",
7
- base_branch: "origin/main",
8
- setup_commands: [],
9
- ide: "zed",
10
- ide_open_args: ["-n"],
11
- agent_command: "claude --permission-mode plan",
12
- agent_trigger_chord: "ctrl-shift-cmd-c",
13
- repos: [],
14
- repo_overrides: {}
15
- };
16
- function createStore(cwd) {
17
- return new Conf({
18
- projectName: "wt",
19
- defaults: DEFAULT_CONFIG,
20
- ...cwd ? { cwd } : {}
21
- });
22
- }
23
- function getGlobalConfig(store = createStore()) {
24
- return store.store;
25
- }
26
- function getEffectiveConfig(repoPath, store = createStore()) {
27
- const {
28
- repos: _repos,
29
- repo_overrides,
30
- ...repoFields
31
- } = getGlobalConfig(store);
32
- const override = repo_overrides[repoPath] ?? {};
33
- return { ...repoFields, ...override };
34
- }
35
-
36
- export {
37
- createStore,
38
- getGlobalConfig,
39
- getEffectiveConfig
40
- };
@@ -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>`\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.\'\n```\n\nIt writes a temporary `.zed/tasks.json` running\n`<agent_command> \'<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"` | Command `wt agent` runs in Zed; `<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
- };