@vellumai/assistant 0.6.3 → 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 +298 -39
- package/Dockerfile +14 -3
- package/README.md +3 -4
- package/bun.lock +13 -16
- package/docs/architecture/integrations.md +1 -20
- package/docs/architecture/security.md +16 -16
- package/docs/backup-troubleshooting.md +52 -0
- package/docs/browser-use-architecture-phase2.md +174 -0
- package/docs/error-handling.md +111 -0
- package/docs/skills.md +10 -10
- package/docs/stt-provider-onboarding.md +121 -0
- package/knip.json +20 -3
- package/node_modules/@vellumai/ces-contracts/bun.lock +8 -6
- package/node_modules/@vellumai/ces-contracts/package.json +5 -4
- 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 +1094 -72
- package/package.json +9 -8
- package/scripts/generate-openapi.ts +50 -12
- package/scripts/test.sh +73 -18
- package/src/__tests__/agent-image-optimize.test.ts +28 -0
- 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 +235 -1
- package/src/__tests__/anthropic-error-formatting.test.ts +98 -0
- package/src/__tests__/anthropic-provider.test.ts +434 -12
- 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__/auto-analysis-end-to-end.test.ts +550 -0
- package/src/__tests__/auto-analysis-prompt.test.ts +50 -0
- package/src/__tests__/browser-fill-credential.test.ts +12 -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 +52 -159
- package/src/__tests__/btw-routes.test.ts +54 -1
- package/src/__tests__/call-controller.test.ts +582 -22
- package/src/__tests__/call-site-routing-provider.test.ts +214 -0
- package/src/__tests__/catalog-cache.test.ts +27 -4
- package/src/__tests__/catalog-files.test.ts +138 -0
- package/src/__tests__/channel-approval-routes.test.ts +4 -4
- package/src/__tests__/channel-invite-transport.test.ts +2 -2
- package/src/__tests__/channel-readiness-routes.test.ts +16 -20
- package/src/__tests__/channel-readiness-service.test.ts +12 -7
- package/src/__tests__/channel-reply-delivery.test.ts +300 -2
- package/src/__tests__/checker.test.ts +576 -502
- package/src/__tests__/clawhub-files.test.ts +347 -0
- package/src/__tests__/cli-command-risk-guard.test.ts +30 -33
- package/src/__tests__/commit-message-enrichment-service.test.ts +36 -19
- 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 +83 -0
- 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 +1458 -198
- package/src/__tests__/config-watcher-cleanup-throttle.test.ts +339 -0
- package/src/__tests__/config-watcher.test.ts +45 -10
- package/src/__tests__/contact-store-user-file.test.ts +511 -0
- package/src/__tests__/contacts-write.test.ts +197 -0
- package/src/__tests__/context-token-estimator.test.ts +191 -1
- package/src/__tests__/context-window-manager.test.ts +618 -2
- package/src/__tests__/conversation-abort-tool-results.test.ts +32 -16
- package/src/__tests__/conversation-agent-loop-overflow.test.ts +62 -17
- package/src/__tests__/conversation-agent-loop.test.ts +510 -84
- package/src/__tests__/conversation-attachments.test.ts +1 -1
- package/src/__tests__/conversation-confirmation-signals.test.ts +165 -9
- package/src/__tests__/conversation-error.test.ts +102 -1
- package/src/__tests__/conversation-history-web-search.test.ts +17 -4
- package/src/__tests__/conversation-init.benchmark.test.ts +42 -1
- package/src/__tests__/conversation-launcher-skill-regression.test.ts +51 -0
- package/src/__tests__/conversation-lifecycle.test.ts +336 -0
- package/src/__tests__/conversation-list-source.test.ts +145 -0
- package/src/__tests__/conversation-load-history-repair.test.ts +27 -10
- package/src/__tests__/conversation-pre-run-repair.test.ts +32 -16
- package/src/__tests__/conversation-process-callsite.test.ts +306 -0
- package/src/__tests__/conversation-provider-retry-repair.test.ts +32 -16
- package/src/__tests__/conversation-queue.test.ts +932 -76
- package/src/__tests__/conversation-routes-disk-view.test.ts +299 -1
- package/src/__tests__/conversation-routes-slash-commands.test.ts +31 -3
- package/src/__tests__/conversation-runtime-assembly.test.ts +2790 -55
- package/src/__tests__/conversation-runtime-workspace.test.ts +12 -12
- package/src/__tests__/conversation-skill-tools.test.ts +12 -143
- package/src/__tests__/conversation-slash-commands.test.ts +33 -0
- package/src/__tests__/conversation-slash-queue.test.ts +120 -34
- package/src/__tests__/conversation-slash-unknown.test.ts +32 -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 +226 -0
- 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 +45 -15
- package/src/__tests__/conversation-workspace-tool-tracking.test.ts +46 -16
- package/src/__tests__/credential-broker-browser-fill.test.ts +110 -0
- package/src/__tests__/credential-health-service.test.ts +352 -0
- package/src/__tests__/credential-security-invariants.test.ts +8 -3
- 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 +495 -3
- package/src/__tests__/credentials-cli.test.ts +32 -16
- package/src/__tests__/cross-provider-web-search.test.ts +230 -35
- 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__/deterministic-verification-control-plane.test.ts +10 -1
- package/src/__tests__/device-id.test.ts +112 -0
- package/src/__tests__/dm-backfill.test.ts +417 -0
- package/src/__tests__/dm-persistence.test.ts +227 -0
- package/src/__tests__/docker-signing-key-bootstrap.test.ts +167 -4
- package/src/__tests__/dynamic-skill-workflow-prompt.test.ts +1 -3
- package/src/__tests__/edit-propagation.test.ts +280 -0
- package/src/__tests__/email-html-renderer.test.ts +71 -0
- package/src/__tests__/email-invite-adapter.test.ts +36 -32
- package/src/__tests__/emit-event-signal.test.ts +71 -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 +101 -15
- package/src/__tests__/file-write-tool.test.ts +151 -1
- package/src/__tests__/filing-service.test.ts +255 -0
- package/src/__tests__/fixtures/mock-chrome-extension.ts +11 -0
- package/src/__tests__/gateway-only-enforcement.test.ts +206 -1
- package/src/__tests__/gateway-only-guard.test.ts +0 -1
- package/src/__tests__/gemini-provider.test.ts +64 -3
- package/src/__tests__/get-skill-detail-audit.test.ts +325 -0
- package/src/__tests__/guardian-grant-minting.test.ts +8 -0
- package/src/__tests__/headless-browser-interactions.test.ts +44 -1
- package/src/__tests__/headless-browser-mode.test.ts +614 -0
- package/src/__tests__/headless-browser-navigate.test.ts +142 -5
- package/src/__tests__/headless-browser-read-tools.test.ts +11 -0
- package/src/__tests__/headless-browser-snapshot.test.ts +10 -0
- package/src/__tests__/heartbeat-service.test.ts +166 -32
- package/src/__tests__/home-state-routes.test.ts +162 -0
- package/src/__tests__/host-bash-proxy.test.ts +0 -5
- package/src/__tests__/host-browser-e2e-cloud.test.ts +138 -4
- package/src/__tests__/host-browser-e2e-self-hosted.test.ts +4 -4
- package/src/__tests__/host-browser-ws-events-e2e.test.ts +103 -0
- package/src/__tests__/host-cu-proxy.test.ts +0 -5
- package/src/__tests__/host-shell-tool.test.ts +124 -18
- package/src/__tests__/http-user-message-parity.test.ts +29 -1
- package/src/__tests__/identity-intro-cache.test.ts +40 -10
- package/src/__tests__/inbound-slack-persistence.test.ts +340 -0
- package/src/__tests__/init-feature-flag-overrides.test.ts +38 -112
- package/src/__tests__/intent-routing.test.ts +1 -40
- package/src/__tests__/jobs-store-upsert-debounced.test.ts +141 -0
- package/src/__tests__/llm-catalog-parity.test.ts +174 -0
- package/src/__tests__/llm-context-normalization.test.ts +609 -0
- package/src/__tests__/llm-context-route-provider.test.ts +86 -5
- package/src/__tests__/llm-resolver.test.ts +214 -0
- package/src/__tests__/llm-schema.test.ts +223 -0
- package/src/__tests__/llm-usage-store.test.ts +363 -0
- package/src/__tests__/managed-proxy-context.test.ts +6 -2
- package/src/__tests__/media-stream-output.test.ts +555 -0
- package/src/__tests__/media-stream-parser.test.ts +374 -0
- package/src/__tests__/media-stream-server-integration.test.ts +1234 -0
- package/src/__tests__/media-stream-stt-session.test.ts +588 -0
- package/src/__tests__/media-turn-detector.test.ts +440 -0
- package/src/__tests__/message-queue.test.ts +125 -0
- package/src/__tests__/messaging-skill-split.test.ts +3 -34
- package/src/__tests__/migration-export-http.test.ts +6 -6
- package/src/__tests__/migration-import-commit-http.test.ts +8 -6
- package/src/__tests__/migration-import-from-url.test.ts +684 -0
- package/src/__tests__/migration-import-preflight-http.test.ts +6 -5
- package/src/__tests__/migration-validate-http.test.ts +3 -3
- package/src/__tests__/mock-gateway-ipc.ts +151 -0
- package/src/__tests__/model-intents.test.ts +10 -84
- 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-apps-routes.test.ts +1 -0
- package/src/__tests__/oauth-cli.test.ts +2 -0
- package/src/__tests__/oauth-connect-orchestrator.test.ts +2 -0
- package/src/__tests__/oauth-provider-serializer.test.ts +1 -0
- package/src/__tests__/oauth-providers-routes.test.ts +2 -0
- package/src/__tests__/oauth-store.test.ts +95 -7
- package/src/__tests__/oauth2-gateway-transport.test.ts +257 -9
- package/src/__tests__/oauth2-refresh-retry.test.ts +279 -0
- package/src/__tests__/onboarding-template-contract.test.ts +6 -13
- package/src/__tests__/openai-provider.test.ts +183 -0
- package/src/__tests__/openai-responses-cutover-guard.test.ts +184 -0
- package/src/__tests__/openai-responses-provider.test.ts +1501 -0
- package/src/__tests__/openrouter-provider-only.test.ts +135 -0
- package/src/__tests__/openrouter-token-estimation.test.ts +100 -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 +251 -0
- package/src/__tests__/pkb-autoinject.test.ts +37 -1
- package/src/__tests__/platform-bash-auto-approve.test.ts +5 -1
- package/src/__tests__/platform.test.ts +92 -1
- package/src/__tests__/post-turn-tool-result-truncation.test.ts +47 -0
- package/src/__tests__/prechat-onboarding-contract.test.ts +267 -0
- package/src/__tests__/pricing.test.ts +224 -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__/qdrant-manager.test.ts +29 -8
- package/src/__tests__/reaction-persistence.test.ts +560 -0
- package/src/__tests__/regenerate-fire-and-forget-trace.test.ts +194 -0
- package/src/__tests__/relationship-state-contract.test.ts +175 -0
- package/src/__tests__/relay-server.test.ts +424 -6
- 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__/search-skills-unified.test.ts +118 -0
- 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 +5 -1
- package/src/__tests__/secure-keys.test.ts +107 -0
- package/src/__tests__/send-endpoint-busy.test.ts +34 -2
- package/src/__tests__/sequence-store.test.ts +1 -1
- package/src/__tests__/server-history-render.test.ts +80 -0
- package/src/__tests__/settings-routes.test.ts +201 -0
- package/src/__tests__/shell-parser-property.test.ts +13 -13
- package/src/__tests__/skill-cache-store.test.ts +182 -0
- package/src/__tests__/skill-load-feature-flag.test.ts +1 -0
- package/src/__tests__/skills-file-content-endpoint.test.ts +276 -145
- package/src/__tests__/skills-files-catalog-fallback.test.ts +381 -93
- package/src/__tests__/skills.test.ts +19 -30
- package/src/__tests__/skillssh-files.test.ts +446 -0
- package/src/__tests__/slack-app-setup-skill-regression.test.ts +3 -1
- package/src/__tests__/slack-block-formatting.test.ts +110 -0
- package/src/__tests__/slack-channel-config.test.ts +564 -1
- package/src/__tests__/slack-skill.test.ts +3 -8
- package/src/__tests__/starter-bundle.test.ts +35 -0
- package/src/__tests__/stt-catalog-parity.test.ts +282 -0
- package/src/__tests__/stt-stream-session.test.ts +535 -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 +126 -53
- package/src/__tests__/task-runner.test.ts +3 -1
- package/src/__tests__/tcc-sandbox-deny.test.ts +198 -0
- package/src/__tests__/telephony-stt-routing.test.ts +329 -0
- package/src/__tests__/terminal-tools.test.ts +26 -7
- package/src/__tests__/test-preload.ts +18 -0
- package/src/__tests__/test-support/browser-skill-harness.ts +2 -49
- 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 +10 -6
- package/src/__tests__/tool-executor-shell-integration.test.ts +4 -0
- package/src/__tests__/tool-executor.test.ts +88 -113
- package/src/__tests__/tool-result-truncation.test.ts +36 -0
- package/src/__tests__/trust-store.test.ts +442 -103
- package/src/__tests__/trusted-contact-approval-notifier.test.ts +1 -1
- package/src/__tests__/tts-catalog-parity.test.ts +345 -0
- package/src/__tests__/twilio-routes-twiml.test.ts +512 -114
- package/src/__tests__/twilio-routes.test.ts +376 -0
- package/src/__tests__/unicode.test.ts +293 -0
- package/src/__tests__/update-bulletin-job.test.ts +389 -0
- package/src/__tests__/usage-cache-backfill-migration.test.ts +3 -1
- package/src/__tests__/usage-routes.test.ts +25 -4
- package/src/__tests__/user-reference.test.ts +46 -61
- package/src/__tests__/verification-control-plane-policy.test.ts +5 -22
- package/src/__tests__/voice-config-update.test.ts +403 -0
- package/src/__tests__/voice-quality.test.ts +434 -19
- 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-heartbeat-service.test.ts +7 -0
- package/src/__tests__/workspace-migration-033-stt-service-explicit-config.test.ts +547 -0
- package/src/__tests__/workspace-migration-034-remove-calls-voice-transcription-provider.test.ts +596 -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 +368 -0
- package/src/__tests__/workspace-migration-meets.test.ts +244 -0
- package/src/__tests__/workspace-migration-seed-device-id.test.ts +14 -20
- package/src/__tests__/workspace-migration-unify-llm-callsite-configs.test.ts +841 -0
- package/src/__tests__/workspace-policy.test.ts +1 -11
- package/src/acp/client-handler.ts +1 -2
- package/src/agent/image-optimize.ts +24 -12
- package/src/agent/loop.ts +251 -19
- 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/backup/__tests__/backup-key.test.ts +152 -0
- package/src/backup/__tests__/backup-worker.test.ts +767 -0
- package/src/backup/__tests__/list-snapshots.test.ts +87 -0
- package/src/backup/__tests__/local-writer.test.ts +218 -0
- package/src/backup/__tests__/offsite-writer.test.ts +641 -0
- package/src/backup/__tests__/paths.test.ts +300 -0
- package/src/backup/__tests__/restore.test.ts +498 -0
- package/src/backup/__tests__/snapshot-lock.test.ts +352 -0
- package/src/backup/__tests__/stream-crypt.test.ts +228 -0
- package/src/backup/backup-key.ts +137 -0
- package/src/backup/backup-worker.ts +459 -0
- package/src/backup/list-snapshots.ts +147 -0
- package/src/backup/local-writer.ts +133 -0
- package/src/backup/offsite-writer.ts +222 -0
- package/src/backup/paths.ts +226 -0
- package/src/backup/restore.ts +322 -0
- package/src/backup/snapshot-lock.ts +431 -0
- package/src/backup/stream-crypt.ts +263 -0
- 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/bundler/package-resolver.ts +4 -0
- package/src/calls/audio-store.ts +11 -5
- package/src/calls/call-controller.ts +226 -71
- package/src/calls/call-domain.ts +9 -0
- package/src/calls/call-speech-output.ts +190 -0
- package/src/calls/call-transport.ts +77 -0
- package/src/calls/guardian-question-copy.ts +2 -2
- package/src/calls/media-stream-audio-transcode.ts +173 -0
- package/src/calls/media-stream-output.ts +660 -0
- package/src/calls/media-stream-parser.ts +300 -0
- package/src/calls/media-stream-protocol.ts +166 -0
- package/src/calls/media-stream-server.ts +592 -0
- package/src/calls/media-stream-stt-session.ts +460 -0
- package/src/calls/media-turn-detector.ts +230 -0
- package/src/calls/relay-server.ts +90 -75
- package/src/calls/resolve-call-tts-provider.ts +136 -0
- package/src/calls/telephony-stt-routing.ts +145 -0
- package/src/calls/tts-call-strategy.ts +161 -0
- package/src/calls/tts-text-sanitizer.ts +32 -16
- package/src/calls/twilio-routes.ts +281 -17
- package/src/calls/voice-quality.ts +78 -35
- package/src/calls/voice-session-bridge.ts +9 -1
- package/src/channels/types.ts +16 -0
- package/src/cli/AGENTS.md +1 -1
- package/src/cli/__tests__/run-assistant-command.ts +11 -1
- package/src/cli/commands/__tests__/attachment.test.ts +438 -0
- package/src/cli/commands/__tests__/backup.test.ts +1165 -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__/domain-register.test.ts +234 -0
- package/src/cli/commands/__tests__/domain-status.test.ts +132 -0
- package/src/cli/commands/__tests__/email-attachment.test.ts +422 -0
- package/src/cli/commands/__tests__/email-download.test.ts +16 -1
- package/src/cli/commands/__tests__/email-list.test.ts +28 -4
- package/src/cli/commands/__tests__/email-register.test.ts +4 -4
- package/src/cli/commands/__tests__/email-send.test.ts +130 -5
- package/src/cli/commands/__tests__/email-status.test.ts +5 -1
- package/src/cli/commands/__tests__/email-unregister.test.ts +34 -5
- 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/backup.ts +993 -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 +90 -0
- package/src/cli/commands/credentials.ts +0 -1
- package/src/cli/commands/domain.ts +210 -0
- package/src/cli/commands/email.ts +308 -16
- 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/oauth/__tests__/connect.test.ts +12 -0
- package/src/cli/commands/oauth/__tests__/providers-delete.test.ts +1 -0
- package/src/cli/commands/oauth/__tests__/providers-register.test.ts +1 -0
- package/src/cli/commands/oauth/__tests__/providers-update.test.ts +1 -0
- package/src/cli/commands/oauth/mode.ts +12 -3
- package/src/cli/commands/oauth/providers.ts +15 -0
- package/src/cli/commands/oauth/shared.ts +2 -1
- package/src/cli/commands/platform/__tests__/callback-routes-list.test.ts +4 -10
- package/src/cli/commands/platform/__tests__/connect.test.ts +6 -1
- package/src/cli/commands/platform/__tests__/disconnect.test.ts +7 -2
- package/src/cli/commands/platform/__tests__/status.test.ts +6 -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 +53 -8
- package/src/cli.ts +0 -37
- package/src/config/__tests__/backup-schema.test.ts +134 -0
- package/src/config/assistant-feature-flags.ts +61 -62
- package/src/config/bundled-skills/app-builder/references/CUSTOM_ROUTES.md +37 -1
- package/src/config/bundled-skills/contacts/SKILL.md +2 -2
- package/src/config/bundled-skills/conversations/tools/rename-conversation.ts +23 -1
- package/src/config/bundled-skills/media-processing/SKILL.md +3 -9
- package/src/config/bundled-skills/media-processing/TOOLS.json +1 -6
- package/src/config/bundled-skills/media-processing/__tests__/audio-transcribe.test.ts +125 -0
- package/src/config/bundled-skills/media-processing/__tests__/extract-keyframes.test.ts +181 -0
- package/src/config/bundled-skills/media-processing/__tests__/preprocess-audio.test.ts +141 -0
- package/src/config/bundled-skills/media-processing/services/audio-transcribe.ts +32 -87
- package/src/config/bundled-skills/media-processing/services/preprocess.ts +8 -4
- package/src/config/bundled-skills/media-processing/services/reduce.ts +1 -1
- package/src/config/bundled-skills/media-processing/tools/extract-keyframes.ts +0 -10
- package/src/config/bundled-skills/messaging/SKILL.md +5 -5
- package/src/config/bundled-skills/messaging/TOOLS.json +4 -0
- package/src/config/bundled-skills/messaging/tools/messaging-archive-by-sender.ts +9 -2
- 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/SKILL.md +2 -2
- package/src/config/bundled-skills/phone-calls/references/CONFIG.md +28 -18
- package/src/config/bundled-skills/phone-calls/references/TROUBLESHOOTING.md +3 -3
- package/src/config/bundled-skills/settings/TOOLS.json +3 -3
- package/src/config/bundled-skills/settings/tools/voice-config-update.ts +26 -22
- package/src/config/bundled-skills/transcribe/SKILL.md +9 -14
- package/src/config/bundled-skills/transcribe/TOOLS.json +2 -7
- package/src/config/bundled-skills/transcribe/tools/transcribe-media.test.ts +256 -0
- package/src/config/bundled-skills/transcribe/tools/transcribe-media.ts +38 -188
- package/src/config/bundled-tool-registry.ts +0 -167
- package/src/config/env-registry.ts +24 -0
- package/src/config/env.ts +39 -10
- package/src/config/feature-flag-registry.json +63 -15
- package/src/config/llm-resolver.ts +128 -0
- package/src/config/loader.ts +220 -22
- package/src/config/raw-config-utils.ts +30 -2
- package/src/config/sanitize-for-transfer.ts +35 -0
- package/src/config/schema.ts +65 -51
- package/src/config/schemas/__tests__/stt.test.ts +43 -0
- package/src/config/schemas/analysis.ts +32 -0
- package/src/config/schemas/backup.ts +72 -0
- package/src/config/schemas/calls.ts +1 -30
- package/src/config/schemas/elevenlabs.ts +0 -59
- package/src/config/schemas/filing.ts +49 -14
- package/src/config/schemas/heartbeat.ts +27 -10
- package/src/config/schemas/host-browser.ts +47 -1
- package/src/config/schemas/inference.ts +3 -23
- package/src/config/schemas/llm.ts +318 -0
- package/src/config/schemas/memory-lifecycle.ts +14 -2
- 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 +53 -4
- package/src/config/schemas/stt.ts +60 -0
- package/src/config/schemas/tts.ts +283 -0
- package/src/config/schemas/updates.ts +14 -0
- package/src/config/schemas/workspace-git.ts +3 -40
- package/src/config/skills.ts +6 -2
- package/src/config/types.ts +4 -0
- package/src/contacts/contact-store.ts +56 -11
- package/src/contacts/contacts-write.ts +38 -1
- 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/post-turn-tool-result-truncation.ts +3 -2
- package/src/context/prompts/compact.md +12 -0
- package/src/context/token-estimator.ts +61 -3
- package/src/context/tool-result-truncation.ts +2 -1
- package/src/context/window-manager.ts +272 -35
- package/src/credential-execution/approval-bridge.ts +0 -1
- package/src/credential-execution/executable-discovery.ts +23 -2
- package/src/credential-execution/process-manager.test.ts +109 -0
- package/src/credential-execution/process-manager.ts +96 -2
- package/src/credential-health/credential-health-service.ts +366 -0
- package/src/daemon/__tests__/conversation-lifecycle-auto-analyze.test.ts +324 -0
- package/src/daemon/__tests__/conversation-surfaces-launch.test.ts +497 -0
- package/src/daemon/__tests__/conversation-tool-setup.test.ts +17 -8
- package/src/daemon/__tests__/lifecycle-startup-ordering.test.ts +127 -0
- 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 +99 -6
- package/src/daemon/context-overflow-reducer.ts +4 -1
- package/src/daemon/conversation-agent-loop-handlers.ts +85 -12
- package/src/daemon/conversation-agent-loop.ts +563 -104
- package/src/daemon/conversation-attachments.ts +2 -6
- package/src/daemon/conversation-error.ts +46 -0
- package/src/daemon/conversation-history.ts +40 -6
- package/src/daemon/conversation-launch.ts +220 -0
- package/src/daemon/conversation-lifecycle.ts +85 -11
- package/src/daemon/conversation-messaging.ts +110 -7
- package/src/daemon/conversation-notifiers.ts +5 -0
- package/src/daemon/conversation-process.ts +591 -23
- package/src/daemon/conversation-queue-manager.ts +27 -0
- package/src/daemon/conversation-runtime-assembly.ts +769 -28
- package/src/daemon/conversation-slash.ts +38 -2
- package/src/daemon/conversation-surfaces.ts +483 -5
- package/src/daemon/conversation-tool-setup.ts +35 -5
- package/src/daemon/conversation-usage.ts +8 -5
- package/src/daemon/conversation.ts +193 -47
- 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/config-slack-channel.ts +269 -94
- package/src/daemon/handlers/conversations.ts +13 -3
- package/src/daemon/handlers/shared.ts +51 -1
- package/src/daemon/handlers/skills.ts +323 -79
- package/src/daemon/handlers/slack-channel-oauth-install.ts +197 -0
- package/src/daemon/host-browser-proxy.ts +2 -1
- package/src/daemon/lifecycle.ts +185 -26
- package/src/daemon/message-protocol.ts +6 -0
- package/src/daemon/message-types/conversations.ts +48 -1
- package/src/daemon/message-types/home.ts +40 -0
- package/src/daemon/message-types/meet.ts +143 -0
- package/src/daemon/message-types/messages.ts +23 -1
- package/src/daemon/message-types/schedules.ts +34 -2
- package/src/daemon/message-types/skills.ts +16 -0
- package/src/daemon/message-types/surfaces.ts +2 -0
- 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 +463 -10
- package/src/daemon/shutdown-handlers.ts +32 -4
- package/src/daemon/shutdown-registry.ts +40 -0
- package/src/daemon/tool-side-effects.ts +9 -9
- package/src/daemon/watch-handler.ts +4 -4
- package/src/daemon/web-search-history.ts +126 -0
- package/src/email/html-renderer.ts +76 -0
- package/src/events/domain-events.ts +0 -1
- package/src/filing/filing-service.ts +9 -10
- package/src/heartbeat/heartbeat-service.ts +156 -22
- package/src/home/__tests__/assistant-feed-authoring.test.ts +156 -0
- package/src/home/__tests__/emit-feed-event.test.ts +169 -0
- package/src/home/__tests__/feed-scheduler.test.ts +222 -0
- package/src/home/__tests__/feed-types.test.ts +275 -0
- package/src/home/__tests__/feed-writer.test.ts +688 -0
- package/src/home/__tests__/phase5-exit-criteria.test.ts +212 -0
- package/src/home/__tests__/platform-gmail-digest.test.ts +222 -0
- package/src/home/__tests__/progress-formula.test.ts +213 -0
- package/src/home/__tests__/relationship-state-writer.test.ts +740 -0
- package/src/home/__tests__/rollup-producer.test.ts +442 -0
- package/src/home/assistant-feed-authoring.ts +128 -0
- package/src/home/emit-feed-event.ts +162 -0
- package/src/home/feed-scheduler.ts +263 -0
- package/src/home/feed-types.ts +235 -0
- package/src/home/feed-writer.ts +469 -0
- package/src/home/platform-gmail-digest.ts +163 -0
- package/src/home/progress-formula.ts +86 -0
- package/src/home/relationship-state-writer.ts +824 -0
- package/src/home/relationship-state.ts +143 -0
- package/src/home/rollup-producer.ts +413 -0
- package/src/home/suggested-prompts.ts +101 -0
- package/src/hooks/runner.ts +7 -0
- package/src/inbound/platform-callback-registration.ts +12 -3
- package/src/inbound/public-ingress-urls.ts +12 -0
- package/src/instrument.ts +1 -1
- 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__/cli-ipc.test.ts +200 -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 +152 -0
- package/src/ipc/cli-server.ts +252 -0
- package/src/ipc/gateway-client.ts +180 -0
- 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 +21 -0
- 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/wake-conversation.ts +19 -0
- package/src/ipc/routes/watcher.ts +203 -0
- package/src/ipc/socket-path.ts +100 -0
- package/src/memory/__tests__/auto-analysis-enqueue.test.ts +356 -0
- package/src/memory/__tests__/auto-analysis-guard.test.ts +57 -0
- package/src/memory/__tests__/conversation-analyze-job.test.ts +233 -0
- package/src/memory/__tests__/conversation-group-migration.test.ts +99 -0
- package/src/memory/__tests__/find-analysis-conversation.test.ts +196 -0
- package/src/memory/admin.ts +18 -0
- package/src/memory/app-store.ts +1 -1
- package/src/memory/attachments-store.ts +70 -0
- package/src/memory/auto-analysis-enqueue.ts +127 -0
- package/src/memory/auto-analysis-guard.ts +27 -0
- package/src/memory/cleanup-schedule-state.ts +37 -0
- package/src/memory/conversation-analyze-job.ts +74 -0
- package/src/memory/conversation-attention-store.ts +13 -6
- package/src/memory/conversation-crud.ts +199 -0
- package/src/memory/conversation-disk-view.ts +7 -0
- package/src/memory/conversation-group-migration.ts +65 -1
- package/src/memory/conversation-queries.ts +6 -5
- package/src/memory/conversation-title-service.ts +7 -4
- package/src/memory/db-init.ts +8 -0
- package/src/memory/db-maintenance.ts +108 -0
- package/src/memory/db.ts +1 -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 +104 -29
- package/src/memory/graph/extraction.test.ts +295 -2
- package/src/memory/graph/extraction.ts +181 -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 +257 -66
- package/src/memory/graph/scoring.test.ts +186 -0
- package/src/memory/graph/scoring.ts +31 -1
- 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/group-crud.ts +6 -1
- package/src/memory/indexer.ts +95 -16
- package/src/memory/job-handlers/cleanup.ts +11 -8
- package/src/memory/job-handlers/conversation-starters.ts +39 -30
- 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 +106 -5
- package/src/memory/jobs-worker.ts +26 -9
- package/src/memory/llm-usage-store.ts +92 -56
- package/src/memory/migrations/140-backfill-usage-cache-accounting.ts +1 -1
- package/src/memory/migrations/219-oauth-providers-token-exchange-body-format.ts +15 -0
- package/src/memory/migrations/220-normalize-user-file-by-principal.ts +190 -0
- package/src/memory/migrations/221-conversations-archived-at.ts +16 -0
- package/src/memory/migrations/222-strip-placeholder-sentinels-from-messages.ts +82 -0
- package/src/memory/migrations/index.ts +7 -0
- package/src/memory/migrations/registry.ts +8 -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/qdrant-manager.ts +43 -16
- package/src/memory/schema/conversations.ts +2 -0
- package/src/memory/schema/oauth.ts +3 -0
- package/src/memory/slack-thread-store.ts +37 -0
- package/src/memory/usage-buckets.ts +396 -0
- package/src/messaging/providers/gmail/adapter.ts +6 -16
- package/src/messaging/providers/gmail/client.ts +79 -6
- package/src/messaging/providers/gmail/types.ts +7 -0
- package/src/messaging/providers/slack/__tests__/adapter-token-routing.test.ts +282 -0
- package/src/messaging/providers/slack/adapter.ts +155 -38
- package/src/messaging/providers/slack/backfill.test.ts +257 -0
- package/src/messaging/providers/slack/backfill.ts +101 -0
- package/src/messaging/providers/slack/client.ts +16 -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/providers/slack/types.ts +4 -0
- package/src/messaging/style-analyzer.ts +5 -2
- package/src/notifications/README.md +9 -5
- package/src/notifications/decision-engine.ts +6 -12
- package/src/notifications/preference-extractor.ts +2 -6
- package/src/notifications/signal.ts +5 -0
- package/src/oauth/__tests__/identity-verifier.test.ts +1 -0
- package/src/oauth/byo-connection.test.ts +18 -1
- package/src/oauth/byo-connection.ts +3 -1
- package/src/oauth/connect-orchestrator.ts +2 -0
- package/src/oauth/connection-resolver.ts +6 -2
- package/src/oauth/connection.ts +2 -0
- package/src/oauth/oauth-store.ts +10 -0
- package/src/oauth/platform-connection.test.ts +145 -0
- package/src/oauth/platform-connection.ts +62 -31
- package/src/oauth/seed-providers.ts +10 -1
- 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 +218 -699
- package/src/permissions/command-registry.test.ts +535 -0
- package/src/permissions/command-registry.ts +825 -0
- package/src/permissions/defaults.ts +71 -75
- 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 +164 -65
- 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 -13
- package/src/platform/client.test.ts +10 -0
- package/src/platform/client.ts +19 -1
- package/src/platform/sync-identity.ts +129 -0
- package/src/prompts/persona-resolver.ts +127 -3
- package/src/prompts/system-prompt.ts +78 -38
- package/src/prompts/templates/BOOTSTRAP.md +5 -5
- package/src/prompts/templates/SOUL.md +5 -3
- package/src/prompts/templates/channels/slack.md +20 -0
- package/src/prompts/update-bulletin-job.ts +190 -0
- package/src/prompts/user-reference.ts +20 -17
- 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__/provider-secret-catalog.test.ts +42 -0
- package/src/providers/__tests__/retry-callsite.test.ts +424 -0
- package/src/providers/anthropic/client.ts +335 -70
- package/src/providers/call-site-routing.ts +71 -0
- package/src/providers/fireworks/client.ts +2 -2
- package/src/providers/gemini/client.ts +74 -3
- package/src/providers/managed-proxy/constants.ts +2 -1
- package/src/providers/model-catalog.ts +502 -28
- package/src/providers/model-intents.ts +8 -8
- package/src/providers/ollama/client.ts +2 -2
- package/src/providers/openai/chat-completions-provider.ts +530 -0
- package/src/providers/openai/client.ts +25 -440
- package/src/providers/openai/responses-provider.ts +579 -0
- package/src/providers/openrouter/client.ts +168 -4
- package/src/providers/provider-env-vars.ts +56 -0
- package/src/providers/provider-secret-catalog.ts +139 -0
- package/src/providers/provider-send-message.ts +22 -5
- package/src/providers/ratelimit.ts +4 -0
- package/src/providers/registry.ts +21 -10
- package/src/providers/retry.ts +185 -39
- package/src/providers/speech-to-text/__tests__/provider-catalog.test.ts +251 -0
- package/src/providers/speech-to-text/__tests__/resolve.test.ts +883 -0
- package/src/providers/speech-to-text/deepgram-realtime.test.ts +980 -0
- package/src/providers/speech-to-text/deepgram-realtime.ts +767 -0
- package/src/providers/speech-to-text/deepgram.test.ts +332 -0
- package/src/providers/speech-to-text/deepgram.ts +115 -0
- package/src/providers/speech-to-text/google-gemini-live-stream.test.ts +743 -0
- package/src/providers/speech-to-text/google-gemini-live-stream.ts +625 -0
- package/src/providers/speech-to-text/google-gemini.test.ts +226 -0
- package/src/providers/speech-to-text/google-gemini.ts +101 -0
- package/src/providers/speech-to-text/openai-whisper-stream.test.ts +564 -0
- package/src/providers/speech-to-text/openai-whisper-stream.ts +381 -0
- package/src/providers/speech-to-text/openai-whisper.test.ts +1 -37
- package/src/providers/speech-to-text/openai-whisper.ts +63 -33
- package/src/providers/speech-to-text/provider-catalog.ts +323 -0
- package/src/providers/speech-to-text/resolve.ts +393 -6
- 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 +102 -3
- package/src/runtime/AGENTS.md +45 -3
- package/src/runtime/__tests__/agent-wake.test.ts +872 -0
- package/src/runtime/__tests__/interactive-ui.test.ts +673 -0
- package/src/runtime/__tests__/runtime-mode.test.ts +62 -0
- package/src/runtime/__tests__/slack-block-formatting.test.ts +481 -0
- package/src/runtime/agent-wake.ts +553 -0
- package/src/runtime/auth/__tests__/route-policy.test.ts +40 -0
- package/src/runtime/auth/route-policy.ts +34 -5
- package/src/runtime/auth/token-service.ts +56 -1
- package/src/runtime/btw-sidechain.ts +15 -3
- package/src/runtime/capability-tokens.ts +10 -10
- package/src/runtime/channel-invite-transport.ts +1 -1
- package/src/runtime/channel-invite-transports/email.ts +14 -6
- package/src/runtime/channel-readiness-service.ts +12 -22
- package/src/runtime/channel-reply-delivery.ts +106 -2
- package/src/runtime/chrome-extension-registry.ts +38 -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 +447 -11
- package/src/runtime/http-types.ts +29 -3
- 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-import-credentials.test.ts +36 -0
- package/src/runtime/migrations/__tests__/vbundle-legacy-user-md.test.ts +360 -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/migration-transport.ts +1 -0
- package/src/runtime/migrations/migration-wizard.ts +1 -0
- package/src/runtime/migrations/vbundle-import-analyzer.ts +77 -1
- package/src/runtime/migrations/vbundle-importer.ts +187 -8
- 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/pending-interactions.ts +0 -11
- package/src/runtime/routes/__tests__/backup-routes.test.ts +967 -0
- package/src/runtime/routes/__tests__/home-feed-routes.test.ts +618 -0
- package/src/runtime/routes/__tests__/migration-import-credential-filter.test.ts +247 -0
- package/src/runtime/routes/__tests__/migration-vellum-metadata-reconcile.test.ts +246 -0
- package/src/runtime/routes/__tests__/stt-routes.test.ts +406 -0
- package/src/runtime/routes/__tests__/tts-routes.test.ts +474 -0
- package/src/runtime/routes/__tests__/user-route-dispatcher.test.ts +148 -17
- package/src/runtime/routes/app-management-routes.ts +12 -18
- 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/attachment-routes.test.ts +9 -3
- package/src/runtime/routes/attachment-routes.ts +216 -17
- package/src/runtime/routes/avatar-routes.ts +20 -4
- package/src/runtime/routes/backup-routes.ts +519 -0
- package/src/runtime/routes/browser-extension-pair-routes.ts +82 -23
- package/src/runtime/routes/btw-routes.ts +9 -10
- package/src/runtime/routes/contact-routes.test.ts +298 -0
- package/src/runtime/routes/contact-routes.ts +132 -5
- package/src/runtime/routes/conversation-analysis-routes.ts +22 -142
- package/src/runtime/routes/conversation-management-routes.ts +133 -0
- package/src/runtime/routes/conversation-routes.ts +487 -160
- 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/filing-routes.ts +93 -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 +452 -0
- package/src/runtime/routes/home-state-routes.ts +138 -0
- package/src/runtime/routes/host-browser-routes.ts +3 -14
- package/src/runtime/routes/identity-intro-cache.ts +7 -3
- package/src/runtime/routes/identity-routes.ts +3 -17
- 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/inbound-stages/transcribe-audio.test.ts +46 -39
- package/src/runtime/routes/inbound-stages/transcribe-audio.ts +15 -15
- package/src/runtime/routes/integrations/slack/__tests__/channel.test.ts +137 -0
- package/src/runtime/routes/integrations/slack/__tests__/share.test.ts +179 -0
- package/src/runtime/routes/integrations/slack/channel.ts +36 -6
- package/src/runtime/routes/integrations/slack/share.ts +45 -7
- package/src/runtime/routes/llm-context-normalization.ts +325 -0
- package/src/runtime/routes/memory-item-routes.test.ts +3 -2
- package/src/runtime/routes/migration-routes.ts +722 -91
- package/src/runtime/routes/settings-routes.ts +26 -7
- package/src/runtime/routes/skills-routes.ts +76 -7
- package/src/runtime/routes/stt-routes.ts +233 -0
- package/src/runtime/routes/surface-action-routes.ts +41 -2
- package/src/runtime/routes/trust-rules-routes.ts +30 -14
- package/src/runtime/routes/tts-routes.ts +108 -24
- package/src/runtime/routes/usage-routes.ts +30 -2
- package/src/runtime/routes/user-route-dispatcher.ts +50 -5
- package/src/runtime/routes/user-routes.ts +13 -1
- package/src/runtime/routes/work-items-routes.test.ts +1 -1
- package/src/runtime/routes/work-items-routes.ts +11 -3
- package/src/runtime/runtime-mode.ts +33 -0
- package/src/runtime/services/__tests__/analyze-conversation.test.ts +426 -0
- package/src/runtime/services/__tests__/analyze-deps-singleton.test.ts +67 -0
- package/src/runtime/services/__tests__/auto-analysis-prompt.test.ts +53 -0
- package/src/runtime/services/__tests__/manual-analysis-prompt.test.ts +41 -0
- package/src/runtime/services/analyze-conversation.ts +340 -0
- package/src/runtime/services/analyze-deps-singleton.ts +32 -0
- package/src/runtime/services/auto-analysis-prompt.ts +55 -0
- package/src/runtime/skill-route-registry.ts +71 -0
- package/src/runtime/slack-block-formatting.ts +437 -10
- package/src/schedule/scheduler.ts +58 -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 +122 -37
- package/src/security/secure-keys.ts +32 -10
- package/src/security/token-manager.ts +35 -13
- package/src/security/untrusted-content.ts +102 -0
- package/src/sequence/engine.ts +23 -0
- package/src/sequence/types.ts +1 -1
- package/src/skills/catalog-cache.ts +26 -7
- package/src/skills/catalog-files.ts +64 -2
- package/src/skills/catalog-install.ts +31 -3
- package/src/skills/category-inference.ts +122 -0
- package/src/skills/clawhub-files.ts +213 -0
- package/src/skills/clawhub.ts +84 -23
- package/src/skills/skill-cache-store.ts +97 -0
- package/src/skills/skill-file-provider.ts +40 -0
- package/src/skills/skillssh-files.ts +395 -0
- package/src/skills/skillssh-registry.ts +4 -4
- package/src/stt/__tests__/daemon-batch-transcriber.test.ts +468 -0
- package/src/stt/__tests__/types.test.ts +89 -0
- package/src/stt/daemon-batch-transcriber.ts +228 -0
- package/src/stt/stt-stream-session.ts +506 -0
- package/src/stt/types.ts +334 -0
- package/src/stt/wav-encoder.test.ts +373 -0
- package/src/stt/wav-encoder.ts +175 -0
- package/src/subagent/manager.ts +79 -27
- package/src/tasks/ephemeral-permissions.ts +9 -4
- package/src/telemetry/usage-telemetry-reporter.ts +27 -5
- package/src/tools/browser/__tests__/browser-mode.test.ts +119 -0
- package/src/tools/browser/__tests__/browser-status.test.ts +166 -0
- package/src/tools/browser/browser-execution.ts +1208 -41
- package/src/tools/browser/browser-manager.ts +45 -0
- package/src/tools/browser/browser-mode-constants.ts +12 -0
- package/src/tools/browser/browser-mode.ts +92 -0
- package/src/tools/browser/browser-status-constants.ts +33 -0
- package/src/tools/browser/cdp-client/__tests__/cdp-inspect-client.test.ts +393 -0
- package/src/tools/browser/cdp-client/__tests__/extension-cdp-client.test.ts +29 -0
- package/src/tools/browser/cdp-client/__tests__/factory.test.ts +1648 -32
- package/src/tools/browser/cdp-client/cdp-inspect/__tests__/discovery.test.ts +264 -0
- package/src/tools/browser/cdp-client/cdp-inspect/discovery.ts +205 -17
- package/src/tools/browser/cdp-client/cdp-inspect-client.ts +254 -21
- package/src/tools/browser/cdp-client/errors.ts +15 -0
- package/src/tools/browser/cdp-client/extension-cdp-client.ts +39 -16
- package/src/tools/browser/cdp-client/factory.ts +797 -87
- package/src/tools/browser/cdp-client/index.ts +16 -2
- package/src/tools/browser/cdp-client/types.ts +68 -0
- package/src/tools/credentials/tool-policy.ts +39 -5
- package/src/tools/credentials/vault.ts +41 -7
- 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 +25 -12
- package/src/tools/network/web-search.ts +20 -2
- 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/shared/shell-output.ts +3 -1
- package/src/tools/side-effects.ts +0 -9
- package/src/tools/skills/execute.ts +2 -2
- package/src/tools/skills/sandbox-runner.ts +6 -2
- package/src/tools/terminal/backends/native.ts +51 -2
- package/src/tools/terminal/safe-env.ts +11 -2
- package/src/tools/terminal/shell.ts +16 -4
- package/src/tools/tool-manifest.ts +6 -0
- package/src/tools/types.ts +29 -3
- package/src/tools/ui-surface/definitions.ts +6 -1
- package/src/tools/verification-control-plane-policy.ts +1 -1
- package/src/tts/__tests__/provider-adapters.test.ts +1061 -0
- package/src/tts/__tests__/provider-catalog-consistency.test.ts +196 -0
- package/src/tts/__tests__/provider-catalog.test.ts +183 -0
- package/src/tts/__tests__/provider-registry.test.ts +90 -0
- package/src/tts/provider-catalog.ts +219 -0
- package/src/tts/provider-registry.ts +73 -0
- package/src/tts/providers/deepgram-provider.ts +219 -0
- package/src/tts/providers/elevenlabs-provider.ts +211 -0
- package/src/tts/providers/fish-audio-provider.ts +183 -0
- package/src/tts/providers/index.ts +44 -0
- package/src/tts/providers/register-builtins.ts +130 -0
- package/src/tts/providers/xai-provider.ts +224 -0
- package/src/tts/synthesize-text.ts +110 -0
- package/src/tts/tts-config-resolver.ts +78 -0
- package/src/tts/types.ts +199 -0
- package/src/types/onboarding-context.ts +7 -0
- package/src/types/tar-stream.d.ts +66 -0
- package/src/util/abort-reasons.ts +58 -0
- package/src/util/device-id.ts +32 -16
- package/src/util/errors.ts +9 -1
- package/src/util/json.ts +17 -0
- package/src/util/platform.ts +56 -12
- package/src/util/pricing.ts +78 -5
- package/src/util/spawn.ts +1 -1
- package/src/util/truncate.ts +4 -2
- package/src/util/unicode.ts +201 -0
- package/src/version.ts +19 -24
- package/src/watcher/engine.ts +24 -1
- package/src/watcher/providers/google-calendar.ts +134 -8
- package/src/watcher/providers/outlook-calendar.ts +42 -2
- package/src/watcher/watcher-store.ts +31 -0
- package/src/workspace/git-service.ts +23 -4
- package/src/workspace/migrations/003-seed-device-id.ts +9 -3
- package/src/workspace/migrations/017-seed-persona-dirs.ts +68 -4
- package/src/workspace/migrations/029-seed-pkb.ts +1 -1
- package/src/workspace/migrations/031-drop-user-md.ts +317 -0
- package/src/workspace/migrations/031-llm-log-retention-zero-to-null.ts +73 -0
- package/src/workspace/migrations/032-tts-provider-unification.ts +227 -0
- package/src/workspace/migrations/033-stt-service-explicit-config.ts +122 -0
- package/src/workspace/migrations/034-remove-calls-voice-transcription-provider.ts +215 -0
- package/src/workspace/migrations/035-seed-slack-channel-persona.ts +50 -0
- package/src/workspace/migrations/036-update-pkb-index-bar.ts +37 -0
- package/src/workspace/migrations/037-create-meets-dir.ts +61 -0
- 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 +32 -0
- package/src/workspace/provider-commit-message-generator.ts +19 -38
- package/src/workspace/top-level-renderer.ts +13 -1
- package/src/workspace/turn-commit.ts +31 -0
- package/src/__tests__/email-cli.test.ts +0 -297
- package/src/__tests__/email-service-config-fallback.test.ts +0 -102
- 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 -250
- package/src/__tests__/update-bulletin-format.test.ts +0 -122
- package/src/__tests__/update-bulletin-state.test.ts +0 -135
- package/src/__tests__/update-bulletin.test.ts +0 -277
- package/src/__tests__/update-template-contract.test.ts +0 -29
- package/src/cli/commands/browser-relay.ts +0 -466
- package/src/cli/commands/doctor.ts +0 -341
- package/src/config/bundled-skills/browser/SKILL.md +0 -63
- package/src/config/bundled-skills/browser/TOOLS.json +0 -393
- 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-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-type.ts +0 -12
- package/src/config/bundled-skills/browser/tools/browser-wait-for-download.ts +0 -32
- 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 -175
- package/src/config/bundled-skills/gmail/TOOLS.json +0 -558
- package/src/config/bundled-skills/gmail/tools/gmail-archive.ts +0 -149
- 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 -220
- 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 -251
- 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 -107
- 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/email/guardrails.ts +0 -221
- package/src/email/provider.ts +0 -117
- package/src/email/providers/agentmail.ts +0 -361
- package/src/email/providers/index.ts +0 -65
- package/src/email/service.ts +0 -384
- package/src/email/types.ts +0 -126
- package/src/prompts/templates/UPDATES.md +0 -38
- package/src/prompts/templates/USER.md +0 -13
- package/src/prompts/update-bulletin-format.ts +0 -68
- 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 -128
- package/src/providers/speech-to-text/types.ts +0 -17
- package/src/runtime/routes/browser-cdp-routes.ts +0 -229
- 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
|
@@ -1,17 +1,13 @@
|
|
|
1
1
|
import { createHash } from "node:crypto";
|
|
2
2
|
import { homedir } from "node:os";
|
|
3
|
-
import { dirname,
|
|
3
|
+
import { dirname, resolve } from "node:path";
|
|
4
4
|
|
|
5
5
|
import { isAssistantFeatureFlagEnabled } from "../config/assistant-feature-flags.js";
|
|
6
6
|
import { getIsContainerized } from "../config/env-registry.js";
|
|
7
7
|
import { getConfig } from "../config/loader.js";
|
|
8
8
|
import { loadSkillCatalog, resolveSkillSelector } from "../config/skills.js";
|
|
9
9
|
import { indexCatalogById } from "../skills/include-graph.js";
|
|
10
|
-
import {
|
|
11
|
-
isSkillSourcePath,
|
|
12
|
-
normalizeDirPath,
|
|
13
|
-
normalizeFilePath,
|
|
14
|
-
} from "../skills/path-classifier.js";
|
|
10
|
+
import { normalizeFilePath } from "../skills/path-classifier.js";
|
|
15
11
|
import { computeTransitiveSkillVersionHash } from "../skills/transitive-version-hash.js";
|
|
16
12
|
import { computeSkillVersionHash } from "../skills/version-hash.js";
|
|
17
13
|
import type { ManifestOverride } from "../tools/execution-target.js";
|
|
@@ -20,13 +16,21 @@ import {
|
|
|
20
16
|
looksLikePathOnlyInput,
|
|
21
17
|
} from "../tools/network/url-safety.js";
|
|
22
18
|
import { getTool } from "../tools/registry.js";
|
|
23
|
-
import {
|
|
19
|
+
import {
|
|
20
|
+
type ApprovalContext,
|
|
21
|
+
DefaultApprovalPolicy,
|
|
22
|
+
resolveThreshold,
|
|
23
|
+
} from "./approval-policy.js";
|
|
24
|
+
import { bashRiskClassifier } from "./bash-risk-classifier.js";
|
|
25
|
+
import { fileRiskClassifier } from "./file-risk-classifier.js";
|
|
26
|
+
import { type RiskAssessment, riskToRiskLevel } from "./risk-types.js";
|
|
24
27
|
import {
|
|
25
28
|
buildShellAllowlistOptions,
|
|
26
29
|
buildShellCommandCandidates,
|
|
27
30
|
cachedParse,
|
|
28
31
|
type ParsedCommand,
|
|
29
32
|
} from "./shell-identity.js";
|
|
33
|
+
import { skillLoadRiskClassifier } from "./skill-risk-classifier.js";
|
|
30
34
|
import { findHighestPriorityRule, onRulesChanged } from "./trust-store.js";
|
|
31
35
|
import {
|
|
32
36
|
type AllowlistOption,
|
|
@@ -35,6 +39,7 @@ import {
|
|
|
35
39
|
RiskLevel,
|
|
36
40
|
type ScopeOption,
|
|
37
41
|
} from "./types.js";
|
|
42
|
+
import { webRiskClassifier } from "./web-risk-classifier.js";
|
|
38
43
|
import { isWorkspaceScopedInvocation } from "./workspace-policy.js";
|
|
39
44
|
|
|
40
45
|
// ── Risk classification cache ────────────────────────────────────────────────
|
|
@@ -44,10 +49,35 @@ import { isWorkspaceScopedInvocation } from "./workspace-policy.js";
|
|
|
44
49
|
// Invalidated when trust rules change since risk classification for file tools
|
|
45
50
|
// depends on skill source path checks which reference config, but the core
|
|
46
51
|
// risk logic is input-deterministic.
|
|
52
|
+
/** The result of classifyRisk(): a risk level with an optional human-readable reason. */
|
|
53
|
+
export interface RiskClassification {
|
|
54
|
+
level: RiskLevel;
|
|
55
|
+
/** Human-readable explanation of why this risk level was assigned. */
|
|
56
|
+
reason?: string;
|
|
57
|
+
}
|
|
58
|
+
|
|
47
59
|
const RISK_CACHE_MAX = 256;
|
|
48
|
-
const riskCache = new Map<string,
|
|
60
|
+
const riskCache = new Map<string, RiskClassification>();
|
|
49
61
|
let riskCacheInvalidationHookRegistered = false;
|
|
50
62
|
|
|
63
|
+
// ── Assessment cache ─────────────────────────────────────────────────────────
|
|
64
|
+
// Stores the full RiskAssessment from classifier-backed tools so that
|
|
65
|
+
// generateAllowlistOptions() can read classifier-produced allowlistOptions
|
|
66
|
+
// without re-classifying. Keyed on (toolName, inputHash) — a simpler key
|
|
67
|
+
// than the full risk cache since generateAllowlistOptions() does not receive
|
|
68
|
+
// workingDir or manifestOverride. Cleared alongside the risk cache.
|
|
69
|
+
const assessmentCache = new Map<string, RiskAssessment>();
|
|
70
|
+
|
|
71
|
+
function assessmentCacheKey(
|
|
72
|
+
toolName: string,
|
|
73
|
+
input: Record<string, unknown>,
|
|
74
|
+
): string {
|
|
75
|
+
const { reason: _reason, activity: _activity, ...cacheableInput } = input;
|
|
76
|
+
const inputJson = JSON.stringify(cacheableInput);
|
|
77
|
+
const hash = createHash("sha256").update(inputJson).digest("hex");
|
|
78
|
+
return `${toolName}\0${hash}`;
|
|
79
|
+
}
|
|
80
|
+
|
|
51
81
|
function riskCacheKey(
|
|
52
82
|
toolName: string,
|
|
53
83
|
input: Record<string, unknown>,
|
|
@@ -72,6 +102,7 @@ function riskCacheKey(
|
|
|
72
102
|
/** Clear the risk classification cache. Called when trust rules change. */
|
|
73
103
|
function clearRiskCache(): void {
|
|
74
104
|
riskCache.clear();
|
|
105
|
+
assessmentCache.clear();
|
|
75
106
|
}
|
|
76
107
|
|
|
77
108
|
function ensureRiskCacheInvalidationHook(): void {
|
|
@@ -82,319 +113,8 @@ function ensureRiskCacheInvalidationHook(): void {
|
|
|
82
113
|
onRulesChanged(clearRiskCache);
|
|
83
114
|
}
|
|
84
115
|
|
|
85
|
-
//
|
|
86
|
-
const
|
|
87
|
-
"ls",
|
|
88
|
-
"cat",
|
|
89
|
-
"head",
|
|
90
|
-
"tail",
|
|
91
|
-
"less",
|
|
92
|
-
"more",
|
|
93
|
-
"wc",
|
|
94
|
-
"file",
|
|
95
|
-
"stat",
|
|
96
|
-
"grep",
|
|
97
|
-
"rg",
|
|
98
|
-
"ag",
|
|
99
|
-
"ack",
|
|
100
|
-
"find",
|
|
101
|
-
"fd",
|
|
102
|
-
"which",
|
|
103
|
-
"where",
|
|
104
|
-
"whereis",
|
|
105
|
-
"type",
|
|
106
|
-
"echo",
|
|
107
|
-
"printf",
|
|
108
|
-
"date",
|
|
109
|
-
"cal",
|
|
110
|
-
"uptime",
|
|
111
|
-
"whoami",
|
|
112
|
-
"hostname",
|
|
113
|
-
"uname",
|
|
114
|
-
"pwd",
|
|
115
|
-
"realpath",
|
|
116
|
-
"dirname",
|
|
117
|
-
"basename",
|
|
118
|
-
"git",
|
|
119
|
-
"node",
|
|
120
|
-
"bun",
|
|
121
|
-
"deno",
|
|
122
|
-
"npm",
|
|
123
|
-
"npx",
|
|
124
|
-
"yarn",
|
|
125
|
-
"pnpm",
|
|
126
|
-
"python",
|
|
127
|
-
"python3",
|
|
128
|
-
"pip",
|
|
129
|
-
"pip3",
|
|
130
|
-
"man",
|
|
131
|
-
"help",
|
|
132
|
-
"info",
|
|
133
|
-
"env",
|
|
134
|
-
"printenv",
|
|
135
|
-
"set",
|
|
136
|
-
"diff",
|
|
137
|
-
"sort",
|
|
138
|
-
"uniq",
|
|
139
|
-
"cut",
|
|
140
|
-
"tr",
|
|
141
|
-
"tee",
|
|
142
|
-
"xargs",
|
|
143
|
-
"jq",
|
|
144
|
-
"yq",
|
|
145
|
-
"http",
|
|
146
|
-
"dig",
|
|
147
|
-
"nslookup",
|
|
148
|
-
"ping",
|
|
149
|
-
"tree",
|
|
150
|
-
"du",
|
|
151
|
-
"df",
|
|
152
|
-
]);
|
|
153
|
-
|
|
154
|
-
// High-risk shell programs / patterns
|
|
155
|
-
const HIGH_RISK_PROGRAMS = new Set([
|
|
156
|
-
"sudo",
|
|
157
|
-
"su",
|
|
158
|
-
"doas",
|
|
159
|
-
"dd",
|
|
160
|
-
"mkfs",
|
|
161
|
-
"fdisk",
|
|
162
|
-
"parted",
|
|
163
|
-
"mount",
|
|
164
|
-
"umount",
|
|
165
|
-
"systemctl",
|
|
166
|
-
"service",
|
|
167
|
-
"launchctl",
|
|
168
|
-
"useradd",
|
|
169
|
-
"userdel",
|
|
170
|
-
"usermod",
|
|
171
|
-
"groupadd",
|
|
172
|
-
"groupdel",
|
|
173
|
-
"iptables",
|
|
174
|
-
"ufw",
|
|
175
|
-
"firewall-cmd",
|
|
176
|
-
"reboot",
|
|
177
|
-
"shutdown",
|
|
178
|
-
"halt",
|
|
179
|
-
"poweroff",
|
|
180
|
-
"kill",
|
|
181
|
-
"killall",
|
|
182
|
-
"pkill",
|
|
183
|
-
]);
|
|
184
|
-
|
|
185
|
-
// Git subcommands that are low-risk (read-only)
|
|
186
|
-
const LOW_RISK_GIT_SUBCOMMANDS = new Set([
|
|
187
|
-
"status",
|
|
188
|
-
"log",
|
|
189
|
-
"diff",
|
|
190
|
-
"show",
|
|
191
|
-
"branch",
|
|
192
|
-
"tag",
|
|
193
|
-
"remote",
|
|
194
|
-
"stash",
|
|
195
|
-
"blame",
|
|
196
|
-
"shortlog",
|
|
197
|
-
"describe",
|
|
198
|
-
"rev-parse",
|
|
199
|
-
"ls-files",
|
|
200
|
-
"ls-tree",
|
|
201
|
-
"cat-file",
|
|
202
|
-
"reflog",
|
|
203
|
-
]);
|
|
204
|
-
|
|
205
|
-
/**
|
|
206
|
-
* Classify risk for `assistant` CLI subcommands. Multi-word subcommands
|
|
207
|
-
* (e.g. `assistant oauth token`) are matched by walking the positional args.
|
|
208
|
-
*/
|
|
209
|
-
function classifyAssistantSubcommand(args: string[]): RiskLevel {
|
|
210
|
-
const sub = firstPositionalArg(args);
|
|
211
|
-
if (!sub) return RiskLevel.Low;
|
|
212
|
-
|
|
213
|
-
if (sub === "oauth") {
|
|
214
|
-
const oauthSub = firstPositionalArg(args.slice(args.indexOf(sub) + 1));
|
|
215
|
-
if (oauthSub === "token") return RiskLevel.High;
|
|
216
|
-
if (oauthSub === "mode") {
|
|
217
|
-
// `oauth mode --set` is high risk; bare `oauth mode` (read) is low.
|
|
218
|
-
// Match both `--set value` (two tokens) and `--set=value` (one token).
|
|
219
|
-
if (args.some((a) => a === "--set" || a.startsWith("--set=")))
|
|
220
|
-
return RiskLevel.High;
|
|
221
|
-
return RiskLevel.Low;
|
|
222
|
-
}
|
|
223
|
-
if (oauthSub === "request") return RiskLevel.Medium;
|
|
224
|
-
if (oauthSub === "connect" || oauthSub === "disconnect")
|
|
225
|
-
return RiskLevel.Medium;
|
|
226
|
-
return RiskLevel.Low;
|
|
227
|
-
}
|
|
228
|
-
|
|
229
|
-
if (sub === "credentials") {
|
|
230
|
-
const credSub = firstPositionalArg(args.slice(args.indexOf(sub) + 1));
|
|
231
|
-
if (credSub === "reveal") return RiskLevel.High;
|
|
232
|
-
if (credSub === "set" || credSub === "delete") return RiskLevel.High;
|
|
233
|
-
return RiskLevel.Low;
|
|
234
|
-
}
|
|
235
|
-
|
|
236
|
-
if (sub === "keys") {
|
|
237
|
-
const keysSub = firstPositionalArg(args.slice(args.indexOf(sub) + 1));
|
|
238
|
-
if (keysSub === "set" || keysSub === "delete") return RiskLevel.High;
|
|
239
|
-
return RiskLevel.Low;
|
|
240
|
-
}
|
|
241
|
-
|
|
242
|
-
if (sub === "trust") {
|
|
243
|
-
const trustSub = firstPositionalArg(args.slice(args.indexOf(sub) + 1));
|
|
244
|
-
if (trustSub === "remove" || trustSub === "clear") return RiskLevel.High;
|
|
245
|
-
return RiskLevel.Low;
|
|
246
|
-
}
|
|
247
|
-
|
|
248
|
-
return RiskLevel.Low;
|
|
249
|
-
}
|
|
250
|
-
|
|
251
|
-
// Commands that wrap another program — the real program appears as the first
|
|
252
|
-
// non-flag argument. When one of these is the segment program we look through
|
|
253
|
-
// its args to find the effective program (e.g. `env curl …` → curl).
|
|
254
|
-
const WRAPPER_PROGRAMS = new Set([
|
|
255
|
-
"env",
|
|
256
|
-
"nice",
|
|
257
|
-
"nohup",
|
|
258
|
-
"time",
|
|
259
|
-
"command",
|
|
260
|
-
"exec",
|
|
261
|
-
"strace",
|
|
262
|
-
"ltrace",
|
|
263
|
-
"ionice",
|
|
264
|
-
"taskset",
|
|
265
|
-
"timeout",
|
|
266
|
-
]);
|
|
267
|
-
|
|
268
|
-
// `env` flags that consume the next positional argument as their value.
|
|
269
|
-
// Without this, `env -u curl echo` would incorrectly identify `curl` (the
|
|
270
|
-
// value of -u) as the wrapped program instead of `echo`.
|
|
271
|
-
const ENV_VALUE_FLAGS = new Set(["-u", "--unset", "-C", "--chdir"]);
|
|
272
|
-
|
|
273
|
-
// `timeout` flags that consume the next positional argument as their value.
|
|
274
|
-
const TIMEOUT_VALUE_FLAGS = new Set(["-s", "--signal", "-k", "--kill-after"]);
|
|
275
|
-
|
|
276
|
-
// Wrapper programs where the first non-flag positional argument is a
|
|
277
|
-
// configuration value (duration, CPU mask), not the wrapped program name.
|
|
278
|
-
// For these wrappers, the second non-flag positional is the real program.
|
|
279
|
-
const WRAPPER_SKIP_FIRST_POSITIONAL = new Set(["timeout", "taskset"]);
|
|
280
|
-
|
|
281
|
-
// `git` global flags that consume the next positional argument as their value.
|
|
282
|
-
// Without this, `git -C status commit` would incorrectly identify `status`
|
|
283
|
-
// (the directory path) as the subcommand instead of `commit`.
|
|
284
|
-
const GIT_VALUE_FLAGS = new Set([
|
|
285
|
-
"-C",
|
|
286
|
-
"-c",
|
|
287
|
-
"--git-dir",
|
|
288
|
-
"--work-tree",
|
|
289
|
-
"--namespace",
|
|
290
|
-
"--super-prefix",
|
|
291
|
-
"--config-env",
|
|
292
|
-
]);
|
|
293
|
-
|
|
294
|
-
/**
|
|
295
|
-
* Return the first non-flag argument from an argument list, optionally
|
|
296
|
-
* skipping value-taking flags. Flags are arguments that start with `-`.
|
|
297
|
-
* This is used to skip global options (e.g. `--verbose`, `-h`, `-C <path>`)
|
|
298
|
-
* when extracting the subcommand from CLIs like `git`, `vellum`, and
|
|
299
|
-
* `assistant`.
|
|
300
|
-
*
|
|
301
|
-
* When `valueFlags` is provided, any flag in that set causes the next
|
|
302
|
-
* argument to be skipped as well (it is the flag's value, not a positional).
|
|
303
|
-
*/
|
|
304
|
-
function firstPositionalArg(
|
|
305
|
-
args: string[],
|
|
306
|
-
valueFlags?: Set<string>,
|
|
307
|
-
): string | undefined {
|
|
308
|
-
for (let i = 0; i < args.length; i++) {
|
|
309
|
-
const arg = args[i];
|
|
310
|
-
if (arg.startsWith("-")) {
|
|
311
|
-
if (valueFlags?.has(arg)) i++; // skip the next arg (the flag's value)
|
|
312
|
-
continue;
|
|
313
|
-
}
|
|
314
|
-
return arg;
|
|
315
|
-
}
|
|
316
|
-
return undefined;
|
|
317
|
-
}
|
|
318
|
-
|
|
319
|
-
// Bare filenames that `rm` is allowed to delete at Medium risk (instead of
|
|
320
|
-
// High) so workspace-scoped allow rules can approve them without the
|
|
321
|
-
// dangerous `allowHighRisk` flag. Only matches when the args contain no
|
|
322
|
-
// flags and exactly one of these filenames.
|
|
323
|
-
const RM_SAFE_BARE_FILES = new Set(["BOOTSTRAP.md", "UPDATES.md"]);
|
|
324
|
-
|
|
325
|
-
function isRmOfKnownSafeFile(args: string[]): boolean {
|
|
326
|
-
if (args.length !== 1) return false;
|
|
327
|
-
const target = args[0];
|
|
328
|
-
if (target.startsWith("-") || target.includes("/")) return false;
|
|
329
|
-
return RM_SAFE_BARE_FILES.has(target);
|
|
330
|
-
}
|
|
331
|
-
|
|
332
|
-
/**
|
|
333
|
-
* Given a segment whose program is a known wrapper, return the first
|
|
334
|
-
* non-flag argument (i.e. the wrapped program name). Returns `undefined`
|
|
335
|
-
* when no suitable argument is found.
|
|
336
|
-
*
|
|
337
|
-
* Handles `env` specially: skips `VAR=value` pairs and value-taking flags
|
|
338
|
-
* like `-u NAME` and `-C DIR`.
|
|
339
|
-
*
|
|
340
|
-
* Handles `timeout` and `taskset` specially: their first non-flag positional
|
|
341
|
-
* argument is a duration or CPU mask, not the wrapped program. The second
|
|
342
|
-
* non-flag positional is the real program.
|
|
343
|
-
*/
|
|
344
|
-
function getWrappedProgram(seg: {
|
|
345
|
-
program: string;
|
|
346
|
-
args: string[];
|
|
347
|
-
}): string | undefined {
|
|
348
|
-
const isEnv = seg.program === "env";
|
|
349
|
-
const isTimeout = seg.program === "timeout";
|
|
350
|
-
const skipFirst = WRAPPER_SKIP_FIRST_POSITIONAL.has(seg.program);
|
|
351
|
-
let skippedFirstPositional = false;
|
|
352
|
-
for (let i = 0; i < seg.args.length; i++) {
|
|
353
|
-
const arg = seg.args[i];
|
|
354
|
-
if (arg.startsWith("-")) {
|
|
355
|
-
if (isEnv && ENV_VALUE_FLAGS.has(arg)) i++; // skip the value argument
|
|
356
|
-
if (isTimeout && TIMEOUT_VALUE_FLAGS.has(arg)) i++; // skip the value argument
|
|
357
|
-
continue;
|
|
358
|
-
}
|
|
359
|
-
if (isEnv && arg.includes("=")) continue; // skip env VAR=value pairs
|
|
360
|
-
if (skipFirst && !skippedFirstPositional) {
|
|
361
|
-
skippedFirstPositional = true;
|
|
362
|
-
continue; // skip the duration/CPU mask
|
|
363
|
-
}
|
|
364
|
-
return arg;
|
|
365
|
-
}
|
|
366
|
-
return undefined;
|
|
367
|
-
}
|
|
368
|
-
|
|
369
|
-
/**
|
|
370
|
-
* Like `getWrappedProgram`, but also returns the remaining args after the
|
|
371
|
-
* wrapped program name. This allows callers to propagate subcommand-aware
|
|
372
|
-
* classification (e.g. `env assistant oauth token` → classify `oauth token`).
|
|
373
|
-
*/
|
|
374
|
-
function getWrappedProgramWithArgs(seg: {
|
|
375
|
-
program: string;
|
|
376
|
-
args: string[];
|
|
377
|
-
}): { program: string; args: string[] } | undefined {
|
|
378
|
-
const isEnv = seg.program === "env";
|
|
379
|
-
const isTimeout = seg.program === "timeout";
|
|
380
|
-
const skipFirst = WRAPPER_SKIP_FIRST_POSITIONAL.has(seg.program);
|
|
381
|
-
let skippedFirstPositional = false;
|
|
382
|
-
for (let i = 0; i < seg.args.length; i++) {
|
|
383
|
-
const arg = seg.args[i];
|
|
384
|
-
if (arg.startsWith("-")) {
|
|
385
|
-
if (isEnv && ENV_VALUE_FLAGS.has(arg)) i++;
|
|
386
|
-
if (isTimeout && TIMEOUT_VALUE_FLAGS.has(arg)) i++;
|
|
387
|
-
continue;
|
|
388
|
-
}
|
|
389
|
-
if (isEnv && arg.includes("=")) continue;
|
|
390
|
-
if (skipFirst && !skippedFirstPositional) {
|
|
391
|
-
skippedFirstPositional = true;
|
|
392
|
-
continue; // skip the duration/CPU mask
|
|
393
|
-
}
|
|
394
|
-
return { program: arg, args: seg.args.slice(i + 1) };
|
|
395
|
-
}
|
|
396
|
-
return undefined;
|
|
397
|
-
}
|
|
116
|
+
// ── Approval policy singleton ────────────────────────────────────────────────
|
|
117
|
+
const defaultApprovalPolicy = new DefaultApprovalPolicy();
|
|
398
118
|
|
|
399
119
|
function getStringField(
|
|
400
120
|
input: Record<string, unknown>,
|
|
@@ -578,11 +298,7 @@ async function buildCommandCandidates(
|
|
|
578
298
|
return [`${toolName}:${skillId}`];
|
|
579
299
|
}
|
|
580
300
|
|
|
581
|
-
if (
|
|
582
|
-
toolName === "web_fetch" ||
|
|
583
|
-
toolName === "browser_navigate" ||
|
|
584
|
-
toolName === "network_request"
|
|
585
|
-
) {
|
|
301
|
+
if (toolName === "web_fetch" || toolName === "network_request") {
|
|
586
302
|
const rawUrl = getStringField(input, "url").trim();
|
|
587
303
|
const candidates: string[] = [];
|
|
588
304
|
|
|
@@ -659,7 +375,7 @@ export async function classifyRisk(
|
|
|
659
375
|
preParsed?: ParsedCommand,
|
|
660
376
|
manifestOverride?: ManifestOverride,
|
|
661
377
|
signal?: AbortSignal,
|
|
662
|
-
): Promise<
|
|
378
|
+
): Promise<RiskClassification> {
|
|
663
379
|
signal?.throwIfAborted();
|
|
664
380
|
ensureRiskCacheInvalidationHook();
|
|
665
381
|
|
|
@@ -678,13 +394,98 @@ export async function classifyRisk(
|
|
|
678
394
|
}
|
|
679
395
|
}
|
|
680
396
|
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
397
|
+
// ── Bash/host_bash: delegate to the registry-driven BashRiskClassifier ────
|
|
398
|
+
let result: RiskClassification;
|
|
399
|
+
let classifierAssessment: RiskAssessment | undefined;
|
|
400
|
+
if (toolName === "bash" || toolName === "host_bash") {
|
|
401
|
+
const command = ((input.command as string) ?? "").trim();
|
|
402
|
+
if (!command) {
|
|
403
|
+
result = { level: RiskLevel.Low };
|
|
404
|
+
} else {
|
|
405
|
+
const assessment = await bashRiskClassifier.classify({
|
|
406
|
+
command,
|
|
407
|
+
toolName: toolName as "bash" | "host_bash",
|
|
408
|
+
});
|
|
409
|
+
classifierAssessment = assessment;
|
|
410
|
+
result = {
|
|
411
|
+
level: riskToRiskLevel(assessment.riskLevel),
|
|
412
|
+
reason: assessment.reason,
|
|
413
|
+
};
|
|
414
|
+
}
|
|
415
|
+
}
|
|
416
|
+
// ── File tools: delegate to FileRiskClassifier ──────────────────────────
|
|
417
|
+
else if (
|
|
418
|
+
[
|
|
419
|
+
"file_read",
|
|
420
|
+
"file_write",
|
|
421
|
+
"file_edit",
|
|
422
|
+
"host_file_read",
|
|
423
|
+
"host_file_write",
|
|
424
|
+
"host_file_edit",
|
|
425
|
+
].includes(toolName)
|
|
426
|
+
) {
|
|
427
|
+
const filePath = getStringField(input, "path", "file_path");
|
|
428
|
+
const isHostTool = toolName.startsWith("host_");
|
|
429
|
+
const assessment = await fileRiskClassifier.classify({
|
|
430
|
+
toolName: toolName as
|
|
431
|
+
| "file_read"
|
|
432
|
+
| "file_write"
|
|
433
|
+
| "file_edit"
|
|
434
|
+
| "host_file_read"
|
|
435
|
+
| "host_file_write"
|
|
436
|
+
| "host_file_edit",
|
|
437
|
+
filePath,
|
|
438
|
+
workingDir: isHostTool ? "/" : (workingDir ?? process.cwd()),
|
|
439
|
+
});
|
|
440
|
+
classifierAssessment = assessment;
|
|
441
|
+
result = {
|
|
442
|
+
level: riskToRiskLevel(assessment.riskLevel),
|
|
443
|
+
reason: assessment.reason,
|
|
444
|
+
};
|
|
445
|
+
}
|
|
446
|
+
// ── Web tools: delegate to WebRiskClassifier ────────────────────────────
|
|
447
|
+
else if (["web_fetch", "network_request", "web_search"].includes(toolName)) {
|
|
448
|
+
const assessment = await webRiskClassifier.classify({
|
|
449
|
+
toolName: toolName as "web_fetch" | "network_request" | "web_search",
|
|
450
|
+
url: getStringField(input, "url"),
|
|
451
|
+
allowPrivateNetwork: input.allow_private_network === true,
|
|
452
|
+
});
|
|
453
|
+
classifierAssessment = assessment;
|
|
454
|
+
result = {
|
|
455
|
+
level: riskToRiskLevel(assessment.riskLevel),
|
|
456
|
+
reason: assessment.reason,
|
|
457
|
+
};
|
|
458
|
+
}
|
|
459
|
+
// ── Skill tools: delegate to SkillLoadRiskClassifier ────────────────────
|
|
460
|
+
else if (
|
|
461
|
+
["skill_load", "scaffold_managed_skill", "delete_managed_skill"].includes(
|
|
462
|
+
toolName,
|
|
463
|
+
)
|
|
464
|
+
) {
|
|
465
|
+
const assessment = await skillLoadRiskClassifier.classify({
|
|
466
|
+
toolName: toolName as
|
|
467
|
+
| "skill_load"
|
|
468
|
+
| "scaffold_managed_skill"
|
|
469
|
+
| "delete_managed_skill",
|
|
470
|
+
skillSelector: getStringField(input, "skill", "skill_id").trim(),
|
|
471
|
+
});
|
|
472
|
+
classifierAssessment = assessment;
|
|
473
|
+
result = {
|
|
474
|
+
level: riskToRiskLevel(assessment.riskLevel),
|
|
475
|
+
reason: assessment.reason,
|
|
476
|
+
};
|
|
477
|
+
}
|
|
478
|
+
// ── Remaining tools: fall through to registry-based classification ──────
|
|
479
|
+
else {
|
|
480
|
+
result = {
|
|
481
|
+
level: await classifyRiskFromRegistry(
|
|
482
|
+
toolName,
|
|
483
|
+
input,
|
|
484
|
+
workingDir,
|
|
485
|
+
manifestOverride,
|
|
486
|
+
),
|
|
487
|
+
};
|
|
488
|
+
}
|
|
688
489
|
|
|
689
490
|
// Proxied bash commands route through the credential proxy which handles
|
|
690
491
|
// per-request approval separately. Cap the bash tool's own risk at Medium
|
|
@@ -692,9 +493,9 @@ export async function classifyRisk(
|
|
|
692
493
|
if (
|
|
693
494
|
toolName === "bash" &&
|
|
694
495
|
input.network_mode === "proxied" &&
|
|
695
|
-
result === RiskLevel.High
|
|
496
|
+
result.level === RiskLevel.High
|
|
696
497
|
) {
|
|
697
|
-
result = RiskLevel.Medium;
|
|
498
|
+
result = { level: RiskLevel.Medium, reason: result.reason };
|
|
698
499
|
}
|
|
699
500
|
|
|
700
501
|
if (cacheKey) {
|
|
@@ -705,237 +506,26 @@ export async function classifyRisk(
|
|
|
705
506
|
riskCache.set(cacheKey, result);
|
|
706
507
|
}
|
|
707
508
|
|
|
509
|
+
// Store the full assessment in a separate cache keyed on (toolName, input)
|
|
510
|
+
// so generateAllowlistOptions() can retrieve classifier-produced options.
|
|
511
|
+
if (classifierAssessment) {
|
|
512
|
+
const aKey = assessmentCacheKey(toolName, input);
|
|
513
|
+
if (assessmentCache.size >= RISK_CACHE_MAX) {
|
|
514
|
+
const oldest = assessmentCache.keys().next().value;
|
|
515
|
+
if (oldest !== undefined) assessmentCache.delete(oldest);
|
|
516
|
+
}
|
|
517
|
+
assessmentCache.set(aKey, classifierAssessment);
|
|
518
|
+
}
|
|
519
|
+
|
|
708
520
|
return result;
|
|
709
521
|
}
|
|
710
522
|
|
|
711
|
-
async function
|
|
523
|
+
async function classifyRiskFromRegistry(
|
|
712
524
|
toolName: string,
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
preParsed?: ParsedCommand,
|
|
525
|
+
_input: Record<string, unknown>,
|
|
526
|
+
_workingDir?: string,
|
|
716
527
|
manifestOverride?: ManifestOverride,
|
|
717
528
|
): Promise<RiskLevel> {
|
|
718
|
-
if (toolName === "file_read") {
|
|
719
|
-
const filePath = getStringField(input, "path", "file_path");
|
|
720
|
-
if (isActorTokenSigningKeyPath(filePath, workingDir)) {
|
|
721
|
-
return RiskLevel.High;
|
|
722
|
-
}
|
|
723
|
-
return RiskLevel.Low;
|
|
724
|
-
}
|
|
725
|
-
if (toolName === "file_write" || toolName === "file_edit") {
|
|
726
|
-
const filePath = getStringField(input, "path", "file_path");
|
|
727
|
-
if (
|
|
728
|
-
filePath &&
|
|
729
|
-
isSkillSourcePath(
|
|
730
|
-
resolve(workingDir ?? process.cwd(), filePath),
|
|
731
|
-
getConfig().skills.load.extraDirs,
|
|
732
|
-
)
|
|
733
|
-
) {
|
|
734
|
-
return RiskLevel.High;
|
|
735
|
-
}
|
|
736
|
-
if (filePath) {
|
|
737
|
-
const normalizedHooksDir = normalizeDirPath(getWorkspaceHooksDir());
|
|
738
|
-
const normalizedPath = normalizeFilePath(
|
|
739
|
-
resolve(workingDir ?? process.cwd(), filePath),
|
|
740
|
-
);
|
|
741
|
-
const hooksDirNoTrailingSlash = normalizedHooksDir.slice(0, -1);
|
|
742
|
-
if (
|
|
743
|
-
normalizedPath === hooksDirNoTrailingSlash ||
|
|
744
|
-
normalizedPath.startsWith(normalizedHooksDir)
|
|
745
|
-
) {
|
|
746
|
-
return RiskLevel.High;
|
|
747
|
-
}
|
|
748
|
-
}
|
|
749
|
-
return RiskLevel.Low;
|
|
750
|
-
}
|
|
751
|
-
if (toolName === "web_search") return RiskLevel.Low;
|
|
752
|
-
if (toolName === "web_fetch") {
|
|
753
|
-
// Private-network fetches are High risk so that blanket allow rules
|
|
754
|
-
// (including the starter bundle) cannot silently bypass the prompt.
|
|
755
|
-
return input.allow_private_network === true
|
|
756
|
-
? RiskLevel.High
|
|
757
|
-
: RiskLevel.Low;
|
|
758
|
-
}
|
|
759
|
-
if (toolName === "browser_navigate") {
|
|
760
|
-
return input.allow_private_network === true
|
|
761
|
-
? RiskLevel.High
|
|
762
|
-
: RiskLevel.Low;
|
|
763
|
-
}
|
|
764
|
-
// All other browser tools are low risk — the browser is sandboxed and user-visible.
|
|
765
|
-
if (toolName.startsWith("browser_")) return RiskLevel.Low;
|
|
766
|
-
// Proxy-authenticated network requests are Medium risk — they carry injected
|
|
767
|
-
// credentials and the user should approve the target host/origin.
|
|
768
|
-
if (toolName === "network_request") return RiskLevel.Medium;
|
|
769
|
-
if (toolName === "skill_load") return RiskLevel.Low;
|
|
770
|
-
|
|
771
|
-
// Skill mutation tools are always High risk — they write or delete persistent
|
|
772
|
-
// skill source code. These tools moved from core tool registry to bundled
|
|
773
|
-
// skills, but their security classification must remain High regardless of
|
|
774
|
-
// whether they appear in the tool registry.
|
|
775
|
-
if (
|
|
776
|
-
toolName === "scaffold_managed_skill" ||
|
|
777
|
-
toolName === "delete_managed_skill"
|
|
778
|
-
) {
|
|
779
|
-
return RiskLevel.High;
|
|
780
|
-
}
|
|
781
|
-
|
|
782
|
-
// Escalate host file mutations targeting skill source paths to High risk.
|
|
783
|
-
// The host variants fall through to the tool registry (Medium) by default,
|
|
784
|
-
// but writing to skill source code is a privilege-escalation vector.
|
|
785
|
-
if (toolName === "host_file_write" || toolName === "host_file_edit") {
|
|
786
|
-
const filePath = getStringField(input, "path", "file_path");
|
|
787
|
-
if (
|
|
788
|
-
filePath &&
|
|
789
|
-
isSkillSourcePath(resolve(filePath), getConfig().skills.load.extraDirs)
|
|
790
|
-
) {
|
|
791
|
-
return RiskLevel.High;
|
|
792
|
-
}
|
|
793
|
-
if (filePath) {
|
|
794
|
-
const normalizedHooksDir = normalizeDirPath(getWorkspaceHooksDir());
|
|
795
|
-
const normalizedPath = normalizeFilePath(resolve(filePath));
|
|
796
|
-
const hooksDirNoTrailingSlash = normalizedHooksDir.slice(0, -1);
|
|
797
|
-
if (
|
|
798
|
-
normalizedPath === hooksDirNoTrailingSlash ||
|
|
799
|
-
normalizedPath.startsWith(normalizedHooksDir)
|
|
800
|
-
) {
|
|
801
|
-
return RiskLevel.High;
|
|
802
|
-
}
|
|
803
|
-
}
|
|
804
|
-
// Fall through to the tool registry default (Medium) below.
|
|
805
|
-
}
|
|
806
|
-
|
|
807
|
-
if (toolName === "bash" || toolName === "host_bash") {
|
|
808
|
-
const command = (input.command as string) ?? "";
|
|
809
|
-
if (!command.trim()) return RiskLevel.Low;
|
|
810
|
-
|
|
811
|
-
const parsed = preParsed ?? (await cachedParse(command));
|
|
812
|
-
|
|
813
|
-
// Dangerous patterns → High
|
|
814
|
-
if (parsed.dangerousPatterns.length > 0) return RiskLevel.High;
|
|
815
|
-
|
|
816
|
-
// Opaque constructs → at least Medium (never Low)
|
|
817
|
-
if (parsed.hasOpaqueConstructs) return RiskLevel.Medium;
|
|
818
|
-
|
|
819
|
-
// Check each segment
|
|
820
|
-
let maxRisk = RiskLevel.Low;
|
|
821
|
-
|
|
822
|
-
for (const seg of parsed.segments) {
|
|
823
|
-
const prog = seg.program;
|
|
824
|
-
|
|
825
|
-
if (HIGH_RISK_PROGRAMS.has(prog)) return RiskLevel.High;
|
|
826
|
-
|
|
827
|
-
if (prog === "rm") {
|
|
828
|
-
// Only downgrade rm of known safe workspace files for sandboxed bash.
|
|
829
|
-
// host_bash has a global ask rule that would prompt Medium-risk
|
|
830
|
-
// commands, so rm on the host must always require explicit approval.
|
|
831
|
-
if (toolName === "bash" && isRmOfKnownSafeFile(seg.args)) {
|
|
832
|
-
maxRisk = RiskLevel.Medium;
|
|
833
|
-
continue;
|
|
834
|
-
}
|
|
835
|
-
return RiskLevel.High;
|
|
836
|
-
}
|
|
837
|
-
|
|
838
|
-
if (
|
|
839
|
-
prog === "chmod" ||
|
|
840
|
-
prog === "chown" ||
|
|
841
|
-
prog === "chgrp" ||
|
|
842
|
-
prog === "sed" ||
|
|
843
|
-
prog === "awk"
|
|
844
|
-
) {
|
|
845
|
-
maxRisk = RiskLevel.Medium;
|
|
846
|
-
continue;
|
|
847
|
-
}
|
|
848
|
-
|
|
849
|
-
// curl/wget can download and execute arbitrary code from the internet.
|
|
850
|
-
// Also catch wrapped invocations like `env curl …` or `nice wget …`.
|
|
851
|
-
if (prog === "curl" || prog === "wget") {
|
|
852
|
-
maxRisk = RiskLevel.Medium;
|
|
853
|
-
continue;
|
|
854
|
-
}
|
|
855
|
-
|
|
856
|
-
if (WRAPPER_PROGRAMS.has(prog)) {
|
|
857
|
-
// `command -v` and `command -V` are read-only lookups (print where
|
|
858
|
-
// a command lives) — don't escalate to high risk for those.
|
|
859
|
-
if (
|
|
860
|
-
prog === "command" &&
|
|
861
|
-
seg.args.length > 0 &&
|
|
862
|
-
(seg.args[0] === "-v" || seg.args[0] === "-V")
|
|
863
|
-
) {
|
|
864
|
-
continue;
|
|
865
|
-
}
|
|
866
|
-
const wrapped = getWrappedProgram(seg);
|
|
867
|
-
if (wrapped === "rm") return RiskLevel.High;
|
|
868
|
-
if (wrapped && HIGH_RISK_PROGRAMS.has(wrapped)) return RiskLevel.High;
|
|
869
|
-
if (wrapped === "curl" || wrapped === "wget") {
|
|
870
|
-
maxRisk = RiskLevel.Medium;
|
|
871
|
-
continue;
|
|
872
|
-
}
|
|
873
|
-
// Propagate subcommand-aware classification for wrapped git/assistant
|
|
874
|
-
if (wrapped === "git") {
|
|
875
|
-
const wrappedWithArgs = getWrappedProgramWithArgs(seg);
|
|
876
|
-
if (wrappedWithArgs) {
|
|
877
|
-
const subcommand = firstPositionalArg(
|
|
878
|
-
wrappedWithArgs.args,
|
|
879
|
-
GIT_VALUE_FLAGS,
|
|
880
|
-
);
|
|
881
|
-
if (subcommand && LOW_RISK_GIT_SUBCOMMANDS.has(subcommand)) {
|
|
882
|
-
continue;
|
|
883
|
-
}
|
|
884
|
-
maxRisk = RiskLevel.Medium;
|
|
885
|
-
continue;
|
|
886
|
-
}
|
|
887
|
-
}
|
|
888
|
-
if (wrapped === "assistant") {
|
|
889
|
-
const wrappedWithArgs = getWrappedProgramWithArgs(seg);
|
|
890
|
-
if (wrappedWithArgs) {
|
|
891
|
-
const assistantRisk = classifyAssistantSubcommand(
|
|
892
|
-
wrappedWithArgs.args,
|
|
893
|
-
);
|
|
894
|
-
if (assistantRisk === RiskLevel.High) return RiskLevel.High;
|
|
895
|
-
if (assistantRisk === RiskLevel.Medium) {
|
|
896
|
-
maxRisk = RiskLevel.Medium;
|
|
897
|
-
}
|
|
898
|
-
continue;
|
|
899
|
-
}
|
|
900
|
-
}
|
|
901
|
-
}
|
|
902
|
-
|
|
903
|
-
if (prog === "git") {
|
|
904
|
-
const subcommand = firstPositionalArg(seg.args, GIT_VALUE_FLAGS);
|
|
905
|
-
if (subcommand && LOW_RISK_GIT_SUBCOMMANDS.has(subcommand)) {
|
|
906
|
-
// Stay at current risk
|
|
907
|
-
continue;
|
|
908
|
-
}
|
|
909
|
-
// Non-read-only git commands are medium
|
|
910
|
-
maxRisk = RiskLevel.Medium;
|
|
911
|
-
continue;
|
|
912
|
-
}
|
|
913
|
-
|
|
914
|
-
if (prog === "assistant") {
|
|
915
|
-
const assistantRisk = classifyAssistantSubcommand(seg.args);
|
|
916
|
-
if (assistantRisk === RiskLevel.High) return RiskLevel.High;
|
|
917
|
-
if (assistantRisk === RiskLevel.Medium) {
|
|
918
|
-
maxRisk = RiskLevel.Medium;
|
|
919
|
-
}
|
|
920
|
-
continue;
|
|
921
|
-
}
|
|
922
|
-
|
|
923
|
-
if (!LOW_RISK_PROGRAMS.has(prog)) {
|
|
924
|
-
// Unknown program → medium
|
|
925
|
-
if (maxRisk === RiskLevel.Low) {
|
|
926
|
-
maxRisk = RiskLevel.Medium;
|
|
927
|
-
}
|
|
928
|
-
}
|
|
929
|
-
}
|
|
930
|
-
|
|
931
|
-
// If no segments could be extracted, treat as opaque
|
|
932
|
-
if (parsed.segments.length === 0) {
|
|
933
|
-
return RiskLevel.Medium;
|
|
934
|
-
}
|
|
935
|
-
|
|
936
|
-
return maxRisk;
|
|
937
|
-
}
|
|
938
|
-
|
|
939
529
|
// Check the tool registry for a declared default risk level
|
|
940
530
|
const tool = getTool(toolName);
|
|
941
531
|
if (tool) return tool.defaultRiskLevel;
|
|
@@ -955,21 +545,6 @@ async function classifyRiskUncached(
|
|
|
955
545
|
return RiskLevel.Medium;
|
|
956
546
|
}
|
|
957
547
|
|
|
958
|
-
function isActorTokenSigningKeyPath(
|
|
959
|
-
filePath: string | undefined,
|
|
960
|
-
workingDir?: string,
|
|
961
|
-
): boolean {
|
|
962
|
-
if (!filePath) return false;
|
|
963
|
-
const cwd = workingDir ?? process.cwd();
|
|
964
|
-
const resolvedPath = resolve(cwd, filePath);
|
|
965
|
-
const signingKeyPaths = [
|
|
966
|
-
join(homedir(), ".vellum", "protected", "actor-token-signing-key"),
|
|
967
|
-
join(getDeprecatedDir(), "actor-token-signing-key"),
|
|
968
|
-
resolve(cwd, "deprecated", "actor-token-signing-key"),
|
|
969
|
-
];
|
|
970
|
-
return signingKeyPaths.includes(resolvedPath);
|
|
971
|
-
}
|
|
972
|
-
|
|
973
548
|
export async function check(
|
|
974
549
|
toolName: string,
|
|
975
550
|
input: Record<string, unknown>,
|
|
@@ -989,7 +564,7 @@ export async function check(
|
|
|
989
564
|
}
|
|
990
565
|
}
|
|
991
566
|
|
|
992
|
-
const risk = await classifyRisk(
|
|
567
|
+
const { level: risk, reason: riskReason } = await classifyRisk(
|
|
993
568
|
toolName,
|
|
994
569
|
input,
|
|
995
570
|
workingDir,
|
|
@@ -1014,129 +589,55 @@ export async function check(
|
|
|
1014
589
|
policyContext,
|
|
1015
590
|
);
|
|
1016
591
|
|
|
1017
|
-
//
|
|
1018
|
-
|
|
1019
|
-
|
|
1020
|
-
|
|
1021
|
-
|
|
1022
|
-
|
|
1023
|
-
|
|
1024
|
-
|
|
1025
|
-
|
|
1026
|
-
|
|
1027
|
-
|
|
1028
|
-
|
|
1029
|
-
|
|
1030
|
-
|
|
1031
|
-
|
|
1032
|
-
|
|
1033
|
-
|
|
1034
|
-
|
|
1035
|
-
|
|
1036
|
-
|
|
1037
|
-
|
|
1038
|
-
|
|
1039
|
-
|
|
1040
|
-
|
|
1041
|
-
|
|
1042
|
-
|
|
1043
|
-
|
|
1044
|
-
|
|
1045
|
-
|
|
1046
|
-
|
|
1047
|
-
|
|
1048
|
-
|
|
1049
|
-
|
|
1050
|
-
|
|
1051
|
-
|
|
1052
|
-
|
|
1053
|
-
|
|
1054
|
-
|
|
1055
|
-
|
|
1056
|
-
|
|
1057
|
-
|
|
1058
|
-
// Third-party skill-origin tools default to prompting when no trust rule
|
|
1059
|
-
// matches, regardless of risk level. Bundled skill tools are first-party
|
|
1060
|
-
// and trusted, so they fall through to the normal risk-based policy.
|
|
1061
|
-
// When manifestOverride is present, the tool comes from a skill manifest
|
|
1062
|
-
// but isn't registered — treat it as a third-party skill tool.
|
|
1063
|
-
if (!matchedRule) {
|
|
1064
|
-
const tool = getTool(toolName);
|
|
1065
|
-
if (tool?.origin === "skill" && !tool.ownerSkillBundled) {
|
|
1066
|
-
return {
|
|
1067
|
-
decision: "prompt",
|
|
1068
|
-
reason: "Skill tool: requires approval by default",
|
|
1069
|
-
};
|
|
1070
|
-
}
|
|
1071
|
-
if (!tool && manifestOverride) {
|
|
1072
|
-
return {
|
|
1073
|
-
decision: "prompt",
|
|
1074
|
-
reason: "Skill tool: requires approval by default",
|
|
1075
|
-
};
|
|
1076
|
-
}
|
|
1077
|
-
}
|
|
1078
|
-
|
|
1079
|
-
// In strict mode, every tool without an explicit matching rule must be
|
|
1080
|
-
// prompted — there is no implicit auto-allow for any risk level.
|
|
1081
|
-
// This explicitly covers skill_load: activating a skill can grant the
|
|
1082
|
-
// agent new capabilities, so in strict mode users must approve each
|
|
1083
|
-
// skill load via an exact-version or wildcard trust rule.
|
|
1084
|
-
const permissionsMode = getConfig().permissions.mode;
|
|
1085
|
-
|
|
1086
|
-
if (permissionsMode === "strict" && !matchedRule) {
|
|
1087
|
-
return {
|
|
1088
|
-
decision: "prompt",
|
|
1089
|
-
reason: `Strict mode: no matching rule, requires approval`,
|
|
1090
|
-
};
|
|
1091
|
-
}
|
|
1092
|
-
|
|
1093
|
-
// Workspace mode: auto-allow workspace-scoped operations that don't have
|
|
1094
|
-
// an explicit rule, but only when risk is Low. Medium and High risk operations
|
|
1095
|
-
// fall through to risk-based policy and always require approval.
|
|
1096
|
-
if (
|
|
1097
|
-
permissionsMode === "workspace" &&
|
|
1098
|
-
!matchedRule &&
|
|
1099
|
-
risk === RiskLevel.Low
|
|
1100
|
-
) {
|
|
1101
|
-
// Outside a container, bash runs on the host — don't auto-allow
|
|
1102
|
-
if (toolName === "bash" && !getIsContainerized()) {
|
|
1103
|
-
// Fall through to risk-based policy below
|
|
1104
|
-
} else if (isWorkspaceScopedInvocation(toolName, input, workingDir)) {
|
|
1105
|
-
return {
|
|
1106
|
-
decision: "allow",
|
|
1107
|
-
reason: "Workspace mode: workspace-scoped operation auto-allowed",
|
|
1108
|
-
};
|
|
1109
|
-
}
|
|
1110
|
-
}
|
|
1111
|
-
|
|
1112
|
-
// Auto-allow low-risk bundled skill tools even without explicit trust rules.
|
|
1113
|
-
// These are first-party tools with a vetted risk declaration — applying the
|
|
1114
|
-
// same policy as the per-tool default allow rules for browser tools, but
|
|
1115
|
-
// generically so every new bundled skill benefits automatically.
|
|
1116
|
-
// This block must come AFTER the strict mode check so that strict mode
|
|
1117
|
-
// still prompts for bundled skill tools without explicit rules.
|
|
1118
|
-
if (!matchedRule && risk === RiskLevel.Low) {
|
|
1119
|
-
const tool = getTool(toolName);
|
|
1120
|
-
if (tool?.origin === "skill" && tool.ownerSkillBundled) {
|
|
1121
|
-
return {
|
|
1122
|
-
decision: "allow",
|
|
1123
|
-
reason: "Bundled skill tool: low risk, auto-allowed",
|
|
1124
|
-
};
|
|
592
|
+
// Build approval context from local variables
|
|
593
|
+
const tool = getTool(toolName);
|
|
594
|
+
const config = getConfig();
|
|
595
|
+
const resolvedThreshold = resolveThreshold(
|
|
596
|
+
config.permissions.autoApproveUpTo,
|
|
597
|
+
policyContext?.executionContext,
|
|
598
|
+
);
|
|
599
|
+
const approvalContext: ApprovalContext = {
|
|
600
|
+
riskLevel: risk,
|
|
601
|
+
toolName,
|
|
602
|
+
matchedRule: matchedRule ?? undefined,
|
|
603
|
+
permissionsMode: config.permissions.mode,
|
|
604
|
+
isContainerized: getIsContainerized(),
|
|
605
|
+
isWorkspaceScoped:
|
|
606
|
+
risk === RiskLevel.Low
|
|
607
|
+
? isWorkspaceScopedInvocation(toolName, input, workingDir)
|
|
608
|
+
: false,
|
|
609
|
+
toolOrigin:
|
|
610
|
+
tool?.origin === "skill" ? "skill" : tool ? "builtin" : undefined,
|
|
611
|
+
isSkillBundled: tool?.ownerSkillBundled ?? false,
|
|
612
|
+
hasManifestOverride: !!manifestOverride,
|
|
613
|
+
autoApproveUpTo: resolvedThreshold,
|
|
614
|
+
};
|
|
615
|
+
|
|
616
|
+
// Delegate the allow/prompt/deny decision to the approval policy
|
|
617
|
+
const approvalDecision = defaultApprovalPolicy.evaluate(approvalContext);
|
|
618
|
+
|
|
619
|
+
// Enrich the reason with the classifier's explanation when available.
|
|
620
|
+
// For risk-based fallback decisions (prompt/deny from High/Medium risk),
|
|
621
|
+
// incorporate the classifier reason so the user sees *why* the command
|
|
622
|
+
// was classified at that level (e.g. "High risk (Recursive force delete): requires approval").
|
|
623
|
+
let enrichedReason = approvalDecision.reason;
|
|
624
|
+
if (riskReason && !approvalDecision.matchedRule) {
|
|
625
|
+
const riskLabelMatch = enrichedReason.match(
|
|
626
|
+
/^(High|Medium|Low|high|medium|low) risk(.*)/i,
|
|
627
|
+
);
|
|
628
|
+
if (riskLabelMatch) {
|
|
629
|
+
const capitalizedLabel =
|
|
630
|
+
riskLabelMatch[1].charAt(0).toUpperCase() +
|
|
631
|
+
riskLabelMatch[1].slice(1).toLowerCase();
|
|
632
|
+
enrichedReason = `${capitalizedLabel} risk (${riskReason})${riskLabelMatch[2]}`;
|
|
1125
633
|
}
|
|
1126
634
|
}
|
|
1127
635
|
|
|
1128
|
-
|
|
1129
|
-
|
|
1130
|
-
|
|
1131
|
-
|
|
1132
|
-
|
|
1133
|
-
}
|
|
1134
|
-
|
|
1135
|
-
if (risk === RiskLevel.Low) {
|
|
1136
|
-
return { decision: "allow", reason: "Low risk: auto-allowed" };
|
|
1137
|
-
}
|
|
1138
|
-
|
|
1139
|
-
return { decision: "prompt", reason: `${risk} risk: requires approval` };
|
|
636
|
+
return {
|
|
637
|
+
decision: approvalDecision.decision,
|
|
638
|
+
reason: enrichedReason,
|
|
639
|
+
matchedRule: approvalDecision.matchedRule,
|
|
640
|
+
};
|
|
1140
641
|
}
|
|
1141
642
|
|
|
1142
643
|
const TOOL_DISPLAY_NAMES: Record<string, string> = {
|
|
@@ -1147,7 +648,6 @@ const TOOL_DISPLAY_NAMES: Record<string, string> = {
|
|
|
1147
648
|
host_file_write: "host file writes",
|
|
1148
649
|
host_file_edit: "host file edits",
|
|
1149
650
|
web_fetch: "URL fetches",
|
|
1150
|
-
browser_navigate: "browser navigations",
|
|
1151
651
|
network_request: "network requests",
|
|
1152
652
|
};
|
|
1153
653
|
|
|
@@ -1175,6 +675,10 @@ function shellAllowlistStrategy(
|
|
|
1175
675
|
input: Record<string, unknown>,
|
|
1176
676
|
): Promise<AllowlistOption[]> {
|
|
1177
677
|
const command = ((input.command as string) ?? "").trim();
|
|
678
|
+
// TODO(phase-3): Wire RiskAssessment.scopeOptions into permission prompts
|
|
679
|
+
// and retire buildShellAllowlistOptions + buildShellCommandCandidates from
|
|
680
|
+
// shell-identity.ts. The classifier's generateScopeOptions produces the
|
|
681
|
+
// canonical scope ladder; this legacy path should not diverge further.
|
|
1178
682
|
return buildShellAllowlistOptions(command);
|
|
1179
683
|
}
|
|
1180
684
|
|
|
@@ -1356,7 +860,6 @@ const ALLOWLIST_STRATEGIES: Record<string, AllowlistStrategy> = {
|
|
|
1356
860
|
host_file_write: fileAllowlistStrategy,
|
|
1357
861
|
host_file_edit: fileAllowlistStrategy,
|
|
1358
862
|
web_fetch: urlAllowlistStrategy,
|
|
1359
|
-
browser_navigate: urlAllowlistStrategy,
|
|
1360
863
|
network_request: urlAllowlistStrategy,
|
|
1361
864
|
scaffold_managed_skill: managedSkillAllowlistStrategy,
|
|
1362
865
|
delete_managed_skill: managedSkillAllowlistStrategy,
|
|
@@ -1370,6 +873,22 @@ export async function generateAllowlistOptions(
|
|
|
1370
873
|
): Promise<AllowlistOption[]> {
|
|
1371
874
|
signal?.throwIfAborted();
|
|
1372
875
|
|
|
876
|
+
// Check if a classifier already produced allowlist options during
|
|
877
|
+
// classifyRisk(). If so, return those directly — avoids duplicate
|
|
878
|
+
// computation and keeps scope option generation unified with risk
|
|
879
|
+
// classification.
|
|
880
|
+
const aKey = assessmentCacheKey(toolName, input);
|
|
881
|
+
const cachedAssessment = assessmentCache.get(aKey);
|
|
882
|
+
if (
|
|
883
|
+
cachedAssessment?.allowlistOptions &&
|
|
884
|
+
cachedAssessment.allowlistOptions.length > 0
|
|
885
|
+
) {
|
|
886
|
+
return cachedAssessment.allowlistOptions;
|
|
887
|
+
}
|
|
888
|
+
|
|
889
|
+
// Fall back to the per-tool strategy function for tools that don't have
|
|
890
|
+
// classifier-produced options (e.g. bash tools use the shell identity
|
|
891
|
+
// strategy, or when the cache was missed).
|
|
1373
892
|
if (Object.hasOwn(ALLOWLIST_STRATEGIES, toolName)) {
|
|
1374
893
|
return ALLOWLIST_STRATEGIES[toolName](toolName, input);
|
|
1375
894
|
}
|