@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
|
@@ -20,7 +20,6 @@ import { existsSync, readFileSync } from "node:fs";
|
|
|
20
20
|
import { homedir } from "node:os";
|
|
21
21
|
import { dirname, join } from "node:path";
|
|
22
22
|
|
|
23
|
-
import { getIsContainerized } from "./env-registry.js";
|
|
24
23
|
import type { AssistantConfig } from "./schema.js";
|
|
25
24
|
|
|
26
25
|
// ---------------------------------------------------------------------------
|
|
@@ -173,61 +172,49 @@ function loadOverridesFromFile(): Record<string, boolean> {
|
|
|
173
172
|
}
|
|
174
173
|
|
|
175
174
|
/**
|
|
176
|
-
*
|
|
175
|
+
* Fetch override values from the gateway via async HTTP.
|
|
177
176
|
*
|
|
178
|
-
*
|
|
179
|
-
*
|
|
180
|
-
* gateway returns `{ flags: Array<{ key, enabled, ... }> }` and we extract
|
|
181
|
-
* just the key → enabled map.
|
|
177
|
+
* Returns the gateway's merged feature flag map (persisted > remote >
|
|
178
|
+
* registry), or an empty record on any failure (network, auth, parse).
|
|
182
179
|
*/
|
|
183
|
-
function
|
|
180
|
+
async function fetchOverridesFromGateway(): Promise<Record<string, boolean>> {
|
|
184
181
|
try {
|
|
185
182
|
// Lazy-import to avoid circular dependency and keep this module
|
|
186
183
|
// importable from bootstrap code when not in containerized mode.
|
|
187
184
|
const { getGatewayInternalBaseUrl } =
|
|
188
185
|
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
|
189
186
|
require("./env.js") as typeof import("./env.js");
|
|
190
|
-
const {
|
|
187
|
+
const {
|
|
188
|
+
mintEdgeRelayToken,
|
|
189
|
+
isSigningKeyInitialized,
|
|
190
|
+
initAuthSigningKey,
|
|
191
|
+
resolveSigningKey,
|
|
192
|
+
} =
|
|
191
193
|
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
|
192
194
|
require("../runtime/auth/token-service.js") as typeof import("../runtime/auth/token-service.js");
|
|
193
195
|
|
|
196
|
+
// CLI subprocesses don't run daemon startup, so the signing key
|
|
197
|
+
// may not be initialized yet. Initialize it now so mintEdgeRelayToken
|
|
198
|
+
// can produce a valid JWT for the gateway request.
|
|
199
|
+
if (!isSigningKeyInitialized()) {
|
|
200
|
+
initAuthSigningKey(resolveSigningKey());
|
|
201
|
+
}
|
|
202
|
+
|
|
194
203
|
const url = `${getGatewayInternalBaseUrl()}/v1/feature-flags`;
|
|
195
204
|
const token = mintEdgeRelayToken();
|
|
196
205
|
|
|
197
|
-
const
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
"
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
"Accept: application/json",
|
|
210
|
-
"-w",
|
|
211
|
-
"\n%{http_code}",
|
|
212
|
-
url,
|
|
213
|
-
],
|
|
214
|
-
{ stdout: "pipe", stderr: "pipe" },
|
|
215
|
-
);
|
|
216
|
-
|
|
217
|
-
if (proc.exitCode !== 0) return {};
|
|
218
|
-
|
|
219
|
-
const output = proc.stdout.toString().trim();
|
|
220
|
-
const lastNewline = output.lastIndexOf("\n");
|
|
221
|
-
const responseBody = lastNewline >= 0 ? output.slice(0, lastNewline) : "";
|
|
222
|
-
const statusCode = parseInt(
|
|
223
|
-
lastNewline >= 0 ? output.slice(lastNewline + 1) : output,
|
|
224
|
-
10,
|
|
225
|
-
);
|
|
226
|
-
|
|
227
|
-
if (statusCode < 200 || statusCode >= 300) return {};
|
|
228
|
-
if (!responseBody) return {};
|
|
229
|
-
|
|
230
|
-
const parsed = JSON.parse(responseBody) as {
|
|
206
|
+
const response = await fetch(url, {
|
|
207
|
+
method: "GET",
|
|
208
|
+
headers: {
|
|
209
|
+
Authorization: `Bearer ${token}`,
|
|
210
|
+
Accept: "application/json",
|
|
211
|
+
},
|
|
212
|
+
signal: AbortSignal.timeout(10_000),
|
|
213
|
+
});
|
|
214
|
+
|
|
215
|
+
if (!response.ok) return {};
|
|
216
|
+
|
|
217
|
+
const parsed = (await response.json()) as {
|
|
231
218
|
flags?: Array<{ key: string; enabled: boolean }>;
|
|
232
219
|
};
|
|
233
220
|
if (!Array.isArray(parsed.flags)) return {};
|
|
@@ -245,25 +232,42 @@ function loadOverridesFromGateway(): Record<string, boolean> {
|
|
|
245
232
|
}
|
|
246
233
|
|
|
247
234
|
/**
|
|
248
|
-
*
|
|
235
|
+
* Pre-populate the override cache from the gateway (async).
|
|
249
236
|
*
|
|
250
|
-
*
|
|
251
|
-
*
|
|
252
|
-
* the gateway
|
|
237
|
+
* Call this once during startup (daemon or CLI entry) before any sync
|
|
238
|
+
* `isAssistantFeatureFlagEnabled` calls. In containerized mode, always
|
|
239
|
+
* uses the gateway. In local mode, falls back to the local file when
|
|
240
|
+
* the gateway is unreachable.
|
|
253
241
|
*
|
|
254
|
-
*
|
|
242
|
+
* On failure, the cache is left unset so subsequent sync calls fall
|
|
243
|
+
* through to the file-based fallback rather than caching an empty map
|
|
244
|
+
* that masks all overrides for the process lifetime.
|
|
255
245
|
*/
|
|
256
|
-
function
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
const gatewayOverrides = loadOverridesFromGateway();
|
|
260
|
-
if (Object.keys(gatewayOverrides).length > 0 || getIsContainerized()) {
|
|
246
|
+
export async function initFeatureFlagOverrides(): Promise<void> {
|
|
247
|
+
const gatewayOverrides = await fetchOverridesFromGateway();
|
|
248
|
+
if (Object.keys(gatewayOverrides).length > 0) {
|
|
261
249
|
cachedOverrides = gatewayOverrides;
|
|
262
|
-
return
|
|
250
|
+
return;
|
|
263
251
|
}
|
|
264
252
|
|
|
265
|
-
//
|
|
266
|
-
// (
|
|
253
|
+
// Gateway returned empty or failed. Leave the cache unset so
|
|
254
|
+
// loadOverrides() falls through to file on the next sync read,
|
|
255
|
+
// regardless of containerized vs local mode.
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
/**
|
|
259
|
+
* Read cached overrides synchronously.
|
|
260
|
+
*
|
|
261
|
+
* If `initFeatureFlagOverrides()` was called at startup, this returns the
|
|
262
|
+
* pre-populated cache. Otherwise falls back to the local file — this
|
|
263
|
+
* ensures the resolver never blocks on a network call.
|
|
264
|
+
*/
|
|
265
|
+
function loadOverrides(): Record<string, boolean> {
|
|
266
|
+
if (cachedOverrides != null) return cachedOverrides;
|
|
267
|
+
|
|
268
|
+
// Cache not yet populated (initFeatureFlagOverrides wasn't called or
|
|
269
|
+
// hasn't finished). Fall back to the local file so the resolver still
|
|
270
|
+
// works, just without gateway data.
|
|
267
271
|
cachedOverrides = loadOverridesFromFile();
|
|
268
272
|
return cachedOverrides;
|
|
269
273
|
}
|
|
@@ -8,6 +8,10 @@ metadata:
|
|
|
8
8
|
display-name: "App Builder"
|
|
9
9
|
includes:
|
|
10
10
|
- "frontend-design"
|
|
11
|
+
activation-hints:
|
|
12
|
+
- "User asks to build an app, landing page, website, dashboard, tool, calculator, game, tracker, or interactive page"
|
|
13
|
+
- "User asks to visualize data or says 'let's visualize this' — use the app sandbox to build interactive visualizations"
|
|
14
|
+
- "ALWAYS prefer the app sandbox over building standalone web apps, local servers, or outputting raw HTML/CSS/JS in chat — even when the user says 'make this an app' or 'turn this into an app'"
|
|
11
15
|
---
|
|
12
16
|
|
|
13
17
|
You are an expert app builder and visual designer. When the user asks you to create an app, tool, or utility, you immediately design a data schema, choose a stunning visual direction, build the interface, and open it - all in one step. You don't discuss or ask for permission to be creative. You ARE the designer: you pick the colors, the layout, the atmosphere, the micro-interactions. Your apps should make users stop and say "whoa" - they should feel designed, not generated.
|
|
@@ -173,13 +177,16 @@ export const Header: FunctionComponent<Props> = ({ title, count }) => {
|
|
|
173
177
|
|
|
174
178
|
**CSS:** Import CSS files directly in TSX (`import './styles.css'`). You can also use inline styles via the `style` attribute on JSX elements.
|
|
175
179
|
|
|
176
|
-
**
|
|
180
|
+
**Custom routes in TSX:** Use `window.vellum.fetch()` to call custom route handlers from components — see the [Custom route handlers](#custom-route-handlers-user-defined-routes) section for full details:
|
|
177
181
|
|
|
178
182
|
```tsx
|
|
179
|
-
const [
|
|
183
|
+
const [items, setItems] = useState<Item[]>([]);
|
|
180
184
|
|
|
181
185
|
useEffect(() => {
|
|
182
|
-
window.vellum.
|
|
186
|
+
window.vellum.fetch("/v1/x/items")
|
|
187
|
+
.then((res) => (res.ok ? res.json() : Promise.reject(res.status)))
|
|
188
|
+
.then(setItems)
|
|
189
|
+
.catch(console.error);
|
|
183
190
|
}, []);
|
|
184
191
|
```
|
|
185
192
|
|
|
@@ -211,7 +218,10 @@ export const App: FunctionComponent = () => {
|
|
|
211
218
|
const [records, setRecords] = useState([]);
|
|
212
219
|
|
|
213
220
|
useEffect(() => {
|
|
214
|
-
window.vellum.
|
|
221
|
+
window.vellum.fetch("/v1/x/projects")
|
|
222
|
+
.then((res) => res.ok ? res.json() : Promise.reject(res.status))
|
|
223
|
+
.then(setRecords)
|
|
224
|
+
.catch(console.error);
|
|
215
225
|
}, []);
|
|
216
226
|
|
|
217
227
|
return (
|
|
@@ -309,131 +319,15 @@ window.addEventListener("vellum-theme-change", (e) => {
|
|
|
309
319
|
|
|
310
320
|
#### Widget component library
|
|
311
321
|
|
|
312
|
-
A CSS/JS widget library is auto-injected alongside the design system. Use
|
|
313
|
-
|
|
314
|
-
**Layout widgets** (class names, infer HTML structure):
|
|
315
|
-
|
|
316
|
-
| Widget | Purpose |
|
|
317
|
-
| ------------------------------------------------------------ | -------------------------------------------------------------- |
|
|
318
|
-
| `.v-metric-card` (`.v-metric-grid`) | Big number with emoji icon, label, trend |
|
|
319
|
-
| `.v-data-table` | Sortable table with sticky header, `th[data-sortable]` |
|
|
320
|
-
| `.v-tabs` / `.v-tab-bar` / `.v-tab-panel` | Tab navigation with keyboard support |
|
|
321
|
-
| `.v-accordion` / `.v-accordion-item` | Collapsible sections |
|
|
322
|
-
| `.v-search-bar` | Search input with clear button |
|
|
323
|
-
| `.v-empty-state` | No-data placeholder with CTA |
|
|
324
|
-
| `.v-timeline` / `.v-timeline-entry` | Vertical timeline (`.active`/`.success`/`.error`) |
|
|
325
|
-
| `.v-action-list` / `.v-action-list-item` | Rows with per-item actions |
|
|
326
|
-
| `.v-card-grid` | Responsive card grid |
|
|
327
|
-
| `.v-progress-bar` / `.v-progress-track` / `.v-progress-fill` | Horizontal progress |
|
|
328
|
-
| `.v-status-badge` | Colored pill with dot (`.success`/`.error`/`.warning`/`.info`) |
|
|
329
|
-
| `.v-stat-row` / `.v-stat` | Horizontal label-value pairs |
|
|
330
|
-
| `.v-toast` | Notification banner - prefer `vellum.widgets.toast()` |
|
|
331
|
-
| `.v-avatar-row` | Contact/team display |
|
|
332
|
-
| `.v-tag-group` | Wrapping tag row |
|
|
333
|
-
|
|
334
|
-
**Domain-specific widgets** (class names, infer HTML structure):
|
|
335
|
-
|
|
336
|
-
| Widget | Purpose |
|
|
337
|
-
| ------------------ | ---------------------- |
|
|
338
|
-
| `.v-weather-card` | Temperature + forecast |
|
|
339
|
-
| `.v-stock-ticker` | Price display + chart |
|
|
340
|
-
| `.v-flight-card` | Flight info with route |
|
|
341
|
-
| `.v-billing-chart` | Usage/billing display |
|
|
342
|
-
| `.v-boarding-pass` | Pass-styled layout |
|
|
343
|
-
| `.v-itinerary` | Day-by-day travel plan |
|
|
344
|
-
| `.v-receipt` | Receipt layout |
|
|
345
|
-
| `.v-invoice` | Formal invoice |
|
|
346
|
-
|
|
347
|
-
**Content & landing page components** (class names, infer HTML structure):
|
|
348
|
-
|
|
349
|
-
| Widget | Purpose |
|
|
350
|
-
| ------------------------------------------------ | --------------------------------------------------- |
|
|
351
|
-
| `.v-hero` / `.v-hero-badge` / `.v-hero-subtitle` | Hero banner with gradient, trust badge, accent word |
|
|
352
|
-
| `.v-section-header` / `.v-section-label` | Section intro with label |
|
|
353
|
-
| `.v-feature-grid` / `.v-feature-card` | Feature showcase with hover lift |
|
|
354
|
-
| `.v-pullquote` | Blockquote with gradient accent border |
|
|
355
|
-
| `.v-comparison` | Before/after cards (`.before`/`.after`) |
|
|
356
|
-
| `.v-page` | Centered container (max-width 600px) |
|
|
357
|
-
| `.v-gradient-text` | Accent-colored gradient text |
|
|
358
|
-
| `.v-animate-in` | Staggered fade-in for children |
|
|
359
|
-
|
|
360
|
-
#### Widget JavaScript utilities
|
|
361
|
-
|
|
362
|
-
Interactive utilities at `window.vellum.widgets.*`:
|
|
363
|
-
|
|
364
|
-
**Charts** (always use these instead of hand-coding SVG/CSS charts):
|
|
322
|
+
A CSS/JS widget library is auto-injected alongside the design system. Use `.v-*` class names for standard UI patterns (tables, metrics, timelines, cards, etc.) and `window.vellum.widgets.*` JS utilities for charts, data formatting, and interactive behaviors. **ALWAYS use `vellum.widgets.*` chart functions** instead of hand-coding SVG/CSS charts.
|
|
365
323
|
|
|
366
|
-
|
|
367
|
-
vellum.widgets.sparkline("container-id", [10, 25, 15, 30], {
|
|
368
|
-
width: 200,
|
|
369
|
-
height: 40,
|
|
370
|
-
color: "var(--v-success)",
|
|
371
|
-
strokeWidth: 2,
|
|
372
|
-
fill: true,
|
|
373
|
-
});
|
|
374
|
-
vellum.widgets.barChart(
|
|
375
|
-
"container-id",
|
|
376
|
-
[
|
|
377
|
-
{ label: "Jan", value: 120 },
|
|
378
|
-
{ label: "Feb", value: 180, color: "var(--v-success)" },
|
|
379
|
-
],
|
|
380
|
-
{
|
|
381
|
-
width: 400,
|
|
382
|
-
height: 200,
|
|
383
|
-
showLabels: true,
|
|
384
|
-
showValues: true,
|
|
385
|
-
horizontal: false,
|
|
386
|
-
},
|
|
387
|
-
);
|
|
388
|
-
vellum.widgets.lineChart(
|
|
389
|
-
"container-id",
|
|
390
|
-
[
|
|
391
|
-
{ label: "Mon", value: 42 },
|
|
392
|
-
{ label: "Tue", value: 58 },
|
|
393
|
-
],
|
|
394
|
-
{ width: 400, height: 200, showDots: true, showGrid: true, gridLines: 4 },
|
|
395
|
-
);
|
|
396
|
-
vellum.widgets.progressRing("container-id", 75, {
|
|
397
|
-
size: 100,
|
|
398
|
-
strokeWidth: 8,
|
|
399
|
-
color: "var(--v-success)",
|
|
400
|
-
label: "75%",
|
|
401
|
-
});
|
|
402
|
-
```
|
|
403
|
-
|
|
404
|
-
**Data Formatting:**
|
|
405
|
-
|
|
406
|
-
```javascript
|
|
407
|
-
vellum.widgets.formatCurrency(1234.56, "USD"); // "$1,234.56"
|
|
408
|
-
vellum.widgets.formatDate("2025-01-15", "relative"); // "3d ago"
|
|
409
|
-
vellum.widgets.formatDate("2025-01-15", "short"); // "1/15/25"
|
|
410
|
-
vellum.widgets.formatNumber(1234567, { compact: true }); // "1.2M"
|
|
411
|
-
```
|
|
324
|
+
For the full widget reference (class names, JS APIs, chart functions, formatting utilities), see **[Widget Component Library](references/WIDGETS.md)**.
|
|
412
325
|
|
|
413
|
-
|
|
326
|
+
#### Data bridge API (deprecated)
|
|
414
327
|
|
|
415
|
-
|
|
416
|
-
vellum.widgets.sortTable("table-id"); // Wire th[data-sortable] click-to-sort
|
|
417
|
-
vellum.widgets.filterTable("table-id", "input-id"); // Live text search
|
|
418
|
-
vellum.widgets.tabs("tabs-id"); // Tab switching + keyboard nav
|
|
419
|
-
vellum.widgets.accordion("accordion-id", { allowMultiple: true });
|
|
420
|
-
vellum.widgets.multiSelect("table-id"); // Checkboxes + select-all
|
|
421
|
-
vellum.widgets.toast("Saved!", "success", 4000); // Auto-dismiss notification
|
|
422
|
-
vellum.widgets.countdown("timer-el", "2025-12-31T00:00:00Z", {
|
|
423
|
-
onComplete: () => {},
|
|
424
|
-
});
|
|
425
|
-
```
|
|
426
|
-
|
|
427
|
-
#### When to use widgets vs custom HTML
|
|
428
|
-
|
|
429
|
-
- **Use widgets** for standard patterns - tables, metrics, timelines, notifications
|
|
430
|
-
- **Use custom HTML** for novel or creative UIs - games, art tools, unique dashboards
|
|
431
|
-
- **Mix freely** - widgets compose well together and with custom elements
|
|
432
|
-
- **ALWAYS use `vellum.widgets.*` chart functions** instead of hand-coding SVG/CSS charts. They handle overflow clipping, bounds, scaling, and dark mode. Hand-coded charts break layouts.
|
|
328
|
+
> **Prefer custom route handlers** for new apps. The data bridge (`window.vellum.data`) only works for assistants that run on the same machine as the desktop app, which will also be deprecated soon.
|
|
433
329
|
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
The HTML interface can read and write records via `window.vellum.data`. All methods return Promises.
|
|
330
|
+
The native WebView can read and write app records via `window.vellum.data`. All methods return Promises.
|
|
437
331
|
|
|
438
332
|
- `window.vellum.data.query()` - Returns all records: `{ id, appId, data, createdAt, updatedAt }[]`
|
|
439
333
|
- `window.vellum.data.create(data)` - Creates a record. Returns the created record.
|
|
@@ -448,9 +342,15 @@ Important:
|
|
|
448
342
|
- All operations are async - use `async/await`
|
|
449
343
|
- Wrap all calls in `try/catch`
|
|
450
344
|
|
|
345
|
+
#### Custom route handlers (user-defined routes)
|
|
346
|
+
|
|
347
|
+
When the app needs server-side persistence, custom API logic, or workspace file access, use **user-defined routes**. Route handlers are TypeScript/JavaScript files in the workspace `routes/` directory, served under `/v1/x/`. Call them from the frontend via `window.vellum.fetch("/v1/x/...")`. **Never use raw `fetch()` for `/v1/x/` routes** — it will fail in the sandboxed origin.
|
|
348
|
+
|
|
349
|
+
For handler conventions, examples, key rules, and frontend usage patterns, see **[Custom Route Handlers](references/CUSTOM_ROUTES.md)**.
|
|
350
|
+
|
|
451
351
|
#### Client-side state management
|
|
452
352
|
|
|
453
|
-
`localStorage` and `sessionStorage` are available for ephemeral UI state (filters, view modes, collapsed state, preferences, form drafts). Use
|
|
353
|
+
`localStorage` and `sessionStorage` are available for ephemeral UI state (filters, view modes, collapsed state, preferences, form drafts). Use custom routes for persistent app records, `localStorage` for UI preferences.
|
|
454
354
|
|
|
455
355
|
<!-- feature:app-builder-multifile:alt -->
|
|
456
356
|
|
|
@@ -467,7 +367,9 @@ let allRecords = [];
|
|
|
467
367
|
|
|
468
368
|
async function loadRecords() {
|
|
469
369
|
try {
|
|
470
|
-
|
|
370
|
+
const res = await window.vellum.fetch("/v1/x/records");
|
|
371
|
+
if (!res.ok) throw new Error(`HTTP ${res.status}`);
|
|
372
|
+
allRecords = await res.json();
|
|
471
373
|
render();
|
|
472
374
|
} catch (err) {
|
|
473
375
|
console.error("Failed to load:", err);
|
|
@@ -556,7 +458,7 @@ Every app must meet these baselines:
|
|
|
556
458
|
|
|
557
459
|
## Presentation Slide Design
|
|
558
460
|
|
|
559
|
-
Slides are a different domain from apps. Skip app-specific patterns (contextual headers, search/filter, toast notifications, form validation,
|
|
461
|
+
Slides are a different domain from apps. Skip app-specific patterns (contextual headers, search/filter, toast notifications, form validation, custom routes). Slides are static content — build navigation and layouts with custom HTML/CSS.
|
|
560
462
|
|
|
561
463
|
**Key principles:**
|
|
562
464
|
|
|
@@ -569,58 +471,16 @@ Slides are a different domain from apps. Skip app-specific patterns (contextual
|
|
|
569
471
|
|
|
570
472
|
## Error Handling
|
|
571
473
|
|
|
572
|
-
- All `window.vellum.
|
|
474
|
+
- All `window.vellum.fetch()` calls to custom routes must be wrapped in `try/catch` with user-friendly feedback. Always check `res.ok` before parsing the response body.
|
|
573
475
|
- Never let a failed operation silently pass - always show a toast or inline error.
|
|
574
476
|
- If the page loads with no data, show a designed empty state (`.v-empty-state`).
|
|
575
477
|
- For forms, show validation errors inline next to the relevant field.
|
|
576
478
|
|
|
577
479
|
## App Interaction Hooks
|
|
578
480
|
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
### Reactive hooks
|
|
582
|
-
|
|
583
|
-
Reactive hooks trigger an assistant response. Use them for moments where the assistant's input adds value - selections that need explanation, completions worth celebrating, or submissions that benefit from feedback.
|
|
584
|
-
|
|
585
|
-
```javascript
|
|
586
|
-
// User selects a city on a map — assistant can provide insights
|
|
587
|
-
window.vellum.sendAction('city_selected', { city: 'Tokyo' });
|
|
588
|
-
|
|
589
|
-
// User submits a form — assistant can confirm and suggest next steps
|
|
590
|
-
window.vellum.sendAction('form_submitted', { formId: 'signup', email: 'user@example.com' });
|
|
591
|
-
|
|
592
|
-
// User completes a level — assistant can congratulate and hint at what's next
|
|
593
|
-
window.vellum.sendAction('level_complete', { level: 5, score: 2400 });
|
|
594
|
-
```
|
|
595
|
-
|
|
596
|
-
### Silent hooks
|
|
597
|
-
|
|
598
|
-
Silent hooks accumulate state without interrupting the user. The state is automatically included as context when the next reactive hook fires.
|
|
599
|
-
|
|
600
|
-
```javascript
|
|
601
|
-
// User navigates to a new tab — no response needed, but assistant should know
|
|
602
|
-
window.vellum.sendAction('state_update', { currentView: 'forecast', city: 'Tokyo' });
|
|
603
|
-
|
|
604
|
-
// Score changes during gameplay — track silently
|
|
605
|
-
window.vellum.sendAction('state_update', { score: 1250, lives: 2 });
|
|
606
|
-
|
|
607
|
-
// User applies a filter — context for future questions
|
|
608
|
-
window.vellum.sendAction('state_update', { filter: 'last-30-days', sortBy: 'revenue' });
|
|
609
|
-
```
|
|
610
|
-
|
|
611
|
-
### When to use reactive vs silent
|
|
612
|
-
|
|
613
|
-
Choose based on whether the assistant's response would genuinely help the user at that moment:
|
|
614
|
-
|
|
615
|
-
| App type | Silent (state accumulation) | Reactive (triggers response) |
|
|
616
|
-
|---|---|---|
|
|
617
|
-
| **Dashboards** | Tab navigation, filter changes, date range selection | Anomaly detected, threshold breached, data export complete |
|
|
618
|
-
| **Games** | Score updates, move tracking, timer ticks | Level complete, achievement unlocked, game over |
|
|
619
|
-
| **Forms & wizards** | Field focus, partial input, step navigation | Form submitted, validation failed on submit |
|
|
620
|
-
| **Trackers** | Incremental progress, status toggles, reordering | Milestone reached, streak achieved, all items complete |
|
|
621
|
-
| **Data explorers** | Sorting, paging, column toggling | Row selected for detail, comparison initiated |
|
|
481
|
+
Proactively wire `window.vellum.sendAction()` hooks so the assistant stays aware of meaningful user interactions. Two patterns: **reactive** hooks (trigger assistant response) and **silent** hooks (`state_update` — accumulate context without interrupting). Wire hooks during the initial build, don't wait for the user to ask.
|
|
622
482
|
|
|
623
|
-
|
|
483
|
+
For examples, reactive vs silent guidance, and per-app-type recommendations, see **[App Interaction Hooks](references/INTERACTION_HOOKS.md)**.
|
|
624
484
|
|
|
625
485
|
## Actionable UI
|
|
626
486
|
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
# Custom Route Handlers (User-Defined Routes)
|
|
2
|
+
|
|
3
|
+
When the app needs server-side persistence, custom API logic, or workspace file access, use **user-defined routes**. Route handlers are TypeScript or JavaScript files that live in the workspace `routes/` directory and are served under the `/v1/x/` URL path.
|
|
4
|
+
|
|
5
|
+
**Common use cases:** CRUD storage, file-based persistence, search/aggregation, external API proxying, webhook receivers.
|
|
6
|
+
|
|
7
|
+
## Handler file convention
|
|
8
|
+
|
|
9
|
+
Each handler file exports named functions for the HTTP methods it supports (`GET`, `POST`, `PUT`, `PATCH`, `DELETE`). Handlers use the standard Web API `Request`/`Response` signature.
|
|
10
|
+
|
|
11
|
+
```
|
|
12
|
+
{workspaceDir}/routes/
|
|
13
|
+
items.ts # Handles /v1/x/items
|
|
14
|
+
items/
|
|
15
|
+
[id].ts # Not supported — use query params instead
|
|
16
|
+
index.ts # Also handles /v1/x/items (index convention)
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
## Example handler — JSON file persistence
|
|
20
|
+
|
|
21
|
+
```typescript
|
|
22
|
+
// routes/items.ts
|
|
23
|
+
import { readFileSync, writeFileSync, mkdirSync, existsSync } from "node:fs";
|
|
24
|
+
import { join } from "node:path";
|
|
25
|
+
|
|
26
|
+
export const description = "Item CRUD — stores records as a JSON file";
|
|
27
|
+
|
|
28
|
+
const DATA_DIR = join(process.env.VELLUM_WORKSPACE_DIR!, "data");
|
|
29
|
+
const DATA_FILE = join(DATA_DIR, "items.json");
|
|
30
|
+
|
|
31
|
+
function loadItems(): Array<Record<string, unknown>> {
|
|
32
|
+
mkdirSync(DATA_DIR, { recursive: true });
|
|
33
|
+
if (!existsSync(DATA_FILE)) return [];
|
|
34
|
+
return JSON.parse(readFileSync(DATA_FILE, "utf-8"));
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
function saveItems(items: Array<Record<string, unknown>>): void {
|
|
38
|
+
mkdirSync(DATA_DIR, { recursive: true });
|
|
39
|
+
writeFileSync(DATA_FILE, JSON.stringify(items, null, 2));
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
export function GET(): Response {
|
|
43
|
+
return Response.json(loadItems());
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
export async function POST(request: Request): Promise<Response> {
|
|
47
|
+
const body = await request.json();
|
|
48
|
+
const items = loadItems();
|
|
49
|
+
const item = {
|
|
50
|
+
id: crypto.randomUUID(),
|
|
51
|
+
...body,
|
|
52
|
+
createdAt: new Date().toISOString(),
|
|
53
|
+
};
|
|
54
|
+
items.push(item);
|
|
55
|
+
saveItems(items);
|
|
56
|
+
return Response.json(item, { status: 201 });
|
|
57
|
+
}
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
## Calling routes from the app frontend
|
|
61
|
+
|
|
62
|
+
Apps call custom routes via `window.vellum.fetch()` using the `/v1/x/` prefix. This authenticated wrapper automatically injects the gateway URL and auth headers so requests reach the assistant runtime. **Never use raw `fetch()` for `/v1/x/` routes** — it will fail because the app runs in a sandboxed origin.
|
|
63
|
+
|
|
64
|
+
```typescript
|
|
65
|
+
// In a TSX component or HTML script
|
|
66
|
+
const res = await window.vellum.fetch("/v1/x/items");
|
|
67
|
+
if (!res.ok) throw new Error(`HTTP ${res.status}`);
|
|
68
|
+
const items = await res.json();
|
|
69
|
+
|
|
70
|
+
// Create a new item
|
|
71
|
+
const createRes = await window.vellum.fetch("/v1/x/items", {
|
|
72
|
+
method: "POST",
|
|
73
|
+
headers: { "Content-Type": "application/json" },
|
|
74
|
+
body: JSON.stringify({ name: "New item", status: "active" }),
|
|
75
|
+
});
|
|
76
|
+
if (!createRes.ok) throw new Error(`HTTP ${createRes.status}`);
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
## Key rules
|
|
80
|
+
|
|
81
|
+
- Always create the route handler files via `file_write` before calling `app_refresh`
|
|
82
|
+
- Export an optional `description` string for CLI discoverability (`assistant routes list`)
|
|
83
|
+
- Handlers have full Node.js API access — `fs`, `path`, `crypto`, etc.
|
|
84
|
+
- Handlers get a 30-second timeout per request
|
|
85
|
+
- Files are hot-reloaded on change (mtime-based cache)
|
|
86
|
+
- Use `.ts` (preferred) or `.js` extensions
|
|
87
|
+
- Route resolution: `routes/foo.ts` → `/v1/x/foo`, `routes/bar/index.ts` → `/v1/x/bar`
|
|
88
|
+
|
|
89
|
+
## Using custom routes in TSX components
|
|
90
|
+
|
|
91
|
+
```tsx
|
|
92
|
+
const [items, setItems] = useState<Item[]>([]);
|
|
93
|
+
|
|
94
|
+
useEffect(() => {
|
|
95
|
+
window.vellum
|
|
96
|
+
.fetch("/v1/x/items")
|
|
97
|
+
.then((res) => (res.ok ? res.json() : Promise.reject(res.status)))
|
|
98
|
+
.then(setItems)
|
|
99
|
+
.catch(console.error);
|
|
100
|
+
}, []);
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
## Error handling
|
|
104
|
+
|
|
105
|
+
All `window.vellum.fetch()` calls to custom routes must be wrapped in `try/catch` with user-friendly feedback. Always check `res.ok` before parsing the response body. Never let a failed operation silently pass — always show a toast or inline error.
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
# App Interaction Hooks
|
|
2
|
+
|
|
3
|
+
When building apps, proactively wire `sendAction` hooks so the assistant stays aware of meaningful user interactions. Two patterns are available:
|
|
4
|
+
|
|
5
|
+
## Reactive hooks
|
|
6
|
+
|
|
7
|
+
Reactive hooks trigger an assistant response. Use them for moments where the assistant's input adds value - selections that need explanation, completions worth celebrating, or submissions that benefit from feedback.
|
|
8
|
+
|
|
9
|
+
```javascript
|
|
10
|
+
// User selects a city on a map — assistant can provide insights
|
|
11
|
+
window.vellum.sendAction("city_selected", { city: "Tokyo" });
|
|
12
|
+
|
|
13
|
+
// User submits a form — assistant can confirm and suggest next steps
|
|
14
|
+
window.vellum.sendAction("form_submitted", {
|
|
15
|
+
formId: "signup",
|
|
16
|
+
email: "user@example.com",
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
// User completes a level — assistant can congratulate and hint at what's next
|
|
20
|
+
window.vellum.sendAction("level_complete", { level: 5, score: 2400 });
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
## Silent hooks
|
|
24
|
+
|
|
25
|
+
Silent hooks accumulate state without interrupting the user. The state is automatically included as context when the next reactive hook fires.
|
|
26
|
+
|
|
27
|
+
```javascript
|
|
28
|
+
// User navigates to a new tab — no response needed, but assistant should know
|
|
29
|
+
window.vellum.sendAction("state_update", {
|
|
30
|
+
currentView: "forecast",
|
|
31
|
+
city: "Tokyo",
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
// Score changes during gameplay — track silently
|
|
35
|
+
window.vellum.sendAction("state_update", { score: 1250, lives: 2 });
|
|
36
|
+
|
|
37
|
+
// User applies a filter — context for future questions
|
|
38
|
+
window.vellum.sendAction("state_update", {
|
|
39
|
+
filter: "last-30-days",
|
|
40
|
+
sortBy: "revenue",
|
|
41
|
+
});
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
## When to use reactive vs silent
|
|
45
|
+
|
|
46
|
+
Choose based on whether the assistant's response would genuinely help the user at that moment:
|
|
47
|
+
|
|
48
|
+
| App type | Silent (state accumulation) | Reactive (triggers response) |
|
|
49
|
+
| ------------------- | ---------------------------------------------------- | ---------------------------------------------------------- |
|
|
50
|
+
| **Dashboards** | Tab navigation, filter changes, date range selection | Anomaly detected, threshold breached, data export complete |
|
|
51
|
+
| **Games** | Score updates, move tracking, timer ticks | Level complete, achievement unlocked, game over |
|
|
52
|
+
| **Forms & wizards** | Field focus, partial input, step navigation | Form submitted, validation failed on submit |
|
|
53
|
+
| **Trackers** | Incremental progress, status toggles, reordering | Milestone reached, streak achieved, all items complete |
|
|
54
|
+
| **Data explorers** | Sorting, paging, column toggling | Row selected for detail, comparison initiated |
|
|
55
|
+
|
|
56
|
+
Wire hooks during the initial build - don't wait for the user to ask. Apps that communicate state back to the assistant feel alive; apps that don't feel like static pages.
|