@pellux/goodvibes-agent 1.1.4 → 1.1.6

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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pellux/goodvibes-agent",
3
- "version": "1.1.4",
3
+ "version": "1.1.6",
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",
@@ -38,6 +38,8 @@ interface AgentWorkspaceActivationHost {
38
38
  applyLocalLibraryOperation(operation: AgentWorkspaceLocalOperation): void;
39
39
  applySettingAction(action: AgentWorkspaceCategory['actions'][number], requestRender?: () => void): void;
40
40
  importTuiSettings(requestRender?: () => void): void;
41
+ openModelPickerAction(action: AgentWorkspaceCategory['actions'][number], requestRender?: () => void): void;
42
+ openSettingsModalAction(action: AgentWorkspaceCategory['actions'][number], requestRender?: () => void): void;
41
43
  completeOnboarding(): void;
42
44
  hasCommandDispatch(): boolean;
43
45
  dispatchWorkspaceCommand: AgentWorkspaceCommandDispatcher;
@@ -67,6 +69,14 @@ export function activateAgentWorkspaceSelection(
67
69
  workspace.importTuiSettings(requestRender);
68
70
  return;
69
71
  }
72
+ if (action.kind === 'model-picker') {
73
+ workspace.openModelPickerAction(action, requestRender);
74
+ return;
75
+ }
76
+ if (action.kind === 'settings-modal') {
77
+ workspace.openSettingsModalAction(action, requestRender);
78
+ return;
79
+ }
70
80
  if (action.kind === 'editor' && action.editorKind) {
71
81
  const editor = createAgentWorkspaceEditor(action.editorKind, {
72
82
  runtimeStarterTemplates: workspace.runtimeSnapshot?.runtimeStarterTemplates ?? [],
@@ -613,7 +613,7 @@ export function createAgentWorkspaceBasicCommandEditor(kind: AgentWorkspaceBasic
613
613
  selectedFieldIndex: 0,
614
614
  message: 'Inspect one provider subscription route without starting login or printing token values.',
615
615
  fields: [
616
- { id: 'provider', label: 'Provider', value: 'openai', required: true, multiline: false, hint: 'Subscription provider id from /subscription providers.' },
616
+ { id: 'provider', label: 'Provider', value: 'openai', required: true, multiline: false, hint: 'Subscription provider id, such as openai.' },
617
617
  ],
618
618
  };
619
619
  }
@@ -623,12 +623,11 @@ export function createAgentWorkspaceBasicCommandEditor(kind: AgentWorkspaceBasic
623
623
  mode: 'create',
624
624
  title: 'Start Provider Subscription Login',
625
625
  selectedFieldIndex: 0,
626
- message: 'Begin one provider subscription OAuth login. Type yes on the final field to confirm browser and pending-login side effects.',
626
+ message: 'Begin one provider subscription OAuth login, save the pending session, and return here for completion.',
627
627
  fields: [
628
- { id: 'provider', label: 'Provider', value: 'openai', required: true, multiline: false, hint: 'Subscription provider id from /subscription providers.' },
628
+ { id: 'provider', label: 'Provider', value: 'openai', required: true, multiline: false, hint: 'Subscription provider id, such as openai.' },
629
629
  { id: 'openBrowser', label: 'Open browser', value: 'yes', required: false, multiline: false, hint: 'yes/no. Use no to print the authorization URL only.' },
630
- { id: 'manual', label: 'Manual completion', value: 'yes', required: false, multiline: false, hint: 'Agent always finishes subscription login through the explicit finish form.' },
631
- { id: 'confirm', label: 'Confirm', value: '', required: true, multiline: false, hint: 'Type yes to run /subscription login <provider> start with --yes.' },
630
+ { id: 'confirm', label: 'Confirm', value: '', required: true, multiline: false, hint: 'Type yes to save pending login state and open or show the authorization URL.' },
632
631
  ],
633
632
  };
634
633
  }
@@ -638,11 +637,11 @@ export function createAgentWorkspaceBasicCommandEditor(kind: AgentWorkspaceBasic
638
637
  mode: 'update',
639
638
  title: 'Finish Provider Subscription Login',
640
639
  selectedFieldIndex: 0,
641
- message: 'Finish a pending provider subscription OAuth login from a code or redirected URL. Type yes on the final field to confirm token storage.',
640
+ message: 'Finish a pending provider subscription OAuth login from a code or redirected URL and save the subscription session.',
642
641
  fields: [
643
642
  { id: 'provider', label: 'Provider', value: 'openai', required: true, multiline: false, hint: 'Provider id used when starting login.' },
644
643
  { id: 'code', label: 'Code or redirect URL', value: '', required: true, multiline: false, hint: 'OAuth code or full redirect URL containing code=...' },
645
- { id: 'confirm', label: 'Confirm', value: '', required: true, multiline: false, hint: 'Type yes to run /subscription login <provider> finish with --yes.' },
644
+ { id: 'confirm', label: 'Confirm', value: '', required: true, multiline: false, hint: 'Type yes to exchange the code and save the provider subscription session.' },
646
645
  ],
647
646
  };
648
647
  }
@@ -652,10 +651,10 @@ export function createAgentWorkspaceBasicCommandEditor(kind: AgentWorkspaceBasic
652
651
  mode: 'delete',
653
652
  title: 'Logout Provider Subscription',
654
653
  selectedFieldIndex: 0,
655
- message: 'Remove one stored provider subscription session. Ambient API key resolution applies again if configured. Type yes to confirm.',
654
+ message: 'Remove one active or pending provider subscription session. Ambient API key resolution applies again if configured.',
656
655
  fields: [
657
656
  { id: 'provider', label: 'Provider', value: 'openai', required: true, multiline: false, hint: 'Stored subscription provider id.' },
658
- { id: 'confirm', label: 'Confirm', value: '', required: true, multiline: false, hint: 'Type yes to run /subscription logout with --yes.' },
657
+ { id: 'confirm', label: 'Confirm', value: '', required: true, multiline: false, hint: 'Type yes to remove active or pending subscription state.' },
659
658
  ],
660
659
  };
661
660
  }
@@ -1,5 +1,6 @@
1
1
  import type { AgentWorkspaceCategory } from './agent-workspace-types.ts';
2
2
  import { settingAction } from './agent-workspace-category-actions.ts';
3
+ import { AGENT_WORKSPACE_HOST_CATEGORY } from './agent-workspace-host-category.ts';
3
4
 
4
5
  export const AGENT_WORKSPACE_CATEGORIES: readonly AgentWorkspaceCategory[] = [
5
6
  {
@@ -12,6 +13,7 @@ export const AGENT_WORKSPACE_CATEGORIES: readonly AgentWorkspaceCategory[] = [
12
13
  { id: 'chat', label: 'Continue assistant chat', detail: 'Return to the main composer and type a normal message. Agent work stays serial in the main conversation.', kind: 'guidance', safety: 'safe' },
13
14
  { id: 'brief', label: 'Operator briefing', detail: 'Show a concise Agent status and next-actions briefing without mutating the connected host.', command: '/brief', kind: 'command', safety: 'read-only' },
14
15
  { id: 'model', label: 'Choose model', detail: 'Open the model/provider workspace for the Agent chat route.', command: '/model', kind: 'command', safety: 'safe' },
16
+ { id: 'model-refresh', label: 'Refresh model catalog', detail: 'Refresh locally cached provider model lists without changing the selected route.', command: '/refresh-models', kind: 'command', safety: 'safe' },
15
17
  { id: 'setup-home', label: 'Onboarding', detail: 'Jump to first-run configuration for account, model, tools, channels, voice, local context, and finish.', targetCategoryId: 'setup', kind: 'workspace', safety: 'safe' },
16
18
  { id: 'channels-home', label: 'Channels', detail: 'Jump to companion pairing and channel readiness without changing connected-host routing.', targetCategoryId: 'channels', kind: 'workspace', safety: 'read-only' },
17
19
  { id: 'mode-show', label: 'Interaction mode', detail: 'Review Agent interaction noise level and per-domain verbosity.', command: '/mode show', kind: 'command', safety: 'read-only' },
@@ -38,63 +40,55 @@ export const AGENT_WORKSPACE_CATEGORIES: readonly AgentWorkspaceCategory[] = [
38
40
  id: 'setup',
39
41
  group: 'ONBOARDING',
40
42
  label: 'Start',
41
- summary: 'Import existing GoodVibes preferences, choose a main model, and sign in.',
42
- detail: 'Use this first. Every row either imports existing settings, edits a setting inline, or opens a concrete sign-in/provider form.',
43
+ summary: 'Import preferences, sign in, and choose the main model.',
44
+ detail: 'Start here on a fresh install. Every row either saves state, opens the shared model picker, or opens a confirmed in-modal form.',
43
45
  actions: [
44
- { id: 'import-goodvibes-tui-settings', label: 'Import GoodVibes settings', detail: 'Copy existing GoodVibes TUI display, provider, behavior, permission, TTS, channel, helper, tool, release, and automation values into Agent-owned settings.', kind: 'settings-import', safety: 'safe' },
45
- settingAction({ id: 'setup-provider-model', label: 'Main model', detail: 'Set the provider-qualified model used for normal assistant turns.', key: 'provider.model' }),
46
- settingAction({ id: 'setup-reasoning-effort', label: 'Reasoning effort', detail: 'Cycle the reasoning level used when the selected model supports it.', key: 'provider.reasoningEffort' }),
47
- { id: 'subscription-login-start', label: 'Start subscription login', detail: 'Open a confirmed form for one provider OAuth login start, with browser/manual completion controls.', editorKind: 'subscription-login-start', kind: 'editor', safety: 'safe' },
48
- { id: 'subscription-login-finish', label: 'Finish subscription login', detail: 'Open a confirmed form that stores one completed provider subscription session from a code or redirect URL.', editorKind: 'subscription-login-finish', kind: 'editor', safety: 'safe' },
49
- { id: 'subscription-logout', label: 'Logout subscription', detail: 'Open a confirmed form that removes one stored provider subscription session.', editorKind: 'subscription-logout', kind: 'editor', safety: 'safe' },
50
- { id: 'subscription-inspect', label: 'Inspect subscription route', detail: 'Inspect one provider subscription OAuth route before starting or finishing login.', editorKind: 'subscription-inspect', kind: 'editor', safety: 'read-only' },
51
- { id: 'subscription-bundle-export', label: 'Export subscription bundle', detail: 'Export a redacted provider subscription bundle for setup review.', editorKind: 'subscription-bundle-export', kind: 'editor', safety: 'safe' },
52
- { id: 'subscription-bundle-inspect', label: 'Inspect subscription bundle', detail: 'Inspect a provider subscription bundle before setup review.', editorKind: 'subscription-bundle-inspect', kind: 'editor', safety: 'read-only' },
46
+ { id: 'import-goodvibes-tui-settings', label: 'Import GoodVibes settings', detail: 'Copy existing display, provider, subscription, behavior, permission, TTS, channel, helper, tool, release, and automation values into Agent-owned state.', kind: 'settings-import', safety: 'safe' },
47
+ { id: 'subscription-login-start', label: 'Start subscription login', detail: 'Start one provider sign-in flow, save pending state, and return here.', editorKind: 'subscription-login-start', kind: 'editor', safety: 'safe' },
48
+ { id: 'subscription-login-finish', label: 'Finish subscription login', detail: 'Exchange a code or redirect URL and save the provider subscription session.', editorKind: 'subscription-login-finish', kind: 'editor', safety: 'safe' },
49
+ { id: 'setup-provider-model', label: 'Choose main model', detail: 'Open the shared provider/model picker for normal assistant turns.', kind: 'model-picker', modelPickerFlow: 'providerModel', modelPickerTarget: 'main', safety: 'safe' },
50
+ settingAction({ id: 'setup-reasoning-effort', label: 'Reasoning effort', detail: 'Cycle reasoning level when the selected model supports it.', key: 'provider.reasoningEffort' }),
51
+ { id: 'subscription-logout', label: 'Logout subscription', detail: 'Remove one stored or pending provider subscription session after confirmation.', editorKind: 'subscription-logout', kind: 'editor', safety: 'safe' },
53
52
  { id: 'provider-add', label: 'Add custom provider', detail: 'Add one OpenAI-compatible provider for Agent model routing.', editorKind: 'provider-add', kind: 'editor', safety: 'safe' },
54
- { id: 'secret-set-provider', label: 'Store API secret', detail: 'Store a provider or channel credential through the Agent secret manager.', editorKind: 'secret-set', kind: 'editor', safety: 'safe' },
55
- settingAction({ id: 'setup-secret-policy', label: 'Secret storage policy', detail: 'Choose whether secret persistence prefers or requires secure storage.', key: 'storage.secretPolicy' }),
56
- settingAction({ id: 'setup-save-history', label: 'Save conversation history', detail: 'Toggle local conversation history persistence.', key: 'behavior.saveHistory' }),
53
+ { id: 'secret-set-provider', label: 'Store secret', detail: 'Store a provider or channel credential through the Agent secret manager.', editorKind: 'secret-set', kind: 'editor', safety: 'safe' },
54
+ settingAction({ id: 'setup-secret-policy', label: 'Secret storage', detail: 'Choose how strongly Agent prefers secure secret storage.', key: 'storage.secretPolicy' }),
55
+ settingAction({ id: 'setup-save-history', label: 'Save history', detail: 'Toggle local conversation history persistence.', key: 'behavior.saveHistory' }),
57
56
  ],
58
57
  },
59
58
  {
60
59
  id: 'account-model',
61
60
  group: 'ONBOARDING',
62
- label: 'Account & Model',
63
- summary: 'Model routing for chat, helpers, tools, embeddings, and spoken turns.',
64
- detail: 'Use this after sign-in to make model routing explicit for each workload.',
61
+ label: 'Model Routing',
62
+ summary: 'Set chat, embedding, helper, tool, and spoken-turn routes.',
63
+ detail: 'Use this after sign-in. Routes are saved settings, so selections persist across launches.',
65
64
  actions: [
66
- { id: 'provider-use', label: 'Switch provider', detail: 'Open a provider-id form that switches the Agent chat provider.', editorKind: 'provider-use', kind: 'editor', safety: 'safe' },
67
- { id: 'provider-inspect', label: 'Inspect provider auth', detail: 'Inspect one provider auth/setup route without storing tokens or starting login.', editorKind: 'provider-inspect', kind: 'editor', safety: 'read-only' },
68
- { id: 'provider-routes', label: 'Inspect provider routes', detail: 'Inspect provider route and fallback posture for one provider.', editorKind: 'provider-routes', kind: 'editor', safety: 'read-only' },
69
- { id: 'provider-account-repair', label: 'Provider repair guidance', detail: 'Show provider account repair guidance without mutating credentials.', editorKind: 'provider-account-repair', kind: 'editor', safety: 'read-only' },
70
- { id: 'provider-remove', label: 'Remove custom provider', detail: 'Remove one Agent custom provider config after confirmation.', editorKind: 'provider-remove', kind: 'editor', safety: 'safe' },
71
- { id: 'model-refresh', label: 'Refresh model catalog', detail: 'Refresh model catalog, benchmark, and token-limit metadata.', command: '/refresh-models', kind: 'command', safety: 'safe' },
72
- { id: 'model-pin', label: 'Pin model', detail: 'Pin one model registry key for quick reuse.', editorKind: 'model-pin', kind: 'editor', safety: 'safe' },
73
- { id: 'model-unpin', label: 'Unpin model', detail: 'Remove one pinned model registry key.', editorKind: 'model-unpin', kind: 'editor', safety: 'safe' },
74
- { id: 'auth-show', label: 'Show provider auth', detail: 'Inspect provider auth state without printing token values.', editorKind: 'auth-show', kind: 'editor', safety: 'read-only' },
75
- { id: 'auth-repair', label: 'Auth repair guidance', detail: 'Show auth repair guidance without storing tokens or starting login.', editorKind: 'auth-repair', kind: 'editor', safety: 'read-only' },
76
- { id: 'auth-bundle-export', label: 'Export auth bundle', detail: 'Export a redacted auth review bundle after confirmation.', editorKind: 'auth-bundle-export', kind: 'editor', safety: 'safe' },
77
- { id: 'auth-bundle-inspect', label: 'Inspect auth bundle', detail: 'Inspect an auth review bundle before setup review.', editorKind: 'auth-bundle-inspect', kind: 'editor', safety: 'read-only' },
78
- settingAction({ id: 'account-main-model', label: 'Main model', detail: 'Edit the provider-qualified model registry key for normal assistant turns.', key: 'provider.model' }),
79
- settingAction({ id: 'account-reasoning', label: 'Reasoning effort', detail: 'Cycle instant, low, medium, or high reasoning effort.', key: 'provider.reasoningEffort' }),
80
- settingAction({ id: 'account-embedding', label: 'Embedding provider', detail: 'Set the embedding provider used by local memory and retrieval.', key: 'provider.embeddingProvider' }),
65
+ { id: 'provider-use', label: 'Choose provider and model', detail: 'Open the shared provider/model picker for the main chat route.', kind: 'model-picker', modelPickerFlow: 'providerModel', modelPickerTarget: 'main', safety: 'safe' },
66
+ { id: 'provider-remove', label: 'Remove custom provider', detail: 'Remove one custom provider config after confirmation.', editorKind: 'provider-remove', kind: 'editor', safety: 'safe' },
67
+ { id: 'account-main-model', label: 'Choose main model', detail: 'Open the shared model picker for normal assistant turns.', kind: 'model-picker', modelPickerFlow: 'model', modelPickerTarget: 'main', safety: 'safe' },
68
+ settingAction({ id: 'account-reasoning', label: 'Reasoning effort', detail: 'Cycle the reasoning effort used when supported.', key: 'provider.reasoningEffort' }),
69
+ settingAction({ id: 'account-embedding', label: 'Embedding provider', detail: 'Set the embedding provider for memory and retrieval.', key: 'provider.embeddingProvider' }),
81
70
  settingAction({ id: 'account-system-prompt', label: 'System prompt file', detail: 'Set an optional local system prompt file path.', key: 'provider.systemPromptFile' }),
82
71
  settingAction({ id: 'account-helper-enabled', label: 'Enable helper model', detail: 'Toggle dedicated helper routing for background utility work.', key: 'helper.enabled' }),
83
- settingAction({ id: 'account-helper-provider', label: 'Helper provider', detail: 'Set the helper provider id.', key: 'helper.globalProvider', visibleWhenKey: 'helper.enabled', visibleWhenValue: true }),
84
- settingAction({ id: 'account-helper-model', label: 'Helper model', detail: 'Set the helper model registry key.', key: 'helper.globalModel', visibleWhenKey: 'helper.enabled', visibleWhenValue: true }),
72
+ { id: 'account-helper-provider', label: 'Choose helper provider/model', detail: 'Open the shared provider/model picker for helper routing.', kind: 'model-picker', modelPickerFlow: 'providerModel', modelPickerTarget: 'helper', visibleWhenSettingKey: 'helper.enabled', visibleWhenSettingValue: true, safety: 'safe' },
73
+ { id: 'account-helper-model', label: 'Choose helper model', detail: 'Open the shared model picker for helper routing.', kind: 'model-picker', modelPickerFlow: 'model', modelPickerTarget: 'helper', visibleWhenSettingKey: 'helper.enabled', visibleWhenSettingValue: true, safety: 'safe' },
85
74
  settingAction({ id: 'account-tool-llm-enabled', label: 'Enable tool LLM', detail: 'Toggle a dedicated tool LLM for internal operations.', key: 'tools.llmEnabled' }),
86
- settingAction({ id: 'account-tool-provider', label: 'Tool LLM provider', detail: 'Set the provider for dedicated tool LLM calls.', key: 'tools.llmProvider', visibleWhenKey: 'tools.llmEnabled', visibleWhenValue: true }),
87
- settingAction({ id: 'account-tool-model', label: 'Tool LLM model', detail: 'Set the model for dedicated tool LLM calls.', key: 'tools.llmModel', visibleWhenKey: 'tools.llmEnabled', visibleWhenValue: true }),
88
- settingAction({ id: 'account-tts-llm-provider', label: 'Spoken-turn provider', detail: 'Set an optional provider override for spoken-response turns.', key: 'tts.llmProvider' }),
89
- settingAction({ id: 'account-tts-llm-model', label: 'Spoken-turn model', detail: 'Set an optional model override for spoken-response turns.', key: 'tts.llmModel' }),
75
+ { id: 'account-tool-provider', label: 'Choose tool provider/model', detail: 'Open the shared provider/model picker for dedicated tool LLM calls.', kind: 'model-picker', modelPickerFlow: 'providerModel', modelPickerTarget: 'tool', visibleWhenSettingKey: 'tools.llmEnabled', visibleWhenSettingValue: true, safety: 'safe' },
76
+ { id: 'account-tool-model', label: 'Choose tool model', detail: 'Open the shared model picker for dedicated tool LLM calls.', kind: 'model-picker', modelPickerFlow: 'model', modelPickerTarget: 'tool', visibleWhenSettingKey: 'tools.llmEnabled', visibleWhenSettingValue: true, safety: 'safe' },
77
+ { id: 'account-tts-llm-provider', label: 'Choose spoken-turn provider/model', detail: 'Open the shared provider/model picker for spoken-response turns.', kind: 'model-picker', modelPickerFlow: 'providerModel', modelPickerTarget: 'tts', safety: 'safe' },
78
+ { id: 'account-tts-llm-model', label: 'Choose spoken-turn model', detail: 'Open the shared model picker for spoken-response turns.', kind: 'model-picker', modelPickerFlow: 'model', modelPickerTarget: 'tts', safety: 'safe' },
79
+ settingAction({ id: 'account-provider-fallback-hint', label: 'Provider failure hints', detail: 'Toggle alternative model suggestions when the current provider fails non-transiently.', key: 'behavior.suggestAlternativeOnProviderFail' }),
80
+ settingAction({ id: 'account-cache-enabled', label: 'Prompt cache', detail: 'Toggle prompt caching for eligible providers.', key: 'cache.enabled' }),
81
+ settingAction({ id: 'account-cache-ttl', label: 'Cache TTL', detail: 'Cycle ephemeral or persistent cache TTL for stable content.', key: 'cache.stableTtl', visibleWhenKey: 'cache.enabled', visibleWhenValue: true }),
82
+ settingAction({ id: 'account-cache-monitor', label: 'Cache hit-rate monitor', detail: 'Toggle cache hit-rate monitoring.', key: 'cache.monitorHitRate', visibleWhenKey: 'cache.enabled', visibleWhenValue: true }),
83
+ settingAction({ id: 'account-cache-threshold', label: 'Cache warning threshold', detail: 'Set the cache hit-rate warning threshold.', key: 'cache.hitRateWarningThreshold', visibleWhenKey: 'cache.monitorHitRate', visibleWhenValue: true }),
90
84
  ],
91
85
  },
92
86
  {
93
87
  id: 'assistant-behavior',
94
88
  group: 'ONBOARDING',
95
- label: 'Assistant Behavior',
96
- summary: 'Interaction, context, notifications, and reasoning display.',
97
- detail: 'Use this page to decide how much the assistant talks while it works and how it handles context pressure.',
89
+ label: 'Behavior',
90
+ summary: 'Set interaction style, context pressure behavior, and visible reasoning.',
91
+ detail: 'Use this to choose how chat feels during normal work and long-running tasks.',
98
92
  actions: [
99
93
  settingAction({ id: 'behavior-hitl-mode', label: 'Interaction mode', detail: 'Cycle quiet, balanced, or operator interaction mode.', key: 'behavior.hitlMode' }),
100
94
  settingAction({ id: 'behavior-guidance-mode', label: 'Guidance mode', detail: 'Cycle off, minimal, or guided operational guidance.', key: 'behavior.guidanceMode' }),
@@ -110,28 +104,41 @@ export const AGENT_WORKSPACE_CATEGORIES: readonly AgentWorkspaceCategory[] = [
110
104
  id: 'tools-permissions',
111
105
  group: 'ONBOARDING',
112
106
  label: 'Tools & Permissions',
113
- summary: 'Tool approval policy, MCP trust entry points, and secret handling.',
114
- detail: 'Use this page to set how Agent asks before file, shell, network, MCP, workflow, and delegation operations.',
107
+ summary: 'Set approval policy, MCP entry points, and secret references.',
108
+ detail: 'Use this before enabling tool-heavy work. Permission rows write policy; MCP and secret rows open setup forms.',
115
109
  actions: [
116
110
  settingAction({ id: 'permissions-mode', label: 'Permission mode', detail: 'Cycle prompt, allow-all, or custom permission mode.', key: 'permissions.mode' }),
111
+ settingAction({ id: 'permissions-auto-approve', label: 'Auto-approve tools', detail: 'Toggle automatic approval for all tool permission requests.', key: 'behavior.autoApprove' }),
112
+ settingAction({ id: 'permissions-read', label: 'File reads', detail: 'Cycle allow, prompt, or deny for file read operations.', key: 'permissions.tools.read' }),
113
+ settingAction({ id: 'permissions-find', label: 'File search', detail: 'Cycle allow, prompt, or deny for file and directory search operations.', key: 'permissions.tools.find' }),
117
114
  settingAction({ id: 'permissions-write', label: 'File writes', detail: 'Cycle allow, prompt, or deny for file write operations.', key: 'permissions.tools.write' }),
118
115
  settingAction({ id: 'permissions-edit', label: 'File edits', detail: 'Cycle allow, prompt, or deny for edit and patch operations.', key: 'permissions.tools.edit' }),
119
116
  settingAction({ id: 'permissions-exec', label: 'Shell commands', detail: 'Cycle allow, prompt, or deny for shell execution.', key: 'permissions.tools.exec' }),
120
117
  settingAction({ id: 'permissions-fetch', label: 'Network fetches', detail: 'Cycle allow, prompt, or deny for outbound fetch requests.', key: 'permissions.tools.fetch' }),
118
+ settingAction({ id: 'permissions-analyze', label: 'Code analysis', detail: 'Cycle allow, prompt, or deny for code and project analysis operations.', key: 'permissions.tools.analyze' }),
119
+ settingAction({ id: 'permissions-inspect', label: 'Runtime inspect', detail: 'Cycle allow, prompt, or deny for runtime state inspection.', key: 'permissions.tools.inspect' }),
120
+ settingAction({ id: 'permissions-state', label: 'State reads', detail: 'Cycle allow, prompt, or deny for reading runtime and session state.', key: 'permissions.tools.state' }),
121
+ settingAction({ id: 'permissions-registry', label: 'Registry reads', detail: 'Cycle allow, prompt, or deny for tool and skill registry queries.', key: 'permissions.tools.registry' }),
121
122
  settingAction({ id: 'permissions-mcp', label: 'MCP tools', detail: 'Cycle allow, prompt, or deny for external MCP tool calls.', key: 'permissions.tools.mcp' }),
122
123
  settingAction({ id: 'permissions-agent', label: 'Agent delegation', detail: 'Cycle allow, prompt, or deny for subagent and delegation operations.', key: 'permissions.tools.agent' }),
123
124
  settingAction({ id: 'permissions-workflow', label: 'Workflow automation', detail: 'Cycle allow, prompt, or deny for multi-step workflow automation.', key: 'permissions.tools.workflow' }),
125
+ settingAction({ id: 'permissions-delegate', label: 'Unknown tools', detail: 'Cycle allow, prompt, or deny for unknown or unregistered tools.', key: 'permissions.tools.delegate' }),
124
126
  { id: 'onboarding-mcp-server', label: 'Add MCP server', detail: 'Add or update one MCP server with command, args, role, trust, env refs, paths, and hosts.', editorKind: 'mcp-server', kind: 'editor', safety: 'safe' },
125
127
  { id: 'onboarding-secret-link', label: 'Link secret reference', detail: 'Link one config key to a goodvibes secret reference.', editorKind: 'secret-link', kind: 'editor', safety: 'safe' },
126
128
  { id: 'onboarding-secret-test', label: 'Test secret reference', detail: 'Check one stored secret reference without printing the value.', editorKind: 'secret-test', kind: 'editor', safety: 'safe' },
129
+ settingAction({ id: 'tools-auto-heal', label: 'Tool auto-heal', detail: 'Toggle automatic syntax repair for precision write and edit operations.', key: 'tools.autoHeal' }),
130
+ settingAction({ id: 'tools-token-budget', label: 'Tool token budget', detail: 'Set the default token budget for precision read operations.', key: 'tools.defaultTokenBudget' }),
131
+ settingAction({ id: 'tools-hooks-file', label: 'Hooks file', detail: 'Set the hook configuration file name relative to host data.', key: 'tools.hooksFile' }),
132
+ settingAction({ id: 'storage-artifact-limit', label: 'Artifact storage limit', detail: 'Set the maximum artifact size for file, URL, multipart, and raw upload ingest.', key: 'storage.artifacts.maxBytes' }),
133
+ settingAction({ id: 'telemetry-raw-prompts', label: 'Raw prompt telemetry', detail: 'Toggle raw prompt and response telemetry; leave off unless debugging locally.', key: 'telemetry.includeRawPrompts' }),
127
134
  ],
128
135
  },
129
136
  {
130
137
  id: 'onboarding-display',
131
138
  group: 'ONBOARDING',
132
139
  label: 'Interface',
133
- summary: 'Display, streaming, operational messages, and release channel.',
134
- detail: 'Use this page to make the terminal readable for normal daily work.',
140
+ summary: 'Display, streaming, message placement, and release channel.',
141
+ detail: 'Use this page to make the terminal readable for daily operation.',
135
142
  actions: [
136
143
  settingAction({ id: 'display-stream', label: 'Stream tokens', detail: 'Toggle streaming assistant tokens as they arrive.', key: 'display.stream' }),
137
144
  settingAction({ id: 'display-theme', label: 'Theme', detail: 'Set the color theme name.', key: 'display.theme' }),
@@ -148,18 +155,20 @@ export const AGENT_WORKSPACE_CATEGORIES: readonly AgentWorkspaceCategory[] = [
148
155
  id: 'onboarding-channels',
149
156
  group: 'ONBOARDING',
150
157
  label: 'Messaging',
151
- summary: 'Messaging surfaces and settings for enabled channels.',
152
- detail: 'Start by enabling the channels you want. Channel-specific fields appear below each enabled channel.',
158
+ summary: 'Choose remote channels, then fill only the fields for enabled channels.',
159
+ detail: 'Enable the channels you actually want. Channel credentials and default targets are saved as Agent settings or secret refs.',
153
160
  actions: [
154
- { id: 'onboarding-pair-companion', label: 'Pair companion app', detail: 'Open the QR pairing view for companion access.', command: '/pair', kind: 'command', safety: 'safe' },
155
161
  settingAction({ id: 'channel-ntfy-enabled', label: 'Use ntfy', detail: 'Toggle ntfy notifications and chat routing.', key: 'surfaces.ntfy.enabled' }),
156
162
  settingAction({ id: 'channel-ntfy-base-url', label: 'ntfy base URL', detail: 'Set the ntfy server URL.', key: 'surfaces.ntfy.baseUrl', visibleWhenKey: 'surfaces.ntfy.enabled', visibleWhenValue: true }),
157
163
  settingAction({ id: 'channel-ntfy-chat-topic', label: 'ntfy chat topic', detail: 'Set the topic routed into active terminal chat.', key: 'surfaces.ntfy.chatTopic', visibleWhenKey: 'surfaces.ntfy.enabled', visibleWhenValue: true }),
158
164
  settingAction({ id: 'channel-ntfy-agent-topic', label: 'ntfy agent topic', detail: 'Set the topic routed to Agent work.', key: 'surfaces.ntfy.agentTopic', visibleWhenKey: 'surfaces.ntfy.enabled', visibleWhenValue: true }),
165
+ settingAction({ id: 'channel-ntfy-default-topic', label: 'ntfy default topic', detail: 'Set the default outbound notification topic.', key: 'surfaces.ntfy.topic', visibleWhenKey: 'surfaces.ntfy.enabled', visibleWhenValue: true }),
166
+ settingAction({ id: 'channel-ntfy-remote-topic', label: 'ntfy remote topic', detail: 'Set the daemon-owned remote chat topic.', key: 'surfaces.ntfy.remoteTopic', visibleWhenKey: 'surfaces.ntfy.enabled', visibleWhenValue: true }),
159
167
  settingAction({ id: 'channel-ntfy-token', label: 'ntfy token', detail: 'Store the ntfy access token or secret reference.', key: 'surfaces.ntfy.token', visibleWhenKey: 'surfaces.ntfy.enabled', visibleWhenValue: true }),
160
168
  settingAction({ id: 'channel-ntfy-priority', label: 'ntfy priority', detail: 'Set default ntfy priority from 1 to 5.', key: 'surfaces.ntfy.defaultPriority', visibleWhenKey: 'surfaces.ntfy.enabled', visibleWhenValue: true }),
161
169
  settingAction({ id: 'channel-slack-enabled', label: 'Use Slack', detail: 'Toggle Slack adapter configuration.', key: 'surfaces.slack.enabled' }),
162
170
  settingAction({ id: 'channel-slack-bot-token', label: 'Slack bot token', detail: 'Store the Slack bot token or secret reference.', key: 'surfaces.slack.botToken', visibleWhenKey: 'surfaces.slack.enabled', visibleWhenValue: true }),
171
+ settingAction({ id: 'channel-slack-app-token', label: 'Slack app token', detail: 'Store the Slack app token or secret reference.', key: 'surfaces.slack.appToken', visibleWhenKey: 'surfaces.slack.enabled', visibleWhenValue: true }),
163
172
  settingAction({ id: 'channel-slack-signing-secret', label: 'Slack signing secret', detail: 'Store the Slack signing secret or secret reference.', key: 'surfaces.slack.signingSecret', visibleWhenKey: 'surfaces.slack.enabled', visibleWhenValue: true }),
164
173
  settingAction({ id: 'channel-slack-default-channel', label: 'Slack default channel', detail: 'Set the default Slack channel for notifications and replies.', key: 'surfaces.slack.defaultChannel', visibleWhenKey: 'surfaces.slack.enabled', visibleWhenValue: true }),
165
174
  settingAction({ id: 'channel-slack-workspace', label: 'Slack workspace ID', detail: 'Set the Slack workspace id for route binding.', key: 'surfaces.slack.workspaceId', visibleWhenKey: 'surfaces.slack.enabled', visibleWhenValue: true }),
@@ -167,49 +176,67 @@ export const AGENT_WORKSPACE_CATEGORIES: readonly AgentWorkspaceCategory[] = [
167
176
  settingAction({ id: 'channel-discord-bot-token', label: 'Discord bot token', detail: 'Store the Discord bot token or secret reference.', key: 'surfaces.discord.botToken', visibleWhenKey: 'surfaces.discord.enabled', visibleWhenValue: true }),
168
177
  settingAction({ id: 'channel-discord-application', label: 'Discord application ID', detail: 'Set the Discord application id.', key: 'surfaces.discord.applicationId', visibleWhenKey: 'surfaces.discord.enabled', visibleWhenValue: true }),
169
178
  settingAction({ id: 'channel-discord-public-key', label: 'Discord public key', detail: 'Set the Discord application public key.', key: 'surfaces.discord.publicKey', visibleWhenKey: 'surfaces.discord.enabled', visibleWhenValue: true }),
179
+ settingAction({ id: 'channel-discord-guild', label: 'Discord guild ID', detail: 'Set the default Discord guild id.', key: 'surfaces.discord.guildId', visibleWhenKey: 'surfaces.discord.enabled', visibleWhenValue: true }),
170
180
  settingAction({ id: 'channel-discord-default-channel', label: 'Discord default channel', detail: 'Set the default Discord channel id.', key: 'surfaces.discord.defaultChannelId', visibleWhenKey: 'surfaces.discord.enabled', visibleWhenValue: true }),
171
181
  settingAction({ id: 'channel-webhook-enabled', label: 'Use webhooks', detail: 'Toggle generic webhook delivery.', key: 'surfaces.webhook.enabled' }),
172
182
  settingAction({ id: 'channel-webhook-target', label: 'Webhook target URL', detail: 'Set the default outbound webhook target URL.', key: 'surfaces.webhook.defaultTarget', visibleWhenKey: 'surfaces.webhook.enabled', visibleWhenValue: true }),
173
183
  settingAction({ id: 'channel-webhook-secret', label: 'Webhook secret', detail: 'Store the shared webhook secret or secret reference.', key: 'surfaces.webhook.secret', visibleWhenKey: 'surfaces.webhook.enabled', visibleWhenValue: true }),
184
+ settingAction({ id: 'channel-webhook-timeout', label: 'Webhook timeout', detail: 'Set outbound webhook timeout in milliseconds.', key: 'surfaces.webhook.timeoutMs', visibleWhenKey: 'surfaces.webhook.enabled', visibleWhenValue: true }),
174
185
  settingAction({ id: 'channel-telegram-enabled', label: 'Use Telegram', detail: 'Toggle Telegram bot delivery.', key: 'surfaces.telegram.enabled' }),
175
186
  settingAction({ id: 'channel-telegram-bot-token', label: 'Telegram bot token', detail: 'Store the Telegram bot token or secret reference.', key: 'surfaces.telegram.botToken', visibleWhenKey: 'surfaces.telegram.enabled', visibleWhenValue: true }),
187
+ settingAction({ id: 'channel-telegram-bot-username', label: 'Telegram bot username', detail: 'Set the Telegram bot username.', key: 'surfaces.telegram.botUsername', visibleWhenKey: 'surfaces.telegram.enabled', visibleWhenValue: true }),
176
188
  settingAction({ id: 'channel-telegram-chat', label: 'Telegram chat ID', detail: 'Set the default Telegram chat, group, or channel id.', key: 'surfaces.telegram.defaultChatId', visibleWhenKey: 'surfaces.telegram.enabled', visibleWhenValue: true }),
177
189
  settingAction({ id: 'channel-telegram-mode', label: 'Telegram mode', detail: 'Cycle webhook or polling ingress mode.', key: 'surfaces.telegram.mode', visibleWhenKey: 'surfaces.telegram.enabled', visibleWhenValue: true }),
190
+ settingAction({ id: 'channel-telegram-webhook-secret', label: 'Telegram webhook secret', detail: 'Store the Telegram webhook secret or secret reference.', key: 'surfaces.telegram.webhookSecret', visibleWhenKey: 'surfaces.telegram.enabled', visibleWhenValue: true }),
178
191
  settingAction({ id: 'channel-googlechat-enabled', label: 'Use Google Chat', detail: 'Toggle Google Chat delivery.', key: 'surfaces.googleChat.enabled' }),
179
192
  settingAction({ id: 'channel-googlechat-webhook', label: 'Google Chat webhook', detail: 'Set the Google Chat webhook or app callback URL.', key: 'surfaces.googleChat.webhookUrl', visibleWhenKey: 'surfaces.googleChat.enabled', visibleWhenValue: true }),
193
+ settingAction({ id: 'channel-googlechat-space', label: 'Google Chat space', detail: 'Set the default Google Chat space id.', key: 'surfaces.googleChat.spaceId', visibleWhenKey: 'surfaces.googleChat.enabled', visibleWhenValue: true }),
194
+ settingAction({ id: 'channel-googlechat-app-id', label: 'Google Chat app ID', detail: 'Set the Google Chat app id.', key: 'surfaces.googleChat.appId', visibleWhenKey: 'surfaces.googleChat.enabled', visibleWhenValue: true }),
195
+ settingAction({ id: 'channel-googlechat-verification', label: 'Google Chat verification', detail: 'Store the Google Chat verification token or secret reference.', key: 'surfaces.googleChat.verificationToken', visibleWhenKey: 'surfaces.googleChat.enabled', visibleWhenValue: true }),
180
196
  settingAction({ id: 'channel-homeassistant-enabled', label: 'Use home automation', detail: 'Toggle home automation conversation and event delivery.', key: 'surfaces.homeassistant.enabled' }),
181
197
  settingAction({ id: 'channel-homeassistant-url', label: 'Home automation URL', detail: 'Set the home automation instance URL.', key: 'surfaces.homeassistant.instanceUrl', visibleWhenKey: 'surfaces.homeassistant.enabled', visibleWhenValue: true }),
182
198
  settingAction({ id: 'channel-homeassistant-token', label: 'Home automation token', detail: 'Store the home automation access token or secret reference.', key: 'surfaces.homeassistant.accessToken', visibleWhenKey: 'surfaces.homeassistant.enabled', visibleWhenValue: true }),
199
+ settingAction({ id: 'channel-homeassistant-webhook-secret', label: 'Home automation webhook secret', detail: 'Store the shared secret used to verify inbound callbacks.', key: 'surfaces.homeassistant.webhookSecret', visibleWhenKey: 'surfaces.homeassistant.enabled', visibleWhenValue: true }),
200
+ settingAction({ id: 'channel-homeassistant-conversation', label: 'Home automation conversation', detail: 'Set the default conversation id.', key: 'surfaces.homeassistant.defaultConversationId', visibleWhenKey: 'surfaces.homeassistant.enabled', visibleWhenValue: true }),
201
+ settingAction({ id: 'channel-homeassistant-device-id', label: 'Home automation device ID', detail: 'Set the stable device id exposed to the home automation surface.', key: 'surfaces.homeassistant.deviceId', visibleWhenKey: 'surfaces.homeassistant.enabled', visibleWhenValue: true }),
202
+ settingAction({ id: 'channel-homeassistant-device-name', label: 'Home automation device name', detail: 'Set the device display name exposed to the home automation surface.', key: 'surfaces.homeassistant.deviceName', visibleWhenKey: 'surfaces.homeassistant.enabled', visibleWhenValue: true }),
203
+ settingAction({ id: 'channel-homeassistant-event-type', label: 'Home automation event type', detail: 'Set the event type used for daemon-to-home automation delivery.', key: 'surfaces.homeassistant.eventType', visibleWhenKey: 'surfaces.homeassistant.enabled', visibleWhenValue: true }),
204
+ settingAction({ id: 'channel-homeassistant-session-ttl', label: 'Home automation session TTL', detail: 'Set the idle TTL for remote home automation conversation sessions.', key: 'surfaces.homeassistant.remoteSessionTtlMs', visibleWhenKey: 'surfaces.homeassistant.enabled', visibleWhenValue: true }),
183
205
  settingAction({ id: 'channel-signal-enabled', label: 'Use Signal', detail: 'Toggle Signal bridge delivery.', key: 'surfaces.signal.enabled' }),
184
206
  settingAction({ id: 'channel-signal-bridge', label: 'Signal bridge URL', detail: 'Set the Signal bridge base URL.', key: 'surfaces.signal.bridgeUrl', visibleWhenKey: 'surfaces.signal.enabled', visibleWhenValue: true }),
207
+ settingAction({ id: 'channel-signal-account', label: 'Signal account', detail: 'Set the Signal account id or phone number.', key: 'surfaces.signal.account', visibleWhenKey: 'surfaces.signal.enabled', visibleWhenValue: true }),
208
+ settingAction({ id: 'channel-signal-token', label: 'Signal token', detail: 'Store the Signal bridge token or secret reference.', key: 'surfaces.signal.token', visibleWhenKey: 'surfaces.signal.enabled', visibleWhenValue: true }),
185
209
  settingAction({ id: 'channel-signal-recipient', label: 'Signal recipient', detail: 'Set the default Signal recipient or group.', key: 'surfaces.signal.defaultRecipient', visibleWhenKey: 'surfaces.signal.enabled', visibleWhenValue: true }),
186
210
  settingAction({ id: 'channel-whatsapp-enabled', label: 'Use WhatsApp', detail: 'Toggle WhatsApp delivery.', key: 'surfaces.whatsapp.enabled' }),
187
211
  settingAction({ id: 'channel-whatsapp-provider', label: 'WhatsApp provider', detail: 'Cycle Meta Cloud API or bridge provider mode.', key: 'surfaces.whatsapp.provider', visibleWhenKey: 'surfaces.whatsapp.enabled', visibleWhenValue: true }),
188
212
  settingAction({ id: 'channel-whatsapp-token', label: 'WhatsApp access token', detail: 'Store the WhatsApp provider access token or secret reference.', key: 'surfaces.whatsapp.accessToken', visibleWhenKey: 'surfaces.whatsapp.enabled', visibleWhenValue: true }),
213
+ settingAction({ id: 'channel-whatsapp-phone-id', label: 'WhatsApp phone number ID', detail: 'Set the WhatsApp phone number id.', key: 'surfaces.whatsapp.phoneNumberId', visibleWhenKey: 'surfaces.whatsapp.enabled', visibleWhenValue: true }),
214
+ settingAction({ id: 'channel-whatsapp-business-id', label: 'WhatsApp business ID', detail: 'Set the WhatsApp business account id.', key: 'surfaces.whatsapp.businessAccountId', visibleWhenKey: 'surfaces.whatsapp.enabled', visibleWhenValue: true }),
215
+ settingAction({ id: 'channel-whatsapp-verify', label: 'WhatsApp verify token', detail: 'Store the WhatsApp verify token or secret reference.', key: 'surfaces.whatsapp.verifyToken', visibleWhenKey: 'surfaces.whatsapp.enabled', visibleWhenValue: true }),
216
+ settingAction({ id: 'channel-whatsapp-signing', label: 'WhatsApp signing secret', detail: 'Store the WhatsApp signing secret or secret reference.', key: 'surfaces.whatsapp.signingSecret', visibleWhenKey: 'surfaces.whatsapp.enabled', visibleWhenValue: true }),
189
217
  settingAction({ id: 'channel-whatsapp-recipient', label: 'WhatsApp recipient', detail: 'Set the default WhatsApp recipient or chat id.', key: 'surfaces.whatsapp.defaultRecipient', visibleWhenKey: 'surfaces.whatsapp.enabled', visibleWhenValue: true }),
190
218
  settingAction({ id: 'channel-imessage-enabled', label: 'Use iMessage', detail: 'Toggle iMessage bridge delivery.', key: 'surfaces.imessage.enabled' }),
191
219
  settingAction({ id: 'channel-imessage-bridge', label: 'iMessage bridge URL', detail: 'Set the iMessage bridge base URL.', key: 'surfaces.imessage.bridgeUrl', visibleWhenKey: 'surfaces.imessage.enabled', visibleWhenValue: true }),
220
+ settingAction({ id: 'channel-imessage-account', label: 'iMessage account', detail: 'Set the iMessage account id.', key: 'surfaces.imessage.account', visibleWhenKey: 'surfaces.imessage.enabled', visibleWhenValue: true }),
221
+ settingAction({ id: 'channel-imessage-token', label: 'iMessage token', detail: 'Store the iMessage bridge token or secret reference.', key: 'surfaces.imessage.token', visibleWhenKey: 'surfaces.imessage.enabled', visibleWhenValue: true }),
192
222
  settingAction({ id: 'channel-imessage-chat', label: 'iMessage chat ID', detail: 'Set the default iMessage chat id.', key: 'surfaces.imessage.defaultChatId', visibleWhenKey: 'surfaces.imessage.enabled', visibleWhenValue: true }),
193
- { id: 'onboarding-notify-webhook', label: 'Add notification webhook', detail: 'Add one webhook target for explicit reminder and routine delivery.', editorKind: 'notify-webhook', kind: 'editor', safety: 'safe' },
194
- { id: 'onboarding-test-webhook', label: 'Test notification webhooks', detail: 'Send one confirmed test notification to configured webhook targets.', editorKind: 'notify-webhook-test', kind: 'editor', safety: 'safe' },
195
223
  ],
196
224
  },
197
225
  {
198
226
  id: 'onboarding-voice-media',
199
227
  group: 'ONBOARDING',
200
228
  label: 'Voice & Phone',
201
- summary: 'Configure spoken replies, TTS routing, media prompts, and telephony.',
202
- detail: 'Use this page for local voice, spoken-output defaults, image/media prompts, and SMS or phone-call delivery.',
229
+ summary: 'Configure voice controls, spoken output, and SMS or phone-call delivery.',
230
+ detail: 'Use this page for saved voice/TTS settings and telephony credentials. Generating media is available later from Voice & Media.',
203
231
  actions: [
204
232
  settingAction({ id: 'voice-enabled', label: 'Use voice controls', detail: 'Toggle the optional local voice control surface.', key: 'ui.voiceEnabled' }),
205
233
  settingAction({ id: 'voice-tts-provider', label: 'TTS provider', detail: 'Set the default text-to-speech provider id.', key: 'tts.provider' }),
206
234
  settingAction({ id: 'voice-tts-voice', label: 'TTS voice', detail: 'Set the default text-to-speech voice id.', key: 'tts.voice' }),
207
- { id: 'voice-speak-prompt', label: 'Try spoken prompt', detail: 'Open a prompt form for a spoken assistant reply through configured TTS.', editorKind: 'tts-prompt', kind: 'editor', safety: 'safe' },
208
- { id: 'media-attach-image', label: 'Attach image', detail: 'Attach a local image path and optional prompt to the next assistant turn.', editorKind: 'image-input', kind: 'editor', safety: 'safe' },
209
- { id: 'onboarding-media-generate', label: 'Generate media', detail: 'Generate image or video artifacts through a configured media provider after confirmation.', editorKind: 'media-generate', kind: 'editor', safety: 'safe' },
210
235
  settingAction({ id: 'telephony-enabled', label: 'Use telephony', detail: 'Toggle SMS, voice call, or telephony bridge delivery.', key: 'surfaces.telephony.enabled' }),
211
236
  settingAction({ id: 'telephony-provider', label: 'Telephony provider', detail: 'Cycle direct provider or bridge mode.', key: 'surfaces.telephony.provider', visibleWhenKey: 'surfaces.telephony.enabled', visibleWhenValue: true }),
212
237
  settingAction({ id: 'telephony-mode', label: 'Telephony mode', detail: 'Cycle SMS, voice call, or bridge delivery mode.', key: 'surfaces.telephony.mode', visibleWhenKey: 'surfaces.telephony.enabled', visibleWhenValue: true }),
238
+ settingAction({ id: 'telephony-bridge-url', label: 'Telephony bridge URL', detail: 'Set the telephony bridge base URL.', key: 'surfaces.telephony.bridgeUrl', visibleWhenKey: 'surfaces.telephony.enabled', visibleWhenValue: true }),
239
+ settingAction({ id: 'telephony-token', label: 'Telephony bridge token', detail: 'Store the telephony bridge token or secret reference.', key: 'surfaces.telephony.token', visibleWhenKey: 'surfaces.telephony.enabled', visibleWhenValue: true }),
213
240
  settingAction({ id: 'telephony-account-sid', label: 'Twilio account SID', detail: 'Set the Twilio account SID for provider-direct delivery.', key: 'surfaces.telephony.accountSid', visibleWhenKey: 'surfaces.telephony.enabled', visibleWhenValue: true }),
214
241
  settingAction({ id: 'telephony-auth-token', label: 'Twilio auth token', detail: 'Store the Twilio auth token or secret reference.', key: 'surfaces.telephony.authToken', visibleWhenKey: 'surfaces.telephony.enabled', visibleWhenValue: true }),
215
242
  settingAction({ id: 'telephony-from', label: 'Sender phone number', detail: 'Set the default caller or sender phone number.', key: 'surfaces.telephony.fromNumber', visibleWhenKey: 'surfaces.telephony.enabled', visibleWhenValue: true }),
@@ -221,9 +248,9 @@ export const AGENT_WORKSPACE_CATEGORIES: readonly AgentWorkspaceCategory[] = [
221
248
  {
222
249
  id: 'onboarding-context',
223
250
  group: 'ONBOARDING',
224
- label: 'Context',
225
- summary: 'Local persona, memory, skills, routines, notes, and Agent Knowledge.',
226
- detail: 'Use this page to make the assistant useful with durable local context and source-backed knowledge.',
251
+ label: 'Local Context',
252
+ summary: 'Create/import memory, personas, skills, routines, notes, and Knowledge.',
253
+ detail: 'Use this page to seed the assistant with durable local context. These forms create Agent-owned records or ingest reviewed sources.',
227
254
  actions: [
228
255
  { id: 'context-profile-from-discovered', label: 'Profile from discovered files', detail: 'Create an isolated Agent profile from reviewed local persona, skill, and routine files.', editorKind: 'profile-from-discovered', kind: 'editor', safety: 'safe' },
229
256
  { id: 'context-persona-discovery', label: 'Import persona files', detail: 'Import discovered persona files into the Agent persona registry.', editorKind: 'persona-discovery-import', kind: 'editor', safety: 'safe' },
@@ -241,20 +268,19 @@ export const AGENT_WORKSPACE_CATEGORIES: readonly AgentWorkspaceCategory[] = [
241
268
  ],
242
269
  },
243
270
  {
244
- id: 'onboarding-verify',
271
+ id: 'onboarding-automation',
245
272
  group: 'ONBOARDING',
246
- label: 'Verify',
247
- summary: 'Review the configured runtime before finishing onboarding.',
248
- detail: 'Use this page to inspect health, model/provider state, channels, MCP, and knowledge before applying the completion marker.',
273
+ label: 'Automation Setup',
274
+ summary: 'Set scheduled work limits for reminders and routines.',
275
+ detail: 'Use this page to enable automation and set bounded run limits. Creating actual reminders and routines remains a separate confirmed action.',
249
276
  actions: [
250
- { id: 'verify-brief', label: 'Operator briefing', detail: 'Show a concise status and next-action briefing.', command: '/brief', kind: 'command', safety: 'read-only' },
251
- { id: 'verify-health', label: 'Health review', detail: 'Review local runtime and connected-host status.', command: '/health review', kind: 'command', safety: 'read-only' },
252
- { id: 'verify-compat', label: 'Compatibility', detail: 'Inspect connected-host compatibility and Agent Knowledge route readiness.', command: '/compat', kind: 'command', safety: 'read-only' },
253
- { id: 'verify-provider', label: 'Provider status', detail: 'Inspect provider/model routing state.', command: '/provider', kind: 'command', safety: 'read-only' },
254
- { id: 'verify-subscription', label: 'Subscription status', detail: 'Inspect active and pending provider subscription sessions.', command: '/subscription review', kind: 'command', safety: 'read-only' },
255
- { id: 'verify-channels', label: 'Channel readiness', detail: 'Inspect channel readiness and enabled-channel attention items.', command: '/channels attention', kind: 'command', safety: 'read-only' },
256
- { id: 'verify-mcp', label: 'MCP review', detail: 'Inspect MCP server connection, role, trust, and quarantine posture.', command: '/mcp review', kind: 'command', safety: 'read-only' },
257
- { id: 'verify-knowledge', label: 'Knowledge status', detail: 'Inspect isolated Agent Knowledge readiness and counts.', command: '/knowledge status', kind: 'command', safety: 'read-only' },
277
+ settingAction({ id: 'automation-enabled', label: 'Use automation', detail: 'Toggle the automation subsystem for reminders and scheduled routines.', key: 'automation.enabled' }),
278
+ settingAction({ id: 'automation-max-concurrent', label: 'Concurrent runs', detail: 'Set the maximum automation runs that can execute concurrently.', key: 'automation.maxConcurrentRuns', visibleWhenKey: 'automation.enabled', visibleWhenValue: true }),
279
+ settingAction({ id: 'automation-history-limit', label: 'Run history limit', detail: 'Set the number of run history entries retained per automation job.', key: 'automation.runHistoryLimit', visibleWhenKey: 'automation.enabled', visibleWhenValue: true }),
280
+ settingAction({ id: 'automation-default-timeout', label: 'Default timeout', detail: 'Set the default automation run timeout in milliseconds.', key: 'automation.defaultTimeoutMs', visibleWhenKey: 'automation.enabled', visibleWhenValue: true }),
281
+ settingAction({ id: 'automation-catch-up', label: 'Catch-up window', detail: 'Set how long startup should catch up missed automation runs.', key: 'automation.catchUpWindowMinutes', visibleWhenKey: 'automation.enabled', visibleWhenValue: true }),
282
+ settingAction({ id: 'automation-failure-cooldown', label: 'Failure cooldown', detail: 'Set the cooldown after a failed automation run.', key: 'automation.failureCooldownMs', visibleWhenKey: 'automation.enabled', visibleWhenValue: true }),
283
+ settingAction({ id: 'automation-delete-after-run', label: 'Delete one-shot jobs', detail: 'Toggle deleting one-shot automation jobs after their first successful run.', key: 'automation.deleteAfterRun', visibleWhenKey: 'automation.enabled', visibleWhenValue: true }),
258
284
  ],
259
285
  },
260
286
  {
@@ -690,52 +716,7 @@ export const AGENT_WORKSPACE_CATEGORIES: readonly AgentWorkspaceCategory[] = [
690
716
  { id: 'approval-cancel', label: 'Cancel request', detail: 'Open a confirmed form for cancelling one pending connected-host approval request by id.', editorKind: 'approval-cancel', kind: 'editor', safety: 'safe' },
691
717
  ],
692
718
  },
693
- {
694
- id: 'host',
695
- group: 'OPERATIONS',
696
- label: 'Connected Host',
697
- summary: 'Connected-host health, tasks, sessions, channels, and automation.',
698
- detail: 'Use this workspace to inspect the GoodVibes host surfaces that Agent can see: system health, remote routes, host tasks, sessions, channels, schedules, knowledge, media, MCP, provider auth, support bundles, and telemetry/config posture.',
699
- actions: [
700
- { id: 'host-overview', label: 'Host overview', detail: 'Review connected-host, provider, settings, continuity, and Agent health without starting or mutating host work.', command: '/health review', kind: 'command', safety: 'read-only' },
701
- { id: 'host-services', label: 'Host services', detail: 'Inspect connected-host service readiness, credentials, and integration issues without changing them.', command: '/health host', kind: 'command', safety: 'read-only' },
702
- { id: 'host-setup', label: 'Setup review', detail: 'Inspect setup issues that affect connected-host and Agent runtime readiness.', command: '/health setup', kind: 'command', safety: 'read-only' },
703
- { id: 'host-remote', label: 'Remote routes', detail: 'Inspect remote build-host route health and recovery signals without starting build work.', command: '/health remote', kind: 'command', safety: 'read-only' },
704
- { id: 'host-maintenance', label: 'Session maintenance', detail: 'Review continuity, compaction, and current-session maintenance posture.', command: '/health maintenance', kind: 'command', safety: 'read-only' },
705
- { id: 'host-continuity', label: 'Continuity', detail: 'Inspect last-session pointer, recovery-file posture, and return-context state.', command: '/health continuity', kind: 'command', safety: 'read-only' },
706
- { id: 'host-tasks', label: 'Host tasks', detail: 'Inspect connected-host task state without creating, retrying, or mutating tasks.', command: '/tasks list', kind: 'command', safety: 'read-only' },
707
- { id: 'host-task-filter', label: 'Filter host tasks', detail: 'Open a status/type form for read-only connected-host task filtering.', editorKind: 'task-list-filter', kind: 'editor', safety: 'read-only' },
708
- { id: 'host-task-show', label: 'Inspect host task', detail: 'Open a task-id form for read-only connected-host task metadata.', editorKind: 'task-show', kind: 'editor', safety: 'read-only' },
709
- { id: 'host-task-output', label: 'Show task output', detail: 'Open a task-id form for read-only connected-host task output.', editorKind: 'task-output', kind: 'editor', safety: 'read-only' },
710
- { id: 'host-sessions', label: 'Host session routes', detail: 'Browse saved Agent sessions and return-context posture exposed through the runtime session surface.', command: '/session list', kind: 'command', safety: 'read-only' },
711
- { id: 'host-session-graph', label: 'Session graph', detail: 'Open a read-only form for cross-session graph inspection; graph mutation remains blocked in Agent.', editorKind: 'session-graph', kind: 'editor', safety: 'read-only' },
712
- { id: 'host-channels-status', label: 'Channel status', detail: 'Inspect connected channel runtime status from the host without mutating delivery state.', command: '/channels status', kind: 'command', safety: 'read-only' },
713
- { id: 'host-channel-accounts', label: 'Channel accounts', detail: 'Inspect connected channel accounts without printing secret values or sending messages.', command: '/channels accounts', kind: 'command', safety: 'read-only' },
714
- { id: 'host-channel-policies', label: 'Channel policies', detail: 'Inspect channel delivery policy posture without changing routing.', command: '/channels policies', kind: 'command', safety: 'read-only' },
715
- { id: 'host-channels', label: 'Open Channels', detail: 'Jump to the channel setup and delivery workspace.', targetCategoryId: 'channels', kind: 'workspace', safety: 'safe' },
716
- { id: 'host-automation', label: 'Open Automation', detail: 'Jump to connected schedules, reminders, receipts, and explicit run controls.', targetCategoryId: 'automation', kind: 'workspace', safety: 'safe' },
717
- { id: 'host-schedules', label: 'Schedule status', detail: 'Inspect schedules and run history without running or mutating them.', command: '/schedule list', kind: 'command', safety: 'read-only' },
718
- { id: 'host-schedule-reconcile', label: 'Reconcile schedules', detail: 'Compare local promotion receipts with live connected schedules.', command: '/schedule reconcile', kind: 'command', safety: 'read-only' },
719
- { id: 'host-knowledge', label: 'Knowledge route', detail: 'Inspect isolated Agent Knowledge route readiness and source counts.', command: '/knowledge status', kind: 'command', safety: 'read-only' },
720
- { id: 'host-knowledge-open', label: 'Open Knowledge', detail: 'Jump to Agent Knowledge source, graph, review, and ingest controls.', targetCategoryId: 'knowledge', kind: 'workspace', safety: 'safe' },
721
- { id: 'host-media', label: 'Media providers', detail: 'Inspect configured media providers before generating media with confirmation.', command: '/media providers', kind: 'command', safety: 'read-only' },
722
- { id: 'host-media-open', label: 'Open Voice and Media', detail: 'Jump to voice, TTS, image input, media provider, and browser-tool setup actions.', targetCategoryId: 'voice-media', kind: 'workspace', safety: 'safe' },
723
- { id: 'host-mcp-health', label: 'MCP health', detail: 'Inspect MCP lifecycle issues without changing trust posture or approving tool-definition review.', command: '/health mcp', kind: 'command', safety: 'read-only' },
724
- { id: 'host-mcp-review', label: 'MCP review', detail: 'Inspect MCP server connection, trust, role, and review posture.', command: '/mcp review', kind: 'command', safety: 'read-only' },
725
- { id: 'host-tools-open', label: 'Open Tools and MCP', detail: 'Jump to MCP server setup, tool inventory, secrets, and security review.', targetCategoryId: 'tools', kind: 'workspace', safety: 'safe' },
726
- { id: 'host-provider-accounts', label: 'Provider accounts', detail: 'Review provider account routes, subscription windows, and billing-path safety.', command: '/accounts review', kind: 'command', safety: 'read-only' },
727
- { id: 'host-auth-owner', label: 'Connected-host auth owner', detail: 'Show that connected-host auth administration belongs to the owning GoodVibes host, not Agent.', command: '/auth local', kind: 'command', safety: 'read-only' },
728
- { id: 'host-auth-review', label: 'Provider auth review', detail: 'Review provider auth posture without printing token values.', command: '/auth review', kind: 'command', safety: 'read-only' },
729
- { id: 'host-security', label: 'Security review', detail: 'Inspect token posture, MCP attack paths, policy lint, plugin risk, and incident pressure.', command: '/security review', kind: 'command', safety: 'read-only' },
730
- { id: 'host-trust', label: 'Trust review', detail: 'Review permission, secret, plugin, and MCP trust posture without exporting bundles or changing trust.', command: '/trust review', kind: 'command', safety: 'read-only' },
731
- { id: 'host-support-bundle-export', label: 'Export support bundle', detail: 'Export a redacted Agent support bundle from the Host page.', editorKind: 'support-bundle-export', kind: 'editor', safety: 'safe' },
732
- { id: 'host-support-bundle-inspect', label: 'Inspect support bundle', detail: 'Inspect a support bundle before import or sharing.', editorKind: 'support-bundle-inspect', kind: 'editor', safety: 'read-only' },
733
- { id: 'host-support-bundle-import', label: 'Import support bundle', detail: 'Import reviewed, non-redacted config values from a support bundle.', editorKind: 'support-bundle-import', kind: 'editor', safety: 'safe' },
734
- { id: 'host-telemetry', label: 'Telemetry settings', detail: 'Open telemetry payload policy settings for connected-host and Agent observability review.', command: '/config telemetry', kind: 'command', safety: 'safe' },
735
- { id: 'host-config', label: 'Control-plane settings', detail: 'Open configuration controls for service, channels, tools, automation, provider, and storage posture.', command: '/config', kind: 'command', safety: 'safe' },
736
- { id: 'host-safety', label: 'Host mutation policy', detail: 'Agent may inspect connected-host surfaces and run explicit confirmed actions, but does not silently create tasks, send channel messages, mutate auth, or start automation.', kind: 'guidance', safety: 'blocked' },
737
- ],
738
- },
719
+ AGENT_WORKSPACE_HOST_CATEGORY,
739
720
  {
740
721
  id: 'automation',
741
722
  group: 'OPERATIONS',
@@ -792,7 +773,18 @@ export function renderAgentWorkspacePackageText(): string {
792
773
  lines.push(category.id, category.group, category.label, category.summary, category.detail);
793
774
  for (const action of category.actions) {
794
775
  lines.push(action.id, action.label, action.detail, action.kind);
795
- const extras = [action.command, action.targetCategoryId ? `target:${action.targetCategoryId}` : '', action.editorKind ? `editor:${action.editorKind}` : '', action.settingKey ? `setting:${action.settingKey}` : '', action.kind === 'settings-import' ? 'import:goodvibes-tui-settings' : '', action.localKind ? `local:${action.localKind}` : '', action.localOperation ? `operation:${action.localOperation}` : ''];
776
+ const extras = [
777
+ action.command,
778
+ action.targetCategoryId ? `target:${action.targetCategoryId}` : '',
779
+ action.editorKind ? `editor:${action.editorKind}` : '',
780
+ action.settingKey ? `setting:${action.settingKey}` : '',
781
+ action.modelPickerTarget ? `model-picker-target:${action.modelPickerTarget}` : '',
782
+ action.modelPickerFlow ? `model-picker-flow:${action.modelPickerFlow}` : '',
783
+ action.settingsTarget ? `settings-target:${action.settingsTarget}` : '',
784
+ action.kind === 'settings-import' ? 'import:goodvibes-tui-settings' : '',
785
+ action.localKind ? `local:${action.localKind}` : '',
786
+ action.localOperation ? `operation:${action.localOperation}` : '',
787
+ ];
796
788
  for (const extra of extras) if (extra) lines.push(extra);
797
789
  }
798
790
  }