@pellux/goodvibes-tui 1.16.1 → 1.18.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 +138 -9
- package/README.md +1 -1
- package/docs/foundation-artifacts/operator-contract.json +5490 -1806
- package/package.json +7 -7
- package/src/cli/completions/generate.ts +5 -4
- package/src/cli/config-overrides.ts +51 -11
- package/src/cli/doctor.ts +4 -5
- package/src/cli/entrypoint.ts +13 -8
- package/src/cli/help.ts +7 -6
- package/src/cli/launch-auto-update.ts +214 -0
- package/src/cli/management-commands.ts +82 -15
- package/src/cli/management.ts +0 -2
- package/src/cli/parser.ts +5 -0
- package/src/cli/status.ts +13 -0
- package/src/cli/surface-command.ts +5 -5
- package/src/cli/tui-startup.ts +60 -97
- package/src/cli/types.ts +2 -0
- package/src/config/index.ts +1 -1
- package/src/config/tui-extension-settings.ts +33 -0
- package/src/core/composer-state.ts +1 -1
- package/src/core/consolidation-receipt.ts +41 -0
- package/src/core/conversation-line-cache.ts +3 -3
- package/src/core/conversation-rendering.ts +18 -9
- package/src/core/conversation.ts +2 -2
- package/src/core/long-task-notifier.ts +7 -7
- package/src/core/memory-provenance.ts +67 -0
- package/src/core/pairing-devices.ts +49 -0
- package/src/core/pairing-handoff.ts +101 -0
- package/src/core/pairing-offers.ts +83 -0
- package/src/core/pairing-origin.ts +78 -0
- package/src/core/pairing-tailscale-gateway.ts +56 -0
- package/src/core/power-chip-source.ts +91 -0
- package/src/core/power-status.ts +95 -0
- package/src/core/stable-host.ts +171 -0
- package/src/core/stream-event-wiring.ts +29 -6
- package/src/core/system-message-noise.ts +1 -1
- package/src/core/system-message-router.ts +6 -6
- package/src/core/turn-budget-outcome.ts +60 -0
- package/src/core/turn-cancellation.ts +40 -1
- package/src/core/turn-event-wiring.ts +14 -8
- package/src/daemon/cli.ts +64 -58
- package/src/daemon/lifecycle.ts +41 -0
- package/src/daemon/service-commands.ts +5 -5
- package/src/export/cost-utils.ts +128 -6
- package/src/input/autocomplete.ts +2 -2
- package/src/input/command-registry.ts +55 -9
- package/src/input/commands/acp-runtime.ts +72 -0
- package/src/input/commands/ci-runtime.ts +5 -1
- package/src/input/commands/codebase-runtime.ts +6 -6
- package/src/input/commands/cost-runtime.ts +1 -1
- package/src/input/commands/devices-runtime.ts +109 -0
- package/src/input/commands/git-runtime.ts +28 -4
- package/src/input/commands/graph-runtime.ts +45 -0
- package/src/input/commands/health-runtime.ts +2 -2
- package/src/input/commands/intelligence-runtime.ts +1 -1
- package/src/input/commands/local-auth-runtime.ts +1 -1
- package/src/input/commands/local-provider-runtime.ts +49 -10
- package/src/input/commands/local-runtime.ts +53 -5
- package/src/input/commands/memory.ts +2 -2
- package/src/input/commands/operator-panel-runtime.ts +5 -5
- package/src/input/commands/operator-rpc.ts +32 -11
- package/src/input/commands/permissions-provenance.ts +1 -1
- package/src/input/commands/permissions-runtime.ts +99 -8
- package/src/input/commands/planning-runtime.ts +3 -3
- package/src/input/commands/platform-sandbox-runtime.ts +1 -1
- package/src/input/commands/power-runtime.ts +56 -0
- package/src/input/commands/provider-accounts-runtime.ts +71 -6
- package/src/input/commands/provider.ts +7 -5
- package/src/input/commands/qrcode-runtime.ts +14 -19
- package/src/input/commands/queue-runtime.ts +70 -0
- package/src/input/commands/recall-files-git.ts +13 -51
- package/src/input/commands/recall-files.ts +8 -11
- package/src/input/commands/recall-review.ts +2 -2
- package/src/input/commands/relay-runtime.ts +1 -1
- package/src/input/commands/remote-runtime.ts +1 -1
- package/src/input/commands/runtime-services.ts +4 -4
- package/src/input/commands/schedule-runtime.ts +14 -7
- package/src/input/commands/services-runtime.ts +1 -1
- package/src/input/commands/session-workflow.ts +2 -2
- package/src/input/commands/settings-sync-runtime.ts +2 -2
- package/src/input/commands/share-runtime.ts +1 -1
- package/src/input/commands/shell-core.ts +46 -68
- package/src/input/commands/subscription-runtime.ts +1 -1
- package/src/input/commands/update-runtime.ts +153 -96
- package/src/input/commands/work-plan-runtime.ts +1 -1
- package/src/input/commands/workstream-attempts.ts +6 -1
- package/src/input/commands/workstream-runtime.ts +46 -27
- package/src/input/commands/worktree-runtime.ts +35 -8
- package/src/input/commands.ts +10 -2
- package/src/input/config-modal-types.ts +14 -3
- package/src/input/config-modal.ts +75 -13
- package/src/input/feature-unit-layout.ts +93 -82
- package/src/input/feed-context-factory.ts +2 -2
- package/src/input/handler-command-route.ts +2 -2
- package/src/input/handler-content-actions.ts +1 -1
- package/src/input/handler-feed-routes.ts +7 -7
- package/src/input/handler-feed.ts +4 -4
- package/src/input/handler-interactions.ts +3 -2
- package/src/input/handler-modal-routes.ts +12 -4
- package/src/input/handler-modal-token-routes.ts +1 -1
- package/src/input/handler-onboarding-daemon-adopt.ts +2 -2
- package/src/input/handler-onboarding.ts +3 -2
- package/src/input/handler-picker-routes.ts +26 -13
- package/src/input/handler-shortcuts.ts +29 -6
- package/src/input/handler.ts +2 -2
- package/src/input/keybindings.ts +21 -3
- package/src/input/onboarding/onboarding-feature-units.ts +34 -27
- package/src/input/onboarding/onboarding-provider-key-fields.ts +112 -0
- package/src/input/onboarding/onboarding-wizard-apply.ts +22 -21
- package/src/input/onboarding/onboarding-wizard-external-surfaces.ts +17 -0
- package/src/input/onboarding/onboarding-wizard-network-adopt.ts +2 -2
- package/src/input/onboarding/onboarding-wizard-steps.ts +30 -42
- package/src/input/panel-integration-actions.ts +2 -2
- package/src/input/panel-mouse-geometry.ts +1 -1
- package/src/input/panel-paste-flood-guard.ts +1 -1
- package/src/input/provider-key-intake.ts +167 -0
- package/src/input/sandbox-exec-config.ts +2 -2
- package/src/input/selection-modal.ts +1 -1
- package/src/input/settings-modal-activation.ts +5 -0
- package/src/input/settings-modal-adjustment.ts +4 -31
- package/src/input/settings-modal-data.ts +52 -57
- package/src/input/settings-modal-mutations.ts +12 -68
- package/src/input/settings-modal-types.ts +27 -17
- package/src/input/settings-modal.ts +74 -55
- package/src/main.ts +90 -90
- package/src/panels/agent-inspector-shared.ts +4 -4
- package/src/panels/base-panel.ts +2 -2
- package/src/panels/builtin/agent.ts +4 -4
- package/src/panels/builtin/development.ts +4 -4
- package/src/panels/builtin/knowledge.ts +1 -1
- package/src/panels/builtin/operations.ts +83 -11
- package/src/panels/builtin/session.ts +5 -5
- package/src/panels/builtin/shared.ts +16 -4
- package/src/panels/builtin-modals.ts +59 -42
- package/src/panels/builtin-panels.ts +1 -1
- package/src/panels/cost-tracker-panel.ts +124 -7
- package/src/panels/diff-panel.ts +39 -6
- package/src/panels/eval-registry.ts +2 -2
- package/src/panels/fleet-acts.ts +446 -0
- package/src/panels/fleet-deep-link.ts +1 -1
- package/src/panels/fleet-gateway.ts +117 -0
- package/src/panels/fleet-observed-render.ts +128 -0
- package/src/panels/fleet-panel-format.ts +163 -11
- package/src/panels/fleet-panel-worktree-detail.ts +14 -0
- package/src/panels/fleet-panel.ts +73 -57
- package/src/panels/fleet-read-model.ts +84 -14
- package/src/panels/fleet-spawn.ts +266 -0
- package/src/panels/fleet-steer.ts +2 -2
- package/src/panels/fleet-stop.ts +41 -5
- package/src/panels/fleet-tabs.ts +15 -16
- package/src/panels/fleet-transcript.ts +5 -5
- package/src/panels/git-panel.ts +2 -2
- package/src/panels/index.ts +4 -1
- package/src/panels/local-auth-panel.ts +1 -1
- package/src/panels/memory-consolidation-gateway.ts +94 -0
- package/src/panels/modals/devices-modal.ts +161 -0
- package/src/panels/modals/hooks-modal.ts +1 -1
- package/src/panels/modals/keybindings-modal.ts +2 -2
- package/src/panels/modals/knowledge-modal.ts +1 -1
- package/src/panels/modals/marketplace-modal.ts +4 -4
- package/src/panels/modals/memory-modal.ts +153 -9
- package/src/panels/modals/modal-surface-helpers.ts +1 -1
- package/src/panels/modals/modal-theme.ts +1 -1
- package/src/panels/modals/pairing-modal.ts +198 -68
- package/src/panels/modals/planning-modal.ts +2 -2
- package/src/panels/modals/plugins-modal.ts +1 -1
- package/src/panels/modals/policy-modal.ts +1 -1
- package/src/panels/modals/security-modal.ts +7 -1
- package/src/panels/modals/skills-modal.ts +1 -1
- package/src/panels/modals/work-plan-modal.ts +3 -3
- package/src/panels/notifications-feed.ts +127 -0
- package/src/panels/notifications-panel.ts +160 -0
- package/src/panels/panel-manager.ts +9 -9
- package/src/panels/plugins-panel.ts +4 -4
- package/src/panels/project-planning-answer-actions.ts +1 -1
- package/src/panels/provider-health-routes.ts +2 -2
- package/src/panels/skills-panel.ts +4 -5
- package/src/panels/token-budget-panel.ts +11 -3
- package/src/panels/types.ts +5 -5
- package/src/panels/workstream-graph-render.ts +123 -0
- package/src/permissions/broker-approval-card.ts +201 -0
- package/src/permissions/hunk-selection.ts +28 -4
- package/src/permissions/prompt.ts +244 -29
- package/src/renderer/autocomplete-overlay.ts +107 -54
- package/src/renderer/code-block.ts +2 -2
- package/src/renderer/compaction-history-modal.ts +1 -1
- package/src/renderer/compaction-preview.ts +1 -1
- package/src/renderer/compaction-quality.ts +1 -1
- package/src/renderer/composer-fragments.ts +69 -0
- package/src/renderer/compositor.ts +2 -2
- package/src/renderer/config-modal.ts +1 -1
- package/src/renderer/conversation-overlays.ts +1 -1
- package/src/renderer/footer-tips.ts +3 -3
- package/src/renderer/hint-grammar.ts +1 -1
- package/src/renderer/modal-factory.ts +1 -1
- package/src/renderer/model-picker-overlay.ts +1 -1
- package/src/renderer/model-workspace.ts +7 -2
- package/src/renderer/panel-composite.ts +2 -2
- package/src/renderer/panel-workspace-bar.ts +1 -1
- package/src/renderer/process-indicator.ts +1 -1
- package/src/renderer/selection-modal-overlay.ts +1 -1
- package/src/renderer/session-picker-modal.ts +2 -2
- package/src/renderer/settings-modal-helpers.ts +23 -5
- package/src/renderer/settings-modal.ts +129 -39
- package/src/renderer/shell-surface.ts +6 -0
- package/src/renderer/terminal-bg-probe.ts +1 -1
- package/src/renderer/theme.ts +3 -3
- package/src/renderer/tool-call.ts +13 -7
- package/src/renderer/tool-result-summary.ts +1 -1
- package/src/renderer/turn-injection.ts +7 -6
- package/src/renderer/ui-factory.ts +38 -1
- package/src/runtime/bootstrap-command-context.ts +7 -2
- package/src/runtime/bootstrap-command-parts.ts +9 -5
- package/src/runtime/bootstrap-core.ts +41 -41
- package/src/runtime/bootstrap-hook-bridge.ts +1 -1
- package/src/runtime/bootstrap-shell.ts +13 -5
- package/src/runtime/bootstrap.ts +34 -32
- package/src/runtime/channel-composition.ts +46 -0
- package/src/runtime/code-index-services.ts +3 -4
- package/src/runtime/daemon-attach-notices.ts +120 -0
- package/src/runtime/durability-services.ts +90 -0
- package/src/runtime/embedded-service-factories.ts +40 -0
- package/src/runtime/feature-settings.ts +147 -0
- package/src/runtime/fleet-services.ts +41 -0
- package/src/runtime/idle-power-services.ts +85 -0
- package/src/runtime/index.ts +6 -21
- package/src/runtime/interaction-seams.ts +109 -0
- package/src/runtime/legacy-daemon-migration.ts +29 -19
- package/src/runtime/memory-fold.ts +1 -1
- package/src/runtime/notification-dispatch.ts +110 -0
- package/src/runtime/onboarding/apply.ts +3 -29
- package/src/runtime/onboarding/fast-path.ts +39 -6
- package/src/runtime/onboarding/provider-key-capture.ts +126 -0
- package/src/runtime/onboarding/snapshot.ts +0 -1
- package/src/runtime/onboarding/types.ts +9 -3
- package/src/runtime/power-keepawake-remote.ts +75 -0
- package/src/runtime/process-lifecycle.ts +3 -1
- package/src/runtime/provider-fallback.ts +55 -0
- package/src/runtime/provider-optimizer-wiring.ts +55 -0
- package/src/runtime/release-artifacts.ts +19 -103
- package/src/runtime/resume-notice.ts +1 -1
- package/src/runtime/services.ts +113 -113
- package/src/runtime/session-continuity-hints.ts +38 -0
- package/src/runtime/surface-feature-flags.ts +40 -9
- package/src/runtime/terminal-output-guard.ts +2 -2
- package/src/runtime/trust/workspace-registration.ts +10 -2
- package/src/runtime/trust/workspace-trust.ts +58 -31
- package/src/runtime/ui-services.ts +6 -1
- package/src/runtime/update-check.ts +15 -69
- package/src/runtime/workstream-services.ts +2 -2
- package/src/shell/blocking-input.ts +108 -132
- package/src/shell/recovery-input-helpers.ts +53 -166
- package/src/shell/ui-openers.ts +38 -6
- package/src/utils/format-duration.ts +1 -1
- package/src/verification/verification-ledger.ts +21 -4
- package/src/version.ts +1 -1
- package/src/input/commands/flags-runtime.ts +0 -328
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import type { ConfigManager, ConfigKey, GoodVibesConfig } from '../../config/index.ts';
|
|
2
2
|
import type { SecretsManager, SecretRecord, SecretStorageReview } from '../../config/secrets.ts';
|
|
3
|
-
import type { FeatureFlagConfigKey } from '../surface-feature-flags.ts';
|
|
4
3
|
import type { LocalAuthSnapshot, UserAuthManager } from '@pellux/goodvibes-sdk/platform/security';
|
|
5
4
|
import type { ShellPathService } from '@/runtime/index.ts';
|
|
6
5
|
import type {
|
|
@@ -46,7 +45,6 @@ export interface OnboardingConfigSnapshot {
|
|
|
46
45
|
readonly network: GoodVibesConfig['network'];
|
|
47
46
|
readonly surfaces: GoodVibesConfig['surfaces'];
|
|
48
47
|
readonly service: GoodVibesConfig['service'];
|
|
49
|
-
readonly featureFlags: GoodVibesConfig['featureFlags'];
|
|
50
48
|
readonly batch: GoodVibesConfig['batch'];
|
|
51
49
|
readonly cloudflare: GoodVibesConfig['cloudflare'];
|
|
52
50
|
}
|
|
@@ -157,6 +155,14 @@ export interface OnboardingProviderAccountRecord {
|
|
|
157
155
|
readonly availableRoutes: readonly string[];
|
|
158
156
|
readonly activeRoute: string;
|
|
159
157
|
readonly authFreshness: string;
|
|
158
|
+
/**
|
|
159
|
+
* The secrets-store key this provider reads its API key from — its declared
|
|
160
|
+
* auth env var, read from the live provider's registration-time auth state.
|
|
161
|
+
* Present only for providers that accept an API key; absent for keyless /
|
|
162
|
+
* subscription-only providers. Used to offer provider-agnostic key entry in
|
|
163
|
+
* onboarding, and as the storage key when the entered value is saved.
|
|
164
|
+
*/
|
|
165
|
+
readonly apiKeyEnvVar?: string;
|
|
160
166
|
}
|
|
161
167
|
|
|
162
168
|
export interface OnboardingProviderAccountsSnapshot {
|
|
@@ -267,7 +273,7 @@ export interface OnboardingStepDerivationState {
|
|
|
267
273
|
export type OnboardingApplyOperation =
|
|
268
274
|
| {
|
|
269
275
|
readonly kind: 'set-config';
|
|
270
|
-
readonly key: ConfigKey
|
|
276
|
+
readonly key: ConfigKey;
|
|
271
277
|
readonly value: unknown;
|
|
272
278
|
readonly scope?: 'global' | 'project';
|
|
273
279
|
}
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
// ---------------------------------------------------------------------------
|
|
2
|
+
// power-keepawake-remote.ts — forward the keep-awake toggle to an adopted
|
|
3
|
+
// EXTERNAL daemon over the power.keepAwake.set operator verb.
|
|
4
|
+
//
|
|
5
|
+
// In the external/adopted-daemon topology the in-process PowerManager is NOT
|
|
6
|
+
// the daemon's, so a keep-awake toggle applied only locally dies when the TUI
|
|
7
|
+
// closes. The owner ruling is that keep-awake is daemon-held: it must survive
|
|
8
|
+
// the TUI closing. The config file does NOT carry it across (power.keepAwake is
|
|
9
|
+
// not a cross-surface shared key), so the toggle is forwarded to the daemon
|
|
10
|
+
// over the verb instead — best-effort, gated on reachability. Mirrors the
|
|
11
|
+
// agent's own power-keep-awake-remote seam.
|
|
12
|
+
//
|
|
13
|
+
// A single config subscriber carries ALL THREE toggle paths (/power, Alt+A, the
|
|
14
|
+
// settings modal): each lands on the power.keepAwake config key — the local
|
|
15
|
+
// PowerManager persists it on set, and the settings modal writes it directly —
|
|
16
|
+
// so subscribing to that one key catches every origin. In the EMBEDDED topology
|
|
17
|
+
// this is a no-op: the in-process manager already IS the daemon.
|
|
18
|
+
// ---------------------------------------------------------------------------
|
|
19
|
+
|
|
20
|
+
import type { ConfigManager } from '@pellux/goodvibes-sdk/platform/config';
|
|
21
|
+
import type { PowerState } from '@pellux/goodvibes-sdk/platform/power';
|
|
22
|
+
import { resolveOperatorRpc } from '../input/commands/operator-rpc.ts';
|
|
23
|
+
|
|
24
|
+
export interface KeepAwakeRemoteDeps {
|
|
25
|
+
readonly configManager: ConfigManager;
|
|
26
|
+
readonly homeDirectory: string | (() => string);
|
|
27
|
+
/** True only in the external/adopted-daemon topology (the local manager is not the daemon's). */
|
|
28
|
+
readonly isExternalDaemon: () => boolean;
|
|
29
|
+
/** Injectable rpc resolution (tests); defaults to the shared resolveOperatorRpc. */
|
|
30
|
+
readonly resolveRpc?: typeof resolveOperatorRpc;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Best-effort forward of the keep-awake toggle to the adopted external daemon so
|
|
35
|
+
* the DAEMON holds the inhibitor (surviving the TUI closing). A no-op in the
|
|
36
|
+
* embedded topology and quiet when the daemon is unreachable — a transient
|
|
37
|
+
* daemon hiccup never breaks the local toggle.
|
|
38
|
+
*/
|
|
39
|
+
export async function forwardKeepAwakeToDaemon(enabled: boolean, deps: KeepAwakeRemoteDeps): Promise<void> {
|
|
40
|
+
if (!deps.isExternalDaemon()) return;
|
|
41
|
+
const rpc = (deps.resolveRpc ?? resolveOperatorRpc)({ configManager: deps.configManager, homeDirectory: deps.homeDirectory });
|
|
42
|
+
if (!rpc.available) return;
|
|
43
|
+
try {
|
|
44
|
+
await rpc.sdk.operator.invoke('power.keepAwake.set', { enabled });
|
|
45
|
+
} catch {
|
|
46
|
+
// Best-effort by design; the local toggle already applied.
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* Install a config subscriber that forwards every power.keepAwake change to the
|
|
52
|
+
* adopted external daemon. Returns an unsubscribe handle. Because all three
|
|
53
|
+
* toggle origins land on the same config key, this one seam carries them all.
|
|
54
|
+
*/
|
|
55
|
+
export function installKeepAwakeRemoteForward(deps: KeepAwakeRemoteDeps): () => void {
|
|
56
|
+
return deps.configManager.subscribe('power.keepAwake', (newValue) => {
|
|
57
|
+
void forwardKeepAwakeToDaemon(newValue === true, deps);
|
|
58
|
+
});
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* Fetch the adopted DAEMON's power.status.get (null when unreachable or not in
|
|
63
|
+
* the external topology). The chip's external-mode poll source — the adopted
|
|
64
|
+
* wire is plain HTTP with no event bridge, so the chip syncs by polling.
|
|
65
|
+
*/
|
|
66
|
+
export async function fetchDaemonPowerState(deps: KeepAwakeRemoteDeps): Promise<PowerState | null> {
|
|
67
|
+
if (!deps.isExternalDaemon()) return null;
|
|
68
|
+
const rpc = (deps.resolveRpc ?? resolveOperatorRpc)({ configManager: deps.configManager, homeDirectory: deps.homeDirectory });
|
|
69
|
+
if (!rpc.available) return null;
|
|
70
|
+
try {
|
|
71
|
+
return await rpc.sdk.operator.invoke('power.status.get', {}) as unknown as PowerState;
|
|
72
|
+
} catch {
|
|
73
|
+
return null;
|
|
74
|
+
}
|
|
75
|
+
}
|
|
@@ -219,8 +219,10 @@ export function installProcessLifecycle(deps: ProcessLifecycleDeps): ProcessLife
|
|
|
219
219
|
}
|
|
220
220
|
// Only remove the recovery fallback once the durable shutdown save actually completed,
|
|
221
221
|
// so an interrupted or timed-out shutdown leaves the snapshot for the next launch.
|
|
222
|
+
// Scoped to THIS session's id: without it, one session's clean exit wipes
|
|
223
|
+
// every session's crash snapshot (the concurrent-session isolation bug).
|
|
222
224
|
if (shutdownOk) {
|
|
223
|
-
deleteRecoveryFile({ homeDirectory: ctx.services.homeDirectory });
|
|
225
|
+
deleteRecoveryFile({ homeDirectory: ctx.services.homeDirectory }, ctx.runtime.sessionId);
|
|
224
226
|
}
|
|
225
227
|
process.exit(0);
|
|
226
228
|
};
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* provider-fallback.ts — the pre-catalog fallback registration for the
|
|
3
|
+
* configured model, extracted verbatim from services.ts (file-size hygiene):
|
|
4
|
+
* before the model catalog cache has loaded, the configured provider:model is
|
|
5
|
+
* registered with SDK family-aware context-window inference so the meter and
|
|
6
|
+
* compaction denominator agree with the post-catalog window.
|
|
7
|
+
*/
|
|
8
|
+
import type { ConfigManager } from '@pellux/goodvibes-sdk/platform/config';
|
|
9
|
+
import { inferFallbackContextWindow, type ModelDefinition, type ProviderRegistry } from '@pellux/goodvibes-sdk/platform/providers';
|
|
10
|
+
|
|
11
|
+
function buildFallbackModelDefinition(provider: string, modelId: string): ModelDefinition {
|
|
12
|
+
const providerLower = provider.toLowerCase();
|
|
13
|
+
const isReasoningProvider = providerLower.includes('openai')
|
|
14
|
+
|| providerLower.includes('anthropic')
|
|
15
|
+
|| providerLower.includes('gemini')
|
|
16
|
+
|| providerLower.includes('google');
|
|
17
|
+
|
|
18
|
+
return {
|
|
19
|
+
id: modelId,
|
|
20
|
+
provider,
|
|
21
|
+
registryKey: `${provider}:${modelId}`,
|
|
22
|
+
displayName: modelId,
|
|
23
|
+
description: 'Configured model available before the model catalog cache has loaded.',
|
|
24
|
+
capabilities: {
|
|
25
|
+
toolCalling: true,
|
|
26
|
+
codeEditing: true,
|
|
27
|
+
reasoning: isReasoningProvider,
|
|
28
|
+
multimodal: isReasoningProvider,
|
|
29
|
+
},
|
|
30
|
+
contextWindow: inferFallbackContextWindow(provider, modelId),
|
|
31
|
+
contextWindowProvenance: 'fallback',
|
|
32
|
+
selectable: true,
|
|
33
|
+
tier: 'standard',
|
|
34
|
+
...(isReasoningProvider ? { reasoningEffort: ['instant', 'low', 'medium', 'high'] } : {}),
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
export function ensureConfiguredModelIsRoutable(providerRegistry: ProviderRegistry, configManager: ConfigManager): void {
|
|
39
|
+
const configuredModel = String(configManager.get('provider.model') ?? '').trim();
|
|
40
|
+
if (!configuredModel.includes(':')) return;
|
|
41
|
+
if (providerRegistry.listModels().some((model) => model.registryKey === configuredModel)) return;
|
|
42
|
+
|
|
43
|
+
const [providerId, ...modelParts] = configuredModel.split(':');
|
|
44
|
+
const modelId = modelParts.join(':').trim();
|
|
45
|
+
if (!providerId || !modelId) return;
|
|
46
|
+
|
|
47
|
+
const provider = providerRegistry.tryGet(providerId);
|
|
48
|
+
if (!provider) return;
|
|
49
|
+
|
|
50
|
+
providerRegistry.registerRuntimeProvider({
|
|
51
|
+
provider,
|
|
52
|
+
replace: true,
|
|
53
|
+
models: [buildFallbackModelDefinition(providerId, modelId)],
|
|
54
|
+
});
|
|
55
|
+
}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* provider-optimizer-wiring — bind the provider optimizer to its capability
|
|
3
|
+
* gate and seed its persisted routing mode at startup.
|
|
4
|
+
*
|
|
5
|
+
* Mirrors the SDK composition root's provider-optimizer-wiring module (which
|
|
6
|
+
* the SDK does not export through a public seam) so this repo's composition
|
|
7
|
+
* fork cannot drift from it silently: the optimizer is constructed dark, the
|
|
8
|
+
* gate subscription flips it live, and provider.optimizerMode seeds the mode.
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
import type { ConfigManager } from '@pellux/goodvibes-sdk/platform/config';
|
|
12
|
+
import type { ProviderOptimizer } from '@pellux/goodvibes-sdk/platform/providers';
|
|
13
|
+
import type { FeatureFlagManager } from '@/runtime/index.ts';
|
|
14
|
+
|
|
15
|
+
export function bindProviderOptimizerFeatureFlag(
|
|
16
|
+
featureFlags: Pick<FeatureFlagManager, 'isEnabled' | 'subscribe'>,
|
|
17
|
+
providerOptimizer: Pick<ProviderOptimizer, 'setEnabled'>,
|
|
18
|
+
): () => void {
|
|
19
|
+
providerOptimizer.setEnabled(featureFlags.isEnabled('provider-optimizer'));
|
|
20
|
+
return featureFlags.subscribe((flagId, state) => {
|
|
21
|
+
if (flagId === 'provider-optimizer') {
|
|
22
|
+
providerOptimizer.setEnabled(state === 'enabled');
|
|
23
|
+
}
|
|
24
|
+
});
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Apply the persistent provider-optimizer routing mode from config at startup.
|
|
29
|
+
* provider.optimizerMode 'off' keeps the optimizer inactive (its gate derives
|
|
30
|
+
* from the same key); this only seeds the mode/pin so an operator can persist
|
|
31
|
+
* "auto" or a pinned model without re-issuing a /provider command each
|
|
32
|
+
* session. Runtime pin/unpin/setMode still override for the live session.
|
|
33
|
+
*/
|
|
34
|
+
export function applyProviderOptimizerConfigMode(
|
|
35
|
+
configManager: Pick<ConfigManager, 'get'>,
|
|
36
|
+
providerOptimizer: Pick<ProviderOptimizer, 'setMode' | 'pin'>,
|
|
37
|
+
): void {
|
|
38
|
+
const mode = configManager.get('provider.optimizerMode');
|
|
39
|
+
if (mode === 'off') {
|
|
40
|
+
providerOptimizer.setMode('manual'); // inert baseline while inactive
|
|
41
|
+
return;
|
|
42
|
+
}
|
|
43
|
+
if (mode === 'pinned') {
|
|
44
|
+
const pinned = configManager.get('provider.optimizerPinnedModel').trim();
|
|
45
|
+
const sep = pinned.indexOf(':');
|
|
46
|
+
if (sep > 0 && sep < pinned.length - 1) {
|
|
47
|
+
providerOptimizer.pin(pinned.slice(0, sep), pinned.slice(sep + 1));
|
|
48
|
+
} else {
|
|
49
|
+
// Pinned mode requested without a valid provider-qualified model — stay manual.
|
|
50
|
+
providerOptimizer.setMode('manual');
|
|
51
|
+
}
|
|
52
|
+
} else {
|
|
53
|
+
providerOptimizer.setMode(mode);
|
|
54
|
+
}
|
|
55
|
+
}
|
|
@@ -1,109 +1,25 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
3
|
-
*
|
|
4
|
-
*
|
|
5
|
-
* (`goodvibes[-daemon]-{platform}-{arch}`)
|
|
6
|
-
*
|
|
7
|
-
*
|
|
2
|
+
* Release-artifact naming and checksum verification — re-exported from the
|
|
3
|
+
* SDK's canonical update policy module (platform/runtime/self-update), which
|
|
4
|
+
* was hoisted from this file's semantics. One mechanism everywhere: the
|
|
5
|
+
* asset naming convention (`goodvibes[-daemon]-{platform}-{arch}`), the
|
|
6
|
+
* sqlite-vec addon naming, and the "no manifest entry is as fatal as a
|
|
7
|
+
* mismatch" verification rule now have a single owner. Consumers that must
|
|
8
|
+
* stay in lockstep:
|
|
8
9
|
* - scripts/postinstall.js (npm install-time binary download)
|
|
9
|
-
* - src/input/commands/update-runtime.ts (the /update
|
|
10
|
-
*
|
|
11
|
-
* A downloaded artifact with NO entry in the checksum manifest is just as
|
|
12
|
-
* unverified as one with a mismatching entry — verifyChecksum() throws in
|
|
13
|
-
* both cases, never silently skips.
|
|
10
|
+
* - src/input/commands/update-runtime.ts (the /update self-update)
|
|
11
|
+
* - scripts/install.sh (the shell installer; mirrors the same names)
|
|
14
12
|
*/
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
13
|
+
export {
|
|
14
|
+
CHECKSUM_MANIFEST_NAME,
|
|
15
|
+
parseChecksumFile,
|
|
16
|
+
resolveArtifactNames,
|
|
17
|
+
resolveSqliteVecAsset,
|
|
18
|
+
sha256,
|
|
19
|
+
verifyChecksum,
|
|
20
|
+
type ReleaseArtifactNames,
|
|
21
|
+
type SqliteVecAsset,
|
|
22
|
+
} from '@pellux/goodvibes-sdk/platform/runtime/self-update';
|
|
18
23
|
|
|
19
24
|
export type SupportedPlatform = 'linux' | 'darwin';
|
|
20
25
|
export type SupportedArch = 'x64' | 'arm64';
|
|
21
|
-
|
|
22
|
-
export interface ReleaseArtifactNames {
|
|
23
|
-
readonly app: string;
|
|
24
|
-
readonly daemon: string;
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
/** Release-asset platform tag as used in artifact filenames ("linux" | "macos"). */
|
|
28
|
-
const PLATFORM_TAGS: Record<SupportedPlatform, string> = {
|
|
29
|
-
linux: 'linux',
|
|
30
|
-
darwin: 'macos',
|
|
31
|
-
};
|
|
32
|
-
|
|
33
|
-
export function resolveArtifactNames(platform: string, arch: string): ReleaseArtifactNames | null {
|
|
34
|
-
const platformTag = PLATFORM_TAGS[platform as SupportedPlatform];
|
|
35
|
-
if (!platformTag || (arch !== 'x64' && arch !== 'arm64')) {
|
|
36
|
-
return null;
|
|
37
|
-
}
|
|
38
|
-
const suffix = `${platformTag}-${arch}`;
|
|
39
|
-
return {
|
|
40
|
-
app: `goodvibes-${suffix}`,
|
|
41
|
-
daemon: `goodvibes-daemon-${suffix}`,
|
|
42
|
-
};
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
export interface SqliteVecAsset {
|
|
46
|
-
/** Release asset filename, e.g. `sqlite-vec-linux-x64.so`. */
|
|
47
|
-
readonly assetName: string;
|
|
48
|
-
/** Directory name the SDK loader resolves, e.g. `sqlite-vec-linux-x64`. */
|
|
49
|
-
readonly dirName: string;
|
|
50
|
-
/** File the loader opens inside that directory, e.g. `vec0.so`. */
|
|
51
|
-
readonly fileName: string;
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
/**
|
|
55
|
-
* Names the sqlite-vec native addon for a platform/arch. Unlike the binaries
|
|
56
|
-
* (whose release tag maps darwin→"macos"), the addon keeps the Node-style
|
|
57
|
-
* platform tag ("linux" | "darwin") because that is exactly what the SDK's
|
|
58
|
-
* loader resolves at `<execDir>/lib/sqlite-vec-<process.platform>-<process.arch>/vec0.<suffix>`.
|
|
59
|
-
* The scripts/install.sh installer and the release workflow name the asset the
|
|
60
|
-
* same way; all three must stay in lockstep.
|
|
61
|
-
*/
|
|
62
|
-
export function resolveSqliteVecAsset(platform: string, arch: string): SqliteVecAsset | null {
|
|
63
|
-
if ((platform !== 'linux' && platform !== 'darwin') || (arch !== 'x64' && arch !== 'arm64')) {
|
|
64
|
-
return null;
|
|
65
|
-
}
|
|
66
|
-
const suffix = platform === 'darwin' ? 'dylib' : 'so';
|
|
67
|
-
const dirName = `sqlite-vec-${platform}-${arch}`;
|
|
68
|
-
return {
|
|
69
|
-
assetName: `${dirName}.${suffix}`,
|
|
70
|
-
dirName,
|
|
71
|
-
fileName: `vec0.${suffix}`,
|
|
72
|
-
};
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
export function sha256(buffer: Buffer | Uint8Array): string {
|
|
76
|
-
return createHash('sha256').update(buffer).digest('hex');
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
export function parseChecksumFile(contents: string): Map<string, string> {
|
|
80
|
-
const checksums = new Map<string, string>();
|
|
81
|
-
for (const rawLine of contents.split(/\r?\n/)) {
|
|
82
|
-
const line = rawLine.trim();
|
|
83
|
-
if (!line) continue;
|
|
84
|
-
const match = line.match(/^([a-f0-9]{64})\s+\*?(.+)$/i);
|
|
85
|
-
if (!match) continue;
|
|
86
|
-
checksums.set(match[2], match[1].toLowerCase());
|
|
87
|
-
}
|
|
88
|
-
return checksums;
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
/**
|
|
92
|
-
* Verify a downloaded artifact's checksum against the parsed manifest.
|
|
93
|
-
* An artifact with no entry in the manifest is a hard failure, identical
|
|
94
|
-
* in severity to a mismatching entry — never treated as "unverifiable, so
|
|
95
|
-
* skip the check". Throws naming the artifact and the manifest.
|
|
96
|
-
*/
|
|
97
|
-
export function verifyChecksum(
|
|
98
|
-
artifactName: string,
|
|
99
|
-
actual: string,
|
|
100
|
-
expected: string | undefined,
|
|
101
|
-
manifestName: string = CHECKSUM_MANIFEST_NAME,
|
|
102
|
-
): void {
|
|
103
|
-
if (expected === undefined) {
|
|
104
|
-
throw new Error(`no checksum entry for ${artifactName} in ${manifestName} — refusing to install an unverified binary`);
|
|
105
|
-
}
|
|
106
|
-
if (expected !== actual) {
|
|
107
|
-
throw new Error(`checksum mismatch for ${artifactName}: expected ${expected}, got ${actual}`);
|
|
108
|
-
}
|
|
109
|
-
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* resume-notice.ts — the boot-time "previous session found" transcript notice.
|
|
3
3
|
*
|
|
4
|
-
*
|
|
4
|
+
* item 1: a supervision-journey audit of 1.7.0 found that the TUI
|
|
5
5
|
* accumulates rich resumable state on disk (a saved conversation, workspace
|
|
6
6
|
* checkpoints, WRFC chain history) but never surfaces any of it at startup —
|
|
7
7
|
* an operator has no way to know it exists short of already knowing the
|