@vellumai/assistant 0.6.1 → 0.6.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bun.lock +40 -40
- package/bunfig.toml +3 -0
- package/docker-entrypoint.sh +12 -2
- package/docs/architecture/memory.md +1 -1
- package/node_modules/@vellumai/ces-contracts/src/handles.ts +7 -9
- package/node_modules/@vellumai/ces-contracts/src/rpc.ts +42 -0
- package/openapi.yaml +184 -69
- package/package.json +41 -41
- package/scripts/generate-openapi.ts +1 -2
- package/src/__tests__/acp-session.test.ts +43 -0
- package/src/__tests__/app-builder-tool-scripts.test.ts +1 -0
- package/src/__tests__/app-executors.test.ts +1 -0
- package/src/__tests__/app-source-watcher.test.ts +37 -11
- package/src/__tests__/approval-routes-http.test.ts +178 -1
- package/src/__tests__/assistant-event-hub.test.ts +30 -0
- package/src/__tests__/browser-fill-credential.test.ts +229 -94
- package/src/__tests__/browser-manager.test.ts +40 -27
- package/src/__tests__/catalog-files.test.ts +862 -0
- package/src/__tests__/channel-approvals.test.ts +53 -0
- package/src/__tests__/checker.test.ts +104 -170
- package/src/__tests__/cli-command-risk-guard.test.ts +1 -1
- package/src/__tests__/config-managed-gemini-defaults.test.ts +326 -0
- package/src/__tests__/config-schema-cmd.test.ts +2 -2
- package/src/__tests__/config-schema.test.ts +125 -48
- package/src/__tests__/confirmation-request-guardian-bridge.test.ts +23 -0
- package/src/__tests__/context-overflow-approval.test.ts +21 -6
- package/src/__tests__/conversation-agent-loop-overflow.test.ts +1 -1
- package/src/__tests__/conversation-agent-loop.test.ts +1 -1
- package/src/__tests__/conversation-analysis-routes.test.ts +169 -0
- package/src/__tests__/conversation-attachments.test.ts +80 -4
- package/src/__tests__/conversation-confirmation-signals.test.ts +155 -0
- package/src/__tests__/conversation-directories-parse.test.ts +105 -0
- package/src/__tests__/conversation-fork-crud.test.ts +17 -0
- package/src/__tests__/conversation-history-web-search.test.ts +1 -0
- package/src/__tests__/conversation-host-access-routes.test.ts +229 -0
- package/src/__tests__/conversation-inject-context.test.ts +103 -0
- package/src/__tests__/conversation-queue.test.ts +45 -2
- package/src/__tests__/conversation-routes-disk-view.test.ts +5 -0
- package/src/__tests__/conversation-routes-guardian-reply.test.ts +16 -0
- package/src/__tests__/conversation-routes-slash-commands.test.ts +1 -0
- package/src/__tests__/conversation-runtime-assembly.test.ts +269 -46
- package/src/__tests__/conversation-starter-routes.test.ts +126 -0
- package/src/__tests__/conversation-starters-cadence.test.ts +161 -0
- package/src/__tests__/conversation-store.test.ts +195 -0
- package/src/__tests__/conversation-workspace-cache-state.test.ts +193 -0
- package/src/__tests__/credential-execution-approval-bridge.test.ts +32 -3
- package/src/__tests__/credential-security-invariants.test.ts +1 -0
- package/src/__tests__/credential-vault-unit.test.ts +4 -4
- package/src/__tests__/credential-vault.test.ts +152 -13
- package/src/__tests__/credentials-cli.test.ts +2 -2
- package/src/__tests__/date-context.test.ts +4 -4
- package/src/__tests__/embedding-managed-proxy-selection.test.ts +256 -0
- package/src/__tests__/extension-id-sync-guard.test.ts +155 -0
- package/src/__tests__/fixtures/mock-chrome-extension.ts +375 -0
- package/src/__tests__/gateway-only-guard.test.ts +3 -0
- package/src/__tests__/gemini-provider.test.ts +2 -2
- package/src/__tests__/guardian-routing-invariants.test.ts +70 -2
- package/src/__tests__/headless-browser-interactions.test.ts +707 -371
- package/src/__tests__/headless-browser-navigate.test.ts +389 -47
- package/src/__tests__/headless-browser-read-tools.test.ts +266 -103
- package/src/__tests__/headless-browser-snapshot.test.ts +240 -77
- package/src/__tests__/host-bash-proxy.test.ts +150 -1
- package/src/__tests__/host-browser-e2e-cloud.test.ts +462 -0
- package/src/__tests__/host-browser-e2e-self-hosted-capability.test.ts +286 -0
- package/src/__tests__/host-browser-e2e-self-hosted.test.ts +374 -0
- package/src/__tests__/host-browser-event-routes.test.ts +350 -0
- package/src/__tests__/host-browser-proxy.test.ts +444 -0
- package/src/__tests__/host-browser-routes.test.ts +198 -0
- package/src/__tests__/host-browser-ws-events-e2e.test.ts +320 -0
- package/src/__tests__/host-cu-proxy.test.ts +171 -1
- package/src/__tests__/host-file-proxy.test.ts +185 -1
- package/src/__tests__/host-file-read-tool.test.ts +52 -0
- package/src/__tests__/host-proxy-interface.test.ts +165 -0
- package/src/__tests__/host-shell-tool.test.ts +1 -11
- package/src/__tests__/http-user-message-parity.test.ts +1 -0
- package/src/__tests__/init-feature-flag-overrides.test.ts +167 -0
- package/src/__tests__/inline-command-runner.test.ts +7 -5
- package/src/__tests__/integration-status.test.ts +6 -7
- package/src/__tests__/list-messages-tool-merge.test.ts +37 -12
- package/src/__tests__/log-export-workspace.test.ts +190 -0
- package/src/__tests__/managed-credential-catalog-cli.test.ts +12 -14
- package/src/__tests__/mcp-client-auth.test.ts +40 -4
- package/src/__tests__/mcp-health-check.test.ts +10 -3
- package/src/__tests__/migration-cross-version-compatibility.test.ts +3 -1
- package/src/__tests__/migration-export-http.test.ts +61 -2
- package/src/__tests__/migration-export-streaming.test.ts +66 -0
- package/src/__tests__/migration-import-commit-http.test.ts +101 -1
- package/src/__tests__/native-host-marker-sync-guard.test.ts +157 -0
- package/src/__tests__/navigate-settings-tab.test.ts +14 -1
- package/src/__tests__/notification-broadcaster.test.ts +65 -0
- package/src/__tests__/oauth-apps-routes.test.ts +17 -12
- package/src/__tests__/oauth-cli.test.ts +707 -60
- package/src/__tests__/oauth-connect-orchestrator.test.ts +116 -24
- package/src/__tests__/oauth-provider-seed-logos.test.ts +23 -0
- package/src/__tests__/oauth-provider-serializer.test.ts +146 -10
- package/src/__tests__/oauth-provider-visibility.test.ts +19 -21
- package/src/__tests__/oauth-providers-routes.test.ts +50 -14
- package/src/__tests__/oauth-store.test.ts +1386 -182
- package/src/__tests__/oauth2-gateway-transport.test.ts +211 -20
- package/src/__tests__/onboarding-template-contract.test.ts +74 -55
- package/src/__tests__/openai-provider.test.ts +2 -2
- package/src/__tests__/outlook-categories.test.ts +1 -1
- package/src/__tests__/outlook-client-automation.test.ts +1 -1
- package/src/__tests__/outlook-compose-tools.test.ts +1 -1
- package/src/__tests__/outlook-email-watcher.test.ts +1 -1
- package/src/__tests__/outlook-follow-up.test.ts +1 -1
- package/src/__tests__/outlook-messaging-provider.test.ts +2 -2
- package/src/__tests__/outlook-trash.test.ts +1 -1
- package/src/__tests__/outlook-unsubscribe.test.ts +1 -1
- package/src/__tests__/permission-checker-host-gate.test.ts +74 -14
- package/src/__tests__/permission-mode.test.ts +28 -56
- package/src/__tests__/pkb-autoinject.test.ts +96 -0
- package/src/__tests__/platform-callback-registration.test.ts +19 -0
- package/src/__tests__/post-turn-tool-result-truncation.test.ts +296 -0
- package/src/__tests__/proxy-approval-callback.test.ts +18 -0
- package/src/__tests__/require-fresh-approval.test.ts +40 -3
- package/src/__tests__/sandbox-diagnostics.test.ts +1 -32
- package/src/__tests__/sanitize-config-for-transfer.test.ts +132 -0
- package/src/__tests__/schedule-routes.test.ts +162 -0
- package/src/__tests__/secret-detection-handler.test.ts +84 -0
- package/src/__tests__/secret-ingress-http.test.ts +1 -0
- package/src/__tests__/send-endpoint-busy.test.ts +3 -0
- package/src/__tests__/set-permission-mode.test.ts +13 -250
- package/src/__tests__/skills-file-content-endpoint.test.ts +670 -0
- package/src/__tests__/skills-files-catalog-fallback.test.ts +450 -0
- package/src/__tests__/slack-channel-config.test.ts +12 -15
- package/src/__tests__/subagent-detail.test.ts +44 -2
- package/src/__tests__/subagent-disposal.test.ts +1 -0
- package/src/__tests__/subagent-fork-notifications.test.ts +291 -0
- package/src/__tests__/subagent-fork-spawn.test.ts +384 -0
- package/src/__tests__/subagent-manager-notify.test.ts +1 -0
- package/src/__tests__/subagent-notify-parent.test.ts +1 -0
- package/src/__tests__/subagent-spawn-tool-fork.test.ts +411 -0
- package/src/__tests__/subagent-tools.test.ts +1 -0
- package/src/__tests__/subagent-types.test.ts +1 -0
- package/src/__tests__/system-prompt-ask-mode.test.ts +27 -71
- package/src/__tests__/system-prompt.test.ts +72 -1
- package/src/__tests__/task-scheduler.test.ts +32 -6
- package/src/__tests__/telegram-config.test.ts +10 -13
- package/src/__tests__/terminal-sandbox.test.ts +1 -1
- package/src/__tests__/terminal-tools.test.ts +11 -5
- package/src/__tests__/test-preload.ts +14 -0
- package/src/__tests__/tool-approval-handler.test.ts +73 -0
- package/src/__tests__/tool-domain-event-publisher.test.ts +0 -1
- package/src/__tests__/tool-executor-lifecycle-events.test.ts +1 -8
- package/src/__tests__/tool-executor.test.ts +0 -1
- package/src/__tests__/tool-side-effects-slack-dm.test.ts +22 -0
- package/src/__tests__/top-level-renderer.test.ts +73 -1
- package/src/__tests__/transport-hints-queue.test.ts +62 -0
- package/src/__tests__/trust-store.test.ts +4 -4
- package/src/__tests__/trusted-contact-inline-approval-integration.test.ts +109 -0
- package/src/__tests__/v2-consent-policy.test.ts +103 -0
- package/src/__tests__/workspace-migration-030-seed-pkb-autoinject.test.ts +168 -0
- package/src/__tests__/workspace-policy.test.ts +2 -7
- package/src/acp/client-handler.ts +30 -4
- package/src/agent/loop.ts +12 -35
- package/src/approvals/guardian-request-resolvers.ts +21 -15
- package/src/browser-session/__tests__/manager.test.ts +297 -0
- package/src/browser-session/backends/cdp-inspect.ts +30 -0
- package/src/browser-session/backends/extension.ts +26 -0
- package/src/browser-session/backends/local.ts +24 -0
- package/src/browser-session/events.ts +164 -0
- package/src/browser-session/index.ts +27 -0
- package/src/browser-session/manager.ts +159 -0
- package/src/browser-session/types.ts +28 -0
- package/src/channels/__tests__/types.test.ts +134 -0
- package/src/channels/types.ts +55 -0
- package/src/cli/__tests__/run-assistant-command.ts +34 -7
- package/src/cli/__tests__/unknown-command.test.ts +33 -0
- package/src/cli/commands/browser-relay.ts +339 -409
- package/src/cli/commands/credentials.ts +3 -3
- package/src/cli/commands/default-action.ts +68 -1
- package/src/cli/commands/email.ts +18 -13
- package/src/cli/commands/mcp.ts +16 -4
- package/src/cli/commands/oauth/__tests__/connect.test.ts +68 -41
- package/src/cli/commands/oauth/__tests__/disconnect.test.ts +21 -21
- package/src/cli/commands/oauth/__tests__/mode.test.ts +17 -17
- package/src/cli/commands/oauth/__tests__/ping.test.ts +16 -16
- package/src/cli/commands/oauth/__tests__/providers-delete.test.ts +31 -33
- package/src/cli/commands/oauth/__tests__/providers-register.test.ts +329 -0
- package/src/cli/commands/oauth/__tests__/providers-update.test.ts +116 -12
- package/src/cli/commands/oauth/__tests__/status.test.ts +10 -10
- package/src/cli/commands/oauth/__tests__/token.test.ts +7 -7
- package/src/cli/commands/oauth/apps.ts +7 -4
- package/src/cli/commands/oauth/connect.ts +16 -2
- package/src/cli/commands/oauth/disconnect.ts +1 -1
- package/src/cli/commands/oauth/providers.ts +200 -36
- package/src/cli/commands/oauth/shared.ts +5 -5
- package/src/cli/commands/platform/__tests__/callback-routes-list.test.ts +259 -0
- package/src/cli/commands/platform/__tests__/connect.test.ts +1 -1
- package/src/cli/commands/platform/__tests__/disconnect.test.ts +1 -1
- package/src/cli/commands/platform/__tests__/status.test.ts +1 -1
- package/src/cli/commands/platform/index.ts +107 -10
- package/src/cli/commands/usage.ts +10 -9
- package/src/cli/lib/daemon-credential-client.ts +4 -0
- package/src/cli/program.ts +10 -3
- package/src/config/assistant-feature-flags.ts +59 -55
- package/src/config/bundled-skills/app-builder/SKILL.md +33 -173
- package/src/config/bundled-skills/app-builder/references/CUSTOM_ROUTES.md +105 -0
- package/src/config/bundled-skills/app-builder/references/INTERACTION_HOOKS.md +56 -0
- package/src/config/bundled-skills/app-builder/references/WIDGETS.md +125 -0
- package/src/config/bundled-skills/contacts/SKILL.md +3 -0
- package/src/config/bundled-skills/document/SKILL.md +4 -0
- package/src/config/bundled-skills/gmail/SKILL.md +12 -7
- package/src/config/bundled-skills/gmail/TOOLS.json +1 -1
- package/src/config/bundled-skills/gmail/tools/gmail-sender-digest.ts +2 -1
- package/src/config/bundled-skills/outlook/SKILL.md +7 -0
- package/src/config/bundled-skills/settings/TOOLS.json +1 -1
- package/src/config/bundled-skills/settings/tools/navigate-settings-tab.ts +8 -3
- package/src/config/bundled-skills/subagent/SKILL.md +21 -0
- package/src/config/bundled-skills/subagent/TOOLS.json +8 -4
- package/src/config/bundled-skills/tasks/SKILL.md +5 -0
- package/src/config/env-registry.ts +14 -0
- package/src/config/env.ts +21 -0
- package/src/config/feature-flag-registry.json +46 -7
- package/src/config/loader.ts +56 -1
- package/src/config/sanitize-for-transfer.ts +47 -0
- package/src/config/schema.ts +46 -5
- package/src/config/schemas/host-browser.ts +66 -0
- package/src/config/schemas/memory-lifecycle.ts +1 -1
- package/src/config/schemas/memory-retrieval.ts +103 -0
- package/src/config/schemas/security.ts +0 -6
- package/src/config/schemas/services.ts +16 -0
- package/src/config/types.ts +0 -1
- package/src/context/post-turn-tool-result-truncation.ts +176 -0
- package/src/context/window-manager.ts +19 -1
- package/src/credential-execution/approval-bridge.ts +49 -16
- package/src/credential-execution/managed-catalog.ts +3 -7
- package/src/daemon/__tests__/conversation-tool-setup.test.ts +186 -0
- package/src/daemon/app-source-watcher.ts +35 -0
- package/src/daemon/config-watcher.ts +6 -2
- package/src/daemon/context-overflow-approval.ts +5 -1
- package/src/daemon/conversation-agent-loop-handlers.ts +17 -2
- package/src/daemon/conversation-agent-loop.ts +74 -19
- package/src/daemon/conversation-attachments.ts +40 -1
- package/src/daemon/conversation-messaging.ts +3 -0
- package/src/daemon/conversation-process.ts +66 -3
- package/src/daemon/conversation-queue-manager.ts +8 -0
- package/src/daemon/conversation-runtime-assembly.ts +159 -20
- package/src/daemon/conversation-surfaces.ts +78 -12
- package/src/daemon/conversation-tool-setup.ts +74 -11
- package/src/daemon/conversation-workspace.ts +12 -0
- package/src/daemon/conversation.ts +227 -11
- package/src/daemon/date-context.ts +10 -10
- package/src/daemon/first-greeting.ts +3 -2
- package/src/daemon/handlers/conversations.ts +9 -139
- package/src/daemon/handlers/shared.ts +65 -0
- package/src/daemon/handlers/skills.ts +232 -37
- package/src/daemon/host-bash-proxy.ts +48 -13
- package/src/daemon/host-browser-proxy.ts +191 -0
- package/src/daemon/host-cu-proxy.ts +36 -11
- package/src/daemon/host-file-proxy.ts +57 -9
- package/src/daemon/lifecycle.ts +86 -12
- package/src/daemon/message-protocol.ts +7 -0
- package/src/daemon/message-types/conversations.ts +59 -13
- package/src/daemon/message-types/host-browser.ts +100 -0
- package/src/daemon/message-types/messages.ts +5 -6
- package/src/daemon/message-types/notifications.ts +12 -0
- package/src/daemon/message-types/settings.ts +12 -0
- package/src/daemon/message-types/skills.ts +10 -0
- package/src/daemon/message-types/subagents.ts +2 -0
- package/src/daemon/server.ts +112 -35
- package/src/daemon/tool-side-effects.ts +6 -0
- package/src/daemon/transport-hints.ts +14 -0
- package/src/inbound/platform-callback-registration.ts +18 -17
- package/src/index.ts +1 -1
- package/src/mcp/client.ts +59 -24
- package/src/memory/app-store.ts +31 -1
- package/src/memory/conversation-crud.ts +38 -10
- package/src/memory/conversation-directories.ts +39 -0
- package/src/memory/conversation-group-migration.ts +65 -5
- package/src/memory/conversation-starters-cadence.ts +76 -0
- package/src/memory/conversation-title-service.ts +5 -2
- package/src/memory/db-init.ts +12 -0
- package/src/memory/embedding-backend.test.ts +75 -0
- package/src/memory/embedding-backend.ts +131 -5
- package/src/memory/embedding-gemini.test.ts +54 -0
- package/src/memory/embedding-gemini.ts +20 -9
- package/src/memory/embedding-local.ts +177 -18
- package/src/memory/graph/capability-seed.ts +3 -5
- package/src/memory/graph/consolidation.ts +10 -23
- package/src/memory/graph/extraction-job.ts +15 -0
- package/src/memory/graph/retriever.ts +40 -22
- package/src/memory/graph/store.test.ts +7 -3
- package/src/memory/graph/store.ts +47 -12
- package/src/memory/group-crud.ts +25 -9
- package/src/memory/llm-usage-store.ts +45 -4
- package/src/memory/migrations/213-oauth-providers-scope-separator.ts +13 -0
- package/src/memory/migrations/214-oauth-providers-refresh-url.ts +11 -0
- package/src/memory/migrations/215-oauth-providers-revoke.ts +14 -0
- package/src/memory/migrations/216-oauth-providers-token-auth-method.ts +30 -0
- package/src/memory/migrations/217-conversation-host-access.ts +40 -0
- package/src/memory/migrations/218-oauth-providers-logo-url.ts +11 -0
- package/src/memory/migrations/index.ts +6 -0
- package/src/memory/migrations/registry.ts +8 -0
- package/src/memory/schema/conversations.ts +1 -0
- package/src/memory/schema/oauth.ts +18 -13
- package/src/messaging/provider.ts +1 -1
- package/src/notifications/broadcaster.ts +6 -0
- package/src/notifications/conversation-pairing.ts +12 -4
- package/src/notifications/emit-signal.ts +14 -0
- package/src/notifications/signal.ts +11 -0
- package/src/oauth/AGENTS.md +76 -0
- package/src/oauth/__tests__/identity-verifier.test.ts +24 -19
- package/src/oauth/__tests__/seed-providers-managed.test.ts +32 -0
- package/src/oauth/byo-connection.test.ts +8 -8
- package/src/oauth/byo-connection.ts +7 -7
- package/src/oauth/connect-orchestrator.ts +23 -21
- package/src/oauth/connect-types.ts +3 -3
- package/src/oauth/connection-resolver.test.ts +17 -4
- package/src/oauth/connection-resolver.ts +16 -16
- package/src/oauth/connection.ts +1 -1
- package/src/oauth/manual-token-connection.ts +13 -13
- package/src/oauth/oauth-store.ts +214 -100
- package/src/oauth/platform-connection.test.ts +5 -5
- package/src/oauth/platform-connection.ts +4 -4
- package/src/oauth/provider-serializer.ts +31 -5
- package/src/oauth/revoke.ts +76 -0
- package/src/oauth/seed-providers.ts +127 -87
- package/src/oauth/token-persistence.ts +1 -1
- package/src/permissions/checker.ts +3 -3
- package/src/permissions/defaults.ts +7 -8
- package/src/permissions/permission-mode.ts +4 -11
- package/src/permissions/prompter.ts +13 -3
- package/src/permissions/v2-consent-policy.ts +87 -0
- package/src/platform/client.ts +1 -1
- package/src/prompts/system-prompt.ts +18 -21
- package/src/prompts/templates/BOOTSTRAP-REFERENCE.md +3 -65
- package/src/prompts/templates/BOOTSTRAP.md +59 -96
- package/src/prompts/templates/SOUL.md +11 -11
- package/src/providers/anthropic/client.ts +1 -0
- package/src/providers/types.ts +1 -1
- package/src/runtime/AGENTS.md +23 -0
- package/src/runtime/__tests__/browser-extension-pair-routes.test.ts +715 -0
- package/src/runtime/__tests__/capability-tokens.test.ts +258 -0
- package/src/runtime/__tests__/chrome-extension-registry.test.ts +518 -0
- package/src/runtime/assistant-event-hub.ts +24 -2
- package/src/runtime/auth/__tests__/guard-tests.test.ts +1 -0
- package/src/runtime/auth/__tests__/middleware.test.ts +116 -1
- package/src/runtime/auth/__tests__/route-policy.test.ts +8 -0
- package/src/runtime/auth/middleware.ts +98 -0
- package/src/runtime/auth/route-policy.ts +6 -7
- package/src/runtime/auth/token-service.ts +8 -0
- package/src/runtime/capability-tokens.ts +414 -0
- package/src/runtime/channel-approvals.ts +18 -5
- package/src/runtime/chrome-extension-registry.ts +332 -0
- package/src/runtime/confirmation-request-guardian-bridge.ts +6 -0
- package/src/runtime/guardian-decision-types.ts +7 -0
- package/src/runtime/http-server.ts +425 -70
- package/src/runtime/migrations/__tests__/rebind-secrets-credentials.test.ts +172 -0
- package/src/runtime/migrations/__tests__/vbundle-builder-credentials.test.ts +276 -0
- package/src/runtime/migrations/__tests__/vbundle-import-credentials.test.ts +162 -0
- package/src/runtime/migrations/migration-transport.ts +6 -0
- package/src/runtime/migrations/migration-wizard.ts +22 -2
- package/src/runtime/migrations/rebind-secrets-screen.ts +76 -15
- package/src/runtime/migrations/vbundle-builder.ts +145 -38
- package/src/runtime/migrations/vbundle-import-analyzer.ts +19 -0
- package/src/runtime/migrations/vbundle-importer.ts +55 -5
- package/src/runtime/pending-interactions.ts +29 -13
- package/src/runtime/routes/approval-routes.ts +90 -16
- package/src/runtime/routes/browser-cdp-routes.ts +229 -0
- package/src/runtime/routes/browser-extension-pair-routes.ts +497 -0
- package/src/runtime/routes/conversation-analysis-routes.ts +18 -5
- package/src/runtime/routes/conversation-management-routes.ts +108 -0
- package/src/runtime/routes/conversation-routes.ts +308 -28
- package/src/runtime/routes/conversation-starter-routes.ts +78 -16
- package/src/runtime/routes/group-routes.ts +22 -8
- package/src/runtime/routes/guardian-action-routes.ts +24 -13
- package/src/runtime/routes/host-browser-routes.ts +279 -0
- package/src/runtime/routes/host-file-routes.ts +9 -1
- package/src/runtime/routes/identity-routes.ts +259 -16
- package/src/runtime/routes/log-export/AGENTS.md +104 -0
- package/src/runtime/routes/log-export/__tests__/workspace-allowlist-error-contract.test.ts +103 -0
- package/src/runtime/routes/log-export/__tests__/workspace-allowlist.test.ts +716 -0
- package/src/runtime/routes/log-export/workspace-allowlist.ts +458 -0
- package/src/runtime/routes/log-export-routes.ts +60 -25
- package/src/runtime/routes/memory-item-routes.ts +1 -7
- package/src/runtime/routes/migration-routes.ts +87 -2
- package/src/runtime/routes/oauth-apps.ts +15 -17
- package/src/runtime/routes/oauth-providers.ts +4 -0
- package/src/runtime/routes/schedule-routes.ts +24 -11
- package/src/runtime/routes/settings-routes.ts +9 -97
- package/src/runtime/routes/skills-routes.ts +52 -2
- package/src/runtime/routes/subagents-routes.ts +14 -10
- package/src/runtime/routes/usage-routes.ts +8 -7
- package/src/runtime/routes/workspace-routes.test.ts +22 -0
- package/src/runtime/routes/workspace-routes.ts +8 -1
- package/src/runtime/routes/workspace-utils.ts +2 -0
- package/src/schedule/scheduler.ts +7 -5
- package/src/security/ces-credential-client.ts +20 -0
- package/src/security/ces-rpc-credential-backend.ts +17 -0
- package/src/security/credential-backend.ts +5 -0
- package/src/security/oauth2.ts +42 -25
- package/src/security/secure-keys.ts +118 -25
- package/src/security/token-manager.ts +23 -10
- package/src/skills/catalog-files.ts +492 -0
- package/src/skills/inline-command-runner.ts +12 -14
- package/src/subagent/manager.ts +131 -26
- package/src/subagent/types.ts +19 -0
- package/src/tools/apps/executors.ts +11 -2
- package/src/tools/browser/__tests__/auth-detector.test.ts +202 -108
- package/src/tools/browser/auth-detector.ts +43 -12
- package/src/tools/browser/browser-execution.ts +645 -340
- package/src/tools/browser/browser-manager.ts +36 -12
- package/src/tools/browser/cdp-client/__tests__/accessibility-snapshot.test.ts +318 -0
- package/src/tools/browser/cdp-client/__tests__/cdp-dom-helpers.test.ts +1175 -0
- package/src/tools/browser/cdp-client/__tests__/cdp-inspect-client.test.ts +870 -0
- package/src/tools/browser/cdp-client/__tests__/extension-cdp-client.test.ts +330 -0
- package/src/tools/browser/cdp-client/__tests__/factory.test.ts +377 -0
- package/src/tools/browser/cdp-client/__tests__/fixtures/ax-tree-nested-frames.json +64 -0
- package/src/tools/browser/cdp-client/__tests__/fixtures/ax-tree-simple.json +69 -0
- package/src/tools/browser/cdp-client/__tests__/local-cdp-client.test.ts +310 -0
- package/src/tools/browser/cdp-client/__tests__/types.test.ts +96 -0
- package/src/tools/browser/cdp-client/accessibility-snapshot.ts +387 -0
- package/src/tools/browser/cdp-client/cdp-dom-helpers.ts +695 -0
- package/src/tools/browser/cdp-client/cdp-inspect/__tests__/discovery.test.ts +743 -0
- package/src/tools/browser/cdp-client/cdp-inspect/__tests__/ws-transport.test.ts +580 -0
- package/src/tools/browser/cdp-client/cdp-inspect/discovery.ts +578 -0
- package/src/tools/browser/cdp-client/cdp-inspect/ws-transport.ts +579 -0
- package/src/tools/browser/cdp-client/cdp-inspect-client.ts +635 -0
- package/src/tools/browser/cdp-client/errors.ts +34 -0
- package/src/tools/browser/cdp-client/extension-cdp-client.ts +125 -0
- package/src/tools/browser/cdp-client/factory.ts +204 -0
- package/src/tools/browser/cdp-client/index.ts +14 -0
- package/src/tools/browser/cdp-client/local-cdp-client.ts +187 -0
- package/src/tools/browser/cdp-client/types.ts +52 -0
- package/src/tools/filesystem/edit.ts +1 -1
- package/src/tools/filesystem/list.ts +1 -1
- package/src/tools/filesystem/read.ts +1 -1
- package/src/tools/filesystem/write.ts +2 -1
- package/src/tools/host-filesystem/edit.ts +1 -1
- package/src/tools/host-filesystem/read.ts +12 -15
- package/src/tools/host-filesystem/write.ts +1 -1
- package/src/tools/host-terminal/host-shell.ts +21 -16
- package/src/tools/permission-checker.ts +77 -100
- package/src/tools/registry.ts +0 -2
- package/src/tools/secret-detection-handler.ts +34 -1
- package/src/tools/shared/filesystem/image-read.ts +61 -40
- package/src/tools/skills/sandbox-runner.ts +3 -6
- package/src/tools/subagent/spawn.ts +47 -3
- package/src/tools/subagent/status.ts +2 -0
- package/src/tools/system/register.ts +2 -16
- package/src/tools/terminal/safe-env.ts +7 -0
- package/src/tools/terminal/sandbox-diagnostics.ts +4 -4
- package/src/tools/terminal/sandbox.ts +4 -1
- package/src/tools/terminal/shell.ts +24 -21
- package/src/tools/tool-approval-handler.ts +48 -2
- package/src/tools/types.ts +2 -3
- package/src/util/platform.ts +14 -19
- package/src/watcher/provider-types.ts +1 -1
- package/src/workspace/migrations/029-seed-pkb.ts +1 -0
- package/src/workspace/migrations/030-seed-pkb-autoinject.ts +73 -0
- package/src/workspace/migrations/registry.ts +2 -0
- package/src/workspace/top-level-renderer.ts +19 -1
- package/src/__tests__/chrome-cdp.test.ts +0 -419
- package/src/__tests__/permission-mode-sse.test.ts +0 -418
- package/src/__tests__/permission-mode-store.test.ts +0 -277
- package/src/browser-extension-relay/protocol.ts +0 -63
- package/src/browser-extension-relay/server.ts +0 -203
- package/src/config/schemas/sandbox.ts +0 -14
- package/src/permissions/permission-mode-store.ts +0 -180
- package/src/tools/browser/chrome-cdp.ts +0 -239
- package/src/tools/system/set-permission-mode.ts +0 -103
|
@@ -128,9 +128,17 @@ describe("scheduler run_task detection", () => {
|
|
|
128
128
|
forceScheduleDue(schedule.id);
|
|
129
129
|
|
|
130
130
|
// Track all processMessage calls
|
|
131
|
-
const directCalls: {
|
|
132
|
-
|
|
133
|
-
|
|
131
|
+
const directCalls: Array<{
|
|
132
|
+
conversationId: string;
|
|
133
|
+
message: string;
|
|
134
|
+
options?: { trustClass?: string; taskRunId?: string };
|
|
135
|
+
}> = [];
|
|
136
|
+
const processMessage = async (
|
|
137
|
+
conversationId: string,
|
|
138
|
+
message: string,
|
|
139
|
+
options?: { trustClass?: string; taskRunId?: string },
|
|
140
|
+
) => {
|
|
141
|
+
directCalls.push({ conversationId, message, options });
|
|
134
142
|
};
|
|
135
143
|
|
|
136
144
|
const scheduler = startScheduler(
|
|
@@ -154,6 +162,8 @@ describe("scheduler run_task detection", () => {
|
|
|
154
162
|
expect(runTaskCalls.length).toBe(1);
|
|
155
163
|
// The scheduler should NOT pass the raw run_task: message to processMessage
|
|
156
164
|
expect(rawCalls.length).toBe(0);
|
|
165
|
+
expect(runTaskCalls[0].options?.trustClass).toBe("guardian");
|
|
166
|
+
expect(typeof runTaskCalls[0].options?.taskRunId).toBe("string");
|
|
157
167
|
});
|
|
158
168
|
|
|
159
169
|
test("regular messages still go through processMessage normally", async () => {
|
|
@@ -167,9 +177,17 @@ describe("scheduler run_task detection", () => {
|
|
|
167
177
|
|
|
168
178
|
forceScheduleDue(schedule.id);
|
|
169
179
|
|
|
170
|
-
const processedMessages: {
|
|
171
|
-
|
|
172
|
-
|
|
180
|
+
const processedMessages: Array<{
|
|
181
|
+
conversationId: string;
|
|
182
|
+
message: string;
|
|
183
|
+
options?: { trustClass?: string; taskRunId?: string };
|
|
184
|
+
}> = [];
|
|
185
|
+
const processMessage = async (
|
|
186
|
+
conversationId: string,
|
|
187
|
+
message: string,
|
|
188
|
+
options?: { trustClass?: string; taskRunId?: string },
|
|
189
|
+
) => {
|
|
190
|
+
processedMessages.push({ conversationId, message, options });
|
|
173
191
|
};
|
|
174
192
|
|
|
175
193
|
const scheduler = startScheduler(
|
|
@@ -185,6 +203,14 @@ describe("scheduler run_task detection", () => {
|
|
|
185
203
|
expect(
|
|
186
204
|
processedMessages.some((m) => m.message === "Do something normal"),
|
|
187
205
|
).toBe(true);
|
|
206
|
+
expect(
|
|
207
|
+
processedMessages.some(
|
|
208
|
+
(m) =>
|
|
209
|
+
m.message === "Do something normal" &&
|
|
210
|
+
m.options?.trustClass === "guardian" &&
|
|
211
|
+
m.options?.taskRunId === undefined,
|
|
212
|
+
),
|
|
213
|
+
).toBe(true);
|
|
188
214
|
});
|
|
189
215
|
|
|
190
216
|
test("handles task not found gracefully", async () => {
|
|
@@ -7,7 +7,7 @@ let oauthConnectionStore: Record<
|
|
|
7
7
|
string,
|
|
8
8
|
{ id: string; status: string; accountInfo?: string | null }
|
|
9
9
|
> = {};
|
|
10
|
-
const syncCalls: Array<{
|
|
10
|
+
const syncCalls: Array<{ provider: string; accountInfo?: string }> = [];
|
|
11
11
|
|
|
12
12
|
mock.module("../config/loader.js", () => ({
|
|
13
13
|
getConfig: () => ({ telegram: {}, ui: {} }),
|
|
@@ -49,32 +49,29 @@ mock.module("../security/secure-keys.js", () => ({
|
|
|
49
49
|
}));
|
|
50
50
|
|
|
51
51
|
mock.module("../oauth/oauth-store.js", () => ({
|
|
52
|
-
getConnectionByProvider: (
|
|
53
|
-
oauthConnectionStore[
|
|
52
|
+
getConnectionByProvider: (provider: string) =>
|
|
53
|
+
oauthConnectionStore[provider] ?? undefined,
|
|
54
54
|
}));
|
|
55
55
|
|
|
56
56
|
mock.module("../oauth/manual-token-connection.js", () => ({
|
|
57
57
|
ensureManualTokenConnection: async () => {},
|
|
58
58
|
removeManualTokenConnection: () => {},
|
|
59
|
-
syncManualTokenConnection: async (
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
) => {
|
|
63
|
-
syncCalls.push({ providerKey, accountInfo });
|
|
64
|
-
if (providerKey !== "telegram") return;
|
|
59
|
+
syncManualTokenConnection: async (provider: string, accountInfo?: string) => {
|
|
60
|
+
syncCalls.push({ provider, accountInfo });
|
|
61
|
+
if (provider !== "telegram") return;
|
|
65
62
|
const hasBotToken =
|
|
66
63
|
!!secureKeyStore[credentialKey("telegram", "bot_token")];
|
|
67
64
|
const hasWebhookSecret =
|
|
68
65
|
!!secureKeyStore[credentialKey("telegram", "webhook_secret")];
|
|
69
66
|
if (hasBotToken && hasWebhookSecret) {
|
|
70
|
-
oauthConnectionStore[
|
|
71
|
-
id: `conn-${
|
|
67
|
+
oauthConnectionStore[provider] = {
|
|
68
|
+
id: `conn-${provider}`,
|
|
72
69
|
status: "active",
|
|
73
70
|
accountInfo: accountInfo ?? null,
|
|
74
71
|
};
|
|
75
72
|
return;
|
|
76
73
|
}
|
|
77
|
-
delete oauthConnectionStore[
|
|
74
|
+
delete oauthConnectionStore[provider];
|
|
78
75
|
},
|
|
79
76
|
}));
|
|
80
77
|
|
|
@@ -114,7 +111,7 @@ describe("Telegram config handler", () => {
|
|
|
114
111
|
expect(result.botUsername).toBe("testbot");
|
|
115
112
|
expect(result.connected).toBe(true);
|
|
116
113
|
expect(syncCalls).toEqual([
|
|
117
|
-
{
|
|
114
|
+
{ provider: "telegram", accountInfo: "@testbot" },
|
|
118
115
|
]);
|
|
119
116
|
expect(oauthConnectionStore["telegram"]?.accountInfo).toBe("@testbot");
|
|
120
117
|
});
|
|
@@ -2,7 +2,7 @@ import * as realChildProcess from "node:child_process";
|
|
|
2
2
|
import * as realFs from "node:fs";
|
|
3
3
|
import { beforeEach, describe, expect, mock, test } from "bun:test";
|
|
4
4
|
|
|
5
|
-
import type { SandboxConfig } from "../
|
|
5
|
+
import type { SandboxConfig } from "../tools/terminal/sandbox.js";
|
|
6
6
|
|
|
7
7
|
let platform = "linux";
|
|
8
8
|
|
|
@@ -65,13 +65,13 @@ mock.module("../tools/network/script-proxy/index.js", () => ({
|
|
|
65
65
|
|
|
66
66
|
// ── Imports (after mocks) ───────────────────────────────────────────────────
|
|
67
67
|
|
|
68
|
-
import type { SandboxConfig } from "../config/schema.js";
|
|
69
68
|
import { parse } from "../tools/terminal/parser.js";
|
|
70
69
|
import {
|
|
71
70
|
ALWAYS_INJECTED_ENV_VARS,
|
|
72
71
|
buildSanitizedEnv,
|
|
73
72
|
SAFE_ENV_VARS,
|
|
74
73
|
} from "../tools/terminal/safe-env.js";
|
|
74
|
+
import type { SandboxConfig } from "../tools/terminal/sandbox.js";
|
|
75
75
|
import { wrapCommand } from "../tools/terminal/sandbox.js";
|
|
76
76
|
import { ToolError } from "../util/errors.js";
|
|
77
77
|
|
|
@@ -445,6 +445,15 @@ describe("buildSanitizedEnv", () => {
|
|
|
445
445
|
expect(env.LC_CTYPE).toBe("UTF-8");
|
|
446
446
|
});
|
|
447
447
|
|
|
448
|
+
test("defaults LANG and LC_ALL to UTF-8 when unset", () => {
|
|
449
|
+
delete process.env.LANG;
|
|
450
|
+
delete process.env.LC_ALL;
|
|
451
|
+
|
|
452
|
+
const env = buildSanitizedEnv();
|
|
453
|
+
expect(env.LANG).toBe("C.UTF-8");
|
|
454
|
+
expect(env.LC_ALL).toBe("C.UTF-8");
|
|
455
|
+
});
|
|
456
|
+
|
|
448
457
|
test("injects INTERNAL_GATEWAY_BASE_URL from gateway config", () => {
|
|
449
458
|
process.env.GATEWAY_PORT = "9000";
|
|
450
459
|
const env = buildSanitizedEnv();
|
|
@@ -455,10 +464,7 @@ describe("buildSanitizedEnv", () => {
|
|
|
455
464
|
test("result is a plain object with no prototype-inherited secrets", () => {
|
|
456
465
|
const env = buildSanitizedEnv();
|
|
457
466
|
const keys = Object.keys(env);
|
|
458
|
-
const safeKeys: string[] = [
|
|
459
|
-
...SAFE_ENV_VARS,
|
|
460
|
-
...ALWAYS_INJECTED_ENV_VARS,
|
|
461
|
-
];
|
|
467
|
+
const safeKeys: string[] = [...SAFE_ENV_VARS, ...ALWAYS_INJECTED_ENV_VARS];
|
|
462
468
|
for (const key of keys) {
|
|
463
469
|
expect(safeKeys).toContain(key);
|
|
464
470
|
}
|
|
@@ -25,11 +25,25 @@ process.env.VELLUM_WORKSPACE_DIR = testDir;
|
|
|
25
25
|
process.env.VELLUM_PLATFORM_URL = "https://test-platform.vellum.ai";
|
|
26
26
|
process.exitCode = 0;
|
|
27
27
|
|
|
28
|
+
// Prevent tests from routing credential writes through the real CES
|
|
29
|
+
// (Credential Execution Service). Without this, setSecureKeyAsync() in
|
|
30
|
+
// containerized environments writes to the live credential store.
|
|
31
|
+
const savedIsContainerized = process.env.IS_CONTAINERIZED;
|
|
32
|
+
const savedCesCredentialUrl = process.env.CES_CREDENTIAL_URL;
|
|
33
|
+
delete process.env.IS_CONTAINERIZED;
|
|
34
|
+
delete process.env.CES_CREDENTIAL_URL;
|
|
35
|
+
|
|
28
36
|
afterAll(() => {
|
|
29
37
|
resetDb();
|
|
30
38
|
process.exitCode = 0;
|
|
31
39
|
delete process.env.VELLUM_WORKSPACE_DIR;
|
|
32
40
|
delete process.env.VELLUM_PLATFORM_URL;
|
|
41
|
+
if (savedIsContainerized !== undefined) {
|
|
42
|
+
process.env.IS_CONTAINERIZED = savedIsContainerized;
|
|
43
|
+
}
|
|
44
|
+
if (savedCesCredentialUrl !== undefined) {
|
|
45
|
+
process.env.CES_CREDENTIAL_URL = savedCesCredentialUrl;
|
|
46
|
+
}
|
|
33
47
|
try {
|
|
34
48
|
rmSync(testDir, { recursive: true, force: true });
|
|
35
49
|
} catch {
|
|
@@ -43,6 +43,11 @@ import {
|
|
|
43
43
|
mintGrantFromDecision,
|
|
44
44
|
type MintGrantParams,
|
|
45
45
|
} from "../approvals/approval-primitive.js";
|
|
46
|
+
import { _setOverridesForTesting } from "../config/assistant-feature-flags.js";
|
|
47
|
+
import {
|
|
48
|
+
createConversation,
|
|
49
|
+
updateConversationHostAccess,
|
|
50
|
+
} from "../memory/conversation-crud.js";
|
|
46
51
|
import { getDb, initializeDb } from "../memory/db.js";
|
|
47
52
|
import { scopedApprovalGrants } from "../memory/schema.js";
|
|
48
53
|
import { computeToolApprovalDigest } from "../security/tool-approval-digest.js";
|
|
@@ -54,6 +59,8 @@ initializeDb();
|
|
|
54
59
|
function clearTables(): void {
|
|
55
60
|
const db = getDb();
|
|
56
61
|
db.delete(scopedApprovalGrants).run();
|
|
62
|
+
db.run("DELETE FROM messages");
|
|
63
|
+
db.run("DELETE FROM conversations");
|
|
57
64
|
}
|
|
58
65
|
|
|
59
66
|
// ---------------------------------------------------------------------------
|
|
@@ -96,6 +103,7 @@ describe("ToolApprovalHandler / pre-exec gate grant check", () => {
|
|
|
96
103
|
beforeEach(() => {
|
|
97
104
|
clearTables();
|
|
98
105
|
events.length = 0;
|
|
106
|
+
_setOverridesForTesting({});
|
|
99
107
|
});
|
|
100
108
|
|
|
101
109
|
test("untrusted actor + matching tool_signature grant -> allow", async () => {
|
|
@@ -508,4 +516,69 @@ describe("ToolApprovalHandler / pre-exec gate grant check", () => {
|
|
|
508
516
|
expect(lastError.isExpected).toBe(true);
|
|
509
517
|
}
|
|
510
518
|
});
|
|
519
|
+
|
|
520
|
+
test("v2 trusted contact bypasses tool grants for sandboxed side-effect tools", async () => {
|
|
521
|
+
_setOverridesForTesting({ "permission-controls-v2": true });
|
|
522
|
+
|
|
523
|
+
const result = await handler.checkPreExecutionGates(
|
|
524
|
+
"bash",
|
|
525
|
+
{ command: "echo hello" },
|
|
526
|
+
makeContext({ trustClass: "trusted_contact" }),
|
|
527
|
+
"sandbox",
|
|
528
|
+
"high",
|
|
529
|
+
Date.now(),
|
|
530
|
+
emitLifecycleEvent,
|
|
531
|
+
);
|
|
532
|
+
|
|
533
|
+
expect(result.allowed).toBe(true);
|
|
534
|
+
expect(events.filter((e) => e.type === "permission_denied")).toHaveLength(
|
|
535
|
+
0,
|
|
536
|
+
);
|
|
537
|
+
});
|
|
538
|
+
|
|
539
|
+
test("v2 trusted contact host tools are denied until computer access is enabled for the conversation", async () => {
|
|
540
|
+
_setOverridesForTesting({ "permission-controls-v2": true });
|
|
541
|
+
|
|
542
|
+
const conv = createConversation("trusted contact host gate");
|
|
543
|
+
const result = await handler.checkPreExecutionGates(
|
|
544
|
+
"bash",
|
|
545
|
+
{ command: "ls -la" },
|
|
546
|
+
makeContext({
|
|
547
|
+
trustClass: "trusted_contact",
|
|
548
|
+
conversationId: conv.id,
|
|
549
|
+
}),
|
|
550
|
+
"host",
|
|
551
|
+
"high",
|
|
552
|
+
Date.now(),
|
|
553
|
+
emitLifecycleEvent,
|
|
554
|
+
);
|
|
555
|
+
|
|
556
|
+
expect(result.allowed).toBe(false);
|
|
557
|
+
if (result.allowed) return;
|
|
558
|
+
expect(result.result.content).toContain(
|
|
559
|
+
"computer access is not enabled for this conversation",
|
|
560
|
+
);
|
|
561
|
+
});
|
|
562
|
+
|
|
563
|
+
test("v2 trusted contact host tools run once computer access is enabled for the conversation", async () => {
|
|
564
|
+
_setOverridesForTesting({ "permission-controls-v2": true });
|
|
565
|
+
|
|
566
|
+
const conv = createConversation("trusted contact host access enabled");
|
|
567
|
+
updateConversationHostAccess(conv.id, true);
|
|
568
|
+
|
|
569
|
+
const result = await handler.checkPreExecutionGates(
|
|
570
|
+
"bash",
|
|
571
|
+
{ command: "ls -la" },
|
|
572
|
+
makeContext({
|
|
573
|
+
trustClass: "trusted_contact",
|
|
574
|
+
conversationId: conv.id,
|
|
575
|
+
}),
|
|
576
|
+
"host",
|
|
577
|
+
"high",
|
|
578
|
+
Date.now(),
|
|
579
|
+
emitLifecycleEvent,
|
|
580
|
+
);
|
|
581
|
+
|
|
582
|
+
expect(result.allowed).toBe(true);
|
|
583
|
+
});
|
|
511
584
|
});
|
|
@@ -41,7 +41,6 @@ let checkerDecision: "allow" | "prompt" | "deny" = "allow";
|
|
|
41
41
|
let checkerReason = "allowed";
|
|
42
42
|
let checkerRisk = "low";
|
|
43
43
|
let promptDecision: "allow" | "always_allow" | "deny" | "always_deny" = "allow";
|
|
44
|
-
let sandboxed = false;
|
|
45
44
|
let fakeToolResult: ToolExecutionResult = { content: "ok", isError: false };
|
|
46
45
|
let toolThrow: Error | null = null;
|
|
47
46
|
|
|
@@ -151,7 +150,7 @@ mock.module("../tools/shared/filesystem/path-policy.js", () => ({
|
|
|
151
150
|
}));
|
|
152
151
|
|
|
153
152
|
mock.module("../tools/terminal/sandbox.js", () => ({
|
|
154
|
-
wrapCommand: () => ({ command: "", sandboxed }),
|
|
153
|
+
wrapCommand: () => ({ command: "", sandboxed: false }),
|
|
155
154
|
}));
|
|
156
155
|
|
|
157
156
|
import { PermissionPrompter } from "../permissions/prompter.js";
|
|
@@ -193,7 +192,6 @@ describe("ToolExecutor lifecycle events", () => {
|
|
|
193
192
|
checkerReason = "allowed";
|
|
194
193
|
checkerRisk = "low";
|
|
195
194
|
promptDecision = "allow";
|
|
196
|
-
sandboxed = false;
|
|
197
195
|
fakeToolResult = { content: "ok", isError: false };
|
|
198
196
|
toolThrow = null;
|
|
199
197
|
});
|
|
@@ -231,7 +229,6 @@ describe("ToolExecutor lifecycle events", () => {
|
|
|
231
229
|
checkerReason = "medium risk: requires approval";
|
|
232
230
|
checkerRisk = "medium";
|
|
233
231
|
promptDecision = "deny";
|
|
234
|
-
sandboxed = true;
|
|
235
232
|
|
|
236
233
|
const events: ToolLifecycleEvent[] = [];
|
|
237
234
|
const executor = new ToolExecutor(makePrompter());
|
|
@@ -256,7 +253,6 @@ describe("ToolExecutor lifecycle events", () => {
|
|
|
256
253
|
expect(promptEvent.executionTarget).toBe("sandbox");
|
|
257
254
|
expect(promptEvent.riskLevel).toBe("medium");
|
|
258
255
|
expect(promptEvent.reason).toBe("medium risk: requires approval");
|
|
259
|
-
expect(promptEvent.sandboxed).toBe(true);
|
|
260
256
|
expect(promptEvent.allowlistOptions).toEqual([
|
|
261
257
|
{ label: "exact", description: "exact", pattern: "exact" },
|
|
262
258
|
]);
|
|
@@ -276,7 +272,6 @@ describe("ToolExecutor lifecycle events", () => {
|
|
|
276
272
|
checkerDecision = "prompt";
|
|
277
273
|
checkerReason = "guardrail prompt";
|
|
278
274
|
checkerRisk = "high";
|
|
279
|
-
sandboxed = true;
|
|
280
275
|
|
|
281
276
|
const events: ToolLifecycleEvent[] = [];
|
|
282
277
|
const executor = new ToolExecutor(
|
|
@@ -580,7 +575,6 @@ describe("ToolExecutor lifecycle events", () => {
|
|
|
580
575
|
checkerReason = "Matched trust rule";
|
|
581
576
|
checkerRisk = "low";
|
|
582
577
|
promptDecision = "allow";
|
|
583
|
-
sandboxed = true;
|
|
584
578
|
|
|
585
579
|
const events: ToolLifecycleEvent[] = [];
|
|
586
580
|
const executor = new ToolExecutor(makePrompter());
|
|
@@ -602,7 +596,6 @@ describe("ToolExecutor lifecycle events", () => {
|
|
|
602
596
|
expect(promptEvent.reason).toBe(
|
|
603
597
|
"Private conversation: side-effect tools require explicit approval",
|
|
604
598
|
);
|
|
605
|
-
expect(promptEvent.sandboxed).toBe(true);
|
|
606
599
|
});
|
|
607
600
|
|
|
608
601
|
test("no permission_prompt event for read-only tool even with forcePromptSideEffects", async () => {
|
|
@@ -1949,7 +1949,6 @@ describe("ToolExecutor persistentDecisionsAllowed contract", () => {
|
|
|
1949
1949
|
_allowlistOptions: AllowlistOption[],
|
|
1950
1950
|
_scopeOptions: ScopeOption[],
|
|
1951
1951
|
_diff: unknown,
|
|
1952
|
-
_sandboxed: unknown,
|
|
1953
1952
|
_conversationId: unknown,
|
|
1954
1953
|
_executionTarget: unknown,
|
|
1955
1954
|
persistentDecisionsAllowed: boolean | undefined,
|
|
@@ -30,8 +30,30 @@ mock.module("../media/app-icon-generator.js", () => ({
|
|
|
30
30
|
mock.module("../memory/app-store.js", () => ({
|
|
31
31
|
getApp: mock(() => null),
|
|
32
32
|
getAppDirPath: mock(() => ""),
|
|
33
|
+
getAppsDir: mock(() => ""),
|
|
33
34
|
isMultifileApp: mock(() => false),
|
|
34
35
|
resolveAppIdFromPath: mock(() => null),
|
|
36
|
+
resolveAppIdByDirName: mock(() => null),
|
|
37
|
+
resolveAppDir: mock(() => ({ dirName: "", dirPath: "" })),
|
|
38
|
+
slugify: mock((s: string) => s),
|
|
39
|
+
validateDirName: mock(() => {}),
|
|
40
|
+
generateAppDirName: mock(() => ""),
|
|
41
|
+
listApps: mock(() => []),
|
|
42
|
+
createApp: mock(() => ({})),
|
|
43
|
+
updateApp: mock(() => {}),
|
|
44
|
+
deleteApp: mock(() => {}),
|
|
45
|
+
getAppPreview: mock(() => null),
|
|
46
|
+
createAppRecord: mock(() => ({})),
|
|
47
|
+
getAppRecord: mock(() => null),
|
|
48
|
+
queryAppRecords: mock(() => []),
|
|
49
|
+
updateAppRecord: mock(() => {}),
|
|
50
|
+
deleteAppRecord: mock(() => {}),
|
|
51
|
+
listAppFiles: mock(() => []),
|
|
52
|
+
appFileExists: mock(() => false),
|
|
53
|
+
readAppFile: mock(() => ""),
|
|
54
|
+
writeAppFile: mock(() => {}),
|
|
55
|
+
editAppFile: mock(() => ({})),
|
|
56
|
+
inlineDistAssets: mock((_, html: string) => html),
|
|
35
57
|
}));
|
|
36
58
|
mock.module("../services/published-app-updater.js", () => ({
|
|
37
59
|
updatePublishedAppDeployment: mock(() => Promise.resolve()),
|
|
@@ -1,10 +1,11 @@
|
|
|
1
|
+
import { homedir, userInfo } from "node:os";
|
|
1
2
|
import { describe, expect, test } from "bun:test";
|
|
2
3
|
|
|
3
4
|
import { renderWorkspaceTopLevelContext } from "../workspace/top-level-renderer.js";
|
|
4
5
|
import type { TopLevelSnapshot } from "../workspace/top-level-scanner.js";
|
|
5
6
|
|
|
6
7
|
describe("renderWorkspaceTopLevelContext", () => {
|
|
7
|
-
test("renders basic snapshot with directories and
|
|
8
|
+
test("renders basic snapshot with directories, files, and host env", () => {
|
|
8
9
|
const snapshot: TopLevelSnapshot = {
|
|
9
10
|
rootPath: "/sandbox",
|
|
10
11
|
directories: ["lib", "src", "tests"],
|
|
@@ -19,6 +20,8 @@ describe("renderWorkspaceTopLevelContext", () => {
|
|
|
19
20
|
"Root: /sandbox",
|
|
20
21
|
"Directories: lib, src, tests",
|
|
21
22
|
"Files: README.md, package.json",
|
|
23
|
+
`Host home directory: ${homedir()}`,
|
|
24
|
+
`Host username: ${userInfo().username}`,
|
|
22
25
|
"</workspace>",
|
|
23
26
|
].join("\n"),
|
|
24
27
|
);
|
|
@@ -65,6 +68,8 @@ describe("renderWorkspaceTopLevelContext", () => {
|
|
|
65
68
|
"Root: /empty",
|
|
66
69
|
"Directories: ",
|
|
67
70
|
"Files: ",
|
|
71
|
+
`Host home directory: ${homedir()}`,
|
|
72
|
+
`Host username: ${userInfo().username}`,
|
|
68
73
|
"</workspace>",
|
|
69
74
|
].join("\n"),
|
|
70
75
|
);
|
|
@@ -142,4 +147,71 @@ describe("renderWorkspaceTopLevelContext", () => {
|
|
|
142
147
|
);
|
|
143
148
|
expect(result).not.toContain("Current conversation folder");
|
|
144
149
|
});
|
|
150
|
+
|
|
151
|
+
test("prefers client-reported host env over daemon os.homedir()", () => {
|
|
152
|
+
const snapshot: TopLevelSnapshot = {
|
|
153
|
+
rootPath: "/sandbox",
|
|
154
|
+
directories: ["src"],
|
|
155
|
+
files: ["package.json"],
|
|
156
|
+
truncated: false,
|
|
157
|
+
};
|
|
158
|
+
|
|
159
|
+
const result = renderWorkspaceTopLevelContext(snapshot, {
|
|
160
|
+
hostHomeDir: "/Users/alice",
|
|
161
|
+
hostUsername: "alice",
|
|
162
|
+
});
|
|
163
|
+
|
|
164
|
+
expect(result).toContain("Host home directory: /Users/alice");
|
|
165
|
+
expect(result).toContain("Host username: alice");
|
|
166
|
+
// Fallback values must NOT appear when client values are provided.
|
|
167
|
+
expect(result).not.toContain(`Host home directory: ${homedir()}`);
|
|
168
|
+
expect(result).not.toContain(`Host username: ${userInfo().username}`);
|
|
169
|
+
});
|
|
170
|
+
|
|
171
|
+
test("falls back to daemon os info when host env options omitted", () => {
|
|
172
|
+
const snapshot: TopLevelSnapshot = {
|
|
173
|
+
rootPath: "/sandbox",
|
|
174
|
+
directories: ["src"],
|
|
175
|
+
files: ["package.json"],
|
|
176
|
+
truncated: false,
|
|
177
|
+
};
|
|
178
|
+
|
|
179
|
+
const result = renderWorkspaceTopLevelContext(snapshot, {});
|
|
180
|
+
|
|
181
|
+
expect(result).toContain(`Host home directory: ${homedir()}`);
|
|
182
|
+
expect(result).toContain(`Host username: ${userInfo().username}`);
|
|
183
|
+
});
|
|
184
|
+
|
|
185
|
+
test("falls back to daemon os info when host env options are undefined", () => {
|
|
186
|
+
const snapshot: TopLevelSnapshot = {
|
|
187
|
+
rootPath: "/sandbox",
|
|
188
|
+
directories: ["src"],
|
|
189
|
+
files: ["package.json"],
|
|
190
|
+
truncated: false,
|
|
191
|
+
};
|
|
192
|
+
|
|
193
|
+
const result = renderWorkspaceTopLevelContext(snapshot, {
|
|
194
|
+
hostHomeDir: undefined,
|
|
195
|
+
hostUsername: undefined,
|
|
196
|
+
});
|
|
197
|
+
|
|
198
|
+
expect(result).toContain(`Host home directory: ${homedir()}`);
|
|
199
|
+
expect(result).toContain(`Host username: ${userInfo().username}`);
|
|
200
|
+
});
|
|
201
|
+
|
|
202
|
+
test("uses client home dir but falls back to os username when only home is provided", () => {
|
|
203
|
+
const snapshot: TopLevelSnapshot = {
|
|
204
|
+
rootPath: "/sandbox",
|
|
205
|
+
directories: ["src"],
|
|
206
|
+
files: ["package.json"],
|
|
207
|
+
truncated: false,
|
|
208
|
+
};
|
|
209
|
+
|
|
210
|
+
const result = renderWorkspaceTopLevelContext(snapshot, {
|
|
211
|
+
hostHomeDir: "/Users/alice",
|
|
212
|
+
});
|
|
213
|
+
|
|
214
|
+
expect(result).toContain("Host home directory: /Users/alice");
|
|
215
|
+
expect(result).toContain(`Host username: ${userInfo().username}`);
|
|
216
|
+
});
|
|
145
217
|
});
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import { describe, expect, test } from "bun:test";
|
|
2
|
+
|
|
3
|
+
import type {
|
|
4
|
+
HostProxyTransportMetadata,
|
|
5
|
+
NonHostProxyTransportMetadata,
|
|
6
|
+
} from "../daemon/message-types/conversations.js";
|
|
7
|
+
import { buildTransportHints } from "../daemon/transport-hints.js";
|
|
8
|
+
|
|
9
|
+
// ---------------------------------------------------------------------------
|
|
10
|
+
// buildTransportHints
|
|
11
|
+
// ---------------------------------------------------------------------------
|
|
12
|
+
|
|
13
|
+
describe("buildTransportHints", () => {
|
|
14
|
+
test("returns empty array for host-proxy transport without client hints", () => {
|
|
15
|
+
const transport: HostProxyTransportMetadata = {
|
|
16
|
+
channelId: "vellum",
|
|
17
|
+
interfaceId: "macos",
|
|
18
|
+
hostHomeDir: "/Users/alice",
|
|
19
|
+
hostUsername: "alice",
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
const hints = buildTransportHints(transport);
|
|
23
|
+
|
|
24
|
+
expect(hints).toHaveLength(0);
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
test("returns empty array for non-host-proxy transport without client hints", () => {
|
|
28
|
+
const transport: NonHostProxyTransportMetadata = {
|
|
29
|
+
channelId: "vellum",
|
|
30
|
+
interfaceId: "ios",
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
const hints = buildTransportHints(transport);
|
|
34
|
+
|
|
35
|
+
expect(hints).toHaveLength(0);
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
test("forwards client-provided hints", () => {
|
|
39
|
+
const transport: HostProxyTransportMetadata = {
|
|
40
|
+
channelId: "vellum",
|
|
41
|
+
interfaceId: "macos",
|
|
42
|
+
hostHomeDir: "/Users/bob",
|
|
43
|
+
hostUsername: "bob",
|
|
44
|
+
hints: ["custom hint"],
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
const hints = buildTransportHints(transport);
|
|
48
|
+
|
|
49
|
+
expect(hints).toEqual(["custom hint"]);
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
test("returns empty array when no hints field present", () => {
|
|
53
|
+
const transport: HostProxyTransportMetadata = {
|
|
54
|
+
channelId: "vellum",
|
|
55
|
+
interfaceId: "macos",
|
|
56
|
+
};
|
|
57
|
+
|
|
58
|
+
const hints = buildTransportHints(transport);
|
|
59
|
+
|
|
60
|
+
expect(hints).toHaveLength(0);
|
|
61
|
+
});
|
|
62
|
+
});
|
|
@@ -909,8 +909,8 @@ describe("Trust Store", () => {
|
|
|
909
909
|
expect(match!.id).toBe("default:allow-bash-rm-bootstrap");
|
|
910
910
|
expect(match!.decision).toBe("allow");
|
|
911
911
|
expect(match!.allowHighRisk).toBe(true);
|
|
912
|
-
// Outside workspace, the bootstrap rule doesn't match —
|
|
913
|
-
//
|
|
912
|
+
// Outside workspace, the bootstrap rule doesn't match — without
|
|
913
|
+
// IS_CONTAINERIZED there is no catch-all bash allow rule either.
|
|
914
914
|
const other = findHighestPriorityRule(
|
|
915
915
|
"bash",
|
|
916
916
|
["rm BOOTSTRAP.md"],
|
|
@@ -930,8 +930,8 @@ describe("Trust Store", () => {
|
|
|
930
930
|
expect(match!.id).toBe("default:allow-bash-rm-updates");
|
|
931
931
|
expect(match!.decision).toBe("allow");
|
|
932
932
|
expect(match!.allowHighRisk).toBe(true);
|
|
933
|
-
// Outside workspace, should NOT match the updates rule —
|
|
934
|
-
//
|
|
933
|
+
// Outside workspace, should NOT match the updates rule — without
|
|
934
|
+
// IS_CONTAINERIZED there is no catch-all bash allow rule either.
|
|
935
935
|
const other = findHighestPriorityRule(
|
|
936
936
|
"bash",
|
|
937
937
|
["rm UPDATES.md"],
|