@vellumai/assistant 0.10.4 → 0.10.5-dev.202607022329.d89bf2f
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/ARCHITECTURE.md +94 -91
- package/Dockerfile +5 -16
- package/README.md +7 -10
- package/bun.lock +0 -4
- package/docs/architecture/security.md +20 -20
- package/docs/stt-provider-onboarding.md +4 -5
- package/docs/trusted-contact-access.md +7 -7
- package/eslint-rules/cli-no-daemon-internals.js +4 -0
- package/eslint.config.mjs +7 -1
- package/knip.json +0 -1
- package/node_modules/@vellumai/gateway-client/src/__tests__/contact-read-contracts.test.ts +36 -0
- package/node_modules/@vellumai/gateway-client/src/__tests__/invite-contract.test.ts +233 -0
- package/node_modules/@vellumai/gateway-client/src/__tests__/trust-verdict-contract.test.ts +40 -0
- package/node_modules/@vellumai/gateway-client/src/gateway-ipc-contracts.ts +20 -8
- package/node_modules/@vellumai/gateway-client/src/inbound-contract.ts +10 -0
- package/node_modules/@vellumai/gateway-client/src/index.ts +33 -0
- package/node_modules/@vellumai/gateway-client/src/invite-contract.ts +216 -0
- package/node_modules/@vellumai/gateway-client/src/outbound-contract.ts +91 -0
- package/node_modules/@vellumai/gateway-client/src/trust-verdict-contract.ts +39 -3
- package/node_modules/@vellumai/service-contracts/src/__tests__/ingress.test.ts +0 -8
- package/node_modules/@vellumai/service-contracts/src/__tests__/package-boundary.test.ts +1 -5
- package/node_modules/@vellumai/service-contracts/src/twilio-ingress.ts +3 -14
- package/openapi.yaml +1073 -225
- package/package.json +1 -4
- package/scripts/test.sh +35 -13
- package/src/__tests__/access-request-seed-content-blocks.test.ts +60 -4
- package/src/__tests__/acp-session.test.ts +4 -1
- package/src/__tests__/actor-trust-resolver-address-fallback.test.ts +0 -6
- package/src/__tests__/add-message-preassigned-id.test.ts +56 -0
- package/src/__tests__/agent-loop-set-system-prompt.test.ts +139 -0
- package/src/__tests__/app-conversation-ids-backfill.test.ts +3 -0
- package/src/__tests__/app-source-watcher.test.ts +11 -0
- package/src/__tests__/approval-interception-trust-gates.test.ts +148 -3
- package/src/__tests__/assistant-attachments.test.ts +62 -4
- package/src/__tests__/assistant-id-boundary-guard.test.ts +0 -1
- package/src/__tests__/attachments-store-heic-normalize.test.ts +230 -0
- package/src/__tests__/attachments-store.test.ts +3 -0
- package/src/__tests__/background-shell-bash.test.ts +34 -0
- package/src/__tests__/background-shell-host-bash.test.ts +12 -0
- package/src/__tests__/background-tool-registry.test.ts +97 -0
- package/src/__tests__/background-tool-routes.test.ts +72 -1
- package/src/__tests__/background-workers-disk-pressure.test.ts +2 -1
- package/src/__tests__/btw-routes.test.ts +57 -3
- package/src/__tests__/call-controller.test.ts +474 -84
- package/src/__tests__/call-domain.test.ts +48 -1
- package/src/__tests__/call-pointer-messages.test.ts +57 -19
- package/src/__tests__/call-pointer-no-hardcoded-copy.guard.test.ts +2 -6
- package/src/__tests__/call-routes-http.test.ts +15 -14
- package/src/__tests__/call-setup-flow-invite.test.ts +568 -0
- package/src/__tests__/call-setup-flow-midcall-trust.test.ts +231 -0
- package/src/__tests__/call-setup-flow-name-capture.test.ts +754 -0
- package/src/__tests__/call-setup-flow-verification.test.ts +925 -0
- package/src/__tests__/call-setup-flow.test.ts +311 -0
- package/src/__tests__/cancel-resolves-conversation-key.test.ts +0 -1
- package/src/__tests__/channel-guardian.test.ts +4 -7
- package/src/__tests__/channel-readiness-service.test.ts +0 -6
- package/src/__tests__/channel-readiness-slack-remote.test.ts +0 -4
- package/src/__tests__/channel-retry-sweep.test.ts +76 -64
- package/src/__tests__/channel-setup-panel-ack.test.ts +184 -0
- package/src/__tests__/clear-all-lexical.test.ts +90 -0
- package/src/__tests__/compactor-media-strip.test.ts +177 -0
- package/src/__tests__/config-loader-backfill.test.ts +5 -5
- package/src/__tests__/config-schema.test.ts +17 -0
- package/src/__tests__/contact-store-interaction-info.test.ts +27 -70
- package/src/__tests__/contacts-relay-reads.test.ts +188 -23
- package/src/__tests__/contacts-tools.test.ts +42 -1
- package/src/__tests__/contacts-write.test.ts +181 -0
- package/src/__tests__/context-search-conversations-source.test.ts +220 -81
- package/src/__tests__/conversation-agent-loop-disk-pressure.test.ts +1 -0
- package/src/__tests__/conversation-agent-loop-inference-profile.test.ts +1 -0
- package/src/__tests__/conversation-agent-loop-overflow.test.ts +1 -0
- package/src/__tests__/conversation-agent-loop.test.ts +39 -0
- package/src/__tests__/conversation-analysis-routes.test.ts +1 -1
- package/src/__tests__/conversation-app-control-instantiation.test.ts +2 -0
- package/src/__tests__/conversation-clear-safety.test.ts +0 -1
- package/src/__tests__/conversation-crud-enabled-plugins.test.ts +60 -0
- package/src/__tests__/conversation-delete-schedule-cleanup.test.ts +0 -1
- package/src/__tests__/conversation-disk-view.test.ts +1 -0
- package/src/__tests__/conversation-enabledplugins-route.test.ts +184 -0
- package/src/__tests__/conversation-error.test.ts +0 -18
- package/src/__tests__/conversation-fork-crud.test.ts +67 -0
- package/src/__tests__/conversation-history-web-search.test.ts +7 -137
- package/src/__tests__/conversation-initial-prompt.test.ts +110 -0
- package/src/__tests__/conversation-loop-db-lock-resilience.test.ts +191 -0
- package/src/__tests__/conversation-process-callsite.test.ts +37 -0
- package/src/__tests__/conversation-queue.test.ts +149 -0
- package/src/__tests__/conversation-routes-enabled-plugins.test.ts +392 -0
- package/src/__tests__/conversation-routes-guardian-reply.test.ts +84 -0
- package/src/__tests__/conversation-routes-hidden-queue.test.ts +407 -0
- package/src/__tests__/conversation-runtime-assembly.test.ts +36 -16
- package/src/__tests__/conversation-skill-tools.test.ts +73 -0
- package/src/__tests__/conversation-wipe.test.ts +20 -5
- package/src/__tests__/credential-prompt-route.test.ts +69 -0
- package/src/__tests__/credential-security-invariants.test.ts +1 -3
- package/src/__tests__/db-drop-messages-fts.test.ts +115 -0
- package/src/__tests__/deterministic-verification-control-plane.test.ts +1 -62
- package/src/__tests__/edit-propagation.test.ts +56 -2
- package/src/__tests__/empty-state-greeting-cache.test.ts +9 -0
- package/src/__tests__/gateway-only-enforcement.test.ts +15 -110
- package/src/__tests__/guardian-expiry-notifier.test.ts +1 -0
- package/src/__tests__/guardian-question-mode.test.ts +57 -0
- package/src/__tests__/guardian-verification-voice-binding.test.ts +1 -1
- package/src/__tests__/guardian-wait-controller.test.ts +619 -0
- package/src/__tests__/handlers-skills-memory-v2-reseed.test.ts +33 -2
- package/src/__tests__/heic-fixture.ts +55 -0
- package/src/__tests__/helpers/seed-contact-channel.ts +0 -2
- package/src/__tests__/http-conversation-lineage.test.ts +6 -1
- package/src/__tests__/image-conversion.test.ts +170 -0
- package/src/__tests__/inbound-invite-redemption.test.ts +72 -341
- package/src/__tests__/introduction-card-resolver.test.ts +354 -0
- package/src/__tests__/invite-redeemed-ipc.test.ts +97 -0
- package/src/__tests__/invite-routes-http.test.ts +246 -420
- package/src/__tests__/job-handler-registration-guard.test.ts +104 -0
- package/src/__tests__/lexical-index-dual-write.test.ts +426 -0
- package/src/__tests__/lifecycle-memory-v2-seed.test.ts +2 -2
- package/src/__tests__/list-messages-attachments.test.ts +159 -0
- package/src/__tests__/list-messages-background-tool-completion.test.ts +141 -0
- package/src/__tests__/list-messages-queued.test.ts +25 -0
- package/src/__tests__/managed-store.test.ts +129 -1
- package/src/__tests__/media-stream-audio-transcode.test.ts +113 -0
- package/src/__tests__/media-stream-output.test.ts +350 -19
- package/src/__tests__/media-stream-server-integration.test.ts +943 -169
- package/src/__tests__/media-stream-stt-session.test.ts +498 -1
- package/src/__tests__/memory-jobs-worker-lanes.test.ts +2 -2
- package/src/__tests__/model-intents.test.ts +1 -1
- package/src/__tests__/mtime-cache.test.ts +19 -0
- package/src/__tests__/non-member-access-request.test.ts +349 -3
- package/src/__tests__/notification-decision-fallback.test.ts +104 -8
- package/src/__tests__/notification-decision-strategy.test.ts +57 -8
- package/src/__tests__/onboarding-template-contract.test.ts +27 -43
- package/src/__tests__/openai-provider.test.ts +33 -0
- package/src/__tests__/openai-responses-provider.test.ts +40 -0
- package/src/__tests__/persistence-layering-guard.test.ts +29 -20
- package/src/__tests__/persona-resolver.test.ts +56 -2
- package/src/__tests__/personal-memory-auth-bypass.test.ts +62 -0
- package/src/__tests__/phone.test.ts +1 -15
- package/src/__tests__/plugin-bootstrap.test.ts +25 -196
- package/src/__tests__/plugin-disabled-state.test.ts +33 -0
- package/src/__tests__/plugin-effective-enabled-set.test.ts +227 -0
- package/src/__tests__/plugin-event-hub-facade.test.ts +323 -0
- package/src/__tests__/plugin-import-boundary-guard.test.ts +156 -42
- package/src/__tests__/plugin-injector-contribution.test.ts +4 -20
- package/src/__tests__/plugin-pipeline.test.ts +63 -1
- package/src/__tests__/plugin-route-contribution.test.ts +62 -115
- package/src/__tests__/plugin-tool-contribution.test.ts +0 -22
- package/src/__tests__/plugin-types.test.ts +0 -1
- package/src/__tests__/pointer-conversation-trust.test.ts +38 -6
- package/src/__tests__/pre-model-call-sanitize.test.ts +1 -1
- package/src/__tests__/prune-old-tool-invocations-job.test.ts +97 -0
- package/src/__tests__/public-ingress-urls.test.ts +0 -48
- package/src/__tests__/qdrant-collection-migration.test.ts +145 -2
- package/src/__tests__/reaction-intercept-member-verdict-warm.test.ts +0 -1
- package/src/__tests__/resolve-trust-class.test.ts +28 -10
- package/src/__tests__/scaffold-managed-skill-tool.test.ts +137 -0
- package/src/__tests__/schedule-retry.test.ts +38 -14
- package/src/__tests__/schedule-routes-workflow-validation.test.ts +3 -3
- package/src/__tests__/schedule-routes.test.ts +14 -6
- package/src/__tests__/schedule-store.test.ts +3 -1
- package/src/__tests__/scheduler-disk-pressure.test.ts +17 -6
- package/src/__tests__/scheduler-recurrence.test.ts +57 -107
- package/src/__tests__/scheduler-reuse-conversation.test.ts +51 -46
- package/src/__tests__/scheduler-wake.test.ts +13 -23
- package/src/__tests__/scheduler-worker-standdown.test.ts +220 -0
- package/src/__tests__/secret-routes-platform-proxy.test.ts +1 -1
- package/src/__tests__/shell-observability.test.ts +1 -0
- package/src/__tests__/skill-boundary-guard.test.ts +3 -4
- package/src/__tests__/skill-load-plugin-scope.test.ts +238 -0
- package/src/__tests__/skill-projection-feature-flag.test.ts +2 -0
- package/src/__tests__/skill-script-runner-host.test.ts +53 -0
- package/src/__tests__/skill-script-runner-sandbox.test.ts +5 -2
- package/src/__tests__/skill-tool-factory.test.ts +73 -1
- package/src/__tests__/slack-app-setup-skill-regression.test.ts +37 -14
- package/src/__tests__/slack-inbound-verification.test.ts +36 -0
- package/src/__tests__/slack-notification-approval-card.test.ts +89 -2
- package/src/__tests__/slack-reaction-canonical-approval.test.ts +51 -1
- package/src/__tests__/stt-hints.test.ts +2 -256
- package/src/__tests__/subagent-allowlist-validation.test.ts +47 -0
- package/src/__tests__/subagent-call-site-routing.test.ts +72 -0
- package/src/__tests__/subagent-fork-notifications.test.ts +14 -2
- package/src/__tests__/subagent-persistence.test.ts +122 -0
- package/src/__tests__/subagent-spawn-and-await.test.ts +1 -0
- package/src/__tests__/subagent-terminal-message.test.ts +99 -0
- package/src/__tests__/subagent-tool-gate-mode.test.ts +78 -1
- package/src/__tests__/system-prompt.test.ts +17 -118
- package/src/__tests__/task-scheduler.test.ts +68 -89
- package/src/__tests__/telephony-credential-preflight.test.ts +312 -0
- package/src/__tests__/telephony-tts-guard.test.ts +538 -0
- package/src/__tests__/title-generate-hook.test.ts +16 -0
- package/src/__tests__/tool-approval-handler.test.ts +87 -1
- package/src/__tests__/tool-approval-seed-content-blocks.test.ts +45 -20
- package/src/__tests__/tool-grant-request-escalation.test.ts +39 -0
- package/src/__tests__/trust-context-guards.test.ts +21 -10
- package/src/__tests__/trusted-contact-multichannel.test.ts +4 -0
- package/src/__tests__/twilio-provider.test.ts +17 -17
- package/src/__tests__/twilio-routes-twiml.test.ts +6 -543
- package/src/__tests__/twilio-routes.test.ts +257 -387
- package/src/__tests__/twilio-validation.test.ts +1 -1
- package/src/__tests__/unified-turn-context-client-os.test.ts +45 -0
- package/src/__tests__/usage-cache-backfill-migration.test.ts +5 -0
- package/src/__tests__/voice-approval-resolver-relay.test.ts +150 -0
- package/src/__tests__/voice-ingress-preflight.test.ts +61 -0
- package/src/__tests__/voice-quality.test.ts +2 -2
- package/src/__tests__/voice-scoped-grant-consumer.test.ts +1 -7
- package/src/__tests__/voice-session-bridge-processing-wait.test.ts +27 -0
- package/src/__tests__/voice-session-bridge.test.ts +1 -10
- package/src/__tests__/workspace-git-service.test.ts +1 -1
- package/src/__tests__/workspace-migration-013-repair-conversation-disk-view.test.ts +1 -0
- package/src/__tests__/workspace-migration-118-seed-now-md.test.ts +120 -0
- package/src/__tests__/workspace-migration-120-revise-onboarding-threads.test.ts +175 -0
- package/src/__tests__/workspace-migration-121-seed-default-user-guardrails.test.ts +118 -0
- package/src/__tests__/workspace-migration-122-relocate-default-user-boundary.test.ts +119 -0
- package/src/__tests__/workspace-migration-123-swap-quality-profile-to-fable.test.ts +191 -0
- package/src/__tests__/workspace-migration-backfill-installation-id.test.ts +235 -241
- package/src/acp/__tests__/prepare-agent-env.test.ts +0 -97
- package/src/acp/__tests__/session-manager-persistence.test.ts +2 -0
- package/src/acp/__tests__/session-manager-resume.test.ts +8 -0
- package/src/acp/__tests__/session-manager-usage.test.ts +6 -0
- package/src/acp/__tests__/session-manager.test.ts +6 -0
- package/src/acp/agent-process.test.ts +116 -0
- package/src/acp/agent-process.ts +71 -0
- package/src/acp/auto-install.ts +12 -8
- package/src/acp/failure-error.test.ts +109 -0
- package/src/acp/failure-error.ts +111 -0
- package/src/acp/prepare-agent-env.ts +0 -12
- package/src/acp/resolve-agent.test.ts +6 -45
- package/src/acp/resolve-agent.ts +2 -4
- package/src/acp/session-manager.test.ts +312 -0
- package/src/acp/session-manager.ts +102 -46
- package/src/agent/ax-tree-compaction.test.ts +4 -1
- package/src/agent/image-optimize.ts +17 -127
- package/src/agent/loop.ts +45 -192
- package/src/api/events/background-tool-completed.test.ts +51 -0
- package/src/api/events/background-tool-completed.ts +29 -0
- package/src/api/events/background-tool-started.test.ts +36 -0
- package/src/api/events/background-tool-started.ts +28 -0
- package/src/api/events/conversation-error.ts +0 -1
- package/src/api/events/open-panel.ts +33 -0
- package/src/api/events/subagent-status-changed.ts +4 -1
- package/src/api/index.ts +19 -0
- package/src/api/responses/conversation-message.ts +34 -0
- package/src/approvals/guardian-decision-primitive.ts +74 -24
- package/src/approvals/guardian-request-resolvers.ts +450 -122
- package/src/apps/app-store.ts +1 -0
- package/src/apps/shared-app-links-store.ts +1 -0
- package/src/avatar/identity-avatar.ts +3 -7
- package/src/background-wake/wake-intent-hooks.test.ts +1 -1
- package/src/calls/__tests__/fish-audio-client.test.ts +73 -0
- package/src/calls/__tests__/gateway-invite-reader.test.ts +170 -0
- package/src/calls/__tests__/relay-setup-router.test.ts +126 -102
- package/src/calls/call-controller.ts +134 -48
- package/src/calls/call-domain.ts +18 -42
- package/src/calls/call-pointer-messages.ts +51 -67
- package/src/calls/call-setup-flow-types.ts +76 -0
- package/src/calls/call-setup-flow.ts +1743 -0
- package/src/calls/call-speech-output.ts +87 -23
- package/src/calls/call-store.ts +4 -0
- package/src/calls/call-transport.ts +22 -36
- package/src/calls/fish-audio-client.ts +3 -0
- package/src/calls/gateway-invite-reader.ts +98 -0
- package/src/calls/guardian-wait-controller.ts +451 -0
- package/src/calls/media-stream-audio-transcode.ts +82 -2
- package/src/calls/media-stream-output.ts +142 -36
- package/src/calls/media-stream-server.ts +297 -178
- package/src/calls/media-stream-stt-session.ts +393 -50
- package/src/calls/media-turn-detector.ts +4 -6
- package/src/calls/relay-access-wait.ts +3 -4
- package/src/calls/relay-setup-router.ts +22 -43
- package/src/calls/relay-verification.ts +17 -24
- package/src/calls/resolve-call-tts-provider.ts +96 -29
- package/src/calls/stt-hints.ts +24 -87
- package/src/calls/telephony-credential-preflight.ts +159 -0
- package/src/calls/telephony-tts-capability.ts +183 -0
- package/src/calls/tts-call-strategy.ts +18 -20
- package/src/calls/twilio-provider.ts +3 -2
- package/src/calls/twilio-routes.ts +47 -351
- package/src/calls/types.ts +5 -3
- package/src/calls/voice-ingress-preflight.ts +9 -0
- package/src/calls/voice-quality.ts +13 -18
- package/src/calls/voice-session-bridge.ts +25 -35
- package/src/channels/__tests__/types.test.ts +28 -0
- package/src/channels/channel-verification-sessions.ts +7 -2
- package/src/channels/config.ts +0 -42
- package/src/channels/slack-thread-store.ts +12 -0
- package/src/channels/types.ts +23 -0
- package/src/cli/commands/__tests__/conversations-slack.test.ts +1 -1
- package/src/cli/commands/__tests__/schedules.test.ts +83 -34
- package/src/cli/commands/__tests__/status.test.ts +42 -2
- package/src/cli/commands/contacts.ts +2 -2
- package/src/cli/commands/credentials.ts +17 -0
- package/src/cli/commands/monitoring.ts +191 -0
- package/src/cli/commands/schedules-worker.ts +175 -0
- package/src/cli/commands/schedules.ts +169 -43
- package/src/cli/commands/status.ts +12 -1
- package/src/cli/commands/tools.ts +5 -1
- package/src/cli/lib/__tests__/plugin-catalog-cache.test.ts +1 -0
- package/src/cli/lib/__tests__/search-plugins.test.ts +29 -1
- package/src/cli/lib/__tests__/toggle-plugin.test.ts +7 -0
- package/src/cli/lib/search-plugins.ts +6 -0
- package/src/cli/lib/toggle-plugin.ts +21 -2
- package/src/cli/program.ts +3 -1
- package/src/config/__tests__/deployment-context-defaults.test.ts +23 -0
- package/src/config/acp-defaults.test.ts +0 -10
- package/src/config/acp-defaults.ts +0 -6
- package/src/config/bundled-skills/acp/SKILL.md +13 -45
- package/src/config/bundled-skills/acp/TOOLS.json +3 -3
- package/src/config/bundled-skills/app-builder/SKILL.md +3 -3
- package/src/config/bundled-skills/app-builder/references/RESPONSIVE.md +9 -9
- package/src/config/bundled-skills/contacts/tools/contact-merge.ts +1 -1
- package/src/config/bundled-skills/contacts/tools/contact-search.ts +1 -1
- package/src/config/bundled-skills/phone-calls/SKILL.md +1 -1
- package/src/config/bundled-skills/phone-calls/references/CONFIG.md +9 -9
- package/src/config/bundled-skills/phone-calls/references/TROUBLESHOOTING.md +10 -7
- package/src/config/bundled-skills/skill-management/TOOLS.json +10 -0
- package/src/config/call-site-defaults.ts +0 -2
- package/src/config/feature-flag-registry.json +16 -8
- package/src/config/loader.ts +11 -0
- package/src/config/schema.ts +9 -1
- package/src/config/schemas/__tests__/memory-v2.test.ts +2 -2
- package/src/config/schemas/__tests__/memory-v3.test.ts +64 -0
- package/src/config/schemas/call-site-catalog.ts +0 -12
- package/src/config/schemas/calls.ts +8 -0
- package/src/config/schemas/elevenlabs.ts +1 -1
- package/src/config/schemas/llm.ts +0 -2
- package/src/config/schemas/memory-v2.ts +1 -1
- package/src/config/schemas/memory-v3.ts +82 -0
- package/src/config/schemas/monitoring.ts +61 -0
- package/src/config/schemas/schedules.ts +35 -0
- package/src/config/seed-inference-profiles.ts +2 -2
- package/src/config/skills-plugin-filter.test.ts +96 -0
- package/src/config/skills.ts +26 -0
- package/src/contacts/__tests__/member-write-relay.test.ts +156 -4
- package/src/contacts/canonical-guardian-store.ts +5 -0
- package/src/contacts/contact-store.ts +81 -35
- package/src/contacts/contacts-write.ts +50 -25
- package/src/contacts/member-write-relay.ts +115 -31
- package/src/contacts/types.ts +0 -8
- package/src/context/compactor.ts +29 -15
- package/src/context/outbound-sanitize.ts +202 -0
- package/src/daemon/__tests__/abort-null-controller.test.ts +167 -0
- package/src/daemon/__tests__/conversation-tool-setup-plugin-scope.test.ts +122 -0
- package/src/daemon/__tests__/embedding-reconcile.test.ts +99 -16
- package/src/daemon/__tests__/wake-conversation-ops-completion.test.ts +107 -0
- package/src/daemon/abort-watchdog.ts +7 -0
- package/src/daemon/app-source-watcher.ts +9 -0
- package/src/daemon/assistant-attachments.ts +42 -0
- package/src/daemon/conversation-agent-loop-handlers.ts +256 -147
- package/src/daemon/conversation-agent-loop.ts +61 -68
- package/src/daemon/conversation-error.ts +1 -15
- package/src/daemon/conversation-history.ts +32 -236
- package/src/daemon/conversation-initial-prompt.ts +77 -0
- package/src/daemon/conversation-lifecycle.ts +25 -1
- package/src/daemon/conversation-messaging.ts +2 -2
- package/src/daemon/conversation-plugin-scope.ts +38 -0
- package/src/daemon/conversation-process.ts +50 -14
- package/src/daemon/conversation-runtime-assembly.ts +36 -6
- package/src/daemon/conversation-skill-tools.ts +19 -3
- package/src/daemon/conversation-store.ts +3 -3
- package/src/daemon/conversation-surfaces.ts +171 -0
- package/src/daemon/conversation-tool-setup.test.ts +95 -0
- package/src/daemon/conversation-tool-setup.ts +116 -1
- package/src/daemon/conversation-turn-finalize.ts +211 -0
- package/src/daemon/conversation.ts +92 -1
- package/src/daemon/disk-pressure-policy.ts +2 -1
- package/src/daemon/event-loop-watchdog.ts +22 -6
- package/src/daemon/external-plugins-bootstrap.ts +47 -134
- package/src/daemon/handlers/__tests__/config-a2a-accept.test.ts +1 -1
- package/src/daemon/handlers/__tests__/config-a2a-complete.test.ts +26 -14
- package/src/daemon/handlers/__tests__/config-a2a-invite.test.ts +27 -14
- package/src/daemon/handlers/__tests__/config-channels.test.ts +0 -5
- package/src/daemon/handlers/config-a2a.ts +7 -14
- package/src/daemon/handlers/config-channels.ts +2 -10
- package/src/daemon/handlers/conversation-history.ts +3 -1
- package/src/daemon/handlers/conversations.ts +0 -52
- package/src/daemon/handlers/shared.ts +4 -24
- package/src/daemon/handlers/skills.ts +4 -1
- package/src/daemon/host-cu-proxy.ts +1 -1
- package/src/daemon/lifecycle.ts +59 -472
- package/src/daemon/message-protocol.ts +3 -3
- package/src/daemon/message-provenance.ts +12 -14
- package/src/daemon/message-types/background-tools.ts +28 -0
- package/src/daemon/message-types/contacts.ts +2 -10
- package/src/daemon/message-types/conversations.ts +10 -0
- package/src/daemon/message-types/integrations.ts +2 -0
- package/src/daemon/message-types/surfaces.ts +1 -0
- package/src/daemon/message-types/sync.ts +1 -0
- package/src/daemon/pointer-conversation-trust.ts +23 -9
- package/src/daemon/pointer-turn-runner.ts +174 -0
- package/src/daemon/providers-setup.ts +16 -0
- package/src/daemon/shutdown-handlers.ts +139 -47
- package/src/daemon/skill-memory-refresh.ts +2 -2
- package/src/daemon/sqlite-corruption-watchdog.test.ts +217 -0
- package/src/daemon/sqlite-corruption-watchdog.ts +155 -0
- package/src/daemon/tool-setup-types.ts +8 -0
- package/src/daemon/trust-context.ts +21 -6
- package/src/daemon/turn-latency-tracker.test.ts +93 -0
- package/src/daemon/turn-latency-tracker.ts +38 -0
- package/src/daemon/wake-conversation-ops.ts +10 -8
- package/src/documents/document-comments-store.test.ts +7 -1
- package/src/documents/document-comments-store.ts +8 -0
- package/src/documents/document-store.ts +15 -0
- package/src/export/__tests__/transcript-formatter.test.ts +11 -0
- package/src/export/transcript-formatter.ts +49 -67
- package/src/home/__tests__/feed-writer.test.ts +247 -1
- package/src/home/conversation-starter-checkpoints.ts +1 -0
- package/src/home/feed-writer.ts +61 -0
- package/src/home/job-handlers/conversation-starters.ts +1 -0
- package/src/hooks/hook-loader.ts +12 -0
- package/src/hooks/registry.ts +32 -4
- package/src/inbound/public-ingress-urls.ts +0 -17
- package/src/ipc/__tests__/contacts-info-ipc.test.ts +285 -0
- package/src/ipc/assistant-server.ts +28 -7
- package/src/ipc/routes/__tests__/contacts-mirror-apply-atomicity.test.ts +62 -0
- package/src/ipc/routes/__tests__/contacts-mirror-apply.test.ts +272 -0
- package/src/ipc/routes/__tests__/contacts-mirror-ipc-routes.test.ts +322 -0
- package/src/ipc/routes/__tests__/invite-ipc-routes.test.ts +60 -4
- package/src/ipc/routes/contacts-info-ipc-routes.ts +239 -0
- package/src/ipc/routes/contacts-mirror-ipc-routes.ts +202 -0
- package/src/ipc/routes/db-proxy.ts +5 -2
- package/src/ipc/routes/invite-ipc-routes.ts +53 -39
- package/src/jobs/worker.ts +9 -2
- package/src/live-voice/__tests__/live-voice-archive.test.ts +10 -1
- package/src/live-voice/live-voice-archive.ts +5 -0
- package/src/messaging/providers/__tests__/transport-dispatch.test.ts +22 -6
- package/src/messaging/providers/channel-transport.ts +6 -0
- package/src/messaging/providers/index.ts +3 -0
- package/src/messaging/providers/slack/api.test.ts +49 -1
- package/src/messaging/providers/slack/api.ts +110 -0
- package/src/messaging/providers/slack/send.test.ts +85 -0
- package/src/messaging/providers/slack/send.ts +100 -28
- package/src/messaging/providers/slack/transport.ts +7 -13
- package/src/messaging/providers/whatsapp/send.ts +29 -9
- package/src/monitoring/__tests__/control.test.ts +235 -0
- package/src/monitoring/__tests__/sample-ring-buffer.test.ts +96 -0
- package/src/monitoring/control.ts +105 -0
- package/src/monitoring/resource-sampler.ts +258 -0
- package/src/monitoring/sample-ring-buffer.ts +108 -0
- package/src/monitoring/worker.ts +94 -0
- package/src/notifications/README.md +1 -1
- package/src/notifications/access-request-copy.ts +94 -23
- package/src/notifications/adapters/slack.ts +89 -21
- package/src/notifications/approval-card-builder.ts +33 -18
- package/src/notifications/approval-card-data.ts +48 -15
- package/src/notifications/broadcaster.ts +25 -16
- package/src/notifications/decision-engine.ts +131 -32
- package/src/notifications/guardian-question-mode.ts +58 -10
- package/src/permissions/approval-policy.ts +8 -1
- package/src/permissions/checker.ts +2 -0
- package/src/permissions/gateway-threshold-reader.ts +7 -6
- package/src/permissions/ipc-risk-types.ts +1 -0
- package/src/permissions/secret-prompter.ts +11 -3
- package/src/permissions/types.ts +2 -2
- package/src/persistence/__tests__/conversation-queries-search.test.ts +397 -0
- package/src/persistence/__tests__/conversation-search-lexical.test.ts +103 -0
- package/src/persistence/__tests__/jobs-worker-memory-disabled.test.ts +95 -0
- package/src/persistence/__tests__/slow-query-log.test.ts +266 -0
- package/src/persistence/__tests__/slow-sync-log.test.ts +155 -0
- package/src/persistence/a2a-invite-store.ts +205 -0
- package/src/persistence/attachments-store.ts +94 -10
- package/src/persistence/checkpoints.ts +45 -0
- package/src/persistence/conversation-crud.ts +453 -260
- package/src/persistence/conversation-display-order-migration.ts +8 -2
- package/src/persistence/conversation-group-migration.test.ts +8 -0
- package/src/persistence/conversation-group-migration.ts +9 -0
- package/src/persistence/conversation-queries.ts +244 -125
- package/src/persistence/conversation-row-batch-delete.ts +9 -5
- package/src/persistence/conversation-search-lexical.ts +49 -0
- package/src/persistence/db-async-query.ts +42 -0
- package/src/persistence/db-connection.ts +13 -0
- package/src/persistence/delivery-channels.ts +0 -82
- package/src/persistence/delivery-crud.ts +27 -6
- package/src/persistence/embeddings/__tests__/embedding-identity.test.ts +18 -5
- package/src/persistence/embeddings/__tests__/messages-lexical-index.test.ts +334 -0
- package/src/persistence/embeddings/embedding-identity.ts +17 -5
- package/src/persistence/embeddings/embedding-runtime-manager.ts +31 -0
- package/src/persistence/embeddings/messages-lexical-index.ts +396 -0
- package/src/persistence/embeddings/qdrant-client.ts +81 -5
- package/src/persistence/group-crud.ts +13 -1
- package/src/persistence/job-handlers/__tests__/message-lexical-backfill.test.ts +506 -0
- package/src/persistence/job-handlers/__tests__/message-lexical-enqueue.test.ts +164 -0
- package/src/persistence/job-handlers/__tests__/message-lexical.test.ts +259 -0
- package/src/persistence/job-handlers/cleanup.ts +57 -9
- package/src/persistence/job-handlers/message-lexical-backfill.ts +187 -0
- package/src/persistence/job-handlers/message-lexical.ts +251 -0
- package/src/persistence/jobs-store.ts +102 -8
- package/src/persistence/jobs-worker.ts +68 -28
- package/src/persistence/llm-request-log-store.ts +35 -19
- package/src/persistence/llm-usage-store.ts +11 -0
- package/src/persistence/memory-lifecycle-hooks.test.ts +65 -0
- package/src/persistence/memory-lifecycle-hooks.ts +55 -1
- package/src/persistence/migrations/028-call-session-mode.ts +1 -1
- package/src/persistence/migrations/116-messages-fts.ts +8 -1
- package/src/persistence/migrations/311-create-subagents-table.ts +50 -0
- package/src/persistence/migrations/312-drop-inbox-conversation-state-table.ts +15 -0
- package/src/persistence/migrations/313-drop-messages-fts.ts +17 -0
- package/src/persistence/migrations/314-add-conversation-enabled-plugins.ts +25 -0
- package/src/persistence/migrations/315-create-a2a-invites.ts +58 -0
- package/src/persistence/migrations/316-drop-contact-channels-invite-id.ts +28 -0
- package/src/persistence/migrations/317-canonical-guardian-requester-signals.ts +24 -0
- package/src/persistence/migrations/318-drop-contact-channel-telemetry.ts +32 -0
- package/src/persistence/migrations/__tests__/315-create-a2a-invites.test.ts +161 -0
- package/src/persistence/migrations/__tests__/316-drop-contact-channels-invite-id.test.ts +156 -0
- package/src/persistence/migrations/__tests__/318-drop-contact-channel-telemetry.test.ts +134 -0
- package/src/persistence/migrations/__tests__/migration-prefix-guard.test.ts +99 -0
- package/src/persistence/raw-query.ts +50 -11
- package/src/persistence/schema/a2a.ts +14 -0
- package/src/persistence/schema/contacts.ts +0 -62
- package/src/persistence/schema/conversation-groups.ts +12 -0
- package/src/persistence/schema/conversations.ts +2 -0
- package/src/persistence/schema/documents.ts +65 -0
- package/src/persistence/schema/guardian.ts +4 -0
- package/src/persistence/schema/index.ts +4 -0
- package/src/persistence/schema/memory-injection.ts +62 -0
- package/src/persistence/schema/workflows.ts +55 -0
- package/src/persistence/slow-query-log.ts +437 -0
- package/src/persistence/slow-sync-log.ts +204 -0
- package/src/persistence/steps.ts +16 -0
- package/src/persistence/subagent-store.ts +125 -0
- package/src/persistence/worker-control.ts +45 -238
- package/src/plugin-api/event-hub-facade.ts +172 -0
- package/src/plugin-api/index.ts +9 -1
- package/src/plugin-api/types.ts +40 -9
- package/src/plugins/defaults/default-plugin-names.ts +60 -0
- package/src/plugins/defaults/index.ts +19 -29
- package/src/plugins/defaults/memory/__tests__/conversation-queries.test.ts +46 -67
- package/src/plugins/defaults/memory/__tests__/db-async-query.test.ts +36 -1
- package/src/plugins/defaults/memory/__tests__/find-most-recent-retrospective-for.test.ts +2 -4
- package/src/plugins/defaults/memory/__tests__/jobs-worker-v2-graph-trigger-embed.test.ts +2 -2
- package/src/plugins/defaults/memory/__tests__/jobs-worker-v2-schedule.test.ts +9 -0
- package/src/plugins/defaults/memory/__tests__/memory-retrospective-job.test.ts +7 -4
- package/src/plugins/defaults/memory/config.ts +11 -0
- package/src/plugins/defaults/memory/context-search/agent-runner.ts +1 -1
- package/src/plugins/defaults/memory/context-search/sources/conversations.ts +124 -113
- package/src/plugins/defaults/memory/embeddings.ts +77 -0
- package/src/plugins/defaults/memory/find-most-recent-retrospective-for.ts +66 -0
- package/src/plugins/defaults/memory/frontmatter.ts +50 -0
- package/src/plugins/defaults/memory/graph/bootstrap.test.ts +36 -10
- package/src/plugins/defaults/memory/graph/bootstrap.ts +6 -5
- package/src/plugins/defaults/memory/graph/consolidation.ts +3 -5
- package/src/plugins/defaults/memory/graph/extraction.ts +3 -6
- package/src/plugins/defaults/memory/graph/graph-search.ts +12 -23
- package/src/plugins/defaults/memory/graph/narrative.ts +3 -5
- package/src/plugins/defaults/memory/graph/pattern-scan.ts +3 -5
- package/src/plugins/defaults/memory/graph/retriever.test.ts +1 -6
- package/src/plugins/defaults/memory/graph/retriever.ts +5 -10
- package/src/plugins/defaults/memory/graph/tools.ts +1 -1
- package/src/plugins/defaults/memory/hooks/init.ts +31 -5
- package/src/plugins/defaults/memory/indexer.ts +2 -3
- package/src/plugins/defaults/memory/injectors.ts +2 -2
- package/src/plugins/defaults/memory/job-handler-registration.ts +96 -0
- package/src/plugins/defaults/memory/job-handlers/backfill.ts +4 -26
- package/src/plugins/defaults/memory/job-handlers/embedding.test.ts +6 -19
- package/src/plugins/defaults/memory/job-handlers/embedding.ts +9 -22
- package/src/plugins/defaults/memory/job-handlers/index-maintenance.ts +2 -3
- package/src/plugins/defaults/memory/job-handlers.ts +13 -12
- package/src/plugins/defaults/memory/jobs/embed-concept-page.ts +1 -1
- package/src/plugins/defaults/memory/llm-helpers.ts +76 -0
- package/src/plugins/defaults/memory/memory-retrospective-job.ts +8 -5
- package/src/plugins/defaults/memory/memory-retrospective-startup-cleanup.ts +2 -2
- package/src/plugins/defaults/memory/memory-v2-concept-frequency.ts +2 -0
- package/src/plugins/defaults/memory/persistence-hooks.ts +46 -1
- package/src/plugins/defaults/memory/pkb/pkb-index.ts +1 -5
- package/src/plugins/defaults/memory/pkb/pkb-search.ts +2 -2
- package/src/plugins/defaults/memory/routes/__tests__/memory-v2-simulate-route.test.ts +4 -6
- package/src/plugins/defaults/memory/routes/memory-item-routes.ts +1 -1
- package/src/plugins/defaults/memory/search/semantic.ts +2 -2
- package/src/plugins/defaults/memory/startup.ts +244 -0
- package/src/plugins/defaults/memory/task-memory-cleanup.ts +8 -0
- package/src/{daemon → plugins/defaults/memory/v2}/__tests__/memory-v2-startup.test.ts +6 -6
- package/src/plugins/defaults/memory/v2/__tests__/migration.test.ts +2 -13
- package/src/plugins/defaults/memory/v2/__tests__/router.test.ts +4 -5
- package/src/plugins/defaults/memory/v2/__tests__/sweep-job.test.ts +1 -8
- package/src/plugins/defaults/memory/v2/activation.ts +2 -4
- package/src/plugins/defaults/memory/v2/cli-command-store.ts +2 -4
- package/src/plugins/defaults/memory/v2/frontmatter-sweep.ts +1 -1
- package/src/{daemon → plugins/defaults/memory/v2}/memory-v2-startup.test.ts +8 -8
- package/src/{daemon → plugins/defaults/memory/v2}/memory-v2-startup.ts +20 -22
- package/src/plugins/defaults/memory/v2/migration.ts +2 -5
- package/src/plugins/defaults/memory/v2/page-store.ts +1 -1
- package/src/plugins/defaults/memory/v2/qdrant.ts +2 -3
- package/src/plugins/defaults/memory/v2/router.ts +5 -5
- package/src/plugins/defaults/memory/v2/sim.ts +2 -4
- package/src/plugins/defaults/memory/v2/skill-store.ts +2 -4
- package/src/plugins/defaults/memory/v2/sweep-job.ts +6 -6
- package/src/plugins/defaults/memory/v3/__tests__/carry-integration.test.ts +11 -9
- package/src/plugins/defaults/memory/v3/__tests__/dense.test.ts +107 -2
- package/src/plugins/defaults/memory/v3/__tests__/gate-flag.test.ts +69 -0
- package/src/plugins/defaults/memory/v3/__tests__/gate.test.ts +181 -0
- package/src/plugins/defaults/memory/v3/__tests__/live-integration.test.ts +7 -3
- package/src/plugins/defaults/memory/v3/__tests__/orchestrate.test.ts +345 -8
- package/src/plugins/defaults/memory/v3/__tests__/pool-select.test.ts +1 -4
- package/src/plugins/defaults/memory/v3/__tests__/section-needle.test.ts +64 -0
- package/src/plugins/defaults/memory/v3/__tests__/shadow-integration.test.ts +18 -13
- package/src/plugins/defaults/memory/v3/__tests__/shadow-plugin.test.ts +62 -1
- package/src/plugins/defaults/memory/v3/card.ts +1 -4
- package/src/plugins/defaults/memory/v3/dense.ts +60 -25
- package/src/plugins/defaults/memory/v3/edge.ts +1 -1
- package/src/plugins/defaults/memory/v3/gate-flag.ts +20 -0
- package/src/plugins/defaults/memory/v3/gate.ts +158 -0
- package/src/plugins/defaults/memory/v3/maintain-job.ts +2 -4
- package/src/plugins/defaults/memory/v3/orchestrate.ts +186 -25
- package/src/plugins/defaults/memory/v3/pool-select.test.ts +7 -9
- package/src/plugins/defaults/memory/v3/pool-select.ts +6 -6
- package/src/plugins/defaults/memory/v3/prune.ts +2 -2
- package/src/plugins/defaults/memory/v3/section-dense-store.ts +8 -11
- package/src/plugins/defaults/memory/v3/section-needle.ts +27 -7
- package/src/plugins/defaults/memory/v3/shadow-plugin.ts +10 -0
- package/src/plugins/defaults/memory/v3-eval/eval-packets.ts +1 -4
- package/src/plugins/defaults/title-generate/hooks/user-prompt-submit.ts +5 -0
- package/src/plugins/defaults/turn-context/injectors.ts +1 -0
- package/src/plugins/defaults/turn-context/unified-turn-context.ts +12 -0
- package/src/plugins/injector-registry.ts +13 -2
- package/src/plugins/mtime-cache.ts +36 -47
- package/src/plugins/pipeline.ts +15 -1
- package/src/plugins/types.ts +14 -23
- package/src/prompts/__tests__/system-prompt.test.ts +170 -32
- package/src/prompts/persona-resolver.ts +13 -9
- package/src/prompts/system-prompt.ts +30 -9
- package/src/prompts/templates/BOOTSTRAP.md +16 -119
- package/src/prompts/templates/SOUL.md +43 -13
- package/src/prompts/templates/system-sections.ts +32 -27
- package/src/prompts/templates/users/default.md +19 -0
- package/src/providers/__tests__/placeholder-sentinels.test.ts +56 -0
- package/src/providers/inference/__tests__/base-url-route-validation.test.ts +96 -1
- package/src/providers/model-intents.ts +2 -2
- package/src/providers/openai/chat-completions-provider.ts +14 -1
- package/src/providers/openai/responses-provider.ts +18 -0
- package/src/providers/placeholder-sentinels.ts +18 -8
- package/src/providers/retry.ts +1 -0
- package/src/providers/speech-to-text/__tests__/provider-catalog.test.ts +0 -64
- package/src/providers/speech-to-text/__tests__/resolve.test.ts +92 -79
- package/src/providers/speech-to-text/deepgram-realtime.test.ts +98 -0
- package/src/providers/speech-to-text/deepgram-realtime.ts +62 -3
- package/src/providers/speech-to-text/provider-catalog.ts +0 -89
- package/src/providers/speech-to-text/resolve.ts +55 -0
- package/src/providers/tool-progress-events.test.ts +50 -0
- package/src/providers/tool-progress-events.ts +99 -0
- package/src/providers/types.ts +1 -1
- package/src/providers/vellum-model-routing.test.ts +51 -0
- package/src/providers/vellum-model-routing.ts +84 -0
- package/src/runtime/AGENTS.md +5 -4
- package/src/runtime/__tests__/agent-wake.test.ts +158 -1
- package/src/runtime/__tests__/channel-verification-service.test.ts +2 -2
- package/src/runtime/__tests__/trust-verdict-consumer.test.ts +37 -8
- package/src/runtime/access-request-helper.ts +154 -3
- package/src/runtime/actor-trust-resolver.ts +7 -21
- package/src/runtime/agent-wake.ts +41 -1
- package/src/runtime/assistant-event.ts +86 -12
- package/src/runtime/auth/__tests__/route-policy.test.ts +31 -0
- package/src/runtime/channel-approval-types.ts +52 -2
- package/src/runtime/channel-approvals.ts +23 -8
- package/src/runtime/channel-invite-transport.ts +2 -2
- package/src/runtime/channel-invite-transports/voice.ts +1 -1
- package/src/runtime/channel-readiness-service.ts +3 -5
- package/src/runtime/channel-retry-sweep.ts +18 -24
- package/src/runtime/channel-verification-service.ts +9 -11
- package/src/runtime/finalize-event-delivery.ts +30 -16
- package/src/runtime/guardian-action-service.ts +10 -11
- package/src/runtime/guardian-reply-router.ts +122 -21
- package/src/runtime/http-server.ts +44 -101
- package/src/runtime/introduction-policy.test.ts +214 -0
- package/src/runtime/introduction-policy.ts +284 -0
- package/src/runtime/invite-service.ts +104 -361
- package/src/runtime/local-actor-identity.test.ts +38 -0
- package/src/runtime/local-actor-identity.ts +14 -0
- package/src/runtime/middleware/__tests__/rate-limiter.test.ts +22 -0
- package/src/runtime/middleware/rate-limiter.ts +30 -0
- package/src/runtime/middleware/twilio-validation.ts +5 -7
- package/src/runtime/migrations/__tests__/gcs-signed-url.test.ts +28 -0
- package/src/runtime/migrations/origin-mode.ts +6 -6
- package/src/runtime/pre-first-message-gate.ts +1 -0
- package/src/runtime/routes/__tests__/channel-verification-revoke.test.ts +6 -35
- package/src/runtime/routes/__tests__/consolidation-routes.test.ts +24 -3
- package/src/runtime/routes/__tests__/contact-routes.test.ts +80 -15
- package/src/runtime/routes/__tests__/conversation-list-routes.test.ts +7 -1
- package/src/runtime/routes/__tests__/global-search-routes.test.ts +0 -3
- package/src/runtime/routes/__tests__/home-feed-routes.test.ts +142 -1
- package/src/runtime/routes/__tests__/invite-relay-routes.test.ts +119 -30
- package/src/runtime/routes/__tests__/migration-import-allowed-hosts-env.test.ts +70 -0
- package/src/runtime/routes/__tests__/monitoring-routes.test.ts +194 -0
- package/src/runtime/routes/__tests__/plugins-routes.test.ts +755 -29
- package/src/runtime/routes/__tests__/retrospective-routes.test.ts +4 -0
- package/src/runtime/routes/__tests__/schedule-routes-create.test.ts +70 -0
- package/src/runtime/routes/__tests__/schedule-worker-routes.test.ts +161 -0
- package/src/runtime/routes/__tests__/surface-action-routes.test.ts +1 -1
- package/src/runtime/routes/__tests__/surface-content-routes.test.ts +1 -1
- package/src/runtime/routes/acp-routes.ts +15 -3
- package/src/runtime/routes/app-management-routes.ts +4 -7
- package/src/runtime/routes/approval-routes.ts +4 -0
- package/src/runtime/routes/attachment-routes.ts +54 -3
- package/src/runtime/routes/avatar-routes.ts +0 -4
- package/src/runtime/routes/background-tool-routes.ts +34 -5
- package/src/runtime/routes/btw-routes.ts +32 -4
- package/src/runtime/routes/channel-route-shared.ts +18 -14
- package/src/runtime/routes/channel-verification-routes.ts +0 -3
- package/src/runtime/routes/contact-routes.ts +298 -117
- package/src/runtime/routes/conversation-list-routes.ts +6 -0
- package/src/runtime/routes/conversation-management-routes.ts +74 -37
- package/src/runtime/routes/conversation-query-routes.ts +5 -2
- package/src/runtime/routes/conversation-routes.ts +222 -82
- package/src/runtime/routes/conversations-import-routes.ts +8 -1
- package/src/runtime/routes/credential-prompt-routes.ts +20 -5
- package/src/runtime/routes/debug-routes.ts +1 -0
- package/src/runtime/routes/documents-routes.ts +5 -2
- package/src/runtime/routes/empty-state-greeting-cache.ts +37 -10
- package/src/runtime/routes/global-search-routes.ts +2 -1
- package/src/runtime/routes/guardian-approval-interception.ts +51 -0
- package/src/runtime/routes/home-feed-routes.ts +60 -1
- package/src/runtime/routes/identity-routes.ts +4 -87
- package/src/runtime/routes/inbound-message-handler.ts +82 -41
- package/src/runtime/routes/inbound-stages/acl-enforcement.test.ts +430 -57
- package/src/runtime/routes/inbound-stages/acl-enforcement.ts +302 -572
- package/src/runtime/routes/inbound-stages/background-dispatch.test.ts +76 -270
- package/src/runtime/routes/inbound-stages/background-dispatch.ts +21 -116
- package/src/runtime/routes/inbound-stages/edit-intercept.ts +9 -1
- package/src/runtime/routes/inbound-stages/escalation-intercept.test.ts +158 -0
- package/src/runtime/routes/inbound-stages/escalation-intercept.ts +22 -1
- package/src/runtime/routes/index.ts +6 -0
- package/src/runtime/routes/inference-provider-connection-routes.ts +22 -16
- package/src/runtime/routes/internal-twilio-routes.ts +0 -15
- package/src/runtime/routes/messages-lexical-routes.ts +75 -0
- package/src/runtime/routes/migration-routes.ts +69 -6
- package/src/runtime/routes/monitoring-routes.ts +237 -0
- package/src/runtime/routes/plugins-routes.ts +329 -8
- package/src/runtime/routes/schedule-routes.ts +49 -8
- package/src/runtime/routes/schedule-worker-routes.ts +210 -0
- package/src/runtime/routes/secret-routes.ts +1 -1
- package/src/runtime/routes/surface-conversation-resolver.ts +1 -0
- package/src/runtime/services/__tests__/analyze-conversation.test.ts +54 -9
- package/src/runtime/services/__tests__/auto-analysis-enqueue.test.ts +30 -6
- package/src/runtime/services/__tests__/conversation-analyze-job.test.ts +43 -8
- package/src/runtime/services/__tests__/conversation-serializer.test.ts +20 -0
- package/src/runtime/services/analyze-conversation.ts +14 -4
- package/src/runtime/services/conversation-serializer.ts +5 -0
- package/src/runtime/slack-no-response.ts +47 -0
- package/src/runtime/slack-reply-session.test.ts +633 -0
- package/src/runtime/slack-reply-session.ts +382 -0
- package/src/runtime/slack-task-progress.ts +95 -0
- package/src/runtime/sync/resource-sync-events.ts +25 -0
- package/src/runtime/tool-grant-request-helper.ts +17 -1
- package/src/runtime/trust-class.test.ts +141 -0
- package/src/runtime/trust-class.ts +121 -0
- package/src/runtime/trust-verdict-consumer.ts +7 -6
- package/src/schedule/__tests__/run-script.test.ts +21 -0
- package/src/schedule/__tests__/worker-control.test.ts +241 -0
- package/src/schedule/run-script.ts +13 -6
- package/src/schedule/schedule-usage-store.ts +1 -0
- package/src/schedule/scheduler.ts +178 -127
- package/src/schedule/worker-control.ts +118 -0
- package/src/schedule/worker.ts +131 -0
- package/src/skills/__tests__/categories-cache.test.ts +38 -0
- package/src/skills/categories-cache.ts +40 -5
- package/src/skills/managed-store.ts +41 -6
- package/src/skills/validate-input.ts +47 -0
- package/src/stt/types.ts +5 -9
- package/src/subagent/manager.ts +267 -39
- package/src/subagent/types.ts +6 -2
- package/src/subagent/validate-allowlists.ts +65 -0
- package/src/telemetry/watchdog-direct-emit.test.ts +109 -0
- package/src/telemetry/watchdog-direct-emit.ts +89 -0
- package/src/tools/acp/list-agents.test.ts +0 -6
- package/src/tools/background-tool-registry.ts +61 -0
- package/src/tools/document/document-comment-tool.test.ts +4 -0
- package/src/tools/host-terminal/host-shell.test.ts +397 -0
- package/src/tools/host-terminal/host-shell.ts +203 -14
- package/src/tools/skills/find-similar-skills.test.ts +152 -1
- package/src/tools/skills/find-similar-skills.ts +30 -4
- package/src/tools/skills/load.ts +36 -0
- package/src/tools/skills/scaffold-managed.ts +66 -34
- package/src/tools/skills/skill-script-runner.ts +17 -0
- package/src/tools/skills/skill-tool-factory.ts +5 -1
- package/src/tools/terminal/safe-env.ts +3 -0
- package/src/tools/terminal/shell.test.ts +177 -0
- package/src/tools/terminal/shell.ts +98 -4
- package/src/tools/tool-approval-handler.ts +106 -29
- package/{node_modules/@vellumai/skill-host-contracts/src → src/tools}/tool-types.ts +16 -17
- package/src/tools/types.ts +29 -17
- package/src/tools/ui-surface/definitions.ts +3 -1
- package/src/tts/__tests__/provider-adapters.test.ts +37 -0
- package/src/tts/__tests__/provider-catalog.test.ts +21 -0
- package/src/tts/provider-catalog.ts +40 -9
- package/src/tts/providers/fish-audio-provider.ts +19 -10
- package/src/tts/types.ts +3 -4
- package/src/util/__tests__/process-tree.test.ts +10 -2
- package/src/util/__tests__/text-spacing.test.ts +53 -0
- package/src/util/cgroup-memory.ts +142 -0
- package/src/util/image-conversion.ts +281 -0
- package/src/util/phone.ts +1 -8
- package/src/util/platform.ts +33 -0
- package/src/util/process-tree.ts +10 -2
- package/src/util/text-spacing.ts +53 -0
- package/src/util/worker-process.ts +271 -0
- package/src/workflows/journal-store.ts +16 -1
- package/src/workflows/library.test.ts +35 -20
- package/src/workflows/library.ts +105 -66
- package/src/workspace/git-service.ts +1 -0
- package/src/workspace/migrations/011-backfill-installation-id.ts +83 -31
- package/src/workspace/migrations/041-backfill-google-gmail-settings-scope.ts +41 -22
- package/src/workspace/migrations/070-memory-v2-summary-schema-rebuild.ts +1 -1
- package/src/workspace/migrations/118-seed-now-md.ts +64 -0
- package/src/workspace/migrations/119-strip-persisted-memory-v3-tuning-defaults.ts +169 -0
- package/src/workspace/migrations/120-revise-onboarding-threads.ts +47 -0
- package/src/workspace/migrations/121-seed-default-user-guardrails.ts +82 -0
- package/src/workspace/migrations/122-relocate-default-user-boundary.ts +111 -0
- package/src/workspace/migrations/123-swap-quality-profile-to-fable.ts +85 -0
- package/src/workspace/migrations/__tests__/119-strip-persisted-memory-v3-tuning-defaults.test.ts +181 -0
- package/src/workspace/migrations/registry.ts +12 -0
- package/drizzle/0000_dizzy_maggott.sql +0 -301
- package/drizzle/meta/0000_snapshot.json +0 -1933
- package/drizzle/meta/_journal.json +0 -13
- package/node_modules/@vellumai/skill-host-contracts/__tests__/client.test.ts +0 -887
- package/node_modules/@vellumai/skill-host-contracts/bun.lock +0 -24
- package/node_modules/@vellumai/skill-host-contracts/package.json +0 -18
- package/node_modules/@vellumai/skill-host-contracts/src/assistant-event.ts +0 -97
- package/node_modules/@vellumai/skill-host-contracts/src/client.ts +0 -1349
- package/node_modules/@vellumai/skill-host-contracts/src/index.ts +0 -6
- package/node_modules/@vellumai/skill-host-contracts/src/runtime-mode.ts +0 -11
- package/node_modules/@vellumai/skill-host-contracts/src/server-message.ts +0 -32
- package/node_modules/@vellumai/skill-host-contracts/src/skill-host.ts +0 -333
- package/node_modules/@vellumai/skill-host-contracts/tsconfig.json +0 -20
- package/node_modules/@vellumai/skill-host-contracts/tsconfig.test.json +0 -12
- package/src/__tests__/invite-redemption-service.test.ts +0 -1180
- package/src/__tests__/invite-service-ipc.test.ts +0 -350
- package/src/__tests__/job-handler-registry-guard.test.ts +0 -125
- package/src/__tests__/regenerate-fire-and-forget-trace.test.ts +0 -203
- package/src/__tests__/relay-server.test.ts +0 -6153
- package/src/__tests__/telephony-stt-routing.test.ts +0 -329
- package/src/__tests__/voice-invite-redemption.test.ts +0 -702
- package/src/calls/relay-server.ts +0 -2463
- package/src/calls/telephony-stt-routing.ts +0 -145
- package/src/contacts/__tests__/contacts-write-revoke-relay.test.ts +0 -128
- package/src/daemon/__tests__/daemon-skill-host.test.ts +0 -273
- package/src/daemon/daemon-skill-host.ts +0 -262
- package/src/daemon/message-types/meet.ts +0 -143
- package/src/daemon/shutdown-registry.ts +0 -40
- package/src/ipc/__tests__/skill-server-bidirectional.test.ts +0 -253
- package/src/ipc/__tests__/skill-server.test.ts +0 -182
- package/src/ipc/skill-ipc-types.ts +0 -54
- package/src/ipc/skill-routes/__tests__/config.test.ts +0 -146
- package/src/ipc/skill-routes/__tests__/events-ipc.test.ts +0 -448
- package/src/ipc/skill-routes/__tests__/identity.test.ts +0 -62
- package/src/ipc/skill-routes/__tests__/log.test.ts +0 -133
- package/src/ipc/skill-routes/__tests__/memory.test.ts +0 -203
- package/src/ipc/skill-routes/__tests__/platform.test.ts +0 -111
- package/src/ipc/skill-routes/__tests__/providers.test.ts +0 -265
- package/src/ipc/skill-routes/__tests__/registries.test.ts +0 -400
- package/src/ipc/skill-routes/config.ts +0 -47
- package/src/ipc/skill-routes/events.ts +0 -147
- package/src/ipc/skill-routes/identity.ts +0 -21
- package/src/ipc/skill-routes/index.ts +0 -37
- package/src/ipc/skill-routes/log.ts +0 -40
- package/src/ipc/skill-routes/memory.ts +0 -92
- package/src/ipc/skill-routes/platform.ts +0 -39
- package/src/ipc/skill-routes/providers.ts +0 -162
- package/src/ipc/skill-routes/registries.ts +0 -338
- package/src/ipc/skill-server.ts +0 -831
- package/src/ipc/skill-socket-path.ts +0 -20
- package/src/jobs/register-job-handlers.ts +0 -74
- package/src/persistence/invite-store.ts +0 -481
- package/src/plugins/job-handler-registry.ts +0 -94
- package/src/providers/cache-control.ts +0 -26
- package/src/runtime/__tests__/runtime-mode.test.ts +0 -62
- package/src/runtime/invite-redemption-service.ts +0 -828
- package/src/runtime/invite-redemption-templates.ts +0 -46
- package/src/runtime/runtime-mode.ts +0 -40
- package/src/runtime/slack-dm-text-delivery.ts +0 -177
- package/src/util/voice-code.ts +0 -31
|
@@ -5,12 +5,19 @@ import { stopCes } from "../credential-execution/ces-runtime.js";
|
|
|
5
5
|
import { stopHeartbeatService } from "../heartbeat/heartbeat-service.js";
|
|
6
6
|
import { stopCliIpcServer } from "../ipc/assistant-server.js";
|
|
7
7
|
import { stopGatewayFlagListener } from "../ipc/gateway-flag-listener.js";
|
|
8
|
-
import { stopSkillIpcServer } from "../ipc/skill-server.js";
|
|
9
8
|
import { stopMcpServerManager } from "../mcp/manager.js";
|
|
10
|
-
import {
|
|
9
|
+
import { stopMonitoring } from "../monitoring/control.js";
|
|
10
|
+
import {
|
|
11
|
+
runAsyncSqlite,
|
|
12
|
+
spawnDetachedWalCheckpoint,
|
|
13
|
+
} from "../persistence/db-async-query.js";
|
|
14
|
+
import { getSqlite, isDbOpen, resetDb } from "../persistence/db-connection.js";
|
|
11
15
|
import { stopQdrantManager } from "../persistence/embeddings/qdrant-manager.js";
|
|
12
16
|
import { stopMemoryJobsWorker } from "../persistence/jobs-worker.js";
|
|
13
17
|
import { stopMemoryWorkerProcess } from "../persistence/worker-control.js";
|
|
18
|
+
import { stopConsentRefresh } from "../platform/consent-cache.js";
|
|
19
|
+
import { HOOKS } from "../plugin-api/constants.js";
|
|
20
|
+
import { runHook } from "../plugins/pipeline.js";
|
|
14
21
|
import { stopRuntimeHttpServer } from "../runtime/http-server.js";
|
|
15
22
|
import { stopScheduler } from "../schedule/scheduler.js";
|
|
16
23
|
import { getSubagentManager } from "../subagent/index.js";
|
|
@@ -18,6 +25,7 @@ import { stopUsageTelemetryReporter } from "../telemetry/usage-telemetry-reporte
|
|
|
18
25
|
import { browserManager } from "../tools/browser/browser-manager.js";
|
|
19
26
|
import { cleanupShellOutputTempFiles } from "../tools/shared/shell-output.js";
|
|
20
27
|
import { getLogger } from "../util/logger.js";
|
|
28
|
+
import { APP_VERSION } from "../version.js";
|
|
21
29
|
import { getEnrichmentService } from "../workspace/commit-message-enrichment-service.js";
|
|
22
30
|
import {
|
|
23
31
|
commitAllPendingWorkspaceChanges,
|
|
@@ -27,11 +35,11 @@ import { stopAppSourceWatcher } from "./app-source-watcher.js";
|
|
|
27
35
|
import { stopConfigWatcher } from "./config-watcher.js";
|
|
28
36
|
import { stopConversationEvictor } from "./conversation-evictor.js";
|
|
29
37
|
import { stopConversations } from "./conversation-store.js";
|
|
30
|
-
import { cleanupPidFile } from "./daemon-control.js";
|
|
38
|
+
import { cleanupPidFile, cleanupPidFileIfOwner } from "./daemon-control.js";
|
|
39
|
+
import { isStartupComplete } from "./daemon-readiness.js";
|
|
31
40
|
import { stopEventLoopWatchdog } from "./event-loop-watchdog.js";
|
|
32
41
|
import { stopDiskPressureGuardForLifecycle } from "./lifecycle.js";
|
|
33
42
|
import { stopOrphanReaper } from "./orphan-reaper.js";
|
|
34
|
-
import { runShutdownHooks } from "./shutdown-registry.js";
|
|
35
43
|
|
|
36
44
|
const log = getLogger("lifecycle");
|
|
37
45
|
|
|
@@ -71,6 +79,16 @@ async function shutdown(): Promise<void> {
|
|
|
71
79
|
// bump only changes behavior for the stuck-shutdown path.
|
|
72
80
|
const forceTimer = setTimeout(() => {
|
|
73
81
|
log.warn("Graceful shutdown timed out, forcing exit");
|
|
82
|
+
// A stuck shutdown may never reach the graceful WAL checkpoint below —
|
|
83
|
+
// fold the WAL from a detached subprocess that survives this exit, so
|
|
84
|
+
// the next boot opens a small WAL instead of paying a multi-minute
|
|
85
|
+
// recovery. Skipped when the DB was never opened: there is nothing to
|
|
86
|
+
// fold, and sqlite3 would create an empty DB file.
|
|
87
|
+
if (isDbOpen() && !spawnDetachedWalCheckpoint()) {
|
|
88
|
+
log.warn(
|
|
89
|
+
"No sqlite3 CLI on host — WAL left at high-water mark on force-exit",
|
|
90
|
+
);
|
|
91
|
+
}
|
|
74
92
|
stopBackgroundServicesAndCleanupPidFile();
|
|
75
93
|
process.exit(1);
|
|
76
94
|
}, 20_000);
|
|
@@ -79,13 +97,21 @@ async function shutdown(): Promise<void> {
|
|
|
79
97
|
await stopWorkspaceHeartbeatService();
|
|
80
98
|
await stopHeartbeatService();
|
|
81
99
|
|
|
82
|
-
//
|
|
83
|
-
|
|
84
|
-
|
|
100
|
+
// Stop the periodic consent-cache refresh (a daemon-owned interval).
|
|
101
|
+
await stopConsentRefresh();
|
|
102
|
+
|
|
103
|
+
// Fire plugin / user / workspace / skill `shutdown` hooks through the unified
|
|
104
|
+
// hook pipeline — the same dispatch path every other lifecycle hook uses —
|
|
105
|
+
// before stopping the server so any teardown work still has live transports.
|
|
106
|
+
// We don't unregister tool/route surfaces here: the daemon is exiting, so that
|
|
107
|
+
// in-memory registry state is discarded with the process anyway.
|
|
85
108
|
try {
|
|
86
|
-
await
|
|
109
|
+
await runHook(HOOKS.SHUTDOWN, {
|
|
110
|
+
assistantVersion: APP_VERSION,
|
|
111
|
+
reason: "shutdown",
|
|
112
|
+
});
|
|
87
113
|
} catch (err) {
|
|
88
|
-
log.warn({ err }, "
|
|
114
|
+
log.warn({ err }, "Plugin shutdown hooks failed (non-fatal)");
|
|
89
115
|
}
|
|
90
116
|
|
|
91
117
|
// Commit any uncommitted workspace changes before stopping the server.
|
|
@@ -104,7 +130,6 @@ async function shutdown(): Promise<void> {
|
|
|
104
130
|
stopConfigWatcher();
|
|
105
131
|
stopAppSourceWatcher();
|
|
106
132
|
stopCliIpcServer();
|
|
107
|
-
stopSkillIpcServer();
|
|
108
133
|
stopConversations();
|
|
109
134
|
await stopCes();
|
|
110
135
|
|
|
@@ -160,6 +185,9 @@ async function shutdown(): Promise<void> {
|
|
|
160
185
|
log.warn({ err }, "Failed to stop memory worker process (non-fatal)");
|
|
161
186
|
}
|
|
162
187
|
|
|
188
|
+
// Stop the resource monitor process if it's actually running.
|
|
189
|
+
stopMonitoring();
|
|
190
|
+
|
|
163
191
|
try {
|
|
164
192
|
await stopMcpServerManager();
|
|
165
193
|
} catch (err) {
|
|
@@ -171,21 +199,51 @@ async function shutdown(): Promise<void> {
|
|
|
171
199
|
// Optimize query planner statistics before closing so they persist for
|
|
172
200
|
// the next session. Checkpoint WAL and close SQLite so no writes are
|
|
173
201
|
// lost on exit. Each step is in its own try block so later steps still
|
|
174
|
-
// run if an earlier one throws (e.g. SQLITE_BUSY).
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
202
|
+
// run if an earlier one throws (e.g. SQLITE_BUSY). Skipped entirely when
|
|
203
|
+
// the DB was never opened: there is nothing to persist, fold, or close,
|
|
204
|
+
// and the lazy `getSqlite()` accessor would open the database just to
|
|
205
|
+
// tear it down.
|
|
206
|
+
if (isDbOpen()) {
|
|
207
|
+
try {
|
|
208
|
+
getSqlite().exec("PRAGMA optimize");
|
|
209
|
+
} catch (err) {
|
|
210
|
+
log.warn({ err }, "PRAGMA optimize at shutdown failed (non-fatal)");
|
|
211
|
+
}
|
|
212
|
+
// Fold the WAL back into the main database so the next boot opens a
|
|
213
|
+
// small WAL instead of paying a multi-minute recovery (see
|
|
214
|
+
// `checkpointWalBeforeOpen` in db-init.ts). Runs through `runAsyncSqlite`
|
|
215
|
+
// (sqlite3 subprocess when available) because a synchronous checkpoint
|
|
216
|
+
// of a WAL at its high-water mark blocks the event loop, which keeps the
|
|
217
|
+
// force-exit timer above from ever firing. Off the loop, the timer stays
|
|
218
|
+
// armed — and if it fires mid-checkpoint, the subprocess survives
|
|
219
|
+
// `process.exit` and finishes the fold in the background.
|
|
220
|
+
try {
|
|
221
|
+
const checkpointResult = await runAsyncSqlite(
|
|
222
|
+
"PRAGMA wal_checkpoint(TRUNCATE)",
|
|
223
|
+
"shutdown:wal-checkpoint-truncate",
|
|
224
|
+
);
|
|
225
|
+
if (checkpointResult.ok) {
|
|
226
|
+
log.info(
|
|
227
|
+
{
|
|
228
|
+
backend: checkpointResult.backend,
|
|
229
|
+
elapsedMs: checkpointResult.elapsedMs,
|
|
230
|
+
},
|
|
231
|
+
"Shutdown WAL checkpoint complete",
|
|
232
|
+
);
|
|
233
|
+
} else {
|
|
234
|
+
log.warn(
|
|
235
|
+
{ error: checkpointResult.error, backend: checkpointResult.backend },
|
|
236
|
+
"WAL checkpoint failed (non-fatal)",
|
|
237
|
+
);
|
|
238
|
+
}
|
|
239
|
+
} catch (err) {
|
|
240
|
+
log.warn({ err }, "WAL checkpoint failed (non-fatal)");
|
|
241
|
+
}
|
|
242
|
+
try {
|
|
243
|
+
resetDb();
|
|
244
|
+
} catch (err) {
|
|
245
|
+
log.warn({ err }, "Database close failed (non-fatal)");
|
|
246
|
+
}
|
|
189
247
|
}
|
|
190
248
|
|
|
191
249
|
await Sentry.flush(2000);
|
|
@@ -194,45 +252,79 @@ async function shutdown(): Promise<void> {
|
|
|
194
252
|
process.exit(exitCode);
|
|
195
253
|
}
|
|
196
254
|
|
|
255
|
+
/**
|
|
256
|
+
* Minimal exit for signals and fatal errors that land before startup
|
|
257
|
+
* completes. The graceful `shutdown()` path assumes started subsystems and
|
|
258
|
+
* would interleave its teardown with the still-running startup sequence, so
|
|
259
|
+
* this path does only the work that matters mid-boot: fold the WAL when the
|
|
260
|
+
* DB is already open (detached, so the fold survives the exit) and remove
|
|
261
|
+
* the PID file when this process wrote it — ownership-checked so a duplicate
|
|
262
|
+
* daemon exiting early never deletes the live daemon's PID file.
|
|
263
|
+
*/
|
|
264
|
+
function exitDuringStartup(code: number): void {
|
|
265
|
+
if (isDbOpen()) {
|
|
266
|
+
spawnDetachedWalCheckpoint();
|
|
267
|
+
}
|
|
268
|
+
cleanupPidFileIfOwner(process.pid);
|
|
269
|
+
process.exit(code);
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
function handleShutdownSignal(signal: string, message: string): void {
|
|
273
|
+
log.warn({ signal, pid: process.pid, uptime: process.uptime() }, message);
|
|
274
|
+
if (!isStartupComplete()) {
|
|
275
|
+
log.warn(
|
|
276
|
+
{ signal },
|
|
277
|
+
"Signal arrived before startup completed — exiting without graceful shutdown",
|
|
278
|
+
);
|
|
279
|
+
exitDuringStartup(0);
|
|
280
|
+
return;
|
|
281
|
+
}
|
|
282
|
+
void shutdown();
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
function handleFatalError(err: unknown, message: string): void {
|
|
286
|
+
log.error({ err }, message);
|
|
287
|
+
Sentry.captureException(err);
|
|
288
|
+
exitCode = 1;
|
|
289
|
+
if (!isStartupComplete()) {
|
|
290
|
+
exitDuringStartup(1);
|
|
291
|
+
return;
|
|
292
|
+
}
|
|
293
|
+
void shutdown();
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
/**
|
|
297
|
+
* Install signal and fatal-error handlers. Runs before any blocking startup
|
|
298
|
+
* work — a boot that inherits a large WAL can spend minutes in DB init, and
|
|
299
|
+
* without handlers a SIGTERM in that window is the default hard kill (no WAL
|
|
300
|
+
* fold, no PID cleanup). Handlers stay in the minimal `exitDuringStartup`
|
|
301
|
+
* mode until `setStartupComplete()` marks the daemon ready; from then on
|
|
302
|
+
* signals run the full graceful `shutdown()`.
|
|
303
|
+
*/
|
|
197
304
|
export function installShutdownHandlers(): void {
|
|
198
305
|
process.on("SIGTERM", () => {
|
|
199
|
-
|
|
200
|
-
|
|
306
|
+
handleShutdownSignal(
|
|
307
|
+
"SIGTERM",
|
|
201
308
|
"Received SIGTERM — process termination requested",
|
|
202
309
|
);
|
|
203
|
-
void shutdown();
|
|
204
310
|
});
|
|
205
311
|
|
|
206
312
|
process.on("SIGINT", () => {
|
|
207
|
-
|
|
208
|
-
{ signal: "SIGINT", pid: process.pid, uptime: process.uptime() },
|
|
209
|
-
"Received SIGINT — user interrupt",
|
|
210
|
-
);
|
|
211
|
-
void shutdown();
|
|
313
|
+
handleShutdownSignal("SIGINT", "Received SIGINT — user interrupt");
|
|
212
314
|
});
|
|
213
315
|
|
|
214
316
|
process.on("SIGHUP", () => {
|
|
215
|
-
|
|
216
|
-
{ signal: "SIGHUP", pid: process.pid, uptime: process.uptime() },
|
|
217
|
-
"Received SIGHUP — terminal hangup",
|
|
218
|
-
);
|
|
219
|
-
void shutdown();
|
|
317
|
+
handleShutdownSignal("SIGHUP", "Received SIGHUP — terminal hangup");
|
|
220
318
|
});
|
|
221
319
|
|
|
222
320
|
process.on("unhandledRejection", (reason) => {
|
|
223
|
-
|
|
224
|
-
|
|
321
|
+
handleFatalError(
|
|
322
|
+
reason,
|
|
225
323
|
"Unhandled promise rejection — initiating shutdown",
|
|
226
324
|
);
|
|
227
|
-
Sentry.captureException(reason);
|
|
228
|
-
exitCode = 1;
|
|
229
|
-
void shutdown();
|
|
230
325
|
});
|
|
231
326
|
|
|
232
327
|
process.on("uncaughtException", (err) => {
|
|
233
|
-
|
|
234
|
-
Sentry.captureException(err);
|
|
235
|
-
exitCode = 1;
|
|
236
|
-
void shutdown();
|
|
328
|
+
handleFatalError(err, "Uncaught exception — initiating shutdown");
|
|
237
329
|
});
|
|
238
330
|
}
|
|
@@ -4,11 +4,11 @@ import {
|
|
|
4
4
|
seedSkillGraphNodes,
|
|
5
5
|
seedUninstalledCatalogSkillMemories,
|
|
6
6
|
} from "../plugins/defaults/memory/graph/capability-seed.js";
|
|
7
|
-
import { getLogger } from "../util/logger.js";
|
|
8
7
|
import {
|
|
9
8
|
maybeSeedMemoryV2CliCommands,
|
|
10
9
|
maybeSeedMemoryV2Skills,
|
|
11
|
-
} from "
|
|
10
|
+
} from "../plugins/defaults/memory/v2/memory-v2-startup.js";
|
|
11
|
+
import { getLogger } from "../util/logger.js";
|
|
12
12
|
|
|
13
13
|
const log = getLogger("skill-memory-refresh");
|
|
14
14
|
|
|
@@ -0,0 +1,217 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tests for the SQLite corruption watchdog.
|
|
3
|
+
*
|
|
4
|
+
* The watchdog turns a `SQLITE_CORRUPT` / `SQLITE_NOTADB` error thrown by any
|
|
5
|
+
* statement into a direct `sqlite_corrupted` telemetry emit (bypassing the
|
|
6
|
+
* SQLite watchdog buffer). It must ignore non-corruption errors, debounce per
|
|
7
|
+
* database, and — wired straight into the slow-query wrapper — fire the moment
|
|
8
|
+
* a wrapped connection hits corruption. The direct emit itself (opt-out gate,
|
|
9
|
+
* POST payload) is covered in `../telemetry/watchdog-direct-emit.test.ts`.
|
|
10
|
+
*/
|
|
11
|
+
import { mkdtempSync, writeFileSync } from "node:fs";
|
|
12
|
+
import { tmpdir } from "node:os";
|
|
13
|
+
import { join } from "node:path";
|
|
14
|
+
import { Database } from "bun:sqlite";
|
|
15
|
+
import { beforeEach, describe, expect, mock, test } from "bun:test";
|
|
16
|
+
|
|
17
|
+
// Silence the logger.
|
|
18
|
+
mock.module("../util/logger.js", () => ({
|
|
19
|
+
getLogger: () =>
|
|
20
|
+
new Proxy({} as Record<string, unknown>, { get: () => () => {} }),
|
|
21
|
+
}));
|
|
22
|
+
|
|
23
|
+
// Sentry is a side-effecting no-op in tests.
|
|
24
|
+
mock.module("@sentry/node", () => ({
|
|
25
|
+
withScope: (fn: (scope: unknown) => void) =>
|
|
26
|
+
fn({ setLevel() {}, setTag() {}, setContext() {} }),
|
|
27
|
+
captureMessage: () => {},
|
|
28
|
+
}));
|
|
29
|
+
|
|
30
|
+
// Capture direct emits instead of POSTing them.
|
|
31
|
+
const emitCalls: Array<{ checkName: string; detail: Record<string, unknown> }> =
|
|
32
|
+
[];
|
|
33
|
+
mock.module("../telemetry/watchdog-direct-emit.js", () => ({
|
|
34
|
+
emitWatchdogEventDirect: (
|
|
35
|
+
checkName: string,
|
|
36
|
+
detail: Record<string, unknown>,
|
|
37
|
+
) => {
|
|
38
|
+
emitCalls.push({ checkName, detail });
|
|
39
|
+
return Promise.resolve();
|
|
40
|
+
},
|
|
41
|
+
}));
|
|
42
|
+
|
|
43
|
+
import { wrapSqliteForSlowQueryLogging } from "../persistence/slow-query-log.js";
|
|
44
|
+
import {
|
|
45
|
+
flushCorruptionEmitsForTesting,
|
|
46
|
+
isSqliteCorruptionError,
|
|
47
|
+
observeSqliteStatementError,
|
|
48
|
+
resetSqliteCorruptionWatchdogForTesting,
|
|
49
|
+
SQLITE_CORRUPTED_CHECK_NAME,
|
|
50
|
+
} from "./sqlite-corruption-watchdog.js";
|
|
51
|
+
|
|
52
|
+
/** A synthetic `bun:sqlite`-style error carrying a `code`. */
|
|
53
|
+
function sqliteError(code: string, message: string): Error {
|
|
54
|
+
return Object.assign(new Error(message), { code });
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
describe("isSqliteCorruptionError", () => {
|
|
58
|
+
test("matches the SQLITE_CORRUPT / SQLITE_NOTADB families by code", () => {
|
|
59
|
+
expect(
|
|
60
|
+
isSqliteCorruptionError(
|
|
61
|
+
sqliteError("SQLITE_CORRUPT", "database disk image is malformed"),
|
|
62
|
+
),
|
|
63
|
+
).toBe(true);
|
|
64
|
+
expect(
|
|
65
|
+
isSqliteCorruptionError(
|
|
66
|
+
sqliteError("SQLITE_CORRUPT_VTAB", "corrupt virtual table"),
|
|
67
|
+
),
|
|
68
|
+
).toBe(true);
|
|
69
|
+
expect(
|
|
70
|
+
isSqliteCorruptionError(
|
|
71
|
+
sqliteError("SQLITE_NOTADB", "file is not a database"),
|
|
72
|
+
),
|
|
73
|
+
).toBe(true);
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
test("matches the canonical corruption messages even without a code", () => {
|
|
77
|
+
expect(
|
|
78
|
+
isSqliteCorruptionError(new Error("database disk image is malformed")),
|
|
79
|
+
).toBe(true);
|
|
80
|
+
expect(isSqliteCorruptionError(new Error("file is not a database"))).toBe(
|
|
81
|
+
true,
|
|
82
|
+
);
|
|
83
|
+
});
|
|
84
|
+
|
|
85
|
+
test("does not match transient contention or unrelated errors", () => {
|
|
86
|
+
expect(
|
|
87
|
+
isSqliteCorruptionError(sqliteError("SQLITE_BUSY", "database is locked")),
|
|
88
|
+
).toBe(false);
|
|
89
|
+
expect(
|
|
90
|
+
isSqliteCorruptionError(sqliteError("SQLITE_IOERR", "disk I/O error")),
|
|
91
|
+
).toBe(false);
|
|
92
|
+
expect(
|
|
93
|
+
isSqliteCorruptionError(
|
|
94
|
+
sqliteError("SQLITE_CONSTRAINT", "UNIQUE constraint failed"),
|
|
95
|
+
),
|
|
96
|
+
).toBe(false);
|
|
97
|
+
expect(isSqliteCorruptionError(new Error("no such table: foo"))).toBe(
|
|
98
|
+
false,
|
|
99
|
+
);
|
|
100
|
+
});
|
|
101
|
+
});
|
|
102
|
+
|
|
103
|
+
describe("observeSqliteStatementError", () => {
|
|
104
|
+
beforeEach(() => {
|
|
105
|
+
emitCalls.length = 0;
|
|
106
|
+
resetSqliteCorruptionWatchdogForTesting();
|
|
107
|
+
});
|
|
108
|
+
|
|
109
|
+
test("a corruption error emits sqlite_corrupted with detail", async () => {
|
|
110
|
+
observeSqliteStatementError(
|
|
111
|
+
sqliteError("SQLITE_CORRUPT", "database disk image is malformed"),
|
|
112
|
+
{
|
|
113
|
+
sql: "SELECT * FROM messages WHERE id = ?",
|
|
114
|
+
database: "main",
|
|
115
|
+
label: "load-history",
|
|
116
|
+
},
|
|
117
|
+
);
|
|
118
|
+
await flushCorruptionEmitsForTesting();
|
|
119
|
+
|
|
120
|
+
expect(emitCalls).toHaveLength(1);
|
|
121
|
+
expect(emitCalls[0].checkName).toBe(SQLITE_CORRUPTED_CHECK_NAME);
|
|
122
|
+
expect(emitCalls[0].checkName).toBe("sqlite_corrupted");
|
|
123
|
+
expect(emitCalls[0].detail).toMatchObject({
|
|
124
|
+
database: "main",
|
|
125
|
+
error: "database disk image is malformed",
|
|
126
|
+
sql: "SELECT * FROM messages WHERE id = ?",
|
|
127
|
+
label: "load-history",
|
|
128
|
+
});
|
|
129
|
+
});
|
|
130
|
+
|
|
131
|
+
test('falls back to "unknown" when the connection carried no database tag', async () => {
|
|
132
|
+
observeSqliteStatementError(new Error("file is not a database"), {
|
|
133
|
+
sql: "SELECT 1",
|
|
134
|
+
});
|
|
135
|
+
await flushCorruptionEmitsForTesting();
|
|
136
|
+
|
|
137
|
+
expect(emitCalls).toHaveLength(1);
|
|
138
|
+
expect(emitCalls[0].detail.database).toBe("unknown");
|
|
139
|
+
});
|
|
140
|
+
|
|
141
|
+
test("a transient / unrelated error emits nothing", async () => {
|
|
142
|
+
observeSqliteStatementError(sqliteError("SQLITE_BUSY", "locked"), {
|
|
143
|
+
sql: "INSERT ...",
|
|
144
|
+
database: "main",
|
|
145
|
+
});
|
|
146
|
+
observeSqliteStatementError(
|
|
147
|
+
sqliteError("SQLITE_CONSTRAINT", "UNIQUE constraint failed"),
|
|
148
|
+
{ sql: "INSERT ...", database: "main" },
|
|
149
|
+
);
|
|
150
|
+
observeSqliteStatementError(new Error("no such table: foo"), {
|
|
151
|
+
sql: "SELECT ...",
|
|
152
|
+
database: "main",
|
|
153
|
+
});
|
|
154
|
+
await flushCorruptionEmitsForTesting();
|
|
155
|
+
|
|
156
|
+
expect(emitCalls).toHaveLength(0);
|
|
157
|
+
});
|
|
158
|
+
|
|
159
|
+
test("debounces repeated corruption on the same database", async () => {
|
|
160
|
+
const err = sqliteError(
|
|
161
|
+
"SQLITE_CORRUPT",
|
|
162
|
+
"database disk image is malformed",
|
|
163
|
+
);
|
|
164
|
+
observeSqliteStatementError(err, { sql: "SELECT 1", database: "main" });
|
|
165
|
+
observeSqliteStatementError(err, { sql: "SELECT 2", database: "main" });
|
|
166
|
+
observeSqliteStatementError(err, { sql: "SELECT 3", database: "main" });
|
|
167
|
+
await flushCorruptionEmitsForTesting();
|
|
168
|
+
// One report for `main` within the cooldown window...
|
|
169
|
+
expect(emitCalls).toHaveLength(1);
|
|
170
|
+
|
|
171
|
+
// ...but a distinct database is still free to report.
|
|
172
|
+
observeSqliteStatementError(err, { sql: "SELECT 1", database: "memory" });
|
|
173
|
+
await flushCorruptionEmitsForTesting();
|
|
174
|
+
expect(emitCalls).toHaveLength(2);
|
|
175
|
+
});
|
|
176
|
+
});
|
|
177
|
+
|
|
178
|
+
describe("wired into the slow-query wrapper", () => {
|
|
179
|
+
beforeEach(() => {
|
|
180
|
+
emitCalls.length = 0;
|
|
181
|
+
resetSqliteCorruptionWatchdogForTesting();
|
|
182
|
+
});
|
|
183
|
+
|
|
184
|
+
test("a wrapped connection hitting a corrupt-header file emits, and the error still propagates", async () => {
|
|
185
|
+
// A garbage file throws SQLITE_NOTADB while `.query()` compiles the SQL —
|
|
186
|
+
// the wrapper's create-time seam surfaces it straight to the watchdog, and
|
|
187
|
+
// names the file from the connection's own `filename` (no key plumbing).
|
|
188
|
+
const dir = mkdtempSync(join(tmpdir(), "sqlite-corruption-wd-"));
|
|
189
|
+
const garbagePath = join(dir, "not-a.db");
|
|
190
|
+
writeFileSync(
|
|
191
|
+
garbagePath,
|
|
192
|
+
Buffer.from("this is definitely not a sqlite db"),
|
|
193
|
+
);
|
|
194
|
+
|
|
195
|
+
const db = new Database(garbagePath);
|
|
196
|
+
wrapSqliteForSlowQueryLogging(db);
|
|
197
|
+
|
|
198
|
+
// The original SQLite error must still propagate unchanged.
|
|
199
|
+
expect(() => db.query("SELECT name FROM sqlite_master").all()).toThrow();
|
|
200
|
+
await flushCorruptionEmitsForTesting();
|
|
201
|
+
|
|
202
|
+
expect(emitCalls).toHaveLength(1);
|
|
203
|
+
expect(emitCalls[0].checkName).toBe("sqlite_corrupted");
|
|
204
|
+
expect(emitCalls[0].detail.database).toBe("not-a.db");
|
|
205
|
+
});
|
|
206
|
+
|
|
207
|
+
test("a wrapped connection running healthy queries emits nothing", async () => {
|
|
208
|
+
const db = new Database(":memory:");
|
|
209
|
+
wrapSqliteForSlowQueryLogging(db);
|
|
210
|
+
db.exec("CREATE TABLE t (id INTEGER PRIMARY KEY)");
|
|
211
|
+
db.query("INSERT INTO t (id) VALUES (1)").run();
|
|
212
|
+
db.query("SELECT * FROM t").all();
|
|
213
|
+
await flushCorruptionEmitsForTesting();
|
|
214
|
+
|
|
215
|
+
expect(emitCalls).toHaveLength(0);
|
|
216
|
+
});
|
|
217
|
+
});
|
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SQLite corruption watchdog.
|
|
3
|
+
*
|
|
4
|
+
* The daemon keeps all of its state — conversations, schedules, memory,
|
|
5
|
+
* telemetry — in `bun:sqlite` files. When one of those files is damaged (a
|
|
6
|
+
* torn write, a truncated file, bad disk media) SQLite surfaces it as a
|
|
7
|
+
* `SQLITE_CORRUPT` / `SQLITE_NOTADB` error ("database disk image is malformed"
|
|
8
|
+
* / "file is not a database") on the next statement that touches the damaged
|
|
9
|
+
* page. Left unobserved, that damage is only noticed when a user hits a broken
|
|
10
|
+
* feature; the platform has no fleet-wide view of how often it happens.
|
|
11
|
+
*
|
|
12
|
+
* This watchdog makes corruption observable. It emits a `watchdog` telemetry
|
|
13
|
+
* event with `check_name = "sqlite_corrupted"` — the same stream the event-loop
|
|
14
|
+
* watchdog uses — but POSTs it *directly* to the platform ingest rather than
|
|
15
|
+
* through the SQLite-backed watchdog buffer: a check that fires because SQLite
|
|
16
|
+
* is unusable must not depend on writing to SQLite, and going direct keeps this
|
|
17
|
+
* module out of the `db-connection` import graph. The direct path still honors
|
|
18
|
+
* the `share_analytics` opt-out (see {@link emitWatchdogEventDirect}). The
|
|
19
|
+
* platform's already-merged `watchdog__sqlite_corruption_daily` admin query
|
|
20
|
+
* filters `check_name` to this exact string, so it is the cross-repo contract
|
|
21
|
+
* and must stay stable.
|
|
22
|
+
*
|
|
23
|
+
* Detection is per-statement: the shared slow-query wrapper — which already
|
|
24
|
+
* wraps every `bun:sqlite` connection (main, logs, memory, telemetry — Drizzle
|
|
25
|
+
* and raw) — hands every failed statement to {@link observeSqliteStatementError}.
|
|
26
|
+
* So corruption is caught on *any* failing query or write, read or write, the
|
|
27
|
+
* moment the workload actually hits the damaged page — no dedicated scan
|
|
28
|
+
* needed. Non-corruption errors (constraint violations, syntax errors,
|
|
29
|
+
* transient `SQLITE_BUSY`) are ignored.
|
|
30
|
+
*
|
|
31
|
+
* Reports are debounced per-database (a corrupt file throws on every
|
|
32
|
+
* subsequent statement) — see {@link REPORT_COOLDOWN_MS}.
|
|
33
|
+
*/
|
|
34
|
+
|
|
35
|
+
import * as Sentry from "@sentry/node";
|
|
36
|
+
|
|
37
|
+
import type { StatementErrorContext } from "../persistence/slow-query-log.js";
|
|
38
|
+
import { getLogger } from "../util/logger.js";
|
|
39
|
+
|
|
40
|
+
const log = getLogger("sqlite-corruption-watchdog");
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Check name emitted for SQLite corruption events. The platform's
|
|
44
|
+
* `watchdog__sqlite_corruption_daily` admin query filters `check_name` to
|
|
45
|
+
* this exact string — it is the cross-repo contract, keep it stable.
|
|
46
|
+
*/
|
|
47
|
+
export const SQLITE_CORRUPTED_CHECK_NAME = "sqlite_corrupted";
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* Minimum spacing between reports for a single database. Corruption is sticky:
|
|
51
|
+
* once a file is malformed every subsequent statement against it throws the
|
|
52
|
+
* same way, so without a cooldown a single damaged DB hit in a tight loop
|
|
53
|
+
* would emit a flood of identical events. Keyed per database so damage to one
|
|
54
|
+
* file never suppresses the first report for another.
|
|
55
|
+
*/
|
|
56
|
+
const REPORT_COOLDOWN_MS = 60_000;
|
|
57
|
+
|
|
58
|
+
const lastReportAtByDatabase = new Map<string, number>();
|
|
59
|
+
|
|
60
|
+
/** The most recent in-flight direct emit, so tests can await it. */
|
|
61
|
+
let pendingEmit: Promise<unknown> = Promise.resolve();
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* Whether an error is SQLite reporting structural corruption — the
|
|
65
|
+
* `SQLITE_CORRUPT` / `SQLITE_NOTADB` families, by extended result code or by
|
|
66
|
+
* the canonical message text ("database disk image is malformed" / "file is
|
|
67
|
+
* not a database"). Deliberately distinct from `isRetryableSqliteError`: a
|
|
68
|
+
* corrupt image is permanent, not transient contention, so retrying can never
|
|
69
|
+
* help. Pure, so callers (and tests) can classify a synthesized error without
|
|
70
|
+
* a real database.
|
|
71
|
+
*/
|
|
72
|
+
export function isSqliteCorruptionError(err: unknown): boolean {
|
|
73
|
+
const code = (err as { code?: string } | null)?.code ?? "";
|
|
74
|
+
if (code.startsWith("SQLITE_CORRUPT") || code.startsWith("SQLITE_NOTADB")) {
|
|
75
|
+
return true;
|
|
76
|
+
}
|
|
77
|
+
const message = (
|
|
78
|
+
err instanceof Error ? err.message : String(err)
|
|
79
|
+
).toLowerCase();
|
|
80
|
+
return (
|
|
81
|
+
message.includes("database disk image is malformed") ||
|
|
82
|
+
message.includes("file is not a database")
|
|
83
|
+
);
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* Report a corruption detection: debounce per database, capture to Sentry, and
|
|
88
|
+
* emit the `sqlite_corrupted` telemetry event directly (opt-out gated inside
|
|
89
|
+
* {@link emitWatchdogEventDirect}). The direct emit is lazy-imported so the
|
|
90
|
+
* platform/telemetry stack only loads on the rare corruption path — and so this
|
|
91
|
+
* module never pulls `db-connection` into its static import graph. Fire-and-
|
|
92
|
+
* forget: the observer runs on a query hot path, so nothing here throws or
|
|
93
|
+
* blocks on the POST.
|
|
94
|
+
*/
|
|
95
|
+
function reportCorruption(
|
|
96
|
+
detail: Record<string, unknown> & { database: string },
|
|
97
|
+
): void {
|
|
98
|
+
const now = Date.now();
|
|
99
|
+
const last =
|
|
100
|
+
lastReportAtByDatabase.get(detail.database) ?? Number.NEGATIVE_INFINITY;
|
|
101
|
+
if (now - last < REPORT_COOLDOWN_MS) return;
|
|
102
|
+
lastReportAtByDatabase.set(detail.database, now);
|
|
103
|
+
|
|
104
|
+
log.error(detail, "SQLite corruption detected");
|
|
105
|
+
|
|
106
|
+
pendingEmit = import("../telemetry/watchdog-direct-emit.js")
|
|
107
|
+
.then(({ emitWatchdogEventDirect }) =>
|
|
108
|
+
emitWatchdogEventDirect(SQLITE_CORRUPTED_CHECK_NAME, detail),
|
|
109
|
+
)
|
|
110
|
+
.catch(() => {
|
|
111
|
+
// Best-effort; never let a telemetry failure escape the query path.
|
|
112
|
+
});
|
|
113
|
+
|
|
114
|
+
try {
|
|
115
|
+
Sentry.withScope((scope) => {
|
|
116
|
+
scope.setLevel("error");
|
|
117
|
+
scope.setTag("sqlite_corruption_database", detail.database);
|
|
118
|
+
scope.setContext("sqlite_corruption", detail);
|
|
119
|
+
Sentry.captureMessage(SQLITE_CORRUPTED_CHECK_NAME);
|
|
120
|
+
});
|
|
121
|
+
} catch {
|
|
122
|
+
// Never let a Sentry failure escape into the calling query path.
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
/**
|
|
127
|
+
* Called by the slow-query wrapper for every failed statement: fires the
|
|
128
|
+
* corruption event for `SQLITE_CORRUPT` / `SQLITE_NOTADB` errors and ignores
|
|
129
|
+
* everything else (constraint/syntax errors, transient `SQLITE_BUSY` /
|
|
130
|
+
* `SQLITE_IOERR` contention). The wrapper calls this directly, so there is no
|
|
131
|
+
* observer registration or start/stop lifecycle — a corrupt file reports the
|
|
132
|
+
* moment a statement hits it.
|
|
133
|
+
*/
|
|
134
|
+
export function observeSqliteStatementError(
|
|
135
|
+
err: unknown,
|
|
136
|
+
context: StatementErrorContext,
|
|
137
|
+
): void {
|
|
138
|
+
if (!isSqliteCorruptionError(err)) return;
|
|
139
|
+
reportCorruption({
|
|
140
|
+
database: context.database ?? "unknown",
|
|
141
|
+
error: err instanceof Error ? err.message : String(err),
|
|
142
|
+
...(context.sql ? { sql: context.sql } : {}),
|
|
143
|
+
...(context.label ? { label: context.label } : {}),
|
|
144
|
+
});
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
/** Test-only: clear the per-database debounce state between cases. */
|
|
148
|
+
export function resetSqliteCorruptionWatchdogForTesting(): void {
|
|
149
|
+
lastReportAtByDatabase.clear();
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
/** Test-only: await the most recent fire-and-forget direct emit. */
|
|
153
|
+
export function flushCorruptionEmitsForTesting(): Promise<unknown> {
|
|
154
|
+
return pendingEmit;
|
|
155
|
+
}
|
|
@@ -105,6 +105,14 @@ export interface ToolSetupContext extends SurfaceConversationContext {
|
|
|
105
105
|
callSessionId?: string;
|
|
106
106
|
/** The interface ID of the connected client driving the current turn (e.g. "macos", "chrome-extension"). Propagated into ToolContext for browser backend selection. */
|
|
107
107
|
readonly transportInterface?: InterfaceId;
|
|
108
|
+
/**
|
|
109
|
+
* The conversation's per-chat plugin scope (mirrors
|
|
110
|
+
* {@link Conversation.enabledPlugins}). `null`/absent means no per-chat
|
|
111
|
+
* restriction. Read per tool call to derive the effective enabled-plugin set
|
|
112
|
+
* (via `getEffectiveEnabledPluginSet`) for the `ToolContext.enabledPluginSet`
|
|
113
|
+
* field and the `skill_execute` dispatch guard.
|
|
114
|
+
*/
|
|
115
|
+
readonly enabledPlugins?: string[] | null;
|
|
108
116
|
|
|
109
117
|
/** Turn-scoped flag: true when any tool call in the current turn received explicit user approval via interactive prompt. Cleared at turn end. */
|
|
110
118
|
approvedViaPromptThisTurn?: boolean;
|