@pellux/goodvibes-agent 0.1.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/.goodvibes/GOODVIBES.md +35 -0
- package/.goodvibes/agents/reviewer.md +48 -0
- package/.goodvibes/skills/add-provider/SKILL.md +199 -0
- package/CHANGELOG.md +25 -0
- package/README.md +74 -0
- package/bin/goodvibes-agent.ts +2 -0
- package/docs/README.md +23 -0
- package/docs/deployment-and-services.md +57 -0
- package/docs/getting-started.md +53 -0
- package/docs/release-and-publishing.md +46 -0
- package/package.json +134 -0
- package/scripts/check-bun.sh +20 -0
- package/src/audio/player.ts +156 -0
- package/src/audio/spoken-turn-controller.ts +203 -0
- package/src/audio/spoken-turn-model-routing.ts +117 -0
- package/src/audio/spoken-turn-wiring.ts +44 -0
- package/src/audio/text-chunker.ts +110 -0
- package/src/cli/bundle-command.ts +227 -0
- package/src/cli/completion.ts +90 -0
- package/src/cli/config-overrides.ts +159 -0
- package/src/cli/endpoints.ts +63 -0
- package/src/cli/entrypoint.ts +172 -0
- package/src/cli/help.ts +299 -0
- package/src/cli/index.ts +11 -0
- package/src/cli/management-commands.ts +426 -0
- package/src/cli/management.ts +744 -0
- package/src/cli/network-posture.ts +46 -0
- package/src/cli/package-verification.ts +123 -0
- package/src/cli/parser.ts +369 -0
- package/src/cli/provider-auth-routes.ts +22 -0
- package/src/cli/provider-classification.ts +107 -0
- package/src/cli/redaction.ts +105 -0
- package/src/cli/service-command.ts +26 -0
- package/src/cli/service-posture.ts +482 -0
- package/src/cli/status.ts +383 -0
- package/src/cli/surface-command.ts +247 -0
- package/src/cli/tui-startup.ts +32 -0
- package/src/cli/types.ts +69 -0
- package/src/cli-flags.ts +21 -0
- package/src/config/goodvibes-home-audit.ts +465 -0
- package/src/config/index.ts +57 -0
- package/src/config/provider-model.ts +23 -0
- package/src/config/secret-config.ts +119 -0
- package/src/config/secrets.ts +71 -0
- package/src/config/surface.ts +1 -0
- package/src/core/composer-state.ts +61 -0
- package/src/core/conversation-rendering.ts +359 -0
- package/src/core/conversation.ts +551 -0
- package/src/core/history.ts +45 -0
- package/src/core/orchestrator.ts +7 -0
- package/src/core/system-message-router.ts +171 -0
- package/src/daemon/cli.ts +55 -0
- package/src/daemon/safe-serve.ts +61 -0
- package/src/input/agent-workspace.ts +428 -0
- package/src/input/autocomplete.ts +96 -0
- package/src/input/bookmark-modal.ts +115 -0
- package/src/input/command-args-hint.ts +36 -0
- package/src/input/command-registry.ts +329 -0
- package/src/input/commands/agent-externalized-tui.ts +73 -0
- package/src/input/commands/agent-workspace-runtime.ts +17 -0
- package/src/input/commands/branch-runtime.ts +72 -0
- package/src/input/commands/cloudflare-runtime.ts +370 -0
- package/src/input/commands/config.ts +18 -0
- package/src/input/commands/control-room-runtime.ts +255 -0
- package/src/input/commands/conversation-runtime.ts +207 -0
- package/src/input/commands/discovery-runtime.ts +52 -0
- package/src/input/commands/eval.ts +204 -0
- package/src/input/commands/experience-runtime.ts +278 -0
- package/src/input/commands/guidance-runtime.ts +106 -0
- package/src/input/commands/health-runtime.ts +434 -0
- package/src/input/commands/hooks-runtime.ts +148 -0
- package/src/input/commands/incident-runtime.ts +95 -0
- package/src/input/commands/integration-runtime.ts +394 -0
- package/src/input/commands/intelligence-runtime.ts +223 -0
- package/src/input/commands/knowledge.ts +531 -0
- package/src/input/commands/local-auth-runtime.ts +105 -0
- package/src/input/commands/local-provider-runtime.ts +170 -0
- package/src/input/commands/local-runtime.ts +392 -0
- package/src/input/commands/local-setup-review.ts +199 -0
- package/src/input/commands/local-setup-transfer.ts +135 -0
- package/src/input/commands/local-setup.ts +282 -0
- package/src/input/commands/managed-runtime.ts +209 -0
- package/src/input/commands/marketplace-runtime.ts +290 -0
- package/src/input/commands/mcp-runtime.ts +432 -0
- package/src/input/commands/memory-product-runtime.ts +111 -0
- package/src/input/commands/memory.ts +151 -0
- package/src/input/commands/notify-runtime.ts +83 -0
- package/src/input/commands/onboarding-runtime.ts +14 -0
- package/src/input/commands/operator-panel-runtime.ts +146 -0
- package/src/input/commands/operator-runtime.ts +392 -0
- package/src/input/commands/planning-runtime.ts +205 -0
- package/src/input/commands/platform-access-runtime.ts +422 -0
- package/src/input/commands/platform-services-runtime.ts +246 -0
- package/src/input/commands/policy-dispatch.ts +339 -0
- package/src/input/commands/policy.ts +17 -0
- package/src/input/commands/product-runtime.ts +351 -0
- package/src/input/commands/profile-sync-runtime.ts +99 -0
- package/src/input/commands/provider-accounts-runtime.ts +113 -0
- package/src/input/commands/provider.ts +363 -0
- package/src/input/commands/qrcode-runtime.ts +20 -0
- package/src/input/commands/quit-shared.ts +162 -0
- package/src/input/commands/recall-bundle.ts +132 -0
- package/src/input/commands/recall-capture.ts +152 -0
- package/src/input/commands/recall-query.ts +229 -0
- package/src/input/commands/recall-review.ts +98 -0
- package/src/input/commands/recall-shared.ts +22 -0
- package/src/input/commands/remote-runtime-pool.ts +106 -0
- package/src/input/commands/remote-runtime-setup.ts +199 -0
- package/src/input/commands/remote-runtime.ts +431 -0
- package/src/input/commands/replay-runtime.ts +18 -0
- package/src/input/commands/runtime-services.ts +291 -0
- package/src/input/commands/schedule-runtime.ts +91 -0
- package/src/input/commands/services-runtime.ts +209 -0
- package/src/input/commands/session-content.ts +408 -0
- package/src/input/commands/session-workflow.ts +464 -0
- package/src/input/commands/session.ts +375 -0
- package/src/input/commands/settings-sync-runtime.ts +174 -0
- package/src/input/commands/share-runtime.ts +119 -0
- package/src/input/commands/shell-core.ts +307 -0
- package/src/input/commands/skills-runtime.ts +221 -0
- package/src/input/commands/subscription-runtime.ts +434 -0
- package/src/input/commands/tasks-runtime.ts +230 -0
- package/src/input/commands/teamwork-runtime.ts +339 -0
- package/src/input/commands/teleport-runtime.ts +57 -0
- package/src/input/commands/tts-runtime.ts +29 -0
- package/src/input/commands/work-plan-runtime.ts +169 -0
- package/src/input/commands.ts +131 -0
- package/src/input/feed-context-factory.ts +254 -0
- package/src/input/file-picker.ts +192 -0
- package/src/input/handler-command-route.ts +180 -0
- package/src/input/handler-content-actions.ts +497 -0
- package/src/input/handler-feed-routes.ts +648 -0
- package/src/input/handler-feed.ts +452 -0
- package/src/input/handler-interactions.ts +281 -0
- package/src/input/handler-modal-routes.ts +418 -0
- package/src/input/handler-modal-stack.ts +263 -0
- package/src/input/handler-modal-token-routes.ts +329 -0
- package/src/input/handler-onboarding-cloudflare.ts +391 -0
- package/src/input/handler-onboarding.ts +620 -0
- package/src/input/handler-picker-routes.ts +472 -0
- package/src/input/handler-prompt-buffer.ts +320 -0
- package/src/input/handler-shortcuts.ts +213 -0
- package/src/input/handler-ui-state.ts +372 -0
- package/src/input/handler.ts +729 -0
- package/src/input/input-history.ts +297 -0
- package/src/input/keybindings.ts +292 -0
- package/src/input/mcp-workspace.ts +554 -0
- package/src/input/model-picker-provider-filter.ts +28 -0
- package/src/input/model-picker-types.ts +137 -0
- package/src/input/model-picker.ts +797 -0
- package/src/input/onboarding/handler-onboarding-routes.ts +125 -0
- package/src/input/onboarding/onboarding-runtime-status.ts +87 -0
- package/src/input/onboarding/onboarding-wizard-apply.ts +277 -0
- package/src/input/onboarding/onboarding-wizard-cloudflare-step.ts +494 -0
- package/src/input/onboarding/onboarding-wizard-cloudflare.ts +204 -0
- package/src/input/onboarding/onboarding-wizard-constants.ts +158 -0
- package/src/input/onboarding/onboarding-wizard-external-surface-extra-specs.ts +130 -0
- package/src/input/onboarding/onboarding-wizard-external-surfaces.ts +762 -0
- package/src/input/onboarding/onboarding-wizard-helpers.ts +167 -0
- package/src/input/onboarding/onboarding-wizard-rules.ts +256 -0
- package/src/input/onboarding/onboarding-wizard-state.ts +365 -0
- package/src/input/onboarding/onboarding-wizard-steps.ts +798 -0
- package/src/input/onboarding/onboarding-wizard-types.ts +195 -0
- package/src/input/onboarding/onboarding-wizard.ts +711 -0
- package/src/input/panel-integration-actions.ts +78 -0
- package/src/input/profile-picker-modal.ts +222 -0
- package/src/input/search.ts +100 -0
- package/src/input/selection-modal.ts +163 -0
- package/src/input/selection.ts +135 -0
- package/src/input/session-picker-modal.ts +136 -0
- package/src/input/settings-modal-behavior.ts +37 -0
- package/src/input/settings-modal-secrets.ts +41 -0
- package/src/input/settings-modal-subscriptions.ts +95 -0
- package/src/input/settings-modal-types.ts +91 -0
- package/src/input/settings-modal.ts +793 -0
- package/src/input/submission-intent.ts +17 -0
- package/src/input/submission-router.ts +59 -0
- package/src/input/tts-settings-actions.ts +100 -0
- package/src/main.ts +792 -0
- package/src/mcp/runtime-reload.ts +81 -0
- package/src/panels/agent-inspector-panel.ts +521 -0
- package/src/panels/agent-inspector-shared.ts +94 -0
- package/src/panels/agent-logs-panel.ts +559 -0
- package/src/panels/agent-logs-shared.ts +129 -0
- package/src/panels/approval-panel.ts +150 -0
- package/src/panels/automation-control-panel.ts +212 -0
- package/src/panels/base-panel.ts +254 -0
- package/src/panels/builtin/agent.ts +117 -0
- package/src/panels/builtin/development.ts +31 -0
- package/src/panels/builtin/knowledge.ts +26 -0
- package/src/panels/builtin/operations.ts +349 -0
- package/src/panels/builtin/session.ts +129 -0
- package/src/panels/builtin/shared.ts +274 -0
- package/src/panels/builtin-panels.ts +23 -0
- package/src/panels/cockpit-panel.ts +183 -0
- package/src/panels/communication-panel.ts +153 -0
- package/src/panels/confirm-state.ts +61 -0
- package/src/panels/context-visualizer-panel.ts +204 -0
- package/src/panels/control-plane-panel.ts +211 -0
- package/src/panels/cost-tracker-panel.ts +444 -0
- package/src/panels/debug-panel.ts +432 -0
- package/src/panels/diff-panel.ts +520 -0
- package/src/panels/docs-panel.ts +283 -0
- package/src/panels/eval-panel.ts +399 -0
- package/src/panels/file-explorer-panel.ts +584 -0
- package/src/panels/file-preview-panel.ts +434 -0
- package/src/panels/forensics-panel.ts +364 -0
- package/src/panels/git-panel.ts +638 -0
- package/src/panels/hooks-panel.ts +239 -0
- package/src/panels/incident-review-panel.ts +197 -0
- package/src/panels/index.ts +46 -0
- package/src/panels/intelligence-panel.ts +176 -0
- package/src/panels/knowledge-panel.ts +345 -0
- package/src/panels/local-auth-panel.ts +130 -0
- package/src/panels/marketplace-panel.ts +212 -0
- package/src/panels/memory-panel.ts +225 -0
- package/src/panels/ops-control-panel.ts +150 -0
- package/src/panels/ops-strategy-panel.ts +235 -0
- package/src/panels/orchestration-panel.ts +273 -0
- package/src/panels/panel-list-panel.ts +509 -0
- package/src/panels/panel-manager.ts +570 -0
- package/src/panels/panel-picker.ts +106 -0
- package/src/panels/plan-dashboard-panel.ts +274 -0
- package/src/panels/plugins-panel.ts +178 -0
- package/src/panels/policy-panel.ts +308 -0
- package/src/panels/polish.ts +717 -0
- package/src/panels/project-planning-panel.ts +711 -0
- package/src/panels/provider-account-snapshot.ts +259 -0
- package/src/panels/provider-accounts-panel.ts +218 -0
- package/src/panels/provider-health-domains.ts +215 -0
- package/src/panels/provider-health-panel.ts +727 -0
- package/src/panels/provider-health-tracker.ts +115 -0
- package/src/panels/provider-stats-panel.ts +366 -0
- package/src/panels/qr-panel.ts +182 -0
- package/src/panels/remote-panel.ts +449 -0
- package/src/panels/routes-panel.ts +178 -0
- package/src/panels/sandbox-panel.ts +283 -0
- package/src/panels/schedule-panel.ts +329 -0
- package/src/panels/scrollable-list-panel.ts +491 -0
- package/src/panels/search-focus.ts +32 -0
- package/src/panels/security-panel.ts +295 -0
- package/src/panels/services-panel.ts +231 -0
- package/src/panels/session-browser-panel.ts +400 -0
- package/src/panels/session-maintenance.ts +125 -0
- package/src/panels/settings-sync-panel.ts +120 -0
- package/src/panels/skills-panel.ts +431 -0
- package/src/panels/subscription-panel.ts +263 -0
- package/src/panels/symbol-outline-panel.ts +486 -0
- package/src/panels/system-messages-panel.ts +230 -0
- package/src/panels/tasks-panel.ts +399 -0
- package/src/panels/thinking-panel.ts +304 -0
- package/src/panels/token-budget-panel.ts +475 -0
- package/src/panels/tool-inspector-panel.ts +429 -0
- package/src/panels/types.ts +54 -0
- package/src/panels/watchers-panel.ts +193 -0
- package/src/panels/work-plan-panel.ts +175 -0
- package/src/panels/worktree-panel.ts +182 -0
- package/src/panels/wrfc-panel.ts +609 -0
- package/src/permissions/prompt.ts +165 -0
- package/src/planning/project-planning-coordinator.ts +543 -0
- package/src/plugins/loader.ts +15 -0
- package/src/renderer/agent-detail-modal.ts +331 -0
- package/src/renderer/agent-workspace.ts +238 -0
- package/src/renderer/ansi-sanitize.ts +76 -0
- package/src/renderer/autocomplete-overlay.ts +154 -0
- package/src/renderer/block-actions.ts +76 -0
- package/src/renderer/bookmark-modal.ts +101 -0
- package/src/renderer/bottom-bar.ts +58 -0
- package/src/renderer/buffer.ts +113 -0
- package/src/renderer/code-block.ts +373 -0
- package/src/renderer/compositor.ts +283 -0
- package/src/renderer/context-inspector.ts +219 -0
- package/src/renderer/conversation-layout.ts +67 -0
- package/src/renderer/conversation-overlays.ts +140 -0
- package/src/renderer/conversation-surface.ts +260 -0
- package/src/renderer/diff-view.ts +132 -0
- package/src/renderer/diff.ts +130 -0
- package/src/renderer/file-picker-overlay.ts +101 -0
- package/src/renderer/file-tree.ts +153 -0
- package/src/renderer/fullscreen-primitives.ts +130 -0
- package/src/renderer/fullscreen-workspace.ts +199 -0
- package/src/renderer/git-status.ts +89 -0
- package/src/renderer/help-overlay.ts +267 -0
- package/src/renderer/history-search-overlay.ts +73 -0
- package/src/renderer/layout-engine.ts +97 -0
- package/src/renderer/layout.ts +32 -0
- package/src/renderer/live-tail-modal.ts +156 -0
- package/src/renderer/markdown.ts +635 -0
- package/src/renderer/mcp-workspace.ts +237 -0
- package/src/renderer/modal-factory.ts +467 -0
- package/src/renderer/modal-utils.ts +24 -0
- package/src/renderer/model-picker-overlay.ts +473 -0
- package/src/renderer/model-workspace.ts +488 -0
- package/src/renderer/onboarding/onboarding-wizard.ts +615 -0
- package/src/renderer/overlay-box.ts +146 -0
- package/src/renderer/overlay-viewport.ts +104 -0
- package/src/renderer/panel-composite.ts +158 -0
- package/src/renderer/panel-picker-overlay.ts +202 -0
- package/src/renderer/panel-tab-bar.ts +69 -0
- package/src/renderer/panel-workspace-bar.ts +42 -0
- package/src/renderer/process-indicator.ts +96 -0
- package/src/renderer/process-modal.ts +656 -0
- package/src/renderer/process-summary.ts +67 -0
- package/src/renderer/profile-picker-modal.ts +129 -0
- package/src/renderer/progress.ts +98 -0
- package/src/renderer/qr-renderer.ts +120 -0
- package/src/renderer/search-overlay.ts +54 -0
- package/src/renderer/selection-modal-overlay.ts +214 -0
- package/src/renderer/semantic-diff.ts +369 -0
- package/src/renderer/session-picker-modal.ts +127 -0
- package/src/renderer/settings-modal-helpers.ts +193 -0
- package/src/renderer/settings-modal.ts +537 -0
- package/src/renderer/shell-surface.ts +88 -0
- package/src/renderer/status-glyphs.ts +21 -0
- package/src/renderer/status-token.ts +67 -0
- package/src/renderer/surface-layout.ts +101 -0
- package/src/renderer/syntax-highlighter.ts +542 -0
- package/src/renderer/system-message.ts +83 -0
- package/src/renderer/tab-strip.ts +108 -0
- package/src/renderer/text-layout.ts +31 -0
- package/src/renderer/thinking.ts +17 -0
- package/src/renderer/tool-call.ts +234 -0
- package/src/renderer/ui-factory.ts +524 -0
- package/src/renderer/ui-primitives.ts +96 -0
- package/src/runtime/bootstrap-command-context.ts +278 -0
- package/src/runtime/bootstrap-command-parts.ts +386 -0
- package/src/runtime/bootstrap-core.ts +540 -0
- package/src/runtime/bootstrap-hook-bridge.ts +112 -0
- package/src/runtime/bootstrap-shell.ts +283 -0
- package/src/runtime/bootstrap.ts +575 -0
- package/src/runtime/cloudflare-control-plane.ts +349 -0
- package/src/runtime/context.ts +142 -0
- package/src/runtime/diagnostics/panels/index.ts +24 -0
- package/src/runtime/diagnostics/panels/ops.ts +156 -0
- package/src/runtime/diagnostics/panels/panel-resources.ts +118 -0
- package/src/runtime/diagnostics/panels/policy.ts +177 -0
- package/src/runtime/index.ts +662 -0
- package/src/runtime/onboarding/apply.ts +642 -0
- package/src/runtime/onboarding/derivation.ts +534 -0
- package/src/runtime/onboarding/index.ts +7 -0
- package/src/runtime/onboarding/markers.ts +148 -0
- package/src/runtime/onboarding/snapshot.ts +406 -0
- package/src/runtime/onboarding/state.ts +141 -0
- package/src/runtime/onboarding/types.ts +404 -0
- package/src/runtime/onboarding/verify.ts +171 -0
- package/src/runtime/operator-token-cleanup.ts +27 -0
- package/src/runtime/perf/panel-contracts.ts +32 -0
- package/src/runtime/perf/panel-health-monitor.ts +18 -0
- package/src/runtime/sandbox-public-gaps.ts +358 -0
- package/src/runtime/services.ts +670 -0
- package/src/runtime/store/domains/domain-read-matrix.ts +15 -0
- package/src/runtime/store/domains/index.ts +222 -0
- package/src/runtime/store/domains/panels.ts +117 -0
- package/src/runtime/store/domains/ui-perf.ts +103 -0
- package/src/runtime/store/index.ts +305 -0
- package/src/runtime/store/selectors/index.ts +359 -0
- package/src/runtime/store/state.ts +145 -0
- package/src/runtime/surface-feature-flags.ts +65 -0
- package/src/runtime/terminal-output-guard.ts +228 -0
- package/src/runtime/ui/index.ts +39 -0
- package/src/runtime/ui/model-picker/data-provider.ts +182 -0
- package/src/runtime/ui/model-picker/health-enrichment.ts +228 -0
- package/src/runtime/ui/model-picker/index.ts +59 -0
- package/src/runtime/ui/model-picker/types.ts +149 -0
- package/src/runtime/ui/provider-health/data-provider.ts +244 -0
- package/src/runtime/ui/provider-health/fallback-visualizer.ts +71 -0
- package/src/runtime/ui/provider-health/index.ts +46 -0
- package/src/runtime/ui/provider-health/types.ts +146 -0
- package/src/runtime/ui-events.ts +1 -0
- package/src/runtime/ui-read-model-helpers.ts +1 -0
- package/src/runtime/ui-read-models-observability-maintenance.ts +1 -0
- package/src/runtime/ui-read-models-observability-options.ts +1 -0
- package/src/runtime/ui-read-models-observability-remote.ts +1 -0
- package/src/runtime/ui-read-models-observability-security.ts +1 -0
- package/src/runtime/ui-read-models-observability-system.ts +1 -0
- package/src/runtime/ui-read-models-observability.ts +1 -0
- package/src/runtime/ui-read-models.ts +61 -0
- package/src/runtime/ui-service-queries.ts +1 -0
- package/src/runtime/ui-services.ts +190 -0
- package/src/scripts/process-messages.ts +42 -0
- package/src/shell/blocking-input.ts +98 -0
- package/src/shell/service-settings-sync.ts +273 -0
- package/src/shell/ui-openers.ts +352 -0
- package/src/tools/index.ts +1 -0
- package/src/tools/wrfc-agent-guard.ts +49 -0
- package/src/types/grid.ts +48 -0
- package/src/types/sql-js.d.ts +15 -0
- package/src/utils/clipboard.ts +22 -0
- package/src/utils/splash-lines.ts +46 -0
- package/src/utils/terminal-width.ts +185 -0
- package/src/verification/live-verifier.ts +430 -0
- package/src/verification/verification-ledger.ts +242 -0
- package/src/version.ts +17 -0
- package/src/widget/index.ts +2 -0
- package/src/widget/types.ts +9 -0
- package/src/widget/widget.ts +8 -0
- package/src/work-plans/work-plan-store.ts +374 -0
- package/tsconfig.json +18 -0
|
@@ -0,0 +1,575 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Bootstrap composition root for GoodVibes Agent.
|
|
3
|
+
*
|
|
4
|
+
* Initializes all runtime subsystems in dependency order and returns a
|
|
5
|
+
* RuntimeContext that main.ts uses to drive the render loop and terminal I/O.
|
|
6
|
+
*
|
|
7
|
+
* Separation of concerns:
|
|
8
|
+
* - bootstrap.ts: initialization, event wiring, manager setup
|
|
9
|
+
* - main.ts: terminal setup, render loop, stdin/stdout handlers
|
|
10
|
+
* - lifecycle.ts: save/shutdown helpers
|
|
11
|
+
*/
|
|
12
|
+
import { Orchestrator, type OrchestratorUserInputOptions } from '../core/orchestrator.ts';
|
|
13
|
+
import { AcpManager } from '@pellux/goodvibes-sdk/platform/acp';
|
|
14
|
+
import { getTierPromptSupplement, getTierForContextWindow } from '@pellux/goodvibes-sdk/platform/providers';
|
|
15
|
+
import { logger } from '@pellux/goodvibes-sdk/platform/utils';
|
|
16
|
+
import type { PermissionRequestHandler } from '@pellux/goodvibes-sdk/platform/permissions';
|
|
17
|
+
import type { CommandContext } from '../input/command-registry.ts';
|
|
18
|
+
import type { InputHistory } from '../input/input-history.ts';
|
|
19
|
+
import type { GitStatusProvider } from '../renderer/git-status.ts';
|
|
20
|
+
import type { GitHeaderInfo } from '../renderer/git-status.ts';
|
|
21
|
+
import type { SelectionManager } from '../input/selection.ts';
|
|
22
|
+
import type { Compositor } from '../renderer/compositor.ts';
|
|
23
|
+
|
|
24
|
+
import type { RuntimeContext, BootstrapOptions } from './context.ts';
|
|
25
|
+
import { shutdownRuntime, fireSessionStart, saveSession } from '@/runtime/index.ts';
|
|
26
|
+
import { createTaskManager } from '@/runtime/index.ts';
|
|
27
|
+
import { OpsControlPlane } from '@/runtime/index.ts';
|
|
28
|
+
import { AcpTaskAdapter } from '@/runtime/index.ts';
|
|
29
|
+
import type { SystemMessageRouter } from '../core/system-message-router.ts';
|
|
30
|
+
import { emitSessionReady, emitSessionStarted } from '@/runtime/index.ts';
|
|
31
|
+
import {
|
|
32
|
+
loadLastConversation,
|
|
33
|
+
writeLastSessionPointer,
|
|
34
|
+
} from '@/runtime/index.ts';
|
|
35
|
+
import { scheduleBackgroundMcpDiscovery, startBackgroundProviderRegistration } from '@/runtime/index.ts';
|
|
36
|
+
import { restoreSavedModel } from '@/runtime/index.ts';
|
|
37
|
+
import type { ExternalServicesHandle, HostServiceStatus } from '@/runtime/index.ts';
|
|
38
|
+
import type { UiRuntimeServices } from './ui-services.ts';
|
|
39
|
+
import { createDeferredStartupCoordinator } from '@/runtime/index.ts';
|
|
40
|
+
import { initializeBootstrapCore } from './bootstrap-core.ts';
|
|
41
|
+
import { createBootstrapShell } from './bootstrap-shell.ts';
|
|
42
|
+
import { summarizeError } from '@pellux/goodvibes-sdk/platform/utils';
|
|
43
|
+
import { startMcpConfigAutoReload } from '../mcp/runtime-reload.ts';
|
|
44
|
+
import { GOODVIBES_AGENT_SURFACE_ROOT } from '../config/surface.ts';
|
|
45
|
+
|
|
46
|
+
const GOODVIBES_AGENT_OPERATOR_POLICY = [
|
|
47
|
+
'## GoodVibes Agent Operator Policy',
|
|
48
|
+
'- Default to serial, proactive assistant work in the main conversation. Answer, inspect, summarize, remember useful non-secret facts, configure local Agent state, use read-only daemon/operator routes, and take safe non-destructive actions without spawning local agents or WRFC.',
|
|
49
|
+
'- GoodVibes Agent connects to an externally managed GoodVibes daemon. Do not start, stop, restart, install, expose, or mutate daemon/listener/control-plane surface posture from Agent runtime.',
|
|
50
|
+
'- WRFC is never the default Agent reasoning path. Do not create local WRFC chains for planning, research, operations, knowledge, memory, configuration, approvals, automation observability, or ordinary assistant work.',
|
|
51
|
+
'- GoodVibes Agent is not the coding TUI. Do not use the `agent` tool to spawn local Engineer, Reviewer, Tester, Verifier, or batch-spawn roots from Agent.',
|
|
52
|
+
'- When the user explicitly asks to build, implement, fix, patch, or review code, preserve the full original user ask and delegate one build request to GoodVibes TUI through the public shared-session/build-delegation contract. Include clear executionIntent and request WRFC only for explicit build/fix/review work or when the user explicitly asks for WRFC/agent review.',
|
|
53
|
+
'- Do not narrow explicit build/fix/review requests into design-only, read-only, or no-write work unless the user explicitly requested that limitation. TUI owns file edits, git/worktree work, sandbox/QEMU UX, and any WRFC owner chain.',
|
|
54
|
+
'- If a stable public delegation route is unavailable, say that the task needs GoodVibes TUI delegation and report the missing route instead of pretending to implement it locally or spawning sibling local agents.',
|
|
55
|
+
].join('\n');
|
|
56
|
+
|
|
57
|
+
function joinPromptParts(...parts: Array<string | null | undefined>): string {
|
|
58
|
+
return parts.map((part) => part?.trim()).filter((part): part is string => Boolean(part)).join('\n\n');
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
// ── Bootstrap context type ──────────────────────────────────────────────────
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* The fully-initialized context returned by bootstrapRuntime().
|
|
65
|
+
*
|
|
66
|
+
* A typed superset of RuntimeContext that exposes the additional fields required
|
|
67
|
+
* by main.ts (UI-layer objects that do not belong in the shared RuntimeContext
|
|
68
|
+
* interface, since they are not needed by anything else).
|
|
69
|
+
*/
|
|
70
|
+
export type BootstrapContext = RuntimeContext & {
|
|
71
|
+
/** Compositor handles double-buffered terminal output. */
|
|
72
|
+
compositor: Compositor;
|
|
73
|
+
/** Manages text selection state. */
|
|
74
|
+
selection: SelectionManager;
|
|
75
|
+
/** Context object passed to slash-command handlers. */
|
|
76
|
+
commandContext: CommandContext;
|
|
77
|
+
/** Shell-facing read models, events, and narrow runtime services. */
|
|
78
|
+
uiServices: UiRuntimeServices;
|
|
79
|
+
/** Persists and navigates input history across sessions. */
|
|
80
|
+
inputHistory: InputHistory;
|
|
81
|
+
/** Provides git branch/dirty state for the header. */
|
|
82
|
+
gitStatusProvider: GitStatusProvider;
|
|
83
|
+
/** Mutable ref so async git refreshes propagate without closure capture issues. */
|
|
84
|
+
lastGitInfoRef: { value: GitHeaderInfo | undefined };
|
|
85
|
+
/** Unsubscribe functions owned by bootstrap (cleared on shutdown). */
|
|
86
|
+
bootstrapUnsubs: Array<() => void>;
|
|
87
|
+
/** Ref holding the periodic agent-status interval (use ref — not local var — to keep shutdown in sync). */
|
|
88
|
+
agentStatusIntervalRef: { value: ReturnType<typeof setInterval> | null };
|
|
89
|
+
/** Mutable refs for viewport/scroll/render functions; main.ts patches these after constructing UI state. */
|
|
90
|
+
orchestratorRefs: { getViewportHeight: () => number; scrollToEnd: (vHeight: number) => void; requestRender: () => void };
|
|
91
|
+
/** Patch the bootstrap-owned render bridge after main.ts constructs the real render loop. */
|
|
92
|
+
setRenderRequest: (fn: () => void) => void;
|
|
93
|
+
/** Shell-owned permission prompt bridge that main.ts patches after UI setup. */
|
|
94
|
+
permissionPromptRef: { requestPermission: PermissionRequestHandler };
|
|
95
|
+
/** Load the most recently saved conversation from disk. */
|
|
96
|
+
loadLastConversation: () => { messages: Array<Record<string, unknown>> } | null;
|
|
97
|
+
/** Write the last-session pointer file (used after session resume). */
|
|
98
|
+
_writeLastSessionPointer: (sessionId: string) => void;
|
|
99
|
+
/** Save a conversation snapshot to disk. */
|
|
100
|
+
_saveSession: typeof saveSession;
|
|
101
|
+
/** Retrieve pinned model IDs for the model picker. */
|
|
102
|
+
_getPinned: () => Promise<string[]>;
|
|
103
|
+
/** Retrieve configured provider IDs for the model picker. */
|
|
104
|
+
_getConfiguredProviderIds: () => string[];
|
|
105
|
+
/** Command registry used by InputHandler. main.ts needs this to wire input. */
|
|
106
|
+
commandRegistry: import('../input/command-registry.ts').CommandRegistry;
|
|
107
|
+
/**
|
|
108
|
+
* System message router instantiated at startup, wired to conversation and panel manager.
|
|
109
|
+
*
|
|
110
|
+
* @remarks
|
|
111
|
+
* Route operational messages through this rather than calling
|
|
112
|
+
* conversation.addSystemMessage() directly so that low-priority messages
|
|
113
|
+
* stay out of the main conversation and go to the SystemMessagesPanel instead.
|
|
114
|
+
*/
|
|
115
|
+
systemMessageRouter: SystemMessageRouter;
|
|
116
|
+
};
|
|
117
|
+
|
|
118
|
+
// ── Bootstrap function ────────────────────────────────────────────────────
|
|
119
|
+
|
|
120
|
+
/**
|
|
121
|
+
* Initialize all runtime subsystems and return a fully-wired RuntimeContext.
|
|
122
|
+
*
|
|
123
|
+
* main.ts calls this once, then uses the returned context to:
|
|
124
|
+
* - Run the render loop
|
|
125
|
+
* - Handle stdin/stdout events
|
|
126
|
+
* - Manage terminal lifecycle (alt-screen, raw mode, resize)
|
|
127
|
+
*
|
|
128
|
+
* Phase summary:
|
|
129
|
+
* 1. Config, caches, keybindings
|
|
130
|
+
* 2. Runtime event bus, conversation, compositor, selection
|
|
131
|
+
* 3. Tool registry + agent wiring
|
|
132
|
+
* 4. Runtime bus subscriptions (WRFC, subagent, hook bridge)
|
|
133
|
+
* 5. Providers, webhooks, PermissionManager, HookDispatcher
|
|
134
|
+
* 6. Orchestrator + AcpManager
|
|
135
|
+
* 7. MCP auto-connect + workspace/panel manager
|
|
136
|
+
* 8. Command registry + plugin init + CommandContext
|
|
137
|
+
* 9. Input handler wiring
|
|
138
|
+
* 10. Input history, splash options
|
|
139
|
+
* 11. Background: provider auto-registration, persisted providers, scan
|
|
140
|
+
*/
|
|
141
|
+
export async function bootstrapRuntime(
|
|
142
|
+
stdout: NodeJS.WriteStream,
|
|
143
|
+
options: BootstrapOptions,
|
|
144
|
+
): Promise<BootstrapContext> {
|
|
145
|
+
const workingDir = options.workingDir;
|
|
146
|
+
const configManager = options.configManager;
|
|
147
|
+
const controlPlaneRecentEventsRef: {
|
|
148
|
+
value: (limit: number) => readonly import('@pellux/goodvibes-sdk/platform/control-plane').ControlPlaneRecentEvent[];
|
|
149
|
+
} = {
|
|
150
|
+
value: (_limit) => [],
|
|
151
|
+
};
|
|
152
|
+
const {
|
|
153
|
+
userSessionId,
|
|
154
|
+
runtimeBus,
|
|
155
|
+
store,
|
|
156
|
+
services,
|
|
157
|
+
uiServices,
|
|
158
|
+
conversation,
|
|
159
|
+
compositor,
|
|
160
|
+
selection,
|
|
161
|
+
toolRegistry,
|
|
162
|
+
fileCache,
|
|
163
|
+
projectIndex,
|
|
164
|
+
permissionManager,
|
|
165
|
+
forensicsCollector,
|
|
166
|
+
forensicsRegistry,
|
|
167
|
+
runtime,
|
|
168
|
+
bootstrapUnsubs,
|
|
169
|
+
runtimeUnsubs,
|
|
170
|
+
agentStatusIntervalRef,
|
|
171
|
+
permissionPromptRef,
|
|
172
|
+
systemMessageRouterRef,
|
|
173
|
+
conversationFollowUpRef,
|
|
174
|
+
orchestratorHandleUserInputRef,
|
|
175
|
+
requestRender,
|
|
176
|
+
setRenderRequest,
|
|
177
|
+
runtimeSessionIdRef,
|
|
178
|
+
} = await initializeBootstrapCore(stdout, options, (limit) => controlPlaneRecentEventsRef.value(limit));
|
|
179
|
+
const providerRegistry = services.providerRegistry;
|
|
180
|
+
const {
|
|
181
|
+
automationManager,
|
|
182
|
+
hookDispatcher,
|
|
183
|
+
panelManager,
|
|
184
|
+
pluginManager,
|
|
185
|
+
} = services;
|
|
186
|
+
|
|
187
|
+
// ── Phase 6: Orchestrator + AcpManager ───────────────────────────────────
|
|
188
|
+
|
|
189
|
+
// Mutable function refs so main.ts can patch these after constructing the scroll/viewport state.
|
|
190
|
+
// The orchestrator closes over these refs, so patching them in main.ts takes immediate effect.
|
|
191
|
+
const orchestratorRefs = {
|
|
192
|
+
getViewportHeight: (): number => 20,
|
|
193
|
+
scrollToEnd: (_vHeight: number): void => { /* patched by main.ts */ },
|
|
194
|
+
requestRender: (): void => { requestRender(); },
|
|
195
|
+
};
|
|
196
|
+
|
|
197
|
+
const orchestrator = new Orchestrator({
|
|
198
|
+
conversation,
|
|
199
|
+
getViewportHeight: () => orchestratorRefs.getViewportHeight(),
|
|
200
|
+
scrollToEnd: (vHeight: number) => orchestratorRefs.scrollToEnd(vHeight),
|
|
201
|
+
toolRegistry,
|
|
202
|
+
permissionManager,
|
|
203
|
+
getSystemPrompt: () => {
|
|
204
|
+
const currentModel = providerRegistry.getCurrentModel();
|
|
205
|
+
const contextWindow = providerRegistry.getContextWindowForModel(currentModel);
|
|
206
|
+
const tier = getTierForContextWindow(contextWindow);
|
|
207
|
+
const supplement = getTierPromptSupplement(tier);
|
|
208
|
+
return joinPromptParts(runtime.systemPrompt, GOODVIBES_AGENT_OPERATOR_POLICY, supplement);
|
|
209
|
+
},
|
|
210
|
+
hookDispatcher,
|
|
211
|
+
flagManager: services.featureFlags,
|
|
212
|
+
requestRender: () => orchestratorRefs.requestRender(),
|
|
213
|
+
runtimeBus,
|
|
214
|
+
sessionId: runtime.sessionId,
|
|
215
|
+
services: {
|
|
216
|
+
agentManager: services.agentManager,
|
|
217
|
+
wrfcController: services.wrfcController,
|
|
218
|
+
},
|
|
219
|
+
});
|
|
220
|
+
conversationFollowUpRef.value = (item) => orchestrator.enqueueConversationFollowUp(item);
|
|
221
|
+
// Wire orchestratorHandleUserInputRef so COMPANION_MESSAGE_RECEIVED fires a real LLM turn.
|
|
222
|
+
orchestratorHandleUserInputRef.value = (text: string, options?: OrchestratorUserInputOptions) => {
|
|
223
|
+
orchestrator.handleUserInput(text, undefined, options).catch((err: unknown) => {
|
|
224
|
+
logger.debug('companion handleUserInput safety catch', { error: String(err) });
|
|
225
|
+
});
|
|
226
|
+
};
|
|
227
|
+
orchestrator.setCoreServices({
|
|
228
|
+
configManager,
|
|
229
|
+
providerRegistry,
|
|
230
|
+
cacheHitTracker: services.cacheHitTracker,
|
|
231
|
+
planManager: services.planManager,
|
|
232
|
+
adaptivePlanner: services.adaptivePlanner,
|
|
233
|
+
sessionMemoryStore: services.sessionMemoryStore,
|
|
234
|
+
sessionLineageTracker: services.sessionLineageTracker,
|
|
235
|
+
idempotencyStore: services.idempotencyStore,
|
|
236
|
+
});
|
|
237
|
+
conversation.setSessionLineageTracker(services.sessionLineageTracker);
|
|
238
|
+
|
|
239
|
+
const acpManager = new AcpManager({
|
|
240
|
+
requestPermission: (request) => permissionPromptRef.requestPermission(request),
|
|
241
|
+
runtimeBus,
|
|
242
|
+
hookDispatcher: services.hookDispatcher,
|
|
243
|
+
});
|
|
244
|
+
const acpTaskAdapter = new AcpTaskAdapter(store);
|
|
245
|
+
const ACP_TASK_SYNC_INTERVAL_MS = 1_000;
|
|
246
|
+
const acpTaskSyncInterval = setInterval(() => {
|
|
247
|
+
acpTaskAdapter.sync(acpManager);
|
|
248
|
+
}, ACP_TASK_SYNC_INTERVAL_MS);
|
|
249
|
+
bootstrapUnsubs.push(() => clearInterval(acpTaskSyncInterval));
|
|
250
|
+
const opsTaskManager = createTaskManager(store, runtimeBus, userSessionId);
|
|
251
|
+
const opsControlPlane = services.featureFlags.isEnabled('operator-control-plane')
|
|
252
|
+
? new OpsControlPlane(opsTaskManager, runtimeBus, store, userSessionId)
|
|
253
|
+
: undefined;
|
|
254
|
+
|
|
255
|
+
const shell = createBootstrapShell({
|
|
256
|
+
configManager,
|
|
257
|
+
runtimeBus,
|
|
258
|
+
runtimeStore: store,
|
|
259
|
+
services,
|
|
260
|
+
conversation,
|
|
261
|
+
runtime,
|
|
262
|
+
orchestrator,
|
|
263
|
+
requestRender,
|
|
264
|
+
permissionPromptRef,
|
|
265
|
+
onSessionIdChanged: (sessionId) => {
|
|
266
|
+
runtimeSessionIdRef.value = sessionId;
|
|
267
|
+
},
|
|
268
|
+
writeLastSessionPointer,
|
|
269
|
+
getControlPlaneRecentEvents: (limit) => controlPlaneRecentEventsRef.value(limit),
|
|
270
|
+
toolRegistry,
|
|
271
|
+
forensicsRegistry,
|
|
272
|
+
policyRuntimeState: services.policyRuntimeState,
|
|
273
|
+
uiServices,
|
|
274
|
+
taskManager: opsTaskManager,
|
|
275
|
+
opsControlPlane,
|
|
276
|
+
completeModelSelectionSideEffect: () => {
|
|
277
|
+
compositor.resetDiff();
|
|
278
|
+
},
|
|
279
|
+
});
|
|
280
|
+
const systemMessageRouter = shell.systemMessageRouter;
|
|
281
|
+
systemMessageRouterRef.value = systemMessageRouter;
|
|
282
|
+
const commandRegistry = shell.commandRegistry;
|
|
283
|
+
const commandContext = shell.commandContext;
|
|
284
|
+
const gitStatusProvider = shell.gitStatusProvider;
|
|
285
|
+
const inputHistory = shell.inputHistory;
|
|
286
|
+
const lastGitInfoRef = shell.lastGitInfoRef;
|
|
287
|
+
const pluginCommandRegistry = {
|
|
288
|
+
register(command: {
|
|
289
|
+
readonly name: string;
|
|
290
|
+
readonly aliases?: readonly string[];
|
|
291
|
+
readonly description: string;
|
|
292
|
+
readonly usage?: string;
|
|
293
|
+
readonly argsHint?: string;
|
|
294
|
+
readonly handler: (args: string[]) => void | Promise<void>;
|
|
295
|
+
}): void {
|
|
296
|
+
commandRegistry.register({
|
|
297
|
+
...command,
|
|
298
|
+
aliases: command.aliases ? [...command.aliases] : undefined,
|
|
299
|
+
});
|
|
300
|
+
},
|
|
301
|
+
unregister(name: string): void {
|
|
302
|
+
commandRegistry.unregister(name);
|
|
303
|
+
},
|
|
304
|
+
};
|
|
305
|
+
|
|
306
|
+
// ── Phase 7: External services + deferred startup ──────────────────────
|
|
307
|
+
|
|
308
|
+
const deferredStartup = createDeferredStartupCoordinator();
|
|
309
|
+
|
|
310
|
+
const formatHostServiceBaseUrl = (host: string, port: number): string => {
|
|
311
|
+
const normalized = host.trim().toLowerCase();
|
|
312
|
+
const probeHost = normalized === '0.0.0.0'
|
|
313
|
+
? '127.0.0.1'
|
|
314
|
+
: normalized === '::' || normalized === '[::]'
|
|
315
|
+
? '::1'
|
|
316
|
+
: host;
|
|
317
|
+
const urlHost = probeHost.includes(':') && !probeHost.startsWith('[') ? `[${probeHost}]` : probeHost;
|
|
318
|
+
return `http://${urlHost}:${port}`;
|
|
319
|
+
};
|
|
320
|
+
|
|
321
|
+
const createExternalAgentServiceStatus = (
|
|
322
|
+
service: 'daemon' | 'httpListener',
|
|
323
|
+
): HostServiceStatus => {
|
|
324
|
+
const host = String(configManager.get(service === 'daemon' ? 'controlPlane.host' : 'httpListener.host') ?? '127.0.0.1');
|
|
325
|
+
const port = Number(configManager.get(service === 'daemon' ? 'controlPlane.port' : 'httpListener.port') ?? (service === 'daemon' ? 3421 : 3422));
|
|
326
|
+
return {
|
|
327
|
+
mode: service === 'daemon' ? 'external' : 'disabled',
|
|
328
|
+
host,
|
|
329
|
+
port,
|
|
330
|
+
baseUrl: formatHostServiceBaseUrl(host, port),
|
|
331
|
+
reason: service === 'daemon'
|
|
332
|
+
? 'GoodVibes Agent connects to an externally managed GoodVibes daemon and does not start or restart it.'
|
|
333
|
+
: 'GoodVibes Agent does not own the HTTP listener lifecycle.',
|
|
334
|
+
};
|
|
335
|
+
};
|
|
336
|
+
|
|
337
|
+
const hostServiceIsActive = (status: HostServiceStatus): boolean => status.mode === 'embedded' || status.mode === 'external';
|
|
338
|
+
|
|
339
|
+
const hostServiceIsBlocked = (status: HostServiceStatus): boolean => status.mode === 'blocked';
|
|
340
|
+
|
|
341
|
+
const inspectExternalServices = () => {
|
|
342
|
+
const daemonStatus = externalServices.daemonStatus;
|
|
343
|
+
const httpListenerStatus = externalServices.httpListenerStatus;
|
|
344
|
+
return {
|
|
345
|
+
daemonRunning: hostServiceIsActive(daemonStatus),
|
|
346
|
+
daemonPortInUse: hostServiceIsBlocked(daemonStatus),
|
|
347
|
+
httpListenerRunning: hostServiceIsActive(httpListenerStatus),
|
|
348
|
+
httpListenerPortInUse: hostServiceIsBlocked(httpListenerStatus),
|
|
349
|
+
daemonStatus,
|
|
350
|
+
httpListenerStatus,
|
|
351
|
+
};
|
|
352
|
+
};
|
|
353
|
+
|
|
354
|
+
let externalServices: ExternalServicesHandle = {
|
|
355
|
+
daemonServer: null,
|
|
356
|
+
httpListener: null,
|
|
357
|
+
daemonStatus: createExternalAgentServiceStatus('daemon'),
|
|
358
|
+
httpListenerStatus: createExternalAgentServiceStatus('httpListener'),
|
|
359
|
+
listRecentControlPlaneEvents: () => [],
|
|
360
|
+
async stop(): Promise<void> {},
|
|
361
|
+
};
|
|
362
|
+
const platformExternalServices = uiServices.platform as typeof uiServices.platform & {
|
|
363
|
+
externalServices: NonNullable<typeof uiServices.platform.externalServices>;
|
|
364
|
+
};
|
|
365
|
+
platformExternalServices.externalServices = {
|
|
366
|
+
inspect: inspectExternalServices,
|
|
367
|
+
restart: async () => {
|
|
368
|
+
externalServices = {
|
|
369
|
+
...externalServices,
|
|
370
|
+
daemonStatus: createExternalAgentServiceStatus('daemon'),
|
|
371
|
+
httpListenerStatus: createExternalAgentServiceStatus('httpListener'),
|
|
372
|
+
};
|
|
373
|
+
systemMessageRouter.high('[Startup] GoodVibes Agent does not start or restart daemon/listener services. Start the daemon from GoodVibes TUI or the daemon host, then refresh status.');
|
|
374
|
+
requestRender();
|
|
375
|
+
return inspectExternalServices();
|
|
376
|
+
},
|
|
377
|
+
};
|
|
378
|
+
deferredStartup.schedule({
|
|
379
|
+
label: 'plugins',
|
|
380
|
+
run: async () => {
|
|
381
|
+
await pluginManager.init({
|
|
382
|
+
runtimeBus,
|
|
383
|
+
commandRegistry: pluginCommandRegistry,
|
|
384
|
+
providerRegistry,
|
|
385
|
+
toolRegistry,
|
|
386
|
+
gatewayMethods: services.gatewayMethods,
|
|
387
|
+
channelRegistry: services.channelPlugins,
|
|
388
|
+
channelDeliveryRouter: services.deliveryManager.getDeliveryRouter(),
|
|
389
|
+
memoryEmbeddingRegistry: services.memoryEmbeddingRegistry,
|
|
390
|
+
voiceProviderRegistry: services.voiceProviders,
|
|
391
|
+
mediaProviderRegistry: services.mediaProviders,
|
|
392
|
+
webSearchProviderRegistry: services.webSearchProviders,
|
|
393
|
+
getPluginConfig: (name) => pluginManager.getPluginConfig(name),
|
|
394
|
+
isEnabled: (name) => pluginManager.isEnabled(name),
|
|
395
|
+
});
|
|
396
|
+
requestRender();
|
|
397
|
+
},
|
|
398
|
+
onError: (error) => {
|
|
399
|
+
const message = summarizeError(error);
|
|
400
|
+
logger.error('Deferred plugin startup failed', { error: message });
|
|
401
|
+
systemMessageRouter.high(`[Startup] Plugin initialization failed: ${message}`);
|
|
402
|
+
requestRender();
|
|
403
|
+
},
|
|
404
|
+
});
|
|
405
|
+
const toolCount = toolRegistry.list().length;
|
|
406
|
+
conversation.splashOptions = {
|
|
407
|
+
workingDir,
|
|
408
|
+
model: runtime.model,
|
|
409
|
+
provider: runtime.provider,
|
|
410
|
+
toolCount,
|
|
411
|
+
};
|
|
412
|
+
|
|
413
|
+
// ── Phase 8: Background provider registration (non-blocking) ────────────
|
|
414
|
+
// These run after the initial render so they don't delay startup.
|
|
415
|
+
|
|
416
|
+
startBackgroundProviderRegistration({
|
|
417
|
+
configManager,
|
|
418
|
+
providerRegistry,
|
|
419
|
+
runtime,
|
|
420
|
+
requestRender,
|
|
421
|
+
restoreRuntimeModel: restoreSavedModel,
|
|
422
|
+
systemMessageRouter,
|
|
423
|
+
shellPaths: services.shellPaths,
|
|
424
|
+
surfaceRoot: GOODVIBES_AGENT_SURFACE_ROOT,
|
|
425
|
+
});
|
|
426
|
+
const mcpDiscovery = scheduleBackgroundMcpDiscovery({
|
|
427
|
+
mcpRegistry: services.mcpRegistry,
|
|
428
|
+
systemMessageRouter,
|
|
429
|
+
requestRender,
|
|
430
|
+
shellPaths: services.shellPaths,
|
|
431
|
+
surfaceRoot: GOODVIBES_AGENT_SURFACE_ROOT,
|
|
432
|
+
});
|
|
433
|
+
bootstrapUnsubs.push(() => mcpDiscovery.stop());
|
|
434
|
+
const mcpAutoReload = startMcpConfigAutoReload({
|
|
435
|
+
roots: services.shellPaths,
|
|
436
|
+
registry: services.mcpRegistry,
|
|
437
|
+
onReload: ({ connected, total }) => {
|
|
438
|
+
systemMessageRouter.low(`[MCP] Reloaded config: ${connected}/${total} server(s) connected.`);
|
|
439
|
+
requestRender();
|
|
440
|
+
},
|
|
441
|
+
onError: (error) => {
|
|
442
|
+
const message = summarizeError(error);
|
|
443
|
+
logger.warn('MCP config auto-reload failed', { error: message });
|
|
444
|
+
systemMessageRouter.high(`[MCP] Config reload failed: ${message}`);
|
|
445
|
+
requestRender();
|
|
446
|
+
},
|
|
447
|
+
});
|
|
448
|
+
bootstrapUnsubs.push(() => mcpAutoReload.stop());
|
|
449
|
+
if (configManager.get('automation.enabled')) {
|
|
450
|
+
logger.warn('Local automation startup is disabled in GoodVibes Agent; use external daemon observability instead.');
|
|
451
|
+
systemMessageRouter.low('[Startup] Local automation runners are disabled in GoodVibes Agent; use read-only automation observability or explicit external-daemon actions.');
|
|
452
|
+
}
|
|
453
|
+
|
|
454
|
+
// ── Phase 12: Session:start lifecycle hook ─────────────────────────────
|
|
455
|
+
|
|
456
|
+
fireSessionStart(runtime.sessionId, services.hookDispatcher);
|
|
457
|
+
emitSessionStarted(runtimeBus, {
|
|
458
|
+
sessionId: runtime.sessionId,
|
|
459
|
+
traceId: `${runtime.sessionId}:session-start`,
|
|
460
|
+
source: 'bootstrap',
|
|
461
|
+
}, {
|
|
462
|
+
sessionId: runtime.sessionId,
|
|
463
|
+
profileId: 'default',
|
|
464
|
+
workingDir,
|
|
465
|
+
});
|
|
466
|
+
emitSessionReady(runtimeBus, {
|
|
467
|
+
sessionId: runtime.sessionId,
|
|
468
|
+
traceId: `${runtime.sessionId}:session-ready`,
|
|
469
|
+
source: 'bootstrap',
|
|
470
|
+
}, {
|
|
471
|
+
sessionId: runtime.sessionId,
|
|
472
|
+
});
|
|
473
|
+
|
|
474
|
+
// ── Compose RuntimeContext ────────────────────────────────────────────────
|
|
475
|
+
|
|
476
|
+
const ctx: BootstrapContext = {
|
|
477
|
+
runtimeBus,
|
|
478
|
+
store,
|
|
479
|
+
services,
|
|
480
|
+
featureFlags: services.featureFlags,
|
|
481
|
+
conversation,
|
|
482
|
+
permissions: permissionManager,
|
|
483
|
+
toolRegistry,
|
|
484
|
+
providerRegistry,
|
|
485
|
+
componentHealthMonitor: services.componentHealthMonitor,
|
|
486
|
+
worktreeRegistry: services.worktreeRegistry,
|
|
487
|
+
sandboxSessionRegistry: services.sandboxSessionRegistry,
|
|
488
|
+
hookDispatcher,
|
|
489
|
+
fileCache,
|
|
490
|
+
projectIndex,
|
|
491
|
+
sessionId: userSessionId,
|
|
492
|
+
isResumed: false, // Sessions start fresh; use /session resume to load a previous one
|
|
493
|
+
runtime,
|
|
494
|
+
orchestrator,
|
|
495
|
+
compositor,
|
|
496
|
+
selection,
|
|
497
|
+
commandContext,
|
|
498
|
+
uiServices,
|
|
499
|
+
inputHistory,
|
|
500
|
+
gitStatusProvider,
|
|
501
|
+
lastGitInfoRef,
|
|
502
|
+
bootstrapUnsubs,
|
|
503
|
+
agentStatusIntervalRef,
|
|
504
|
+
orchestratorRefs,
|
|
505
|
+
setRenderRequest,
|
|
506
|
+
permissionPromptRef,
|
|
507
|
+
loadLastConversation: () => loadLastConversation({
|
|
508
|
+
workingDirectory: services.workingDirectory,
|
|
509
|
+
homeDirectory: services.homeDirectory,
|
|
510
|
+
sessionManager: services.sessionManager,
|
|
511
|
+
}),
|
|
512
|
+
_writeLastSessionPointer: (sessionId) => writeLastSessionPointer(sessionId, {
|
|
513
|
+
workingDirectory: services.workingDirectory,
|
|
514
|
+
homeDirectory: services.homeDirectory,
|
|
515
|
+
}),
|
|
516
|
+
_saveSession: saveSession,
|
|
517
|
+
_getPinned: () => services.favoritesStore.getPinned(),
|
|
518
|
+
_getConfiguredProviderIds: () => services.providerRegistry.getConfiguredProviderIds(),
|
|
519
|
+
commandRegistry,
|
|
520
|
+
systemMessageRouter,
|
|
521
|
+
shutdown: async (sessionData) => {
|
|
522
|
+
// Clear bootstrap-owned subscriptions
|
|
523
|
+
bootstrapUnsubs.forEach(fn => fn());
|
|
524
|
+
bootstrapUnsubs.length = 0;
|
|
525
|
+
runtimeUnsubs.forEach((fn) => fn());
|
|
526
|
+
runtimeUnsubs.length = 0;
|
|
527
|
+
forensicsCollector.dispose();
|
|
528
|
+
await deferredStartup.drain(100);
|
|
529
|
+
await externalServices.stop();
|
|
530
|
+
// Clear agent status interval via ref (consistent with agentStatusIntervalRef usage)
|
|
531
|
+
if (agentStatusIntervalRef.value !== null) {
|
|
532
|
+
clearInterval(agentStatusIntervalRef.value);
|
|
533
|
+
agentStatusIntervalRef.value = null;
|
|
534
|
+
}
|
|
535
|
+
await shutdownRuntime(
|
|
536
|
+
runtime.sessionId,
|
|
537
|
+
sessionData,
|
|
538
|
+
runtime.model,
|
|
539
|
+
runtime.provider,
|
|
540
|
+
conversation.title || '',
|
|
541
|
+
services.workflow.scheduleManager,
|
|
542
|
+
services.hookDispatcher,
|
|
543
|
+
services.providerRegistry,
|
|
544
|
+
services.sessionOrchestration,
|
|
545
|
+
{
|
|
546
|
+
workingDirectory: services.workingDirectory,
|
|
547
|
+
homeDirectory: services.homeDirectory,
|
|
548
|
+
sessionManager: services.sessionManager,
|
|
549
|
+
},
|
|
550
|
+
);
|
|
551
|
+
},
|
|
552
|
+
};
|
|
553
|
+
|
|
554
|
+
// ── Phase 12b: Operator Control Plane wiring (feature-gated) ──────────────
|
|
555
|
+
// Wire the OpsControlPlane into CommandContext when the feature flag is enabled.
|
|
556
|
+
// The store and task manager are created unconditionally so they reflect the
|
|
557
|
+
// real runtime state (tasks registered before the flag check are visible).
|
|
558
|
+
ctx.commandContext.ops.acpManager = acpManager;
|
|
559
|
+
if (opsControlPlane) {
|
|
560
|
+
ctx.commandContext.openOpsPanel = () => {
|
|
561
|
+
if (ctx.commandContext.showPanel) ctx.commandContext.showPanel('ops-control');
|
|
562
|
+
else {
|
|
563
|
+
panelManager.open('ops-control');
|
|
564
|
+
requestRender();
|
|
565
|
+
}
|
|
566
|
+
};
|
|
567
|
+
}
|
|
568
|
+
|
|
569
|
+
// Wire exit from options if provided; otherwise main.ts binds the shell bridge.
|
|
570
|
+
if (options?.exit) {
|
|
571
|
+
ctx.commandContext.exit = options.exit;
|
|
572
|
+
}
|
|
573
|
+
|
|
574
|
+
return ctx;
|
|
575
|
+
}
|