@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
@@ -62,6 +62,43 @@ export interface BootstrapShellOptions {
62
62
  readonly completeModelSelectionSideEffect?: () => void;
63
63
  }
64
64
 
65
+ type PlanningAnswerSubmit = (answer: string) => void;
66
+
67
+ export interface PlanningAnswerSubmitBridgeOptions {
68
+ readonly getSubmitInput: () => PlanningAnswerSubmit | undefined;
69
+ readonly addSystemMessage: (message: string) => void;
70
+ readonly requestRender: () => void;
71
+ readonly defer?: (callback: () => void) => void;
72
+ }
73
+
74
+ export function submitPlanningAnswerWithShellFallback(
75
+ answer: string,
76
+ options: PlanningAnswerSubmitBridgeOptions,
77
+ ): void {
78
+ const submit = options.getSubmitInput();
79
+ if (submit) {
80
+ submit(answer);
81
+ return;
82
+ }
83
+
84
+ const defer = options.defer ?? ((callback) => {
85
+ setTimeout(callback, 0);
86
+ });
87
+ defer(() => {
88
+ const deferredSubmit = options.getSubmitInput();
89
+ if (deferredSubmit) {
90
+ deferredSubmit(answer);
91
+ return;
92
+ }
93
+
94
+ options.addSystemMessage([
95
+ '[Planning] Could not submit the selected answer because the prompt bridge is not ready.',
96
+ `Paste this answer into the prompt to continue planning: ${answer}`,
97
+ ].join('\n'));
98
+ options.requestRender();
99
+ });
100
+ }
101
+
65
102
  export function createBootstrapShell(options: BootstrapShellOptions): BootstrapShellState {
66
103
  const {
67
104
  configManager,
@@ -113,10 +150,11 @@ export function createBootstrapShell(options: BootstrapShellOptions): BootstrapS
113
150
  resumeSession,
114
151
  requestRender,
115
152
  submitPlanningAnswer: (answer) => {
116
- if (!commandContextRef?.submitInput) {
117
- throw new Error('Planning answer submission is not wired yet.');
118
- }
119
- commandContextRef.submitInput(answer);
153
+ submitPlanningAnswerWithShellFallback(answer, {
154
+ getSubmitInput: () => commandContextRef?.submitInput,
155
+ addSystemMessage: (message) => conversation.addSystemMessage(message),
156
+ requestRender,
157
+ });
120
158
  },
121
159
  dismissPlanning: () => {
122
160
  services.panelManager.close('project-planning');
@@ -10,7 +10,6 @@
10
10
  * - lifecycle.ts: save/shutdown helpers
11
11
  */
12
12
  import { Orchestrator, type OrchestratorUserInputOptions } from '../core/orchestrator.ts';
13
- import { AcpManager } from '@pellux/goodvibes-sdk/platform/acp';
14
13
  import { getTierPromptSupplement, getTierForContextWindow } from '@pellux/goodvibes-sdk/platform/providers';
15
14
  import { logger } from '@pellux/goodvibes-sdk/platform/utils';
16
15
  import type { PermissionRequestHandler } from '@pellux/goodvibes-sdk/platform/permissions';
@@ -23,7 +22,6 @@ import type { RuntimeContext, BootstrapOptions } from './context.ts';
23
22
  import { shutdownRuntime, fireSessionStart, saveSession } from '@/runtime/index.ts';
24
23
  import { createTaskManager } from '@/runtime/index.ts';
25
24
  import { OpsControlPlane } from '@/runtime/index.ts';
26
- import { AcpTaskAdapter } from '@/runtime/index.ts';
27
25
  import type { SystemMessageRouter } from '../core/system-message-router.ts';
28
26
  import { emitSessionReady, emitSessionStarted } from '@/runtime/index.ts';
29
27
  import {
@@ -47,8 +45,8 @@ import { buildReviewedMemoryPrompt } from '../agent/memory-prompt.ts';
47
45
 
48
46
  const GOODVIBES_AGENT_OPERATOR_POLICY = [
49
47
  '## GoodVibes Agent Operator Policy',
50
- '- Default to serial, proactive assistant work in the main conversation. Answer, inspect, summarize, remember useful non-secret facts, configure local Agent state, use read-only connected-service/operator routes, and take safe non-destructive actions without spawning local agents or WRFC.',
51
- '- GoodVibes Agent connects to GoodVibes services owned outside this package. Do not start, stop, restart, install, expose, or mutate connected-service network/listener posture from Agent.',
48
+ '- Default to serial, proactive assistant work in the main conversation. Answer, inspect, summarize, remember useful non-secret facts, configure local Agent state, use read-only connected-host/operator routes, and take safe non-destructive actions without spawning local agents or WRFC.',
49
+ '- GoodVibes Agent connects to a GoodVibes host owned outside this package. Do not start, stop, restart, install, expose, or mutate connected-host network/listener posture from Agent.',
52
50
  '- Use the `agent_local_registry` tool when a durable memory, reusable persona, skill, skill bundle, or routine would improve future work. Keep those records local, non-secret, source/provenance tagged, and reviewable. Review memory with a confidence score when it should shape future turns. Starting a routine means applying its steps in this same serial conversation, not creating a background job.',
53
51
  '- WRFC is never the default Agent reasoning path. Do not create local WRFC chains for planning, research, operations, knowledge, memory, configuration, approvals, automation observability, or ordinary assistant work.',
54
52
  '- GoodVibes Agent is not the coding TUI. Do not use the `agent` tool to spawn local Engineer, Reviewer, Tester, Verifier, or batch-spawn roots from Agent.',
@@ -130,7 +128,7 @@ export type BootstrapContext = RuntimeContext & {
130
128
  * 3. Tool registry + agent wiring
131
129
  * 4. Runtime bus subscriptions (WRFC, subagent, hook bridge)
132
130
  * 5. Providers, webhooks, PermissionManager, HookDispatcher
133
- * 6. Orchestrator + AcpManager
131
+ * 6. Orchestrator and Agent-local task read models
134
132
  * 7. MCP auto-connect + workspace/panel manager
135
133
  * 8. Command registry + plugin init + CommandContext
136
134
  * 9. Input handler wiring
@@ -183,7 +181,7 @@ export async function bootstrapRuntime(
183
181
  pluginManager,
184
182
  } = services;
185
183
 
186
- // ── Phase 6: Orchestrator + AcpManager ───────────────────────────────────
184
+ // ── Phase 6: Orchestrator and Agent-local task read models ───────────────
187
185
 
188
186
  // Mutable function refs so main.ts can patch these after constructing the scroll/viewport state.
189
187
  // The orchestrator closes over these refs, so patching them in main.ts takes immediate effect.
@@ -243,17 +241,6 @@ export async function bootstrapRuntime(
243
241
  });
244
242
  conversation.setSessionLineageTracker(services.sessionLineageTracker);
245
243
 
246
- const acpManager = new AcpManager({
247
- requestPermission: (request) => permissionPromptRef.requestPermission(request),
248
- runtimeBus,
249
- hookDispatcher: services.hookDispatcher,
250
- });
251
- const acpTaskAdapter = new AcpTaskAdapter(store);
252
- const ACP_TASK_SYNC_INTERVAL_MS = 1_000;
253
- const acpTaskSyncInterval = setInterval(() => {
254
- acpTaskAdapter.sync(acpManager);
255
- }, ACP_TASK_SYNC_INTERVAL_MS);
256
- bootstrapUnsubs.push(() => clearInterval(acpTaskSyncInterval));
257
244
  const opsTaskManager = createTaskManager(store, runtimeBus, userSessionId);
258
245
  const opsControlPlane = services.featureFlags.isEnabled('operator-control-plane')
259
246
  ? new OpsControlPlane(opsTaskManager, runtimeBus, store, userSessionId)
@@ -334,7 +321,7 @@ export async function bootstrapRuntime(
334
321
  port,
335
322
  baseUrl: formatHostServiceBaseUrl(host, port),
336
323
  reason: service === 'daemon'
337
- ? 'GoodVibes Agent connects to GoodVibes services owned outside this product and does not start or restart them.'
324
+ ? 'GoodVibes Agent connects to a GoodVibes host owned outside this product and does not start or restart them.'
338
325
  : 'GoodVibes Agent does not own listener lifecycle.',
339
326
  };
340
327
  };
@@ -375,7 +362,7 @@ export async function bootstrapRuntime(
375
362
  daemonStatus: createExternalAgentServiceStatus('daemon'),
376
363
  httpListenerStatus: createExternalAgentServiceStatus('httpListener'),
377
364
  };
378
- systemMessageRouter.high('[Startup] GoodVibes Agent does not start or restart connected GoodVibes services. Start them from GoodVibes TUI or the owning host, then refresh status.');
365
+ systemMessageRouter.high('[Startup] GoodVibes Agent does not start or restart the connected GoodVibes host. Start it from GoodVibes TUI or the owning host, then refresh status.');
379
366
  requestRender();
380
367
  return inspectExternalServices();
381
368
  },
@@ -452,8 +439,8 @@ export async function bootstrapRuntime(
452
439
  });
453
440
  bootstrapUnsubs.push(() => mcpAutoReload.stop());
454
441
  if (configManager.get('automation.enabled')) {
455
- logger.warn('Local automation startup is disabled in GoodVibes Agent; use connected-service observability instead.');
456
- systemMessageRouter.low('[Startup] Local automation runners are disabled in GoodVibes Agent; use read-only automation observability or explicit connected-service actions.');
442
+ logger.warn('Local automation startup is disabled in GoodVibes Agent; use connected-host observability instead.');
443
+ systemMessageRouter.low('[Startup] Local automation runners are disabled in GoodVibes Agent; use read-only automation observability or explicit connected-host actions.');
457
444
  }
458
445
 
459
446
  // ── Phase 12: Session:start lifecycle hook ─────────────────────────────
@@ -554,12 +541,6 @@ export async function bootstrapRuntime(
554
541
  },
555
542
  };
556
543
 
557
- // ── Phase 12b: Operator intervention wiring (feature-gated) ──────────────
558
- // Keep service-owned control-plane state internal. GoodVibes Agent does not
559
- // expose the local ops-control panel; operator control is surfaced
560
- // through Agent-owned status, approvals, automation, and delegation flows.
561
- ctx.commandContext.ops.acpManager = acpManager;
562
-
563
544
  // Wire exit from options if provided; otherwise main.ts binds the shell bridge.
564
545
  if (options?.exit) {
565
546
  ctx.commandContext.exit = options.exit;
@@ -0,0 +1,42 @@
1
+ import { existsSync, readFileSync } from 'node:fs';
2
+ import { join } from 'node:path';
3
+
4
+ type JsonRecord = Record<string, unknown>;
5
+
6
+ export interface ConnectedHostOperatorToken {
7
+ readonly path: string;
8
+ readonly present: boolean;
9
+ readonly token: string | null;
10
+ readonly error?: string;
11
+ }
12
+
13
+ function isRecord(value: unknown): value is JsonRecord {
14
+ return Boolean(value) && typeof value === 'object' && !Array.isArray(value);
15
+ }
16
+
17
+ export function connectedHostOperatorTokenPath(homeDirectory: string): string {
18
+ return join(homeDirectory, '.goodvibes', 'daemon', 'operator-tokens.json');
19
+ }
20
+
21
+ export function readConnectedHostOperatorToken(homeDirectory: string): ConnectedHostOperatorToken {
22
+ const path = connectedHostOperatorTokenPath(homeDirectory);
23
+ if (!existsSync(path)) return { path, present: false, token: null };
24
+ try {
25
+ const parsed = JSON.parse(readFileSync(path, 'utf-8')) as unknown;
26
+ const token = isRecord(parsed) && typeof parsed.token === 'string' && parsed.token.trim().length > 0
27
+ ? parsed.token
28
+ : null;
29
+ return { path, present: true, token };
30
+ } catch (error) {
31
+ return { path, present: true, token: null, error: error instanceof Error ? error.message : String(error) };
32
+ }
33
+ }
34
+
35
+ export function connectedHostTokenRequiredMessage(path: string): string {
36
+ return [
37
+ 'Connected-host operator token is required.',
38
+ ` token path: ${path}`,
39
+ ' Agent does not create or rotate connected-host auth tokens.',
40
+ ' Start or repair the owning GoodVibes host, then rerun this command.',
41
+ ].join('\n');
42
+ }
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * Panel resource diagnostics panel data provider.
3
3
  *
4
- * Polls the shared TUI-owned ComponentHealthMonitor and produces PanelResourceSnapshot
4
+ * Polls the shared shell ComponentHealthMonitor and produces PanelResourceSnapshot
5
5
  * values for the diagnostics panel to render.
6
6
  */
7
7
  import type { ComponentHealthMonitor } from '../../perf/panel-health-monitor.ts';
@@ -97,7 +97,6 @@ export const restoreRuntimeModel = bootstrap.restoreRuntimeModel;
97
97
  export const restoreSavedModel = bootstrap.restoreRuntimeModel;
98
98
  export const synchronizeConfiguredServices = bootstrap.synchronizeConfiguredServices;
99
99
  export const syncConfiguredServices = bootstrap.synchronizeConfiguredServices;
100
- export const registerBootstrapRuntimeEvents = bootstrap.registerBootstrapRuntimeEvents;
101
100
  export const registerHostRuntimeEvents = bootstrap.registerHostRuntimeEvents;
102
101
  function agentExternalHostStatus(
103
102
  config: Bootstrap.HostServicesConfig,
@@ -113,7 +112,7 @@ function agentExternalHostStatus(
113
112
  port,
114
113
  baseUrl: `http://${host}:${port}`,
115
114
  reason: service === 'daemon'
116
- ? 'GoodVibes Agent connects to GoodVibes services owned outside this product and does not start or restart them.'
115
+ ? 'GoodVibes Agent connects to a GoodVibes host owned outside this product and does not start or restart them.'
117
116
  : 'GoodVibes Agent does not own listener lifecycle.',
118
117
  };
119
118
  }
@@ -245,7 +244,6 @@ export type RemoteRuntimeEvents = Transport.RemoteRuntimeEvents;
245
244
  export type SerializedRuntimeEnvelope = Transport.SerializedRuntimeEnvelope;
246
245
 
247
246
  // Operations compatibility aliases.
248
- export const AcpTaskAdapter = operations.AcpTaskAdapter;
249
247
  export const OpsControlPlane = operations.OpsControlPlane;
250
248
  export const OpsIllegalActionError = operations.OpsIllegalActionError;
251
249
  export const OpsTargetNotFoundError = operations.OpsTargetNotFoundError;
@@ -436,7 +434,6 @@ export const uninstallEcosystemCatalogEntry = shell.uninstallEcosystemCatalogEnt
436
434
  export const updateInstalledEcosystemEntry = shell.updateInstalledEcosystemEntry;
437
435
  export const upsertEcosystemCatalogEntry = shell.upsertEcosystemCatalogEntry;
438
436
  export const summarizeWorktreeOwnership = shell.summarizeWorktreeOwnership;
439
- export const WorktreeRegistry = shell.WorktreeRegistry;
440
437
  export const listPersistedWorktreeMeta = shell.listPersistedWorktreeMeta;
441
438
  export const getPersistedWorktreeMeta = shell.getPersistedWorktreeMeta;
442
439
  export const reviewWorktreeAttachments = shell.reviewWorktreeAttachments;
@@ -458,7 +455,6 @@ export type WorktreeRegistry = Shell.WorktreeRegistry;
458
455
  export type WorktreeStatusRecord = Shell.WorktreeStatusRecord;
459
456
  export type ManagedWorktreeMeta = Shell.ManagedWorktreeMeta;
460
457
  export type ShellAgentManagerService = Shell.ShellAgentManagerService;
461
- export type ShellAcpManagerService = Shell.ShellAcpManagerService;
462
458
  export type ShellAutomationManagerService = Shell.ShellAutomationManagerService;
463
459
  export type ShellAutomationManagerRuntimeService = Shell.ShellAutomationManagerRuntimeService;
464
460
  export type ShellModeManagerService = Shell.ShellModeManagerService;
@@ -5,8 +5,14 @@ import { CONFIG_SCHEMA, DEFAULT_CONFIG } from '../../config/index.ts';
5
5
  import {
6
6
  createAgentRuntimeProfile,
7
7
  getAgentRuntimeProfileTemplate,
8
+ getAgentRuntimeProfileSelectionPath,
9
+ readAgentRuntimeProfileSelection,
8
10
  resolveAgentRuntimeProfileHome,
11
+ setAgentRuntimeProfileSelection,
9
12
  } from '../../agent/runtime-profile.ts';
13
+ import { AgentPersonaRegistry, assertNoSecretLikeText } from '../../agent/persona-registry.ts';
14
+ import { AgentRoutineRegistry } from '../../agent/routine-registry.ts';
15
+ import { AgentSkillRegistry } from '../../agent/skill-registry.ts';
10
16
  import type { FeatureFlagConfigKey } from '../surface-feature-flags.ts';
11
17
  import {
12
18
  getOnboardingRuntimeStatePath,
@@ -222,6 +228,65 @@ function validateCreateAgentProfileOperation(
222
228
  if (templateId) getAgentRuntimeProfileTemplate(templateId, deps.shellPaths.homeDirectory);
223
229
  }
224
230
 
231
+ function validateSelectAgentProfileOperation(
232
+ deps: OnboardingApplyDependencies,
233
+ operation: Extract<OnboardingApplyOperation, { kind: 'select-agent-profile' }>,
234
+ ): void {
235
+ const name = operation.name.trim();
236
+ if (name.length === 0) throw new Error('Agent profile name is required.');
237
+ const resolution = resolveAgentRuntimeProfileHome(deps.shellPaths.homeDirectory, name);
238
+ if (!existsSync(resolution.homeDirectory)) {
239
+ throw new Error(`Agent profile does not exist: ${resolution.id}`);
240
+ }
241
+ }
242
+
243
+ function validateCreateLocalPersonaOperation(
244
+ deps: OnboardingApplyDependencies,
245
+ operation: Extract<OnboardingApplyOperation, { kind: 'create-local-persona' }>,
246
+ ): void {
247
+ const name = operation.name.trim();
248
+ const description = operation.description.trim();
249
+ const body = operation.body.trim();
250
+ if (!name) throw new Error('Persona name is required.');
251
+ if (!description) throw new Error('Persona description is required.');
252
+ if (!body) throw new Error('Persona body is required.');
253
+ assertNoSecretLikeText([name, description, body]);
254
+ const duplicate = AgentPersonaRegistry.fromShellPaths(deps.shellPaths).get(name);
255
+ if (duplicate) throw new Error(`Persona already exists: ${duplicate.id}`);
256
+ }
257
+
258
+ function validateCreateLocalSkillOperation(
259
+ deps: OnboardingApplyDependencies,
260
+ operation: Extract<OnboardingApplyOperation, { kind: 'create-local-skill' }>,
261
+ ): void {
262
+ const registry = AgentSkillRegistry.fromShellPaths(deps.shellPaths);
263
+ const name = operation.name.trim();
264
+ const description = operation.description.trim();
265
+ const procedure = operation.procedure.trim();
266
+ if (!name) throw new Error('Skill name is required.');
267
+ if (!description) throw new Error('Skill description is required.');
268
+ if (!procedure) throw new Error('Skill procedure is required.');
269
+ assertNoSecretLikeText([name, description, procedure]);
270
+ const duplicate = registry.get(name);
271
+ if (duplicate) throw new Error(`Skill already exists: ${duplicate.id}`);
272
+ }
273
+
274
+ function validateCreateLocalRoutineOperation(
275
+ deps: OnboardingApplyDependencies,
276
+ operation: Extract<OnboardingApplyOperation, { kind: 'create-local-routine' }>,
277
+ ): void {
278
+ const registry = AgentRoutineRegistry.fromShellPaths(deps.shellPaths);
279
+ const name = operation.name.trim();
280
+ const description = operation.description.trim();
281
+ const steps = operation.steps.trim();
282
+ if (!name) throw new Error('Routine name is required.');
283
+ if (!description) throw new Error('Routine description is required.');
284
+ if (!steps) throw new Error('Routine steps are required.');
285
+ assertNoSecretLikeText([name, description, steps]);
286
+ const duplicate = registry.get(name);
287
+ if (duplicate) throw new Error(`Routine already exists: ${duplicate.id}`);
288
+ }
289
+
225
290
  function applyConfigOperation(
226
291
  deps: OnboardingApplyDependencies,
227
292
  operation: Extract<OnboardingApplyOperation, { kind: 'set-config' }>,
@@ -322,6 +387,26 @@ async function buildRollbackAction(
322
387
  };
323
388
  }
324
389
 
390
+ if (operation.kind === 'select-agent-profile') {
391
+ const path = getAgentRuntimeProfileSelectionPath(deps.shellPaths.homeDirectory);
392
+ return snapshotFileRollback(path);
393
+ }
394
+
395
+ if (operation.kind === 'create-local-persona') {
396
+ const registry = AgentPersonaRegistry.fromShellPaths(deps.shellPaths);
397
+ return snapshotFileRollback(registry.snapshot().path);
398
+ }
399
+
400
+ if (operation.kind === 'create-local-skill') {
401
+ const registry = AgentSkillRegistry.fromShellPaths(deps.shellPaths);
402
+ return snapshotFileRollback(registry.snapshot().path);
403
+ }
404
+
405
+ if (operation.kind === 'create-local-routine') {
406
+ const registry = AgentRoutineRegistry.fromShellPaths(deps.shellPaths);
407
+ return snapshotFileRollback(registry.snapshot().path);
408
+ }
409
+
325
410
  const neverOperation: never = operation;
326
411
  throw new Error(`Unsupported onboarding operation: ${JSON.stringify(neverOperation)}`);
327
412
  }
@@ -364,6 +449,73 @@ function applyCreateAgentProfileOperation(
364
449
  };
365
450
  }
366
451
 
452
+ function applySelectAgentProfileOperation(
453
+ deps: OnboardingApplyDependencies,
454
+ operation: Extract<OnboardingApplyOperation, { kind: 'select-agent-profile' }>,
455
+ ): OnboardingAppliedOperation {
456
+ validateSelectAgentProfileOperation(deps, operation);
457
+ const selection = setAgentRuntimeProfileSelection(deps.shellPaths.homeDirectory, operation.name);
458
+ return {
459
+ kind: operation.kind,
460
+ summary: `Selected Agent profile ${selection.id} for future launches.`,
461
+ };
462
+ }
463
+
464
+ function applyCreateLocalPersonaOperation(
465
+ deps: OnboardingApplyDependencies,
466
+ operation: Extract<OnboardingApplyOperation, { kind: 'create-local-persona' }>,
467
+ ): OnboardingAppliedOperation {
468
+ const registry = AgentPersonaRegistry.fromShellPaths(deps.shellPaths);
469
+ const persona = registry.create({
470
+ name: operation.name,
471
+ description: operation.description,
472
+ body: operation.body,
473
+ source: 'user',
474
+ provenance: 'onboarding',
475
+ });
476
+ if (operation.activate !== false) registry.setActive(persona.id);
477
+ return {
478
+ kind: operation.kind,
479
+ summary: `Created local Agent persona ${persona.id}.`,
480
+ };
481
+ }
482
+
483
+ function applyCreateLocalSkillOperation(
484
+ deps: OnboardingApplyDependencies,
485
+ operation: Extract<OnboardingApplyOperation, { kind: 'create-local-skill' }>,
486
+ ): OnboardingAppliedOperation {
487
+ const skill = AgentSkillRegistry.fromShellPaths(deps.shellPaths).create({
488
+ name: operation.name,
489
+ description: operation.description,
490
+ procedure: operation.procedure,
491
+ enabled: operation.enabled !== false,
492
+ source: 'user',
493
+ provenance: 'onboarding',
494
+ });
495
+ return {
496
+ kind: operation.kind,
497
+ summary: `Created local Agent skill ${skill.id}.`,
498
+ };
499
+ }
500
+
501
+ function applyCreateLocalRoutineOperation(
502
+ deps: OnboardingApplyDependencies,
503
+ operation: Extract<OnboardingApplyOperation, { kind: 'create-local-routine' }>,
504
+ ): OnboardingAppliedOperation {
505
+ const routine = AgentRoutineRegistry.fromShellPaths(deps.shellPaths).create({
506
+ name: operation.name,
507
+ description: operation.description,
508
+ steps: operation.steps,
509
+ enabled: operation.enabled !== false,
510
+ source: 'user',
511
+ provenance: 'onboarding',
512
+ });
513
+ return {
514
+ kind: operation.kind,
515
+ summary: `Created local Agent routine ${routine.id}.`,
516
+ };
517
+ }
518
+
367
519
  function orderApplyOperations(
368
520
  operations: readonly OnboardingApplyOperation[],
369
521
  ): readonly OnboardingApplyOperation[] {
@@ -376,6 +528,12 @@ function orderApplyOperations(
376
528
  operation.kind === 'set-config' && operation.key !== 'storage.secretPolicy'
377
529
  ));
378
530
  const agentProfileOperations = operations.filter((operation) => operation.kind === 'create-agent-profile');
531
+ const agentProfileSelectionOperations = operations.filter((operation) => operation.kind === 'select-agent-profile');
532
+ const localBehaviorOperations = operations.filter((operation) => (
533
+ operation.kind === 'create-local-persona'
534
+ || operation.kind === 'create-local-skill'
535
+ || operation.kind === 'create-local-routine'
536
+ ));
379
537
  const finalOperations = operations.filter((operation) => (
380
538
  operation.kind === 'acknowledge'
381
539
  ));
@@ -386,6 +544,8 @@ function orderApplyOperations(
386
544
  ...secretOperations,
387
545
  ...configOperations,
388
546
  ...agentProfileOperations,
547
+ ...agentProfileSelectionOperations,
548
+ ...localBehaviorOperations,
389
549
  ...finalOperations,
390
550
  ];
391
551
  }
@@ -427,6 +587,31 @@ function prevalidateApplyRequest(
427
587
  continue;
428
588
  }
429
589
 
590
+ if (operation.kind === 'select-agent-profile') {
591
+ const createdEarlier = orderedOperations.some((candidate) => (
592
+ candidate.kind === 'create-agent-profile'
593
+ && resolveAgentRuntimeProfileHome(deps.shellPaths.homeDirectory, candidate.name).id
594
+ === resolveAgentRuntimeProfileHome(deps.shellPaths.homeDirectory, operation.name).id
595
+ ));
596
+ if (!createdEarlier) validateSelectAgentProfileOperation(deps, operation);
597
+ continue;
598
+ }
599
+
600
+ if (operation.kind === 'create-local-persona') {
601
+ validateCreateLocalPersonaOperation(deps, operation);
602
+ continue;
603
+ }
604
+
605
+ if (operation.kind === 'create-local-skill') {
606
+ validateCreateLocalSkillOperation(deps, operation);
607
+ continue;
608
+ }
609
+
610
+ if (operation.kind === 'create-local-routine') {
611
+ validateCreateLocalRoutineOperation(deps, operation);
612
+ continue;
613
+ }
614
+
430
615
  const neverOperation: never = operation;
431
616
  throw new Error(`Unsupported onboarding operation: ${JSON.stringify(neverOperation)}`);
432
617
  } catch (error) {
@@ -446,6 +631,10 @@ function getVerificationFailureKind(itemId: string): OnboardingApplyOperation['k
446
631
  if (itemId.startsWith('auth:')) return 'ensure-auth-user';
447
632
  if (itemId.startsWith('acknowledge:')) return 'acknowledge';
448
633
  if (itemId.startsWith('agent-profile:')) return 'create-agent-profile';
634
+ if (itemId.startsWith('selected-agent-profile:')) return 'select-agent-profile';
635
+ if (itemId.startsWith('local-persona:')) return 'create-local-persona';
636
+ if (itemId.startsWith('local-skill:')) return 'create-local-skill';
637
+ if (itemId.startsWith('local-routine:')) return 'create-local-routine';
449
638
  return 'set-config';
450
639
  }
451
640
 
@@ -502,6 +691,30 @@ export async function applyOnboardingRequest(
502
691
  continue;
503
692
  }
504
693
 
694
+ if (operation.kind === 'select-agent-profile') {
695
+ applied.push(applySelectAgentProfileOperation(deps, operation));
696
+ rollbacks.push(rollback);
697
+ continue;
698
+ }
699
+
700
+ if (operation.kind === 'create-local-persona') {
701
+ applied.push(applyCreateLocalPersonaOperation(deps, operation));
702
+ rollbacks.push(rollback);
703
+ continue;
704
+ }
705
+
706
+ if (operation.kind === 'create-local-skill') {
707
+ applied.push(applyCreateLocalSkillOperation(deps, operation));
708
+ rollbacks.push(rollback);
709
+ continue;
710
+ }
711
+
712
+ if (operation.kind === 'create-local-routine') {
713
+ applied.push(applyCreateLocalRoutineOperation(deps, operation));
714
+ rollbacks.push(rollback);
715
+ continue;
716
+ }
717
+
505
718
  const neverOperation: never = operation;
506
719
  throw new Error(`Unsupported onboarding operation: ${JSON.stringify(neverOperation)}`);
507
720
  } catch (error) {
@@ -224,7 +224,7 @@ function hasAutomationReviewSignals(snapshot: OnboardingSnapshotState): boolean
224
224
  }
225
225
 
226
226
  function describeOperatorTerminal(): string {
227
- return 'Use GoodVibes Agent as the terminal operator while connecting to existing GoodVibes services. Agent setup does not create new entrypoints.';
227
+ return 'Use GoodVibes Agent as the terminal operator while connecting to an existing GoodVibes host. Agent setup does not create new entrypoints.';
228
228
  }
229
229
 
230
230
  function describeProviderAccess(snapshot: OnboardingSnapshotState): string {
@@ -458,23 +458,23 @@ export function deriveReopenEditAcknowledgementState(
458
458
  snapshot,
459
459
  'auth',
460
460
  'bootstrap-credential',
461
- 'A connected-service bootstrap credential signal is still visible to Agent.',
461
+ 'A connected-host bootstrap credential signal is still visible to Agent.',
462
462
  )
463
463
  : authSessionCount > 0
464
464
  ? buildRequiredAcknowledgement(
465
465
  snapshot,
466
466
  'auth',
467
467
  'active-sessions',
468
- `${authSessionCount} connected-service auth session signal(s) are currently visible.`,
468
+ `${authSessionCount} connected-host auth session signal(s) are currently visible.`,
469
469
  )
470
470
  : authUserCount > 0
471
471
  ? buildRequiredAcknowledgement(
472
472
  snapshot,
473
473
  'auth',
474
474
  'auth-state',
475
- `${authUserCount} connected-service auth user signal(s) are already visible.`,
475
+ `${authUserCount} connected-host auth user signal(s) are already visible.`,
476
476
  )
477
- : buildNotNeededAcknowledgement(snapshot, 'auth', 'No connected-service auth signal needs confirmation.');
477
+ : buildNotNeededAcknowledgement(snapshot, 'auth', 'No connected-host auth signal needs confirmation.');
478
478
 
479
479
  return {
480
480
  providers,
@@ -99,7 +99,7 @@ async function buildServicesSnapshot(
99
99
  },
100
100
  issues: [
101
101
  {
102
- area: 'services',
102
+ area: 'host',
103
103
  message: error instanceof Error ? error.message : String(error),
104
104
  },
105
105
  ],
@@ -146,7 +146,7 @@ async function buildServicesSnapshot(
146
146
  hasAppToken: false,
147
147
  } satisfies OnboardingServiceState,
148
148
  issue: {
149
- area: 'services',
149
+ area: 'host',
150
150
  message: `${name}: ${error instanceof Error ? error.message : String(error)}`,
151
151
  } satisfies OnboardingSnapshotCollectionIssue,
152
152
  };
@@ -162,7 +162,7 @@ export interface OnboardingAcknowledgementSnapshot {
162
162
  }
163
163
 
164
164
  export type OnboardingSnapshotCollectionIssueArea =
165
- | 'services'
165
+ | 'host'
166
166
  | 'subscriptions-active'
167
167
  | 'subscriptions-pending'
168
168
  | 'auth'
@@ -271,6 +271,31 @@ export type OnboardingApplyOperation =
271
271
  readonly kind: 'create-agent-profile';
272
272
  readonly name: string;
273
273
  readonly templateId?: string;
274
+ }
275
+ | {
276
+ readonly kind: 'select-agent-profile';
277
+ readonly name: string;
278
+ }
279
+ | {
280
+ readonly kind: 'create-local-persona';
281
+ readonly name: string;
282
+ readonly description: string;
283
+ readonly body: string;
284
+ readonly activate?: boolean;
285
+ }
286
+ | {
287
+ readonly kind: 'create-local-skill';
288
+ readonly name: string;
289
+ readonly description: string;
290
+ readonly procedure: string;
291
+ readonly enabled?: boolean;
292
+ }
293
+ | {
294
+ readonly kind: 'create-local-routine';
295
+ readonly name: string;
296
+ readonly description: string;
297
+ readonly steps: string;
298
+ readonly enabled?: boolean;
274
299
  };
275
300
 
276
301
  export interface OnboardingApplyRequest {