@pellux/goodvibes-tui 0.18.12 → 0.18.13

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 (157) hide show
  1. package/CHANGELOG.md +50 -0
  2. package/README.md +1 -1
  3. package/docs/foundation-artifacts/operator-contract.json +1 -1
  4. package/package.json +2 -2
  5. package/src/config/index.ts +1 -138
  6. package/src/config/subscription-providers.ts +1 -127
  7. package/src/core/conversation-rendering.ts +3 -3
  8. package/src/core/conversation.ts +176 -423
  9. package/src/core/history.ts +45 -0
  10. package/src/core/orchestrator.ts +3 -735
  11. package/src/core/system-message-router.ts +19 -58
  12. package/src/input/handler-content-actions.ts +2 -2
  13. package/src/input/handler-feed.ts +1 -1
  14. package/src/input/handler-modal-token-routes.ts +1 -1
  15. package/src/input/handler-ui-state.ts +1 -1
  16. package/src/input/handler.ts +1 -1
  17. package/src/input/search.ts +1 -1
  18. package/src/input/selection.ts +2 -2
  19. package/src/main.ts +1 -1
  20. package/src/panels/agent-inspector-panel.ts +3 -3
  21. package/src/panels/agent-logs-panel.ts +3 -3
  22. package/src/panels/approval-panel.ts +2 -2
  23. package/src/panels/automation-control-panel.ts +3 -3
  24. package/src/panels/base-panel.ts +14 -14
  25. package/src/panels/builtin/operations.ts +1 -1
  26. package/src/panels/builtin/session.ts +1 -1
  27. package/src/panels/builtin/shared.ts +3 -3
  28. package/src/panels/cockpit-panel.ts +2 -2
  29. package/src/panels/communication-panel.ts +3 -3
  30. package/src/panels/context-visualizer-panel.ts +2 -2
  31. package/src/panels/control-plane-panel.ts +3 -3
  32. package/src/panels/cost-tracker-panel.ts +3 -3
  33. package/src/panels/debug-panel.ts +2 -2
  34. package/src/panels/diff-panel.ts +2 -2
  35. package/src/panels/docs-panel.ts +1 -1
  36. package/src/panels/eval-panel.ts +2 -2
  37. package/src/panels/file-explorer-panel.ts +3 -3
  38. package/src/panels/file-preview-panel.ts +3 -3
  39. package/src/panels/forensics-panel.ts +2 -2
  40. package/src/panels/git-panel.ts +1 -1
  41. package/src/panels/hooks-panel.ts +3 -3
  42. package/src/panels/incident-review-panel.ts +1 -1
  43. package/src/panels/intelligence-panel.ts +2 -2
  44. package/src/panels/knowledge-panel.ts +1 -1
  45. package/src/panels/local-auth-panel.ts +2 -2
  46. package/src/panels/marketplace-panel.ts +1 -1
  47. package/src/panels/mcp-panel.ts +3 -3
  48. package/src/panels/memory-panel.ts +1 -1
  49. package/src/panels/ops-control-panel.ts +3 -3
  50. package/src/panels/ops-strategy-panel.ts +2 -2
  51. package/src/panels/orchestration-panel.ts +2 -2
  52. package/src/panels/panel-list-panel.ts +6 -6
  53. package/src/panels/plan-dashboard-panel.ts +1 -1
  54. package/src/panels/plugins-panel.ts +2 -2
  55. package/src/panels/policy-panel.ts +2 -2
  56. package/src/panels/polish.ts +3 -3
  57. package/src/panels/provider-accounts-panel.ts +2 -2
  58. package/src/panels/provider-health-panel.ts +2 -2
  59. package/src/panels/provider-stats-panel.ts +3 -3
  60. package/src/panels/remote-panel.ts +3 -3
  61. package/src/panels/routes-panel.ts +3 -3
  62. package/src/panels/sandbox-panel.ts +2 -2
  63. package/src/panels/schedule-panel.ts +1 -1
  64. package/src/panels/security-panel.ts +2 -2
  65. package/src/panels/services-panel.ts +2 -2
  66. package/src/panels/session-browser-panel.ts +2 -2
  67. package/src/panels/settings-sync-panel.ts +2 -2
  68. package/src/panels/skills-panel.ts +6 -6
  69. package/src/panels/subscription-panel.ts +2 -2
  70. package/src/panels/symbol-outline-panel.ts +3 -3
  71. package/src/panels/system-messages-panel.ts +4 -4
  72. package/src/panels/tasks-panel.ts +2 -2
  73. package/src/panels/thinking-panel.ts +3 -3
  74. package/src/panels/token-budget-panel.ts +1 -1
  75. package/src/panels/tool-inspector-panel.ts +3 -3
  76. package/src/panels/types.ts +5 -5
  77. package/src/panels/watchers-panel.ts +3 -3
  78. package/src/panels/welcome-panel.ts +1 -1
  79. package/src/panels/worktree-panel.ts +2 -2
  80. package/src/panels/wrfc-panel.ts +3 -3
  81. package/src/permissions/prompt.ts +3 -22
  82. package/src/plugins/loader.ts +15 -304
  83. package/src/renderer/agent-detail-modal.ts +1 -1
  84. package/src/renderer/autocomplete-overlay.ts +2 -2
  85. package/src/renderer/bookmark-modal.ts +1 -1
  86. package/src/renderer/bottom-bar.ts +2 -2
  87. package/src/renderer/buffer.ts +1 -1
  88. package/src/renderer/code-block.ts +2 -2
  89. package/src/renderer/compositor.ts +2 -2
  90. package/src/renderer/context-inspector.ts +1 -1
  91. package/src/renderer/conversation-layout.ts +2 -2
  92. package/src/renderer/conversation-overlays.ts +1 -1
  93. package/src/renderer/conversation-surface.ts +2 -2
  94. package/src/renderer/diff-view.ts +2 -2
  95. package/src/renderer/diff.ts +1 -1
  96. package/src/renderer/file-picker-overlay.ts +2 -2
  97. package/src/renderer/file-tree.ts +2 -2
  98. package/src/renderer/help-overlay.ts +1 -1
  99. package/src/renderer/history-search-overlay.ts +2 -2
  100. package/src/renderer/live-tail-modal.ts +1 -1
  101. package/src/renderer/markdown.ts +2 -2
  102. package/src/renderer/modal-factory.ts +3 -3
  103. package/src/renderer/model-picker-overlay.ts +2 -2
  104. package/src/renderer/overlay-box.ts +2 -2
  105. package/src/renderer/panel-composite.ts +1 -1
  106. package/src/renderer/panel-picker-overlay.ts +2 -2
  107. package/src/renderer/panel-tab-bar.ts +1 -1
  108. package/src/renderer/panel-workspace-bar.ts +1 -1
  109. package/src/renderer/process-indicator.ts +2 -2
  110. package/src/renderer/process-modal.ts +1 -1
  111. package/src/renderer/profile-picker-modal.ts +2 -2
  112. package/src/renderer/progress.ts +2 -2
  113. package/src/renderer/search-overlay.ts +2 -2
  114. package/src/renderer/selection-modal-overlay.ts +2 -2
  115. package/src/renderer/session-picker-modal.ts +2 -2
  116. package/src/renderer/settings-modal.ts +2 -2
  117. package/src/renderer/shell-surface.ts +1 -1
  118. package/src/renderer/system-message.ts +1 -1
  119. package/src/renderer/tab-strip.ts +2 -2
  120. package/src/renderer/text-layout.ts +1 -1
  121. package/src/renderer/thinking.ts +1 -1
  122. package/src/renderer/tool-call.ts +2 -2
  123. package/src/renderer/ui-factory.ts +2 -2
  124. package/src/runtime/bootstrap-command-context.ts +4 -5
  125. package/src/runtime/bootstrap-command-parts.ts +1 -3
  126. package/src/runtime/bootstrap-core.ts +3 -2
  127. package/src/runtime/bootstrap-hook-bridge.ts +15 -174
  128. package/src/runtime/bootstrap-shell.ts +4 -4
  129. package/src/runtime/bootstrap.ts +1 -1
  130. package/src/runtime/context.ts +4 -20
  131. package/src/runtime/diagnostics/panels/index.ts +1 -1
  132. package/src/runtime/diagnostics/panels/ops.ts +1 -1
  133. package/src/runtime/diagnostics/panels/panel-resources.ts +118 -0
  134. package/src/runtime/perf/panel-contracts.ts +32 -0
  135. package/src/runtime/perf/panel-health-monitor.ts +18 -0
  136. package/src/runtime/services.ts +4 -4
  137. package/src/runtime/store/domains/conversation.ts +1 -181
  138. package/src/runtime/store/domains/permissions.ts +1 -143
  139. package/src/runtime/store/helpers/reducers/conversation.ts +1 -228
  140. package/src/runtime/store/helpers/reducers/lifecycle.ts +1 -440
  141. package/src/runtime/store/selectors/index.ts +11 -6
  142. package/src/runtime/store/state.ts +12 -4
  143. package/src/runtime/ui-events.ts +46 -0
  144. package/src/runtime/ui-services.ts +1 -1
  145. package/src/shell/ui-openers.ts +1 -1
  146. package/src/tools/index.ts +1 -186
  147. package/src/types/grid.ts +48 -0
  148. package/src/utils/clipboard.ts +21 -0
  149. package/src/utils/splash-lines.ts +1 -1
  150. package/src/utils/terminal-width.ts +185 -0
  151. package/src/version.ts +1 -1
  152. package/src/daemon/facade-composition.ts +0 -398
  153. package/src/daemon/facade.ts +0 -638
  154. package/src/daemon/surface-policy.ts +0 -60
  155. package/src/daemon/types.ts +0 -191
  156. package/src/runtime/ui-read-models-core.ts +0 -95
  157. package/src/runtime/ui-read-models-operations.ts +0 -203
@@ -1,304 +1,15 @@
1
- import { existsSync, readdirSync, readFileSync, statSync } from 'fs';
2
- import { join, resolve, isAbsolute } from 'path';
3
- import { logger } from '@pellux/goodvibes-sdk/platform/utils/logger';
4
- import { createPluginAPI, type PluginAPIContext } from '@pellux/goodvibes-sdk/platform/plugins/api';
5
- import type { CommandRegistry } from '../input/command-registry.ts';
6
- import type { ProviderRegistry } from '@pellux/goodvibes-sdk/platform/providers/registry';
7
- import type { ToolRegistry } from '@pellux/goodvibes-sdk/platform/tools/registry';
8
- import type { RuntimeEventBus } from '@pellux/goodvibes-sdk/platform/runtime/events/index';
9
- import type { GatewayMethodCatalog } from '@pellux/goodvibes-sdk/platform/control-plane/index';
10
- import type { ChannelDeliveryRouter, ChannelPluginRegistry } from '@pellux/goodvibes-sdk/platform/channels/index';
11
- import type { MemoryEmbeddingProviderRegistry } from '@pellux/goodvibes-sdk/platform/state/index';
12
- import type { VoiceProviderRegistry } from '@pellux/goodvibes-sdk/platform/voice/index';
13
- import type { MediaProviderRegistry } from '@pellux/goodvibes-sdk/platform/media/index';
14
- import type { WebSearchProviderRegistry } from '@pellux/goodvibes-sdk/platform/web-search/index';
15
- import { summarizeError } from '@pellux/goodvibes-sdk/platform/utils/error-display';
16
-
17
- export interface PluginPathOptions {
18
- readonly cwd: string;
19
- readonly homeDir: string;
20
- }
21
-
22
- /**
23
- * Plugin search directories in precedence order.
24
- * Project-local plugins override global plugins with the same manifest name.
25
- */
26
- export function getUserPluginDirectory(options: PluginPathOptions): string {
27
- return join(options.homeDir, '.goodvibes', 'tui', 'plugins');
28
- }
29
-
30
- export function getPluginDirectories(options: PluginPathOptions): string[] {
31
- return [
32
- join(options.cwd, '.goodvibes', 'plugins'),
33
- join(options.cwd, '.goodvibes', 'tui', 'plugins'),
34
- getUserPluginDirectory(options),
35
- ];
36
- }
37
-
38
- /**
39
- * PluginManifest — The structure of a plugin's manifest.json.
40
- */
41
- export interface PluginManifest {
42
- /** Unique plugin identifier (no spaces, lowercase-kebab). */
43
- name: string;
44
- version: string;
45
- description: string;
46
- author?: string;
47
- /** Entry point relative to plugin directory. Defaults to "index.ts". */
48
- main?: string;
49
- /** Optional list of runtime event names the plugin subscribes to. */
50
- hooks?: string[];
51
- }
52
-
53
- /**
54
- * PluginEntryPoint — The exports expected from a plugin's entry file.
55
- */
56
- export interface PluginEntryPoint {
57
- /** Called once after the plugin is loaded. Receives the sandboxed PluginAPI. */
58
- init(api: ReturnType<typeof createPluginAPI>): void | Promise<void>;
59
- /** Optional: called when the plugin is activated (after init). */
60
- activate?(): void | Promise<void>;
61
- /** Optional: called when the plugin is deactivated (before cleanup). */
62
- deactivate?(): void | Promise<void>;
63
- }
64
-
65
- /**
66
- * LoadedPlugin — Runtime state of a single loaded plugin.
67
- */
68
- export interface LoadedPlugin {
69
- manifest: PluginManifest;
70
- /** Absolute path to the plugin directory. */
71
- pluginDir: string;
72
- /** Whether the plugin is currently active (init + activate completed). */
73
- active: boolean;
74
- /** Cleanup callbacks accumulated during plugin API use. */
75
- cleanup: Array<() => void>;
76
- /** The resolved entry point module (available after load). */
77
- entry?: PluginEntryPoint;
78
- }
79
-
80
- /**
81
- * DiscoveredPlugin — Result of scanning the plugins directory.
82
- */
83
- export interface DiscoveredPlugin {
84
- pluginDir: string;
85
- manifest: PluginManifest;
86
- }
87
-
88
- /**
89
- * discoverPlugins — Scan the configured plugin directories for valid plugin folders.
90
- * Each subdirectory with a readable manifest.json is a candidate.
91
- */
92
- function scanPluginDirectory(rootDir: string): DiscoveredPlugin[] {
93
- if (!existsSync(rootDir)) return [];
94
- const results: DiscoveredPlugin[] = [];
95
- let entries: string[];
96
- try {
97
- entries = readdirSync(rootDir);
98
- } catch (err) {
99
- logger.warn(`[plugins] Could not read plugins directory '${rootDir}': ${summarizeError(err)}`);
100
- return [];
101
- }
102
-
103
- for (const entry of entries) {
104
- const pluginDir = join(rootDir, entry);
105
- try {
106
- if (!statSync(pluginDir).isDirectory()) continue;
107
-
108
- const manifestPath = join(pluginDir, 'manifest.json');
109
- if (!existsSync(manifestPath)) continue;
110
-
111
- const raw = readFileSync(manifestPath, 'utf-8');
112
- const manifest = JSON.parse(raw) as PluginManifest;
113
-
114
- if (!manifest.name || !manifest.version) {
115
- logger.warn(`[plugins] ${entry}: manifest.json missing required fields (name, version)`);
116
- continue;
117
- }
118
-
119
- // Validate manifest field types
120
- if (typeof manifest.name !== 'string' || typeof manifest.version !== 'string') {
121
- logger.warn(`[plugins] ${entry}: manifest.json 'name' and 'version' must be strings`);
122
- continue;
123
- }
124
- if (manifest.main !== undefined) {
125
- if (typeof manifest.main !== 'string') {
126
- logger.warn(`[plugins] ${entry}: manifest.json 'main' must be a string`);
127
- continue;
128
- }
129
- if (isAbsolute(manifest.main)) {
130
- logger.warn(`[plugins] ${entry}: manifest.json 'main' must be a relative path, not absolute`);
131
- continue;
132
- }
133
- }
134
-
135
- results.push({ pluginDir, manifest });
136
- } catch (err) {
137
- logger.warn(`[plugins] ${entry}: failed to parse manifest — ${summarizeError(err)}`);
138
- }
139
- }
140
-
141
- return results;
142
- }
143
-
144
- export function discoverPlugins(options: PluginPathOptions): DiscoveredPlugin[] {
145
- const discovered = new Map<string, DiscoveredPlugin>();
146
- for (const dir of getPluginDirectories(options)) {
147
- for (const plugin of scanPluginDirectory(dir)) {
148
- if (!discovered.has(plugin.manifest.name)) {
149
- discovered.set(plugin.manifest.name, plugin);
150
- }
151
- }
152
- }
153
- return [...discovered.values()];
154
- }
155
-
156
- /**
157
- * PluginLoaderDeps — External dependencies injected into the loader.
158
- */
159
- export interface PluginLoaderDeps {
160
- runtimeBus: RuntimeEventBus;
161
- commandRegistry: CommandRegistry;
162
- providerRegistry: ProviderRegistry;
163
- toolRegistry: ToolRegistry;
164
- gatewayMethods: GatewayMethodCatalog;
165
- channelRegistry: ChannelPluginRegistry;
166
- channelDeliveryRouter: ChannelDeliveryRouter;
167
- memoryEmbeddingRegistry: MemoryEmbeddingProviderRegistry;
168
- voiceProviderRegistry: VoiceProviderRegistry;
169
- mediaProviderRegistry: MediaProviderRegistry;
170
- webSearchProviderRegistry: WebSearchProviderRegistry;
171
- /** Returns plugin-specific config given a plugin name. */
172
- getPluginConfig(name: string): Record<string, unknown>;
173
- /** Returns whether a plugin is enabled in persistent state. */
174
- isEnabled(name: string): boolean;
175
- }
176
-
177
- /**
178
- * loadPlugin — Load, init, and activate a single plugin.
179
- * Returns a LoadedPlugin on success, or null on failure.
180
- *
181
- * @param cacheBust - Optional timestamp suffix appended to the import URL to bypass
182
- * Bun's module cache. Pass `Date.now()` on reload to force fresh execution.
183
- */
184
- export async function loadPlugin(
185
- discovered: DiscoveredPlugin,
186
- deps: PluginLoaderDeps,
187
- cacheBust?: number,
188
- ): Promise<LoadedPlugin | null> {
189
- const { manifest, pluginDir } = discovered;
190
- const entryFile = manifest.main ?? 'index.ts';
191
- const entryPath = join(pluginDir, entryFile);
192
-
193
- // Path traversal guard: resolved entry must remain within pluginDir
194
- const resolvedEntry = resolve(entryPath);
195
- const resolvedPluginDir = resolve(pluginDir);
196
- if (!resolvedEntry.startsWith(resolvedPluginDir + '/') && resolvedEntry !== resolvedPluginDir) {
197
- logger.error(`[plugins] ${manifest.name}: path traversal detected — entry '${entryFile}' resolves outside plugin directory`);
198
- return null;
199
- }
200
-
201
- if (!existsSync(entryPath)) {
202
- logger.warn(`[plugins] ${manifest.name}: entry file not found: ${entryPath}`);
203
- return null;
204
- }
205
-
206
- // Trust notice — plugins run as trusted code (like VS Code extensions)
207
- logger.warn(`[plugins] Loading '${manifest.name}' — plugins are trusted code and run with full application access`);
208
-
209
- const loaded: LoadedPlugin = {
210
- manifest,
211
- pluginDir,
212
- active: false,
213
- cleanup: [],
214
- };
215
-
216
- try {
217
- // Dynamic import — Bun supports TS imports directly.
218
- // Append cache-bust query param on reload so Bun re-executes the module.
219
- const importPath = cacheBust !== undefined ? `${entryPath}?t=${cacheBust}` : entryPath;
220
- const mod = await import(importPath) as unknown;
221
-
222
- // Validate module shape before casting
223
- if (!mod || typeof mod !== 'object') {
224
- logger.warn(`[plugins] ${manifest.name}: entry file did not export a module object`);
225
- return null;
226
- }
227
- const modObj = mod as Record<string, unknown>;
228
- if (typeof modObj['init'] !== 'function') {
229
- logger.warn(`[plugins] ${manifest.name}: entry file must export an init() function`);
230
- return null;
231
- }
232
- if (modObj['activate'] !== undefined && typeof modObj['activate'] !== 'function') {
233
- logger.warn(`[plugins] ${manifest.name}: entry file 'activate' export must be a function`);
234
- return null;
235
- }
236
- if (modObj['deactivate'] !== undefined && typeof modObj['deactivate'] !== 'function') {
237
- logger.warn(`[plugins] ${manifest.name}: entry file 'deactivate' export must be a function`);
238
- return null;
239
- }
240
- const entry = mod as PluginEntryPoint;
241
-
242
- loaded.entry = entry;
243
-
244
- const ctx: PluginAPIContext = {
245
- pluginName: manifest.name,
246
- runtimeBus: deps.runtimeBus,
247
- commandRegistry: deps.commandRegistry as PluginAPIContext['commandRegistry'],
248
- providerRegistry: deps.providerRegistry,
249
- toolRegistry: deps.toolRegistry,
250
- gatewayMethods: deps.gatewayMethods,
251
- channelRegistry: deps.channelRegistry,
252
- channelDeliveryRouter: deps.channelDeliveryRouter,
253
- memoryEmbeddingRegistry: deps.memoryEmbeddingRegistry,
254
- voiceProviderRegistry: deps.voiceProviderRegistry,
255
- mediaProviderRegistry: deps.mediaProviderRegistry,
256
- webSearchProviderRegistry: deps.webSearchProviderRegistry,
257
- pluginConfig: deps.getPluginConfig(manifest.name),
258
- cleanup: loaded.cleanup,
259
- };
260
-
261
- const api = createPluginAPI(ctx);
262
-
263
- // Lifecycle: init
264
- await entry.init(api);
265
-
266
- // Lifecycle: activate
267
- if (typeof entry.activate === 'function') {
268
- await entry.activate();
269
- }
270
-
271
- loaded.active = true;
272
- logger.info(`[plugins] ${manifest.name} v${manifest.version} activated`);
273
- return loaded;
274
- } catch (err) {
275
- logger.error(`[plugins] ${manifest.name}: load failed — ${summarizeError(err)}`);
276
- // Run cleanup for anything that was registered before the error
277
- for (const fn of loaded.cleanup) {
278
- try { fn(); } catch { /* best-effort */ }
279
- }
280
- return null;
281
- }
282
- }
283
-
284
- /**
285
- * unloadPlugin — Deactivate a plugin and run all cleanup callbacks.
286
- */
287
- export async function unloadPlugin(plugin: LoadedPlugin): Promise<void> {
288
- if (!plugin.active) return;
289
-
290
- try {
291
- if (typeof plugin.entry?.deactivate === 'function') {
292
- await plugin.entry.deactivate();
293
- }
294
- } catch (err) {
295
- logger.warn(`[plugins] ${plugin.manifest.name}: deactivate threw — ${summarizeError(err)}`);
296
- }
297
-
298
- for (const fn of plugin.cleanup) {
299
- try { fn(); } catch { /* best-effort */ }
300
- }
301
- plugin.cleanup.length = 0;
302
- plugin.active = false;
303
- logger.info(`[plugins] ${plugin.manifest.name} deactivated`);
304
- }
1
+ export {
2
+ getUserPluginDirectory,
3
+ getPluginDirectories,
4
+ discoverPlugins,
5
+ loadPlugin,
6
+ unloadPlugin,
7
+ } from '@pellux/goodvibes-sdk/platform/plugins/loader';
8
+ export type {
9
+ PluginPathOptions,
10
+ PluginManifest,
11
+ PluginEntryPoint,
12
+ LoadedPlugin,
13
+ DiscoveredPlugin,
14
+ PluginLoaderDeps,
15
+ } from '@pellux/goodvibes-sdk/platform/plugins/loader';
@@ -1,6 +1,6 @@
1
1
  import { join } from 'path';
2
2
  import { readFile } from 'fs/promises';
3
- import { type Line } from '@pellux/goodvibes-sdk/platform/types/grid';
3
+ import { type Line } from '../types/grid.ts';
4
4
  import { ModalFactory } from './modal-factory.ts';
5
5
  import type { AgentManager } from '@pellux/goodvibes-sdk/platform/tools/agent/index';
6
6
  import type { AgentMessageBus } from '@pellux/goodvibes-sdk/platform/agents/message-bus';
@@ -1,5 +1,5 @@
1
- import { type Line } from '@pellux/goodvibes-sdk/platform/types/grid';
2
- import { fitDisplay, getDisplayWidth, truncateDisplay } from '@pellux/goodvibes-sdk/platform/utils/terminal-width';
1
+ import { type Line } from '../types/grid.ts';
2
+ import { fitDisplay, getDisplayWidth, truncateDisplay } from '../utils/terminal-width.ts';
3
3
  import type { AutocompleteEngine } from '../input/autocomplete.ts';
4
4
  import {
5
5
  createOverlayBorderLine,
@@ -7,7 +7,7 @@
7
7
  * Footer hints: [Up/Down] Navigate [Enter] Jump [o] Open File [d] Remove [Esc] Close
8
8
  */
9
9
 
10
- import { type Line } from '@pellux/goodvibes-sdk/platform/types/grid';
10
+ import { type Line } from '../types/grid.ts';
11
11
  import { ModalFactory } from './modal-factory.ts';
12
12
  import { BookmarkModal } from '../input/bookmark-modal.ts';
13
13
  import type { BookmarkEntry } from '@pellux/goodvibes-sdk/platform/bookmarks/manager';
@@ -1,5 +1,5 @@
1
- import { createEmptyLine, createStyledCell, type Line } from '@pellux/goodvibes-sdk/platform/types/grid';
2
- import { getDisplayWidth } from '@pellux/goodvibes-sdk/platform/utils/terminal-width';
1
+ import { createEmptyLine, createStyledCell, type Line } from '../types/grid.ts';
2
+ import { getDisplayWidth } from '../utils/terminal-width.ts';
3
3
 
4
4
  export interface BottomBarStyle {
5
5
  readonly fg: string;
@@ -1,4 +1,4 @@
1
- import { type Line, type Cell, createEmptyLine, createEmptyCell } from '@pellux/goodvibes-sdk/platform/types/grid';
1
+ import { type Line, type Cell, createEmptyLine, createEmptyCell } from '../types/grid.ts';
2
2
 
3
3
  /**
4
4
  * TerminalBuffer - Represents a 2D grid of styled cells.
@@ -1,6 +1,6 @@
1
- import { type Line, type Cell, createStyledCell, createEmptyLine } from '@pellux/goodvibes-sdk/platform/types/grid';
1
+ import { type Line, type Cell, createStyledCell, createEmptyLine } from '../types/grid.ts';
2
2
  import { UIFactory } from './ui-factory.ts';
3
- import { getDisplayWidth } from '@pellux/goodvibes-sdk/platform/utils/terminal-width';
3
+ import { getDisplayWidth } from '../utils/terminal-width.ts';
4
4
  import { LAYOUT } from './layout.ts';
5
5
  import { SyntaxHighlighter, type SyntaxToken as HLToken } from './syntax-highlighter.ts';
6
6
 
@@ -1,7 +1,7 @@
1
1
  import { TerminalBuffer } from './buffer.ts';
2
2
  import { DiffEngine } from './diff.ts';
3
- import { type Line, createStyledCell } from '@pellux/goodvibes-sdk/platform/types/grid';
4
- import { getDisplayWidth } from '@pellux/goodvibes-sdk/platform/utils/terminal-width';
3
+ import { type Line, createStyledCell } from '../types/grid.ts';
4
+ import { getDisplayWidth } from '../utils/terminal-width.ts';
5
5
  import type { SearchManager } from '../input/search.ts';
6
6
 
7
7
  export interface SelectionInfo {
@@ -1,4 +1,4 @@
1
- import { type Line } from '@pellux/goodvibes-sdk/platform/types/grid';
1
+ import { type Line } from '../types/grid.ts';
2
2
  import { ModalFactory } from './modal-factory.ts';
3
3
  import type { ConversationManager } from '../core/conversation';
4
4
  import { getOverlayContentBudget, getOverlaySurfaceMetrics, getStableOverlayContentRows } from './overlay-viewport.ts';
@@ -1,5 +1,5 @@
1
- import type { Line } from '@pellux/goodvibes-sdk/platform/types/grid';
2
- import { createEmptyLine } from '@pellux/goodvibes-sdk/platform/types/grid';
1
+ import type { Line } from '../types/grid.ts';
2
+ import { createEmptyLine } from '../types/grid.ts';
3
3
  import type { ConversationManager } from '../core/conversation';
4
4
 
5
5
  export interface ConversationViewportRequest {
@@ -1,4 +1,4 @@
1
- import type { Line } from '@pellux/goodvibes-sdk/platform/types/grid';
1
+ import type { Line } from '../types/grid.ts';
2
2
  import type { ConversationManager } from '../core/conversation';
3
3
  import type { CommandRegistry } from '../input/command-registry.ts';
4
4
  import type { InputHandler } from '../input/handler.ts';
@@ -1,5 +1,5 @@
1
- import { type Line, createEmptyLine, createStyledCell } from '@pellux/goodvibes-sdk/platform/types/grid';
2
- import { getDisplayWidth, truncateDisplay, wrapText } from '@pellux/goodvibes-sdk/platform/utils/terminal-width';
1
+ import { type Line, createEmptyLine, createStyledCell } from '../types/grid.ts';
2
+ import { getDisplayWidth, truncateDisplay, wrapText } from '../utils/terminal-width.ts';
3
3
  import { LAYOUT } from './layout.ts';
4
4
  import { GLYPHS } from './ui-primitives.ts';
5
5
 
@@ -1,6 +1,6 @@
1
- import { type Line, type Cell, createStyledCell } from '@pellux/goodvibes-sdk/platform/types/grid';
1
+ import { type Line, type Cell, createStyledCell } from '../types/grid.ts';
2
2
  import { UIFactory } from './ui-factory.ts';
3
- import { getDisplayWidth } from '@pellux/goodvibes-sdk/platform/utils/terminal-width';
3
+ import { getDisplayWidth } from '../utils/terminal-width.ts';
4
4
 
5
5
  /**
6
6
  * renderDiffView - Render a unified diff string as styled Line[].
@@ -1,5 +1,5 @@
1
1
  import { TerminalBuffer } from './buffer.ts';
2
- import { type Cell } from '@pellux/goodvibes-sdk/platform/types/grid';
2
+ import { type Cell } from '../types/grid.ts';
3
3
 
4
4
  /**
5
5
  * DiffEngine - Generates minimal ANSI updates between two buffers.
@@ -1,5 +1,5 @@
1
- import { type Line } from '@pellux/goodvibes-sdk/platform/types/grid';
2
- import { fitDisplay, getDisplayWidth, truncateDisplay } from '@pellux/goodvibes-sdk/platform/utils/terminal-width';
1
+ import { type Line } from '../types/grid.ts';
2
+ import { fitDisplay, getDisplayWidth, truncateDisplay } from '../utils/terminal-width.ts';
3
3
  import type { FilePickerModal } from '../input/file-picker.ts';
4
4
  import {
5
5
  createOverlayBoxLayout,
@@ -1,6 +1,6 @@
1
- import { type Line, createStyledCell } from '@pellux/goodvibes-sdk/platform/types/grid';
1
+ import { type Line, createStyledCell } from '../types/grid.ts';
2
2
  import { UIFactory } from './ui-factory.ts';
3
- import { getDisplayWidth } from '@pellux/goodvibes-sdk/platform/utils/terminal-width';
3
+ import { getDisplayWidth } from '../utils/terminal-width.ts';
4
4
 
5
5
  /** Color by file extension category. */
6
6
  function getFileColor(name: string): string {
@@ -4,7 +4,7 @@
4
4
  * Toggle with `?` key or `/help` command.
5
5
  */
6
6
 
7
- import { type Line } from '@pellux/goodvibes-sdk/platform/types/grid';
7
+ import { type Line } from '../types/grid.ts';
8
8
  import { ModalFactory } from './modal-factory.ts';
9
9
  import type { SlashCommand } from '../input/command-registry.ts';
10
10
  import type { KeybindingsManager } from '../input/keybindings.ts';
@@ -1,5 +1,5 @@
1
- import type { Line } from '@pellux/goodvibes-sdk/platform/types/grid';
2
- import { getDisplayWidth } from '@pellux/goodvibes-sdk/platform/utils/terminal-width';
1
+ import type { Line } from '../types/grid.ts';
2
+ import { getDisplayWidth } from '../utils/terminal-width.ts';
3
3
  import type { HistorySearch } from '../input/input-history.ts';
4
4
  import { createBottomBarLine, writeBottomBarText } from './bottom-bar.ts';
5
5
 
@@ -1,4 +1,4 @@
1
- import { type Line } from '@pellux/goodvibes-sdk/platform/types/grid';
1
+ import { type Line } from '../types/grid.ts';
2
2
  import { ModalFactory } from './modal-factory.ts';
3
3
  import type { ProcessManager } from '@pellux/goodvibes-sdk/platform/tools/shared/process-manager';
4
4
  import type { AgentManager } from '@pellux/goodvibes-sdk/platform/tools/agent/index';
@@ -1,7 +1,7 @@
1
- import { type Line, type Cell, createStyledCell } from '@pellux/goodvibes-sdk/platform/types/grid';
1
+ import { type Line, type Cell, createStyledCell } from '../types/grid.ts';
2
2
  import { UIFactory } from './ui-factory.ts';
3
3
  import { renderCodeBlock } from './code-block.ts';
4
- import { getDisplayWidth } from '@pellux/goodvibes-sdk/platform/utils/terminal-width';
4
+ import { getDisplayWidth } from '../utils/terminal-width.ts';
5
5
  import { LAYOUT } from './layout.ts';
6
6
 
7
7
  export interface MarkdownRenderOptions {
@@ -1,6 +1,6 @@
1
- import type { Line, Cell } from '@pellux/goodvibes-sdk/platform/types/grid';
2
- import { createStyledCell } from '@pellux/goodvibes-sdk/platform/types/grid';
3
- import { fitDisplay, getDisplayWidth, truncateDisplay, wrapText } from '@pellux/goodvibes-sdk/platform/utils/terminal-width';
1
+ import type { Line, Cell } from '../types/grid.ts';
2
+ import { createStyledCell } from '../types/grid.ts';
3
+ import { fitDisplay, getDisplayWidth, truncateDisplay, wrapText } from '../utils/terminal-width.ts';
4
4
  import {
5
5
  createOverlayBorderLine,
6
6
  createOverlayBoxLayout,
@@ -1,5 +1,5 @@
1
- import { type Line } from '@pellux/goodvibes-sdk/platform/types/grid';
2
- import { fitDisplay, getDisplayWidth, truncateDisplay } from '@pellux/goodvibes-sdk/platform/utils/terminal-width';
1
+ import { type Line } from '../types/grid.ts';
2
+ import { fitDisplay, getDisplayWidth, truncateDisplay } from '../utils/terminal-width.ts';
3
3
  import type { ModelPickerModal } from '../input/model-picker.ts';
4
4
  import { EFFORT_DESCRIPTIONS } from '@pellux/goodvibes-sdk/platform/providers/effort-levels';
5
5
  import { getQualityTier, getQualityTierFromScore } from '@pellux/goodvibes-sdk/platform/providers/model-benchmarks';
@@ -1,5 +1,5 @@
1
- import { createEmptyLine, createStyledCell, type Line } from '@pellux/goodvibes-sdk/platform/types/grid';
2
- import { getDisplayWidth } from '@pellux/goodvibes-sdk/platform/utils/terminal-width';
1
+ import { createEmptyLine, createStyledCell, type Line } from '../types/grid.ts';
2
+ import { getDisplayWidth } from '../utils/terminal-width.ts';
3
3
  import { getOverlayMaxWidth } from './overlay-viewport.ts';
4
4
  import { GLYPHS, UI_TONES } from './ui-primitives.ts';
5
5
 
@@ -1,4 +1,4 @@
1
- import type { Line } from '@pellux/goodvibes-sdk/platform/types/grid';
1
+ import type { Line } from '../types/grid.ts';
2
2
  import type { InputHandler } from '../input/handler.ts';
3
3
  import type { PanelManager } from '../panels/panel-manager.ts';
4
4
  import type { PanelCompositeData } from './compositor.ts';
@@ -1,5 +1,5 @@
1
- import { type Line } from '@pellux/goodvibes-sdk/platform/types/grid';
2
- import { fitDisplay, getDisplayWidth, truncateDisplay } from '@pellux/goodvibes-sdk/platform/utils/terminal-width';
1
+ import { type Line } from '../types/grid.ts';
2
+ import { fitDisplay, getDisplayWidth, truncateDisplay } from '../utils/terminal-width.ts';
3
3
  import type { PanelPicker } from '../panels/panel-picker.ts';
4
4
  import { CATEGORY_LABELS, CATEGORY_ORDER } from '../panels/panel-picker.ts';
5
5
  import type { PanelCategory, PanelRegistration } from '../panels/types.ts';
@@ -1,4 +1,4 @@
1
- import { type Line } from '@pellux/goodvibes-sdk/platform/types/grid';
1
+ import { type Line } from '../types/grid.ts';
2
2
  import type { Panel } from '../panels/types.ts';
3
3
  import { renderTabStrip } from './tab-strip.ts';
4
4
 
@@ -1,4 +1,4 @@
1
- import type { Line } from '@pellux/goodvibes-sdk/platform/types/grid';
1
+ import type { Line } from '../types/grid.ts';
2
2
  import type { WorkspaceTab } from '../panels/panel-manager.ts';
3
3
  import { renderTabStrip } from './tab-strip.ts';
4
4
 
@@ -1,6 +1,6 @@
1
- import { type Line } from '@pellux/goodvibes-sdk/platform/types/grid';
1
+ import { type Line } from '../types/grid.ts';
2
2
  import { UIFactory } from './ui-factory.ts';
3
- import { getDisplayWidth } from '@pellux/goodvibes-sdk/platform/utils/terminal-width';
3
+ import { getDisplayWidth } from '../utils/terminal-width.ts';
4
4
  import { GLYPHS } from './ui-primitives.ts';
5
5
 
6
6
  /** Truncate a string to fit within maxWidth display columns. */
@@ -1,4 +1,4 @@
1
- import { type Line } from '@pellux/goodvibes-sdk/platform/types/grid';
1
+ import { type Line } from '../types/grid.ts';
2
2
  import { ModalFactory } from './modal-factory.ts';
3
3
  import { formatDuration } from './modal-utils.ts';
4
4
  import type { ProcessManager } from '@pellux/goodvibes-sdk/platform/tools/shared/process-manager';
@@ -7,11 +7,11 @@
7
7
  * Footer hints: [Up/Down] Navigate [Enter] Load [d] Arm/Delete [s] Save current [Esc] Close
8
8
  */
9
9
 
10
- import type { Line } from '@pellux/goodvibes-sdk/platform/types/grid';
10
+ import type { Line } from '../types/grid.ts';
11
11
  import { ModalFactory } from './modal-factory.ts';
12
12
  import type { ProfilePickerModal } from '../input/profile-picker-modal.ts';
13
13
  import { formatTimestamp } from './modal-utils.ts';
14
- import { fitDisplay } from '@pellux/goodvibes-sdk/platform/utils/terminal-width';
14
+ import { fitDisplay } from '../utils/terminal-width.ts';
15
15
  import { getOverlaySurfaceMetrics, getStableOverlayContentRows } from './overlay-viewport.ts';
16
16
 
17
17
  // ---------------------------------------------------------------------------
@@ -1,6 +1,6 @@
1
- import { type Line } from '@pellux/goodvibes-sdk/platform/types/grid';
1
+ import { type Line } from '../types/grid.ts';
2
2
  import { UIFactory } from './ui-factory.ts';
3
- import { getDisplayWidth } from '@pellux/goodvibes-sdk/platform/utils/terminal-width';
3
+ import { getDisplayWidth } from '../utils/terminal-width.ts';
4
4
 
5
5
  // Rich spinner frames (used by progress indicators)
6
6
  export const SPINNER_FRAMES = ['⠋', '⠙', '⠹', '⠸', '⠼', '⠴', '⠦', '⠧', '⠇', '⠏'];
@@ -1,5 +1,5 @@
1
- import type { Line } from '@pellux/goodvibes-sdk/platform/types/grid';
2
- import { fitDisplay, getDisplayWidth, truncateDisplay } from '@pellux/goodvibes-sdk/platform/utils/terminal-width';
1
+ import type { Line } from '../types/grid.ts';
2
+ import { fitDisplay, getDisplayWidth, truncateDisplay } from '../utils/terminal-width.ts';
3
3
  import type { SearchManager } from '../input/search.ts';
4
4
  import { createBottomBarLine, writeBottomBarText } from './bottom-bar.ts';
5
5
 
@@ -1,5 +1,5 @@
1
- import { type Line } from '@pellux/goodvibes-sdk/platform/types/grid';
2
- import { fitDisplay, getDisplayWidth, truncateDisplay } from '@pellux/goodvibes-sdk/platform/utils/terminal-width';
1
+ import { type Line } from '../types/grid.ts';
2
+ import { fitDisplay, getDisplayWidth, truncateDisplay } from '../utils/terminal-width.ts';
3
3
  import type { SelectionModal } from '../input/selection-modal.ts';
4
4
  import {
5
5
  createOverlayBoxLayout,
@@ -7,11 +7,11 @@
7
7
  * Footer hints: [Enter] Load [d] Delete [Esc] Close
8
8
  */
9
9
 
10
- import type { Line } from '@pellux/goodvibes-sdk/platform/types/grid';
10
+ import type { Line } from '../types/grid.ts';
11
11
  import { ModalFactory } from './modal-factory.ts';
12
12
  import type { SessionPickerModal } from '../input/session-picker-modal.ts';
13
13
  import { formatTimestamp } from './modal-utils.ts';
14
- import { fitDisplay } from '@pellux/goodvibes-sdk/platform/utils/terminal-width';
14
+ import { fitDisplay } from '../utils/terminal-width.ts';
15
15
  import { getOverlaySurfaceMetrics, getStableOverlayContentRows } from './overlay-viewport.ts';
16
16
 
17
17
  // ---------------------------------------------------------------------------