erosolar-cli 1.7.16 → 1.7.18

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.
@@ -1,6 +1,5 @@
1
1
  import readline from 'node:readline';
2
2
  import { stdin as input, stdout as output, exit } from 'node:process';
3
- import chalk from 'chalk';
4
3
  import { display } from '../ui/display.js';
5
4
  import { formatUserPrompt, theme } from '../ui/theme.js';
6
5
  import { getContextWindowTokens } from '../core/contextWindow.js';
@@ -112,6 +111,8 @@ export class InteractiveShell {
112
111
  activeSessionTitle = null;
113
112
  sessionResumeNotice = null;
114
113
  lastAssistantResponse = null;
114
+ verificationRetryCount = 0;
115
+ maxVerificationRetries = 2;
115
116
  customCommands;
116
117
  customCommandMap;
117
118
  sessionRestoreConfig;
@@ -1574,12 +1575,14 @@ export class InteractiveShell {
1574
1575
  /**
1575
1576
  * Schedule auto-verification after assistant response if it contains verifiable claims.
1576
1577
  * Runs asynchronously to not block the UI.
1578
+ * If verification fails and retries are available, generates a fix strategy and retries.
1577
1579
  */
1578
1580
  scheduleAutoVerification(response) {
1579
1581
  // Extract claims to see if verification is needed
1580
1582
  const claims = extractClaims(response);
1581
1583
  if (claims.length === 0) {
1582
- // No verifiable claims - skip verification
1584
+ // No verifiable claims - skip verification and reset retry count
1585
+ this.verificationRetryCount = 0;
1583
1586
  return;
1584
1587
  }
1585
1588
  // Run verification asynchronously after a short delay
@@ -1592,16 +1595,24 @@ export class InteractiveShell {
1592
1595
  // Show compact result
1593
1596
  if (report.overallVerdict === 'verified') {
1594
1597
  display.showInfo(`✅ Verified: ${report.summary.verified}/${report.summary.total} claims confirmed`);
1598
+ // Reset retry count on success
1599
+ this.verificationRetryCount = 0;
1595
1600
  }
1596
- else if (report.overallVerdict === 'contradicted') {
1597
- display.showError(`❌ Verification failed: ${report.summary.failed} claim${report.summary.failed > 1 ? 's' : ''} could not be verified`);
1598
- // Show full report for failures
1599
- display.showSystemMessage(formattedReport);
1600
- }
1601
- else if (report.overallVerdict === 'partially_verified') {
1602
- display.showWarning(`⚠️ Partial: ${report.summary.verified}/${report.summary.total} verified, ${report.summary.failed} failed`);
1603
- // Show details for partial verification
1601
+ else if (report.overallVerdict === 'contradicted' || report.overallVerdict === 'partially_verified') {
1602
+ const failedCount = report.summary.failed;
1603
+ const icon = report.overallVerdict === 'contradicted' ? '❌' : '⚠️';
1604
+ const label = report.overallVerdict === 'contradicted' ? 'Verification failed' : 'Partial verification';
1605
+ display.showError(`${icon} ${label}: ${failedCount} claim${failedCount > 1 ? 's' : ''} could not be verified`);
1604
1606
  display.showSystemMessage(formattedReport);
1607
+ // Attempt to fix if we have retries left
1608
+ if (this.verificationRetryCount < this.maxVerificationRetries) {
1609
+ this.verificationRetryCount++;
1610
+ this.requestVerificationFix(report);
1611
+ }
1612
+ else {
1613
+ display.showWarning(`Max verification retries (${this.maxVerificationRetries}) reached. Use /verify to check manually.`);
1614
+ this.verificationRetryCount = 0;
1615
+ }
1605
1616
  }
1606
1617
  // For 'unverified' (no claims found), we already skipped above
1607
1618
  }
@@ -1611,6 +1622,61 @@ export class InteractiveShell {
1611
1622
  }
1612
1623
  }, 500);
1613
1624
  }
1625
+ /**
1626
+ * Request the AI to fix failed verification claims.
1627
+ * Generates a strategic fix request with context about what failed and why.
1628
+ */
1629
+ requestVerificationFix(report) {
1630
+ const failedResults = report.results.filter(r => !r.verified && r.confidence === 'high');
1631
+ if (failedResults.length === 0) {
1632
+ return;
1633
+ }
1634
+ // Build detailed failure descriptions with suggested fixes
1635
+ const failureDetails = failedResults.map(r => {
1636
+ const claim = r.claim;
1637
+ const evidence = r.evidence;
1638
+ // Generate specific fix strategy based on claim type
1639
+ let suggestedFix = '';
1640
+ switch (claim.type) {
1641
+ case 'file_created':
1642
+ case 'file_modified':
1643
+ suggestedFix = `Re-create or update the file at: ${claim.params.path || 'specified path'}`;
1644
+ break;
1645
+ case 'code_compiles':
1646
+ suggestedFix = 'Fix any type errors or syntax issues, then run the build again';
1647
+ break;
1648
+ case 'tests_pass':
1649
+ suggestedFix = 'Fix failing tests or update test expectations';
1650
+ break;
1651
+ case 'git_committed':
1652
+ suggestedFix = 'Stage changes and create the commit';
1653
+ break;
1654
+ case 'package_published':
1655
+ suggestedFix = 'Ensure package.json version is updated and run npm publish';
1656
+ break;
1657
+ default:
1658
+ suggestedFix = 'Retry the operation';
1659
+ }
1660
+ return `• ${claim.description}
1661
+ Evidence: ${evidence.slice(0, 150)}
1662
+ Suggested fix: ${suggestedFix}`;
1663
+ }).join('\n\n');
1664
+ const fixMessage = `🔧 VERIFICATION FAILED - AUTO-RETRY (attempt ${this.verificationRetryCount}/${this.maxVerificationRetries})
1665
+
1666
+ The following claims could not be verified:
1667
+
1668
+ ${failureDetails}
1669
+
1670
+ Please:
1671
+ 1. Analyze why each operation failed
1672
+ 2. Fix the underlying issue
1673
+ 3. Retry the failed operation(s)
1674
+ 4. Confirm successful completion`;
1675
+ display.showSystemMessage(`\n🔧 Auto-retry: Generating fix strategy for ${failedResults.length} failed claim${failedResults.length > 1 ? 's' : ''}...`);
1676
+ // Queue the fix request
1677
+ this.followUpQueue.push({ type: 'request', text: fixMessage });
1678
+ this.scheduleQueueProcessing();
1679
+ }
1614
1680
  showImprovementSuggestions() {
1615
1681
  const suggestions = this.alphaZeroMetrics.getImprovementSuggestions();
1616
1682
  if (suggestions.length === 0) {
@@ -3278,7 +3344,7 @@ What's the next action?`;
3278
3344
  }
3279
3345
  /**
3280
3346
  * Style streaming chunks in real-time (Claude Code style)
3281
- * Detects <thinking> blocks and applies dim styling, hides XML tags
3347
+ * Detects <thinking> blocks and applies cyan styling, hides XML tags
3282
3348
  */
3283
3349
  styleStreamingChunk(chunk) {
3284
3350
  let result = '';
@@ -3290,16 +3356,16 @@ What's the next action?`;
3290
3356
  if (endIdx !== -1) {
3291
3357
  // End of thinking block found
3292
3358
  const thinkingContent = remaining.slice(0, endIdx);
3293
- // Apply dim styling to thinking content (hide the closing tag)
3294
- result += chalk.dim(thinkingContent);
3359
+ // Apply cyan thinking styling to content (hide the closing tag)
3360
+ result += theme.thinking.text(thinkingContent);
3295
3361
  remaining = remaining.slice(endIdx + '</thinking>'.length);
3296
3362
  this.isInsideThinkingBlock = false;
3297
- // Add newline after thinking block ends
3298
- result += '\n';
3363
+ // Add separator and newline after thinking block ends
3364
+ result += '\n' + theme.thinking.border('─'.repeat(40)) + '\n';
3299
3365
  }
3300
3366
  else {
3301
- // Still inside thinking block, apply dim to all remaining
3302
- result += chalk.dim(remaining);
3367
+ // Still inside thinking block, apply cyan styling to all remaining
3368
+ result += theme.thinking.text(remaining);
3303
3369
  remaining = '';
3304
3370
  }
3305
3371
  }
@@ -3311,8 +3377,8 @@ What's the next action?`;
3311
3377
  if (startIdx > 0) {
3312
3378
  result += remaining.slice(0, startIdx);
3313
3379
  }
3314
- // Show thinking header instead of raw tag (Claude Code style)
3315
- result += chalk.dim('💭 ');
3380
+ // Show thinking header with cyan styling (Claude Code style)
3381
+ result += theme.thinking.icon('💭') + ' ' + theme.thinking.label('Thinking') + '\n';
3316
3382
  remaining = remaining.slice(startIdx + '<thinking>'.length);
3317
3383
  this.isInsideThinkingBlock = true;
3318
3384
  }