@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
|
@@ -67,8 +67,8 @@ import { and, eq } from "drizzle-orm";
|
|
|
67
67
|
import { DEFAULT_CONFIG } from "../config/defaults.js";
|
|
68
68
|
import { vectorToBlob } from "../memory/job-utils.js";
|
|
69
69
|
|
|
70
|
-
// Disable LLM extraction in tests to avoid real API calls
|
|
71
|
-
// deterministic pattern-based extraction.
|
|
70
|
+
// Disable LLM extraction and summarization in tests to avoid real API calls
|
|
71
|
+
// and ensure deterministic pattern-based extraction / fallback summaries.
|
|
72
72
|
const TEST_CONFIG = {
|
|
73
73
|
...DEFAULT_CONFIG,
|
|
74
74
|
memory: {
|
|
@@ -77,6 +77,10 @@ const TEST_CONFIG = {
|
|
|
77
77
|
...DEFAULT_CONFIG.memory.extraction,
|
|
78
78
|
useLLM: false,
|
|
79
79
|
},
|
|
80
|
+
summarization: {
|
|
81
|
+
...DEFAULT_CONFIG.memory.summarization,
|
|
82
|
+
useLLM: false,
|
|
83
|
+
},
|
|
80
84
|
},
|
|
81
85
|
};
|
|
82
86
|
|
|
@@ -86,6 +90,7 @@ mock.module("../config/loader.js", () => ({
|
|
|
86
90
|
invalidateConfigCache: () => {},
|
|
87
91
|
}));
|
|
88
92
|
import { estimateTextTokens } from "../context/token-estimator.js";
|
|
93
|
+
import { stripUserTextBlocksByPrefix } from "../daemon/conversation-runtime-assembly.js";
|
|
89
94
|
import {
|
|
90
95
|
getMemorySystemStatus,
|
|
91
96
|
requestMemoryBackfill,
|
|
@@ -120,8 +125,7 @@ import {
|
|
|
120
125
|
escapeXmlTags,
|
|
121
126
|
formatAbsoluteTime,
|
|
122
127
|
formatRelativeTime,
|
|
123
|
-
|
|
124
|
-
stripMemoryRecallMessages,
|
|
128
|
+
injectMemoryRecallAsUserBlock,
|
|
125
129
|
} from "../memory/retriever.js";
|
|
126
130
|
import {
|
|
127
131
|
conversations,
|
|
@@ -133,6 +137,7 @@ import {
|
|
|
133
137
|
messages,
|
|
134
138
|
} from "../memory/schema.js";
|
|
135
139
|
import { buildCoreIdentityContext } from "../prompts/system-prompt.js";
|
|
140
|
+
import type { Message } from "../providers/types.js";
|
|
136
141
|
|
|
137
142
|
describe("Memory regressions", () => {
|
|
138
143
|
beforeAll(() => {
|
|
@@ -308,133 +313,124 @@ describe("Memory regressions", () => {
|
|
|
308
313
|
expect(recall.enabled).toBe(true);
|
|
309
314
|
});
|
|
310
315
|
|
|
311
|
-
test("memory recall injection
|
|
316
|
+
test("memory recall injection as user block and stripped from runtime history", () => {
|
|
312
317
|
const memoryRecallText =
|
|
313
|
-
"<memory_context>\n\n<relevant_context>\nuser prefers concise answers\n</relevant_context>\n\n</memory_context>";
|
|
314
|
-
const originalMessages = [
|
|
318
|
+
"<memory_context __injected>\n\n<relevant_context>\nuser prefers concise answers\n</relevant_context>\n\n</memory_context>";
|
|
319
|
+
const originalMessages: Message[] = [
|
|
315
320
|
{
|
|
316
|
-
role: "user"
|
|
317
|
-
content: [{ type: "text", text: "Actual user request" }],
|
|
321
|
+
role: "user",
|
|
322
|
+
content: [{ type: "text" as const, text: "Actual user request" }],
|
|
318
323
|
},
|
|
319
324
|
];
|
|
320
|
-
const injected =
|
|
325
|
+
const injected = injectMemoryRecallAsUserBlock(
|
|
321
326
|
originalMessages,
|
|
322
327
|
memoryRecallText,
|
|
323
328
|
);
|
|
324
329
|
|
|
325
|
-
|
|
330
|
+
// Memory context prepended to last user message as content block
|
|
331
|
+
expect(injected).toHaveLength(1);
|
|
326
332
|
expect(injected[0].role).toBe("user");
|
|
327
|
-
expect(injected[0].content
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
expect(
|
|
331
|
-
|
|
332
|
-
|
|
333
|
+
expect(injected[0].content).toHaveLength(2);
|
|
334
|
+
const b0 = injected[0].content[0];
|
|
335
|
+
const b1 = injected[0].content[1];
|
|
336
|
+
expect(b0.type === "text" && b0.text).toBe(memoryRecallText);
|
|
337
|
+
expect(b1.type === "text" && b1.text).toBe("Actual user request");
|
|
338
|
+
|
|
339
|
+
// Stripped by prefix-based stripping
|
|
340
|
+
const cleaned = stripUserTextBlocksByPrefix(injected, [
|
|
341
|
+
"<memory_context __injected>",
|
|
342
|
+
]);
|
|
333
343
|
expect(cleaned).toHaveLength(1);
|
|
334
|
-
expect(cleaned[0].content
|
|
344
|
+
expect(cleaned[0].content).toHaveLength(1);
|
|
345
|
+
const cb0 = cleaned[0].content[0];
|
|
346
|
+
expect(cb0.type === "text" && cb0.text).toBe("Actual user request");
|
|
335
347
|
});
|
|
336
348
|
|
|
337
|
-
test("
|
|
349
|
+
test("prefix-based stripping removes all <memory_context> blocks from merged content", () => {
|
|
338
350
|
const memoryRecallText =
|
|
339
|
-
"
|
|
340
|
-
// Simulate deep-repair merging
|
|
341
|
-
//
|
|
342
|
-
const mergedUserMessage = {
|
|
343
|
-
role: "user"
|
|
351
|
+
"<memory_context __injected>\n\n<relevant_context>\nuser prefers concise answers\n</relevant_context>\n\n</memory_context>";
|
|
352
|
+
// Simulate deep-repair merging where multiple memory context blocks exist.
|
|
353
|
+
// Prefix-based stripping removes all blocks starting with <memory_context __injected>.
|
|
354
|
+
const mergedUserMessage: Message = {
|
|
355
|
+
role: "user",
|
|
344
356
|
content: [
|
|
345
|
-
{ type: "text", text: memoryRecallText },
|
|
346
|
-
{ type: "text", text: "Earlier user request" },
|
|
347
|
-
{ type: "text", text: memoryRecallText },
|
|
348
|
-
{ type: "text", text: "Latest user request" },
|
|
357
|
+
{ type: "text" as const, text: memoryRecallText },
|
|
358
|
+
{ type: "text" as const, text: "Earlier user request" },
|
|
359
|
+
{ type: "text" as const, text: memoryRecallText },
|
|
360
|
+
{ type: "text" as const, text: "Latest user request" },
|
|
349
361
|
],
|
|
350
362
|
};
|
|
351
363
|
|
|
352
|
-
const cleaned =
|
|
364
|
+
const cleaned = stripUserTextBlocksByPrefix(
|
|
353
365
|
[mergedUserMessage],
|
|
354
|
-
|
|
366
|
+
["<memory_context __injected>"],
|
|
355
367
|
);
|
|
356
368
|
expect(cleaned).toHaveLength(1);
|
|
357
|
-
// The last (active) recall block should be stripped, the first (leaked) one preserved
|
|
358
369
|
expect(cleaned[0].content).toEqual([
|
|
359
|
-
{ type: "text", text: memoryRecallText },
|
|
360
370
|
{ type: "text", text: "Earlier user request" },
|
|
361
371
|
{ type: "text", text: "Latest user request" },
|
|
362
372
|
]);
|
|
363
373
|
});
|
|
364
374
|
|
|
365
|
-
test("
|
|
366
|
-
const history = [
|
|
367
|
-
{ role: "user"
|
|
368
|
-
{ role: "assistant"
|
|
375
|
+
test("injectMemoryRecallAsUserBlock prepends memory to last user message", () => {
|
|
376
|
+
const history: Message[] = [
|
|
377
|
+
{ role: "user", content: [{ type: "text" as const, text: "Hello" }] },
|
|
378
|
+
{ role: "assistant", content: [{ type: "text" as const, text: "Hi!" }] },
|
|
369
379
|
{
|
|
370
|
-
role: "user"
|
|
371
|
-
content: [{ type: "text", text: "Tell me about X" }],
|
|
380
|
+
role: "user",
|
|
381
|
+
content: [{ type: "text" as const, text: "Tell me about X" }],
|
|
372
382
|
},
|
|
373
383
|
];
|
|
374
|
-
const recallText =
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
384
|
+
const recallText =
|
|
385
|
+
"<memory_context __injected>\n\n<relevant_context>\nSome recalled fact\n</relevant_context>\n\n</memory_context>";
|
|
386
|
+
const result = injectMemoryRecallAsUserBlock(history, recallText);
|
|
387
|
+
// Same number of messages — no synthetic pair
|
|
388
|
+
expect(result).toHaveLength(3);
|
|
378
389
|
expect(result[0]).toBe(history[0]);
|
|
379
390
|
expect(result[1]).toBe(history[1]);
|
|
380
|
-
//
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
expect(
|
|
385
|
-
expect(result[3].content).toEqual([
|
|
386
|
-
{ type: "text", text: "[Memory context loaded.]" },
|
|
387
|
-
]);
|
|
388
|
-
// Original user message preserved unchanged
|
|
389
|
-
expect(result[4]).toBe(history[2]);
|
|
391
|
+
// Last user message has memory prepended
|
|
392
|
+
const r0 = result[2].content[0];
|
|
393
|
+
const r1 = result[2].content[1];
|
|
394
|
+
expect(r0.type === "text" && r0.text).toBe(recallText);
|
|
395
|
+
expect(r1.type === "text" && r1.text).toBe("Tell me about X");
|
|
390
396
|
});
|
|
391
397
|
|
|
392
|
-
test("
|
|
393
|
-
const history = [
|
|
394
|
-
{ role: "user"
|
|
398
|
+
test("injectMemoryRecallAsUserBlock with empty text is a no-op", () => {
|
|
399
|
+
const history: Message[] = [
|
|
400
|
+
{ role: "user", content: [{ type: "text" as const, text: "Hello" }] },
|
|
395
401
|
];
|
|
396
|
-
const result =
|
|
402
|
+
const result = injectMemoryRecallAsUserBlock(history, " ");
|
|
397
403
|
expect(result).toBe(history);
|
|
398
404
|
});
|
|
399
405
|
|
|
400
|
-
test("
|
|
401
|
-
const recallText =
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
{ role: "
|
|
405
|
-
// Injected context message pair
|
|
406
|
-
{ role: "user" as const, content: [{ type: "text", text: recallText }] },
|
|
406
|
+
test("stripUserTextBlocksByPrefix removes memory_context block from user message", () => {
|
|
407
|
+
const recallText =
|
|
408
|
+
"<memory_context __injected>\n\n<relevant_context>\nSome recalled fact\n</relevant_context>\n\n</memory_context>";
|
|
409
|
+
const msgs: Message[] = [
|
|
410
|
+
{ role: "user", content: [{ type: "text" as const, text: "Hello" }] },
|
|
407
411
|
{
|
|
408
|
-
role: "assistant"
|
|
409
|
-
content: [{ type: "text", text: "
|
|
410
|
-
},
|
|
411
|
-
// Real user message
|
|
412
|
-
{
|
|
413
|
-
role: "user" as const,
|
|
414
|
-
content: [{ type: "text", text: "Tell me about X" }],
|
|
412
|
+
role: "assistant",
|
|
413
|
+
content: [{ type: "text" as const, text: "Hi!" }],
|
|
415
414
|
},
|
|
416
|
-
];
|
|
417
|
-
const cleaned = stripMemoryRecallMessages(messages, recallText);
|
|
418
|
-
expect(cleaned).toHaveLength(3);
|
|
419
|
-
expect(cleaned[0].content[0].text).toBe("Hello");
|
|
420
|
-
expect(cleaned[1].content[0].text).toBe("Hi!");
|
|
421
|
-
expect(cleaned[2].content[0].text).toBe("Tell me about X");
|
|
422
|
-
});
|
|
423
|
-
|
|
424
|
-
test("stripMemoryRecallMessages falls back to prepend_user_block when no separate pair found", () => {
|
|
425
|
-
const recallText = "<memory>Fact</memory>";
|
|
426
|
-
const messages = [
|
|
427
415
|
{
|
|
428
|
-
role: "user"
|
|
416
|
+
role: "user",
|
|
429
417
|
content: [
|
|
430
|
-
{ type: "text", text: recallText },
|
|
431
|
-
{ type: "text", text: "
|
|
418
|
+
{ type: "text" as const, text: recallText },
|
|
419
|
+
{ type: "text" as const, text: "Tell me about X" },
|
|
432
420
|
],
|
|
433
421
|
},
|
|
434
422
|
];
|
|
435
|
-
const cleaned =
|
|
436
|
-
|
|
437
|
-
|
|
423
|
+
const cleaned = stripUserTextBlocksByPrefix(msgs, [
|
|
424
|
+
"<memory_context __injected>",
|
|
425
|
+
]);
|
|
426
|
+
expect(cleaned).toHaveLength(3);
|
|
427
|
+
const c0 = cleaned[0].content[0];
|
|
428
|
+
const c1 = cleaned[1].content[0];
|
|
429
|
+
const c2 = cleaned[2].content[0];
|
|
430
|
+
expect(c0.type === "text" && c0.text).toBe("Hello");
|
|
431
|
+
expect(c1.type === "text" && c1.text).toBe("Hi!");
|
|
432
|
+
expect(cleaned[2].content).toHaveLength(1);
|
|
433
|
+
expect(c2.type === "text" && c2.text).toBe("Tell me about X");
|
|
438
434
|
});
|
|
439
435
|
|
|
440
436
|
test("aborting memory recall embedding returns a non-degraded aborted recall result", async () => {
|
|
@@ -1819,7 +1815,7 @@ describe("Memory regressions", () => {
|
|
|
1819
1815
|
totalOutputTokens: 0,
|
|
1820
1816
|
totalEstimatedCost: 0,
|
|
1821
1817
|
contextSummary: null,
|
|
1822
|
-
contextCompactedMessageCount:
|
|
1818
|
+
contextCompactedMessageCount: 1,
|
|
1823
1819
|
contextCompactedAt: null,
|
|
1824
1820
|
})
|
|
1825
1821
|
.run();
|
|
@@ -2064,7 +2060,7 @@ describe("Memory regressions", () => {
|
|
|
2064
2060
|
totalOutputTokens: 0,
|
|
2065
2061
|
totalEstimatedCost: 0,
|
|
2066
2062
|
contextSummary: null,
|
|
2067
|
-
contextCompactedMessageCount:
|
|
2063
|
+
contextCompactedMessageCount: 1,
|
|
2068
2064
|
contextCompactedAt: null,
|
|
2069
2065
|
})
|
|
2070
2066
|
.run();
|
|
@@ -2138,7 +2134,7 @@ describe("Memory regressions", () => {
|
|
|
2138
2134
|
totalOutputTokens: 0,
|
|
2139
2135
|
totalEstimatedCost: 0,
|
|
2140
2136
|
contextSummary: null,
|
|
2141
|
-
contextCompactedMessageCount:
|
|
2137
|
+
contextCompactedMessageCount: 1,
|
|
2142
2138
|
contextCompactedAt: null,
|
|
2143
2139
|
})
|
|
2144
2140
|
.run();
|
|
@@ -53,13 +53,14 @@ function toArrayBuffer(data: Uint8Array): ArrayBuffer {
|
|
|
53
53
|
const testDir = realpathSync(
|
|
54
54
|
mkdtempSync(join(tmpdir(), "migration-cross-version-test-")),
|
|
55
55
|
);
|
|
56
|
-
const testDbDir = join(testDir, "db");
|
|
56
|
+
const testDbDir = join(testDir, "data", "db");
|
|
57
57
|
const testDbPath = join(testDbDir, "assistant.db");
|
|
58
58
|
const testConfigPath = join(testDir, "config.json");
|
|
59
59
|
|
|
60
60
|
mock.module("../util/platform.js", () => ({
|
|
61
61
|
getRootDir: () => testDir,
|
|
62
|
-
getDataDir: () => testDir,
|
|
62
|
+
getDataDir: () => join(testDir, "data"),
|
|
63
|
+
getWorkspaceDir: () => testDir,
|
|
63
64
|
getWorkspaceConfigPath: () => testConfigPath,
|
|
64
65
|
isMacOS: () => process.platform === "darwin",
|
|
65
66
|
isLinux: () => process.platform === "linux",
|
|
@@ -83,9 +84,8 @@ mock.module("../config/loader.js", () => ({
|
|
|
83
84
|
model: "test",
|
|
84
85
|
provider: "test",
|
|
85
86
|
memory: { enabled: false },
|
|
86
|
-
rateLimit: { maxRequestsPerMinute: 0
|
|
87
|
+
rateLimit: { maxRequestsPerMinute: 0 },
|
|
87
88
|
secretDetection: { enabled: false },
|
|
88
|
-
sandbox: { enabled: false },
|
|
89
89
|
}),
|
|
90
90
|
}));
|
|
91
91
|
|
|
@@ -445,7 +445,7 @@ describe("schema version compatibility", () => {
|
|
|
445
445
|
{ schema_version: "3.0" },
|
|
446
446
|
);
|
|
447
447
|
|
|
448
|
-
const resolver = new DefaultPathResolver(
|
|
448
|
+
const resolver = new DefaultPathResolver(undefined, testDir);
|
|
449
449
|
const result = commitImport({
|
|
450
450
|
archiveData: vbundle,
|
|
451
451
|
pathResolver: resolver,
|
|
@@ -463,7 +463,7 @@ describe("schema version compatibility", () => {
|
|
|
463
463
|
schema_version: "5.0-beta",
|
|
464
464
|
});
|
|
465
465
|
|
|
466
|
-
const resolver = new DefaultPathResolver(
|
|
466
|
+
const resolver = new DefaultPathResolver(undefined, testDir);
|
|
467
467
|
const validationResult = validateVBundle(vbundle);
|
|
468
468
|
expect(validationResult.manifest).toBeDefined();
|
|
469
469
|
|
|
@@ -774,9 +774,10 @@ describe("round-trip: export -> validate -> preflight -> import", () => {
|
|
|
774
774
|
expect(preflightBody.files).toBeDefined();
|
|
775
775
|
expect(preflightBody.manifest).toBeDefined();
|
|
776
776
|
|
|
777
|
-
// The files should show "unchanged" since we exported from the same disk
|
|
777
|
+
// The files should show "unchanged" since we exported from the same disk.
|
|
778
|
+
// New format uses workspace/ prefix for archive paths.
|
|
778
779
|
const dbFile = preflightBody.files!.find(
|
|
779
|
-
(f) => f.path === "data/db/assistant.db",
|
|
780
|
+
(f) => f.path === "workspace/data/db/assistant.db",
|
|
780
781
|
);
|
|
781
782
|
expect(dbFile).toBeDefined();
|
|
782
783
|
expect(dbFile!.action).toBe("unchanged");
|
|
@@ -829,7 +830,7 @@ describe("round-trip: export -> validate -> preflight -> import", () => {
|
|
|
829
830
|
);
|
|
830
831
|
|
|
831
832
|
// Step 3: Analyze (preflight)
|
|
832
|
-
const resolver = new DefaultPathResolver(
|
|
833
|
+
const resolver = new DefaultPathResolver(undefined, testDir);
|
|
833
834
|
const report = analyzeImport({
|
|
834
835
|
manifest: validationResult.manifest!,
|
|
835
836
|
pathResolver: resolver,
|
|
@@ -888,13 +889,14 @@ describe("partial failure scenarios", () => {
|
|
|
888
889
|
{ path: "data/db/assistant.db", data: newDbData },
|
|
889
890
|
]);
|
|
890
891
|
|
|
891
|
-
// Point to a path
|
|
892
|
-
//
|
|
893
|
-
const
|
|
894
|
-
|
|
895
|
-
|
|
892
|
+
// Point to a workspace path where data/db cannot be created
|
|
893
|
+
// (a regular file blocks directory creation)
|
|
894
|
+
const blockerWorkspace = join(testDir, "blocker-workspace");
|
|
895
|
+
mkdirSync(blockerWorkspace, { recursive: true });
|
|
896
|
+
// Create "data" as a regular file — mkdirSync("data/db") will fail
|
|
897
|
+
writeFileSync(join(blockerWorkspace, "data"), "I am a file, not a directory");
|
|
896
898
|
|
|
897
|
-
const resolver = new DefaultPathResolver(
|
|
899
|
+
const resolver = new DefaultPathResolver(undefined, blockerWorkspace);
|
|
898
900
|
const result = commitImport({
|
|
899
901
|
archiveData: vbundle,
|
|
900
902
|
pathResolver: resolver,
|
|
@@ -908,11 +910,11 @@ describe("partial failure scenarios", () => {
|
|
|
908
910
|
}
|
|
909
911
|
|
|
910
912
|
// Clean up
|
|
911
|
-
rmSync(
|
|
913
|
+
rmSync(blockerWorkspace, { recursive: true, force: true });
|
|
912
914
|
});
|
|
913
915
|
|
|
914
916
|
test("commitImport with invalid archive returns validation_failed", () => {
|
|
915
|
-
const resolver = new DefaultPathResolver(
|
|
917
|
+
const resolver = new DefaultPathResolver(undefined, testDir);
|
|
916
918
|
const result = commitImport({
|
|
917
919
|
archiveData: new Uint8Array([0xba, 0xad, 0xf0, 0x0d]),
|
|
918
920
|
pathResolver: resolver,
|
|
@@ -1000,7 +1002,7 @@ describe("partial failure scenarios", () => {
|
|
|
1000
1002
|
]);
|
|
1001
1003
|
const corruptVBundle = gzipSync(tar);
|
|
1002
1004
|
|
|
1003
|
-
const resolver = new DefaultPathResolver(
|
|
1005
|
+
const resolver = new DefaultPathResolver(undefined, testDir);
|
|
1004
1006
|
const result = commitImport({
|
|
1005
1007
|
archiveData: corruptVBundle,
|
|
1006
1008
|
pathResolver: resolver,
|
|
@@ -1032,7 +1034,7 @@ describe("edge cases", () => {
|
|
|
1032
1034
|
expect(result.manifest?.files[0].size).toBe(0);
|
|
1033
1035
|
|
|
1034
1036
|
// Import should also succeed
|
|
1035
|
-
const resolver = new DefaultPathResolver(
|
|
1037
|
+
const resolver = new DefaultPathResolver(undefined, testDir);
|
|
1036
1038
|
const importResult = commitImport({
|
|
1037
1039
|
archiveData: vbundle,
|
|
1038
1040
|
pathResolver: resolver,
|
|
@@ -1186,7 +1188,10 @@ describe("edge cases", () => {
|
|
|
1186
1188
|
expect(missingError!.message).toContain("data/extra/ghost.bin");
|
|
1187
1189
|
});
|
|
1188
1190
|
|
|
1189
|
-
test("bundle with only manifest (no
|
|
1191
|
+
test("bundle with only manifest (no data files) is valid", () => {
|
|
1192
|
+
// After the workspace walk refactor, only manifest.json is required.
|
|
1193
|
+
// A bundle with no data files is structurally valid — it just won't
|
|
1194
|
+
// restore anything meaningful.
|
|
1190
1195
|
const manifestWithoutChecksum = {
|
|
1191
1196
|
schema_version: "1.0",
|
|
1192
1197
|
created_at: new Date().toISOString(),
|
|
@@ -1205,12 +1210,7 @@ describe("edge cases", () => {
|
|
|
1205
1210
|
const vbundle = gzipSync(tar);
|
|
1206
1211
|
const result = validateVBundle(vbundle);
|
|
1207
1212
|
|
|
1208
|
-
expect(result.is_valid).toBe(
|
|
1209
|
-
expect(
|
|
1210
|
-
result.errors.some(
|
|
1211
|
-
(e) => e.code === "MISSING_ENTRY" && e.path === "data/db/assistant.db",
|
|
1212
|
-
),
|
|
1213
|
-
).toBe(true);
|
|
1213
|
+
expect(result.is_valid).toBe(true);
|
|
1214
1214
|
});
|
|
1215
1215
|
|
|
1216
1216
|
test("completely empty gzip content (no tar entries) fails gracefully", () => {
|
|
@@ -1424,7 +1424,7 @@ describe("diagnostic quality", () => {
|
|
|
1424
1424
|
});
|
|
1425
1425
|
|
|
1426
1426
|
test("import commit validation_failed response includes error codes and messages", () => {
|
|
1427
|
-
const resolver = new DefaultPathResolver(
|
|
1427
|
+
const resolver = new DefaultPathResolver(undefined, testDir);
|
|
1428
1428
|
const result = commitImport({
|
|
1429
1429
|
archiveData: new Uint8Array([0x00]),
|
|
1430
1430
|
pathResolver: resolver,
|
|
@@ -1633,7 +1633,7 @@ describe("builder -> validator consistency", () => {
|
|
|
1633
1633
|
|
|
1634
1634
|
describe("import analyzer edge cases", () => {
|
|
1635
1635
|
test("all-unchanged files produce correct summary", () => {
|
|
1636
|
-
const resolver = new DefaultPathResolver(
|
|
1636
|
+
const resolver = new DefaultPathResolver(undefined, testDir);
|
|
1637
1637
|
const existingConfig = new Uint8Array(readFileSync(testConfigPath));
|
|
1638
1638
|
|
|
1639
1639
|
const report = analyzeImport({
|
|
@@ -1666,8 +1666,8 @@ describe("import analyzer edge cases", () => {
|
|
|
1666
1666
|
|
|
1667
1667
|
test("all-create scenario (fresh install) produces correct summary", () => {
|
|
1668
1668
|
const resolver = new DefaultPathResolver(
|
|
1669
|
-
|
|
1670
|
-
join(testDir, "nonexistent-
|
|
1669
|
+
undefined,
|
|
1670
|
+
join(testDir, "nonexistent-workspace"),
|
|
1671
1671
|
);
|
|
1672
1672
|
|
|
1673
1673
|
const report = analyzeImport({
|
|
@@ -1698,7 +1698,7 @@ describe("import analyzer edge cases", () => {
|
|
|
1698
1698
|
});
|
|
1699
1699
|
|
|
1700
1700
|
test("mixed create/overwrite/unchanged produces accurate counts", () => {
|
|
1701
|
-
const resolver = new DefaultPathResolver(
|
|
1701
|
+
const resolver = new DefaultPathResolver(undefined, testDir);
|
|
1702
1702
|
|
|
1703
1703
|
// db: different from disk -> overwrite
|
|
1704
1704
|
// config: same as disk -> unchanged
|
|
@@ -1731,7 +1731,7 @@ describe("import analyzer edge cases", () => {
|
|
|
1731
1731
|
});
|
|
1732
1732
|
|
|
1733
1733
|
test("unknown archive path produces UNKNOWN_ARCHIVE_PATH conflict", () => {
|
|
1734
|
-
const resolver = new DefaultPathResolver(
|
|
1734
|
+
const resolver = new DefaultPathResolver(undefined, testDir);
|
|
1735
1735
|
|
|
1736
1736
|
const report = analyzeImport({
|
|
1737
1737
|
manifest: {
|
|
@@ -27,13 +27,14 @@ import { afterAll, beforeAll, describe, expect, mock, test } from "bun:test";
|
|
|
27
27
|
const testDir = realpathSync(
|
|
28
28
|
mkdtempSync(join(tmpdir(), "migration-export-http-test-")),
|
|
29
29
|
);
|
|
30
|
-
const testDbDir = join(testDir, "db");
|
|
30
|
+
const testDbDir = join(testDir, "data", "db");
|
|
31
31
|
const testDbPath = join(testDbDir, "assistant.db");
|
|
32
32
|
const testConfigPath = join(testDir, "config.json");
|
|
33
33
|
|
|
34
34
|
mock.module("../util/platform.js", () => ({
|
|
35
35
|
getRootDir: () => testDir,
|
|
36
|
-
getDataDir: () => testDir,
|
|
36
|
+
getDataDir: () => join(testDir, "data"),
|
|
37
|
+
getWorkspaceDir: () => testDir,
|
|
37
38
|
getWorkspaceConfigPath: () => testConfigPath,
|
|
38
39
|
isMacOS: () => process.platform === "darwin",
|
|
39
40
|
isLinux: () => process.platform === "linux",
|
|
@@ -57,9 +58,8 @@ mock.module("../config/loader.js", () => ({
|
|
|
57
58
|
model: "test",
|
|
58
59
|
provider: "test",
|
|
59
60
|
memory: { enabled: false },
|
|
60
|
-
rateLimit: { maxRequestsPerMinute: 0
|
|
61
|
+
rateLimit: { maxRequestsPerMinute: 0 },
|
|
61
62
|
secretDetection: { enabled: false },
|
|
62
|
-
sandbox: { enabled: false },
|
|
63
63
|
}),
|
|
64
64
|
}));
|
|
65
65
|
|
|
@@ -206,10 +206,10 @@ describe("handleMigrationExport", () => {
|
|
|
206
206
|
expect(manifest.created_at).toBeDefined();
|
|
207
207
|
expect(manifest.manifest_sha256).toBeDefined();
|
|
208
208
|
|
|
209
|
-
// Verify file entries
|
|
209
|
+
// Verify file entries — workspace walk uses workspace/ prefix
|
|
210
210
|
const filePaths = manifest.files.map((f) => f.path);
|
|
211
|
-
expect(filePaths).toContain("data/db/assistant.db");
|
|
212
|
-
expect(filePaths).toContain("config
|
|
211
|
+
expect(filePaths).toContain("workspace/data/db/assistant.db");
|
|
212
|
+
expect(filePaths).toContain("workspace/config.json");
|
|
213
213
|
|
|
214
214
|
// Verify each file entry has proper sha256 and size
|
|
215
215
|
for (const file of manifest.files) {
|
|
@@ -299,7 +299,7 @@ describe("export data population", () => {
|
|
|
299
299
|
const archiveData = new Uint8Array(await res.arrayBuffer());
|
|
300
300
|
const entries = parseTarEntries(archiveData);
|
|
301
301
|
|
|
302
|
-
const dbEntry = entries.find((e) => e.name === "data/db/assistant.db");
|
|
302
|
+
const dbEntry = entries.find((e) => e.name === "workspace/data/db/assistant.db");
|
|
303
303
|
expect(dbEntry).toBeDefined();
|
|
304
304
|
expect(dbEntry!.data.length).toBe(SQLITE_HEADER.length);
|
|
305
305
|
// Verify the exported data matches the test fixture exactly
|
|
@@ -315,7 +315,7 @@ describe("export data population", () => {
|
|
|
315
315
|
const archiveData = new Uint8Array(await res.arrayBuffer());
|
|
316
316
|
const entries = parseTarEntries(archiveData);
|
|
317
317
|
|
|
318
|
-
const configEntry = entries.find((e) => e.name === "config
|
|
318
|
+
const configEntry = entries.find((e) => e.name === "workspace/config.json");
|
|
319
319
|
expect(configEntry).toBeDefined();
|
|
320
320
|
|
|
321
321
|
const configContent = new TextDecoder().decode(configEntry!.data);
|
|
@@ -336,13 +336,13 @@ describe("export data population", () => {
|
|
|
336
336
|
const manifest = validationResult.manifest!;
|
|
337
337
|
|
|
338
338
|
const dbFile = manifest.files.find(
|
|
339
|
-
(f) => f.path === "data/db/assistant.db",
|
|
339
|
+
(f) => f.path === "workspace/data/db/assistant.db",
|
|
340
340
|
);
|
|
341
341
|
expect(dbFile).toBeDefined();
|
|
342
342
|
expect(dbFile!.size).toBe(SQLITE_HEADER.length);
|
|
343
343
|
|
|
344
344
|
const configFile = manifest.files.find(
|
|
345
|
-
(f) => f.path === "config
|
|
345
|
+
(f) => f.path === "workspace/config.json",
|
|
346
346
|
);
|
|
347
347
|
expect(configFile).toBeDefined();
|
|
348
348
|
const expectedConfigSize = Buffer.byteLength(
|
|
@@ -382,7 +382,7 @@ describe("export data population", () => {
|
|
|
382
382
|
const manifest = validationResult.manifest!;
|
|
383
383
|
|
|
384
384
|
const dbFile = manifest.files.find(
|
|
385
|
-
(f) => f.path === "data/db/assistant.db",
|
|
385
|
+
(f) => f.path === "workspace/data/db/assistant.db",
|
|
386
386
|
);
|
|
387
387
|
expect(dbFile).toBeDefined();
|
|
388
388
|
// The skeleton used size 0 — real export should have actual content
|
|
@@ -398,7 +398,7 @@ describe("export data population", () => {
|
|
|
398
398
|
const archiveData = new Uint8Array(await res.arrayBuffer());
|
|
399
399
|
const entries = parseTarEntries(archiveData);
|
|
400
400
|
|
|
401
|
-
const configEntry = entries.find((e) => e.name === "config
|
|
401
|
+
const configEntry = entries.find((e) => e.name === "workspace/config.json");
|
|
402
402
|
expect(configEntry).toBeDefined();
|
|
403
403
|
|
|
404
404
|
const configContent = new TextDecoder().decode(configEntry!.data);
|
|
@@ -413,42 +413,41 @@ describe("export data population", () => {
|
|
|
413
413
|
// ---------------------------------------------------------------------------
|
|
414
414
|
|
|
415
415
|
describe("export graceful fallback", () => {
|
|
416
|
-
test("
|
|
416
|
+
test("nonexistent workspace produces valid archive with no files", async () => {
|
|
417
417
|
const { buildExportVBundle } =
|
|
418
418
|
await import("../runtime/migrations/vbundle-builder.js");
|
|
419
419
|
|
|
420
420
|
const result = buildExportVBundle({
|
|
421
|
-
|
|
422
|
-
configPath: testConfigPath,
|
|
421
|
+
workspaceDir: join(testDir, "nonexistent-workspace"),
|
|
423
422
|
});
|
|
424
423
|
|
|
425
424
|
const validationResult = validateVBundle(result.archive);
|
|
426
425
|
expect(validationResult.is_valid).toBe(true);
|
|
427
|
-
|
|
428
|
-
const dbFile = result.manifest.files.find(
|
|
429
|
-
(f) => f.path === "data/db/assistant.db",
|
|
430
|
-
);
|
|
431
|
-
expect(dbFile).toBeDefined();
|
|
432
|
-
expect(dbFile!.size).toBe(0);
|
|
426
|
+
expect(result.manifest.files).toHaveLength(0);
|
|
433
427
|
});
|
|
434
428
|
|
|
435
|
-
test("
|
|
429
|
+
test("workspace walk includes db and config under workspace/ prefix", async () => {
|
|
436
430
|
const { buildExportVBundle } =
|
|
437
431
|
await import("../runtime/migrations/vbundle-builder.js");
|
|
438
432
|
|
|
439
433
|
const result = buildExportVBundle({
|
|
440
|
-
|
|
441
|
-
configPath: join(testDir, "nonexistent-config.json"),
|
|
434
|
+
workspaceDir: testDir,
|
|
442
435
|
});
|
|
443
436
|
|
|
444
437
|
const validationResult = validateVBundle(result.archive);
|
|
445
438
|
expect(validationResult.is_valid).toBe(true);
|
|
446
439
|
|
|
440
|
+
const dbFile = result.manifest.files.find(
|
|
441
|
+
(f) => f.path === "workspace/data/db/assistant.db",
|
|
442
|
+
);
|
|
443
|
+
expect(dbFile).toBeDefined();
|
|
444
|
+
expect(dbFile!.size).toBeGreaterThan(0);
|
|
445
|
+
|
|
447
446
|
const configFile = result.manifest.files.find(
|
|
448
|
-
(f) => f.path === "config
|
|
447
|
+
(f) => f.path === "workspace/config.json",
|
|
449
448
|
);
|
|
450
449
|
expect(configFile).toBeDefined();
|
|
451
|
-
expect(configFile!.size).
|
|
450
|
+
expect(configFile!.size).toBeGreaterThan(0);
|
|
452
451
|
});
|
|
453
452
|
});
|
|
454
453
|
|