@pellux/goodvibes-agent 0.1.116 → 1.0.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 +48 -661
- package/README.md +64 -57
- package/bin/goodvibes-agent.ts +16 -2
- package/dist/package/main.js +199180 -192185
- package/docs/README.md +15 -8
- package/docs/channels-remote-and-api.md +50 -0
- package/docs/connected-host.md +59 -0
- package/docs/getting-started.md +61 -50
- package/docs/knowledge-artifacts-and-multimodal.md +91 -0
- package/docs/project-planning.md +79 -0
- package/docs/providers-and-routing.md +46 -0
- package/docs/release-and-publishing.md +48 -11
- package/docs/tools-and-commands.md +123 -0
- package/docs/voice-and-live-tts.md +51 -0
- package/package.json +3 -6
- package/src/agent/behavior-discovery-summary.ts +1 -3
- package/src/agent/channel-delivery.ts +201 -0
- package/src/agent/media-generation.ts +159 -0
- package/src/agent/memory-prompt.ts +0 -1
- package/src/agent/note-registry.ts +329 -0
- package/src/agent/operator-actions.ts +343 -0
- package/src/agent/persona-discovery.ts +1 -3
- package/src/agent/persona-registry.ts +19 -16
- package/src/agent/record-labels.ts +107 -0
- package/src/agent/reminder-schedule-format.ts +33 -24
- package/src/agent/reminder-schedule.ts +27 -26
- package/src/agent/routine-registry.ts +54 -14
- package/src/agent/routine-schedule-args.ts +2 -1
- package/src/agent/routine-schedule-format.ts +77 -53
- package/src/agent/routine-schedule-promotion.ts +35 -33
- package/src/agent/routine-schedule-receipts.ts +29 -27
- package/src/agent/runtime-profile-starters.ts +5 -5
- package/src/agent/runtime-profile.ts +91 -12
- package/src/agent/skill-registry.ts +210 -32
- package/src/cli/agent-knowledge-args.ts +5 -1
- package/src/cli/agent-knowledge-command.ts +40 -34
- package/src/cli/agent-knowledge-format.ts +80 -67
- package/src/cli/agent-knowledge-methods.ts +1 -1
- package/src/cli/agent-knowledge-runtime.ts +32 -26
- package/src/cli/bundle-command.ts +14 -9
- package/src/cli/config-overrides.ts +37 -36
- package/src/cli/entrypoint.ts +16 -7
- package/src/cli/external-runtime.ts +10 -4
- package/src/cli/help.ts +54 -29
- package/src/cli/local-library-command.ts +203 -83
- package/src/cli/management-commands.ts +105 -68
- package/src/cli/management.ts +55 -74
- package/src/cli/memory-command.ts +66 -32
- package/src/cli/parser.ts +37 -3
- package/src/cli/profiles-command.ts +166 -31
- package/src/cli/provider-auth-routes.ts +2 -1
- package/src/cli/routines-command.ts +176 -40
- package/src/cli/service-posture.ts +16 -16
- package/src/cli/status.ts +56 -135
- package/src/core/conversation-message-snapshot.ts +131 -0
- package/src/input/agent-workspace-access-command-editor-submission.ts +149 -0
- package/src/input/agent-workspace-access-command-editors.ts +170 -0
- package/src/input/agent-workspace-activation.ts +35 -8
- package/src/input/agent-workspace-basic-command-editor-submission.ts +351 -94
- package/src/input/agent-workspace-basic-command-editors.ts +502 -9
- package/src/input/agent-workspace-categories.ts +423 -51
- package/src/input/agent-workspace-channel-command-editor-submission.ts +83 -0
- package/src/input/agent-workspace-channel-command-editors.ts +65 -0
- package/src/input/agent-workspace-channels.ts +35 -2
- package/src/input/agent-workspace-command-editor.ts +41 -3
- package/src/input/agent-workspace-config-reader.ts +16 -0
- package/src/input/agent-workspace-delegation-editor-submission.ts +55 -0
- package/src/input/agent-workspace-editors.ts +166 -1
- package/src/input/agent-workspace-knowledge-command-editor-submission.ts +132 -0
- package/src/input/agent-workspace-knowledge-command-editors.ts +110 -0
- package/src/input/agent-workspace-knowledge-query-editor.ts +1 -1
- package/src/input/agent-workspace-learned-behavior.ts +67 -0
- package/src/input/agent-workspace-library-command-editor-submission.ts +50 -0
- package/src/input/agent-workspace-library-command-editors.ts +35 -0
- package/src/input/agent-workspace-local-operations.ts +218 -0
- package/src/input/agent-workspace-local-selection.ts +75 -0
- package/src/input/agent-workspace-mcp-command-editor-submission.ts +95 -0
- package/src/input/agent-workspace-media-command-editor-submission.ts +62 -0
- package/src/input/agent-workspace-media-command-editors.ts +27 -0
- package/src/input/agent-workspace-memory-command-editor-submission.ts +232 -0
- package/src/input/agent-workspace-memory-command-editors.ts +180 -0
- package/src/input/agent-workspace-memory-editor.ts +2 -2
- package/src/input/agent-workspace-navigation.ts +81 -0
- package/src/input/agent-workspace-notify-editor-submission.ts +121 -0
- package/src/input/agent-workspace-operations-command-editor-submission.ts +208 -0
- package/src/input/agent-workspace-operations-command-editors.ts +196 -0
- package/src/input/agent-workspace-panel-route.ts +43 -0
- package/src/input/agent-workspace-provider-command-editor-submission.ts +155 -0
- package/src/input/agent-workspace-provider-command-editors.ts +93 -0
- package/src/input/agent-workspace-reminder-schedule-editor.ts +1 -1
- package/src/input/agent-workspace-requirements.ts +11 -0
- package/src/input/agent-workspace-routine-schedule-editor.ts +2 -2
- package/src/input/agent-workspace-search.ts +169 -0
- package/src/input/agent-workspace-secret-editor-submission.ts +153 -0
- package/src/input/agent-workspace-session-command-editor-submission.ts +199 -0
- package/src/input/agent-workspace-session-command-editors.ts +249 -0
- package/src/input/agent-workspace-setup.ts +37 -16
- package/src/input/agent-workspace-skill-bundle-command-editor-submission.ts +101 -0
- package/src/input/agent-workspace-skill-bundle-command-editors.ts +110 -0
- package/src/input/agent-workspace-snapshot.ts +162 -21
- package/src/input/agent-workspace-task-command-editor-submission.ts +61 -0
- package/src/input/agent-workspace-task-command-editors.ts +47 -0
- package/src/input/agent-workspace-token.ts +18 -2
- package/src/input/agent-workspace-types.ts +212 -4
- package/src/input/agent-workspace-voice-media.ts +4 -7
- package/src/input/agent-workspace-web-research-editor.ts +104 -0
- package/src/input/agent-workspace-workplan-editor-submission.ts +153 -0
- package/src/input/agent-workspace.ts +178 -240
- package/src/input/command-registry.ts +5 -2
- package/src/input/commands/agent-runtime-profile-runtime.ts +126 -37
- package/src/input/commands/agent-skills-runtime.ts +149 -72
- package/src/input/commands/agent-workspace-runtime.ts +23 -6
- package/src/input/commands/brief-runtime.ts +55 -25
- package/src/input/commands/channels-runtime.ts +147 -33
- package/src/input/commands/compat-runtime.ts +32 -0
- package/src/input/commands/delegation-runtime.ts +29 -23
- package/src/input/commands/experience-runtime.ts +6 -4
- package/src/input/commands/guidance-runtime.ts +4 -4
- package/src/input/commands/health-runtime.ts +149 -126
- package/src/input/commands/knowledge.ts +82 -60
- package/src/input/commands/local-provider-runtime.ts +43 -21
- package/src/input/commands/local-runtime.ts +138 -16
- package/src/input/commands/local-setup-review.ts +10 -20
- package/src/input/commands/mcp-runtime.ts +63 -46
- package/src/input/commands/notify-runtime.ts +38 -9
- package/src/input/commands/operator-actions-runtime.ts +138 -0
- package/src/input/commands/operator-runtime.ts +6 -76
- package/src/input/commands/personas-runtime.ts +46 -31
- package/src/input/commands/planning-runtime.ts +1 -1
- package/src/input/commands/platform-access-runtime.ts +35 -98
- package/src/input/commands/product-runtime.ts +2 -2
- package/src/input/commands/provider-accounts-runtime.ts +60 -39
- package/src/input/commands/qrcode-runtime.ts +50 -9
- package/src/input/commands/recall-bundle.ts +11 -11
- package/src/input/commands/recall-capture.ts +13 -11
- package/src/input/commands/recall-query.ts +29 -21
- package/src/input/commands/recall-review.ts +2 -1
- package/src/input/commands/routines-runtime.ts +99 -45
- package/src/input/commands/runtime-services.ts +1 -14
- package/src/input/commands/schedule-runtime.ts +33 -20
- package/src/input/commands/security-runtime.ts +6 -11
- package/src/input/commands/session-content.ts +80 -78
- package/src/input/commands/session-workflow.ts +134 -104
- package/src/input/commands/session.ts +3 -174
- package/src/input/commands/shell-core.ts +38 -17
- package/src/input/commands/subscription-runtime.ts +54 -185
- package/src/input/commands/support-bundle-runtime.ts +53 -0
- package/src/input/commands/tasks-runtime.ts +21 -21
- package/src/input/commands/work-plan-runtime.ts +33 -8
- package/src/input/commands.ts +6 -2
- package/src/input/feed-context-factory.ts +2 -2
- package/src/input/file-picker.ts +3 -2
- package/src/input/handler-command-route.ts +4 -7
- package/src/input/handler-content-actions.ts +89 -26
- package/src/input/handler-feed-routes.ts +19 -12
- package/src/input/handler-feed.ts +6 -5
- package/src/input/handler-interactions.ts +9 -36
- package/src/input/handler-modal-stack.ts +3 -3
- package/src/input/handler-onboarding.ts +52 -91
- package/src/input/handler-shortcuts.ts +16 -7
- package/src/input/handler.ts +50 -23
- package/src/input/input-history.ts +5 -6
- package/src/input/keybindings.ts +27 -16
- package/src/input/mcp-workspace.ts +90 -26
- package/src/input/onboarding/handler-onboarding-routes.ts +3 -1
- package/src/input/onboarding/onboarding-wizard-apply.ts +62 -0
- package/src/input/onboarding/onboarding-wizard-constants.ts +1 -0
- package/src/input/onboarding/onboarding-wizard-helpers.ts +1 -1
- package/src/input/onboarding/onboarding-wizard-operator-steps.ts +223 -55
- package/src/input/onboarding/onboarding-wizard-steps.ts +59 -35
- package/src/input/onboarding/onboarding-wizard-types.ts +4 -1
- package/src/input/onboarding/onboarding-wizard.ts +87 -2
- package/src/input/profile-picker-modal.ts +31 -12
- package/src/input/session-picker-modal.ts +21 -4
- package/src/input/settings-modal-agent-policy.ts +6 -6
- package/src/input/settings-modal-behavior.ts +0 -3
- package/src/input/settings-modal-subscriptions.ts +3 -3
- package/src/input/settings-modal-types.ts +2 -13
- package/src/input/settings-modal.ts +20 -66
- package/src/input/submission-intent.ts +0 -1
- package/src/input/submission-router.ts +3 -3
- package/src/main.ts +18 -10
- package/src/panels/approval-panel.ts +8 -8
- package/src/panels/automation-control-panel.ts +4 -4
- package/src/panels/base-panel.ts +1 -1
- package/src/panels/builtin/agent.ts +1 -1
- package/src/panels/builtin/operations.ts +3 -12
- package/src/panels/builtin/session.ts +32 -24
- package/src/panels/builtin/shared.ts +7 -7
- package/src/panels/cost-tracker-panel.ts +1 -1
- package/src/panels/docs-panel.ts +5 -3
- package/src/panels/index.ts +0 -1
- package/src/panels/knowledge-panel.ts +6 -5
- package/src/panels/memory-panel.ts +7 -6
- package/src/panels/panel-list-panel.ts +36 -80
- package/src/panels/project-planning-panel.ts +19 -12
- package/src/panels/provider-account-snapshot.ts +51 -25
- package/src/panels/provider-accounts-panel.ts +33 -18
- package/src/panels/provider-health-domains.ts +48 -7
- package/src/panels/provider-health-panel.ts +5 -4
- package/src/panels/qr-panel.ts +44 -20
- package/src/panels/schedule-panel.ts +9 -17
- package/src/panels/security-panel.ts +8 -8
- package/src/panels/session-browser-panel.ts +10 -10
- package/src/panels/subscription-panel.ts +6 -6
- package/src/panels/system-messages-panel.ts +3 -3
- package/src/panels/tasks-panel.ts +21 -14
- package/src/panels/tool-inspector-panel.ts +19 -12
- package/src/panels/work-plan-panel.ts +5 -5
- package/src/planning/project-planning-coordinator.ts +3 -3
- package/src/provider-auth-route-display.ts +9 -0
- package/src/renderer/agent-workspace-style.ts +34 -0
- package/src/renderer/agent-workspace.ts +254 -57
- package/src/renderer/autocomplete-overlay.ts +25 -6
- package/src/renderer/block-actions.ts +1 -3
- package/src/renderer/bookmark-modal.ts +19 -4
- package/src/renderer/buffer.ts +4 -2
- package/src/renderer/context-inspector.ts +50 -13
- package/src/renderer/diff.ts +1 -1
- package/src/renderer/file-picker-overlay.ts +19 -6
- package/src/renderer/help-overlay.ts +112 -34
- package/src/renderer/history-search-overlay.ts +19 -4
- package/src/renderer/live-tail-modal.ts +27 -5
- package/src/renderer/mcp-workspace.ts +176 -43
- package/src/renderer/model-picker-overlay.ts +58 -3
- package/src/renderer/model-workspace.ts +104 -22
- package/src/renderer/onboarding/onboarding-wizard.ts +20 -4
- package/src/renderer/process-modal.ts +27 -6
- package/src/renderer/profile-picker-modal.ts +21 -5
- package/src/renderer/search-overlay.ts +25 -5
- package/src/renderer/selection-modal-overlay.ts +46 -14
- package/src/renderer/session-picker-modal.ts +18 -1
- package/src/renderer/settings-modal-helpers.ts +2 -40
- package/src/renderer/settings-modal.ts +88 -55
- package/src/renderer/system-message.ts +1 -1
- package/src/renderer/tool-call.ts +20 -11
- package/src/runtime/agent-runtime-events.ts +129 -0
- package/src/runtime/bootstrap-command-context.ts +7 -1
- package/src/runtime/bootstrap-command-parts.ts +11 -8
- package/src/runtime/bootstrap-core.ts +23 -65
- package/src/runtime/bootstrap-hook-bridge.ts +7 -18
- package/src/runtime/bootstrap-shell.ts +46 -8
- package/src/runtime/bootstrap.ts +36 -46
- package/src/runtime/connected-host-auth.ts +47 -0
- package/src/runtime/diagnostics/panels/index.ts +2 -2
- package/src/runtime/diagnostics/panels/panel-resources.ts +1 -1
- package/src/runtime/diagnostics/panels/policy.ts +7 -7
- package/src/runtime/index.ts +2 -5
- package/src/runtime/onboarding/apply-file-helpers.ts +66 -0
- package/src/runtime/onboarding/apply.ts +288 -74
- package/src/runtime/onboarding/derivation.ts +10 -13
- package/src/runtime/onboarding/snapshot.ts +2 -17
- package/src/runtime/onboarding/types.ts +34 -20
- package/src/runtime/onboarding/verify.ts +105 -4
- package/src/runtime/operator-token-cleanup.ts +3 -3
- package/src/runtime/services.ts +95 -11
- package/src/runtime/store/selectors/index.ts +3 -3
- package/src/runtime/store/state.ts +1 -4
- package/src/runtime/surface-feature-flags.ts +41 -6
- package/src/runtime/ui-read-models.ts +3 -4
- package/src/runtime/ui-services.ts +6 -6
- package/src/shell/blocking-input.ts +2 -1
- package/src/shell/service-settings-sync.ts +7 -7
- package/src/shell/ui-openers.ts +17 -38
- package/src/tools/agent-analysis-registry-policy.ts +0 -1
- package/src/tools/agent-channel-send-tool.ts +133 -0
- package/src/tools/agent-context-policy.ts +1 -1
- package/src/tools/agent-knowledge-ingest-tool.ts +405 -0
- package/src/tools/agent-knowledge-tool.ts +170 -0
- package/src/tools/agent-local-registry-tool.ts +279 -73
- package/src/tools/agent-media-generate-tool.ts +133 -0
- package/src/tools/agent-notify-tool.ts +143 -0
- package/src/tools/agent-operator-action-tool.ts +137 -0
- package/src/tools/agent-operator-briefing-tool.ts +217 -0
- package/src/tools/agent-reminder-schedule-tool.ts +237 -0
- package/src/tools/agent-tool-policy-guard.ts +13 -15
- package/src/tools/agent-work-plan-tool.ts +256 -0
- package/src/version.ts +1 -1
- package/docs/connected-services.md +0 -51
- package/src/cli/package-verification.ts +0 -274
- package/src/input/commands/policy-dispatch.ts +0 -339
- package/src/input/commands/policy.ts +0 -17
- package/src/panels/panel-picker.ts +0 -105
- package/src/panels/policy-panel.ts +0 -308
- package/src/renderer/panel-picker-overlay.ts +0 -202
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
import type { AgentWorkspaceActionResult, AgentWorkspaceEditorKind, AgentWorkspaceLocalEditor } from './agent-workspace-types.ts';
|
|
2
|
+
import type { AgentWorkspaceProviderCommandEditorKind } from './agent-workspace-provider-command-editors.ts';
|
|
3
|
+
import { isAgentWorkspaceProviderCommandEditorKind } from './agent-workspace-provider-command-editors.ts';
|
|
4
|
+
import { quoteSlashCommandArg } from './slash-command-parser.ts';
|
|
5
|
+
|
|
6
|
+
type AgentWorkspaceFieldReader = (fieldId: string) => string;
|
|
7
|
+
|
|
8
|
+
export type AgentWorkspaceProviderCommandEditorSubmission =
|
|
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
|
+
};
|
|
21
|
+
|
|
22
|
+
function isAffirmative(value: string): boolean {
|
|
23
|
+
return /^(y|yes|true)$/i.test(value.trim());
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
function unconfirmed(editor: AgentWorkspaceLocalEditor, label: string): AgentWorkspaceProviderCommandEditorSubmission {
|
|
27
|
+
return {
|
|
28
|
+
kind: 'editor',
|
|
29
|
+
editor: { ...editor, message: `${label} not confirmed. Type yes, then press Enter.` },
|
|
30
|
+
status: `${label} not confirmed.`,
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export function isAgentWorkspaceProviderCommandSubmissionKind(kind: AgentWorkspaceEditorKind): kind is AgentWorkspaceProviderCommandEditorKind {
|
|
35
|
+
return isAgentWorkspaceProviderCommandEditorKind(kind);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
export function buildAgentWorkspaceProviderCommandEditorSubmission(
|
|
39
|
+
editor: AgentWorkspaceLocalEditor,
|
|
40
|
+
readField: AgentWorkspaceFieldReader,
|
|
41
|
+
): AgentWorkspaceProviderCommandEditorSubmission {
|
|
42
|
+
if (editor.kind === 'provider-use') {
|
|
43
|
+
const model = readField('model');
|
|
44
|
+
const command = [
|
|
45
|
+
'/provider',
|
|
46
|
+
quoteSlashCommandArg(readField('provider')),
|
|
47
|
+
...(model.length > 0 ? [quoteSlashCommandArg(model)] : []),
|
|
48
|
+
].join(' ');
|
|
49
|
+
return {
|
|
50
|
+
kind: 'dispatch',
|
|
51
|
+
command,
|
|
52
|
+
status: 'Opening provider selection.',
|
|
53
|
+
actionResult: {
|
|
54
|
+
kind: 'dispatched',
|
|
55
|
+
title: 'Opening provider selection',
|
|
56
|
+
detail: 'The workspace handed provider selection to the shell-owned command router.',
|
|
57
|
+
command,
|
|
58
|
+
safety: 'safe',
|
|
59
|
+
},
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
if (editor.kind === 'provider-inspect') {
|
|
63
|
+
const command = `/accounts show ${quoteSlashCommandArg(readField('provider'))}`;
|
|
64
|
+
return {
|
|
65
|
+
kind: 'dispatch',
|
|
66
|
+
command,
|
|
67
|
+
status: 'Opening provider inspection.',
|
|
68
|
+
actionResult: {
|
|
69
|
+
kind: 'dispatched',
|
|
70
|
+
title: 'Opening provider inspection',
|
|
71
|
+
detail: 'The workspace handed read-only provider inspection to the shell-owned command router.',
|
|
72
|
+
command,
|
|
73
|
+
safety: 'read-only',
|
|
74
|
+
},
|
|
75
|
+
};
|
|
76
|
+
}
|
|
77
|
+
if (editor.kind === 'provider-routes') {
|
|
78
|
+
const command = `/accounts routes ${quoteSlashCommandArg(readField('provider'))}`;
|
|
79
|
+
return {
|
|
80
|
+
kind: 'dispatch',
|
|
81
|
+
command,
|
|
82
|
+
status: 'Opening provider route inspection.',
|
|
83
|
+
actionResult: {
|
|
84
|
+
kind: 'dispatched',
|
|
85
|
+
title: 'Opening provider route inspection',
|
|
86
|
+
detail: 'The workspace handed read-only provider route inspection to the shell-owned command router.',
|
|
87
|
+
command,
|
|
88
|
+
safety: 'read-only',
|
|
89
|
+
},
|
|
90
|
+
};
|
|
91
|
+
}
|
|
92
|
+
if (editor.kind === 'provider-account-repair') {
|
|
93
|
+
const command = `/accounts repair ${quoteSlashCommandArg(readField('provider'))}`;
|
|
94
|
+
return {
|
|
95
|
+
kind: 'dispatch',
|
|
96
|
+
command,
|
|
97
|
+
status: 'Opening provider account repair review.',
|
|
98
|
+
actionResult: {
|
|
99
|
+
kind: 'dispatched',
|
|
100
|
+
title: 'Opening provider account repair review',
|
|
101
|
+
detail: 'The workspace handed read-only provider account repair guidance to the shell-owned command router.',
|
|
102
|
+
command,
|
|
103
|
+
safety: 'read-only',
|
|
104
|
+
},
|
|
105
|
+
};
|
|
106
|
+
}
|
|
107
|
+
if (editor.kind === 'provider-add') {
|
|
108
|
+
if (!isAffirmative(readField('confirm'))) {
|
|
109
|
+
return unconfirmed(editor, 'Custom provider add');
|
|
110
|
+
}
|
|
111
|
+
const key = readField('apiKey');
|
|
112
|
+
const parts = [
|
|
113
|
+
'/provider',
|
|
114
|
+
'add',
|
|
115
|
+
quoteSlashCommandArg(readField('name')),
|
|
116
|
+
quoteSlashCommandArg(readField('baseUrl')),
|
|
117
|
+
];
|
|
118
|
+
const redactedParts = [...parts];
|
|
119
|
+
if (key.length > 0) {
|
|
120
|
+
parts.push(quoteSlashCommandArg(key));
|
|
121
|
+
redactedParts.push('<redacted-api-key>');
|
|
122
|
+
}
|
|
123
|
+
parts.push('--yes');
|
|
124
|
+
redactedParts.push('--yes');
|
|
125
|
+
return {
|
|
126
|
+
kind: 'dispatch',
|
|
127
|
+
command: parts.join(' '),
|
|
128
|
+
status: 'Opening custom provider add.',
|
|
129
|
+
actionResult: {
|
|
130
|
+
kind: 'dispatched',
|
|
131
|
+
title: 'Opening custom provider add',
|
|
132
|
+
detail: 'The workspace handed a confirmed custom provider add command to the shell-owned command router without rendering the raw API key.',
|
|
133
|
+
command: redactedParts.join(' '),
|
|
134
|
+
safety: 'safe',
|
|
135
|
+
},
|
|
136
|
+
};
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
if (!isAffirmative(readField('confirm'))) {
|
|
140
|
+
return unconfirmed(editor, 'Custom provider removal');
|
|
141
|
+
}
|
|
142
|
+
const command = `/provider remove ${quoteSlashCommandArg(readField('name'))} --yes`;
|
|
143
|
+
return {
|
|
144
|
+
kind: 'dispatch',
|
|
145
|
+
command,
|
|
146
|
+
status: 'Opening custom provider removal.',
|
|
147
|
+
actionResult: {
|
|
148
|
+
kind: 'dispatched',
|
|
149
|
+
title: 'Opening custom provider removal',
|
|
150
|
+
detail: 'The workspace handed a confirmed custom provider removal command to the shell-owned command router.',
|
|
151
|
+
command,
|
|
152
|
+
safety: 'safe',
|
|
153
|
+
},
|
|
154
|
+
};
|
|
155
|
+
}
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
import type { AgentWorkspaceEditorKind, AgentWorkspaceLocalEditor } from './agent-workspace-types.ts';
|
|
2
|
+
|
|
3
|
+
export type AgentWorkspaceProviderCommandEditorKind = Extract<
|
|
4
|
+
AgentWorkspaceEditorKind,
|
|
5
|
+
'provider-add' | 'provider-remove' | 'provider-use' | 'provider-inspect' | 'provider-routes' | 'provider-account-repair'
|
|
6
|
+
>;
|
|
7
|
+
|
|
8
|
+
export function isAgentWorkspaceProviderCommandEditorKind(kind: AgentWorkspaceEditorKind): kind is AgentWorkspaceProviderCommandEditorKind {
|
|
9
|
+
return kind === 'provider-add'
|
|
10
|
+
|| kind === 'provider-remove'
|
|
11
|
+
|| kind === 'provider-use'
|
|
12
|
+
|| kind === 'provider-inspect'
|
|
13
|
+
|| kind === 'provider-routes'
|
|
14
|
+
|| kind === 'provider-account-repair';
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export function createAgentWorkspaceProviderCommandEditor(kind: AgentWorkspaceProviderCommandEditorKind): AgentWorkspaceLocalEditor {
|
|
18
|
+
if (kind === 'provider-use') {
|
|
19
|
+
return {
|
|
20
|
+
kind,
|
|
21
|
+
mode: 'create',
|
|
22
|
+
title: 'Use Provider',
|
|
23
|
+
selectedFieldIndex: 0,
|
|
24
|
+
message: 'Switch the Agent chat provider through the TUI command router. Add a model id when you want an exact provider/model route.',
|
|
25
|
+
fields: [
|
|
26
|
+
{ id: 'provider', label: 'Provider id', value: '', required: true, multiline: false, hint: 'Provider row id, such as openai-subscriber, openai, anthropic, or a custom provider.' },
|
|
27
|
+
{ id: 'model', label: 'Model id', value: '', required: false, multiline: false, hint: 'Optional model id or provider:model registry key. Blank uses the provider default selectable model.' },
|
|
28
|
+
],
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
if (kind === 'provider-inspect') {
|
|
32
|
+
return {
|
|
33
|
+
kind,
|
|
34
|
+
mode: 'create',
|
|
35
|
+
title: 'Inspect Provider',
|
|
36
|
+
selectedFieldIndex: 0,
|
|
37
|
+
message: 'Inspect provider auth and setup routes from the Agent TUI without changing provider selection.',
|
|
38
|
+
fields: [
|
|
39
|
+
{ id: 'provider', label: 'Provider id', value: '', required: true, multiline: false, hint: 'Provider row id to inspect.' },
|
|
40
|
+
],
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
if (kind === 'provider-routes') {
|
|
44
|
+
return {
|
|
45
|
+
kind,
|
|
46
|
+
mode: 'create',
|
|
47
|
+
title: 'Inspect Provider Routes',
|
|
48
|
+
selectedFieldIndex: 0,
|
|
49
|
+
message: 'Inspect provider account routes from the Agent TUI without changing routing or auth.',
|
|
50
|
+
fields: [
|
|
51
|
+
{ id: 'provider', label: 'Provider id', value: '', required: true, multiline: false, hint: 'Provider row id to inspect.' },
|
|
52
|
+
],
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
if (kind === 'provider-account-repair') {
|
|
56
|
+
return {
|
|
57
|
+
kind,
|
|
58
|
+
mode: 'create',
|
|
59
|
+
title: 'Review Provider Account Repair',
|
|
60
|
+
selectedFieldIndex: 0,
|
|
61
|
+
message: 'Show provider account repair guidance from the Agent TUI without starting login or storing tokens.',
|
|
62
|
+
fields: [
|
|
63
|
+
{ id: 'provider', label: 'Provider id', value: '', required: true, multiline: false, hint: 'Provider row id to inspect.' },
|
|
64
|
+
],
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
if (kind === 'provider-add') {
|
|
68
|
+
return {
|
|
69
|
+
kind,
|
|
70
|
+
mode: 'create',
|
|
71
|
+
title: 'Add Custom Provider',
|
|
72
|
+
selectedFieldIndex: 0,
|
|
73
|
+
message: 'Add an OpenAI-compatible provider for Agent chat/model routing. Type yes on the final field to confirm.',
|
|
74
|
+
fields: [
|
|
75
|
+
{ id: 'name', label: 'Provider name', value: '', required: true, multiline: false, hint: 'Letters, numbers, hyphens, and underscores only.' },
|
|
76
|
+
{ id: 'baseUrl', label: 'Base URL', value: '', required: true, multiline: false, hint: 'OpenAI-compatible base URL, such as http://127.0.0.1:8000/v1.' },
|
|
77
|
+
{ id: 'apiKey', label: 'API key', value: '', required: false, multiline: false, hint: 'Optional API key. Prefer a local provider or a secret-backed provider config when possible.', redact: true },
|
|
78
|
+
{ id: 'confirm', label: 'Confirm', value: '', required: true, multiline: false, hint: 'Type yes to run /provider add with --yes.' },
|
|
79
|
+
],
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
return {
|
|
83
|
+
kind,
|
|
84
|
+
mode: 'delete',
|
|
85
|
+
title: 'Remove Custom Provider',
|
|
86
|
+
selectedFieldIndex: 0,
|
|
87
|
+
message: 'Remove one custom provider config from the Agent provider list. Type yes on the final field to confirm.',
|
|
88
|
+
fields: [
|
|
89
|
+
{ id: 'name', label: 'Provider name', value: '', required: true, multiline: false, hint: 'Existing custom provider name.' },
|
|
90
|
+
{ id: 'confirm', label: 'Confirm', value: '', required: true, multiline: false, hint: 'Type yes to run /provider remove with --yes.' },
|
|
91
|
+
],
|
|
92
|
+
};
|
|
93
|
+
}
|
|
@@ -32,7 +32,7 @@ export function createReminderScheduleEditor(): AgentWorkspaceLocalEditor {
|
|
|
32
32
|
{ id: 'scheduleValue', label: 'Schedule value', value: '', required: true, multiline: false, hint: 'Examples: 2026-06-01T09:00:00-05:00, 7d, or 0 9 * * *.' },
|
|
33
33
|
{ id: 'timezone', label: 'Timezone', value: '', required: false, multiline: false, hint: 'Optional IANA timezone for cron schedules, for example America/Chicago.' },
|
|
34
34
|
{ id: 'scheduleName', label: 'Schedule name', value: '', required: false, multiline: false, hint: 'Optional display name for the connected reminder.' },
|
|
35
|
-
{ id: 'deliveryChannel', label: 'Delivery channel', value: '', required: false, multiline: false, hint: 'Optional channel target, for example slack
|
|
35
|
+
{ id: 'deliveryChannel', label: 'Delivery channel', value: '', required: false, multiline: false, hint: 'Optional channel target, for example slack, slack:ops-alerts:Ops, or telephony:+15551234567.' },
|
|
36
36
|
{ id: 'disabled', label: 'Create disabled', value: 'no', required: false, multiline: false, hint: 'yes/no. Default no.' },
|
|
37
37
|
{ id: 'confirm', label: 'Confirm', value: '', required: true, multiline: false, hint: 'Type yes to run /schedule remind with --yes.' },
|
|
38
38
|
],
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { buildAgentSkillRequirements, type AgentSkillRequirement } from '../agent/skill-registry.ts';
|
|
2
|
+
import { splitList } from './agent-workspace-editors.ts';
|
|
3
|
+
|
|
4
|
+
export type AgentWorkspaceEditorFieldReader = (fieldId: string) => string;
|
|
5
|
+
|
|
6
|
+
export function buildAgentWorkspaceRequirements(readField: AgentWorkspaceEditorFieldReader): readonly AgentSkillRequirement[] {
|
|
7
|
+
return buildAgentSkillRequirements({
|
|
8
|
+
env: splitList(readField('requiresEnv')),
|
|
9
|
+
commands: splitList(readField('requiresCommands')),
|
|
10
|
+
});
|
|
11
|
+
}
|
|
@@ -30,12 +30,12 @@ export function createRoutineScheduleEditor(
|
|
|
30
30
|
selectedFieldIndex: 0,
|
|
31
31
|
message: `Create one connected schedule from a reviewed local routine. Selected: ${selected}. Type yes on the final field to confirm.`,
|
|
32
32
|
fields: [
|
|
33
|
-
{ id: 'routineId', label: 'Routine id', value: selectedRoutine?.id ?? '', required: true, multiline: false, hint: '
|
|
33
|
+
{ id: 'routineId', label: 'Routine id', value: selectedRoutine?.id ?? '', required: true, multiline: false, hint: 'Agent-local routine id to promote.' },
|
|
34
34
|
{ id: 'scheduleKind', label: 'Schedule type', value: 'cron', required: true, multiline: false, hint: 'cron, every, or at.' },
|
|
35
35
|
{ id: 'scheduleValue', label: 'Schedule value', value: '', required: true, multiline: false, hint: 'Examples: 0 9 * * *, 7d, or 2026-06-01T09:00:00-05:00.' },
|
|
36
36
|
{ id: 'timezone', label: 'Timezone', value: '', required: false, multiline: false, hint: 'Optional IANA timezone, for example America/Chicago.' },
|
|
37
37
|
{ id: 'scheduleName', label: 'Schedule name', value: selectedRoutine?.name ?? '', required: false, multiline: false, hint: 'Optional display name for the connected schedule.' },
|
|
38
|
-
{ id: 'deliveryChannel', label: 'Delivery channel', value: '', required: false, multiline: false, hint: 'Optional channel target, for example slack
|
|
38
|
+
{ id: 'deliveryChannel', label: 'Delivery channel', value: '', required: false, multiline: false, hint: 'Optional channel target, for example slack, slack:ops-alerts:Ops, or telephony:+15551234567.' },
|
|
39
39
|
{ id: 'disabled', label: 'Create disabled', value: 'no', required: false, multiline: false, hint: 'yes/no. Default no.' },
|
|
40
40
|
{ id: 'confirm', label: 'Confirm', value: '', required: true, multiline: false, hint: 'Type yes to run /schedule promote-routine with --yes.' },
|
|
41
41
|
],
|
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
import type {
|
|
2
|
+
AgentWorkspaceActionResult,
|
|
3
|
+
AgentWorkspaceActionSearchResult,
|
|
4
|
+
AgentWorkspaceCategory,
|
|
5
|
+
AgentWorkspaceFocusPane,
|
|
6
|
+
} from './agent-workspace-types.ts';
|
|
7
|
+
|
|
8
|
+
export interface AgentWorkspaceSearchHost {
|
|
9
|
+
readonly categories: readonly AgentWorkspaceCategory[];
|
|
10
|
+
readonly selectedCategory: AgentWorkspaceCategory;
|
|
11
|
+
actionSearchActive: boolean;
|
|
12
|
+
actionSearchQuery: string;
|
|
13
|
+
focusPane: AgentWorkspaceFocusPane;
|
|
14
|
+
selectedCategoryIndex: number;
|
|
15
|
+
selectedActionIndex: number;
|
|
16
|
+
status: string;
|
|
17
|
+
lastActionResult: AgentWorkspaceActionResult | null;
|
|
18
|
+
focusActions(): void;
|
|
19
|
+
clampSelection(): void;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export function searchAgentWorkspaceActions(
|
|
23
|
+
categories: readonly AgentWorkspaceCategory[],
|
|
24
|
+
query: string,
|
|
25
|
+
): readonly AgentWorkspaceActionSearchResult[] {
|
|
26
|
+
const normalized = query.trim().toLowerCase();
|
|
27
|
+
if (!normalized) return [];
|
|
28
|
+
const terms = normalized.split(/\s+/).filter(Boolean);
|
|
29
|
+
const results: Array<{ readonly result: AgentWorkspaceActionSearchResult; readonly score: number }> = [];
|
|
30
|
+
categories.forEach((category, categoryIndex) => {
|
|
31
|
+
category.actions.forEach((action, actionIndex) => {
|
|
32
|
+
const haystack = [
|
|
33
|
+
category.id,
|
|
34
|
+
category.label,
|
|
35
|
+
category.summary,
|
|
36
|
+
category.detail,
|
|
37
|
+
action.id,
|
|
38
|
+
action.label,
|
|
39
|
+
action.detail,
|
|
40
|
+
action.command ?? '',
|
|
41
|
+
action.editorKind ?? '',
|
|
42
|
+
action.targetCategoryId ?? '',
|
|
43
|
+
action.localOperation ?? '',
|
|
44
|
+
action.safety,
|
|
45
|
+
].join(' ').toLowerCase();
|
|
46
|
+
if (terms.every((term) => haystack.includes(term))) {
|
|
47
|
+
const result = { category, categoryIndex, action, actionIndex };
|
|
48
|
+
results.push({ result, score: scoreActionSearchResult(result, normalized, terms) });
|
|
49
|
+
}
|
|
50
|
+
});
|
|
51
|
+
});
|
|
52
|
+
return results
|
|
53
|
+
.sort((left, right) => right.score - left.score || left.result.categoryIndex - right.result.categoryIndex || left.result.actionIndex - right.result.actionIndex)
|
|
54
|
+
.map((entry) => entry.result);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
function scoreField(value: string | undefined, terms: readonly string[], exactQuery: string, exactWeight: number, termWeight: number): number {
|
|
58
|
+
const normalized = (value ?? '').toLowerCase();
|
|
59
|
+
if (!normalized) return 0;
|
|
60
|
+
const bareNormalized = normalized.replace(/^\//, '');
|
|
61
|
+
let score = bareNormalized === exactQuery || normalized === exactQuery
|
|
62
|
+
? exactWeight
|
|
63
|
+
: exactQuery.includes(' ') && normalized.includes(exactQuery)
|
|
64
|
+
? exactWeight
|
|
65
|
+
: 0;
|
|
66
|
+
for (const term of terms) {
|
|
67
|
+
if (normalized.includes(term)) score += termWeight;
|
|
68
|
+
}
|
|
69
|
+
return score;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
function scoreActionSearchResult(
|
|
73
|
+
result: AgentWorkspaceActionSearchResult,
|
|
74
|
+
exactQuery: string,
|
|
75
|
+
terms: readonly string[],
|
|
76
|
+
): number {
|
|
77
|
+
const { category, action } = result;
|
|
78
|
+
let score = 0;
|
|
79
|
+
score += scoreField(action.id, terms, exactQuery, 90, 28);
|
|
80
|
+
score += scoreField(action.editorKind, terms, exactQuery, 85, 26);
|
|
81
|
+
score += scoreField(action.command, terms, exactQuery, 75, 22);
|
|
82
|
+
score += scoreField(action.label, terms, exactQuery, 65, 18);
|
|
83
|
+
score += scoreField(action.localOperation, terms, exactQuery, 50, 16);
|
|
84
|
+
score += scoreField(action.targetCategoryId, terms, exactQuery, 40, 12);
|
|
85
|
+
score += scoreField(action.detail, terms, exactQuery, 24, 6);
|
|
86
|
+
score += scoreField(category.id, terms, exactQuery, 30, 8);
|
|
87
|
+
score += scoreField(category.label, terms, exactQuery, 25, 7);
|
|
88
|
+
score += scoreField(category.summary, terms, exactQuery, 12, 3);
|
|
89
|
+
score += scoreField(category.detail, terms, exactQuery, 8, 2);
|
|
90
|
+
|
|
91
|
+
if (category.id === 'setup' && !terms.includes('setup')) score -= 14;
|
|
92
|
+
if (action.id.startsWith('setup-') && !terms.includes('setup')) score -= 18;
|
|
93
|
+
if (action.kind === 'workspace' && !terms.includes('open')) score -= 4;
|
|
94
|
+
return score;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
export function beginAgentWorkspaceActionSearch(host: AgentWorkspaceSearchHost): void {
|
|
98
|
+
host.actionSearchActive = true;
|
|
99
|
+
host.actionSearchQuery = '';
|
|
100
|
+
host.focusPane = 'actions';
|
|
101
|
+
host.selectedActionIndex = 0;
|
|
102
|
+
host.status = 'Search Agent workspace actions.';
|
|
103
|
+
host.lastActionResult = {
|
|
104
|
+
kind: 'guidance',
|
|
105
|
+
title: 'Action search',
|
|
106
|
+
detail: 'Type to filter every Agent workspace action. Enter opens the selected result; Esc clears search.',
|
|
107
|
+
safety: 'safe',
|
|
108
|
+
};
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
export function appendAgentWorkspaceActionSearchText(host: AgentWorkspaceSearchHost, text: string): void {
|
|
112
|
+
if (!host.actionSearchActive || text.length === 0) return;
|
|
113
|
+
host.actionSearchQuery += text.replace(/[\r\n]+/g, ' ');
|
|
114
|
+
host.selectedActionIndex = 0;
|
|
115
|
+
host.status = actionSearchStatus(host);
|
|
116
|
+
host.clampSelection();
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
export function backspaceAgentWorkspaceActionSearch(host: AgentWorkspaceSearchHost): void {
|
|
120
|
+
if (!host.actionSearchActive || host.actionSearchQuery.length === 0) return;
|
|
121
|
+
const chars = Array.from(host.actionSearchQuery);
|
|
122
|
+
chars.pop();
|
|
123
|
+
host.actionSearchQuery = chars.join('');
|
|
124
|
+
host.selectedActionIndex = 0;
|
|
125
|
+
host.status = host.actionSearchQuery.length === 0 ? 'Search Agent workspace actions.' : actionSearchStatus(host);
|
|
126
|
+
host.clampSelection();
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
export function clearAgentWorkspaceActionSearch(host: AgentWorkspaceSearchHost): void {
|
|
130
|
+
if (!host.actionSearchActive) return;
|
|
131
|
+
host.actionSearchActive = false;
|
|
132
|
+
host.actionSearchQuery = '';
|
|
133
|
+
host.selectedActionIndex = Math.max(0, Math.min(host.selectedActionIndex, host.selectedCategory.actions.length - 1));
|
|
134
|
+
host.status = 'Action search cleared.';
|
|
135
|
+
host.clampSelection();
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
export function commitAgentWorkspaceActionSearchSelection(
|
|
139
|
+
host: AgentWorkspaceSearchHost,
|
|
140
|
+
result: AgentWorkspaceActionSearchResult | null,
|
|
141
|
+
): boolean {
|
|
142
|
+
if (!host.actionSearchActive) return true;
|
|
143
|
+
if (!result) {
|
|
144
|
+
host.status = host.actionSearchQuery.trim().length === 0
|
|
145
|
+
? 'Type a search query before opening an action.'
|
|
146
|
+
: `No Agent workspace actions match "${host.actionSearchQuery}".`;
|
|
147
|
+
host.lastActionResult = {
|
|
148
|
+
kind: 'guidance',
|
|
149
|
+
title: 'No action selected',
|
|
150
|
+
detail: 'Type a different search query or press Esc to return to normal workspace navigation.',
|
|
151
|
+
safety: 'safe',
|
|
152
|
+
};
|
|
153
|
+
return false;
|
|
154
|
+
}
|
|
155
|
+
host.selectedCategoryIndex = result.categoryIndex;
|
|
156
|
+
host.selectedActionIndex = result.actionIndex;
|
|
157
|
+
host.actionSearchActive = false;
|
|
158
|
+
host.actionSearchQuery = '';
|
|
159
|
+
host.focusActions();
|
|
160
|
+
host.clampSelection();
|
|
161
|
+
return true;
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
function actionSearchStatus(host: AgentWorkspaceSearchHost): string {
|
|
165
|
+
const count = searchAgentWorkspaceActions(host.categories, host.actionSearchQuery).length;
|
|
166
|
+
return count === 0
|
|
167
|
+
? `No Agent workspace actions match "${host.actionSearchQuery}".`
|
|
168
|
+
: `Found ${count} Agent workspace action(s) for "${host.actionSearchQuery}".`;
|
|
169
|
+
}
|
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
import type { AgentWorkspaceActionResult, AgentWorkspaceLocalEditor } from './agent-workspace-types.ts';
|
|
2
|
+
import { quoteSlashCommandArg } from './slash-command-parser.ts';
|
|
3
|
+
|
|
4
|
+
type AgentWorkspaceFieldReader = (fieldId: string) => string;
|
|
5
|
+
|
|
6
|
+
type AgentWorkspaceSecretEditorSubmission =
|
|
7
|
+
| {
|
|
8
|
+
readonly kind: 'editor';
|
|
9
|
+
readonly editor: AgentWorkspaceLocalEditor;
|
|
10
|
+
readonly status: string;
|
|
11
|
+
readonly actionResult?: AgentWorkspaceActionResult;
|
|
12
|
+
}
|
|
13
|
+
| {
|
|
14
|
+
readonly kind: 'dispatch';
|
|
15
|
+
readonly command: string;
|
|
16
|
+
readonly status: string;
|
|
17
|
+
readonly actionResult: AgentWorkspaceActionResult;
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
function isAffirmative(value: string): boolean {
|
|
21
|
+
return /^(y|yes|true)$/i.test(value.trim());
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
function secretScopeFlag(scope: string): string | null {
|
|
25
|
+
const normalized = scope.trim().toLowerCase();
|
|
26
|
+
if (normalized === 'user') return '--user';
|
|
27
|
+
if (normalized === 'project') return '--project';
|
|
28
|
+
return null;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
function secretStorageFlag(storage: string): string | null {
|
|
32
|
+
const normalized = storage.trim().toLowerCase();
|
|
33
|
+
if (normalized === 'plaintext') return '--plaintext';
|
|
34
|
+
if (normalized === 'secure') return '--secure';
|
|
35
|
+
return null;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
function appendOptionalSecretFlags(parts: string[], scope: string, storage: string): void {
|
|
39
|
+
const scopeFlag = secretScopeFlag(scope);
|
|
40
|
+
const storageFlag = secretStorageFlag(storage);
|
|
41
|
+
if (scopeFlag) parts.push(scopeFlag);
|
|
42
|
+
if (storageFlag) parts.push(storageFlag);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
export function isAgentWorkspaceSecretEditorKind(kind: AgentWorkspaceLocalEditor['kind']): kind is 'secret-set' | 'secret-link' | 'secret-test' | 'secret-delete' {
|
|
46
|
+
return kind === 'secret-set' || kind === 'secret-link' || kind === 'secret-test' || kind === 'secret-delete';
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
export function buildAgentWorkspaceSecretEditorSubmission(
|
|
50
|
+
editor: AgentWorkspaceLocalEditor,
|
|
51
|
+
readField: AgentWorkspaceFieldReader,
|
|
52
|
+
): AgentWorkspaceSecretEditorSubmission {
|
|
53
|
+
if (editor.kind === 'secret-set') {
|
|
54
|
+
if (!isAffirmative(readField('confirm'))) {
|
|
55
|
+
return {
|
|
56
|
+
kind: 'editor',
|
|
57
|
+
editor: { ...editor, message: 'Secret value storage not confirmed. Type yes, then press Enter.' },
|
|
58
|
+
status: 'Secret value storage not confirmed.',
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
const key = readField('key');
|
|
62
|
+
const parts = ['/secrets', 'set', quoteSlashCommandArg(key), quoteSlashCommandArg(readField('value'))];
|
|
63
|
+
appendOptionalSecretFlags(parts, readField('scope'), readField('storage'));
|
|
64
|
+
parts.push('--yes');
|
|
65
|
+
const redactedParts = ['/secrets', 'set', quoteSlashCommandArg(key), '<redacted>'];
|
|
66
|
+
appendOptionalSecretFlags(redactedParts, readField('scope'), readField('storage'));
|
|
67
|
+
redactedParts.push('--yes');
|
|
68
|
+
return {
|
|
69
|
+
kind: 'dispatch',
|
|
70
|
+
command: parts.join(' '),
|
|
71
|
+
status: 'Opening secret value storage.',
|
|
72
|
+
actionResult: {
|
|
73
|
+
kind: 'dispatched',
|
|
74
|
+
title: 'Opening secret value storage',
|
|
75
|
+
detail: 'The workspace handed a confirmed secret value storage command to the shell-owned command router without rendering the raw value.',
|
|
76
|
+
command: redactedParts.join(' '),
|
|
77
|
+
safety: 'safe',
|
|
78
|
+
},
|
|
79
|
+
};
|
|
80
|
+
}
|
|
81
|
+
if (editor.kind === 'secret-link') {
|
|
82
|
+
if (!isAffirmative(readField('confirm'))) {
|
|
83
|
+
return {
|
|
84
|
+
kind: 'editor',
|
|
85
|
+
editor: { ...editor, message: 'Secret reference link not confirmed. Type yes, then press Enter.' },
|
|
86
|
+
status: 'Secret reference link not confirmed.',
|
|
87
|
+
};
|
|
88
|
+
}
|
|
89
|
+
const key = readField('key');
|
|
90
|
+
const parts = ['/secrets', 'link', quoteSlashCommandArg(key), quoteSlashCommandArg(readField('ref'))];
|
|
91
|
+
appendOptionalSecretFlags(parts, readField('scope'), readField('storage'));
|
|
92
|
+
parts.push('--yes');
|
|
93
|
+
const redactedParts = ['/secrets', 'link', quoteSlashCommandArg(key), '<secret-ref>'];
|
|
94
|
+
appendOptionalSecretFlags(redactedParts, readField('scope'), readField('storage'));
|
|
95
|
+
redactedParts.push('--yes');
|
|
96
|
+
return {
|
|
97
|
+
kind: 'dispatch',
|
|
98
|
+
command: parts.join(' '),
|
|
99
|
+
status: 'Opening secret reference link.',
|
|
100
|
+
actionResult: {
|
|
101
|
+
kind: 'dispatched',
|
|
102
|
+
title: 'Opening secret reference link',
|
|
103
|
+
detail: 'The workspace handed a confirmed secret reference link command to the shell-owned command router without rendering the full reference.',
|
|
104
|
+
command: redactedParts.join(' '),
|
|
105
|
+
safety: 'safe',
|
|
106
|
+
},
|
|
107
|
+
};
|
|
108
|
+
}
|
|
109
|
+
if (editor.kind === 'secret-test') {
|
|
110
|
+
if (!isAffirmative(readField('confirm'))) {
|
|
111
|
+
return {
|
|
112
|
+
kind: 'editor',
|
|
113
|
+
editor: { ...editor, message: 'Secret reference test not confirmed. Type yes, then press Enter.' },
|
|
114
|
+
status: 'Secret reference test not confirmed.',
|
|
115
|
+
};
|
|
116
|
+
}
|
|
117
|
+
return {
|
|
118
|
+
kind: 'dispatch',
|
|
119
|
+
command: `/secrets test ${quoteSlashCommandArg(readField('ref'))}`,
|
|
120
|
+
status: 'Opening secret reference test.',
|
|
121
|
+
actionResult: {
|
|
122
|
+
kind: 'dispatched',
|
|
123
|
+
title: 'Opening secret reference test',
|
|
124
|
+
detail: 'The workspace handed a confirmed secret reference test command to the shell-owned command router; the command output remains redacted.',
|
|
125
|
+
command: '/secrets test <secret-ref>',
|
|
126
|
+
safety: 'safe',
|
|
127
|
+
},
|
|
128
|
+
};
|
|
129
|
+
}
|
|
130
|
+
if (!isAffirmative(readField('confirm'))) {
|
|
131
|
+
return {
|
|
132
|
+
kind: 'editor',
|
|
133
|
+
editor: { ...editor, message: 'Secret deletion not confirmed. Type yes, then press Enter.' },
|
|
134
|
+
status: 'Secret deletion not confirmed.',
|
|
135
|
+
};
|
|
136
|
+
}
|
|
137
|
+
const key = readField('key');
|
|
138
|
+
const parts = ['/secrets', 'delete', quoteSlashCommandArg(key)];
|
|
139
|
+
appendOptionalSecretFlags(parts, readField('scope'), readField('storage'));
|
|
140
|
+
parts.push('--yes');
|
|
141
|
+
return {
|
|
142
|
+
kind: 'dispatch',
|
|
143
|
+
command: parts.join(' '),
|
|
144
|
+
status: 'Opening secret deletion.',
|
|
145
|
+
actionResult: {
|
|
146
|
+
kind: 'dispatched',
|
|
147
|
+
title: 'Opening secret deletion',
|
|
148
|
+
detail: 'The workspace handed a confirmed secret deletion command to the shell-owned command router.',
|
|
149
|
+
command: parts.join(' '),
|
|
150
|
+
safety: 'safe',
|
|
151
|
+
},
|
|
152
|
+
};
|
|
153
|
+
}
|