@vellumai/assistant 0.8.8 → 0.8.9-dev.202606091853.fbaa2ae
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 +6 -6
- package/bun.lock +2 -2
- package/docs/activation-funnel-telemetry.md +310 -0
- package/examples/plugins/echo/README.md +61 -60
- package/examples/plugins/echo/hooks/post-tool-use.ts +18 -0
- package/examples/plugins/echo/hooks/stop.ts +16 -0
- package/examples/plugins/echo/hooks/user-prompt-submit.ts +18 -0
- package/examples/plugins/echo/package.json +1 -2
- package/examples/plugins/echo/src/emit.ts +19 -0
- package/node_modules/@vellumai/skill-host-contracts/src/skill-host.ts +7 -6
- package/openapi.yaml +263 -121
- package/package.json +2 -2
- package/src/__tests__/activation-early-marking.test.ts +120 -0
- package/src/__tests__/agent-loop-callsite-precedence.test.ts +69 -14
- package/src/__tests__/agent-loop-exit-reason.test.ts +204 -144
- package/src/__tests__/agent-loop-mutable-latest-user-message.test.ts +50 -35
- package/src/__tests__/agent-loop-output-hooks.test.ts +357 -0
- package/src/__tests__/agent-loop-override-profile.test.ts +25 -6
- package/src/__tests__/agent-loop-provider-error-recording.test.ts +41 -21
- package/src/__tests__/agent-loop-thinking.test.ts +36 -20
- package/src/__tests__/agent-loop.test.ts +441 -96
- package/src/__tests__/agent-wake-disk-pressure-callsite.test.ts +14 -14
- package/src/__tests__/agent-wake-override-profile.test.ts +17 -21
- package/src/__tests__/anthropic-provider.test.ts +23 -8
- package/src/__tests__/app-builder-tool-scripts.test.ts +21 -0
- package/src/__tests__/app-control-flow.test.ts +1 -1
- package/src/__tests__/app-dir-path-guard.test.ts +1 -0
- package/src/__tests__/app-executors.test.ts +132 -0
- package/src/__tests__/approval-cascade.test.ts +6 -5
- package/src/__tests__/approval-routes-http.test.ts +4 -1
- package/src/__tests__/background-workers-disk-pressure.test.ts +1 -1
- package/src/__tests__/channel-approval-routes.test.ts +1 -1
- package/src/__tests__/channel-approvals.test.ts +1 -1
- package/src/__tests__/compaction-circuit.test.ts +258 -0
- package/src/__tests__/compaction-direct.test.ts +146 -0
- package/src/__tests__/compaction-events.test.ts +7 -7
- package/src/__tests__/compaction.benchmark.test.ts +1 -1
- package/src/__tests__/compactor-web-search-strip.test.ts +213 -0
- package/src/__tests__/context-overflow-reducer.test.ts +265 -125
- package/src/__tests__/context-window-manager-compact-retry.test.ts +121 -15
- package/src/__tests__/conversation-abort-tool-results.test.ts +7 -5
- package/src/__tests__/conversation-agent-loop-disk-pressure.test.ts +7 -10
- package/src/__tests__/conversation-agent-loop-inference-profile.test.ts +78 -119
- package/src/__tests__/conversation-agent-loop-overflow.test.ts +158 -234
- package/src/__tests__/conversation-agent-loop.test.ts +342 -623
- package/src/__tests__/conversation-clean-command.test.ts +5 -2
- package/src/__tests__/conversation-confirmation-signals.test.ts +6 -5
- package/src/__tests__/conversation-crud-inference-profile.test.ts +7 -9
- package/src/__tests__/conversation-error.test.ts +15 -1
- package/src/__tests__/conversation-history-web-search.test.ts +6 -1
- package/src/__tests__/conversation-media-retry.test.ts +1 -1
- package/src/__tests__/conversation-process-app-control-preactivation.test.ts +44 -4
- package/src/__tests__/conversation-process-callsite.test.ts +15 -15
- package/src/__tests__/conversation-provider-retry-repair.test.ts +66 -65
- package/src/__tests__/conversation-queue.test.ts +10 -10
- package/src/__tests__/conversation-runtime-assembly.test.ts +1059 -231
- package/src/__tests__/conversation-runtime-workspace.test.ts +115 -20
- package/src/__tests__/conversation-slash-queue.test.ts +7 -5
- package/src/__tests__/conversation-slash-unknown.test.ts +7 -5
- package/src/__tests__/conversation-speed-override.test.ts +11 -10
- package/src/__tests__/conversation-starter-routes.test.ts +14 -6
- package/src/__tests__/conversation-surfaces-activation-emit.test.ts +395 -0
- package/src/__tests__/conversation-surfaces-app-control.test.ts +48 -1
- package/src/__tests__/conversation-tool-setup-app-refresh.test.ts +73 -4
- package/src/__tests__/conversation-undo.test.ts +2 -2
- package/src/__tests__/conversation-workspace-cache-state.test.ts +24 -21
- package/src/__tests__/conversation-workspace-injection.test.ts +69 -7
- package/src/__tests__/conversation-workspace-tool-tracking.test.ts +15 -12
- package/src/__tests__/conversations-import-system-filter.test.ts +101 -0
- package/src/__tests__/corrected-target.test.ts +93 -0
- package/src/__tests__/credential-security-invariants.test.ts +1 -0
- package/src/__tests__/cu-unified-flow.test.ts +36 -0
- package/src/__tests__/db-acp-history.test.ts +101 -0
- package/src/__tests__/dynamic-page-surface.test.ts +31 -0
- package/src/__tests__/empty-response-hook.test.ts +1 -1
- package/src/__tests__/file-write-tool.test.ts +63 -0
- package/src/__tests__/gateway-only-guard.test.ts +17 -2
- package/src/__tests__/guardian-grant-minting.test.ts +1 -1
- package/src/__tests__/guardian-routing-invariants.test.ts +93 -4
- package/src/__tests__/handlers-user-message-approval-consumption.test.ts +1 -1
- package/src/__tests__/heartbeat-disk-pressure.test.ts +1 -0
- package/src/__tests__/heartbeat-service.test.ts +1 -0
- package/src/__tests__/history-repair-hook.test.ts +5 -1
- package/src/__tests__/host-app-control-proxy.test.ts +45 -0
- package/src/__tests__/host-app-control-routes.test.ts +1 -1
- package/src/__tests__/host-cu-routes-targeted.test.ts +3 -3
- package/src/__tests__/inference-profile-reaper.test.ts +62 -0
- package/src/__tests__/inference-profile-session-handler.test.ts +86 -0
- package/src/__tests__/injector-background-turn.test.ts +13 -23
- package/src/__tests__/injector-chain.test.ts +268 -44
- package/src/__tests__/injector-disk-pressure.test.ts +210 -52
- package/src/__tests__/injector-document-comments.test.ts +97 -114
- package/src/__tests__/injector-pkb-v2-silenced.test.ts +2 -2
- package/src/__tests__/injector-v3-suppression.test.ts +4 -4
- package/src/__tests__/list-messages-client-message-id.test.ts +91 -0
- package/src/__tests__/list-messages-hidden-metadata.test.ts +38 -0
- package/src/__tests__/llm-resolver.test.ts +73 -0
- package/src/__tests__/memory-retrieval-hook.test.ts +156 -38
- package/src/__tests__/memory-v2-static-injector.test.ts +86 -8
- package/src/__tests__/notification-decision-strategy.test.ts +3 -3
- package/src/__tests__/parallel-tool.benchmark.test.ts +35 -8
- package/src/__tests__/persist-unsendable-image-downscale.test.ts +145 -0
- package/src/__tests__/persist-unsendable-image.test.ts +97 -1
- package/src/__tests__/plugin-api-shim.test.ts +6 -9
- package/src/__tests__/plugin-bootstrap.test.ts +91 -81
- package/src/__tests__/plugin-registry.test.ts +3 -49
- package/src/__tests__/plugin-skill-contribution.test.ts +15 -14
- package/src/__tests__/plugin-tool-contribution.test.ts +7 -4
- package/src/__tests__/plugin-types.test.ts +0 -70
- package/src/__tests__/post-turn-tool-result-truncation.test.ts +69 -0
- package/src/__tests__/pre-model-call-sanitize.test.ts +109 -0
- package/src/__tests__/published-app-updater.test.ts +138 -0
- package/src/__tests__/reaction-persistence.test.ts +1 -1
- package/src/__tests__/send-endpoint-busy.test.ts +4 -1
- package/src/__tests__/skill-feature-flags-integration.test.ts +31 -0
- package/src/__tests__/steer-tool-repair.test.ts +1 -1
- package/src/__tests__/subagent-call-site-routing.test.ts +1 -1
- package/src/__tests__/subagent-detail.test.ts +25 -7
- package/src/__tests__/subagent-fork-notifications.test.ts +1 -3
- package/src/__tests__/subagent-fork-spawn.test.ts +1 -1
- package/src/__tests__/subagent-manager-notify.test.ts +1 -3
- package/src/__tests__/subagent-notify-parent.test.ts +1 -3
- package/src/__tests__/subagent-spawn-tool-fork.test.ts +1 -1
- package/src/__tests__/title-generate-hook.test.ts +5 -1
- package/src/__tests__/tool-error-hook.test.ts +1 -1
- package/src/__tests__/tool-result-truncate-hook.test.ts +1 -1
- package/src/__tests__/user-plugin-loader.test.ts +54 -286
- package/src/__tests__/web-fetch.test.ts +45 -0
- package/src/acp/__tests__/agent-process.test.ts +161 -0
- package/src/acp/__tests__/client-handler.test.ts +40 -0
- package/src/acp/__tests__/helpers/acp-config-stub.ts +0 -2
- package/src/acp/__tests__/helpers/acp-history-db.ts +82 -0
- package/src/acp/__tests__/helpers/exec-file-stub.ts +106 -0
- package/src/acp/__tests__/prepare-agent-env.test.ts +97 -0
- package/src/acp/__tests__/session-manager-persistence.test.ts +95 -28
- package/src/acp/__tests__/session-manager-resume.test.ts +888 -0
- package/src/acp/agent-process.ts +61 -1
- package/src/acp/auto-install.test.ts +280 -0
- package/src/acp/auto-install.ts +232 -0
- package/src/acp/client-handler.ts +31 -0
- package/src/acp/prepare-agent-env.ts +80 -27
- package/src/acp/resolve-agent.test.ts +188 -28
- package/src/acp/resolve-agent.ts +119 -42
- package/src/acp/resume-hint.ts +23 -0
- package/src/acp/session-manager.ts +507 -73
- package/src/agent/compaction-circuit.ts +60 -102
- package/src/agent/loop.ts +403 -251
- package/src/api/responses/conversation-message.ts +22 -2
- package/src/api/responses/memory-v3-selection-log.ts +19 -10
- package/src/approvals/guardian-request-resolvers.ts +27 -1
- package/src/background-wake/next-wake.ts +1 -0
- package/src/cli/commands/__tests__/memory-v3.test.ts +191 -210
- package/src/cli/commands/channel-verification-sessions.ts +6 -6
- package/src/cli/commands/db/__tests__/repair.test.ts +3 -1
- package/src/cli/commands/memory-v3.ts +57 -199
- package/src/cli/commands/plugins.ts +43 -37
- package/src/cli/lib/__tests__/install-from-github.test.ts +790 -111
- package/src/cli/lib/__tests__/plugin-catalog-cache.test.ts +196 -0
- package/src/cli/lib/__tests__/plugin-details.test.ts +381 -0
- package/src/cli/lib/__tests__/plugin-marketplace.test.ts +270 -0
- package/src/cli/lib/__tests__/search-plugins.test.ts +233 -32
- package/src/cli/lib/install-from-github.ts +797 -60
- package/src/cli/lib/plugin-catalog-cache.ts +84 -0
- package/src/cli/lib/plugin-details.ts +416 -0
- package/src/cli/lib/plugin-marketplace.ts +215 -0
- package/src/cli/lib/search-plugins.ts +201 -29
- package/src/config/__tests__/feature-flag-registry-guard.test.ts +2 -2
- package/src/config/acp-defaults.test.ts +10 -0
- package/src/config/acp-defaults.ts +9 -3
- package/src/config/acp-schema.ts +1 -7
- package/src/config/bundled-skills/acp/SKILL.md +80 -41
- package/src/config/bundled-skills/acp/TOOLS.json +4 -4
- package/src/config/bundled-skills/app-builder/SKILL.md +224 -381
- package/src/config/bundled-skills/app-builder/TOOLS.json +72 -2
- package/src/config/bundled-skills/app-builder/references/DESIGN_SYSTEM.md +48 -0
- package/src/config/bundled-skills/app-builder/references/RESPONSIVE.md +57 -0
- package/src/config/bundled-skills/app-builder/references/SLIDES.md +38 -0
- package/src/config/bundled-skills/app-builder/tools/app-list.ts +62 -0
- package/src/config/bundled-skills/app-builder/tools/app-update.ts +18 -0
- package/src/config/bundled-skills/document-editor/SKILL.md +28 -23
- package/src/config/bundled-skills/document-editor/TOOLS.json +1 -1
- package/src/config/bundled-tool-registry.ts +4 -0
- package/src/config/call-site-defaults.ts +0 -3
- package/src/config/feature-flag-registry.json +10 -16
- package/src/config/llm-resolver.ts +39 -7
- package/src/config/schemas/__tests__/memory-v3.test.ts +25 -9
- package/src/config/schemas/call-site-catalog.ts +0 -21
- package/src/config/schemas/heartbeat.ts +9 -0
- package/src/config/schemas/llm.ts +17 -3
- package/src/config/schemas/memory-v3.ts +58 -8
- package/src/config/seed-inference-profiles.ts +18 -0
- package/src/context/compactor.ts +22 -4
- package/src/context/post-turn-tool-result-truncation.ts +39 -1
- package/src/context/strip-injections.ts +8 -2
- package/src/daemon/conversation-agent-loop-handlers.ts +18 -36
- package/src/daemon/conversation-agent-loop.ts +308 -1297
- package/src/daemon/conversation-error.ts +31 -4
- package/src/daemon/conversation-history.ts +1 -1
- package/src/daemon/conversation-lifecycle.ts +11 -255
- package/src/daemon/conversation-media-retry.ts +19 -6
- package/src/daemon/conversation-messaging.ts +17 -0
- package/src/daemon/conversation-process.ts +22 -141
- package/src/daemon/conversation-queue-manager.ts +8 -0
- package/src/daemon/conversation-registry.ts +159 -0
- package/src/daemon/conversation-runtime-assembly.ts +361 -393
- package/src/daemon/conversation-store.ts +9 -90
- package/src/daemon/conversation-surfaces.ts +165 -11
- package/src/daemon/conversation-workspace.ts +17 -0
- package/src/daemon/conversation.ts +444 -62
- package/src/daemon/disk-pressure-policy.ts +0 -1
- package/src/daemon/external-plugins-bootstrap.ts +36 -46
- package/src/daemon/handlers/config-channels.ts +11 -2
- package/src/daemon/handlers/conversations.ts +3 -1
- package/src/daemon/handlers/skills.ts +4 -1
- package/src/daemon/host-app-control-proxy.ts +72 -57
- package/src/daemon/host-proxy-preactivation.ts +1 -3
- package/src/daemon/lifecycle.ts +21 -7
- package/src/daemon/persist-unsendable-image.ts +62 -25
- package/src/daemon/process-message.ts +1 -1
- package/src/daemon/server.ts +2 -0
- package/src/daemon/tool-side-effects.ts +15 -0
- package/src/daemon/wake-conversation-ops.ts +269 -0
- package/src/embedded/plugin-api.ts +2 -2
- package/src/export/__tests__/transcript-formatter.test.ts +5 -0
- package/src/heartbeat/__tests__/heartbeat-service.test.ts +3 -0
- package/src/heartbeat/heartbeat-run-store.ts +23 -1
- package/src/heartbeat/heartbeat-service.ts +26 -0
- package/src/ipc/__tests__/browser-ipc.test.ts +1 -1
- package/src/ipc/__tests__/ui-request-route.test.ts +3 -3
- package/src/ipc/skill-routes/__tests__/memory.test.ts +15 -0
- package/src/ipc/skill-routes/memory.ts +4 -2
- package/src/memory/__tests__/activation-session-store.test.ts +41 -0
- package/src/memory/__tests__/jobs-worker-v2-schedule.test.ts +87 -0
- package/src/memory/__tests__/onboarding-events-store.test.ts +80 -0
- package/src/memory/activation-session-store.ts +43 -0
- package/src/memory/conversation-crud.ts +29 -19
- package/src/memory/conversation-starter-checkpoints.ts +1 -0
- package/src/memory/db-init.ts +6 -0
- package/src/memory/job-handlers/conversation-starters.ts +13 -2
- package/src/memory/jobs/__tests__/embed-concept-page.test.ts +5 -4
- package/src/memory/jobs-worker.ts +25 -1
- package/src/memory/migrations/272-acp-session-history-cwd.ts +36 -0
- package/src/memory/migrations/273-onboarding-events-funnel-columns.ts +46 -0
- package/src/memory/migrations/274-create-activation-sessions.ts +15 -0
- package/src/memory/migrations/index.ts +3 -0
- package/src/memory/onboarding-events-store.ts +66 -18
- package/src/memory/schema/acp.ts +4 -0
- package/src/memory/schema/infrastructure.ts +13 -0
- package/src/memory/v2/__tests__/consolidation-job.test.ts +4 -97
- package/src/memory/v2/__tests__/page-store.test.ts +22 -0
- package/src/memory/v2/consolidation-job.ts +2 -63
- package/src/memory/v2/types.ts +5 -0
- package/src/messaging/providers/telegram-bot/api.ts +14 -5
- package/src/notifications/__tests__/copy-composer.test.ts +244 -0
- package/src/notifications/access-request-copy.ts +298 -0
- package/src/notifications/adapters/slack.ts +3 -3
- package/src/notifications/adapters/telegram.ts +9 -2
- package/src/notifications/copy-composer.ts +49 -267
- package/src/notifications/decision-engine.ts +16 -35
- package/src/notifications/home-feed-side-effect.ts +1 -6
- package/src/plugin-api/constants.ts +4 -0
- package/src/plugin-api/index.ts +40 -11
- package/src/plugin-api/types.ts +108 -0
- package/src/plugins/defaults/compaction/compact.ts +106 -0
- package/src/{daemon → plugins/defaults/compaction}/context-overflow-reducer.ts +250 -42
- package/src/plugins/defaults/compaction/corrected-target.ts +53 -0
- package/src/plugins/defaults/compaction/manager-store.ts +57 -0
- package/src/plugins/defaults/compaction/package.json +1 -2
- package/src/{context → plugins/defaults/compaction}/window-manager.ts +95 -25
- package/src/plugins/defaults/empty-response/package.json +0 -1
- package/src/plugins/defaults/history-repair/package.json +0 -1
- package/src/plugins/defaults/index.ts +156 -26
- package/src/plugins/defaults/memory-retrieval/hooks/post-compact.ts +100 -52
- package/src/plugins/defaults/memory-retrieval/hooks/user-prompt-submit.ts +285 -0
- package/src/plugins/defaults/memory-retrieval/injector-chain.ts +2 -2
- package/src/plugins/defaults/{injectors/register.ts → memory-retrieval/injectors.ts} +148 -73
- package/src/plugins/defaults/memory-retrieval/package.json +14 -0
- package/src/plugins/defaults/memory-retrieval/unified-turn-context.ts +223 -0
- package/src/plugins/defaults/memory-v3-shadow/__tests__/capabilities.test.ts +71 -0
- package/src/plugins/defaults/memory-v3-shadow/__tests__/dense.test.ts +181 -0
- package/src/plugins/defaults/memory-v3-shadow/__tests__/edge.test.ts +247 -0
- package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/__tests__/live-integration.test.ts +147 -134
- package/src/plugins/defaults/memory-v3-shadow/__tests__/maintain-job.test.ts +456 -0
- package/src/plugins/defaults/memory-v3-shadow/__tests__/orchestrate.test.ts +662 -0
- package/src/plugins/defaults/memory-v3-shadow/__tests__/pool-select.test.ts +306 -0
- package/src/plugins/defaults/memory-v3-shadow/__tests__/render-injection.test.ts +91 -0
- package/src/plugins/defaults/memory-v3-shadow/__tests__/section-dense-store.test.ts +402 -0
- package/src/plugins/defaults/memory-v3-shadow/__tests__/section-needle.test.ts +135 -0
- package/src/plugins/defaults/memory-v3-shadow/__tests__/sections.test.ts +125 -0
- package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/__tests__/selection-log-store.test.ts +74 -19
- package/src/plugins/defaults/memory-v3-shadow/__tests__/shadow-integration.test.ts +446 -0
- package/src/plugins/defaults/memory-v3-shadow/__tests__/shadow-plugin.test.ts +592 -0
- package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/__tests__/types.test.ts +2 -24
- package/src/plugins/defaults/memory-v3-shadow/capabilities.ts +91 -0
- package/src/plugins/defaults/memory-v3-shadow/dense.ts +97 -0
- package/src/plugins/defaults/memory-v3-shadow/edge.ts +252 -0
- package/src/plugins/defaults/memory-v3-shadow/hooks/post-compact.ts +14 -0
- package/src/plugins/defaults/memory-v3-shadow/hooks/user-prompt-submit.ts +19 -0
- package/src/plugins/defaults/memory-v3-shadow/injector.ts +76 -0
- package/src/plugins/defaults/memory-v3-shadow/maintain-job.ts +555 -0
- package/src/plugins/defaults/memory-v3-shadow/orchestrate.ts +266 -0
- package/src/plugins/defaults/memory-v3-shadow/package.json +14 -0
- package/src/plugins/defaults/memory-v3-shadow/page-content.ts +71 -0
- package/src/plugins/defaults/memory-v3-shadow/pool-select.ts +204 -0
- package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/render-injection.ts +16 -8
- package/src/plugins/defaults/memory-v3-shadow/section-dense-store.ts +236 -0
- package/src/plugins/defaults/memory-v3-shadow/section-needle.ts +200 -0
- package/src/plugins/defaults/memory-v3-shadow/sections.ts +115 -0
- package/src/plugins/defaults/memory-v3-shadow/selection-log-store.ts +156 -0
- package/src/plugins/defaults/memory-v3-shadow/shadow-plugin.ts +382 -0
- package/src/plugins/defaults/memory-v3-shadow/types.ts +92 -0
- package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/working-set.ts +4 -1
- package/src/plugins/defaults/title-generate/package.json +0 -1
- package/src/plugins/defaults/tool-error/package.json +0 -1
- package/src/plugins/defaults/tool-result-truncate/package.json +0 -1
- package/src/plugins/external-api.ts +12 -2
- package/src/plugins/pipeline.ts +6 -293
- package/src/plugins/registry.ts +9 -37
- package/src/plugins/types.ts +76 -381
- package/src/plugins/user-loader.ts +30 -127
- package/src/prompts/__tests__/system-prompt.test.ts +6 -0
- package/src/prompts/system-prompt.ts +61 -10
- package/src/prompts/templates/BOOTSTRAP-ACTIVATION-RAIL.md +71 -4
- package/src/providers/anthropic/client.ts +9 -10
- package/src/providers/inference/kimi-cjk-token-ids.ts +493 -0
- package/src/providers/inference/logit-bias.ts +55 -0
- package/src/providers/model-catalog.ts +34 -0
- package/src/providers/openai/__tests__/vision-not-supported.test.ts +75 -0
- package/src/providers/openai/chat-completions-provider.ts +44 -1
- package/src/providers/retry.ts +22 -0
- package/src/providers/types.ts +6 -0
- package/src/runtime/__tests__/agent-wake.test.ts +555 -691
- package/src/runtime/__tests__/interactive-ui.test.ts +1 -1
- package/src/runtime/agent-wake.ts +108 -209
- package/src/runtime/assistant-event-hub.ts +1 -1
- package/src/runtime/channel-approvals.ts +1 -1
- package/src/runtime/interactive-ui.ts +1 -1
- package/src/runtime/routes/__tests__/acp-routes.test.ts +466 -55
- package/src/runtime/routes/__tests__/conversation-list-routes.test.ts +1 -1
- package/src/runtime/routes/__tests__/plugins-routes.test.ts +423 -73
- package/src/runtime/routes/__tests__/stt-routes.test.ts +112 -0
- package/src/runtime/routes/__tests__/surface-action-routes.test.ts +5 -4
- package/src/runtime/routes/__tests__/surface-content-routes.test.ts +4 -1
- package/src/runtime/routes/acp-routes.test.ts +185 -32
- package/src/runtime/routes/acp-routes.ts +328 -30
- package/src/runtime/routes/app-management-routes.ts +3 -0
- package/src/runtime/routes/approval-routes.ts +1 -1
- package/src/runtime/routes/browser-routes.ts +1 -1
- package/src/runtime/routes/browser-tabs-routes.ts +6 -10
- package/src/runtime/routes/channel-verification-routes.ts +14 -5
- package/src/runtime/routes/conversation-cli-routes.ts +1 -1
- package/src/runtime/routes/conversation-list-routes.ts +1 -1
- package/src/runtime/routes/conversation-query-routes.ts +1 -1
- package/src/runtime/routes/conversation-routes.ts +30 -2
- package/src/runtime/routes/conversation-starter-routes.ts +13 -7
- package/src/runtime/routes/conversations-import-routes.ts +24 -7
- package/src/runtime/routes/host-app-control-routes.ts +1 -1
- package/src/runtime/routes/host-cu-routes.ts +1 -1
- package/src/runtime/routes/identity-routes.ts +18 -3
- package/src/runtime/routes/inbound-message-handler.ts +1 -1
- package/src/runtime/routes/inbound-stages/acl-enforcement.ts +33 -34
- package/src/runtime/routes/inference-profile-session-handler.ts +11 -0
- package/src/runtime/routes/inference-profile-session-reaper.ts +6 -0
- package/src/runtime/routes/memory-v3-routes.ts +65 -305
- package/src/runtime/routes/playground/__tests__/force-compact.test.ts +1 -1
- package/src/runtime/routes/playground/helpers.ts +1 -1
- package/src/runtime/routes/plugins-routes.ts +337 -35
- package/src/runtime/routes/stt-routes.ts +45 -12
- package/src/runtime/routes/surface-conversation-resolver.ts +4 -3
- package/src/runtime/routes/work-items-routes.ts +2 -4
- package/src/runtime/routes/workspace-routes.ts +50 -15
- package/src/runtime/services/conversation-serializer.ts +1 -1
- package/src/runtime/verification-outbound-actions.ts +147 -2
- package/src/runtime/verification-templates.ts +29 -3
- package/src/services/published-app-updater.ts +30 -8
- package/src/signals/cancel.ts +2 -4
- package/src/subagent/manager.ts +21 -5
- package/src/telemetry/__tests__/activation-funnel.test.ts +95 -0
- package/src/telemetry/activation-funnel.ts +167 -0
- package/src/telemetry/types.ts +13 -0
- package/src/telemetry/usage-telemetry-reporter.test.ts +154 -0
- package/src/telemetry/usage-telemetry-reporter.ts +26 -1
- package/src/tools/acp/context.ts +20 -0
- package/src/tools/acp/list-agents.test.ts +9 -19
- package/src/tools/acp/list-agents.ts +3 -15
- package/src/tools/acp/spawn.test.ts +173 -202
- package/src/tools/acp/spawn.ts +37 -172
- package/src/tools/acp/steer.test.ts +105 -8
- package/src/tools/acp/steer.ts +48 -17
- package/src/tools/apps/executors.ts +166 -50
- package/src/tools/browser/browser-execution.ts +12 -2
- package/src/tools/filesystem/write.ts +34 -0
- package/src/tools/network/web-fetch.ts +65 -24
- package/src/tools/skills/load.ts +1 -1
- package/src/tools/subagent/spawn.ts +2 -4
- package/src/tools/ui-surface/definitions.ts +32 -5
- package/src/workspace/migrations/051-seed-conversation-summarization-callsite.ts +4 -5
- package/src/workspace/migrations/097-enable-adaptive-thinking-managed-profiles.ts +69 -45
- package/docs/plugins.md +0 -832
- package/examples/plugins/echo/register.ts +0 -143
- package/src/__tests__/circuit-breaker-pipeline.test.ts +0 -405
- package/src/__tests__/compaction-pipeline.test.ts +0 -210
- package/src/__tests__/compaction-timeout-recovery.test.ts +0 -251
- package/src/__tests__/overflow-reduce-pipeline.test.ts +0 -667
- package/src/__tests__/pipeline-runner.test.ts +0 -554
- package/src/daemon/wake-target-adapter.ts +0 -253
- package/src/memory/v3/__tests__/assign.test.ts +0 -242
- package/src/memory/v3/__tests__/capabilities.test.ts +0 -118
- package/src/memory/v3/__tests__/core.test.ts +0 -39
- package/src/memory/v3/__tests__/health.test.ts +0 -219
- package/src/memory/v3/__tests__/maintain-job.test.ts +0 -288
- package/src/memory/v3/__tests__/needle.test.ts +0 -107
- package/src/memory/v3/__tests__/orchestrate.test.ts +0 -436
- package/src/memory/v3/__tests__/provider-blocks.test.ts +0 -13
- package/src/memory/v3/__tests__/reconcile.test.ts +0 -274
- package/src/memory/v3/__tests__/render-injection.test.ts +0 -61
- package/src/memory/v3/__tests__/router.test.ts +0 -332
- package/src/memory/v3/__tests__/selector.test.ts +0 -470
- package/src/memory/v3/__tests__/shadow-plugin.test.ts +0 -432
- package/src/memory/v3/__tests__/snapshot.test.ts +0 -168
- package/src/memory/v3/__tests__/tree.test.ts +0 -192
- package/src/memory/v3/assign.ts +0 -268
- package/src/memory/v3/capabilities.ts +0 -124
- package/src/memory/v3/core.ts +0 -26
- package/src/memory/v3/health.ts +0 -0
- package/src/memory/v3/maintain-job.ts +0 -314
- package/src/memory/v3/needle.ts +0 -115
- package/src/memory/v3/orchestrate.ts +0 -126
- package/src/memory/v3/page-content.ts +0 -34
- package/src/memory/v3/provider-blocks.ts +0 -26
- package/src/memory/v3/reconcile.ts +0 -523
- package/src/memory/v3/router.ts +0 -190
- package/src/memory/v3/selection-log-store.ts +0 -84
- package/src/memory/v3/selector.ts +0 -226
- package/src/memory/v3/shadow-plugin.ts +0 -411
- package/src/memory/v3/snapshot.ts +0 -209
- package/src/memory/v3/tree.ts +0 -174
- package/src/memory/v3/types.ts +0 -59
- package/src/notifications/__tests__/emit-signal-home-feed.test.ts +0 -187
- package/src/plugins/defaults/circuit-breaker/middlewares/circuitBreaker.ts +0 -93
- package/src/plugins/defaults/circuit-breaker/package.json +0 -15
- package/src/plugins/defaults/circuit-breaker/register.ts +0 -39
- package/src/plugins/defaults/compaction/middlewares/compaction.ts +0 -25
- package/src/plugins/defaults/compaction/register.ts +0 -35
- package/src/plugins/defaults/compaction/terminal.ts +0 -73
- package/src/plugins/defaults/empty-response/register.ts +0 -23
- package/src/plugins/defaults/history-repair/register.ts +0 -24
- package/src/plugins/defaults/memory-retrieval/hooks/user-prompt-submit-temp.ts +0 -216
- package/src/plugins/defaults/overflow-reduce/middlewares/overflowReduce.ts +0 -126
- package/src/plugins/defaults/overflow-reduce/package.json +0 -15
- package/src/plugins/defaults/overflow-reduce/register.ts +0 -42
- package/src/plugins/defaults/title-generate/register.ts +0 -35
- package/src/plugins/defaults/tool-error/register.ts +0 -23
- package/src/plugins/defaults/tool-result-truncate/register.ts +0 -24
- package/src/proactive-artifact/aux-message-injector.ts +0 -97
- package/src/proactive-artifact/decision.test.ts +0 -226
- package/src/proactive-artifact/decision.ts +0 -165
- package/src/proactive-artifact/index.ts +0 -7
- package/src/proactive-artifact/job.test.ts +0 -962
- package/src/proactive-artifact/job.ts +0 -372
- package/src/proactive-artifact/message-copy.ts +0 -58
- package/src/proactive-artifact/trigger-state.test.ts +0 -286
- package/src/proactive-artifact/trigger-state.ts +0 -123
- package/src/util/map-limit.ts +0 -27
- /package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/__tests__/fixtures/eval-turns.json +0 -0
- /package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/__tests__/fixtures/live-turns.json +0 -0
- /package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/__tests__/working-set-eviction.test.ts +0 -0
- /package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/__tests__/working-set-skeleton.test.ts +0 -0
- /package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/data/README.md +0 -0
- /package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/data/assignments.json +0 -0
- /package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/data/core.json +0 -0
- /package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/data/leaves/domain-a/topic-x.md +0 -0
- /package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/data/leaves/domain-a/topic-y.md +0 -0
- /package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/data/leaves/domain-b/topic-z.md +0 -0
- /package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/llm-retry.ts +0 -0
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import * as realChildProcess from "node:child_process";
|
|
2
1
|
import { afterAll, beforeEach, describe, expect, mock, test } from "bun:test";
|
|
3
2
|
|
|
4
3
|
import { installAcpConfigStub } from "../../acp/__tests__/helpers/acp-config-stub.js";
|
|
4
|
+
import { installExecFileStub } from "../../acp/__tests__/helpers/exec-file-stub.js";
|
|
5
5
|
import { installWhichStub } from "../../acp/__tests__/helpers/which-stub.js";
|
|
6
6
|
import type { ToolContext } from "../types.js";
|
|
7
7
|
|
|
@@ -9,58 +9,18 @@ import type { ToolContext } from "../types.js";
|
|
|
9
9
|
// Mock infrastructure
|
|
10
10
|
// ---------------------------------------------------------------------------
|
|
11
11
|
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
interface ExecScript {
|
|
19
|
-
/** When set, the call rejects with this error. */
|
|
20
|
-
error?: Error;
|
|
21
|
-
/** When set, the call resolves with this stdout. */
|
|
22
|
-
stdout?: string;
|
|
23
|
-
}
|
|
12
|
+
const {
|
|
13
|
+
execScripts,
|
|
14
|
+
execFileMock,
|
|
15
|
+
reset: resetExecFileStub,
|
|
16
|
+
} = installExecFileStub();
|
|
24
17
|
|
|
25
|
-
/**
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
*/
|
|
29
|
-
const execScripts: Map<string, ExecScript> = new Map();
|
|
30
|
-
|
|
31
|
-
const execFileMock = mock(
|
|
32
|
-
(
|
|
33
|
-
command: string,
|
|
34
|
-
args: string[],
|
|
35
|
-
_options: unknown,
|
|
36
|
-
callback?: ExecCallback,
|
|
37
|
-
) => {
|
|
38
|
-
const key = `${command} ${args[0]}`;
|
|
39
|
-
const script = execScripts.get(key);
|
|
40
|
-
queueMicrotask(() => {
|
|
41
|
-
if (!callback) return;
|
|
42
|
-
if (!script) {
|
|
43
|
-
callback(new Error(`No script for ${key}`), "", "");
|
|
44
|
-
return;
|
|
45
|
-
}
|
|
46
|
-
if (script.error) {
|
|
47
|
-
callback(script.error, "", "");
|
|
48
|
-
return;
|
|
49
|
-
}
|
|
50
|
-
callback(null, script.stdout ?? "", "");
|
|
51
|
-
});
|
|
52
|
-
// Return value is not used by execFileWithTimeout.
|
|
53
|
-
return {} as ReturnType<typeof realChildProcess.execFile>;
|
|
54
|
-
},
|
|
55
|
-
);
|
|
56
|
-
|
|
57
|
-
mock.module("node:child_process", () => ({
|
|
58
|
-
...realChildProcess,
|
|
59
|
-
execFile: execFileMock,
|
|
60
|
-
}));
|
|
18
|
+
/** Fixed resolved `bun` path so install script keys are predictable. */
|
|
19
|
+
const BUN_BIN = "/usr/local/bin/bun";
|
|
20
|
+
const BUN_ADD_KEY = `${BUN_BIN} add`;
|
|
61
21
|
|
|
62
22
|
// Default ACP config used by these tests: the `unknown-agent` entry is here
|
|
63
|
-
// to give the "
|
|
23
|
+
// to give the "unmapped binary" tests a configured agent whose command isn't
|
|
64
24
|
// in DEFAULT_AGENT_NPM_PACKAGES.
|
|
65
25
|
const DEFAULT_TEST_AGENTS = {
|
|
66
26
|
claude: { command: "claude-agent-acp", args: [] },
|
|
@@ -187,8 +147,10 @@ mock.module("../../acp/index.js", () => ({
|
|
|
187
147
|
getAcpSessionManager: () => ({ spawn: spawnMock }),
|
|
188
148
|
}));
|
|
189
149
|
|
|
190
|
-
const { executeAcpSpawn
|
|
191
|
-
|
|
150
|
+
const { executeAcpSpawn } = await import("./spawn.js");
|
|
151
|
+
const { _resetAdapterInstallCacheForTests } = await import(
|
|
152
|
+
"../../acp/auto-install.js"
|
|
153
|
+
);
|
|
192
154
|
|
|
193
155
|
// ---------------------------------------------------------------------------
|
|
194
156
|
// Helpers
|
|
@@ -204,11 +166,12 @@ function makeContext(): ToolContext {
|
|
|
204
166
|
}
|
|
205
167
|
|
|
206
168
|
beforeEach(() => {
|
|
207
|
-
|
|
208
|
-
execFileMock.mockClear();
|
|
169
|
+
resetExecFileStub();
|
|
209
170
|
spawnMock.mockClear();
|
|
210
|
-
|
|
171
|
+
_resetAdapterInstallCacheForTests();
|
|
211
172
|
config.setConfig({ agents: DEFAULT_TEST_AGENTS });
|
|
173
|
+
// Default: every command (including bun and the adapters) on PATH, so
|
|
174
|
+
// spawns resolve directly with no install.
|
|
212
175
|
which.setWhich((cmd) => `/usr/local/bin/${cmd}`);
|
|
213
176
|
// Default: vault has a claude token so the preflight in `prepareAgentEnv`
|
|
214
177
|
// succeeds for tests that don't care about env injection. Env-injection
|
|
@@ -222,135 +185,41 @@ beforeEach(() => {
|
|
|
222
185
|
// Tests
|
|
223
186
|
// ---------------------------------------------------------------------------
|
|
224
187
|
|
|
225
|
-
describe("executeAcpSpawn
|
|
226
|
-
test("
|
|
227
|
-
execScripts.set("npm ls", { error: new Error("npm not installed") });
|
|
228
|
-
execScripts.set("npm view", { error: new Error("npm not installed") });
|
|
229
|
-
|
|
188
|
+
describe("executeAcpSpawn - happy path", () => {
|
|
189
|
+
test("binary on PATH: spawns directly with no install and no npm probe", async () => {
|
|
230
190
|
const result = await executeAcpSpawn(
|
|
231
191
|
{ agent: "claude", task: "do something" },
|
|
232
192
|
makeContext(),
|
|
233
193
|
);
|
|
234
194
|
|
|
235
195
|
expect(result.isError).toBe(false);
|
|
196
|
+
// No package manager is ever invoked when the binary is already present.
|
|
197
|
+
expect(execFileMock).not.toHaveBeenCalled();
|
|
236
198
|
expect(result.content).not.toContain("outdated");
|
|
237
|
-
expect(result.content).not.toContain("Note:");
|
|
238
|
-
// Spawn was actually invoked.
|
|
239
199
|
expect(spawnMock).toHaveBeenCalledTimes(1);
|
|
240
|
-
|
|
241
|
-
const lines = result.content.split("\n\n");
|
|
242
|
-
const payload = JSON.parse(lines[0]);
|
|
200
|
+
const payload = JSON.parse(result.content);
|
|
243
201
|
expect(payload.acpSessionId).toBe("acp-session-test");
|
|
244
202
|
expect(payload.status).toBe("running");
|
|
203
|
+
// The real adapter binary is spawned (no `bun x` wrapper).
|
|
204
|
+
const agentConfigArg = spawnMock.mock.calls[0][1] as { command: string };
|
|
205
|
+
expect(agentConfigArg.command).toBe("claude-agent-acp");
|
|
245
206
|
});
|
|
246
207
|
|
|
247
|
-
test("
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
},
|
|
253
|
-
}),
|
|
254
|
-
});
|
|
255
|
-
execScripts.set("npm view", { stdout: "0.2.0\n" });
|
|
256
|
-
|
|
257
|
-
const result = await executeAcpSpawn(
|
|
258
|
-
{ agent: "claude", task: "do something" },
|
|
259
|
-
makeContext(),
|
|
260
|
-
);
|
|
261
|
-
|
|
262
|
-
expect(result.isError).toBe(false);
|
|
263
|
-
expect(result.content).toContain("outdated");
|
|
264
|
-
expect(result.content).toContain("@agentclientprotocol/claude-agent-acp");
|
|
265
|
-
expect(result.content).toContain("0.1.0");
|
|
266
|
-
expect(result.content).toContain("0.2.0");
|
|
267
|
-
expect(result.content).toContain(
|
|
268
|
-
"npm install -g @agentclientprotocol/claude-agent-acp@0.2.0",
|
|
269
|
-
);
|
|
270
|
-
expect(spawnMock).toHaveBeenCalledTimes(1);
|
|
271
|
-
// Payload still parses as JSON before the warning suffix.
|
|
272
|
-
const [payloadJson] = result.content.split("\n\n");
|
|
273
|
-
const payload = JSON.parse(payloadJson);
|
|
274
|
-
expect(payload.acpSessionId).toBe("acp-session-test");
|
|
275
|
-
});
|
|
276
|
-
|
|
277
|
-
test("up-to-date version: spawn proceeds, no warning", async () => {
|
|
278
|
-
execScripts.set("npm ls", {
|
|
279
|
-
stdout: JSON.stringify({
|
|
280
|
-
dependencies: {
|
|
281
|
-
"@agentclientprotocol/claude-agent-acp": { version: "0.2.0" },
|
|
282
|
-
},
|
|
283
|
-
}),
|
|
284
|
-
});
|
|
285
|
-
execScripts.set("npm view", { stdout: "0.2.0\n" });
|
|
286
|
-
|
|
287
|
-
const result = await executeAcpSpawn(
|
|
288
|
-
{ agent: "claude", task: "do something" },
|
|
289
|
-
makeContext(),
|
|
290
|
-
);
|
|
291
|
-
|
|
292
|
-
expect(result.isError).toBe(false);
|
|
293
|
-
expect(result.content).not.toContain("outdated");
|
|
294
|
-
expect(spawnMock).toHaveBeenCalledTimes(1);
|
|
295
|
-
});
|
|
296
|
-
|
|
297
|
-
test("unknown command: no version check is performed", async () => {
|
|
298
|
-
// No execScripts set — if the implementation tried to run npm, the
|
|
299
|
-
// mock would callback with "No script for ..." and we could detect
|
|
300
|
-
// the failure. But since the registry doesn't include this command,
|
|
301
|
-
// the implementation should skip the check entirely without calling
|
|
302
|
-
// execFile.
|
|
303
|
-
execFileMock.mockClear();
|
|
208
|
+
test("default-profile fallback when user config is empty", async () => {
|
|
209
|
+
// No user `agents.codex` entry, but `agent: "codex"` works via the bundled
|
|
210
|
+
// default profile (command: "codex-acp"). The resolver merges defaults
|
|
211
|
+
// automatically.
|
|
212
|
+
config.setConfig({ agents: {} });
|
|
304
213
|
|
|
305
214
|
const result = await executeAcpSpawn(
|
|
306
|
-
{ agent: "
|
|
215
|
+
{ agent: "codex", task: "do something" },
|
|
307
216
|
makeContext(),
|
|
308
217
|
);
|
|
309
218
|
|
|
310
219
|
expect(result.isError).toBe(false);
|
|
311
|
-
expect(execFileMock).not.toHaveBeenCalled();
|
|
312
220
|
expect(spawnMock).toHaveBeenCalledTimes(1);
|
|
313
|
-
|
|
314
|
-
expect(
|
|
315
|
-
});
|
|
316
|
-
|
|
317
|
-
test("cached null result: second call does not reprobe", async () => {
|
|
318
|
-
execScripts.set("npm ls", { error: new Error("npm not installed") });
|
|
319
|
-
execScripts.set("npm view", { error: new Error("npm not installed") });
|
|
320
|
-
|
|
321
|
-
await executeAcpSpawn({ agent: "claude", task: "task 1" }, makeContext());
|
|
322
|
-
const firstCallCount = execFileMock.mock.calls.length;
|
|
323
|
-
expect(firstCallCount).toBeGreaterThan(0);
|
|
324
|
-
|
|
325
|
-
await executeAcpSpawn({ agent: "claude", task: "task 2" }, makeContext());
|
|
326
|
-
// No additional execFile calls — result was cached.
|
|
327
|
-
expect(execFileMock.mock.calls.length).toBe(firstCallCount);
|
|
328
|
-
});
|
|
329
|
-
|
|
330
|
-
test("cached outdated result: second call does not reprobe but still warns", async () => {
|
|
331
|
-
execScripts.set("npm ls", {
|
|
332
|
-
stdout: JSON.stringify({
|
|
333
|
-
dependencies: {
|
|
334
|
-
"@agentclientprotocol/claude-agent-acp": { version: "0.1.0" },
|
|
335
|
-
},
|
|
336
|
-
}),
|
|
337
|
-
});
|
|
338
|
-
execScripts.set("npm view", { stdout: "0.2.0\n" });
|
|
339
|
-
|
|
340
|
-
const first = await executeAcpSpawn(
|
|
341
|
-
{ agent: "claude", task: "task 1" },
|
|
342
|
-
makeContext(),
|
|
343
|
-
);
|
|
344
|
-
expect(first.content).toContain("outdated");
|
|
345
|
-
const firstCallCount = execFileMock.mock.calls.length;
|
|
346
|
-
|
|
347
|
-
const second = await executeAcpSpawn(
|
|
348
|
-
{ agent: "claude", task: "task 2" },
|
|
349
|
-
makeContext(),
|
|
350
|
-
);
|
|
351
|
-
expect(second.content).toContain("outdated");
|
|
352
|
-
// No additional execFile calls — outdated info was cached.
|
|
353
|
-
expect(execFileMock.mock.calls.length).toBe(firstCallCount);
|
|
221
|
+
const agentConfigArg = spawnMock.mock.calls[0][1] as { command: string };
|
|
222
|
+
expect(agentConfigArg.command).toBe("codex-acp");
|
|
354
223
|
});
|
|
355
224
|
});
|
|
356
225
|
|
|
@@ -381,84 +250,190 @@ describe("executeAcpSpawn — input validation", () => {
|
|
|
381
250
|
expect(result.content).toContain("Available:");
|
|
382
251
|
});
|
|
383
252
|
|
|
384
|
-
test("
|
|
385
|
-
|
|
253
|
+
test("missing binary + bun absent returns install hint, no install attempted", async () => {
|
|
254
|
+
which.setWhich({}); // neither bun nor the adapter on PATH
|
|
386
255
|
const result = await executeAcpSpawn(
|
|
387
256
|
{ agent: "claude", task: "do something" },
|
|
388
257
|
makeContext(),
|
|
389
258
|
);
|
|
390
259
|
expect(result.isError).toBe(true);
|
|
391
|
-
expect(result.content).toContain("acp
|
|
260
|
+
expect(result.content).toContain("claude-agent-acp is not on PATH");
|
|
261
|
+
expect(result.content).toContain(
|
|
262
|
+
"bun add -g @agentclientprotocol/claude-agent-acp",
|
|
263
|
+
);
|
|
264
|
+
expect(execFileMock).not.toHaveBeenCalled();
|
|
265
|
+
expect(spawnMock).not.toHaveBeenCalled();
|
|
392
266
|
});
|
|
267
|
+
});
|
|
268
|
+
|
|
269
|
+
describe("executeAcpSpawn: sandboxed bun auto-install on missing binary", () => {
|
|
270
|
+
test("known command + bun present: installs via bun and spawn proceeds with a note", async () => {
|
|
271
|
+
// Only bun is on PATH until `bun add --global` runs, simulating a
|
|
272
|
+
// successful global install that links the adapter bin onto PATH.
|
|
273
|
+
let binaryOnPath = false;
|
|
274
|
+
which.setWhich((cmd) => {
|
|
275
|
+
if (cmd === "bun") return BUN_BIN;
|
|
276
|
+
if (binaryOnPath) return `/usr/local/bin/${cmd}`;
|
|
277
|
+
return null;
|
|
278
|
+
});
|
|
279
|
+
execScripts.set(BUN_ADD_KEY, {
|
|
280
|
+
stdout: "",
|
|
281
|
+
onCall: () => {
|
|
282
|
+
binaryOnPath = true;
|
|
283
|
+
},
|
|
284
|
+
});
|
|
393
285
|
|
|
394
|
-
test("missing binary returns install hint", async () => {
|
|
395
|
-
which.setWhich({});
|
|
396
286
|
const result = await executeAcpSpawn(
|
|
397
287
|
{ agent: "claude", task: "do something" },
|
|
398
288
|
makeContext(),
|
|
399
289
|
);
|
|
290
|
+
|
|
291
|
+
expect(result.isError).toBe(false);
|
|
292
|
+
expect(spawnMock).toHaveBeenCalledTimes(1);
|
|
293
|
+
const payload = JSON.parse(result.content);
|
|
294
|
+
expect(payload.message).toContain(
|
|
295
|
+
"Installed @agentclientprotocol/claude-agent-acp automatically.",
|
|
296
|
+
);
|
|
297
|
+
// The real binary was spawned with cwd = the project dir and token
|
|
298
|
+
// injected (trusted-binary config, no resolution at spawn).
|
|
299
|
+
const agentConfigArg = spawnMock.mock.calls[0][1] as {
|
|
300
|
+
command: string;
|
|
301
|
+
env?: Record<string, string>;
|
|
302
|
+
};
|
|
303
|
+
expect(agentConfigArg.command).toBe("claude-agent-acp");
|
|
304
|
+
expect(agentConfigArg.env?.CLAUDE_CODE_OAUTH_TOKEN).toBe(
|
|
305
|
+
"default-test-token",
|
|
306
|
+
);
|
|
307
|
+
expect(spawnMock.mock.calls[0][3]).toBe("/tmp");
|
|
308
|
+
|
|
309
|
+
// Exactly one install, and it was `bun add --global` (never npm).
|
|
310
|
+
expect(execFileMock).toHaveBeenCalledTimes(1);
|
|
311
|
+
const [command, args] = execFileMock.mock.calls[0];
|
|
312
|
+
expect(command).toBe(BUN_BIN);
|
|
313
|
+
expect(args).toEqual([
|
|
314
|
+
"add",
|
|
315
|
+
"--global",
|
|
316
|
+
"@agentclientprotocol/claude-agent-acp",
|
|
317
|
+
]);
|
|
318
|
+
});
|
|
319
|
+
|
|
320
|
+
test("the installer cwd is a temp dir (not the project cwd) with secrets stripped", async () => {
|
|
321
|
+
let binaryOnPath = false;
|
|
322
|
+
which.setWhich((cmd) => {
|
|
323
|
+
if (cmd === "bun") return BUN_BIN;
|
|
324
|
+
if (binaryOnPath) return `/usr/local/bin/${cmd}`;
|
|
325
|
+
return null;
|
|
326
|
+
});
|
|
327
|
+
execScripts.set(BUN_ADD_KEY, {
|
|
328
|
+
stdout: "",
|
|
329
|
+
onCall: () => {
|
|
330
|
+
binaryOnPath = true;
|
|
331
|
+
},
|
|
332
|
+
});
|
|
333
|
+
|
|
334
|
+
await executeAcpSpawn(
|
|
335
|
+
{ agent: "claude", task: "do something", cwd: "/untrusted/project" },
|
|
336
|
+
makeContext(),
|
|
337
|
+
);
|
|
338
|
+
|
|
339
|
+
const options = execFileMock.mock.calls[0][2] as {
|
|
340
|
+
cwd?: string;
|
|
341
|
+
env?: NodeJS.ProcessEnv;
|
|
342
|
+
};
|
|
343
|
+
expect(options.cwd).toBeDefined();
|
|
344
|
+
expect(options.cwd).not.toBe("/untrusted/project");
|
|
345
|
+
expect(options.cwd).toContain("vellum-acp-install-");
|
|
346
|
+
expect(options.env?.CLAUDE_CODE_OAUTH_TOKEN).toBeUndefined();
|
|
347
|
+
expect(options.env?.GEMINI_API_KEY).toBeUndefined();
|
|
348
|
+
expect(options.env?.BUN_CONFIG_REGISTRY).toBe(
|
|
349
|
+
"https://registry.npmjs.org/",
|
|
350
|
+
);
|
|
351
|
+
});
|
|
352
|
+
|
|
353
|
+
test("unmapped command: no install attempted, plain hint returned", async () => {
|
|
354
|
+
which.setWhich({});
|
|
355
|
+
|
|
356
|
+
const result = await executeAcpSpawn(
|
|
357
|
+
{ agent: "unknown-agent", task: "do something" },
|
|
358
|
+
makeContext(),
|
|
359
|
+
);
|
|
360
|
+
|
|
400
361
|
expect(result.isError).toBe(true);
|
|
401
|
-
expect(result.content).toContain("
|
|
402
|
-
expect(result.content).toContain(
|
|
403
|
-
|
|
362
|
+
expect(result.content).toContain("some-other-binary is not on PATH");
|
|
363
|
+
expect(result.content).toContain("Install 'some-other-binary'");
|
|
364
|
+
expect(result.content).not.toContain("auto-install failed");
|
|
365
|
+
expect(execFileMock).not.toHaveBeenCalled();
|
|
366
|
+
expect(spawnMock).not.toHaveBeenCalled();
|
|
367
|
+
});
|
|
368
|
+
|
|
369
|
+
test("no client connected: no install attempted even when the binary is missing", async () => {
|
|
370
|
+
// The no-client guard is a pure precondition and must run BEFORE the
|
|
371
|
+
// auto-install side effect: without a client the spawn fails anyway, so
|
|
372
|
+
// the host must not be mutated by a global install (which can also block
|
|
373
|
+
// for up to the install timeout).
|
|
374
|
+
which.setWhich({ bun: BUN_BIN });
|
|
375
|
+
|
|
376
|
+
const result = await executeAcpSpawn(
|
|
377
|
+
{ agent: "claude", task: "do something" },
|
|
378
|
+
{ ...makeContext(), sendToClient: undefined },
|
|
404
379
|
);
|
|
380
|
+
|
|
381
|
+
expect(result.isError).toBe(true);
|
|
382
|
+
expect(result.content).toContain("No client connected");
|
|
383
|
+
expect(execFileMock).not.toHaveBeenCalled();
|
|
405
384
|
expect(spawnMock).not.toHaveBeenCalled();
|
|
406
385
|
});
|
|
407
386
|
|
|
408
|
-
test("
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
execScripts.set("npm ls", { error: new Error("npm not installed") });
|
|
414
|
-
execScripts.set("npm view", { error: new Error("npm not installed") });
|
|
387
|
+
test("install failure: hint and install failure both surface, never npm", async () => {
|
|
388
|
+
which.setWhich({ bun: BUN_BIN }); // bun present, adapter never appears
|
|
389
|
+
execScripts.set(BUN_ADD_KEY, {
|
|
390
|
+
error: new Error("EACCES: permission denied"),
|
|
391
|
+
});
|
|
415
392
|
|
|
416
393
|
const result = await executeAcpSpawn(
|
|
417
|
-
{ agent: "
|
|
394
|
+
{ agent: "claude", task: "do something" },
|
|
418
395
|
makeContext(),
|
|
419
396
|
);
|
|
420
397
|
|
|
421
|
-
expect(result.isError).toBe(
|
|
422
|
-
expect(
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
398
|
+
expect(result.isError).toBe(true);
|
|
399
|
+
expect(result.content).toContain("claude-agent-acp is not on PATH");
|
|
400
|
+
expect(result.content).toContain(
|
|
401
|
+
"bun add -g @agentclientprotocol/claude-agent-acp",
|
|
402
|
+
);
|
|
403
|
+
expect(result.content).toContain("auto-install failed");
|
|
404
|
+
expect(result.content).toContain("EACCES");
|
|
405
|
+
for (const call of execFileMock.mock.calls) {
|
|
406
|
+
expect(call[0]).not.toBe("npm");
|
|
407
|
+
}
|
|
408
|
+
expect(spawnMock).not.toHaveBeenCalled();
|
|
426
409
|
});
|
|
427
410
|
});
|
|
428
411
|
|
|
429
412
|
describe("executeAcpSpawn — per-agent resume hint", () => {
|
|
430
413
|
test("claude payload includes the `claude --resume` hint", async () => {
|
|
431
|
-
execScripts.set("npm ls", { error: new Error("npm not installed") });
|
|
432
|
-
execScripts.set("npm view", { error: new Error("npm not installed") });
|
|
433
|
-
|
|
434
414
|
const result = await executeAcpSpawn(
|
|
435
415
|
{ agent: "claude", task: "do something" },
|
|
436
416
|
makeContext(),
|
|
437
417
|
);
|
|
438
418
|
|
|
439
419
|
expect(result.isError).toBe(false);
|
|
440
|
-
const
|
|
441
|
-
const payload = JSON.parse(payloadJson);
|
|
420
|
+
const payload = JSON.parse(result.content);
|
|
442
421
|
expect(payload.message).toContain("claude --resume");
|
|
443
|
-
expect(payload.message).toContain("To resume
|
|
422
|
+
expect(payload.message).toContain("To resume:");
|
|
444
423
|
});
|
|
445
424
|
|
|
446
425
|
test("non-claude payload omits the `claude --resume` hint", async () => {
|
|
447
426
|
// `claude --resume <id>` is Claude Code-specific. Codex (and any other
|
|
448
427
|
// adapter) should not have that command suggested back to the user.
|
|
449
|
-
execScripts.set("npm ls", { error: new Error("npm not installed") });
|
|
450
|
-
execScripts.set("npm view", { error: new Error("npm not installed") });
|
|
451
|
-
|
|
452
428
|
const result = await executeAcpSpawn(
|
|
453
429
|
{ agent: "codex", task: "do something" },
|
|
454
430
|
makeContext(),
|
|
455
431
|
);
|
|
456
432
|
|
|
457
433
|
expect(result.isError).toBe(false);
|
|
458
|
-
const
|
|
459
|
-
const payload = JSON.parse(payloadJson);
|
|
434
|
+
const payload = JSON.parse(result.content);
|
|
460
435
|
expect(payload.message).not.toContain("claude --resume");
|
|
461
|
-
expect(payload.message).not.toContain("To resume
|
|
436
|
+
expect(payload.message).not.toContain("To resume:");
|
|
462
437
|
});
|
|
463
438
|
});
|
|
464
439
|
|
|
@@ -482,8 +457,6 @@ describe("executeAcpSpawn — CLAUDE_CODE_OAUTH_TOKEN injection", () => {
|
|
|
482
457
|
vaultStore.clear();
|
|
483
458
|
metadataStore.clear();
|
|
484
459
|
vaultStore.set("acp/claude_oauth_token", "tool-vault-token-abc");
|
|
485
|
-
execScripts.set("npm ls", { error: new Error("npm not installed") });
|
|
486
|
-
execScripts.set("npm view", { error: new Error("npm not installed") });
|
|
487
460
|
|
|
488
461
|
const result = await executeAcpSpawn(
|
|
489
462
|
{ agent: "claude", task: "do something" },
|
|
@@ -514,8 +487,6 @@ describe("executeAcpSpawn — CLAUDE_CODE_OAUTH_TOKEN injection", () => {
|
|
|
514
487
|
"unknown-agent": { command: "some-other-binary", args: [] },
|
|
515
488
|
},
|
|
516
489
|
});
|
|
517
|
-
execScripts.set("npm ls", { error: new Error("npm not installed") });
|
|
518
|
-
execScripts.set("npm view", { error: new Error("npm not installed") });
|
|
519
490
|
|
|
520
491
|
const result = await executeAcpSpawn(
|
|
521
492
|
{ agent: "claude", task: "do something" },
|