erosolar-cli 1.7.421 → 1.7.422

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 (36) hide show
  1. package/dist/capabilities/statusCapability.d.ts +4 -0
  2. package/dist/capabilities/statusCapability.d.ts.map +1 -0
  3. package/dist/capabilities/statusCapability.js +92 -0
  4. package/dist/capabilities/statusCapability.js.map +1 -0
  5. package/dist/core/toolRuntime.d.ts +5 -0
  6. package/dist/core/toolRuntime.d.ts.map +1 -1
  7. package/dist/core/toolRuntime.js +25 -1
  8. package/dist/core/toolRuntime.js.map +1 -1
  9. package/dist/shell/interactiveShell.d.ts +2 -8
  10. package/dist/shell/interactiveShell.d.ts.map +1 -1
  11. package/dist/shell/interactiveShell.js +58 -73
  12. package/dist/shell/interactiveShell.js.map +1 -1
  13. package/dist/shell/shellApp.d.ts.map +1 -1
  14. package/dist/shell/shellApp.js +3 -0
  15. package/dist/shell/shellApp.js.map +1 -1
  16. package/dist/shell/terminalInput.d.ts +0 -5
  17. package/dist/shell/terminalInput.d.ts.map +1 -1
  18. package/dist/shell/terminalInput.js +0 -7
  19. package/dist/shell/terminalInput.js.map +1 -1
  20. package/dist/tools/localExplore.d.ts +1 -1
  21. package/dist/tools/localExplore.d.ts.map +1 -1
  22. package/dist/tools/localExplore.js +117 -46
  23. package/dist/tools/localExplore.js.map +1 -1
  24. package/dist/ui/ShellUIAdapter.d.ts +6 -0
  25. package/dist/ui/ShellUIAdapter.d.ts.map +1 -1
  26. package/dist/ui/ShellUIAdapter.js +78 -1
  27. package/dist/ui/ShellUIAdapter.js.map +1 -1
  28. package/dist/ui/display.d.ts +0 -31
  29. package/dist/ui/display.d.ts.map +1 -1
  30. package/dist/ui/display.js +0 -42
  31. package/dist/ui/display.js.map +1 -1
  32. package/dist/ui/streamingFormatter.d.ts +6 -2
  33. package/dist/ui/streamingFormatter.d.ts.map +1 -1
  34. package/dist/ui/streamingFormatter.js +37 -23
  35. package/dist/ui/streamingFormatter.js.map +1 -1
  36. package/package.json +1 -1
@@ -6,7 +6,6 @@ import { join } from 'node:path';
6
6
  import { display } from '../ui/display.js';
7
7
  import { isPlainOutputMode } from '../ui/outputMode.js';
8
8
  import { theme } from '../ui/theme.js';
9
- import { renderDivider } from '../ui/unified/layout.js';
10
9
  import { StreamingResponseFormatter } from '../ui/streamingFormatter.js';
11
10
  import { getContextWindowTokens } from '../core/contextWindow.js';
12
11
  import { ensureSecretForProvider, getSecretDefinitionForProvider, getSecretValue, listSecretDefinitions, maskSecret, setSecretValue, } from '../core/secretStore.js';
@@ -33,7 +32,7 @@ import { addToolPattern } from '../core/learningPersistence.js';
33
32
  import { classifyTaskType } from '../core/alphaZeroEngine.js';
34
33
  import { analyzeImprovementOpportunities, runSelfImprovementCycle, getImprovementSummary, runAutonomousImprovement, requestAutoImprovementStop, getAutoImprovementState, emergencyRollback, } from '../core/selfImprovement.js';
35
34
  import { listAvailablePlugins } from '../plugins/index.js';
36
- import { isErosolarRepo, isValidSourceRepo, getRepoName, analyzeSource, runSelfEvolution, stopEvolution, getEvolutionStatus, emergencyEvolutionRollback, learnSourcePatterns, generateFix, } from '../core/selfEvolution.js';
35
+ import { isValidSourceRepo, getRepoName, analyzeSource, runSelfEvolution, stopEvolution, getEvolutionStatus, emergencyEvolutionRollback, learnSourcePatterns, generateFix, } from '../core/selfEvolution.js';
37
36
  import { analyzeTokenUsage, discoverModularTargets, getModularStatusDisplay, generateContextOptimizations, getGuidelines, deleteGuideline, getPendingActions, executeModularAction, } from '../core/alphaZeroModular.js';
38
37
  import { startOffsecRun, resumeOffsecRun, recordOffsecOutcome, getOffsecNextActions, simulateOffsecRollout, formatOffsecStatus, listOffsecRuns, } from '../core/offsecAlphaZero.js';
39
38
  import { generateTestFlows, detectBugs, detectUIUpdates, saveTestFlows, saveBugReports, saveUIUpdates, getTestFlowStatus, } from '../core/intelligentTestFlows.js';
@@ -77,7 +76,6 @@ const CONTEXT_AUTOCOMPACT_PERCENT = Math.round(CONTEXT_USAGE_THRESHOLD * 100);
77
76
  const CONTEXT_AUTOCOMPACT_FLOOR = 0.6;
78
77
  const MIN_COMPACTION_TOKEN_SAVINGS = 200;
79
78
  const MIN_COMPACTION_PERCENT_SAVINGS = 0.5;
80
- const CONTEXT_RECENT_MESSAGE_COUNT = 12;
81
79
  const CONTEXT_CLEANUP_CHARS_PER_CHUNK = 6000;
82
80
  const CONTEXT_CLEANUP_MAX_OUTPUT_TOKENS = 800;
83
81
  const CONTEXT_CLEANUP_SYSTEM_PROMPT = `Summarize earlier IDE collaboration so the agent can keep working.
@@ -125,7 +123,6 @@ export class InteractiveShell {
125
123
  planApprovalBridgeRegistered = false;
126
124
  contextCompactionInFlight = false;
127
125
  contextCompactionLog = [];
128
- bannerShown = false;
129
126
  lastContextWarningLevel = null;
130
127
  sessionPreferences;
131
128
  autosaveEnabled;
@@ -173,9 +170,9 @@ export class InteractiveShell {
173
170
  statusMessageOverride = null;
174
171
  promptRefreshTimer = null;
175
172
  launchPaletteShown = false;
176
- launchBannerText = null;
177
173
  version;
178
174
  alternateScreenEnabled;
175
+ welcomeShown = false;
179
176
  constructor(config) {
180
177
  this.profile = config.profile;
181
178
  this.profileLabel = config.profileLabel;
@@ -379,29 +376,25 @@ export class InteractiveShell {
379
376
  display.showInfo(this.sessionResumeNotice);
380
377
  this.sessionResumeNotice = null;
381
378
  }
382
- renderWelcomeBanner(force = false) {
383
- const header = `${theme.fields.model(this.sessionState.model)} ${theme.ui.muted('@')} ${theme.fields.agent(this.providerLabel(this.sessionState.provider))}`;
379
+ showWelcomeBanner(force = false) {
380
+ if (this.welcomeShown && !force) {
381
+ return;
382
+ }
383
+ const header = theme.gradient.primary('Erosolar CLI');
384
+ const modelLine = `${theme.fields.model(this.sessionState.model)} ${theme.ui.muted('@')} ${theme.fields.agent(this.providerLabel(this.sessionState.provider))}`;
384
385
  const profileLine = `${theme.fields.profile(this.profileLabel)} ${theme.ui.muted(`(${this.profile})`)}`;
385
386
  const workspaceLine = theme.fields.workspace(this.workingDir);
386
387
  const versionLine = this.version ? theme.ui.muted(`v${this.version} · support@ero.solar`) : null;
387
388
  const hintLine = theme.ui.muted('/help for commands · /model to switch · /secrets for keys');
388
- const width = output.columns ?? 80;
389
- const banner = [header, profileLine, workspaceLine, versionLine, hintLine, renderDivider(width)]
389
+ const message = [header, modelLine, profileLine, workspaceLine, versionLine, hintLine]
390
390
  .filter(Boolean)
391
391
  .join('\n');
392
- if (this.bannerShown && !force) {
393
- return;
394
- }
395
- if (this.launchBannerText === banner) {
396
- return;
397
- }
398
- display.stream(`${banner}\n`);
399
- this.bannerShown = true;
400
- this.launchBannerText = banner;
392
+ display.stream(`\n${message}\n\n`);
393
+ this.welcomeShown = true;
401
394
  this.requestPromptRefresh(true);
402
395
  }
403
396
  async start(initialPrompt) {
404
- this.renderWelcomeBanner();
397
+ this.showWelcomeBanner();
405
398
  if (initialPrompt) {
406
399
  await this.processInputBlock(initialPrompt);
407
400
  return;
@@ -579,11 +572,11 @@ export class InteractiveShell {
579
572
  if (!changed && source === 'shortcut') {
580
573
  return;
581
574
  }
582
- display.showInfo(`Auto-continue ${this.autoContinueEnabled ? 'enabled' : 'disabled'}. ` +
583
- (this.autoContinueEnabled
584
- ? 'The model will be auto-prompted to continue when it expresses intent but does not use tools.'
585
- : 'The model will not be auto-prompted to continue.') +
586
- ' Toggle with Ctrl+Shift+C.');
575
+ const modeLabel = this.autoContinueEnabled ? 'enabled' : 'disabled';
576
+ const behavior = this.autoContinueEnabled
577
+ ? 'The model will be auto-prompted to continue when it expresses intent but does not use tools.'
578
+ : 'The model will not be auto-prompted to continue.';
579
+ display.showInfo(`Auto-continue ${modeLabel}. ${behavior} Toggle with Ctrl+Shift+C.`);
587
580
  }
588
581
  /**
589
582
  * Cycle through thinking modes (Tab shortcut).
@@ -1384,7 +1377,10 @@ export class InteractiveShell {
1384
1377
  // Emit a streaming note for stop/quit so the status stays inside the stream
1385
1378
  if (reason === 'stop' || reason === 'quit') {
1386
1379
  const note = reason === 'quit' ? 'Session closed.' : 'Stream stopped.';
1387
- this.finishStreamingFormatter(note, { refreshPrompt: false });
1380
+ this.finishStreamingFormatter(note, {
1381
+ refreshPrompt: false,
1382
+ mode: reason,
1383
+ });
1388
1384
  }
1389
1385
  // Force refresh to update the input area now that streaming has ended
1390
1386
  if (!quiet) {
@@ -1414,7 +1410,10 @@ export class InteractiveShell {
1414
1410
  if (!this.streamingFormatter) {
1415
1411
  return;
1416
1412
  }
1417
- const closing = this.streamingFormatter.finish(note);
1413
+ const closing = this.streamingFormatter.finish({
1414
+ note,
1415
+ mode: options?.mode ?? 'complete',
1416
+ });
1418
1417
  if (closing) {
1419
1418
  this.terminalInput.streamContent(closing);
1420
1419
  }
@@ -1710,7 +1709,6 @@ export class InteractiveShell {
1710
1709
  this.showAlphaZeroMetrics();
1711
1710
  break;
1712
1711
  case '/suggestions':
1713
- case '/improve':
1714
1712
  this.showImprovementSuggestions();
1715
1713
  break;
1716
1714
  case '/plugins':
@@ -2137,7 +2135,7 @@ export class InteractiveShell {
2137
2135
  lines.push(theme.bold('Session File Changes'));
2138
2136
  lines.push('');
2139
2137
  lines.push(`${theme.info('•')} ${summary.files} file${summary.files === 1 ? '' : 's'} modified`);
2140
- lines.push(`${theme.info('•')} ${theme.success('+' + summary.additions)} ${theme.error('-' + summary.removals)} lines`);
2138
+ lines.push(`${theme.info('•')} ${theme.success(`+${summary.additions}`)} ${theme.error(`-${summary.removals}`)} lines`);
2141
2139
  lines.push('');
2142
2140
  // Group changes by file
2143
2141
  const fileMap = new Map();
@@ -2161,7 +2159,7 @@ export class InteractiveShell {
2161
2159
  if (stats.writes > 0)
2162
2160
  operations.push(`${stats.writes} write${stats.writes === 1 ? '' : 's'}`);
2163
2161
  const opsText = operations.join(', ');
2164
- const diffText = `${theme.success('+' + stats.additions)} ${theme.error('-' + stats.removals)}`;
2162
+ const diffText = `${theme.success(`+${stats.additions}`)} ${theme.error(`-${stats.removals}`)}`;
2165
2163
  lines.push(` ${theme.dim(path)}`);
2166
2164
  lines.push(` ${opsText} • ${diffText}`);
2167
2165
  }
@@ -2618,7 +2616,7 @@ export class InteractiveShell {
2618
2616
  if (!isValidSourceRepo(this.workingDir)) {
2619
2617
  display.showWarning('Self-evolution requires a git repository with source code.');
2620
2618
  display.showSystemMessage('');
2621
- display.showSystemMessage('Current directory: ' + this.workingDir);
2619
+ display.showSystemMessage(`Current directory: ${this.workingDir}`);
2622
2620
  display.showSystemMessage('');
2623
2621
  display.showSystemMessage('Requirements:');
2624
2622
  display.showSystemMessage(' • Must be a git repository (.git folder)');
@@ -2628,7 +2626,6 @@ export class InteractiveShell {
2628
2626
  return;
2629
2627
  }
2630
2628
  const repoName = getRepoName(this.workingDir);
2631
- const isErosolar = isErosolarRepo(this.workingDir);
2632
2629
  if (subcommand === 'analyze') {
2633
2630
  display.showSystemMessage(theme.gradient.primary(`🔍 Analyzing ${repoName} Source Code...`));
2634
2631
  display.showSystemMessage('');
@@ -3000,13 +2997,6 @@ export class InteractiveShell {
3000
2997
  ' /offsec win|fail|detect <actionId> [note]\n' +
3001
2998
  ' /offsec resume <runId>\n' +
3002
2999
  ' /offsec runs';
3003
- const loadRun = (explicitId) => {
3004
- const run = resumeOffsecRun(explicitId ?? this.offsecRunId);
3005
- if (!run) {
3006
- display.showWarning('No offsec run found. Start one with /offsec start "<objective>".');
3007
- }
3008
- return run;
3009
- };
3010
3000
  if (sub === 'start') {
3011
3001
  const rest = args.slice(1);
3012
3002
  const scope = [];
@@ -3445,8 +3435,7 @@ export class InteractiveShell {
3445
3435
  const value = tokens[0]?.toLowerCase();
3446
3436
  if (!value) {
3447
3437
  // Show current status
3448
- display.showInfo(`Auto-continue is ${this.autoContinueEnabled ? 'enabled' : 'disabled'}. ` +
3449
- `Use /autocontinue on|off or Ctrl+Shift+C to toggle.`);
3438
+ display.showInfo(`Auto-continue is ${this.autoContinueEnabled ? 'enabled' : 'disabled'}. Use /autocontinue on|off or Ctrl+Shift+C to toggle.`);
3450
3439
  return;
3451
3440
  }
3452
3441
  if (value !== 'on' && value !== 'off') {
@@ -3456,7 +3445,7 @@ export class InteractiveShell {
3456
3445
  this.setAutoContinueMode(value === 'on', 'command');
3457
3446
  }
3458
3447
  // ==================== Claude Code Style Commands ====================
3459
- async handleRewindCommand(input) {
3448
+ async handleRewindCommand(_input) {
3460
3449
  const lines = [];
3461
3450
  lines.push(theme.bold('Rewind / Checkpoint System'));
3462
3451
  lines.push('');
@@ -3472,7 +3461,7 @@ export class InteractiveShell {
3472
3461
  lines.push(theme.ui.muted('Press Esc+Esc for quick access to the rewind menu'));
3473
3462
  display.showSystemMessage(lines.join('\n'));
3474
3463
  }
3475
- handleMemoryCommand(input) {
3464
+ handleMemoryCommand(_input) {
3476
3465
  const lines = [];
3477
3466
  lines.push(theme.bold('Memory System (EROSOLAR.md)'));
3478
3467
  lines.push('');
@@ -3513,7 +3502,7 @@ export class InteractiveShell {
3513
3502
  lines.push(theme.ui.muted('Vim mode is experimental. Toggle with /vim'));
3514
3503
  display.showSystemMessage(lines.join('\n'));
3515
3504
  }
3516
- handleOutputStyleCommand(input) {
3505
+ handleOutputStyleCommand(_input) {
3517
3506
  const lines = [];
3518
3507
  lines.push(theme.bold('Output Styles'));
3519
3508
  lines.push('');
@@ -3634,7 +3623,7 @@ export class InteractiveShell {
3634
3623
  }
3635
3624
  }
3636
3625
  }
3637
- handleExportCommand(input) {
3626
+ handleExportCommand(_input) {
3638
3627
  const lines = [];
3639
3628
  lines.push(theme.bold('Export Conversation'));
3640
3629
  lines.push('');
@@ -4227,7 +4216,7 @@ export class InteractiveShell {
4227
4216
  const parts = tool.name.split('__');
4228
4217
  const serverName = parts[1] || '';
4229
4218
  const toolName = parts.slice(2).join('__') || tool.name;
4230
- lines.push(` ${theme.info('•')} ${theme.ui.muted(serverName + ':')} ${toolName}`);
4219
+ lines.push(` ${theme.info('•')} ${theme.ui.muted(`${serverName}:`)} ${toolName}`);
4231
4220
  }
4232
4221
  if (mcpTools.length > 15) {
4233
4222
  lines.push(` ${theme.ui.muted(`... and ${mcpTools.length - 15} more`)}`);
@@ -4688,7 +4677,7 @@ export class InteractiveShell {
4688
4677
  // Start streaming - no header needed, the input area already provides context
4689
4678
  this.startStreamingHeartbeat('Streaming response');
4690
4679
  responseText = await agent.send(request, true);
4691
- this.finishStreamingFormatter(undefined, { refreshPrompt: false });
4680
+ this.finishStreamingFormatter(undefined, { refreshPrompt: false, mode: 'complete' });
4692
4681
  await this.awaitPendingCleanup();
4693
4682
  this.captureHistorySnapshot();
4694
4683
  this.autosaveIfEnabled();
@@ -4744,7 +4733,7 @@ export class InteractiveShell {
4744
4733
  }
4745
4734
  }
4746
4735
  finally {
4747
- this.finishStreamingFormatter(undefined, { refreshPrompt: false });
4736
+ this.finishStreamingFormatter(undefined, { refreshPrompt: false, mode: 'complete' });
4748
4737
  display.stopThinking(false);
4749
4738
  this.uiUpdates.setMode('processing');
4750
4739
  this.stopStreamingHeartbeat('complete', { quiet: true });
@@ -4753,7 +4742,6 @@ export class InteractiveShell {
4753
4742
  this.terminalInput.setStreaming(false);
4754
4743
  this.uiAdapter.endProcessing('Ready for prompts');
4755
4744
  this.setIdleStatus();
4756
- display.newLine();
4757
4745
  this.updateStatusMessage(null);
4758
4746
  queueMicrotask(() => this.uiUpdates.setMode('idle'));
4759
4747
  // CRITICAL: Ensure readline prompt is active for user input
@@ -4837,7 +4825,7 @@ When truly finished with ALL tasks, explicitly state "TASK_FULLY_COMPLETE".`;
4837
4825
  display.showThinking('Responding...');
4838
4826
  this.refreshStatusLine(true);
4839
4827
  const response = await agent.send(currentPrompt, true);
4840
- this.finishStreamingFormatter(undefined, { refreshPrompt: false });
4828
+ this.finishStreamingFormatter(undefined, { refreshPrompt: false, mode: 'complete' });
4841
4829
  await this.awaitPendingCleanup();
4842
4830
  this.captureHistorySnapshot();
4843
4831
  this.autosaveIfEnabled();
@@ -4970,7 +4958,7 @@ What's the next action?`;
4970
4958
  }
4971
4959
  }
4972
4960
  finally {
4973
- this.finishStreamingFormatter(undefined, { refreshPrompt: false });
4961
+ this.finishStreamingFormatter(undefined, { refreshPrompt: false, mode: 'complete' });
4974
4962
  const totalElapsed = Date.now() - overallStartTime;
4975
4963
  const minutes = Math.floor(totalElapsed / 60000);
4976
4964
  const seconds = Math.floor((totalElapsed % 60000) / 1000);
@@ -4985,10 +4973,6 @@ What's the next action?`;
4985
4973
  this.uiAdapter.endProcessing('Ready for prompts');
4986
4974
  this.setIdleStatus();
4987
4975
  this.updateStatusMessage(null);
4988
- display.newLine();
4989
- // Claude Code style: Show unified status bar before prompt
4990
- // This creates consistent UI between startup and post-streaming
4991
- this.showUnifiedStatusBar();
4992
4976
  queueMicrotask(() => this.uiUpdates.setMode('idle'));
4993
4977
  // CRITICAL: Ensure readline prompt is active for user input
4994
4978
  // Claude Code style: New prompt naturally appears at bottom
@@ -5182,7 +5166,14 @@ What's the next action?`;
5182
5166
  return latest;
5183
5167
  }
5184
5168
  formatCommandError(error) {
5185
- const parts = [error?.stdout, error?.stderr, error?.message].filter((part) => typeof part === 'string' && part.trim());
5169
+ const candidates = [];
5170
+ if (error && typeof error === 'object') {
5171
+ const stdout = error.stdout;
5172
+ const stderr = error.stderr;
5173
+ const message = error.message;
5174
+ candidates.push(stdout, stderr, message);
5175
+ }
5176
+ const parts = candidates.filter((part) => typeof part === 'string' && part.trim().length > 0);
5186
5177
  return parts.join('\n').trim();
5187
5178
  }
5188
5179
  runAutoQualityChecks(trigger, assistantResponse, verificationContext) {
@@ -5515,7 +5506,6 @@ Return ONLY JSON array:
5515
5506
  display.showThinking('Analyzing build errors');
5516
5507
  this.refreshStatusLine(true);
5517
5508
  const response = await this.agent.send(prompt, true);
5518
- this.finishStreamingFormatter();
5519
5509
  display.stopThinking();
5520
5510
  this.refreshStatusLine(true);
5521
5511
  if (response) {
@@ -5528,7 +5518,7 @@ Return ONLY JSON array:
5528
5518
  display.showWarning('Agent could not automatically fix build errors. Please review manually.');
5529
5519
  }
5530
5520
  finally {
5531
- this.finishStreamingFormatter();
5521
+ this.finishStreamingFormatter(undefined, { refreshPrompt: false, mode: 'complete' });
5532
5522
  }
5533
5523
  }
5534
5524
  rebuildAgent() {
@@ -5699,9 +5689,9 @@ Return ONLY JSON array:
5699
5689
  * Ensures the input area is visible and ready for input, just like on startup.
5700
5690
  */
5701
5691
  resetChatBoxAfterModelSwap() {
5702
- this.renderWelcomeBanner(true);
5703
5692
  this.updateStatusMessage(null);
5704
5693
  this.terminalInput.setStreaming(false);
5694
+ this.requestPromptRefresh(true);
5705
5695
  this.ensureReadlineReady();
5706
5696
  }
5707
5697
  /**
@@ -6254,7 +6244,7 @@ Return ONLY JSON array:
6254
6244
  const reason = info.reason ? ` (${info.reason.replace(/-/g, ' ')})` : '';
6255
6245
  const partialNote = info.partialResponse ? ' Received partial stream before failure.' : '';
6256
6246
  display.showWarning(`Streaming failed${reason}, retrying without streaming.${detail}${partialNote}`);
6257
- this.finishStreamingFormatter('Stream interrupted - retrying without streaming');
6247
+ this.finishStreamingFormatter('Stream interrupted - retrying without streaming', { mode: 'update' });
6258
6248
  this.startStreamingHeartbeat('Fallback in progress');
6259
6249
  this.requestPromptRefresh(true);
6260
6250
  }
@@ -6355,7 +6345,7 @@ Return ONLY JSON array:
6355
6345
  // Truncate to reasonable length
6356
6346
  const maxLength = 50;
6357
6347
  return cleaned.length > maxLength
6358
- ? cleaned.slice(0, maxLength - 3) + '...'
6348
+ ? `${cleaned.slice(0, maxLength - 3)}...`
6359
6349
  : cleaned;
6360
6350
  }
6361
6351
  splitThinkingResponse(content) {
@@ -6520,13 +6510,15 @@ Return ONLY JSON array:
6520
6510
  await this.scanLocalProviders();
6521
6511
  break;
6522
6512
  case 'use':
6523
- const provider = tokens[1]?.toLowerCase();
6524
- if (!provider) {
6525
- display.showWarning('Usage: /local use <provider>');
6526
- display.showInfo('Example: /local use ollama');
6527
- return;
6513
+ {
6514
+ const provider = tokens[1]?.toLowerCase();
6515
+ if (!provider) {
6516
+ display.showWarning('Usage: /local use <provider>');
6517
+ display.showInfo('Example: /local use ollama');
6518
+ return;
6519
+ }
6520
+ await this.handleProviderCommand(`/provider ${provider}`);
6528
6521
  }
6529
- await this.handleProviderCommand(`/provider ${provider}`);
6530
6522
  break;
6531
6523
  default:
6532
6524
  this.showLocalHelp();
@@ -6633,13 +6625,6 @@ Return ONLY JSON array:
6633
6625
  setProviderStatus(providers) {
6634
6626
  this.cachedProviderStatus = providers;
6635
6627
  }
6636
- /**
6637
- * Show the unified status bar (Claude Code style).
6638
- * Displays provider indicators and ready hints before the prompt.
6639
- */
6640
- showUnifiedStatusBar() {
6641
- display.showUnifiedStatusBar(this.cachedProviderStatus);
6642
- }
6643
6628
  }
6644
6629
  function setsEqual(first, second) {
6645
6630
  if (first.size !== second.size) {