@pellux/goodvibes-tui 1.27.1 → 2.0.2
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 +127 -2
- package/README.md +7 -9
- package/bin/goodvibes +2 -2
- package/bin/launcher-support.js +8 -4
- package/docs/README.md +11 -2
- package/docs/foundation-artifacts/operator-contract.json +6403 -2347
- package/package.json +14 -25
- package/scripts/postinstall.js +35 -35
- package/src/audio/spoken-turn-model-routing.ts +1 -1
- package/src/cli/bundle-command.ts +5 -5
- package/src/cli/completions/generate.ts +1 -1
- package/src/cli/doctor.ts +3 -3
- package/src/cli/entrypoint.ts +12 -7
- package/src/cli/help.ts +4 -5
- package/src/cli/hooks-command.ts +1 -1
- package/src/cli/index.ts +1 -4
- package/src/cli/launch-auto-update.ts +59 -7
- package/src/cli/management-commands.ts +6 -6
- package/src/cli/management-utils.ts +5 -5
- package/src/cli/management.ts +7 -7
- package/src/cli/network-posture.ts +1 -1
- package/src/cli/package-verification.ts +7 -6
- package/src/cli/plugin-bundles-command.ts +1 -1
- package/src/cli/plugin-command.ts +2 -2
- package/src/cli/service-command.ts +2 -2
- package/src/cli/service-posture.ts +4 -4
- package/src/cli/status.ts +9 -8
- package/src/cli/surface-command.ts +4 -4
- package/src/cli/tui-startup.ts +3 -3
- package/src/cli-flags.ts +3 -3
- package/src/config/goodvibes-home-audit.ts +0 -2
- package/src/config/secret-config.ts +37 -5
- package/src/config/tui-extension-settings.ts +1 -1
- package/src/core/approval-alert.ts +2 -2
- package/src/core/budget-breach-notifier.ts +3 -3
- package/src/core/conversation-compaction-render.ts +1 -1
- package/src/core/conversation-line-cache.ts +1 -1
- package/src/core/conversation-render-context.ts +1 -1
- package/src/core/conversation-rendering.ts +2 -2
- package/src/core/conversation.ts +10 -10
- package/src/core/long-task-notifier.ts +2 -2
- package/src/core/memory-diagnostics-gateway.ts +1 -1
- package/src/core/scriptable-statusline.ts +1 -1
- package/src/core/session-auto-titler.ts +1 -1
- package/src/core/session-resume-core.ts +2 -2
- package/src/core/stream-event-wiring.ts +24 -44
- package/src/core/terminal-notifier.ts +3 -3
- package/src/core/turn-cancellation.ts +1 -1
- package/src/core/turn-event-wiring.ts +5 -5
- package/src/input/command-registry.ts +6 -6
- package/src/input/commands/channel-pairing.ts +1 -1
- package/src/input/commands/cluster-runtime.ts +1 -1
- package/src/input/commands/codebase-runtime.ts +1 -1
- package/src/input/commands/devices-runtime.ts +1 -1
- package/src/input/commands/hosted-runtime.ts +330 -0
- package/src/input/commands/local-setup-review.ts +1 -1
- package/src/input/commands/local-setup-transfer.ts +2 -2
- package/src/input/commands/local-setup.ts +3 -3
- package/src/input/commands/managed-runtime.ts +2 -2
- package/src/input/commands/operator-rpc.ts +24 -110
- package/src/input/commands/payment-card-intake.ts +1 -1
- package/src/input/commands/permissions-provenance.ts +2 -2
- package/src/input/commands/plugin-runtime.ts +1 -1
- package/src/input/commands/provider.ts +1 -1
- package/src/input/commands/relay-runtime.ts +18 -9
- package/src/input/commands/rewind-runtime.ts +1 -1
- package/src/input/commands/runtime-services.ts +1 -1
- package/src/input/commands/services-runtime.ts +1 -1
- package/src/input/commands/session-workflow.ts +1 -1
- package/src/input/commands/settings-sync-runtime.ts +2 -2
- package/src/input/commands/share-runtime.ts +1 -1
- package/src/input/commands/tasks-runtime.ts +145 -55
- package/src/input/commands/update-runtime.ts +31 -28
- package/src/input/commands/work-plan-runtime.ts +2 -2
- package/src/input/commands/workstream-attempts.ts +1 -1
- package/src/input/commands/workstream-runtime.ts +2 -2
- package/src/input/commands.ts +2 -0
- package/src/input/feature-unit-layout.ts +1 -1
- package/src/input/feed-context-factory.ts +3 -3
- package/src/input/handler-content-actions.ts +2 -2
- package/src/input/handler-feed-routes.ts +1 -1
- package/src/input/handler-feed.ts +3 -3
- package/src/input/handler-modal-token-routes.ts +1 -1
- package/src/input/handler-onboarding-daemon-adopt.ts +3 -2
- package/src/input/handler-onboarding.ts +1 -1
- package/src/input/handler-types.ts +2 -2
- package/src/input/handler-ui-state.ts +1 -1
- package/src/input/handler.ts +4 -4
- package/src/input/input-history.ts +1 -1
- package/src/input/onboarding/onboarding-feature-units.ts +2 -2
- package/src/input/onboarding/onboarding-runtime-status.ts +15 -1
- package/src/input/onboarding/onboarding-wizard-apply.ts +17 -8
- package/src/input/onboarding/onboarding-wizard-cloudflare-step.ts +5 -3
- package/src/input/onboarding/onboarding-wizard-external-surfaces.ts +1 -1
- package/src/input/onboarding/onboarding-wizard-types.ts +1 -1
- package/src/input/payments-config.ts +6 -6
- package/src/input/search.ts +1 -1
- package/src/input/session-picker-modal.ts +46 -0
- package/src/input/settings-modal-activation.ts +1 -1
- package/src/input/settings-modal-behavior.ts +4 -4
- package/src/input/settings-modal-commit.ts +11 -0
- package/src/input/settings-modal-data.ts +9 -122
- package/src/input/settings-modal-mutations.ts +33 -0
- package/src/input/settings-modal-secrets.ts +34 -0
- package/src/input/settings-modal-subscriptions.ts +1 -1
- package/src/input/settings-modal-types.ts +15 -1
- package/src/input/settings-modal.ts +28 -3
- package/src/input/worktree-setup-config.ts +1 -1
- package/src/main.ts +11 -9
- package/src/panels/agent-inspector-shared.ts +2 -2
- package/src/panels/base-panel.ts +2 -2
- package/src/panels/builtin/operations.ts +6 -8
- package/src/panels/builtin/session.ts +17 -0
- package/src/panels/builtin/shared.ts +5 -5
- package/src/panels/builtin-modals.ts +3 -3
- package/src/panels/confirm-state.ts +1 -1
- package/src/panels/cost-tracker-panel.ts +4 -4
- package/src/panels/diff-panel.ts +2 -2
- package/src/panels/diff-review-panel.ts +2 -2
- package/src/panels/expandable-list-panel.ts +2 -2
- package/src/panels/fleet-acts.ts +1 -1
- package/src/panels/fleet-observed-render.ts +1 -1
- package/src/panels/fleet-panel-format.ts +1 -1
- package/src/panels/fleet-panel.ts +1 -1
- package/src/panels/fleet-spawn.ts +1 -1
- package/src/panels/fleet-steer.ts +1 -1
- package/src/panels/fleet-transcript.ts +1 -1
- package/src/panels/git-panel.ts +1 -1
- package/src/panels/hosted-session-feed.ts +352 -0
- package/src/panels/hosted-session-panel.ts +221 -0
- package/src/panels/local-auth-panel.ts +3 -3
- package/src/panels/modals/devices-modal.ts +1 -1
- package/src/panels/modals/local-auth-modal.ts +1 -1
- package/src/panels/modals/pairing-modal.ts +1 -1
- package/src/panels/modals/services-modal.ts +1 -1
- package/src/panels/modals/settings-sync-modal.ts +1 -1
- package/src/panels/modals/subscription-modal.ts +1 -1
- package/src/panels/modals/work-plan-modal.ts +1 -1
- package/src/panels/notifications-panel.ts +1 -1
- package/src/panels/panel-confirm-overlay.ts +1 -1
- package/src/panels/plugins-panel.ts +2 -2
- package/src/panels/polish-core.ts +2 -2
- package/src/panels/polish-tables.ts +1 -1
- package/src/panels/polish.ts +2 -2
- package/src/panels/scrollable-list-panel.ts +3 -3
- package/src/panels/skills-panel.ts +3 -3
- package/src/panels/token-budget-panel.ts +5 -5
- package/src/panels/types.ts +1 -2
- package/src/permissions/prompt.ts +1 -1
- package/src/renderer/autocomplete-overlay.ts +1 -1
- package/src/renderer/block-actions-overlay.ts +1 -1
- package/src/renderer/bookmark-modal.ts +1 -1
- package/src/renderer/buffer.ts +1 -1
- package/src/renderer/code-block.ts +1 -1
- package/src/renderer/composer-fragments.ts +1 -1
- package/src/renderer/compositor.ts +2 -2
- package/src/renderer/config-modal.ts +1 -1
- package/src/renderer/context-inspector.ts +1 -1
- package/src/renderer/conversation-layout.ts +2 -2
- package/src/renderer/conversation-overlays.ts +1 -1
- package/src/renderer/conversation-surface.ts +2 -2
- package/src/renderer/diff-view.ts +1 -1
- package/src/renderer/diff.ts +1 -1
- package/src/renderer/file-picker-overlay.ts +1 -1
- package/src/renderer/fleet-tab-strip.ts +1 -1
- package/src/renderer/fullscreen-primitives.ts +2 -2
- package/src/renderer/fullscreen-workspace.ts +1 -1
- package/src/renderer/header-line.ts +1 -1
- package/src/renderer/help-overlay.ts +1 -1
- package/src/renderer/history-search-overlay.ts +2 -2
- package/src/renderer/layout.ts +5 -8
- package/src/renderer/markdown-inline.ts +1 -1
- package/src/renderer/markdown-table.ts +1 -1
- package/src/renderer/markdown.ts +1 -1
- package/src/renderer/mcp-workspace.ts +1 -1
- package/src/renderer/modal-factory.ts +2 -2
- package/src/renderer/model-workspace.ts +2 -2
- package/src/renderer/onboarding/onboarding-wizard.ts +1 -1
- package/src/renderer/overlay-box.ts +1 -1
- package/src/renderer/panel-composite.ts +1 -1
- package/src/renderer/panel-workspace-bar.ts +1 -1
- package/src/renderer/process-indicator.ts +1 -1
- package/src/renderer/profile-picker-modal.ts +1 -1
- package/src/renderer/search-overlay.ts +2 -2
- package/src/renderer/selection-modal-overlay.ts +1 -1
- package/src/renderer/session-picker-modal.ts +124 -3
- package/src/renderer/settings-modal-helpers.ts +2 -0
- package/src/renderer/settings-modal.ts +2 -2
- package/src/renderer/shell-surface.ts +2 -2
- package/src/renderer/system-message.ts +1 -1
- package/src/renderer/tab-strip.ts +1 -1
- package/src/renderer/theme-mode-config.ts +21 -33
- package/src/renderer/theme.ts +11 -12
- package/src/renderer/thinking.ts +1 -1
- package/src/renderer/tool-call.ts +2 -2
- package/src/renderer/tool-result-expanded-lines.ts +1 -1
- package/src/renderer/turn-injection.ts +7 -8
- package/src/renderer/ui-factory.ts +3 -3
- package/src/runtime/bootstrap-command-context.ts +4 -4
- package/src/runtime/bootstrap-command-parts.ts +5 -5
- package/src/runtime/bootstrap-core.ts +30 -30
- package/src/runtime/bootstrap-shell.ts +4 -4
- package/src/runtime/bootstrap.ts +128 -157
- package/src/runtime/client/approval-updates.ts +82 -0
- package/src/runtime/client/build-floors.ts +167 -0
- package/src/runtime/client/daemon-attach-handshake.ts +115 -0
- package/src/runtime/client/fleet-union.ts +147 -0
- package/src/runtime/client/host-service-status.ts +71 -0
- package/src/runtime/client/hosted-exit.ts +86 -0
- package/src/runtime/client/hosted-roster.ts +110 -0
- package/src/runtime/client/hosted-session-stream.ts +178 -0
- package/src/runtime/client/hosted-sessions.ts +187 -0
- package/src/runtime/client/operator-endpoint.ts +213 -0
- package/src/runtime/client/spine-adoption.ts +99 -0
- package/src/runtime/cloudflare-control-plane.ts +1 -1
- package/src/runtime/context-accounting-source.ts +1 -1
- package/src/runtime/context.ts +2 -2
- package/src/runtime/conversation-rewind-port.ts +42 -14
- package/src/runtime/daemon-attach-notices.ts +55 -19
- package/src/runtime/diagnostics/panels/ops.ts +1 -1
- package/src/runtime/disposal-wiring.ts +4 -24
- package/src/runtime/index.ts +119 -105
- package/src/runtime/install-self-check-startup.ts +2 -2
- package/src/runtime/interaction-seams.ts +1 -1
- package/src/runtime/knowledge-services.ts +8 -2
- package/src/runtime/legacy-daemon-migration.ts +4 -3
- package/src/runtime/legacy-daemon-reconcile.ts +3 -2
- package/src/runtime/memory-spine-transport.ts +37 -267
- package/src/runtime/notification-dispatch.ts +2 -2
- package/src/runtime/onboarding/apply.ts +2 -2
- package/src/runtime/onboarding/derivation.ts +2 -2
- package/src/runtime/onboarding/markers.ts +2 -2
- package/src/runtime/onboarding/progress.ts +2 -2
- package/src/runtime/onboarding/snapshot.ts +1 -1
- package/src/runtime/onboarding/state.ts +2 -2
- package/src/runtime/onboarding/types.ts +2 -2
- package/src/runtime/orchestrator-core-services.ts +1 -1
- package/src/runtime/path-shadow-startup.ts +28 -221
- package/src/runtime/power-keepawake-remote.ts +3 -2
- package/src/runtime/process-lifecycle.ts +2 -2
- package/src/runtime/provider-fallback.ts +10 -66
- package/src/runtime/recovery-autosave.ts +1 -1
- package/src/runtime/recovery-offer-wiring.ts +39 -23
- package/src/runtime/recovery-prompt.ts +31 -17
- package/src/runtime/relay-reachability-bridge.ts +53 -42
- package/src/runtime/release-artifacts.ts +2 -1
- package/src/runtime/runtime-services-types.ts +82 -35
- package/src/runtime/services.ts +305 -300
- package/src/runtime/session-resume-liveness-confirm.ts +1 -1
- package/src/runtime/ui-services.ts +7 -6
- package/src/runtime/update-check.ts +23 -43
- package/src/runtime/workspace-checkpointing.ts +1 -1
- package/src/runtime/wrfc-persistence.ts +2 -2
- package/src/shell/ui-openers.ts +30 -7
- package/src/utils/clipboard.ts +1 -1
- package/src/verification/verification-ledger.ts +10 -8
- package/src/version.ts +1 -1
- package/bin/goodvibes-daemon +0 -90
- package/src/cli/config-overrides.ts +0 -267
- package/src/cli/endpoints.ts +0 -109
- package/src/cli/parser.ts +0 -395
- package/src/cli/redaction.ts +0 -170
- package/src/cli/types.ts +0 -84
- package/src/cluster/commands.ts +0 -382
- package/src/cluster/remote-daemon-target.ts +0 -225
- package/src/cluster/render.ts +0 -268
- package/src/config/atomic-write.ts +0 -70
- package/src/config/credential-availability.ts +0 -122
- package/src/config/goodvibes-home.ts +0 -149
- package/src/config/index.ts +0 -88
- package/src/config/provider-model.ts +0 -23
- package/src/config/read-versioned.ts +0 -228
- package/src/core/alert-gating.ts +0 -67
- package/src/core/consolidation-receipt.ts +0 -41
- package/src/core/focus-tracker.ts +0 -41
- package/src/core/history.ts +0 -45
- package/src/core/memory-status.ts +0 -118
- package/src/core/orchestrator.ts +0 -7
- package/src/core/pairing-devices.ts +0 -49
- package/src/core/pairing-handoff.ts +0 -101
- package/src/core/pairing-offers.ts +0 -83
- package/src/core/pairing-origin.ts +0 -78
- package/src/core/rewind-turn-anchors.ts +0 -311
- package/src/core/session-recovery.ts +0 -210
- package/src/core/stable-host.ts +0 -171
- package/src/core/transcript-journal.ts +0 -503
- package/src/daemon/cli.ts +0 -693
- package/src/daemon/fatal-boot-report.ts +0 -111
- package/src/daemon/handlers/context.ts +0 -29
- package/src/daemon/handlers/contracts.ts +0 -77
- package/src/daemon/handlers/credentials.ts +0 -139
- package/src/daemon/handlers/drafts/draft-store.ts +0 -427
- package/src/daemon/handlers/drafts/index.ts +0 -17
- package/src/daemon/handlers/drafts/register.ts +0 -331
- package/src/daemon/handlers/errors.ts +0 -18
- package/src/daemon/handlers/inbox/cursor-store.ts +0 -457
- package/src/daemon/handlers/inbox/index.ts +0 -284
- package/src/daemon/handlers/inbox/mapping.ts +0 -192
- package/src/daemon/handlers/inbox/poller.ts +0 -212
- package/src/daemon/handlers/inbox/provider-adapter.ts +0 -156
- package/src/daemon/handlers/inbox/providers/discord.ts +0 -252
- package/src/daemon/handlers/inbox/providers/email.ts +0 -152
- package/src/daemon/handlers/inbox/providers/imap-client.ts +0 -300
- package/src/daemon/handlers/inbox/providers/route-util.ts +0 -24
- package/src/daemon/handlers/inbox/providers/slack.ts +0 -263
- package/src/daemon/handlers/index.ts +0 -117
- package/src/daemon/handlers/register.ts +0 -168
- package/src/daemon/handlers/remote/backends/cloud-terminal.ts +0 -142
- package/src/daemon/handlers/remote/backends/docker.ts +0 -79
- package/src/daemon/handlers/remote/backends/index.ts +0 -40
- package/src/daemon/handlers/remote/backends/local-process.ts +0 -113
- package/src/daemon/handlers/remote/backends/process-runner.ts +0 -127
- package/src/daemon/handlers/remote/backends/ssh.ts +0 -125
- package/src/daemon/handlers/remote/backends/types.ts +0 -97
- package/src/daemon/handlers/remote/dispatcher.ts +0 -181
- package/src/daemon/handlers/remote/index.ts +0 -119
- package/src/daemon/handlers/remote/peer-registry.ts +0 -357
- package/src/daemon/handlers/remote/service.ts +0 -191
- package/src/daemon/handlers/routing/inbox-bridge.ts +0 -71
- package/src/daemon/handlers/routing/index.ts +0 -261
- package/src/daemon/handlers/routing/route-store.ts +0 -319
- package/src/daemon/handlers/routing/routing-resolver.ts +0 -75
- package/src/daemon/handlers/sqlite-store.ts +0 -278
- package/src/daemon/handlers/triage/index.ts +0 -57
- package/src/daemon/handlers/triage/integration.ts +0 -213
- package/src/daemon/handlers/triage/pipeline.ts +0 -274
- package/src/daemon/handlers/triage/scorer.ts +0 -287
- package/src/daemon/handlers/triage/tagger/discord.ts +0 -187
- package/src/daemon/handlers/triage/tagger/imap.ts +0 -384
- package/src/daemon/handlers/triage/tagger/index.ts +0 -184
- package/src/daemon/handlers/triage/tagger/shared.ts +0 -70
- package/src/daemon/handlers/triage/tagger/slack.ts +0 -69
- package/src/daemon/handlers/triage/types.ts +0 -50
- package/src/daemon/lifecycle.ts +0 -41
- package/src/daemon/provision-wake-model.ts +0 -81
- package/src/daemon/safe-serve.ts +0 -61
- package/src/daemon/send/channels.ts +0 -200
- package/src/daemon/send/command.ts +0 -332
- package/src/daemon/send/composition.ts +0 -99
- package/src/daemon/send/failure-text.ts +0 -93
- package/src/daemon/send/inert-text.ts +0 -225
- package/src/daemon/send/stdin.ts +0 -24
- package/src/daemon/service-commands.ts +0 -329
- package/src/export/cost-utils.ts +0 -319
- package/src/input/selection.ts +0 -135
- package/src/plugins/loader.ts +0 -15
- package/src/renderer/bottom-bar.ts +0 -58
- package/src/renderer/conversation-tree.ts +0 -228
- package/src/runtime/agent-graph-composition.ts +0 -78
- package/src/runtime/channel-composition.ts +0 -46
- package/src/runtime/cluster-composition.ts +0 -124
- package/src/runtime/cluster-group-composition.ts +0 -284
- package/src/runtime/code-index-services.ts +0 -167
- package/src/runtime/daemon-handler-composition.ts +0 -76
- package/src/runtime/device-posture-composition.ts +0 -110
- package/src/runtime/durability-housekeeping.ts +0 -183
- package/src/runtime/durability-services.ts +0 -155
- package/src/runtime/embedded-service-factories.ts +0 -74
- package/src/runtime/feature-settings.ts +0 -154
- package/src/runtime/fleet-needs-input-push.ts +0 -70
- package/src/runtime/fleet-services.ts +0 -41
- package/src/runtime/idle-power-services.ts +0 -85
- package/src/runtime/mail-composition.ts +0 -65
- package/src/runtime/memory-fold.ts +0 -55
- package/src/runtime/operator-token-cleanup.ts +0 -109
- package/src/runtime/path-shadow.ts +0 -418
- package/src/runtime/perf/panel-health-monitor.ts +0 -18
- package/src/runtime/provider-optimizer-wiring.ts +0 -55
- package/src/runtime/reachability-notice.ts +0 -100
- package/src/runtime/remote-execution-composition.ts +0 -62
- package/src/runtime/session-liveness-marker.ts +0 -257
- package/src/runtime/session-pointer-surface.ts +0 -22
- package/src/runtime/session-storage-services.ts +0 -41
- package/src/runtime/surface-feature-flags.ts +0 -96
- package/src/runtime/terminal-output-guard.ts +0 -235
- package/src/runtime/trust/workspace-registration.ts +0 -192
- package/src/runtime/trust/workspace-trust.ts +0 -229
- package/src/runtime/ui/index.ts +0 -39
- package/src/runtime/ui/model-picker/data-provider.ts +0 -182
- package/src/runtime/ui/model-picker/health-enrichment.ts +0 -231
- package/src/runtime/ui/model-picker/index.ts +0 -59
- package/src/runtime/ui/model-picker/types.ts +0 -153
- package/src/runtime/ui/provider-health/data-provider.ts +0 -244
- package/src/runtime/ui/provider-health/fallback-visualizer.ts +0 -71
- package/src/runtime/ui/provider-health/index.ts +0 -46
- package/src/runtime/ui/provider-health/types.ts +0 -146
- package/src/runtime/ui-events.ts +0 -1
- package/src/runtime/ui-read-model-helpers.ts +0 -1
- package/src/runtime/ui-read-models-observability-maintenance.ts +0 -1
- package/src/runtime/ui-read-models-observability-options.ts +0 -1
- package/src/runtime/ui-read-models-observability-remote.ts +0 -1
- package/src/runtime/ui-read-models-observability-security.ts +0 -1
- package/src/runtime/ui-read-models-observability-system.ts +0 -1
- package/src/runtime/ui-read-models-observability.ts +0 -1
- package/src/runtime/ui-service-queries.ts +0 -1
- package/src/runtime/voice-setup-services.ts +0 -98
- package/src/runtime/workstream-attempts-validation.ts +0 -77
- package/src/runtime/workstream-draft-edits.ts +0 -95
- package/src/runtime/workstream-draft-store.ts +0 -274
- package/src/runtime/workstream-draft-types.ts +0 -42
- package/src/runtime/workstream-services.ts +0 -373
- package/src/tools/index.ts +0 -1
- package/src/types/grid.ts +0 -48
- package/src/types/sql-js.d.ts +0 -15
- package/src/work-plans/work-plan-store.ts +0 -702
|
@@ -1,228 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* conversation-tree.ts — column geometry for the transcript's branch tree.
|
|
3
|
-
*
|
|
4
|
-
* The transcript renders an assistant turn as a small tree: the turn header at
|
|
5
|
-
* depth 0, each tool call it issues as a depth-1 branch, and each call's result
|
|
6
|
-
* as a depth-2 branch under that call. This module owns the *only* arithmetic
|
|
7
|
-
* that decides where those branch glyphs, status markers and row text land, so
|
|
8
|
-
* every row type (event lines, tool-call rows, collapsed fragments) agrees on a
|
|
9
|
-
* single column grid instead of each re-deriving it.
|
|
10
|
-
*
|
|
11
|
-
* ## The grid
|
|
12
|
-
*
|
|
13
|
-
* One function generates every column, from LAYOUT.LEFT_MARGIN and the row's
|
|
14
|
-
* depth. With LEFT_MARGIN = 4 and TREE_STEP_COLS = 2 that is:
|
|
15
|
-
*
|
|
16
|
-
* depth 0 ` ● assistant …` marker col 3, text col 6
|
|
17
|
-
* depth 1 ` ✓ ├ read foo.ts` marker col 3, connector col 5, text col 8
|
|
18
|
-
* depth 2 ` │ └ ▸ 31 lines` connector col 7, text col 10
|
|
19
|
-
* depth 3 ` │ │ └ …` connector col 9, text col 12
|
|
20
|
-
*
|
|
21
|
-
* A level's connector sits where its parent's content began, and the row's
|
|
22
|
-
* first printable character sits two columns further right — the same
|
|
23
|
-
* marker→text relationship a depth-0 row has. So the step between levels is
|
|
24
|
-
* exactly TREE_STEP_COLS at every depth, for every row type.
|
|
25
|
-
*
|
|
26
|
-
* ## The status column IS the bullet column
|
|
27
|
-
*
|
|
28
|
-
* `treeStatusCol()` is defined as `treeBranchCol(0)` — literally the column the
|
|
29
|
-
* `●` of `● assistant` occupies. A tool row's ✓ / ✗ / ⊘ / ◌ therefore lands in
|
|
30
|
-
* the same column as the bullet of the turn that issued it, and reads as that
|
|
31
|
-
* bullet's column continuing down the turn rather than as a separate rail off
|
|
32
|
-
* to the left. Deriving it from treeBranchCol rather than restating a number is
|
|
33
|
-
* what keeps the two from drifting: move the bullet and the markers follow.
|
|
34
|
-
*
|
|
35
|
-
* The column is free at every depth ≥ 1 by construction — a branch row's own
|
|
36
|
-
* marker moves right with its indent, and depth 0 never contributes a `│`
|
|
37
|
-
* gutter (a top-level row has no ancestor to continue), so nothing else can
|
|
38
|
-
* claim it.
|
|
39
|
-
*
|
|
40
|
-
* ## Rails are continuous
|
|
41
|
-
*
|
|
42
|
-
* `drawTreeRails` paints EVERY line a row emits, not just its first: the
|
|
43
|
-
* connector on line 0, then `│` down the row's own column for as long as the
|
|
44
|
-
* row has a sibling below it, plus `│` in each open ancestor's gutter on every
|
|
45
|
-
* line. That is what closes the gaps a first-line-only connector leaves under
|
|
46
|
-
* multi-line rows (collapsed fragment boxes, wrapped text, expanded bodies).
|
|
47
|
-
*
|
|
48
|
-
* Rails never overwrite text: apart from the connector itself — which
|
|
49
|
-
* deliberately replaces the marker cell of the row it labels — a rail is drawn
|
|
50
|
-
* only into a cell that is blank and unstyled. A row whose own content reaches
|
|
51
|
-
* into a rail column keeps its content and loses the rail there.
|
|
52
|
-
*
|
|
53
|
-
* ## Narrow terminals
|
|
54
|
-
*
|
|
55
|
-
* Indenting unconditionally would eat the content budget and silently truncate
|
|
56
|
-
* the informative end of a row — the failure class the markdown-table column
|
|
57
|
-
* bug came from. treeIndentCols() therefore clamps the indent to whatever still
|
|
58
|
-
* leaves TREE_MIN_CONTENT_COLS of content, and drops to 0 (flush, no branch
|
|
59
|
-
* glyph) when even one level does not fit. Losing the visual nesting on a
|
|
60
|
-
* 30-column terminal is acceptable; losing characters is not.
|
|
61
|
-
*/
|
|
62
|
-
|
|
63
|
-
import { LAYOUT } from './layout.ts';
|
|
64
|
-
import type { Line } from '../types/grid.ts';
|
|
65
|
-
import { createStyledCell } from '../types/grid.ts';
|
|
66
|
-
import { getDisplayWidth } from '../utils/terminal-width.ts';
|
|
67
|
-
|
|
68
|
-
/** Columns added per nesting level. Fixed — never content-dependent. */
|
|
69
|
-
const TREE_STEP_COLS = 2;
|
|
70
|
-
|
|
71
|
-
/**
|
|
72
|
-
* Content columns a branch row is guaranteed to keep. Below this the indent is
|
|
73
|
-
* reduced (and finally dropped) rather than squeezing the row's text.
|
|
74
|
-
*/
|
|
75
|
-
const TREE_MIN_CONTENT_COLS = 16;
|
|
76
|
-
|
|
77
|
-
/** Vertical rail drawn in an ancestor's gutter and down an open row's column. */
|
|
78
|
-
const TREE_RAIL = '│';
|
|
79
|
-
|
|
80
|
-
/** The connector a row draws when a sibling follows it below. */
|
|
81
|
-
const TREE_CONNECTOR_CONTINUES = '├';
|
|
82
|
-
|
|
83
|
-
/**
|
|
84
|
-
* Effective indent, in columns, for a branch at `depth` rendered at `width`.
|
|
85
|
-
*
|
|
86
|
-
* Returns 0 for depth <= 0 (a flush, non-branch row) and for widths too narrow
|
|
87
|
-
* to carry even one level while keeping TREE_MIN_CONTENT_COLS of content. The
|
|
88
|
-
* result is always a whole multiple of TREE_STEP_COLS, so branch glyphs across
|
|
89
|
-
* different depths stay on the same column grid.
|
|
90
|
-
*/
|
|
91
|
-
export function treeIndentCols(depth: number, width: number): number {
|
|
92
|
-
if (depth <= 0) return 0;
|
|
93
|
-
const budget = width - LAYOUT.LEFT_MARGIN - LAYOUT.RIGHT_MARGIN - TREE_MIN_CONTENT_COLS;
|
|
94
|
-
if (budget < TREE_STEP_COLS) return 0;
|
|
95
|
-
const affordableLevels = Math.floor(budget / TREE_STEP_COLS);
|
|
96
|
-
return Math.min(depth, affordableLevels) * TREE_STEP_COLS;
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
/**
|
|
100
|
-
* Column the row's leading glyph occupies for a given effective indent: the
|
|
101
|
-
* `●` of a depth-0 row, the `├`/`└` of a branch row, and the `│` an ancestor
|
|
102
|
-
* carries down through its descendants' rows.
|
|
103
|
-
*/
|
|
104
|
-
export function treeBranchCol(indentCols: number): number {
|
|
105
|
-
return LAYOUT.LEFT_MARGIN - 1 + indentCols;
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
/**
|
|
109
|
-
* Column at which a row's segment run begins. Segment runs carry one leading
|
|
110
|
-
* blank by convention (` assistant `, ` ▸ 31 lines `, the fragment's ` ▸ `
|
|
111
|
-
* prefix), so this is the gap column and treeTextCol is where glyphs land.
|
|
112
|
-
*/
|
|
113
|
-
export function treeContentCol(indentCols: number): number {
|
|
114
|
-
return treeBranchCol(indentCols) + 2;
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
/**
|
|
118
|
-
* Column of a row's first PRINTABLE character. Every row type must land its
|
|
119
|
-
* text here — that is the invariant which makes each level step by exactly
|
|
120
|
-
* TREE_STEP_COLS regardless of whether the row came from an event line, a
|
|
121
|
-
* tool-call row or a collapsed fragment.
|
|
122
|
-
*/
|
|
123
|
-
export function treeTextCol(indentCols: number): number {
|
|
124
|
-
return treeContentCol(indentCols) + 1;
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
/**
|
|
128
|
-
* Write a branch row's status marker into the shared bullet column.
|
|
129
|
-
*
|
|
130
|
-
* Success and failure differ by GLYPH, not only by colour, so the distinction
|
|
131
|
-
* survives a monochrome terminal and colour-blind viewers. A double-width glyph
|
|
132
|
-
* claims its trailing cell too, so the column math stays honest for emoji-class
|
|
133
|
-
* markers instead of leaving a stale half-character behind.
|
|
134
|
-
*/
|
|
135
|
-
export function writeTreeStatusMarker(
|
|
136
|
-
line: Line,
|
|
137
|
-
glyph: string | null,
|
|
138
|
-
fg: string,
|
|
139
|
-
width: number,
|
|
140
|
-
): void {
|
|
141
|
-
if (!glyph) return;
|
|
142
|
-
// THE column: treeBranchCol(0) is where a depth-0 row draws its `●`, so a
|
|
143
|
-
// branch row's marker lands in the bullet column of the turn it belongs to.
|
|
144
|
-
// Derived, never restated, so the two cannot drift apart.
|
|
145
|
-
const col = treeBranchCol(0);
|
|
146
|
-
if (col < 0 || col >= width) return;
|
|
147
|
-
const glyphWidth = getDisplayWidth(glyph);
|
|
148
|
-
if (glyphWidth <= 0) return;
|
|
149
|
-
line[col] = createStyledCell(glyph, { fg, bold: true });
|
|
150
|
-
if (glyphWidth > 1 && col + 1 < width) {
|
|
151
|
-
line[col + 1] = createStyledCell('', { fg, bold: true });
|
|
152
|
-
}
|
|
153
|
-
}
|
|
154
|
-
|
|
155
|
-
/**
|
|
156
|
-
* Columns at which ancestor `│` gutters are drawn for a row at `depth`, given
|
|
157
|
-
* the set of ancestor depths whose subtrees are still open.
|
|
158
|
-
*
|
|
159
|
-
* Clamping can push two levels onto the same column at narrow widths; a gutter
|
|
160
|
-
* is emitted only when it lands strictly left of this row's own connector, so
|
|
161
|
-
* a clamped tree degrades by losing gutters rather than by overwriting the
|
|
162
|
-
* connector.
|
|
163
|
-
*/
|
|
164
|
-
function treeGutterCols(
|
|
165
|
-
openAncestorDepths: readonly number[],
|
|
166
|
-
depth: number,
|
|
167
|
-
width: number,
|
|
168
|
-
): number[] {
|
|
169
|
-
const ownCol = treeBranchCol(treeIndentCols(depth, width));
|
|
170
|
-
const cols: number[] = [];
|
|
171
|
-
for (const ancestorDepth of openAncestorDepths) {
|
|
172
|
-
const col = treeBranchCol(treeIndentCols(ancestorDepth, width));
|
|
173
|
-
if (col < ownCol) cols.push(col);
|
|
174
|
-
}
|
|
175
|
-
return cols;
|
|
176
|
-
}
|
|
177
|
-
|
|
178
|
-
/** True when a rail may claim this cell without destroying rendered content. */
|
|
179
|
-
function railCellIsFree(line: Line, col: number): boolean {
|
|
180
|
-
const cell = line[col];
|
|
181
|
-
if (!cell) return false;
|
|
182
|
-
return cell.char === ' ' && !cell.bg;
|
|
183
|
-
}
|
|
184
|
-
|
|
185
|
-
function writeRail(line: Line, col: number, glyph: string, fg: string, width: number, force: boolean): void {
|
|
186
|
-
if (col < 0 || col >= width) return;
|
|
187
|
-
if (!force && !railCellIsFree(line, col)) return;
|
|
188
|
-
line[col] = createStyledCell(glyph, { fg, dim: true });
|
|
189
|
-
}
|
|
190
|
-
|
|
191
|
-
/**
|
|
192
|
-
* Draw a row's connector and every rail that must pass through it, across ALL
|
|
193
|
-
* the lines the row emitted.
|
|
194
|
-
*
|
|
195
|
-
* Line 0 gets the connector in the row's own column (deliberately replacing
|
|
196
|
-
* whatever marker the row drew there — the connector IS that row's marker).
|
|
197
|
-
* Subsequent lines get `│` in that column while the row still has a sibling
|
|
198
|
-
* below it, so the rail runs unbroken from one `├` to the next. Every line
|
|
199
|
-
* additionally gets `│` in each open ancestor's gutter.
|
|
200
|
-
*
|
|
201
|
-
* Connectors and gutters are recomputed from live structure on every rebuild
|
|
202
|
-
* (see conversation-turn-structure.ts), never cached, so a row that stops being
|
|
203
|
-
* last flips `└`→`├` here with nothing stale to invalidate.
|
|
204
|
-
*/
|
|
205
|
-
export function drawTreeRails(
|
|
206
|
-
lines: readonly Line[],
|
|
207
|
-
depth: number,
|
|
208
|
-
connector: string | undefined,
|
|
209
|
-
openAncestorDepths: readonly number[],
|
|
210
|
-
width: number,
|
|
211
|
-
fg: string,
|
|
212
|
-
): void {
|
|
213
|
-
if (depth <= 0 || !connector || lines.length === 0) return;
|
|
214
|
-
const indent = treeIndentCols(depth, width);
|
|
215
|
-
if (indent <= 0) return;
|
|
216
|
-
const ownCol = treeBranchCol(indent);
|
|
217
|
-
const gutterCols = treeGutterCols(openAncestorDepths, depth, width);
|
|
218
|
-
const continuesBelow = connector === TREE_CONNECTOR_CONTINUES;
|
|
219
|
-
|
|
220
|
-
for (let i = 0; i < lines.length; i++) {
|
|
221
|
-
const line = lines[i]!;
|
|
222
|
-
for (const gutterCol of gutterCols) {
|
|
223
|
-
writeRail(line, gutterCol, TREE_RAIL, fg, width, false);
|
|
224
|
-
}
|
|
225
|
-
if (i === 0) writeRail(line, ownCol, connector, fg, width, true);
|
|
226
|
-
else if (continuesBelow) writeRail(line, ownCol, TREE_RAIL, fg, width, false);
|
|
227
|
-
}
|
|
228
|
-
}
|
|
@@ -1,78 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* agent-graph-composition.ts — the graph that runs agents.
|
|
3
|
-
*
|
|
4
|
-
* Six collaborators that are only meaningful as a set, so they are built as
|
|
5
|
-
* one: a message bus, the archetype loader, the orchestrator that executes a
|
|
6
|
-
* run, the manager that owns the records, the context-accounting holder, and
|
|
7
|
-
* the WRFC controller. Every one of them holds a reference to at least one
|
|
8
|
-
* other, and two of the links are circular — the orchestrator writes
|
|
9
|
-
* conversation snapshots back through the manager, and the manager drives the
|
|
10
|
-
* WRFC controller which was built from the manager. Assembled anywhere but in
|
|
11
|
-
* one place, a half-wired graph looks correct and silently drops either the
|
|
12
|
-
* snapshot bridge or the review loop.
|
|
13
|
-
*
|
|
14
|
-
* It is also the graph whose runs `cancelHostedAgentRuns` cancels at disposal:
|
|
15
|
-
* the manager returned here is the one the runtime hands to the SDK's
|
|
16
|
-
* `cancelAllAgentRuns`.
|
|
17
|
-
*/
|
|
18
|
-
import { join } from 'node:path';
|
|
19
|
-
import { AgentMessageBus, AgentOrchestrator, ArchetypeLoader, WrfcController } from '@pellux/goodvibes-sdk/platform/agents';
|
|
20
|
-
import { AgentManager, ContextAccountingHolder } from '@pellux/goodvibes-sdk/platform/tools';
|
|
21
|
-
import type { ConfigManager } from '@pellux/goodvibes-sdk/platform/config';
|
|
22
|
-
import type { ProviderRegistry } from '@pellux/goodvibes-sdk/platform/providers';
|
|
23
|
-
import type { RuntimeEventBus } from '@/runtime/index.ts';
|
|
24
|
-
|
|
25
|
-
export interface AgentGraph {
|
|
26
|
-
readonly agentMessageBus: AgentMessageBus;
|
|
27
|
-
readonly archetypeLoader: ArchetypeLoader;
|
|
28
|
-
readonly agentOrchestrator: AgentOrchestrator;
|
|
29
|
-
readonly agentManager: AgentManager;
|
|
30
|
-
readonly contextAccountingHolder: ContextAccountingHolder;
|
|
31
|
-
readonly wrfcController: WrfcController;
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
/** Build the agent-execution graph, fully wired in both directions. */
|
|
35
|
-
export function createAgentGraph(options: {
|
|
36
|
-
readonly runtimeBus: RuntimeEventBus;
|
|
37
|
-
readonly workingDirectory: string;
|
|
38
|
-
readonly configManager: ConfigManager;
|
|
39
|
-
readonly providerRegistry: ProviderRegistry;
|
|
40
|
-
}): AgentGraph {
|
|
41
|
-
const agentMessageBus = new AgentMessageBus();
|
|
42
|
-
agentMessageBus.setRuntimeBus(options.runtimeBus);
|
|
43
|
-
const archetypeLoader = new ArchetypeLoader(join(options.workingDirectory, '.goodvibes', 'agents'));
|
|
44
|
-
const agentOrchestrator = new AgentOrchestrator({
|
|
45
|
-
messageBus: agentMessageBus,
|
|
46
|
-
});
|
|
47
|
-
agentOrchestrator.setRuntimeBus(options.runtimeBus);
|
|
48
|
-
const agentManager = new AgentManager({
|
|
49
|
-
archetypeLoader,
|
|
50
|
-
messageBus: agentMessageBus,
|
|
51
|
-
executor: agentOrchestrator,
|
|
52
|
-
configManager: options.configManager,
|
|
53
|
-
// The live registry lets a bare model id in a spawn() override resolve
|
|
54
|
-
// through the shared resolver instead of being rejected as unqualified.
|
|
55
|
-
providerRegistry: options.providerRegistry,
|
|
56
|
-
});
|
|
57
|
-
const contextAccountingHolder = new ContextAccountingHolder();
|
|
58
|
-
// Conversation-snapshot bridge (mirrors the SDK's own createRuntimeServices).
|
|
59
|
-
agentOrchestrator.setConversationSink({
|
|
60
|
-
register: (agentId, source) => agentManager.registerConversationSource(agentId, source),
|
|
61
|
-
release: (agentId) => agentManager.releaseConversationSource(agentId),
|
|
62
|
-
});
|
|
63
|
-
agentManager.setRuntimeBus(options.runtimeBus);
|
|
64
|
-
const wrfcController = new WrfcController(options.runtimeBus, agentMessageBus, {
|
|
65
|
-
agentManager,
|
|
66
|
-
configManager: options.configManager,
|
|
67
|
-
projectRoot: options.workingDirectory,
|
|
68
|
-
});
|
|
69
|
-
agentManager.setWrfcController(wrfcController);
|
|
70
|
-
return {
|
|
71
|
-
agentMessageBus,
|
|
72
|
-
archetypeLoader,
|
|
73
|
-
agentOrchestrator,
|
|
74
|
-
agentManager,
|
|
75
|
-
contextAccountingHolder,
|
|
76
|
-
wrfcController,
|
|
77
|
-
};
|
|
78
|
-
}
|
|
@@ -1,46 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* channel-composition — route bindings, surface registry, and channel plugin
|
|
3
|
-
* registry for the TUI composition root (split out of services.ts for the
|
|
4
|
-
* line cap).
|
|
5
|
-
*
|
|
6
|
-
* RECORDED DIVERGENCE from the SDK composition root: SurfaceRegistry and
|
|
7
|
-
* ChannelPluginRegistry are constructed WITHOUT the gate manager. The SDK's
|
|
8
|
-
* surface gate map only names six surfaces (web/slack/discord/ntfy/webhook/
|
|
9
|
-
* homeassistant) and reads every other adapter (telegram, whatsapp, signal,
|
|
10
|
-
* imessage, msteams, ...) as OFF whenever a manager is present — no settings
|
|
11
|
-
* key could re-enable them. Until the gate map covers every adapter, the
|
|
12
|
-
* honest governing switch here stays the surfaces.<id>.enabled config each
|
|
13
|
-
* adapter already reads, exactly as the feature surface's own
|
|
14
|
-
* constant-binding rule states. RouteBindingManager keeps its manager — its
|
|
15
|
-
* route-binding gate is a real registry feature.
|
|
16
|
-
*/
|
|
17
|
-
|
|
18
|
-
import { AutomationRouteStore } from '@pellux/goodvibes-sdk/platform/automation';
|
|
19
|
-
import { ChannelPluginRegistry, RouteBindingManager, SurfaceRegistry } from '@pellux/goodvibes-sdk/platform/channels';
|
|
20
|
-
import type { ConfigManager } from '@pellux/goodvibes-sdk/platform/config';
|
|
21
|
-
import type { FeatureFlagManager, RuntimeEventBus } from '@/runtime/index.ts';
|
|
22
|
-
import type { RuntimeStore } from './store/index.ts';
|
|
23
|
-
|
|
24
|
-
export interface ChannelComposition {
|
|
25
|
-
readonly routeBindings: RouteBindingManager;
|
|
26
|
-
readonly surfaceRegistry: SurfaceRegistry;
|
|
27
|
-
readonly channelPlugins: ChannelPluginRegistry;
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
export function createChannelComposition(options: {
|
|
31
|
-
readonly configManager: ConfigManager;
|
|
32
|
-
readonly runtimeStore: RuntimeStore;
|
|
33
|
-
readonly runtimeBus: RuntimeEventBus;
|
|
34
|
-
readonly featureFlags: FeatureFlagManager;
|
|
35
|
-
}): ChannelComposition {
|
|
36
|
-
const routeBindings = new RouteBindingManager({
|
|
37
|
-
store: new AutomationRouteStore({ configManager: options.configManager }),
|
|
38
|
-
runtimeStore: options.runtimeStore,
|
|
39
|
-
runtimeBus: options.runtimeBus,
|
|
40
|
-
featureFlags: options.featureFlags,
|
|
41
|
-
});
|
|
42
|
-
const surfaceRegistry = new SurfaceRegistry(options.configManager, options.runtimeStore);
|
|
43
|
-
const channelPlugins = new ChannelPluginRegistry();
|
|
44
|
-
surfaceRegistry.attachPluginRegistry(channelPlugins);
|
|
45
|
-
return { routeBindings, surfaceRegistry, channelPlugins };
|
|
46
|
-
}
|
|
@@ -1,124 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* cluster-composition.ts — this daemon's seat in the LAN leader election.
|
|
3
|
-
*
|
|
4
|
-
* When the same goodvibes install runs more than once on one network — a
|
|
5
|
-
* laptop and a desktop, or two processes on one machine — every copy
|
|
6
|
-
* independently reads the shared inbox, so one message is picked up twice and
|
|
7
|
-
* answered twice. The SDK's cluster coordinator elects exactly one node to be
|
|
8
|
-
* responsible for inbound consumption; everything else stays warm and silent.
|
|
9
|
-
*
|
|
10
|
-
* This file exists because the goodvibes-tui daemon does NOT get that for free
|
|
11
|
-
* from the SDK facade. The facade gates the consumers IT owns (Telegram
|
|
12
|
-
* ingress, the ntfy/Slack/Discord provider runtime), but this repository
|
|
13
|
-
* composes an inbound consumer of its own — the Slack/Discord/email inbox
|
|
14
|
-
* poller in daemon/handlers/inbox — and the facade knows nothing about it.
|
|
15
|
-
* A fix that only landed in the facade would leave the poller double-reading
|
|
16
|
-
* on exactly the machine this product runs on.
|
|
17
|
-
*
|
|
18
|
-
* So this composition builds the ONE coordinator for the process, registers
|
|
19
|
-
* the inbox poller with it, and hands the same instance to the DaemonServer
|
|
20
|
-
* (via `DaemonConfig.clusterCoordinator`) so the SDK's consumers ride the same
|
|
21
|
-
* leadership rather than holding a second, competing election.
|
|
22
|
-
*
|
|
23
|
-
* What leadership does NOT gate, here or anywhere: outbound delivery,
|
|
24
|
-
* sessions, the control plane, the HTTP listener, the UI. A standby node is a
|
|
25
|
-
* complete goodvibes daemon that simply is not the one reading the inbox.
|
|
26
|
-
*/
|
|
27
|
-
import {
|
|
28
|
-
ClusterCoordinator,
|
|
29
|
-
inboxSurface,
|
|
30
|
-
readClusterSettings,
|
|
31
|
-
type ClusterConsumerGate,
|
|
32
|
-
type ClusterTransport,
|
|
33
|
-
} from '@pellux/goodvibes-sdk/platform/cluster';
|
|
34
|
-
import type { ConfigManager } from '@pellux/goodvibes-sdk/platform/config';
|
|
35
|
-
import type { ShellPathService } from '@/runtime/index.ts';
|
|
36
|
-
import { logger } from '@pellux/goodvibes-sdk/platform/utils';
|
|
37
|
-
import { GOODVIBES_TUI_SURFACE_ROOT } from '../config/surface.ts';
|
|
38
|
-
import { VERSION } from '../version.ts';
|
|
39
|
-
|
|
40
|
-
/** What an inbound poller must expose to be placed under leadership. */
|
|
41
|
-
export interface GatedPollerControl {
|
|
42
|
-
/** Begin polling. Must not resolve until polling has actually begun. */
|
|
43
|
-
start(): Promise<void>;
|
|
44
|
-
/** Stop polling. Must not resolve until no further poll can run. */
|
|
45
|
-
stop(): Promise<void>;
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
/**
|
|
49
|
-
* Build the process's single coordinator.
|
|
50
|
-
*
|
|
51
|
-
* Constructing it is inert: no socket is opened and no state is written until
|
|
52
|
-
* `start()` runs, so composing a runtime in a test never joins a network.
|
|
53
|
-
*
|
|
54
|
-
* The version is THIS BINARY's version, not the SDK package's — the same
|
|
55
|
-
* distinction daemon/cli.ts already makes for the self-update artifact. It is
|
|
56
|
-
* the first ranking tier, so getting it wrong would let a stale build hold the
|
|
57
|
-
* role through an update.
|
|
58
|
-
*/
|
|
59
|
-
export function createClusterComposition(options: {
|
|
60
|
-
/**
|
|
61
|
-
* Narrowed to what is actually read, which is exactly what
|
|
62
|
-
* `readClusterSettings` asks for. The daemon passes a whole ConfigManager;
|
|
63
|
-
* the handler context carries only this slice, and a test standing in a
|
|
64
|
-
* minimal config object should not have to fabricate the full fifty-odd
|
|
65
|
-
* members to compose a coordinator — a cast there would hide a real shape
|
|
66
|
-
* mismatch rather than document one.
|
|
67
|
-
*/
|
|
68
|
-
readonly configManager: Pick<ConfigManager, 'getCategory'>;
|
|
69
|
-
readonly shellPaths: ShellPathService;
|
|
70
|
-
/**
|
|
71
|
-
* The datagram transport to coordinate over.
|
|
72
|
-
*
|
|
73
|
-
* Supplied by the group layer (cluster-group-composition.ts), which owns the
|
|
74
|
-
* socket and wraps every election datagram in the group envelope, signed with
|
|
75
|
-
* the current group key. That is what stops a daemon belonging to somebody
|
|
76
|
-
* else on the same network from taking part in this election at all.
|
|
77
|
-
*
|
|
78
|
-
* Absent — the plain default — means the coordinator opens its own socket and
|
|
79
|
-
* coordinates with anything that answers on the configured port.
|
|
80
|
-
*/
|
|
81
|
-
readonly transport?: ClusterTransport | undefined;
|
|
82
|
-
}): ClusterCoordinator {
|
|
83
|
-
return new ClusterCoordinator({
|
|
84
|
-
settings: readClusterSettings(options.configManager),
|
|
85
|
-
version: VERSION,
|
|
86
|
-
// Surface-scoped, alongside this surface's other durable state: the node
|
|
87
|
-
// identity is per-surface and must not leak across surface roots.
|
|
88
|
-
stateDirectory: options.shellPaths.resolveProjectPath(GOODVIBES_TUI_SURFACE_ROOT, 'cluster'),
|
|
89
|
-
logger,
|
|
90
|
-
...(options.transport ? { transport: options.transport } : {}),
|
|
91
|
-
});
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
/**
|
|
95
|
-
* ONE inbox provider as a leadership gate.
|
|
96
|
-
*
|
|
97
|
-
* One gate per account, not one for the poller. Each inbox account is its own
|
|
98
|
-
* surface in the election, so this laptop can hold the work Slack account
|
|
99
|
-
* while the desktop holds the mailbox — and losing one machine moves only the
|
|
100
|
-
* accounts it was reading. A single gate covering the whole poller could not
|
|
101
|
-
* express that: it would hand every account over together, and a node with a
|
|
102
|
-
* credential for only one of them could never take part at all.
|
|
103
|
-
*
|
|
104
|
-
* The provider id is the surface's local discriminator and is hashed before it
|
|
105
|
-
* reaches the network, so what travels is a digest and not an account name.
|
|
106
|
-
*
|
|
107
|
-
* No replay cursor is threaded in, and that is deliberate rather than an
|
|
108
|
-
* omission: the inbox keeps a persisted per-provider cursor of its own
|
|
109
|
-
* (InboxCursorStore), so a node taking an account over resumes from where the
|
|
110
|
-
* previous one committed. ntfy needs an explicit `since=` because it has no
|
|
111
|
-
* server-side per-subscriber cursor; this poller does not.
|
|
112
|
-
*/
|
|
113
|
-
export function inboxPollerGate(providerId: string, control: GatedPollerControl): ClusterConsumerGate {
|
|
114
|
-
return {
|
|
115
|
-
id: `inbox-poller:${providerId}`,
|
|
116
|
-
surface: inboxSurface(providerId),
|
|
117
|
-
start: async () => {
|
|
118
|
-
await control.start();
|
|
119
|
-
},
|
|
120
|
-
stop: async () => {
|
|
121
|
-
await control.stop();
|
|
122
|
-
},
|
|
123
|
-
};
|
|
124
|
-
}
|