@pellux/goodvibes-tui 0.26.0 → 0.27.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 +17 -0
- package/README.md +12 -7
- package/docs/foundation-artifacts/operator-contract.json +4 -1
- package/package.json +2 -2
- package/src/cli/bundle-command.ts +2 -1
- package/src/cli/service-posture.ts +2 -1
- package/src/core/conversation-rendering.ts +2 -2
- package/src/core/conversation.ts +49 -2
- package/src/core/session-recovery.ts +24 -18
- package/src/core/system-message-router.ts +42 -26
- package/src/core/turn-event-wiring.ts +12 -16
- package/src/daemon/handlers/calendar/caldav-client.ts +2 -1
- package/src/daemon/handlers/inbox/index.ts +2 -1
- package/src/daemon/handlers/inbox/poller.ts +2 -1
- package/src/daemon/handlers/inbox/providers/discord.ts +2 -1
- package/src/daemon/handlers/inbox/providers/email.ts +2 -1
- package/src/daemon/handlers/inbox/providers/route-util.ts +2 -1
- package/src/daemon/handlers/inbox/providers/slack.ts +2 -1
- package/src/daemon/handlers/triage/integration.ts +2 -1
- package/src/daemon/handlers/triage/pipeline.ts +2 -1
- package/src/daemon/handlers/triage/tagger/discord.ts +2 -1
- package/src/daemon/handlers/triage/tagger/imap.ts +4 -3
- package/src/export/gist-uploader.ts +3 -1
- package/src/input/command-registry.ts +1 -0
- package/src/input/commands/cloudflare-runtime.ts +2 -1
- package/src/input/commands/guidance-runtime.ts +2 -4
- package/src/input/commands/health-runtime.ts +13 -7
- package/src/input/commands/knowledge.ts +2 -1
- package/src/input/commands/runtime-services.ts +40 -10
- package/src/input/handler-command-route.ts +1 -1
- package/src/input/handler-interactions.ts +2 -1
- package/src/input/handler-modal-routes.ts +2 -1
- package/src/input/handler-onboarding-cloudflare.ts +2 -1
- package/src/input/handler-onboarding.ts +8 -8
- package/src/input/handler-ui-state.ts +1 -1
- package/src/input/tts-settings-actions.ts +2 -1
- package/src/main.ts +52 -59
- package/src/panels/agent-inspector-panel.ts +72 -2
- package/src/panels/agent-logs-panel.ts +127 -19
- package/src/panels/base-panel.ts +2 -1
- package/src/panels/builtin/agent.ts +3 -1
- package/src/panels/builtin/development.ts +1 -0
- package/src/panels/builtin/session.ts +1 -1
- package/src/panels/context-visualizer-panel.ts +24 -14
- package/src/panels/cost-tracker-panel.ts +7 -13
- package/src/panels/debug-panel.ts +11 -22
- package/src/panels/docs-panel.ts +14 -24
- package/src/panels/file-explorer-panel.ts +2 -1
- package/src/panels/file-preview-panel.ts +2 -1
- package/src/panels/git-panel.ts +10 -17
- package/src/panels/marketplace-panel.ts +2 -1
- package/src/panels/memory-panel.ts +2 -1
- package/src/panels/project-planning-panel.ts +5 -4
- package/src/panels/provider-health-panel.ts +56 -67
- package/src/panels/schedule-panel.ts +4 -7
- package/src/panels/session-browser-panel.ts +13 -21
- package/src/panels/skills-panel.ts +2 -1
- package/src/panels/tasks-panel.ts +2 -7
- package/src/panels/thinking-panel.ts +6 -11
- package/src/panels/token-budget-panel.ts +31 -15
- package/src/panels/tool-inspector-panel.ts +10 -18
- package/src/panels/work-plan-panel.ts +2 -1
- package/src/panels/wrfc-panel.ts +37 -35
- package/src/renderer/agent-detail-modal.ts +2 -2
- package/src/renderer/modal-utils.ts +0 -10
- package/src/renderer/process-modal.ts +2 -2
- package/src/runtime/bootstrap-command-context.ts +3 -0
- package/src/runtime/bootstrap-command-parts.ts +3 -1
- package/src/runtime/bootstrap-core.ts +31 -31
- package/src/runtime/bootstrap-shell.ts +1 -0
- package/src/runtime/onboarding/apply.ts +4 -3
- package/src/runtime/onboarding/snapshot.ts +4 -3
- package/src/runtime/process-lifecycle.ts +195 -0
- package/src/runtime/services.ts +4 -1
- package/src/runtime/wrfc-persistence.ts +20 -5
- package/src/shell/ui-openers.ts +3 -2
- package/src/verification/live-verifier.ts +4 -3
- package/src/version.ts +1 -1
- package/src/core/context-auto-compact.ts +0 -110
|
@@ -18,14 +18,12 @@ import {
|
|
|
18
18
|
buildStyledPanelLine,
|
|
19
19
|
buildPanelWorkspace,
|
|
20
20
|
DEFAULT_PANEL_PALETTE,
|
|
21
|
+
extendPalette,
|
|
21
22
|
} from './polish.ts';
|
|
22
23
|
|
|
23
|
-
const C = {
|
|
24
|
+
const C = extendPalette(DEFAULT_PANEL_PALETTE, {
|
|
24
25
|
convFg: '#cc99ff',
|
|
25
|
-
|
|
26
|
-
barEmpty: '#333344',
|
|
27
|
-
labelFg: '#8888bb',
|
|
28
|
-
} as const;
|
|
26
|
+
});
|
|
29
27
|
|
|
30
28
|
|
|
31
29
|
|
|
@@ -49,8 +47,9 @@ export class ContextVisualizerPanel extends BasePanel {
|
|
|
49
47
|
sessionMemoryStore: SessionMemoryQuery,
|
|
50
48
|
private readonly configManager: Pick<ConfigManager, 'get'>,
|
|
51
49
|
private getUsage?: () => { input: number; output: number; cacheRead: number; cacheWrite: number; model?: string },
|
|
52
|
-
private contextLimit?: number,
|
|
50
|
+
private contextLimit?: number | (() => number),
|
|
53
51
|
private sessionReadModel?: UiReadModel<UiSessionSnapshot>,
|
|
52
|
+
private getLastInputTokens?: () => number,
|
|
54
53
|
) {
|
|
55
54
|
super('context', 'Context', 'C', 'ai');
|
|
56
55
|
this.sessionMemoryStore = sessionMemoryStore;
|
|
@@ -80,7 +79,7 @@ export class ContextVisualizerPanel extends BasePanel {
|
|
|
80
79
|
const pct = limit > 0 ? Math.min(100, Math.round((input / limit) * 100)) : 0;
|
|
81
80
|
const barWidth = Math.max(1, width - 2);
|
|
82
81
|
const overLimit = limit > 0 && input > limit;
|
|
83
|
-
const fg = overLimit ? C.
|
|
82
|
+
const fg = overLimit ? C.bad : C.convFg;
|
|
84
83
|
if (limit <= 0) {
|
|
85
84
|
return buildPanelWorkspace(width, height, {
|
|
86
85
|
title: ' Context Usage',
|
|
@@ -138,10 +137,10 @@ export class ContextVisualizerPanel extends BasePanel {
|
|
|
138
137
|
private _renderBar(width: number, barWidth: number, input: number, limit: number): Line {
|
|
139
138
|
const filled = limit > 0 ? Math.min(barWidth, Math.round((input / limit) * barWidth)) : 0;
|
|
140
139
|
const overLimit = limit > 0 && input > limit;
|
|
141
|
-
const barFg = overLimit ? C.
|
|
140
|
+
const barFg = overLimit ? C.bad : C.convFg;
|
|
142
141
|
return buildMeterLine(width, filled, barWidth, {
|
|
143
142
|
filled: barFg,
|
|
144
|
-
empty: C.
|
|
143
|
+
empty: C.empty,
|
|
145
144
|
label: DEFAULT_PANEL_PALETTE.dim,
|
|
146
145
|
});
|
|
147
146
|
}
|
|
@@ -151,7 +150,7 @@ export class ContextVisualizerPanel extends BasePanel {
|
|
|
151
150
|
const valStr = formatK(val).padStart(7);
|
|
152
151
|
const pctStr = `${pct}%`.padStart(5);
|
|
153
152
|
return buildStyledPanelLine(width, [
|
|
154
|
-
{ text: labelPadded, fg: C.
|
|
153
|
+
{ text: labelPadded, fg: C.label },
|
|
155
154
|
{ text: valStr, fg },
|
|
156
155
|
{ text: ' ', fg: DEFAULT_PANEL_PALETTE.dim },
|
|
157
156
|
{ text: pctStr, fg },
|
|
@@ -159,10 +158,21 @@ export class ContextVisualizerPanel extends BasePanel {
|
|
|
159
158
|
}
|
|
160
159
|
|
|
161
160
|
private _refresh(): void {
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
this.
|
|
161
|
+
// Resolve the context window live so the panel tracks /model switches when a
|
|
162
|
+
// getter is supplied; a plain number stays fixed at its provided value.
|
|
163
|
+
this.snapshot.limit =
|
|
164
|
+
typeof this.contextLimit === 'function' ? this.contextLimit() : (this.contextLimit ?? 0);
|
|
165
|
+
// Prefer the live per-call input occupancy (cache-inclusive, matching the
|
|
166
|
+
// Tokens panel and the auto-compaction threshold) when a getter is wired;
|
|
167
|
+
// otherwise fall back to the cumulative usage input.
|
|
168
|
+
const lastInput = this.getLastInputTokens?.();
|
|
169
|
+
if (lastInput !== undefined) {
|
|
170
|
+
this.snapshot.input = lastInput;
|
|
171
|
+
} else {
|
|
172
|
+
const usage = this.getUsage?.();
|
|
173
|
+
if (usage) {
|
|
174
|
+
this.snapshot.input = usage.input;
|
|
175
|
+
}
|
|
166
176
|
}
|
|
167
177
|
this.markDirty();
|
|
168
178
|
}
|
|
@@ -14,6 +14,7 @@ import {
|
|
|
14
14
|
buildStyledPanelLine,
|
|
15
15
|
buildPanelWorkspace,
|
|
16
16
|
resolveScrollablePanelSection,
|
|
17
|
+
extendPalette,
|
|
17
18
|
DEFAULT_PANEL_PALETTE,
|
|
18
19
|
type PanelWorkspaceSection,
|
|
19
20
|
} from './polish.ts';
|
|
@@ -75,20 +76,13 @@ function buildSparkline(history: number[]): string {
|
|
|
75
76
|
// Colour palette
|
|
76
77
|
// ---------------------------------------------------------------------------
|
|
77
78
|
|
|
78
|
-
const C = {
|
|
79
|
-
header: '#ffffff',
|
|
80
|
-
label: '#aaaaaa',
|
|
81
|
-
value: '#00ff88',
|
|
79
|
+
const C = extendPalette(DEFAULT_PANEL_PALETTE, {
|
|
82
80
|
cost: '#ffdd44',
|
|
83
|
-
alert: '#ff4444',
|
|
84
|
-
dim: '#555555',
|
|
85
81
|
model: '#88aaff',
|
|
86
82
|
running: '#88aaff',
|
|
87
|
-
done: '#00ff88',
|
|
88
|
-
failed: '#ff4444',
|
|
89
83
|
separator: '#333333',
|
|
90
84
|
bg: '',
|
|
91
|
-
}
|
|
85
|
+
});
|
|
92
86
|
|
|
93
87
|
// ---------------------------------------------------------------------------
|
|
94
88
|
// CostTrackerPanel
|
|
@@ -273,7 +267,7 @@ export class CostTrackerPanel extends BasePanel {
|
|
|
273
267
|
const overBudget = this.budgetThreshold > 0 && sessionCost > this.budgetThreshold;
|
|
274
268
|
const sparkline = buildSparkline(this.costHistory);
|
|
275
269
|
const costStr = formatCost(sessionCost);
|
|
276
|
-
const costFg = overBudget ? C.
|
|
270
|
+
const costFg = overBudget ? C.bad : C.cost;
|
|
277
271
|
const budgetStr = this.budgetThreshold > 0
|
|
278
272
|
? ` / ${formatCost(this.budgetThreshold)}`
|
|
279
273
|
: '';
|
|
@@ -281,7 +275,7 @@ export class CostTrackerPanel extends BasePanel {
|
|
|
281
275
|
const sessionLines: Line[] = [
|
|
282
276
|
this.renderKeyValue(width, ' Total', `${costStr}${budgetStr}${alertStr}`, costFg),
|
|
283
277
|
];
|
|
284
|
-
if (sparkline.length > 0) sessionLines.push(this.renderLabeledLine(width, ' Trend', sparkline, C.
|
|
278
|
+
if (sparkline.length > 0) sessionLines.push(this.renderLabeledLine(width, ' Trend', sparkline, C.good));
|
|
285
279
|
sessionLines.push(this.renderKeyValue(width, ' Input', formatTokens(this.sessionUsage.input), C.label));
|
|
286
280
|
sessionLines.push(this.renderKeyValue(width, ' Output', formatTokens(this.sessionUsage.output), C.label));
|
|
287
281
|
if (this.sessionUsage.cacheRead > 0 || this.sessionUsage.cacheWrite > 0) {
|
|
@@ -307,8 +301,8 @@ export class CostTrackerPanel extends BasePanel {
|
|
|
307
301
|
];
|
|
308
302
|
for (const agent of agentList) {
|
|
309
303
|
const statusFg = agent.status === 'running' ? C.running
|
|
310
|
-
: agent.status === 'failed' ? C.
|
|
311
|
-
: C.
|
|
304
|
+
: agent.status === 'failed' ? C.bad
|
|
305
|
+
: C.good;
|
|
312
306
|
const statusIcon = agent.status === 'running' ? '…'
|
|
313
307
|
: agent.status === 'failed' ? '✕'
|
|
314
308
|
: '✓';
|
|
@@ -11,6 +11,7 @@ import {
|
|
|
11
11
|
resolveScrollablePanelSection,
|
|
12
12
|
resolveStackedScrollableSections,
|
|
13
13
|
DEFAULT_PANEL_PALETTE,
|
|
14
|
+
extendPalette,
|
|
14
15
|
type PanelWorkspaceSection,
|
|
15
16
|
} from './polish.ts';
|
|
16
17
|
|
|
@@ -52,24 +53,12 @@ const MAX_ERROR_LOG = 20;
|
|
|
52
53
|
// Colors
|
|
53
54
|
// ---------------------------------------------------------------------------
|
|
54
55
|
|
|
55
|
-
const C = {
|
|
56
|
-
title: '#00ffff',
|
|
57
|
-
ok: '#5fd700',
|
|
58
|
-
error: '#ff5f5f',
|
|
59
|
-
warn: '#ffaf00',
|
|
60
|
-
label: '244',
|
|
61
|
-
value: '252',
|
|
62
|
-
dim: '240',
|
|
56
|
+
const C = extendPalette(DEFAULT_PANEL_PALETTE, {
|
|
63
57
|
provName: '#e2e8f0',
|
|
64
|
-
separator: '#374151',
|
|
65
58
|
input: '#00ffff',
|
|
66
59
|
output: '#d000ff',
|
|
67
|
-
latGood: '#5fd700',
|
|
68
|
-
latWarn: '#ffaf00',
|
|
69
|
-
latBad: '#ff5f5f',
|
|
70
|
-
sectionHdr: '238',
|
|
71
60
|
colHdr: '242',
|
|
72
|
-
}
|
|
61
|
+
});
|
|
73
62
|
|
|
74
63
|
const LATENCY_WARN_MS = 2_000;
|
|
75
64
|
const LATENCY_BAD_MS = 5_000;
|
|
@@ -99,9 +88,9 @@ function fmtAgo(ts: number): string {
|
|
|
99
88
|
}
|
|
100
89
|
|
|
101
90
|
function latColor(ms: number): string {
|
|
102
|
-
if (ms >= LATENCY_BAD_MS) return C.
|
|
103
|
-
if (ms >= LATENCY_WARN_MS) return C.
|
|
104
|
-
return C.
|
|
91
|
+
if (ms >= LATENCY_BAD_MS) return C.bad;
|
|
92
|
+
if (ms >= LATENCY_WARN_MS) return C.warn;
|
|
93
|
+
return C.good;
|
|
105
94
|
}
|
|
106
95
|
|
|
107
96
|
function statusCodeFromError(msg: string): number {
|
|
@@ -346,9 +335,9 @@ export class DebugPanel extends BasePanel {
|
|
|
346
335
|
{ text: ' Calls: ', fg: C.label },
|
|
347
336
|
{ text: String(this._totalCalls), fg: C.value },
|
|
348
337
|
{ text: ' OK: ', fg: C.label },
|
|
349
|
-
{ text: String(okCount), fg: C.
|
|
338
|
+
{ text: String(okCount), fg: C.good },
|
|
350
339
|
{ text: ' Errors: ', fg: C.label },
|
|
351
|
-
{ text: String(errCount), fg: errCount > 0 ? C.
|
|
340
|
+
{ text: String(errCount), fg: errCount > 0 ? C.bad : C.dim },
|
|
352
341
|
]),
|
|
353
342
|
];
|
|
354
343
|
}
|
|
@@ -372,7 +361,7 @@ export class DebugPanel extends BasePanel {
|
|
|
372
361
|
private _callLogRow(e: ApiCallEntry, width: number): Line {
|
|
373
362
|
const timeStr = fmtAgo(e.ts).padEnd(8);
|
|
374
363
|
const statusChar = e.status === 'ok' ? '✓' : '✕';
|
|
375
|
-
const statusFg = e.status === 'ok' ? C.
|
|
364
|
+
const statusFg = e.status === 'ok' ? C.good : C.bad;
|
|
376
365
|
const provStr = e.provider.slice(0, 11).padEnd(12);
|
|
377
366
|
const modelStr = e.model.slice(0, 19).padEnd(20);
|
|
378
367
|
const inStr = fmtTok(e.inputTokens).padStart(8);
|
|
@@ -391,7 +380,7 @@ export class DebugPanel extends BasePanel {
|
|
|
391
380
|
|
|
392
381
|
// Append status code for errors
|
|
393
382
|
if (e.status === 'error' && e.statusCode > 0) {
|
|
394
|
-
segments.push({ text: ` [${e.statusCode}]`, fg: C.
|
|
383
|
+
segments.push({ text: ` [${e.statusCode}]`, fg: C.bad });
|
|
395
384
|
}
|
|
396
385
|
|
|
397
386
|
return buildStyledPanelLine(
|
|
@@ -414,7 +403,7 @@ export class DebugPanel extends BasePanel {
|
|
|
414
403
|
const codeStr = e.statusCode > 0 ? `[${e.statusCode}] ` : '';
|
|
415
404
|
const msgStr = (e.errorMessage ?? 'unknown error').slice(0, width - 12 - codeStr.length);
|
|
416
405
|
const full = ` ${timeStr} ${codeStr}${msgStr}`;
|
|
417
|
-
return this._textLine(full.slice(0, width), C.
|
|
406
|
+
return this._textLine(full.slice(0, width), C.bad, width);
|
|
418
407
|
}
|
|
419
408
|
|
|
420
409
|
// -------------------------------------------------------------------------
|
package/src/panels/docs-panel.ts
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
|
|
5
5
|
import type { Line } from '../types/grid.ts';
|
|
6
6
|
import { BasePanel } from './base-panel.ts';
|
|
7
|
-
import { buildPanelLine, buildPanelWorkspace, buildSearchInputLine, resolveScrollablePanelSection, DEFAULT_PANEL_PALETTE } from './polish.ts';
|
|
7
|
+
import { buildPanelLine, buildPanelWorkspace, buildSearchInputLine, resolveScrollablePanelSection, extendPalette, DEFAULT_PANEL_PALETTE } from './polish.ts';
|
|
8
8
|
import type { ProviderModelCatalogQuery, ToolCatalogQuery } from '../runtime/ui-service-queries.ts';
|
|
9
9
|
import {
|
|
10
10
|
getPanelSearchFocusTransition,
|
|
@@ -14,22 +14,12 @@ import {
|
|
|
14
14
|
isPanelSearchPrintable,
|
|
15
15
|
} from './search-focus.ts';
|
|
16
16
|
|
|
17
|
-
const C = {
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
sectionBg: '#0d1a2a',
|
|
24
|
-
toolFg: '#88ccff',
|
|
25
|
-
descFg: '#aaaaaa',
|
|
26
|
-
keyFg: '#ffcc44',
|
|
27
|
-
valueFg: '#ccccdd',
|
|
28
|
-
dimFg: '#555566',
|
|
29
|
-
selected: '#00ffff',
|
|
30
|
-
selectedBg: '#1a2a3a',
|
|
31
|
-
searchFg: '#ffffff',
|
|
32
|
-
} as const;
|
|
17
|
+
const C = extendPalette(DEFAULT_PANEL_PALETTE, {
|
|
18
|
+
// Panel-specific domain colors with no clean shared equivalent.
|
|
19
|
+
sectionFg: '#00ffff',
|
|
20
|
+
toolFg: '#88ccff',
|
|
21
|
+
selected: '#00ffff',
|
|
22
|
+
});
|
|
33
23
|
|
|
34
24
|
// ---------------------------------------------------------------------------
|
|
35
25
|
// Hardcoded keyboard shortcut reference
|
|
@@ -68,7 +58,7 @@ interface FlatRow {
|
|
|
68
58
|
}
|
|
69
59
|
|
|
70
60
|
function renderRow(width: number, row: FlatRow, isCursor: boolean): Line {
|
|
71
|
-
const bg = isCursor ? C.
|
|
61
|
+
const bg = isCursor ? C.selectBg : row.bg;
|
|
72
62
|
return buildPanelLine(width, [
|
|
73
63
|
[isCursor ? '▸' : ' ', C.selected, bg],
|
|
74
64
|
[row.text, isCursor ? C.selected : row.fg, bg],
|
|
@@ -217,13 +207,13 @@ export class DocsPanel extends BasePanel {
|
|
|
217
207
|
const tools = this.toolRegistry?.list() ?? [];
|
|
218
208
|
const filtered = q ? tools.filter(t => t.definition.name.toLowerCase().includes(q) || (t.definition.description ?? '').toLowerCase().includes(q)) : tools;
|
|
219
209
|
if (filtered.length === 0) {
|
|
220
|
-
rows.push({ kind: 'empty', text: ' No tools match.', fg: C.
|
|
210
|
+
rows.push({ kind: 'empty', text: ' No tools match.', fg: C.dim, bg: '' });
|
|
221
211
|
} else {
|
|
222
212
|
rows.push({ kind: 'header', text: ` Tools (${filtered.length})`, fg: C.sectionFg, bg: C.sectionBg, bold: true });
|
|
223
213
|
for (const tool of filtered) {
|
|
224
214
|
rows.push({ kind: 'item', text: ` ${tool.definition.name}`, fg: C.toolFg, bg: '', bold: true });
|
|
225
215
|
if (tool.definition.description) {
|
|
226
|
-
rows.push({ kind: 'detail', text: ` ${tool.definition.description}`, fg: C.
|
|
216
|
+
rows.push({ kind: 'detail', text: ` ${tool.definition.description}`, fg: C.label, bg: '' });
|
|
227
217
|
}
|
|
228
218
|
const metadata: string[] = [];
|
|
229
219
|
if (tool.definition.sideEffects && tool.definition.sideEffects.length > 0) {
|
|
@@ -239,7 +229,7 @@ export class DocsPanel extends BasePanel {
|
|
|
239
229
|
metadata.push('streaming');
|
|
240
230
|
}
|
|
241
231
|
if (metadata.length > 0) {
|
|
242
|
-
rows.push({ kind: 'detail', text: ` ${metadata.join(' | ')}`, fg: C.
|
|
232
|
+
rows.push({ kind: 'detail', text: ` ${metadata.join(' | ')}`, fg: C.dim, bg: '' });
|
|
243
233
|
}
|
|
244
234
|
}
|
|
245
235
|
}
|
|
@@ -247,7 +237,7 @@ export class DocsPanel extends BasePanel {
|
|
|
247
237
|
const models = this.providerRegistry?.listModels() ?? [];
|
|
248
238
|
const filtered = q ? models.filter(m => m.id.toLowerCase().includes(q) || m.displayName.toLowerCase().includes(q) || m.provider.toLowerCase().includes(q)) : models;
|
|
249
239
|
if (filtered.length === 0) {
|
|
250
|
-
rows.push({ kind: 'empty', text: ' No models match.', fg: C.
|
|
240
|
+
rows.push({ kind: 'empty', text: ' No models match.', fg: C.dim, bg: '' });
|
|
251
241
|
} else {
|
|
252
242
|
// Group by provider
|
|
253
243
|
const byProvider = new Map<string, typeof filtered>();
|
|
@@ -262,7 +252,7 @@ export class DocsPanel extends BasePanel {
|
|
|
262
252
|
const ctxK = m.contextWindow > 0 ? `${(m.contextWindow / 1000).toFixed(0)}k` : '?';
|
|
263
253
|
const caps = [m.contextWindow > 0 ? `ctx:${ctxK}` : ''].filter(Boolean).join(' ');
|
|
264
254
|
rows.push({ kind: 'item', text: ` ${m.displayName} ${caps}`, fg: C.toolFg, bg: '' });
|
|
265
|
-
rows.push({ kind: 'detail', text: ` ${m.id}`, fg: C.
|
|
255
|
+
rows.push({ kind: 'detail', text: ` ${m.id}`, fg: C.label, bg: '' });
|
|
266
256
|
}
|
|
267
257
|
}
|
|
268
258
|
}
|
|
@@ -272,7 +262,7 @@ export class DocsPanel extends BasePanel {
|
|
|
272
262
|
rows.push({ kind: 'header', text: ' Keyboard Shortcuts', fg: C.sectionFg, bg: C.sectionBg, bold: true });
|
|
273
263
|
for (const s of filtered) {
|
|
274
264
|
const key = s.key.padEnd(16);
|
|
275
|
-
rows.push({ kind: 'item', text: ` ${key} ${s.desc}`, fg: C.
|
|
265
|
+
rows.push({ kind: 'item', text: ` ${key} ${s.desc}`, fg: C.value, bg: '' });
|
|
276
266
|
}
|
|
277
267
|
}
|
|
278
268
|
|
|
@@ -24,6 +24,7 @@ import {
|
|
|
24
24
|
isPanelSearchCommit,
|
|
25
25
|
isPanelSearchPrintable,
|
|
26
26
|
} from './search-focus.ts';
|
|
27
|
+
import { summarizeError } from '@pellux/goodvibes-sdk/platform/utils';
|
|
27
28
|
|
|
28
29
|
// ---------------------------------------------------------------------------
|
|
29
30
|
// Constants
|
|
@@ -342,7 +343,7 @@ export class FileExplorerPanel extends BasePanel {
|
|
|
342
343
|
this.cacheValid = true;
|
|
343
344
|
});
|
|
344
345
|
} catch (err) {
|
|
345
|
-
this.setError(
|
|
346
|
+
this.setError(summarizeError(err));
|
|
346
347
|
}
|
|
347
348
|
this.markDirty();
|
|
348
349
|
})();
|
|
@@ -13,6 +13,7 @@ import {
|
|
|
13
13
|
resolveScrollablePanelSection,
|
|
14
14
|
DEFAULT_PANEL_PALETTE,
|
|
15
15
|
} from './polish.ts';
|
|
16
|
+
import { summarizeError } from '@pellux/goodvibes-sdk/platform/utils';
|
|
16
17
|
|
|
17
18
|
// ─── Constants ────────────────────────────────────────────────────────────────
|
|
18
19
|
|
|
@@ -144,7 +145,7 @@ export class FilePreviewPanel extends BasePanel {
|
|
|
144
145
|
this.clampScroll(0);
|
|
145
146
|
});
|
|
146
147
|
} catch (err) {
|
|
147
|
-
this.setError(
|
|
148
|
+
this.setError(summarizeError(err));
|
|
148
149
|
}
|
|
149
150
|
this.markDirty();
|
|
150
151
|
}
|
package/src/panels/git-panel.ts
CHANGED
|
@@ -10,6 +10,7 @@ import {
|
|
|
10
10
|
resolveScrollablePanelSection,
|
|
11
11
|
buildStyledPanelLine,
|
|
12
12
|
DEFAULT_PANEL_PALETTE,
|
|
13
|
+
extendPalette,
|
|
13
14
|
} from './polish.ts';
|
|
14
15
|
|
|
15
16
|
// ---------------------------------------------------------------------------
|
|
@@ -56,25 +57,17 @@ const MIN_VISIBLE_DIFF_LINES = 5;
|
|
|
56
57
|
// Colors
|
|
57
58
|
// ---------------------------------------------------------------------------
|
|
58
59
|
|
|
59
|
-
const C = {
|
|
60
|
+
const C = extendPalette(DEFAULT_PANEL_PALETTE, {
|
|
60
61
|
branch: '#00d7ff',
|
|
61
|
-
clean: '#5fd700',
|
|
62
|
-
dirty: '#ffaf00',
|
|
63
|
-
ahead: '#5fd700',
|
|
64
|
-
behind: '#ff5f5f',
|
|
65
62
|
sectionHeader: '244',
|
|
66
|
-
staged: '#5fd700',
|
|
67
|
-
unstaged: '#ff5f5f',
|
|
68
63
|
commit: '250',
|
|
69
64
|
commitHash: '238',
|
|
70
65
|
commitAuthor: '244',
|
|
71
66
|
selected: '#1c1c1c',
|
|
72
67
|
selectedFg: '#ffffff',
|
|
73
|
-
diffAdd: '#5fd700',
|
|
74
|
-
diffRemove: '#ff5f5f',
|
|
75
68
|
diffMeta: '#5f87ff',
|
|
76
69
|
diffNeutral: '250',
|
|
77
|
-
}
|
|
70
|
+
});
|
|
78
71
|
|
|
79
72
|
// ---------------------------------------------------------------------------
|
|
80
73
|
// GitPanel
|
|
@@ -352,7 +345,7 @@ export class GitPanel extends BasePanel {
|
|
|
352
345
|
return this.renderMessage(width, height, 'Loading git status...', C.branch);
|
|
353
346
|
}
|
|
354
347
|
if (this.error) {
|
|
355
|
-
return this.renderMessage(width, height, `Git error: ${this.error}`, C.
|
|
348
|
+
return this.renderMessage(width, height, `Git error: ${this.error}`, C.bad);
|
|
356
349
|
}
|
|
357
350
|
// I3: spinner during openDiff() async fetch
|
|
358
351
|
if (this.loadingState === 'loading') {
|
|
@@ -398,15 +391,15 @@ export class GitPanel extends BasePanel {
|
|
|
398
391
|
x = this.paintText(line, this.data.branch, x, width, C.branch, { bold: true });
|
|
399
392
|
|
|
400
393
|
if (this.data.ahead > 0) {
|
|
401
|
-
x = this.paintText(line, ` +${this.data.ahead}`, x, width, C.
|
|
394
|
+
x = this.paintText(line, ` +${this.data.ahead}`, x, width, C.good);
|
|
402
395
|
}
|
|
403
396
|
if (this.data.behind > 0) {
|
|
404
|
-
x = this.paintText(line, ` -${this.data.behind}`, x, width, C.
|
|
397
|
+
x = this.paintText(line, ` -${this.data.behind}`, x, width, C.bad);
|
|
405
398
|
}
|
|
406
399
|
|
|
407
400
|
const isDirty = this.data.stagedFiles.length > 0 || this.data.unstagedFiles.length > 0;
|
|
408
401
|
const statusText = isDirty ? ' * dirty' : ' y clean';
|
|
409
|
-
const statusFg = isDirty ? C.
|
|
402
|
+
const statusFg = isDirty ? C.warn : C.good;
|
|
410
403
|
this.paintText(line, statusText, x, width, statusFg);
|
|
411
404
|
|
|
412
405
|
return line;
|
|
@@ -418,7 +411,7 @@ export class GitPanel extends BasePanel {
|
|
|
418
411
|
|
|
419
412
|
private renderFileRow(entry: GitFileEntry, selected: boolean, width: number): Line {
|
|
420
413
|
const line = createEmptyLine(width);
|
|
421
|
-
const fg = entry.staged ? C.
|
|
414
|
+
const fg = entry.staged ? C.good : C.bad;
|
|
422
415
|
const prefix = ' ';
|
|
423
416
|
const label = `${prefix}${entry.path}`;
|
|
424
417
|
|
|
@@ -602,9 +595,9 @@ export class GitPanel extends BasePanel {
|
|
|
602
595
|
const dLine = createEmptyLine(width);
|
|
603
596
|
let fg: string;
|
|
604
597
|
if (rawLine.startsWith('+') && !rawLine.startsWith('+++')) {
|
|
605
|
-
fg = C.
|
|
598
|
+
fg = C.good;
|
|
606
599
|
} else if (rawLine.startsWith('-') && !rawLine.startsWith('---')) {
|
|
607
|
-
fg = C.
|
|
600
|
+
fg = C.bad;
|
|
608
601
|
} else if (rawLine.startsWith('@@') || rawLine.startsWith('diff') || rawLine.startsWith('index')) {
|
|
609
602
|
fg = C.diffMeta;
|
|
610
603
|
} else {
|
|
@@ -18,6 +18,7 @@ import {
|
|
|
18
18
|
type EcosystemEntryKind,
|
|
19
19
|
} from '@/runtime/index.ts';
|
|
20
20
|
import type { UiMarketplaceSnapshot, UiReadModel } from '../runtime/ui-read-models.ts';
|
|
21
|
+
import { summarizeError } from '@pellux/goodvibes-sdk/platform/utils';
|
|
21
22
|
|
|
22
23
|
const C = {
|
|
23
24
|
...DEFAULT_PANEL_PALETTE,
|
|
@@ -114,7 +115,7 @@ export class MarketplacePanel extends ScrollableListPanel<MarketplaceRow> {
|
|
|
114
115
|
this.clearError();
|
|
115
116
|
} catch (e) {
|
|
116
117
|
// I2: surface catalog load failure
|
|
117
|
-
this.setError(`Catalog load failed: ${
|
|
118
|
+
this.setError(`Catalog load failed: ${summarizeError(e)}`);
|
|
118
119
|
}
|
|
119
120
|
}
|
|
120
121
|
|
|
@@ -28,6 +28,7 @@ import {
|
|
|
28
28
|
getPanelSearchFocusTransition,
|
|
29
29
|
isPanelSearchCancel,
|
|
30
30
|
} from './search-focus.ts';
|
|
31
|
+
import { summarizeError } from '@pellux/goodvibes-sdk/platform/utils';
|
|
31
32
|
|
|
32
33
|
// ---------------------------------------------------------------------------
|
|
33
34
|
// Colour palette
|
|
@@ -267,7 +268,7 @@ export class MemoryPanel extends SearchableListPanel<MemoryRecord> {
|
|
|
267
268
|
});
|
|
268
269
|
}
|
|
269
270
|
} catch (e) {
|
|
270
|
-
this.setError(`Review update failed: ${
|
|
271
|
+
this.setError(`Review update failed: ${summarizeError(e)}`);
|
|
271
272
|
}
|
|
272
273
|
}
|
|
273
274
|
this.refreshReviewRecords();
|
|
@@ -23,6 +23,7 @@ import {
|
|
|
23
23
|
resolveScrollablePanelSection,
|
|
24
24
|
type PanelWorkspaceSection,
|
|
25
25
|
} from './polish.ts';
|
|
26
|
+
import { summarizeError } from '@pellux/goodvibes-sdk/platform/utils';
|
|
26
27
|
|
|
27
28
|
const C = extendPalette(DEFAULT_PANEL_PALETTE, {
|
|
28
29
|
planning: '#38bdf8',
|
|
@@ -512,7 +513,7 @@ export class ProjectPlanningPanel extends BasePanel {
|
|
|
512
513
|
};
|
|
513
514
|
this.clearError();
|
|
514
515
|
} catch (err) {
|
|
515
|
-
this.setError(
|
|
516
|
+
this.setError(summarizeError(err));
|
|
516
517
|
} finally {
|
|
517
518
|
this.loading = false;
|
|
518
519
|
this.markDirty();
|
|
@@ -647,7 +648,7 @@ export class ProjectPlanningPanel extends BasePanel {
|
|
|
647
648
|
this.refresh(true);
|
|
648
649
|
this.registerTimer(setTimeout(() => this.refresh(true), 250));
|
|
649
650
|
} catch (err) {
|
|
650
|
-
this.setError(
|
|
651
|
+
this.setError(summarizeError(err));
|
|
651
652
|
this.requestRender();
|
|
652
653
|
}
|
|
653
654
|
})();
|
|
@@ -698,7 +699,7 @@ export class ProjectPlanningPanel extends BasePanel {
|
|
|
698
699
|
this.dismissPlanning?.();
|
|
699
700
|
this.refresh(true);
|
|
700
701
|
} catch (err) {
|
|
701
|
-
this.setError(
|
|
702
|
+
this.setError(summarizeError(err));
|
|
702
703
|
this.requestRender();
|
|
703
704
|
}
|
|
704
705
|
})();
|
|
@@ -741,7 +742,7 @@ export class ProjectPlanningPanel extends BasePanel {
|
|
|
741
742
|
});
|
|
742
743
|
this.refresh(true);
|
|
743
744
|
} catch (err) {
|
|
744
|
-
this.setError(
|
|
745
|
+
this.setError(summarizeError(err));
|
|
745
746
|
this.requestRender();
|
|
746
747
|
}
|
|
747
748
|
})();
|