erosolar-cli 1.7.205 → 1.7.207

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,6 +1,9 @@
1
1
  import { spawn } from 'node:child_process';
2
2
  import { stdin as input, stdout as output } from 'node:process';
3
3
  import { createInterface } from 'node:readline/promises';
4
+ import { writeFileSync, chmodSync } from 'node:fs';
5
+ import { tmpdir } from 'node:os';
6
+ import { join } from 'node:path';
4
7
  import { display } from '../ui/display.js';
5
8
  const PACKAGE_NAME = 'erosolar-cli';
6
9
  const REGISTRY_URL = `https://registry.npmjs.org/${PACKAGE_NAME}/latest`;
@@ -127,32 +130,83 @@ async function installLatestVersion() {
127
130
  }
128
131
  /**
129
132
  * Relaunch the CLI with the same arguments after update.
130
- * Uses process.execPath to ensure we run the same Node.js,
131
- * and process.argv to pass the same arguments.
133
+ * Ensures the old instance fully exits before the new one starts.
134
+ *
135
+ * Strategy: Create a temporary launcher script that:
136
+ * 1. Waits for the parent process to exit
137
+ * 2. Then launches the new CLI
138
+ * 3. Cleans up after itself
132
139
  */
133
140
  function relaunchCli() {
134
- // Clear the terminal input state before exit
135
- if (input.isTTY && input.setRawMode) {
136
- try {
141
+ // Fully disable terminal input to prevent any further processing
142
+ // This is critical: we must stop all input handling before exit
143
+ try {
144
+ // Pause stdin to stop emitting data/keypress events
145
+ input.pause();
146
+ // Remove all listeners to prevent any queued events from firing
147
+ input.removeAllListeners('data');
148
+ input.removeAllListeners('keypress');
149
+ // Clear the terminal input state before exit
150
+ if (input.isTTY && input.setRawMode) {
137
151
  input.setRawMode(false);
138
152
  }
153
+ }
154
+ catch {
155
+ // Ignore errors during cleanup - we're exiting anyway
156
+ }
157
+ const parentPid = process.pid;
158
+ const args = process.argv.slice(2).map(arg => `"${arg.replace(/"/g, '\\"')}"`).join(' ');
159
+ if (process.platform === 'win32') {
160
+ // Windows: Use a batch script
161
+ const scriptPath = join(tmpdir(), `erosolar-relaunch-${parentPid}.bat`);
162
+ const script = `@echo off
163
+ :wait
164
+ tasklist /FI "PID eq ${parentPid}" 2>NUL | find /I "${parentPid}" >NUL
165
+ if %ERRORLEVEL%==0 (
166
+ timeout /t 1 /nobreak >NUL
167
+ goto wait
168
+ )
169
+ erosolar ${args}
170
+ del "%~f0"
171
+ `;
172
+ writeFileSync(scriptPath, script);
173
+ spawn('cmd', ['/c', 'start', '/b', scriptPath], {
174
+ detached: true,
175
+ stdio: 'inherit', // Inherit terminal so new CLI can use stdin/stdout
176
+ shell: false,
177
+ }).unref();
178
+ }
179
+ else {
180
+ // Unix: Use a shell script that waits for parent to exit
181
+ const scriptPath = join(tmpdir(), `erosolar-relaunch-${parentPid}.sh`);
182
+ const script = `#!/bin/sh
183
+ SCRIPT_PATH="${scriptPath}"
184
+ # Wait for parent process to fully exit
185
+ while kill -0 ${parentPid} 2>/dev/null; do
186
+ sleep 0.2
187
+ done
188
+ # Small additional delay to ensure cleanup
189
+ sleep 0.3
190
+ # Clean up this script
191
+ rm -f "$SCRIPT_PATH" 2>/dev/null
192
+ # Launch new CLI (exec replaces this shell) with terminal connected
193
+ exec erosolar ${args} </dev/tty >/dev/tty 2>&1
194
+ `;
195
+ writeFileSync(scriptPath, script, { mode: 0o755 });
196
+ // Also try to make it executable explicitly
197
+ try {
198
+ chmodSync(scriptPath, 0o755);
199
+ }
139
200
  catch {
140
- // Ignore if already in cooked mode
201
+ // Ignore chmod errors
141
202
  }
203
+ spawn('/bin/sh', [scriptPath], {
204
+ detached: true,
205
+ stdio: 'inherit', // Inherit terminal so new CLI can use stdin/stdout
206
+ shell: false,
207
+ }).unref();
142
208
  }
143
- // Get the erosolar binary path - it should be in PATH after update
144
- const binary = process.platform === 'win32' ? 'erosolar.cmd' : 'erosolar';
145
- // Spawn the new process detached so it survives parent exit
146
- const child = spawn(binary, process.argv.slice(2), {
147
- stdio: 'inherit',
148
- detached: true,
149
- shell: true,
150
- });
151
- // Unref so we can exit without waiting
152
- child.unref();
153
- // Give the child process a moment to start, then exit
154
- setTimeout(() => {
155
- process.exit(0);
156
- }, 200);
209
+ // Exit immediately - the launcher script will start the new CLI after we're gone
210
+ process.exit(0);
157
211
  }
158
212
  //# sourceMappingURL=updateManager.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"updateManager.js","sourceRoot":"","sources":["../../src/shell/updateManager.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"updateManager.js","sourceRoot":"","sources":["../../src/shell/updateManager.ts"],"names":[],"mappings":"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"}
@@ -71,8 +71,8 @@ export declare class Display {
71
71
  private writeLine;
72
72
  /**
73
73
  * Write raw content directly to output stream.
74
- * Goes through interceptors and shared write lock so overlays refresh safely.
75
- * Use this for streaming output chunks.
74
+ * For streaming output chunks - uses output interceptors for cursor positioning
75
+ * but avoids complex locking that can cause race conditions.
76
76
  */
77
77
  writeRaw(content: string): void;
78
78
  /**
@@ -88,17 +88,27 @@ export declare class Display {
88
88
  * Prefer writeRaw/writeStreamChunk for interceptor support.
89
89
  */
90
90
  getOutputStream(): OutputStream;
91
+ /**
92
+ * Current number of lines written to stdout (tracked for positioning).
93
+ */
94
+ getTotalWrittenLines(): number;
95
+ /**
96
+ * Number of lines at the top of the terminal that belong to the pinned banner.
97
+ * For integrated scroll-region layouts, banners are not pinned, so this is 0.
98
+ */
99
+ getPinnedHeaderLines(): number;
91
100
  private getColumnWidth;
92
101
  private bannerState;
102
+ private bannerContext;
93
103
  /**
94
- * Displays the welcome banner with session information.
95
- * Stores banner state for potential in-place updates.
104
+ * Displays the welcome banner with session information and tracks its bounds
105
+ * for potential in-place updates (still rendered inside the scroll region).
96
106
  */
97
107
  showWelcome(profileLabel: string, profileName: string, model: string, provider: string, workingDir: string, version?: string): void;
98
108
  /**
99
- * Updates the session information banner with new model/provider.
100
- * Attempts in-place update if possible, otherwise re-renders.
101
- */
109
+ * Updates the session information banner with new model/provider by appending
110
+ * a new banner entry in the scroll region (no pinned header rewriting).
111
+ */
102
112
  updateSessionInfo(model: string, provider: string): void;
103
113
  showThinking(message?: string): void;
104
114
  /**
@@ -148,6 +158,10 @@ export declare class Display {
148
158
  updateStreamingStatus(status: string | null): void;
149
159
  /**
150
160
  * Internal implementation of updateStreamingStatus (called with lock held)
161
+ * NOTE: During streaming, we do NOT write status lines to stdout to prevent
162
+ * race conditions with stream chunks. The status is tracked internally and
163
+ * the terminalInput's status message display handles showing it in the
164
+ * reserved input area, separate from the main content stream.
151
165
  */
152
166
  private updateStreamingStatusInternal;
153
167
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"display.d.ts","sourceRoot":"","sources":["../../src/ui/display.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"display.d.ts","sourceRoot":"","sources":["../../src/ui/display.ts"],"names":[],"mappings":"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"}
@@ -242,20 +242,17 @@ export class Display {
242
242
  }
243
243
  /**
244
244
  * Write raw content directly to output stream.
245
- * Goes through interceptors and shared write lock so overlays refresh safely.
246
- * Use this for streaming output chunks.
245
+ * For streaming output chunks - uses output interceptors for cursor positioning
246
+ * but avoids complex locking that can cause race conditions.
247
247
  */
248
248
  writeRaw(content) {
249
- if (typeof content !== 'string') {
249
+ if (typeof content !== 'string' || !content) {
250
250
  return;
251
251
  }
252
- // Use shared writeLock to coordinate with terminalInput
253
- writeLock.safeWrite(() => {
254
- this.outputLock.safeWrite(() => {
255
- this.withOutput(() => {
256
- this.write(content);
257
- });
258
- });
252
+ // Use withOutput to trigger interceptors (for cursor positioning during scroll region)
253
+ // but write synchronously without queueing
254
+ this.withOutput(() => {
255
+ this.write(content);
259
256
  });
260
257
  }
261
258
  /**
@@ -277,6 +274,19 @@ export class Display {
277
274
  getOutputStream() {
278
275
  return this.outputStream;
279
276
  }
277
+ /**
278
+ * Current number of lines written to stdout (tracked for positioning).
279
+ */
280
+ getTotalWrittenLines() {
281
+ return this.stdoutTracker.totalLines;
282
+ }
283
+ /**
284
+ * Number of lines at the top of the terminal that belong to the pinned banner.
285
+ * For integrated scroll-region layouts, banners are not pinned, so this is 0.
286
+ */
287
+ getPinnedHeaderLines() {
288
+ return 0;
289
+ }
280
290
  getColumnWidth() {
281
291
  if (typeof this.outputStream.columns === 'number' &&
282
292
  Number.isFinite(this.outputStream.columns) &&
@@ -286,9 +296,10 @@ export class Display {
286
296
  return getTerminalColumns();
287
297
  }
288
298
  bannerState = null;
299
+ bannerContext = null;
289
300
  /**
290
- * Displays the welcome banner with session information.
291
- * Stores banner state for potential in-place updates.
301
+ * Displays the welcome banner with session information and tracks its bounds
302
+ * for potential in-place updates (still rendered inside the scroll region).
292
303
  */
293
304
  showWelcome(profileLabel, profileName, model, provider, workingDir, version) {
294
305
  // Validate required inputs
@@ -304,47 +315,64 @@ export class Display {
304
315
  this.withOutput(() => {
305
316
  this.writeLine(banner);
306
317
  });
307
- const nextState = {
318
+ const height = this.measureBannerHeight(banner);
319
+ this.bannerState = {
308
320
  startLine,
309
- height: this.measureBannerHeight(banner),
321
+ height,
310
322
  width,
311
323
  workingDir,
324
+ version: version?.trim() || undefined,
312
325
  model,
313
326
  provider,
314
327
  profileLabel: profileLabel ?? '',
315
328
  profileName: profileName ?? '',
316
329
  };
317
- if (version?.trim()) {
318
- nextState.version = version.trim();
319
- }
320
- this.bannerState = nextState;
330
+ this.bannerContext = {
331
+ workingDir,
332
+ model,
333
+ provider,
334
+ profileLabel: profileLabel ?? '',
335
+ profileName: profileName ?? '',
336
+ version: version?.trim() || undefined,
337
+ };
321
338
  }
322
339
  /**
323
- * Updates the session information banner with new model/provider.
324
- * Attempts in-place update if possible, otherwise re-renders.
325
- */
340
+ * Updates the session information banner with new model/provider by appending
341
+ * a new banner entry in the scroll region (no pinned header rewriting).
342
+ */
326
343
  updateSessionInfo(model, provider) {
327
344
  const state = this.bannerState;
328
345
  if (!state) {
329
346
  return;
330
347
  }
331
- // Validate inputs
332
- if (!model?.trim() || !provider?.trim()) {
333
- return;
334
- }
335
348
  const width = this.getBannerWidth();
336
349
  const banner = this.buildClaudeStyleBanner(state.profileLabel, state.profileName, model, provider, state.workingDir, width, state.version);
337
350
  const height = this.measureBannerHeight(banner);
338
351
  // If height changed or rewrite failed, do full re-render
339
352
  if (height !== state.height || !this.tryRewriteBanner(state, banner)) {
340
353
  this.renderAndStoreBanner(state, model, provider);
354
+ this.bannerContext = {
355
+ workingDir: state.workingDir,
356
+ model: state.model,
357
+ provider: state.provider,
358
+ profileLabel: state.profileLabel,
359
+ profileName: state.profileName,
360
+ version: state.version,
361
+ };
341
362
  return;
342
363
  }
343
- // Update succeeded, update state
344
364
  state.model = model;
345
365
  state.provider = provider;
346
366
  state.width = width;
347
367
  state.height = height;
368
+ this.bannerContext = {
369
+ workingDir: state.workingDir,
370
+ model,
371
+ provider,
372
+ profileLabel: state.profileLabel,
373
+ profileName: state.profileName,
374
+ version: state.version,
375
+ };
348
376
  }
349
377
  showThinking(message = 'Thinking...') {
350
378
  // If we already have a spinner, just update its text instead of creating a new one
@@ -498,53 +526,18 @@ export class Display {
498
526
  }
499
527
  /**
500
528
  * Internal implementation of updateStreamingStatus (called with lock held)
529
+ * NOTE: During streaming, we do NOT write status lines to stdout to prevent
530
+ * race conditions with stream chunks. The status is tracked internally and
531
+ * the terminalInput's status message display handles showing it in the
532
+ * reserved input area, separate from the main content stream.
501
533
  */
502
534
  updateStreamingStatusInternal(status) {
503
535
  if (!status) {
504
- if (this.streamingStatusVisible) {
505
- if (this.scrollRegionActive) {
506
- // Clear status in the fixed area
507
- const rows = this.getTerminalRows();
508
- this.outputStream.write('\x1b[s'); // Save cursor
509
- this.outputStream.write(`\x1b[${rows};1H\x1b[2K`); // Go to status line, clear
510
- this.outputStream.write('\x1b[u'); // Restore cursor
511
- }
512
- else {
513
- this.outputStream.write('\r\x1b[2K');
514
- }
515
- this.streamingStatusVisible = false;
516
- }
536
+ this.streamingStatusVisible = false;
517
537
  return;
518
538
  }
519
- // Truncate status if needed
520
- const cols = this.getColumnWidth();
521
- const maxStatusLen = cols - 4;
522
- const displayStatus = status.length > maxStatusLen
523
- ? `${status.slice(0, maxStatusLen - 3)}...`
524
- : status;
525
- if (this.scrollRegionActive) {
526
- // Update status in the fixed area at bottom (outside scroll region)
527
- const rows = this.getTerminalRows();
528
- const separatorWidth = Math.min(cols - 2, 72);
529
- const separator = theme.ui.border('─'.repeat(separatorWidth));
530
- this.outputStream.write('\x1b[s'); // Save cursor position
531
- // Draw separator on row (rows - 1)
532
- this.outputStream.write(`\x1b[${rows - 1};1H\x1b[2K${separator}`);
533
- // Draw status on row (rows)
534
- this.outputStream.write(`\x1b[${rows};1H\x1b[2K${theme.ui.muted(displayStatus)}`);
535
- this.outputStream.write('\x1b[u'); // Restore cursor position
536
- this.streamingStatusVisible = true;
537
- }
538
- else {
539
- // Fallback: simple single-line update
540
- if (this.streamingStatusVisible) {
541
- this.outputStream.write(`\r\x1b[2K${theme.ui.muted(displayStatus)}`);
542
- }
543
- else {
544
- this.outputStream.write(`\n${theme.ui.muted(displayStatus)}`);
545
- this.streamingStatusVisible = true;
546
- }
547
- }
539
+ // Just track the status - don't write to stdout during streaming
540
+ this.streamingStatusVisible = true;
548
541
  }
549
542
  /**
550
543
  * Check if streaming status is currently visible.
@@ -562,15 +555,7 @@ export class Display {
562
555
  * Clear streaming status and reset state.
563
556
  */
564
557
  clearStreamingStatus() {
565
- if (this.streamingStatusVisible) {
566
- if (this.scrollRegionActive) {
567
- this.teardownScrollRegion();
568
- }
569
- else {
570
- this.outputStream.write('\r\x1b[2K');
571
- this.streamingStatusVisible = false;
572
- }
573
- }
558
+ this.streamingStatusVisible = false;
574
559
  }
575
560
  clearSpinnerIfActive(addNewLine = true) {
576
561
  if (!this.activeSpinner) {
@@ -794,7 +779,46 @@ export class Display {
794
779
  * Show streaming header - Claude Code style (minimal)
795
780
  */
796
781
  showStreamingHeader() {
797
- // Claude Code style: no header, just start streaming
782
+ const banner = this.bannerState;
783
+ const modelLabel = banner ? this.formatModelLabel(banner.model) : null;
784
+ const provider = banner?.provider ?? '';
785
+ const maxWidth = Math.min(this.getColumnWidth() - 4, DISPLAY_CONSTANTS.MAX_MESSAGE_WIDTH);
786
+ const width = Math.max(32, Math.min(80, maxWidth));
787
+ const workspace = banner
788
+ ? this.abbreviatePath(banner.workingDir, Math.max(18, width - 14))
789
+ : '';
790
+ // Plain output: keep it simple
791
+ if (isPlainOutputMode()) {
792
+ const label = modelLabel ? `Streaming ${modelLabel}` : 'Streaming response';
793
+ this.withOutput(() => this.writeLine(`--- ${label} ---`));
794
+ return;
795
+ }
796
+ const line = theme.gradient.cool('━'.repeat(width));
797
+ const pad = (value) => {
798
+ const visible = this.visibleLength(value);
799
+ const padding = Math.max(0, width - visible);
800
+ return `${value}${' '.repeat(padding)}`;
801
+ };
802
+ const statusParts = [
803
+ theme.gradient.cool('▶'),
804
+ theme.info('Live stream'),
805
+ modelLabel ? theme.ui.muted('•') : '',
806
+ modelLabel ? theme.info(modelLabel) : '',
807
+ provider ? theme.ui.muted('@') : '',
808
+ provider ? theme.accent(provider) : '',
809
+ ].filter(Boolean);
810
+ const statusLine = statusParts.join(' ');
811
+ const workspaceLine = workspace ? `${theme.ui.muted('Workspace')} ${workspace}` : '';
812
+ this.withOutput(() => {
813
+ this.writeLine();
814
+ this.writeLine(line);
815
+ this.writeLine(pad(`${theme.gradient.cool('┃')} ${statusLine}`));
816
+ if (workspaceLine) {
817
+ this.writeLine(pad(`${theme.gradient.cool('┃')} ${workspaceLine}`));
818
+ }
819
+ this.writeLine(line);
820
+ this.writeLine();
821
+ });
798
822
  }
799
823
  /**
800
824
  * Show model commands help
@@ -877,44 +901,36 @@ export class Display {
877
901
  if (!banner) {
878
902
  return 0;
879
903
  }
880
- const lines = banner.split('\n').length;
881
- return lines;
904
+ return banner.split('\n').length;
882
905
  }
883
906
  /**
884
907
  * Attempts to rewrite the banner in place using terminal cursor manipulation.
885
908
  * Returns true if successful, false if rewrite is not possible.
886
909
  */
887
910
  tryRewriteBanner(state, banner) {
888
- // Validate TTY availability
889
911
  if (!this.outputStream.isTTY) {
890
912
  return false;
891
913
  }
892
- // Validate banner state
893
914
  if (!banner || state.height <= 0) {
894
915
  return false;
895
916
  }
896
917
  const linesWritten = this.stdoutTracker.totalLines;
897
918
  const linesAfterBanner = linesWritten - (state.startLine + state.height);
898
- // Cannot rewrite if banner position is invalid
899
919
  if (linesAfterBanner < 0) {
900
920
  return false;
901
921
  }
902
922
  const totalOffset = linesAfterBanner + state.height;
903
923
  const maxRows = this.outputStream.rows;
904
- // Cannot rewrite if offset exceeds terminal height
905
924
  if (typeof maxRows === 'number' && maxRows > 0 && totalOffset > maxRows) {
906
925
  return false;
907
926
  }
908
927
  try {
909
928
  this.withOutput(() => {
910
- // Move cursor up to banner start
911
929
  moveCursor(this.outputStream, 0, -totalOffset);
912
930
  cursorTo(this.outputStream, 0);
913
- // Write new banner without tracking
914
931
  this.stdoutTracker.withSuspended(() => {
915
932
  this.outputStream.write(`${banner}\n`);
916
933
  });
917
- // Restore cursor position
918
934
  if (linesAfterBanner > 0) {
919
935
  moveCursor(this.outputStream, 0, linesAfterBanner);
920
936
  }
@@ -922,11 +938,7 @@ export class Display {
922
938
  });
923
939
  return true;
924
940
  }
925
- catch (error) {
926
- // Cursor manipulation failed (e.g., terminal doesn't support it)
927
- if (error instanceof Error) {
928
- // Could log error in debug mode if needed
929
- }
941
+ catch {
930
942
  return false;
931
943
  }
932
944
  }
@@ -1029,23 +1041,28 @@ export class Display {
1029
1041
  }
1030
1042
  buildClaudeStyleBanner(_profileLabel, _profileName, model, provider, workingDir, _width, version) {
1031
1043
  // Advanced banner with clean visual hierarchy
1032
- const lines = [];
1044
+ const baseWidth = Number.isFinite(_width) ? Math.max(0, _width) : this.getBannerWidth();
1045
+ const totalWidth = Math.max(DISPLAY_CONSTANTS.MIN_BANNER_WIDTH, Math.min(baseWidth, DISPLAY_CONSTANTS.MAX_BANNER_WIDTH));
1046
+ const innerWidth = Math.max(28, totalWidth - 4);
1047
+ const frameWidth = innerWidth + 2;
1033
1048
  const modelLabel = this.formatModelLabel(model);
1034
- const versionStr = version ? `v${version}` : '';
1035
- // Top separator with branding
1036
- const sepWidth = Math.min(this.getColumnWidth() - 4, 56);
1037
- lines.push(theme.gradient.cool(''.repeat(sepWidth)));
1038
- // Title line with version
1039
- lines.push(`${theme.gradient.cool('⚡ EROSOLAR')} ${theme.ui.muted(versionStr)}`);
1040
- // Model and provider info
1041
- lines.push(`${theme.ui.muted('┃')} ${theme.ui.muted('Model:')} ${theme.info(modelLabel)} ${theme.ui.muted('via')} ${theme.accent(provider)}`);
1042
- // Working directory
1043
- const shortDir = this.abbreviatePath(workingDir, 40);
1044
- lines.push(`${theme.ui.muted('')} ${theme.ui.muted('Path:')} ${shortDir}`);
1045
- // Commands hint
1046
- lines.push(`${theme.ui.muted('')} ${theme.ui.muted('Help:')} /help · /model · /clear · /quit`);
1047
- // Bottom separator
1048
- lines.push(theme.ui.muted(''.repeat(sepWidth)));
1049
+ const versionStr = version ? `v${version}` : 'live';
1050
+ const profileLabel = _profileLabel || _profileName || 'Default';
1051
+ const shortDir = this.abbreviatePath(workingDir, Math.max(16, innerWidth - 14));
1052
+ const commands = '/help · /model · /clear · /quit';
1053
+ const renderRow = (content) => {
1054
+ const visible = this.visibleLength(content);
1055
+ const padding = Math.max(0, innerWidth - visible);
1056
+ return `${theme.gradient.cool('┃')} ${content}${' '.repeat(padding)} ${theme.gradient.cool('')}`;
1057
+ };
1058
+ const lines = [];
1059
+ lines.push(theme.gradient.cool(`╭${''.repeat(frameWidth)}╮`));
1060
+ lines.push(renderRow(`${theme.gradient.cool('⚡ EROSOLAR CLI')} ${theme.ui.muted(versionStr)}`));
1061
+ lines.push(renderRow(`${theme.ui.muted('Profile')} ${theme.info(profileLabel)}`));
1062
+ lines.push(renderRow(`${theme.ui.muted('Model')} ${theme.info(modelLabel)} ${theme.ui.muted('via')} ${theme.accent(provider)}`));
1063
+ lines.push(renderRow(`${theme.ui.muted('Workspace')} ${shortDir}`));
1064
+ lines.push(renderRow(`${theme.ui.muted('Shortcuts')} ${commands}`));
1065
+ lines.push(theme.gradient.cool(`╰${'━'.repeat(frameWidth)}╯`));
1049
1066
  return lines.join('\n');
1050
1067
  }
1051
1068
  abbreviatePath(path, maxLen) {