@pellux/goodvibes-agent 0.1.46 → 0.1.48

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.
@@ -5,6 +5,16 @@ import { AgentPersonaRegistry } from '../agent/persona-registry.ts';
5
5
  import { AgentRoutineRegistry } from '../agent/routine-registry.ts';
6
6
  import { AgentSkillRegistry } from '../agent/skill-registry.ts';
7
7
  import { getAgentRuntimeProfilesRoot, listAgentRuntimeProfiles, listAgentRuntimeProfileTemplates } from '../agent/runtime-profile.ts';
8
+ import {
9
+ buildAgentWorkspaceChannels,
10
+ type AgentWorkspaceChannelStatus,
11
+ } from './agent-workspace-channels.ts';
12
+ import {
13
+ buildAgentWorkspaceSetupChecklist,
14
+ type AgentWorkspaceSetupChecklistItem,
15
+ } from './agent-workspace-setup.ts';
16
+
17
+ export type { AgentWorkspaceChannelRisk, AgentWorkspaceChannelStatus } from './agent-workspace-channels.ts';
8
18
 
9
19
  export const AGENT_WORKSPACE_MODAL_NAME = 'agentWorkspace';
10
20
 
@@ -32,20 +42,6 @@ export interface AgentWorkspaceCategory {
32
42
 
33
43
  export type AgentWorkspaceCommandDispatcher = (command: string) => void;
34
44
 
35
- export type AgentWorkspaceChannelRisk = 'dm' | 'group' | 'public' | 'webhook' | 'bridge';
36
-
37
- export interface AgentWorkspaceChannelStatus {
38
- readonly id: string;
39
- readonly label: string;
40
- readonly enabled: boolean;
41
- readonly ready: boolean;
42
- readonly missingConfigCount: number;
43
- readonly defaultTarget: 'configured' | 'missing' | 'not-required';
44
- readonly delivery: 'disabled' | 'blocked' | 'explicit-target' | 'default-ready';
45
- readonly risk: AgentWorkspaceChannelRisk;
46
- readonly riskLabel: string;
47
- }
48
-
49
45
  export type AgentWorkspaceActionResultKind = 'guidance' | 'blocked' | 'dispatched' | 'refreshed' | 'error';
50
46
 
51
47
  export interface AgentWorkspaceActionResult {
@@ -100,139 +96,10 @@ export interface AgentWorkspaceRuntimeSnapshot {
100
96
  readonly runtimeStarterTemplateCount: number;
101
97
  readonly localStarterTemplateCount: number;
102
98
  readonly configProfileCount: number;
99
+ readonly setupChecklist: readonly AgentWorkspaceSetupChecklistItem[];
103
100
  readonly warnings: readonly string[];
104
101
  }
105
102
 
106
- interface AgentWorkspaceChannelSpec {
107
- readonly id: string;
108
- readonly label: string;
109
- readonly enabledKey: string;
110
- readonly requiredKeys: readonly string[];
111
- readonly defaultTargetKeys: readonly string[];
112
- readonly risk: AgentWorkspaceChannelRisk;
113
- readonly riskLabel: string;
114
- }
115
-
116
- const AGENT_WORKSPACE_CHANNEL_SPECS: readonly AgentWorkspaceChannelSpec[] = [
117
- {
118
- id: 'slack',
119
- label: 'Slack',
120
- enabledKey: 'surfaces.slack.enabled',
121
- requiredKeys: ['surfaces.slack.botToken', 'surfaces.slack.signingSecret'],
122
- defaultTargetKeys: ['surfaces.slack.defaultChannel'],
123
- risk: 'group',
124
- riskLabel: 'workspace/group channel',
125
- },
126
- {
127
- id: 'discord',
128
- label: 'Discord',
129
- enabledKey: 'surfaces.discord.enabled',
130
- requiredKeys: ['surfaces.discord.botToken', 'surfaces.discord.publicKey', 'surfaces.discord.applicationId'],
131
- defaultTargetKeys: ['surfaces.discord.defaultChannelId'],
132
- risk: 'group',
133
- riskLabel: 'server/channel delivery',
134
- },
135
- {
136
- id: 'telegram',
137
- label: 'Telegram',
138
- enabledKey: 'surfaces.telegram.enabled',
139
- requiredKeys: ['surfaces.telegram.botToken'],
140
- defaultTargetKeys: ['surfaces.telegram.defaultChatId'],
141
- risk: 'dm',
142
- riskLabel: 'bot DM/group delivery',
143
- },
144
- {
145
- id: 'ntfy',
146
- label: 'ntfy',
147
- enabledKey: 'surfaces.ntfy.enabled',
148
- requiredKeys: ['surfaces.ntfy.baseUrl', 'surfaces.ntfy.chatTopic', 'surfaces.ntfy.agentTopic'],
149
- defaultTargetKeys: ['surfaces.ntfy.topic'],
150
- risk: 'public',
151
- riskLabel: 'topic-based public/private feed',
152
- },
153
- {
154
- id: 'googleChat',
155
- label: 'Google Chat',
156
- enabledKey: 'surfaces.googleChat.enabled',
157
- requiredKeys: ['surfaces.googleChat.webhookUrl', 'surfaces.googleChat.verificationToken'],
158
- defaultTargetKeys: ['surfaces.googleChat.spaceId'],
159
- risk: 'group',
160
- riskLabel: 'space delivery',
161
- },
162
- {
163
- id: 'signal',
164
- label: 'Signal',
165
- enabledKey: 'surfaces.signal.enabled',
166
- requiredKeys: ['surfaces.signal.bridgeUrl', 'surfaces.signal.account'],
167
- defaultTargetKeys: ['surfaces.signal.defaultRecipient'],
168
- risk: 'bridge',
169
- riskLabel: 'private bridge delivery',
170
- },
171
- {
172
- id: 'whatsapp',
173
- label: 'WhatsApp',
174
- enabledKey: 'surfaces.whatsapp.enabled',
175
- requiredKeys: ['surfaces.whatsapp.accessToken', 'surfaces.whatsapp.verifyToken', 'surfaces.whatsapp.phoneNumberId'],
176
- defaultTargetKeys: ['surfaces.whatsapp.defaultRecipient'],
177
- risk: 'dm',
178
- riskLabel: 'phone-number delivery',
179
- },
180
- {
181
- id: 'imessage',
182
- label: 'iMessage',
183
- enabledKey: 'surfaces.imessage.enabled',
184
- requiredKeys: ['surfaces.imessage.bridgeUrl', 'surfaces.imessage.account'],
185
- defaultTargetKeys: ['surfaces.imessage.defaultChatId'],
186
- risk: 'bridge',
187
- riskLabel: 'Apple bridge delivery',
188
- },
189
- {
190
- id: 'bluebubbles',
191
- label: 'BlueBubbles',
192
- enabledKey: 'surfaces.bluebubbles.enabled',
193
- requiredKeys: ['surfaces.bluebubbles.serverUrl', 'surfaces.bluebubbles.password'],
194
- defaultTargetKeys: ['surfaces.bluebubbles.defaultChatGuid'],
195
- risk: 'bridge',
196
- riskLabel: 'iMessage bridge delivery',
197
- },
198
- {
199
- id: 'msteams',
200
- label: 'Microsoft Teams',
201
- enabledKey: 'surfaces.msteams.enabled',
202
- requiredKeys: ['surfaces.msteams.appId', 'surfaces.msteams.appPassword'],
203
- defaultTargetKeys: ['surfaces.msteams.defaultConversationId', 'surfaces.msteams.defaultChannelId'],
204
- risk: 'group',
205
- riskLabel: 'tenant/channel delivery',
206
- },
207
- {
208
- id: 'mattermost',
209
- label: 'Mattermost',
210
- enabledKey: 'surfaces.mattermost.enabled',
211
- requiredKeys: ['surfaces.mattermost.baseUrl', 'surfaces.mattermost.botToken'],
212
- defaultTargetKeys: ['surfaces.mattermost.defaultChannelId'],
213
- risk: 'group',
214
- riskLabel: 'team/channel delivery',
215
- },
216
- {
217
- id: 'matrix',
218
- label: 'Matrix',
219
- enabledKey: 'surfaces.matrix.enabled',
220
- requiredKeys: ['surfaces.matrix.homeserverUrl', 'surfaces.matrix.accessToken'],
221
- defaultTargetKeys: ['surfaces.matrix.defaultRoomId'],
222
- risk: 'group',
223
- riskLabel: 'room delivery',
224
- },
225
- {
226
- id: 'webhook',
227
- label: 'Webhook',
228
- enabledKey: 'surfaces.webhook.enabled',
229
- requiredKeys: ['surfaces.webhook.defaultTarget'],
230
- defaultTargetKeys: ['surfaces.webhook.defaultTarget'],
231
- risk: 'webhook',
232
- riskLabel: 'external HTTP delivery',
233
- },
234
- ];
235
-
236
103
  function readConfigString(context: CommandContext, key: string, fallback: string): string {
237
104
  try {
238
105
  const configManager = context.platform?.configManager as unknown as AgentWorkspaceConfigReader | undefined;
@@ -270,48 +137,6 @@ function readConfigBoolean(context: CommandContext, key: string, fallback: boole
270
137
  }
271
138
  }
272
139
 
273
- function hasConfigValue(context: CommandContext, key: string): boolean {
274
- try {
275
- const configManager = context.platform?.configManager as unknown as AgentWorkspaceConfigReader | undefined;
276
- const value = configManager?.get(key);
277
- if (typeof value === 'string') return value.trim().length > 0;
278
- if (typeof value === 'number') return Number.isFinite(value);
279
- if (typeof value === 'boolean') return value;
280
- return value !== null && value !== undefined;
281
- } catch {
282
- return false;
283
- }
284
- }
285
-
286
- function buildChannelStatus(context: CommandContext, spec: AgentWorkspaceChannelSpec): AgentWorkspaceChannelStatus {
287
- const enabled = readConfigBoolean(context, spec.enabledKey, false);
288
- const missingConfigCount = spec.requiredKeys.filter((key) => !hasConfigValue(context, key)).length;
289
- const defaultTarget = spec.defaultTargetKeys.length === 0
290
- ? 'not-required'
291
- : spec.defaultTargetKeys.some((key) => hasConfigValue(context, key))
292
- ? 'configured'
293
- : 'missing';
294
- const ready = enabled && missingConfigCount === 0;
295
- const delivery = !enabled
296
- ? 'disabled'
297
- : !ready
298
- ? 'blocked'
299
- : defaultTarget === 'configured'
300
- ? 'default-ready'
301
- : 'explicit-target';
302
- return {
303
- id: spec.id,
304
- label: spec.label,
305
- enabled,
306
- ready,
307
- missingConfigCount,
308
- defaultTarget,
309
- delivery,
310
- risk: spec.risk,
311
- riskLabel: spec.riskLabel,
312
- };
313
- }
314
-
315
140
  function inferActiveRuntimeProfile(homeDirectory: string): string {
316
141
  const marker = `${sep}.goodvibes${sep}agent${sep}profile-homes${sep}`;
317
142
  return homeDirectory.includes(marker) ? basename(homeDirectory) : '(default home)';
@@ -408,6 +233,24 @@ export function buildAgentWorkspaceRuntimeSnapshot(context: CommandContext): Age
408
233
  const ttsVoice = readConfigString(context, 'tts.voice', '(voice default)');
409
234
  const ttsLlmProvider = readConfigString(context, 'tts.llmProvider', '');
410
235
  const ttsLlmModel = readConfigString(context, 'tts.llmModel', '');
236
+ const daemonBaseUrl = `http://${host}:${port}`;
237
+ const channels = buildAgentWorkspaceChannels(context);
238
+ const setupChecklist = buildAgentWorkspaceSetupChecklist({
239
+ provider,
240
+ model,
241
+ daemonBaseUrl,
242
+ sessionMemoryCount,
243
+ routineCount: routineSnapshot.count,
244
+ enabledRoutineCount: routineSnapshot.enabled,
245
+ skillCount: skillSnapshot.count,
246
+ enabledSkillCount: skillSnapshot.enabled,
247
+ activePersonaName: personaSnapshot.activeName,
248
+ readyChannelCount: channels.filter((channel) => channel.ready).length,
249
+ voiceProviderCount: voiceProviders.length,
250
+ mediaProviderCount: mediaProviders.length,
251
+ runtimeProfileCount: runtimeProfiles.length,
252
+ runtimeStarterTemplateCount: runtimeStarterTemplates.length,
253
+ });
411
254
 
412
255
  return {
413
256
  provider,
@@ -416,7 +259,7 @@ export function buildAgentWorkspaceRuntimeSnapshot(context: CommandContext): Age
416
259
  sessionId: context.session?.runtime?.sessionId ?? 'unknown',
417
260
  workingDirectory: context.workspace?.shellPaths?.workingDirectory ?? 'unavailable',
418
261
  homeDirectory: context.workspace?.shellPaths?.homeDirectory ?? 'unavailable',
419
- daemonBaseUrl: `http://${host}:${port}`,
262
+ daemonBaseUrl,
420
263
  daemonOwnership: 'external',
421
264
  sessionMemoryCount,
422
265
  localRoutineCount: routineSnapshot.count,
@@ -429,7 +272,7 @@ export function buildAgentWorkspaceRuntimeSnapshot(context: CommandContext): Age
429
272
  knowledgeIsolation: 'agent-only',
430
273
  executionPolicy: 'serial-proactive',
431
274
  wrfcPolicy: 'explicit-build-delegation-only',
432
- channels: AGENT_WORKSPACE_CHANNEL_SPECS.map((spec) => buildChannelStatus(context, spec)),
275
+ channels,
433
276
  voiceProviderCount: voiceProviders.length,
434
277
  voiceStreamingProviderCount: voiceProviders.filter((entry) => entry.capabilities.includes('tts-stream')).length,
435
278
  voiceSttProviderCount: voiceProviders.filter((entry) => entry.capabilities.includes('stt')).length,
@@ -449,6 +292,7 @@ export function buildAgentWorkspaceRuntimeSnapshot(context: CommandContext): Age
449
292
  runtimeStarterTemplateCount: runtimeStarterTemplates.length,
450
293
  localStarterTemplateCount: runtimeStarterTemplates.filter((template) => template.source === 'local').length,
451
294
  configProfileCount,
295
+ setupChecklist,
452
296
  warnings,
453
297
  };
454
298
  }
@@ -480,23 +324,6 @@ export const AGENT_WORKSPACE_CATEGORIES: readonly AgentWorkspaceCategory[] = [
480
324
  { id: 'auth', label: 'Auth review', detail: 'Review authentication posture without printing token values.', command: '/auth review', kind: 'command', safety: 'read-only' },
481
325
  ],
482
326
  },
483
- {
484
- id: 'capabilities',
485
- group: 'SETUP',
486
- label: 'Capabilities',
487
- summary: 'OpenClaw/Hermes benchmark and live daemon coverage.',
488
- detail: 'Use this area to measure both layers: what GoodVibes Agent makes usable, and what the externally owned GoodVibes daemon actually exposes through public routes. Agent Knowledge is checked only through /api/goodvibes-agent/knowledge/*.',
489
- actions: [
490
- { id: 'capabilities-benchmark', label: 'Benchmark report', detail: 'Show the OpenClaw/Hermes parity benchmark with Agent posture, setup commands, usage paths, and remaining product gaps.', command: '/capabilities', kind: 'command', safety: 'read-only' },
491
- { id: 'capabilities-daemon', label: 'Live daemon audit', detail: 'Inspect the public daemon method catalog plus isolated Agent Knowledge route coverage. Does not query default Knowledge/Wiki or HomeGraph.', command: '/capabilities daemon', kind: 'command', safety: 'read-only' },
492
- { id: 'capabilities-daemon-gaps', label: 'Daemon gap plan', detail: 'Classify live daemon coverage into platform gaps, Agent route gaps, route-risk reviews, and Agent UX work without querying default Knowledge/Wiki or HomeGraph.', command: '/capabilities daemon gaps', kind: 'command', safety: 'read-only' },
493
- { id: 'capabilities-daemon-risk', label: 'Route risk review', detail: 'Inspect daemon read-only, mutating, dangerous, and authenticated route metadata for approval-center planning.', command: '/capabilities daemon risk', kind: 'command', safety: 'read-only' },
494
- { id: 'capabilities-daemon-inventory', label: 'Full method inventory', detail: 'List every public daemon method by category, HTTP posture, access, and dangerous flag without querying default Knowledge/Wiki or HomeGraph.', command: '/capabilities daemon inventory', kind: 'command', safety: 'read-only' },
495
- { id: 'capabilities-daemon-knowledge', label: 'Knowledge coverage', detail: 'Filter the live daemon audit to the isolated Agent Knowledge segment.', command: '/capabilities daemon knowledge', kind: 'command', safety: 'read-only' },
496
- { id: 'capabilities-daemon-channels', label: 'Channel coverage', detail: 'Filter the live daemon audit to channel and delivery gateway route coverage.', command: '/capabilities daemon channels', kind: 'command', safety: 'read-only' },
497
- { id: 'capabilities-daemon-automation', label: 'Automation coverage', detail: 'Filter the live daemon audit to automation, schedule, run, and capacity route coverage.', command: '/capabilities daemon automation', kind: 'command', safety: 'read-only' },
498
- ],
499
- },
500
327
  {
501
328
  id: 'channels',
502
329
  group: 'SETUP',
@@ -531,7 +358,7 @@ export const AGENT_WORKSPACE_CATEGORIES: readonly AgentWorkspaceCategory[] = [
531
358
  group: 'SETUP',
532
359
  label: 'Voice, Media & Nodes',
533
360
  summary: 'Voice, TTS, image input, browser surface, and node/remote posture.',
534
- detail: 'Hermes and OpenClaw expose voice, media, browser, and node surfaces as first-class operator capabilities. Agent uses the GoodVibes voice/media/provider/browser/remote bones while keeping daemon ownership external and side effects explicit.',
361
+ detail: 'Voice, media, browser, and node surfaces are first-class operator surfaces. Agent uses the GoodVibes voice/media/provider/browser/remote bones while keeping daemon ownership external and side effects explicit.',
535
362
  actions: [
536
363
  { id: 'tts-config', label: 'Configure live TTS', detail: 'Open the TUI-derived config workspace at the TTS settings group.', command: '/config tts', kind: 'command', safety: 'safe' },
537
364
  { id: 'tts-provider', label: 'Choose TTS provider', detail: 'Open provider/model routing for spoken responses through the settings flow.', command: '/config tts.provider', kind: 'command', safety: 'safe' },
@@ -547,7 +374,7 @@ export const AGENT_WORKSPACE_CATEGORIES: readonly AgentWorkspaceCategory[] = [
547
374
  group: 'SETUP',
548
375
  label: 'Profiles & Portability',
549
376
  summary: 'Isolated Agent homes, config profiles, and setup bundles.',
550
- detail: 'Hermes profiles isolate agent state. GoodVibes Agent exposes named runtime homes, config profile pickers, profile-sync bundles, setup transfer bundles, and support bundles while keeping the daemon external.',
377
+ detail: 'Profiles isolate agent state. GoodVibes Agent exposes named runtime homes, config profile pickers, profile-sync bundles, setup transfer bundles, and support bundles while keeping the daemon external.',
551
378
  actions: [
552
379
  { id: 'profiles-open', label: 'Open config profiles', detail: 'Open the TUI-derived config profile picker for display/provider/behavior profile files.', command: '/profiles', kind: 'command', safety: 'safe' },
553
380
  { id: 'runtime-profile-guide', label: 'Starter authoring guide', detail: 'Open the Agent-local starter authoring flow inside the TUI command surface.', command: '/agent-profile guide', kind: 'command', safety: 'safe' },
@@ -583,7 +410,6 @@ export const AGENT_WORKSPACE_CATEGORIES: readonly AgentWorkspaceCategory[] = [
583
410
  { id: 'workplan', label: 'Open work plan', detail: 'Open the workspace-scoped work plan panel.', command: '/workplan panel', kind: 'command', safety: 'read-only' },
584
411
  { id: 'workplan-list', label: 'List work plan', detail: 'Print a concise work plan summary.', command: '/workplan list', kind: 'command', safety: 'read-only' },
585
412
  { id: 'approvals', label: 'Review approvals', detail: 'Open/read approval posture. This workspace does not approve or deny requests.', command: '/approval open', kind: 'command', safety: 'read-only' },
586
- { id: 'approval-risk', label: 'Route risk review', detail: 'Inspect daemon route risk and dangerous method metadata without approving, denying, or mutating requests.', command: '/approval risk', kind: 'command', safety: 'read-only' },
587
413
  ],
588
414
  },
589
415
  {
@@ -4,13 +4,6 @@ import type { CommandRegistry } from '../command-registry.ts';
4
4
  import { requirePanelManager, requireShellPaths } from './runtime-services.ts';
5
5
  import { requireYesFlag, stripYesFlag } from './confirmation.ts';
6
6
  import { resolveAgentDaemonConnection } from '../../agent/routine-schedule-promotion.ts';
7
- import {
8
- buildDaemonCapabilityRouteRiskReport,
9
- fetchLiveDaemonCapabilityAudit,
10
- filterDaemonCapabilityRouteRiskAreas,
11
- renderDaemonCapabilityFailure,
12
- renderDaemonCapabilityRouteRisk,
13
- } from '../../operator/daemon-capability-audit.ts';
14
7
 
15
8
  interface VoiceBundle {
16
9
  readonly version: 1;
@@ -186,7 +179,7 @@ export function registerExperienceRuntimeCommands(registry: CommandRegistry): vo
186
179
  name: 'approval',
187
180
  aliases: ['approvals'],
188
181
  description: 'Review action-specific approval classes and the specialized security UX matrix',
189
- usage: '[matrix|risk|review <kind>]',
182
+ usage: '[matrix|review <kind>]',
190
183
  async handler(args, ctx) {
191
184
  const sub = (args[0] ?? 'matrix').toLowerCase();
192
185
  if (sub === 'open' || sub === 'panel') {
@@ -213,25 +206,9 @@ export function registerExperienceRuntimeCommands(registry: CommandRegistry): vo
213
206
  ctx.print([
214
207
  'Approval Matrix',
215
208
  ...matrix.map(([kind, summary]) => ` ${kind.padEnd(10)} ${summary}`),
216
- '',
217
- 'Live daemon route risk: /approval risk',
218
209
  ].join('\n'));
219
210
  return;
220
211
  }
221
- if (sub === 'risk' || sub === 'route-risk') {
222
- const shellPaths = requireShellPaths(ctx);
223
- const connection = resolveAgentDaemonConnection(ctx.platform.configManager, shellPaths.homeDirectory);
224
- const audit = await fetchLiveDaemonCapabilityAudit(connection);
225
- if (!audit.ok) {
226
- ctx.print(renderDaemonCapabilityFailure(audit));
227
- return;
228
- }
229
- const report = buildDaemonCapabilityRouteRiskReport(audit);
230
- const query = args.slice(1).join(' ').trim() || undefined;
231
- const areas = filterDaemonCapabilityRouteRiskAreas(report.areas, query);
232
- ctx.print(renderDaemonCapabilityRouteRisk(report, areas));
233
- return;
234
- }
235
212
  if (sub === 'review') {
236
213
  const kind = (args[1] ?? '').toLowerCase();
237
214
  const entry = matrix.find(([id]) => id === kind);
@@ -246,7 +223,7 @@ export function registerExperienceRuntimeCommands(registry: CommandRegistry): vo
246
223
  ].join('\n'));
247
224
  return;
248
225
  }
249
- ctx.print('Usage: /approval [open|matrix|risk|review <kind>]');
226
+ ctx.print('Usage: /approval [open|matrix|review <kind>]');
250
227
  },
251
228
  });
252
229
 
@@ -46,7 +46,7 @@ export function registerRemoteRuntimeCommands(registry: CommandRegistry): void {
46
46
  name: 'remote',
47
47
  aliases: [],
48
48
  description: 'Inspect, dispatch, and review self-hosted remote runners and artifacts',
49
- usage: '[list | show [agentId] | supervisor [runnerId] | capabilities [runnerId] | recover [runnerId] | setup [export <path> --yes] | env [export <path> --yes] | tunnel [review|export <path> --yes] | bootstrap [export <path> --yes|inspect <path>] | session <export|inspect|import> <path> [--yes] | pool <list|show|create|assign|unassign> ... | dispatch [template] <description> | dispatch-pool <pool> [template] <description> | contract [agentId] | cancel <agentId> | export <agentId> [path] --yes | artifact list | artifact show <id> | artifact export <id> [path] --yes | review <id> | rerun-local <id> | import <path> --yes]',
49
+ usage: '[list | show [agentId] | supervisor [runnerId] | support [runnerId] | recover [runnerId] | setup [export <path> --yes] | env [export <path> --yes] | tunnel [review|export <path> --yes] | bootstrap [export <path> --yes|inspect <path>] | session <export|inspect|import> <path> [--yes] | pool <list|show|create|assign|unassign> ... | dispatch [template] <description> | dispatch-pool <pool> [template] <description> | contract [agentId] | cancel <agentId> | export <agentId> [path] --yes | artifact list | artifact show <id> | artifact export <id> [path] --yes | review <id> | rerun-local <id> | import <path> --yes]',
50
50
  async handler(args, ctx) {
51
51
  if (args.length === 0) {
52
52
  if (ctx.openRemotePanel) {
@@ -131,7 +131,7 @@ export function registerRemoteRuntimeCommands(registry: CommandRegistry): void {
131
131
  ` messageCount: ${selected.messageCount}`,
132
132
  ` errorCount: ${selected.errorCount}`,
133
133
  ...(selected.lastError ? [` lastError: ${selected.lastError}`] : []),
134
- ' capabilities:',
134
+ ' runner support:',
135
135
  ...selected.capabilities.map((capability) => ` ${capability.id}: ${capability.supported ? 'yes' : 'no'} (${capability.detail})`),
136
136
  ' recovery:',
137
137
  ...selected.recovery.map((action) => ` ${action.command} — ${action.reason}`),
@@ -139,7 +139,7 @@ export function registerRemoteRuntimeCommands(registry: CommandRegistry): void {
139
139
  return;
140
140
  }
141
141
 
142
- if (subcommand === 'capabilities') {
142
+ if (subcommand === 'support') {
143
143
  const snapshot = peerSnapshot.supervisor;
144
144
  const runnerId = args[1];
145
145
  const selected = runnerId
@@ -150,14 +150,14 @@ export function registerRemoteRuntimeCommands(registry: CommandRegistry): void {
150
150
  return;
151
151
  }
152
152
  ctx.print([
153
- `Remote Capabilities ${selected.runnerId}`,
153
+ `Remote Support ${selected.runnerId}`,
154
154
  ` label: ${selected.label}`,
155
155
  ` transport: ${selected.transportState}`,
156
156
  ` executionProtocol: ${selected.negotiation.executionProtocol}`,
157
157
  ` reviewMode: ${selected.negotiation.reviewMode}`,
158
158
  ` communicationLane: ${selected.negotiation.communicationLane}`,
159
159
  ` trustClass: ${selected.negotiation.trustClass}`,
160
- ' capabilities:',
160
+ ' runner support:',
161
161
  ...selected.capabilities.map((capability) => (
162
162
  ` ${capability.id}: ${capability.supported ? 'supported' : 'missing'} — ${capability.detail}`
163
163
  )),
@@ -59,7 +59,6 @@ import { registerDelegationRuntimeCommands } from './commands/delegation-runtime
59
59
  import { registerPersonasRuntimeCommands } from './commands/personas-runtime.ts';
60
60
  import { registerAgentSkillsRuntimeCommands } from './commands/agent-skills-runtime.ts';
61
61
  import { registerRoutinesRuntimeCommands } from './commands/routines-runtime.ts';
62
- import { registerCapabilitiesRuntimeCommands } from './commands/capabilities-runtime.ts';
63
62
 
64
63
  /**
65
64
  * registerBuiltinCommands - Register all built-in slash commands into the registry.
@@ -69,7 +68,6 @@ export function registerBuiltinCommands(registry: CommandRegistry): void {
69
68
  registerShellCoreCommands(registry);
70
69
  registerAgentWorkspaceRuntimeCommands(registry);
71
70
  registerAgentRuntimeProfileRuntimeCommands(registry);
72
- registerCapabilitiesRuntimeCommands(registry);
73
71
  registerPersonasRuntimeCommands(registry);
74
72
  registerAgentSkillsRuntimeCommands(registry);
75
73
  registerRoutinesRuntimeCommands(registry);
@@ -114,7 +114,7 @@ export function buildCapabilitiesStep(controller: OnboardingWizardController): O
114
114
  kind: 'action',
115
115
  id: 'capabilities.select-all',
116
116
  action: 'select-all-capabilities',
117
- label: 'Review external-daemon capabilities',
117
+ label: 'Review external-daemon surfaces',
118
118
  hint: 'Review browser, LAN, webhooks/events, and external app surfaces without letting Agent own daemon lifecycle.',
119
119
  defaultValue: 'Action',
120
120
  },
@@ -123,17 +123,17 @@ export function buildCapabilitiesStep(controller: OnboardingWizardController): O
123
123
  id: 'capabilities.clear',
124
124
  action: 'clear-capabilities',
125
125
  label: 'Keep Agent local-only',
126
- hint: 'Clear external-daemon capabilities and keep Agent work in this terminal conversation.',
126
+ hint: 'Clear external-daemon surfaces and keep Agent work in this terminal conversation.',
127
127
  defaultValue: 'Action',
128
128
  },
129
129
  ];
130
130
 
131
131
  return {
132
132
  id: 'capabilities',
133
- title: 'Choose GoodVibes capabilities',
133
+ title: 'Choose GoodVibes surfaces',
134
134
  shortLabel: 'Capabilities',
135
- description: 'Choose what Agent should prepare locally. Daemon-backed capabilities are reviewed as external dependencies; Agent does not enable service mode or autostart.',
136
- summaryTitle: 'Selected capabilities',
135
+ description: 'Choose what Agent should prepare locally. Daemon-backed surfaces are reviewed as external dependencies; Agent does not enable service mode or autostart.',
136
+ summaryTitle: 'Selected surfaces',
137
137
  summaryLines: [
138
138
  `${selectedCount}/${capabilities.length} option(s) selected`,
139
139
  `Mode: ${controller.mode === 'edit' ? 'edit existing shell state' : controller.mode === 'reopen' ? 'reopen review flow' : 'new setup'}`,
@@ -327,7 +327,7 @@ export function buildExternalServicesStep(controller: OnboardingWizardController
327
327
  id: 'external-services.clear',
328
328
  action: 'clear-external-surfaces',
329
329
  label: 'Clear all external surfaces',
330
- hint: 'Hide all external surface setup screens. The HTTP listener can still be enabled separately by webhook/event capabilities.',
330
+ hint: 'Hide all external surface setup screens. The HTTP listener can still be enabled separately by webhook/event settings.',
331
331
  defaultValue: 'Action',
332
332
  },
333
333
  {
@@ -705,7 +705,7 @@ export function buildAccountsStep(controller: OnboardingWizardController): Onboa
705
705
  ? 'An existing local auth admin user was detected and will be kept.'
706
706
  : controller.hasLocalAuthUser()
707
707
  ? 'Existing local auth users were detected and will be kept.'
708
- : 'No server-backed capability is selected, so local auth is not required.',
708
+ : 'No server-backed surface is selected, so local auth is not required.',
709
709
  defaultValue: needsAuthBootstrap
710
710
  ? controller.hasBootstrapCredentialPresent() ? 'Bootstrap replacement required' : 'Local admin required'
711
711
  : controller.hasAdminAuthUser() ? 'Admin detected' : controller.hasLocalAuthUser() ? 'Local auth detected' : 'Not required',
@@ -104,7 +104,7 @@ export function buildProviderHealthDomainSummaries(
104
104
  .slice(0, 3)
105
105
  .map((entry) => `${entry.runnerId}: transport=${entry.transportState} heartbeat=${entry.heartbeat.status}${entry.lastError ? ` error=${entry.lastError}` : ''}`),
106
106
  nextSteps: remote.supervisor.degradedConnections > 0
107
- ? ['/remote supervisor', '/remote recover <runnerId>', '/remote capabilities']
107
+ ? ['/remote supervisor', '/remote recover <runnerId>', '/remote support']
108
108
  : ['/remote supervisor'],
109
109
  });
110
110
 
@@ -204,8 +204,8 @@ export class RemotePanel extends BasePanel {
204
204
  ]));
205
205
  }
206
206
  postureLines.push(
207
- buildGuidanceLine(width, '/remote recover', 'resume remote state with runner, capability, and disconnect recovery hints', C),
208
- buildGuidanceLine(width, '/remote capabilities', 'inspect transport support before routing remote work or reattaching a session', C),
207
+ buildGuidanceLine(width, '/remote recover', 'resume remote state with runner support and disconnect recovery hints', C),
208
+ buildGuidanceLine(width, '/remote support', 'inspect transport support before routing remote work or reattaching a session', C),
209
209
  );
210
210
 
211
211
  const footerLines = [
@@ -72,6 +72,33 @@ function actionCommand(action: AgentWorkspaceAction): string {
72
72
 
73
73
  type ContextLine = { readonly text: string; readonly fg?: string; readonly bold?: boolean; readonly dim?: boolean };
74
74
 
75
+ function setupStatusColor(status: AgentWorkspaceRuntimeSnapshot['setupChecklist'][number]['status']): string {
76
+ if (status === 'ready') return PALETTE.good;
77
+ if (status === 'recommended') return PALETTE.warn;
78
+ if (status === 'blocked') return PALETTE.bad;
79
+ return PALETTE.muted;
80
+ }
81
+
82
+ function setupChecklistLines(snapshot: AgentWorkspaceRuntimeSnapshot): ContextLine[] {
83
+ const readyCount = snapshot.setupChecklist.filter((item) => item.status === 'ready').length;
84
+ const recommendedCount = snapshot.setupChecklist.filter((item) => item.status === 'recommended').length;
85
+ const blockedCount = snapshot.setupChecklist.filter((item) => item.status === 'blocked').length;
86
+ const lines: ContextLine[] = [
87
+ { text: 'Setup Checklist', fg: PALETTE.title, bold: true },
88
+ { text: `${readyCount}/${snapshot.setupChecklist.length} ready; ${recommendedCount} recommended; ${blockedCount} blocked`, fg: blockedCount > 0 ? PALETTE.warn : PALETTE.info },
89
+ ];
90
+ for (const item of snapshot.setupChecklist) {
91
+ const command = item.command ? ` -> ${item.command}` : '';
92
+ lines.push({
93
+ text: `${item.status.toUpperCase()} ${item.label}${command}`,
94
+ fg: setupStatusColor(item.status),
95
+ bold: item.status === 'blocked',
96
+ });
97
+ lines.push({ text: ` ${item.detail}`, fg: PALETTE.muted });
98
+ }
99
+ return lines;
100
+ }
101
+
75
102
  function snapshotLines(category: AgentWorkspaceCategory, snapshot: AgentWorkspaceRuntimeSnapshot | null): ContextLine[] {
76
103
  if (!snapshot) return [{ text: 'Runtime context is not loaded yet.', fg: PALETTE.warn }];
77
104
  const base: ContextLine[] = [{ text: 'Live Agent Context', fg: PALETTE.title, bold: true }];
@@ -87,14 +114,8 @@ function snapshotLines(category: AgentWorkspaceCategory, snapshot: AgentWorkspac
87
114
  { text: `Daemon ownership: ${snapshot.daemonOwnership}; Agent never starts or restarts it`, fg: PALETTE.good },
88
115
  { text: `Workspace: ${snapshot.workingDirectory}`, fg: PALETTE.muted },
89
116
  { text: `Home: ${snapshot.homeDirectory}`, fg: PALETTE.muted },
90
- );
91
- } else if (category.id === 'capabilities') {
92
- base.push(
93
- { text: `External daemon: ${snapshot.daemonBaseUrl}`, fg: PALETTE.info },
94
- { text: 'Live audit source: /api/control-plane/methods plus /api/goodvibes-agent/knowledge/status.', fg: PALETTE.info },
95
- { text: 'Isolation: no default Knowledge/Wiki, HomeGraph, or Home Assistant route is used for Agent Knowledge coverage.', fg: PALETTE.good },
96
- { text: 'Readiness meaning: daemon route coverage is platform capability; missing Agent UX remains a product gap to close here.', fg: PALETTE.muted },
97
- { text: 'Use filtered audits for knowledge, channels, automation, voice/media/nodes, providers, MCP/tools, approvals, or sessions.', fg: PALETTE.muted },
117
+ { text: '' },
118
+ ...setupChecklistLines(snapshot),
98
119
  );
99
120
  } else if (category.id === 'channels') {
100
121
  const enabledCount = snapshot.channels.filter((channel) => channel.enabled).length;
@@ -275,10 +296,17 @@ function footerText(workspace: AgentWorkspace): string {
275
296
  }
276
297
 
277
298
  export function renderAgentWorkspace(workspace: AgentWorkspace, width: number, height: number): Line[] {
278
- const layoutOptions = { width, height, leftWidth: width < 90 ? undefined : 30, contextRatio: 0.62, minContextRows: 10 };
279
- const metrics = getFullscreenWorkspaceMetrics(layoutOptions);
280
299
  const category = workspace.selectedCategory;
281
300
  const action = workspace.selectedAction;
301
+ const setupCategory = category.id === 'setup';
302
+ const layoutOptions = {
303
+ width,
304
+ height,
305
+ leftWidth: width < 90 ? undefined : 30,
306
+ contextRatio: setupCategory ? 0.86 : 0.62,
307
+ minContextRows: setupCategory ? 18 : 10,
308
+ };
309
+ const metrics = getFullscreenWorkspaceMetrics(layoutOptions);
282
310
 
283
311
  return renderFullscreenWorkspace({
284
312
  width,
@@ -3,13 +3,13 @@ import type { Tool } from '@pellux/goodvibes-sdk/platform/types';
3
3
  const CONTEXT_TOOL_DENIAL = [
4
4
  'GoodVibes Agent does not expose copied GoodVibes runtime context through model tools in the main conversation.',
5
5
  'The copied context tool can describe TUI/default runtime assumptions that are not the Agent product boundary.',
6
- 'Use explicit Agent CLI/slash commands such as status, compat, capabilities, and isolated Agent Knowledge instead.',
6
+ 'Use explicit Agent CLI/slash commands such as status, compat, setup, and isolated Agent Knowledge instead.',
7
7
  ].join(' ');
8
8
 
9
9
  export function wrapBlockedContextToolForAgentPolicy(tool: Tool): void {
10
10
  tool.definition.description = [
11
11
  'Blocked in GoodVibes Agent main conversation: copied runtime context.',
12
- 'Use explicit Agent CLI/slash status, compat, capabilities, and Agent Knowledge commands for product-scoped context.',
12
+ 'Use explicit Agent CLI/slash status, compat, setup, and Agent Knowledge commands for product-scoped context.',
13
13
  'Default Knowledge/Wiki, HomeGraph, and copied TUI runtime assumptions are not Agent fallbacks.',
14
14
  ].join(' ');
15
15
  tool.definition.sideEffects = [];
@@ -1,7 +1,6 @@
1
1
  import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs';
2
2
  import { join, resolve } from 'node:path';
3
3
  import { spawn } from 'node:child_process';
4
- import { auditGoodVibesHome } from '../config/goodvibes-home-audit.ts';
5
4
  import { buildVerificationLedger } from './verification-ledger.ts';
6
5
  import { SDK_VERSION } from '../version.ts';
7
6
 
@@ -309,20 +308,6 @@ export async function buildLiveVerificationReport(options: LiveVerificationOptio
309
308
  detail: `${ledger.totals.localBehaviorPercent}% local behavior verified; ${ledger.totals.externalOutcomeRequired} item(s) require external outcomes.`,
310
309
  });
311
310
 
312
- const audit = await auditGoodVibesHome({ homeDir });
313
- const staleCandidates = audit.settings?.staleCandidates?.length ?? 0;
314
- checks.push({
315
- id: 'goodvibes-home-audit',
316
- title: 'GoodVibes home ownership/settings audit',
317
- status: audit.findings.length === 0 && staleCandidates === 0 ? 'pass' : 'warn',
318
- summary: audit.findings.length === 0
319
- ? 'No ownership, stale-setting, or secret-permission findings.'
320
- : `${audit.findings.length} audit finding(s).`,
321
- detail: audit.findings.length === 0
322
- ? `${audit.settings?.recognizedKeyCount ?? 0} current schema key(s), ${staleCandidates} stale candidate(s).`
323
- : audit.findings.map((finding) => `${finding.severity}: ${finding.message}`).join('\n'),
324
- });
325
-
326
311
  checks.push({
327
312
  id: 'compiled-cli-present',
328
313
  title: 'Compiled GoodVibes Agent CLI binary',
package/src/version.ts CHANGED
@@ -6,7 +6,7 @@ import { join } from 'node:path';
6
6
  // The prebuild script updates the fallback value before compilation.
7
7
  // Uses import.meta.dir (Bun) to locate package.json relative to this file,
8
8
  // which is correct regardless of the process working directory.
9
- let _version = '0.1.46';
9
+ let _version = '0.1.48';
10
10
  let _sdkVersion = '0.33.35';
11
11
  try {
12
12
  const pkg = JSON.parse(readFileSync(join(import.meta.dir, '..', 'package.json'), 'utf-8')) as {