@hytfjwr/claude-worktree 0.1.0

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 (103) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +233 -0
  3. package/dist/bin/claude-worktree.d.ts +3 -0
  4. package/dist/bin/claude-worktree.d.ts.map +1 -0
  5. package/dist/bin/claude-worktree.js +14 -0
  6. package/dist/bin/claude-worktree.js.map +1 -0
  7. package/dist/src/cli.d.ts +17 -0
  8. package/dist/src/cli.d.ts.map +1 -0
  9. package/dist/src/cli.js +360 -0
  10. package/dist/src/cli.js.map +1 -0
  11. package/dist/src/commands/clean.d.ts +3 -0
  12. package/dist/src/commands/clean.d.ts.map +1 -0
  13. package/dist/src/commands/clean.js +190 -0
  14. package/dist/src/commands/clean.js.map +1 -0
  15. package/dist/src/commands/create.d.ts +14 -0
  16. package/dist/src/commands/create.d.ts.map +1 -0
  17. package/dist/src/commands/create.js +458 -0
  18. package/dist/src/commands/create.js.map +1 -0
  19. package/dist/src/commands/hooks.d.ts +8 -0
  20. package/dist/src/commands/hooks.d.ts.map +1 -0
  21. package/dist/src/commands/hooks.js +28 -0
  22. package/dist/src/commands/hooks.js.map +1 -0
  23. package/dist/src/commands/list.d.ts +17 -0
  24. package/dist/src/commands/list.d.ts.map +1 -0
  25. package/dist/src/commands/list.js +228 -0
  26. package/dist/src/commands/list.js.map +1 -0
  27. package/dist/src/commands/rollback.d.ts +3 -0
  28. package/dist/src/commands/rollback.d.ts.map +1 -0
  29. package/dist/src/commands/rollback.js +99 -0
  30. package/dist/src/commands/rollback.js.map +1 -0
  31. package/dist/src/commands/run-in-pane.d.ts +4 -0
  32. package/dist/src/commands/run-in-pane.d.ts.map +1 -0
  33. package/dist/src/commands/run-in-pane.js +120 -0
  34. package/dist/src/commands/run-in-pane.js.map +1 -0
  35. package/dist/src/core/cache.d.ts +10 -0
  36. package/dist/src/core/cache.d.ts.map +1 -0
  37. package/dist/src/core/cache.js +66 -0
  38. package/dist/src/core/cache.js.map +1 -0
  39. package/dist/src/core/config.d.ts +11 -0
  40. package/dist/src/core/config.d.ts.map +1 -0
  41. package/dist/src/core/config.js +181 -0
  42. package/dist/src/core/config.js.map +1 -0
  43. package/dist/src/core/errors.d.ts +9 -0
  44. package/dist/src/core/errors.d.ts.map +1 -0
  45. package/dist/src/core/errors.js +20 -0
  46. package/dist/src/core/errors.js.map +1 -0
  47. package/dist/src/core/exec.d.ts +73 -0
  48. package/dist/src/core/exec.d.ts.map +1 -0
  49. package/dist/src/core/exec.js +138 -0
  50. package/dist/src/core/exec.js.map +1 -0
  51. package/dist/src/core/git.d.ts +28 -0
  52. package/dist/src/core/git.d.ts.map +1 -0
  53. package/dist/src/core/git.js +291 -0
  54. package/dist/src/core/git.js.map +1 -0
  55. package/dist/src/core/session.d.ts +9 -0
  56. package/dist/src/core/session.d.ts.map +1 -0
  57. package/dist/src/core/session.js +87 -0
  58. package/dist/src/core/session.js.map +1 -0
  59. package/dist/src/core/slot.d.ts +7 -0
  60. package/dist/src/core/slot.d.ts.map +1 -0
  61. package/dist/src/core/slot.js +73 -0
  62. package/dist/src/core/slot.js.map +1 -0
  63. package/dist/src/external/claude.d.ts +3 -0
  64. package/dist/src/external/claude.d.ts.map +1 -0
  65. package/dist/src/external/claude.js +71 -0
  66. package/dist/src/external/claude.js.map +1 -0
  67. package/dist/src/external/wezterm.d.ts +11 -0
  68. package/dist/src/external/wezterm.d.ts.map +1 -0
  69. package/dist/src/external/wezterm.js +87 -0
  70. package/dist/src/external/wezterm.js.map +1 -0
  71. package/dist/src/index.d.ts +24 -0
  72. package/dist/src/index.d.ts.map +1 -0
  73. package/dist/src/index.js +44 -0
  74. package/dist/src/index.js.map +1 -0
  75. package/dist/src/options.d.ts +3 -0
  76. package/dist/src/options.d.ts.map +1 -0
  77. package/dist/src/options.js +54 -0
  78. package/dist/src/options.js.map +1 -0
  79. package/dist/src/types.d.ts +273 -0
  80. package/dist/src/types.d.ts.map +1 -0
  81. package/dist/src/types.js +5 -0
  82. package/dist/src/types.js.map +1 -0
  83. package/dist/src/ui/color.d.ts +12 -0
  84. package/dist/src/ui/color.d.ts.map +1 -0
  85. package/dist/src/ui/color.js +40 -0
  86. package/dist/src/ui/color.js.map +1 -0
  87. package/dist/src/ui/icons.d.ts +22 -0
  88. package/dist/src/ui/icons.d.ts.map +1 -0
  89. package/dist/src/ui/icons.js +26 -0
  90. package/dist/src/ui/icons.js.map +1 -0
  91. package/dist/src/ui/logger.d.ts +14 -0
  92. package/dist/src/ui/logger.d.ts.map +1 -0
  93. package/dist/src/ui/logger.js +35 -0
  94. package/dist/src/ui/logger.js.map +1 -0
  95. package/dist/src/ui/prompt.d.ts +4 -0
  96. package/dist/src/ui/prompt.d.ts.map +1 -0
  97. package/dist/src/ui/prompt.js +57 -0
  98. package/dist/src/ui/prompt.js.map +1 -0
  99. package/dist/src/ui/spinner.d.ts +26 -0
  100. package/dist/src/ui/spinner.d.ts.map +1 -0
  101. package/dist/src/ui/spinner.js +319 -0
  102. package/dist/src/ui/spinner.js.map +1 -0
  103. package/package.json +54 -0
@@ -0,0 +1,181 @@
1
+ import { spawn } from "node:child_process";
2
+ import { readFile } from "node:fs/promises";
3
+ import { join } from "node:path";
4
+ import { TextDecoder } from "node:util";
5
+ import { logWarn } from "../ui/logger.js";
6
+ import { getErrorMessage, isNodeError } from "./errors.js";
7
+ import { exec } from "./exec.js";
8
+ export async function loadProjectConfig(repoRoot) {
9
+ const configPath = join(repoRoot, ".claude-worktree.json");
10
+ let content;
11
+ try {
12
+ content = await readFile(configPath, "utf-8");
13
+ }
14
+ catch (error) {
15
+ if (isNodeError(error) && error.code === "ENOENT") {
16
+ return null;
17
+ }
18
+ throw error;
19
+ }
20
+ try {
21
+ return JSON.parse(content);
22
+ }
23
+ catch (error) {
24
+ const message = getErrorMessage(error);
25
+ logWarn(`Failed to parse .claude-worktree.json: ${message}`);
26
+ return null;
27
+ }
28
+ }
29
+ /**
30
+ * Validate template variable values to prevent shell injection.
31
+ * The command template itself is trusted (committed to repo like npm scripts),
32
+ * but dynamic values substituted via {path}/{slot} must be safe.
33
+ */
34
+ function validateHookVars(vars) {
35
+ if (vars.path.length === 0) {
36
+ throw new Error("Invalid path in hook variables. Path must not be empty.");
37
+ }
38
+ const SAFE_PATH = /^[a-zA-Z0-9._/-]+$/;
39
+ if (!SAFE_PATH.test(vars.path)) {
40
+ throw new Error(`Invalid path in hook variables: ${JSON.stringify(vars.path)}. Only alphanumeric, dots, underscores, slashes, and hyphens are allowed.`);
41
+ }
42
+ if (vars.path.startsWith("-")) {
43
+ throw new Error("Invalid path in hook variables. Path must not start with '-' to avoid being interpreted as a command-line option.");
44
+ }
45
+ if (vars.slot != null && (!Number.isInteger(vars.slot) || vars.slot < 1 || vars.slot > 9)) {
46
+ throw new Error("Invalid slot: must be an integer between 1-9");
47
+ }
48
+ }
49
+ export function buildHookCommand(template, vars) {
50
+ validateHookVars(vars);
51
+ return template.replace(/\{path\}/g, vars.path).replace(/\{slot\}/g, vars.slot != null ? String(vars.slot) : "");
52
+ }
53
+ export const DEFAULT_HOOK_TIMEOUT = 600;
54
+ export function resolveHookTimeout(hookName, config) {
55
+ if (hookName === "postCreate" && config?.postCreateTimeout !== undefined) {
56
+ return config.postCreateTimeout;
57
+ }
58
+ if (hookName === "preClean" && config?.preCleanTimeout !== undefined) {
59
+ return config.preCleanTimeout;
60
+ }
61
+ if (hookName === "postClean" && config?.postCleanTimeout !== undefined) {
62
+ return config.postCleanTimeout;
63
+ }
64
+ return config?.hookTimeout ?? DEFAULT_HOOK_TIMEOUT;
65
+ }
66
+ function withTimeout(promise, timeoutMs, command) {
67
+ let timer;
68
+ const timeoutPromise = new Promise((_, reject) => {
69
+ timer = setTimeout(() => reject(new Error(`Hook command timed out after ${timeoutMs / 1000}s: ${command}`)), timeoutMs);
70
+ });
71
+ return Promise.race([promise, timeoutPromise]).finally(() => {
72
+ if (timer !== undefined)
73
+ clearTimeout(timer);
74
+ });
75
+ }
76
+ export async function runHook(command, cwd, options) {
77
+ const timeoutMs = options?.timeout !== undefined ? options.timeout * 1000 : undefined;
78
+ if (options?.verbose) {
79
+ const resultPromise = exec("sh", ["-c", command]).cwd(cwd).nothrow();
80
+ const result = timeoutMs !== undefined ? await withTimeout(resultPromise, timeoutMs, command) : await resultPromise;
81
+ if (result.exitCode !== 0) {
82
+ throw new Error(`Hook command failed with exit code ${result.exitCode}: ${command}`);
83
+ }
84
+ return;
85
+ }
86
+ if (options?.onLine) {
87
+ const proc = spawn("sh", ["-c", command], {
88
+ cwd,
89
+ stdio: ["ignore", "pipe", "pipe"],
90
+ });
91
+ const readStream = (stream) => {
92
+ return new Promise((resolve, reject) => {
93
+ const decoder = new TextDecoder();
94
+ let buffer = "";
95
+ stream.on("data", (chunk) => {
96
+ buffer += decoder.decode(chunk, { stream: true });
97
+ const lines = buffer.split(/\r?\n/);
98
+ buffer = lines.pop() || "";
99
+ for (const line of lines) {
100
+ if (line.trim()) {
101
+ options.onLine?.(line);
102
+ }
103
+ }
104
+ });
105
+ stream.on("error", reject);
106
+ stream.on("end", () => {
107
+ // Flush remaining multibyte characters from the decoder
108
+ const remaining = decoder.decode();
109
+ if (remaining) {
110
+ buffer += remaining;
111
+ }
112
+ if (buffer.trim()) {
113
+ options.onLine?.(buffer);
114
+ }
115
+ resolve();
116
+ });
117
+ });
118
+ };
119
+ const streamAndExit = async () => {
120
+ const exitPromise = new Promise((resolve, reject) => {
121
+ proc.on("error", reject);
122
+ proc.on("close", (code) => resolve(code ?? 1));
123
+ });
124
+ const readPromises = [];
125
+ if (proc.stdout) {
126
+ readPromises.push(readStream(proc.stdout));
127
+ }
128
+ if (proc.stderr) {
129
+ readPromises.push(readStream(proc.stderr));
130
+ }
131
+ let exitCode;
132
+ try {
133
+ const results = await Promise.all([exitPromise, ...readPromises]);
134
+ exitCode = results[0];
135
+ }
136
+ catch (error) {
137
+ // Kill the process if a stream error occurs and process is still alive
138
+ try {
139
+ if (!proc.killed) {
140
+ proc.kill();
141
+ }
142
+ }
143
+ catch {
144
+ // Process may already be dead (ESRCH)
145
+ }
146
+ throw error;
147
+ }
148
+ if (exitCode !== 0) {
149
+ throw new Error(`Hook command failed with exit code ${exitCode}: ${command}`);
150
+ }
151
+ };
152
+ if (timeoutMs !== undefined) {
153
+ let timer;
154
+ try {
155
+ await Promise.race([
156
+ streamAndExit(),
157
+ new Promise((_, reject) => {
158
+ timer = setTimeout(() => {
159
+ proc.kill();
160
+ reject(new Error(`Hook command timed out after ${timeoutMs / 1000}s: ${command}`));
161
+ }, timeoutMs);
162
+ }),
163
+ ]);
164
+ }
165
+ finally {
166
+ if (timer !== undefined)
167
+ clearTimeout(timer);
168
+ }
169
+ }
170
+ else {
171
+ await streamAndExit();
172
+ }
173
+ return;
174
+ }
175
+ const resultPromise = exec("sh", ["-c", command]).cwd(cwd).nothrow().quiet();
176
+ const result = timeoutMs !== undefined ? await withTimeout(resultPromise, timeoutMs, command) : await resultPromise;
177
+ if (result.exitCode !== 0) {
178
+ throw new Error(`Hook command failed with exit code ${result.exitCode}: ${command}`);
179
+ }
180
+ }
181
+ //# sourceMappingURL=config.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.js","sourceRoot":"","sources":["../../../src/core/config.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,9 @@
1
+ /**
2
+ * Type guard: checks if an unknown error is a Node.js ErrnoException.
3
+ */
4
+ export declare function isNodeError(err: unknown): err is NodeJS.ErrnoException;
5
+ /**
6
+ * Safely extract an error message from an unknown error.
7
+ */
8
+ export declare function getErrorMessage(error: unknown): string;
9
+ //# sourceMappingURL=errors.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../../../src/core/errors.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,wBAAgB,WAAW,CAAC,GAAG,EAAE,OAAO,GAAG,GAAG,IAAI,MAAM,CAAC,cAAc,CAStE;AAED;;GAEG;AACH,wBAAgB,eAAe,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,CAEtD"}
@@ -0,0 +1,20 @@
1
+ /**
2
+ * Type guard: checks if an unknown error is a Node.js ErrnoException.
3
+ */
4
+ export function isNodeError(err) {
5
+ if (!(err instanceof Error)) {
6
+ return false;
7
+ }
8
+ if (!Object.prototype.hasOwnProperty.call(err, "code")) {
9
+ return false;
10
+ }
11
+ const code = err.code;
12
+ return typeof code === "string" || typeof code === "undefined";
13
+ }
14
+ /**
15
+ * Safely extract an error message from an unknown error.
16
+ */
17
+ export function getErrorMessage(error) {
18
+ return error instanceof Error ? error.message : String(error);
19
+ }
20
+ //# sourceMappingURL=errors.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"errors.js","sourceRoot":"","sources":["../../../src/core/errors.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,MAAM,UAAU,WAAW,CAAC,GAAY;IACtC,IAAI,CAAC,CAAC,GAAG,YAAY,KAAK,CAAC,EAAE,CAAC;QAC5B,OAAO,KAAK,CAAC;IACf,CAAC;IACD,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,cAAc,CAAC,IAAI,CAAC,GAAG,EAAE,MAAM,CAAC,EAAE,CAAC;QACvD,OAAO,KAAK,CAAC;IACf,CAAC;IACD,MAAM,IAAI,GAAI,GAA0B,CAAC,IAAI,CAAC;IAC9C,OAAO,OAAO,IAAI,KAAK,QAAQ,IAAI,OAAO,IAAI,KAAK,WAAW,CAAC;AACjE,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,eAAe,CAAC,KAAc;IAC5C,OAAO,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;AAChE,CAAC"}
@@ -0,0 +1,73 @@
1
+ /**
2
+ * Result of a command execution.
3
+ */
4
+ export interface ExecResult {
5
+ /** Process exit code (0 = success) */
6
+ readonly exitCode: number;
7
+ /** Captured stdout as a Buffer */
8
+ readonly stdout: Buffer;
9
+ /** Captured stderr as a Buffer */
10
+ readonly stderr: Buffer;
11
+ /** Returns stdout as a UTF-8 string */
12
+ text(): string;
13
+ }
14
+ /**
15
+ * Error thrown when a command exits with non-zero code (unless .nothrow() is used).
16
+ */
17
+ export declare class ExecError extends Error {
18
+ readonly exitCode: number;
19
+ readonly stdout: Buffer;
20
+ readonly stderr: Buffer;
21
+ constructor(message: string, exitCode: number, stdout: Buffer, stderr: Buffer);
22
+ text(): string;
23
+ }
24
+ /**
25
+ * Builder for constructing and executing a shell command.
26
+ * Supports chaining `.nothrow()`, `.quiet()`, and `.cwd()` before awaiting.
27
+ *
28
+ * Can be awaited directly (returns ExecResult) or call `.text()` for stdout string.
29
+ */
30
+ export declare class ExecBuilder implements PromiseLike<ExecResult> {
31
+ private readonly cmd;
32
+ private readonly args;
33
+ private _nothrow;
34
+ private _quiet;
35
+ private _cwd;
36
+ constructor(cmd: string, args: string[]);
37
+ /** Do not throw on non-zero exit code. */
38
+ nothrow(): ExecBuilder;
39
+ /** Suppress stdout/stderr from appearing in the terminal. */
40
+ quiet(): ExecBuilder;
41
+ /** Set the working directory for the command. */
42
+ cwd(dir: string): ExecBuilder;
43
+ /**
44
+ * Execute the command and return stdout as a UTF-8 string.
45
+ * Terminal output is suppressed (equivalent to .quiet().text()).
46
+ */
47
+ text(): Promise<string>;
48
+ then<TResult1 = ExecResult, TResult2 = never>(onfulfilled?: ((value: ExecResult) => TResult1 | PromiseLike<TResult1>) | null, onrejected?: ((reason: unknown) => TResult2 | PromiseLike<TResult2>) | null): Promise<TResult1 | TResult2>;
49
+ private execute;
50
+ }
51
+ /**
52
+ * Execute a command with the given arguments.
53
+ *
54
+ * Returns an ExecBuilder that can be:
55
+ * - Awaited directly: `const result = await exec("git", ["status"])`
56
+ * - Chained: `await exec("git", ["status"]).nothrow().quiet()`
57
+ * - Used for text: `const text = await exec("git", ["rev-parse", "--show-toplevel"]).text()`
58
+ *
59
+ * @example
60
+ * // Get stdout as text
61
+ * const branch = (await exec("git", ["branch", "--show-current"]).text()).trim();
62
+ *
63
+ * @example
64
+ * // Check exit code without throwing
65
+ * const result = await exec("git", ["status"]).nothrow().quiet();
66
+ * if (result.exitCode !== 0) { ... }
67
+ *
68
+ * @example
69
+ * // Run with working directory
70
+ * const result = await exec("sh", ["-c", command]).cwd("/tmp").nothrow();
71
+ */
72
+ export declare function exec(cmd: string, args: string[]): ExecBuilder;
73
+ //# sourceMappingURL=exec.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"exec.d.ts","sourceRoot":"","sources":["../../../src/core/exec.ts"],"names":[],"mappings":"AAEA;;GAEG;AACH,MAAM,WAAW,UAAU;IACzB,sCAAsC;IACtC,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,kCAAkC;IAClC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,kCAAkC;IAClC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,uCAAuC;IACvC,IAAI,IAAI,MAAM,CAAC;CAChB;AAED;;GAEG;AACH,qBAAa,SAAU,SAAQ,KAAK;IAClC,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;gBAEZ,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM;IAS7E,IAAI,IAAI,MAAM;CAGf;AAED;;;;;GAKG;AACH,qBAAa,WAAY,YAAW,WAAW,CAAC,UAAU,CAAC;IAMvD,OAAO,CAAC,QAAQ,CAAC,GAAG;IACpB,OAAO,CAAC,QAAQ,CAAC,IAAI;IANvB,OAAO,CAAC,QAAQ,CAAS;IACzB,OAAO,CAAC,MAAM,CAAS;IACvB,OAAO,CAAC,IAAI,CAAqB;gBAGd,GAAG,EAAE,MAAM,EACX,IAAI,EAAE,MAAM,EAAE;IAGjC,0CAA0C;IAC1C,OAAO,IAAI,WAAW;IAKtB,6DAA6D;IAC7D,KAAK,IAAI,WAAW;IAKpB,iDAAiD;IACjD,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG,WAAW;IAK7B;;;OAGG;IACG,IAAI,IAAI,OAAO,CAAC,MAAM,CAAC;IAM7B,IAAI,CAAC,QAAQ,GAAG,UAAU,EAAE,QAAQ,GAAG,KAAK,EAC1C,WAAW,CAAC,EAAE,CAAC,CAAC,KAAK,EAAE,UAAU,KAAK,QAAQ,GAAG,WAAW,CAAC,QAAQ,CAAC,CAAC,GAAG,IAAI,EAC9E,UAAU,CAAC,EAAE,CAAC,CAAC,MAAM,EAAE,OAAO,KAAK,QAAQ,GAAG,WAAW,CAAC,QAAQ,CAAC,CAAC,GAAG,IAAI,GAC1E,OAAO,CAAC,QAAQ,GAAG,QAAQ,CAAC;IAI/B,OAAO,CAAC,OAAO;CAgEhB;AAED;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,wBAAgB,IAAI,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,GAAG,WAAW,CAE7D"}
@@ -0,0 +1,138 @@
1
+ import { spawn } from "node:child_process";
2
+ /**
3
+ * Error thrown when a command exits with non-zero code (unless .nothrow() is used).
4
+ */
5
+ export class ExecError extends Error {
6
+ exitCode;
7
+ stdout;
8
+ stderr;
9
+ constructor(message, exitCode, stdout, stderr) {
10
+ super(message);
11
+ this.name = "ExecError";
12
+ this.exitCode = exitCode;
13
+ this.stdout = stdout;
14
+ this.stderr = stderr;
15
+ Object.setPrototypeOf(this, new.target.prototype);
16
+ }
17
+ text() {
18
+ return this.stdout.toString("utf-8");
19
+ }
20
+ }
21
+ /**
22
+ * Builder for constructing and executing a shell command.
23
+ * Supports chaining `.nothrow()`, `.quiet()`, and `.cwd()` before awaiting.
24
+ *
25
+ * Can be awaited directly (returns ExecResult) or call `.text()` for stdout string.
26
+ */
27
+ export class ExecBuilder {
28
+ cmd;
29
+ args;
30
+ _nothrow = false;
31
+ _quiet = false;
32
+ _cwd;
33
+ constructor(cmd, args) {
34
+ this.cmd = cmd;
35
+ this.args = args;
36
+ }
37
+ /** Do not throw on non-zero exit code. */
38
+ nothrow() {
39
+ this._nothrow = true;
40
+ return this;
41
+ }
42
+ /** Suppress stdout/stderr from appearing in the terminal. */
43
+ quiet() {
44
+ this._quiet = true;
45
+ return this;
46
+ }
47
+ /** Set the working directory for the command. */
48
+ cwd(dir) {
49
+ this._cwd = dir;
50
+ return this;
51
+ }
52
+ /**
53
+ * Execute the command and return stdout as a UTF-8 string.
54
+ * Terminal output is suppressed (equivalent to .quiet().text()).
55
+ */
56
+ async text() {
57
+ const result = await this.execute(true);
58
+ return result.text();
59
+ }
60
+ // biome-ignore lint/suspicious/noThenProperty: intentional PromiseLike implementation for builder pattern
61
+ then(onfulfilled, onrejected) {
62
+ return this.execute(this._quiet).then(onfulfilled, onrejected);
63
+ }
64
+ execute(suppressOutput) {
65
+ return new Promise((resolve, reject) => {
66
+ const proc = spawn(this.cmd, this.args, {
67
+ cwd: this._cwd,
68
+ stdio: ["pipe", "pipe", "pipe"],
69
+ });
70
+ const stdoutChunks = [];
71
+ const stderrChunks = [];
72
+ proc.stdout.on("data", (chunk) => {
73
+ stdoutChunks.push(chunk);
74
+ if (!suppressOutput) {
75
+ const canContinue = process.stdout.write(chunk);
76
+ if (!canContinue) {
77
+ proc.stdout.pause();
78
+ process.stdout.once("drain", () => proc.stdout.resume());
79
+ }
80
+ }
81
+ });
82
+ proc.stderr.on("data", (chunk) => {
83
+ stderrChunks.push(chunk);
84
+ if (!suppressOutput) {
85
+ const canContinue = process.stderr.write(chunk);
86
+ if (!canContinue) {
87
+ proc.stderr.pause();
88
+ process.stderr.once("drain", () => proc.stderr.resume());
89
+ }
90
+ }
91
+ });
92
+ proc.on("error", reject);
93
+ proc.on("close", (code) => {
94
+ const exitCode = code ?? 1;
95
+ const stdout = Buffer.concat(stdoutChunks);
96
+ const stderr = Buffer.concat(stderrChunks);
97
+ if (exitCode !== 0 && !this._nothrow) {
98
+ reject(new ExecError(`Command failed with exit code ${exitCode}: ${this.cmd} ${this.args.map((a) => JSON.stringify(a)).join(" ")}`, exitCode, stdout, stderr));
99
+ return;
100
+ }
101
+ resolve({
102
+ exitCode,
103
+ stdout,
104
+ stderr,
105
+ text() {
106
+ return stdout.toString("utf-8");
107
+ },
108
+ });
109
+ });
110
+ proc.stdin.end();
111
+ });
112
+ }
113
+ }
114
+ /**
115
+ * Execute a command with the given arguments.
116
+ *
117
+ * Returns an ExecBuilder that can be:
118
+ * - Awaited directly: `const result = await exec("git", ["status"])`
119
+ * - Chained: `await exec("git", ["status"]).nothrow().quiet()`
120
+ * - Used for text: `const text = await exec("git", ["rev-parse", "--show-toplevel"]).text()`
121
+ *
122
+ * @example
123
+ * // Get stdout as text
124
+ * const branch = (await exec("git", ["branch", "--show-current"]).text()).trim();
125
+ *
126
+ * @example
127
+ * // Check exit code without throwing
128
+ * const result = await exec("git", ["status"]).nothrow().quiet();
129
+ * if (result.exitCode !== 0) { ... }
130
+ *
131
+ * @example
132
+ * // Run with working directory
133
+ * const result = await exec("sh", ["-c", command]).cwd("/tmp").nothrow();
134
+ */
135
+ export function exec(cmd, args) {
136
+ return new ExecBuilder(cmd, args);
137
+ }
138
+ //# sourceMappingURL=exec.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"exec.js","sourceRoot":"","sources":["../../../src/core/exec.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,28 @@
1
+ import type { AheadBehind, CommitInfo, GitContext, ListWorktreesResult, ParsedWorktree, WorktreeInfo, WorktreeStatus } from "../types.ts";
2
+ export declare function getGitContext(): Promise<GitContext>;
3
+ export declare function getWorktreePath(repoRoot: string, repoName: string, branchName: string): string;
4
+ export declare function buildWorktreeCommand(branchName: string, worktreePath: string, baseBranch: string): string;
5
+ export declare function createWorktree(branchName: string, worktreePath: string, baseBranch: string): Promise<void>;
6
+ export declare function getMainBranch(): Promise<string>;
7
+ /**
8
+ * Pure function to parse git worktree list --porcelain output.
9
+ */
10
+ export declare function parseWorktreePorcelain(output: string, mainBranch: string): ParsedWorktree[];
11
+ export declare function listWorktrees(): Promise<ListWorktreesResult>;
12
+ export declare function isWorktreeDirty(worktreePath: string): Promise<boolean>;
13
+ export declare function isBranchMerged(branch: string, baseBranch?: string): Promise<boolean>;
14
+ export declare function isRemoteBranchDeleted(branch: string): Promise<boolean>;
15
+ export declare function removeWorktree(worktreePath: string, force?: boolean): Promise<void>;
16
+ export declare function findWorktreeByBranch(branchName: string): Promise<WorktreeInfo | null>;
17
+ export declare function deleteLocalBranch(branchName: string, force?: boolean): Promise<void>;
18
+ export declare function getLastCommit(worktreePath: string): Promise<CommitInfo | null>;
19
+ export declare function getAheadBehind(branch: string, baseBranch: string): Promise<AheadBehind | null>;
20
+ export declare function fetchAndPrune(): Promise<void>;
21
+ export declare function branchExists(branchName: string): Promise<boolean>;
22
+ /**
23
+ * Verify that a branch or ref exists (resolves to a valid commit).
24
+ * Uses `git rev-parse --verify` which works for both local and remote refs.
25
+ */
26
+ export declare function verifyBranchRef(ref: string): Promise<boolean>;
27
+ export declare function getWorktreeStatuses(worktrees: WorktreeInfo[], mainBranch: string): Promise<WorktreeStatus[]>;
28
+ //# sourceMappingURL=git.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"git.d.ts","sourceRoot":"","sources":["../../../src/core/git.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EACV,WAAW,EACX,UAAU,EACV,UAAU,EACV,mBAAmB,EACnB,cAAc,EACd,YAAY,EACZ,cAAc,EACf,MAAM,aAAa,CAAC;AAwBrB,wBAAsB,aAAa,IAAI,OAAO,CAAC,UAAU,CAAC,CAkCzD;AAED,wBAAgB,eAAe,CAAC,QAAQ,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,MAAM,CAE9F;AAED,wBAAgB,oBAAoB,CAAC,UAAU,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,MAAM,CAEzG;AAED,wBAAsB,cAAc,CAAC,UAAU,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAMhH;AAED,wBAAsB,aAAa,IAAI,OAAO,CAAC,MAAM,CAAC,CAmBrD;AAED;;GAEG;AACH,wBAAgB,sBAAsB,CAAC,MAAM,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,cAAc,EAAE,CAsC3F;AAED,wBAAsB,aAAa,IAAI,OAAO,CAAC,mBAAmB,CAAC,CAkBlE;AAED,wBAAsB,eAAe,CAAC,YAAY,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAM5E;AAED,wBAAsB,cAAc,CAAC,MAAM,EAAE,MAAM,EAAE,UAAU,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAe1F;AAED,wBAAsB,qBAAqB,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAO5E;AAED,wBAAsB,cAAc,CAAC,YAAY,EAAE,MAAM,EAAE,KAAK,UAAQ,GAAG,OAAO,CAAC,IAAI,CAAC,CAMvF;AAED,wBAAsB,oBAAoB,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,GAAG,IAAI,CAAC,CAG3F;AAED,wBAAsB,iBAAiB,CAAC,UAAU,EAAE,MAAM,EAAE,KAAK,UAAQ,GAAG,OAAO,CAAC,IAAI,CAAC,CAOxF;AAED,wBAAsB,aAAa,CAAC,YAAY,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,GAAG,IAAI,CAAC,CAcpF;AAED,wBAAsB,cAAc,CAAC,MAAM,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,GAAG,IAAI,CAAC,CAkBpG;AAED,wBAAsB,aAAa,IAAI,OAAO,CAAC,IAAI,CAAC,CAEnD;AAED,wBAAsB,YAAY,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAKvE;AAED;;;GAGG;AACH,wBAAsB,eAAe,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAGnE;AAED,wBAAsB,mBAAmB,CAAC,SAAS,EAAE,YAAY,EAAE,EAAE,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,cAAc,EAAE,CAAC,CA2DlH"}