@vellumai/assistant 0.10.12 → 0.11.0-staging.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/AGENTS.md +1 -1
- package/ARCHITECTURE.md +4 -5
- package/README.md +1 -1
- package/docs/architecture/memory.md +60 -23
- package/docs/error-handling.md +3 -3
- package/docs/guardian-request-flow.md +112 -0
- package/node_modules/@vellumai/ces-client/node_modules/@vellumai/service-contracts/package.json +1 -0
- package/node_modules/@vellumai/ces-client/node_modules/@vellumai/service-contracts/src/__tests__/channels.test.ts +9 -1
- package/node_modules/@vellumai/ces-client/node_modules/@vellumai/service-contracts/src/__tests__/secret-detection.test.ts +449 -0
- package/node_modules/@vellumai/ces-client/node_modules/@vellumai/service-contracts/src/channels.ts +1 -0
- package/node_modules/@vellumai/ces-client/node_modules/@vellumai/service-contracts/src/secret-detection.ts +468 -0
- package/node_modules/@vellumai/gateway-client/node_modules/@slack/types/dist/events/app.d.ts +28 -0
- package/node_modules/@vellumai/gateway-client/node_modules/@slack/types/dist/events/app.d.ts.map +1 -1
- package/node_modules/@vellumai/gateway-client/node_modules/@slack/types/dist/events/index.d.ts +2 -2
- package/node_modules/@vellumai/gateway-client/node_modules/@slack/types/dist/events/index.d.ts.map +1 -1
- package/node_modules/@vellumai/gateway-client/node_modules/@slack/types/dist/events/index.js.map +1 -1
- package/node_modules/@vellumai/gateway-client/node_modules/@slack/types/dist/events/message.d.ts +2 -0
- package/node_modules/@vellumai/gateway-client/node_modules/@slack/types/dist/events/message.d.ts.map +1 -1
- package/node_modules/@vellumai/gateway-client/node_modules/@slack/types/package.json +1 -1
- package/node_modules/@vellumai/gateway-client/node_modules/@vellumai/service-contracts/package.json +1 -0
- package/node_modules/@vellumai/gateway-client/node_modules/@vellumai/service-contracts/src/__tests__/channels.test.ts +9 -1
- package/node_modules/@vellumai/gateway-client/node_modules/@vellumai/service-contracts/src/__tests__/secret-detection.test.ts +449 -0
- package/node_modules/@vellumai/gateway-client/node_modules/@vellumai/service-contracts/src/channels.ts +1 -0
- package/node_modules/@vellumai/gateway-client/node_modules/@vellumai/service-contracts/src/secret-detection.ts +468 -0
- package/node_modules/@vellumai/gateway-client/package.json +1 -1
- package/node_modules/@vellumai/gateway-client/src/admission-policy-contract.ts +6 -0
- package/node_modules/@vellumai/gateway-client/src/inbound-contract.ts +34 -0
- package/node_modules/@vellumai/service-contracts/package.json +1 -0
- package/node_modules/@vellumai/service-contracts/src/__tests__/channels.test.ts +9 -1
- package/node_modules/@vellumai/service-contracts/src/__tests__/secret-detection.test.ts +449 -0
- package/node_modules/@vellumai/service-contracts/src/channels.ts +1 -0
- package/node_modules/@vellumai/service-contracts/src/secret-detection.ts +468 -0
- package/openapi.yaml +264 -14
- package/package.json +2 -2
- package/src/__tests__/acp-session.test.ts +3 -3
- package/src/__tests__/agent-loop-mutable-latest-user-message.test.ts +3 -0
- package/src/__tests__/anthropic-provider.test.ts +40 -0
- package/src/__tests__/app-conversation-ids-backfill.test.ts +33 -2
- package/src/__tests__/app-conversation-ids.test.ts +204 -0
- package/src/__tests__/approval-cascade.test.ts +5 -5
- package/src/__tests__/approval-routes-http.test.ts +3 -3
- package/src/__tests__/ask-question-resolver.test.ts +207 -0
- package/src/__tests__/assistant-event-hub-self-exclusion.test.ts +16 -16
- package/src/__tests__/assistant-event-hub-targeted.test.ts +13 -11
- package/src/__tests__/assistant-event-hub.test.ts +13 -11
- package/src/__tests__/assistant-event.test.ts +12 -9
- package/src/__tests__/assistant-feature-flag-guard.test.ts +3 -3
- package/src/__tests__/assistant-feature-flag-guardrails.test.ts +1 -1
- package/src/__tests__/assistant-id-boundary-guard.test.ts +0 -58
- package/src/__tests__/assistant-stream-state.test.ts +17 -7
- package/src/__tests__/avatar-identity-sync.test.ts +3 -3
- package/src/__tests__/background-workers-disk-pressure.test.ts +1 -0
- package/src/__tests__/call-conversation-messages.test.ts +134 -18
- package/src/__tests__/call-start-guardian-guard.test.ts +27 -0
- package/src/__tests__/channel-approvals.test.ts +0 -27
- package/src/__tests__/channel-guardian.test.ts +85 -512
- package/src/__tests__/channel-readiness-slack-remote.test.ts +151 -3
- package/src/__tests__/channel-retry-sweep.test.ts +88 -1
- package/src/__tests__/channel-setup-panel-ack.test.ts +12 -9
- package/src/__tests__/chat-reveal-guard-priming.test.ts +31 -34
- package/src/__tests__/cli-memory-v2-reembed-skills.test.ts +2 -2
- package/src/__tests__/compaction-events.test.ts +8 -8
- package/src/__tests__/config-loader-platform-defaults.test.ts +54 -28
- package/src/__tests__/config-model-image-provider.test.ts +20 -0
- package/src/__tests__/config-schema-memory-substrate.test.ts +306 -0
- package/src/__tests__/config-schema.test.ts +14 -2
- package/src/__tests__/config-set-platform-guard.test.ts +11 -12
- package/src/__tests__/config-sounds-sync.test.ts +4 -4
- package/src/__tests__/confirmation-request-guardian-bridge.test.ts +5 -0
- package/src/__tests__/context-search-memory-source.test.ts +1 -1
- package/src/__tests__/context-search-memory-v2-source.test.ts +6 -6
- package/src/__tests__/context-token-estimator.test.ts +54 -1
- package/src/__tests__/conversation-agent-loop-disk-pressure.test.ts +12 -3
- package/src/__tests__/conversation-agent-loop-fatal-cleanup.test.ts +13 -4
- package/src/__tests__/conversation-agent-loop-handlers-max-tokens.test.ts +4 -4
- package/src/__tests__/conversation-agent-loop-inference-profile.test.ts +10 -1
- package/src/__tests__/conversation-agent-loop-overflow.test.ts +22 -13
- package/src/__tests__/conversation-agent-loop.test.ts +39 -30
- package/src/__tests__/conversation-confirmation-signals.test.ts +14 -14
- package/src/__tests__/conversation-evictor.test.ts +49 -0
- package/src/__tests__/conversation-fork-crud.test.ts +1 -1
- package/src/__tests__/conversation-group-tools.test.ts +279 -0
- package/src/__tests__/conversation-history-web-search.test.ts +1 -1
- package/src/__tests__/conversation-key-store-disk-view.test.ts +5 -5
- package/src/__tests__/conversation-lineage.test.ts +235 -0
- package/src/__tests__/conversation-loop-db-lock-resilience.test.ts +5 -5
- package/src/__tests__/conversation-message-sync-tags.test.ts +4 -4
- package/src/__tests__/conversation-queue.test.ts +81 -81
- package/src/__tests__/conversation-routes-enabled-plugins.test.ts +8 -1
- package/src/__tests__/conversation-routes-hidden-queue.test.ts +8 -1
- package/src/__tests__/conversation-routes-slash-commands.test.ts +10 -1
- package/src/__tests__/conversation-runtime-assembly.test.ts +29 -2
- package/src/__tests__/conversation-slash-queue.test.ts +11 -11
- package/src/__tests__/conversation-slash-unknown.test.ts +2 -2
- package/src/__tests__/conversation-speed-override.test.ts +2 -2
- package/src/__tests__/conversation-summarize-route.test.ts +9 -0
- package/src/__tests__/conversation-surfaces-action-delivery.test.ts +18 -16
- package/src/__tests__/conversation-surfaces-activation-emit.test.ts +17 -17
- package/src/__tests__/conversation-surfaces-app-open.test.ts +7 -4
- package/src/__tests__/conversation-surfaces-data-persist.test.ts +7 -7
- package/src/__tests__/conversation-surfaces-standalone-payloads.test.ts +9 -9
- package/src/__tests__/conversation-surfaces-standalone.test.ts +12 -12
- package/src/__tests__/conversation-surfaces-state-update.test.ts +8 -5
- package/src/__tests__/conversation-surfaces-table-action.test.ts +6 -3
- package/src/__tests__/conversation-surfaces-task-progress.test.ts +46 -46
- package/src/__tests__/conversation-sync-tags.test.ts +5 -5
- package/src/__tests__/conversation-wait-for-idle.test.ts +2 -2
- package/src/__tests__/conversation-workspace-cache-state.test.ts +0 -4
- package/src/__tests__/conversation-workspace-injection.test.ts +0 -3
- package/src/__tests__/conversation-workspace-tool-tracking.test.ts +0 -3
- package/src/__tests__/copy-composer-tc-templates.test.ts +3 -131
- package/src/__tests__/credential-security-invariants.test.ts +1 -0
- package/src/__tests__/daemon-assistant-events.test.ts +14 -15
- package/src/__tests__/db-test-helpers.ts +13 -27
- package/src/__tests__/disk-pressure-routes.test.ts +12 -3
- package/src/__tests__/document-tool-security.test.ts +95 -0
- package/src/__tests__/drain-kick-guard.test.ts +232 -0
- package/src/__tests__/dynamic-skill-background-guard.test.ts +19 -6
- package/src/__tests__/emit-event-signal.test.ts +5 -6
- package/src/__tests__/encrypted-store-test-helpers.ts +10 -20
- package/src/__tests__/events-tail-route.test.ts +6 -4
- package/src/__tests__/feature-flag-test-helpers.ts +10 -20
- package/src/__tests__/file-edit-tool.test.ts +24 -4
- package/src/__tests__/file-list-tool.test.ts +2 -1
- package/src/__tests__/file-read-tool.test.ts +62 -10
- package/src/__tests__/file-write-tool.test.ts +24 -5
- package/src/__tests__/followup-tools.test.ts +58 -0
- package/src/__tests__/gateway-threshold-reader-mock.ts +99 -0
- package/src/__tests__/graph-extraction-event-date.test.ts +1 -1
- package/src/__tests__/guardian-question-mode.test.ts +42 -3
- package/src/__tests__/guardian-reply-router-answer-mode.test.ts +283 -0
- package/src/__tests__/guardian-vellum-destination-pinning.test.ts +221 -0
- package/src/__tests__/heartbeat-disk-pressure.test.ts +1 -0
- package/src/__tests__/heartbeat-service.test.ts +1 -0
- package/src/__tests__/helpers/native-web-search-harness.ts +10 -10
- package/src/__tests__/host-browser-proxy.test.ts +1 -1
- package/src/__tests__/host-file-edit-tool.test.ts +3 -3
- package/src/__tests__/host-file-read-tool.test.ts +2 -2
- package/src/__tests__/host-file-write-tool.test.ts +7 -3
- package/src/__tests__/host-shell-tool.test.ts +17 -5
- package/src/__tests__/host-transfer-pending-interactions.test.ts +8 -8
- package/src/__tests__/image-credentials.test.ts +65 -8
- package/src/__tests__/injection-block.test.ts +4 -4
- package/src/__tests__/injector-chain.test.ts +1 -1
- package/src/__tests__/injector-pkb-v2-silenced.test.ts +2 -2
- package/src/__tests__/injector-registry-order-guard.test.ts +4 -9
- package/src/__tests__/injector-v3-suppression.test.ts +6 -4
- package/src/__tests__/lifecycle-memory-v2-seed.test.ts +27 -28
- package/src/__tests__/list-messages-page-latest.test.ts +2 -2
- package/src/__tests__/llm-usage-store.test.ts +67 -4
- package/src/__tests__/log-redact.test.ts +18 -0
- package/src/__tests__/managed-profile-guard.test.ts +27 -0
- package/src/__tests__/managed-skill-lifecycle.test.ts +2 -2
- package/src/__tests__/media-generate-image.test.ts +62 -11
- package/src/__tests__/memory-identity-context-parity.test.ts +1 -1
- package/src/__tests__/memory-jobs-worker-lanes.test.ts +9 -1
- package/src/__tests__/memory-retrieval-hook.test.ts +4 -4
- package/src/__tests__/notification-decision-strategy.test.ts +115 -11
- package/src/__tests__/notification-deep-link.test.ts +12 -12
- package/src/__tests__/notification-vellum-adapter.test.ts +8 -8
- package/src/__tests__/outbound-slack-persistence.test.ts +8 -8
- package/src/__tests__/path-policy.test.ts +315 -0
- package/src/__tests__/pending-interactions-resolved-event.test.ts +6 -6
- package/src/__tests__/persistence-layering-guard.test.ts +2 -2
- package/src/__tests__/pkb-autoinject.test.ts +1 -1
- package/src/__tests__/platform-bash-auto-approve.test.ts +1 -0
- package/src/__tests__/platform-callback-registration.test.ts +10 -10
- package/src/__tests__/plugin-event-hub-facade.test.ts +22 -15
- package/src/__tests__/plugin-import-boundary-guard.test.ts +15 -15
- package/src/__tests__/processing-flag-persist-failure.test.ts +0 -4
- package/src/__tests__/provider-platform-proxy-integration.test.ts +0 -1
- package/src/__tests__/rebuild-index-graph-nodes.test.ts +1 -1
- package/src/__tests__/request-secret-standalone-channel-gate.test.ts +5 -5
- package/src/__tests__/require-fresh-approval.test.ts +38 -38
- package/src/__tests__/resolve-app-id.test.ts +32 -0
- package/src/__tests__/run-due-schedules.test.ts +72 -1
- package/src/__tests__/runtime-events-sse-parity.test.ts +11 -10
- package/src/__tests__/runtime-events-sse.test.ts +1 -1
- package/src/__tests__/schedule-routes.test.ts +44 -5
- package/src/__tests__/schedule-store.test.ts +3 -3
- package/src/__tests__/schedule-tools.test.ts +176 -0
- package/src/__tests__/secret-prompt-log-hygiene.test.ts +3 -3
- package/src/__tests__/secret-prompter-channel-fallback.test.ts +3 -3
- package/src/__tests__/secret-response-routing.test.ts +3 -3
- package/src/__tests__/secret-routes-platform-proxy.test.ts +4 -7
- package/src/__tests__/secret-scanner.test.ts +36 -0
- package/src/__tests__/send-endpoint-busy.test.ts +7 -7
- package/src/__tests__/slack-required-scopes-mirror.test.ts +81 -0
- package/src/__tests__/starter-task-flow.test.ts +26 -3
- package/src/__tests__/subagent-call-site-routing.test.ts +2 -2
- package/src/__tests__/subagent-disposal.test.ts +40 -11
- package/src/__tests__/subagent-fork-notifications.test.ts +4 -4
- package/src/__tests__/subagent-fork-prompt-role.test.ts +3 -3
- package/src/__tests__/subagent-fork-spawn.test.ts +4 -4
- package/src/__tests__/subagent-manager-notify.test.ts +73 -14
- package/src/__tests__/subagent-notify-parent.test.ts +48 -4
- package/src/__tests__/subagent-spawn-and-await.test.ts +62 -14
- package/src/__tests__/subagent-tools.test.ts +64 -0
- package/src/__tests__/sync-message-contract.test.ts +3 -3
- package/src/__tests__/terminal-tools.test.ts +12 -3
- package/src/__tests__/test-preload.ts +9 -0
- package/src/__tests__/tool-approval-handler.test.ts +587 -43
- package/src/__tests__/tool-execution-pipeline.benchmark.test.ts +7 -4
- package/src/__tests__/tool-executor.test.ts +116 -0
- package/src/__tests__/tool-grant-request-escalation.test.ts +5 -0
- package/src/__tests__/tool-preview-lifecycle.test.ts +32 -29
- package/src/__tests__/tool-result-metadata-plumbing.test.ts +5 -5
- package/src/__tests__/tool-side-effects-slack-dm.test.ts +1 -0
- package/src/__tests__/tool-start-timestamp.test.ts +4 -4
- package/src/__tests__/trusted-contact-lifecycle-notifications.test.ts +9 -22
- package/src/__tests__/ui-choice-copy-surfaces.test.ts +13 -13
- package/src/__tests__/ui-work-result-surface.test.ts +3 -3
- package/src/__tests__/voice-scoped-grant-consumer.test.ts +6 -6
- package/src/__tests__/voice-session-bridge.test.ts +44 -44
- package/src/__tests__/workspace-migration-134-image-generation-mode-to-provider.test.ts +284 -0
- package/src/__tests__/workspace-policy.test.ts +482 -2
- package/src/acp/__tests__/client-handler.test.ts +3 -3
- package/src/acp/__tests__/session-manager-persistence.test.ts +10 -10
- package/src/acp/__tests__/session-manager-resume.test.ts +7 -7
- package/src/acp/client-handler.ts +3 -3
- package/src/acp/session-manager.ts +8 -8
- package/src/api/events/subagent-event.ts +2 -2
- package/src/api/responses/memory-v2-activation-log.ts +2 -2
- package/src/api/responses/subagent-detail.ts +13 -0
- package/src/approvals/AGENTS.md +2 -0
- package/src/approvals/guardian-request-resolvers.ts +118 -24
- package/src/apps/app-store.ts +95 -4
- package/src/calls/__tests__/voice-control-protocol.test.ts +57 -0
- package/src/calls/__tests__/voice-session-bridge.test.ts +229 -7
- package/src/calls/__tests__/voice-triage-escalate.test.ts +3 -4
- package/src/calls/call-controller.ts +27 -27
- package/src/calls/call-conversation-messages.ts +58 -18
- package/src/calls/voice-control-protocol.ts +56 -0
- package/src/calls/voice-session-bridge.ts +178 -65
- package/src/calls/voice-triage-escalate.ts +2 -3
- package/src/channels/config.ts +8 -0
- package/src/channels/types.ts +1 -0
- package/src/cli/commands/config.ts +49 -13
- package/src/cli/commands/memory/index.help.ts +4 -2
- package/src/cli/commands/memory/memory-retrospective.ts +5 -0
- package/src/cli/commands/webhooks.help.ts +9 -4
- package/src/cli/lib/bundled-marketplace.json +12 -0
- package/src/cli.ts +2 -109
- package/src/config/__tests__/deployment-context-defaults.test.ts +9 -0
- package/src/config/__tests__/substrate-twin-shadowing.test.ts +191 -0
- package/src/config/assistant-feature-flags.ts +1 -1
- package/src/config/bundled-skills/conversation-groups/SKILL.md +29 -0
- package/src/config/bundled-skills/conversation-groups/TOOLS.json +58 -0
- package/src/config/bundled-skills/conversation-groups/tools/group-create.ts +12 -0
- package/src/config/bundled-skills/conversation-groups/tools/group-list.ts +12 -0
- package/src/config/bundled-skills/conversation-groups/tools/move-to-group.ts +12 -0
- package/src/config/bundled-skills/image-studio/tools/media-generate-image.ts +13 -7
- package/src/config/bundled-skills/schedule/SKILL.md +2 -0
- package/src/config/feature-flag-cache.ts +6 -16
- package/src/config/feature-flag-registry.json +14 -38
- package/src/config/loader.ts +7 -1
- package/src/config/memory-tier.ts +15 -10
- package/src/config/memory-v3-gate.test.ts +278 -1
- package/src/config/memory-v3-gate.ts +88 -26
- package/src/config/raw-config-utils.ts +1 -1
- package/src/config/schemas/__tests__/live-voice.test.ts +27 -16
- package/src/config/schemas/__tests__/memory-v3.test.ts +1 -0
- package/src/config/schemas/live-voice.ts +33 -7
- package/src/config/schemas/llm.ts +1 -0
- package/src/config/schemas/memory-retrospective.ts +13 -0
- package/src/config/schemas/memory-substrate.ts +183 -0
- package/src/config/schemas/memory-v2.ts +3 -2
- package/src/config/schemas/memory-v3.ts +11 -4
- package/src/config/schemas/memory.ts +35 -1
- package/src/config/schemas/services.ts +10 -2
- package/src/config/substrate-twin-shadowing.ts +195 -0
- package/src/config/webhook-routing.ts +67 -0
- package/src/context/compactor.ts +10 -3
- package/src/context/token-estimator.ts +21 -0
- package/src/daemon/__tests__/channel-ui-capability.test.ts +85 -0
- package/src/daemon/__tests__/conversation-surfaces-launch.test.ts +3 -3
- package/src/daemon/__tests__/embedding-reconcile.test.ts +3 -3
- package/src/daemon/__tests__/inference-profile-notification.test.ts +3 -6
- package/src/daemon/__tests__/native-web-search-metadata.test.ts +5 -5
- package/src/daemon/__tests__/web-search-status-text.test.ts +2 -2
- package/src/daemon/channel-ui-capability.ts +70 -1
- package/src/daemon/conversation-agent-loop-handlers.ts +4 -4
- package/src/daemon/conversation-agent-loop.ts +12 -5
- package/src/daemon/conversation-evictor.ts +26 -4
- package/src/daemon/conversation-launch.ts +11 -14
- package/src/daemon/conversation-lineage.ts +76 -0
- package/src/daemon/conversation-messaging.ts +14 -14
- package/src/daemon/conversation-notifiers.ts +2 -2
- package/src/daemon/conversation-process.ts +133 -21
- package/src/daemon/conversation-queue-manager.ts +7 -7
- package/src/daemon/conversation-runtime-assembly.ts +16 -0
- package/src/daemon/conversation-store.ts +11 -3
- package/src/daemon/conversation-surfaces.ts +8 -14
- package/src/daemon/conversation-tool-setup.ts +13 -7
- package/src/daemon/conversation-usage.ts +12 -11
- package/src/daemon/conversation.ts +38 -15
- package/src/daemon/disk-pressure-guard.ts +5 -12
- package/src/daemon/embedding-reconcile.ts +14 -9
- package/src/daemon/handlers/config-channels.ts +40 -134
- package/src/daemon/handlers/config-model.ts +15 -7
- package/src/daemon/handlers/conversations.ts +4 -2
- package/src/daemon/handlers/shared.ts +29 -0
- package/src/daemon/host-proxy-base.ts +4 -4
- package/src/daemon/lifecycle.ts +13 -0
- package/src/daemon/message-protocol.ts +8 -144
- package/src/daemon/message-types/computer-use.ts +0 -12
- package/src/daemon/message-types/conversations.ts +9 -345
- package/src/daemon/message-types/host-app-control.ts +0 -9
- package/src/daemon/message-types/host-browser.ts +0 -7
- package/src/daemon/message-types/host-ui-snapshot.ts +0 -7
- package/src/daemon/message-types/messages.ts +0 -48
- package/src/daemon/message-types/notifications.ts +0 -7
- package/src/daemon/message-types/skills.ts +0 -5
- package/src/daemon/message-types/surfaces.ts +0 -9
- package/src/daemon/message-types/sync.ts +0 -2
- package/src/daemon/process-message.ts +5 -5
- package/src/daemon/skill-memory-refresh.ts +5 -5
- package/src/daemon/tool-side-effects.ts +32 -16
- package/src/daemon/trust-context.ts +1 -1
- package/src/daemon/wake-conversation-ops.ts +4 -4
- package/src/heartbeat/__tests__/heartbeat-run-store.test.ts +100 -7
- package/src/heartbeat/__tests__/heartbeat-service.test.ts +67 -0
- package/src/heartbeat/heartbeat-run-store.ts +81 -4
- package/src/heartbeat/heartbeat-service.ts +32 -1
- package/src/home/__tests__/feed-writer.test.ts +7 -7
- package/src/home/__tests__/home-content-refresh.test.ts +3 -0
- package/src/home/__tests__/suggested-prompts.test.ts +1 -0
- package/src/home/feed-writer.ts +6 -13
- package/src/home/home-content-refresh.ts +6 -9
- package/src/home/relationship-state-writer.ts +5 -12
- package/src/home/suggested-prompts-cache.ts +6 -19
- package/src/ipc/__tests__/events-publish-client.test.ts +67 -0
- package/src/ipc/events-publish-client.ts +44 -0
- package/src/ipc/routes/__tests__/conversation-sync-ipc-routes.test.ts +2 -2
- package/src/ipc/routes/__tests__/events-ipc-routes.test.ts +38 -9
- package/src/ipc/routes/events-ipc-routes.ts +11 -31
- package/src/live-voice/__tests__/front-decision.test.ts +4 -176
- package/src/live-voice/__tests__/live-voice-agent-turn.test.ts +276 -68
- package/src/live-voice/__tests__/live-voice-continuation-fork-hydration.test.ts +286 -0
- package/src/live-voice/__tests__/live-voice-events.test.ts +6 -3
- package/src/live-voice/__tests__/live-voice-progress.test.ts +185 -46
- package/src/live-voice/__tests__/live-voice-triage-escalate.test.ts +24 -59
- package/src/live-voice/__tests__/live-voice-tts-session.test.ts +38 -54
- package/src/live-voice/__tests__/live-voice-vad.test.ts +1154 -636
- package/src/live-voice/front-decision.ts +5 -155
- package/src/live-voice/live-voice-metrics.ts +4 -1
- package/src/live-voice/live-voice-session.ts +1288 -439
- package/src/live-voice/progress-phrases.ts +17 -0
- package/src/live-voice/protocol.ts +15 -0
- package/src/media/app-icon-generator.ts +15 -8
- package/src/media/avatar-router.ts +9 -5
- package/src/media/image-credentials.ts +42 -10
- package/src/media/image-service.ts +1 -13
- package/src/media/types.ts +26 -3
- package/src/notifications/AGENTS.md +2 -0
- package/src/notifications/__tests__/broadcaster.test.ts +95 -0
- package/src/notifications/adapters/macos.ts +3 -3
- package/src/notifications/broadcaster.ts +57 -0
- package/src/notifications/copy-composer.ts +0 -15
- package/src/notifications/decision-engine.ts +21 -22
- package/src/notifications/guardian-question-mode.ts +57 -2
- package/src/notifications/home-feed-side-effect.ts +4 -0
- package/src/notifications/signal.ts +6 -4
- package/src/notifications/trusted-contact-payloads.ts +3 -4
- package/src/notifications/vellum-card-affinity.ts +39 -0
- package/src/oauth/AGENTS.md +1 -1
- package/src/permissions/channel-permission-query.test.ts +69 -0
- package/src/permissions/channel-permission-query.ts +73 -1
- package/src/permissions/checker.test.ts +298 -15
- package/src/permissions/checker.ts +102 -36
- package/src/permissions/confirmation-guardian-request.test.ts +2 -2
- package/src/permissions/confirmation-guardian-request.ts +2 -2
- package/src/permissions/gateway-threshold-reader.test.ts +224 -17
- package/src/permissions/gateway-threshold-reader.ts +82 -10
- package/src/permissions/ipc-risk-types.ts +8 -0
- package/src/permissions/prompter.ts +5 -5
- package/src/permissions/question-guardian-request.test.ts +222 -0
- package/src/permissions/question-guardian-request.ts +179 -0
- package/src/permissions/question-prompter.test.ts +8 -8
- package/src/permissions/question-prompter.ts +18 -0
- package/src/permissions/secret-prompter.ts +2 -4
- package/src/permissions/workspace-policy.ts +269 -34
- package/src/persistence/__tests__/lifecycle-quiesce.test.ts +82 -0
- package/src/persistence/__tests__/message-content-file.test.ts +58 -3
- package/src/persistence/conversation-crud.ts +93 -0
- package/src/persistence/conversation-key-store.ts +63 -0
- package/src/persistence/conversation-parent.ts +27 -0
- package/src/persistence/db-async-query.ts +1 -1
- package/src/persistence/db-singleton.ts +14 -27
- package/src/persistence/delivery-crud.ts +45 -0
- package/src/persistence/embeddings/embedding-backend.ts +2 -1
- package/src/persistence/embeddings/embedding-identity.ts +7 -3
- package/src/persistence/job-utils.ts +32 -27
- package/src/persistence/jobs-store.ts +92 -3
- package/src/persistence/lifecycle-quiesce.ts +80 -0
- package/src/persistence/llm-usage-store.ts +45 -8
- package/src/persistence/message-content-file.ts +4 -4
- package/src/persistence/migrations/336-move-memory-v2-activation-logs-to-memory-db.ts +1 -1
- package/src/persistence/migrations/351-schedule-skill-script-handoff.ts +39 -0
- package/src/persistence/migrations/352-drop-schedule-skill-script-handoff.test.ts +83 -0
- package/src/persistence/migrations/352-drop-schedule-skill-script-handoff.ts +36 -0
- package/src/persistence/migrations/353-add-llm-usage-conversation-type.test.ts +110 -0
- package/src/persistence/migrations/353-add-llm-usage-conversation-type.ts +49 -0
- package/src/persistence/migrations/354-backfill-app-conversation-lineage.ts +41 -0
- package/src/persistence/schema/infrastructure.ts +11 -0
- package/src/persistence/steps.ts +9 -1
- package/src/plugin-api/__tests__/publish-event-forwarding.test.ts +113 -0
- package/src/plugin-api/__tests__/publish-event.test.ts +57 -0
- package/src/plugin-api/conversation-turn.ts +4 -4
- package/src/plugin-api/event-hub-facade.ts +15 -6
- package/src/plugin-api/index.ts +10 -4
- package/src/plugin-api/publish-event.ts +36 -0
- package/src/plugins/AGENTS.md +2 -0
- package/src/plugins/defaults/compaction/window-manager.ts +9 -0
- package/src/plugins/defaults/index.ts +9 -13
- package/src/plugins/defaults/memory/AGENTS.md +775 -0
- package/src/plugins/defaults/memory/__tests__/capability-seed-embed-gate.test.ts +186 -0
- package/src/plugins/defaults/memory/__tests__/fixtures/memory-v2-activation-fixtures.ts +1 -1
- package/src/plugins/defaults/memory/__tests__/indexer-tier-dispatch.test.ts +129 -0
- package/src/plugins/defaults/memory/__tests__/jobs-worker-quiesce-gate.test.ts +91 -0
- package/src/plugins/defaults/memory/__tests__/jobs-worker-v1-graph-substrate-noop.test.ts +342 -0
- package/src/plugins/defaults/memory/__tests__/jobs-worker-v2-graph-trigger-embed.test.ts +9 -1
- package/src/plugins/defaults/memory/__tests__/jobs-worker-v2-schedule.test.ts +36 -1
- package/src/plugins/defaults/memory/__tests__/jobs-worker-v2-sweep-defer.test.ts +9 -1
- package/src/plugins/defaults/memory/__tests__/memory-log-stores-degraded.test.ts +2 -2
- package/src/plugins/defaults/memory/__tests__/memory-retrospective-job.test.ts +44 -10
- package/src/plugins/defaults/memory/__tests__/memory-retrospective-sweep.test.ts +151 -10
- package/src/plugins/defaults/memory/__tests__/memory-tier-boundary-guard.test.ts +1155 -0
- package/src/plugins/defaults/memory/__tests__/memory-v2-activation-log-store.test.ts +1 -1
- package/src/plugins/defaults/memory/__tests__/memory-v2-concept-frequency.test.ts +3 -3
- package/src/plugins/defaults/memory/__tests__/tools-delete-memory-page.test.ts +1 -1
- package/src/plugins/defaults/memory/context-search/sources/memory-v2.ts +71 -35
- package/src/plugins/defaults/memory/context-search/sources/memory.ts +5 -1
- package/src/plugins/defaults/memory/fork-conversation-memory.ts +4 -4
- package/src/plugins/defaults/memory/graph/__tests__/conversation-graph-memory-v2-routing.test.ts +80 -10
- package/src/plugins/defaults/memory/graph/__tests__/handle-remember-v2.test.ts +1 -1
- package/src/plugins/defaults/memory/graph/capability-seed.ts +24 -10
- package/src/plugins/defaults/memory/graph/conversation-graph-memory.ts +123 -49
- package/src/plugins/defaults/memory/graph/graph-search.ts +6 -118
- package/src/plugins/defaults/memory/graph/in-context-tracker.test.ts +173 -0
- package/src/plugins/defaults/memory/graph/in-context-tracker.ts +109 -0
- package/src/plugins/defaults/memory/graph/store.ts +1 -0
- package/src/plugins/defaults/memory/graph/tool-handlers.test.ts +1 -1
- package/src/plugins/defaults/memory/graph/tool-handlers.ts +5 -2
- package/src/plugins/defaults/memory/graph-topology/__tests__/build-memory-graph.test.ts +1 -1
- package/src/plugins/defaults/memory/graph-topology/build-memory-graph.ts +6 -9
- package/src/plugins/defaults/memory/hooks/__tests__/user-prompt-submit.test.ts +30 -16
- package/src/plugins/defaults/memory/hooks/user-prompt-submit.ts +18 -14
- package/src/plugins/defaults/memory/indexer.ts +146 -89
- package/src/plugins/defaults/memory/injectors.ts +86 -41
- package/src/plugins/defaults/memory/job-handlers.ts +130 -39
- package/src/plugins/defaults/memory/jobs/__tests__/embed-concept-page.test.ts +2 -2
- package/src/plugins/defaults/memory/jobs/embed-concept-page.ts +22 -10
- package/src/plugins/defaults/memory/jobs-worker.ts +279 -208
- package/src/plugins/defaults/memory/memory-retrospective-enqueue.ts +4 -2
- package/src/plugins/defaults/memory/memory-retrospective-job.ts +40 -3
- package/src/plugins/defaults/memory/memory-retrospective-sweep.ts +99 -11
- package/src/plugins/defaults/memory/src/__tests__/memory-v2-routes.test.ts +5 -3
- package/src/plugins/defaults/memory/src/__tests__/memory-v2-simulate-route.test.ts +3 -4
- package/src/plugins/defaults/memory/src/memory-graph-routes.ts +2 -1
- package/src/plugins/defaults/memory/src/memory-item-routes.test.ts +7 -5
- package/src/plugins/defaults/memory/src/memory-item-routes.ts +51 -19
- package/src/plugins/defaults/memory/src/memory-v2-routes.ts +31 -20
- package/src/plugins/defaults/memory/startup.ts +58 -21
- package/src/plugins/defaults/memory/substrate/__tests__/boot-maintenance.test.ts +335 -0
- package/src/plugins/defaults/memory/{v3/substrate → substrate}/__tests__/cli-command-store.test.ts +14 -8
- package/src/plugins/defaults/memory/{v3/substrate → substrate}/__tests__/consolidation-job.test.ts +51 -21
- package/src/plugins/defaults/memory/{v3/substrate → substrate}/__tests__/edge-index.test.ts +1 -1
- package/src/plugins/defaults/memory/{v3/substrate → substrate}/__tests__/frontmatter-sweep.test.ts +3 -3
- package/src/plugins/defaults/memory/{v3/substrate → substrate}/__tests__/page-index.test.ts +1 -1
- package/src/plugins/defaults/memory/{v3/substrate → substrate}/__tests__/page-store.test.ts +1 -1
- package/src/plugins/defaults/memory/{v3/substrate → substrate}/__tests__/prompts-consolidation.test.ts +2 -2
- package/src/plugins/defaults/memory/{v3/substrate → substrate}/__tests__/qdrant.test.ts +23 -14
- package/src/plugins/defaults/memory/substrate/__tests__/reembed-job.test.ts +262 -0
- package/src/plugins/defaults/memory/{v3/substrate → substrate}/__tests__/sim.test.ts +9 -12
- package/src/plugins/defaults/memory/{v3/substrate → substrate}/__tests__/skill-content.test.ts +2 -2
- package/src/plugins/defaults/memory/{v3/substrate → substrate}/__tests__/skill-store.test.ts +9 -9
- package/src/plugins/defaults/memory/{v3/substrate → substrate}/__tests__/sparse-bm25.test.ts +12 -5
- package/src/plugins/defaults/memory/substrate/__tests__/spread.test.ts +276 -0
- package/src/plugins/defaults/memory/{v3/substrate → substrate}/__tests__/static-context.test.ts +17 -8
- package/src/plugins/defaults/memory/{v3/substrate → substrate}/__tests__/sweep-job.test.ts +9 -9
- package/src/plugins/defaults/memory/{v3/substrate/memory-v2-startup.ts → substrate/boot-maintenance.ts} +43 -24
- package/src/plugins/defaults/memory/{v3/substrate → substrate}/cli-command-store.ts +13 -8
- package/src/plugins/defaults/memory/{v3/substrate → substrate}/consolidation-job.ts +51 -27
- package/src/plugins/defaults/memory/{v3/substrate → substrate}/constants.ts +1 -0
- package/src/plugins/defaults/memory/{v3/substrate → substrate}/edge-index.ts +28 -9
- package/src/plugins/defaults/memory/{v3/substrate → substrate}/frontmatter-sweep.ts +14 -7
- package/src/plugins/defaults/memory/{v3/substrate → substrate}/injected-block-slugs.ts +9 -3
- package/src/plugins/defaults/memory/{v3/substrate → substrate}/page-index.ts +29 -10
- package/src/plugins/defaults/memory/{v3/substrate → substrate}/page-store.ts +35 -12
- package/src/plugins/defaults/memory/{v3/substrate → substrate}/prompts/consolidation.ts +14 -8
- package/src/plugins/defaults/memory/{v3/substrate → substrate}/prompts/sweep.ts +4 -1
- package/src/plugins/defaults/memory/{v3/substrate → substrate}/qdrant.ts +96 -36
- package/src/plugins/defaults/memory/substrate/reembed-job.ts +54 -0
- package/src/plugins/defaults/memory/{v3/substrate → substrate}/sim.ts +26 -15
- package/src/plugins/defaults/memory/{v3/substrate → substrate}/skill-content.ts +1 -1
- package/src/plugins/defaults/memory/{v3/substrate → substrate}/skill-store.ts +13 -8
- package/src/plugins/defaults/memory/{v3/substrate → substrate}/sparse-bm25.ts +27 -10
- package/src/plugins/defaults/memory/substrate/spread.ts +165 -0
- package/src/plugins/defaults/memory/{v3/substrate → substrate}/static-context.ts +12 -7
- package/src/plugins/defaults/memory/{v3/substrate → substrate}/sweep-job.ts +20 -15
- package/src/plugins/defaults/memory/substrate/tuning.ts +93 -0
- package/src/plugins/defaults/memory/{v3/substrate → substrate}/types.ts +7 -4
- package/src/plugins/defaults/memory/tools.test.ts +1 -1
- package/src/plugins/defaults/memory/tools.ts +1 -1
- package/src/plugins/defaults/memory/v1/README.md +5 -0
- package/src/plugins/defaults/memory/{__tests__ → v1/__tests__}/filing-jobs.test.ts +4 -4
- package/src/plugins/defaults/memory/{filing-jobs.ts → v1/filing-jobs.ts} +3 -3
- package/src/plugins/defaults/memory/{graph → v1/graph}/bootstrap.test.ts +68 -6
- package/src/plugins/defaults/memory/{graph → v1/graph}/bootstrap.ts +40 -21
- package/src/plugins/defaults/memory/{graph → v1/graph}/consolidation.ts +14 -14
- package/src/plugins/defaults/memory/{graph → v1/graph}/decay.test.ts +1 -1
- package/src/plugins/defaults/memory/{graph → v1/graph}/decay.ts +3 -3
- package/src/plugins/defaults/memory/{graph → v1/graph}/extraction-job.ts +5 -5
- package/src/plugins/defaults/memory/{graph → v1/graph}/extraction.test.ts +1 -1
- package/src/plugins/defaults/memory/{graph → v1/graph}/extraction.ts +20 -14
- package/src/plugins/defaults/memory/{graph → v1/graph}/graph-search.test.ts +3 -3
- package/src/plugins/defaults/memory/v1/graph/graph-search.ts +123 -0
- package/src/plugins/defaults/memory/{graph → v1/graph}/injection.test.ts +1 -118
- package/src/plugins/defaults/memory/{graph → v1/graph}/injection.ts +9 -111
- package/src/plugins/defaults/memory/{graph → v1/graph}/narrative.ts +6 -6
- package/src/plugins/defaults/memory/{graph → v1/graph}/pattern-scan.ts +5 -5
- package/src/plugins/defaults/memory/{graph → v1/graph}/retriever.test.ts +135 -42
- package/src/plugins/defaults/memory/{graph → v1/graph}/retriever.ts +40 -22
- package/src/plugins/defaults/memory/{graph → v1/graph}/scoring.test.ts +1 -1
- package/src/plugins/defaults/memory/{graph → v1/graph}/scoring.ts +1 -1
- package/src/plugins/defaults/memory/{graph → v1/graph}/serendipity.ts +1 -1
- package/src/plugins/defaults/memory/{graph → v1/graph}/triggers.test.ts +1 -1
- package/src/plugins/defaults/memory/{graph → v1/graph}/triggers.ts +1 -1
- package/src/plugins/defaults/memory/{identity-context.ts → v1/identity-context.ts} +4 -4
- package/src/plugins/defaults/memory/{job-handlers → v1/job-handlers}/backfill.ts +6 -6
- package/src/plugins/defaults/memory/{job-handlers → v1/job-handlers}/embedding.test.ts +6 -6
- package/src/plugins/defaults/memory/{job-handlers → v1/job-handlers}/embedding.ts +6 -6
- package/src/plugins/defaults/memory/{job-handlers → v1/job-handlers}/index-maintenance.ts +8 -8
- package/src/plugins/defaults/memory/{jobs → v1/jobs}/embed-pkb-file.test.ts +7 -7
- package/src/plugins/defaults/memory/{jobs → v1/jobs}/embed-pkb-file.ts +5 -5
- package/src/plugins/defaults/memory/{pkb → v1/pkb}/autoinject.ts +1 -1
- package/src/plugins/defaults/memory/{pkb → v1/pkb}/context.ts +2 -2
- package/src/plugins/defaults/memory/{pkb → v1/pkb}/pkb-index.test.ts +3 -3
- package/src/plugins/defaults/memory/{pkb → v1/pkb}/pkb-index.ts +2 -2
- package/src/plugins/defaults/memory/{pkb → v1/pkb}/pkb-reconcile.test.ts +3 -3
- package/src/plugins/defaults/memory/{pkb → v1/pkb}/pkb-reconcile.ts +2 -2
- package/src/plugins/defaults/memory/{pkb → v1/pkb}/pkb-search.test.ts +3 -3
- package/src/plugins/defaults/memory/{pkb → v1/pkb}/pkb-search.ts +6 -6
- package/src/plugins/defaults/memory/{pkb → v1/pkb}/types.ts +3 -5
- package/src/plugins/defaults/memory/{pkb-schedule.ts → v1/pkb-schedule.ts} +2 -2
- package/src/plugins/defaults/memory/{search/semantic.ts → v1/semantic-search.ts} +1 -1
- package/src/plugins/defaults/memory/v2/__tests__/activation-store.test.ts +1 -1
- package/src/plugins/defaults/memory/v2/__tests__/activation.test.ts +11 -274
- package/src/plugins/defaults/memory/v2/__tests__/backfill-jobs.test.ts +9 -131
- package/src/plugins/defaults/memory/v2/__tests__/harness-compare.test.ts +1 -1
- package/src/plugins/defaults/memory/v2/__tests__/harness-oracle.test.ts +1 -1
- package/src/plugins/defaults/memory/v2/__tests__/harness-replay-input.test.ts +1 -1
- package/src/plugins/defaults/memory/v2/__tests__/injection.test.ts +14 -10
- package/src/plugins/defaults/memory/v2/__tests__/reranker.test.ts +7 -5
- package/src/plugins/defaults/memory/v2/__tests__/router.test.ts +12 -6
- package/src/plugins/defaults/memory/{memory-v2-activation-log-store.ts → v2/activation-log-store.ts} +2 -2
- package/src/plugins/defaults/memory/v2/activation-store.ts +22 -8
- package/src/plugins/defaults/memory/v2/activation.ts +30 -163
- package/src/plugins/defaults/memory/v2/backfill-jobs.ts +7 -54
- package/src/plugins/defaults/memory/{memory-v2-concept-frequency.ts → v2/concept-frequency.ts} +3 -3
- package/src/plugins/defaults/memory/v2/harness/oracle.ts +1 -1
- package/src/plugins/defaults/memory/v2/harness/replay-input.ts +2 -2
- package/src/plugins/defaults/memory/v2/harness/retriever.ts +1 -1
- package/src/plugins/defaults/memory/v2/injection.ts +36 -26
- package/src/plugins/defaults/memory/v2/migration.ts +2 -2
- package/src/plugins/defaults/memory/{rerank-local.ts → v2/rerank-local.ts} +44 -18
- package/src/plugins/defaults/memory/v2/reranker.ts +29 -11
- package/src/plugins/defaults/memory/v2/router.ts +38 -15
- package/src/plugins/defaults/memory/v3/__tests__/candidate-match.test.ts +5 -3
- package/src/plugins/defaults/memory/v3/__tests__/carry-integration.test.ts +21 -8
- package/src/plugins/defaults/memory/v3/__tests__/edge.test.ts +1 -1
- package/src/plugins/defaults/memory/v3/__tests__/live-integration.test.ts +1 -1
- package/src/plugins/defaults/memory/v3/__tests__/maintain-job.test.ts +4 -1
- package/src/plugins/defaults/memory/v3/__tests__/orchestrate.test.ts +181 -3
- package/src/plugins/defaults/memory/v3/__tests__/selection-log-store.test.ts +3 -0
- package/src/plugins/defaults/memory/v3/__tests__/shadow-integration.test.ts +14 -5
- package/src/plugins/defaults/memory/v3/__tests__/shadow-plugin.test.ts +40 -50
- package/src/plugins/defaults/memory/v3/__tests__/tuning-profile.test.ts +1 -0
- package/src/plugins/defaults/memory/v3/candidate-match.ts +2 -2
- package/src/plugins/defaults/memory/v3/capabilities.ts +6 -4
- package/src/plugins/defaults/memory/v3/card.ts +25 -9
- package/src/plugins/defaults/memory/v3/edge.ts +52 -18
- package/src/plugins/defaults/memory/v3/gate.ts +4 -4
- package/src/plugins/defaults/memory/v3/injector.ts +10 -3
- package/src/plugins/defaults/memory/v3/maintain-job.ts +3 -3
- package/src/plugins/defaults/memory/v3/orchestrate.ts +100 -18
- package/src/plugins/defaults/memory/v3/page-content.ts +26 -10
- package/src/plugins/defaults/memory/v3/prune.ts +40 -16
- package/src/plugins/defaults/memory/v3/selection-log-store.ts +34 -12
- package/src/plugins/defaults/memory/v3/shadow-plugin.ts +9 -13
- package/src/plugins/defaults/memory/v3/span-query.test.ts +86 -0
- package/src/plugins/defaults/memory/v3/span-query.ts +71 -0
- package/src/plugins/defaults/memory/v3/tuning-profile.ts +3 -0
- package/src/plugins/defaults/memory/v3/types.ts +4 -1
- package/src/plugins/defaults/memory/v3-eval/eval-packets.ts +2 -2
- package/src/plugins/defaults/memory/validation.ts +1 -1
- package/src/plugins/defaults/memory/worker.ts +2 -1
- package/src/plugins/defaults/platform-hosted/__tests__/reengage.test.ts +104 -12
- package/src/plugins/defaults/platform-hosted/routes/reengage.ts +104 -12
- package/src/plugins/types.ts +2 -2
- package/src/prompts/sections.ts +4 -16
- package/src/providers/__tests__/registry-native-web-search.test.ts +47 -2
- package/src/providers/anthropic/client.ts +15 -6
- package/src/providers/content-block-schema.ts +26 -0
- package/src/providers/inference/__tests__/connections-credential-normalize.test.ts +87 -0
- package/src/providers/inference/adapter-factory.ts +6 -0
- package/src/providers/inference/connections.ts +30 -14
- package/src/providers/model-catalog.ts +77 -0
- package/src/providers/openai/__tests__/chat-completions-input-audio.test.ts +260 -0
- package/src/providers/openai/chat-completions-provider.ts +65 -17
- package/src/providers/openai/input-audio.ts +76 -0
- package/src/providers/openrouter/client.ts +0 -2
- package/src/providers/platform-proxy/constants.ts +4 -0
- package/src/providers/poolside/client.ts +42 -0
- package/src/providers/registry.ts +40 -8
- package/src/providers/retry.ts +2 -0
- package/src/providers/types.ts +39 -1
- package/src/providers/vercel-ai-gateway/client.ts +0 -2
- package/src/runtime/AGENTS.md +7 -5
- package/src/runtime/__tests__/question-request-guardian-bridge.test.ts +173 -0
- package/src/runtime/__tests__/question-resolution.test.ts +111 -0
- package/src/runtime/access-request-helper.ts +7 -15
- package/src/runtime/assistant-event-hub.ts +43 -31
- package/src/runtime/assistant-event-publish-options.ts +31 -0
- package/src/runtime/assistant-event.ts +19 -30
- package/src/runtime/assistant-stream-state.ts +4 -4
- package/src/runtime/channel-approvals.ts +0 -25
- package/src/runtime/channel-readiness-service.ts +99 -40
- package/src/runtime/channel-retry-sweep.ts +38 -15
- package/src/runtime/confirmation-request-guardian-bridge.ts +4 -0
- package/src/runtime/guardian-reply-router.ts +108 -0
- package/src/runtime/http-server.ts +8 -0
- package/src/runtime/http-types.ts +2 -2
- package/src/runtime/process-role.ts +42 -0
- package/src/runtime/question-request-guardian-bridge.ts +184 -0
- package/src/runtime/question-resolution.ts +153 -0
- package/src/runtime/routes/__tests__/bookmark-routes.test.ts +6 -2
- package/src/runtime/routes/__tests__/conversation-query-routes.test.ts +1 -1
- package/src/runtime/routes/__tests__/subagents-routes.test.ts +250 -0
- package/src/runtime/routes/__tests__/webhook-routes.test.ts +201 -0
- package/src/runtime/routes/acp-routes.ts +2 -2
- package/src/runtime/routes/bookmark-routes.ts +3 -15
- package/src/runtime/routes/canned-message-complete.ts +2 -2
- package/src/runtime/routes/consolidation-routes.ts +8 -2
- package/src/runtime/routes/conversation-list-routes.ts +3 -19
- package/src/runtime/routes/conversation-management-routes.ts +1 -5
- package/src/runtime/routes/conversation-query-routes.ts +52 -8
- package/src/runtime/routes/conversation-routes.ts +36 -22
- package/src/runtime/routes/credential-request-routes.ts +0 -1
- package/src/runtime/routes/filing-routes.ts +7 -7
- package/src/runtime/routes/global-search-routes.ts +1 -1
- package/src/runtime/routes/guardian-approval-prompt.ts +2 -2
- package/src/runtime/routes/image-generation-routes.ts +12 -9
- package/src/runtime/routes/inbound-message-handler.ts +17 -0
- package/src/runtime/routes/inbound-stages/acl-enforcement.test.ts +50 -0
- package/src/runtime/routes/inbound-stages/acl-enforcement.ts +19 -0
- package/src/runtime/routes/inbound-stages/background-dispatch.ts +4 -4
- package/src/runtime/routes/inbound-stages/inbound-content-prep.test.ts +129 -0
- package/src/runtime/routes/inbound-stages/inbound-content-prep.ts +141 -9
- package/src/runtime/routes/index.ts +2 -0
- package/src/runtime/routes/lifecycle-routes.ts +199 -0
- package/src/runtime/routes/platform-routes.ts +3 -8
- package/src/runtime/routes/playground/__tests__/inject-failures.test.ts +7 -7
- package/src/runtime/routes/playground/__tests__/reset-circuit.test.ts +5 -5
- package/src/runtime/routes/question-routes.ts +34 -87
- package/src/runtime/routes/secret-routes.ts +11 -1
- package/src/runtime/routes/settings-routes.ts +8 -18
- package/src/runtime/routes/subagents-routes.ts +35 -8
- package/src/runtime/routes/upgrade-broadcast-routes.ts +4 -5
- package/src/runtime/routes/webhook-routes.ts +89 -30
- package/src/runtime/routes/workspace-routes.test.ts +7 -4
- package/src/runtime/slack-reply-session.test.ts +12 -12
- package/src/runtime/slack-reply-session.ts +17 -17
- package/src/runtime/sync/sync-publisher.test.ts +7 -5
- package/src/runtime/tool-grant-request-helper.ts +4 -0
- package/src/schedule/schedule-store.ts +70 -0
- package/src/schedule/scheduler.ts +27 -0
- package/src/security/AGENTS.md +1 -1
- package/src/security/credential-key.ts +17 -0
- package/src/security/secret-ingress.ts +14 -105
- package/src/security/secret-patterns.ts +8 -139
- package/src/security/secret-scanner.ts +8 -3
- package/src/security/store-path-override.ts +6 -16
- package/src/sequence/store.ts +8 -0
- package/src/signals/emit-event.ts +5 -10
- package/src/signals/event-stream.ts +20 -10
- package/src/subagent/manager.ts +76 -25
- package/src/subagent/notify.ts +8 -0
- package/src/subagent/types.ts +13 -3
- package/src/telegram/__tests__/webhook-health.test.ts +442 -0
- package/src/telegram/webhook-health.ts +478 -0
- package/src/telemetry/AGENTS.md +6 -0
- package/src/telemetry/memory-corpus-size.test.ts +129 -0
- package/src/telemetry/memory-corpus-size.ts +184 -0
- package/src/telemetry/memory-tier-reporter.test.ts +67 -2
- package/src/telemetry/memory-tier-reporter.ts +30 -3
- package/src/tools/__tests__/conversation-group-tool-input-schemas.test.ts +61 -0
- package/src/tools/__tests__/document-tool-input-schemas.test.ts +103 -0
- package/src/tools/__tests__/followup-call-acp-tool-input-schemas.test.ts +125 -0
- package/src/tools/__tests__/schedule-tool-input-schemas.test.ts +83 -0
- package/src/tools/__tests__/subagent-workflow-tool-input-schemas.test.ts +116 -0
- package/src/tools/__tests__/tool-input-schemas.test.ts +192 -0
- package/src/tools/__tests__/tool-schema-drift-harness.ts +142 -0
- package/src/tools/acp/abort.ts +21 -1
- package/src/tools/acp/context.ts +5 -5
- package/src/tools/acp/spawn.test.ts +15 -5
- package/src/tools/acp/spawn.ts +26 -3
- package/src/tools/acp/status.ts +20 -1
- package/src/tools/acp/steer.test.ts +20 -0
- package/src/tools/acp/steer.ts +23 -2
- package/src/tools/apps/resolve-app-id.ts +15 -3
- package/src/tools/ask-question/ask-question-tool.test.ts +65 -0
- package/src/tools/ask-question/ask-question-tool.ts +68 -92
- package/src/tools/browser/browser-screencast.ts +6 -6
- package/src/tools/calls/call-end.ts +24 -3
- package/src/tools/calls/call-start.ts +35 -11
- package/src/tools/calls/call-status.ts +20 -1
- package/src/tools/conversation-groups/group_create.ts +63 -0
- package/src/tools/conversation-groups/group_list.ts +20 -0
- package/src/tools/conversation-groups/group_shared.ts +52 -0
- package/src/tools/conversation-groups/move_to_group.ts +106 -0
- package/src/tools/document/document-comment-tool.test.ts +49 -0
- package/src/tools/document/document-comment-tool.ts +45 -6
- package/src/tools/document/document-tool.ts +142 -24
- package/src/tools/executor.ts +27 -13
- package/src/tools/filesystem/edit.ts +62 -60
- package/src/tools/filesystem/list.ts +36 -29
- package/src/tools/filesystem/read.ts +56 -39
- package/src/tools/filesystem/write.ts +44 -38
- package/src/tools/followups/followup_create.ts +41 -12
- package/src/tools/followups/followup_list.ts +34 -6
- package/src/tools/followups/followup_resolve.ts +26 -4
- package/src/tools/host-filesystem/edit.ts +50 -60
- package/src/tools/host-filesystem/read.ts +45 -39
- package/src/tools/host-filesystem/write.ts +31 -36
- package/src/tools/host-terminal/host-shell.ts +76 -62
- package/src/tools/policy-context.ts +27 -10
- package/src/tools/schedule/create.ts +76 -33
- package/src/tools/schedule/delete.ts +21 -2
- package/src/tools/schedule/list.ts +25 -3
- package/src/tools/schedule/update.ts +105 -48
- package/src/tools/shared/filesystem/path-policy.ts +246 -40
- package/src/tools/shared/zod-tool-schema.ts +117 -0
- package/src/tools/subagent/abort.ts +12 -4
- package/src/tools/subagent/consult-deadline.ts +9 -3
- package/src/tools/subagent/message.ts +21 -5
- package/src/tools/subagent/notify-parent.ts +44 -23
- package/src/tools/subagent/read.ts +15 -4
- package/src/tools/subagent/resolve.ts +26 -4
- package/src/tools/subagent/spawn.ts +37 -13
- package/src/tools/subagent/status.ts +12 -4
- package/src/tools/system/request-permission.ts +35 -26
- package/src/tools/terminal/shell.ts +68 -55
- package/src/tools/tool-approval-handler.ts +327 -53
- package/src/tools/tool-input-schemas.ts +85 -0
- package/src/tools/tool-types.ts +7 -0
- package/src/tools/types.ts +8 -0
- package/src/tools/workflows/manage-workflows.ts +30 -2
- package/src/tools/workflows/run-workflow.test.ts +54 -2
- package/src/tools/workflows/run-workflow.ts +32 -4
- package/src/util/fs-symlinks.ts +30 -0
- package/src/util/log-redact.ts +7 -3
- package/src/util/platform.ts +15 -0
- package/src/vellum-assistant-namespace.d.ts +80 -0
- package/src/watcher/watcher-store.ts +8 -0
- package/src/workflows/leaf-runner.test.ts +104 -2
- package/src/workflows/leaf-runner.ts +31 -6
- package/src/workspace/migrations/070-memory-v2-summary-schema-rebuild.ts +2 -2
- package/src/workspace/migrations/134-image-generation-mode-to-provider.ts +128 -0
- package/src/workspace/migrations/135-copy-substrate-tunables.ts +248 -0
- package/src/workspace/migrations/__tests__/135-copy-substrate-tunables.test.ts +446 -0
- package/src/workspace/migrations/__tests__/backfill-v3-leaves.test.ts +2 -2
- package/src/workspace/migrations/registry.ts +4 -0
- package/tsconfig.plugin-api.json +1 -1
- package/src/__tests__/memory-retrieval-budget.test.ts +0 -49
- package/src/__tests__/secret-patterns.test.ts +0 -27
- package/src/config/__tests__/proc-to-skills.test.ts +0 -21
- package/src/config/memory-tier.test.ts +0 -44
- package/src/daemon/message-types/acp.ts +0 -20
- package/src/daemon/message-types/apps.ts +0 -11
- package/src/daemon/message-types/background-tools.ts +0 -14
- package/src/daemon/message-types/bookmarks.ts +0 -13
- package/src/daemon/message-types/contacts.ts +0 -13
- package/src/daemon/message-types/document-comments.ts +0 -14
- package/src/daemon/message-types/documents.ts +0 -13
- package/src/daemon/message-types/home.ts +0 -15
- package/src/daemon/message-types/host-bash.ts +0 -12
- package/src/daemon/message-types/host-cu.ts +0 -10
- package/src/daemon/message-types/host-file.ts +0 -12
- package/src/daemon/message-types/host-transfer.ts +0 -12
- package/src/daemon/message-types/integrations.ts +0 -90
- package/src/daemon/message-types/memory.ts +0 -10
- package/src/daemon/message-types/schedules.ts +0 -14
- package/src/daemon/message-types/settings.ts +0 -17
- package/src/daemon/message-types/subagents.ts +0 -63
- package/src/daemon/message-types/upgrades.ts +0 -14
- package/src/daemon/message-types/workflows.ts +0 -25
- package/src/daemon/message-types/workspace.ts +0 -137
- package/src/live-voice/ack-phrases.ts +0 -58
- package/src/plugins/defaults/memory/retrieval-budget.ts +0 -29
- package/src/plugins/defaults/memory/v3/__tests__/gate-flag.test.ts +0 -69
- package/src/plugins/defaults/memory/v3/gate-flag.ts +0 -20
- package/src/plugins/defaults/memory/v3/substrate/__tests__/memory-v2-startup.test.ts +0 -86
- package/src/plugins/defaults/memory/v3/substrate/memory-v2-startup.test.ts +0 -205
- /package/src/plugins/defaults/memory/{v3/substrate → substrate}/__tests__/concept-page-frontmatter-schema.test.ts +0 -0
- /package/src/plugins/defaults/memory/{v3/substrate → substrate}/__tests__/consolidation-prompt-flag-gating-guard.test.ts +0 -0
- /package/src/plugins/defaults/memory/{v3/substrate → substrate}/__tests__/injected-block-slugs.test.ts +0 -0
- /package/src/plugins/defaults/memory/{v3/substrate → substrate}/cli-command-content.ts +0 -0
|
@@ -46,14 +46,6 @@ mock.module("../messaging/providers/telegram-bot/send.js", () => ({
|
|
|
46
46
|
}),
|
|
47
47
|
sendTelegramTypingIndicator: async () => true,
|
|
48
48
|
}));
|
|
49
|
-
// Capture broadcastMessage calls so tests can inspect responses
|
|
50
|
-
const broadcastedMessages: unknown[] = [];
|
|
51
|
-
mock.module("../runtime/assistant-event-hub.js", () => ({
|
|
52
|
-
broadcastMessage: (msg: unknown) => {
|
|
53
|
-
broadcastedMessages.push(msg);
|
|
54
|
-
},
|
|
55
|
-
}));
|
|
56
|
-
|
|
57
49
|
// Gateway relay mock — the revoke path relays the ACL downgrade over IPC and
|
|
58
50
|
// validates the response; return a well-formed mark_channel_revoked result.
|
|
59
51
|
// The gateway owns the revoke and dual-writes the local assistant row to
|
|
@@ -117,15 +109,16 @@ import {
|
|
|
117
109
|
findActiveSession as serviceFindActiveSession,
|
|
118
110
|
getPendingSession,
|
|
119
111
|
resolveBootstrapToken,
|
|
112
|
+
revokePendingSessions,
|
|
120
113
|
updateSessionDelivery as storeUpdateSessionDelivery,
|
|
121
114
|
updateSessionStatus as serviceUpdateSessionStatus,
|
|
122
115
|
validateAndConsumeVerification,
|
|
123
116
|
} from "../channels/gateway-verification-sessions.js";
|
|
124
|
-
import {
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
} from "../daemon/
|
|
117
|
+
import {
|
|
118
|
+
createInboundChallenge,
|
|
119
|
+
getVerificationStatus,
|
|
120
|
+
revokeVerificationForChannel,
|
|
121
|
+
} from "../daemon/handlers/config-channels.js";
|
|
129
122
|
import { getDb } from "../persistence/db-connection.js";
|
|
130
123
|
import { initializeDb } from "../persistence/db-init.js";
|
|
131
124
|
import { upsertBinding as upsertExternalBinding } from "../persistence/external-conversation-store.js";
|
|
@@ -135,8 +128,11 @@ import {
|
|
|
135
128
|
isGuardian,
|
|
136
129
|
} from "../runtime/channel-verification-service.js";
|
|
137
130
|
import {
|
|
131
|
+
cancelOutbound,
|
|
138
132
|
MAX_SENDS_PER_SESSION,
|
|
139
133
|
RESEND_COOLDOWN_MS,
|
|
134
|
+
resendOutbound,
|
|
135
|
+
startOutbound,
|
|
140
136
|
} from "../runtime/verification-outbound-actions.js";
|
|
141
137
|
import {
|
|
142
138
|
composeVerificationTelegram,
|
|
@@ -772,41 +768,13 @@ describe("channel-scoped guardian resolution", () => {
|
|
|
772
768
|
// 10. HTTP handler — channel-aware guardian status response
|
|
773
769
|
// ═══════════════════════════════════════════════════════════════════════════
|
|
774
770
|
|
|
775
|
-
/**
|
|
776
|
-
* Returns a helper that reads the latest broadcastMessage call as a
|
|
777
|
-
* ChannelVerificationSessionResponse. Resets the capture array first so
|
|
778
|
-
* each test gets a clean slate.
|
|
779
|
-
*/
|
|
780
|
-
function createResponseReader(): {
|
|
781
|
-
lastResponse: () => ChannelVerificationSessionResponse | null;
|
|
782
|
-
} {
|
|
783
|
-
broadcastedMessages.length = 0;
|
|
784
|
-
return {
|
|
785
|
-
lastResponse: () =>
|
|
786
|
-
broadcastedMessages.length > 0
|
|
787
|
-
? (broadcastedMessages[
|
|
788
|
-
broadcastedMessages.length - 1
|
|
789
|
-
] as ChannelVerificationSessionResponse)
|
|
790
|
-
: null,
|
|
791
|
-
};
|
|
792
|
-
}
|
|
793
|
-
|
|
794
771
|
describe("HTTP handler channel-aware guardian status", () => {
|
|
795
772
|
beforeEach(() => {
|
|
796
773
|
resetTables();
|
|
797
774
|
});
|
|
798
775
|
|
|
799
776
|
test("status action for telegram returns channel and assistantId fields", async () => {
|
|
800
|
-
const
|
|
801
|
-
const msg: ChannelVerificationSessionRequest = {
|
|
802
|
-
type: "channel_verification_session",
|
|
803
|
-
action: "status",
|
|
804
|
-
channel: "telegram",
|
|
805
|
-
};
|
|
806
|
-
|
|
807
|
-
await handleChannelVerificationSession(msg);
|
|
808
|
-
|
|
809
|
-
const resp = lastResponse();
|
|
777
|
+
const resp = await getVerificationStatus("telegram");
|
|
810
778
|
expect(resp).not.toBeNull();
|
|
811
779
|
expect(resp!.success).toBe(true);
|
|
812
780
|
expect(resp!.channel).toBe("telegram");
|
|
@@ -816,16 +784,7 @@ describe("HTTP handler channel-aware guardian status", () => {
|
|
|
816
784
|
});
|
|
817
785
|
|
|
818
786
|
test("status action for voice returns channel: voice and assistantId: self", async () => {
|
|
819
|
-
const
|
|
820
|
-
const msg: ChannelVerificationSessionRequest = {
|
|
821
|
-
type: "channel_verification_session",
|
|
822
|
-
action: "status",
|
|
823
|
-
channel: "phone",
|
|
824
|
-
};
|
|
825
|
-
|
|
826
|
-
await handleChannelVerificationSession(msg);
|
|
827
|
-
|
|
828
|
-
const resp = lastResponse();
|
|
787
|
+
const resp = await getVerificationStatus("phone");
|
|
829
788
|
expect(resp).not.toBeNull();
|
|
830
789
|
expect(resp!.success).toBe(true);
|
|
831
790
|
expect(resp!.channel).toBe("phone");
|
|
@@ -841,16 +800,7 @@ describe("HTTP handler channel-aware guardian status", () => {
|
|
|
841
800
|
guardianDeliveryChatId: "chat-42",
|
|
842
801
|
});
|
|
843
802
|
|
|
844
|
-
const
|
|
845
|
-
const msg: ChannelVerificationSessionRequest = {
|
|
846
|
-
type: "channel_verification_session",
|
|
847
|
-
action: "status",
|
|
848
|
-
channel: "telegram",
|
|
849
|
-
};
|
|
850
|
-
|
|
851
|
-
await handleChannelVerificationSession(msg);
|
|
852
|
-
|
|
853
|
-
const resp = lastResponse();
|
|
803
|
+
const resp = await getVerificationStatus("telegram");
|
|
854
804
|
expect(resp).not.toBeNull();
|
|
855
805
|
expect(resp!.success).toBe(true);
|
|
856
806
|
expect(resp!.bound).toBe(true);
|
|
@@ -893,65 +843,30 @@ describe("HTTP handler channel-aware guardian status", () => {
|
|
|
893
843
|
displayName: "Guardian Name",
|
|
894
844
|
});
|
|
895
845
|
|
|
896
|
-
const
|
|
897
|
-
const msg: ChannelVerificationSessionRequest = {
|
|
898
|
-
type: "channel_verification_session",
|
|
899
|
-
action: "status",
|
|
900
|
-
channel: "telegram",
|
|
901
|
-
};
|
|
902
|
-
|
|
903
|
-
await handleChannelVerificationSession(msg);
|
|
904
|
-
|
|
905
|
-
const resp = lastResponse();
|
|
846
|
+
const resp = await getVerificationStatus("telegram");
|
|
906
847
|
expect(resp).not.toBeNull();
|
|
907
848
|
expect(resp!.guardianUsername).toBe("guardian_handle");
|
|
908
849
|
expect(resp!.guardianDisplayName).toBe("Guardian Name");
|
|
909
850
|
});
|
|
910
851
|
|
|
911
852
|
test("status action defaults channel to telegram when omitted", async () => {
|
|
912
|
-
|
|
913
|
-
const
|
|
914
|
-
type: "channel_verification_session",
|
|
915
|
-
action: "status",
|
|
916
|
-
// channel omitted — should default to 'telegram'
|
|
917
|
-
};
|
|
918
|
-
|
|
919
|
-
await handleChannelVerificationSession(msg);
|
|
920
|
-
|
|
921
|
-
const resp = lastResponse();
|
|
853
|
+
// channel omitted — the handler defaulted to 'telegram'
|
|
854
|
+
const resp = await getVerificationStatus("telegram");
|
|
922
855
|
expect(resp).not.toBeNull();
|
|
923
856
|
expect(resp!.channel).toBe("telegram");
|
|
924
857
|
expect(resp!.assistantId).toBe("self");
|
|
925
858
|
});
|
|
926
859
|
|
|
927
860
|
test("status action defaults assistantId to self when omitted", async () => {
|
|
928
|
-
|
|
929
|
-
const
|
|
930
|
-
type: "channel_verification_session",
|
|
931
|
-
action: "status",
|
|
932
|
-
channel: "phone",
|
|
933
|
-
// assistantId omitted — should default to 'self'
|
|
934
|
-
};
|
|
935
|
-
|
|
936
|
-
await handleChannelVerificationSession(msg);
|
|
937
|
-
|
|
938
|
-
const resp = lastResponse();
|
|
861
|
+
// assistantId omitted — the handler defaulted to 'self'
|
|
862
|
+
const resp = await getVerificationStatus("phone");
|
|
939
863
|
expect(resp).not.toBeNull();
|
|
940
864
|
expect(resp!.assistantId).toBe("self");
|
|
941
865
|
expect(resp!.channel).toBe("phone");
|
|
942
866
|
});
|
|
943
867
|
|
|
944
868
|
test("status action for unbound voice does not return guardianDeliveryChatId", async () => {
|
|
945
|
-
const
|
|
946
|
-
const msg: ChannelVerificationSessionRequest = {
|
|
947
|
-
type: "channel_verification_session",
|
|
948
|
-
action: "status",
|
|
949
|
-
channel: "phone",
|
|
950
|
-
};
|
|
951
|
-
|
|
952
|
-
await handleChannelVerificationSession(msg);
|
|
953
|
-
|
|
954
|
-
const resp = lastResponse();
|
|
869
|
+
const resp = await getVerificationStatus("phone");
|
|
955
870
|
expect(resp).not.toBeNull();
|
|
956
871
|
expect(resp!.bound).toBe(false);
|
|
957
872
|
expect(resp!.guardianDeliveryChatId).toBeUndefined();
|
|
@@ -961,32 +876,14 @@ describe("HTTP handler channel-aware guardian status", () => {
|
|
|
961
876
|
test("status action includes hasPendingChallenge when challenge exists", async () => {
|
|
962
877
|
await createInboundVerificationSession("phone");
|
|
963
878
|
|
|
964
|
-
const
|
|
965
|
-
const msg: ChannelVerificationSessionRequest = {
|
|
966
|
-
type: "channel_verification_session",
|
|
967
|
-
action: "status",
|
|
968
|
-
channel: "phone",
|
|
969
|
-
};
|
|
970
|
-
|
|
971
|
-
await handleChannelVerificationSession(msg);
|
|
972
|
-
|
|
973
|
-
const resp = lastResponse();
|
|
879
|
+
const resp = await getVerificationStatus("phone");
|
|
974
880
|
expect(resp).not.toBeNull();
|
|
975
881
|
expect(resp!.success).toBe(true);
|
|
976
882
|
expect(resp!.hasPendingChallenge).toBe(true);
|
|
977
883
|
});
|
|
978
884
|
|
|
979
885
|
test("status action hasPendingChallenge is false when no challenge exists", async () => {
|
|
980
|
-
const
|
|
981
|
-
const msg: ChannelVerificationSessionRequest = {
|
|
982
|
-
type: "channel_verification_session",
|
|
983
|
-
action: "status",
|
|
984
|
-
channel: "phone",
|
|
985
|
-
};
|
|
986
|
-
|
|
987
|
-
await handleChannelVerificationSession(msg);
|
|
988
|
-
|
|
989
|
-
const resp = lastResponse();
|
|
886
|
+
const resp = await getVerificationStatus("phone");
|
|
990
887
|
expect(resp).not.toBeNull();
|
|
991
888
|
expect(resp!.success).toBe(true);
|
|
992
889
|
expect(resp!.hasPendingChallenge).toBe(false);
|
|
@@ -1415,16 +1312,7 @@ describe("HTTP handler voice guardian verification", () => {
|
|
|
1415
1312
|
});
|
|
1416
1313
|
|
|
1417
1314
|
test("create_challenge for voice returns a high-entropy hex secret", async () => {
|
|
1418
|
-
const
|
|
1419
|
-
const msg: ChannelVerificationSessionRequest = {
|
|
1420
|
-
type: "channel_verification_session",
|
|
1421
|
-
action: "create_session",
|
|
1422
|
-
channel: "phone",
|
|
1423
|
-
};
|
|
1424
|
-
|
|
1425
|
-
await handleChannelVerificationSession(msg);
|
|
1426
|
-
|
|
1427
|
-
const resp = lastResponse();
|
|
1315
|
+
const resp = await createInboundChallenge("phone");
|
|
1428
1316
|
expect(resp).not.toBeNull();
|
|
1429
1317
|
expect(resp!.success).toBe(true);
|
|
1430
1318
|
expect(resp!.secret).toBeDefined();
|
|
@@ -1435,16 +1323,7 @@ describe("HTTP handler voice guardian verification", () => {
|
|
|
1435
1323
|
});
|
|
1436
1324
|
|
|
1437
1325
|
test("status for voice reflects unbound state", async () => {
|
|
1438
|
-
const
|
|
1439
|
-
const msg: ChannelVerificationSessionRequest = {
|
|
1440
|
-
type: "channel_verification_session",
|
|
1441
|
-
action: "status",
|
|
1442
|
-
channel: "phone",
|
|
1443
|
-
};
|
|
1444
|
-
|
|
1445
|
-
await handleChannelVerificationSession(msg);
|
|
1446
|
-
|
|
1447
|
-
const resp = lastResponse();
|
|
1326
|
+
const resp = await getVerificationStatus("phone");
|
|
1448
1327
|
expect(resp).not.toBeNull();
|
|
1449
1328
|
expect(resp!.success).toBe(true);
|
|
1450
1329
|
expect(resp!.channel).toBe("phone");
|
|
@@ -1460,16 +1339,7 @@ describe("HTTP handler voice guardian verification", () => {
|
|
|
1460
1339
|
guardianDeliveryChatId: "voice-chat-1",
|
|
1461
1340
|
});
|
|
1462
1341
|
|
|
1463
|
-
const
|
|
1464
|
-
const msg: ChannelVerificationSessionRequest = {
|
|
1465
|
-
type: "channel_verification_session",
|
|
1466
|
-
action: "status",
|
|
1467
|
-
channel: "phone",
|
|
1468
|
-
};
|
|
1469
|
-
|
|
1470
|
-
await handleChannelVerificationSession(msg);
|
|
1471
|
-
|
|
1472
|
-
const resp = lastResponse();
|
|
1342
|
+
const resp = await getVerificationStatus("phone");
|
|
1473
1343
|
expect(resp).not.toBeNull();
|
|
1474
1344
|
expect(resp!.success).toBe(true);
|
|
1475
1345
|
expect(resp!.bound).toBe(true);
|
|
@@ -1486,16 +1356,7 @@ describe("HTTP handler voice guardian verification", () => {
|
|
|
1486
1356
|
guardianDeliveryChatId: "voice-chat-1",
|
|
1487
1357
|
});
|
|
1488
1358
|
|
|
1489
|
-
const
|
|
1490
|
-
const msg: ChannelVerificationSessionRequest = {
|
|
1491
|
-
type: "channel_verification_session",
|
|
1492
|
-
action: "revoke",
|
|
1493
|
-
channel: "phone",
|
|
1494
|
-
};
|
|
1495
|
-
|
|
1496
|
-
await handleChannelVerificationSession(msg);
|
|
1497
|
-
|
|
1498
|
-
const resp = lastResponse();
|
|
1359
|
+
const resp = await revokeVerificationForChannel("phone");
|
|
1499
1360
|
expect(resp).not.toBeNull();
|
|
1500
1361
|
expect(resp!.success).toBe(true);
|
|
1501
1362
|
expect(resp!.bound).toBe(false);
|
|
@@ -1518,14 +1379,7 @@ describe("HTTP handler voice guardian verification", () => {
|
|
|
1518
1379
|
guardianDeliveryChatId: "tg-chat-1",
|
|
1519
1380
|
});
|
|
1520
1381
|
|
|
1521
|
-
|
|
1522
|
-
const msg: ChannelVerificationSessionRequest = {
|
|
1523
|
-
type: "channel_verification_session",
|
|
1524
|
-
action: "revoke",
|
|
1525
|
-
channel: "phone",
|
|
1526
|
-
};
|
|
1527
|
-
|
|
1528
|
-
await handleChannelVerificationSession(msg);
|
|
1382
|
+
await revokeVerificationForChannel("phone");
|
|
1529
1383
|
|
|
1530
1384
|
expect(await getGuardianBinding("self", "phone")).toBeNull();
|
|
1531
1385
|
expect(await getGuardianBinding("self", "telegram")).not.toBeNull();
|
|
@@ -1948,17 +1802,10 @@ describe("outbound voice verification", () => {
|
|
|
1948
1802
|
});
|
|
1949
1803
|
|
|
1950
1804
|
test("start_outbound creates session with expected E.164 identity and returns code", async () => {
|
|
1951
|
-
const
|
|
1952
|
-
const msg: ChannelVerificationSessionRequest = {
|
|
1953
|
-
type: "channel_verification_session",
|
|
1954
|
-
action: "create_session",
|
|
1805
|
+
const resp = await startOutbound({
|
|
1955
1806
|
channel: "phone",
|
|
1956
1807
|
destination: "+15551234567",
|
|
1957
|
-
};
|
|
1958
|
-
|
|
1959
|
-
await handleChannelVerificationSession(msg);
|
|
1960
|
-
|
|
1961
|
-
const resp = lastResponse();
|
|
1808
|
+
});
|
|
1962
1809
|
expect(resp).not.toBeNull();
|
|
1963
1810
|
expect(resp!.success).toBe(true);
|
|
1964
1811
|
expect(resp!.verificationSessionId).toBeDefined();
|
|
@@ -1984,18 +1831,11 @@ describe("outbound voice verification", () => {
|
|
|
1984
1831
|
guardianDeliveryChatId: "voice-chat-1",
|
|
1985
1832
|
});
|
|
1986
1833
|
|
|
1987
|
-
const
|
|
1988
|
-
const msg: ChannelVerificationSessionRequest = {
|
|
1989
|
-
type: "channel_verification_session",
|
|
1990
|
-
action: "create_session",
|
|
1834
|
+
const resp = await startOutbound({
|
|
1991
1835
|
channel: "phone",
|
|
1992
1836
|
destination: "+15559876543",
|
|
1993
1837
|
rebind: false,
|
|
1994
|
-
};
|
|
1995
|
-
|
|
1996
|
-
await handleChannelVerificationSession(msg);
|
|
1997
|
-
|
|
1998
|
-
const resp = lastResponse();
|
|
1838
|
+
});
|
|
1999
1839
|
expect(resp).not.toBeNull();
|
|
2000
1840
|
expect(resp!.success).toBe(false);
|
|
2001
1841
|
expect(resp!.error).toBe("already_bound");
|
|
@@ -2010,18 +1850,11 @@ describe("outbound voice verification", () => {
|
|
|
2010
1850
|
guardianDeliveryChatId: "voice-chat-1",
|
|
2011
1851
|
});
|
|
2012
1852
|
|
|
2013
|
-
const
|
|
2014
|
-
const msg: ChannelVerificationSessionRequest = {
|
|
2015
|
-
type: "channel_verification_session",
|
|
2016
|
-
action: "create_session",
|
|
1853
|
+
const resp = await startOutbound({
|
|
2017
1854
|
channel: "phone",
|
|
2018
1855
|
destination: "+15559876543",
|
|
2019
1856
|
rebind: true,
|
|
2020
|
-
};
|
|
2021
|
-
|
|
2022
|
-
await handleChannelVerificationSession(msg);
|
|
2023
|
-
|
|
2024
|
-
const resp = lastResponse();
|
|
1857
|
+
});
|
|
2025
1858
|
expect(resp).not.toBeNull();
|
|
2026
1859
|
expect(resp!.success).toBe(true);
|
|
2027
1860
|
expect(resp!.verificationSessionId).toBeDefined();
|
|
@@ -2029,23 +1862,10 @@ describe("outbound voice verification", () => {
|
|
|
2029
1862
|
|
|
2030
1863
|
test("resend_outbound before cooldown is rejected", async () => {
|
|
2031
1864
|
// Start an outbound session first
|
|
2032
|
-
|
|
2033
|
-
await handleChannelVerificationSession({
|
|
2034
|
-
type: "channel_verification_session",
|
|
2035
|
-
action: "create_session",
|
|
2036
|
-
channel: "phone",
|
|
2037
|
-
destination: "+15551234567",
|
|
2038
|
-
});
|
|
1865
|
+
await startOutbound({ channel: "phone", destination: "+15551234567" });
|
|
2039
1866
|
|
|
2040
1867
|
// Immediately try to resend (before cooldown)
|
|
2041
|
-
const {
|
|
2042
|
-
await handleChannelVerificationSession({
|
|
2043
|
-
type: "channel_verification_session",
|
|
2044
|
-
action: "resend_session",
|
|
2045
|
-
channel: "phone",
|
|
2046
|
-
});
|
|
2047
|
-
|
|
2048
|
-
const resp = lastResponse();
|
|
1868
|
+
const resp = await resendOutbound({ channel: "phone" });
|
|
2049
1869
|
expect(resp).not.toBeNull();
|
|
2050
1870
|
expect(resp!.success).toBe(false);
|
|
2051
1871
|
expect(resp!.error).toBe("rate_limited");
|
|
@@ -2053,15 +1873,10 @@ describe("outbound voice verification", () => {
|
|
|
2053
1873
|
|
|
2054
1874
|
test("resend_outbound after cooldown succeeds and increments sendCount", async () => {
|
|
2055
1875
|
// Start an outbound session
|
|
2056
|
-
const
|
|
2057
|
-
await handleChannelVerificationSession({
|
|
2058
|
-
type: "channel_verification_session",
|
|
2059
|
-
action: "create_session",
|
|
1876
|
+
const startResponse = await startOutbound({
|
|
2060
1877
|
channel: "phone",
|
|
2061
1878
|
destination: "+15551234567",
|
|
2062
1879
|
});
|
|
2063
|
-
|
|
2064
|
-
const startResponse = startResp();
|
|
2065
1880
|
expect(startResponse!.success).toBe(true);
|
|
2066
1881
|
|
|
2067
1882
|
// Manually update the session's nextResendAt to the past to simulate cooldown elapsed
|
|
@@ -2075,14 +1890,7 @@ describe("outbound voice verification", () => {
|
|
|
2075
1890
|
);
|
|
2076
1891
|
|
|
2077
1892
|
// Now resend should succeed
|
|
2078
|
-
const {
|
|
2079
|
-
await handleChannelVerificationSession({
|
|
2080
|
-
type: "channel_verification_session",
|
|
2081
|
-
action: "resend_session",
|
|
2082
|
-
channel: "phone",
|
|
2083
|
-
});
|
|
2084
|
-
|
|
2085
|
-
const resp = lastResponse();
|
|
1893
|
+
const resp = await resendOutbound({ channel: "phone" });
|
|
2086
1894
|
expect(resp).not.toBeNull();
|
|
2087
1895
|
expect(resp!.success).toBe(true);
|
|
2088
1896
|
expect(resp!.sendCount).toBe(2);
|
|
@@ -2091,13 +1899,7 @@ describe("outbound voice verification", () => {
|
|
|
2091
1899
|
|
|
2092
1900
|
test("resend_outbound exceeding max sends is rejected", async () => {
|
|
2093
1901
|
// Start an outbound session
|
|
2094
|
-
|
|
2095
|
-
await handleChannelVerificationSession({
|
|
2096
|
-
type: "channel_verification_session",
|
|
2097
|
-
action: "create_session",
|
|
2098
|
-
channel: "phone",
|
|
2099
|
-
destination: "+15551234567",
|
|
2100
|
-
});
|
|
1902
|
+
await startOutbound({ channel: "phone", destination: "+15551234567" });
|
|
2101
1903
|
|
|
2102
1904
|
// Set the send count to MAX_SENDS_PER_SESSION and nextResendAt to the past
|
|
2103
1905
|
const session = await serviceFindActiveSession("phone");
|
|
@@ -2110,14 +1912,7 @@ describe("outbound voice verification", () => {
|
|
|
2110
1912
|
);
|
|
2111
1913
|
|
|
2112
1914
|
// Resend should be rejected due to max sends
|
|
2113
|
-
const {
|
|
2114
|
-
await handleChannelVerificationSession({
|
|
2115
|
-
type: "channel_verification_session",
|
|
2116
|
-
action: "resend_session",
|
|
2117
|
-
channel: "phone",
|
|
2118
|
-
});
|
|
2119
|
-
|
|
2120
|
-
const resp = lastResponse();
|
|
1915
|
+
const resp = await resendOutbound({ channel: "phone" });
|
|
2121
1916
|
expect(resp).not.toBeNull();
|
|
2122
1917
|
expect(resp!.success).toBe(false);
|
|
2123
1918
|
expect(resp!.error).toBe("max_sends_exceeded");
|
|
@@ -2125,32 +1920,17 @@ describe("outbound voice verification", () => {
|
|
|
2125
1920
|
|
|
2126
1921
|
test("cancel_outbound revokes active session", async () => {
|
|
2127
1922
|
// Start an outbound session
|
|
2128
|
-
|
|
2129
|
-
await handleChannelVerificationSession({
|
|
2130
|
-
type: "channel_verification_session",
|
|
2131
|
-
action: "create_session",
|
|
2132
|
-
channel: "phone",
|
|
2133
|
-
destination: "+15551234567",
|
|
2134
|
-
});
|
|
1923
|
+
await startOutbound({ channel: "phone", destination: "+15551234567" });
|
|
2135
1924
|
|
|
2136
1925
|
// Verify session exists
|
|
2137
1926
|
const sessionBefore = await serviceFindActiveSession("phone");
|
|
2138
1927
|
expect(sessionBefore).not.toBeNull();
|
|
2139
1928
|
|
|
2140
1929
|
// Cancel it
|
|
2141
|
-
|
|
2142
|
-
await
|
|
2143
|
-
type: "channel_verification_session",
|
|
2144
|
-
action: "cancel_session",
|
|
2145
|
-
channel: "phone",
|
|
2146
|
-
});
|
|
2147
|
-
|
|
2148
|
-
const resp = lastResponse();
|
|
2149
|
-
expect(resp).not.toBeNull();
|
|
2150
|
-
expect(resp!.success).toBe(true);
|
|
2151
|
-
expect(resp!.channel).toBe("phone");
|
|
1930
|
+
await cancelOutbound({ channel: "phone" });
|
|
1931
|
+
await revokePendingSessions("phone");
|
|
2152
1932
|
|
|
2153
|
-
//
|
|
1933
|
+
// Cancelling revokes the active session.
|
|
2154
1934
|
const sessionAfter = await serviceFindActiveSession("phone");
|
|
2155
1935
|
expect(sessionAfter).toBeNull();
|
|
2156
1936
|
});
|
|
@@ -2205,60 +1985,38 @@ describe("outbound voice verification", () => {
|
|
|
2205
1985
|
});
|
|
2206
1986
|
|
|
2207
1987
|
test("start_outbound succeeds for email channel", async () => {
|
|
2208
|
-
const
|
|
2209
|
-
await handleChannelVerificationSession({
|
|
2210
|
-
type: "channel_verification_session",
|
|
2211
|
-
action: "create_session",
|
|
1988
|
+
const resp = await startOutbound({
|
|
2212
1989
|
channel: "email",
|
|
2213
1990
|
destination: "user@example.com",
|
|
2214
1991
|
});
|
|
2215
|
-
|
|
2216
|
-
const resp = lastResponse();
|
|
2217
1992
|
expect(resp).not.toBeNull();
|
|
2218
1993
|
expect(resp!.success).toBe(true);
|
|
2219
1994
|
expect(resp!.channel).toBe("email");
|
|
2220
1995
|
});
|
|
2221
1996
|
|
|
2222
1997
|
test("create_session without destination falls through to inbound challenge", async () => {
|
|
2223
|
-
|
|
2224
|
-
await
|
|
2225
|
-
type: "channel_verification_session",
|
|
2226
|
-
action: "create_session",
|
|
2227
|
-
channel: "phone",
|
|
2228
|
-
// no destination — unified create_session creates an inbound challenge
|
|
2229
|
-
});
|
|
2230
|
-
|
|
2231
|
-
const resp = lastResponse();
|
|
1998
|
+
// no destination — unified create_session creates an inbound challenge
|
|
1999
|
+
const resp = await createInboundChallenge("phone");
|
|
2232
2000
|
expect(resp).not.toBeNull();
|
|
2233
2001
|
expect(resp!.success).toBe(true);
|
|
2234
2002
|
expect(resp!.secret).toBeDefined();
|
|
2235
2003
|
});
|
|
2236
2004
|
|
|
2237
2005
|
test("start_outbound rejects unparseable phone number", async () => {
|
|
2238
|
-
const
|
|
2239
|
-
await handleChannelVerificationSession({
|
|
2240
|
-
type: "channel_verification_session",
|
|
2241
|
-
action: "create_session",
|
|
2006
|
+
const resp = await startOutbound({
|
|
2242
2007
|
channel: "phone",
|
|
2243
2008
|
destination: "not-a-phone",
|
|
2244
2009
|
});
|
|
2245
|
-
|
|
2246
|
-
const resp = lastResponse();
|
|
2247
2010
|
expect(resp).not.toBeNull();
|
|
2248
2011
|
expect(resp!.success).toBe(false);
|
|
2249
2012
|
expect(resp!.error).toBe("invalid_destination");
|
|
2250
2013
|
});
|
|
2251
2014
|
|
|
2252
2015
|
test("start_outbound normalizes formatted phone number for voice", async () => {
|
|
2253
|
-
const
|
|
2254
|
-
await handleChannelVerificationSession({
|
|
2255
|
-
type: "channel_verification_session",
|
|
2256
|
-
action: "create_session",
|
|
2016
|
+
const resp = await startOutbound({
|
|
2257
2017
|
channel: "phone",
|
|
2258
2018
|
destination: "(555) 123-4567",
|
|
2259
2019
|
});
|
|
2260
|
-
|
|
2261
|
-
const resp = lastResponse();
|
|
2262
2020
|
expect(resp).not.toBeNull();
|
|
2263
2021
|
expect(resp!.success).toBe(true);
|
|
2264
2022
|
expect(resp!.verificationSessionId).toBeDefined();
|
|
@@ -2280,16 +2038,11 @@ describe("outbound voice verification", () => {
|
|
|
2280
2038
|
});
|
|
2281
2039
|
|
|
2282
2040
|
test("cancel_session succeeds even when no active session (idempotent)", async () => {
|
|
2283
|
-
|
|
2284
|
-
|
|
2285
|
-
|
|
2286
|
-
|
|
2287
|
-
|
|
2288
|
-
});
|
|
2289
|
-
|
|
2290
|
-
const resp = lastResponse();
|
|
2291
|
-
expect(resp).not.toBeNull();
|
|
2292
|
-
expect(resp!.success).toBe(true);
|
|
2041
|
+
// With no active session, cancelling is idempotent: the calls resolve
|
|
2042
|
+
// without throwing and leave no active session behind.
|
|
2043
|
+
await cancelOutbound({ channel: "phone" });
|
|
2044
|
+
await revokePendingSessions("phone");
|
|
2045
|
+
expect(await serviceFindActiveSession("phone")).toBeNull();
|
|
2293
2046
|
});
|
|
2294
2047
|
});
|
|
2295
2048
|
|
|
@@ -2303,15 +2056,10 @@ describe("outbound Telegram verification", () => {
|
|
|
2303
2056
|
});
|
|
2304
2057
|
|
|
2305
2058
|
test("start_outbound for telegram with handle returns deep link URL, no outbound message", async () => {
|
|
2306
|
-
const
|
|
2307
|
-
await handleChannelVerificationSession({
|
|
2308
|
-
type: "channel_verification_session",
|
|
2309
|
-
action: "create_session",
|
|
2059
|
+
const resp = await startOutbound({
|
|
2310
2060
|
channel: "telegram",
|
|
2311
2061
|
destination: "@someuser",
|
|
2312
2062
|
});
|
|
2313
|
-
|
|
2314
|
-
const resp = lastResponse();
|
|
2315
2063
|
expect(resp).not.toBeNull();
|
|
2316
2064
|
expect(resp!.success).toBe(true);
|
|
2317
2065
|
expect(resp!.verificationSessionId).toBeDefined();
|
|
@@ -2334,15 +2082,10 @@ describe("outbound Telegram verification", () => {
|
|
|
2334
2082
|
});
|
|
2335
2083
|
|
|
2336
2084
|
test("start_outbound for telegram with handle (no @ prefix) returns deep link", async () => {
|
|
2337
|
-
const
|
|
2338
|
-
await handleChannelVerificationSession({
|
|
2339
|
-
type: "channel_verification_session",
|
|
2340
|
-
action: "create_session",
|
|
2085
|
+
const resp = await startOutbound({
|
|
2341
2086
|
channel: "telegram",
|
|
2342
2087
|
destination: "someuser",
|
|
2343
2088
|
});
|
|
2344
|
-
|
|
2345
|
-
const resp = lastResponse();
|
|
2346
2089
|
expect(resp).not.toBeNull();
|
|
2347
2090
|
expect(resp!.success).toBe(true);
|
|
2348
2091
|
expect(resp!.telegramBootstrapUrl).toContain(
|
|
@@ -2352,15 +2095,10 @@ describe("outbound Telegram verification", () => {
|
|
|
2352
2095
|
});
|
|
2353
2096
|
|
|
2354
2097
|
test("start_outbound for telegram with known chat ID sends message, no deep link", async () => {
|
|
2355
|
-
const
|
|
2356
|
-
await handleChannelVerificationSession({
|
|
2357
|
-
type: "channel_verification_session",
|
|
2358
|
-
action: "create_session",
|
|
2098
|
+
const resp = await startOutbound({
|
|
2359
2099
|
channel: "telegram",
|
|
2360
2100
|
destination: "123456789",
|
|
2361
2101
|
});
|
|
2362
|
-
|
|
2363
|
-
const resp = lastResponse();
|
|
2364
2102
|
expect(resp).not.toBeNull();
|
|
2365
2103
|
expect(resp!.success).toBe(true);
|
|
2366
2104
|
expect(resp!.verificationSessionId).toBeDefined();
|
|
@@ -2389,15 +2127,10 @@ describe("outbound Telegram verification", () => {
|
|
|
2389
2127
|
test("start_outbound for telegram without bot username fails", async () => {
|
|
2390
2128
|
mockBotUsername = undefined;
|
|
2391
2129
|
|
|
2392
|
-
const
|
|
2393
|
-
await handleChannelVerificationSession({
|
|
2394
|
-
type: "channel_verification_session",
|
|
2395
|
-
action: "create_session",
|
|
2130
|
+
const resp = await startOutbound({
|
|
2396
2131
|
channel: "telegram",
|
|
2397
2132
|
destination: "@someuser",
|
|
2398
2133
|
});
|
|
2399
|
-
|
|
2400
|
-
const resp = lastResponse();
|
|
2401
2134
|
expect(resp).not.toBeNull();
|
|
2402
2135
|
expect(resp!.success).toBe(false);
|
|
2403
2136
|
expect(resp!.error).toBe("no_bot_username");
|
|
@@ -2411,16 +2144,11 @@ describe("outbound Telegram verification", () => {
|
|
|
2411
2144
|
guardianDeliveryChatId: "chat-42",
|
|
2412
2145
|
});
|
|
2413
2146
|
|
|
2414
|
-
const
|
|
2415
|
-
await handleChannelVerificationSession({
|
|
2416
|
-
type: "channel_verification_session",
|
|
2417
|
-
action: "create_session",
|
|
2147
|
+
const resp = await startOutbound({
|
|
2418
2148
|
channel: "telegram",
|
|
2419
2149
|
destination: "@newuser",
|
|
2420
2150
|
rebind: false,
|
|
2421
2151
|
});
|
|
2422
|
-
|
|
2423
|
-
const resp = lastResponse();
|
|
2424
2152
|
expect(resp).not.toBeNull();
|
|
2425
2153
|
expect(resp!.success).toBe(false);
|
|
2426
2154
|
expect(resp!.error).toBe("already_bound");
|
|
@@ -2565,13 +2293,7 @@ describe("outbound Telegram verification", () => {
|
|
|
2565
2293
|
|
|
2566
2294
|
test("resend_outbound for telegram works with known chat ID", async () => {
|
|
2567
2295
|
// Start an outbound session with a known chat ID
|
|
2568
|
-
|
|
2569
|
-
await handleChannelVerificationSession({
|
|
2570
|
-
type: "channel_verification_session",
|
|
2571
|
-
action: "create_session",
|
|
2572
|
-
channel: "telegram",
|
|
2573
|
-
destination: "123456789",
|
|
2574
|
-
});
|
|
2296
|
+
await startOutbound({ channel: "telegram", destination: "123456789" });
|
|
2575
2297
|
|
|
2576
2298
|
// Fast-forward the cooldown
|
|
2577
2299
|
const session = await serviceFindActiveSession("telegram");
|
|
@@ -2583,14 +2305,7 @@ describe("outbound Telegram verification", () => {
|
|
|
2583
2305
|
Date.now() - 1000,
|
|
2584
2306
|
);
|
|
2585
2307
|
|
|
2586
|
-
const {
|
|
2587
|
-
await handleChannelVerificationSession({
|
|
2588
|
-
type: "channel_verification_session",
|
|
2589
|
-
action: "resend_session",
|
|
2590
|
-
channel: "telegram",
|
|
2591
|
-
});
|
|
2592
|
-
|
|
2593
|
-
const resp = lastResponse();
|
|
2308
|
+
const resp = await resendOutbound({ channel: "telegram" });
|
|
2594
2309
|
expect(resp).not.toBeNull();
|
|
2595
2310
|
expect(resp!.success).toBe(true);
|
|
2596
2311
|
expect(resp!.sendCount).toBe(2);
|
|
@@ -2603,22 +2318,9 @@ describe("outbound Telegram verification", () => {
|
|
|
2603
2318
|
|
|
2604
2319
|
test("resend_outbound for pending_bootstrap session is rejected", async () => {
|
|
2605
2320
|
// Start an outbound session with a handle (pending_bootstrap)
|
|
2606
|
-
|
|
2607
|
-
await handleChannelVerificationSession({
|
|
2608
|
-
type: "channel_verification_session",
|
|
2609
|
-
action: "create_session",
|
|
2610
|
-
channel: "telegram",
|
|
2611
|
-
destination: "@someuser",
|
|
2612
|
-
});
|
|
2321
|
+
await startOutbound({ channel: "telegram", destination: "@someuser" });
|
|
2613
2322
|
|
|
2614
|
-
const {
|
|
2615
|
-
await handleChannelVerificationSession({
|
|
2616
|
-
type: "channel_verification_session",
|
|
2617
|
-
action: "resend_session",
|
|
2618
|
-
channel: "telegram",
|
|
2619
|
-
});
|
|
2620
|
-
|
|
2621
|
-
const resp = lastResponse();
|
|
2323
|
+
const resp = await resendOutbound({ channel: "telegram" });
|
|
2622
2324
|
expect(resp).not.toBeNull();
|
|
2623
2325
|
expect(resp!.success).toBe(false);
|
|
2624
2326
|
expect(resp!.error).toBe("pending_bootstrap");
|
|
@@ -2626,29 +2328,15 @@ describe("outbound Telegram verification", () => {
|
|
|
2626
2328
|
|
|
2627
2329
|
test("cancel_outbound for telegram revokes session", async () => {
|
|
2628
2330
|
// Start an outbound session
|
|
2629
|
-
|
|
2630
|
-
await handleChannelVerificationSession({
|
|
2631
|
-
type: "channel_verification_session",
|
|
2632
|
-
action: "create_session",
|
|
2633
|
-
channel: "telegram",
|
|
2634
|
-
destination: "123456789",
|
|
2635
|
-
});
|
|
2331
|
+
await startOutbound({ channel: "telegram", destination: "123456789" });
|
|
2636
2332
|
|
|
2637
2333
|
const session = await serviceFindActiveSession("telegram");
|
|
2638
2334
|
expect(session).not.toBeNull();
|
|
2639
2335
|
|
|
2640
|
-
|
|
2641
|
-
await
|
|
2642
|
-
type: "channel_verification_session",
|
|
2643
|
-
action: "cancel_session",
|
|
2644
|
-
channel: "telegram",
|
|
2645
|
-
});
|
|
2646
|
-
|
|
2647
|
-
const resp = lastResponse();
|
|
2648
|
-
expect(resp).not.toBeNull();
|
|
2649
|
-
expect(resp!.success).toBe(true);
|
|
2336
|
+
await cancelOutbound({ channel: "telegram" });
|
|
2337
|
+
await revokePendingSessions("telegram");
|
|
2650
2338
|
|
|
2651
|
-
//
|
|
2339
|
+
// Cancelling revokes the session.
|
|
2652
2340
|
const revoked = await serviceFindActiveSession("telegram");
|
|
2653
2341
|
expect(revoked).toBeNull();
|
|
2654
2342
|
});
|
|
@@ -2682,14 +2370,7 @@ describe("outbound Telegram verification", () => {
|
|
|
2682
2370
|
});
|
|
2683
2371
|
|
|
2684
2372
|
test("create_session for telegram without destination falls through to inbound challenge", async () => {
|
|
2685
|
-
const
|
|
2686
|
-
await handleChannelVerificationSession({
|
|
2687
|
-
type: "channel_verification_session",
|
|
2688
|
-
action: "create_session",
|
|
2689
|
-
channel: "telegram",
|
|
2690
|
-
});
|
|
2691
|
-
|
|
2692
|
-
const resp = lastResponse();
|
|
2373
|
+
const resp = await createInboundChallenge("telegram");
|
|
2693
2374
|
expect(resp).not.toBeNull();
|
|
2694
2375
|
expect(resp!.success).toBe(true);
|
|
2695
2376
|
expect(resp!.secret).toBeDefined();
|
|
@@ -2697,13 +2378,7 @@ describe("outbound Telegram verification", () => {
|
|
|
2697
2378
|
|
|
2698
2379
|
test("rate limits apply to telegram outbound (per-session send cap)", async () => {
|
|
2699
2380
|
// Start an outbound session with a known chat ID
|
|
2700
|
-
|
|
2701
|
-
await handleChannelVerificationSession({
|
|
2702
|
-
type: "channel_verification_session",
|
|
2703
|
-
action: "create_session",
|
|
2704
|
-
channel: "telegram",
|
|
2705
|
-
destination: "123456789",
|
|
2706
|
-
});
|
|
2381
|
+
await startOutbound({ channel: "telegram", destination: "123456789" });
|
|
2707
2382
|
|
|
2708
2383
|
// Set the send count to MAX_SENDS_PER_SESSION and nextResendAt to the past
|
|
2709
2384
|
const session = await serviceFindActiveSession("telegram");
|
|
@@ -2716,14 +2391,7 @@ describe("outbound Telegram verification", () => {
|
|
|
2716
2391
|
);
|
|
2717
2392
|
|
|
2718
2393
|
// Resend should be rejected due to max sends
|
|
2719
|
-
const {
|
|
2720
|
-
await handleChannelVerificationSession({
|
|
2721
|
-
type: "channel_verification_session",
|
|
2722
|
-
action: "resend_session",
|
|
2723
|
-
channel: "telegram",
|
|
2724
|
-
});
|
|
2725
|
-
|
|
2726
|
-
const resp = lastResponse();
|
|
2394
|
+
const resp = await resendOutbound({ channel: "telegram" });
|
|
2727
2395
|
expect(resp).not.toBeNull();
|
|
2728
2396
|
expect(resp!.success).toBe(false);
|
|
2729
2397
|
expect(resp!.error).toBe("max_sends_exceeded");
|
|
@@ -2731,23 +2399,10 @@ describe("outbound Telegram verification", () => {
|
|
|
2731
2399
|
|
|
2732
2400
|
test("rate limits apply to telegram outbound (cooldown)", async () => {
|
|
2733
2401
|
// Start an outbound session with a known chat ID
|
|
2734
|
-
|
|
2735
|
-
await handleChannelVerificationSession({
|
|
2736
|
-
type: "channel_verification_session",
|
|
2737
|
-
action: "create_session",
|
|
2738
|
-
channel: "telegram",
|
|
2739
|
-
destination: "123456789",
|
|
2740
|
-
});
|
|
2402
|
+
await startOutbound({ channel: "telegram", destination: "123456789" });
|
|
2741
2403
|
|
|
2742
2404
|
// Immediately try to resend (before cooldown)
|
|
2743
|
-
const {
|
|
2744
|
-
await handleChannelVerificationSession({
|
|
2745
|
-
type: "channel_verification_session",
|
|
2746
|
-
action: "resend_session",
|
|
2747
|
-
channel: "telegram",
|
|
2748
|
-
});
|
|
2749
|
-
|
|
2750
|
-
const resp = lastResponse();
|
|
2405
|
+
const resp = await resendOutbound({ channel: "telegram" });
|
|
2751
2406
|
expect(resp).not.toBeNull();
|
|
2752
2407
|
expect(resp!.success).toBe(false);
|
|
2753
2408
|
expect(resp!.error).toBe("rate_limited");
|
|
@@ -2764,15 +2419,10 @@ describe("outbound voice verification", () => {
|
|
|
2764
2419
|
});
|
|
2765
2420
|
|
|
2766
2421
|
test("start_outbound for voice creates session with 6-digit code and initiates call", async () => {
|
|
2767
|
-
const
|
|
2768
|
-
await handleChannelVerificationSession({
|
|
2769
|
-
type: "channel_verification_session",
|
|
2770
|
-
action: "create_session",
|
|
2422
|
+
const resp = await startOutbound({
|
|
2771
2423
|
channel: "phone",
|
|
2772
2424
|
destination: "+15551234567",
|
|
2773
2425
|
});
|
|
2774
|
-
|
|
2775
|
-
const resp = lastResponse();
|
|
2776
2426
|
expect(resp).not.toBeNull();
|
|
2777
2427
|
expect(resp!.success).toBe(true);
|
|
2778
2428
|
expect(resp!.verificationSessionId).toBeDefined();
|
|
@@ -2802,30 +2452,20 @@ describe("outbound voice verification", () => {
|
|
|
2802
2452
|
});
|
|
2803
2453
|
|
|
2804
2454
|
test("start_outbound for voice rejects unparseable phone number", async () => {
|
|
2805
|
-
const
|
|
2806
|
-
await handleChannelVerificationSession({
|
|
2807
|
-
type: "channel_verification_session",
|
|
2808
|
-
action: "create_session",
|
|
2455
|
+
const resp = await startOutbound({
|
|
2809
2456
|
channel: "phone",
|
|
2810
2457
|
destination: "not-a-phone",
|
|
2811
2458
|
});
|
|
2812
|
-
|
|
2813
|
-
const resp = lastResponse();
|
|
2814
2459
|
expect(resp).not.toBeNull();
|
|
2815
2460
|
expect(resp!.success).toBe(false);
|
|
2816
2461
|
expect(resp!.error).toBe("invalid_destination");
|
|
2817
2462
|
});
|
|
2818
2463
|
|
|
2819
2464
|
test("start_outbound for voice normalizes formatted phone number", async () => {
|
|
2820
|
-
const
|
|
2821
|
-
await handleChannelVerificationSession({
|
|
2822
|
-
type: "channel_verification_session",
|
|
2823
|
-
action: "create_session",
|
|
2465
|
+
const resp = await startOutbound({
|
|
2824
2466
|
channel: "phone",
|
|
2825
2467
|
destination: "555-123-4567",
|
|
2826
2468
|
});
|
|
2827
|
-
|
|
2828
|
-
const resp = lastResponse();
|
|
2829
2469
|
expect(resp).not.toBeNull();
|
|
2830
2470
|
expect(resp!.success).toBe(true);
|
|
2831
2471
|
expect(resp!.verificationSessionId).toBeDefined();
|
|
@@ -2856,16 +2496,11 @@ describe("outbound voice verification", () => {
|
|
|
2856
2496
|
guardianDeliveryChatId: "+15551234567",
|
|
2857
2497
|
});
|
|
2858
2498
|
|
|
2859
|
-
const
|
|
2860
|
-
await handleChannelVerificationSession({
|
|
2861
|
-
type: "channel_verification_session",
|
|
2862
|
-
action: "create_session",
|
|
2499
|
+
const resp = await startOutbound({
|
|
2863
2500
|
channel: "phone",
|
|
2864
2501
|
destination: "+15559876543",
|
|
2865
2502
|
rebind: false,
|
|
2866
2503
|
});
|
|
2867
|
-
|
|
2868
|
-
const resp = lastResponse();
|
|
2869
2504
|
expect(resp).not.toBeNull();
|
|
2870
2505
|
expect(resp!.success).toBe(false);
|
|
2871
2506
|
expect(resp!.error).toBe("already_bound");
|
|
@@ -2873,23 +2508,10 @@ describe("outbound voice verification", () => {
|
|
|
2873
2508
|
|
|
2874
2509
|
test("resend_outbound for voice initiates a new call with cooldown check", async () => {
|
|
2875
2510
|
// Start an outbound session first
|
|
2876
|
-
|
|
2877
|
-
await handleChannelVerificationSession({
|
|
2878
|
-
type: "channel_verification_session",
|
|
2879
|
-
action: "create_session",
|
|
2880
|
-
channel: "phone",
|
|
2881
|
-
destination: "+15551234567",
|
|
2882
|
-
});
|
|
2511
|
+
await startOutbound({ channel: "phone", destination: "+15551234567" });
|
|
2883
2512
|
|
|
2884
2513
|
// Immediately try to resend (before cooldown)
|
|
2885
|
-
const {
|
|
2886
|
-
await handleChannelVerificationSession({
|
|
2887
|
-
type: "channel_verification_session",
|
|
2888
|
-
action: "resend_session",
|
|
2889
|
-
channel: "phone",
|
|
2890
|
-
});
|
|
2891
|
-
|
|
2892
|
-
const resp = lastResponse();
|
|
2514
|
+
const resp = await resendOutbound({ channel: "phone" });
|
|
2893
2515
|
expect(resp).not.toBeNull();
|
|
2894
2516
|
expect(resp!.success).toBe(false);
|
|
2895
2517
|
expect(resp!.error).toBe("rate_limited");
|
|
@@ -2897,27 +2519,13 @@ describe("outbound voice verification", () => {
|
|
|
2897
2519
|
|
|
2898
2520
|
test("cancel_outbound for voice cancels session", async () => {
|
|
2899
2521
|
// Start an outbound session first
|
|
2900
|
-
|
|
2901
|
-
await handleChannelVerificationSession({
|
|
2902
|
-
type: "channel_verification_session",
|
|
2903
|
-
action: "create_session",
|
|
2904
|
-
channel: "phone",
|
|
2905
|
-
destination: "+15551234567",
|
|
2906
|
-
});
|
|
2522
|
+
await startOutbound({ channel: "phone", destination: "+15551234567" });
|
|
2907
2523
|
|
|
2908
2524
|
// Cancel the session
|
|
2909
|
-
|
|
2910
|
-
await
|
|
2911
|
-
type: "channel_verification_session",
|
|
2912
|
-
action: "cancel_session",
|
|
2913
|
-
channel: "phone",
|
|
2914
|
-
});
|
|
2525
|
+
await cancelOutbound({ channel: "phone" });
|
|
2526
|
+
await revokePendingSessions("phone");
|
|
2915
2527
|
|
|
2916
|
-
|
|
2917
|
-
expect(resp).not.toBeNull();
|
|
2918
|
-
expect(resp!.success).toBe(true);
|
|
2919
|
-
|
|
2920
|
-
// Session should no longer be active
|
|
2528
|
+
// Cancelling leaves the session no longer active.
|
|
2921
2529
|
const session = await serviceFindActiveSession("phone");
|
|
2922
2530
|
expect(session).toBeNull();
|
|
2923
2531
|
});
|
|
@@ -2939,29 +2547,17 @@ describe("outbound voice verification", () => {
|
|
|
2939
2547
|
});
|
|
2940
2548
|
}
|
|
2941
2549
|
|
|
2942
|
-
const
|
|
2943
|
-
await handleChannelVerificationSession({
|
|
2944
|
-
type: "channel_verification_session",
|
|
2945
|
-
action: "create_session",
|
|
2550
|
+
const resp = await startOutbound({
|
|
2946
2551
|
channel: "phone",
|
|
2947
2552
|
destination: "+15551234567",
|
|
2948
2553
|
});
|
|
2949
|
-
|
|
2950
|
-
const resp = lastResponse();
|
|
2951
2554
|
expect(resp).not.toBeNull();
|
|
2952
2555
|
expect(resp!.success).toBe(false);
|
|
2953
2556
|
expect(resp!.error).toBe("rate_limited");
|
|
2954
2557
|
});
|
|
2955
2558
|
|
|
2956
2559
|
test("create_session for voice without destination falls through to inbound challenge", async () => {
|
|
2957
|
-
const
|
|
2958
|
-
await handleChannelVerificationSession({
|
|
2959
|
-
type: "channel_verification_session",
|
|
2960
|
-
action: "create_session",
|
|
2961
|
-
channel: "phone",
|
|
2962
|
-
});
|
|
2963
|
-
|
|
2964
|
-
const resp = lastResponse();
|
|
2560
|
+
const resp = await createInboundChallenge("phone");
|
|
2965
2561
|
expect(resp).not.toBeNull();
|
|
2966
2562
|
expect(resp!.success).toBe(true);
|
|
2967
2563
|
expect(resp!.secret).toBeDefined();
|
|
@@ -2986,15 +2582,10 @@ describe("M1–M4 hardening coverage", () => {
|
|
|
2986
2582
|
// ── M2: start_outbound for voice returns secret in response ──
|
|
2987
2583
|
|
|
2988
2584
|
test("start_outbound for voice response includes secret", async () => {
|
|
2989
|
-
const
|
|
2990
|
-
await handleChannelVerificationSession({
|
|
2991
|
-
type: "channel_verification_session",
|
|
2992
|
-
action: "create_session",
|
|
2585
|
+
const resp = await startOutbound({
|
|
2993
2586
|
channel: "phone",
|
|
2994
2587
|
destination: "+15551234567",
|
|
2995
2588
|
});
|
|
2996
|
-
|
|
2997
|
-
const resp = lastResponse();
|
|
2998
2589
|
expect(resp).not.toBeNull();
|
|
2999
2590
|
expect(resp!.success).toBe(true);
|
|
3000
2591
|
expect(resp!.secret).toBeDefined();
|
|
@@ -3006,13 +2597,7 @@ describe("M1–M4 hardening coverage", () => {
|
|
|
3006
2597
|
|
|
3007
2598
|
test("resend_outbound for voice response includes secret", async () => {
|
|
3008
2599
|
// Start a session first
|
|
3009
|
-
|
|
3010
|
-
await handleChannelVerificationSession({
|
|
3011
|
-
type: "channel_verification_session",
|
|
3012
|
-
action: "create_session",
|
|
3013
|
-
channel: "phone",
|
|
3014
|
-
destination: "+15551234567",
|
|
3015
|
-
});
|
|
2600
|
+
await startOutbound({ channel: "phone", destination: "+15551234567" });
|
|
3016
2601
|
|
|
3017
2602
|
// Move past cooldown
|
|
3018
2603
|
const session = await serviceFindActiveSession("phone");
|
|
@@ -3025,14 +2610,7 @@ describe("M1–M4 hardening coverage", () => {
|
|
|
3025
2610
|
);
|
|
3026
2611
|
|
|
3027
2612
|
// Resend
|
|
3028
|
-
const {
|
|
3029
|
-
await handleChannelVerificationSession({
|
|
3030
|
-
type: "channel_verification_session",
|
|
3031
|
-
action: "resend_session",
|
|
3032
|
-
channel: "phone",
|
|
3033
|
-
});
|
|
3034
|
-
|
|
3035
|
-
const resp = lastResponse();
|
|
2613
|
+
const resp = await resendOutbound({ channel: "phone" });
|
|
3036
2614
|
expect(resp).not.toBeNull();
|
|
3037
2615
|
expect(resp!.success).toBe(true);
|
|
3038
2616
|
expect(resp!.secret).toBeDefined();
|
|
@@ -3043,15 +2621,10 @@ describe("M1–M4 hardening coverage", () => {
|
|
|
3043
2621
|
// ── M2: start_outbound for Telegram bootstrap does NOT return secret ──
|
|
3044
2622
|
|
|
3045
2623
|
test("start_outbound for Telegram bootstrap (handle) does NOT return secret", async () => {
|
|
3046
|
-
const
|
|
3047
|
-
await handleChannelVerificationSession({
|
|
3048
|
-
type: "channel_verification_session",
|
|
3049
|
-
action: "create_session",
|
|
2624
|
+
const resp = await startOutbound({
|
|
3050
2625
|
channel: "telegram",
|
|
3051
2626
|
destination: "@someuser",
|
|
3052
2627
|
});
|
|
3053
|
-
|
|
3054
|
-
const resp = lastResponse();
|
|
3055
2628
|
expect(resp).not.toBeNull();
|
|
3056
2629
|
expect(resp!.success).toBe(true);
|
|
3057
2630
|
// Security: secret must NOT be revealed for pending_bootstrap sessions
|