@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.
- package/CHANGELOG.md +101 -0
- package/README.md +1 -1
- package/package.json +1 -1
- package/src/input/commands/cost-runtime.ts +49 -0
- package/src/input/commands/operator-runtime.ts +5 -1
- package/src/input/commands.ts +2 -0
- package/src/input/handler-feed-routes.ts +12 -35
- package/src/input/handler-feed.ts +4 -8
- package/src/input/handler-shortcuts.ts +51 -0
- package/src/input/handler.ts +43 -6
- package/src/input/keybindings.ts +48 -8
- package/src/input/panel-integration-actions.ts +107 -1
- package/src/main.ts +5 -1
- package/src/panels/agent-inspector-panel.ts +125 -36
- package/src/panels/agent-inspector-shared.ts +144 -0
- package/src/panels/approval-panel.ts +67 -16
- package/src/panels/automation-control-panel.ts +368 -124
- package/src/panels/builtin/agent.ts +28 -37
- package/src/panels/builtin/development.ts +40 -32
- package/src/panels/builtin/knowledge.ts +15 -6
- package/src/panels/builtin/operations.ts +178 -117
- package/src/panels/builtin/session.ts +35 -9
- package/src/panels/builtin/shared.ts +98 -6
- package/src/panels/cockpit-panel.ts +232 -73
- package/src/panels/communication-panel.ts +58 -20
- package/src/panels/confirm-state.ts +8 -1
- package/src/panels/control-plane-panel.ts +351 -118
- package/src/panels/cost-tracker-panel.ts +165 -7
- package/src/panels/debug-panel.ts +312 -159
- package/src/panels/diff-panel.ts +203 -57
- package/src/panels/docs-panel.ts +152 -66
- package/src/panels/eval-panel.ts +220 -42
- package/src/panels/file-explorer-panel.ts +202 -122
- package/src/panels/file-preview-panel.ts +132 -57
- package/src/panels/git-panel.ts +309 -128
- package/src/panels/hooks-panel.ts +150 -22
- package/src/panels/incident-review-panel.ts +223 -35
- package/src/panels/index.ts +0 -4
- package/src/panels/intelligence-panel.ts +212 -86
- package/src/panels/knowledge-graph-panel.ts +461 -101
- package/src/panels/local-auth-panel.ts +240 -28
- package/src/panels/marketplace-panel.ts +193 -26
- package/src/panels/memory-panel.ts +78 -77
- package/src/panels/ops-control-panel.ts +146 -29
- package/src/panels/ops-strategy-panel.ts +72 -4
- package/src/panels/orchestration-panel.ts +231 -69
- package/src/panels/panel-list-panel.ts +154 -131
- package/src/panels/panel-manager.ts +97 -9
- package/src/panels/plan-dashboard-panel.ts +333 -17
- package/src/panels/plugins-panel.ts +184 -29
- package/src/panels/policy-panel.ts +210 -38
- package/src/panels/polish-core.ts +7 -2
- package/src/panels/polish.ts +23 -4
- package/src/panels/project-planning-answer-actions.ts +134 -0
- package/src/panels/project-planning-panel.ts +62 -113
- package/src/panels/provider-health-panel.ts +434 -518
- package/src/panels/provider-health-routes.ts +203 -0
- package/src/panels/provider-health-tracker.ts +194 -6
- package/src/panels/provider-health-views.ts +560 -0
- package/src/panels/qr-panel.ts +116 -30
- package/src/panels/remote-panel.ts +114 -36
- package/src/panels/routes-panel.ts +63 -22
- package/src/panels/sandbox-panel.ts +174 -42
- package/src/panels/scrollable-list-panel.ts +19 -135
- package/src/panels/security-panel.ts +133 -33
- package/src/panels/services-panel.ts +116 -64
- package/src/panels/session-browser-panel.ts +73 -2
- package/src/panels/session-maintenance.ts +4 -122
- package/src/panels/settings-sync-panel.ts +335 -72
- package/src/panels/skills-panel.ts +157 -89
- package/src/panels/subscription-panel.ts +86 -33
- package/src/panels/symbol-outline-panel.ts +248 -108
- package/src/panels/system-messages-panel.ts +114 -13
- package/src/panels/tasks-panel.ts +326 -139
- package/src/panels/thinking-panel.ts +43 -10
- package/src/panels/token-budget-panel.ts +194 -18
- package/src/panels/tool-inspector-panel.ts +144 -34
- package/src/panels/types.ts +40 -4
- package/src/panels/work-plan-panel.ts +280 -17
- package/src/panels/worktree-panel.ts +175 -42
- package/src/panels/wrfc-panel.ts +116 -24
- package/src/renderer/conversation-overlays.ts +25 -11
- package/src/renderer/footer-tips.ts +41 -0
- package/src/renderer/fullscreen-primitives.ts +22 -16
- package/src/renderer/help-overlay.ts +91 -14
- package/src/renderer/hint-grammar.ts +52 -0
- package/src/renderer/layout.ts +7 -7
- package/src/renderer/modal-factory.ts +23 -15
- package/src/renderer/model-picker-overlay.ts +21 -7
- package/src/renderer/overlay-box.ts +16 -10
- package/src/renderer/process-indicator.ts +3 -1
- package/src/renderer/progress.ts +5 -4
- package/src/renderer/search-overlay.ts +27 -6
- package/src/renderer/session-picker-modal.ts +6 -4
- package/src/renderer/settings-modal.ts +70 -10
- package/src/renderer/shell-surface.ts +41 -15
- package/src/renderer/status-glyphs.ts +11 -9
- package/src/renderer/theme.ts +60 -3
- package/src/renderer/ui-factory.ts +41 -30
- package/src/renderer/ui-primitives.ts +23 -2
- package/src/runtime/bootstrap-shell.ts +35 -18
- package/src/runtime/diagnostics/panels/index.ts +0 -3
- package/src/shell/ui-openers.ts +14 -22
- package/src/utils/format-duration.ts +2 -2
- package/src/utils/splash-lines.ts +44 -3
- package/src/version.ts +1 -1
- package/src/work-plans/work-plan-store.ts +13 -0
- package/src/panels/agent-logs-panel.ts +0 -635
- package/src/panels/agent-logs-shared.ts +0 -129
- package/src/panels/context-visualizer-panel.ts +0 -238
- package/src/panels/forensics-panel.ts +0 -378
- package/src/panels/provider-account-snapshot.ts +0 -259
- package/src/panels/provider-accounts-panel.ts +0 -255
- package/src/panels/provider-stats-panel.ts +0 -391
- package/src/panels/schedule-panel.ts +0 -365
- package/src/panels/watchers-panel.ts +0 -213
- package/src/runtime/diagnostics/panels/panel-resources.ts +0 -118
- package/src/runtime/diagnostics/panels/policy.ts +0 -177
package/src/panels/diff-panel.ts
CHANGED
|
@@ -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
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
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
|
-
/**
|
|
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
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
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
|
|
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.
|
|
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);
|