@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
|
@@ -1,16 +1,25 @@
|
|
|
1
1
|
import { mkdirSync, writeFileSync } from 'node:fs';
|
|
2
|
-
import { dirname
|
|
2
|
+
import { dirname } from 'node:path';
|
|
3
3
|
import { SecretsManager } from '../config/secrets.ts';
|
|
4
4
|
import { BUILTIN_SECRET_PROVIDER_SOURCES, describeSecretRef, isSecretRefInput, resolveSecretRef } from '@pellux/goodvibes-sdk/platform/config';
|
|
5
5
|
import { getSubscriptionProviderConfig, listAvailableSubscriptionProviders } from '@pellux/goodvibes-sdk/platform/config';
|
|
6
|
+
import type { OAuthProviderConfig } from '@pellux/goodvibes-sdk/platform/config';
|
|
6
7
|
import { beginOpenAICodexLogin, exchangeOpenAICodexCode } from '@pellux/goodvibes-sdk/platform/config';
|
|
7
8
|
import { inspectProviderAuth } from '@/runtime/index.ts';
|
|
8
|
-
import {
|
|
9
|
+
import { buildCompanionConnectionInfo, encodeConnectionPayload, formatConnectionBlock } from '@pellux/goodvibes-sdk/platform/pairing';
|
|
9
10
|
import { generateQrMatrix, renderQrToString } from '@pellux/goodvibes-sdk/platform/pairing';
|
|
10
11
|
import { resolveRuntimeEndpointBinding } from './endpoints.ts';
|
|
11
12
|
import type { CliCommandRuntime } from './management.ts';
|
|
12
13
|
import { extractAuthorizationCode, formatJsonOrText, hasCommandFlag, openBrowser, urlHostForBindHost, withRuntimeServices, yesNo } from './management.ts';
|
|
13
14
|
import { GOODVIBES_AGENT_PAIRING_SURFACE } from '../config/surface.ts';
|
|
15
|
+
import { connectedHostTokenRequiredMessage, readConnectedHostOperatorToken } from '../runtime/connected-host-auth.ts';
|
|
16
|
+
import { formatAgentRecordSource } from '../agent/record-labels.ts';
|
|
17
|
+
|
|
18
|
+
function resolveManualSubscriptionConfig(config: OAuthProviderConfig): OAuthProviderConfig {
|
|
19
|
+
return config.manualRedirectUri
|
|
20
|
+
? { ...config, redirectUri: config.manualRedirectUri }
|
|
21
|
+
: config;
|
|
22
|
+
}
|
|
14
23
|
|
|
15
24
|
export async function renderSubscriptions(runtime: CliCommandRuntime): Promise<string> {
|
|
16
25
|
return await withRuntimeServices(runtime, async (services) => {
|
|
@@ -22,7 +31,7 @@ export async function renderSubscriptions(runtime: CliCommandRuntime): Promise<s
|
|
|
22
31
|
if (sub === 'providers') {
|
|
23
32
|
return formatJsonOrText(runtime.cli)(available, [
|
|
24
33
|
'GoodVibes subscription providers',
|
|
25
|
-
...available.map((provider) => ` ${provider.provider}
|
|
34
|
+
...available.map((provider) => ` ${provider.provider} origin ${provider.source} redirect ${provider.oauth.redirectUri}`),
|
|
26
35
|
].join('\n'));
|
|
27
36
|
}
|
|
28
37
|
if (sub === 'inspect' || sub === 'show') {
|
|
@@ -40,21 +49,21 @@ export async function renderSubscriptions(runtime: CliCommandRuntime): Promise<s
|
|
|
40
49
|
const stored = services.subscriptionManager.get(provider);
|
|
41
50
|
return formatJsonOrText(runtime.cli)({ provider, resolved, inspection, stored }, [
|
|
42
51
|
`GoodVibes subscription ${provider}`,
|
|
43
|
-
` configured
|
|
44
|
-
` freshness
|
|
45
|
-
|
|
52
|
+
` configured ${yesNo(inspection.configured)}`,
|
|
53
|
+
` freshness ${inspection.freshness}`,
|
|
54
|
+
' finish mode explicit manual',
|
|
46
55
|
...(resolved ? [
|
|
47
|
-
`
|
|
48
|
-
`
|
|
56
|
+
` origin ${formatAgentRecordSource(resolved.source)}`,
|
|
57
|
+
` redirect URI ${resolved.oauth.redirectUri}`,
|
|
49
58
|
] : []),
|
|
50
59
|
...(stored ? [
|
|
51
|
-
`
|
|
52
|
-
`
|
|
53
|
-
`
|
|
54
|
-
`
|
|
55
|
-
] : [' stored
|
|
56
|
-
...inspection.issues.map((issue) => ` issue
|
|
57
|
-
...inspection.nextActions.map((action) => ` next
|
|
60
|
+
` token type ${stored.tokenType}`,
|
|
61
|
+
` expires ${stored.expiresAt ? new Date(stored.expiresAt).toISOString() : 'n/a'}`,
|
|
62
|
+
` refresh token ${stored.refreshToken ? 'present' : 'absent'}`,
|
|
63
|
+
` override ambient ${yesNo(stored.overrideAmbientApiKeys)}`,
|
|
64
|
+
] : [' stored no']),
|
|
65
|
+
...inspection.issues.map((issue) => ` issue ${issue}`),
|
|
66
|
+
...inspection.nextActions.map((action) => ` next ${action}`),
|
|
58
67
|
].join('\n'));
|
|
59
68
|
}
|
|
60
69
|
if (sub === 'login' || sub === 'start') {
|
|
@@ -62,7 +71,7 @@ export async function renderSubscriptions(runtime: CliCommandRuntime): Promise<s
|
|
|
62
71
|
const mode = sub === 'start' ? 'start' : rest[1]?.toLowerCase();
|
|
63
72
|
if (!provider || mode !== 'start') return `Usage: ${binary} subscription login <provider> start [--open]`;
|
|
64
73
|
const resolved = getSubscriptionProviderConfig(provider, services.serviceRegistry.get(provider));
|
|
65
|
-
if (!resolved) return `No subscription provider found
|
|
74
|
+
if (!resolved) return `No subscription provider found ${provider}`;
|
|
66
75
|
if (provider === 'openai' && resolved.source === 'builtin') {
|
|
67
76
|
const started = await beginOpenAICodexLogin();
|
|
68
77
|
services.subscriptionManager.savePending({
|
|
@@ -74,26 +83,29 @@ export async function renderSubscriptions(runtime: CliCommandRuntime): Promise<s
|
|
|
74
83
|
});
|
|
75
84
|
const openResult = runtime.cli.flags.open || hasCommandFlag(rest, '--open') ? openBrowser(started.authorizationUrl) : null;
|
|
76
85
|
return [
|
|
77
|
-
`Subscription OAuth started
|
|
78
|
-
`
|
|
79
|
-
` state
|
|
80
|
-
`
|
|
81
|
-
...(openResult ? [` open
|
|
82
|
-
|
|
83
|
-
|
|
86
|
+
`Subscription OAuth started ${provider}`,
|
|
87
|
+
` origin ${formatAgentRecordSource(resolved.source)}`,
|
|
88
|
+
` state ${started.state}`,
|
|
89
|
+
` redirect URI ${started.redirectUri}`,
|
|
90
|
+
...(openResult ? [` open ${openResult}`] : []),
|
|
91
|
+
' completion paste the callback code or redirect URL into the finish command',
|
|
92
|
+
` next ${binary} subscription login ${provider} finish <code-or-url>`,
|
|
93
|
+
' authorization URL',
|
|
84
94
|
` ${started.authorizationUrl}`,
|
|
85
95
|
].join('\n');
|
|
86
96
|
}
|
|
87
|
-
const
|
|
97
|
+
const activeConfig = resolveManualSubscriptionConfig(resolved.oauth);
|
|
98
|
+
const started = await services.subscriptionManager.beginOAuthLogin(provider, activeConfig);
|
|
88
99
|
const openResult = runtime.cli.flags.open || hasCommandFlag(rest, '--open') ? openBrowser(started.authorizationUrl) : null;
|
|
89
100
|
return [
|
|
90
|
-
`Subscription OAuth started
|
|
91
|
-
`
|
|
92
|
-
` state
|
|
93
|
-
`
|
|
94
|
-
...(openResult ? [` open
|
|
95
|
-
|
|
96
|
-
|
|
101
|
+
`Subscription OAuth started ${provider}`,
|
|
102
|
+
` origin ${formatAgentRecordSource(resolved.source)}`,
|
|
103
|
+
` state ${started.pending.state}`,
|
|
104
|
+
` redirect URI ${started.pending.redirectUri}`,
|
|
105
|
+
...(openResult ? [` open ${openResult}`] : []),
|
|
106
|
+
' completion paste the callback code or redirect URL into the finish command',
|
|
107
|
+
` next ${binary} subscription login ${provider} finish <code-or-url>`,
|
|
108
|
+
' authorization URL',
|
|
97
109
|
` ${started.authorizationUrl}`,
|
|
98
110
|
].join('\n');
|
|
99
111
|
}
|
|
@@ -102,7 +114,7 @@ export async function renderSubscriptions(runtime: CliCommandRuntime): Promise<s
|
|
|
102
114
|
const codeInput = sub === 'finish' ? rest[1] : rest[2];
|
|
103
115
|
if (!provider || !codeInput) return `Usage: ${binary} subscription login <provider> finish <code-or-url>`;
|
|
104
116
|
const resolved = getSubscriptionProviderConfig(provider, services.serviceRegistry.get(provider));
|
|
105
|
-
if (!resolved) return `No subscription provider found
|
|
117
|
+
if (!resolved) return `No subscription provider found ${provider}`;
|
|
106
118
|
const code = extractAuthorizationCode(codeInput);
|
|
107
119
|
if (provider === 'openai' && resolved.source === 'builtin') {
|
|
108
120
|
const pendingLogin = services.subscriptionManager.getPending(provider);
|
|
@@ -121,24 +133,36 @@ export async function renderSubscriptions(runtime: CliCommandRuntime): Promise<s
|
|
|
121
133
|
createdAt: services.subscriptionManager.get(provider)?.createdAt ?? now,
|
|
122
134
|
updatedAt: now,
|
|
123
135
|
});
|
|
124
|
-
return
|
|
136
|
+
return [
|
|
137
|
+
`Subscription stored ${provider}`,
|
|
138
|
+
` token type ${record.tokenType}`,
|
|
139
|
+
` expires ${record.expiresAt ? new Date(record.expiresAt).toISOString() : 'n/a'}`,
|
|
140
|
+
].join('\n');
|
|
125
141
|
}
|
|
126
|
-
const
|
|
127
|
-
|
|
142
|
+
const activeConfig = resolveManualSubscriptionConfig(resolved.oauth);
|
|
143
|
+
const record = await services.subscriptionManager.completeOAuthLogin(provider, activeConfig, code);
|
|
144
|
+
return [
|
|
145
|
+
`Subscription stored ${provider}`,
|
|
146
|
+
` token type ${record.tokenType}`,
|
|
147
|
+
` expires ${record.expiresAt ? new Date(record.expiresAt).toISOString() : 'n/a'}`,
|
|
148
|
+
].join('\n');
|
|
128
149
|
}
|
|
129
150
|
if (sub === 'refresh') {
|
|
130
151
|
const provider = rest[0];
|
|
131
152
|
if (!provider) return `Usage: ${binary} subscription refresh <provider>`;
|
|
132
153
|
const resolved = getSubscriptionProviderConfig(provider, services.serviceRegistry.get(provider));
|
|
133
|
-
if (!resolved) return `No subscription provider found
|
|
154
|
+
if (!resolved) return `No subscription provider found ${provider}`;
|
|
134
155
|
const record = await services.subscriptionManager.refreshOAuthToken(provider, resolved.oauth);
|
|
135
|
-
return
|
|
156
|
+
return [
|
|
157
|
+
`Subscription refreshed ${provider}`,
|
|
158
|
+
` expires ${record.expiresAt ? new Date(record.expiresAt).toISOString() : 'n/a'}`,
|
|
159
|
+
].join('\n');
|
|
136
160
|
}
|
|
137
161
|
if (sub === 'logout' || sub === 'remove') {
|
|
138
162
|
const provider = rest[0];
|
|
139
163
|
if (!provider) return `Usage: ${binary} subscription logout <provider>`;
|
|
140
164
|
const removed = services.subscriptionManager.logout(provider);
|
|
141
|
-
return removed ? `Subscription removed
|
|
165
|
+
return removed ? `Subscription removed ${provider}` : `No stored subscription session existed for ${provider}.`;
|
|
142
166
|
}
|
|
143
167
|
if (sub !== 'list' && sub !== 'status' && sub !== 'review') {
|
|
144
168
|
return `Usage: ${binary} subscription [list|providers|inspect <provider>|login <provider> start|finish <code-or-url>|refresh <provider>|logout <provider>]`;
|
|
@@ -154,10 +178,10 @@ export async function renderSubscriptions(runtime: CliCommandRuntime): Promise<s
|
|
|
154
178
|
};
|
|
155
179
|
return formatJsonOrText(runtime.cli)(value, [
|
|
156
180
|
'GoodVibes subscriptions',
|
|
157
|
-
subscriptions.length === 0 ? ' active
|
|
158
|
-
...subscriptions.map((sub) => ` ${sub.provider} token
|
|
159
|
-
pending.length === 0 ? ' pending
|
|
160
|
-
...pending.map((sub) => ` ${sub.provider} created
|
|
181
|
+
subscriptions.length === 0 ? ' active none' : ' active',
|
|
182
|
+
...subscriptions.map((sub) => ` ${sub.provider} token ${sub.tokenType} expires ${sub.expiresAt ? new Date(sub.expiresAt).toISOString() : 'n/a'} override ambient ${yesNo(sub.overrideAmbientApiKeys)}`),
|
|
183
|
+
pending.length === 0 ? ' pending none' : ' pending',
|
|
184
|
+
...pending.map((sub) => ` ${sub.provider} created ${new Date(sub.createdAt).toISOString()}`),
|
|
161
185
|
].join('\n'));
|
|
162
186
|
});
|
|
163
187
|
}
|
|
@@ -185,7 +209,11 @@ export async function handleSecrets(runtime: CliCommandRuntime): Promise<string>
|
|
|
185
209
|
}
|
|
186
210
|
const resolved = await resolveSecretRef(ref, { resolveLocalSecret: (key) => secrets.get(key) });
|
|
187
211
|
const value = { ref: describeSecretRef(ref), resolved: Boolean(resolved.value) };
|
|
188
|
-
return formatJsonOrText(runtime.cli)(value,
|
|
212
|
+
return formatJsonOrText(runtime.cli)(value, [
|
|
213
|
+
'GoodVibes secret test',
|
|
214
|
+
` ref ${value.ref}`,
|
|
215
|
+
` result ${value.resolved ? 'resolved <redacted>' : 'missing'}`,
|
|
216
|
+
].join('\n'));
|
|
189
217
|
}
|
|
190
218
|
if (sub === 'set' || sub === 'link') {
|
|
191
219
|
const flags = new Set(rest.filter((arg) => arg.startsWith('--')));
|
|
@@ -200,7 +228,10 @@ export async function handleSecrets(runtime: CliCommandRuntime): Promise<string>
|
|
|
200
228
|
scope: flags.has('--user') ? 'user' : 'project',
|
|
201
229
|
medium: flags.has('--plaintext') ? 'plaintext' : 'secure',
|
|
202
230
|
});
|
|
203
|
-
return
|
|
231
|
+
return [
|
|
232
|
+
`Secret ${sub === 'link' ? 'linked' : 'stored'}`,
|
|
233
|
+
` key ${key}`,
|
|
234
|
+
].join('\n');
|
|
204
235
|
}
|
|
205
236
|
if (sub === 'delete') {
|
|
206
237
|
const key = rest.find((arg) => !arg.startsWith('--'));
|
|
@@ -210,18 +241,21 @@ export async function handleSecrets(runtime: CliCommandRuntime): Promise<string>
|
|
|
210
241
|
scope: flags.has('--user') ? 'user' : flags.has('--project') ? 'project' : undefined,
|
|
211
242
|
medium: flags.has('--secure') ? 'secure' : flags.has('--plaintext') ? 'plaintext' : undefined,
|
|
212
243
|
});
|
|
213
|
-
return
|
|
244
|
+
return [
|
|
245
|
+
'Secret deleted',
|
|
246
|
+
` key ${key}`,
|
|
247
|
+
].join('\n');
|
|
214
248
|
}
|
|
215
249
|
const [records, review] = await Promise.all([secrets.listDetailed(), secrets.inspect()]);
|
|
216
250
|
const stored = records.filter((record) => record.source !== 'env');
|
|
217
251
|
const value = { policy: review.policy, records: stored, warnings: review.warnings };
|
|
218
252
|
return formatJsonOrText(runtime.cli)(value, [
|
|
219
253
|
'GoodVibes secrets',
|
|
220
|
-
` policy
|
|
221
|
-
` secure available
|
|
222
|
-
` stored keys
|
|
254
|
+
` policy ${review.policy}`,
|
|
255
|
+
` secure available ${yesNo(review.secureAvailable)}`,
|
|
256
|
+
` stored keys ${stored.length}`,
|
|
223
257
|
...stored.map((record) => ` ${record.key} (${record.source}${record.refSource ? `, ref:${record.refSource}` : ''}${record.overriddenByEnv ? ', env override' : ''})`),
|
|
224
|
-
...review.warnings.map((warning) => ` warning
|
|
258
|
+
...review.warnings.map((warning) => ` warning ${warning}`),
|
|
225
259
|
].join('\n'));
|
|
226
260
|
}
|
|
227
261
|
|
|
@@ -234,21 +268,21 @@ export async function handleSessions(runtime: CliCommandRuntime): Promise<string
|
|
|
234
268
|
const value = sessions;
|
|
235
269
|
return formatJsonOrText(runtime.cli)(value, [
|
|
236
270
|
`GoodVibes sessions (${sessions.length})`,
|
|
237
|
-
...sessions.slice(0, 50).map((session) => ` ${session.name} messages
|
|
271
|
+
...sessions.slice(0, 50).map((session) => ` ${session.name} messages ${session.messageCount} ${new Date(session.timestamp).toISOString()} ${session.title || '(untitled)'}`),
|
|
238
272
|
].join('\n'));
|
|
239
273
|
}
|
|
240
274
|
if (sub === 'show' || sub === 'info') {
|
|
241
275
|
const target = rest.join(' ').trim();
|
|
242
276
|
if (!target) return `Usage: ${binary} sessions show <id|name>`;
|
|
243
277
|
const found = sessions.find((session) => session.name === target || session.name.startsWith(target) || session.title.toLowerCase() === target.toLowerCase());
|
|
244
|
-
if (!found) return `Session not found
|
|
278
|
+
if (!found) return `Session not found ${target}`;
|
|
245
279
|
return formatJsonOrText(runtime.cli)(found, [
|
|
246
280
|
`Session ${found.name}`,
|
|
247
|
-
` title
|
|
248
|
-
` messages
|
|
249
|
-
` provider/model
|
|
250
|
-
` updated
|
|
251
|
-
` file
|
|
281
|
+
` title ${found.title || '(untitled)'}`,
|
|
282
|
+
` messages ${found.messageCount}`,
|
|
283
|
+
` provider/model ${found.provider}/${found.model}`,
|
|
284
|
+
` updated ${new Date(found.timestamp).toISOString()}`,
|
|
285
|
+
` file ${found.filePath}`,
|
|
252
286
|
].join('\n'));
|
|
253
287
|
}
|
|
254
288
|
if (sub === 'export') {
|
|
@@ -256,14 +290,17 @@ export async function handleSessions(runtime: CliCommandRuntime): Promise<string
|
|
|
256
290
|
const outputPath = rest[1];
|
|
257
291
|
if (!target) return `Usage: ${binary} sessions export <id|name> [path]`;
|
|
258
292
|
const found = sessions.find((session) => session.name === target || session.name.startsWith(target) || session.title.toLowerCase() === target.toLowerCase());
|
|
259
|
-
if (!found) return `Session not found
|
|
293
|
+
if (!found) return `Session not found ${target}`;
|
|
260
294
|
const data = services.sessionManager.load(found.name);
|
|
261
295
|
const text = JSON.stringify({ name: found.name, ...data }, null, 2) + '\n';
|
|
262
296
|
if (outputPath) {
|
|
263
297
|
const targetPath = services.shellPaths.resolveWorkspacePath(outputPath);
|
|
264
298
|
mkdirSync(dirname(targetPath), { recursive: true });
|
|
265
299
|
writeFileSync(targetPath, text, 'utf-8');
|
|
266
|
-
return
|
|
300
|
+
return [
|
|
301
|
+
'Session exported',
|
|
302
|
+
` path ${targetPath}`,
|
|
303
|
+
].join('\n');
|
|
267
304
|
}
|
|
268
305
|
return text.trimEnd();
|
|
269
306
|
}
|
|
@@ -279,35 +316,35 @@ export async function handleTasks(runtime: CliCommandRuntime): Promise<string> {
|
|
|
279
316
|
const [sub = 'list', ...rest] = runtime.cli.commandArgs;
|
|
280
317
|
if (sub === 'submit') {
|
|
281
318
|
return [
|
|
282
|
-
'GoodVibes Agent blocks CLI task submission from the
|
|
283
|
-
' policy
|
|
284
|
-
' build/fix/review
|
|
285
|
-
' result
|
|
319
|
+
'GoodVibes Agent blocks CLI task submission from the host-owned task workflow.',
|
|
320
|
+
' policy do normal assistant work in the main Agent conversation or use `goodvibes-agent run <prompt>` for an explicit one-shot run.',
|
|
321
|
+
' build/fix/review use `goodvibes-agent delegate <task>` for explicit GoodVibes TUI handoff.',
|
|
322
|
+
' result no local task was started.',
|
|
286
323
|
].join('\n');
|
|
287
324
|
}
|
|
288
325
|
return await withRuntimeServices(runtime, (services) => {
|
|
289
326
|
const tasks = [...services.runtimeStore.getState().tasks.tasks.values()];
|
|
290
327
|
if (sub === 'list') {
|
|
291
328
|
return tasks.length === 0
|
|
292
|
-
? 'GoodVibes tasks\n No connected-
|
|
329
|
+
? 'GoodVibes tasks\n No connected-host tasks are currently recorded.'
|
|
293
330
|
: ['GoodVibes tasks', ...tasks.map((task) => ` ${task.id} ${task.status} ${task.kind} ${task.title}`)].join('\n');
|
|
294
331
|
}
|
|
295
332
|
if (sub === 'show') {
|
|
296
333
|
if (!rest[0]) return `Usage: ${runtime.cli.binary} tasks show <taskId>`;
|
|
297
334
|
const task = tasks.find((candidate) => candidate.id === rest[0]);
|
|
298
|
-
return task ? JSON.stringify(task, null, 2) : `Unknown task
|
|
335
|
+
return task ? JSON.stringify(task, null, 2) : `Unknown task ${rest[0] ?? ''}`;
|
|
299
336
|
}
|
|
300
337
|
return `Usage: ${runtime.cli.binary} tasks list|show <taskId>`;
|
|
301
338
|
});
|
|
302
339
|
}
|
|
303
340
|
|
|
304
341
|
export async function renderPairing(runtime: CliCommandRuntime): Promise<string> {
|
|
305
|
-
const
|
|
306
|
-
|
|
342
|
+
const tokenRecord = readConnectedHostOperatorToken(runtime.homeDirectory);
|
|
343
|
+
if (!tokenRecord.token) return connectedHostTokenRequiredMessage(tokenRecord.path);
|
|
307
344
|
const binding = resolveRuntimeEndpointBinding(runtime.configManager, 'controlPlane');
|
|
308
|
-
const
|
|
345
|
+
const connectedHostUrl = `http://${urlHostForBindHost(binding.host)}:${binding.port}`;
|
|
309
346
|
const info = buildCompanionConnectionInfo({
|
|
310
|
-
daemonUrl,
|
|
347
|
+
daemonUrl: connectedHostUrl,
|
|
311
348
|
token: tokenRecord.token,
|
|
312
349
|
username: 'admin',
|
|
313
350
|
surface: GOODVIBES_AGENT_PAIRING_SURFACE,
|
package/src/cli/management.ts
CHANGED
|
@@ -13,20 +13,18 @@ import type { RuntimeServices } from '../runtime/services.ts';
|
|
|
13
13
|
import { SecretsManager } from '../config/secrets.ts';
|
|
14
14
|
import { RuntimeEventBus, type TurnEvent } from '@/runtime/index.ts';
|
|
15
15
|
import { createShellPathService } from '@/runtime/index.ts';
|
|
16
|
+
import { buildPersistedSessionContext } from '@/runtime/index.ts';
|
|
17
|
+
import type { SessionSnapshot } from '@/runtime/index.ts';
|
|
18
|
+
import { conversationMessagesAsSessionRecords } from '../core/conversation-message-snapshot.ts';
|
|
16
19
|
import { summarizeError } from '@pellux/goodvibes-sdk/platform/utils';
|
|
17
20
|
import { listProviderRuntimeSnapshots } from '@pellux/goodvibes-sdk/platform/providers';
|
|
18
21
|
import { BUILTIN_SECRET_PROVIDER_SOURCES, describeSecretRef, isSecretRefInput, resolveSecretRef } from '@pellux/goodvibes-sdk/platform/config';
|
|
19
22
|
import { getSubscriptionProviderConfig, listAvailableSubscriptionProviders } from '@pellux/goodvibes-sdk/platform/config';
|
|
20
23
|
import { beginOpenAICodexLogin, exchangeOpenAICodexCode } from '@pellux/goodvibes-sdk/platform/config';
|
|
21
24
|
import { inspectProviderAuth } from '@/runtime/index.ts';
|
|
22
|
-
import { getOrCreateCompanionToken, buildCompanionConnectionInfo, encodeConnectionPayload, formatConnectionBlock } from '@pellux/goodvibes-sdk/platform/pairing';
|
|
23
|
-
import { generateQrMatrix, renderQrToString } from '@pellux/goodvibes-sdk/platform/pairing';
|
|
24
25
|
import type { GoodVibesCliParseResult } from './types.ts';
|
|
25
26
|
import { formatProviderAuthRoute, summarizeProviderAuthRoutes } from './provider-auth-routes.ts';
|
|
26
27
|
import { classifyProviderSetup } from './provider-classification.ts';
|
|
27
|
-
import { resolveRuntimeEndpointBinding } from './endpoints.ts';
|
|
28
|
-
import { applyRuntimeEndpointFlagOverrides } from './config-overrides.ts';
|
|
29
|
-
import type { RuntimeEndpointId } from './endpoints.ts';
|
|
30
28
|
import { handleBundleCommand } from './bundle-command.ts';
|
|
31
29
|
import { handleSecrets, handleSessions, handleTasks, renderPairing, renderSubscriptions } from './management-commands.ts';
|
|
32
30
|
import { handleAgentKnowledgeCommand, handleAgentKnowledgeShortcutCommand, handleCompatCommand, handleDelegateCommand } from './agent-knowledge-command.ts';
|
|
@@ -61,8 +59,8 @@ export function formatJsonOrText(cli: GoodVibesCliParseResult): Formatter {
|
|
|
61
59
|
}
|
|
62
60
|
|
|
63
61
|
function exitCodeForText(output: string): number {
|
|
64
|
-
if (output.startsWith('Usage:') || output.startsWith('Invalid ') || output.startsWith('Unsupported
|
|
65
|
-
if (output.startsWith('Session not found
|
|
62
|
+
if (output.startsWith('Usage:') || output.startsWith('Invalid ') || output.startsWith('Unsupported')) return 2;
|
|
63
|
+
if (output.startsWith('Session not found') || output.startsWith('Unknown task') || output.startsWith('Task submit failed ')) return 1;
|
|
66
64
|
if (output.startsWith('No stored ') || output.startsWith('No pending ') || output.startsWith('No model ') || output.startsWith('No provider ') || output.startsWith('No auth ')) return 1;
|
|
67
65
|
if (output.startsWith('Unknown ')) return 1;
|
|
68
66
|
if (output === 'Bundle has no config object to import.') return 1;
|
|
@@ -103,7 +101,7 @@ export function getNestedValue(source: unknown, key: string): unknown {
|
|
|
103
101
|
let cursor = source;
|
|
104
102
|
for (const part of key.split('.')) {
|
|
105
103
|
if (cursor == null || typeof cursor !== 'object') return undefined;
|
|
106
|
-
cursor = (cursor
|
|
104
|
+
cursor = Reflect.get(cursor, part);
|
|
107
105
|
}
|
|
108
106
|
return cursor;
|
|
109
107
|
}
|
|
@@ -132,46 +130,6 @@ export function urlHostForBindHost(host: string): string {
|
|
|
132
130
|
return host || '127.0.0.1';
|
|
133
131
|
}
|
|
134
132
|
|
|
135
|
-
export function enableServicePosture(config: ConfigManager): void {
|
|
136
|
-
config.setDynamic('service.enabled', true);
|
|
137
|
-
config.setDynamic('service.autostart', true);
|
|
138
|
-
config.setDynamic('service.restartOnFailure', true);
|
|
139
|
-
}
|
|
140
|
-
|
|
141
|
-
export function enableEndpointLanDefault(config: ConfigManager, endpoint: RuntimeEndpointId): void {
|
|
142
|
-
const binding = resolveRuntimeEndpointBinding(config, endpoint);
|
|
143
|
-
if (binding.hostMode === 'custom') return;
|
|
144
|
-
if (endpoint === 'controlPlane') {
|
|
145
|
-
config.setDynamic('controlPlane.hostMode', 'network');
|
|
146
|
-
config.setDynamic('controlPlane.host', '0.0.0.0');
|
|
147
|
-
config.setDynamic('controlPlane.allowRemote', true);
|
|
148
|
-
return;
|
|
149
|
-
}
|
|
150
|
-
if (endpoint === 'httpListener') {
|
|
151
|
-
config.setDynamic('httpListener.hostMode', 'network');
|
|
152
|
-
config.setDynamic('httpListener.host', '0.0.0.0');
|
|
153
|
-
return;
|
|
154
|
-
}
|
|
155
|
-
config.setDynamic('web.hostMode', 'network');
|
|
156
|
-
config.setDynamic('web.host', '0.0.0.0');
|
|
157
|
-
}
|
|
158
|
-
|
|
159
|
-
export function applyTargetEndpointFlagsOrDefault(
|
|
160
|
-
runtime: CliCommandRuntime,
|
|
161
|
-
endpoint: RuntimeEndpointId,
|
|
162
|
-
): string | null {
|
|
163
|
-
const errors = applyRuntimeEndpointFlagOverrides(runtime.configManager, endpoint, runtime.cli.flags);
|
|
164
|
-
if (errors.length > 0) return errors.join('\n');
|
|
165
|
-
if (runtime.cli.flags.hostname === undefined) {
|
|
166
|
-
enableEndpointLanDefault(runtime.configManager, endpoint);
|
|
167
|
-
}
|
|
168
|
-
if (endpoint === 'controlPlane') {
|
|
169
|
-
const binding = resolveRuntimeEndpointBinding(runtime.configManager, endpoint);
|
|
170
|
-
runtime.configManager.setDynamic('controlPlane.allowRemote', binding.hostMode !== 'local');
|
|
171
|
-
}
|
|
172
|
-
return null;
|
|
173
|
-
}
|
|
174
|
-
|
|
175
133
|
export function openBrowser(url: string): string {
|
|
176
134
|
const platform = process.platform;
|
|
177
135
|
const command = platform === 'darwin' ? 'open' : platform === 'win32' ? 'cmd' : 'xdg-open';
|
|
@@ -323,7 +281,13 @@ export async function runNonInteractiveAgent(runtime: CliCommandRuntime): Promis
|
|
|
323
281
|
}) + '\n');
|
|
324
282
|
}
|
|
325
283
|
} finally {
|
|
326
|
-
const
|
|
284
|
+
const messages = ctx.conversation.getMessageSnapshot();
|
|
285
|
+
const snapshot: SessionSnapshot = {
|
|
286
|
+
messages: conversationMessagesAsSessionRecords(messages),
|
|
287
|
+
timestamp: Date.now(),
|
|
288
|
+
title: ctx.conversation.title,
|
|
289
|
+
...buildPersistedSessionContext(messages, ctx.conversation.getTitleSource()),
|
|
290
|
+
};
|
|
327
291
|
await ctx.shutdown(snapshot);
|
|
328
292
|
}
|
|
329
293
|
return exitCode;
|
|
@@ -371,18 +335,25 @@ async function renderProviders(runtime: CliCommandRuntime): Promise<string> {
|
|
|
371
335
|
} else {
|
|
372
336
|
runtime.configManager.setDynamic('provider.model', formatProviderModel(provider, getModelIdFromProviderModel(runtime.configManager.get('provider.model'))));
|
|
373
337
|
}
|
|
374
|
-
return
|
|
375
|
-
|
|
376
|
-
|
|
338
|
+
return [
|
|
339
|
+
'Provider selected',
|
|
340
|
+
` provider ${provider}`,
|
|
341
|
+
...(requestedModel ? [` model ${requestedModel}`] : []),
|
|
342
|
+
` warning model catalog entry was not available locally; ${requestedModel ? 'saved explicit selection' : 'model selection was left unchanged'}.`,
|
|
343
|
+
].join('\n');
|
|
377
344
|
}
|
|
378
345
|
runtime.configManager.setDynamic('provider.model', selected.registryKey);
|
|
379
|
-
return
|
|
346
|
+
return [
|
|
347
|
+
'Provider selected',
|
|
348
|
+
` provider ${selected.provider}`,
|
|
349
|
+
` model ${selected.registryKey}`,
|
|
350
|
+
].join('\n');
|
|
380
351
|
}
|
|
381
352
|
if (sub === 'inspect' || sub === 'show') {
|
|
382
353
|
const provider = rest[0];
|
|
383
354
|
if (!provider) return `Usage: ${binary} providers inspect <provider>`;
|
|
384
355
|
const snapshot = snapshots.find((candidate) => candidate.providerId === provider);
|
|
385
|
-
if (!snapshot) return `No provider found
|
|
356
|
+
if (!snapshot) return `No provider found ${provider}`;
|
|
386
357
|
const setup = classifyProviderSetup({
|
|
387
358
|
providerId: snapshot.providerId,
|
|
388
359
|
authMode: snapshot.runtime.auth?.mode,
|
|
@@ -428,7 +399,7 @@ async function renderProviders(runtime: CliCommandRuntime): Promise<string> {
|
|
|
428
399
|
return formatJsonOrText(runtime.cli)(value, [
|
|
429
400
|
'GoodVibes providers',
|
|
430
401
|
...value.map((provider) =>
|
|
431
|
-
` ${provider.current ? '*' : ' '} ${provider.provider.padEnd(18)} setup
|
|
402
|
+
` ${provider.current ? '*' : ' '} ${provider.provider.padEnd(18)} setup ${provider.setupClass} configured ${yesNo(provider.configured)} via ${provider.configuredVia ?? 'n/a'} models ${provider.models} routes ${provider.authRouteSummary} ${provider.detail ?? ''}`.trimEnd(),
|
|
432
403
|
),
|
|
433
404
|
].join('\n'));
|
|
434
405
|
});
|
|
@@ -481,18 +452,28 @@ async function renderModels(runtime: CliCommandRuntime): Promise<string> {
|
|
|
481
452
|
const provider = inferProviderFromRegistryKey(modelKey);
|
|
482
453
|
runtime.configManager.setDynamic('provider.model', formatProviderModel(provider, modelKey));
|
|
483
454
|
await services.favoritesStore.recordUsage(modelKey);
|
|
484
|
-
return
|
|
455
|
+
return [
|
|
456
|
+
'Model selected',
|
|
457
|
+
` model ${modelKey}`,
|
|
458
|
+
' warning model catalog entry was not available locally; saved explicit selection.',
|
|
459
|
+
].join('\n');
|
|
485
460
|
}
|
|
486
461
|
runtime.configManager.setDynamic('provider.model', model.registryKey);
|
|
487
462
|
await services.favoritesStore.recordUsage(model.registryKey);
|
|
488
|
-
return
|
|
463
|
+
return [
|
|
464
|
+
'Model selected',
|
|
465
|
+
` model ${model.registryKey}`,
|
|
466
|
+
].join('\n');
|
|
489
467
|
}
|
|
490
468
|
if (subOrFilter === 'pin' || subOrFilter === 'unpin') {
|
|
491
469
|
const modelKey = rest[0];
|
|
492
470
|
if (!modelKey) return `Usage: ${binary} models ${subOrFilter} <registryKey>`;
|
|
493
471
|
if (subOrFilter === 'pin') await services.favoritesStore.pinModel(modelKey);
|
|
494
472
|
else await services.favoritesStore.unpinModel(modelKey);
|
|
495
|
-
return
|
|
473
|
+
return [
|
|
474
|
+
`Model ${subOrFilter === 'pin' ? 'pinned' : 'unpinned'}`,
|
|
475
|
+
` model ${modelKey}`,
|
|
476
|
+
].join('\n');
|
|
496
477
|
}
|
|
497
478
|
if (subOrFilter === 'pinned') {
|
|
498
479
|
const pinned = await services.favoritesStore.getPinned();
|
|
@@ -524,7 +505,7 @@ async function renderModels(runtime: CliCommandRuntime): Promise<string> {
|
|
|
524
505
|
}));
|
|
525
506
|
return formatJsonOrText(runtime.cli)(value, [
|
|
526
507
|
`GoodVibes models${filter ? ` (${filter})` : ''}`,
|
|
527
|
-
...value.map((model) => ` ${model.current ? '*' : ' '} ${model.registryKey.padEnd(42)} setup
|
|
508
|
+
...value.map((model) => ` ${model.current ? '*' : ' '} ${model.registryKey.padEnd(42)} setup ${model.setupClass} context ${model.contextWindow.toLocaleString()} ${model.displayName}`),
|
|
528
509
|
].join('\n'));
|
|
529
510
|
});
|
|
530
511
|
}
|
|
@@ -544,8 +525,8 @@ async function renderAuth(runtime: CliCommandRuntime): Promise<string> {
|
|
|
544
525
|
]);
|
|
545
526
|
if (blocked.has(sub)) {
|
|
546
527
|
return [
|
|
547
|
-
'Unsupported: connected-
|
|
548
|
-
'GoodVibes Agent does not create, delete, rotate, revoke, or clear connected-
|
|
528
|
+
'Unsupported: connected-host auth user/session administration is outside GoodVibes Agent.',
|
|
529
|
+
'GoodVibes Agent does not create, delete, rotate, revoke, or clear connected-host users, sessions, or bootstrap credentials.',
|
|
549
530
|
'Use the owning GoodVibes host for auth administration.',
|
|
550
531
|
].join('\n');
|
|
551
532
|
}
|
|
@@ -566,23 +547,23 @@ async function renderAuth(runtime: CliCommandRuntime): Promise<string> {
|
|
|
566
547
|
if (sub === 'users' || sub === 'sessions') {
|
|
567
548
|
return formatJsonOrText(runtime.cli)(value, [
|
|
568
549
|
`GoodVibes Agent auth ${sub}`,
|
|
569
|
-
' owner
|
|
570
|
-
` operator token
|
|
571
|
-
` operator token path
|
|
572
|
-
` ${sub}
|
|
573
|
-
' Agent does not enumerate or mutate connected-
|
|
550
|
+
' owner connected GoodVibes host',
|
|
551
|
+
` operator token ${paths.operatorTokenPresent ? 'present' : 'missing'}`,
|
|
552
|
+
` operator token path ${paths.operatorTokenPath}`,
|
|
553
|
+
` ${sub} managed outside Agent`,
|
|
554
|
+
' Agent does not enumerate or mutate connected-host users/sessions from the local CLI.',
|
|
574
555
|
].join('\n'));
|
|
575
556
|
}
|
|
576
557
|
return formatJsonOrText(runtime.cli)(value, [
|
|
577
558
|
'GoodVibes Agent auth',
|
|
578
|
-
' owner
|
|
579
|
-
` permission mode
|
|
580
|
-
` operator token
|
|
581
|
-
` compatibility user store
|
|
582
|
-
` compatibility bootstrap credential
|
|
583
|
-
' connected-
|
|
584
|
-
' next
|
|
585
|
-
' next
|
|
559
|
+
' owner connected GoodVibes host',
|
|
560
|
+
` permission mode ${String(value.permissionMode)}`,
|
|
561
|
+
` operator token ${paths.operatorTokenPresent ? 'present' : 'missing'} (${paths.operatorTokenPath})`,
|
|
562
|
+
` compatibility user store ${paths.userStorePresent ? 'present' : 'missing'} (${paths.userStorePath})`,
|
|
563
|
+
` compatibility bootstrap credential ${paths.bootstrapCredentialPresent ? 'present' : 'missing'} (${paths.bootstrapCredentialPath})`,
|
|
564
|
+
' connected-host user/session administration outside Agent',
|
|
565
|
+
' next goodvibes-agent providers',
|
|
566
|
+
' next goodvibes-agent subscription providers',
|
|
586
567
|
].join('\n'));
|
|
587
568
|
}
|
|
588
569
|
|