@pellux/goodvibes-tui 1.27.0 → 2.0.1
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 +125 -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 +12 -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 +13 -80
- 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 +1 -1
- 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 +15 -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 -641
- 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 -58
- 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,274 +0,0 @@
|
|
|
1
|
-
// ---------------------------------------------------------------------------
|
|
2
|
-
// workstream-draft-store.ts — durable journal for not-yet-launched proposals
|
|
3
|
-
//
|
|
4
|
-
// A /workstream proposal (WorkstreamDraft, workstream-services.ts) is TUI-owned
|
|
5
|
-
// state the OrchestrationEngine has no concept of — its only creation entry
|
|
6
|
-
// point materializes a real, ticking workstream with no pre-launch "draft"
|
|
7
|
-
// stage (see that module's REALITY-WINS header). Earlier waves therefore held
|
|
8
|
-
// drafts in memory only, and a restart between create and launch silently lost
|
|
9
|
-
// them. This store journals each draft to disk so the plan-review gate survives
|
|
10
|
-
// a restart and is resumable: the same reshaped, approved proposal is still
|
|
11
|
-
// there to launch afterward.
|
|
12
|
-
//
|
|
13
|
-
// This is TUI-side persistence, NOT an engine feature — it sits ALONGSIDE the
|
|
14
|
-
// engine's own .goodvibes/orchestration/<id>.json workstream snapshots, under a
|
|
15
|
-
// drafts/ subdirectory, and is loaded by the command facade at construction the
|
|
16
|
-
// same way the engine's resumeAllFromDisk() reloads live workstreams. A draft
|
|
17
|
-
// is a pure-data object (id/task/spec/gate/proposal/provenance/approved), so a
|
|
18
|
-
// plain JSON round-trip is lossless.
|
|
19
|
-
//
|
|
20
|
-
// Every operation is guarded and NEVER throws: a missing directory, an
|
|
21
|
-
// unreadable or malformed file, or a write failure degrades to "that draft
|
|
22
|
-
// isn't there" rather than crashing session startup — mirroring the engine
|
|
23
|
-
// persistence layer's own quarantine-don't-propagate discipline.
|
|
24
|
-
//
|
|
25
|
-
// RECLAIM: `remove(id)` retires a draft the moment it is launched or cancelled,
|
|
26
|
-
// but a draft the user simply walks away from was never reclaimed by anything,
|
|
27
|
-
// so the directory grew forever. `loadAll()` — the recovery point, called once
|
|
28
|
-
// at command-facade construction — now also bounds the directory by BOTH an age
|
|
29
|
-
// TTL and a count cap, and reports what it reclaimed through `lastReclaim` /
|
|
30
|
-
// the `onReclaim` hook. Deletions are `rmSync(..., { force: true })`, so a file
|
|
31
|
-
// another process removed first is not an error: two concurrent `loadAll()`
|
|
32
|
-
// calls converge on the same surviving set.
|
|
33
|
-
// ---------------------------------------------------------------------------
|
|
34
|
-
|
|
35
|
-
import { mkdirSync, readdirSync, readFileSync, rmSync, statSync } from 'node:fs';
|
|
36
|
-
import { join } from 'node:path';
|
|
37
|
-
import { atomicWriteFileSync } from '@/config/atomic-write.ts';
|
|
38
|
-
import type { WorkstreamDraft } from './workstream-draft-types.ts';
|
|
39
|
-
|
|
40
|
-
/**
|
|
41
|
-
* Age TTL for an abandoned draft. A proposal that has sat un-launched and
|
|
42
|
-
* un-cancelled this long is not a plan the user is still reviewing; it is
|
|
43
|
-
* litter. Measured from the draft's own `createdAt`.
|
|
44
|
-
*/
|
|
45
|
-
export const WORKSTREAM_DRAFT_TTL_MS = 14 * 24 * 60 * 60 * 1000; // 14 days
|
|
46
|
-
|
|
47
|
-
/**
|
|
48
|
-
* Count cap on retained drafts: the newest this many survive, older ones are
|
|
49
|
-
* reclaimed oldest-first. Bounds the directory even if every draft is recent.
|
|
50
|
-
*/
|
|
51
|
-
export const WORKSTREAM_DRAFT_CAP = 50;
|
|
52
|
-
|
|
53
|
-
/**
|
|
54
|
-
* Minimum gap between reaps triggered by `save()`. `loadAll()` is the recovery
|
|
55
|
-
* point but runs once per session, so a session that stays open for days would
|
|
56
|
-
* otherwise never reap again. Every `save()` (draft created, reshaped, or
|
|
57
|
-
* approved) re-checks the bounds, throttled to this interval so the directory
|
|
58
|
-
* is not re-scanned on every keystroke-driven save.
|
|
59
|
-
*/
|
|
60
|
-
export const WORKSTREAM_DRAFT_SWEEP_INTERVAL_MS = 5 * 60 * 1000; // 5 minutes
|
|
61
|
-
|
|
62
|
-
/** What one `loadAll()` reclaimed. Counts only — never draft text. */
|
|
63
|
-
export interface WorkstreamDraftReclaim {
|
|
64
|
-
/** Unix ms of the sweep. */
|
|
65
|
-
readonly at: number;
|
|
66
|
-
/** Valid drafts removed because they aged past the TTL. */
|
|
67
|
-
readonly expired: number;
|
|
68
|
-
/** Valid drafts removed because they fell outside the count cap. */
|
|
69
|
-
readonly overCap: number;
|
|
70
|
-
/** Torn/malformed snapshots removed once they were older than the TTL. */
|
|
71
|
-
readonly unreadable: number;
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
export interface WorkstreamDraftStoreOptions {
|
|
75
|
-
/**
|
|
76
|
-
* Called after a `loadAll()` that reclaimed at least one file, so the count
|
|
77
|
-
* can be surfaced to the operator. Receives counts only. Never throws out of
|
|
78
|
-
* `loadAll()` — a failing hook is swallowed like every other side effect here.
|
|
79
|
-
*/
|
|
80
|
-
readonly onReclaim?: (summary: WorkstreamDraftReclaim) => void;
|
|
81
|
-
/** Clock seam (tests). Defaults to Date.now. */
|
|
82
|
-
readonly now?: () => number;
|
|
83
|
-
/** Override the age TTL (tests / embedders). Defaults to WORKSTREAM_DRAFT_TTL_MS. */
|
|
84
|
-
readonly ttlMs?: number;
|
|
85
|
-
/** Override the count cap (tests / embedders). Defaults to WORKSTREAM_DRAFT_CAP. */
|
|
86
|
-
readonly cap?: number;
|
|
87
|
-
/**
|
|
88
|
-
* Throttle for the reap that `save()` triggers. 0 or less means every save
|
|
89
|
-
* reaps (tests); defaults to WORKSTREAM_DRAFT_SWEEP_INTERVAL_MS.
|
|
90
|
-
*/
|
|
91
|
-
readonly sweepIntervalMs?: number;
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
export interface WorkstreamDraftStore {
|
|
95
|
-
/**
|
|
96
|
-
* Every valid draft on disk, oldest first, after reaping abandoned ones. A
|
|
97
|
-
* directory that doesn't exist yet ⇒ []. Malformed files are skipped, never
|
|
98
|
-
* fatal, and are only deleted once older than the TTL.
|
|
99
|
-
*/
|
|
100
|
-
loadAll(): WorkstreamDraft[];
|
|
101
|
-
/** Write (or overwrite) one draft's snapshot atomically. Silently no-ops on any I/O failure — a lost journal write must never break the in-memory flow. */
|
|
102
|
-
save(draft: WorkstreamDraft): void;
|
|
103
|
-
/** Delete one draft's snapshot (on launch or cancel). Missing file ⇒ no-op. */
|
|
104
|
-
remove(id: string): void;
|
|
105
|
-
/** Summary of the most recent `loadAll()` that reclaimed something; null otherwise. */
|
|
106
|
-
readonly lastReclaim: WorkstreamDraftReclaim | null;
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
/** Human-readable, content-free disclosure line for a reclaim summary. */
|
|
110
|
-
export function formatWorkstreamDraftReclaim(summary: WorkstreamDraftReclaim): string {
|
|
111
|
-
const parts: string[] = [];
|
|
112
|
-
if (summary.expired > 0) parts.push(`${summary.expired} abandoned`);
|
|
113
|
-
if (summary.overCap > 0) parts.push(`${summary.overCap} over the retention cap`);
|
|
114
|
-
if (summary.unreadable > 0) parts.push(`${summary.unreadable} unreadable`);
|
|
115
|
-
if (parts.length === 0) return 'Workstream drafts: nothing reclaimed.';
|
|
116
|
-
return `Workstream drafts: reclaimed ${parts.join(', ')} draft file(s).`;
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
/** Draft ids are `wsd_<hex>`; this refuses anything else so a crafted id can never escape the drafts directory. */
|
|
120
|
-
function isSafeId(id: string): boolean {
|
|
121
|
-
return /^[A-Za-z0-9_-]{1,64}$/.test(id);
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
function isDraftShape(value: unknown): value is WorkstreamDraft {
|
|
125
|
-
if (typeof value !== 'object' || value === null) return false;
|
|
126
|
-
const d = value as Record<string, unknown>;
|
|
127
|
-
return (
|
|
128
|
-
typeof d.id === 'string'
|
|
129
|
-
&& typeof d.task === 'string'
|
|
130
|
-
&& typeof d.approved === 'boolean'
|
|
131
|
-
&& typeof d.createdAt === 'number'
|
|
132
|
-
&& typeof d.spec === 'object' && d.spec !== null
|
|
133
|
-
&& Array.isArray((d.spec as Record<string, unknown>).items)
|
|
134
|
-
);
|
|
135
|
-
}
|
|
136
|
-
|
|
137
|
-
export function createWorkstreamDraftStore(
|
|
138
|
-
projectRoot: string,
|
|
139
|
-
options: WorkstreamDraftStoreOptions = {},
|
|
140
|
-
): WorkstreamDraftStore {
|
|
141
|
-
const dir = join(projectRoot, '.goodvibes', 'orchestration', 'drafts');
|
|
142
|
-
const fileFor = (id: string): string => join(dir, `${id}.json`);
|
|
143
|
-
const clock = options.now ?? Date.now;
|
|
144
|
-
const ttlMs = options.ttlMs ?? WORKSTREAM_DRAFT_TTL_MS;
|
|
145
|
-
const cap = options.cap ?? WORKSTREAM_DRAFT_CAP;
|
|
146
|
-
const sweepIntervalMs = options.sweepIntervalMs ?? WORKSTREAM_DRAFT_SWEEP_INTERVAL_MS;
|
|
147
|
-
let lastReclaim: WorkstreamDraftReclaim | null = null;
|
|
148
|
-
/** Unix ms of this instance's last reap; 0 means "never", so the first save sweeps. */
|
|
149
|
-
let lastSweepAt = 0;
|
|
150
|
-
|
|
151
|
-
/** Delete one path, treating "already gone" as success (concurrent sweeps). */
|
|
152
|
-
const discard = (path: string): void => {
|
|
153
|
-
try {
|
|
154
|
-
rmSync(path, { force: true });
|
|
155
|
-
} catch {
|
|
156
|
-
// Unremovable (permissions, or a racing process holding it) — the next
|
|
157
|
-
// loadAll() will try again; never fatal.
|
|
158
|
-
}
|
|
159
|
-
};
|
|
160
|
-
|
|
161
|
-
/** Age of a file by mtime, used only for snapshots whose contents we cannot trust. */
|
|
162
|
-
const modifiedBefore = (path: string, cutoff: number): boolean => {
|
|
163
|
-
try {
|
|
164
|
-
return statSync(path).mtimeMs < cutoff;
|
|
165
|
-
} catch {
|
|
166
|
-
return false;
|
|
167
|
-
}
|
|
168
|
-
};
|
|
169
|
-
|
|
170
|
-
/**
|
|
171
|
-
* Read every snapshot, reject the ones whose CONTENT is not a draft, apply
|
|
172
|
-
* both bounds, and record/announce what was reclaimed. Returns the surviving
|
|
173
|
-
* drafts, oldest first. Never throws.
|
|
174
|
-
*
|
|
175
|
-
* Idempotent: a second run over the same directory finds nothing left to
|
|
176
|
-
* remove, which is also what makes two processes running it at once safe —
|
|
177
|
-
* they converge on the same surviving set and unlink races count as done.
|
|
178
|
-
*/
|
|
179
|
-
const reap = (): WorkstreamDraft[] => {
|
|
180
|
-
let entries: string[];
|
|
181
|
-
try {
|
|
182
|
-
entries = readdirSync(dir);
|
|
183
|
-
} catch {
|
|
184
|
-
lastReclaim = null;
|
|
185
|
-
return []; // directory not created yet, or unreadable — nothing to resume
|
|
186
|
-
}
|
|
187
|
-
const now = clock();
|
|
188
|
-
lastSweepAt = now;
|
|
189
|
-
const cutoff = now - ttlMs;
|
|
190
|
-
const drafts: WorkstreamDraft[] = [];
|
|
191
|
-
let unreadable = 0;
|
|
192
|
-
for (const entry of entries) {
|
|
193
|
-
if (!entry.endsWith('.json')) continue;
|
|
194
|
-
const path = join(dir, entry);
|
|
195
|
-
let parsed: unknown;
|
|
196
|
-
try {
|
|
197
|
-
parsed = JSON.parse(readFileSync(path, 'utf8'));
|
|
198
|
-
} catch {
|
|
199
|
-
parsed = undefined;
|
|
200
|
-
}
|
|
201
|
-
// Validation is by CONTENT: a torn or half-written snapshot never
|
|
202
|
-
// becomes a draft. It is only DELETED once it is older than the TTL, so
|
|
203
|
-
// a file another process is writing right now is left alone.
|
|
204
|
-
if (parsed !== undefined && isDraftShape(parsed) && isSafeId(parsed.id)) {
|
|
205
|
-
drafts.push(parsed);
|
|
206
|
-
continue;
|
|
207
|
-
}
|
|
208
|
-
if (modifiedBefore(path, cutoff)) {
|
|
209
|
-
discard(path);
|
|
210
|
-
unreadable += 1;
|
|
211
|
-
}
|
|
212
|
-
}
|
|
213
|
-
drafts.sort((a, b) => a.createdAt - b.createdAt);
|
|
214
|
-
|
|
215
|
-
// Bound 1 — age TTL: an abandoned proposal is reclaimed.
|
|
216
|
-
const live: WorkstreamDraft[] = [];
|
|
217
|
-
let expired = 0;
|
|
218
|
-
for (const draft of drafts) {
|
|
219
|
-
if (now - draft.createdAt > ttlMs) {
|
|
220
|
-
discard(fileFor(draft.id));
|
|
221
|
-
expired += 1;
|
|
222
|
-
continue;
|
|
223
|
-
}
|
|
224
|
-
live.push(draft);
|
|
225
|
-
}
|
|
226
|
-
// Bound 2 — count cap: keep the newest `cap`, reclaim the oldest overflow.
|
|
227
|
-
const overCapCount = Math.max(0, live.length - cap);
|
|
228
|
-
for (const draft of live.slice(0, overCapCount)) discard(fileFor(draft.id));
|
|
229
|
-
const kept = live.slice(overCapCount);
|
|
230
|
-
|
|
231
|
-
if (expired + overCapCount + unreadable > 0) {
|
|
232
|
-
lastReclaim = { at: now, expired, overCap: overCapCount, unreadable };
|
|
233
|
-
try {
|
|
234
|
-
options.onReclaim?.(lastReclaim);
|
|
235
|
-
} catch {
|
|
236
|
-
// Disclosure must never take startup down.
|
|
237
|
-
}
|
|
238
|
-
} else {
|
|
239
|
-
lastReclaim = null;
|
|
240
|
-
}
|
|
241
|
-
return kept;
|
|
242
|
-
};
|
|
243
|
-
|
|
244
|
-
return {
|
|
245
|
-
get lastReclaim(): WorkstreamDraftReclaim | null {
|
|
246
|
-
return lastReclaim;
|
|
247
|
-
},
|
|
248
|
-
loadAll(): WorkstreamDraft[] {
|
|
249
|
-
return reap();
|
|
250
|
-
},
|
|
251
|
-
save(draft: WorkstreamDraft): void {
|
|
252
|
-
if (!isSafeId(draft.id)) return;
|
|
253
|
-
try {
|
|
254
|
-
mkdirSync(dir, { recursive: true });
|
|
255
|
-
// Atomic (temp + fsync + rename): a crash mid-save can no longer leave a
|
|
256
|
-
// truncated snapshot behind for loadAll() to reject.
|
|
257
|
-
atomicWriteFileSync(fileFor(draft.id), JSON.stringify(draft));
|
|
258
|
-
} catch {
|
|
259
|
-
// A failed journal write leaves the in-memory draft intact and usable;
|
|
260
|
-
// only its restart-durability is lost, which is strictly better than
|
|
261
|
-
// failing the edit the user just made.
|
|
262
|
-
}
|
|
263
|
-
// Keep reaping DURING the session, not only at the loadAll() recovery
|
|
264
|
-
// point: loadAll runs once at construction, so a long-lived session would
|
|
265
|
-
// otherwise never bound the directory again. Throttled, and always after
|
|
266
|
-
// this draft is on disk so the newest file is never the one reclaimed.
|
|
267
|
-
if (clock() - lastSweepAt >= sweepIntervalMs) reap();
|
|
268
|
-
},
|
|
269
|
-
remove(id: string): void {
|
|
270
|
-
if (!isSafeId(id)) return;
|
|
271
|
-
discard(fileFor(id));
|
|
272
|
-
},
|
|
273
|
-
};
|
|
274
|
-
}
|
|
@@ -1,42 +0,0 @@
|
|
|
1
|
-
// ---------------------------------------------------------------------------
|
|
2
|
-
// workstream-draft-types.ts — the not-yet-launched proposal's data shape
|
|
3
|
-
//
|
|
4
|
-
// Extracted from workstream-services.ts purely to give the durable draft store
|
|
5
|
-
// (workstream-draft-store.ts) a type to persist WITHOUT importing back into the
|
|
6
|
-
// service construction module — that back-edge would form an import cycle the
|
|
7
|
-
// architecture check rejects. workstream-services.ts re-exports both types, so
|
|
8
|
-
// every existing importer (the /workstream command, the tests) keeps importing
|
|
9
|
-
// them from there unchanged.
|
|
10
|
-
// ---------------------------------------------------------------------------
|
|
11
|
-
|
|
12
|
-
import type { CreateWorkstreamInput } from '@pellux/goodvibes-sdk/platform/orchestration';
|
|
13
|
-
import type { DecompositionGate, PlanProposal } from '@pellux/goodvibes-sdk/platform/core';
|
|
14
|
-
|
|
15
|
-
/**
|
|
16
|
-
* Honest provenance for how a draft's decomposition was produced. Derived from
|
|
17
|
-
* the SDK decomposition service's outcome so the draft render can state plainly
|
|
18
|
-
* whether a planning agent decomposed the goal, or the heuristic path did (and
|
|
19
|
-
* if so, why).
|
|
20
|
-
*/
|
|
21
|
-
export interface WorkstreamDraftProvenance {
|
|
22
|
-
readonly kind: 'agent' | 'heuristic-configured' | 'gate-declined' | 'fallback';
|
|
23
|
-
readonly itemCount: number;
|
|
24
|
-
readonly agentCostUsd?: number | undefined;
|
|
25
|
-
readonly agentTokens?: number | undefined;
|
|
26
|
-
readonly elapsedMs?: number | undefined;
|
|
27
|
-
readonly fallbackReason?: string | undefined;
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
/** A not-yet-launched /workstream proposal. TUI-owned (the engine has no draft concept) and journaled to disk via workstream-draft-store.ts so it survives a restart. See workstream-services.ts's header doc. */
|
|
31
|
-
export interface WorkstreamDraft {
|
|
32
|
-
readonly id: string;
|
|
33
|
-
task: string;
|
|
34
|
-
spec: CreateWorkstreamInput;
|
|
35
|
-
readonly gate: DecompositionGate;
|
|
36
|
-
/** The engine-agnostic decomposition proposal (model- or heuristic-produced). */
|
|
37
|
-
proposal: PlanProposal;
|
|
38
|
-
/** How that proposal came to be, for honest rendering. */
|
|
39
|
-
provenance: WorkstreamDraftProvenance;
|
|
40
|
-
approved: boolean;
|
|
41
|
-
readonly createdAt: number;
|
|
42
|
-
}
|