@pellux/goodvibes-tui 2.0.13 → 2.0.15
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.goodvibes/GOODVIBES.md +1 -1
- package/.goodvibes/agents/reviewer.md +8 -8
- package/.goodvibes/skills/add-provider/SKILL.md +22 -22
- package/CHANGELOG.md +61 -0
- package/README.md +40 -29
- package/docs/README.md +1 -1
- package/docs/foundation-artifacts/README.md +5 -5
- package/docs/foundation-artifacts/operator-contract.json +123 -123
- package/package.json +12 -10
- package/scripts/postinstall.js +3 -3
- package/src/audio/activation-sound.ts +7 -7
- package/src/audio/capture.ts +7 -7
- package/src/audio/onnxruntime-assets.d.ts +1 -1
- package/src/audio/player.ts +4 -4
- package/src/audio/spoken-turn-wiring.ts +4 -4
- package/src/audio/voice-capture-wiring.ts +5 -5
- package/src/audio/voice-input-session.ts +3 -3
- package/src/audio/wake-inference.ts +13 -8
- package/src/audio/wake-runtime.ts +10 -10
- package/src/cli/completions/generate.ts +2 -2
- package/src/cli/doctor.ts +13 -13
- package/src/cli/ensure-goodvibes-gitignore.ts +3 -3
- package/src/cli/entrypoint.ts +3 -3
- package/src/cli/help.ts +6 -6
- package/src/cli/hooks-command.ts +4 -4
- package/src/cli/hooks-report.ts +4 -4
- package/src/cli/launch-auto-update.ts +17 -17
- package/src/cli/management-commands.ts +8 -8
- package/src/cli/management-utils.ts +3 -3
- package/src/cli/management.ts +1 -1
- package/src/cli/plugin-bundles-command.ts +10 -10
- package/src/cli/plugin-command.ts +9 -9
- package/src/cli/service-posture.ts +1 -1
- package/src/cli/status.ts +10 -10
- package/src/cli/surface-command.ts +4 -4
- package/src/cli/tui-startup.ts +23 -23
- package/src/config/run-daemon-config-migration.ts +3 -3
- package/src/config/secret-config.ts +10 -10
- package/src/config/surface.ts +1 -1
- package/src/config/tui-extension-settings.ts +8 -8
- package/src/core/active-model-identity.ts +7 -7
- package/src/core/approval-alert.ts +5 -5
- package/src/core/bookmark-navigation.ts +3 -3
- package/src/core/budget-breach-notifier.ts +6 -6
- package/src/core/compaction-receipt.ts +8 -8
- package/src/core/composer-state.ts +2 -2
- package/src/core/context-usage.ts +1 -1
- package/src/core/conversation-compaction-render.ts +3 -3
- package/src/core/conversation-event-navigation.ts +2 -2
- package/src/core/conversation-fold.ts +9 -9
- package/src/core/conversation-line-cache.ts +14 -14
- package/src/core/conversation-render-context.ts +6 -6
- package/src/core/conversation-rendering.ts +27 -30
- package/src/core/conversation-search-expansion.ts +6 -6
- package/src/core/conversation-splash-state.ts +3 -3
- package/src/core/conversation-turn-structure.ts +13 -13
- package/src/core/conversation-types.ts +3 -3
- package/src/core/conversation-user-receipts.ts +5 -5
- package/src/core/conversation.ts +17 -17
- package/src/core/format-user-error.ts +5 -5
- package/src/core/long-task-notifier.ts +9 -9
- package/src/core/memory-diagnostics-gateway.ts +8 -8
- package/src/core/memory-provenance.ts +5 -5
- package/src/core/model-routing-chip.ts +3 -3
- package/src/core/pairing-tailscale-gateway.ts +3 -3
- package/src/core/permission-mode.ts +5 -5
- package/src/core/power-chip-source.ts +3 -3
- package/src/core/power-status.ts +8 -8
- package/src/core/rewind-receipt.ts +6 -6
- package/src/core/session-resume-core.ts +8 -8
- package/src/core/stream-event-wiring.ts +36 -36
- package/src/core/stream-stall-watchdog.ts +4 -4
- package/src/core/system-message-noise.ts +7 -7
- package/src/core/system-message-router.ts +10 -10
- package/src/core/terminal-notifier.ts +5 -5
- package/src/core/turn-budget-outcome.ts +5 -5
- package/src/core/turn-cancellation.ts +3 -3
- package/src/core/turn-event-wiring.ts +16 -16
- package/src/core/voice-capture-status.ts +2 -2
- package/src/core/voice-provision-gateway.ts +12 -12
- package/src/core/voice-provision-status.ts +19 -19
- package/src/core/voice-stt-gateway.ts +6 -6
- package/src/core/wake-provision-runner.ts +7 -7
- package/src/core/wake-provision-status.ts +17 -17
- package/src/core/workstream-notification.ts +8 -8
- package/src/export/gist-uploader.ts +7 -7
- package/src/input/autocomplete.ts +3 -3
- package/src/input/bookmark-modal.ts +1 -1
- package/src/input/command-args-hint.ts +2 -2
- package/src/input/command-reference.ts +9 -9
- package/src/input/command-registry.ts +32 -32
- package/src/input/commands/acp-runtime.ts +6 -6
- package/src/input/commands/calendar-runtime.ts +9 -9
- package/src/input/commands/channel-pairing.ts +11 -11
- package/src/input/commands/channel-runtime.ts +1 -1
- package/src/input/commands/checkin-runtime.ts +4 -4
- package/src/input/commands/checkpoint-runtime.ts +4 -4
- package/src/input/commands/ci-runtime.ts +4 -4
- package/src/input/commands/cluster-runtime.ts +3 -3
- package/src/input/commands/codebase-runtime.ts +16 -16
- package/src/input/commands/config.ts +6 -6
- package/src/input/commands/connection-status.ts +12 -12
- package/src/input/commands/context-window.ts +2 -2
- package/src/input/commands/cost-attribution-format.ts +4 -4
- package/src/input/commands/cost-runtime.ts +2 -2
- package/src/input/commands/devices-runtime.ts +7 -7
- package/src/input/commands/diff-runtime.ts +2 -2
- package/src/input/commands/editor-runtime.ts +1 -1
- package/src/input/commands/eval.ts +4 -4
- package/src/input/commands/experience-runtime.ts +1 -1
- package/src/input/commands/git-runtime.ts +3 -3
- package/src/input/commands/graph-runtime.ts +3 -3
- package/src/input/commands/guidance-runtime.ts +1 -1
- package/src/input/commands/health-metrics-format.ts +2 -2
- package/src/input/commands/health-runtime.ts +8 -8
- package/src/input/commands/hosted-runtime.ts +13 -13
- package/src/input/commands/image-runtime.ts +6 -6
- package/src/input/commands/intelligence-runtime.ts +2 -2
- package/src/input/commands/local-auth-runtime.ts +3 -3
- package/src/input/commands/local-provider-runtime.ts +3 -3
- package/src/input/commands/local-runtime.ts +7 -7
- package/src/input/commands/mail-runtime.ts +9 -9
- package/src/input/commands/mcp-runtime.ts +1 -1
- package/src/input/commands/memory.ts +13 -13
- package/src/input/commands/notify-runtime.ts +1 -1
- package/src/input/commands/operator-panel-runtime.ts +8 -8
- package/src/input/commands/operator-rpc.ts +3 -3
- package/src/input/commands/operator-runtime.ts +3 -3
- package/src/input/commands/palette-runtime.ts +1 -1
- package/src/input/commands/payment-card-intake.ts +17 -17
- package/src/input/commands/permissions-provenance.ts +7 -7
- package/src/input/commands/permissions-runtime.ts +1 -1
- package/src/input/commands/planning-runtime.ts +9 -9
- package/src/input/commands/platform-services-runtime.ts +2 -2
- package/src/input/commands/policy-dispatch.ts +6 -6
- package/src/input/commands/power-runtime.ts +6 -6
- package/src/input/commands/principals-runtime.ts +3 -3
- package/src/input/commands/product-runtime.ts +3 -3
- package/src/input/commands/profile-render.ts +13 -13
- package/src/input/commands/profile-runtime.ts +13 -13
- package/src/input/commands/profile-types.ts +13 -13
- package/src/input/commands/provider-accounts-runtime.ts +5 -5
- package/src/input/commands/provider.ts +10 -10
- package/src/input/commands/qrcode-runtime.ts +3 -3
- package/src/input/commands/queue-runtime.ts +6 -6
- package/src/input/commands/recall-files-config.ts +4 -4
- package/src/input/commands/recall-files-git.ts +3 -3
- package/src/input/commands/recall-files.ts +12 -12
- package/src/input/commands/recall-query.ts +3 -3
- package/src/input/commands/recall-review.ts +3 -3
- package/src/input/commands/recall-shared.ts +1 -1
- package/src/input/commands/relay-runtime.ts +5 -5
- package/src/input/commands/remote-runtime.ts +3 -3
- package/src/input/commands/review-runtime.ts +8 -8
- package/src/input/commands/rewind-runtime.ts +21 -21
- package/src/input/commands/runtime-services.ts +1 -2
- package/src/input/commands/schedule-nl.ts +2 -2
- package/src/input/commands/schedule-runtime.ts +2 -2
- package/src/input/commands/secret-runtime.ts +3 -3
- package/src/input/commands/session-content.ts +7 -7
- package/src/input/commands/session-picker-filter.ts +3 -3
- package/src/input/commands/session-workflow.ts +10 -10
- package/src/input/commands/session.ts +15 -15
- package/src/input/commands/settings-sync-runtime.ts +2 -2
- package/src/input/commands/share-runtime.ts +4 -4
- package/src/input/commands/shell-core.ts +11 -11
- package/src/input/commands/tasks-runtime.ts +4 -4
- package/src/input/commands/test-runtime.ts +6 -6
- package/src/input/commands/tts-runtime.ts +4 -4
- package/src/input/commands/update-runtime.ts +27 -27
- package/src/input/commands/websearch-runtime.ts +2 -2
- package/src/input/commands/work-plan-runtime.ts +2 -2
- package/src/input/commands/workstream-attempt-dependents.ts +4 -4
- package/src/input/commands/workstream-attempts.ts +16 -16
- package/src/input/commands/workstream-runtime.ts +36 -36
- package/src/input/commands/worktree-runtime.ts +6 -6
- package/src/input/composer-capture.ts +5 -5
- package/src/input/concealed-input.ts +2 -2
- package/src/input/config-modal-types.ts +16 -16
- package/src/input/config-modal.ts +30 -30
- package/src/input/daemon-owned-settings-descriptions.ts +4 -4
- package/src/input/delete-key-policy.ts +1 -1
- package/src/input/exec-env-scrub-config.ts +7 -7
- package/src/input/feature-unit-layout.ts +5 -5
- package/src/input/feed-context-factory.ts +38 -38
- package/src/input/file-picker.ts +1 -1
- package/src/input/handler-command-route.ts +2 -2
- package/src/input/handler-content-actions.ts +8 -8
- package/src/input/handler-feed-routes.ts +13 -13
- package/src/input/handler-feed.ts +31 -31
- package/src/input/handler-interactions.ts +2 -2
- package/src/input/handler-modal-routes.ts +13 -13
- package/src/input/handler-modal-stack.ts +1 -1
- package/src/input/handler-modal-token-routes.ts +1 -1
- package/src/input/handler-onboarding-daemon-adopt.ts +6 -6
- package/src/input/handler-picker-routes.ts +7 -7
- package/src/input/handler-prompt-buffer.ts +1 -1
- package/src/input/handler-shortcuts.ts +12 -12
- package/src/input/handler-types.ts +3 -3
- package/src/input/handler-ui-state.ts +1 -1
- package/src/input/handler.ts +9 -9
- package/src/input/input-history.ts +1 -1
- package/src/input/keybindings.ts +13 -13
- package/src/input/kill-ring.ts +7 -11
- package/src/input/model-picker-filter.ts +3 -3
- package/src/input/model-picker-items.ts +5 -5
- package/src/input/model-picker-types.ts +2 -2
- package/src/input/model-picker.ts +18 -18
- package/src/input/onboarding/onboarding-feature-units.ts +9 -13
- package/src/input/onboarding/onboarding-provider-key-fields.ts +3 -3
- package/src/input/onboarding/onboarding-runtime-status.ts +3 -3
- package/src/input/onboarding/onboarding-wizard-apply.ts +6 -6
- package/src/input/onboarding/onboarding-wizard-cloudflare-step.ts +1 -1
- package/src/input/onboarding/onboarding-wizard-constants.ts +1 -1
- package/src/input/onboarding/onboarding-wizard-external-surfaces.ts +4 -4
- package/src/input/onboarding/onboarding-wizard-network-adopt.ts +6 -6
- package/src/input/onboarding/onboarding-wizard-steps.ts +2 -2
- package/src/input/panel-integration-actions.ts +3 -3
- package/src/input/panel-mouse-geometry.ts +1 -1
- package/src/input/panel-paste-flood-guard.ts +9 -9
- package/src/input/payments-config.ts +15 -15
- package/src/input/profile-picker-modal.ts +1 -1
- package/src/input/provider-key-intake.ts +9 -9
- package/src/input/relay-settings-descriptions.ts +3 -3
- package/src/input/sandbox-exec-config.ts +9 -9
- package/src/input/search.ts +18 -18
- package/src/input/selection-modal-queue.ts +10 -10
- package/src/input/selection-modal.ts +2 -2
- package/src/input/session-picker-modal.ts +7 -7
- package/src/input/settings-modal-activation.ts +1 -1
- package/src/input/settings-modal-adjustment.ts +2 -2
- package/src/input/settings-modal-commit.ts +6 -6
- package/src/input/settings-modal-connections.ts +2 -2
- package/src/input/settings-modal-data.ts +29 -29
- package/src/input/settings-modal-mutations.ts +7 -7
- package/src/input/settings-modal-reset.ts +3 -3
- package/src/input/settings-modal-search.ts +6 -6
- package/src/input/settings-modal-secrets.ts +3 -3
- package/src/input/settings-modal-types.ts +16 -16
- package/src/input/settings-modal.ts +4 -4
- package/src/input/voice-local-settings.ts +3 -3
- package/src/input/worktree-setup-config.ts +8 -8
- package/src/main.ts +15 -15
- package/src/panels/agent-inspector-shared.ts +5 -5
- package/src/panels/base-panel.ts +3 -3
- package/src/panels/builtin/agent.ts +3 -3
- package/src/panels/builtin/development.ts +4 -4
- package/src/panels/builtin/knowledge.ts +1 -1
- package/src/panels/builtin/operations.ts +12 -12
- package/src/panels/builtin/session.ts +8 -8
- package/src/panels/builtin/shared.ts +6 -6
- package/src/panels/builtin-modals.ts +8 -8
- package/src/panels/confirm-state.ts +5 -5
- package/src/panels/cost-tracker-panel.ts +22 -22
- package/src/panels/diff-panel.ts +20 -20
- package/src/panels/diff-review-model.ts +5 -5
- package/src/panels/diff-review-panel.ts +5 -5
- package/src/panels/eval-registry.ts +2 -2
- package/src/panels/expandable-list-panel.ts +5 -5
- package/src/panels/fleet-acts.ts +20 -20
- package/src/panels/fleet-deep-link.ts +5 -5
- package/src/panels/fleet-gateway.ts +12 -12
- package/src/panels/fleet-observed-render.ts +11 -11
- package/src/panels/fleet-panel-format.ts +14 -14
- package/src/panels/fleet-panel-worktree-detail.ts +8 -8
- package/src/panels/fleet-panel.ts +34 -34
- package/src/panels/fleet-read-model.ts +49 -49
- package/src/panels/fleet-spawn.ts +15 -15
- package/src/panels/fleet-steer.ts +7 -7
- package/src/panels/fleet-stop.ts +5 -5
- package/src/panels/fleet-tabs.ts +14 -14
- package/src/panels/fleet-transcript.ts +26 -26
- package/src/panels/git-panel.ts +8 -8
- package/src/panels/hosted-session-feed.ts +13 -13
- package/src/panels/hosted-session-panel.ts +7 -7
- package/src/panels/index.ts +1 -1
- package/src/panels/local-auth-panel.ts +15 -15
- package/src/panels/memory-consolidation-gateway.ts +8 -8
- package/src/panels/modals/devices-modal.ts +8 -8
- package/src/panels/modals/hooks-modal.ts +1 -1
- package/src/panels/modals/keybindings-modal.ts +5 -5
- package/src/panels/modals/knowledge-modal.ts +2 -2
- package/src/panels/modals/local-auth-modal.ts +4 -4
- package/src/panels/modals/marketplace-modal.ts +3 -3
- package/src/panels/modals/memory-modal.ts +19 -19
- package/src/panels/modals/modal-surface-helpers.ts +1 -1
- package/src/panels/modals/modal-theme.ts +3 -3
- package/src/panels/modals/pairing-modal.ts +19 -19
- package/src/panels/modals/planning-modal.ts +4 -4
- package/src/panels/modals/plugins-modal.ts +1 -1
- package/src/panels/modals/policy-modal.ts +4 -4
- package/src/panels/modals/provider-health-modal.ts +1 -1
- package/src/panels/modals/remote-modal.ts +1 -1
- package/src/panels/modals/sandbox-modal.ts +2 -2
- package/src/panels/modals/security-modal.ts +4 -4
- package/src/panels/modals/services-modal.ts +1 -1
- package/src/panels/modals/work-plan-modal.ts +4 -4
- package/src/panels/notifications-feed.ts +6 -6
- package/src/panels/notifications-panel.ts +6 -6
- package/src/panels/panel-confirm-overlay.ts +4 -4
- package/src/panels/panel-manager.ts +13 -13
- package/src/panels/plugins-panel.ts +6 -6
- package/src/panels/polish-core.ts +2 -2
- package/src/panels/polish-tables.ts +2 -2
- package/src/panels/polish.ts +1 -1
- package/src/panels/project-planning-answer-actions.ts +3 -3
- package/src/panels/scrollable-list-panel.ts +15 -15
- package/src/panels/search-focus.ts +1 -1
- package/src/panels/session-maintenance.ts +1 -1
- package/src/panels/skills-panel.ts +3 -3
- package/src/panels/token-budget-panel.ts +11 -11
- package/src/panels/types.ts +14 -14
- package/src/panels/workstream-graph-render.ts +5 -5
- package/src/panels/wrfc-panel-format.ts +1 -1
- package/src/permissions/broker-approval-card.ts +13 -13
- package/src/permissions/hunk-selection.ts +13 -13
- package/src/permissions/prompt.ts +22 -22
- package/src/permissions/sandbox-exec-gate.ts +5 -5
- package/src/providers/provider-classification.ts +1 -1
- package/src/providers/reasoning-effort-surface.ts +12 -12
- package/src/renderer/ansi-sanitize.ts +5 -6
- package/src/renderer/autocomplete-overlay.ts +5 -5
- package/src/renderer/block-actions-overlay.ts +1 -1
- package/src/renderer/bookmark-modal.ts +1 -1
- package/src/renderer/code-block.ts +2 -2
- package/src/renderer/compaction-history-modal.ts +4 -4
- package/src/renderer/compaction-preview.ts +5 -5
- package/src/renderer/compaction-quality.ts +5 -5
- package/src/renderer/composer-fragments.ts +6 -6
- package/src/renderer/compositor.ts +9 -9
- package/src/renderer/config-modal.ts +3 -3
- package/src/renderer/context-inspector.ts +1 -1
- package/src/renderer/context-status-hint.ts +10 -10
- package/src/renderer/conversation-layout.ts +2 -2
- package/src/renderer/conversation-overlays.ts +2 -2
- package/src/renderer/conversation-surface.ts +6 -6
- package/src/renderer/diff.ts +4 -4
- package/src/renderer/fleet-tab-strip.ts +2 -2
- package/src/renderer/footer-tips.ts +4 -4
- package/src/renderer/fullscreen-primitives.ts +1 -1
- package/src/renderer/git-status.ts +5 -5
- package/src/renderer/header-line.ts +5 -5
- package/src/renderer/help-overlay.ts +5 -5
- package/src/renderer/hint-grammar.ts +2 -2
- package/src/renderer/layout.ts +1 -1
- package/src/renderer/markdown-inline.ts +3 -3
- package/src/renderer/markdown-table.ts +7 -7
- package/src/renderer/modal-factory.ts +3 -3
- package/src/renderer/model-picker-overlay.ts +2 -2
- package/src/renderer/model-workspace.ts +7 -7
- package/src/renderer/onboarding/onboarding-wizard.ts +1 -1
- package/src/renderer/overlay-box.ts +1 -1
- package/src/renderer/panel-composite.ts +5 -5
- package/src/renderer/panel-workspace-bar.ts +1 -1
- package/src/renderer/process-indicator.ts +8 -8
- package/src/renderer/profile-picker-modal.ts +3 -3
- package/src/renderer/prompt-content-width.ts +1 -1
- package/src/renderer/search-overlay.ts +3 -3
- package/src/renderer/selection-modal-overlay.ts +6 -6
- package/src/renderer/semantic-diff.ts +6 -7
- package/src/renderer/session-picker-modal.ts +24 -24
- package/src/renderer/settings-modal-connections.ts +3 -3
- package/src/renderer/settings-modal-helpers.ts +16 -16
- package/src/renderer/settings-modal.ts +10 -10
- package/src/renderer/shell-surface.ts +8 -8
- package/src/renderer/status-glyphs.ts +6 -6
- package/src/renderer/syntax-highlighter.ts +2 -3
- package/src/renderer/system-message.ts +3 -3
- package/src/renderer/tab-strip.ts +2 -2
- package/src/renderer/term-caps.ts +12 -12
- package/src/renderer/terminal-bg-probe.ts +10 -10
- package/src/renderer/terminal-escapes.ts +1 -1
- package/src/renderer/theme-mode-config.ts +3 -3
- package/src/renderer/theme.ts +34 -34
- package/src/renderer/thinking.ts +1 -1
- package/src/renderer/tool-call.ts +5 -5
- package/src/renderer/tool-result-expanded-lines.ts +3 -3
- package/src/renderer/tool-result-summary.ts +6 -6
- package/src/renderer/turn-injection.ts +9 -9
- package/src/renderer/ui-factory.ts +33 -33
- package/src/renderer/ui-primitives.ts +4 -4
- package/src/runtime/bootstrap-command-parts.ts +3 -3
- package/src/runtime/bootstrap-core.ts +21 -21
- package/src/runtime/bootstrap-hook-bridge.ts +8 -8
- package/src/runtime/bootstrap-shell.ts +9 -9
- package/src/runtime/bootstrap.ts +16 -16
- package/src/runtime/client/approval-updates.ts +3 -3
- package/src/runtime/client/build-floors.ts +7 -7
- package/src/runtime/client/daemon-attach-handshake.ts +5 -5
- package/src/runtime/client/fleet-union.ts +7 -7
- package/src/runtime/client/host-service-status.ts +2 -2
- package/src/runtime/client/hosted-exit.ts +4 -4
- package/src/runtime/client/hosted-roster.ts +4 -4
- package/src/runtime/client/hosted-session-stream.ts +5 -5
- package/src/runtime/client/hosted-sessions.ts +8 -8
- package/src/runtime/client/operator-endpoint.ts +14 -14
- package/src/runtime/client/spine-adoption.ts +8 -8
- package/src/runtime/context-accounting-source.ts +4 -4
- package/src/runtime/context.ts +2 -2
- package/src/runtime/conversation-rewind-port.ts +6 -6
- package/src/runtime/credential-composition.ts +2 -2
- package/src/runtime/daemon-attach-notices.ts +6 -6
- package/src/runtime/diagnostics/panels/index.ts +1 -1
- package/src/runtime/diagnostics/panels/ops.ts +2 -2
- package/src/runtime/disposal-wiring.ts +6 -6
- package/src/runtime/index.ts +11 -11
- package/src/runtime/install-self-check-startup.ts +4 -4
- package/src/runtime/install-self-check.ts +6 -6
- package/src/runtime/interaction-seams.ts +4 -4
- package/src/runtime/knowledge-services.ts +2 -2
- package/src/runtime/legacy-daemon-migration.ts +37 -37
- package/src/runtime/legacy-daemon-reconcile.ts +30 -30
- package/src/runtime/memory-governance-services.ts +3 -3
- package/src/runtime/memory-spine-transport.ts +3 -3
- package/src/runtime/notification-dispatch.ts +4 -4
- package/src/runtime/onboarding/apply.ts +1 -1
- package/src/runtime/onboarding/derivation.ts +1 -1
- package/src/runtime/onboarding/fast-path.ts +7 -7
- package/src/runtime/onboarding/progress.ts +2 -2
- package/src/runtime/onboarding/provider-key-capture.ts +4 -4
- package/src/runtime/onboarding/snapshot.ts +2 -2
- package/src/runtime/onboarding/state.ts +4 -4
- package/src/runtime/onboarding/types.ts +4 -4
- package/src/runtime/orchestrator-core-services.ts +5 -5
- package/src/runtime/path-shadow-startup.ts +3 -3
- package/src/runtime/perf/panel-contracts.ts +1 -1
- package/src/runtime/power-keepawake-remote.ts +6 -6
- package/src/runtime/process-lifecycle.ts +14 -14
- package/src/runtime/provider-fallback.ts +3 -3
- package/src/runtime/recovery-autosave.ts +3 -3
- package/src/runtime/recovery-decisions.ts +19 -19
- package/src/runtime/recovery-offer-wiring.ts +4 -4
- package/src/runtime/recovery-prompt.ts +20 -20
- package/src/runtime/relay-reachability-bridge.ts +3 -3
- package/src/runtime/release-artifacts.ts +1 -1
- package/src/runtime/resume-notice.ts +20 -20
- package/src/runtime/runtime-services-types.ts +20 -20
- package/src/runtime/services.ts +20 -20
- package/src/runtime/session-continuity-hints.ts +1 -1
- package/src/runtime/session-inbound-inputs.ts +12 -12
- package/src/runtime/session-resume-liveness-confirm.ts +4 -4
- package/src/runtime/session-spine-transport.ts +3 -3
- package/src/runtime/store/domains/panels.ts +2 -2
- package/src/runtime/store/domains/ui-perf.ts +2 -2
- package/src/runtime/store/index.ts +1 -1
- package/src/runtime/store/selectors/index.ts +1 -1
- package/src/runtime/store/state.ts +2 -2
- package/src/runtime/ui-services.ts +3 -3
- package/src/runtime/workspace-checkpointing.ts +3 -3
- package/src/runtime/wrfc-persistence.ts +15 -15
- package/src/scripts/process-messages.ts +1 -1
- package/src/shell/blocking-input.ts +9 -9
- package/src/shell/recovery-input-helpers.ts +2 -2
- package/src/shell/retry-affordance.ts +9 -9
- package/src/shell/ui-openers.ts +14 -14
- package/src/shell/voice-capture-shell.ts +3 -3
- package/src/tools/wrfc-agent-guard.ts +4 -4
- package/src/utils/browser.ts +2 -2
- package/src/utils/format-duration.ts +3 -3
- package/src/utils/format-number.ts +2 -2
- package/src/utils/splash-lines.ts +4 -4
- package/src/utils/terminal-width.ts +6 -6
- package/src/verification/verification-ledger.ts +25 -25
- package/src/version.ts +3 -3
|
@@ -20,7 +20,7 @@ import { readBudgetAlertUsd } from '@pellux/goodvibes-sdk/platform/providers';
|
|
|
20
20
|
/** Minimal orchestrator surface required by turn-event wiring. */
|
|
21
21
|
interface TurnOrchestrator {
|
|
22
22
|
readonly lastInputTokens: number;
|
|
23
|
-
/** Cumulative session usage
|
|
23
|
+
/** Cumulative session usage, same object CostTrackerPanel reads, used here for budget-breach checks. */
|
|
24
24
|
readonly usage: { readonly input: number; readonly output: number; readonly cacheRead: number; readonly cacheWrite: number };
|
|
25
25
|
}
|
|
26
26
|
|
|
@@ -50,7 +50,7 @@ export interface WireTurnEventHandlersOptions {
|
|
|
50
50
|
readonly events: UiRuntimeEvents;
|
|
51
51
|
/**
|
|
52
52
|
* Raw runtime event bus. Needed for domains NOT surfaced by the grouped
|
|
53
|
-
* UiRuntimeEvents feed
|
|
53
|
+
* UiRuntimeEvents feed, specifically the 'compaction' domain, whose
|
|
54
54
|
* mandatory COMPACTION_RECEIPT the transcript renders as a distinct block.
|
|
55
55
|
* Optional so headless/test callers can omit it.
|
|
56
56
|
*/
|
|
@@ -65,7 +65,7 @@ export interface WireTurnEventHandlersOptions {
|
|
|
65
65
|
/**
|
|
66
66
|
* The app's declare-once session-storage handle. The turn snapshot, the
|
|
67
67
|
* last-session pointer it writes, the transcript journal, and the rewind
|
|
68
|
-
* anchor sidecar all resolve off this one handle
|
|
68
|
+
* anchor sidecar all resolve off this one handle, so the boot notice and
|
|
69
69
|
* `--continue`, which read through the same handle, land on the files this
|
|
70
70
|
* writer actually produced.
|
|
71
71
|
*/
|
|
@@ -77,13 +77,13 @@ export interface WireTurnEventHandlersOptions {
|
|
|
77
77
|
/**
|
|
78
78
|
* Outbound webhook notifier. When provided and URLs are configured,
|
|
79
79
|
* long-task push notifications are delivered to configured ntfy/webhook
|
|
80
|
-
* endpoints after the configured threshold. Optional
|
|
80
|
+
* endpoints after the configured threshold. Optional, silently skipped
|
|
81
81
|
* when absent.
|
|
82
82
|
*/
|
|
83
83
|
readonly webhookNotifier?: WebhookNotifier | null;
|
|
84
84
|
/**
|
|
85
85
|
* Terminal focus tracker. Gates the long-task, budget-breach, and
|
|
86
|
-
* agent/chain-failure desktop alerts wired in this module
|
|
86
|
+
* agent/chain-failure desktop alerts wired in this module, see
|
|
87
87
|
* alert-gating.ts. Optional; when absent, none of the new alert
|
|
88
88
|
* behavior is gated by focus (long-task keeps its always-fire
|
|
89
89
|
* behavior from before focus gating existed, and budget-breach/failure alerts are
|
|
@@ -102,7 +102,7 @@ export interface WireTurnEventHandlersOptions {
|
|
|
102
102
|
/**
|
|
103
103
|
* Minimal test seam: injectable clock for controlling Date.now() in tests.
|
|
104
104
|
* Defaults to the real Date.now when absent.
|
|
105
|
-
* @internal
|
|
105
|
+
* @internal, tests only
|
|
106
106
|
*/
|
|
107
107
|
readonly _clock?: () => number;
|
|
108
108
|
}
|
|
@@ -179,7 +179,7 @@ export function wireTurnEventHandlers(
|
|
|
179
179
|
// /session fork reassign `sessionId` on in place (session-workflow.ts,
|
|
180
180
|
// bootstrap-hook-bridge.ts), so a session switch is visible here just by
|
|
181
181
|
// re-reading `runtime.sessionId`. Wrapped so every write re-checks it and
|
|
182
|
-
// rebinds to the new session's file first
|
|
182
|
+
// rebinds to the new session's file first, otherwise the journal opened
|
|
183
183
|
// for the OLD session keeps appending the NEW session's snapshots into the
|
|
184
184
|
// OLD session's file, and a later resume of the old session replays the
|
|
185
185
|
// wrong conversation.
|
|
@@ -192,7 +192,7 @@ export function wireTurnEventHandlers(
|
|
|
192
192
|
// Track turn start time for long-task notification threshold.
|
|
193
193
|
let turnStartTime: number | null = null;
|
|
194
194
|
|
|
195
|
-
// Budget-breach edge-trigger checker
|
|
195
|
+
// Budget-breach edge-trigger checker, one instance per session,
|
|
196
196
|
// piggybacking on the same TURN_COMPLETED handler as the long-task
|
|
197
197
|
// notification below rather than adding a second TURN_COMPLETED subscription.
|
|
198
198
|
const budgetBreachNotifier: BudgetBreachNotifier | null = focusTracker
|
|
@@ -220,7 +220,7 @@ export function wireTurnEventHandlers(
|
|
|
220
220
|
const notifyThreshold = readNotifyAfterSeconds((k) => configManager.get(k as Parameters<typeof configManager.get>[0]));
|
|
221
221
|
// stopReason 'empty_response' signals a non-successful completion.
|
|
222
222
|
const taskStatus: LongTaskStatus = evt.stopReason === 'completed' ? 'ok' : 'fail';
|
|
223
|
-
// In-terminal (OSC 9) turn-end notification
|
|
223
|
+
// In-terminal (OSC 9) turn-end notification, fires on its own per-signal
|
|
224
224
|
// config + focus gate, independent of the long-task duration threshold below.
|
|
225
225
|
terminalNotifier?.notify('turn-end', taskStatus === 'ok' ? 'Turn finished' : 'Turn finished with errors');
|
|
226
226
|
maybeNotifyLongTask({
|
|
@@ -256,10 +256,10 @@ export function wireTurnEventHandlers(
|
|
|
256
256
|
'auto',
|
|
257
257
|
);
|
|
258
258
|
hookDispatcher.fire({ path: 'Lifecycle:session:save' as HookEventPath, phase: 'Lifecycle' as HookPhase, category: 'session' as HookCategory, specific: 'save', sessionId: runtime.sessionId, timestamp: Date.now(), payload: { sessionId: runtime.sessionId } }).catch((err: unknown) => logger.debug('hook fire error', { error: summarizeError(err) }));
|
|
259
|
-
// Snapshot succeeded
|
|
259
|
+
// Snapshot succeeded, rotate the journal (gap-filler no longer needed).
|
|
260
260
|
transcriptJournal.rotate();
|
|
261
261
|
} catch (e) {
|
|
262
|
-
// Snapshot failed
|
|
262
|
+
// Snapshot failed, append the turn to the journal so recovery can
|
|
263
263
|
// reconstruct it. Best-effort; never crash the TUI.
|
|
264
264
|
try {
|
|
265
265
|
const snap = conversation.toJSON() as { messages: Array<import('./conversation.ts').ConversationMessageSnapshot> };
|
|
@@ -270,7 +270,7 @@ export function wireTurnEventHandlers(
|
|
|
270
270
|
// Record this turn's rewind anchor: pair the turnId (shared with the
|
|
271
271
|
// workspace checkpoint the turn engine snapshots for this same turn) with
|
|
272
272
|
// the live conversation message count, so a later message-anchored /rewind
|
|
273
|
-
// can truncate the conversation to exactly this boundary
|
|
273
|
+
// can truncate the conversation to exactly this boundary, the join key
|
|
274
274
|
// between conversation and files rewind (see core/rewind-turn-anchors.ts).
|
|
275
275
|
try {
|
|
276
276
|
recordTurnAnchor(runtime.sessionId, {
|
|
@@ -294,7 +294,7 @@ export function wireTurnEventHandlers(
|
|
|
294
294
|
// In-terminal (OSC 9) agent-blocked notification: a delegated agent parked
|
|
295
295
|
// waiting for a human message (AGENT_AWAITING_MESSAGE) is "blocked on you".
|
|
296
296
|
// Gated by the notifier's own per-signal config + focus rule. PRIVACY: the
|
|
297
|
-
// short agent id only
|
|
297
|
+
// short agent id only, never task text.
|
|
298
298
|
if (terminalNotifier) {
|
|
299
299
|
unsubs.push(events.agents.on('AGENT_AWAITING_MESSAGE', (payload) => {
|
|
300
300
|
terminalNotifier.notify('agent-blocked', `agent ${payload.agentId.slice(0, 8)} is waiting for your input`);
|
|
@@ -311,16 +311,16 @@ export function wireTurnEventHandlers(
|
|
|
311
311
|
// Agent/chain-failure desktop alerts. The SDK's WebhookNotifier and
|
|
312
312
|
// Notifier already fire webhook/Slack/Discord notifications for these two
|
|
313
313
|
// events unconditionally (attachToRuntimeBus in the SDK's
|
|
314
|
-
// platform/integrations
|
|
314
|
+
// platform/integrations, pre-existing, not focus-gated: an out-of-band
|
|
315
315
|
// push to another device is useful regardless of terminal focus). What was
|
|
316
316
|
// missing was a desktop notification, gated by focus like the other three
|
|
317
|
-
// alert classes
|
|
317
|
+
// alert classes, that's the only thing added here, to avoid double-firing
|
|
318
318
|
// a webhook that's already covered.
|
|
319
319
|
if (focusTracker) {
|
|
320
320
|
unsubs.push(events.agents.on('AGENT_FAILED', (payload) => {
|
|
321
321
|
if (!shouldFireAlert(focusTracker, configGet, 'behavior.notifyOnAgentFailure')) return;
|
|
322
322
|
try {
|
|
323
|
-
notifyCompletion('GoodVibes
|
|
323
|
+
notifyCompletion('GoodVibes: agent failed', `agent ${payload.agentId.slice(0, 8)} failed: ${payload.error}`, FORCE_NOTIFY_DURATION_MS);
|
|
324
324
|
} catch (err) {
|
|
325
325
|
logger.debug('turn-event-wiring: agent-failure notify error', { error: String(err) });
|
|
326
326
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* voice-capture-status.ts
|
|
2
|
+
* voice-capture-status.ts, what the shell shows while a microphone is open.
|
|
3
3
|
*
|
|
4
4
|
* A capture indicator is not decoration. Two of the three states here exist
|
|
5
5
|
* because the alternative is a user who cannot tell whether their microphone is
|
|
@@ -41,7 +41,7 @@ export interface VoiceCaptureIndicatorState {
|
|
|
41
41
|
* one keypress ago and is owed the confirmation.
|
|
42
42
|
*/
|
|
43
43
|
readonly indicator: 'off' | 'statusline' | 'banner';
|
|
44
|
-
/** Extra words for the row
|
|
44
|
+
/** Extra words for the row, a restart delay, a latch reason, an elapsed time. */
|
|
45
45
|
readonly detail?: string | undefined;
|
|
46
46
|
}
|
|
47
47
|
|
|
@@ -2,15 +2,15 @@
|
|
|
2
2
|
// voice-provision-gateway.ts
|
|
3
3
|
//
|
|
4
4
|
// The daemon-backed verbs the /voice setup + /voice status surfaces read:
|
|
5
|
-
// voice.local.status (GET /api/voice/local/status)
|
|
6
|
-
// snapshot
|
|
5
|
+
// voice.local.status (GET /api/voice/local/status), the no-network installed
|
|
6
|
+
// snapshot, and voice.local.install (POST /api/voice/local/install), the
|
|
7
7
|
// one-act managed install. Neither has a named facade on the in-process
|
|
8
|
-
// OperatorClient, so
|
|
8
|
+
// OperatorClient, so, exactly like the memory-consolidation gateway, they go
|
|
9
9
|
// over the generic operator invoke path (operator-rpc.ts's resolveOperatorRpc
|
|
10
10
|
// -> sdk.operator.invoke), reaching the SAME daemon the command layer does.
|
|
11
11
|
//
|
|
12
12
|
// A daemon that predates managed voice provisioning answers an honest 501 (verb
|
|
13
|
-
// cataloged but no handler) or a 404 (older daemon without the route)
|
|
13
|
+
// cataloged but no handler) or a 404 (older daemon without the route), both
|
|
14
14
|
// are "verb unavailable", NOT a fabricated empty/failed install (see
|
|
15
15
|
// classifyVoiceProvisionError). The interface is injectable so the command and
|
|
16
16
|
// its tests round-trip against a mocked daemon.
|
|
@@ -33,7 +33,7 @@ export interface VoiceProvisionGateway {
|
|
|
33
33
|
/**
|
|
34
34
|
* Why the gateway could not be built (daemon disabled / no control-plane URL),
|
|
35
35
|
* surfaced verbatim so the surface prints an honest "unavailable" line rather
|
|
36
|
-
* than guessing
|
|
36
|
+
* than guessing, mirrors MemoryConsolidationGatewayResolution.
|
|
37
37
|
*/
|
|
38
38
|
export type VoiceProvisionGatewayResolution =
|
|
39
39
|
| { readonly available: true; readonly gateway: VoiceProvisionGateway }
|
|
@@ -46,7 +46,7 @@ export interface VoiceProvisionGatewayDeps {
|
|
|
46
46
|
|
|
47
47
|
/**
|
|
48
48
|
* Build the live voice-provisioning gateway over the generic operator invoke
|
|
49
|
-
* path
|
|
49
|
+
* path, the same daemon resolution the command layer uses. Returns an honest
|
|
50
50
|
* unavailable reason when no daemon is reachable, so the surface refuses
|
|
51
51
|
* cleanly instead of throwing mid-render.
|
|
52
52
|
*/
|
|
@@ -70,7 +70,7 @@ export type VoiceProvisionFetchFailure =
|
|
|
70
70
|
|
|
71
71
|
/**
|
|
72
72
|
* Classify a voice verb rejection: a 501 (a daemon that predates managed voice
|
|
73
|
-
* provisioning
|
|
73
|
+
* provisioning, cataloged but unhandled) or a 404 (an older daemon without the
|
|
74
74
|
* route) are both "verb unavailable", distinct from a generic request failure
|
|
75
75
|
* (network error, 401/403, 500). Reuses describeOperatorRpcError's wording so
|
|
76
76
|
* the call sites never diverge on how they describe the same daemon response.
|
|
@@ -86,12 +86,12 @@ export function classifyVoiceProvisionError(error: unknown): VoiceProvisionFetch
|
|
|
86
86
|
export const VOICE_SETUP_ANNOUNCEMENT = [
|
|
87
87
|
'Local Voice Setup',
|
|
88
88
|
' provisioning the managed local voice runtime (piper TTS + a default voice; whisper STT where a bundle is published)…',
|
|
89
|
-
' downloads are checksum-verified and resumable
|
|
89
|
+
' downloads are checksum-verified and resumable; re-run /voice setup to retry any failed component.',
|
|
90
90
|
].join('\n');
|
|
91
91
|
|
|
92
92
|
/**
|
|
93
93
|
* Render the /voice status or /voice setup RESULT block from an already-resolved
|
|
94
|
-
* gateway resolution
|
|
94
|
+
* gateway resolution, the testable core the command wraps. Kept separate from
|
|
95
95
|
* the live gateway construction so a wire test injects a fake resolution
|
|
96
96
|
* (available / unavailable / failing) with no HTTP, mirroring the Memory modal's
|
|
97
97
|
* injectable resolveConsolidationGateway seam. The caller prints
|
|
@@ -120,7 +120,7 @@ export async function renderVoiceProvision(
|
|
|
120
120
|
// setup
|
|
121
121
|
try {
|
|
122
122
|
const receipt = await resolution.gateway.runInstall();
|
|
123
|
-
return ['Local Voice Setup
|
|
123
|
+
return ['Local Voice Setup: receipt', ...voiceInstallReceiptLines(receipt)].join('\n');
|
|
124
124
|
} catch (error) {
|
|
125
125
|
const failure = classifyVoiceProvisionError(error);
|
|
126
126
|
return failure.kind === 'unavailable'
|
|
@@ -146,7 +146,7 @@ const realSleep = (ms: number): Promise<void> => new Promise((resolve) => setTim
|
|
|
146
146
|
* `installInProgress` snapshot, printing a per-component line each time a
|
|
147
147
|
* component's phase advances (download → verify → extract → done). When the
|
|
148
148
|
* install settles, print the final receipt (or an honest failure). The install
|
|
149
|
-
* verb streams nothing itself
|
|
149
|
+
* verb streams nothing itself, this polling is exactly how the SDK intends
|
|
150
150
|
* surfaces to render real progress instead of busy→receipt.
|
|
151
151
|
*
|
|
152
152
|
* The caller prints VOICE_SETUP_ANNOUNCEMENT before calling this. gateway
|
|
@@ -192,7 +192,7 @@ export async function runVoiceSetupWithProgress(
|
|
|
192
192
|
|
|
193
193
|
const result = await installPromise;
|
|
194
194
|
if (result.ok) {
|
|
195
|
-
opts.print(['Local Voice Setup
|
|
195
|
+
opts.print(['Local Voice Setup: receipt', ...voiceInstallReceiptLines(result.receipt)].join('\n'));
|
|
196
196
|
} else {
|
|
197
197
|
const failure = classifyVoiceProvisionError(result.error);
|
|
198
198
|
opts.print(failure.kind === 'unavailable'
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
// ---------------------------------------------------------------------------
|
|
2
|
-
// voice-provision-status.ts
|
|
2
|
+
// voice-provision-status.ts, the surface-facing projection of the managed
|
|
3
3
|
// local-voice runtime (voice.local.status / voice.local.install).
|
|
4
4
|
//
|
|
5
5
|
// The SDK owns the provisioning policy: a one-act install that fetches the
|
|
6
6
|
// piper TTS engine + a default voice (fully hosted) and, where a pinned bundle
|
|
7
|
-
// is hosted for the platform, the whisper STT engine + model
|
|
7
|
+
// is hosted for the platform, the whisper STT engine + model, atomic,
|
|
8
8
|
// checksum-verified, resumable, and honest about every terminal state. This
|
|
9
9
|
// module is the read-only projection the /voice surfaces render from: sizes
|
|
10
10
|
// declared up front, a receipt of what was installed / skipped / failed, and
|
|
@@ -18,9 +18,9 @@
|
|
|
18
18
|
|
|
19
19
|
import type { OperatorMethodOutput } from '@pellux/goodvibes-sdk';
|
|
20
20
|
|
|
21
|
-
/** voice.local.status output
|
|
21
|
+
/** voice.local.status output, the no-network installed/available snapshot. */
|
|
22
22
|
export type VoiceRuntimeStatusResult = OperatorMethodOutput<'voice.local.status'>;
|
|
23
|
-
/** voice.local.install receipt
|
|
23
|
+
/** voice.local.install receipt, the one-act install outcome. */
|
|
24
24
|
export type VoiceLocalInstallResult = OperatorMethodOutput<'voice.local.install'>;
|
|
25
25
|
/** The live per-component progress carried on voice.local.status WHILE an install runs. */
|
|
26
26
|
export type VoiceInstallProgress = NonNullable<VoiceRuntimeStatusResult['installInProgress']>;
|
|
@@ -43,7 +43,7 @@ export function formatVoiceBytes(bytes: number | null | undefined): string {
|
|
|
43
43
|
|
|
44
44
|
/**
|
|
45
45
|
* True when a whisper STT bundle is PINNED for this platform (bytes + checksum
|
|
46
|
-
* fixed) but not yet hosted/sideloaded
|
|
46
|
+
* fixed) but not yet hosted/sideloaded, the "supported but not yet published"
|
|
47
47
|
* state. The SDK signals it as supported === true with an unprovisioned state
|
|
48
48
|
* and an honest reason string; contrast an unsupported platform (supported ===
|
|
49
49
|
* false), which has no pin at all.
|
|
@@ -60,7 +60,7 @@ export function voiceRuntimeNeedsSetup(status: VoiceRuntimeStatusResult): boolea
|
|
|
60
60
|
}
|
|
61
61
|
|
|
62
62
|
/**
|
|
63
|
-
* The /voice status lines
|
|
63
|
+
* The /voice status lines, an honest, plain-language account of the managed
|
|
64
64
|
* local-voice runtime with sizes declared up front. Order: platform + overall
|
|
65
65
|
* state, then the TTS (piper) engine, then the STT (whisper) engine with its
|
|
66
66
|
* honest unsupported / not-yet-published wording, then the one-act offer size.
|
|
@@ -70,7 +70,7 @@ export function voiceStatusLines(status: VoiceRuntimeStatusResult): string[] {
|
|
|
70
70
|
lines.push(` platform: ${status.platform ?? 'unrecognized (no managed voice build)'}`);
|
|
71
71
|
lines.push(` runtime: ${status.state}`);
|
|
72
72
|
|
|
73
|
-
// TTS
|
|
73
|
+
// TTS, piper, fully hosted where a platform build exists.
|
|
74
74
|
const tts = status.tts;
|
|
75
75
|
if (tts.binaryPresent && tts.voicePresent) {
|
|
76
76
|
lines.push(` tts (${tts.engine}): installed`);
|
|
@@ -81,9 +81,9 @@ export function voiceStatusLines(status: VoiceRuntimeStatusResult): string[] {
|
|
|
81
81
|
lines.push(` tts (${tts.engine}): not installed${have.length ? ` (have ${have.join(' + ')})` : ''}`);
|
|
82
82
|
}
|
|
83
83
|
|
|
84
|
-
// STT
|
|
84
|
+
// STT, whisper, hosted only where a pinned bundle is published. Render the
|
|
85
85
|
// REAL state honestly: a platform with no pinned build (supported === false,
|
|
86
|
-
// or state 'unsupported-platform'
|
|
86
|
+
// or state 'unsupported-platform', every platform except linux-x64 today)
|
|
87
87
|
// reads "unsupported on this platform"; a platform whose bundle is pinned but
|
|
88
88
|
// not yet hosted (supported === true, unprovisioned, with a reason) reads
|
|
89
89
|
// "not yet published for this platform".
|
|
@@ -102,7 +102,7 @@ export function voiceStatusLines(status: VoiceRuntimeStatusResult): string[] {
|
|
|
102
102
|
}
|
|
103
103
|
|
|
104
104
|
if (status.offerBytes !== null && status.offerBytes !== undefined && voiceRuntimeNeedsSetup(status)) {
|
|
105
|
-
lines.push(` setup download: ${formatVoiceBytes(status.offerBytes)}
|
|
105
|
+
lines.push(` setup download: ${formatVoiceBytes(status.offerBytes)}; run /voice setup to install`);
|
|
106
106
|
}
|
|
107
107
|
return lines;
|
|
108
108
|
}
|
|
@@ -127,7 +127,7 @@ export function voiceInstallComponentLine(component: VoiceInstallComponentProgre
|
|
|
127
127
|
const done = component.bytesDone !== undefined ? `${formatVoiceBytes(component.bytesDone)}/` : '';
|
|
128
128
|
size = ` (${done}${formatVoiceBytes(component.bytesTotal)})`;
|
|
129
129
|
}
|
|
130
|
-
const msg = component.message ?
|
|
130
|
+
const msg = component.message ? `: ${component.message}` : '';
|
|
131
131
|
return ` ${component.component}: ${voiceProgressPhaseLabel(component.phase)}${size}${msg}`;
|
|
132
132
|
}
|
|
133
133
|
|
|
@@ -142,22 +142,22 @@ export function voiceEngineOutcomeLine(engine: string, state: string, reason: st
|
|
|
142
142
|
case 'provisioned':
|
|
143
143
|
return ` ${engine}: installed`;
|
|
144
144
|
case 'download-failed':
|
|
145
|
-
return ` ${engine}: download failed${reason ?
|
|
145
|
+
return ` ${engine}: download failed${reason ? `; ${reason}` : ''} (re-run /voice setup to retry; completed parts are kept)`;
|
|
146
146
|
case 'checksum-mismatch':
|
|
147
|
-
return ` ${engine}: checksum mismatch
|
|
147
|
+
return ` ${engine}: checksum mismatch; the downloaded file did not match its pinned checksum and was discarded${reason ? ` (${reason})` : ''}`;
|
|
148
148
|
case 'bundle-unavailable':
|
|
149
|
-
return ` ${engine}: not yet published for this platform${reason ?
|
|
149
|
+
return ` ${engine}: not yet published for this platform${reason ? `; ${reason}` : ''}`;
|
|
150
150
|
case 'sideload-mismatch':
|
|
151
|
-
return ` ${engine}: a sideloaded bundle was present but did not match the pinned checksum${reason ?
|
|
151
|
+
return ` ${engine}: a sideloaded bundle was present but did not match the pinned checksum${reason ? `; ${reason}` : ''}`;
|
|
152
152
|
case 'unsupported-platform':
|
|
153
|
-
return ` ${engine}: unsupported on this platform${reason ?
|
|
153
|
+
return ` ${engine}: unsupported on this platform${reason ? `; ${reason}` : ''}`;
|
|
154
154
|
default:
|
|
155
|
-
return ` ${engine}: ${state}${reason ?
|
|
155
|
+
return ` ${engine}: ${state}${reason ? `; ${reason}` : ''}`;
|
|
156
156
|
}
|
|
157
157
|
}
|
|
158
158
|
|
|
159
159
|
/**
|
|
160
|
-
* The /voice setup receipt lines
|
|
160
|
+
* The /voice setup receipt lines, the final one-act outcome. Renders the
|
|
161
161
|
* per-component breakdown (installed / skipped-as-present / failed with size),
|
|
162
162
|
* the TTS and STT terminal states with honest wording, and the config write
|
|
163
163
|
* receipt (which voice.local.* keys were configured vs skipped as user-set).
|
|
@@ -174,7 +174,7 @@ export function voiceInstallReceiptLines(result: VoiceLocalInstallResult): strin
|
|
|
174
174
|
lines.push(' components:');
|
|
175
175
|
for (const component of result.components) {
|
|
176
176
|
const size = component.bytes !== undefined ? ` (${formatVoiceBytes(component.bytes)})` : '';
|
|
177
|
-
const err = component.error ?
|
|
177
|
+
const err = component.error ? `: ${component.error}` : '';
|
|
178
178
|
const state = component.state === 'skipped' ? 'already present' : component.state;
|
|
179
179
|
lines.push(` ${component.id}: ${state}${size}${err}`);
|
|
180
180
|
}
|
|
@@ -1,16 +1,16 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* voice-stt-gateway.ts
|
|
2
|
+
* voice-stt-gateway.ts, speech-to-text for captured audio.
|
|
3
3
|
*
|
|
4
4
|
* Both voice consumers end here: push-to-talk hands over what the user just
|
|
5
5
|
* said, and a confirmed wake hands over the utterance that followed it. The
|
|
6
|
-
* transcription itself is the daemon's, not this process's
|
|
6
|
+
* transcription itself is the daemon's, not this process's, `voice.stt`
|
|
7
7
|
* (POST /api/voice/stt) transcribes an audio artifact through whichever voice
|
|
8
8
|
* provider is registered, including the managed local whisper that
|
|
9
9
|
* `/voice setup` provisions.
|
|
10
10
|
*
|
|
11
11
|
* The verb has no named facade on the in-process OperatorClient, so it goes over
|
|
12
12
|
* the generic operator invoke path exactly like the voice PROVISIONING verbs do
|
|
13
|
-
* (see core/voice-provision-gateway.ts)
|
|
13
|
+
* (see core/voice-provision-gateway.ts), same daemon, same resolution, same
|
|
14
14
|
* honest refusal reasons up front rather than a throw mid-capture.
|
|
15
15
|
*/
|
|
16
16
|
|
|
@@ -20,7 +20,7 @@ import type { OperatorMethodOutput } from '@pellux/goodvibes-sdk';
|
|
|
20
20
|
import type { UtteranceAudioArtifact } from '@pellux/goodvibes-sdk/platform/voice';
|
|
21
21
|
import { resolveOperatorRpc, describeOperatorRpcError } from '../input/commands/operator-rpc.ts';
|
|
22
22
|
|
|
23
|
-
/** voice.stt output
|
|
23
|
+
/** voice.stt output, the recognised text plus the provider that produced it. */
|
|
24
24
|
export type VoiceTranscriptionResult = OperatorMethodOutput<'voice.stt'>;
|
|
25
25
|
|
|
26
26
|
/** The narrow verb surface a capture consumer needs. */
|
|
@@ -64,12 +64,12 @@ export function createVoiceSttGateway(deps: VoiceSttGatewayDeps): VoiceSttGatewa
|
|
|
64
64
|
/**
|
|
65
65
|
* Render a `voice.stt` rejection honestly. A 501 (the verb is cataloged but this
|
|
66
66
|
* daemon has no voice provider wired behind it) and a 404 (an older daemon
|
|
67
|
-
* without the route) are both "no transcription here"
|
|
67
|
+
* without the route) are both "no transcription here", distinct from a request
|
|
68
68
|
* that reached a provider and failed, which the user can act on differently.
|
|
69
69
|
*/
|
|
70
70
|
export function describeTranscriptionFailure(error: unknown): string {
|
|
71
71
|
if (error instanceof GoodVibesSdkError && (error.status === 501 || error.status === 404)) {
|
|
72
|
-
return 'this daemon has no speech-to-text provider wired up
|
|
72
|
+
return 'this daemon has no speech-to-text provider wired up; run /voice setup to provision the managed local runtime.';
|
|
73
73
|
}
|
|
74
74
|
return describeOperatorRpcError(error);
|
|
75
75
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
// ---------------------------------------------------------------------------
|
|
2
|
-
// wake-provision-runner.ts
|
|
2
|
+
// wake-provision-runner.ts, what `/voice wake status` and `/voice wake setup` do.
|
|
3
3
|
//
|
|
4
4
|
// `/voice wake setup` IS NO LONGER HOW THE MODEL ARRIVES. It used to be the only
|
|
5
5
|
// way, and the result was that installing goodvibes produced a wake-word feature
|
|
@@ -11,17 +11,17 @@
|
|
|
11
11
|
// So what this command is FOR, on a normal machine, is recovery and
|
|
12
12
|
// re-provisioning: an install that was offline, an artifact that stopped
|
|
13
13
|
// verifying, or a re-fetch after the pinned model changes. It still works
|
|
14
|
-
// exactly as it did, which is the point
|
|
14
|
+
// exactly as it did, which is the point, the degraded path an offline install
|
|
15
15
|
// falls back to is this one.
|
|
16
16
|
//
|
|
17
17
|
// What has NOT changed is the runtime rule. Nothing in this path downloads on its
|
|
18
18
|
// own: `/voice wake status` only reads what is on disk (verifying by content,
|
|
19
19
|
// never by existence), and a download happens only because the user typed
|
|
20
|
-
// `setup`. Turning `voice.wake.enabled` on never fetches anything either
|
|
20
|
+
// `setup`. Turning `voice.wake.enabled` on never fetches anything either, see
|
|
21
21
|
// audio/wake-runtime.ts, which reports what is missing and names this command.
|
|
22
22
|
//
|
|
23
|
-
// Both SDK calls are injectable so a wire test drives the whole flow
|
|
24
|
-
// host, a corrupt artifact, a failed component
|
|
23
|
+
// Both SDK calls are injectable so a wire test drives the whole flow, a fresh
|
|
24
|
+
// host, a corrupt artifact, a failed component, with no network and no files.
|
|
25
25
|
// ---------------------------------------------------------------------------
|
|
26
26
|
|
|
27
27
|
import {
|
|
@@ -74,12 +74,12 @@ export async function runWakeProvision(deps: WakeProvisionRunnerDeps): Promise<v
|
|
|
74
74
|
const onProgress = (progress: WakeProvisionProgress): void => {
|
|
75
75
|
if (lastPhase.get(progress.component) === progress.phase) return;
|
|
76
76
|
lastPhase.set(progress.component, progress.phase);
|
|
77
|
-
const extra = progress.message !== undefined ?
|
|
77
|
+
const extra = progress.message !== undefined ? `: ${progress.message}` : '';
|
|
78
78
|
deps.print(` ${progress.component}: ${progress.phase}${extra}`);
|
|
79
79
|
};
|
|
80
80
|
try {
|
|
81
81
|
const result = await provision(deps.managedRoot, onProgress);
|
|
82
|
-
deps.print(['Wake-Word Setup
|
|
82
|
+
deps.print(['Wake-Word Setup: receipt', ...wakeProvisionReceiptLines(result)].join('\n'));
|
|
83
83
|
} catch (error) {
|
|
84
84
|
deps.print(`Wake-Word Setup\n provisioning failed: ${error instanceof Error ? error.message : String(error)}`);
|
|
85
85
|
}
|
|
@@ -1,16 +1,16 @@
|
|
|
1
1
|
// ---------------------------------------------------------------------------
|
|
2
|
-
// wake-provision-status.ts
|
|
2
|
+
// wake-provision-status.ts, the surface-facing projection of wake-word
|
|
3
3
|
// provisioning and of the rows that are or are not in force.
|
|
4
4
|
//
|
|
5
5
|
// The wake models are checksum-pinned and arrive WITH THE INSTALLATION: the
|
|
6
6
|
// installer and the npm postinstall provision them, and a daemon retries at boot
|
|
7
7
|
// whatever the install could not fetch. `/voice wake setup` is the recovery act
|
|
8
|
-
// for the case where that did not land, not the normal way in
|
|
8
|
+
// for the case where that did not land, not the normal way in, so the lines
|
|
9
9
|
// below name it where it helps and do not imply it is a required step.
|
|
10
10
|
//
|
|
11
11
|
// This module is the read-only projection the /voice wake surfaces render from:
|
|
12
12
|
// per-artifact present / verified / corrupt / bytes taken straight from the SDK's
|
|
13
|
-
// wakeProvisionStatus, which verifies by CONTENT rather than by existence
|
|
13
|
+
// wakeProvisionStatus, which verifies by CONTENT rather than by existence, a
|
|
14
14
|
// truncated or wrong-asset file reports corrupt instead of present, because a
|
|
15
15
|
// detector loading it would fail in a way the user could not diagnose.
|
|
16
16
|
//
|
|
@@ -31,15 +31,15 @@ import { formatVoiceBytes } from './voice-provision-status.ts';
|
|
|
31
31
|
|
|
32
32
|
/**
|
|
33
33
|
* What a terminal can actually do, so a `voice.wake.*` row is refused or reported
|
|
34
|
-
* rather than faked. Lives here
|
|
35
|
-
* inference runtime
|
|
34
|
+
* rather than faked. Lives here, beside the status projection and away from the
|
|
35
|
+
* inference runtime, so the command layer can resolve settings without pulling
|
|
36
36
|
* onnxruntime into a `/voice wake status` call.
|
|
37
37
|
*/
|
|
38
38
|
export function terminalWakeCapabilities(status?: Pick<WakeProvisionStatus, 'vadReady'>): WakeSurfaceCapabilities {
|
|
39
39
|
return {
|
|
40
40
|
// Asked of the SDK rather than declared here. The filter is a WebAssembly
|
|
41
41
|
// module carried in the package, so the only question is whether this runtime
|
|
42
|
-
// has WebAssembly at all
|
|
42
|
+
// has WebAssembly at all, which the SDK answers, with a reason a settings
|
|
43
43
|
// surface can show. A host constant would go stale the moment the stage
|
|
44
44
|
// shipped, which is exactly what happened to the previous one.
|
|
45
45
|
speexAvailable: noiseSuppressionSupport().supported,
|
|
@@ -58,14 +58,14 @@ export function terminalWakeCapabilities(status?: Pick<WakeProvisionStatus, 'vad
|
|
|
58
58
|
export function wakeArtifactLine(label: string, artifact: WakeArtifactStatus): string {
|
|
59
59
|
if (artifact.verified) return ` ${label}: verified (${formatVoiceBytes(artifact.bytes)})`;
|
|
60
60
|
if (artifact.corrupt) {
|
|
61
|
-
return ` ${label}: PRESENT BUT FAILS VERIFICATION (${formatVoiceBytes(artifact.bytes)})
|
|
61
|
+
return ` ${label}: PRESENT BUT FAILS VERIFICATION (${formatVoiceBytes(artifact.bytes)}); torn, truncated, or the wrong asset; /voice wake setup replaces it`;
|
|
62
62
|
}
|
|
63
63
|
return ` ${label}: missing`;
|
|
64
64
|
}
|
|
65
65
|
|
|
66
66
|
/**
|
|
67
67
|
* Blockers, in the SDK's own words. A blocker means the detector must NOT start,
|
|
68
|
-
* so the row's key and the written reason are both shown
|
|
68
|
+
* so the row's key and the written reason are both shown, a swallowed blocker is
|
|
69
69
|
* a user staring at a feature that is on and doing nothing.
|
|
70
70
|
*/
|
|
71
71
|
export function describeWakeBlockers(settings: Pick<WakeRuntimeSettings, 'blockers'>): string[] {
|
|
@@ -102,14 +102,14 @@ export function wakeStatusLines(
|
|
|
102
102
|
// someone turns it on, so a missing gate is not a broken detector. It is
|
|
103
103
|
// printed rather than left out because vadThreshold above 0 refuses to start
|
|
104
104
|
// when the gate is absent, and a reader needs to see why.
|
|
105
|
-
` speech gate provisioned: ${status.vadReady ? 'yes' : 'no
|
|
105
|
+
` speech gate provisioned: ${status.vadReady ? 'yes' : 'no; voice.wake.vadThreshold above 0 will refuse to start'}`,
|
|
106
106
|
wakeArtifactLine('speech gate', status.vad),
|
|
107
107
|
wakeArtifactLine('attribution NOTICE (speech gate)', status.vadNotice),
|
|
108
108
|
];
|
|
109
109
|
if (!status.ready) {
|
|
110
110
|
lines.push(
|
|
111
111
|
` a fresh provision would download ${formatVoiceBytes(status.downloadBytes)}. Installing goodvibes normally does this,`,
|
|
112
|
-
' and a running daemon retries at boot
|
|
112
|
+
' and a running daemon retries at boot; run /voice wake setup to fetch it now (nothing downloads on its own).',
|
|
113
113
|
);
|
|
114
114
|
}
|
|
115
115
|
lines.push(
|
|
@@ -120,7 +120,7 @@ export function wakeStatusLines(
|
|
|
120
120
|
` retained audio: voice.wake.retainAudio=${settings.retainAudio}`,
|
|
121
121
|
);
|
|
122
122
|
if (status.recallIsSyntheticOnly) {
|
|
123
|
-
lines.push(' the published recall figures for this model are measured on synthesised speech only
|
|
123
|
+
lines.push(' the published recall figures for this model are measured on synthesised speech only; no human recording of the phrase exists behind them.');
|
|
124
124
|
}
|
|
125
125
|
const blockers = describeWakeBlockers(settings);
|
|
126
126
|
if (blockers.length > 0) lines.push(' rows blocking startup:', ...blockers);
|
|
@@ -136,15 +136,15 @@ export function wakeProvisionReceiptLines(result: WakeProvisionResult): string[]
|
|
|
136
136
|
` model version: ${result.modelVersion ?? 'unpinned'}`,
|
|
137
137
|
// Separate from `ready` on purpose: this terminal loads the onnx build, so a
|
|
138
138
|
// missing tflite twin is not a detector that cannot run.
|
|
139
|
-
` tflite form (for runtimes that cannot load onnx): ${result.mobileFormatReady ? 'installed' : 'not installed
|
|
139
|
+
` tflite form (for runtimes that cannot load onnx): ${result.mobileFormatReady ? 'installed' : 'not installed; nothing on this terminal needs it'}`,
|
|
140
140
|
// Separate from `ready` for its own reason: voice.wake.vadThreshold ships at
|
|
141
|
-
// 0, so the detector runs without the gate
|
|
141
|
+
// 0, so the detector runs without the gate, but a value above 0 refuses to
|
|
142
142
|
// start without it, which is what this line lets a reader act on.
|
|
143
|
-
` speech gate (voice.wake.vadThreshold): ${result.vadReady ? 'installed' : 'not installed
|
|
143
|
+
` speech gate (voice.wake.vadThreshold): ${result.vadReady ? 'installed' : 'not installed; voice.wake.vadThreshold above 0 will refuse to start'}`,
|
|
144
144
|
];
|
|
145
145
|
for (const outcome of result.outcomes) {
|
|
146
146
|
const detail = outcome.state === 'failed'
|
|
147
|
-
?
|
|
147
|
+
? `: ${outcome.error ?? 'no reason reported'}`
|
|
148
148
|
: outcome.bytes !== undefined ? ` (${formatVoiceBytes(outcome.bytes)})` : '';
|
|
149
149
|
lines.push(` ${outcome.component}: ${outcome.state}${detail}`);
|
|
150
150
|
lines.push(` ${outcome.path}`);
|
|
@@ -156,7 +156,7 @@ export function wakeProvisionReceiptLines(result: WakeProvisionResult): string[]
|
|
|
156
156
|
lines.push(` attribution NOTICE (travels with the front end): ${result.embeddingNoticePath}`);
|
|
157
157
|
}
|
|
158
158
|
if (result.recallIsSyntheticOnly) {
|
|
159
|
-
lines.push(' the published recall figures for this model are measured on synthesised speech only
|
|
159
|
+
lines.push(' the published recall figures for this model are measured on synthesised speech only; no human recording of the phrase exists behind them.');
|
|
160
160
|
}
|
|
161
161
|
return lines;
|
|
162
162
|
}
|
|
@@ -165,6 +165,6 @@ export function wakeProvisionReceiptLines(result: WakeProvisionResult): string[]
|
|
|
165
165
|
export const WAKE_SETUP_ANNOUNCEMENT = [
|
|
166
166
|
'Wake-Word Setup',
|
|
167
167
|
' downloading the pinned "hey goodvibes" classifier (both runtime formats), the shared speech-embedding front end, and the speech gate voice.wake.vadThreshold runs…',
|
|
168
|
-
' every artifact is checksum-verified and the download is resumable
|
|
168
|
+
' every artifact is checksum-verified and the download is resumable; one that already matches is skipped, so re-running this only fetches what is missing.',
|
|
169
169
|
' installing goodvibes normally does this for you; running it by hand is how you recover an install that could not reach the network.',
|
|
170
170
|
].join('\n');
|
|
@@ -1,16 +1,16 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* workstream-notification.ts
|
|
2
|
+
* workstream-notification.ts, the desktop notification a finished workstream
|
|
3
3
|
* pushes, in words rather than identifiers.
|
|
4
4
|
*
|
|
5
5
|
* These three notifications used to read:
|
|
6
6
|
*
|
|
7
|
-
* GoodVibes
|
|
7
|
+
* GoodVibes, WRFC chain failed
|
|
8
8
|
* chain 7f3a91c02b4e failed: review rejected
|
|
9
9
|
*
|
|
10
10
|
* A desktop notification is a message TO a person, so the standing rule applies
|
|
11
11
|
* to it the same way it applies to a chat message: no internal name for the
|
|
12
12
|
* machinery, and no register id. `WRFC` is the first; `7f3a91c02b4e` is the
|
|
13
|
-
* second, and it is not something the reader can do anything with
|
|
13
|
+
* second, and it is not something the reader can do anything with, it is not
|
|
14
14
|
* the commit, not the branch, not the session.
|
|
15
15
|
*
|
|
16
16
|
* What the reader can act on is why the work stopped, so that is what the body
|
|
@@ -19,7 +19,7 @@
|
|
|
19
19
|
* plain words, never by an opaque identifier.
|
|
20
20
|
*
|
|
21
21
|
* Split out of turn-event-wiring.ts as a pure function so the text is testable
|
|
22
|
-
* on its own
|
|
22
|
+
* on its own, the wiring itself cannot be asserted against without mocking a
|
|
23
23
|
* process-global notifier.
|
|
24
24
|
*/
|
|
25
25
|
import { formatTurnBudgetOutcome } from './turn-budget-outcome.ts';
|
|
@@ -40,7 +40,7 @@ export interface WorkstreamNotification {
|
|
|
40
40
|
/**
|
|
41
41
|
* Title and body for a workstream that reached a terminal state.
|
|
42
42
|
*
|
|
43
|
-
* An operator cancellation is an intended stop, not a failure
|
|
43
|
+
* An operator cancellation is an intended stop, not a failure, it is narrated
|
|
44
44
|
* as cancelled (the reason already carries the landed-work count from the
|
|
45
45
|
* workstream's edit ledger) so the notification never contradicts the cancelled
|
|
46
46
|
* workstream/owner/cohort surfaces. A turn-budget exhaustion is a spent ceiling
|
|
@@ -52,18 +52,18 @@ export function workstreamFailureNotification(
|
|
|
52
52
|
): WorkstreamNotification {
|
|
53
53
|
if (payload.failureKind === 'cancelled') {
|
|
54
54
|
return {
|
|
55
|
-
title: 'GoodVibes
|
|
55
|
+
title: 'GoodVibes: workstream cancelled',
|
|
56
56
|
body: `Cancelled: ${payload.reason}`,
|
|
57
57
|
};
|
|
58
58
|
}
|
|
59
59
|
if (payload.failureKind === 'max_turns') {
|
|
60
60
|
return {
|
|
61
|
-
title: 'GoodVibes
|
|
61
|
+
title: 'GoodVibes: workstream hit its turn budget',
|
|
62
62
|
body: `The workstream ${formatTurnBudgetOutcome({ limit: payload.turnLimit, source: payload.turnLimitSource })}`,
|
|
63
63
|
};
|
|
64
64
|
}
|
|
65
65
|
return {
|
|
66
|
-
title: 'GoodVibes
|
|
66
|
+
title: 'GoodVibes: workstream failed',
|
|
67
67
|
body: `Failed: ${payload.failureKind === 'transport' ? 'transient transport error' : payload.reason}`,
|
|
68
68
|
};
|
|
69
69
|
}
|