@pellux/goodvibes-tui 1.27.1 → 2.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +127 -2
- package/README.md +7 -9
- package/bin/goodvibes +2 -2
- package/bin/launcher-support.js +8 -4
- package/docs/README.md +11 -2
- package/docs/foundation-artifacts/operator-contract.json +6403 -2347
- package/package.json +14 -25
- package/scripts/postinstall.js +35 -35
- package/src/audio/spoken-turn-model-routing.ts +1 -1
- package/src/cli/bundle-command.ts +5 -5
- package/src/cli/completions/generate.ts +1 -1
- package/src/cli/doctor.ts +3 -3
- package/src/cli/entrypoint.ts +12 -7
- package/src/cli/help.ts +4 -5
- package/src/cli/hooks-command.ts +1 -1
- package/src/cli/index.ts +1 -4
- package/src/cli/launch-auto-update.ts +59 -7
- package/src/cli/management-commands.ts +6 -6
- package/src/cli/management-utils.ts +5 -5
- package/src/cli/management.ts +7 -7
- package/src/cli/network-posture.ts +1 -1
- package/src/cli/package-verification.ts +7 -6
- package/src/cli/plugin-bundles-command.ts +1 -1
- package/src/cli/plugin-command.ts +2 -2
- package/src/cli/service-command.ts +2 -2
- package/src/cli/service-posture.ts +4 -4
- package/src/cli/status.ts +9 -8
- package/src/cli/surface-command.ts +4 -4
- package/src/cli/tui-startup.ts +3 -3
- package/src/cli-flags.ts +3 -3
- package/src/config/goodvibes-home-audit.ts +0 -2
- package/src/config/secret-config.ts +37 -5
- package/src/config/tui-extension-settings.ts +1 -1
- package/src/core/approval-alert.ts +2 -2
- package/src/core/budget-breach-notifier.ts +3 -3
- package/src/core/conversation-compaction-render.ts +1 -1
- package/src/core/conversation-line-cache.ts +1 -1
- package/src/core/conversation-render-context.ts +1 -1
- package/src/core/conversation-rendering.ts +2 -2
- package/src/core/conversation.ts +10 -10
- package/src/core/long-task-notifier.ts +2 -2
- package/src/core/memory-diagnostics-gateway.ts +1 -1
- package/src/core/scriptable-statusline.ts +1 -1
- package/src/core/session-auto-titler.ts +1 -1
- package/src/core/session-resume-core.ts +2 -2
- package/src/core/stream-event-wiring.ts +24 -44
- package/src/core/terminal-notifier.ts +3 -3
- package/src/core/turn-cancellation.ts +1 -1
- package/src/core/turn-event-wiring.ts +5 -5
- package/src/input/command-registry.ts +6 -6
- package/src/input/commands/channel-pairing.ts +1 -1
- package/src/input/commands/cluster-runtime.ts +1 -1
- package/src/input/commands/codebase-runtime.ts +1 -1
- package/src/input/commands/devices-runtime.ts +1 -1
- package/src/input/commands/hosted-runtime.ts +330 -0
- package/src/input/commands/local-setup-review.ts +1 -1
- package/src/input/commands/local-setup-transfer.ts +2 -2
- package/src/input/commands/local-setup.ts +3 -3
- package/src/input/commands/managed-runtime.ts +2 -2
- package/src/input/commands/operator-rpc.ts +24 -110
- package/src/input/commands/payment-card-intake.ts +1 -1
- package/src/input/commands/permissions-provenance.ts +2 -2
- package/src/input/commands/plugin-runtime.ts +1 -1
- package/src/input/commands/provider.ts +1 -1
- package/src/input/commands/relay-runtime.ts +18 -9
- package/src/input/commands/rewind-runtime.ts +1 -1
- package/src/input/commands/runtime-services.ts +1 -1
- package/src/input/commands/services-runtime.ts +1 -1
- package/src/input/commands/session-workflow.ts +1 -1
- package/src/input/commands/settings-sync-runtime.ts +2 -2
- package/src/input/commands/share-runtime.ts +1 -1
- package/src/input/commands/tasks-runtime.ts +145 -55
- package/src/input/commands/update-runtime.ts +31 -28
- package/src/input/commands/work-plan-runtime.ts +2 -2
- package/src/input/commands/workstream-attempts.ts +1 -1
- package/src/input/commands/workstream-runtime.ts +2 -2
- package/src/input/commands.ts +2 -0
- package/src/input/feature-unit-layout.ts +1 -1
- package/src/input/feed-context-factory.ts +3 -3
- package/src/input/handler-content-actions.ts +2 -2
- package/src/input/handler-feed-routes.ts +1 -1
- package/src/input/handler-feed.ts +3 -3
- package/src/input/handler-modal-token-routes.ts +1 -1
- package/src/input/handler-onboarding-daemon-adopt.ts +3 -2
- package/src/input/handler-onboarding.ts +1 -1
- package/src/input/handler-types.ts +2 -2
- package/src/input/handler-ui-state.ts +1 -1
- package/src/input/handler.ts +4 -4
- package/src/input/input-history.ts +1 -1
- package/src/input/onboarding/onboarding-feature-units.ts +2 -2
- package/src/input/onboarding/onboarding-runtime-status.ts +15 -1
- package/src/input/onboarding/onboarding-wizard-apply.ts +17 -8
- package/src/input/onboarding/onboarding-wizard-cloudflare-step.ts +5 -3
- package/src/input/onboarding/onboarding-wizard-external-surfaces.ts +1 -1
- package/src/input/onboarding/onboarding-wizard-types.ts +1 -1
- package/src/input/payments-config.ts +6 -6
- package/src/input/search.ts +1 -1
- package/src/input/session-picker-modal.ts +46 -0
- package/src/input/settings-modal-activation.ts +1 -1
- package/src/input/settings-modal-behavior.ts +4 -4
- package/src/input/settings-modal-commit.ts +11 -0
- package/src/input/settings-modal-data.ts +9 -122
- package/src/input/settings-modal-mutations.ts +33 -0
- package/src/input/settings-modal-secrets.ts +34 -0
- package/src/input/settings-modal-subscriptions.ts +1 -1
- package/src/input/settings-modal-types.ts +15 -1
- package/src/input/settings-modal.ts +28 -3
- package/src/input/worktree-setup-config.ts +1 -1
- package/src/main.ts +11 -9
- package/src/panels/agent-inspector-shared.ts +2 -2
- package/src/panels/base-panel.ts +2 -2
- package/src/panels/builtin/operations.ts +6 -8
- package/src/panels/builtin/session.ts +17 -0
- package/src/panels/builtin/shared.ts +5 -5
- package/src/panels/builtin-modals.ts +3 -3
- package/src/panels/confirm-state.ts +1 -1
- package/src/panels/cost-tracker-panel.ts +4 -4
- package/src/panels/diff-panel.ts +2 -2
- package/src/panels/diff-review-panel.ts +2 -2
- package/src/panels/expandable-list-panel.ts +2 -2
- package/src/panels/fleet-acts.ts +1 -1
- package/src/panels/fleet-observed-render.ts +1 -1
- package/src/panels/fleet-panel-format.ts +1 -1
- package/src/panels/fleet-panel.ts +1 -1
- package/src/panels/fleet-spawn.ts +1 -1
- package/src/panels/fleet-steer.ts +1 -1
- package/src/panels/fleet-transcript.ts +1 -1
- package/src/panels/git-panel.ts +1 -1
- package/src/panels/hosted-session-feed.ts +352 -0
- package/src/panels/hosted-session-panel.ts +221 -0
- package/src/panels/local-auth-panel.ts +3 -3
- package/src/panels/modals/devices-modal.ts +1 -1
- package/src/panels/modals/local-auth-modal.ts +1 -1
- package/src/panels/modals/pairing-modal.ts +1 -1
- package/src/panels/modals/services-modal.ts +1 -1
- package/src/panels/modals/settings-sync-modal.ts +1 -1
- package/src/panels/modals/subscription-modal.ts +1 -1
- package/src/panels/modals/work-plan-modal.ts +1 -1
- package/src/panels/notifications-panel.ts +1 -1
- package/src/panels/panel-confirm-overlay.ts +1 -1
- package/src/panels/plugins-panel.ts +2 -2
- package/src/panels/polish-core.ts +2 -2
- package/src/panels/polish-tables.ts +1 -1
- package/src/panels/polish.ts +2 -2
- package/src/panels/scrollable-list-panel.ts +3 -3
- package/src/panels/skills-panel.ts +3 -3
- package/src/panels/token-budget-panel.ts +5 -5
- package/src/panels/types.ts +1 -2
- package/src/permissions/prompt.ts +1 -1
- package/src/renderer/autocomplete-overlay.ts +1 -1
- package/src/renderer/block-actions-overlay.ts +1 -1
- package/src/renderer/bookmark-modal.ts +1 -1
- package/src/renderer/buffer.ts +1 -1
- package/src/renderer/code-block.ts +1 -1
- package/src/renderer/composer-fragments.ts +1 -1
- package/src/renderer/compositor.ts +2 -2
- package/src/renderer/config-modal.ts +1 -1
- package/src/renderer/context-inspector.ts +1 -1
- package/src/renderer/conversation-layout.ts +2 -2
- package/src/renderer/conversation-overlays.ts +1 -1
- package/src/renderer/conversation-surface.ts +2 -2
- package/src/renderer/diff-view.ts +1 -1
- package/src/renderer/diff.ts +1 -1
- package/src/renderer/file-picker-overlay.ts +1 -1
- package/src/renderer/fleet-tab-strip.ts +1 -1
- package/src/renderer/fullscreen-primitives.ts +2 -2
- package/src/renderer/fullscreen-workspace.ts +1 -1
- package/src/renderer/header-line.ts +1 -1
- package/src/renderer/help-overlay.ts +1 -1
- package/src/renderer/history-search-overlay.ts +2 -2
- package/src/renderer/layout.ts +5 -8
- package/src/renderer/markdown-inline.ts +1 -1
- package/src/renderer/markdown-table.ts +1 -1
- package/src/renderer/markdown.ts +1 -1
- package/src/renderer/mcp-workspace.ts +1 -1
- package/src/renderer/modal-factory.ts +2 -2
- package/src/renderer/model-workspace.ts +2 -2
- package/src/renderer/onboarding/onboarding-wizard.ts +1 -1
- package/src/renderer/overlay-box.ts +1 -1
- package/src/renderer/panel-composite.ts +1 -1
- package/src/renderer/panel-workspace-bar.ts +1 -1
- package/src/renderer/process-indicator.ts +1 -1
- package/src/renderer/profile-picker-modal.ts +1 -1
- package/src/renderer/search-overlay.ts +2 -2
- package/src/renderer/selection-modal-overlay.ts +1 -1
- package/src/renderer/session-picker-modal.ts +124 -3
- package/src/renderer/settings-modal-helpers.ts +2 -0
- package/src/renderer/settings-modal.ts +2 -2
- package/src/renderer/shell-surface.ts +2 -2
- package/src/renderer/system-message.ts +1 -1
- package/src/renderer/tab-strip.ts +1 -1
- package/src/renderer/theme-mode-config.ts +21 -33
- package/src/renderer/theme.ts +11 -12
- package/src/renderer/thinking.ts +1 -1
- package/src/renderer/tool-call.ts +2 -2
- package/src/renderer/tool-result-expanded-lines.ts +1 -1
- package/src/renderer/turn-injection.ts +7 -8
- package/src/renderer/ui-factory.ts +3 -3
- package/src/runtime/bootstrap-command-context.ts +4 -4
- package/src/runtime/bootstrap-command-parts.ts +5 -5
- package/src/runtime/bootstrap-core.ts +30 -30
- package/src/runtime/bootstrap-shell.ts +4 -4
- package/src/runtime/bootstrap.ts +128 -157
- package/src/runtime/client/approval-updates.ts +82 -0
- package/src/runtime/client/build-floors.ts +167 -0
- package/src/runtime/client/daemon-attach-handshake.ts +115 -0
- package/src/runtime/client/fleet-union.ts +147 -0
- package/src/runtime/client/host-service-status.ts +71 -0
- package/src/runtime/client/hosted-exit.ts +86 -0
- package/src/runtime/client/hosted-roster.ts +110 -0
- package/src/runtime/client/hosted-session-stream.ts +178 -0
- package/src/runtime/client/hosted-sessions.ts +187 -0
- package/src/runtime/client/operator-endpoint.ts +213 -0
- package/src/runtime/client/spine-adoption.ts +99 -0
- package/src/runtime/cloudflare-control-plane.ts +1 -1
- package/src/runtime/context-accounting-source.ts +1 -1
- package/src/runtime/context.ts +2 -2
- package/src/runtime/conversation-rewind-port.ts +42 -14
- package/src/runtime/daemon-attach-notices.ts +55 -19
- package/src/runtime/diagnostics/panels/ops.ts +1 -1
- package/src/runtime/disposal-wiring.ts +4 -24
- package/src/runtime/index.ts +119 -105
- package/src/runtime/install-self-check-startup.ts +2 -2
- package/src/runtime/interaction-seams.ts +1 -1
- package/src/runtime/knowledge-services.ts +8 -2
- package/src/runtime/legacy-daemon-migration.ts +4 -3
- package/src/runtime/legacy-daemon-reconcile.ts +3 -2
- package/src/runtime/memory-spine-transport.ts +37 -267
- package/src/runtime/notification-dispatch.ts +2 -2
- package/src/runtime/onboarding/apply.ts +2 -2
- package/src/runtime/onboarding/derivation.ts +2 -2
- package/src/runtime/onboarding/markers.ts +2 -2
- package/src/runtime/onboarding/progress.ts +2 -2
- package/src/runtime/onboarding/snapshot.ts +1 -1
- package/src/runtime/onboarding/state.ts +2 -2
- package/src/runtime/onboarding/types.ts +2 -2
- package/src/runtime/orchestrator-core-services.ts +1 -1
- package/src/runtime/path-shadow-startup.ts +28 -221
- package/src/runtime/power-keepawake-remote.ts +3 -2
- package/src/runtime/process-lifecycle.ts +2 -2
- package/src/runtime/provider-fallback.ts +10 -66
- package/src/runtime/recovery-autosave.ts +1 -1
- package/src/runtime/recovery-offer-wiring.ts +39 -23
- package/src/runtime/recovery-prompt.ts +31 -17
- package/src/runtime/relay-reachability-bridge.ts +53 -42
- package/src/runtime/release-artifacts.ts +2 -1
- package/src/runtime/runtime-services-types.ts +82 -35
- package/src/runtime/services.ts +305 -300
- package/src/runtime/session-resume-liveness-confirm.ts +1 -1
- package/src/runtime/ui-services.ts +7 -6
- package/src/runtime/update-check.ts +23 -43
- package/src/runtime/workspace-checkpointing.ts +1 -1
- package/src/runtime/wrfc-persistence.ts +2 -2
- package/src/shell/ui-openers.ts +30 -7
- package/src/utils/clipboard.ts +1 -1
- package/src/verification/verification-ledger.ts +10 -8
- package/src/version.ts +1 -1
- package/bin/goodvibes-daemon +0 -90
- package/src/cli/config-overrides.ts +0 -267
- package/src/cli/endpoints.ts +0 -109
- package/src/cli/parser.ts +0 -395
- package/src/cli/redaction.ts +0 -170
- package/src/cli/types.ts +0 -84
- package/src/cluster/commands.ts +0 -382
- package/src/cluster/remote-daemon-target.ts +0 -225
- package/src/cluster/render.ts +0 -268
- package/src/config/atomic-write.ts +0 -70
- package/src/config/credential-availability.ts +0 -122
- package/src/config/goodvibes-home.ts +0 -149
- package/src/config/index.ts +0 -88
- package/src/config/provider-model.ts +0 -23
- package/src/config/read-versioned.ts +0 -228
- package/src/core/alert-gating.ts +0 -67
- package/src/core/consolidation-receipt.ts +0 -41
- package/src/core/focus-tracker.ts +0 -41
- package/src/core/history.ts +0 -45
- package/src/core/memory-status.ts +0 -118
- package/src/core/orchestrator.ts +0 -7
- package/src/core/pairing-devices.ts +0 -49
- package/src/core/pairing-handoff.ts +0 -101
- package/src/core/pairing-offers.ts +0 -83
- package/src/core/pairing-origin.ts +0 -78
- package/src/core/rewind-turn-anchors.ts +0 -311
- package/src/core/session-recovery.ts +0 -210
- package/src/core/stable-host.ts +0 -171
- package/src/core/transcript-journal.ts +0 -503
- package/src/daemon/cli.ts +0 -693
- package/src/daemon/fatal-boot-report.ts +0 -111
- package/src/daemon/handlers/context.ts +0 -29
- package/src/daemon/handlers/contracts.ts +0 -77
- package/src/daemon/handlers/credentials.ts +0 -139
- package/src/daemon/handlers/drafts/draft-store.ts +0 -427
- package/src/daemon/handlers/drafts/index.ts +0 -17
- package/src/daemon/handlers/drafts/register.ts +0 -331
- package/src/daemon/handlers/errors.ts +0 -18
- package/src/daemon/handlers/inbox/cursor-store.ts +0 -457
- package/src/daemon/handlers/inbox/index.ts +0 -284
- package/src/daemon/handlers/inbox/mapping.ts +0 -192
- package/src/daemon/handlers/inbox/poller.ts +0 -212
- package/src/daemon/handlers/inbox/provider-adapter.ts +0 -156
- package/src/daemon/handlers/inbox/providers/discord.ts +0 -252
- package/src/daemon/handlers/inbox/providers/email.ts +0 -152
- package/src/daemon/handlers/inbox/providers/imap-client.ts +0 -300
- package/src/daemon/handlers/inbox/providers/route-util.ts +0 -24
- package/src/daemon/handlers/inbox/providers/slack.ts +0 -263
- package/src/daemon/handlers/index.ts +0 -117
- package/src/daemon/handlers/register.ts +0 -168
- package/src/daemon/handlers/remote/backends/cloud-terminal.ts +0 -142
- package/src/daemon/handlers/remote/backends/docker.ts +0 -79
- package/src/daemon/handlers/remote/backends/index.ts +0 -40
- package/src/daemon/handlers/remote/backends/local-process.ts +0 -113
- package/src/daemon/handlers/remote/backends/process-runner.ts +0 -127
- package/src/daemon/handlers/remote/backends/ssh.ts +0 -125
- package/src/daemon/handlers/remote/backends/types.ts +0 -97
- package/src/daemon/handlers/remote/dispatcher.ts +0 -181
- package/src/daemon/handlers/remote/index.ts +0 -119
- package/src/daemon/handlers/remote/peer-registry.ts +0 -357
- package/src/daemon/handlers/remote/service.ts +0 -191
- package/src/daemon/handlers/routing/inbox-bridge.ts +0 -71
- package/src/daemon/handlers/routing/index.ts +0 -261
- package/src/daemon/handlers/routing/route-store.ts +0 -319
- package/src/daemon/handlers/routing/routing-resolver.ts +0 -75
- package/src/daemon/handlers/sqlite-store.ts +0 -278
- package/src/daemon/handlers/triage/index.ts +0 -57
- package/src/daemon/handlers/triage/integration.ts +0 -213
- package/src/daemon/handlers/triage/pipeline.ts +0 -274
- package/src/daemon/handlers/triage/scorer.ts +0 -287
- package/src/daemon/handlers/triage/tagger/discord.ts +0 -187
- package/src/daemon/handlers/triage/tagger/imap.ts +0 -384
- package/src/daemon/handlers/triage/tagger/index.ts +0 -184
- package/src/daemon/handlers/triage/tagger/shared.ts +0 -70
- package/src/daemon/handlers/triage/tagger/slack.ts +0 -69
- package/src/daemon/handlers/triage/types.ts +0 -50
- package/src/daemon/lifecycle.ts +0 -41
- package/src/daemon/provision-wake-model.ts +0 -81
- package/src/daemon/safe-serve.ts +0 -61
- package/src/daemon/send/channels.ts +0 -200
- package/src/daemon/send/command.ts +0 -332
- package/src/daemon/send/composition.ts +0 -99
- package/src/daemon/send/failure-text.ts +0 -93
- package/src/daemon/send/inert-text.ts +0 -225
- package/src/daemon/send/stdin.ts +0 -24
- package/src/daemon/service-commands.ts +0 -329
- package/src/export/cost-utils.ts +0 -319
- package/src/input/selection.ts +0 -135
- package/src/plugins/loader.ts +0 -15
- package/src/renderer/bottom-bar.ts +0 -58
- package/src/renderer/conversation-tree.ts +0 -228
- package/src/runtime/agent-graph-composition.ts +0 -78
- package/src/runtime/channel-composition.ts +0 -46
- package/src/runtime/cluster-composition.ts +0 -124
- package/src/runtime/cluster-group-composition.ts +0 -284
- package/src/runtime/code-index-services.ts +0 -167
- package/src/runtime/daemon-handler-composition.ts +0 -76
- package/src/runtime/device-posture-composition.ts +0 -110
- package/src/runtime/durability-housekeeping.ts +0 -183
- package/src/runtime/durability-services.ts +0 -155
- package/src/runtime/embedded-service-factories.ts +0 -74
- package/src/runtime/feature-settings.ts +0 -154
- package/src/runtime/fleet-needs-input-push.ts +0 -70
- package/src/runtime/fleet-services.ts +0 -41
- package/src/runtime/idle-power-services.ts +0 -85
- package/src/runtime/mail-composition.ts +0 -65
- package/src/runtime/memory-fold.ts +0 -55
- package/src/runtime/operator-token-cleanup.ts +0 -109
- package/src/runtime/path-shadow.ts +0 -418
- package/src/runtime/perf/panel-health-monitor.ts +0 -18
- package/src/runtime/provider-optimizer-wiring.ts +0 -55
- package/src/runtime/reachability-notice.ts +0 -100
- package/src/runtime/remote-execution-composition.ts +0 -62
- package/src/runtime/session-liveness-marker.ts +0 -257
- package/src/runtime/session-pointer-surface.ts +0 -22
- package/src/runtime/session-storage-services.ts +0 -41
- package/src/runtime/surface-feature-flags.ts +0 -96
- package/src/runtime/terminal-output-guard.ts +0 -235
- package/src/runtime/trust/workspace-registration.ts +0 -192
- package/src/runtime/trust/workspace-trust.ts +0 -229
- package/src/runtime/ui/index.ts +0 -39
- package/src/runtime/ui/model-picker/data-provider.ts +0 -182
- package/src/runtime/ui/model-picker/health-enrichment.ts +0 -231
- package/src/runtime/ui/model-picker/index.ts +0 -59
- package/src/runtime/ui/model-picker/types.ts +0 -153
- package/src/runtime/ui/provider-health/data-provider.ts +0 -244
- package/src/runtime/ui/provider-health/fallback-visualizer.ts +0 -71
- package/src/runtime/ui/provider-health/index.ts +0 -46
- package/src/runtime/ui/provider-health/types.ts +0 -146
- package/src/runtime/ui-events.ts +0 -1
- package/src/runtime/ui-read-model-helpers.ts +0 -1
- package/src/runtime/ui-read-models-observability-maintenance.ts +0 -1
- package/src/runtime/ui-read-models-observability-options.ts +0 -1
- package/src/runtime/ui-read-models-observability-remote.ts +0 -1
- package/src/runtime/ui-read-models-observability-security.ts +0 -1
- package/src/runtime/ui-read-models-observability-system.ts +0 -1
- package/src/runtime/ui-read-models-observability.ts +0 -1
- package/src/runtime/ui-service-queries.ts +0 -1
- package/src/runtime/voice-setup-services.ts +0 -98
- package/src/runtime/workstream-attempts-validation.ts +0 -77
- package/src/runtime/workstream-draft-edits.ts +0 -95
- package/src/runtime/workstream-draft-store.ts +0 -274
- package/src/runtime/workstream-draft-types.ts +0 -42
- package/src/runtime/workstream-services.ts +0 -373
- package/src/tools/index.ts +0 -1
- package/src/types/grid.ts +0 -48
- package/src/types/sql-js.d.ts +0 -15
- package/src/work-plans/work-plan-store.ts +0 -702
|
@@ -1,184 +0,0 @@
|
|
|
1
|
-
// ---------------------------------------------------------------------------
|
|
2
|
-
// Daemon-internal triage TAGGER (composition).
|
|
3
|
-
//
|
|
4
|
-
// Applies user-defined triage labels back on the provider side:
|
|
5
|
-
// - IMAP : STORE a keyword flag on the message (IMAP4rev1 over TLS).
|
|
6
|
-
// - Slack: reactions.add emoji on the source message.
|
|
7
|
-
// - Discord: real forum thread tags (PATCH applied_tags, merge) when a
|
|
8
|
-
// forum-tag mapping is configured, else a unicode reaction analog.
|
|
9
|
-
//
|
|
10
|
-
// Hard rules honored here:
|
|
11
|
-
// - All provider credentials come ONLY from the daemon credential store.
|
|
12
|
-
// They are never returned in results and never logged.
|
|
13
|
-
// - The whole tagger is gated behind a config flag (surfaces.triage.autoTag);
|
|
14
|
-
// when disabled, applyTags() is a no-op that reports skipped:true.
|
|
15
|
-
// - Provider-side writes are EFFECTFUL; callers must pass an explicitly
|
|
16
|
-
// confirmed request (confirm === true && explicitUserRequest === true).
|
|
17
|
-
// Unconfirmed calls throw HandlerError(REQUIRE_CONFIRM).
|
|
18
|
-
//
|
|
19
|
-
// Contract-fidelity note: the triage surface (`inbox.triage.*`) is daemon-
|
|
20
|
-
// internal and NOT a published operator method, so there is no external
|
|
21
|
-
// request/response schema to certify these tag shapes against. What is
|
|
22
|
-
// guaranteed is the provider-side behavior: no silent data loss (Discord thread
|
|
23
|
-
// tags are merged, never blindly overwritten) and no command injection (IMAP
|
|
24
|
-
// quoting rejects control characters).
|
|
25
|
-
// ---------------------------------------------------------------------------
|
|
26
|
-
|
|
27
|
-
import type { HandlerContext } from '../../context.ts';
|
|
28
|
-
import type { DaemonCredentialStore } from '../../credentials.ts';
|
|
29
|
-
import { HandlerError, REQUIRE_CONFIRM } from '../../errors.ts';
|
|
30
|
-
import { labelToTag } from '../scorer.ts';
|
|
31
|
-
import { applyImap, imapStoreFlagOverTls, makeRetryingImapStoreFlag } from './imap.ts';
|
|
32
|
-
import type { ImapRetryOptions, ImapStoreFlag } from './imap.ts';
|
|
33
|
-
import { applySlack } from './slack.ts';
|
|
34
|
-
import { applyDiscord } from './discord.ts';
|
|
35
|
-
import type { ApplyTagsRequest, ApplyTagsResult, TaggerProviderConfig } from './shared.ts';
|
|
36
|
-
|
|
37
|
-
export type {
|
|
38
|
-
ApplyTagsRequest,
|
|
39
|
-
ApplyTagsResult,
|
|
40
|
-
TaggerProviderConfig,
|
|
41
|
-
} from './shared.ts';
|
|
42
|
-
export type { ImapRetryOptions, ImapStoreArgs, ImapStoreFlag } from './imap.ts';
|
|
43
|
-
|
|
44
|
-
export const TRIAGE_AUTOTAG_FLAG = 'surfaces.triage.autoTag';
|
|
45
|
-
|
|
46
|
-
export interface TriageTaggerOptions {
|
|
47
|
-
credentials?: DaemonCredentialStore;
|
|
48
|
-
/** Override the autotag flag lookup (used in tests). */
|
|
49
|
-
autoTagEnabled?: boolean;
|
|
50
|
-
/** Per-surface provider config; usually derived from configManager. */
|
|
51
|
-
providers?: TaggerProviderConfig;
|
|
52
|
-
/** Injectable fetch (Slack/Discord HTTP). Defaults to global fetch. */
|
|
53
|
-
fetchImpl?: typeof fetch;
|
|
54
|
-
/** Injectable IMAP flag-setter (used in tests to avoid a live socket). */
|
|
55
|
-
imapStoreFlag?: ImapStoreFlag;
|
|
56
|
-
/**
|
|
57
|
-
* Transient-failure retry policy for the default IMAP store implementation.
|
|
58
|
-
* Ignored when imapStoreFlag is injected and succeeds first-try.
|
|
59
|
-
*/
|
|
60
|
-
imapRetry?: ImapRetryOptions;
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
export interface TriageTagger {
|
|
64
|
-
/** Whether provider-side tagging is currently enabled. */
|
|
65
|
-
enabled(): boolean;
|
|
66
|
-
applyTags(request: ApplyTagsRequest): Promise<ApplyTagsResult>;
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
function readBoolFlag(
|
|
70
|
-
configManager: HandlerContext['configManager'],
|
|
71
|
-
key: string,
|
|
72
|
-
): boolean {
|
|
73
|
-
try {
|
|
74
|
-
const value = configManager.get(key as never) as unknown;
|
|
75
|
-
return value === true || value === 'true' || value === 1;
|
|
76
|
-
} catch {
|
|
77
|
-
return false;
|
|
78
|
-
}
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
function safeGet(configManager: HandlerContext['configManager'], key: string): unknown {
|
|
82
|
-
try {
|
|
83
|
-
return configManager.get(key as never) as unknown;
|
|
84
|
-
} catch {
|
|
85
|
-
return undefined;
|
|
86
|
-
}
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
function resolveProvidersFromConfig(
|
|
90
|
-
configManager: HandlerContext['configManager'],
|
|
91
|
-
): TaggerProviderConfig {
|
|
92
|
-
const out: TaggerProviderConfig = {};
|
|
93
|
-
const slackToken = safeGet(configManager, 'surfaces.slack.botToken');
|
|
94
|
-
if (typeof slackToken === 'string' && slackToken.length > 0) {
|
|
95
|
-
out.slack = { tokenConfigKey: 'surfaces.slack.botToken' };
|
|
96
|
-
}
|
|
97
|
-
const discordToken = safeGet(configManager, 'surfaces.discord.botToken');
|
|
98
|
-
if (typeof discordToken === 'string' && discordToken.length > 0) {
|
|
99
|
-
out.discord = { tokenConfigKey: 'surfaces.discord.botToken' };
|
|
100
|
-
}
|
|
101
|
-
const imapHost = safeGet(configManager, 'surfaces.email.imap.host');
|
|
102
|
-
const imapUser = safeGet(configManager, 'surfaces.email.imap.user');
|
|
103
|
-
if (typeof imapHost === 'string' && imapHost.length > 0 && typeof imapUser === 'string') {
|
|
104
|
-
const portRaw = safeGet(configManager, 'surfaces.email.imap.port');
|
|
105
|
-
const mailbox = safeGet(configManager, 'surfaces.email.imap.mailbox');
|
|
106
|
-
out.imap = {
|
|
107
|
-
host: imapHost,
|
|
108
|
-
port: typeof portRaw === 'number' ? portRaw : 993,
|
|
109
|
-
user: imapUser,
|
|
110
|
-
passwordConfigKey: 'surfaces.email.imap.password',
|
|
111
|
-
mailbox: typeof mailbox === 'string' && mailbox.length > 0 ? mailbox : 'INBOX',
|
|
112
|
-
};
|
|
113
|
-
}
|
|
114
|
-
return out;
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
function resolveTags(request: ApplyTagsRequest): string[] {
|
|
118
|
-
if (request.tags && request.tags.length > 0) {
|
|
119
|
-
return [...new Set(request.tags.map((t) => t.trim()).filter((t) => t.length > 0))];
|
|
120
|
-
}
|
|
121
|
-
if (request.label) return [labelToTag(request.label)];
|
|
122
|
-
return [];
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
/**
|
|
126
|
-
* Create the triage tagger. Reads the autotag flag and provider config from the
|
|
127
|
-
* handler context; credentials are resolved lazily, per apply, from the daemon
|
|
128
|
-
* credential store.
|
|
129
|
-
*/
|
|
130
|
-
export function createTriageTagger(
|
|
131
|
-
ctx: HandlerContext,
|
|
132
|
-
options: TriageTaggerOptions = {},
|
|
133
|
-
): TriageTagger {
|
|
134
|
-
const credentials = options.credentials ?? ctx.credentials;
|
|
135
|
-
const fetchImpl = options.fetchImpl ?? fetch;
|
|
136
|
-
const providers = options.providers ?? resolveProvidersFromConfig(ctx.configManager);
|
|
137
|
-
// Retry wraps whichever store impl is in use (default TLS client OR an
|
|
138
|
-
// injected one), so transient failures are retried uniformly.
|
|
139
|
-
const imapStoreFlag = makeRetryingImapStoreFlag(
|
|
140
|
-
options.imapStoreFlag ?? imapStoreFlagOverTls,
|
|
141
|
-
options.imapRetry,
|
|
142
|
-
);
|
|
143
|
-
const enabled = (): boolean =>
|
|
144
|
-
options.autoTagEnabled ?? readBoolFlag(ctx.configManager, TRIAGE_AUTOTAG_FLAG);
|
|
145
|
-
|
|
146
|
-
return {
|
|
147
|
-
enabled,
|
|
148
|
-
async applyTags(request: ApplyTagsRequest): Promise<ApplyTagsResult> {
|
|
149
|
-
const { item } = request;
|
|
150
|
-
const tags = resolveTags(request);
|
|
151
|
-
const base: ApplyTagsResult = {
|
|
152
|
-
surface: item.surface,
|
|
153
|
-
itemId: item.id,
|
|
154
|
-
appliedTags: [],
|
|
155
|
-
skipped: true,
|
|
156
|
-
};
|
|
157
|
-
|
|
158
|
-
if (!enabled()) {
|
|
159
|
-
return { ...base, reason: 'autotag-disabled' };
|
|
160
|
-
}
|
|
161
|
-
|
|
162
|
-
// Provider-side mutation is effectful — require explicit confirmation.
|
|
163
|
-
if (request.confirm !== true || request.explicitUserRequest !== true) {
|
|
164
|
-
throw new HandlerError(
|
|
165
|
-
'Provider-side triage tagging requires explicit user confirmation.',
|
|
166
|
-
REQUIRE_CONFIRM,
|
|
167
|
-
403,
|
|
168
|
-
);
|
|
169
|
-
}
|
|
170
|
-
|
|
171
|
-
switch (item.surface) {
|
|
172
|
-
case 'email':
|
|
173
|
-
case 'imap':
|
|
174
|
-
return applyImap(item, tags, providers, credentials, imapStoreFlag, base);
|
|
175
|
-
case 'slack':
|
|
176
|
-
return applySlack(item, tags, providers, credentials, fetchImpl, ctx, base);
|
|
177
|
-
case 'discord':
|
|
178
|
-
return applyDiscord(item, tags, providers, credentials, fetchImpl, ctx, base);
|
|
179
|
-
default:
|
|
180
|
-
return { ...base, reason: `unsupported-surface:${item.surface}` };
|
|
181
|
-
}
|
|
182
|
-
},
|
|
183
|
-
};
|
|
184
|
-
}
|
|
@@ -1,70 +0,0 @@
|
|
|
1
|
-
// ---------------------------------------------------------------------------
|
|
2
|
-
// Triage tagger — shared types and provider-agnostic helpers.
|
|
3
|
-
//
|
|
4
|
-
// Provider config shapes, the apply request/result contract, and the tag
|
|
5
|
-
// normalization helpers used by the IMAP/Slack/Discord modules. No I/O here.
|
|
6
|
-
// ---------------------------------------------------------------------------
|
|
7
|
-
|
|
8
|
-
import type { InboundChannelItem, TriageLabel } from '../types.ts';
|
|
9
|
-
|
|
10
|
-
export interface TaggerProviderConfig {
|
|
11
|
-
/** IMAP host:port (default port 993, TLS). Credentials resolved separately. */
|
|
12
|
-
imap?: { host: string; port?: number; user: string; passwordConfigKey: string; mailbox?: string };
|
|
13
|
-
/** Slack bot token config key (resolved from credential store). */
|
|
14
|
-
slack?: { tokenConfigKey: string };
|
|
15
|
-
/**
|
|
16
|
-
* Discord bot token config key (resolved from credential store), plus an
|
|
17
|
-
* optional forum-tag mapping. When `forumTagIds` maps a GoodVibes triage tag
|
|
18
|
-
* (e.g. 'GoodVibes/Spam') to a forum tag SNOWFLAKE id, items that target a
|
|
19
|
-
* forum/media-channel thread get that REAL thread tag applied (PATCH
|
|
20
|
-
* applied_tags) — exact fidelity to the contract's "Discord thread tags".
|
|
21
|
-
* Without a mapping (or for non-thread messages) tagging degrades to a
|
|
22
|
-
* unicode reaction analog.
|
|
23
|
-
*/
|
|
24
|
-
discord?: { tokenConfigKey: string; forumTagIds?: Record<string, string> };
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
export interface ApplyTagsRequest {
|
|
28
|
-
item: InboundChannelItem;
|
|
29
|
-
/** Provider-side tags to apply. Defaults to [labelToTag(label)] when omitted. */
|
|
30
|
-
tags?: readonly string[];
|
|
31
|
-
label?: TriageLabel;
|
|
32
|
-
/** Must be true — provider-side mutation requires explicit confirmation. */
|
|
33
|
-
confirm?: boolean;
|
|
34
|
-
/** Mirror of the operator invocation context flag. */
|
|
35
|
-
explicitUserRequest?: boolean;
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
export interface ApplyTagsResult {
|
|
39
|
-
surface: string;
|
|
40
|
-
itemId: string;
|
|
41
|
-
appliedTags: string[];
|
|
42
|
-
/** True when the autotag flag is disabled or no provider matched. */
|
|
43
|
-
skipped: boolean;
|
|
44
|
-
reason?: string;
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
/** IMAP keywords cannot contain spaces or '/'; normalize the canonical tag. */
|
|
48
|
-
export function imapKeywordForTag(tag: string): string {
|
|
49
|
-
return tag.replace(/[^A-Za-z0-9_]+/g, '_');
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
export function slackEmojiForTag(tag: string): string {
|
|
53
|
-
const lower = tag.toLowerCase();
|
|
54
|
-
if (lower.includes('spam')) return 'no_entry_sign';
|
|
55
|
-
if (lower.includes('priority')) return 'rotating_light';
|
|
56
|
-
return 'inbox_tray';
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
export function discordEmojiForTag(tag: string): string {
|
|
60
|
-
const lower = tag.toLowerCase();
|
|
61
|
-
if (lower.includes('spam')) return '\u{1F6AB}';
|
|
62
|
-
if (lower.includes('priority')) return '\u{1F6A8}';
|
|
63
|
-
return '\u{1F4E5}';
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
/** Read a non-empty string from the item's opaque metadata bag. */
|
|
67
|
-
export function stringMeta(item: InboundChannelItem, key: string): string | undefined {
|
|
68
|
-
const value = item.metadata?.[key];
|
|
69
|
-
return typeof value === 'string' && value.length > 0 ? value : undefined;
|
|
70
|
-
}
|
|
@@ -1,69 +0,0 @@
|
|
|
1
|
-
// ---------------------------------------------------------------------------
|
|
2
|
-
// Triage tagger — Slack provider.
|
|
3
|
-
//
|
|
4
|
-
// Applies a triage label as a Slack message reaction (reactions.add). The bot
|
|
5
|
-
// token is resolved per-apply from the daemon credential store and is never
|
|
6
|
-
// logged or returned. `already_reacted` is treated as idempotent success.
|
|
7
|
-
// ---------------------------------------------------------------------------
|
|
8
|
-
|
|
9
|
-
import type { HandlerContext } from '../../context.ts';
|
|
10
|
-
import type { DaemonCredentialStore } from '../../credentials.ts';
|
|
11
|
-
import { HandlerError } from '../../errors.ts';
|
|
12
|
-
import type { InboundChannelItem } from '../types.ts';
|
|
13
|
-
import type { ApplyTagsResult, TaggerProviderConfig } from './shared.ts';
|
|
14
|
-
import { slackEmojiForTag, stringMeta } from './shared.ts';
|
|
15
|
-
|
|
16
|
-
export async function applySlack(
|
|
17
|
-
item: InboundChannelItem,
|
|
18
|
-
tags: string[],
|
|
19
|
-
providers: TaggerProviderConfig,
|
|
20
|
-
credentials: DaemonCredentialStore,
|
|
21
|
-
fetchImpl: typeof fetch,
|
|
22
|
-
ctx: HandlerContext,
|
|
23
|
-
base: ApplyTagsResult,
|
|
24
|
-
): Promise<ApplyTagsResult> {
|
|
25
|
-
const cfg = providers.slack;
|
|
26
|
-
if (!cfg) return { ...base, reason: 'slack-not-configured' };
|
|
27
|
-
const channel = stringMeta(item, 'channelId') ?? item.conversationId;
|
|
28
|
-
const ts = stringMeta(item, 'ts') ?? stringMeta(item, 'messageTs');
|
|
29
|
-
if (!channel || !ts) return { ...base, reason: 'slack-missing-target' };
|
|
30
|
-
if (tags.length === 0) return { ...base, reason: 'no-tags' };
|
|
31
|
-
|
|
32
|
-
const token = await credentials.resolveConfigSecret(cfg.tokenConfigKey);
|
|
33
|
-
if (!token) return { ...base, reason: 'slack-no-credentials' };
|
|
34
|
-
|
|
35
|
-
const applied: string[] = [];
|
|
36
|
-
for (const tag of tags) {
|
|
37
|
-
const emoji = slackEmojiForTag(tag);
|
|
38
|
-
const response = await fetchImpl('https://slack.com/api/reactions.add', {
|
|
39
|
-
method: 'POST',
|
|
40
|
-
headers: {
|
|
41
|
-
Authorization: `Bearer ${token}`,
|
|
42
|
-
'Content-Type': 'application/json; charset=utf-8',
|
|
43
|
-
},
|
|
44
|
-
body: JSON.stringify({ channel, timestamp: ts, name: emoji }),
|
|
45
|
-
});
|
|
46
|
-
const payload = (await response.json().catch(() => ({}))) as {
|
|
47
|
-
ok?: boolean;
|
|
48
|
-
error?: string;
|
|
49
|
-
};
|
|
50
|
-
if (!response.ok) {
|
|
51
|
-
throw new HandlerError(
|
|
52
|
-
`Slack reactions.add HTTP ${response.status}`,
|
|
53
|
-
'TRIAGE_SLACK_TAG_FAILED',
|
|
54
|
-
502,
|
|
55
|
-
);
|
|
56
|
-
}
|
|
57
|
-
// 'already_reacted' is an idempotent success for our purposes.
|
|
58
|
-
if (payload.ok !== true && payload.error !== 'already_reacted') {
|
|
59
|
-
ctx.logger.warn('triage: slack reaction rejected', { error: payload.error });
|
|
60
|
-
throw new HandlerError(
|
|
61
|
-
`Slack reactions.add rejected: ${payload.error ?? 'unknown'}`,
|
|
62
|
-
'TRIAGE_SLACK_TAG_FAILED',
|
|
63
|
-
502,
|
|
64
|
-
);
|
|
65
|
-
}
|
|
66
|
-
applied.push(tag);
|
|
67
|
-
}
|
|
68
|
-
return { surface: item.surface, itemId: item.id, appliedTags: applied, skipped: false };
|
|
69
|
-
}
|
|
@@ -1,50 +0,0 @@
|
|
|
1
|
-
// ---------------------------------------------------------------------------
|
|
2
|
-
// Daemon-internal triage domain types.
|
|
3
|
-
//
|
|
4
|
-
// `InboundChannelItem` is the daemon-internal shape the inbox poller produces
|
|
5
|
-
// and the triage pipeline scores. It is NOT an SDK catalog contract: the
|
|
6
|
-
// published `channels.inbox.list` output schema (CHANNEL_INBOX_ITEM_SCHEMA) is
|
|
7
|
-
// owned by the SDK and never re-declared here. This is the internal poller
|
|
8
|
-
// item per the handoff doc — it carries `fromDigest` (never a raw sender id),
|
|
9
|
-
// `subjectPreview`/`bodyPreview` (PII-stripped, length-bounded) and an opaque
|
|
10
|
-
// `metadata` bag the tagger reads provider targeting from (imapUid, channelId,
|
|
11
|
-
// Slack ts, Discord messageId/threadId).
|
|
12
|
-
// ---------------------------------------------------------------------------
|
|
13
|
-
|
|
14
|
-
/** Triage label assigned by the scorer. */
|
|
15
|
-
export type TriageLabel = 'spam' | 'priority' | 'normal';
|
|
16
|
-
|
|
17
|
-
/** 1:1 vs group/channel/thread conversation hint (priority signal). */
|
|
18
|
-
export type ConversationKind = 'direct' | 'group' | 'channel' | 'thread' | 'service';
|
|
19
|
-
|
|
20
|
-
/**
|
|
21
|
-
* Internal inbound feed item. Mirrors the handoff `InboundChannelItem` shape
|
|
22
|
-
* plus the optional fields the scorer/tagger consult. `surface` is the provider
|
|
23
|
-
* family ('email' | 'imap' | 'slack' | 'discord' | ...) the tagger dispatches
|
|
24
|
-
* on; `provider` is the handoff-facing provider id. They are usually equal.
|
|
25
|
-
*/
|
|
26
|
-
export interface InboundChannelItem {
|
|
27
|
-
/** Stable, provider-scoped dedup key. */
|
|
28
|
-
readonly id: string;
|
|
29
|
-
/** Provider family the tagger dispatches on (email/imap/slack/discord/...). */
|
|
30
|
-
readonly surface: string;
|
|
31
|
-
/** Handoff-facing provider id ("slack" | "discord" | "email" | ...). */
|
|
32
|
-
readonly provider?: string;
|
|
33
|
-
readonly kind?: 'dm' | 'thread' | 'mention' | 'reaction';
|
|
34
|
-
/** SHA-256 first-N of sender external id — NEVER a raw identifier. */
|
|
35
|
-
readonly fromDigest?: string;
|
|
36
|
-
/** Conversation id (Slack/Discord channel, IMAP mailbox-scoped). */
|
|
37
|
-
readonly conversationId?: string;
|
|
38
|
-
readonly conversationKind?: ConversationKind;
|
|
39
|
-
/** Display subject (<= 200 chars). */
|
|
40
|
-
readonly subject?: string;
|
|
41
|
-
/** Display body preview (<= 500 chars, PII-stripped). Alias: bodyPreview. */
|
|
42
|
-
readonly snippet?: string;
|
|
43
|
-
/** Optional daemon route binding id. */
|
|
44
|
-
readonly routeId?: string;
|
|
45
|
-
/** Unix ms. */
|
|
46
|
-
readonly receivedAt?: number;
|
|
47
|
-
readonly unread?: boolean;
|
|
48
|
-
/** Opaque provider targeting bag (imapUid/uid, channelId, ts, messageId, threadId). */
|
|
49
|
-
readonly metadata?: Record<string, unknown>;
|
|
50
|
-
}
|
package/src/daemon/lifecycle.ts
DELETED
|
@@ -1,41 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* lifecycle.ts — resolve THIS binary's update-artifact identity for the SDK
|
|
3
|
-
* DaemonServer facade's auto-update lifecycle.
|
|
4
|
-
*
|
|
5
|
-
* The SDK facade now runs the entire self-update loop itself when handed a
|
|
6
|
-
* DaemonUpdateArtifact ({version, execPath}): it compares the HOST binary's
|
|
7
|
-
* version against the release tags (no longer the version-blind sdk-package
|
|
8
|
-
* comparison that used to restart-loop), swaps only at an idle moment, keeps
|
|
9
|
-
* the outgoing file at `<path>.previous`, and leaves a receipt in the store it
|
|
10
|
-
* serves on /status. When the artifact is ABSENT, updates are host-managed —
|
|
11
|
-
* the facade runs no loop (the safe embedded default).
|
|
12
|
-
*
|
|
13
|
-
* The one guard the facade does NOT apply is install-kind: it must never swap a
|
|
14
|
-
* dev `bun run daemon` interpreter or a bun-global package install. This helper
|
|
15
|
-
* is that guard — it hands the facade an artifact ONLY for a compiled binary
|
|
16
|
-
* install, so a dev run resolves to `undefined` (host-managed, no loop) and
|
|
17
|
-
* only a real self-contained binary self-updates.
|
|
18
|
-
*/
|
|
19
|
-
import type { DaemonUpdateArtifact } from '@pellux/goodvibes-sdk/platform/daemon';
|
|
20
|
-
import { VERSION } from '../version.ts';
|
|
21
|
-
import { detectInstallKind } from '../runtime/update-check.ts';
|
|
22
|
-
|
|
23
|
-
export interface ResolveDaemonUpdateArtifactOptions {
|
|
24
|
-
/** The executable to identify; defaults to process.execPath. */
|
|
25
|
-
readonly execPath?: string;
|
|
26
|
-
/** Injectable so tests pin a fixture version — never the live build VERSION. */
|
|
27
|
-
readonly version?: string;
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
/**
|
|
31
|
-
* The update-artifact identity to hand the DaemonServer facade, or `undefined`
|
|
32
|
-
* for a non-binary install (dev/source or bun-global package) — in which case
|
|
33
|
-
* the facade keeps updates host-managed and runs no swap loop.
|
|
34
|
-
*/
|
|
35
|
-
export function resolveDaemonUpdateArtifact(
|
|
36
|
-
options: ResolveDaemonUpdateArtifactOptions = {},
|
|
37
|
-
): DaemonUpdateArtifact | undefined {
|
|
38
|
-
const execPath = options.execPath ?? process.execPath;
|
|
39
|
-
if (detectInstallKind(execPath) !== 'binary') return undefined;
|
|
40
|
-
return { version: options.version ?? VERSION, execPath };
|
|
41
|
-
}
|
|
@@ -1,81 +0,0 @@
|
|
|
1
|
-
// ---------------------------------------------------------------------------
|
|
2
|
-
// provision-wake-model.ts — `goodvibes-daemon provision-wake-model`.
|
|
3
|
-
//
|
|
4
|
-
// WHAT THIS IS FOR
|
|
5
|
-
//
|
|
6
|
-
// The curl installer needs to put the wake-word model on the machine, and it must
|
|
7
|
-
// not hold the pinned URLs, byte counts or checksums to do it. Those live in ONE
|
|
8
|
-
// place — the SDK's wake-word manifest — and a shell script that copied them
|
|
9
|
-
// would be a second copy of a pin, drifting silently the first time the model is
|
|
10
|
-
// retrained. So the installer runs the binary it just installed and lets the SDK
|
|
11
|
-
// do what the SDK owns.
|
|
12
|
-
//
|
|
13
|
-
// IT EXITS 0 EVEN WHEN THE DOWNLOAD FAILS, ON PURPOSE
|
|
14
|
-
//
|
|
15
|
-
// The caller is an installer. A wake-word model is not a reason to fail installing
|
|
16
|
-
// a coding tool, and an installer that aborts half-way through is worse than one
|
|
17
|
-
// that finishes without a wake word. The outcome is printed either way — one plain
|
|
18
|
-
// line naming what happened and how to retry — and a running daemon retries at
|
|
19
|
-
// every boot. `--strict` is there for a caller that genuinely wants the exit code
|
|
20
|
-
// to carry the result (a test, a provisioning script that is checking); the
|
|
21
|
-
// installer does not pass it.
|
|
22
|
-
//
|
|
23
|
-
// It composes NOTHING. No runtime, no config manager, no gateway: this reads a
|
|
24
|
-
// home directory, derives the managed voice root the same way the running daemon
|
|
25
|
-
// does, and calls one SDK function. Composing a runtime here would start a second
|
|
26
|
-
// set of pollers on a machine whose daemon is probably already running.
|
|
27
|
-
// ---------------------------------------------------------------------------
|
|
28
|
-
|
|
29
|
-
import {
|
|
30
|
-
provisionWakeWordModelsAtInstall,
|
|
31
|
-
resolveManagedVoiceRoot,
|
|
32
|
-
} from '@pellux/goodvibes-sdk/platform/voice';
|
|
33
|
-
|
|
34
|
-
export interface ProvisionWakeModelResult {
|
|
35
|
-
readonly exitCode: number;
|
|
36
|
-
readonly lines: readonly string[];
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
export interface ProvisionWakeModelDeps {
|
|
40
|
-
/** The home directory whose `.goodvibes/voice` tree receives the artifacts. */
|
|
41
|
-
readonly homeDirectory: string;
|
|
42
|
-
readonly env?: Readonly<Record<string, string | undefined>> | undefined;
|
|
43
|
-
/** Injected in tests: the SDK policy, so nothing downloads. */
|
|
44
|
-
readonly provisionAtInstall?: typeof provisionWakeWordModelsAtInstall | undefined;
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
/**
|
|
48
|
-
* Run the install-time provision and report it.
|
|
49
|
-
*
|
|
50
|
-
* `--strict` makes a degraded outcome exit 1. Without it, every outcome exits 0,
|
|
51
|
-
* because the caller is an installer and the alternative is an aborted install
|
|
52
|
-
* over an optional model.
|
|
53
|
-
*/
|
|
54
|
-
export async function runProvisionWakeModelCommand(
|
|
55
|
-
argv: readonly string[],
|
|
56
|
-
deps: ProvisionWakeModelDeps,
|
|
57
|
-
): Promise<ProvisionWakeModelResult> {
|
|
58
|
-
const strict = argv.includes('--strict');
|
|
59
|
-
const provision = deps.provisionAtInstall ?? provisionWakeWordModelsAtInstall;
|
|
60
|
-
let managedRoot: string;
|
|
61
|
-
try {
|
|
62
|
-
managedRoot = resolveManagedVoiceRoot(deps.homeDirectory);
|
|
63
|
-
} catch (error) {
|
|
64
|
-
// A home directory this process cannot make sense of is still not a reason to
|
|
65
|
-
// fail an install, so it is reported on the same terms as a failed download.
|
|
66
|
-
const message = error instanceof Error ? error.message : String(error);
|
|
67
|
-
return {
|
|
68
|
-
exitCode: strict ? 1 : 0,
|
|
69
|
-
lines: [`wake-word model: skipped — ${message}`],
|
|
70
|
-
};
|
|
71
|
-
}
|
|
72
|
-
const outcome = await provision({
|
|
73
|
-
managedRoot,
|
|
74
|
-
recoveryHint: '/voice wake setup',
|
|
75
|
-
...(deps.env !== undefined ? { env: deps.env } : {}),
|
|
76
|
-
});
|
|
77
|
-
return {
|
|
78
|
-
exitCode: strict && outcome.state === 'degraded' ? 1 : 0,
|
|
79
|
-
lines: [`wake-word model: ${outcome.message}`],
|
|
80
|
-
};
|
|
81
|
-
}
|
package/src/daemon/safe-serve.ts
DELETED
|
@@ -1,61 +0,0 @@
|
|
|
1
|
-
import { logger } from '@pellux/goodvibes-sdk/platform/utils';
|
|
2
|
-
import { summarizeError } from '@pellux/goodvibes-sdk/platform/utils';
|
|
3
|
-
|
|
4
|
-
type HostServeFetch = (
|
|
5
|
-
request: Request,
|
|
6
|
-
server: unknown,
|
|
7
|
-
) => Response | undefined | Promise<Response | undefined>;
|
|
8
|
-
|
|
9
|
-
type HostServeOptions = Parameters<typeof Bun.serve>[0] & {
|
|
10
|
-
fetch?: HostServeFetch;
|
|
11
|
-
};
|
|
12
|
-
|
|
13
|
-
function requestPath(request: Request): string {
|
|
14
|
-
try {
|
|
15
|
-
return new URL(request.url).pathname;
|
|
16
|
-
} catch {
|
|
17
|
-
return request.url;
|
|
18
|
-
}
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
export function createHostRequestFailureResponse(
|
|
22
|
-
surface: string,
|
|
23
|
-
request: Request,
|
|
24
|
-
error: unknown,
|
|
25
|
-
): Response {
|
|
26
|
-
const message = summarizeError(error);
|
|
27
|
-
logger.error(`${surface}: request handler failed`, {
|
|
28
|
-
method: request.method,
|
|
29
|
-
path: requestPath(request),
|
|
30
|
-
error: message,
|
|
31
|
-
});
|
|
32
|
-
return Response.json({
|
|
33
|
-
error: message,
|
|
34
|
-
code: 'HOST_REQUEST_HANDLER_FAILED',
|
|
35
|
-
}, { status: 500 });
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
export function createSafeHostServeFactory(
|
|
39
|
-
surface: string,
|
|
40
|
-
baseServeFactory: typeof Bun.serve = Bun.serve,
|
|
41
|
-
): typeof Bun.serve {
|
|
42
|
-
return ((options: HostServeOptions) => {
|
|
43
|
-
const originalFetch = options.fetch;
|
|
44
|
-
if (typeof originalFetch !== 'function') {
|
|
45
|
-
return baseServeFactory(options as Parameters<typeof Bun.serve>[0]);
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
const wrappedFetch: HostServeFetch = async (request, server) => {
|
|
49
|
-
try {
|
|
50
|
-
return await originalFetch(request, server);
|
|
51
|
-
} catch (error) {
|
|
52
|
-
return createHostRequestFailureResponse(surface, request, error);
|
|
53
|
-
}
|
|
54
|
-
};
|
|
55
|
-
|
|
56
|
-
return baseServeFactory({
|
|
57
|
-
...options,
|
|
58
|
-
fetch: wrappedFetch,
|
|
59
|
-
} as Parameters<typeof Bun.serve>[0]);
|
|
60
|
-
}) as typeof Bun.serve;
|
|
61
|
-
}
|