@pellux/goodvibes-tui 0.18.12 → 0.18.17
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 +172 -0
- package/README.md +1 -1
- package/docs/foundation-artifacts/operator-contract.json +1 -1
- package/package.json +3 -2
- package/src/config/index.ts +1 -138
- package/src/core/conversation-rendering.ts +3 -3
- package/src/core/conversation.ts +176 -423
- package/src/core/history.ts +45 -0
- package/src/core/orchestrator.ts +3 -735
- package/src/core/system-message-router.ts +19 -58
- package/src/daemon/cli.ts +82 -6
- package/src/input/command-registry.ts +2 -0
- package/src/input/commands/control-room-runtime.ts +1 -1
- package/src/input/commands/health-runtime.ts +1 -1
- package/src/input/commands/local-setup-review.ts +1 -1
- package/src/input/commands/platform-access-runtime.ts +1 -1
- package/src/input/commands/qrcode-runtime.ts +20 -0
- package/src/input/commands/subscription-runtime.ts +1 -1
- package/src/input/commands.ts +2 -0
- package/src/input/handler-content-actions.ts +2 -2
- package/src/input/handler-feed.ts +7 -1
- package/src/input/handler-modal-routes.ts +19 -2
- package/src/input/handler-modal-token-routes.ts +4 -1
- package/src/input/handler-picker-routes.ts +4 -2
- package/src/input/handler-ui-state.ts +1 -1
- package/src/input/handler.ts +1 -1
- package/src/input/model-picker.ts +11 -0
- package/src/input/search.ts +1 -1
- package/src/input/selection.ts +2 -2
- package/src/input/settings-modal.ts +31 -3
- package/src/main.ts +1 -1
- package/src/panels/agent-inspector-panel.ts +3 -3
- package/src/panels/agent-logs-panel.ts +26 -27
- package/src/panels/approval-panel.ts +2 -2
- package/src/panels/automation-control-panel.ts +3 -3
- package/src/panels/base-panel.ts +14 -14
- package/src/panels/builtin/operations.ts +1 -1
- package/src/panels/builtin/session.ts +67 -1
- package/src/panels/builtin/shared.ts +4 -4
- package/src/panels/cockpit-panel.ts +2 -2
- package/src/panels/communication-panel.ts +3 -3
- package/src/panels/context-visualizer-panel.ts +2 -2
- package/src/panels/control-plane-panel.ts +3 -3
- package/src/panels/cost-tracker-panel.ts +3 -3
- package/src/panels/debug-panel.ts +2 -2
- package/src/panels/diff-panel.ts +2 -2
- package/src/panels/docs-panel.ts +1 -1
- package/src/panels/eval-panel.ts +2 -2
- package/src/panels/file-explorer-panel.ts +3 -3
- package/src/panels/file-preview-panel.ts +3 -3
- package/src/panels/forensics-panel.ts +2 -2
- package/src/panels/git-panel.ts +1 -1
- package/src/panels/hooks-panel.ts +3 -3
- package/src/panels/incident-review-panel.ts +1 -1
- package/src/panels/intelligence-panel.ts +2 -2
- package/src/panels/knowledge-panel.ts +1 -1
- package/src/panels/local-auth-panel.ts +2 -2
- package/src/panels/marketplace-panel.ts +1 -1
- package/src/panels/mcp-panel.ts +3 -3
- package/src/panels/memory-panel.ts +1 -1
- package/src/panels/ops-control-panel.ts +3 -3
- package/src/panels/ops-strategy-panel.ts +2 -2
- package/src/panels/orchestration-panel.ts +2 -2
- package/src/panels/panel-list-panel.ts +6 -6
- package/src/panels/plan-dashboard-panel.ts +1 -1
- package/src/panels/plugins-panel.ts +2 -2
- package/src/panels/policy-panel.ts +2 -2
- package/src/panels/polish.ts +3 -3
- package/src/panels/provider-account-snapshot.ts +1 -1
- package/src/panels/provider-accounts-panel.ts +25 -29
- package/src/panels/provider-health-panel.ts +2 -2
- package/src/panels/provider-stats-panel.ts +3 -3
- package/src/panels/qr-panel.ts +182 -0
- package/src/panels/remote-panel.ts +3 -3
- package/src/panels/routes-panel.ts +3 -3
- package/src/panels/sandbox-panel.ts +2 -2
- package/src/panels/schedule-panel.ts +1 -1
- package/src/panels/scrollable-list-panel.ts +407 -0
- package/src/panels/security-panel.ts +2 -2
- package/src/panels/services-panel.ts +3 -3
- package/src/panels/session-browser-panel.ts +2 -2
- package/src/panels/settings-sync-panel.ts +2 -2
- package/src/panels/skills-panel.ts +6 -6
- package/src/panels/subscription-panel.ts +3 -3
- package/src/panels/symbol-outline-panel.ts +3 -3
- package/src/panels/system-messages-panel.ts +4 -4
- package/src/panels/tasks-panel.ts +2 -2
- package/src/panels/thinking-panel.ts +3 -3
- package/src/panels/token-budget-panel.ts +1 -1
- package/src/panels/tool-inspector-panel.ts +3 -3
- package/src/panels/types.ts +5 -5
- package/src/panels/watchers-panel.ts +3 -3
- package/src/panels/welcome-panel.ts +1 -1
- package/src/panels/worktree-panel.ts +22 -21
- package/src/panels/wrfc-panel.ts +3 -3
- package/src/permissions/prompt.ts +3 -22
- package/src/plugins/loader.ts +15 -304
- package/src/renderer/agent-detail-modal.ts +1 -1
- package/src/renderer/autocomplete-overlay.ts +2 -2
- package/src/renderer/bookmark-modal.ts +1 -1
- package/src/renderer/bottom-bar.ts +2 -2
- package/src/renderer/buffer.ts +1 -1
- package/src/renderer/code-block.ts +2 -2
- package/src/renderer/compositor.ts +2 -2
- package/src/renderer/context-inspector.ts +1 -1
- package/src/renderer/conversation-layout.ts +2 -2
- package/src/renderer/conversation-overlays.ts +1 -1
- package/src/renderer/conversation-surface.ts +2 -2
- package/src/renderer/diff-view.ts +2 -2
- package/src/renderer/diff.ts +1 -1
- package/src/renderer/file-picker-overlay.ts +2 -2
- package/src/renderer/file-tree.ts +2 -2
- package/src/renderer/help-overlay.ts +1 -1
- package/src/renderer/history-search-overlay.ts +2 -2
- package/src/renderer/live-tail-modal.ts +1 -1
- package/src/renderer/markdown.ts +2 -2
- package/src/renderer/modal-factory.ts +3 -3
- package/src/renderer/model-picker-overlay.ts +2 -2
- package/src/renderer/overlay-box.ts +2 -2
- package/src/renderer/panel-composite.ts +1 -1
- package/src/renderer/panel-picker-overlay.ts +2 -2
- package/src/renderer/panel-tab-bar.ts +1 -1
- package/src/renderer/panel-workspace-bar.ts +1 -1
- package/src/renderer/process-indicator.ts +2 -2
- package/src/renderer/process-modal.ts +1 -1
- package/src/renderer/profile-picker-modal.ts +2 -2
- package/src/renderer/progress.ts +2 -2
- package/src/renderer/qr-renderer.ts +117 -0
- package/src/renderer/search-overlay.ts +2 -2
- package/src/renderer/selection-modal-overlay.ts +2 -2
- package/src/renderer/session-picker-modal.ts +2 -2
- package/src/renderer/settings-modal-helpers.ts +122 -0
- package/src/renderer/settings-modal.ts +149 -113
- package/src/renderer/shell-surface.ts +1 -1
- package/src/renderer/system-message.ts +1 -1
- package/src/renderer/tab-strip.ts +2 -2
- package/src/renderer/text-layout.ts +1 -1
- package/src/renderer/thinking.ts +1 -1
- package/src/renderer/tool-call.ts +2 -2
- package/src/renderer/ui-factory.ts +2 -2
- package/src/runtime/bootstrap-command-context.ts +5 -6
- package/src/runtime/bootstrap-command-parts.ts +32 -18
- package/src/runtime/bootstrap-core.ts +3 -2
- package/src/runtime/bootstrap-hook-bridge.ts +15 -174
- package/src/runtime/bootstrap-shell.ts +4 -4
- package/src/runtime/bootstrap.ts +7 -2
- package/src/runtime/context.ts +4 -20
- package/src/runtime/diagnostics/panels/index.ts +6 -6
- package/src/runtime/diagnostics/panels/ops.ts +1 -1
- package/src/runtime/diagnostics/panels/panel-resources.ts +118 -0
- package/src/runtime/perf/panel-contracts.ts +32 -0
- package/src/runtime/perf/panel-health-monitor.ts +18 -0
- package/src/runtime/services.ts +5 -5
- package/src/runtime/store/domains/domain-read-matrix.ts +0 -2
- package/src/runtime/store/selectors/index.ts +11 -6
- package/src/runtime/store/state.ts +12 -4
- package/src/runtime/ui-events.ts +1 -0
- package/src/runtime/ui-read-model-helpers.ts +1 -32
- package/src/runtime/ui-read-models-observability-maintenance.ts +1 -81
- package/src/runtime/ui-read-models-observability-options.ts +1 -5
- package/src/runtime/ui-read-models-observability-remote.ts +1 -73
- package/src/runtime/ui-read-models-observability-security.ts +1 -172
- package/src/runtime/ui-read-models-observability-system.ts +1 -217
- package/src/runtime/ui-read-models-observability.ts +1 -59
- package/src/runtime/ui-service-queries.ts +1 -114
- package/src/runtime/ui-services.ts +1 -1
- package/src/shell/ui-openers.ts +1 -1
- package/src/tools/index.ts +1 -186
- package/src/types/grid.ts +48 -0
- package/src/utils/clipboard.ts +21 -0
- package/src/utils/splash-lines.ts +1 -1
- package/src/utils/terminal-width.ts +185 -0
- package/src/version.ts +1 -1
- package/src/config/service-registry.ts +0 -1
- package/src/config/subscription-providers.ts +0 -127
- package/src/daemon/facade-composition.ts +0 -398
- package/src/daemon/facade.ts +0 -638
- package/src/daemon/surface-policy.ts +0 -60
- package/src/daemon/types.ts +0 -191
- package/src/runtime/diagnostics/actions.ts +0 -776
- package/src/runtime/diagnostics/index.ts +0 -99
- package/src/runtime/diagnostics/panels/agents.ts +0 -252
- package/src/runtime/diagnostics/panels/events.ts +0 -188
- package/src/runtime/diagnostics/panels/health.ts +0 -242
- package/src/runtime/diagnostics/panels/tasks.ts +0 -251
- package/src/runtime/diagnostics/panels/tool-calls.ts +0 -267
- package/src/runtime/diagnostics/provider.ts +0 -262
- package/src/runtime/store/domains/conversation.ts +0 -181
- package/src/runtime/store/domains/permissions.ts +0 -143
- package/src/runtime/store/helpers/reducers/conversation.ts +0 -228
- package/src/runtime/store/helpers/reducers/lifecycle.ts +0 -440
- package/src/runtime/store/helpers/reducers/shared.ts +0 -60
- package/src/runtime/store/helpers/reducers/sync.ts +0 -555
- package/src/runtime/store/helpers/reducers.ts +0 -30
- package/src/runtime/ui-read-models-core.ts +0 -95
- package/src/runtime/ui-read-models-operations.ts +0 -203
|
@@ -5,8 +5,8 @@
|
|
|
5
5
|
|
|
6
6
|
import { join } from 'node:path';
|
|
7
7
|
import { readFile } from 'node:fs/promises';
|
|
8
|
-
import type { Line } from '
|
|
9
|
-
import { createEmptyLine } from '
|
|
8
|
+
import type { Line } from '../types/grid.ts';
|
|
9
|
+
import { createEmptyLine } from '../types/grid.ts';
|
|
10
10
|
import { BasePanel } from './base-panel.ts';
|
|
11
11
|
import type { AgentManager, AgentRecord } from '@pellux/goodvibes-sdk/platform/tools/agent/index';
|
|
12
12
|
import type { AgentMessageBus } from '@pellux/goodvibes-sdk/platform/agents/message-bus';
|
|
@@ -21,7 +21,7 @@ import {
|
|
|
21
21
|
resolveScrollablePanelSection,
|
|
22
22
|
DEFAULT_PANEL_PALETTE,
|
|
23
23
|
} from './polish.ts';
|
|
24
|
-
import { truncateDisplay } from '
|
|
24
|
+
import { truncateDisplay } from '../utils/terminal-width.ts';
|
|
25
25
|
import { summarizeError } from '@pellux/goodvibes-sdk/platform/utils/error-display';
|
|
26
26
|
import {
|
|
27
27
|
type AgentDisplayRow as DisplayRow,
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import { readFileSync, existsSync, watch, type FSWatcher } from 'fs';
|
|
2
|
-
import type { Line } from '
|
|
3
|
-
import { createEmptyLine, createStyledCell } from '
|
|
4
|
-
import {
|
|
2
|
+
import type { Line } from '../types/grid.ts';
|
|
3
|
+
import { createEmptyLine, createStyledCell } from '../types/grid.ts';
|
|
4
|
+
import { ScrollableListPanel } from './scrollable-list-panel.ts';
|
|
5
5
|
import type { AgentManager, AgentRecord } from '@pellux/goodvibes-sdk/platform/tools/agent/index';
|
|
6
6
|
import type { AgentEvent } from '@pellux/goodvibes-sdk/platform/runtime/events/index';
|
|
7
|
-
import type { UiEventFeed } from '
|
|
7
|
+
import type { UiEventFeed } from '../runtime/ui-events.ts';
|
|
8
8
|
import {
|
|
9
9
|
buildEmptyState,
|
|
10
10
|
buildPanelLine,
|
|
@@ -38,7 +38,7 @@ export interface AgentLogsPanelDeps {
|
|
|
38
38
|
// AgentLogsPanel
|
|
39
39
|
// ---------------------------------------------------------------------------
|
|
40
40
|
|
|
41
|
-
export class AgentLogsPanel extends
|
|
41
|
+
export class AgentLogsPanel extends ScrollableListPanel<LogEntry> {
|
|
42
42
|
// ── Agent state ─────────────────────────────────────────────────────────
|
|
43
43
|
private agents: AgentRecord[] = [];
|
|
44
44
|
private selectedAgentIndex = 0;
|
|
@@ -47,7 +47,6 @@ export class AgentLogsPanel extends BasePanel {
|
|
|
47
47
|
private allEntries: LogEntry[] = []; // raw parsed JSONL for selected agent
|
|
48
48
|
private filteredEntries: LogEntry[] = []; // after filter applied
|
|
49
49
|
private lastFileSize = 0;
|
|
50
|
-
private scrollOffset = 0;
|
|
51
50
|
|
|
52
51
|
// ── Modes ────────────────────────────────────────────────────────────────
|
|
53
52
|
private autoFollow = true;
|
|
@@ -68,6 +67,16 @@ export class AgentLogsPanel extends BasePanel {
|
|
|
68
67
|
this._subscribeEvents();
|
|
69
68
|
}
|
|
70
69
|
|
|
70
|
+
// ── ScrollableListPanel<LogEntry> contract ────────────────────────────────
|
|
71
|
+
|
|
72
|
+
protected getItems(): readonly LogEntry[] {
|
|
73
|
+
return this.filteredEntries;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
protected renderItem(entry: LogEntry, _index: number, _selected: boolean, width: number): Line {
|
|
77
|
+
return this._renderEntry(entry, width);
|
|
78
|
+
}
|
|
79
|
+
|
|
71
80
|
// ── Lifecycle ─────────────────────────────────────────────────────────────
|
|
72
81
|
|
|
73
82
|
override onActivate(): void {
|
|
@@ -100,7 +109,7 @@ export class AgentLogsPanel extends BasePanel {
|
|
|
100
109
|
this._cycleFilter();
|
|
101
110
|
return true;
|
|
102
111
|
case 'g': // g — jump to top
|
|
103
|
-
this.
|
|
112
|
+
this.selectedIndex = 0;
|
|
104
113
|
this.autoFollow = false;
|
|
105
114
|
this.markDirty();
|
|
106
115
|
return true;
|
|
@@ -109,19 +118,8 @@ export class AgentLogsPanel extends BasePanel {
|
|
|
109
118
|
this._clampScroll();
|
|
110
119
|
this.markDirty();
|
|
111
120
|
return true;
|
|
112
|
-
case 'k': // k / up
|
|
113
|
-
case '\x1b[A':
|
|
114
|
-
this.autoFollow = false;
|
|
115
|
-
this.scrollOffset = Math.max(0, this.scrollOffset - 1);
|
|
116
|
-
this.markDirty();
|
|
117
|
-
return true;
|
|
118
|
-
case 'j': // j / down
|
|
119
|
-
case '\x1b[B':
|
|
120
|
-
this.scrollOffset++;
|
|
121
|
-
this.markDirty();
|
|
122
|
-
return true;
|
|
123
121
|
default:
|
|
124
|
-
return
|
|
122
|
+
return super.handleInput(key);
|
|
125
123
|
}
|
|
126
124
|
}
|
|
127
125
|
|
|
@@ -205,7 +203,7 @@ export class AgentLogsPanel extends BasePanel {
|
|
|
205
203
|
|
|
206
204
|
const focusIndex = this.autoFollow
|
|
207
205
|
? Math.max(0, this.filteredEntries.length - 1)
|
|
208
|
-
: Math.min(this.
|
|
206
|
+
: Math.min(this.selectedIndex, Math.max(0, this.filteredEntries.length - 1));
|
|
209
207
|
const summarySection = { title: 'Summary', lines: summaryLines } as const;
|
|
210
208
|
const agentsSection = { title: 'Agents', lines: [selectorLine] } as const;
|
|
211
209
|
const logStreamSection = resolveScrollablePanelSection(width, height, {
|
|
@@ -217,11 +215,11 @@ export class AgentLogsPanel extends BasePanel {
|
|
|
217
215
|
title: 'Log Stream',
|
|
218
216
|
scrollableLines: this.filteredEntries.map((entry) => this._renderEntry(entry, width)),
|
|
219
217
|
selectedIndex: focusIndex,
|
|
220
|
-
scrollOffset: this.
|
|
218
|
+
scrollOffset: this.scrollStart,
|
|
221
219
|
minRows: 8,
|
|
222
220
|
},
|
|
223
221
|
});
|
|
224
|
-
this.
|
|
222
|
+
this.scrollStart = logStreamSection.scrollOffset;
|
|
225
223
|
|
|
226
224
|
return buildPanelWorkspace(width, height, {
|
|
227
225
|
title: ' Agents',
|
|
@@ -273,7 +271,7 @@ export class AgentLogsPanel extends BasePanel {
|
|
|
273
271
|
this.allEntries = parseAgentJsonl(content);
|
|
274
272
|
this._applyFilter();
|
|
275
273
|
if (this.autoFollow) {
|
|
276
|
-
this.
|
|
274
|
+
this.selectedIndex = Math.max(0, this.filteredEntries.length - 1);
|
|
277
275
|
}
|
|
278
276
|
this.markDirty();
|
|
279
277
|
} catch {
|
|
@@ -373,7 +371,8 @@ export class AgentLogsPanel extends BasePanel {
|
|
|
373
371
|
this.allEntries = [];
|
|
374
372
|
this.filteredEntries = [];
|
|
375
373
|
this.lastFileSize = 0;
|
|
376
|
-
this.
|
|
374
|
+
this.selectedIndex = 0;
|
|
375
|
+
this.scrollStart = 0;
|
|
377
376
|
this.autoFollow = true;
|
|
378
377
|
const agent = this._selectedAgent();
|
|
379
378
|
if (agent) {
|
|
@@ -406,7 +405,7 @@ export class AgentLogsPanel extends BasePanel {
|
|
|
406
405
|
this.allEntries = parseAgentJsonl(content);
|
|
407
406
|
this._applyFilter();
|
|
408
407
|
if (this.autoFollow) {
|
|
409
|
-
this.
|
|
408
|
+
this.selectedIndex = Math.max(0, this.filteredEntries.length - 1);
|
|
410
409
|
}
|
|
411
410
|
} catch {
|
|
412
411
|
this.allEntries = [];
|
|
@@ -438,7 +437,7 @@ export class AgentLogsPanel extends BasePanel {
|
|
|
438
437
|
this.filter = FILTER_CYCLE[(idx + 1) % FILTER_CYCLE.length]!;
|
|
439
438
|
this._applyFilter();
|
|
440
439
|
if (this.autoFollow) {
|
|
441
|
-
this.
|
|
440
|
+
this.selectedIndex = Math.max(0, this.filteredEntries.length - 1);
|
|
442
441
|
}
|
|
443
442
|
this.markDirty();
|
|
444
443
|
}
|
|
@@ -449,7 +448,7 @@ export class AgentLogsPanel extends BasePanel {
|
|
|
449
448
|
}
|
|
450
449
|
|
|
451
450
|
private _clampScroll(): void {
|
|
452
|
-
this.
|
|
451
|
+
this.selectedIndex = Math.min(this.selectedIndex, Math.max(0, this.filteredEntries.length - 1));
|
|
453
452
|
}
|
|
454
453
|
|
|
455
454
|
// ── Private: rendering helpers ─────────────────────────────────────────────
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import type { Line } from '
|
|
2
|
-
import { createEmptyLine } from '
|
|
1
|
+
import type { Line } from '../types/grid.ts';
|
|
2
|
+
import { createEmptyLine } from '../types/grid.ts';
|
|
3
3
|
import { BasePanel } from './base-panel.ts';
|
|
4
4
|
import {
|
|
5
5
|
buildGuidanceLine,
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import type { Line } from '
|
|
2
|
-
import { createEmptyLine } from '
|
|
1
|
+
import type { Line } from '../types/grid.ts';
|
|
2
|
+
import { createEmptyLine } from '../types/grid.ts';
|
|
3
3
|
import { BasePanel } from './base-panel.ts';
|
|
4
4
|
import type { UiAutomationSnapshot, UiReadModel } from '../runtime/ui-read-models.ts';
|
|
5
|
-
import { truncateDisplay } from '
|
|
5
|
+
import { truncateDisplay } from '../utils/terminal-width.ts';
|
|
6
6
|
import {
|
|
7
7
|
buildEmptyState,
|
|
8
8
|
buildGuidanceLine,
|
package/src/panels/base-panel.ts
CHANGED
|
@@ -1,27 +1,27 @@
|
|
|
1
|
-
import type { Line } from '
|
|
1
|
+
import type { Line } from '../types/grid.ts';
|
|
2
2
|
import type { Panel, PanelCategory } from './types.ts';
|
|
3
|
-
import type {
|
|
4
|
-
import type {
|
|
3
|
+
import type { ComponentResourceContract, ComponentHealthState } from '../runtime/perf/panel-contracts.ts';
|
|
4
|
+
import type { ComponentHealthMonitor } from '../runtime/perf/panel-health-monitor.ts';
|
|
5
5
|
|
|
6
6
|
export abstract class BasePanel implements Panel {
|
|
7
7
|
public needsRender = true;
|
|
8
8
|
public isTransient = false;
|
|
9
9
|
public isPinned = false;
|
|
10
|
-
protected readonly
|
|
10
|
+
protected readonly componentHealthMonitor?: ComponentHealthMonitor;
|
|
11
11
|
|
|
12
12
|
/**
|
|
13
13
|
* Optional resource contract for this panel.
|
|
14
14
|
* Override in subclasses to declare a custom contract; leave undefined
|
|
15
|
-
* to use the category default enforced by
|
|
15
|
+
* to use the category default enforced by ComponentHealthMonitor.
|
|
16
16
|
*/
|
|
17
|
-
public resourceContract: Readonly<
|
|
17
|
+
public resourceContract: Readonly<ComponentResourceContract> | undefined = undefined;
|
|
18
18
|
|
|
19
19
|
/**
|
|
20
|
-
* Live health state populated by
|
|
20
|
+
* Live health state populated by ComponentHealthMonitor.
|
|
21
21
|
* Read-only from outside the monitor.
|
|
22
22
|
*/
|
|
23
|
-
public get healthState(): Readonly<
|
|
24
|
-
return this.
|
|
23
|
+
public get healthState(): Readonly<ComponentHealthState> | undefined {
|
|
24
|
+
return this.componentHealthMonitor?.getHealth(this.id);
|
|
25
25
|
}
|
|
26
26
|
|
|
27
27
|
constructor(
|
|
@@ -29,9 +29,9 @@ export abstract class BasePanel implements Panel {
|
|
|
29
29
|
public readonly name: string,
|
|
30
30
|
public readonly icon: string,
|
|
31
31
|
public readonly category: PanelCategory,
|
|
32
|
-
|
|
32
|
+
componentHealthMonitor?: ComponentHealthMonitor,
|
|
33
33
|
) {
|
|
34
|
-
this.
|
|
34
|
+
this.componentHealthMonitor = componentHealthMonitor;
|
|
35
35
|
}
|
|
36
36
|
|
|
37
37
|
onActivate(): void { this.needsRender = true; }
|
|
@@ -45,7 +45,7 @@ export abstract class BasePanel implements Panel {
|
|
|
45
45
|
/**
|
|
46
46
|
* Check whether the panel is currently permitted to render.
|
|
47
47
|
*
|
|
48
|
-
* Consults the shared
|
|
48
|
+
* Consults the shared ComponentHealthMonitor. Returns true if not registered
|
|
49
49
|
* (unthrottled) or if the monitor permits a render at this moment.
|
|
50
50
|
*
|
|
51
51
|
* Call this inside render() or before invoking render() to skip
|
|
@@ -59,7 +59,7 @@ export abstract class BasePanel implements Panel {
|
|
|
59
59
|
* ```
|
|
60
60
|
*/
|
|
61
61
|
protected canRenderNow(now: number = Date.now()): boolean {
|
|
62
|
-
return this.
|
|
62
|
+
return this.componentHealthMonitor?.canRender(this.id, now) ?? true;
|
|
63
63
|
}
|
|
64
64
|
|
|
65
65
|
/**
|
|
@@ -67,6 +67,6 @@ export abstract class BasePanel implements Panel {
|
|
|
67
67
|
* Call this at the end of render() after measuring wall-clock cost.
|
|
68
68
|
*/
|
|
69
69
|
protected reportRenderDuration(durationMs: number, now: number = Date.now()): void {
|
|
70
|
-
this.
|
|
70
|
+
this.componentHealthMonitor?.recordRender(this.id, durationMs, now);
|
|
71
71
|
}
|
|
72
72
|
}
|
|
@@ -97,7 +97,7 @@ export function registerOperationsPanels(manager: PanelManager, deps: ResolvedBu
|
|
|
97
97
|
category: 'monitoring',
|
|
98
98
|
description: 'Project-local and global skill discovery with origin and dependency details',
|
|
99
99
|
factory: () => new SkillsPanel({
|
|
100
|
-
|
|
100
|
+
componentHealthMonitor: deps.componentHealthMonitor,
|
|
101
101
|
shellPaths: ui.environment.shellPaths,
|
|
102
102
|
}),
|
|
103
103
|
});
|
|
@@ -1,12 +1,78 @@
|
|
|
1
|
+
import { networkInterfaces } from 'node:os';
|
|
2
|
+
import { readFileSync } from 'node:fs';
|
|
1
3
|
import type { PanelManager } from '../panel-manager.ts';
|
|
2
4
|
import { SessionBrowserPanel } from '../session-browser-panel.ts';
|
|
5
|
+
import { QrPanel } from '../qr-panel.ts';
|
|
3
6
|
import { DocsPanel } from '../docs-panel.ts';
|
|
4
7
|
import { PanelListPanel } from '../panel-list-panel.ts';
|
|
5
8
|
import { TokenBudgetPanel } from '../token-budget-panel.ts';
|
|
6
9
|
import type { ResolvedBuiltinPanelDeps } from './shared.ts';
|
|
7
10
|
import { requireUiServices } from './shared.ts';
|
|
11
|
+
import {
|
|
12
|
+
getOrCreateCompanionToken,
|
|
13
|
+
regenerateCompanionToken,
|
|
14
|
+
buildCompanionConnectionInfo,
|
|
15
|
+
} from '@pellux/goodvibes-sdk/platform/pairing/index';
|
|
16
|
+
import { copyToClipboard } from '../../utils/clipboard.ts';
|
|
17
|
+
|
|
18
|
+
function getLocalNetworkIp(): string {
|
|
19
|
+
const nets = networkInterfaces();
|
|
20
|
+
for (const name of Object.keys(nets)) {
|
|
21
|
+
for (const net of nets[name] ?? []) {
|
|
22
|
+
if (net.family === 'IPv4' && !net.internal) {
|
|
23
|
+
return net.address;
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
return 'localhost';
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
function readBootstrapPassword(credentialPath: string): string | undefined {
|
|
31
|
+
try {
|
|
32
|
+
const content = readFileSync(credentialPath, 'utf-8');
|
|
33
|
+
for (const line of content.split('\n')) {
|
|
34
|
+
if (line.startsWith('password=')) {
|
|
35
|
+
return line.slice('password='.length).trim();
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
} catch {
|
|
39
|
+
// credential file may not exist yet
|
|
40
|
+
}
|
|
41
|
+
return undefined;
|
|
42
|
+
}
|
|
8
43
|
|
|
9
44
|
export function registerSessionPanels(manager: PanelManager, deps: ResolvedBuiltinPanelDeps): void {
|
|
45
|
+
manager.registerType({
|
|
46
|
+
id: 'qr-code',
|
|
47
|
+
name: 'QR Code',
|
|
48
|
+
icon: 'Q',
|
|
49
|
+
category: 'session',
|
|
50
|
+
description: 'QR code for companion app pairing — scan to connect a mobile or desktop companion',
|
|
51
|
+
factory: () => {
|
|
52
|
+
const tokenRecord = getOrCreateCompanionToken('tui');
|
|
53
|
+
const daemonPort = deps.configManager.get('controlPlane.port');
|
|
54
|
+
const daemonHost = String(process.env['GOODVIBES_DAEMON_HOST'] ?? getLocalNetworkIp());
|
|
55
|
+
const daemonUrl = `http://${daemonHost}:${daemonPort}`;
|
|
56
|
+
const bootstrapPassword = readBootstrapPassword(deps.localUserAuthManager.getBootstrapCredentialPath());
|
|
57
|
+
const connectionInfo = buildCompanionConnectionInfo({
|
|
58
|
+
daemonUrl,
|
|
59
|
+
token: tokenRecord.token,
|
|
60
|
+
password: bootstrapPassword,
|
|
61
|
+
surface: 'tui',
|
|
62
|
+
});
|
|
63
|
+
const regenerate = (): typeof connectionInfo => {
|
|
64
|
+
const newRecord = regenerateCompanionToken('tui');
|
|
65
|
+
return buildCompanionConnectionInfo({
|
|
66
|
+
daemonUrl,
|
|
67
|
+
token: newRecord.token,
|
|
68
|
+
password: bootstrapPassword,
|
|
69
|
+
surface: 'tui',
|
|
70
|
+
});
|
|
71
|
+
};
|
|
72
|
+
return new QrPanel(connectionInfo, regenerate, copyToClipboard);
|
|
73
|
+
},
|
|
74
|
+
});
|
|
75
|
+
|
|
10
76
|
manager.registerType({
|
|
11
77
|
id: 'sessions',
|
|
12
78
|
name: 'Sessions',
|
|
@@ -31,7 +97,7 @@ export function registerSessionPanels(manager: PanelManager, deps: ResolvedBuilt
|
|
|
31
97
|
icon: 'L',
|
|
32
98
|
category: 'session',
|
|
33
99
|
description: 'Browse all registered panels grouped by category, with open/closed status and Enter-to-open',
|
|
34
|
-
factory: () => new PanelListPanel(manager, deps.
|
|
100
|
+
factory: () => new PanelListPanel(manager, deps.componentHealthMonitor),
|
|
35
101
|
});
|
|
36
102
|
|
|
37
103
|
manager.registerType({
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { ConfigManager } from '@pellux/goodvibes-sdk/platform/config/manager';
|
|
2
|
-
import type { ServiceRegistry } from '
|
|
2
|
+
import type { ServiceRegistry } from '@pellux/goodvibes-sdk/platform/config/service-registry';
|
|
3
3
|
import type { ToolRegistry } from '@pellux/goodvibes-sdk/platform/tools/registry';
|
|
4
4
|
import type { ProviderRegistry } from '@pellux/goodvibes-sdk/platform/providers/registry';
|
|
5
5
|
import type { Orchestrator } from '../../core/orchestrator';
|
|
@@ -21,7 +21,7 @@ import type { SessionMemoryStore } from '@pellux/goodvibes-sdk/platform/core/ses
|
|
|
21
21
|
import type { ExecutionPlanManager } from '@pellux/goodvibes-sdk/platform/core/execution-plan';
|
|
22
22
|
import type { AdaptivePlanner } from '@pellux/goodvibes-sdk/platform/core/adaptive-planner';
|
|
23
23
|
import type { ApiTokenAuditor } from '@pellux/goodvibes-sdk/platform/security/token-audit';
|
|
24
|
-
import type {
|
|
24
|
+
import type { ComponentHealthMonitor } from '../../runtime/perf/panel-health-monitor.ts';
|
|
25
25
|
import type { WorktreeRegistry } from '@pellux/goodvibes-sdk/platform/runtime/worktree/registry';
|
|
26
26
|
import type { SandboxSessionRegistry } from '@pellux/goodvibes-sdk/platform/runtime/sandbox/session-registry';
|
|
27
27
|
|
|
@@ -72,8 +72,8 @@ export interface BuiltinPanelDeps {
|
|
|
72
72
|
getControlPlaneRecentEvents?: (limit: number) => readonly ControlPlaneRecentEvent[];
|
|
73
73
|
/** Token auditor for the security control-room panel. */
|
|
74
74
|
tokenAuditor: ApiTokenAuditor;
|
|
75
|
-
/** Shared
|
|
76
|
-
|
|
75
|
+
/** Shared component-health monitor for rate-limited panels and diagnostics. */
|
|
76
|
+
componentHealthMonitor: ComponentHealthMonitor;
|
|
77
77
|
/** Shared worktree registry for worktree surfaces. */
|
|
78
78
|
worktreeRegistry: WorktreeRegistry;
|
|
79
79
|
/** Shared sandbox session registry for sandbox surfaces and tools. */
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import type { Line } from '
|
|
2
|
-
import { createEmptyLine } from '
|
|
1
|
+
import type { Line } from '../types/grid.ts';
|
|
2
|
+
import { createEmptyLine } from '../types/grid.ts';
|
|
3
3
|
import { BasePanel } from './base-panel.ts';
|
|
4
4
|
import type { UiCockpitSnapshot, UiReadModel } from '../runtime/ui-read-models.ts';
|
|
5
5
|
import {
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import type { Line } from '
|
|
2
|
-
import { createEmptyLine } from '
|
|
1
|
+
import type { Line } from '../types/grid.ts';
|
|
2
|
+
import { createEmptyLine } from '../types/grid.ts';
|
|
3
3
|
import { BasePanel } from './base-panel.ts';
|
|
4
4
|
import type { UiCommunicationSnapshot, UiReadModel } from '../runtime/ui-read-models.ts';
|
|
5
|
-
import { truncateDisplay } from '
|
|
5
|
+
import { truncateDisplay } from '../utils/terminal-width.ts';
|
|
6
6
|
import {
|
|
7
7
|
buildBodyText,
|
|
8
8
|
buildEmptyState,
|
|
@@ -3,11 +3,11 @@
|
|
|
3
3
|
// ---------------------------------------------------------------------------
|
|
4
4
|
|
|
5
5
|
import type { ConfigManager } from '@pellux/goodvibes-sdk/platform/config/manager';
|
|
6
|
-
import type { Line } from '
|
|
6
|
+
import type { Line } from '../types/grid.ts';
|
|
7
7
|
import { BasePanel } from './base-panel.ts';
|
|
8
8
|
import { evaluateSessionMaintenance } from '@pellux/goodvibes-sdk/platform/runtime/session-maintenance';
|
|
9
9
|
import type { TurnEvent } from '@pellux/goodvibes-sdk/platform/runtime/events/index';
|
|
10
|
-
import type { UiEventFeed } from '
|
|
10
|
+
import type { UiEventFeed } from '../runtime/ui-events.ts';
|
|
11
11
|
import type { UiReadModel, UiSessionSnapshot } from '../runtime/ui-read-models.ts';
|
|
12
12
|
import type { SessionMemoryQuery } from '../runtime/ui-service-queries.ts';
|
|
13
13
|
import {
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import type { Line } from '
|
|
2
|
-
import { createEmptyLine } from '
|
|
1
|
+
import type { Line } from '../types/grid.ts';
|
|
2
|
+
import { createEmptyLine } from '../types/grid.ts';
|
|
3
3
|
import { BasePanel } from './base-panel.ts';
|
|
4
4
|
import type { UiControlPlaneSnapshot, UiReadModel } from '../runtime/ui-read-models.ts';
|
|
5
|
-
import { truncateDisplay } from '
|
|
5
|
+
import { truncateDisplay } from '../utils/terminal-width.ts';
|
|
6
6
|
import {
|
|
7
7
|
buildEmptyState,
|
|
8
8
|
buildGuidanceLine,
|
|
@@ -2,11 +2,11 @@
|
|
|
2
2
|
// CostTrackerPanel — per-session / per-agent / per-plan cost estimates
|
|
3
3
|
// ---------------------------------------------------------------------------
|
|
4
4
|
|
|
5
|
-
import type { Line } from '
|
|
6
|
-
import { createStyledCell, createEmptyLine } from '
|
|
5
|
+
import type { Line } from '../types/grid.ts';
|
|
6
|
+
import { createStyledCell, createEmptyLine } from '../types/grid.ts';
|
|
7
7
|
import { BasePanel } from './base-panel.ts';
|
|
8
8
|
import type { AgentEvent, TurnEvent } from '@pellux/goodvibes-sdk/platform/runtime/events/index';
|
|
9
|
-
import type { UiEventFeed } from '
|
|
9
|
+
import type { UiEventFeed } from '../runtime/ui-events.ts';
|
|
10
10
|
import {
|
|
11
11
|
buildEmptyState,
|
|
12
12
|
buildPanelLine,
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { BasePanel } from './base-panel.ts';
|
|
2
|
-
import { createEmptyLine, createStyledCell, type Line } from '
|
|
2
|
+
import { createEmptyLine, createStyledCell, type Line } from '../types/grid.ts';
|
|
3
3
|
import type { TurnEvent } from '@pellux/goodvibes-sdk/platform/runtime/events/index';
|
|
4
|
-
import type { UiEventFeed } from '
|
|
4
|
+
import type { UiEventFeed } from '../runtime/ui-events.ts';
|
|
5
5
|
import type { Orchestrator } from '../core/orchestrator';
|
|
6
6
|
import {
|
|
7
7
|
buildEmptyState,
|
package/src/panels/diff-panel.ts
CHANGED
|
@@ -2,8 +2,8 @@
|
|
|
2
2
|
// DiffPanel — unified diff view of agent file changes
|
|
3
3
|
// ---------------------------------------------------------------------------
|
|
4
4
|
|
|
5
|
-
import type { Line } from '
|
|
6
|
-
import { createStyledCell, createEmptyLine } from '
|
|
5
|
+
import type { Line } from '../types/grid.ts';
|
|
6
|
+
import { createStyledCell, createEmptyLine } from '../types/grid.ts';
|
|
7
7
|
import { BasePanel } from './base-panel.ts';
|
|
8
8
|
import {
|
|
9
9
|
buildBodyText,
|
package/src/panels/docs-panel.ts
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
// DocsPanel — tool list, model capabilities, and keyboard shortcut reference.
|
|
3
3
|
// ---------------------------------------------------------------------------
|
|
4
4
|
|
|
5
|
-
import type { Line } from '
|
|
5
|
+
import type { Line } from '../types/grid.ts';
|
|
6
6
|
import { BasePanel } from './base-panel.ts';
|
|
7
7
|
import { buildPanelLine, buildPanelWorkspace, buildSearchInputLine, resolveScrollablePanelSection, DEFAULT_PANEL_PALETTE } from './polish.ts';
|
|
8
8
|
import type { ProviderModelCatalogQuery, ToolCatalogQuery } from '../runtime/ui-service-queries.ts';
|
package/src/panels/eval-panel.ts
CHANGED
|
@@ -6,8 +6,8 @@
|
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
8
|
import { BasePanel } from './base-panel.ts';
|
|
9
|
-
import type { Line } from '
|
|
10
|
-
import { createEmptyLine } from '
|
|
9
|
+
import type { Line } from '../types/grid.ts';
|
|
10
|
+
import { createEmptyLine } from '../types/grid.ts';
|
|
11
11
|
import {
|
|
12
12
|
buildEmptyState,
|
|
13
13
|
buildPanelLine,
|
|
@@ -4,8 +4,8 @@
|
|
|
4
4
|
|
|
5
5
|
import { readdirSync, statSync } from 'node:fs';
|
|
6
6
|
import { join, relative, basename } from 'node:path';
|
|
7
|
-
import type { Line } from '
|
|
8
|
-
import { createEmptyLine } from '
|
|
7
|
+
import type { Line } from '../types/grid.ts';
|
|
8
|
+
import { createEmptyLine } from '../types/grid.ts';
|
|
9
9
|
import { BasePanel } from './base-panel.ts';
|
|
10
10
|
import {
|
|
11
11
|
buildEmptyState,
|
|
@@ -16,7 +16,7 @@ import {
|
|
|
16
16
|
resolveScrollablePanelSection,
|
|
17
17
|
DEFAULT_PANEL_PALETTE,
|
|
18
18
|
} from './polish.ts';
|
|
19
|
-
import { getDisplayWidth } from '
|
|
19
|
+
import { getDisplayWidth } from '../utils/terminal-width.ts';
|
|
20
20
|
import {
|
|
21
21
|
getPanelSearchFocusTransition,
|
|
22
22
|
isPanelSearchBackspace,
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import * as fs from 'node:fs';
|
|
2
2
|
import * as path from 'node:path';
|
|
3
|
-
import type { Line, Cell } from '
|
|
4
|
-
import { createStyledCell, createEmptyLine } from '
|
|
3
|
+
import type { Line, Cell } from '../types/grid.ts';
|
|
4
|
+
import { createStyledCell, createEmptyLine } from '../types/grid.ts';
|
|
5
5
|
import { BasePanel } from './base-panel.ts';
|
|
6
6
|
import { SyntaxHighlighter, type SyntaxToken } from '../renderer/syntax-highlighter.ts';
|
|
7
|
-
import { getDisplayWidth } from '
|
|
7
|
+
import { getDisplayWidth } from '../utils/terminal-width.ts';
|
|
8
8
|
import {
|
|
9
9
|
buildEmptyState,
|
|
10
10
|
buildPanelLine,
|
|
@@ -6,12 +6,12 @@
|
|
|
6
6
|
*
|
|
7
7
|
* Open via /forensics or the panel picker.
|
|
8
8
|
*/
|
|
9
|
-
import type { Line } from '
|
|
9
|
+
import type { Line } from '../types/grid.ts';
|
|
10
10
|
import type { ForensicsRegistry } from '@pellux/goodvibes-sdk/platform/runtime/forensics/registry';
|
|
11
11
|
import type { FailureReport, CausalChainEntry, PhaseTimingEntry } from '@pellux/goodvibes-sdk/platform/runtime/forensics/types';
|
|
12
12
|
import { ForensicsDataPanel } from '@pellux/goodvibes-sdk/platform/runtime/diagnostics/panels/forensics';
|
|
13
13
|
import { BasePanel } from './base-panel.ts';
|
|
14
|
-
import { createEmptyLine } from '
|
|
14
|
+
import { createEmptyLine } from '../types/grid.ts';
|
|
15
15
|
import {
|
|
16
16
|
buildEmptyState,
|
|
17
17
|
buildPanelLine,
|
package/src/panels/git-panel.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { BasePanel } from './base-panel.ts';
|
|
2
|
-
import { createEmptyLine, createStyledCell, type Line } from '
|
|
2
|
+
import { createEmptyLine, createStyledCell, type Line } from '../types/grid.ts';
|
|
3
3
|
import { GitService } from '@pellux/goodvibes-sdk/platform/git/service';
|
|
4
4
|
import { logger } from '@pellux/goodvibes-sdk/platform/utils/logger';
|
|
5
5
|
import { summarizeError } from '@pellux/goodvibes-sdk/platform/utils/error-display';
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import type { Line } from '
|
|
2
|
-
import { createEmptyLine } from '
|
|
1
|
+
import type { Line } from '../types/grid.ts';
|
|
2
|
+
import { createEmptyLine } from '../types/grid.ts';
|
|
3
3
|
import { BasePanel } from './base-panel.ts';
|
|
4
4
|
import { listHookPointContracts } from '@pellux/goodvibes-sdk/platform/hooks/index';
|
|
5
5
|
import type { HookDispatcher } from '@pellux/goodvibes-sdk/platform/hooks/dispatcher';
|
|
@@ -8,7 +8,7 @@ import type { HookActivityRecord, HookActivityTracker } from '@pellux/goodvibes-
|
|
|
8
8
|
import type { HookAuthoringAction, HookSimulationResult } from '@pellux/goodvibes-sdk/platform/hooks/workbench';
|
|
9
9
|
import type { HookChain, HookDefinition } from '@pellux/goodvibes-sdk/platform/hooks/types';
|
|
10
10
|
import type { HookWorkbench } from '@pellux/goodvibes-sdk/platform/hooks/workbench';
|
|
11
|
-
import { truncateDisplay } from '
|
|
11
|
+
import { truncateDisplay } from '../utils/terminal-width.ts';
|
|
12
12
|
import {
|
|
13
13
|
buildEmptyState,
|
|
14
14
|
buildPanelLine,
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { Line } from '
|
|
1
|
+
import type { Line } from '../types/grid.ts';
|
|
2
2
|
import type { ForensicsRegistry } from '@pellux/goodvibes-sdk/platform/runtime/forensics/registry';
|
|
3
3
|
import { BasePanel } from './base-panel.ts';
|
|
4
4
|
import {
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import type { Line } from '
|
|
2
|
-
import { createEmptyLine } from '
|
|
1
|
+
import type { Line } from '../types/grid.ts';
|
|
2
|
+
import { createEmptyLine } from '../types/grid.ts';
|
|
3
3
|
import { BasePanel } from './base-panel.ts';
|
|
4
4
|
import type { UiIntelligenceSnapshot, UiReadModel } from '../runtime/ui-read-models.ts';
|
|
5
5
|
import {
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { Line } from '
|
|
1
|
+
import type { Line } from '../types/grid.ts';
|
|
2
2
|
import { BasePanel } from './base-panel.ts';
|
|
3
3
|
import type { MemoryClass, MemoryRecord, MemoryRegistry, MemoryReviewState } from '@pellux/goodvibes-sdk/platform/state/memory-store';
|
|
4
4
|
import {
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import type { Line } from '
|
|
2
|
-
import { createEmptyLine } from '
|
|
1
|
+
import type { Line } from '../types/grid.ts';
|
|
2
|
+
import { createEmptyLine } from '../types/grid.ts';
|
|
3
3
|
import { BasePanel } from './base-panel.ts';
|
|
4
4
|
import {
|
|
5
5
|
buildDetailBlock,
|
package/src/panels/mcp-panel.ts
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import type { Line } from '
|
|
2
|
-
import { createEmptyLine } from '
|
|
1
|
+
import type { Line } from '../types/grid.ts';
|
|
2
|
+
import { createEmptyLine } from '../types/grid.ts';
|
|
3
3
|
import { BasePanel } from './base-panel.ts';
|
|
4
4
|
import type { McpRegistry } from '@pellux/goodvibes-sdk/platform/mcp/registry';
|
|
5
5
|
import type { McpDecisionRecord } from '@pellux/goodvibes-sdk/platform/runtime/mcp/types';
|
|
6
|
-
import { truncateDisplay } from '
|
|
6
|
+
import { truncateDisplay } from '../utils/terminal-width.ts';
|
|
7
7
|
import {
|
|
8
8
|
buildEmptyState,
|
|
9
9
|
buildGuidanceLine,
|