@pellux/goodvibes-agent 0.1.111 → 0.1.113

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 (34) hide show
  1. package/CHANGELOG.md +22 -0
  2. package/README.md +3 -3
  3. package/dist/package/main.js +9921 -9868
  4. package/docs/getting-started.md +3 -3
  5. package/package.json +1 -1
  6. package/src/cli/help.ts +4 -1
  7. package/src/cli/local-library-command.ts +90 -1
  8. package/src/cli/parser.ts +0 -8
  9. package/src/cli/service-posture.ts +1 -8
  10. package/src/cli/status.ts +1 -30
  11. package/src/cli/types.ts +0 -1
  12. package/src/input/agent-workspace-categories.ts +5 -7
  13. package/src/input/agent-workspace-snapshot.ts +2 -10
  14. package/src/input/agent-workspace-types.ts +2 -3
  15. package/src/input/commands/brief-runtime.ts +1 -1
  16. package/src/input/commands/channels-runtime.ts +397 -35
  17. package/src/input/commands/experience-runtime.ts +4 -9
  18. package/src/input/commands/health-runtime.ts +26 -6
  19. package/src/input/commands/mcp-runtime.ts +51 -26
  20. package/src/input/commands/memory.ts +10 -10
  21. package/src/input/commands/planning-runtime.ts +4 -9
  22. package/src/input/commands/provider-accounts-runtime.ts +2 -3
  23. package/src/input/commands/qrcode-runtime.ts +48 -9
  24. package/src/input/commands/recall-bundle.ts +16 -16
  25. package/src/input/commands/recall-capture.ts +18 -18
  26. package/src/input/commands/recall-query.ts +22 -22
  27. package/src/input/commands/recall-review.ts +12 -12
  28. package/src/input/commands/tasks-runtime.ts +9 -15
  29. package/src/input/commands/work-plan-runtime.ts +5 -19
  30. package/src/input/commands.ts +2 -7
  31. package/src/renderer/agent-workspace.ts +1 -2
  32. package/src/renderer/ui-factory.ts +1 -1
  33. package/src/runtime/onboarding/derivation.ts +6 -67
  34. package/src/version.ts +1 -1
@@ -96,9 +96,9 @@ Memory, personas, routines, and reusable Agent skills are local to GoodVibes Age
96
96
  /channels
97
97
  /agent-skills create --name "Morning Brief" --description "Daily briefing flow" --procedure "Check tasks, approvals, calendar, and unread state before summarizing." --enabled true
98
98
  /agent-skills enabled
99
- /skills local list
100
- /recall add fact Prefers concise morning briefings --scope project --tags preference
101
- /recall search morning
99
+ /skills list
100
+ /memory add fact "Prefers concise morning briefings" --scope project --tags preference
101
+ /memory search morning
102
102
  ```
103
103
 
104
104
  The active persona plus enabled Agent routines, reviewed memory, and skills are injected into the main serial assistant conversation. Starting a routine records local usage and prints its steps; it does not spawn background agents or automation jobs. Promoting a routine to a schedule is an explicit `schedules.create` call, requires `--yes`, writes a local redacted promotion receipt, and preserves the rule that Agent Knowledge never falls back to default Knowledge/Wiki or non-Agent knowledge segments.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pellux/goodvibes-agent",
3
- "version": "0.1.111",
3
+ "version": "0.1.113",
4
4
  "private": false,
5
5
  "description": "GoodVibes personal operator assistant TUI with a proactive Agent product brain, isolated Agent Knowledge, local profiles, routines, skills, personas, and explicit build delegation.",
6
6
  "type": "module",
package/src/cli/help.ts CHANGED
@@ -188,6 +188,8 @@ const COMMAND_HELP: Record<string, CommandHelp> = {
188
188
  'skills list',
189
189
  'skills enabled',
190
190
  'skills active',
191
+ 'skills discover',
192
+ 'skills import-discovered <name> [--enabled] --yes',
191
193
  'skills search <query>',
192
194
  'skills show <id>',
193
195
  'skills create --name <name> --description <summary> --procedure <steps> [--tags a,b] [--triggers a,b] [--enabled]',
@@ -202,6 +204,8 @@ const COMMAND_HELP: Record<string, CommandHelp> = {
202
204
  summary: 'Manage reusable Agent-local procedures and skill bundles for the main conversation.',
203
205
  examples: [
204
206
  'skills list',
207
+ 'skills discover',
208
+ 'skills import-discovered "Daily Brief" --enabled --yes',
205
209
  'skills create --name "Daily Brief" --description "Summarize operator state" --procedure "Review Agent Knowledge, work plans, approvals, and routines" --enabled',
206
210
  'skills bundle create --name "Ops Pack" --description "Daily operations bundle" --skills daily-brief --enabled',
207
211
  'skills delete daily-brief --yes',
@@ -366,7 +370,6 @@ const HELP_ALIASES: Record<string, string> = {
366
370
  skill: 'skills',
367
371
  'agent-skills': 'skills',
368
372
  memories: 'memory',
369
- recall: 'memory',
370
373
  subscriptions: 'subscription',
371
374
  secret: 'secrets',
372
375
  session: 'sessions',
@@ -1,5 +1,6 @@
1
1
  import { createShellPathService } from '@/runtime/index.ts';
2
2
  import { AgentPersonaRegistry, type AgentPersonaRecord } from '../agent/persona-registry.ts';
3
+ import { discoverSkills, type SkillRecord } from '../agent/skill-discovery.ts';
3
4
  import {
4
5
  AgentSkillRegistry,
5
6
  type AgentSkillBundleRecord,
@@ -107,6 +108,13 @@ function skillRegistry(runtime: CliCommandRuntime): AgentSkillRegistry {
107
108
  }));
108
109
  }
109
110
 
111
+ function shellPaths(runtime: CliCommandRuntime): ReturnType<typeof createShellPathService> {
112
+ return createShellPathService({
113
+ workingDirectory: runtime.workingDirectory,
114
+ homeDirectory: runtime.homeDirectory,
115
+ });
116
+ }
117
+
110
118
  function summarizePersona(persona: AgentPersonaRecord, activePersonaId: string | null): string {
111
119
  const active = persona.id === activePersonaId ? 'active' : 'available';
112
120
  const tags = persona.tags.length > 0 ? ` tags=${persona.tags.join(',')}` : '';
@@ -174,6 +182,52 @@ function renderSkillList(title: string, path: string, skills: readonly AgentSkil
174
182
  ].join('\n');
175
183
  }
176
184
 
185
+ function summarizeDiscoveredSkill(skill: SkillRecord): string {
186
+ const description = skill.description ? ` - ${skill.description}` : '';
187
+ const dependencies = skill.dependencies.length > 0 ? ` deps=${skill.dependencies.join(',')}` : '';
188
+ const includes = skill.includes.length > 0 ? ` includes=${skill.includes.join(',')}` : '';
189
+ return [
190
+ ` ${skill.name} ${skill.origin}${description}${dependencies}${includes}`,
191
+ ` path: ${skill.path}`,
192
+ ].join('\n');
193
+ }
194
+
195
+ function renderDiscoveredSkillList(skills: readonly SkillRecord[]): string {
196
+ if (skills.length === 0) {
197
+ return [
198
+ 'Discovered Agent skill files',
199
+ ' No SKILL.md or .md skill files found in Agent skill folders.',
200
+ ' Search roots: .goodvibes/skills, .goodvibes/agent/skills, ~/.goodvibes/skills, ~/.goodvibes/agent/skills',
201
+ ].join('\n');
202
+ }
203
+ return [
204
+ `Discovered Agent skill files (${skills.length})`,
205
+ ...skills.map(summarizeDiscoveredSkill),
206
+ '',
207
+ 'Import one with: goodvibes-agent skills import-discovered <name> --yes',
208
+ ].join('\n');
209
+ }
210
+
211
+ function discoveredSkillLookupValues(skill: SkillRecord): readonly string[] {
212
+ const slug = skill.name.trim().toLowerCase().replace(/[^a-z0-9]+/g, '-').replace(/^-+|-+$/g, '');
213
+ const basename = skill.path.split(/[\\/]/).pop()?.replace(/\.md$/i, '') ?? '';
214
+ return [skill.name, slug, skill.path, basename]
215
+ .map((value) => value.trim().toLowerCase())
216
+ .filter(Boolean);
217
+ }
218
+
219
+ function findDiscoveredSkill(skills: readonly SkillRecord[], idOrName: string): SkillRecord | null {
220
+ const lookup = idOrName.trim().toLowerCase();
221
+ if (!lookup) return null;
222
+ return skills.find((skill) => discoveredSkillLookupValues(skill).includes(lookup)) ?? null;
223
+ }
224
+
225
+ function discoveredFrontmatterList(skill: SkillRecord, key: string): readonly string[] {
226
+ const value = skill.frontmatter[key];
227
+ if (!value) return [];
228
+ return value.split(',').map((entry) => entry.trim()).filter(Boolean);
229
+ }
230
+
177
231
  function renderBundleList(title: string, path: string, bundles: readonly AgentSkillBundleRecord[]): string {
178
232
  if (bundles.length === 0) {
179
233
  return [
@@ -231,7 +285,7 @@ function usagePersonas(): string {
231
285
  }
232
286
 
233
287
  function usageSkills(): string {
234
- return 'Usage: goodvibes-agent skills [list|enabled|active|search <query>|show <id>|create|update <id>|enable <id>|disable <id>|review <id>|stale <id> <reason>|delete <id> --yes|bundle ...]';
288
+ return 'Usage: goodvibes-agent skills [list|enabled|active|discover|import-discovered <name> --yes|search <query>|show <id>|create|update <id>|enable <id>|disable <id>|review <id>|stale <id> <reason>|delete <id> --yes|bundle ...]';
235
289
  }
236
290
 
237
291
  function usageBundles(): string {
@@ -453,6 +507,41 @@ export async function handleSkillsCommand(runtime: CliCommandRuntime): Promise<C
453
507
  snapshot.enabledBundles.length > 0 ? renderBundleList('Enabled Agent skill bundles', snapshot.path, snapshot.enabledBundles) : '',
454
508
  ].filter(Boolean).join('\n\n'));
455
509
  }
510
+ if (normalized === 'discover') {
511
+ const discovered = await discoverSkills(shellPaths(runtime));
512
+ return success(runtime, 'agent.skills.discover', { skills: discovered }, renderDiscoveredSkillList(discovered));
513
+ }
514
+ if (normalized === 'import-discovered' || normalized === 'import-skill') {
515
+ const options = parseOptions(rest);
516
+ const name = options.positionals.join(' ').trim();
517
+ if (!name) return failure(runtime, 'invalid_skill_command', 'Usage: goodvibes-agent skills import-discovered <name> [--enabled] --yes', 2);
518
+ const discovered = findDiscoveredSkill(await discoverSkills(shellPaths(runtime)), name);
519
+ if (!discovered) {
520
+ return failure(runtime, 'skill_discovery_not_found', `Unknown discovered Agent skill: ${name}\nRun goodvibes-agent skills discover to inspect available skill files.`, 1);
521
+ }
522
+ if (!hasFlag(options, 'yes')) {
523
+ return success(runtime, 'agent.skills.import_discovered.preview', { skill: discovered }, [
524
+ 'Agent skill import preview',
525
+ ` name: ${discovered.name}`,
526
+ ` origin: ${discovered.origin}`,
527
+ ` path: ${discovered.path}`,
528
+ ` description: ${discovered.description || '(none)'}`,
529
+ ` procedure characters: ${discovered.body.length}`,
530
+ ' next: rerun with --yes to import into the Agent-local skill registry',
531
+ ].join('\n'));
532
+ }
533
+ const skill = registry.create({
534
+ name: discovered.name,
535
+ description: discovered.description || `Imported skill from ${discovered.origin} skill file.`,
536
+ procedure: discovered.body,
537
+ tags: discoveredFrontmatterList(discovered, 'tags'),
538
+ triggers: discoveredFrontmatterList(discovered, 'triggers'),
539
+ enabled: hasFlag(options, 'enabled'),
540
+ source: 'imported',
541
+ provenance: `discovered:${discovered.origin}:${discovered.path}`,
542
+ });
543
+ return success(runtime, 'agent.skills.import_discovered', skill, `Imported Agent skill ${skill.id}: ${skill.name}${skill.enabled ? ' (enabled)' : ''}`);
544
+ }
456
545
  if (normalized === 'search' || normalized === 'find') {
457
546
  const query = rest.join(' ').trim();
458
547
  const results = registry.search(query);
package/src/cli/parser.ts CHANGED
@@ -26,7 +26,6 @@ const COMMAND_ALIASES: Readonly<Record<string, GoodVibesCliCommand>> = {
26
26
  'agent-skills': 'skills',
27
27
  memory: 'memory',
28
28
  memories: 'memory',
29
- recall: 'memory',
30
29
  routines: 'routines',
31
30
  routine: 'routines',
32
31
  auth: 'auth',
@@ -66,7 +65,6 @@ function createDefaultFlags(): GoodVibesCliFlags {
66
65
  provider: undefined,
67
66
  model: undefined,
68
67
  agentProfile: undefined,
69
- daemonHome: undefined,
70
68
  runtimeUrl: undefined,
71
69
  workingDir: undefined,
72
70
  help: false,
@@ -286,12 +284,6 @@ export function parseGoodVibesCli(
286
284
  if (consumed.value !== undefined) flags = withFlag(flags, 'agentProfile', consumed.value);
287
285
  continue;
288
286
  }
289
- if (name === '--daemon-home') {
290
- const consumed = getValue(argv, index, inlineValue, name, errors);
291
- index = consumed.nextIndex;
292
- if (consumed.value !== undefined) flags = withFlag(flags, 'daemonHome', consumed.value);
293
- continue;
294
- }
295
287
  if (name === '--runtime-url' || name === '--runtime') {
296
288
  const consumed = getValue(argv, index, inlineValue, name, errors);
297
289
  index = consumed.nextIndex;
@@ -186,12 +186,6 @@ export async function buildCliServicePosture(
186
186
  if (serverBackedEnabled && !config.enabled) {
187
187
  issues.push('Connected-service settings are present, but Agent service ownership is disabled by design.');
188
188
  }
189
- if (config.enabled && !config.autostart) {
190
- issues.push('Connected-service autostart is off.');
191
- }
192
- if (config.enabled && !config.restartOnFailure) {
193
- issues.push('Connected-service restart-on-failure is off.');
194
- }
195
189
  for (const endpoint of endpoints) {
196
190
  if (endpoint.enabled && options.probe && endpoint.reachable === false) {
197
191
  issues.push(`${endpoint.label} is enabled but not reachable on ${endpoint.binding.host}:${endpoint.binding.port}.`);
@@ -233,8 +227,7 @@ export function formatCliServicePosture(posture: CliServicePosture, json = false
233
227
  ' ownership: managed outside goodvibes-agent',
234
228
  ' Agent owns lifecycle: no',
235
229
  ` external host config present: ${yesNo(posture.config.enabled)}`,
236
- ` external host autostart config: ${yesNo(posture.config.autostart)}`,
237
- ` external host restart config: ${yesNo(posture.config.restartOnFailure)}`,
230
+ ' external host lifecycle config: ignored by Agent',
238
231
  ` legacy host switch present: ${yesNo(posture.config.daemonEnabled)}`,
239
232
  ` log: ${posture.log.path ?? 'n/a'} (${posture.log.exists ? 'present' : 'missing'})`,
240
233
  ...(posture.log.readError ? [` log read error: ${posture.log.readError}`] : []),
package/src/cli/status.ts CHANGED
@@ -99,8 +99,6 @@ function bindLine(label: string, enabled: unknown, binding: { readonly hostMode:
99
99
  export function buildCliDoctorFindings(options: CliStatusOptions): readonly CliDoctorFinding[] {
100
100
  const config = options.configManager;
101
101
  const serviceEnabled = config.get('service.enabled') === true;
102
- const serviceAutostart = config.get('service.autostart') === true;
103
- const restartOnFailure = config.get('service.restartOnFailure') === true;
104
102
  const daemonEnabled = config.get('danger.daemon') === true;
105
103
  const listenerEnabled = config.get('danger.httpListener') === true;
106
104
  const webEnabled = config.get('web.enabled') === true;
@@ -180,30 +178,6 @@ export function buildCliDoctorFindings(options: CliStatusOptions): readonly CliD
180
178
  });
181
179
  }
182
180
 
183
- if (serviceEnabled && !serviceAutostart) {
184
- findings.push({
185
- id: 'runtime-autostart-disabled',
186
- area: 'runtime',
187
- severity: 'warning',
188
- summary: 'Connected-service autostart is off.',
189
- cause: 'service.enabled is true and service.autostart is false.',
190
- impact: 'Connected GoodVibes services may not be available after login or reboot even though host-managed startup is selected.',
191
- action: 'Configure autostart from GoodVibes TUI or the owning host; Agent will not mutate this setting.',
192
- });
193
- }
194
-
195
- if (serviceEnabled && !restartOnFailure) {
196
- findings.push({
197
- id: 'runtime-restart-disabled',
198
- area: 'runtime',
199
- severity: 'warning',
200
- summary: 'Connected-service restart-on-failure is off.',
201
- cause: 'service.enabled is true and service.restartOnFailure is false.',
202
- impact: 'A crashed connected service or listener may stay down until manually restarted.',
203
- action: 'Configure restart-on-failure from GoodVibes TUI or the owning host; Agent will not mutate this setting.',
204
- });
205
- }
206
-
207
181
  if (options.service) {
208
182
  for (const issue of options.service.issues) {
209
183
  if (findings.some((finding) => finding.summary === issue)) continue;
@@ -342,8 +316,6 @@ export function renderCliStatus(options: CliStatusOptions): string {
342
316
  const config = options.configManager;
343
317
  const snapshot = buildCliStatusSnapshot(options);
344
318
  const serviceEnabled = snapshot.runtimeConnection.enabled;
345
- const serviceAutostart = snapshot.runtimeConnection.autostart;
346
- const restartOnFailure = snapshot.runtimeConnection.restartOnFailure;
347
319
  const controlPlaneEnabled = snapshot.runtimeEndpoints.controlPlane.enabled;
348
320
  const listenerEnabled = snapshot.runtimeEndpoints.httpListener.enabled;
349
321
  const webEnabled = snapshot.runtimeEndpoints.web.enabled;
@@ -414,8 +386,7 @@ export function renderCliStatus(options: CliStatusOptions): string {
414
386
  '',
415
387
  'Connected-Service Config Signals:',
416
388
  ` host config present: ${yesNo(serviceEnabled)}`,
417
- ` host autostart: ${yesNo(serviceAutostart)}`,
418
- ` host restart policy: ${yesNo(restartOnFailure)}`,
389
+ ' lifecycle config: external to Agent',
419
390
  '',
420
391
  'Endpoint Diagnostics:',
421
392
  bindLine('runtimeApi', controlPlaneEnabled, controlPlaneBinding),
package/src/cli/types.ts CHANGED
@@ -39,7 +39,6 @@ export interface GoodVibesCliFlags {
39
39
  readonly provider: string | undefined;
40
40
  readonly model: string | undefined;
41
41
  readonly agentProfile: string | undefined;
42
- readonly daemonHome: string | undefined;
43
42
  readonly runtimeUrl: string | undefined;
44
43
  readonly workingDir: string | undefined;
45
44
  readonly help: boolean;
@@ -52,7 +52,7 @@ export const AGENT_WORKSPACE_CATEGORIES: readonly AgentWorkspaceCategory[] = [
52
52
  detail: 'Agent uses connected channel accounts. Pairing, account inspection, and readiness checks are visible here; inbound delivery and public channel exposure stay policy-gated.',
53
53
  actions: [
54
54
  { id: 'pair', label: 'Pair companion', detail: 'Open the QR pairing view for companion app setup.', command: '/pair', kind: 'command', safety: 'safe' },
55
- { id: 'channel-readiness', label: 'Channel readiness', detail: 'Show a read-only readiness matrix for configured messaging and notification channels.', command: '/channels', kind: 'command', safety: 'read-only' },
55
+ { id: 'channel-readiness', label: 'Channel readiness', detail: 'Show the read-only readiness matrix, then use /channels attention or /channels show <id> for setup detail.', command: '/channels', kind: 'command', safety: 'read-only' },
56
56
  { id: 'notification-routes', label: 'Notification routes', detail: 'Inspect configured webhook notification URLs without sending a test message.', command: '/notify list', kind: 'command', safety: 'read-only' },
57
57
  { id: 'notification-add-webhook', label: 'Add webhook target', detail: 'Open a confirmed form that adds one webhook notification target for explicit reminder and routine delivery.', editorKind: 'notify-webhook', kind: 'editor', safety: 'safe' },
58
58
  { id: 'notification-remove-webhook', label: 'Remove webhook target', detail: 'Open a confirmed form that removes one exact webhook notification target from Agent delivery.', editorKind: 'notify-webhook-remove', kind: 'editor', safety: 'safe' },
@@ -116,10 +116,9 @@ export const AGENT_WORKSPACE_CATEGORIES: readonly AgentWorkspaceCategory[] = [
116
116
  id: 'profiles',
117
117
  group: 'SETUP',
118
118
  label: 'Profiles',
119
- summary: 'Isolated Agent homes, config profiles, and setup bundles.',
120
- detail: 'Profiles isolate Agent state. Named homes and starter templates let one install behave like separate assistants for household, research, travel, operations, or personal workflows.',
119
+ summary: 'Isolated Agent homes, starter templates, and setup bundles.',
120
+ detail: 'Agent profiles isolate Agent state. Named homes and starter templates let one install behave like separate assistants for household, research, travel, operations, or personal workflows.',
121
121
  actions: [
122
- { id: 'profiles-open', label: 'Open config profiles', detail: 'Open the config profile picker for display/provider/behavior profile files.', command: '/profiles', kind: 'command', safety: 'safe' },
123
122
  { id: 'runtime-profile-guide', label: 'Starter authoring guide', detail: 'Open the Agent-local starter authoring flow inside the Agent TUI.', command: '/agent-profile guide', kind: 'command', safety: 'safe' },
124
123
  { id: 'runtime-profile-templates', label: 'Browse starter templates', detail: 'List built-in and local Agent starter templates with persona, skill, routine, and source details.', command: '/agent-profile templates', kind: 'command', safety: 'read-only' },
125
124
  { id: 'runtime-profile-list', label: 'List Agent profiles', detail: 'List isolated Agent profile homes under this Agent home.', command: '/agent-profile list', kind: 'command', safety: 'read-only' },
@@ -221,9 +220,8 @@ export const AGENT_WORKSPACE_CATEGORIES: readonly AgentWorkspaceCategory[] = [
221
220
  summary: 'Visible task state, work plan, and approval posture.',
222
221
  detail: 'Use this workspace to inspect active operator state. Side-effecting approval decisions require explicit commands and confirmation outside this workspace.',
223
222
  actions: [
224
- { id: 'workplan', label: 'Open work plan', detail: 'Open the workspace-scoped work plan panel.', command: '/workplan panel', kind: 'command', safety: 'read-only' },
225
- { id: 'workplan-list', label: 'List work plan', detail: 'Print a concise work plan summary.', command: '/workplan list', kind: 'command', safety: 'read-only' },
226
- { 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' },
223
+ { id: 'workplan', label: 'Review work plan', detail: 'Print a concise work plan summary in the main Agent transcript.', command: '/workplan list', kind: 'command', safety: 'read-only' },
224
+ { id: 'approvals', label: 'Review approvals', detail: 'Print the approval matrix without approving or denying requests.', command: '/approval matrix', kind: 'command', safety: 'read-only' },
227
225
  ],
228
226
  },
229
227
  {
@@ -240,13 +240,6 @@ export function buildAgentWorkspaceRuntimeSnapshot(context: CommandContext): Age
240
240
  return [];
241
241
  }
242
242
  })();
243
- const configProfileCount = (() => {
244
- try {
245
- return context.workspace?.profileManager?.list?.().length ?? 0;
246
- } catch {
247
- return 0;
248
- }
249
- })();
250
243
  const runtimeStarterTemplates = (() => {
251
244
  try {
252
245
  return listAgentRuntimeProfileTemplates(context.workspace?.shellPaths?.homeDirectory ?? '');
@@ -379,8 +372,8 @@ export function buildAgentWorkspaceRuntimeSnapshot(context: CommandContext): Age
379
372
  mcpConnectedServerCount: mcpSnapshot.connectedCount,
380
373
  mcpQuarantinedServerCount: mcpSnapshot.quarantinedCount,
381
374
  mcpAllowAllServerCount: mcpSnapshot.allowAllCount,
382
- browserSurfaceEnabled: readConfigBoolean(context, 'web.enabled', false),
383
- browserSurfacePublicBaseUrl: readConfigString(context, 'web.publicBaseUrl', '(not configured)'),
375
+ browserToolExposureEnabled: readConfigBoolean(context, 'web.enabled', false),
376
+ browserToolPublicBaseUrl: readConfigString(context, 'web.publicBaseUrl', '(not configured)'),
384
377
  activeRuntimeProfile: inferActiveRuntimeProfile(context.workspace?.shellPaths?.homeDirectory ?? ''),
385
378
  runtimeProfileCount: runtimeProfiles.length,
386
379
  runtimeProfiles: runtimeProfiles.map(summarizeRuntimeProfile),
@@ -388,7 +381,6 @@ export function buildAgentWorkspaceRuntimeSnapshot(context: CommandContext): Age
388
381
  runtimeStarterTemplateCount: runtimeStarterTemplates.length,
389
382
  localStarterTemplateCount: runtimeStarterTemplates.filter((template) => template.source === 'local').length,
390
383
  runtimeStarterTemplates: runtimeStarterTemplates.map(summarizeStarterTemplate),
391
- configProfileCount,
392
384
  setupChecklist,
393
385
  warnings,
394
386
  };
@@ -190,8 +190,8 @@ export interface AgentWorkspaceRuntimeSnapshot {
190
190
  readonly mcpConnectedServerCount: number;
191
191
  readonly mcpQuarantinedServerCount: number;
192
192
  readonly mcpAllowAllServerCount: number;
193
- readonly browserSurfaceEnabled: boolean;
194
- readonly browserSurfacePublicBaseUrl: string;
193
+ readonly browserToolExposureEnabled: boolean;
194
+ readonly browserToolPublicBaseUrl: string;
195
195
  readonly activeRuntimeProfile: string;
196
196
  readonly runtimeProfileCount: number;
197
197
  readonly runtimeProfiles: readonly AgentWorkspaceRuntimeProfileItem[];
@@ -199,7 +199,6 @@ export interface AgentWorkspaceRuntimeSnapshot {
199
199
  readonly runtimeStarterTemplateCount: number;
200
200
  readonly localStarterTemplateCount: number;
201
201
  readonly runtimeStarterTemplates: readonly AgentWorkspaceRuntimeStarterTemplateItem[];
202
- readonly configProfileCount: number;
203
202
  readonly setupChecklist: readonly AgentWorkspaceSetupChecklistItem[];
204
203
  readonly warnings: readonly string[];
205
204
  }
@@ -101,7 +101,7 @@ export function formatAgentOperatorBriefing(ctx: CommandContext): string {
101
101
  ` skills: ${snapshot.enabledSkillCount}/${snapshot.localSkillCount} enabled; bundles ${snapshot.enabledSkillBundleCount}/${snapshot.localSkillBundleCount}; active ${snapshot.activeSkillCount}`,
102
102
  ` routines: ${snapshot.enabledRoutineCount}/${snapshot.localRoutineCount} enabled`,
103
103
  ` channels: ${readyChannels}/${snapshot.channels.length} ready; ${enabledChannels} enabled`,
104
- ` voice/media: ${snapshot.voiceProviderCount} voice, ${snapshot.mediaProviderCount} media; browser surface ${snapshot.browserSurfaceEnabled ? 'enabled' : 'disabled'}`,
104
+ ` voice/media: ${snapshot.voiceProviderCount} voice, ${snapshot.mediaProviderCount} media; browser tools ${snapshot.voiceMediaReadiness.browserToolState}`,
105
105
  formatWorkPlanLine(workPlan.total, workPlan.counts),
106
106
  ` schedules: ${enabledJobs}/${jobs.length} visible jobs enabled`,
107
107
  '',