@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
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { Line } from '../types/grid.ts';
|
|
2
2
|
import { ScrollableListPanel } from './scrollable-list-panel.ts';
|
|
3
|
+
import type { PanelIntegrationContext } from './types.ts';
|
|
3
4
|
import type { UiCommunicationSnapshot, UiReadModel } from '../runtime/ui-read-models.ts';
|
|
4
5
|
import { truncateDisplay } from '../utils/terminal-width.ts';
|
|
5
6
|
import {
|
|
@@ -18,15 +19,9 @@ import {
|
|
|
18
19
|
} from './polish.ts';
|
|
19
20
|
import { createEmptyLine } from '../types/grid.ts';
|
|
20
21
|
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
headerBg: '#1e293b',
|
|
25
|
-
ok: '#22c55e',
|
|
26
|
-
warn: '#eab308',
|
|
27
|
-
error: '#ef4444',
|
|
28
|
-
selectBg: '#0f172a',
|
|
29
|
-
} as const;
|
|
22
|
+
// Base chrome only — title band, state colors, and text tokens all come
|
|
23
|
+
// straight from DEFAULT_PANEL_PALETTE (WO-002).
|
|
24
|
+
const C = DEFAULT_PANEL_PALETTE;
|
|
30
25
|
|
|
31
26
|
type CommunicationRecord = UiCommunicationSnapshot['records'][number];
|
|
32
27
|
|
|
@@ -41,18 +36,31 @@ function fmtAgo(ts: number): string {
|
|
|
41
36
|
return `${Math.floor(sec / 3600)}h`;
|
|
42
37
|
}
|
|
43
38
|
|
|
39
|
+
// Set by handleInput (enter/o) and consumed on the very next
|
|
40
|
+
// handlePanelIntegrationAction dispatch of that same key — handleInput has
|
|
41
|
+
// no access to the panelManager/openAgentDetail callback.
|
|
42
|
+
type PendingCommunicationAction =
|
|
43
|
+
| { readonly kind: 'open-orchestration' }
|
|
44
|
+
| { readonly kind: 'open-agent-detail'; readonly agentId: string };
|
|
45
|
+
|
|
44
46
|
export class CommunicationPanel extends ScrollableListPanel<CommunicationRecord> {
|
|
45
47
|
private readonly readModel?: UiReadModel<UiCommunicationSnapshot>;
|
|
46
48
|
private readonly unsub: (() => void) | null;
|
|
49
|
+
private readonly openAgentDetail?: (agentId: string) => void;
|
|
47
50
|
/** When true, the list is narrowed to blocked messages only (b toggles). */
|
|
48
51
|
private blockedOnly = false;
|
|
52
|
+
private pendingAction: PendingCommunicationAction | null = null;
|
|
49
53
|
|
|
50
|
-
public constructor(
|
|
51
|
-
|
|
54
|
+
public constructor(
|
|
55
|
+
readModel?: UiReadModel<UiCommunicationSnapshot>,
|
|
56
|
+
openAgentDetail?: (agentId: string) => void,
|
|
57
|
+
) {
|
|
58
|
+
super('communication', 'Communication', 'Y', 'runtime-ops');
|
|
52
59
|
this.showSelectionGutter = true; // I5: non-color selection affordance
|
|
53
60
|
this.filterEnabled = true;
|
|
54
61
|
this.filterLabel = 'Filter messages';
|
|
55
62
|
this.readModel = readModel;
|
|
63
|
+
this.openAgentDetail = openAgentDetail;
|
|
56
64
|
this.unsub = readModel ? readModel.subscribe(() => this.markDirty()) : null;
|
|
57
65
|
}
|
|
58
66
|
|
|
@@ -86,9 +94,38 @@ export class CommunicationPanel extends ScrollableListPanel<CommunicationRecord>
|
|
|
86
94
|
this.markDirty();
|
|
87
95
|
return true;
|
|
88
96
|
}
|
|
97
|
+
// Enter jumps to the orchestration workspace that actually produces this
|
|
98
|
+
// traffic (a direct panel jump, not a printed "/orchestration" signpost).
|
|
99
|
+
// Guarded so it doesn't hijack the filter input's commit-on-enter.
|
|
100
|
+
if ((key === 'enter' || key === 'return') && !this.filterActive) {
|
|
101
|
+
this.pendingAction = { kind: 'open-orchestration' };
|
|
102
|
+
return true;
|
|
103
|
+
}
|
|
104
|
+
// `o` on a blocked record opens the sender's agent detail (falling back
|
|
105
|
+
// to the receiver when the sender id is missing) via deps.openAgentDetail.
|
|
106
|
+
if (key === 'o' && !this.filterActive) {
|
|
107
|
+
const record = this.getSelectedItem();
|
|
108
|
+
if (!record || record.status !== 'blocked') return false;
|
|
109
|
+
const agentId = record.fromId || record.toId;
|
|
110
|
+
if (!agentId) return false;
|
|
111
|
+
this.pendingAction = { kind: 'open-agent-detail', agentId };
|
|
112
|
+
return true;
|
|
113
|
+
}
|
|
89
114
|
return super.handleInput(key);
|
|
90
115
|
}
|
|
91
116
|
|
|
117
|
+
public handlePanelIntegrationAction(_key: string, ctx: PanelIntegrationContext): boolean {
|
|
118
|
+
if (!this.pendingAction) return false;
|
|
119
|
+
const action = this.pendingAction;
|
|
120
|
+
this.pendingAction = null;
|
|
121
|
+
if (action.kind === 'open-orchestration') {
|
|
122
|
+
ctx.panelManager.open('orchestration');
|
|
123
|
+
return true;
|
|
124
|
+
}
|
|
125
|
+
this.openAgentDetail?.(action.agentId);
|
|
126
|
+
return true;
|
|
127
|
+
}
|
|
128
|
+
|
|
92
129
|
protected renderItem(record: CommunicationRecord, _index: number, selected: boolean, width: number): Line {
|
|
93
130
|
const bg = selected ? C.selectBg : undefined;
|
|
94
131
|
const badge = buildStatusBadge(statusBadgeKind(record.status), record.status)[0]!;
|
|
@@ -117,7 +154,6 @@ export class CommunicationPanel extends ScrollableListPanel<CommunicationRecord>
|
|
|
117
154
|
protected override getEmptyStateActions(): Array<{ command: string; summary: string }> {
|
|
118
155
|
return [
|
|
119
156
|
{ command: '/orchestration', summary: 'review graphs and recursive agent activity that emit messages' },
|
|
120
|
-
{ command: '/communication', summary: 'reopen this workspace once the runtime emits message traffic' },
|
|
121
157
|
];
|
|
122
158
|
}
|
|
123
159
|
|
|
@@ -133,7 +169,7 @@ export class CommunicationPanel extends ScrollableListPanel<CommunicationRecord>
|
|
|
133
169
|
width,
|
|
134
170
|
' Runtime store not wired into this panel yet.',
|
|
135
171
|
'This workspace needs the live runtime store before it can show communication history and policy outcomes.',
|
|
136
|
-
[{ command: '/
|
|
172
|
+
[{ command: '/orchestration', summary: 'inspect recursive routing and agent activity while this workspace is unwired' }],
|
|
137
173
|
C,
|
|
138
174
|
),
|
|
139
175
|
}],
|
|
@@ -159,7 +195,7 @@ export class CommunicationPanel extends ScrollableListPanel<CommunicationRecord>
|
|
|
159
195
|
]),
|
|
160
196
|
snapshot.totalBlocked > 0
|
|
161
197
|
? buildPanelLine(width, [[` ${snapshot.totalBlocked} message${snapshot.totalBlocked !== 1 ? 's' : ''} blocked by routing policy — press b to isolate blocked lanes.`, C.warn]])
|
|
162
|
-
:
|
|
198
|
+
: buildPanelLine(width, [[' No blocked lanes — press Enter on a record to inspect routing in the orchestration console.', C.dim]]),
|
|
163
199
|
];
|
|
164
200
|
|
|
165
201
|
if (records.length === 0) {
|
|
@@ -171,14 +207,13 @@ export class CommunicationPanel extends ScrollableListPanel<CommunicationRecord>
|
|
|
171
207
|
}
|
|
172
208
|
|
|
173
209
|
this.clampSelection();
|
|
174
|
-
const
|
|
175
|
-
const selected = visible[this.selectedIndex];
|
|
210
|
+
const selected = this.getSelectedItem();
|
|
176
211
|
|
|
177
212
|
const detailLines: Line[] = [];
|
|
178
213
|
if (selected) {
|
|
179
214
|
detailLines.push(...buildDetailBlock(width, `Message · ${selected.kind}`, [
|
|
180
215
|
buildKeyValueLine(width, [
|
|
181
|
-
{ label: 'status', value: selected.status, valueColor: selected.status === 'blocked' ? C.
|
|
216
|
+
{ label: 'status', value: selected.status, valueColor: selected.status === 'blocked' ? C.bad : C.good },
|
|
182
217
|
{ label: 'scope', value: selected.scope, valueColor: C.value },
|
|
183
218
|
{ label: 'when', value: `${fmtAgo(selected.timestamp)} ago`, valueColor: C.dim },
|
|
184
219
|
], C),
|
|
@@ -196,15 +231,18 @@ export class CommunicationPanel extends ScrollableListPanel<CommunicationRecord>
|
|
|
196
231
|
return this.renderList(width, height, {
|
|
197
232
|
title: 'Communication Control Room',
|
|
198
233
|
header: postureLines(),
|
|
199
|
-
footer: [...detailLines, buildKeyboardHints(width, this.footerHints(true), C)],
|
|
234
|
+
footer: [...detailLines, buildKeyboardHints(width, this.footerHints(true, selected?.status === 'blocked'), C)],
|
|
200
235
|
});
|
|
201
236
|
}
|
|
202
237
|
|
|
203
238
|
// Context-aware hints: filter keys reflect filter state, `b` reflects the
|
|
204
|
-
// blocked-only toggle,
|
|
205
|
-
|
|
239
|
+
// blocked-only toggle, `o` only appears on a blocked selection, and the
|
|
240
|
+
// inspect hint only appears when rows exist.
|
|
241
|
+
private footerHints(hasRows: boolean, onBlockedSelection = false): Array<{ keys: string; label: string }> {
|
|
206
242
|
const hints: Array<{ keys: string; label: string }> = [];
|
|
207
243
|
if (hasRows) hints.push({ keys: '↑/↓', label: 'select' });
|
|
244
|
+
hints.push({ keys: 'Enter', label: 'orchestration' });
|
|
245
|
+
if (onBlockedSelection) hints.push({ keys: 'o', label: 'sender detail' });
|
|
208
246
|
hints.push({ keys: 'b', label: this.blockedOnly ? 'show all lanes' : 'blocked only' });
|
|
209
247
|
if (this.filterActive) {
|
|
210
248
|
hints.push({ keys: 'Esc', label: 'clear filter' });
|
|
@@ -28,6 +28,12 @@ export interface ConfirmState<T = string> {
|
|
|
28
28
|
readonly subject: T;
|
|
29
29
|
/** Human-readable label for the item being destroyed. */
|
|
30
30
|
readonly label: string;
|
|
31
|
+
/**
|
|
32
|
+
* Action verb shown in the confirmation prompt (e.g. 'Cancel', 'Regenerate',
|
|
33
|
+
* 'Promote'). Defaults to 'Delete' so existing destructive confirms are
|
|
34
|
+
* unaffected; non-destructive confirms should set this for honest copy.
|
|
35
|
+
*/
|
|
36
|
+
readonly verb?: string;
|
|
31
37
|
}
|
|
32
38
|
|
|
33
39
|
/**
|
|
@@ -61,9 +67,10 @@ export function handleConfirmInput<T = string>(
|
|
|
61
67
|
*/
|
|
62
68
|
export function renderConfirmLines<T = string>(width: number, state: ConfirmState<T>): Line[] {
|
|
63
69
|
const palette = DEFAULT_PANEL_PALETTE;
|
|
70
|
+
const verb = state.verb ?? 'Delete';
|
|
64
71
|
return [
|
|
65
72
|
buildPanelLine(width, [[
|
|
66
|
-
`
|
|
73
|
+
` ${verb} "${state.label}"?`,
|
|
67
74
|
palette.warn,
|
|
68
75
|
]]),
|
|
69
76
|
buildPanelLine(width, [
|