@pellux/goodvibes-tui 0.28.0 → 0.29.0

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 (118) hide show
  1. package/CHANGELOG.md +101 -0
  2. package/README.md +1 -1
  3. package/package.json +1 -1
  4. package/src/input/commands/cost-runtime.ts +49 -0
  5. package/src/input/commands/operator-runtime.ts +5 -1
  6. package/src/input/commands.ts +2 -0
  7. package/src/input/handler-feed-routes.ts +12 -35
  8. package/src/input/handler-feed.ts +4 -8
  9. package/src/input/handler-shortcuts.ts +51 -0
  10. package/src/input/handler.ts +43 -6
  11. package/src/input/keybindings.ts +48 -8
  12. package/src/input/panel-integration-actions.ts +107 -1
  13. package/src/main.ts +5 -1
  14. package/src/panels/agent-inspector-panel.ts +125 -36
  15. package/src/panels/agent-inspector-shared.ts +144 -0
  16. package/src/panels/approval-panel.ts +67 -16
  17. package/src/panels/automation-control-panel.ts +368 -124
  18. package/src/panels/builtin/agent.ts +28 -37
  19. package/src/panels/builtin/development.ts +40 -32
  20. package/src/panels/builtin/knowledge.ts +15 -6
  21. package/src/panels/builtin/operations.ts +178 -117
  22. package/src/panels/builtin/session.ts +35 -9
  23. package/src/panels/builtin/shared.ts +98 -6
  24. package/src/panels/cockpit-panel.ts +232 -73
  25. package/src/panels/communication-panel.ts +58 -20
  26. package/src/panels/confirm-state.ts +8 -1
  27. package/src/panels/control-plane-panel.ts +351 -118
  28. package/src/panels/cost-tracker-panel.ts +165 -7
  29. package/src/panels/debug-panel.ts +312 -159
  30. package/src/panels/diff-panel.ts +203 -57
  31. package/src/panels/docs-panel.ts +152 -66
  32. package/src/panels/eval-panel.ts +220 -42
  33. package/src/panels/file-explorer-panel.ts +202 -122
  34. package/src/panels/file-preview-panel.ts +132 -57
  35. package/src/panels/git-panel.ts +309 -128
  36. package/src/panels/hooks-panel.ts +150 -22
  37. package/src/panels/incident-review-panel.ts +223 -35
  38. package/src/panels/index.ts +0 -4
  39. package/src/panels/intelligence-panel.ts +212 -86
  40. package/src/panels/knowledge-graph-panel.ts +461 -101
  41. package/src/panels/local-auth-panel.ts +240 -28
  42. package/src/panels/marketplace-panel.ts +193 -26
  43. package/src/panels/memory-panel.ts +78 -77
  44. package/src/panels/ops-control-panel.ts +146 -29
  45. package/src/panels/ops-strategy-panel.ts +72 -4
  46. package/src/panels/orchestration-panel.ts +231 -69
  47. package/src/panels/panel-list-panel.ts +154 -131
  48. package/src/panels/panel-manager.ts +97 -9
  49. package/src/panels/plan-dashboard-panel.ts +333 -17
  50. package/src/panels/plugins-panel.ts +184 -29
  51. package/src/panels/policy-panel.ts +210 -38
  52. package/src/panels/polish-core.ts +7 -2
  53. package/src/panels/polish.ts +23 -4
  54. package/src/panels/project-planning-answer-actions.ts +134 -0
  55. package/src/panels/project-planning-panel.ts +62 -113
  56. package/src/panels/provider-health-panel.ts +434 -518
  57. package/src/panels/provider-health-routes.ts +203 -0
  58. package/src/panels/provider-health-tracker.ts +194 -6
  59. package/src/panels/provider-health-views.ts +560 -0
  60. package/src/panels/qr-panel.ts +116 -30
  61. package/src/panels/remote-panel.ts +114 -36
  62. package/src/panels/routes-panel.ts +63 -22
  63. package/src/panels/sandbox-panel.ts +174 -42
  64. package/src/panels/scrollable-list-panel.ts +19 -135
  65. package/src/panels/security-panel.ts +133 -33
  66. package/src/panels/services-panel.ts +116 -64
  67. package/src/panels/session-browser-panel.ts +73 -2
  68. package/src/panels/session-maintenance.ts +4 -122
  69. package/src/panels/settings-sync-panel.ts +335 -72
  70. package/src/panels/skills-panel.ts +157 -89
  71. package/src/panels/subscription-panel.ts +86 -33
  72. package/src/panels/symbol-outline-panel.ts +248 -108
  73. package/src/panels/system-messages-panel.ts +114 -13
  74. package/src/panels/tasks-panel.ts +326 -139
  75. package/src/panels/thinking-panel.ts +43 -10
  76. package/src/panels/token-budget-panel.ts +194 -18
  77. package/src/panels/tool-inspector-panel.ts +144 -34
  78. package/src/panels/types.ts +40 -4
  79. package/src/panels/work-plan-panel.ts +280 -17
  80. package/src/panels/worktree-panel.ts +175 -42
  81. package/src/panels/wrfc-panel.ts +116 -24
  82. package/src/renderer/conversation-overlays.ts +25 -11
  83. package/src/renderer/footer-tips.ts +41 -0
  84. package/src/renderer/fullscreen-primitives.ts +22 -16
  85. package/src/renderer/help-overlay.ts +91 -14
  86. package/src/renderer/hint-grammar.ts +52 -0
  87. package/src/renderer/layout.ts +7 -7
  88. package/src/renderer/modal-factory.ts +23 -15
  89. package/src/renderer/model-picker-overlay.ts +21 -7
  90. package/src/renderer/overlay-box.ts +16 -10
  91. package/src/renderer/process-indicator.ts +3 -1
  92. package/src/renderer/progress.ts +5 -4
  93. package/src/renderer/search-overlay.ts +27 -6
  94. package/src/renderer/session-picker-modal.ts +6 -4
  95. package/src/renderer/settings-modal.ts +70 -10
  96. package/src/renderer/shell-surface.ts +41 -15
  97. package/src/renderer/status-glyphs.ts +11 -9
  98. package/src/renderer/theme.ts +60 -3
  99. package/src/renderer/ui-factory.ts +41 -30
  100. package/src/renderer/ui-primitives.ts +23 -2
  101. package/src/runtime/bootstrap-shell.ts +35 -18
  102. package/src/runtime/diagnostics/panels/index.ts +0 -3
  103. package/src/shell/ui-openers.ts +14 -22
  104. package/src/utils/format-duration.ts +2 -2
  105. package/src/utils/splash-lines.ts +44 -3
  106. package/src/version.ts +1 -1
  107. package/src/work-plans/work-plan-store.ts +13 -0
  108. package/src/panels/agent-logs-panel.ts +0 -635
  109. package/src/panels/agent-logs-shared.ts +0 -129
  110. package/src/panels/context-visualizer-panel.ts +0 -238
  111. package/src/panels/forensics-panel.ts +0 -378
  112. package/src/panels/provider-account-snapshot.ts +0 -259
  113. package/src/panels/provider-accounts-panel.ts +0 -255
  114. package/src/panels/provider-stats-panel.ts +0 -391
  115. package/src/panels/schedule-panel.ts +0 -365
  116. package/src/panels/watchers-panel.ts +0 -213
  117. package/src/runtime/diagnostics/panels/panel-resources.ts +0 -118
  118. package/src/runtime/diagnostics/panels/policy.ts +0 -177
@@ -6,6 +6,10 @@ import type { Line } from '../types/grid.ts';
6
6
  import { createStyledCell, createEmptyLine } from '../types/grid.ts';
7
7
  import { truncateDisplay, getDisplayWidth } from '../utils/terminal-width.ts';
8
8
  import { BasePanel } from './base-panel.ts';
9
+ import { UI_TONES } from '../renderer/ui-primitives.ts';
10
+ import { FilePreviewPanel } from './file-preview-panel.ts';
11
+ import type { PanelIntegrationContext } from './types.ts';
12
+ import { logger } from '@pellux/goodvibes-sdk/platform/utils';
9
13
  import {
10
14
  buildBodyText,
11
15
  buildEmptyState,
@@ -14,31 +18,63 @@ import {
14
18
  buildStyledPanelLine,
15
19
  type PanelWorkspaceSection,
16
20
  DEFAULT_PANEL_PALETTE,
21
+ extendPalette,
17
22
  } from './polish.ts';
18
23
 
19
24
  // ---------------------------------------------------------------------------
20
- // Colour palette
25
+ // Colour palette — dedicated diff-viewer scheme (like a mini syntax
26
+ // highlighter). Each hex literal is named once and reused for every role
27
+ // that shares it, including the workspace-chrome aliases (info/dim/value/
28
+ // empty) so the raw-hex count never grows. The title band itself is NOT
29
+ // overridden — buildPanelWorkspace always falls back to the canonical
30
+ // DEFAULT_PANEL_PALETTE.headerBg (WO-002: one title band everywhere).
21
31
  // ---------------------------------------------------------------------------
22
32
 
23
- const COLOR = {
24
- addition: '#00ff88',
25
- additionBg: '#001a0d',
26
- deletion: '#ff4444',
27
- deletionBg: '#1a0000',
28
- hunk: '#88aaff',
29
- hunkBg: '#0a0a1a',
30
- header: '#aaaaaa',
31
- lineNum: '#555555',
32
- lineNumAdd: '#00aa55',
33
- lineNumDel: '#aa2222',
34
- filename: '#ffffff',
35
- tabActive: '#ffffff',
36
- tabActiveBg: '#333333',
37
- tabInactive: '#666666',
38
- tabBg: '#222222',
39
- context: '#888888',
40
- statusBar: '#444444',
41
- } as const;
33
+ const HUNK_BLUE = '#88aaff';
34
+ // Context rows and line-number gutter use the shared theme's muted/dim
35
+ // foreground tones rather than dedicated gray hex literals.
36
+ const CONTEXT_GRAY = UI_TONES.fg.muted;
37
+ const FILENAME_WHITE = '#ffffff';
38
+ const ADD_GREEN = '#00ff88';
39
+ const ADD_BG = '#001a0d';
40
+ const DEL_RED = '#ff4444';
41
+ const DEL_BG = '#1a0000';
42
+ const HUNK_BG = '#0a0a1a';
43
+ const MARKER_GRAY = '#aaaaaa';
44
+ const LINE_NUM_GRAY = UI_TONES.fg.dim;
45
+ const LINE_NUM_ADD = '#00aa55';
46
+ const LINE_NUM_DEL = '#aa2222';
47
+ const TAB_ACTIVE_BG = '#333333';
48
+ const TAB_INACTIVE_GRAY = '#666666';
49
+ const TAB_BG = '#222222';
50
+ const STATUS_BAR_BG = '#444444';
51
+
52
+ const COLOR = extendPalette(DEFAULT_PANEL_PALETTE, {
53
+ // Workspace-chrome aliases (title band excluded — no headerBg override)
54
+ info: HUNK_BLUE,
55
+ dim: CONTEXT_GRAY,
56
+ value: FILENAME_WHITE,
57
+ empty: CONTEXT_GRAY,
58
+
59
+ // Domain accents
60
+ addition: ADD_GREEN,
61
+ additionBg: ADD_BG,
62
+ deletion: DEL_RED,
63
+ deletionBg: DEL_BG,
64
+ hunk: HUNK_BLUE,
65
+ hunkBg: HUNK_BG,
66
+ markerText: MARKER_GRAY,
67
+ lineNum: LINE_NUM_GRAY,
68
+ lineNumAdd: LINE_NUM_ADD,
69
+ lineNumDel: LINE_NUM_DEL,
70
+ filename: FILENAME_WHITE,
71
+ tabActive: FILENAME_WHITE,
72
+ tabActiveBg: TAB_ACTIVE_BG,
73
+ tabInactive: TAB_INACTIVE_GRAY,
74
+ tabBg: TAB_BG,
75
+ context: CONTEXT_GRAY,
76
+ statusBar: STATUS_BAR_BG,
77
+ } as const);
42
78
 
43
79
  // ---------------------------------------------------------------------------
44
80
  // Types
@@ -190,6 +226,9 @@ export class DiffPanel extends BasePanel {
190
226
  private selectedFile = 0;
191
227
  private scrollOffset = 0;
192
228
 
229
+ /** Set by the 'o' key; consumed by handlePanelIntegrationAction on the next dispatch. */
230
+ private pendingOpenPreview = false;
231
+
193
232
  constructor(workingDirectory: string) {
194
233
  super('diff', 'Diff', 'D', 'development');
195
234
  this.workingDirectory = workingDirectory;
@@ -233,9 +272,14 @@ export class DiffPanel extends BasePanel {
233
272
  const raw = await new Response(proc.stdout).text();
234
273
  await proc.exited;
235
274
  this.loadRawDiff(raw);
275
+ this.enrichSemanticDiffs(files, ref ?? 'HEAD').catch((err) => { logger.debug('DiffPanel: semantic diff enrichment failed', { err }); });
236
276
  }
237
277
 
238
- /** Run `git diff` and populate all changed files. */
278
+ /**
279
+ * Run `git diff` and populate all changed files. Self-load entry point for
280
+ * the 'w' (working tree, no ref) and 'h' (vs HEAD) keys. Automatically
281
+ * enriches every loaded file with a semantic-diff summary in the background.
282
+ */
239
283
  async showGitDiff(ref?: string): Promise<void> {
240
284
  const args = ['diff', ...(ref ? [ref] : [])];
241
285
  const proc = Bun.spawn(['git', ...args], { stdout: 'pipe', stderr: 'pipe', cwd: this.workingDirectory });
@@ -266,6 +310,73 @@ export class DiffPanel extends BasePanel {
266
310
  this.selectedFile = Math.min(this.selectedFile, Math.max(0, this.entries.length - 1));
267
311
  this.scrollOffset = 0;
268
312
  this.markDirty();
313
+ this.enrichSemanticDiffs(newEntries.map((e) => e.filePath), 'HEAD').catch((err) => { logger.debug('DiffPanel: semantic diff enrichment failed', { err }); });
314
+ }
315
+
316
+ /**
317
+ * Run `git diff --cached` and populate the staged changes. Self-load entry
318
+ * point for the 's' key — its own diff plumbing, independent of the
319
+ * `/diff staged` command handler.
320
+ */
321
+ async showStagedDiff(): Promise<void> {
322
+ const proc = Bun.spawn(['/bin/sh', '-c', 'git diff --cached'], { stdout: 'pipe', stderr: 'pipe', cwd: this.workingDirectory });
323
+ const [raw, errText] = await Promise.all([
324
+ new Response(proc.stdout).text(),
325
+ new Response(proc.stderr).text(),
326
+ ]);
327
+ const exitCode = await proc.exited;
328
+ if (exitCode !== 0) {
329
+ const errorText = errText.trim() || 'git diff --cached failed';
330
+ this.showDiff('(error)', `--- error\n+++ error\n@@ -0,0 +1,1 @@\n+${errorText}`);
331
+ return;
332
+ }
333
+ if (!raw.trim()) {
334
+ this.showDiff('(no staged changes)', '@@ -0,0 +0,0 @@\n No staged changes.');
335
+ return;
336
+ }
337
+ this.loadRawDiff(raw);
338
+ this.enrichSemanticDiffs(this.entries.map((e) => e.filePath), 'HEAD').catch((err) => { logger.debug('DiffPanel: semantic diff enrichment failed', { err }); });
339
+ }
340
+
341
+ /**
342
+ * Best-effort semantic-diff enrichment for a set of files, run against the
343
+ * before-content at `ref` and the current on-disk after-content. Self-contained
344
+ * diff plumbing — does not depend on the `/diff` command handler.
345
+ */
346
+ private async enrichSemanticDiffs(files: string[], ref: string): Promise<void> {
347
+ if (files.length === 0) return;
348
+ const { computeSemanticDiff, formatSemanticDiffSummary } = await import('../renderer/semantic-diff.ts');
349
+ const { join, relative: pathRelative } = await import('path');
350
+ const repoRootProc = Bun.spawn(['git', 'rev-parse', '--show-toplevel'], { stdout: 'pipe', cwd: this.workingDirectory });
351
+ await repoRootProc.exited;
352
+ const repoRoot = (await new Response(repoRootProc.stdout).text()).trim() || this.workingDirectory;
353
+ await Promise.allSettled(
354
+ files.map(async (filePath) => {
355
+ try {
356
+ const absPath = filePath.startsWith('/') ? filePath : join(this.workingDirectory, filePath);
357
+ const repoRelPath = filePath.startsWith('/') ? pathRelative(repoRoot, filePath) : filePath;
358
+ const [beforeResult, afterResult] = await Promise.allSettled([
359
+ (async () => {
360
+ const proc = Bun.spawn(
361
+ ['git', 'show', `${ref}:${repoRelPath}`],
362
+ { stdout: 'pipe', stderr: 'pipe', cwd: repoRoot },
363
+ );
364
+ const [text, exitCode] = await Promise.all([new Response(proc.stdout).text(), proc.exited]);
365
+ if (exitCode !== 0) throw new Error(`git show failed for ${repoRelPath}`);
366
+ return text;
367
+ })(),
368
+ Bun.file(absPath).text(),
369
+ ]);
370
+ if (beforeResult.status !== 'fulfilled' || afterResult.status !== 'fulfilled') return;
371
+ const semanticDiff = await computeSemanticDiff(filePath, beforeResult.value, afterResult.value);
372
+ if (!semanticDiff) return;
373
+ const summary = formatSemanticDiffSummary(semanticDiff);
374
+ if (summary) this.setSemanticSummary(filePath, summary);
375
+ } catch {
376
+ // best-effort only
377
+ }
378
+ }),
379
+ );
269
380
  }
270
381
 
271
382
  /**
@@ -306,12 +417,62 @@ export class DiffPanel extends BasePanel {
306
417
  case 'up': this.scrollUp(); return true;
307
418
  case 'down': this.scrollDown(); return true;
308
419
  case 'tab': this.nextFile(); return true;
420
+ // Shift+Tab: most terminals send the bare CSI-Z ("backtab") escape
421
+ // sequence rather than a Tab keypress with a shift modifier, and the
422
+ // input tokenizer passes that sequence through unchanged as the
423
+ // logical key name — so it (and the friendlier aliases some terminals/
424
+ // future tokenizer versions may emit) are matched explicitly here.
425
+ case '\x1b[Z':
426
+ case 'shift-tab':
427
+ case 'backtab': this.prevFile(); return true;
309
428
  case 'pageup': this.scrollPageUp(); return true;
310
429
  case 'pagedown': this.scrollPageDown(); return true;
430
+ case 'w': void this.showGitDiff(); return true;
431
+ case 'h': void this.showGitDiff('HEAD'); return true;
432
+ case 's': void this.showStagedDiff(); return true;
433
+ case 'o': {
434
+ if (!this.currentEntry()) return false;
435
+ this.pendingOpenPreview = true;
436
+ return true;
437
+ }
311
438
  default: return false;
312
439
  }
313
440
  }
314
441
 
442
+ /**
443
+ * Cross-panel integration hook — 'o' opens the currently selected file in
444
+ * the preview panel via the same open/focus bridge FileExplorerPanel uses
445
+ * (src/input/panel-integration-actions.ts), without this panel needing to
446
+ * know about PanelManager pane/focus mechanics beyond what ctx exposes.
447
+ */
448
+ handlePanelIntegrationAction(_key: string, ctx: PanelIntegrationContext): boolean {
449
+ if (!this.pendingOpenPreview) return false;
450
+ this.pendingOpenPreview = false;
451
+ const entry = this.currentEntry();
452
+ if (!entry) return false;
453
+
454
+ const pm = ctx.panelManager;
455
+ let previewPanel = pm.getPanel('preview');
456
+ if (previewPanel instanceof FilePreviewPanel) {
457
+ const pane = pm.getPaneOf('preview');
458
+ pm.activateById('preview');
459
+ if (pane) pm.focusPane(pane);
460
+ } else {
461
+ const targetPane: 'top' | 'bottom' = pm.isBottomPaneVisible()
462
+ ? (pm.getFocusedPane() === 'top' ? 'bottom' : 'top')
463
+ : 'bottom';
464
+ const opened = pm.open('preview', targetPane);
465
+ pm.show();
466
+ pm.focusPane(targetPane);
467
+ previewPanel = opened instanceof FilePreviewPanel ? opened : null;
468
+ }
469
+ if (previewPanel instanceof FilePreviewPanel) {
470
+ previewPanel.openFile(entry.filePath);
471
+ return true;
472
+ }
473
+ return false;
474
+ }
475
+
315
476
  private scrollUp(): void {
316
477
  if (this.scrollOffset > 0) {
317
478
  this.scrollOffset--;
@@ -349,6 +510,13 @@ export class DiffPanel extends BasePanel {
349
510
  this.markDirty();
350
511
  }
351
512
 
513
+ private prevFile(): void {
514
+ if (this.entries.length === 0) return;
515
+ this.selectedFile = (this.selectedFile - 1 + this.entries.length) % this.entries.length;
516
+ this.scrollOffset = 0;
517
+ this.markDirty();
518
+ }
519
+
352
520
  private currentEntry(): DiffEntry | null {
353
521
  return this.entries[this.selectedFile] ?? null;
354
522
  }
@@ -364,26 +532,20 @@ export class DiffPanel extends BasePanel {
364
532
  if (this.entries.length === 0) {
365
533
  return buildPanelWorkspace(width, height, {
366
534
  title: 'Diff Workspace',
367
- palette: {
368
- ...DEFAULT_PANEL_PALETTE,
369
- info: COLOR.hunk,
370
- dim: COLOR.context,
371
- value: COLOR.filename,
372
- },
535
+ palette: COLOR,
373
536
  sections: [{
374
537
  title: 'Diff',
375
538
  lines: buildEmptyState(
376
539
  width,
377
540
  ' No diff to display.',
378
- 'Load a git diff or select a changed file to populate the workspace.',
379
- [{ command: '/git diff', summary: 'load the current working-tree diff into the diff workspace' }],
380
- {
381
- ...DEFAULT_PANEL_PALETTE,
382
- info: COLOR.hunk,
383
- dim: COLOR.context,
384
- value: COLOR.filename,
385
- empty: COLOR.context,
386
- },
541
+ 'Load a git diff or select a changed file to populate the workspace. w=working h=HEAD s=staged self-load right here.',
542
+ // WO-160: corrected bare /diff loads files changed *this
543
+ // session* (falling back to the full HEAD diff when none are
544
+ // tracked yet), not the working-tree diff the w key already
545
+ // loads in-panel; the old summary text described the wrong
546
+ // command.
547
+ [{ command: '/diff', summary: 'load files changed this session into the diff workspace (falls back to the HEAD diff if none yet)' }],
548
+ COLOR,
387
549
  ),
388
550
  }],
389
551
  });
@@ -396,20 +558,10 @@ export class DiffPanel extends BasePanel {
396
558
 
397
559
  const compact = height <= 12;
398
560
  const summaryLines = entry.semanticSummary
399
- ? buildBodyText(width, `Semantic summary: ${entry.semanticSummary}`, {
400
- ...DEFAULT_PANEL_PALETTE,
401
- dim: COLOR.context,
402
- value: COLOR.filename,
403
- }, COLOR.context)
561
+ ? buildBodyText(width, `Semantic summary: ${entry.semanticSummary}`, COLOR, COLOR.context)
404
562
  : [];
405
563
  const previewSection = resolveScrollablePanelSection(width, height, {
406
- palette: {
407
- ...DEFAULT_PANEL_PALETTE,
408
- info: COLOR.hunk,
409
- dim: COLOR.context,
410
- value: COLOR.filename,
411
- headerBg: COLOR.tabBg,
412
- },
564
+ palette: COLOR,
413
565
  footerLines: [this.renderStatusBar(width, entry)],
414
566
  beforeSections: [
415
567
  {
@@ -444,13 +596,7 @@ export class DiffPanel extends BasePanel {
444
596
  ];
445
597
  return buildPanelWorkspace(width, height, {
446
598
  title: 'Diff Workspace',
447
- palette: {
448
- ...DEFAULT_PANEL_PALETTE,
449
- info: COLOR.hunk,
450
- dim: COLOR.context,
451
- value: COLOR.filename,
452
- headerBg: COLOR.tabBg,
453
- },
599
+ palette: COLOR,
454
600
  sections,
455
601
  footerLines: [this.renderStatusBar(width, entry)],
456
602
  });
@@ -509,7 +655,7 @@ export class DiffPanel extends BasePanel {
509
655
  { text: ' -', fg: COLOR.tabInactive, bg: COLOR.statusBar },
510
656
  { text: String(stat.removed), fg: COLOR.deletion, bg: COLOR.statusBar },
511
657
  { text: ` L${this.scrollOffset + 1}/${entry.lines.length}`, fg: COLOR.tabInactive, bg: COLOR.statusBar },
512
- { text: ' Tab next ↑/↓ scroll', fg: COLOR.context, bg: COLOR.statusBar },
658
+ { text: ' Tab/S-Tab file o open w/h/s load ↑/↓ scroll', fg: COLOR.context, bg: COLOR.statusBar },
513
659
  ];
514
660
  if (entry.semanticSummary) {
515
661
  segments.push({ text: ` ◈ ${entry.semanticSummary}`, fg: COLOR.hunk, bg: COLOR.statusBar });
@@ -531,7 +677,7 @@ export class DiffPanel extends BasePanel {
531
677
  case 'hunk':
532
678
  return renderText(width, pl.text, COLOR.hunk, COLOR.hunkBg, false);
533
679
  case 'header':
534
- return renderText(width, pl.text, COLOR.header, '', false);
680
+ return renderText(width, pl.text, COLOR.markerText, '', false);
535
681
  case 'context':
536
682
  default:
537
683
  return makeLine(width, left, right, ` ${pl.text}`, COLOR.context, '', COLOR.lineNum, false);