@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
package/src/runtime/services.ts
CHANGED
|
@@ -2,11 +2,15 @@ import { join } from 'node:path';
|
|
|
2
2
|
import { FocusTracker } from '../core/focus-tracker.ts';
|
|
3
3
|
import { ConfigManager, ServiceRegistry, SubscriptionManager, ToolLLM } from '@pellux/goodvibes-sdk/platform/config';
|
|
4
4
|
import { SecretsManager } from '../config/secrets.ts';
|
|
5
|
-
import { AutomationDeliveryManager, AutomationManager
|
|
6
|
-
import { ChannelDeliveryRouter,
|
|
7
|
-
import { ApprovalBroker, GatewayMethodCatalog, SharedSessionBroker } from '@pellux/goodvibes-sdk/platform/control-plane';
|
|
5
|
+
import { AutomationDeliveryManager, AutomationManager } from '@pellux/goodvibes-sdk/platform/automation';
|
|
6
|
+
import { ChannelDeliveryRouter, ChannelPolicyManager, type ChannelPluginRegistry, type RouteBindingManager, type SurfaceRegistry } from '@pellux/goodvibes-sdk/platform/channels';
|
|
7
|
+
import { ApprovalBroker, GatewayMethodCatalog, SessionLiveTurnControlsHolder, SharedSessionBroker } from '@pellux/goodvibes-sdk/platform/control-plane';
|
|
8
|
+
import type { PowerManager } from '@pellux/goodvibes-sdk/platform/power';
|
|
9
|
+
import { wireIdlePowerAndLiveTurn } from './idle-power-services.ts';
|
|
8
10
|
import { StepUpService } from '@pellux/goodvibes-sdk/daemon';
|
|
9
|
-
import {
|
|
11
|
+
import { PairingTokenManager } from '@pellux/goodvibes-sdk/platform/pairing';
|
|
12
|
+
import { resolvePairingWebOrigin } from '../core/pairing-origin.ts';
|
|
13
|
+
import { attachWsOnlyGatewayVerbHandlers } from '@pellux/goodvibes-terminal-shell';
|
|
10
14
|
import { WatcherRegistry } from '@pellux/goodvibes-sdk/platform/watchers';
|
|
11
15
|
import { ArtifactStore } from '@pellux/goodvibes-sdk/platform/artifacts';
|
|
12
16
|
import {
|
|
@@ -25,7 +29,13 @@ import { MediaProviderRegistry, ensureBuiltinMediaProviders } from '@pellux/good
|
|
|
25
29
|
import { MultimodalService } from '@pellux/goodvibes-sdk/platform/multimodal';
|
|
26
30
|
import { AgentMessageBus, AgentOrchestrator, ArchetypeLoader, WrfcController } from '@pellux/goodvibes-sdk/platform/agents';
|
|
27
31
|
import { AgentManager, ContextAccountingHolder, OverflowHandler, ProcessManager, createWorkflowServices, type WorkflowServices } from '@pellux/goodvibes-sdk/platform/tools';
|
|
28
|
-
import { FileStateCache, FileUndoManager, MemoryEmbeddingProviderRegistry, MemoryRegistry, MemoryStore, ModeManager, ProjectIndex, resolveCanonicalMemoryDbPath, type CodeIndexStore, type CodeIndexReindexScheduler } from '@pellux/goodvibes-sdk/platform/state';
|
|
32
|
+
import { FileStateCache, FileUndoManager, MemoryConsolidationScheduler, MemoryEmbeddingProviderRegistry, MemoryRegistry, MemoryStore, ModeManager, ProjectIndex, resolveCanonicalMemoryDbPath, type CodeIndexStore, type CodeIndexReindexScheduler } from '@pellux/goodvibes-sdk/platform/state';
|
|
33
|
+
import type { StoreSnapshotScheduler } from '@pellux/goodvibes-sdk/platform/state/store-snapshots';
|
|
34
|
+
import type { UserPermissionRuleStore } from '@pellux/goodvibes-sdk/platform/permissions';
|
|
35
|
+
import { buildExecPromptAnswerHandler } from '@pellux/goodvibes-sdk/platform/runtime/permissions/exec-prompt-wiring';
|
|
36
|
+
import { buildLocalhostFetchApproval } from '@pellux/goodvibes-sdk/platform/runtime/permissions/localhost-fetch-approval';
|
|
37
|
+
import { createNotificationDispatcher, wireRuntimeNotificationBridge, type NotificationDispatcher } from './notification-dispatch.ts';
|
|
38
|
+
import { createDurabilityServices } from './durability-services.ts';
|
|
29
39
|
import { MemorySpineClient, createLocalMemoryAccess } from '@pellux/goodvibes-sdk/platform/runtime/memory-spine';
|
|
30
40
|
import { WorkspaceCheckpointManager } from '@pellux/goodvibes-sdk/platform/workspace';
|
|
31
41
|
import { createWorkspaceCheckpointing } from './workspace-checkpointing.ts';
|
|
@@ -49,20 +59,19 @@ import { SessionManager, CrossSessionTaskRegistry, SessionChangeTracker } from '
|
|
|
49
59
|
import { ApiTokenAuditor, UserAuthManager } from '@pellux/goodvibes-sdk/platform/security';
|
|
50
60
|
import { WebhookNotifier } from '@pellux/goodvibes-sdk/platform/integrations';
|
|
51
61
|
import { McpRegistry } from '@pellux/goodvibes-sdk/platform/mcp';
|
|
52
|
-
import { BenchmarkStore, CacheHitTracker, FavoritesStore,
|
|
62
|
+
import { BenchmarkStore, CacheHitTracker, FavoritesStore, ModelLimitsService, ProviderCapabilityRegistry, ProviderOptimizer, ProviderRegistry } from '@pellux/goodvibes-sdk/platform/providers';
|
|
53
63
|
import { KeybindingsManager } from '../input/keybindings.ts';
|
|
54
64
|
import { AdaptivePlanner, DeterministicReplayEngine, ExecutionPlanManager, SessionLineageTracker, SessionMemoryStore } from '@pellux/goodvibes-sdk/platform/core';
|
|
55
|
-
import {
|
|
65
|
+
import { deriveFeatureStates, bindFeatureSettingsBridge } from '@pellux/goodvibes-sdk/platform/runtime/state';
|
|
66
|
+
import { createChannelComposition } from './channel-composition.ts';
|
|
67
|
+
import { applyProviderOptimizerConfigMode, bindProviderOptimizerFeatureFlag } from './provider-optimizer-wiring.ts';
|
|
56
68
|
import { type ArchivableProcessRegistry } from '@pellux/goodvibes-sdk/platform/runtime/fleet';
|
|
57
|
-
import {
|
|
69
|
+
import { createFleetServices } from './fleet-services.ts';
|
|
58
70
|
import { createWorkstreamServices, type OrchestrationEngine, type WorkstreamCommandService } from './workstream-services.ts';
|
|
59
71
|
import { wireFleetNeedsInputPush } from './fleet-needs-input-push.ts';
|
|
60
72
|
import { codeIndexDbPath, createCodeIndexServices, isCodeInjectionSettingEnabled } from './code-index-services.ts';
|
|
61
73
|
import { WorkPlanStore } from '../work-plans/work-plan-store.ts';
|
|
62
|
-
import {
|
|
63
|
-
registerDaemonHandlers,
|
|
64
|
-
type DaemonHandlerSurfaces,
|
|
65
|
-
} from '../daemon/handlers/index.ts';
|
|
74
|
+
import { registerDaemonHandlers, type DaemonHandlerSurfaces } from '../daemon/handlers/index.ts';
|
|
66
75
|
import type { HandlerContext, HandlerLogger } from '../daemon/handlers/context.ts';
|
|
67
76
|
import { createDaemonCredentialStore } from '../daemon/handlers/credentials.ts';
|
|
68
77
|
import { registerRouting } from '../daemon/handlers/routing/index.ts';
|
|
@@ -73,58 +82,10 @@ import { registerCalendar } from '../daemon/handlers/calendar/index.ts';
|
|
|
73
82
|
import { registerEmailMethods } from '../daemon/handlers/email/index.ts';
|
|
74
83
|
import { registerRemoteSurface } from '../daemon/handlers/remote/index.ts';
|
|
75
84
|
import { WorkspaceTrustManager } from './trust/workspace-trust.ts';
|
|
85
|
+
import { ensureConfiguredModelIsRoutable } from './provider-fallback.ts';
|
|
76
86
|
|
|
77
87
|
const REGULAR_KNOWLEDGE_DB_FILE = 'knowledge-wiki.sqlite';
|
|
78
88
|
const HOME_GRAPH_KNOWLEDGE_DB_FILE = 'knowledge-home-graph.sqlite';
|
|
79
|
-
|
|
80
|
-
function buildFallbackModelDefinition(provider: string, modelId: string): ModelDefinition {
|
|
81
|
-
const providerLower = provider.toLowerCase();
|
|
82
|
-
const isReasoningProvider = providerLower.includes('openai')
|
|
83
|
-
|| providerLower.includes('anthropic')
|
|
84
|
-
|| providerLower.includes('gemini')
|
|
85
|
-
|| providerLower.includes('google');
|
|
86
|
-
|
|
87
|
-
return {
|
|
88
|
-
id: modelId,
|
|
89
|
-
provider,
|
|
90
|
-
registryKey: `${provider}:${modelId}`,
|
|
91
|
-
displayName: modelId,
|
|
92
|
-
description: 'Configured model available before the model catalog cache has loaded.',
|
|
93
|
-
capabilities: {
|
|
94
|
-
toolCalling: true,
|
|
95
|
-
codeEditing: true,
|
|
96
|
-
reasoning: isReasoningProvider,
|
|
97
|
-
multimodal: isReasoningProvider,
|
|
98
|
-
},
|
|
99
|
-
// Pre-catalog fallback uses the SDK's family-aware inference (SDK 0.35.0+),
|
|
100
|
-
// matching the post-catalog window so the meter/compaction denominator agrees.
|
|
101
|
-
contextWindow: inferFallbackContextWindow(provider, modelId),
|
|
102
|
-
contextWindowProvenance: 'fallback',
|
|
103
|
-
selectable: true,
|
|
104
|
-
tier: 'standard',
|
|
105
|
-
...(isReasoningProvider ? { reasoningEffort: ['instant', 'low', 'medium', 'high'] } : {}),
|
|
106
|
-
};
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
function ensureConfiguredModelIsRoutable(providerRegistry: ProviderRegistry, configManager: ConfigManager): void {
|
|
110
|
-
const configuredModel = String(configManager.get('provider.model') ?? '').trim();
|
|
111
|
-
if (!configuredModel.includes(':')) return;
|
|
112
|
-
if (providerRegistry.listModels().some((model) => model.registryKey === configuredModel)) return;
|
|
113
|
-
|
|
114
|
-
const [providerId, ...modelParts] = configuredModel.split(':');
|
|
115
|
-
const modelId = modelParts.join(':').trim();
|
|
116
|
-
if (!providerId || !modelId) return;
|
|
117
|
-
|
|
118
|
-
const provider = providerRegistry.tryGet(providerId);
|
|
119
|
-
if (!provider) return;
|
|
120
|
-
|
|
121
|
-
providerRegistry.registerRuntimeProvider({
|
|
122
|
-
provider,
|
|
123
|
-
replace: true,
|
|
124
|
-
models: [buildFallbackModelDefinition(providerId, modelId)],
|
|
125
|
-
});
|
|
126
|
-
}
|
|
127
|
-
|
|
128
89
|
export interface RuntimeServicesOptions {
|
|
129
90
|
readonly runtimeBus: RuntimeEventBus;
|
|
130
91
|
readonly runtimeStore: RuntimeStore;
|
|
@@ -134,8 +95,13 @@ export interface RuntimeServicesOptions {
|
|
|
134
95
|
readonly getConversationTitle?: () => string | undefined;
|
|
135
96
|
readonly workingDir: string;
|
|
136
97
|
readonly homeDirectory: string;
|
|
137
|
-
/**
|
|
138
|
-
|
|
98
|
+
/** Opt-in (daemon-side only): fold host-observed external coding-agent sessions
|
|
99
|
+
* into the fleet as 'observed-external' rows. Interactive leaves it off and reads
|
|
100
|
+
* the daemon snapshot. Mirrors the SDK's own createRuntimeServices option. */
|
|
101
|
+
readonly observeExternalAgents?: boolean | undefined;
|
|
102
|
+
/** Host power seam opt-in. Fork mirrors the SDK: non-spawning unavailable-seam
|
|
103
|
+
* default (idle-power-services.ts); daemon + embedded runtime pass createHostPowerSeam(). */
|
|
104
|
+
readonly powerSeam?: Parameters<typeof wireIdlePowerAndLiveTurn>[0]['powerSeam'];
|
|
139
105
|
}
|
|
140
106
|
|
|
141
107
|
export interface RuntimeServices {
|
|
@@ -155,6 +121,14 @@ export interface RuntimeServices {
|
|
|
155
121
|
readonly channelDeliveryRouter: ChannelDeliveryRouter;
|
|
156
122
|
readonly watcherRegistry: WatcherRegistry;
|
|
157
123
|
readonly approvalBroker: ApprovalBroker;
|
|
124
|
+
/** Loopback-fetch approval that rides the approval broker; shared by the tool registry and orchestrator so every surface asks the same way. */
|
|
125
|
+
readonly localhostFetchApproval: ReturnType<typeof buildLocalhostFetchApproval>;
|
|
126
|
+
/** Terminal prompt-answer handler that rides the approval broker; shared by the tool registry and orchestrator so an interactive command's prompt gets an ask/card on every surface. */
|
|
127
|
+
readonly execPromptAnswerHandler: ReturnType<typeof buildExecPromptAnswerHandler>;
|
|
128
|
+
/** Routes curated runtime-domain events into the panel_only notification feed (the panel's live producer). */
|
|
129
|
+
readonly notificationDispatcher: NotificationDispatcher;
|
|
130
|
+
/** Durable user-origin permission rules (remembered approvals); permissions.rules.* surface. Mirrors the SDK composition. */
|
|
131
|
+
readonly userPermissionRuleStore: UserPermissionRuleStore;
|
|
158
132
|
readonly sessionBroker: SharedSessionBroker;
|
|
159
133
|
readonly deliveryManager: AutomationDeliveryManager;
|
|
160
134
|
readonly automationManager: AutomationManager;
|
|
@@ -173,6 +147,7 @@ export interface RuntimeServices {
|
|
|
173
147
|
readonly serviceRegistry: ServiceRegistry;
|
|
174
148
|
readonly secretsManager: SecretsManager;
|
|
175
149
|
readonly stepUpService: StepUpService;
|
|
150
|
+
readonly pairingTokens: PairingTokenManager; // backs pairing.tokens.* verbs + the settings device surface (mirrors the SDK composition)
|
|
176
151
|
readonly subscriptionManager: SubscriptionManager;
|
|
177
152
|
readonly localUserAuthManager: UserAuthManager;
|
|
178
153
|
readonly profileManager: ProfileManager;
|
|
@@ -198,7 +173,7 @@ export interface RuntimeServices {
|
|
|
198
173
|
readonly worktreeRegistry: WorktreeRegistry;
|
|
199
174
|
readonly sandboxSessionRegistry: SandboxSessionRegistry;
|
|
200
175
|
readonly webhookNotifier: WebhookNotifier;
|
|
201
|
-
/** Terminal focus tracker
|
|
176
|
+
/** Terminal focus tracker — fed by input/handler-feed.ts, read by the alert notifiers in core/. */
|
|
202
177
|
readonly focusTracker: FocusTracker;
|
|
203
178
|
readonly replayEngine: DeterministicReplayEngine;
|
|
204
179
|
readonly providerOptimizer: ProviderOptimizer;
|
|
@@ -234,6 +209,11 @@ export interface RuntimeServices {
|
|
|
234
209
|
/** The repo source-tree code index — see runtime/code-index-services.ts. */
|
|
235
210
|
readonly codeIndexStore: CodeIndexStore;
|
|
236
211
|
readonly codeIndexReindexScheduler: CodeIndexReindexScheduler; // tool-site reindex
|
|
212
|
+
/** Daily snapshots of every SQLite store this runtime writes, with bounded retention; unref'd timers (mirrors the SDK composition — hosts that tear down a runtime stop() it themselves). */
|
|
213
|
+
readonly storeSnapshotScheduler: StoreSnapshotScheduler;
|
|
214
|
+
readonly memoryConsolidationScheduler: MemoryConsolidationScheduler;
|
|
215
|
+
readonly powerManager: PowerManager;
|
|
216
|
+
readonly sessionLiveTurnControls: SessionLiveTurnControlsHolder;
|
|
237
217
|
/** Unified live process registry (agents, WRFC chains, workflows, watchers, background processes) backing the Fleet panel; archive-aware — finished subtrees can be moved to the session archive view. */
|
|
238
218
|
readonly processRegistry: ArchivableProcessRegistry;
|
|
239
219
|
readonly modeManager: ModeManager;
|
|
@@ -253,26 +233,31 @@ export function createRuntimeServices(options: RuntimeServicesOptions): RuntimeS
|
|
|
253
233
|
workingDirectory,
|
|
254
234
|
homeDirectory,
|
|
255
235
|
});
|
|
256
|
-
const workspaceTrustManager = new WorkspaceTrustManager({ shellPaths
|
|
236
|
+
const workspaceTrustManager = new WorkspaceTrustManager({ shellPaths });
|
|
257
237
|
const configManager = options.configManager;
|
|
258
238
|
const featureFlags = options.featureFlags ?? createFeatureFlagManager();
|
|
239
|
+
if (options.featureFlags === undefined) {
|
|
240
|
+
// Owned manager: gate states derive from domain settings keys + live
|
|
241
|
+
// bridge (mirrors the SDK composition root; a passed manager is the caller's to wire).
|
|
242
|
+
featureFlags.loadFromConfig({ flags: deriveFeatureStates(configManager) });
|
|
243
|
+
bindFeatureSettingsBridge(configManager, featureFlags);
|
|
244
|
+
}
|
|
259
245
|
const runtimeDispatch = createDomainDispatch(options.runtimeStore);
|
|
260
246
|
const gatewayMethods = new GatewayMethodCatalog();
|
|
261
247
|
const panelManager = new PanelManager();
|
|
262
|
-
//
|
|
248
|
+
// (the purge): MIGRATE-TO-MODAL surface + redirect registration moved to
|
|
263
249
|
// registerBuiltinPanels (builtin-panels.ts), where the panels' resolved deps
|
|
264
250
|
// are available for the surfaces to close over.
|
|
265
251
|
const keybindingsManager = new KeybindingsManager({
|
|
266
252
|
configPath: shellPaths.resolveUserPath('tui', 'keybindings.json'),
|
|
267
253
|
});
|
|
268
|
-
|
|
269
|
-
|
|
254
|
+
// Channel/surface wiring: see channel-composition.ts (incl. the recorded surface-gating divergence note).
|
|
255
|
+
const { routeBindings, surfaceRegistry, channelPlugins } = createChannelComposition({
|
|
256
|
+
configManager,
|
|
270
257
|
runtimeStore: options.runtimeStore,
|
|
271
258
|
runtimeBus: options.runtimeBus,
|
|
259
|
+
featureFlags,
|
|
272
260
|
});
|
|
273
|
-
const surfaceRegistry = new SurfaceRegistry(configManager, options.runtimeStore);
|
|
274
|
-
const channelPlugins = new ChannelPluginRegistry();
|
|
275
|
-
surfaceRegistry.attachPluginRegistry(channelPlugins);
|
|
276
261
|
const secretsManager = new SecretsManager({
|
|
277
262
|
projectRoot: workingDirectory,
|
|
278
263
|
globalHome: homeDirectory,
|
|
@@ -280,6 +265,7 @@ export function createRuntimeServices(options: RuntimeServicesOptions): RuntimeS
|
|
|
280
265
|
});
|
|
281
266
|
// Step-up (WebAuthn) ceremony service, shared between the ceremony gateway verbs and the relay gate's verifier.
|
|
282
267
|
const stepUpService = new StepUpService({ secrets: secretsManager });
|
|
268
|
+
const pairingTokens = new PairingTokenManager(shellPaths.resolveUserPath('control-plane', 'pairing-tokens.json'));
|
|
283
269
|
const subscriptionManager = new SubscriptionManager(shellPaths.resolveUserPath('tui', 'subscriptions.json'));
|
|
284
270
|
const serviceRegistry = new ServiceRegistry(shellPaths.resolveProjectPath('tui', 'services.json'), {
|
|
285
271
|
secretsManager,
|
|
@@ -307,6 +293,10 @@ export function createRuntimeServices(options: RuntimeServicesOptions): RuntimeS
|
|
|
307
293
|
});
|
|
308
294
|
ensureConfiguredModelIsRoutable(providerRegistry, configManager);
|
|
309
295
|
providerRegistry.initCustomProviders();
|
|
296
|
+
// Kick off the background, TTL-respecting live model discovery sweep so
|
|
297
|
+
// provider model lists refresh from their own listing APIs — matching the
|
|
298
|
+
// SDK and agent compositions (this call was the one omitted here).
|
|
299
|
+
providerRegistry.initProviderModelDiscovery();
|
|
310
300
|
const toolLLM = new ToolLLM({
|
|
311
301
|
configManager,
|
|
312
302
|
providerRegistry,
|
|
@@ -341,6 +331,9 @@ export function createRuntimeServices(options: RuntimeServicesOptions): RuntimeS
|
|
|
341
331
|
messageBus: agentMessageBus,
|
|
342
332
|
executor: agentOrchestrator,
|
|
343
333
|
configManager,
|
|
334
|
+
// The live registry lets a bare model id in a spawn() override resolve
|
|
335
|
+
// through the shared resolver instead of being rejected as unqualified.
|
|
336
|
+
providerRegistry,
|
|
344
337
|
});
|
|
345
338
|
const contextAccountingHolder = new ContextAccountingHolder();
|
|
346
339
|
agentOrchestrator.setConversationSink({ // Conversation-snapshot bridge (mirrors the SDK's own createRuntimeServices)
|
|
@@ -418,6 +411,9 @@ export function createRuntimeServices(options: RuntimeServicesOptions): RuntimeS
|
|
|
418
411
|
runtimeStore: options.runtimeStore,
|
|
419
412
|
runtimeBus: options.runtimeBus,
|
|
420
413
|
deliveryManager,
|
|
414
|
+
// Same live registry: a bare model id on an automation job resolves through
|
|
415
|
+
// the shared resolver instead of a format-only rejection.
|
|
416
|
+
providerRegistry,
|
|
421
417
|
spawnTask: (input) => {
|
|
422
418
|
const record = agentManager.spawn({
|
|
423
419
|
mode: 'spawn',
|
|
@@ -489,7 +485,7 @@ export function createRuntimeServices(options: RuntimeServicesOptions): RuntimeS
|
|
|
489
485
|
projectRoot: workingDirectory,
|
|
490
486
|
});
|
|
491
487
|
const voiceProviders = new VoiceProviderRegistry();
|
|
492
|
-
ensureBuiltinVoiceProviders(voiceProviders);
|
|
488
|
+
ensureBuiltinVoiceProviders(voiceProviders, { readConfig: (key) => configManager.get(key as Parameters<typeof configManager.get>[0]) });
|
|
493
489
|
const voiceService = new VoiceService(voiceProviders);
|
|
494
490
|
const webSearchProviders = new WebSearchProviderRegistry({
|
|
495
491
|
env: process.env,
|
|
@@ -499,18 +495,9 @@ export function createRuntimeServices(options: RuntimeServicesOptions): RuntimeS
|
|
|
499
495
|
serviceRegistry,
|
|
500
496
|
featureFlags,
|
|
501
497
|
});
|
|
502
|
-
knowledgeSemanticService
|
|
503
|
-
searchService: webSearchService,
|
|
504
|
-
|
|
505
|
-
}));
|
|
506
|
-
agentKnowledgeSemanticService.setGapRepairer(createWebKnowledgeGapRepairer({
|
|
507
|
-
searchService: webSearchService,
|
|
508
|
-
ingestService: agentKnowledgeService,
|
|
509
|
-
}));
|
|
510
|
-
homeGraphSemanticService.setGapRepairer(createWebKnowledgeGapRepairer({
|
|
511
|
-
searchService: webSearchService,
|
|
512
|
-
ingestService: homeGraphService,
|
|
513
|
-
}));
|
|
498
|
+
for (const [semantic, ingest] of [[knowledgeSemanticService, knowledgeService], [agentKnowledgeSemanticService, agentKnowledgeService], [homeGraphSemanticService, homeGraphService]] as const) {
|
|
499
|
+
semantic.setGapRepairer(createWebKnowledgeGapRepairer({ searchService: webSearchService, ingestService: ingest }));
|
|
500
|
+
}
|
|
514
501
|
const mediaProviders = new MediaProviderRegistry();
|
|
515
502
|
ensureBuiltinMediaProviders(mediaProviders, artifactStore, providerRegistry);
|
|
516
503
|
const multimodalService = new MultimodalService(artifactStore, mediaProviders, voiceService, knowledgeService);
|
|
@@ -578,11 +565,9 @@ export function createRuntimeServices(options: RuntimeServicesOptions): RuntimeS
|
|
|
578
565
|
const webhookNotifier = new WebhookNotifier();
|
|
579
566
|
const focusTracker = new FocusTracker();
|
|
580
567
|
const replayEngine = new DeterministicReplayEngine(workingDirectory);
|
|
581
|
-
const providerOptimizer = new ProviderOptimizer(
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
isFeatureFlagEnabled(configManager, 'provider-optimizer'),
|
|
585
|
-
);
|
|
568
|
+
const providerOptimizer = new ProviderOptimizer(providerRegistry, providerCapabilityRegistry, false); // dark until its gate flips it (see provider-optimizer-wiring.ts)
|
|
569
|
+
bindProviderOptimizerFeatureFlag(featureFlags, providerOptimizer);
|
|
570
|
+
applyProviderOptimizerConfigMode(configManager, providerOptimizer);
|
|
586
571
|
const sessionMemoryStore = new SessionMemoryStore();
|
|
587
572
|
const sessionLineageTracker = new SessionLineageTracker();
|
|
588
573
|
const sessionChangeTracker = new SessionChangeTracker();
|
|
@@ -611,37 +596,28 @@ export function createRuntimeServices(options: RuntimeServicesOptions): RuntimeS
|
|
|
611
596
|
// with MemoryStore above. Auto-build is config-gated (default off) — see
|
|
612
597
|
// code-index-services.ts's header doc.
|
|
613
598
|
const { codeIndexStore, codeIndexReindexScheduler } = createCodeIndexServices({ workingDirectory, configManager, memoryEmbeddingRegistry });
|
|
599
|
+
// Store snapshots + durable remembered-approval rules + the live credential
|
|
600
|
+
// chain, mirroring the SDK composition — see durability-services.ts.
|
|
601
|
+
const { storeSnapshotScheduler, userPermissionRuleStore } = createDurabilityServices({
|
|
602
|
+
configManager, secretsManager, providerRegistry, memoryDbPath, codeIndexDbPath: codeIndexDbPath(workingDirectory), workingDirectory, surfaceRoot: 'tui', homeDirectory, shellPaths, // + retention-sweep roots & live config watch (mirrors the SDK)
|
|
603
|
+
});
|
|
614
604
|
const codeInjectionOrchestratorDeps = { codeIndex: codeIndexStore, isCodeInjectionSettingEnabled: () => isCodeInjectionSettingEnabled(configManager), codeIndexReindexScheduler }; // Code-injection seam (agent here; main via orchestrator-core-services.ts)
|
|
615
|
-
// Shared
|
|
616
|
-
|
|
617
|
-
agentManager,
|
|
618
|
-
wrfcController,
|
|
605
|
+
const { processRegistry } = createFleetServices({ // Shared archive-aware fleet registry (+ daemon observed rows) — see fleet-services.ts
|
|
606
|
+
agentManager, wrfcController,
|
|
619
607
|
orchestrationEngine, // Folds workstream/phase/work-item nodes into the fleet
|
|
620
608
|
codeIndexService: codeIndexStore, // Folds a single 'code-index' node into the fleet
|
|
621
|
-
processManager,
|
|
622
|
-
watcherRegistry,
|
|
623
|
-
workflow,
|
|
624
|
-
approvalBroker,
|
|
625
|
-
sessionBroker,
|
|
609
|
+
processManager, watcherRegistry, workflow, approvalBroker, sessionBroker,
|
|
626
610
|
messageBus: agentMessageBus, // Backs steer()/`steerable` (the Fleet steer composer builds on top)
|
|
627
611
|
automationManager, // Folds /schedule AutomationJobs into the fleet as 'schedule' nodes
|
|
628
612
|
runtimeBus: options.runtimeBus,
|
|
629
|
-
|
|
630
|
-
priceUsage: (model, usage) => {
|
|
631
|
-
const modelId = model ?? 'unknown';
|
|
632
|
-
if (!isModelPriced(modelId)) return null;
|
|
633
|
-
return calcSessionCost(usage.inputTokens, usage.outputTokens, usage.cacheReadTokens, usage.cacheWriteTokens, modelId);
|
|
634
|
-
},
|
|
613
|
+
observeExternalAgents: options.observeExternalAgents, providerRegistry, // observeExternalAgents is daemon-side only
|
|
635
614
|
});
|
|
636
|
-
const modeManager = new ModeManager();
|
|
637
|
-
const fileUndoManager = new FileUndoManager();
|
|
615
|
+
const modeManager = new ModeManager(); const fileUndoManager = new FileUndoManager();
|
|
638
616
|
const workspaceCheckpointManager = createWorkspaceCheckpointing({ workspaceRoot: workingDirectory, runtimeBus: options.runtimeBus, configManager });
|
|
617
|
+
const { memoryConsolidationScheduler, powerManager, sessionLiveTurnControls } = wireIdlePowerAndLiveTurn({ configManager, memoryRegistry, runtimeBus: options.runtimeBus, isIdle: () => sessionBroker.countBusySessions() === 0, snapshotTick: () => storeSnapshotScheduler.tick(), heartbeat: async () => { await automationManager.triggerHeartbeat({ source: 'wake-catchup' }); }, powerSeam: options.powerSeam });
|
|
639
618
|
|
|
640
|
-
//
|
|
641
|
-
|
|
642
|
-
// channelDeliveryRouter/providerRegistry/automationManager/sessionLister ALL present; fleet needs-input push gated by
|
|
643
|
-
// runtimeBus/sessionPresence (fleet-needs-input-push.ts). conversationRewindPort serves conversation-scope rewind live.
|
|
644
|
-
attachWsOnlyGatewayVerbHandlers(gatewayMethods, { processRegistry, workspaceCheckpointManager, conversationRewindPort: createSessionConversationRewindPort(), sessionBroker, secretsManager, stepUpService, approvalBroker, shellPaths, configManager, runtimeStore: options.runtimeStore, channelDeliveryRouter, providerRegistry, automationManager, sessionLister: sessionBroker, ...wireFleetNeedsInputPush({ registry: processRegistry, runtimeBus: options.runtimeBus, sessionBroker }) });
|
|
619
|
+
// Terminal-shell wrapper over the SDK registerGatewayVerbGroups (gateway-verbs.ts); checkin.*/fleet-needs-input/pairing.* register only when their deps are present.
|
|
620
|
+
attachWsOnlyGatewayVerbHandlers(gatewayMethods, { processRegistry, workspaceCheckpointManager, conversationRewindPort: createSessionConversationRewindPort(), sessionBroker, secretsManager, stepUpService, approvalBroker, requestApproval: (input) => approvalBroker.requestApproval(input), watcherRegistry, userPermissionRuleStore, shellPaths, configManager, runtimeStore: options.runtimeStore, channelDeliveryRouter, providerRegistry, automationManager, sessionLister: sessionBroker, sessionIntake: sessionBroker, workingDirectory, memoryRegistry, pairingTokens, sessionLiveTurnControls, powerManager, relayAvailable: () => configManager.get('relay.enabled') === true, pairingWebOrigin: () => resolvePairingWebOrigin(configManager).origin, ...wireFleetNeedsInputPush({ registry: processRegistry, runtimeBus: options.runtimeBus, sessionBroker }) });
|
|
645
621
|
const integrationHelpers = new IntegrationHelperService({
|
|
646
622
|
workingDirectory,
|
|
647
623
|
homeDirectory,
|
|
@@ -662,8 +638,16 @@ export function createRuntimeServices(options: RuntimeServicesOptions): RuntimeS
|
|
|
662
638
|
subscriptionManager,
|
|
663
639
|
secretsManager,
|
|
664
640
|
});
|
|
641
|
+
// A loopback fetch that isn't allow-listed asks once through the approval
|
|
642
|
+
// broker; "allow for this project" persists and later fetches never ask. Built
|
|
643
|
+
// once and shared with the tool registry (bootstrap-core) so both ask alike.
|
|
644
|
+
const localhostFetchApproval = buildLocalhostFetchApproval({ requestApproval: (input) => approvalBroker.requestApproval(input), configManager });
|
|
645
|
+
// Exec stuck on a terminal prompt rides the approval broker; the typed answer feeds the continuing run. Built once and shared (like localhostFetchApproval) so the tool registry AND every setDependencies site — incl. the post-clobber rewire in bootstrap-core — install the SAME handler; otherwise a wholesale replace drops it and interactive prompts hang.
|
|
646
|
+
const execPromptAnswerHandler = buildExecPromptAnswerHandler({ requestApproval: (input) => approvalBroker.requestApproval(input) });
|
|
665
647
|
agentOrchestrator.setDependencies({
|
|
666
648
|
surfaceRoot: 'tui',
|
|
649
|
+
execPromptAnswerHandler,
|
|
650
|
+
localhostFetchApproval,
|
|
667
651
|
fileCache,
|
|
668
652
|
projectIndex,
|
|
669
653
|
workingDirectory,
|
|
@@ -691,6 +675,12 @@ export function createRuntimeServices(options: RuntimeServicesOptions): RuntimeS
|
|
|
691
675
|
contextAccountingHolder,
|
|
692
676
|
});
|
|
693
677
|
|
|
678
|
+
// Give the panel_only notification target a live producer: curated
|
|
679
|
+
// runtime-domain events route through the notification router into the shared
|
|
680
|
+
// panel feed (panel_only and burst-collapsed decisions land there).
|
|
681
|
+
const notificationDispatcher = createNotificationDispatcher(configManager);
|
|
682
|
+
wireRuntimeNotificationBridge(options.runtimeBus, notificationDispatcher);
|
|
683
|
+
|
|
694
684
|
return {
|
|
695
685
|
workingDirectory,
|
|
696
686
|
homeDirectory,
|
|
@@ -709,6 +699,10 @@ export function createRuntimeServices(options: RuntimeServicesOptions): RuntimeS
|
|
|
709
699
|
channelDeliveryRouter,
|
|
710
700
|
watcherRegistry,
|
|
711
701
|
approvalBroker,
|
|
702
|
+
localhostFetchApproval,
|
|
703
|
+
execPromptAnswerHandler,
|
|
704
|
+
notificationDispatcher,
|
|
705
|
+
userPermissionRuleStore,
|
|
712
706
|
sessionBroker,
|
|
713
707
|
deliveryManager,
|
|
714
708
|
automationManager,
|
|
@@ -726,6 +720,7 @@ export function createRuntimeServices(options: RuntimeServicesOptions): RuntimeS
|
|
|
726
720
|
serviceRegistry,
|
|
727
721
|
secretsManager,
|
|
728
722
|
stepUpService,
|
|
723
|
+
pairingTokens,
|
|
729
724
|
subscriptionManager,
|
|
730
725
|
localUserAuthManager,
|
|
731
726
|
profileManager,
|
|
@@ -784,6 +779,10 @@ export function createRuntimeServices(options: RuntimeServicesOptions): RuntimeS
|
|
|
784
779
|
workstreamCommands,
|
|
785
780
|
codeIndexStore,
|
|
786
781
|
codeIndexReindexScheduler,
|
|
782
|
+
storeSnapshotScheduler,
|
|
783
|
+
memoryConsolidationScheduler,
|
|
784
|
+
powerManager,
|
|
785
|
+
sessionLiveTurnControls,
|
|
787
786
|
processRegistry,
|
|
788
787
|
modeManager,
|
|
789
788
|
fileUndoManager,
|
|
@@ -791,8 +790,9 @@ export function createRuntimeServices(options: RuntimeServicesOptions): RuntimeS
|
|
|
791
790
|
integrationHelpers,
|
|
792
791
|
async rerootStores(newWorkingDir: string): Promise<void> {
|
|
793
792
|
// The memory store is the home-scoped canonical cross-surface store and
|
|
794
|
-
// deliberately does NOT reroot per-project (that would re-silo memory
|
|
795
|
-
//
|
|
793
|
+
// deliberately does NOT reroot per-project (that would re-silo memory back
|
|
794
|
+
// into per-project stores). Only working-tree-bound stores (code index,
|
|
795
|
+
// project index) reroot.
|
|
796
796
|
await codeIndexStore.reroot(newWorkingDir, codeIndexDbPath(newWorkingDir));
|
|
797
797
|
await projectIndex.reroot(newWorkingDir);
|
|
798
798
|
},
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* session-continuity-hints — the recovery snapshot's continuity summary.
|
|
3
|
+
*
|
|
4
|
+
* Extracted from main.ts (which sits at the architecture line cap) so the
|
|
5
|
+
* startup wiring there stays within budget. Builds the small counts/paths
|
|
6
|
+
* bundle written into the recovery file so a resumed session can describe what
|
|
7
|
+
* was in flight (pending approvals, active/blocked tasks, remotes, worktrees,
|
|
8
|
+
* open panels) without re-reading live state.
|
|
9
|
+
*/
|
|
10
|
+
import type { UiReadModels } from './ui-read-models.ts';
|
|
11
|
+
import type { PanelManager } from '../panels/panel-manager.ts';
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* The continuity summary written into the recovery file. A loose serializable
|
|
15
|
+
* bag (Record) because it is JSON-persisted and read back by the recovery
|
|
16
|
+
* continuity-hints consumer, which types it structurally.
|
|
17
|
+
*/
|
|
18
|
+
export function createSessionContinuityHintsBuilder(deps: {
|
|
19
|
+
readonly readModels: UiReadModels;
|
|
20
|
+
readonly panelManager: Pick<PanelManager, 'getAllOpen'>;
|
|
21
|
+
}): () => Record<string, unknown> {
|
|
22
|
+
return () => {
|
|
23
|
+
const sessionSnapshot = deps.readModels.session.getSnapshot();
|
|
24
|
+
const tasksSnapshot = deps.readModels.tasks.getSnapshot();
|
|
25
|
+
const remoteSnapshot = deps.readModels.remote.getSnapshot();
|
|
26
|
+
const worktreeSnapshot = deps.readModels.worktrees.getSnapshot();
|
|
27
|
+
return {
|
|
28
|
+
pendingApprovals: sessionSnapshot.pendingApproval ? 1 : 0,
|
|
29
|
+
activeTasks: tasksSnapshot.tasks.filter((task) => task.status === 'running' || task.status === 'queued').length,
|
|
30
|
+
blockedTasks: tasksSnapshot.tasks.filter((task) => task.status === 'blocked').length,
|
|
31
|
+
remoteContracts: remoteSnapshot.contracts.length,
|
|
32
|
+
remoteRunners: remoteSnapshot.contracts.slice(0, 4).map((contract) => contract.runnerId),
|
|
33
|
+
worktreeCount: worktreeSnapshot.records.length,
|
|
34
|
+
worktreePaths: worktreeSnapshot.records.slice(0, 3).map((record) => record.path),
|
|
35
|
+
openPanels: deps.panelManager.getAllOpen().map((panel) => panel.id),
|
|
36
|
+
};
|
|
37
|
+
};
|
|
38
|
+
}
|
|
@@ -1,5 +1,16 @@
|
|
|
1
|
-
|
|
1
|
+
/**
|
|
2
|
+
* surface-feature-flags — which platform capabilities a surface/server setup
|
|
3
|
+
* needs, and how to switch them on through their real domain settings keys.
|
|
4
|
+
*
|
|
5
|
+
* Capabilities are configured through first-class domain settings (see
|
|
6
|
+
* feature-settings.ts); enabling a surface writes keys like
|
|
7
|
+
* `controlPlane.gateway` or `surfaces.slack.enabled`, never a separate
|
|
8
|
+
* enablement namespace.
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
import type { ConfigManager } from '../config/index.ts';
|
|
2
12
|
import { surfaceFeatureGateId } from '@/runtime/index.ts';
|
|
13
|
+
import { featureEnablementWrite, getFeatureSetting, isFeatureConfigEnabled } from './feature-settings.ts';
|
|
3
14
|
|
|
4
15
|
export const CONTROL_PLANE_FEATURE_FLAG = 'control-plane-gateway';
|
|
5
16
|
export const ROUTE_BINDING_FEATURE_FLAG = 'route-binding';
|
|
@@ -12,10 +23,15 @@ const CORE_CHANNEL_FEATURE_FLAGS = [
|
|
|
12
23
|
DELIVERY_ENGINE_FEATURE_FLAG,
|
|
13
24
|
] as const;
|
|
14
25
|
|
|
15
|
-
export type FeatureFlagConfigKey = 'featureFlags' | `featureFlags.${string}`;
|
|
16
|
-
|
|
17
26
|
export function getSurfaceFeatureFlag(surfaceId: string): string | null {
|
|
18
|
-
|
|
27
|
+
// Onboarding surface ids may be camelCase ('googleChat'); the SDK's gate
|
|
28
|
+
// map is keyed by the kebab-case ChannelSurface id ('google-chat'). Try the
|
|
29
|
+
// literal id first, then the kebab-case form, so choosing Google Chat in
|
|
30
|
+
// onboarding really flips google-chat-surface.
|
|
31
|
+
const literal = surfaceFeatureGateId(surfaceId);
|
|
32
|
+
if (literal) return literal;
|
|
33
|
+
const kebab = surfaceId.replace(/[A-Z]/g, (ch) => `-${ch.toLowerCase()}`);
|
|
34
|
+
return kebab === surfaceId ? null : surfaceFeatureGateId(kebab);
|
|
19
35
|
}
|
|
20
36
|
|
|
21
37
|
export function getServerSurfaceFeatureFlags(options: {
|
|
@@ -46,20 +62,35 @@ export function getServerSurfaceFeatureFlags(options: {
|
|
|
46
62
|
return [...flags].sort((left, right) => left.localeCompare(right));
|
|
47
63
|
}
|
|
48
64
|
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
return
|
|
65
|
+
/** Whether the live config has the capability on, derived from its domain settings key. */
|
|
66
|
+
export function isFeatureFlagEnabled(config: Pick<ConfigManager, 'get'>, flagId: string): boolean {
|
|
67
|
+
return isFeatureConfigEnabled(config, flagId);
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* Translate internal feature-gate ids (e.g. 'control-plane-gateway') to the
|
|
72
|
+
* canonical domain settings keys the user actually sets (e.g.
|
|
73
|
+
* 'controlPlane.gateway') — matching the SDK's own gate errors, which name the
|
|
74
|
+
* settings key. A gate with no mapped setting falls back to its id. Deduped and
|
|
75
|
+
* sorted for stable output.
|
|
76
|
+
*/
|
|
77
|
+
export function surfaceFeatureGateSettingsKeys(flagIds: readonly string[]): string[] {
|
|
78
|
+
const keys = new Set<string>();
|
|
79
|
+
for (const flagId of flagIds) keys.add(getFeatureSetting(flagId)?.enablement.key ?? flagId);
|
|
80
|
+
return [...keys].sort((left, right) => left.localeCompare(right));
|
|
52
81
|
}
|
|
53
82
|
|
|
54
|
-
export function getMissingSurfaceFeatureFlags(config: Pick<ConfigManager, '
|
|
83
|
+
export function getMissingSurfaceFeatureFlags(config: Pick<ConfigManager, 'get'>, surfaceId: string): readonly string[] {
|
|
55
84
|
const required = surfaceId === 'web'
|
|
56
85
|
? getServerSurfaceFeatureFlags({ web: true })
|
|
57
86
|
: getServerSurfaceFeatureFlags({ externalSurfaces: [surfaceId] });
|
|
58
87
|
return required.filter((flagId) => !isFeatureFlagEnabled(config, flagId));
|
|
59
88
|
}
|
|
60
89
|
|
|
90
|
+
/** Switch each capability on by writing its real enablement settings key. */
|
|
61
91
|
export function enableFeatureFlags(config: Pick<ConfigManager, 'setDynamic'>, flagIds: readonly string[]): void {
|
|
62
92
|
for (const flagId of flagIds) {
|
|
63
|
-
|
|
93
|
+
const write = featureEnablementWrite(flagId, true);
|
|
94
|
+
if (write) config.setDynamic(write.key, write.value);
|
|
64
95
|
}
|
|
65
96
|
}
|
|
@@ -45,7 +45,7 @@ export type TuiTerminalOutputGuardOptions = {
|
|
|
45
45
|
* writes captured this session, so an honest quiet counter (e.g. /debug) can
|
|
46
46
|
* refresh. The per-write detail is already recorded to the activity log via
|
|
47
47
|
* logger.warn — this callback intentionally does NOT push transcript lines.
|
|
48
|
-
* (
|
|
48
|
+
* (item 1a.)
|
|
49
49
|
*/
|
|
50
50
|
readonly onCapture?: (total: number) => void;
|
|
51
51
|
};
|
|
@@ -224,7 +224,7 @@ export function installTuiTerminalOutputGuard(options: TuiTerminalOutputGuardOpt
|
|
|
224
224
|
onIntercept: () => {
|
|
225
225
|
// Each intercept is already logged (logger.warn in record()). Here we only
|
|
226
226
|
// maintain a cumulative counter and, rate-limited, refresh a quiet counter
|
|
227
|
-
// surface — no repeated transcript lines. (
|
|
227
|
+
// surface — no repeated transcript lines. (item 1a.)
|
|
228
228
|
totalInterceptedWrites++;
|
|
229
229
|
const now = Date.now();
|
|
230
230
|
if (now - lastNoticeAt < 5_000) return;
|
|
@@ -137,13 +137,21 @@ export class WorkspaceRegistrationManager {
|
|
|
137
137
|
* Register the current working directory at its resolved project root. The
|
|
138
138
|
* store refuses broad roots (WorkspaceRegistrationError) — we surface that
|
|
139
139
|
* honestly rather than record a phantom registration.
|
|
140
|
+
*
|
|
141
|
+
* `origin` stamps which surface wrote the record (honest provenance). This
|
|
142
|
+
* NEVER passes `checkpointEligible`: absent means false, so a TUI self-record
|
|
143
|
+
* can never widen the checkpoint-owning consumer's boundary — only that
|
|
144
|
+
* consumer stamps its own roots eligible on boot.
|
|
140
145
|
*/
|
|
141
|
-
async register(label?: string): Promise<
|
|
146
|
+
async register(label?: string, origin?: string): Promise<
|
|
142
147
|
| { readonly registered: true; readonly result: RegisterWorkspaceResult }
|
|
143
148
|
| { readonly registered: false; readonly refusedReason: string }
|
|
144
149
|
> {
|
|
150
|
+
const opts = label || origin
|
|
151
|
+
? { ...(label ? { label } : {}), ...(origin ? { origin } : {}) }
|
|
152
|
+
: undefined;
|
|
145
153
|
try {
|
|
146
|
-
const result = await this.store.add(this.workingDirectory,
|
|
154
|
+
const result = await this.store.add(this.workingDirectory, opts);
|
|
147
155
|
return { registered: true, result };
|
|
148
156
|
} catch (error) {
|
|
149
157
|
if (error instanceof WorkspaceRegistrationError) {
|