@vellumai/assistant 0.10.2-dev.202606250318.5e7cfb0 → 0.10.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/bun.lock +0 -20
- package/docs/workspace-tools.md +33 -42
- package/eslint-rules/cli-no-daemon-internals.js +0 -6
- package/node_modules/@vellumai/gateway-client/src/__tests__/trust-verdict-contract.test.ts +0 -31
- package/node_modules/@vellumai/gateway-client/src/gateway-ipc-contracts.ts +0 -44
- package/node_modules/@vellumai/gateway-client/src/index.ts +0 -14
- package/node_modules/@vellumai/gateway-client/src/trust-verdict-contract.ts +0 -17
- package/node_modules/@vellumai/service-contracts/package.json +0 -1
- package/node_modules/@vellumai/service-contracts/src/index.ts +0 -1
- package/openapi.yaml +0 -155
- package/package.json +1 -4
- package/scripts/test.sh +15 -36
- package/src/__tests__/actor-token-service.test.ts +14 -36
- package/src/__tests__/agent-loop-override-profile.test.ts +0 -1
- package/src/__tests__/agent-wake-disk-pressure-callsite.test.ts +0 -2
- package/src/__tests__/agent-wake-override-profile.test.ts +0 -2
- package/src/__tests__/annotate-activity-metadata.test.ts +0 -2
- package/src/__tests__/annotate-risk-options.test.ts +0 -2
- package/src/__tests__/approval-cascade.test.ts +0 -2
- package/src/__tests__/assistant-attachments.test.ts +0 -42
- package/src/__tests__/background-workers-disk-pressure.test.ts +0 -2
- package/src/__tests__/btw-routes.test.ts +0 -2
- package/src/__tests__/build-persisted-content.test.ts +0 -2
- package/src/__tests__/call-controller.test.ts +0 -19
- package/src/__tests__/channel-guardian.test.ts +58 -94
- package/src/__tests__/channel-reply-delivery.test.ts +0 -2
- package/src/__tests__/compaction-events.test.ts +0 -2
- package/src/__tests__/compaction.benchmark.test.ts +0 -2
- package/src/__tests__/compactor-call-site-logging.test.ts +0 -2
- package/src/__tests__/compactor-low-watermark-cut.test.ts +0 -2
- package/src/__tests__/compactor-preserved-tail-count.test.ts +0 -2
- package/src/__tests__/compactor-summary-call-truncation.test.ts +0 -2
- package/src/__tests__/compactor-web-search-strip.test.ts +0 -2
- package/src/__tests__/config-loader-backfill.test.ts +10 -123
- package/src/__tests__/config-schema.test.ts +0 -1
- package/src/__tests__/confirmation-request-guardian-bridge.test.ts +29 -31
- package/src/__tests__/contacts-relay-reads.test.ts +15 -13
- package/src/__tests__/conversation-abort-tool-results.test.ts +0 -2
- package/src/__tests__/conversation-agent-loop-disk-pressure.test.ts +0 -2
- package/src/__tests__/conversation-agent-loop-inference-profile.test.ts +0 -2
- package/src/__tests__/conversation-agent-loop-overflow.test.ts +0 -2
- package/src/__tests__/conversation-agent-loop.test.ts +0 -134
- package/src/__tests__/conversation-analysis-routes.test.ts +0 -2
- package/src/__tests__/conversation-app-control-lifecycle.test.ts +0 -2
- package/src/__tests__/conversation-confirmation-signals.test.ts +0 -2
- package/src/__tests__/conversation-history-web-search.test.ts +0 -2
- package/src/__tests__/conversation-load-history-repair.test.ts +0 -2
- package/src/__tests__/conversation-load-history-stripped.test.ts +0 -2
- package/src/__tests__/conversation-pairing.test.ts +0 -2
- package/src/__tests__/conversation-process-app-control-preactivation.test.ts +0 -2
- package/src/__tests__/conversation-process-callsite.test.ts +0 -2
- package/src/__tests__/conversation-provider-retry-repair.test.ts +0 -2
- package/src/__tests__/conversation-queue.test.ts +0 -91
- package/src/__tests__/conversation-routes-guardian-reply.test.ts +0 -14
- package/src/__tests__/conversation-routes-slash-commands.test.ts +0 -14
- package/src/__tests__/conversation-slash-queue.test.ts +0 -2
- package/src/__tests__/conversation-slash-unknown.test.ts +0 -2
- package/src/__tests__/conversation-speed-override.test.ts +0 -2
- package/src/__tests__/conversation-surfaces-task-progress.test.ts +0 -29
- package/src/__tests__/conversation-title-service.test.ts +0 -2
- package/src/__tests__/conversation-tool-setup-attribution.test.ts +0 -47
- package/src/__tests__/conversation-usage.test.ts +0 -2
- package/src/__tests__/conversation-workspace-cache-state.test.ts +0 -2
- package/src/__tests__/conversation-workspace-injection.test.ts +0 -2
- package/src/__tests__/conversation-workspace-tool-tracking.test.ts +0 -2
- package/src/__tests__/credential-security-invariants.test.ts +1 -1
- package/src/__tests__/db-migration-rollback.test.ts +171 -205
- package/src/__tests__/db-test-helpers.ts +4 -5
- package/src/__tests__/deterministic-verification-control-plane.test.ts +2 -4
- package/src/__tests__/disk-pressure-guard.test.ts +0 -41
- package/src/__tests__/dm-persistence.test.ts +0 -2
- package/src/__tests__/emit-signal-routing-intent.test.ts +5 -10
- package/src/__tests__/events-dev-bypass-actor.test.ts +1 -7
- package/src/__tests__/exploration-drift-hook.test.ts +2 -3
- package/src/__tests__/filing-service.test.ts +0 -2
- package/src/__tests__/guardian-binding-drift-heal.test.ts +10 -75
- package/src/__tests__/guardian-dispatch.test.ts +1 -95
- package/src/__tests__/guardian-outbound-http.test.ts +0 -13
- package/src/__tests__/heartbeat-disk-pressure.test.ts +0 -2
- package/src/__tests__/heartbeat-service.test.ts +0 -2
- package/src/__tests__/helpers/channel-test-adapter.ts +7 -1
- package/src/__tests__/host-app-control-routes.test.ts +30 -24
- package/src/__tests__/host-bash-routes.test.ts +41 -31
- package/src/__tests__/host-browser-routes.test.ts +32 -26
- package/src/__tests__/host-cu-routes-targeted.test.ts +33 -25
- package/src/__tests__/host-file-routes-targeted.test.ts +52 -40
- package/src/__tests__/host-transfer-routes-targeted.test.ts +43 -31
- package/src/__tests__/http-user-message-parity.test.ts +8 -290
- package/src/__tests__/inbound-invite-redemption.test.ts +0 -28
- package/src/__tests__/inbound-slack-persistence.test.ts +0 -2
- package/src/__tests__/invite-redemption-service.test.ts +0 -198
- package/src/__tests__/llm-context-normalization.test.ts +0 -105
- package/src/__tests__/llm-request-log-error-payload.test.ts +9 -71
- package/src/__tests__/llm-usage-store.test.ts +0 -25
- package/src/__tests__/mcp-health-check.test.ts +1 -2
- package/src/__tests__/media-stream-server-integration.test.ts +0 -127
- package/src/__tests__/memory-retrieval-hook.test.ts +0 -2
- package/src/__tests__/messaging-send-tool.test.ts +0 -2
- package/src/__tests__/migration-import-from-url.test.ts +2 -2
- package/src/__tests__/mtime-cache.test.ts +5 -146
- package/src/__tests__/native-web-search.test.ts +0 -2
- package/src/__tests__/non-member-access-request.test.ts +17 -189
- package/src/__tests__/notification-broadcaster.test.ts +0 -4
- package/src/__tests__/notification-decision-recipient-context.test.ts +32 -33
- package/src/__tests__/notification-deep-link.test.ts +0 -6
- package/src/__tests__/notification-guardian-path.test.ts +0 -19
- package/src/__tests__/openai-provider.test.ts +12 -22
- package/src/__tests__/openai-responses-provider.test.ts +2 -12
- package/src/__tests__/outbound-slack-persistence.test.ts +0 -2
- package/src/__tests__/pending-interactions-resolved-event.test.ts +4 -7
- package/src/__tests__/persistence-secret-redaction.test.ts +0 -2
- package/src/__tests__/plugin-bootstrap.test.ts +73 -3
- package/src/__tests__/plugin-route-contribution.test.ts +17 -4
- package/src/__tests__/plugin-tool-contribution.test.ts +18 -3
- package/src/__tests__/plugin-types.test.ts +2 -0
- package/src/__tests__/process-message-background-slack.test.ts +0 -2
- package/src/__tests__/process-message-display-content.test.ts +0 -2
- package/src/__tests__/provider-error-scenarios.test.ts +4 -5
- package/src/__tests__/provider-usage-tracking.test.ts +0 -39
- package/src/__tests__/regenerate-fire-and-forget-trace.test.ts +0 -2
- package/src/__tests__/registry.test.ts +1 -4
- package/src/__tests__/relay-server.test.ts +25 -694
- package/src/__tests__/runtime-attachment-metadata.test.ts +1 -0
- package/src/__tests__/secret-ingress-http.test.ts +0 -14
- package/src/__tests__/send-endpoint-busy.test.ts +8 -30
- package/src/__tests__/skills.test.ts +0 -44
- package/src/__tests__/slack-inbound-verification.test.ts +2 -47
- package/src/__tests__/stt-hints.test.ts +13 -44
- package/src/__tests__/subagent-detail.test.ts +0 -27
- package/src/__tests__/subagent-disposal.test.ts +0 -65
- package/src/__tests__/subagent-notify-parent.test.ts +0 -2
- package/src/__tests__/subagent-role-registry.test.ts +2 -7
- package/src/__tests__/subagent-spawn-tool-fork.test.ts +0 -2
- package/src/__tests__/subagent-tools.test.ts +0 -2
- package/src/__tests__/suggestion-routes.test.ts +0 -2
- package/src/__tests__/title-generate-hook.test.ts +0 -2
- package/src/__tests__/tool-executor-lifecycle-events.test.ts +0 -2
- package/src/__tests__/tool-executor.test.ts +11 -16
- package/src/__tests__/tool-preview-lifecycle.test.ts +0 -2
- package/src/__tests__/tool-result-metadata-plumbing.test.ts +0 -2
- package/src/__tests__/tool-start-timestamp.test.ts +0 -2
- package/src/__tests__/trusted-contact-inline-approval-integration.test.ts +10 -10
- package/src/__tests__/twilio-routes.test.ts +0 -96
- package/src/__tests__/ui-file-upload-surface.test.ts +0 -86
- package/src/__tests__/verification-control-plane-policy.test.ts +0 -2
- package/src/__tests__/voice-invite-redemption.test.ts +0 -33
- package/src/__tests__/web-search-backend-failure.test.ts +0 -2
- package/src/__tests__/workspace-migration-remove-hooks.test.ts +35 -14
- package/src/__tests__/workspace-tool-loader.test.ts +2 -195
- package/src/__tests__/workspace-tools-watcher-flag.test.ts +70 -0
- package/src/agent/loop.ts +0 -56
- package/src/api/index.ts +1 -19
- package/src/api/responses/llm-request-log-entry.ts +0 -29
- package/src/api/responses/subagent-detail.ts +0 -17
- package/src/api/surfaces.ts +3 -39
- package/src/approvals/guardian-request-resolvers.ts +11 -1
- package/src/calls/__tests__/relay-setup-router.test.ts +4 -262
- package/src/calls/call-domain.ts +3 -3
- package/src/calls/guardian-dispatch.ts +8 -10
- package/src/calls/inbound-trust-reader.ts +1 -17
- package/src/calls/media-stream-server.ts +0 -21
- package/src/calls/relay-server.ts +50 -167
- package/src/calls/relay-setup-router.ts +7 -37
- package/src/calls/relay-verification.ts +4 -4
- package/src/calls/stt-hints.ts +12 -9
- package/src/calls/twilio-routes.ts +4 -14
- package/src/channels/types.ts +20 -10
- package/src/cli/commands/__tests__/cache.test.ts +1 -8
- package/src/cli/commands/cache.ts +181 -194
- package/src/cli/commands/db/__tests__/repair.test.ts +5 -6
- package/src/cli/commands/db/status.ts +1 -37
- package/src/cli/commands/mcp.ts +218 -252
- package/src/cli/commands/memory/index.ts +0 -2
- package/src/cli/commands/plugins.ts +3 -75
- package/src/cli/lib/__tests__/install-from-github.test.ts +0 -102
- package/src/cli/lib/__tests__/list-installed-plugins.test.ts +1 -160
- package/src/cli/lib/list-installed-plugins.ts +1 -179
- package/src/config/__tests__/sync-gated-profiles.test.ts +3 -11
- package/src/config/bundled-skills/contacts/tools/contact-merge.ts +17 -27
- package/src/config/bundled-skills/contacts/tools/contact-search.ts +3 -13
- package/src/config/bundled-skills/subagent/SKILL.md +1 -1
- package/src/config/bundled-skills/subagent/TOOLS.json +1 -1
- package/src/config/feature-flag-registry.json +13 -5
- package/src/config/loader.ts +5 -38
- package/src/config/schemas/__tests__/memory-v3.test.ts +0 -1
- package/src/config/schemas/memory-lifecycle.ts +0 -12
- package/src/config/schemas/memory-v3.ts +0 -7
- package/src/config/schemas/memory.ts +0 -4
- package/src/config/schemas/timeouts.ts +0 -8
- package/src/config/seed-inference-profiles.ts +11 -21
- package/src/config/skills.ts +5 -27
- package/src/config/sync-gated-profiles.ts +13 -12
- package/src/contacts/contacts-write.ts +0 -3
- package/src/daemon/assistant-attachments.ts +4 -27
- package/src/daemon/conversation-agent-loop.ts +0 -28
- package/src/daemon/conversation-process.ts +16 -35
- package/src/daemon/conversation-surfaces.ts +38 -111
- package/src/daemon/conversation-tool-setup.ts +16 -50
- package/src/daemon/conversation.ts +1 -13
- package/src/daemon/disk-pressure-guard.ts +2 -12
- package/src/daemon/event-loop-watchdog.ts +1 -28
- package/src/daemon/external-plugins-bootstrap.ts +34 -4
- package/src/daemon/handlers/__tests__/config-a2a-redeem.test.ts +0 -25
- package/src/daemon/handlers/config-a2a.ts +14 -6
- package/src/daemon/handlers/config-channels.ts +22 -78
- package/src/daemon/handlers/conversations.ts +0 -77
- package/src/daemon/lifecycle.ts +0 -4
- package/src/daemon/mcp-reload-service.ts +0 -10
- package/src/daemon/memory-v2-startup.test.ts +0 -72
- package/src/daemon/memory-v2-startup.ts +19 -87
- package/src/daemon/message-types/conversations.ts +0 -2
- package/src/daemon/message-types/surfaces.ts +12 -12
- package/src/daemon/server.ts +4 -0
- package/src/daemon/shutdown-handlers.ts +0 -20
- package/src/daemon/tool-setup-types.ts +0 -9
- package/src/daemon/workspace-tools-watcher.ts +328 -0
- package/src/ipc/__tests__/clients-list-ipc.test.ts +1 -1
- package/src/ipc/assistant-server.ts +2 -2
- package/src/mcp/__tests__/mcp-auth-orchestrator.test.ts +0 -1
- package/src/mcp/client.ts +1 -15
- package/src/mcp/mcp-auth-orchestrator.ts +1 -6
- package/src/mcp/mcp-oauth-provider.ts +8 -19
- package/src/memory/__tests__/memory-retrospective-job.test.ts +0 -8
- package/src/memory/conversation-crud.ts +0 -38
- package/src/memory/db-connection.ts +3 -22
- package/src/memory/db-init.ts +502 -36
- package/src/memory/db-singleton.ts +4 -6
- package/src/memory/jobs-worker.ts +0 -58
- package/src/memory/llm-request-log-store.ts +1 -26
- package/src/memory/llm-usage-store.ts +20 -48
- package/src/memory/memory-retrospective-job.ts +8 -9
- package/src/memory/migrations/209-strip-thinking-from-consolidated.ts +56 -130
- package/src/memory/migrations/__tests__/run-migrations.test.ts +2 -2
- package/src/memory/migrations/registry.ts +573 -0
- package/src/memory/migrations/run-migrations.ts +6 -90
- package/src/memory/migrations/validate-migration-state.ts +66 -101
- package/src/memory/schema/conversations.ts +0 -9
- package/src/memory/schema/infrastructure.ts +0 -20
- package/src/memory/v2/__tests__/cli-command-store.test.ts +0 -25
- package/src/memory/v2/__tests__/skill-store.test.ts +0 -80
- package/src/memory/v2/cli-command-store.ts +38 -75
- package/src/memory/v2/prompts/consolidation.ts +82 -13
- package/src/memory/v2/prompts/router.ts +93 -21
- package/src/memory/v2/skill-store.ts +31 -68
- package/src/notifications/__tests__/broadcaster.test.ts +8 -16
- package/src/notifications/__tests__/decision-engine.test.ts +9 -78
- package/src/notifications/broadcaster.ts +1 -8
- package/src/notifications/decision-engine.ts +7 -15
- package/src/notifications/destination-resolver.ts +24 -68
- package/src/notifications/emit-signal.ts +14 -39
- package/src/permissions/question-prompter.test.ts +1 -1
- package/src/permissions/question-prompter.ts +4 -7
- package/src/plugin-api/index.ts +6 -6
- package/src/plugin-api/types.ts +5 -3
- package/src/plugin-api/vision-support.test.ts +4 -28
- package/src/plugin-api/vision-support.ts +31 -66
- package/src/plugins/defaults/advisor/__tests__/consult.test.ts +0 -161
- package/src/plugins/defaults/advisor/consult.ts +6 -110
- package/src/plugins/defaults/advisor/steering.ts +2 -14
- package/src/plugins/defaults/advisor/tools/advisor.ts +5 -32
- package/src/plugins/defaults/exploration-drift/hooks/post-tool-use.ts +1 -2
- package/src/plugins/defaults/image-fallback/__tests__/image-fallback.test.ts +7 -47
- package/src/plugins/defaults/image-fallback/hooks/post-tool-use.ts +11 -10
- package/src/plugins/defaults/image-fallback/hooks/user-prompt-submit.ts +20 -12
- package/src/plugins/defaults/image-fallback/src/caption-blocks.ts +11 -42
- package/src/plugins/defaults/memory-v3-shadow/__tests__/injection.test.ts +3 -33
- package/src/plugins/defaults/memory-v3-shadow/__tests__/pool-select.test.ts +4 -48
- package/src/plugins/defaults/memory-v3-shadow/__tests__/shadow-plugin.test.ts +8 -4
- package/src/plugins/defaults/memory-v3-shadow/injector.ts +15 -43
- package/src/plugins/defaults/memory-v3-shadow/orchestrate.ts +2 -11
- package/src/plugins/defaults/memory-v3-shadow/pool-select.ts +13 -77
- package/src/plugins/defaults/memory-v3-shadow/shadow-plugin.ts +11 -12
- package/src/plugins/mtime-cache.ts +291 -76
- package/src/plugins/pipeline.ts +13 -111
- package/src/plugins/types.ts +2 -0
- package/src/providers/anthropic/client.ts +0 -5
- package/src/providers/call-site-routing.ts +0 -4
- package/src/providers/model-catalog.ts +0 -16
- package/src/providers/openai/__tests__/api-error-detail.test.ts +120 -0
- package/src/providers/openai/chat-completions-provider.ts +83 -37
- package/src/providers/openai/responses-provider.ts +46 -50
- package/src/providers/openrouter/client.ts +0 -5
- package/src/providers/provider-send-message.ts +0 -4
- package/src/providers/ratelimit.ts +0 -4
- package/src/providers/retry.ts +0 -4
- package/src/providers/types.ts +0 -9
- package/src/providers/usage-tracking.ts +0 -4
- package/src/runtime/__tests__/trust-verdict-consumer.test.ts +3 -335
- package/src/runtime/access-request-helper.ts +39 -19
- package/src/runtime/actor-trust-resolver.ts +2 -2
- package/src/runtime/assistant-event-hub.ts +1 -1
- package/src/runtime/assistant-stream-state.ts +2 -9
- package/src/runtime/auth/require-bound-guardian.ts +11 -21
- package/src/runtime/channel-verification-service.ts +31 -56
- package/src/runtime/confirmation-request-guardian-bridge.ts +3 -3
- package/src/runtime/guardian-vellum-migration.ts +7 -66
- package/src/runtime/invite-redemption-service.ts +187 -198
- package/src/runtime/local-actor-identity.ts +11 -76
- package/src/runtime/pending-interactions.ts +1 -11
- package/src/runtime/routes/__tests__/channel-verification-revoke.test.ts +5 -56
- package/src/runtime/routes/__tests__/channel-verification-routes.test.ts +1 -1
- package/src/runtime/routes/__tests__/surface-action-routes.test.ts +0 -187
- package/src/runtime/routes/browser-routes.ts +1 -1
- package/src/runtime/routes/canonical-guardian-expiry-sweep.ts +5 -13
- package/src/runtime/routes/channel-verification-routes.ts +3 -3
- package/src/runtime/routes/contact-routes.ts +32 -8
- package/src/runtime/routes/conversation-cli-routes.ts +5 -4
- package/src/runtime/routes/conversation-list-routes.ts +7 -4
- package/src/runtime/routes/conversation-query-routes.ts +0 -72
- package/src/runtime/routes/conversation-routes.ts +85 -84
- package/src/runtime/routes/events-routes.ts +2 -2
- package/src/runtime/routes/global-search-routes.ts +1 -3
- package/src/runtime/routes/guardian-action-routes.ts +5 -4
- package/src/runtime/routes/host-app-control-routes.ts +4 -5
- package/src/runtime/routes/host-bash-routes.ts +4 -5
- package/src/runtime/routes/host-browser-routes.ts +11 -9
- package/src/runtime/routes/host-cu-routes.ts +4 -5
- package/src/runtime/routes/host-file-routes.ts +4 -5
- package/src/runtime/routes/host-transfer-routes.ts +6 -6
- package/src/runtime/routes/http-adapter.ts +1 -1
- package/src/runtime/routes/identity-routes.ts +2 -3
- package/src/runtime/routes/inbound-message-handler.ts +5 -5
- package/src/runtime/routes/inbound-stages/acl-enforcement.test.ts +5 -97
- package/src/runtime/routes/inbound-stages/acl-enforcement.ts +49 -61
- package/src/runtime/routes/inbound-stages/background-dispatch.ts +4 -16
- package/src/runtime/routes/inbound-stages/escalation-intercept.ts +7 -7
- package/src/runtime/routes/inbound-stages/guardian-activation-intercept.test.ts +8 -21
- package/src/runtime/routes/inbound-stages/guardian-activation-intercept.ts +3 -14
- package/src/runtime/routes/index.ts +0 -2
- package/src/runtime/routes/llm-context-normalization.ts +0 -83
- package/src/runtime/routes/mcp-auth-routes.ts +19 -171
- package/src/runtime/routes/migration-rollback-routes.ts +3 -4
- package/src/runtime/routes/migration-routes.ts +1 -4
- package/src/runtime/routes/subagents-routes.ts +0 -5
- package/src/runtime/routes/surface-action-routes.ts +56 -42
- package/src/runtime/services/__tests__/conversation-serializer.test.ts +0 -1
- package/src/runtime/services/conversation-serializer.ts +9 -7
- package/src/runtime/tool-grant-request-helper.ts +3 -3
- package/src/runtime/trust-verdict-consumer.ts +9 -85
- package/src/runtime/verification-outbound-actions.ts +18 -18
- package/src/signals/user-message.ts +0 -16
- package/src/subagent/manager.ts +0 -9
- package/src/subagent/types.ts +3 -3
- package/src/telemetry/types.ts +1 -34
- package/src/telemetry/usage-telemetry-reporter.test.ts +2 -3
- package/src/telemetry/usage-telemetry-reporter.ts +3 -87
- package/src/tools/ask-question/ask-question-tool.test.ts +0 -29
- package/src/tools/ask-question/ask-question-tool.ts +0 -13
- package/src/tools/executor.ts +4 -4
- package/src/tools/registry.ts +0 -18
- package/src/tools/shared/filesystem/path-policy.ts +5 -12
- package/src/tools/tool-approval-handler.ts +1 -1
- package/src/tools/tool-defaults.ts +2 -9
- package/src/tools/tool-manifest.ts +0 -3
- package/src/tools/types.ts +2 -17
- package/src/tools/workspace-tools/loader.ts +244 -348
- package/src/util/errors.ts +1 -26
- package/src/util/platform.ts +0 -5
- package/src/workflows/library.test.ts +0 -140
- package/src/workflows/library.ts +28 -82
- package/src/workspace/migrations/017-seed-persona-dirs.ts +34 -3
- package/src/workspace/migrations/019-scope-journal-to-guardian.ts +24 -3
- package/src/workspace/migrations/048-remove-workspace-hooks.ts +66 -14
- package/src/workspace/migrations/registry.ts +0 -2
- package/node_modules/@vellumai/gateway-client/src/__tests__/guardian-delivery-contract.test.ts +0 -91
- package/node_modules/@vellumai/gateway-client/src/guardian-delivery-contract.ts +0 -48
- package/node_modules/@vellumai/service-contracts/src/__tests__/channels.test.ts +0 -28
- package/node_modules/@vellumai/service-contracts/src/channels.ts +0 -41
- package/src/__tests__/code-search-tool.test.ts +0 -585
- package/src/__tests__/guardian-expiry-notifier.test.ts +0 -282
- package/src/__tests__/mcp-config-secret-boundary.test.ts +0 -390
- package/src/__tests__/plugin-pipeline.test.ts +0 -96
- package/src/__tests__/sse-actor-principal-guardian-source.test.ts +0 -102
- package/src/__tests__/steer-on-enqueue-question.test.ts +0 -181
- package/src/__tests__/workspace-migration-111-prune-seeded-callsite-defaults.test.ts +0 -208
- package/src/agent/loop-exclusive-tool.test.ts +0 -150
- package/src/api/constants/sse-replay.ts +0 -41
- package/src/api/events/conversation-notice.ts +0 -26
- package/src/approvals/guardian-channel-delivery.ts +0 -30
- package/src/approvals/guardian-expiry-notifier.ts +0 -148
- package/src/cli/commands/memory/__tests__/worker.test.ts +0 -302
- package/src/cli/commands/memory/worker.ts +0 -175
- package/src/config/__tests__/loader-callsite-strip-fallback.test.ts +0 -143
- package/src/config/prune-seeded-callsite-defaults.ts +0 -110
- package/src/contacts/__tests__/contacts-write-revoke-relay.test.ts +0 -129
- package/src/contacts/__tests__/guardian-delivery-reader.test.ts +0 -312
- package/src/contacts/__tests__/member-write-relay.test.ts +0 -202
- package/src/contacts/guardian-delivery-reader.ts +0 -223
- package/src/contacts/member-write-relay.ts +0 -189
- package/src/daemon/conversation-notices.ts +0 -60
- package/src/daemon/handlers/__tests__/config-channels.test.ts +0 -225
- package/src/hooks/hook-loader.ts +0 -341
- package/src/mcp/mcp-header-store.ts +0 -134
- package/src/memory/__tests__/301-create-watchdog-events.test.ts +0 -110
- package/src/memory/__tests__/prompt-override.test.ts +0 -192
- package/src/memory/__tests__/watchdog-events-store.test.ts +0 -161
- package/src/memory/migrations/300-add-processing-started-at.ts +0 -30
- package/src/memory/migrations/301-create-watchdog-events.ts +0 -45
- package/src/memory/migrations/__tests__/209-strip-thinking-from-consolidated.test.ts +0 -224
- package/src/memory/prompt-override.ts +0 -129
- package/src/memory/steps.ts +0 -573
- package/src/memory/watchdog-events-store.ts +0 -87
- package/src/memory/worker-control.ts +0 -118
- package/src/memory/worker-process.ts +0 -72
- package/src/notifications/__tests__/connected-channels.test.ts +0 -114
- package/src/notifications/__tests__/destination-resolver.test.ts +0 -256
- package/src/onboarding/checkin-event.test.ts +0 -222
- package/src/onboarding/checkin-event.ts +0 -321
- package/src/onboarding/schedule-checkin.ts +0 -190
- package/src/plugins/defaults/advisor/__tests__/context-pack-gating.test.ts +0 -106
- package/src/plugins/defaults/advisor/__tests__/context-pack.test.ts +0 -60
- package/src/plugins/defaults/advisor/context-pack.ts +0 -288
- package/src/plugins/defaults/memory-v3-shadow/pool-select.test.ts +0 -146
- package/src/plugins/surface-import.ts +0 -121
- package/src/providers/openai/__tests__/api-error-normalization.test.ts +0 -321
- package/src/providers/openai/api-error-normalization.ts +0 -270
- package/src/runtime/__tests__/channel-verification-service.test.ts +0 -133
- package/src/runtime/__tests__/guardian-vellum-migration.test.ts +0 -181
- package/src/runtime/__tests__/is-guardian-bound-for-channel.test.ts +0 -66
- package/src/runtime/__tests__/local-principal-trust.test.ts +0 -164
- package/src/runtime/anchored-guardian.test.ts +0 -156
- package/src/runtime/anchored-guardian.ts +0 -135
- package/src/runtime/auth/__tests__/require-bound-guardian.test.ts +0 -99
- package/src/runtime/local-principal-trust.ts +0 -52
- package/src/runtime/routes/__tests__/contact-routes.test.ts +0 -212
- package/src/runtime/routes/__tests__/global-search-routes.test.ts +0 -93
- package/src/runtime/routes/onboarding-checkin-routes.ts +0 -86
- package/src/tools/filesystem/search.ts +0 -543
- package/src/util/telemetry-db-path.ts +0 -24
- package/src/workspace/migrations/111-prune-seeded-callsite-defaults.ts +0 -134
|
@@ -62,21 +62,6 @@ mock.module("../runtime/guardian-reply-router.js", () => ({
|
|
|
62
62
|
routeGuardianReply: routeGuardianReplyMock,
|
|
63
63
|
}));
|
|
64
64
|
|
|
65
|
-
// Stub for the shared reset-drift helper. handleSendMessage only consumes its
|
|
66
|
-
// result (a guardian TrustContext or null) on a first-pass-unknown actor; the
|
|
67
|
-
// gate itself is covered in runtime/__tests__/guardian-vellum-migration.test.ts.
|
|
68
|
-
const reResolveCalls: string[] = [];
|
|
69
|
-
let mockReResolve: { trustClass: string; sourceChannel: string } | null = null;
|
|
70
|
-
mock.module("../runtime/guardian-vellum-migration.js", () => ({
|
|
71
|
-
reResolveTrustOnResetDrift: async (
|
|
72
|
-
incomingPrincipalId: string,
|
|
73
|
-
_sourceChannel: string,
|
|
74
|
-
) => {
|
|
75
|
-
reResolveCalls.push(incomingPrincipalId);
|
|
76
|
-
return mockReResolve;
|
|
77
|
-
},
|
|
78
|
-
}));
|
|
79
|
-
|
|
80
65
|
mock.module("../memory/canonical-guardian-store.js", () => ({
|
|
81
66
|
createCanonicalGuardianRequest: () => ({
|
|
82
67
|
id: "canonical-id",
|
|
@@ -109,8 +94,6 @@ mock.module("../runtime/confirmation-request-guardian-bridge.js", () => ({
|
|
|
109
94
|
}));
|
|
110
95
|
|
|
111
96
|
mock.module("../memory/conversation-crud.js", () => ({
|
|
112
|
-
setConversationProcessingStartedAt: () => {},
|
|
113
|
-
isConversationProcessing: () => false,
|
|
114
97
|
addMessage: (
|
|
115
98
|
conversationId: string,
|
|
116
99
|
role: string,
|
|
@@ -121,70 +104,17 @@ mock.module("../memory/conversation-crud.js", () => ({
|
|
|
121
104
|
}));
|
|
122
105
|
|
|
123
106
|
mock.module("../runtime/local-actor-identity.js", () => ({
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
}));
|
|
129
|
-
|
|
130
|
-
// Capture the sourceActorPrincipalId that handleSendMessage threads into
|
|
131
|
-
// shouldAttachHostProxyForCapability / preactivateHostProxySkills, so tests
|
|
132
|
-
// can assert the dev-bypass translation landed before the CU proxy gate.
|
|
133
|
-
// The macOS "native_support" path short-circuits before reading the
|
|
134
|
-
// principal, so only web/ios turns exercise the same-actor branch.
|
|
135
|
-
const hostProxyAttachCalls: Array<{
|
|
136
|
-
capability: string;
|
|
137
|
-
sourceInterface: unknown;
|
|
138
|
-
sourceActorPrincipalId: string | undefined;
|
|
139
|
-
}> = [];
|
|
140
|
-
const preactivateCalls: Array<{
|
|
141
|
-
sourceInterface: unknown;
|
|
142
|
-
sourceActorPrincipalId: string | undefined;
|
|
143
|
-
}> = [];
|
|
144
|
-
mock.module("../daemon/host-proxy-preactivation.js", () => ({
|
|
145
|
-
shouldAttachHostProxyForCapability: (
|
|
146
|
-
capability: string,
|
|
147
|
-
sourceInterface: unknown,
|
|
148
|
-
sourceActorPrincipalId: string | undefined,
|
|
149
|
-
) => {
|
|
150
|
-
hostProxyAttachCalls.push({
|
|
151
|
-
capability,
|
|
152
|
-
sourceInterface,
|
|
153
|
-
sourceActorPrincipalId,
|
|
154
|
-
});
|
|
155
|
-
// Return false so the route skips proxy instantiation; we only care
|
|
156
|
-
// that the translated principal reached the gate.
|
|
157
|
-
return false;
|
|
158
|
-
},
|
|
159
|
-
preactivateHostProxySkills: (
|
|
160
|
-
_conversation: unknown,
|
|
161
|
-
sourceInterface: unknown,
|
|
162
|
-
sourceActorPrincipalId: string | undefined,
|
|
163
|
-
) => {
|
|
164
|
-
preactivateCalls.push({ sourceInterface, sourceActorPrincipalId });
|
|
165
|
-
},
|
|
166
|
-
}));
|
|
167
|
-
|
|
168
|
-
let mockGuardians: Array<Record<string, unknown>> | null = [
|
|
169
|
-
{
|
|
170
|
-
channelType: "vellum",
|
|
171
|
-
contactId: "guardian-contact",
|
|
172
|
-
principalId: "test-user",
|
|
173
|
-
address: "test-user",
|
|
174
|
-
status: "active",
|
|
175
|
-
},
|
|
176
|
-
];
|
|
177
|
-
|
|
178
|
-
mock.module("../contacts/guardian-delivery-reader.js", () => ({
|
|
179
|
-
getGuardianDelivery: async () => mockGuardians,
|
|
180
|
-
guardianForChannel: (
|
|
181
|
-
list: Array<Record<string, unknown>>,
|
|
182
|
-
channelType: string,
|
|
183
|
-
) => list.find((g) => g.channelType === channelType && g.status === "active"),
|
|
107
|
+
resolveLocalTrustContext: () => ({
|
|
108
|
+
trustClass: "guardian",
|
|
109
|
+
sourceChannel: "vellum",
|
|
110
|
+
}),
|
|
184
111
|
}));
|
|
185
112
|
|
|
186
|
-
// handleSendMessage wraps the first-pass resolve with withSourceChannel.
|
|
187
113
|
mock.module("../runtime/trust-context-resolver.js", () => ({
|
|
114
|
+
resolveTrustContext: () => ({
|
|
115
|
+
trustClass: "guardian",
|
|
116
|
+
sourceChannel: "vellum",
|
|
117
|
+
}),
|
|
188
118
|
withSourceChannel: (sourceChannel: unknown, ctx: unknown) => ({
|
|
189
119
|
...(ctx as Record<string, unknown>),
|
|
190
120
|
sourceChannel,
|
|
@@ -524,215 +454,3 @@ describe("HTTP POST /v1/messages clientTimezone transport metadata", () => {
|
|
|
524
454
|
expect(runAgentLoop).toHaveBeenCalledTimes(1);
|
|
525
455
|
});
|
|
526
456
|
});
|
|
527
|
-
|
|
528
|
-
// ============================================================================
|
|
529
|
-
// TRUST CONTEXT — derived from the gateway guardian binding
|
|
530
|
-
// ============================================================================
|
|
531
|
-
describe("HTTP POST /v1/messages trust context from the gateway binding", () => {
|
|
532
|
-
beforeEach(() => {
|
|
533
|
-
mockGuardians = [
|
|
534
|
-
{
|
|
535
|
-
channelType: "vellum",
|
|
536
|
-
contactId: "guardian-contact",
|
|
537
|
-
principalId: "test-user",
|
|
538
|
-
address: "test-user",
|
|
539
|
-
status: "active",
|
|
540
|
-
},
|
|
541
|
-
];
|
|
542
|
-
reResolveCalls.length = 0;
|
|
543
|
-
mockReResolve = null;
|
|
544
|
-
});
|
|
545
|
-
|
|
546
|
-
function requestAs(principalId: string, sourceChannel = "vellum") {
|
|
547
|
-
return new Request("http://localhost/v1/messages", {
|
|
548
|
-
method: "POST",
|
|
549
|
-
headers: {
|
|
550
|
-
"Content-Type": "application/json",
|
|
551
|
-
"x-vellum-actor-principal-id": principalId,
|
|
552
|
-
"x-vellum-principal-type": "actor",
|
|
553
|
-
},
|
|
554
|
-
body: JSON.stringify({
|
|
555
|
-
conversationKey: "trust-test-key",
|
|
556
|
-
content: "hi",
|
|
557
|
-
sourceChannel,
|
|
558
|
-
interface: "macos",
|
|
559
|
-
}),
|
|
560
|
-
});
|
|
561
|
-
}
|
|
562
|
-
|
|
563
|
-
async function trustContextFor(
|
|
564
|
-
principalId: string,
|
|
565
|
-
sourceChannel = "vellum",
|
|
566
|
-
): Promise<Record<string, unknown>> {
|
|
567
|
-
let captured: Record<string, unknown> | undefined;
|
|
568
|
-
const conversation = makeConversation({
|
|
569
|
-
setTrustContext: (ctx: Record<string, unknown>) => {
|
|
570
|
-
captured = ctx;
|
|
571
|
-
},
|
|
572
|
-
});
|
|
573
|
-
const res = await callHandler(
|
|
574
|
-
(args) =>
|
|
575
|
-
handleSendMessage(args, {
|
|
576
|
-
sendMessageDeps: {
|
|
577
|
-
getOrCreateConversation: async () => conversation,
|
|
578
|
-
assistantEventHub: { publish: async () => {} } as any,
|
|
579
|
-
resolveAttachments: () => [],
|
|
580
|
-
},
|
|
581
|
-
}),
|
|
582
|
-
requestAs(principalId, sourceChannel),
|
|
583
|
-
undefined,
|
|
584
|
-
202,
|
|
585
|
-
);
|
|
586
|
-
expect(res.status).toBe(202);
|
|
587
|
-
return captured ?? {};
|
|
588
|
-
}
|
|
589
|
-
|
|
590
|
-
async function trustClassFor(principalId: string): Promise<string> {
|
|
591
|
-
return (await trustContextFor(principalId)).trustClass as string;
|
|
592
|
-
}
|
|
593
|
-
|
|
594
|
-
test("guardian principal resolves to guardian context, helper not called", async () => {
|
|
595
|
-
expect(await trustClassFor("test-user")).toBe("guardian");
|
|
596
|
-
expect(reResolveCalls).toEqual([]);
|
|
597
|
-
});
|
|
598
|
-
|
|
599
|
-
test("non-guardian principal: helper consulted, null result stays unknown", async () => {
|
|
600
|
-
mockReResolve = null;
|
|
601
|
-
expect(await trustClassFor("vellum-principal-stranger")).toBe("unknown");
|
|
602
|
-
expect(reResolveCalls).toEqual(["vellum-principal-stranger"]);
|
|
603
|
-
});
|
|
604
|
-
|
|
605
|
-
test("reset drift: helper returns guardian → route adopts it", async () => {
|
|
606
|
-
mockGuardians = [
|
|
607
|
-
{
|
|
608
|
-
channelType: "vellum",
|
|
609
|
-
contactId: "guardian-contact",
|
|
610
|
-
principalId: "vellum-principal-stale",
|
|
611
|
-
address: "vellum-principal-stale",
|
|
612
|
-
status: "active",
|
|
613
|
-
},
|
|
614
|
-
];
|
|
615
|
-
mockReResolve = { trustClass: "guardian", sourceChannel: "vellum" };
|
|
616
|
-
|
|
617
|
-
expect(await trustClassFor("vellum-principal-healed")).toBe("guardian");
|
|
618
|
-
expect(reResolveCalls).toEqual(["vellum-principal-healed"]);
|
|
619
|
-
});
|
|
620
|
-
|
|
621
|
-
test("helper returns an unknown-class ctx → trust stays unknown (not adopted)", async () => {
|
|
622
|
-
mockGuardians = [
|
|
623
|
-
{
|
|
624
|
-
channelType: "vellum",
|
|
625
|
-
contactId: "guardian-contact",
|
|
626
|
-
principalId: "vellum-principal-stale",
|
|
627
|
-
address: "vellum-principal-stale",
|
|
628
|
-
status: "active",
|
|
629
|
-
},
|
|
630
|
-
];
|
|
631
|
-
mockReResolve = { trustClass: "unknown", sourceChannel: "vellum" };
|
|
632
|
-
|
|
633
|
-
expect(await trustClassFor("vellum-principal-healed")).toBe("unknown");
|
|
634
|
-
});
|
|
635
|
-
|
|
636
|
-
test("dev-bypass maps the gateway guardian principal to guardian", async () => {
|
|
637
|
-
expect(await trustClassFor("dev-bypass")).toBe("guardian");
|
|
638
|
-
});
|
|
639
|
-
|
|
640
|
-
test("dev-bypass fails closed to unknown on an empty gateway", async () => {
|
|
641
|
-
// No active gateway binding: dev-bypass cannot translate to a real guardian,
|
|
642
|
-
// and the helper (null) leaves trust unknown — parity with /v1/surface-actions.
|
|
643
|
-
mockGuardians = [];
|
|
644
|
-
mockReResolve = null;
|
|
645
|
-
expect(await trustClassFor("dev-bypass")).toBe("unknown");
|
|
646
|
-
});
|
|
647
|
-
|
|
648
|
-
test("preserves the request body channel on the guardian-match happy path", async () => {
|
|
649
|
-
const ctx = await trustContextFor("test-user", "telegram");
|
|
650
|
-
expect(ctx.trustClass).toBe("guardian");
|
|
651
|
-
expect(ctx.sourceChannel).toBe("telegram");
|
|
652
|
-
});
|
|
653
|
-
|
|
654
|
-
// A web turn's "dev-bypass" principal must translate to the real guardian
|
|
655
|
-
// principal before the CU/app-control same-actor proxy-attachment gate,
|
|
656
|
-
// so it matches the macOS client's SSE-registered principal.
|
|
657
|
-
test("dev-bypass is translated to the guardian principal before the CU proxy attach gate (web turn)", async () => {
|
|
658
|
-
hostProxyAttachCalls.length = 0;
|
|
659
|
-
preactivateCalls.length = 0;
|
|
660
|
-
const conversation = makeConversation();
|
|
661
|
-
const res = await callHandler(
|
|
662
|
-
(args) =>
|
|
663
|
-
handleSendMessage(args, {
|
|
664
|
-
sendMessageDeps: {
|
|
665
|
-
getOrCreateConversation: async () => conversation,
|
|
666
|
-
assistantEventHub: { publish: async () => {} } as any,
|
|
667
|
-
resolveAttachments: () => [],
|
|
668
|
-
},
|
|
669
|
-
}),
|
|
670
|
-
new Request("http://localhost/v1/messages", {
|
|
671
|
-
method: "POST",
|
|
672
|
-
headers: {
|
|
673
|
-
"Content-Type": "application/json",
|
|
674
|
-
"x-vellum-actor-principal-id": "dev-bypass",
|
|
675
|
-
"x-vellum-principal-type": "actor",
|
|
676
|
-
},
|
|
677
|
-
body: JSON.stringify({
|
|
678
|
-
conversationKey: "cu-attach-key",
|
|
679
|
-
content: "hi",
|
|
680
|
-
sourceChannel: "vellum",
|
|
681
|
-
interface: "web",
|
|
682
|
-
}),
|
|
683
|
-
}),
|
|
684
|
-
undefined,
|
|
685
|
-
202,
|
|
686
|
-
);
|
|
687
|
-
expect(res.status).toBe(202);
|
|
688
|
-
|
|
689
|
-
// The CU attach gate receives the translated guardian principal, not
|
|
690
|
-
// the raw "dev-bypass" string.
|
|
691
|
-
const cuCall = hostProxyAttachCalls.find(
|
|
692
|
-
(c) => c.capability === "host_cu",
|
|
693
|
-
);
|
|
694
|
-
expect(cuCall).toBeDefined();
|
|
695
|
-
expect(cuCall?.sourceActorPrincipalId).toBe("test-user");
|
|
696
|
-
expect(cuCall?.sourceActorPrincipalId).not.toBe("dev-bypass");
|
|
697
|
-
|
|
698
|
-
// Preactivation receives the same translated principal.
|
|
699
|
-
const preactivateCall = preactivateCalls[0];
|
|
700
|
-
expect(preactivateCall?.sourceActorPrincipalId).toBe("test-user");
|
|
701
|
-
});
|
|
702
|
-
|
|
703
|
-
test("real (non-dev-bypass) principal passes through the CU proxy attach gate unchanged", async () => {
|
|
704
|
-
hostProxyAttachCalls.length = 0;
|
|
705
|
-
const conversation = makeConversation();
|
|
706
|
-
await callHandler(
|
|
707
|
-
(args) =>
|
|
708
|
-
handleSendMessage(args, {
|
|
709
|
-
sendMessageDeps: {
|
|
710
|
-
getOrCreateConversation: async () => conversation,
|
|
711
|
-
assistantEventHub: { publish: async () => {} } as any,
|
|
712
|
-
resolveAttachments: () => [],
|
|
713
|
-
},
|
|
714
|
-
}),
|
|
715
|
-
new Request("http://localhost/v1/messages", {
|
|
716
|
-
method: "POST",
|
|
717
|
-
headers: {
|
|
718
|
-
"Content-Type": "application/json",
|
|
719
|
-
"x-vellum-actor-principal-id": "real-jwt-principal",
|
|
720
|
-
"x-vellum-principal-type": "actor",
|
|
721
|
-
},
|
|
722
|
-
body: JSON.stringify({
|
|
723
|
-
conversationKey: "cu-attach-real-key",
|
|
724
|
-
content: "hi",
|
|
725
|
-
sourceChannel: "vellum",
|
|
726
|
-
interface: "web",
|
|
727
|
-
}),
|
|
728
|
-
}),
|
|
729
|
-
undefined,
|
|
730
|
-
202,
|
|
731
|
-
);
|
|
732
|
-
|
|
733
|
-
const cuCall = hostProxyAttachCalls.find(
|
|
734
|
-
(c) => c.capability === "host_cu",
|
|
735
|
-
);
|
|
736
|
-
expect(cuCall?.sourceActorPrincipalId).toBe("real-jwt-principal");
|
|
737
|
-
});
|
|
738
|
-
});
|
|
@@ -64,28 +64,6 @@ mock.module("../runtime/approval-message-composer.js", () => ({
|
|
|
64
64
|
composeApprovalMessageGenerative: async () => "mock generative message",
|
|
65
65
|
}));
|
|
66
66
|
|
|
67
|
-
// Stub the gateway IPC so redemption claims + activation relays resolve
|
|
68
|
-
// deterministically without a running gateway socket.
|
|
69
|
-
const gatewayIpcCalls: Array<{
|
|
70
|
-
method: string;
|
|
71
|
-
params?: Record<string, unknown>;
|
|
72
|
-
}> = [];
|
|
73
|
-
mock.module("../ipc/gateway-client.js", () => ({
|
|
74
|
-
ipcCallPersistent: async (
|
|
75
|
-
method: string,
|
|
76
|
-
params?: Record<string, unknown>,
|
|
77
|
-
) => {
|
|
78
|
-
gatewayIpcCalls.push({ method, params });
|
|
79
|
-
if (method === "record_invite_redemption") {
|
|
80
|
-
return { ok: true, updated: true, mirrored: true };
|
|
81
|
-
}
|
|
82
|
-
if (method === "upsert_verified_channel") {
|
|
83
|
-
return { ok: true, verified: true };
|
|
84
|
-
}
|
|
85
|
-
return undefined;
|
|
86
|
-
},
|
|
87
|
-
}));
|
|
88
|
-
|
|
89
67
|
import {
|
|
90
68
|
findContactChannel,
|
|
91
69
|
upsertContact,
|
|
@@ -120,7 +98,6 @@ function resetState(): void {
|
|
|
120
98
|
db.run("DELETE FROM contacts");
|
|
121
99
|
emitSignalCalls.length = 0;
|
|
122
100
|
deliverReplyCalls.length = 0;
|
|
123
|
-
gatewayIpcCalls.length = 0;
|
|
124
101
|
msgCounter = 0;
|
|
125
102
|
}
|
|
126
103
|
|
|
@@ -200,11 +177,6 @@ describe("inbound invite redemption intercept", () => {
|
|
|
200
177
|
expect(result).not.toBeNull();
|
|
201
178
|
expect(result!.channel.status).toBe("active");
|
|
202
179
|
|
|
203
|
-
// The activation is written to the gateway via upsert_verified_channel.
|
|
204
|
-
expect(
|
|
205
|
-
gatewayIpcCalls.some((c) => c.method === "upsert_verified_channel"),
|
|
206
|
-
).toBe(true);
|
|
207
|
-
|
|
208
180
|
// Verify a welcome reply was delivered
|
|
209
181
|
expect(deliverReplyCalls.length).toBe(1);
|
|
210
182
|
const replyText = (deliverReplyCalls[0].payload as Record<string, unknown>)
|
|
@@ -35,8 +35,6 @@ const addMessageCalls: Array<{
|
|
|
35
35
|
}> = [];
|
|
36
36
|
|
|
37
37
|
mock.module("../memory/conversation-crud.js", () => ({
|
|
38
|
-
setConversationProcessingStartedAt: () => {},
|
|
39
|
-
isConversationProcessing: () => false,
|
|
40
38
|
addMessage: async (
|
|
41
39
|
conversationId: string,
|
|
42
40
|
role: string,
|
|
@@ -7,26 +7,6 @@ mock.module("../util/logger.js", () => ({
|
|
|
7
7
|
}),
|
|
8
8
|
}));
|
|
9
9
|
|
|
10
|
-
// Wrap the real contacts-write so a test can force the best-effort local mirror
|
|
11
|
-
// to fail (simulating a gateway-verified activation whose local DB row failed),
|
|
12
|
-
// while normal setup keeps the real implementation. Capture the concrete real
|
|
13
|
-
// function BEFORE registering the mock so the wrapper never recurses into
|
|
14
|
-
// itself via the (now live) module namespace.
|
|
15
|
-
const contactsWriteState = { mirrorThrows: false };
|
|
16
|
-
const realContactsWrite = await import("../contacts/contacts-write.js");
|
|
17
|
-
const realUpsertContactChannel = realContactsWrite.upsertContactChannel;
|
|
18
|
-
mock.module("../contacts/contacts-write.js", () => ({
|
|
19
|
-
...realContactsWrite,
|
|
20
|
-
upsertContactChannel: (
|
|
21
|
-
params: Parameters<typeof realUpsertContactChannel>[0],
|
|
22
|
-
) => {
|
|
23
|
-
if (contactsWriteState.mirrorThrows) {
|
|
24
|
-
throw new Error("local mirror exploded");
|
|
25
|
-
}
|
|
26
|
-
return realUpsertContactChannel(params);
|
|
27
|
-
},
|
|
28
|
-
}));
|
|
29
|
-
|
|
30
10
|
// Mock the gateway IPC bridge used by the redemption service for the
|
|
31
11
|
// authoritative pre-mutation claim (record_invite_redemption). Tests drive the
|
|
32
12
|
// claim result via `gatewayIpc`.
|
|
@@ -37,12 +17,6 @@ const gatewayIpc = {
|
|
|
37
17
|
mirrored: boolean;
|
|
38
18
|
},
|
|
39
19
|
claimThrows: false,
|
|
40
|
-
// Drives the upsert_verified_channel relay verdict. When false the gateway
|
|
41
|
-
// refuses the actor (blocked/revoked) and the activation is refused.
|
|
42
|
-
activationVerified: true,
|
|
43
|
-
// Gateway channel returned on a verified activation, surfaced as the memberId
|
|
44
|
-
// when the local mirror produces no row.
|
|
45
|
-
activationChannelId: "gw-channel-id" as string | undefined,
|
|
46
20
|
calls: [] as { method: string; params?: Record<string, unknown> }[],
|
|
47
21
|
};
|
|
48
22
|
|
|
@@ -54,49 +28,18 @@ mock.module("../ipc/gateway-client.js", () => ({
|
|
|
54
28
|
gatewayIpc.calls.push({ method, params });
|
|
55
29
|
if (method === "record_invite_redemption") {
|
|
56
30
|
if (gatewayIpc.claimThrows) throw new Error("gateway unreachable");
|
|
57
|
-
onGatewayClaim?.();
|
|
58
31
|
return gatewayIpc.claim;
|
|
59
32
|
}
|
|
60
|
-
if (method === "upsert_verified_channel") {
|
|
61
|
-
if (!gatewayIpc.activationVerified) {
|
|
62
|
-
return { ok: true, verified: false };
|
|
63
|
-
}
|
|
64
|
-
return {
|
|
65
|
-
ok: true,
|
|
66
|
-
verified: true,
|
|
67
|
-
channel: gatewayIpc.activationChannelId
|
|
68
|
-
? {
|
|
69
|
-
id: gatewayIpc.activationChannelId,
|
|
70
|
-
contactId: (params?.contactId as string) ?? "gw-contact",
|
|
71
|
-
type: (params?.type as string) ?? "telegram",
|
|
72
|
-
address: (params?.address as string) ?? "gw-addr",
|
|
73
|
-
status: "active",
|
|
74
|
-
verifiedAt: 1,
|
|
75
|
-
verifiedVia: (params?.verifiedVia as string) ?? "invite",
|
|
76
|
-
}
|
|
77
|
-
: undefined,
|
|
78
|
-
};
|
|
79
|
-
}
|
|
80
33
|
return undefined;
|
|
81
34
|
},
|
|
82
35
|
}));
|
|
83
36
|
|
|
84
|
-
// Lets a test inject a side-effect into the gateway claim — runs after the
|
|
85
|
-
// service's pre-validation but before the assistant use-bump, so it can race a
|
|
86
|
-
// revoke into the window that makes `recordInviteUse` return false.
|
|
87
|
-
let onGatewayClaim: (() => void) | null = null;
|
|
88
|
-
|
|
89
37
|
function resetGatewayIpc() {
|
|
90
38
|
gatewayIpc.claim = { ok: true, updated: true, mirrored: true };
|
|
91
39
|
gatewayIpc.claimThrows = false;
|
|
92
|
-
gatewayIpc.activationVerified = true;
|
|
93
|
-
gatewayIpc.activationChannelId = "gw-channel-id";
|
|
94
40
|
gatewayIpc.calls = [];
|
|
95
|
-
onGatewayClaim = null;
|
|
96
41
|
}
|
|
97
42
|
|
|
98
|
-
import type { TrustVerdict } from "@vellumai/gateway-client";
|
|
99
|
-
|
|
100
43
|
import {
|
|
101
44
|
findContactChannel,
|
|
102
45
|
getContact,
|
|
@@ -113,7 +56,6 @@ import {
|
|
|
113
56
|
type InviteRedemptionOutcome,
|
|
114
57
|
redeemInvite,
|
|
115
58
|
redeemInviteByCode,
|
|
116
|
-
resolveMemberGateStatus,
|
|
117
59
|
} from "../runtime/invite-redemption-service.js";
|
|
118
60
|
import { hashVoiceCode } from "../util/voice-code.js";
|
|
119
61
|
|
|
@@ -134,7 +76,6 @@ describe("invite-redemption-service", () => {
|
|
|
134
76
|
beforeEach(() => {
|
|
135
77
|
resetTables();
|
|
136
78
|
resetGatewayIpc();
|
|
137
|
-
contactsWriteState.mirrorThrows = false;
|
|
138
79
|
});
|
|
139
80
|
|
|
140
81
|
test("redeems a valid invite and returns typed outcome", async () => {
|
|
@@ -158,11 +99,6 @@ describe("invite-redemption-service", () => {
|
|
|
158
99
|
memberId: expect.any(String),
|
|
159
100
|
inviteId: invite.id,
|
|
160
101
|
});
|
|
161
|
-
|
|
162
|
-
// The activation is written to the gateway via upsert_verified_channel.
|
|
163
|
-
expect(
|
|
164
|
-
gatewayIpc.calls.some((c) => c.method === "upsert_verified_channel"),
|
|
165
|
-
).toBe(true);
|
|
166
102
|
});
|
|
167
103
|
|
|
168
104
|
test("marks channel as verified via invite on redemption", async () => {
|
|
@@ -421,18 +357,6 @@ describe("invite-redemption-service", () => {
|
|
|
421
357
|
expect(outcome.ok).toBe(true);
|
|
422
358
|
expect((outcome as { type: string }).type).toBe("redeemed");
|
|
423
359
|
|
|
424
|
-
// Gateway-first: the activation relays the target contactId so the gateway
|
|
425
|
-
// binds the channel to Mom (not the guardian) — the binding is not lost.
|
|
426
|
-
const upsert = gatewayIpc.calls.find(
|
|
427
|
-
(c) => c.method === "upsert_verified_channel",
|
|
428
|
-
);
|
|
429
|
-
expect(upsert).toBeDefined();
|
|
430
|
-
expect(upsert!.params).toMatchObject({
|
|
431
|
-
type: "telegram",
|
|
432
|
-
address: "guardian-tg-id",
|
|
433
|
-
contactId: momContact.id,
|
|
434
|
-
});
|
|
435
|
-
|
|
436
360
|
// Verify the redeemer's Telegram ID is now bound to Mom's contact
|
|
437
361
|
const result = findContactChannel({
|
|
438
362
|
channelType: "telegram",
|
|
@@ -704,39 +628,6 @@ describe("invite-redemption-service", () => {
|
|
|
704
628
|
).toBeNull();
|
|
705
629
|
});
|
|
706
630
|
|
|
707
|
-
test("does not activate the member when recordInviteUse loses the race (returns false)", async () => {
|
|
708
|
-
const targetContactId = createTargetContact();
|
|
709
|
-
const { rawToken, invite } = createInvite({
|
|
710
|
-
sourceChannel: "telegram",
|
|
711
|
-
contactId: targetContactId,
|
|
712
|
-
maxUses: 1,
|
|
713
|
-
});
|
|
714
|
-
|
|
715
|
-
// Legacy gateway row so the claim proceeds past the gateway gate. Revoke
|
|
716
|
-
// the assistant invite during the claim — after pre-validation, before the
|
|
717
|
-
// use-bump — so `recordInviteUse` sees a non-active row and returns false.
|
|
718
|
-
gatewayIpc.claim = { ok: true, updated: false, mirrored: false };
|
|
719
|
-
onGatewayClaim = () => {
|
|
720
|
-
revokeStoreFn(invite.id);
|
|
721
|
-
};
|
|
722
|
-
|
|
723
|
-
const outcome = await redeemInvite({
|
|
724
|
-
rawToken,
|
|
725
|
-
sourceChannel: "telegram",
|
|
726
|
-
externalUserId: "raced-user",
|
|
727
|
-
});
|
|
728
|
-
|
|
729
|
-
expect(outcome).toEqual({ ok: false, reason: "invalid_token" });
|
|
730
|
-
|
|
731
|
-
// The member was NOT activated: no gateway upsert and no active channel.
|
|
732
|
-
expect(
|
|
733
|
-
gatewayIpc.calls.some((c) => c.method === "upsert_verified_channel"),
|
|
734
|
-
).toBe(false);
|
|
735
|
-
expect(
|
|
736
|
-
findContactChannel({ channelType: "telegram", address: "raced-user" }),
|
|
737
|
-
).toBeNull();
|
|
738
|
-
});
|
|
739
|
-
|
|
740
631
|
test("proceeds and mutates when the gateway claim is consumed (updated:true)", async () => {
|
|
741
632
|
const targetContactId = createTargetContact();
|
|
742
633
|
const { rawToken, invite } = createInvite({
|
|
@@ -871,93 +762,4 @@ describe("invite-redemption-service", () => {
|
|
|
871
762
|
}),
|
|
872
763
|
).toBeNull();
|
|
873
764
|
});
|
|
874
|
-
|
|
875
|
-
test("returns invalid_token (no throw) when the gateway refuses the activation", async () => {
|
|
876
|
-
const targetContactId = createTargetContact();
|
|
877
|
-
const { rawToken } = createInvite({
|
|
878
|
-
sourceChannel: "telegram",
|
|
879
|
-
contactId: targetContactId,
|
|
880
|
-
maxUses: 1,
|
|
881
|
-
});
|
|
882
|
-
|
|
883
|
-
// Gateway claim consumes the row, then refuses the channel activation
|
|
884
|
-
// (blocked/revoked actor). The committed use is acceptable for this rare
|
|
885
|
-
// blocked-backstop path; the outcome must be the branch failure, not a 500.
|
|
886
|
-
gatewayIpc.activationVerified = false;
|
|
887
|
-
|
|
888
|
-
const outcome = await redeemInvite({
|
|
889
|
-
rawToken,
|
|
890
|
-
sourceChannel: "telegram",
|
|
891
|
-
externalUserId: "refused-user",
|
|
892
|
-
});
|
|
893
|
-
|
|
894
|
-
expect(outcome).toEqual({ ok: false, reason: "invalid_token" });
|
|
895
|
-
});
|
|
896
|
-
|
|
897
|
-
test("redeems with the gateway channel id when the gateway verifies but the local mirror fails", async () => {
|
|
898
|
-
const targetContactId = createTargetContact();
|
|
899
|
-
const { rawToken, invite } = createInvite({
|
|
900
|
-
sourceChannel: "telegram",
|
|
901
|
-
contactId: targetContactId,
|
|
902
|
-
maxUses: 1,
|
|
903
|
-
});
|
|
904
|
-
|
|
905
|
-
// Gateway verifies and returns its channel; the best-effort local mirror
|
|
906
|
-
// throws. The activation must still stand using the gateway channel id.
|
|
907
|
-
gatewayIpc.activationChannelId = "gw-verified-channel";
|
|
908
|
-
contactsWriteState.mirrorThrows = true;
|
|
909
|
-
|
|
910
|
-
const outcome = await redeemInvite({
|
|
911
|
-
rawToken,
|
|
912
|
-
sourceChannel: "telegram",
|
|
913
|
-
externalUserId: "mirrorless-user",
|
|
914
|
-
});
|
|
915
|
-
|
|
916
|
-
expect(outcome).toEqual({
|
|
917
|
-
ok: true,
|
|
918
|
-
type: "redeemed",
|
|
919
|
-
memberId: "gw-verified-channel",
|
|
920
|
-
inviteId: invite.id,
|
|
921
|
-
});
|
|
922
|
-
});
|
|
923
|
-
});
|
|
924
|
-
|
|
925
|
-
describe("resolveMemberGateStatus", () => {
|
|
926
|
-
const memberlessVerdict: TrustVerdict = {
|
|
927
|
-
trustClass: "unverified_contact",
|
|
928
|
-
canonicalSenderId: "telegram:blocked-user",
|
|
929
|
-
};
|
|
930
|
-
const memberVerdict: TrustVerdict = {
|
|
931
|
-
trustClass: "trusted_contact",
|
|
932
|
-
canonicalSenderId: "telegram:active-user",
|
|
933
|
-
contactId: "contact-1",
|
|
934
|
-
channelId: "channel-1",
|
|
935
|
-
type: "telegram",
|
|
936
|
-
address: "active-user",
|
|
937
|
-
status: "active",
|
|
938
|
-
policy: "allow",
|
|
939
|
-
};
|
|
940
|
-
|
|
941
|
-
test("uses the verdict member status when the verdict resolves a member", async () => {
|
|
942
|
-
expect(await resolveMemberGateStatus(memberVerdict, "blocked")).toBe(
|
|
943
|
-
"active",
|
|
944
|
-
);
|
|
945
|
-
});
|
|
946
|
-
|
|
947
|
-
test("falls back to local status when a non-null verdict carries no member", async () => {
|
|
948
|
-
// A previously blocked contact with a valid invite must stay blocked even
|
|
949
|
-
// when the verdict is non-null but memberless (externalChatId-only match /
|
|
950
|
-
// resolutionFailed), so it can't bypass the gate.
|
|
951
|
-
expect(await resolveMemberGateStatus(memberlessVerdict, "blocked")).toBe(
|
|
952
|
-
"blocked",
|
|
953
|
-
);
|
|
954
|
-
});
|
|
955
|
-
|
|
956
|
-
test("falls back to local status when the verdict is null", async () => {
|
|
957
|
-
expect(await resolveMemberGateStatus(null, "blocked")).toBe("blocked");
|
|
958
|
-
});
|
|
959
|
-
|
|
960
|
-
test("returns null when neither verdict member nor local status is present", async () => {
|
|
961
|
-
expect(await resolveMemberGateStatus(memberlessVerdict, null)).toBeNull();
|
|
962
|
-
});
|
|
963
765
|
});
|