@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.
Files changed (257) hide show
  1. package/CHANGELOG.md +138 -9
  2. package/README.md +1 -1
  3. package/docs/foundation-artifacts/operator-contract.json +5490 -1806
  4. package/package.json +7 -7
  5. package/src/cli/completions/generate.ts +5 -4
  6. package/src/cli/config-overrides.ts +51 -11
  7. package/src/cli/doctor.ts +4 -5
  8. package/src/cli/entrypoint.ts +13 -8
  9. package/src/cli/help.ts +7 -6
  10. package/src/cli/launch-auto-update.ts +214 -0
  11. package/src/cli/management-commands.ts +82 -15
  12. package/src/cli/management.ts +0 -2
  13. package/src/cli/parser.ts +5 -0
  14. package/src/cli/status.ts +13 -0
  15. package/src/cli/surface-command.ts +5 -5
  16. package/src/cli/tui-startup.ts +60 -97
  17. package/src/cli/types.ts +2 -0
  18. package/src/config/index.ts +1 -1
  19. package/src/config/tui-extension-settings.ts +33 -0
  20. package/src/core/composer-state.ts +1 -1
  21. package/src/core/consolidation-receipt.ts +41 -0
  22. package/src/core/conversation-line-cache.ts +3 -3
  23. package/src/core/conversation-rendering.ts +18 -9
  24. package/src/core/conversation.ts +2 -2
  25. package/src/core/long-task-notifier.ts +7 -7
  26. package/src/core/memory-provenance.ts +67 -0
  27. package/src/core/pairing-devices.ts +49 -0
  28. package/src/core/pairing-handoff.ts +101 -0
  29. package/src/core/pairing-offers.ts +83 -0
  30. package/src/core/pairing-origin.ts +78 -0
  31. package/src/core/pairing-tailscale-gateway.ts +56 -0
  32. package/src/core/power-chip-source.ts +91 -0
  33. package/src/core/power-status.ts +95 -0
  34. package/src/core/stable-host.ts +171 -0
  35. package/src/core/stream-event-wiring.ts +29 -6
  36. package/src/core/system-message-noise.ts +1 -1
  37. package/src/core/system-message-router.ts +6 -6
  38. package/src/core/turn-budget-outcome.ts +60 -0
  39. package/src/core/turn-cancellation.ts +40 -1
  40. package/src/core/turn-event-wiring.ts +14 -8
  41. package/src/daemon/cli.ts +64 -58
  42. package/src/daemon/lifecycle.ts +41 -0
  43. package/src/daemon/service-commands.ts +5 -5
  44. package/src/export/cost-utils.ts +128 -6
  45. package/src/input/autocomplete.ts +2 -2
  46. package/src/input/command-registry.ts +55 -9
  47. package/src/input/commands/acp-runtime.ts +72 -0
  48. package/src/input/commands/ci-runtime.ts +5 -1
  49. package/src/input/commands/codebase-runtime.ts +6 -6
  50. package/src/input/commands/cost-runtime.ts +1 -1
  51. package/src/input/commands/devices-runtime.ts +109 -0
  52. package/src/input/commands/git-runtime.ts +28 -4
  53. package/src/input/commands/graph-runtime.ts +45 -0
  54. package/src/input/commands/health-runtime.ts +2 -2
  55. package/src/input/commands/intelligence-runtime.ts +1 -1
  56. package/src/input/commands/local-auth-runtime.ts +1 -1
  57. package/src/input/commands/local-provider-runtime.ts +49 -10
  58. package/src/input/commands/local-runtime.ts +53 -5
  59. package/src/input/commands/memory.ts +2 -2
  60. package/src/input/commands/operator-panel-runtime.ts +5 -5
  61. package/src/input/commands/operator-rpc.ts +32 -11
  62. package/src/input/commands/permissions-provenance.ts +1 -1
  63. package/src/input/commands/permissions-runtime.ts +99 -8
  64. package/src/input/commands/planning-runtime.ts +3 -3
  65. package/src/input/commands/platform-sandbox-runtime.ts +1 -1
  66. package/src/input/commands/power-runtime.ts +56 -0
  67. package/src/input/commands/provider-accounts-runtime.ts +71 -6
  68. package/src/input/commands/provider.ts +7 -5
  69. package/src/input/commands/qrcode-runtime.ts +14 -19
  70. package/src/input/commands/queue-runtime.ts +70 -0
  71. package/src/input/commands/recall-files-git.ts +13 -51
  72. package/src/input/commands/recall-files.ts +8 -11
  73. package/src/input/commands/recall-review.ts +2 -2
  74. package/src/input/commands/relay-runtime.ts +1 -1
  75. package/src/input/commands/remote-runtime.ts +1 -1
  76. package/src/input/commands/runtime-services.ts +4 -4
  77. package/src/input/commands/schedule-runtime.ts +14 -7
  78. package/src/input/commands/services-runtime.ts +1 -1
  79. package/src/input/commands/session-workflow.ts +2 -2
  80. package/src/input/commands/settings-sync-runtime.ts +2 -2
  81. package/src/input/commands/share-runtime.ts +1 -1
  82. package/src/input/commands/shell-core.ts +46 -68
  83. package/src/input/commands/subscription-runtime.ts +1 -1
  84. package/src/input/commands/update-runtime.ts +153 -96
  85. package/src/input/commands/work-plan-runtime.ts +1 -1
  86. package/src/input/commands/workstream-attempts.ts +6 -1
  87. package/src/input/commands/workstream-runtime.ts +46 -27
  88. package/src/input/commands/worktree-runtime.ts +35 -8
  89. package/src/input/commands.ts +10 -2
  90. package/src/input/config-modal-types.ts +14 -3
  91. package/src/input/config-modal.ts +75 -13
  92. package/src/input/feature-unit-layout.ts +93 -82
  93. package/src/input/feed-context-factory.ts +2 -2
  94. package/src/input/handler-command-route.ts +2 -2
  95. package/src/input/handler-content-actions.ts +1 -1
  96. package/src/input/handler-feed-routes.ts +7 -7
  97. package/src/input/handler-feed.ts +4 -4
  98. package/src/input/handler-interactions.ts +3 -2
  99. package/src/input/handler-modal-routes.ts +12 -4
  100. package/src/input/handler-modal-token-routes.ts +1 -1
  101. package/src/input/handler-onboarding-daemon-adopt.ts +2 -2
  102. package/src/input/handler-onboarding.ts +3 -2
  103. package/src/input/handler-picker-routes.ts +26 -13
  104. package/src/input/handler-shortcuts.ts +29 -6
  105. package/src/input/handler.ts +2 -2
  106. package/src/input/keybindings.ts +21 -3
  107. package/src/input/onboarding/onboarding-feature-units.ts +34 -27
  108. package/src/input/onboarding/onboarding-provider-key-fields.ts +112 -0
  109. package/src/input/onboarding/onboarding-wizard-apply.ts +22 -21
  110. package/src/input/onboarding/onboarding-wizard-external-surfaces.ts +17 -0
  111. package/src/input/onboarding/onboarding-wizard-network-adopt.ts +2 -2
  112. package/src/input/onboarding/onboarding-wizard-steps.ts +30 -42
  113. package/src/input/panel-integration-actions.ts +2 -2
  114. package/src/input/panel-mouse-geometry.ts +1 -1
  115. package/src/input/panel-paste-flood-guard.ts +1 -1
  116. package/src/input/provider-key-intake.ts +167 -0
  117. package/src/input/sandbox-exec-config.ts +2 -2
  118. package/src/input/selection-modal.ts +1 -1
  119. package/src/input/settings-modal-activation.ts +5 -0
  120. package/src/input/settings-modal-adjustment.ts +4 -31
  121. package/src/input/settings-modal-data.ts +52 -57
  122. package/src/input/settings-modal-mutations.ts +12 -68
  123. package/src/input/settings-modal-types.ts +27 -17
  124. package/src/input/settings-modal.ts +74 -55
  125. package/src/main.ts +90 -90
  126. package/src/panels/agent-inspector-shared.ts +4 -4
  127. package/src/panels/base-panel.ts +2 -2
  128. package/src/panels/builtin/agent.ts +4 -4
  129. package/src/panels/builtin/development.ts +4 -4
  130. package/src/panels/builtin/knowledge.ts +1 -1
  131. package/src/panels/builtin/operations.ts +83 -11
  132. package/src/panels/builtin/session.ts +5 -5
  133. package/src/panels/builtin/shared.ts +16 -4
  134. package/src/panels/builtin-modals.ts +59 -42
  135. package/src/panels/builtin-panels.ts +1 -1
  136. package/src/panels/cost-tracker-panel.ts +124 -7
  137. package/src/panels/diff-panel.ts +39 -6
  138. package/src/panels/eval-registry.ts +2 -2
  139. package/src/panels/fleet-acts.ts +446 -0
  140. package/src/panels/fleet-deep-link.ts +1 -1
  141. package/src/panels/fleet-gateway.ts +117 -0
  142. package/src/panels/fleet-observed-render.ts +128 -0
  143. package/src/panels/fleet-panel-format.ts +163 -11
  144. package/src/panels/fleet-panel-worktree-detail.ts +14 -0
  145. package/src/panels/fleet-panel.ts +73 -57
  146. package/src/panels/fleet-read-model.ts +84 -14
  147. package/src/panels/fleet-spawn.ts +266 -0
  148. package/src/panels/fleet-steer.ts +2 -2
  149. package/src/panels/fleet-stop.ts +41 -5
  150. package/src/panels/fleet-tabs.ts +15 -16
  151. package/src/panels/fleet-transcript.ts +5 -5
  152. package/src/panels/git-panel.ts +2 -2
  153. package/src/panels/index.ts +4 -1
  154. package/src/panels/local-auth-panel.ts +1 -1
  155. package/src/panels/memory-consolidation-gateway.ts +94 -0
  156. package/src/panels/modals/devices-modal.ts +161 -0
  157. package/src/panels/modals/hooks-modal.ts +1 -1
  158. package/src/panels/modals/keybindings-modal.ts +2 -2
  159. package/src/panels/modals/knowledge-modal.ts +1 -1
  160. package/src/panels/modals/marketplace-modal.ts +4 -4
  161. package/src/panels/modals/memory-modal.ts +153 -9
  162. package/src/panels/modals/modal-surface-helpers.ts +1 -1
  163. package/src/panels/modals/modal-theme.ts +1 -1
  164. package/src/panels/modals/pairing-modal.ts +198 -68
  165. package/src/panels/modals/planning-modal.ts +2 -2
  166. package/src/panels/modals/plugins-modal.ts +1 -1
  167. package/src/panels/modals/policy-modal.ts +1 -1
  168. package/src/panels/modals/security-modal.ts +7 -1
  169. package/src/panels/modals/skills-modal.ts +1 -1
  170. package/src/panels/modals/work-plan-modal.ts +3 -3
  171. package/src/panels/notifications-feed.ts +127 -0
  172. package/src/panels/notifications-panel.ts +160 -0
  173. package/src/panels/panel-manager.ts +9 -9
  174. package/src/panels/plugins-panel.ts +4 -4
  175. package/src/panels/project-planning-answer-actions.ts +1 -1
  176. package/src/panels/provider-health-routes.ts +2 -2
  177. package/src/panels/skills-panel.ts +4 -5
  178. package/src/panels/token-budget-panel.ts +11 -3
  179. package/src/panels/types.ts +5 -5
  180. package/src/panels/workstream-graph-render.ts +123 -0
  181. package/src/permissions/broker-approval-card.ts +201 -0
  182. package/src/permissions/hunk-selection.ts +28 -4
  183. package/src/permissions/prompt.ts +244 -29
  184. package/src/renderer/autocomplete-overlay.ts +107 -54
  185. package/src/renderer/code-block.ts +2 -2
  186. package/src/renderer/compaction-history-modal.ts +1 -1
  187. package/src/renderer/compaction-preview.ts +1 -1
  188. package/src/renderer/compaction-quality.ts +1 -1
  189. package/src/renderer/composer-fragments.ts +69 -0
  190. package/src/renderer/compositor.ts +2 -2
  191. package/src/renderer/config-modal.ts +1 -1
  192. package/src/renderer/conversation-overlays.ts +1 -1
  193. package/src/renderer/footer-tips.ts +3 -3
  194. package/src/renderer/hint-grammar.ts +1 -1
  195. package/src/renderer/modal-factory.ts +1 -1
  196. package/src/renderer/model-picker-overlay.ts +1 -1
  197. package/src/renderer/model-workspace.ts +7 -2
  198. package/src/renderer/panel-composite.ts +2 -2
  199. package/src/renderer/panel-workspace-bar.ts +1 -1
  200. package/src/renderer/process-indicator.ts +1 -1
  201. package/src/renderer/selection-modal-overlay.ts +1 -1
  202. package/src/renderer/session-picker-modal.ts +2 -2
  203. package/src/renderer/settings-modal-helpers.ts +23 -5
  204. package/src/renderer/settings-modal.ts +129 -39
  205. package/src/renderer/shell-surface.ts +6 -0
  206. package/src/renderer/terminal-bg-probe.ts +1 -1
  207. package/src/renderer/theme.ts +3 -3
  208. package/src/renderer/tool-call.ts +13 -7
  209. package/src/renderer/tool-result-summary.ts +1 -1
  210. package/src/renderer/turn-injection.ts +7 -6
  211. package/src/renderer/ui-factory.ts +38 -1
  212. package/src/runtime/bootstrap-command-context.ts +7 -2
  213. package/src/runtime/bootstrap-command-parts.ts +9 -5
  214. package/src/runtime/bootstrap-core.ts +41 -41
  215. package/src/runtime/bootstrap-hook-bridge.ts +1 -1
  216. package/src/runtime/bootstrap-shell.ts +13 -5
  217. package/src/runtime/bootstrap.ts +34 -32
  218. package/src/runtime/channel-composition.ts +46 -0
  219. package/src/runtime/code-index-services.ts +3 -4
  220. package/src/runtime/daemon-attach-notices.ts +120 -0
  221. package/src/runtime/durability-services.ts +90 -0
  222. package/src/runtime/embedded-service-factories.ts +40 -0
  223. package/src/runtime/feature-settings.ts +147 -0
  224. package/src/runtime/fleet-services.ts +41 -0
  225. package/src/runtime/idle-power-services.ts +85 -0
  226. package/src/runtime/index.ts +6 -21
  227. package/src/runtime/interaction-seams.ts +109 -0
  228. package/src/runtime/legacy-daemon-migration.ts +29 -19
  229. package/src/runtime/memory-fold.ts +1 -1
  230. package/src/runtime/notification-dispatch.ts +110 -0
  231. package/src/runtime/onboarding/apply.ts +3 -29
  232. package/src/runtime/onboarding/fast-path.ts +39 -6
  233. package/src/runtime/onboarding/provider-key-capture.ts +126 -0
  234. package/src/runtime/onboarding/snapshot.ts +0 -1
  235. package/src/runtime/onboarding/types.ts +9 -3
  236. package/src/runtime/power-keepawake-remote.ts +75 -0
  237. package/src/runtime/process-lifecycle.ts +3 -1
  238. package/src/runtime/provider-fallback.ts +55 -0
  239. package/src/runtime/provider-optimizer-wiring.ts +55 -0
  240. package/src/runtime/release-artifacts.ts +19 -103
  241. package/src/runtime/resume-notice.ts +1 -1
  242. package/src/runtime/services.ts +113 -113
  243. package/src/runtime/session-continuity-hints.ts +38 -0
  244. package/src/runtime/surface-feature-flags.ts +40 -9
  245. package/src/runtime/terminal-output-guard.ts +2 -2
  246. package/src/runtime/trust/workspace-registration.ts +10 -2
  247. package/src/runtime/trust/workspace-trust.ts +58 -31
  248. package/src/runtime/ui-services.ts +6 -1
  249. package/src/runtime/update-check.ts +15 -69
  250. package/src/runtime/workstream-services.ts +2 -2
  251. package/src/shell/blocking-input.ts +108 -132
  252. package/src/shell/recovery-input-helpers.ts +53 -166
  253. package/src/shell/ui-openers.ts +38 -6
  254. package/src/utils/format-duration.ts +1 -1
  255. package/src/verification/verification-ledger.ts +21 -4
  256. package/src/version.ts +1 -1
  257. 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 | FeatureFlagConfigKey;
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
- * Shared release-artifact naming and checksum-verification logic.
3
- *
4
- * This is the one place that knows the release asset naming convention
5
- * (`goodvibes[-daemon]-{platform}-{arch}`) and how to verify a downloaded
6
- * artifact against SHA256SUMS.txt. Two callers share it and must stay in
7
- * lockstep:
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 command's self-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
- import { createHash } from 'node:crypto';
16
-
17
- export const CHECKSUM_MANIFEST_NAME = 'SHA256SUMS.txt';
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
- * UX-D item 1: a supervision-journey audit of 1.7.0 found that the TUI
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