erosolar-cli 1.7.393 โ†’ 1.7.395

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 (45) hide show
  1. package/dist/core/offsecAlphaZero.d.ts +56 -0
  2. package/dist/core/offsecAlphaZero.d.ts.map +1 -0
  3. package/dist/core/offsecAlphaZero.js +395 -0
  4. package/dist/core/offsecAlphaZero.js.map +1 -0
  5. package/dist/core/preferences.d.ts +1 -0
  6. package/dist/core/preferences.d.ts.map +1 -1
  7. package/dist/core/preferences.js +7 -0
  8. package/dist/core/preferences.js.map +1 -1
  9. package/dist/shell/interactiveShell.d.ts +23 -5
  10. package/dist/shell/interactiveShell.d.ts.map +1 -1
  11. package/dist/shell/interactiveShell.js +486 -135
  12. package/dist/shell/interactiveShell.js.map +1 -1
  13. package/dist/shell/keyboardShortcuts.d.ts.map +1 -1
  14. package/dist/shell/keyboardShortcuts.js +11 -8
  15. package/dist/shell/keyboardShortcuts.js.map +1 -1
  16. package/dist/shell/liveStatus.d.ts +1 -0
  17. package/dist/shell/liveStatus.d.ts.map +1 -1
  18. package/dist/shell/liveStatus.js +32 -7
  19. package/dist/shell/liveStatus.js.map +1 -1
  20. package/dist/shell/terminalInput.d.ts +25 -2
  21. package/dist/shell/terminalInput.d.ts.map +1 -1
  22. package/dist/shell/terminalInput.js +270 -60
  23. package/dist/shell/terminalInput.js.map +1 -1
  24. package/dist/shell/terminalInputAdapter.d.ts +14 -0
  25. package/dist/shell/terminalInputAdapter.d.ts.map +1 -1
  26. package/dist/shell/terminalInputAdapter.js +14 -0
  27. package/dist/shell/terminalInputAdapter.js.map +1 -1
  28. package/dist/shell/updateManager.d.ts +8 -1
  29. package/dist/shell/updateManager.d.ts.map +1 -1
  30. package/dist/shell/updateManager.js +4 -2
  31. package/dist/shell/updateManager.js.map +1 -1
  32. package/dist/ui/ShellUIAdapter.d.ts +6 -12
  33. package/dist/ui/ShellUIAdapter.d.ts.map +1 -1
  34. package/dist/ui/ShellUIAdapter.js +26 -37
  35. package/dist/ui/ShellUIAdapter.js.map +1 -1
  36. package/dist/ui/shortcutsHelp.d.ts.map +1 -1
  37. package/dist/ui/shortcutsHelp.js +22 -21
  38. package/dist/ui/shortcutsHelp.js.map +1 -1
  39. package/dist/ui/unified/index.d.ts +2 -2
  40. package/dist/ui/unified/index.d.ts.map +1 -1
  41. package/dist/ui/unified/index.js.map +1 -1
  42. package/dist/ui/unified/layout.d.ts.map +1 -1
  43. package/dist/ui/unified/layout.js +31 -25
  44. package/dist/ui/unified/layout.js.map +1 -1
  45. package/package.json +1 -1
@@ -30,11 +30,11 @@ import { analyzeImprovementOpportunities, runSelfImprovementCycle, getImprovemen
30
30
  import { listAvailablePlugins } from '../plugins/index.js';
31
31
  import { isErosolarRepo, isValidSourceRepo, getRepoName, analyzeSource, runSelfEvolution, stopEvolution, getEvolutionStatus, emergencyEvolutionRollback, learnSourcePatterns, generateFix, } from '../core/selfEvolution.js';
32
32
  import { analyzeTokenUsage, discoverModularTargets, getModularStatusDisplay, generateContextOptimizations, getGuidelines, deleteGuideline, getPendingActions, executeModularAction, } from '../core/alphaZeroModular.js';
33
+ import { startOffsecRun, resumeOffsecRun, recordOffsecOutcome, getOffsecNextActions, simulateOffsecRollout, formatOffsecStatus, listOffsecRuns, } from '../core/offsecAlphaZero.js';
33
34
  import { generateTestFlows, detectBugs, detectUIUpdates, saveTestFlows, saveBugReports, saveUIUpdates, getTestFlowStatus, } from '../core/intelligentTestFlows.js';
34
35
  import { TerminalInputAdapter } from './terminalInputAdapter.js';
35
36
  import { renderSessionFrame } from '../ui/unified/layout.js';
36
37
  import { isUpdateInProgress, maybeOfferCliUpdate } from './updateManager.js';
37
- import { writeLock } from '../ui/writeLock.js';
38
38
  import { enterStreamingMode, exitStreamingMode } from '../ui/globalWriteLock.js';
39
39
  import { setGlobalAIEnhancer } from '../tools/localExplore.js';
40
40
  import { createProvider } from '../providers/providerFactory.js';
@@ -101,7 +101,6 @@ export class InteractiveShell {
101
101
  ctrlCHandledThisPress = false;
102
102
  pendingCleanup = null;
103
103
  cleanupInProgress = false;
104
- slashPreviewVisible = false;
105
104
  lastLoggedPrompt = null;
106
105
  lastLoggedPromptAt = 0;
107
106
  skillRepository;
@@ -119,6 +118,7 @@ export class InteractiveShell {
119
118
  statusSubscription = null;
120
119
  followUpQueue = [];
121
120
  isDrainingQueue = false;
121
+ apiKeyGateActive = false;
122
122
  activeContextWindowTokens = null;
123
123
  latestTokenUsage = { used: null, limit: null };
124
124
  planApprovalBridgeRegistered = false;
@@ -128,6 +128,8 @@ export class InteractiveShell {
128
128
  autosaveEnabled;
129
129
  autoContinueEnabled;
130
130
  verificationEnabled = true;
131
+ alphaZeroModeEnabled;
132
+ alphaZeroVerificationSnapshot = null;
131
133
  editGuardMode = 'display-edits';
132
134
  pendingPermissionInput = null;
133
135
  pendingHistoryLoad = null;
@@ -152,6 +154,8 @@ export class InteractiveShell {
152
154
  // Auto-build tracking
153
155
  autoBuildInFlight = false;
154
156
  lastAutoBuildRun = null;
157
+ // Offsec AlphaZero tracking
158
+ offsecRunId = null;
155
159
  // Streaming UX tracking
156
160
  streamingHeartbeatStart = null;
157
161
  streamingHeartbeatFrame = 0;
@@ -159,6 +163,7 @@ export class InteractiveShell {
159
163
  lastStreamingElapsedSeconds = null; // Preserve final elapsed time
160
164
  statusLineState = null;
161
165
  statusMessageOverride = null;
166
+ hasShownThoughtProcess = false;
162
167
  promptRefreshTimer = null;
163
168
  launchPaletteShown = false;
164
169
  version;
@@ -174,6 +179,7 @@ export class InteractiveShell {
174
179
  this.thinkingMode = this.sessionPreferences.thinkingMode;
175
180
  this.autosaveEnabled = this.sessionPreferences.autosave;
176
181
  this.autoContinueEnabled = this.sessionPreferences.autoContinue;
182
+ this.alphaZeroModeEnabled = this.sessionPreferences.alphaZeroMode;
177
183
  this.sessionRestoreConfig = config.sessionRestore ?? { mode: 'none' };
178
184
  this._enabledPlugins = config.enabledPlugins ?? [];
179
185
  this.version = config.version ?? '0.0.0';
@@ -224,6 +230,16 @@ export class InteractiveShell {
224
230
  description: 'Show available and loaded plugins',
225
231
  category: 'configuration',
226
232
  });
233
+ this.slashCommands.push({
234
+ command: '/offsec',
235
+ description: 'AlphaZero offensive security run (start/status/next)',
236
+ category: 'automation',
237
+ });
238
+ this.slashCommands.push({
239
+ command: '/alphazero',
240
+ description: 'Toggle AlphaZero RL mode with full-cycle verification',
241
+ category: 'mode',
242
+ });
227
243
  this.statusTracker = config.statusTracker;
228
244
  this.ui = config.ui;
229
245
  this.uiAdapter = config.ui.adapter;
@@ -235,7 +251,11 @@ export class InteractiveShell {
235
251
  });
236
252
  // Set up tool status callback to update status during tool execution
237
253
  this.uiAdapter.setToolStatusCallback((status) => {
238
- this.updateStatusMessage(status ?? null);
254
+ const statusText = status?.text ?? null;
255
+ if (statusText) {
256
+ this.terminalInput.recordRecentAction(`[tool] ${statusText}`);
257
+ }
258
+ this.updateStatusMessage(statusText, { logRecent: false });
239
259
  });
240
260
  this.skillRepository = new SkillRepository({
241
261
  workingDir: this.workingDir,
@@ -255,6 +275,7 @@ export class InteractiveShell {
255
275
  onToggleVerify: () => this.toggleVerificationMode(),
256
276
  onToggleAutoContinue: () => this.toggleAutoContinueMode(),
257
277
  onToggleThinking: () => this.cycleThinkingMode(),
278
+ onToggleAlphaZero: () => this.toggleAlphaZeroMode('shortcut'),
258
279
  onClearContext: () => this.handleClearContext(),
259
280
  });
260
281
  // Initialize Alpha Zero 2 metrics tracking
@@ -282,7 +303,7 @@ export class InteractiveShell {
282
303
  this.terminalInput.streamContent(banner + '\n\n');
283
304
  // Render chat box after banner is streamed
284
305
  this.refreshControlBar();
285
- this.terminalInput.forceRender();
306
+ this.renderPromptArea(true);
286
307
  this.rebuildAgent();
287
308
  this.setupHandlers();
288
309
  this.refreshBannerSessionInfo();
@@ -297,7 +318,13 @@ export class InteractiveShell {
297
318
  this.parallelAgentDisplayLines = manager.formatDisplay();
298
319
  // Trigger UI refresh if streaming
299
320
  if (this.streamingHeartbeatStart) {
300
- this.displayParallelAgents();
321
+ this.uiUpdates.enqueue({
322
+ lane: 'stream',
323
+ mode: ['streaming', 'processing'],
324
+ coalesceKey: 'parallel-agents',
325
+ description: 'parallel agent status',
326
+ run: () => this.displayParallelAgents(),
327
+ });
301
328
  }
302
329
  };
303
330
  manager.on('agent:started', updateDisplay);
@@ -378,7 +405,7 @@ export class InteractiveShell {
378
405
  }
379
406
  this.showLaunchCommandPalette();
380
407
  // Ensure the terminal input is visible
381
- this.terminalInput.render();
408
+ this.renderPromptArea();
382
409
  }
383
410
  showLaunchCommandPalette() {
384
411
  // Disabled: Quick commands palette takes up too much space
@@ -475,9 +502,11 @@ export class InteractiveShell {
475
502
  // Mode toggles
476
503
  '/thinking',
477
504
  '/autocontinue',
505
+ '/alphazero',
478
506
  // Discovery and plugins
479
507
  '/local', '/discover',
480
508
  '/plugins',
509
+ '/offsec',
481
510
  '/skills',
482
511
  // Self-improvement
483
512
  '/evolve', '/modular', '/a0',
@@ -507,7 +536,6 @@ export class InteractiveShell {
507
536
  if (text.length > 0) {
508
537
  this.resetCtrlCSequence();
509
538
  }
510
- this.handleSlashCommandPreviewChange();
511
539
  }
512
540
  /**
513
541
  * Edit guard mode change handler (Shift+Tab from terminal input)
@@ -526,7 +554,7 @@ export class InteractiveShell {
526
554
  display.showSystemMessage('โœ๏ธ Display edits mode enabled.');
527
555
  }
528
556
  }
529
- this.terminalInput.render();
557
+ this.renderPromptArea();
530
558
  }
531
559
  toggleVerificationMode() {
532
560
  this.setVerificationMode(!this.verificationEnabled, 'shortcut');
@@ -539,8 +567,8 @@ export class InteractiveShell {
539
567
  return;
540
568
  }
541
569
  const message = enabled
542
- ? 'โœ… Verification on. Auto-tests will run after edits. (alt+v to toggle)'
543
- : 'โญ๏ธ Verification off. Skipping auto-tests until re-enabled. (alt+v to toggle)';
570
+ ? 'โœ… Verification on. Auto-tests will run after edits. (Ctrl+Shift+V to toggle)'
571
+ : 'โญ๏ธ Verification off. Skipping auto-tests until re-enabled. (Ctrl+Shift+V to toggle)';
544
572
  display.showSystemMessage(message);
545
573
  }
546
574
  toggleAutoContinueMode() {
@@ -561,10 +589,41 @@ export class InteractiveShell {
561
589
  (this.autoContinueEnabled
562
590
  ? 'The model will be auto-prompted to continue when it expresses intent but does not use tools.'
563
591
  : 'The model will not be auto-prompted to continue.') +
564
- ' Toggle with alt+c.');
592
+ ' Toggle with Ctrl+Shift+C.');
593
+ }
594
+ toggleAlphaZeroMode(source = 'shortcut') {
595
+ this.setAlphaZeroMode(!this.alphaZeroModeEnabled, source);
596
+ }
597
+ setAlphaZeroMode(enabled, source) {
598
+ const changed = this.alphaZeroModeEnabled !== enabled;
599
+ this.alphaZeroModeEnabled = enabled;
600
+ saveSessionPreferences({ alphaZeroMode: this.alphaZeroModeEnabled });
601
+ // Force verification on while AlphaZero mode is active to guarantee deep checks
602
+ if (enabled) {
603
+ if (this.alphaZeroVerificationSnapshot === null) {
604
+ this.alphaZeroVerificationSnapshot = this.verificationEnabled;
605
+ }
606
+ if (!this.verificationEnabled) {
607
+ this.setVerificationMode(true, 'command');
608
+ }
609
+ }
610
+ else if (this.alphaZeroVerificationSnapshot !== null) {
611
+ this.setVerificationMode(this.alphaZeroVerificationSnapshot, 'command');
612
+ this.alphaZeroVerificationSnapshot = null;
613
+ }
614
+ this.refreshControlBar();
615
+ if (!changed && source === 'shortcut') {
616
+ return;
617
+ }
618
+ if (enabled) {
619
+ display.showSystemMessage('โ™ž AlphaZero RL mode enabled. Difficult prompts will use the duel/self-critique playbook with full lifecycle verification.');
620
+ }
621
+ else {
622
+ display.showInfo('AlphaZero RL mode disabled. Returning to standard flow.');
623
+ }
565
624
  }
566
625
  /**
567
- * Cycle through thinking modes (Alt+T keyboard shortcut).
626
+ * Cycle through thinking modes (Ctrl+Shift+T keyboard shortcut).
568
627
  */
569
628
  cycleThinkingMode() {
570
629
  const modes = ['concise', 'balanced', 'extended'];
@@ -640,7 +699,7 @@ export class InteractiveShell {
640
699
  if (['n', 'no', 'cancel', '/cancel'].includes(lower)) {
641
700
  this.pendingPermissionInput = null;
642
701
  display.showInfo('Request cancelled.');
643
- this.terminalInput.render();
702
+ this.renderPromptArea();
644
703
  return null;
645
704
  }
646
705
  // Treat any other input as a replacement request that also needs confirmation
@@ -658,7 +717,7 @@ export class InteractiveShell {
658
717
  ]
659
718
  .filter(Boolean)
660
719
  .join('\n'));
661
- this.terminalInput.render();
720
+ this.renderPromptArea();
662
721
  }
663
722
  /**
664
723
  * Handle Ctrl+C presses in three stages:
@@ -673,7 +732,7 @@ export class InteractiveShell {
673
732
  this.clearChatInput();
674
733
  const prefix = hadBuffer ? 'Input cleared.' : 'Nothing to clear.';
675
734
  display.showSystemMessage(`${prefix} Press Ctrl+C again to pause the AI; a third time quits.`);
676
- this.terminalInput.render();
735
+ this.renderPromptArea();
677
736
  return;
678
737
  }
679
738
  if (this.ctrlCPressCount === 2) {
@@ -774,8 +833,11 @@ export class InteractiveShell {
774
833
  /**
775
834
  * Update status bar message
776
835
  */
777
- updateStatusMessage(message) {
836
+ updateStatusMessage(message, options = {}) {
778
837
  this.statusMessageOverride = message;
838
+ if (message && options.logRecent !== false) {
839
+ this.terminalInput.recordRecentAction(`[status] ${message}`);
840
+ }
779
841
  // During streaming we still want the spinner prefix; when idle force a fast refresh.
780
842
  this.refreshStatusLine(!this.isProcessing);
781
843
  }
@@ -787,26 +849,26 @@ export class InteractiveShell {
787
849
  const trimmed = input.trim();
788
850
  if (!trimmed) {
789
851
  display.showWarning('Enter a number, "save", "defaults", or "cancel".');
790
- this.terminalInput.render();
852
+ this.renderPromptArea();
791
853
  return;
792
854
  }
793
855
  const normalized = trimmed.toLowerCase();
794
856
  if (normalized === 'cancel') {
795
857
  this.pendingInteraction = null;
796
858
  display.showInfo('Tool selection cancelled.');
797
- this.terminalInput.render();
859
+ this.renderPromptArea();
798
860
  return;
799
861
  }
800
862
  if (normalized === 'defaults') {
801
863
  pending.selection = buildEnabledToolSet(null);
802
864
  this.renderToolMenu(pending);
803
- this.terminalInput.render();
865
+ this.renderPromptArea();
804
866
  return;
805
867
  }
806
868
  if (normalized === 'save') {
807
869
  await this.persistToolSelection(pending);
808
870
  this.pendingInteraction = null;
809
- this.terminalInput.render();
871
+ this.renderPromptArea();
810
872
  return;
811
873
  }
812
874
  const choice = Number.parseInt(trimmed, 10);
@@ -824,11 +886,11 @@ export class InteractiveShell {
824
886
  }
825
887
  this.renderToolMenu(pending);
826
888
  }
827
- this.terminalInput.render();
889
+ this.renderPromptArea();
828
890
  return;
829
891
  }
830
892
  display.showWarning('Enter a number, "save", "defaults", or "cancel".');
831
- this.terminalInput.render();
893
+ this.renderPromptArea();
832
894
  }
833
895
  async persistToolSelection(interaction) {
834
896
  if (setsEqual(interaction.selection, interaction.initialSelection)) {
@@ -855,36 +917,36 @@ export class InteractiveShell {
855
917
  if (!this.agentMenu) {
856
918
  this.pendingInteraction = null;
857
919
  display.showWarning('Agent selection is unavailable in this CLI.');
858
- this.terminalInput.render();
920
+ this.renderPromptArea();
859
921
  return;
860
922
  }
861
923
  const trimmed = input.trim();
862
924
  if (!trimmed) {
863
925
  display.showWarning('Enter a number or type "cancel".');
864
- this.terminalInput.render();
926
+ this.renderPromptArea();
865
927
  return;
866
928
  }
867
929
  if (trimmed.toLowerCase() === 'cancel') {
868
930
  this.pendingInteraction = null;
869
931
  display.showInfo('Agent selection cancelled.');
870
- this.terminalInput.render();
932
+ this.renderPromptArea();
871
933
  return;
872
934
  }
873
935
  const choice = Number.parseInt(trimmed, 10);
874
936
  if (!Number.isFinite(choice)) {
875
937
  display.showWarning('Please enter a valid number.');
876
- this.terminalInput.render();
938
+ this.renderPromptArea();
877
939
  return;
878
940
  }
879
941
  const option = pending.options[choice - 1];
880
942
  if (!option) {
881
943
  display.showWarning('That option is not available.');
882
- this.terminalInput.render();
944
+ this.renderPromptArea();
883
945
  return;
884
946
  }
885
947
  await this.persistAgentSelection(option.name);
886
948
  this.pendingInteraction = null;
887
- this.terminalInput.render();
949
+ this.renderPromptArea();
888
950
  }
889
951
  async persistAgentSelection(profileName) {
890
952
  if (!this.agentMenu) {
@@ -957,7 +1019,7 @@ export class InteractiveShell {
957
1019
  lines.push(` ${theme.primary('[text]')} Submit your own solution instead`);
958
1020
  lines.push('');
959
1021
  display.showSystemMessage(lines.join('\n'));
960
- this.terminalInput.render();
1022
+ this.renderPromptArea();
961
1023
  }
962
1024
  async handlePlanApprovalInput(input) {
963
1025
  const pending = this.pendingInteraction;
@@ -966,7 +1028,7 @@ export class InteractiveShell {
966
1028
  const trimmed = input.trim();
967
1029
  if (!trimmed) {
968
1030
  display.showWarning('Enter a command or your own solution.');
969
- this.terminalInput.render();
1031
+ this.renderPromptArea();
970
1032
  return;
971
1033
  }
972
1034
  const lower = trimmed.toLowerCase();
@@ -974,7 +1036,7 @@ export class InteractiveShell {
974
1036
  if (lower === 'cancel' || lower === 'c') {
975
1037
  this.pendingInteraction = null;
976
1038
  display.showInfo('Plan cancelled. You can continue with a different approach.');
977
- this.terminalInput.render();
1039
+ this.renderPromptArea();
978
1040
  return;
979
1041
  }
980
1042
  // Select all
@@ -994,7 +1056,7 @@ export class InteractiveShell {
994
1056
  const selectedSteps = pending.steps.filter(s => pending.selectedSteps.has(s.id));
995
1057
  if (selectedSteps.length === 0) {
996
1058
  display.showWarning('No steps selected. Select steps or enter your own solution.');
997
- this.terminalInput.render();
1059
+ this.renderPromptArea();
998
1060
  return;
999
1061
  }
1000
1062
  this.pendingInteraction = null;
@@ -1027,15 +1089,17 @@ export class InteractiveShell {
1027
1089
  return;
1028
1090
  }
1029
1091
  display.showWarning('Invalid input. Enter a step number, command (go/cancel/all/none), or your own solution.');
1030
- this.terminalInput.render();
1092
+ this.renderPromptArea();
1031
1093
  }
1032
1094
  setupHandlers() {
1033
1095
  // Handle terminal resize
1034
1096
  output.on('resize', () => {
1097
+ this.terminalInput.resetContentPosition();
1035
1098
  this.terminalInput.handleResize();
1099
+ this.terminalInput.forceRender();
1036
1100
  });
1037
1101
  // Show initial input UI
1038
- this.terminalInput.render();
1102
+ this.renderPromptArea();
1039
1103
  }
1040
1104
  /**
1041
1105
  * Set up command autocomplete with all available slash commands.
@@ -1066,6 +1130,14 @@ export class InteractiveShell {
1066
1130
  catch {
1067
1131
  // Custom commands are optional
1068
1132
  }
1133
+ // Add manual commands that are not yet in the schema
1134
+ if (!commands.some((cmd) => cmd.command === '/alphazero')) {
1135
+ commands.push({
1136
+ command: '/alphazero',
1137
+ description: 'Toggle AlphaZero RL mode',
1138
+ category: 'mode',
1139
+ });
1140
+ }
1069
1141
  // Sort commands alphabetically
1070
1142
  commands.sort((a, b) => a.command.localeCompare(b.command));
1071
1143
  this.terminalInput.setAvailableCommands(commands);
@@ -1106,7 +1178,16 @@ export class InteractiveShell {
1106
1178
  const parts = detail?.trim() ? [detail.trim()] : [];
1107
1179
  const queued = this.followUpQueue.length;
1108
1180
  if (queued > 0) {
1109
- parts.push(`${queued} follow-up${queued === 1 ? '' : 's'} queued`);
1181
+ const nextText = this.followUpQueue[0]?.text ?? '';
1182
+ const normalized = nextText.replace(/\s+/g, ' ').trim();
1183
+ const previewLimit = 48;
1184
+ const preview = normalized
1185
+ ? normalized.length > previewLimit
1186
+ ? `${normalized.slice(0, previewLimit - 1)}โ€ฆ`
1187
+ : normalized
1188
+ : '';
1189
+ const suffix = preview ? ` (next: ${preview})` : '';
1190
+ parts.push(`${queued} follow-up${queued === 1 ? '' : 's'} queued${suffix}`);
1110
1191
  }
1111
1192
  return parts.join(' โ€ข ');
1112
1193
  }
@@ -1133,27 +1214,55 @@ export class InteractiveShell {
1133
1214
  this.terminalInput.setModeToggles({
1134
1215
  verificationEnabled: this.verificationEnabled,
1135
1216
  autoContinueEnabled: this.autoContinueEnabled,
1136
- verificationHotkey: 'alt+v',
1137
- autoContinueHotkey: 'alt+c',
1217
+ verificationHotkey: 'ctrl+shift+v',
1218
+ autoContinueHotkey: 'ctrl+shift+c',
1138
1219
  thinkingModeLabel: this.thinkingMode,
1139
- thinkingHotkey: '/thinking',
1220
+ thinkingHotkey: 'ctrl+shift+t',
1221
+ alphaZeroEnabled: this.alphaZeroModeEnabled,
1222
+ alphaZeroHotkey: 'ctrl+shift+a',
1223
+ alphaZeroLabel: 'AlphaZero RL',
1140
1224
  });
1141
1225
  this.refreshStatusLine();
1142
- this.terminalInput.render();
1226
+ this.renderPromptArea();
1143
1227
  }
1144
1228
  writeLocked(content) {
1145
1229
  if (!content) {
1146
1230
  return;
1147
1231
  }
1148
- // If lock is already held, write directly - we're in a protected context
1149
- // This prevents queuing issues where content gets delayed
1150
- if (writeLock.isLocked()) {
1151
- process.stdout.write(content);
1232
+ // Route through display stream so scroll regions and streaming locks stay in sync
1233
+ display.stream(content);
1234
+ }
1235
+ isStreamingUiActive() {
1236
+ return this.streamingHeartbeatStart !== null;
1237
+ }
1238
+ /**
1239
+ * Render the prompt/control bar. During streaming, rely on the streaming frame
1240
+ * renderer and enqueue through the UIUpdateCoordinator to avoid fighting the
1241
+ * scroll region or duplicating the prompt.
1242
+ */
1243
+ renderPromptArea(force = false) {
1244
+ if (this.isStreamingUiActive()) {
1245
+ this.uiUpdates.enqueue({
1246
+ lane: 'prompt',
1247
+ mode: ['streaming', 'processing'],
1248
+ coalesceKey: 'prompt:streaming-frame',
1249
+ description: 'render streaming prompt frame',
1250
+ run: () => {
1251
+ if (force) {
1252
+ this.terminalInput.renderStreamingFrame(true);
1253
+ return;
1254
+ }
1255
+ this.terminalInput.renderStreamingFrame();
1256
+ },
1257
+ });
1152
1258
  return;
1153
1259
  }
1154
- writeLock.withLock(() => {
1155
- process.stdout.write(content);
1156
- }, 'interactiveShell.stdout');
1260
+ if (force) {
1261
+ this.terminalInput.forceRender();
1262
+ }
1263
+ else {
1264
+ this.terminalInput.render();
1265
+ }
1157
1266
  }
1158
1267
  /**
1159
1268
  * Refresh the status line in the persistent input area.
@@ -1199,7 +1308,7 @@ export class InteractiveShell {
1199
1308
  provider: this.providerLabel(this.sessionState.provider),
1200
1309
  });
1201
1310
  if (forceRender) {
1202
- this.terminalInput.render();
1311
+ this.renderPromptArea(true);
1203
1312
  }
1204
1313
  }
1205
1314
  /**
@@ -1232,45 +1341,11 @@ export class InteractiveShell {
1232
1341
  }
1233
1342
  return parts.join(' โ€ข ');
1234
1343
  }
1235
- handleSlashCommandPreviewChange() {
1236
- if (this.pendingInteraction) {
1237
- this.slashPreviewVisible = false;
1238
- return;
1239
- }
1240
- const shouldShow = this.shouldShowSlashCommandPreview();
1241
- if (shouldShow && !this.slashPreviewVisible) {
1242
- this.slashPreviewVisible = true;
1243
- this.showSlashCommandPreview();
1244
- return;
1245
- }
1246
- if (!shouldShow && this.slashPreviewVisible) {
1247
- this.slashPreviewVisible = false;
1248
- this.uiAdapter.hideSlashCommandPreview();
1249
- }
1250
- }
1251
- shouldShowSlashCommandPreview() {
1252
- const line = this.currentInput ?? '';
1253
- if (!line.trim()) {
1254
- return false;
1255
- }
1256
- const trimmed = line.trimStart();
1257
- return trimmed.startsWith('/');
1258
- }
1259
- showSlashCommandPreview() {
1260
- // Filter commands based on current input
1261
- const line = this.currentInput ?? '';
1262
- const trimmed = line.trimStart();
1263
- // Filter commands that match the current input
1264
- const filtered = this.slashCommands.filter(cmd => cmd.command.startsWith(trimmed) || trimmed === '/');
1265
- // Show in the unified UI with dynamic overlay
1266
- this.uiAdapter.showSlashCommandPreview(filtered);
1267
- // Don't reprompt - this causes flickering
1268
- }
1269
1344
  /**
1270
1345
  * Ensure the terminal input is ready for interactive input.
1271
1346
  */
1272
1347
  ensureReadlineReady() {
1273
- this.terminalInput.render();
1348
+ this.renderPromptArea();
1274
1349
  }
1275
1350
  /**
1276
1351
  * Log user prompt to the scroll region so it's part of the conversation flow.
@@ -1292,7 +1367,7 @@ export class InteractiveShell {
1292
1367
  }
1293
1368
  requestPromptRefresh(force = false) {
1294
1369
  if (force) {
1295
- this.terminalInput.forceRender();
1370
+ this.renderPromptArea(true);
1296
1371
  return;
1297
1372
  }
1298
1373
  if (this.promptRefreshTimer) {
@@ -1300,7 +1375,7 @@ export class InteractiveShell {
1300
1375
  }
1301
1376
  this.promptRefreshTimer = setTimeout(() => {
1302
1377
  this.promptRefreshTimer = null;
1303
- this.terminalInput.render();
1378
+ this.renderPromptArea();
1304
1379
  }, 48);
1305
1380
  }
1306
1381
  clearPromptRefreshTimer() {
@@ -1309,6 +1384,25 @@ export class InteractiveShell {
1309
1384
  this.promptRefreshTimer = null;
1310
1385
  }
1311
1386
  }
1387
+ async withStreamingUi(label, run) {
1388
+ if (this.isStreamingUiActive()) {
1389
+ return run();
1390
+ }
1391
+ this.terminalInput.setStreaming(true);
1392
+ this.startStreamingHeartbeat(label);
1393
+ try {
1394
+ return await run();
1395
+ }
1396
+ finally {
1397
+ this.stopStreamingHeartbeat();
1398
+ this.terminalInput.setStreaming(false);
1399
+ const nextMode = this.isProcessing ? 'processing' : 'idle';
1400
+ this.uiUpdates.setMode(nextMode);
1401
+ if (nextMode === 'processing') {
1402
+ queueMicrotask(() => this.uiUpdates.setMode('idle'));
1403
+ }
1404
+ }
1405
+ }
1312
1406
  startStreamingHeartbeat(label = 'Streaming') {
1313
1407
  this.stopStreamingHeartbeat();
1314
1408
  // Enter global streaming mode - blocks all non-streaming UI output
@@ -1389,7 +1483,7 @@ export class InteractiveShell {
1389
1483
  else {
1390
1484
  this.setIdleStatus();
1391
1485
  }
1392
- this.terminalInput.render();
1486
+ this.renderPromptArea();
1393
1487
  }
1394
1488
  enqueueFollowUpAction(action) {
1395
1489
  this.followUpQueue.push(action);
@@ -1408,7 +1502,7 @@ export class InteractiveShell {
1408
1502
  this.refreshQueueIndicators();
1409
1503
  this.scheduleQueueProcessing();
1410
1504
  // Re-show the prompt so user can continue typing more follow-ups
1411
- this.terminalInput.render();
1505
+ this.renderPromptArea();
1412
1506
  }
1413
1507
  scheduleQueueProcessing() {
1414
1508
  if (!this.followUpQueue.length) {
@@ -1449,8 +1543,6 @@ export class InteractiveShell {
1449
1543
  }
1450
1544
  }
1451
1545
  async processInputBlock(line, _wasRapidMultiLine = false) {
1452
- this.slashPreviewVisible = false;
1453
- this.uiAdapter.hideSlashCommandPreview();
1454
1546
  const trimmed = line.trim();
1455
1547
  if (await this.handlePendingInteraction(trimmed)) {
1456
1548
  return;
@@ -1465,12 +1557,12 @@ export class InteractiveShell {
1465
1557
  }
1466
1558
  if (lower === 'clear') {
1467
1559
  display.clear();
1468
- this.terminalInput.render();
1560
+ this.renderPromptArea();
1469
1561
  return;
1470
1562
  }
1471
1563
  if (lower === 'help') {
1472
1564
  this.showHelp();
1473
- this.terminalInput.render();
1565
+ this.renderPromptArea();
1474
1566
  return;
1475
1567
  }
1476
1568
  if (trimmed.startsWith('/')) {
@@ -1480,12 +1572,12 @@ export class InteractiveShell {
1480
1572
  // Check for continuous/infinite loop commands
1481
1573
  if (this.isContinuousCommand(trimmed)) {
1482
1574
  await this.processContinuousRequest(trimmed);
1483
- this.terminalInput.render();
1575
+ this.renderPromptArea();
1484
1576
  return;
1485
1577
  }
1486
1578
  // Direct execution for all inputs, including multi-line pastes
1487
1579
  await this.processRequest(trimmed);
1488
- this.terminalInput.render();
1580
+ this.renderPromptArea();
1489
1581
  }
1490
1582
  /**
1491
1583
  * Check if the command is a continuous/infinite loop command
@@ -1523,6 +1615,60 @@ export class InteractiveShell {
1523
1615
  ];
1524
1616
  return patterns.some(pattern => pattern.test(lower));
1525
1617
  }
1618
+ isDifficultProblem(input) {
1619
+ const normalized = input.toLowerCase();
1620
+ const wordCount = normalized.split(/\s+/).filter(Boolean).length;
1621
+ if (normalized.length > 600 || wordCount > 80) {
1622
+ return true;
1623
+ }
1624
+ const signals = [
1625
+ 'root cause',
1626
+ 'postmortem',
1627
+ 'crash',
1628
+ 'incident',
1629
+ 'outage',
1630
+ 'optimiz',
1631
+ 'performance',
1632
+ 'throughput',
1633
+ 'latency',
1634
+ 'scalab',
1635
+ 'architecture',
1636
+ 'rewrite',
1637
+ 'migration',
1638
+ 'refactor',
1639
+ 'reverse engineer',
1640
+ 'security',
1641
+ 'exploit',
1642
+ 'injection',
1643
+ 'vulnerability',
1644
+ 'compliance',
1645
+ 'multi-step',
1646
+ 'complex',
1647
+ 'difficult',
1648
+ 'hard problem',
1649
+ 'debug',
1650
+ 'trace',
1651
+ 'profil',
1652
+ 'bottleneck',
1653
+ ];
1654
+ return signals.some((signal) => normalized.includes(signal));
1655
+ }
1656
+ buildAlphaZeroPrompt(request, flaggedDifficult) {
1657
+ const playbook = [
1658
+ 'AlphaZero RL MODE is ACTIVE. Operate as a self-play reinforcement loop.',
1659
+ flaggedDifficult
1660
+ ? 'Treat this as a difficult, high-risk task and over-verify the result.'
1661
+ : 'Apply the reinforcement loop even if the task looks small.',
1662
+ 'Follow this closed-loop playbook:',
1663
+ '- Draft two competing solution strategies and merge the strongest ideas before executing.',
1664
+ '- Execute with tools while logging decisions and evidence.',
1665
+ '- Self-critique and repair until the quality is excellent (aim โ‰ฅ90/100).',
1666
+ '- Run full-lifecycle verification like a human reviewer: build/tests, manual sanity checks, edge cases, performance/safety/security probes, docs/UX/readiness notes.',
1667
+ '- Keep a verification ledger: each check with PASS/FAIL, evidence, and remaining risks. If anything fails, fix and re-verify before claiming completion.',
1668
+ 'Finish with a concise sign-off that lists what was achieved and the proof of completion.',
1669
+ ];
1670
+ return `${playbook.join('\n')}\n\nPrimary user request:\n${request.trim()}`;
1671
+ }
1526
1672
  async handlePendingInteraction(input) {
1527
1673
  if (!this.pendingInteraction) {
1528
1674
  return false;
@@ -1530,7 +1676,7 @@ export class InteractiveShell {
1530
1676
  switch (this.pendingInteraction.type) {
1531
1677
  case 'model-loading':
1532
1678
  display.showInfo('Still fetching model options. Please wait a moment.');
1533
- this.terminalInput.render();
1679
+ this.renderPromptArea();
1534
1680
  return true;
1535
1681
  case 'model-provider':
1536
1682
  await this.handleModelProviderSelection(input);
@@ -1561,7 +1707,7 @@ export class InteractiveShell {
1561
1707
  const [command] = input.split(/\s+/);
1562
1708
  if (!command) {
1563
1709
  display.showWarning('Enter a slash command.');
1564
- this.terminalInput.render();
1710
+ this.renderPromptArea();
1565
1711
  return;
1566
1712
  }
1567
1713
  switch (command) {
@@ -1619,6 +1765,9 @@ export class InteractiveShell {
1619
1765
  case '/autocontinue':
1620
1766
  this.handleAutoContinueCommand(input);
1621
1767
  break;
1768
+ case '/alphazero':
1769
+ this.handleAlphaZeroCommand(input);
1770
+ break;
1622
1771
  case '/shortcuts':
1623
1772
  case '/keys':
1624
1773
  this.handleShortcutsCommand();
@@ -1646,6 +1795,9 @@ export class InteractiveShell {
1646
1795
  case '/a0':
1647
1796
  void this.handleModularCommand(input);
1648
1797
  break;
1798
+ case '/offsec':
1799
+ void this.handleOffsecCommand(input);
1800
+ break;
1649
1801
  case '/test':
1650
1802
  case '/tests':
1651
1803
  void this.handleTestCommand(input);
@@ -1720,7 +1872,7 @@ export class InteractiveShell {
1720
1872
  }
1721
1873
  break;
1722
1874
  }
1723
- this.terminalInput.render();
1875
+ this.renderPromptArea();
1724
1876
  }
1725
1877
  async tryCustomSlashCommand(command, fullInput) {
1726
1878
  const custom = this.customCommandMap.get(command);
@@ -1757,6 +1909,7 @@ export class InteractiveShell {
1757
1909
  ` ${theme.info('Option+V')} ${theme.ui.muted('Toggle verification')}`,
1758
1910
  ` ${theme.info('Option+C')} ${theme.ui.muted('Toggle auto-continue')}`,
1759
1911
  ` ${theme.info('Option+T')} ${theme.ui.muted('Cycle thinking mode')}`,
1912
+ ` ${theme.info('Option+A')} ${theme.ui.muted('Toggle AlphaZero RL mode')}`,
1760
1913
  ` ${theme.info('Option+E')} ${theme.ui.muted('Toggle edit permission mode')}`,
1761
1914
  ` ${theme.info('Option+X')} ${theme.ui.muted('Clear/compact context')}`,
1762
1915
  '',
@@ -2042,6 +2195,24 @@ export class InteractiveShell {
2042
2195
  };
2043
2196
  display.showInfo(`Thinking mode set to ${theme.info(value)} โ€“ ${descriptions[this.thinkingMode]}`);
2044
2197
  }
2198
+ handleAlphaZeroCommand(input) {
2199
+ const value = input.slice('/alphazero'.length).trim().toLowerCase();
2200
+ if (!value || value === 'status') {
2201
+ const status = this.alphaZeroModeEnabled ? theme.success('on') : theme.ui.muted('off');
2202
+ const verification = this.verificationEnabled ? 'verification locked on' : 'verification optional';
2203
+ display.showInfo(`AlphaZero RL mode is ${status}. When enabled, difficult prompts use duel/self-critique and human-style verification (${verification}).`);
2204
+ return;
2205
+ }
2206
+ if (['on', 'enable', 'enabled'].includes(value)) {
2207
+ this.setAlphaZeroMode(true, 'command');
2208
+ return;
2209
+ }
2210
+ if (['off', 'disable', 'disabled'].includes(value)) {
2211
+ this.setAlphaZeroMode(false, 'command');
2212
+ return;
2213
+ }
2214
+ display.showWarning('Usage: /alphazero [on|off|status]');
2215
+ }
2045
2216
  handleShortcutsCommand() {
2046
2217
  // Display keyboard shortcuts help (Claude Code style)
2047
2218
  display.showSystemMessage(formatShortcutsHelp());
@@ -2907,6 +3078,150 @@ export class InteractiveShell {
2907
3078
  display.showInfo('Note: /modular is now part of /evolve. Use /evolve tokens, /evolve targets, etc.');
2908
3079
  await this.handleEvolveCommand(evolveInput);
2909
3080
  }
3081
+ /**
3082
+ * Handle /offsec command - AlphaZero offensive security run helper
3083
+ */
3084
+ async handleOffsecCommand(input) {
3085
+ const args = input.trim().split(/\s+/).slice(1);
3086
+ const sub = (args[0]?.toLowerCase() ?? 'status');
3087
+ const usage = 'Usage: /offsec start <objective> [--scope target1,target2]\n' +
3088
+ ' /offsec status [runId]\n' +
3089
+ ' /offsec next [count]\n' +
3090
+ ' /offsec auto [steps]\n' +
3091
+ ' /offsec win|fail|detect <actionId> [note]\n' +
3092
+ ' /offsec resume <runId>\n' +
3093
+ ' /offsec runs';
3094
+ const loadRun = (explicitId) => {
3095
+ const run = resumeOffsecRun(explicitId ?? this.offsecRunId);
3096
+ if (!run) {
3097
+ display.showWarning('No offsec run found. Start one with /offsec start "<objective>".');
3098
+ }
3099
+ return run;
3100
+ };
3101
+ if (sub === 'start') {
3102
+ const rest = args.slice(1);
3103
+ const scope = [];
3104
+ const objectiveParts = [];
3105
+ for (let i = 0; i < rest.length; i++) {
3106
+ if (rest[i]?.toLowerCase() === '--scope') {
3107
+ const scopeArg = rest[i + 1];
3108
+ if (scopeArg) {
3109
+ scope.push(...scopeArg.split(',').map((s) => s.trim()).filter(Boolean));
3110
+ }
3111
+ i += 1;
3112
+ continue;
3113
+ }
3114
+ objectiveParts.push(rest[i]);
3115
+ }
3116
+ const objective = objectiveParts.join(' ').trim();
3117
+ if (!objective) {
3118
+ display.showWarning('Provide an objective. Example: /offsec start gain shell on api.example.com --scope api.example.com');
3119
+ display.showInfo(usage);
3120
+ return;
3121
+ }
3122
+ const run = startOffsecRun(objective, scope);
3123
+ this.offsecRunId = run.id;
3124
+ const next = getOffsecNextActions(run.id, 3);
3125
+ display.showSystemMessage(theme.gradient.primary('๐Ÿ›ก๏ธ Offsec AlphaZero run started'));
3126
+ display.showSystemMessage(formatOffsecStatus(run, next));
3127
+ return;
3128
+ }
3129
+ if (sub === 'resume') {
3130
+ const targetRun = args[1] ?? this.offsecRunId;
3131
+ const run = resumeOffsecRun(targetRun);
3132
+ if (!run) {
3133
+ display.showWarning(`No offsec run found for id ${targetRun ?? '<unset>'}`);
3134
+ return;
3135
+ }
3136
+ this.offsecRunId = run.id;
3137
+ display.showSystemMessage(theme.gradient.primary(`Resumed offsec run ${run.id}`));
3138
+ display.showSystemMessage(formatOffsecStatus(run, getOffsecNextActions(run.id, 3)));
3139
+ return;
3140
+ }
3141
+ if (sub === 'runs') {
3142
+ const runs = listOffsecRuns();
3143
+ if (runs.length === 0) {
3144
+ display.showInfo('No offsec runs recorded yet.');
3145
+ return;
3146
+ }
3147
+ const lines = [];
3148
+ lines.push(theme.gradient.primary('Recorded offsec runs'));
3149
+ for (const run of runs.slice(0, 10)) {
3150
+ lines.push(`- ${run.id} :: ${run.objective} (updated ${run.updatedAt})`);
3151
+ }
3152
+ if (runs.length > 10) {
3153
+ lines.push(`...and ${runs.length - 10} more`);
3154
+ }
3155
+ display.showSystemMessage(lines.join('\n'));
3156
+ return;
3157
+ }
3158
+ const run = resumeOffsecRun(args[1] ?? this.offsecRunId);
3159
+ if (!run) {
3160
+ return;
3161
+ }
3162
+ this.offsecRunId = run.id;
3163
+ if (sub === 'status' || sub === 'help') {
3164
+ const next = getOffsecNextActions(run.id, 3);
3165
+ display.showSystemMessage(formatOffsecStatus(run, next));
3166
+ if (next.length === 0) {
3167
+ display.showInfo('No pending actions. Mark outcomes or start a new run.');
3168
+ }
3169
+ return;
3170
+ }
3171
+ if (sub === 'next') {
3172
+ const count = Number.isFinite(Number(args[1])) ? Math.max(1, parseInt(args[1], 10)) : 3;
3173
+ const next = getOffsecNextActions(run.id, count);
3174
+ if (next.length === 0) {
3175
+ display.showInfo('No pending actions to suggest.');
3176
+ return;
3177
+ }
3178
+ const lines = [];
3179
+ lines.push(theme.gradient.primary(`Top ${next.length} actions`));
3180
+ for (const action of next) {
3181
+ lines.push(`- [${action.id}] ${action.label} (${action.category}) score=${action.score}`);
3182
+ lines.push(` cmd: ${action.command}`);
3183
+ lines.push(` path: ${action.path.join(' -> ')}`);
3184
+ }
3185
+ lines.push('Mark progress with /offsec win|fail|detect <actionId> [note]');
3186
+ display.showSystemMessage(lines.join('\n'));
3187
+ return;
3188
+ }
3189
+ if (sub === 'auto') {
3190
+ const steps = Number.isFinite(Number(args[1])) ? Math.max(1, parseInt(args[1], 10)) : 5;
3191
+ const plan = simulateOffsecRollout(run.id, steps);
3192
+ if (plan.length === 0) {
3193
+ display.showInfo('No pending actions to simulate.');
3194
+ return;
3195
+ }
3196
+ const lines = [];
3197
+ lines.push(theme.gradient.primary(`Simulated ${plan.length} steps (AlphaZero-style rollout)`));
3198
+ for (const action of plan) {
3199
+ lines.push(`- [${action.id}] ${action.label} (${action.category}) score=${action.score}`);
3200
+ }
3201
+ lines.push('Use /offsec next to view updated ranking.');
3202
+ display.showSystemMessage(lines.join('\n'));
3203
+ return;
3204
+ }
3205
+ if (sub === 'win' || sub === 'fail' || sub === 'detect') {
3206
+ const actionId = args[1];
3207
+ if (!actionId) {
3208
+ display.showWarning('Specify an action id. Example: /offsec win a3 "got shell via RCE"');
3209
+ return;
3210
+ }
3211
+ const note = args.slice(2).join(' ').trim();
3212
+ const outcome = sub === 'win' ? 'success' : sub === 'fail' ? 'fail' : 'detected';
3213
+ const updated = recordOffsecOutcome(run.id, actionId, outcome, note);
3214
+ if (!updated) {
3215
+ display.showWarning(`Action ${actionId} not found in run ${run.id}.`);
3216
+ return;
3217
+ }
3218
+ const next = getOffsecNextActions(run.id, 3);
3219
+ display.showSystemMessage(theme.success(`Recorded ${outcome} for ${actionId} in run ${run.id}`));
3220
+ display.showSystemMessage(formatOffsecStatus(updated, next));
3221
+ return;
3222
+ }
3223
+ display.showInfo(usage);
3224
+ }
2910
3225
  /**
2911
3226
  * Handle /test command for intelligent test flows
2912
3227
  */
@@ -3222,7 +3537,7 @@ export class InteractiveShell {
3222
3537
  if (!value) {
3223
3538
  // Show current status
3224
3539
  display.showInfo(`Auto-continue is ${this.autoContinueEnabled ? 'enabled' : 'disabled'}. ` +
3225
- `Use /autocontinue on|off or alt+c to toggle.`);
3540
+ `Use /autocontinue on|off or Ctrl+Shift+C to toggle.`);
3226
3541
  return;
3227
3542
  }
3228
3543
  if (value !== 'on' && value !== 'off') {
@@ -3367,7 +3682,7 @@ export class InteractiveShell {
3367
3682
  display.clear();
3368
3683
  clearAutosaveSnapshot(this.profile);
3369
3684
  display.showInfo('Conversation cleared. Starting fresh.');
3370
- this.terminalInput.render();
3685
+ this.renderPromptArea();
3371
3686
  }
3372
3687
  async handleResumeCommand(input) {
3373
3688
  const tokens = input.split(/\s+/).slice(1);
@@ -3676,7 +3991,7 @@ export class InteractiveShell {
3676
3991
  if (!providerOptions.length) {
3677
3992
  display.showWarning('No providers are available.');
3678
3993
  this.pendingInteraction = null;
3679
- this.terminalInput.render();
3994
+ this.renderPromptArea();
3680
3995
  return;
3681
3996
  }
3682
3997
  const lines = [
@@ -3697,7 +4012,7 @@ export class InteractiveShell {
3697
4012
  catch (error) {
3698
4013
  display.showError('Failed to load model list. Try again in a moment.', error);
3699
4014
  this.pendingInteraction = null;
3700
- this.terminalInput.render();
4015
+ this.renderPromptArea();
3701
4016
  }
3702
4017
  }
3703
4018
  buildProviderOptions() {
@@ -4242,29 +4557,29 @@ export class InteractiveShell {
4242
4557
  const trimmed = input.trim();
4243
4558
  if (!trimmed) {
4244
4559
  display.showWarning('Enter a number or type cancel.');
4245
- this.terminalInput.render();
4560
+ this.renderPromptArea();
4246
4561
  return;
4247
4562
  }
4248
4563
  if (trimmed.toLowerCase() === 'cancel') {
4249
4564
  this.pendingInteraction = null;
4250
4565
  display.showInfo('Model selection cancelled.');
4251
- this.terminalInput.render();
4566
+ this.renderPromptArea();
4252
4567
  return;
4253
4568
  }
4254
4569
  const choice = Number.parseInt(trimmed, 10);
4255
4570
  if (!Number.isFinite(choice)) {
4256
4571
  display.showWarning('Please enter a valid number.');
4257
- this.terminalInput.render();
4572
+ this.renderPromptArea();
4258
4573
  return;
4259
4574
  }
4260
4575
  const option = pending.options[choice - 1];
4261
4576
  if (!option) {
4262
4577
  display.showWarning('That option is not available.');
4263
- this.terminalInput.render();
4578
+ this.renderPromptArea();
4264
4579
  return;
4265
4580
  }
4266
4581
  this.showProviderModels(option);
4267
- this.terminalInput.render();
4582
+ this.renderPromptArea();
4268
4583
  }
4269
4584
  async handleModelSelection(input) {
4270
4585
  const pending = this.pendingInteraction;
@@ -4274,35 +4589,35 @@ export class InteractiveShell {
4274
4589
  const trimmed = input.trim();
4275
4590
  if (!trimmed) {
4276
4591
  display.showWarning('Enter a number, type "back", or type "cancel".');
4277
- this.terminalInput.render();
4592
+ this.renderPromptArea();
4278
4593
  return;
4279
4594
  }
4280
4595
  if (trimmed.toLowerCase() === 'back') {
4281
4596
  this.showModelMenu();
4282
- this.terminalInput.render();
4597
+ this.renderPromptArea();
4283
4598
  return;
4284
4599
  }
4285
4600
  if (trimmed.toLowerCase() === 'cancel') {
4286
4601
  this.pendingInteraction = null;
4287
4602
  display.showInfo('Model selection cancelled.');
4288
- this.terminalInput.render();
4603
+ this.renderPromptArea();
4289
4604
  return;
4290
4605
  }
4291
4606
  const choice = Number.parseInt(trimmed, 10);
4292
4607
  if (!Number.isFinite(choice)) {
4293
4608
  display.showWarning('Please enter a valid number.');
4294
- this.terminalInput.render();
4609
+ this.renderPromptArea();
4295
4610
  return;
4296
4611
  }
4297
4612
  const preset = pending.options[choice - 1];
4298
4613
  if (!preset) {
4299
4614
  display.showWarning('That option is not available.');
4300
- this.terminalInput.render();
4615
+ this.renderPromptArea();
4301
4616
  return;
4302
4617
  }
4303
4618
  this.pendingInteraction = null;
4304
4619
  await this.applyModelPreset(preset);
4305
- this.terminalInput.render();
4620
+ this.renderPromptArea();
4306
4621
  }
4307
4622
  async applyModelPreset(preset) {
4308
4623
  try {
@@ -4335,30 +4650,30 @@ export class InteractiveShell {
4335
4650
  const trimmed = input.trim();
4336
4651
  if (!trimmed) {
4337
4652
  display.showWarning('Enter a number or type cancel.');
4338
- this.terminalInput.render();
4653
+ this.renderPromptArea();
4339
4654
  return;
4340
4655
  }
4341
4656
  if (trimmed.toLowerCase() === 'cancel') {
4342
4657
  this.pendingInteraction = null;
4343
4658
  display.showInfo('Secret management cancelled.');
4344
- this.terminalInput.render();
4659
+ this.renderPromptArea();
4345
4660
  return;
4346
4661
  }
4347
4662
  const choice = Number.parseInt(trimmed, 10);
4348
4663
  if (!Number.isFinite(choice)) {
4349
4664
  display.showWarning('Please enter a valid number.');
4350
- this.terminalInput.render();
4665
+ this.renderPromptArea();
4351
4666
  return;
4352
4667
  }
4353
4668
  const secret = pending.options[choice - 1];
4354
4669
  if (!secret) {
4355
4670
  display.showWarning('That option is not available.');
4356
- this.terminalInput.render();
4671
+ this.renderPromptArea();
4357
4672
  return;
4358
4673
  }
4359
4674
  display.showSystemMessage(`Enter a new value for ${secret.label} or type "cancel".`);
4360
4675
  this.pendingInteraction = { type: 'secret-input', secret };
4361
- this.terminalInput.render();
4676
+ this.renderPromptArea();
4362
4677
  }
4363
4678
  async handleSecretInput(input) {
4364
4679
  const pending = this.pendingInteraction;
@@ -4368,14 +4683,14 @@ export class InteractiveShell {
4368
4683
  const trimmed = input.trim();
4369
4684
  if (!trimmed) {
4370
4685
  display.showWarning('Enter a value or type cancel.');
4371
- this.terminalInput.render();
4686
+ this.renderPromptArea();
4372
4687
  return;
4373
4688
  }
4374
4689
  if (trimmed.toLowerCase() === 'cancel') {
4375
4690
  this.pendingInteraction = null;
4376
4691
  this.pendingSecretRetry = null;
4377
4692
  display.showInfo('Secret unchanged.');
4378
- this.terminalInput.render();
4693
+ this.renderPromptArea();
4379
4694
  return;
4380
4695
  }
4381
4696
  try {
@@ -4399,11 +4714,11 @@ export class InteractiveShell {
4399
4714
  this.pendingInteraction = null;
4400
4715
  this.pendingSecretRetry = null;
4401
4716
  }
4402
- this.terminalInput.render();
4717
+ this.renderPromptArea();
4403
4718
  }
4404
- async processRequest(request) {
4719
+ async processRequest(userRequest) {
4405
4720
  if (this.isProcessing) {
4406
- this.enqueueFollowUpAction({ type: 'request', text: request });
4721
+ this.enqueueFollowUpAction({ type: 'request', text: userRequest });
4407
4722
  return;
4408
4723
  }
4409
4724
  if (!this.agent && !this.rebuildAgent()) {
@@ -4414,28 +4729,48 @@ export class InteractiveShell {
4414
4729
  if (!agent) {
4415
4730
  return;
4416
4731
  }
4417
- this.logUserPrompt(request);
4732
+ const alphaZeroEngaged = this.alphaZeroModeEnabled;
4733
+ const alphaZeroDifficult = alphaZeroEngaged ? this.isDifficultProblem(userRequest) : false;
4734
+ const requestForAgent = alphaZeroEngaged
4735
+ ? this.buildAlphaZeroPrompt(userRequest, alphaZeroDifficult)
4736
+ : userRequest;
4737
+ const alphaZeroStatusId = 'alpha-zero';
4738
+ let alphaZeroStatusApplied = false;
4739
+ let alphaZeroTaskStarted = false;
4740
+ let alphaZeroTaskCompleted = false;
4741
+ if (alphaZeroEngaged) {
4742
+ const detail = alphaZeroDifficult ? 'Difficult request detected' : 'Reinforcement loop enabled';
4743
+ this.statusTracker.pushOverride(alphaZeroStatusId, 'AlphaZero RL active', {
4744
+ detail: `${detail} ยท full verification`,
4745
+ tone: 'info',
4746
+ });
4747
+ alphaZeroStatusApplied = true;
4748
+ display.showInfo(`AlphaZero RL mode engaged${alphaZeroDifficult ? ' for a difficult request' : ''}. Duel + self-critique with verification enabled.`);
4749
+ this.alphaZeroMetrics.startAlphaZeroTask(userRequest);
4750
+ alphaZeroTaskStarted = true;
4751
+ }
4752
+ this.logUserPrompt(userRequest);
4418
4753
  this.isProcessing = true;
4419
4754
  this.uiUpdates.setMode('processing');
4420
4755
  this.terminalInput.setStreaming(true);
4421
4756
  // Keep the persistent input/control bar active as we transition into streaming.
4422
- this.terminalInput.forceRender();
4757
+ this.renderPromptArea(true);
4423
4758
  const requestStartTime = Date.now(); // Alpha Zero 2 timing
4424
4759
  // Clear previous parallel agents and start fresh for new request
4425
4760
  const parallelManager = getParallelAgentManager();
4426
4761
  parallelManager.clear();
4427
4762
  parallelManager.startBatch();
4428
4763
  // AlphaZero: Track task for learning
4429
- this.lastUserQuery = request;
4430
- this.currentTaskType = classifyTaskType(request);
4764
+ this.lastUserQuery = userRequest;
4765
+ this.currentTaskType = classifyTaskType(userRequest);
4431
4766
  this.currentToolCalls = [];
4432
4767
  this.uiAdapter.startProcessing('Working on your request');
4433
4768
  this.setProcessingStatus();
4434
4769
  let responseText = '';
4435
4770
  try {
4436
4771
  // Start streaming - no header needed, the input area already provides context
4437
- this.startStreamingHeartbeat('Streaming response');
4438
- responseText = await agent.send(request, true);
4772
+ this.startStreamingHeartbeat(alphaZeroEngaged ? 'AlphaZero RL' : 'Streaming response');
4773
+ responseText = await agent.send(requestForAgent, true);
4439
4774
  await this.awaitPendingCleanup();
4440
4775
  this.captureHistorySnapshot();
4441
4776
  this.autosaveIfEnabled();
@@ -4456,8 +4791,12 @@ export class InteractiveShell {
4456
4791
  // AlphaZero: Check for failure in response
4457
4792
  const failure = detectFailure(responseText, {
4458
4793
  toolCalls: this.currentToolCalls,
4459
- userMessage: request,
4794
+ userMessage: userRequest,
4460
4795
  });
4796
+ if (alphaZeroEngaged && alphaZeroTaskStarted && !alphaZeroTaskCompleted) {
4797
+ this.alphaZeroMetrics.completeAlphaZeroTask(!failure);
4798
+ alphaZeroTaskCompleted = true;
4799
+ }
4461
4800
  if (failure) {
4462
4801
  this.lastFailure = failure;
4463
4802
  // Check if we have a recovery strategy
@@ -4484,13 +4823,23 @@ export class InteractiveShell {
4484
4823
  }
4485
4824
  }
4486
4825
  catch (error) {
4487
- const handled = this.handleProviderError(error, () => this.processRequest(request));
4826
+ const handled = this.handleProviderError(error, () => this.processRequest(userRequest));
4827
+ if (alphaZeroEngaged && alphaZeroTaskStarted && !alphaZeroTaskCompleted) {
4828
+ this.alphaZeroMetrics.completeAlphaZeroTask(false);
4829
+ alphaZeroTaskCompleted = true;
4830
+ }
4488
4831
  if (!handled) {
4489
4832
  // Pass full error object for enhanced formatting with stack trace
4490
4833
  display.showError(error instanceof Error ? error.message : String(error), error);
4491
4834
  }
4492
4835
  }
4493
4836
  finally {
4837
+ if (alphaZeroEngaged && alphaZeroStatusApplied) {
4838
+ this.statusTracker.clearOverride(alphaZeroStatusId);
4839
+ }
4840
+ if (alphaZeroEngaged && alphaZeroTaskStarted && !alphaZeroTaskCompleted) {
4841
+ this.alphaZeroMetrics.completeAlphaZeroTask(false);
4842
+ }
4494
4843
  display.stopThinking(false);
4495
4844
  this.uiUpdates.setMode('processing');
4496
4845
  this.stopStreamingHeartbeat();
@@ -4504,7 +4853,7 @@ export class InteractiveShell {
4504
4853
  // CRITICAL: Ensure readline prompt is active for user input
4505
4854
  // Claude Code style: New prompt naturally appears at bottom
4506
4855
  this.ensureReadlineReady();
4507
- this.terminalInput.render();
4856
+ this.renderPromptArea();
4508
4857
  this.scheduleQueueProcessing();
4509
4858
  this.refreshQueueIndicators();
4510
4859
  }
@@ -4975,6 +5324,8 @@ What's the next action?`;
4975
5324
  finally {
4976
5325
  this.updateStatusMessage(null);
4977
5326
  this.autoTestInFlight = false;
5327
+ this.terminalInput.resetContentPosition();
5328
+ this.terminalInput.forceRender();
4978
5329
  }
4979
5330
  }
4980
5331
  isBuildToolCall(entry) {
@@ -5081,7 +5432,7 @@ What's the next action?`;
5081
5432
  // Send the error to the agent for fixing
5082
5433
  display.showThinking('Analyzing build errors');
5083
5434
  this.refreshStatusLine(true);
5084
- const response = await this.agent.send(prompt, true);
5435
+ const response = await this.withStreamingUi('Fixing build errors', () => this.agent.send(prompt, true));
5085
5436
  display.stopThinking();
5086
5437
  this.refreshStatusLine(true);
5087
5438
  if (response) {
@@ -5191,19 +5542,19 @@ What's the next action?`;
5191
5542
  this.updateContextUsage(percentage);
5192
5543
  }
5193
5544
  // Ensure prompt remains visible at bottom after context messages
5194
- this.terminalInput.render();
5545
+ this.renderPromptArea();
5195
5546
  },
5196
5547
  onContinueAfterRecovery: () => {
5197
5548
  // Update UI to show we're continuing after context recovery
5198
5549
  display.showSystemMessage(`๐Ÿ”„ Continuing after context recovery...`);
5199
5550
  this.updateStatusMessage('Retrying with reduced context...');
5200
- this.terminalInput.render();
5551
+ this.renderPromptArea();
5201
5552
  },
5202
5553
  onAutoContinue: (attempt, maxAttempts, _message) => {
5203
5554
  // Show auto-continue progress in UI
5204
5555
  display.showSystemMessage(`๐Ÿ”„ Auto-continue (${attempt}/${maxAttempts}): Model expressed intent, prompting to act...`);
5205
5556
  this.updateStatusMessage('Auto-continuing...');
5206
- this.terminalInput.render();
5557
+ this.renderPromptArea();
5207
5558
  },
5208
5559
  onCancelled: () => {
5209
5560
  // Update UI to show operation was cancelled
@@ -5212,7 +5563,7 @@ What's the next action?`;
5212
5563
  this.stopStreamingHeartbeat();
5213
5564
  this.updateStatusMessage(null);
5214
5565
  this.terminalInput.setStreaming(false);
5215
- this.terminalInput.render();
5566
+ this.renderPromptArea();
5216
5567
  },
5217
5568
  onVerificationNeeded: () => {
5218
5569
  void this.enforceAutoBuild('verification');
@@ -5250,7 +5601,7 @@ What's the next action?`;
5250
5601
  resetChatBoxAfterModelSwap() {
5251
5602
  this.updateStatusMessage(null);
5252
5603
  this.terminalInput.setStreaming(false);
5253
- this.terminalInput.render();
5604
+ this.renderPromptArea();
5254
5605
  this.ensureReadlineReady();
5255
5606
  }
5256
5607
  /**