@link-assistant/hive-mind 0.39.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 (63) hide show
  1. package/CHANGELOG.md +20 -0
  2. package/LICENSE +24 -0
  3. package/README.md +769 -0
  4. package/package.json +58 -0
  5. package/src/agent.lib.mjs +705 -0
  6. package/src/agent.prompts.lib.mjs +196 -0
  7. package/src/buildUserMention.lib.mjs +71 -0
  8. package/src/claude-limits.lib.mjs +389 -0
  9. package/src/claude.lib.mjs +1445 -0
  10. package/src/claude.prompts.lib.mjs +203 -0
  11. package/src/codex.lib.mjs +552 -0
  12. package/src/codex.prompts.lib.mjs +194 -0
  13. package/src/config.lib.mjs +207 -0
  14. package/src/contributing-guidelines.lib.mjs +268 -0
  15. package/src/exit-handler.lib.mjs +205 -0
  16. package/src/git.lib.mjs +145 -0
  17. package/src/github-issue-creator.lib.mjs +246 -0
  18. package/src/github-linking.lib.mjs +152 -0
  19. package/src/github.batch.lib.mjs +272 -0
  20. package/src/github.graphql.lib.mjs +258 -0
  21. package/src/github.lib.mjs +1479 -0
  22. package/src/hive.config.lib.mjs +254 -0
  23. package/src/hive.mjs +1500 -0
  24. package/src/instrument.mjs +191 -0
  25. package/src/interactive-mode.lib.mjs +1000 -0
  26. package/src/lenv-reader.lib.mjs +206 -0
  27. package/src/lib.mjs +490 -0
  28. package/src/lino.lib.mjs +176 -0
  29. package/src/local-ci-checks.lib.mjs +324 -0
  30. package/src/memory-check.mjs +419 -0
  31. package/src/model-mapping.lib.mjs +145 -0
  32. package/src/model-validation.lib.mjs +278 -0
  33. package/src/opencode.lib.mjs +479 -0
  34. package/src/opencode.prompts.lib.mjs +194 -0
  35. package/src/protect-branch.mjs +159 -0
  36. package/src/review.mjs +433 -0
  37. package/src/reviewers-hive.mjs +643 -0
  38. package/src/sentry.lib.mjs +284 -0
  39. package/src/solve.auto-continue.lib.mjs +568 -0
  40. package/src/solve.auto-pr.lib.mjs +1374 -0
  41. package/src/solve.branch-errors.lib.mjs +341 -0
  42. package/src/solve.branch.lib.mjs +230 -0
  43. package/src/solve.config.lib.mjs +342 -0
  44. package/src/solve.error-handlers.lib.mjs +256 -0
  45. package/src/solve.execution.lib.mjs +291 -0
  46. package/src/solve.feedback.lib.mjs +436 -0
  47. package/src/solve.mjs +1128 -0
  48. package/src/solve.preparation.lib.mjs +210 -0
  49. package/src/solve.repo-setup.lib.mjs +114 -0
  50. package/src/solve.repository.lib.mjs +961 -0
  51. package/src/solve.results.lib.mjs +558 -0
  52. package/src/solve.session.lib.mjs +135 -0
  53. package/src/solve.validation.lib.mjs +325 -0
  54. package/src/solve.watch.lib.mjs +572 -0
  55. package/src/start-screen.mjs +324 -0
  56. package/src/task.mjs +308 -0
  57. package/src/telegram-bot.mjs +1481 -0
  58. package/src/telegram-markdown.lib.mjs +64 -0
  59. package/src/usage-limit.lib.mjs +218 -0
  60. package/src/version.lib.mjs +41 -0
  61. package/src/youtrack/solve.youtrack.lib.mjs +116 -0
  62. package/src/youtrack/youtrack-sync.mjs +219 -0
  63. package/src/youtrack/youtrack.lib.mjs +425 -0
@@ -0,0 +1,341 @@
1
+ #!/usr/bin/env node
2
+ 'use strict';
3
+
4
+ /**
5
+ * Branch error handling module for solve.mjs
6
+ * Provides improved error messages for branch checkout/creation failures
7
+ */
8
+
9
+ // Import Sentry integration
10
+ import { reportError } from './sentry.lib.mjs';
11
+
12
+ export async function handleBranchCheckoutError({
13
+ branchName,
14
+ prNumber,
15
+ errorOutput,
16
+ issueUrl,
17
+ owner,
18
+ repo,
19
+ tempDir,
20
+ argv,
21
+ formatAligned,
22
+ log,
23
+ $
24
+ }) {
25
+ // Check if this is a PR from a fork
26
+ let isForkPR = false;
27
+ let forkOwner = null;
28
+ let forkRepoName = null; // Track the actual fork repo name (may be prefixed)
29
+ let userHasFork = false;
30
+ let suggestForkOption = false;
31
+ let branchExistsInFork = false;
32
+
33
+ if (prNumber) {
34
+ try {
35
+ const prCheckResult = await $`gh pr view ${prNumber} --repo ${owner}/${repo} --json headRepositoryOwner,headRefName,headRepository 2>/dev/null`;
36
+ if (prCheckResult.code === 0) {
37
+ const prData = JSON.parse(prCheckResult.stdout.toString());
38
+ if (prData.headRepositoryOwner && prData.headRepositoryOwner.login !== owner) {
39
+ isForkPR = true;
40
+ forkOwner = prData.headRepositoryOwner.login;
41
+ suggestForkOption = true;
42
+
43
+ // Get the actual fork repository name (might be prefixed)
44
+ let forkRepoFullName = `${forkOwner}/${repo}`;
45
+ if (prData.headRepository && prData.headRepository.name) {
46
+ forkRepoFullName = `${forkOwner}/${prData.headRepository.name}`;
47
+ forkRepoName = prData.headRepository.name;
48
+ }
49
+
50
+ // Check if the branch exists in the fork
51
+ try {
52
+ const branchCheckResult = await $`gh api repos/${forkRepoFullName}/git/ref/heads/${branchName} 2>/dev/null`;
53
+ if (branchCheckResult.code === 0) {
54
+ branchExistsInFork = true;
55
+ }
56
+ } catch (e) {
57
+ reportError(e, {
58
+ context: 'check_fork_for_branch',
59
+ prNumber,
60
+ forkOwner,
61
+ forkRepoFullName,
62
+ branchName,
63
+ operation: 'verify_fork_branch'
64
+ });
65
+ // Branch doesn't exist in fork or can't access it
66
+ }
67
+ }
68
+ }
69
+ } catch (e) {
70
+ reportError(e, {
71
+ context: 'handle_branch_checkout_error',
72
+ prNumber,
73
+ branchName,
74
+ operation: 'analyze_branch_error'
75
+ });
76
+ // Ignore error, proceed with default message
77
+ }
78
+
79
+ // Check if the current user has a fork of this repository
80
+ try {
81
+ const userResult = await $`gh api user --jq .login`;
82
+ if (userResult.code === 0) {
83
+ const currentUser = userResult.stdout.toString().trim();
84
+ // Determine fork name based on --prefix-fork-name-with-owner-name option
85
+ const userForkRepoName = (argv && argv.prefixForkNameWithOwnerName) ? `${owner}-${repo}` : repo;
86
+ const userForkRepo = `${currentUser}/${userForkRepoName}`;
87
+ const forkCheckResult = await $`gh repo view ${userForkRepo} --json parent 2>/dev/null`;
88
+ if (forkCheckResult.code === 0) {
89
+ const forkData = JSON.parse(forkCheckResult.stdout.toString());
90
+ if (forkData.parent && forkData.parent.owner && forkData.parent.owner.login === owner) {
91
+ userHasFork = true;
92
+ if (!forkOwner) forkOwner = currentUser;
93
+ if (!forkRepoName) forkRepoName = userForkRepoName;
94
+ suggestForkOption = true;
95
+
96
+ // Check if the branch exists in user's fork
97
+ if (!branchExistsInFork) {
98
+ try {
99
+ const branchCheckResult = await $`gh api repos/${userForkRepo}/git/ref/heads/${branchName} 2>/dev/null`;
100
+ if (branchCheckResult.code === 0) {
101
+ branchExistsInFork = true;
102
+ forkOwner = currentUser;
103
+ forkRepoName = userForkRepoName;
104
+ }
105
+ } catch (e) {
106
+ reportError(e, {
107
+ context: 'check_user_fork_branch',
108
+ userForkOwner: currentUser,
109
+ userForkRepoName,
110
+ branchName,
111
+ operation: 'check_branch_in_user_fork'
112
+ });
113
+ // Branch doesn't exist in user's fork
114
+ }
115
+ }
116
+ }
117
+ }
118
+ }
119
+ } catch (e) {
120
+ reportError(e, {
121
+ context: 'handle_branch_checkout_error',
122
+ prNumber,
123
+ branchName,
124
+ operation: 'analyze_branch_error'
125
+ });
126
+ // Ignore error, proceed with default message
127
+ }
128
+ }
129
+
130
+ await log(`${formatAligned('❌', 'BRANCH CHECKOUT FAILED', '')}`, { level: 'error' });
131
+ await log('');
132
+
133
+ // Provide a clearer explanation of what happened
134
+ await log(' 🔍 What happened:');
135
+ await log(` Failed to checkout the branch '${branchName}' for PR #${prNumber}.`);
136
+ await log(` Repository: https://github.com/${owner}/${repo}`);
137
+ await log(` Pull Request: https://github.com/${owner}/${repo}/pull/${prNumber}`);
138
+ if (errorOutput.includes('is not a commit')) {
139
+ await log(` The branch doesn't exist in the main repository (https://github.com/${owner}/${repo}).`);
140
+ } else {
141
+ await log(' Git was unable to find or access the branch.');
142
+ }
143
+ await log('');
144
+
145
+ // Only show git output if it's not the typical "not a commit" error
146
+ if (!errorOutput.includes('is not a commit') || argv.verbose) {
147
+ await log(' 📦 Git error details:');
148
+ for (const line of errorOutput.split('\n')) {
149
+ await log(` ${line}`);
150
+ }
151
+ await log('');
152
+ }
153
+
154
+ // Explain why this happened
155
+ await log(' 💡 Why this happened:');
156
+ if (isForkPR && forkOwner) {
157
+ // Use forkRepoName if available, otherwise default to repo
158
+ const displayForkRepo = forkRepoName || repo;
159
+ if (branchExistsInFork) {
160
+ await log(` The PR branch '${branchName}' exists in the fork repository:`);
161
+ await log(` https://github.com/${forkOwner}/${displayForkRepo}`);
162
+ await log(' but you\'re trying to access it from the main repository:');
163
+ await log(` https://github.com/${owner}/${repo}`);
164
+ await log(' This branch does NOT exist in the main repository.');
165
+ } else {
166
+ await log(` The PR is from a fork (https://github.com/${forkOwner}/${displayForkRepo})`);
167
+ await log(` but the branch '${branchName}' could not be found there either.`);
168
+ await log(' The branch may have been deleted or renamed.');
169
+ }
170
+ await log(' This is a common issue with pull requests from forks.');
171
+ } else if (userHasFork && branchExistsInFork) {
172
+ // Use forkRepoName if available, otherwise default to repo
173
+ const displayForkRepo = forkRepoName || repo;
174
+ await log(` The branch '${branchName}' exists in your fork:`);
175
+ await log(` https://github.com/${forkOwner}/${displayForkRepo}`);
176
+ await log(' but NOT in the main repository:');
177
+ await log(` https://github.com/${owner}/${repo}`);
178
+ await log(' You need to use --fork to work with your fork.');
179
+ } else if (userHasFork) {
180
+ await log(' You have a fork of this repository, but the PR branch');
181
+ await log(` '${branchName}' doesn't exist in either the main repository`);
182
+ await log(' or your fork. It may have been deleted or renamed.');
183
+ } else {
184
+ await log(` • The branch '${branchName}' doesn't exist in https://github.com/${owner}/${repo}`);
185
+ await log(' • This might be a PR from a fork (use --fork option)');
186
+ await log(' • Or the branch may have been deleted/renamed');
187
+ }
188
+ await log('');
189
+
190
+ // Provide clear solutions
191
+ await log(' 🔧 How to fix this:');
192
+
193
+ if (isForkPR || suggestForkOption) {
194
+ await log('');
195
+ await log(' ┌──────────────────────────────────────────────────────────┐');
196
+ await log(' │ RECOMMENDED: Use the --fork option │');
197
+ await log(' └──────────────────────────────────────────────────────────┘');
198
+ await log('');
199
+ await log(' Run this command:');
200
+ const fullUrl = prNumber ? `https://github.com/${owner}/${repo}/pull/${prNumber}` : issueUrl;
201
+ await log(` ./solve.mjs "${fullUrl}" --fork`);
202
+ await log('');
203
+ await log(' This will automatically:');
204
+ if (userHasFork) {
205
+ // Use forkRepoName if available, otherwise default to repo
206
+ const displayForkRepo = forkRepoName || repo;
207
+ await log(` ✓ Use your existing fork (${forkOwner}/${displayForkRepo})`);
208
+ } else if (isForkPR && forkOwner) {
209
+ await log(' ✓ Work with the fork that contains the PR branch');
210
+ } else {
211
+ await log(' ✓ Create or use a fork of the repository');
212
+ }
213
+ await log(' ✓ Set up the correct remotes and branches');
214
+ await log(' ✓ Allow you to work on the PR without permission issues');
215
+ await log('');
216
+ await log(' ─────────────────────────────────────────────────────────');
217
+ await log('');
218
+ await log(' Alternative options:');
219
+ await log(` • Verify PR details: gh pr view ${prNumber} --repo ${owner}/${repo}`);
220
+ await log(` • Check your local setup: cd ${tempDir} && git remote -v`);
221
+ } else {
222
+ await log(` 1. Verify PR branch exists: gh pr view ${prNumber} --repo ${owner}/${repo}`);
223
+ await log(` 2. Check remote branches: cd ${tempDir} && git branch -r`);
224
+ await log(` 3. Try fetching manually: cd ${tempDir} && git fetch origin`);
225
+ await log('');
226
+ await log(' If you don\'t have write access to this repository,');
227
+ await log(' consider using the --fork option:');
228
+ const altFullUrl = prNumber ? `https://github.com/${owner}/${repo}/pull/${prNumber}` : issueUrl;
229
+ await log(` ./solve.mjs "${altFullUrl}" --fork`);
230
+ }
231
+ }
232
+
233
+ export async function handleBranchCreationError({
234
+ branchName,
235
+ errorOutput,
236
+ tempDir,
237
+ owner,
238
+ repo,
239
+ formatAligned,
240
+ log
241
+ }) {
242
+ await log(`${formatAligned('❌', 'BRANCH CREATION FAILED', '')}`, { level: 'error' });
243
+ await log('');
244
+ await log(' 🔍 What happened:');
245
+ await log(` Unable to create branch '${branchName}'.`);
246
+ if (owner && repo) {
247
+ await log(` Repository: https://github.com/${owner}/${repo}`);
248
+ }
249
+ await log('');
250
+ await log(' 📦 Git output:');
251
+ for (const line of errorOutput.split('\n')) {
252
+ await log(` ${line}`);
253
+ }
254
+ await log('');
255
+ await log(' 💡 Possible causes:');
256
+ await log(' • Branch name already exists');
257
+ await log(' • Uncommitted changes in repository');
258
+ await log(' • Git configuration issues');
259
+ await log('');
260
+ await log(' 🔧 How to fix:');
261
+ await log(' 1. Try running the command again (uses random names)');
262
+ await log(` 2. Check git status: cd ${tempDir} && git status`);
263
+ await log(` 3. View existing branches: cd ${tempDir} && git branch -a`);
264
+ }
265
+
266
+ export async function handleBranchVerificationError({
267
+ isContinueMode,
268
+ branchName,
269
+ actualBranch,
270
+ prNumber,
271
+ owner,
272
+ repo,
273
+ tempDir,
274
+ formatAligned,
275
+ log,
276
+ $
277
+ }) {
278
+ await log('');
279
+ await log(`${formatAligned('❌', isContinueMode ? 'BRANCH CHECKOUT FAILED' : 'BRANCH CREATION FAILED', '')}`, { level: 'error' });
280
+ await log('');
281
+ await log(' 🔍 What happened:');
282
+ if (isContinueMode) {
283
+ await log(' Git checkout command didn\'t switch to the PR branch.');
284
+ } else {
285
+ await log(' Git checkout -b command didn\'t create or switch to the branch.');
286
+ }
287
+ if (owner && repo) {
288
+ await log(` Repository: https://github.com/${owner}/${repo}`);
289
+ if (prNumber) {
290
+ await log(` Pull Request: https://github.com/${owner}/${repo}/pull/${prNumber}`);
291
+ }
292
+ }
293
+ await log('');
294
+ await log(' 📊 Branch status:');
295
+ await log(` Expected branch: ${branchName}`);
296
+ await log(` Currently on: ${actualBranch || '(unknown)'}`);
297
+ await log('');
298
+
299
+ // Show all branches to help debug
300
+ const allBranchesResult = await $({ cwd: tempDir })`git branch -a 2>&1`;
301
+ if (allBranchesResult.code === 0) {
302
+ await log(' 🌿 Available branches:');
303
+ for (const line of allBranchesResult.stdout.toString().split('\n')) {
304
+ if (line.trim()) await log(` ${line}`);
305
+ }
306
+ await log('');
307
+ }
308
+
309
+ if (isContinueMode) {
310
+ await log(' 💡 This might mean:');
311
+ await log(' • PR branch doesn\'t exist on remote');
312
+ await log(' • Branch name mismatch');
313
+ await log(' • Network/permission issues');
314
+ await log('');
315
+ await log(' 🔧 How to fix:');
316
+ await log(` 1. Check PR details: gh pr view ${prNumber} --repo ${owner}/${repo}`);
317
+ await log(` 2. List remote branches: cd ${tempDir} && git branch -r`);
318
+ await log(` 3. Try manual checkout: cd ${tempDir} && git checkout ${branchName}`);
319
+ } else {
320
+ await log(' 💡 This is unusual. Possible causes:');
321
+ await log(' • Git version incompatibility');
322
+ await log(' • File system permissions issue');
323
+ await log(' • Repository corruption');
324
+ await log('');
325
+ await log(' 🔧 How to fix:');
326
+ await log(' 1. Try creating the branch manually:');
327
+ await log(` cd ${tempDir}`);
328
+ await log(` git checkout -b ${branchName}`);
329
+ await log(' ');
330
+ await log(' 2. If that fails, try two-step approach:');
331
+ await log(` cd ${tempDir}`);
332
+ await log(` git branch ${branchName}`);
333
+ await log(` git checkout ${branchName}`);
334
+ await log(' ');
335
+ await log(' 3. Check your git version:');
336
+ await log(' git --version');
337
+ }
338
+ await log('');
339
+ await log(` 📂 Working directory: ${tempDir}`);
340
+ await log('');
341
+ }
@@ -0,0 +1,230 @@
1
+ /**
2
+ * Branch creation and checkout functionality for solve.mjs
3
+ * Handles creating new branches or checking out existing PR branches
4
+ */
5
+
6
+ /**
7
+ * Regular expressions for branch name validation
8
+ * Supports both legacy (8-char) and new (12-char) formats
9
+ */
10
+ const branchNameRegex = {
11
+ // Legacy format: issue-{number}-{8-hex-chars}
12
+ legacy: /^issue-(\d+)-([a-f0-9]{8})$/,
13
+ // New format: issue-{number}-{12-hex-chars}
14
+ new: /^issue-(\d+)-([a-f0-9]{12})$/,
15
+ // Combined pattern for both formats
16
+ any: /^issue-(\d+)-([a-f0-9]{8}|[a-f0-9]{12})$/,
17
+ // Pattern for prefix matching: issue-{number}-
18
+ prefix: (issueNumber) => new RegExp(`^issue-${issueNumber}-([a-f0-9]{8}|[a-f0-9]{12})$`)
19
+ };
20
+
21
+ /**
22
+ * Validates if a branch name matches the expected pattern for issue branches
23
+ * @param {string} branchName - The branch name to validate
24
+ * @param {number|string} [issueNumber] - Optional issue number to validate against
25
+ * @returns {boolean} True if branch name is valid
26
+ */
27
+ export function isValidIssueBranchName(branchName, issueNumber = null) {
28
+ if (!branchName || typeof branchName !== 'string') {
29
+ return false;
30
+ }
31
+
32
+ if (issueNumber !== null) {
33
+ // Validate against specific issue number
34
+ const regex = branchNameRegex.prefix(issueNumber);
35
+ return regex.test(branchName);
36
+ }
37
+
38
+ // Validate against any issue branch pattern
39
+ return branchNameRegex.any.test(branchName);
40
+ }
41
+
42
+ /**
43
+ * Extracts issue number and random ID from a branch name
44
+ * @param {string} branchName - The branch name to parse
45
+ * @returns {{issueNumber: string, randomId: string} | null} Parsed components or null if invalid
46
+ */
47
+ export function parseIssueBranchName(branchName) {
48
+ if (!branchName || typeof branchName !== 'string') {
49
+ return null;
50
+ }
51
+
52
+ const match = branchName.match(branchNameRegex.any);
53
+ if (!match) {
54
+ return null;
55
+ }
56
+
57
+ return {
58
+ issueNumber: match[1],
59
+ randomId: match[2]
60
+ };
61
+ }
62
+
63
+ /**
64
+ * Creates the branch name prefix for a given issue number
65
+ * @param {number|string} issueNumber - The issue number
66
+ * @returns {string} The branch name prefix (e.g., "issue-123-")
67
+ */
68
+ export function getIssueBranchPrefix(issueNumber) {
69
+ return `issue-${issueNumber}-`;
70
+ }
71
+
72
+ /**
73
+ * Checks if a branch name matches the expected pattern for a specific issue
74
+ * @param {string} branchName - The branch name to check
75
+ * @param {number|string} issueNumber - The issue number
76
+ * @returns {boolean} True if branch matches the issue pattern
77
+ */
78
+ export function matchesIssuePattern(branchName, issueNumber) {
79
+ return isValidIssueBranchName(branchName, issueNumber);
80
+ }
81
+
82
+ /**
83
+ * Detects if a branch name uses the legacy (8-char) or new (12-char) format
84
+ * @param {string} branchName - The branch name to check
85
+ * @returns {'legacy' | 'new' | null} The format type or null if invalid
86
+ */
87
+ export function detectBranchFormat(branchName) {
88
+ if (!branchName || typeof branchName !== 'string') {
89
+ return null;
90
+ }
91
+
92
+ if (branchNameRegex.new.test(branchName)) {
93
+ return 'new';
94
+ }
95
+
96
+ if (branchNameRegex.legacy.test(branchName)) {
97
+ return 'legacy';
98
+ }
99
+
100
+ return null;
101
+ }
102
+
103
+ export async function createOrCheckoutBranch({
104
+ isContinueMode,
105
+ prBranch,
106
+ issueNumber,
107
+ tempDir,
108
+ defaultBranch,
109
+ argv,
110
+ log,
111
+ formatAligned,
112
+ $,
113
+ crypto
114
+ }) {
115
+ // Create a branch for the issue or checkout existing PR branch
116
+ let branchName;
117
+ let checkoutResult;
118
+
119
+ if (isContinueMode && prBranch) {
120
+ // Continue mode: checkout existing PR branch
121
+ branchName = prBranch;
122
+ const repository = await import('./solve.repository.lib.mjs');
123
+ const { checkoutPrBranch } = repository;
124
+ checkoutResult = await checkoutPrBranch(tempDir, branchName, null, null); // prForkRemote and prForkOwner not needed here
125
+ } else {
126
+ // Traditional mode: create new branch for issue
127
+ const randomHex = crypto.randomBytes(6).toString('hex');
128
+ branchName = `issue-${issueNumber}-${randomHex}`;
129
+ await log(`\n${formatAligned('🌿', 'Creating branch:', `${branchName} from ${defaultBranch}`)}`);
130
+
131
+ // IMPORTANT: Don't use 2>&1 here as it can interfere with exit codes
132
+ // Git checkout -b outputs to stderr but that's normal
133
+ checkoutResult = await $({ cwd: tempDir })`git checkout -b ${branchName}`;
134
+ }
135
+
136
+ if (checkoutResult.code !== 0) {
137
+ const errorOutput = (checkoutResult.stderr || checkoutResult.stdout || 'Unknown error').toString().trim();
138
+ await log('');
139
+
140
+ if (isContinueMode) {
141
+ const branchErrors = await import('./solve.branch-errors.lib.mjs');
142
+ const { handleBranchCheckoutError } = branchErrors;
143
+ await handleBranchCheckoutError({
144
+ branchName,
145
+ prNumber: null, // Will be set later
146
+ errorOutput,
147
+ issueUrl: argv['issue-url'] || argv._[0],
148
+ owner: null, // Will be set later
149
+ repo: null, // Will be set later
150
+ tempDir,
151
+ argv,
152
+ formatAligned,
153
+ log,
154
+ $
155
+ });
156
+ } else {
157
+ const branchErrors = await import('./solve.branch-errors.lib.mjs');
158
+ const { handleBranchCreationError } = branchErrors;
159
+ await handleBranchCreationError({
160
+ branchName,
161
+ errorOutput,
162
+ tempDir,
163
+ owner: null, // Will be set later
164
+ repo: null, // Will be set later
165
+ formatAligned,
166
+ log
167
+ });
168
+ }
169
+
170
+ await log('');
171
+ await log(` 📂 Working directory: ${tempDir}`);
172
+ throw new Error('Branch operation failed');
173
+ }
174
+
175
+ // CRITICAL: Verify the branch was checked out and we switched to it
176
+ await log(`${formatAligned('🔍', 'Verifying:', isContinueMode ? 'Branch checkout...' : 'Branch creation...')}`);
177
+ const verifyResult = await $({ cwd: tempDir })`git branch --show-current`;
178
+
179
+ if (verifyResult.code !== 0 || !verifyResult.stdout) {
180
+ await log('');
181
+ await log(`${formatAligned('❌', 'BRANCH VERIFICATION FAILED', '')}`, { level: 'error' });
182
+ await log('');
183
+ await log(' 🔍 What happened:');
184
+ await log(` Unable to verify branch after ${isContinueMode ? 'checkout' : 'creation'} attempt.`);
185
+ await log('');
186
+ await log(' 🔧 Debug commands to try:');
187
+ await log(` cd ${tempDir} && git branch -a`);
188
+ await log(` cd ${tempDir} && git status`);
189
+ await log('');
190
+ throw new Error('Branch verification failed');
191
+ }
192
+
193
+ const actualBranch = verifyResult.stdout.toString().trim();
194
+ if (actualBranch !== branchName) {
195
+ // Branch wasn't actually created/checked out or we didn't switch to it
196
+ const branchErrors = await import('./solve.branch-errors.lib.mjs');
197
+ const { handleBranchVerificationError } = branchErrors;
198
+ await handleBranchVerificationError({
199
+ isContinueMode,
200
+ branchName,
201
+ actualBranch,
202
+ prNumber: null, // Will be set later
203
+ owner: null, // Will be set later
204
+ repo: null, // Will be set later
205
+ tempDir,
206
+ formatAligned,
207
+ log,
208
+ $
209
+ });
210
+ throw new Error('Branch verification mismatch');
211
+ }
212
+
213
+ if (isContinueMode) {
214
+ await log(`${formatAligned('✅', 'Branch checked out:', branchName)}`);
215
+ await log(`${formatAligned('✅', 'Current branch:', actualBranch)}`);
216
+ if (argv.verbose) {
217
+ await log(' Branch operation: Checkout existing PR branch', { verbose: true });
218
+ await log(` Branch verification: ${actualBranch === branchName ? 'Matches expected' : 'MISMATCH!'}`, { verbose: true });
219
+ }
220
+ } else {
221
+ await log(`${formatAligned('✅', 'Branch created:', branchName)}`);
222
+ await log(`${formatAligned('✅', 'Current branch:', actualBranch)}`);
223
+ if (argv.verbose) {
224
+ await log(' Branch operation: Create new branch', { verbose: true });
225
+ await log(` Branch verification: ${actualBranch === branchName ? 'Matches expected' : 'MISMATCH!'}`, { verbose: true });
226
+ }
227
+ }
228
+
229
+ return branchName;
230
+ }