@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,210 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* session-recovery.ts — Journal replay at session resume.
|
|
3
|
-
*
|
|
4
|
-
* Purpose
|
|
5
|
-
* ───────
|
|
6
|
-
* When a session is resumed, this module checks whether a transcript journal
|
|
7
|
-
* exists for that session whose records post-date the loaded snapshot. If so,
|
|
8
|
-
* it replays those records onto the live conversation and writes a fresh
|
|
9
|
-
* snapshot so the gap is permanently closed.
|
|
10
|
-
*
|
|
11
|
-
* Seams (both must call replayJournalForSession)
|
|
12
|
-
* ───────────────────────────────────────────────
|
|
13
|
-
* 1. CLI / command resume — session-workflow.ts, after `fromJSON` +
|
|
14
|
-
* `rebuildHistory` complete. Handles --continue, --resume, /session resume,
|
|
15
|
-
* and --fork.
|
|
16
|
-
* 2. In-TUI panel resume — bootstrap-hook-bridge.ts
|
|
17
|
-
* `createResumeSessionHandler`, after `options.runtime.sessionId` is
|
|
18
|
-
* assigned. Handles the session browser / panel-driven resume.
|
|
19
|
-
*
|
|
20
|
-
* Recovery protocol
|
|
21
|
-
* ─────────────────
|
|
22
|
-
* 1. Call replayJournal() with the journal path and the snapshot timestamp.
|
|
23
|
-
* 2. If no records are newer than the snapshot, rotate the (now-stale)
|
|
24
|
-
* journal silently and return.
|
|
25
|
-
* 3. If records are found, apply the final record's messages — each journal
|
|
26
|
-
* record carries the full conversation snapshot at that moment, so the
|
|
27
|
-
* record with the newest timestamp is the authoritative post-crash state
|
|
28
|
-
* (resilient to seq collisions across re-inits onto a stale journal file).
|
|
29
|
-
* 4. Rebuild the conversation history and call the snapshot writer so the
|
|
30
|
-
* gap is durably closed before the user sees the restored conversation.
|
|
31
|
-
* 5. Rotate the journal (it is no longer needed as a gap-filler).
|
|
32
|
-
* 6. Return a result so the caller can emit an honest notice.
|
|
33
|
-
*/
|
|
34
|
-
|
|
35
|
-
import { journalPathFor, openTranscriptJournal, replayJournal } from './transcript-journal.ts';
|
|
36
|
-
import type { ConversationManager } from './conversation.ts';
|
|
37
|
-
import type { ConversationMessageSnapshot } from '@pellux/goodvibes-sdk/platform/core';
|
|
38
|
-
import type { SessionSurface } from '@/runtime/index.ts';
|
|
39
|
-
|
|
40
|
-
// ─── Types ──────────────────────────────────────────────────────────────────
|
|
41
|
-
|
|
42
|
-
export interface ReplayIntoConversationOptions {
|
|
43
|
-
/** Absolute path to the journal file for this session. */
|
|
44
|
-
readonly journalPath: string;
|
|
45
|
-
/**
|
|
46
|
-
* The `timestamp` field from the loaded session snapshot (SessionMeta).
|
|
47
|
-
* Only journal records with ts > snapshotTimestamp are replayed.
|
|
48
|
-
*/
|
|
49
|
-
readonly snapshotTimestamp: number;
|
|
50
|
-
/** The live conversation manager to mutate with replayed messages. */
|
|
51
|
-
readonly conversation: ConversationManager;
|
|
52
|
-
/** Session ID — used when creating the post-replay journal instance for rotate(). */
|
|
53
|
-
readonly sessionId: string;
|
|
54
|
-
/**
|
|
55
|
-
* Persist the restored conversation so the gap is durably closed.
|
|
56
|
-
* Called with the final replayed message list. Best-effort — failures
|
|
57
|
-
* are swallowed so recovery never hard-fails a resume.
|
|
58
|
-
*/
|
|
59
|
-
readonly persistSnapshot: (messages: ConversationMessageSnapshot[]) => void;
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
export interface ReplayIntoConversationResult {
|
|
63
|
-
/** Number of journal records that post-dated the snapshot. 0 if nothing to replay. */
|
|
64
|
-
readonly replayed: number;
|
|
65
|
-
/** True if the journal tail was corrupt (quarantined). */
|
|
66
|
-
readonly hadCorruptTail: boolean;
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
// ─── Public API ─────────────────────────────────────────────────────────────
|
|
70
|
-
|
|
71
|
-
/**
|
|
72
|
-
* Replay journal records newer than `snapshotTimestamp` onto `conversation`.
|
|
73
|
-
*
|
|
74
|
-
* Returns a result object so the caller can emit an appropriate notice.
|
|
75
|
-
* Never throws — all errors are swallowed to preserve the "best-effort"
|
|
76
|
-
* recovery contract.
|
|
77
|
-
*/
|
|
78
|
-
export function replayJournalIntoConversation(
|
|
79
|
-
options: ReplayIntoConversationOptions,
|
|
80
|
-
): ReplayIntoConversationResult {
|
|
81
|
-
const { journalPath, snapshotTimestamp, conversation, sessionId, persistSnapshot } = options;
|
|
82
|
-
|
|
83
|
-
try {
|
|
84
|
-
const { records, hadCorruptTail } = replayJournal(journalPath, snapshotTimestamp);
|
|
85
|
-
|
|
86
|
-
const journal = openTranscriptJournal(journalPath, sessionId);
|
|
87
|
-
|
|
88
|
-
if (records.length === 0) {
|
|
89
|
-
// Nothing to replay — rotate the (now-stale) journal silently.
|
|
90
|
-
journal.rotate();
|
|
91
|
-
return { replayed: 0, hadCorruptTail };
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
// Select the authoritative record by newest wall-clock timestamp (tie-broken
|
|
95
|
-
// by highest seq). Each record carries the full conversation snapshot at its
|
|
96
|
-
// moment, so the newest ts is by definition the most recent state. This is
|
|
97
|
-
// resilient to seq collisions that arise when a fresh process appends to a
|
|
98
|
-
// pre-existing, non-rotated journal: its records restart at seq 0 after the
|
|
99
|
-
// surviving old records, so "last by seq" could otherwise pick a stale one.
|
|
100
|
-
const lastRecord = records.reduce((newest, candidate) =>
|
|
101
|
-
candidate.ts > newest.ts ||
|
|
102
|
-
(candidate.ts === newest.ts && candidate.seq > newest.seq)
|
|
103
|
-
? candidate
|
|
104
|
-
: newest,
|
|
105
|
-
);
|
|
106
|
-
const replayedMessages = lastRecord.messages as ConversationMessageSnapshot[];
|
|
107
|
-
|
|
108
|
-
// Preserve the session identity (title/titleSource/branches/currentBranch)
|
|
109
|
-
// that the resume seam already hydrated onto the live conversation. Journal
|
|
110
|
-
// records carry only messages, so a bare fromJSON would blank the title and
|
|
111
|
-
// reset titleSource to the system default — and the next TURN_COMPLETED
|
|
112
|
-
// snapshot would then persist the empty title, making the loss permanent.
|
|
113
|
-
const preserved = conversation.toJSON();
|
|
114
|
-
conversation.fromJSON({
|
|
115
|
-
...preserved,
|
|
116
|
-
messages: replayedMessages as never[],
|
|
117
|
-
title: conversation.title,
|
|
118
|
-
titleSource: conversation.getTitleSource(),
|
|
119
|
-
});
|
|
120
|
-
conversation.rebuildHistory();
|
|
121
|
-
|
|
122
|
-
// Write a fresh snapshot so the gap is durably closed even if the
|
|
123
|
-
// process is killed again before the next turn-complete snapshot.
|
|
124
|
-
try {
|
|
125
|
-
persistSnapshot(replayedMessages);
|
|
126
|
-
} catch {
|
|
127
|
-
// Best-effort — never hard-fail recovery due to snapshot write failure.
|
|
128
|
-
}
|
|
129
|
-
|
|
130
|
-
// Rotate the journal — it is no longer needed as a gap-filler.
|
|
131
|
-
journal.rotate();
|
|
132
|
-
|
|
133
|
-
return { replayed: records.length, hadCorruptTail };
|
|
134
|
-
} catch {
|
|
135
|
-
// Absolute last-resort guard — recovery must never crash a resume.
|
|
136
|
-
return { replayed: 0, hadCorruptTail: false };
|
|
137
|
-
}
|
|
138
|
-
}
|
|
139
|
-
|
|
140
|
-
/**
|
|
141
|
-
* Build the journal path for a given session and home directory, then call
|
|
142
|
-
* replayJournalIntoConversation().
|
|
143
|
-
*
|
|
144
|
-
* Convenience wrapper used by session-workflow.ts so it does not need to
|
|
145
|
-
* import journalPathFor directly.
|
|
146
|
-
*/
|
|
147
|
-
export function replayJournalForSession(
|
|
148
|
-
options: Omit<ReplayIntoConversationOptions, 'journalPath'> & {
|
|
149
|
-
readonly surface: SessionSurface;
|
|
150
|
-
},
|
|
151
|
-
): ReplayIntoConversationResult {
|
|
152
|
-
const journalPath = journalPathFor(options.surface, options.sessionId);
|
|
153
|
-
return replayJournalIntoConversation({ ...options, journalPath });
|
|
154
|
-
}
|
|
155
|
-
|
|
156
|
-
// ─── Prompted crash-snapshot restore ────────────────────────────────────────
|
|
157
|
-
|
|
158
|
-
/** What a crash-recovery snapshot carries back from disk. */
|
|
159
|
-
export interface RecoverySnapshotPayload {
|
|
160
|
-
readonly messages: Array<Record<string, unknown>>;
|
|
161
|
-
readonly title?: string | undefined;
|
|
162
|
-
readonly titleSource?: string | undefined;
|
|
163
|
-
readonly timestamp?: number | undefined;
|
|
164
|
-
}
|
|
165
|
-
|
|
166
|
-
export interface ApplyRecoverySnapshotResult {
|
|
167
|
-
/** Messages the conversation holds once the snapshot (plus any journal tail) is in place. */
|
|
168
|
-
readonly messageCount: number;
|
|
169
|
-
/** Journal records that post-dated the snapshot and were folded in on top of it. */
|
|
170
|
-
readonly journalReplay: ReplayIntoConversationResult;
|
|
171
|
-
}
|
|
172
|
-
|
|
173
|
-
/**
|
|
174
|
-
* Apply a crash-recovery snapshot the user explicitly asked to resume.
|
|
175
|
-
*
|
|
176
|
-
* This is deliberately the same sequence `resumeSessionCore` runs for a saved
|
|
177
|
-
* session — reset, fromJSON, rebuildHistory, then fold in any journal records
|
|
178
|
-
* newer than the snapshot — with one difference: the messages come from the
|
|
179
|
-
* recovery file the SDK just handed back (`consumeRecovery`) instead of the
|
|
180
|
-
* session store, because a session that crashed before its first clean save
|
|
181
|
-
* has no entry in the store to load. Nothing here decides WHETHER to restore;
|
|
182
|
-
* the caller has already asked the user (see runtime/recovery-prompt.ts).
|
|
183
|
-
*/
|
|
184
|
-
export function applyRecoverySnapshot(options: {
|
|
185
|
-
readonly snapshot: RecoverySnapshotPayload;
|
|
186
|
-
readonly sessionId: string;
|
|
187
|
-
readonly conversation: ConversationManager;
|
|
188
|
-
readonly surface: SessionSurface;
|
|
189
|
-
readonly persistSnapshot: (messages: ConversationMessageSnapshot[]) => void;
|
|
190
|
-
}): ApplyRecoverySnapshotResult {
|
|
191
|
-
const { snapshot, sessionId, conversation, surface, persistSnapshot } = options;
|
|
192
|
-
|
|
193
|
-
conversation.resetAll();
|
|
194
|
-
conversation.fromJSON({
|
|
195
|
-
messages: snapshot.messages as never[],
|
|
196
|
-
title: snapshot.title,
|
|
197
|
-
titleSource: snapshot.titleSource as never,
|
|
198
|
-
});
|
|
199
|
-
conversation.rebuildHistory();
|
|
200
|
-
|
|
201
|
-
const journalReplay = replayJournalForSession({
|
|
202
|
-
surface,
|
|
203
|
-
sessionId,
|
|
204
|
-
snapshotTimestamp: snapshot.timestamp ?? 0,
|
|
205
|
-
conversation,
|
|
206
|
-
persistSnapshot,
|
|
207
|
-
});
|
|
208
|
-
|
|
209
|
-
return { messageCount: conversation.getMessageCount(), journalReplay };
|
|
210
|
-
}
|
package/src/core/stable-host.ts
DELETED
|
@@ -1,171 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* stable-host.ts — a stable name for printed/QR pairing links.
|
|
3
|
-
*
|
|
4
|
-
* The legacy resolution used the first non-internal IPv4 in enumeration order
|
|
5
|
-
* (see getLocalNetworkIp in management-utils.ts). That address is bound to the
|
|
6
|
-
* current DHCP lease: when the lease changes, every printed link and every QR
|
|
7
|
-
* that encoded it stops resolving. This module resolves a name that survives a
|
|
8
|
-
* lease change where one exists, and only falls back to a routable address when
|
|
9
|
-
* no stable name is available.
|
|
10
|
-
*
|
|
11
|
-
* Resolution ladder (highest preference first):
|
|
12
|
-
* 1. Tailscale MagicDNS name — preferred when tailscale is up. It resolves on
|
|
13
|
-
* and off the LAN and is never bound to a DHCP lease.
|
|
14
|
-
* 2. mDNS `<hostname>.local` — a LAN name a DHCP change does not break.
|
|
15
|
-
* 3. Gateway-routed interface address — the IPv4 on the default-route
|
|
16
|
-
* interface (not merely the first non-internal one, which can land on a
|
|
17
|
-
* bridge/VPN). The last resort; DHCP-bound.
|
|
18
|
-
* 4. Loopback — nothing routable enumerated.
|
|
19
|
-
*
|
|
20
|
-
* The resolver (resolveStableHost) is a pure function of injected inputs so the
|
|
21
|
-
* ladder is testable under mocked interface / tailscale states; the probes that
|
|
22
|
-
* gather those inputs are impure and bounded, and degrade to undefined rather
|
|
23
|
-
* than throw when a tool is missing or slow.
|
|
24
|
-
*/
|
|
25
|
-
import { execFileSync } from 'node:child_process';
|
|
26
|
-
import { hostname as osHostname, networkInterfaces } from 'node:os';
|
|
27
|
-
|
|
28
|
-
export type StableHostKind = 'tailscale-magicdns' | 'mdns-local' | 'gateway-interface' | 'loopback';
|
|
29
|
-
|
|
30
|
-
export interface TailscaleState {
|
|
31
|
-
/** BackendState === 'Running'. */
|
|
32
|
-
readonly up: boolean;
|
|
33
|
-
/** Self.DNSName from `tailscale status --json`, trailing dot stripped. */
|
|
34
|
-
readonly magicDnsName?: string | undefined;
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
export interface StableHostInputs {
|
|
38
|
-
/** os.hostname(), possibly an FQDN — the `.local` name derives from its first label. */
|
|
39
|
-
readonly hostname: string;
|
|
40
|
-
/** The routable IPv4 on the default-route interface, when known. */
|
|
41
|
-
readonly gatewayInterfaceIp?: string | undefined;
|
|
42
|
-
/** First non-internal IPv4 in enumeration order — the legacy fallback address. */
|
|
43
|
-
readonly firstNonInternalIp?: string | undefined;
|
|
44
|
-
/** Tailscale state, when the CLI is present and answered in time. */
|
|
45
|
-
readonly tailscale?: TailscaleState | undefined;
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
export interface ResolvedStableHost {
|
|
49
|
-
readonly host: string;
|
|
50
|
-
readonly kind: StableHostKind;
|
|
51
|
-
/** True when `host` is a name that survives a DHCP lease change. */
|
|
52
|
-
readonly stable: boolean;
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
function stripTrailingDot(name: string): string {
|
|
56
|
-
return name.replace(/\.+$/, '');
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
/** `<hostname>.local` from the first label of a hostname, or null when there is no usable label. */
|
|
60
|
-
export function mdnsLocalName(host: string): string | null {
|
|
61
|
-
const label = (host ?? '').trim().split('.')[0]?.trim();
|
|
62
|
-
if (!label || label.toLowerCase() === 'localhost') return null;
|
|
63
|
-
// Already a `.local` name (hostname was set to the mDNS form): keep it as-is.
|
|
64
|
-
if (host.trim().toLowerCase().endsWith('.local')) return stripTrailingDot(host.trim());
|
|
65
|
-
return `${label}.local`;
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
/**
|
|
69
|
-
* Resolve the stable host from injected inputs. Pure — no I/O — so the ladder is
|
|
70
|
-
* exercised directly under mocked interface / tailscale states.
|
|
71
|
-
*/
|
|
72
|
-
export function resolveStableHost(inputs: StableHostInputs): ResolvedStableHost {
|
|
73
|
-
const magic = inputs.tailscale?.up ? inputs.tailscale.magicDnsName?.trim() : undefined;
|
|
74
|
-
if (magic) return { host: stripTrailingDot(magic), kind: 'tailscale-magicdns', stable: true };
|
|
75
|
-
|
|
76
|
-
const local = mdnsLocalName(inputs.hostname);
|
|
77
|
-
if (local) return { host: local, kind: 'mdns-local', stable: true };
|
|
78
|
-
|
|
79
|
-
const routed = inputs.gatewayInterfaceIp?.trim() || inputs.firstNonInternalIp?.trim();
|
|
80
|
-
if (routed) return { host: routed, kind: 'gateway-interface', stable: false };
|
|
81
|
-
|
|
82
|
-
return { host: '127.0.0.1', kind: 'loopback', stable: false };
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
/** First non-internal IPv4 in enumeration order (the legacy fallback address). */
|
|
86
|
-
export function firstNonInternalIpv4(nets: ReturnType<typeof networkInterfaces>): string | undefined {
|
|
87
|
-
for (const name of Object.keys(nets)) {
|
|
88
|
-
for (const netInfo of nets[name] ?? []) {
|
|
89
|
-
if (netInfo.family === 'IPv4' && !netInfo.internal) return netInfo.address;
|
|
90
|
-
}
|
|
91
|
-
}
|
|
92
|
-
return undefined;
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
/** Parse the `src <ip>` field out of a Linux `ip route get` line. */
|
|
96
|
-
export function parseIpRouteSrc(output: string): string | undefined {
|
|
97
|
-
const match = /\bsrc\s+(\d+\.\d+\.\d+\.\d+)/.exec(output);
|
|
98
|
-
return match?.[1];
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
/** Parse `Self.DNSName` + running state out of `tailscale status --json` output. */
|
|
102
|
-
export function parseTailscaleStatus(json: string): TailscaleState | undefined {
|
|
103
|
-
try {
|
|
104
|
-
const parsed = JSON.parse(json) as { BackendState?: unknown; Self?: { DNSName?: unknown } };
|
|
105
|
-
const up = parsed.BackendState === 'Running';
|
|
106
|
-
const dnsName = typeof parsed.Self?.DNSName === 'string' ? stripTrailingDot(parsed.Self.DNSName) : undefined;
|
|
107
|
-
return { up, ...(dnsName ? { magicDnsName: dnsName } : {}) };
|
|
108
|
-
} catch {
|
|
109
|
-
return undefined;
|
|
110
|
-
}
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
function probeGatewayInterfaceIp(): string | undefined {
|
|
114
|
-
try {
|
|
115
|
-
const out = execFileSync('ip', ['route', 'get', '1.1.1.1'], { encoding: 'utf8', stdio: ['ignore', 'pipe', 'ignore'], timeout: 1500 });
|
|
116
|
-
return parseIpRouteSrc(out);
|
|
117
|
-
} catch {
|
|
118
|
-
return undefined;
|
|
119
|
-
}
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
function probeTailscaleState(): TailscaleState | undefined {
|
|
123
|
-
try {
|
|
124
|
-
const out = execFileSync('tailscale', ['status', '--json'], { encoding: 'utf8', stdio: ['ignore', 'pipe', 'ignore'], timeout: 1500 });
|
|
125
|
-
return parseTailscaleStatus(out);
|
|
126
|
-
} catch {
|
|
127
|
-
return undefined;
|
|
128
|
-
}
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
/** Gather the impure inputs the resolver needs, each bounded and failure-tolerant. */
|
|
132
|
-
export function probeStableHostInputs(): StableHostInputs {
|
|
133
|
-
let nets: ReturnType<typeof networkInterfaces> = {};
|
|
134
|
-
try {
|
|
135
|
-
nets = networkInterfaces();
|
|
136
|
-
} catch {
|
|
137
|
-
nets = {};
|
|
138
|
-
}
|
|
139
|
-
const first = firstNonInternalIpv4(nets);
|
|
140
|
-
const gateway = probeGatewayInterfaceIp();
|
|
141
|
-
const tailscale = probeTailscaleState();
|
|
142
|
-
return {
|
|
143
|
-
hostname: safeHostname(),
|
|
144
|
-
...(gateway ? { gatewayInterfaceIp: gateway } : {}),
|
|
145
|
-
...(first ? { firstNonInternalIp: first } : {}),
|
|
146
|
-
...(tailscale ? { tailscale } : {}),
|
|
147
|
-
};
|
|
148
|
-
}
|
|
149
|
-
|
|
150
|
-
function safeHostname(): string {
|
|
151
|
-
try {
|
|
152
|
-
return osHostname();
|
|
153
|
-
} catch {
|
|
154
|
-
return '';
|
|
155
|
-
}
|
|
156
|
-
}
|
|
157
|
-
|
|
158
|
-
/**
|
|
159
|
-
* The stable host for a printed/QR link given the endpoint's bind host. A
|
|
160
|
-
* wildcard bind (0.0.0.0 / ::) resolves through the ladder; an explicit bind
|
|
161
|
-
* host is honored as-is (loopback stays loopback). `probe` is injectable for
|
|
162
|
-
* tests.
|
|
163
|
-
*/
|
|
164
|
-
export function stableUrlHostForBindHost(
|
|
165
|
-
host: string,
|
|
166
|
-
probe: () => StableHostInputs = probeStableHostInputs,
|
|
167
|
-
): ResolvedStableHost {
|
|
168
|
-
if (host === '0.0.0.0' || host === '::') return resolveStableHost(probe());
|
|
169
|
-
const bound = host || '127.0.0.1';
|
|
170
|
-
return { host: bound, kind: bound === '127.0.0.1' ? 'loopback' : 'gateway-interface', stable: false };
|
|
171
|
-
}
|