@pellux/goodvibes-agent 0.1.63 → 0.1.65

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 (42) hide show
  1. package/CHANGELOG.md +12 -0
  2. package/README.md +3 -3
  3. package/docs/getting-started.md +2 -2
  4. package/docs/release-and-publishing.md +1 -1
  5. package/package.json +1 -1
  6. package/src/cli/agent-knowledge-command.ts +1 -1
  7. package/src/cli/help.ts +3 -3
  8. package/src/cli/management-commands.ts +7 -7
  9. package/src/cli/profiles-command.ts +8 -8
  10. package/src/cli/routines-command.ts +1 -1
  11. package/src/cli/service-posture.ts +2 -2
  12. package/src/cli/status.ts +6 -6
  13. package/src/cli/surface-command.ts +1 -1
  14. package/src/input/agent-workspace-categories.ts +16 -17
  15. package/src/input/agent-workspace-setup.ts +4 -4
  16. package/src/input/agent-workspace.ts +1 -1
  17. package/src/input/commands/agent-runtime-profile-runtime.ts +10 -10
  18. package/src/input/commands/local-auth-runtime.ts +1 -1
  19. package/src/input/commands/operator-runtime.ts +2 -2
  20. package/src/input/commands/platform-access-runtime.ts +28 -15
  21. package/src/input/commands/remote-runtime-setup.ts +6 -6
  22. package/src/input/commands/routines-runtime.ts +1 -1
  23. package/src/input/onboarding/onboarding-wizard-steps.ts +3 -3
  24. package/src/panels/automation-control-panel.ts +2 -2
  25. package/src/panels/builtin/agent.ts +1 -1
  26. package/src/panels/builtin/operations.ts +5 -5
  27. package/src/panels/control-plane-panel.ts +10 -10
  28. package/src/panels/local-auth-panel.ts +1 -1
  29. package/src/panels/ops-control-panel.ts +3 -3
  30. package/src/panels/project-planning-panel.ts +2 -2
  31. package/src/panels/provider-health-domains.ts +2 -2
  32. package/src/panels/remote-panel.ts +2 -2
  33. package/src/panels/schedule-panel.ts +1 -1
  34. package/src/panels/watchers-panel.ts +1 -1
  35. package/src/renderer/agent-workspace.ts +9 -9
  36. package/src/renderer/settings-modal-helpers.ts +14 -14
  37. package/src/renderer/settings-modal.ts +4 -4
  38. package/src/runtime/bootstrap.ts +8 -8
  39. package/src/runtime/diagnostics/panels/ops.ts +1 -1
  40. package/src/runtime/index.ts +2 -2
  41. package/src/runtime/onboarding/derivation.ts +15 -15
  42. package/src/version.ts +1 -1
@@ -31,13 +31,26 @@ interface UpdateBundle {
31
31
  interface AuthReviewBundle {
32
32
  readonly version: 1;
33
33
  readonly exportedAt: number;
34
- readonly daemonLoginUrl: string;
34
+ readonly runtimeLoginUrl: string;
35
35
  readonly listenerLoginUrl: string;
36
36
  readonly secretKeys: readonly string[];
37
37
  readonly activeSubscriptions: readonly string[];
38
38
  readonly pendingSubscriptions: readonly string[];
39
39
  }
40
40
 
41
+ type AuthServiceLoginTarget = 'runtime' | 'listener';
42
+
43
+ function normalizeAuthServiceLoginTarget(value: string | undefined): AuthServiceLoginTarget | null {
44
+ const normalized = value?.trim().toLowerCase();
45
+ if (normalized === 'runtime' || normalized === 'daemon') return 'runtime';
46
+ if (normalized === 'listener' || normalized === 'inbound-listener') return 'listener';
47
+ return null;
48
+ }
49
+
50
+ function authServiceSecretPrefix(target: AuthServiceLoginTarget): string {
51
+ return target === 'runtime' ? 'RUNTIME' : 'LISTENER';
52
+ }
53
+
41
54
  function buildSetupLink(surface: string, target?: string): string {
42
55
  const params = target ? `?target=${encodeURIComponent(target)}` : '';
43
56
  return `goodvibes://open/${surface}${params}`;
@@ -68,7 +81,7 @@ function inspectAuthBundle(bundle: AuthReviewBundle): string {
68
81
  return [
69
82
  'Auth Review Bundle',
70
83
  ` exportedAt: ${new Date(bundle.exportedAt).toISOString()}`,
71
- ` daemonLoginUrl: ${bundle.daemonLoginUrl}`,
84
+ ` runtimeLoginUrl: ${bundle.runtimeLoginUrl}`,
72
85
  ` listenerLoginUrl: ${bundle.listenerLoginUrl}`,
73
86
  ` stored secrets: ${bundle.secretKeys.length}`,
74
87
  ` active subscriptions: ${bundle.activeSubscriptions.length}`,
@@ -80,7 +93,7 @@ export function registerPlatformAccessRuntimeCommands(registry: CommandRegistry)
80
93
  registry.register({
81
94
  name: 'login',
82
95
  description: 'Front-door login flow for provider subscriptions and local service sessions',
83
- usage: '[provider <name> start|finish <code> --yes|service <daemon|listener> <baseUrl> <username> <password> [secretKey] --yes]',
96
+ usage: '[provider <name> start|finish <code> --yes|service <runtime|listener> <baseUrl> <username> <password> [secretKey] --yes]',
84
97
  async handler(args, ctx) {
85
98
  const parsed = stripYesFlag(args);
86
99
  const commandArgs = [...parsed.rest];
@@ -106,17 +119,17 @@ export function registerPlatformAccessRuntimeCommands(registry: CommandRegistry)
106
119
  }
107
120
  if (target === 'service') {
108
121
  if (!parsed.yes) {
109
- requireYesFlag(ctx, 'store a local service session token', '/login service <daemon|listener> <baseUrl> <username> <password> [secretKey] --yes');
122
+ requireYesFlag(ctx, 'store a local service session token', '/login service <runtime|listener> <baseUrl> <username> <password> [secretKey] --yes');
110
123
  return;
111
124
  }
112
125
  if (ctx.executeCommand) {
113
126
  await ctx.executeCommand('auth', ['login', ...commandArgs.slice(1), '--yes']);
114
127
  return;
115
128
  }
116
- ctx.print('Use /auth login <daemon|listener> <baseUrl> <username> <password> [secretKey] --yes');
129
+ ctx.print('Use /auth login <runtime|listener> <baseUrl> <username> <password> [secretKey] --yes');
117
130
  return;
118
131
  }
119
- ctx.print('Usage: /login [provider <name> start|finish <code> --yes|service <daemon|listener> <baseUrl> <username> <password> [secretKey] --yes]');
132
+ ctx.print('Usage: /login [provider <name> start|finish <code> --yes|service <runtime|listener> <baseUrl> <username> <password> [secretKey] --yes]');
120
133
  },
121
134
  });
122
135
 
@@ -293,7 +306,7 @@ export function registerPlatformAccessRuntimeCommands(registry: CommandRegistry)
293
306
  registry.register({
294
307
  name: 'auth',
295
308
  description: 'Review auth posture and exchange session login tokens with local services',
296
- usage: '[review|show <provider>|repair <provider>|bundle export <path> --yes|bundle inspect <path>|login <daemon|listener> <baseUrl> <username> <password> [secretKey] --yes|local <review|panel|add-user --yes|delete-user --yes|rotate-password --yes|revoke-session --yes|clear-bootstrap-file --yes>]',
309
+ usage: '[review|show <provider>|repair <provider>|bundle export <path> --yes|bundle inspect <path>|login <runtime|listener> <baseUrl> <username> <password> [secretKey] --yes|local <review|panel|add-user --yes|delete-user --yes|rotate-password --yes|revoke-session --yes|clear-bootstrap-file --yes>]',
297
310
  async handler(args, ctx) {
298
311
  const parsed = stripYesFlag(args);
299
312
  const commandArgs = [...parsed.rest];
@@ -315,7 +328,7 @@ export function registerPlatformAccessRuntimeCommands(registry: CommandRegistry)
315
328
  const builtinProviders = listBuiltinSubscriptionProviders().map((entry) => entry.provider);
316
329
  ctx.print([
317
330
  'Auth Review',
318
- ' daemon login route: /login',
331
+ ' runtime login route: /login',
319
332
  ' listener login route: /login',
320
333
  ` stored secrets: ${snapshot.secretKeyCount}`,
321
334
  ` built-in providers: ${builtinProviders.length}${builtinProviders.length > 0 ? ` (${builtinProviders.join(', ')})` : ''}`,
@@ -397,7 +410,7 @@ export function registerPlatformAccessRuntimeCommands(registry: CommandRegistry)
397
410
  const bundle: AuthReviewBundle = {
398
411
  version: 1,
399
412
  exportedAt: Date.now(),
400
- daemonLoginUrl: 'http://127.0.0.1:3421/login',
413
+ runtimeLoginUrl: 'http://127.0.0.1:3421/login',
401
414
  listenerLoginUrl: 'http://127.0.0.1:3422/login',
402
415
  secretKeys,
403
416
  activeSubscriptions: subscriptions.list().map((entry) => entry.provider),
@@ -416,17 +429,17 @@ export function registerPlatformAccessRuntimeCommands(registry: CommandRegistry)
416
429
  }
417
430
 
418
431
  if (sub === 'login') {
419
- const target = commandArgs[1];
432
+ const target = normalizeAuthServiceLoginTarget(commandArgs[1]);
420
433
  const baseUrl = commandArgs[2];
421
434
  const username = commandArgs[3];
422
435
  const password = commandArgs[4];
423
- const secretKey = commandArgs[5] ?? `${target?.toUpperCase() ?? 'SERVICE'}_SESSION_TOKEN`;
424
- if ((target !== 'daemon' && target !== 'listener') || !baseUrl || !username || !password) {
425
- ctx.print('Usage: /auth login <daemon|listener> <baseUrl> <username> <password> [secretKey] --yes');
436
+ const secretKey = commandArgs[5] ?? `${target ? authServiceSecretPrefix(target) : 'SERVICE'}_SESSION_TOKEN`;
437
+ if (!target || !baseUrl || !username || !password) {
438
+ ctx.print('Usage: /auth login <runtime|listener> <baseUrl> <username> <password> [secretKey] --yes');
426
439
  return;
427
440
  }
428
441
  if (!parsed.yes) {
429
- requireYesFlag(ctx, `store ${target} session token`, '/auth login <daemon|listener> <baseUrl> <username> <password> [secretKey] --yes');
442
+ requireYesFlag(ctx, `store ${target} session token`, '/auth login <runtime|listener> <baseUrl> <username> <password> [secretKey] --yes');
430
443
  return;
431
444
  }
432
445
  const url = new URL('/login', baseUrl).toString();
@@ -450,7 +463,7 @@ export function registerPlatformAccessRuntimeCommands(registry: CommandRegistry)
450
463
  return;
451
464
  }
452
465
 
453
- ctx.print('Usage: /auth [review|show <provider>|bundle export <path> --yes|bundle inspect <path>|login <daemon|listener> <baseUrl> <username> <password> [secretKey] --yes|local <review|panel|add-user --yes|delete-user --yes|rotate-password --yes|revoke-session --yes|clear-bootstrap-file --yes>]');
466
+ ctx.print('Usage: /auth [review|show <provider>|bundle export <path> --yes|bundle inspect <path>|login <runtime|listener> <baseUrl> <username> <password> [secretKey] --yes|local <review|panel|add-user --yes|delete-user --yes|rotate-password --yes|revoke-session --yes|clear-bootstrap-file --yes>]');
454
467
  },
455
468
  });
456
469
  }
@@ -43,15 +43,15 @@ export async function handleRemoteSetupCommand(
43
43
  const lines = [
44
44
  'Remote Setup Review',
45
45
  ` acp agent command: ${command.join(' ')}`,
46
- ` daemon enabled: ${danger.daemon ? 'yes' : 'no'}`,
47
- ` http listener enabled: ${danger.httpListener ? 'yes' : 'no'}`,
46
+ ` runtime host enabled: ${danger.daemon ? 'yes' : 'no'}`,
47
+ ` inbound listener enabled: ${danger.httpListener ? 'yes' : 'no'}`,
48
48
  ` remote runner contracts: ${remoteRegistry.listContracts().length}`,
49
49
  ` active acp connections: ${activeConnections.length}`,
50
50
  '',
51
51
  ' guidance:',
52
52
  ' - set ACP_AGENT_CMD to override the spawned remote agent command',
53
53
  ' - use /remote env to export a reusable shell snippet',
54
- ' - enable danger.daemon / danger.httpListener only when you actually need those remote surfaces',
54
+ ' - runtime-host and inbound-listener posture belongs to the runtime owner, not Agent onboarding',
55
55
  ];
56
56
  if (commandArgs[1]?.toLowerCase() === 'export') {
57
57
  const pathArg = commandArgs[2];
@@ -69,8 +69,8 @@ export async function handleRemoteSetupCommand(
69
69
  writeFileSync(targetPath, `${JSON.stringify({
70
70
  exportedAt: Date.now(),
71
71
  acpAgentCommand: command,
72
- daemonEnabled: Boolean(danger.daemon),
73
- httpListenerEnabled: Boolean(danger.httpListener),
72
+ runtimeHostEnabled: Boolean(danger.daemon),
73
+ inboundListenerEnabled: Boolean(danger.httpListener),
74
74
  remoteRunnerContracts: remoteRegistry.listContracts().length,
75
75
  }, null, 2)}\n`, 'utf-8');
76
76
  ctx.print(`Exported remote setup bundle to ${targetPath}`);
@@ -111,7 +111,7 @@ export async function handleRemoteSetupCommand(
111
111
  const mode = commandArgs[1]?.toLowerCase() ?? 'review';
112
112
  const lines = [
113
113
  'Remote Tunnel Review',
114
- ' transport: self-hosted ACP / daemon relay',
114
+ ' transport: self-hosted ACP / runtime relay',
115
115
  ` session: ${ctx.session.runtime.sessionId}`,
116
116
  ` active remote connections: ${activeConnections.length}`,
117
117
  ' guidance: forward ACP agent traffic through your chosen self-hosted tunnel or SSH transport',
@@ -243,7 +243,7 @@ export async function runRoutinesRuntimeCommand(args: readonly string[], ctx: Co
243
243
  const routine = routineRegistry.markStarted(id);
244
244
  ctx.print([
245
245
  `Started Agent routine ${routine.id}: ${routine.name}`,
246
- ' policy: same main conversation; no hidden background job, daemon mutation, or external side effect was started',
246
+ ' policy: same main conversation; no hidden job, runtime mutation, or external side effect was started',
247
247
  '',
248
248
  routine.steps,
249
249
  ].join('\n'));
@@ -201,7 +201,7 @@ export function buildAgentSetupStep(controller: OnboardingWizardController): Onb
201
201
  {
202
202
  kind: 'status',
203
203
  id: 'agent-setup.profile-guide',
204
- label: 'Runtime profiles',
204
+ label: 'Agent profiles',
205
205
  hint: 'Use /agent-profile guide after setup to create household, research, travel, operations, or custom Agent profiles.',
206
206
  defaultValue: 'Local profiles',
207
207
  },
@@ -378,7 +378,7 @@ export function buildLocalStateStep(): OnboardingWizardStepDefinition {
378
378
  id: 'agent-local-state',
379
379
  title: 'Local memory and behavior',
380
380
  shortLabel: 'Memory',
381
- description: 'Review the Agent-local behavior model. Memory, personas, skills, routines, and runtime profiles stay local until a stable shared registry exists.',
381
+ description: 'Review the Agent-local behavior model. Memory, personas, skills, routines, and Agent profiles stay local until a stable shared registry exists.',
382
382
  summaryTitle: 'Local Agent state',
383
383
  summaryLines: [
384
384
  'Memory/personas/skills/routines: local Agent registries',
@@ -501,7 +501,7 @@ export function buildVoiceMediaStep(): OnboardingWizardStepDefinition {
501
501
  kind: 'status',
502
502
  id: 'agent-voice-media.nodes',
503
503
  label: 'Node and device posture',
504
- hint: 'Remote devices and nodes are inspected as capability surfaces. Agent does not own runner topology or launch service processes from onboarding.',
504
+ hint: 'Remote devices and nodes are inspected only when useful. Agent onboarding does not launch runners or background service processes.',
505
505
  defaultValue: 'External',
506
506
  },
507
507
  ],
@@ -88,12 +88,12 @@ export class AutomationControlPanel extends ScrollableListPanel<AutomationRun> {
88
88
  protected override getEmptyStateActions(): Array<{ command: string; summary: string }> {
89
89
  return [
90
90
  { command: '/schedule list', summary: 'inspect jobs and run history without mutating schedules' },
91
- { command: '/automation jobs', summary: 'review daemon-owned automation jobs from the Agent CLI' },
91
+ { command: '/automation jobs', summary: 'review runtime-owned automation jobs from Agent' },
92
92
  ];
93
93
  }
94
94
 
95
95
  public render(width: number, height: number): Line[] {
96
- const intro = 'Automation jobs, active runs, deliveries, and failure posture across the shared control plane.';
96
+ const intro = 'Automation jobs, active runs, deliveries, and failure posture across the shared runtime.';
97
97
 
98
98
  if (!this.readModel) {
99
99
  const workspace = buildPanelWorkspace(width, height, {
@@ -97,7 +97,7 @@ export function registerAgentPanels(manager: PanelManager, deps: ResolvedBuiltin
97
97
  name: 'Schedule',
98
98
  icon: 'Z',
99
99
  category: 'agent',
100
- description: 'Read-only schedule posture from the external daemon; local Agent schedule mutation is blocked',
100
+ description: 'Read-only schedule posture from the external runtime; local Agent schedule mutation is blocked',
101
101
  factory: () => new SchedulePanel(requireAutomationManager(deps)),
102
102
  });
103
103
  }
@@ -102,7 +102,7 @@ export function registerOperationsPanels(manager: PanelManager, deps: ResolvedBu
102
102
  name: 'Automation',
103
103
  icon: 'M',
104
104
  category: 'monitoring',
105
- description: 'Automation jobs, runs, deliveries, and failure posture across the control plane',
105
+ description: 'Automation jobs, runs, deliveries, and failure posture across the shared runtime',
106
106
  factory: () => new AutomationControlPanel(ui.readModels.automation),
107
107
  });
108
108
 
@@ -126,10 +126,10 @@ export function registerOperationsPanels(manager: PanelManager, deps: ResolvedBu
126
126
 
127
127
  manager.registerType({
128
128
  id: 'control-plane',
129
- name: 'Control Plane',
129
+ name: 'Runtime Status',
130
130
  icon: 'C',
131
131
  category: 'monitoring',
132
- description: 'Daemon control-plane state, clients, approvals, and recent operator activity',
132
+ description: 'Runtime state, clients, approvals, and recent operator activity',
133
133
  factory: () => {
134
134
  requireControlPlanePanelDeps(deps);
135
135
  return new ControlPlanePanel(ui.readModels.controlPlane);
@@ -150,7 +150,7 @@ export function registerOperationsPanels(manager: PanelManager, deps: ResolvedBu
150
150
  name: 'Local Auth',
151
151
  icon: 'U',
152
152
  category: 'monitoring',
153
- description: 'Local daemon/listener auth users, bootstrap posture, and active sessions',
153
+ description: 'Local runtime auth users, bootstrap posture, and active sessions',
154
154
  factory: () => new LocalAuthPanel(deps.localUserAuthManager),
155
155
  });
156
156
 
@@ -251,7 +251,7 @@ export function registerOperationsPanels(manager: PanelManager, deps: ResolvedBu
251
251
  name: 'Remote',
252
252
  icon: 'R',
253
253
  category: 'monitoring',
254
- description: 'Self-hosted daemon and ACP transport state with active remote connections',
254
+ description: 'Runtime transport state with active remote connections',
255
255
  factory: () => new RemotePanel(ui.readModels.remote),
256
256
  });
257
257
 
@@ -42,7 +42,7 @@ export class ControlPlanePanel extends ScrollableListPanel<ControlPlaneClient> {
42
42
  private readonly unsub: (() => void) | null;
43
43
 
44
44
  public constructor(private readonly readModel?: UiReadModel<UiControlPlaneSnapshot>) {
45
- super('control-plane', 'Control Plane', 'C', 'monitoring');
45
+ super('control-plane', 'Runtime Status', 'C', 'monitoring');
46
46
  this.showSelectionGutter = true; // I5: non-color selection affordance
47
47
  this.unsub = readModel ? readModel.subscribe(() => this.markDirty()) : null;
48
48
  }
@@ -72,7 +72,7 @@ export class ControlPlanePanel extends ScrollableListPanel<ControlPlaneClient> {
72
72
  }
73
73
 
74
74
  protected override getEmptyStateMessage(): string {
75
- return ' No control-plane activity recorded.';
75
+ return ' No runtime activity recorded.';
76
76
  }
77
77
 
78
78
  protected override getEmptyStateActions(): Array<{ command: string; summary: string }> {
@@ -83,18 +83,18 @@ export class ControlPlanePanel extends ScrollableListPanel<ControlPlaneClient> {
83
83
  }
84
84
 
85
85
  public render(width: number, height: number): Line[] {
86
- const intro = 'Shared daemon control plane state, live clients, approval pressure, and recent omnichannel session posture.';
86
+ const intro = 'Shared runtime state, live clients, approval pressure, and recent channel session posture.';
87
87
 
88
88
  if (!this.readModel) {
89
89
  const workspace = buildPanelWorkspace(width, height, {
90
- title: 'Control Plane',
90
+ title: 'Runtime Status',
91
91
  intro,
92
92
  sections: [{
93
93
  lines: buildEmptyState(
94
94
  width,
95
95
  ' Runtime read model not wired.',
96
- 'This panel needs the shared control-plane read model to inspect clients, requests, and approvals.',
97
- [{ command: '/cockpit', summary: 'use the cockpit while control-plane wiring is unavailable' }],
96
+ 'This panel needs the shared runtime read model to inspect clients, requests, and approvals.',
97
+ [{ command: '/cockpit', summary: 'use the cockpit while runtime wiring is unavailable' }],
98
98
  C,
99
99
  ),
100
100
  }],
@@ -123,14 +123,14 @@ export class ControlPlanePanel extends ScrollableListPanel<ControlPlaneClient> {
123
123
  { label: 'sessions', value: String(sessions.length), valueColor: sessions.length > 0 ? C.info : C.dim },
124
124
  { label: 'events', value: String(recentEvents.length), valueColor: recentEvents.length > 0 ? C.info : C.dim },
125
125
  ], C),
126
- buildGuidanceLine(width, '/cockpit', 'use the web operator surface or daemon APIs for direct interventions while this panel tracks overall posture', C),
126
+ buildGuidanceLine(width, '/cockpit', 'use confirmed runtime actions for interventions while this panel tracks overall posture', C),
127
127
  ];
128
128
 
129
129
  if (clients.length === 0 && approvals.length === 0 && sessions.length === 0) {
130
130
  return this.renderList(width, height, {
131
- title: 'Control Plane',
131
+ title: 'Runtime Status',
132
132
  header: headerLines,
133
- emptyMessage: ' No control-plane activity recorded.',
133
+ emptyMessage: ' No runtime activity recorded.',
134
134
  });
135
135
  }
136
136
 
@@ -203,7 +203,7 @@ export class ControlPlanePanel extends ScrollableListPanel<ControlPlaneClient> {
203
203
  footerLines.push(buildPanelLine(width, [[' Up/Down move through connected clients', C.dim]]));
204
204
 
205
205
  return this.renderList(width, height, {
206
- title: 'Control Plane',
206
+ title: 'Runtime Status',
207
207
  header: headerLines,
208
208
  footer: footerLines,
209
209
  });
@@ -57,7 +57,7 @@ export class LocalAuthPanel extends ScrollableListPanel<LocalAuthUser> {
57
57
  }
58
58
 
59
59
  public render(width: number, height: number): Line[] {
60
- const intro = 'Manage local daemon and HTTP-listener auth users, bootstrap state, and active sessions.';
60
+ const intro = 'Review local runtime auth users, bootstrap state, and active sessions.';
61
61
  const snapshot = this.authManager.inspect();
62
62
  const users = this.getItems();
63
63
 
@@ -1,5 +1,5 @@
1
1
  /**
2
- * OpsControlPanel — operator control plane UI panel.
2
+ * OpsControlPanel — operator intervention log panel.
3
3
  *
4
4
  * Renders the ops audit log sourced from the OpsPanel diagnostics subscriber.
5
5
  * Each entry shows: seq, timestamp, action, target, outcome, and optional note.
@@ -130,7 +130,7 @@ export class OpsControlPanel extends ScrollableListPanel<OpsAuditEntry> {
130
130
  }
131
131
 
132
132
  protected override getEmptyStateActions(): Array<{ command: string; summary: string }> {
133
- return [{ command: '/cockpit', summary: 'open the cockpit and drive runtime interventions from the control rooms' }];
133
+ return [{ command: '/cockpit', summary: 'open the cockpit and review runtime interventions' }];
134
134
  }
135
135
 
136
136
  public render(width: number, height: number): Line[] {
@@ -142,7 +142,7 @@ export class OpsControlPanel extends ScrollableListPanel<OpsAuditEntry> {
142
142
  ];
143
143
 
144
144
  return this.renderList(width, height, {
145
- title: 'Operator Control Plane',
145
+ title: 'Operator Interventions',
146
146
  header: headerLines,
147
147
  footer: footerLines,
148
148
  });
@@ -545,13 +545,13 @@ export class ProjectPlanningPanel extends BasePanel {
545
545
  id: 'scope-end-to-end',
546
546
  label: 'End-to-end required scope',
547
547
  detail: 'Let the plan include every component needed to make this work, but avoid unrelated cleanup.',
548
- answer: 'Scope is everything required to make the requested outcome work end-to-end. Include TUI, daemon composition, configuration, docs, and tests if they are required. Do not include unrelated cleanup or broad refactors unless they are necessary for this task.',
548
+ answer: 'Scope is everything required to make the requested outcome work end-to-end. Include TUI, runtime composition, configuration, docs, and tests if they are required. Do not include unrelated cleanup or broad refactors unless they are necessary for this task.',
549
549
  });
550
550
  actions.push({
551
551
  id: 'scope-agent-first',
552
552
  label: 'Agent-first scope',
553
553
  detail: 'Fix Agent behavior here; report SDK blockers instead of patching around SDK-owned bugs.',
554
- answer: 'Scope is Agent-owned behavior first. If a blocker is SDK-owned, report the exact SDK contract/runtime issue instead of patching around it locally. Include daemon contracts only where Agent consumes public daemon routes.',
554
+ answer: 'Scope is Agent-owned behavior first. If a blocker is SDK-owned, report the exact SDK contract/runtime issue instead of patching around it locally. Include runtime contracts only where Agent consumes public runtime routes.',
555
555
  });
556
556
  }
557
557
  actions.push({
@@ -63,10 +63,10 @@ export function buildProviderHealthDomainSummaries(
63
63
  name: 'settings',
64
64
  level: !settings.available ? 'info' : settingIssueCount > 0 ? 'warn' : 'good',
65
65
  summary: !settings.available
66
- ? 'settings control plane unavailable'
66
+ ? 'settings runtime API unavailable'
67
67
  : settingIssueCount > 0
68
68
  ? `${settings.conflictCount} conflicts / ${settings.recentFailureCount} failures${settings.hasStagedManagedBundle ? ' / staged bundle' : ''}`
69
- : 'settings control plane clean',
69
+ : 'settings runtime API clean',
70
70
  next: settingIssueCount > 0 ? '/settingssync panel' : '/settingssync show <key>',
71
71
  details: [
72
72
  settings.conflictCount > 0 ? `${settings.conflictCount} unresolved import conflict(s)` : '',
@@ -158,7 +158,7 @@ export class RemotePanel extends BasePanel {
158
158
 
159
159
  const postureLines: Line[] = [
160
160
  buildPanelLine(width, [
161
- [' daemon ', C.label],
161
+ [' runtime ', C.label],
162
162
  [daemon.transportState.toUpperCase(), stateColor(daemon.transportState)],
163
163
  [' running ', C.label],
164
164
  [daemon.isRunning ? 'yes' : 'no', daemon.isRunning ? C.ok : C.dim],
@@ -199,7 +199,7 @@ export class RemotePanel extends BasePanel {
199
199
 
200
200
  if (daemon.lastError) {
201
201
  postureLines.push(buildPanelLine(width, [
202
- [' daemon error ', C.label],
202
+ [' runtime error ', C.label],
203
203
  [daemon.lastError.slice(0, Math.max(0, width - 14)), C.error],
204
204
  ]));
205
205
  }
@@ -171,7 +171,7 @@ export class SchedulePanel extends BasePanel {
171
171
  }
172
172
  case 'return':
173
173
  case ' ': {
174
- this.setError('Schedule mutation is read-only in GoodVibes Agent; use daemon/TUI-owned explicit approval routes later.');
174
+ this.setError('Schedule mutation is read-only in GoodVibes Agent; use explicit runtime approval routes later.');
175
175
  return true;
176
176
  }
177
177
  case 'r': {
@@ -130,7 +130,7 @@ export class WatchersPanel extends ScrollableListPanel<WatcherEntry> {
130
130
  { label: 'degraded', value: String(snapshot.totalDegraded), valueColor: snapshot.totalDegraded > 0 ? C.warn : C.dim },
131
131
  { label: 'lagged', value: String(snapshot.totalLagged), valueColor: snapshot.totalLagged > 0 ? C.warn : C.dim },
132
132
  ], C),
133
- buildGuidanceLine(width, '/schedule list', 'verify jobs consuming these sources and use daemon APIs for watcher lifecycle control', C),
133
+ buildGuidanceLine(width, '/schedule list', 'verify jobs consuming these sources; Agent keeps watcher lifecycle read-only here', C),
134
134
  ];
135
135
 
136
136
  if (watchers.length === 0) {
@@ -153,8 +153,8 @@ function snapshotLines(workspace: AgentWorkspace, category: AgentWorkspaceCatego
153
153
  );
154
154
  } else if (category.id === 'setup') {
155
155
  base.push(
156
- { text: `External runtime: ${snapshot.daemonBaseUrl}`, fg: PALETTE.info },
157
- { text: `Runtime ownership: ${snapshot.daemonOwnership}; Agent never starts or restarts it`, fg: PALETTE.good },
156
+ { text: `GoodVibes runtime: ${snapshot.daemonBaseUrl}`, fg: PALETTE.info },
157
+ { text: `Runtime owner: ${snapshot.daemonOwnership}; Agent connects but never starts or restarts it`, fg: PALETTE.good },
158
158
  { text: `Workspace: ${snapshot.workingDirectory}`, fg: PALETTE.muted },
159
159
  { text: `Home: ${snapshot.homeDirectory}`, fg: PALETTE.muted },
160
160
  { text: '' },
@@ -166,7 +166,7 @@ function snapshotLines(workspace: AgentWorkspace, category: AgentWorkspaceCatego
166
166
  const configuredDefaults = snapshot.channels.filter((channel) => channel.defaultTarget === 'configured').length;
167
167
  const disabledChannels = snapshot.channels.filter((channel) => !channel.enabled).map((channel) => channel.label).join(', ');
168
168
  base.push(
169
- { text: `External runtime: ${snapshot.daemonBaseUrl}`, fg: PALETTE.info },
169
+ { text: `GoodVibes runtime: ${snapshot.daemonBaseUrl}`, fg: PALETTE.info },
170
170
  { text: `Readiness: ${readyCount}/${snapshot.channels.length} ready; ${enabledCount} enabled; ${configuredDefaults} default target(s) configured.`, fg: PALETTE.info },
171
171
  { text: `Disabled channels: ${disabledChannels || 'none'}.`, fg: PALETTE.dim },
172
172
  { text: 'Pairing: use /pair or /qrcode for companion setup.', fg: PALETTE.info },
@@ -195,18 +195,18 @@ function snapshotLines(workspace: AgentWorkspace, category: AgentWorkspaceCatego
195
195
  { text: `Voice surface: ${snapshot.voiceSurfaceEnabled ? 'enabled' : 'disabled'}; use /voice review for portable voice posture.`, fg: snapshot.voiceSurfaceEnabled ? PALETTE.warn : PALETTE.muted },
196
196
  { text: `TTS config: provider ${snapshot.ttsProvider}; voice ${snapshot.ttsVoice}; response model ${snapshot.ttsResponseModel}.`, fg: PALETTE.info },
197
197
  { text: `Media providers: ${snapshot.mediaProviderCount}; understanding: ${snapshot.mediaUnderstandingProviderCount}; generation: ${snapshot.mediaGenerationProviderCount}.`, fg: PALETTE.info },
198
- { text: `Browser surface: ${snapshot.browserSurfaceEnabled ? 'enabled' : 'disabled'}; public base URL ${snapshot.browserSurfacePublicBaseUrl}.`, fg: snapshot.browserSurfaceEnabled ? PALETTE.warn : PALETTE.muted },
199
- { text: 'Node/remote posture is read-only here; build dispatch remains explicit TUI delegation.', fg: PALETTE.good },
198
+ { text: `Browser tools: ${snapshot.browserSurfaceEnabled ? 'available' : 'not advertised'}; public base URL ${snapshot.browserSurfacePublicBaseUrl}.`, fg: snapshot.browserSurfaceEnabled ? PALETTE.warn : PALETTE.muted },
199
+ { text: 'Remote runner posture is hidden from this setup surface; build dispatch remains explicit delegation.', fg: PALETTE.good },
200
200
  { text: 'Image input uses prompt attachments; media generation/provider setup stays behind explicit commands and configured providers.', fg: PALETTE.muted },
201
201
  );
202
202
  } else if (category.id === 'profiles') {
203
203
  base.push(
204
- { text: `Active runtime profile: ${snapshot.activeRuntimeProfile}`, fg: PALETTE.info },
205
- { text: `Runtime profiles under this home: ${snapshot.runtimeProfileCount}`, fg: PALETTE.info },
206
- { text: `Runtime profile root: ${snapshot.runtimeProfileRoot}`, fg: PALETTE.muted },
204
+ { text: `Active Agent profile: ${snapshot.activeRuntimeProfile}`, fg: PALETTE.info },
205
+ { text: `Agent profiles under this home: ${snapshot.runtimeProfileCount}`, fg: PALETTE.info },
206
+ { text: `Agent profile root: ${snapshot.runtimeProfileRoot}`, fg: PALETTE.muted },
207
207
  { text: `Starter templates: ${snapshot.runtimeStarterTemplateCount}; local custom: ${snapshot.localStarterTemplateCount}`, fg: PALETTE.info },
208
208
  { text: `Config profiles: ${snapshot.configProfileCount}`, fg: PALETTE.info },
209
- { text: 'Named runtime profiles isolate Agent-local config, sessions, memory, personas, skills, routines, setup, and bundles.', fg: PALETTE.good },
209
+ { text: 'Named Agent profiles isolate local config, sessions, memory, personas, skills, routines, setup, and bundles.', fg: PALETTE.good },
210
210
  { text: 'Starter authoring: browse, export, edit, import, and create Agent profiles from inside this workspace via /agent-profile.', fg: PALETTE.info },
211
211
  { text: 'The external GoodVibes runtime remains shared unless the owning host is configured separately.', fg: PALETTE.warn },
212
212
  { text: 'Portable bundles require explicit export/import commands with real paths and --yes.', fg: PALETTE.muted },
@@ -87,7 +87,7 @@ export const CATEGORY_LABELS: Record<(typeof SETTINGS_CATEGORIES)[number], strin
87
87
  helper: 'Helper',
88
88
  tts: 'TTS',
89
89
  service: 'Service',
90
- controlPlane: 'Control Plane',
90
+ controlPlane: 'Runtime API',
91
91
  httpListener: 'HTTP Listener',
92
92
  web: 'Web',
93
93
  batch: 'Batch',
@@ -123,18 +123,18 @@ export const SETTING_LABELS: Partial<Record<string, string>> = {
123
123
  'helper.enabled': 'Helper Enabled',
124
124
  'helper.globalProvider': 'Helper Provider',
125
125
  'helper.globalModel': 'Helper Model',
126
- // Control Plane
127
- 'controlPlane.enabled': 'CP Enabled',
128
- 'controlPlane.hostMode': 'CP Host Mode',
129
- 'controlPlane.host': 'CP Host',
130
- 'controlPlane.port': 'CP Port',
131
- 'controlPlane.baseUrl': 'CP Base URL',
132
- 'controlPlane.streamMode': 'CP Stream Mode',
133
- 'controlPlane.allowRemote': 'CP Allow Remote',
134
- 'controlPlane.trustProxy': 'CP Trust Proxy',
135
- 'controlPlane.tls.mode': 'CP TLS Mode',
136
- 'controlPlane.tls.certFile': 'CP TLS Cert',
137
- 'controlPlane.tls.keyFile': 'CP TLS Key',
126
+ // Runtime API
127
+ 'controlPlane.enabled': 'Runtime API Enabled',
128
+ 'controlPlane.hostMode': 'Runtime API Host Mode',
129
+ 'controlPlane.host': 'Runtime API Host',
130
+ 'controlPlane.port': 'Runtime API Port',
131
+ 'controlPlane.baseUrl': 'Runtime API Base URL',
132
+ 'controlPlane.streamMode': 'Runtime API Stream Mode',
133
+ 'controlPlane.allowRemote': 'Runtime API Allow Remote',
134
+ 'controlPlane.trustProxy': 'Runtime API Trust Proxy',
135
+ 'controlPlane.tls.mode': 'Runtime API TLS Mode',
136
+ 'controlPlane.tls.certFile': 'Runtime API TLS Cert',
137
+ 'controlPlane.tls.keyFile': 'Runtime API TLS Key',
138
138
  // HTTP Listener
139
139
  'httpListener.hostMode': 'HTTP Host Mode',
140
140
  'httpListener.host': 'HTTP Host',
@@ -154,7 +154,7 @@ export const SETTING_LABELS: Partial<Record<string, string>> = {
154
154
  'surfaces.ntfy.topic': 'ntfy Default Delivery Topic',
155
155
  'surfaces.ntfy.chatTopic': 'ntfy Chat Topic',
156
156
  'surfaces.ntfy.agentTopic': 'ntfy Agent Topic',
157
- 'surfaces.ntfy.remoteTopic': 'ntfy Daemon-Only Remote Topic',
157
+ 'surfaces.ntfy.remoteTopic': 'ntfy Runtime-Only Remote Topic',
158
158
  'surfaces.ntfy.token': 'ntfy Token',
159
159
  'surfaces.ntfy.defaultPriority': 'ntfy Default Priority',
160
160
  };
@@ -35,7 +35,7 @@ const CATEGORY_INFO: Record<SettingsCategory, string> = {
35
35
  helper: 'Helper model defaults used by helper subsystems when they do not use the main chat route.',
36
36
  tts: 'Text-to-speech provider, voice, and optional spoken-turn LLM overrides.',
37
37
  service: 'External GoodVibes runtime service posture. Agent shows these compatibility keys for inspection only and does not install, start, stop, restart, or autostart services.',
38
- controlPlane: 'External GoodVibes runtime control-plane settings for local admin/API access. Agent connects to that runtime and does not mutate its bind posture.',
38
+ controlPlane: 'External GoodVibes runtime API settings for local admin/API access. Agent connects to that runtime and does not mutate its bind posture.',
39
39
  httpListener: 'External HTTP listener settings for webhook and integration ingress. Agent does not start or expose the listener.',
40
40
  web: 'External browser surface settings. Agent does not own the web listener or network bind lifecycle.',
41
41
  batch: 'Batch execution settings reported from the external GoodVibes runtime. Agent does not own remote queue provisioning.',
@@ -50,7 +50,7 @@ const CATEGORY_INFO: Record<SettingsCategory, string> = {
50
50
  danger: 'High-impact runtime and listener switches. Agent renders host-owned switches read-only; use GoodVibes TUI or the owning host to change them.',
51
51
  tools: 'Tool LLM and helper model routing. Empty provider/model values inherit the active chat route unless a specific helper/tool route is set.',
52
52
  flags: 'Feature flags are SDK runtime gates. They are separate from normal config keys because they enable or disable staged runtime behavior.',
53
- network: 'Read-only view of external GoodVibes runtime control-plane, HTTP listener, and browser web bind posture plus editable Agent network settings.',
53
+ network: 'Read-only view of external GoodVibes runtime API, HTTP listener, and browser web bind posture plus editable Agent network settings.',
54
54
  };
55
55
 
56
56
  const ENUM_VALUE_DESCRIPTIONS: Record<string, Record<string, string>> = {
@@ -75,9 +75,9 @@ const ENUM_VALUE_DESCRIPTIONS: Record<string, Record<string, string>> = {
75
75
  plaintext_allowed: 'Allow plaintext fallback when secure storage is unavailable.',
76
76
  },
77
77
  'batch.mode': {
78
- off: 'Keep daemon work on the immediate local path.',
78
+ off: 'Keep runtime work on the immediate local path.',
79
79
  explicit: 'Use batch only when callers explicitly request batch execution.',
80
- 'eligible-by-default': 'Allow eligible daemon work to use the batch path unless callers opt out.',
80
+ 'eligible-by-default': 'Allow eligible runtime work to use the batch path unless callers opt out.',
81
81
  },
82
82
  'controlPlane.hostMode': {
83
83
  localhost: 'Bind only to this computer.',
@@ -46,8 +46,8 @@ import { buildEnabledRoutinesPrompt } from '../agent/routine-registry.ts';
46
46
 
47
47
  const GOODVIBES_AGENT_OPERATOR_POLICY = [
48
48
  '## GoodVibes Agent Operator Policy',
49
- '- 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 daemon/operator routes, and take safe non-destructive actions without spawning local agents or WRFC.',
50
- '- GoodVibes Agent connects to an externally managed GoodVibes daemon. Do not start, stop, restart, install, expose, or mutate daemon/listener/control-plane surface posture from Agent runtime.',
49
+ '- 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 runtime/operator routes, and take safe non-destructive actions without spawning local agents or WRFC.',
50
+ '- GoodVibes Agent connects to an externally managed GoodVibes runtime host. Do not start, stop, restart, install, expose, or mutate runtime-host network/listener posture from Agent runtime.',
51
51
  '- Use the `agent_local_registry` tool when a reusable persona, skill, or routine would improve future work. Keep those records local, non-secret, source/provenance tagged, and reviewable. Starting a routine means applying its steps in this same serial conversation, not creating a background job.',
52
52
  '- 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.',
53
53
  '- 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.',
@@ -332,8 +332,8 @@ export async function bootstrapRuntime(
332
332
  port,
333
333
  baseUrl: formatHostServiceBaseUrl(host, port),
334
334
  reason: service === 'daemon'
335
- ? 'GoodVibes Agent connects to an externally managed GoodVibes daemon and does not start or restart it.'
336
- : 'GoodVibes Agent does not own the HTTP listener lifecycle.',
335
+ ? 'GoodVibes Agent connects to an externally managed GoodVibes runtime host and does not start or restart it.'
336
+ : 'GoodVibes Agent does not own external listener lifecycle.',
337
337
  };
338
338
  };
339
339
 
@@ -373,7 +373,7 @@ export async function bootstrapRuntime(
373
373
  daemonStatus: createExternalAgentServiceStatus('daemon'),
374
374
  httpListenerStatus: createExternalAgentServiceStatus('httpListener'),
375
375
  };
376
- systemMessageRouter.high('[Startup] GoodVibes Agent does not start or restart daemon/listener services. Start the daemon from GoodVibes TUI or the daemon host, then refresh status.');
376
+ systemMessageRouter.high('[Startup] GoodVibes Agent does not start or restart runtime-host services. Start the GoodVibes runtime from its owner, then refresh status.');
377
377
  requestRender();
378
378
  return inspectExternalServices();
379
379
  },
@@ -450,8 +450,8 @@ export async function bootstrapRuntime(
450
450
  });
451
451
  bootstrapUnsubs.push(() => mcpAutoReload.stop());
452
452
  if (configManager.get('automation.enabled')) {
453
- logger.warn('Local automation startup is disabled in GoodVibes Agent; use external daemon observability instead.');
454
- systemMessageRouter.low('[Startup] Local automation runners are disabled in GoodVibes Agent; use read-only automation observability or explicit external-daemon actions.');
453
+ logger.warn('Local automation startup is disabled in GoodVibes Agent; use external runtime observability instead.');
454
+ systemMessageRouter.low('[Startup] Local automation runners are disabled in GoodVibes Agent; use read-only automation observability or explicit external-runtime actions.');
455
455
  }
456
456
 
457
457
  // ── Phase 12: Session:start lifecycle hook ─────────────────────────────
@@ -552,7 +552,7 @@ export async function bootstrapRuntime(
552
552
  },
553
553
  };
554
554
 
555
- // ── Phase 12b: Operator Control Plane wiring (feature-gated) ──────────────
555
+ // ── Phase 12b: Operator intervention wiring (feature-gated) ──────────────
556
556
  // Wire the OpsControlPlane into CommandContext when the feature flag is enabled.
557
557
  // The store and task manager are created unconditionally so they reflect the
558
558
  // real runtime state (tasks registered before the flag check are visible).