@pellux/goodvibes-agent 1.4.4 → 1.5.0
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/CHANGELOG.md +14 -0
- package/README.md +7 -7
- package/dist/package/main.js +7424 -12241
- package/docs/README.md +2 -2
- package/docs/channels-remote-and-api.md +1 -1
- package/docs/getting-started.md +2 -2
- package/docs/release-and-publishing.md +1 -1
- package/docs/tools-and-commands.md +5 -5
- package/package.json +4 -2
- package/release/performance-snapshot.json +2 -2
- package/release/release-notes.md +11 -7
- package/release/release-readiness.json +6 -6
- package/src/agent/behavior-discovery-summary.ts +4 -18
- package/src/agent/calendar-registry.ts +322 -0
- package/src/agent/competitive-feature-inventory.ts +268 -130
- package/src/agent/document-registry.ts +5 -1
- package/src/agent/email/email-service.ts +350 -0
- package/src/agent/email/imap-client.ts +596 -0
- package/src/agent/email/smtp-client.ts +453 -0
- package/src/agent/ics-calendar.ts +662 -0
- package/src/agent/ics-timezone.ts +172 -0
- package/src/agent/markdown-frontmatter.ts +31 -0
- package/src/agent/memory-safety.ts +1 -1
- package/src/agent/note-registry.ts +3 -9
- package/src/agent/persona-discovery.ts +3 -15
- package/src/agent/persona-registry.ts +1 -10
- package/src/agent/research-source-registry.ts +5 -1
- package/src/agent/routine-discovery.ts +3 -15
- package/src/agent/runtime-profile.ts +3 -0
- package/src/agent/skill-discovery.ts +3 -15
- package/src/agent/skill-draft-proposer.ts +203 -0
- package/src/agent/skill-draft-runner.ts +201 -0
- package/src/agent/skill-registry.ts +36 -1
- package/src/agent/skill-standard.ts +99 -0
- package/src/agent/vibe-file.ts +7 -22
- package/src/cli/completion.ts +1 -1
- package/src/cli/config-overrides.ts +10 -1
- package/src/cli/redaction.ts +17 -5
- package/src/config/provider-model.ts +2 -1
- package/src/config/secret-config.ts +13 -6
- package/src/core/activity-feed.ts +97 -0
- package/src/core/away-digest.ts +161 -0
- package/src/core/conversation-rendering.ts +7 -3
- package/src/core/conversation.ts +22 -15
- package/src/core/hardware-profile.ts +362 -0
- package/src/core/last-seen-store.ts +78 -0
- package/src/core/plain-language.ts +52 -0
- package/src/core/setup-incomplete-hint.ts +90 -0
- package/src/core/system-message-router.ts +38 -87
- package/src/input/agent-workspace-basic-command-editor-submission.ts +60 -220
- package/src/input/agent-workspace-basic-command-editors.ts +39 -141
- package/src/input/agent-workspace-categories.ts +40 -125
- package/src/input/agent-workspace-command-editor.ts +4 -0
- package/src/input/agent-workspace-host-category.ts +0 -5
- package/src/input/agent-workspace-local-editor-submission.ts +3 -1
- package/src/input/agent-workspace-navigation.ts +10 -3
- package/src/input/agent-workspace-onboarding-actions.ts +132 -0
- package/src/input/agent-workspace-onboarding-categories.ts +29 -26
- package/src/input/agent-workspace-onboarding-finish.ts +11 -4
- package/src/input/agent-workspace-onboarding-state.ts +111 -0
- package/src/input/agent-workspace-profile-editor-submission.ts +260 -0
- package/src/input/agent-workspace-profile-editors.ts +155 -0
- package/src/input/agent-workspace-subscription-editor.ts +7 -0
- package/src/input/agent-workspace-types.ts +5 -1
- package/src/input/agent-workspace.ts +65 -39
- package/src/input/command-registry.ts +18 -5
- package/src/input/commands/agent-runtime-profile-runtime.ts +2 -1
- package/src/input/commands/agent-skills-runtime.ts +60 -3
- package/src/input/commands/calendar-runtime.ts +209 -0
- package/src/input/commands/channels-runtime.ts +1 -0
- package/src/input/commands/command-error.ts +9 -0
- package/src/input/commands/compat-runtime.ts +1 -0
- package/src/input/commands/config.ts +1 -0
- package/src/input/commands/conversation-runtime.ts +1 -1
- package/src/input/commands/delegation-runtime.ts +5 -6
- package/src/input/commands/email-runtime.ts +387 -0
- package/src/input/commands/experience-runtime.ts +17 -4
- package/src/input/commands/guidance-runtime.ts +1 -1
- package/src/input/commands/health-runtime.ts +6 -1
- package/src/input/commands/knowledge-format.ts +73 -0
- package/src/input/commands/knowledge.ts +9 -74
- package/src/input/commands/local-provider-runtime.ts +2 -1
- package/src/input/commands/local-runtime.ts +10 -4
- package/src/input/commands/mcp-runtime.ts +7 -0
- package/src/input/commands/notify-runtime.ts +17 -1
- package/src/input/commands/onboarding-runtime.ts +1 -0
- package/src/input/commands/operator-actions-runtime.ts +1 -0
- package/src/input/commands/operator-runtime.ts +3 -0
- package/src/input/commands/personas-runtime.ts +1 -0
- package/src/input/commands/platform-access-runtime.ts +40 -17
- package/src/input/commands/product-runtime.ts +6 -1
- package/src/input/commands/provider-accounts-runtime.ts +3 -2
- package/src/input/commands/qrcode-runtime.ts +1 -0
- package/src/input/commands/routines-runtime.ts +1 -0
- package/src/input/commands/runtime-services.ts +0 -13
- package/src/input/commands/security-runtime.ts +1 -0
- package/src/input/commands/session-content.ts +1 -0
- package/src/input/commands/shell-core.ts +5 -2
- package/src/input/commands/subscription-runtime.ts +33 -9
- package/src/input/commands/support-bundle-runtime.ts +8 -1
- package/src/input/commands/tasks-runtime.ts +1 -0
- package/src/input/commands/tts-runtime.ts +1 -0
- package/src/input/commands/vibe-runtime.ts +1 -0
- package/src/input/commands.ts +4 -0
- package/src/input/feed-context-factory.ts +3 -12
- package/src/input/handler-command-route.ts +7 -60
- package/src/input/handler-feed-routes.ts +0 -194
- package/src/input/handler-feed.ts +2 -54
- package/src/input/handler-interactions.ts +0 -2
- package/src/input/handler-modal-stack.ts +0 -9
- package/src/input/handler-picker-routes.ts +24 -1
- package/src/input/handler-shortcuts.ts +11 -40
- package/src/input/handler-ui-state.ts +13 -0
- package/src/input/handler.ts +8 -35
- package/src/input/keybindings.ts +40 -17
- package/src/input/model-picker-local-fit.ts +130 -0
- package/src/input/submission-router.ts +0 -5
- package/src/main.ts +111 -89
- package/src/renderer/activity-sidebar.ts +186 -0
- package/src/renderer/agent-workspace-context-lines.ts +5 -48
- package/src/renderer/agent-workspace-style.ts +1 -1
- package/src/renderer/agent-workspace.ts +14 -2
- package/src/renderer/compositor.ts +37 -125
- package/src/renderer/conversation-overlays.ts +3 -3
- package/src/renderer/help-overlay.ts +7 -5
- package/src/renderer/model-workspace.ts +101 -86
- package/src/{panels → renderer}/polish.ts +3 -3
- package/src/renderer/shell-surface.ts +4 -5
- package/src/renderer/status-token.ts +31 -11
- package/src/renderer/tab-strip.ts +1 -1
- package/src/renderer/tool-call.ts +7 -8
- package/src/renderer/tool-labels.ts +92 -0
- package/src/renderer/ui-factory.ts +48 -96
- package/src/runtime/bootstrap-command-context.ts +0 -5
- package/src/runtime/bootstrap-command-parts.ts +6 -15
- package/src/runtime/bootstrap-core.ts +34 -13
- package/src/runtime/bootstrap-hook-bridge.ts +3 -1
- package/src/runtime/bootstrap-shell.ts +3 -50
- package/src/runtime/bootstrap.ts +3 -4
- package/src/runtime/context.ts +1 -1
- package/src/runtime/diagnostics/panels/index.ts +0 -1
- package/src/runtime/diagnostics/panels/policy.ts +1 -1
- package/src/runtime/execution-ledger.ts +16 -1
- package/src/runtime/index.ts +6 -1
- package/src/runtime/onboarding/index.ts +1 -0
- package/src/runtime/onboarding/onboarding-state.ts +200 -0
- package/src/{panels → runtime}/provider-account-snapshot.ts +5 -2
- package/src/runtime/services.ts +16 -4
- package/src/runtime/terminal-output-guard.ts +7 -0
- package/src/runtime/tool-permission-safety.ts +1 -1
- package/src/runtime/ui/model-picker/data-provider.ts +1 -1
- package/src/runtime/ui/model-picker/health-enrichment.ts +2 -2
- package/src/runtime/ui/model-picker/types.ts +2 -2
- package/src/runtime/ui/provider-health/data-provider.ts +3 -3
- package/src/runtime/ui/provider-health/types.ts +2 -2
- package/src/runtime/ui-services.ts +0 -2
- package/src/shell/agent-workspace-fullscreen.ts +0 -1
- package/src/shell/autonomy-surfacing.ts +272 -0
- package/src/shell/session-continuity-hints.ts +0 -6
- package/src/shell/startup-wiring.ts +221 -0
- package/src/shell/ui-openers.ts +18 -29
- package/src/tools/agent-context-policy.ts +1 -1
- package/src/tools/agent-harness-background-processes.ts +4 -4
- package/src/tools/agent-harness-browser-cockpit-route.ts +3 -3
- package/src/tools/agent-harness-command-runner.ts +6 -1
- package/src/tools/agent-harness-document-ops.ts +26 -53
- package/src/tools/agent-harness-execution-history.ts +1 -13
- package/src/tools/agent-harness-execution-posture.ts +0 -15
- package/src/tools/agent-harness-keybinding-metadata.ts +28 -29
- package/src/tools/agent-harness-local-model-cookbook.ts +24 -1
- package/src/tools/agent-harness-metadata.ts +16 -0
- package/src/tools/agent-harness-mode-catalog.ts +2 -9
- package/src/tools/agent-harness-provider-account-metadata.ts +2 -2
- package/src/tools/agent-harness-setup-posture-utils.ts +1 -1
- package/src/tools/agent-harness-tool-schema.ts +13 -14
- package/src/tools/agent-harness-tool.ts +27 -23
- package/src/tools/agent-harness-ui-surface-metadata.ts +10 -20
- package/src/tools/agent-harness-workspace-action-runner.ts +3 -4
- package/src/tools/agent-workspace-tool.ts +2 -33
- package/src/utils/terminal-width.ts +9 -3
- package/src/version.ts +1 -1
- package/src/input/agent-workspace-panel-route.ts +0 -44
- package/src/input/panel-integration-actions.ts +0 -26
- package/src/panels/approval-panel.ts +0 -149
- package/src/panels/automation-control-panel.ts +0 -212
- package/src/panels/base-panel.ts +0 -254
- package/src/panels/builtin/agent.ts +0 -58
- package/src/panels/builtin/knowledge.ts +0 -26
- package/src/panels/builtin/operations.ts +0 -121
- package/src/panels/builtin/session.ts +0 -138
- package/src/panels/builtin/shared.ts +0 -275
- package/src/panels/builtin/usage.ts +0 -21
- package/src/panels/builtin-panels.ts +0 -23
- package/src/panels/confirm-state.ts +0 -61
- package/src/panels/context-visualizer-panel.ts +0 -204
- package/src/panels/cost-tracker-panel.ts +0 -444
- package/src/panels/docs-panel.ts +0 -285
- package/src/panels/index.ts +0 -25
- package/src/panels/knowledge-panel.ts +0 -417
- package/src/panels/memory-panel.ts +0 -226
- package/src/panels/panel-list-panel.ts +0 -464
- package/src/panels/panel-manager.ts +0 -570
- package/src/panels/provider-accounts-panel.ts +0 -233
- package/src/panels/provider-health-domains.ts +0 -208
- package/src/panels/provider-health-panel.ts +0 -720
- package/src/panels/provider-health-tracker.ts +0 -115
- package/src/panels/provider-stats-panel.ts +0 -366
- package/src/panels/qr-panel.ts +0 -207
- package/src/panels/schedule-panel.ts +0 -321
- package/src/panels/scrollable-list-panel.ts +0 -491
- package/src/panels/search-focus.ts +0 -32
- package/src/panels/security-panel.ts +0 -295
- package/src/panels/session-browser-panel.ts +0 -395
- package/src/panels/session-maintenance.ts +0 -125
- package/src/panels/subscription-panel.ts +0 -263
- package/src/panels/system-messages-panel.ts +0 -230
- package/src/panels/tasks-panel.ts +0 -344
- package/src/panels/thinking-panel.ts +0 -304
- package/src/panels/token-budget-panel.ts +0 -475
- package/src/panels/tool-inspector-panel.ts +0 -436
- package/src/panels/types.ts +0 -54
- package/src/renderer/panel-composite.ts +0 -158
- package/src/renderer/panel-tab-bar.ts +0 -69
- package/src/renderer/panel-workspace-bar.ts +0 -42
- package/src/runtime/diagnostics/panels/panel-resources.ts +0 -118
- package/src/tools/agent-harness-panel-metadata.ts +0 -211
- /package/src/runtime/perf/{panel-health-monitor.ts → component-health.ts} +0 -0
|
@@ -4,7 +4,6 @@ import type { ConversationManager } from '../core/conversation';
|
|
|
4
4
|
import type { KnowledgeApi } from '@pellux/goodvibes-sdk/platform/knowledge';
|
|
5
5
|
import type { HookApi } from '@pellux/goodvibes-sdk/platform/hooks';
|
|
6
6
|
import type { McpApi } from '@pellux/goodvibes-sdk/platform/mcp';
|
|
7
|
-
import type { PanelManager } from '../panels/panel-manager.ts';
|
|
8
7
|
import type { ProviderApi } from '@pellux/goodvibes-sdk/platform/providers';
|
|
9
8
|
import type { OpsApi } from '@/runtime/index.ts';
|
|
10
9
|
import type { MutableRuntimeState } from '@/runtime/index.ts';
|
|
@@ -116,7 +115,6 @@ export type CreateBootstrapCommandContextOptions = {
|
|
|
116
115
|
mcpApi?: McpApi;
|
|
117
116
|
opsApi?: OpsApi;
|
|
118
117
|
directTransport?: DirectTransport;
|
|
119
|
-
panelManager: PanelManager;
|
|
120
118
|
worktreeRegistry: WorktreeRegistry;
|
|
121
119
|
sandboxSessionRegistry: SandboxSessionRegistry;
|
|
122
120
|
loadSystemPrompt: () => string;
|
|
@@ -192,7 +190,6 @@ export function createBootstrapCommandContext(
|
|
|
192
190
|
mcpApi,
|
|
193
191
|
opsApi,
|
|
194
192
|
directTransport,
|
|
195
|
-
panelManager,
|
|
196
193
|
worktreeRegistry,
|
|
197
194
|
sandboxSessionRegistry,
|
|
198
195
|
loadSystemPrompt,
|
|
@@ -247,7 +244,6 @@ export function createBootstrapCommandContext(
|
|
|
247
244
|
const workspace = createBootstrapCommandWorkspaceSection({
|
|
248
245
|
keybindingsManager,
|
|
249
246
|
fileUndoManager,
|
|
250
|
-
panelManager,
|
|
251
247
|
processManager,
|
|
252
248
|
profileManager,
|
|
253
249
|
bookmarkManager,
|
|
@@ -277,7 +273,6 @@ export function createBootstrapCommandContext(
|
|
|
277
273
|
conversation,
|
|
278
274
|
runtime,
|
|
279
275
|
requestRender,
|
|
280
|
-
panelManager,
|
|
281
276
|
loadSystemPrompt,
|
|
282
277
|
activatePlan,
|
|
283
278
|
requestPermission,
|
|
@@ -6,7 +6,6 @@ import type { KnowledgeApi } from '@pellux/goodvibes-sdk/platform/knowledge';
|
|
|
6
6
|
import type { AgentPromptContextReceiptStore } from '../agent/prompt-context-receipts.ts';
|
|
7
7
|
import type { HookApi } from '@pellux/goodvibes-sdk/platform/hooks';
|
|
8
8
|
import type { McpApi } from '@pellux/goodvibes-sdk/platform/mcp';
|
|
9
|
-
import type { PanelManager } from '../panels/panel-manager.ts';
|
|
10
9
|
import type { ProviderApi } from '@pellux/goodvibes-sdk/platform/providers';
|
|
11
10
|
import type { OpsApi } from '@/runtime/index.ts';
|
|
12
11
|
import type { MutableRuntimeState } from '@/runtime/index.ts';
|
|
@@ -62,7 +61,6 @@ export interface BootstrapCommandActionOptions {
|
|
|
62
61
|
readonly conversation: ConversationManager;
|
|
63
62
|
readonly runtime: MutableRuntimeState;
|
|
64
63
|
readonly requestRender: () => void;
|
|
65
|
-
readonly panelManager: PanelManager;
|
|
66
64
|
readonly loadSystemPrompt: () => string;
|
|
67
65
|
readonly activatePlan: (planId: string, task: string) => void;
|
|
68
66
|
readonly requestPermission: PermissionRequestHandler;
|
|
@@ -76,7 +74,6 @@ export interface BootstrapCommandSectionOptions {
|
|
|
76
74
|
readonly runtime: MutableRuntimeState;
|
|
77
75
|
readonly keybindingsManager?: KeybindingsManager;
|
|
78
76
|
readonly processManager?: import('@pellux/goodvibes-sdk/platform/tools').ProcessManager;
|
|
79
|
-
readonly panelManager: PanelManager;
|
|
80
77
|
readonly requestRender: () => void;
|
|
81
78
|
readonly requestPermission: PermissionRequestHandler;
|
|
82
79
|
readonly toolRegistry: ToolRegistry;
|
|
@@ -158,7 +155,6 @@ export function createBootstrapCommandActions(
|
|
|
158
155
|
| 'print'
|
|
159
156
|
| 'exit'
|
|
160
157
|
| 'reloadSystemPrompt'
|
|
161
|
-
| 'showPanel'
|
|
162
158
|
| 'openMcpWorkspace'
|
|
163
159
|
| 'openAgentWorkspace'
|
|
164
160
|
| 'dismissAgentWorkspace'
|
|
@@ -172,17 +168,14 @@ export function createBootstrapCommandActions(
|
|
|
172
168
|
conversation,
|
|
173
169
|
runtime,
|
|
174
170
|
requestRender,
|
|
175
|
-
panelManager,
|
|
176
171
|
loadSystemPrompt,
|
|
177
172
|
activatePlan,
|
|
178
173
|
requestPermission,
|
|
179
174
|
completeModelSelectionSideEffect,
|
|
180
175
|
} = options;
|
|
181
176
|
|
|
182
|
-
const
|
|
183
|
-
|
|
184
|
-
panelManager.hide();
|
|
185
|
-
conversation.log(`Panel route "${panelId}" is handled through Agent Workspace. Use /agent for current operator controls.`, { fg: '214' });
|
|
177
|
+
const pointToWorkspace = (what: string) => {
|
|
178
|
+
conversation.log(`${what} lives in the Agent workspace — press Ctrl+P or run /agent.`, { fg: '214' });
|
|
186
179
|
requestRender();
|
|
187
180
|
};
|
|
188
181
|
|
|
@@ -246,18 +239,17 @@ export function createBootstrapCommandActions(
|
|
|
246
239
|
},
|
|
247
240
|
exit: () => unwiredShellAction('exit'),
|
|
248
241
|
reloadSystemPrompt: loadSystemPrompt,
|
|
249
|
-
showPanel,
|
|
250
242
|
openMcpWorkspace: () => unwiredShellAction('openMcpWorkspace'),
|
|
251
243
|
openAgentWorkspace: () => unwiredShellAction('openAgentWorkspace'),
|
|
252
244
|
dismissAgentWorkspace: () => unwiredShellAction('dismissAgentWorkspace'),
|
|
253
245
|
openSecurityPanel: () => {
|
|
254
|
-
|
|
246
|
+
pointToWorkspace('Security review');
|
|
255
247
|
},
|
|
256
248
|
openKnowledgePanel: () => {
|
|
257
|
-
|
|
249
|
+
pointToWorkspace('Knowledge');
|
|
258
250
|
},
|
|
259
251
|
openSubscriptionPanel: () => {
|
|
260
|
-
|
|
252
|
+
pointToWorkspace('Provider subscriptions');
|
|
261
253
|
},
|
|
262
254
|
};
|
|
263
255
|
}
|
|
@@ -295,7 +287,7 @@ export function createBootstrapCommandProviderSection(
|
|
|
295
287
|
export function createBootstrapCommandWorkspaceSection(
|
|
296
288
|
options: Pick<
|
|
297
289
|
BootstrapCommandSectionOptions,
|
|
298
|
-
'keybindingsManager' | 'fileUndoManager' | '
|
|
290
|
+
'keybindingsManager' | 'fileUndoManager' | 'profileManager' | 'bookmarkManager'
|
|
299
291
|
| 'processManager' | 'projectPlanningService' | 'projectPlanningProjectId' | 'workPlanStore'
|
|
300
292
|
>,
|
|
301
293
|
shellServices: BootstrapCommandShellServices,
|
|
@@ -303,7 +295,6 @@ export function createBootstrapCommandWorkspaceSection(
|
|
|
303
295
|
return {
|
|
304
296
|
keybindingsManager: options.keybindingsManager,
|
|
305
297
|
fileUndoManager: options.fileUndoManager,
|
|
306
|
-
panelManager: options.panelManager,
|
|
307
298
|
processManager: options.processManager,
|
|
308
299
|
profileManager: options.profileManager,
|
|
309
300
|
bookmarkManager: options.bookmarkManager,
|
|
@@ -6,8 +6,8 @@ import { getProviderIdFromModel } from '../config/provider-model.ts';
|
|
|
6
6
|
import { ToolRegistry } from '@pellux/goodvibes-sdk/platform/tools';
|
|
7
7
|
import { registerAllTools } from '@pellux/goodvibes-sdk/platform/tools';
|
|
8
8
|
import { PermissionManager, createPermissionConfigReader } from '@pellux/goodvibes-sdk/platform/permissions';
|
|
9
|
-
import { Notifier } from '@pellux/goodvibes-sdk/platform/integrations';
|
|
10
|
-
|
|
9
|
+
import { Notifier, WebhookNotifier } from '@pellux/goodvibes-sdk/platform/integrations';
|
|
10
|
+
|
|
11
11
|
import { Compositor } from '../renderer/compositor.ts';
|
|
12
12
|
import type { PermissionRequestHandler } from '@pellux/goodvibes-sdk/platform/permissions';
|
|
13
13
|
import type { SystemMessageRouter } from '../core/system-message-router.ts';
|
|
@@ -94,6 +94,26 @@ export interface BootstrapCoreState {
|
|
|
94
94
|
|
|
95
95
|
export type CompanionMessagePayload = Extract<SessionEvent, { type: 'COMPANION_MESSAGE_RECEIVED' }>;
|
|
96
96
|
|
|
97
|
+
/**
|
|
98
|
+
* Registers the webhook notifier for the runtime session.
|
|
99
|
+
*
|
|
100
|
+
* Configures the provided WebhookNotifier with the given URL list, attaches it
|
|
101
|
+
* to the runtime bus so it receives SESSION_NOTIFICATION events, and pushes a
|
|
102
|
+
* detach() cleanup into runtimeUnsubs for shutdown. When webhookUrls is empty
|
|
103
|
+
* this function is a complete no-op.
|
|
104
|
+
*/
|
|
105
|
+
export function registerWebhookNotifier(
|
|
106
|
+
webhookNotifier: WebhookNotifier,
|
|
107
|
+
webhookUrls: string[],
|
|
108
|
+
runtimeBus: RuntimeEventBus,
|
|
109
|
+
runtimeUnsubs: Array<() => void>,
|
|
110
|
+
): void {
|
|
111
|
+
if (webhookUrls.length === 0) return;
|
|
112
|
+
webhookNotifier.setUrls(webhookUrls);
|
|
113
|
+
webhookNotifier.attachToRuntimeBus(runtimeBus);
|
|
114
|
+
runtimeUnsubs.push(() => webhookNotifier.detach());
|
|
115
|
+
}
|
|
116
|
+
|
|
97
117
|
export function companionMessageToOrchestratorInputOptions(
|
|
98
118
|
payload: CompanionMessagePayload,
|
|
99
119
|
): OrchestratorUserInputOptions {
|
|
@@ -161,7 +181,7 @@ export async function initializeBootstrapCore(
|
|
|
161
181
|
sessionId: userSessionId,
|
|
162
182
|
authenticatedAt: Date.now(),
|
|
163
183
|
lastSeenAt: Date.now(),
|
|
164
|
-
capabilities: ['session', '
|
|
184
|
+
capabilities: ['session', 'commands', 'automation'],
|
|
165
185
|
metadata: {
|
|
166
186
|
product: 'goodvibes-agent',
|
|
167
187
|
surfaceRoot: GOODVIBES_AGENT_SURFACE_ROOT,
|
|
@@ -176,7 +196,6 @@ export async function initializeBootstrapCore(
|
|
|
176
196
|
hookDispatcher,
|
|
177
197
|
hookWorkbench,
|
|
178
198
|
memoryStore,
|
|
179
|
-
panelManager,
|
|
180
199
|
routeBindings,
|
|
181
200
|
sessionBroker: sharedSessionBroker,
|
|
182
201
|
surfaceRegistry,
|
|
@@ -215,13 +234,7 @@ export async function initializeBootstrapCore(
|
|
|
215
234
|
getControlPlaneRecentEvents,
|
|
216
235
|
});
|
|
217
236
|
|
|
218
|
-
const conversation = new ConversationManager(() =>
|
|
219
|
-
const width = getTerminalSize(stdout).width;
|
|
220
|
-
if (panelManager.isVisible() && panelManager.getAllOpen().length > 0) {
|
|
221
|
-
return Math.max(1, panelManager.getLeftWidth(width) - 1);
|
|
222
|
-
}
|
|
223
|
-
return width;
|
|
224
|
-
});
|
|
237
|
+
const conversation = new ConversationManager(() => getTerminalSize(stdout).width);
|
|
225
238
|
conversation.setConfigManager(configManager);
|
|
226
239
|
getConversationTitle = () => conversation.title;
|
|
227
240
|
|
|
@@ -321,6 +334,11 @@ export async function initializeBootstrapCore(
|
|
|
321
334
|
});
|
|
322
335
|
|
|
323
336
|
const bootstrapUnsubs: Array<() => void> = [];
|
|
337
|
+
// D5 fix: stop the heartbeat watcher on shutdown so the setInterval is cleared.
|
|
338
|
+
// Registered here (after declaration) rather than inside the watcher block above.
|
|
339
|
+
if (configManager.get('watchers.enabled')) {
|
|
340
|
+
bootstrapUnsubs.push(() => watcherRegistry.stopWatcher('runtime-heartbeat'));
|
|
341
|
+
}
|
|
324
342
|
await memoryStore.init();
|
|
325
343
|
bootstrapUnsubs.push(() => {
|
|
326
344
|
void memoryStore.save();
|
|
@@ -420,8 +438,11 @@ export async function initializeBootstrapCore(
|
|
|
420
438
|
|
|
421
439
|
const webhookUrls = (configManager.getCategory('notifications') as { webhookUrls?: string[] }).webhookUrls ?? [];
|
|
422
440
|
if (webhookUrls.length > 0) {
|
|
423
|
-
|
|
424
|
-
|
|
441
|
+
// Reuse the services.webhookNotifier instance (constructed no-arg in services.ts).
|
|
442
|
+
// Configure it with the resolved URL list via setUrls(), attach it to the runtime
|
|
443
|
+
// bus so it receives SESSION_NOTIFICATION events, and register detach() in
|
|
444
|
+
// runtimeUnsubs so the bus subscription is cleaned up on shutdown.
|
|
445
|
+
registerWebhookNotifier(services.webhookNotifier, webhookUrls, runtimeBus, runtimeUnsubs);
|
|
425
446
|
domainDispatch.syncIntegration({
|
|
426
447
|
id: 'webhooks',
|
|
427
448
|
displayName: 'Webhooks',
|
|
@@ -52,9 +52,11 @@ export function createResumeSessionHandler(options: ResumeSessionOptions): (sess
|
|
|
52
52
|
options.writeLastSessionPointer(sessionId);
|
|
53
53
|
void options.sharedSessionBroker.reopenSession(sessionId).catch((err) => { logger.debug('session broker reopen session failed', { err }); });
|
|
54
54
|
options.conversation.log(`Resumed session: ${sessionId}`, { fg: '135' });
|
|
55
|
-
const ignoredPanels = meta.returnContext?.openPanels?.slice(0, 4) ?? [];
|
|
56
55
|
const returnContextMode = getReturnContextMode(options.configManager);
|
|
57
56
|
if (returnContextMode !== 'off' && meta.returnContext) {
|
|
57
|
+
// N1 fix: compute ignoredPanels inside the guard so it is only evaluated
|
|
58
|
+
// when returnContext is present and the mode is not 'off'.
|
|
59
|
+
const ignoredPanels = meta.returnContext.openPanels?.slice(0, 4) ?? [];
|
|
58
60
|
for (const line of formatReturnContextForDisplay(meta.returnContext)) {
|
|
59
61
|
if (line.startsWith('Open panels:')) continue;
|
|
60
62
|
options.conversation.log(`Resume: ${line}`, { fg: '244' });
|
|
@@ -13,8 +13,7 @@ import { CommandRegistry } from '../input/command-registry.ts';
|
|
|
13
13
|
import { registerBuiltinCommands } from '../input/commands.ts';
|
|
14
14
|
import { InputHistory } from '../input/input-history.ts';
|
|
15
15
|
import type { PermissionRequestHandler } from '@pellux/goodvibes-sdk/platform/permissions';
|
|
16
|
-
import {
|
|
17
|
-
import { SystemMessagesPanel } from '../panels/system-messages-panel.ts';
|
|
16
|
+
import { ActivityFeed } from '../core/activity-feed.ts';
|
|
18
17
|
import { createSystemMessageRouter, type SystemMessageRouter } from '../core/system-message-router.ts';
|
|
19
18
|
import { getConfigSnapshot } from '../config/index.ts';
|
|
20
19
|
import { createBootstrapCommandContext } from './bootstrap-command-context.ts';
|
|
@@ -24,7 +23,6 @@ import { loadBootstrapSystemPrompt } from '@/runtime/index.ts';
|
|
|
24
23
|
import { createShellPlanRuntime, createShellRemoteCommandService } from '@/runtime/index.ts';
|
|
25
24
|
import { createRuntimeFoundationClients } from '@/runtime/index.ts';
|
|
26
25
|
import type { ControlPlaneRecentEvent } from '@pellux/goodvibes-sdk/platform/control-plane';
|
|
27
|
-
import type { BuiltinPanelDeps } from '../panels/builtin/shared.ts';
|
|
28
26
|
import type { ToolRegistry } from '@pellux/goodvibes-sdk/platform/tools';
|
|
29
27
|
import type { ForensicsRegistry } from '@/runtime/index.ts';
|
|
30
28
|
import type { PolicyRuntimeState } from '@/runtime/index.ts';
|
|
@@ -125,7 +123,7 @@ export function createBootstrapShell(options: BootstrapShellOptions): BootstrapS
|
|
|
125
123
|
completeModelSelectionSideEffect,
|
|
126
124
|
} = options;
|
|
127
125
|
|
|
128
|
-
const
|
|
126
|
+
const activityFeed = new ActivityFeed();
|
|
129
127
|
const resumeSession = createResumeSessionHandler({
|
|
130
128
|
runtimeBus,
|
|
131
129
|
runtime,
|
|
@@ -141,54 +139,10 @@ export function createBootstrapShell(options: BootstrapShellOptions): BootstrapS
|
|
|
141
139
|
});
|
|
142
140
|
|
|
143
141
|
let commandContextRef: CommandContext | null = null;
|
|
144
|
-
registerBuiltinPanels(services.panelManager, {
|
|
145
|
-
configManager,
|
|
146
|
-
getOrchestratorUsage: () => orchestrator.usage as { input: number; output: number; cacheRead: number; cacheWrite: number; model?: string },
|
|
147
|
-
toolRegistry,
|
|
148
|
-
providerRegistry: services.providerRegistry,
|
|
149
|
-
contextWindow: services.providerRegistry.getContextWindowForModel(services.providerRegistry.getCurrentModel()),
|
|
150
|
-
orchestrator,
|
|
151
|
-
getCtxWindow: () => services.providerRegistry.getContextWindowForModel(services.providerRegistry.getCurrentModel()),
|
|
152
|
-
resumeSession,
|
|
153
|
-
requestRender,
|
|
154
|
-
submitPlanningAnswer: (answer) => {
|
|
155
|
-
submitPlanningAnswerWithShellFallback(answer, {
|
|
156
|
-
getSubmitInput: () => commandContextRef?.submitInput,
|
|
157
|
-
addSystemMessage: (message) => conversation.addSystemMessage(message),
|
|
158
|
-
requestRender,
|
|
159
|
-
});
|
|
160
|
-
},
|
|
161
|
-
dismissPlanning: () => {
|
|
162
|
-
services.panelManager.close('project-planning');
|
|
163
|
-
commandContextRef?.focusPrompt?.();
|
|
164
|
-
requestRender();
|
|
165
|
-
},
|
|
166
|
-
forensicsRegistry,
|
|
167
|
-
policyRuntimeState,
|
|
168
|
-
approvalBroker: services.approvalBroker,
|
|
169
|
-
sessionBroker: services.sessionBroker,
|
|
170
|
-
automationManager: services.automationManager,
|
|
171
|
-
getControlPlaneRecentEvents,
|
|
172
|
-
tokenAuditor: services.tokenAuditor,
|
|
173
|
-
componentHealthMonitor: services.componentHealthMonitor,
|
|
174
|
-
worktreeRegistry: services.worktreeRegistry,
|
|
175
|
-
sandboxSessionRegistry: services.sandboxSessionRegistry,
|
|
176
|
-
systemMessagesPanel,
|
|
177
|
-
memoryRegistry: services.memoryRegistry,
|
|
178
|
-
agentKnowledgeService: services.agentKnowledgeService,
|
|
179
|
-
uiServices,
|
|
180
|
-
pluginManager: services.pluginManager,
|
|
181
|
-
hookDispatcher: services.hookDispatcher,
|
|
182
|
-
hookActivityTracker: services.hookActivityTracker,
|
|
183
|
-
hookWorkbench: services.hookWorkbench,
|
|
184
|
-
mcpRegistry: services.mcpRegistry,
|
|
185
|
-
connectedHostTokenDir: join(services.homeDirectory, '.goodvibes', 'daemon'),
|
|
186
|
-
});
|
|
187
|
-
services.panelManager.prewarmRegistered();
|
|
188
142
|
|
|
189
143
|
const systemMessageRouter = createSystemMessageRouter(
|
|
190
144
|
conversation,
|
|
191
|
-
|
|
145
|
+
activityFeed,
|
|
192
146
|
(kind) => {
|
|
193
147
|
const ui = getConfigSnapshot(configManager).ui;
|
|
194
148
|
if (kind === 'wrfc') return ui.wrfcMessages;
|
|
@@ -287,7 +241,6 @@ export function createBootstrapShell(options: BootstrapShellOptions): BootstrapS
|
|
|
287
241
|
mcpApi,
|
|
288
242
|
opsApi,
|
|
289
243
|
directTransport,
|
|
290
|
-
panelManager: services.panelManager,
|
|
291
244
|
worktreeRegistry: services.worktreeRegistry,
|
|
292
245
|
sandboxSessionRegistry: services.sandboxSessionRegistry,
|
|
293
246
|
loadSystemPrompt: () => loadBootstrapSystemPrompt(configManager),
|
package/src/runtime/bootstrap.ts
CHANGED
|
@@ -69,10 +69,10 @@ const GOODVIBES_AGENT_OPERATOR_POLICY = [
|
|
|
69
69
|
'- Act as one user-facing autonomous assistant. Prefer the lowest-friction safe path that completes the user outcome; do not expose internal package or host ownership unless it is needed for diagnosis, setup, or safety.',
|
|
70
70
|
'- Work serially in the main conversation by default for ordinary chat, research, planning, setup, local context, and short tool work. Use visible schedules, work plans, operator actions, or delegated/remote routes for durable or long-running autonomy.',
|
|
71
71
|
'- Connected-host lifecycle is not ambient. If the host is unavailable, explain the shortest user action to make the assistant reachable; do not pretend a missing host route worked.',
|
|
72
|
-
'- Read tools: `route action:"plan|status"`, `schedule action:"list"`, `setup action:"status|item|repair|checkpoint"`, `settings action:"list|get"`, `vibe action:"status|show"`, `context action:"status|files|file|prompt|receipts|receipt"`, `memory action:"status|provider|curator|candidate|list|search|get"`, `channels action:"status|channel|setup|triage|deliveries"`, `models action:"status|route|local|providers|provider"`, `personal_ops action:"briefing|status|queue|intake|lane"`, `autonomy action:"intake|queue|item|status"`, `delegation action:"status|routes|route"`, `execution action:"status|route|history|record|processes|process_capabilities|process|recovery"`, `security action:"status|finding|explain"`, `support action:"status|bundle"`, `sessions action:"list|get"`, `audit action:"readiness|item|evidence|artifact"`, `computer action:"status|plan|control|browser|setup|mcp"`, `research action:"plan|search|runner|runs|run|sources|source|bundle|reports|report_artifact"`, `device action:"status|capability|browser|control|voice|provider"`, `workspace action:"status|actions|action|surfaces|surface|
|
|
73
|
-
'- Harness access: use `settings action:"set|reset|import"` and `workspace action:"run|run_command|open|
|
|
72
|
+
'- Read tools: `route action:"plan|status"`, `schedule action:"list"`, `setup action:"status|item|repair|checkpoint"`, `settings action:"list|get"`, `vibe action:"status|show"`, `context action:"status|files|file|prompt|receipts|receipt"`, `memory action:"status|provider|curator|candidate|list|search|get"`, `channels action:"status|channel|setup|triage|deliveries"`, `models action:"status|route|local|providers|provider"`, `personal_ops action:"briefing|status|queue|intake|lane"`, `autonomy action:"intake|queue|item|status"`, `delegation action:"status|routes|route"`, `execution action:"status|route|history|record|processes|process_capabilities|process|recovery"`, `security action:"status|finding|explain"`, `support action:"status|bundle"`, `sessions action:"list|get"`, `audit action:"readiness|item|evidence|artifact"`, `computer action:"status|plan|control|browser|setup|mcp"`, `research action:"plan|search|runner|runs|run|sources|source|bundle|reports|report_artifact"`, `device action:"status|capability|browser|control|voice|provider"`, `workspace action:"status|actions|action|surfaces|surface|shortcuts|keybindings|keybinding|commands|command|cli_commands|cli_command"`, `host action:"status|capabilities|capability|services|service|methods|method"`, `import_goodvibes_settings action:"preview"`, and `agent_operator_briefing` for connected work/approvals/automation/schedules, `agent_knowledge` for isolated Agent Knowledge, and `agent_harness` for harness catalogs/status/capability discovery. Use `agent_artifacts` for saved artifact list/preview/export/package/archive; write modes are confirmation-gated.',
|
|
73
|
+
'- Harness access: use `settings action:"set|reset|import"` and `workspace action:"run|run_command|open|run_keybinding|set_keybinding|reset_keybinding"` to use the same surfaces the user can use; lower-level `agent_harness` modes remain for detail inspection and compatibility.',
|
|
74
74
|
'- State tools: `agent_work_plan` for visible local work items; `agent_local_registry` for Agent-local notes, memory, personas, skills, bundles, and routines; `agent_learning_consolidation` for confirmed duplicate cleanup phases; `agent_documents` for versioned Agent document drafts. Keep records non-secret, sourced, and reviewable.',
|
|
75
|
-
'- Confirmed tools: use `schedule`, `setup action:"save_checkpoint|clear_checkpoint|token|smoke|finish|import_settings"`, `vibe action:"init|import_persona"`, `models action:"smoke"` for local model server checks, `personal_ops action:"read"` for one live read-only inbox/calendar connector operation, `research action:"create_run|start_run|checkpoint|pause|resume|cancel|complete|fail|delete_run|add_source|review_source|reject_source|use_source|delete_source|report"`, `computer action:"open_browser"`, `device action:"open_browser|open_tts_provider|open_tts_voice"`, `workspace action:"run|run_command|open|
|
|
75
|
+
'- Confirmed tools: use `schedule`, `setup action:"save_checkpoint|clear_checkpoint|token|smoke|finish|import_settings"`, `vibe action:"init|import_persona"`, `models action:"smoke"` for local model server checks, `personal_ops action:"read"` for one live read-only inbox/calendar connector operation, `research action:"create_run|start_run|checkpoint|pause|resume|cancel|complete|fail|delete_run|add_source|review_source|reject_source|use_source|delete_source|report"`, `computer action:"open_browser"`, `device action:"open_browser|open_tts_provider|open_tts_voice"`, `workspace action:"run|run_command|open|run_keybinding|set_keybinding|reset_keybinding"`, `import_goodvibes_settings`, `agent_operator_action`, `agent_artifacts` export/package/archive, `agent_documents`, `agent_review_packet_presets` save/refresh, `agent_review_packet_share`, `agent_knowledge_ingest`, `agent_learning_consolidation`, `agent_media_generate`, `agent_model_compare`, `agent_research_runs`, `agent_research_sources`, `agent_research_report`, `agent_notify`, `agent_channel_send`, `agent_autonomy_schedule`, `agent_reminder_schedule`, and `agent_schedule_edit` only for explicit user requests with confirm:true and explicitUserRequest.',
|
|
76
76
|
'- Agent Knowledge must use only `/api/goodvibes-agent/knowledge/*` and fail closed. Do not use default knowledge or non-Agent knowledge spaces.',
|
|
77
77
|
'- External delivery, media generation, reminders, settings writes, slash-command mirrors, workspace action mirrors, and destructive local changes require explicit user intent and the owning tool/command confirmation.',
|
|
78
78
|
'- Autonomous work must be visible, reviewable, and cancellable. Never create silent hidden jobs; when work should continue later, create or use an explicit schedule, reminder, work-plan item, operator action, or delegated/remote task route.',
|
|
@@ -237,7 +237,6 @@ export async function bootstrapRuntime(
|
|
|
237
237
|
const {
|
|
238
238
|
automationManager,
|
|
239
239
|
hookDispatcher,
|
|
240
|
-
panelManager,
|
|
241
240
|
pluginManager,
|
|
242
241
|
} = services;
|
|
243
242
|
|
package/src/runtime/context.ts
CHANGED
|
@@ -19,7 +19,7 @@ import type { FeatureFlagManager } from '@/runtime/index.ts';
|
|
|
19
19
|
import type { MutableRuntimeState } from '@/runtime/index.ts';
|
|
20
20
|
import type { SessionSnapshot } from '@/runtime/index.ts';
|
|
21
21
|
import type { RuntimeServices } from './services.ts';
|
|
22
|
-
import type { ComponentHealthMonitor } from './perf/
|
|
22
|
+
import type { ComponentHealthMonitor } from './perf/component-health.ts';
|
|
23
23
|
import type { WorktreeRegistry } from '@/runtime/index.ts';
|
|
24
24
|
import type { SandboxSessionRegistry } from '@/runtime/index.ts';
|
|
25
25
|
|
|
@@ -19,6 +19,5 @@ export { TransportPanel } from '@/runtime/index.ts';
|
|
|
19
19
|
export type { TransportPanelSnapshot } from '@/runtime/index.ts';
|
|
20
20
|
export { OpsPanel } from './ops.ts';
|
|
21
21
|
export type { OpsAuditEntry } from './ops.ts';
|
|
22
|
-
export { PanelResourcesPanel } from './panel-resources.ts';
|
|
23
22
|
export { SecurityPanel } from '@/runtime/index.ts';
|
|
24
23
|
export type { SecurityPanelSnapshot } from '@/runtime/index.ts';
|
|
@@ -155,7 +155,7 @@ export class PolicyDiagnosticsPanel {
|
|
|
155
155
|
*/
|
|
156
156
|
public subscribe(callback: () => void): () => void {
|
|
157
157
|
this._subscribers.add(callback);
|
|
158
|
-
return () => this._subscribers.delete(callback);
|
|
158
|
+
return () => { this._subscribers.delete(callback); };
|
|
159
159
|
}
|
|
160
160
|
|
|
161
161
|
/**
|
|
@@ -98,6 +98,21 @@ function stringArg(args: Record<string, unknown>, keys: readonly string[]): stri
|
|
|
98
98
|
return undefined;
|
|
99
99
|
}
|
|
100
100
|
|
|
101
|
+
/**
|
|
102
|
+
* Classify a tool call into a route kind for display and filtering.
|
|
103
|
+
*
|
|
104
|
+
* Keyword precedence (first match wins):
|
|
105
|
+
* 1. browser — browser/desktop/screenshot keywords
|
|
106
|
+
* 2. delegation — delegate/agent keywords
|
|
107
|
+
* 3. shell — exec/shell/bash keywords OR args.command is a string
|
|
108
|
+
* 4. write — write/edit/patch/delete keywords
|
|
109
|
+
* 5. network — fetch/web/http/url keywords
|
|
110
|
+
* 6. read — read/find/inspect/grep/search keywords
|
|
111
|
+
* 7. other — fallback for unrecognized tool names
|
|
112
|
+
*
|
|
113
|
+
* N2: precedence is intentional — shell beats write/read so that bash-exec tools
|
|
114
|
+
* that also match 'exec' are not misclassified as filesystem writes.
|
|
115
|
+
*/
|
|
101
116
|
function routeKindForTool(tool: string, args: Record<string, unknown>): AgentExecutionRouteKind {
|
|
102
117
|
const name = tool.toLowerCase();
|
|
103
118
|
if (name.includes('browser') || name.includes('desktop') || name.includes('screenshot')) return 'browser';
|
|
@@ -162,7 +177,7 @@ export class AgentExecutionLedger {
|
|
|
162
177
|
|
|
163
178
|
public subscribe(callback: () => void): () => void {
|
|
164
179
|
this.subscribers.add(callback);
|
|
165
|
-
return () => this.subscribers.delete(callback);
|
|
180
|
+
return () => { this.subscribers.delete(callback); };
|
|
166
181
|
}
|
|
167
182
|
|
|
168
183
|
public dispose(): void {
|
package/src/runtime/index.ts
CHANGED
|
@@ -325,6 +325,11 @@ export const getDistributedNodeHostContract = operations.getDistributedNodeHostC
|
|
|
325
325
|
export const CURRENT_PROTOCOL_VERSION = operations.CURRENT_PROTOCOL_VERSION;
|
|
326
326
|
export const VersionMismatchError = operations.VersionMismatchError;
|
|
327
327
|
export const negotiateProtocolVersion = operations.negotiateProtocolVersion;
|
|
328
|
+
// Protocol version types — re-exported for transport compatibility tests.
|
|
329
|
+
// ProtocolVersion, VersionNegotiationResult, NegotiatedProtocol are available
|
|
330
|
+
// via operations namespace (operations.ProtocolVersion etc.) but cannot be
|
|
331
|
+
// re-exported here without a registered subpath. Tests that need these types
|
|
332
|
+
// should import from the operations namespace types directly.
|
|
328
333
|
export const createTaskManager = operations.createTaskManager;
|
|
329
334
|
export const PhasedToolExecutor = operations.PhasedToolExecutor;
|
|
330
335
|
export const budgetPhase = operations.budgetPhase;
|
|
@@ -614,7 +619,7 @@ export type BundleProvenance = Security.BundleProvenance;
|
|
|
614
619
|
export type DecisionReason = Security.DecisionReason;
|
|
615
620
|
export type DivergenceReport = Security.DivergenceReport;
|
|
616
621
|
export type EnforceGateResult = Security.EnforceGateResult;
|
|
617
|
-
export type SignedPolicyBundle = Security.SignedPolicyBundle
|
|
622
|
+
export type SignedPolicyBundle<T = unknown> = Security.SignedPolicyBundle<T>;
|
|
618
623
|
|
|
619
624
|
export interface InspectableDomain {
|
|
620
625
|
readonly name: string;
|
|
@@ -0,0 +1,200 @@
|
|
|
1
|
+
import type { SetupPlanItem, SetupPlanStatus } from '../../tools/agent-harness-setup-posture-types.ts';
|
|
2
|
+
import type { OnboardingCheckMarkerState } from './types.ts';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Maps each setup plan item id to the Agent Workspace category that resolves it.
|
|
6
|
+
* This is the single sequencing table — every onboarding surface reads from here.
|
|
7
|
+
*/
|
|
8
|
+
const PLAN_ITEM_CATEGORY_MAP: Readonly<Record<string, string>> = {
|
|
9
|
+
'connected-host-readiness': 'setup',
|
|
10
|
+
'connected-host-auth': 'setup',
|
|
11
|
+
'goodvibes-settings-import': 'setup',
|
|
12
|
+
'provider-access': 'account-model',
|
|
13
|
+
'install-smoke': 'setup',
|
|
14
|
+
'local-model-readiness': 'account-model',
|
|
15
|
+
'agent-knowledge': 'setup',
|
|
16
|
+
'vibe-personality': 'assistant-behavior',
|
|
17
|
+
'local-behavior': 'onboarding-context',
|
|
18
|
+
'communication-channels': 'onboarding-channels',
|
|
19
|
+
'automation-review': 'tools-permissions',
|
|
20
|
+
'browser-desktop-control': 'tools-permissions',
|
|
21
|
+
'sudo-execution-posture': 'tools-permissions',
|
|
22
|
+
'build-delegation': 'tools-permissions',
|
|
23
|
+
'finish-onboarding': 'setup',
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
const DEFAULT_CATEGORY_ID = 'setup';
|
|
27
|
+
|
|
28
|
+
function planItemCategoryId(planItemId: string): string {
|
|
29
|
+
return PLAN_ITEM_CATEGORY_MAP[planItemId] ?? DEFAULT_CATEGORY_ID;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export interface OnboardingStep {
|
|
33
|
+
readonly id: string;
|
|
34
|
+
readonly label: string;
|
|
35
|
+
readonly status: SetupPlanStatus;
|
|
36
|
+
readonly blocksAutonomy: boolean;
|
|
37
|
+
/** Human-readable hint shown in the UI for the next action. */
|
|
38
|
+
readonly nextLabel: string;
|
|
39
|
+
/** Agent Workspace category id that resolves this step. */
|
|
40
|
+
readonly categoryId: string;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
export interface OnboardingRecap {
|
|
44
|
+
/** Single headline sentence describing overall readiness. */
|
|
45
|
+
readonly headline: string;
|
|
46
|
+
/** One line per ready capability plus optional trailing lines. */
|
|
47
|
+
readonly lines: readonly string[];
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
export type OnboardingPhase = 'fresh' | 'in-progress' | 'complete';
|
|
51
|
+
|
|
52
|
+
export interface OnboardingState {
|
|
53
|
+
/**
|
|
54
|
+
* Phase derived from markers:
|
|
55
|
+
* - 'complete' completion marker present
|
|
56
|
+
* - 'in-progress' check marker present but no completion marker
|
|
57
|
+
* - 'fresh' neither marker present
|
|
58
|
+
*/
|
|
59
|
+
readonly phase: OnboardingPhase;
|
|
60
|
+
/** All setup plan items converted to lightweight steps. */
|
|
61
|
+
readonly steps: readonly OnboardingStep[];
|
|
62
|
+
/** First non-ready step that blocks autonomy, or first non-ready step if none, or null. */
|
|
63
|
+
readonly currentStepId: string | null;
|
|
64
|
+
/** Human-readable progress, e.g. "2 of 5 ready". */
|
|
65
|
+
readonly progressLabel: string;
|
|
66
|
+
/** Steps that are not ready and block autonomy. */
|
|
67
|
+
readonly blockers: readonly OnboardingStep[];
|
|
68
|
+
/**
|
|
69
|
+
* True when a usable model route exists:
|
|
70
|
+
* the provider-access plan item is 'ready', or local-model-readiness is 'ready'.
|
|
71
|
+
*/
|
|
72
|
+
readonly readyToChat: boolean;
|
|
73
|
+
/** Summary shown at the end of onboarding or as a re-entry summary. */
|
|
74
|
+
readonly recap: OnboardingRecap;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
export interface DeriveOnboardingStateContext {
|
|
78
|
+
/** Fully-built setup plan (from buildSetupPlan). */
|
|
79
|
+
readonly plan: readonly SetupPlanItem[];
|
|
80
|
+
/** User-scope check marker (from readOnboardingCheckMarker). */
|
|
81
|
+
readonly checkMarker: OnboardingCheckMarkerState;
|
|
82
|
+
/** User-scope completion marker (from readOnboardingCompletionMarker). */
|
|
83
|
+
readonly completionMarker: OnboardingCheckMarkerState;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
function derivePhase(
|
|
87
|
+
checkMarker: OnboardingCheckMarkerState,
|
|
88
|
+
completionMarker: OnboardingCheckMarkerState,
|
|
89
|
+
): OnboardingPhase {
|
|
90
|
+
if (completionMarker.exists && completionMarker.payload !== null) return 'complete';
|
|
91
|
+
if (checkMarker.exists) return 'in-progress';
|
|
92
|
+
return 'fresh';
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
function planItemToStep(item: SetupPlanItem): OnboardingStep {
|
|
96
|
+
return {
|
|
97
|
+
id: item.id,
|
|
98
|
+
label: item.label,
|
|
99
|
+
status: item.status,
|
|
100
|
+
blocksAutonomy: item.blocksAutonomy,
|
|
101
|
+
nextLabel: item.nextAction,
|
|
102
|
+
categoryId: planItemCategoryId(item.id),
|
|
103
|
+
};
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
function deriveCurrentStepId(steps: readonly OnboardingStep[]): string | null {
|
|
107
|
+
// Priority: first non-ready blocker, then first non-ready step overall.
|
|
108
|
+
const firstBlocker = steps.find((s) => s.status !== 'ready' && s.blocksAutonomy);
|
|
109
|
+
if (firstBlocker) return firstBlocker.id;
|
|
110
|
+
const firstNonReady = steps.find((s) => s.status !== 'ready');
|
|
111
|
+
return firstNonReady?.id ?? null;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
function deriveProgressLabel(plan: readonly SetupPlanItem[]): string {
|
|
115
|
+
const ready = plan.filter((item) => item.status === 'ready').length;
|
|
116
|
+
const total = plan.length;
|
|
117
|
+
return `${ready} of ${total} ready`;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
function deriveReadyToChat(plan: readonly SetupPlanItem[]): boolean {
|
|
121
|
+
const providerItem = plan.find((item) => item.id === 'provider-access');
|
|
122
|
+
if (providerItem?.status === 'ready') return true;
|
|
123
|
+
const localModelItem = plan.find((item) => item.id === 'local-model-readiness');
|
|
124
|
+
return localModelItem?.status === 'ready';
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
function deriveRecap(
|
|
128
|
+
phase: OnboardingPhase,
|
|
129
|
+
steps: readonly OnboardingStep[],
|
|
130
|
+
plan: readonly SetupPlanItem[],
|
|
131
|
+
): OnboardingRecap {
|
|
132
|
+
const readySteps = steps.filter((s) => s.status === 'ready');
|
|
133
|
+
const optionalCount = plan.filter(
|
|
134
|
+
(item) => item.status !== 'ready' && !item.blocksAutonomy,
|
|
135
|
+
).length;
|
|
136
|
+
|
|
137
|
+
const headline =
|
|
138
|
+
phase === 'complete'
|
|
139
|
+
? "You're set up. Here's what you can do now."
|
|
140
|
+
: phase === 'in-progress'
|
|
141
|
+
? "Setup is in progress. Here's what's ready so far."
|
|
142
|
+
: 'Getting started — a few things to set up before the full experience.';
|
|
143
|
+
|
|
144
|
+
const lines: string[] = readySteps.map((s) => s.label);
|
|
145
|
+
|
|
146
|
+
// Capability examples: show what the user can actually do right now.
|
|
147
|
+
// Always-safe examples (research/draft/summarize) are shown whenever a model route is ready.
|
|
148
|
+
// Channel-dependent examples (reminders/messaging) only appear when that lane is configured.
|
|
149
|
+
const modelReady = deriveReadyToChat(plan);
|
|
150
|
+
if (modelReady && phase !== 'fresh') {
|
|
151
|
+
const channelsReady = plan.some(
|
|
152
|
+
(item) => item.id === 'communication-channels' && item.status === 'ready',
|
|
153
|
+
);
|
|
154
|
+
const capabilityLines: string[] = [
|
|
155
|
+
'Ask me to research a topic, draft an email, summarize a file, or compare models.',
|
|
156
|
+
];
|
|
157
|
+
if (channelsReady) {
|
|
158
|
+
capabilityLines.push('You can also set reminders and send messages through your connected channels.');
|
|
159
|
+
}
|
|
160
|
+
lines.push(...capabilityLines);
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
if (optionalCount > 0 && phase !== 'fresh') {
|
|
164
|
+
lines.push(`Still optional: ${optionalCount} item${optionalCount === 1 ? '' : 's'} available`);
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
if (phase !== 'fresh') {
|
|
168
|
+
lines.push('Try: "What can you help me with today?"');
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
return { headline, lines };
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
/**
|
|
175
|
+
* Pure selector: derives the full OnboardingState from an already-built plan and
|
|
176
|
+
* the current marker files. No side effects, no Date.now() calls.
|
|
177
|
+
*/
|
|
178
|
+
export function deriveOnboardingState(
|
|
179
|
+
context: DeriveOnboardingStateContext,
|
|
180
|
+
): OnboardingState {
|
|
181
|
+
const { plan, checkMarker, completionMarker } = context;
|
|
182
|
+
|
|
183
|
+
const phase = derivePhase(checkMarker, completionMarker);
|
|
184
|
+
const steps = plan.map(planItemToStep);
|
|
185
|
+
const currentStepId = deriveCurrentStepId(steps);
|
|
186
|
+
const progressLabel = deriveProgressLabel(plan);
|
|
187
|
+
const blockers = steps.filter((s) => s.status !== 'ready' && s.blocksAutonomy);
|
|
188
|
+
const readyToChat = deriveReadyToChat(plan);
|
|
189
|
+
const recap = deriveRecap(phase, steps, plan);
|
|
190
|
+
|
|
191
|
+
return {
|
|
192
|
+
phase,
|
|
193
|
+
steps,
|
|
194
|
+
currentStepId,
|
|
195
|
+
progressLabel,
|
|
196
|
+
blockers,
|
|
197
|
+
readyToChat,
|
|
198
|
+
recap,
|
|
199
|
+
};
|
|
200
|
+
}
|