@vellumai/assistant 0.8.3 → 0.8.5
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 +2 -2
- package/docker-entrypoint.sh +0 -1
- package/docs/browser-use-architecture-phase2.md +1 -1
- package/knip.json +2 -1
- package/node_modules/@vellumai/gateway-client/src/types.ts +2 -0
- package/openapi.yaml +1492 -100
- package/package.json +1 -1
- package/src/__tests__/agent-loop-exit-reason.test.ts +4 -5
- package/src/__tests__/agent-loop-override-profile.test.ts +1 -1
- package/src/__tests__/agent-loop.test.ts +88 -3
- package/src/__tests__/anthropic-provider.test.ts +302 -33
- package/src/__tests__/approval-cascade.test.ts +1 -1
- package/src/__tests__/assistant-event-hub-self-exclusion.test.ts +293 -0
- package/src/__tests__/assistant-feature-flags-integration.test.ts +3 -3
- package/src/__tests__/audit-log-rotation.test.ts +70 -16
- package/src/__tests__/background-workers-disk-pressure.test.ts +4 -3
- package/src/__tests__/btw-routes.test.ts +2 -3
- package/src/__tests__/call-controller.test.ts +0 -1
- package/src/__tests__/cancel-resolves-conversation-key.test.ts +1 -1
- package/src/__tests__/channel-delivery-store.test.ts +193 -0
- package/src/__tests__/channel-guardian.test.ts +3 -3
- package/src/__tests__/channel-reply-delivery.test.ts +284 -5
- package/src/__tests__/channel-retry-sweep.test.ts +274 -1
- package/src/__tests__/checker.test.ts +6 -15
- package/src/__tests__/compaction-events.test.ts +2 -1
- package/src/__tests__/compactor-call-site-logging.test.ts +214 -0
- package/src/__tests__/compactor-preserved-tail-count.test.ts +110 -0
- package/src/__tests__/computer-use-skill-manifest-regression.test.ts +5 -11
- package/src/__tests__/computer-use-tools.test.ts +2 -4
- package/src/__tests__/config-watcher.test.ts +1 -1
- package/src/__tests__/confirmation-request-guardian-bridge.test.ts +0 -1
- package/src/__tests__/context-token-estimator.test.ts +91 -1
- package/src/__tests__/conversation-abort-tool-results.test.ts +1 -1
- package/src/__tests__/conversation-agent-loop-disk-pressure.test.ts +1 -1
- package/src/__tests__/conversation-agent-loop-inference-profile.test.ts +55 -4
- package/src/__tests__/conversation-agent-loop-overflow.test.ts +228 -8
- package/src/__tests__/conversation-agent-loop.test.ts +188 -129
- package/src/__tests__/conversation-app-control-instantiation.test.ts +2 -5
- package/src/__tests__/conversation-app-control-lifecycle.test.ts +1 -1
- package/src/__tests__/conversation-clean-command.test.ts +137 -0
- package/src/__tests__/conversation-clear-safety.test.ts +25 -25
- package/src/__tests__/conversation-confirmation-signals.test.ts +1 -1
- package/src/__tests__/conversation-delete-schedule-cleanup.test.ts +1 -1
- package/src/__tests__/conversation-disk-view-integration.test.ts +2 -2
- package/src/__tests__/conversation-error.test.ts +31 -0
- package/src/__tests__/conversation-fork-crud.test.ts +324 -0
- package/src/__tests__/conversation-lifecycle.test.ts +53 -12
- package/src/__tests__/conversation-load-history-repair.test.ts +1 -1
- package/src/__tests__/conversation-load-history-stripped.test.ts +279 -0
- package/src/__tests__/conversation-pairing.test.ts +2 -2
- package/src/__tests__/conversation-process-callsite.test.ts +1 -1
- package/src/__tests__/conversation-provider-retry-repair.test.ts +2 -1
- package/src/__tests__/conversation-queue.test.ts +1 -1
- package/src/__tests__/conversation-routes-disk-view.test.ts +109 -0
- package/src/__tests__/conversation-routes-slash-commands.test.ts +35 -0
- package/src/__tests__/conversation-runtime-assembly.test.ts +264 -81
- package/src/__tests__/conversation-seed-composer.test.ts +66 -4
- package/src/__tests__/conversation-skill-tools.test.ts +2 -5
- package/src/__tests__/conversation-slash-commands.test.ts +36 -8
- package/src/__tests__/conversation-slash-queue.test.ts +1 -1
- package/src/__tests__/conversation-slash-unknown.test.ts +1 -1
- package/src/__tests__/conversation-speed-override.test.ts +1 -1
- package/src/__tests__/conversation-store.test.ts +1 -1
- package/src/__tests__/conversation-surfaces-task-progress.test.ts +220 -0
- package/src/__tests__/conversation-sync-tags.test.ts +99 -32
- package/src/__tests__/conversation-workspace-cache-state.test.ts +2 -1
- package/src/__tests__/conversation-workspace-injection.test.ts +5 -1
- package/src/__tests__/conversation-workspace-tool-tracking.test.ts +5 -1
- package/src/__tests__/credential-execution-feature-gates.test.ts +9 -7
- package/src/__tests__/credential-execution-tools.test.ts +6 -6
- package/src/__tests__/credential-security-invariants.test.ts +7 -0
- package/src/__tests__/credential-vault-unit.test.ts +2 -2
- package/src/__tests__/cu-unified-flow.test.ts +10 -1
- package/src/__tests__/dm-backfill.test.ts +64 -0
- package/src/__tests__/dm-persistence.test.ts +33 -0
- package/src/__tests__/document-find-replace.test.ts +501 -0
- package/src/__tests__/dynamic-page-surface.test.ts +2 -2
- package/src/__tests__/email-html-renderer.test.ts +12 -0
- package/src/__tests__/first-greeting.test.ts +23 -2
- package/src/__tests__/gateway-flag-listener.test.ts +237 -0
- package/src/__tests__/gemini-provider.test.ts +78 -0
- package/src/__tests__/guardian-dispatch.test.ts +0 -1
- package/src/__tests__/guardian-outbound-http.test.ts +7 -5
- package/src/__tests__/handlers-user-message-approval-consumption.test.ts +1 -1
- package/src/__tests__/headless-browser-navigate.test.ts +172 -0
- package/src/__tests__/heartbeat-disk-pressure.test.ts +4 -0
- package/src/__tests__/heartbeat-service.test.ts +4 -0
- package/src/__tests__/host-bash-proxy.test.ts +6 -0
- package/src/__tests__/host-browser-proxy.test.ts +10 -0
- package/src/__tests__/host-cu-proxy.test.ts +8 -1
- package/src/__tests__/host-file-proxy.test.ts +8 -1
- package/src/__tests__/host-shell-tool.test.ts +1 -1
- package/src/__tests__/host-transfer-proxy.test.ts +8 -1
- package/src/__tests__/identity-routes.test.ts +57 -0
- package/src/__tests__/inbound-slack-persistence.test.ts +3 -0
- package/src/__tests__/init-feature-flag-overrides.test.ts +5 -6
- package/src/__tests__/injector-chain.test.ts +2 -0
- package/src/__tests__/injector-document-comments.test.ts +378 -0
- package/src/__tests__/injector-pkb-v2-silenced.test.ts +4 -25
- package/src/__tests__/list-messages-attachments.test.ts +21 -17
- package/src/__tests__/list-messages-hidden-metadata.test.ts +217 -0
- package/src/__tests__/list-messages-page-latest.test.ts +130 -14
- package/src/__tests__/list-messages-tool-merge.test.ts +77 -17
- package/src/__tests__/llm-context-normalization.test.ts +0 -2
- package/src/__tests__/llm-request-log-call-site.test.ts +136 -0
- package/src/__tests__/llm-request-log-source-clickhouse.test.ts +26 -0
- package/src/__tests__/llm-resolver.test.ts +161 -9
- package/src/__tests__/llm-usage-store.test.ts +66 -0
- package/src/__tests__/log-export-routes.test.ts +99 -2
- package/src/__tests__/logger.test.ts +89 -0
- package/src/__tests__/mcp-abort-signal.test.ts +2 -2
- package/src/__tests__/media-generate-image.test.ts +31 -0
- package/src/__tests__/memory-v2-static-injector.test.ts +7 -7
- package/src/__tests__/message-queue-steer.test.ts +114 -0
- package/src/__tests__/model-intents.test.ts +2 -4
- package/src/__tests__/notification-guardian-path.test.ts +0 -1
- package/src/__tests__/onboarding-template-contract.test.ts +1 -1
- package/src/__tests__/openai-provider.test.ts +151 -0
- package/src/__tests__/openai-responses-provider.test.ts +118 -16
- package/src/__tests__/outbound-slack-persistence.test.ts +187 -20
- package/src/__tests__/pending-interactions-resolved-event.test.ts +189 -0
- package/src/__tests__/platform-bash-auto-approve.test.ts +2 -2
- package/src/__tests__/platform.test.ts +2 -5
- package/src/__tests__/plugin-api-tool-definition.test.ts +92 -0
- package/src/__tests__/plugin-bootstrap.test.ts +2 -2
- package/src/__tests__/plugin-source-watcher.test.ts +302 -0
- package/src/__tests__/plugin-tool-contribution.test.ts +13 -6
- package/src/__tests__/plugin-types.test.ts +3 -2
- package/src/__tests__/prechat-onboarding-contract.test.ts +131 -98
- package/src/__tests__/pricing.test.ts +12 -0
- package/src/__tests__/process-message-background-slack.test.ts +1 -51
- package/src/__tests__/process-message-display-content.test.ts +21 -16
- package/src/__tests__/prune-jobs-changes-parser.test.ts +61 -0
- package/src/__tests__/registry.test.ts +2 -8
- package/src/__tests__/require-fresh-approval.test.ts +2 -2
- package/src/__tests__/runtime-events-sse-bilingual.test.ts +154 -0
- package/src/__tests__/server-history-render.test.ts +83 -4
- package/src/__tests__/shell-tool-proxy-mode.test.ts +1 -1
- package/src/__tests__/skill-feature-flags.test.ts +2 -2
- package/src/__tests__/skill-projection-feature-flag.test.ts +4 -7
- package/src/__tests__/skill-projection.benchmark.test.ts +2 -6
- package/src/__tests__/skill-tool-factory.test.ts +1 -1
- package/src/__tests__/steer-tool-repair.test.ts +249 -0
- package/src/__tests__/subagent-notify-parent.test.ts +1 -1
- package/src/__tests__/suggestion-routes.test.ts +1 -0
- package/src/__tests__/sync-message-contract.test.ts +59 -0
- package/src/__tests__/system-prompt.test.ts +161 -124
- package/src/__tests__/terminal-tools.test.ts +12 -2
- package/src/__tests__/thinking-block-replay.test.ts +113 -0
- package/src/__tests__/thread-backfill.test.ts +370 -22
- package/src/__tests__/tool-approval-handler.test.ts +1 -5
- package/src/__tests__/tool-execute-pipeline.test.ts +2 -2
- package/src/__tests__/tool-execution-pipeline.benchmark.test.ts +2 -5
- package/src/__tests__/tool-executor-lifecycle-events.test.ts +15 -5
- package/src/__tests__/tool-executor.test.ts +89 -53
- package/src/__tests__/tool-grant-request-escalation.test.ts +1 -6
- package/src/__tests__/tool-result-metadata-plumbing.test.ts +167 -0
- package/src/__tests__/trusted-contact-approval-notifier.test.ts +0 -1
- package/src/__tests__/trusted-contact-inline-approval-integration.test.ts +1 -6
- package/src/__tests__/trusted-contact-multichannel.test.ts +0 -1
- package/src/__tests__/twilio-routes.test.ts +1 -1
- package/src/__tests__/ui-file-upload-surface.test.ts +2 -2
- package/src/__tests__/usage-routes.test.ts +3 -0
- package/src/__tests__/verification-control-plane-policy.test.ts +2 -2
- package/src/__tests__/web-fetch.test.ts +2 -2
- package/src/__tests__/workspace-git-service.test.ts +94 -10
- package/src/__tests__/workspace-migration-088-deprecate-background-conversation-override.test.ts +158 -0
- package/src/__tests__/workspace-migration-089-move-memory-tree-out-of-v3.test.ts +86 -0
- package/src/acp/__tests__/prepare-agent-env.test.ts +146 -0
- package/src/acp/prepare-agent-env.ts +78 -0
- package/src/acp/session-manager.ts +1 -1
- package/src/agent/attachments.ts +1 -0
- package/src/agent/loop.ts +65 -20
- package/src/api/README.md +5 -0
- package/src/api/index.ts +4 -0
- package/src/api/package.json +10 -0
- package/src/background-wake/background-wake-routes.test.ts +233 -0
- package/src/background-wake/next-wake.test.ts +289 -0
- package/src/background-wake/next-wake.ts +172 -0
- package/src/background-wake/runtime-registry.ts +24 -0
- package/src/browser/operations.ts +15 -0
- package/src/cli/commands/__tests__/browser.test.ts +23 -5
- package/src/cli/commands/__tests__/conversations-slack.test.ts +572 -0
- package/src/cli/commands/__tests__/domain-register.test.ts +110 -0
- package/src/cli/commands/__tests__/domain-status.test.ts +33 -33
- package/src/cli/commands/__tests__/inference-send.test.ts +108 -5
- package/src/cli/commands/__tests__/memory-v2-compare-render.test.ts +98 -0
- package/src/cli/commands/__tests__/memory-v2.test.ts +10 -12
- package/src/cli/commands/__tests__/memory-v3-render.test.ts +340 -0
- package/src/cli/commands/browser.ts +247 -0
- package/src/cli/commands/conversations.ts +128 -1
- package/src/cli/commands/domain.ts +91 -41
- package/src/cli/commands/inference-providers.ts +147 -1
- package/src/cli/commands/inference.ts +93 -40
- package/src/cli/commands/memory-v2-compare-render.ts +115 -0
- package/src/cli/commands/memory-v2.ts +483 -0
- package/src/cli/commands/memory-v3-render.ts +344 -0
- package/src/cli/commands/memory-v3.ts +316 -0
- package/src/cli/commands/notifications.ts +24 -2
- package/src/cli/program.ts +2 -0
- package/src/cli/utils/conversation-id.ts +17 -5
- package/src/config/assistant-feature-flags.ts +21 -9
- package/src/config/bundled-skills/app-builder/SKILL.md +2 -2
- package/src/config/bundled-skills/document-editor/SKILL.md +124 -0
- package/src/config/bundled-skills/document-editor/TOOLS.json +258 -0
- package/src/config/bundled-skills/document-editor/tools/comment-list.ts +12 -0
- package/src/config/bundled-skills/document-editor/tools/comment-reply.ts +12 -0
- package/src/config/bundled-skills/document-editor/tools/comment-resolve.ts +12 -0
- package/src/config/bundled-skills/document-editor/tools/document-find.ts +12 -0
- package/src/config/bundled-skills/document-editor/tools/document-open.ts +12 -0
- package/src/config/bundled-skills/document-editor/tools/document-replace-text.ts +12 -0
- package/src/config/bundled-skills/image-studio/SKILL.md +4 -0
- package/src/config/bundled-skills/image-studio/tools/media-generate-image.ts +2 -2
- package/src/config/bundled-skills/media-processing/SKILL.md +8 -0
- package/src/config/bundled-skills/media-processing/tools/ingest-media.ts +13 -8
- package/src/config/bundled-skills/messaging/tools/messaging-analyze-style.ts +10 -3
- package/src/config/bundled-skills/phone-calls/references/TRANSCRIPTS.md +16 -14
- package/src/config/bundled-skills/playbooks/tools/playbook-create.ts +7 -2
- package/src/config/bundled-skills/playbooks/tools/playbook-update.ts +7 -2
- package/src/config/bundled-skills/schedule/SKILL.md +8 -0
- package/src/config/bundled-tool-registry.ts +24 -12
- package/src/config/call-site-defaults.ts +20 -0
- package/src/config/feature-flag-registry.json +115 -3
- package/src/config/llm-resolver.ts +16 -2
- package/src/config/schemas/__tests__/memory-v2.test.ts +217 -1
- package/src/config/schemas/call-site-catalog.ts +35 -0
- package/src/config/schemas/llm.ts +14 -0
- package/src/config/schemas/memory-v2.ts +294 -1
- package/src/config/schemas/memory.ts +2 -1
- package/src/context/compactor.ts +60 -1
- package/src/context/token-estimator.ts +47 -4
- package/src/context/window-manager.ts +25 -0
- package/src/conversations/__tests__/message-consolidation.test.ts +350 -0
- package/src/conversations/message-consolidation.ts +404 -0
- package/src/credential-health/credential-health-service.ts +34 -19
- package/src/daemon/__tests__/conversation-tool-setup-exclude.test.ts +1 -1
- package/src/daemon/__tests__/conversation-tool-setup.test.ts +66 -6
- package/src/daemon/__tests__/meet-manifest-loader.test.ts +1 -1
- package/src/daemon/__tests__/native-web-search-metadata.test.ts +357 -0
- package/src/daemon/__tests__/web-search-status-text.test.ts +287 -0
- package/src/daemon/conversation-agent-loop-handlers.ts +155 -36
- package/src/daemon/conversation-agent-loop.ts +307 -88
- package/src/daemon/conversation-error.ts +31 -1
- package/src/daemon/conversation-lifecycle.ts +149 -118
- package/src/daemon/conversation-messaging.ts +3 -0
- package/src/daemon/conversation-process.ts +273 -0
- package/src/daemon/conversation-queue-manager.ts +14 -0
- package/src/daemon/conversation-runtime-assembly.ts +145 -84
- package/src/daemon/conversation-slash.ts +37 -5
- package/src/daemon/conversation-surfaces.ts +45 -2
- package/src/daemon/conversation-tool-setup.ts +70 -3
- package/src/daemon/conversation-usage.ts +2 -0
- package/src/daemon/conversation.ts +54 -32
- package/src/daemon/disk-pressure-guard.ts +14 -2
- package/src/daemon/first-greeting.ts +10 -0
- package/src/daemon/handlers/__tests__/config-a2a-accept.test.ts +498 -0
- package/src/daemon/handlers/config-a2a.ts +160 -0
- package/src/daemon/handlers/config-model.test.ts +2 -0
- package/src/daemon/handlers/conversations.ts +90 -3
- package/src/daemon/handlers/shared.ts +92 -29
- package/src/daemon/host-bash-proxy.ts +1 -1
- package/src/daemon/host-browser-proxy.ts +5 -5
- package/src/daemon/host-cu-proxy.ts +5 -5
- package/src/daemon/host-file-proxy.ts +5 -5
- package/src/daemon/host-proxy-base.ts +4 -4
- package/src/daemon/host-transfer-proxy.ts +11 -11
- package/src/daemon/lifecycle.ts +40 -23
- package/src/daemon/meet-manifest-loader.ts +1 -7
- package/src/daemon/message-protocol.ts +4 -0
- package/src/daemon/message-types/conversations.ts +14 -9
- package/src/daemon/message-types/document-comments.ts +50 -0
- package/src/daemon/message-types/home.ts +1 -13
- package/src/daemon/message-types/messages.ts +66 -7
- package/src/daemon/message-types/surfaces.ts +3 -1
- package/src/daemon/message-types/sync.ts +14 -0
- package/src/daemon/message-types/web-activity.ts +57 -0
- package/src/daemon/plugin-source-watcher.ts +135 -3
- package/src/daemon/process-message.ts +69 -12
- package/src/daemon/shutdown-handlers.ts +24 -5
- package/src/daemon/switch-inference-profile-tool.ts +52 -0
- package/src/daemon/tool-setup-types.ts +13 -0
- package/src/daemon/trust-context.ts +6 -0
- package/src/documents/document-comments-store.test.ts +338 -0
- package/src/documents/document-comments-store.ts +237 -0
- package/src/documents/document-store.ts +202 -0
- package/src/events/relationship-state-updated.ts +25 -0
- package/src/heartbeat/__tests__/heartbeat-service.test.ts +1 -2
- package/src/heartbeat/heartbeat-service.ts +1 -0
- package/src/home/__tests__/suggested-prompts.test.ts +33 -2
- package/src/home/feed-types.ts +6 -1
- package/src/home/home-content-refresh.ts +52 -0
- package/src/home/home-greeting-cache.ts +69 -0
- package/src/home/home-greeting.ts +85 -0
- package/src/home/suggested-prompts.ts +168 -9
- package/src/ipc/gateway-flag-listener.ts +123 -0
- package/src/ipc/skill-routes/registries.ts +8 -12
- package/src/memory/__tests__/db-async-query.test.ts +165 -0
- package/src/memory/__tests__/db-maintenance.test.ts +115 -0
- package/src/memory/__tests__/jobs-store-enqueue-gate.test.ts +241 -0
- package/src/memory/__tests__/jobs-store-job-classes.test.ts +28 -1
- package/src/memory/__tests__/jobs-worker-v2-schedule.test.ts +135 -2
- package/src/memory/__tests__/memory-retrospective-job.test.ts +327 -6
- package/src/memory/auto-analysis-enqueue.ts +5 -1
- package/src/memory/conversation-crud.ts +191 -100
- package/src/memory/conversation-starters-cadence.ts +3 -1
- package/src/memory/conversation-title-service.ts +19 -3
- package/src/memory/db-async-query.ts +214 -0
- package/src/memory/db-init.ts +26 -0
- package/src/memory/db-maintenance.ts +30 -21
- package/src/memory/delivery-crud.ts +41 -0
- package/src/memory/delivery-status.ts +141 -15
- package/src/memory/external-conversation-store.ts +32 -1
- package/src/memory/graph/bootstrap.ts +8 -1
- package/src/memory/graph/capability-seed.ts +7 -3
- package/src/memory/graph/conversation-graph-memory.ts +100 -17
- package/src/memory/graph/extraction.ts +1 -5
- package/src/memory/graph/graph-search.ts +7 -1
- package/src/memory/indexer.ts +28 -18
- package/src/memory/job-handlers/cleanup.ts +76 -18
- package/src/memory/job-handlers/conversation-starters.ts +1 -4
- package/src/memory/jobs/embed-pkb-file.ts +6 -1
- package/src/memory/jobs-store.ts +14 -0
- package/src/memory/jobs-worker.ts +68 -15
- package/src/memory/llm-request-log-source-clickhouse.ts +42 -2
- package/src/memory/llm-request-log-source-local.ts +7 -0
- package/src/memory/llm-request-log-source.ts +9 -2
- package/src/memory/llm-request-log-store.ts +43 -1
- package/src/memory/llm-usage-store.ts +24 -0
- package/src/memory/memory-retrospective-constants.ts +28 -0
- package/src/memory/memory-retrospective-enqueue.ts +11 -3
- package/src/memory/memory-retrospective-job.ts +413 -18
- package/src/memory/memory-retrospective-startup-cleanup.ts +3 -3
- package/src/memory/memory-v2-activation-log-store.ts +41 -14
- package/src/memory/migrations/100-core-tables.ts +1 -0
- package/src/memory/migrations/109-external-conversation-bindings.ts +1 -0
- package/src/memory/migrations/253-conversation-last-notified-profile.ts +15 -0
- package/src/memory/migrations/253-document-comments.ts +47 -0
- package/src/memory/migrations/254-external-conversation-binding-chat-name.ts +43 -0
- package/src/memory/migrations/255-channel-inbound-delivery-attempts.ts +24 -0
- package/src/memory/migrations/256-memory-v2-injection-events.ts +113 -0
- package/src/memory/migrations/257-strip-base-url-non-openai-compatible.ts +22 -0
- package/src/memory/migrations/258-onboarding-events-prior-assistants.ts +13 -0
- package/src/memory/migrations/259-conversation-cleaned-at.ts +33 -0
- package/src/memory/migrations/260-rename-cleaned-at.ts +44 -0
- package/src/memory/migrations/261-llm-usage-add-raw-usage.ts +36 -0
- package/src/memory/migrations/262-memory-v3-coactivation.ts +57 -0
- package/src/memory/migrations/263-memory-v3-auto-edges.ts +50 -0
- package/src/memory/migrations/264-llm-request-log-call-site.ts +29 -0
- package/src/memory/migrations/index.ts +34 -0
- package/src/memory/migrations/registry.ts +58 -0
- package/src/memory/onboarding-events-store.ts +7 -0
- package/src/memory/schema/calls.ts +1 -0
- package/src/memory/schema/conversations.ts +3 -0
- package/src/memory/schema/infrastructure.ts +22 -0
- package/src/memory/tool-usage-store.ts +36 -8
- package/src/memory/v2/__tests__/consolidation-job.test.ts +1 -0
- package/src/memory/v2/__tests__/harness-compare.test.ts +186 -0
- package/src/memory/v2/__tests__/harness-metrics.test.ts +74 -0
- package/src/memory/v2/__tests__/harness-oracle.test.ts +257 -0
- package/src/memory/v2/__tests__/harness-replay-input.test.ts +225 -0
- package/src/memory/v2/__tests__/harness-runner.test.ts +109 -0
- package/src/memory/v2/__tests__/injection-events.test.ts +318 -0
- package/src/memory/v2/__tests__/injection.test.ts +158 -112
- package/src/memory/v2/__tests__/page-index.test.ts +365 -1
- package/src/memory/v2/__tests__/qdrant.test.ts +36 -0
- package/src/memory/v2/__tests__/router.test.ts +660 -4
- package/src/memory/v2/consolidation-job.ts +14 -0
- package/src/memory/v2/harness/compare.ts +57 -0
- package/src/memory/v2/harness/metrics.ts +124 -0
- package/src/memory/v2/harness/oracle.ts +145 -0
- package/src/memory/v2/harness/replay-input.ts +224 -0
- package/src/memory/v2/harness/retriever.ts +74 -0
- package/src/memory/v2/harness/router-retriever.ts +43 -0
- package/src/memory/v2/harness/runner.ts +106 -0
- package/src/memory/v2/harness/trace.ts +58 -0
- package/src/memory/v2/injection-events.ts +101 -0
- package/src/memory/v2/injection.ts +42 -25
- package/src/memory/v2/page-index.ts +209 -7
- package/src/memory/v2/page-store.ts +18 -0
- package/src/memory/v2/prompts/router.ts +26 -1
- package/src/memory/v2/qdrant.ts +14 -2
- package/src/memory/v2/router.ts +369 -62
- package/src/memory/v3/__tests__/coactivation-store.test.ts +422 -0
- package/src/memory/v3/__tests__/consolidation-job.test.ts +468 -0
- package/src/memory/v3/__tests__/edge-learning-job.test.ts +324 -0
- package/src/memory/v3/__tests__/edges.test.ts +563 -0
- package/src/memory/v3/__tests__/filter.test.ts +512 -0
- package/src/memory/v3/__tests__/gate.test.ts +574 -0
- package/src/memory/v3/__tests__/index-composition.test.ts +233 -0
- package/src/memory/v3/__tests__/loop.test.ts +530 -0
- package/src/memory/v3/__tests__/retriever.test.ts +226 -0
- package/src/memory/v3/__tests__/scouts.test.ts +440 -0
- package/src/memory/v3/__tests__/shadow-middleware.test.ts +312 -0
- package/src/memory/v3/__tests__/system-prompts.test.ts +154 -0
- package/src/memory/v3/__tests__/traversal.test.ts +469 -0
- package/src/memory/v3/__tests__/tree-index.test.ts +280 -0
- package/src/memory/v3/__tests__/tree-store.test.ts +529 -0
- package/src/memory/v3/__tests__/tree-walk.test.ts +707 -0
- package/src/memory/v3/__tests__/validate.test.ts +245 -0
- package/src/memory/v3/auto-edges.ts +223 -0
- package/src/memory/v3/coactivation-store.ts +124 -0
- package/src/memory/v3/consolidation-job.ts +323 -0
- package/src/memory/v3/edge-learning-job.ts +160 -0
- package/src/memory/v3/edges.ts +249 -0
- package/src/memory/v3/filter.ts +281 -0
- package/src/memory/v3/gate.ts +334 -0
- package/src/memory/v3/index-composition.ts +113 -0
- package/src/memory/v3/llm-capture.ts +46 -0
- package/src/memory/v3/loop.ts +382 -0
- package/src/memory/v3/maintenance.ts +144 -0
- package/src/memory/v3/prompt-context.ts +33 -0
- package/src/memory/v3/prompts/consolidation.ts +458 -0
- package/src/memory/v3/prompts/system-prompts.ts +196 -0
- package/src/memory/v3/retriever.ts +33 -0
- package/src/memory/v3/scouts.ts +420 -0
- package/src/memory/v3/shadow-middleware.ts +305 -0
- package/src/memory/v3/traversal.ts +206 -0
- package/src/memory/v3/tree-index.ts +237 -0
- package/src/memory/v3/tree-store.ts +394 -0
- package/src/memory/v3/tree-walk.ts +351 -0
- package/src/memory/v3/types.ts +65 -0
- package/src/memory/v3/validate.ts +300 -0
- package/src/messaging/providers/index.ts +7 -1
- package/src/messaging/providers/slack/__tests__/adapter-mention-rendering.test.ts +329 -3
- package/src/messaging/providers/slack/__tests__/adapter-token-routing.test.ts +34 -1
- package/src/messaging/providers/slack/adapter.ts +178 -25
- package/src/messaging/providers/slack/api.test.ts +54 -0
- package/src/messaging/providers/slack/api.ts +119 -3
- package/src/messaging/providers/slack/client.ts +12 -0
- package/src/messaging/providers/slack/deep-link.ts +20 -1
- package/src/messaging/providers/slack/message-metadata.test.ts +48 -0
- package/src/messaging/providers/slack/message-metadata.ts +156 -0
- package/src/messaging/providers/slack/render-transcript.test.ts +107 -75
- package/src/messaging/providers/slack/render-transcript.ts +176 -49
- package/src/messaging/providers/slack/send.test.ts +77 -0
- package/src/messaging/providers/slack/send.ts +8 -2
- package/src/messaging/providers/slack/types.ts +14 -0
- package/src/notifications/__tests__/emit-signal-home-feed.test.ts +4 -1
- package/src/notifications/__tests__/home-feed-side-effect.test.ts +116 -54
- package/src/notifications/adapters/macos.ts +18 -1
- package/src/notifications/adapters/platform.ts +1 -1
- package/src/notifications/conversation-seed-composer.ts +14 -2
- package/src/notifications/decision-engine.ts +1 -4
- package/src/notifications/deferred-emit.ts +135 -0
- package/src/notifications/emit-signal.ts +38 -50
- package/src/notifications/home-feed-side-effect.ts +60 -30
- package/src/oauth/connect-orchestrator.ts +3 -0
- package/src/oauth/credential-token-resolver.ts +2 -0
- package/src/oauth/manual-token-connection.ts +19 -0
- package/src/oauth/oauth-store.ts +12 -0
- package/src/oauth/seed-providers.ts +22 -0
- package/src/permissions/prompter.ts +8 -5
- package/src/permissions/question-prompter.ts +5 -2
- package/src/permissions/secret-prompter.ts +6 -3
- package/src/plugin-api/index.ts +4 -0
- package/src/plugin-api/types.ts +7 -33
- package/src/plugins/defaults/index.ts +6 -0
- package/src/plugins/defaults/injectors.ts +100 -20
- package/src/plugins/external-plugin-loader.ts +5 -68
- package/src/plugins/types.ts +11 -16
- package/src/proactive-artifact/aux-message-injector.ts +17 -4
- package/src/prompts/__tests__/system-prompt.test.ts +46 -2
- package/src/prompts/__tests__/task-progress-hint-section.test.ts +3 -9
- package/src/prompts/normalize-onboarding.ts +40 -0
- package/src/prompts/persona-resolver.ts +36 -21
- package/src/prompts/sections.ts +69 -19
- package/src/prompts/system-prompt.ts +118 -216
- package/src/prompts/template-detection.ts +37 -0
- package/src/prompts/templates/BOOTSTRAP-CONTENT-AUTOMATION.md +141 -0
- package/src/prompts/templates/BOOTSTRAP.md +10 -2
- package/src/prompts/templates/VOICE.md +3 -0
- package/src/prompts/templates/system-sections.ts +281 -9
- package/src/providers/__tests__/connection-model-compat.test.ts +234 -0
- package/src/providers/__tests__/retry-callsite.test.ts +85 -5
- package/src/providers/anthropic/client.ts +159 -66
- package/src/providers/call-site-routing.ts +14 -2
- package/src/providers/connection-model-compat.ts +38 -0
- package/src/providers/connection-resolution.ts +16 -2
- package/src/providers/fireworks/client.ts +20 -2
- package/src/providers/gemini/client.ts +49 -6
- package/src/providers/inference/__tests__/base-url-route-validation.test.ts +342 -0
- package/src/providers/inference/__tests__/base-url-security.test.ts +189 -0
- package/src/providers/inference/__tests__/codex-token-refresh.test.ts +254 -0
- package/src/providers/inference/adapter-factory.ts +18 -1
- package/src/providers/inference/auth.ts +3 -3
- package/src/providers/inference/codex-token-refresh.ts +128 -0
- package/src/providers/inference/resolve-auth.ts +49 -6
- package/src/providers/minimax/client.ts +106 -0
- package/src/providers/model-catalog.ts +91 -1
- package/src/providers/model-intents.ts +1 -1
- package/src/providers/openai/chat-completions-provider.ts +63 -23
- package/src/providers/openai/codex-models.ts +18 -0
- package/src/providers/openai/responses-provider.ts +86 -23
- package/src/providers/openrouter/client.ts +5 -1
- package/src/providers/provider-send-message.ts +7 -1
- package/src/providers/retry.ts +34 -3
- package/src/providers/thinking-config.ts +26 -1
- package/src/providers/types.ts +25 -0
- package/src/providers/usage-tracking.ts +2 -0
- package/src/runtime/AGENTS.md +2 -2
- package/src/runtime/__tests__/agent-wake.test.ts +214 -0
- package/src/runtime/__tests__/background-job-runner.test.ts +128 -0
- package/src/runtime/agent-wake.ts +152 -56
- package/src/runtime/assistant-event-hub.ts +76 -6
- package/src/runtime/auth/route-policy.ts +43 -3
- package/src/runtime/background-job-runner.ts +26 -0
- package/src/runtime/btw-sidechain.ts +0 -6
- package/src/runtime/channel-reply-delivery.ts +182 -47
- package/src/runtime/channel-retry-sweep.ts +141 -16
- package/src/runtime/http-types.ts +7 -6
- package/src/runtime/migrations/vbundle-builder.ts +10 -3
- package/src/runtime/pending-interactions.ts +50 -8
- package/src/runtime/routes/__tests__/content-source-routes.test.ts +162 -0
- package/src/runtime/routes/__tests__/conversation-query-routes.test.ts +161 -1
- package/src/runtime/routes/__tests__/memory-v2-routes.test.ts +14 -0
- package/src/runtime/routes/__tests__/memory-v2-simulate-route.test.ts +290 -0
- package/src/runtime/routes/__tests__/plugins-routes.test.ts +512 -0
- package/src/runtime/routes/__tests__/sanity-routes.test.ts +280 -0
- package/src/runtime/routes/__tests__/slack-channel-routes.test.ts +266 -0
- package/src/runtime/routes/acp-routes.test.ts +255 -6
- package/src/runtime/routes/acp-routes.ts +8 -1
- package/src/runtime/routes/approval-routes.ts +4 -1
- package/src/runtime/routes/avatar-routes.ts +10 -10
- package/src/runtime/routes/background-wake-routes.ts +188 -0
- package/src/runtime/routes/browser-tabs-routes.ts +200 -0
- package/src/runtime/routes/btw-routes.ts +0 -6
- package/src/runtime/routes/chatgpt-subscription-auth-routes.ts +246 -0
- package/src/runtime/routes/content-source-routes.ts +78 -0
- package/src/runtime/routes/conversation-cli-routes.ts +147 -2
- package/src/runtime/routes/conversation-list-routes.ts +12 -4
- package/src/runtime/routes/conversation-management-routes.ts +77 -20
- package/src/runtime/routes/conversation-query-routes.ts +196 -31
- package/src/runtime/routes/conversation-routes.ts +472 -425
- package/src/runtime/routes/conversation-starter-routes.ts +6 -3
- package/src/runtime/routes/disk-pressure-routes.ts +1 -1
- package/src/runtime/routes/document-comments-routes.ts +287 -0
- package/src/runtime/routes/documents-routes.ts +33 -0
- package/src/runtime/routes/domain-routes.ts +60 -10
- package/src/runtime/routes/email-routes.ts +5 -2
- package/src/runtime/routes/events-routes.ts +54 -10
- package/src/runtime/routes/group-routes.ts +24 -8
- package/src/runtime/routes/home-feed-routes.ts +6 -3
- package/src/runtime/routes/host-app-control-routes.ts +1 -1
- package/src/runtime/routes/host-browser-routes.ts +17 -2
- package/src/runtime/routes/host-cu-routes.ts +2 -2
- package/src/runtime/routes/identity-routes.ts +21 -0
- package/src/runtime/routes/inbound-message-handler.ts +288 -58
- package/src/runtime/routes/inbound-stages/acl-enforcement.ts +96 -3
- package/src/runtime/routes/inbound-stages/background-dispatch.test.ts +365 -6
- package/src/runtime/routes/inbound-stages/background-dispatch.ts +283 -82
- package/src/runtime/routes/index.ts +20 -4
- package/src/runtime/routes/inference-profile-session-handler.ts +22 -12
- package/src/runtime/routes/inference-profile-session-routes.ts +7 -1
- package/src/runtime/routes/inference-provider-connection-routes.ts +63 -7
- package/src/runtime/routes/integrations/a2a.ts +60 -1
- package/src/runtime/routes/llm-call-sites-routes.ts +32 -5
- package/src/runtime/routes/log-export-routes.ts +39 -0
- package/src/runtime/routes/memory-item-routes.ts +8 -3
- package/src/runtime/routes/memory-v2-routes.ts +427 -0
- package/src/runtime/routes/memory-v3-routes.ts +316 -0
- package/src/runtime/routes/migration-routes.ts +21 -24
- package/src/runtime/routes/notification-routes.ts +19 -2
- package/src/runtime/routes/plugins-routes.ts +337 -0
- package/src/runtime/routes/question-routes.ts +4 -1
- package/src/runtime/routes/rename-conversation-routes.ts +6 -2
- package/src/runtime/routes/sanity-routes.ts +159 -0
- package/src/runtime/routes/secret-routes.ts +25 -5
- package/src/runtime/routes/settings-routes.ts +12 -11
- package/src/runtime/routes/slack-channel-routes.ts +188 -0
- package/src/runtime/routes/workspace-routes.ts +25 -10
- package/src/runtime/services/conversation-serializer.ts +30 -4
- package/src/runtime/sync/resource-sync-events.ts +106 -38
- package/src/runtime/sync/sync-publisher.test.ts +49 -0
- package/src/runtime/sync/sync-publisher.ts +2 -1
- package/src/runtime/verification-outbound-actions.ts +73 -1
- package/src/schedule/integration-status.ts +3 -1
- package/src/security/__tests__/oauth2-device-code.test.ts +479 -0
- package/src/security/oauth2-device-code.ts +307 -0
- package/src/security/oauth2.ts +26 -9
- package/src/security/secure-keys.ts +5 -0
- package/src/skills/catalog-install.ts +6 -2
- package/src/telemetry/types.ts +12 -0
- package/src/telemetry/usage-telemetry-reporter.test.ts +48 -0
- package/src/telemetry/usage-telemetry-reporter.ts +1 -0
- package/src/tools/acp/spawn.test.ts +119 -0
- package/src/tools/acp/spawn.ts +15 -2
- package/src/tools/apps/definitions.ts +2 -8
- package/src/tools/ask-question/ask-question-tool.test.ts +3 -3
- package/src/tools/ask-question/ask-question-tool.ts +38 -45
- package/src/tools/browser/__tests__/pinned-tabs.test.ts +150 -0
- package/src/tools/browser/browser-execution.ts +106 -0
- package/src/tools/browser/cdp-client/__tests__/browser-tabs-factory.test.ts +402 -0
- package/src/tools/browser/cdp-client/__tests__/factory.test.ts +28 -0
- package/src/tools/browser/cdp-client/__tests__/types.test.ts +4 -0
- package/src/tools/browser/cdp-client/cdp-inspect-client.ts +22 -0
- package/src/tools/browser/cdp-client/extension-cdp-client.ts +42 -2
- package/src/tools/browser/cdp-client/factory.ts +171 -4
- package/src/tools/browser/cdp-client/local-cdp-client.ts +21 -0
- package/src/tools/browser/cdp-client/types.ts +101 -0
- package/src/tools/browser/pinned-tabs.ts +146 -0
- package/src/tools/computer-use/definitions.ts +22 -78
- package/src/tools/credential-execution/make-authenticated-request.ts +3 -9
- package/src/tools/credential-execution/manage-secure-command-tool.ts +3 -9
- package/src/tools/credential-execution/run-authenticated-command.ts +3 -9
- package/src/tools/credentials/vault.ts +3 -9
- package/src/tools/document/document-comment-tool.test.ts +379 -0
- package/src/tools/document/document-comment-tool.ts +156 -0
- package/src/tools/document/document-tool.ts +187 -2
- package/src/tools/execution-target.ts +21 -23
- package/src/tools/executor.ts +6 -1
- package/src/tools/filesystem/edit.ts +3 -9
- package/src/tools/filesystem/list.ts +3 -9
- package/src/tools/filesystem/read.ts +3 -9
- package/src/tools/filesystem/write.ts +3 -9
- package/src/tools/host-filesystem/edit.ts +3 -9
- package/src/tools/host-filesystem/read.ts +3 -9
- package/src/tools/host-filesystem/transfer.ts +3 -9
- package/src/tools/host-filesystem/write.ts +3 -9
- package/src/tools/host-terminal/host-shell.ts +3 -9
- package/src/tools/mcp/mcp-tool-factory.ts +1 -8
- package/src/tools/memory/register.test.ts +1 -1
- package/src/tools/memory/register.ts +4 -9
- package/src/tools/network/__tests__/web-fetch-metadata.test.ts +229 -0
- package/src/tools/network/__tests__/web-search-metadata.test.ts +346 -0
- package/src/tools/network/domain-normalize.ts +17 -0
- package/src/tools/network/web-fetch.ts +216 -73
- package/src/tools/network/web-search.ts +216 -98
- package/src/tools/registry.ts +7 -23
- package/src/tools/schema-transforms.ts +1 -1
- package/src/tools/skills/execute.ts +3 -9
- package/src/tools/skills/load.ts +3 -9
- package/src/tools/skills/skill-tool-factory.ts +1 -8
- package/src/tools/subagent/notify-parent.ts +3 -9
- package/src/tools/system/request-permission.ts +3 -9
- package/src/tools/terminal/safe-env.ts +3 -2
- package/src/tools/terminal/shell.ts +3 -9
- package/src/tools/tool-approval-handler.ts +19 -12
- package/src/tools/tool-defaults.ts +94 -0
- package/src/tools/types.ts +31 -98
- package/src/tools/ui-surface/definitions.ts +9 -23
- package/src/types/onboarding-context.ts +4 -0
- package/src/usage/pricing.ts +23 -0
- package/src/usage/types.ts +12 -0
- package/src/util/__tests__/favicon.test.ts +84 -0
- package/src/util/favicon.ts +40 -0
- package/src/util/logger.ts +16 -7
- package/src/util/platform.ts +7 -7
- package/src/util/sqlite3-runtime.ts +65 -0
- package/src/workspace/git-service.ts +75 -4
- package/src/workspace/migrations/086-revert-stale-gemini-mis-rewrites.ts +1 -0
- package/src/workspace/migrations/088-deprecate-background-conversation-override.ts +103 -0
- package/src/workspace/migrations/089-move-memory-tree-out-of-v3.ts +86 -0
- package/src/workspace/migrations/registry.ts +4 -0
- package/src/__tests__/compaction-strip-metadata-clear.test.ts +0 -206
- package/src/__tests__/message-complete-display-id.test.ts +0 -175
- package/src/config/bundled-skills/document/SKILL.md +0 -54
- package/src/config/bundled-skills/document/TOOLS.json +0 -106
- package/src/daemon/seed-files.ts +0 -18
- package/src/prompts/cache-boundary.ts +0 -8
- package/src/runtime/routes/interface-routes.ts +0 -43
- /package/src/config/bundled-skills/{document → document-editor}/tools/document-create.ts +0 -0
- /package/src/config/bundled-skills/{document → document-editor}/tools/document-delete.ts +0 -0
- /package/src/config/bundled-skills/{document → document-editor}/tools/document-list.ts +0 -0
- /package/src/config/bundled-skills/{document → document-editor}/tools/document-read.ts +0 -0
- /package/src/config/bundled-skills/{document → document-editor}/tools/document-update.ts +0 -0
|
@@ -5,6 +5,7 @@ import {
|
|
|
5
5
|
mkdirSync,
|
|
6
6
|
readFileSync,
|
|
7
7
|
rmSync,
|
|
8
|
+
statSync,
|
|
8
9
|
writeFileSync,
|
|
9
10
|
} from "node:fs";
|
|
10
11
|
import { tmpdir } from "node:os";
|
|
@@ -87,6 +88,58 @@ describe("WorkspaceGitService", () => {
|
|
|
87
88
|
expect(userEmail).toBe("assistant@vellum.ai");
|
|
88
89
|
});
|
|
89
90
|
|
|
91
|
+
test("installs branch guard hook that blocks non-main branches", async () => {
|
|
92
|
+
const service = new WorkspaceGitService(testDir);
|
|
93
|
+
await service.ensureInitialized();
|
|
94
|
+
|
|
95
|
+
const hooksPath = execFileSync("git", ["config", "core.hooksPath"], {
|
|
96
|
+
cwd: testDir,
|
|
97
|
+
encoding: "utf-8",
|
|
98
|
+
}).trim();
|
|
99
|
+
expect(hooksPath).toBe(".githooks");
|
|
100
|
+
|
|
101
|
+
const hookPath = join(testDir, ".githooks", "reference-transaction");
|
|
102
|
+
expect(existsSync(hookPath)).toBe(true);
|
|
103
|
+
expect(statSync(hookPath).mode & 0o111).not.toBe(0);
|
|
104
|
+
|
|
105
|
+
const hookContent = readFileSync(hookPath, "utf-8");
|
|
106
|
+
expect(hookContent).toContain(
|
|
107
|
+
"assistant workspace git branches are disabled",
|
|
108
|
+
);
|
|
109
|
+
|
|
110
|
+
expect(() =>
|
|
111
|
+
execFileSync("git", ["branch", "apollo/test-branch"], {
|
|
112
|
+
cwd: testDir,
|
|
113
|
+
encoding: "utf-8",
|
|
114
|
+
}),
|
|
115
|
+
).toThrow(/assistant workspace git branches are disabled/);
|
|
116
|
+
});
|
|
117
|
+
|
|
118
|
+
test("branch guard allows deleting old non-main branches", async () => {
|
|
119
|
+
const service = new WorkspaceGitService(testDir);
|
|
120
|
+
await service.ensureInitialized();
|
|
121
|
+
|
|
122
|
+
execFileSync(
|
|
123
|
+
"git",
|
|
124
|
+
["-c", "core.hooksPath=/dev/null", "branch", "old-branch"],
|
|
125
|
+
{
|
|
126
|
+
cwd: testDir,
|
|
127
|
+
},
|
|
128
|
+
);
|
|
129
|
+
|
|
130
|
+
execFileSync("git", ["branch", "-D", "old-branch"], { cwd: testDir });
|
|
131
|
+
|
|
132
|
+
const branches = execFileSync(
|
|
133
|
+
"git",
|
|
134
|
+
["branch", "--format=%(refname:short)"],
|
|
135
|
+
{
|
|
136
|
+
cwd: testDir,
|
|
137
|
+
encoding: "utf-8",
|
|
138
|
+
},
|
|
139
|
+
);
|
|
140
|
+
expect(branches).not.toContain("old-branch");
|
|
141
|
+
});
|
|
142
|
+
|
|
90
143
|
test("multiple ensureInitialized calls are idempotent", async () => {
|
|
91
144
|
const service = new WorkspaceGitService(testDir);
|
|
92
145
|
|
|
@@ -368,11 +421,12 @@ describe("WorkspaceGitService", () => {
|
|
|
368
421
|
|
|
369
422
|
await Promise.all(commits);
|
|
370
423
|
|
|
371
|
-
//
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
424
|
+
// Read through the service so GIT_* vars set by CI runners are stripped
|
|
425
|
+
// (matches the env used for the commits themselves).
|
|
426
|
+
const { stdout: log } = await service.runReadOnlyGit([
|
|
427
|
+
"log",
|
|
428
|
+
"--oneline",
|
|
429
|
+
]);
|
|
376
430
|
|
|
377
431
|
for (let i = 0; i < 10; i++) {
|
|
378
432
|
expect(log).toContain(`Add file ${i}`);
|
|
@@ -487,7 +541,7 @@ describe("WorkspaceGitService", () => {
|
|
|
487
541
|
// Set up a pre-existing git repo on a feature branch
|
|
488
542
|
execFileSync("git", ["init", "-b", "main"], { cwd: testDir });
|
|
489
543
|
execFileSync("git", ["config", "user.name", "Test"], { cwd: testDir });
|
|
490
|
-
execFileSync("git", ["config", "user.email", "
|
|
544
|
+
execFileSync("git", ["config", "user.email", "user@example.com"], {
|
|
491
545
|
cwd: testDir,
|
|
492
546
|
});
|
|
493
547
|
writeFileSync(join(testDir, "file.txt"), "content");
|
|
@@ -527,7 +581,7 @@ describe("WorkspaceGitService", () => {
|
|
|
527
581
|
// Set up a pre-existing git repo then detach HEAD
|
|
528
582
|
execFileSync("git", ["init", "-b", "main"], { cwd: testDir });
|
|
529
583
|
execFileSync("git", ["config", "user.name", "Test"], { cwd: testDir });
|
|
530
|
-
execFileSync("git", ["config", "user.email", "
|
|
584
|
+
execFileSync("git", ["config", "user.email", "user@example.com"], {
|
|
531
585
|
cwd: testDir,
|
|
532
586
|
});
|
|
533
587
|
writeFileSync(join(testDir, "file.txt"), "content");
|
|
@@ -571,7 +625,7 @@ describe("WorkspaceGitService", () => {
|
|
|
571
625
|
// This exercises the --discard-changes fallback in ensureOnMainLocked().
|
|
572
626
|
execFileSync("git", ["init", "-b", "main"], { cwd: testDir });
|
|
573
627
|
execFileSync("git", ["config", "user.name", "Test"], { cwd: testDir });
|
|
574
|
-
execFileSync("git", ["config", "user.email", "
|
|
628
|
+
execFileSync("git", ["config", "user.email", "user@example.com"], {
|
|
575
629
|
cwd: testDir,
|
|
576
630
|
});
|
|
577
631
|
writeFileSync(join(testDir, "file.txt"), "original content");
|
|
@@ -619,7 +673,7 @@ describe("WorkspaceGitService", () => {
|
|
|
619
673
|
// Set up a pre-existing git repo without our gitignore rules
|
|
620
674
|
execFileSync("git", ["init", "-b", "main"], { cwd: testDir });
|
|
621
675
|
execFileSync("git", ["config", "user.name", "Test"], { cwd: testDir });
|
|
622
|
-
execFileSync("git", ["config", "user.email", "
|
|
676
|
+
execFileSync("git", ["config", "user.email", "user@example.com"], {
|
|
623
677
|
cwd: testDir,
|
|
624
678
|
});
|
|
625
679
|
writeFileSync(join(testDir, ".gitignore"), "node_modules/\n");
|
|
@@ -648,7 +702,7 @@ describe("WorkspaceGitService", () => {
|
|
|
648
702
|
// Set up a pre-existing git repo with the OLD broad data/ rule
|
|
649
703
|
execFileSync("git", ["init", "-b", "main"], { cwd: testDir });
|
|
650
704
|
execFileSync("git", ["config", "user.name", "Test"], { cwd: testDir });
|
|
651
|
-
execFileSync("git", ["config", "user.email", "
|
|
705
|
+
execFileSync("git", ["config", "user.email", "user@example.com"], {
|
|
652
706
|
cwd: testDir,
|
|
653
707
|
});
|
|
654
708
|
const oldGitignore =
|
|
@@ -711,6 +765,36 @@ describe("WorkspaceGitService", () => {
|
|
|
711
765
|
expect(userEmail).toBe("assistant@vellum.ai");
|
|
712
766
|
});
|
|
713
767
|
|
|
768
|
+
test("existing repo gets branch guard installed on init", async () => {
|
|
769
|
+
execFileSync("git", ["init", "-b", "main"], { cwd: testDir });
|
|
770
|
+
execFileSync("git", ["config", "user.name", "Test"], { cwd: testDir });
|
|
771
|
+
execFileSync("git", ["config", "user.email", "user@example.com"], {
|
|
772
|
+
cwd: testDir,
|
|
773
|
+
});
|
|
774
|
+
writeFileSync(join(testDir, "file.txt"), "content");
|
|
775
|
+
execFileSync("git", ["add", "-A"], { cwd: testDir });
|
|
776
|
+
execFileSync("git", ["commit", "-m", "init"], { cwd: testDir });
|
|
777
|
+
|
|
778
|
+
const service = new WorkspaceGitService(testDir);
|
|
779
|
+
await service.ensureInitialized();
|
|
780
|
+
|
|
781
|
+
const hooksPath = execFileSync("git", ["config", "core.hooksPath"], {
|
|
782
|
+
cwd: testDir,
|
|
783
|
+
encoding: "utf-8",
|
|
784
|
+
}).trim();
|
|
785
|
+
expect(hooksPath).toBe(".githooks");
|
|
786
|
+
expect(
|
|
787
|
+
existsSync(join(testDir, ".githooks", "reference-transaction")),
|
|
788
|
+
).toBe(true);
|
|
789
|
+
|
|
790
|
+
expect(() =>
|
|
791
|
+
execFileSync("git", ["branch", "feature-after-init"], {
|
|
792
|
+
cwd: testDir,
|
|
793
|
+
encoding: "utf-8",
|
|
794
|
+
}),
|
|
795
|
+
).toThrow(/assistant workspace git branches are disabled/);
|
|
796
|
+
});
|
|
797
|
+
|
|
714
798
|
test("existing repo with correct config is idempotent", async () => {
|
|
715
799
|
// Set up a repo that already has everything configured correctly
|
|
716
800
|
execFileSync("git", ["init", "-b", "main"], { cwd: testDir });
|
package/src/__tests__/workspace-migration-088-deprecate-background-conversation-override.test.ts
ADDED
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
import {
|
|
2
|
+
existsSync,
|
|
3
|
+
mkdirSync,
|
|
4
|
+
mkdtempSync,
|
|
5
|
+
readFileSync,
|
|
6
|
+
rmSync,
|
|
7
|
+
writeFileSync,
|
|
8
|
+
} from "node:fs";
|
|
9
|
+
import { tmpdir } from "node:os";
|
|
10
|
+
import { join } from "node:path";
|
|
11
|
+
import { afterEach, beforeEach, describe, expect, test } from "bun:test";
|
|
12
|
+
|
|
13
|
+
import { deprecateBackgroundConversationOverrideMigration } from "../workspace/migrations/088-deprecate-background-conversation-override.js";
|
|
14
|
+
|
|
15
|
+
let workspaceDir: string;
|
|
16
|
+
|
|
17
|
+
beforeEach(() => {
|
|
18
|
+
workspaceDir = mkdtempSync(join(tmpdir(), "vellum-migration-088-test-"));
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
afterEach(() => {
|
|
22
|
+
if (existsSync(workspaceDir)) {
|
|
23
|
+
rmSync(workspaceDir, { recursive: true, force: true });
|
|
24
|
+
}
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
function promptSystemDir(): string {
|
|
28
|
+
return join(workspaceDir, "prompts", "system");
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
function writeOverride(body: string): string {
|
|
32
|
+
const dir = promptSystemDir();
|
|
33
|
+
mkdirSync(dir, { recursive: true });
|
|
34
|
+
const filePath = join(dir, "08-background-conversation.md");
|
|
35
|
+
writeFileSync(filePath, body, "utf-8");
|
|
36
|
+
return filePath;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
describe("088-deprecate-background-conversation-override migration", () => {
|
|
40
|
+
test("has expected id and description", () => {
|
|
41
|
+
expect(deprecateBackgroundConversationOverrideMigration.id).toBe(
|
|
42
|
+
"088-deprecate-background-conversation-override",
|
|
43
|
+
);
|
|
44
|
+
expect(
|
|
45
|
+
deprecateBackgroundConversationOverrideMigration.description,
|
|
46
|
+
).toContain("08-background-conversation");
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
test("renames the override to .deprecated, preserving body", () => {
|
|
50
|
+
const body = "## Custom\n\nUser-customized background note.\n";
|
|
51
|
+
writeOverride(body);
|
|
52
|
+
|
|
53
|
+
deprecateBackgroundConversationOverrideMigration.run(workspaceDir);
|
|
54
|
+
|
|
55
|
+
const originalPath = join(
|
|
56
|
+
promptSystemDir(),
|
|
57
|
+
"08-background-conversation.md",
|
|
58
|
+
);
|
|
59
|
+
const deprecatedPath = join(
|
|
60
|
+
promptSystemDir(),
|
|
61
|
+
"08-background-conversation.md.deprecated",
|
|
62
|
+
);
|
|
63
|
+
|
|
64
|
+
expect(existsSync(originalPath)).toBe(false);
|
|
65
|
+
expect(existsSync(deprecatedPath)).toBe(true);
|
|
66
|
+
expect(readFileSync(deprecatedPath, "utf-8")).toBe(body);
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
test("no-ops when the override is absent", () => {
|
|
70
|
+
expect(() =>
|
|
71
|
+
deprecateBackgroundConversationOverrideMigration.run(workspaceDir),
|
|
72
|
+
).not.toThrow();
|
|
73
|
+
|
|
74
|
+
const deprecatedPath = join(
|
|
75
|
+
promptSystemDir(),
|
|
76
|
+
"08-background-conversation.md.deprecated",
|
|
77
|
+
);
|
|
78
|
+
expect(existsSync(deprecatedPath)).toBe(false);
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
test("does not touch unrelated section overrides", () => {
|
|
82
|
+
const dir = promptSystemDir();
|
|
83
|
+
mkdirSync(dir, { recursive: true });
|
|
84
|
+
const otherPath = join(dir, "07-external-content.md");
|
|
85
|
+
writeFileSync(otherPath, "## External Content\n\nUntouched.\n", "utf-8");
|
|
86
|
+
writeOverride("body");
|
|
87
|
+
|
|
88
|
+
deprecateBackgroundConversationOverrideMigration.run(workspaceDir);
|
|
89
|
+
|
|
90
|
+
expect(readFileSync(otherPath, "utf-8")).toContain("Untouched");
|
|
91
|
+
});
|
|
92
|
+
|
|
93
|
+
test("is safe to re-run after the rename has happened", () => {
|
|
94
|
+
writeOverride("body");
|
|
95
|
+
|
|
96
|
+
deprecateBackgroundConversationOverrideMigration.run(workspaceDir);
|
|
97
|
+
expect(() =>
|
|
98
|
+
deprecateBackgroundConversationOverrideMigration.run(workspaceDir),
|
|
99
|
+
).not.toThrow();
|
|
100
|
+
|
|
101
|
+
const deprecatedPath = join(
|
|
102
|
+
promptSystemDir(),
|
|
103
|
+
"08-background-conversation.md.deprecated",
|
|
104
|
+
);
|
|
105
|
+
expect(readFileSync(deprecatedPath, "utf-8")).toBe("body");
|
|
106
|
+
});
|
|
107
|
+
|
|
108
|
+
test("drops the .md and keeps the .deprecated copy when both exist", () => {
|
|
109
|
+
// A user re-created the override after a prior partial run. The bundled
|
|
110
|
+
// section is gone, so the .md would render unconditionally — drop it.
|
|
111
|
+
const dir = promptSystemDir();
|
|
112
|
+
mkdirSync(dir, { recursive: true });
|
|
113
|
+
const deprecatedPath = join(
|
|
114
|
+
dir,
|
|
115
|
+
"08-background-conversation.md.deprecated",
|
|
116
|
+
);
|
|
117
|
+
writeFileSync(deprecatedPath, "preserved.\n", "utf-8");
|
|
118
|
+
const recreatedPath = writeOverride("re-created body\n");
|
|
119
|
+
|
|
120
|
+
deprecateBackgroundConversationOverrideMigration.run(workspaceDir);
|
|
121
|
+
|
|
122
|
+
expect(existsSync(recreatedPath)).toBe(false);
|
|
123
|
+
expect(readFileSync(deprecatedPath, "utf-8")).toBe("preserved.\n");
|
|
124
|
+
});
|
|
125
|
+
|
|
126
|
+
test("down() restores the override when only .deprecated exists", () => {
|
|
127
|
+
writeOverride("body");
|
|
128
|
+
deprecateBackgroundConversationOverrideMigration.run(workspaceDir);
|
|
129
|
+
|
|
130
|
+
deprecateBackgroundConversationOverrideMigration.down(workspaceDir);
|
|
131
|
+
|
|
132
|
+
const overridePath = join(
|
|
133
|
+
promptSystemDir(),
|
|
134
|
+
"08-background-conversation.md",
|
|
135
|
+
);
|
|
136
|
+
const deprecatedPath = join(
|
|
137
|
+
promptSystemDir(),
|
|
138
|
+
"08-background-conversation.md.deprecated",
|
|
139
|
+
);
|
|
140
|
+
expect(existsSync(overridePath)).toBe(true);
|
|
141
|
+
expect(existsSync(deprecatedPath)).toBe(false);
|
|
142
|
+
expect(readFileSync(overridePath, "utf-8")).toBe("body");
|
|
143
|
+
});
|
|
144
|
+
|
|
145
|
+
test("down() is a no-op when only the .md exists", () => {
|
|
146
|
+
writeOverride("body");
|
|
147
|
+
|
|
148
|
+
expect(() =>
|
|
149
|
+
deprecateBackgroundConversationOverrideMigration.down(workspaceDir),
|
|
150
|
+
).not.toThrow();
|
|
151
|
+
|
|
152
|
+
const overridePath = join(
|
|
153
|
+
promptSystemDir(),
|
|
154
|
+
"08-background-conversation.md",
|
|
155
|
+
);
|
|
156
|
+
expect(readFileSync(overridePath, "utf-8")).toBe("body");
|
|
157
|
+
});
|
|
158
|
+
});
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
import * as fs from "node:fs";
|
|
2
|
+
import { tmpdir } from "node:os";
|
|
3
|
+
import { join } from "node:path";
|
|
4
|
+
import { afterEach, beforeEach, describe, expect, test } from "bun:test";
|
|
5
|
+
|
|
6
|
+
import { moveMemoryTreeOutOfV3Migration } from "../workspace/migrations/089-move-memory-tree-out-of-v3.js";
|
|
7
|
+
|
|
8
|
+
describe("workspace migration 089 — move memory tree out of v3", () => {
|
|
9
|
+
let ws: string;
|
|
10
|
+
|
|
11
|
+
beforeEach(() => {
|
|
12
|
+
ws = fs.mkdtempSync(join(tmpdir(), "ws-mig-089-"));
|
|
13
|
+
});
|
|
14
|
+
|
|
15
|
+
afterEach(() => {
|
|
16
|
+
fs.rmSync(ws, { recursive: true, force: true });
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
function writeOldTree(): void {
|
|
20
|
+
const oldTree = join(ws, "memory", "v3", "tree");
|
|
21
|
+
fs.mkdirSync(join(oldTree, "people"), { recursive: true });
|
|
22
|
+
fs.writeFileSync(join(oldTree, "_root.md"), "root");
|
|
23
|
+
fs.writeFileSync(join(oldTree, "people", "alice.md"), "alice");
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
test("moves memory/v3/tree -> memory/tree (incl. nested) and drops the empty v3 wrapper", () => {
|
|
27
|
+
writeOldTree();
|
|
28
|
+
moveMemoryTreeOutOfV3Migration.run(ws);
|
|
29
|
+
|
|
30
|
+
expect(fs.existsSync(join(ws, "memory", "v3"))).toBe(false);
|
|
31
|
+
expect(
|
|
32
|
+
fs.readFileSync(join(ws, "memory", "tree", "_root.md"), "utf-8"),
|
|
33
|
+
).toBe("root");
|
|
34
|
+
expect(
|
|
35
|
+
fs.readFileSync(
|
|
36
|
+
join(ws, "memory", "tree", "people", "alice.md"),
|
|
37
|
+
"utf-8",
|
|
38
|
+
),
|
|
39
|
+
).toBe("alice");
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
test("is idempotent — re-running after the move changes nothing", () => {
|
|
43
|
+
writeOldTree();
|
|
44
|
+
moveMemoryTreeOutOfV3Migration.run(ws);
|
|
45
|
+
moveMemoryTreeOutOfV3Migration.run(ws);
|
|
46
|
+
|
|
47
|
+
expect(
|
|
48
|
+
fs.readFileSync(join(ws, "memory", "tree", "_root.md"), "utf-8"),
|
|
49
|
+
).toBe("root");
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
test("no-op on a fresh workspace with no old tree", () => {
|
|
53
|
+
moveMemoryTreeOutOfV3Migration.run(ws);
|
|
54
|
+
expect(fs.existsSync(join(ws, "memory", "tree"))).toBe(false);
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
test("never clobbers an existing memory/tree", () => {
|
|
58
|
+
writeOldTree();
|
|
59
|
+
const newTree = join(ws, "memory", "tree");
|
|
60
|
+
fs.mkdirSync(newTree, { recursive: true });
|
|
61
|
+
fs.writeFileSync(join(newTree, "_root.md"), "existing");
|
|
62
|
+
|
|
63
|
+
moveMemoryTreeOutOfV3Migration.run(ws);
|
|
64
|
+
|
|
65
|
+
// Destination preserved; source left in place for manual resolution.
|
|
66
|
+
expect(fs.readFileSync(join(newTree, "_root.md"), "utf-8")).toBe(
|
|
67
|
+
"existing",
|
|
68
|
+
);
|
|
69
|
+
expect(fs.existsSync(join(ws, "memory", "v3", "tree", "_root.md"))).toBe(
|
|
70
|
+
true,
|
|
71
|
+
);
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
test("down() restores memory/tree back to memory/v3/tree", () => {
|
|
75
|
+
const newTree = join(ws, "memory", "tree");
|
|
76
|
+
fs.mkdirSync(newTree, { recursive: true });
|
|
77
|
+
fs.writeFileSync(join(newTree, "_root.md"), "root");
|
|
78
|
+
|
|
79
|
+
moveMemoryTreeOutOfV3Migration.down(ws);
|
|
80
|
+
|
|
81
|
+
expect(fs.existsSync(join(ws, "memory", "tree"))).toBe(false);
|
|
82
|
+
expect(
|
|
83
|
+
fs.readFileSync(join(ws, "memory", "v3", "tree", "_root.md"), "utf-8"),
|
|
84
|
+
).toBe("root");
|
|
85
|
+
});
|
|
86
|
+
});
|
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tests for `prepareAgentEnv` — the shared helper that injects required env
|
|
3
|
+
* vars onto an `AcpAgentConfig` and preflights that they're set.
|
|
4
|
+
*
|
|
5
|
+
* The route-level test in `runtime/routes/acp-routes.test.ts` covers the same
|
|
6
|
+
* behavior through the HTTP handler; these tests pin the helper in isolation
|
|
7
|
+
* so the contract is clear and a future refactor can't silently break it.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import { beforeEach, describe, expect, mock, test } from "bun:test";
|
|
11
|
+
|
|
12
|
+
// Stub the secure-keys backend BEFORE importing the helper. Bun's
|
|
13
|
+
// `mock.module` is process-global and only takes effect for imports that
|
|
14
|
+
// follow it — the dynamic import below ensures correctness.
|
|
15
|
+
const secureKeyStore = new Map<string, string>();
|
|
16
|
+
|
|
17
|
+
mock.module("../../security/secure-keys.js", () => ({
|
|
18
|
+
getSecureKeyAsync: async (key: string) => secureKeyStore.get(key),
|
|
19
|
+
}));
|
|
20
|
+
|
|
21
|
+
const { prepareAgentEnv } = await import("../prepare-agent-env.js");
|
|
22
|
+
|
|
23
|
+
beforeEach(() => {
|
|
24
|
+
secureKeyStore.clear();
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
describe("prepareAgentEnv — claude-agent-acp gating", () => {
|
|
28
|
+
test("injects CLAUDE_CODE_OAUTH_TOKEN from the secure store when agent.env has no override", async () => {
|
|
29
|
+
secureKeyStore.set("credential/acp/claude_oauth_token", "vault-AAA");
|
|
30
|
+
|
|
31
|
+
const prepared = await prepareAgentEnv({
|
|
32
|
+
command: "claude-agent-acp",
|
|
33
|
+
args: [],
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
expect(prepared.env?.CLAUDE_CODE_OAUTH_TOKEN).toBe("vault-AAA");
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
test("accepts CLAUDE_CODE_OAUTH_TOKEN from agent.env (config.json override) with no vault entry", async () => {
|
|
40
|
+
const prepared = await prepareAgentEnv({
|
|
41
|
+
command: "claude-agent-acp",
|
|
42
|
+
args: [],
|
|
43
|
+
env: { CLAUDE_CODE_OAUTH_TOKEN: "config-BBB" },
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
expect(prepared.env?.CLAUDE_CODE_OAUTH_TOKEN).toBe("config-BBB");
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
test("agent.env override wins over the secure-store entry (precedence pin)", async () => {
|
|
50
|
+
// The config-supplied env wins so users can rotate per-workspace without
|
|
51
|
+
// racing the vault. Mirrors the route-level precedence test.
|
|
52
|
+
secureKeyStore.set("credential/acp/claude_oauth_token", "vault-CCC");
|
|
53
|
+
|
|
54
|
+
const prepared = await prepareAgentEnv({
|
|
55
|
+
command: "claude-agent-acp",
|
|
56
|
+
args: [],
|
|
57
|
+
env: { CLAUDE_CODE_OAUTH_TOKEN: "config-DDD" },
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
expect(prepared.env?.CLAUDE_CODE_OAUTH_TOKEN).toBe("config-DDD");
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
test("preserves unrelated env vars on agent.env when injecting from the vault", async () => {
|
|
64
|
+
secureKeyStore.set("credential/acp/claude_oauth_token", "vault-EEE");
|
|
65
|
+
|
|
66
|
+
const prepared = await prepareAgentEnv({
|
|
67
|
+
command: "claude-agent-acp",
|
|
68
|
+
args: [],
|
|
69
|
+
env: { OTHER_VAR: "keep-me" },
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
expect(prepared.env?.CLAUDE_CODE_OAUTH_TOKEN).toBe("vault-EEE");
|
|
73
|
+
expect(prepared.env?.OTHER_VAR).toBe("keep-me");
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
test("throws FailedDependencyError when no token is provided from either route", async () => {
|
|
77
|
+
// secureKeyStore empty, no agent.env override — the preflight must throw
|
|
78
|
+
// so callers fail fast instead of spawning a zombie subprocess that the
|
|
79
|
+
// SDK rejects with 'Authentication required' after the first prompt.
|
|
80
|
+
await expect(
|
|
81
|
+
prepareAgentEnv({ command: "claude-agent-acp", args: [] }),
|
|
82
|
+
).rejects.toThrow("CLAUDE_CODE_OAUTH_TOKEN");
|
|
83
|
+
});
|
|
84
|
+
|
|
85
|
+
test("gates on the resolved command BASENAME (alias to /custom/path/claude-agent-acp still gets the token)", async () => {
|
|
86
|
+
// A user-supplied `acp.agents.my-claude = { command: "/opt/.../claude-agent-acp" }`
|
|
87
|
+
// is the only realistic path that lands a non-bare basename here. The
|
|
88
|
+
// helper must still recognize it.
|
|
89
|
+
secureKeyStore.set("credential/acp/claude_oauth_token", "vault-FFF");
|
|
90
|
+
|
|
91
|
+
const prepared = await prepareAgentEnv({
|
|
92
|
+
command: "/opt/bin/claude-agent-acp",
|
|
93
|
+
args: [],
|
|
94
|
+
});
|
|
95
|
+
|
|
96
|
+
expect(prepared.env?.CLAUDE_CODE_OAUTH_TOKEN).toBe("vault-FFF");
|
|
97
|
+
});
|
|
98
|
+
|
|
99
|
+
test("does NOT mutate the caller's agentConfig", async () => {
|
|
100
|
+
// Callers pass `resolved.agent` which is shared state from the resolver's
|
|
101
|
+
// config cache. The helper must clone before mutating, otherwise repeated
|
|
102
|
+
// spawns would race on the same object.
|
|
103
|
+
secureKeyStore.set("credential/acp/claude_oauth_token", "vault-GGG");
|
|
104
|
+
const original = {
|
|
105
|
+
command: "claude-agent-acp",
|
|
106
|
+
args: [],
|
|
107
|
+
env: { OTHER: "keep" },
|
|
108
|
+
};
|
|
109
|
+
const beforeEnv = { ...original.env };
|
|
110
|
+
|
|
111
|
+
const prepared = await prepareAgentEnv(original);
|
|
112
|
+
|
|
113
|
+
expect(prepared).not.toBe(original);
|
|
114
|
+
expect(prepared.env).not.toBe(original.env);
|
|
115
|
+
expect(original.env).toEqual(beforeEnv);
|
|
116
|
+
expect(original.env).not.toHaveProperty("CLAUDE_CODE_OAUTH_TOKEN");
|
|
117
|
+
});
|
|
118
|
+
});
|
|
119
|
+
|
|
120
|
+
describe("prepareAgentEnv — non-claude commands", () => {
|
|
121
|
+
test("returns the config unchanged for codex-acp (no required env vars today)", async () => {
|
|
122
|
+
// codex-acp inherits auth from the underlying `codex` CLI binary
|
|
123
|
+
// (codex login / CODEX_API_KEY / OPENAI_API_KEY in process.env) — no
|
|
124
|
+
// ACP-level env injection. Pin that contract so a future change has
|
|
125
|
+
// to update this test explicitly.
|
|
126
|
+
const prepared = await prepareAgentEnv({
|
|
127
|
+
command: "codex-acp",
|
|
128
|
+
args: [],
|
|
129
|
+
});
|
|
130
|
+
|
|
131
|
+
expect(prepared.env).toEqual({});
|
|
132
|
+
});
|
|
133
|
+
|
|
134
|
+
test("returns the config unchanged for an unrecognized command basename", async () => {
|
|
135
|
+
secureKeyStore.set("credential/acp/claude_oauth_token", "vault-HHH");
|
|
136
|
+
|
|
137
|
+
const prepared = await prepareAgentEnv({
|
|
138
|
+
command: "some-future-adapter",
|
|
139
|
+
args: [],
|
|
140
|
+
env: { FOO: "bar" },
|
|
141
|
+
});
|
|
142
|
+
|
|
143
|
+
// No injection — basename gate skipped.
|
|
144
|
+
expect(prepared.env).toEqual({ FOO: "bar" });
|
|
145
|
+
});
|
|
146
|
+
});
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Inject required env vars for an ACP agent and preflight that they're set.
|
|
3
|
+
*
|
|
4
|
+
* Called by every code path that hands an `AcpAgentConfig` to
|
|
5
|
+
* `AcpSessionManager.spawn`. There are TWO such paths today — the HTTP
|
|
6
|
+
* route `/v1/acp/spawn` (`runtime/routes/acp-routes.ts:spawnSession`) and
|
|
7
|
+
* the skill tool `acp_spawn` (`tools/acp/spawn.ts:executeAcpSpawn`) — and
|
|
8
|
+
* before this helper existed the env-injection logic lived inline in the
|
|
9
|
+
* route only. The skill-tool path bypassed it entirely, so spawns landed
|
|
10
|
+
* with no `CLAUDE_CODE_OAUTH_TOKEN`, the SDK rejected the first prompt
|
|
11
|
+
* with "Authentication required", and the subprocess died as a zombie
|
|
12
|
+
* with no completion notification.
|
|
13
|
+
*
|
|
14
|
+
* The fix: have this single helper own injection + preflight, and have
|
|
15
|
+
* every caller route through it before calling `manager.spawn`.
|
|
16
|
+
*/
|
|
17
|
+
|
|
18
|
+
import { basename } from "node:path";
|
|
19
|
+
|
|
20
|
+
import { FailedDependencyError } from "../runtime/routes/errors.js";
|
|
21
|
+
import { credentialKey } from "../security/credential-key.js";
|
|
22
|
+
import { getSecureKeyAsync } from "../security/secure-keys.js";
|
|
23
|
+
import type { AcpAgentConfig } from "./types.js";
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Returns a NEW config with any required credentials merged into `env`.
|
|
27
|
+
* Does NOT mutate the input. Throws `FailedDependencyError` if a required
|
|
28
|
+
* credential is missing from both the user-supplied env override and the
|
|
29
|
+
* secure store.
|
|
30
|
+
*
|
|
31
|
+
* Gating is keyed off the resolved agent COMMAND (basename), not the
|
|
32
|
+
* user-facing agent id, so a custom `acp.agents.my-claude = { command:
|
|
33
|
+
* "claude-agent-acp", ... }` alias still gets the env it needs.
|
|
34
|
+
*
|
|
35
|
+
* For `claude-agent-acp` the only required env var is
|
|
36
|
+
* `CLAUDE_CODE_OAUTH_TOKEN`. Two provisioning routes converge on it, with
|
|
37
|
+
* config.json winning over the vault so explicit user overrides
|
|
38
|
+
* (per-workspace, rotated, etc.) are never silently clobbered:
|
|
39
|
+
* 1. `acp.agents.<id>.env.CLAUDE_CODE_OAUTH_TOKEN` in `config.json` —
|
|
40
|
+
* the user-supplied env override on the resolved agent config.
|
|
41
|
+
* 2. Secure store via CLI: `assistant credentials set --service acp \
|
|
42
|
+
* --field claude_oauth_token <token>` — written to the canonical
|
|
43
|
+
* `credential/{service}/{field}` key built by `credentialKey()`,
|
|
44
|
+
* used as fallback when (1) is unset.
|
|
45
|
+
* After resolution, this asserts the token is present (from either route)
|
|
46
|
+
* before spawning. The "fail-fast" throw is symmetric with the existing
|
|
47
|
+
* `binary_not_found` preflight in `resolveAcpAgent` and strictly better
|
|
48
|
+
* than a `warn` + zombie subprocess 10 seconds later.
|
|
49
|
+
*/
|
|
50
|
+
export async function prepareAgentEnv(
|
|
51
|
+
agentConfig: AcpAgentConfig,
|
|
52
|
+
): Promise<AcpAgentConfig> {
|
|
53
|
+
// Clone caller's config + env so we never mutate the resolver's cached
|
|
54
|
+
// agent reference. The local `env` binding sidesteps TS narrowing
|
|
55
|
+
// limitations on the optional `AcpAgentConfig.env` field.
|
|
56
|
+
const env: Record<string, string> = { ...(agentConfig.env ?? {}) };
|
|
57
|
+
const commandBasename = basename(agentConfig.command);
|
|
58
|
+
|
|
59
|
+
if (commandBasename === "claude-agent-acp") {
|
|
60
|
+
if (!env.CLAUDE_CODE_OAUTH_TOKEN) {
|
|
61
|
+
const claudeToken = await getSecureKeyAsync(
|
|
62
|
+
credentialKey("acp", "claude_oauth_token"),
|
|
63
|
+
);
|
|
64
|
+
if (claudeToken) {
|
|
65
|
+
env.CLAUDE_CODE_OAUTH_TOKEN = claudeToken;
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
if (!env.CLAUDE_CODE_OAUTH_TOKEN) {
|
|
69
|
+
throw new FailedDependencyError(
|
|
70
|
+
"claude-agent-acp requires CLAUDE_CODE_OAUTH_TOKEN. " +
|
|
71
|
+
"Run: assistant credentials set --service acp --field claude_oauth_token <token> " +
|
|
72
|
+
"(or set it under acp.agents.<id>.env in config.json).",
|
|
73
|
+
);
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
return { ...agentConfig, env };
|
|
78
|
+
}
|
|
@@ -306,7 +306,7 @@ export class AcpSessionManager {
|
|
|
306
306
|
*/
|
|
307
307
|
private teardownSession(acpSessionId: string, entry: SessionEntry): void {
|
|
308
308
|
for (const requestId of entry.clientHandler.pendingRequestIds) {
|
|
309
|
-
const interaction = pendingInteractions.resolve(requestId);
|
|
309
|
+
const interaction = pendingInteractions.resolve(requestId, "cancelled");
|
|
310
310
|
if (interaction?.directResolve) {
|
|
311
311
|
interaction.directResolve("deny");
|
|
312
312
|
}
|
package/src/agent/attachments.ts
CHANGED