@compilr-dev/cli 0.5.5 → 0.5.6

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/dist/repl-v2.js CHANGED
@@ -24,7 +24,8 @@ import { getCurrentProject } from './tools/project-db.js';
24
24
  import { TerminalUI } from './ui/terminal-ui.js';
25
25
  import * as terminal from './ui/terminal.js';
26
26
  import { getStyles } from './themes/index.js';
27
- import { getSettings, getStartupMode, syncPermissionModeFromUI, getPermissionMode, permissionModeToAgentMode, getProjectSessionMode, isFirstRunComplete, getSessionRetentionDays, updateSettings } from './settings/index.js';
27
+ import { getSettings, getStartupMode, syncPermissionModeFromUI, getPermissionMode, permissionModeToAgentMode, getProjectSessionMode, isFirstRunComplete, getSessionRetentionDays, updateSettings, getVerbosity } from './settings/index.js';
28
+ import { isReadOnlyTool } from './utils/readonly-tools.js';
28
29
  import { renderMascotWithLogo } from './ui/mascot/renderer.js';
29
30
  import { getStartupHighlights } from './changelog/index.js';
30
31
  import { registerCommands, executeCommand, allCommands, getAutocompleteCommands, saveCurrentSession, saveCurrentTeam, loadProjectSession, archiveCurrentSession, convertMessagesToItems, } from './commands-v2/index.js';
@@ -801,6 +802,7 @@ export class ReplV2 {
801
802
  const initialUiMode = permissionModeToAgentMode(savedPermissionMode);
802
803
  this.ui = new TerminalUI({
803
804
  initialMode: initialUiMode,
805
+ config: { verbosity: getVerbosity() },
804
806
  });
805
807
  // Print welcome screen
806
808
  // Skip if: login overlay shows its own branded welcome,
@@ -2483,6 +2485,7 @@ export class ReplV2 {
2483
2485
  params: categoryParam,
2484
2486
  summary: `${String(count)} tools available`,
2485
2487
  success: result.success,
2488
+ readOnly: isReadOnlyTool('list_tools'),
2486
2489
  agentId: activeAgentId,
2487
2490
  });
2488
2491
  this.ui.setCurrentTool(null);
@@ -2517,6 +2520,7 @@ export class ReplV2 {
2517
2520
  content: content || undefined,
2518
2521
  diffLines: innerDiffLines,
2519
2522
  success,
2523
+ readOnly: isReadOnlyTool(innerToolName),
2520
2524
  agentId: activeAgentId,
2521
2525
  });
2522
2526
  this.ui.setCurrentTool(null);
@@ -2545,6 +2549,7 @@ export class ReplV2 {
2545
2549
  params: name,
2546
2550
  summary: `Schema: ${name}`,
2547
2551
  success: result.success,
2552
+ readOnly: isReadOnlyTool('get_tool_info'),
2548
2553
  agentId: activeAgentId,
2549
2554
  });
2550
2555
  this.ui.setCurrentTool(null);
@@ -2590,6 +2595,7 @@ export class ReplV2 {
2590
2595
  content: content || undefined,
2591
2596
  diffLines,
2592
2597
  success,
2598
+ readOnly: isReadOnlyTool(toolName),
2593
2599
  agentId: activeAgentId,
2594
2600
  });
2595
2601
  this.ui.setCurrentTool(null);
@@ -3154,6 +3160,7 @@ export class ReplV2 {
3154
3160
  params: '**/*.ts',
3155
3161
  summary: 'Found 42 files',
3156
3162
  content: 'src/index.ts\nsrc/config.ts\nsrc/utils/helpers.ts\n... and 39 more',
3163
+ readOnly: true,
3157
3164
  });
3158
3165
  this.ui.setTodos([
3159
3166
  { content: 'Analyze the request', status: 'completed' },
@@ -13,6 +13,7 @@ export type ProjectStartupMode = 'last' | 'off';
13
13
  export type MascotSetting = 'none' | 'random' | 'neutral' | 'thinking' | 'looking_left' | 'looking_right' | 'sleeping' | 'alert' | 'error' | 'success' | 'success_minimal' | 'searching' | 'skeptical';
14
14
  export type ProjectSessionMode = 'auto' | 'ask' | 'fresh';
15
15
  export type CompactMode = 'active' | 'all' | 'auto';
16
+ export type Verbosity = 'normal' | 'focused' | 'verbose';
16
17
  /**
17
18
  * Permission rule for a tool or pattern.
18
19
  * Supports wildcards: git_* matches git_commit, git_branch, etc.
@@ -34,6 +35,7 @@ export interface Settings {
34
35
  showTips: boolean;
35
36
  reviseCode: boolean;
36
37
  verbose: boolean;
38
+ verbosity: Verbosity;
37
39
  progressBar: boolean;
38
40
  checkUpdates: boolean;
39
41
  lastUpdateCheck: number | null;
@@ -82,6 +84,7 @@ export declare const getDefaultModel: () => string | null;
82
84
  export declare const isAutoCompactEnabled: () => boolean;
83
85
  export declare const isShowTipsEnabled: () => boolean;
84
86
  export declare const isReviseCodeEnabled: () => boolean;
87
+ export declare const getVerbosity: () => Verbosity;
85
88
  export declare const isVerboseEnabled: () => boolean;
86
89
  export declare const isProgressBarEnabled: () => boolean;
87
90
  export declare const isTelemetryEnabled: () => boolean;
@@ -166,6 +169,14 @@ export declare function sessionRetentionToDisplay(days: number): string;
166
169
  * Map display value to session retention days
167
170
  */
168
171
  export declare function displayToSessionRetention(display: string): number;
172
+ /**
173
+ * Map internal verbosity to display value
174
+ */
175
+ export declare function verbosityToDisplay(v: Verbosity): string;
176
+ /**
177
+ * Map display value to internal verbosity
178
+ */
179
+ export declare function displayToVerbosity(d: string): Verbosity;
169
180
  /**
170
181
  * Map internal compact mode to display value
171
182
  */
@@ -29,6 +29,7 @@ const DEFAULT_SETTINGS = {
29
29
  showTips: true, // TODO: Not yet implemented
30
30
  reviseCode: true, // TODO: Not yet implemented
31
31
  verbose: false,
32
+ verbosity: 'normal',
32
33
  progressBar: true,
33
34
  // Update defaults
34
35
  checkUpdates: true, // Check for updates on startup
@@ -112,7 +113,16 @@ export function getSettings() {
112
113
  return settingsCache;
113
114
  }
114
115
  const stored = loadFromDisk();
116
+ let needsSave = false;
117
+ // Migration: convert verbose boolean to verbosity string (before merge with defaults)
118
+ if (!('verbosity' in stored) && stored.verbose === true) {
119
+ stored.verbosity = 'verbose';
120
+ needsSave = true;
121
+ }
115
122
  settingsCache = { ...DEFAULT_SETTINGS, ...stored };
123
+ if (needsSave) {
124
+ saveToDisk(settingsCache);
125
+ }
116
126
  // Migration: convert deprecated 'cwd' to 'off'
117
127
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
118
128
  if (settingsCache.projectStartup === 'cwd') {
@@ -179,7 +189,8 @@ export const getDefaultModel = () => getSetting('defaultModel');
179
189
  export const isAutoCompactEnabled = () => getSetting('autoCompact');
180
190
  export const isShowTipsEnabled = () => getSetting('showTips'); // TODO: Not yet implemented
181
191
  export const isReviseCodeEnabled = () => getSetting('reviseCode'); // TODO: Not yet implemented
182
- export const isVerboseEnabled = () => getSetting('verbose');
192
+ export const getVerbosity = () => getSetting('verbosity');
193
+ export const isVerboseEnabled = () => getVerbosity() === 'verbose';
183
194
  export const isProgressBarEnabled = () => getSetting('progressBar');
184
195
  export const isTelemetryEnabled = () => getSetting('telemetryEnabled');
185
196
  // Update getters
@@ -378,6 +389,18 @@ export function displayToSessionRetention(display) {
378
389
  return parseInt(match[1], 10);
379
390
  return 30; // Default fallback
380
391
  }
392
+ /**
393
+ * Map internal verbosity to display value
394
+ */
395
+ export function verbosityToDisplay(v) {
396
+ return v === 'normal' ? 'Normal' : v === 'focused' ? 'Focused' : 'Verbose';
397
+ }
398
+ /**
399
+ * Map display value to internal verbosity
400
+ */
401
+ export function displayToVerbosity(d) {
402
+ return d === 'Focused' ? 'focused' : d === 'Verbose' ? 'verbose' : 'normal';
403
+ }
381
404
  /**
382
405
  * Map internal compact mode to display value
383
406
  */
@@ -11,11 +11,13 @@ import type { AutocompleteController } from './autocomplete-controller.js';
11
11
  import type { OverlayManager } from './overlay-manager.js';
12
12
  import type { StatusBarController } from './status-bar-controller.js';
13
13
  import type { Overlay } from './overlay/index.js';
14
+ import type { Verbosity } from '../settings/index.js';
14
15
  export interface KeyboardHandlerHost {
15
16
  isGuardActive(): boolean;
16
17
  isAgentRunning(): boolean;
17
- getViewMode(): 'normal' | 'verbose-temp';
18
- setViewMode(mode: 'normal' | 'verbose-temp'): void;
18
+ getViewMode(): 'normal' | 'focused-temp' | 'verbose-temp';
19
+ setViewMode(mode: 'normal' | 'focused-temp' | 'verbose-temp'): void;
20
+ getPersistedVerbosity(): Verbosity;
19
21
  requestRender(): void;
20
22
  emit(event: string, ...args: unknown[]): void;
21
23
  readonly input: InputController;
@@ -28,10 +30,10 @@ export interface KeyboardHandlerHost {
28
30
  backgroundBashCommand(): void;
29
31
  hasRestoredHistory(): boolean;
30
32
  showRestoredHistory(): void;
31
- toggleVerboseView(): void;
33
+ cycleVerbosityView(): void;
32
34
  toggleLiveRegionExpanded(): void;
33
35
  toggleTodos(): void;
34
- reRenderConversationVerbose(verbose: boolean): void;
36
+ reRenderConversationWithVerbosity(verbosity: Verbosity): void;
35
37
  }
36
38
  export declare class KeyboardHandler {
37
39
  private keyHandler;
@@ -126,10 +126,10 @@ export class KeyboardHandler {
126
126
  handleEscape() {
127
127
  const host = this.host;
128
128
  const { input, ac } = host;
129
- // In verbose-temp mode, escape returns to normal
130
- if (host.getViewMode() === 'verbose-temp') {
129
+ // In temp mode, escape returns to persisted verbosity
130
+ if (host.getViewMode() !== 'normal') {
131
131
  host.setViewMode('normal');
132
- host.reRenderConversationVerbose(false);
132
+ host.reRenderConversationWithVerbosity(host.getPersistedVerbosity());
133
133
  return;
134
134
  }
135
135
  // Route escape to active overlay if present
@@ -261,17 +261,17 @@ export class KeyboardHandler {
261
261
  host.statusBar.handleKey(str, key);
262
262
  return;
263
263
  }
264
- // In verbose-temp mode, any key (except Ctrl+O) returns to normal
265
- if (host.getViewMode() === 'verbose-temp') {
266
- // Ctrl+O toggles back
264
+ // In temp mode (focused-temp or verbose-temp), any key (except Ctrl+O) returns to persisted
265
+ if (host.getViewMode() !== 'normal') {
266
+ // Ctrl+O cycles to next temp mode
267
267
  if (key.ctrl && key.name === 'o') {
268
- host.toggleVerboseView();
268
+ host.cycleVerbosityView();
269
269
  host.toggleLiveRegionExpanded();
270
270
  return;
271
271
  }
272
- // Any other key returns to normal
272
+ // Any other key returns to persisted verbosity
273
273
  host.setViewMode('normal');
274
- host.reRenderConversationVerbose(false);
274
+ host.reRenderConversationWithVerbosity(host.getPersistedVerbosity());
275
275
  // Don't consume the key - let it be processed normally
276
276
  }
277
277
  // Ctrl+C - interrupt/exit
@@ -284,9 +284,9 @@ export class KeyboardHandler {
284
284
  host.toggleTodos();
285
285
  return;
286
286
  }
287
- // Ctrl+O - toggle verbose view mode AND LiveRegion expansion
287
+ // Ctrl+O - cycle verbosity view mode AND LiveRegion expansion
288
288
  if (key.ctrl && key.name === 'o') {
289
- host.toggleVerboseView();
289
+ host.cycleVerbosityView();
290
290
  host.toggleLiveRegionExpanded();
291
291
  return;
292
292
  }
@@ -144,6 +144,7 @@ export class LiveRegionFacade {
144
144
  summary: exitCode === 0 ? 'Completed' : `Exit code ${String(exitCode)}`,
145
145
  content: output,
146
146
  success: exitCode === 0,
147
+ readOnly: false,
147
148
  });
148
149
  }
149
150
  this.host.requestRender();
@@ -15,7 +15,7 @@ import * as path from 'path';
15
15
  import { execSync } from 'child_process';
16
16
  import { BaseOverlayV2, isEscape, isTab, isShiftTab, isEnter, isSpace, isCtrlC, isNavigateUp, isNavigateDown, isBackspace, getNumberKey, isPrintable, extractPrintable, renderProgressBar, formatTokens, truncate, } from '../../base/index.js';
17
17
  import { getCurrentTheme, } from '../../../themes/index.js';
18
- import { getSettings, setSetting, permissionModeToDisplay, displayToPermissionMode, notificationModeToDisplay, displayToNotificationMode, projectStartupModeToDisplay, displayToProjectStartupMode, projectSessionModeToDisplay, displayToProjectSessionMode, sessionRetentionToDisplay, displayToSessionRetention, compactModeToDisplay, displayToCompactMode, } from '../../../settings/index.js';
18
+ import { getSettings, setSetting, permissionModeToDisplay, displayToPermissionMode, notificationModeToDisplay, displayToNotificationMode, projectStartupModeToDisplay, displayToProjectStartupMode, projectSessionModeToDisplay, displayToProjectSessionMode, sessionRetentionToDisplay, displayToSessionRetention, compactModeToDisplay, displayToCompactMode, verbosityToDisplay, displayToVerbosity, } from '../../../settings/index.js';
19
19
  import { getResolvedPathConfig, setDeleteProtection, setProjectMatchRequired, setWorkspacePath, setProjectsPath, setDataPath, } from '../../../settings/paths.js';
20
20
  import { MASCOT_LABELS, } from '../../mascot/index.js';
21
21
  import { ThemeOverlayV2 } from './theme-overlay-v2.js';
@@ -128,7 +128,7 @@ function getConfigItems(currentModel) {
128
128
  // { id: 'showTips', label: 'Show tips', type: 'boolean', value: settings.showTips },
129
129
  // TODO: Implement checkpoints/rewind feature (Claude Code v2.0)
130
130
  // { id: 'reviseCode', label: 'Revise code (checkpoints)', type: 'boolean', value: settings.reviseCode },
131
- { id: 'verbose', label: 'Verbose output', type: 'boolean', value: settings.verbose },
131
+ { id: 'verbosity', label: 'Verbosity', type: 'cycle', value: verbosityToDisplay(settings.verbosity), options: ['Normal', 'Focused', 'Verbose'] },
132
132
  { id: 'progressBar', label: 'Terminal progress bar', type: 'boolean', value: settings.progressBar },
133
133
  {
134
134
  id: 'permissionMode',
@@ -623,9 +623,7 @@ export class ConfigOverlayV2 extends BaseOverlayV2 {
623
623
  case 'autoCompact':
624
624
  setSetting('autoCompact', newValue);
625
625
  break;
626
- case 'verbose':
627
- setSetting('verbose', newValue);
628
- break;
626
+ // verbose: removed — now a 'cycle' item as 'verbosity'
629
627
  case 'progressBar':
630
628
  setSetting('progressBar', newValue);
631
629
  break;
@@ -680,6 +678,9 @@ export class ConfigOverlayV2 extends BaseOverlayV2 {
680
678
  case 'compactMode':
681
679
  setSetting('compactMode', displayToCompactMode(newValue));
682
680
  break;
681
+ case 'verbosity':
682
+ setSetting('verbosity', displayToVerbosity(newValue));
683
+ break;
683
684
  }
684
685
  return null;
685
686
  }
@@ -63,7 +63,7 @@ export function renderItem(item, config) {
63
63
  }
64
64
  case 'thinking':
65
65
  // Only show thinking in verbose mode
66
- if (config.verbose) {
66
+ if (config.verbosity === 'verbose') {
67
67
  console.log(s.muted(`∴ Thinking…`));
68
68
  console.log('');
69
69
  // Indent thinking text
@@ -76,6 +76,9 @@ export function renderItem(item, config) {
76
76
  // If not verbose, skip entirely (but still stored in history)
77
77
  break;
78
78
  case 'tool-start': {
79
+ // In focused mode, spinner already shows tool name — skip scroll output
80
+ if (config.verbosity === 'focused')
81
+ break;
79
82
  // Truncate long params (e.g., long bash commands)
80
83
  const maxLen = Math.min(60, terminal.getTerminalWidth() - 15);
81
84
  let params = item.params;
@@ -94,6 +97,25 @@ export function renderItem(item, config) {
94
97
  break;
95
98
  }
96
99
  case 'tool-result': {
100
+ // === FOCUSED MODE ===
101
+ if (config.verbosity === 'focused') {
102
+ // Errors always visible
103
+ if (item.success === false) {
104
+ console.log(s.info(`● ${item.name}`) + s.error(` — ${item.summary}`));
105
+ console.log('');
106
+ }
107
+ else if (item.readOnly) {
108
+ // Read-only tools: spinner-only, no scroll output
109
+ break;
110
+ }
111
+ else {
112
+ // Write/mutation tools: single summary line
113
+ console.log(s.info(`● ${item.name}`) + s.muted(` — ${item.summary}`));
114
+ console.log('');
115
+ }
116
+ break;
117
+ }
118
+ // === NORMAL & VERBOSE MODES ===
97
119
  // Truncate long params (e.g., long bash commands)
98
120
  const maxParamsLen = Math.min(60, terminal.getTerminalWidth() - 15);
99
121
  let paramsDisplay = item.params;
@@ -114,7 +136,7 @@ export function renderItem(item, config) {
114
136
  // Diff lines: render directly (already ANSI-formatted by diff.ts)
115
137
  if (item.diffLines && item.diffLines.length > 0) {
116
138
  const maxDiffPreview = 10;
117
- if (config.verbose || item.diffLines.length <= maxDiffPreview) {
139
+ if (config.verbosity === 'verbose' || item.diffLines.length <= maxDiffPreview) {
118
140
  for (const line of item.diffLines) {
119
141
  console.log(` ${line}`);
120
142
  }
@@ -130,7 +152,7 @@ export function renderItem(item, config) {
130
152
  else if (item.content) {
131
153
  const contentLines = item.content.split('\n').filter((l) => l.length > 0);
132
154
  const maxPreviewLines = 3;
133
- if (config.verbose) {
155
+ if (config.verbosity === 'verbose') {
134
156
  // Verbose: show all lines
135
157
  for (const line of contentLines) {
136
158
  console.log(s.muted(` ⎿ ${line}`));
@@ -6,6 +6,7 @@
6
6
  */
7
7
  import type { CommandOption } from './types.js';
8
8
  import type { FileMatch } from './file-autocomplete.js';
9
+ import type { Verbosity } from '../settings/index.js';
9
10
  /**
10
11
  * Message to be sent to the agent from a command.
11
12
  * Allows commands to invoke the agent with a detailed prompt while
@@ -39,6 +40,7 @@ export interface TerminalUIEvents {
39
40
  */
40
41
  export interface TerminalUIConfig {
41
42
  verbose: boolean;
43
+ verbosity: Verbosity;
42
44
  theme: string;
43
45
  showMascot: boolean;
44
46
  }
@@ -121,6 +123,7 @@ export type PrintableItem = {
121
123
  content?: string;
122
124
  diffLines?: string[];
123
125
  success?: boolean;
126
+ readOnly?: boolean;
124
127
  agentId?: string;
125
128
  } | {
126
129
  type: 'tool-error';
@@ -6,6 +6,7 @@
6
6
  */
7
7
  export const DEFAULT_TERMINAL_UI_CONFIG = {
8
8
  verbose: false,
9
+ verbosity: 'normal',
9
10
  theme: 'default',
10
11
  showMascot: true,
11
12
  };
@@ -224,15 +224,15 @@ export declare class TerminalUI extends EventEmitter {
224
224
  */
225
225
  getShowTodos(): boolean;
226
226
  /**
227
- * Toggle verbose view mode (Ctrl+O)
228
- * Shows conversation in verbose mode temporarily.
229
- * Any key returns to normal view.
227
+ * Cycle verbosity view mode (Ctrl+O)
228
+ * Cycles: normal focused-temp → verbose-temp normal
229
+ * Any non-Ctrl+O key returns to persisted verbosity.
230
230
  */
231
- toggleVerboseView(): void;
231
+ cycleVerbosityView(): void;
232
232
  /**
233
- * Re-render conversation with temporary verbose setting.
233
+ * Re-render conversation with temporary verbosity setting.
234
234
  */
235
- private reRenderConversationVerbose;
235
+ private reRenderConversationWithVerbosity;
236
236
  /**
237
237
  * Store restored conversation items for Ctrl+R history view.
238
238
  * Called when a session is resumed/restored.
@@ -83,9 +83,10 @@ export class TerminalUI extends EventEmitter {
83
83
  activeTeamAgent = null;
84
84
  // Todo visibility (Ctrl+T to toggle)
85
85
  showTodos = true;
86
- // View mode (Ctrl+O to toggle verbose view)
87
- // normal: compact output
88
- // verbose-temp: temporarily show last N items verbose (any key returns to normal)
86
+ // View mode (Ctrl+O to cycle: normal → focused-temp → verbose-temp → normal)
87
+ // normal: use persisted verbosity setting
88
+ // focused-temp: temporarily show focused mode (any key returns to persisted)
89
+ // verbose-temp: temporarily show verbose mode (any key returns to persisted)
89
90
  viewMode = 'normal';
90
91
  // Status bar navigation (down arrow into footer indicators)
91
92
  statusBar = new StatusBarController({
@@ -104,7 +105,7 @@ export class TerminalUI extends EventEmitter {
104
105
  isFooterRenderAllowed: () => this.isRunning && !this.isPaused && !this.overlay.hasActiveOverlay(),
105
106
  getRenderData: () => ({
106
107
  liveRegion: this.live.region,
107
- liveVerbose: this.config.verbose,
108
+ liveVerbose: this.config.verbosity === 'verbose',
108
109
  agentRunning: this.agentRunning,
109
110
  currentTool: this.currentTool,
110
111
  spinnerText: this.spinnerText,
@@ -136,6 +137,7 @@ export class TerminalUI extends EventEmitter {
136
137
  isAgentRunning: () => this.agentRunning,
137
138
  getViewMode: () => this.viewMode,
138
139
  setViewMode: (mode) => { this.viewMode = mode; },
140
+ getPersistedVerbosity: () => this.config.verbosity,
139
141
  requestRender: () => { this.needsRender = true; },
140
142
  emit: (event, ...args) => { this.emit(event, ...args); },
141
143
  input: this.input,
@@ -148,10 +150,10 @@ export class TerminalUI extends EventEmitter {
148
150
  backgroundBashCommand: () => { this.backgroundBashCommand(); },
149
151
  hasRestoredHistory: () => this.conversation.hasRestoredHistory(),
150
152
  showRestoredHistory: () => { this.showRestoredHistory(); },
151
- toggleVerboseView: () => { this.toggleVerboseView(); },
153
+ cycleVerbosityView: () => { this.cycleVerbosityView(); },
152
154
  toggleLiveRegionExpanded: () => { this.toggleLiveRegionExpanded(); },
153
155
  toggleTodos: () => { this.toggleTodos(); },
154
- reRenderConversationVerbose: (verbose) => { this.reRenderConversationVerbose(verbose); },
156
+ reRenderConversationWithVerbosity: (verbosity) => { this.reRenderConversationWithVerbosity(verbosity); },
155
157
  });
156
158
  constructor(options = {}) {
157
159
  super();
@@ -517,42 +519,50 @@ export class TerminalUI extends EventEmitter {
517
519
  return this.showTodos;
518
520
  }
519
521
  /**
520
- * Toggle verbose view mode (Ctrl+O)
521
- * Shows conversation in verbose mode temporarily.
522
- * Any key returns to normal view.
522
+ * Cycle verbosity view mode (Ctrl+O)
523
+ * Cycles: normal focused-temp → verbose-temp normal
524
+ * Any non-Ctrl+O key returns to persisted verbosity.
523
525
  */
524
- toggleVerboseView() {
526
+ cycleVerbosityView() {
525
527
  if (this.viewMode === 'normal') {
528
+ this.viewMode = 'focused-temp';
529
+ this.reRenderConversationWithVerbosity('focused');
530
+ }
531
+ else if (this.viewMode === 'focused-temp') {
526
532
  this.viewMode = 'verbose-temp';
527
- this.reRenderConversationVerbose(true);
533
+ this.reRenderConversationWithVerbosity('verbose');
528
534
  }
529
535
  else {
530
536
  this.viewMode = 'normal';
531
- this.reRenderConversationVerbose(false);
537
+ this.reRenderConversationWithVerbosity(this.config.verbosity);
532
538
  }
533
539
  }
534
540
  /**
535
- * Re-render conversation with temporary verbose setting.
541
+ * Re-render conversation with temporary verbosity setting.
536
542
  */
537
- reRenderConversationVerbose(verbose) {
543
+ reRenderConversationWithVerbosity(verbosity) {
538
544
  const s = getStyles();
539
545
  // Clear screen and scrollback buffer
540
546
  process.stdout.write('\x1b[2J\x1b[3J\x1b[H');
541
547
  // Reset footer state
542
548
  this.footer.resetRenderState();
543
- // Show mode indicator at top
544
- if (verbose) {
545
- console.log(s.info(`[Verbose View Mode] Press any key to return to normal view`));
549
+ // Show mode indicator at top for temp modes
550
+ if (this.viewMode === 'focused-temp') {
551
+ console.log(s.info(`[Focused View] Press any key to return`));
552
+ console.log('');
553
+ }
554
+ else if (this.viewMode === 'verbose-temp') {
555
+ console.log(s.info(`[Verbose View] Press any key to return`));
546
556
  console.log('');
547
557
  }
548
- // Re-render all items with temporary verbose override
549
- const originalVerbose = this.config.verbose;
550
- this.config.verbose = verbose;
558
+ // Re-render all items with temporary verbosity override
559
+ const originalVerbosity = this.config.verbosity;
560
+ this.config.verbosity = verbosity;
551
561
  for (const item of this.conversation.history) {
552
562
  this.renderItemToConsole(item);
553
563
  }
554
564
  // Restore original config
555
- this.config.verbose = originalVerbose;
565
+ this.config.verbosity = originalVerbosity;
556
566
  // Footer will be re-rendered by the render loop
557
567
  this.needsRender = true;
558
568
  }
@@ -604,10 +614,14 @@ export class TerminalUI extends EventEmitter {
604
614
  * If verbose changes, re-renders the entire conversation.
605
615
  */
606
616
  setConfig(newConfig) {
607
- const oldVerbose = this.config.verbose;
617
+ const oldVerbosity = this.config.verbosity;
608
618
  this.config = { ...this.config, ...newConfig };
609
- // If verbose changed, re-render entire conversation
610
- if (newConfig.verbose !== undefined && newConfig.verbose !== oldVerbose) {
619
+ // Keep legacy verbose in sync with verbosity
620
+ if (newConfig.verbosity !== undefined) {
621
+ this.config.verbose = newConfig.verbosity === 'verbose';
622
+ }
623
+ // If verbosity changed, re-render entire conversation
624
+ if (newConfig.verbosity !== undefined && newConfig.verbosity !== oldVerbosity) {
611
625
  this.reRenderConversation();
612
626
  }
613
627
  // Theme change requires prompt refresh