@link-assistant/hive-mind 0.46.1 → 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.
- package/CHANGELOG.md +10 -15
- package/README.md +42 -8
- package/package.json +16 -3
- package/src/agent.lib.mjs +49 -70
- package/src/agent.prompts.lib.mjs +6 -20
- package/src/buildUserMention.lib.mjs +4 -17
- package/src/claude-limits.lib.mjs +15 -15
- package/src/claude.lib.mjs +617 -626
- package/src/claude.prompts.lib.mjs +7 -22
- package/src/codex.lib.mjs +39 -71
- package/src/codex.prompts.lib.mjs +6 -20
- package/src/config.lib.mjs +3 -16
- package/src/contributing-guidelines.lib.mjs +5 -18
- package/src/exit-handler.lib.mjs +4 -4
- package/src/git.lib.mjs +7 -7
- package/src/github-issue-creator.lib.mjs +17 -17
- package/src/github-linking.lib.mjs +8 -33
- package/src/github.batch.lib.mjs +20 -16
- package/src/github.graphql.lib.mjs +18 -18
- package/src/github.lib.mjs +89 -91
- package/src/hive.config.lib.mjs +50 -50
- package/src/hive.mjs +1293 -1296
- package/src/instrument.mjs +7 -11
- package/src/interactive-mode.lib.mjs +112 -138
- package/src/lenv-reader.lib.mjs +1 -6
- package/src/lib.mjs +36 -45
- package/src/lino.lib.mjs +2 -2
- package/src/local-ci-checks.lib.mjs +15 -14
- package/src/memory-check.mjs +52 -60
- package/src/model-mapping.lib.mjs +25 -32
- package/src/model-validation.lib.mjs +31 -31
- package/src/opencode.lib.mjs +37 -62
- package/src/opencode.prompts.lib.mjs +7 -21
- package/src/protect-branch.mjs +14 -15
- package/src/review.mjs +28 -27
- package/src/reviewers-hive.mjs +64 -69
- package/src/sentry.lib.mjs +13 -10
- package/src/solve.auto-continue.lib.mjs +48 -38
- package/src/solve.auto-pr.lib.mjs +111 -69
- package/src/solve.branch-errors.lib.mjs +17 -46
- package/src/solve.branch.lib.mjs +16 -23
- package/src/solve.config.lib.mjs +263 -261
- package/src/solve.error-handlers.lib.mjs +21 -79
- package/src/solve.execution.lib.mjs +10 -18
- package/src/solve.feedback.lib.mjs +25 -46
- package/src/solve.mjs +59 -60
- package/src/solve.preparation.lib.mjs +10 -36
- package/src/solve.repo-setup.lib.mjs +4 -19
- package/src/solve.repository.lib.mjs +37 -37
- package/src/solve.results.lib.mjs +32 -46
- package/src/solve.session.lib.mjs +7 -22
- package/src/solve.validation.lib.mjs +19 -17
- package/src/solve.watch.lib.mjs +20 -33
- package/src/start-screen.mjs +24 -24
- package/src/task.mjs +38 -44
- package/src/telegram-bot.mjs +125 -121
- package/src/telegram-top-command.lib.mjs +32 -48
- package/src/usage-limit.lib.mjs +9 -13
- package/src/version-info.lib.mjs +1 -1
- package/src/version.lib.mjs +1 -1
- package/src/youtrack/solve.youtrack.lib.mjs +3 -8
- package/src/youtrack/youtrack-sync.mjs +8 -14
- 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 =
|
|
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 =
|
|
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 =
|
|
22
|
+
export const mapModelToId = model => {
|
|
23
23
|
const modelMap = {
|
|
24
|
-
|
|
24
|
+
gpt5: 'gpt-5',
|
|
25
25
|
'gpt5-codex': 'gpt-5-codex',
|
|
26
|
-
|
|
26
|
+
o3: 'o3',
|
|
27
27
|
'o3-mini': 'o3-mini',
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
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
|
|
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
|
|
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()}`, {
|
|
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()}`, {
|
|
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()}`, {
|
|
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()}`, {
|
|
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 =
|
|
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 =
|
|
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
|
};
|
package/src/config.lib.mjs
CHANGED
|
@@ -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 };
|
package/src/exit-handler.lib.mjs
CHANGED
|
@@ -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',
|
|
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
|
|
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
|
|
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
|
|
27
|
-
return new Promise(
|
|
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): ',
|
|
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
|
|
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
|
|
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
|
+
};
|