@vellumai/assistant 0.4.16 → 0.4.18
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/Dockerfile +6 -6
- package/README.md +1 -2
- package/eslint.config.mjs +2 -2
- package/package.json +1 -1
- package/src/__tests__/access-request-decision.test.ts +128 -120
- package/src/__tests__/account-registry.test.ts +121 -110
- package/src/__tests__/active-skill-tools.test.ts +200 -172
- package/src/__tests__/actor-token-service.test.ts +341 -274
- package/src/__tests__/agent-loop-thinking.test.ts +28 -19
- package/src/__tests__/agent-loop.test.ts +798 -378
- package/src/__tests__/anthropic-provider.test.ts +405 -247
- package/src/__tests__/app-builder-tool-scripts.test.ts +97 -97
- package/src/__tests__/app-bundler.test.ts +112 -79
- package/src/__tests__/app-executors.test.ts +205 -178
- package/src/__tests__/app-git-history.test.ts +90 -73
- package/src/__tests__/app-git-service.test.ts +67 -53
- package/src/__tests__/app-open-proxy.test.ts +29 -25
- package/src/__tests__/approval-conversation-turn.test.ts +100 -81
- package/src/__tests__/approval-hardcoded-copy-guard.test.ts +45 -17
- package/src/__tests__/approval-message-composer.test.ts +119 -119
- package/src/__tests__/approval-primitive.test.ts +264 -233
- package/src/__tests__/approval-routes-http.test.ts +4 -3
- package/src/__tests__/asset-materialize-tool.test.ts +250 -178
- package/src/__tests__/asset-search-tool.test.ts +251 -191
- package/src/__tests__/assistant-attachment-directive.test.ts +187 -142
- package/src/__tests__/assistant-attachments.test.ts +254 -186
- package/src/__tests__/assistant-event-hub.test.ts +105 -63
- package/src/__tests__/assistant-event.test.ts +66 -58
- package/src/__tests__/assistant-events-sse-hardening.test.ts +113 -73
- package/src/__tests__/assistant-feature-flag-guard.test.ts +78 -52
- package/src/__tests__/assistant-feature-flag-guardrails.test.ts +48 -45
- package/src/__tests__/assistant-feature-flags-integration.test.ts +118 -77
- package/src/__tests__/assistant-id-boundary-guard.test.ts +158 -104
- package/src/__tests__/attachments-store.test.ts +240 -183
- package/src/__tests__/attachments.test.ts +70 -62
- package/src/__tests__/audit-log-rotation.test.ts +50 -35
- package/src/__tests__/browser-fill-credential.test.ts +169 -101
- package/src/__tests__/browser-manager.test.ts +97 -75
- package/src/__tests__/browser-runtime-check.test.ts +16 -15
- package/src/__tests__/browser-skill-baseline-tool-payload.test.ts +12 -10
- package/src/__tests__/browser-skill-endstate.test.ts +97 -72
- package/src/__tests__/bundle-scanner.test.ts +47 -22
- package/src/__tests__/bundled-asset.test.ts +74 -47
- package/src/__tests__/call-constants.test.ts +19 -19
- package/src/__tests__/call-controller.test.ts +1073 -751
- package/src/__tests__/call-conversation-messages.test.ts +90 -65
- package/src/__tests__/call-domain.test.ts +149 -121
- package/src/__tests__/call-pointer-message-composer.test.ts +113 -83
- package/src/__tests__/call-pointer-messages.test.ts +213 -154
- package/src/__tests__/call-pointer-no-hardcoded-copy.guard.test.ts +9 -10
- package/src/__tests__/call-recovery.test.ts +232 -212
- package/src/__tests__/call-routes-http.test.ts +328 -279
- package/src/__tests__/call-start-guardian-guard.test.ts +32 -30
- package/src/__tests__/call-state-machine.test.ts +62 -51
- package/src/__tests__/call-state.test.ts +89 -75
- package/src/__tests__/call-store.test.ts +387 -316
- package/src/__tests__/callback-handoff-copy.test.ts +84 -82
- package/src/__tests__/canonical-guardian-store.test.ts +331 -280
- package/src/__tests__/channel-approval-routes.test.ts +1643 -1126
- package/src/__tests__/channel-approval.test.ts +139 -137
- package/src/__tests__/channel-approvals.test.ts +226 -182
- package/src/__tests__/channel-delivery-store.test.ts +232 -194
- package/src/__tests__/channel-guardian.test.ts +6 -3
- package/src/__tests__/channel-invite-transport.test.ts +107 -92
- package/src/__tests__/channel-policy.test.ts +42 -38
- package/src/__tests__/channel-readiness-service.test.ts +119 -102
- package/src/__tests__/channel-reply-delivery.test.ts +147 -118
- package/src/__tests__/channel-retry-sweep.test.ts +153 -110
- package/src/__tests__/checker.test.ts +3309 -1850
- package/src/__tests__/clarification-resolver.test.ts +91 -79
- package/src/__tests__/classifier.test.ts +64 -54
- package/src/__tests__/claude-code-skill-regression.test.ts +42 -37
- package/src/__tests__/claude-code-tool-profiles.test.ts +31 -29
- package/src/__tests__/clawhub.test.ts +92 -82
- package/src/__tests__/cli.test.ts +30 -30
- package/src/__tests__/clipboard.test.ts +53 -46
- package/src/__tests__/commit-guarantee.test.ts +59 -52
- package/src/__tests__/commit-message-enrichment-service.test.ts +203 -75
- package/src/__tests__/compaction.benchmark.test.ts +33 -31
- package/src/__tests__/computer-use-session-compaction.test.ts +60 -50
- package/src/__tests__/computer-use-session-lifecycle.test.ts +145 -117
- package/src/__tests__/computer-use-session-working-dir.test.ts +62 -48
- package/src/__tests__/computer-use-skill-baseline.test.ts +22 -19
- package/src/__tests__/computer-use-skill-endstate.test.ts +45 -31
- package/src/__tests__/computer-use-skill-lifecycle-cleanup.test.ts +121 -88
- package/src/__tests__/computer-use-skill-manifest-regression.test.ts +65 -42
- package/src/__tests__/computer-use-skill-proxy-bridge.test.ts +33 -18
- package/src/__tests__/computer-use-tools.test.ts +121 -98
- package/src/__tests__/config-schema.test.ts +443 -347
- package/src/__tests__/config-watcher.test.ts +96 -81
- package/src/__tests__/confirmation-request-guardian-bridge.test.ts +148 -133
- package/src/__tests__/conflict-intent-tokenization.test.ts +96 -78
- package/src/__tests__/conflict-policy.test.ts +151 -80
- package/src/__tests__/conflict-store.test.ts +203 -157
- package/src/__tests__/connection-policy.test.ts +89 -59
- package/src/__tests__/contacts-tools.test.ts +247 -178
- package/src/__tests__/context-memory-e2e.test.ts +306 -214
- package/src/__tests__/context-token-estimator.test.ts +114 -74
- package/src/__tests__/context-window-manager.test.ts +269 -167
- package/src/__tests__/contradiction-checker.test.ts +161 -135
- package/src/__tests__/conversation-attention-store.test.ts +350 -290
- package/src/__tests__/conversation-attention-telegram.test.ts +156 -114
- package/src/__tests__/conversation-pairing.test.ts +220 -113
- package/src/__tests__/conversation-routes-guardian-reply.test.ts +164 -104
- package/src/__tests__/conversation-routes.test.ts +71 -41
- package/src/__tests__/conversation-store.test.ts +390 -235
- package/src/__tests__/credential-broker-browser-fill.test.ts +325 -250
- package/src/__tests__/credential-broker-server-use.test.ts +283 -243
- package/src/__tests__/credential-broker.test.ts +128 -74
- package/src/__tests__/credential-host-pattern-match.test.ts +64 -44
- package/src/__tests__/credential-metadata-store.test.ts +360 -311
- package/src/__tests__/credential-policy-validate.test.ts +81 -65
- package/src/__tests__/credential-resolve.test.ts +212 -145
- package/src/__tests__/credential-security-e2e.test.ts +144 -103
- package/src/__tests__/credential-security-invariants.test.ts +253 -208
- package/src/__tests__/credential-selection.test.ts +254 -146
- package/src/__tests__/credential-vault-unit.test.ts +531 -341
- package/src/__tests__/credential-vault.test.ts +761 -484
- package/src/__tests__/daemon-assistant-events.test.ts +91 -66
- package/src/__tests__/daemon-lifecycle.test.ts +258 -190
- package/src/__tests__/daemon-server-session-init.test.ts +257 -191
- package/src/__tests__/date-context.test.ts +314 -249
- package/src/__tests__/db-migration-rollback.test.ts +259 -130
- package/src/__tests__/db-schedule-syntax-migration.test.ts +78 -41
- package/src/__tests__/delete-managed-skill-tool.test.ts +77 -53
- package/src/__tests__/deterministic-verification-control-plane.test.ts +183 -135
- package/src/__tests__/dictation-mode-detection.test.ts +77 -55
- package/src/__tests__/dictation-profile-store.test.ts +70 -56
- package/src/__tests__/dictation-text-processing.test.ts +53 -35
- package/src/__tests__/diff.test.ts +102 -98
- package/src/__tests__/domain-normalize.test.ts +54 -54
- package/src/__tests__/domain-policy.test.ts +71 -55
- package/src/__tests__/dynamic-page-surface.test.ts +31 -33
- package/src/__tests__/dynamic-skill-workflow-prompt.test.ts +69 -69
- package/src/__tests__/edit-engine.test.ts +56 -56
- package/src/__tests__/elevenlabs-client.test.ts +117 -91
- package/src/__tests__/elevenlabs-config.test.ts +32 -31
- package/src/__tests__/email-classifier.test.ts +15 -12
- package/src/__tests__/email-cli.test.ts +121 -108
- package/src/__tests__/emit-signal-routing-intent.test.ts +76 -69
- package/src/__tests__/encrypted-store.test.ts +180 -154
- package/src/__tests__/entity-extractor.test.ts +108 -87
- package/src/__tests__/entity-search.test.ts +664 -258
- package/src/__tests__/ephemeral-permissions.test.ts +224 -188
- package/src/__tests__/event-bus.test.ts +81 -77
- package/src/__tests__/extract-email.test.ts +51 -0
- package/src/__tests__/file-edit-tool.test.ts +62 -44
- package/src/__tests__/file-ops-service.test.ts +131 -114
- package/src/__tests__/file-read-tool.test.ts +48 -31
- package/src/__tests__/file-write-tool.test.ts +43 -37
- package/src/__tests__/filesystem-tools.test.ts +238 -209
- package/src/__tests__/followup-tools.test.ts +237 -162
- package/src/__tests__/forbidden-legacy-symbols.test.ts +19 -20
- package/src/__tests__/frontmatter.test.ts +96 -81
- package/src/__tests__/fuzzy-match-property.test.ts +75 -81
- package/src/__tests__/fuzzy-match.test.ts +71 -65
- package/src/__tests__/gateway-client-managed-outbound.test.ts +76 -57
- package/src/__tests__/gateway-only-enforcement.test.ts +467 -369
- package/src/__tests__/gateway-only-guard.test.ts +54 -56
- package/src/__tests__/gemini-image-service.test.ts +113 -100
- package/src/__tests__/gemini-provider.test.ts +297 -220
- package/src/__tests__/get-weather.test.ts +188 -114
- package/src/__tests__/gmail-integration.test.ts +47 -46
- package/src/__tests__/guardian-action-conversation-turn.test.ts +226 -171
- package/src/__tests__/guardian-action-copy-generator.test.ts +111 -93
- package/src/__tests__/guardian-action-followup-executor.test.ts +215 -151
- package/src/__tests__/guardian-action-followup-store.test.ts +199 -167
- package/src/__tests__/guardian-action-grant-mint-consume.test.ts +297 -250
- package/src/__tests__/guardian-action-late-reply.test.ts +462 -316
- package/src/__tests__/guardian-action-no-hardcoded-copy.test.ts +23 -18
- package/src/__tests__/guardian-action-store.test.ts +158 -109
- package/src/__tests__/guardian-action-sweep.test.ts +114 -100
- package/src/__tests__/guardian-actions-endpoint.test.ts +440 -256
- package/src/__tests__/guardian-control-plane-policy.test.ts +497 -331
- package/src/__tests__/guardian-decision-primitive-canonical.test.ts +217 -215
- package/src/__tests__/guardian-dispatch.test.ts +316 -256
- package/src/__tests__/guardian-grant-minting.test.ts +247 -178
- package/src/__tests__/guardian-outbound-http.test.ts +337 -209
- package/src/__tests__/guardian-principal-id-roundtrip.test.ts +99 -96
- package/src/__tests__/guardian-question-copy.test.ts +17 -17
- package/src/__tests__/guardian-question-mode.test.ts +134 -100
- package/src/__tests__/guardian-routing-invariants.test.ts +679 -613
- package/src/__tests__/guardian-routing-state.test.ts +256 -209
- package/src/__tests__/guardian-verification-intent-routing.test.ts +94 -88
- package/src/__tests__/guardian-verification-voice-binding.test.ts +47 -41
- package/src/__tests__/guardian-verify-setup-skill-regression.test.ts +0 -1
- package/src/__tests__/handle-user-message-secret-resume.test.ts +43 -21
- package/src/__tests__/handlers-add-trust-rule-metadata.test.ts +92 -76
- package/src/__tests__/handlers-cu-observation-blob.test.ts +103 -70
- package/src/__tests__/handlers-ipc-blob-probe.test.ts +77 -51
- package/src/__tests__/handlers-slack-config.test.ts +63 -54
- package/src/__tests__/handlers-task-submit-slash.test.ts +18 -18
- package/src/__tests__/handlers-telegram-config.test.ts +662 -329
- package/src/__tests__/handlers-twitter-config.test.ts +525 -298
- package/src/__tests__/handlers-user-message-approval-consumption.test.ts +270 -195
- package/src/__tests__/headless-browser-interactions.test.ts +444 -280
- package/src/__tests__/headless-browser-navigate.test.ts +116 -79
- package/src/__tests__/headless-browser-read-tools.test.ts +123 -86
- package/src/__tests__/headless-browser-snapshot.test.ts +71 -56
- package/src/__tests__/heartbeat-service.test.ts +76 -58
- package/src/__tests__/history-repair-observability.test.ts +14 -14
- package/src/__tests__/history-repair.test.ts +171 -167
- package/src/__tests__/home-base-bootstrap.test.ts +30 -27
- package/src/__tests__/hooks-blocking.test.ts +86 -37
- package/src/__tests__/hooks-cli.test.ts +104 -68
- package/src/__tests__/hooks-config.test.ts +81 -43
- package/src/__tests__/hooks-discovery.test.ts +106 -96
- package/src/__tests__/hooks-integration.test.ts +78 -72
- package/src/__tests__/hooks-manager.test.ts +99 -61
- package/src/__tests__/hooks-runner.test.ts +94 -71
- package/src/__tests__/hooks-settings.test.ts +69 -64
- package/src/__tests__/hooks-templates.test.ts +85 -54
- package/src/__tests__/hooks-ts-runner.test.ts +82 -45
- package/src/__tests__/hooks-watch.test.ts +32 -22
- package/src/__tests__/host-file-edit-tool.test.ts +190 -148
- package/src/__tests__/host-file-read-tool.test.ts +86 -63
- package/src/__tests__/host-file-write-tool.test.ts +98 -64
- package/src/__tests__/host-shell-tool.test.ts +342 -233
- package/src/__tests__/inbound-invite-redemption.test.ts +194 -152
- package/src/__tests__/ingress-member-store.test.ts +163 -159
- package/src/__tests__/ingress-reconcile.test.ts +183 -142
- package/src/__tests__/ingress-routes-http.test.ts +441 -356
- package/src/__tests__/ingress-url-consistency.test.ts +125 -64
- package/src/__tests__/integration-status.test.ts +93 -73
- package/src/__tests__/intent-routing.test.ts +148 -118
- package/src/__tests__/invite-redemption-service.test.ts +163 -121
- package/src/__tests__/ipc-blob-store.test.ts +104 -91
- package/src/__tests__/ipc-contract-inventory.test.ts +27 -15
- package/src/__tests__/ipc-contract.test.ts +24 -23
- package/src/__tests__/ipc-protocol.test.ts +52 -46
- package/src/__tests__/ipc-roundtrip.benchmark.test.ts +61 -50
- package/src/__tests__/ipc-snapshot.test.ts +1135 -1056
- package/src/__tests__/ipc-validate.test.ts +240 -179
- package/src/__tests__/key-migration.test.ts +123 -90
- package/src/__tests__/keychain.test.ts +150 -123
- package/src/__tests__/lifecycle-docs-guard.test.ts +65 -64
- package/src/__tests__/llm-usage-store.test.ts +112 -87
- package/src/__tests__/managed-skill-lifecycle.test.ts +147 -108
- package/src/__tests__/managed-store.test.ts +411 -360
- package/src/__tests__/mcp-cli.test.ts +189 -123
- package/src/__tests__/mcp-health-check.test.ts +26 -21
- package/src/__tests__/media-generate-image.test.ts +122 -99
- package/src/__tests__/media-reuse-story.e2e.test.ts +282 -214
- package/src/__tests__/media-visibility-policy.test.ts +86 -38
- package/src/__tests__/memory-context-benchmark.benchmark.test.ts +146 -100
- package/src/__tests__/memory-lifecycle-e2e.test.ts +385 -297
- package/src/__tests__/memory-query-builder.test.ts +32 -33
- package/src/__tests__/memory-recall-quality.test.ts +761 -407
- package/src/__tests__/memory-regressions.experimental.test.ts +443 -380
- package/src/__tests__/memory-regressions.test.ts +3725 -2642
- package/src/__tests__/memory-retrieval-budget.test.ts +7 -8
- package/src/__tests__/memory-retrieval.benchmark.test.ts +144 -109
- package/src/__tests__/memory-upsert-concurrency.test.ts +292 -201
- package/src/__tests__/messaging-send-tool.test.ts +36 -29
- package/src/__tests__/migration-cli-flows.test.ts +69 -53
- package/src/__tests__/migration-ordering.test.ts +103 -86
- package/src/__tests__/mime-builder.test.ts +55 -32
- package/src/__tests__/mock-signup-server.test.ts +384 -246
- package/src/__tests__/model-intents.test.ts +61 -37
- package/src/__tests__/no-direct-anthropic-sdk-imports.test.ts +9 -12
- package/src/__tests__/no-is-trusted-guard.test.ts +24 -21
- package/src/__tests__/non-member-access-request.test.ts +294 -249
- package/src/__tests__/notification-broadcaster.test.ts +99 -81
- package/src/__tests__/notification-decision-fallback.test.ts +223 -178
- package/src/__tests__/notification-decision-strategy.test.ts +375 -337
- package/src/__tests__/notification-deep-link.test.ts +67 -61
- package/src/__tests__/notification-guardian-path.test.ts +248 -206
- package/src/__tests__/notification-routing-intent.test.ts +166 -93
- package/src/__tests__/notification-telegram-adapter.test.ts +60 -46
- package/src/__tests__/notification-thread-candidate-validation.test.ts +78 -75
- package/src/__tests__/notification-thread-candidates.test.ts +64 -61
- package/src/__tests__/oauth-callback-registry.test.ts +40 -30
- package/src/__tests__/oauth-connect-handler.test.ts +109 -89
- package/src/__tests__/oauth-scope-policy.test.ts +63 -55
- package/src/__tests__/oauth2-gateway-transport.test.ts +252 -174
- package/src/__tests__/onboarding-starter-tasks.test.ts +93 -89
- package/src/__tests__/onboarding-template-contract.test.ts +93 -94
- package/src/__tests__/openai-provider.test.ts +366 -274
- package/src/__tests__/pairing-concurrent.test.ts +18 -12
- package/src/__tests__/pairing-routes.test.ts +45 -41
- package/src/__tests__/parallel-tool.benchmark.test.ts +108 -58
- package/src/__tests__/parser.test.ts +316 -226
- package/src/__tests__/path-classifier.test.ts +24 -25
- package/src/__tests__/path-policy.test.ts +187 -147
- package/src/__tests__/phone.test.ts +36 -36
- package/src/__tests__/platform-move-helper.test.ts +48 -40
- package/src/__tests__/platform-socket-path.test.ts +23 -24
- package/src/__tests__/platform-workspace-migration.test.ts +464 -414
- package/src/__tests__/platform.test.ts +61 -53
- package/src/__tests__/playbook-execution.test.ts +397 -265
- package/src/__tests__/playbook-tools.test.ts +267 -196
- package/src/__tests__/prebuilt-home-base-seed.test.ts +30 -27
- package/src/__tests__/pricing.test.ts +316 -136
- package/src/__tests__/profile-compiler.test.ts +206 -188
- package/src/__tests__/provider-commit-message-generator.test.ts +114 -106
- package/src/__tests__/provider-error-scenarios.test.ts +212 -158
- package/src/__tests__/provider-fail-open-selection.test.ts +51 -44
- package/src/__tests__/provider-registry-ollama.test.ts +13 -9
- package/src/__tests__/provider-streaming.benchmark.test.ts +232 -183
- package/src/__tests__/proxy-approval-callback.test.ts +180 -119
- package/src/__tests__/public-ingress-urls.test.ts +112 -94
- package/src/__tests__/qdrant-manager.test.ts +147 -98
- package/src/__tests__/ratelimit.test.ts +152 -82
- package/src/__tests__/recording-handler.test.ts +273 -151
- package/src/__tests__/recording-intent-fallback.test.ts +94 -75
- package/src/__tests__/recording-intent-handler.test.ts +422 -292
- package/src/__tests__/recording-intent.test.ts +578 -379
- package/src/__tests__/recording-state-machine.test.ts +530 -316
- package/src/__tests__/recurrence-engine-rruleset.test.ts +150 -92
- package/src/__tests__/recurrence-engine.test.ts +81 -41
- package/src/__tests__/recurrence-types.test.ts +63 -44
- package/src/__tests__/relay-server.test.ts +2131 -1602
- package/src/__tests__/reminder-store.test.ts +158 -80
- package/src/__tests__/reminder.test.ts +113 -109
- package/src/__tests__/remote-skill-policy.test.ts +96 -72
- package/src/__tests__/request-file-tool.test.ts +74 -67
- package/src/__tests__/response-tier.test.ts +131 -74
- package/src/__tests__/runtime-attachment-metadata.test.ts +107 -70
- package/src/__tests__/runtime-events-sse-parity.test.ts +167 -145
- package/src/__tests__/runtime-events-sse.test.ts +67 -51
- package/src/__tests__/sandbox-diagnostics.test.ts +66 -56
- package/src/__tests__/sandbox-host-parity.test.ts +377 -301
- package/src/__tests__/scaffold-managed-skill-tool.test.ts +213 -161
- package/src/__tests__/schedule-store.test.ts +268 -205
- package/src/__tests__/schedule-tools.test.ts +702 -524
- package/src/__tests__/scheduler-recurrence.test.ts +240 -130
- package/src/__tests__/scoped-approval-grants.test.ts +258 -168
- package/src/__tests__/scoped-grant-security-matrix.test.ts +160 -146
- package/src/__tests__/script-proxy-certs.test.ts +38 -35
- package/src/__tests__/script-proxy-connect-tunnel.test.ts +71 -46
- package/src/__tests__/script-proxy-decision-trace.test.ts +161 -84
- package/src/__tests__/script-proxy-http-forwarder.test.ts +146 -129
- package/src/__tests__/script-proxy-injection-runtime.test.ts +139 -113
- package/src/__tests__/script-proxy-mitm-handler.test.ts +226 -142
- package/src/__tests__/script-proxy-policy-runtime.test.ts +126 -86
- package/src/__tests__/script-proxy-policy.test.ts +308 -153
- package/src/__tests__/script-proxy-rewrite-specificity.test.ts +74 -62
- package/src/__tests__/script-proxy-router.test.ts +111 -77
- package/src/__tests__/script-proxy-session-manager.test.ts +156 -113
- package/src/__tests__/script-proxy-session-runtime.test.ts +28 -24
- package/src/__tests__/secret-allowlist.test.ts +105 -90
- package/src/__tests__/secret-ingress-handler.test.ts +41 -30
- package/src/__tests__/secret-onetime-send.test.ts +67 -50
- package/src/__tests__/secret-prompt-log-hygiene.test.ts +35 -31
- package/src/__tests__/secret-response-routing.test.ts +50 -41
- package/src/__tests__/secret-scanner-executor.test.ts +152 -111
- package/src/__tests__/secret-scanner.test.ts +495 -413
- package/src/__tests__/secure-keys.test.ts +132 -121
- package/src/__tests__/send-endpoint-busy.test.ts +313 -232
- package/src/__tests__/send-notification-tool.test.ts +43 -42
- package/src/__tests__/sensitive-output-placeholders.test.ts +72 -64
- package/src/__tests__/sequence-store.test.ts +335 -167
- package/src/__tests__/server-history-render.test.ts +341 -202
- package/src/__tests__/session-abort-tool-results.test.ts +133 -70
- package/src/__tests__/session-approval-overrides.test.ts +93 -91
- package/src/__tests__/session-confirmation-signals.test.ts +252 -160
- package/src/__tests__/session-conflict-gate.test.ts +775 -585
- package/src/__tests__/session-error.test.ts +222 -191
- package/src/__tests__/session-evictor.test.ts +79 -62
- package/src/__tests__/session-init.benchmark.test.ts +170 -108
- package/src/__tests__/session-load-history-repair.test.ts +273 -139
- package/src/__tests__/session-messaging-secret-redirect.test.ts +130 -90
- package/src/__tests__/session-pre-run-repair.test.ts +106 -59
- package/src/__tests__/session-profile-injection.test.ts +198 -130
- package/src/__tests__/session-provider-retry-repair.test.ts +223 -141
- package/src/__tests__/session-queue.test.ts +624 -321
- package/src/__tests__/session-runtime-assembly.test.ts +425 -329
- package/src/__tests__/session-runtime-workspace.test.ts +69 -61
- package/src/__tests__/session-skill-tools.test.ts +973 -678
- package/src/__tests__/session-slash-known.test.ts +185 -133
- package/src/__tests__/session-slash-queue.test.ts +147 -81
- package/src/__tests__/session-slash-unknown.test.ts +135 -90
- package/src/__tests__/session-surfaces-task-progress.test.ts +122 -87
- package/src/__tests__/session-tool-setup-app-refresh.test.ts +338 -177
- package/src/__tests__/session-tool-setup-memory-scope.test.ts +63 -40
- package/src/__tests__/session-tool-setup-side-effect-flag.test.ts +60 -37
- package/src/__tests__/session-tool-setup-tools-disabled.test.ts +28 -26
- package/src/__tests__/session-undo.test.ts +43 -30
- package/src/__tests__/session-workspace-cache-state.test.ts +108 -67
- package/src/__tests__/session-workspace-injection.test.ts +245 -117
- package/src/__tests__/session-workspace-tool-tracking.test.ts +260 -93
- package/src/__tests__/shared-filesystem-errors.test.ts +47 -47
- package/src/__tests__/shell-credential-ref.test.ts +126 -90
- package/src/__tests__/shell-identity.test.ts +134 -111
- package/src/__tests__/shell-parser-fuzz.test.ts +263 -179
- package/src/__tests__/shell-parser-property.test.ts +435 -288
- package/src/__tests__/shell-tool-proxy-mode.test.ts +142 -70
- package/src/__tests__/size-guard.test.ts +42 -44
- package/src/__tests__/skill-feature-flags-integration.test.ts +79 -52
- package/src/__tests__/skill-feature-flags.test.ts +75 -47
- package/src/__tests__/skill-include-graph.test.ts +143 -148
- package/src/__tests__/skill-load-feature-flag.test.ts +94 -59
- package/src/__tests__/skill-load-tool.test.ts +371 -199
- package/src/__tests__/skill-projection-feature-flag.test.ts +131 -88
- package/src/__tests__/skill-projection.benchmark.test.ts +93 -65
- package/src/__tests__/skill-script-runner-host.test.ts +460 -250
- package/src/__tests__/skill-script-runner-sandbox.test.ts +168 -108
- package/src/__tests__/skill-script-runner.test.ts +115 -74
- package/src/__tests__/skill-tool-factory.test.ts +140 -96
- package/src/__tests__/skill-tool-manifest.test.ts +306 -210
- package/src/__tests__/skill-version-hash.test.ts +70 -56
- package/src/__tests__/skills.test.ts +0 -1
- package/src/__tests__/slack-channel-config.test.ts +127 -84
- package/src/__tests__/slack-skill.test.ts +60 -47
- package/src/__tests__/slash-commands-catalog.test.ts +37 -31
- package/src/__tests__/slash-commands-parser.test.ts +71 -64
- package/src/__tests__/slash-commands-resolver.test.ts +143 -107
- package/src/__tests__/slash-commands-rewrite.test.ts +22 -22
- package/src/__tests__/sms-messaging-provider.test.ts +74 -47
- package/src/__tests__/speaker-identification.test.ts +28 -25
- package/src/__tests__/starter-bundle.test.ts +27 -23
- package/src/__tests__/starter-task-flow.test.ts +67 -52
- package/src/__tests__/subagent-manager-notify.test.ts +154 -108
- package/src/__tests__/subagent-tools.test.ts +311 -270
- package/src/__tests__/subagent-types.test.ts +40 -40
- package/src/__tests__/surface-mutex-cleanup.test.ts +42 -30
- package/src/__tests__/swarm-dag-pathological.test.ts +122 -111
- package/src/__tests__/swarm-orchestrator.test.ts +135 -101
- package/src/__tests__/swarm-plan-validator.test.ts +125 -73
- package/src/__tests__/swarm-recursion.test.ts +58 -46
- package/src/__tests__/swarm-router-planner.test.ts +99 -74
- package/src/__tests__/swarm-session-integration.test.ts +148 -91
- package/src/__tests__/swarm-tool.test.ts +65 -45
- package/src/__tests__/swarm-worker-backend.test.ts +59 -45
- package/src/__tests__/swarm-worker-runner.test.ts +133 -118
- package/src/__tests__/system-prompt.test.ts +290 -256
- package/src/__tests__/task-compiler.test.ts +176 -120
- package/src/__tests__/task-management-tools.test.ts +561 -456
- package/src/__tests__/task-memory-cleanup.test.ts +627 -362
- package/src/__tests__/task-runner.test.ts +117 -94
- package/src/__tests__/task-scheduler.test.ts +113 -84
- package/src/__tests__/task-tools.test.ts +349 -264
- package/src/__tests__/terminal-sandbox.test.ts +138 -108
- package/src/__tests__/terminal-tools.test.ts +350 -305
- package/src/__tests__/thread-seed-composer.test.ts +307 -180
- package/src/__tests__/tool-approval-handler.test.ts +238 -137
- package/src/__tests__/tool-audit-listener.test.ts +69 -69
- package/src/__tests__/tool-domain-event-publisher.test.ts +142 -132
- package/src/__tests__/tool-execution-abort-cleanup.test.ts +153 -146
- package/src/__tests__/tool-execution-pipeline.benchmark.test.ts +136 -105
- package/src/__tests__/tool-executor-lifecycle-events.test.ts +355 -239
- package/src/__tests__/tool-executor-redaction.test.ts +112 -109
- package/src/__tests__/tool-executor-shell-integration.test.ts +130 -79
- package/src/__tests__/tool-executor.test.ts +1274 -674
- package/src/__tests__/tool-grant-request-escalation.test.ts +401 -283
- package/src/__tests__/tool-metrics-listener.test.ts +97 -85
- package/src/__tests__/tool-notification-listener.test.ts +42 -25
- package/src/__tests__/tool-permission-simulate-handler.test.ts +137 -113
- package/src/__tests__/tool-policy.test.ts +44 -25
- package/src/__tests__/tool-profiling-listener.test.ts +99 -93
- package/src/__tests__/tool-result-truncation.test.ts +5 -4
- package/src/__tests__/tool-trace-listener.test.ts +131 -111
- package/src/__tests__/top-level-renderer.test.ts +62 -58
- package/src/__tests__/top-level-scanner.test.ts +68 -64
- package/src/__tests__/trace-emitter.test.ts +56 -56
- package/src/__tests__/trust-context-guards.test.ts +65 -65
- package/src/__tests__/trust-store.test.ts +1239 -806
- package/src/__tests__/trusted-contact-approval-notifier.test.ts +339 -275
- package/src/__tests__/trusted-contact-inline-approval-integration.test.ts +484 -373
- package/src/__tests__/trusted-contact-lifecycle-notifications.test.ts +264 -241
- package/src/__tests__/trusted-contact-multichannel.test.ts +182 -142
- package/src/__tests__/trusted-contact-verification.test.ts +251 -231
- package/src/__tests__/turn-commit.test.ts +259 -200
- package/src/__tests__/twilio-config.test.ts +49 -41
- package/src/__tests__/twilio-provider.test.ts +140 -126
- package/src/__tests__/twilio-rest.test.ts +22 -18
- package/src/__tests__/twilio-routes-elevenlabs.test.ts +188 -162
- package/src/__tests__/twilio-routes-twiml.test.ts +55 -55
- package/src/__tests__/twilio-routes.test.ts +389 -281
- package/src/__tests__/twitter-auth-handler.test.ts +184 -139
- package/src/__tests__/twitter-cli-error-shaping.test.ts +88 -73
- package/src/__tests__/twitter-cli-routing.test.ts +146 -99
- package/src/__tests__/twitter-oauth-client.test.ts +82 -65
- package/src/__tests__/update-bulletin-format.test.ts +69 -66
- package/src/__tests__/update-bulletin-state.test.ts +66 -60
- package/src/__tests__/update-bulletin.test.ts +150 -114
- package/src/__tests__/update-template-contract.test.ts +15 -10
- package/src/__tests__/url-safety.test.ts +288 -265
- package/src/__tests__/user-reference.test.ts +32 -32
- package/src/__tests__/view-image-tool.test.ts +118 -96
- package/src/__tests__/voice-invite-redemption.test.ts +111 -106
- package/src/__tests__/voice-quality.test.ts +117 -102
- package/src/__tests__/voice-scoped-grant-consumer.test.ts +204 -146
- package/src/__tests__/voice-session-bridge.test.ts +351 -216
- package/src/__tests__/weather-skill-regression.test.ts +170 -120
- package/src/__tests__/web-fetch.test.ts +664 -526
- package/src/__tests__/web-search.test.ts +379 -213
- package/src/__tests__/work-item-output.test.ts +90 -53
- package/src/__tests__/workspace-git-service.test.ts +437 -356
- package/src/__tests__/workspace-heartbeat-service.test.ts +125 -91
- package/src/__tests__/workspace-lifecycle.test.ts +98 -64
- package/src/__tests__/workspace-policy.test.ts +139 -71
- package/src/commands/__tests__/cc-command-registry.test.ts +142 -134
- package/src/config/__tests__/feature-flag-registry-guard.test.ts +48 -39
- package/src/config/bundled-skills/chatgpt-import/tools/chatgpt-import.ts +44 -4
- package/src/config/bundled-skills/doordash/__tests__/doordash-session.test.ts +0 -1
- package/src/config/bundled-skills/messaging/SKILL.md +9 -7
- package/src/config/bundled-skills/messaging/tools/gmail-outreach-scan.ts +15 -5
- package/src/config/bundled-skills/messaging/tools/gmail-sender-digest.ts +16 -5
- package/src/config/bundled-skills/messaging/tools/messaging-reply.ts +11 -7
- package/src/config/bundled-skills/slack/tools/slack-scan-digest.ts +34 -32
- package/src/config/bundled-tool-registry.ts +2 -0
- package/src/config/env.ts +38 -29
- package/src/daemon/handlers/skills.ts +18 -10
- package/src/daemon/ipc-contract/messages.ts +1 -0
- package/src/daemon/ipc-contract/surfaces.ts +7 -1
- package/src/daemon/session-agent-loop-handlers.ts +5 -0
- package/src/daemon/session-agent-loop.ts +1 -1
- package/src/daemon/session-process.ts +1 -1
- package/src/daemon/session-surfaces.ts +42 -2
- package/src/memory/db-connection.ts +16 -10
- package/src/messaging/providers/gmail/adapter.ts +10 -3
- package/src/messaging/providers/gmail/client.ts +280 -72
- package/src/runtime/auth/__tests__/context.test.ts +75 -65
- package/src/runtime/auth/__tests__/credential-service.test.ts +137 -114
- package/src/runtime/auth/__tests__/guard-tests.test.ts +84 -90
- package/src/runtime/auth/__tests__/ipc-auth-context.test.ts +40 -40
- package/src/runtime/auth/__tests__/middleware.test.ts +80 -74
- package/src/runtime/auth/__tests__/policy.test.ts +9 -9
- package/src/runtime/auth/__tests__/route-policy.test.ts +76 -65
- package/src/runtime/auth/__tests__/scopes.test.ts +68 -60
- package/src/runtime/auth/__tests__/subject.test.ts +54 -54
- package/src/runtime/auth/__tests__/token-service.test.ts +115 -108
- package/src/runtime/auth/scopes.ts +3 -0
- package/src/runtime/auth/token-service.ts +78 -48
- package/src/runtime/auth/types.ts +2 -1
- package/src/runtime/http-server.ts +2 -1
- package/src/security/secure-keys.ts +103 -53
- package/src/sequence/reply-matcher.ts +10 -6
- package/src/skills/frontmatter.ts +9 -6
- package/src/tools/browser/__tests__/auth-cache.test.ts +69 -63
- package/src/tools/browser/__tests__/auth-detector.test.ts +218 -157
- package/src/tools/browser/__tests__/jit-auth.test.ts +83 -99
- package/src/tools/ui-surface/definitions.ts +2 -1
- package/src/util/platform.ts +0 -12
- package/docs/architecture/http-token-refresh.md +0 -274
|
@@ -11,135 +11,146 @@
|
|
|
11
11
|
* 4. activated — when the trusted contact successfully verifies
|
|
12
12
|
* 5. denied — when the guardian denies the request
|
|
13
13
|
*/
|
|
14
|
-
import { mkdtempSync, rmSync } from
|
|
15
|
-
import { tmpdir } from
|
|
16
|
-
import { join } from
|
|
17
|
-
|
|
18
|
-
import { afterAll, beforeEach, describe, expect, mock, test } from 'bun:test';
|
|
14
|
+
import { mkdtempSync, rmSync } from "node:fs";
|
|
15
|
+
import { tmpdir } from "node:os";
|
|
16
|
+
import { join } from "node:path";
|
|
17
|
+
import { afterAll, beforeEach, describe, expect, mock, test } from "bun:test";
|
|
19
18
|
|
|
20
19
|
// ---------------------------------------------------------------------------
|
|
21
20
|
// Test isolation: in-memory SQLite via temp directory
|
|
22
21
|
// ---------------------------------------------------------------------------
|
|
23
22
|
|
|
24
|
-
const testDir = mkdtempSync(join(tmpdir(),
|
|
23
|
+
const testDir = mkdtempSync(join(tmpdir(), "trusted-contact-lifecycle-notif-"));
|
|
25
24
|
|
|
26
|
-
mock.module(
|
|
25
|
+
mock.module("../util/platform.js", () => ({
|
|
27
26
|
getRootDir: () => testDir,
|
|
28
27
|
getDataDir: () => testDir,
|
|
29
|
-
isMacOS: () => process.platform ===
|
|
30
|
-
isLinux: () => process.platform ===
|
|
31
|
-
isWindows: () => process.platform ===
|
|
32
|
-
getSocketPath: () => join(testDir,
|
|
33
|
-
getPidPath: () => join(testDir,
|
|
34
|
-
getDbPath: () => join(testDir,
|
|
35
|
-
getLogPath: () => join(testDir,
|
|
28
|
+
isMacOS: () => process.platform === "darwin",
|
|
29
|
+
isLinux: () => process.platform === "linux",
|
|
30
|
+
isWindows: () => process.platform === "win32",
|
|
31
|
+
getSocketPath: () => join(testDir, "test.sock"),
|
|
32
|
+
getPidPath: () => join(testDir, "test.pid"),
|
|
33
|
+
getDbPath: () => join(testDir, "test.db"),
|
|
34
|
+
getLogPath: () => join(testDir, "test.log"),
|
|
36
35
|
ensureDataDir: () => {},
|
|
37
|
-
readHttpToken: () =>
|
|
36
|
+
readHttpToken: () => "test-bearer-token",
|
|
38
37
|
}));
|
|
39
38
|
|
|
40
|
-
mock.module(
|
|
41
|
-
getLogger: () =>
|
|
42
|
-
|
|
43
|
-
|
|
39
|
+
mock.module("../util/logger.js", () => ({
|
|
40
|
+
getLogger: () =>
|
|
41
|
+
new Proxy({} as Record<string, unknown>, {
|
|
42
|
+
get: () => () => {},
|
|
43
|
+
}),
|
|
44
44
|
}));
|
|
45
45
|
|
|
46
46
|
// Mock security check to always pass
|
|
47
|
-
mock.module(
|
|
47
|
+
mock.module("../security/secret-ingress.js", () => ({
|
|
48
48
|
checkIngressForSecrets: () => ({ blocked: false }),
|
|
49
49
|
}));
|
|
50
50
|
|
|
51
|
-
mock.module(
|
|
52
|
-
|
|
51
|
+
mock.module("../config/env.js", () => ({
|
|
52
|
+
isHttpAuthDisabled: () => true,
|
|
53
|
+
getGatewayInternalBaseUrl: () => "http://127.0.0.1:7830",
|
|
53
54
|
}));
|
|
54
55
|
|
|
55
56
|
// Track emitNotificationSignal calls
|
|
56
57
|
const emitSignalCalls: Array<Record<string, unknown>> = [];
|
|
57
|
-
mock.module(
|
|
58
|
+
mock.module("../notifications/emit-signal.js", () => ({
|
|
58
59
|
emitNotificationSignal: async (params: Record<string, unknown>) => {
|
|
59
60
|
emitSignalCalls.push(params);
|
|
60
61
|
return {
|
|
61
|
-
signalId:
|
|
62
|
+
signalId: "mock-signal-id",
|
|
62
63
|
deduplicated: false,
|
|
63
64
|
dispatched: true,
|
|
64
|
-
reason:
|
|
65
|
+
reason: "mock",
|
|
65
66
|
deliveryResults: [],
|
|
66
67
|
};
|
|
67
68
|
},
|
|
68
69
|
}));
|
|
69
70
|
|
|
70
71
|
// Track deliverChannelReply calls
|
|
71
|
-
const deliverReplyCalls: Array<{
|
|
72
|
-
|
|
73
|
-
|
|
72
|
+
const deliverReplyCalls: Array<{
|
|
73
|
+
url: string;
|
|
74
|
+
payload: Record<string, unknown>;
|
|
75
|
+
}> = [];
|
|
76
|
+
mock.module("../runtime/gateway-client.js", () => ({
|
|
77
|
+
deliverChannelReply: async (
|
|
78
|
+
url: string,
|
|
79
|
+
payload: Record<string, unknown>,
|
|
80
|
+
) => {
|
|
74
81
|
deliverReplyCalls.push({ url, payload });
|
|
75
82
|
},
|
|
76
83
|
}));
|
|
77
84
|
|
|
78
85
|
// Mock the approval conversation / copy generators so they return canned text.
|
|
79
|
-
mock.module(
|
|
80
|
-
composeApprovalMessage: () =>
|
|
81
|
-
composeApprovalMessageGenerative: async () =>
|
|
86
|
+
mock.module("../runtime/approval-message-composer.js", () => ({
|
|
87
|
+
composeApprovalMessage: () => "mock approval message",
|
|
88
|
+
composeApprovalMessageGenerative: async () => "mock generative message",
|
|
82
89
|
}));
|
|
83
90
|
|
|
84
|
-
import { getResolver } from
|
|
91
|
+
import { getResolver } from "../approvals/guardian-request-resolvers.js";
|
|
85
92
|
import {
|
|
86
93
|
createApprovalRequest,
|
|
87
94
|
createBinding,
|
|
88
|
-
} from
|
|
89
|
-
import { getDb, initializeDb, resetDb } from
|
|
90
|
-
import { findMember, upsertMember } from
|
|
91
|
-
import {
|
|
92
|
-
|
|
93
|
-
} from '../runtime/channel-guardian-service.js';
|
|
94
|
-
import { handleChannelInbound } from '../runtime/routes/channel-routes.js';
|
|
95
|
+
} from "../memory/channel-guardian-store.js";
|
|
96
|
+
import { getDb, initializeDb, resetDb } from "../memory/db.js";
|
|
97
|
+
import { findMember, upsertMember } from "../memory/ingress-member-store.js";
|
|
98
|
+
import { createOutboundSession } from "../runtime/channel-guardian-service.js";
|
|
99
|
+
import { handleChannelInbound } from "../runtime/routes/channel-routes.js";
|
|
95
100
|
|
|
96
101
|
initializeDb();
|
|
97
102
|
|
|
98
103
|
afterAll(() => {
|
|
99
104
|
resetDb();
|
|
100
|
-
try {
|
|
105
|
+
try {
|
|
106
|
+
rmSync(testDir, { recursive: true });
|
|
107
|
+
} catch {
|
|
108
|
+
/* best effort */
|
|
109
|
+
}
|
|
101
110
|
});
|
|
102
111
|
|
|
103
112
|
// ---------------------------------------------------------------------------
|
|
104
113
|
// Helpers
|
|
105
114
|
// ---------------------------------------------------------------------------
|
|
106
115
|
|
|
107
|
-
const TEST_BEARER_TOKEN =
|
|
116
|
+
const TEST_BEARER_TOKEN = "test-token";
|
|
108
117
|
const GUARDIAN_APPROVAL_TTL_MS = 5 * 60 * 1000;
|
|
109
118
|
|
|
110
119
|
function resetState(): void {
|
|
111
120
|
const db = getDb();
|
|
112
|
-
db.run(
|
|
113
|
-
db.run(
|
|
114
|
-
db.run(
|
|
115
|
-
db.run(
|
|
116
|
-
db.run(
|
|
117
|
-
db.run(
|
|
118
|
-
db.run(
|
|
119
|
-
db.run(
|
|
121
|
+
db.run("DELETE FROM channel_guardian_approval_requests");
|
|
122
|
+
db.run("DELETE FROM channel_guardian_bindings");
|
|
123
|
+
db.run("DELETE FROM channel_guardian_verification_challenges");
|
|
124
|
+
db.run("DELETE FROM channel_guardian_rate_limits");
|
|
125
|
+
db.run("DELETE FROM channel_inbound_events");
|
|
126
|
+
db.run("DELETE FROM conversations");
|
|
127
|
+
db.run("DELETE FROM notification_events");
|
|
128
|
+
db.run("DELETE FROM assistant_ingress_members");
|
|
120
129
|
emitSignalCalls.length = 0;
|
|
121
130
|
deliverReplyCalls.length = 0;
|
|
122
131
|
}
|
|
123
132
|
|
|
124
133
|
function buildInboundRequest(overrides: Record<string, unknown> = {}): Request {
|
|
125
134
|
const body: Record<string, unknown> = {
|
|
126
|
-
sourceChannel:
|
|
127
|
-
interface:
|
|
128
|
-
conversationExternalId:
|
|
129
|
-
externalMessageId: `msg-${Date.now()}-${Math.random()
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
+
sourceChannel: "telegram",
|
|
136
|
+
interface: "telegram",
|
|
137
|
+
conversationExternalId: "chat-123",
|
|
138
|
+
externalMessageId: `msg-${Date.now()}-${Math.random()
|
|
139
|
+
.toString(36)
|
|
140
|
+
.slice(2, 8)}`,
|
|
141
|
+
content: "Hello",
|
|
142
|
+
actorExternalId: "requester-user-456",
|
|
143
|
+
actorDisplayName: "Alice Requester",
|
|
144
|
+
actorUsername: "alice_req",
|
|
145
|
+
replyCallbackUrl: "http://localhost:7830/deliver/telegram",
|
|
135
146
|
...overrides,
|
|
136
147
|
};
|
|
137
148
|
|
|
138
|
-
return new Request(
|
|
139
|
-
method:
|
|
149
|
+
return new Request("http://localhost:8080/channels/inbound", {
|
|
150
|
+
method: "POST",
|
|
140
151
|
headers: {
|
|
141
|
-
|
|
142
|
-
|
|
152
|
+
"Content-Type": "application/json",
|
|
153
|
+
"X-Gateway-Origin": TEST_BEARER_TOKEN,
|
|
143
154
|
},
|
|
144
155
|
body: JSON.stringify(body),
|
|
145
156
|
});
|
|
@@ -149,27 +160,27 @@ function buildInboundRequest(overrides: Record<string, unknown> = {}): Request {
|
|
|
149
160
|
// Tests: Guardian decision signals (approve/deny)
|
|
150
161
|
// ---------------------------------------------------------------------------
|
|
151
162
|
|
|
152
|
-
describe(
|
|
163
|
+
describe("trusted contact lifecycle notification signals", () => {
|
|
153
164
|
beforeEach(() => {
|
|
154
165
|
resetState();
|
|
155
166
|
});
|
|
156
167
|
|
|
157
|
-
test(
|
|
168
|
+
test("guardian deny emits guardian_decision and denied signals", async () => {
|
|
158
169
|
// Set up guardian binding and member record (guardians must pass ACL)
|
|
159
170
|
createBinding({
|
|
160
|
-
assistantId:
|
|
161
|
-
channel:
|
|
162
|
-
guardianExternalUserId:
|
|
163
|
-
guardianDeliveryChatId:
|
|
164
|
-
guardianPrincipalId:
|
|
171
|
+
assistantId: "self",
|
|
172
|
+
channel: "telegram",
|
|
173
|
+
guardianExternalUserId: "guardian-user-789",
|
|
174
|
+
guardianDeliveryChatId: "guardian-chat-789",
|
|
175
|
+
guardianPrincipalId: "guardian-user-789",
|
|
165
176
|
});
|
|
166
177
|
upsertMember({
|
|
167
|
-
assistantId:
|
|
168
|
-
sourceChannel:
|
|
169
|
-
externalUserId:
|
|
170
|
-
externalChatId:
|
|
171
|
-
status:
|
|
172
|
-
policy:
|
|
178
|
+
assistantId: "self",
|
|
179
|
+
sourceChannel: "telegram",
|
|
180
|
+
externalUserId: "guardian-user-789",
|
|
181
|
+
externalChatId: "guardian-chat-789",
|
|
182
|
+
status: "active",
|
|
183
|
+
policy: "allow",
|
|
173
184
|
});
|
|
174
185
|
|
|
175
186
|
const testRequestId = `req-deny-${Date.now()}`;
|
|
@@ -178,25 +189,25 @@ describe('trusted contact lifecycle notification signals', () => {
|
|
|
178
189
|
const _approval = createApprovalRequest({
|
|
179
190
|
runId: `ingress-access-request-${Date.now()}`,
|
|
180
191
|
requestId: testRequestId,
|
|
181
|
-
conversationId:
|
|
182
|
-
assistantId:
|
|
183
|
-
channel:
|
|
184
|
-
requesterExternalUserId:
|
|
185
|
-
requesterChatId:
|
|
186
|
-
guardianExternalUserId:
|
|
187
|
-
guardianChatId:
|
|
188
|
-
toolName:
|
|
189
|
-
riskLevel:
|
|
190
|
-
reason:
|
|
192
|
+
conversationId: "access-req-telegram-requester-user-456",
|
|
193
|
+
assistantId: "self",
|
|
194
|
+
channel: "telegram",
|
|
195
|
+
requesterExternalUserId: "requester-user-456",
|
|
196
|
+
requesterChatId: "requester-chat-456",
|
|
197
|
+
guardianExternalUserId: "guardian-user-789",
|
|
198
|
+
guardianChatId: "guardian-chat-789",
|
|
199
|
+
toolName: "ingress_access_request",
|
|
200
|
+
riskLevel: "access_request",
|
|
201
|
+
reason: "Alice is requesting access",
|
|
191
202
|
expiresAt: Date.now() + GUARDIAN_APPROVAL_TTL_MS,
|
|
192
203
|
});
|
|
193
204
|
|
|
194
205
|
// Guardian denies via callback button
|
|
195
206
|
const guardianReq = buildInboundRequest({
|
|
196
|
-
conversationExternalId:
|
|
197
|
-
actorExternalId:
|
|
198
|
-
actorDisplayName:
|
|
199
|
-
content:
|
|
207
|
+
conversationExternalId: "guardian-chat-789",
|
|
208
|
+
actorExternalId: "guardian-user-789",
|
|
209
|
+
actorDisplayName: "Guardian",
|
|
210
|
+
content: "",
|
|
200
211
|
callbackData: `apr:${testRequestId}:reject`,
|
|
201
212
|
});
|
|
202
213
|
|
|
@@ -205,47 +216,52 @@ describe('trusted contact lifecycle notification signals', () => {
|
|
|
205
216
|
// Should emit guardian_decision and denied signals
|
|
206
217
|
|
|
207
218
|
const guardianDecisionSignals = emitSignalCalls.filter(
|
|
208
|
-
(c) => c.sourceEventName ===
|
|
219
|
+
(c) => c.sourceEventName === "ingress.trusted_contact.guardian_decision",
|
|
209
220
|
);
|
|
210
221
|
const deniedSignals = emitSignalCalls.filter(
|
|
211
|
-
(c) => c.sourceEventName ===
|
|
222
|
+
(c) => c.sourceEventName === "ingress.trusted_contact.denied",
|
|
212
223
|
);
|
|
213
224
|
|
|
214
225
|
expect(guardianDecisionSignals.length).toBe(1);
|
|
215
226
|
expect(deniedSignals.length).toBe(1);
|
|
216
227
|
|
|
217
228
|
// Verify guardian_decision payload
|
|
218
|
-
const gdPayload = guardianDecisionSignals[0].contextPayload as Record<
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
229
|
+
const gdPayload = guardianDecisionSignals[0].contextPayload as Record<
|
|
230
|
+
string,
|
|
231
|
+
unknown
|
|
232
|
+
>;
|
|
233
|
+
expect(gdPayload.decision).toBe("denied");
|
|
234
|
+
expect(gdPayload.requesterExternalUserId).toBe("requester-user-456");
|
|
235
|
+
expect(gdPayload.decidedByExternalUserId).toBe("guardian-user-789");
|
|
222
236
|
|
|
223
237
|
// Verify denied payload
|
|
224
238
|
const dPayload = deniedSignals[0].contextPayload as Record<string, unknown>;
|
|
225
|
-
expect(dPayload.decision).toBe(
|
|
226
|
-
expect(dPayload.requesterExternalUserId).toBe(
|
|
239
|
+
expect(dPayload.decision).toBe("denied");
|
|
240
|
+
expect(dPayload.requesterExternalUserId).toBe("requester-user-456");
|
|
227
241
|
|
|
228
242
|
// Verify deduplication keys are distinct
|
|
229
|
-
expect(guardianDecisionSignals[0].dedupeKey).toContain(
|
|
230
|
-
|
|
243
|
+
expect(guardianDecisionSignals[0].dedupeKey).toContain(
|
|
244
|
+
"trusted-contact:guardian-decision:",
|
|
245
|
+
);
|
|
246
|
+
expect(deniedSignals[0].dedupeKey).toContain("trusted-contact:denied:");
|
|
231
247
|
});
|
|
232
248
|
|
|
233
|
-
test(
|
|
249
|
+
test("guardian approve emits guardian_decision and verification_sent signals", async () => {
|
|
234
250
|
// Set up guardian binding and member record (guardians must pass ACL)
|
|
235
251
|
createBinding({
|
|
236
|
-
assistantId:
|
|
237
|
-
channel:
|
|
238
|
-
guardianExternalUserId:
|
|
239
|
-
guardianDeliveryChatId:
|
|
240
|
-
guardianPrincipalId:
|
|
252
|
+
assistantId: "self",
|
|
253
|
+
channel: "telegram",
|
|
254
|
+
guardianExternalUserId: "guardian-user-789",
|
|
255
|
+
guardianDeliveryChatId: "guardian-chat-789",
|
|
256
|
+
guardianPrincipalId: "guardian-user-789",
|
|
241
257
|
});
|
|
242
258
|
upsertMember({
|
|
243
|
-
assistantId:
|
|
244
|
-
sourceChannel:
|
|
245
|
-
externalUserId:
|
|
246
|
-
externalChatId:
|
|
247
|
-
status:
|
|
248
|
-
policy:
|
|
259
|
+
assistantId: "self",
|
|
260
|
+
sourceChannel: "telegram",
|
|
261
|
+
externalUserId: "guardian-user-789",
|
|
262
|
+
externalChatId: "guardian-chat-789",
|
|
263
|
+
status: "active",
|
|
264
|
+
policy: "allow",
|
|
249
265
|
});
|
|
250
266
|
|
|
251
267
|
const testRequestId = `req-approve-${Date.now()}`;
|
|
@@ -254,25 +270,25 @@ describe('trusted contact lifecycle notification signals', () => {
|
|
|
254
270
|
const _approval = createApprovalRequest({
|
|
255
271
|
runId: `ingress-access-request-${Date.now()}`,
|
|
256
272
|
requestId: testRequestId,
|
|
257
|
-
conversationId:
|
|
258
|
-
assistantId:
|
|
259
|
-
channel:
|
|
260
|
-
requesterExternalUserId:
|
|
261
|
-
requesterChatId:
|
|
262
|
-
guardianExternalUserId:
|
|
263
|
-
guardianChatId:
|
|
264
|
-
toolName:
|
|
265
|
-
riskLevel:
|
|
266
|
-
reason:
|
|
273
|
+
conversationId: "access-req-telegram-requester-user-456",
|
|
274
|
+
assistantId: "self",
|
|
275
|
+
channel: "telegram",
|
|
276
|
+
requesterExternalUserId: "requester-user-456",
|
|
277
|
+
requesterChatId: "requester-chat-456",
|
|
278
|
+
guardianExternalUserId: "guardian-user-789",
|
|
279
|
+
guardianChatId: "guardian-chat-789",
|
|
280
|
+
toolName: "ingress_access_request",
|
|
281
|
+
riskLevel: "access_request",
|
|
282
|
+
reason: "Alice is requesting access",
|
|
267
283
|
expiresAt: Date.now() + GUARDIAN_APPROVAL_TTL_MS,
|
|
268
284
|
});
|
|
269
285
|
|
|
270
286
|
// Guardian approves via callback button
|
|
271
287
|
const guardianReq = buildInboundRequest({
|
|
272
|
-
conversationExternalId:
|
|
273
|
-
actorExternalId:
|
|
274
|
-
actorDisplayName:
|
|
275
|
-
content:
|
|
288
|
+
conversationExternalId: "guardian-chat-789",
|
|
289
|
+
actorExternalId: "guardian-user-789",
|
|
290
|
+
actorDisplayName: "Guardian",
|
|
291
|
+
content: "",
|
|
276
292
|
callbackData: `apr:${testRequestId}:approve_once`,
|
|
277
293
|
});
|
|
278
294
|
|
|
@@ -282,10 +298,10 @@ describe('trusted contact lifecycle notification signals', () => {
|
|
|
282
298
|
// is still pending — it would cause the notification pipeline to send a
|
|
283
299
|
// premature "approved" message to the guardian's chat.
|
|
284
300
|
const guardianDecisionSignals = emitSignalCalls.filter(
|
|
285
|
-
(c) => c.sourceEventName ===
|
|
301
|
+
(c) => c.sourceEventName === "ingress.trusted_contact.guardian_decision",
|
|
286
302
|
);
|
|
287
303
|
const verificationSentSignals = emitSignalCalls.filter(
|
|
288
|
-
(c) => c.sourceEventName ===
|
|
304
|
+
(c) => c.sourceEventName === "ingress.trusted_contact.verification_sent",
|
|
289
305
|
);
|
|
290
306
|
|
|
291
307
|
expect(guardianDecisionSignals.length).toBe(0);
|
|
@@ -294,33 +310,35 @@ describe('trusted contact lifecycle notification signals', () => {
|
|
|
294
310
|
// Verify verification_sent payload and that it's suppressed from delivery
|
|
295
311
|
const vsSignal = verificationSentSignals[0];
|
|
296
312
|
const vsPayload = vsSignal.contextPayload as Record<string, unknown>;
|
|
297
|
-
expect(vsPayload.requesterExternalUserId).toBe(
|
|
313
|
+
expect(vsPayload.requesterExternalUserId).toBe("requester-user-456");
|
|
298
314
|
expect(vsPayload.verificationSessionId).toBeDefined();
|
|
299
|
-
expect(
|
|
315
|
+
expect(
|
|
316
|
+
(vsSignal.attentionHints as Record<string, unknown>).visibleInSourceNow,
|
|
317
|
+
).toBe(true);
|
|
300
318
|
|
|
301
319
|
// Should NOT emit denied signal
|
|
302
320
|
const deniedSignals = emitSignalCalls.filter(
|
|
303
|
-
(c) => c.sourceEventName ===
|
|
321
|
+
(c) => c.sourceEventName === "ingress.trusted_contact.denied",
|
|
304
322
|
);
|
|
305
323
|
expect(deniedSignals.length).toBe(0);
|
|
306
324
|
});
|
|
307
325
|
|
|
308
|
-
test(
|
|
326
|
+
test("deduplication keys prevent duplicate signals", async () => {
|
|
309
327
|
// Set up guardian binding and member record (guardians must pass ACL)
|
|
310
328
|
createBinding({
|
|
311
|
-
assistantId:
|
|
312
|
-
channel:
|
|
313
|
-
guardianExternalUserId:
|
|
314
|
-
guardianDeliveryChatId:
|
|
315
|
-
guardianPrincipalId:
|
|
329
|
+
assistantId: "self",
|
|
330
|
+
channel: "telegram",
|
|
331
|
+
guardianExternalUserId: "guardian-user-789",
|
|
332
|
+
guardianDeliveryChatId: "guardian-chat-789",
|
|
333
|
+
guardianPrincipalId: "guardian-user-789",
|
|
316
334
|
});
|
|
317
335
|
upsertMember({
|
|
318
|
-
assistantId:
|
|
319
|
-
sourceChannel:
|
|
320
|
-
externalUserId:
|
|
321
|
-
externalChatId:
|
|
322
|
-
status:
|
|
323
|
-
policy:
|
|
336
|
+
assistantId: "self",
|
|
337
|
+
sourceChannel: "telegram",
|
|
338
|
+
externalUserId: "guardian-user-789",
|
|
339
|
+
externalChatId: "guardian-chat-789",
|
|
340
|
+
status: "active",
|
|
341
|
+
policy: "allow",
|
|
324
342
|
});
|
|
325
343
|
|
|
326
344
|
const testRequestId = `req-dedup-${Date.now()}`;
|
|
@@ -328,32 +346,34 @@ describe('trusted contact lifecycle notification signals', () => {
|
|
|
328
346
|
const approval = createApprovalRequest({
|
|
329
347
|
runId: `ingress-access-request-${Date.now()}`,
|
|
330
348
|
requestId: testRequestId,
|
|
331
|
-
conversationId:
|
|
332
|
-
assistantId:
|
|
333
|
-
channel:
|
|
334
|
-
requesterExternalUserId:
|
|
335
|
-
requesterChatId:
|
|
336
|
-
guardianExternalUserId:
|
|
337
|
-
guardianChatId:
|
|
338
|
-
toolName:
|
|
339
|
-
riskLevel:
|
|
340
|
-
reason:
|
|
349
|
+
conversationId: "access-req-telegram-requester-user-456",
|
|
350
|
+
assistantId: "self",
|
|
351
|
+
channel: "telegram",
|
|
352
|
+
requesterExternalUserId: "requester-user-456",
|
|
353
|
+
requesterChatId: "requester-chat-456",
|
|
354
|
+
guardianExternalUserId: "guardian-user-789",
|
|
355
|
+
guardianChatId: "guardian-chat-789",
|
|
356
|
+
toolName: "ingress_access_request",
|
|
357
|
+
riskLevel: "access_request",
|
|
358
|
+
reason: "Alice is requesting access",
|
|
341
359
|
expiresAt: Date.now() + GUARDIAN_APPROVAL_TTL_MS,
|
|
342
360
|
});
|
|
343
361
|
|
|
344
362
|
// All guardian_decision signals include the approval ID in the dedupe key
|
|
345
363
|
const guardianReq = buildInboundRequest({
|
|
346
|
-
conversationExternalId:
|
|
347
|
-
actorExternalId:
|
|
348
|
-
actorDisplayName:
|
|
349
|
-
content:
|
|
364
|
+
conversationExternalId: "guardian-chat-789",
|
|
365
|
+
actorExternalId: "guardian-user-789",
|
|
366
|
+
actorDisplayName: "Guardian",
|
|
367
|
+
content: "",
|
|
350
368
|
callbackData: `apr:${testRequestId}:reject`,
|
|
351
369
|
});
|
|
352
370
|
|
|
353
371
|
await handleChannelInbound(guardianReq, undefined, TEST_BEARER_TOKEN);
|
|
354
372
|
|
|
355
373
|
const signals = emitSignalCalls.filter(
|
|
356
|
-
(c) =>
|
|
374
|
+
(c) =>
|
|
375
|
+
typeof c.dedupeKey === "string" &&
|
|
376
|
+
(c.dedupeKey as string).includes(approval.id),
|
|
357
377
|
);
|
|
358
378
|
// guardian_decision and denied — both keyed on approval.id
|
|
359
379
|
expect(signals.length).toBe(2);
|
|
@@ -364,188 +384,191 @@ describe('trusted contact lifecycle notification signals', () => {
|
|
|
364
384
|
// Tests: Activated signal (trusted contact verification success)
|
|
365
385
|
// ---------------------------------------------------------------------------
|
|
366
386
|
|
|
367
|
-
describe(
|
|
387
|
+
describe("trusted contact activated notification signal", () => {
|
|
368
388
|
beforeEach(() => {
|
|
369
389
|
resetState();
|
|
370
390
|
});
|
|
371
391
|
|
|
372
|
-
test(
|
|
392
|
+
test("successful trusted contact verification emits activated signal", async () => {
|
|
373
393
|
// Set up a guardian binding so the verification path allows bypass
|
|
374
394
|
createBinding({
|
|
375
|
-
assistantId:
|
|
376
|
-
channel:
|
|
377
|
-
guardianExternalUserId:
|
|
378
|
-
guardianDeliveryChatId:
|
|
379
|
-
guardianPrincipalId:
|
|
395
|
+
assistantId: "self",
|
|
396
|
+
channel: "telegram",
|
|
397
|
+
guardianExternalUserId: "guardian-user-789",
|
|
398
|
+
guardianDeliveryChatId: "guardian-chat-789",
|
|
399
|
+
guardianPrincipalId: "guardian-user-789",
|
|
380
400
|
});
|
|
381
401
|
|
|
382
402
|
// Create an identity-bound outbound session (simulates M3 approval flow)
|
|
383
403
|
const session = createOutboundSession({
|
|
384
|
-
assistantId:
|
|
385
|
-
channel:
|
|
386
|
-
expectedExternalUserId:
|
|
387
|
-
expectedChatId:
|
|
388
|
-
identityBindingStatus:
|
|
389
|
-
destinationAddress:
|
|
390
|
-
verificationPurpose:
|
|
404
|
+
assistantId: "self",
|
|
405
|
+
channel: "telegram",
|
|
406
|
+
expectedExternalUserId: "requester-user-456",
|
|
407
|
+
expectedChatId: "chat-123",
|
|
408
|
+
identityBindingStatus: "bound",
|
|
409
|
+
destinationAddress: "chat-123",
|
|
410
|
+
verificationPurpose: "trusted_contact",
|
|
391
411
|
});
|
|
392
412
|
|
|
393
413
|
// Requester enters the verification code
|
|
394
414
|
const verifyReq = buildInboundRequest({
|
|
395
415
|
content: session.secret,
|
|
396
|
-
conversationExternalId:
|
|
397
|
-
actorExternalId:
|
|
416
|
+
conversationExternalId: "chat-123",
|
|
417
|
+
actorExternalId: "requester-user-456",
|
|
398
418
|
});
|
|
399
419
|
|
|
400
420
|
await handleChannelInbound(verifyReq, undefined, TEST_BEARER_TOKEN);
|
|
401
421
|
|
|
402
422
|
// Should emit the activated signal
|
|
403
423
|
const activatedSignals = emitSignalCalls.filter(
|
|
404
|
-
(c) => c.sourceEventName ===
|
|
424
|
+
(c) => c.sourceEventName === "ingress.trusted_contact.activated",
|
|
405
425
|
);
|
|
406
426
|
|
|
407
427
|
expect(activatedSignals.length).toBe(1);
|
|
408
428
|
|
|
409
429
|
// Verify payload
|
|
410
|
-
const payload = activatedSignals[0].contextPayload as Record<
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
430
|
+
const payload = activatedSignals[0].contextPayload as Record<
|
|
431
|
+
string,
|
|
432
|
+
unknown
|
|
433
|
+
>;
|
|
434
|
+
expect(payload.sourceChannel).toBe("telegram");
|
|
435
|
+
expect(payload.actorExternalId).toBe("requester-user-456");
|
|
436
|
+
expect(payload.conversationExternalId).toBe("chat-123");
|
|
414
437
|
|
|
415
438
|
// Verify deduplication key includes the user identity
|
|
416
439
|
const dedupeKey = activatedSignals[0].dedupeKey as string;
|
|
417
|
-
expect(dedupeKey).toContain(
|
|
418
|
-
expect(dedupeKey).toContain(
|
|
440
|
+
expect(dedupeKey).toContain("trusted-contact:activated:");
|
|
441
|
+
expect(dedupeKey).toContain("requester-user-456");
|
|
419
442
|
|
|
420
443
|
// Verify attention hints indicate informational (no action required)
|
|
421
444
|
const hints = activatedSignals[0].attentionHints as Record<string, unknown>;
|
|
422
445
|
expect(hints.requiresAction).toBe(false);
|
|
423
|
-
expect(hints.urgency).toBe(
|
|
446
|
+
expect(hints.urgency).toBe("low");
|
|
424
447
|
});
|
|
425
448
|
|
|
426
|
-
test(
|
|
449
|
+
test("re-verification preserves an existing guardian-managed member display name", async () => {
|
|
427
450
|
createBinding({
|
|
428
|
-
assistantId:
|
|
429
|
-
channel:
|
|
430
|
-
guardianExternalUserId:
|
|
431
|
-
guardianDeliveryChatId:
|
|
432
|
-
guardianPrincipalId:
|
|
451
|
+
assistantId: "self",
|
|
452
|
+
channel: "telegram",
|
|
453
|
+
guardianExternalUserId: "guardian-user-789",
|
|
454
|
+
guardianDeliveryChatId: "guardian-chat-789",
|
|
455
|
+
guardianPrincipalId: "guardian-user-789",
|
|
433
456
|
});
|
|
434
457
|
|
|
435
458
|
upsertMember({
|
|
436
|
-
assistantId:
|
|
437
|
-
sourceChannel:
|
|
438
|
-
externalUserId:
|
|
439
|
-
externalChatId:
|
|
440
|
-
status:
|
|
441
|
-
policy:
|
|
442
|
-
displayName:
|
|
459
|
+
assistantId: "self",
|
|
460
|
+
sourceChannel: "telegram",
|
|
461
|
+
externalUserId: "requester-user-456",
|
|
462
|
+
externalChatId: "chat-123",
|
|
463
|
+
status: "revoked",
|
|
464
|
+
policy: "allow",
|
|
465
|
+
displayName: "Jeff",
|
|
443
466
|
});
|
|
444
467
|
|
|
445
468
|
const session = createOutboundSession({
|
|
446
|
-
assistantId:
|
|
447
|
-
channel:
|
|
448
|
-
expectedExternalUserId:
|
|
449
|
-
expectedChatId:
|
|
450
|
-
identityBindingStatus:
|
|
451
|
-
destinationAddress:
|
|
452
|
-
verificationPurpose:
|
|
469
|
+
assistantId: "self",
|
|
470
|
+
channel: "telegram",
|
|
471
|
+
expectedExternalUserId: "requester-user-456",
|
|
472
|
+
expectedChatId: "chat-123",
|
|
473
|
+
identityBindingStatus: "bound",
|
|
474
|
+
destinationAddress: "chat-123",
|
|
475
|
+
verificationPurpose: "trusted_contact",
|
|
453
476
|
});
|
|
454
477
|
|
|
455
478
|
const verifyReq = buildInboundRequest({
|
|
456
479
|
content: session.secret,
|
|
457
|
-
conversationExternalId:
|
|
458
|
-
actorExternalId:
|
|
459
|
-
actorDisplayName:
|
|
480
|
+
conversationExternalId: "chat-123",
|
|
481
|
+
actorExternalId: "requester-user-456",
|
|
482
|
+
actorDisplayName: "Noa Flaherty",
|
|
460
483
|
});
|
|
461
484
|
|
|
462
485
|
await handleChannelInbound(verifyReq, undefined, TEST_BEARER_TOKEN);
|
|
463
486
|
|
|
464
487
|
const member = findMember({
|
|
465
|
-
assistantId:
|
|
466
|
-
sourceChannel:
|
|
467
|
-
externalUserId:
|
|
468
|
-
externalChatId:
|
|
488
|
+
assistantId: "self",
|
|
489
|
+
sourceChannel: "telegram",
|
|
490
|
+
externalUserId: "requester-user-456",
|
|
491
|
+
externalChatId: "chat-123",
|
|
469
492
|
});
|
|
470
493
|
expect(member).not.toBeNull();
|
|
471
|
-
expect(member!.status).toBe(
|
|
472
|
-
expect(member!.displayName).toBe(
|
|
494
|
+
expect(member!.status).toBe("active");
|
|
495
|
+
expect(member!.displayName).toBe("Jeff");
|
|
473
496
|
});
|
|
474
497
|
|
|
475
|
-
test(
|
|
498
|
+
test("guardian verification does NOT emit activated signal", async () => {
|
|
476
499
|
// Create an inbound challenge (guardian flow, not trusted contact)
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
const { secret } = createVerificationChallenge(
|
|
500
|
+
const { createVerificationChallenge } =
|
|
501
|
+
await import("../runtime/channel-guardian-service.js");
|
|
502
|
+
const { secret } = createVerificationChallenge("self", "telegram");
|
|
480
503
|
|
|
481
504
|
// "Guardian" enters the verification code
|
|
482
505
|
const verifyReq = buildInboundRequest({
|
|
483
506
|
content: secret,
|
|
484
|
-
conversationExternalId:
|
|
485
|
-
actorExternalId:
|
|
507
|
+
conversationExternalId: "guardian-chat-new",
|
|
508
|
+
actorExternalId: "guardian-user-new",
|
|
486
509
|
});
|
|
487
510
|
|
|
488
511
|
await handleChannelInbound(verifyReq, undefined, TEST_BEARER_TOKEN);
|
|
489
512
|
|
|
490
513
|
// Should NOT emit the trusted_contact.activated signal
|
|
491
514
|
const activatedSignals = emitSignalCalls.filter(
|
|
492
|
-
(c) => c.sourceEventName ===
|
|
515
|
+
(c) => c.sourceEventName === "ingress.trusted_contact.activated",
|
|
493
516
|
);
|
|
494
517
|
expect(activatedSignals.length).toBe(0);
|
|
495
518
|
});
|
|
496
519
|
|
|
497
|
-
test(
|
|
520
|
+
test("voice access_request resolver has registered handler for access_request kind", () => {
|
|
498
521
|
// The access_request resolver is registered during module load. When the
|
|
499
522
|
// source channel is 'voice', it should directly activate the member via
|
|
500
523
|
// upsertMember (no verification session). This test validates the resolver
|
|
501
524
|
// is registered and accessible.
|
|
502
|
-
const resolver = getResolver(
|
|
525
|
+
const resolver = getResolver("access_request");
|
|
503
526
|
expect(resolver).toBeDefined();
|
|
504
|
-
expect(resolver!.kind).toBe(
|
|
527
|
+
expect(resolver!.kind).toBe("access_request");
|
|
505
528
|
});
|
|
506
529
|
|
|
507
|
-
test(
|
|
530
|
+
test("member is persisted BEFORE activated signal is emitted", async () => {
|
|
508
531
|
// Set up a guardian binding
|
|
509
532
|
createBinding({
|
|
510
|
-
assistantId:
|
|
511
|
-
channel:
|
|
512
|
-
guardianExternalUserId:
|
|
513
|
-
guardianDeliveryChatId:
|
|
514
|
-
guardianPrincipalId:
|
|
533
|
+
assistantId: "self",
|
|
534
|
+
channel: "telegram",
|
|
535
|
+
guardianExternalUserId: "guardian-user-789",
|
|
536
|
+
guardianDeliveryChatId: "guardian-chat-789",
|
|
537
|
+
guardianPrincipalId: "guardian-user-789",
|
|
515
538
|
});
|
|
516
539
|
|
|
517
540
|
const session = createOutboundSession({
|
|
518
|
-
assistantId:
|
|
519
|
-
channel:
|
|
520
|
-
expectedExternalUserId:
|
|
521
|
-
expectedChatId:
|
|
522
|
-
identityBindingStatus:
|
|
523
|
-
destinationAddress:
|
|
524
|
-
verificationPurpose:
|
|
541
|
+
assistantId: "self",
|
|
542
|
+
channel: "telegram",
|
|
543
|
+
expectedExternalUserId: "requester-user-456",
|
|
544
|
+
expectedChatId: "chat-123",
|
|
545
|
+
identityBindingStatus: "bound",
|
|
546
|
+
destinationAddress: "chat-123",
|
|
547
|
+
verificationPurpose: "trusted_contact",
|
|
525
548
|
});
|
|
526
549
|
|
|
527
550
|
const verifyReq = buildInboundRequest({
|
|
528
551
|
content: session.secret,
|
|
529
|
-
conversationExternalId:
|
|
530
|
-
actorExternalId:
|
|
552
|
+
conversationExternalId: "chat-123",
|
|
553
|
+
actorExternalId: "requester-user-456",
|
|
531
554
|
});
|
|
532
555
|
|
|
533
556
|
await handleChannelInbound(verifyReq, undefined, TEST_BEARER_TOKEN);
|
|
534
557
|
|
|
535
558
|
// The activated signal was emitted
|
|
536
559
|
const activatedSignals = emitSignalCalls.filter(
|
|
537
|
-
(c) => c.sourceEventName ===
|
|
560
|
+
(c) => c.sourceEventName === "ingress.trusted_contact.activated",
|
|
538
561
|
);
|
|
539
562
|
expect(activatedSignals.length).toBe(1);
|
|
540
563
|
|
|
541
564
|
// Verify the member was already persisted (the signal fires after upsertMember)
|
|
542
565
|
const member = findMember({
|
|
543
|
-
assistantId:
|
|
544
|
-
sourceChannel:
|
|
545
|
-
externalUserId:
|
|
566
|
+
assistantId: "self",
|
|
567
|
+
sourceChannel: "telegram",
|
|
568
|
+
externalUserId: "requester-user-456",
|
|
546
569
|
});
|
|
547
570
|
expect(member).not.toBeNull();
|
|
548
|
-
expect(member!.status).toBe(
|
|
549
|
-
expect(member!.policy).toBe(
|
|
571
|
+
expect(member!.status).toBe("active");
|
|
572
|
+
expect(member!.policy).toBe("allow");
|
|
550
573
|
});
|
|
551
574
|
});
|