@pellux/goodvibes-agent 1.4.3 → 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 +24 -0
- package/README.md +7 -7
- package/dist/package/main.js +7450 -12285
- 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 +63 -158
- 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
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
import type { AgentWorkspaceActionResult } from './agent-workspace-types.ts';
|
|
2
|
+
import type { OnboardingShellPaths } from '../runtime/onboarding/types.ts';
|
|
3
|
+
import type { AgentWorkspaceRuntimeSnapshot } from './agent-workspace-types.ts';
|
|
4
|
+
import { writeOnboardingCheckMarker, writeOnboardingCompletionMarker } from '../runtime/onboarding/index.ts';
|
|
5
|
+
import { computeOnboardingStateFromSnapshot, deriveOnboardingEntry } from './agent-workspace-onboarding-state.ts';
|
|
6
|
+
import type { OnboardingState } from '../runtime/onboarding/onboarding-state.ts';
|
|
7
|
+
|
|
8
|
+
export interface CompleteOnboardingParams {
|
|
9
|
+
readonly awaitingRecapDismiss: boolean;
|
|
10
|
+
readonly runtimeSnapshot: AgentWorkspaceRuntimeSnapshot | null;
|
|
11
|
+
readonly shellPaths: OnboardingShellPaths | undefined;
|
|
12
|
+
readonly dismissAgentWorkspace: (() => boolean) | undefined;
|
|
13
|
+
readonly close: () => void;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export interface CompleteOnboardingResult {
|
|
17
|
+
/** True when the dismiss path was taken — caller should close immediately. */
|
|
18
|
+
readonly dismissed: boolean;
|
|
19
|
+
/** New value for _awaitingRecapDismiss (only meaningful when dismissed=false). */
|
|
20
|
+
readonly awaitingRecapDismiss: boolean;
|
|
21
|
+
readonly status: string;
|
|
22
|
+
readonly lastActionResult: AgentWorkspaceActionResult;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Pure logic for the completeOnboarding() class method.
|
|
27
|
+
* Handles both the initial "write markers + show recap" path and the
|
|
28
|
+
* deferred "dismiss recap" path.
|
|
29
|
+
*/
|
|
30
|
+
export function completeOnboardingAction(params: CompleteOnboardingParams): CompleteOnboardingResult {
|
|
31
|
+
const { awaitingRecapDismiss, runtimeSnapshot, shellPaths, dismissAgentWorkspace, close } = params;
|
|
32
|
+
|
|
33
|
+
// Second activation: dismiss the recap and close the workspace.
|
|
34
|
+
if (awaitingRecapDismiss) {
|
|
35
|
+
if (!dismissAgentWorkspace?.()) close();
|
|
36
|
+
return {
|
|
37
|
+
dismissed: true,
|
|
38
|
+
awaitingRecapDismiss: false,
|
|
39
|
+
status: '',
|
|
40
|
+
lastActionResult: { kind: 'guidance', title: '', detail: '', safety: 'safe' },
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
// Shell paths are required to write the completion markers.
|
|
45
|
+
if (!shellPaths) {
|
|
46
|
+
return {
|
|
47
|
+
dismissed: false,
|
|
48
|
+
awaitingRecapDismiss: false,
|
|
49
|
+
status: 'Cannot complete onboarding without Agent shell paths.',
|
|
50
|
+
lastActionResult: {
|
|
51
|
+
kind: 'error',
|
|
52
|
+
title: 'Onboarding completion unavailable',
|
|
53
|
+
detail: 'The Agent workspace cannot locate the user onboarding completion marker path for this runtime.',
|
|
54
|
+
safety: 'safe',
|
|
55
|
+
},
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
try {
|
|
60
|
+
const marker = { scope: 'user', source: 'wizard', mode: 'new', workspaceRoot: shellPaths.workingDirectory } as const;
|
|
61
|
+
writeOnboardingCheckMarker(shellPaths, marker);
|
|
62
|
+
writeOnboardingCompletionMarker(shellPaths, marker);
|
|
63
|
+
const obs = computeOnboardingStateFromSnapshot(runtimeSnapshot, shellPaths);
|
|
64
|
+
const headline = obs?.recap.headline ?? 'Onboarding complete';
|
|
65
|
+
const lines: readonly string[] = obs?.recap.lines ?? [];
|
|
66
|
+
return {
|
|
67
|
+
dismissed: false,
|
|
68
|
+
awaitingRecapDismiss: true,
|
|
69
|
+
status: headline,
|
|
70
|
+
lastActionResult: {
|
|
71
|
+
kind: 'recap',
|
|
72
|
+
title: headline,
|
|
73
|
+
detail: lines.join('\n') || 'Saved the user onboarding completion marker.',
|
|
74
|
+
lines,
|
|
75
|
+
safety: 'safe',
|
|
76
|
+
},
|
|
77
|
+
};
|
|
78
|
+
} catch (error) {
|
|
79
|
+
const detail = error instanceof Error ? error.message : String(error);
|
|
80
|
+
return {
|
|
81
|
+
dismissed: false,
|
|
82
|
+
awaitingRecapDismiss: false,
|
|
83
|
+
status: 'Onboarding completion failed.',
|
|
84
|
+
lastActionResult: { kind: 'error', title: 'Onboarding completion failed', detail, safety: 'safe' },
|
|
85
|
+
};
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
export interface OnSubscriptionLoginSuccessParams {
|
|
90
|
+
readonly onlyGroup: string | null;
|
|
91
|
+
readonly runtimeSnapshot: AgentWorkspaceRuntimeSnapshot | null;
|
|
92
|
+
readonly shellPaths: OnboardingShellPaths | undefined;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
export interface OnSubscriptionLoginSuccessResult {
|
|
96
|
+
/** Updated onboarding state, or null when not in ONBOARDING mode. */
|
|
97
|
+
readonly onboardingState: OnboardingState | null;
|
|
98
|
+
/**
|
|
99
|
+
* Category ID to navigate to (undefined = no change).
|
|
100
|
+
* The caller must resolve this against its own this.categories AFTER
|
|
101
|
+
* updating _onboardingState and the reveal set, so the index is never stale.
|
|
102
|
+
*/
|
|
103
|
+
readonly targetCategoryId: string | undefined;
|
|
104
|
+
readonly status: string;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
/**
|
|
108
|
+
* Pure logic for the onSubscriptionLoginSuccess() class method.
|
|
109
|
+
* Re-derives onboarding state and returns the target category ID.
|
|
110
|
+
* The caller is responsible for resolving the ID to an index against
|
|
111
|
+
* its FRESHLY-UPDATED categories list (after assigning _onboardingState
|
|
112
|
+
* and updating the reveal set) to avoid a stale-index window.
|
|
113
|
+
*/
|
|
114
|
+
export function onSubscriptionLoginSuccessAction(params: OnSubscriptionLoginSuccessParams): OnSubscriptionLoginSuccessResult {
|
|
115
|
+
const { onlyGroup, runtimeSnapshot, shellPaths } = params;
|
|
116
|
+
|
|
117
|
+
if (onlyGroup !== 'ONBOARDING') {
|
|
118
|
+
return { onboardingState: null, targetCategoryId: undefined, status: '' };
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
const obs = computeOnboardingStateFromSnapshot(runtimeSnapshot, shellPaths);
|
|
122
|
+
if (!obs) {
|
|
123
|
+
return { onboardingState: null, targetCategoryId: undefined, status: '' };
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
const entry = deriveOnboardingEntry(obs);
|
|
127
|
+
const status = obs.readyToChat
|
|
128
|
+
? 'Signed in. You are ready to chat — Apply & close when ready.'
|
|
129
|
+
: `Signed in. ${entry.status}`;
|
|
130
|
+
|
|
131
|
+
return { onboardingState: obs, targetCategoryId: entry.categoryId, status };
|
|
132
|
+
}
|
|
@@ -6,15 +6,15 @@ export const AGENT_WORKSPACE_ONBOARDING_DETAIL_CATEGORIES: readonly AgentWorkspa
|
|
|
6
6
|
id: 'onboarding-channels',
|
|
7
7
|
group: 'ONBOARDING',
|
|
8
8
|
label: 'Messaging',
|
|
9
|
-
summary: '
|
|
10
|
-
detail: '
|
|
9
|
+
summary: 'Connect messaging channels, then check, test, and send from one page.',
|
|
10
|
+
detail: 'Connect a chat app so the assistant can message you and you can reply from your phone. Enable the channels you want, then fill in the credentials for each one.',
|
|
11
11
|
actions: [
|
|
12
|
-
settingAction({ id: 'channel-ntfy-enabled', label: 'Use ntfy', detail: '
|
|
12
|
+
settingAction({ id: 'channel-ntfy-enabled', label: 'Use ntfy', detail: 'Turn on ntfy to get push notifications and send replies from your phone or browser. Fill in the server URL and topics below once enabled.', key: 'surfaces.ntfy.enabled' }),
|
|
13
13
|
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 }),
|
|
14
14
|
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 }),
|
|
15
15
|
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 }),
|
|
16
16
|
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 }),
|
|
17
|
-
settingAction({ id: 'channel-ntfy-remote-topic', label: 'ntfy remote topic', detail: 'Set the
|
|
17
|
+
settingAction({ id: 'channel-ntfy-remote-topic', label: 'ntfy remote topic', detail: 'Set the assistant service remote chat topic.', key: 'surfaces.ntfy.remoteTopic', visibleWhenKey: 'surfaces.ntfy.enabled', visibleWhenValue: true }),
|
|
18
18
|
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 }),
|
|
19
19
|
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 }),
|
|
20
20
|
settingAction({ id: 'channel-slack-enabled', label: 'Use Slack', detail: 'Toggle Slack adapter configuration.', key: 'surfaces.slack.enabled' }),
|
|
@@ -51,7 +51,7 @@ export const AGENT_WORKSPACE_ONBOARDING_DETAIL_CATEGORIES: readonly AgentWorkspa
|
|
|
51
51
|
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 }),
|
|
52
52
|
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 }),
|
|
53
53
|
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 }),
|
|
54
|
-
settingAction({ id: 'channel-homeassistant-event-type', label: 'Home automation event type', detail: 'Set the event type used for
|
|
54
|
+
settingAction({ id: 'channel-homeassistant-event-type', label: 'Home automation event type', detail: 'Set the event type used for home automation delivery.', key: 'surfaces.homeassistant.eventType', visibleWhenKey: 'surfaces.homeassistant.enabled', visibleWhenValue: true }),
|
|
55
55
|
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 }),
|
|
56
56
|
settingAction({ id: 'channel-signal-enabled', label: 'Use Signal', detail: 'Toggle Signal bridge delivery.', key: 'surfaces.signal.enabled' }),
|
|
57
57
|
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 }),
|
|
@@ -71,16 +71,26 @@ export const AGENT_WORKSPACE_ONBOARDING_DETAIL_CATEGORIES: readonly AgentWorkspa
|
|
|
71
71
|
settingAction({ id: 'channel-imessage-account', label: 'iMessage account', detail: 'Set the iMessage account id.', key: 'surfaces.imessage.account', visibleWhenKey: 'surfaces.imessage.enabled', visibleWhenValue: true }),
|
|
72
72
|
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 }),
|
|
73
73
|
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 }),
|
|
74
|
+
{ id: 'channel-show', label: 'Check a channel', detail: 'Open a read-only readiness check for one channel.', editorKind: 'channel-show', kind: 'editor', safety: 'read-only' },
|
|
75
|
+
{ id: 'channel-doctor', label: 'Diagnose a channel', detail: 'Run read-only delivery diagnostics for one channel.', editorKind: 'channel-doctor', kind: 'editor', safety: 'read-only' },
|
|
76
|
+
{ id: 'channel-setup', label: 'Channel setup guide', detail: 'Open step-by-step setup guidance for one channel.', editorKind: 'channel-setup', kind: 'editor', safety: 'read-only' },
|
|
77
|
+
{ id: 'channel-send', label: 'Send a message', detail: 'Send one message through a configured channel after confirmation.', editorKind: 'channel-send', kind: 'editor', safety: 'safe' },
|
|
78
|
+
{ id: 'notification-send', label: 'Send a notification', detail: 'Send one plain-text notification to your configured targets after confirmation.', editorKind: 'notify-send', kind: 'editor', safety: 'safe' },
|
|
79
|
+
{ id: 'notification-add-webhook', label: 'Add notification target', detail: 'Add one webhook target for reminder and routine delivery.', editorKind: 'notify-webhook', kind: 'editor', safety: 'safe' },
|
|
80
|
+
{ id: 'notification-remove-webhook', label: 'Remove notification target', detail: 'Remove one webhook notification target after confirmation.', editorKind: 'notify-webhook-remove', kind: 'editor', safety: 'safe' },
|
|
81
|
+
{ id: 'notification-clear-webhooks', label: 'Clear notification targets', detail: 'Remove every configured webhook notification target after confirmation.', editorKind: 'notify-webhook-clear', kind: 'editor', safety: 'safe' },
|
|
82
|
+
{ id: 'notification-test-webhooks', label: 'Test notification targets', detail: 'Send one test notification to configured targets after typed confirmation.', editorKind: 'notify-webhook-test', kind: 'editor', safety: 'safe' },
|
|
83
|
+
{ id: 'channel-safety', label: 'Delivery safety', detail: 'Messages only go out when you explicitly send them. Nothing is delivered silently from this page.', kind: 'guidance', safety: 'blocked' },
|
|
74
84
|
],
|
|
75
85
|
},
|
|
76
86
|
{
|
|
77
87
|
id: 'onboarding-voice-media',
|
|
78
88
|
group: 'ONBOARDING',
|
|
79
|
-
label: 'Voice &
|
|
80
|
-
summary: '
|
|
81
|
-
detail: '
|
|
89
|
+
label: 'Voice & Media',
|
|
90
|
+
summary: 'Voice controls, spoken output, media generation, and phone delivery.',
|
|
91
|
+
detail: 'Let the assistant speak to you, listen for your voice, describe images, or send SMS. Voice, TTS, image input, media generation, and telephony live on this one page. Side effects stay explicit.',
|
|
82
92
|
actions: [
|
|
83
|
-
settingAction({ id: 'voice-enabled', label: 'Use voice controls', detail: '
|
|
93
|
+
settingAction({ id: 'voice-enabled', label: 'Use voice controls', detail: 'Turn on the local voice control surface so the assistant can listen and respond out loud. Requires a microphone and configured TTS provider.', key: 'ui.voiceEnabled' }),
|
|
84
94
|
settingAction({ id: 'voice-tts-provider', label: 'TTS provider', detail: 'Set the default text-to-speech provider id.', key: 'tts.provider' }),
|
|
85
95
|
settingAction({ id: 'voice-tts-voice', label: 'TTS voice', detail: 'Set the default text-to-speech voice id.', key: 'tts.voice' }),
|
|
86
96
|
settingAction({ id: 'telephony-enabled', label: 'Use telephony', detail: 'Toggle SMS, voice call, or telephony bridge delivery.', key: 'surfaces.telephony.enabled' }),
|
|
@@ -94,6 +104,15 @@ export const AGENT_WORKSPACE_ONBOARDING_DETAIL_CATEGORIES: readonly AgentWorkspa
|
|
|
94
104
|
settingAction({ id: 'telephony-recipient', label: 'Recipient phone number', detail: 'Set the default telephony recipient number.', key: 'surfaces.telephony.defaultRecipient', visibleWhenKey: 'surfaces.telephony.enabled', visibleWhenValue: true }),
|
|
95
105
|
settingAction({ id: 'telephony-webhook-secret', label: 'Telephony webhook secret', detail: 'Store the shared telephony webhook secret or secret reference.', key: 'surfaces.telephony.webhookSecret', visibleWhenKey: 'surfaces.telephony.enabled', visibleWhenValue: true }),
|
|
96
106
|
settingAction({ id: 'telephony-voice-language', label: 'Voice language', detail: 'Set the BCP-47 language code for voice-call text-to-speech.', key: 'surfaces.telephony.voiceLanguage', visibleWhenKey: 'surfaces.telephony.enabled', visibleWhenValue: true }),
|
|
107
|
+
{ id: 'voice-enable', label: 'Enable voice', detail: 'Open a confirmed form that enables local voice interaction.', editorKind: 'voice-enable', kind: 'editor', safety: 'safe' },
|
|
108
|
+
{ id: 'voice-disable', label: 'Disable voice', detail: 'Open a confirmed form that disables local voice interaction.', editorKind: 'voice-disable', kind: 'editor', safety: 'safe' },
|
|
109
|
+
{ id: 'tts-speak', label: 'Speak a prompt', detail: 'Open a prompt form for spoken assistant replies through configured live TTS.', editorKind: 'tts-prompt', kind: 'editor', safety: 'safe' },
|
|
110
|
+
{ id: 'image-attach', label: 'Attach image input', detail: 'Open an image form for attaching a real image path and optional prompt.', editorKind: 'image-input', kind: 'editor', safety: 'safe' },
|
|
111
|
+
{ id: 'media-generate', label: 'Generate media', detail: 'Open a confirmed prompt form that generates image or video artifacts through configured media providers.', editorKind: 'media-generate', kind: 'editor', safety: 'safe' },
|
|
112
|
+
{ id: 'voice-workflow-posture', label: 'Voice readiness', detail: 'Check push-to-talk, voice memo transcription, spoken responses, and wake-word readiness.', kind: 'guidance', safety: 'read-only' },
|
|
113
|
+
{ id: 'device-capability-map', label: 'Device capability map', detail: 'Check pairing, mobile command routing, browser, notification, and camera/location readiness for this device.', kind: 'guidance', safety: 'read-only' },
|
|
114
|
+
{ id: 'voice-bundle-export', label: 'Export voice bundle', detail: 'Open a confirmed form that exports voice setup state for review.', editorKind: 'voice-bundle-export', kind: 'editor', safety: 'safe' },
|
|
115
|
+
{ id: 'voice-bundle-inspect', label: 'Inspect voice bundle', detail: 'Open a form that inspects voice setup state before review.', editorKind: 'voice-bundle-inspect', kind: 'editor', safety: 'read-only' },
|
|
97
116
|
],
|
|
98
117
|
},
|
|
99
118
|
{
|
|
@@ -101,7 +120,7 @@ export const AGENT_WORKSPACE_ONBOARDING_DETAIL_CATEGORIES: readonly AgentWorkspa
|
|
|
101
120
|
group: 'ONBOARDING',
|
|
102
121
|
label: 'Local Context',
|
|
103
122
|
summary: 'Create/import memory, personas, skills, routines, notes, and Knowledge.',
|
|
104
|
-
detail: '
|
|
123
|
+
detail: 'Give the assistant a memory of who you are and what you care about. Create personas, starter memories, skills, and routines, or import context files you already have. These records are stored locally and used on every turn.',
|
|
105
124
|
actions: [
|
|
106
125
|
{ id: 'context-vibe-status', label: 'Inspect VIBE.md', detail: 'Show project/global VIBE.md personality files, blocked files, and init paths before relying on a custom assistant feel.', kind: 'guidance', safety: 'read-only' },
|
|
107
126
|
{ id: 'context-project-files', label: 'Inspect project context', detail: 'List secret-scanned .hermes.md, HERMES.md, AGENTS.md, CLAUDE.md, SOUL.md, and Cursor context files with blocked/truncated status.', kind: 'guidance', safety: 'read-only' },
|
|
@@ -122,20 +141,4 @@ export const AGENT_WORKSPACE_ONBOARDING_DETAIL_CATEGORIES: readonly AgentWorkspa
|
|
|
122
141
|
{ id: 'context-knowledge-browser-history', label: 'Import browser history', detail: 'Import local browser history or bookmarks into isolated Agent Knowledge.', editorKind: 'knowledge-browser-history', kind: 'editor', safety: 'safe' },
|
|
123
142
|
],
|
|
124
143
|
},
|
|
125
|
-
{
|
|
126
|
-
id: 'onboarding-automation',
|
|
127
|
-
group: 'ONBOARDING',
|
|
128
|
-
label: 'Automation Setup',
|
|
129
|
-
summary: 'Set scheduled work limits for reminders and routines.',
|
|
130
|
-
detail: 'Use this page to enable automation and set bounded run limits. Creating actual reminders and routines remains a separate confirmed action.',
|
|
131
|
-
actions: [
|
|
132
|
-
settingAction({ id: 'automation-enabled', label: 'Use automation', detail: 'Toggle the automation subsystem for reminders and scheduled routines.', key: 'automation.enabled' }),
|
|
133
|
-
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 }),
|
|
134
|
-
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 }),
|
|
135
|
-
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 }),
|
|
136
|
-
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 }),
|
|
137
|
-
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 }),
|
|
138
|
-
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 }),
|
|
139
|
-
],
|
|
140
|
-
},
|
|
141
144
|
];
|
|
@@ -1,5 +1,8 @@
|
|
|
1
1
|
import type { AgentWorkspaceAction, AgentWorkspaceCategory } from './agent-workspace-types.ts';
|
|
2
2
|
|
|
3
|
+
// These are WIZARD-STEP ids (AgentSetupWizardStep.id), NOT normalized plan ids.
|
|
4
|
+
// Do NOT cross-check these against SetupPlanItem ids or PLAN_ITEM_CATEGORY_MAP keys.
|
|
5
|
+
// (Compare: agent-workspace-onboarding-state.ts normalises 'provider-model' → 'provider-access' for plan-layer lookups.)
|
|
3
6
|
export const ONBOARDING_CRITICAL_STEP_IDS = ['runtime', 'connected-host-auth', 'provider-model'] as const;
|
|
4
7
|
|
|
5
8
|
export const ONBOARDING_COMPLETE_SYNTHETIC_ACTION: AgentWorkspaceAction = {
|
|
@@ -13,9 +16,13 @@ export const ONBOARDING_COMPLETE_SYNTHETIC_ACTION: AgentWorkspaceAction = {
|
|
|
13
16
|
export function shouldShowOnboardingFinishFooter(
|
|
14
17
|
category: AgentWorkspaceCategory,
|
|
15
18
|
baseActions: readonly AgentWorkspaceAction[],
|
|
19
|
+
readyToChat?: boolean,
|
|
16
20
|
): boolean {
|
|
17
|
-
return
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
)
|
|
21
|
+
if (category.group !== 'ONBOARDING') return false;
|
|
22
|
+
if (baseActions.some((a) => a.kind === 'onboarding-complete')) return false;
|
|
23
|
+
// When readyToChat is explicitly false (we have a valid OnboardingState and the user
|
|
24
|
+
// cannot chat yet), withhold the footer so completion is not premature.
|
|
25
|
+
// When readyToChat is undefined (no OnboardingState available), default to showing.
|
|
26
|
+
if (readyToChat === false) return false;
|
|
27
|
+
return true;
|
|
21
28
|
}
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
import type { AgentSetupWizardStep } from '../agent/setup-wizard.ts';
|
|
2
|
+
import type { SetupPlanItem } from '../tools/agent-harness-setup-posture-types.ts';
|
|
3
|
+
import type { AgentWorkspaceRuntimeSnapshot } from './agent-workspace-types.ts';
|
|
4
|
+
import type { OnboardingShellPaths } from '../runtime/onboarding/types.ts';
|
|
5
|
+
import {
|
|
6
|
+
deriveOnboardingState,
|
|
7
|
+
readOnboardingCheckMarker,
|
|
8
|
+
readOnboardingCompletionMarker,
|
|
9
|
+
type OnboardingState,
|
|
10
|
+
} from '../runtime/onboarding/index.ts';
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Adapts an AgentSetupWizardStep to a SetupPlanItem for use with
|
|
14
|
+
* deriveOnboardingState. The wizard uses different IDs for some steps;
|
|
15
|
+
* this adapter normalises the two known divergences:
|
|
16
|
+
* - 'provider-model' (wizard) → 'provider-access' (plan) so readyToChat
|
|
17
|
+
* and PLAN_ITEM_CATEGORY_MAP both resolve correctly.
|
|
18
|
+
* The output ids are PLAN ids (SetupPlanItem.id), not wizard-step ids.
|
|
19
|
+
* Do NOT compare the output ids against ONBOARDING_CRITICAL_STEP_IDS which
|
|
20
|
+
* operates on wizard-step ids (see agent-workspace-onboarding-finish.ts).
|
|
21
|
+
* blocksAutonomy is inferred from sourceStatus: blocked or check items block autonomy.
|
|
22
|
+
* Intentional approximation: AgentSetupWizardStep does not carry the authoritative
|
|
23
|
+
* SetupPlanItem.blocksAutonomy field; the wizard snapshot only exposes sourceStatus,
|
|
24
|
+
* so we derive it from status here rather than threading the real value through.
|
|
25
|
+
*/
|
|
26
|
+
function wizardItemToSetupPlanItem(step: AgentSetupWizardStep): SetupPlanItem {
|
|
27
|
+
const id = step.id === 'provider-model' ? 'provider-access' : step.id;
|
|
28
|
+
return {
|
|
29
|
+
id,
|
|
30
|
+
label: step.label,
|
|
31
|
+
status: step.sourceStatus,
|
|
32
|
+
priority: 0,
|
|
33
|
+
// Intentional approximation: AgentSetupWizardStep doesn't carry blocksAutonomy;
|
|
34
|
+
// derive it from sourceStatus since the real value isn't available at this layer.
|
|
35
|
+
blocksAutonomy: step.sourceStatus === 'blocked' || step.sourceStatus === 'check',
|
|
36
|
+
reason: step.detail,
|
|
37
|
+
nextAction: step.userRoute,
|
|
38
|
+
userRoute: step.userRoute,
|
|
39
|
+
modelRoute: step.modelRoute,
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
export interface OnboardingEntryResult {
|
|
44
|
+
/** Category ID to navigate to on entry (undefined = leave as-is). */
|
|
45
|
+
readonly categoryId: string | undefined;
|
|
46
|
+
/** Status message to display. */
|
|
47
|
+
readonly status: string;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* Derives the entry navigation and status message from an OnboardingState.
|
|
52
|
+
* Called by open() in ONBOARDING mode.
|
|
53
|
+
*/
|
|
54
|
+
export function deriveOnboardingEntry(obs: OnboardingState): OnboardingEntryResult {
|
|
55
|
+
if (obs.phase === 'in-progress' && obs.currentStepId) {
|
|
56
|
+
const step = obs.steps.find((s) => s.id === obs.currentStepId);
|
|
57
|
+
if (step) return { categoryId: step.categoryId, status: `Picking up where you left off: ${step.label}.` };
|
|
58
|
+
}
|
|
59
|
+
const currentStep = obs.steps.find((s) => s.id === obs.currentStepId);
|
|
60
|
+
const nextHint = currentStep ? ` — ${currentStep.nextLabel}` : '';
|
|
61
|
+
return { categoryId: undefined, status: `${obs.progressLabel}${nextHint}.` };
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* Given an OnboardingState, computes the set of ONBOARDING category IDs that are
|
|
66
|
+
* currently unlocked and adds them to the provided mutable revealed set.
|
|
67
|
+
* 'setup' is always present; other categories unlock once their step is ready.
|
|
68
|
+
*/
|
|
69
|
+
export function updateRevealedOnboardingCategories(
|
|
70
|
+
obs: OnboardingState,
|
|
71
|
+
revealed: Set<string>,
|
|
72
|
+
): void {
|
|
73
|
+
revealed.add('setup');
|
|
74
|
+
for (const step of obs.steps) {
|
|
75
|
+
if (step.status === 'ready') revealed.add(step.categoryId);
|
|
76
|
+
}
|
|
77
|
+
if (obs.readyToChat) revealed.add('account-model');
|
|
78
|
+
// Also reveal the active resume target so that navigating to it on re-entry
|
|
79
|
+
// actually works. The resume target is by definition non-ready (it is the
|
|
80
|
+
// first blocker), so it would otherwise be filtered out above. Only adds —
|
|
81
|
+
// preserves monotonicity of the revealed set.
|
|
82
|
+
if (obs.phase === 'in-progress' && obs.currentStepId) {
|
|
83
|
+
const cur = obs.steps.find((s) => s.id === obs.currentStepId);
|
|
84
|
+
if (cur) revealed.add(cur.categoryId);
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
/**
|
|
89
|
+
* Derives the current OnboardingState from a runtime snapshot and shell paths.
|
|
90
|
+
* Returns null when no snapshot is available (e.g. context is not fully initialised).
|
|
91
|
+
* Reads check and completion markers from shellPaths when provided.
|
|
92
|
+
*/
|
|
93
|
+
export function computeOnboardingStateFromSnapshot(
|
|
94
|
+
snapshot: AgentWorkspaceRuntimeSnapshot | null,
|
|
95
|
+
shellPaths: OnboardingShellPaths | undefined,
|
|
96
|
+
): OnboardingState | null {
|
|
97
|
+
const wizard = snapshot?.setupWizard;
|
|
98
|
+
if (!wizard?.steps?.length) return null;
|
|
99
|
+
|
|
100
|
+
const plan: SetupPlanItem[] = wizard.steps.map(wizardItemToSetupPlanItem);
|
|
101
|
+
|
|
102
|
+
// Build minimal marker states — default to non-existent when shellPaths is unavailable.
|
|
103
|
+
const checkMarker = shellPaths
|
|
104
|
+
? readOnboardingCheckMarker(shellPaths, 'user')
|
|
105
|
+
: { scope: 'user' as const, path: '', exists: false, payload: null };
|
|
106
|
+
const completionMarker = shellPaths
|
|
107
|
+
? readOnboardingCompletionMarker(shellPaths, 'user')
|
|
108
|
+
: { scope: 'user' as const, path: '', exists: false, payload: null };
|
|
109
|
+
|
|
110
|
+
return deriveOnboardingState({ plan, checkMarker, completionMarker });
|
|
111
|
+
}
|
|
@@ -0,0 +1,260 @@
|
|
|
1
|
+
import type { AgentWorkspaceActionResult, AgentWorkspaceLocalEditor } from './agent-workspace-types.ts';
|
|
2
|
+
import { quoteSlashCommandArg } from './slash-command-parser.ts';
|
|
3
|
+
import type { AgentWorkspaceProfileEditorKind } from './agent-workspace-profile-editors.ts';
|
|
4
|
+
|
|
5
|
+
type AgentWorkspaceFieldReader = (fieldId: string) => string;
|
|
6
|
+
|
|
7
|
+
type AgentWorkspaceProfileEditorSubmissionResult =
|
|
8
|
+
| {
|
|
9
|
+
readonly kind: 'editor';
|
|
10
|
+
readonly editor: AgentWorkspaceLocalEditor;
|
|
11
|
+
readonly status: string;
|
|
12
|
+
readonly actionResult?: AgentWorkspaceActionResult;
|
|
13
|
+
}
|
|
14
|
+
| {
|
|
15
|
+
readonly kind: 'dispatch';
|
|
16
|
+
readonly command: string;
|
|
17
|
+
readonly status: string;
|
|
18
|
+
readonly actionResult: AgentWorkspaceActionResult;
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
function isAffirmative(value: string): boolean {
|
|
22
|
+
return /^(y|yes|true)$/i.test(value.trim());
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export function isAgentWorkspaceProfileEditorSubmissionKind(kind: string): kind is AgentWorkspaceProfileEditorKind {
|
|
26
|
+
return kind === 'profile-template-export'
|
|
27
|
+
|| kind === 'profile-template-import'
|
|
28
|
+
|| kind === 'profile-template-show'
|
|
29
|
+
|| kind === 'profile-show'
|
|
30
|
+
|| kind === 'profile-template-from-discovered'
|
|
31
|
+
|| kind === 'profile-from-discovered'
|
|
32
|
+
|| kind === 'profile-default'
|
|
33
|
+
|| kind === 'profile-default-clear'
|
|
34
|
+
|| kind === 'profile-delete';
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export function buildAgentWorkspaceProfileEditorSubmission(
|
|
38
|
+
editor: AgentWorkspaceLocalEditor,
|
|
39
|
+
readField: AgentWorkspaceFieldReader,
|
|
40
|
+
): AgentWorkspaceProfileEditorSubmissionResult {
|
|
41
|
+
if (editor.kind === 'profile-template-export') {
|
|
42
|
+
if (!isAffirmative(readField('confirm'))) {
|
|
43
|
+
return {
|
|
44
|
+
kind: 'editor',
|
|
45
|
+
editor: { ...editor, message: 'Starter template export not confirmed. Type yes, then press Enter.' },
|
|
46
|
+
status: 'Agent starter template export not confirmed.',
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
const command = `/agent-profile template export ${quoteSlashCommandArg(readField('templateId'))} ${quoteSlashCommandArg(readField('path'))} --yes`;
|
|
50
|
+
return {
|
|
51
|
+
kind: 'dispatch',
|
|
52
|
+
command,
|
|
53
|
+
status: 'Opening Agent starter template export.',
|
|
54
|
+
actionResult: {
|
|
55
|
+
kind: 'dispatched',
|
|
56
|
+
title: 'Opening Agent starter template export',
|
|
57
|
+
detail: 'The workspace handed a confirmed starter template export command to the shell-owned command router.',
|
|
58
|
+
command,
|
|
59
|
+
safety: 'safe',
|
|
60
|
+
},
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
if (editor.kind === 'profile-template-import') {
|
|
64
|
+
if (!isAffirmative(readField('confirm'))) {
|
|
65
|
+
return {
|
|
66
|
+
kind: 'editor',
|
|
67
|
+
editor: { ...editor, message: 'Starter template import not confirmed. Type yes, then press Enter.' },
|
|
68
|
+
status: 'Agent starter template import not confirmed.',
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
const command = `/agent-profile template import ${quoteSlashCommandArg(readField('path'))} --yes`;
|
|
72
|
+
return {
|
|
73
|
+
kind: 'dispatch',
|
|
74
|
+
command,
|
|
75
|
+
status: 'Opening Agent starter template import.',
|
|
76
|
+
actionResult: {
|
|
77
|
+
kind: 'dispatched',
|
|
78
|
+
title: 'Opening Agent starter template import',
|
|
79
|
+
detail: 'The workspace handed a confirmed starter template import command to the shell-owned command router.',
|
|
80
|
+
command,
|
|
81
|
+
safety: 'safe',
|
|
82
|
+
},
|
|
83
|
+
};
|
|
84
|
+
}
|
|
85
|
+
if (editor.kind === 'profile-template-show') {
|
|
86
|
+
const command = `/agent-profile template show ${quoteSlashCommandArg(readField('id'))}`;
|
|
87
|
+
return {
|
|
88
|
+
kind: 'dispatch',
|
|
89
|
+
command,
|
|
90
|
+
status: 'Opening Agent starter template preview.',
|
|
91
|
+
actionResult: {
|
|
92
|
+
kind: 'dispatched',
|
|
93
|
+
title: 'Opening Agent starter template preview',
|
|
94
|
+
detail: 'The workspace handed a read-only starter template preview command to the shell-owned command router.',
|
|
95
|
+
command,
|
|
96
|
+
safety: 'read-only',
|
|
97
|
+
},
|
|
98
|
+
};
|
|
99
|
+
}
|
|
100
|
+
if (editor.kind === 'profile-show') {
|
|
101
|
+
const command = `/agent-profile show ${quoteSlashCommandArg(readField('profile'))}`;
|
|
102
|
+
return {
|
|
103
|
+
kind: 'dispatch',
|
|
104
|
+
command,
|
|
105
|
+
status: 'Opening Agent profile detail.',
|
|
106
|
+
actionResult: {
|
|
107
|
+
kind: 'dispatched',
|
|
108
|
+
title: 'Opening Agent profile detail',
|
|
109
|
+
detail: 'The workspace handed a read-only Agent profile inspection command to the shell-owned command router.',
|
|
110
|
+
command,
|
|
111
|
+
safety: 'read-only',
|
|
112
|
+
},
|
|
113
|
+
};
|
|
114
|
+
}
|
|
115
|
+
if (editor.kind === 'profile-template-from-discovered') {
|
|
116
|
+
if (!isAffirmative(readField('confirm'))) {
|
|
117
|
+
return {
|
|
118
|
+
kind: 'editor',
|
|
119
|
+
editor: { ...editor, message: 'Starter-from-discovered creation not confirmed. Type yes, then press Enter.' },
|
|
120
|
+
status: 'Agent starter-from-discovered creation not confirmed.',
|
|
121
|
+
};
|
|
122
|
+
}
|
|
123
|
+
const parts = [
|
|
124
|
+
'/agent-profile',
|
|
125
|
+
'template',
|
|
126
|
+
'from-discovered',
|
|
127
|
+
quoteSlashCommandArg(readField('id')),
|
|
128
|
+
];
|
|
129
|
+
const name = readField('name');
|
|
130
|
+
const description = readField('description');
|
|
131
|
+
const persona = readField('persona');
|
|
132
|
+
const skills = readField('skills');
|
|
133
|
+
const routines = readField('routines');
|
|
134
|
+
if (name.length > 0) parts.push('--name', quoteSlashCommandArg(name));
|
|
135
|
+
if (description.length > 0) parts.push('--description', quoteSlashCommandArg(description));
|
|
136
|
+
if (persona.length > 0) parts.push('--persona', quoteSlashCommandArg(persona));
|
|
137
|
+
if (skills.length > 0) parts.push('--skills', quoteSlashCommandArg(skills));
|
|
138
|
+
if (routines.length > 0) parts.push('--routines', quoteSlashCommandArg(routines));
|
|
139
|
+
if (isAffirmative(readField('replace'))) parts.push('--replace');
|
|
140
|
+
parts.push('--yes');
|
|
141
|
+
const command = parts.join(' ');
|
|
142
|
+
return {
|
|
143
|
+
kind: 'dispatch',
|
|
144
|
+
command,
|
|
145
|
+
status: 'Opening Agent starter-from-discovered creation.',
|
|
146
|
+
actionResult: {
|
|
147
|
+
kind: 'dispatched',
|
|
148
|
+
title: 'Opening Agent starter-from-discovered creation',
|
|
149
|
+
detail: 'The workspace handed a confirmed starter creation command to the shell-owned command router.',
|
|
150
|
+
command,
|
|
151
|
+
safety: 'safe',
|
|
152
|
+
},
|
|
153
|
+
};
|
|
154
|
+
}
|
|
155
|
+
if (editor.kind === 'profile-from-discovered') {
|
|
156
|
+
if (!isAffirmative(readField('confirm'))) {
|
|
157
|
+
return {
|
|
158
|
+
kind: 'editor',
|
|
159
|
+
editor: { ...editor, message: 'Profile-from-discovered creation not confirmed. Type yes, then press Enter.' },
|
|
160
|
+
status: 'Agent profile-from-discovered creation not confirmed.',
|
|
161
|
+
};
|
|
162
|
+
}
|
|
163
|
+
const parts = [
|
|
164
|
+
'/agent-profile',
|
|
165
|
+
'create-from-discovered',
|
|
166
|
+
quoteSlashCommandArg(readField('profile')),
|
|
167
|
+
];
|
|
168
|
+
const templateId = readField('templateId');
|
|
169
|
+
const name = readField('name');
|
|
170
|
+
const description = readField('description');
|
|
171
|
+
const persona = readField('persona');
|
|
172
|
+
const skills = readField('skills');
|
|
173
|
+
const routines = readField('routines');
|
|
174
|
+
if (templateId.length > 0) parts.push('--template-id', quoteSlashCommandArg(templateId));
|
|
175
|
+
if (name.length > 0) parts.push('--name', quoteSlashCommandArg(name));
|
|
176
|
+
if (description.length > 0) parts.push('--description', quoteSlashCommandArg(description));
|
|
177
|
+
if (persona.length > 0) parts.push('--persona', quoteSlashCommandArg(persona));
|
|
178
|
+
if (skills.length > 0) parts.push('--skills', quoteSlashCommandArg(skills));
|
|
179
|
+
if (routines.length > 0) parts.push('--routines', quoteSlashCommandArg(routines));
|
|
180
|
+
if (isAffirmative(readField('replace'))) parts.push('--replace');
|
|
181
|
+
parts.push('--yes');
|
|
182
|
+
const command = parts.join(' ');
|
|
183
|
+
return {
|
|
184
|
+
kind: 'dispatch',
|
|
185
|
+
command,
|
|
186
|
+
status: 'Opening Agent profile-from-discovered creation.',
|
|
187
|
+
actionResult: {
|
|
188
|
+
kind: 'dispatched',
|
|
189
|
+
title: 'Opening Agent profile-from-discovered creation',
|
|
190
|
+
detail: 'The workspace handed a confirmed discovered-behavior profile creation command to the shell-owned command router.',
|
|
191
|
+
command,
|
|
192
|
+
safety: 'safe',
|
|
193
|
+
},
|
|
194
|
+
};
|
|
195
|
+
}
|
|
196
|
+
if (editor.kind === 'profile-default') {
|
|
197
|
+
if (!isAffirmative(readField('confirm'))) {
|
|
198
|
+
return {
|
|
199
|
+
kind: 'editor',
|
|
200
|
+
editor: { ...editor, message: 'Default Agent profile selection not confirmed. Type yes, then press Enter.' },
|
|
201
|
+
status: 'Default Agent profile selection not confirmed.',
|
|
202
|
+
};
|
|
203
|
+
}
|
|
204
|
+
const command = `/agent-profile use ${quoteSlashCommandArg(readField('profile'))} --yes`;
|
|
205
|
+
return {
|
|
206
|
+
kind: 'dispatch',
|
|
207
|
+
command,
|
|
208
|
+
status: 'Opening default Agent profile selection.',
|
|
209
|
+
actionResult: {
|
|
210
|
+
kind: 'dispatched',
|
|
211
|
+
title: 'Opening default Agent profile selection',
|
|
212
|
+
detail: 'The workspace handed a confirmed default profile selection command to the shell-owned command router.',
|
|
213
|
+
command,
|
|
214
|
+
safety: 'safe',
|
|
215
|
+
},
|
|
216
|
+
};
|
|
217
|
+
}
|
|
218
|
+
if (editor.kind === 'profile-default-clear') {
|
|
219
|
+
if (!isAffirmative(readField('confirm'))) {
|
|
220
|
+
return {
|
|
221
|
+
kind: 'editor',
|
|
222
|
+
editor: { ...editor, message: 'Default Agent profile clear not confirmed. Type yes, then press Enter.' },
|
|
223
|
+
status: 'Default Agent profile clear not confirmed.',
|
|
224
|
+
};
|
|
225
|
+
}
|
|
226
|
+
const command = '/agent-profile default clear --yes';
|
|
227
|
+
return {
|
|
228
|
+
kind: 'dispatch',
|
|
229
|
+
command,
|
|
230
|
+
status: 'Opening default Agent profile clear.',
|
|
231
|
+
actionResult: {
|
|
232
|
+
kind: 'dispatched',
|
|
233
|
+
title: 'Opening default Agent profile clear',
|
|
234
|
+
detail: 'The workspace handed a confirmed default profile clear command to the shell-owned command router.',
|
|
235
|
+
command,
|
|
236
|
+
safety: 'safe',
|
|
237
|
+
},
|
|
238
|
+
};
|
|
239
|
+
}
|
|
240
|
+
if (!isAffirmative(readField('confirm'))) {
|
|
241
|
+
return {
|
|
242
|
+
kind: 'editor',
|
|
243
|
+
editor: { ...editor, message: 'Agent profile delete not confirmed. Type yes, then press Enter.' },
|
|
244
|
+
status: 'Agent profile delete not confirmed.',
|
|
245
|
+
};
|
|
246
|
+
}
|
|
247
|
+
const command = `/agent-profile delete ${quoteSlashCommandArg(readField('profile'))} --yes`;
|
|
248
|
+
return {
|
|
249
|
+
kind: 'dispatch',
|
|
250
|
+
command,
|
|
251
|
+
status: 'Opening Agent profile deletion.',
|
|
252
|
+
actionResult: {
|
|
253
|
+
kind: 'dispatched',
|
|
254
|
+
title: 'Opening Agent profile deletion',
|
|
255
|
+
detail: 'The workspace handed a confirmed profile deletion command to the shell-owned command router.',
|
|
256
|
+
command,
|
|
257
|
+
safety: 'safe',
|
|
258
|
+
},
|
|
259
|
+
};
|
|
260
|
+
}
|