@pellux/goodvibes-tui 0.27.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 +124 -0
- package/README.md +1 -1
- package/package.json +1 -1
- package/src/core/context-usage.ts +53 -0
- package/src/core/conversation.ts +4 -6
- package/src/core/session-recovery.ts +2 -0
- package/src/core/turn-event-wiring.ts +1 -0
- package/src/input/commands/cost-runtime.ts +49 -0
- package/src/input/commands/eval.ts +4 -3
- package/src/input/commands/operator-runtime.ts +5 -1
- package/src/input/commands.ts +2 -0
- package/src/input/handler-feed-routes.ts +60 -26
- package/src/input/handler-feed.ts +17 -8
- package/src/input/handler-picker-routes.ts +18 -13
- package/src/input/handler-shortcuts.ts +51 -0
- package/src/input/handler-ui-state.ts +4 -0
- package/src/input/handler.ts +43 -6
- package/src/input/keybindings.ts +53 -8
- package/src/input/model-picker.ts +5 -0
- package/src/input/panel-integration-actions.ts +117 -1
- package/src/main.ts +5 -2
- package/src/panels/agent-inspector-panel.ts +139 -45
- package/src/panels/agent-inspector-shared.ts +147 -3
- package/src/panels/approval-panel.ts +204 -102
- package/src/panels/automation-control-panel.ts +370 -103
- package/src/panels/base-panel.ts +26 -2
- 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 +253 -75
- package/src/panels/cockpit-read-model.ts +2 -1
- package/src/panels/communication-panel.ts +159 -56
- package/src/panels/confirm-state.ts +8 -1
- package/src/panels/control-plane-panel.ts +354 -95
- package/src/panels/cost-tracker-panel.ts +243 -57
- package/src/panels/debug-panel.ts +347 -159
- package/src/panels/diff-panel.ts +257 -82
- package/src/panels/docs-panel.ts +166 -64
- package/src/panels/eval-panel.ts +336 -109
- package/src/panels/expandable-list-panel.ts +189 -0
- package/src/panels/file-explorer-panel.ts +238 -159
- package/src/panels/file-preview-panel.ts +141 -59
- package/src/panels/git-panel.ts +360 -191
- package/src/panels/hooks-panel.ts +181 -19
- package/src/panels/incident-review-panel.ts +252 -43
- package/src/panels/index.ts +0 -4
- package/src/panels/intelligence-panel.ts +310 -103
- package/src/panels/knowledge-graph-panel.ts +480 -58
- package/src/panels/local-auth-panel.ts +251 -33
- package/src/panels/marketplace-panel.ts +219 -33
- package/src/panels/memory-panel.ts +83 -81
- package/src/panels/ops-control-panel.ts +211 -32
- package/src/panels/ops-strategy-panel.ts +131 -45
- package/src/panels/orchestration-panel.ts +259 -67
- package/src/panels/panel-list-panel.ts +184 -136
- package/src/panels/panel-manager.ts +120 -13
- package/src/panels/plan-dashboard-panel.ts +507 -74
- package/src/panels/plugins-panel.ts +227 -34
- package/src/panels/policy-panel.ts +264 -55
- package/src/panels/polish-core.ts +162 -0
- package/src/panels/polish-tables.ts +258 -0
- package/src/panels/polish.ts +67 -149
- package/src/panels/project-planning-answer-actions.ts +134 -0
- package/src/panels/project-planning-panel.ts +84 -113
- package/src/panels/provider-health-panel.ts +438 -480
- 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 +136 -38
- package/src/panels/remote-panel.ts +123 -38
- package/src/panels/routes-panel.ts +87 -24
- package/src/panels/sandbox-panel.ts +232 -65
- package/src/panels/scrollable-list-panel.ts +143 -145
- package/src/panels/security-panel.ts +204 -52
- package/src/panels/services-panel.ts +174 -76
- package/src/panels/session-browser-panel.ts +101 -6
- package/src/panels/session-maintenance.ts +4 -122
- package/src/panels/settings-sync-panel.ts +346 -68
- package/src/panels/skills-panel.ts +157 -89
- package/src/panels/subscription-panel.ts +105 -34
- package/src/panels/symbol-outline-panel.ts +287 -154
- package/src/panels/system-messages-panel.ts +172 -38
- package/src/panels/tasks-panel.ts +348 -134
- package/src/panels/thinking-panel.ts +66 -32
- package/src/panels/token-budget-panel.ts +233 -46
- package/src/panels/tool-inspector-panel.ts +170 -54
- package/src/panels/types.ts +65 -4
- package/src/panels/work-plan-panel.ts +393 -39
- package/src/panels/worktree-panel.ts +239 -61
- package/src/panels/wrfc-panel-format.ts +133 -0
- package/src/panels/wrfc-panel.ts +146 -150
- package/src/renderer/compaction-preview.ts +2 -1
- package/src/renderer/compositor.ts +46 -43
- 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 +30 -11
- package/src/renderer/model-workspace.ts +2 -3
- package/src/renderer/overlay-box.ts +16 -10
- package/src/renderer/panel-composite.ts +7 -20
- package/src/renderer/panel-workspace-bar.ts +14 -8
- package/src/renderer/process-indicator.ts +3 -1
- package/src/renderer/progress.ts +8 -6
- 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/tab-strip.ts +148 -34
- package/src/renderer/theme.ts +60 -3
- package/src/renderer/ui-factory.ts +45 -36
- 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/runtime/ui/model-picker/health-enrichment.ts +3 -0
- package/src/runtime/ui/model-picker/types.ts +4 -0
- package/src/shell/ui-openers.ts +14 -22
- package/src/utils/format-duration.ts +55 -0
- package/src/utils/format-number.ts +71 -0
- 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 -666
- package/src/panels/agent-logs-shared.ts +0 -129
- package/src/panels/context-visualizer-panel.ts +0 -214
- package/src/panels/forensics-panel.ts +0 -364
- package/src/panels/panel-picker.ts +0 -106
- package/src/panels/provider-account-snapshot.ts +0 -259
- package/src/panels/provider-accounts-panel.ts +0 -218
- package/src/panels/provider-stats-panel.ts +0 -366
- package/src/panels/schedule-panel.ts +0 -342
- package/src/panels/watchers-panel.ts +0 -193
- package/src/renderer/panel-picker-overlay.ts +0 -202
- package/src/renderer/panel-tab-bar.ts +0 -69
- package/src/runtime/diagnostics/panels/panel-resources.ts +0 -118
- package/src/runtime/diagnostics/panels/policy.ts +0 -177
|
@@ -7,15 +7,17 @@
|
|
|
7
7
|
*/
|
|
8
8
|
|
|
9
9
|
import { ScrollableListPanel } from './scrollable-list-panel.ts';
|
|
10
|
-
import type
|
|
10
|
+
import { createEmptyLine, type Line } from '../types/grid.ts';
|
|
11
11
|
import type { ComponentHealthMonitor } from '../runtime/perf/panel-health-monitor.ts';
|
|
12
12
|
import {
|
|
13
13
|
buildBodyText,
|
|
14
14
|
buildEmptyState,
|
|
15
15
|
buildGuidanceLine,
|
|
16
16
|
buildKeyValueLine,
|
|
17
|
+
buildKeyboardHints,
|
|
17
18
|
buildPanelListRow,
|
|
18
19
|
buildPanelLine,
|
|
20
|
+
buildStatusBadge,
|
|
19
21
|
buildSummaryBlock,
|
|
20
22
|
buildPanelWorkspace,
|
|
21
23
|
resolvePrimaryScrollableSection,
|
|
@@ -24,13 +26,24 @@ import {
|
|
|
24
26
|
type PanelPalette,
|
|
25
27
|
type PanelWorkspaceSection,
|
|
26
28
|
} from './polish.ts';
|
|
29
|
+
import { type ConfirmState, handleConfirmInput, renderConfirmLines } from './confirm-state.ts';
|
|
27
30
|
import { ConfigManager } from '@pellux/goodvibes-sdk/platform/config';
|
|
28
31
|
|
|
29
32
|
const MAX_MESSAGES = 500;
|
|
30
33
|
|
|
34
|
+
// UI message-routing targets (ui.systemMessages / ui.operationalMessages /
|
|
35
|
+
// ui.wrfcMessages) all share the same enum. Cycled in-panel by s/o/w and
|
|
36
|
+
// persisted via ConfigManager.set (WO-137).
|
|
37
|
+
type RouteTarget = 'panel' | 'conversation' | 'both';
|
|
38
|
+
const ROUTE_CYCLE: readonly RouteTarget[] = ['panel', 'conversation', 'both'];
|
|
39
|
+
function nextRoute(current: string): RouteTarget {
|
|
40
|
+
const idx = ROUTE_CYCLE.indexOf(current as RouteTarget);
|
|
41
|
+
return ROUTE_CYCLE[(idx + 1 + ROUTE_CYCLE.length) % ROUTE_CYCLE.length]!;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
// Domain accents only; the title band comes straight from
|
|
45
|
+
// DEFAULT_PANEL_PALETTE (WO-002).
|
|
31
46
|
const C = extendPalette(DEFAULT_PANEL_PALETTE, {
|
|
32
|
-
header: '#00ffff',
|
|
33
|
-
headerBg: '#0f172a',
|
|
34
47
|
high: '#fbbf24',
|
|
35
48
|
low: '#9ca3af',
|
|
36
49
|
ts: '#6b7280',
|
|
@@ -44,6 +57,10 @@ export interface SystemMessageEntry {
|
|
|
44
57
|
priority: SystemMessagePriority;
|
|
45
58
|
}
|
|
46
59
|
|
|
60
|
+
// One-key priority cycle (all -> high -> low -> all), applied on top of the
|
|
61
|
+
// existing text filter rather than replacing it.
|
|
62
|
+
const PRIORITY_CYCLE: ReadonlyArray<'' | SystemMessagePriority> = ['', 'high', 'low'];
|
|
63
|
+
|
|
47
64
|
function fmtTime(ts: number): string {
|
|
48
65
|
const d = new Date(ts);
|
|
49
66
|
const hh = String(d.getHours()).padStart(2, '0');
|
|
@@ -55,10 +72,27 @@ function fmtTime(ts: number): string {
|
|
|
55
72
|
export class SystemMessagesPanel extends ScrollableListPanel<SystemMessageEntry> {
|
|
56
73
|
private _messages: SystemMessageEntry[] = [];
|
|
57
74
|
private readonly configManager: ConfigManager;
|
|
75
|
+
/** '' = all priorities; set via the one-key priority cycle ('p'). */
|
|
76
|
+
private priorityFilter: '' | SystemMessagePriority = '';
|
|
77
|
+
/** c=clear backlog confirmation. */
|
|
78
|
+
private confirmClear: ConfirmState<'clear'> | null = null;
|
|
58
79
|
|
|
59
80
|
constructor(configManager: ConfigManager, componentHealthMonitor?: ComponentHealthMonitor) {
|
|
60
|
-
super('system-messages', 'System Messages', '
|
|
81
|
+
super('system-messages', 'System Messages', '▥', 'runtime-ops', componentHealthMonitor);
|
|
61
82
|
this.configManager = configManager;
|
|
83
|
+
this.filterEnabled = true;
|
|
84
|
+
this.filterLabel = 'Filter messages';
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
protected override filterMatches(entry: SystemMessageEntry, q: string): boolean {
|
|
88
|
+
return entry.text.toLowerCase().includes(q) || entry.priority.toLowerCase().includes(q);
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
/** Text filter (base class) combined with the priority cycle filter. */
|
|
92
|
+
protected override getVisibleItems(): readonly SystemMessageEntry[] {
|
|
93
|
+
const base = super.getVisibleItems();
|
|
94
|
+
if (!this.priorityFilter) return base;
|
|
95
|
+
return base.filter((entry) => entry.priority === this.priorityFilter);
|
|
62
96
|
}
|
|
63
97
|
|
|
64
98
|
// ---------------------------------------------------------------------------
|
|
@@ -79,7 +113,7 @@ export class SystemMessagesPanel extends ScrollableListPanel<SystemMessageEntry>
|
|
|
79
113
|
return buildPanelListRow(width, [
|
|
80
114
|
{ text: `${fmtTime(entry.ts)} `, fg: C.ts },
|
|
81
115
|
{
|
|
82
|
-
text: `${entry.priority === 'high' ? 'HIGH' : 'LOW
|
|
116
|
+
text: `${(entry.priority === 'high' ? 'HIGH' : 'LOW').padEnd(4)} `,
|
|
83
117
|
fg: entry.priority === 'high' ? C.high : C.low,
|
|
84
118
|
bold: entry.priority === 'high',
|
|
85
119
|
},
|
|
@@ -103,13 +137,21 @@ export class SystemMessagesPanel extends ScrollableListPanel<SystemMessageEntry>
|
|
|
103
137
|
// ---------------------------------------------------------------------------
|
|
104
138
|
|
|
105
139
|
push(text: string, priority: SystemMessagePriority): void {
|
|
140
|
+
// Follow-mode: only auto-jump to the new message when the selection was
|
|
141
|
+
// already at the tail of what's currently visible. Otherwise the user is
|
|
142
|
+
// reviewing history and a new low-priority message shouldn't yank the
|
|
143
|
+
// cursor out from under them.
|
|
144
|
+
const visibleBefore = this.getVisibleItems();
|
|
145
|
+
const wasAtTail = visibleBefore.length === 0 || this.selectedIndex >= visibleBefore.length - 1;
|
|
106
146
|
this._messages.push({ ts: Date.now(), text, priority });
|
|
107
147
|
if (this._messages.length > MAX_MESSAGES) {
|
|
108
148
|
this._messages.shift();
|
|
109
149
|
if (this.selectedIndex > 0) this.selectedIndex--;
|
|
110
150
|
}
|
|
111
|
-
|
|
112
|
-
|
|
151
|
+
if (wasAtTail) {
|
|
152
|
+
const visibleAfter = this.getVisibleItems();
|
|
153
|
+
this.selectedIndex = Math.max(0, visibleAfter.length - 1);
|
|
154
|
+
}
|
|
113
155
|
this.markDirty();
|
|
114
156
|
}
|
|
115
157
|
|
|
@@ -122,15 +164,96 @@ export class SystemMessagesPanel extends ScrollableListPanel<SystemMessageEntry>
|
|
|
122
164
|
}
|
|
123
165
|
|
|
124
166
|
// ---------------------------------------------------------------------------
|
|
125
|
-
// Input
|
|
167
|
+
// Input
|
|
126
168
|
// ---------------------------------------------------------------------------
|
|
127
169
|
|
|
170
|
+
override handleInput(key: string): boolean {
|
|
171
|
+
const confirmResult = handleConfirmInput(this.confirmClear, key);
|
|
172
|
+
if (confirmResult === 'confirmed') {
|
|
173
|
+
this.confirmClear = null;
|
|
174
|
+
this._messages = [];
|
|
175
|
+
this.selectedIndex = 0;
|
|
176
|
+
this.markDirty();
|
|
177
|
+
return true;
|
|
178
|
+
}
|
|
179
|
+
if (confirmResult === 'cancelled') {
|
|
180
|
+
this.confirmClear = null;
|
|
181
|
+
this.markDirty();
|
|
182
|
+
return true;
|
|
183
|
+
}
|
|
184
|
+
if (confirmResult === 'absorbed') return true;
|
|
185
|
+
|
|
186
|
+
if (!this.filterActive && key === 'p') {
|
|
187
|
+
const idx = PRIORITY_CYCLE.indexOf(this.priorityFilter);
|
|
188
|
+
this.priorityFilter = PRIORITY_CYCLE[(idx + 1) % PRIORITY_CYCLE.length]!;
|
|
189
|
+
this.selectedIndex = 0;
|
|
190
|
+
this.markDirty();
|
|
191
|
+
return true;
|
|
192
|
+
}
|
|
193
|
+
if (!this.filterActive && key === 's') {
|
|
194
|
+
const ui = this.configManager.getRaw().ui;
|
|
195
|
+
this.configManager.set('ui.systemMessages', nextRoute(ui.systemMessages));
|
|
196
|
+
this.markDirty();
|
|
197
|
+
return true;
|
|
198
|
+
}
|
|
199
|
+
if (!this.filterActive && key === 'o') {
|
|
200
|
+
const ui = this.configManager.getRaw().ui;
|
|
201
|
+
this.configManager.set('ui.operationalMessages', nextRoute(ui.operationalMessages));
|
|
202
|
+
this.markDirty();
|
|
203
|
+
return true;
|
|
204
|
+
}
|
|
205
|
+
if (!this.filterActive && key === 'w') {
|
|
206
|
+
const ui = this.configManager.getRaw().ui;
|
|
207
|
+
this.configManager.set('ui.wrfcMessages', nextRoute(ui.wrfcMessages));
|
|
208
|
+
this.markDirty();
|
|
209
|
+
return true;
|
|
210
|
+
}
|
|
211
|
+
if (!this.filterActive && key === 'c') {
|
|
212
|
+
if (this._messages.length === 0) return false;
|
|
213
|
+
this.confirmClear = { subject: 'clear', label: `${this._messages.length} system message(s)`, verb: 'Clear' };
|
|
214
|
+
this.markDirty();
|
|
215
|
+
return true;
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
return super.handleInput(key);
|
|
219
|
+
}
|
|
220
|
+
|
|
128
221
|
// ---------------------------------------------------------------------------
|
|
129
222
|
// Render — multi-section layout (posture + list + detail)
|
|
130
223
|
// ---------------------------------------------------------------------------
|
|
131
224
|
|
|
225
|
+
// Context-aware footer: navigation keys plus filter keys that reflect the
|
|
226
|
+
// current filter state (active typing / applied query / inactive).
|
|
227
|
+
private footerHints(): Array<{ keys: string; label: string }> {
|
|
228
|
+
const hints: Array<{ keys: string; label: string }> = [
|
|
229
|
+
{ keys: 'j/k', label: 'scroll' },
|
|
230
|
+
{ keys: 'g/G', label: 'jump' },
|
|
231
|
+
{ keys: 'p', label: 'priority' },
|
|
232
|
+
];
|
|
233
|
+
if (this.filterActive) {
|
|
234
|
+
hints.push({ keys: 'Esc', label: 'clear filter' });
|
|
235
|
+
} else if (this.filterQuery) {
|
|
236
|
+
hints.push({ keys: '/', label: 'edit filter' }, { keys: 'Esc', label: 'clear filter' });
|
|
237
|
+
} else {
|
|
238
|
+
hints.push({ keys: '/', label: 'filter' });
|
|
239
|
+
if (this._messages.length > 0) hints.push({ keys: 'c', label: 'clear' });
|
|
240
|
+
}
|
|
241
|
+
return hints;
|
|
242
|
+
}
|
|
243
|
+
|
|
132
244
|
override render(width: number, height: number): Line[] {
|
|
133
245
|
return this.trackedRender(() => {
|
|
246
|
+
if (this.confirmClear) {
|
|
247
|
+
this.needsRender = false;
|
|
248
|
+
const lines = buildPanelWorkspace(width, height, {
|
|
249
|
+
title: 'System Messages',
|
|
250
|
+
sections: [{ title: 'Confirmation', lines: renderConfirmLines(width, this.confirmClear) }],
|
|
251
|
+
palette: C,
|
|
252
|
+
});
|
|
253
|
+
while (lines.length < height) lines.push(createEmptyLine(width));
|
|
254
|
+
return lines.slice(0, height);
|
|
255
|
+
}
|
|
256
|
+
|
|
134
257
|
const intro = 'Operational system traffic routed out of the main conversation to reduce noise and keep runtime status reviewable.';
|
|
135
258
|
|
|
136
259
|
if (this._messages.length === 0) {
|
|
@@ -151,7 +274,7 @@ export class SystemMessagesPanel extends ScrollableListPanel<SystemMessageEntry>
|
|
|
151
274
|
),
|
|
152
275
|
}],
|
|
153
276
|
footerLines: [
|
|
154
|
-
buildPanelLine(width, [['
|
|
277
|
+
buildPanelLine(width, [[' Low-priority system traffic lands here by default. Routing is configurable via /settings.', C.dim]]),
|
|
155
278
|
],
|
|
156
279
|
palette: C,
|
|
157
280
|
});
|
|
@@ -162,42 +285,54 @@ export class SystemMessagesPanel extends ScrollableListPanel<SystemMessageEntry>
|
|
|
162
285
|
const lowCount = this._messages.length - highCount;
|
|
163
286
|
this.selectedIndex = Math.min(this.selectedIndex, this._messages.length - 1);
|
|
164
287
|
const ui = this.configManager.getRaw().ui;
|
|
288
|
+
const latest = this._messages[this._messages.length - 1];
|
|
165
289
|
const postureLines = [
|
|
290
|
+
// Severity + recency first: high-priority count leads, newest message age follows.
|
|
291
|
+
buildPanelLine(width, [
|
|
292
|
+
[' ', C.label],
|
|
293
|
+
...buildStatusBadge(highCount > 0 ? 'failed' : 'completed', 'high', { count: highCount }),
|
|
294
|
+
[' ', C.dim],
|
|
295
|
+
...buildStatusBadge('review', 'low', { count: lowCount }),
|
|
296
|
+
...(latest ? ([[' newest ', C.label], [`${fmtTime(latest.ts)}`, C.value]] as Array<[string, string]>) : []),
|
|
297
|
+
]),
|
|
166
298
|
buildKeyValueLine(width, [
|
|
167
|
-
{ label: '
|
|
168
|
-
{ label: '
|
|
169
|
-
{ label: '
|
|
170
|
-
], C),
|
|
171
|
-
buildKeyValueLine(width, [
|
|
172
|
-
{ label: 'system route', value: ui.systemMessages, valueColor: C.info },
|
|
173
|
-
{ label: 'ops route', value: ui.operationalMessages, valueColor: C.info },
|
|
174
|
-
{ label: 'wrfc route', value: ui.wrfcMessages, valueColor: C.info },
|
|
299
|
+
{ label: 'system route (s)', value: ui.systemMessages, valueColor: C.info },
|
|
300
|
+
{ label: 'ops route (o)', value: ui.operationalMessages, valueColor: C.info },
|
|
301
|
+
{ label: 'wrfc route (w)', value: ui.wrfcMessages, valueColor: C.info },
|
|
175
302
|
], C),
|
|
176
|
-
buildGuidanceLine(width, '/settings', '
|
|
303
|
+
buildGuidanceLine(width, '/settings', 'review the full settings surface (routing is also toggleable in-panel with s/o/w)', C),
|
|
177
304
|
];
|
|
178
305
|
|
|
179
|
-
const
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
)
|
|
306
|
+
const visible = this.getVisibleItems();
|
|
307
|
+
this.selectedIndex = Math.max(0, Math.min(this.selectedIndex, visible.length - 1));
|
|
308
|
+
const selected = this.getSelectedItem();
|
|
309
|
+
const noMatchReason = this.filterQuery.trim()
|
|
310
|
+
? `"${this.filterQuery.trim()}"${this.priorityFilter ? ` + priority:${this.priorityFilter}` : ''}`
|
|
311
|
+
: `priority:${this.priorityFilter}`;
|
|
312
|
+
const messageRows: Line[] = visible.length > 0
|
|
313
|
+
? visible.map((entry, index) => this.renderItem(entry, index, index === this.selectedIndex, width))
|
|
314
|
+
: [buildPanelLine(width, [[` No messages match ${noMatchReason} (Esc to clear filter, p to reset priority)`, C.dim]])];
|
|
183
315
|
|
|
316
|
+
const filterSection: PanelWorkspaceSection = { lines: [this.buildFilterLine(width)] };
|
|
184
317
|
const postureSection: PanelWorkspaceSection = { lines: buildSummaryBlock(width, 'System posture', postureLines, C) };
|
|
185
|
-
const detailSection: PanelWorkspaceSection =
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
318
|
+
const detailSection: PanelWorkspaceSection = selected
|
|
319
|
+
? {
|
|
320
|
+
title: 'Selected Message',
|
|
321
|
+
lines: [
|
|
322
|
+
buildPanelLine(width, [
|
|
323
|
+
[' Time ', C.label],
|
|
324
|
+
[fmtTime(selected.ts), C.value],
|
|
325
|
+
[' Priority ', C.label],
|
|
326
|
+
[selected.priority, selected.priority === 'high' ? C.high : C.low],
|
|
327
|
+
]),
|
|
328
|
+
...buildBodyText(width, selected.text, C, C.value),
|
|
329
|
+
],
|
|
330
|
+
}
|
|
331
|
+
: { title: 'Selected Message', lines: [] };
|
|
197
332
|
const messagesSection = resolvePrimaryScrollableSection(width, height, {
|
|
198
333
|
intro,
|
|
199
334
|
palette: C,
|
|
200
|
-
beforeSections: [postureSection],
|
|
335
|
+
beforeSections: [filterSection, postureSection],
|
|
201
336
|
section: {
|
|
202
337
|
title: 'Timeline',
|
|
203
338
|
scrollableLines: messageRows,
|
|
@@ -210,6 +345,7 @@ export class SystemMessagesPanel extends ScrollableListPanel<SystemMessageEntry>
|
|
|
210
345
|
});
|
|
211
346
|
this.scrollStart = messagesSection.scrollOffset;
|
|
212
347
|
const sections: PanelWorkspaceSection[] = [
|
|
348
|
+
filterSection,
|
|
213
349
|
postureSection,
|
|
214
350
|
messagesSection.section,
|
|
215
351
|
detailSection,
|
|
@@ -219,9 +355,7 @@ export class SystemMessagesPanel extends ScrollableListPanel<SystemMessageEntry>
|
|
|
219
355
|
title: 'System Messages',
|
|
220
356
|
intro,
|
|
221
357
|
sections,
|
|
222
|
-
footerLines: [
|
|
223
|
-
buildPanelLine(width, [[' j/k or Up/Down scroll PgUp/PgDn page g/G jump', C.dim]]),
|
|
224
|
-
],
|
|
358
|
+
footerLines: [buildKeyboardHints(width, this.footerHints(), C)],
|
|
225
359
|
palette: C,
|
|
226
360
|
});
|
|
227
361
|
return lines;
|