@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,342 @@
1
+ // CLI configuration module for solve command
2
+ // Extracted from solve.mjs to keep files under 1500 lines
3
+
4
+ // This module expects 'use' to be passed in from the parent module
5
+ // to avoid duplicate use-m initialization issues
6
+
7
+ // Note: Strict options validation is now handled by yargs built-in .strict() mode (see below)
8
+ // This approach was adopted per issue #482 feedback to minimize custom code maintenance
9
+
10
+ // Export an initialization function that accepts 'use'
11
+ export const initializeConfig = async (use) => {
12
+ // Import yargs with specific version for hideBin support
13
+ const yargsModule = await use('yargs@17.7.2');
14
+ const yargs = yargsModule.default || yargsModule;
15
+ const { hideBin } = await use('yargs@17.7.2/helpers');
16
+
17
+ return { yargs, hideBin };
18
+ };
19
+
20
+ // Function to create yargs configuration - avoids duplication
21
+ export const createYargsConfig = (yargsInstance) => {
22
+ return yargsInstance
23
+ .usage('Usage: solve.mjs <issue-url> [options]')
24
+ .command('$0 <issue-url>', 'Solve a GitHub issue or pull request', (yargs) => {
25
+ yargs.positional('issue-url', {
26
+ type: 'string',
27
+ description: 'The GitHub issue URL to solve'
28
+ });
29
+ })
30
+ .fail((msg, err) => {
31
+ // Custom fail handler to suppress yargs error output
32
+ // Errors will be handled in the parseArguments catch block
33
+ if (err) throw err; // Rethrow actual errors
34
+ // For validation errors, throw a clean error object with the message
35
+ const error = new Error(msg);
36
+ error.name = 'YargsValidationError';
37
+ throw error;
38
+ })
39
+ .option('resume', {
40
+ type: 'string',
41
+ description: 'Resume from a previous session ID (when limit was reached)',
42
+ alias: 'r'
43
+ })
44
+ .option('only-prepare-command', {
45
+ type: 'boolean',
46
+ description: 'Only prepare and print the claude command without executing it',
47
+ })
48
+ .option('dry-run', {
49
+ type: 'boolean',
50
+ description: 'Prepare everything but do not execute Claude (alias for --only-prepare-command)',
51
+ alias: 'n'
52
+ })
53
+ .option('skip-tool-connection-check', {
54
+ type: 'boolean',
55
+ description: 'Skip tool connection check (useful in CI environments). Does NOT skip model validation.',
56
+ default: false
57
+ })
58
+ .option('skip-tool-check', {
59
+ type: 'boolean',
60
+ description: 'Alias for --skip-tool-connection-check (deprecated, use --skip-tool-connection-check instead)',
61
+ default: false,
62
+ hidden: true
63
+ })
64
+ .option('skip-claude-check', {
65
+ type: 'boolean',
66
+ description: 'Alias for --skip-tool-connection-check (deprecated)',
67
+ default: false,
68
+ hidden: true
69
+ })
70
+ .option('tool-connection-check', {
71
+ type: 'boolean',
72
+ description: 'Perform tool connection check (enabled by default, use --no-tool-connection-check to skip). Does NOT affect model validation.',
73
+ default: true,
74
+ hidden: true
75
+ })
76
+ .option('tool-check', {
77
+ type: 'boolean',
78
+ description: 'Alias for --tool-connection-check (deprecated)',
79
+ default: true,
80
+ hidden: true
81
+ })
82
+ .option('model', {
83
+ type: 'string',
84
+ description: 'Model to use (for claude: opus, sonnet, haiku, haiku-3-5, haiku-3; for opencode: grok, gpt4o; for codex: gpt5, gpt5-codex, o3; for agent: grok, grok-code, big-pickle)',
85
+ alias: 'm',
86
+ default: (currentParsedArgs) => {
87
+ // Dynamic default based on tool selection
88
+ if (currentParsedArgs?.tool === 'opencode') {
89
+ return 'grok-code-fast-1';
90
+ } else if (currentParsedArgs?.tool === 'codex') {
91
+ return 'gpt-5';
92
+ } else if (currentParsedArgs?.tool === 'agent') {
93
+ return 'grok-code';
94
+ }
95
+ return 'sonnet';
96
+ }
97
+ })
98
+ .option('auto-pull-request-creation', {
99
+ type: 'boolean',
100
+ description: 'Automatically create a draft pull request before running Claude',
101
+ default: true
102
+ })
103
+ .option('verbose', {
104
+ type: 'boolean',
105
+ description: 'Enable verbose logging for debugging',
106
+ alias: 'v',
107
+ default: false
108
+ })
109
+ .option('fork', {
110
+ type: 'boolean',
111
+ description: 'Fork the repository if you don\'t have write access',
112
+ alias: 'f',
113
+ default: false
114
+ })
115
+ .option('auto-fork', {
116
+ type: 'boolean',
117
+ description: 'Automatically fork public repositories without write access (fails for private repos)',
118
+ default: true
119
+ })
120
+ .option('attach-logs', {
121
+ type: 'boolean',
122
+ description: 'Upload the solution draft log file to the Pull Request on completion (āš ļø WARNING: May expose sensitive data)',
123
+ default: false
124
+ })
125
+ .option('auto-close-pull-request-on-fail', {
126
+ type: 'boolean',
127
+ description: 'Automatically close the pull request if execution fails',
128
+ default: false
129
+ })
130
+ .option('auto-continue', {
131
+ type: 'boolean',
132
+ description: 'Continue with existing PR when issue URL is provided (instead of creating new PR)',
133
+ default: true
134
+ })
135
+ .option('auto-continue-on-limit-reset', {
136
+ type: 'boolean',
137
+ description: 'Automatically continue when AI tool limit resets (calculates reset time and waits)',
138
+ default: false
139
+ })
140
+ .option('auto-resume-on-errors', {
141
+ type: 'boolean',
142
+ description: 'Automatically resume on network errors (503, etc.) with exponential backoff',
143
+ default: false
144
+ })
145
+ .option('auto-continue-only-on-new-comments', {
146
+ type: 'boolean',
147
+ description: 'Explicitly fail on absence of new comments in auto-continue or continue mode',
148
+ default: false
149
+ })
150
+ .option('auto-commit-uncommitted-changes', {
151
+ type: 'boolean',
152
+ description: 'Automatically commit and push uncommitted changes made by Claude (disabled by default)',
153
+ default: false
154
+ })
155
+ .option('auto-restart-on-uncommitted-changes', {
156
+ type: 'boolean',
157
+ description: 'Automatically restart when uncommitted changes are detected to allow the tool to handle them (default: true, use --no-auto-restart-on-uncommitted-changes to disable)',
158
+ default: true
159
+ })
160
+ .option('auto-restart-max-iterations', {
161
+ type: 'number',
162
+ description: 'Maximum number of auto-restart iterations when uncommitted changes are detected (default: 3)',
163
+ default: 3
164
+ })
165
+ .option('continue-only-on-feedback', {
166
+ type: 'boolean',
167
+ description: 'Only continue if feedback is detected (works only with pull request link or issue link with --auto-continue)',
168
+ default: false
169
+ })
170
+ .option('watch', {
171
+ type: 'boolean',
172
+ description: 'Monitor continuously for feedback and auto-restart when detected (stops when PR is merged)',
173
+ alias: 'w',
174
+ default: false
175
+ })
176
+ .option('watch-interval', {
177
+ type: 'number',
178
+ description: 'Interval in seconds for checking feedback in watch mode (default: 60)',
179
+ default: 60
180
+ })
181
+ .option('min-disk-space', {
182
+ type: 'number',
183
+ description: 'Minimum required disk space in MB (default: 500)',
184
+ default: 500
185
+ })
186
+ .option('log-dir', {
187
+ type: 'string',
188
+ description: 'Directory to save log files (defaults to current working directory)',
189
+ alias: 'l'
190
+ })
191
+ .option('think', {
192
+ type: 'string',
193
+ description: 'Thinking level: low (Think.), medium (Think hard.), high (Think harder.), max (Ultrathink.)',
194
+ choices: ['low', 'medium', 'high', 'max'],
195
+ default: undefined
196
+ })
197
+ .option('base-branch', {
198
+ type: 'string',
199
+ description: 'Target branch for the pull request (defaults to repository default branch)',
200
+ alias: 'b'
201
+ })
202
+ .option('sentry', {
203
+ type: 'boolean',
204
+ description: 'Enable Sentry error tracking and monitoring (use --no-sentry to disable)',
205
+ default: true
206
+ })
207
+ .option('auto-cleanup', {
208
+ type: 'boolean',
209
+ description: 'Automatically delete temporary working directory on completion (error, success, or CTRL+C). Default: true for private repos, false for public repos. Use explicit flag to override.',
210
+ default: undefined
211
+ })
212
+ .option('auto-merge-default-branch-to-pull-request-branch', {
213
+ type: 'boolean',
214
+ description: 'Automatically merge the default branch to the pull request branch when continuing work (only in continue mode)',
215
+ default: false
216
+ })
217
+ .option('allow-fork-divergence-resolution-using-force-push-with-lease', {
218
+ type: 'boolean',
219
+ description: 'Allow automatic force-push (--force-with-lease) when fork diverges from upstream (DANGEROUS: can overwrite fork history)',
220
+ default: false
221
+ })
222
+ .option('allow-to-push-to-contributors-pull-requests-as-maintainer', {
223
+ type: 'boolean',
224
+ description: 'When continuing a fork PR as a maintainer, attempt to push directly to the contributor\'s fork if "Allow edits by maintainers" is enabled. Requires --auto-fork to be enabled.',
225
+ default: false
226
+ })
227
+ .option('prefix-fork-name-with-owner-name', {
228
+ type: 'boolean',
229
+ description: 'Prefix fork name with original owner name (e.g., "owner-repo" instead of "repo"). Useful when forking repositories with same name from different owners.',
230
+ default: true
231
+ })
232
+ .option('tool', {
233
+ type: 'string',
234
+ description: 'AI tool to use for solving issues',
235
+ choices: ['claude', 'opencode', 'codex', 'agent'],
236
+ default: 'claude'
237
+ })
238
+ .option('interactive-mode', {
239
+ type: 'boolean',
240
+ description: '[EXPERIMENTAL] Post Claude output as PR comments in real-time. Only supported for --tool claude.',
241
+ default: false
242
+ })
243
+ .option('prompt-explore-sub-agent', {
244
+ type: 'boolean',
245
+ description: 'Encourage Claude to use Explore sub-agent for codebase exploration. Only supported for --tool claude.',
246
+ default: false
247
+ })
248
+ .parserConfiguration({
249
+ 'boolean-negation': true
250
+ })
251
+ // Use yargs built-in strict mode to reject unrecognized options
252
+ // This prevents issues like #453 and #482 where unknown options are silently ignored
253
+ .strict()
254
+ .help('h')
255
+ .alias('h', 'help');
256
+ };
257
+
258
+ // Parse command line arguments - now needs yargs and hideBin passed in
259
+ export const parseArguments = async (yargs, hideBin) => {
260
+ const rawArgs = hideBin(process.argv);
261
+ // Use .parse() instead of .argv to ensure .strict() mode works correctly
262
+ // When you call yargs(args) and use .argv, strict mode doesn't trigger
263
+ // See: https://github.com/yargs/yargs/issues - .strict() only works with .parse()
264
+
265
+ let argv;
266
+ try {
267
+ // Suppress stderr output from yargs during parsing to prevent validation errors from appearing
268
+ // This prevents "YError: Not enough arguments" from polluting stderr (issue #583)
269
+ // Save the original stderr.write
270
+ const originalStderrWrite = process.stderr.write;
271
+ const stderrBuffer = [];
272
+
273
+ // Temporarily override stderr.write to capture output
274
+ process.stderr.write = function(chunk, encoding, callback) {
275
+ stderrBuffer.push(chunk.toString());
276
+ // Call the callback if provided (for compatibility)
277
+ if (typeof encoding === 'function') {
278
+ encoding();
279
+ } else if (typeof callback === 'function') {
280
+ callback();
281
+ }
282
+ return true;
283
+ };
284
+
285
+ try {
286
+ argv = await createYargsConfig(yargs()).parse(rawArgs);
287
+ } finally {
288
+ // Always restore stderr.write
289
+ process.stderr.write = originalStderrWrite;
290
+
291
+ // In verbose mode, show what was captured from stderr (for debugging)
292
+ if (global.verboseMode && stderrBuffer.length > 0) {
293
+ const captured = stderrBuffer.join('');
294
+ if (captured.trim()) {
295
+ console.error('[Suppressed yargs stderr]:', captured);
296
+ }
297
+ }
298
+ }
299
+ } catch (error) {
300
+ // Yargs throws errors for validation issues
301
+ // If the error is about unknown arguments (strict mode), re-throw it
302
+ if (error.message && error.message.includes('Unknown arguments')) {
303
+ throw error;
304
+ }
305
+ // For other validation errors, show a warning in verbose mode
306
+ if (error.message && global.verboseMode) {
307
+ console.error('Yargs parsing warning:', error.message);
308
+ }
309
+ // Try to get the argv even with the error
310
+ argv = error.argv || {};
311
+ }
312
+
313
+ // Post-processing: Fix model default for opencode and codex tools
314
+ // Yargs doesn't properly handle dynamic defaults based on other arguments,
315
+ // so we need to handle this manually after parsing
316
+ const modelExplicitlyProvided = rawArgs.includes('--model') || rawArgs.includes('-m');
317
+
318
+ // Normalize alias flags: legacy --skip-tool-check and --skip-claude-check behave like --skip-tool-connection-check
319
+ if (argv) {
320
+ // Support deprecated flags
321
+ if (argv.skipToolCheck || argv.skipClaudeCheck) {
322
+ argv.skipToolConnectionCheck = true;
323
+ }
324
+ // Support negated deprecated flag: --no-tool-check becomes --no-tool-connection-check
325
+ if (argv.toolCheck === false) {
326
+ argv.toolConnectionCheck = false;
327
+ }
328
+ }
329
+
330
+ if (argv.tool === 'opencode' && !modelExplicitlyProvided) {
331
+ // User did not explicitly provide --model, so use the correct default for opencode
332
+ argv.model = 'grok-code-fast-1';
333
+ } else if (argv.tool === 'codex' && !modelExplicitlyProvided) {
334
+ // User did not explicitly provide --model, so use the correct default for codex
335
+ argv.model = 'gpt-5';
336
+ } else if (argv.tool === 'agent' && !modelExplicitlyProvided) {
337
+ // User did not explicitly provide --model, so use the correct default for agent
338
+ argv.model = 'grok-code';
339
+ }
340
+
341
+ return argv;
342
+ };
@@ -0,0 +1,256 @@
1
+ /**
2
+ * Error handling utilities for solve.mjs
3
+ */
4
+
5
+ // Import exit handler
6
+ import { safeExit } from './exit-handler.lib.mjs';
7
+
8
+ // Import Sentry integration
9
+ import { reportError } from './sentry.lib.mjs';
10
+
11
+ // Import GitHub issue creator
12
+ import { handleErrorWithIssueCreation } from './github-issue-creator.lib.mjs';
13
+
14
+ /**
15
+ * Handles log attachment and PR closing on failure
16
+ */
17
+ export const handleFailure = async (options) => {
18
+ const {
19
+ error,
20
+ errorType,
21
+ shouldAttachLogs,
22
+ argv,
23
+ global,
24
+ owner,
25
+ repo,
26
+ log,
27
+ getLogFile,
28
+ attachLogToGitHub,
29
+ cleanErrorMessage,
30
+ sanitizeLogContent,
31
+ $
32
+ } = options;
33
+
34
+ // Offer to create GitHub issue for the error
35
+ try {
36
+ await handleErrorWithIssueCreation({
37
+ error,
38
+ errorType,
39
+ logFile: getLogFile(),
40
+ context: {
41
+ owner: global.owner || owner,
42
+ repo: global.repo || repo,
43
+ prNumber: global.createdPR?.number,
44
+ errorType
45
+ },
46
+ skipPrompt: !process.stdin.isTTY || argv.noIssueCreation
47
+ });
48
+ } catch (issueError) {
49
+ reportError(issueError, {
50
+ context: 'automatic_issue_creation',
51
+ operation: 'handle_error_with_issue_creation'
52
+ });
53
+ await log(`āš ļø Could not create issue: ${issueError.message}`, { level: 'warning' });
54
+ }
55
+
56
+ // If --attach-logs is enabled, try to attach failure logs
57
+ if (shouldAttachLogs && getLogFile() && global.createdPR && global.createdPR.number) {
58
+ await log('\nšŸ“„ Attempting to attach failure logs...');
59
+ try {
60
+ const logUploadSuccess = await attachLogToGitHub({
61
+ logFile: getLogFile(),
62
+ targetType: 'pr',
63
+ targetNumber: global.createdPR.number,
64
+ owner: global.owner || owner,
65
+ repo: global.repo || repo,
66
+ $,
67
+ log,
68
+ sanitizeLogContent,
69
+ verbose: argv.verbose,
70
+ errorMessage: cleanErrorMessage(error)
71
+ });
72
+ if (logUploadSuccess) {
73
+ await log('šŸ“Ž Failure log attached to Pull Request');
74
+ }
75
+ } catch (attachError) {
76
+ reportError(attachError, {
77
+ context: 'attach_failure_log',
78
+ prNumber: global.createdPR?.number,
79
+ errorType,
80
+ operation: 'attach_log_to_pr'
81
+ });
82
+ await log(`āš ļø Could not attach failure log: ${attachError.message}`, { level: 'warning' });
83
+ }
84
+ }
85
+
86
+ // If --auto-close-pull-request-on-fail is enabled, close the PR
87
+ if (argv.autoClosePullRequestOnFail && global.createdPR && global.createdPR.number) {
88
+ await log('\nšŸ”’ Auto-closing pull request due to failure...');
89
+ try {
90
+ const closeMessage = errorType === 'uncaughtException'
91
+ ? 'Auto-closed due to uncaught exception. Logs have been attached for debugging.'
92
+ : errorType === 'unhandledRejection'
93
+ ? 'Auto-closed due to unhandled rejection. Logs have been attached for debugging.'
94
+ : 'Auto-closed due to execution failure. Logs have been attached for debugging.';
95
+
96
+ const result = await $`gh pr close ${global.createdPR.number} --repo ${global.owner || owner}/${global.repo || repo} --comment ${closeMessage}`;
97
+ if (result.exitCode === 0) {
98
+ await log('āœ… Pull request closed successfully');
99
+ }
100
+ } catch (closeError) {
101
+ reportError(closeError, {
102
+ context: 'close_pr_on_failure',
103
+ prNumber: global.createdPR?.number,
104
+ owner,
105
+ repo,
106
+ operation: 'close_pull_request'
107
+ });
108
+ await log(`āš ļø Could not close pull request: ${closeError.message}`, { level: 'warning' });
109
+ }
110
+ }
111
+ };
112
+
113
+ /**
114
+ * Creates an uncaught exception handler
115
+ */
116
+ export const createUncaughtExceptionHandler = (options) => {
117
+ const {
118
+ log,
119
+ cleanErrorMessage,
120
+ absoluteLogPath,
121
+ shouldAttachLogs,
122
+ argv,
123
+ global,
124
+ owner,
125
+ repo,
126
+ getLogFile,
127
+ attachLogToGitHub,
128
+ sanitizeLogContent,
129
+ $
130
+ } = options;
131
+
132
+ return async (error) => {
133
+ await log(`\nāŒ Uncaught Exception: ${cleanErrorMessage(error)}`, { level: 'error' });
134
+ await log(` šŸ“ Full log file: ${absoluteLogPath}`, { level: 'error' });
135
+
136
+ await handleFailure({
137
+ error,
138
+ errorType: 'uncaughtException',
139
+ shouldAttachLogs,
140
+ argv,
141
+ global,
142
+ owner,
143
+ repo,
144
+ log,
145
+ getLogFile,
146
+ attachLogToGitHub,
147
+ cleanErrorMessage,
148
+ sanitizeLogContent,
149
+ $
150
+ });
151
+
152
+ await safeExit(1, 'Error occurred');
153
+ };
154
+ };
155
+
156
+ /**
157
+ * Creates an unhandled rejection handler
158
+ */
159
+ export const createUnhandledRejectionHandler = (options) => {
160
+ const {
161
+ log,
162
+ cleanErrorMessage,
163
+ absoluteLogPath,
164
+ shouldAttachLogs,
165
+ argv,
166
+ global,
167
+ owner,
168
+ repo,
169
+ getLogFile,
170
+ attachLogToGitHub,
171
+ sanitizeLogContent,
172
+ $
173
+ } = options;
174
+
175
+ return async (reason) => {
176
+ await log(`\nāŒ Unhandled Rejection: ${cleanErrorMessage(reason)}`, { level: 'error' });
177
+ await log(` šŸ“ Full log file: ${absoluteLogPath}`, { level: 'error' });
178
+
179
+ await handleFailure({
180
+ error: reason,
181
+ errorType: 'unhandledRejection',
182
+ shouldAttachLogs,
183
+ argv,
184
+ global,
185
+ owner,
186
+ repo,
187
+ log,
188
+ getLogFile,
189
+ attachLogToGitHub,
190
+ cleanErrorMessage,
191
+ sanitizeLogContent,
192
+ $
193
+ });
194
+
195
+ await safeExit(1, 'Error occurred');
196
+ };
197
+ };
198
+
199
+ /**
200
+ * Handles execution errors in the main catch block
201
+ */
202
+ export const handleMainExecutionError = async (options) => {
203
+ const {
204
+ error,
205
+ log,
206
+ cleanErrorMessage,
207
+ absoluteLogPath,
208
+ shouldAttachLogs,
209
+ argv,
210
+ global,
211
+ owner,
212
+ repo,
213
+ getLogFile,
214
+ attachLogToGitHub,
215
+ sanitizeLogContent,
216
+ $
217
+ } = options;
218
+
219
+ // Special handling for authentication errors
220
+ if (error.isAuthError) {
221
+ await log('\nāŒ AUTHENTICATION ERROR', { level: 'error' });
222
+ await log('', { level: 'error' });
223
+ await log(' The AI tool authentication has failed.', { level: 'error' });
224
+ await log(' This error cannot be resolved by retrying.', { level: 'error' });
225
+ await log('', { level: 'error' });
226
+ await log(` Error: ${cleanErrorMessage(error)}`, { level: 'error' });
227
+ await log('', { level: 'error' });
228
+ await log(` šŸ“ Full log file: ${absoluteLogPath}`, { level: 'error' });
229
+
230
+ // Don't try to attach logs or create issues for auth errors
231
+ await safeExit(1, 'Authentication error');
232
+ return;
233
+ }
234
+
235
+ await log('Error executing command:', cleanErrorMessage(error));
236
+ await log(`Stack trace: ${error.stack}`, { verbose: true });
237
+ await log(` šŸ“ Full log file: ${absoluteLogPath}`, { level: 'error' });
238
+
239
+ await handleFailure({
240
+ error,
241
+ errorType: 'execution',
242
+ shouldAttachLogs,
243
+ argv,
244
+ global,
245
+ owner,
246
+ repo,
247
+ log,
248
+ getLogFile,
249
+ attachLogToGitHub,
250
+ cleanErrorMessage,
251
+ sanitizeLogContent,
252
+ $
253
+ });
254
+
255
+ await safeExit(1, 'Error occurred');
256
+ };