@link-assistant/hive-mind 0.46.0 → 0.47.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 +26 -13
  2. package/README.md +42 -8
  3. package/package.json +16 -3
  4. package/src/agent.lib.mjs +49 -70
  5. package/src/agent.prompts.lib.mjs +6 -20
  6. package/src/buildUserMention.lib.mjs +4 -17
  7. package/src/claude-limits.lib.mjs +15 -15
  8. package/src/claude.lib.mjs +617 -626
  9. package/src/claude.prompts.lib.mjs +7 -22
  10. package/src/codex.lib.mjs +39 -71
  11. package/src/codex.prompts.lib.mjs +6 -20
  12. package/src/config.lib.mjs +3 -16
  13. package/src/contributing-guidelines.lib.mjs +5 -18
  14. package/src/exit-handler.lib.mjs +4 -4
  15. package/src/git.lib.mjs +7 -7
  16. package/src/github-issue-creator.lib.mjs +17 -17
  17. package/src/github-linking.lib.mjs +8 -33
  18. package/src/github.batch.lib.mjs +20 -16
  19. package/src/github.graphql.lib.mjs +18 -18
  20. package/src/github.lib.mjs +89 -91
  21. package/src/hive.config.lib.mjs +50 -50
  22. package/src/hive.mjs +1293 -1296
  23. package/src/instrument.mjs +7 -11
  24. package/src/interactive-mode.lib.mjs +112 -138
  25. package/src/lenv-reader.lib.mjs +1 -6
  26. package/src/lib.mjs +36 -45
  27. package/src/lino.lib.mjs +2 -2
  28. package/src/local-ci-checks.lib.mjs +15 -14
  29. package/src/memory-check.mjs +52 -60
  30. package/src/model-mapping.lib.mjs +25 -32
  31. package/src/model-validation.lib.mjs +31 -31
  32. package/src/opencode.lib.mjs +37 -62
  33. package/src/opencode.prompts.lib.mjs +7 -21
  34. package/src/protect-branch.mjs +14 -15
  35. package/src/review.mjs +28 -27
  36. package/src/reviewers-hive.mjs +64 -69
  37. package/src/sentry.lib.mjs +13 -10
  38. package/src/solve.auto-continue.lib.mjs +48 -38
  39. package/src/solve.auto-pr.lib.mjs +111 -69
  40. package/src/solve.branch-errors.lib.mjs +17 -46
  41. package/src/solve.branch.lib.mjs +16 -23
  42. package/src/solve.config.lib.mjs +263 -261
  43. package/src/solve.error-handlers.lib.mjs +21 -79
  44. package/src/solve.execution.lib.mjs +10 -18
  45. package/src/solve.feedback.lib.mjs +25 -46
  46. package/src/solve.mjs +59 -60
  47. package/src/solve.preparation.lib.mjs +10 -36
  48. package/src/solve.repo-setup.lib.mjs +4 -19
  49. package/src/solve.repository.lib.mjs +37 -37
  50. package/src/solve.results.lib.mjs +32 -46
  51. package/src/solve.session.lib.mjs +7 -22
  52. package/src/solve.validation.lib.mjs +19 -17
  53. package/src/solve.watch.lib.mjs +20 -33
  54. package/src/start-screen.mjs +24 -24
  55. package/src/task.mjs +38 -44
  56. package/src/telegram-bot.mjs +125 -121
  57. package/src/telegram-top-command.lib.mjs +32 -48
  58. package/src/usage-limit.lib.mjs +9 -13
  59. package/src/version-info.lib.mjs +1 -1
  60. package/src/version.lib.mjs +1 -1
  61. package/src/youtrack/solve.youtrack.lib.mjs +3 -8
  62. package/src/youtrack/youtrack-sync.mjs +8 -14
  63. package/src/youtrack/youtrack.lib.mjs +26 -28
@@ -8,22 +8,8 @@
8
8
  * @param {Object} params - Parameters for building the user prompt
9
9
  * @returns {string} The formatted user prompt
10
10
  */
11
- export const buildUserPrompt = (params) => {
12
- const {
13
- issueUrl,
14
- issueNumber,
15
- prNumber,
16
- prUrl,
17
- branchName,
18
- tempDir,
19
- isContinueMode,
20
- forkedRepo,
21
- feedbackLines,
22
- owner,
23
- repo,
24
- argv,
25
- contributingGuidelines
26
- } = params;
11
+ export const buildUserPrompt = params => {
12
+ const { issueUrl, issueNumber, prNumber, prUrl, branchName, tempDir, isContinueMode, forkedRepo, feedbackLines, owner, repo, argv, contributingGuidelines } = params;
27
13
 
28
14
  const promptLines = [];
29
15
 
@@ -76,7 +62,7 @@ export const buildUserPrompt = (params) => {
76
62
  low: 'Think.',
77
63
  medium: 'Think hard.',
78
64
  high: 'Think harder.',
79
- max: 'Ultrathink.'
65
+ max: 'Ultrathink.',
80
66
  };
81
67
  promptLines.push(thinkMessages[argv.think]);
82
68
  }
@@ -93,7 +79,7 @@ export const buildUserPrompt = (params) => {
93
79
  * @param {Object} params - Parameters for building the prompt
94
80
  * @returns {string} The formatted system prompt
95
81
  */
96
- export const buildSystemPrompt = (params) => {
82
+ export const buildSystemPrompt = params => {
97
83
  const { owner, repo, issueNumber, prNumber, branchName, argv } = params;
98
84
 
99
85
  // Build thinking instruction based on --think level
@@ -103,7 +89,7 @@ export const buildSystemPrompt = (params) => {
103
89
  low: 'You always think on every step.',
104
90
  medium: 'You always think hard on every step.',
105
91
  high: 'You always think harder on every step.',
106
- max: 'You always ultrathink on every step.'
92
+ max: 'You always ultrathink on every step.',
107
93
  };
108
94
  thinkLine = `\n${thinkMessages[argv.think]}\n`;
109
95
  }
@@ -195,11 +181,10 @@ Self review.
195
181
  - When you check your solution draft, verify git status shows a clean working tree with no uncommitted changes.
196
182
  - When you compare with repo style, use gh pr diff [number].
197
183
  - When you finalize, confirm code, tests, and description are consistent.${argv && argv.promptPlaywrightMcp ? '\n\nPlaywright MCP usage (browser automation via mcp__playwright__* tools).\n - When you develop frontend web applications (HTML, CSS, JavaScript, React, Vue, Angular, etc.), use Playwright MCP tools to test the UI in a real browser.\n - When WebFetch tool fails to retrieve expected content (e.g., returns empty content, JavaScript-rendered pages, or login-protected pages), use Playwright MCP tools (browser_navigate, browser_snapshot) as a fallback for web browsing.\n - When you need to interact with dynamic web pages that require JavaScript execution, use Playwright MCP tools.\n - When you need to visually verify how a web page looks or take screenshots, use browser_take_screenshot from Playwright MCP.\n - When you need to fill forms, click buttons, or perform user interactions on web pages, use Playwright MCP tools (browser_click, browser_type, browser_fill_form).\n - When you need to test responsive design or different viewport sizes, use browser_resize from Playwright MCP.\n - When you finish using the browser, always close it with browser_close to free resources.' : ''}${argv && argv.promptPlanSubAgent ? '\n\nPlan sub-agent usage.\n - When you start working on a task, consider using the Plan sub-agent to research the codebase and create an implementation plan.\n - When using the Plan sub-agent, you can add it as the first item in your todo list.\n - When you delegate planning, use the Task tool with subagent_type="Plan" before starting implementation work.' : ''}`;
198
-
199
184
  };
200
185
 
201
186
  // Export all functions as default object too
202
187
  export default {
203
188
  buildUserPrompt,
204
- buildSystemPrompt
205
- };
189
+ buildSystemPrompt,
190
+ };
package/src/codex.lib.mjs CHANGED
@@ -19,17 +19,17 @@ import { timeouts } from './config.lib.mjs';
19
19
  import { detectUsageLimit, formatUsageLimitMessage } from './usage-limit.lib.mjs';
20
20
 
21
21
  // Model mapping to translate aliases to full model IDs for Codex
22
- export const mapModelToId = (model) => {
22
+ export const mapModelToId = model => {
23
23
  const modelMap = {
24
- 'gpt5': 'gpt-5',
24
+ gpt5: 'gpt-5',
25
25
  'gpt5-codex': 'gpt-5-codex',
26
- 'o3': 'o3',
26
+ o3: 'o3',
27
27
  'o3-mini': 'o3-mini',
28
- 'gpt4': 'gpt-4',
29
- 'gpt4o': 'gpt-4o',
30
- 'claude': 'claude-3-5-sonnet',
31
- 'sonnet': 'claude-3-5-sonnet',
32
- 'opus': 'claude-3-opus',
28
+ gpt4: 'gpt-4',
29
+ gpt4o: 'gpt-4o',
30
+ claude: 'claude-3-5-sonnet',
31
+ sonnet: 'claude-3-5-sonnet',
32
+ opus: 'claude-3-opus',
33
33
  };
34
34
 
35
35
  // Return mapped model ID if it's an alias, otherwise return as-is
@@ -78,8 +78,7 @@ export const validateCodexConnection = async (model = 'gpt-5') => {
78
78
 
79
79
  // Check for authentication errors in both stderr and stdout
80
80
  // Codex CLI may return auth errors in JSON format on stdout
81
- if (stderr.includes('auth') || stderr.includes('login') ||
82
- stdout.includes('Not logged in') || stdout.includes('401 Unauthorized')) {
81
+ if (stderr.includes('auth') || stderr.includes('login') || stdout.includes('Not logged in') || stdout.includes('401 Unauthorized')) {
83
82
  const authError = new Error('Codex authentication failed - 401 Unauthorized');
84
83
  authError.isAuthError = true;
85
84
  await log('❌ Codex authentication failed', { level: 'error' });
@@ -115,28 +114,8 @@ export const handleCodexRuntimeSwitch = async () => {
115
114
  };
116
115
 
117
116
  // Main function to execute Codex with prompts and settings
118
- export const executeCodex = async (params) => {
119
- const {
120
- issueUrl,
121
- issueNumber,
122
- prNumber,
123
- prUrl,
124
- branchName,
125
- tempDir,
126
- isContinueMode,
127
- mergeStateStatus,
128
- forkedRepo,
129
- feedbackLines,
130
- forkActionsUrl,
131
- owner,
132
- repo,
133
- argv,
134
- log,
135
- formatAligned,
136
- getResourceSnapshot,
137
- codexPath = 'codex',
138
- $
139
- } = params;
117
+ export const executeCodex = async params => {
118
+ const { issueUrl, issueNumber, prNumber, prUrl, branchName, tempDir, isContinueMode, mergeStateStatus, forkedRepo, feedbackLines, forkActionsUrl, owner, repo, argv, log, formatAligned, getResourceSnapshot, codexPath = 'codex', $ } = params;
140
119
 
141
120
  // Import prompt building functions from codex.prompts.lib.mjs
142
121
  const { buildUserPrompt, buildSystemPrompt } = await import('./codex.prompts.lib.mjs');
@@ -156,7 +135,7 @@ export const executeCodex = async (params) => {
156
135
  forkActionsUrl,
157
136
  owner,
158
137
  repo,
159
- argv
138
+ argv,
160
139
  });
161
140
 
162
141
  // Build the system prompt
@@ -169,7 +148,7 @@ export const executeCodex = async (params) => {
169
148
  tempDir,
170
149
  isContinueMode,
171
150
  forkedRepo,
172
- argv
151
+ argv,
173
152
  });
174
153
 
175
154
  // Log prompt details in verbose mode
@@ -206,25 +185,12 @@ export const executeCodex = async (params) => {
206
185
  forkedRepo,
207
186
  feedbackLines,
208
187
  codexPath,
209
- $
188
+ $,
210
189
  });
211
190
  };
212
191
 
213
- export const executeCodexCommand = async (params) => {
214
- const {
215
- tempDir,
216
- branchName,
217
- prompt,
218
- systemPrompt,
219
- argv,
220
- log,
221
- formatAligned,
222
- getResourceSnapshot,
223
- forkedRepo,
224
- feedbackLines,
225
- codexPath,
226
- $
227
- } = params;
192
+ export const executeCodexCommand = async params => {
193
+ const { tempDir, branchName, prompt, systemPrompt, argv, log, formatAligned, getResourceSnapshot, forkedRepo, feedbackLines, codexPath, $ } = params;
228
194
 
229
195
  // Retry configuration
230
196
  const maxRetries = 3;
@@ -296,12 +262,12 @@ export const executeCodexCommand = async (params) => {
296
262
  if (argv.resume) {
297
263
  execCommand = $({
298
264
  cwd: tempDir,
299
- mirror: false
265
+ mirror: false,
300
266
  })`cat ${promptFile} | ${codexPath} exec resume ${argv.resume} --json --skip-git-repo-check --dangerously-bypass-approvals-and-sandbox`;
301
267
  } else {
302
268
  execCommand = $({
303
269
  cwd: tempDir,
304
- mirror: false
270
+ mirror: false,
305
271
  })`cat ${promptFile} | ${codexPath} exec --model ${mappedModel} --json --skip-git-repo-check --dangerously-bypass-approvals-and-sandbox`;
306
272
  }
307
273
 
@@ -343,10 +309,7 @@ export const executeCodexCommand = async (params) => {
343
309
 
344
310
  // Check for authentication errors (401 Unauthorized)
345
311
  // These should never be retried as they indicate missing/invalid credentials
346
- if (data.type === 'error' && data.message &&
347
- (data.message.includes('401 Unauthorized') ||
348
- data.message.includes('401') ||
349
- data.message.includes('Unauthorized'))) {
312
+ if (data.type === 'error' && data.message && (data.message.includes('401 Unauthorized') || data.message.includes('401') || data.message.includes('Unauthorized'))) {
350
313
  authError = true;
351
314
  await log('\n❌ Authentication error detected: 401 Unauthorized', { level: 'error' });
352
315
  await log(' This error cannot be resolved by retrying.', { level: 'error' });
@@ -354,10 +317,7 @@ export const executeCodexCommand = async (params) => {
354
317
  }
355
318
 
356
319
  // Also check turn.failed events for auth errors
357
- if (data.type === 'turn.failed' && data.error && data.error.message &&
358
- (data.error.message.includes('401 Unauthorized') ||
359
- data.error.message.includes('401') ||
360
- data.error.message.includes('Unauthorized'))) {
320
+ if (data.type === 'turn.failed' && data.error && data.error.message && (data.error.message.includes('401 Unauthorized') || data.error.message.includes('401') || data.error.message.includes('Unauthorized'))) {
361
321
  authError = true;
362
322
  await log('\n❌ Authentication error detected in turn.failed event', { level: 'error' });
363
323
  await log(' This error cannot be resolved by retrying.', { level: 'error' });
@@ -404,7 +364,7 @@ export const executeCodexCommand = async (params) => {
404
364
  tool: 'Codex',
405
365
  resetTime: limitInfo.resetTime,
406
366
  sessionId,
407
- resumeCommand: sessionId ? `${process.argv[0]} ${process.argv[1]} ${argv.url} --resume ${sessionId}` : null
367
+ resumeCommand: sessionId ? `${process.argv[0]} ${process.argv[1]} ${argv.url} --resume ${sessionId}` : null,
408
368
  });
409
369
 
410
370
  for (const line of messageLines) {
@@ -423,7 +383,7 @@ export const executeCodexCommand = async (params) => {
423
383
  success: false,
424
384
  sessionId,
425
385
  limitReached,
426
- limitResetTime
386
+ limitResetTime,
427
387
  };
428
388
  }
429
389
 
@@ -433,7 +393,7 @@ export const executeCodexCommand = async (params) => {
433
393
  success: true,
434
394
  sessionId,
435
395
  limitReached,
436
- limitResetTime
396
+ limitResetTime,
437
397
  };
438
398
  } catch (error) {
439
399
  // Don't report auth errors to Sentry as they are user configuration issues
@@ -442,7 +402,7 @@ export const executeCodexCommand = async (params) => {
442
402
  context: 'execute_codex',
443
403
  command: params.command,
444
404
  codexPath: params.codexPath,
445
- operation: 'run_codex_command'
405
+ operation: 'run_codex_command',
446
406
  });
447
407
  }
448
408
 
@@ -457,7 +417,7 @@ export const executeCodexCommand = async (params) => {
457
417
  success: false,
458
418
  sessionId: null,
459
419
  limitReached: false,
460
- limitResetTime: null
420
+ limitResetTime: null,
461
421
  };
462
422
  }
463
423
  };
@@ -498,13 +458,19 @@ export const checkForUncommittedChanges = async (tempDir, owner, repo, branchNam
498
458
  if (pushResult.code === 0) {
499
459
  await log('✅ Changes pushed successfully');
500
460
  } else {
501
- await log(`⚠️ Warning: Could not push changes: ${pushResult.stderr?.toString().trim()}`, { level: 'warning' });
461
+ await log(`⚠️ Warning: Could not push changes: ${pushResult.stderr?.toString().trim()}`, {
462
+ level: 'warning',
463
+ });
502
464
  }
503
465
  } else {
504
- await log(`⚠️ Warning: Could not commit changes: ${commitResult.stderr?.toString().trim()}`, { level: 'warning' });
466
+ await log(`⚠️ Warning: Could not commit changes: ${commitResult.stderr?.toString().trim()}`, {
467
+ level: 'warning',
468
+ });
505
469
  }
506
470
  } else {
507
- await log(`⚠️ Warning: Could not stage changes: ${addResult.stderr?.toString().trim()}`, { level: 'warning' });
471
+ await log(`⚠️ Warning: Could not stage changes: ${addResult.stderr?.toString().trim()}`, {
472
+ level: 'warning',
473
+ });
508
474
  }
509
475
  return false;
510
476
  } else if (autoRestartEnabled) {
@@ -528,14 +494,16 @@ export const checkForUncommittedChanges = async (tempDir, owner, repo, branchNam
528
494
  return false;
529
495
  }
530
496
  } else {
531
- await log(`⚠️ Warning: Could not check git status: ${gitStatusResult.stderr?.toString().trim()}`, { level: 'warning' });
497
+ await log(`⚠️ Warning: Could not check git status: ${gitStatusResult.stderr?.toString().trim()}`, {
498
+ level: 'warning',
499
+ });
532
500
  return false;
533
501
  }
534
502
  } catch (gitError) {
535
503
  reportError(gitError, {
536
504
  context: 'check_uncommitted_changes_codex',
537
505
  tempDir,
538
- operation: 'git_status_check'
506
+ operation: 'git_status_check',
539
507
  });
540
508
  await log(`⚠️ Warning: Error checking for uncommitted changes: ${gitError.message}`, { level: 'warning' });
541
509
  return false;
@@ -548,5 +516,5 @@ export default {
548
516
  handleCodexRuntimeSwitch,
549
517
  executeCodex,
550
518
  executeCodexCommand,
551
- checkForUncommittedChanges
519
+ checkForUncommittedChanges,
552
520
  };
@@ -8,22 +8,8 @@
8
8
  * @param {Object} params - Parameters for building the user prompt
9
9
  * @returns {string} The formatted user prompt
10
10
  */
11
- export const buildUserPrompt = (params) => {
12
- const {
13
- issueUrl,
14
- issueNumber,
15
- prNumber,
16
- prUrl,
17
- branchName,
18
- tempDir,
19
- isContinueMode,
20
- forkedRepo,
21
- feedbackLines,
22
- forkActionsUrl,
23
- owner,
24
- repo,
25
- argv
26
- } = params;
11
+ export const buildUserPrompt = params => {
12
+ const { issueUrl, issueNumber, prNumber, prUrl, branchName, tempDir, isContinueMode, forkedRepo, feedbackLines, forkActionsUrl, owner, repo, argv } = params;
27
13
 
28
14
  const promptLines = [];
29
15
 
@@ -70,7 +56,7 @@ export const buildUserPrompt = (params) => {
70
56
  low: 'Think.',
71
57
  medium: 'Think hard.',
72
58
  high: 'Think harder.',
73
- max: 'Ultrathink.'
59
+ max: 'Ultrathink.',
74
60
  };
75
61
  promptLines.push(thinkMessages[argv.think]);
76
62
  }
@@ -87,7 +73,7 @@ export const buildUserPrompt = (params) => {
87
73
  * @param {Object} params - Parameters for building the prompt
88
74
  * @returns {string} The formatted system prompt
89
75
  */
90
- export const buildSystemPrompt = (params) => {
76
+ export const buildSystemPrompt = params => {
91
77
  const { owner, repo, issueNumber, prNumber, branchName, argv } = params;
92
78
 
93
79
  // Build thinking instruction based on --think level
@@ -97,7 +83,7 @@ export const buildSystemPrompt = (params) => {
97
83
  low: 'You always think on every step.',
98
84
  medium: 'You always think hard on every step.',
99
85
  high: 'You always think harder on every step.',
100
- max: 'You always ultrathink on every step.'
86
+ max: 'You always ultrathink on every step.',
101
87
  };
102
88
  thinkLine = `\n${thinkMessages[argv.think]}\n`;
103
89
  }
@@ -190,5 +176,5 @@ Self review.
190
176
  // Export all functions as default object too
191
177
  export default {
192
178
  buildUserPrompt,
193
- buildSystemPrompt
179
+ buildSystemPrompt,
194
180
  };
@@ -144,15 +144,7 @@ export const version = {
144
144
  // Helper function to validate configuration values
145
145
  export function validateConfig() {
146
146
  // Ensure all numeric values are valid
147
- const numericConfigs = [
148
- ...Object.values(timeouts),
149
- ...Object.values(githubLimits),
150
- ...Object.values(systemLimits),
151
- ...Object.values(retryLimits).filter(v => typeof v === 'number'),
152
- ...Object.values(textProcessing),
153
- display.labelWidth,
154
- autoContinue.ageThresholdHours,
155
- ];
147
+ const numericConfigs = [...Object.values(timeouts), ...Object.values(githubLimits), ...Object.values(systemLimits), ...Object.values(retryLimits).filter(v => typeof v === 'number'), ...Object.values(textProcessing), display.labelWidth, autoContinue.ageThresholdHours];
156
148
 
157
149
  for (const value of numericConfigs) {
158
150
  if (isNaN(value) || value < 0) {
@@ -161,12 +153,7 @@ export function validateConfig() {
161
153
  }
162
154
 
163
155
  // Ensure sample rates are between 0 and 1
164
- const sampleRates = [
165
- sentry.tracesSampleRateDev,
166
- sentry.tracesSampleRateProd,
167
- sentry.profileSessionSampleRateDev,
168
- sentry.profileSessionSampleRateProd,
169
- ];
156
+ const sampleRates = [sentry.tracesSampleRateDev, sentry.tracesSampleRateProd, sentry.profileSessionSampleRateDev, sentry.profileSessionSampleRateProd];
170
157
 
171
158
  for (const rate of sampleRates) {
172
159
  if (isNaN(rate) || rate < 0 || rate > 1) {
@@ -204,4 +191,4 @@ export function getAllConfigurations() {
204
191
  export function printConfiguration() {
205
192
  console.log('Current Configuration:');
206
193
  console.log(JSON.stringify(getAllConfigurations(), null, 2));
207
- }
194
+ }
@@ -14,25 +14,12 @@ const { $ } = await use('command-stream');
14
14
  /**
15
15
  * Common paths where contributing guidelines might be found
16
16
  */
17
- const CONTRIBUTING_PATHS = [
18
- 'CONTRIBUTING.md',
19
- 'CONTRIBUTING',
20
- 'docs/CONTRIBUTING.md',
21
- 'docs/contributing.md',
22
- '.github/CONTRIBUTING.md',
23
- 'CONTRIBUTE.md',
24
- 'docs/contribute.md'
25
- ];
17
+ const CONTRIBUTING_PATHS = ['CONTRIBUTING.md', 'CONTRIBUTING', 'docs/CONTRIBUTING.md', 'docs/contributing.md', '.github/CONTRIBUTING.md', 'CONTRIBUTE.md', 'docs/contribute.md'];
26
18
 
27
19
  /**
28
20
  * Common documentation URLs patterns
29
21
  */
30
- const DOCS_PATTERNS = [
31
- 'readthedocs.io',
32
- 'github.io',
33
- '/docs/',
34
- '/documentation/'
35
- ];
22
+ const DOCS_PATTERNS = ['readthedocs.io', 'github.io', '/docs/', '/documentation/'];
36
23
 
37
24
  /**
38
25
  * Detect contributing guidelines in a repository
@@ -46,7 +33,7 @@ export async function detectContributingGuidelines(owner, repo) {
46
33
  path: null,
47
34
  url: null,
48
35
  content: null,
49
- docsUrl: null
36
+ docsUrl: null,
50
37
  };
51
38
 
52
39
  // Try to find CONTRIBUTING file in the repo
@@ -124,7 +111,7 @@ export function extractCIRequirements(content) {
124
111
  linters: [],
125
112
  testCommands: [],
126
113
  styleGuide: [],
127
- preCommitChecks: []
114
+ preCommitChecks: [],
128
115
  };
129
116
 
130
117
  if (!content) return requirements;
@@ -260,7 +247,7 @@ export async function checkWorkflowApprovalStatus(owner, repo) {
260
247
  return {
261
248
  hasApprovalRequired: approvalRequiredRuns.length > 0,
262
249
  runs: approvalRequiredRuns,
263
- totalRuns: runs.length
250
+ totalRuns: runs.length,
264
251
  };
265
252
  } catch (err) {
266
253
  return { hasApprovalRequired: false, runs: [], error: err.message };
@@ -85,7 +85,7 @@ export const safeExit = async (code = 0, reason = 'Process completed') => {
85
85
  */
86
86
  export const installGlobalExitHandlers = () => {
87
87
  // Handle normal exit
88
- process.on('exit', (code) => {
88
+ process.on('exit', code => {
89
89
  // Synchronous fallback - can't use async here
90
90
  if (!exitMessageShown && getLogPathFunction) {
91
91
  try {
@@ -149,7 +149,7 @@ export const installGlobalExitHandlers = () => {
149
149
  });
150
150
 
151
151
  // Handle uncaught exceptions
152
- process.on('uncaughtException', async (error) => {
152
+ process.on('uncaughtException', async error => {
153
153
  if (cleanupFunction) {
154
154
  try {
155
155
  await cleanupFunction();
@@ -173,7 +173,7 @@ export const installGlobalExitHandlers = () => {
173
173
  });
174
174
 
175
175
  // Handle unhandled rejections
176
- process.on('unhandledRejection', async (reason) => {
176
+ process.on('unhandledRejection', async reason => {
177
177
  if (cleanupFunction) {
178
178
  try {
179
179
  await cleanupFunction();
@@ -202,4 +202,4 @@ export const installGlobalExitHandlers = () => {
202
202
  */
203
203
  export const resetExitHandler = () => {
204
204
  exitMessageShown = false;
205
- };
205
+ };
package/src/git.lib.mjs CHANGED
@@ -12,7 +12,7 @@ export const isGitRepository = async (execFunc = execAsync) => {
12
12
  try {
13
13
  await execFunc('git rev-parse --git-dir', {
14
14
  encoding: 'utf8',
15
- env: process.env
15
+ env: process.env,
16
16
  });
17
17
  return true;
18
18
  } catch {
@@ -25,7 +25,7 @@ export const getGitTag = async (execFunc = execAsync) => {
25
25
  try {
26
26
  const { stdout } = await execFunc('git describe --exact-match --tags HEAD', {
27
27
  encoding: 'utf8',
28
- env: process.env
28
+ env: process.env,
29
29
  });
30
30
  return stdout.trim();
31
31
  } catch {
@@ -38,7 +38,7 @@ export const getLatestGitTag = async (execFunc = execAsync) => {
38
38
  try {
39
39
  const { stdout } = await execFunc('git describe --tags --abbrev=0', {
40
40
  encoding: 'utf8',
41
- env: process.env
41
+ env: process.env,
42
42
  });
43
43
  return stdout.trim().replace(/^v/, '');
44
44
  } catch {
@@ -51,7 +51,7 @@ export const getCommitSha = async (execFunc = execAsync) => {
51
51
  try {
52
52
  const { stdout } = await execFunc('git rev-parse --short HEAD', {
53
53
  encoding: 'utf8',
54
- env: process.env
54
+ env: process.env,
55
55
  });
56
56
  return stdout.trim();
57
57
  } catch {
@@ -62,7 +62,7 @@ export const getCommitSha = async (execFunc = execAsync) => {
62
62
  // Helper function to get version string based on git state
63
63
  export const getGitVersion = async (execFunc = execAsync, currentVersion) => {
64
64
  // First check if we're in a git repository
65
- if (!await isGitRepository(execFunc)) {
65
+ if (!(await isGitRepository(execFunc))) {
66
66
  return currentVersion;
67
67
  }
68
68
 
@@ -141,5 +141,5 @@ export default {
141
141
  getLatestGitTag,
142
142
  getCommitSha,
143
143
  getGitVersion,
144
- getGitVersionAsync
145
- };
144
+ getGitVersionAsync,
145
+ };
@@ -23,11 +23,11 @@ const GITHUB_FILE_MAX_SIZE = 10 * 1024 * 1024;
23
23
  * @param {string} errorMessage - The error message to display
24
24
  * @returns {Promise<boolean>} True if user agrees, false otherwise
25
25
  */
26
- export const promptUserForIssueCreation = async (errorMessage) => {
27
- return new Promise((resolve) => {
26
+ export const promptUserForIssueCreation = async errorMessage => {
27
+ return new Promise(resolve => {
28
28
  const rl = createInterface({
29
29
  input: process.stdin,
30
- output: process.stdout
30
+ output: process.stdout,
31
31
  });
32
32
 
33
33
  console.log('\n❌ An error occurred:');
@@ -37,7 +37,7 @@ export const promptUserForIssueCreation = async (errorMessage) => {
37
37
  console.log('\n✅ Error reported to Sentry successfully');
38
38
  }
39
39
 
40
- rl.question('\n❓ Would you like to create a GitHub issue for this error? (y/n): ', (answer) => {
40
+ rl.question('\n❓ Would you like to create a GitHub issue for this error? (y/n): ', answer => {
41
41
  rl.close();
42
42
  resolve(answer.toLowerCase() === 'y' || answer.toLowerCase() === 'yes');
43
43
  });
@@ -57,7 +57,7 @@ const getCurrentGitHubUser = async () => {
57
57
  } catch (error) {
58
58
  reportError(error, {
59
59
  context: 'get_github_user',
60
- operation: 'gh_api_user'
60
+ operation: 'gh_api_user',
61
61
  });
62
62
  }
63
63
  return null;
@@ -83,7 +83,7 @@ const createSecretGist = async (logContent, filename) => {
83
83
  } catch (error) {
84
84
  reportError(error, {
85
85
  context: 'create_secret_gist',
86
- operation: 'gh_gist_create'
86
+ operation: 'gh_gist_create',
87
87
  });
88
88
  }
89
89
  return null;
@@ -101,14 +101,14 @@ export const formatLogForIssue = async (logContent, logFilePath) => {
101
101
  if (logSize < GITHUB_ISSUE_BODY_MAX_SIZE) {
102
102
  return {
103
103
  method: 'inline',
104
- content: `\`\`\`\n${logContent}\n\`\`\``
104
+ content: `\`\`\`\n${logContent}\n\`\`\``,
105
105
  };
106
106
  }
107
107
 
108
108
  if (logSize < GITHUB_FILE_MAX_SIZE) {
109
109
  return {
110
110
  method: 'file',
111
- content: `Log file is too large to include inline. Please see the attached log file.\n\nLog file path: \`${logFilePath}\``
111
+ content: `Log file is too large to include inline. Please see the attached log file.\n\nLog file path: \`${logFilePath}\``,
112
112
  };
113
113
  }
114
114
 
@@ -116,13 +116,13 @@ export const formatLogForIssue = async (logContent, logFilePath) => {
116
116
  if (gistUrl) {
117
117
  return {
118
118
  method: 'gist',
119
- content: `Log file is too large for inline attachment.\n\n📄 View full log: ${gistUrl}`
119
+ content: `Log file is too large for inline attachment.\n\n📄 View full log: ${gistUrl}`,
120
120
  };
121
121
  }
122
122
 
123
123
  return {
124
124
  method: 'truncated',
125
- content: `Log file is too large. Showing last 5000 characters:\n\n\`\`\`\n${logContent.slice(-5000)}\n\`\`\``
125
+ content: `Log file is too large. Showing last 5000 characters:\n\n\`\`\`\n${logContent.slice(-5000)}\n\`\`\``,
126
126
  };
127
127
  };
128
128
 
@@ -135,7 +135,7 @@ export const formatLogForIssue = async (logContent, logFilePath) => {
135
135
  * @param {Object} options.context - Additional context about the error
136
136
  * @returns {Promise<string|null>} Issue URL or null on failure
137
137
  */
138
- export const createIssueForError = async (options) => {
138
+ export const createIssueForError = async options => {
139
139
  const { error, errorType, logFile, context = {} } = options;
140
140
 
141
141
  try {
@@ -180,7 +180,7 @@ export const createIssueForError = async (options) => {
180
180
  reportError(readError, {
181
181
  context: 'read_log_file',
182
182
  operation: 'fs_read_file',
183
- logFile
183
+ logFile,
184
184
  });
185
185
  issueBody += `### Log File\n\nCould not read log file: ${logFile}\n\n`;
186
186
  }
@@ -208,7 +208,7 @@ export const createIssueForError = async (options) => {
208
208
  reportError(createError, {
209
209
  context: 'create_github_issue',
210
210
  operation: 'gh_issue_create',
211
- originalError: error.message
211
+ originalError: error.message,
212
212
  });
213
213
  await log(`❌ Error creating issue: ${cleanErrorMessage(createError)}`, { level: 'error' });
214
214
  return null;
@@ -225,7 +225,7 @@ export const createIssueForError = async (options) => {
225
225
  * @param {boolean} options.skipPrompt - Skip user prompt (for non-interactive mode)
226
226
  * @returns {Promise<string|null>} Issue URL if created, null otherwise
227
227
  */
228
- export const handleErrorWithIssueCreation = async (options) => {
228
+ export const handleErrorWithIssueCreation = async options => {
229
229
  const { error, errorType, logFile, context = {}, skipPrompt = false } = options;
230
230
 
231
231
  if (skipPrompt) {
@@ -240,7 +240,7 @@ export const handleErrorWithIssueCreation = async (options) => {
240
240
  return await createIssueForError({
241
241
  error,
242
242
  errorType,
243
- logFile: logFile || await getAbsoluteLogPath(),
244
- context
243
+ logFile: logFile || (await getAbsoluteLogPath()),
244
+ context,
245
245
  });
246
- };
246
+ };