cluttry 1.0.3 → 1.5.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 (91) hide show
  1. package/CHANGELOG.md +71 -0
  2. package/README.md +203 -300
  3. package/dist/commands/completions.d.ts +16 -0
  4. package/dist/commands/completions.d.ts.map +1 -0
  5. package/dist/commands/completions.js +46 -0
  6. package/dist/commands/completions.js.map +1 -0
  7. package/dist/commands/explain-copy.d.ts +11 -0
  8. package/dist/commands/explain-copy.d.ts.map +1 -0
  9. package/dist/commands/explain-copy.js +34 -0
  10. package/dist/commands/explain-copy.js.map +1 -0
  11. package/dist/commands/finish.d.ts +20 -0
  12. package/dist/commands/finish.d.ts.map +1 -0
  13. package/dist/commands/finish.js +817 -0
  14. package/dist/commands/finish.js.map +1 -0
  15. package/dist/commands/gc.d.ts +22 -0
  16. package/dist/commands/gc.d.ts.map +1 -0
  17. package/dist/commands/gc.js +163 -0
  18. package/dist/commands/gc.js.map +1 -0
  19. package/dist/commands/init.d.ts.map +1 -1
  20. package/dist/commands/init.js +1 -0
  21. package/dist/commands/init.js.map +1 -1
  22. package/dist/commands/open.d.ts +15 -1
  23. package/dist/commands/open.d.ts.map +1 -1
  24. package/dist/commands/open.js +96 -17
  25. package/dist/commands/open.js.map +1 -1
  26. package/dist/commands/resume.d.ts +21 -0
  27. package/dist/commands/resume.d.ts.map +1 -0
  28. package/dist/commands/resume.js +106 -0
  29. package/dist/commands/resume.js.map +1 -0
  30. package/dist/commands/rm.d.ts.map +1 -1
  31. package/dist/commands/rm.js +6 -14
  32. package/dist/commands/rm.js.map +1 -1
  33. package/dist/commands/spawn.d.ts +3 -0
  34. package/dist/commands/spawn.d.ts.map +1 -1
  35. package/dist/commands/spawn.js +182 -19
  36. package/dist/commands/spawn.js.map +1 -1
  37. package/dist/index.d.ts +4 -0
  38. package/dist/index.d.ts.map +1 -1
  39. package/dist/index.js +198 -9
  40. package/dist/index.js.map +1 -1
  41. package/dist/lib/completions.d.ts +35 -0
  42. package/dist/lib/completions.d.ts.map +1 -0
  43. package/dist/lib/completions.js +368 -0
  44. package/dist/lib/completions.js.map +1 -0
  45. package/dist/lib/config.d.ts.map +1 -1
  46. package/dist/lib/config.js +2 -0
  47. package/dist/lib/config.js.map +1 -1
  48. package/dist/lib/errors.d.ts +43 -0
  49. package/dist/lib/errors.d.ts.map +1 -0
  50. package/dist/lib/errors.js +251 -0
  51. package/dist/lib/errors.js.map +1 -0
  52. package/dist/lib/git.d.ts +17 -0
  53. package/dist/lib/git.d.ts.map +1 -1
  54. package/dist/lib/git.js +78 -10
  55. package/dist/lib/git.js.map +1 -1
  56. package/dist/lib/safety.d.ts +79 -0
  57. package/dist/lib/safety.d.ts.map +1 -0
  58. package/dist/lib/safety.js +133 -0
  59. package/dist/lib/safety.js.map +1 -0
  60. package/dist/lib/secrets.d.ts +29 -0
  61. package/dist/lib/secrets.d.ts.map +1 -1
  62. package/dist/lib/secrets.js +115 -0
  63. package/dist/lib/secrets.js.map +1 -1
  64. package/dist/lib/session.d.ts +93 -0
  65. package/dist/lib/session.d.ts.map +1 -0
  66. package/dist/lib/session.js +254 -0
  67. package/dist/lib/session.js.map +1 -0
  68. package/dist/lib/types.d.ts +6 -1
  69. package/dist/lib/types.d.ts.map +1 -1
  70. package/package.json +1 -1
  71. package/.claude/settings.local.json +0 -7
  72. package/src/commands/doctor.ts +0 -222
  73. package/src/commands/init.ts +0 -120
  74. package/src/commands/list.ts +0 -133
  75. package/src/commands/open.ts +0 -78
  76. package/src/commands/prune.ts +0 -36
  77. package/src/commands/rm.ts +0 -125
  78. package/src/commands/shell.ts +0 -99
  79. package/src/commands/spawn.ts +0 -169
  80. package/src/index.ts +0 -123
  81. package/src/lib/config.ts +0 -120
  82. package/src/lib/git.ts +0 -243
  83. package/src/lib/output.ts +0 -102
  84. package/src/lib/paths.ts +0 -108
  85. package/src/lib/secrets.ts +0 -193
  86. package/src/lib/types.ts +0 -69
  87. package/tests/config.test.ts +0 -102
  88. package/tests/paths.test.ts +0 -155
  89. package/tests/secrets.test.ts +0 -150
  90. package/tsconfig.json +0 -20
  91. package/vitest.config.ts +0 -15
@@ -0,0 +1,251 @@
1
+ /**
2
+ * Structured error handling for cry CLI
3
+ *
4
+ * Each error includes:
5
+ * - what: What happened
6
+ * - why: Why it likely happened
7
+ * - fix: Exact command(s) the user should run
8
+ */
9
+ import * as out from './output.js';
10
+ /**
11
+ * Print a structured error message and exit
12
+ */
13
+ export function fail(error) {
14
+ out.error(error.what);
15
+ out.newline();
16
+ out.log(`${out.fmt.bold('Why:')} ${error.why}`);
17
+ out.newline();
18
+ out.log(out.fmt.bold('Fix:'));
19
+ const fixes = Array.isArray(error.fix) ? error.fix : [error.fix];
20
+ for (const fix of fixes) {
21
+ out.log(` ${out.fmt.cyan(fix)}`);
22
+ }
23
+ process.exit(1);
24
+ }
25
+ /**
26
+ * Print a structured error without exiting (for non-fatal errors)
27
+ */
28
+ export function printError(error) {
29
+ out.error(error.what);
30
+ out.newline();
31
+ out.log(`${out.fmt.bold('Why:')} ${error.why}`);
32
+ out.newline();
33
+ out.log(out.fmt.bold('Fix:'));
34
+ const fixes = Array.isArray(error.fix) ? error.fix : [error.fix];
35
+ for (const fix of fixes) {
36
+ out.log(` ${out.fmt.cyan(fix)}`);
37
+ }
38
+ }
39
+ // ─────────────────────────────────────────────────────────────────────────────
40
+ // Common error factories
41
+ // ─────────────────────────────────────────────────────────────────────────────
42
+ export const errors = {
43
+ notGitRepo() {
44
+ return {
45
+ what: 'Not a git repository.',
46
+ why: 'cry requires a git repository to manage worktrees. The current directory is not inside a git repo.',
47
+ fix: [
48
+ 'cd /path/to/your/repo',
49
+ 'git init # or clone an existing repo',
50
+ ],
51
+ };
52
+ },
53
+ gitNotInstalled() {
54
+ return {
55
+ what: 'Git is not installed or not in PATH.',
56
+ why: 'cry requires git to manage worktrees. Git was not found on your system.',
57
+ fix: [
58
+ 'brew install git # macOS',
59
+ 'sudo apt install git # Ubuntu/Debian',
60
+ 'https://git-scm.com/downloads',
61
+ ],
62
+ };
63
+ },
64
+ branchAlreadyExists(branch) {
65
+ return {
66
+ what: `Branch '${branch}' already exists.`,
67
+ why: 'You used --new but the branch already exists locally or remotely.',
68
+ fix: [
69
+ `cry spawn ${branch} # use existing branch (without --new)`,
70
+ `cry spawn ${branch}-v2 --new # choose a different name`,
71
+ `git branch -d ${branch} # delete the existing branch first`,
72
+ ],
73
+ };
74
+ },
75
+ worktreeAlreadyExists(branch, existingPath) {
76
+ return {
77
+ what: `A worktree already exists for branch '${branch}'.`,
78
+ why: `The branch is already checked out in another worktree at: ${existingPath}`,
79
+ fix: [
80
+ `cry rm ${branch} # remove the existing worktree`,
81
+ `cry open ${branch} # open the existing worktree instead`,
82
+ ],
83
+ };
84
+ },
85
+ destinationExists(path) {
86
+ return {
87
+ what: `Destination already exists: ${path}`,
88
+ why: 'The target directory for the worktree already exists on disk.',
89
+ fix: [
90
+ `rm -rf "${path}" # remove the directory`,
91
+ `cry spawn <branch> --path /different/path # use a different path`,
92
+ ],
93
+ };
94
+ },
95
+ dirtyWorkingTree(branch) {
96
+ return {
97
+ what: 'Worktree has uncommitted changes.',
98
+ why: 'There are modified or untracked files that would be lost.',
99
+ fix: [
100
+ 'git status # see what changed',
101
+ 'git add . && git commit -m "WIP" # commit changes',
102
+ `cry rm ${branch} --force # remove anyway (changes lost)`,
103
+ ],
104
+ };
105
+ },
106
+ ghNotInstalled() {
107
+ return {
108
+ what: 'GitHub CLI (gh) is not installed.',
109
+ why: 'cry uses the gh CLI to create pull requests. It was not found on your system.',
110
+ fix: [
111
+ 'brew install gh # macOS',
112
+ 'sudo apt install gh # Ubuntu/Debian',
113
+ 'https://cli.github.com/',
114
+ 'gh auth login # after installing, authenticate',
115
+ ],
116
+ };
117
+ },
118
+ ghNotAuthenticated() {
119
+ return {
120
+ what: 'GitHub CLI is not authenticated.',
121
+ why: 'You have gh installed but have not logged in yet.',
122
+ fix: [
123
+ 'gh auth login',
124
+ 'gh auth status # verify authentication',
125
+ ],
126
+ };
127
+ },
128
+ noRemoteConfigured() {
129
+ return {
130
+ what: 'No remote repository configured.',
131
+ why: 'This repository has no origin remote, so there is nowhere to push or create PRs.',
132
+ fix: [
133
+ 'git remote add origin https://github.com/user/repo.git',
134
+ 'git remote add origin git@github.com:user/repo.git',
135
+ 'git remote -v # list current remotes',
136
+ ],
137
+ };
138
+ },
139
+ pushFailed(branch) {
140
+ return {
141
+ what: `Failed to push branch '${branch}'.`,
142
+ why: 'The push was rejected. This could be due to no remote, auth issues, or branch protection.',
143
+ fix: [
144
+ 'git remote -v # check remote is configured',
145
+ 'gh auth status # check GitHub authentication',
146
+ `git push -u origin ${branch} # try manually`,
147
+ 'git fetch origin && git rebase origin/main # if behind remote',
148
+ ],
149
+ };
150
+ },
151
+ permissionDenied(path) {
152
+ return {
153
+ what: `Permission denied: ${path}`,
154
+ why: 'You do not have permission to read or write to this path.',
155
+ fix: [
156
+ `ls -la "${path}" # check permissions`,
157
+ `sudo chown -R $(whoami) "${path}" # take ownership (if appropriate)`,
158
+ 'Try a different directory with --path',
159
+ ],
160
+ };
161
+ },
162
+ worktreeNotFound(nameOrPath, available) {
163
+ const availableList = available.slice(0, 5).map(a => ` • ${a}`).join('\n');
164
+ return {
165
+ what: `Worktree not found: ${nameOrPath}`,
166
+ why: 'No worktree matches that branch name or path.',
167
+ fix: [
168
+ 'cry list # see all worktrees',
169
+ `Available:\n${availableList}`,
170
+ ],
171
+ };
172
+ },
173
+ sessionNotFound(nameOrId) {
174
+ return {
175
+ what: `Session not found: ${nameOrId}`,
176
+ why: 'No session matches that branch name or session ID.',
177
+ fix: [
178
+ 'cry list # see all worktrees and sessions',
179
+ 'cry spawn <branch> --new # create a new session',
180
+ ],
181
+ };
182
+ },
183
+ detachedHead() {
184
+ return {
185
+ what: 'Cannot determine base branch: HEAD is detached.',
186
+ why: 'You are not on a branch, so cry cannot determine the PR target.',
187
+ fix: [
188
+ 'git checkout main # switch to a branch first',
189
+ 'cry spawn <branch> --new --base-branch main # specify base explicitly',
190
+ ],
191
+ };
192
+ },
193
+ configNotFound() {
194
+ return {
195
+ what: 'No .cry.json found.',
196
+ why: 'This repository has not been initialized with cry.',
197
+ fix: [
198
+ 'cry init # initialize cry in this repo',
199
+ ],
200
+ };
201
+ },
202
+ agentNotFound(agent) {
203
+ return {
204
+ what: `Agent command not found: ${agent}`,
205
+ why: `The '${agent}' command is not installed or not in your PATH.`,
206
+ fix: agent === 'claude' ? [
207
+ 'npm install -g @anthropic-ai/claude-code',
208
+ 'https://docs.anthropic.com/claude-code',
209
+ ] : agent === 'cursor' ? [
210
+ 'Download Cursor from https://cursor.sh',
211
+ 'Ensure cursor CLI is in your PATH',
212
+ ] : [
213
+ `Install ${agent} or update agentCommand in .cry.json`,
214
+ ],
215
+ };
216
+ },
217
+ editorNotFound(editor) {
218
+ return {
219
+ what: `Editor command not found: ${editor}`,
220
+ why: `The '${editor}' command is not installed or not in your PATH.`,
221
+ fix: editor === 'code' ? [
222
+ 'Install VS Code from https://code.visualstudio.com',
223
+ 'Run "Shell Command: Install code in PATH" from VS Code',
224
+ ] : [
225
+ `Install ${editor} or update editorCommand in .cry.json`,
226
+ ],
227
+ };
228
+ },
229
+ cannotRemoveMainWorktree() {
230
+ return {
231
+ what: 'Cannot remove the main worktree.',
232
+ why: 'This is your primary repository checkout. Removing it would delete your repo.',
233
+ fix: [
234
+ 'cry list # see worktrees - the main one cannot be removed',
235
+ 'Use cry rm <branch> to remove other worktrees',
236
+ ],
237
+ };
238
+ },
239
+ worktreeMissing(path, branch) {
240
+ return {
241
+ what: `Worktree no longer exists: ${path}`,
242
+ why: 'The worktree directory was deleted but the session manifest still exists.',
243
+ fix: [
244
+ `cry spawn ${branch} --new # recreate the worktree`,
245
+ 'cry gc # clean up stale sessions',
246
+ 'cry prune # clean up git worktree references',
247
+ ],
248
+ };
249
+ },
250
+ };
251
+ //# sourceMappingURL=errors.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"errors.js","sourceRoot":"","sources":["../../src/lib/errors.ts"],"names":[],"mappings":"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"}
package/dist/lib/git.d.ts CHANGED
@@ -4,6 +4,7 @@
4
4
  import type { WorktreeInfo } from './types.js';
5
5
  /**
6
6
  * Execute a git command and return stdout
7
+ * Uses spawnSync to properly handle arguments with spaces
7
8
  */
8
9
  export declare function git(args: string[], cwd?: string): string;
9
10
  /**
@@ -26,6 +27,22 @@ export declare function branchExists(branch: string, cwd?: string): boolean;
26
27
  * Get the current branch name
27
28
  */
28
29
  export declare function getCurrentBranch(cwd?: string): string | null;
30
+ /**
31
+ * Check if HEAD is detached (not on any branch)
32
+ */
33
+ export declare function isDetachedHead(cwd?: string): boolean;
34
+ /**
35
+ * Get the default branch name (from origin/HEAD or common defaults)
36
+ */
37
+ export declare function getDefaultBranch(cwd?: string): string | null;
38
+ /**
39
+ * Get the merge-base between two refs
40
+ */
41
+ export declare function getMergeBase(ref1: string, ref2: string, cwd?: string): string | null;
42
+ /**
43
+ * Get the upstream tracking branch for the current branch
44
+ */
45
+ export declare function getUpstreamBranch(cwd?: string): string | null;
29
46
  /**
30
47
  * Check if a file is tracked by git
31
48
  */
@@ -1 +1 @@
1
- {"version":3,"file":"git.d.ts","sourceRoot":"","sources":["../../src/lib/git.ts"],"names":[],"mappings":"AAAA;;GAEG;AAKH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAE/C;;GAEG;AACH,wBAAgB,GAAG,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,GAAG,CAAC,EAAE,MAAM,GAAG,MAAM,CASxD;AAED;;GAEG;AACH,wBAAgB,SAAS,CAAC,GAAG,CAAC,EAAE,MAAM,GAAG,OAAO,CAO/C;AAED;;GAEG;AACH,wBAAgB,WAAW,CAAC,GAAG,CAAC,EAAE,MAAM,GAAG,MAAM,CAEhD;AAED;;GAEG;AACH,wBAAgB,WAAW,CAAC,GAAG,CAAC,EAAE,MAAM,GAAG,MAAM,CAGhD;AAED;;GAEG;AACH,wBAAgB,YAAY,CAAC,MAAM,EAAE,MAAM,EAAE,GAAG,CAAC,EAAE,MAAM,GAAG,OAAO,CAOlE;AAED;;GAEG;AACH,wBAAgB,gBAAgB,CAAC,GAAG,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAM5D;AAED;;GAEG;AACH,wBAAgB,SAAS,CAAC,QAAQ,EAAE,MAAM,EAAE,GAAG,CAAC,EAAE,MAAM,GAAG,OAAO,CAOjE;AAED;;GAEG;AACH,wBAAgB,SAAS,CAAC,QAAQ,EAAE,MAAM,EAAE,GAAG,CAAC,EAAE,MAAM,GAAG,OAAO,CAOjE;AAED;;GAEG;AACH,wBAAgB,aAAa,CAAC,GAAG,CAAC,EAAE,MAAM,GAAG,YAAY,EAAE,CAiC1D;AAED;;GAEG;AACH,wBAAgB,WAAW,CACzB,UAAU,EAAE,MAAM,EAClB,MAAM,EAAE,MAAM,EACd,YAAY,EAAE,OAAO,EACrB,GAAG,CAAC,EAAE,MAAM,GACX,IAAI,CAUN;AAED;;GAEG;AACH,wBAAgB,cAAc,CAAC,YAAY,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,EAAE,GAAG,CAAC,EAAE,MAAM,GAAG,IAAI,CAOvF;AAED;;GAEG;AACH,wBAAgB,cAAc,CAAC,GAAG,CAAC,EAAE,MAAM,GAAG,MAAM,CAEnD;AAED;;GAEG;AACH,wBAAgB,YAAY,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,EAAE,GAAG,CAAC,EAAE,MAAM,GAAG,IAAI,CAG/E;AAED;;GAEG;AACH,wBAAgB,eAAe,CAAC,YAAY,EAAE,MAAM,GAAG,OAAO,CAO7D;AAED;;GAEG;AACH,wBAAgB,YAAY,CAAC,YAAY,EAAE,MAAM,GAAG,MAAM,CAMzD;AAED;;GAEG;AACH,wBAAgB,UAAU,CAAC,OAAO,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAoBxE;AAED;;GAEG;AACH,wBAAgB,aAAa,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CASlD"}
1
+ {"version":3,"file":"git.d.ts","sourceRoot":"","sources":["../../src/lib/git.ts"],"names":[],"mappings":"AAAA;;GAEG;AAKH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAE/C;;;GAGG;AACH,wBAAgB,GAAG,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,GAAG,CAAC,EAAE,MAAM,GAAG,MAAM,CAaxD;AAED;;GAEG;AACH,wBAAgB,SAAS,CAAC,GAAG,CAAC,EAAE,MAAM,GAAG,OAAO,CAO/C;AAED;;GAEG;AACH,wBAAgB,WAAW,CAAC,GAAG,CAAC,EAAE,MAAM,GAAG,MAAM,CAEhD;AAED;;GAEG;AACH,wBAAgB,WAAW,CAAC,GAAG,CAAC,EAAE,MAAM,GAAG,MAAM,CAGhD;AAED;;GAEG;AACH,wBAAgB,YAAY,CAAC,MAAM,EAAE,MAAM,EAAE,GAAG,CAAC,EAAE,MAAM,GAAG,OAAO,CAOlE;AAED;;GAEG;AACH,wBAAgB,gBAAgB,CAAC,GAAG,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAW5D;AAED;;GAEG;AACH,wBAAgB,cAAc,CAAC,GAAG,CAAC,EAAE,MAAM,GAAG,OAAO,CAOpD;AAED;;GAEG;AACH,wBAAgB,gBAAgB,CAAC,GAAG,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAqB5D;AAED;;GAEG;AACH,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,GAAG,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAMpF;AAED;;GAEG;AACH,wBAAgB,iBAAiB,CAAC,GAAG,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAO7D;AAED;;GAEG;AACH,wBAAgB,SAAS,CAAC,QAAQ,EAAE,MAAM,EAAE,GAAG,CAAC,EAAE,MAAM,GAAG,OAAO,CAOjE;AAED;;GAEG;AACH,wBAAgB,SAAS,CAAC,QAAQ,EAAE,MAAM,EAAE,GAAG,CAAC,EAAE,MAAM,GAAG,OAAO,CAOjE;AAED;;GAEG;AACH,wBAAgB,aAAa,CAAC,GAAG,CAAC,EAAE,MAAM,GAAG,YAAY,EAAE,CAiC1D;AAED;;GAEG;AACH,wBAAgB,WAAW,CACzB,UAAU,EAAE,MAAM,EAClB,MAAM,EAAE,MAAM,EACd,YAAY,EAAE,OAAO,EACrB,GAAG,CAAC,EAAE,MAAM,GACX,IAAI,CAUN;AAED;;GAEG;AACH,wBAAgB,cAAc,CAAC,YAAY,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,EAAE,GAAG,CAAC,EAAE,MAAM,GAAG,IAAI,CAOvF;AAED;;GAEG;AACH,wBAAgB,cAAc,CAAC,GAAG,CAAC,EAAE,MAAM,GAAG,MAAM,CAEnD;AAED;;GAEG;AACH,wBAAgB,YAAY,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,EAAE,GAAG,CAAC,EAAE,MAAM,GAAG,IAAI,CAG/E;AAED;;GAEG;AACH,wBAAgB,eAAe,CAAC,YAAY,EAAE,MAAM,GAAG,OAAO,CAO7D;AAED;;GAEG;AACH,wBAAgB,YAAY,CAAC,YAAY,EAAE,MAAM,GAAG,MAAM,CAMzD;AAED;;GAEG;AACH,wBAAgB,UAAU,CAAC,OAAO,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAoBxE;AAED;;GAEG;AACH,wBAAgB,aAAa,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAWlD"}
package/dist/lib/git.js CHANGED
@@ -1,21 +1,23 @@
1
1
  /**
2
2
  * Git operations for cry
3
3
  */
4
- import { execSync, spawn } from 'node:child_process';
4
+ import { execSync, spawn, spawnSync } from 'node:child_process';
5
5
  import path from 'node:path';
6
6
  /**
7
7
  * Execute a git command and return stdout
8
+ * Uses spawnSync to properly handle arguments with spaces
8
9
  */
9
10
  export function git(args, cwd) {
10
- const options = cwd ? { cwd, encoding: 'utf-8' } : { encoding: 'utf-8' };
11
- try {
12
- return execSync(`git ${args.join(' ')}`, { ...options, stdio: ['pipe', 'pipe', 'pipe'] }).trim();
13
- }
14
- catch (error) {
15
- const execError = error;
16
- const stderr = execError.stderr?.toString?.() || execError.message || 'Unknown git error';
11
+ const result = spawnSync('git', args, {
12
+ cwd,
13
+ encoding: 'utf-8',
14
+ stdio: ['pipe', 'pipe', 'pipe'],
15
+ });
16
+ if (result.status !== 0) {
17
+ const stderr = result.stderr?.toString?.() || result.error?.message || 'Unknown git error';
17
18
  throw new Error(stderr.trim());
18
19
  }
20
+ return (result.stdout || '').trim();
19
21
  }
20
22
  /**
21
23
  * Check if we're in a git repository
@@ -59,7 +61,71 @@ export function branchExists(branch, cwd) {
59
61
  */
60
62
  export function getCurrentBranch(cwd) {
61
63
  try {
62
- return git(['rev-parse', '--abbrev-ref', 'HEAD'], cwd);
64
+ const branch = git(['rev-parse', '--abbrev-ref', 'HEAD'], cwd);
65
+ // Returns 'HEAD' when in detached state
66
+ if (branch === 'HEAD') {
67
+ return null;
68
+ }
69
+ return branch;
70
+ }
71
+ catch {
72
+ return null;
73
+ }
74
+ }
75
+ /**
76
+ * Check if HEAD is detached (not on any branch)
77
+ */
78
+ export function isDetachedHead(cwd) {
79
+ try {
80
+ const branch = git(['rev-parse', '--abbrev-ref', 'HEAD'], cwd);
81
+ return branch === 'HEAD';
82
+ }
83
+ catch {
84
+ return false;
85
+ }
86
+ }
87
+ /**
88
+ * Get the default branch name (from origin/HEAD or common defaults)
89
+ */
90
+ export function getDefaultBranch(cwd) {
91
+ // Try origin/HEAD first
92
+ try {
93
+ const ref = git(['symbolic-ref', 'refs/remotes/origin/HEAD'], cwd);
94
+ // Returns something like "refs/remotes/origin/main"
95
+ const match = ref.match(/refs\/remotes\/origin\/(.+)$/);
96
+ if (match) {
97
+ return match[1];
98
+ }
99
+ }
100
+ catch {
101
+ // origin/HEAD not set, try other methods
102
+ }
103
+ // Try to find main or master
104
+ for (const candidate of ['main', 'master']) {
105
+ if (branchExists(candidate, cwd)) {
106
+ return candidate;
107
+ }
108
+ }
109
+ return null;
110
+ }
111
+ /**
112
+ * Get the merge-base between two refs
113
+ */
114
+ export function getMergeBase(ref1, ref2, cwd) {
115
+ try {
116
+ return git(['merge-base', ref1, ref2], cwd);
117
+ }
118
+ catch {
119
+ return null;
120
+ }
121
+ }
122
+ /**
123
+ * Get the upstream tracking branch for the current branch
124
+ */
125
+ export function getUpstreamBranch(cwd) {
126
+ try {
127
+ const upstream = git(['rev-parse', '--abbrev-ref', '@{upstream}'], cwd);
128
+ return upstream;
63
129
  }
64
130
  catch {
65
131
  return null;
@@ -213,8 +279,10 @@ export function runCommand(command, cwd) {
213
279
  */
214
280
  export function commandExists(cmd) {
215
281
  try {
282
+ // Extract just the command name (first word) from a potentially complex command
283
+ const cmdName = cmd.split(/\s+/)[0];
216
284
  const isWindows = process.platform === 'win32';
217
- const checkCmd = isWindows ? `where ${cmd}` : `which ${cmd}`;
285
+ const checkCmd = isWindows ? `where ${cmdName}` : `which ${cmdName}`;
218
286
  execSync(checkCmd, { stdio: 'pipe' });
219
287
  return true;
220
288
  }
@@ -1 +1 @@
1
- {"version":3,"file":"git.js","sourceRoot":"","sources":["../../src/lib/git.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"git.js","sourceRoot":"","sources":["../../src/lib/git.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,79 @@
1
+ /**
2
+ * Safety module for dangerous operations
3
+ *
4
+ * This module enforces hard safety constraints:
5
+ * 1. Never auto-merge PRs
6
+ * 2. Never delete branches/worktrees without explicit confirmation
7
+ * 3. Never copy tracked files to worktrees
8
+ *
9
+ * All dangerous operations must go through this module.
10
+ */
11
+ /**
12
+ * Types of dangerous operations
13
+ */
14
+ export type DangerousOperation = 'delete_worktree' | 'delete_branch' | 'force_remove_dirty' | 'cleanup_session' | 'merge_pr';
15
+ /**
16
+ * Confirmation state for dangerous operations
17
+ */
18
+ export interface ConfirmationState {
19
+ operation: DangerousOperation;
20
+ confirmed: boolean;
21
+ method: 'prompt' | 'flag' | 'none';
22
+ }
23
+ /**
24
+ * HARD CONSTRAINT: Merge is never allowed by default
25
+ * This function always returns false - merge must be done manually
26
+ */
27
+ export declare function isMergeAllowed(): boolean;
28
+ /**
29
+ * HARD CONSTRAINT: Check if deletion is explicitly confirmed
30
+ *
31
+ * Deletion requires EITHER:
32
+ * - Interactive confirmation (user typed 'y')
33
+ * - Explicit --yes flag
34
+ * - Explicit --cleanup flag (for finish command)
35
+ */
36
+ export declare function isDeletionConfirmed(state: ConfirmationState): boolean;
37
+ /**
38
+ * Require explicit confirmation for a dangerous operation
39
+ *
40
+ * @param operation - Type of dangerous operation
41
+ * @param options - Confirmation options
42
+ * @returns ConfirmationState with confirmed status
43
+ */
44
+ export declare function requireConfirmation(operation: DangerousOperation, options: {
45
+ skipPrompt?: boolean;
46
+ autoConfirm?: boolean;
47
+ message?: string;
48
+ }): Promise<ConfirmationState>;
49
+ /**
50
+ * Assert that a dangerous operation was properly confirmed
51
+ * Throws if not confirmed - use this as a guard
52
+ */
53
+ export declare function assertConfirmed(state: ConfirmationState): void;
54
+ /**
55
+ * HARD CONSTRAINT: Check if a file can be copied to worktree
56
+ *
57
+ * A file can ONLY be copied if:
58
+ * 1. It is NOT tracked by git
59
+ * 2. It IS ignored by git (in .gitignore)
60
+ *
61
+ * This function does not do the actual check - that's in secrets.ts
62
+ * This documents the invariant.
63
+ */
64
+ export interface FileCopyDecision {
65
+ path: string;
66
+ allowed: boolean;
67
+ reason: string;
68
+ isTracked: boolean;
69
+ isIgnored: boolean;
70
+ }
71
+ /**
72
+ * Validate that a file copy decision follows safety rules
73
+ */
74
+ export declare function validateFileCopy(decision: FileCopyDecision): void;
75
+ /**
76
+ * Safety summary for logging/debugging
77
+ */
78
+ export declare function getSafetyConstraints(): string[];
79
+ //# sourceMappingURL=safety.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"safety.d.ts","sourceRoot":"","sources":["../../src/lib/safety.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAIH;;GAEG;AACH,MAAM,MAAM,kBAAkB,GAC1B,iBAAiB,GACjB,eAAe,GACf,oBAAoB,GACpB,iBAAiB,GACjB,UAAU,CAAC;AAEf;;GAEG;AACH,MAAM,WAAW,iBAAiB;IAChC,SAAS,EAAE,kBAAkB,CAAC;IAC9B,SAAS,EAAE,OAAO,CAAC;IACnB,MAAM,EAAE,QAAQ,GAAG,MAAM,GAAG,MAAM,CAAC;CACpC;AAED;;;GAGG;AACH,wBAAgB,cAAc,IAAI,OAAO,CAIxC;AAED;;;;;;;GAOG;AACH,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,iBAAiB,GAAG,OAAO,CAWrE;AAED;;;;;;GAMG;AACH,wBAAsB,mBAAmB,CACvC,SAAS,EAAE,kBAAkB,EAC7B,OAAO,EAAE;IACP,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB,GACA,OAAO,CAAC,iBAAiB,CAAC,CAmB5B;AAuCD;;;GAGG;AACH,wBAAgB,eAAe,CAAC,KAAK,EAAE,iBAAiB,GAAG,IAAI,CAO9D;AAED;;;;;;;;;GASG;AACH,MAAM,WAAW,gBAAgB;IAC/B,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,OAAO,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,OAAO,CAAC;IACnB,SAAS,EAAE,OAAO,CAAC;CACpB;AAED;;GAEG;AACH,wBAAgB,gBAAgB,CAAC,QAAQ,EAAE,gBAAgB,GAAG,IAAI,CAgBjE;AAED;;GAEG;AACH,wBAAgB,oBAAoB,IAAI,MAAM,EAAE,CAM/C"}
@@ -0,0 +1,133 @@
1
+ /**
2
+ * Safety module for dangerous operations
3
+ *
4
+ * This module enforces hard safety constraints:
5
+ * 1. Never auto-merge PRs
6
+ * 2. Never delete branches/worktrees without explicit confirmation
7
+ * 3. Never copy tracked files to worktrees
8
+ *
9
+ * All dangerous operations must go through this module.
10
+ */
11
+ import * as readline from 'node:readline';
12
+ /**
13
+ * HARD CONSTRAINT: Merge is never allowed by default
14
+ * This function always returns false - merge must be done manually
15
+ */
16
+ export function isMergeAllowed() {
17
+ // SAFETY: Auto-merge is NEVER allowed
18
+ // Users must merge PRs manually through GitHub UI
19
+ return false;
20
+ }
21
+ /**
22
+ * HARD CONSTRAINT: Check if deletion is explicitly confirmed
23
+ *
24
+ * Deletion requires EITHER:
25
+ * - Interactive confirmation (user typed 'y')
26
+ * - Explicit --yes flag
27
+ * - Explicit --cleanup flag (for finish command)
28
+ */
29
+ export function isDeletionConfirmed(state) {
30
+ if (!state.confirmed) {
31
+ return false;
32
+ }
33
+ // Must have explicit confirmation method
34
+ if (state.method === 'none') {
35
+ return false;
36
+ }
37
+ return true;
38
+ }
39
+ /**
40
+ * Require explicit confirmation for a dangerous operation
41
+ *
42
+ * @param operation - Type of dangerous operation
43
+ * @param options - Confirmation options
44
+ * @returns ConfirmationState with confirmed status
45
+ */
46
+ export async function requireConfirmation(operation, options) {
47
+ // If --yes or --cleanup flag provided, treat as confirmed via flag
48
+ if (options.skipPrompt || options.autoConfirm) {
49
+ return {
50
+ operation,
51
+ confirmed: true,
52
+ method: 'flag',
53
+ };
54
+ }
55
+ // Otherwise, require interactive prompt
56
+ const message = options.message ?? getDefaultMessage(operation);
57
+ const confirmed = await promptConfirmation(message);
58
+ return {
59
+ operation,
60
+ confirmed,
61
+ method: confirmed ? 'prompt' : 'none',
62
+ };
63
+ }
64
+ /**
65
+ * Interactive confirmation prompt
66
+ */
67
+ async function promptConfirmation(message) {
68
+ const rl = readline.createInterface({
69
+ input: process.stdin,
70
+ output: process.stdout,
71
+ });
72
+ return new Promise((resolve) => {
73
+ rl.question(`${message} [y/N] `, (answer) => {
74
+ rl.close();
75
+ const normalized = answer.toLowerCase().trim();
76
+ resolve(normalized === 'y' || normalized === 'yes');
77
+ });
78
+ });
79
+ }
80
+ /**
81
+ * Get default confirmation message for an operation
82
+ */
83
+ function getDefaultMessage(operation) {
84
+ switch (operation) {
85
+ case 'delete_worktree':
86
+ return 'Remove worktree?';
87
+ case 'delete_branch':
88
+ return 'Delete branch?';
89
+ case 'force_remove_dirty':
90
+ return 'Worktree has uncommitted changes. Remove anyway?';
91
+ case 'cleanup_session':
92
+ return 'Clean up session (remove worktree)?';
93
+ case 'merge_pr':
94
+ // This should never be called - merge is not allowed
95
+ return 'Merge is not supported. Please merge manually.';
96
+ }
97
+ }
98
+ /**
99
+ * Assert that a dangerous operation was properly confirmed
100
+ * Throws if not confirmed - use this as a guard
101
+ */
102
+ export function assertConfirmed(state) {
103
+ if (!isDeletionConfirmed(state)) {
104
+ throw new Error(`Safety violation: ${state.operation} was not explicitly confirmed. ` +
105
+ `Use --yes flag or answer 'y' to confirmation prompt.`);
106
+ }
107
+ }
108
+ /**
109
+ * Validate that a file copy decision follows safety rules
110
+ */
111
+ export function validateFileCopy(decision) {
112
+ // HARD CONSTRAINT: Tracked files are NEVER copied
113
+ if (decision.isTracked && decision.allowed) {
114
+ throw new Error(`Safety violation: Attempted to copy tracked file '${decision.path}'. ` +
115
+ `Tracked files must NEVER be copied to worktrees.`);
116
+ }
117
+ // HARD CONSTRAINT: Non-ignored files should not be copied
118
+ if (!decision.isIgnored && decision.allowed) {
119
+ throw new Error(`Safety violation: Attempted to copy non-ignored file '${decision.path}'. ` +
120
+ `Only gitignored files can be copied to worktrees.`);
121
+ }
122
+ }
123
+ /**
124
+ * Safety summary for logging/debugging
125
+ */
126
+ export function getSafetyConstraints() {
127
+ return [
128
+ 'Never auto-merge PRs (merge must be done manually)',
129
+ 'Never delete branches/worktrees without explicit --yes flag or prompt confirmation',
130
+ 'Never copy tracked files to worktrees (only gitignored files allowed)',
131
+ ];
132
+ }
133
+ //# sourceMappingURL=safety.js.map