@pellux/goodvibes-agent 0.1.116 → 0.1.117

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 (168) hide show
  1. package/CHANGELOG.md +41 -663
  2. package/README.md +38 -52
  3. package/dist/package/main.js +37826 -35924
  4. package/docs/README.md +5 -4
  5. package/docs/{connected-services.md → connected-host.md} +18 -10
  6. package/docs/getting-started.md +41 -44
  7. package/docs/release-and-publishing.md +6 -4
  8. package/package.json +3 -3
  9. package/src/agent/behavior-discovery-summary.ts +1 -3
  10. package/src/agent/persona-discovery.ts +1 -3
  11. package/src/agent/persona-registry.ts +5 -3
  12. package/src/agent/reminder-schedule-format.ts +6 -6
  13. package/src/agent/reminder-schedule.ts +1 -1
  14. package/src/agent/routine-registry.ts +43 -4
  15. package/src/agent/routine-schedule-format.ts +6 -6
  16. package/src/agent/routine-schedule-promotion.ts +1 -1
  17. package/src/agent/routine-schedule-receipts.ts +1 -1
  18. package/src/agent/runtime-profile-starters.ts +3 -3
  19. package/src/agent/runtime-profile.ts +78 -0
  20. package/src/agent/skill-registry.ts +190 -13
  21. package/src/cli/agent-knowledge-command.ts +2 -2
  22. package/src/cli/agent-knowledge-format.ts +2 -2
  23. package/src/cli/agent-knowledge-runtime.ts +1 -1
  24. package/src/cli/bundle-command.ts +1 -1
  25. package/src/cli/entrypoint.ts +16 -7
  26. package/src/cli/help.ts +26 -19
  27. package/src/cli/local-library-command.ts +75 -21
  28. package/src/cli/management-commands.ts +7 -6
  29. package/src/cli/management.ts +6 -51
  30. package/src/cli/parser.ts +23 -2
  31. package/src/cli/profiles-command.ts +119 -1
  32. package/src/cli/routines-command.ts +139 -11
  33. package/src/cli/service-posture.ts +11 -11
  34. package/src/cli/status.ts +21 -25
  35. package/src/input/agent-workspace-access-command-editor-submission.ts +149 -0
  36. package/src/input/agent-workspace-access-command-editors.ts +170 -0
  37. package/src/input/agent-workspace-activation.ts +2 -1
  38. package/src/input/agent-workspace-basic-command-editor-submission.ts +345 -92
  39. package/src/input/agent-workspace-basic-command-editors.ts +480 -7
  40. package/src/input/agent-workspace-categories.ts +175 -15
  41. package/src/input/agent-workspace-channel-command-editor-submission.ts +49 -0
  42. package/src/input/agent-workspace-channel-command-editors.ts +47 -0
  43. package/src/input/agent-workspace-command-editor.ts +23 -1
  44. package/src/input/agent-workspace-delegation-editor-submission.ts +55 -0
  45. package/src/input/agent-workspace-editors.ts +27 -0
  46. package/src/input/agent-workspace-knowledge-command-editor-submission.ts +132 -0
  47. package/src/input/agent-workspace-knowledge-command-editors.ts +110 -0
  48. package/src/input/agent-workspace-learned-behavior.ts +67 -0
  49. package/src/input/agent-workspace-library-command-editor-submission.ts +50 -0
  50. package/src/input/agent-workspace-library-command-editors.ts +35 -0
  51. package/src/input/agent-workspace-mcp-command-editor-submission.ts +95 -0
  52. package/src/input/agent-workspace-memory-command-editor-submission.ts +232 -0
  53. package/src/input/agent-workspace-memory-command-editors.ts +180 -0
  54. package/src/input/agent-workspace-navigation.ts +45 -0
  55. package/src/input/agent-workspace-notify-editor-submission.ts +107 -0
  56. package/src/input/agent-workspace-operations-command-editor-submission.ts +146 -0
  57. package/src/input/agent-workspace-operations-command-editors.ts +119 -0
  58. package/src/input/agent-workspace-provider-command-editor-submission.ts +155 -0
  59. package/src/input/agent-workspace-provider-command-editors.ts +93 -0
  60. package/src/input/agent-workspace-requirements.ts +11 -0
  61. package/src/input/agent-workspace-secret-editor-submission.ts +153 -0
  62. package/src/input/agent-workspace-session-command-editor-submission.ts +199 -0
  63. package/src/input/agent-workspace-session-command-editors.ts +249 -0
  64. package/src/input/agent-workspace-setup.ts +24 -14
  65. package/src/input/agent-workspace-skill-bundle-command-editor-submission.ts +101 -0
  66. package/src/input/agent-workspace-skill-bundle-command-editors.ts +110 -0
  67. package/src/input/agent-workspace-snapshot.ts +50 -8
  68. package/src/input/agent-workspace-task-command-editor-submission.ts +61 -0
  69. package/src/input/agent-workspace-task-command-editors.ts +47 -0
  70. package/src/input/agent-workspace-types.ts +120 -0
  71. package/src/input/agent-workspace-voice-media.ts +1 -1
  72. package/src/input/agent-workspace-workplan-editor-submission.ts +153 -0
  73. package/src/input/agent-workspace.ts +47 -37
  74. package/src/input/command-registry.ts +1 -1
  75. package/src/input/commands/agent-runtime-profile-runtime.ts +89 -4
  76. package/src/input/commands/agent-skills-runtime.ts +76 -12
  77. package/src/input/commands/agent-workspace-runtime.ts +4 -3
  78. package/src/input/commands/brief-runtime.ts +38 -9
  79. package/src/input/commands/channels-runtime.ts +3 -3
  80. package/src/input/commands/compat-runtime.ts +32 -0
  81. package/src/input/commands/health-runtime.ts +22 -24
  82. package/src/input/commands/knowledge.ts +26 -5
  83. package/src/input/commands/local-provider-runtime.ts +7 -3
  84. package/src/input/commands/local-setup-review.ts +4 -14
  85. package/src/input/commands/mcp-runtime.ts +8 -12
  86. package/src/input/commands/operator-runtime.ts +8 -67
  87. package/src/input/commands/personas-runtime.ts +1 -1
  88. package/src/input/commands/platform-access-runtime.ts +7 -70
  89. package/src/input/commands/policy-dispatch.ts +1 -1
  90. package/src/input/commands/policy.ts +1 -5
  91. package/src/input/commands/product-runtime.ts +2 -2
  92. package/src/input/commands/qrcode-runtime.ts +6 -4
  93. package/src/input/commands/routines-runtime.ts +44 -6
  94. package/src/input/commands/runtime-services.ts +1 -14
  95. package/src/input/commands/security-runtime.ts +3 -8
  96. package/src/input/commands/session-content.ts +1 -1
  97. package/src/input/commands/session-workflow.ts +5 -14
  98. package/src/input/commands/shell-core.ts +8 -2
  99. package/src/input/commands/subscription-runtime.ts +1 -6
  100. package/src/input/commands/support-bundle-runtime.ts +53 -0
  101. package/src/input/commands/tasks-runtime.ts +2 -2
  102. package/src/input/commands.ts +4 -0
  103. package/src/input/feed-context-factory.ts +0 -1
  104. package/src/input/handler-content-actions.ts +0 -25
  105. package/src/input/handler-feed.ts +0 -2
  106. package/src/input/handler-interactions.ts +2 -31
  107. package/src/input/handler-onboarding.ts +29 -12
  108. package/src/input/handler-shortcuts.ts +1 -3
  109. package/src/input/handler.ts +4 -7
  110. package/src/input/keybindings.ts +9 -9
  111. package/src/input/mcp-workspace.ts +90 -26
  112. package/src/input/onboarding/handler-onboarding-routes.ts +3 -1
  113. package/src/input/onboarding/onboarding-wizard-apply.ts +49 -0
  114. package/src/input/onboarding/onboarding-wizard-helpers.ts +1 -1
  115. package/src/input/onboarding/onboarding-wizard-operator-steps.ts +81 -3
  116. package/src/input/onboarding/onboarding-wizard-steps.ts +14 -7
  117. package/src/input/onboarding/onboarding-wizard-types.ts +1 -0
  118. package/src/input/onboarding/onboarding-wizard.ts +19 -2
  119. package/src/input/profile-picker-modal.ts +2 -2
  120. package/src/input/settings-modal-agent-policy.ts +6 -6
  121. package/src/input/settings-modal-subscriptions.ts +3 -3
  122. package/src/input/settings-modal.ts +14 -14
  123. package/src/main.ts +0 -2
  124. package/src/panels/automation-control-panel.ts +3 -3
  125. package/src/panels/builtin/agent.ts +1 -1
  126. package/src/panels/builtin/operations.ts +2 -2
  127. package/src/panels/builtin/session.ts +26 -18
  128. package/src/panels/builtin/shared.ts +6 -6
  129. package/src/panels/project-planning-panel.ts +1 -1
  130. package/src/panels/provider-health-domains.ts +3 -3
  131. package/src/panels/qr-panel.ts +44 -20
  132. package/src/panels/subscription-panel.ts +3 -3
  133. package/src/panels/system-messages-panel.ts +2 -2
  134. package/src/panels/tasks-panel.ts +4 -4
  135. package/src/planning/project-planning-coordinator.ts +2 -2
  136. package/src/renderer/agent-workspace.ts +26 -5
  137. package/src/renderer/block-actions.ts +1 -3
  138. package/src/renderer/help-overlay.ts +13 -8
  139. package/src/renderer/mcp-workspace.ts +32 -13
  140. package/src/renderer/model-picker-overlay.ts +0 -1
  141. package/src/renderer/model-workspace.ts +0 -2
  142. package/src/renderer/onboarding/onboarding-wizard.ts +20 -4
  143. package/src/renderer/panel-picker-overlay.ts +1 -1
  144. package/src/renderer/profile-picker-modal.ts +2 -2
  145. package/src/renderer/settings-modal-helpers.ts +23 -23
  146. package/src/renderer/settings-modal.ts +18 -18
  147. package/src/renderer/system-message.ts +1 -1
  148. package/src/runtime/agent-runtime-events.ts +129 -0
  149. package/src/runtime/bootstrap-command-parts.ts +3 -2
  150. package/src/runtime/bootstrap-core.ts +4 -64
  151. package/src/runtime/bootstrap-shell.ts +42 -4
  152. package/src/runtime/bootstrap.ts +8 -27
  153. package/src/runtime/connected-host-auth.ts +42 -0
  154. package/src/runtime/diagnostics/panels/panel-resources.ts +1 -1
  155. package/src/runtime/index.ts +1 -5
  156. package/src/runtime/onboarding/apply.ts +213 -0
  157. package/src/runtime/onboarding/derivation.ts +5 -5
  158. package/src/runtime/onboarding/snapshot.ts +2 -2
  159. package/src/runtime/onboarding/types.ts +26 -1
  160. package/src/runtime/onboarding/verify.ts +81 -2
  161. package/src/runtime/operator-token-cleanup.ts +2 -2
  162. package/src/runtime/services.ts +27 -12
  163. package/src/shell/service-settings-sync.ts +7 -7
  164. package/src/shell/ui-openers.ts +27 -38
  165. package/src/tools/agent-local-registry-tool.ts +10 -4
  166. package/src/tools/agent-tool-policy-guard.ts +5 -7
  167. package/src/version.ts +1 -1
  168. package/src/cli/package-verification.ts +0 -274
@@ -34,7 +34,7 @@ import {
34
34
  type SettingsModalOpenOptions,
35
35
  type SubscriptionEntry,
36
36
  } from './settings-modal-types.ts';
37
- import { AGENT_EXTERNAL_DAEMON_SETTING_LOCK_REASON, isAgentHiddenSettingKey, isExternalDaemonOwnedSettingKey } from './settings-modal-agent-policy.ts';
37
+ import { AGENT_EXTERNAL_HOST_SETTING_LOCK_REASON, isAgentHiddenSettingKey, isExternalHostOwnedSettingKey } from './settings-modal-agent-policy.ts';
38
38
 
39
39
  export {
40
40
  SETTINGS_CATEGORIES,
@@ -50,7 +50,7 @@ export {
50
50
  type SettingsModalOpenOptions,
51
51
  type SubscriptionEntry,
52
52
  } from './settings-modal-types.ts';
53
- export { AGENT_EXTERNAL_DAEMON_SETTING_LOCK_REASON, isExternalDaemonOwnedSettingKey } from './settings-modal-agent-policy.ts';
53
+ export { AGENT_EXTERNAL_HOST_SETTING_LOCK_REASON, isExternalHostOwnedSettingKey } from './settings-modal-agent-policy.ts';
54
54
  export { isAgentHiddenSettingKey } from './settings-modal-agent-policy.ts';
55
55
 
56
56
  // ---------------------------------------------------------------------------
@@ -352,7 +352,7 @@ export class SettingsModal {
352
352
 
353
353
  const entry = this.getSelected();
354
354
  if (!entry || !this.configManager) return;
355
- if (this._blockExternalDaemonOwnedSetting(entry)) return;
355
+ if (this._blockExternalHostOwnedSetting(entry)) return;
356
356
 
357
357
  const { setting } = entry;
358
358
 
@@ -417,7 +417,7 @@ export class SettingsModal {
417
417
 
418
418
  const entry = this.getSelected();
419
419
  if (!entry || !this.configManager) return;
420
- if (this._blockExternalDaemonOwnedSetting(entry)) return;
420
+ if (this._blockExternalHostOwnedSetting(entry)) return;
421
421
  const { setting } = entry;
422
422
 
423
423
  if (setting.type === 'boolean') {
@@ -539,7 +539,7 @@ export class SettingsModal {
539
539
 
540
540
  const entry = this.getSelected();
541
541
  if (!entry || !this.configManager) return false;
542
- if (this._blockExternalDaemonOwnedSetting(entry)) {
542
+ if (this._blockExternalHostOwnedSetting(entry)) {
543
543
  this.editingMode = false;
544
544
  this.editBuffer = '';
545
545
  return false;
@@ -590,7 +590,7 @@ export class SettingsModal {
590
590
  if (this.editingMode || !this.configManager) return null;
591
591
  const entry = this.getSelected();
592
592
  if (!entry) return null;
593
- if (this._blockExternalDaemonOwnedSetting(entry)) return null;
593
+ if (this._blockExternalHostOwnedSetting(entry)) return null;
594
594
  const key = entry.setting.key as ConfigKey;
595
595
  this._setValue(key, entry.setting.default);
596
596
  if (isSecretConfigKey(key) && this.secretsManager) {
@@ -627,16 +627,16 @@ export class SettingsModal {
627
627
  const cat = rawCat as SettingsCategory;
628
628
  const currentValue = configManager.get(setting.key as ConfigKey);
629
629
  const resolved = getResolvedSettingLookup(configManager, setting.key as ConfigKey)?.entry;
630
- const daemonOwned = isExternalDaemonOwnedSettingKey(setting.key);
630
+ const hostOwned = isExternalHostOwnedSettingKey(setting.key);
631
631
  const entry: SettingEntry = {
632
632
  setting,
633
633
  currentValue,
634
634
  isDefault: currentValue === setting.default,
635
635
  effectiveSource: resolved?.effectiveSource,
636
- locked: daemonOwned || resolved?.locked,
636
+ locked: hostOwned || resolved?.locked,
637
637
  conflict: resolved?.conflict,
638
638
  sourceLabel: resolved?.sourceLabel,
639
- lockReason: daemonOwned ? AGENT_EXTERNAL_DAEMON_SETTING_LOCK_REASON : resolved?.lockReason,
639
+ lockReason: hostOwned ? AGENT_EXTERNAL_HOST_SETTING_LOCK_REASON : resolved?.lockReason,
640
640
  };
641
641
  if (this.groups.has(cat)) this.groups.get(cat)!.push(entry);
642
642
  if ((rawCat === 'controlPlane' || rawCat === 'httpListener' || rawCat === 'web') && this.groups.has('network')) {
@@ -745,8 +745,8 @@ export class SettingsModal {
745
745
 
746
746
  private _setValue(key: ConfigKey, value: unknown): void {
747
747
  if (!this.configManager) return;
748
- if (isExternalDaemonOwnedSettingKey(key)) {
749
- this.lastSettingEffectMessage = AGENT_EXTERNAL_DAEMON_SETTING_LOCK_REASON;
748
+ if (isExternalHostOwnedSettingKey(key)) {
749
+ this.lastSettingEffectMessage = AGENT_EXTERNAL_HOST_SETTING_LOCK_REASON;
750
750
  return;
751
751
  }
752
752
  // Diff previous value before writing — avoids false restart notices on no-op saves
@@ -787,9 +787,9 @@ export class SettingsModal {
787
787
  }
788
788
  }
789
789
 
790
- private _blockExternalDaemonOwnedSetting(entry: SettingEntry): boolean {
791
- if (!isExternalDaemonOwnedSettingKey(entry.setting.key)) return false;
792
- this.lastSettingEffectMessage = entry.lockReason ?? AGENT_EXTERNAL_DAEMON_SETTING_LOCK_REASON;
790
+ private _blockExternalHostOwnedSetting(entry: SettingEntry): boolean {
791
+ if (!isExternalHostOwnedSettingKey(entry.setting.key)) return false;
792
+ this.lastSettingEffectMessage = entry.lockReason ?? AGENT_EXTERNAL_HOST_SETTING_LOCK_REASON;
793
793
  return true;
794
794
  }
795
795
 
package/src/main.ts CHANGED
@@ -11,7 +11,6 @@ import { ToolRegistry } from '@pellux/goodvibes-sdk/platform/tools';
11
11
  import { registerAllTools } from '@pellux/goodvibes-sdk/platform/tools';
12
12
  import { FileUndoManager } from '@pellux/goodvibes-sdk/platform/state';
13
13
  import { PermissionManager } from '@pellux/goodvibes-sdk/platform/permissions';
14
- import { AcpManager } from '@pellux/goodvibes-sdk/platform/acp';
15
14
  import { PermissionPromptUI } from './permissions/prompt.ts';
16
15
  import { CommandRegistry } from './input/command-registry.ts';
17
16
  import type { CommandContext } from './input/command-registry.ts';
@@ -114,7 +113,6 @@ async function main() {
114
113
  sessionLineageTracker: ctx.services.sessionLineageTracker,
115
114
  idempotencyStore: ctx.services.idempotencyStore,
116
115
  });
117
- ctx.services.wrfcController.setPlanManager(ctx.services.planManager);
118
116
  let activeConversationWidth = stdout.columns || 80;
119
117
  conversation.setWidthProvider(() => activeConversationWidth);
120
118
  {
@@ -102,9 +102,9 @@ export class AutomationControlPanel extends ScrollableListPanel<AutomationRun> {
102
102
  sections: [{
103
103
  lines: buildEmptyState(
104
104
  width,
105
- ' Runtime store not wired.',
106
- 'This panel needs the shared runtime store to inspect automation jobs, runs, and deliveries.',
107
- [{ command: '/schedule list', summary: 'review automation from the shell while the runtime wiring is restored' }],
105
+ ' Connected-host automation state is unavailable.',
106
+ 'Use /schedule list for the supported Agent schedule summary. This deferred panel does not start or mutate automation.',
107
+ [{ command: '/schedule list', summary: 'review automation without starting hidden work' }],
108
108
  C,
109
109
  ),
110
110
  }],
@@ -80,7 +80,7 @@ export function registerAgentPanels(manager: PanelManager, deps: ResolvedBuiltin
80
80
  name: 'Schedule',
81
81
  icon: 'Z',
82
82
  category: 'agent',
83
- description: 'Read-only schedule posture from connected GoodVibes services; local Agent schedule mutation is blocked',
83
+ description: 'Read-only schedule posture from the connected GoodVibes host; local Agent schedule mutation is blocked',
84
84
  factory: () => new SchedulePanel(requireAutomationManager(deps)),
85
85
  });
86
86
  }
@@ -45,7 +45,7 @@ export function registerOperationsPanels(manager: PanelManager, deps: ResolvedBu
45
45
  name: 'Automation',
46
46
  icon: 'M',
47
47
  category: 'monitoring',
48
- description: 'Read-only automation jobs, runs, deliveries, and failure posture from connected GoodVibes services',
48
+ description: 'Read-only automation jobs, runs, deliveries, and failure posture from the connected GoodVibes host',
49
49
  factory: () => new AutomationControlPanel(ui.readModels.automation),
50
50
  });
51
51
 
@@ -81,7 +81,7 @@ export function registerOperationsPanels(manager: PanelManager, deps: ResolvedBu
81
81
  name: 'Tasks',
82
82
  icon: 'J',
83
83
  category: 'monitoring',
84
- description: 'Queued, running, blocked, failed, and completed task summaries from connected GoodVibes services',
84
+ description: 'Queued, running, blocked, failed, and completed task summaries from the connected GoodVibes host',
85
85
  factory: () => new TasksPanel(ui.readModels.tasks),
86
86
  });
87
87
 
@@ -1,5 +1,5 @@
1
1
  import { networkInterfaces } from 'node:os';
2
- import { readFileSync } from 'node:fs';
2
+ import { existsSync, readFileSync } from 'node:fs';
3
3
  import type { PanelManager } from '../panel-manager.ts';
4
4
  import { SessionBrowserPanel } from '../session-browser-panel.ts';
5
5
  import { QrPanel } from '../qr-panel.ts';
@@ -9,8 +9,6 @@ import { TokenBudgetPanel } from '../token-budget-panel.ts';
9
9
  import type { ResolvedBuiltinPanelDeps } from './shared.ts';
10
10
  import { requireUiServices } from './shared.ts';
11
11
  import {
12
- getOrCreateCompanionToken,
13
- regenerateCompanionToken,
14
12
  buildCompanionConnectionInfo,
15
13
  } from '@pellux/goodvibes-sdk/platform/pairing';
16
14
  import { copyToClipboard } from '../../utils/clipboard.ts';
@@ -42,6 +40,18 @@ function readBootstrapPassword(credentialPath: string): string | undefined {
42
40
  return undefined;
43
41
  }
44
42
 
43
+ function readOperatorToken(tokenPath: string): string | null {
44
+ if (!existsSync(tokenPath)) return null;
45
+ try {
46
+ const parsed = JSON.parse(readFileSync(tokenPath, 'utf-8')) as unknown;
47
+ if (!parsed || typeof parsed !== 'object' || Array.isArray(parsed)) return null;
48
+ const token = (parsed as Record<string, unknown>)['token'];
49
+ return typeof token === 'string' && token.trim().length > 0 ? token : null;
50
+ } catch {
51
+ return null;
52
+ }
53
+ }
54
+
45
55
  export function registerSessionPanels(manager: PanelManager, deps: ResolvedBuiltinPanelDeps): void {
46
56
  manager.registerType({
47
57
  id: 'qr-code',
@@ -51,28 +61,26 @@ export function registerSessionPanels(manager: PanelManager, deps: ResolvedBuilt
51
61
  description: 'QR code for companion app pairing — scan to connect a mobile or desktop companion',
52
62
  factory: () => {
53
63
  if (!deps.daemonHomeDir) throw new Error('daemonHomeDir must be provided to the session panel factory via BuiltinPanelDeps');
54
- const daemonHomeDir = deps.daemonHomeDir;
55
- const tokenRecord = getOrCreateCompanionToken(GOODVIBES_AGENT_PAIRING_SURFACE, { daemonHomeDir });
64
+ const token = readOperatorToken(`${deps.daemonHomeDir}/operator-tokens.json`);
56
65
  const daemonPort = deps.configManager.get('controlPlane.port');
57
66
  const daemonHost = String(process.env['GOODVIBES_DAEMON_HOST'] ?? getLocalNetworkIp());
58
67
  const daemonUrl = `http://${daemonHost}:${daemonPort}`;
59
68
  const bootstrapPassword = readBootstrapPassword(deps.localUserAuthManager.getBootstrapCredentialPath());
60
- const connectionInfo = buildCompanionConnectionInfo({
61
- daemonUrl,
62
- token: tokenRecord.token,
63
- password: bootstrapPassword,
64
- surface: GOODVIBES_AGENT_PAIRING_SURFACE,
65
- });
66
- const regenerate = (): typeof connectionInfo => {
67
- const newRecord = regenerateCompanionToken({ daemonHomeDir });
68
- return buildCompanionConnectionInfo({
69
+ const connectionInfo = token
70
+ ? buildCompanionConnectionInfo({
69
71
  daemonUrl,
70
- token: newRecord.token,
72
+ token,
71
73
  password: bootstrapPassword,
72
74
  surface: GOODVIBES_AGENT_PAIRING_SURFACE,
73
- });
74
- };
75
- return new QrPanel(connectionInfo, regenerate, copyToClipboard);
75
+ })
76
+ : {
77
+ url: daemonUrl,
78
+ token: '',
79
+ username: 'admin',
80
+ ...(bootstrapPassword !== undefined ? { password: bootstrapPassword } : {}),
81
+ surface: GOODVIBES_AGENT_PAIRING_SURFACE,
82
+ };
83
+ return new QrPanel(connectionInfo, undefined, copyToClipboard);
76
84
  },
77
85
  });
78
86
 
@@ -80,13 +80,13 @@ export interface BuiltinPanelDeps {
80
80
  tokenAuditor: ApiTokenAuditor;
81
81
  /** Shared component-health monitor for rate-limited panels and diagnostics. */
82
82
  componentHealthMonitor: ComponentHealthMonitor;
83
- /** Shared worktree registry for worktree surfaces. */
83
+ /** Copied shell dependency kept inert in Agent; build worktree UX belongs to GoodVibes TUI delegation. */
84
84
  worktreeRegistry: WorktreeRegistry;
85
- /** Shared sandbox session registry for sandbox surfaces and tools. */
85
+ /** Isolation session registry used by MCP internals; Agent does not expose local execution-isolation command UX. */
86
86
  sandboxSessionRegistry: SandboxSessionRegistry;
87
87
  /**
88
- * Resolved daemon home directory (e.g. `~/.goodvibes/daemon`) — owned by the composition root
89
- * and passed explicitly so panel factories do not discover cwd/home implicitly.
88
+ * Resolved connected-host token directory (e.g. `~/.goodvibes/daemon`) — owned by the
89
+ * composition root and passed explicitly so panel factories do not discover cwd/home implicitly.
90
90
  */
91
91
  daemonHomeDir?: string;
92
92
  /** Session memory store for context and token budget panels. */
@@ -103,7 +103,7 @@ export interface BuiltinPanelDeps {
103
103
  workPlanStore?: import('../../work-plans/work-plan-store.ts').WorkPlanStore;
104
104
  /** Shared system-messages panel instance attached from boot so low-priority chatter stays out of conversation. */
105
105
  systemMessagesPanel?: import('../system-messages-panel.ts').SystemMessagesPanel;
106
- /** Explicit UI-facing runtime services for agent/process/WRFC/remote panels and modals. */
106
+ /** Explicit UI-facing runtime services for operator panels and modals. */
107
107
  uiServices?: UiRuntimeServices;
108
108
  /** Shared plugin manager observer for plugin and security panels. */
109
109
  pluginManager?: PluginManagerObserver;
@@ -240,7 +240,7 @@ export function requireAutomationManager(deps: BuiltinPanelDeps): AutomationMana
240
240
 
241
241
  export function requireUiServices(deps: BuiltinPanelDeps): UiRuntimeServices {
242
242
  if (!deps.uiServices) {
243
- throw new Error('UI runtime services must be wired at bootstrap for agent, process, WRFC, and remote panels.');
243
+ throw new Error('UI runtime services must be wired at bootstrap for operator panels.');
244
244
  }
245
245
  return deps.uiServices;
246
246
  }
@@ -600,7 +600,7 @@ export class ProjectPlanningPanel extends BasePanel {
600
600
  return;
601
601
  }
602
602
  if (!this.submitAnswer) {
603
- this.setError('Planning answer submission is not wired in this runtime.');
603
+ this.setError('Planning answer submission is unavailable in this Agent runtime. Return to the composer and answer there.');
604
604
  this.requestRender();
605
605
  return;
606
606
  }
@@ -46,11 +46,11 @@ export function buildProviderHealthDomainSummaries(
46
46
  name: 'auth',
47
47
  level: auth.bootstrapCredentialPresent ? 'warn' : 'info',
48
48
  summary: auth.bootstrapCredentialPresent
49
- ? 'connected-service bootstrap credential visible in local compatibility state'
50
- : 'connected-service auth administration belongs outside Agent',
49
+ ? 'connected-host bootstrap credential visible in local compatibility state'
50
+ : 'connected-host auth administration belongs outside Agent',
51
51
  next: '/auth review',
52
52
  details: [
53
- 'GoodVibes Agent does not create, delete, rotate, revoke, or clear connected-service auth users or sessions.',
53
+ 'GoodVibes Agent does not create, delete, rotate, revoke, or clear connected-host auth users or sessions.',
54
54
  `${auth.userCount} compatibility user record(s) and ${auth.sessionCount} session record(s) are visible for diagnostics only.`,
55
55
  auth.bootstrapCredentialPresent ? 'Bootstrap cleanup must be done in the owning GoodVibes host.' : '',
56
56
  ].filter(Boolean),
@@ -79,13 +79,15 @@ export class QrPanel extends BasePanel {
79
79
  this.connectionInfo = this.regenerateToken();
80
80
  this.lastStatus = 'Token regenerated.';
81
81
  } else {
82
- this.lastStatus = 'Regeneration not available.';
82
+ this.lastStatus = 'Token rotation belongs to the connected host.';
83
83
  }
84
84
  this.markDirty();
85
85
  return true;
86
86
  }
87
87
  if (key === 'c') {
88
- if (this.copyToClipboard) {
88
+ if (!this.connectionInfo.token) {
89
+ this.lastStatus = 'No connected-host token is available to copy.';
90
+ } else if (this.copyToClipboard) {
89
91
  this.copyToClipboard(this.connectionInfo.token);
90
92
  this.lastStatus = 'Token copied to clipboard.';
91
93
  } else {
@@ -134,18 +136,36 @@ export class QrPanel extends BasePanel {
134
136
  lines.push(createEmptyLine(width));
135
137
 
136
138
  // ── QR code ────────────────────────────────────────────────────────────
137
- const payload = encodeConnectionPayload({
138
- url: this.connectionInfo.url,
139
- token: this.connectionInfo.token,
140
- username: this.connectionInfo.username,
141
- ...(this.connectionInfo.password !== undefined ? { password: this.connectionInfo.password } : {}),
142
- version: this.connectionInfo.version ?? '0.0.0',
143
- surface: this.connectionInfo.surface ?? GOODVIBES_AGENT_PAIRING_SURFACE,
144
- });
145
- const matrix = generateQrMatrix(payload);
146
- const qrLines = renderQrMatrix(matrix.modules, width, { fg: C.qrFg, bg: C.qrBg });
147
- for (const qrLine of qrLines) {
148
- lines.push(qrLine);
139
+ if (this.connectionInfo.token) {
140
+ const payload = encodeConnectionPayload({
141
+ url: this.connectionInfo.url,
142
+ token: this.connectionInfo.token,
143
+ username: this.connectionInfo.username,
144
+ ...(this.connectionInfo.password !== undefined ? { password: this.connectionInfo.password } : {}),
145
+ version: this.connectionInfo.version ?? '0.0.0',
146
+ surface: this.connectionInfo.surface ?? GOODVIBES_AGENT_PAIRING_SURFACE,
147
+ });
148
+ const matrix = generateQrMatrix(payload);
149
+ const qrLines = renderQrMatrix(matrix.modules, width, { fg: C.qrFg, bg: C.qrBg });
150
+ for (const qrLine of qrLines) {
151
+ lines.push(qrLine);
152
+ }
153
+ } else {
154
+ lines.push(
155
+ buildPanelLine(width, [
156
+ [' Pairing unavailable ', C.hint],
157
+ ]),
158
+ );
159
+ lines.push(
160
+ buildPanelLine(width, [
161
+ [' Connected-host operator token is missing. Agent does not create or rotate host auth tokens. ', C.dim],
162
+ ]),
163
+ );
164
+ lines.push(
165
+ buildPanelLine(width, [
166
+ [' Start or repair the owning GoodVibes host, then reopen this panel. ', C.dim],
167
+ ]),
168
+ );
149
169
  }
150
170
 
151
171
  lines.push(createEmptyLine(width));
@@ -160,12 +180,16 @@ export class QrPanel extends BasePanel {
160
180
  }
161
181
 
162
182
  // ── Hints ──────────────────────────────────────────────────────────────
163
- const hintsLine = buildPanelLine(width, [
164
- [' r ', C.hint],
165
- ['regenerate ', C.dim],
166
- [' c ', C.hint],
167
- ['copy token', C.dim],
168
- ]);
183
+ const hintParts: Array<[string, string]> = this.connectionInfo.token
184
+ ? [
185
+ [' c ', C.hint],
186
+ ['copy token', C.dim],
187
+ ]
188
+ : [
189
+ [' h ', C.hint],
190
+ ['host auth required', C.dim],
191
+ ];
192
+ const hintsLine = buildPanelLine(width, hintParts);
169
193
 
170
194
  // Push hints at the bottom if we have room, otherwise append after QR
171
195
  const remaining = height - lines.length;
@@ -79,8 +79,8 @@ export class SubscriptionPanel extends ScrollableListPanel<SubscriptionRow> {
79
79
  protected override getEmptyStateActions() {
80
80
  return [
81
81
  { command: '/subscription login openai start --yes', summary: 'start the first-class OpenAI subscription flow' },
82
- { command: '/login provider <name> start --yes', summary: 'use the front-door auth flow for supported providers' },
83
- { command: '/auth review', summary: 'inspect connected-service auth posture without exposing token values' },
82
+ { command: '/subscription login <provider> finish <code> --yes', summary: 'finish a pending provider subscription login' },
83
+ { command: '/auth review', summary: 'inspect connected-host auth posture without exposing token values' },
84
84
  ];
85
85
  }
86
86
 
@@ -196,7 +196,7 @@ export class SubscriptionPanel extends ScrollableListPanel<SubscriptionRow> {
196
196
  const emptyLines = buildEmptyState(
197
197
  width,
198
198
  this.getEmptyStateMessage(),
199
- 'Built-in OAuth-capable providers and configured service providers will appear here once available for browser login or session import.',
199
+ 'Built-in OAuth-capable providers and configured provider routes will appear here once available for browser login or session import.',
200
200
  this.getEmptyStateActions(),
201
201
  C,
202
202
  );
@@ -171,9 +171,9 @@ export class SystemMessagesPanel extends ScrollableListPanel<SystemMessageEntry>
171
171
  buildKeyValueLine(width, [
172
172
  { label: 'system route', value: ui.systemMessages, valueColor: C.info },
173
173
  { label: 'ops route', value: ui.operationalMessages, valueColor: C.info },
174
- { label: 'wrfc route', value: ui.wrfcMessages, valueColor: C.info },
174
+ { label: 'review route', value: ui.wrfcMessages, valueColor: C.info },
175
175
  ], C),
176
- buildGuidanceLine(width, '/settings', 'adjust where operational and WRFC messages render across panels and conversation', C),
176
+ buildGuidanceLine(width, '/settings', 'adjust where operational and delegated review/build messages render across panels and conversation', C),
177
177
  ];
178
178
 
179
179
  const selected = this._messages[this.selectedIndex]!;
@@ -183,9 +183,9 @@ export class TasksPanel extends ScrollableListPanel<RuntimeTask> {
183
183
  sections: [{
184
184
  lines: buildEmptyState(
185
185
  width,
186
- ' Task store not wired into this panel yet.',
187
- 'Use the Tasks panel with live connected-service task state to review active execution, cancellations, retries, and completion results.',
188
- [{ command: '/tasks', summary: 'inspect connected-service tasks without starting background work' }],
186
+ ' Connected-host task state is unavailable.',
187
+ 'Use /tasks list for the supported Agent task summary. This deferred panel does not start or mutate task execution.',
188
+ [{ command: '/tasks', summary: 'inspect connected-host tasks without launching local workers' }],
189
189
  C,
190
190
  ),
191
191
  }],
@@ -235,7 +235,7 @@ export class TasksPanel extends ScrollableListPanel<RuntimeTask> {
235
235
  ]));
236
236
  }
237
237
  postureLines.push(
238
- buildGuidanceLine(width, '/tasks', 'inspect local runtime task posture without starting background agents', C),
238
+ buildGuidanceLine(width, '/tasks', 'inspect connected-host task posture without launching local workers', C),
239
239
  buildGuidanceLine(width, '/delegate <task>', 'delegate explicit build/fix/review work to GoodVibes TUI when code execution is required', C),
240
240
  );
241
241
 
@@ -288,7 +288,7 @@ export class ProjectPlanningCoordinator {
288
288
  const cleanGoal = goal.trim() || 'the requested change';
289
289
  return [
290
290
  `First pass: make "${cleanGoal}" work end-to-end for the primary local TUI workflow.`,
291
- 'Include the minimum TUI, daemon wiring, configuration persistence, documentation, and verification required for the feature to actually work.',
291
+ 'Include the minimum TUI, connected-host wiring, configuration persistence, documentation, and verification required for the feature to actually work.',
292
292
  'Exclude unrelated cleanup, broad refactors, polish-only changes, third-party integrations, and advanced distributed behavior unless they directly block the primary workflow.',
293
293
  ].join(' ');
294
294
  }
@@ -344,7 +344,7 @@ export class ProjectPlanningCoordinator {
344
344
  {
345
345
  id: 'wire-user-surface',
346
346
  title: `Wire the user-facing path for ${cleanGoal}`,
347
- why: 'The feature must be reachable through the intended TUI/daemon/config surface, not just internal code.',
347
+ why: 'The feature must be reachable through the intended TUI/connected-host/config surface, not just internal code.',
348
348
  status: 'pending',
349
349
  dependencies: ['implement-core-behavior'],
350
350
  verification: ['A command, panel, route, or setting path exercises the behavior from the user-facing entry point.'],
@@ -150,6 +150,9 @@ function localLibraryLines(
150
150
  item.enabled === true ? 'enabled' : item.enabled === false ? 'disabled' : '',
151
151
  item.scope && item.cls ? `${item.scope}/${item.cls}` : '',
152
152
  item.confidence !== undefined ? `${item.confidence}%` : '',
153
+ item.requirementCount !== undefined && item.requirementCount > 0
154
+ ? (item.missingRequirementCount && item.missingRequirementCount > 0 ? `needs ${item.missingRequirementCount}/${item.requirementCount}` : `ready ${item.requirementCount}/${item.requirementCount}`)
155
+ : '',
153
156
  item.reviewState,
154
157
  item.startCount !== undefined ? `starts ${item.startCount}` : '',
155
158
  ].filter(Boolean).join(' / ');
@@ -162,6 +165,9 @@ function localLibraryLines(
162
165
  bold: selected || item.active === true,
163
166
  });
164
167
  lines.push({ text: ` ${item.description}${tags}${triggers}`, fg: PALETTE.muted });
168
+ if (item.missingRequirements && item.missingRequirements.length > 0) {
169
+ lines.push({ text: ` missing setup: ${item.missingRequirements.join(', ')}`, fg: PALETTE.warn });
170
+ }
165
171
  }
166
172
  if (items.length > 8) {
167
173
  lines.push({ text: `${items.length - 8} more item(s). Open the library command for the full list.`, fg: PALETTE.dim });
@@ -180,7 +186,16 @@ function profileLines(snapshot: AgentWorkspaceRuntimeSnapshot): ContextLine[] {
180
186
  for (const profile of snapshot.runtimeProfiles.slice(0, 6)) {
181
187
  const starter = profile.starterTemplateId ? ` starter=${profile.starterTemplateId}` : ' starter=none';
182
188
  const created = profile.createdAt ? ` created=${profile.createdAt.slice(0, 10)}` : '';
183
- lines.push({ text: `${profile.id}${starter}${created}`, fg: PALETTE.info, bold: profile.id === snapshot.activeRuntimeProfile });
189
+ const states = [
190
+ profile.id === snapshot.activeRuntimeProfile ? 'active' : '',
191
+ profile.id === snapshot.selectedRuntimeProfile ? 'default' : '',
192
+ ].filter(Boolean).join(', ');
193
+ const stateText = states ? ` [${states}]` : '';
194
+ lines.push({
195
+ text: `${profile.id}${stateText}${starter}${created}`,
196
+ fg: profile.id === snapshot.selectedRuntimeProfile ? PALETTE.good : PALETTE.info,
197
+ bold: profile.id === snapshot.activeRuntimeProfile || profile.id === snapshot.selectedRuntimeProfile,
198
+ });
184
199
  lines.push({ text: ` home: ${profile.homeDirectory}`, fg: PALETTE.muted });
185
200
  }
186
201
  if (snapshot.runtimeProfiles.length > 6) {
@@ -272,8 +287,8 @@ function snapshotLines(workspace: AgentWorkspace, category: AgentWorkspaceCatego
272
287
  } else if (category.id === 'tools') {
273
288
  base.push(
274
289
  { text: `MCP servers: ${snapshot.mcpConnectedServerCount}/${snapshot.mcpServerCount} connected; quarantined ${snapshot.mcpQuarantinedServerCount}; allow-all ${snapshot.mcpAllowAllServerCount}.`, fg: snapshot.mcpQuarantinedServerCount > 0 || snapshot.mcpAllowAllServerCount > 0 ? PALETTE.warn : PALETTE.info },
275
- { text: 'Open MCP workspace for live server status, tool inventory, config paths, and command previews.', fg: PALETTE.info },
276
- { text: 'Add/update requires typed confirmation and dispatches /mcp add ... --yes through the command router.', fg: PALETTE.good },
290
+ { text: 'Open MCP workspace for live server status, tool inventory, config paths, and confirmed add/remove/reload actions.', fg: PALETTE.info },
291
+ { text: 'Add/update requires typed confirmation and dispatches through the TUI command router.', fg: PALETTE.good },
277
292
  { text: 'Trust changes remain explicit; allow-all is kept behind the settings workspace.', fg: PALETTE.warn },
278
293
  { text: 'Useful first actions: /mcp review, /mcp tools, /mcp config, and Add MCP server.', fg: PALETTE.muted },
279
294
  { text: 'Normal assistant chat can use tools serially when policy allows; onboarding does not start hidden tool work.', fg: PALETTE.muted },
@@ -317,8 +332,12 @@ function snapshotLines(workspace: AgentWorkspace, category: AgentWorkspaceCatego
317
332
  { text: 'Image input uses prompt attachments; media generation/provider setup stays behind explicit commands and configured providers.', fg: PALETTE.muted },
318
333
  );
319
334
  } else if (category.id === 'profiles') {
335
+ const defaultProfile = snapshot.selectedRuntimeProfile
336
+ ? `${snapshot.selectedRuntimeProfile}${snapshot.selectedRuntimeProfileExists ? '' : ' (missing)'}`
337
+ : '(base Agent home)';
320
338
  base.push(
321
339
  { text: `Active Agent profile: ${snapshot.activeRuntimeProfile}`, fg: PALETTE.info },
340
+ { text: `Default for next launch: ${defaultProfile}`, fg: snapshot.selectedRuntimeProfileExists || !snapshot.selectedRuntimeProfile ? PALETTE.info : PALETTE.warn },
322
341
  { text: `Agent profiles under this home: ${snapshot.runtimeProfileCount}`, fg: PALETTE.info },
323
342
  { text: `Starter templates: ${snapshot.runtimeStarterTemplateCount}; local custom: ${snapshot.localStarterTemplateCount}`, fg: PALETTE.info },
324
343
  { text: `Starter ids: ${snapshot.runtimeStarterTemplates.map((template) => template.id).join(', ') || 'none'}`, fg: PALETTE.info },
@@ -331,7 +350,7 @@ function snapshotLines(workspace: AgentWorkspace, category: AgentWorkspaceCatego
331
350
  { text: '' },
332
351
  { text: 'Named Agent profiles isolate local config, sessions, memory, personas, skills, routines, setup, and bundles.', fg: PALETTE.good },
333
352
  { text: 'Starter authoring: browse, export, edit, import, and create Agent profiles from inside this workspace.', fg: PALETTE.info },
334
- { text: 'Connected GoodVibes services stay shared unless the owning host is configured separately.', fg: PALETTE.warn },
353
+ { text: 'The connected GoodVibes host stays shared unless that host is configured separately.', fg: PALETTE.warn },
335
354
  { text: 'Portable bundles require explicit export/import commands with real paths and --yes.', fg: PALETTE.muted },
336
355
  );
337
356
  } else if (category.id === 'memory') {
@@ -486,7 +505,9 @@ function buildEditorFieldRows(editor: AgentWorkspaceLocalEditor, index: number,
486
505
  const selected = index === editor.selectedFieldIndex;
487
506
  const marker = selected ? GLYPHS.navigation.selected : ' ';
488
507
  const required = field.required ? ' *' : '';
489
- const value = field.value.length > 0 ? field.value : '(empty)';
508
+ const value = field.value.length > 0
509
+ ? field.redact ? '*'.repeat(Math.min(12, Math.max(6, Array.from(field.value).length))) : field.value
510
+ : '(empty)';
490
511
  const color = selected ? PALETTE.text : field.value.length > 0 ? PALETTE.info : PALETTE.muted;
491
512
  const rows: WorkspaceRow[] = [{
492
513
  text: `${marker} ${field.label}${required}`,
@@ -1,6 +1,6 @@
1
1
  import type { BlockMeta } from '../core/conversation';
2
2
 
3
- export type BlockActionId = 'copy' | 'bookmark' | 'toggle' | 'apply' | 'rerun';
3
+ export type BlockActionId = 'copy' | 'bookmark' | 'toggle' | 'rerun';
4
4
 
5
5
  export interface BlockAction {
6
6
  id: BlockActionId;
@@ -12,7 +12,6 @@ const ALL_ACTIONS: BlockAction[] = [
12
12
  { id: 'copy', label: 'Copy', key: 'c' },
13
13
  { id: 'bookmark', label: 'Bookmark', key: 'b' },
14
14
  { id: 'toggle', label: 'Collapse/Expand',key: 'Tab' },
15
- { id: 'apply', label: 'Diff apply blocked', key: 'a' },
16
15
  { id: 'rerun', label: 'Re-run tool', key: 'r' },
17
16
  ];
18
17
 
@@ -36,7 +35,6 @@ export class BlockActionsMenu {
36
35
  open(block: BlockMeta): void {
37
36
  this.block = block;
38
37
  this.actions = ALL_ACTIONS.filter(a => {
39
- if (a.id === 'apply') return block.type === 'diff';
40
38
  if (a.id === 'rerun') return block.type === 'tool';
41
39
  return true;
42
40
  });
@@ -57,11 +57,11 @@ export function renderHelpOverlay(
57
57
  ` ${kb('paste').padEnd(20)} Paste (image priority)`,
58
58
  ` ${(kb('undo') + ' / ' + kb('redo')).padEnd(20)} Undo / redo`,
59
59
  '',
60
- ' Overlays And Panels',
60
+ ' Overlays And Workspace',
61
61
  ' ' + '\u2500'.repeat(40),
62
62
  ` ${'?'.padEnd(20)} Toggle help`,
63
63
  ` ${'/shortcuts'.padEnd(20)} Full keyboard shortcuts`,
64
- ` ${kb('panel-picker').padEnd(20)} Open or focus the panel workspace`,
64
+ ` ${kb('panel-picker').padEnd(20)} Open the Agent operator workspace`,
65
65
  '',
66
66
  ];
67
67
 
@@ -70,6 +70,9 @@ export function renderHelpOverlay(
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
72
  ['agent', '', 'Open the Agent operator workspace'],
73
+ ['agent', 'setup', 'Open setup, local behavior, channel, and voice workspaces'],
74
+ ['agent', 'knowledge', 'Open isolated Agent Knowledge workflows'],
75
+ ['agent', 'voice-media', 'Open voice, image, browser, and media setup'],
73
76
  ['setup', '', 'Open Agent setup with current settings preloaded'],
74
77
  ['knowledge', 'status', 'Inspect isolated Agent Knowledge readiness'],
75
78
  ['memory', '', 'Manage local Agent memory records'],
@@ -85,6 +88,8 @@ export function renderHelpOverlay(
85
88
  ['model', '', 'Select the active model route'],
86
89
  ['subscription', '', 'Review provider logins and subscriptions'],
87
90
  ['secrets', '', 'Manage secret references without printing values'],
91
+ ['bundle', 'inspect', 'Inspect Agent support bundles from the TUI'],
92
+ ['compat', '', 'Inspect connected-host and Agent Knowledge compatibility'],
88
93
  ['health', '', 'Run Agent runtime and setup diagnostics'],
89
94
  ];
90
95
 
@@ -238,7 +243,7 @@ export function renderShortcutsOverlay(
238
243
  row(kb('clear-prompt'), 'Clear prompt'),
239
244
  row(kb('delete-word'), 'Delete word backward'),
240
245
  row(kb('kill-line'), 'Kill to end of line'),
241
- row(kb('apply-diff-line-start'), 'Delegate diff changes / line start'),
246
+ row(kb('line-start'), 'Move to start of line'),
242
247
  row(kb('next-error-line-end'), 'Next error / line end'),
243
248
  '',
244
249
  ' Actions',
@@ -252,12 +257,12 @@ export function renderShortcutsOverlay(
252
257
  row('?', 'Help overlay'),
253
258
  row(`${kb('clear-cancel')} x2`, 'Exit'),
254
259
  '',
255
- ' Panels',
260
+ ' Workspace',
256
261
  ' ' + '\u2500'.repeat(40),
257
- row('Tab', 'Swap focus between input and panel workspace'),
258
- row(kb('panel-picker'), 'Open / focus / hide panel workspace'),
259
- row(kb('panel-tab-next'), 'Next workspace panel tab'),
260
- row(kb('panel-tab-prev'), 'Previous workspace panel tab'),
262
+ row('Tab', 'Swap focus between input and active Agent workspace'),
263
+ row(kb('panel-picker'), 'Open the Agent operator workspace'),
264
+ row(kb('panel-tab-next'), 'Reserved for future Agent workspace tabs'),
265
+ row(kb('panel-tab-prev'), 'Reserved for future Agent workspace tabs'),
261
266
  '',
262
267
  ` Config: /keybindings to list and customize`,
263
268
  ];