@pellux/goodvibes-agent 0.1.117 → 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 +13 -4
- package/README.md +35 -14
- package/bin/goodvibes-agent.ts +16 -2
- package/dist/package/main.js +176073 -170980
- package/docs/README.md +11 -5
- package/docs/channels-remote-and-api.md +50 -0
- package/docs/connected-host.md +3 -3
- package/docs/getting-started.md +29 -15
- 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 +44 -9
- package/docs/tools-and-commands.md +123 -0
- package/docs/voice-and-live-tts.md +51 -0
- package/package.json +2 -5
- 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-registry.ts +15 -14
- package/src/agent/record-labels.ts +107 -0
- package/src/agent/reminder-schedule-format.ts +33 -24
- package/src/agent/reminder-schedule.ts +26 -25
- package/src/agent/routine-registry.ts +13 -12
- 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 +34 -32
- package/src/agent/routine-schedule-receipts.ts +28 -26
- package/src/agent/runtime-profile-starters.ts +2 -2
- package/src/agent/runtime-profile.ts +18 -17
- package/src/agent/skill-registry.ts +25 -24
- package/src/cli/agent-knowledge-args.ts +5 -1
- package/src/cli/agent-knowledge-command.ts +39 -33
- 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 +13 -8
- package/src/cli/config-overrides.ts +37 -36
- package/src/cli/external-runtime.ts +10 -4
- package/src/cli/help.ts +29 -11
- package/src/cli/local-library-command.ts +134 -68
- package/src/cli/management-commands.ts +98 -62
- package/src/cli/management.ts +52 -26
- package/src/cli/memory-command.ts +66 -32
- package/src/cli/parser.ts +37 -24
- package/src/cli/profiles-command.ts +52 -35
- package/src/cli/provider-auth-routes.ts +2 -1
- package/src/cli/routines-command.ts +44 -36
- package/src/cli/service-posture.ts +6 -6
- package/src/cli/status.ts +46 -121
- package/src/core/conversation-message-snapshot.ts +131 -0
- package/src/input/agent-workspace-activation.ts +33 -7
- package/src/input/agent-workspace-basic-command-editor-submission.ts +7 -3
- package/src/input/agent-workspace-basic-command-editors.ts +30 -10
- package/src/input/agent-workspace-categories.ts +276 -64
- package/src/input/agent-workspace-channel-command-editor-submission.ts +34 -0
- package/src/input/agent-workspace-channel-command-editors.ts +23 -5
- package/src/input/agent-workspace-channels.ts +35 -2
- package/src/input/agent-workspace-command-editor.ts +18 -2
- package/src/input/agent-workspace-config-reader.ts +16 -0
- package/src/input/agent-workspace-delegation-editor-submission.ts +1 -1
- package/src/input/agent-workspace-editors.ts +140 -2
- package/src/input/agent-workspace-knowledge-query-editor.ts +1 -1
- package/src/input/agent-workspace-learned-behavior.ts +2 -2
- package/src/input/agent-workspace-library-command-editor-submission.ts +1 -1
- package/src/input/agent-workspace-library-command-editors.ts +2 -2
- 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-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-editors.ts +1 -1
- package/src/input/agent-workspace-memory-editor.ts +2 -2
- package/src/input/agent-workspace-navigation.ts +38 -2
- package/src/input/agent-workspace-notify-editor-submission.ts +16 -2
- package/src/input/agent-workspace-operations-command-editor-submission.ts +63 -1
- package/src/input/agent-workspace-operations-command-editors.ts +80 -3
- package/src/input/agent-workspace-panel-route.ts +43 -0
- package/src/input/agent-workspace-reminder-schedule-editor.ts +1 -1
- 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-setup.ts +22 -11
- package/src/input/agent-workspace-skill-bundle-command-editor-submission.ts +6 -6
- package/src/input/agent-workspace-skill-bundle-command-editors.ts +10 -10
- package/src/input/agent-workspace-snapshot.ts +112 -13
- package/src/input/agent-workspace-task-command-editors.ts +4 -4
- package/src/input/agent-workspace-token.ts +18 -2
- package/src/input/agent-workspace-types.ts +92 -4
- package/src/input/agent-workspace-voice-media.ts +3 -6
- package/src/input/agent-workspace-web-research-editor.ts +104 -0
- package/src/input/agent-workspace.ts +136 -208
- package/src/input/command-registry.ts +4 -1
- package/src/input/commands/agent-runtime-profile-runtime.ts +45 -41
- package/src/input/commands/agent-skills-runtime.ts +83 -70
- package/src/input/commands/agent-workspace-runtime.ts +23 -7
- package/src/input/commands/brief-runtime.ts +25 -24
- package/src/input/commands/channels-runtime.ts +145 -31
- 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 +140 -115
- package/src/input/commands/knowledge.ts +57 -56
- package/src/input/commands/local-provider-runtime.ts +36 -18
- package/src/input/commands/local-runtime.ts +138 -16
- package/src/input/commands/local-setup-review.ts +7 -7
- package/src/input/commands/mcp-runtime.ts +56 -35
- 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 -17
- package/src/input/commands/personas-runtime.ts +45 -30
- package/src/input/commands/planning-runtime.ts +1 -1
- package/src/input/commands/platform-access-runtime.ts +29 -29
- package/src/input/commands/provider-accounts-runtime.ts +60 -39
- package/src/input/commands/qrcode-runtime.ts +45 -6
- 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 +59 -43
- package/src/input/commands/schedule-runtime.ts +33 -20
- package/src/input/commands/security-runtime.ts +4 -4
- package/src/input/commands/session-content.ts +80 -78
- package/src/input/commands/session-workflow.ts +132 -93
- package/src/input/commands/session.ts +3 -174
- package/src/input/commands/shell-core.ts +32 -17
- package/src/input/commands/subscription-runtime.ts +53 -179
- package/src/input/commands/tasks-runtime.ts +20 -20
- package/src/input/commands/work-plan-runtime.ts +33 -8
- package/src/input/commands.ts +2 -2
- package/src/input/feed-context-factory.ts +2 -1
- 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 -1
- package/src/input/handler-feed-routes.ts +19 -12
- package/src/input/handler-feed.ts +6 -3
- package/src/input/handler-interactions.ts +7 -5
- package/src/input/handler-modal-stack.ts +3 -3
- package/src/input/handler-onboarding.ts +24 -80
- package/src/input/handler-shortcuts.ts +15 -4
- package/src/input/handler.ts +47 -17
- package/src/input/input-history.ts +5 -6
- package/src/input/keybindings.ts +22 -11
- package/src/input/onboarding/onboarding-wizard-apply.ts +13 -0
- package/src/input/onboarding/onboarding-wizard-constants.ts +1 -0
- package/src/input/onboarding/onboarding-wizard-operator-steps.ts +147 -57
- package/src/input/onboarding/onboarding-wizard-steps.ts +46 -29
- package/src/input/onboarding/onboarding-wizard-types.ts +3 -1
- package/src/input/onboarding/onboarding-wizard.ts +68 -0
- package/src/input/profile-picker-modal.ts +31 -12
- package/src/input/session-picker-modal.ts +21 -4
- 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 +6 -52
- package/src/input/submission-intent.ts +0 -1
- package/src/input/submission-router.ts +3 -3
- package/src/main.ts +18 -8
- package/src/panels/approval-panel.ts +8 -8
- package/src/panels/automation-control-panel.ts +2 -2
- package/src/panels/base-panel.ts +1 -1
- package/src/panels/builtin/agent.ts +1 -1
- package/src/panels/builtin/operations.ts +1 -10
- package/src/panels/builtin/session.ts +9 -9
- package/src/panels/builtin/shared.ts +2 -2
- 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 +18 -11
- 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 +45 -4
- package/src/panels/provider-health-panel.ts +5 -4
- package/src/panels/qr-panel.ts +1 -1
- 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 +3 -3
- package/src/panels/system-messages-panel.ts +1 -1
- package/src/panels/tasks-panel.ts +20 -13
- 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 +1 -1
- package/src/provider-auth-route-display.ts +9 -0
- package/src/renderer/agent-workspace-style.ts +34 -0
- package/src/renderer/agent-workspace.ts +228 -52
- package/src/renderer/autocomplete-overlay.ts +25 -6
- 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 +106 -33
- package/src/renderer/history-search-overlay.ts +19 -4
- package/src/renderer/live-tail-modal.ts +27 -5
- package/src/renderer/mcp-workspace.ts +164 -50
- package/src/renderer/model-picker-overlay.ts +58 -2
- package/src/renderer/model-workspace.ts +104 -20
- package/src/renderer/process-modal.ts +27 -6
- package/src/renderer/profile-picker-modal.ts +20 -4
- 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 +83 -50
- package/src/renderer/tool-call.ts +20 -11
- package/src/runtime/agent-runtime-events.ts +6 -6
- package/src/runtime/bootstrap-command-context.ts +7 -1
- package/src/runtime/bootstrap-command-parts.ts +9 -7
- package/src/runtime/bootstrap-core.ts +19 -1
- package/src/runtime/bootstrap-hook-bridge.ts +7 -18
- package/src/runtime/bootstrap-shell.ts +4 -4
- package/src/runtime/bootstrap.ts +31 -22
- package/src/runtime/connected-host-auth.ts +7 -2
- package/src/runtime/diagnostics/panels/index.ts +2 -2
- package/src/runtime/diagnostics/panels/policy.ts +7 -7
- package/src/runtime/index.ts +2 -1
- package/src/runtime/onboarding/apply-file-helpers.ts +66 -0
- package/src/runtime/onboarding/apply.ts +80 -79
- package/src/runtime/onboarding/derivation.ts +5 -8
- package/src/runtime/onboarding/snapshot.ts +0 -15
- package/src/runtime/onboarding/types.ts +8 -19
- package/src/runtime/onboarding/verify.ts +32 -10
- package/src/runtime/operator-token-cleanup.ts +1 -1
- package/src/runtime/services.ts +91 -22
- 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/ui-openers.ts +3 -13
- 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 +269 -69
- 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 +8 -8
- package/src/tools/agent-work-plan-tool.ts +256 -0
- package/src/version.ts +1 -1
- package/src/input/commands/policy-dispatch.ts +0 -339
- package/src/input/commands/policy.ts +0 -13
- 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,218 @@
|
|
|
1
|
+
import type { MemoryApi } from '@pellux/goodvibes-sdk/platform/knowledge';
|
|
2
|
+
import type { ShellPathService } from '@/runtime/index.ts';
|
|
3
|
+
import { AgentNoteRegistry } from '../agent/note-registry.ts';
|
|
4
|
+
import { AgentPersonaRegistry } from '../agent/persona-registry.ts';
|
|
5
|
+
import { AgentRoutineRegistry } from '../agent/routine-registry.ts';
|
|
6
|
+
import { AgentSkillRegistry } from '../agent/skill-registry.ts';
|
|
7
|
+
import { quoteSlashCommandArg } from './slash-command-parser.ts';
|
|
8
|
+
import {
|
|
9
|
+
createKnowledgeUrlEditorFromNote,
|
|
10
|
+
createMemoryEditorFromNote,
|
|
11
|
+
createMemoryUpdateEditor,
|
|
12
|
+
createNoteUpdateEditor,
|
|
13
|
+
createPersonaEditorFromNote,
|
|
14
|
+
createPersonaUpdateEditor,
|
|
15
|
+
createRoutineEditorFromNote,
|
|
16
|
+
createRoutineUpdateEditor,
|
|
17
|
+
createSkillEditorFromNote,
|
|
18
|
+
createSkillUpdateEditor,
|
|
19
|
+
} from './agent-workspace-editors.ts';
|
|
20
|
+
import type {
|
|
21
|
+
AgentWorkspaceActionResult,
|
|
22
|
+
AgentWorkspaceLocalEditor,
|
|
23
|
+
AgentWorkspaceLocalEditorKind,
|
|
24
|
+
AgentWorkspaceLocalLibraryItem,
|
|
25
|
+
AgentWorkspaceLocalOperation,
|
|
26
|
+
} from './agent-workspace-types.ts';
|
|
27
|
+
|
|
28
|
+
interface AgentWorkspaceLocalOperationHost {
|
|
29
|
+
status: string;
|
|
30
|
+
lastActionResult: AgentWorkspaceActionResult | null;
|
|
31
|
+
localEditor: AgentWorkspaceLocalEditor | null;
|
|
32
|
+
hasCommandDispatch(): boolean;
|
|
33
|
+
dispatchWorkspaceCommand(command: string): void;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
interface AgentWorkspaceLocalOperationCallbacks {
|
|
37
|
+
readonly shellPaths: () => ShellPathService | undefined;
|
|
38
|
+
readonly selectedItemForOperation: (operation: AgentWorkspaceLocalOperation) => AgentWorkspaceLocalLibraryItem | null;
|
|
39
|
+
readonly memoryApi: () => MemoryApi;
|
|
40
|
+
readonly finishLocalOperation: (kind: AgentWorkspaceLocalEditorKind, title: string, detail: string) => void;
|
|
41
|
+
readonly openDeleteEditor: (kind: AgentWorkspaceLocalEditorKind, selected: AgentWorkspaceLocalLibraryItem) => void;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
function setGuidanceEditor(host: AgentWorkspaceLocalOperationHost, editor: AgentWorkspaceLocalEditor, status: string): void {
|
|
45
|
+
host.localEditor = editor;
|
|
46
|
+
host.status = status;
|
|
47
|
+
host.lastActionResult = {
|
|
48
|
+
kind: 'guidance',
|
|
49
|
+
title: editor.title,
|
|
50
|
+
detail: editor.message,
|
|
51
|
+
safety: 'safe',
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
export function applyAgentWorkspaceLocalLibraryOperation(
|
|
56
|
+
host: AgentWorkspaceLocalOperationHost,
|
|
57
|
+
operation: AgentWorkspaceLocalOperation,
|
|
58
|
+
callbacks: AgentWorkspaceLocalOperationCallbacks,
|
|
59
|
+
): void {
|
|
60
|
+
const shellPaths = callbacks.shellPaths();
|
|
61
|
+
if (!shellPaths) {
|
|
62
|
+
host.status = 'Agent-local registry files are unavailable.';
|
|
63
|
+
host.lastActionResult = {
|
|
64
|
+
kind: 'error',
|
|
65
|
+
title: 'Local registry unavailable',
|
|
66
|
+
detail: 'The Agent workspace cannot locate the Agent-local registry files for this runtime.',
|
|
67
|
+
};
|
|
68
|
+
return;
|
|
69
|
+
}
|
|
70
|
+
try {
|
|
71
|
+
if (operation === 'persona-clear') {
|
|
72
|
+
AgentPersonaRegistry.fromShellPaths(shellPaths).clearActive();
|
|
73
|
+
callbacks.finishLocalOperation('persona', 'Cleared active persona', 'The default Agent policy will apply to later turns.');
|
|
74
|
+
return;
|
|
75
|
+
}
|
|
76
|
+
const selected = callbacks.selectedItemForOperation(operation);
|
|
77
|
+
if (!selected) {
|
|
78
|
+
host.status = 'No selected local registry item.';
|
|
79
|
+
host.lastActionResult = {
|
|
80
|
+
kind: 'guidance',
|
|
81
|
+
title: 'Nothing selected',
|
|
82
|
+
detail: 'Create or select a local library item before running this action.',
|
|
83
|
+
safety: 'safe',
|
|
84
|
+
};
|
|
85
|
+
return;
|
|
86
|
+
}
|
|
87
|
+
if (operation === 'memory-edit') {
|
|
88
|
+
const memory = callbacks.memoryApi();
|
|
89
|
+
const record = memory.get(selected.id);
|
|
90
|
+
if (!record) throw new Error(`Unknown Agent memory ${selected.id}`);
|
|
91
|
+
setGuidanceEditor(host, createMemoryUpdateEditor(record), `Editing memory ${record.id}.`);
|
|
92
|
+
} else if (operation === 'memory-review') {
|
|
93
|
+
const record = callbacks.memoryApi().review(selected.id, { state: 'reviewed', confidence: selected.confidence ?? 100, reviewedBy: 'operator' });
|
|
94
|
+
if (!record) throw new Error(`Unknown Agent memory ${selected.id}`);
|
|
95
|
+
callbacks.finishLocalOperation('memory', `Reviewed memory ${record.id}`, `${record.summary} is marked reviewed.`);
|
|
96
|
+
} else if (operation === 'memory-stale') {
|
|
97
|
+
const record = callbacks.memoryApi().review(selected.id, { state: 'stale', staleReason: 'Marked stale from Agent workspace', reviewedBy: 'operator' });
|
|
98
|
+
if (!record) throw new Error(`Unknown Agent memory ${selected.id}`);
|
|
99
|
+
callbacks.finishLocalOperation('memory', `Marked memory stale ${record.id}`, `${record.summary} needs review before reuse.`);
|
|
100
|
+
} else if (operation === 'memory-delete') {
|
|
101
|
+
callbacks.openDeleteEditor('memory', selected);
|
|
102
|
+
} else if (operation === 'note-edit') {
|
|
103
|
+
const note = AgentNoteRegistry.fromShellPaths(shellPaths).get(selected.id);
|
|
104
|
+
if (!note) throw new Error(`Unknown note ${selected.id}`);
|
|
105
|
+
setGuidanceEditor(host, createNoteUpdateEditor(note), `Editing note ${note.title}.`);
|
|
106
|
+
} else if (operation === 'note-review') {
|
|
107
|
+
const note = AgentNoteRegistry.fromShellPaths(shellPaths).markReviewed(selected.id);
|
|
108
|
+
callbacks.finishLocalOperation('note', `Reviewed note ${note.title}`, `${note.title} is marked reviewed in the local scratchpad.`);
|
|
109
|
+
} else if (operation === 'note-stale') {
|
|
110
|
+
const note = AgentNoteRegistry.fromShellPaths(shellPaths).markStale(selected.id, 'Marked stale from Agent workspace');
|
|
111
|
+
callbacks.finishLocalOperation('note', `Marked note stale ${note.title}`, `${note.title} needs review before reuse.`);
|
|
112
|
+
} else if (operation === 'note-delete') {
|
|
113
|
+
callbacks.openDeleteEditor('note', selected);
|
|
114
|
+
} else if (operation === 'note-promote-memory') {
|
|
115
|
+
const note = AgentNoteRegistry.fromShellPaths(shellPaths).get(selected.id);
|
|
116
|
+
if (!note) throw new Error(`Unknown note ${selected.id}`);
|
|
117
|
+
setGuidanceEditor(host, createMemoryEditorFromNote(note), `Creating memory from note ${note.title}.`);
|
|
118
|
+
} else if (operation === 'note-promote-persona') {
|
|
119
|
+
const note = AgentNoteRegistry.fromShellPaths(shellPaths).get(selected.id);
|
|
120
|
+
if (!note) throw new Error(`Unknown note ${selected.id}`);
|
|
121
|
+
setGuidanceEditor(host, createPersonaEditorFromNote(note), `Creating persona from note ${note.title}.`);
|
|
122
|
+
} else if (operation === 'note-promote-skill') {
|
|
123
|
+
const note = AgentNoteRegistry.fromShellPaths(shellPaths).get(selected.id);
|
|
124
|
+
if (!note) throw new Error(`Unknown note ${selected.id}`);
|
|
125
|
+
setGuidanceEditor(host, createSkillEditorFromNote(note), `Creating skill from note ${note.title}.`);
|
|
126
|
+
} else if (operation === 'note-promote-routine') {
|
|
127
|
+
const note = AgentNoteRegistry.fromShellPaths(shellPaths).get(selected.id);
|
|
128
|
+
if (!note) throw new Error(`Unknown note ${selected.id}`);
|
|
129
|
+
setGuidanceEditor(host, createRoutineEditorFromNote(note), `Creating routine from note ${note.title}.`);
|
|
130
|
+
} else if (operation === 'note-promote-knowledge-url') {
|
|
131
|
+
const note = AgentNoteRegistry.fromShellPaths(shellPaths).get(selected.id);
|
|
132
|
+
if (!note) throw new Error(`Unknown note ${selected.id}`);
|
|
133
|
+
const sourceUrl = note.sourceUrl?.trim();
|
|
134
|
+
if (!sourceUrl) {
|
|
135
|
+
host.status = 'Selected note has no reviewed source URL.';
|
|
136
|
+
host.lastActionResult = {
|
|
137
|
+
kind: 'guidance',
|
|
138
|
+
title: 'No note source URL',
|
|
139
|
+
detail: 'Edit the selected note and add a reviewed HTTP(S) source URL before ingesting it into Agent Knowledge.',
|
|
140
|
+
safety: 'safe',
|
|
141
|
+
};
|
|
142
|
+
return;
|
|
143
|
+
}
|
|
144
|
+
const parsed = new URL(sourceUrl);
|
|
145
|
+
if (parsed.protocol !== 'http:' && parsed.protocol !== 'https:') {
|
|
146
|
+
throw new Error('Selected note source URL must be HTTP or HTTPS before Agent Knowledge ingest.');
|
|
147
|
+
}
|
|
148
|
+
setGuidanceEditor(host, createKnowledgeUrlEditorFromNote(note), `Preparing Agent Knowledge ingest from note ${note.title}.`);
|
|
149
|
+
} else if (operation === 'persona-edit') {
|
|
150
|
+
const registry = AgentPersonaRegistry.fromShellPaths(shellPaths);
|
|
151
|
+
const persona = registry.get(selected.id);
|
|
152
|
+
if (!persona) throw new Error(`Unknown persona ${selected.id}`);
|
|
153
|
+
setGuidanceEditor(host, createPersonaUpdateEditor(persona, registry.snapshot().activePersonaId === persona.id), `Editing persona ${persona.name}.`);
|
|
154
|
+
} else if (operation === 'persona-use') {
|
|
155
|
+
AgentPersonaRegistry.fromShellPaths(shellPaths).setActive(selected.id);
|
|
156
|
+
callbacks.finishLocalOperation('persona', `Using persona ${selected.name}`, `${selected.name} will shape later main-conversation turns.`);
|
|
157
|
+
} else if (operation === 'persona-review') {
|
|
158
|
+
AgentPersonaRegistry.fromShellPaths(shellPaths).markReviewed(selected.id);
|
|
159
|
+
callbacks.finishLocalOperation('persona', `Reviewed persona ${selected.name}`, `${selected.name} is marked reviewed.`);
|
|
160
|
+
} else if (operation === 'persona-delete') {
|
|
161
|
+
callbacks.openDeleteEditor('persona', selected);
|
|
162
|
+
} else if (operation === 'skill-edit') {
|
|
163
|
+
const skill = AgentSkillRegistry.fromShellPaths(shellPaths).get(selected.id);
|
|
164
|
+
if (!skill) throw new Error(`Unknown skill ${selected.id}`);
|
|
165
|
+
setGuidanceEditor(host, createSkillUpdateEditor(skill), `Editing skill ${skill.name}.`);
|
|
166
|
+
} else if (operation === 'skill-enable') {
|
|
167
|
+
AgentSkillRegistry.fromShellPaths(shellPaths).setEnabled(selected.id, true);
|
|
168
|
+
callbacks.finishLocalOperation('skill', `Enabled skill ${selected.name}`, `${selected.name} can now inform main-conversation turns.`);
|
|
169
|
+
} else if (operation === 'skill-disable') {
|
|
170
|
+
AgentSkillRegistry.fromShellPaths(shellPaths).setEnabled(selected.id, false);
|
|
171
|
+
callbacks.finishLocalOperation('skill', `Disabled skill ${selected.name}`, `${selected.name} remains saved but is no longer injected into guidance.`);
|
|
172
|
+
} else if (operation === 'skill-review') {
|
|
173
|
+
AgentSkillRegistry.fromShellPaths(shellPaths).markReviewed(selected.id);
|
|
174
|
+
callbacks.finishLocalOperation('skill', `Reviewed skill ${selected.name}`, `${selected.name} is marked reviewed.`);
|
|
175
|
+
} else if (operation === 'skill-delete') {
|
|
176
|
+
callbacks.openDeleteEditor('skill', selected);
|
|
177
|
+
} else if (operation === 'routine-edit') {
|
|
178
|
+
const routine = AgentRoutineRegistry.fromShellPaths(shellPaths).get(selected.id);
|
|
179
|
+
if (!routine) throw new Error(`Unknown routine ${selected.id}`);
|
|
180
|
+
setGuidanceEditor(host, createRoutineUpdateEditor(routine), `Editing routine ${routine.name}.`);
|
|
181
|
+
} else if (operation === 'routine-start') {
|
|
182
|
+
if (host.hasCommandDispatch()) {
|
|
183
|
+
const command = `/routines start ${quoteSlashCommandArg(selected.id)}`;
|
|
184
|
+
host.dispatchWorkspaceCommand(command);
|
|
185
|
+
host.status = `Opening routine ${selected.name}.`;
|
|
186
|
+
host.lastActionResult = {
|
|
187
|
+
kind: 'dispatched',
|
|
188
|
+
title: `Opening routine ${selected.name}`,
|
|
189
|
+
detail: `${selected.name} will print its workflow steps in the main conversation. No hidden job was created.`,
|
|
190
|
+
command,
|
|
191
|
+
safety: 'safe',
|
|
192
|
+
};
|
|
193
|
+
return;
|
|
194
|
+
}
|
|
195
|
+
AgentRoutineRegistry.fromShellPaths(shellPaths).markStarted(selected.id);
|
|
196
|
+
callbacks.finishLocalOperation('routine', `Started routine ${selected.name}`, `${selected.name} was marked started for this main-conversation workflow. No hidden job was created.`);
|
|
197
|
+
} else if (operation === 'routine-enable') {
|
|
198
|
+
AgentRoutineRegistry.fromShellPaths(shellPaths).setEnabled(selected.id, true);
|
|
199
|
+
callbacks.finishLocalOperation('routine', `Enabled routine ${selected.name}`, `${selected.name} can now inform main-conversation turns.`);
|
|
200
|
+
} else if (operation === 'routine-disable') {
|
|
201
|
+
AgentRoutineRegistry.fromShellPaths(shellPaths).setEnabled(selected.id, false);
|
|
202
|
+
callbacks.finishLocalOperation('routine', `Disabled routine ${selected.name}`, `${selected.name} remains saved but is no longer injected into guidance.`);
|
|
203
|
+
} else if (operation === 'routine-review') {
|
|
204
|
+
AgentRoutineRegistry.fromShellPaths(shellPaths).markReviewed(selected.id);
|
|
205
|
+
callbacks.finishLocalOperation('routine', `Reviewed routine ${selected.name}`, `${selected.name} is marked reviewed.`);
|
|
206
|
+
} else {
|
|
207
|
+
callbacks.openDeleteEditor('routine', selected);
|
|
208
|
+
}
|
|
209
|
+
} catch (error) {
|
|
210
|
+
const detail = error instanceof Error ? error.message : String(error);
|
|
211
|
+
host.status = detail;
|
|
212
|
+
host.lastActionResult = {
|
|
213
|
+
kind: 'error',
|
|
214
|
+
title: 'Local registry action failed',
|
|
215
|
+
detail,
|
|
216
|
+
};
|
|
217
|
+
}
|
|
218
|
+
}
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import type {
|
|
2
|
+
AgentWorkspaceActionResult,
|
|
3
|
+
AgentWorkspaceLocalEditorKind,
|
|
4
|
+
AgentWorkspaceLocalLibraryItem,
|
|
5
|
+
AgentWorkspaceRuntimeSnapshot,
|
|
6
|
+
} from './agent-workspace-types.ts';
|
|
7
|
+
|
|
8
|
+
export type AgentWorkspaceLocalSelectionIndexes = Record<AgentWorkspaceLocalEditorKind, number>;
|
|
9
|
+
|
|
10
|
+
export interface AgentWorkspaceLocalSelectionHost {
|
|
11
|
+
readonly runtimeSnapshot: AgentWorkspaceRuntimeSnapshot | null;
|
|
12
|
+
readonly selectedLibraryItemIndexes: AgentWorkspaceLocalSelectionIndexes;
|
|
13
|
+
status: string;
|
|
14
|
+
lastActionResult: AgentWorkspaceActionResult | null;
|
|
15
|
+
selectedLocalLibraryItem(kind: AgentWorkspaceLocalEditorKind): AgentWorkspaceLocalLibraryItem | null;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export function agentWorkspaceLocalLibraryItems(
|
|
19
|
+
snapshot: AgentWorkspaceRuntimeSnapshot | null,
|
|
20
|
+
kind: AgentWorkspaceLocalEditorKind,
|
|
21
|
+
): readonly AgentWorkspaceLocalLibraryItem[] {
|
|
22
|
+
if (kind === 'memory') return snapshot?.localMemories ?? [];
|
|
23
|
+
if (kind === 'note') return snapshot?.localNotes ?? [];
|
|
24
|
+
if (kind === 'persona') return snapshot?.localPersonas ?? [];
|
|
25
|
+
if (kind === 'skill') return snapshot?.localSkills ?? [];
|
|
26
|
+
if (kind === 'profile') return [];
|
|
27
|
+
return snapshot?.localRoutines ?? [];
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export function selectedAgentWorkspaceLocalLibraryItem(
|
|
31
|
+
snapshot: AgentWorkspaceRuntimeSnapshot | null,
|
|
32
|
+
indexes: AgentWorkspaceLocalSelectionIndexes,
|
|
33
|
+
kind: AgentWorkspaceLocalEditorKind,
|
|
34
|
+
): AgentWorkspaceLocalLibraryItem | null {
|
|
35
|
+
const items = agentWorkspaceLocalLibraryItems(snapshot, kind);
|
|
36
|
+
if (items.length === 0) return null;
|
|
37
|
+
const index = Math.max(0, Math.min(indexes[kind], items.length - 1));
|
|
38
|
+
return items[index] ?? null;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
export function clampAgentWorkspaceLocalLibrarySelection(
|
|
42
|
+
snapshot: AgentWorkspaceRuntimeSnapshot | null,
|
|
43
|
+
indexes: AgentWorkspaceLocalSelectionIndexes,
|
|
44
|
+
kind: AgentWorkspaceLocalEditorKind,
|
|
45
|
+
): void {
|
|
46
|
+
const length = agentWorkspaceLocalLibraryItems(snapshot, kind).length;
|
|
47
|
+
indexes[kind] = length === 0 ? 0 : Math.max(0, Math.min(indexes[kind], length - 1));
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
export function moveAgentWorkspaceLocalLibraryItemSelection(
|
|
51
|
+
host: AgentWorkspaceLocalSelectionHost,
|
|
52
|
+
kind: AgentWorkspaceLocalEditorKind,
|
|
53
|
+
delta: number,
|
|
54
|
+
): void {
|
|
55
|
+
const items = agentWorkspaceLocalLibraryItems(host.runtimeSnapshot, kind);
|
|
56
|
+
if (items.length === 0) {
|
|
57
|
+
host.status = `No local ${kind} records to select.`;
|
|
58
|
+
host.lastActionResult = {
|
|
59
|
+
kind: 'guidance',
|
|
60
|
+
title: `No ${kind} records`,
|
|
61
|
+
detail: `Create a local ${kind} before using selection actions.`,
|
|
62
|
+
safety: 'safe',
|
|
63
|
+
};
|
|
64
|
+
return;
|
|
65
|
+
}
|
|
66
|
+
host.selectedLibraryItemIndexes[kind] = Math.max(0, Math.min(items.length - 1, host.selectedLibraryItemIndexes[kind] + delta));
|
|
67
|
+
const selected = host.selectedLocalLibraryItem(kind);
|
|
68
|
+
host.status = selected ? `Selected ${kind}: ${selected.name}.` : `Selected ${kind} updated.`;
|
|
69
|
+
host.lastActionResult = {
|
|
70
|
+
kind: 'guidance',
|
|
71
|
+
title: selected ? `Selected ${selected.name}` : `Selected ${kind}`,
|
|
72
|
+
detail: selected ? `${selected.name} (${selected.id}) is now the selected local ${kind}.` : `Selection changed for ${kind}.`,
|
|
73
|
+
safety: 'safe',
|
|
74
|
+
};
|
|
75
|
+
}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import type { AgentWorkspaceActionResult, AgentWorkspaceLocalEditor } from './agent-workspace-types.ts';
|
|
2
|
+
import type { AgentWorkspaceMediaCommandEditorKind } from './agent-workspace-media-command-editors.ts';
|
|
3
|
+
import { isAgentWorkspaceMediaCommandEditorKind } from './agent-workspace-media-command-editors.ts';
|
|
4
|
+
import { quoteSlashCommandArg } from './slash-command-parser.ts';
|
|
5
|
+
|
|
6
|
+
type AgentWorkspaceFieldReader = (fieldId: string) => string;
|
|
7
|
+
|
|
8
|
+
export type AgentWorkspaceMediaCommandEditorSubmission =
|
|
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
|
+
export function isAgentWorkspaceMediaCommandSubmissionKind(kind: string): kind is AgentWorkspaceMediaCommandEditorKind {
|
|
23
|
+
return isAgentWorkspaceMediaCommandEditorKind(kind as AgentWorkspaceMediaCommandEditorKind);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
function isAffirmative(value: string): boolean {
|
|
27
|
+
return /^(y|yes|true)$/i.test(value.trim());
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export function buildAgentWorkspaceMediaCommandEditorSubmission(
|
|
31
|
+
editor: AgentWorkspaceLocalEditor,
|
|
32
|
+
readField: AgentWorkspaceFieldReader,
|
|
33
|
+
): AgentWorkspaceMediaCommandEditorSubmission {
|
|
34
|
+
if (!isAffirmative(readField('confirm'))) {
|
|
35
|
+
return {
|
|
36
|
+
kind: 'editor',
|
|
37
|
+
editor: { ...editor, message: 'Media generation not confirmed. Type yes, then press Enter.' },
|
|
38
|
+
status: 'Agent media generation not confirmed.',
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
const parts = ['/media', 'generate'];
|
|
42
|
+
const provider = readField('provider');
|
|
43
|
+
const model = readField('model');
|
|
44
|
+
const mime = readField('mime');
|
|
45
|
+
if (provider) parts.push('--provider', quoteSlashCommandArg(provider));
|
|
46
|
+
if (model) parts.push('--model', quoteSlashCommandArg(model));
|
|
47
|
+
if (mime) parts.push('--mime', quoteSlashCommandArg(mime));
|
|
48
|
+
parts.push(quoteSlashCommandArg(readField('prompt')), '--yes');
|
|
49
|
+
const command = parts.join(' ');
|
|
50
|
+
return {
|
|
51
|
+
kind: 'dispatch',
|
|
52
|
+
command,
|
|
53
|
+
status: 'Opening media generation.',
|
|
54
|
+
actionResult: {
|
|
55
|
+
kind: 'dispatched',
|
|
56
|
+
title: 'Opening media generation',
|
|
57
|
+
detail: 'The workspace handed confirmed media generation to the shell-owned command router.',
|
|
58
|
+
command,
|
|
59
|
+
safety: 'safe',
|
|
60
|
+
},
|
|
61
|
+
};
|
|
62
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import type { AgentWorkspaceEditorKind, AgentWorkspaceLocalEditor } from './agent-workspace-types.ts';
|
|
2
|
+
|
|
3
|
+
export type AgentWorkspaceMediaCommandEditorKind = Extract<
|
|
4
|
+
AgentWorkspaceEditorKind,
|
|
5
|
+
'media-generate'
|
|
6
|
+
>;
|
|
7
|
+
|
|
8
|
+
export function isAgentWorkspaceMediaCommandEditorKind(kind: AgentWorkspaceEditorKind): kind is AgentWorkspaceMediaCommandEditorKind {
|
|
9
|
+
return kind === 'media-generate';
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export function createAgentWorkspaceMediaCommandEditor(kind: AgentWorkspaceMediaCommandEditorKind): AgentWorkspaceLocalEditor {
|
|
13
|
+
return {
|
|
14
|
+
kind,
|
|
15
|
+
mode: 'create',
|
|
16
|
+
title: 'Generate Media',
|
|
17
|
+
selectedFieldIndex: 0,
|
|
18
|
+
message: 'Generate image or video artifacts through a configured media provider. Type yes on the final field to confirm.',
|
|
19
|
+
fields: [
|
|
20
|
+
{ id: 'prompt', label: 'Prompt', value: '', required: true, multiline: true, hint: 'Describe the media to generate. Ctrl-J inserts a new line.' },
|
|
21
|
+
{ id: 'provider', label: 'Provider', value: '', required: false, multiline: false, hint: 'Optional media provider id, such as fal, comfy, runway, alibaba, or byteplus.' },
|
|
22
|
+
{ id: 'model', label: 'Model', value: '', required: false, multiline: false, hint: 'Optional provider-specific media model id.' },
|
|
23
|
+
{ id: 'mime', label: 'Output MIME', value: '', required: false, multiline: false, hint: 'Optional output type, such as image/png or video/mp4.' },
|
|
24
|
+
{ id: 'confirm', label: 'Confirm', value: '', required: true, multiline: false, hint: 'Type yes to run /media generate with --yes.' },
|
|
25
|
+
],
|
|
26
|
+
};
|
|
27
|
+
}
|
|
@@ -36,7 +36,7 @@ export function createAgentWorkspaceMemoryCommandEditor(kind: AgentWorkspaceMemo
|
|
|
36
36
|
mode: 'create',
|
|
37
37
|
title: 'Search Agent Memory',
|
|
38
38
|
selectedFieldIndex: 0,
|
|
39
|
-
message: 'Search Agent-local memory only. This does not query default
|
|
39
|
+
message: 'Search Agent-local memory only. This does not query default knowledge or other product routes.',
|
|
40
40
|
fields: [
|
|
41
41
|
{ id: 'query', label: 'Query', value: '', required: false, multiline: false, hint: 'Optional text query. Blank searches by filters.' },
|
|
42
42
|
{ id: 'scope', label: 'Scope', value: '', required: false, multiline: false, hint: 'Optional session, project, or team.' },
|
|
@@ -34,7 +34,7 @@ export async function submitAgentWorkspaceMemoryEditor(
|
|
|
34
34
|
detail: detail.length > 0 ? detail : undefined,
|
|
35
35
|
tags,
|
|
36
36
|
});
|
|
37
|
-
if (!updated) throw new Error(`Unknown Agent memory
|
|
37
|
+
if (!updated) throw new Error(`Unknown Agent memory ${editor.recordId}`);
|
|
38
38
|
return { record: updated, verb: 'Updated' };
|
|
39
39
|
}
|
|
40
40
|
|
|
@@ -67,7 +67,7 @@ export function deleteAgentWorkspaceMemoryEditor(
|
|
|
67
67
|
const expectedId = editor.recordId ?? '';
|
|
68
68
|
if (!expectedId || confirmedId !== expectedId) return null;
|
|
69
69
|
const removed = memory.delete(expectedId);
|
|
70
|
-
if (!removed) throw new Error(`Unknown Agent memory
|
|
70
|
+
if (!removed) throw new Error(`Unknown Agent memory ${expectedId}`);
|
|
71
71
|
return { id: expectedId, name: expectedId };
|
|
72
72
|
}
|
|
73
73
|
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { AgentWorkspaceAction, AgentWorkspaceCategory, AgentWorkspaceFocusPane } from './agent-workspace-types.ts';
|
|
1
|
+
import type { AgentWorkspaceAction, AgentWorkspaceCategory, AgentWorkspaceCategoryId, AgentWorkspaceFocusPane } from './agent-workspace-types.ts';
|
|
2
2
|
|
|
3
3
|
interface AgentWorkspaceNavigationHost {
|
|
4
4
|
readonly categories: readonly AgentWorkspaceCategory[];
|
|
@@ -9,6 +9,42 @@ interface AgentWorkspaceNavigationHost {
|
|
|
9
9
|
clampSelection(): void;
|
|
10
10
|
}
|
|
11
11
|
|
|
12
|
+
const AGENT_WORKSPACE_CATEGORY_ALIASES = {
|
|
13
|
+
connected: 'host',
|
|
14
|
+
'connected-host': 'host',
|
|
15
|
+
host: 'host',
|
|
16
|
+
mcp: 'tools',
|
|
17
|
+
tool: 'tools',
|
|
18
|
+
channel: 'channels',
|
|
19
|
+
voice: 'voice-media',
|
|
20
|
+
media: 'voice-media',
|
|
21
|
+
profile: 'profiles',
|
|
22
|
+
persona: 'personas',
|
|
23
|
+
skill: 'skills',
|
|
24
|
+
routine: 'routines',
|
|
25
|
+
schedule: 'automation',
|
|
26
|
+
schedules: 'automation',
|
|
27
|
+
plan: 'work',
|
|
28
|
+
planning: 'work',
|
|
29
|
+
task: 'host',
|
|
30
|
+
tasks: 'host',
|
|
31
|
+
note: 'notes',
|
|
32
|
+
scratchpad: 'notes',
|
|
33
|
+
kb: 'knowledge',
|
|
34
|
+
} as const satisfies Readonly<Record<string, AgentWorkspaceCategoryId>>;
|
|
35
|
+
|
|
36
|
+
type AgentWorkspaceCategoryAlias = keyof typeof AGENT_WORKSPACE_CATEGORY_ALIASES;
|
|
37
|
+
|
|
38
|
+
function isAgentWorkspaceCategoryAlias(categoryIdOrLabel: string): categoryIdOrLabel is AgentWorkspaceCategoryAlias {
|
|
39
|
+
return Object.prototype.hasOwnProperty.call(AGENT_WORKSPACE_CATEGORY_ALIASES, categoryIdOrLabel);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
function normalizeAgentWorkspaceCategoryRequest(categoryIdOrLabel: string): string {
|
|
43
|
+
const normalized = categoryIdOrLabel.trim().toLowerCase();
|
|
44
|
+
if (!normalized) return '';
|
|
45
|
+
return isAgentWorkspaceCategoryAlias(normalized) ? AGENT_WORKSPACE_CATEGORY_ALIASES[normalized] : normalized;
|
|
46
|
+
}
|
|
47
|
+
|
|
12
48
|
export function moveAgentWorkspaceSelection(host: AgentWorkspaceNavigationHost, delta: -1 | 1): void {
|
|
13
49
|
if (host.focusPane === 'categories') {
|
|
14
50
|
host.selectedCategoryIndex = Math.max(0, Math.min(host.categories.length - 1, host.selectedCategoryIndex + delta));
|
|
@@ -29,7 +65,7 @@ export function jumpAgentWorkspaceSelection(host: AgentWorkspaceNavigationHost,
|
|
|
29
65
|
}
|
|
30
66
|
|
|
31
67
|
export function selectAgentWorkspaceCategory(host: AgentWorkspaceNavigationHost, categoryIdOrLabel: string): boolean {
|
|
32
|
-
const normalized = categoryIdOrLabel
|
|
68
|
+
const normalized = normalizeAgentWorkspaceCategoryRequest(categoryIdOrLabel);
|
|
33
69
|
if (!normalized) return false;
|
|
34
70
|
const categoryIndex = host.categories.findIndex((category) =>
|
|
35
71
|
category.id.toLowerCase() === normalized
|
|
@@ -3,7 +3,7 @@ import { quoteSlashCommandArg } from './slash-command-parser.ts';
|
|
|
3
3
|
|
|
4
4
|
type AgentWorkspaceFieldReader = (fieldId: string) => string;
|
|
5
5
|
|
|
6
|
-
export type AgentWorkspaceNotifyEditorKind = 'notify-webhook' | 'notify-webhook-remove' | 'notify-webhook-clear' | 'notify-webhook-test';
|
|
6
|
+
export type AgentWorkspaceNotifyEditorKind = 'notify-webhook' | 'notify-webhook-remove' | 'notify-webhook-clear' | 'notify-webhook-test' | 'notify-send';
|
|
7
7
|
|
|
8
8
|
export type AgentWorkspaceNotifyEditorSubmission =
|
|
9
9
|
| {
|
|
@@ -23,7 +23,8 @@ export function isAgentWorkspaceNotifyEditorKind(kind: string): kind is AgentWor
|
|
|
23
23
|
return kind === 'notify-webhook'
|
|
24
24
|
|| kind === 'notify-webhook-remove'
|
|
25
25
|
|| kind === 'notify-webhook-clear'
|
|
26
|
-
|| kind === 'notify-webhook-test'
|
|
26
|
+
|| kind === 'notify-webhook-test'
|
|
27
|
+
|| kind === 'notify-send';
|
|
27
28
|
}
|
|
28
29
|
|
|
29
30
|
function isAffirmative(value: string): boolean {
|
|
@@ -95,6 +96,19 @@ export function buildAgentWorkspaceNotifyEditorSubmission(
|
|
|
95
96
|
);
|
|
96
97
|
}
|
|
97
98
|
|
|
99
|
+
if (editor.kind === 'notify-send') {
|
|
100
|
+
if (!isAffirmative(readField('confirm'))) {
|
|
101
|
+
return unconfirmed(editor, 'Notification send not confirmed. Type yes, then press Enter.', 'Notification send not confirmed.');
|
|
102
|
+
}
|
|
103
|
+
const command = `/notify send ${quoteSlashCommandArg(readField('message'))} --yes`;
|
|
104
|
+
return dispatch(
|
|
105
|
+
command,
|
|
106
|
+
'Opening notification send',
|
|
107
|
+
'Opening notification send.',
|
|
108
|
+
'The workspace handed a confirmed notification send command to the shell-owned command router.',
|
|
109
|
+
);
|
|
110
|
+
}
|
|
111
|
+
|
|
98
112
|
if (!isAffirmative(readField('confirm'))) {
|
|
99
113
|
return unconfirmed(editor, 'Notification webhook test not confirmed. Type yes, then press Enter.', 'Notification webhook test not confirmed.');
|
|
100
114
|
}
|
|
@@ -9,6 +9,17 @@ function isAffirmative(value: string): boolean {
|
|
|
9
9
|
return /^(y|yes|true)$/i.test(value.trim());
|
|
10
10
|
}
|
|
11
11
|
|
|
12
|
+
function optionalNoteArgs(value: string): string {
|
|
13
|
+
const trimmed = value.trim();
|
|
14
|
+
return trimmed ? ` --note ${quoteSlashCommandArg(trimmed)}` : '';
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
function optionalRememberArgs(value: string): string {
|
|
18
|
+
const trimmed = value.trim();
|
|
19
|
+
if (!trimmed) return '';
|
|
20
|
+
return isAffirmative(trimmed) ? ' --remember' : ' --no-remember';
|
|
21
|
+
}
|
|
22
|
+
|
|
12
23
|
function unconfirmed(editor: AgentWorkspaceLocalEditor, message: string): AgentWorkspaceOperationsCommandEditorSubmission {
|
|
13
24
|
return {
|
|
14
25
|
kind: 'editor',
|
|
@@ -48,7 +59,7 @@ export function buildAgentWorkspaceOperationsCommandEditorSubmission(
|
|
|
48
59
|
actionResult: {
|
|
49
60
|
kind: 'dispatched',
|
|
50
61
|
title: 'Opening planning goal seeding',
|
|
51
|
-
detail: 'The workspace handed a concrete planning goal to the shell-owned command router without
|
|
62
|
+
detail: 'The workspace handed a concrete planning goal to the shell-owned command router without creating coding-role Agent jobs.',
|
|
52
63
|
command,
|
|
53
64
|
safety: 'safe',
|
|
54
65
|
},
|
|
@@ -100,6 +111,57 @@ export function buildAgentWorkspaceOperationsCommandEditorSubmission(
|
|
|
100
111
|
},
|
|
101
112
|
};
|
|
102
113
|
}
|
|
114
|
+
if (editor.kind === 'approval-approve' || editor.kind === 'approval-deny' || editor.kind === 'approval-cancel') {
|
|
115
|
+
if (!isAffirmative(readField('confirm'))) return unconfirmed(editor, 'Approval action not confirmed. Type yes, then press Enter.');
|
|
116
|
+
const verb = editor.kind.replace('approval-', '');
|
|
117
|
+
const command = `/approval ${verb} ${quoteSlashCommandArg(readField('approvalId'))}${optionalNoteArgs(readField('note'))}${optionalRememberArgs(readField('remember'))} --yes`;
|
|
118
|
+
const title = `${verb[0]?.toUpperCase() ?? ''}${verb.slice(1)} approval`;
|
|
119
|
+
return {
|
|
120
|
+
kind: 'dispatch',
|
|
121
|
+
command,
|
|
122
|
+
status: `${title}.`,
|
|
123
|
+
actionResult: {
|
|
124
|
+
kind: 'dispatched',
|
|
125
|
+
title,
|
|
126
|
+
detail: 'The workspace handed an explicit confirmed approval action to the shell-owned command router.',
|
|
127
|
+
command,
|
|
128
|
+
safety: 'safe',
|
|
129
|
+
},
|
|
130
|
+
};
|
|
131
|
+
}
|
|
132
|
+
if (
|
|
133
|
+
editor.kind === 'automation-job-run'
|
|
134
|
+
|| editor.kind === 'automation-job-pause'
|
|
135
|
+
|| editor.kind === 'automation-job-resume'
|
|
136
|
+
|| editor.kind === 'automation-run-cancel'
|
|
137
|
+
|| editor.kind === 'automation-run-retry'
|
|
138
|
+
|| editor.kind === 'schedule-run'
|
|
139
|
+
) {
|
|
140
|
+
if (!isAffirmative(readField('confirm'))) return unconfirmed(editor, 'Automation action not confirmed. Type yes, then press Enter.');
|
|
141
|
+
const command = editor.kind === 'automation-job-run'
|
|
142
|
+
? `/automation job run ${quoteSlashCommandArg(readField('jobId'))} --yes`
|
|
143
|
+
: editor.kind === 'automation-job-pause'
|
|
144
|
+
? `/automation job pause ${quoteSlashCommandArg(readField('jobId'))} --yes`
|
|
145
|
+
: editor.kind === 'automation-job-resume'
|
|
146
|
+
? `/automation job resume ${quoteSlashCommandArg(readField('jobId'))} --yes`
|
|
147
|
+
: editor.kind === 'automation-run-cancel'
|
|
148
|
+
? `/automation run cancel ${quoteSlashCommandArg(readField('runId'))} --yes`
|
|
149
|
+
: editor.kind === 'automation-run-retry'
|
|
150
|
+
? `/automation run retry ${quoteSlashCommandArg(readField('runId'))} --yes`
|
|
151
|
+
: `/automation schedule run ${quoteSlashCommandArg(readField('scheduleId'))} --yes`;
|
|
152
|
+
return {
|
|
153
|
+
kind: 'dispatch',
|
|
154
|
+
command,
|
|
155
|
+
status: 'Opening confirmed automation action.',
|
|
156
|
+
actionResult: {
|
|
157
|
+
kind: 'dispatched',
|
|
158
|
+
title: 'Opening confirmed automation action',
|
|
159
|
+
detail: 'The workspace handed an explicit connected-host automation action to the shell-owned command router.',
|
|
160
|
+
command,
|
|
161
|
+
safety: 'safe',
|
|
162
|
+
},
|
|
163
|
+
};
|
|
164
|
+
}
|
|
103
165
|
if (editor.kind === 'routine-receipt' || editor.kind === 'schedule-receipt') {
|
|
104
166
|
const routine = editor.kind === 'routine-receipt';
|
|
105
167
|
const command = `/${routine ? 'routines' : 'schedule'} receipt ${quoteSlashCommandArg(readField('receiptId'))}`;
|