@vellumai/assistant 0.6.4 → 0.6.5
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/.prettierignore +5 -0
- package/ARCHITECTURE.md +32 -36
- package/Dockerfile +12 -0
- package/README.md +3 -4
- package/bun.lock +8 -3
- package/docs/architecture/integrations.md +1 -20
- package/docs/architecture/security.md +16 -16
- package/docs/error-handling.md +111 -0
- package/docs/skills.md +10 -10
- package/docs/stt-provider-onboarding.md +2 -1
- package/knip.json +9 -2
- package/node_modules/@vellumai/ces-contracts/package.json +2 -1
- package/node_modules/@vellumai/ces-contracts/src/__tests__/trust-rules.test.ts +471 -0
- package/node_modules/@vellumai/ces-contracts/src/trust-rules.ts +398 -4
- package/node_modules/@vellumai/credential-storage/bun.lock +2 -2
- package/node_modules/@vellumai/credential-storage/package.json +2 -2
- package/node_modules/@vellumai/credential-storage/src/oauth-runtime.ts +20 -2
- package/node_modules/@vellumai/egress-proxy/bun.lock +2 -2
- package/node_modules/@vellumai/egress-proxy/package.json +2 -2
- package/openapi.yaml +123 -11
- package/package.json +6 -3
- package/scripts/generate-openapi.ts +50 -11
- package/src/__tests__/agent-loop-callsite-precedence.test.ts +318 -0
- package/src/__tests__/agent-loop-sentry-hygiene.test.ts +137 -0
- package/src/__tests__/agent-loop.test.ts +112 -1
- package/src/__tests__/anthropic-error-formatting.test.ts +98 -0
- package/src/__tests__/anthropic-provider.test.ts +171 -2
- package/src/__tests__/approval-cascade.test.ts +31 -10
- package/src/__tests__/approval-routes-http.test.ts +134 -10
- package/src/__tests__/assistant-attachments.test.ts +44 -0
- package/src/__tests__/assistant-feature-flags-integration.test.ts +29 -0
- package/src/__tests__/browser-fill-credential.test.ts +1 -1
- package/src/__tests__/browser-identifier-parity-guard.test.ts +53 -0
- package/src/__tests__/browser-skill-baseline-tool-payload.test.ts +23 -33
- package/src/__tests__/browser-skill-endstate.test.ts +51 -182
- package/src/__tests__/btw-routes.test.ts +47 -1
- package/src/__tests__/call-controller.test.ts +1 -2
- package/src/__tests__/call-site-routing-provider.test.ts +214 -0
- package/src/__tests__/catalog-cache.test.ts +27 -4
- package/src/__tests__/channel-approval-routes.test.ts +4 -4
- package/src/__tests__/channel-reply-delivery.test.ts +300 -2
- package/src/__tests__/checker.test.ts +428 -501
- package/src/__tests__/cli-command-risk-guard.test.ts +30 -33
- package/src/__tests__/compaction-circuit-breaker.test.ts +336 -0
- package/src/__tests__/compaction.benchmark.test.ts +1 -1
- package/src/__tests__/config-analysis.test.ts +11 -28
- package/src/__tests__/config-loader-backfill.test.ts +174 -0
- package/src/__tests__/config-loader-corrupt.test.ts +183 -0
- package/src/__tests__/config-loader-quarantine-bulletin.test.ts +202 -0
- package/src/__tests__/config-schema-cmd.test.ts +11 -5
- package/src/__tests__/config-schema.test.ts +427 -114
- package/src/__tests__/config-watcher.test.ts +2 -2
- package/src/__tests__/contact-store-user-file.test.ts +72 -73
- package/src/__tests__/contacts-write.test.ts +4 -4
- package/src/__tests__/context-token-estimator.test.ts +191 -1
- package/src/__tests__/context-window-manager.test.ts +530 -2
- package/src/__tests__/conversation-abort-tool-results.test.ts +30 -16
- package/src/__tests__/conversation-agent-loop-overflow.test.ts +61 -17
- package/src/__tests__/conversation-agent-loop.test.ts +412 -82
- package/src/__tests__/conversation-attachments.test.ts +1 -1
- package/src/__tests__/conversation-confirmation-signals.test.ts +30 -9
- package/src/__tests__/conversation-error.test.ts +37 -6
- package/src/__tests__/conversation-history-web-search.test.ts +6 -0
- package/src/__tests__/conversation-init.benchmark.test.ts +36 -0
- package/src/__tests__/conversation-lifecycle.test.ts +336 -0
- package/src/__tests__/conversation-load-history-repair.test.ts +27 -10
- package/src/__tests__/conversation-pre-run-repair.test.ts +30 -16
- package/src/__tests__/conversation-process-callsite.test.ts +306 -0
- package/src/__tests__/conversation-provider-retry-repair.test.ts +30 -16
- package/src/__tests__/conversation-queue.test.ts +41 -26
- package/src/__tests__/conversation-routes-disk-view.test.ts +29 -1
- package/src/__tests__/conversation-routes-slash-commands.test.ts +31 -3
- package/src/__tests__/conversation-runtime-assembly.test.ts +2735 -55
- package/src/__tests__/conversation-runtime-workspace.test.ts +12 -12
- package/src/__tests__/conversation-skill-tools.test.ts +12 -146
- package/src/__tests__/conversation-slash-queue.test.ts +34 -19
- package/src/__tests__/conversation-slash-unknown.test.ts +30 -16
- package/src/__tests__/conversation-speed-override.test.ts +30 -11
- package/src/__tests__/conversation-surfaces-standalone-payloads.test.ts +1035 -0
- package/src/__tests__/conversation-surfaces-standalone.test.ts +630 -0
- package/src/__tests__/conversation-title-service.test.ts +2 -2
- package/src/__tests__/conversation-tool-setup-batch-authorized.test.ts +1 -1
- package/src/__tests__/conversation-unread-route.test.ts +2 -2
- package/src/__tests__/conversation-usage.test.ts +3 -1
- package/src/__tests__/conversation-workspace-cache-state.test.ts +31 -10
- package/src/__tests__/conversation-workspace-injection.test.ts +43 -15
- package/src/__tests__/conversation-workspace-tool-tracking.test.ts +44 -16
- package/src/__tests__/credential-broker-browser-fill.test.ts +110 -0
- package/src/__tests__/credential-security-invariants.test.ts +3 -0
- package/src/__tests__/credential-storage-oauth-compat.test.ts +18 -0
- package/src/__tests__/credential-storage-static-compat.test.ts +28 -0
- package/src/__tests__/credential-vault-unit.test.ts +135 -19
- package/src/__tests__/credentials-cli.test.ts +1 -9
- package/src/__tests__/cross-provider-web-search.test.ts +84 -0
- package/src/__tests__/daemon-server-persist-and-process-callsite.test.ts +92 -0
- package/src/__tests__/delete-propagation.test.ts +437 -0
- package/src/__tests__/dm-backfill.test.ts +417 -0
- package/src/__tests__/dm-persistence.test.ts +227 -0
- package/src/__tests__/edit-propagation.test.ts +280 -0
- package/src/__tests__/ephemeral-permissions.test.ts +93 -3
- package/src/__tests__/estimator-calibration-integration.test.ts +208 -0
- package/src/__tests__/estimator-calibration.test.ts +213 -0
- package/src/__tests__/extension-id-sync-guard.test.ts +26 -7
- package/src/__tests__/file-write-tool.test.ts +151 -1
- package/src/__tests__/filing-service.test.ts +255 -0
- package/src/__tests__/gemini-provider.test.ts +0 -3
- package/src/__tests__/guardian-grant-minting.test.ts +8 -0
- package/src/__tests__/headless-browser-interactions.test.ts +1 -1
- package/src/__tests__/heartbeat-service.test.ts +96 -15
- package/src/__tests__/host-shell-tool.test.ts +124 -18
- package/src/__tests__/http-user-message-parity.test.ts +29 -1
- package/src/__tests__/inbound-slack-persistence.test.ts +340 -0
- package/src/__tests__/intent-routing.test.ts +1 -40
- package/src/__tests__/llm-catalog-parity.test.ts +174 -0
- package/src/__tests__/llm-context-normalization.test.ts +121 -0
- package/src/__tests__/llm-resolver.test.ts +214 -0
- package/src/__tests__/llm-schema.test.ts +223 -0
- package/src/__tests__/managed-proxy-context.test.ts +6 -2
- package/src/__tests__/messaging-skill-split.test.ts +3 -34
- package/src/__tests__/migration-import-from-url.test.ts +684 -0
- package/src/__tests__/model-intents.test.ts +9 -83
- package/src/__tests__/notification-decision-fallback.test.ts +0 -10
- package/src/__tests__/notification-decision-identity.test.ts +0 -9
- package/src/__tests__/notification-decision-recipient-context.test.ts +0 -9
- package/src/__tests__/oauth-store.test.ts +10 -7
- package/src/__tests__/oauth2-gateway-transport.test.ts +8 -3
- package/src/__tests__/oauth2-refresh-retry.test.ts +279 -0
- package/src/__tests__/openai-provider.test.ts +7 -0
- package/src/__tests__/openai-responses-provider.test.ts +396 -0
- package/src/__tests__/openrouter-provider-only.test.ts +135 -0
- package/src/__tests__/outbound-slack-persistence.test.ts +293 -0
- package/src/__tests__/permission-checker-host-gate.test.ts +1 -1
- package/src/__tests__/permission-mode.test.ts +16 -0
- package/src/__tests__/permission-types.test.ts +0 -1
- package/src/__tests__/persona-resolver.test.ts +13 -13
- package/src/__tests__/pkb-autoinject.test.ts +37 -1
- package/src/__tests__/platform-bash-auto-approve.test.ts +1 -1
- package/src/__tests__/pricing.test.ts +50 -3
- package/src/__tests__/profiler-routes.test.ts +1 -1
- package/src/__tests__/provider-commit-message-generator.test.ts +14 -84
- package/src/__tests__/provider-env-vars-scope.test.ts +52 -0
- package/src/__tests__/provider-error-scenarios.test.ts +135 -6
- package/src/__tests__/provider-managed-proxy-integration.test.ts +42 -11
- package/src/__tests__/provider-registry-ollama.test.ts +1 -2
- package/src/__tests__/proxy-approval-callback.test.ts +0 -1
- package/src/__tests__/reaction-persistence.test.ts +560 -0
- package/src/__tests__/relay-server.test.ts +1 -1
- package/src/__tests__/require-fresh-approval.test.ts +1 -1
- package/src/__tests__/retry-openrouter-only-normalization.test.ts +136 -0
- package/src/__tests__/retry-thinking-tool-choice.test.ts +226 -0
- package/src/__tests__/risk-classifier-parity.test.ts +230 -0
- package/src/__tests__/sanitize-config-for-transfer.test.ts +78 -1
- package/src/__tests__/secret-ingress-http.test.ts +28 -0
- package/src/__tests__/secret-prompter-channel-fallback.test.ts +125 -0
- package/src/__tests__/secret-routes-managed-proxy.test.ts +2 -3
- package/src/__tests__/secret-scanner-executor.test.ts +1 -1
- package/src/__tests__/send-endpoint-busy.test.ts +29 -1
- package/src/__tests__/server-history-render.test.ts +31 -0
- package/src/__tests__/shell-parser-property.test.ts +13 -13
- package/src/__tests__/skill-cache-store.test.ts +182 -0
- package/src/__tests__/skills.test.ts +19 -33
- package/src/__tests__/slack-app-setup-skill-regression.test.ts +3 -1
- package/src/__tests__/slack-skill.test.ts +3 -8
- package/src/__tests__/starter-bundle.test.ts +35 -0
- package/src/__tests__/subagent-call-site-routing.test.ts +280 -0
- package/src/__tests__/suggestion-routes.test.ts +160 -3
- package/src/__tests__/system-prompt.test.ts +22 -35
- package/src/__tests__/task-runner.test.ts +3 -1
- package/src/__tests__/tcc-sandbox-deny.test.ts +198 -0
- package/src/__tests__/terminal-tools.test.ts +8 -0
- package/src/__tests__/test-support/browser-skill-harness.ts +2 -52
- package/src/__tests__/thread-backfill.test.ts +941 -0
- package/src/__tests__/tool-execution-pipeline.benchmark.test.ts +2 -2
- package/src/__tests__/tool-executor-lifecycle-events.test.ts +2 -2
- package/src/__tests__/tool-executor.test.ts +60 -94
- package/src/__tests__/trust-store.test.ts +442 -109
- package/src/__tests__/update-bulletin-job.test.ts +389 -0
- package/src/__tests__/usage-cache-backfill-migration.test.ts +3 -1
- package/src/__tests__/verification-control-plane-policy.test.ts +1 -22
- package/src/__tests__/voice-session-bridge.test.ts +39 -0
- package/src/__tests__/volume-security-guard.test.ts +3 -2
- package/src/__tests__/web-search-history.test.ts +337 -0
- package/src/__tests__/workspace-migration-039-drop-legacy-llm-keys.test.ts +343 -0
- package/src/__tests__/workspace-migration-043-release-notes-latex-rendering.test.ts +202 -0
- package/src/__tests__/workspace-migration-045-release-notes-meet-avatar.test.ts +210 -0
- package/src/__tests__/workspace-migration-drop-user-md.test.ts +11 -11
- package/src/__tests__/workspace-migration-unify-llm-callsite-configs.test.ts +841 -0
- package/src/__tests__/workspace-policy.test.ts +1 -13
- package/src/acp/client-handler.ts +1 -2
- package/src/agent/loop.ts +209 -17
- package/src/avatar/resvg-lazy.test.ts +136 -0
- package/src/avatar/resvg-lazy.ts +82 -9
- package/src/avatar/traits-png-sync.ts +21 -1
- package/src/browser/__tests__/operations.test.ts +163 -0
- package/src/browser/identifiers.ts +51 -0
- package/src/browser/operations.ts +660 -0
- package/src/browser/types.ts +81 -0
- package/src/calls/guardian-question-copy.ts +2 -2
- package/src/calls/telephony-stt-routing.ts +1 -1
- package/src/calls/voice-session-bridge.ts +1 -0
- package/src/cli/AGENTS.md +1 -1
- package/src/cli/commands/__tests__/attachment.test.ts +438 -0
- package/src/cli/commands/__tests__/browser.test.ts +554 -0
- package/src/cli/commands/__tests__/cache.test.ts +623 -0
- package/src/cli/commands/__tests__/email-list.test.ts +6 -0
- package/src/cli/commands/__tests__/email-send.test.ts +93 -1
- package/src/cli/commands/__tests__/image-generation.test.ts +666 -0
- package/src/cli/commands/__tests__/inference-send.test.ts +451 -0
- package/src/cli/commands/__tests__/stt-transcribe.test.ts +454 -0
- package/src/cli/commands/__tests__/task.test.ts +913 -0
- package/src/cli/commands/__tests__/tts-synthesize.test.ts +594 -0
- package/src/cli/commands/__tests__/ui-confirm.test.ts +650 -0
- package/src/cli/commands/__tests__/ui.test.ts +1215 -0
- package/src/cli/commands/__tests__/watchers.test.ts +716 -0
- package/src/cli/commands/attachment.ts +182 -0
- package/src/cli/commands/browser.ts +350 -0
- package/src/cli/commands/cache.ts +341 -0
- package/src/cli/commands/completions.ts +0 -3
- package/src/cli/commands/config.ts +6 -6
- package/src/cli/commands/conversations-import.ts +347 -0
- package/src/cli/commands/conversations.ts +14 -1
- package/src/cli/commands/email.ts +234 -194
- package/src/cli/commands/image-generation.ts +300 -0
- package/src/cli/commands/inference.ts +200 -0
- package/src/cli/commands/memory.ts +127 -17
- package/src/cli/commands/platform/__tests__/callback-routes-list.test.ts +0 -1
- package/src/cli/commands/platform/__tests__/connect.test.ts +0 -1
- package/src/cli/commands/platform/__tests__/disconnect.test.ts +0 -1
- package/src/cli/commands/platform/__tests__/status.test.ts +0 -1
- package/src/cli/commands/stt.ts +339 -0
- package/src/cli/commands/task.ts +795 -0
- package/src/cli/commands/trust.ts +50 -19
- package/src/cli/commands/tts.ts +273 -0
- package/src/cli/commands/ui.ts +670 -0
- package/src/cli/commands/watchers.ts +509 -0
- package/src/cli/lib/daemon-credential-client.ts +0 -19
- package/src/cli/program.ts +23 -4
- package/src/cli.ts +0 -37
- package/src/config/bundled-skills/conversations/tools/rename-conversation.ts +23 -1
- package/src/config/bundled-skills/media-processing/services/reduce.ts +1 -1
- package/src/config/bundled-skills/messaging/SKILL.md +2 -2
- package/src/config/bundled-skills/messaging/TOOLS.json +4 -0
- package/src/config/bundled-skills/messaging/tools/messaging-archive-by-sender.ts +8 -1
- package/src/config/bundled-skills/messaging/tools/messaging-read.ts +15 -1
- package/src/config/bundled-skills/messaging/tools/messaging-search.ts +21 -1
- package/src/config/bundled-skills/messaging/tools/messaging-send.ts +11 -12
- package/src/config/bundled-skills/phone-calls/references/CONFIG.md +9 -8
- package/src/config/bundled-skills/settings/TOOLS.json +3 -3
- package/src/config/bundled-tool-registry.ts +0 -175
- package/src/config/env.ts +7 -2
- package/src/config/feature-flag-registry.json +25 -9
- package/src/config/llm-resolver.ts +128 -0
- package/src/config/loader.ts +194 -10
- package/src/config/raw-config-utils.ts +30 -2
- package/src/config/sanitize-for-transfer.ts +35 -0
- package/src/config/schema.ts +30 -41
- package/src/config/schemas/analysis.ts +3 -22
- package/src/config/schemas/calls.ts +0 -4
- package/src/config/schemas/filing.ts +2 -7
- package/src/config/schemas/heartbeat.ts +0 -5
- package/src/config/schemas/inference.ts +3 -23
- package/src/config/schemas/llm.ts +318 -0
- package/src/config/schemas/memory-processing.ts +1 -9
- package/src/config/schemas/notifications.ts +4 -11
- package/src/config/schemas/platform.ts +3 -9
- package/src/config/schemas/security.ts +33 -0
- package/src/config/schemas/services.ts +9 -4
- package/src/config/schemas/stt.ts +1 -0
- package/src/config/schemas/tts.ts +53 -0
- package/src/config/schemas/updates.ts +1 -1
- package/src/config/schemas/workspace-git.ts +3 -40
- package/src/config/skills.ts +2 -2
- package/src/context/__tests__/compact-prompt.test.ts +45 -0
- package/src/context/__tests__/microcompact.test.ts +805 -0
- package/src/context/estimator-calibration.ts +136 -0
- package/src/context/microcompact.ts +443 -0
- package/src/context/prompts/compact.md +12 -0
- package/src/context/token-estimator.ts +61 -3
- package/src/context/window-manager.ts +229 -25
- package/src/credential-execution/approval-bridge.ts +0 -1
- package/src/credential-execution/executable-discovery.ts +19 -8
- package/src/credential-execution/process-manager.test.ts +109 -0
- package/src/credential-execution/process-manager.ts +65 -2
- package/src/daemon/approval-generators.ts +29 -4
- package/src/daemon/assistant-attachments.ts +24 -13
- package/src/daemon/classifier.ts +2 -2
- package/src/daemon/config-watcher.ts +0 -1
- package/src/daemon/context-overflow-reducer.ts +4 -1
- package/src/daemon/conversation-agent-loop-handlers.ts +79 -12
- package/src/daemon/conversation-agent-loop.ts +462 -80
- package/src/daemon/conversation-attachments.ts +2 -6
- package/src/daemon/conversation-error.ts +36 -1
- package/src/daemon/conversation-lifecycle.ts +30 -6
- package/src/daemon/conversation-messaging.ts +73 -4
- package/src/daemon/conversation-process.ts +10 -4
- package/src/daemon/conversation-queue-manager.ts +3 -0
- package/src/daemon/conversation-runtime-assembly.ts +760 -29
- package/src/daemon/conversation-slash.ts +2 -2
- package/src/daemon/conversation-surfaces.ts +389 -1
- package/src/daemon/conversation-tool-setup.ts +10 -5
- package/src/daemon/conversation-usage.ts +1 -1
- package/src/daemon/conversation.ts +118 -30
- package/src/daemon/external-skills-bootstrap.ts +41 -0
- package/src/daemon/guardian-action-generators.ts +34 -14
- package/src/daemon/handlers/config-model.test.ts +86 -0
- package/src/daemon/handlers/config-model.ts +54 -12
- package/src/daemon/handlers/conversations.ts +9 -2
- package/src/daemon/handlers/shared.ts +39 -11
- package/src/daemon/handlers/skills.ts +2 -2
- package/src/daemon/handlers/slack-channel-oauth-install.ts +197 -0
- package/src/daemon/lifecycle.ts +76 -14
- package/src/daemon/message-types/conversations.ts +14 -0
- package/src/daemon/message-types/messages.ts +9 -1
- package/src/daemon/message-types/trust.ts +0 -2
- package/src/daemon/parse-actual-tokens-from-error.test.ts +57 -1
- package/src/daemon/parse-actual-tokens-from-error.ts +66 -0
- package/src/daemon/pkb-context-tracker.test.ts +169 -0
- package/src/daemon/pkb-context-tracker.ts +125 -0
- package/src/daemon/pkb-reminder-builder.test.ts +70 -0
- package/src/daemon/pkb-reminder-builder.ts +31 -0
- package/src/daemon/providers-setup.ts +6 -0
- package/src/daemon/server.ts +117 -9
- package/src/daemon/tool-side-effects.ts +0 -9
- package/src/daemon/watch-handler.ts +4 -4
- package/src/daemon/web-search-history.ts +126 -0
- package/src/events/domain-events.ts +0 -1
- package/src/filing/filing-service.ts +9 -10
- package/src/heartbeat/heartbeat-service.ts +76 -28
- package/src/home/__tests__/feed-scheduler.test.ts +39 -11
- package/src/home/__tests__/rollup-producer.test.ts +44 -0
- package/src/home/assistant-feed-authoring.ts +4 -0
- package/src/home/emit-feed-event.ts +4 -0
- package/src/home/feed-scheduler.ts +20 -4
- package/src/home/feed-types.ts +56 -2
- package/src/home/relationship-state-writer.ts +2 -2
- package/src/home/rollup-producer.ts +34 -5
- package/src/home/suggested-prompts.ts +101 -0
- package/src/ipc/__tests__/attachment-ipc.test.ts +213 -0
- package/src/ipc/__tests__/browser-ipc.test.ts +339 -0
- package/src/ipc/__tests__/cache-ipc.test.ts +266 -0
- package/src/ipc/__tests__/socket-path.test.ts +73 -0
- package/src/ipc/__tests__/task-ipc.test.ts +577 -0
- package/src/ipc/__tests__/ui-request-route.test.ts +495 -0
- package/src/ipc/__tests__/watcher-ipc.test.ts +295 -0
- package/src/ipc/cli-client.ts +2 -1
- package/src/ipc/cli-server.ts +26 -8
- package/src/ipc/gateway-client.ts +4 -4
- package/src/ipc/routes/attachment.ts +114 -0
- package/src/ipc/routes/browser-context.ts +61 -0
- package/src/ipc/routes/browser.ts +96 -0
- package/src/ipc/routes/cache.ts +96 -0
- package/src/ipc/routes/index.ts +17 -1
- package/src/ipc/routes/task-queue.ts +226 -0
- package/src/ipc/routes/task.ts +173 -0
- package/src/ipc/routes/ui-request.ts +50 -0
- package/src/ipc/routes/watcher.ts +203 -0
- package/src/ipc/socket-path.ts +100 -0
- package/src/memory/__tests__/conversation-analyze-job.test.ts +9 -8
- package/src/memory/__tests__/conversation-group-migration.test.ts +99 -0
- package/src/memory/admin.ts +18 -0
- package/src/memory/conversation-analyze-job.ts +14 -13
- package/src/memory/conversation-attention-store.ts +13 -6
- package/src/memory/conversation-crud.ts +103 -3
- package/src/memory/conversation-group-migration.ts +38 -6
- package/src/memory/conversation-title-service.ts +7 -4
- package/src/memory/db-init.ts +2 -0
- package/src/memory/embedding-backend.ts +1 -1
- package/src/memory/graph/compaction.ts +299 -0
- package/src/memory/graph/consolidation.ts +4 -4
- package/src/memory/graph/conversation-graph-memory.ts +89 -29
- package/src/memory/graph/extraction.test.ts +272 -2
- package/src/memory/graph/extraction.ts +173 -51
- package/src/memory/graph/graph-search.test.ts +92 -0
- package/src/memory/graph/graph-search.ts +4 -1
- package/src/memory/graph/narrative.ts +2 -2
- package/src/memory/graph/pattern-scan.ts +2 -2
- package/src/memory/graph/retriever.test.ts +459 -0
- package/src/memory/graph/retriever.ts +230 -48
- package/src/memory/graph/store.ts +41 -0
- package/src/memory/graph/tool-handlers.ts +27 -0
- package/src/memory/graph/tools.ts +6 -1
- package/src/memory/indexer.ts +5 -5
- package/src/memory/job-handlers/conversation-starters.ts +23 -20
- package/src/memory/job-handlers/summarization.ts +2 -2
- package/src/memory/job-utils.ts +7 -1
- package/src/memory/jobs/embed-pkb-file.test.ts +168 -0
- package/src/memory/jobs/embed-pkb-file.ts +54 -0
- package/src/memory/jobs-store.ts +44 -3
- package/src/memory/jobs-worker.ts +4 -0
- package/src/memory/migrations/140-backfill-usage-cache-accounting.ts +1 -1
- package/src/memory/migrations/220-normalize-user-file-by-principal.ts +2 -2
- package/src/memory/migrations/222-strip-placeholder-sentinels-from-messages.ts +82 -0
- package/src/memory/migrations/index.ts +1 -0
- package/src/memory/pkb/pkb-index.test.ts +368 -0
- package/src/memory/pkb/pkb-index.ts +255 -0
- package/src/memory/pkb/pkb-reconcile.test.ts +251 -0
- package/src/memory/pkb/pkb-reconcile.ts +148 -0
- package/src/memory/pkb/pkb-search.test.ts +438 -0
- package/src/memory/pkb/pkb-search.ts +137 -0
- package/src/memory/pkb/types.ts +53 -0
- package/src/memory/qdrant-client.ts +122 -1
- package/src/memory/slack-thread-store.ts +37 -0
- package/src/messaging/providers/gmail/adapter.ts +6 -16
- package/src/messaging/providers/gmail/client.ts +22 -0
- package/src/messaging/providers/gmail/types.ts +7 -0
- package/src/messaging/providers/slack/adapter.ts +14 -2
- package/src/messaging/providers/slack/backfill.test.ts +257 -0
- package/src/messaging/providers/slack/backfill.ts +101 -0
- package/src/messaging/providers/slack/message-metadata.test.ts +316 -0
- package/src/messaging/providers/slack/message-metadata.ts +123 -0
- package/src/messaging/providers/slack/render-transcript.test.ts +1373 -0
- package/src/messaging/providers/slack/render-transcript.ts +443 -0
- package/src/messaging/style-analyzer.ts +5 -2
- package/src/notifications/README.md +9 -5
- package/src/notifications/decision-engine.ts +3 -9
- package/src/notifications/preference-extractor.ts +2 -6
- package/src/oauth/oauth-store.ts +1 -0
- package/src/oauth/platform-connection.test.ts +47 -0
- package/src/oauth/platform-connection.ts +15 -5
- package/src/oauth/seed-providers.ts +4 -2
- package/src/permissions/approval-policy.test.ts +948 -0
- package/src/permissions/approval-policy.ts +257 -0
- package/src/permissions/bash-risk-classifier.test.ts +1208 -0
- package/src/permissions/bash-risk-classifier.ts +707 -0
- package/src/permissions/checker.ts +217 -708
- package/src/permissions/command-registry.test.ts +535 -0
- package/src/permissions/command-registry.ts +825 -0
- package/src/permissions/defaults.ts +26 -78
- package/src/permissions/file-risk-classifier.test.ts +535 -0
- package/src/permissions/file-risk-classifier.ts +274 -0
- package/src/permissions/risk-types.ts +205 -0
- package/src/permissions/secret-prompter.ts +53 -2
- package/src/permissions/skill-risk-classifier.test.ts +311 -0
- package/src/permissions/skill-risk-classifier.ts +214 -0
- package/src/permissions/trust-client.ts +52 -25
- package/src/permissions/trust-store-interface.ts +1 -6
- package/src/permissions/trust-store.ts +161 -62
- package/src/permissions/types.ts +23 -14
- package/src/permissions/web-risk-classifier.test.ts +170 -0
- package/src/permissions/web-risk-classifier.ts +89 -0
- package/src/permissions/workspace-policy.ts +1 -16
- package/src/platform/client.ts +19 -1
- package/src/prompts/persona-resolver.ts +3 -3
- package/src/prompts/system-prompt.ts +19 -20
- package/src/prompts/templates/SOUL.md +2 -2
- package/src/prompts/update-bulletin-job.ts +190 -0
- package/src/providers/__tests__/context-overflow-error.test.ts +328 -0
- package/src/providers/__tests__/provider-env-vars.test.ts +102 -0
- package/src/providers/__tests__/retry-callsite.test.ts +424 -0
- package/src/providers/anthropic/client.ts +183 -14
- package/src/providers/call-site-routing.ts +71 -0
- package/src/providers/gemini/client.ts +65 -2
- package/src/providers/managed-proxy/constants.ts +2 -1
- package/src/providers/model-catalog.ts +501 -33
- package/src/providers/model-intents.ts +4 -4
- package/src/providers/openai/chat-completions-provider.ts +57 -1
- package/src/providers/openai/responses-provider.ts +86 -9
- package/src/providers/openrouter/client.ts +76 -9
- package/src/providers/provider-env-vars.ts +56 -0
- package/src/providers/provider-send-message.ts +22 -5
- package/src/providers/ratelimit.ts +4 -0
- package/src/providers/registry.ts +19 -8
- package/src/providers/retry.ts +174 -39
- package/src/providers/speech-to-text/__tests__/resolve.test.ts +55 -0
- package/src/providers/speech-to-text/google-gemini-live-stream.ts +4 -4
- package/src/providers/speech-to-text/provider-catalog.ts +17 -0
- package/src/providers/speech-to-text/resolve.ts +7 -0
- package/src/providers/speech-to-text/xai-realtime.test.ts +578 -0
- package/src/providers/speech-to-text/xai-realtime.ts +796 -0
- package/src/providers/speech-to-text/xai.test.ts +155 -0
- package/src/providers/speech-to-text/xai.ts +97 -0
- package/src/providers/types.ts +93 -3
- package/src/runtime/AGENTS.md +2 -2
- package/src/runtime/__tests__/agent-wake.test.ts +43 -2
- package/src/runtime/__tests__/interactive-ui.test.ts +673 -0
- package/src/runtime/agent-wake.ts +63 -22
- package/src/runtime/auth/route-policy.ts +4 -0
- package/src/runtime/btw-sidechain.ts +13 -3
- package/src/runtime/channel-reply-delivery.ts +106 -2
- package/src/runtime/decision-token.ts +116 -0
- package/src/runtime/gateway-client.ts +2 -2
- package/src/runtime/http-router.ts +32 -0
- package/src/runtime/http-server.ts +52 -1
- package/src/runtime/http-types.ts +23 -1
- package/src/runtime/interactive-ui.ts +362 -0
- package/src/runtime/invite-instruction-generator.ts +2 -2
- package/src/runtime/migrations/__tests__/gcs-signed-url.test.ts +176 -0
- package/src/runtime/migrations/__tests__/vbundle-metadata-merge-integration.test.ts +390 -0
- package/src/runtime/migrations/__tests__/vbundle-metadata-merge.test.ts +221 -0
- package/src/runtime/migrations/__tests__/vbundle-streaming-importer.test.ts +1540 -0
- package/src/runtime/migrations/__tests__/vbundle-streaming-validator.test.ts +453 -0
- package/src/runtime/migrations/__tests__/vbundle-tar-stream.test.ts +222 -0
- package/src/runtime/migrations/gcs-signed-url.ts +162 -0
- package/src/runtime/migrations/vbundle-importer.ts +154 -9
- package/src/runtime/migrations/vbundle-metadata-merge.ts +124 -0
- package/src/runtime/migrations/vbundle-streaming-importer.ts +2522 -0
- package/src/runtime/migrations/vbundle-streaming-validator.ts +244 -0
- package/src/runtime/migrations/vbundle-tar-stream.ts +217 -0
- package/src/runtime/migrations/vbundle-validator.ts +15 -6
- package/src/runtime/routes/__tests__/home-feed-routes.test.ts +111 -0
- package/src/runtime/routes/__tests__/migration-import-credential-filter.test.ts +114 -75
- package/src/runtime/routes/__tests__/migration-vellum-metadata-reconcile.test.ts +246 -0
- package/src/runtime/routes/approval-prompt-ts-tracker.ts +58 -0
- package/src/runtime/routes/approval-routes.ts +12 -17
- package/src/runtime/routes/approval-strategies/guardian-callback-strategy.ts +9 -0
- package/src/runtime/routes/avatar-routes.ts +20 -4
- package/src/runtime/routes/btw-routes.ts +1 -4
- package/src/runtime/routes/conversation-management-routes.ts +20 -2
- package/src/runtime/routes/conversation-routes.ts +133 -27
- package/src/runtime/routes/debug-routes.ts +1 -1
- package/src/runtime/routes/diagnostics-routes.ts +6 -4
- package/src/runtime/routes/events-routes.ts +16 -0
- package/src/runtime/routes/guardian-approval-interception.ts +33 -3
- package/src/runtime/routes/guardian-approval-prompt.ts +13 -3
- package/src/runtime/routes/home-feed-routes.ts +120 -2
- package/src/runtime/routes/inbound-message-handler.ts +912 -2
- package/src/runtime/routes/inbound-stages/background-dispatch.test.ts +113 -2
- package/src/runtime/routes/inbound-stages/background-dispatch.ts +61 -3
- package/src/runtime/routes/inbound-stages/edit-intercept.ts +129 -6
- package/src/runtime/routes/integrations/slack/channel.ts +25 -3
- package/src/runtime/routes/llm-context-normalization.ts +23 -1
- package/src/runtime/routes/migration-routes.ts +720 -124
- package/src/runtime/routes/settings-routes.ts +4 -2
- package/src/runtime/routes/trust-rules-routes.ts +30 -14
- package/src/runtime/routes/work-items-routes.test.ts +1 -1
- package/src/runtime/routes/work-items-routes.ts +3 -2
- package/src/runtime/services/__tests__/analyze-conversation.test.ts +25 -43
- package/src/runtime/services/analyze-conversation.ts +12 -16
- package/src/runtime/skill-route-registry.ts +28 -6
- package/src/schedule/scheduler.ts +8 -0
- package/src/security/__tests__/provider-key-env-fallback.test.ts +119 -0
- package/src/security/__tests__/untrusted-content.test.ts +109 -0
- package/src/security/oauth2.ts +98 -35
- package/src/security/secure-keys.ts +7 -8
- package/src/security/token-manager.ts +27 -13
- package/src/security/untrusted-content.ts +102 -0
- package/src/skills/catalog-cache.ts +26 -7
- package/src/skills/catalog-install.ts +31 -3
- package/src/skills/skill-cache-store.ts +97 -0
- package/src/stt/__tests__/daemon-batch-transcriber.test.ts +76 -0
- package/src/stt/daemon-batch-transcriber.ts +33 -0
- package/src/stt/stt-stream-session.ts +8 -1
- package/src/stt/types.ts +5 -1
- package/src/subagent/manager.ts +41 -13
- package/src/tasks/ephemeral-permissions.ts +9 -4
- package/src/telemetry/usage-telemetry-reporter.ts +27 -5
- package/src/tools/browser/__tests__/browser-status.test.ts +45 -2
- package/src/tools/browser/browser-execution.ts +65 -38
- package/src/tools/browser/cdp-client/cdp-inspect/discovery.ts +22 -0
- package/src/tools/credentials/tool-policy.ts +39 -5
- package/src/tools/credentials/vault.ts +9 -4
- package/src/tools/executor.ts +4 -0
- package/src/tools/filesystem/write.ts +52 -0
- package/src/tools/host-terminal/host-shell.ts +45 -5
- package/src/tools/memory/register.test.ts +185 -0
- package/src/tools/memory/register.ts +3 -1
- package/src/tools/network/web-fetch.ts +20 -10
- package/src/tools/network/web-search.ts +19 -4
- package/src/tools/permission-checker.ts +36 -15
- package/src/tools/policy-context.ts +25 -8
- package/src/tools/registry.ts +55 -3
- package/src/tools/side-effects.ts +0 -11
- package/src/tools/skills/execute.ts +2 -2
- package/src/tools/skills/sandbox-runner.ts +5 -2
- package/src/tools/terminal/backends/native.ts +51 -2
- package/src/tools/terminal/safe-env.ts +3 -2
- package/src/tools/terminal/shell.ts +1 -0
- package/src/tools/tool-manifest.ts +6 -21
- package/src/tools/types.ts +12 -3
- package/src/tools/verification-control-plane-policy.ts +1 -1
- package/src/tts/__tests__/provider-adapters.test.ts +240 -13
- package/src/tts/provider-catalog.ts +18 -0
- package/src/tts/providers/index.ts +2 -0
- package/src/tts/providers/xai-provider.ts +224 -0
- package/src/tts/types.ts +46 -0
- package/src/types/tar-stream.d.ts +66 -0
- package/src/util/json.ts +17 -0
- package/src/util/platform.ts +2 -2
- package/src/util/pricing.ts +15 -5
- package/src/watcher/engine.ts +1 -1
- package/src/watcher/providers/google-calendar.ts +134 -8
- package/src/watcher/providers/outlook-calendar.ts +42 -2
- package/src/workspace/git-service.ts +23 -4
- package/src/workspace/migrations/038-unify-llm-callsite-configs.ts +516 -0
- package/src/workspace/migrations/039-drop-legacy-llm-keys.ts +171 -0
- package/src/workspace/migrations/040-seed-latency-callsite-defaults.ts +154 -0
- package/src/workspace/migrations/041-backfill-google-gmail-settings-scope.ts +57 -0
- package/src/workspace/migrations/042-fix-backfill-google-gmail-settings-scope.ts +70 -0
- package/src/workspace/migrations/043-release-notes-latex-rendering.ts +75 -0
- package/src/workspace/migrations/044-bump-stale-provider-stream-timeout.ts +51 -0
- package/src/workspace/migrations/045-release-notes-meet-avatar.ts +130 -0
- package/src/workspace/migrations/AGENTS.md +1 -1
- package/src/workspace/migrations/registry.ts +16 -0
- package/src/workspace/provider-commit-message-generator.ts +19 -38
- package/src/__tests__/gmail-archive-fallback.test.ts +0 -193
- package/src/__tests__/gmail-archive-gate.test.ts +0 -246
- package/src/__tests__/gmail-preferences.test.ts +0 -117
- package/src/__tests__/outlook-attachments.test.ts +0 -301
- package/src/__tests__/outlook-automation-tools.test.ts +0 -425
- package/src/__tests__/outlook-categories.test.ts +0 -212
- package/src/__tests__/outlook-compose-tools.test.ts +0 -325
- package/src/__tests__/outlook-declutter-tools.test.ts +0 -585
- package/src/__tests__/outlook-follow-up.test.ts +0 -196
- package/src/__tests__/outlook-trash.test.ts +0 -77
- package/src/__tests__/outlook-unsubscribe.test.ts +0 -279
- package/src/__tests__/update-bulletin-format.test.ts +0 -181
- package/src/__tests__/update-bulletin-state.test.ts +0 -135
- package/src/__tests__/update-bulletin.test.ts +0 -478
- package/src/__tests__/update-template-contract.test.ts +0 -29
- package/src/cli/commands/doctor.ts +0 -341
- package/src/config/bundled-skills/browser/SKILL.md +0 -88
- package/src/config/bundled-skills/browser/TOOLS.json +0 -516
- package/src/config/bundled-skills/browser/tools/browser-attach.ts +0 -12
- package/src/config/bundled-skills/browser/tools/browser-click.ts +0 -12
- package/src/config/bundled-skills/browser/tools/browser-close.ts +0 -12
- package/src/config/bundled-skills/browser/tools/browser-detach.ts +0 -12
- package/src/config/bundled-skills/browser/tools/browser-extract.ts +0 -12
- package/src/config/bundled-skills/browser/tools/browser-fill-credential.ts +0 -12
- package/src/config/bundled-skills/browser/tools/browser-hover.ts +0 -12
- package/src/config/bundled-skills/browser/tools/browser-navigate.ts +0 -12
- package/src/config/bundled-skills/browser/tools/browser-press-key.ts +0 -12
- package/src/config/bundled-skills/browser/tools/browser-screenshot.ts +0 -12
- package/src/config/bundled-skills/browser/tools/browser-scroll.ts +0 -12
- package/src/config/bundled-skills/browser/tools/browser-select-option.ts +0 -12
- package/src/config/bundled-skills/browser/tools/browser-snapshot.ts +0 -12
- package/src/config/bundled-skills/browser/tools/browser-status.ts +0 -12
- package/src/config/bundled-skills/browser/tools/browser-type.ts +0 -12
- package/src/config/bundled-skills/browser/tools/browser-wait-for-download.ts +0 -49
- package/src/config/bundled-skills/browser/tools/browser-wait-for.ts +0 -12
- package/src/config/bundled-skills/chatgpt-import/SKILL.md +0 -27
- package/src/config/bundled-skills/chatgpt-import/TOOLS.json +0 -27
- package/src/config/bundled-skills/chatgpt-import/tools/chatgpt-import.ts +0 -378
- package/src/config/bundled-skills/gmail/SKILL.md +0 -221
- package/src/config/bundled-skills/gmail/TOOLS.json +0 -588
- package/src/config/bundled-skills/gmail/tools/gmail-archive.ts +0 -256
- package/src/config/bundled-skills/gmail/tools/gmail-attachments.ts +0 -112
- package/src/config/bundled-skills/gmail/tools/gmail-draft.ts +0 -44
- package/src/config/bundled-skills/gmail/tools/gmail-filters.ts +0 -81
- package/src/config/bundled-skills/gmail/tools/gmail-follow-up.ts +0 -108
- package/src/config/bundled-skills/gmail/tools/gmail-forward.ts +0 -146
- package/src/config/bundled-skills/gmail/tools/gmail-label.ts +0 -53
- package/src/config/bundled-skills/gmail/tools/gmail-outreach-scan.ts +0 -347
- package/src/config/bundled-skills/gmail/tools/gmail-preferences-tool.ts +0 -59
- package/src/config/bundled-skills/gmail/tools/gmail-preferences.ts +0 -82
- package/src/config/bundled-skills/gmail/tools/gmail-send-draft.ts +0 -26
- package/src/config/bundled-skills/gmail/tools/gmail-sender-digest.ts +0 -347
- package/src/config/bundled-skills/gmail/tools/gmail-trash.ts +0 -29
- package/src/config/bundled-skills/gmail/tools/gmail-unsubscribe.ts +0 -122
- package/src/config/bundled-skills/gmail/tools/gmail-vacation.ts +0 -67
- package/src/config/bundled-skills/gmail/tools/scan-result-store.ts +0 -100
- package/src/config/bundled-skills/gmail/tools/shared.ts +0 -47
- package/src/config/bundled-skills/google-calendar/SKILL.md +0 -51
- package/src/config/bundled-skills/google-calendar/TOOLS.json +0 -226
- package/src/config/bundled-skills/google-calendar/calendar-client.ts +0 -223
- package/src/config/bundled-skills/google-calendar/tools/calendar-check-availability.ts +0 -27
- package/src/config/bundled-skills/google-calendar/tools/calendar-create-event.ts +0 -48
- package/src/config/bundled-skills/google-calendar/tools/calendar-get-event.ts +0 -19
- package/src/config/bundled-skills/google-calendar/tools/calendar-list-events.ts +0 -36
- package/src/config/bundled-skills/google-calendar/tools/calendar-rsvp.ts +0 -58
- package/src/config/bundled-skills/google-calendar/tools/shared.ts +0 -17
- package/src/config/bundled-skills/google-calendar/types.ts +0 -97
- package/src/config/bundled-skills/outlook/SKILL.md +0 -196
- package/src/config/bundled-skills/outlook/TOOLS.json +0 -530
- package/src/config/bundled-skills/outlook/tools/outlook-attachments.ts +0 -85
- package/src/config/bundled-skills/outlook/tools/outlook-categories.ts +0 -77
- package/src/config/bundled-skills/outlook/tools/outlook-draft.ts +0 -84
- package/src/config/bundled-skills/outlook/tools/outlook-follow-up.ts +0 -94
- package/src/config/bundled-skills/outlook/tools/outlook-forward.ts +0 -49
- package/src/config/bundled-skills/outlook/tools/outlook-outreach-scan.ts +0 -237
- package/src/config/bundled-skills/outlook/tools/outlook-rules.ts +0 -161
- package/src/config/bundled-skills/outlook/tools/outlook-send-draft.ts +0 -32
- package/src/config/bundled-skills/outlook/tools/outlook-sender-digest.ts +0 -272
- package/src/config/bundled-skills/outlook/tools/outlook-trash.ts +0 -29
- package/src/config/bundled-skills/outlook/tools/outlook-unsubscribe.ts +0 -129
- package/src/config/bundled-skills/outlook/tools/outlook-vacation.ts +0 -87
- package/src/config/bundled-skills/outlook/tools/shared.ts +0 -20
- package/src/config/bundled-skills/outlook-calendar/SKILL.md +0 -51
- package/src/config/bundled-skills/outlook-calendar/TOOLS.json +0 -221
- package/src/config/bundled-skills/outlook-calendar/calendar-client.ts +0 -252
- package/src/config/bundled-skills/outlook-calendar/tools/outlook-calendar-check-availability.ts +0 -53
- package/src/config/bundled-skills/outlook-calendar/tools/outlook-calendar-create-event.ts +0 -74
- package/src/config/bundled-skills/outlook-calendar/tools/outlook-calendar-get-event.ts +0 -18
- package/src/config/bundled-skills/outlook-calendar/tools/outlook-calendar-list-events.ts +0 -46
- package/src/config/bundled-skills/outlook-calendar/tools/outlook-calendar-rsvp.ts +0 -36
- package/src/config/bundled-skills/outlook-calendar/tools/shared.ts +0 -17
- package/src/config/bundled-skills/outlook-calendar/types.ts +0 -120
- package/src/config/bundled-skills/slack/SKILL.md +0 -108
- package/src/config/bundled-skills/tasks/SKILL.md +0 -37
- package/src/config/bundled-skills/tasks/TOOLS.json +0 -353
- package/src/config/bundled-skills/tasks/icon.svg +0 -34
- package/src/config/bundled-skills/tasks/tools/task-delete.ts +0 -12
- package/src/config/bundled-skills/tasks/tools/task-list-add.ts +0 -12
- package/src/config/bundled-skills/tasks/tools/task-list-remove.ts +0 -12
- package/src/config/bundled-skills/tasks/tools/task-list-show.ts +0 -12
- package/src/config/bundled-skills/tasks/tools/task-list-update.ts +0 -12
- package/src/config/bundled-skills/tasks/tools/task-list.ts +0 -12
- package/src/config/bundled-skills/tasks/tools/task-queue-run.ts +0 -12
- package/src/config/bundled-skills/tasks/tools/task-run.ts +0 -12
- package/src/config/bundled-skills/tasks/tools/task-save.ts +0 -12
- package/src/config/bundled-skills/watcher/SKILL.md +0 -31
- package/src/config/bundled-skills/watcher/TOOLS.json +0 -167
- package/src/config/bundled-skills/watcher/tools/watcher-create.ts +0 -12
- package/src/config/bundled-skills/watcher/tools/watcher-delete.ts +0 -12
- package/src/config/bundled-skills/watcher/tools/watcher-digest.ts +0 -12
- package/src/config/bundled-skills/watcher/tools/watcher-list.ts +0 -12
- package/src/config/bundled-skills/watcher/tools/watcher-update.ts +0 -12
- package/src/prompts/templates/UPDATES.md +0 -50
- package/src/prompts/update-bulletin-format.ts +0 -85
- package/src/prompts/update-bulletin-state.ts +0 -58
- package/src/prompts/update-bulletin-template-path.ts +0 -13
- package/src/prompts/update-bulletin.ts +0 -139
- package/src/shared/provider-env-vars.ts +0 -19
- package/src/tools/watcher/create.ts +0 -86
- package/src/tools/watcher/delete.ts +0 -36
- package/src/tools/watcher/digest.ts +0 -54
- package/src/tools/watcher/list.ts +0 -83
- package/src/tools/watcher/update.ts +0 -71
|
@@ -45,11 +45,7 @@ export interface TrustStoreBackend {
|
|
|
45
45
|
): TrustRule | null;
|
|
46
46
|
|
|
47
47
|
/** Find the first matching deny rule for a tool/command/scope. */
|
|
48
|
-
findDenyRule(
|
|
49
|
-
tool: string,
|
|
50
|
-
command: string,
|
|
51
|
-
scope: string,
|
|
52
|
-
): TrustRule | null;
|
|
48
|
+
findDenyRule(tool: string, command: string, scope: string): TrustRule | null;
|
|
53
49
|
|
|
54
50
|
/** Add a new trust rule and persist it. */
|
|
55
51
|
addRule(
|
|
@@ -59,7 +55,6 @@ export interface TrustStoreBackend {
|
|
|
59
55
|
decision?: "allow" | "deny" | "ask",
|
|
60
56
|
priority?: number,
|
|
61
57
|
options?: {
|
|
62
|
-
allowHighRisk?: boolean;
|
|
63
58
|
executionTarget?: string;
|
|
64
59
|
},
|
|
65
60
|
): TrustRule;
|
|
@@ -8,6 +8,12 @@ import {
|
|
|
8
8
|
} from "node:fs";
|
|
9
9
|
import { dirname, join } from "node:path";
|
|
10
10
|
|
|
11
|
+
import {
|
|
12
|
+
parseTrustFileData,
|
|
13
|
+
parseTrustRule,
|
|
14
|
+
ruleScope,
|
|
15
|
+
SCOPED_TOOLS,
|
|
16
|
+
} from "@vellumai/ces-contracts";
|
|
11
17
|
import { Minimatch } from "minimatch";
|
|
12
18
|
import { v4 as uuid } from "uuid";
|
|
13
19
|
|
|
@@ -31,6 +37,9 @@ export type { TrustStoreBackend } from "./trust-store-interface.js";
|
|
|
31
37
|
|
|
32
38
|
const log = getLogger("trust-store");
|
|
33
39
|
|
|
40
|
+
/** O(1) lookup set for scoped tool names. */
|
|
41
|
+
const SCOPED_TOOLS_SET: ReadonlySet<string> = new Set(SCOPED_TOOLS);
|
|
42
|
+
|
|
34
43
|
const TRUST_FILE_VERSION = 3;
|
|
35
44
|
|
|
36
45
|
interface TrustFile {
|
|
@@ -151,7 +160,7 @@ function ruleOrder(a: TrustRule, b: TrustRule): number {
|
|
|
151
160
|
if (b.priority !== a.priority) return b.priority - a.priority;
|
|
152
161
|
if (a.decision !== b.decision) {
|
|
153
162
|
// deny > ask > allow
|
|
154
|
-
const order = { deny: 0, ask: 1, allow: 2 };
|
|
163
|
+
const order: Record<string, number> = { deny: 0, ask: 1, allow: 2 };
|
|
155
164
|
return (order[a.decision] ?? 2) - (order[b.decision] ?? 2);
|
|
156
165
|
}
|
|
157
166
|
return 0;
|
|
@@ -197,21 +206,39 @@ function backfillDefaults(rules: TrustRule[]): boolean {
|
|
|
197
206
|
}
|
|
198
207
|
}
|
|
199
208
|
|
|
200
|
-
// Migrate existing default rules whose priority, pattern, scope, decision
|
|
201
|
-
//
|
|
202
|
-
//
|
|
203
|
-
//
|
|
209
|
+
// Migrate existing default rules whose priority, pattern, scope, or decision
|
|
210
|
+
// has changed in the template (e.g. host_bash pattern changed from '*' to
|
|
211
|
+
// '**', host tool priorities changed from 1000 to 50, workspace scope
|
|
212
|
+
// changed from getRootDir()+workspace to getWorkspaceDir()).
|
|
213
|
+
//
|
|
214
|
+
// Also strip any leftover allowHighRisk fields from persisted default rules
|
|
215
|
+
// since the field has been replaced by runtime determination.
|
|
216
|
+
//
|
|
217
|
+
// Rules with `userModifiedAt` set are skipped — the user explicitly
|
|
218
|
+
// customized them and their override should be preserved across upgrades.
|
|
204
219
|
for (const template of getDefaultRuleTemplates()) {
|
|
205
220
|
if (existingIds.has(template.id)) {
|
|
206
221
|
const rule = rules.find((r) => r.id === template.id);
|
|
222
|
+
if (!rule) continue;
|
|
223
|
+
// Strip legacy allowHighRisk from persisted default rules.
|
|
224
|
+
const ruleRecord = rule as unknown as Record<string, unknown>;
|
|
225
|
+
if ("allowHighRisk" in ruleRecord) {
|
|
226
|
+
delete ruleRecord.allowHighRisk;
|
|
227
|
+
changed = true;
|
|
228
|
+
}
|
|
207
229
|
if (
|
|
208
|
-
rule
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
rule.decision !== template.decision ||
|
|
213
|
-
rule.allowHighRisk !== template.allowHighRisk)
|
|
230
|
+
rule.priority !== template.priority ||
|
|
231
|
+
rule.pattern !== template.pattern ||
|
|
232
|
+
ruleScope(rule) !== (template.scope ?? "everywhere") ||
|
|
233
|
+
rule.decision !== template.decision
|
|
214
234
|
) {
|
|
235
|
+
if (rule.userModifiedAt != null) {
|
|
236
|
+
log.info(
|
|
237
|
+
{ ruleId: rule.id, userModifiedAt: rule.userModifiedAt },
|
|
238
|
+
"Skipping migration of user-modified default rule",
|
|
239
|
+
);
|
|
240
|
+
continue;
|
|
241
|
+
}
|
|
215
242
|
log.info(
|
|
216
243
|
{
|
|
217
244
|
ruleId: rule.id,
|
|
@@ -219,20 +246,17 @@ function backfillDefaults(rules: TrustRule[]): boolean {
|
|
|
219
246
|
newPriority: template.priority,
|
|
220
247
|
oldPattern: rule.pattern,
|
|
221
248
|
newPattern: template.pattern,
|
|
222
|
-
oldScope: rule
|
|
223
|
-
newScope: template.scope,
|
|
249
|
+
oldScope: ruleScope(rule),
|
|
250
|
+
newScope: template.scope ?? "everywhere",
|
|
224
251
|
},
|
|
225
252
|
"Migrated default rule to updated template values",
|
|
226
253
|
);
|
|
227
254
|
rule.priority = template.priority;
|
|
228
255
|
rule.pattern = template.pattern;
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
if (template.allowHighRisk != null) {
|
|
232
|
-
rule.allowHighRisk = template.allowHighRisk;
|
|
233
|
-
} else {
|
|
234
|
-
delete rule.allowHighRisk;
|
|
256
|
+
if (template.scope != null) {
|
|
257
|
+
rule.scope = template.scope;
|
|
235
258
|
}
|
|
259
|
+
rule.decision = template.decision;
|
|
236
260
|
changed = true;
|
|
237
261
|
}
|
|
238
262
|
}
|
|
@@ -240,19 +264,13 @@ function backfillDefaults(rules: TrustRule[]): boolean {
|
|
|
240
264
|
|
|
241
265
|
for (const template of getDefaultRuleTemplates()) {
|
|
242
266
|
if (!existingIds.has(template.id)) {
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
scope: template.scope,
|
|
248
|
-
decision: template.decision,
|
|
249
|
-
priority: template.priority,
|
|
267
|
+
// Canonicalize through parseTrustRule so family-specific field
|
|
268
|
+
// validation is applied (consistent with fileAddRule/fileUpdateRule).
|
|
269
|
+
const { rule } = parseTrustRule({
|
|
270
|
+
...template,
|
|
250
271
|
createdAt: Date.now(),
|
|
251
|
-
};
|
|
252
|
-
|
|
253
|
-
rule.allowHighRisk = template.allowHighRisk;
|
|
254
|
-
}
|
|
255
|
-
rules.push(rule);
|
|
272
|
+
});
|
|
273
|
+
rules.push(rule as TrustRule);
|
|
256
274
|
changed = true;
|
|
257
275
|
log.info({ ruleId: template.id }, "Backfilled default trust rule");
|
|
258
276
|
}
|
|
@@ -294,7 +312,6 @@ function loadFromDisk(): TrustRule[] {
|
|
|
294
312
|
data.version === 1 ||
|
|
295
313
|
data.version === 2
|
|
296
314
|
) {
|
|
297
|
-
rules = sanitizedRules;
|
|
298
315
|
if (sanitizedRules.length < rawRules.length) {
|
|
299
316
|
needsSave = true;
|
|
300
317
|
}
|
|
@@ -306,6 +323,21 @@ function loadFromDisk(): TrustRule[] {
|
|
|
306
323
|
);
|
|
307
324
|
}
|
|
308
325
|
|
|
326
|
+
// Apply canonical parser for family-aware normalization.
|
|
327
|
+
// The parser strips fields that are invalid for a rule's tool family
|
|
328
|
+
// (e.g. executionTarget on URL rules) and coerces malformed values.
|
|
329
|
+
const { data: parsedData, normalized } = parseTrustFileData({
|
|
330
|
+
...data,
|
|
331
|
+
rules: sanitizedRules,
|
|
332
|
+
});
|
|
333
|
+
// The contracts parser returns the union TrustRule type; our local
|
|
334
|
+
// TrustRule flattens the union with optional fields for backward
|
|
335
|
+
// compatibility. The structural overlap is safe to cast here.
|
|
336
|
+
rules = parsedData.rules as TrustRule[];
|
|
337
|
+
if (normalized) {
|
|
338
|
+
needsSave = true;
|
|
339
|
+
}
|
|
340
|
+
|
|
309
341
|
// Strip legacy principal-scoped fields from persisted v3 rules.
|
|
310
342
|
// Before the principal concept was removed, rules could carry
|
|
311
343
|
// principalKind/principalId/principalVersion which acted as scope
|
|
@@ -400,31 +432,37 @@ function fileAddRule(
|
|
|
400
432
|
decision: "allow" | "deny" | "ask" = "allow",
|
|
401
433
|
priority: number = 100,
|
|
402
434
|
options?: {
|
|
403
|
-
allowHighRisk?: boolean;
|
|
404
435
|
executionTarget?: string;
|
|
405
436
|
},
|
|
406
437
|
): TrustRule {
|
|
407
438
|
if (tool.startsWith("__internal:"))
|
|
408
439
|
throw new Error(`Cannot create internal pseudo-rule via addRule: ${tool}`);
|
|
409
|
-
|
|
410
|
-
//
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
440
|
+
|
|
441
|
+
// Canonicalize through the shared parser so fields invalid for the tool's
|
|
442
|
+
// family are stripped before persistence, regardless of which callsite
|
|
443
|
+
// invoked addRule. Only include scope for scoped tools — non-scoped tools
|
|
444
|
+
// don't carry a scope field.
|
|
445
|
+
const rawRule: Record<string, unknown> = {
|
|
414
446
|
id: uuid(),
|
|
415
447
|
tool,
|
|
416
448
|
pattern,
|
|
417
|
-
scope,
|
|
418
449
|
decision,
|
|
419
450
|
priority,
|
|
420
451
|
createdAt: Date.now(),
|
|
421
452
|
};
|
|
422
|
-
if (
|
|
423
|
-
|
|
453
|
+
if (SCOPED_TOOLS_SET.has(tool)) {
|
|
454
|
+
rawRule.scope = scope;
|
|
424
455
|
}
|
|
425
456
|
if (options?.executionTarget != null) {
|
|
426
|
-
|
|
457
|
+
rawRule.executionTarget = options.executionTarget;
|
|
427
458
|
}
|
|
459
|
+
const { rule: canonical } = parseTrustRule(rawRule);
|
|
460
|
+
const rule = canonical as TrustRule;
|
|
461
|
+
|
|
462
|
+
// Re-read from disk to avoid lost updates if another call modified rules
|
|
463
|
+
// between our last read and now (e.g. two rapid trust rule additions).
|
|
464
|
+
cachedRules = null;
|
|
465
|
+
const rules = [...getRules()];
|
|
428
466
|
rules.push(rule);
|
|
429
467
|
rules.sort(ruleOrder);
|
|
430
468
|
cachedRules = rules;
|
|
@@ -445,9 +483,6 @@ function fileUpdateRule(
|
|
|
445
483
|
priority?: number;
|
|
446
484
|
},
|
|
447
485
|
): TrustRule {
|
|
448
|
-
const defaultIds = new Set(getDefaultRuleTemplates().map((t) => t.id));
|
|
449
|
-
if (defaultIds.has(id))
|
|
450
|
-
throw new Error(`Cannot modify default trust rule: ${id}`);
|
|
451
486
|
if (updates.tool?.startsWith("__internal:"))
|
|
452
487
|
throw new Error(
|
|
453
488
|
`Cannot update tool to internal pseudo-rule: ${updates.tool}`,
|
|
@@ -458,12 +493,45 @@ function fileUpdateRule(
|
|
|
458
493
|
const rules = [...getRules()];
|
|
459
494
|
const index = rules.findIndex((r) => r.id === id);
|
|
460
495
|
if (index === -1) throw new Error(`Trust rule not found: ${id}`);
|
|
461
|
-
const
|
|
462
|
-
if (updates.tool != null)
|
|
463
|
-
if (updates.pattern != null)
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
if (updates.
|
|
496
|
+
const merged = { ...rules[index] };
|
|
497
|
+
if (updates.tool != null) merged.tool = updates.tool;
|
|
498
|
+
if (updates.pattern != null) merged.pattern = updates.pattern;
|
|
499
|
+
// Only apply scope updates for scoped tools — non-scoped tools ignore scope.
|
|
500
|
+
const effectiveTool = updates.tool ?? merged.tool;
|
|
501
|
+
if (updates.scope != null && SCOPED_TOOLS_SET.has(effectiveTool)) {
|
|
502
|
+
merged.scope = updates.scope;
|
|
503
|
+
}
|
|
504
|
+
if (updates.decision != null) merged.decision = updates.decision;
|
|
505
|
+
if (updates.priority != null) merged.priority = updates.priority;
|
|
506
|
+
|
|
507
|
+
// Mark default rules with userModifiedAt so backfillDefaults() preserves
|
|
508
|
+
// the user's customization across upgrades instead of overwriting it.
|
|
509
|
+
// Only set the timestamp when the merged result actually diverges from the
|
|
510
|
+
// template — a no-op PATCH (same values) should not permanently opt a rule
|
|
511
|
+
// out of future template migrations.
|
|
512
|
+
const templates = getDefaultRuleTemplates();
|
|
513
|
+
const template = templates.find((t) => t.id === id);
|
|
514
|
+
if (template) {
|
|
515
|
+
const diverges =
|
|
516
|
+
merged.tool !== template.tool ||
|
|
517
|
+
merged.pattern !== template.pattern ||
|
|
518
|
+
ruleScope(merged) !== (template.scope ?? "everywhere") ||
|
|
519
|
+
merged.decision !== template.decision ||
|
|
520
|
+
merged.priority !== template.priority;
|
|
521
|
+
if (diverges) {
|
|
522
|
+
merged.userModifiedAt = Date.now();
|
|
523
|
+
} else {
|
|
524
|
+
// Rule matches the template again — clear the override marker so
|
|
525
|
+
// future template changes are applied normally.
|
|
526
|
+
delete merged.userModifiedAt;
|
|
527
|
+
}
|
|
528
|
+
}
|
|
529
|
+
|
|
530
|
+
// Canonicalize through parseTrustRule so that fields invalid for the
|
|
531
|
+
// (potentially changed) tool family are stripped. For example, if a rule's
|
|
532
|
+
// tool is changed from "bash" to "web_fetch", executionTarget is dropped
|
|
533
|
+
// because URL-family tools don't support target scoping.
|
|
534
|
+
const { rule } = parseTrustRule(merged as unknown as Record<string, unknown>);
|
|
467
535
|
rules[index] = rule;
|
|
468
536
|
rules.sort(ruleOrder);
|
|
469
537
|
cachedRules = rules;
|
|
@@ -514,7 +582,7 @@ function findRuleByDecision(
|
|
|
514
582
|
if (rule.decision !== decision) continue;
|
|
515
583
|
const compiled = getCompiledPattern(rule.pattern);
|
|
516
584
|
if (!compiled || !compiled.match(command)) continue;
|
|
517
|
-
if (!matchesScope(rule
|
|
585
|
+
if (!matchesScope(ruleScope(rule), scope)) continue;
|
|
518
586
|
return rule;
|
|
519
587
|
}
|
|
520
588
|
return null;
|
|
@@ -525,6 +593,10 @@ function findRuleByDecision(
|
|
|
525
593
|
*
|
|
526
594
|
* If the rule does not specify an executionTarget it matches any target
|
|
527
595
|
* (wildcard). If specified, it must match exactly.
|
|
596
|
+
*
|
|
597
|
+
* Not all trust rule families carry `executionTarget` — URL, managed-skill,
|
|
598
|
+
* and skill-load rules never have it. For those families the check is a
|
|
599
|
+
* no-op (wildcard match).
|
|
528
600
|
*/
|
|
529
601
|
function matchesExecutionTarget(rule: TrustRule, ctx?: PolicyContext): boolean {
|
|
530
602
|
if (rule.executionTarget == null) return true;
|
|
@@ -561,7 +633,7 @@ function fileFindHighestPriorityRule(
|
|
|
561
633
|
|
|
562
634
|
for (const rule of allRules) {
|
|
563
635
|
if (rule.tool !== tool) continue;
|
|
564
|
-
if (!matchesScope(rule
|
|
636
|
+
if (!matchesScope(ruleScope(rule), scope)) continue;
|
|
565
637
|
if (!matchesExecutionTarget(rule, ctx)) continue;
|
|
566
638
|
const compiled = getCompiledPattern(rule.pattern);
|
|
567
639
|
if (!compiled) continue;
|
|
@@ -914,7 +986,7 @@ class GatewayTrustStoreAdapter implements TrustStoreBackend {
|
|
|
914
986
|
|
|
915
987
|
for (const rule of allRules) {
|
|
916
988
|
if (rule.tool !== tool) continue;
|
|
917
|
-
if (!matchesScope(rule
|
|
989
|
+
if (!matchesScope(ruleScope(rule), scope)) continue;
|
|
918
990
|
if (!matchesExecutionTarget(rule, ctx)) continue;
|
|
919
991
|
const compiled = this.getCompiledPattern(rule.pattern);
|
|
920
992
|
if (!compiled) continue;
|
|
@@ -938,7 +1010,7 @@ class GatewayTrustStoreAdapter implements TrustStoreBackend {
|
|
|
938
1010
|
if (rule.decision !== "allow") continue;
|
|
939
1011
|
const compiled = this.getCompiledPattern(rule.pattern);
|
|
940
1012
|
if (!compiled || !compiled.match(command)) continue;
|
|
941
|
-
if (!matchesScope(rule
|
|
1013
|
+
if (!matchesScope(ruleScope(rule), scope)) continue;
|
|
942
1014
|
return rule;
|
|
943
1015
|
}
|
|
944
1016
|
return null;
|
|
@@ -951,7 +1023,7 @@ class GatewayTrustStoreAdapter implements TrustStoreBackend {
|
|
|
951
1023
|
if (rule.decision !== "deny") continue;
|
|
952
1024
|
const compiled = this.getCompiledPattern(rule.pattern);
|
|
953
1025
|
if (!compiled || !compiled.match(command)) continue;
|
|
954
|
-
if (!matchesScope(rule
|
|
1026
|
+
if (!matchesScope(ruleScope(rule), scope)) continue;
|
|
955
1027
|
return rule;
|
|
956
1028
|
}
|
|
957
1029
|
return null;
|
|
@@ -964,7 +1036,6 @@ class GatewayTrustStoreAdapter implements TrustStoreBackend {
|
|
|
964
1036
|
decision: "allow" | "deny" | "ask" = "allow",
|
|
965
1037
|
priority: number = 100,
|
|
966
1038
|
options?: {
|
|
967
|
-
allowHighRisk?: boolean;
|
|
968
1039
|
executionTarget?: string;
|
|
969
1040
|
},
|
|
970
1041
|
): TrustRule {
|
|
@@ -972,15 +1043,39 @@ class GatewayTrustStoreAdapter implements TrustStoreBackend {
|
|
|
972
1043
|
throw new Error(
|
|
973
1044
|
`Cannot create internal pseudo-rule via addRule: ${tool}`,
|
|
974
1045
|
);
|
|
975
|
-
|
|
976
|
-
|
|
1046
|
+
|
|
1047
|
+
// Canonicalize through the shared parser so fields invalid for the tool's
|
|
1048
|
+
// family are stripped before sending to the gateway.
|
|
1049
|
+
const { rule: canonical } = parseTrustRule({
|
|
1050
|
+
id: "",
|
|
977
1051
|
tool,
|
|
978
1052
|
pattern,
|
|
979
1053
|
scope,
|
|
980
1054
|
decision,
|
|
981
1055
|
priority,
|
|
982
|
-
|
|
983
|
-
|
|
1056
|
+
createdAt: 0,
|
|
1057
|
+
...(options?.executionTarget != null
|
|
1058
|
+
? { executionTarget: options.executionTarget }
|
|
1059
|
+
: {}),
|
|
1060
|
+
});
|
|
1061
|
+
const canonicalOpts: { executionTarget?: string } = {};
|
|
1062
|
+
if ("executionTarget" in canonical) {
|
|
1063
|
+
canonicalOpts.executionTarget = (
|
|
1064
|
+
canonical as { executionTarget?: string }
|
|
1065
|
+
).executionTarget;
|
|
1066
|
+
}
|
|
1067
|
+
|
|
1068
|
+
this.ensureInitialized();
|
|
1069
|
+
const rule = trustClient.addRuleSync({
|
|
1070
|
+
tool: canonical.tool,
|
|
1071
|
+
pattern: canonical.pattern,
|
|
1072
|
+
// Only send scope for scoped tools — non-scoped tools omit it.
|
|
1073
|
+
...(SCOPED_TOOLS_SET.has(canonical.tool)
|
|
1074
|
+
? { scope: ruleScope(canonical) }
|
|
1075
|
+
: {}),
|
|
1076
|
+
decision: canonical.decision,
|
|
1077
|
+
priority: canonical.priority,
|
|
1078
|
+
executionTarget: canonicalOpts.executionTarget,
|
|
984
1079
|
});
|
|
985
1080
|
// Update local cache
|
|
986
1081
|
this.rules = [...this.rules, rule].sort(ruleOrder);
|
|
@@ -1005,6 +1100,11 @@ class GatewayTrustStoreAdapter implements TrustStoreBackend {
|
|
|
1005
1100
|
`Cannot update tool to internal pseudo-rule: ${updates.tool}`,
|
|
1006
1101
|
);
|
|
1007
1102
|
this.ensureInitialized();
|
|
1103
|
+
|
|
1104
|
+
// Send only the caller's partial updates to the gateway. The gateway's
|
|
1105
|
+
// own updateRule merges and canonicalizes via parseTrustRule, so doing a
|
|
1106
|
+
// full-rule merge here against the local cache would risk overwriting
|
|
1107
|
+
// concurrent edits with stale cached values.
|
|
1008
1108
|
const rule = trustClient.updateRuleSync(id, updates);
|
|
1009
1109
|
// Update local cache
|
|
1010
1110
|
const idx = this.rules.findIndex((r) => r.id === id);
|
|
@@ -1139,7 +1239,6 @@ export function addRule(
|
|
|
1139
1239
|
decision: "allow" | "deny" | "ask" = "allow",
|
|
1140
1240
|
priority: number = 100,
|
|
1141
1241
|
options?: {
|
|
1142
|
-
allowHighRisk?: boolean;
|
|
1143
1242
|
executionTarget?: string;
|
|
1144
1243
|
},
|
|
1145
1244
|
): TrustRule {
|
package/src/permissions/types.ts
CHANGED
|
@@ -1,27 +1,30 @@
|
|
|
1
|
+
import type { TrustRuleBase } from "@vellumai/ces-contracts";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Re-exported TrustRule type from `@vellumai/ces-contracts`.
|
|
5
|
+
*
|
|
6
|
+
* The contracts package defines `TrustRule` as a discriminated union over tool
|
|
7
|
+
* families (scoped, URL, managed-skill, skill-load, generic). Some variants
|
|
8
|
+
* don't carry `executionTarget`. To maintain backward
|
|
9
|
+
* compatibility with existing callsites that access those fields on any rule,
|
|
10
|
+
* we flatten the union here by intersecting the base with the optional fields.
|
|
11
|
+
*/
|
|
12
|
+
export type TrustRule = TrustRuleBase & {
|
|
13
|
+
scope?: string;
|
|
14
|
+
executionTarget?: string;
|
|
15
|
+
};
|
|
16
|
+
|
|
1
17
|
export enum RiskLevel {
|
|
2
18
|
Low = "low",
|
|
3
19
|
Medium = "medium",
|
|
4
20
|
High = "high",
|
|
5
21
|
}
|
|
6
22
|
|
|
7
|
-
export interface TrustRule {
|
|
8
|
-
id: string;
|
|
9
|
-
tool: string;
|
|
10
|
-
pattern: string;
|
|
11
|
-
scope: string;
|
|
12
|
-
decision: "allow" | "deny" | "ask";
|
|
13
|
-
priority: number;
|
|
14
|
-
createdAt: number;
|
|
15
|
-
executionTarget?: string;
|
|
16
|
-
allowHighRisk?: boolean;
|
|
17
|
-
}
|
|
18
|
-
|
|
19
23
|
export type UserDecision =
|
|
20
24
|
| "allow"
|
|
21
25
|
| "allow_10m"
|
|
22
26
|
| "allow_conversation"
|
|
23
27
|
| "always_allow"
|
|
24
|
-
| "always_allow_high_risk"
|
|
25
28
|
| "deny"
|
|
26
29
|
| "always_deny"
|
|
27
30
|
| "temporary_override";
|
|
@@ -33,7 +36,6 @@ export function isAllowDecision(decision: UserDecision): boolean {
|
|
|
33
36
|
decision === "allow_10m" ||
|
|
34
37
|
decision === "allow_conversation" ||
|
|
35
38
|
decision === "always_allow" ||
|
|
36
|
-
decision === "always_allow_high_risk" ||
|
|
37
39
|
decision === "temporary_override"
|
|
38
40
|
);
|
|
39
41
|
}
|
|
@@ -60,4 +62,11 @@ export interface PolicyContext {
|
|
|
60
62
|
executionTarget?: string;
|
|
61
63
|
/** Ephemeral rules for task-scoped permissions — checked before persistent trust.json rules. */
|
|
62
64
|
ephemeralRules?: TrustRule[];
|
|
65
|
+
/**
|
|
66
|
+
* Execution context for per-context threshold resolution.
|
|
67
|
+
* - "conversation": interactive client session (default)
|
|
68
|
+
* - "background": non-interactive guardian session (e.g. scheduled jobs)
|
|
69
|
+
* - "headless": non-interactive non-guardian session
|
|
70
|
+
*/
|
|
71
|
+
executionContext?: "conversation" | "background" | "headless";
|
|
63
72
|
}
|
|
@@ -0,0 +1,170 @@
|
|
|
1
|
+
import { describe, expect, test } from "bun:test";
|
|
2
|
+
|
|
3
|
+
import { WebRiskClassifier } from "./web-risk-classifier.js";
|
|
4
|
+
|
|
5
|
+
// ── Helper ───────────────────────────────────────────────────────────────────
|
|
6
|
+
|
|
7
|
+
function makeClassifier(): WebRiskClassifier {
|
|
8
|
+
return new WebRiskClassifier();
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
// ── web_search ───────────────────────────────────────────────────────────────
|
|
12
|
+
|
|
13
|
+
describe("web_search", () => {
|
|
14
|
+
test("always classified as low risk", async () => {
|
|
15
|
+
const classifier = makeClassifier();
|
|
16
|
+
const result = await classifier.classify({
|
|
17
|
+
toolName: "web_search",
|
|
18
|
+
});
|
|
19
|
+
expect(result.riskLevel).toBe("low");
|
|
20
|
+
expect(result.reason).toBe("Web search (read-only)");
|
|
21
|
+
expect(result.matchType).toBe("registry");
|
|
22
|
+
expect(result.scopeOptions).toEqual([]);
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
test("low risk even with url provided", async () => {
|
|
26
|
+
const classifier = makeClassifier();
|
|
27
|
+
const result = await classifier.classify({
|
|
28
|
+
toolName: "web_search",
|
|
29
|
+
url: "https://example.com",
|
|
30
|
+
});
|
|
31
|
+
expect(result.riskLevel).toBe("low");
|
|
32
|
+
});
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
// ── web_fetch ────────────────────────────────────────────────────────────────
|
|
36
|
+
|
|
37
|
+
describe("web_fetch", () => {
|
|
38
|
+
test("default (no private network) is low risk", async () => {
|
|
39
|
+
const classifier = makeClassifier();
|
|
40
|
+
const result = await classifier.classify({
|
|
41
|
+
toolName: "web_fetch",
|
|
42
|
+
});
|
|
43
|
+
expect(result.riskLevel).toBe("low");
|
|
44
|
+
expect(result.reason).toBe("Web fetch (default)");
|
|
45
|
+
expect(result.matchType).toBe("registry");
|
|
46
|
+
expect(result.scopeOptions).toEqual([]);
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
test("allowPrivateNetwork=false is low risk", async () => {
|
|
50
|
+
const classifier = makeClassifier();
|
|
51
|
+
const result = await classifier.classify({
|
|
52
|
+
toolName: "web_fetch",
|
|
53
|
+
allowPrivateNetwork: false,
|
|
54
|
+
});
|
|
55
|
+
expect(result.riskLevel).toBe("low");
|
|
56
|
+
expect(result.reason).toBe("Web fetch (default)");
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
test("allowPrivateNetwork=undefined is low risk", async () => {
|
|
60
|
+
const classifier = makeClassifier();
|
|
61
|
+
const result = await classifier.classify({
|
|
62
|
+
toolName: "web_fetch",
|
|
63
|
+
allowPrivateNetwork: undefined,
|
|
64
|
+
});
|
|
65
|
+
expect(result.riskLevel).toBe("low");
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
test("allowPrivateNetwork=true is high risk", async () => {
|
|
69
|
+
const classifier = makeClassifier();
|
|
70
|
+
const result = await classifier.classify({
|
|
71
|
+
toolName: "web_fetch",
|
|
72
|
+
allowPrivateNetwork: true,
|
|
73
|
+
});
|
|
74
|
+
expect(result.riskLevel).toBe("high");
|
|
75
|
+
expect(result.reason).toBe("Private network fetch");
|
|
76
|
+
expect(result.matchType).toBe("registry");
|
|
77
|
+
expect(result.scopeOptions).toEqual([]);
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
test("private network fetch with url", async () => {
|
|
81
|
+
const classifier = makeClassifier();
|
|
82
|
+
const result = await classifier.classify({
|
|
83
|
+
toolName: "web_fetch",
|
|
84
|
+
url: "http://192.168.1.1/admin",
|
|
85
|
+
allowPrivateNetwork: true,
|
|
86
|
+
});
|
|
87
|
+
expect(result.riskLevel).toBe("high");
|
|
88
|
+
expect(result.reason).toBe("Private network fetch");
|
|
89
|
+
});
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
// ── network_request ──────────────────────────────────────────────────────────
|
|
93
|
+
|
|
94
|
+
describe("network_request", () => {
|
|
95
|
+
test("always classified as medium risk", async () => {
|
|
96
|
+
const classifier = makeClassifier();
|
|
97
|
+
const result = await classifier.classify({
|
|
98
|
+
toolName: "network_request",
|
|
99
|
+
});
|
|
100
|
+
expect(result.riskLevel).toBe("medium");
|
|
101
|
+
expect(result.reason).toBe("Network request (proxied credentials)");
|
|
102
|
+
expect(result.matchType).toBe("registry");
|
|
103
|
+
expect(result.scopeOptions).toEqual([]);
|
|
104
|
+
});
|
|
105
|
+
|
|
106
|
+
test("medium risk with url provided", async () => {
|
|
107
|
+
const classifier = makeClassifier();
|
|
108
|
+
const result = await classifier.classify({
|
|
109
|
+
toolName: "network_request",
|
|
110
|
+
url: "https://api.example.com/data",
|
|
111
|
+
});
|
|
112
|
+
expect(result.riskLevel).toBe("medium");
|
|
113
|
+
});
|
|
114
|
+
|
|
115
|
+
test("medium risk regardless of allowPrivateNetwork flag", async () => {
|
|
116
|
+
const classifier = makeClassifier();
|
|
117
|
+
const result = await classifier.classify({
|
|
118
|
+
toolName: "network_request",
|
|
119
|
+
allowPrivateNetwork: true,
|
|
120
|
+
});
|
|
121
|
+
expect(result.riskLevel).toBe("medium");
|
|
122
|
+
expect(result.reason).toBe("Network request (proxied credentials)");
|
|
123
|
+
});
|
|
124
|
+
});
|
|
125
|
+
|
|
126
|
+
// ── Allowlist options ────────────────────────────────────────────────────────
|
|
127
|
+
// The web classifier intentionally does NOT produce allowlistOptions.
|
|
128
|
+
// URL normalization for scope options is handled by the canonical
|
|
129
|
+
// urlAllowlistStrategy in checker.ts (avoids circular import + divergent
|
|
130
|
+
// normalization). These tests verify the classifier omits them.
|
|
131
|
+
|
|
132
|
+
describe("allowlistOptions", () => {
|
|
133
|
+
test("web_fetch omits allowlistOptions (defers to canonical urlAllowlistStrategy)", async () => {
|
|
134
|
+
const classifier = makeClassifier();
|
|
135
|
+
const result = await classifier.classify({
|
|
136
|
+
toolName: "web_fetch",
|
|
137
|
+
url: "https://example.com/api/data?key=value",
|
|
138
|
+
});
|
|
139
|
+
expect(result.allowlistOptions).toBeUndefined();
|
|
140
|
+
});
|
|
141
|
+
|
|
142
|
+
test("network_request omits allowlistOptions", async () => {
|
|
143
|
+
const classifier = makeClassifier();
|
|
144
|
+
const result = await classifier.classify({
|
|
145
|
+
toolName: "network_request",
|
|
146
|
+
url: "https://api.example.com/v1/users",
|
|
147
|
+
});
|
|
148
|
+
expect(result.allowlistOptions).toBeUndefined();
|
|
149
|
+
});
|
|
150
|
+
|
|
151
|
+
test("web_search omits allowlistOptions", async () => {
|
|
152
|
+
const classifier = makeClassifier();
|
|
153
|
+
const result = await classifier.classify({
|
|
154
|
+
toolName: "web_search",
|
|
155
|
+
});
|
|
156
|
+
expect(result.allowlistOptions).toBeUndefined();
|
|
157
|
+
});
|
|
158
|
+
});
|
|
159
|
+
|
|
160
|
+
// ── Singleton ────────────────────────────────────────────────────────────────
|
|
161
|
+
|
|
162
|
+
describe("singleton", () => {
|
|
163
|
+
test("webRiskClassifier is exported and functional", async () => {
|
|
164
|
+
const { webRiskClassifier } = await import("./web-risk-classifier.js");
|
|
165
|
+
const result = await webRiskClassifier.classify({
|
|
166
|
+
toolName: "web_search",
|
|
167
|
+
});
|
|
168
|
+
expect(result.riskLevel).toBe("low");
|
|
169
|
+
});
|
|
170
|
+
});
|