@pellux/goodvibes-tui 1.27.1 → 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 +116 -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 +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 +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,71 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Fallback chain visualization data builder.
|
|
3
|
-
*
|
|
4
|
-
* Converts the raw fallback chain from ModelDomainState and current
|
|
5
|
-
* provider health records into a structured FallbackChainData snapshot
|
|
6
|
-
* suitable for UI rendering.
|
|
7
|
-
*/
|
|
8
|
-
import type { ModelDomainState } from '@/runtime/index.ts';
|
|
9
|
-
import type { ProviderHealthDomainState } from '@/runtime/index.ts';
|
|
10
|
-
import type { FallbackChainData, FallbackChainNode } from '@/runtime/index.ts';
|
|
11
|
-
|
|
12
|
-
/**
|
|
13
|
-
* Build a FallbackChainData snapshot from the current model and health state.
|
|
14
|
-
*
|
|
15
|
-
* The primary model is always node 0. Each entry in ModelDomainState.fallbackChain
|
|
16
|
-
* becomes a subsequent node. Health status is enriched from the provider health domain.
|
|
17
|
-
*
|
|
18
|
-
* @param modelState - Current model domain state.
|
|
19
|
-
* @param healthState - Current provider health domain state.
|
|
20
|
-
* @returns Immutable FallbackChainData for visualization.
|
|
21
|
-
*/
|
|
22
|
-
export function buildFallbackChainData(
|
|
23
|
-
modelState: ModelDomainState,
|
|
24
|
-
healthState: ProviderHealthDomainState,
|
|
25
|
-
): FallbackChainData {
|
|
26
|
-
const nodes: FallbackChainNode[] = [];
|
|
27
|
-
|
|
28
|
-
// Node 0 — primary (active model)
|
|
29
|
-
const primaryRecord = healthState.providers.get(modelState.activeProviderId);
|
|
30
|
-
nodes.push({
|
|
31
|
-
registryKey: `${modelState.activeProviderId}:${modelState.activeModelId}`,
|
|
32
|
-
providerId: modelState.activeProviderId,
|
|
33
|
-
modelId: modelState.activeModelId,
|
|
34
|
-
displayName: modelState.displayName,
|
|
35
|
-
position: 0,
|
|
36
|
-
isCurrent: modelState.activeFallbackIndex === -1,
|
|
37
|
-
providerStatus: primaryRecord?.status ?? 'unknown',
|
|
38
|
-
reason: undefined,
|
|
39
|
-
});
|
|
40
|
-
|
|
41
|
-
// Nodes 1..N — fallback chain entries
|
|
42
|
-
for (let i = 0; i < modelState.fallbackChain.length; i++) {
|
|
43
|
-
const entry = modelState.fallbackChain[i];
|
|
44
|
-
const record = healthState.providers.get(entry.providerId);
|
|
45
|
-
nodes.push({
|
|
46
|
-
registryKey: `${entry.providerId}:${entry.modelId}`,
|
|
47
|
-
providerId: entry.providerId,
|
|
48
|
-
modelId: entry.modelId,
|
|
49
|
-
displayName: entry.displayName,
|
|
50
|
-
position: i + 1,
|
|
51
|
-
isCurrent: modelState.activeFallbackIndex === i,
|
|
52
|
-
providerStatus: record?.status ?? 'unknown',
|
|
53
|
-
reason: entry.reason,
|
|
54
|
-
});
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
const hasUnhealthyNode = nodes.some(
|
|
58
|
-
(n) =>
|
|
59
|
-
n.providerStatus === 'degraded' ||
|
|
60
|
-
n.providerStatus === 'rate_limited' ||
|
|
61
|
-
n.providerStatus === 'unavailable' ||
|
|
62
|
-
n.providerStatus === 'auth_error',
|
|
63
|
-
);
|
|
64
|
-
|
|
65
|
-
return {
|
|
66
|
-
nodes,
|
|
67
|
-
activeIndex: modelState.activeFallbackIndex,
|
|
68
|
-
falloverCount: modelState.falloverCount,
|
|
69
|
-
hasUnhealthyNode,
|
|
70
|
-
};
|
|
71
|
-
}
|
|
@@ -1,46 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Provider health UI data surface barrel.
|
|
3
|
-
*
|
|
4
|
-
* Re-exports all types and the ProviderHealthDataProvider class.
|
|
5
|
-
* Also provides the createProviderHealthData() factory for one-shot snapshots.
|
|
6
|
-
*/
|
|
7
|
-
export type {
|
|
8
|
-
ProviderStatus,
|
|
9
|
-
CompositeHealthStatus,
|
|
10
|
-
HealthTimelinePoint,
|
|
11
|
-
HealthTimeline,
|
|
12
|
-
ProviderHealthEntry,
|
|
13
|
-
FallbackChainNode,
|
|
14
|
-
FallbackChainData,
|
|
15
|
-
ProviderHealthData,
|
|
16
|
-
} from '@/runtime/index.ts';
|
|
17
|
-
|
|
18
|
-
export { ProviderHealthDataProvider } from '@/runtime/index.ts';
|
|
19
|
-
export { buildFallbackChainData } from '@/runtime/index.ts';
|
|
20
|
-
|
|
21
|
-
import type { ProviderHealthDomainState } from '@/runtime/index.ts';
|
|
22
|
-
import type { ModelDomainState } from '@/runtime/index.ts';
|
|
23
|
-
import { ProviderHealthDataProvider } from '@/runtime/index.ts';
|
|
24
|
-
import type { ProviderHealthData } from '@/runtime/index.ts';
|
|
25
|
-
|
|
26
|
-
/**
|
|
27
|
-
* Produce a one-shot ProviderHealthData snapshot without creating a long-lived provider.
|
|
28
|
-
*
|
|
29
|
-
* Use this when you need a single render pass and do not require change subscriptions.
|
|
30
|
-
* For reactive/subscription-based UIs, prefer ProviderHealthDataProvider.
|
|
31
|
-
*
|
|
32
|
-
* @param healthState - Current provider health domain state.
|
|
33
|
-
* @param modelState - Current model domain state.
|
|
34
|
-
* @returns Immutable ProviderHealthData snapshot.
|
|
35
|
-
*/
|
|
36
|
-
export function createProviderHealthData(
|
|
37
|
-
healthState: ProviderHealthDomainState,
|
|
38
|
-
modelState: ModelDomainState,
|
|
39
|
-
): ProviderHealthData {
|
|
40
|
-
// Delegate to the data provider for consistent derivation logic,
|
|
41
|
-
// then dispose immediately since no subscriptions are needed.
|
|
42
|
-
const dp = new ProviderHealthDataProvider(healthState, modelState);
|
|
43
|
-
const snapshot = dp.getSnapshot();
|
|
44
|
-
dp.dispose();
|
|
45
|
-
return snapshot;
|
|
46
|
-
}
|
|
@@ -1,146 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Provider health UI data types.
|
|
3
|
-
*
|
|
4
|
-
* Purely data-oriented — no rendering logic. These types are produced by
|
|
5
|
-
* ProviderHealthDataProvider and consumed by renderers/components.
|
|
6
|
-
*/
|
|
7
|
-
import type { ProviderStatus, CompositeHealthStatus } from '@/runtime/index.ts';
|
|
8
|
-
|
|
9
|
-
// Re-exports for convenience
|
|
10
|
-
export type { ProviderStatus, CompositeHealthStatus };
|
|
11
|
-
|
|
12
|
-
/**
|
|
13
|
-
* A single point in a provider health timeline.
|
|
14
|
-
* Used to render charts of success rate, latency, or error rate over time.
|
|
15
|
-
*/
|
|
16
|
-
export interface HealthTimelinePoint {
|
|
17
|
-
/** Epoch ms timestamp of this sample. */
|
|
18
|
-
readonly ts: number;
|
|
19
|
-
/** Observed success rate at this point (0–1). */
|
|
20
|
-
readonly successRate: number;
|
|
21
|
-
/** Observed average latency in ms at this point. */
|
|
22
|
-
readonly avgLatencyMs: number;
|
|
23
|
-
/** Observed error rate at this point (0–1). */
|
|
24
|
-
readonly errorRate: number;
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
/**
|
|
28
|
-
* Timeline data for a single provider, for chart rendering.
|
|
29
|
-
*/
|
|
30
|
-
export interface HealthTimeline {
|
|
31
|
-
/** Provider ID this timeline belongs to. */
|
|
32
|
-
readonly providerId: string;
|
|
33
|
-
/** Ordered timeline points (oldest first). */
|
|
34
|
-
readonly points: readonly HealthTimelinePoint[];
|
|
35
|
-
/** The number of points retained in this timeline. */
|
|
36
|
-
readonly length: number;
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
/**
|
|
40
|
-
* Full health entry for a single provider, enriched for UI consumption.
|
|
41
|
-
*/
|
|
42
|
-
export interface ProviderHealthEntry {
|
|
43
|
-
// ── Identity ──────────────────────────────────────────────────────────────
|
|
44
|
-
/** Provider identifier. */
|
|
45
|
-
readonly providerId: string;
|
|
46
|
-
/** Human-readable provider name. */
|
|
47
|
-
readonly displayName: string;
|
|
48
|
-
|
|
49
|
-
// ── Status ────────────────────────────────────────────────────────────────
|
|
50
|
-
/** Current health status. */
|
|
51
|
-
readonly status: ProviderStatus;
|
|
52
|
-
/** True when this provider is the active selection. */
|
|
53
|
-
readonly isActive: boolean;
|
|
54
|
-
/** True when this provider is configured with a valid API key. */
|
|
55
|
-
readonly isConfigured: boolean;
|
|
56
|
-
|
|
57
|
-
// ── Performance metrics ───────────────────────────────────────────────────
|
|
58
|
-
/** Success rate (0–1), derived from totalCalls and successCalls. */
|
|
59
|
-
readonly successRate: number;
|
|
60
|
-
/** Error rate (0–1), derived from totalCalls and errorCalls. */
|
|
61
|
-
readonly errorRate: number;
|
|
62
|
-
/** Approximate p95 latency in ms (max of recent observations). */
|
|
63
|
-
readonly p95LatencyMs: number;
|
|
64
|
-
/** Moving average latency in ms. */
|
|
65
|
-
readonly avgLatencyMs: number;
|
|
66
|
-
/** Total API calls recorded. */
|
|
67
|
-
readonly totalCalls: number;
|
|
68
|
-
|
|
69
|
-
// ── Cache metrics ─────────────────────────────────────────────────────────
|
|
70
|
-
/** Cache hit rate (0–1). Present only when cache metrics are available. */
|
|
71
|
-
readonly cacheHitRate?: number;
|
|
72
|
-
/** Cumulative cache read tokens saved. */
|
|
73
|
-
readonly cacheReadTokens?: number;
|
|
74
|
-
/** Cumulative cache write tokens. */
|
|
75
|
-
readonly cacheWriteTokens?: number;
|
|
76
|
-
|
|
77
|
-
// ── Timing ────────────────────────────────────────────────────────────────
|
|
78
|
-
/** Epoch ms of the last successful call, if any. */
|
|
79
|
-
readonly lastSuccessAt?: number;
|
|
80
|
-
/** Epoch ms of the last error, if any. */
|
|
81
|
-
readonly lastErrorAt?: number;
|
|
82
|
-
/** Most recent error message, if any. */
|
|
83
|
-
readonly lastErrorMessage?: string;
|
|
84
|
-
/** Epoch ms of the last health check. */
|
|
85
|
-
readonly lastCheckedAt?: number;
|
|
86
|
-
/** Rate limit reset time (epoch ms), if currently rate-limited. */
|
|
87
|
-
readonly rateLimitResetAt?: number;
|
|
88
|
-
|
|
89
|
-
// ── Timeline ──────────────────────────────────────────────────────────────
|
|
90
|
-
/** Timeline data for chart rendering. */
|
|
91
|
-
readonly timeline: HealthTimeline;
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
/**
|
|
95
|
-
* A single node in the fallback chain visualization.
|
|
96
|
-
*/
|
|
97
|
-
export interface FallbackChainNode {
|
|
98
|
-
/** Provider identifier. */
|
|
99
|
-
readonly providerId: string;
|
|
100
|
-
/** Model identifier on this provider. */
|
|
101
|
-
readonly modelId: string;
|
|
102
|
-
/** Human-readable display label. */
|
|
103
|
-
readonly displayName: string;
|
|
104
|
-
/** Position in the chain (0 = primary). */
|
|
105
|
-
readonly position: number;
|
|
106
|
-
/** Whether this node is the currently active entry in the chain. */
|
|
107
|
-
readonly isCurrent: boolean;
|
|
108
|
-
/** Current health status of this provider. */
|
|
109
|
-
readonly providerStatus: ProviderStatus;
|
|
110
|
-
/** Reason this fallback was configured. */
|
|
111
|
-
readonly reason?: string;
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
/**
|
|
115
|
-
* Fallback chain visualization data for the current model configuration.
|
|
116
|
-
*/
|
|
117
|
-
export interface FallbackChainData {
|
|
118
|
-
/** Ordered nodes in the fallback chain (primary first). */
|
|
119
|
-
readonly nodes: readonly FallbackChainNode[];
|
|
120
|
-
/** Index of the currently active node (-1 = primary is active). */
|
|
121
|
-
readonly activeIndex: number;
|
|
122
|
-
/** Number of fallover events since session start. */
|
|
123
|
-
readonly falloverCount: number;
|
|
124
|
-
/** True when the chain has at least one degraded or unavailable node. */
|
|
125
|
-
readonly hasUnhealthyNode: boolean;
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
/**
|
|
129
|
-
* Complete data snapshot produced by ProviderHealthDataProvider.
|
|
130
|
-
*/
|
|
131
|
-
export interface ProviderHealthData {
|
|
132
|
-
/** All provider health entries, sorted by status priority then name. */
|
|
133
|
-
readonly entries: readonly ProviderHealthEntry[];
|
|
134
|
-
/** Composite health status across all providers. */
|
|
135
|
-
readonly compositeStatus: CompositeHealthStatus;
|
|
136
|
-
/** Number of providers currently in a non-healthy state. */
|
|
137
|
-
readonly degradedCount: number;
|
|
138
|
-
/** Number of providers currently unavailable. */
|
|
139
|
-
readonly unavailableCount: number;
|
|
140
|
-
/** Fallback chain visualization data. */
|
|
141
|
-
readonly fallbackChain: FallbackChainData;
|
|
142
|
-
/** Warning messages from provider discovery. */
|
|
143
|
-
readonly warnings: readonly string[];
|
|
144
|
-
/** Epoch ms when this snapshot was produced. */
|
|
145
|
-
readonly snapshotAt: number;
|
|
146
|
-
}
|
package/src/runtime/ui-events.ts
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export * from '@/runtime/index.ts';
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export * from '@/runtime/index.ts';
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export * from '@/runtime/index.ts';
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export * from '@/runtime/index.ts';
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export * from '@/runtime/index.ts';
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export * from '@/runtime/index.ts';
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export * from '@/runtime/index.ts';
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export * from '@/runtime/index.ts';
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export * from '@/runtime/index.ts';
|
|
@@ -1,98 +0,0 @@
|
|
|
1
|
-
// ---------------------------------------------------------------------------
|
|
2
|
-
// voice-setup-services.ts — managed local-voice provisioning composition (TUI wiring)
|
|
3
|
-
//
|
|
4
|
-
// Backs the daemon's voice.local.status / voice.local.install verbs. The
|
|
5
|
-
// provisioning policy — a single-flight one-act install that provisions the
|
|
6
|
-
// piper engine + a default voice (and whisper STT where a bundle is published),
|
|
7
|
-
// live install-progress folded onto status(), ownership-aware preconfigure of
|
|
8
|
-
// the voice.local.* keys (values THIS installer previously wrote update to the
|
|
9
|
-
// new managed paths; genuinely user-set values still win; a user-cleared
|
|
10
|
-
// installer value stays cleared), a no-network status() read, and critical-tier
|
|
11
|
-
// admission gating — lives in the SDK's createVoiceSetupService. Earlier the
|
|
12
|
-
// composer was not exported, so the TUI rebuilt it from the voice primitives;
|
|
13
|
-
// SDK 1.10.1 exports it through ./platform/runtime/voice-setup, so this module
|
|
14
|
-
// is now a thin adapter that maps the TUI's injected seams (configManager,
|
|
15
|
-
// shellPaths, voiceProviders) onto the SDK service's flat deps.
|
|
16
|
-
//
|
|
17
|
-
// Extracted into its own module rather than built inline in services.ts, which
|
|
18
|
-
// sits at the architecture check's 800-line cap (scripts/check-architecture.ts)
|
|
19
|
-
// — new service construction gets its own module and a single wiring call there.
|
|
20
|
-
// ---------------------------------------------------------------------------
|
|
21
|
-
|
|
22
|
-
import {
|
|
23
|
-
createVoiceSetupService,
|
|
24
|
-
type VoiceSetupService,
|
|
25
|
-
} from '@pellux/goodvibes-sdk/platform/runtime/voice-setup';
|
|
26
|
-
import {
|
|
27
|
-
startWakeBootProvisioning,
|
|
28
|
-
type VoiceProviderRegistry,
|
|
29
|
-
} from '@pellux/goodvibes-sdk/platform/voice';
|
|
30
|
-
import type { ConfigManager } from '@pellux/goodvibes-sdk/platform/config';
|
|
31
|
-
import { logger } from '@pellux/goodvibes-sdk/platform/utils';
|
|
32
|
-
import type { ShellPathService } from '@/runtime/index.ts';
|
|
33
|
-
|
|
34
|
-
export type { VoiceSetupService };
|
|
35
|
-
|
|
36
|
-
/**
|
|
37
|
-
* The recovery act this surface names when a boot provision degrades. The SDK
|
|
38
|
-
* would otherwise name the control-plane verb, which is correct everywhere and
|
|
39
|
-
* useless to someone sitting in a terminal.
|
|
40
|
-
*/
|
|
41
|
-
export const WAKE_RECOVERY_COMMAND = '/voice wake setup';
|
|
42
|
-
|
|
43
|
-
export interface VoiceSetupServicesDeps {
|
|
44
|
-
readonly configManager: ConfigManager;
|
|
45
|
-
readonly shellPaths: Pick<ShellPathService, 'resolveUserPath'>;
|
|
46
|
-
readonly voiceProviders: VoiceProviderRegistry;
|
|
47
|
-
/** Critical-tier admission gate — a provision run allocates archive + model buffers. */
|
|
48
|
-
readonly admitExpensiveWork: (label: string) => { allowed: boolean; reason?: string | undefined };
|
|
49
|
-
/**
|
|
50
|
-
* Opt into boot-time wake-model provisioning and the recovery sweeper.
|
|
51
|
-
*
|
|
52
|
-
* Off unless a real entrypoint asks for it, matching how this graph treats the
|
|
53
|
-
* host power seam: `daemon/cli.ts` and `runtime/bootstrap-core.ts` opt in, the
|
|
54
|
-
* one-shot CLI commands do not, and a test composing the graph gets neither a
|
|
55
|
-
* network fetch nor a repeating timer it did not ask for.
|
|
56
|
-
*/
|
|
57
|
-
readonly provisionWakeModelsAtBoot?: boolean | undefined;
|
|
58
|
-
/** Injected in tests: the boot starter, so no sweeper and no fetch are real. */
|
|
59
|
-
readonly startBootProvisioning?: typeof startWakeBootProvisioning | undefined;
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
export interface VoiceSetupServices {
|
|
63
|
-
readonly voiceSetup: VoiceSetupService;
|
|
64
|
-
/**
|
|
65
|
-
* Stop the wake-word recovery sweeper and cancel a pending boot provision.
|
|
66
|
-
* A no-op when boot provisioning was not opted into. Registered on the
|
|
67
|
-
* disposal scope (disposal-wiring.ts) — an hourly timer nothing stops is a
|
|
68
|
-
* poller this surface leaked, which is exactly what that scope exists for.
|
|
69
|
-
*/
|
|
70
|
-
readonly stopWakeHousekeeping: () => void;
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
/** Compose the managed-voice single-flight install + no-network status read. */
|
|
74
|
-
export function wireVoiceSetup(deps: VoiceSetupServicesDeps): VoiceSetupServices {
|
|
75
|
-
const { configManager, voiceProviders } = deps;
|
|
76
|
-
const managedVoiceRoot = deps.shellPaths.resolveUserPath('voice');
|
|
77
|
-
const voiceSetup = createVoiceSetupService({
|
|
78
|
-
managedVoiceRoot,
|
|
79
|
-
getConfig: (key) => String(configManager.get(key as Parameters<typeof configManager.get>[0]) ?? ''),
|
|
80
|
-
setConfig: (key, value) => configManager.setDynamic(key as Parameters<typeof configManager.setDynamic>[0], value),
|
|
81
|
-
// A successful (re-)install clears any tripped local-engine breaker.
|
|
82
|
-
resetLocalEngineFailureState: () => voiceProviders.get('local')?.resetEngineFailureState?.(),
|
|
83
|
-
admitExpensiveWork: deps.admitExpensiveWork,
|
|
84
|
-
});
|
|
85
|
-
if (deps.provisionWakeModelsAtBoot !== true) {
|
|
86
|
-
return { voiceSetup, stopWakeHousekeeping: () => {} };
|
|
87
|
-
}
|
|
88
|
-
// Sweep the wake tree, then fetch whatever the install could not. The SDK owns
|
|
89
|
-
// the policy — never throws, one plain message, reaps before it retries — and
|
|
90
|
-
// routes the attempt through the setup service's single flight so a boot
|
|
91
|
-
// attempt and a user typing /voice wake setup are one download.
|
|
92
|
-
const boot = (deps.startBootProvisioning ?? startWakeBootProvisioning)({
|
|
93
|
-
managedRoot: managedVoiceRoot,
|
|
94
|
-
ensureProvisioned: () => voiceSetup.wakeEnsureProvisioned({ recoveryHint: WAKE_RECOVERY_COMMAND }),
|
|
95
|
-
announce: (message) => { logger.info(message); },
|
|
96
|
-
});
|
|
97
|
-
return { voiceSetup, stopWakeHousekeeping: () => boot.stop() };
|
|
98
|
-
}
|
|
@@ -1,77 +0,0 @@
|
|
|
1
|
-
// ---------------------------------------------------------------------------
|
|
2
|
-
// workstream-attempts-validation.ts — plan-format validation for best-of-N.
|
|
3
|
-
//
|
|
4
|
-
// The plan format re-enables the per-item `attempts` field (SDK WorkItem/
|
|
5
|
-
// WorkItemSpec.attempts — best-of-N). A best-of-N item MAY be non-leaf: it may
|
|
6
|
-
// declare its own `dependsOn` (each sibling inherits it) and other items may
|
|
7
|
-
// depend on it — a dependent is held by the dependency gate until the group's
|
|
8
|
-
// winner is picked and merged, then resolves to that winner (SDK
|
|
9
|
-
// WorkItemSpec.attempts doc). The TUI enforces the engine's genuine constraints
|
|
10
|
-
// at plan validation rather than letting a launch silently drop the field:
|
|
11
|
-
// • WORKTREE isolation. Best-of-N needs isolated worktrees to run and compare
|
|
12
|
-
// the N sibling attempts; under `shared` isolation the value is ignored.
|
|
13
|
-
// • STABLE id when depended upon. A dependency edge references an id, so a
|
|
14
|
-
// best-of-N item that others depend on must carry a stable `id`; an
|
|
15
|
-
// anonymous best-of-N item stays a leaf by construction (nothing can name it).
|
|
16
|
-
// Values above the engine's MAX_ATTEMPTS (5) are clamped by the engine; the TUI
|
|
17
|
-
// surfaces that as a note so the preview never overstates the fan-out.
|
|
18
|
-
// ---------------------------------------------------------------------------
|
|
19
|
-
|
|
20
|
-
import type { CreateWorkstreamInput } from '@pellux/goodvibes-sdk/platform/orchestration';
|
|
21
|
-
|
|
22
|
-
/** The engine's hard cap on sibling attempts per work item (SDK MAX_ATTEMPTS). */
|
|
23
|
-
export const MAX_ATTEMPTS = 5;
|
|
24
|
-
|
|
25
|
-
export interface AttemptsValidation {
|
|
26
|
-
/** True when any item requests best-of-N (attempts >= 2). */
|
|
27
|
-
readonly hasAttempts: boolean;
|
|
28
|
-
/** Hard rule breaks that must block a launch (worktree isolation + stable id when depended upon). */
|
|
29
|
-
readonly violations: readonly string[];
|
|
30
|
-
/** Non-blocking notes (e.g. an over-cap value the engine will clamp). */
|
|
31
|
-
readonly notes: readonly string[];
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
function itemKey(item: CreateWorkstreamInput['items'][number]): string {
|
|
35
|
-
return item.id ?? item.title;
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
/**
|
|
39
|
-
* Validate a draft spec's best-of-N usage against the worktree-isolation and
|
|
40
|
-
* stable-id (when depended upon) constraints. Non-leaf best-of-N is allowed.
|
|
41
|
-
* Pure — no I/O. `violations` are hard (block launch); `notes` are advisory.
|
|
42
|
-
*/
|
|
43
|
-
export function validateAttempts(spec: CreateWorkstreamInput): AttemptsValidation {
|
|
44
|
-
const violations: string[] = [];
|
|
45
|
-
const notes: string[] = [];
|
|
46
|
-
const worktree = spec.isolation === 'worktree';
|
|
47
|
-
|
|
48
|
-
// Which items are depended upon (so a best-of-N item that is a dependency
|
|
49
|
-
// target can be checked for the stable-id requirement).
|
|
50
|
-
const dependedUpon = new Set<string>();
|
|
51
|
-
for (const item of spec.items) {
|
|
52
|
-
for (const dep of item.dependsOn ?? []) dependedUpon.add(dep);
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
let hasAttempts = false;
|
|
56
|
-
for (const item of spec.items) {
|
|
57
|
-
const attempts = item.attempts ?? 1;
|
|
58
|
-
if (attempts < 2) continue;
|
|
59
|
-
hasAttempts = true;
|
|
60
|
-
const label = item.title;
|
|
61
|
-
|
|
62
|
-
if (!worktree) {
|
|
63
|
-
violations.push(`"${label}" requests ${attempts} attempts, but the workstream is not worktree-isolated — best-of-N needs isolated trees. Set --isolation worktree.`);
|
|
64
|
-
}
|
|
65
|
-
// Non-leaf best-of-N is allowed. The only structural requirement: if other
|
|
66
|
-
// items depend on this one, it must carry a stable id for the dependency
|
|
67
|
-
// edge to name — an anonymous best-of-N item cannot be a dependency target.
|
|
68
|
-
if (dependedUpon.has(itemKey(item)) && !item.id) {
|
|
69
|
-
violations.push(`another item depends on best-of-N item "${label}", but it has no stable id — give the item an id so the dependency can resolve to the winner (an anonymous best-of-N item cannot be a dependency target).`);
|
|
70
|
-
}
|
|
71
|
-
if (attempts > MAX_ATTEMPTS) {
|
|
72
|
-
notes.push(`"${label}" requests ${attempts} attempts — the engine caps best-of-N at ${MAX_ATTEMPTS}, so ${MAX_ATTEMPTS} siblings will run.`);
|
|
73
|
-
}
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
return { hasAttempts, violations, notes };
|
|
77
|
-
}
|
|
@@ -1,95 +0,0 @@
|
|
|
1
|
-
// ---------------------------------------------------------------------------
|
|
2
|
-
// workstream-draft-edits.ts — pure item edits for a not-yet-launched proposal
|
|
3
|
-
//
|
|
4
|
-
// The plan-review gate (see /workstream, input/commands/workstream-runtime.ts)
|
|
5
|
-
// lets a human reshape a decomposed proposal BEFORE anything is spent: rewrite
|
|
6
|
-
// one item's brief, drop an item, or reorder items. These are pure functions
|
|
7
|
-
// over the launchable CreateWorkstreamInput (@pellux/goodvibes-sdk/platform/
|
|
8
|
-
// orchestration) — no engine calls, no I/O — so the same spec that is edited
|
|
9
|
-
// here is byte-for-byte what launch hands createWorkstream. Extracted from
|
|
10
|
-
// workstream-services.ts to keep that construction module lean (its own
|
|
11
|
-
// header explains the 800-line-cap discipline) and to give the edits a clean
|
|
12
|
-
// unit-test target.
|
|
13
|
-
//
|
|
14
|
-
// HONEST SCOPE (stated so the review surface never overstates what an edit
|
|
15
|
-
// does):
|
|
16
|
-
// - editItemBrief rewrites an item's `task` (the instructions its agent
|
|
17
|
-
// runs), never its `title` (the short label). The engineer/review phase
|
|
18
|
-
// template is unchanged — a brief is WHAT the item does, not HOW the
|
|
19
|
-
// pipeline runs it.
|
|
20
|
-
// - removeItem also strips the removed item's id from every other item's
|
|
21
|
-
// `dependsOn`, so the spec never carries a dangling dependency into
|
|
22
|
-
// fromPlanProposal's assembly (which would otherwise reject it). It
|
|
23
|
-
// refuses to remove the last item — a workstream needs at least one.
|
|
24
|
-
// - moveItem reorders the AUTHORING order (the ordinals shown in the review
|
|
25
|
-
// and the tie-break when the engine has a free capacity slot and several
|
|
26
|
-
// claimable items). It never rewrites dependencies, so it cannot create a
|
|
27
|
-
// cycle; the engine still schedules strictly by dependency + capacity, not
|
|
28
|
-
// by array position. Reordering is a presentation/authoring act, not a
|
|
29
|
-
// scheduling override — and is documented as such where it is offered.
|
|
30
|
-
// ---------------------------------------------------------------------------
|
|
31
|
-
|
|
32
|
-
import type { CreateWorkstreamInput, WorkItemSpec } from '@pellux/goodvibes-sdk/platform/orchestration';
|
|
33
|
-
|
|
34
|
-
/** Success carries the rewritten spec; failure carries an honest, user-facing reason. */
|
|
35
|
-
export type DraftEditResult = { readonly spec: CreateWorkstreamInput } | { readonly error: string };
|
|
36
|
-
|
|
37
|
-
/**
|
|
38
|
-
* Resolve a user-typed item reference to a 0-based index. A reference is
|
|
39
|
-
* either the 1-based ordinal shown in the proposal (the primary handle) or an
|
|
40
|
-
* item id / unique id-prefix (the stable handle that survives reordering). An
|
|
41
|
-
* ambiguous or unmatched reference resolves to undefined so the caller can
|
|
42
|
-
* refuse honestly rather than editing the wrong item.
|
|
43
|
-
*/
|
|
44
|
-
export function resolveItemIndex(items: readonly WorkItemSpec[], ref: string): number | undefined {
|
|
45
|
-
const trimmed = ref.trim();
|
|
46
|
-
const ordinal = Number(trimmed);
|
|
47
|
-
if (Number.isInteger(ordinal) && ordinal >= 1 && ordinal <= items.length) return ordinal - 1;
|
|
48
|
-
const matches = items
|
|
49
|
-
.map((item, index) => ({ item, index }))
|
|
50
|
-
.filter(({ item }) => item.id !== undefined && item.id.startsWith(trimmed));
|
|
51
|
-
return matches.length === 1 ? matches[0]!.index : undefined;
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
function unresolvedError(items: readonly WorkItemSpec[], ref: string): string {
|
|
55
|
-
return `No draft item matches "${ref}". Use a number from 1 to ${items.length}, or an item id.`;
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
/** Rewrite one item's brief (its `task`). Empty/whitespace briefs are refused. */
|
|
59
|
-
export function editItemBrief(spec: CreateWorkstreamInput, ref: string, brief: string): DraftEditResult {
|
|
60
|
-
const index = resolveItemIndex(spec.items, ref);
|
|
61
|
-
if (index === undefined) return { error: unresolvedError(spec.items, ref) };
|
|
62
|
-
const trimmed = brief.trim();
|
|
63
|
-
if (!trimmed) return { error: 'A new brief cannot be empty.' };
|
|
64
|
-
const items = spec.items.map((item, i) => (i === index ? { ...item, task: trimmed } : item));
|
|
65
|
-
return { spec: { ...spec, items } };
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
/** Drop one item and strip its id from every sibling's dependsOn. Refuses to empty the plan. */
|
|
69
|
-
export function removeItemFromSpec(spec: CreateWorkstreamInput, ref: string): DraftEditResult {
|
|
70
|
-
const index = resolveItemIndex(spec.items, ref);
|
|
71
|
-
if (index === undefined) return { error: unresolvedError(spec.items, ref) };
|
|
72
|
-
if (spec.items.length <= 1) return { error: 'Cannot remove the last item — a workstream needs at least one.' };
|
|
73
|
-
const removedId = spec.items[index]!.id;
|
|
74
|
-
const items = spec.items
|
|
75
|
-
.filter((_, i) => i !== index)
|
|
76
|
-
.map((item) =>
|
|
77
|
-
removedId && item.dependsOn?.includes(removedId)
|
|
78
|
-
? { ...item, dependsOn: item.dependsOn.filter((dep) => dep !== removedId) }
|
|
79
|
-
: item,
|
|
80
|
-
);
|
|
81
|
-
return { spec: { ...spec, items } };
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
/** Reorder one item to a new 1-based authoring position. Never touches dependencies. */
|
|
85
|
-
export function moveItemInSpec(spec: CreateWorkstreamInput, ref: string, toPosition: number): DraftEditResult {
|
|
86
|
-
const index = resolveItemIndex(spec.items, ref);
|
|
87
|
-
if (index === undefined) return { error: unresolvedError(spec.items, ref) };
|
|
88
|
-
if (!Number.isInteger(toPosition) || toPosition < 1 || toPosition > spec.items.length) {
|
|
89
|
-
return { error: `Position must be a whole number from 1 to ${spec.items.length}.` };
|
|
90
|
-
}
|
|
91
|
-
const items = [...spec.items];
|
|
92
|
-
const [moved] = items.splice(index, 1);
|
|
93
|
-
items.splice(toPosition - 1, 0, moved!);
|
|
94
|
-
return { spec: { ...spec, items } };
|
|
95
|
-
}
|