@pellux/goodvibes-agent 0.1.114 → 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 -650
  2. package/README.md +40 -50
  3. package/dist/package/main.js +38224 -35673
  4. package/docs/README.md +5 -4
  5. package/docs/{connected-services.md → connected-host.md} +18 -10
  6. package/docs/getting-started.md +43 -42
  7. package/docs/release-and-publishing.md +6 -4
  8. package/package.json +3 -3
  9. package/src/agent/behavior-discovery-summary.ts +165 -0
  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 +331 -0
  19. package/src/agent/runtime-profile.ts +228 -330
  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 +247 -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 +787 -0
  39. package/src/input/agent-workspace-basic-command-editors.ts +524 -459
  40. package/src/input/agent-workspace-categories.ts +177 -14
  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 +25 -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 +49 -19
  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 +56 -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 +124 -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 +160 -6
  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 +126 -11
  116. package/src/input/onboarding/onboarding-wizard-steps.ts +15 -8
  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 +52 -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 +25 -6
  158. package/src/runtime/onboarding/snapshot.ts +4 -2
  159. package/src/runtime/onboarding/types.ts +28 -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
@@ -145,7 +145,7 @@ export class ProfilePickerModal {
145
145
  const profile = this.getSelected();
146
146
  if (!profile) return false;
147
147
  this.deleteConfirmationTarget = null;
148
- this.statusMessage = `Deletion requires an explicit command: /profiles delete ${profile.name} --yes`;
148
+ this.statusMessage = `Config-profile deletion is disabled in Agent for ${profile.name}. Use /agent profiles for isolated Agent profile homes.`;
149
149
  return false;
150
150
  }
151
151
 
@@ -158,7 +158,7 @@ export class ProfilePickerModal {
158
158
  return false;
159
159
  }
160
160
  void configManager;
161
- this.statusMessage = `Saving requires an explicit command: /profiles save ${name} --yes`;
161
+ this.statusMessage = `Config-profile saving is disabled in Agent for ${name}. Use /agent profiles to create isolated Agent homes.`;
162
162
  return false;
163
163
  }
164
164
 
@@ -1,4 +1,4 @@
1
- export const AGENT_EXTERNAL_DAEMON_SETTING_LOCK_REASON = 'GoodVibes Agent uses connected GoodVibes services. Change service lifecycle and bind posture from the owning host; Agent settings are read-only for those controls.';
1
+ export const AGENT_EXTERNAL_HOST_SETTING_LOCK_REASON = 'GoodVibes Agent uses a connected GoodVibes host. Change host lifecycle and bind posture from the owning host; Agent settings are read-only for those controls.';
2
2
 
3
3
  const AGENT_HIDDEN_SETTING_PREFIXES = [
4
4
  ['cloud', 'flare.'].join(''),
@@ -21,21 +21,21 @@ const AGENT_HIDDEN_SETTING_KEYS = new Set<string>([
21
21
  'ui.wrfcMessages',
22
22
  ]);
23
23
 
24
- const EXTERNAL_DAEMON_SETTING_PREFIXES = [
24
+ const EXTERNAL_HOST_SETTING_PREFIXES = [
25
25
  'service.',
26
26
  'controlPlane.',
27
27
  'httpListener.',
28
28
  'web.',
29
29
  ] as const;
30
30
 
31
- const EXTERNAL_DAEMON_SETTING_KEYS = new Set<string>([
31
+ const EXTERNAL_HOST_SETTING_KEYS = new Set<string>([
32
32
  'danger.daemon',
33
33
  'danger.httpListener',
34
34
  ]);
35
35
 
36
- export function isExternalDaemonOwnedSettingKey(key: string): boolean {
37
- return EXTERNAL_DAEMON_SETTING_KEYS.has(key)
38
- || EXTERNAL_DAEMON_SETTING_PREFIXES.some((prefix) => key.startsWith(prefix));
36
+ export function isExternalHostOwnedSettingKey(key: string): boolean {
37
+ return EXTERNAL_HOST_SETTING_KEYS.has(key)
38
+ || EXTERNAL_HOST_SETTING_PREFIXES.some((prefix) => key.startsWith(prefix));
39
39
  }
40
40
 
41
41
  export function isAgentHiddenSettingKey(key: string): boolean {
@@ -23,7 +23,7 @@ export function buildSubscriptionEntries(
23
23
  activeRoute: 'unconfigured',
24
24
  authFreshness: 'unconfigured',
25
25
  routeReason: 'Built-in subscription adapter is available, but no active subscription session is stored yet.',
26
- nextActions: [`Use /subscription login ${provider} start --yes to begin browser sign-in.`],
26
+ nextActions: [`Open /agent setup and choose Start subscription login for ${provider}.`],
27
27
  });
28
28
  }
29
29
 
@@ -38,7 +38,7 @@ export function buildSubscriptionEntries(
38
38
  activeRoute: providers.get(provider)?.activeRoute ?? 'unconfigured',
39
39
  authFreshness: providers.get(provider)?.authFreshness ?? 'unconfigured',
40
40
  routeReason: providers.get(provider)?.routeReason ?? 'OAuth metadata is configured for this provider.',
41
- nextActions: providers.get(provider)?.nextActions ?? [`Use /subscription login ${provider} start --yes to begin browser sign-in.`],
41
+ nextActions: providers.get(provider)?.nextActions ?? [`Open /agent setup and choose Start subscription login for ${provider}.`],
42
42
  });
43
43
  }
44
44
 
@@ -51,7 +51,7 @@ export function buildSubscriptionEntries(
51
51
  activeRoute: 'unconfigured',
52
52
  authFreshness: 'pending',
53
53
  routeReason: 'OAuth login is pending completion for this provider.',
54
- nextActions: [`Finish /subscription login ${pending.provider} finish <code> --yes to activate this session.`],
54
+ nextActions: [`Open /agent setup and choose Finish subscription login for ${pending.provider}.`],
55
55
  });
56
56
  }
57
57
 
@@ -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.'],