@vellumai/assistant 0.8.7 → 0.8.8-dev.202606052332.17fc8ea
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/Dockerfile +20 -4
- package/bun.lock +2 -2
- package/docker-entrypoint.sh +4 -2
- package/docker-init-apt-root.sh +3 -1
- package/docker-kata-apt-env.sh +3 -1
- package/docker-kata-runtime-family.sh +12 -0
- package/docs/architecture/memory.md +1 -1
- package/examples/plugins/echo/README.md +61 -66
- 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/server-message.ts +3 -3
- package/node_modules/@vellumai/skill-host-contracts/src/skill-host.ts +7 -6
- package/openapi.yaml +3378 -335
- package/package.json +2 -2
- package/scripts/generate-openapi.ts +68 -41
- package/src/__tests__/agent-loop-exit-reason.test.ts +35 -93
- package/src/__tests__/agent-loop-provider-error-recording.test.ts +1 -1
- package/src/__tests__/agent-loop.test.ts +37 -87
- package/src/__tests__/agent-wake-disk-pressure-callsite.test.ts +2 -0
- package/src/__tests__/annotate-activity-metadata.test.ts +262 -0
- package/src/__tests__/annotate-risk-options.test.ts +2 -3
- package/src/__tests__/anthropic-provider.test.ts +95 -2
- package/src/__tests__/app-control-flow.test.ts +1 -1
- package/src/__tests__/app-dir-path-guard.test.ts +1 -0
- package/src/__tests__/approval-routes-http.test.ts +4 -1
- package/src/__tests__/assistant-event-hub.test.ts +25 -0
- package/src/__tests__/assistant-events-sse-shed.test.ts +8 -0
- package/src/__tests__/{conversation-stream-state.test.ts → assistant-stream-state.test.ts} +252 -91
- package/src/__tests__/auth-fallback-events-store.test.ts +116 -0
- package/src/__tests__/background-workers-disk-pressure.test.ts +6 -0
- package/src/__tests__/btw-routes.test.ts +62 -3
- package/src/__tests__/build-persisted-content.test.ts +184 -0
- package/src/__tests__/catalog-files.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__/clawhub-files.test.ts +1 -1
- package/src/__tests__/compaction-circuit.test.ts +258 -0
- package/src/__tests__/compaction-direct.test.ts +132 -0
- package/src/__tests__/compaction.benchmark.test.ts +0 -30
- package/src/__tests__/config-watcher.test.ts +1 -1
- package/src/__tests__/conversation-abort-tool-results.test.ts +57 -19
- package/src/__tests__/conversation-agent-loop-disk-pressure.test.ts +6 -5
- package/src/__tests__/conversation-agent-loop-inference-profile.test.ts +10 -7
- package/src/__tests__/conversation-agent-loop-overflow.test.ts +316 -1143
- package/src/__tests__/conversation-agent-loop.test.ts +638 -1655
- package/src/__tests__/conversation-analysis-routes.test.ts +6 -0
- package/src/__tests__/conversation-clean-command.test.ts +5 -2
- package/src/__tests__/conversation-history-web-search.test.ts +11 -1
- package/src/__tests__/conversation-pairing.test.ts +4 -31
- package/src/__tests__/conversation-process-app-control-preactivation.test.ts +6 -0
- package/src/__tests__/conversation-provider-retry-repair.test.ts +30 -10
- package/src/__tests__/conversation-queue.test.ts +2 -0
- package/src/__tests__/conversation-routes-disk-view.test.ts +3 -0
- package/src/__tests__/conversation-routes-slash-commands.test.ts +6 -5
- package/src/__tests__/conversation-runtime-assembly.test.ts +310 -300
- package/src/__tests__/conversation-runtime-workspace.test.ts +105 -45
- package/src/__tests__/conversation-slash-commands.test.ts +8 -42
- package/src/__tests__/conversation-slash-queue.test.ts +6 -1
- package/src/__tests__/conversation-starter-routes.test.ts +14 -6
- package/src/__tests__/conversation-surfaces-action-delivery.test.ts +84 -0
- package/src/__tests__/conversation-sync-tags.test.ts +27 -15
- package/src/__tests__/conversation-title-service.test.ts +135 -2
- package/src/__tests__/conversation-workspace-cache-state.test.ts +17 -16
- package/src/__tests__/conversation-workspace-injection.test.ts +67 -2
- package/src/__tests__/conversation-workspace-tool-tracking.test.ts +7 -6
- package/src/__tests__/conversations-import-system-filter.test.ts +101 -0
- package/src/__tests__/cross-provider-web-search.test.ts +214 -1
- package/src/__tests__/db-acp-history.test.ts +101 -0
- package/src/__tests__/db-schedule-syntax-migration.test.ts +5 -0
- package/src/__tests__/dm-persistence.test.ts +5 -1
- package/src/__tests__/dynamic-page-surface.test.ts +31 -0
- package/src/__tests__/empty-response-hook.test.ts +304 -0
- package/src/__tests__/feature-flag-test-helpers.ts +2 -2
- package/src/__tests__/file-write-tool.test.ts +63 -0
- package/src/__tests__/gateway-only-guard.test.ts +12 -2
- package/src/__tests__/gemini-image-service.test.ts +13 -0
- package/src/__tests__/guardian-grant-minting.test.ts +1 -1
- package/src/__tests__/guardian-routing-invariants.test.ts +2 -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__/helpers/mock-provider.ts +110 -0
- package/src/__tests__/helpers/native-web-search-harness.ts +129 -0
- package/src/__tests__/history-repair-hook.test.ts +1 -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__/identity-intro-cache.test.ts +12 -100
- package/src/__tests__/identity-routes.test.ts +248 -7
- package/src/__tests__/inbound-slack-persistence.test.ts +5 -1
- package/src/__tests__/injector-background-turn.test.ts +3 -9
- package/src/__tests__/injector-chain.test.ts +139 -275
- package/src/__tests__/injector-disk-pressure.test.ts +75 -41
- package/src/__tests__/injector-document-comments.test.ts +3 -3
- package/src/__tests__/injector-pkb-v2-silenced.test.ts +30 -22
- package/src/__tests__/injector-v3-suppression.test.ts +31 -37
- package/src/__tests__/internal-telemetry-routes.test.ts +109 -0
- package/src/__tests__/list-messages-hidden-metadata.test.ts +38 -0
- package/src/__tests__/list-messages-page-latest.test.ts +60 -0
- package/src/__tests__/list-messages-tool-merge.test.ts +20 -0
- package/src/__tests__/llm-usage-store.test.ts +223 -1
- package/src/__tests__/memory-retrieval-hook.test.ts +297 -0
- package/src/__tests__/memory-v2-static-injector.test.ts +103 -35
- package/src/__tests__/native-web-search.test.ts +191 -0
- package/src/__tests__/onboarding-template-contract.test.ts +2 -0
- package/src/__tests__/openai-image-service.test.ts +17 -0
- package/src/__tests__/openai-provider.test.ts +31 -1
- package/src/__tests__/{overflow-reduce-pipeline.test.ts → overflow-reduction-loop.test.ts} +64 -284
- package/src/__tests__/persist-unsendable-image.test.ts +215 -0
- package/src/__tests__/persistence-secret-redaction.test.ts +1 -0
- package/src/__tests__/pkb-autoinject.test.ts +2 -5
- package/src/__tests__/plugin-api-shim.test.ts +3 -6
- package/src/__tests__/plugin-bootstrap.test.ts +14 -40
- package/src/__tests__/plugin-registry.test.ts +3 -76
- package/src/__tests__/plugin-types.test.ts +0 -193
- package/src/__tests__/process-message-display-content.test.ts +6 -2
- package/src/__tests__/reaction-persistence.test.ts +1 -1
- package/src/__tests__/regenerate-fire-and-forget-trace.test.ts +5 -1
- package/src/__tests__/resolve-trust-class.test.ts +4 -4
- package/src/__tests__/runtime-events-sse-reconnect.test.ts +60 -23
- package/src/__tests__/schedule-routes.test.ts +603 -2
- package/src/__tests__/schedule-store.test.ts +41 -0
- package/src/__tests__/schedule-tools.test.ts +35 -0
- package/src/__tests__/send-endpoint-busy.test.ts +4 -1
- package/src/__tests__/server-history-render.test.ts +314 -1
- package/src/__tests__/skill-feature-flags-integration.test.ts +33 -0
- package/src/__tests__/skillssh-files.test.ts +1 -1
- package/src/__tests__/subagent-call-site-routing.test.ts +1 -1
- 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__/system-prompt.test.ts +20 -0
- package/src/__tests__/task-scheduler.test.ts +162 -1
- package/src/__tests__/terminal-tools.test.ts +6 -1
- package/src/__tests__/title-generate-hook.test.ts +319 -0
- package/src/__tests__/tool-error-hook.test.ts +278 -0
- package/src/__tests__/tool-preview-lifecycle.test.ts +468 -5
- package/src/__tests__/tool-result-metadata-plumbing.test.ts +1 -0
- package/src/__tests__/tool-result-truncate-hook.test.ts +127 -0
- package/src/__tests__/tool-result-truncation.test.ts +0 -2
- package/src/__tests__/ui-choice-copy-surfaces.test.ts +254 -0
- package/src/__tests__/ui-work-result-surface.test.ts +159 -0
- package/src/__tests__/usage-routes.test.ts +285 -1
- package/src/__tests__/user-plugin-loader.test.ts +54 -286
- package/src/__tests__/voice-session-bridge.test.ts +6 -3
- package/src/__tests__/web-search-backend-failure.test.ts +166 -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-history-db.ts +82 -0
- package/src/acp/__tests__/helpers/exec-file-stub.ts +101 -0
- package/src/acp/__tests__/prepare-agent-env.test.ts +137 -0
- package/src/acp/__tests__/session-manager-persistence.test.ts +95 -28
- package/src/acp/__tests__/session-manager-resume.test.ts +736 -0
- package/src/acp/agent-process.ts +61 -1
- package/src/acp/auto-install.test.ts +196 -0
- package/src/acp/auto-install.ts +177 -0
- package/src/acp/client-handler.ts +31 -0
- package/src/acp/feature-gate.test.ts +48 -0
- package/src/acp/feature-gate.ts +34 -0
- package/src/acp/prepare-agent-env.ts +83 -29
- package/src/acp/resolve-agent.test.ts +320 -7
- package/src/acp/resolve-agent.ts +182 -18
- package/src/acp/resume-hint.ts +25 -0
- package/src/acp/session-manager.ts +495 -73
- package/src/acp/types.ts +8 -0
- package/src/agent/compaction-circuit.ts +60 -102
- package/src/agent/loop.ts +362 -485
- package/src/api/events/assistant-thinking-delta.ts +33 -0
- package/src/api/events/tool-output-chunk.ts +45 -0
- package/src/api/events/tool-use-preview-start.ts +32 -0
- package/src/api/events/trace-event.ts +69 -0
- package/src/api/index.ts +48 -13
- package/src/api/responses/conversation-message.ts +374 -0
- package/src/approvals/guardian-request-resolvers.ts +1 -1
- package/src/avatar/__tests__/avatar-store.test.ts +34 -29
- package/src/background-wake/next-wake.ts +1 -0
- package/src/cli/commands/__tests__/notifications.test.ts +58 -14
- package/src/cli/commands/notifications.ts +112 -60
- 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 +6 -0
- package/src/config/assistant-feature-flags.ts +22 -11
- package/src/config/bundled-skills/acp/SKILL.md +83 -31
- package/src/config/bundled-skills/acp/TOOLS.json +4 -4
- package/src/config/bundled-skills/app-builder/SKILL.md +224 -398
- package/src/config/bundled-skills/app-builder/TOOLS.json +29 -0
- 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/references/examples/README.md +17 -0
- package/src/config/bundled-skills/app-builder/references/examples/expense-tracker.md +515 -0
- package/src/config/bundled-skills/app-builder/references/examples/focus-timer.md +342 -0
- package/src/config/bundled-skills/app-builder/references/examples/habit-tracker.md +490 -0
- package/src/config/bundled-skills/app-builder/tools/app-list.ts +62 -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-skills/messaging/SKILL.md +0 -7
- package/src/config/bundled-tool-registry.ts +2 -0
- package/src/config/feature-flag-cache.ts +3 -3
- package/src/config/feature-flag-registry.json +48 -7
- package/src/config/schemas/__tests__/memory-v2.test.ts +1 -0
- package/src/config/schemas/__tests__/memory-v3.test.ts +25 -0
- package/src/config/schemas/heartbeat.ts +9 -0
- package/src/config/schemas/llm.ts +1 -0
- package/src/config/schemas/memory-v2.ts +8 -0
- package/src/config/schemas/memory-v3.ts +8 -0
- package/src/config/schemas/platform.ts +8 -0
- package/src/config/seed-inference-profiles.ts +2 -2
- package/src/config/skills.ts +13 -0
- package/src/context/compactor.ts +1 -1
- package/src/context/strip-injections.ts +128 -0
- package/src/context/token-estimator.ts +23 -0
- package/src/context/tool-result-truncation.ts +0 -23
- package/src/context/window-manager.ts +5 -7
- package/src/credential-execution/executable-discovery.ts +16 -0
- package/src/daemon/__tests__/conversation-lifecycle-auto-analyze.test.ts +6 -0
- package/src/daemon/__tests__/inference-profile-notification.test.ts +153 -0
- package/src/daemon/__tests__/native-web-search-metadata.test.ts +10 -8
- package/src/daemon/assistant-attachments.ts +1 -1
- package/src/daemon/config-watcher.ts +2 -2
- package/src/daemon/context-overflow-reducer.ts +0 -1
- package/src/daemon/conversation-agent-loop-handlers.ts +594 -153
- package/src/daemon/conversation-agent-loop.ts +301 -997
- package/src/daemon/conversation-history.ts +5 -4
- package/src/daemon/conversation-lifecycle.ts +3 -4
- package/src/daemon/conversation-messaging.ts +7 -6
- package/src/daemon/conversation-process.ts +11 -16
- package/src/daemon/conversation-registry.ts +159 -0
- package/src/daemon/conversation-runtime-assembly.ts +218 -398
- package/src/daemon/conversation-slash.ts +6 -25
- package/src/daemon/conversation-store.ts +9 -90
- package/src/daemon/conversation-surfaces.ts +222 -4
- package/src/daemon/conversation-tool-setup.ts +2 -29
- package/src/daemon/conversation-workspace.ts +17 -0
- package/src/daemon/conversation.ts +32 -20
- package/src/daemon/external-plugins-bootstrap.ts +17 -18
- package/src/daemon/handlers/config-a2a.ts +51 -36
- package/src/daemon/handlers/config-slack-channel.ts +20 -14
- package/src/daemon/handlers/config-telegram.ts +16 -2
- package/src/daemon/handlers/conversations.ts +3 -1
- package/src/daemon/handlers/shared.ts +156 -84
- package/src/daemon/handlers/skills.ts +42 -10
- package/src/daemon/lifecycle.ts +25 -0
- package/src/daemon/message-types/apps.ts +1 -29
- package/src/daemon/message-types/messages.ts +9 -57
- package/src/daemon/message-types/skills.ts +2 -0
- package/src/daemon/message-types/surfaces.ts +136 -3
- package/src/daemon/now-scratchpad.ts +21 -0
- package/src/daemon/orphan-reaper.test.ts +210 -0
- package/src/daemon/orphan-reaper.ts +240 -0
- package/src/daemon/overflow-reduction-loop.ts +230 -0
- package/src/daemon/persist-unsendable-image.ts +117 -0
- package/src/daemon/process-message.ts +1 -3
- package/src/daemon/server.ts +2 -0
- package/src/daemon/trace-emitter.ts +6 -4
- package/src/daemon/trust-context.ts +19 -0
- package/src/daemon/wake-target-adapter.ts +3 -1
- 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/home/home-greeting-cache.ts +24 -1
- package/src/ipc/__tests__/browser-ipc.test.ts +1 -1
- package/src/ipc/__tests__/ui-request-route.test.ts +3 -3
- package/src/ipc/gateway-client.test.ts +2 -2
- package/src/ipc/gateway-client.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/media/gemini-image-service.ts +15 -0
- package/src/media/openai-image-service.ts +14 -0
- package/src/media/types.ts +34 -0
- package/src/memory/__tests__/jobs-worker-v2-schedule.test.ts +56 -0
- package/src/memory/auth-fallback-events-store.ts +94 -0
- package/src/memory/conversation-starter-checkpoints.ts +1 -0
- package/src/memory/conversation-title-service.ts +65 -41
- package/src/memory/db-init.ts +6 -0
- package/src/memory/graph/__tests__/conversation-graph-memory-registry.test.ts +119 -0
- package/src/memory/graph/conversation-graph-memory.ts +65 -0
- package/src/memory/job-handlers/conversation-starters.ts +13 -2
- package/src/memory/jobs-store.ts +33 -0
- package/src/memory/jobs-worker.ts +32 -5
- package/src/memory/llm-usage-store.ts +224 -50
- package/src/memory/migrations/222-strip-placeholder-sentinels-from-messages.ts +6 -5
- package/src/memory/migrations/270-schedule-source-conversation.ts +13 -0
- package/src/memory/migrations/271-create-auth-fallback-events.ts +21 -0
- package/src/memory/migrations/272-acp-session-history-cwd.ts +36 -0
- package/src/memory/migrations/index.ts +3 -0
- package/src/memory/pkb/autoinject.ts +61 -0
- package/src/memory/pkb/context.ts +50 -0
- package/src/memory/pkb/types.ts +14 -0
- package/src/memory/schedule-attribution-sql.ts +104 -0
- package/src/memory/schema/acp.ts +4 -0
- package/src/memory/schema/infrastructure.ts +16 -0
- package/src/memory/usage-grouped-buckets.ts +6 -1
- package/src/memory/v2/__tests__/consolidation-job.test.ts +4 -4
- package/src/memory/v2/consolidation-job.ts +14 -5
- package/src/notifications/conversation-pairing.ts +8 -15
- package/src/notifications/decision-engine.ts +6 -3
- package/src/notifications/home-feed-side-effect.ts +12 -1
- package/src/permissions/prompter.ts +4 -0
- package/src/plugin-api/constants.ts +4 -0
- package/src/plugin-api/index.ts +7 -5
- package/src/plugin-api/types.ts +151 -1
- package/src/plugins/defaults/compaction/compact.ts +59 -0
- package/src/plugins/defaults/compaction/package.json +1 -1
- package/src/plugins/defaults/compaction/register.ts +8 -19
- package/src/plugins/defaults/empty-response/hooks/stop.ts +126 -0
- package/src/plugins/defaults/empty-response/register.ts +8 -13
- package/src/plugins/defaults/index.ts +2 -18
- package/src/plugins/defaults/memory-retrieval/hooks/post-compact.ts +95 -0
- package/src/plugins/defaults/memory-retrieval/hooks/user-prompt-submit-temp.ts +216 -0
- package/src/plugins/defaults/memory-retrieval/injector-chain.ts +35 -0
- package/src/plugins/defaults/{injectors/register.ts → memory-retrieval/injectors.ts} +288 -81
- package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/__tests__/assign.test.ts +4 -4
- package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/__tests__/health.test.ts +16 -0
- package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/__tests__/live-integration.test.ts +4 -4
- package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/__tests__/maintain-job.test.ts +5 -5
- package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/__tests__/orchestrate.test.ts +48 -12
- package/src/plugins/defaults/memory-v3-shadow/__tests__/provider-blocks.test.ts +13 -0
- package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/__tests__/reconcile.test.ts +2 -2
- package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/__tests__/render-injection.test.ts +1 -1
- package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/__tests__/router.test.ts +104 -32
- package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/__tests__/selection-log-store.test.ts +8 -8
- package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/__tests__/selector.test.ts +96 -30
- package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/__tests__/shadow-plugin.test.ts +34 -16
- package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/assign.ts +5 -5
- package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/capabilities.ts +2 -2
- package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/health.ts +0 -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 +75 -0
- package/src/plugins/defaults/memory-v3-shadow/llm-retry.ts +32 -0
- package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/maintain-job.ts +8 -8
- package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/orchestrate.ts +26 -14
- package/src/plugins/defaults/{llm-call → memory-v3-shadow}/package.json +2 -2
- package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/page-content.ts +2 -2
- package/src/plugins/defaults/memory-v3-shadow/provider-blocks.ts +26 -0
- package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/reconcile.ts +3 -3
- package/src/plugins/defaults/memory-v3-shadow/register.ts +26 -0
- package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/render-injection.ts +1 -1
- package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/router.ts +51 -45
- package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/selection-log-store.ts +4 -4
- package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/selector.ts +61 -46
- package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/shadow-plugin.ts +69 -99
- package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/tree.ts +1 -1
- package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/types.ts +8 -0
- package/src/plugins/defaults/title-generate/hooks/stop.ts +75 -0
- package/src/plugins/defaults/title-generate/hooks/user-prompt-submit.ts +35 -0
- package/src/plugins/defaults/title-generate/package.json +1 -1
- package/src/plugins/defaults/title-generate/register.ts +18 -18
- package/src/plugins/defaults/tool-error/hooks/post-tool-use.ts +118 -0
- package/src/plugins/defaults/tool-error/package.json +1 -1
- package/src/plugins/defaults/tool-error/register.ts +9 -21
- package/src/plugins/defaults/tool-result-truncate/hooks/post-tool-use.ts +32 -0
- package/src/plugins/defaults/tool-result-truncate/register.ts +10 -21
- package/src/plugins/defaults/tool-result-truncate/terminal.ts +37 -18
- package/src/plugins/external-api.ts +2 -2
- package/src/plugins/pipeline.ts +6 -305
- package/src/plugins/registry.ts +10 -55
- package/src/plugins/types.ts +62 -797
- package/src/plugins/user-loader.ts +30 -127
- package/src/proactive-artifact/aux-message-injector.ts +4 -4
- package/src/proactive-artifact/job.test.ts +8 -13
- package/src/prompts/__tests__/system-prompt.test.ts +42 -0
- package/src/prompts/templates/BOOTSTRAP-ACTIVATION-RAIL.md +64 -0
- package/src/prompts/templates/BOOTSTRAP.md +2 -2
- package/src/prompts/templates/system-sections.ts +15 -0
- package/src/providers/anthropic/client.ts +37 -29
- package/src/providers/openai/__tests__/chat-completions-provider-reasoning.test.ts +112 -0
- package/src/providers/openai/chat-completions-provider.ts +44 -0
- package/src/providers/openrouter/client.ts +1 -0
- package/src/providers/placeholder-sentinels.ts +35 -0
- package/src/runtime/__tests__/agent-wake.test.ts +10 -6
- package/src/runtime/__tests__/interactive-ui.test.ts +1 -1
- package/src/runtime/agent-wake.ts +2 -5
- package/src/runtime/assistant-event-hub.ts +37 -7
- package/src/runtime/{conversation-stream-state.ts → assistant-stream-state.ts} +132 -58
- package/src/runtime/channel-approvals.ts +1 -1
- package/src/runtime/http-router.ts +16 -21
- package/src/runtime/http-types.ts +16 -70
- package/src/runtime/interactive-ui.ts +1 -1
- package/src/runtime/pending-interactions.ts +1 -0
- package/src/runtime/routes/__tests__/acp-routes.test.ts +283 -55
- package/src/runtime/routes/__tests__/consolidation-routes.test.ts +265 -2
- package/src/runtime/routes/__tests__/conversation-list-routes.test.ts +1 -1
- package/src/runtime/routes/__tests__/conversation-query-routes.test.ts +31 -1
- package/src/runtime/routes/__tests__/memory-v2-routes.test.ts +6 -2
- 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/__tests__/tts-routes.test.ts +6 -2
- package/src/runtime/routes/acp-routes.test.ts +89 -25
- package/src/runtime/routes/acp-routes.ts +81 -29
- package/src/runtime/routes/app-management-routes.ts +6 -117
- package/src/runtime/routes/app-routes.ts +13 -15
- package/src/runtime/routes/approval-routes.ts +1 -1
- package/src/runtime/routes/attachment-routes.ts +26 -15
- package/src/runtime/routes/avatar-routes.ts +26 -0
- package/src/runtime/routes/browser-routes.ts +1 -1
- package/src/runtime/routes/browser-tabs-routes.ts +6 -10
- package/src/runtime/routes/btw-routes.ts +29 -23
- package/src/runtime/routes/consolidation-routes.ts +120 -20
- 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 +3 -1
- package/src/runtime/routes/conversation-routes.ts +372 -185
- package/src/runtime/routes/conversation-starter-routes.ts +13 -7
- package/src/runtime/routes/conversations-import-routes.ts +24 -7
- package/src/runtime/routes/documents-routes.ts +4 -0
- package/src/runtime/routes/domain-routes.ts +51 -37
- package/src/runtime/routes/epoch-millis-range.ts +34 -0
- package/src/runtime/routes/events-routes.ts +28 -34
- package/src/runtime/routes/gateway-log-routes.ts +26 -4
- package/src/runtime/routes/heartbeat-routes.ts +32 -12
- 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-intro-cache.ts +11 -34
- package/src/runtime/routes/identity-routes.ts +224 -18
- package/src/runtime/routes/image-generation-routes.ts +40 -2
- package/src/runtime/routes/inbound-message-handler.ts +1 -1
- package/src/runtime/routes/index.ts +2 -0
- package/src/runtime/routes/integrations/a2a.ts +12 -10
- package/src/runtime/routes/integrations/slack/__tests__/channel.test.ts +16 -0
- package/src/runtime/routes/integrations/slack/channel.ts +4 -0
- package/src/runtime/routes/integrations/slack/share.ts +27 -6
- package/src/runtime/routes/integrations/telegram.ts +6 -0
- package/src/runtime/routes/integrations/twilio.ts +42 -0
- package/src/runtime/routes/internal-telemetry-routes.ts +88 -0
- package/src/runtime/routes/log-export-routes.ts +8 -0
- package/src/runtime/routes/memory-v2-routes.ts +15 -8
- package/src/runtime/routes/memory-v3-routes.ts +66 -34
- package/src/runtime/routes/oauth-apps.ts +66 -12
- package/src/runtime/routes/oauth-providers.ts +44 -5
- package/src/runtime/routes/platform-routes.ts +81 -5
- package/src/runtime/routes/playground/__tests__/force-compact.test.ts +6 -4
- package/src/runtime/routes/playground/force-compact.ts +1 -1
- package/src/runtime/routes/playground/helpers.ts +1 -1
- package/src/runtime/routes/rename-conversation-routes.ts +5 -0
- package/src/runtime/routes/schedule-routes.ts +152 -42
- package/src/runtime/routes/secret-routes.ts +14 -2
- package/src/runtime/routes/skills-routes.ts +43 -14
- package/src/runtime/routes/surface-conversation-resolver.ts +4 -3
- package/src/runtime/routes/tool-call-confirmation-enrichment.test.ts +161 -0
- package/src/runtime/routes/tool-call-confirmation-enrichment.ts +107 -0
- package/src/runtime/routes/trust-rules-routes.ts +26 -2
- package/src/runtime/routes/tts-routes.ts +35 -0
- package/src/runtime/routes/types.ts +66 -8
- package/src/runtime/routes/usage-routes.ts +47 -39
- package/src/runtime/routes/webhook-routes.ts +41 -2
- package/src/runtime/routes/work-items-routes.ts +2 -4
- package/src/runtime/routes/workspace-routes.ts +4 -0
- package/src/runtime/services/__tests__/analyze-conversation.test.ts +6 -0
- package/src/runtime/services/analyze-conversation.ts +2 -2
- package/src/runtime/services/conversation-serializer.ts +1 -1
- package/src/schedule/schedule-store.ts +20 -1
- package/src/schedule/schedule-usage-store.ts +83 -0
- package/src/schedule/scheduler.ts +12 -5
- package/src/signals/cancel.ts +2 -4
- package/src/skills/catalog-files.ts +2 -2
- package/src/skills/catalog-install.ts +3 -0
- package/src/skills/categories-cache.ts +118 -0
- package/src/skills/clawhub-files.ts +1 -2
- package/src/skills/skillssh-files.ts +1 -2
- package/src/subagent/manager.ts +17 -5
- package/src/telemetry/types.ts +29 -1
- package/src/telemetry/usage-telemetry-reporter.test.ts +112 -3
- package/src/telemetry/usage-telemetry-reporter.ts +57 -2
- package/src/tools/acp/context.ts +20 -0
- package/src/tools/acp/list-agents.test.ts +7 -1
- package/src/tools/acp/spawn.test.ts +158 -55
- package/src/tools/acp/spawn.ts +47 -72
- package/src/tools/acp/steer.test.ts +105 -8
- package/src/tools/acp/steer.ts +48 -17
- package/src/tools/apps/executors.ts +13 -8
- package/src/tools/executor.ts +1 -53
- package/src/tools/filesystem/write.ts +34 -0
- package/src/tools/network/__tests__/web-search-metadata.test.ts +7 -1
- package/src/tools/network/__tests__/web-search.test.ts +11 -3
- package/src/tools/network/web-search-error.test.ts +248 -0
- package/src/tools/network/web-search-error.ts +267 -0
- package/src/tools/network/web-search.ts +207 -48
- package/src/tools/schedule/create.ts +2 -0
- package/src/tools/subagent/spawn.ts +2 -4
- package/src/tools/terminal/safe-env.ts +10 -1
- package/src/tools/ui-surface/definitions.ts +34 -5
- package/src/tts/__tests__/provider-catalog-consistency.test.ts +85 -1
- package/src/tts/provider-catalog.ts +76 -1
- package/src/util/mutex.ts +47 -0
- package/src/workspace/git-service.ts +1 -42
- package/src/workspace/migrations/051-seed-conversation-summarization-callsite.ts +4 -5
- package/src/workspace/migrations/095-bump-heartbeat-interval-30m-to-60m.ts +51 -0
- package/src/workspace/migrations/096-reduce-quality-profile-effort.ts +72 -0
- package/src/workspace/migrations/097-enable-adaptive-thinking-managed-profiles.ts +117 -0
- package/src/workspace/migrations/registry.ts +6 -0
- package/docs/plugins.md +0 -836
- package/examples/plugins/echo/register.ts +0 -184
- package/src/__tests__/bootstrap-turn-cleanup.test.ts +0 -44
- 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__/empty-response-pipeline.test.ts +0 -423
- package/src/__tests__/llm-call-pipeline.test.ts +0 -287
- package/src/__tests__/memory-retrieval-pipeline.test.ts +0 -418
- package/src/__tests__/persistence-pipeline.test.ts +0 -503
- package/src/__tests__/pipeline-runner.test.ts +0 -564
- package/src/__tests__/title-generate-pipeline.test.ts +0 -211
- package/src/__tests__/token-estimate-pipeline.test.ts +0 -479
- package/src/__tests__/tool-error-pipeline.test.ts +0 -241
- package/src/__tests__/tool-execute-pipeline.test.ts +0 -417
- package/src/__tests__/tool-result-truncate-pipeline.test.ts +0 -341
- package/src/daemon/bootstrap-turn-cleanup.ts +0 -45
- package/src/gallery/default-gallery.ts +0 -1359
- package/src/gallery/gallery-manifest.ts +0 -28
- package/src/home/feature-gate.ts +0 -22
- package/src/memory/v3/provider-blocks.ts +0 -16
- 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/terminal.ts +0 -73
- package/src/plugins/defaults/empty-response/middlewares/emptyResponse.ts +0 -22
- package/src/plugins/defaults/empty-response/terminal.ts +0 -106
- package/src/plugins/defaults/injectors/package.json +0 -15
- package/src/plugins/defaults/llm-call/middlewares/llmCall.ts +0 -17
- package/src/plugins/defaults/llm-call/register.ts +0 -45
- package/src/plugins/defaults/memory-retrieval/middlewares/memoryRetrieval.ts +0 -17
- package/src/plugins/defaults/memory-retrieval/package.json +0 -15
- package/src/plugins/defaults/memory-retrieval/register.ts +0 -181
- 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/persistence/middlewares/persistence.ts +0 -19
- package/src/plugins/defaults/persistence/package.json +0 -15
- package/src/plugins/defaults/persistence/register.ts +0 -38
- package/src/plugins/defaults/persistence/terminal.ts +0 -83
- package/src/plugins/defaults/title-generate/terminal.ts +0 -31
- package/src/plugins/defaults/token-estimate/middlewares/tokenEstimate.ts +0 -23
- package/src/plugins/defaults/token-estimate/package.json +0 -15
- package/src/plugins/defaults/token-estimate/register.ts +0 -34
- package/src/plugins/defaults/token-estimate/terminal.ts +0 -40
- package/src/plugins/defaults/tool-error/middlewares/toolError.ts +0 -21
- package/src/plugins/defaults/tool-error/terminal.ts +0 -47
- package/src/plugins/defaults/tool-execute/middlewares/toolExecute.ts +0 -23
- package/src/plugins/defaults/tool-execute/package.json +0 -15
- package/src/plugins/defaults/tool-execute/register.ts +0 -49
- package/src/plugins/defaults/tool-result-truncate/middlewares/toolResultTruncate.ts +0 -23
- package/src/plugins/defaults/tool-result-truncate/types.ts +0 -22
- package/src/skills/category-inference.ts +0 -111
- /package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/__tests__/capabilities.test.ts +0 -0
- /package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/__tests__/core.test.ts +0 -0
- /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__/needle.test.ts +0 -0
- /package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/__tests__/snapshot.test.ts +0 -0
- /package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/__tests__/tree.test.ts +0 -0
- /package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/__tests__/types.test.ts +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}/core.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}/needle.ts +0 -0
- /package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/snapshot.ts +0 -0
- /package/src/{memory/v3 → plugins/defaults/memory-v3-shadow}/working-set.ts +0 -0
|
@@ -20,56 +20,91 @@
|
|
|
20
20
|
* owns the plaintext read boundary.
|
|
21
21
|
*/
|
|
22
22
|
|
|
23
|
-
import { basename } from "node:path";
|
|
24
|
-
|
|
25
23
|
import { FailedDependencyError } from "../runtime/routes/errors.js";
|
|
26
24
|
import { credentialBroker } from "../tools/credentials/broker.js";
|
|
27
25
|
import {
|
|
28
26
|
getCredentialMetadata,
|
|
29
27
|
upsertCredentialMetadata,
|
|
30
28
|
} from "../tools/credentials/metadata-store.js";
|
|
29
|
+
import { getLogger } from "../util/logger.js";
|
|
30
|
+
import { adapterCommandOf } from "./resolve-agent.js";
|
|
31
31
|
import type { AcpAgentConfig } from "./types.js";
|
|
32
32
|
|
|
33
|
+
const log = getLogger("acp:prepare-agent-env");
|
|
34
|
+
|
|
33
35
|
const ACP_SPAWN_TOOL = "acp_spawn";
|
|
36
|
+
const ACP_SERVICE = "acp";
|
|
34
37
|
|
|
35
38
|
/**
|
|
36
|
-
* Ensure
|
|
37
|
-
*
|
|
39
|
+
* Ensure an `acp/<field>` credential has metadata that allows the
|
|
40
|
+
* `acp_spawn` tool to read it, but only for legacy/unmanaged cases:
|
|
38
41
|
*
|
|
39
|
-
* - No metadata at all
|
|
40
|
-
* - Metadata exists with an empty `allowedTools
|
|
42
|
+
* - No metadata at all: create with `allowedTools: ["acp_spawn"]`.
|
|
43
|
+
* - Metadata exists with an empty `allowedTools`: default provisioning
|
|
41
44
|
* path (user ran `credentials set` without `--allowed-tools`), add it.
|
|
42
|
-
* - Metadata exists with a non-empty `allowedTools
|
|
43
|
-
* by the user/admin. Respect it even if `acp_spawn` is absent
|
|
44
|
-
* broker will deny the read and the
|
|
45
|
+
* - Metadata exists with a non-empty `allowedTools`: explicit policy set
|
|
46
|
+
* by the user/admin. Respect it even if `acp_spawn` is absent; the
|
|
47
|
+
* broker will deny the read and the caller decides whether that's fatal.
|
|
45
48
|
*/
|
|
46
|
-
function
|
|
47
|
-
|
|
49
|
+
function ensureAcpCredentialPolicy(
|
|
50
|
+
field: string,
|
|
51
|
+
usageDescription: string,
|
|
52
|
+
): void {
|
|
53
|
+
const meta = getCredentialMetadata(ACP_SERVICE, field);
|
|
48
54
|
if (!meta) {
|
|
49
|
-
upsertCredentialMetadata(
|
|
55
|
+
upsertCredentialMetadata(ACP_SERVICE, field, {
|
|
50
56
|
allowedTools: [ACP_SPAWN_TOOL],
|
|
51
|
-
usageDescription
|
|
52
|
-
"Claude OAuth token for ACP agent authentication",
|
|
57
|
+
usageDescription,
|
|
53
58
|
});
|
|
54
59
|
return;
|
|
55
60
|
}
|
|
56
61
|
const tools = meta.allowedTools ?? [];
|
|
57
62
|
if (tools.length === 0) {
|
|
58
|
-
upsertCredentialMetadata(
|
|
63
|
+
upsertCredentialMetadata(ACP_SERVICE, field, {
|
|
59
64
|
allowedTools: [ACP_SPAWN_TOOL],
|
|
60
65
|
});
|
|
61
66
|
}
|
|
62
67
|
}
|
|
63
68
|
|
|
69
|
+
/**
|
|
70
|
+
* Read an `acp/<field>` credential through the broker and inject it into
|
|
71
|
+
* `env` under `envVar`. Returns the broker's failure reason when the value
|
|
72
|
+
* was not injected (missing credential, denied policy, no stored value),
|
|
73
|
+
* or undefined on success. Never throws: `serverUse` signals every failure
|
|
74
|
+
* mode, including a simply-absent credential, as `{ success: false,
|
|
75
|
+
* reason }`, so callers choose whether a miss is fatal.
|
|
76
|
+
*/
|
|
77
|
+
async function injectCredential(
|
|
78
|
+
env: Record<string, string>,
|
|
79
|
+
field: string,
|
|
80
|
+
envVar: string,
|
|
81
|
+
usageDescription: string,
|
|
82
|
+
): Promise<string | undefined> {
|
|
83
|
+
ensureAcpCredentialPolicy(field, usageDescription);
|
|
84
|
+
const result = await credentialBroker.serverUse<void>({
|
|
85
|
+
service: ACP_SERVICE,
|
|
86
|
+
field,
|
|
87
|
+
toolName: ACP_SPAWN_TOOL,
|
|
88
|
+
execute: async (value) => {
|
|
89
|
+
env[envVar] = value;
|
|
90
|
+
},
|
|
91
|
+
});
|
|
92
|
+
return result.success ? undefined : result.reason;
|
|
93
|
+
}
|
|
94
|
+
|
|
64
95
|
/**
|
|
65
96
|
* Returns a NEW config with any required credentials merged into `env`.
|
|
66
97
|
* Does NOT mutate the input. Throws `FailedDependencyError` if a required
|
|
67
98
|
* credential is missing from both the user-supplied env override and the
|
|
68
99
|
* secure store.
|
|
69
100
|
*
|
|
70
|
-
* Gating is keyed off the
|
|
71
|
-
*
|
|
72
|
-
*
|
|
101
|
+
* Gating is keyed off the canonical adapter identity (`adapterCommand` set
|
|
102
|
+
* by the resolver, falling back to the command basename for plain configs),
|
|
103
|
+
* not the user-facing agent id. A custom `acp.agents.my-claude = { command:
|
|
104
|
+
* "claude-agent-acp", ... }` alias still gets the env it needs, and so does
|
|
105
|
+
* the bunx-rewritten claude adapter (whose `command` is "bun"). Without
|
|
106
|
+
* the adapterCommand gate, bunx-resolved spawns would start with no auth
|
|
107
|
+
* and die as zombies on the first prompt.
|
|
73
108
|
*
|
|
74
109
|
* For `claude-agent-acp` the only required env var is
|
|
75
110
|
* `CLAUDE_CODE_OAUTH_TOKEN`. Two provisioning routes converge on it, with
|
|
@@ -84,6 +119,11 @@ function ensureAcpTokenPolicy(): void {
|
|
|
84
119
|
* before spawning. The "fail-fast" throw is symmetric with the existing
|
|
85
120
|
* `binary_not_found` preflight in `resolveAcpAgent` and strictly better
|
|
86
121
|
* than a `warn` + zombie subprocess 10 seconds later.
|
|
122
|
+
*
|
|
123
|
+
* For `gemini` the env var is `GEMINI_API_KEY`, provisioned the same two
|
|
124
|
+
* ways (config.json override wins, vault field `gemini_api_key` second),
|
|
125
|
+
* but it is OPTIONAL: the Gemini CLI supports its own OAuth login, so a
|
|
126
|
+
* vault miss proceeds without the key instead of failing the spawn.
|
|
87
127
|
*/
|
|
88
128
|
export async function prepareAgentEnv(
|
|
89
129
|
agentConfig: AcpAgentConfig,
|
|
@@ -92,19 +132,16 @@ export async function prepareAgentEnv(
|
|
|
92
132
|
// agent reference. The local `env` binding sidesteps TS narrowing
|
|
93
133
|
// limitations on the optional `AcpAgentConfig.env` field.
|
|
94
134
|
const env: Record<string, string> = { ...(agentConfig.env ?? {}) };
|
|
95
|
-
const
|
|
135
|
+
const adapterCommand = adapterCommandOf(agentConfig);
|
|
96
136
|
|
|
97
|
-
if (
|
|
137
|
+
if (adapterCommand === "claude-agent-acp") {
|
|
98
138
|
if (!env.CLAUDE_CODE_OAUTH_TOKEN) {
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
env.CLAUDE_CODE_OAUTH_TOKEN = token;
|
|
106
|
-
},
|
|
107
|
-
});
|
|
139
|
+
await injectCredential(
|
|
140
|
+
env,
|
|
141
|
+
"claude_oauth_token",
|
|
142
|
+
"CLAUDE_CODE_OAUTH_TOKEN",
|
|
143
|
+
"Claude OAuth token for ACP agent authentication",
|
|
144
|
+
);
|
|
108
145
|
}
|
|
109
146
|
if (!env.CLAUDE_CODE_OAUTH_TOKEN) {
|
|
110
147
|
throw new FailedDependencyError(
|
|
@@ -113,6 +150,23 @@ export async function prepareAgentEnv(
|
|
|
113
150
|
"(or set it under acp.agents.<id>.env in config.json).",
|
|
114
151
|
);
|
|
115
152
|
}
|
|
153
|
+
} else if (adapterCommand === "gemini") {
|
|
154
|
+
if (!env.GEMINI_API_KEY) {
|
|
155
|
+
const missReason = await injectCredential(
|
|
156
|
+
env,
|
|
157
|
+
"gemini_api_key",
|
|
158
|
+
"GEMINI_API_KEY",
|
|
159
|
+
"Gemini API key for ACP agent authentication",
|
|
160
|
+
);
|
|
161
|
+
if (missReason !== undefined) {
|
|
162
|
+
// Optional credential: Gemini CLI can authenticate via its own
|
|
163
|
+
// OAuth login, so a vault miss must not fail the spawn.
|
|
164
|
+
log.debug(
|
|
165
|
+
{ reason: missReason },
|
|
166
|
+
"Gemini API key unavailable from the vault; spawning without GEMINI_API_KEY",
|
|
167
|
+
);
|
|
168
|
+
}
|
|
169
|
+
}
|
|
116
170
|
}
|
|
117
171
|
|
|
118
172
|
return { ...agentConfig, env };
|
|
@@ -1,19 +1,26 @@
|
|
|
1
1
|
import { afterAll, beforeEach, describe, expect, test } from "bun:test";
|
|
2
2
|
|
|
3
|
+
import { setOverridesForTesting } from "../__tests__/feature-flag-test-helpers.js";
|
|
3
4
|
import { installAcpConfigStub } from "./__tests__/helpers/acp-config-stub.js";
|
|
4
5
|
import { installWhichStub } from "./__tests__/helpers/which-stub.js";
|
|
6
|
+
import { ACP_FLAG_KEY } from "./feature-gate.js";
|
|
5
7
|
|
|
6
8
|
const config = await installAcpConfigStub();
|
|
7
9
|
const which = installWhichStub();
|
|
8
10
|
|
|
9
11
|
afterAll(() => {
|
|
10
12
|
which.restore();
|
|
13
|
+
setOverridesForTesting({});
|
|
11
14
|
});
|
|
12
15
|
|
|
13
|
-
const { resolveAcpAgent, listAcpAgents } =
|
|
16
|
+
const { resolveAcpAgent, listAcpAgents, adapterCommandOf, runsViaBunx } =
|
|
17
|
+
await import("./resolve-agent.js");
|
|
14
18
|
|
|
15
19
|
beforeEach(() => {
|
|
16
20
|
config.setConfig({});
|
|
21
|
+
// Default: no flag overrides, so the `acp` flag falls back to its registry
|
|
22
|
+
// default (false) and enablement comes from the config stub alone.
|
|
23
|
+
setOverridesForTesting({});
|
|
17
24
|
// Default: every command on PATH so binary preflight passes unless a test
|
|
18
25
|
// explicitly says otherwise.
|
|
19
26
|
which.setWhich((cmd) => `/usr/local/bin/${cmd}`);
|
|
@@ -24,7 +31,7 @@ beforeEach(() => {
|
|
|
24
31
|
// ---------------------------------------------------------------------------
|
|
25
32
|
|
|
26
33
|
describe("resolveAcpAgent", () => {
|
|
27
|
-
test("returns acp_disabled when config.acp.enabled
|
|
34
|
+
test("returns acp_disabled when both the feature flag and config.acp.enabled are off", () => {
|
|
28
35
|
config.setConfig({ enabled: false });
|
|
29
36
|
|
|
30
37
|
const result = resolveAcpAgent("claude");
|
|
@@ -33,10 +40,23 @@ describe("resolveAcpAgent", () => {
|
|
|
33
40
|
if (result.ok) return;
|
|
34
41
|
expect(result.reason).toBe("acp_disabled");
|
|
35
42
|
if (result.reason !== "acp_disabled") return;
|
|
43
|
+
expect(result.hint).toContain("ACP Coding Agents");
|
|
44
|
+
expect(result.hint).toContain("feature flag");
|
|
36
45
|
expect(result.hint).toContain("acp.enabled");
|
|
37
46
|
expect(result.hint).toContain("config.json");
|
|
38
47
|
});
|
|
39
48
|
|
|
49
|
+
test("resolution proceeds when the acp feature flag is on and config.acp.enabled is false", () => {
|
|
50
|
+
config.setConfig({ enabled: false });
|
|
51
|
+
setOverridesForTesting({ [ACP_FLAG_KEY]: true });
|
|
52
|
+
|
|
53
|
+
const result = resolveAcpAgent("claude");
|
|
54
|
+
|
|
55
|
+
expect(result.ok).toBe(true);
|
|
56
|
+
if (!result.ok) return;
|
|
57
|
+
expect(result.agent.command).toBe("claude-agent-acp");
|
|
58
|
+
});
|
|
59
|
+
|
|
40
60
|
test("user config wins over default profile", () => {
|
|
41
61
|
config.setConfig({
|
|
42
62
|
agents: {
|
|
@@ -78,6 +98,79 @@ describe("resolveAcpAgent", () => {
|
|
|
78
98
|
expect(result.agent.command).toBe("claude-agent-acp");
|
|
79
99
|
});
|
|
80
100
|
|
|
101
|
+
test("falls back to the gemini default profile when no user entry", () => {
|
|
102
|
+
config.setConfig({ agents: {} });
|
|
103
|
+
|
|
104
|
+
const result = resolveAcpAgent("gemini");
|
|
105
|
+
|
|
106
|
+
expect(result.ok).toBe(true);
|
|
107
|
+
if (!result.ok) return;
|
|
108
|
+
expect(result.agent.command).toBe("gemini");
|
|
109
|
+
expect(result.agent.args).toEqual(["--acp"]);
|
|
110
|
+
});
|
|
111
|
+
|
|
112
|
+
test.each([
|
|
113
|
+
["claude code", "claude-agent-acp"],
|
|
114
|
+
["Claude Code", "claude-agent-acp"],
|
|
115
|
+
["claude-code", "claude-agent-acp"],
|
|
116
|
+
["claude_code", "claude-agent-acp"],
|
|
117
|
+
["codex cli", "codex-acp"],
|
|
118
|
+
["OpenAI Codex", "codex-acp"],
|
|
119
|
+
["gemini cli", "gemini"],
|
|
120
|
+
["Gemini CLI", "gemini"],
|
|
121
|
+
["google gemini", "gemini"],
|
|
122
|
+
])("alias %p resolves to the %p profile", (alias, command) => {
|
|
123
|
+
config.setConfig({ agents: {} });
|
|
124
|
+
|
|
125
|
+
const result = resolveAcpAgent(alias);
|
|
126
|
+
|
|
127
|
+
expect(result.ok).toBe(true);
|
|
128
|
+
if (!result.ok) return;
|
|
129
|
+
expect(result.agent.command).toBe(command);
|
|
130
|
+
});
|
|
131
|
+
|
|
132
|
+
test("user config entry literally keyed 'claude code' beats the alias", () => {
|
|
133
|
+
config.setConfig({
|
|
134
|
+
agents: {
|
|
135
|
+
"claude code": {
|
|
136
|
+
command: "my-claude-fork",
|
|
137
|
+
args: [],
|
|
138
|
+
description: "user-defined agent that happens to share an alias",
|
|
139
|
+
},
|
|
140
|
+
},
|
|
141
|
+
});
|
|
142
|
+
|
|
143
|
+
const result = resolveAcpAgent("claude code");
|
|
144
|
+
|
|
145
|
+
expect(result.ok).toBe(true);
|
|
146
|
+
if (!result.ok) return;
|
|
147
|
+
expect(result.agent.command).toBe("my-claude-fork");
|
|
148
|
+
});
|
|
149
|
+
|
|
150
|
+
test("alias re-runs the normal lookup, so a user override of the canonical id wins", () => {
|
|
151
|
+
config.setConfig({
|
|
152
|
+
agents: {
|
|
153
|
+
claude: { command: "my-custom-claude", args: [] },
|
|
154
|
+
},
|
|
155
|
+
});
|
|
156
|
+
|
|
157
|
+
const result = resolveAcpAgent("claude code");
|
|
158
|
+
|
|
159
|
+
expect(result.ok).toBe(true);
|
|
160
|
+
if (!result.ok) return;
|
|
161
|
+
expect(result.agent.command).toBe("my-custom-claude");
|
|
162
|
+
});
|
|
163
|
+
|
|
164
|
+
test("non-alias unknown id still returns unknown_agent", () => {
|
|
165
|
+
config.setConfig({ agents: {} });
|
|
166
|
+
|
|
167
|
+
const result = resolveAcpAgent("cursor cli");
|
|
168
|
+
|
|
169
|
+
expect(result.ok).toBe(false);
|
|
170
|
+
if (result.ok) return;
|
|
171
|
+
expect(result.reason).toBe("unknown_agent");
|
|
172
|
+
});
|
|
173
|
+
|
|
81
174
|
test("returns unknown_agent with merged available list when id not found", () => {
|
|
82
175
|
config.setConfig({
|
|
83
176
|
agents: {
|
|
@@ -92,7 +185,12 @@ describe("resolveAcpAgent", () => {
|
|
|
92
185
|
expect(result.reason).toBe("unknown_agent");
|
|
93
186
|
if (result.reason !== "unknown_agent") return;
|
|
94
187
|
// Defaults plus user-only ids, deduped, in stable order (defaults first).
|
|
95
|
-
expect(result.available).toEqual([
|
|
188
|
+
expect(result.available).toEqual([
|
|
189
|
+
"claude",
|
|
190
|
+
"codex",
|
|
191
|
+
"gemini",
|
|
192
|
+
"user-only",
|
|
193
|
+
]);
|
|
96
194
|
});
|
|
97
195
|
|
|
98
196
|
test("unknown_agent available list contains both defaults when user config is empty", () => {
|
|
@@ -106,6 +204,7 @@ describe("resolveAcpAgent", () => {
|
|
|
106
204
|
if (result.reason !== "unknown_agent") return;
|
|
107
205
|
expect(result.available).toContain("claude");
|
|
108
206
|
expect(result.available).toContain("codex");
|
|
207
|
+
expect(result.available).toContain("gemini");
|
|
109
208
|
});
|
|
110
209
|
|
|
111
210
|
test("returns binary_not_found with the registered install hint", () => {
|
|
@@ -200,6 +299,158 @@ describe("resolveAcpAgent", () => {
|
|
|
200
299
|
if (!result.ok) return;
|
|
201
300
|
expect(result.agent.args).toEqual(["--verbose"]);
|
|
202
301
|
});
|
|
302
|
+
|
|
303
|
+
test("direct resolution sets adapterCommand to the command basename", () => {
|
|
304
|
+
config.setConfig({
|
|
305
|
+
agents: {
|
|
306
|
+
custom: { command: "/opt/bin/claude-agent-acp", args: [] },
|
|
307
|
+
},
|
|
308
|
+
});
|
|
309
|
+
|
|
310
|
+
const direct = resolveAcpAgent("claude");
|
|
311
|
+
expect(direct.ok).toBe(true);
|
|
312
|
+
if (!direct.ok) return;
|
|
313
|
+
expect(direct.agent.adapterCommand).toBe("claude-agent-acp");
|
|
314
|
+
expect(runsViaBunx(direct.agent)).toBe(false);
|
|
315
|
+
|
|
316
|
+
const fullPath = resolveAcpAgent("custom");
|
|
317
|
+
expect(fullPath.ok).toBe(true);
|
|
318
|
+
if (!fullPath.ok) return;
|
|
319
|
+
expect(fullPath.agent.adapterCommand).toBe("claude-agent-acp");
|
|
320
|
+
});
|
|
321
|
+
});
|
|
322
|
+
|
|
323
|
+
// ---------------------------------------------------------------------------
|
|
324
|
+
// resolveAcpAgent - bunx fallback for missing binaries
|
|
325
|
+
// ---------------------------------------------------------------------------
|
|
326
|
+
|
|
327
|
+
describe("resolveAcpAgent - bunx fallback", () => {
|
|
328
|
+
test("binary missing + bun present: rewrites to `bun x --bun <pkg>` with adapterCommand preserved", () => {
|
|
329
|
+
config.setConfig({ agents: {} });
|
|
330
|
+
which.setWhich({ bun: "/usr/local/bin/bun" });
|
|
331
|
+
|
|
332
|
+
const result = resolveAcpAgent("claude");
|
|
333
|
+
|
|
334
|
+
expect(result.ok).toBe(true);
|
|
335
|
+
if (!result.ok) return;
|
|
336
|
+
expect(result.agent.command).toBe("bun");
|
|
337
|
+
expect(result.agent.args).toEqual([
|
|
338
|
+
"x",
|
|
339
|
+
"--bun",
|
|
340
|
+
"@agentclientprotocol/claude-agent-acp",
|
|
341
|
+
]);
|
|
342
|
+
expect(result.agent.adapterCommand).toBe("claude-agent-acp");
|
|
343
|
+
expect(runsViaBunx(result.agent)).toBe(true);
|
|
344
|
+
expect(adapterCommandOf(result.agent)).toBe("claude-agent-acp");
|
|
345
|
+
});
|
|
346
|
+
|
|
347
|
+
test("bunx rewrite appends the original args after the package (gemini --acp)", () => {
|
|
348
|
+
config.setConfig({ agents: {} });
|
|
349
|
+
which.setWhich({ bun: "/usr/local/bin/bun" });
|
|
350
|
+
|
|
351
|
+
const result = resolveAcpAgent("gemini");
|
|
352
|
+
|
|
353
|
+
expect(result.ok).toBe(true);
|
|
354
|
+
if (!result.ok) return;
|
|
355
|
+
expect(result.agent.command).toBe("bun");
|
|
356
|
+
expect(result.agent.args).toEqual([
|
|
357
|
+
"x",
|
|
358
|
+
"--bun",
|
|
359
|
+
"@google/gemini-cli",
|
|
360
|
+
"--acp",
|
|
361
|
+
]);
|
|
362
|
+
expect(result.agent.adapterCommand).toBe("gemini");
|
|
363
|
+
});
|
|
364
|
+
|
|
365
|
+
test("bunx rewrite leaves env unchanged", () => {
|
|
366
|
+
config.setConfig({
|
|
367
|
+
agents: {
|
|
368
|
+
claude: {
|
|
369
|
+
command: "claude-agent-acp",
|
|
370
|
+
args: [],
|
|
371
|
+
env: { KEEP_ME: "yes" },
|
|
372
|
+
},
|
|
373
|
+
},
|
|
374
|
+
});
|
|
375
|
+
which.setWhich({ bun: "/usr/local/bin/bun" });
|
|
376
|
+
|
|
377
|
+
const result = resolveAcpAgent("claude");
|
|
378
|
+
|
|
379
|
+
expect(result.ok).toBe(true);
|
|
380
|
+
if (!result.ok) return;
|
|
381
|
+
expect(result.agent.command).toBe("bun");
|
|
382
|
+
expect(result.agent.env).toEqual({ KEEP_ME: "yes" });
|
|
383
|
+
});
|
|
384
|
+
|
|
385
|
+
test("bun lookup honors agent.env.PATH override (matches spawn env)", () => {
|
|
386
|
+
config.setConfig({
|
|
387
|
+
agents: {
|
|
388
|
+
claude: {
|
|
389
|
+
command: "claude-agent-acp",
|
|
390
|
+
args: [],
|
|
391
|
+
env: { PATH: "/opt/custom/bin" },
|
|
392
|
+
},
|
|
393
|
+
},
|
|
394
|
+
});
|
|
395
|
+
which.setWhich((cmd, options) =>
|
|
396
|
+
cmd === "bun" && options?.PATH === "/opt/custom/bin"
|
|
397
|
+
? "/opt/custom/bin/bun"
|
|
398
|
+
: null,
|
|
399
|
+
);
|
|
400
|
+
|
|
401
|
+
const result = resolveAcpAgent("claude");
|
|
402
|
+
|
|
403
|
+
expect(result.ok).toBe(true);
|
|
404
|
+
if (!result.ok) return;
|
|
405
|
+
expect(result.agent.command).toBe("bun");
|
|
406
|
+
});
|
|
407
|
+
|
|
408
|
+
test("user-config command without a package mapping is NOT rewritten even when bun is present", () => {
|
|
409
|
+
config.setConfig({
|
|
410
|
+
agents: {
|
|
411
|
+
custom: { command: "unknown-binary", args: [] },
|
|
412
|
+
},
|
|
413
|
+
});
|
|
414
|
+
which.setWhich({ bun: "/usr/local/bin/bun" });
|
|
415
|
+
|
|
416
|
+
const result = resolveAcpAgent("custom");
|
|
417
|
+
|
|
418
|
+
expect(result.ok).toBe(false);
|
|
419
|
+
if (result.ok) return;
|
|
420
|
+
expect(result.reason).toBe("binary_not_found");
|
|
421
|
+
});
|
|
422
|
+
|
|
423
|
+
test("binary missing + bun missing: binary_not_found with the npm hint", () => {
|
|
424
|
+
config.setConfig({ agents: {} });
|
|
425
|
+
which.setWhich({});
|
|
426
|
+
|
|
427
|
+
const result = resolveAcpAgent("claude");
|
|
428
|
+
|
|
429
|
+
expect(result.ok).toBe(false);
|
|
430
|
+
if (result.ok) return;
|
|
431
|
+
expect(result.reason).toBe("binary_not_found");
|
|
432
|
+
if (result.reason !== "binary_not_found") return;
|
|
433
|
+
expect(result.hint).toBe("npm i -g @agentclientprotocol/claude-agent-acp");
|
|
434
|
+
});
|
|
435
|
+
});
|
|
436
|
+
|
|
437
|
+
// ---------------------------------------------------------------------------
|
|
438
|
+
// adapterCommandOf - fallback for plain configs
|
|
439
|
+
// ---------------------------------------------------------------------------
|
|
440
|
+
|
|
441
|
+
describe("adapterCommandOf", () => {
|
|
442
|
+
test("falls back to the command basename for configs without adapterCommand", () => {
|
|
443
|
+
expect(adapterCommandOf({ command: "/opt/bin/claude-agent-acp" })).toBe(
|
|
444
|
+
"claude-agent-acp",
|
|
445
|
+
);
|
|
446
|
+
expect(adapterCommandOf({ command: "codex-acp" })).toBe("codex-acp");
|
|
447
|
+
});
|
|
448
|
+
|
|
449
|
+
test("prefers an explicit adapterCommand over the command", () => {
|
|
450
|
+
expect(
|
|
451
|
+
adapterCommandOf({ command: "bun", adapterCommand: "claude-agent-acp" }),
|
|
452
|
+
).toBe("claude-agent-acp");
|
|
453
|
+
});
|
|
203
454
|
});
|
|
204
455
|
|
|
205
456
|
// ---------------------------------------------------------------------------
|
|
@@ -207,7 +458,7 @@ describe("resolveAcpAgent", () => {
|
|
|
207
458
|
// ---------------------------------------------------------------------------
|
|
208
459
|
|
|
209
460
|
describe("listAcpAgents", () => {
|
|
210
|
-
test("returns enabled: false with empty agents when
|
|
461
|
+
test("returns enabled: false with empty agents when both the flag and config are off", () => {
|
|
211
462
|
config.setConfig({ enabled: false });
|
|
212
463
|
|
|
213
464
|
const result = listAcpAgents();
|
|
@@ -216,14 +467,28 @@ describe("listAcpAgents", () => {
|
|
|
216
467
|
expect(result.agents).toEqual([]);
|
|
217
468
|
});
|
|
218
469
|
|
|
219
|
-
test("
|
|
470
|
+
test("returns the catalog when the acp feature flag is on and config.acp.enabled is false", () => {
|
|
471
|
+
config.setConfig({ enabled: false });
|
|
472
|
+
setOverridesForTesting({ [ACP_FLAG_KEY]: true });
|
|
473
|
+
|
|
474
|
+
const result = listAcpAgents();
|
|
475
|
+
|
|
476
|
+
expect(result.enabled).toBe(true);
|
|
477
|
+
expect(result.agents.map((a) => a.id)).toEqual([
|
|
478
|
+
"claude",
|
|
479
|
+
"codex",
|
|
480
|
+
"gemini",
|
|
481
|
+
]);
|
|
482
|
+
});
|
|
483
|
+
|
|
484
|
+
test("includes all bundled defaults when user config is empty", () => {
|
|
220
485
|
config.setConfig({ agents: {} });
|
|
221
486
|
|
|
222
487
|
const result = listAcpAgents();
|
|
223
488
|
|
|
224
489
|
expect(result.enabled).toBe(true);
|
|
225
490
|
const ids = result.agents.map((a) => a.id);
|
|
226
|
-
expect(ids).toEqual(["claude", "codex"]);
|
|
491
|
+
expect(ids).toEqual(["claude", "codex", "gemini"]);
|
|
227
492
|
for (const entry of result.agents) {
|
|
228
493
|
expect(entry.source).toBe("default");
|
|
229
494
|
expect(entry.available).toBe(true);
|
|
@@ -245,6 +510,7 @@ describe("listAcpAgents", () => {
|
|
|
245
510
|
which.setWhich({
|
|
246
511
|
"my-claude": "/usr/bin/my-claude",
|
|
247
512
|
"codex-acp": "/usr/bin/codex-acp",
|
|
513
|
+
gemini: "/usr/bin/gemini",
|
|
248
514
|
});
|
|
249
515
|
|
|
250
516
|
const result = listAcpAgents();
|
|
@@ -257,6 +523,25 @@ describe("listAcpAgents", () => {
|
|
|
257
523
|
expect(codex?.source).toBe("default");
|
|
258
524
|
});
|
|
259
525
|
|
|
526
|
+
test("missing binaries with bun present are listed available (bunx fallback)", () => {
|
|
527
|
+
config.setConfig({ agents: {} });
|
|
528
|
+
which.setWhich({ bun: "/usr/local/bin/bun" });
|
|
529
|
+
|
|
530
|
+
const result = listAcpAgents();
|
|
531
|
+
|
|
532
|
+
for (const entry of result.agents) {
|
|
533
|
+
expect(entry.available).toBe(true);
|
|
534
|
+
expect(entry.unavailableReason).toBeUndefined();
|
|
535
|
+
expect(entry.setupHint).toBeUndefined();
|
|
536
|
+
}
|
|
537
|
+
// The catalog keeps the canonical adapter commands, not the rewrite.
|
|
538
|
+
expect(result.agents.map((a) => a.command)).toEqual([
|
|
539
|
+
"claude-agent-acp",
|
|
540
|
+
"codex-acp",
|
|
541
|
+
"gemini",
|
|
542
|
+
]);
|
|
543
|
+
});
|
|
544
|
+
|
|
260
545
|
test("unavailable agent surfaces install hint derived from DEFAULT_AGENT_NPM_PACKAGES", () => {
|
|
261
546
|
config.setConfig({ agents: {} });
|
|
262
547
|
which.setWhich({ "claude-agent-acp": "/usr/bin/claude-agent-acp" });
|
|
@@ -269,6 +554,32 @@ describe("listAcpAgents", () => {
|
|
|
269
554
|
expect(codex?.setupHint).toBe("npm i -g @zed-industries/codex-acp");
|
|
270
555
|
});
|
|
271
556
|
|
|
557
|
+
test("unavailable gemini surfaces the @google/gemini-cli install hint", () => {
|
|
558
|
+
config.setConfig({ agents: {} });
|
|
559
|
+
which.setWhich({
|
|
560
|
+
"claude-agent-acp": "/usr/bin/claude-agent-acp",
|
|
561
|
+
"codex-acp": "/usr/bin/codex-acp",
|
|
562
|
+
});
|
|
563
|
+
|
|
564
|
+
const result = listAcpAgents();
|
|
565
|
+
|
|
566
|
+
const gemini = result.agents.find((a) => a.id === "gemini");
|
|
567
|
+
expect(gemini?.available).toBe(false);
|
|
568
|
+
expect(gemini?.unavailableReason).toBe("'gemini' is not on PATH");
|
|
569
|
+
expect(gemini?.setupHint).toBe("npm i -g @google/gemini-cli");
|
|
570
|
+
});
|
|
571
|
+
|
|
572
|
+
test("aliases are resolution sugar, not catalog entries", () => {
|
|
573
|
+
config.setConfig({ agents: {} });
|
|
574
|
+
|
|
575
|
+
// "gemini cli" resolves via the alias...
|
|
576
|
+
expect(resolveAcpAgent("gemini cli").ok).toBe(true);
|
|
577
|
+
|
|
578
|
+
// ...but the catalog lists only canonical ids.
|
|
579
|
+
const ids = listAcpAgents().agents.map((a) => a.id);
|
|
580
|
+
expect(ids).toEqual(["claude", "codex", "gemini"]);
|
|
581
|
+
});
|
|
582
|
+
|
|
272
583
|
test("user-only agent appended after defaults in stable order", () => {
|
|
273
584
|
config.setConfig({
|
|
274
585
|
agents: {
|
|
@@ -282,6 +593,7 @@ describe("listAcpAgents", () => {
|
|
|
282
593
|
which.setWhich({
|
|
283
594
|
"claude-agent-acp": "/x",
|
|
284
595
|
"codex-acp": "/x",
|
|
596
|
+
gemini: "/x",
|
|
285
597
|
"my-binary": "/x",
|
|
286
598
|
});
|
|
287
599
|
|
|
@@ -290,9 +602,10 @@ describe("listAcpAgents", () => {
|
|
|
290
602
|
expect(result.agents.map((a) => a.id)).toEqual([
|
|
291
603
|
"claude",
|
|
292
604
|
"codex",
|
|
605
|
+
"gemini",
|
|
293
606
|
"my-agent",
|
|
294
607
|
]);
|
|
295
|
-
const userOnly = result.agents[
|
|
608
|
+
const userOnly = result.agents[3];
|
|
296
609
|
expect(userOnly.source).toBe("config");
|
|
297
610
|
expect(userOnly.description).toBe("user-only");
|
|
298
611
|
});
|