git-codex 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 (66) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +249 -0
  3. package/dist/cli.d.ts +2 -0
  4. package/dist/cli.js +146 -0
  5. package/dist/cli.js.map +1 -0
  6. package/dist/commands/add.d.ts +20 -0
  7. package/dist/commands/add.js +250 -0
  8. package/dist/commands/add.js.map +1 -0
  9. package/dist/commands/list.d.ts +6 -0
  10. package/dist/commands/list.js +64 -0
  11. package/dist/commands/list.js.map +1 -0
  12. package/dist/commands/open.d.ts +7 -0
  13. package/dist/commands/open.js +41 -0
  14. package/dist/commands/open.js.map +1 -0
  15. package/dist/commands/prompt.d.ts +7 -0
  16. package/dist/commands/prompt.js +41 -0
  17. package/dist/commands/prompt.js.map +1 -0
  18. package/dist/commands/rm.d.ts +6 -0
  19. package/dist/commands/rm.js +99 -0
  20. package/dist/commands/rm.js.map +1 -0
  21. package/dist/lib/add-strategy.d.ts +9 -0
  22. package/dist/lib/add-strategy.js +18 -0
  23. package/dist/lib/add-strategy.js.map +1 -0
  24. package/dist/lib/clipboard.d.ts +1 -0
  25. package/dist/lib/clipboard.js +45 -0
  26. package/dist/lib/clipboard.js.map +1 -0
  27. package/dist/lib/config.d.ts +52 -0
  28. package/dist/lib/config.js +238 -0
  29. package/dist/lib/config.js.map +1 -0
  30. package/dist/lib/env-files.d.ts +18 -0
  31. package/dist/lib/env-files.js +196 -0
  32. package/dist/lib/env-files.js.map +1 -0
  33. package/dist/lib/env-scope.d.ts +3 -0
  34. package/dist/lib/env-scope.js +15 -0
  35. package/dist/lib/env-scope.js.map +1 -0
  36. package/dist/lib/errors.d.ts +2 -0
  37. package/dist/lib/errors.js +26 -0
  38. package/dist/lib/errors.js.map +1 -0
  39. package/dist/lib/fs-utils.d.ts +1 -0
  40. package/dist/lib/fs-utils.js +11 -0
  41. package/dist/lib/fs-utils.js.map +1 -0
  42. package/dist/lib/git.d.ts +20 -0
  43. package/dist/lib/git.js +82 -0
  44. package/dist/lib/git.js.map +1 -0
  45. package/dist/lib/output.d.ts +18 -0
  46. package/dist/lib/output.js +78 -0
  47. package/dist/lib/output.js.map +1 -0
  48. package/dist/lib/prompt.d.ts +8 -0
  49. package/dist/lib/prompt.js +14 -0
  50. package/dist/lib/prompt.js.map +1 -0
  51. package/dist/lib/repo.d.ts +8 -0
  52. package/dist/lib/repo.js +24 -0
  53. package/dist/lib/repo.js.map +1 -0
  54. package/dist/lib/task-utils.d.ts +3 -0
  55. package/dist/lib/task-utils.js +24 -0
  56. package/dist/lib/task-utils.js.map +1 -0
  57. package/dist/lib/template.d.ts +22 -0
  58. package/dist/lib/template.js +111 -0
  59. package/dist/lib/template.js.map +1 -0
  60. package/dist/lib/vscode.d.ts +1 -0
  61. package/dist/lib/vscode.js +8 -0
  62. package/dist/lib/vscode.js.map +1 -0
  63. package/dist/lib/worktrees.d.ts +11 -0
  64. package/dist/lib/worktrees.js +59 -0
  65. package/dist/lib/worktrees.js.map +1 -0
  66. package/package.json +51 -0
@@ -0,0 +1,250 @@
1
+ import { readFile, rm } from "node:fs/promises";
2
+ import path from "node:path";
3
+ import { buildWorktreeAddArgs } from "../lib/add-strategy.js";
4
+ import { resolveAddConfig } from "../lib/config.js";
5
+ import { copyEnvLikeFiles, parseEnvGlobs } from "../lib/env-files.js";
6
+ import { isMissingExecutableError, toErrorMessage } from "../lib/errors.js";
7
+ import { pathExists } from "../lib/fs-utils.js";
8
+ import { doesLocalBranchExist, fetchRemoteTrackingBranch, getRemoteBranchState, runGitCapture, runGitStatus, runGitStreamWithOptions, } from "../lib/git.js";
9
+ import { createOutput } from "../lib/output.js";
10
+ import { resolveRepoContext, resolveWorktreePath } from "../lib/repo.js";
11
+ import { buildBranchName, toTaskSlug } from "../lib/task-utils.js";
12
+ import { normalizeTemplateType, writeTaskTemplate } from "../lib/template.js";
13
+ import { openInVSCode } from "../lib/vscode.js";
14
+ import { parseWorktreeListPorcelain, stripHeadsRef, } from "../lib/worktrees.js";
15
+ export async function runAddCommand(task, options, output = createOutput()) {
16
+ const repoContext = await resolveRepoContext();
17
+ const resolved = await resolveAddConfig(repoContext.repoRoot, options);
18
+ const taskSlug = toTaskSlug(task);
19
+ const branchName = buildBranchName(resolved.branchPrefix, taskSlug);
20
+ const worktreePath = resolveWorktreePath(repoContext.repoRoot, repoContext.repoName, taskSlug, resolved.dir);
21
+ const reuse = Boolean(options.reuse);
22
+ const rmFirst = Boolean(options.rmFirst);
23
+ if (reuse && rmFirst) {
24
+ throw new Error("Cannot use --reuse and --rm-first together.");
25
+ }
26
+ const worktreeExists = await pathExists(worktreePath);
27
+ let reusedExistingWorktree = false;
28
+ if (!worktreeExists && reuse) {
29
+ throw new Error(`Cannot use --reuse: worktree path does not exist: ${worktreePath}`);
30
+ }
31
+ if (worktreeExists) {
32
+ if (rmFirst) {
33
+ await removeExistingWorktreeForRecreate(repoContext.repoRoot, worktreePath, output);
34
+ }
35
+ else if (reuse) {
36
+ await assertReusableWorktreePath(repoContext.repoRoot, worktreePath, branchName);
37
+ reusedExistingWorktree = true;
38
+ output.info(`Reusing existing worktree at ${worktreePath}`);
39
+ }
40
+ else {
41
+ throw new Error([
42
+ `Worktree path already exists: ${worktreePath}`,
43
+ "Use --reuse to continue with the existing worktree or --rm-first to recreate it.",
44
+ ].join("\n"));
45
+ }
46
+ }
47
+ if (!reusedExistingWorktree) {
48
+ if (resolved.fetch) {
49
+ output.info("Fetching latest refs...");
50
+ await runGitStreamWithOptions(["fetch"], repoContext.repoRoot, {
51
+ quiet: output.quiet || output.json,
52
+ });
53
+ }
54
+ const remoteName = inferRemoteNameFromRef(resolved.base);
55
+ const branchExists = await doesLocalBranchExist(repoContext.repoRoot, branchName);
56
+ const remoteState = branchExists
57
+ ? {
58
+ trackingRefExists: false,
59
+ exists: false,
60
+ }
61
+ : await getRemoteBranchState(repoContext.repoRoot, branchName, remoteName);
62
+ if (remoteState.exists && !remoteState.trackingRefExists) {
63
+ output.info(`Fetching remote branch reference ${remoteName}/${branchName}...`);
64
+ await fetchRemoteTrackingBranch(repoContext.repoRoot, branchName, remoteName, {
65
+ quiet: output.quiet || output.json,
66
+ });
67
+ }
68
+ const worktreeAddArgs = buildWorktreeAddArgs({
69
+ branchName,
70
+ worktreePath,
71
+ baseRef: resolved.base,
72
+ localBranchExists: branchExists,
73
+ remoteBranchExists: remoteState.exists,
74
+ remoteName,
75
+ });
76
+ await runGitStreamWithOptions(worktreeAddArgs, repoContext.repoRoot, {
77
+ quiet: output.quiet || output.json,
78
+ });
79
+ }
80
+ if (resolved.copyEnv) {
81
+ const envGlobs = parseEnvGlobs(resolved.envGlobs);
82
+ const copyResult = await copyEnvLikeFiles({
83
+ repoRoot: repoContext.repoRoot,
84
+ worktreePath,
85
+ globs: envGlobs,
86
+ scope: resolved.envScope,
87
+ overwrite: resolved.overwriteEnv,
88
+ });
89
+ if (copyResult.matched.length === 0) {
90
+ output.info(`No env-like files matched copy patterns for scope "${copyResult.scope}".`);
91
+ }
92
+ else {
93
+ output.info(`Env copy scope "${copyResult.scope}": matched ${copyResult.matched.length}, copied ${copyResult.copied.length}, skipped ${copyResult.skipped.length}.`);
94
+ for (const copiedFile of copyResult.copied) {
95
+ output.info(`Copied ${copiedFile}`);
96
+ }
97
+ for (const skippedFile of copyResult.skipped) {
98
+ output.info(`Skipped ${skippedFile} (already exists)`);
99
+ }
100
+ }
101
+ }
102
+ if (resolved.template) {
103
+ const templateType = normalizeTemplateType(resolved.templateType);
104
+ const templateSource = await loadOptionalTemplateSource(repoContext.repoRoot, resolved.templateFile);
105
+ const templateResult = await writeTaskTemplate({
106
+ worktreePath,
107
+ templateType,
108
+ variables: {
109
+ task,
110
+ taskSlug,
111
+ branch: branchName,
112
+ worktreePath,
113
+ },
114
+ templateSource,
115
+ overwrite: resolved.overwriteTemplate,
116
+ });
117
+ if (templateResult.created) {
118
+ output.info(`Generated ${templateResult.templatePath}`);
119
+ }
120
+ else {
121
+ output.info(`Skipped ${templateResult.templatePath} (already exists; use --overwrite-template to replace)`);
122
+ }
123
+ output.event("template.generated", {
124
+ path: templateResult.templatePath,
125
+ created: templateResult.created,
126
+ overwritten: templateResult.overwritten,
127
+ templateType,
128
+ });
129
+ }
130
+ if (resolved.open) {
131
+ try {
132
+ await openInVSCode(worktreePath);
133
+ output.info(`Opened VS Code at ${worktreePath}`);
134
+ }
135
+ catch (error) {
136
+ if (isMissingExecutableError(error)) {
137
+ output.warn("VS Code CLI `code` was not found in PATH. Install it from VS Code command palette: 'Shell Command: Install code command in PATH'.");
138
+ }
139
+ else {
140
+ throw error;
141
+ }
142
+ }
143
+ }
144
+ output.info(`Worktree ready at ${worktreePath}`);
145
+ output.info(`Branch: ${branchName}`);
146
+ output.event(reusedExistingWorktree ? "worktree.reused" : "worktree.created", {
147
+ path: worktreePath,
148
+ branch: branchName,
149
+ reused: reusedExistingWorktree,
150
+ });
151
+ }
152
+ function inferRemoteNameFromRef(ref) {
153
+ const trimmed = ref.trim();
154
+ if (!trimmed) {
155
+ return "origin";
156
+ }
157
+ if (trimmed.startsWith("refs/remotes/")) {
158
+ const parts = trimmed.split("/");
159
+ return parts[2] || "origin";
160
+ }
161
+ const slashIndex = trimmed.indexOf("/");
162
+ if (slashIndex > 0) {
163
+ return trimmed.slice(0, slashIndex);
164
+ }
165
+ return "origin";
166
+ }
167
+ async function loadOptionalTemplateSource(repoRoot, templateFile) {
168
+ if (!templateFile) {
169
+ return undefined;
170
+ }
171
+ const resolvedTemplatePath = path.isAbsolute(templateFile)
172
+ ? templateFile
173
+ : path.resolve(repoRoot, templateFile);
174
+ if (!(await pathExists(resolvedTemplatePath))) {
175
+ throw new Error(`Template file not found: ${resolvedTemplatePath}`);
176
+ }
177
+ return readFile(resolvedTemplatePath, "utf8");
178
+ }
179
+ async function assertReusableWorktreePath(repoRoot, worktreePath, expectedBranch) {
180
+ const matchingEntry = await findWorktreeByPath(repoRoot, worktreePath);
181
+ if (!matchingEntry) {
182
+ throw new Error([
183
+ `Cannot reuse ${worktreePath}: path exists, but it is not registered as a worktree in this repository.`,
184
+ "Use --rm-first to remove it and recreate the worktree.",
185
+ ].join("\n"));
186
+ }
187
+ const actualBranch = matchingEntry.branch
188
+ ? stripHeadsRef(matchingEntry.branch)
189
+ : undefined;
190
+ if (!actualBranch) {
191
+ throw new Error([
192
+ `Cannot reuse ${worktreePath}: worktree is detached.`,
193
+ `Expected branch: ${expectedBranch}`,
194
+ ].join("\n"));
195
+ }
196
+ if (actualBranch !== expectedBranch) {
197
+ throw new Error([
198
+ `Cannot reuse ${worktreePath}: branch mismatch.`,
199
+ `Expected branch: ${expectedBranch}`,
200
+ `Actual branch: ${actualBranch}`,
201
+ "Use --rm-first to recreate it for this task.",
202
+ ].join("\n"));
203
+ }
204
+ }
205
+ async function removeExistingWorktreeForRecreate(repoRoot, worktreePath, output) {
206
+ output.info(`Removing existing worktree at ${worktreePath} before recreate...`);
207
+ const removeResult = await runGitStatus(["worktree", "remove", "--force", worktreePath], repoRoot);
208
+ const removeError = mergeGitErrorOutput(removeResult.stderr, removeResult.stdout);
209
+ if (removeResult.exitCode !== 0 &&
210
+ !isMissingWorktreeMappingError(removeError)) {
211
+ throw new Error([
212
+ `Failed to remove existing worktree mapping for ${worktreePath}`,
213
+ removeError || "Unknown git error",
214
+ ].join("\n"));
215
+ }
216
+ try {
217
+ await rm(worktreePath, {
218
+ recursive: true,
219
+ force: true,
220
+ maxRetries: 5,
221
+ retryDelay: 150,
222
+ });
223
+ }
224
+ catch (error) {
225
+ throw new Error([
226
+ `Failed to remove existing worktree directory: ${worktreePath}`,
227
+ toErrorMessage(error),
228
+ ].join("\n"));
229
+ }
230
+ await runGitStreamWithOptions(["worktree", "prune"], repoRoot, {
231
+ quiet: output.quiet || output.json,
232
+ });
233
+ }
234
+ async function findWorktreeByPath(repoRoot, worktreePath) {
235
+ const listOutput = await runGitCapture(["worktree", "list", "--porcelain"], repoRoot);
236
+ const entries = parseWorktreeListPorcelain(listOutput);
237
+ const normalizedTarget = normalizePathForComparison(worktreePath);
238
+ return entries.find((entry) => normalizePathForComparison(entry.worktree) === normalizedTarget);
239
+ }
240
+ function normalizePathForComparison(targetPath) {
241
+ const normalized = path.normalize(path.resolve(targetPath));
242
+ return process.platform === "win32" ? normalized.toLowerCase() : normalized;
243
+ }
244
+ function mergeGitErrorOutput(stderr, stdout) {
245
+ return [stderr, stdout].filter(Boolean).join("\n").trim();
246
+ }
247
+ function isMissingWorktreeMappingError(message) {
248
+ return /is not a working tree|is not registered|no such file|does not exist/i.test(message);
249
+ }
250
+ //# sourceMappingURL=add.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"add.js","sourceRoot":"","sources":["../../src/commands/add.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,6 @@
1
+ import { type Output } from "../lib/output.js";
2
+ export interface ListCommandOptions {
3
+ pretty?: boolean;
4
+ branchPrefix?: string;
5
+ }
6
+ export declare function runListCommand(options: ListCommandOptions, output?: Output): Promise<void>;
@@ -0,0 +1,64 @@
1
+ import { resolveListConfig } from "../lib/config.js";
2
+ import { runGitCapture } from "../lib/git.js";
3
+ import { createOutput } from "../lib/output.js";
4
+ import { resolveRepoContext } from "../lib/repo.js";
5
+ import { parseWorktreeListPorcelain, stripHeadsRef } from "../lib/worktrees.js";
6
+ export async function runListCommand(options, output = createOutput()) {
7
+ const repoContext = await resolveRepoContext();
8
+ const resolved = await resolveListConfig(repoContext.repoRoot, options);
9
+ if (!resolved.pretty && !output.json) {
10
+ const text = await runGitCapture(["worktree", "list"], repoContext.repoRoot);
11
+ output.print(text);
12
+ return;
13
+ }
14
+ const listOutput = await runGitCapture(["worktree", "list", "--porcelain"], repoContext.repoRoot);
15
+ const entries = parseWorktreeListPorcelain(listOutput);
16
+ if (output.json) {
17
+ const normalizedPrefix = normalizePrefix(resolved.branchPrefix);
18
+ const filteredEntries = resolved.pretty
19
+ ? entries.filter((entry) => entry.branch
20
+ ? entry.branch.startsWith(`refs/heads/${normalizedPrefix}`)
21
+ : false)
22
+ : entries;
23
+ output.event("worktree.list", {
24
+ pretty: resolved.pretty,
25
+ branchPrefix: normalizedPrefix,
26
+ entries: filteredEntries.map((entry) => ({
27
+ path: entry.worktree,
28
+ branch: entry.branch ? stripHeadsRef(entry.branch) : undefined,
29
+ head: entry.head,
30
+ })),
31
+ });
32
+ return;
33
+ }
34
+ const normalizedPrefix = normalizePrefix(resolved.branchPrefix);
35
+ const targetRefPrefix = `refs/heads/${normalizedPrefix}`;
36
+ const filtered = entries.filter((entry) => entry.branch ? entry.branch.startsWith(targetRefPrefix) : false);
37
+ if (filtered.length === 0) {
38
+ output.info(`No worktrees found for branch prefix "${normalizedPrefix}".`);
39
+ return;
40
+ }
41
+ const rows = filtered.map((entry) => ({
42
+ path: entry.worktree,
43
+ branch: stripHeadsRef(entry.branch ?? "(detached)"),
44
+ head: (entry.head ?? "").slice(0, 7),
45
+ }));
46
+ const pathWidth = Math.max("Path".length, ...rows.map((row) => row.path.length));
47
+ const branchWidth = Math.max("Branch".length, ...rows.map((row) => row.branch.length));
48
+ output.print(`${padRight("Path", pathWidth)} ${padRight("Branch", branchWidth)} HEAD`);
49
+ output.print(`${"-".repeat(pathWidth)} ${"-".repeat(branchWidth)} -------`);
50
+ for (const row of rows) {
51
+ output.print(`${padRight(row.path, pathWidth)} ${padRight(row.branch, branchWidth)} ${row.head}`);
52
+ }
53
+ }
54
+ function padRight(value, width) {
55
+ return value.padEnd(width, " ");
56
+ }
57
+ function normalizePrefix(prefix) {
58
+ const trimmed = prefix.trim();
59
+ if (!trimmed) {
60
+ return "";
61
+ }
62
+ return trimmed.endsWith("/") ? trimmed : `${trimmed}/`;
63
+ }
64
+ //# sourceMappingURL=list.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"list.js","sourceRoot":"","sources":["../../src/commands/list.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AACrD,OAAO,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AAC9C,OAAO,EAAE,YAAY,EAAe,MAAM,kBAAkB,CAAC;AAC7D,OAAO,EAAE,kBAAkB,EAAE,MAAM,gBAAgB,CAAC;AACpD,OAAO,EAAE,0BAA0B,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAOhF,MAAM,CAAC,KAAK,UAAU,cAAc,CAClC,OAA2B,EAC3B,SAAiB,YAAY,EAAE;IAE/B,MAAM,WAAW,GAAG,MAAM,kBAAkB,EAAE,CAAC;IAC/C,MAAM,QAAQ,GAAG,MAAM,iBAAiB,CAAC,WAAW,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;IAExE,IAAI,CAAC,QAAQ,CAAC,MAAM,IAAI,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC;QACrC,MAAM,IAAI,GAAG,MAAM,aAAa,CAC9B,CAAC,UAAU,EAAE,MAAM,CAAC,EACpB,WAAW,CAAC,QAAQ,CACrB,CAAC;QACF,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;QACnB,OAAO;IACT,CAAC;IAED,MAAM,UAAU,GAAG,MAAM,aAAa,CACpC,CAAC,UAAU,EAAE,MAAM,EAAE,aAAa,CAAC,EACnC,WAAW,CAAC,QAAQ,CACrB,CAAC;IACF,MAAM,OAAO,GAAG,0BAA0B,CAAC,UAAU,CAAC,CAAC;IACvD,IAAI,MAAM,CAAC,IAAI,EAAE,CAAC;QAChB,MAAM,gBAAgB,GAAG,eAAe,CAAC,QAAQ,CAAC,YAAY,CAAC,CAAC;QAChE,MAAM,eAAe,GAAG,QAAQ,CAAC,MAAM;YACrC,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,KAAK,EAAE,EAAE,CACvB,KAAK,CAAC,MAAM;gBACV,CAAC,CAAC,KAAK,CAAC,MAAM,CAAC,UAAU,CAAC,cAAc,gBAAgB,EAAE,CAAC;gBAC3D,CAAC,CAAC,KAAK,CACV;YACH,CAAC,CAAC,OAAO,CAAC;QACZ,MAAM,CAAC,KAAK,CAAC,eAAe,EAAE;YAC5B,MAAM,EAAE,QAAQ,CAAC,MAAM;YACvB,YAAY,EAAE,gBAAgB;YAC9B,OAAO,EAAE,eAAe,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;gBACvC,IAAI,EAAE,KAAK,CAAC,QAAQ;gBACpB,MAAM,EAAE,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,aAAa,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,SAAS;gBAC9D,IAAI,EAAE,KAAK,CAAC,IAAI;aACjB,CAAC,CAAC;SACJ,CAAC,CAAC;QACH,OAAO;IACT,CAAC;IAED,MAAM,gBAAgB,GAAG,eAAe,CAAC,QAAQ,CAAC,YAAY,CAAC,CAAC;IAChE,MAAM,eAAe,GAAG,cAAc,gBAAgB,EAAE,CAAC;IACzD,MAAM,QAAQ,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC,KAAK,EAAE,EAAE,CACxC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC,MAAM,CAAC,UAAU,CAAC,eAAe,CAAC,CAAC,CAAC,CAAC,KAAK,CAChE,CAAC;IAEF,IAAI,QAAQ,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAC1B,MAAM,CAAC,IAAI,CAAC,yCAAyC,gBAAgB,IAAI,CAAC,CAAC;QAC3E,OAAO;IACT,CAAC;IAED,MAAM,IAAI,GAAG,QAAQ,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;QACpC,IAAI,EAAE,KAAK,CAAC,QAAQ;QACpB,MAAM,EAAE,aAAa,CAAC,KAAK,CAAC,MAAM,IAAI,YAAY,CAAC;QACnD,IAAI,EAAE,CAAC,KAAK,CAAC,IAAI,IAAI,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC;KACrC,CAAC,CAAC,CAAC;IAEJ,MAAM,SAAS,GAAG,IAAI,CAAC,GAAG,CACxB,MAAM,CAAC,MAAM,EACb,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,CAAC,IAAI,CAAC,MAAM,CAAC,CACtC,CAAC;IACF,MAAM,WAAW,GAAG,IAAI,CAAC,GAAG,CAC1B,QAAQ,CAAC,MAAM,EACf,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,CAAC,MAAM,CAAC,MAAM,CAAC,CACxC,CAAC;IAEF,MAAM,CAAC,KAAK,CACV,GAAG,QAAQ,CAAC,MAAM,EAAE,SAAS,CAAC,KAAK,QAAQ,CAAC,QAAQ,EAAE,WAAW,CAAC,QAAQ,CAC3E,CAAC;IACF,MAAM,CAAC,KAAK,CAAC,GAAG,GAAG,CAAC,MAAM,CAAC,SAAS,CAAC,KAAK,GAAG,CAAC,MAAM,CAAC,WAAW,CAAC,WAAW,CAAC,CAAC;IAE9E,KAAK,MAAM,GAAG,IAAI,IAAI,EAAE,CAAC;QACvB,MAAM,CAAC,KAAK,CACV,GAAG,QAAQ,CAAC,GAAG,CAAC,IAAI,EAAE,SAAS,CAAC,KAAK,QAAQ,CAAC,GAAG,CAAC,MAAM,EAAE,WAAW,CAAC,KAAK,GAAG,CAAC,IAAI,EAAE,CACtF,CAAC;IACJ,CAAC;AACH,CAAC;AAED,SAAS,QAAQ,CAAC,KAAa,EAAE,KAAa;IAC5C,OAAO,KAAK,CAAC,MAAM,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC;AAClC,CAAC;AAED,SAAS,eAAe,CAAC,MAAc;IACrC,MAAM,OAAO,GAAG,MAAM,CAAC,IAAI,EAAE,CAAC;IAC9B,IAAI,CAAC,OAAO,EAAE,CAAC;QACb,OAAO,EAAE,CAAC;IACZ,CAAC;IAED,OAAO,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,OAAO,GAAG,CAAC;AACzD,CAAC"}
@@ -0,0 +1,7 @@
1
+ import { type Output } from "../lib/output.js";
2
+ export interface OpenCommandOptions {
3
+ dir?: string;
4
+ branchPrefix?: string;
5
+ open?: boolean;
6
+ }
7
+ export declare function runOpenCommand(task: string, options: OpenCommandOptions, output?: Output): Promise<void>;
@@ -0,0 +1,41 @@
1
+ import { resolveOpenConfig } from "../lib/config.js";
2
+ import { isMissingExecutableError } from "../lib/errors.js";
3
+ import { pathExists } from "../lib/fs-utils.js";
4
+ import { createOutput } from "../lib/output.js";
5
+ import { resolveRepoContext, resolveWorktreePath } from "../lib/repo.js";
6
+ import { buildBranchName, toTaskSlug } from "../lib/task-utils.js";
7
+ import { openInVSCode } from "../lib/vscode.js";
8
+ export async function runOpenCommand(task, options, output = createOutput()) {
9
+ const repoContext = await resolveRepoContext();
10
+ const resolved = await resolveOpenConfig(repoContext.repoRoot, options);
11
+ const taskSlug = toTaskSlug(task);
12
+ const branchName = buildBranchName(resolved.branchPrefix, taskSlug);
13
+ const worktreePath = resolveWorktreePath(repoContext.repoRoot, repoContext.repoName, taskSlug, resolved.dir);
14
+ if (!(await pathExists(worktreePath))) {
15
+ throw new Error(`Worktree does not exist: ${worktreePath}`);
16
+ }
17
+ let opened = false;
18
+ if (resolved.open) {
19
+ try {
20
+ await openInVSCode(worktreePath);
21
+ opened = true;
22
+ output.info(`Opened VS Code at ${worktreePath}`);
23
+ }
24
+ catch (error) {
25
+ if (isMissingExecutableError(error)) {
26
+ output.warn("VS Code CLI `code` was not found in PATH. Install it from VS Code command palette: 'Shell Command: Install code command in PATH'.");
27
+ }
28
+ else {
29
+ throw error;
30
+ }
31
+ }
32
+ }
33
+ output.info(`Worktree path: ${worktreePath}`);
34
+ output.info(`Expected branch: ${branchName}`);
35
+ output.event("worktree.opened", {
36
+ path: worktreePath,
37
+ branch: branchName,
38
+ opened,
39
+ });
40
+ }
41
+ //# sourceMappingURL=open.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"open.js","sourceRoot":"","sources":["../../src/commands/open.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AACrD,OAAO,EAAE,wBAAwB,EAAE,MAAM,kBAAkB,CAAC;AAC5D,OAAO,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AAChD,OAAO,EAAE,YAAY,EAAe,MAAM,kBAAkB,CAAC;AAC7D,OAAO,EAAE,kBAAkB,EAAE,mBAAmB,EAAE,MAAM,gBAAgB,CAAC;AACzE,OAAO,EAAE,eAAe,EAAE,UAAU,EAAE,MAAM,sBAAsB,CAAC;AACnE,OAAO,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC;AAQhD,MAAM,CAAC,KAAK,UAAU,cAAc,CAClC,IAAY,EACZ,OAA2B,EAC3B,SAAiB,YAAY,EAAE;IAE/B,MAAM,WAAW,GAAG,MAAM,kBAAkB,EAAE,CAAC;IAC/C,MAAM,QAAQ,GAAG,MAAM,iBAAiB,CAAC,WAAW,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;IACxE,MAAM,QAAQ,GAAG,UAAU,CAAC,IAAI,CAAC,CAAC;IAClC,MAAM,UAAU,GAAG,eAAe,CAAC,QAAQ,CAAC,YAAY,EAAE,QAAQ,CAAC,CAAC;IACpE,MAAM,YAAY,GAAG,mBAAmB,CACtC,WAAW,CAAC,QAAQ,EACpB,WAAW,CAAC,QAAQ,EACpB,QAAQ,EACR,QAAQ,CAAC,GAAG,CACb,CAAC;IAEF,IAAI,CAAC,CAAC,MAAM,UAAU,CAAC,YAAY,CAAC,CAAC,EAAE,CAAC;QACtC,MAAM,IAAI,KAAK,CAAC,4BAA4B,YAAY,EAAE,CAAC,CAAC;IAC9D,CAAC;IAED,IAAI,MAAM,GAAG,KAAK,CAAC;IAEnB,IAAI,QAAQ,CAAC,IAAI,EAAE,CAAC;QAClB,IAAI,CAAC;YACH,MAAM,YAAY,CAAC,YAAY,CAAC,CAAC;YACjC,MAAM,GAAG,IAAI,CAAC;YACd,MAAM,CAAC,IAAI,CAAC,qBAAqB,YAAY,EAAE,CAAC,CAAC;QACnD,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,IAAI,wBAAwB,CAAC,KAAK,CAAC,EAAE,CAAC;gBACpC,MAAM,CAAC,IAAI,CACT,mIAAmI,CACpI,CAAC;YACJ,CAAC;iBAAM,CAAC;gBACN,MAAM,KAAK,CAAC;YACd,CAAC;QACH,CAAC;IACH,CAAC;IAED,MAAM,CAAC,IAAI,CAAC,kBAAkB,YAAY,EAAE,CAAC,CAAC;IAC9C,MAAM,CAAC,IAAI,CAAC,oBAAoB,UAAU,EAAE,CAAC,CAAC;IAC9C,MAAM,CAAC,KAAK,CAAC,iBAAiB,EAAE;QAC9B,IAAI,EAAE,YAAY;QAClB,MAAM,EAAE,UAAU;QAClB,MAAM;KACP,CAAC,CAAC;AACL,CAAC"}
@@ -0,0 +1,7 @@
1
+ import { type Output } from "../lib/output.js";
2
+ export interface PromptCommandOptions {
3
+ dir?: string;
4
+ branchPrefix?: string;
5
+ copy?: boolean;
6
+ }
7
+ export declare function runPromptCommand(task: string, message: string, options: PromptCommandOptions, output?: Output): Promise<void>;
@@ -0,0 +1,41 @@
1
+ import { copyToClipboard } from "../lib/clipboard.js";
2
+ import { resolvePromptConfig } from "../lib/config.js";
3
+ import { createOutput } from "../lib/output.js";
4
+ import { buildTaskPrompt } from "../lib/prompt.js";
5
+ import { resolveRepoContext, resolveWorktreePath } from "../lib/repo.js";
6
+ import { buildBranchName, toTaskSlug } from "../lib/task-utils.js";
7
+ export async function runPromptCommand(task, message, options, output = createOutput()) {
8
+ const repoContext = await resolveRepoContext();
9
+ const resolved = await resolvePromptConfig(repoContext.repoRoot, options);
10
+ const taskSlug = toTaskSlug(task);
11
+ const branchName = buildBranchName(resolved.branchPrefix, taskSlug);
12
+ const worktreePath = resolveWorktreePath(repoContext.repoRoot, repoContext.repoName, taskSlug, resolved.dir);
13
+ const promptText = buildTaskPrompt({
14
+ task,
15
+ taskSlug,
16
+ branch: branchName,
17
+ worktreePath,
18
+ message,
19
+ });
20
+ let copied = false;
21
+ if (options.copy) {
22
+ await copyToClipboard(promptText);
23
+ copied = true;
24
+ }
25
+ if (output.json) {
26
+ output.event("prompt.generated", {
27
+ task,
28
+ taskSlug,
29
+ branch: branchName,
30
+ worktreePath,
31
+ copied,
32
+ prompt: promptText,
33
+ });
34
+ return;
35
+ }
36
+ output.print(promptText);
37
+ if (copied) {
38
+ output.info("Prompt copied to clipboard.");
39
+ }
40
+ }
41
+ //# sourceMappingURL=prompt.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"prompt.js","sourceRoot":"","sources":["../../src/commands/prompt.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,qBAAqB,CAAC;AACtD,OAAO,EAAE,mBAAmB,EAAE,MAAM,kBAAkB,CAAC;AACvD,OAAO,EAAE,YAAY,EAAe,MAAM,kBAAkB,CAAC;AAC7D,OAAO,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAC;AACnD,OAAO,EAAE,kBAAkB,EAAE,mBAAmB,EAAE,MAAM,gBAAgB,CAAC;AACzE,OAAO,EAAE,eAAe,EAAE,UAAU,EAAE,MAAM,sBAAsB,CAAC;AAQnE,MAAM,CAAC,KAAK,UAAU,gBAAgB,CACpC,IAAY,EACZ,OAAe,EACf,OAA6B,EAC7B,SAAiB,YAAY,EAAE;IAE/B,MAAM,WAAW,GAAG,MAAM,kBAAkB,EAAE,CAAC;IAC/C,MAAM,QAAQ,GAAG,MAAM,mBAAmB,CAAC,WAAW,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;IAC1E,MAAM,QAAQ,GAAG,UAAU,CAAC,IAAI,CAAC,CAAC;IAClC,MAAM,UAAU,GAAG,eAAe,CAAC,QAAQ,CAAC,YAAY,EAAE,QAAQ,CAAC,CAAC;IACpE,MAAM,YAAY,GAAG,mBAAmB,CACtC,WAAW,CAAC,QAAQ,EACpB,WAAW,CAAC,QAAQ,EACpB,QAAQ,EACR,QAAQ,CAAC,GAAG,CACb,CAAC;IACF,MAAM,UAAU,GAAG,eAAe,CAAC;QACjC,IAAI;QACJ,QAAQ;QACR,MAAM,EAAE,UAAU;QAClB,YAAY;QACZ,OAAO;KACR,CAAC,CAAC;IAEH,IAAI,MAAM,GAAG,KAAK,CAAC;IACnB,IAAI,OAAO,CAAC,IAAI,EAAE,CAAC;QACjB,MAAM,eAAe,CAAC,UAAU,CAAC,CAAC;QAClC,MAAM,GAAG,IAAI,CAAC;IAChB,CAAC;IAED,IAAI,MAAM,CAAC,IAAI,EAAE,CAAC;QAChB,MAAM,CAAC,KAAK,CAAC,kBAAkB,EAAE;YAC/B,IAAI;YACJ,QAAQ;YACR,MAAM,EAAE,UAAU;YAClB,YAAY;YACZ,MAAM;YACN,MAAM,EAAE,UAAU;SACnB,CAAC,CAAC;QACH,OAAO;IACT,CAAC;IAED,MAAM,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC;IACzB,IAAI,MAAM,EAAE,CAAC;QACX,MAAM,CAAC,IAAI,CAAC,6BAA6B,CAAC,CAAC;IAC7C,CAAC;AACH,CAAC"}
@@ -0,0 +1,6 @@
1
+ import { type Output } from "../lib/output.js";
2
+ export interface RmCommandOptions {
3
+ dir?: string;
4
+ forceDelete?: boolean;
5
+ }
6
+ export declare function runRmCommand(task: string, options: RmCommandOptions, output?: Output): Promise<void>;
@@ -0,0 +1,99 @@
1
+ import { rm } from "node:fs/promises";
2
+ import { resolveRmConfig } from "../lib/config.js";
3
+ import { toErrorMessage } from "../lib/errors.js";
4
+ import { pathExists } from "../lib/fs-utils.js";
5
+ import { runGitStatus, runGitStreamWithOptions } from "../lib/git.js";
6
+ import { createOutput } from "../lib/output.js";
7
+ import { resolveRepoContext, resolveWorktreePath } from "../lib/repo.js";
8
+ import { toTaskSlug } from "../lib/task-utils.js";
9
+ export async function runRmCommand(task, options, output = createOutput()) {
10
+ const repoContext = await resolveRepoContext();
11
+ const resolved = await resolveRmConfig(repoContext.repoRoot, options);
12
+ const taskSlug = toTaskSlug(task);
13
+ const worktreePath = resolveWorktreePath(repoContext.repoRoot, repoContext.repoName, taskSlug, resolved.dir);
14
+ let removedMapping = false;
15
+ const removeResult = await runGitStatus(["worktree", "remove", worktreePath], repoContext.repoRoot);
16
+ if (removeResult.exitCode === 0) {
17
+ removedMapping = true;
18
+ }
19
+ else {
20
+ const firstError = [removeResult.stderr, removeResult.stdout]
21
+ .filter(Boolean)
22
+ .join("\n")
23
+ .trim();
24
+ const mappingMissing = isMissingWorktreeMappingError(firstError);
25
+ if (!mappingMissing && resolved.forceDelete) {
26
+ const forceRemoveResult = await runGitStatus(["worktree", "remove", "--force", worktreePath], repoContext.repoRoot);
27
+ if (forceRemoveResult.exitCode === 0) {
28
+ removedMapping = true;
29
+ }
30
+ else {
31
+ const forcedMessage = [
32
+ forceRemoveResult.stderr,
33
+ forceRemoveResult.stdout,
34
+ ]
35
+ .filter(Boolean)
36
+ .join("\n")
37
+ .trim();
38
+ if (!isMissingWorktreeMappingError(forcedMessage)) {
39
+ throw new Error(`Failed to remove worktree mapping for ${worktreePath}\n${forcedMessage || "Unknown git error"}`);
40
+ }
41
+ }
42
+ }
43
+ else if (!mappingMissing) {
44
+ throw new Error([
45
+ `Failed to remove worktree mapping for ${worktreePath}`,
46
+ firstError || "Unknown git error",
47
+ "",
48
+ "Likely causes: VS Code still open, a watcher process still running, or a terminal in that folder.",
49
+ "Close those and retry, or use --force-delete.",
50
+ ].join("\n"));
51
+ }
52
+ }
53
+ if (resolved.forceDelete && (await pathExists(worktreePath))) {
54
+ try {
55
+ await rm(worktreePath, {
56
+ recursive: true,
57
+ force: true,
58
+ maxRetries: 5,
59
+ retryDelay: 150,
60
+ });
61
+ }
62
+ catch (error) {
63
+ throw new Error([
64
+ `Worktree mapping may be removed, but directory delete failed: ${worktreePath}`,
65
+ toErrorMessage(error),
66
+ "Close VS Code and any watchers/terminals using this folder, then retry.",
67
+ ].join("\n"));
68
+ }
69
+ }
70
+ await runGitStreamWithOptions(["worktree", "prune"], repoContext.repoRoot, {
71
+ quiet: output.quiet || output.json,
72
+ });
73
+ if (!resolved.forceDelete && (await pathExists(worktreePath))) {
74
+ output.info(`Removed worktree mapping for ${worktreePath}`);
75
+ output.info("Directory still exists on disk. Use --force-delete to remove it as well.");
76
+ output.event("worktree.removed", {
77
+ path: worktreePath,
78
+ mappingOnly: true,
79
+ });
80
+ return;
81
+ }
82
+ if (removedMapping) {
83
+ output.info(`Removed worktree ${worktreePath}`);
84
+ output.event("worktree.removed", {
85
+ path: worktreePath,
86
+ mappingOnly: false,
87
+ });
88
+ }
89
+ else {
90
+ output.info(`No existing worktree mapping found for ${worktreePath}`);
91
+ output.event("worktree.not_found", {
92
+ path: worktreePath,
93
+ });
94
+ }
95
+ }
96
+ function isMissingWorktreeMappingError(message) {
97
+ return /is not a working tree|is not registered|no such file|does not exist/i.test(message);
98
+ }
99
+ //# sourceMappingURL=rm.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"rm.js","sourceRoot":"","sources":["../../src/commands/rm.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,9 @@
1
+ export interface BuildWorktreeAddArgsInput {
2
+ branchName: string;
3
+ worktreePath: string;
4
+ baseRef: string;
5
+ localBranchExists: boolean;
6
+ remoteBranchExists: boolean;
7
+ remoteName?: string;
8
+ }
9
+ export declare function buildWorktreeAddArgs(input: BuildWorktreeAddArgsInput): string[];
@@ -0,0 +1,18 @@
1
+ export function buildWorktreeAddArgs(input) {
2
+ if (input.localBranchExists) {
3
+ return ["worktree", "add", input.worktreePath, input.branchName];
4
+ }
5
+ const remoteName = input.remoteName ?? "origin";
6
+ const startPoint = input.remoteBranchExists
7
+ ? `${remoteName}/${input.branchName}`
8
+ : input.baseRef;
9
+ return [
10
+ "worktree",
11
+ "add",
12
+ "-b",
13
+ input.branchName,
14
+ input.worktreePath,
15
+ startPoint,
16
+ ];
17
+ }
18
+ //# sourceMappingURL=add-strategy.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"add-strategy.js","sourceRoot":"","sources":["../../src/lib/add-strategy.ts"],"names":[],"mappings":"AASA,MAAM,UAAU,oBAAoB,CAClC,KAAgC;IAEhC,IAAI,KAAK,CAAC,iBAAiB,EAAE,CAAC;QAC5B,OAAO,CAAC,UAAU,EAAE,KAAK,EAAE,KAAK,CAAC,YAAY,EAAE,KAAK,CAAC,UAAU,CAAC,CAAC;IACnE,CAAC;IAED,MAAM,UAAU,GAAG,KAAK,CAAC,UAAU,IAAI,QAAQ,CAAC;IAChD,MAAM,UAAU,GAAG,KAAK,CAAC,kBAAkB;QACzC,CAAC,CAAC,GAAG,UAAU,IAAI,KAAK,CAAC,UAAU,EAAE;QACrC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC;IAElB,OAAO;QACL,UAAU;QACV,KAAK;QACL,IAAI;QACJ,KAAK,CAAC,UAAU;QAChB,KAAK,CAAC,YAAY;QAClB,UAAU;KACX,CAAC;AACJ,CAAC"}
@@ -0,0 +1 @@
1
+ export declare function copyToClipboard(text: string): Promise<void>;