@pellux/goodvibes-tui 0.19.23 → 0.19.25

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 (72) hide show
  1. package/CHANGELOG.md +21 -0
  2. package/README.md +5 -5
  3. package/bin/goodvibes +5 -0
  4. package/bin/goodvibes-daemon +5 -0
  5. package/docs/foundation-artifacts/operator-contract.json +1 -1
  6. package/package.json +2 -2
  7. package/src/cli/completion.ts +89 -0
  8. package/src/cli/config-overrides.ts +159 -0
  9. package/src/cli/endpoints.ts +63 -0
  10. package/src/cli/entrypoint.ts +155 -0
  11. package/src/cli/help.ts +122 -0
  12. package/src/cli/index.ts +8 -0
  13. package/src/cli/management-commands.ts +576 -0
  14. package/src/cli/management.ts +693 -0
  15. package/src/cli/parser.ts +367 -0
  16. package/src/cli/status.ts +112 -0
  17. package/src/cli/tui-startup.ts +32 -0
  18. package/src/cli/types.ts +63 -0
  19. package/src/cli-flags.ts +17 -55
  20. package/src/config/index.ts +1 -1
  21. package/src/config/secrets.ts +44 -0
  22. package/src/core/conversation.ts +36 -13
  23. package/src/daemon/cli.ts +62 -11
  24. package/src/input/command-registry.ts +3 -0
  25. package/src/input/commands/guidance-runtime.ts +9 -4
  26. package/src/input/commands/local-runtime.ts +21 -7
  27. package/src/input/commands/local-setup.ts +31 -38
  28. package/src/input/commands/onboarding-runtime.ts +14 -0
  29. package/src/input/commands/runtime-services.ts +9 -0
  30. package/src/input/commands.ts +2 -0
  31. package/src/input/feed-context-factory.ts +8 -1
  32. package/src/input/handler-feed.ts +13 -8
  33. package/src/input/handler-interactions.ts +266 -0
  34. package/src/input/handler-modal-stack.ts +23 -3
  35. package/src/input/handler-modal-token-routes.ts +23 -1
  36. package/src/input/handler-onboarding.ts +696 -0
  37. package/src/input/handler-picker-routes.ts +15 -7
  38. package/src/input/handler-ui-state.ts +58 -0
  39. package/src/input/handler.ts +120 -246
  40. package/src/input/onboarding/handler-onboarding-routes.ts +105 -0
  41. package/src/input/onboarding/onboarding-wizard-apply.ts +211 -0
  42. package/src/input/onboarding/onboarding-wizard-constants.ts +148 -0
  43. package/src/input/onboarding/onboarding-wizard-external-surfaces.ts +712 -0
  44. package/src/input/onboarding/onboarding-wizard-helpers.ts +218 -0
  45. package/src/input/onboarding/onboarding-wizard-rules.ts +224 -0
  46. package/src/input/onboarding/onboarding-wizard-state.ts +354 -0
  47. package/src/input/onboarding/onboarding-wizard-steps.ts +642 -0
  48. package/src/input/onboarding/onboarding-wizard-types.ts +170 -0
  49. package/src/input/onboarding/onboarding-wizard.ts +594 -0
  50. package/src/main.ts +32 -39
  51. package/src/panels/builtin/operations.ts +0 -10
  52. package/src/panels/index.ts +0 -1
  53. package/src/panels/panel-manager.ts +6 -2
  54. package/src/renderer/conversation-overlays.ts +6 -0
  55. package/src/renderer/help-overlay.ts +1 -1
  56. package/src/renderer/onboarding/onboarding-wizard.ts +533 -0
  57. package/src/renderer/panel-composite.ts +42 -5
  58. package/src/renderer/panel-workspace-bar.ts +5 -1
  59. package/src/runtime/bootstrap-core.ts +1 -0
  60. package/src/runtime/bootstrap.ts +123 -0
  61. package/src/runtime/onboarding/apply.ts +685 -0
  62. package/src/runtime/onboarding/derivation.ts +495 -0
  63. package/src/runtime/onboarding/index.ts +7 -0
  64. package/src/runtime/onboarding/markers.ts +161 -0
  65. package/src/runtime/onboarding/snapshot.ts +400 -0
  66. package/src/runtime/onboarding/state.ts +140 -0
  67. package/src/runtime/onboarding/types.ts +402 -0
  68. package/src/runtime/onboarding/verify.ts +233 -0
  69. package/src/runtime/ui-services.ts +16 -0
  70. package/src/shell/ui-openers.ts +12 -2
  71. package/src/version.ts +1 -1
  72. package/src/panels/welcome-panel.ts +0 -64
package/src/main.ts CHANGED
@@ -1,13 +1,11 @@
1
1
  #!/usr/bin/env bun
2
2
  import { homedir } from 'node:os';
3
- import { join } from 'node:path';
4
3
  import { Compositor } from './renderer/compositor.ts';
5
4
  import { type Line } from './types/grid.ts';
6
5
  import { UIFactory } from './renderer/ui-factory.ts';
7
6
  import { Orchestrator } from './core/orchestrator';
8
7
  import { InputHandler } from './input/handler.ts';
9
8
  import { SelectionManager } from './input/selection.ts';
10
- import { ConfigManager } from './config/index.ts';
11
9
  import type { ContentPart } from '@pellux/goodvibes-sdk/platform/providers/interface';
12
10
  import { ToolRegistry } from '@pellux/goodvibes-sdk/platform/tools/registry';
13
11
  import { registerAllTools } from '@pellux/goodvibes-sdk/platform/tools/index';
@@ -32,7 +30,7 @@ import {
32
30
  } from './renderer/conversation-layout.ts';
33
31
  import { applyConversationOverlays } from './renderer/conversation-overlays.ts';
34
32
  import { buildPanelCompositeData } from './renderer/panel-composite.ts';
35
- import { configureActivityLogger, logger } from '@pellux/goodvibes-sdk/platform/utils/logger';
33
+ import { logger } from '@pellux/goodvibes-sdk/platform/utils/logger';
36
34
  import { registerBuiltinPanels } from './panels/builtin-panels.ts';
37
35
  import { renderPanelTabBar } from './renderer/panel-tab-bar.ts';
38
36
  import { bootstrapRuntime } from './runtime/bootstrap.ts';
@@ -50,9 +48,9 @@ import { handleBlockingShellInput, type PendingPermissionState } from './shell/b
50
48
  import { wireShellUiOpeners } from './shell/ui-openers.ts';
51
49
  import { deriveComposerState } from './core/composer-state.ts';
52
50
  import { buildPersistedSessionContext, formatReturnContextForDisplay, getReturnContextMode, maybeAssistReturnContextSummary } from '@pellux/goodvibes-sdk/platform/runtime/session-return-context';
53
- import { GlobalNetworkTransportInstaller } from '@pellux/goodvibes-sdk/platform/runtime/network/index';
54
51
  import { summarizeError } from '@pellux/goodvibes-sdk/platform/utils/error-display';
55
- import { parseCliFlags } from './cli-flags.ts';
52
+ import { prepareShellCliRuntime } from './cli/entrypoint.ts';
53
+ import { applyInitialTuiCliState } from './cli/tui-startup.ts';
56
54
 
57
55
  const ALT_SCREEN_ENTER = '\x1b[?1049h';
58
56
  const ALT_SCREEN_EXIT = '\x1b[?1049l';
@@ -66,41 +64,13 @@ const KEYBOARD_EXT_DISABLE = '\x1b[>4;0m' + '\x1b[?1l';
66
64
  const PASTE_ENABLE = '\x1b[?2004h';
67
65
  const PASTE_DISABLE = '\x1b[?2004l';
68
66
 
69
- type ShellEntrypointOwnership = {
70
- readonly workingDirectory: string;
71
- readonly homeDirectory: string;
72
- };
73
-
74
- function resolveShellEntrypointOwnership(): ShellEntrypointOwnership {
75
- return {
76
- workingDirectory: process.cwd(),
77
- homeDirectory: homedir(),
78
- };
79
- }
80
-
81
67
  async function main() {
82
68
  const stdout = process.stdout;
83
69
  const stdin = process.stdin;
84
- const {
85
- workingDirectory: bootstrapWorkingDir,
86
- homeDirectory: bootstrapHomeDirectory,
87
- } = resolveShellEntrypointOwnership();
88
- configureActivityLogger(join(bootstrapWorkingDir, '.goodvibes', 'logs'));
89
- const configManager = new ConfigManager({
90
- workingDir: bootstrapWorkingDir,
91
- homeDir: bootstrapHomeDirectory,
92
- surfaceRoot: 'tui',
93
- });
94
- new GlobalNetworkTransportInstaller().install(configManager);
95
-
96
- // Apply CLI flags — override settings.json before the provider registry is constructed
97
- const cliFlags = parseCliFlags(process.argv.slice(2), 'goodvibes');
98
- if (cliFlags.provider !== undefined) {
99
- configManager.set('provider.provider', cliFlags.provider);
100
- }
101
- if (cliFlags.model !== undefined) {
102
- configManager.set('provider.model', cliFlags.model);
103
- }
70
+ const { cli, configManager, bootstrapWorkingDir, bootstrapHomeDirectory } = await prepareShellCliRuntime(process.argv.slice(2), {
71
+ defaultWorkingDirectory: process.env['GOODVIBES_WORKING_DIR'] ?? process.cwd(),
72
+ homeDirectory: homedir(),
73
+ }, 'goodvibes');
104
74
 
105
75
  // ── Bootstrap runtime subsystems via bootstrapRuntime.
106
76
  const ctx: BootstrapContext = await bootstrapRuntime(stdout, {
@@ -288,7 +258,7 @@ async function main() {
288
258
  stdout.removeListener('resize', resizeHandler);
289
259
  process.removeListener('SIGINT', sigintHandler);
290
260
  process.removeListener('unhandledRejection', unhandledRejectionHandler);
291
- stdout.write(PASTE_DISABLE + KEYBOARD_EXT_DISABLE + MOUSE_DISABLE + CURSOR_SHOW + ALT_SCREEN_EXIT);
261
+ stdout.write(PASTE_DISABLE + KEYBOARD_EXT_DISABLE + MOUSE_DISABLE + CURSOR_SHOW + (cli.flags.noAltScreen ? '' : ALT_SCREEN_EXIT));
292
262
  stdin.setRawMode(false);
293
263
  process.exit(0);
294
264
  };
@@ -404,6 +374,20 @@ async function main() {
404
374
  favoritesStore: ctx.services.favoritesStore,
405
375
  providerRegistry: ctx.services.providerRegistry,
406
376
  },
377
+ platform: {
378
+ configManager: ctx.services.configManager,
379
+ localUserAuthManager: ctx.services.localUserAuthManager,
380
+ mcpRegistry: ctx.services.mcpRegistry,
381
+ serviceRegistry: ctx.services.serviceRegistry,
382
+ surfaceRegistry: ctx.services.surfaceRegistry,
383
+ subscriptionManager: ctx.services.subscriptionManager,
384
+ secretsManager: ctx.services.secretsManager,
385
+ tokenAuditor: ctx.services.tokenAuditor,
386
+ replayEngine: ctx.services.replayEngine,
387
+ webhookNotifier: ctx.services.webhookNotifier,
388
+ policyRuntimeState: ctx.services.policyRuntimeState,
389
+ externalServices: uiServices.platform.externalServices,
390
+ },
407
391
  shell: {
408
392
  bookmarkManager: ctx.services.bookmarkManager,
409
393
  keybindingsManager: ctx.services.keybindingsManager,
@@ -690,6 +674,15 @@ async function main() {
690
674
  render,
691
675
  });
692
676
 
677
+ applyInitialTuiCliState({
678
+ cli,
679
+ input,
680
+ commandRegistry,
681
+ commandContext,
682
+ shellPaths: ctx.services.shellPaths,
683
+ render,
684
+ });
685
+
693
686
  // --- Streaming speed + tool preview wiring ---
694
687
  const refreshGit = () => gitStatusProvider.refresh().then((info) => { lastGitInfoRef.value = info; render(); }).catch(() => { /* non-fatal */ });
695
688
  // Refresh git status after each turn completes or after tool results arrive
@@ -733,7 +726,7 @@ async function main() {
733
726
  stdin.setRawMode(true);
734
727
  stdin.resume();
735
728
  stdin.setEncoding('utf8');
736
- stdout.write(ALT_SCREEN_ENTER + CLEAR_SCREEN + CURSOR_HIDE + MOUSE_ENABLE + KEYBOARD_EXT_ENABLE + PASTE_ENABLE);
729
+ stdout.write((cli.flags.noAltScreen ? '' : ALT_SCREEN_ENTER) + CLEAR_SCREEN + CURSOR_HIDE + MOUSE_ENABLE + KEYBOARD_EXT_ENABLE + PASTE_ENABLE);
737
730
 
738
731
  stdin.on('data', (data: string) => {
739
732
  const blocking = handleBlockingShellInput({
@@ -1,7 +1,6 @@
1
1
  import type { PanelManager } from '../panel-manager.ts';
2
2
  import { CockpitPanel } from '../cockpit-panel.ts';
3
3
  import { ApprovalPanel } from '../approval-panel.ts';
4
- import { WelcomePanel } from '../welcome-panel.ts';
5
4
  import { PluginsPanel } from '../plugins-panel.ts';
6
5
  import { SkillsPanel } from '../skills-panel.ts';
7
6
  import { ServicesPanel } from '../services-panel.ts';
@@ -72,15 +71,6 @@ export function registerOperationsPanels(manager: PanelManager, deps: ResolvedBu
72
71
  factory: () => new ApprovalPanel(deps.policyRuntimeState),
73
72
  });
74
73
 
75
- manager.registerType({
76
- id: 'welcome',
77
- name: 'Welcome',
78
- icon: 'W',
79
- category: 'monitoring',
80
- description: 'Guided start surface for setup, security, marketplace, remote, and operator workflows',
81
- factory: () => new WelcomePanel(),
82
- });
83
-
84
74
  manager.registerType({
85
75
  id: 'plugins',
86
76
  name: 'Plugins',
@@ -41,7 +41,6 @@ export { SecurityPanel } from './security-panel.ts';
41
41
  export { MarketplacePanel } from './marketplace-panel.ts';
42
42
  export { SandboxPanel } from './sandbox-panel.ts';
43
43
  export { ApprovalPanel } from './approval-panel.ts';
44
- export { WelcomePanel } from './welcome-panel.ts';
45
44
  export { KnowledgePanel } from './knowledge-panel.ts';
46
45
  export { SystemMessagesPanel } from './system-messages-panel.ts';
47
46
  export { PanelListPanel } from './panel-list-panel.ts';
@@ -347,13 +347,17 @@ export class PanelManager {
347
347
 
348
348
  getWorkspaceTabs(): readonly WorkspaceTab[] {
349
349
  if (this._cachedWorkspaceTabs !== null) return this._cachedWorkspaceTabs;
350
+ // `active` = the currently selected tab in its own pane (independent of focus).
351
+ // `focused` = true only for the one tab in the globally focused pane that is active.
350
352
  const focusedPanelId = this.getActivePanel()?.id;
353
+ const topActivePanelId = this.topPane.panels[this.topPane.activeIndex]?.id;
354
+ const bottomActivePanelId = this.bottomPane.panels[this.bottomPane.activeIndex]?.id;
351
355
  const topTabs = this.topPane.panels.map((panel) => ({
352
356
  id: panel.id,
353
357
  name: panel.name,
354
358
  icon: panel.icon,
355
359
  pane: 'top' as const,
356
- active: panel.id === focusedPanelId,
360
+ active: panel.id === topActivePanelId,
357
361
  focused: panel.id === focusedPanelId,
358
362
  }));
359
363
  const bottomTabs = this.bottomPane.panels.map((panel) => ({
@@ -361,7 +365,7 @@ export class PanelManager {
361
365
  name: panel.name,
362
366
  icon: panel.icon,
363
367
  pane: 'bottom' as const,
364
- active: panel.id === focusedPanelId,
368
+ active: panel.id === bottomActivePanelId,
365
369
  focused: panel.id === focusedPanelId,
366
370
  }));
367
371
  const tabs = [...topTabs, ...bottomTabs] as WorkspaceTab[];
@@ -18,6 +18,7 @@ import { renderProfilePickerModal } from './profile-picker-modal.ts';
18
18
  import { renderBookmarkModal } from './bookmark-modal.ts';
19
19
  import { renderHelpOverlay, renderShortcutsOverlay } from './help-overlay.ts';
20
20
  import { renderAutocompleteOverlay } from './autocomplete-overlay.ts';
21
+ import { renderOnboardingWizard } from './onboarding/onboarding-wizard.ts';
21
22
  import { overlayViewportBottom, replaceViewportWithOverlay } from './conversation-layout.ts';
22
23
 
23
24
  export interface ConversationOverlayContext {
@@ -38,6 +39,11 @@ export function applyConversationOverlays(
38
39
  let next = viewport;
39
40
  const bottomDockInset = 1 + (input.searchManager.active || input.historySearch.active ? 1 : 0);
40
41
 
42
+ if (input.onboardingWizard.active) {
43
+ const lines = renderOnboardingWizard(input.onboardingWizard, conversationWidth, viewportHeight);
44
+ next = replaceViewportWithOverlay(lines, conversationWidth, viewportHeight);
45
+ }
46
+
41
47
  if (input.filePicker.active) {
42
48
  const lines = renderFilePickerOverlay(input.filePicker, conversationWidth, viewportHeight);
43
49
  next = overlayViewportBottom(next, lines, conversationWidth, viewportHeight, bottomDockInset);
@@ -69,7 +69,7 @@ export function renderHelpOverlay(
69
69
  // Each entry is [commandName, subcommandOrArgHint, description].
70
70
  // Commands not registered in the live registry are omitted at render time.
71
71
  const FEATURED_COMMANDS: Array<[name: string, argHint: string, desc: string]> = [
72
- ['setup', 'onboarding', 'Guided first-run review and environment posture'],
72
+ ['onboarding', '', 'Open the onboarding wizard with current settings preloaded'],
73
73
  ['cockpit', '', 'Unified runtime control room'],
74
74
  ['settings', '', 'Settings and config browser'],
75
75
  ['provider', '', 'Choose provider or model family'],