@vellumai/assistant 0.4.56 → 0.5.0
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/ARCHITECTURE.md +10 -10
- package/Dockerfile +3 -0
- package/README.md +11 -11
- package/docs/architecture/integrations.md +2 -2
- package/docs/architecture/memory.md +3 -4
- package/docs/credential-execution-service.md +13 -20
- package/node_modules/@vellumai/ces-contracts/src/error.ts +5 -4
- package/package.json +1 -1
- package/src/__tests__/actor-token-service.test.ts +7 -7
- package/src/__tests__/anthropic-provider.test.ts +172 -0
- package/src/__tests__/app-builder-tool-scripts.test.ts +15 -1
- package/src/__tests__/approval-cascade.test.ts +2 -2
- package/src/__tests__/approval-routes-http.test.ts +3 -4
- package/src/__tests__/asset-materialize-tool.test.ts +5 -5
- package/src/__tests__/asset-search-tool.test.ts +1 -1
- package/src/__tests__/assistant-attachments.test.ts +5 -5
- package/src/__tests__/assistant-events-sse-hardening.test.ts +1 -1
- package/src/__tests__/assistant-feature-flags-integration.test.ts +50 -38
- package/src/__tests__/attachments-store.test.ts +2 -2
- package/src/__tests__/avatar-e2e.test.ts +5 -3
- package/src/__tests__/browser-skill-endstate.test.ts +0 -1
- package/src/__tests__/call-routes-http.test.ts +2 -2
- package/src/__tests__/callback-handoff-copy.test.ts +1 -1
- package/src/__tests__/cancel-resolves-conversation-key.test.ts +158 -0
- package/src/__tests__/channel-readiness-routes.test.ts +0 -1
- package/src/__tests__/channel-readiness-service.test.ts +0 -1
- package/src/__tests__/checker.test.ts +31 -32
- package/src/__tests__/chrome-cdp.test.ts +47 -18
- package/src/__tests__/claude-code-skill-regression.test.ts +2 -2
- package/src/__tests__/config-schema-cmd.test.ts +2 -2
- package/src/__tests__/config-schema.test.ts +9 -18
- package/src/__tests__/confirmation-request-guardian-bridge.test.ts +1 -1
- package/src/__tests__/conversation-abort-tool-results.test.ts +4 -4
- package/src/__tests__/conversation-agent-loop-overflow.test.ts +2 -2
- package/src/__tests__/conversation-agent-loop.test.ts +11 -4
- package/src/__tests__/conversation-attachments.test.ts +1 -1
- package/src/__tests__/conversation-confirmation-signals.test.ts +2 -2
- package/src/__tests__/conversation-error.test.ts +33 -0
- package/src/__tests__/conversation-init.benchmark.test.ts +0 -1
- package/src/__tests__/conversation-load-history-repair.test.ts +1 -1
- package/src/__tests__/conversation-pairing.test.ts +1 -1
- package/src/__tests__/conversation-pre-run-repair.test.ts +4 -4
- package/src/__tests__/conversation-provider-retry-repair.test.ts +4 -4
- package/src/__tests__/conversation-queue.test.ts +23 -14
- package/src/__tests__/conversation-routes-slash-commands.test.ts +3 -3
- package/src/__tests__/conversation-runtime-assembly.test.ts +204 -185
- package/src/__tests__/conversation-seed-composer.test.ts +1 -1
- package/src/__tests__/conversation-slash-queue.test.ts +4 -4
- package/src/__tests__/conversation-slash-unknown.test.ts +4 -4
- package/src/__tests__/conversation-starter-routes.test.ts +291 -0
- package/src/__tests__/conversation-wipe.test.ts +438 -0
- package/src/__tests__/conversation-workspace-cache-state.test.ts +2 -3
- package/src/__tests__/conversation-workspace-injection.test.ts +4 -5
- package/src/__tests__/conversation-workspace-tool-tracking.test.ts +4 -5
- package/src/__tests__/credential-security-e2e.test.ts +20 -0
- package/src/__tests__/credential-security-invariants.test.ts +1 -0
- package/src/__tests__/credential-vault-unit.test.ts +227 -0
- package/src/__tests__/credentials-cli.test.ts +3 -0
- package/src/__tests__/date-context.test.ts +59 -377
- package/src/__tests__/drop-capability-card-state-migration.test.ts +169 -0
- package/src/__tests__/dynamic-skill-workflow-prompt.test.ts +11 -45
- package/src/__tests__/emit-signal-routing-intent.test.ts +3 -3
- package/src/__tests__/encrypted-store.test.ts +249 -15
- package/src/__tests__/ephemeral-permissions.test.ts +4 -5
- package/src/__tests__/event-bus.test.ts +3 -3
- package/src/__tests__/file-read-tool.test.ts +40 -0
- package/src/__tests__/gateway-only-enforcement.test.ts +2 -2
- package/src/__tests__/gateway-only-guard.test.ts +1 -0
- package/src/__tests__/gemini-image-service.test.ts +4 -4
- package/src/__tests__/gemini-provider.test.ts +6 -9
- package/src/__tests__/guardian-binding-drift-heal.test.ts +128 -0
- package/src/__tests__/guardian-dispatch.test.ts +0 -1
- package/src/__tests__/host-file-read-tool.test.ts +87 -0
- package/src/__tests__/host-shell-tool.test.ts +6 -6
- package/src/__tests__/http-user-message-parity.test.ts +2 -2
- package/src/__tests__/identity-intro-cache.test.ts +209 -0
- package/src/__tests__/intent-routing.test.ts +51 -99
- package/src/__tests__/invite-routes-http.test.ts +5 -0
- package/src/__tests__/list-messages-attachments.test.ts +1 -1
- package/src/__tests__/managed-proxy-context.test.ts +2 -5
- package/src/__tests__/managed-skill-lifecycle.test.ts +8 -8
- package/src/__tests__/media-generate-image.test.ts +32 -15
- package/src/__tests__/media-reuse-story.e2e.test.ts +1 -1
- package/src/__tests__/memory-context-benchmark.benchmark.test.ts +1 -1
- package/src/__tests__/memory-lifecycle-e2e.test.ts +24 -18
- package/src/__tests__/memory-recall-quality.test.ts +4 -3
- package/src/__tests__/memory-regressions.test.ts +86 -90
- package/src/__tests__/migration-cross-version-compatibility.test.ts +32 -32
- package/src/__tests__/migration-export-http.test.ts +26 -27
- package/src/__tests__/migration-import-commit-http.test.ts +165 -37
- package/src/__tests__/migration-import-preflight-http.test.ts +81 -20
- package/src/__tests__/migration-validate-http.test.ts +16 -16
- package/src/__tests__/model-intents.test.ts +2 -2
- package/src/__tests__/no-domain-routing-in-prompt-guard.test.ts +1 -1
- package/src/__tests__/non-member-access-request.test.ts +3 -3
- package/src/__tests__/notification-broadcaster.test.ts +1 -1
- package/src/__tests__/notification-decision-fallback.test.ts +2 -2
- package/src/__tests__/notification-decision-identity.test.ts +8 -9
- package/src/__tests__/notification-decision-strategy.test.ts +1 -1
- package/src/__tests__/notification-deep-link.test.ts +1 -1
- package/src/__tests__/notification-guardian-path.test.ts +0 -1
- package/src/__tests__/notification-schedule-dedup.test.ts +7 -7
- package/src/__tests__/oauth-store.test.ts +1 -3
- package/src/__tests__/oauth2-gateway-transport.test.ts +6 -1
- package/src/__tests__/onboarding-template-contract.test.ts +23 -59
- package/src/__tests__/provider-error-scenarios.test.ts +154 -0
- package/src/__tests__/provider-fail-open-selection.test.ts +2 -2
- package/src/__tests__/provider-managed-proxy-integration.test.ts +8 -9
- package/src/__tests__/provider-registry-ollama.test.ts +5 -2
- package/src/__tests__/qdrant-manager.test.ts +7 -7
- package/src/__tests__/ratelimit.test.ts +0 -74
- package/src/__tests__/recording-handler.test.ts +0 -1
- package/src/__tests__/require-fresh-approval.test.ts +1 -1
- package/src/__tests__/runtime-attachment-metadata.test.ts +1 -1
- package/src/__tests__/runtime-events-sse-parity.test.ts +1 -1
- package/src/__tests__/runtime-events-sse.test.ts +1 -1
- package/src/__tests__/scheduler-recurrence.test.ts +46 -2
- package/src/__tests__/schema-transforms.test.ts +114 -54
- package/src/__tests__/secret-onetime-send.test.ts +20 -0
- package/src/__tests__/secret-routes-managed-proxy.test.ts +5 -2
- package/src/__tests__/secret-scanner-executor.test.ts +1 -2
- package/src/__tests__/send-endpoint-busy.test.ts +63 -4
- package/src/__tests__/send-notification-tool.test.ts +2 -2
- package/src/__tests__/shell-credential-ref.test.ts +0 -1
- package/src/__tests__/shell-tool-proxy-mode.test.ts +1 -2
- package/src/__tests__/skill-memory.test.ts +549 -0
- package/src/__tests__/skill-script-runner-sandbox.test.ts +1 -2
- package/src/__tests__/slack-app-setup-skill-regression.test.ts +37 -0
- package/src/__tests__/slack-channel-config.test.ts +109 -94
- package/src/__tests__/swarm-conversation-integration.test.ts +2 -2
- package/src/__tests__/swarm-recursion.test.ts +2 -2
- package/src/__tests__/swarm-tool.test.ts +2 -2
- package/src/__tests__/system-prompt.test.ts +19 -66
- package/src/__tests__/telegram-config.test.ts +121 -0
- package/src/__tests__/terminal-tools.test.ts +1 -1
- package/src/__tests__/tool-execution-abort-cleanup.test.ts +1 -2
- package/src/__tests__/tool-executor-lifecycle-events.test.ts +1 -1
- package/src/__tests__/tool-executor-shell-integration.test.ts +1 -1
- package/src/__tests__/tool-executor.test.ts +1 -1
- package/src/__tests__/trace-emitter.test.ts +8 -1
- package/src/__tests__/trust-store.test.ts +7 -8
- package/src/__tests__/twilio-routes.test.ts +1 -18
- package/src/__tests__/user-reference.test.ts +82 -2
- package/src/__tests__/vbundle-pax-and-symlink.test.ts +196 -0
- package/src/__tests__/verification-control-plane-policy.test.ts +1 -1
- package/src/approvals/guardian-request-resolvers.ts +3 -3
- package/src/avatar/ascii-renderer.ts +2 -2
- package/src/avatar/png-renderer.ts +2 -2
- package/src/avatar/resvg-lazy.ts +21 -0
- package/src/calls/guardian-dispatch.ts +1 -1
- package/src/calls/relay-access-wait.ts +2 -2
- package/src/calls/twilio-rest.ts +0 -248
- package/src/cli/AGENTS.md +5 -8
- package/src/cli/__tests__/notifications.test.ts +5 -5
- package/src/cli/commands/avatar.ts +64 -2
- package/src/cli/commands/conversations.ts +131 -1
- package/src/cli/commands/credentials.ts +2 -0
- package/src/cli/commands/notifications.ts +3 -3
- package/src/cli.ts +10 -0
- package/src/config/bundled-skills/acp/SKILL.md +5 -5
- package/src/config/bundled-skills/acp/TOOLS.json +6 -6
- package/src/config/bundled-skills/app-builder/SKILL.md +42 -42
- package/src/config/bundled-skills/app-builder/TOOLS.json +10 -10
- package/src/config/bundled-skills/browser/SKILL.md +15 -15
- package/src/config/bundled-skills/browser/TOOLS.json +14 -14
- package/src/config/bundled-skills/chatgpt-import/SKILL.md +2 -2
- package/src/config/bundled-skills/chatgpt-import/TOOLS.json +1 -1
- package/src/config/bundled-skills/chatgpt-import/tools/chatgpt-import.ts +1 -1
- package/src/config/bundled-skills/claude-code/SKILL.md +5 -5
- package/src/config/bundled-skills/computer-use/SKILL.md +2 -2
- package/src/config/bundled-skills/computer-use/TOOLS.json +15 -15
- package/src/config/bundled-skills/contacts/SKILL.md +3 -3
- package/src/config/bundled-skills/contacts/TOOLS.json +4 -4
- package/src/config/bundled-skills/document/SKILL.md +4 -4
- package/src/config/bundled-skills/document/TOOLS.json +2 -2
- package/src/config/bundled-skills/followups/TOOLS.json +3 -3
- package/src/config/bundled-skills/gmail/SKILL.md +32 -32
- package/src/config/bundled-skills/gmail/TOOLS.json +16 -16
- package/src/config/bundled-skills/gmail/tools/gmail-archive.ts +1 -1
- package/src/config/bundled-skills/gmail/tools/gmail-sender-digest.ts +1 -1
- package/src/config/bundled-skills/google-calendar/SKILL.md +1 -1
- package/src/config/bundled-skills/google-calendar/TOOLS.json +5 -5
- package/src/config/bundled-skills/google-calendar/types.ts +1 -1
- package/src/config/bundled-skills/heartbeat/SKILL.md +43 -0
- package/src/config/bundled-skills/image-studio/SKILL.md +3 -3
- package/src/config/bundled-skills/image-studio/TOOLS.json +2 -3
- package/src/config/bundled-skills/image-studio/tools/media-generate-image.ts +16 -12
- package/src/config/bundled-skills/media-processing/SKILL.md +40 -40
- package/src/config/bundled-skills/media-processing/TOOLS.json +8 -8
- package/src/config/bundled-skills/media-processing/__tests__/concurrency-pool.test.ts +2 -2
- package/src/config/bundled-skills/media-processing/__tests__/preprocess.test.ts +1 -1
- package/src/config/bundled-skills/media-processing/services/gemini-map.ts +5 -5
- package/src/config/bundled-skills/media-processing/services/gemini-video.ts +2 -2
- package/src/config/bundled-skills/media-processing/services/preprocess.ts +2 -2
- package/src/config/bundled-skills/media-processing/services/processing-pipeline.ts +2 -2
- package/src/config/bundled-skills/media-processing/services/reduce.ts +3 -3
- package/src/config/bundled-skills/media-processing/tools/generate-clip.ts +2 -2
- package/src/config/bundled-skills/media-processing/tools/query-media-events.ts +1 -1
- package/src/config/bundled-skills/messaging/SKILL.md +29 -25
- package/src/config/bundled-skills/messaging/TOOLS.json +11 -11
- package/src/config/bundled-skills/messaging/tools/messaging-send.ts +1 -1
- package/src/config/bundled-skills/messaging/tools/shared.ts +1 -1
- package/src/config/bundled-skills/notifications/SKILL.md +3 -3
- package/src/config/bundled-skills/notifications/TOOLS.json +2 -2
- package/src/config/bundled-skills/notifications/tools/send-notification.ts +3 -3
- package/src/config/bundled-skills/orchestration/SKILL.md +1 -1
- package/src/config/bundled-skills/orchestration/TOOLS.json +1 -1
- package/src/config/bundled-skills/phone-calls/SKILL.md +18 -14
- package/src/config/bundled-skills/phone-calls/TOOLS.json +3 -3
- package/src/config/bundled-skills/phone-calls/references/CONFIG.md +2 -2
- package/src/config/bundled-skills/phone-calls/references/TRANSCRIPTS.md +2 -2
- package/src/config/bundled-skills/phone-calls/references/TROUBLESHOOTING.md +1 -1
- package/src/config/bundled-skills/playbooks/TOOLS.json +4 -4
- package/src/config/bundled-skills/schedule/SKILL.md +26 -26
- package/src/config/bundled-skills/schedule/TOOLS.json +5 -5
- package/src/config/bundled-skills/screen-watch/SKILL.md +3 -3
- package/src/config/bundled-skills/screen-watch/TOOLS.json +1 -1
- package/src/config/bundled-skills/sequences/SKILL.md +2 -2
- package/src/config/bundled-skills/sequences/TOOLS.json +10 -10
- package/src/config/bundled-skills/sequences/tools/sequence-analytics.ts +2 -2
- package/src/config/bundled-skills/sequences/tools/sequence-enroll.ts +2 -2
- package/src/config/bundled-skills/sequences/tools/sequence-enrollment-list.ts +1 -1
- package/src/config/bundled-skills/sequences/tools/sequence-get.ts +1 -1
- package/src/config/bundled-skills/sequences/tools/sequence-import.ts +3 -3
- package/src/config/bundled-skills/sequences/tools/sequence-list.ts +1 -1
- package/src/config/bundled-skills/sequences/tools/sequence-update.ts +1 -1
- package/src/config/bundled-skills/settings/TOOLS.json +3 -3
- package/src/config/bundled-skills/settings/tools/open-system-settings.ts +1 -1
- package/src/config/bundled-skills/skill-management/TOOLS.json +5 -5
- package/src/config/bundled-skills/skills-catalog/SKILL.md +84 -0
- package/src/config/bundled-skills/slack/SKILL.md +2 -2
- package/src/config/bundled-skills/slack/TOOLS.json +8 -8
- package/src/config/bundled-skills/slack/tools/slack-scan-digest.ts +3 -3
- package/src/config/bundled-skills/subagent/TOOLS.json +5 -5
- package/src/config/bundled-skills/tasks/SKILL.md +1 -1
- package/src/config/bundled-skills/tasks/TOOLS.json +9 -9
- package/src/config/bundled-skills/transcribe/SKILL.md +5 -5
- package/src/config/bundled-skills/transcribe/TOOLS.json +1 -1
- package/src/config/bundled-skills/transcribe/tools/transcribe-media.ts +10 -10
- package/src/config/bundled-skills/watcher/SKILL.md +4 -4
- package/src/config/bundled-skills/watcher/TOOLS.json +5 -5
- package/src/config/feature-flag-registry.json +33 -17
- package/src/config/schemas/sandbox.ts +1 -1
- package/src/config/schemas/services.ts +13 -3
- package/src/config/schemas/timeouts.ts +0 -10
- package/src/contacts/contact-store.ts +63 -0
- package/src/contacts/contacts-write.ts +1 -1
- package/src/daemon/assistant-attachments.ts +2 -2
- package/src/daemon/conversation-agent-loop-handlers.ts +2 -2
- package/src/daemon/conversation-agent-loop.ts +7 -30
- package/src/daemon/conversation-error.ts +24 -0
- package/src/daemon/conversation-memory.ts +8 -7
- package/src/daemon/conversation-runtime-assembly.ts +141 -275
- package/src/daemon/conversation-slash.ts +7 -26
- package/src/daemon/conversation-surfaces.ts +14 -0
- package/src/daemon/conversation-tool-setup.ts +9 -8
- package/src/daemon/conversation.ts +2 -0
- package/src/daemon/daemon-control.ts +1 -1
- package/src/daemon/date-context.ts +10 -83
- package/src/daemon/handlers/config-channels.ts +12 -2
- package/src/daemon/handlers/config-slack-channel.ts +7 -1
- package/src/daemon/handlers/config-telegram.ts +6 -1
- package/src/daemon/handlers/conversations.ts +2 -2
- package/src/daemon/handlers/skills.ts +4 -0
- package/src/daemon/lifecycle.ts +28 -4
- package/src/daemon/providers-setup.ts +1 -1
- package/src/daemon/server.ts +1 -5
- package/src/daemon/shutdown-handlers.ts +9 -3
- package/src/daemon/tool-side-effects.ts +40 -0
- package/src/daemon/trace-emitter.ts +26 -2
- package/src/events/domain-events.ts +1 -1
- package/src/events/tool-permission-telemetry-listener.ts +46 -0
- package/src/inbound/platform-callback-registration.ts +0 -18
- package/src/media/app-icon-generator.ts +15 -8
- package/src/media/avatar-router.ts +15 -8
- package/src/media/gemini-image-service.ts +125 -21
- package/src/memory/attachments-store.ts +3 -3
- package/src/memory/channel-verification-sessions.ts +6 -6
- package/src/memory/conversation-crud.ts +196 -1
- package/src/memory/{thread-starters-cadence.ts → conversation-starters-cadence.ts} +9 -42
- package/src/memory/conversation-title-service.ts +2 -3
- package/src/memory/db-init.ts +25 -1
- package/src/memory/invite-store.ts +4 -4
- package/src/memory/items-extractor.ts +4 -4
- package/src/memory/job-handlers/{thread-starters.ts → conversation-starters.ts} +123 -38
- package/src/memory/jobs-store.ts +3 -2
- package/src/memory/jobs-worker.ts +7 -5
- package/src/memory/lifecycle-events-store.ts +63 -0
- package/src/memory/migrations/172-rename-created-by-session-id.ts +27 -0
- package/src/memory/migrations/173-rename-source-session-id.ts +16 -0
- package/src/memory/migrations/174-rename-thread-starters-table.ts +52 -0
- package/src/memory/migrations/175-create-lifecycle-events.ts +15 -0
- package/src/memory/migrations/176-drop-capability-card-state.ts +36 -0
- package/src/memory/migrations/177-create-trace-events-table.ts +40 -0
- package/src/memory/migrations/index.ts +6 -0
- package/src/memory/migrations/registry.ts +13 -0
- package/src/memory/retriever.test.ts +223 -96
- package/src/memory/retriever.ts +115 -138
- package/src/memory/schema/calls.ts +1 -1
- package/src/memory/schema/contacts.ts +1 -1
- package/src/memory/schema/infrastructure.ts +29 -0
- package/src/memory/schema/memory-core.ts +7 -17
- package/src/memory/schema/notifications.ts +1 -1
- package/src/memory/search/formatting.ts +23 -6
- package/src/memory/search/lexical.ts +2 -0
- package/src/memory/search/semantic.ts +2 -0
- package/src/memory/search/staleness.ts +5 -1
- package/src/memory/search/types.ts +4 -0
- package/src/memory/task-memory-cleanup.ts +96 -6
- package/src/memory/trace-event-store.ts +148 -0
- package/src/notifications/README.md +1 -1
- package/src/notifications/decision-engine.ts +45 -4
- package/src/notifications/emit-signal.ts +5 -4
- package/src/notifications/events-store.ts +4 -4
- package/src/notifications/signal.ts +1 -1
- package/src/oauth/manual-token-connection.ts +49 -25
- package/src/permissions/checker.ts +6 -5
- package/src/permissions/defaults.ts +4 -4
- package/src/prompts/__tests__/build-cli-reference-section.test.ts +9 -90
- package/src/prompts/cache-boundary.ts +8 -0
- package/src/prompts/system-prompt.ts +105 -634
- package/src/prompts/templates/BOOTSTRAP.md +172 -33
- package/src/prompts/templates/IDENTITY.md +8 -24
- package/src/prompts/templates/SOUL.md +20 -41
- package/src/prompts/templates/USER.md +3 -19
- package/src/prompts/user-reference.ts +14 -16
- package/src/providers/anthropic/client.ts +51 -19
- package/src/providers/gemini/client.ts +6 -9
- package/src/providers/managed-proxy/constants.ts +1 -7
- package/src/providers/managed-proxy/context.ts +0 -1
- package/src/providers/model-intents.ts +5 -5
- package/src/providers/openai/client.ts +10 -1
- package/src/providers/openrouter/client.ts +1 -0
- package/src/providers/ratelimit.ts +0 -35
- package/src/providers/registry.ts +3 -5
- package/src/providers/retry.ts +18 -1
- package/src/runtime/access-request-helper.ts +16 -2
- package/src/runtime/auth/route-policy.ts +7 -0
- package/src/runtime/channel-verification-service.ts +1 -1
- package/src/runtime/confirmation-request-guardian-bridge.ts +1 -1
- package/src/runtime/guardian-vellum-migration.ts +61 -1
- package/src/runtime/http-server.ts +8 -4
- package/src/runtime/migrations/vbundle-builder.ts +212 -32
- package/src/runtime/migrations/vbundle-import-analyzer.ts +74 -8
- package/src/runtime/migrations/vbundle-importer.ts +66 -1
- package/src/runtime/migrations/vbundle-validator.ts +17 -3
- package/src/runtime/routes/approval-strategies/guardian-callback-strategy.ts +4 -4
- package/src/runtime/routes/attachment-routes.ts +2 -2
- package/src/runtime/routes/btw-routes.ts +93 -0
- package/src/runtime/routes/channel-verification-routes.ts +19 -2
- package/src/runtime/routes/conversation-management-routes.ts +55 -1
- package/src/runtime/routes/conversation-query-routes.ts +1 -1
- package/src/runtime/routes/conversation-routes.ts +49 -5
- package/src/runtime/routes/conversation-starter-routes.ts +207 -0
- package/src/runtime/routes/guardian-bootstrap-routes.ts +13 -9
- package/src/runtime/routes/identity-intro-cache.ts +105 -0
- package/src/runtime/routes/identity-routes.ts +51 -0
- package/src/runtime/routes/inbound-stages/escalation-intercept.ts +1 -1
- package/src/runtime/routes/inbound-stages/verification-intercept.ts +1 -1
- package/src/runtime/routes/migration-routes.ts +25 -13
- package/src/runtime/routes/secret-routes.ts +18 -0
- package/src/runtime/routes/settings-routes.ts +9 -9
- package/src/runtime/routes/telemetry-routes.ts +53 -0
- package/src/runtime/routes/trace-event-routes.ts +62 -0
- package/src/runtime/tool-grant-request-helper.ts +1 -1
- package/src/runtime/verification-outbound-actions.ts +47 -31
- package/src/security/encrypted-store.ts +262 -78
- package/src/skills/catalog-install.ts +10 -0
- package/src/skills/managed-store.ts +2 -0
- package/src/skills/skill-memory.ts +222 -0
- package/src/subagent/manager.ts +1 -4
- package/src/telemetry/types.ts +10 -1
- package/src/telemetry/usage-telemetry-reporter.test.ts +7 -2
- package/src/telemetry/usage-telemetry-reporter.ts +53 -4
- package/src/tools/AGENTS.md +11 -11
- package/src/tools/acp/spawn.ts +1 -1
- package/src/tools/apps/executors.ts +8 -8
- package/src/tools/apps/registry.ts +1 -1
- package/src/tools/assets/materialize.ts +6 -6
- package/src/tools/assets/search.ts +10 -10
- package/src/tools/browser/__tests__/auth-cache.test.ts +2 -2
- package/src/tools/browser/__tests__/auth-detector.test.ts +4 -4
- package/src/tools/browser/auth-detector.ts +6 -6
- package/src/tools/browser/browser-execution.ts +13 -13
- package/src/tools/browser/browser-manager.ts +3 -3
- package/src/tools/browser/chrome-cdp.ts +5 -5
- package/src/tools/browser/jit-auth.ts +2 -2
- package/src/tools/browser/network-recorder.test.ts +2 -2
- package/src/tools/browser/network-recorder.ts +3 -3
- package/src/tools/browser/runtime-check.ts +3 -3
- package/src/tools/claude-code/claude-code.ts +2 -2
- package/src/tools/computer-use/definitions.ts +18 -18
- package/src/tools/credential-execution/make-authenticated-request.ts +4 -4
- package/src/tools/credential-execution/manage-secure-command-tool.ts +3 -3
- package/src/tools/credential-execution/run-authenticated-command.ts +4 -4
- package/src/tools/credentials/broker-types.ts +5 -5
- package/src/tools/credentials/broker.ts +15 -15
- package/src/tools/credentials/metadata-store.ts +2 -2
- package/src/tools/credentials/resolve.ts +1 -1
- package/src/tools/credentials/selection.ts +1 -1
- package/src/tools/credentials/tool-policy.ts +1 -1
- package/src/tools/credentials/vault.ts +115 -25
- package/src/tools/execution-target.ts +2 -2
- package/src/tools/executor.ts +7 -7
- package/src/tools/filesystem/edit.ts +2 -2
- package/src/tools/filesystem/read.ts +15 -4
- package/src/tools/filesystem/write.ts +1 -1
- package/src/tools/host-filesystem/edit.ts +2 -1
- package/src/tools/host-filesystem/read.ts +18 -1
- package/src/tools/host-filesystem/write.ts +1 -1
- package/src/tools/host-terminal/host-shell.ts +9 -8
- package/src/tools/mcp/mcp-tool-factory.ts +7 -6
- package/src/tools/memory/definitions.ts +6 -5
- package/src/tools/memory/handlers.test.ts +1 -1
- package/src/tools/network/__tests__/web-search.test.ts +3 -3
- package/src/tools/network/domain-normalize.ts +2 -2
- package/src/tools/network/script-proxy/session-manager.ts +10 -10
- package/src/tools/network/web-fetch.ts +1 -1
- package/src/tools/network/web-search.ts +3 -3
- package/src/tools/permission-checker.ts +8 -8
- package/src/tools/registry.ts +7 -7
- package/src/tools/schedule/list.ts +2 -2
- package/src/tools/schema-transforms.ts +31 -21
- package/src/tools/secret-detection-handler.ts +1 -1
- package/src/tools/sensitive-output-placeholders.ts +1 -1
- package/src/tools/shared/filesystem/edit-engine.ts +1 -1
- package/src/tools/shared/filesystem/file-ops-service.ts +3 -3
- package/src/tools/shared/filesystem/image-read.ts +25 -5
- package/src/tools/shared/filesystem/path-policy.ts +2 -2
- package/src/tools/shared/shell-output.ts +1 -1
- package/src/tools/side-effects.ts +1 -1
- package/src/tools/skills/execute.ts +1 -1
- package/src/tools/skills/load.ts +3 -3
- package/src/tools/skills/sandbox-runner.ts +3 -3
- package/src/tools/subagent/read.ts +1 -1
- package/src/tools/subagent/spawn.ts +2 -2
- package/src/tools/swarm/delegate.ts +3 -3
- package/src/tools/system/request-permission.ts +5 -4
- package/src/tools/terminal/backends/native.ts +4 -4
- package/src/tools/terminal/parser.ts +6 -6
- package/src/tools/terminal/sandbox-diagnostics.ts +1 -1
- package/src/tools/terminal/shell.ts +16 -16
- package/src/tools/tool-approval-handler.ts +21 -12
- package/src/tools/tool-manifest.ts +4 -4
- package/src/tools/types.ts +3 -3
- package/src/tools/ui-surface/definitions.ts +9 -37
- package/src/tools/watcher/list.ts +1 -1
- package/src/util/logger.ts +7 -2
- package/src/util/pricing.ts +4 -0
- package/src/util/retry.ts +29 -1
- package/src/workspace/migrations/007-web-search-provider-rename.ts +37 -0
- package/src/workspace/migrations/registry.ts +2 -0
- package/src/__tests__/cli-help-reference-sync.test.ts +0 -26
- package/src/__tests__/onboarding-starter-tasks.test.ts +0 -190
- package/src/cli/reference.ts +0 -38
- package/src/memory/job-handlers/capability-cards.ts +0 -420
- package/src/runtime/routes/thread-starter-routes.ts +0 -294
|
@@ -48,13 +48,14 @@ function toArrayBuffer(data: Uint8Array): ArrayBuffer {
|
|
|
48
48
|
const testDir = realpathSync(
|
|
49
49
|
mkdtempSync(join(tmpdir(), "migration-import-commit-http-test-")),
|
|
50
50
|
);
|
|
51
|
-
const testDbDir = join(testDir, "db");
|
|
51
|
+
const testDbDir = join(testDir, "data", "db");
|
|
52
52
|
const testDbPath = join(testDbDir, "assistant.db");
|
|
53
53
|
const testConfigPath = join(testDir, "config.json");
|
|
54
54
|
|
|
55
55
|
mock.module("../util/platform.js", () => ({
|
|
56
56
|
getRootDir: () => testDir,
|
|
57
|
-
getDataDir: () => testDir,
|
|
57
|
+
getDataDir: () => join(testDir, "data"),
|
|
58
|
+
getWorkspaceDir: () => testDir,
|
|
58
59
|
getWorkspaceConfigPath: () => testConfigPath,
|
|
59
60
|
isMacOS: () => process.platform === "darwin",
|
|
60
61
|
isLinux: () => process.platform === "linux",
|
|
@@ -78,9 +79,8 @@ mock.module("../config/loader.js", () => ({
|
|
|
78
79
|
model: "test",
|
|
79
80
|
provider: "test",
|
|
80
81
|
memory: { enabled: false },
|
|
81
|
-
rateLimit: { maxRequestsPerMinute: 0
|
|
82
|
+
rateLimit: { maxRequestsPerMinute: 0 },
|
|
82
83
|
secretDetection: { enabled: false },
|
|
83
|
-
sandbox: { enabled: false },
|
|
84
84
|
}),
|
|
85
85
|
}));
|
|
86
86
|
|
|
@@ -377,10 +377,13 @@ describe("handleMigrationImport", () => {
|
|
|
377
377
|
expect(writtenData).toEqual(newDbData);
|
|
378
378
|
});
|
|
379
379
|
|
|
380
|
-
test("
|
|
380
|
+
test("workspace is cleared before restore — files are created fresh", async () => {
|
|
381
|
+
// Only new-format bundles (workspace/ prefix) trigger workspace clearing.
|
|
382
|
+
// With clearing, existing files are removed before writing, so all files
|
|
383
|
+
// in the bundle are "created" (not "overwritten") and no backups are made.
|
|
381
384
|
const newDbData = new Uint8Array([0x01, 0x02, 0x03]);
|
|
382
385
|
const vbundle = createValidVBundle([
|
|
383
|
-
{ path: "data/db/assistant.db", data: newDbData },
|
|
386
|
+
{ path: "workspace/data/db/assistant.db", data: newDbData },
|
|
384
387
|
]);
|
|
385
388
|
const req = new Request("http://localhost/v1/migrations/import", {
|
|
386
389
|
method: "POST",
|
|
@@ -392,29 +395,22 @@ describe("handleMigrationImport", () => {
|
|
|
392
395
|
const body = (await res.json()) as ImportCommitResponse;
|
|
393
396
|
|
|
394
397
|
expect(body.success).toBe(true);
|
|
395
|
-
expect(body.summary.backups_created).
|
|
398
|
+
expect(body.summary.backups_created).toBe(0);
|
|
396
399
|
|
|
397
|
-
|
|
398
|
-
|
|
400
|
+
const dbFile = body.files.find(
|
|
401
|
+
(f) => f.path === "workspace/data/db/assistant.db",
|
|
402
|
+
);
|
|
399
403
|
expect(dbFile).toBeDefined();
|
|
400
|
-
expect(dbFile!.action).toBe("
|
|
401
|
-
expect(dbFile!.backup_path).not.toBeNull();
|
|
402
|
-
expect(existsSync(dbFile!.backup_path!)).toBe(true);
|
|
403
|
-
|
|
404
|
-
// Verify backup contains the original data
|
|
405
|
-
const backupData = new Uint8Array(readFileSync(dbFile!.backup_path!));
|
|
406
|
-
expect(backupData).toEqual(EXISTING_DB_DATA);
|
|
404
|
+
expect(dbFile!.action).toBe("created");
|
|
407
405
|
});
|
|
408
406
|
|
|
409
|
-
test("reports
|
|
410
|
-
//
|
|
411
|
-
rmSync(testConfigPath, { force: true });
|
|
412
|
-
|
|
407
|
+
test("reports all files as created after workspace clear", async () => {
|
|
408
|
+
// New-format workspace/ paths trigger clearing — both files are fresh.
|
|
413
409
|
const newDbData = new Uint8Array([0xaa, 0xbb]);
|
|
414
410
|
const newConfigData = new TextEncoder().encode('{"provider":"openai"}');
|
|
415
411
|
const vbundle = createValidVBundle([
|
|
416
|
-
{ path: "data/db/assistant.db", data: newDbData },
|
|
417
|
-
{ path: "config
|
|
412
|
+
{ path: "workspace/data/db/assistant.db", data: newDbData },
|
|
413
|
+
{ path: "workspace/config.json", data: newConfigData },
|
|
418
414
|
]);
|
|
419
415
|
const req = new Request("http://localhost/v1/migrations/import", {
|
|
420
416
|
method: "POST",
|
|
@@ -427,14 +423,16 @@ describe("handleMigrationImport", () => {
|
|
|
427
423
|
|
|
428
424
|
expect(body.success).toBe(true);
|
|
429
425
|
|
|
430
|
-
const dbFile = body.files.find(
|
|
426
|
+
const dbFile = body.files.find(
|
|
427
|
+
(f) => f.path === "workspace/data/db/assistant.db",
|
|
428
|
+
);
|
|
431
429
|
const configFile = body.files.find(
|
|
432
|
-
(f) => f.path === "config
|
|
430
|
+
(f) => f.path === "workspace/config.json",
|
|
433
431
|
);
|
|
434
432
|
|
|
435
|
-
|
|
433
|
+
// Both are "created" because workspace was cleared before writing
|
|
434
|
+
expect(dbFile!.action).toBe("created");
|
|
436
435
|
expect(configFile!.action).toBe("created");
|
|
437
|
-
expect(configFile!.backup_path).toBeNull();
|
|
438
436
|
});
|
|
439
437
|
|
|
440
438
|
test("summary counts match file details", async () => {
|
|
@@ -641,7 +639,7 @@ describe("commitImport", () => {
|
|
|
641
639
|
{ path: "data/db/assistant.db", data: newDbData },
|
|
642
640
|
]);
|
|
643
641
|
|
|
644
|
-
const resolver = new DefaultPathResolver(
|
|
642
|
+
const resolver = new DefaultPathResolver(undefined, testDir);
|
|
645
643
|
const result = commitImport({
|
|
646
644
|
archiveData: vbundle,
|
|
647
645
|
pathResolver: resolver,
|
|
@@ -655,7 +653,7 @@ describe("commitImport", () => {
|
|
|
655
653
|
});
|
|
656
654
|
|
|
657
655
|
test("returns validation_failed for invalid bundles", () => {
|
|
658
|
-
const resolver = new DefaultPathResolver(
|
|
656
|
+
const resolver = new DefaultPathResolver(undefined, testDir);
|
|
659
657
|
const result = commitImport({
|
|
660
658
|
archiveData: new Uint8Array([0xba, 0xad]),
|
|
661
659
|
pathResolver: resolver,
|
|
@@ -671,17 +669,16 @@ describe("commitImport", () => {
|
|
|
671
669
|
});
|
|
672
670
|
|
|
673
671
|
test("creates parent directories if they do not exist", () => {
|
|
674
|
-
// Use a
|
|
675
|
-
const
|
|
676
|
-
const
|
|
677
|
-
const newConfigPath = join(testDir, "new-config.json");
|
|
672
|
+
// Use a workspace that does not exist yet
|
|
673
|
+
const nonexistentWorkspace = join(testDir, "new-workspace");
|
|
674
|
+
const expectedDbPath = join(nonexistentWorkspace, "data", "db", "assistant.db");
|
|
678
675
|
|
|
679
676
|
const dbData = new Uint8Array([0x01, 0x02, 0x03]);
|
|
680
677
|
const vbundle = createValidVBundle([
|
|
681
678
|
{ path: "data/db/assistant.db", data: dbData },
|
|
682
679
|
]);
|
|
683
680
|
|
|
684
|
-
const resolver = new DefaultPathResolver(
|
|
681
|
+
const resolver = new DefaultPathResolver(undefined, nonexistentWorkspace);
|
|
685
682
|
const result = commitImport({
|
|
686
683
|
archiveData: vbundle,
|
|
687
684
|
pathResolver: resolver,
|
|
@@ -690,11 +687,11 @@ describe("commitImport", () => {
|
|
|
690
687
|
expect(result.ok).toBe(true);
|
|
691
688
|
if (result.ok) {
|
|
692
689
|
expect(result.report.files[0].action).toBe("created");
|
|
693
|
-
expect(existsSync(
|
|
690
|
+
expect(existsSync(expectedDbPath)).toBe(true);
|
|
694
691
|
}
|
|
695
692
|
|
|
696
693
|
// Clean up
|
|
697
|
-
rmSync(
|
|
694
|
+
rmSync(nonexistentWorkspace, { recursive: true, force: true });
|
|
698
695
|
});
|
|
699
696
|
|
|
700
697
|
test("post-write integrity: written file SHA-256 matches expected", () => {
|
|
@@ -705,7 +702,7 @@ describe("commitImport", () => {
|
|
|
705
702
|
{ path: "data/db/assistant.db", data: newDbData },
|
|
706
703
|
]);
|
|
707
704
|
|
|
708
|
-
const resolver = new DefaultPathResolver(
|
|
705
|
+
const resolver = new DefaultPathResolver(undefined, testDir);
|
|
709
706
|
const result = commitImport({
|
|
710
707
|
archiveData: vbundle,
|
|
711
708
|
pathResolver: resolver,
|
|
@@ -735,7 +732,7 @@ describe("commitImport", () => {
|
|
|
735
732
|
{ path: "config/settings.json", data: newConfigData },
|
|
736
733
|
]);
|
|
737
734
|
|
|
738
|
-
const resolver = new DefaultPathResolver(
|
|
735
|
+
const resolver = new DefaultPathResolver(undefined, testDir);
|
|
739
736
|
const result = commitImport({
|
|
740
737
|
archiveData: vbundle,
|
|
741
738
|
pathResolver: resolver,
|
|
@@ -755,6 +752,137 @@ describe("commitImport", () => {
|
|
|
755
752
|
});
|
|
756
753
|
});
|
|
757
754
|
|
|
755
|
+
// ---------------------------------------------------------------------------
|
|
756
|
+
// Workspace clearing tests
|
|
757
|
+
// ---------------------------------------------------------------------------
|
|
758
|
+
|
|
759
|
+
describe("commitImport — workspace clearing", () => {
|
|
760
|
+
const skillsDir = join(testDir, "skills");
|
|
761
|
+
const hooksDir = join(testDir, "hooks");
|
|
762
|
+
|
|
763
|
+
afterEach(() => {
|
|
764
|
+
// Restore test fixture files for subsequent tests
|
|
765
|
+
mkdirSync(testDbDir, { recursive: true });
|
|
766
|
+
writeFileSync(testDbPath, EXISTING_DB_DATA);
|
|
767
|
+
writeFileSync(testConfigPath, JSON.stringify(EXISTING_CONFIG, null, 2));
|
|
768
|
+
// Clean up skills/hooks dirs
|
|
769
|
+
for (const dir of [skillsDir, hooksDir]) {
|
|
770
|
+
if (existsSync(dir)) rmSync(dir, { recursive: true, force: true });
|
|
771
|
+
}
|
|
772
|
+
});
|
|
773
|
+
|
|
774
|
+
test("clears stale files via workspace clearing (new-format workspace/ entries)", () => {
|
|
775
|
+
mkdirSync(join(skillsDir, "stale-skill"), { recursive: true });
|
|
776
|
+
writeFileSync(join(skillsDir, "stale-skill", "SKILL.md"), "stale");
|
|
777
|
+
|
|
778
|
+
const skillData = new TextEncoder().encode("# New Skill");
|
|
779
|
+
const vbundle = createValidVBundle([
|
|
780
|
+
{ path: "workspace/skills/new-skill/SKILL.md", data: skillData },
|
|
781
|
+
]);
|
|
782
|
+
|
|
783
|
+
const resolver = new DefaultPathResolver(undefined, testDir);
|
|
784
|
+
const result = commitImport({
|
|
785
|
+
archiveData: vbundle,
|
|
786
|
+
pathResolver: resolver,
|
|
787
|
+
workspaceDir: testDir,
|
|
788
|
+
});
|
|
789
|
+
|
|
790
|
+
expect(result.ok).toBe(true);
|
|
791
|
+
if (!result.ok) return;
|
|
792
|
+
|
|
793
|
+
// New skill written
|
|
794
|
+
expect(existsSync(join(skillsDir, "new-skill", "SKILL.md"))).toBe(true);
|
|
795
|
+
expect(readFileSync(join(skillsDir, "new-skill", "SKILL.md"), "utf8")).toBe(
|
|
796
|
+
"# New Skill",
|
|
797
|
+
);
|
|
798
|
+
|
|
799
|
+
// Stale skill removed by workspace clearing
|
|
800
|
+
expect(existsSync(join(skillsDir, "stale-skill"))).toBe(false);
|
|
801
|
+
});
|
|
802
|
+
|
|
803
|
+
test("old-format skills/ entries do not trigger workspace clearing", () => {
|
|
804
|
+
mkdirSync(join(skillsDir, "stale-skill"), { recursive: true });
|
|
805
|
+
writeFileSync(join(skillsDir, "stale-skill", "SKILL.md"), "stale");
|
|
806
|
+
|
|
807
|
+
const skillData = new TextEncoder().encode("# New Skill");
|
|
808
|
+
const vbundle = createValidVBundle([
|
|
809
|
+
{ path: "skills/new-skill/SKILL.md", data: skillData },
|
|
810
|
+
]);
|
|
811
|
+
|
|
812
|
+
const resolver = new DefaultPathResolver(undefined, testDir);
|
|
813
|
+
const result = commitImport({
|
|
814
|
+
archiveData: vbundle,
|
|
815
|
+
pathResolver: resolver,
|
|
816
|
+
workspaceDir: testDir,
|
|
817
|
+
});
|
|
818
|
+
|
|
819
|
+
expect(result.ok).toBe(true);
|
|
820
|
+
if (!result.ok) return;
|
|
821
|
+
|
|
822
|
+
// New skill written
|
|
823
|
+
expect(existsSync(join(skillsDir, "new-skill", "SKILL.md"))).toBe(true);
|
|
824
|
+
|
|
825
|
+
// Stale skill survives — old-format bundles don't trigger workspace clearing
|
|
826
|
+
expect(existsSync(join(skillsDir, "stale-skill", "SKILL.md"))).toBe(true);
|
|
827
|
+
});
|
|
828
|
+
|
|
829
|
+
test("hooks/ entries import to hooksDir (not workspace/hooks/)", () => {
|
|
830
|
+
// Use a separate hooks dir outside the workspace, like production layout
|
|
831
|
+
const externalHooksDir = join(testDir, ".hooks-external");
|
|
832
|
+
mkdirSync(externalHooksDir, { recursive: true });
|
|
833
|
+
|
|
834
|
+
const hookData = new TextEncoder().encode("#!/bin/sh\necho new");
|
|
835
|
+
const vbundle = createValidVBundle([
|
|
836
|
+
{ path: "hooks/new-hook/hook.sh", data: hookData },
|
|
837
|
+
]);
|
|
838
|
+
|
|
839
|
+
const resolver = new DefaultPathResolver(undefined, testDir, externalHooksDir);
|
|
840
|
+
const result = commitImport({
|
|
841
|
+
archiveData: vbundle,
|
|
842
|
+
pathResolver: resolver,
|
|
843
|
+
workspaceDir: testDir,
|
|
844
|
+
});
|
|
845
|
+
|
|
846
|
+
expect(result.ok).toBe(true);
|
|
847
|
+
if (!result.ok) return;
|
|
848
|
+
|
|
849
|
+
// Hook written to the external hooks dir, not workspace/hooks/
|
|
850
|
+
expect(existsSync(join(externalHooksDir, "new-hook", "hook.sh"))).toBe(true);
|
|
851
|
+
expect(
|
|
852
|
+
readFileSync(join(externalHooksDir, "new-hook", "hook.sh"), "utf8"),
|
|
853
|
+
).toBe("#!/bin/sh\necho new");
|
|
854
|
+
|
|
855
|
+
// Cleanup
|
|
856
|
+
rmSync(externalHooksDir, { recursive: true, force: true });
|
|
857
|
+
});
|
|
858
|
+
|
|
859
|
+
test("without workspaceDir, no clearing happens", () => {
|
|
860
|
+
mkdirSync(join(skillsDir, "existing-skill"), { recursive: true });
|
|
861
|
+
writeFileSync(
|
|
862
|
+
join(skillsDir, "existing-skill", "SKILL.md"),
|
|
863
|
+
"should survive",
|
|
864
|
+
);
|
|
865
|
+
|
|
866
|
+
const vbundle = createValidVBundle([
|
|
867
|
+
{ path: "skills/new-skill/SKILL.md", data: new TextEncoder().encode("new") },
|
|
868
|
+
]);
|
|
869
|
+
|
|
870
|
+
const resolver = new DefaultPathResolver(undefined, testDir);
|
|
871
|
+
// No workspaceDir — no clearing
|
|
872
|
+
const result = commitImport({
|
|
873
|
+
archiveData: vbundle,
|
|
874
|
+
pathResolver: resolver,
|
|
875
|
+
});
|
|
876
|
+
|
|
877
|
+
expect(result.ok).toBe(true);
|
|
878
|
+
|
|
879
|
+
// Existing skill survives (no workspace clearing without workspaceDir)
|
|
880
|
+
expect(existsSync(join(skillsDir, "existing-skill", "SKILL.md"))).toBe(
|
|
881
|
+
true,
|
|
882
|
+
);
|
|
883
|
+
});
|
|
884
|
+
});
|
|
885
|
+
|
|
758
886
|
// ---------------------------------------------------------------------------
|
|
759
887
|
// Auth policy registration tests
|
|
760
888
|
// ---------------------------------------------------------------------------
|
|
@@ -34,13 +34,14 @@ function toArrayBuffer(data: Uint8Array): ArrayBuffer {
|
|
|
34
34
|
const testDir = realpathSync(
|
|
35
35
|
mkdtempSync(join(tmpdir(), "migration-import-preflight-http-test-")),
|
|
36
36
|
);
|
|
37
|
-
const testDbDir = join(testDir, "db");
|
|
37
|
+
const testDbDir = join(testDir, "data", "db");
|
|
38
38
|
const testDbPath = join(testDbDir, "assistant.db");
|
|
39
39
|
const testConfigPath = join(testDir, "config.json");
|
|
40
40
|
|
|
41
41
|
mock.module("../util/platform.js", () => ({
|
|
42
42
|
getRootDir: () => testDir,
|
|
43
|
-
getDataDir: () => testDir,
|
|
43
|
+
getDataDir: () => join(testDir, "data"),
|
|
44
|
+
getWorkspaceDir: () => testDir,
|
|
44
45
|
getWorkspaceConfigPath: () => testConfigPath,
|
|
45
46
|
isMacOS: () => process.platform === "darwin",
|
|
46
47
|
isLinux: () => process.platform === "linux",
|
|
@@ -64,9 +65,8 @@ mock.module("../config/loader.js", () => ({
|
|
|
64
65
|
model: "test",
|
|
65
66
|
provider: "test",
|
|
66
67
|
memory: { enabled: false },
|
|
67
|
-
rateLimit: { maxRequestsPerMinute: 0
|
|
68
|
+
rateLimit: { maxRequestsPerMinute: 0 },
|
|
68
69
|
secretDetection: { enabled: false },
|
|
69
|
-
sandbox: { enabled: false },
|
|
70
70
|
}),
|
|
71
71
|
}));
|
|
72
72
|
|
|
@@ -525,8 +525,8 @@ describe("handleMigrationImportPreflight — validation failures", () => {
|
|
|
525
525
|
describe("analyzeImport", () => {
|
|
526
526
|
test("detects create when file does not exist on disk", () => {
|
|
527
527
|
const resolver = new DefaultPathResolver(
|
|
528
|
-
|
|
529
|
-
join(testDir, "nonexistent-
|
|
528
|
+
undefined,
|
|
529
|
+
join(testDir, "nonexistent-workspace"),
|
|
530
530
|
);
|
|
531
531
|
|
|
532
532
|
const report = analyzeImport({
|
|
@@ -553,7 +553,7 @@ describe("analyzeImport", () => {
|
|
|
553
553
|
});
|
|
554
554
|
|
|
555
555
|
test("detects unchanged when file on disk matches bundle", () => {
|
|
556
|
-
const resolver = new DefaultPathResolver(
|
|
556
|
+
const resolver = new DefaultPathResolver(undefined, testDir);
|
|
557
557
|
|
|
558
558
|
const report = analyzeImport({
|
|
559
559
|
manifest: {
|
|
@@ -577,7 +577,7 @@ describe("analyzeImport", () => {
|
|
|
577
577
|
});
|
|
578
578
|
|
|
579
579
|
test("detects overwrite when file on disk differs from bundle", () => {
|
|
580
|
-
const resolver = new DefaultPathResolver(
|
|
580
|
+
const resolver = new DefaultPathResolver(undefined, testDir);
|
|
581
581
|
|
|
582
582
|
const report = analyzeImport({
|
|
583
583
|
manifest: {
|
|
@@ -602,7 +602,7 @@ describe("analyzeImport", () => {
|
|
|
602
602
|
});
|
|
603
603
|
|
|
604
604
|
test("flags unknown archive paths as conflicts with skip action", () => {
|
|
605
|
-
const resolver = new DefaultPathResolver(
|
|
605
|
+
const resolver = new DefaultPathResolver(undefined, testDir);
|
|
606
606
|
|
|
607
607
|
const report = analyzeImport({
|
|
608
608
|
manifest: {
|
|
@@ -640,7 +640,7 @@ describe("analyzeImport", () => {
|
|
|
640
640
|
});
|
|
641
641
|
|
|
642
642
|
test("includes manifest in report", () => {
|
|
643
|
-
const resolver = new DefaultPathResolver(
|
|
643
|
+
const resolver = new DefaultPathResolver(undefined, testDir);
|
|
644
644
|
const manifest = {
|
|
645
645
|
schema_version: "1.0",
|
|
646
646
|
created_at: "2024-01-01T00:00:00.000Z",
|
|
@@ -668,29 +668,90 @@ describe("analyzeImport", () => {
|
|
|
668
668
|
// ---------------------------------------------------------------------------
|
|
669
669
|
|
|
670
670
|
describe("DefaultPathResolver", () => {
|
|
671
|
-
test("resolves data/db/assistant.db to
|
|
671
|
+
test("resolves data/db/assistant.db to workspace db path (backward compat)", () => {
|
|
672
672
|
const resolver = new DefaultPathResolver(
|
|
673
|
-
|
|
674
|
-
"/
|
|
673
|
+
undefined,
|
|
674
|
+
"/home/user/.vellum/workspace",
|
|
675
|
+
);
|
|
676
|
+
expect(resolver.resolve("data/db/assistant.db")).toBe(
|
|
677
|
+
"/home/user/.vellum/workspace/data/db/assistant.db",
|
|
675
678
|
);
|
|
676
|
-
expect(resolver.resolve("data/db/assistant.db")).toBe("/some/db.db");
|
|
677
679
|
});
|
|
678
680
|
|
|
679
|
-
test("resolves config/settings.json to
|
|
681
|
+
test("resolves config/settings.json to workspace config path (backward compat)", () => {
|
|
680
682
|
const resolver = new DefaultPathResolver(
|
|
681
|
-
|
|
682
|
-
"/
|
|
683
|
+
undefined,
|
|
684
|
+
"/home/user/.vellum/workspace",
|
|
685
|
+
);
|
|
686
|
+
expect(resolver.resolve("config/settings.json")).toBe(
|
|
687
|
+
"/home/user/.vellum/workspace/config.json",
|
|
683
688
|
);
|
|
684
|
-
expect(resolver.resolve("config/settings.json")).toBe("/some/config.json");
|
|
685
689
|
});
|
|
686
690
|
|
|
687
691
|
test("returns null for unknown paths", () => {
|
|
688
692
|
const resolver = new DefaultPathResolver(
|
|
689
|
-
|
|
690
|
-
"/
|
|
693
|
+
undefined,
|
|
694
|
+
"/home/user/.vellum/workspace",
|
|
691
695
|
);
|
|
692
696
|
expect(resolver.resolve("unknown/path.txt")).toBeNull();
|
|
693
697
|
});
|
|
698
|
+
|
|
699
|
+
test("resolves valid skills path via backward compat", () => {
|
|
700
|
+
const resolver = new DefaultPathResolver(
|
|
701
|
+
undefined,
|
|
702
|
+
"/home/user/.vellum/workspace",
|
|
703
|
+
);
|
|
704
|
+
expect(resolver.resolve("skills/my-skill/SKILL.md")).toBe(
|
|
705
|
+
"/home/user/.vellum/workspace/skills/my-skill/SKILL.md",
|
|
706
|
+
);
|
|
707
|
+
});
|
|
708
|
+
|
|
709
|
+
test("resolves workspace/ prefix paths", () => {
|
|
710
|
+
const resolver = new DefaultPathResolver(
|
|
711
|
+
undefined,
|
|
712
|
+
"/home/user/.vellum/workspace",
|
|
713
|
+
);
|
|
714
|
+
expect(resolver.resolve("workspace/data/db/assistant.db")).toBe(
|
|
715
|
+
"/home/user/.vellum/workspace/data/db/assistant.db",
|
|
716
|
+
);
|
|
717
|
+
expect(resolver.resolve("workspace/config.json")).toBe(
|
|
718
|
+
"/home/user/.vellum/workspace/config.json",
|
|
719
|
+
);
|
|
720
|
+
expect(resolver.resolve("workspace/skills/my-skill/SKILL.md")).toBe(
|
|
721
|
+
"/home/user/.vellum/workspace/skills/my-skill/SKILL.md",
|
|
722
|
+
);
|
|
723
|
+
});
|
|
724
|
+
|
|
725
|
+
test("returns null for workspace/ path traversal attempt", () => {
|
|
726
|
+
const resolver = new DefaultPathResolver(
|
|
727
|
+
undefined,
|
|
728
|
+
"/home/user/.vellum/workspace",
|
|
729
|
+
);
|
|
730
|
+
expect(resolver.resolve("workspace/../../etc/passwd")).toBeNull();
|
|
731
|
+
});
|
|
732
|
+
|
|
733
|
+
test("returns null for skills path traversal attempt (../../etc/passwd)", () => {
|
|
734
|
+
const resolver = new DefaultPathResolver(
|
|
735
|
+
undefined,
|
|
736
|
+
"/home/user/.vellum/workspace",
|
|
737
|
+
);
|
|
738
|
+
expect(resolver.resolve("skills/../../etc/passwd")).toBeNull();
|
|
739
|
+
});
|
|
740
|
+
|
|
741
|
+
test("returns null for skills path traversal attempt (../../../.ssh/authorized_keys)", () => {
|
|
742
|
+
const resolver = new DefaultPathResolver(
|
|
743
|
+
undefined,
|
|
744
|
+
"/home/user/.vellum/workspace",
|
|
745
|
+
);
|
|
746
|
+
expect(
|
|
747
|
+
resolver.resolve("skills/../../../.ssh/authorized_keys"),
|
|
748
|
+
).toBeNull();
|
|
749
|
+
});
|
|
750
|
+
|
|
751
|
+
test("returns null for skills paths when workspaceDir is not provided", () => {
|
|
752
|
+
const resolver = new DefaultPathResolver();
|
|
753
|
+
expect(resolver.resolve("skills/my-skill/SKILL.md")).toBeNull();
|
|
754
|
+
});
|
|
694
755
|
});
|
|
695
756
|
|
|
696
757
|
// ---------------------------------------------------------------------------
|
|
@@ -53,9 +53,8 @@ mock.module("../config/loader.js", () => ({
|
|
|
53
53
|
model: "test",
|
|
54
54
|
provider: "test",
|
|
55
55
|
memory: { enabled: false },
|
|
56
|
-
rateLimit: { maxRequestsPerMinute: 0
|
|
56
|
+
rateLimit: { maxRequestsPerMinute: 0 },
|
|
57
57
|
secretDetection: { enabled: false },
|
|
58
|
-
sandbox: { enabled: false },
|
|
59
58
|
}),
|
|
60
59
|
}));
|
|
61
60
|
|
|
@@ -307,26 +306,27 @@ describe("validateVBundle", () => {
|
|
|
307
306
|
expect(manifestError).toBeDefined();
|
|
308
307
|
});
|
|
309
308
|
|
|
310
|
-
test("
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
);
|
|
309
|
+
test("bundle with only manifest (no data files) is structurally valid", () => {
|
|
310
|
+
// After the workspace walk refactor, only manifest.json is required.
|
|
311
|
+
// But the manifest checksum must match for full validity.
|
|
312
|
+
const manifestWithoutChecksum = {
|
|
313
|
+
schema_version: "1.0",
|
|
314
|
+
created_at: new Date().toISOString(),
|
|
315
|
+
files: [],
|
|
316
|
+
};
|
|
317
|
+
const manifestSha256 = sha256Hex(canonicalizeJson(manifestWithoutChecksum));
|
|
318
|
+
const manifest = {
|
|
319
|
+
...manifestWithoutChecksum,
|
|
320
|
+
manifest_sha256: manifestSha256,
|
|
321
|
+
};
|
|
322
|
+
const manifestData = new TextEncoder().encode(JSON.stringify(manifest));
|
|
319
323
|
const tar = createTarArchive([
|
|
320
324
|
{ name: "manifest.json", data: manifestData },
|
|
321
325
|
]);
|
|
322
326
|
const vbundle = gzipSync(tar);
|
|
323
327
|
const result = validateVBundle(vbundle);
|
|
324
328
|
|
|
325
|
-
expect(result.is_valid).toBe(
|
|
326
|
-
const dbError = result.errors.find(
|
|
327
|
-
(e) => e.code === "MISSING_ENTRY" && e.path === "data/db/assistant.db",
|
|
328
|
-
);
|
|
329
|
-
expect(dbError).toBeDefined();
|
|
329
|
+
expect(result.is_valid).toBe(true);
|
|
330
330
|
});
|
|
331
331
|
|
|
332
332
|
test("invalid manifest JSON returns INVALID_MANIFEST_JSON error", () => {
|
|
@@ -62,10 +62,10 @@ describe("model intents", () => {
|
|
|
62
62
|
"claude-opus-4-6",
|
|
63
63
|
);
|
|
64
64
|
expect(resolveModelIntent("anthropic", "vision-optimized")).toBe(
|
|
65
|
-
"claude-
|
|
65
|
+
"claude-opus-4-6",
|
|
66
66
|
);
|
|
67
67
|
expect(resolveModelIntent("openai", "latency-optimized")).toBe(
|
|
68
|
-
"gpt-
|
|
68
|
+
"gpt-5.4-nano",
|
|
69
69
|
);
|
|
70
70
|
});
|
|
71
71
|
|
|
@@ -5,7 +5,7 @@ import { describe, expect, test } from "bun:test";
|
|
|
5
5
|
/**
|
|
6
6
|
* Guard test: domain-specific routing sections must NOT appear in the system
|
|
7
7
|
* prompt source file. Routing cues now live in skill frontmatter
|
|
8
|
-
* (`activation-hints` / `avoid-when`) and are projected into
|
|
8
|
+
* (`activation-hints` / `avoid-when`) and are projected into the skills catalog.
|
|
9
9
|
*
|
|
10
10
|
* If this test fails, you are re-introducing hardcoded routing into the system
|
|
11
11
|
* prompt. Instead, add `activation-hints` to the skill's SKILL.md frontmatter.
|
|
@@ -623,7 +623,7 @@ describe("access-request-helper unit tests", () => {
|
|
|
623
623
|
expect(telegram!.status).toBe("sent");
|
|
624
624
|
});
|
|
625
625
|
|
|
626
|
-
test("notifyGuardianOfAccessRequest
|
|
626
|
+
test("notifyGuardianOfAccessRequest skips vellum fallback for same-channel-only routing (telegram)", async () => {
|
|
627
627
|
mockEmitResult = {
|
|
628
628
|
signalId: "sig-no-vellum",
|
|
629
629
|
deduplicated: false,
|
|
@@ -657,8 +657,8 @@ describe("access-request-helper unit tests", () => {
|
|
|
657
657
|
(d) => d.destinationChannel === "telegram",
|
|
658
658
|
);
|
|
659
659
|
|
|
660
|
-
|
|
661
|
-
expect(vellum
|
|
660
|
+
// Same-channel routing skips vellum delivery entirely — no fallback record
|
|
661
|
+
expect(vellum).toBeUndefined();
|
|
662
662
|
expect(telegram).toBeDefined();
|
|
663
663
|
expect(telegram!.destinationChatId).toBe("guardian-chat-456");
|
|
664
664
|
expect(telegram!.status).toBe("sent");
|
|
@@ -115,7 +115,7 @@ function makeSignal(
|
|
|
115
115
|
signalId: "sig-broadcast-001",
|
|
116
116
|
createdAt: Date.now(),
|
|
117
117
|
sourceChannel: "scheduler",
|
|
118
|
-
|
|
118
|
+
sourceContextId: "sess-001",
|
|
119
119
|
sourceEventName: "test.event",
|
|
120
120
|
contextPayload: {},
|
|
121
121
|
attentionHints: {
|
|
@@ -65,7 +65,7 @@ function makeSignal(
|
|
|
65
65
|
signalId: "sig-fallback-guardian-1",
|
|
66
66
|
createdAt: Date.now(),
|
|
67
67
|
sourceChannel: "phone",
|
|
68
|
-
|
|
68
|
+
sourceContextId: "call-session-1",
|
|
69
69
|
sourceEventName: "guardian.question",
|
|
70
70
|
contextPayload: {
|
|
71
71
|
questionText: "What is the gate code?",
|
|
@@ -308,7 +308,7 @@ describe("access-request instruction enforcement", () => {
|
|
|
308
308
|
signalId: "sig-access-req-1",
|
|
309
309
|
createdAt: Date.now(),
|
|
310
310
|
sourceChannel: "telegram",
|
|
311
|
-
|
|
311
|
+
sourceContextId: "tg-session-1",
|
|
312
312
|
sourceEventName: "ingress.access_request",
|
|
313
313
|
contextPayload: {
|
|
314
314
|
senderIdentifier: "Alice",
|
|
@@ -45,7 +45,9 @@ mock.module("../prompts/system-prompt.js", () => ({
|
|
|
45
45
|
|
|
46
46
|
// ── Provider mock with system prompt capture ──────────────────────────
|
|
47
47
|
|
|
48
|
-
let configuredProvider: {
|
|
48
|
+
let configuredProvider: {
|
|
49
|
+
sendMessage: (...args: unknown[]) => Promise<unknown>;
|
|
50
|
+
} | null = null;
|
|
49
51
|
let extractedToolUse: unknown = null;
|
|
50
52
|
let capturedSystemPrompt: string | undefined;
|
|
51
53
|
|
|
@@ -81,7 +83,7 @@ function makeSignal(
|
|
|
81
83
|
signalId: "sig-identity-test-1",
|
|
82
84
|
createdAt: Date.now(),
|
|
83
85
|
sourceChannel: "phone",
|
|
84
|
-
|
|
86
|
+
sourceContextId: "call-session-1",
|
|
85
87
|
sourceEventName: "guardian.question",
|
|
86
88
|
contextPayload: {
|
|
87
89
|
questionText: "What is the gate code?",
|
|
@@ -141,9 +143,7 @@ describe("identity context in notification decision engine", () => {
|
|
|
141
143
|
|
|
142
144
|
expect(capturedSystemPrompt).toBeDefined();
|
|
143
145
|
expect(capturedSystemPrompt).toContain("<assistant-identity>");
|
|
144
|
-
expect(capturedSystemPrompt).toContain(
|
|
145
|
-
"I am Jarvis, a helpful assistant",
|
|
146
|
-
);
|
|
146
|
+
expect(capturedSystemPrompt).toContain("I am Jarvis, a helpful assistant");
|
|
147
147
|
expect(capturedSystemPrompt).toContain("</assistant-identity>");
|
|
148
148
|
});
|
|
149
149
|
|
|
@@ -192,10 +192,9 @@ describe("identity context in notification decision engine", () => {
|
|
|
192
192
|
configuredProvider = null;
|
|
193
193
|
|
|
194
194
|
const signal = makeSignal();
|
|
195
|
-
const decision = await evaluateSignal(
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
);
|
|
195
|
+
const decision = await evaluateSignal(signal, [
|
|
196
|
+
"vellum",
|
|
197
|
+
] as NotificationChannel[]);
|
|
199
198
|
|
|
200
199
|
// Fallback should produce valid copy regardless of identity context
|
|
201
200
|
expect(decision.fallbackUsed).toBe(true);
|