@pellux/goodvibes-tui 0.28.0 → 1.0.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.
Files changed (144) hide show
  1. package/CHANGELOG.md +133 -0
  2. package/README.md +1 -1
  3. package/package.json +1 -1
  4. package/src/core/conversation-line-cache.ts +432 -0
  5. package/src/core/conversation-rendering.ts +11 -3
  6. package/src/core/conversation.ts +50 -4
  7. package/src/input/commands/cost-runtime.ts +49 -0
  8. package/src/input/commands/operator-runtime.ts +5 -1
  9. package/src/input/commands.ts +2 -0
  10. package/src/input/handler-content-actions.ts +8 -3
  11. package/src/input/handler-feed-routes.ts +12 -35
  12. package/src/input/handler-feed.ts +4 -8
  13. package/src/input/handler-shortcuts.ts +51 -0
  14. package/src/input/handler.ts +43 -6
  15. package/src/input/input-history.ts +17 -4
  16. package/src/input/keybindings.ts +48 -8
  17. package/src/input/panel-integration-actions.ts +107 -1
  18. package/src/main.ts +19 -11
  19. package/src/panels/agent-inspector-panel.ts +125 -36
  20. package/src/panels/agent-inspector-shared.ts +144 -0
  21. package/src/panels/approval-panel.ts +67 -16
  22. package/src/panels/automation-control-panel.ts +368 -124
  23. package/src/panels/base-panel.ts +1 -1
  24. package/src/panels/builtin/agent.ts +28 -37
  25. package/src/panels/builtin/development.ts +40 -32
  26. package/src/panels/builtin/knowledge.ts +15 -6
  27. package/src/panels/builtin/operations.ts +178 -117
  28. package/src/panels/builtin/session.ts +35 -9
  29. package/src/panels/builtin/shared.ts +98 -6
  30. package/src/panels/cockpit-panel.ts +232 -73
  31. package/src/panels/communication-panel.ts +58 -20
  32. package/src/panels/confirm-state.ts +8 -1
  33. package/src/panels/control-plane-panel.ts +351 -118
  34. package/src/panels/cost-tracker-panel.ts +165 -7
  35. package/src/panels/debug-panel.ts +312 -159
  36. package/src/panels/diff-panel.ts +209 -57
  37. package/src/panels/docs-panel.ts +152 -66
  38. package/src/panels/eval-panel.ts +220 -42
  39. package/src/panels/file-explorer-panel.ts +202 -122
  40. package/src/panels/file-preview-panel.ts +132 -57
  41. package/src/panels/git-panel.ts +310 -129
  42. package/src/panels/hooks-panel.ts +150 -22
  43. package/src/panels/incident-review-panel.ts +223 -35
  44. package/src/panels/index.ts +0 -4
  45. package/src/panels/intelligence-panel.ts +212 -86
  46. package/src/panels/knowledge-graph-panel.ts +461 -101
  47. package/src/panels/local-auth-panel.ts +240 -28
  48. package/src/panels/marketplace-panel.ts +193 -26
  49. package/src/panels/memory-panel.ts +78 -77
  50. package/src/panels/ops-control-panel.ts +146 -29
  51. package/src/panels/ops-strategy-panel.ts +72 -4
  52. package/src/panels/orchestration-panel.ts +231 -69
  53. package/src/panels/panel-list-panel.ts +154 -131
  54. package/src/panels/panel-manager.ts +97 -9
  55. package/src/panels/plan-dashboard-panel.ts +333 -17
  56. package/src/panels/plugins-panel.ts +184 -29
  57. package/src/panels/policy-panel.ts +210 -38
  58. package/src/panels/polish-core.ts +7 -2
  59. package/src/panels/polish.ts +23 -4
  60. package/src/panels/project-planning-answer-actions.ts +134 -0
  61. package/src/panels/project-planning-panel.ts +62 -113
  62. package/src/panels/provider-health-panel.ts +434 -518
  63. package/src/panels/provider-health-routes.ts +203 -0
  64. package/src/panels/provider-health-tracker.ts +194 -6
  65. package/src/panels/provider-health-views.ts +560 -0
  66. package/src/panels/qr-panel.ts +116 -30
  67. package/src/panels/remote-panel.ts +114 -36
  68. package/src/panels/routes-panel.ts +63 -22
  69. package/src/panels/sandbox-panel.ts +174 -42
  70. package/src/panels/scrollable-list-panel.ts +19 -135
  71. package/src/panels/security-panel.ts +133 -33
  72. package/src/panels/services-panel.ts +116 -64
  73. package/src/panels/session-browser-panel.ts +73 -2
  74. package/src/panels/session-maintenance.ts +4 -122
  75. package/src/panels/settings-sync-panel.ts +335 -72
  76. package/src/panels/skills-panel.ts +157 -89
  77. package/src/panels/subscription-panel.ts +86 -33
  78. package/src/panels/symbol-outline-panel.ts +248 -108
  79. package/src/panels/system-messages-panel.ts +114 -13
  80. package/src/panels/tasks-panel.ts +326 -139
  81. package/src/panels/thinking-panel.ts +43 -10
  82. package/src/panels/token-budget-panel.ts +194 -18
  83. package/src/panels/tool-inspector-panel.ts +144 -34
  84. package/src/panels/types.ts +40 -4
  85. package/src/panels/work-plan-panel.ts +280 -17
  86. package/src/panels/worktree-panel.ts +175 -42
  87. package/src/panels/wrfc-panel.ts +116 -24
  88. package/src/renderer/agent-detail-modal.ts +37 -8
  89. package/src/renderer/code-block.ts +58 -28
  90. package/src/renderer/context-inspector.ts +3 -6
  91. package/src/renderer/conversation-overlays.ts +25 -11
  92. package/src/renderer/conversation-surface.ts +1 -21
  93. package/src/renderer/diff-view.ts +6 -4
  94. package/src/renderer/footer-tips.ts +41 -0
  95. package/src/renderer/fullscreen-primitives.ts +23 -17
  96. package/src/renderer/fullscreen-workspace.ts +2 -7
  97. package/src/renderer/help-overlay.ts +91 -14
  98. package/src/renderer/hint-grammar.ts +52 -0
  99. package/src/renderer/history-search-overlay.ts +10 -16
  100. package/src/renderer/layout.ts +7 -7
  101. package/src/renderer/markdown.ts +9 -1
  102. package/src/renderer/modal-factory.ts +23 -15
  103. package/src/renderer/model-picker-overlay.ts +8 -485
  104. package/src/renderer/model-workspace.ts +9 -24
  105. package/src/renderer/overlay-box.ts +23 -19
  106. package/src/renderer/process-indicator.ts +15 -25
  107. package/src/renderer/profile-picker-modal.ts +13 -14
  108. package/src/renderer/prompt-content-width.ts +16 -0
  109. package/src/renderer/search-overlay.ts +27 -6
  110. package/src/renderer/selection-modal-overlay.ts +3 -1
  111. package/src/renderer/semantic-diff.ts +1 -1
  112. package/src/renderer/session-picker-modal.ts +6 -4
  113. package/src/renderer/settings-modal-helpers.ts +10 -34
  114. package/src/renderer/settings-modal.ts +70 -10
  115. package/src/renderer/shell-surface.ts +54 -15
  116. package/src/renderer/status-glyphs.ts +11 -9
  117. package/src/renderer/surface-layout.ts +0 -12
  118. package/src/renderer/term-caps.ts +1 -1
  119. package/src/renderer/theme.ts +60 -3
  120. package/src/renderer/tool-call.ts +6 -20
  121. package/src/renderer/ui-factory.ts +48 -37
  122. package/src/renderer/ui-primitives.ts +41 -3
  123. package/src/runtime/bootstrap-shell.ts +35 -18
  124. package/src/runtime/diagnostics/panels/index.ts +0 -3
  125. package/src/runtime/render-scheduler.ts +80 -0
  126. package/src/shell/ui-openers.ts +14 -22
  127. package/src/utils/format-duration.ts +2 -2
  128. package/src/utils/splash-lines.ts +54 -5
  129. package/src/version.ts +1 -1
  130. package/src/work-plans/work-plan-store.ts +13 -0
  131. package/src/panels/agent-logs-panel.ts +0 -635
  132. package/src/panels/agent-logs-shared.ts +0 -129
  133. package/src/panels/context-visualizer-panel.ts +0 -238
  134. package/src/panels/forensics-panel.ts +0 -378
  135. package/src/panels/provider-account-snapshot.ts +0 -259
  136. package/src/panels/provider-accounts-panel.ts +0 -255
  137. package/src/panels/provider-stats-panel.ts +0 -391
  138. package/src/panels/schedule-panel.ts +0 -365
  139. package/src/panels/watchers-panel.ts +0 -213
  140. package/src/renderer/file-tree.ts +0 -153
  141. package/src/renderer/progress.ts +0 -99
  142. package/src/renderer/status-token.ts +0 -67
  143. package/src/runtime/diagnostics/panels/panel-resources.ts +0 -118
  144. package/src/runtime/diagnostics/panels/policy.ts +0 -177
@@ -1,129 +0,0 @@
1
- export type AgentLogFilterType = 'all' | 'assistant' | 'tool' | 'error';
2
-
3
- export interface AgentLogEntry {
4
- raw: Record<string, unknown>;
5
- type: string;
6
- text: string;
7
- color: string;
8
- bold: boolean;
9
- }
10
-
11
- export const AGENT_LOG_FILTER_LABELS: Record<AgentLogFilterType, string> = {
12
- all: 'All',
13
- assistant: 'Assistant',
14
- tool: 'Tool',
15
- error: 'Error',
16
- };
17
-
18
- export const AGENT_LOG_FILTER_CYCLE: AgentLogFilterType[] = ['all', 'assistant', 'tool', 'error'];
19
-
20
- export const AGENT_LOG_COLORS = {
21
- header_bg: '235',
22
- header_fg: '250',
23
- header_accent: '#00ffff',
24
- header_label: '244',
25
- agent_selected: '#00ffff',
26
- agent_running: '#00ff87',
27
- agent_pending: '220',
28
- agent_done: '244',
29
- agent_error: '#ff5f5f',
30
- assistant: '255',
31
- tool: '#00e5ff',
32
- error: '#ff5f5f',
33
- dim: '240',
34
- paused: '220',
35
- auto_follow: '#00ff87',
36
- session_start: '238',
37
- separator: '237',
38
- filter_active: '#00ffff',
39
- filter_inactive: '244',
40
- } as const;
41
-
42
- export function parseAgentJsonl(content: string): AgentLogEntry[] {
43
- const entries: AgentLogEntry[] = [];
44
- for (const line of content.split('\n')) {
45
- const trimmed = line.trim();
46
- if (!trimmed) continue;
47
- try {
48
- const obj = JSON.parse(trimmed) as Record<string, unknown>;
49
- entries.push(toAgentLogEntry(obj));
50
- } catch {
51
- // ignore malformed lines
52
- }
53
- }
54
- return entries;
55
- }
56
-
57
- export function toAgentLogEntry(obj: Record<string, unknown>): AgentLogEntry {
58
- const type = typeof obj.type === 'string' ? obj.type : 'unknown';
59
- switch (type) {
60
- case 'meta':
61
- case 'session_start': {
62
- const agentId = String(obj.agentId ?? '');
63
- const model = String(obj.model ?? '');
64
- const provider = String(obj.provider ?? '');
65
- const ts = String(obj.timestamp ?? '').replace('T', ' ').replace(/\.\d+Z$/, '');
66
- return {
67
- raw: obj,
68
- type: 'session_start',
69
- text: `[${ts}] Session started agent=${agentId} model=${model} provider=${provider}`,
70
- color: AGENT_LOG_COLORS.session_start,
71
- bold: false,
72
- };
73
- }
74
- case 'assistant':
75
- return {
76
- raw: obj,
77
- type: 'assistant',
78
- text: String(obj.content ?? obj.text ?? ''),
79
- color: AGENT_LOG_COLORS.assistant,
80
- bold: false,
81
- };
82
- case 'tool_call': {
83
- const tool = String(obj.tool ?? obj.name ?? '');
84
- const args = obj.args ?? obj.arguments ?? {};
85
- const argsStr = typeof args === 'string' ? args : JSON.stringify(args);
86
- return {
87
- raw: obj,
88
- type: 'tool',
89
- text: `[tool] ${tool} ${argsStr.slice(0, 120)}`,
90
- color: AGENT_LOG_COLORS.tool,
91
- bold: false,
92
- };
93
- }
94
- case 'tool_result': {
95
- const tool = String(obj.tool ?? obj.name ?? '');
96
- const result = obj.result ?? obj.output ?? '';
97
- const resultStr = typeof result === 'string' ? result : JSON.stringify(result);
98
- return {
99
- raw: obj,
100
- type: 'tool',
101
- text: `[result] ${tool} ${resultStr.slice(0, 120)}`,
102
- color: AGENT_LOG_COLORS.tool,
103
- bold: false,
104
- };
105
- }
106
- case 'error':
107
- return {
108
- raw: obj,
109
- type: 'error',
110
- text: `[error] ${String(obj.error ?? obj.message ?? obj.msg ?? JSON.stringify(obj))}`,
111
- color: AGENT_LOG_COLORS.error,
112
- bold: true,
113
- };
114
- default: {
115
- const text = typeof obj.text === 'string'
116
- ? obj.text
117
- : typeof obj.content === 'string'
118
- ? obj.content
119
- : `[${type}] ${JSON.stringify(obj).slice(0, 120)}`;
120
- return {
121
- raw: obj,
122
- type,
123
- text,
124
- color: AGENT_LOG_COLORS.dim,
125
- bold: false,
126
- };
127
- }
128
- }
129
- }
@@ -1,238 +0,0 @@
1
- // ---------------------------------------------------------------------------
2
- // ContextVisualizerPanel — stacked bar showing context window composition.
3
- // ---------------------------------------------------------------------------
4
-
5
- import type { ConfigManager } from '@pellux/goodvibes-sdk/platform/config';
6
- import type { Line } from '../types/grid.ts';
7
- import { BasePanel } from './base-panel.ts';
8
- import { evaluateSessionMaintenance } from '@/runtime/index.ts';
9
- import type { TurnEvent } from '@/runtime/index.ts';
10
- import type { UiEventFeed } from '../runtime/ui-events.ts';
11
- import type { UiReadModel, UiSessionSnapshot } from '../runtime/ui-read-models.ts';
12
- import type { SessionMemoryQuery } from '../runtime/ui-service-queries.ts';
13
- import {
14
- buildEmptyState,
15
- buildGuidanceLine,
16
- buildKeyboardHints,
17
- buildMeterLine,
18
- buildPanelLine,
19
- buildStatusPill,
20
- buildStyledPanelLine,
21
- buildPanelWorkspace,
22
- DEFAULT_PANEL_PALETTE,
23
- extendPalette,
24
- } from './polish.ts';
25
-
26
- const C = extendPalette(DEFAULT_PANEL_PALETTE, {
27
- convFg: '#cc99ff',
28
- });
29
-
30
-
31
-
32
- interface ContextSnapshot {
33
- input: number;
34
- limit: number;
35
- }
36
-
37
- function formatK(n: number): string {
38
- if (n >= 1000) return `${(n / 1000).toFixed(1)}k`;
39
- return String(n);
40
- }
41
-
42
- export class ContextVisualizerPanel extends BasePanel {
43
- private snapshot: ContextSnapshot = { input: 0, limit: 0 };
44
- private unsubs: Array<() => void> = [];
45
- private readonly sessionMemoryStore: SessionMemoryQuery;
46
-
47
- constructor(
48
- private readonly turnEvents: UiEventFeed<TurnEvent>,
49
- sessionMemoryStore: SessionMemoryQuery,
50
- private readonly configManager: Pick<ConfigManager, 'get'>,
51
- private getUsage?: () => { input: number; output: number; cacheRead: number; cacheWrite: number; model?: string },
52
- private contextLimit?: number | (() => number),
53
- private sessionReadModel?: UiReadModel<UiSessionSnapshot>,
54
- private getLastInputTokens?: () => number,
55
- ) {
56
- super('context', 'Context', 'C', 'ai');
57
- this.sessionMemoryStore = sessionMemoryStore;
58
- this._attachBus();
59
- this._refresh();
60
- }
61
-
62
- override onActivate(): void {
63
- this.needsRender = true;
64
- this._refresh();
65
- }
66
-
67
- override onDeactivate(): void {
68
- super.onDeactivate();
69
- }
70
-
71
- override onDestroy(): void {
72
- this._detachBus();
73
- }
74
-
75
- render(width: number, height: number): Line[] {
76
- return this.trackedRender(() => {
77
- if (height <= 0 || width <= 0) return [];
78
-
79
- const input = this.snapshot.input;
80
- const limit = this.snapshot.limit;
81
- const pct = limit > 0 ? Math.min(100, Math.round((input / limit) * 100)) : 0;
82
- const barWidth = Math.max(1, width - 2);
83
- const overLimit = limit > 0 && input > limit;
84
- const fg = overLimit ? C.bad : C.convFg;
85
- if (limit <= 0) {
86
- return buildPanelWorkspace(width, height, {
87
- title: ' Context Usage',
88
- intro: 'Visualize current input-token pressure against the active model context window.',
89
- sections: [
90
- {
91
- lines: buildEmptyState(
92
- width,
93
- ' Context limit unavailable',
94
- 'Select a model with a known context window and submit or complete a turn to populate live context usage.',
95
- [
96
- { command: '/model', summary: 'pick an active model so its context window is known' },
97
- { command: '/context', summary: 'review current context composition and pressure' },
98
- ],
99
- DEFAULT_PANEL_PALETTE,
100
- ),
101
- },
102
- ],
103
- palette: DEFAULT_PANEL_PALETTE,
104
- });
105
- }
106
-
107
- // Pressure state drives the headline pill and the footer hint so the most
108
- // important signal — am I about to overflow context — is obvious at a glance.
109
- const pressureState = overLimit ? 'bad' : pct >= 90 ? 'bad' : pct >= 75 ? 'warn' : 'good';
110
- const pressureLabel = overLimit ? 'over limit' : pct >= 90 ? 'critical' : pct >= 75 ? 'elevated' : 'healthy';
111
-
112
- return buildPanelWorkspace(width, height, {
113
- title: ' Context Usage',
114
- intro: 'Visualize current input-token pressure against the active model context window.',
115
- sections: [
116
- {
117
- title: 'Summary',
118
- lines: [
119
- buildPanelLine(width, [
120
- [' Input ', DEFAULT_PANEL_PALETTE.label],
121
- [formatK(input), DEFAULT_PANEL_PALETTE.value],
122
- [' Limit ', DEFAULT_PANEL_PALETTE.label],
123
- [formatK(limit), DEFAULT_PANEL_PALETTE.info],
124
- [' Fill ', DEFAULT_PANEL_PALETTE.label],
125
- [`${pct}%`, overLimit ? DEFAULT_PANEL_PALETTE.bad : DEFAULT_PANEL_PALETTE.good],
126
- [' ', DEFAULT_PANEL_PALETTE.dim],
127
- ...buildStatusPill(pressureState, pressureLabel),
128
- ]),
129
- ],
130
- },
131
- {
132
- title: 'Usage',
133
- lines: [
134
- this._renderBar(width, barWidth, input, limit),
135
- this._renderSegLine(width, 'Input tokens', input, pct, fg),
136
- buildPanelLine(width, [[` ${formatK(input)} / ${formatK(limit)} tokens (${pct}%) Refreshes each LLM call`, DEFAULT_PANEL_PALETTE.dim]]),
137
- ],
138
- },
139
- {
140
- title: 'Maintenance',
141
- lines: this._renderMaintenance(width),
142
- },
143
- ],
144
- footerLines: [
145
- buildKeyboardHints(width, pressureState === 'good'
146
- ? [
147
- { keys: '/context', label: 'composition' },
148
- { keys: '/model', label: 'switch model' },
149
- ]
150
- : [
151
- { keys: '/compact', label: 'reduce context now' },
152
- { keys: '/context', label: 'composition' },
153
- { keys: '/model', label: 'larger window' },
154
- ], DEFAULT_PANEL_PALETTE),
155
- ],
156
- palette: DEFAULT_PANEL_PALETTE,
157
- });
158
- });
159
- }
160
-
161
- private _renderBar(width: number, barWidth: number, input: number, limit: number): Line {
162
- const filled = limit > 0 ? Math.min(barWidth, Math.round((input / limit) * barWidth)) : 0;
163
- const overLimit = limit > 0 && input > limit;
164
- const barFg = overLimit ? C.bad : C.convFg;
165
- return buildMeterLine(width, filled, barWidth, {
166
- filled: barFg,
167
- empty: C.empty,
168
- label: DEFAULT_PANEL_PALETTE.dim,
169
- });
170
- }
171
-
172
- private _renderSegLine(width: number, label: string, val: number, pct: number, fg: string): Line {
173
- const labelPadded = ` ${label}`.padEnd(22);
174
- const valStr = formatK(val).padStart(7);
175
- const pctStr = `${pct}%`.padStart(5);
176
- return buildStyledPanelLine(width, [
177
- { text: labelPadded, fg: C.label },
178
- { text: valStr, fg },
179
- { text: ' ', fg: DEFAULT_PANEL_PALETTE.dim },
180
- { text: pctStr, fg },
181
- ]);
182
- }
183
-
184
- private _refresh(): void {
185
- // Resolve the context window live so the panel tracks /model switches when a
186
- // getter is supplied; a plain number stays fixed at its provided value.
187
- this.snapshot.limit =
188
- typeof this.contextLimit === 'function' ? this.contextLimit() : (this.contextLimit ?? 0);
189
- // Prefer the live per-call input occupancy (cache-inclusive, matching the
190
- // Tokens panel and the auto-compaction threshold) when a getter is wired;
191
- // otherwise fall back to the cumulative usage input.
192
- const lastInput = this.getLastInputTokens?.();
193
- if (lastInput !== undefined) {
194
- this.snapshot.input = lastInput;
195
- } else {
196
- const usage = this.getUsage?.();
197
- if (usage) {
198
- this.snapshot.input = usage.input;
199
- }
200
- }
201
- this.markDirty();
202
- }
203
-
204
- private _renderMaintenance(width: number): Line[] {
205
- const status = evaluateSessionMaintenance({
206
- configManager: this.configManager,
207
- currentTokens: this.snapshot.input,
208
- contextWindow: this.snapshot.limit,
209
- sessionMemoryCount: this.sessionMemoryStore.list().length,
210
- session: this.sessionReadModel?.getSnapshot().session,
211
- });
212
- const lines: Line[] = [
213
- buildPanelLine(width, [[` ${status.summary}`, DEFAULT_PANEL_PALETTE.label]]),
214
- ];
215
- if (status.reasons[0]) {
216
- lines.push(buildPanelLine(width, [[` ${status.reasons[0]}`, DEFAULT_PANEL_PALETTE.dim]]));
217
- }
218
- if (status.guidanceMode !== 'off' && status.nextSteps[0]) {
219
- lines.push(buildGuidanceLine(width, status.nextSteps[0], 'open the suggested maintenance action', DEFAULT_PANEL_PALETTE));
220
- }
221
- return lines;
222
- }
223
-
224
- private _attachBus(): void {
225
- if (this.unsubs.length > 0) return;
226
- this.unsubs.push(this.turnEvents.on('TURN_COMPLETED', () => {
227
- this._refresh();
228
- }));
229
- this.unsubs.push(this.turnEvents.on('TURN_SUBMITTED', () => {
230
- this._refresh();
231
- }));
232
- }
233
-
234
- private _detachBus(): void {
235
- for (const unsub of this.unsubs) unsub();
236
- this.unsubs = [];
237
- }
238
- }