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