@vellumai/assistant 0.12.1 → 0.12.2-staging.2
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/AGENTS.md +4 -0
- package/ARCHITECTURE.md +20 -21
- package/docs/architecture/turn-actor.md +15 -8
- package/docs/guardian-request-flow.md +16 -0
- package/node_modules/@vellumai/slack-text/src/index.ts +13 -8
- package/node_modules/@vellumai/slack-text/src/label-resolution-entities.test.ts +95 -0
- package/openapi.yaml +360 -51
- package/package.json +3 -1
- package/scripts/smoke-desktop-window-theme.ts +186 -0
- package/src/__tests__/always-loaded-tools-guard.test.ts +18 -10
- package/src/__tests__/anthropic-provider.test.ts +0 -63
- package/src/__tests__/app-compiler.test.ts +6 -0
- package/src/__tests__/app-control-tool-schemas.test.ts +5 -2
- package/src/__tests__/app-dir-path-guard.test.ts +1 -3
- package/src/__tests__/assistant-event-hub-machine-name.test.ts +6 -7
- package/src/__tests__/assistant-event-hub.test.ts +44 -0
- package/src/__tests__/computer-use-skill-manifest-regression.test.ts +1 -1
- package/src/__tests__/computer-use-skill-proxy-bridge.test.ts +5 -2
- package/src/__tests__/computer-use-tools.test.ts +19 -7
- package/src/__tests__/config-schema-cmd.test.ts +2 -2
- package/src/__tests__/config-schema.test.ts +28 -29
- package/src/__tests__/config-watcher.test.ts +23 -8
- package/src/__tests__/connection-model-compat.test.ts +2 -2
- package/src/__tests__/conversation-key-store-disk-view.test.ts +1 -1
- package/src/__tests__/conversation-pairing.test.ts +26 -0
- package/src/__tests__/conversation-process-app-control-preactivation.test.ts +4 -10
- package/src/__tests__/conversation-queue.test.ts +48 -207
- package/src/__tests__/conversation-retry-discard.test.ts +54 -1
- package/src/__tests__/conversation-runtime-assembly.test.ts +28 -0
- package/src/__tests__/conversation-skill-tools.test.ts +27 -0
- package/src/__tests__/conversation-surfaces-app-control.test.ts +8 -3
- package/src/__tests__/conversation-surfaces-point-at-budget.test.ts +1 -0
- package/src/__tests__/conversation-surfaces-point-at-capability.test.ts +1 -0
- package/src/__tests__/conversation-surfaces-task-progress.test.ts +67 -0
- package/src/__tests__/conversation-title-service.test.ts +14 -10
- package/src/__tests__/conversation-tool-setup-app-refresh.test.ts +3 -5
- package/src/__tests__/conversation-tool-setup-attribution.test.ts +51 -0
- package/src/__tests__/credential-record-retire.test.ts +171 -1
- package/src/__tests__/credential-routes.test.ts +250 -3
- package/src/__tests__/credential-security-invariants.test.ts +5 -3
- package/src/__tests__/cu-unified-flow.test.ts +14 -4
- package/src/__tests__/document-sync-tags.test.ts +25 -0
- package/src/__tests__/drain-kick-guard.test.ts +0 -2
- package/src/__tests__/drain-requeue-on-contention.test.ts +0 -6
- package/src/__tests__/evict-conversations-for-reload.test.ts +1 -1
- package/src/__tests__/git-porcelain.test.ts +47 -0
- package/src/__tests__/heartbeat-service.test.ts +56 -40
- package/src/__tests__/helpers/set-workspace-mcp.ts +11 -0
- package/src/__tests__/host-bash-proxy.test.ts +26 -45
- package/src/__tests__/host-browser-proxy.test.ts +6 -17
- package/src/__tests__/host-cu-proxy.test.ts +596 -0
- package/src/__tests__/host-file-proxy-targeted.test.ts +23 -0
- package/src/__tests__/host-file-proxy.test.ts +11 -23
- package/src/__tests__/host-transfer-proxy-targeted.test.ts +30 -9
- package/src/__tests__/list-messages-camera-frame.test.ts +121 -0
- package/src/__tests__/llm-catalog-parity.test.ts +25 -0
- package/src/__tests__/mcp-auth-routes.test.ts +6 -9
- package/src/__tests__/mcp-config-secret-boundary.test.ts +78 -136
- package/src/__tests__/mcp-health-check.test.ts +8 -11
- package/src/__tests__/mcp-list-plugin-servers.test.ts +8 -10
- package/src/__tests__/message-deleted-hook-dispatch.test.ts +119 -0
- package/src/__tests__/messages-after-tiebreaker.test.ts +91 -0
- package/src/__tests__/messages-read-boundary-guard.test.ts +1 -1
- package/src/__tests__/messaging-send-tool.test.ts +355 -548
- package/src/__tests__/model-intents.test.ts +3 -0
- package/src/__tests__/notification-vellum-adapter.test.ts +85 -2
- package/src/__tests__/oauth-commands-routes.test.ts +168 -0
- package/src/__tests__/oauth-provider-profiles.test.ts +18 -0
- package/src/__tests__/oauth-provider-serializer.test.ts +22 -0
- package/src/__tests__/oauth-providers-routes.test.ts +1 -0
- package/src/__tests__/openai-provider.test.ts +1 -0
- package/src/__tests__/outlook-messaging-provider.test.ts +6 -6
- package/src/__tests__/platform-callback-registration.test.ts +8 -16
- package/src/__tests__/platform-client-verify-credential.test.ts +2 -0
- package/src/__tests__/plugin-import-boundary-guard.test.ts +14 -0
- package/src/__tests__/qdrant-manager.test.ts +132 -0
- package/src/__tests__/resolve-app.test.ts +135 -0
- package/src/__tests__/scaffold-managed-skill-tool.test.ts +229 -6
- package/src/__tests__/script-proxy-certs.test.ts +35 -0
- package/src/__tests__/secret-routes-acp-guard.test.ts +59 -1
- package/src/__tests__/service-account-token.test.ts +247 -0
- package/src/__tests__/skill-feature-flags-integration.test.ts +1 -1
- package/src/__tests__/skill-feature-flags.test.ts +2 -2
- package/src/__tests__/skills.test.ts +9 -4
- package/src/__tests__/source-fingerprint.test.ts +184 -0
- package/src/__tests__/subagent-tool-gate-mode.test.ts +70 -3
- package/src/__tests__/subagent-tools.test.ts +3 -2
- package/src/__tests__/telephony-tts-guard.test.ts +38 -3
- package/src/__tests__/test-support/computer-use-skill-harness.ts +3 -2
- package/src/__tests__/ui-channel-variants.test.ts +1 -56
- package/src/__tests__/unicode.test.ts +13 -0
- package/src/__tests__/vellum-self-knowledge-inline-command.test.ts +4 -0
- package/src/__tests__/watch-retro-tool-availability.test.ts +8 -17
- package/src/__tests__/workspace-git-service.test.ts +26 -0
- package/src/__tests__/workspace-migration-154-repair-retired-codex-gpt-5-4-model-ids.test.ts +336 -0
- package/src/acp/__tests__/acp-claude-oauth.test.ts +257 -6
- package/src/acp/__tests__/acp-credentials.test.ts +13 -0
- package/src/acp/__tests__/agent-process.test.ts +258 -4
- package/src/acp/__tests__/auth-required.test.ts +96 -0
- package/src/acp/__tests__/claude-token-refresh.test.ts +257 -0
- package/src/acp/__tests__/client-handler.test.ts +90 -2
- package/src/acp/__tests__/helpers/acp-model-option.ts +51 -0
- package/src/acp/__tests__/prepare-agent-env.test.ts +60 -1
- package/src/acp/__tests__/session-manager-persistence.test.ts +5 -1
- package/src/acp/__tests__/session-manager-resume.test.ts +270 -6
- package/src/acp/__tests__/session-manager-usage.test.ts +4 -2
- package/src/acp/__tests__/session-manager.test.ts +895 -4
- package/src/acp/acp-claude-oauth.ts +328 -14
- package/src/acp/acp-credentials.ts +19 -0
- package/src/acp/agent-process.test.ts +4 -1
- package/src/acp/agent-process.ts +96 -10
- package/src/acp/auth-required.ts +50 -1
- package/src/acp/auto-install.test.ts +9 -7
- package/src/acp/claude-token-refresh.ts +150 -0
- package/src/acp/client-handler.ts +16 -3
- package/src/acp/model-config.test.ts +166 -0
- package/src/acp/model-config.ts +138 -0
- package/src/acp/prepare-agent-env.ts +21 -6
- package/src/acp/resolve-agent.test.ts +220 -6
- package/src/acp/resolve-agent.ts +88 -23
- package/src/acp/session-manager.test.ts +196 -3
- package/src/acp/session-manager.ts +441 -18
- package/src/acp/types.ts +50 -5
- package/src/agent/loop.ts +1 -0
- package/src/api/events/acp-session-model-update.test.ts +88 -0
- package/src/api/events/acp-session-model-update.ts +46 -0
- package/src/api/events/app-files-changed.ts +4 -3
- package/src/api/events/notification-intent.ts +2 -0
- package/src/api/events/user-message-echo.ts +7 -1
- package/src/api/index.ts +6 -0
- package/src/api/responses/conversation-message.ts +5 -0
- package/src/apps/app-store.ts +1 -1
- package/src/apps/resolve-app.ts +81 -0
- package/src/apps/source-fingerprint.ts +266 -0
- package/src/avatar/identity-avatar.ts +7 -2
- package/src/bundler/app-compiler.ts +15 -0
- package/src/calls/__tests__/barge-in-guard.test.ts +81 -0
- package/src/{__tests__ → calls/__tests__}/call-controller.test.ts +503 -82
- package/src/{__tests__ → calls/__tests__}/media-stream-audio-transcode.test.ts +1 -1
- package/src/{__tests__ → calls/__tests__}/media-stream-output.test.ts +37 -8
- package/src/{__tests__ → calls/__tests__}/media-stream-parser.test.ts +1 -1
- package/src/{__tests__ → calls/__tests__}/media-stream-server-integration.test.ts +150 -57
- package/src/{__tests__ → calls/__tests__}/media-stream-stt-session.test.ts +5 -5
- package/src/{__tests__ → calls/__tests__}/media-turn-detector.test.ts +1 -1
- package/src/{live-voice → calls}/__tests__/progress-narration.test.ts +4 -4
- package/src/{live-voice → calls}/__tests__/progress-phrases.test.ts +1 -1
- package/src/calls/__tests__/voice-control-protocol.test.ts +120 -25
- package/src/calls/__tests__/voice-leg-coordinator.test.ts +229 -0
- package/src/calls/__tests__/voice-progress-cadence.test.ts +274 -0
- package/src/{__tests__/voice-session-bridge.test.ts → calls/__tests__/voice-session-bridge-turn-flow.test.ts} +20 -12
- package/src/calls/__tests__/voice-session-bridge.test.ts +56 -1
- package/src/calls/__tests__/voice-triage-escalate.test.ts +105 -0
- package/src/calls/barge-in-guard.ts +118 -0
- package/src/calls/call-constants.ts +24 -4
- package/src/calls/call-controller.ts +499 -199
- package/src/calls/call-transport.ts +16 -0
- package/src/calls/media-stream-output.ts +32 -0
- package/src/calls/media-stream-server.ts +82 -30
- package/src/calls/media-stream-stt-session.ts +15 -0
- package/src/{live-voice → calls}/progress-narration.ts +2 -2
- package/src/calls/resolve-call-tts-provider.ts +33 -2
- package/src/calls/tts-call-strategy.ts +9 -5
- package/src/calls/types.ts +2 -0
- package/src/calls/voice-control-protocol.ts +155 -21
- package/src/calls/voice-leg-coordinator.ts +189 -0
- package/src/calls/voice-progress-cadence.ts +423 -0
- package/src/calls/voice-session-bridge.ts +92 -72
- package/src/calls/voice-triage-escalate.ts +178 -59
- package/src/cli/commands/__tests__/apps.test.ts +245 -0
- package/src/cli/commands/__tests__/bash.test.ts +53 -0
- package/src/cli/commands/__tests__/roadmap.help.test.ts +19 -0
- package/src/cli/commands/apps.help.ts +67 -13
- package/src/cli/commands/apps.ts +183 -0
- package/src/cli/commands/bash.help.ts +8 -13
- package/src/cli/commands/bash.ts +7 -25
- package/src/cli/commands/channels/__tests__/send.test.ts +218 -0
- package/src/cli/commands/channels/index.help.ts +70 -2
- package/src/cli/commands/channels/index.ts +16 -3
- package/src/cli/commands/channels/send.ts +128 -0
- package/src/cli/commands/credentials.help.ts +6 -2
- package/src/cli/commands/credentials.ts +2 -2
- package/src/cli/commands/mcp.help.ts +8 -8
- package/src/cli/commands/mcp.ts +1 -1
- package/src/cli/commands/oauth/status.ts +5 -0
- package/src/cli/commands/roadmap.help.ts +5 -1
- package/src/cli/commands/roadmap.ts +1 -1
- package/src/cli/lib/bundled-marketplace.json +103 -90
- package/src/config/__tests__/default-profile-catalog.test.ts +22 -0
- package/src/config/__tests__/memory-retrospective-schema.test.ts +15 -1
- package/src/config/__tests__/platform-identity.test.ts +255 -0
- package/src/config/__tests__/platform-rehydration.test.ts +99 -9
- package/src/config/acp-agent-write.ts +43 -0
- package/src/config/acp-defaults.test.ts +13 -3
- package/src/config/acp-defaults.ts +23 -6
- package/src/config/acp-schema.test.ts +81 -0
- package/src/config/acp-schema.ts +30 -2
- package/src/config/bundled-skills/acp/SKILL.md +22 -14
- package/src/config/bundled-skills/acp/TOOLS.json +5 -1
- package/src/config/bundled-skills/app-builder/SKILL.md +12 -9
- package/src/config/bundled-skills/app-builder/references/CUSTOM_ROUTES.md +1 -1
- package/src/config/bundled-skills/computer-use/SKILL.md +29 -2
- package/src/config/bundled-skills/computer-use/TOOLS.json +99 -0
- package/src/config/bundled-skills/computer-use/tools/computer-use-sequence.ts +12 -0
- package/src/config/bundled-skills/media-processing/services/preprocess.ts +2 -1
- package/src/config/bundled-skills/media-processing/services/processing-pipeline.ts +2 -1
- package/src/config/bundled-skills/media-processing/tools/generate-clip.ts +2 -1
- package/src/config/bundled-skills/messaging/SKILL.md +3 -3
- package/src/config/bundled-skills/messaging/TOOLS.json +3 -3
- package/src/config/bundled-skills/messaging/tools/messaging-send.ts +67 -139
- package/src/config/bundled-skills/phone-calls/references/TRANSCRIPTS.md +1 -1
- package/src/config/bundled-skills/playbooks/tools/playbook-create.ts +2 -1
- package/src/config/bundled-skills/playbooks/tools/playbook-update.ts +2 -1
- package/src/config/bundled-skills/schedule/SKILL.md +3 -4
- package/src/config/bundled-skills/screen-annotation/SKILL.md +8 -1
- package/src/config/bundled-skills/screen-annotation/tools/screen-annotation.test.ts +4 -1
- package/src/config/bundled-skills/skill-management/TOOLS.json +6 -2
- package/src/config/bundled-skills/transcribe/tools/transcribe-media.ts +5 -2
- package/src/config/default-profile-catalog.ts +1 -1
- package/src/config/env.ts +2 -2
- package/src/config/feature-flag-registry.json +33 -13
- package/src/config/loader.ts +2 -0
- package/src/config/memory-v3-gate.test.ts +31 -0
- package/src/config/memory-v3-gate.ts +20 -16
- package/src/config/platform-identity.ts +201 -0
- package/src/config/platform-rehydration.ts +11 -27
- package/src/config/schema.ts +2 -2
- package/src/config/schemas/__tests__/live-voice.test.ts +8 -158
- package/src/config/schemas/__tests__/voice.test.ts +148 -0
- package/src/config/schemas/calls.ts +1 -28
- package/src/config/schemas/live-voice.ts +1 -173
- package/src/config/schemas/mcp.ts +1 -1
- package/src/config/schemas/memory-retrospective.ts +10 -0
- package/src/config/schemas/services.ts +18 -0
- package/src/config/schemas/skills.ts +0 -14
- package/src/config/schemas/voice.ts +150 -0
- package/src/credential-execution/process-manager.test.ts +18 -19
- package/src/credential-health/credential-health-service.ts +11 -17
- package/src/daemon/__tests__/conversation-tool-setup.test.ts +66 -121
- package/src/daemon/__tests__/plugin-mcp-reconcile.test.ts +4 -1
- package/src/daemon/__tests__/skill-memory-refresh-mtime.test.ts +133 -0
- package/src/daemon/app-change-notify.ts +45 -0
- package/src/daemon/config-watcher.ts +13 -194
- package/src/daemon/conversation-error.ts +3 -2
- package/src/daemon/conversation-media-retry.ts +2 -1
- package/src/daemon/conversation-process.ts +35 -64
- package/src/daemon/conversation-runtime-assembly.ts +20 -7
- package/src/daemon/conversation-skill-tools.ts +13 -31
- package/src/daemon/conversation-store.ts +1 -1
- package/src/daemon/conversation-surfaces.ts +21 -10
- package/src/daemon/conversation-tool-setup.ts +45 -59
- package/src/daemon/conversation.ts +0 -3
- package/src/daemon/dictation-profile-store.ts +2 -1
- package/src/daemon/handlers/shared.ts +2 -1
- package/src/daemon/handlers/skills.ts +6 -3
- package/src/daemon/host-bash-proxy.ts +8 -12
- package/src/daemon/host-browser-proxy.ts +15 -1
- package/src/daemon/host-cu-proxy.ts +224 -19
- package/src/daemon/host-file-proxy.ts +8 -10
- package/src/daemon/host-proxy-preactivation.ts +2 -1
- package/src/daemon/host-transfer-proxy.ts +14 -18
- package/src/daemon/lifecycle.ts +0 -5
- package/src/daemon/mcp-reload-service.ts +5 -5
- package/src/daemon/message-types/sync.ts +1 -0
- package/src/daemon/orphan-reaper.ts +1 -1
- package/src/daemon/providers-setup.ts +1 -1
- package/src/daemon/reaction-history-render.ts +2 -1
- package/src/daemon/shutdown-handlers.ts +1 -9
- package/src/daemon/skill-memory-refresh.ts +64 -0
- package/src/daemon/tool-side-effects.ts +7 -18
- package/src/desktop/__tests__/fake-desktop.ts +122 -0
- package/src/desktop/desktop-chrome-policy.test.ts +79 -0
- package/src/desktop/desktop-chrome-policy.ts +47 -0
- package/src/desktop/desktop-chrome-session.ts +37 -0
- package/src/desktop/desktop-dependencies.test.ts +102 -0
- package/src/desktop/desktop-dependencies.ts +308 -0
- package/src/desktop/desktop-feature.test.ts +18 -0
- package/src/desktop/desktop-feature.ts +19 -0
- package/src/desktop/desktop-panel-config.test.ts +135 -0
- package/src/desktop/desktop-panel-config.ts +149 -0
- package/src/desktop/desktop-session-manager.test.ts +730 -0
- package/src/desktop/desktop-session-manager.ts +850 -0
- package/src/desktop/desktop-stream-bridge.test.ts +395 -0
- package/src/desktop/desktop-stream-bridge.ts +214 -0
- package/src/desktop/desktop-wallpaper.test.ts +191 -0
- package/src/desktop/desktop-wallpaper.ts +113 -0
- package/src/desktop/desktop-window-drag.ts +177 -0
- package/src/desktop/desktop-window-manager-config.test.ts +230 -0
- package/src/desktop/desktop-window-manager-config.ts +238 -0
- package/src/desktop/desktop-window-theme.ts +170 -0
- package/src/heartbeat/heartbeat-service.ts +21 -3
- package/src/home/__tests__/feed-writer.test.ts +22 -0
- package/src/home/feed-writer.ts +11 -2
- package/src/hooks/types.ts +33 -0
- package/src/i18n/AGENTS.md +22 -0
- package/src/i18n/__tests__/i18n.test.ts +108 -0
- package/src/i18n/index.ts +16 -0
- package/src/i18n/locales.ts +93 -0
- package/src/i18n/messages.ts +61 -0
- package/src/i18n/title.ts +25 -0
- package/src/inbound/platform-callback-registration.ts +4 -5
- package/src/live-voice/__tests__/live-voice-agent-turn.test.ts +121 -0
- package/src/live-voice/__tests__/live-voice-events.test.ts +8 -7
- package/src/live-voice/__tests__/live-voice-metrics.test.ts +0 -3
- package/src/live-voice/__tests__/live-voice-progress.test.ts +94 -15
- package/src/live-voice/__tests__/live-voice-sight-frame-echo.test.ts +238 -0
- package/src/live-voice/__tests__/live-voice-vad.test.ts +2 -2
- package/src/live-voice/__tests__/protocol.test.ts +39 -0
- package/src/live-voice/__tests__/runtime-websocket-shell.test.ts +13 -69
- package/src/live-voice/__tests__/session-controls.test.ts +79 -0
- package/src/live-voice/live-voice-photo.ts +25 -6
- package/src/live-voice/live-voice-session.ts +297 -699
- package/src/live-voice/protocol.ts +60 -2
- package/src/live-voice/session-controls.ts +111 -0
- package/src/mcp/__tests__/effective-config.test.ts +2 -2
- package/src/mcp/__tests__/workspace-mcp-config.test.ts +135 -0
- package/src/mcp/effective-config.ts +3 -3
- package/src/mcp/mcp-header-store.ts +29 -45
- package/src/mcp/spec-schema.ts +111 -0
- package/src/mcp/startup.ts +8 -4
- package/src/mcp/workspace-mcp-config.ts +188 -0
- package/src/messaging/provider.ts +10 -3
- package/src/messaging/providers/__tests__/proactive-address.test.ts +95 -0
- package/src/messaging/providers/callback-routing.ts +18 -0
- package/src/messaging/providers/channel-transport.ts +56 -0
- package/src/messaging/providers/discord/transport.ts +17 -0
- package/src/messaging/providers/slack/__tests__/adapter-token-routing.test.ts +6 -17
- package/src/messaging/providers/slack/adapter.ts +7 -44
- package/src/messaging/providers/slack/transport.ts +16 -0
- package/src/messaging/providers/telegram-bot/adapter.ts +1 -48
- package/src/messaging/providers/telegram-bot/client.ts +0 -26
- package/src/messaging/providers/telegram-bot/transport.ts +20 -0
- package/src/messaging/providers/whatsapp/adapter.ts +1 -48
- package/src/messaging/providers/whatsapp/transport.ts +18 -0
- package/src/monitoring/__tests__/workspace-git-heartbeat.test.ts +8 -0
- package/src/notifications/__tests__/assistant-reply-producer.test.ts +55 -0
- package/src/notifications/__tests__/guardian-feed-projection.test.ts +158 -2
- package/src/notifications/__tests__/home-feed-side-effect.test.ts +153 -3
- package/src/notifications/__tests__/schedule-result-producer.test.ts +99 -3
- package/src/notifications/adapters/macos.ts +3 -0
- package/src/notifications/assistant-reply-producer.ts +8 -3
- package/src/notifications/conversation-pairing.ts +36 -16
- package/src/notifications/delivered-post-record.ts +11 -1
- package/src/notifications/guardian-feed-projection.ts +125 -5
- package/src/notifications/home-feed-side-effect.ts +55 -7
- package/src/notifications/schedule-result-producer.ts +66 -22
- package/src/oauth/AGENTS.md +2 -0
- package/src/oauth/__tests__/seed-providers-managed.test.ts +149 -0
- package/src/oauth/byo-connection.test.ts +105 -0
- package/src/oauth/byo-connection.ts +36 -6
- package/src/oauth/connection-resolver.test.ts +100 -0
- package/src/oauth/connection-resolver.ts +120 -3
- package/src/oauth/provider-serializer.ts +9 -0
- package/src/oauth/scope-utils.ts +24 -0
- package/src/oauth/seed-providers.ts +314 -27
- package/src/outbound-proxy/certs.ts +3 -5
- package/src/permissions/checker.test.ts +11 -6
- package/src/persistence/compaction-log-store-clickhouse.ts +3 -3
- package/src/persistence/conversation-crud.ts +71 -63
- package/src/persistence/conversation-lineage.ts +12 -4
- package/src/persistence/conversation-queries.ts +2 -2
- package/src/persistence/conversation-title-placeholders.ts +23 -0
- package/src/persistence/conversation-title-service.ts +9 -26
- package/src/persistence/embeddings/qdrant-manager.ts +163 -18
- package/src/persistence/llm-request-log-sink-clickhouse.ts +3 -3
- package/src/persistence/llm-request-log-source-clickhouse.ts +3 -3
- package/src/persistence/message-cursor.ts +78 -0
- package/src/persistence/message-reads.ts +30 -0
- package/src/persistence/migrations/157-invite-contact-id.ts +18 -6
- package/src/persistence/migrations/__tests__/157-invite-contact-id.test.ts +149 -0
- package/src/persistence/schema/memory-core.ts +5 -0
- package/src/platform/client.test.ts +4 -2
- package/src/platform/client.ts +2 -10
- package/src/plugin-api/constants.ts +2 -0
- package/src/plugin-api/index.ts +1 -0
- package/src/plugin-api/types.ts +2 -0
- package/src/plugins/defaults/index.ts +2 -0
- package/src/plugins/defaults/memory/__tests__/memory-retrospective-accounting.test.ts +46 -0
- package/src/plugins/defaults/memory/__tests__/memory-retrospective-cursor-backfill.test.ts +118 -0
- package/src/plugins/defaults/memory/__tests__/memory-retrospective-cursor-preserve.test.ts +83 -0
- package/src/plugins/defaults/memory/__tests__/memory-retrospective-enqueue.test.ts +9 -5
- package/src/plugins/defaults/memory/__tests__/memory-retrospective-job.test.ts +20 -10
- package/src/plugins/defaults/memory/__tests__/memory-retrospective-prompt.test.ts +5 -0
- package/src/plugins/defaults/memory/__tests__/memory-retrospective-state.test.ts +219 -0
- package/src/plugins/defaults/memory/__tests__/memory-retrospective-sweep.test.ts +31 -0
- package/src/plugins/defaults/memory/__tests__/memory-retrospective-trigger-check.test.ts +63 -0
- package/src/plugins/defaults/memory/__tests__/shutdown-hook.test.ts +4 -0
- package/src/plugins/defaults/memory/context-search/agent-runner.ts +3 -2
- package/src/plugins/defaults/memory/context-search/format.ts +3 -2
- package/src/plugins/defaults/memory/context-search/sources/memory-v2.ts +6 -3
- package/src/plugins/defaults/memory/context-search/sources/workspace.ts +3 -2
- package/src/plugins/defaults/memory/graph/capability-seed.ts +6 -7
- package/src/plugins/defaults/memory/hooks/init.ts +10 -0
- package/src/plugins/defaults/memory/hooks/message-deleted.ts +21 -0
- package/src/plugins/defaults/memory/hooks/shutdown.ts +2 -0
- package/src/plugins/defaults/memory/host-utils.ts +10 -0
- package/src/plugins/defaults/memory/jobs-worker.ts +13 -0
- package/src/plugins/defaults/memory/memory-retrospective-accounting.ts +34 -60
- package/src/plugins/defaults/memory/memory-retrospective-cursor-backfill.ts +126 -0
- package/src/plugins/defaults/memory/memory-retrospective-cursor-preserve.ts +79 -0
- package/src/plugins/defaults/memory/memory-retrospective-cursor.ts +28 -0
- package/src/plugins/defaults/memory/memory-retrospective-enqueue.ts +3 -5
- package/src/plugins/defaults/memory/memory-retrospective-job.ts +12 -3
- package/src/plugins/defaults/memory/memory-retrospective-prompt.ts +1 -1
- package/src/plugins/defaults/memory/memory-retrospective-state.ts +312 -71
- package/src/plugins/defaults/memory/memory-retrospective-sweep.ts +2 -1
- package/src/plugins/defaults/memory/memory-retrospective-trigger-check.ts +5 -3
- package/src/plugins/defaults/memory/skill-md-mtime-poll.ts +9 -0
- package/src/plugins/defaults/memory/startup.ts +28 -2
- package/src/plugins/defaults/memory/substrate/__tests__/skill-content.test.ts +7 -9
- package/src/plugins/defaults/memory/substrate/page-index.ts +6 -1
- package/src/plugins/defaults/memory/substrate/skill-content.ts +2 -2
- package/src/plugins/defaults/memory/v1/graph/consolidation.ts +4 -2
- package/src/plugins/defaults/memory/v1/graph/extraction.ts +4 -2
- package/src/plugins/defaults/memory/v1/graph/retriever.ts +4 -1
- package/src/plugins/defaults/memory/v2/reranker.ts +6 -1
- package/src/plugins/defaults/memory/v3/__tests__/card.test.ts +24 -0
- package/src/plugins/defaults/memory/v3/__tests__/pool-select.test.ts +125 -0
- package/src/plugins/defaults/memory/v3/__tests__/sections.test.ts +26 -0
- package/src/plugins/defaults/memory/v3/__tests__/shadow-plugin.test.ts +30 -0
- package/src/plugins/defaults/memory/v3/card.ts +3 -2
- package/src/plugins/defaults/memory/v3/pool-select.ts +5 -3
- package/src/plugins/defaults/memory/v3/sections.ts +9 -3
- package/src/plugins/defaults/memory/v3/shadow-plugin.ts +5 -2
- package/src/plugins/defaults/memory/worker.ts +6 -0
- package/src/plugins/mcp-servers.ts +15 -75
- package/src/providers/__tests__/connection-model-compat.test.ts +3 -3
- package/src/providers/__tests__/retry-callsite.test.ts +41 -0
- package/src/providers/__tests__/retry-outbound-sanitize.test.ts +176 -0
- package/src/providers/anthropic/client.ts +0 -47
- package/src/providers/gemini/client.ts +9 -23
- package/src/providers/gemini-thought-signature.test.ts +63 -0
- package/src/providers/gemini-thought-signature.ts +44 -0
- package/src/providers/inference/__tests__/endpoint-probe.test.ts +42 -3
- package/src/providers/inference/auth.ts +2 -3
- package/src/providers/inference/connection-availability.ts +27 -8
- package/src/providers/inference/endpoint-probe.ts +10 -1
- package/src/providers/inference/resolve-auth.ts +22 -4
- package/src/providers/inference/service-account-token.ts +248 -0
- package/src/providers/model-catalog.ts +34 -0
- package/src/providers/model-intents.ts +10 -5
- package/src/providers/openai/__tests__/chat-completions-output-token-limit.test.ts +141 -0
- package/src/providers/openai/__tests__/chat-completions-provider-reasoning.test.ts +146 -18
- package/src/providers/openai/__tests__/chat-completions-provider-thought-signature.test.ts +613 -0
- package/src/providers/openai/__tests__/google-thought-signature.test.ts +235 -0
- package/src/providers/openai/__tests__/tool-choice-mapping.test.ts +83 -1
- package/src/providers/openai/chat-completions-provider.ts +212 -79
- package/src/providers/openai/codex-models.ts +0 -4
- package/src/providers/openai/google-thought-signature.ts +320 -0
- package/src/providers/opencode/client.test.ts +73 -4
- package/src/providers/opencode/client.ts +60 -3
- package/src/providers/openrouter/client.ts +20 -0
- package/src/providers/outbound-request-sanitize.ts +96 -0
- package/src/providers/retry.ts +30 -19
- package/src/providers/unparseable-tool-args.ts +5 -1
- package/src/runtime/AGENTS.md +3 -1
- package/src/runtime/__tests__/channel-send.test.ts +443 -0
- package/src/runtime/__tests__/desktop-stream-upgrade.test.ts +89 -0
- package/src/runtime/__tests__/host-observe.test.ts +40 -1
- package/src/runtime/__tests__/live-voice-upgrade.test.ts +58 -0
- package/src/runtime/__tests__/runtime-ws-test-utils.ts +72 -0
- package/src/runtime/__tests__/watch-stream-upgrade.test.ts +59 -0
- package/src/runtime/agent-wake.ts +2 -1
- package/src/runtime/assistant-event-hub.ts +21 -3
- package/src/runtime/auth/same-actor.ts +38 -3
- package/src/runtime/channel-send.ts +316 -0
- package/src/runtime/host-observe.ts +11 -1
- package/src/runtime/http-server.ts +160 -151
- package/src/runtime/routes/__tests__/acp-claude-auth-routes.test.ts +16 -5
- package/src/runtime/routes/__tests__/acp-routes.test.ts +159 -4
- package/src/runtime/routes/__tests__/apps-refresh-route.test.ts +275 -0
- package/src/runtime/routes/__tests__/channel-send-routes.test.ts +127 -0
- package/src/runtime/routes/__tests__/conversation-query-routes.test.ts +108 -1
- package/src/runtime/routes/__tests__/default-provider-routes.test.ts +2 -2
- package/src/runtime/routes/__tests__/dictation-cleanup-guard.test.ts +107 -0
- package/src/runtime/routes/__tests__/mcp-add-default-risk.test.ts +16 -12
- package/src/runtime/routes/acp-claude-auth-routes.ts +11 -3
- package/src/runtime/routes/acp-routes.test.ts +15 -0
- package/src/runtime/routes/acp-routes.ts +72 -9
- package/src/runtime/routes/app-management-routes.ts +90 -2
- package/src/runtime/routes/app-routes.ts +1 -1
- package/src/runtime/routes/channel-send-routes.ts +85 -0
- package/src/runtime/routes/conversation-list-routes.ts +14 -3
- package/src/runtime/routes/conversation-query-routes.ts +40 -0
- package/src/runtime/routes/conversation-routes.ts +16 -3
- package/src/runtime/routes/credential-routes.ts +20 -14
- package/src/runtime/routes/desktop-setup-routes.test.ts +74 -0
- package/src/runtime/routes/desktop-setup-routes.ts +35 -0
- package/src/runtime/routes/diagnostics-routes.ts +61 -4
- package/src/runtime/routes/events-routes.ts +4 -0
- package/src/runtime/routes/host-cu-routes.ts +6 -0
- package/src/runtime/routes/index.ts +4 -2
- package/src/runtime/routes/log-export-routes.ts +2 -0
- package/src/runtime/routes/mcp-auth-routes.ts +39 -47
- package/src/runtime/routes/migration-routes.ts +6 -20
- package/src/runtime/routes/oauth-commands-routes.ts +50 -0
- package/src/runtime/routes/oauth-providers.ts +7 -0
- package/src/runtime/routes/platform-routes.ts +18 -15
- package/src/runtime/routes/workspace-routes.test.ts +55 -26
- package/src/runtime/routes/workspace-routes.ts +46 -63
- package/src/runtime/routes/workspace-tree-walk.test.ts +244 -0
- package/src/runtime/routes/workspace-tree-walk.ts +240 -0
- package/src/runtime/routes/workspace-utils.ts +17 -0
- package/src/runtime/services/__tests__/conversation-serializer.test.ts +28 -0
- package/src/runtime/services/conversation-serializer.ts +16 -3
- package/src/runtime/sync/resource-sync-events.ts +2 -1
- package/src/schedule/run-script.ts +2 -1
- package/src/schedule/schedule-store.ts +9 -2
- package/src/schedule/worker.ts +1 -1
- package/src/security/__tests__/ces-http-record-backend.test.ts +137 -0
- package/src/security/ces-http-record-backend.ts +120 -0
- package/src/security/ces-rpc-record-backend.ts +7 -0
- package/src/security/untrusted-content.ts +3 -1
- package/src/skills/__tests__/workspace-skill-md-signature.test.ts +60 -0
- package/src/skills/workspace-skill-md-signature.ts +50 -0
- package/src/subagent/consult-context.ts +12 -25
- package/src/tools/__tests__/side-effect-abort-guard.test.ts +1 -0
- package/src/tools/acp/list-agents.test.ts +3 -1
- package/src/tools/acp/spawn.test.ts +146 -11
- package/src/tools/acp/spawn.ts +21 -3
- package/src/tools/acp/status.test.ts +94 -0
- package/src/tools/acp/status.ts +40 -3
- package/src/tools/app-control/skill-proxy-bridge.ts +2 -1
- package/src/tools/browser/browser-execution.ts +1 -1
- package/src/tools/browser/cdp-client/accessibility-snapshot.ts +9 -3
- package/src/tools/browser/cdp-client/cdp-inspect/discovery.ts +2 -1
- package/src/tools/browser/cdp-client/extension-cdp-client.ts +3 -2
- package/src/tools/browser/network-recorder.ts +2 -1
- package/src/tools/capability-offer.test.ts +22 -2
- package/src/tools/capability-offer.ts +16 -1
- package/src/tools/computer-use/definitions.ts +121 -2
- package/src/tools/computer-use/skill-proxy-bridge.ts +2 -1
- package/src/tools/credentials/metadata-store.ts +100 -0
- package/src/tools/filesystem/search.ts +2 -1
- package/src/tools/host-filesystem/edit.test.ts +2 -1
- package/src/tools/host-filesystem/edit.ts +2 -2
- package/src/tools/host-filesystem/read.test.ts +2 -1
- package/src/tools/host-filesystem/read.ts +2 -2
- package/src/tools/host-filesystem/transfer.test.ts +2 -1
- package/src/tools/host-filesystem/transfer.ts +2 -2
- package/src/tools/host-filesystem/write.test.ts +2 -1
- package/src/tools/host-filesystem/write.ts +2 -2
- package/src/tools/host-terminal/host-shell.test.ts +16 -0
- package/src/tools/host-terminal/host-shell.ts +4 -20
- package/src/tools/network/web-search.ts +6 -1
- package/src/tools/policy-context.ts +6 -7
- package/src/tools/skills/scaffold-managed.ts +61 -3
- package/src/tools/subagent/spawn.ts +5 -8
- package/src/tools/terminal/__tests__/sanitized-bash.test.ts +57 -0
- package/src/tools/terminal/sanitized-bash.ts +105 -0
- package/src/tools/ui-surface/channel-variants.ts +10 -59
- package/src/tools/watch/watch-retro-report.ts +0 -8
- package/src/types/host-capabilities.ts +5 -3
- package/src/util/__tests__/language-subtag.test.ts +23 -1
- package/src/util/ca-bundle.ts +13 -0
- package/src/util/language-subtag.ts +16 -0
- package/src/util/platform.ts +8 -0
- package/src/util/unicode.ts +15 -1
- package/src/watch/watch-retro.ts +6 -8
- package/src/watch/watch-timeline.ts +2 -2
- package/src/workflows/run-manager.ts +2 -1
- package/src/workspace/git-porcelain.ts +66 -0
- package/src/workspace/git-service.ts +6 -55
- package/src/workspace/migrations/154-repair-retired-codex-gpt-5-4-model-ids.ts +258 -0
- package/src/workspace/migrations/155-move-front-model-config-to-voice.ts +78 -0
- package/src/workspace/migrations/156-extract-workspace-mcp-json.ts +214 -0
- package/src/workspace/migrations/__tests__/155-move-front-model-config-to-voice.test.ts +102 -0
- package/src/workspace/migrations/__tests__/156-extract-workspace-mcp-json.test.ts +199 -0
- package/src/workspace/migrations/registry.ts +6 -0
- package/src/__tests__/app-source-watcher.test.ts +0 -218
- package/src/__tests__/config-watcher-skill-reseed.test.ts +0 -359
- package/src/__tests__/speaker-identification.test.ts +0 -56
- package/src/calls/speaker-identification.ts +0 -233
- package/src/daemon/app-source-watcher.ts +0 -218
- package/src/messaging/providers/whatsapp/client.ts +0 -29
- package/src/runtime/routes/debug-bash-routes.ts +0 -173
- package/src/util/fs-watcher-error.ts +0 -36
- /package/src/{live-voice → calls}/progress-phrases.ts +0 -0
|
@@ -1,30 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Tests for
|
|
3
|
-
*
|
|
4
|
-
*
|
|
5
|
-
* - chrome-extension is its own executor and is exempt from the hasNoClient
|
|
6
|
-
* gate (the extension's own popup UI gates commands; there is no SSE
|
|
7
|
-
* interactive approval channel, and chrome-extension turns intentionally
|
|
8
|
-
* run with `hasNoClient: true` because chrome-extension is not in
|
|
9
|
-
* `INTERACTIVE_INTERFACES`).
|
|
10
|
-
* - macos requires a connected SSE client for host tools that flow through
|
|
11
|
-
* the proxy (e.g. host_bash, host_file_*, host_browser), so
|
|
12
|
-
* `hasNoClient: true` denies those on macos.
|
|
13
|
-
* - host_browser IS in the macos capability set — the proxy routes
|
|
14
|
-
* host_browser_request frames to the desktop client via SSE (or via the
|
|
15
|
-
* Chrome extension registry when an extension connection is present).
|
|
16
|
-
*
|
|
17
|
-
* The per-capability check (`supportsHostProxy(transport, capability)`) runs
|
|
18
|
-
* first and is authoritative for structural support, so host_bash and
|
|
19
|
-
* host_file_* are filtered out for chrome-extension regardless of the
|
|
20
|
-
* hasNoClient flag.
|
|
21
|
-
*
|
|
22
|
-
* Cross-client exception: tools whose capabilities are in
|
|
23
|
-
* CROSS_CLIENT_EXPOSED_CAPABILITIES (host_bash, host_file, host_browser)
|
|
24
|
-
* are allowed for non-host-proxy interactive interfaces ("web", "ios")
|
|
25
|
-
* when at least one capable client is connected via the event hub.
|
|
26
|
-
* chrome-extension is excluded as a security boundary, regardless of
|
|
27
|
-
* whether the capability is technically supported elsewhere.
|
|
2
|
+
* Tests for host-tool schema visibility. Host tool definitions stay stable
|
|
3
|
+
* across interactive and background turns. Chrome extension remains limited
|
|
4
|
+
* to host_browser because it is the only host capability it implements.
|
|
28
5
|
*/
|
|
29
6
|
|
|
30
7
|
import { beforeEach, describe, expect, mock, test } from "bun:test";
|
|
@@ -260,7 +237,7 @@ describe("isToolActiveForContext - Slack task_progress UI exception", () => {
|
|
|
260
237
|
expect(isToolActiveForContext("ui_update", ctx)).toBe(true);
|
|
261
238
|
});
|
|
262
239
|
|
|
263
|
-
test("ui_dismiss
|
|
240
|
+
test("ui_dismiss stays active for Slack without dynamic UI support", () => {
|
|
264
241
|
expect(
|
|
265
242
|
isToolActiveForContext(
|
|
266
243
|
"ui_dismiss",
|
|
@@ -272,42 +249,45 @@ describe("isToolActiveForContext - Slack task_progress UI exception", () => {
|
|
|
272
249
|
},
|
|
273
250
|
}),
|
|
274
251
|
),
|
|
275
|
-
).toBe(
|
|
252
|
+
).toBe(true);
|
|
276
253
|
});
|
|
277
254
|
|
|
278
|
-
test("Slack
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
255
|
+
test("Slack UI tools stay active for a clientless turn", () => {
|
|
256
|
+
for (const name of ["ui_show", "ui_update", "ui_dismiss"]) {
|
|
257
|
+
expect(
|
|
258
|
+
isToolActiveForContext(
|
|
259
|
+
name,
|
|
260
|
+
makeCtx({
|
|
261
|
+
hasNoClient: true,
|
|
262
|
+
channelCapabilities: {
|
|
263
|
+
channel: "slack",
|
|
264
|
+
supportsDynamicUi: false,
|
|
265
|
+
},
|
|
266
|
+
}),
|
|
267
|
+
),
|
|
268
|
+
).toBe(true);
|
|
269
|
+
}
|
|
291
270
|
});
|
|
292
271
|
|
|
293
|
-
test("other non-dynamic channels
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
272
|
+
test("other non-dynamic channels keep UI surface tools on the wire", () => {
|
|
273
|
+
for (const name of ["ui_show", "ui_update", "ui_dismiss"]) {
|
|
274
|
+
expect(
|
|
275
|
+
isToolActiveForContext(
|
|
276
|
+
name,
|
|
277
|
+
makeCtx({
|
|
278
|
+
hasNoClient: false,
|
|
279
|
+
channelCapabilities: {
|
|
280
|
+
channel: "telegram",
|
|
281
|
+
supportsDynamicUi: false,
|
|
282
|
+
},
|
|
283
|
+
}),
|
|
284
|
+
),
|
|
285
|
+
).toBe(true);
|
|
286
|
+
}
|
|
306
287
|
});
|
|
307
288
|
});
|
|
308
289
|
|
|
309
290
|
describe("isToolActiveForContext — host tool capability gating", () => {
|
|
310
|
-
// macOS transport: SSE-based interactive approval required.
|
|
311
291
|
test("host_bash is active for macOS with a connected client", () => {
|
|
312
292
|
expect(
|
|
313
293
|
isToolActiveForContext(
|
|
@@ -317,27 +297,22 @@ describe("isToolActiveForContext — host tool capability gating", () => {
|
|
|
317
297
|
).toBe(true);
|
|
318
298
|
});
|
|
319
299
|
|
|
320
|
-
test("host_bash
|
|
321
|
-
// macOS uses an SSE-based interactive approval channel. Without a
|
|
322
|
-
// connected client the guardian auto-approve path could execute host
|
|
323
|
-
// commands unattended, so host tools must be denied.
|
|
300
|
+
test("host_bash remains active for a background macOS turn", () => {
|
|
324
301
|
expect(
|
|
325
302
|
isToolActiveForContext(
|
|
326
303
|
"host_bash",
|
|
327
304
|
makeCtx({ hasNoClient: true, transportInterface: "macos" }),
|
|
328
305
|
),
|
|
329
|
-
).toBe(
|
|
306
|
+
).toBe(true);
|
|
330
307
|
});
|
|
331
|
-
|
|
332
|
-
test("host_file_read is NOT active for macOS when hasNoClient is true", () => {
|
|
308
|
+
test("host_file_read remains active for a background macOS turn", () => {
|
|
333
309
|
expect(
|
|
334
310
|
isToolActiveForContext(
|
|
335
311
|
"host_file_read",
|
|
336
312
|
makeCtx({ hasNoClient: true, transportInterface: "macos" }),
|
|
337
313
|
),
|
|
338
|
-
).toBe(
|
|
314
|
+
).toBe(true);
|
|
339
315
|
});
|
|
340
|
-
|
|
341
316
|
test("host_browser is active for macOS with a connected client", () => {
|
|
342
317
|
// macOS supports host_browser — the proxy routes host_browser_request
|
|
343
318
|
// frames to the desktop client via SSE (or via the Chrome extension
|
|
@@ -350,19 +325,14 @@ describe("isToolActiveForContext — host tool capability gating", () => {
|
|
|
350
325
|
).toBe(true);
|
|
351
326
|
});
|
|
352
327
|
|
|
353
|
-
test("host_browser
|
|
354
|
-
// macOS supports host_browser structurally, but without a connected
|
|
355
|
-
// client the host_browser_request frames have no consumer, so the tool
|
|
356
|
-
// is denied.
|
|
328
|
+
test("host_browser remains active for a background macOS turn", () => {
|
|
357
329
|
expect(
|
|
358
330
|
isToolActiveForContext(
|
|
359
331
|
"host_browser",
|
|
360
332
|
makeCtx({ hasNoClient: true, transportInterface: "macos" }),
|
|
361
333
|
),
|
|
362
|
-
).toBe(
|
|
334
|
+
).toBe(true);
|
|
363
335
|
});
|
|
364
|
-
|
|
365
|
-
// chrome-extension transport: the extension is its own executor.
|
|
366
336
|
test("host_browser is active for chrome-extension even when hasNoClient is true", () => {
|
|
367
337
|
// chrome-extension turns run with `hasNoClient: true` by design because
|
|
368
338
|
// chrome-extension is not in `INTERACTIVE_INTERFACES` — it is not an
|
|
@@ -418,10 +388,7 @@ describe("isToolActiveForContext — host tool capability gating", () => {
|
|
|
418
388
|
).toBe(false);
|
|
419
389
|
});
|
|
420
390
|
|
|
421
|
-
|
|
422
|
-
test("host_bash falls back to hasNoClient gate when transport is undefined (client connected)", () => {
|
|
423
|
-
// Without a transport interface we cannot run the per-capability check,
|
|
424
|
-
// so we fall back to the coarse-grained `hasNoClient` behavior.
|
|
391
|
+
test("host_bash remains active without transport metadata for a connected turn", () => {
|
|
425
392
|
expect(
|
|
426
393
|
isToolActiveForContext(
|
|
427
394
|
"host_bash",
|
|
@@ -430,20 +397,18 @@ describe("isToolActiveForContext — host tool capability gating", () => {
|
|
|
430
397
|
).toBe(true);
|
|
431
398
|
});
|
|
432
399
|
|
|
433
|
-
test("host_bash
|
|
400
|
+
test("host_bash remains active without transport metadata for a background turn", () => {
|
|
434
401
|
expect(
|
|
435
402
|
isToolActiveForContext(
|
|
436
403
|
"host_bash",
|
|
437
404
|
makeCtx({ hasNoClient: true, transportInterface: undefined }),
|
|
438
405
|
),
|
|
439
|
-
).toBe(
|
|
406
|
+
).toBe(true);
|
|
440
407
|
});
|
|
441
408
|
});
|
|
442
409
|
|
|
443
410
|
describe("isToolActiveForContext — cross-client exception (Phase 1: host_bash)", () => {
|
|
444
411
|
test("host_bash is active for web transport when a host_bash-capable client is connected", () => {
|
|
445
|
-
// Cross-client path: a web turn should see host_bash when a macOS client
|
|
446
|
-
// with host_bash capability is connected via the event hub.
|
|
447
412
|
mockClientCountByCapability.set("host_bash", 1);
|
|
448
413
|
expect(
|
|
449
414
|
isToolActiveForContext(
|
|
@@ -453,30 +418,24 @@ describe("isToolActiveForContext — cross-client exception (Phase 1: host_bash)
|
|
|
453
418
|
).toBe(true);
|
|
454
419
|
});
|
|
455
420
|
|
|
456
|
-
test("host_bash
|
|
457
|
-
// No cross-client fallback: hub has no host_bash-capable subscribers.
|
|
421
|
+
test("host_bash remains active for web when no capable client is connected", () => {
|
|
458
422
|
mockClientCountByCapability.set("host_bash", 0);
|
|
459
423
|
expect(
|
|
460
424
|
isToolActiveForContext(
|
|
461
425
|
"host_bash",
|
|
462
426
|
makeCtx({ hasNoClient: false, transportInterface: "web" }),
|
|
463
427
|
),
|
|
464
|
-
).toBe(
|
|
428
|
+
).toBe(true);
|
|
465
429
|
});
|
|
466
|
-
|
|
467
|
-
test("host_file_read is NOT active for web transport when only a host_bash client is connected", () => {
|
|
468
|
-
// The cross-client exception is per-capability: a host_bash-capable
|
|
469
|
-
// client in the hub does not satisfy host_file's exposure check, since
|
|
470
|
-
// listClientsByCapability is queried with the tool's actual capability.
|
|
430
|
+
test("host_file_read remains active for web without host_file clients", () => {
|
|
471
431
|
mockClientCountByCapability.set("host_bash", 1);
|
|
472
432
|
expect(
|
|
473
433
|
isToolActiveForContext(
|
|
474
434
|
"host_file_read",
|
|
475
435
|
makeCtx({ hasNoClient: false, transportInterface: "web" }),
|
|
476
436
|
),
|
|
477
|
-
).toBe(
|
|
437
|
+
).toBe(true);
|
|
478
438
|
});
|
|
479
|
-
|
|
480
439
|
test("host_bash for macos transport is unaffected by the cross-client exception", () => {
|
|
481
440
|
// macos natively supports host_bash via host proxy — the supportsHostProxy
|
|
482
441
|
// check passes, so the cross-client branch is never reached.
|
|
@@ -489,19 +448,15 @@ describe("isToolActiveForContext — cross-client exception (Phase 1: host_bash)
|
|
|
489
448
|
).toBe(true);
|
|
490
449
|
});
|
|
491
450
|
|
|
492
|
-
test("host_bash
|
|
493
|
-
// Even with a capable client in the hub, the macos SSE path takes
|
|
494
|
-
// precedence — it passes the supportsHostProxy check, bypasses the
|
|
495
|
-
// cross-client branch, and reaches the hasNoClient gate.
|
|
451
|
+
test("host_bash remains active for a background macOS turn", () => {
|
|
496
452
|
mockClientCountByCapability.set("host_bash", 1);
|
|
497
453
|
expect(
|
|
498
454
|
isToolActiveForContext(
|
|
499
455
|
"host_bash",
|
|
500
456
|
makeCtx({ hasNoClient: true, transportInterface: "macos" }),
|
|
501
457
|
),
|
|
502
|
-
).toBe(
|
|
458
|
+
).toBe(true);
|
|
503
459
|
});
|
|
504
|
-
|
|
505
460
|
test("host_bash is NOT active for chrome-extension even when a capable client is connected", () => {
|
|
506
461
|
// Security boundary: chrome-extension only gets host_browser. The
|
|
507
462
|
// cross-client exception explicitly excludes chrome-extension transport
|
|
@@ -515,16 +470,14 @@ describe("isToolActiveForContext — cross-client exception (Phase 1: host_bash)
|
|
|
515
470
|
).toBe(false);
|
|
516
471
|
});
|
|
517
472
|
|
|
518
|
-
test("host_bash
|
|
519
|
-
// hasNoClient gate: no interactive approval UI available for this turn.
|
|
520
|
-
// Cross-client exception must not bypass this gate.
|
|
473
|
+
test("host_bash remains active for a background web turn", () => {
|
|
521
474
|
mockClientCountByCapability.set("host_bash", 1);
|
|
522
475
|
expect(
|
|
523
476
|
isToolActiveForContext(
|
|
524
477
|
"host_bash",
|
|
525
478
|
makeCtx({ hasNoClient: true, transportInterface: "web" }),
|
|
526
479
|
),
|
|
527
|
-
).toBe(
|
|
480
|
+
).toBe(true);
|
|
528
481
|
});
|
|
529
482
|
});
|
|
530
483
|
|
|
@@ -547,14 +500,14 @@ describe("isToolActiveForContext — cross-client exposure for host_file_*", ()
|
|
|
547
500
|
).toBe(true);
|
|
548
501
|
});
|
|
549
502
|
|
|
550
|
-
test(`${tool}
|
|
503
|
+
test(`${tool} remains active for web when no host_file client is connected`, () => {
|
|
551
504
|
mockClientCountByCapability.set("host_file", 0);
|
|
552
505
|
expect(
|
|
553
506
|
isToolActiveForContext(
|
|
554
507
|
tool,
|
|
555
508
|
makeCtx({ hasNoClient: false, transportInterface: "web" }),
|
|
556
509
|
),
|
|
557
|
-
).toBe(
|
|
510
|
+
).toBe(true);
|
|
558
511
|
});
|
|
559
512
|
|
|
560
513
|
test(`${tool} is NOT exposed for chrome-extension (security boundary)`, () => {
|
|
@@ -570,20 +523,19 @@ describe("isToolActiveForContext — cross-client exposure for host_file_*", ()
|
|
|
570
523
|
).toBe(false);
|
|
571
524
|
});
|
|
572
525
|
|
|
573
|
-
test(`${tool}
|
|
526
|
+
test(`${tool} remains active for a background web turn`, () => {
|
|
574
527
|
mockClientCountByCapability.set("host_file", 1);
|
|
575
528
|
expect(
|
|
576
529
|
isToolActiveForContext(
|
|
577
530
|
tool,
|
|
578
531
|
makeCtx({ hasNoClient: true, transportInterface: "web" }),
|
|
579
532
|
),
|
|
580
|
-
).toBe(
|
|
533
|
+
).toBe(true);
|
|
581
534
|
});
|
|
582
535
|
}
|
|
583
536
|
|
|
584
|
-
test("
|
|
585
|
-
mockClientCountByCapability.set("
|
|
586
|
-
mockClientCountByCapability.set("host_file", 1);
|
|
537
|
+
test("host_file_transfer does not depend on the live host_file roster", () => {
|
|
538
|
+
mockClientCountByCapability.set("host_file", 0);
|
|
587
539
|
expect(
|
|
588
540
|
isToolActiveForContext(
|
|
589
541
|
"host_file_transfer",
|
|
@@ -622,37 +574,33 @@ describe("isToolActiveForContext — cross-client exposure for host_browser", ()
|
|
|
622
574
|
).toBe(true);
|
|
623
575
|
});
|
|
624
576
|
|
|
625
|
-
test("host_browser
|
|
577
|
+
test("host_browser remains active for web when no host_browser client is connected", () => {
|
|
626
578
|
mockClientCountByCapability.set("host_browser", 0);
|
|
627
579
|
expect(
|
|
628
580
|
isToolActiveForContext(
|
|
629
581
|
"host_browser",
|
|
630
582
|
makeCtx({ hasNoClient: false, transportInterface: "web" }),
|
|
631
583
|
),
|
|
632
|
-
).toBe(
|
|
584
|
+
).toBe(true);
|
|
633
585
|
});
|
|
634
|
-
|
|
635
|
-
test("host_browser is NOT exposed for ios when no host_browser client is connected", () => {
|
|
586
|
+
test("host_browser remains active for ios when no host_browser client is connected", () => {
|
|
636
587
|
mockClientCountByCapability.set("host_browser", 0);
|
|
637
588
|
expect(
|
|
638
589
|
isToolActiveForContext(
|
|
639
590
|
"host_browser",
|
|
640
591
|
makeCtx({ hasNoClient: false, transportInterface: "ios" }),
|
|
641
592
|
),
|
|
642
|
-
).toBe(
|
|
593
|
+
).toBe(true);
|
|
643
594
|
});
|
|
644
|
-
|
|
645
|
-
test("host_browser is NOT exposed when hasNoClient is true (no approval UI)", () => {
|
|
646
|
-
// hasNoClient gate: cross-client exception must not bypass this.
|
|
595
|
+
test("host_browser remains active for a background web turn", () => {
|
|
647
596
|
mockClientCountByCapability.set("host_browser", 1);
|
|
648
597
|
expect(
|
|
649
598
|
isToolActiveForContext(
|
|
650
599
|
"host_browser",
|
|
651
600
|
makeCtx({ hasNoClient: true, transportInterface: "web" }),
|
|
652
601
|
),
|
|
653
|
-
).toBe(
|
|
602
|
+
).toBe(true);
|
|
654
603
|
});
|
|
655
|
-
|
|
656
604
|
test("host_browser for macos transport is unaffected by the cross-client exception", () => {
|
|
657
605
|
// macos natively supports host_browser via host proxy — the
|
|
658
606
|
// supportsHostProxy check passes, so the cross-client branch is never
|
|
@@ -681,10 +629,7 @@ describe("isToolActiveForContext — cross-client exposure for host_browser", ()
|
|
|
681
629
|
).toBe(true);
|
|
682
630
|
});
|
|
683
631
|
|
|
684
|
-
test("
|
|
685
|
-
// Defense against any future regression that hardcodes a different
|
|
686
|
-
// capability in the cross-client check. Only host_browser-capable
|
|
687
|
-
// clients should satisfy host_browser exposure.
|
|
632
|
+
test("host_browser does not depend on the live host_browser roster", () => {
|
|
688
633
|
mockClientCountByCapability.set("host_bash", 1);
|
|
689
634
|
mockClientCountByCapability.set("host_file", 1);
|
|
690
635
|
mockClientCountByCapability.set("host_browser", 0);
|
|
@@ -693,7 +638,7 @@ describe("isToolActiveForContext — cross-client exposure for host_browser", ()
|
|
|
693
638
|
"host_browser",
|
|
694
639
|
makeCtx({ hasNoClient: false, transportInterface: "web" }),
|
|
695
640
|
),
|
|
696
|
-
).toBe(
|
|
641
|
+
).toBe(true);
|
|
697
642
|
});
|
|
698
643
|
});
|
|
699
644
|
|
|
@@ -41,10 +41,13 @@ mock.module("../../mcp/mcp-header-store.js", () => ({
|
|
|
41
41
|
}));
|
|
42
42
|
|
|
43
43
|
mock.module("../../config/loader.js", () => ({
|
|
44
|
-
getConfig: () => ({ mcp: { servers: {} } }),
|
|
45
44
|
invalidateConfigCache: () => {},
|
|
46
45
|
}));
|
|
47
46
|
|
|
47
|
+
mock.module("../../mcp/workspace-mcp-config.js", () => ({
|
|
48
|
+
loadWorkspaceMcpConfig: () => ({ servers: {} }),
|
|
49
|
+
}));
|
|
50
|
+
|
|
48
51
|
mock.module("../../tools/registry.js", () => ({
|
|
49
52
|
registerMcpTools: () => [],
|
|
50
53
|
unregisterAllMcpTools: () => {},
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
import { mkdirSync, mkdtempSync, rmSync, utimesSync, writeFileSync } from "node:fs";
|
|
2
|
+
import { tmpdir } from "node:os";
|
|
3
|
+
import { join } from "node:path";
|
|
4
|
+
import {
|
|
5
|
+
afterEach,
|
|
6
|
+
beforeEach,
|
|
7
|
+
describe,
|
|
8
|
+
expect,
|
|
9
|
+
mock,
|
|
10
|
+
test,
|
|
11
|
+
} from "bun:test";
|
|
12
|
+
|
|
13
|
+
const WORKSPACE_DIR = mkdtempSync(join(tmpdir(), "skill-md-mtime-refresh-"));
|
|
14
|
+
process.env.VELLUM_WORKSPACE_DIR = WORKSPACE_DIR;
|
|
15
|
+
|
|
16
|
+
const seedGraphCalls: number[] = [];
|
|
17
|
+
const seedV2Calls: number[] = [];
|
|
18
|
+
|
|
19
|
+
mock.module("../../config/loader.js", () => ({
|
|
20
|
+
getConfig: () => ({}),
|
|
21
|
+
}));
|
|
22
|
+
|
|
23
|
+
mock.module("../../plugins/defaults/memory/graph/capability-seed.js", () => ({
|
|
24
|
+
seedSkillGraphNodes: () => {
|
|
25
|
+
seedGraphCalls.push(Date.now());
|
|
26
|
+
},
|
|
27
|
+
seedUninstalledCatalogSkillMemories: async () => {},
|
|
28
|
+
}));
|
|
29
|
+
|
|
30
|
+
mock.module(
|
|
31
|
+
"../../plugins/defaults/memory/substrate/boot-maintenance.js",
|
|
32
|
+
() => ({
|
|
33
|
+
maybeSeedCapabilitySkills: () => {
|
|
34
|
+
seedV2Calls.push(Date.now());
|
|
35
|
+
},
|
|
36
|
+
maybeSeedCliCommandCards: () => {},
|
|
37
|
+
}),
|
|
38
|
+
);
|
|
39
|
+
|
|
40
|
+
const {
|
|
41
|
+
_resetSkillMdMtimeStateForTests,
|
|
42
|
+
maybeRefreshSkillCapabilityMemoriesFromMtime,
|
|
43
|
+
refreshSkillCapabilityMemories,
|
|
44
|
+
startWorkspaceSkillMdMtimePoll,
|
|
45
|
+
stopWorkspaceSkillMdMtimePoll,
|
|
46
|
+
} = await import("../skill-memory-refresh.js");
|
|
47
|
+
|
|
48
|
+
const SKILLS_DIR = join(WORKSPACE_DIR, "skills");
|
|
49
|
+
|
|
50
|
+
function writeSkill(id: string): string {
|
|
51
|
+
const dir = join(SKILLS_DIR, id);
|
|
52
|
+
mkdirSync(dir, { recursive: true });
|
|
53
|
+
const skillMd = join(dir, "SKILL.md");
|
|
54
|
+
writeFileSync(
|
|
55
|
+
skillMd,
|
|
56
|
+
`---\nname: ${id}\ndescription: ${id}\n---\nbody\n`,
|
|
57
|
+
);
|
|
58
|
+
return skillMd;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
describe("maybeRefreshSkillCapabilityMemoriesFromMtime", () => {
|
|
62
|
+
beforeEach(() => {
|
|
63
|
+
rmSync(SKILLS_DIR, { recursive: true, force: true });
|
|
64
|
+
mkdirSync(SKILLS_DIR, { recursive: true });
|
|
65
|
+
seedGraphCalls.length = 0;
|
|
66
|
+
seedV2Calls.length = 0;
|
|
67
|
+
_resetSkillMdMtimeStateForTests();
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
afterEach(() => {
|
|
71
|
+
_resetSkillMdMtimeStateForTests();
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
test("first call reseeds, a second call with unchanged SKILL.md does not", () => {
|
|
75
|
+
writeSkill("alpha");
|
|
76
|
+
expect(maybeRefreshSkillCapabilityMemoriesFromMtime()).toBe(true);
|
|
77
|
+
expect(seedGraphCalls).toHaveLength(1);
|
|
78
|
+
expect(seedV2Calls).toHaveLength(1);
|
|
79
|
+
|
|
80
|
+
expect(maybeRefreshSkillCapabilityMemoriesFromMtime()).toBe(false);
|
|
81
|
+
expect(seedGraphCalls).toHaveLength(1);
|
|
82
|
+
});
|
|
83
|
+
|
|
84
|
+
test("explicit refresh remembers the signature so the next poll is a no-op", () => {
|
|
85
|
+
writeSkill("alpha");
|
|
86
|
+
refreshSkillCapabilityMemories();
|
|
87
|
+
expect(seedGraphCalls).toHaveLength(1);
|
|
88
|
+
expect(maybeRefreshSkillCapabilityMemoriesFromMtime()).toBe(false);
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
test("SKILL.md mtime change reseeds", () => {
|
|
92
|
+
const skillMd = writeSkill("alpha");
|
|
93
|
+
expect(maybeRefreshSkillCapabilityMemoriesFromMtime()).toBe(true);
|
|
94
|
+
|
|
95
|
+
const later = new Date(Date.now() + 5_000);
|
|
96
|
+
utimesSync(skillMd, later, later);
|
|
97
|
+
expect(maybeRefreshSkillCapabilityMemoriesFromMtime()).toBe(true);
|
|
98
|
+
expect(seedGraphCalls).toHaveLength(2);
|
|
99
|
+
});
|
|
100
|
+
|
|
101
|
+
test("TOOLS.json change without a SKILL.md mtime change does not reseed", () => {
|
|
102
|
+
writeSkill("alpha");
|
|
103
|
+
expect(maybeRefreshSkillCapabilityMemoriesFromMtime()).toBe(true);
|
|
104
|
+
|
|
105
|
+
writeFileSync(
|
|
106
|
+
join(SKILLS_DIR, "alpha", "TOOLS.json"),
|
|
107
|
+
JSON.stringify({ version: 1, tools: [] }),
|
|
108
|
+
);
|
|
109
|
+
expect(maybeRefreshSkillCapabilityMemoriesFromMtime()).toBe(false);
|
|
110
|
+
expect(seedGraphCalls).toHaveLength(1);
|
|
111
|
+
});
|
|
112
|
+
|
|
113
|
+
test("adding or removing a skill directory reseeds", () => {
|
|
114
|
+
writeSkill("alpha");
|
|
115
|
+
expect(maybeRefreshSkillCapabilityMemoriesFromMtime()).toBe(true);
|
|
116
|
+
|
|
117
|
+
writeSkill("bravo");
|
|
118
|
+
expect(maybeRefreshSkillCapabilityMemoriesFromMtime()).toBe(true);
|
|
119
|
+
|
|
120
|
+
rmSync(join(SKILLS_DIR, "bravo"), { recursive: true, force: true });
|
|
121
|
+
expect(maybeRefreshSkillCapabilityMemoriesFromMtime()).toBe(true);
|
|
122
|
+
expect(seedGraphCalls).toHaveLength(3);
|
|
123
|
+
});
|
|
124
|
+
|
|
125
|
+
test("startWorkspaceSkillMdMtimePoll runs once immediately and is idempotent", () => {
|
|
126
|
+
writeSkill("alpha");
|
|
127
|
+
startWorkspaceSkillMdMtimePoll();
|
|
128
|
+
expect(seedGraphCalls).toHaveLength(1);
|
|
129
|
+
startWorkspaceSkillMdMtimePoll();
|
|
130
|
+
expect(seedGraphCalls).toHaveLength(1);
|
|
131
|
+
stopWorkspaceSkillMdMtimePoll();
|
|
132
|
+
});
|
|
133
|
+
});
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Fan out an app change to open conversation surfaces, connected clients,
|
|
3
|
+
* and the publish pipeline.
|
|
4
|
+
*
|
|
5
|
+
* Compilation is the caller's responsibility. This module only notifies:
|
|
6
|
+
* it must not call `compileApp()` because that begins with `rm -rf dist/`
|
|
7
|
+
* and would race a compile already in flight.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import { broadcastMessage } from "../runtime/assistant-event-hub.js";
|
|
11
|
+
import { publishAppsChanged } from "../runtime/sync/resource-sync-events.js";
|
|
12
|
+
import { updatePublishedAppDeployment } from "../services/published-app-updater.js";
|
|
13
|
+
import type { Conversation } from "./conversation.js";
|
|
14
|
+
import { allConversations } from "./conversation-registry.js";
|
|
15
|
+
import { refreshSurfacesForApp } from "./conversation-surfaces.js";
|
|
16
|
+
|
|
17
|
+
export function broadcastAppFilesChanged(appId: string): void {
|
|
18
|
+
broadcastMessage({ type: "app_files_changed", appId });
|
|
19
|
+
publishAppsChanged();
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Refresh every in-memory conversation that has this app open, then broadcast
|
|
24
|
+
* and re-deploy. Pass `alsoRefresh` when the calling conversation might not
|
|
25
|
+
* yet be in the registry (tool post-execution hooks).
|
|
26
|
+
*/
|
|
27
|
+
export function notifyAppSurfacesChanged(
|
|
28
|
+
appId: string,
|
|
29
|
+
opts?: { fileChange?: boolean; status?: string },
|
|
30
|
+
alsoRefresh?: Conversation,
|
|
31
|
+
): void {
|
|
32
|
+
const seen = new Set<string>();
|
|
33
|
+
if (alsoRefresh) {
|
|
34
|
+
refreshSurfacesForApp(alsoRefresh, appId, opts);
|
|
35
|
+
seen.add(alsoRefresh.conversationId);
|
|
36
|
+
}
|
|
37
|
+
for (const conversation of allConversations()) {
|
|
38
|
+
if (seen.has(conversation.conversationId)) {
|
|
39
|
+
continue;
|
|
40
|
+
}
|
|
41
|
+
refreshSurfacesForApp(conversation, appId, opts);
|
|
42
|
+
}
|
|
43
|
+
broadcastAppFilesChanged(appId);
|
|
44
|
+
void updatePublishedAppDeployment(appId);
|
|
45
|
+
}
|