@vellumai/assistant 0.12.1-dev.202609141913.5e16607 → 0.12.1-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 +0 -4
- package/ARCHITECTURE.md +12 -11
- package/docs/architecture/turn-actor.md +8 -15
- package/docs/guardian-request-flow.md +0 -16
- package/openapi.yaml +49 -291
- package/package.json +1 -1
- package/src/__tests__/always-loaded-tools-guard.test.ts +10 -18
- package/src/__tests__/app-compiler.test.ts +0 -6
- package/src/__tests__/app-control-tool-schemas.test.ts +2 -5
- package/src/__tests__/app-dir-path-guard.test.ts +3 -1
- package/src/__tests__/app-source-watcher.test.ts +218 -0
- package/src/{calls/__tests__ → __tests__}/call-controller.test.ts +82 -503
- package/src/__tests__/computer-use-skill-proxy-bridge.test.ts +2 -5
- package/src/__tests__/computer-use-tools.test.ts +5 -17
- package/src/__tests__/config-schema-cmd.test.ts +2 -2
- package/src/__tests__/config-schema.test.ts +29 -28
- package/src/__tests__/config-watcher-skill-reseed.test.ts +359 -0
- package/src/__tests__/config-watcher.test.ts +8 -23
- 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 +0 -26
- package/src/__tests__/conversation-process-app-control-preactivation.test.ts +10 -4
- package/src/__tests__/conversation-queue.test.ts +207 -48
- package/src/__tests__/conversation-retry-discard.test.ts +1 -54
- package/src/__tests__/conversation-skill-tools.test.ts +0 -27
- package/src/__tests__/conversation-surfaces-app-control.test.ts +3 -8
- package/src/__tests__/conversation-surfaces-task-progress.test.ts +0 -67
- package/src/__tests__/conversation-title-service.test.ts +10 -14
- package/src/__tests__/conversation-tool-setup-app-refresh.test.ts +5 -3
- package/src/__tests__/conversation-tool-setup-attribution.test.ts +0 -51
- package/src/__tests__/credential-record-retire.test.ts +1 -171
- package/src/__tests__/credential-routes.test.ts +3 -212
- package/src/__tests__/credential-security-invariants.test.ts +2 -4
- package/src/__tests__/cu-unified-flow.test.ts +2 -8
- package/src/__tests__/document-sync-tags.test.ts +0 -25
- package/src/__tests__/drain-kick-guard.test.ts +2 -0
- package/src/__tests__/drain-requeue-on-contention.test.ts +6 -0
- package/src/__tests__/evict-conversations-for-reload.test.ts +1 -1
- package/src/__tests__/host-bash-proxy.test.ts +45 -26
- package/src/__tests__/host-browser-proxy.test.ts +17 -6
- package/src/__tests__/host-file-proxy-targeted.test.ts +0 -23
- package/src/__tests__/host-file-proxy.test.ts +23 -11
- package/src/__tests__/host-transfer-proxy-targeted.test.ts +9 -30
- package/src/__tests__/llm-catalog-parity.test.ts +0 -25
- package/src/__tests__/mcp-auth-routes.test.ts +9 -6
- package/src/__tests__/mcp-config-secret-boundary.test.ts +136 -78
- package/src/__tests__/mcp-health-check.test.ts +11 -8
- package/src/__tests__/mcp-list-plugin-servers.test.ts +10 -8
- package/src/{calls/__tests__ → __tests__}/media-stream-audio-transcode.test.ts +1 -1
- package/src/{calls/__tests__ → __tests__}/media-stream-output.test.ts +8 -37
- package/src/{calls/__tests__ → __tests__}/media-stream-parser.test.ts +1 -1
- package/src/{calls/__tests__ → __tests__}/media-stream-server-integration.test.ts +57 -150
- package/src/{calls/__tests__ → __tests__}/media-stream-stt-session.test.ts +5 -5
- package/src/{calls/__tests__ → __tests__}/media-turn-detector.test.ts +1 -1
- package/src/__tests__/messages-after-tiebreaker.test.ts +0 -91
- package/src/__tests__/messages-read-boundary-guard.test.ts +1 -1
- package/src/__tests__/messaging-send-tool.test.ts +548 -355
- package/src/__tests__/model-intents.test.ts +0 -3
- package/src/__tests__/notification-vellum-adapter.test.ts +2 -85
- package/src/__tests__/outlook-messaging-provider.test.ts +6 -6
- package/src/__tests__/platform-callback-registration.test.ts +16 -8
- package/src/__tests__/platform-client-verify-credential.test.ts +0 -2
- package/src/__tests__/plugin-import-boundary-guard.test.ts +0 -13
- package/src/__tests__/script-proxy-certs.test.ts +0 -35
- package/src/__tests__/skill-feature-flags-integration.test.ts +1 -1
- package/src/__tests__/skill-feature-flags.test.ts +2 -2
- package/src/__tests__/speaker-identification.test.ts +56 -0
- package/src/__tests__/subagent-tool-gate-mode.test.ts +3 -19
- package/src/__tests__/subagent-tools.test.ts +2 -3
- package/src/__tests__/telephony-tts-guard.test.ts +3 -38
- package/src/__tests__/vellum-self-knowledge-inline-command.test.ts +0 -4
- package/src/{calls/__tests__/voice-session-bridge-turn-flow.test.ts → __tests__/voice-session-bridge.test.ts} +12 -20
- package/src/__tests__/watch-retro-tool-availability.test.ts +17 -8
- package/src/__tests__/workspace-git-service.test.ts +0 -26
- package/src/acp/__tests__/agent-process.test.ts +4 -258
- package/src/acp/__tests__/auth-required.test.ts +0 -96
- package/src/acp/__tests__/client-handler.test.ts +2 -90
- package/src/acp/__tests__/session-manager-persistence.test.ts +1 -5
- package/src/acp/__tests__/session-manager-resume.test.ts +6 -270
- package/src/acp/__tests__/session-manager-usage.test.ts +2 -4
- package/src/acp/__tests__/session-manager.test.ts +4 -895
- package/src/acp/agent-process.test.ts +1 -4
- package/src/acp/agent-process.ts +9 -94
- package/src/acp/auth-required.ts +1 -50
- package/src/acp/auto-install.test.ts +7 -9
- package/src/acp/client-handler.ts +3 -16
- package/src/acp/resolve-agent.test.ts +6 -220
- package/src/acp/resolve-agent.ts +23 -88
- package/src/acp/session-manager.test.ts +3 -196
- package/src/acp/session-manager.ts +18 -441
- package/src/acp/types.ts +5 -50
- package/src/api/events/app-files-changed.ts +3 -4
- package/src/api/events/notification-intent.ts +0 -2
- package/src/api/index.ts +0 -6
- package/src/apps/app-store.ts +1 -1
- package/src/bundler/app-compiler.ts +0 -15
- package/src/calls/__tests__/voice-control-protocol.test.ts +25 -58
- package/src/calls/__tests__/voice-session-bridge.test.ts +1 -37
- package/src/calls/__tests__/voice-triage-escalate.test.ts +0 -105
- package/src/calls/call-constants.ts +4 -24
- package/src/calls/call-controller.ts +199 -499
- package/src/calls/call-transport.ts +0 -16
- package/src/calls/media-stream-output.ts +0 -32
- package/src/calls/media-stream-server.ts +30 -82
- package/src/calls/media-stream-stt-session.ts +0 -15
- package/src/calls/resolve-call-tts-provider.ts +2 -33
- package/src/calls/speaker-identification.ts +233 -0
- package/src/calls/tts-call-strategy.ts +5 -9
- package/src/calls/types.ts +0 -2
- package/src/calls/voice-control-protocol.ts +21 -53
- package/src/calls/voice-session-bridge.ts +46 -59
- package/src/calls/voice-triage-escalate.ts +56 -175
- package/src/cli/commands/apps.help.ts +13 -67
- package/src/cli/commands/apps.ts +0 -183
- package/src/cli/commands/bash.help.ts +13 -8
- package/src/cli/commands/bash.ts +25 -7
- package/src/cli/commands/channels/index.help.ts +2 -70
- package/src/cli/commands/channels/index.ts +3 -16
- package/src/cli/commands/credentials.help.ts +2 -6
- 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/roadmap.help.ts +1 -5
- package/src/cli/commands/roadmap.ts +1 -1
- package/src/cli/lib/bundled-marketplace.json +90 -103
- package/src/config/__tests__/default-profile-catalog.test.ts +0 -22
- package/src/config/__tests__/memory-retrospective-schema.test.ts +1 -15
- package/src/config/__tests__/platform-rehydration.test.ts +9 -99
- package/src/config/acp-defaults.test.ts +3 -13
- package/src/config/acp-defaults.ts +6 -23
- package/src/config/acp-schema.ts +2 -30
- package/src/config/bundled-skills/acp/SKILL.md +14 -22
- package/src/config/bundled-skills/acp/TOOLS.json +1 -5
- package/src/config/bundled-skills/app-builder/SKILL.md +9 -12
- package/src/config/bundled-skills/app-builder/references/CUSTOM_ROUTES.md +1 -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 +139 -67
- package/src/config/bundled-skills/phone-calls/references/TRANSCRIPTS.md +1 -1
- package/src/config/bundled-skills/schedule/SKILL.md +4 -3
- package/src/config/bundled-skills/screen-annotation/SKILL.md +1 -8
- package/src/config/bundled-skills/screen-annotation/tools/screen-annotation.test.ts +1 -4
- package/src/config/bundled-skills/skill-management/TOOLS.json +2 -2
- package/src/config/default-profile-catalog.ts +1 -1
- package/src/config/env.ts +2 -2
- package/src/config/feature-flag-registry.json +12 -24
- package/src/config/loader.ts +0 -1
- package/src/config/memory-v3-gate.test.ts +0 -31
- package/src/config/memory-v3-gate.ts +16 -20
- package/src/config/platform-rehydration.ts +27 -11
- package/src/config/schema.ts +2 -2
- package/src/config/schemas/__tests__/live-voice.test.ts +158 -8
- package/src/config/schemas/calls.ts +28 -1
- package/src/config/schemas/live-voice.ts +173 -1
- package/src/config/schemas/mcp.ts +1 -1
- package/src/config/schemas/memory-retrospective.ts +0 -10
- package/src/config/schemas/services.ts +0 -8
- package/src/config/schemas/skills.ts +14 -0
- package/src/credential-execution/process-manager.test.ts +19 -18
- package/src/daemon/__tests__/conversation-tool-setup.test.ts +121 -66
- package/src/daemon/__tests__/plugin-mcp-reconcile.test.ts +1 -4
- package/src/daemon/app-source-watcher.ts +218 -0
- package/src/daemon/config-watcher.ts +194 -13
- package/src/daemon/conversation-process.ts +64 -35
- package/src/daemon/conversation-skill-tools.ts +31 -13
- package/src/daemon/conversation-store.ts +1 -1
- package/src/daemon/conversation-surfaces.ts +8 -10
- package/src/daemon/conversation-tool-setup.ts +43 -37
- package/src/daemon/conversation.ts +3 -0
- package/src/daemon/host-bash-proxy.ts +12 -8
- package/src/daemon/host-browser-proxy.ts +1 -15
- package/src/daemon/host-file-proxy.ts +10 -8
- package/src/daemon/host-transfer-proxy.ts +18 -14
- package/src/daemon/lifecycle.ts +5 -0
- package/src/daemon/mcp-reload-service.ts +5 -5
- package/src/daemon/message-types/sync.ts +0 -1
- package/src/daemon/orphan-reaper.ts +1 -1
- package/src/daemon/providers-setup.ts +1 -1
- package/src/daemon/shutdown-handlers.ts +9 -1
- package/src/daemon/skill-memory-refresh.ts +0 -64
- package/src/daemon/tool-side-effects.ts +18 -7
- package/src/home/__tests__/feed-writer.test.ts +0 -22
- package/src/home/feed-writer.ts +2 -11
- package/src/hooks/types.ts +0 -33
- package/src/inbound/platform-callback-registration.ts +5 -4
- package/src/live-voice/__tests__/live-voice-metrics.test.ts +3 -0
- package/src/live-voice/__tests__/live-voice-progress.test.ts +15 -15
- package/src/live-voice/__tests__/live-voice-vad.test.ts +2 -2
- package/src/{calls → live-voice}/__tests__/progress-narration.test.ts +4 -4
- package/src/{calls → live-voice}/__tests__/progress-phrases.test.ts +1 -1
- package/src/live-voice/__tests__/runtime-websocket-shell.test.ts +69 -13
- package/src/live-voice/live-voice-session.ts +693 -213
- package/src/{calls → live-voice}/progress-narration.ts +2 -2
- package/src/live-voice/protocol.ts +2 -0
- package/src/mcp/__tests__/effective-config.test.ts +2 -2
- package/src/mcp/effective-config.ts +3 -3
- package/src/mcp/mcp-header-store.ts +45 -29
- package/src/mcp/startup.ts +4 -8
- package/src/messaging/provider.ts +3 -10
- package/src/messaging/providers/callback-routing.ts +0 -18
- package/src/messaging/providers/channel-transport.ts +0 -56
- package/src/messaging/providers/discord/transport.ts +0 -17
- package/src/messaging/providers/slack/__tests__/adapter-token-routing.test.ts +17 -6
- package/src/messaging/providers/slack/adapter.ts +44 -7
- package/src/messaging/providers/slack/transport.ts +0 -16
- package/src/messaging/providers/telegram-bot/adapter.ts +48 -1
- package/src/messaging/providers/telegram-bot/client.ts +26 -0
- package/src/messaging/providers/telegram-bot/transport.ts +0 -20
- package/src/messaging/providers/whatsapp/adapter.ts +48 -1
- package/src/messaging/providers/whatsapp/client.ts +29 -0
- package/src/messaging/providers/whatsapp/transport.ts +0 -18
- package/src/monitoring/__tests__/workspace-git-heartbeat.test.ts +0 -8
- package/src/notifications/__tests__/assistant-reply-producer.test.ts +0 -55
- package/src/notifications/__tests__/guardian-feed-projection.test.ts +2 -158
- package/src/notifications/__tests__/home-feed-side-effect.test.ts +3 -153
- package/src/notifications/__tests__/schedule-result-producer.test.ts +3 -99
- package/src/notifications/adapters/macos.ts +0 -3
- package/src/notifications/assistant-reply-producer.ts +3 -8
- package/src/notifications/conversation-pairing.ts +16 -36
- package/src/notifications/delivered-post-record.ts +1 -11
- package/src/notifications/guardian-feed-projection.ts +5 -125
- package/src/notifications/home-feed-side-effect.ts +7 -55
- package/src/notifications/schedule-result-producer.ts +22 -66
- package/src/oauth/__tests__/seed-providers-managed.test.ts +0 -54
- package/src/oauth/byo-connection.test.ts +0 -45
- package/src/oauth/byo-connection.ts +6 -36
- package/src/oauth/connection-resolver.test.ts +0 -73
- package/src/oauth/connection-resolver.ts +2 -95
- package/src/oauth/seed-providers.ts +0 -165
- package/src/outbound-proxy/certs.ts +5 -3
- package/src/permissions/checker.test.ts +6 -11
- package/src/persistence/compaction-log-store-clickhouse.ts +3 -3
- package/src/persistence/conversation-crud.ts +63 -71
- package/src/persistence/conversation-lineage.ts +4 -12
- package/src/persistence/conversation-title-service.ts +26 -9
- 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-reads.ts +0 -30
- package/src/persistence/migrations/157-invite-contact-id.ts +6 -18
- package/src/persistence/schema/memory-core.ts +0 -5
- package/src/platform/client.test.ts +2 -4
- package/src/platform/client.ts +10 -2
- package/src/plugin-api/constants.ts +0 -2
- package/src/plugin-api/index.ts +0 -1
- package/src/plugin-api/types.ts +0 -2
- package/src/plugins/defaults/index.ts +0 -2
- package/src/plugins/defaults/memory/__tests__/memory-retrospective-accounting.test.ts +0 -46
- package/src/plugins/defaults/memory/__tests__/memory-retrospective-enqueue.test.ts +5 -9
- package/src/plugins/defaults/memory/__tests__/memory-retrospective-job.test.ts +10 -20
- package/src/plugins/defaults/memory/__tests__/memory-retrospective-state.test.ts +0 -219
- package/src/plugins/defaults/memory/__tests__/memory-retrospective-sweep.test.ts +0 -31
- package/src/plugins/defaults/memory/__tests__/memory-retrospective-trigger-check.test.ts +0 -63
- package/src/plugins/defaults/memory/__tests__/shutdown-hook.test.ts +0 -4
- package/src/plugins/defaults/memory/graph/capability-seed.ts +6 -4
- package/src/plugins/defaults/memory/hooks/init.ts +0 -10
- package/src/plugins/defaults/memory/hooks/shutdown.ts +0 -2
- package/src/plugins/defaults/memory/jobs-worker.ts +0 -13
- package/src/plugins/defaults/memory/memory-retrospective-accounting.ts +60 -34
- package/src/plugins/defaults/memory/memory-retrospective-enqueue.ts +5 -3
- package/src/plugins/defaults/memory/memory-retrospective-job.ts +3 -12
- package/src/plugins/defaults/memory/memory-retrospective-state.ts +71 -312
- package/src/plugins/defaults/memory/memory-retrospective-sweep.ts +1 -2
- package/src/plugins/defaults/memory/memory-retrospective-trigger-check.ts +3 -5
- package/src/plugins/defaults/memory/startup.ts +1 -6
- package/src/plugins/defaults/memory/substrate/__tests__/skill-content.test.ts +9 -7
- package/src/plugins/defaults/memory/substrate/skill-content.ts +2 -2
- package/src/plugins/defaults/memory/v3/__tests__/pool-select.test.ts +0 -89
- package/src/plugins/defaults/memory/worker.ts +0 -6
- package/src/plugins/mcp-servers.ts +75 -15
- package/src/providers/__tests__/connection-model-compat.test.ts +3 -3
- package/src/providers/gemini/client.ts +23 -9
- package/src/providers/inference/auth.ts +3 -2
- package/src/providers/inference/connection-availability.ts +8 -27
- package/src/providers/inference/resolve-auth.ts +4 -22
- package/src/providers/model-catalog.ts +0 -34
- package/src/providers/model-intents.ts +5 -10
- package/src/providers/openai/__tests__/chat-completions-provider-reasoning.test.ts +18 -146
- package/src/providers/openai/__tests__/tool-choice-mapping.test.ts +1 -83
- package/src/providers/openai/chat-completions-provider.ts +78 -192
- package/src/providers/openai/codex-models.ts +4 -0
- package/src/runtime/AGENTS.md +0 -2
- package/src/runtime/auth/same-actor.ts +3 -38
- package/src/runtime/http-server.ts +151 -160
- package/src/runtime/routes/__tests__/acp-routes.test.ts +4 -159
- package/src/runtime/routes/__tests__/conversation-query-routes.test.ts +1 -108
- package/src/runtime/routes/__tests__/default-provider-routes.test.ts +2 -2
- package/src/runtime/routes/__tests__/mcp-add-default-risk.test.ts +12 -16
- package/src/runtime/routes/acp-routes.test.ts +0 -15
- package/src/runtime/routes/acp-routes.ts +9 -72
- package/src/runtime/routes/app-management-routes.ts +0 -73
- package/src/runtime/routes/app-routes.ts +1 -1
- package/src/runtime/routes/conversation-list-routes.ts +3 -14
- package/src/runtime/routes/conversation-query-routes.ts +0 -40
- package/src/runtime/routes/credential-routes.ts +10 -19
- package/src/runtime/routes/debug-bash-routes.ts +173 -0
- package/src/runtime/routes/diagnostics-routes.ts +3 -55
- package/src/runtime/routes/index.ts +2 -4
- package/src/runtime/routes/log-export-routes.ts +0 -2
- package/src/runtime/routes/mcp-auth-routes.ts +47 -39
- package/src/runtime/routes/migration-routes.ts +20 -6
- package/src/runtime/routes/platform-routes.ts +15 -18
- package/src/runtime/services/__tests__/conversation-serializer.test.ts +0 -28
- package/src/runtime/services/conversation-serializer.ts +3 -16
- package/src/runtime/sync/resource-sync-events.ts +1 -2
- package/src/schedule/worker.ts +1 -1
- package/src/security/ces-rpc-record-backend.ts +0 -7
- package/src/subagent/consult-context.ts +25 -12
- package/src/tools/acp/list-agents.test.ts +1 -3
- package/src/tools/acp/spawn.test.ts +11 -146
- package/src/tools/acp/spawn.ts +3 -21
- package/src/tools/acp/status.ts +3 -40
- package/src/tools/app-control/skill-proxy-bridge.ts +1 -2
- package/src/tools/capability-offer.test.ts +2 -22
- package/src/tools/capability-offer.ts +1 -16
- package/src/tools/computer-use/definitions.ts +2 -4
- package/src/tools/computer-use/skill-proxy-bridge.ts +1 -2
- package/src/tools/credentials/metadata-store.ts +0 -100
- package/src/tools/host-filesystem/edit.test.ts +1 -2
- package/src/tools/host-filesystem/edit.ts +2 -2
- package/src/tools/host-filesystem/read.test.ts +1 -2
- package/src/tools/host-filesystem/read.ts +2 -2
- package/src/tools/host-filesystem/transfer.test.ts +1 -2
- package/src/tools/host-filesystem/transfer.ts +2 -2
- package/src/tools/host-filesystem/write.test.ts +1 -2
- package/src/tools/host-filesystem/write.ts +2 -2
- package/src/tools/host-terminal/host-shell.test.ts +0 -16
- package/src/tools/host-terminal/host-shell.ts +20 -4
- package/src/tools/policy-context.ts +7 -6
- package/src/tools/subagent/spawn.ts +8 -5
- package/src/tools/watch/watch-retro-report.ts +8 -0
- package/src/util/__tests__/language-subtag.test.ts +1 -23
- package/src/util/fs-watcher-error.ts +36 -0
- package/src/util/language-subtag.ts +0 -16
- package/src/util/platform.ts +0 -8
- package/src/workspace/git-service.ts +54 -5
- package/src/workspace/migrations/registry.ts +0 -6
- package/scripts/smoke-desktop-window-theme.ts +0 -186
- package/src/__tests__/git-porcelain.test.ts +0 -47
- package/src/__tests__/helpers/set-workspace-mcp.ts +0 -11
- package/src/__tests__/message-deleted-hook-dispatch.test.ts +0 -119
- package/src/__tests__/resolve-app.test.ts +0 -135
- package/src/__tests__/service-account-token.test.ts +0 -247
- package/src/__tests__/source-fingerprint.test.ts +0 -184
- package/src/__tests__/workspace-migration-154-repair-retired-codex-gpt-5-4-model-ids.test.ts +0 -336
- package/src/acp/__tests__/helpers/acp-model-option.ts +0 -51
- package/src/acp/model-config.test.ts +0 -166
- package/src/acp/model-config.ts +0 -138
- package/src/api/events/acp-session-model-update.test.ts +0 -88
- package/src/api/events/acp-session-model-update.ts +0 -46
- package/src/apps/resolve-app.ts +0 -81
- package/src/apps/source-fingerprint.ts +0 -266
- package/src/calls/__tests__/barge-in-guard.test.ts +0 -81
- package/src/calls/__tests__/voice-leg-coordinator.test.ts +0 -229
- package/src/calls/__tests__/voice-progress-cadence.test.ts +0 -274
- package/src/calls/barge-in-guard.ts +0 -118
- package/src/calls/voice-leg-coordinator.ts +0 -189
- package/src/calls/voice-progress-cadence.ts +0 -423
- package/src/cli/commands/__tests__/apps.test.ts +0 -245
- package/src/cli/commands/__tests__/bash.test.ts +0 -53
- package/src/cli/commands/__tests__/roadmap.help.test.ts +0 -19
- package/src/cli/commands/channels/__tests__/send.test.ts +0 -218
- package/src/cli/commands/channels/send.ts +0 -128
- package/src/config/__tests__/platform-identity.test.ts +0 -255
- package/src/config/acp-agent-write.ts +0 -43
- package/src/config/acp-schema.test.ts +0 -81
- package/src/config/platform-identity.ts +0 -201
- package/src/config/schemas/__tests__/voice.test.ts +0 -148
- package/src/config/schemas/voice.ts +0 -150
- package/src/daemon/__tests__/skill-memory-refresh-mtime.test.ts +0 -133
- package/src/daemon/app-change-notify.ts +0 -45
- package/src/desktop/__tests__/fake-desktop.ts +0 -119
- package/src/desktop/desktop-chrome-policy.test.ts +0 -71
- package/src/desktop/desktop-chrome-policy.ts +0 -42
- package/src/desktop/desktop-dependencies.test.ts +0 -102
- package/src/desktop/desktop-dependencies.ts +0 -306
- package/src/desktop/desktop-feature.test.ts +0 -18
- package/src/desktop/desktop-feature.ts +0 -19
- package/src/desktop/desktop-panel-config.test.ts +0 -135
- package/src/desktop/desktop-panel-config.ts +0 -149
- package/src/desktop/desktop-session-manager.test.ts +0 -627
- package/src/desktop/desktop-session-manager.ts +0 -814
- package/src/desktop/desktop-stream-bridge.test.ts +0 -395
- package/src/desktop/desktop-stream-bridge.ts +0 -214
- package/src/desktop/desktop-wallpaper.test.ts +0 -191
- package/src/desktop/desktop-wallpaper.ts +0 -113
- package/src/desktop/desktop-window-theme.ts +0 -170
- package/src/i18n/AGENTS.md +0 -22
- package/src/i18n/__tests__/i18n.test.ts +0 -108
- package/src/i18n/index.ts +0 -16
- package/src/i18n/locales.ts +0 -93
- package/src/i18n/messages.ts +0 -61
- package/src/i18n/title.ts +0 -25
- package/src/mcp/__tests__/workspace-mcp-config.test.ts +0 -135
- package/src/mcp/spec-schema.ts +0 -111
- package/src/mcp/workspace-mcp-config.ts +0 -188
- package/src/messaging/providers/__tests__/proactive-address.test.ts +0 -95
- package/src/persistence/conversation-title-placeholders.ts +0 -23
- package/src/persistence/message-cursor.ts +0 -78
- package/src/persistence/migrations/__tests__/157-invite-contact-id.test.ts +0 -149
- package/src/plugins/defaults/memory/__tests__/memory-retrospective-cursor-backfill.test.ts +0 -118
- package/src/plugins/defaults/memory/__tests__/memory-retrospective-cursor-preserve.test.ts +0 -83
- package/src/plugins/defaults/memory/hooks/message-deleted.ts +0 -21
- package/src/plugins/defaults/memory/memory-retrospective-cursor-backfill.ts +0 -126
- package/src/plugins/defaults/memory/memory-retrospective-cursor-preserve.ts +0 -79
- package/src/plugins/defaults/memory/memory-retrospective-cursor.ts +0 -28
- package/src/plugins/defaults/memory/skill-md-mtime-poll.ts +0 -9
- package/src/providers/gemini-thought-signature.test.ts +0 -63
- package/src/providers/gemini-thought-signature.ts +0 -44
- package/src/providers/inference/service-account-token.ts +0 -248
- package/src/providers/openai/__tests__/chat-completions-provider-thought-signature.test.ts +0 -613
- package/src/providers/openai/__tests__/google-thought-signature.test.ts +0 -235
- package/src/providers/openai/google-thought-signature.ts +0 -320
- package/src/runtime/__tests__/channel-send.test.ts +0 -443
- package/src/runtime/__tests__/desktop-stream-upgrade.test.ts +0 -89
- package/src/runtime/__tests__/live-voice-upgrade.test.ts +0 -58
- package/src/runtime/__tests__/runtime-ws-test-utils.ts +0 -72
- package/src/runtime/__tests__/watch-stream-upgrade.test.ts +0 -59
- package/src/runtime/channel-send.ts +0 -316
- package/src/runtime/routes/__tests__/apps-refresh-route.test.ts +0 -205
- package/src/runtime/routes/__tests__/channel-send-routes.test.ts +0 -127
- package/src/runtime/routes/__tests__/dictation-cleanup-guard.test.ts +0 -107
- package/src/runtime/routes/channel-send-routes.ts +0 -85
- package/src/runtime/routes/desktop-setup-routes.test.ts +0 -74
- package/src/runtime/routes/desktop-setup-routes.ts +0 -35
- package/src/security/__tests__/ces-http-record-backend.test.ts +0 -137
- package/src/security/ces-http-record-backend.ts +0 -120
- package/src/skills/__tests__/workspace-skill-md-signature.test.ts +0 -60
- package/src/skills/workspace-skill-md-signature.ts +0 -50
- package/src/tools/acp/status.test.ts +0 -94
- package/src/tools/terminal/__tests__/sanitized-bash.test.ts +0 -57
- package/src/tools/terminal/sanitized-bash.ts +0 -105
- package/src/util/ca-bundle.ts +0 -13
- package/src/workspace/git-porcelain.ts +0 -66
- package/src/workspace/migrations/154-repair-retired-codex-gpt-5-4-model-ids.ts +0 -258
- package/src/workspace/migrations/155-move-front-model-config-to-voice.ts +0 -78
- package/src/workspace/migrations/156-extract-workspace-mcp-json.ts +0 -214
- package/src/workspace/migrations/__tests__/155-move-front-model-config-to-voice.test.ts +0 -102
- package/src/workspace/migrations/__tests__/156-extract-workspace-mcp-json.test.ts +0 -199
- /package/src/{calls → live-voice}/progress-phrases.ts +0 -0
|
@@ -1,148 +0,0 @@
|
|
|
1
|
-
import { describe, expect, test } from "bun:test";
|
|
2
|
-
|
|
3
|
-
import { VoiceConfigSchema, VoiceFrontModelConfigSchema } from "../voice.js";
|
|
4
|
-
|
|
5
|
-
const PROGRESS_DEFAULTS = {
|
|
6
|
-
enabled: true,
|
|
7
|
-
opsThreshold: 3,
|
|
8
|
-
idleIntervalMs: 5_000,
|
|
9
|
-
maxSilenceMs: 35_000,
|
|
10
|
-
longOpMs: 15_000,
|
|
11
|
-
minGapMs: 6_000,
|
|
12
|
-
generationTimeoutMs: 1_500,
|
|
13
|
-
};
|
|
14
|
-
|
|
15
|
-
const FRONT_MODEL_DEFAULTS = {
|
|
16
|
-
endpointDecisionTimeoutMs: 1200,
|
|
17
|
-
endpointExtensionMs: 1500,
|
|
18
|
-
endpointMaxExtensions: 2,
|
|
19
|
-
progress: PROGRESS_DEFAULTS,
|
|
20
|
-
};
|
|
21
|
-
|
|
22
|
-
describe("VoiceFrontModelConfigSchema", () => {
|
|
23
|
-
test("empty object parses to defaults", () => {
|
|
24
|
-
const parsed = VoiceFrontModelConfigSchema.parse({});
|
|
25
|
-
expect(parsed).toEqual(FRONT_MODEL_DEFAULTS);
|
|
26
|
-
});
|
|
27
|
-
|
|
28
|
-
test("accepts overrides", () => {
|
|
29
|
-
const parsed = VoiceFrontModelConfigSchema.parse({
|
|
30
|
-
endpointDecisionTimeoutMs: 400,
|
|
31
|
-
endpointMaxExtensions: 0,
|
|
32
|
-
});
|
|
33
|
-
expect(parsed.endpointDecisionTimeoutMs).toBe(400);
|
|
34
|
-
expect(parsed.endpointMaxExtensions).toBe(0);
|
|
35
|
-
// Unspecified fields still get defaults
|
|
36
|
-
expect(parsed.endpointExtensionMs).toBe(1500);
|
|
37
|
-
});
|
|
38
|
-
|
|
39
|
-
test("strips retired generated-ack settings", () => {
|
|
40
|
-
const parsed = VoiceFrontModelConfigSchema.parse({
|
|
41
|
-
ackFirstDeltaTimeoutMs: 2500,
|
|
42
|
-
ackGenerationTimeoutMs: 600,
|
|
43
|
-
});
|
|
44
|
-
expect(parsed).not.toHaveProperty("ackFirstDeltaTimeoutMs");
|
|
45
|
-
expect(parsed).not.toHaveProperty("ackGenerationTimeoutMs");
|
|
46
|
-
});
|
|
47
|
-
|
|
48
|
-
test("rejects non-positive endpointDecisionTimeoutMs", () => {
|
|
49
|
-
const result = VoiceFrontModelConfigSchema.safeParse({
|
|
50
|
-
endpointDecisionTimeoutMs: 0,
|
|
51
|
-
});
|
|
52
|
-
expect(result.success).toBe(false);
|
|
53
|
-
});
|
|
54
|
-
|
|
55
|
-
test("rejects negative endpointMaxExtensions", () => {
|
|
56
|
-
const result = VoiceFrontModelConfigSchema.safeParse({
|
|
57
|
-
endpointMaxExtensions: -1,
|
|
58
|
-
});
|
|
59
|
-
expect(result.success).toBe(false);
|
|
60
|
-
});
|
|
61
|
-
|
|
62
|
-
test("absent progress namespace parses to full progress defaults", () => {
|
|
63
|
-
const parsed = VoiceFrontModelConfigSchema.parse({});
|
|
64
|
-
expect(parsed.progress).toEqual(PROGRESS_DEFAULTS);
|
|
65
|
-
});
|
|
66
|
-
|
|
67
|
-
test("partial progress overrides merge with defaults", () => {
|
|
68
|
-
const parsed = VoiceFrontModelConfigSchema.parse({
|
|
69
|
-
progress: { enabled: false, opsThreshold: 5 },
|
|
70
|
-
});
|
|
71
|
-
expect(parsed.progress.enabled).toBe(false);
|
|
72
|
-
expect(parsed.progress.opsThreshold).toBe(5);
|
|
73
|
-
// Unspecified progress fields still get defaults
|
|
74
|
-
expect(parsed.progress.idleIntervalMs).toBe(5_000);
|
|
75
|
-
expect(parsed.progress.maxSilenceMs).toBe(35_000);
|
|
76
|
-
expect(parsed.progress.longOpMs).toBe(15_000);
|
|
77
|
-
expect(parsed.progress.minGapMs).toBe(6_000);
|
|
78
|
-
expect(parsed.progress.generationTimeoutMs).toBe(1_500);
|
|
79
|
-
});
|
|
80
|
-
|
|
81
|
-
test("a stale maxPerTurn key is stripped, not rejected", () => {
|
|
82
|
-
// The cap was removed; configs written while it existed must still parse.
|
|
83
|
-
const parsed = VoiceFrontModelConfigSchema.parse({
|
|
84
|
-
progress: { maxPerTurn: 3 },
|
|
85
|
-
});
|
|
86
|
-
expect("maxPerTurn" in parsed.progress).toBe(false);
|
|
87
|
-
});
|
|
88
|
-
|
|
89
|
-
test("rejects non-positive progress.opsThreshold", () => {
|
|
90
|
-
const result = VoiceFrontModelConfigSchema.safeParse({
|
|
91
|
-
progress: { opsThreshold: 0 },
|
|
92
|
-
});
|
|
93
|
-
expect(result.success).toBe(false);
|
|
94
|
-
});
|
|
95
|
-
|
|
96
|
-
test("rejects a heartbeat ceiling shorter than the idle tick interval", () => {
|
|
97
|
-
// The heartbeat is only checked on the idle tick, so a shorter ceiling
|
|
98
|
-
// could be overshot by a full interval.
|
|
99
|
-
const result = VoiceFrontModelConfigSchema.safeParse({
|
|
100
|
-
progress: { idleIntervalMs: 60_000, maxSilenceMs: 10_000 },
|
|
101
|
-
});
|
|
102
|
-
expect(result.success).toBe(false);
|
|
103
|
-
if (!result.success) {
|
|
104
|
-
const msgs = result.error.issues.map((issue) => issue.message);
|
|
105
|
-
expect(
|
|
106
|
-
msgs.some((msg) =>
|
|
107
|
-
msg.includes("voice.frontModel.progress.maxSilenceMs"),
|
|
108
|
-
),
|
|
109
|
-
).toBe(true);
|
|
110
|
-
}
|
|
111
|
-
// The floor itself is allowed: the tick is exactly on the ceiling.
|
|
112
|
-
expect(
|
|
113
|
-
VoiceFrontModelConfigSchema.safeParse({
|
|
114
|
-
progress: { idleIntervalMs: 60_000, maxSilenceMs: 60_000 },
|
|
115
|
-
}).success,
|
|
116
|
-
).toBe(true);
|
|
117
|
-
});
|
|
118
|
-
|
|
119
|
-
test("rejects a non-boolean progress.enabled", () => {
|
|
120
|
-
const result = VoiceFrontModelConfigSchema.safeParse({
|
|
121
|
-
progress: { enabled: "yes" },
|
|
122
|
-
});
|
|
123
|
-
expect(result.success).toBe(false);
|
|
124
|
-
if (!result.success) {
|
|
125
|
-
const msgs = result.error.issues.map((i) => i.message);
|
|
126
|
-
expect(
|
|
127
|
-
msgs.some((m) => m.includes("voice.frontModel.progress.enabled")),
|
|
128
|
-
).toBe(true);
|
|
129
|
-
}
|
|
130
|
-
});
|
|
131
|
-
});
|
|
132
|
-
|
|
133
|
-
describe("VoiceConfigSchema", () => {
|
|
134
|
-
test("empty object parses to front-model defaults", () => {
|
|
135
|
-
expect(VoiceConfigSchema.parse({})).toEqual({
|
|
136
|
-
frontModel: FRONT_MODEL_DEFAULTS,
|
|
137
|
-
});
|
|
138
|
-
});
|
|
139
|
-
|
|
140
|
-
test("partial frontModel overrides merge with defaults", () => {
|
|
141
|
-
const parsed = VoiceConfigSchema.parse({
|
|
142
|
-
frontModel: { endpointDecisionTimeoutMs: 300 },
|
|
143
|
-
});
|
|
144
|
-
expect(parsed.frontModel.endpointDecisionTimeoutMs).toBe(300);
|
|
145
|
-
expect(parsed.frontModel.endpointExtensionMs).toBe(1500);
|
|
146
|
-
expect(parsed.frontModel.progress).toEqual(PROGRESS_DEFAULTS);
|
|
147
|
-
});
|
|
148
|
-
});
|
|
@@ -1,150 +0,0 @@
|
|
|
1
|
-
import { z } from "zod";
|
|
2
|
-
|
|
3
|
-
export const VoiceProgressConfigSchema = z
|
|
4
|
-
.object({
|
|
5
|
-
enabled: z
|
|
6
|
-
.boolean({
|
|
7
|
-
error: "voice.frontModel.progress.enabled must be a boolean",
|
|
8
|
-
})
|
|
9
|
-
.default(true)
|
|
10
|
-
.describe(
|
|
11
|
-
"Speak short progress updates during long-running tool-heavy turns; the opt-out for progress narration",
|
|
12
|
-
),
|
|
13
|
-
opsThreshold: z
|
|
14
|
-
.number({
|
|
15
|
-
error: "voice.frontModel.progress.opsThreshold must be a number",
|
|
16
|
-
})
|
|
17
|
-
.int("voice.frontModel.progress.opsThreshold must be an integer")
|
|
18
|
-
.positive(
|
|
19
|
-
"voice.frontModel.progress.opsThreshold must be a positive integer",
|
|
20
|
-
)
|
|
21
|
-
.default(3)
|
|
22
|
-
.describe(
|
|
23
|
-
"Narrate after this many tool operations since the last narration",
|
|
24
|
-
),
|
|
25
|
-
idleIntervalMs: z
|
|
26
|
-
.number({
|
|
27
|
-
error: "voice.frontModel.progress.idleIntervalMs must be a number",
|
|
28
|
-
})
|
|
29
|
-
.int("voice.frontModel.progress.idleIntervalMs must be an integer")
|
|
30
|
-
.positive(
|
|
31
|
-
"voice.frontModel.progress.idleIntervalMs must be a positive integer",
|
|
32
|
-
)
|
|
33
|
-
.default(5_000)
|
|
34
|
-
.describe(
|
|
35
|
-
"How often (ms) a running turn's silence is checked, and so the soonest new tool activity is narrated",
|
|
36
|
-
),
|
|
37
|
-
maxSilenceMs: z
|
|
38
|
-
.number({
|
|
39
|
-
error: "voice.frontModel.progress.maxSilenceMs must be a number",
|
|
40
|
-
})
|
|
41
|
-
.int("voice.frontModel.progress.maxSilenceMs must be an integer")
|
|
42
|
-
.positive(
|
|
43
|
-
"voice.frontModel.progress.maxSilenceMs must be a positive integer",
|
|
44
|
-
)
|
|
45
|
-
.default(35_000)
|
|
46
|
-
.describe(
|
|
47
|
-
"Heartbeat ceiling (ms): narrate after this much unbroken silence even when nothing new has happened. Evaluated on the idle tick, so its resolution is idleIntervalMs and it must be at least that long",
|
|
48
|
-
),
|
|
49
|
-
longOpMs: z
|
|
50
|
-
.number({
|
|
51
|
-
error: "voice.frontModel.progress.longOpMs must be a number",
|
|
52
|
-
})
|
|
53
|
-
.int("voice.frontModel.progress.longOpMs must be an integer")
|
|
54
|
-
.positive("voice.frontModel.progress.longOpMs must be a positive integer")
|
|
55
|
-
.default(15_000)
|
|
56
|
-
.describe(
|
|
57
|
-
"A tool operation that ran at least this long (ms) narrates the moment it completes, without waiting for opsThreshold",
|
|
58
|
-
),
|
|
59
|
-
minGapMs: z
|
|
60
|
-
.number({
|
|
61
|
-
error: "voice.frontModel.progress.minGapMs must be a number",
|
|
62
|
-
})
|
|
63
|
-
.int("voice.frontModel.progress.minGapMs must be an integer")
|
|
64
|
-
.positive("voice.frontModel.progress.minGapMs must be a positive integer")
|
|
65
|
-
.default(6_000)
|
|
66
|
-
.describe(
|
|
67
|
-
"Minimum spacing (ms) from any spoken floor-holder (ack or narration)",
|
|
68
|
-
),
|
|
69
|
-
generationTimeoutMs: z
|
|
70
|
-
.number({
|
|
71
|
-
error: "voice.frontModel.progress.generationTimeoutMs must be a number",
|
|
72
|
-
})
|
|
73
|
-
.int("voice.frontModel.progress.generationTimeoutMs must be an integer")
|
|
74
|
-
.positive(
|
|
75
|
-
"voice.frontModel.progress.generationTimeoutMs must be a positive integer",
|
|
76
|
-
)
|
|
77
|
-
.default(1_500)
|
|
78
|
-
.describe(
|
|
79
|
-
"Budget (ms) for LLM-generated progress text. Not latency-critical: it speaks into dead air",
|
|
80
|
-
),
|
|
81
|
-
})
|
|
82
|
-
// The heartbeat is checked when the idle tick finds the turn silent, so a
|
|
83
|
-
// ceiling shorter than the tick interval would be missed by up to a full
|
|
84
|
-
// interval, a promise the cadence cannot keep. Rejecting the combination
|
|
85
|
-
// beats silently overshooting it.
|
|
86
|
-
.refine((progress) => progress.maxSilenceMs >= progress.idleIntervalMs, {
|
|
87
|
-
error:
|
|
88
|
-
"voice.frontModel.progress.maxSilenceMs must be at least idleIntervalMs: the heartbeat is evaluated on the idle tick",
|
|
89
|
-
})
|
|
90
|
-
.describe(
|
|
91
|
-
"Progress-narration tuning for live voice sessions (spoken updates during long-running turns)",
|
|
92
|
-
);
|
|
93
|
-
|
|
94
|
-
export const VoiceFrontModelConfigSchema = z
|
|
95
|
-
.object({
|
|
96
|
-
endpointDecisionTimeoutMs: z
|
|
97
|
-
.number({
|
|
98
|
-
error: "voice.frontModel.endpointDecisionTimeoutMs must be a number",
|
|
99
|
-
})
|
|
100
|
-
.int("voice.frontModel.endpointDecisionTimeoutMs must be an integer")
|
|
101
|
-
.positive(
|
|
102
|
-
"voice.frontModel.endpointDecisionTimeoutMs must be a positive integer",
|
|
103
|
-
)
|
|
104
|
-
.default(1200)
|
|
105
|
-
.describe(
|
|
106
|
-
"Hard budget (ms) for the endpoint decision LLM call. This adds to end-of-turn latency when semantic endpointing is on, so keep it as tight as the decider model's real roundtrip allows. Measured Haiku roundtrips through the managed proxy run ~670-1130ms (dev), so tighter budgets turn the feature into a fail-open no-op.",
|
|
107
|
-
),
|
|
108
|
-
endpointExtensionMs: z
|
|
109
|
-
.number({
|
|
110
|
-
error: "voice.frontModel.endpointExtensionMs must be a number",
|
|
111
|
-
})
|
|
112
|
-
.int("voice.frontModel.endpointExtensionMs must be an integer")
|
|
113
|
-
.positive(
|
|
114
|
-
"voice.frontModel.endpointExtensionMs must be a positive integer",
|
|
115
|
-
)
|
|
116
|
-
.default(1500)
|
|
117
|
-
.describe(
|
|
118
|
-
"How long (ms) a 'hold' decision keeps the turn open before turn-end replays",
|
|
119
|
-
),
|
|
120
|
-
endpointMaxExtensions: z
|
|
121
|
-
.number({
|
|
122
|
-
error: "voice.frontModel.endpointMaxExtensions must be a number",
|
|
123
|
-
})
|
|
124
|
-
.int("voice.frontModel.endpointMaxExtensions must be an integer")
|
|
125
|
-
.nonnegative(
|
|
126
|
-
"voice.frontModel.endpointMaxExtensions must be a nonnegative integer",
|
|
127
|
-
)
|
|
128
|
-
.default(2)
|
|
129
|
-
.describe("Cap on consecutive 'hold' extensions per utterance"),
|
|
130
|
-
progress: VoiceProgressConfigSchema.default(
|
|
131
|
-
VoiceProgressConfigSchema.parse({}),
|
|
132
|
-
),
|
|
133
|
-
})
|
|
134
|
-
.describe(
|
|
135
|
-
"Voice front-door endpointing and long-turn progress narration tuning, shared by live voice and phone calls",
|
|
136
|
-
);
|
|
137
|
-
|
|
138
|
-
export const VoiceConfigSchema = z
|
|
139
|
-
.object({
|
|
140
|
-
frontModel: VoiceFrontModelConfigSchema.default(
|
|
141
|
-
VoiceFrontModelConfigSchema.parse({}),
|
|
142
|
-
),
|
|
143
|
-
})
|
|
144
|
-
.describe(
|
|
145
|
-
"Transport-agnostic voice configuration shared by live voice and phone calls: front-door routing and progress narration tuning",
|
|
146
|
-
);
|
|
147
|
-
|
|
148
|
-
export type VoiceConfig = z.infer<typeof VoiceConfigSchema>;
|
|
149
|
-
export type VoiceFrontModelConfig = z.infer<typeof VoiceFrontModelConfigSchema>;
|
|
150
|
-
export type VoiceProgressConfig = z.infer<typeof VoiceProgressConfigSchema>;
|
|
@@ -1,133 +0,0 @@
|
|
|
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
|
-
});
|
|
@@ -1,45 +0,0 @@
|
|
|
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
|
-
}
|
|
@@ -1,119 +0,0 @@
|
|
|
1
|
-
import { join } from "node:path";
|
|
2
|
-
|
|
3
|
-
import { sleep } from "../../util/retry.js";
|
|
4
|
-
import {
|
|
5
|
-
type DesktopChild,
|
|
6
|
-
type DesktopChildRole,
|
|
7
|
-
type DesktopLoss,
|
|
8
|
-
DesktopSessionManager,
|
|
9
|
-
type DesktopSpawnRequest,
|
|
10
|
-
} from "../desktop-session-manager.js";
|
|
11
|
-
|
|
12
|
-
/** A child the test exits by hand. */
|
|
13
|
-
class FakeChild implements DesktopChild {
|
|
14
|
-
private static nextPid = 1000;
|
|
15
|
-
readonly pid = FakeChild.nextPid++;
|
|
16
|
-
readonly exited: Promise<number>;
|
|
17
|
-
private settle!: (code: number) => void;
|
|
18
|
-
|
|
19
|
-
constructor(
|
|
20
|
-
readonly role: DesktopChildRole,
|
|
21
|
-
readonly request: DesktopSpawnRequest,
|
|
22
|
-
) {
|
|
23
|
-
this.exited = new Promise((resolve) => {
|
|
24
|
-
this.settle = resolve;
|
|
25
|
-
});
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
kill(): void {}
|
|
29
|
-
|
|
30
|
-
exit(code = 0): void {
|
|
31
|
-
this.settle(code);
|
|
32
|
-
}
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
export const LINGER_MS = 20;
|
|
36
|
-
export const KILL_GRACE_MS = 20;
|
|
37
|
-
|
|
38
|
-
export interface FakeDesktopOptions {
|
|
39
|
-
profileDir: string;
|
|
40
|
-
/** Defaults inside `profileDir`, for tests that ignore the dock's config. */
|
|
41
|
-
panelConfigDir?: string;
|
|
42
|
-
/** Roles whose spawn throws, to exercise a start that fails partway. */
|
|
43
|
-
failSpawn?: DesktopChildRole[];
|
|
44
|
-
/** Binaries `which` cannot find. */
|
|
45
|
-
missingBinaries?: string[];
|
|
46
|
-
/** Whether a SIGTERM makes the fake child exit on its own. */
|
|
47
|
-
exitOnTerm?: boolean;
|
|
48
|
-
/** Whether a SIGKILL does; without either the child survives both. */
|
|
49
|
-
exitOnKill?: boolean;
|
|
50
|
-
sourceEnv?: NodeJS.ProcessEnv;
|
|
51
|
-
renderWallpaper?: (width: number, height: number) => Promise<Buffer | null>;
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
export function newFakeDesktop(options: FakeDesktopOptions) {
|
|
55
|
-
const spawned: FakeChild[] = [];
|
|
56
|
-
const killed: { child: FakeChild; signal: string }[] = [];
|
|
57
|
-
let vncReady = true;
|
|
58
|
-
let chromiumPath: () => Promise<string> = async () => "/fake/chromium";
|
|
59
|
-
const manager = new DesktopSessionManager({
|
|
60
|
-
spawn: (role, request) => {
|
|
61
|
-
if (options.failSpawn?.includes(role)) {
|
|
62
|
-
throw new Error(`spawn ${role} failed`);
|
|
63
|
-
}
|
|
64
|
-
const child = new FakeChild(role, request);
|
|
65
|
-
spawned.push(child);
|
|
66
|
-
return child;
|
|
67
|
-
},
|
|
68
|
-
which: (binary) =>
|
|
69
|
-
options.missingBinaries?.includes(binary) ? null : `/usr/bin/${binary}`,
|
|
70
|
-
probeVncPort: async () => vncReady,
|
|
71
|
-
resolveChromePath: () => chromiumPath(),
|
|
72
|
-
renderWallpaper: options.renderWallpaper ?? (async () => null),
|
|
73
|
-
killProcessGroup: (child, signal) => {
|
|
74
|
-
killed.push({ child: child as FakeChild, signal });
|
|
75
|
-
const exits =
|
|
76
|
-
signal === "SIGTERM" ? options.exitOnTerm : options.exitOnKill;
|
|
77
|
-
if (exits) {
|
|
78
|
-
(child as FakeChild).exit(0);
|
|
79
|
-
}
|
|
80
|
-
},
|
|
81
|
-
lingerMs: LINGER_MS,
|
|
82
|
-
readyDeadlineMs: 30,
|
|
83
|
-
killGraceMs: KILL_GRACE_MS,
|
|
84
|
-
profileDir: options.profileDir,
|
|
85
|
-
panelConfigDir:
|
|
86
|
-
options.panelConfigDir ?? join(options.profileDir, "desktop-panel"),
|
|
87
|
-
sourceEnv: options.sourceEnv,
|
|
88
|
-
});
|
|
89
|
-
return {
|
|
90
|
-
manager,
|
|
91
|
-
spawned,
|
|
92
|
-
killed,
|
|
93
|
-
/** Children that got a SIGTERM, in order. */
|
|
94
|
-
terminated: () =>
|
|
95
|
-
killed.filter((k) => k.signal === "SIGTERM").map((k) => k.child),
|
|
96
|
-
setVncReady: (ready: boolean) => {
|
|
97
|
-
vncReady = ready;
|
|
98
|
-
},
|
|
99
|
-
setChromiumPath: (resolve: () => Promise<string>) => {
|
|
100
|
-
chromiumPath = resolve;
|
|
101
|
-
},
|
|
102
|
-
child: (role: DesktopChildRole) =>
|
|
103
|
-
spawned.filter((c) => c.role === role).at(-1)!,
|
|
104
|
-
roles: () => spawned.map((c) => c.role),
|
|
105
|
-
count: (role: DesktopChildRole) =>
|
|
106
|
-
spawned.filter((c) => c.role === role).length,
|
|
107
|
-
};
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
/** Let one awaited step (a path resolution, an exit callback) land. */
|
|
111
|
-
export const settle = (): Promise<void> => sleep(0);
|
|
112
|
-
|
|
113
|
-
export function newViewer() {
|
|
114
|
-
const lost: DesktopLoss[] = [];
|
|
115
|
-
return {
|
|
116
|
-
lost,
|
|
117
|
-
viewer: { onDesktopLost: (loss: DesktopLoss) => lost.push(loss) },
|
|
118
|
-
};
|
|
119
|
-
}
|
|
@@ -1,71 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
mkdtempSync,
|
|
3
|
-
readdirSync,
|
|
4
|
-
readFileSync,
|
|
5
|
-
rmSync,
|
|
6
|
-
statSync,
|
|
7
|
-
writeFileSync,
|
|
8
|
-
} from "node:fs";
|
|
9
|
-
import { tmpdir } from "node:os";
|
|
10
|
-
import { join } from "node:path";
|
|
11
|
-
import { afterEach, expect, test } from "bun:test";
|
|
12
|
-
|
|
13
|
-
import { writeDesktopChromePolicy } from "./desktop-chrome-policy.js";
|
|
14
|
-
|
|
15
|
-
const directories: string[] = [];
|
|
16
|
-
function policyDirectory(): string {
|
|
17
|
-
const path = mkdtempSync(join(tmpdir(), "desktop-chrome-policy-"));
|
|
18
|
-
directories.push(path);
|
|
19
|
-
return path;
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
afterEach(() => {
|
|
23
|
-
for (const path of directories.splice(0)) {
|
|
24
|
-
rmSync(path, { recursive: true, force: true });
|
|
25
|
-
}
|
|
26
|
-
});
|
|
27
|
-
|
|
28
|
-
test("preserves unrelated policies and does not rewrite on repeated startup", () => {
|
|
29
|
-
const directory = policyDirectory();
|
|
30
|
-
const path = join(directory, "vellum-desktop.json");
|
|
31
|
-
const otherPath = join(directory, "organization.json");
|
|
32
|
-
const unrelated = '{ "HomepageLocation": "https://example.com" }\n';
|
|
33
|
-
writeFileSync(otherPath, unrelated);
|
|
34
|
-
writeFileSync(path, JSON.stringify({ DownloadRestrictions: 1 }));
|
|
35
|
-
|
|
36
|
-
writeDesktopChromePolicy(directory);
|
|
37
|
-
const content = readFileSync(path, "utf8");
|
|
38
|
-
expect(JSON.parse(content).DownloadRestrictions).toBe(1);
|
|
39
|
-
expect(readFileSync(otherPath, "utf8")).toBe(unrelated);
|
|
40
|
-
expect(readdirSync(directory).sort()).toEqual([
|
|
41
|
-
"organization.json",
|
|
42
|
-
"vellum-desktop.json",
|
|
43
|
-
]);
|
|
44
|
-
|
|
45
|
-
const before = statSync(path);
|
|
46
|
-
writeDesktopChromePolicy(directory);
|
|
47
|
-
expect(readFileSync(path, "utf8")).toBe(content);
|
|
48
|
-
expect(statSync(path).ino).toBe(before.ino);
|
|
49
|
-
expect(statSync(path).mtimeMs).toBe(before.mtimeMs);
|
|
50
|
-
});
|
|
51
|
-
|
|
52
|
-
test("creates missing policy directories for a fresh desktop", () => {
|
|
53
|
-
const directory = join(policyDirectory(), "policies", "managed");
|
|
54
|
-
writeDesktopChromePolicy(directory);
|
|
55
|
-
expect(readdirSync(directory)).toEqual(["vellum-desktop.json"]);
|
|
56
|
-
expect(statSync(join(directory, "vellum-desktop.json")).mode & 0o777).toBe(
|
|
57
|
-
0o644,
|
|
58
|
-
);
|
|
59
|
-
});
|
|
60
|
-
|
|
61
|
-
test.each(["{broken", "[]", "null", "false"])(
|
|
62
|
-
"leaves invalid existing policy content untouched: %s",
|
|
63
|
-
(content) => {
|
|
64
|
-
const directory = policyDirectory();
|
|
65
|
-
const path = join(directory, "vellum-desktop.json");
|
|
66
|
-
writeFileSync(path, content);
|
|
67
|
-
expect(() => writeDesktopChromePolicy(directory)).toThrow();
|
|
68
|
-
expect(readFileSync(path, "utf8")).toBe(content);
|
|
69
|
-
expect(readdirSync(directory)).toEqual(["vellum-desktop.json"]);
|
|
70
|
-
},
|
|
71
|
-
);
|