@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
|
@@ -0,0 +1,274 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* File risk classifier — path-based risk classification for file tools.
|
|
3
|
+
*
|
|
4
|
+
* Implements RiskClassifier<FileClassifierInput> for all six file tool types:
|
|
5
|
+
* file_read, file_write, file_edit, host_file_read, host_file_write, host_file_edit.
|
|
6
|
+
*
|
|
7
|
+
* Risk escalation paths:
|
|
8
|
+
* - file_read: Low by default, High if targeting the actor token signing key.
|
|
9
|
+
* - file_write / file_edit: Low by default, High if targeting skill source
|
|
10
|
+
* code or the workspace hooks directory.
|
|
11
|
+
* - host_file_read: Medium (tool registry default; no special escalation).
|
|
12
|
+
* - host_file_write / host_file_edit: Medium by default, High if targeting
|
|
13
|
+
* skill source code or the workspace hooks directory.
|
|
14
|
+
*/
|
|
15
|
+
|
|
16
|
+
import { homedir } from "node:os";
|
|
17
|
+
import { dirname, join, resolve } from "node:path";
|
|
18
|
+
|
|
19
|
+
import { getConfig } from "../config/loader.js";
|
|
20
|
+
import {
|
|
21
|
+
isSkillSourcePath,
|
|
22
|
+
normalizeDirPath,
|
|
23
|
+
normalizeFilePath,
|
|
24
|
+
} from "../skills/path-classifier.js";
|
|
25
|
+
import {
|
|
26
|
+
getDeprecatedDir,
|
|
27
|
+
getProtectedDir,
|
|
28
|
+
getWorkspaceHooksDir,
|
|
29
|
+
} from "../util/platform.js";
|
|
30
|
+
import type { RiskAssessment, RiskClassifier } from "./risk-types.js";
|
|
31
|
+
import type { AllowlistOption } from "./types.js";
|
|
32
|
+
|
|
33
|
+
// ── Input type ───────────────────────────────────────────────────────────────
|
|
34
|
+
|
|
35
|
+
/** Input to the file risk classifier. */
|
|
36
|
+
export interface FileClassifierInput {
|
|
37
|
+
toolName:
|
|
38
|
+
| "file_read"
|
|
39
|
+
| "file_write"
|
|
40
|
+
| "file_edit"
|
|
41
|
+
| "host_file_read"
|
|
42
|
+
| "host_file_write"
|
|
43
|
+
| "host_file_edit";
|
|
44
|
+
filePath: string;
|
|
45
|
+
workingDir: string;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
// ── Helpers ──────────────────────────────────────────────────────────────────
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* Check whether a resolved absolute path targets the actor token signing key.
|
|
52
|
+
* Covers both the per-instance protected dir, the legacy global path, and
|
|
53
|
+
* a relative "deprecated/actor-token-signing-key" resolved against workingDir.
|
|
54
|
+
*/
|
|
55
|
+
function isActorTokenSigningKeyPath(
|
|
56
|
+
resolvedPath: string,
|
|
57
|
+
workingDir: string,
|
|
58
|
+
): boolean {
|
|
59
|
+
const signingKeyPaths = Array.from(
|
|
60
|
+
new Set([
|
|
61
|
+
join(homedir(), ".vellum", "protected", "actor-token-signing-key"),
|
|
62
|
+
join(getProtectedDir(), "actor-token-signing-key"),
|
|
63
|
+
join(getDeprecatedDir(), "actor-token-signing-key"),
|
|
64
|
+
resolve(workingDir, "deprecated", "actor-token-signing-key"),
|
|
65
|
+
]),
|
|
66
|
+
);
|
|
67
|
+
return signingKeyPaths.includes(resolvedPath);
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* Check whether a resolved absolute path falls inside the workspace hooks
|
|
72
|
+
* directory (or IS the hooks directory itself).
|
|
73
|
+
*/
|
|
74
|
+
function isHooksPath(resolvedPath: string): boolean {
|
|
75
|
+
const normalizedHooksDir = normalizeDirPath(getWorkspaceHooksDir());
|
|
76
|
+
const normalizedPath = normalizeFilePath(resolvedPath);
|
|
77
|
+
const hooksDirNoTrailingSlash = normalizedHooksDir.slice(0, -1);
|
|
78
|
+
return (
|
|
79
|
+
normalizedPath === hooksDirNoTrailingSlash ||
|
|
80
|
+
normalizedPath.startsWith(normalizedHooksDir)
|
|
81
|
+
);
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
// ── Allowlist option helpers ──────────────────────────────────────────────────
|
|
85
|
+
|
|
86
|
+
const FILE_TOOL_DISPLAY_NAMES: Record<string, string> = {
|
|
87
|
+
file_read: "file reads",
|
|
88
|
+
file_write: "file writes",
|
|
89
|
+
file_edit: "file edits",
|
|
90
|
+
host_file_read: "host file reads",
|
|
91
|
+
host_file_write: "host file writes",
|
|
92
|
+
host_file_edit: "host file edits",
|
|
93
|
+
};
|
|
94
|
+
|
|
95
|
+
function friendlyBasename(filePath: string): string {
|
|
96
|
+
const parts = filePath.split("/");
|
|
97
|
+
return parts[parts.length - 1] || filePath;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
/**
|
|
101
|
+
* Build allowlist options for a file tool invocation, mirroring the logic
|
|
102
|
+
* in checker.ts `fileAllowlistStrategy()`. Options go from most specific
|
|
103
|
+
* (exact file) to broadest (all operations of this tool type).
|
|
104
|
+
*/
|
|
105
|
+
function buildFileAllowlistOptions(
|
|
106
|
+
toolName: string,
|
|
107
|
+
filePath: string,
|
|
108
|
+
): AllowlistOption[] {
|
|
109
|
+
const toolLabel = FILE_TOOL_DISPLAY_NAMES[toolName] ?? toolName;
|
|
110
|
+
const options: AllowlistOption[] = [];
|
|
111
|
+
|
|
112
|
+
// Exact file path
|
|
113
|
+
options.push({
|
|
114
|
+
label: filePath,
|
|
115
|
+
description: "This file only",
|
|
116
|
+
pattern: `${toolName}:${filePath}`,
|
|
117
|
+
});
|
|
118
|
+
|
|
119
|
+
// Ancestor directory wildcards — walk up from immediate parent, stop at home dir or /
|
|
120
|
+
const home = homedir();
|
|
121
|
+
let dir = dirname(filePath);
|
|
122
|
+
const maxLevels = 3;
|
|
123
|
+
let levels = 0;
|
|
124
|
+
while (dir && dir !== "/" && dir !== "." && levels < maxLevels) {
|
|
125
|
+
const dirName = friendlyBasename(dir);
|
|
126
|
+
options.push({
|
|
127
|
+
label: `${dir}/**`,
|
|
128
|
+
description: `Anything in ${dirName}/`,
|
|
129
|
+
pattern: `${toolName}:${dir}/**`,
|
|
130
|
+
});
|
|
131
|
+
if (dir === home) break;
|
|
132
|
+
const parent = dirname(dir);
|
|
133
|
+
if (parent === dir) break;
|
|
134
|
+
dir = parent;
|
|
135
|
+
levels++;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
// All operations of this tool type
|
|
139
|
+
options.push({
|
|
140
|
+
label: `${toolName}:*`,
|
|
141
|
+
description: `All ${toolLabel}`,
|
|
142
|
+
pattern: `${toolName}:*`,
|
|
143
|
+
});
|
|
144
|
+
|
|
145
|
+
return options;
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
// ── Classifier ───────────────────────────────────────────────────────────────
|
|
149
|
+
|
|
150
|
+
/**
|
|
151
|
+
* File risk classifier implementation.
|
|
152
|
+
*
|
|
153
|
+
* Classifies all six file tool types by risk level, with escalation paths
|
|
154
|
+
* for skill source code, workspace hooks, and the actor token signing key.
|
|
155
|
+
*/
|
|
156
|
+
export class FileRiskClassifier implements RiskClassifier<FileClassifierInput> {
|
|
157
|
+
async classify(input: FileClassifierInput): Promise<RiskAssessment> {
|
|
158
|
+
const { toolName, filePath, workingDir } = input;
|
|
159
|
+
const allowlistOptions = filePath
|
|
160
|
+
? buildFileAllowlistOptions(toolName, filePath)
|
|
161
|
+
: [];
|
|
162
|
+
|
|
163
|
+
switch (toolName) {
|
|
164
|
+
case "file_read": {
|
|
165
|
+
if (filePath) {
|
|
166
|
+
const resolvedPath = resolve(workingDir, filePath);
|
|
167
|
+
if (isActorTokenSigningKeyPath(resolvedPath, workingDir)) {
|
|
168
|
+
return {
|
|
169
|
+
riskLevel: "high",
|
|
170
|
+
reason: "Reads actor token signing key",
|
|
171
|
+
scopeOptions: [],
|
|
172
|
+
matchType: "registry",
|
|
173
|
+
allowlistOptions,
|
|
174
|
+
};
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
return {
|
|
178
|
+
riskLevel: "low",
|
|
179
|
+
reason: "File read (default)",
|
|
180
|
+
scopeOptions: [],
|
|
181
|
+
matchType: "registry",
|
|
182
|
+
allowlistOptions,
|
|
183
|
+
};
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
case "file_write":
|
|
187
|
+
case "file_edit": {
|
|
188
|
+
if (filePath) {
|
|
189
|
+
const resolvedPath = resolve(workingDir, filePath);
|
|
190
|
+
if (
|
|
191
|
+
isSkillSourcePath(resolvedPath, getConfig().skills.load.extraDirs)
|
|
192
|
+
) {
|
|
193
|
+
return {
|
|
194
|
+
riskLevel: "high",
|
|
195
|
+
reason: "Writes to skill source code",
|
|
196
|
+
scopeOptions: [],
|
|
197
|
+
matchType: "registry",
|
|
198
|
+
allowlistOptions,
|
|
199
|
+
};
|
|
200
|
+
}
|
|
201
|
+
if (isHooksPath(resolvedPath)) {
|
|
202
|
+
return {
|
|
203
|
+
riskLevel: "high",
|
|
204
|
+
reason: "Writes to hooks directory",
|
|
205
|
+
scopeOptions: [],
|
|
206
|
+
matchType: "registry",
|
|
207
|
+
allowlistOptions,
|
|
208
|
+
};
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
return {
|
|
212
|
+
riskLevel: "low",
|
|
213
|
+
reason: `File ${toolName === "file_write" ? "write" : "edit"} (default)`,
|
|
214
|
+
scopeOptions: [],
|
|
215
|
+
matchType: "registry",
|
|
216
|
+
allowlistOptions,
|
|
217
|
+
};
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
case "host_file_read": {
|
|
221
|
+
// host_file_read has no special escalation paths — the tool registry
|
|
222
|
+
// declares it as Medium risk, and classifyRiskFromRegistry falls through
|
|
223
|
+
// to getTool() which returns that default.
|
|
224
|
+
return {
|
|
225
|
+
riskLevel: "medium",
|
|
226
|
+
reason: "Host file read (default)",
|
|
227
|
+
scopeOptions: [],
|
|
228
|
+
matchType: "registry",
|
|
229
|
+
allowlistOptions,
|
|
230
|
+
};
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
case "host_file_write":
|
|
234
|
+
case "host_file_edit": {
|
|
235
|
+
if (filePath) {
|
|
236
|
+
// Host file tools resolve paths without workingDir — resolve(filePath)
|
|
237
|
+
// treats the path as absolute or relative to cwd.
|
|
238
|
+
const resolvedPath = resolve(filePath);
|
|
239
|
+
if (
|
|
240
|
+
isSkillSourcePath(resolvedPath, getConfig().skills.load.extraDirs)
|
|
241
|
+
) {
|
|
242
|
+
return {
|
|
243
|
+
riskLevel: "high",
|
|
244
|
+
reason: "Writes to skill source code",
|
|
245
|
+
scopeOptions: [],
|
|
246
|
+
matchType: "registry",
|
|
247
|
+
allowlistOptions,
|
|
248
|
+
};
|
|
249
|
+
}
|
|
250
|
+
if (isHooksPath(resolvedPath)) {
|
|
251
|
+
return {
|
|
252
|
+
riskLevel: "high",
|
|
253
|
+
reason: "Writes to hooks directory",
|
|
254
|
+
scopeOptions: [],
|
|
255
|
+
matchType: "registry",
|
|
256
|
+
allowlistOptions,
|
|
257
|
+
};
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
// Fall through to tool registry default (Medium).
|
|
261
|
+
return {
|
|
262
|
+
riskLevel: "medium",
|
|
263
|
+
reason: `Host file ${toolName === "host_file_write" ? "write" : "edit"} (default)`,
|
|
264
|
+
scopeOptions: [],
|
|
265
|
+
matchType: "registry",
|
|
266
|
+
allowlistOptions,
|
|
267
|
+
};
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
/** Singleton classifier instance. */
|
|
274
|
+
export const fileRiskClassifier = new FileRiskClassifier();
|
|
@@ -0,0 +1,205 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Types for the data-driven command risk classifier.
|
|
3
|
+
*
|
|
4
|
+
* All types are JSON-serializable — no native RegExp, no function references.
|
|
5
|
+
* Regex patterns are stored as strings (use `String.raw` for ergonomics in TS).
|
|
6
|
+
* This constraint exists because the registry will eventually be persisted to a
|
|
7
|
+
* DB with per-user/per-org overrides that need to round-trip cleanly.
|
|
8
|
+
*
|
|
9
|
+
* @see /docs/bash-risk-classifier-design.md
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
import { type AllowlistOption, RiskLevel } from "./types.js";
|
|
13
|
+
|
|
14
|
+
// ── Risk levels ──────────────────────────────────────────────────────────────
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Risk level for a classified command or tool invocation.
|
|
18
|
+
*
|
|
19
|
+
* - `"low"`: Read-only, no side effects (auto-allow in most policies)
|
|
20
|
+
* - `"medium"`: Writes to filesystem, network access, state changes (confirm)
|
|
21
|
+
* - `"high"`: Destructive, privilege escalation, force ops, arbitrary code exec
|
|
22
|
+
* - `"unknown"`: Not in registry, unrecognized command or arg pattern
|
|
23
|
+
*/
|
|
24
|
+
export type Risk = "low" | "medium" | "high" | "unknown";
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Risk levels that can be assigned to commands in the registry.
|
|
28
|
+
* Excludes "unknown" — that's a classifier output, not a registry value.
|
|
29
|
+
*/
|
|
30
|
+
export type RegistryRisk = "low" | "medium" | "high";
|
|
31
|
+
|
|
32
|
+
// ── Risk assessment output ───────────────────────────────────────────────────
|
|
33
|
+
|
|
34
|
+
/** A scope option presented to the user when classifying an unknown command. */
|
|
35
|
+
export interface ScopeOption {
|
|
36
|
+
/** Stored in DB if user saves (always regex internally). */
|
|
37
|
+
pattern: string;
|
|
38
|
+
/** Human-readable description shown in UI. */
|
|
39
|
+
label: string;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* The output of a risk classifier. Tool-agnostic — every classifier
|
|
44
|
+
* (bash, file_write, web_fetch, etc.) produces this same shape.
|
|
45
|
+
*/
|
|
46
|
+
export interface RiskAssessment {
|
|
47
|
+
/** Computed risk level. */
|
|
48
|
+
riskLevel: Risk;
|
|
49
|
+
/** Human-readable explanation of why this risk level was assigned. */
|
|
50
|
+
reason: string;
|
|
51
|
+
/** Scope options for the "save this classification" UI, narrowest to broadest. */
|
|
52
|
+
scopeOptions: ScopeOption[];
|
|
53
|
+
/** How the risk was determined. */
|
|
54
|
+
matchType: "user_rule" | "registry" | "unknown";
|
|
55
|
+
/**
|
|
56
|
+
* Allowlist options for the permission prompt "always allow" scope ladder.
|
|
57
|
+
* Populated by classifiers that unify risk classification and scope option
|
|
58
|
+
* generation. When present, `generateAllowlistOptions()` returns these
|
|
59
|
+
* directly instead of calling the per-tool strategy function.
|
|
60
|
+
*/
|
|
61
|
+
allowlistOptions?: AllowlistOption[];
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
// ── Classifier interface ─────────────────────────────────────────────────────
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* Generic risk classifier interface. Each tool type (bash, file_write, etc.)
|
|
68
|
+
* implements this with a tool-specific input type.
|
|
69
|
+
*/
|
|
70
|
+
export interface RiskClassifier<TInput> {
|
|
71
|
+
classify(input: TInput): Promise<RiskAssessment>;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
// ── Bash classifier input ────────────────────────────────────────────────────
|
|
75
|
+
|
|
76
|
+
/** Input to the bash risk classifier. */
|
|
77
|
+
export interface BashClassifierInput {
|
|
78
|
+
/** The raw command string. */
|
|
79
|
+
command: string;
|
|
80
|
+
/** Which tool is being invoked. */
|
|
81
|
+
toolName: "bash" | "host_bash";
|
|
82
|
+
/** Working directory (for path resolution in arg rules). */
|
|
83
|
+
workingDir?: string;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
// ── Command registry types ───────────────────────────────────────────────────
|
|
87
|
+
|
|
88
|
+
/**
|
|
89
|
+
* A single arg-level risk rule within a command spec.
|
|
90
|
+
*
|
|
91
|
+
* Evaluated per arg token. If `flags` is set, the rule only fires when the
|
|
92
|
+
* arg matches one of those flags. If `valuePattern` is set, the arg (or the
|
|
93
|
+
* flag's consumed value) must match the regex.
|
|
94
|
+
*/
|
|
95
|
+
export interface ArgRule {
|
|
96
|
+
/**
|
|
97
|
+
* Stable ID for DB references, partial overrides, and audit trails.
|
|
98
|
+
* Convention: `"command:descriptor"` (e.g. `"curl:upload-file"`, `"rm:recursive-force"`).
|
|
99
|
+
*/
|
|
100
|
+
id: string;
|
|
101
|
+
/**
|
|
102
|
+
* Flag(s) that trigger this rule. Omit for positional/any-arg matching.
|
|
103
|
+
* Combined short flags are listed as literals (e.g. `"-rf"`, `"-fr"`).
|
|
104
|
+
*/
|
|
105
|
+
flags?: string[];
|
|
106
|
+
/**
|
|
107
|
+
* Regex string matched against the arg value. Omit if flag presence alone
|
|
108
|
+
* triggers the rule. Stored as a string (not a native RegExp) for JSON
|
|
109
|
+
* serialization.
|
|
110
|
+
*/
|
|
111
|
+
valuePattern?: string;
|
|
112
|
+
/** Risk level when this rule fires. */
|
|
113
|
+
risk: RegistryRisk;
|
|
114
|
+
/** Human-readable reason (shown in permission prompt). */
|
|
115
|
+
reason: string;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
/**
|
|
119
|
+
* Risk specification for a single command (or subcommand).
|
|
120
|
+
*
|
|
121
|
+
* The registry is a `Record<string, CommandRiskSpec>` mapping program names
|
|
122
|
+
* to their specs. Subcommands nest recursively.
|
|
123
|
+
*/
|
|
124
|
+
export interface CommandRiskSpec {
|
|
125
|
+
/** Base risk when no arg rules match. */
|
|
126
|
+
baseRisk: RegistryRisk;
|
|
127
|
+
/**
|
|
128
|
+
* Subcommand-level overrides. Keys are subcommand names
|
|
129
|
+
* (e.g. `{ push: { baseRisk: "medium", ... } }` under `git`).
|
|
130
|
+
* Subcommands can nest further (e.g. `git stash drop`).
|
|
131
|
+
*/
|
|
132
|
+
subcommands?: Record<string, CommandRiskSpec>;
|
|
133
|
+
/** Arg-level rules, evaluated per arg. First match per arg wins. */
|
|
134
|
+
argRules?: ArgRule[];
|
|
135
|
+
/**
|
|
136
|
+
* Is this a wrapper command? (sudo, env, nice, etc.)
|
|
137
|
+
* When true, the classifier unwraps to find the inner command and
|
|
138
|
+
* takes the max of the wrapper's baseRisk and the inner command's risk.
|
|
139
|
+
*/
|
|
140
|
+
isWrapper?: boolean;
|
|
141
|
+
/**
|
|
142
|
+
* Flags that put a wrapper into a non-exec mode (e.g. command -v, env -0).
|
|
143
|
+
* When the first arg matches a non-exec flag, skip unwrapping and classify
|
|
144
|
+
* the wrapper standalone against its own arg rules.
|
|
145
|
+
*/
|
|
146
|
+
nonExecFlags?: string[];
|
|
147
|
+
/**
|
|
148
|
+
* Does this command have non-standard syntax where intermediate scope
|
|
149
|
+
* options would be confusing? (find, xargs, awk, etc.)
|
|
150
|
+
* When true, the scope ladder only offers exact match and command-level wildcard.
|
|
151
|
+
*/
|
|
152
|
+
complexSyntax?: boolean;
|
|
153
|
+
/** Human-readable reason for the base risk (shown when no arg rule matches). */
|
|
154
|
+
reason?: string;
|
|
155
|
+
/**
|
|
156
|
+
* Global flags that consume the next token as a value (e.g. git -C <path>).
|
|
157
|
+
* Used by resolveSubcommand to skip past flag-value pairs when locating the
|
|
158
|
+
* first positional arg (the subcommand name).
|
|
159
|
+
*/
|
|
160
|
+
globalValueFlags?: string[];
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
// ── User rule types ──────────────────────────────────────────────────────────
|
|
164
|
+
|
|
165
|
+
/**
|
|
166
|
+
* A user-created risk classification rule.
|
|
167
|
+
*
|
|
168
|
+
* Created via the scope ladder UI (from permission prompts) or manually
|
|
169
|
+
* in settings. Stored in the user's DB.
|
|
170
|
+
*/
|
|
171
|
+
export interface UserRule {
|
|
172
|
+
/** Auto-generated unique ID. */
|
|
173
|
+
id: string;
|
|
174
|
+
/** Regex pattern (converted from glob at creation time). */
|
|
175
|
+
pattern: string;
|
|
176
|
+
/** User-assigned risk level. */
|
|
177
|
+
risk: RegistryRisk;
|
|
178
|
+
/** Human-readable label (shown in settings UI). */
|
|
179
|
+
label: string;
|
|
180
|
+
/** ISO 8601 timestamp of when the rule was created. */
|
|
181
|
+
createdAt: string;
|
|
182
|
+
/** How the rule was created. */
|
|
183
|
+
source: "scope_ladder" | "manual";
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
// ── Risk → RiskLevel mapping ─────────────────────────────────────────────────
|
|
187
|
+
|
|
188
|
+
/**
|
|
189
|
+
* Map a classifier `Risk` value to the permission system's `RiskLevel` enum.
|
|
190
|
+
*
|
|
191
|
+
* `"unknown"` maps to `RiskLevel.Medium` — matching the existing checker.ts
|
|
192
|
+
* behavior where unrecognized commands are treated as medium-risk.
|
|
193
|
+
*/
|
|
194
|
+
export function riskToRiskLevel(risk: Risk): RiskLevel {
|
|
195
|
+
switch (risk) {
|
|
196
|
+
case "low":
|
|
197
|
+
return RiskLevel.Low;
|
|
198
|
+
case "medium":
|
|
199
|
+
return RiskLevel.Medium;
|
|
200
|
+
case "high":
|
|
201
|
+
return RiskLevel.High;
|
|
202
|
+
case "unknown":
|
|
203
|
+
return RiskLevel.Medium;
|
|
204
|
+
}
|
|
205
|
+
}
|
|
@@ -14,6 +14,8 @@ export type SecretDelivery = "store" | "transient_send";
|
|
|
14
14
|
export interface SecretPromptResult {
|
|
15
15
|
value: string | null;
|
|
16
16
|
delivery: SecretDelivery;
|
|
17
|
+
/** When set, the prompt could not be delivered and the value is null due to a delivery failure (not user cancellation). */
|
|
18
|
+
error?: "unsupported_channel";
|
|
17
19
|
}
|
|
18
20
|
|
|
19
21
|
interface PendingSecretPrompt {
|
|
@@ -22,21 +24,48 @@ interface PendingSecretPrompt {
|
|
|
22
24
|
timer: ReturnType<typeof setTimeout>;
|
|
23
25
|
}
|
|
24
26
|
|
|
27
|
+
export interface SecretPrompterChannelContext {
|
|
28
|
+
/** The channel the conversation was initiated from (e.g. "slack", "macos"). */
|
|
29
|
+
channel?: string;
|
|
30
|
+
/** Whether the channel supports rendering dynamic UI (secure prompt dialogs). */
|
|
31
|
+
supportsDynamicUi?: boolean;
|
|
32
|
+
}
|
|
33
|
+
|
|
25
34
|
export class SecretPrompter {
|
|
26
35
|
private pending = new Map<string, PendingSecretPrompt>();
|
|
27
36
|
private sendToClient: (msg: ServerMessage) => void;
|
|
37
|
+
private broadcastToAllClients?: (msg: ServerMessage) => void;
|
|
38
|
+
private channelContext?: SecretPrompterChannelContext;
|
|
28
39
|
|
|
29
|
-
constructor(
|
|
40
|
+
constructor(
|
|
41
|
+
sendToClient: (msg: ServerMessage) => void,
|
|
42
|
+
broadcastToAllClients?: (msg: ServerMessage) => void,
|
|
43
|
+
) {
|
|
30
44
|
this.sendToClient = sendToClient;
|
|
45
|
+
this.broadcastToAllClients = broadcastToAllClients;
|
|
31
46
|
}
|
|
32
47
|
|
|
33
48
|
updateSender(sendToClient: (msg: ServerMessage) => void): void {
|
|
34
49
|
this.sendToClient = sendToClient;
|
|
35
50
|
}
|
|
36
51
|
|
|
52
|
+
updateBroadcast(broadcastToAllClients?: (msg: ServerMessage) => void): void {
|
|
53
|
+
this.broadcastToAllClients = broadcastToAllClients;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
setChannelContext(ctx: SecretPrompterChannelContext | undefined): void {
|
|
57
|
+
this.channelContext = ctx;
|
|
58
|
+
}
|
|
59
|
+
|
|
37
60
|
/**
|
|
38
61
|
* Send a secret_request to the client and wait for the response.
|
|
39
62
|
*
|
|
63
|
+
* When the conversation originates from a channel that cannot render secure
|
|
64
|
+
* prompts (e.g. Slack), the request is broadcast to all connected clients
|
|
65
|
+
* via the SSE hub so the desktop app can display it. If no broadcast path
|
|
66
|
+
* is available and the channel doesn't support dynamic UI, the method
|
|
67
|
+
* fails fast with an error result rather than hanging until timeout.
|
|
68
|
+
*
|
|
40
69
|
* SECURITY: Logs only metadata (requestId, service, field) — never the
|
|
41
70
|
* returned secret value. The timeout path also returns a null value
|
|
42
71
|
* without logging anything sensitive.
|
|
@@ -52,6 +81,20 @@ export class SecretPrompter {
|
|
|
52
81
|
allowedTools?: string[],
|
|
53
82
|
allowedDomains?: string[],
|
|
54
83
|
): Promise<SecretPromptResult> {
|
|
84
|
+
// Determine whether the originating channel can render secure prompts.
|
|
85
|
+
const channelSupportsPrompt =
|
|
86
|
+
this.channelContext?.supportsDynamicUi !== false;
|
|
87
|
+
|
|
88
|
+
// If the channel cannot render the prompt and there's no broadcast path
|
|
89
|
+
// to reach a desktop client, fail fast instead of hanging for 5 minutes.
|
|
90
|
+
if (!channelSupportsPrompt && !this.broadcastToAllClients) {
|
|
91
|
+
log.warn(
|
|
92
|
+
{ service, field, channel: this.channelContext?.channel },
|
|
93
|
+
"Secret prompt requested from a channel that cannot render it and no broadcast path is available",
|
|
94
|
+
);
|
|
95
|
+
return { value: null, delivery: "store", error: "unsupported_channel" };
|
|
96
|
+
}
|
|
97
|
+
|
|
55
98
|
const requestId = uuid();
|
|
56
99
|
|
|
57
100
|
return new Promise((resolve, reject) => {
|
|
@@ -79,7 +122,15 @@ export class SecretPrompter {
|
|
|
79
122
|
allowedDomains,
|
|
80
123
|
allowOneTimeSend: config.secretDetection.allowOneTimeSend,
|
|
81
124
|
};
|
|
82
|
-
|
|
125
|
+
|
|
126
|
+
// Use broadcastToAllClients when the originating channel cannot render
|
|
127
|
+
// secure prompts — this routes the request to the SSE hub where a
|
|
128
|
+
// connected desktop client can pick it up.
|
|
129
|
+
if (!channelSupportsPrompt && this.broadcastToAllClients) {
|
|
130
|
+
this.broadcastToAllClients(msg);
|
|
131
|
+
} else {
|
|
132
|
+
this.sendToClient(msg);
|
|
133
|
+
}
|
|
83
134
|
});
|
|
84
135
|
}
|
|
85
136
|
|