@pellux/goodvibes-agent 0.1.117 → 1.0.1
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 +20 -4
- package/README.md +35 -14
- package/bin/goodvibes-agent.ts +16 -2
- package/dist/package/main.js +176093 -171065
- 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 +159 -73
- 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 +59 -39
- 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-knowledge-url-editor.ts +4 -11
- 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-local-library-args.ts +52 -0
- package/src/input/commands/agent-runtime-profile-runtime.ts +45 -41
- package/src/input/commands/agent-skills-runtime.ts +87 -99
- 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 +118 -50
- 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 +49 -59
- 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 +63 -72
- 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 +22 -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
|
@@ -32,10 +32,17 @@ export function registerShellCoreCommands(registry: CommandRegistry): void {
|
|
|
32
32
|
ctx.session.runtime.model = selected.registryKey;
|
|
33
33
|
ctx.session.runtime.provider = selected.providerId;
|
|
34
34
|
ctx.platform.configManager.set('provider.model', selected.registryKey);
|
|
35
|
-
ctx.print(
|
|
35
|
+
ctx.print([
|
|
36
|
+
'Switched model',
|
|
37
|
+
` model ${selected.displayName}`,
|
|
38
|
+
` provider ${selected.providerId}`,
|
|
39
|
+
].join('\n'));
|
|
36
40
|
void providerApi.recordModelUsage(selected.registryKey).catch((err) => { logger.debug('model usage record failed', { err }); });
|
|
37
41
|
} catch (e) {
|
|
38
|
-
ctx.print(
|
|
42
|
+
ctx.print([
|
|
43
|
+
'Error',
|
|
44
|
+
` message ${summarizeError(e)}`,
|
|
45
|
+
].join('\n'));
|
|
39
46
|
}
|
|
40
47
|
}
|
|
41
48
|
},
|
|
@@ -114,18 +121,20 @@ export function registerShellCoreCommands(registry: CommandRegistry): void {
|
|
|
114
121
|
handler(_args, ctx) {
|
|
115
122
|
if (ctx.openSelection) {
|
|
116
123
|
const items: SelectionItem[] = [
|
|
117
|
-
{ id: '/agent', label: '/agent', detail: 'Open the Agent operator workspace', category: 'Agent Operator' },
|
|
118
|
-
{ id: '/agent setup', label: '/agent setup', detail: 'Open the Agent setup workspace', category: 'Agent Operator' },
|
|
124
|
+
{ id: '/agent', label: '/agent', detail: 'Open the Agent operator workspace; press / inside it to search every action', category: 'Agent Operator' },
|
|
125
|
+
{ id: '/agent setup', label: '/agent setup', detail: 'Open the Agent setup workspace; workspace search can find every setup action', category: 'Agent Operator' },
|
|
119
126
|
{ id: '/agent channels', label: '/agent channels', detail: 'Open channel readiness and delivery safety', category: 'Agent Operator' },
|
|
120
127
|
{ id: '/agent knowledge', label: '/agent knowledge', detail: 'Open isolated Agent Knowledge workflows', category: 'Agent Operator' },
|
|
121
128
|
{ id: '/agent voice-media', label: '/agent voice-media', detail: 'Open voice, TTS, image, browser, and media setup', category: 'Agent Operator' },
|
|
122
129
|
{ id: '/home', label: '/home', detail: 'Alias for the Agent operator workspace', category: 'Agent Operator' },
|
|
123
130
|
{ id: '/brief', label: '/brief', detail: 'Show a concise Agent operator briefing and next actions', category: 'Agent Operator' },
|
|
124
131
|
{ id: '/knowledge', label: '/knowledge', detail: 'Inspect isolated Agent Knowledge status, ask/search, and ingest flows', category: 'Agent Operator' },
|
|
125
|
-
{ id: '/memory', label: '/memory', detail: 'Review local
|
|
126
|
-
{ id: '/
|
|
127
|
-
{ id: '/
|
|
132
|
+
{ id: '/memory', label: '/memory', detail: 'Review Agent-local memory records', category: 'Agent Operator' },
|
|
133
|
+
{ id: '/notes', label: '/notes', detail: 'Open Agent-local scratchpad notes for source triage and temporary context', category: 'Agent Operator' },
|
|
134
|
+
{ id: '/personas', label: '/personas', detail: 'Create, review, and activate Agent-local personas', category: 'Agent Operator' },
|
|
135
|
+
{ id: '/skills', label: '/skills', detail: 'Create, review, and enable reusable Agent skills', category: 'Agent Operator' },
|
|
128
136
|
{ id: '/routines', label: '/routines', detail: 'Create, review, start, and promote Agent routines explicitly', category: 'Agent Operator' },
|
|
137
|
+
{ id: '/automation', label: '/automation', detail: 'Run confirmed connected-host automation actions', category: 'Agent Operator' },
|
|
129
138
|
{ id: '/delegate', label: '/delegate [task]', detail: 'Explicit build/fix/review handoff to GoodVibes TUI', category: 'Agent Operator' },
|
|
130
139
|
{ id: '/channels', label: '/channels', detail: 'Inspect messaging-channel readiness without sending messages', category: 'Agent Operator' },
|
|
131
140
|
{ id: '/pair', label: '/pair', detail: 'Pair companion clients through connected GoodVibes host', category: 'Agent Operator' },
|
|
@@ -178,7 +187,7 @@ export function registerShellCoreCommands(registry: CommandRegistry): void {
|
|
|
178
187
|
});
|
|
179
188
|
return;
|
|
180
189
|
}
|
|
181
|
-
ctx.print('
|
|
190
|
+
ctx.print('Open the Agent workspace first, then press / inside it to search every product action. Slash commands remain available: /agent, /brief, /knowledge, /memory, /notes, /personas, /skills, /routines, /channels, /approval, /automation, /schedule, /delegate, /model, /provider, /config, /compat, /bundle, /paste, /sessions, /bookmarks, /save, /load, /undo, /redo, /retry, /clear, /reset, /compact, /export, /title, /effort, /expand, /collapse, /quit');
|
|
182
191
|
},
|
|
183
192
|
});
|
|
184
193
|
|
|
@@ -259,20 +268,23 @@ export function registerShellCoreCommands(registry: CommandRegistry): void {
|
|
|
259
268
|
const level = result.item.id as 'instant' | 'low' | 'medium' | 'high';
|
|
260
269
|
ctx.session.runtime.reasoningEffort = level;
|
|
261
270
|
ctx.platform.configManager.set('provider.reasoningEffort', level);
|
|
262
|
-
ctx.print(
|
|
271
|
+
ctx.print([
|
|
272
|
+
'Reasoning effort set',
|
|
273
|
+
` level ${level}`,
|
|
274
|
+
].join('\n'));
|
|
263
275
|
ctx.renderRequest();
|
|
264
276
|
});
|
|
265
277
|
return;
|
|
266
278
|
}
|
|
267
279
|
const budget = REASONING_BUDGET_MAP[current];
|
|
268
280
|
const lines = [
|
|
269
|
-
`Reasoning effort
|
|
270
|
-
` Mercury-2
|
|
271
|
-
` Claude
|
|
272
|
-
` Gemini
|
|
273
|
-
` GPT-5
|
|
281
|
+
`Reasoning effort ${current}`,
|
|
282
|
+
` Mercury-2 reasoning_effort = '${current}'`,
|
|
283
|
+
` Claude thinking.budget_tokens = ${budget}`,
|
|
284
|
+
` Gemini thinking_config.thinking_budget = ${budget}`,
|
|
285
|
+
` GPT-5 (no-op)`,
|
|
274
286
|
'',
|
|
275
|
-
`Levels
|
|
287
|
+
`Levels ${validLevels.join(', ')}`,
|
|
276
288
|
];
|
|
277
289
|
ctx.print(lines.join('\n'));
|
|
278
290
|
return;
|
|
@@ -280,13 +292,16 @@ export function registerShellCoreCommands(registry: CommandRegistry): void {
|
|
|
280
292
|
|
|
281
293
|
const level = args[0] as 'instant' | 'low' | 'medium' | 'high';
|
|
282
294
|
if (!validLevels.includes(level)) {
|
|
283
|
-
ctx.print(`Invalid effort level
|
|
295
|
+
ctx.print(`Invalid effort level ${level}\nValid levels ${validLevels.join(', ')}`);
|
|
284
296
|
return;
|
|
285
297
|
}
|
|
286
298
|
|
|
287
299
|
ctx.session.runtime.reasoningEffort = level;
|
|
288
300
|
ctx.platform.configManager.set('provider.reasoningEffort', level);
|
|
289
|
-
ctx.print(
|
|
301
|
+
ctx.print([
|
|
302
|
+
'Reasoning effort set',
|
|
303
|
+
` level ${level}`,
|
|
304
|
+
].join('\n'));
|
|
290
305
|
},
|
|
291
306
|
});
|
|
292
307
|
|
|
@@ -1,14 +1,13 @@
|
|
|
1
1
|
import { mkdirSync, readFileSync, writeFileSync } from 'node:fs';
|
|
2
2
|
import { dirname, resolve } from 'node:path';
|
|
3
3
|
import type { CommandContext, CommandRegistry } from '../command-registry.ts';
|
|
4
|
-
import { createOAuthLocalListener } from '@pellux/goodvibes-sdk/platform/config';
|
|
5
4
|
import { beginOpenAICodexLogin, exchangeOpenAICodexCode } from '@pellux/goodvibes-sdk/platform/config';
|
|
6
5
|
import type { OAuthProviderConfig, ProviderSubscription } from '@pellux/goodvibes-sdk/platform/config';
|
|
7
6
|
import { getSubscriptionProviderConfig, listAvailableSubscriptionProviders } from '@pellux/goodvibes-sdk/platform/config';
|
|
8
7
|
import { inspectProviderAuth } from '@/runtime/index.ts';
|
|
8
|
+
import { formatAgentRecordSource } from '../../agent/record-labels.ts';
|
|
9
9
|
import { openExternalUrl } from '@pellux/goodvibes-sdk/platform/utils';
|
|
10
10
|
import { requireSecretsManager, requireServiceRegistry, requireShellPaths, requireSubscriptionManager } from './runtime-services.ts';
|
|
11
|
-
import { summarizeError } from '@pellux/goodvibes-sdk/platform/utils';
|
|
12
11
|
import { requireYesFlag, stripYesFlag } from './confirmation.ts';
|
|
13
12
|
|
|
14
13
|
interface SubscriptionBundle {
|
|
@@ -24,13 +23,13 @@ function buildReviewText(ctx: CommandContext): string {
|
|
|
24
23
|
return [
|
|
25
24
|
'Subscription Review',
|
|
26
25
|
' No provider subscriptions stored yet.',
|
|
27
|
-
...(available.length > 0 ? [` available providers
|
|
26
|
+
...(available.length > 0 ? [` available providers ${available.map((entry) => entry.provider).join(', ')}`] : []),
|
|
28
27
|
].join('\n');
|
|
29
28
|
}
|
|
30
29
|
return [
|
|
31
30
|
`Subscription Review`,
|
|
32
31
|
...subscriptions.map((subscription) => (
|
|
33
|
-
` ${subscription.provider} ${subscription.authMode} token
|
|
32
|
+
` ${subscription.provider} auth mode ${subscription.authMode} token ${subscription.tokenType} expires ${subscription.expiresAt ? new Date(subscription.expiresAt).toISOString() : 'n/a'}`
|
|
34
33
|
)),
|
|
35
34
|
].join('\n');
|
|
36
35
|
}
|
|
@@ -39,8 +38,8 @@ function inspectBundle(path: string): string {
|
|
|
39
38
|
const bundle = JSON.parse(readFileSync(path, 'utf-8')) as SubscriptionBundle;
|
|
40
39
|
return [
|
|
41
40
|
'Subscription Bundle Review',
|
|
42
|
-
`
|
|
43
|
-
` subscriptions
|
|
41
|
+
` exported at ${new Date(bundle.exportedAt).toISOString()}`,
|
|
42
|
+
` subscriptions ${bundle.subscriptions.length}`,
|
|
44
43
|
...bundle.subscriptions.map((subscription) => ` ${subscription.provider} ${subscription.authMode}`),
|
|
45
44
|
].join('\n');
|
|
46
45
|
}
|
|
@@ -57,19 +56,16 @@ function extractAuthorizationCode(input: string): string | null {
|
|
|
57
56
|
}
|
|
58
57
|
}
|
|
59
58
|
|
|
60
|
-
function
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
: config;
|
|
65
|
-
}
|
|
66
|
-
return config;
|
|
59
|
+
function resolveManualLoginConfig(config: OAuthProviderConfig): OAuthProviderConfig {
|
|
60
|
+
return config.manualRedirectUri
|
|
61
|
+
? { ...config, redirectUri: config.manualRedirectUri }
|
|
62
|
+
: config;
|
|
67
63
|
}
|
|
68
64
|
|
|
69
65
|
function describePrecedence(record: Pick<ProviderSubscription, 'overrideAmbientApiKeys'>): string {
|
|
70
66
|
return record.overrideAmbientApiKeys
|
|
71
|
-
? ' precedence
|
|
72
|
-
: ' precedence
|
|
67
|
+
? ' precedence this now overrides ambient API keys for the provider'
|
|
68
|
+
: ' precedence stored for subscription-backed flows only; ambient API keys are unchanged';
|
|
73
69
|
}
|
|
74
70
|
|
|
75
71
|
export function registerSubscriptionRuntimeCommands(registry: CommandRegistry): void {
|
|
@@ -77,7 +73,7 @@ export function registerSubscriptionRuntimeCommands(registry: CommandRegistry):
|
|
|
77
73
|
name: 'subscription',
|
|
78
74
|
aliases: ['subs'],
|
|
79
75
|
description: 'Manage provider subscription sessions and, when supported, let them override ambient API keys for matching providers',
|
|
80
|
-
usage: '[review|list|providers|inspect <provider>|login <provider> start [--no-browser]
|
|
76
|
+
usage: '[review|list|providers|inspect <provider>|login <provider> start [--no-browser] --yes|login <provider> finish <code-or-url> --yes|logout <provider> --yes|bundle export <path> --yes|bundle inspect <path>]',
|
|
81
77
|
async handler(args, ctx) {
|
|
82
78
|
const parsed = stripYesFlag(args);
|
|
83
79
|
const commandArgs = [...parsed.rest];
|
|
@@ -99,7 +95,7 @@ export function registerSubscriptionRuntimeCommands(registry: CommandRegistry):
|
|
|
99
95
|
ctx.print([
|
|
100
96
|
'Available Subscription Providers',
|
|
101
97
|
...available.map((provider) => (
|
|
102
|
-
` ${provider.provider}
|
|
98
|
+
` ${provider.provider} origin ${formatAgentRecordSource(provider.source)} redirect ${provider.oauth.redirectUri}`
|
|
103
99
|
)),
|
|
104
100
|
].join('\n'));
|
|
105
101
|
return;
|
|
@@ -123,29 +119,28 @@ export function registerSubscriptionRuntimeCommands(registry: CommandRegistry):
|
|
|
123
119
|
});
|
|
124
120
|
ctx.print([
|
|
125
121
|
`Subscription ${provider}`,
|
|
126
|
-
` configured
|
|
127
|
-
` freshness
|
|
128
|
-
|
|
122
|
+
` configured ${inspection.configured ? 'yes' : 'no'}`,
|
|
123
|
+
` freshness ${inspection.freshness}`,
|
|
124
|
+
' finish mode explicit manual',
|
|
129
125
|
...(resolved ? [
|
|
130
|
-
`
|
|
131
|
-
`
|
|
132
|
-
`
|
|
133
|
-
`
|
|
134
|
-
...(inspection.localCallback ? [` localCallback: ${inspection.localCallback}`] : []),
|
|
126
|
+
` origin ${formatAgentRecordSource(resolved.source)}`,
|
|
127
|
+
` redirect URI ${resolved.oauth.redirectUri}`,
|
|
128
|
+
` auth URL ${resolved.oauth.authUrl}`,
|
|
129
|
+
` token URL ${resolved.oauth.tokenUrl}`,
|
|
135
130
|
] : []),
|
|
136
131
|
...(inspection.activeSubscription ? [
|
|
137
|
-
`
|
|
138
|
-
`
|
|
139
|
-
`
|
|
140
|
-
`
|
|
141
|
-
`
|
|
142
|
-
`
|
|
132
|
+
` auth mode ${manager.get(provider)?.authMode ?? 'oauth'}`,
|
|
133
|
+
` token type ${inspection.tokenType ?? 'n/a'}`,
|
|
134
|
+
` created at ${manager.get(provider)?.createdAt ? new Date(manager.get(provider)!.createdAt).toISOString() : 'n/a'}`,
|
|
135
|
+
` updated at ${manager.get(provider)?.updatedAt ? new Date(manager.get(provider)!.updatedAt).toISOString() : 'n/a'}`,
|
|
136
|
+
` expires at ${inspection.expiresAt ? new Date(inspection.expiresAt).toISOString() : 'n/a'}`,
|
|
137
|
+
` refresh token ${manager.get(provider)?.refreshToken ? 'present' : 'absent'}`,
|
|
143
138
|
describePrecedence(manager.get(provider)!),
|
|
144
139
|
] : [
|
|
145
|
-
` state
|
|
140
|
+
` state ${inspection.freshness === 'pending' ? 'pending login' : 'available for login'}`,
|
|
146
141
|
]),
|
|
147
|
-
...inspection.issues.map((issue) => ` issue
|
|
148
|
-
...inspection.nextActions.map((action) => ` next
|
|
142
|
+
...inspection.issues.map((issue) => ` issue ${issue}`),
|
|
143
|
+
...inspection.nextActions.map((action) => ` next ${action}`),
|
|
149
144
|
].join('\n'));
|
|
150
145
|
return;
|
|
151
146
|
}
|
|
@@ -174,7 +169,6 @@ export function registerSubscriptionRuntimeCommands(registry: CommandRegistry):
|
|
|
174
169
|
if (mode === 'start') {
|
|
175
170
|
const flags = new Set(commandArgs.slice(3));
|
|
176
171
|
const openBrowser = !flags.has('--no-browser');
|
|
177
|
-
const useManualMode = flags.has('--manual');
|
|
178
172
|
if (provider === 'openai' && resolved.source === 'builtin') {
|
|
179
173
|
const started = await beginOpenAICodexLogin();
|
|
180
174
|
manager.savePending({
|
|
@@ -185,158 +179,38 @@ export function registerSubscriptionRuntimeCommands(registry: CommandRegistry):
|
|
|
185
179
|
createdAt: Date.now(),
|
|
186
180
|
});
|
|
187
181
|
|
|
188
|
-
let listener: Awaited<ReturnType<typeof createOAuthLocalListener>> | null = null;
|
|
189
|
-
if (!useManualMode) {
|
|
190
|
-
try {
|
|
191
|
-
listener = await createOAuthLocalListener({
|
|
192
|
-
expectedState: started.state,
|
|
193
|
-
host: '127.0.0.1',
|
|
194
|
-
port: 1455,
|
|
195
|
-
path: '/auth/callback',
|
|
196
|
-
}).catch(() => null); // best-effort: listener creation is optional; null triggers manual flow
|
|
197
|
-
} catch {
|
|
198
|
-
listener = null;
|
|
199
|
-
}
|
|
200
|
-
}
|
|
201
|
-
|
|
202
182
|
const browserOpened = openBrowser
|
|
203
183
|
? await openExternalUrl(started.authorizationUrl)
|
|
204
184
|
: false;
|
|
205
185
|
|
|
206
|
-
if (listener && browserOpened) {
|
|
207
|
-
try {
|
|
208
|
-
const callback = await listener.waitForCode();
|
|
209
|
-
const token = await exchangeOpenAICodexCode(callback.code, started.verifier);
|
|
210
|
-
const now = Date.now();
|
|
211
|
-
const record = manager.saveSubscription({
|
|
212
|
-
provider,
|
|
213
|
-
accessToken: token.accessToken,
|
|
214
|
-
refreshToken: token.refreshToken,
|
|
215
|
-
tokenType: token.tokenType,
|
|
216
|
-
expiresAt: token.expiresAt,
|
|
217
|
-
...(token.scopes ? { scopes: token.scopes } : {}),
|
|
218
|
-
authMode: 'oauth',
|
|
219
|
-
overrideAmbientApiKeys: false,
|
|
220
|
-
createdAt: manager.get(provider)?.createdAt ?? now,
|
|
221
|
-
updatedAt: now,
|
|
222
|
-
});
|
|
223
|
-
ctx.print([
|
|
224
|
-
`Subscription OAuth Start: ${provider}`,
|
|
225
|
-
` source: ${resolved.source}`,
|
|
226
|
-
` state: ${started.state}`,
|
|
227
|
-
` redirectUri: ${started.redirectUri}`,
|
|
228
|
-
` browser: ${openBrowser ? (browserOpened ? 'opened' : 'open failed') : 'skipped'}`,
|
|
229
|
-
' authorizationUrl:',
|
|
230
|
-
` ${started.authorizationUrl}`,
|
|
231
|
-
`Subscription OAuth Complete: ${provider}`,
|
|
232
|
-
` tokenType: ${record.tokenType}`,
|
|
233
|
-
` expiresAt: ${record.expiresAt ? new Date(record.expiresAt).toISOString() : 'n/a'}`,
|
|
234
|
-
describePrecedence(record),
|
|
235
|
-
].join('\n'));
|
|
236
|
-
return;
|
|
237
|
-
} catch (error) {
|
|
238
|
-
listener.close();
|
|
239
|
-
ctx.print([
|
|
240
|
-
`Subscription OAuth Start: ${provider}`,
|
|
241
|
-
` source: ${resolved.source}`,
|
|
242
|
-
` state: ${started.state}`,
|
|
243
|
-
` redirectUri: ${started.redirectUri}`,
|
|
244
|
-
` browser: ${openBrowser ? (browserOpened ? 'opened' : 'open failed') : 'skipped'}`,
|
|
245
|
-
` next: /subscription login ${provider} finish <code-or-url> --yes`,
|
|
246
|
-
` listener: ${summarizeError(error)}`,
|
|
247
|
-
' authorizationUrl:',
|
|
248
|
-
` ${started.authorizationUrl}`,
|
|
249
|
-
].join('\n'));
|
|
250
|
-
return;
|
|
251
|
-
}
|
|
252
|
-
}
|
|
253
|
-
|
|
254
|
-
listener?.close();
|
|
255
186
|
ctx.print([
|
|
256
|
-
`Subscription OAuth
|
|
257
|
-
`
|
|
258
|
-
` state
|
|
259
|
-
`
|
|
260
|
-
` browser
|
|
261
|
-
|
|
262
|
-
|
|
187
|
+
`Subscription OAuth start ${provider}`,
|
|
188
|
+
` origin ${formatAgentRecordSource(resolved.source)}`,
|
|
189
|
+
` state ${started.state}`,
|
|
190
|
+
` redirect URI ${started.redirectUri}`,
|
|
191
|
+
` browser ${openBrowser ? (browserOpened ? 'opened' : 'open failed') : 'skipped'}`,
|
|
192
|
+
' completion paste the callback code or redirect URL into the finish command',
|
|
193
|
+
` next /subscription login ${provider} finish <code-or-url> --yes`,
|
|
194
|
+
' authorization URL',
|
|
263
195
|
` ${started.authorizationUrl}`,
|
|
264
196
|
].join('\n'));
|
|
265
197
|
return;
|
|
266
198
|
}
|
|
267
|
-
const
|
|
268
|
-
let activeConfig = resolveLoginConfig(resolved.oauth, useLocalCallback);
|
|
269
|
-
let listener: Awaited<ReturnType<typeof createOAuthLocalListener>> | null = null;
|
|
270
|
-
|
|
271
|
-
if (useLocalCallback && resolved.oauth.localCallback) {
|
|
272
|
-
listener = await createOAuthLocalListener({
|
|
273
|
-
expectedState: '',
|
|
274
|
-
host: resolved.oauth.localCallback.host,
|
|
275
|
-
port: resolved.oauth.localCallback.port,
|
|
276
|
-
path: resolved.oauth.localCallback.path,
|
|
277
|
-
}).catch(() => null); // best-effort: local callback listener is optional; null falls back to manual redirect
|
|
278
|
-
}
|
|
279
|
-
|
|
280
|
-
if (listener) {
|
|
281
|
-
activeConfig = { ...activeConfig, redirectUri: listener.redirectUri };
|
|
282
|
-
}
|
|
283
|
-
|
|
199
|
+
const activeConfig = resolveManualLoginConfig(resolved.oauth);
|
|
284
200
|
const started = await manager.beginOAuthLogin(provider, activeConfig);
|
|
285
|
-
if (listener) {
|
|
286
|
-
listener.setExpectedState(started.pending.state);
|
|
287
|
-
}
|
|
288
|
-
|
|
289
201
|
const browserOpened = openBrowser
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
const shouldAutoComplete = Boolean(listener) && (resolved.oauth.localCallback?.autoComplete ?? true) && browserOpened;
|
|
294
|
-
|
|
295
|
-
if (shouldAutoComplete && listener) {
|
|
296
|
-
try {
|
|
297
|
-
const callback = await listener.waitForCode();
|
|
298
|
-
const record = await manager.completeOAuthLogin(provider, activeConfig, callback.code);
|
|
299
|
-
ctx.print([
|
|
300
|
-
`Subscription OAuth Start: ${provider}`,
|
|
301
|
-
` source: ${resolved.source}`,
|
|
302
|
-
` state: ${started.pending.state}`,
|
|
303
|
-
` redirectUri: ${activeConfig.redirectUri}`,
|
|
304
|
-
` browser: ${openBrowser ? (browserOpened ? 'opened' : 'open failed') : 'skipped'}`,
|
|
305
|
-
' authorizationUrl:',
|
|
306
|
-
` ${started.authorizationUrl}`,
|
|
307
|
-
`Subscription OAuth Complete: ${provider}`,
|
|
308
|
-
` tokenType: ${record.tokenType}`,
|
|
309
|
-
` expiresAt: ${record.expiresAt ? new Date(record.expiresAt).toISOString() : 'n/a'}`,
|
|
310
|
-
describePrecedence(record),
|
|
311
|
-
].join('\n'));
|
|
312
|
-
return;
|
|
313
|
-
} catch (error) {
|
|
314
|
-
listener.close();
|
|
315
|
-
ctx.print([
|
|
316
|
-
`Subscription OAuth Start: ${provider}`,
|
|
317
|
-
` source: ${resolved.source}`,
|
|
318
|
-
` state: ${started.pending.state}`,
|
|
319
|
-
` redirectUri: ${activeConfig.redirectUri}`,
|
|
320
|
-
` browser: ${openBrowser ? (browserOpened ? 'opened' : 'open failed') : 'skipped'}`,
|
|
321
|
-
` next: /subscription login ${provider} finish <code-or-url> --yes`,
|
|
322
|
-
` listener: ${summarizeError(error)}`,
|
|
323
|
-
' authorizationUrl:',
|
|
324
|
-
` ${started.authorizationUrl}`,
|
|
325
|
-
].join('\n'));
|
|
326
|
-
return;
|
|
327
|
-
}
|
|
328
|
-
}
|
|
329
|
-
|
|
330
|
-
listener?.close();
|
|
202
|
+
? await openExternalUrl(started.authorizationUrl)
|
|
203
|
+
: false;
|
|
331
204
|
|
|
332
205
|
ctx.print([
|
|
333
|
-
`Subscription OAuth
|
|
334
|
-
`
|
|
335
|
-
` state
|
|
336
|
-
`
|
|
337
|
-
` browser
|
|
338
|
-
|
|
339
|
-
|
|
206
|
+
`Subscription OAuth start ${provider}`,
|
|
207
|
+
` origin ${formatAgentRecordSource(resolved.source)}`,
|
|
208
|
+
` state ${started.pending.state}`,
|
|
209
|
+
` redirect URI ${activeConfig.redirectUri}`,
|
|
210
|
+
` browser ${openBrowser ? (browserOpened ? 'opened' : 'open failed') : 'skipped'}`,
|
|
211
|
+
' completion paste the callback code or redirect URL into the finish command',
|
|
212
|
+
` next /subscription login ${provider} finish <code-or-url> --yes`,
|
|
213
|
+
' authorization URL',
|
|
340
214
|
` ${started.authorizationUrl}`,
|
|
341
215
|
].join('\n'));
|
|
342
216
|
return;
|
|
@@ -370,18 +244,18 @@ export function registerSubscriptionRuntimeCommands(registry: CommandRegistry):
|
|
|
370
244
|
});
|
|
371
245
|
ctx.print([
|
|
372
246
|
`Stored subscription session for ${provider}.`,
|
|
373
|
-
`
|
|
374
|
-
`
|
|
247
|
+
` token type ${record.tokenType}`,
|
|
248
|
+
` expires at ${record.expiresAt ? new Date(record.expiresAt).toISOString() : 'n/a'}`,
|
|
375
249
|
describePrecedence(record),
|
|
376
250
|
].join('\n'));
|
|
377
251
|
return;
|
|
378
252
|
}
|
|
379
|
-
const activeConfig =
|
|
253
|
+
const activeConfig = resolveManualLoginConfig(resolved.oauth);
|
|
380
254
|
const record = await manager.completeOAuthLogin(provider, activeConfig, code);
|
|
381
255
|
ctx.print([
|
|
382
256
|
`Stored subscription session for ${provider}.`,
|
|
383
|
-
`
|
|
384
|
-
`
|
|
257
|
+
` token type ${record.tokenType}`,
|
|
258
|
+
` expires at ${record.expiresAt ? new Date(record.expiresAt).toISOString() : 'n/a'}`,
|
|
385
259
|
describePrecedence(record),
|
|
386
260
|
].join('\n'));
|
|
387
261
|
return;
|
|
@@ -16,10 +16,10 @@ const BLOCKED_TASK_MUTATIONS: ReadonlySet<string> = new Set([
|
|
|
16
16
|
function printTaskMutationBlocked(print: (text: string) => void, subcommand: string): void {
|
|
17
17
|
print([
|
|
18
18
|
`Task mutation "${subcommand}" is blocked in GoodVibes Agent.`,
|
|
19
|
-
' policy
|
|
20
|
-
' durable tasks
|
|
21
|
-
' build/fix/review
|
|
22
|
-
' result
|
|
19
|
+
' policy connected-host tasks are read-only from the Agent TUI; normal work stays in the main conversation.',
|
|
20
|
+
' durable tasks use /workplan for visible planning and task tracking.',
|
|
21
|
+
' build/fix/review use /delegate <task> to hand explicit implementation work to GoodVibes TUI.',
|
|
22
|
+
' result no local task state was changed.',
|
|
23
23
|
].join('\n'));
|
|
24
24
|
}
|
|
25
25
|
|
|
@@ -56,7 +56,7 @@ export function registerTasksRuntimeCommands(registry: CommandRegistry): void {
|
|
|
56
56
|
handler(args, ctx) {
|
|
57
57
|
const subcommand = args[0]?.toLowerCase() ?? 'list';
|
|
58
58
|
if (subcommand === 'open' || subcommand === 'panel') {
|
|
59
|
-
ctx.print('
|
|
59
|
+
ctx.print('Open Agent Workspace -> Work -> Host tasks for the workspace view, or run /tasks list for compact command output.');
|
|
60
60
|
return;
|
|
61
61
|
}
|
|
62
62
|
|
|
@@ -76,7 +76,7 @@ export function registerTasksRuntimeCommands(registry: CommandRegistry): void {
|
|
|
76
76
|
return;
|
|
77
77
|
}
|
|
78
78
|
ctx.print([
|
|
79
|
-
`
|
|
79
|
+
`Connected-host Tasks (${filtered.length})`,
|
|
80
80
|
...filtered.slice(0, 20).map((task) => ` ${task.id} ${task.status.padEnd(9)} ${task.kind.padEnd(11)} ${task.owner} ${task.title}`),
|
|
81
81
|
].join('\n'));
|
|
82
82
|
return;
|
|
@@ -90,23 +90,23 @@ export function registerTasksRuntimeCommands(registry: CommandRegistry): void {
|
|
|
90
90
|
}
|
|
91
91
|
const task = operatorClient.tasks.get(taskId);
|
|
92
92
|
if (!task) {
|
|
93
|
-
ctx.print(`Unknown task
|
|
93
|
+
ctx.print(`Unknown task ${taskId}`);
|
|
94
94
|
return;
|
|
95
95
|
}
|
|
96
96
|
ctx.print([
|
|
97
97
|
`Task ${task.id}`,
|
|
98
|
-
` title
|
|
98
|
+
` title ${task.title}`,
|
|
99
99
|
` kind: ${task.kind}`,
|
|
100
|
-
` status
|
|
101
|
-
` owner
|
|
102
|
-
` cancellable
|
|
103
|
-
`
|
|
104
|
-
`
|
|
105
|
-
`
|
|
106
|
-
` parent
|
|
107
|
-
` children
|
|
108
|
-
`
|
|
109
|
-
` summary
|
|
100
|
+
` status ${task.status}`,
|
|
101
|
+
` owner ${task.owner}`,
|
|
102
|
+
` cancellable ${task.cancellable ? 'yes' : 'no'}`,
|
|
103
|
+
` queued at ${new Date(task.queuedAt).toISOString()}`,
|
|
104
|
+
` started at ${task.startedAt ? new Date(task.startedAt).toISOString() : 'n/a'}`,
|
|
105
|
+
` ended at ${task.endedAt ? new Date(task.endedAt).toISOString() : 'n/a'}`,
|
|
106
|
+
` parent ${task.parentTaskId ?? 'none'}`,
|
|
107
|
+
` children ${task.childTaskIds.join(', ') || '(none)'}`,
|
|
108
|
+
` correlation ID ${task.correlationId ?? 'n/a'}`,
|
|
109
|
+
` summary ${summarizeTaskResult(task)}`,
|
|
110
110
|
].join('\n'));
|
|
111
111
|
return;
|
|
112
112
|
}
|
|
@@ -119,7 +119,7 @@ export function registerTasksRuntimeCommands(registry: CommandRegistry): void {
|
|
|
119
119
|
}
|
|
120
120
|
const task = operatorClient.tasks.get(taskId);
|
|
121
121
|
if (!task) {
|
|
122
|
-
ctx.print(`Unknown task
|
|
122
|
+
ctx.print(`Unknown task ${taskId}`);
|
|
123
123
|
return;
|
|
124
124
|
}
|
|
125
125
|
const payload = typeof task.result === 'string'
|
|
@@ -131,7 +131,7 @@ export function registerTasksRuntimeCommands(registry: CommandRegistry): void {
|
|
|
131
131
|
return;
|
|
132
132
|
}
|
|
133
133
|
|
|
134
|
-
ctx.print(`Unknown tasks subcommand
|
|
134
|
+
ctx.print(`Unknown tasks subcommand ${subcommand}`);
|
|
135
135
|
},
|
|
136
136
|
});
|
|
137
137
|
}
|
|
@@ -26,7 +26,12 @@ function getStore(ctx: import('../command-registry.ts').CommandContext): WorkPla
|
|
|
26
26
|
|
|
27
27
|
function formatList(store: WorkPlanStore): string {
|
|
28
28
|
const items = store.listItems();
|
|
29
|
-
if (items.length === 0)
|
|
29
|
+
if (items.length === 0) {
|
|
30
|
+
return [
|
|
31
|
+
'Work plan is empty',
|
|
32
|
+
' next /workplan add <title>',
|
|
33
|
+
].join('\n');
|
|
34
|
+
}
|
|
30
35
|
return [
|
|
31
36
|
`Work Plan (${items.length})`,
|
|
32
37
|
...items.map((item) => {
|
|
@@ -83,7 +88,7 @@ export function registerWorkPlanRuntimeCommands(registry: CommandRegistry): void
|
|
|
83
88
|
const subcommand = (commandArgs[0] ?? 'list').toLowerCase();
|
|
84
89
|
try {
|
|
85
90
|
if (subcommand === 'panel' || subcommand === 'open') {
|
|
86
|
-
ctx.print('
|
|
91
|
+
ctx.print('Open Agent Workspace -> Work -> Work plan for the workspace view, or run /workplan list for compact command output.');
|
|
87
92
|
return;
|
|
88
93
|
}
|
|
89
94
|
if (subcommand === 'list') {
|
|
@@ -106,7 +111,12 @@ export function registerWorkPlanRuntimeCommands(registry: CommandRegistry): void
|
|
|
106
111
|
...(addArgs.notes ? { notes: addArgs.notes } : {}),
|
|
107
112
|
};
|
|
108
113
|
const item = store.addItem(addArgs.title, addOptions);
|
|
109
|
-
ctx.print(
|
|
114
|
+
ctx.print([
|
|
115
|
+
'Added work plan item',
|
|
116
|
+
` id ${item.id}`,
|
|
117
|
+
` title ${item.title}`,
|
|
118
|
+
' next open Agent Workspace -> Work -> Work plan to review',
|
|
119
|
+
].join('\n'));
|
|
110
120
|
return;
|
|
111
121
|
}
|
|
112
122
|
if (subcommand === 'remove' || subcommand === 'delete' || subcommand === 'rm') {
|
|
@@ -120,7 +130,11 @@ export function registerWorkPlanRuntimeCommands(registry: CommandRegistry): void
|
|
|
120
130
|
return;
|
|
121
131
|
}
|
|
122
132
|
const item = store.removeItem(id);
|
|
123
|
-
ctx.print(
|
|
133
|
+
ctx.print([
|
|
134
|
+
'Removed work plan item',
|
|
135
|
+
` id ${item.id}`,
|
|
136
|
+
` title ${item.title}`,
|
|
137
|
+
].join('\n'));
|
|
124
138
|
return;
|
|
125
139
|
}
|
|
126
140
|
if (subcommand === 'clear-done' || subcommand === 'clear-completed') {
|
|
@@ -129,7 +143,10 @@ export function registerWorkPlanRuntimeCommands(registry: CommandRegistry): void
|
|
|
129
143
|
return;
|
|
130
144
|
}
|
|
131
145
|
const count = store.clearCompleted();
|
|
132
|
-
ctx.print(
|
|
146
|
+
ctx.print([
|
|
147
|
+
'Cleared completed/cancelled work plan items',
|
|
148
|
+
` count ${count}`,
|
|
149
|
+
].join('\n'));
|
|
133
150
|
return;
|
|
134
151
|
}
|
|
135
152
|
if (subcommand === 'cycle' || subcommand === 'toggle') {
|
|
@@ -139,7 +156,11 @@ export function registerWorkPlanRuntimeCommands(registry: CommandRegistry): void
|
|
|
139
156
|
return;
|
|
140
157
|
}
|
|
141
158
|
const item = store.cycleItemStatus(id);
|
|
142
|
-
ctx.print(
|
|
159
|
+
ctx.print([
|
|
160
|
+
'Updated work plan item',
|
|
161
|
+
` id ${item.id}`,
|
|
162
|
+
` status ${item.status}`,
|
|
163
|
+
].join('\n'));
|
|
143
164
|
return;
|
|
144
165
|
}
|
|
145
166
|
const status = STATUS_COMMANDS[subcommand];
|
|
@@ -150,14 +171,18 @@ export function registerWorkPlanRuntimeCommands(registry: CommandRegistry): void
|
|
|
150
171
|
return;
|
|
151
172
|
}
|
|
152
173
|
const item = store.setItemStatus(id, status);
|
|
153
|
-
ctx.print(
|
|
174
|
+
ctx.print([
|
|
175
|
+
'Updated work plan item',
|
|
176
|
+
` id ${item.id}`,
|
|
177
|
+
` status ${item.status}`,
|
|
178
|
+
].join('\n'));
|
|
154
179
|
return;
|
|
155
180
|
}
|
|
156
181
|
if (WORK_PLAN_STATUSES.includes(subcommand as WorkPlanItemStatus)) {
|
|
157
182
|
ctx.print(`Usage: /workplan ${subcommand} <id>`);
|
|
158
183
|
return;
|
|
159
184
|
}
|
|
160
|
-
ctx.print(`Unknown workplan subcommand
|
|
185
|
+
ctx.print(`Unknown workplan subcommand ${subcommand}`);
|
|
161
186
|
} catch (error) {
|
|
162
187
|
ctx.print(summarizeError(error));
|
|
163
188
|
}
|