@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.
Files changed (143) hide show
  1. package/CHANGELOG.md +124 -0
  2. package/README.md +1 -1
  3. package/package.json +1 -1
  4. package/src/core/context-usage.ts +53 -0
  5. package/src/core/conversation.ts +4 -6
  6. package/src/core/session-recovery.ts +2 -0
  7. package/src/core/turn-event-wiring.ts +1 -0
  8. package/src/input/commands/cost-runtime.ts +49 -0
  9. package/src/input/commands/eval.ts +4 -3
  10. package/src/input/commands/operator-runtime.ts +5 -1
  11. package/src/input/commands.ts +2 -0
  12. package/src/input/handler-feed-routes.ts +60 -26
  13. package/src/input/handler-feed.ts +17 -8
  14. package/src/input/handler-picker-routes.ts +18 -13
  15. package/src/input/handler-shortcuts.ts +51 -0
  16. package/src/input/handler-ui-state.ts +4 -0
  17. package/src/input/handler.ts +43 -6
  18. package/src/input/keybindings.ts +53 -8
  19. package/src/input/model-picker.ts +5 -0
  20. package/src/input/panel-integration-actions.ts +117 -1
  21. package/src/main.ts +5 -2
  22. package/src/panels/agent-inspector-panel.ts +139 -45
  23. package/src/panels/agent-inspector-shared.ts +147 -3
  24. package/src/panels/approval-panel.ts +204 -102
  25. package/src/panels/automation-control-panel.ts +370 -103
  26. package/src/panels/base-panel.ts +26 -2
  27. package/src/panels/builtin/agent.ts +28 -37
  28. package/src/panels/builtin/development.ts +40 -32
  29. package/src/panels/builtin/knowledge.ts +15 -6
  30. package/src/panels/builtin/operations.ts +178 -117
  31. package/src/panels/builtin/session.ts +35 -9
  32. package/src/panels/builtin/shared.ts +98 -6
  33. package/src/panels/cockpit-panel.ts +253 -75
  34. package/src/panels/cockpit-read-model.ts +2 -1
  35. package/src/panels/communication-panel.ts +159 -56
  36. package/src/panels/confirm-state.ts +8 -1
  37. package/src/panels/control-plane-panel.ts +354 -95
  38. package/src/panels/cost-tracker-panel.ts +243 -57
  39. package/src/panels/debug-panel.ts +347 -159
  40. package/src/panels/diff-panel.ts +257 -82
  41. package/src/panels/docs-panel.ts +166 -64
  42. package/src/panels/eval-panel.ts +336 -109
  43. package/src/panels/expandable-list-panel.ts +189 -0
  44. package/src/panels/file-explorer-panel.ts +238 -159
  45. package/src/panels/file-preview-panel.ts +141 -59
  46. package/src/panels/git-panel.ts +360 -191
  47. package/src/panels/hooks-panel.ts +181 -19
  48. package/src/panels/incident-review-panel.ts +252 -43
  49. package/src/panels/index.ts +0 -4
  50. package/src/panels/intelligence-panel.ts +310 -103
  51. package/src/panels/knowledge-graph-panel.ts +480 -58
  52. package/src/panels/local-auth-panel.ts +251 -33
  53. package/src/panels/marketplace-panel.ts +219 -33
  54. package/src/panels/memory-panel.ts +83 -81
  55. package/src/panels/ops-control-panel.ts +211 -32
  56. package/src/panels/ops-strategy-panel.ts +131 -45
  57. package/src/panels/orchestration-panel.ts +259 -67
  58. package/src/panels/panel-list-panel.ts +184 -136
  59. package/src/panels/panel-manager.ts +120 -13
  60. package/src/panels/plan-dashboard-panel.ts +507 -74
  61. package/src/panels/plugins-panel.ts +227 -34
  62. package/src/panels/policy-panel.ts +264 -55
  63. package/src/panels/polish-core.ts +162 -0
  64. package/src/panels/polish-tables.ts +258 -0
  65. package/src/panels/polish.ts +67 -149
  66. package/src/panels/project-planning-answer-actions.ts +134 -0
  67. package/src/panels/project-planning-panel.ts +84 -113
  68. package/src/panels/provider-health-panel.ts +438 -480
  69. package/src/panels/provider-health-routes.ts +203 -0
  70. package/src/panels/provider-health-tracker.ts +194 -6
  71. package/src/panels/provider-health-views.ts +560 -0
  72. package/src/panels/qr-panel.ts +136 -38
  73. package/src/panels/remote-panel.ts +123 -38
  74. package/src/panels/routes-panel.ts +87 -24
  75. package/src/panels/sandbox-panel.ts +232 -65
  76. package/src/panels/scrollable-list-panel.ts +143 -145
  77. package/src/panels/security-panel.ts +204 -52
  78. package/src/panels/services-panel.ts +174 -76
  79. package/src/panels/session-browser-panel.ts +101 -6
  80. package/src/panels/session-maintenance.ts +4 -122
  81. package/src/panels/settings-sync-panel.ts +346 -68
  82. package/src/panels/skills-panel.ts +157 -89
  83. package/src/panels/subscription-panel.ts +105 -34
  84. package/src/panels/symbol-outline-panel.ts +287 -154
  85. package/src/panels/system-messages-panel.ts +172 -38
  86. package/src/panels/tasks-panel.ts +348 -134
  87. package/src/panels/thinking-panel.ts +66 -32
  88. package/src/panels/token-budget-panel.ts +233 -46
  89. package/src/panels/tool-inspector-panel.ts +170 -54
  90. package/src/panels/types.ts +65 -4
  91. package/src/panels/work-plan-panel.ts +393 -39
  92. package/src/panels/worktree-panel.ts +239 -61
  93. package/src/panels/wrfc-panel-format.ts +133 -0
  94. package/src/panels/wrfc-panel.ts +146 -150
  95. package/src/renderer/compaction-preview.ts +2 -1
  96. package/src/renderer/compositor.ts +46 -43
  97. package/src/renderer/conversation-overlays.ts +25 -11
  98. package/src/renderer/footer-tips.ts +41 -0
  99. package/src/renderer/fullscreen-primitives.ts +22 -16
  100. package/src/renderer/help-overlay.ts +91 -14
  101. package/src/renderer/hint-grammar.ts +52 -0
  102. package/src/renderer/layout.ts +7 -7
  103. package/src/renderer/modal-factory.ts +23 -15
  104. package/src/renderer/model-picker-overlay.ts +30 -11
  105. package/src/renderer/model-workspace.ts +2 -3
  106. package/src/renderer/overlay-box.ts +16 -10
  107. package/src/renderer/panel-composite.ts +7 -20
  108. package/src/renderer/panel-workspace-bar.ts +14 -8
  109. package/src/renderer/process-indicator.ts +3 -1
  110. package/src/renderer/progress.ts +8 -6
  111. package/src/renderer/search-overlay.ts +27 -6
  112. package/src/renderer/session-picker-modal.ts +6 -4
  113. package/src/renderer/settings-modal.ts +70 -10
  114. package/src/renderer/shell-surface.ts +41 -15
  115. package/src/renderer/status-glyphs.ts +11 -9
  116. package/src/renderer/tab-strip.ts +148 -34
  117. package/src/renderer/theme.ts +60 -3
  118. package/src/renderer/ui-factory.ts +45 -36
  119. package/src/renderer/ui-primitives.ts +23 -2
  120. package/src/runtime/bootstrap-shell.ts +35 -18
  121. package/src/runtime/diagnostics/panels/index.ts +0 -3
  122. package/src/runtime/ui/model-picker/health-enrichment.ts +3 -0
  123. package/src/runtime/ui/model-picker/types.ts +4 -0
  124. package/src/shell/ui-openers.ts +14 -22
  125. package/src/utils/format-duration.ts +55 -0
  126. package/src/utils/format-number.ts +71 -0
  127. package/src/utils/splash-lines.ts +44 -3
  128. package/src/version.ts +1 -1
  129. package/src/work-plans/work-plan-store.ts +13 -0
  130. package/src/panels/agent-logs-panel.ts +0 -666
  131. package/src/panels/agent-logs-shared.ts +0 -129
  132. package/src/panels/context-visualizer-panel.ts +0 -214
  133. package/src/panels/forensics-panel.ts +0 -364
  134. package/src/panels/panel-picker.ts +0 -106
  135. package/src/panels/provider-account-snapshot.ts +0 -259
  136. package/src/panels/provider-accounts-panel.ts +0 -218
  137. package/src/panels/provider-stats-panel.ts +0 -366
  138. package/src/panels/schedule-panel.ts +0 -342
  139. package/src/panels/watchers-panel.ts +0 -193
  140. package/src/renderer/panel-picker-overlay.ts +0 -202
  141. package/src/renderer/panel-tab-bar.ts +0 -69
  142. package/src/runtime/diagnostics/panels/panel-resources.ts +0 -118
  143. package/src/runtime/diagnostics/panels/policy.ts +0 -177
@@ -0,0 +1,189 @@
1
+ import type { Line } from '../types/grid.ts';
2
+ import { createEmptyLine } from '../types/grid.ts';
3
+ import { ScrollableListPanel } from './scrollable-list-panel.ts';
4
+ import {
5
+ buildKeyboardHints,
6
+ buildPanelWorkspace,
7
+ resolveScrollablePanelSection,
8
+ } from './polish.ts';
9
+
10
+ // ---------------------------------------------------------------------------
11
+ // ExpandableListPanel<T>
12
+ // ---------------------------------------------------------------------------
13
+
14
+ /**
15
+ * A list panel with a built-in master → detail drill-down.
16
+ *
17
+ * Encapsulates the collapse/expand + detail-view pattern that was previously
18
+ * hand-rolled in git, tool-inspector, agent-inspector, approval, and wrfc
19
+ * panels: a scrollable list where pressing Enter/→ on a row opens a scrollable
20
+ * detail view for that item, and Esc/← returns to the list.
21
+ *
22
+ * Subclasses implement (in addition to the `ScrollableListPanel` contract):
23
+ * - `getDetailLines(item, width)` — the detail body for the expanded item.
24
+ *
25
+ * Optionally override:
26
+ * - `getDetailTitle(item)` — detail-view title (defaults to `this.name`).
27
+ * - `getListHints()` / `getDetailHints()` — footer keyboard hints per mode.
28
+ * - `renderListView(width, height)` — the list-mode body (defaults to
29
+ * `renderList` with the list hints footer).
30
+ *
31
+ * Do NOT override `render()`; it dispatches between list and detail modes.
32
+ */
33
+ export abstract class ExpandableListPanel<T> extends ScrollableListPanel<T> {
34
+ /** The item currently expanded into the detail view, or null in list mode. */
35
+ protected expandedItem: T | null = null;
36
+ /** First visible row of the detail view. */
37
+ protected detailScroll = 0;
38
+
39
+ /** Render the detail body lines for an expanded item. */
40
+ protected abstract getDetailLines(item: T, width: number): readonly Line[];
41
+
42
+ /** Title shown above the detail view. */
43
+ protected getDetailTitle(_item: T): string {
44
+ return this.name;
45
+ }
46
+
47
+ /** Keyboard hints shown in list mode. */
48
+ protected getListHints(): ReadonlyArray<{ keys: string; label: string }> {
49
+ return [
50
+ { keys: '↑/↓', label: 'move' },
51
+ { keys: 'Enter', label: 'open' },
52
+ ];
53
+ }
54
+
55
+ /** Keyboard hints shown in detail mode. */
56
+ protected getDetailHints(): ReadonlyArray<{ keys: string; label: string }> {
57
+ return [
58
+ { keys: '↑/↓', label: 'scroll' },
59
+ { keys: 'Esc', label: 'back' },
60
+ ];
61
+ }
62
+
63
+ protected isExpanded(): boolean {
64
+ return this.expandedItem !== null;
65
+ }
66
+
67
+ /** Expand the currently selected item into the detail view. */
68
+ protected expandSelected(): void {
69
+ const items = this.getItems();
70
+ const item = items[this.selectedIndex];
71
+ if (item === undefined) return;
72
+ this.expandedItem = item;
73
+ this.detailScroll = 0;
74
+ this.needsRender = true;
75
+ }
76
+
77
+ /** Collapse the detail view back to the list. */
78
+ protected collapse(): void {
79
+ if (this.expandedItem === null) return;
80
+ this.expandedItem = null;
81
+ this.detailScroll = 0;
82
+ this.needsRender = true;
83
+ }
84
+
85
+ // -------------------------------------------------------------------------
86
+ // Input
87
+ // -------------------------------------------------------------------------
88
+
89
+ handleInput(key: string): boolean {
90
+ if (this.expandedItem !== null) {
91
+ // Detail mode: scroll the detail body; Esc/← collapses.
92
+ if (this.lastError !== null) this.clearError();
93
+ switch (key) {
94
+ case 'escape':
95
+ case 'left':
96
+ case 'h':
97
+ this.collapse();
98
+ return true;
99
+ case 'up':
100
+ case 'k':
101
+ this.detailScroll = Math.max(0, this.detailScroll - 1);
102
+ this.needsRender = true;
103
+ return true;
104
+ case 'down':
105
+ case 'j':
106
+ this.detailScroll += 1;
107
+ this.needsRender = true;
108
+ return true;
109
+ case 'pageup':
110
+ this.detailScroll = Math.max(0, this.detailScroll - this.getPageSize());
111
+ this.needsRender = true;
112
+ return true;
113
+ case 'pagedown':
114
+ this.detailScroll += this.getPageSize();
115
+ this.needsRender = true;
116
+ return true;
117
+ case 'home':
118
+ case 'g':
119
+ this.detailScroll = 0;
120
+ this.needsRender = true;
121
+ return true;
122
+ default:
123
+ return false;
124
+ }
125
+ }
126
+
127
+ // List mode: Enter/→ expands; everything else is list navigation.
128
+ if (key === 'enter' || key === 'return' || key === 'right' || key === 'l') {
129
+ if (this.getItems().length === 0) return false;
130
+ this.expandSelected();
131
+ return true;
132
+ }
133
+ return super.handleInput(key);
134
+ }
135
+
136
+ handleScroll(deltaRows: number): boolean {
137
+ if (this.expandedItem !== null) {
138
+ const rows = Math.trunc(deltaRows);
139
+ if (rows === 0) return false;
140
+ this.detailScroll = Math.max(0, this.detailScroll + rows);
141
+ this.needsRender = true;
142
+ return true;
143
+ }
144
+ return super.handleScroll(deltaRows);
145
+ }
146
+
147
+ // -------------------------------------------------------------------------
148
+ // Render
149
+ // -------------------------------------------------------------------------
150
+
151
+ render(width: number, height: number): Line[] {
152
+ if (this.expandedItem !== null) {
153
+ return this.renderDetailView(width, height, this.expandedItem);
154
+ }
155
+ return this.renderListView(width, height);
156
+ }
157
+
158
+ /** List-mode body. Override for a custom header; defaults to renderList. */
159
+ protected renderListView(width: number, height: number): Line[] {
160
+ return this.renderList(width, height, { hints: this.getListHints() });
161
+ }
162
+
163
+ /** Detail-mode body — scrollable detail lines + standardized chrome. */
164
+ protected renderDetailView(width: number, height: number, item: T): Line[] {
165
+ this.needsRender = false;
166
+ const palette = this.getPalette();
167
+ const detailLines = [...this.getDetailLines(item, width)];
168
+ const footer = buildKeyboardHints(width, this.getDetailHints(), palette);
169
+
170
+ const resolved = resolveScrollablePanelSection(width, height, {
171
+ palette,
172
+ afterSections: [{ lines: [footer] }],
173
+ section: {
174
+ scrollableLines: detailLines,
175
+ scrollOffset: this.detailScroll,
176
+ appendWindowSummary: detailLines.length > 5 ? { dimColor: palette.dim } : undefined,
177
+ },
178
+ });
179
+ this.detailScroll = resolved.scrollOffset;
180
+
181
+ const lines = buildPanelWorkspace(width, height, {
182
+ title: this.getDetailTitle(item),
183
+ sections: [resolved.section, { lines: [footer] }],
184
+ palette,
185
+ });
186
+ while (lines.length < height) lines.push(createEmptyLine(width));
187
+ return lines.slice(0, height);
188
+ }
189
+ }