@pellux/goodvibes-agent 0.1.106 → 0.1.108

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 (79) hide show
  1. package/CHANGELOG.md +41 -10
  2. package/README.md +28 -9
  3. package/docs/README.md +5 -5
  4. package/docs/{runtime-connection.md → connected-services.md} +8 -8
  5. package/docs/getting-started.md +29 -10
  6. package/docs/release-and-publishing.md +4 -4
  7. package/package.json +2 -12
  8. package/src/agent/reminder-schedule-format.ts +75 -0
  9. package/src/agent/reminder-schedule.ts +494 -0
  10. package/src/agent/routine-schedule-format.ts +7 -7
  11. package/src/agent/routine-schedule-promotion.ts +1 -1
  12. package/src/agent/routine-schedule-receipts.ts +1 -1
  13. package/src/agent/skill-discovery.ts +2 -0
  14. package/src/cli/agent-knowledge-args.ts +93 -0
  15. package/src/cli/agent-knowledge-command.ts +200 -369
  16. package/src/cli/agent-knowledge-format.ts +58 -7
  17. package/src/cli/agent-knowledge-methods.ts +84 -0
  18. package/src/cli/agent-knowledge-runtime.ts +240 -0
  19. package/src/cli/config-overrides.ts +2 -2
  20. package/src/cli/help.ts +31 -11
  21. package/src/cli/management-commands.ts +2 -2
  22. package/src/cli/management.ts +8 -8
  23. package/src/cli/package-verification.ts +7 -3
  24. package/src/cli/parser.ts +10 -2
  25. package/src/cli/service-posture.ts +6 -6
  26. package/src/cli/status.ts +32 -32
  27. package/src/cli/tui-startup.ts +3 -1
  28. package/src/input/agent-workspace-activation.ts +24 -13
  29. package/src/input/agent-workspace-basic-command-editors.ts +448 -0
  30. package/src/input/agent-workspace-categories.ts +42 -34
  31. package/src/input/agent-workspace-channels.ts +3 -3
  32. package/src/input/agent-workspace-command-editor.ts +65 -0
  33. package/src/input/agent-workspace-editors.ts +17 -2
  34. package/src/input/agent-workspace-knowledge-query-editor.ts +74 -0
  35. package/src/input/agent-workspace-knowledge-url-editor.ts +95 -0
  36. package/src/input/agent-workspace-reminder-schedule-editor.ts +125 -0
  37. package/src/input/agent-workspace-routine-schedule-editor.ts +127 -0
  38. package/src/input/agent-workspace-setup.ts +2 -2
  39. package/src/input/agent-workspace-types.ts +20 -2
  40. package/src/input/agent-workspace-voice-media.ts +5 -5
  41. package/src/input/agent-workspace.ts +39 -2
  42. package/src/input/commands/agent-runtime-profile-runtime.ts +1 -1
  43. package/src/input/commands/agent-skills-runtime.ts +94 -2
  44. package/src/input/commands/brief-runtime.ts +126 -0
  45. package/src/input/commands/channels-runtime.ts +47 -0
  46. package/src/input/commands/health-runtime.ts +10 -10
  47. package/src/input/commands/knowledge.ts +176 -1
  48. package/src/input/commands/planning-runtime.ts +1 -1
  49. package/src/input/commands/platform-access-runtime.ts +10 -10
  50. package/src/input/commands/policy-dispatch.ts +1 -1
  51. package/src/input/commands/schedule-runtime.ts +42 -5
  52. package/src/input/commands/security-runtime.ts +1 -1
  53. package/src/input/commands/session-content.ts +1 -1
  54. package/src/input/commands/session-workflow.ts +1 -1
  55. package/src/input/commands/shell-core.ts +4 -2
  56. package/src/input/commands/tasks-runtime.ts +3 -3
  57. package/src/input/commands.ts +4 -0
  58. package/src/input/handler-onboarding.ts +4 -4
  59. package/src/input/handler.ts +3 -2
  60. package/src/input/onboarding/onboarding-wizard-helpers.ts +1 -1
  61. package/src/input/onboarding/onboarding-wizard-operator-steps.ts +13 -13
  62. package/src/input/onboarding/onboarding-wizard-steps.ts +8 -8
  63. package/src/input/settings-modal-agent-policy.ts +1 -1
  64. package/src/input/slash-command-parser.ts +60 -0
  65. package/src/panels/builtin/agent.ts +1 -1
  66. package/src/panels/builtin/operations.ts +2 -2
  67. package/src/panels/provider-account-snapshot.ts +1 -1
  68. package/src/panels/provider-health-domains.ts +6 -6
  69. package/src/panels/subscription-panel.ts +1 -1
  70. package/src/panels/tasks-panel.ts +3 -3
  71. package/src/renderer/agent-workspace.ts +43 -30
  72. package/src/renderer/help-overlay.ts +1 -1
  73. package/src/renderer/settings-modal.ts +13 -13
  74. package/src/runtime/bootstrap-hook-bridge.ts +1 -1
  75. package/src/runtime/bootstrap.ts +8 -8
  76. package/src/runtime/index.ts +2 -2
  77. package/src/runtime/onboarding/derivation.ts +6 -6
  78. package/src/shell/service-settings-sync.ts +1 -1
  79. package/src/version.ts +1 -1
@@ -144,7 +144,7 @@ export function registerSessionContentCommands(registry: CommandRegistry): void
144
144
  if (meta.title) ctx.session.conversationManager.title = meta.title;
145
145
  ctx.session.conversationManager.rebuildHistory();
146
146
  ctx.renderRequest();
147
- ctx.print(`Session loaded: ${args[0]} (${messages.length} messages)${agentRecords.length > 0 ? ` [ignored ${agentRecords.length} runtime-owned local agent record${agentRecords.length !== 1 ? 's' : ''}]` : ''}`);
147
+ ctx.print(`Session loaded: ${args[0]} (${messages.length} messages)${agentRecords.length > 0 ? ` [ignored ${agentRecords.length} service-owned local agent record${agentRecords.length !== 1 ? 's' : ''}]` : ''}`);
148
148
  } catch (e) {
149
149
  ctx.print(`Failed to load session: ${summarizeError(e)}`);
150
150
  }
@@ -264,7 +264,7 @@ export async function handleSessionWorkflowCommand(args: string[], ctx: CommandC
264
264
  ctx.print(` Reopened panels: ${reopenedPanels.join(', ')}`);
265
265
  }
266
266
  if ((meta.returnContext.remoteRunners?.length ?? 0) > 0) {
267
- ctx.print(' Remote re-entry: use the external runtime host for remote runner recovery; delegate explicit build/fix/review recovery from Agent.');
267
+ ctx.print(' Remote re-entry: handle remote runner recovery outside Agent; delegate explicit build/fix/review recovery from Agent.');
268
268
  }
269
269
  if ((meta.returnContext.worktreePaths?.length ?? 0) > 0) {
270
270
  ctx.print(' Worktree re-entry: open GoodVibes TUI in the target workspace; delegate explicit build/fix/review recovery from Agent.');
@@ -116,13 +116,15 @@ export function registerShellCoreCommands(registry: CommandRegistry): void {
116
116
  const items: SelectionItem[] = [
117
117
  { id: '/agent', label: '/agent', detail: 'Open the Agent operator workspace', category: 'Agent Operator' },
118
118
  { id: '/home', label: '/home', detail: 'Alias for the Agent operator workspace', category: 'Agent Operator' },
119
+ { id: '/brief', label: '/brief', detail: 'Show a concise Agent operator briefing and next actions', category: 'Agent Operator' },
119
120
  { id: '/knowledge', label: '/knowledge', detail: 'Inspect isolated Agent Knowledge status, ask/search, and ingest flows', category: 'Agent Operator' },
120
121
  { id: '/memory', label: '/memory', detail: 'Review local Agent memory records', category: 'Agent Operator' },
121
122
  { id: '/personas', label: '/personas', detail: 'Create, review, and activate local Agent personas', category: 'Agent Operator' },
122
123
  { id: '/agent-skills', label: '/agent-skills', detail: 'Create, review, and enable reusable Agent skills', category: 'Agent Operator' },
123
124
  { id: '/routines', label: '/routines', detail: 'Create, review, start, and promote Agent routines explicitly', category: 'Agent Operator' },
124
125
  { id: '/delegate', label: '/delegate [task]', detail: 'Explicit build/fix/review handoff to GoodVibes TUI', category: 'Agent Operator' },
125
- { id: '/pair', label: '/pair', detail: 'Pair companion clients through the GoodVibes runtime', category: 'Agent Operator' },
126
+ { id: '/channels', label: '/channels', detail: 'Inspect messaging-channel readiness without sending messages', category: 'Agent Operator' },
127
+ { id: '/pair', label: '/pair', detail: 'Pair companion clients through connected GoodVibes services', category: 'Agent Operator' },
126
128
  { id: '/model', label: '/model [id]', detail: 'Select LLM model', category: 'Model & Provider' },
127
129
  { id: '/provider', label: '/provider [name]', detail: 'Switch provider', category: 'Model & Provider' },
128
130
  { id: '/effort', label: '/effort [level]', detail: 'Reasoning effort (instant/low/medium/high)', category: 'Model & Provider' },
@@ -170,7 +172,7 @@ export function registerShellCoreCommands(registry: CommandRegistry): void {
170
172
  });
171
173
  return;
172
174
  }
173
- ctx.print('Use /help to open the help modal. Commands: /agent, /knowledge, /memory, /personas, /agent-skills, /routines, /delegate, /model, /provider, /config, /paste, /sessions, /bookmarks, /save, /load, /undo, /redo, /retry, /clear, /reset, /compact, /export, /title, /effort, /expand, /collapse, /quit');
175
+ ctx.print('Use /help to open the help modal. Commands: /agent, /brief, /knowledge, /memory, /personas, /agent-skills, /routines, /channels, /delegate, /model, /provider, /config, /paste, /sessions, /bookmarks, /save, /load, /undo, /redo, /retry, /clear, /reset, /compact, /export, /title, /effort, /expand, /collapse, /quit');
174
176
  },
175
177
  });
176
178
 
@@ -16,10 +16,10 @@ const BLOCKED_TASK_MUTATIONS: ReadonlySet<string> = new Set([
16
16
  function printTaskMutationBlocked(print: (text: string) => void, subcommand: string): void {
17
17
  print([
18
18
  `Task mutation "${subcommand}" is blocked in GoodVibes Agent.`,
19
- ' policy: runtime tasks are read-only from the Agent TUI; normal work stays in the main conversation.',
19
+ ' policy: connected-service tasks are read-only from the Agent TUI; normal work stays in the main conversation.',
20
20
  ' durable tasks: use /workplan for visible planning and task tracking.',
21
21
  ' build/fix/review: use /delegate <task> to hand explicit implementation work to GoodVibes TUI.',
22
- ' result: no local runtime task state was changed.',
22
+ ' result: no local task state was changed.',
23
23
  ].join('\n'));
24
24
  }
25
25
 
@@ -51,7 +51,7 @@ export function registerTasksRuntimeCommands(registry: CommandRegistry): void {
51
51
  registry.register({
52
52
  name: 'tasks',
53
53
  aliases: ['task'],
54
- description: 'Inspect runtime tasks without starting or mutating local background work',
54
+ description: 'Inspect connected-service tasks without starting or mutating local background work',
55
55
  usage: '[list [status|kind] | show <taskId> | output <taskId>]',
56
56
  handler(args, ctx) {
57
57
  if (args.length === 0) {
@@ -35,6 +35,8 @@ import { registerDelegationRuntimeCommands } from './commands/delegation-runtime
35
35
  import { registerPersonasRuntimeCommands } from './commands/personas-runtime.ts';
36
36
  import { registerAgentSkillsRuntimeCommands } from './commands/agent-skills-runtime.ts';
37
37
  import { registerRoutinesRuntimeCommands } from './commands/routines-runtime.ts';
38
+ import { registerChannelsRuntimeCommands } from './commands/channels-runtime.ts';
39
+ import { registerBriefRuntimeCommands } from './commands/brief-runtime.ts';
38
40
 
39
41
  function registerAgentMemoryCommand(registry: CommandRegistry): void {
40
42
  registry.register({
@@ -56,10 +58,12 @@ function registerAgentMemoryCommand(registry: CommandRegistry): void {
56
58
  export function registerBuiltinCommands(registry: CommandRegistry): void {
57
59
  registerShellCoreCommands(registry);
58
60
  registerAgentWorkspaceRuntimeCommands(registry);
61
+ registerBriefRuntimeCommands(registry);
59
62
  registerAgentRuntimeProfileRuntimeCommands(registry);
60
63
  registerPersonasRuntimeCommands(registry);
61
64
  registerAgentSkillsRuntimeCommands(registry);
62
65
  registerRoutinesRuntimeCommands(registry);
66
+ registerChannelsRuntimeCommands(registry);
63
67
  registerDelegationRuntimeCommands(registry);
64
68
  registerConfigCommand(registry);
65
69
  registerOperatorRuntimeCommands(registry);
@@ -487,11 +487,11 @@ export function getOnboardingRuntimePostureForHandler(handler: InputHandler, req
487
487
  export async function restartOnboardingExternalServicesIfNeededForHandler(handler: InputHandler, request: OnboardingApplyRequest): Promise<OnboardingVerificationItem[]> {
488
488
  const externalServices = handler.uiServices.platform.externalServices;
489
489
  const state = externalServices?.inspect();
490
- const serviceStatus = state?.daemonStatus?.reason ?? (state?.daemonRunning ? 'external GoodVibes runtime appears active' : 'external GoodVibes runtime is not verified from this shell');
490
+ const serviceStatus = state?.daemonStatus?.reason ?? (state?.daemonRunning ? 'connected GoodVibes services appear active' : 'connected GoodVibes services are not verified from this shell');
491
491
  return [{
492
492
  id: 'runtime:external-service-owned',
493
493
  status: 'pass',
494
- message: `GoodVibes Agent did not start, stop, restart, or reconfigure runtime lifecycle. ${serviceStatus}`,
494
+ message: `GoodVibes Agent did not start, stop, restart, or reconfigure connected services. ${serviceStatus}`,
495
495
  target: 'service',
496
496
  }];
497
497
  }
@@ -503,8 +503,8 @@ export function verifyOnboardingRuntimePostureForHandler(handler: InputHandler,
503
503
  id: 'runtime:external-service-owned',
504
504
  status: 'pass',
505
505
  message: externalState
506
- ? 'GoodVibes runtime lifecycle is externally managed; Agent onboarding did not request shutdown, startup, restart, bind, or surface changes.'
507
- : 'GoodVibes runtime lifecycle is externally managed; no local service controller is required for Agent onboarding.',
506
+ ? 'Connected GoodVibes services are managed outside Agent; Agent onboarding did not request shutdown, startup, restart, bind, or surface changes.'
507
+ : 'Connected GoodVibes services are managed outside Agent; no local service controller is required for Agent onboarding.',
508
508
  target: 'service',
509
509
  }];
510
510
  }
@@ -26,6 +26,7 @@ import { BookmarkModal } from './bookmark-modal.ts';
26
26
  import { SettingsModal } from './settings-modal.ts';
27
27
  import { McpWorkspace } from './mcp-workspace.ts';
28
28
  import { AgentWorkspace } from './agent-workspace.ts';
29
+ import { parseSlashCommand } from './slash-command-parser.ts';
29
30
  import { SessionPickerModal } from './session-picker-modal.ts';
30
31
  import { ProfilePickerModal } from './profile-picker-modal.ts';
31
32
  import { OnboardingWizardController, type OnboardingWizardAction, type OnboardingWizardMode } from './onboarding/onboarding-wizard.ts';
@@ -423,9 +424,9 @@ export class InputHandler {
423
424
  for (let index = this.modalStack.length - 1; index >= 0; index -= 1) {
424
425
  if (this.modalStack[index] === 'agentWorkspace') this.modalStack.splice(index, 1);
425
426
  }
426
- const [name, ...args] = command.trim().replace(/^\//, '').split(/\s+/);
427
+ const { name, args } = parseSlashCommand(command);
427
428
  if (!name) return;
428
- void context.executeCommand?.(name, args).catch((error: unknown) => {
429
+ void context.executeCommand?.(name, [...args]).catch((error: unknown) => {
429
430
  context.print(`Agent workspace command failed: ${error instanceof Error ? error.message : String(error)}`);
430
431
  this.requestRender();
431
432
  });
@@ -49,7 +49,7 @@ export function buildDefaultDerivedState(): OnboardingStepDerivationState {
49
49
  required: false,
50
50
  accepted: false,
51
51
  reason: 'not-needed',
52
- detail: 'No external runtime auth signal needs confirmation.',
52
+ detail: 'No connected-service auth signal needs confirmation.',
53
53
  },
54
54
  },
55
55
  };
@@ -5,10 +5,10 @@ export function buildCommunicationStep(): OnboardingWizardStepDefinition {
5
5
  id: 'agent-communication',
6
6
  title: 'Channels and notifications',
7
7
  shortLabel: 'Channels',
8
- description: 'Prepare the Agent for companion pairing, messaging-channel awareness, notification delivery, and safe outbound communication while leaving runtime hosting external.',
8
+ description: 'Prepare companion pairing, messaging-channel readiness, notification delivery, and safe outbound communication for day-one Agent use.',
9
9
  summaryTitle: 'Communication posture',
10
10
  summaryLines: [
11
- 'Companion chat: paired through the GoodVibes runtime',
11
+ 'Companion chat: paired through connected GoodVibes services',
12
12
  'Channel accounts: inspect readiness before using them',
13
13
  'Outbound messages: explicit user action only',
14
14
  ],
@@ -17,14 +17,14 @@ export function buildCommunicationStep(): OnboardingWizardStepDefinition {
17
17
  kind: 'status',
18
18
  id: 'agent-communication.companion',
19
19
  label: 'Companion pairing',
20
- hint: 'Use /pair from the Agent workspace to pair companion clients through the already-running GoodVibes runtime.',
21
- defaultValue: 'External runtime route',
20
+ hint: 'Use /pair from the Agent workspace to pair companion clients through connected GoodVibes services.',
21
+ defaultValue: 'Pair when ready',
22
22
  },
23
23
  {
24
24
  kind: 'status',
25
25
  id: 'agent-communication.channels',
26
26
  label: 'Messaging channels',
27
- hint: 'Use the Channels workspace to inspect account readiness, delivery posture, and recent communication without changing runtime hosting.',
27
+ hint: 'Use the Channels workspace to inspect account readiness, delivery posture, and recent communication without changing connection state.',
28
28
  defaultValue: 'Inspectable',
29
29
  },
30
30
  {
@@ -38,7 +38,7 @@ export function buildCommunicationStep(): OnboardingWizardStepDefinition {
38
38
  kind: 'status',
39
39
  id: 'agent-communication.inbound-policy',
40
40
  label: 'Inbound command policy',
41
- hint: 'Incoming channel commands stay constrained by runtime policy, allowlists, and account posture.',
41
+ hint: 'Incoming channel commands stay constrained by Agent policy, allowlists, and account posture.',
42
42
  defaultValue: 'Policy gated',
43
43
  },
44
44
  ],
@@ -50,7 +50,7 @@ export function buildToolsStep(): OnboardingWizardStepDefinition {
50
50
  id: 'agent-tools',
51
51
  title: 'Tools and MCP',
52
52
  shortLabel: 'Tools',
53
- description: 'Review tool access for the Agent operator: MCP servers, browser/media helpers, safe read-only inspection, and explicit approval before side effects.',
53
+ description: 'Review tool access for the Agent operator: MCP connections, browser/media helpers, safe read-only inspection, and explicit approval before side effects.',
54
54
  summaryTitle: 'Tool posture',
55
55
  summaryLines: [
56
56
  'MCP and tools: inspect before use',
@@ -61,8 +61,8 @@ export function buildToolsStep(): OnboardingWizardStepDefinition {
61
61
  {
62
62
  kind: 'status',
63
63
  id: 'agent-tools.mcp',
64
- label: 'MCP servers and tools',
65
- hint: 'Use /mcp servers and the Agent workspace Tools area to inspect connected servers, roles, and tool readiness.',
64
+ label: 'MCP connections and tools',
65
+ hint: 'Use /mcp servers and the Agent workspace Tools area to inspect connected MCP servers, roles, and tool readiness.',
66
66
  defaultValue: 'Inspectable',
67
67
  },
68
68
  {
@@ -178,11 +178,11 @@ export function buildAutomationStep(): OnboardingWizardStepDefinition {
178
178
  id: 'agent-automation',
179
179
  title: 'Routines and automation',
180
180
  shortLabel: 'Routines',
181
- description: 'Set the Agent automation posture: local routines run in the main conversation, while external schedules remain explicit.',
181
+ description: 'Set the Agent automation posture: local routines run in the main conversation, while connected schedules remain explicit.',
182
182
  summaryTitle: 'Routine and schedule posture',
183
183
  summaryLines: [
184
184
  'Local routines: reusable main-conversation workflows',
185
- 'External schedules: explicit promotion only',
185
+ 'Connected schedules: explicit promotion only',
186
186
  'Runs/cancels/retries: command-confirmed side effects',
187
187
  ],
188
188
  fields: [
@@ -204,7 +204,7 @@ export function buildAutomationStep(): OnboardingWizardStepDefinition {
204
204
  kind: 'status',
205
205
  id: 'agent-automation.schedule-promotion',
206
206
  label: 'Routine-to-schedule promotion',
207
- hint: 'Creating external schedules from routines requires a reviewed routine, a real timing expression, optional delivery target, and explicit confirmation.',
207
+ hint: 'Creating connected schedules from routines requires a reviewed routine, a real timing expression, optional delivery target, and explicit confirmation.',
208
208
  defaultValue: 'Explicit command',
209
209
  },
210
210
  {
@@ -223,7 +223,7 @@ export function buildVoiceMediaStep(): OnboardingWizardStepDefinition {
223
223
  id: 'agent-voice-media',
224
224
  title: 'Voice and media',
225
225
  shortLabel: 'Voice',
226
- description: 'Prepare voice, speech, image input, and media understanding as Agent operator tools rather than runtime lifecycle features.',
226
+ description: 'Prepare voice, speech, image input, and media understanding as optional Agent operator tools.',
227
227
  summaryTitle: 'Voice and media posture',
228
228
  summaryLines: [
229
229
  'Voice and speech: optional operator tools',
@@ -114,10 +114,10 @@ function buildReviewReadinessFields(controller: OnboardingWizardController): rea
114
114
  {
115
115
  kind: 'status',
116
116
  id: 'review.readiness.connection',
117
- label: 'Runtime connection snapshot',
117
+ label: 'Connected services snapshot',
118
118
  hint: collectionIssues > 0
119
119
  ? `${collectionIssues} setup snapshot issue(s) need attention before this Agent is day-one ready.`
120
- : 'The setup snapshot loaded cleanly from the external GoodVibes runtime.',
120
+ : 'The setup snapshot loaded cleanly from connected GoodVibes services.',
121
121
  defaultValue: collectionIssues > 0 ? 'Needs attention' : 'Ready',
122
122
  spacerBeforeRows: 1,
123
123
  },
@@ -160,7 +160,7 @@ function buildReviewReadinessFields(controller: OnboardingWizardController): rea
160
160
  kind: 'status',
161
161
  id: 'review.readiness.automation',
162
162
  label: 'Routines and schedules',
163
- hint: automation?.detail ?? 'Local routines run in the main conversation; external schedules require explicit promotion and confirmation.',
163
+ hint: automation?.detail ?? 'Local routines run in the main conversation; connected schedules require explicit promotion and confirmation.',
164
164
  defaultValue: automation?.selected ? 'Review configured' : 'Local first',
165
165
  },
166
166
  {
@@ -211,7 +211,7 @@ export function buildAgentSetupStep(controller: OnboardingWizardController): Onb
211
211
  summaryLines: [
212
212
  'Agent owns the operator TUI and local behavior registry.',
213
213
  'Optional starter profile: create an isolated Agent home from setup.',
214
- 'GoodVibes runtime lifecycle is external to this product.',
214
+ 'Setup here changes only Agent-owned settings and local state.',
215
215
  `Secret policy: ${controller.getStringFieldValue('agent-setup.secret-policy', secretPolicy)}`,
216
216
  collectionIssues > 0 ? `${collectionIssues} setup snapshot issue(s)` : 'Setup snapshot collected cleanly',
217
217
  ],
@@ -226,11 +226,11 @@ export function buildAgentSetupStep(controller: OnboardingWizardController): Onb
226
226
  {
227
227
  kind: 'status',
228
228
  id: 'agent-setup.connection',
229
- label: 'GoodVibes runtime connection',
229
+ label: 'Connected GoodVibes services',
230
230
  hint: collectionIssues > 0
231
231
  ? `${collectionIssues} setup snapshot issue(s) were reported. Status and doctor commands show connection details.`
232
- : 'Agent connects to an already-running GoodVibes runtime for companion chat, work plans, approvals, automation, and Agent Knowledge.',
233
- defaultValue: collectionIssues > 0 ? `${collectionIssues} issue(s)` : 'External',
232
+ : 'Agent uses connected GoodVibes services for companion chat, work plans, approvals, automation, and Agent Knowledge.',
233
+ defaultValue: collectionIssues > 0 ? `${collectionIssues} issue(s)` : 'Connected',
234
234
  },
235
235
  {
236
236
  kind: 'radio',
@@ -514,7 +514,7 @@ export function buildReviewStep(controller: OnboardingWizardController): Onboard
514
514
  id: 'review.apply',
515
515
  action: 'apply',
516
516
  label: 'Apply Agent settings and verify',
517
- hint: 'Persist the Agent-owned settings and verify that no runtime lifecycle, non-Agent entrypoint, default wiki, or non-Agent knowledge setup was requested.',
517
+ hint: 'Persist Agent-owned settings and verify that setup did not request non-Agent entrypoints, default wiki access, or non-Agent knowledge setup.',
518
518
  defaultValue: 'Ready',
519
519
  },
520
520
  ],
@@ -1,4 +1,4 @@
1
- export const AGENT_EXTERNAL_DAEMON_SETTING_LOCK_REASON = 'GoodVibes Agent connects to an external GoodVibes runtime. Change runtime lifecycle and bind posture from the owning host; Agent settings are read-only for those controls.';
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.';
2
2
 
3
3
  const AGENT_HIDDEN_SETTING_PREFIXES = [
4
4
  ['cloud', 'flare.'].join(''),
@@ -0,0 +1,60 @@
1
+ export interface ParsedSlashCommand {
2
+ readonly name: string;
3
+ readonly args: readonly string[];
4
+ }
5
+
6
+ export function parseSlashCommand(command: string): ParsedSlashCommand {
7
+ const tokens = tokenizeSlashCommand(command.trim().replace(/^\//, ''));
8
+ return {
9
+ name: tokens[0] ?? '',
10
+ args: tokens.slice(1),
11
+ };
12
+ }
13
+
14
+ export function tokenizeSlashCommand(command: string): readonly string[] {
15
+ const tokens: string[] = [];
16
+ let current = '';
17
+ let quote: '"' | "'" | null = null;
18
+ let escaping = false;
19
+
20
+ for (const char of command) {
21
+ if (escaping) {
22
+ current += char;
23
+ escaping = false;
24
+ continue;
25
+ }
26
+ if (char === '\\') {
27
+ escaping = true;
28
+ continue;
29
+ }
30
+ if (quote) {
31
+ if (char === quote) {
32
+ quote = null;
33
+ continue;
34
+ }
35
+ current += char;
36
+ continue;
37
+ }
38
+ if (char === '"' || char === "'") {
39
+ quote = char;
40
+ continue;
41
+ }
42
+ if (/\s/.test(char)) {
43
+ if (current.length > 0) {
44
+ tokens.push(current);
45
+ current = '';
46
+ }
47
+ continue;
48
+ }
49
+ current += char;
50
+ }
51
+
52
+ if (escaping) current += '\\';
53
+ if (current.length > 0) tokens.push(current);
54
+ return tokens;
55
+ }
56
+
57
+ export function quoteSlashCommandArg(value: string): string {
58
+ if (/^[A-Za-z0-9._/:=@,+-]+$/.test(value)) return value;
59
+ return `"${value.replace(/\\/g, '\\\\').replace(/"/g, '\\"')}"`;
60
+ }
@@ -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 the external runtime; local Agent schedule mutation is blocked',
83
+ description: 'Read-only schedule posture from connected GoodVibes services; 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 the external runtime',
48
+ description: 'Read-only automation jobs, runs, deliveries, and failure posture from connected GoodVibes services',
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 the external runtime',
84
+ description: 'Queued, running, blocked, failed, and completed task summaries from connected GoodVibes services',
85
85
  factory: () => new TasksPanel(ui.readModels.tasks),
86
86
  });
87
87
 
@@ -217,7 +217,7 @@ export async function buildProviderAccountSnapshot(
217
217
  }
218
218
  if (hasServiceOAuth && !serviceOauth?.usable) {
219
219
  issues.push('Service OAuth is configured but missing a usable credential.');
220
- recommendedActions.push(`Repair service OAuth credentials for ${providerId} in /settings or the external runtime host.`);
220
+ recommendedActions.push(`Repair service OAuth credentials for ${providerId} in /settings or the owning GoodVibes host.`);
221
221
  }
222
222
 
223
223
  return {
@@ -46,13 +46,13 @@ export function buildProviderHealthDomainSummaries(
46
46
  name: 'auth',
47
47
  level: auth.bootstrapCredentialPresent ? 'warn' : 'info',
48
48
  summary: auth.bootstrapCredentialPresent
49
- ? 'external runtime bootstrap credential visible in local compatibility state'
50
- : 'runtime auth administration belongs to the external runtime owner',
49
+ ? 'connected-service bootstrap credential visible in local compatibility state'
50
+ : 'connected-service auth administration belongs outside Agent',
51
51
  next: '/auth review',
52
52
  details: [
53
- 'GoodVibes Agent does not create, delete, rotate, revoke, or clear runtime auth users or sessions.',
53
+ 'GoodVibes Agent does not create, delete, rotate, revoke, or clear connected-service auth users or sessions.',
54
54
  `${auth.userCount} compatibility user record(s) and ${auth.sessionCount} session record(s) are visible for diagnostics only.`,
55
- auth.bootstrapCredentialPresent ? 'Runtime bootstrap cleanup must be done from the runtime-owning TUI or host tooling.' : '',
55
+ auth.bootstrapCredentialPresent ? 'Bootstrap cleanup must be done in the owning GoodVibes host.' : '',
56
56
  ].filter(Boolean),
57
57
  nextSteps: auth.bootstrapCredentialPresent
58
58
  ? ['/auth review', '/provider', '/subscription providers']
@@ -64,10 +64,10 @@ export function buildProviderHealthDomainSummaries(
64
64
  name: 'settings',
65
65
  level: !settings.available ? 'info' : settingIssueCount > 0 ? 'warn' : 'good',
66
66
  summary: !settings.available
67
- ? 'settings runtime API unavailable'
67
+ ? 'settings API unavailable'
68
68
  : settingIssueCount > 0
69
69
  ? `${settings.conflictCount} conflicts / ${settings.recentFailureCount} failures${settings.hasStagedManagedBundle ? ' / staged bundle' : ''}`
70
- : 'settings runtime API clean',
70
+ : 'settings API clean',
71
71
  next: settingIssueCount > 0 ? '/settings' : '/config <key>',
72
72
  details: [
73
73
  settings.conflictCount > 0 ? `${settings.conflictCount} unresolved import conflict(s)` : '',
@@ -80,7 +80,7 @@ export class SubscriptionPanel extends ScrollableListPanel<SubscriptionRow> {
80
80
  return [
81
81
  { command: '/subscription login openai start --yes', summary: 'start the first-class OpenAI subscription flow' },
82
82
  { command: '/login provider <name> start --yes', summary: 'use the front-door auth flow for supported providers' },
83
- { command: '/auth review', summary: 'inspect runtime auth posture without exposing token values' },
83
+ { command: '/auth review', summary: 'inspect connected-service auth posture without exposing token values' },
84
84
  ];
85
85
  }
86
86
 
@@ -183,9 +183,9 @@ export class TasksPanel extends ScrollableListPanel<RuntimeTask> {
183
183
  sections: [{
184
184
  lines: buildEmptyState(
185
185
  width,
186
- ' Runtime store not wired into this panel yet.',
187
- 'Use the Tasks panel with a live runtime store to review active execution, cancellations, retries, and completion results.',
188
- [{ command: '/tasks', summary: 'inspect runtime tasks without starting background work' }],
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' }],
189
189
  C,
190
190
  ),
191
191
  }],
@@ -196,8 +196,8 @@ function snapshotLines(workspace: AgentWorkspace, category: AgentWorkspaceCatego
196
196
  );
197
197
  } else if (category.id === 'setup') {
198
198
  base.push(
199
- { text: `GoodVibes runtime: ${snapshot.runtimeBaseUrl}`, fg: PALETTE.info },
200
- { text: `Runtime owner: ${snapshot.runtimeOwnership}; Agent connects but never starts or restarts it`, fg: PALETTE.good },
199
+ { text: `Connection: ${snapshot.runtimeBaseUrl}`, fg: PALETTE.info },
200
+ { text: 'Agent role: interactive operator TUI; setup changes here are Agent-local.', fg: PALETTE.good },
201
201
  ...setupChecklistLines(snapshot),
202
202
  { text: '' },
203
203
  { text: `Workspace: ${snapshot.workingDirectory}`, fg: PALETTE.muted },
@@ -218,13 +218,13 @@ function snapshotLines(workspace: AgentWorkspace, category: AgentWorkspaceCatego
218
218
  ...snapshot.channels.filter((channel) => !channel.enabled),
219
219
  ].slice(0, 6);
220
220
  base.push(
221
- { text: `GoodVibes runtime: ${snapshot.runtimeBaseUrl}`, fg: PALETTE.info },
221
+ { text: `GoodVibes API: ${snapshot.runtimeBaseUrl}`, fg: PALETTE.info },
222
222
  { text: `Readiness: ${readyCount}/${snapshot.channels.length} ready; ${enabledCount} enabled; ${configuredDefaults} default target(s) configured.`, fg: PALETTE.info },
223
223
  { text: `Ready channels: ${readyChannels.join(', ') || 'none'}.`, fg: readyChannels.length > 0 ? PALETTE.good : PALETTE.warn },
224
224
  { text: `Needs default target: ${needsTarget.map((channel) => `${channel.label} -> ${channel.defaultTargetKeys.join('|')}`).join(', ') || 'none'}.`, fg: needsTarget.length > 0 ? PALETTE.warn : PALETTE.muted },
225
225
  { text: `Needs config: ${needsConfig.map((channel) => `${channel.label} -> ${channel.missingRequiredKeys.join('|')}`).join(', ') || 'none'}.`, fg: needsConfig.length > 0 ? PALETTE.warn : PALETTE.muted },
226
226
  { text: `Disabled channels: ${disabledPreview || 'none'}${disabledSuffix}.`, fg: PALETTE.dim },
227
- { text: 'Safety: no secret values; sends and public exposure require explicit user action and runtime policy.', fg: PALETTE.warn },
227
+ { text: 'Safety: no secret values; sends and public exposure require explicit user action and Agent policy.', fg: PALETTE.warn },
228
228
  );
229
229
  for (const channel of orderedChannels) {
230
230
  const ready = channel.ready ? 'ready' : `${channel.missingConfigCount} missing`;
@@ -297,7 +297,7 @@ function snapshotLines(workspace: AgentWorkspace, category: AgentWorkspaceCatego
297
297
  { text: '' },
298
298
  { text: 'Named Agent profiles isolate local config, sessions, memory, personas, skills, routines, setup, and bundles.', fg: PALETTE.good },
299
299
  { text: 'Starter authoring: browse, export, edit, import, and create Agent profiles from inside this workspace.', fg: PALETTE.info },
300
- { text: 'The external GoodVibes runtime remains shared unless the owning host is configured separately.', fg: PALETTE.warn },
300
+ { text: 'Connected GoodVibes services stay shared unless the owning host is configured separately.', fg: PALETTE.warn },
301
301
  { text: 'Portable bundles require explicit export/import commands with real paths and --yes.', fg: PALETTE.muted },
302
302
  );
303
303
  } else if (category.id === 'memory') {
@@ -334,7 +334,7 @@ function snapshotLines(workspace: AgentWorkspace, category: AgentWorkspaceCatego
334
334
  base.push(
335
335
  { text: `Routines: ${snapshot.localRoutineCount}; enabled: ${snapshot.enabledRoutineCount}`, fg: PALETTE.info },
336
336
  { text: 'Routines are repeatable main-conversation workflows. Starting one does not create hidden jobs.', fg: PALETTE.good },
337
- { text: 'Scheduling a reviewed routine is explicit and writes to the external GoodVibes runtime only with --yes.', fg: PALETTE.warn },
337
+ { text: 'Scheduling a reviewed routine is explicit and requires a confirmed schedule command.', fg: PALETTE.warn },
338
338
  { text: '' },
339
339
  ...localLibraryLines('Routine Library', snapshot.localRoutines, 'No local routines yet. Create one here with Create routine.', workspace.selectedLocalLibraryItem('routine')?.id ?? null),
340
340
  );
@@ -346,7 +346,8 @@ function snapshotLines(workspace: AgentWorkspace, category: AgentWorkspaceCatego
346
346
  } else if (category.id === 'automation') {
347
347
  base.push(
348
348
  { text: 'Automation and schedules default to read-only observability.', fg: PALETTE.info },
349
- { text: 'Run/pause/resume/cancel/retry require exact explicit commands and confirmation.', fg: PALETTE.warn },
349
+ { text: 'Confirmed reminders and routine promotion use connected schedules only.', fg: PALETTE.info },
350
+ { text: 'Local scheduler mutation/run controls remain blocked.', fg: PALETTE.warn },
350
351
  );
351
352
  } else if (category.id === 'delegate') {
352
353
  base.push(
@@ -430,34 +431,46 @@ function buildEditorRows(editor: AgentWorkspaceLocalEditor, width: number, heigh
430
431
  { text: editor.message, fg: PALETTE.info },
431
432
  { text: '' },
432
433
  ];
433
- for (let index = 0; index < editor.fields.length; index += 1) {
434
- const field = editor.fields[index]!;
435
- const selected = index === editor.selectedFieldIndex;
436
- const marker = selected ? GLYPHS.navigation.selected : ' ';
437
- const required = field.required ? ' *' : '';
438
- const value = field.value.length > 0 ? field.value : '(empty)';
439
- const color = selected ? PALETTE.text : field.value.length > 0 ? PALETTE.info : PALETTE.muted;
440
- rows.push({
441
- text: `${marker} ${field.label}${required}`,
442
- selected,
443
- fg: color,
444
- bold: selected,
445
- });
446
- const valueLines = value.split('\n');
447
- for (const valueLine of valueLines.slice(0, 4)) {
448
- for (const wrapped of wrapText(` ${valueLine}`, Math.max(1, width - 2))) {
449
- rows.push({ text: wrapped, fg: field.value.length > 0 ? PALETTE.text : PALETTE.dim, dim: field.value.length === 0 });
450
- }
451
- }
452
- if (valueLines.length > 4) rows.push({ text: ` ${valueLines.length - 4} more line(s)`, fg: PALETTE.dim, dim: true });
453
- rows.push({ text: ` ${field.hint}`, fg: PALETTE.dim, dim: true });
434
+ const footerRows: WorkspaceRow[] = [
435
+ { text: '' },
436
+ { text: 'Enter next/save · Up/Down field · Backspace edit · Ctrl-J newline · Esc cancel', fg: PALETTE.muted },
437
+ ];
438
+ const visibleFields = Math.max(1, Math.floor(Math.max(1, height - rows.length - footerRows.length) / 3));
439
+ const window = stableWindow(editor.fields.length, editor.selectedFieldIndex, visibleFields);
440
+ if (window.start > 0) rows.push({ text: `${GLYPHS.navigation.moreAbove} ${window.start} more field(s) above`, kind: 'more', fg: PALETTE.dim, dim: true });
441
+ for (let index = window.start; index < window.end; index += 1) {
442
+ rows.push(...buildEditorFieldRows(editor, index, width));
454
443
  }
455
- rows.push({ text: '' });
456
- rows.push({ text: 'Enter next/save · Up/Down field · Backspace edit · Ctrl-J newline · Esc cancel', fg: PALETTE.muted });
444
+ if (window.end < editor.fields.length) rows.push({ text: `${GLYPHS.navigation.moreBelow} ${editor.fields.length - window.end} more field(s) below`, kind: 'more', fg: PALETTE.dim, dim: true });
445
+ rows.push(...footerRows);
457
446
  while (rows.length < height) rows.push({ text: '', kind: 'empty' });
458
447
  return rows.slice(0, height);
459
448
  }
460
449
 
450
+ function buildEditorFieldRows(editor: AgentWorkspaceLocalEditor, index: number, width: number): WorkspaceRow[] {
451
+ const field = editor.fields[index]!;
452
+ const selected = index === editor.selectedFieldIndex;
453
+ const marker = selected ? GLYPHS.navigation.selected : ' ';
454
+ const required = field.required ? ' *' : '';
455
+ const value = field.value.length > 0 ? field.value : '(empty)';
456
+ const color = selected ? PALETTE.text : field.value.length > 0 ? PALETTE.info : PALETTE.muted;
457
+ const rows: WorkspaceRow[] = [{
458
+ text: `${marker} ${field.label}${required}`,
459
+ selected,
460
+ fg: color,
461
+ bold: selected,
462
+ }];
463
+ const valueLines = value.split('\n');
464
+ for (const valueLine of valueLines.slice(0, 4)) {
465
+ for (const wrapped of wrapText(` ${valueLine}`, Math.max(1, width - 2))) {
466
+ rows.push({ text: wrapped, fg: field.value.length > 0 ? PALETTE.text : PALETTE.dim, dim: field.value.length === 0 });
467
+ }
468
+ }
469
+ if (valueLines.length > 4) rows.push({ text: ` ${valueLines.length - 4} more line(s)`, fg: PALETTE.dim, dim: true });
470
+ rows.push({ text: ` ${field.hint}`, fg: PALETTE.dim, dim: true });
471
+ return rows;
472
+ }
473
+
461
474
  function buildActionRows(workspace: AgentWorkspace, width: number, height: number): WorkspaceRow[] {
462
475
  if (workspace.localEditor) return buildEditorRows(workspace.localEditor, width, height);
463
476
  const rows: WorkspaceRow[] = [];
@@ -78,7 +78,7 @@ export function renderHelpOverlay(
78
78
  ['routines', '', 'Manage reusable main-conversation routines'],
79
79
  ['workplan', '', 'Inspect shared work-plan state'],
80
80
  ['approval', '', 'Review and explicitly act on approvals'],
81
- ['schedule', '', 'Inspect schedules and routine promotion receipts'],
81
+ ['schedule', 'remind', 'Create confirmed reminders or inspect schedules'],
82
82
  ['delegate', '', 'Explicitly hand build/fix/review work to GoodVibes TUI'],
83
83
  ['mcp', '', 'Inspect MCP servers and tool readiness'],
84
84
  ['provider', '', 'Choose provider or model family'],