@pellux/goodvibes-agent 1.5.5 → 1.5.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +9 -0
- package/README.md +1 -1
- package/dist/package/main.js +94130 -79335
- package/docs/tools-and-commands.md +2 -1
- package/package.json +6 -3
- package/src/agent/autonomy-schedule-format.ts +1 -1
- package/src/agent/autonomy-schedule.ts +3 -3
- package/src/agent/calendar/calendar-oauth-service.ts +324 -0
- package/src/agent/calendar-subscription-registry.ts +497 -0
- package/src/agent/email/email-service.ts +57 -0
- package/src/agent/email/smtp-client.ts +30 -10
- package/src/agent/memory-prompt.ts +143 -12
- package/src/agent/operator-actions.ts +26 -22
- package/src/agent/prompt-context-receipts.ts +45 -18
- package/src/agent/reminder-schedule-format.ts +1 -1
- package/src/agent/reminder-schedule.ts +3 -3
- package/src/agent/routine-schedule-format.ts +2 -2
- package/src/agent/routine-schedule-promotion.ts +5 -5
- package/src/agent/routine-schedule-receipts.ts +2 -2
- package/src/agent/schedule-edit-format.ts +1 -1
- package/src/agent/schedule-edit.ts +5 -5
- package/src/agent/session-registration.ts +281 -0
- package/src/agent/vibe-file.ts +50 -0
- package/src/cli/local-library-command-shared.ts +146 -0
- package/src/cli/management.ts +2 -1
- package/src/cli/personas-command.ts +252 -0
- package/src/cli/resume-relaunch-notice.ts +151 -0
- package/src/cli/routines-command.ts +25 -2
- package/src/cli/service-posture.ts +3 -2
- package/src/cli/skill-bundle-command.ts +175 -0
- package/src/cli/skills-command.ts +309 -0
- package/src/cli/status.ts +43 -7
- package/src/cli/tui-startup.ts +24 -1
- package/src/config/agent-settings-policy.ts +0 -1
- package/src/config/secret-config.ts +4 -0
- package/src/core/conversation-rendering.ts +20 -11
- package/src/core/focus-tracker.ts +41 -0
- package/src/core/system-message-noise.ts +108 -0
- package/src/core/system-message-router.ts +54 -1
- package/src/core/thinking-overlay.ts +83 -0
- package/src/input/agent-workspace-access-command-editor-submission.ts +75 -108
- package/src/input/agent-workspace-access-command-editors.ts +108 -128
- package/src/input/agent-workspace-activation.ts +15 -0
- package/src/input/agent-workspace-basic-command-editor-submission.ts +292 -513
- package/src/input/agent-workspace-basic-command-editors.ts +433 -564
- package/src/input/agent-workspace-calendar-connect-editor.ts +116 -0
- package/src/input/agent-workspace-calendar-oauth-editor.ts +152 -0
- package/src/input/agent-workspace-calendar-subscribe-editor.ts +128 -0
- package/src/input/agent-workspace-categories.ts +7 -2
- package/src/input/agent-workspace-channel-command-editor-submission.ts +38 -52
- package/src/input/agent-workspace-channel-command-editors.ts +42 -46
- package/src/input/agent-workspace-command-editor-engine.ts +133 -0
- package/src/input/agent-workspace-command-editor.ts +4 -0
- package/src/input/agent-workspace-direct-editor-submission.ts +59 -0
- package/src/input/agent-workspace-email-connect-editor.ts +162 -0
- package/src/input/agent-workspace-knowledge-command-editor-submission.ts +52 -81
- package/src/input/agent-workspace-knowledge-command-editors.ts +71 -71
- package/src/input/agent-workspace-library-command-editor-submission.ts +10 -28
- package/src/input/agent-workspace-library-command-editors.ts +16 -2
- package/src/input/agent-workspace-live-counters.ts +55 -0
- package/src/input/agent-workspace-mcp-command-editor-submission.ts +60 -82
- package/src/input/agent-workspace-mcp-command-editors.ts +52 -0
- package/src/input/agent-workspace-media-command-editor-submission.ts +12 -39
- package/src/input/agent-workspace-media-command-editors.ts +10 -8
- package/src/input/agent-workspace-memory-command-editor-submission.ts +76 -151
- package/src/input/agent-workspace-memory-command-editors.ts +116 -141
- package/src/input/agent-workspace-operations-command-editor-submission.ts +131 -184
- package/src/input/agent-workspace-operations-command-editors.ts +150 -162
- package/src/input/agent-workspace-provider-command-editor-submission.ts +60 -106
- package/src/input/agent-workspace-provider-command-editors.ts +58 -68
- package/src/input/agent-workspace-search.ts +8 -1
- package/src/input/agent-workspace-session-command-editor-submission.ts +104 -132
- package/src/input/agent-workspace-session-command-editors.ts +160 -195
- package/src/input/agent-workspace-settings.ts +40 -1
- package/src/input/agent-workspace-skill-bundle-command-editor-submission.ts +55 -71
- package/src/input/agent-workspace-skill-bundle-command-editors.ts +65 -69
- package/src/input/agent-workspace-snapshot-builders.ts +431 -0
- package/src/input/agent-workspace-snapshot-config.ts +43 -0
- package/src/input/agent-workspace-snapshot.ts +198 -432
- package/src/input/agent-workspace-task-command-editor-submission.ts +34 -44
- package/src/input/agent-workspace-task-command-editors.ts +27 -28
- package/src/input/agent-workspace-types.ts +35 -1
- package/src/input/agent-workspace.ts +5 -14
- package/src/input/command-registry.ts +23 -1
- package/src/input/commands/calendar-connect-runtime.ts +226 -0
- package/src/input/commands/calendar-runtime.ts +110 -7
- package/src/input/commands/calendar-subscription-runtime.ts +225 -0
- package/src/input/commands/email-runtime.ts +100 -40
- package/src/input/commands/knowledge.ts +1 -1
- package/src/input/commands/network-scan-runtime.ts +75 -0
- package/src/input/commands/operator-actions-runtime.ts +9 -6
- package/src/input/commands/personas-runtime.ts +1 -1
- package/src/input/commands/schedule-runtime.ts +4 -4
- package/src/input/commands/session-content.ts +13 -1
- package/src/input/commands/session-workflow.ts +15 -20
- package/src/input/commands/session.ts +3 -1
- package/src/input/commands/shell-core.ts +20 -6
- package/src/input/commands.ts +2 -2
- package/src/input/delete-key-policy.ts +46 -0
- package/src/input/feed-context-factory.ts +10 -0
- package/src/input/handler-feed.ts +87 -0
- package/src/input/handler-modal-routes.ts +6 -1
- package/src/input/handler.ts +5 -0
- package/src/input/panel-paste-flood-guard.ts +94 -0
- package/src/input/settings-modal-types.ts +5 -3
- package/src/input/settings-modal.ts +21 -0
- package/src/main.ts +36 -36
- package/src/permissions/approval-posture.ts +141 -0
- package/src/renderer/agent-workspace-context-lines.ts +10 -2
- package/src/renderer/compositor.ts +27 -4
- package/src/renderer/diff.ts +61 -18
- package/src/renderer/fullscreen-primitives.ts +37 -18
- package/src/renderer/markdown.ts +20 -10
- package/src/renderer/modal-factory.ts +25 -15
- package/src/renderer/overlay-box.ts +23 -12
- package/src/renderer/process-indicator.ts +8 -3
- package/src/renderer/prompt-content-width.ts +16 -0
- package/src/renderer/settings-modal-helpers.ts +2 -0
- package/src/renderer/settings-modal.ts +2 -0
- package/src/renderer/startup-theme-probe.ts +35 -0
- package/src/renderer/status-glyphs.ts +11 -15
- package/src/renderer/system-message.ts +17 -2
- package/src/renderer/term-caps.ts +318 -0
- package/src/renderer/terminal-bg-probe.ts +373 -0
- package/src/renderer/terminal-escapes.ts +24 -0
- package/src/renderer/theme-mode-config.ts +87 -0
- package/src/renderer/theme.ts +241 -0
- package/src/renderer/thinking.ts +12 -3
- package/src/renderer/tool-call.ts +7 -3
- package/src/renderer/ui-factory.ts +92 -36
- package/src/renderer/ui-primitives.ts +33 -93
- package/src/runtime/bootstrap-core.ts +15 -0
- package/src/runtime/bootstrap-hook-bridge.ts +6 -0
- package/src/runtime/bootstrap-shell.ts +2 -0
- package/src/runtime/bootstrap.ts +68 -5
- package/src/runtime/calendar-boot-refresh.ts +105 -0
- package/src/runtime/lan-scan-consent.ts +253 -0
- package/src/runtime/services.ts +127 -2
- package/src/runtime/session-spine-rest-transport.ts +160 -0
- package/src/runtime/terminal-output-guard.ts +6 -1
- package/src/runtime/ui-services.ts +3 -0
- package/src/shell/agent-workspace-fullscreen.ts +5 -0
- package/src/shell/terminal-focus-mode.ts +120 -0
- package/src/shell/ui-openers.ts +13 -4
- package/src/tools/agent-harness-autonomy-intake.ts +5 -5
- package/src/tools/agent-harness-autonomy-queue.ts +1 -1
- package/src/tools/agent-harness-background-processes.ts +2 -1
- package/src/tools/agent-harness-metadata.ts +16 -8
- package/src/tools/agent-harness-operator-methods.ts +44 -8
- package/src/tools/agent-harness-personal-ops-discovery.ts +57 -10
- package/src/tools/agent-harness-personal-ops-lanes.ts +17 -5
- package/src/tools/agent-harness-personal-ops-operations.ts +7 -7
- package/src/tools/agent-harness-personal-ops-types.ts +6 -0
- package/src/tools/agent-harness-prompt-context.ts +26 -12
- package/src/tools/agent-harness-workspace-actions.ts +4 -0
- package/src/tools/agent-local-registry-args.ts +117 -0
- package/src/tools/agent-local-registry-memory.ts +227 -0
- package/src/tools/agent-local-registry-tool.ts +19 -237
- package/src/tools/agent-operator-briefing-tool.ts +2 -2
- package/src/tools/agent-operator-method-tool.ts +13 -0
- package/src/tools/agent-policy-explanation.ts +39 -4
- package/src/tools/agent-schedule-tool.ts +5 -5
- package/src/utils/terminal-width.ts +98 -1
- package/src/version.ts +1 -1
- package/src/cli/local-library-command.ts +0 -825
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Calendar connect card (W4-A5) — promotes the "Calendar workflows" workspace
|
|
3
|
+
* card from a dead guidance card into a real, dispatchable action.
|
|
4
|
+
*
|
|
5
|
+
* GROUNDED: unlike email, there is no external calendar account/CalDAV
|
|
6
|
+
* connector anywhere in this codebase (no config schema, no credential path,
|
|
7
|
+
* no service — /calendar is a purely local .ics-backed event store,
|
|
8
|
+
* src/agent/calendar-registry.ts + src/input/commands/calendar-runtime.ts).
|
|
9
|
+
* Building a credential-capturing "connect wizard" for a service that does
|
|
10
|
+
* not exist would repeat exactly the dogfood finding this brief fixes
|
|
11
|
+
* (advertising a capability that isn't dispatchable). The honest promotion
|
|
12
|
+
* is: a real stepped form that adds a LOCAL calendar event through the
|
|
13
|
+
* existing, already-safe /calendar add command — no credentials involved —
|
|
14
|
+
* with the card's own wording stating plainly that this is local-only.
|
|
15
|
+
*
|
|
16
|
+
* This follows the ordinary generic command-editor pattern (like
|
|
17
|
+
* agent-workspace-reminder-schedule-editor.ts): build one command string,
|
|
18
|
+
* dispatch it through the shell-owned command router. No secret ever touches
|
|
19
|
+
* this path, so the command-string leak class documented in
|
|
20
|
+
* agent-workspace-email-connect-editor.ts does not apply here.
|
|
21
|
+
*/
|
|
22
|
+
import type { AgentWorkspaceActionResult, AgentWorkspaceLocalEditor } from './agent-workspace-types.ts';
|
|
23
|
+
import { isAffirmative } from './agent-workspace-editors.ts';
|
|
24
|
+
import { quoteSlashCommandArg } from './slash-command-parser.ts';
|
|
25
|
+
|
|
26
|
+
type FieldReader = (fieldId: string) => string;
|
|
27
|
+
|
|
28
|
+
export type AgentCalendarConnectEditorSubmission =
|
|
29
|
+
| {
|
|
30
|
+
readonly kind: 'editor';
|
|
31
|
+
readonly editor: AgentWorkspaceLocalEditor;
|
|
32
|
+
readonly status: string;
|
|
33
|
+
readonly actionResult?: AgentWorkspaceActionResult;
|
|
34
|
+
}
|
|
35
|
+
| {
|
|
36
|
+
readonly kind: 'dispatch';
|
|
37
|
+
readonly command: string;
|
|
38
|
+
readonly status: string;
|
|
39
|
+
readonly actionResult: AgentWorkspaceActionResult;
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
export function createCalendarConnectEditor(): AgentWorkspaceLocalEditor {
|
|
43
|
+
return {
|
|
44
|
+
kind: 'calendar-connect',
|
|
45
|
+
mode: 'create',
|
|
46
|
+
title: 'Add Calendar Event',
|
|
47
|
+
selectedFieldIndex: 0,
|
|
48
|
+
message: 'No external calendar account is connected in this build (no CalDAV/Google/Outlook sync) — this adds an event to your local Agent calendar. Type yes on the final field to confirm.',
|
|
49
|
+
fields: [
|
|
50
|
+
{ id: 'title', label: 'Title', value: '', required: true, multiline: false, hint: 'Event title.' },
|
|
51
|
+
{ id: 'start', label: 'Start', value: '', required: true, multiline: false, hint: 'ISO date or datetime, for example 2026-08-01T09:00:00-05:00.' },
|
|
52
|
+
{ id: 'end', label: 'End', value: '', required: false, multiline: false, hint: 'Optional ISO end date or datetime.' },
|
|
53
|
+
{ id: 'location', label: 'Location', value: '', required: false, multiline: false, hint: 'Optional location.' },
|
|
54
|
+
{ id: 'notes', label: 'Notes', value: '', required: false, multiline: true, hint: 'Optional notes. Ctrl-J inserts a new line.' },
|
|
55
|
+
{ id: 'confirm', label: 'Confirm', value: '', required: true, multiline: false, hint: 'Type yes to run /calendar add with --yes.' },
|
|
56
|
+
],
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
export function buildAgentWorkspaceCalendarConnectEditorSubmission(
|
|
61
|
+
editor: AgentWorkspaceLocalEditor,
|
|
62
|
+
readField: FieldReader,
|
|
63
|
+
commandDispatchAvailable: boolean,
|
|
64
|
+
): AgentCalendarConnectEditorSubmission {
|
|
65
|
+
if (!isAffirmative(readField('confirm'))) {
|
|
66
|
+
return {
|
|
67
|
+
kind: 'editor',
|
|
68
|
+
editor: { ...editor, message: 'Type yes to confirm adding this calendar event.' },
|
|
69
|
+
status: 'Calendar event not confirmed.',
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
if (!commandDispatchAvailable) {
|
|
73
|
+
const detail = 'Command dispatch is unavailable; cannot add a calendar event from this workspace.';
|
|
74
|
+
return {
|
|
75
|
+
kind: 'editor',
|
|
76
|
+
editor: { ...editor, message: detail },
|
|
77
|
+
status: detail,
|
|
78
|
+
actionResult: { kind: 'error', title: 'Command dispatch unavailable', detail, safety: 'safe' },
|
|
79
|
+
};
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
const title = readField('title').trim();
|
|
83
|
+
const start = readField('start').trim();
|
|
84
|
+
if (!title || !start) {
|
|
85
|
+
const detail = 'Title and start are required.';
|
|
86
|
+
return {
|
|
87
|
+
kind: 'editor',
|
|
88
|
+
editor: { ...editor, message: detail },
|
|
89
|
+
status: detail,
|
|
90
|
+
actionResult: { kind: 'error', title: 'Calendar event incomplete', detail, safety: 'safe' },
|
|
91
|
+
};
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
const parts = ['/calendar', 'add', '--title', quoteSlashCommandArg(title), '--start', quoteSlashCommandArg(start)];
|
|
95
|
+
const end = readField('end').trim();
|
|
96
|
+
if (end.length > 0) parts.push('--end', quoteSlashCommandArg(end));
|
|
97
|
+
const location = readField('location').trim();
|
|
98
|
+
if (location.length > 0) parts.push('--location', quoteSlashCommandArg(location));
|
|
99
|
+
const notes = readField('notes').trim();
|
|
100
|
+
if (notes.length > 0) parts.push('--notes', quoteSlashCommandArg(notes));
|
|
101
|
+
parts.push('--yes');
|
|
102
|
+
const command = parts.join(' ');
|
|
103
|
+
|
|
104
|
+
return {
|
|
105
|
+
kind: 'dispatch',
|
|
106
|
+
command,
|
|
107
|
+
status: 'Adding calendar event.',
|
|
108
|
+
actionResult: {
|
|
109
|
+
kind: 'dispatched',
|
|
110
|
+
title: 'Adding calendar event',
|
|
111
|
+
detail: 'The workspace handed a confirmed local calendar event command to the shell-owned command router. This is a local calendar only — no external account is connected.',
|
|
112
|
+
command,
|
|
113
|
+
safety: 'safe',
|
|
114
|
+
},
|
|
115
|
+
};
|
|
116
|
+
}
|
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Calendar OAuth advanced-credentials wizard (W4-A10).
|
|
3
|
+
*
|
|
4
|
+
* The DEFAULT connect experience needs no card at all: `/calendar connect google`
|
|
5
|
+
* (or `outlook`) uses the bundled project client id + PKCE and opens the browser.
|
|
6
|
+
* This card is the ADVANCED override for power users who register their own app: it
|
|
7
|
+
* captures a client id and (optionally) a client secret, stores them the same way
|
|
8
|
+
* every other Agent credential is stored (id in config, secret through the secret
|
|
9
|
+
* manager, never in plain config, never in a command string), then directs the user
|
|
10
|
+
* to run the connect command to authorize.
|
|
11
|
+
*
|
|
12
|
+
* Security: like the email connect wizard, this is a DIRECT host action, not a slash
|
|
13
|
+
* command — the client secret never travels through the command-dispatch pipeline
|
|
14
|
+
* that echoes the command string into the rendered result. The OAuth network dance
|
|
15
|
+
* (auth URL / device code) lives in the /calendar connect command, which can print
|
|
16
|
+
* the URL/code immediately; this card only persists credentials.
|
|
17
|
+
*/
|
|
18
|
+
import type { CommandContext } from './command-registry.ts';
|
|
19
|
+
import { isAffirmative } from './agent-workspace-editors.ts';
|
|
20
|
+
import { requireSecretsManager } from './commands/runtime-services.ts';
|
|
21
|
+
import { persistSecretBackedConfigValue } from '../config/secret-config.ts';
|
|
22
|
+
import type { ConfigKey } from '../config/index.ts';
|
|
23
|
+
import {
|
|
24
|
+
CALENDAR_OAUTH_CLIENT_ID_KEYS,
|
|
25
|
+
CALENDAR_OAUTH_CLIENT_SECRET_KEYS,
|
|
26
|
+
ensureCalendarConfigDefaults,
|
|
27
|
+
} from '../agent/calendar/calendar-oauth-service.ts';
|
|
28
|
+
import type { AgentWorkspaceActionResult, AgentWorkspaceEditorKind, AgentWorkspaceLocalEditor } from './agent-workspace-types.ts';
|
|
29
|
+
|
|
30
|
+
type FieldReader = (id: string) => string;
|
|
31
|
+
type Provider = 'google' | 'microsoft';
|
|
32
|
+
|
|
33
|
+
export interface AgentWorkspaceCalendarOAuthEditorHost {
|
|
34
|
+
localEditor: AgentWorkspaceLocalEditor | null;
|
|
35
|
+
status: string;
|
|
36
|
+
lastActionResult: AgentWorkspaceActionResult | null;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/** Honest, no-I/O calendar-OAuth build state per provider — true once a client id override is stored (F1c). */
|
|
40
|
+
export interface AgentWorkspaceCalendarOAuthConfigStatus {
|
|
41
|
+
readonly google: boolean;
|
|
42
|
+
readonly microsoft: boolean;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
const PROVIDER_LABEL: Record<Provider, string> = { google: 'Google Calendar', microsoft: 'Microsoft Outlook' };
|
|
46
|
+
const CONNECT_HINT: Record<Provider, string> = { google: '/calendar connect google', microsoft: '/calendar connect outlook' };
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Build-state-aware card message (F1c): while the build still ships only the
|
|
50
|
+
* bundled SDK placeholder client id, /calendar connect always fails at the
|
|
51
|
+
* config stage, so the old "most people can skip this" wording was a dead
|
|
52
|
+
* end. Once a client id has been stored (through this same card), the
|
|
53
|
+
* original skip-this-if-you-don't-need-it wording applies again.
|
|
54
|
+
*/
|
|
55
|
+
function cardMessage(label: string, isConfigured: boolean): string {
|
|
56
|
+
if (!isConfigured) {
|
|
57
|
+
return (
|
|
58
|
+
`This build needs a client id to connect ${label} — it ships no project default yet. ` +
|
|
59
|
+
'Enter your own below, or follow these steps: register a free OAuth app with the provider ' +
|
|
60
|
+
'(Google Cloud Console, or the Azure portal for Microsoft), copy the client id it gives you ' +
|
|
61
|
+
'(no client secret needed for the desktop/public-client flow), then paste it in here. ' +
|
|
62
|
+
'A client secret (only for a confidential-client registration) is stored through the Agent ' +
|
|
63
|
+
'secret manager and never shown again.'
|
|
64
|
+
);
|
|
65
|
+
}
|
|
66
|
+
return (
|
|
67
|
+
`Advanced: use your OWN registered ${label} app instead of the bundled default. ` +
|
|
68
|
+
'Most people can skip this and just run the connect command. The client id is not a ' +
|
|
69
|
+
'secret; a client secret (only for a confidential-client registration) is stored through ' +
|
|
70
|
+
'the Agent secret manager and never shown again.'
|
|
71
|
+
);
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/** The advanced-credentials wizard for one provider. */
|
|
75
|
+
export function createCalendarOAuthEditor(provider: Provider, isConfigured = false): AgentWorkspaceLocalEditor {
|
|
76
|
+
const label = PROVIDER_LABEL[provider];
|
|
77
|
+
const kind: AgentWorkspaceEditorKind = provider === 'google' ? 'calendar-oauth-google' : 'calendar-oauth-outlook';
|
|
78
|
+
return {
|
|
79
|
+
kind,
|
|
80
|
+
mode: 'create',
|
|
81
|
+
title: `Connect ${label} (advanced)`,
|
|
82
|
+
selectedFieldIndex: 0,
|
|
83
|
+
message: cardMessage(label, isConfigured),
|
|
84
|
+
fields: [
|
|
85
|
+
{ id: 'clientId', label: 'Client ID', value: '', required: true, multiline: false, hint: `Your ${label} OAuth client id (Desktop/public client needs no secret).` },
|
|
86
|
+
{ id: 'clientSecret', label: 'Client secret (optional)', value: '', required: false, multiline: false, hint: 'Only for a confidential-client app. Stored through the secret manager, masked here.', redact: true },
|
|
87
|
+
{ id: 'confirm', label: 'Confirm', value: '', required: true, multiline: false, hint: `Type yes to store these credentials, then run ${CONNECT_HINT[provider]} to authorize.` },
|
|
88
|
+
],
|
|
89
|
+
};
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
export async function submitAgentWorkspaceCalendarOAuthEditor(
|
|
93
|
+
host: AgentWorkspaceCalendarOAuthEditorHost,
|
|
94
|
+
editor: AgentWorkspaceLocalEditor,
|
|
95
|
+
context: CommandContext | null,
|
|
96
|
+
readField: FieldReader,
|
|
97
|
+
): Promise<void> {
|
|
98
|
+
const provider: Provider = editor.kind === 'calendar-oauth-outlook' ? 'microsoft' : 'google';
|
|
99
|
+
const label = PROVIDER_LABEL[provider];
|
|
100
|
+
|
|
101
|
+
if (!isAffirmative(readField('confirm'))) {
|
|
102
|
+
host.localEditor = { ...editor, message: 'Credentials not confirmed. Type yes, then press Enter.' };
|
|
103
|
+
host.status = 'Calendar credentials not confirmed.';
|
|
104
|
+
return;
|
|
105
|
+
}
|
|
106
|
+
if (!context) {
|
|
107
|
+
host.localEditor = { ...editor, message: 'This runtime has no command context; cannot store credentials.' };
|
|
108
|
+
host.status = 'Calendar connect unavailable.';
|
|
109
|
+
host.lastActionResult = { kind: 'error', title: 'Calendar connect unavailable', detail: 'No command context is available in this runtime.', safety: 'safe' };
|
|
110
|
+
return;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
const clientId = readField('clientId').trim();
|
|
114
|
+
if (!clientId) {
|
|
115
|
+
host.localEditor = { ...editor, message: 'A client id is required for the advanced path.' };
|
|
116
|
+
host.status = 'Client id is required.';
|
|
117
|
+
return;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
try {
|
|
121
|
+
const secretsManager = requireSecretsManager(context);
|
|
122
|
+
ensureCalendarConfigDefaults(context.platform.configManager);
|
|
123
|
+
const cm = context.platform.configManager as unknown as {
|
|
124
|
+
get: (key: ConfigKey) => unknown;
|
|
125
|
+
setDynamic: (key: ConfigKey, value: unknown) => void;
|
|
126
|
+
save: () => void;
|
|
127
|
+
};
|
|
128
|
+
// Client id is not a secret — a plain config value.
|
|
129
|
+
cm.setDynamic(CALENDAR_OAUTH_CLIENT_ID_KEYS[provider] as unknown as ConfigKey, clientId);
|
|
130
|
+
// Client secret (if any) goes through the secret-backed path: a ref in config,
|
|
131
|
+
// the raw value only in the secret manager.
|
|
132
|
+
const secret = readField('clientSecret');
|
|
133
|
+
if (secret.trim().length > 0) {
|
|
134
|
+
await persistSecretBackedConfigValue(cm, secretsManager, CALENDAR_OAUTH_CLIENT_SECRET_KEYS[provider] as unknown as ConfigKey, secret);
|
|
135
|
+
}
|
|
136
|
+
cm.save();
|
|
137
|
+
|
|
138
|
+
host.localEditor = null;
|
|
139
|
+
host.status = `${label} credentials stored.`;
|
|
140
|
+
host.lastActionResult = {
|
|
141
|
+
kind: 'refreshed',
|
|
142
|
+
title: `${label} credentials stored`,
|
|
143
|
+
detail: `Your ${label} client id was saved${secret.trim() ? ' (and the client secret through the secret manager)' : ''}. Run ${CONNECT_HINT[provider]} to open the browser and authorize.`,
|
|
144
|
+
safety: 'safe',
|
|
145
|
+
};
|
|
146
|
+
} catch (error) {
|
|
147
|
+
const detail = error instanceof Error ? error.message : String(error);
|
|
148
|
+
host.localEditor = { ...editor, message: detail };
|
|
149
|
+
host.status = detail;
|
|
150
|
+
host.lastActionResult = { kind: 'error', title: 'Calendar credentials not stored', detail, safety: 'safe' };
|
|
151
|
+
}
|
|
152
|
+
}
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Calendar subscribe wizard (W4-A9) — the "Calendar workflows" card's real
|
|
3
|
+
* connect flow. Subscribes to an external calendar by its iCalendar feed URL
|
|
4
|
+
* (Google "secret address", Outlook published .ics, or any .ics URL), READ-ONLY.
|
|
5
|
+
*
|
|
6
|
+
* Security: the feed URL is secrets-adjacent — a Google secret address grants
|
|
7
|
+
* read access to the whole calendar — so this follows the email-connect wizard's
|
|
8
|
+
* pattern EXACTLY: it is a DIRECT host action (not a slash-command string), so the
|
|
9
|
+
* URL never flows through the generic dispatch pipeline that echoes command text
|
|
10
|
+
* back into the workspace UI (which would render the secret). The URL is persisted
|
|
11
|
+
* ONLY through the secret manager (CalendarSubscriptionRegistry stores it under a
|
|
12
|
+
* per-subscription secret key; the on-disk store holds the key, never the URL) and
|
|
13
|
+
* the field is masked (`redact: true`). Validation fetches the feed BEFORE saving
|
|
14
|
+
* and names the failing stage honestly (fetch vs parse); the URL/name are kept so
|
|
15
|
+
* nothing is retyped.
|
|
16
|
+
*/
|
|
17
|
+
import type { CommandContext } from './command-registry.ts';
|
|
18
|
+
import { isAffirmative } from './agent-workspace-editors.ts';
|
|
19
|
+
import { subscriptionRegistryForWrite } from './commands/calendar-subscription-runtime.ts';
|
|
20
|
+
import type { CalendarSubscriptionRegistry } from '../agent/calendar-subscription-registry.ts';
|
|
21
|
+
import { buildAgentWorkspaceRuntimeSnapshot } from './agent-workspace-snapshot.ts';
|
|
22
|
+
import type { AgentWorkspaceActionResult, AgentWorkspaceLocalEditor, AgentWorkspaceRuntimeSnapshot } from './agent-workspace-types.ts';
|
|
23
|
+
|
|
24
|
+
type FieldReader = (id: string) => string;
|
|
25
|
+
|
|
26
|
+
export interface AgentWorkspaceCalendarSubscribeEditorHost {
|
|
27
|
+
localEditor: AgentWorkspaceLocalEditor | null;
|
|
28
|
+
runtimeSnapshot: AgentWorkspaceRuntimeSnapshot | null;
|
|
29
|
+
status: string;
|
|
30
|
+
lastActionResult: AgentWorkspaceActionResult | null;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/** Fields in wizard-step order. The URL is masked and secrets-adjacent. */
|
|
34
|
+
export function createCalendarSubscribeWizardEditor(): AgentWorkspaceLocalEditor {
|
|
35
|
+
return {
|
|
36
|
+
kind: 'calendar-subscribe-wizard',
|
|
37
|
+
mode: 'create',
|
|
38
|
+
title: 'Subscribe to a Calendar',
|
|
39
|
+
selectedFieldIndex: 0,
|
|
40
|
+
message: [
|
|
41
|
+
'Subscribe to an external calendar by its iCalendar (.ics) feed URL — read-only, merged into /calendar.',
|
|
42
|
+
'Google: Settings → your calendar → "Secret address in iCal format" — copy that URL.',
|
|
43
|
+
'Outlook: Settings → Calendar → Shared calendars → Publish → copy the ICS link.',
|
|
44
|
+
'Any .ics URL works too. The URL is stored through the Agent secret manager (a secret address grants read access), and validated by fetching before it is saved.',
|
|
45
|
+
].join('\n'),
|
|
46
|
+
fields: [
|
|
47
|
+
{ id: 'url', label: 'Feed URL', value: '', required: true, multiline: false, hint: 'The .ics feed URL. Stored as a secret; masked here and never rendered in results.', redact: true },
|
|
48
|
+
{ id: 'name', label: 'Name', value: '', required: false, multiline: false, hint: 'Optional. Left blank, the calendar\'s own name is used.' },
|
|
49
|
+
{ id: 'confirm', label: 'Confirm', value: '', required: true, multiline: false, hint: 'Type yes to validate the feed and subscribe.' },
|
|
50
|
+
],
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/** Injectable for tests — production callers omit it and get the real registry (real HTTP fetch). */
|
|
55
|
+
export type CalendarSubscribeRegistryBuilder = (context: CommandContext) => CalendarSubscriptionRegistry | null;
|
|
56
|
+
|
|
57
|
+
const defaultRegistryBuilder: CalendarSubscribeRegistryBuilder = (context) => subscriptionRegistryForWrite(context);
|
|
58
|
+
|
|
59
|
+
export async function submitAgentWorkspaceCalendarSubscribeWizardEditor(
|
|
60
|
+
host: AgentWorkspaceCalendarSubscribeEditorHost,
|
|
61
|
+
editor: AgentWorkspaceLocalEditor,
|
|
62
|
+
context: CommandContext | null,
|
|
63
|
+
readField: FieldReader,
|
|
64
|
+
buildRegistry: CalendarSubscribeRegistryBuilder = defaultRegistryBuilder,
|
|
65
|
+
): Promise<void> {
|
|
66
|
+
if (!isAffirmative(readField('confirm'))) {
|
|
67
|
+
host.localEditor = { ...editor, message: 'Calendar subscription not confirmed. Type yes, then press Enter.' };
|
|
68
|
+
host.status = 'Calendar subscription not confirmed.';
|
|
69
|
+
return;
|
|
70
|
+
}
|
|
71
|
+
if (!context) {
|
|
72
|
+
const detail = 'This runtime has no command context; cannot subscribe to a calendar.';
|
|
73
|
+
host.localEditor = { ...editor, message: detail };
|
|
74
|
+
host.status = 'Calendar subscribe unavailable.';
|
|
75
|
+
host.lastActionResult = { kind: 'error', title: 'Calendar subscribe unavailable', detail, safety: 'safe' };
|
|
76
|
+
return;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
const url = readField('url').trim();
|
|
80
|
+
if (!url) {
|
|
81
|
+
const detail = 'A feed URL is required.';
|
|
82
|
+
host.localEditor = { ...editor, message: detail };
|
|
83
|
+
host.status = detail;
|
|
84
|
+
host.lastActionResult = { kind: 'error', title: 'Calendar subscribe incomplete', detail, safety: 'safe' };
|
|
85
|
+
return;
|
|
86
|
+
}
|
|
87
|
+
const requestedName = readField('name').trim() || undefined;
|
|
88
|
+
|
|
89
|
+
try {
|
|
90
|
+
const registry = buildRegistry(context);
|
|
91
|
+
if (!registry) {
|
|
92
|
+
const detail = 'No secret manager is available in this runtime, and a feed URL is stored only as a secret. Cannot subscribe.';
|
|
93
|
+
host.localEditor = { ...editor, message: detail };
|
|
94
|
+
host.status = 'Calendar subscribe unavailable.';
|
|
95
|
+
host.lastActionResult = { kind: 'error', title: 'Calendar subscribe unavailable', detail, safety: 'safe' };
|
|
96
|
+
return;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
const result = await registry.subscribe(url, requestedName);
|
|
100
|
+
if (!result.ok) {
|
|
101
|
+
// Settings kept so the URL/name are not retyped; the stage is named honestly.
|
|
102
|
+
host.localEditor = { ...editor, message: `Could not subscribe (${result.stage} stage): ${result.detail}` };
|
|
103
|
+
host.status = `Calendar subscription failed (${result.stage}).`;
|
|
104
|
+
host.lastActionResult = {
|
|
105
|
+
kind: 'error',
|
|
106
|
+
title: 'Calendar subscription failed',
|
|
107
|
+
detail: `Could not subscribe at the ${result.stage} stage: ${result.detail}. The URL was not saved — fix it above and try again.`,
|
|
108
|
+
safety: 'safe',
|
|
109
|
+
};
|
|
110
|
+
return;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
host.localEditor = null;
|
|
114
|
+
host.status = `Subscribed to ${result.name}.`;
|
|
115
|
+
host.lastActionResult = {
|
|
116
|
+
kind: 'refreshed',
|
|
117
|
+
title: 'Calendar subscribed',
|
|
118
|
+
detail: `Subscribed to '${result.name}' (${result.eventCount} events, refresh every ${Math.round(result.refreshIntervalMs / 60000)} min). These events are read-only and appear source-labeled in /calendar.`,
|
|
119
|
+
safety: 'safe',
|
|
120
|
+
};
|
|
121
|
+
host.runtimeSnapshot = buildAgentWorkspaceRuntimeSnapshot(context);
|
|
122
|
+
} catch (error) {
|
|
123
|
+
const detail = error instanceof Error ? error.message : String(error);
|
|
124
|
+
host.localEditor = { ...editor, message: detail };
|
|
125
|
+
host.status = detail;
|
|
126
|
+
host.lastActionResult = { kind: 'error', title: 'Calendar subscribe failed', detail, safety: 'safe' };
|
|
127
|
+
}
|
|
128
|
+
}
|
|
@@ -2,6 +2,7 @@ import type { AgentWorkspaceCategory } from './agent-workspace-types.ts';
|
|
|
2
2
|
import { settingAction } from './agent-workspace-category-actions.ts';
|
|
3
3
|
import { AGENT_WORKSPACE_HOST_CATEGORY } from './agent-workspace-host-category.ts';
|
|
4
4
|
import { AGENT_WORKSPACE_ONBOARDING_DETAIL_CATEGORIES } from './agent-workspace-onboarding-categories.ts';
|
|
5
|
+
import { THEME_MODE_CONFIG_KEY } from '../renderer/theme-mode-config.ts';
|
|
5
6
|
|
|
6
7
|
export const AGENT_WORKSPACE_CATEGORIES: readonly AgentWorkspaceCategory[] = [
|
|
7
8
|
{
|
|
@@ -134,6 +135,7 @@ export const AGENT_WORKSPACE_CATEGORIES: readonly AgentWorkspaceCategory[] = [
|
|
|
134
135
|
actions: [
|
|
135
136
|
settingAction({ id: 'display-stream', label: 'Stream tokens', detail: 'Toggle streaming assistant tokens as they arrive.', key: 'display.stream' }),
|
|
136
137
|
settingAction({ id: 'display-theme', label: 'Theme', detail: 'Set the color theme name.', key: 'display.theme' }),
|
|
138
|
+
settingAction({ id: 'display-theme-mode', label: 'Theme mode', detail: 'Cycle auto, dark, or light for the terminal background. Forced dark/light apply immediately; switching to auto takes effect on the next launch, when it re-probes the terminal.', key: THEME_MODE_CONFIG_KEY }),
|
|
137
139
|
settingAction({ id: 'display-line-numbers', label: 'Line numbers', detail: 'Cycle all, code-only, or off for assistant output line numbers.', key: 'display.lineNumbers' }),
|
|
138
140
|
settingAction({ id: 'display-collapse-threshold', label: 'Collapse threshold', detail: 'Set the line count threshold for collapsed tool output.', key: 'display.collapseThreshold' }),
|
|
139
141
|
settingAction({ id: 'display-token-speed', label: 'Token speed counter', detail: 'Toggle tokens-per-second while generating.', key: 'display.showTokenSpeed' }),
|
|
@@ -156,8 +158,11 @@ export const AGENT_WORKSPACE_CATEGORIES: readonly AgentWorkspaceCategory[] = [
|
|
|
156
158
|
{ id: 'personal-ops-queue', label: 'Review queue', detail: 'List saved inbox thread and calendar event review items, refreshable provider-read routes, and follow-up confirmation boundaries with personal_ops action:"queue".', kind: 'guidance', safety: 'read-only' },
|
|
157
159
|
{ id: 'personal-ops-intake', label: 'Request planner', detail: 'Use personal_ops action:"intake" query:"..." to turn an inbox, agenda, task, reminder, note, routine, or delivery request into the safest visible route.', kind: 'guidance', safety: 'read-only' },
|
|
158
160
|
{ id: 'personal-ops-autonomy-queue', label: 'Autonomy queue', detail: 'Inspect visible ongoing work, owners, status, and cancel or recovery routes before creating more background work.', kind: 'guidance', safety: 'read-only' },
|
|
159
|
-
{ id: 'personal-ops-inbox', label: 'Inbox workflows', detail: '
|
|
160
|
-
{ id: 'personal-ops-calendar', label: '
|
|
161
|
+
{ id: 'personal-ops-inbox', label: 'Inbox workflows', detail: 'Connect your inbox (IMAP/SMTP) to enable email triage and draft review. Opens a stepped connect wizard; credentials are stored through the Agent secret manager.', editorKind: 'email-connect-wizard', kind: 'editor', safety: 'safe' },
|
|
162
|
+
{ id: 'personal-ops-calendar', label: 'Subscribe to a calendar', detail: 'Subscribe to an external calendar by its iCalendar (.ics) feed URL — Google "Secret address in iCal format", an Outlook published ICS link, or any .ics URL. Read-only, validated by fetching, merged into /calendar. The URL is stored through the Agent secret manager.', editorKind: 'calendar-subscribe-wizard', kind: 'editor', safety: 'safe' },
|
|
163
|
+
{ id: 'personal-ops-calendar-add', label: 'Add calendar event', detail: 'Add an event to the local Agent calendar with a stepped form (no external account required).', editorKind: 'calendar-connect', kind: 'editor', safety: 'safe' },
|
|
164
|
+
{ id: 'personal-ops-calendar-google', label: 'Connect Google Calendar (advanced)', detail: 'Full two-way sync via OAuth. Default path: just run /calendar connect google (bundled app + PKCE). This card is the advanced override to use your OWN Google OAuth client id; a client secret is stored through the Agent secret manager.', editorKind: 'calendar-oauth-google', kind: 'editor', safety: 'safe' },
|
|
165
|
+
{ id: 'personal-ops-calendar-outlook', label: 'Connect Microsoft Outlook (advanced)', detail: 'Full two-way sync via OAuth. Default path: just run /calendar connect outlook (bundled app + PKCE). This card is the advanced override to use your OWN Microsoft app registration; a client secret is stored through the Agent secret manager.', editorKind: 'calendar-oauth-outlook', kind: 'editor', safety: 'safe' },
|
|
161
166
|
{ id: 'personal-ops-notes', label: 'Scratchpad notes', detail: 'Open Agent-local notes for source triage, decisions, and handoff context.', targetCategoryId: 'notes', kind: 'workspace', safety: 'safe' },
|
|
162
167
|
{ id: 'personal-ops-note-create', label: 'Create note', detail: 'Capture temporary context as an Agent-local scratchpad note.', editorKind: 'note', kind: 'editor', safety: 'safe' },
|
|
163
168
|
{ id: 'personal-ops-reminder', label: 'Create reminder', detail: 'Create one connected reminder schedule with real timing, optional delivery target, and explicit confirmation.', editorKind: 'reminder-schedule', kind: 'editor', safety: 'safe' },
|
|
@@ -1,39 +1,20 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { AgentWorkspaceEditorKind, AgentWorkspaceLocalEditor } from './agent-workspace-types.ts';
|
|
2
2
|
import type { AgentWorkspaceChannelCommandEditorKind } from './agent-workspace-channel-command-editors.ts';
|
|
3
3
|
import { isAgentWorkspaceChannelCommandEditorKind } from './agent-workspace-channel-command-editors.ts';
|
|
4
4
|
import { quoteSlashCommandArg } from './slash-command-parser.ts';
|
|
5
|
+
import type { AgentWorkspaceCommandEditorSubmission, AgentWorkspaceCommandSubmissionHandler, AgentWorkspaceFieldReader } from './agent-workspace-command-editor-engine.ts';
|
|
6
|
+
import { buildCommandEditorSubmissionFromTable, dispatchCommandEditorSubmission, editorMessageSubmission, isAffirmative } from './agent-workspace-command-editor-engine.ts';
|
|
5
7
|
|
|
6
|
-
type
|
|
7
|
-
|
|
8
|
-
export type AgentWorkspaceChannelCommandEditorSubmission =
|
|
9
|
-
| {
|
|
10
|
-
readonly kind: 'editor';
|
|
11
|
-
readonly editor: AgentWorkspaceLocalEditor;
|
|
12
|
-
readonly status: string;
|
|
13
|
-
readonly actionResult?: AgentWorkspaceActionResult;
|
|
14
|
-
}
|
|
15
|
-
| {
|
|
16
|
-
readonly kind: 'dispatch';
|
|
17
|
-
readonly command: string;
|
|
18
|
-
readonly status: string;
|
|
19
|
-
readonly actionResult: AgentWorkspaceActionResult;
|
|
20
|
-
};
|
|
8
|
+
export type AgentWorkspaceChannelCommandEditorSubmission = AgentWorkspaceCommandEditorSubmission;
|
|
21
9
|
|
|
22
10
|
export function isAgentWorkspaceChannelCommandSubmissionKind(kind: AgentWorkspaceEditorKind): kind is AgentWorkspaceChannelCommandEditorKind {
|
|
23
11
|
return isAgentWorkspaceChannelCommandEditorKind(kind);
|
|
24
12
|
}
|
|
25
13
|
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
if (editor.kind === 'channel-send') {
|
|
31
|
-
if (!/^(y|yes|true)$/i.test(readField('confirm').trim())) {
|
|
32
|
-
return {
|
|
33
|
-
kind: 'editor',
|
|
34
|
-
editor: { ...editor, message: 'Channel delivery not confirmed. Type yes, then press Enter.' },
|
|
35
|
-
status: 'Channel delivery not confirmed.',
|
|
36
|
-
};
|
|
14
|
+
const CHANNEL_COMMAND_SUBMISSION_HANDLERS: Readonly<Record<AgentWorkspaceChannelCommandEditorKind, AgentWorkspaceCommandSubmissionHandler>> = {
|
|
15
|
+
'channel-send': (editor, readField) => {
|
|
16
|
+
if (!isAffirmative(readField('confirm'))) {
|
|
17
|
+
return editorMessageSubmission(editor, 'Channel delivery not confirmed. Type yes, then press Enter.', 'Channel delivery not confirmed.');
|
|
37
18
|
}
|
|
38
19
|
const parts = ['/channels', 'send'];
|
|
39
20
|
const title = readField('title');
|
|
@@ -47,20 +28,19 @@ export function buildAgentWorkspaceChannelCommandEditorSubmission(
|
|
|
47
28
|
if (webhook) parts.push('--webhook', quoteSlashCommandArg(webhook));
|
|
48
29
|
if (link) parts.push('--link', quoteSlashCommandArg(link));
|
|
49
30
|
parts.push('--message', quoteSlashCommandArg(readField('message')), '--yes');
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
command,
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
}
|
|
31
|
+
return dispatchCommandEditorSubmission(
|
|
32
|
+
parts.join(' '),
|
|
33
|
+
'Opening channel delivery',
|
|
34
|
+
'The workspace handed a confirmed channel delivery command to the shell-owned command router.',
|
|
35
|
+
'safe',
|
|
36
|
+
);
|
|
37
|
+
},
|
|
38
|
+
'channel-doctor': (editor, readField) => channelInspection(editor, readField),
|
|
39
|
+
'channel-setup': (editor, readField) => channelInspection(editor, readField),
|
|
40
|
+
'channel-show': (editor, readField) => channelInspection(editor, readField),
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
function channelInspection(editor: AgentWorkspaceLocalEditor, readField: AgentWorkspaceFieldReader): AgentWorkspaceCommandEditorSubmission {
|
|
64
44
|
const subcommand = editor.kind === 'channel-doctor' ? 'doctor' : editor.kind === 'channel-setup' ? 'setup' : 'show';
|
|
65
45
|
const command = `/channels ${subcommand} ${quoteSlashCommandArg(readField('channel'))}`;
|
|
66
46
|
const title = editor.kind === 'channel-doctor'
|
|
@@ -68,16 +48,22 @@ export function buildAgentWorkspaceChannelCommandEditorSubmission(
|
|
|
68
48
|
: editor.kind === 'channel-setup'
|
|
69
49
|
? 'Opening channel setup guidance'
|
|
70
50
|
: 'Opening channel detail';
|
|
71
|
-
return
|
|
72
|
-
kind: 'dispatch',
|
|
51
|
+
return dispatchCommandEditorSubmission(
|
|
73
52
|
command,
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
53
|
+
title,
|
|
54
|
+
'The workspace handed read-only channel inspection to the shell-owned command router.',
|
|
55
|
+
'read-only',
|
|
56
|
+
);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
export function buildAgentWorkspaceChannelCommandEditorSubmission(
|
|
60
|
+
editor: AgentWorkspaceLocalEditor,
|
|
61
|
+
readField: AgentWorkspaceFieldReader,
|
|
62
|
+
): AgentWorkspaceCommandEditorSubmission {
|
|
63
|
+
return buildCommandEditorSubmissionFromTable(
|
|
64
|
+
editor.kind as AgentWorkspaceChannelCommandEditorKind,
|
|
65
|
+
editor,
|
|
66
|
+
readField,
|
|
67
|
+
CHANNEL_COMMAND_SUBMISSION_HANDLERS,
|
|
68
|
+
);
|
|
83
69
|
}
|