@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.
- package/CHANGELOG.md +26 -13
- 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
package/src/solve.mjs
CHANGED
|
@@ -133,7 +133,7 @@ if (argv.sentry) {
|
|
|
133
133
|
await initializeSentry({
|
|
134
134
|
noSentry: !argv.sentry,
|
|
135
135
|
debug: argv.verbose,
|
|
136
|
-
version: process.env.npm_package_version || '0.12.0'
|
|
136
|
+
version: process.env.npm_package_version || '0.12.0',
|
|
137
137
|
});
|
|
138
138
|
// Add breadcrumb for solve operation
|
|
139
139
|
addBreadcrumb({
|
|
@@ -142,8 +142,8 @@ if (argv.sentry) {
|
|
|
142
142
|
level: 'info',
|
|
143
143
|
data: {
|
|
144
144
|
model: argv.model,
|
|
145
|
-
issueUrl: argv['issue-url'] || argv._?.[0] || 'not-set-yet'
|
|
146
|
-
}
|
|
145
|
+
issueUrl: argv['issue-url'] || argv._?.[0] || 'not-set-yet',
|
|
146
|
+
},
|
|
147
147
|
});
|
|
148
148
|
}
|
|
149
149
|
// Create a cleanup wrapper that will be populated with context later
|
|
@@ -186,11 +186,11 @@ const errorHandlerOptions = {
|
|
|
186
186
|
argv,
|
|
187
187
|
global,
|
|
188
188
|
owner: null, // Will be set later when parsed
|
|
189
|
-
repo: null,
|
|
189
|
+
repo: null, // Will be set later when parsed
|
|
190
190
|
getLogFile,
|
|
191
191
|
attachLogToGitHub,
|
|
192
192
|
sanitizeLogContent,
|
|
193
|
-
|
|
193
|
+
$,
|
|
194
194
|
};
|
|
195
195
|
process.on('uncaughtException', createUncaughtExceptionHandler(errorHandlerOptions));
|
|
196
196
|
process.on('unhandledRejection', createUnhandledRejectionHandler(errorHandlerOptions));
|
|
@@ -247,12 +247,14 @@ if (argv.autoFork && !argv.fork) {
|
|
|
247
247
|
if (!isPublic) {
|
|
248
248
|
// Private repository without write access - cannot fork
|
|
249
249
|
await log('');
|
|
250
|
-
await log(
|
|
250
|
+
await log("❌ --auto-fork failed: Repository is private and you don't have write access", { level: 'error' });
|
|
251
251
|
await log('');
|
|
252
252
|
await log(' 🔍 What happened:', { level: 'error' });
|
|
253
253
|
await log(` Repository ${owner}/${repo} is private`, { level: 'error' });
|
|
254
|
-
await log(
|
|
255
|
-
await log(' --auto-fork cannot create a fork of a private repository you cannot access', {
|
|
254
|
+
await log(" You don't have write access to this repository", { level: 'error' });
|
|
255
|
+
await log(' --auto-fork cannot create a fork of a private repository you cannot access', {
|
|
256
|
+
level: 'error',
|
|
257
|
+
});
|
|
256
258
|
await log('');
|
|
257
259
|
await log(' 💡 Solution:', { level: 'error' });
|
|
258
260
|
await log(' • Request collaborator access from the repository owner', { level: 'error' });
|
|
@@ -284,7 +286,7 @@ if (argv.autoFork && !argv.fork) {
|
|
|
284
286
|
await log('');
|
|
285
287
|
await log(' 💡 Solutions:', { level: 'error' });
|
|
286
288
|
await log(' • Check your GitHub CLI authentication: gh auth status', { level: 'error' });
|
|
287
|
-
await log(
|
|
289
|
+
await log(" • Request collaborator access if you don't have it yet", { level: 'error' });
|
|
288
290
|
await log(` https://github.com/${owner}/${repo}/settings/access`, { level: 'error' });
|
|
289
291
|
await log('');
|
|
290
292
|
await safeExit(1, 'Auto-fork failed - cannot verify private repository permissions');
|
|
@@ -301,7 +303,7 @@ if (argv.autoFork && !argv.fork) {
|
|
|
301
303
|
const { checkRepositoryWritePermission } = githubLib;
|
|
302
304
|
const hasWriteAccess = await checkRepositoryWritePermission(owner, repo, {
|
|
303
305
|
useFork: argv.fork,
|
|
304
|
-
issueUrl: issueUrl
|
|
306
|
+
issueUrl: issueUrl,
|
|
305
307
|
});
|
|
306
308
|
|
|
307
309
|
if (!hasWriteAccess) {
|
|
@@ -318,7 +320,9 @@ if (argv.autoCleanup === undefined) {
|
|
|
318
320
|
// For private repos: clean up temp directories (default true)
|
|
319
321
|
argv.autoCleanup = !isPublic;
|
|
320
322
|
if (argv.verbose) {
|
|
321
|
-
await log(` Auto-cleanup default: ${argv.autoCleanup} (repository is ${isPublic ? 'public' : 'private'})`, {
|
|
323
|
+
await log(` Auto-cleanup default: ${argv.autoCleanup} (repository is ${isPublic ? 'public' : 'private'})`, {
|
|
324
|
+
verbose: true,
|
|
325
|
+
});
|
|
322
326
|
}
|
|
323
327
|
}
|
|
324
328
|
// Determine mode and get issue details
|
|
@@ -358,7 +362,7 @@ if (autoContinueResult.isContinueMode) {
|
|
|
358
362
|
if (prCheckData.headRepositoryOwner && prCheckData.headRepositoryOwner.login !== owner) {
|
|
359
363
|
forkOwner = prCheckData.headRepositoryOwner.login;
|
|
360
364
|
// Get actual fork repository name (may be prefixed)
|
|
361
|
-
const forkRepoName =
|
|
365
|
+
const forkRepoName = prCheckData.headRepository && prCheckData.headRepository.name ? prCheckData.headRepository.name : repo;
|
|
362
366
|
await log(`🍴 Detected fork PR from ${forkOwner}/${forkRepoName}`);
|
|
363
367
|
if (argv.verbose) {
|
|
364
368
|
await log(` Fork owner: ${forkOwner}`, { verbose: true });
|
|
@@ -372,10 +376,12 @@ if (autoContinueResult.isContinueMode) {
|
|
|
372
376
|
|
|
373
377
|
if (canModify) {
|
|
374
378
|
await log('✅ Maintainer can push to fork: Enabled by contributor');
|
|
375
|
-
await log(
|
|
379
|
+
await log(" Will push changes directly to contributor's fork instead of creating own fork");
|
|
376
380
|
// Don't disable fork mode, but we'll use the contributor's fork
|
|
377
381
|
} else {
|
|
378
|
-
await log('⚠️ Maintainer cannot push to fork: "Allow edits by maintainers" is not enabled', {
|
|
382
|
+
await log('⚠️ Maintainer cannot push to fork: "Allow edits by maintainers" is not enabled', {
|
|
383
|
+
level: 'warning',
|
|
384
|
+
});
|
|
379
385
|
await log(' Posting comment to request access...', { level: 'warning' });
|
|
380
386
|
await requestMaintainerAccess(owner, repo, prNumber);
|
|
381
387
|
await log(' Comment posted. Proceeding with own fork instead.', { level: 'warning' });
|
|
@@ -392,7 +398,9 @@ if (autoContinueResult.isContinueMode) {
|
|
|
392
398
|
// We have a branch but no PR - we'll use the existing branch and create a PR later
|
|
393
399
|
await log(`🔄 Using existing branch: ${prBranch} (no PR yet - will create one)`);
|
|
394
400
|
if (argv.verbose) {
|
|
395
|
-
await log(' Branch will be checked out and PR will be created during auto-PR creation phase', {
|
|
401
|
+
await log(' Branch will be checked out and PR will be created during auto-PR creation phase', {
|
|
402
|
+
verbose: true,
|
|
403
|
+
});
|
|
396
404
|
}
|
|
397
405
|
}
|
|
398
406
|
} else if (isIssueUrl) {
|
|
@@ -415,7 +423,7 @@ if (isPrUrl) {
|
|
|
415
423
|
prNumber,
|
|
416
424
|
owner,
|
|
417
425
|
repo,
|
|
418
|
-
jsonFields: 'headRefName,body,number,mergeStateStatus,state,headRepositoryOwner,headRepository'
|
|
426
|
+
jsonFields: 'headRefName,body,number,mergeStateStatus,state,headRepositoryOwner,headRepository',
|
|
419
427
|
});
|
|
420
428
|
if (prResult.code !== 0 || !prResult.data) {
|
|
421
429
|
await log('Error: Failed to get PR details', { level: 'error' });
|
|
@@ -434,7 +442,7 @@ if (isPrUrl) {
|
|
|
434
442
|
if (prData.headRepositoryOwner && prData.headRepositoryOwner.login !== owner) {
|
|
435
443
|
forkOwner = prData.headRepositoryOwner.login;
|
|
436
444
|
// Get actual fork repository name (may be prefixed)
|
|
437
|
-
const forkRepoName =
|
|
445
|
+
const forkRepoName = prData.headRepository && prData.headRepository.name ? prData.headRepository.name : repo;
|
|
438
446
|
await log(`🍴 Detected fork PR from ${forkOwner}/${forkRepoName}`);
|
|
439
447
|
if (argv.verbose) {
|
|
440
448
|
await log(` Fork owner: ${forkOwner}`, { verbose: true });
|
|
@@ -448,10 +456,12 @@ if (isPrUrl) {
|
|
|
448
456
|
|
|
449
457
|
if (canModify) {
|
|
450
458
|
await log('✅ Maintainer can push to fork: Enabled by contributor');
|
|
451
|
-
await log(
|
|
459
|
+
await log(" Will push changes directly to contributor's fork instead of creating own fork");
|
|
452
460
|
// Don't disable fork mode, but we'll use the contributor's fork
|
|
453
461
|
} else {
|
|
454
|
-
await log('⚠️ Maintainer cannot push to fork: "Allow edits by maintainers" is not enabled', {
|
|
462
|
+
await log('⚠️ Maintainer cannot push to fork: "Allow edits by maintainers" is not enabled', {
|
|
463
|
+
level: 'warning',
|
|
464
|
+
});
|
|
455
465
|
await log(' Posting comment to request access...', { level: 'warning' });
|
|
456
466
|
await requestMaintainerAccess(owner, repo, prNumber);
|
|
457
467
|
await log(' Comment posted. Proceeding with own fork instead.', { level: 'warning' });
|
|
@@ -477,7 +487,7 @@ if (isPrUrl) {
|
|
|
477
487
|
reportError(error, {
|
|
478
488
|
context: 'pr_processing',
|
|
479
489
|
prNumber,
|
|
480
|
-
operation: 'process_pull_request'
|
|
490
|
+
operation: 'process_pull_request',
|
|
481
491
|
});
|
|
482
492
|
await log(`Error: Failed to process PR: ${cleanErrorMessage(error)}`, { level: 'error' });
|
|
483
493
|
await safeExit(1, 'Failed to process PR');
|
|
@@ -506,7 +516,7 @@ try {
|
|
|
506
516
|
issueUrl,
|
|
507
517
|
log,
|
|
508
518
|
formatAligned,
|
|
509
|
-
|
|
519
|
+
$,
|
|
510
520
|
});
|
|
511
521
|
|
|
512
522
|
// Verify default branch and status using the new module
|
|
@@ -514,7 +524,7 @@ try {
|
|
|
514
524
|
tempDir,
|
|
515
525
|
log,
|
|
516
526
|
formatAligned,
|
|
517
|
-
|
|
527
|
+
$,
|
|
518
528
|
});
|
|
519
529
|
// Create or checkout branch using the new module
|
|
520
530
|
const branchName = await createOrCheckoutBranch({
|
|
@@ -527,7 +537,7 @@ try {
|
|
|
527
537
|
log,
|
|
528
538
|
formatAligned,
|
|
529
539
|
$,
|
|
530
|
-
crypto
|
|
540
|
+
crypto,
|
|
531
541
|
});
|
|
532
542
|
|
|
533
543
|
// Auto-merge default branch to pull request branch if enabled
|
|
@@ -593,7 +603,7 @@ try {
|
|
|
593
603
|
$,
|
|
594
604
|
reportError,
|
|
595
605
|
path,
|
|
596
|
-
fs
|
|
606
|
+
fs,
|
|
597
607
|
});
|
|
598
608
|
|
|
599
609
|
let claudeCommitHash = null;
|
|
@@ -653,7 +663,7 @@ try {
|
|
|
653
663
|
await log(`\n${formatAligned('⏭️', 'Auto PR creation:', 'DISABLED')}`);
|
|
654
664
|
await log(formatAligned('', 'Workflow:', 'AI will create the PR', 2));
|
|
655
665
|
}
|
|
656
|
-
|
|
666
|
+
|
|
657
667
|
// Don't build the prompt yet - we'll build it after we have all the information
|
|
658
668
|
// This includes PR URL (if created) and comment info (if in continue mode)
|
|
659
669
|
|
|
@@ -664,7 +674,7 @@ try {
|
|
|
664
674
|
argv,
|
|
665
675
|
log,
|
|
666
676
|
formatAligned,
|
|
667
|
-
|
|
677
|
+
$,
|
|
668
678
|
});
|
|
669
679
|
|
|
670
680
|
// Prepare feedback and timestamps using the new module
|
|
@@ -681,7 +691,7 @@ try {
|
|
|
681
691
|
log,
|
|
682
692
|
formatAligned,
|
|
683
693
|
cleanErrorMessage,
|
|
684
|
-
|
|
694
|
+
$,
|
|
685
695
|
});
|
|
686
696
|
|
|
687
697
|
// Initialize feedback lines
|
|
@@ -708,7 +718,7 @@ try {
|
|
|
708
718
|
tempDir,
|
|
709
719
|
argv,
|
|
710
720
|
log,
|
|
711
|
-
|
|
721
|
+
$,
|
|
712
722
|
});
|
|
713
723
|
if (uncommittedFeedbackLines && uncommittedFeedbackLines.length > 0) {
|
|
714
724
|
if (!feedbackLines) {
|
|
@@ -724,7 +734,7 @@ try {
|
|
|
724
734
|
branchName,
|
|
725
735
|
log,
|
|
726
736
|
formatAligned,
|
|
727
|
-
|
|
737
|
+
$,
|
|
728
738
|
});
|
|
729
739
|
|
|
730
740
|
// Execute tool command with all prompts and settings
|
|
@@ -755,7 +765,7 @@ try {
|
|
|
755
765
|
formatAligned,
|
|
756
766
|
getResourceSnapshot,
|
|
757
767
|
opencodePath,
|
|
758
|
-
|
|
768
|
+
$,
|
|
759
769
|
});
|
|
760
770
|
} else if (argv.tool === 'codex') {
|
|
761
771
|
const codexLib = await import('./codex.lib.mjs');
|
|
@@ -783,7 +793,7 @@ try {
|
|
|
783
793
|
formatAligned,
|
|
784
794
|
getResourceSnapshot,
|
|
785
795
|
codexPath,
|
|
786
|
-
|
|
796
|
+
$,
|
|
787
797
|
});
|
|
788
798
|
} else if (argv.tool === 'agent') {
|
|
789
799
|
const agentLib = await import('./agent.lib.mjs');
|
|
@@ -811,7 +821,7 @@ try {
|
|
|
811
821
|
formatAligned,
|
|
812
822
|
getResourceSnapshot,
|
|
813
823
|
agentPath,
|
|
814
|
-
|
|
824
|
+
$,
|
|
815
825
|
});
|
|
816
826
|
} else {
|
|
817
827
|
// Default to Claude
|
|
@@ -848,7 +858,7 @@ try {
|
|
|
848
858
|
formatAligned,
|
|
849
859
|
getResourceSnapshot,
|
|
850
860
|
claudePath,
|
|
851
|
-
|
|
861
|
+
$,
|
|
852
862
|
});
|
|
853
863
|
toolResult = claudeResult;
|
|
854
864
|
}
|
|
@@ -856,8 +866,8 @@ try {
|
|
|
856
866
|
const { success } = toolResult;
|
|
857
867
|
let sessionId = toolResult.sessionId;
|
|
858
868
|
let anthropicTotalCostUSD = toolResult.anthropicTotalCostUSD;
|
|
859
|
-
let publicPricingEstimate = toolResult.publicPricingEstimate;
|
|
860
|
-
let pricingInfo = toolResult.pricingInfo;
|
|
869
|
+
let publicPricingEstimate = toolResult.publicPricingEstimate; // Used by agent tool
|
|
870
|
+
let pricingInfo = toolResult.pricingInfo; // Used by agent tool for detailed pricing
|
|
861
871
|
limitReached = toolResult.limitReached;
|
|
862
872
|
cleanupContext.limitReached = limitReached;
|
|
863
873
|
|
|
@@ -893,12 +903,9 @@ try {
|
|
|
893
903
|
// Mark this as a usage limit case for proper formatting
|
|
894
904
|
isUsageLimit: true,
|
|
895
905
|
limitResetTime: global.limitResetTime,
|
|
896
|
-
toolName: (argv.tool || 'AI tool').toString().toLowerCase() === 'claude' ? 'Claude' :
|
|
897
|
-
(argv.tool || 'AI tool').toString().toLowerCase() === 'codex' ? 'Codex' :
|
|
898
|
-
(argv.tool || 'AI tool').toString().toLowerCase() === 'opencode' ? 'OpenCode' :
|
|
899
|
-
(argv.tool || 'AI tool').toString().toLowerCase() === 'agent' ? 'Agent' : 'AI tool',
|
|
906
|
+
toolName: (argv.tool || 'AI tool').toString().toLowerCase() === 'claude' ? 'Claude' : (argv.tool || 'AI tool').toString().toLowerCase() === 'codex' ? 'Codex' : (argv.tool || 'AI tool').toString().toLowerCase() === 'opencode' ? 'OpenCode' : (argv.tool || 'AI tool').toString().toLowerCase() === 'agent' ? 'Agent' : 'AI tool',
|
|
900
907
|
resumeCommand,
|
|
901
|
-
sessionId
|
|
908
|
+
sessionId,
|
|
902
909
|
});
|
|
903
910
|
|
|
904
911
|
if (logUploadSuccess) {
|
|
@@ -913,9 +920,7 @@ try {
|
|
|
913
920
|
// Fallback: Post simple failure comment if logs are not attached
|
|
914
921
|
try {
|
|
915
922
|
const resetTime = global.limitResetTime;
|
|
916
|
-
const failureComment = resetTime
|
|
917
|
-
? `❌ **Usage Limit Reached**\n\nThe AI tool has reached its usage limit. The limit will reset at: **${resetTime}**\n\nThis session has failed because \`--auto-continue-on-limit-reset\` was not enabled.\n\nTo automatically wait for the limit to reset and continue, use:\n\`\`\`bash\n./solve.mjs "${issueUrl}" --resume ${sessionId} --auto-continue-on-limit-reset\n\`\`\``
|
|
918
|
-
: `❌ **Usage Limit Reached**\n\nThe AI tool has reached its usage limit. Please wait for the limit to reset.\n\nThis session has failed because \`--auto-continue-on-limit-reset\` was not enabled.\n\nTo resume after the limit resets, use:\n\`\`\`bash\n./solve.mjs "${issueUrl}" --resume ${sessionId}\n\`\`\``;
|
|
923
|
+
const failureComment = resetTime ? `❌ **Usage Limit Reached**\n\nThe AI tool has reached its usage limit. The limit will reset at: **${resetTime}**\n\nThis session has failed because \`--auto-continue-on-limit-reset\` was not enabled.\n\nTo automatically wait for the limit to reset and continue, use:\n\`\`\`bash\n./solve.mjs "${issueUrl}" --resume ${sessionId} --auto-continue-on-limit-reset\n\`\`\`` : `❌ **Usage Limit Reached**\n\nThe AI tool has reached its usage limit. Please wait for the limit to reset.\n\nThis session has failed because \`--auto-continue-on-limit-reset\` was not enabled.\n\nTo resume after the limit resets, use:\n\`\`\`bash\n./solve.mjs "${issueUrl}" --resume ${sessionId}\n\`\`\``;
|
|
919
924
|
|
|
920
925
|
const commentResult = await $`gh pr comment ${prNumber} --repo ${owner}/${repo} --body ${failureComment}`;
|
|
921
926
|
if (commentResult.code === 0) {
|
|
@@ -948,12 +953,9 @@ try {
|
|
|
948
953
|
// Mark this as a usage limit case for proper formatting
|
|
949
954
|
isUsageLimit: true,
|
|
950
955
|
limitResetTime: global.limitResetTime,
|
|
951
|
-
toolName: (argv.tool || 'AI tool').toString().toLowerCase() === 'claude' ? 'Claude' :
|
|
952
|
-
(argv.tool || 'AI tool').toString().toLowerCase() === 'codex' ? 'Codex' :
|
|
953
|
-
(argv.tool || 'AI tool').toString().toLowerCase() === 'opencode' ? 'OpenCode' :
|
|
954
|
-
(argv.tool || 'AI tool').toString().toLowerCase() === 'agent' ? 'Agent' : 'AI tool',
|
|
956
|
+
toolName: (argv.tool || 'AI tool').toString().toLowerCase() === 'claude' ? 'Claude' : (argv.tool || 'AI tool').toString().toLowerCase() === 'codex' ? 'Codex' : (argv.tool || 'AI tool').toString().toLowerCase() === 'opencode' ? 'OpenCode' : (argv.tool || 'AI tool').toString().toLowerCase() === 'agent' ? 'Agent' : 'AI tool',
|
|
955
957
|
resumeCommand,
|
|
956
|
-
sessionId
|
|
958
|
+
sessionId,
|
|
957
959
|
});
|
|
958
960
|
|
|
959
961
|
if (logUploadSuccess) {
|
|
@@ -972,7 +974,7 @@ try {
|
|
|
972
974
|
const { calculateWaitTime } = validation;
|
|
973
975
|
const waitMs = calculateWaitTime(global.limitResetTime);
|
|
974
976
|
|
|
975
|
-
const formatWaitTime =
|
|
977
|
+
const formatWaitTime = ms => {
|
|
976
978
|
const seconds = Math.floor(ms / 1000);
|
|
977
979
|
const minutes = Math.floor(seconds / 60);
|
|
978
980
|
const hours = Math.floor(minutes / 60);
|
|
@@ -1016,15 +1018,12 @@ try {
|
|
|
1016
1018
|
// For usage limit, use a dedicated comment format to make it clear and actionable
|
|
1017
1019
|
isUsageLimit: !!limitReached,
|
|
1018
1020
|
limitResetTime: limitReached ? toolResult.limitResetTime : null,
|
|
1019
|
-
toolName: (argv.tool || 'AI tool').toString().toLowerCase() === 'claude' ? 'Claude' :
|
|
1020
|
-
(argv.tool || 'AI tool').toString().toLowerCase() === 'codex' ? 'Codex' :
|
|
1021
|
-
(argv.tool || 'AI tool').toString().toLowerCase() === 'opencode' ? 'OpenCode' :
|
|
1022
|
-
(argv.tool || 'AI tool').toString().toLowerCase() === 'agent' ? 'Agent' : 'AI tool',
|
|
1021
|
+
toolName: (argv.tool || 'AI tool').toString().toLowerCase() === 'claude' ? 'Claude' : (argv.tool || 'AI tool').toString().toLowerCase() === 'codex' ? 'Codex' : (argv.tool || 'AI tool').toString().toLowerCase() === 'opencode' ? 'OpenCode' : (argv.tool || 'AI tool').toString().toLowerCase() === 'agent' ? 'Agent' : 'AI tool',
|
|
1023
1022
|
resumeCommand,
|
|
1024
1023
|
// Include sessionId so the PR comment can present it
|
|
1025
1024
|
sessionId,
|
|
1026
1025
|
// If not a usage limit case, fall back to generic failure format
|
|
1027
|
-
errorMessage: limitReached ? undefined : `${argv.tool.toUpperCase()} execution failed
|
|
1026
|
+
errorMessage: limitReached ? undefined : `${argv.tool.toUpperCase()} execution failed`,
|
|
1028
1027
|
});
|
|
1029
1028
|
|
|
1030
1029
|
if (logUploadSuccess) {
|
|
@@ -1093,8 +1092,8 @@ try {
|
|
|
1093
1092
|
argv: {
|
|
1094
1093
|
...argv,
|
|
1095
1094
|
watch: argv.watch || shouldRestart, // Enable watch if uncommitted changes
|
|
1096
|
-
temporaryWatch: temporaryWatchMode
|
|
1097
|
-
}
|
|
1095
|
+
temporaryWatch: temporaryWatchMode, // Flag to indicate temporary watch mode
|
|
1096
|
+
},
|
|
1098
1097
|
});
|
|
1099
1098
|
|
|
1100
1099
|
// Update session data with latest from watch mode for accurate pricing
|
|
@@ -1157,7 +1156,7 @@ try {
|
|
|
1157
1156
|
verbose: argv.verbose,
|
|
1158
1157
|
sessionId,
|
|
1159
1158
|
tempDir,
|
|
1160
|
-
anthropicTotalCostUSD
|
|
1159
|
+
anthropicTotalCostUSD,
|
|
1161
1160
|
});
|
|
1162
1161
|
|
|
1163
1162
|
if (logUploadSuccess) {
|
|
@@ -1180,14 +1179,14 @@ try {
|
|
|
1180
1179
|
log,
|
|
1181
1180
|
formatAligned,
|
|
1182
1181
|
$,
|
|
1183
|
-
logsAttached
|
|
1182
|
+
logsAttached,
|
|
1184
1183
|
});
|
|
1185
1184
|
} catch (error) {
|
|
1186
1185
|
// Don't report authentication errors to Sentry as they are user configuration issues
|
|
1187
1186
|
if (!error.isAuthError) {
|
|
1188
1187
|
reportError(error, {
|
|
1189
1188
|
context: 'solve_main',
|
|
1190
|
-
operation: 'main_execution'
|
|
1189
|
+
operation: 'main_execution',
|
|
1191
1190
|
});
|
|
1192
1191
|
}
|
|
1193
1192
|
await handleMainExecutionError({
|
|
@@ -1203,7 +1202,7 @@ try {
|
|
|
1203
1202
|
getLogFile,
|
|
1204
1203
|
attachLogToGitHub,
|
|
1205
1204
|
sanitizeLogContent,
|
|
1206
|
-
|
|
1205
|
+
$,
|
|
1207
1206
|
});
|
|
1208
1207
|
} finally {
|
|
1209
1208
|
// Clean up temporary directory using repository module
|
|
@@ -7,23 +7,7 @@
|
|
|
7
7
|
const feedback = await import('./solve.feedback.lib.mjs');
|
|
8
8
|
const { detectAndCountFeedback } = feedback;
|
|
9
9
|
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
export async function prepareFeedbackAndTimestamps({
|
|
13
|
-
prNumber,
|
|
14
|
-
branchName: _branchName,
|
|
15
|
-
owner,
|
|
16
|
-
repo,
|
|
17
|
-
issueNumber,
|
|
18
|
-
isContinueMode: _isContinueMode,
|
|
19
|
-
mergeStateStatus: _mergeStateStatus,
|
|
20
|
-
prState: _prState,
|
|
21
|
-
argv: _argv,
|
|
22
|
-
log,
|
|
23
|
-
formatAligned,
|
|
24
|
-
cleanErrorMessage: _cleanErrorMessage,
|
|
25
|
-
$
|
|
26
|
-
}) {
|
|
10
|
+
export async function prepareFeedbackAndTimestamps({ prNumber, branchName: _branchName, owner, repo, issueNumber, isContinueMode: _isContinueMode, mergeStateStatus: _mergeStateStatus, prState: _prState, argv: _argv, log, formatAligned, cleanErrorMessage: _cleanErrorMessage, $ }) {
|
|
27
11
|
// Count new comments and detect feedback
|
|
28
12
|
let { feedbackLines } = await detectAndCountFeedback({
|
|
29
13
|
prNumber,
|
|
@@ -39,7 +23,7 @@ export async function prepareFeedbackAndTimestamps({
|
|
|
39
23
|
log,
|
|
40
24
|
formatAligned,
|
|
41
25
|
cleanErrorMessage: _cleanErrorMessage,
|
|
42
|
-
|
|
26
|
+
$,
|
|
43
27
|
});
|
|
44
28
|
|
|
45
29
|
// Get timestamps from GitHub servers before executing the command
|
|
@@ -77,7 +61,9 @@ export async function prepareFeedbackAndTimestamps({
|
|
|
77
61
|
const prsResult = await $`gh pr list --repo ${owner}/${repo} --limit 1 --json createdAt`;
|
|
78
62
|
|
|
79
63
|
if (prsResult.code !== 0) {
|
|
80
|
-
await log(`Warning: Failed to get PRs: ${prsResult.stderr ? prsResult.stderr.toString() : 'Unknown error'}`, {
|
|
64
|
+
await log(`Warning: Failed to get PRs: ${prsResult.stderr ? prsResult.stderr.toString() : 'Unknown error'}`, {
|
|
65
|
+
level: 'warning',
|
|
66
|
+
});
|
|
81
67
|
// Continue anyway, PRs are optional for timestamp calculation
|
|
82
68
|
}
|
|
83
69
|
|
|
@@ -106,7 +92,7 @@ export async function prepareFeedbackAndTimestamps({
|
|
|
106
92
|
context: 'get_reference_timestamp',
|
|
107
93
|
prNumber,
|
|
108
94
|
issueNumber,
|
|
109
|
-
operation: 'fetch_github_timestamps'
|
|
95
|
+
operation: 'fetch_github_timestamps',
|
|
110
96
|
});
|
|
111
97
|
await log('Warning: Could not get GitHub timestamps, using current time as reference', { level: 'warning' });
|
|
112
98
|
await log(` Error: ${timestampError.message}`);
|
|
@@ -117,12 +103,7 @@ export async function prepareFeedbackAndTimestamps({
|
|
|
117
103
|
return { feedbackLines, referenceTime };
|
|
118
104
|
}
|
|
119
105
|
|
|
120
|
-
export async function checkUncommittedChanges({
|
|
121
|
-
tempDir,
|
|
122
|
-
argv,
|
|
123
|
-
log,
|
|
124
|
-
$
|
|
125
|
-
}) {
|
|
106
|
+
export async function checkUncommittedChanges({ tempDir, argv, log, $ }) {
|
|
126
107
|
// Check for uncommitted changes before running Claude
|
|
127
108
|
// Only add to feedback if auto-commit is disabled
|
|
128
109
|
if (!argv['auto-commit-uncommitted-changes']) {
|
|
@@ -163,7 +144,7 @@ export async function checkUncommittedChanges({
|
|
|
163
144
|
reportError(gitError, {
|
|
164
145
|
context: 'check_uncommitted_changes',
|
|
165
146
|
tempDir,
|
|
166
|
-
operation: 'git_status'
|
|
147
|
+
operation: 'git_status',
|
|
167
148
|
});
|
|
168
149
|
await log(`⚠️ Warning: Could not check git status: ${gitError.message}`, { level: 'warning' });
|
|
169
150
|
}
|
|
@@ -171,14 +152,7 @@ export async function checkUncommittedChanges({
|
|
|
171
152
|
return [];
|
|
172
153
|
}
|
|
173
154
|
|
|
174
|
-
export async function checkForkActions({
|
|
175
|
-
argv,
|
|
176
|
-
forkedRepo,
|
|
177
|
-
branchName,
|
|
178
|
-
log,
|
|
179
|
-
formatAligned,
|
|
180
|
-
$
|
|
181
|
-
}) {
|
|
155
|
+
export async function checkForkActions({ argv, forkedRepo, branchName, log, formatAligned, $ }) {
|
|
182
156
|
// Check for GitHub Actions on fork repository if applicable
|
|
183
157
|
let forkActionsUrl = null;
|
|
184
158
|
if (argv.fork && forkedRepo) {
|
|
@@ -207,4 +181,4 @@ export async function checkForkActions({
|
|
|
207
181
|
}
|
|
208
182
|
|
|
209
183
|
return forkActionsUrl;
|
|
210
|
-
}
|
|
184
|
+
}
|
|
@@ -3,17 +3,7 @@
|
|
|
3
3
|
* Handles repository cloning, forking, and remote setup
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
|
-
export async function setupRepositoryAndClone({
|
|
7
|
-
argv,
|
|
8
|
-
owner,
|
|
9
|
-
repo,
|
|
10
|
-
forkOwner,
|
|
11
|
-
tempDir,
|
|
12
|
-
isContinueMode,
|
|
13
|
-
issueUrl,
|
|
14
|
-
log,
|
|
15
|
-
$
|
|
16
|
-
}) {
|
|
6
|
+
export async function setupRepositoryAndClone({ argv, owner, repo, forkOwner, tempDir, isContinueMode, issueUrl, log, $ }) {
|
|
17
7
|
// Set up repository and handle forking
|
|
18
8
|
const { repoToClone, forkedRepo, upstreamRemote, prForkOwner } = await setupRepository(argv, owner, repo, forkOwner, issueUrl);
|
|
19
9
|
|
|
@@ -57,12 +47,7 @@ async function setupPrForkRemote(tempDir, argv, prForkOwner, repo, isContinueMod
|
|
|
57
47
|
return await setupPrForkFn(tempDir, argv, prForkOwner, repo, isContinueMode, owner);
|
|
58
48
|
}
|
|
59
49
|
|
|
60
|
-
export async function verifyDefaultBranchAndStatus({
|
|
61
|
-
tempDir,
|
|
62
|
-
log,
|
|
63
|
-
formatAligned,
|
|
64
|
-
$
|
|
65
|
-
}) {
|
|
50
|
+
export async function verifyDefaultBranchAndStatus({ tempDir, log, formatAligned, $ }) {
|
|
66
51
|
// Verify we're on the default branch and get its name
|
|
67
52
|
const defaultBranchResult = await $({ cwd: tempDir })`git branch --show-current`;
|
|
68
53
|
|
|
@@ -78,7 +63,7 @@ export async function verifyDefaultBranchAndStatus({
|
|
|
78
63
|
await log(`${formatAligned('❌', 'DEFAULT BRANCH DETECTION FAILED', '')}`, { level: 'error' });
|
|
79
64
|
await log('');
|
|
80
65
|
await log(' 🔍 What happened:');
|
|
81
|
-
await log(
|
|
66
|
+
await log(" Unable to determine the repository's default branch.");
|
|
82
67
|
await log('');
|
|
83
68
|
await log(' 💡 This might mean:');
|
|
84
69
|
await log(' • Repository is empty (no commits)');
|
|
@@ -111,4 +96,4 @@ export async function verifyDefaultBranchAndStatus({
|
|
|
111
96
|
}
|
|
112
97
|
|
|
113
98
|
return defaultBranch;
|
|
114
|
-
}
|
|
99
|
+
}
|