@vellumai/assistant 0.8.7-dev.202606052232.2ddc989 → 0.8.8
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/bun.lock +2 -2
- package/docs/plugins.md +832 -0
- package/examples/plugins/echo/README.md +60 -61
- package/examples/plugins/echo/package.json +2 -1
- package/examples/plugins/echo/register.ts +143 -0
- package/node_modules/@vellumai/skill-host-contracts/src/skill-host.ts +6 -7
- package/openapi.yaml +5 -15
- package/package.json +2 -2
- package/src/__tests__/agent-loop-exit-reason.test.ts +56 -3
- package/src/__tests__/anthropic-provider.test.ts +1 -1
- package/src/__tests__/app-control-flow.test.ts +1 -1
- package/src/__tests__/app-dir-path-guard.test.ts +0 -1
- package/src/__tests__/approval-routes-http.test.ts +1 -4
- package/src/__tests__/channel-approval-routes.test.ts +1 -1
- package/src/__tests__/channel-approvals.test.ts +1 -1
- package/src/__tests__/circuit-breaker-pipeline.test.ts +405 -0
- package/src/__tests__/compaction-pipeline.test.ts +210 -0
- package/src/__tests__/compaction-timeout-recovery.test.ts +251 -0
- package/src/__tests__/conversation-agent-loop-disk-pressure.test.ts +3 -0
- package/src/__tests__/conversation-agent-loop-inference-profile.test.ts +3 -0
- package/src/__tests__/conversation-agent-loop-overflow.test.ts +7 -3
- package/src/__tests__/conversation-agent-loop.test.ts +39 -42
- package/src/__tests__/conversation-clean-command.test.ts +2 -5
- package/src/__tests__/conversation-provider-retry-repair.test.ts +5 -4
- package/src/__tests__/conversation-runtime-assembly.test.ts +71 -140
- package/src/__tests__/conversation-runtime-workspace.test.ts +27 -108
- package/src/__tests__/conversation-starter-routes.test.ts +6 -14
- package/src/__tests__/conversation-workspace-cache-state.test.ts +16 -17
- package/src/__tests__/conversation-workspace-injection.test.ts +1 -61
- package/src/__tests__/conversation-workspace-tool-tracking.test.ts +6 -7
- package/src/__tests__/db-acp-history.test.ts +0 -101
- package/src/__tests__/dynamic-page-surface.test.ts +0 -31
- package/src/__tests__/file-write-tool.test.ts +0 -63
- package/src/__tests__/gateway-only-guard.test.ts +2 -12
- package/src/__tests__/guardian-grant-minting.test.ts +1 -1
- package/src/__tests__/guardian-routing-invariants.test.ts +4 -2
- package/src/__tests__/handlers-user-message-approval-consumption.test.ts +1 -1
- package/src/__tests__/heartbeat-disk-pressure.test.ts +0 -1
- package/src/__tests__/heartbeat-service.test.ts +0 -1
- 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__/injector-background-turn.test.ts +1 -1
- package/src/__tests__/injector-chain.test.ts +6 -34
- package/src/__tests__/injector-disk-pressure.test.ts +34 -77
- package/src/__tests__/injector-document-comments.test.ts +1 -1
- package/src/__tests__/list-messages-hidden-metadata.test.ts +0 -38
- package/src/__tests__/memory-v2-static-injector.test.ts +1 -1
- package/src/__tests__/{overflow-reduction-loop.test.ts → overflow-reduce-pipeline.test.ts} +284 -64
- package/src/__tests__/pipeline-runner.test.ts +554 -0
- package/src/__tests__/plugin-api-shim.test.ts +6 -3
- package/src/__tests__/plugin-bootstrap.test.ts +23 -12
- package/src/__tests__/plugin-registry.test.ts +49 -3
- package/src/__tests__/plugin-types.test.ts +70 -0
- package/src/__tests__/reaction-persistence.test.ts +1 -1
- package/src/__tests__/send-endpoint-busy.test.ts +1 -4
- package/src/__tests__/skill-feature-flags-integration.test.ts +0 -33
- package/src/__tests__/subagent-call-site-routing.test.ts +1 -1
- package/src/__tests__/subagent-fork-notifications.test.ts +3 -1
- package/src/__tests__/subagent-fork-spawn.test.ts +1 -1
- package/src/__tests__/subagent-manager-notify.test.ts +3 -1
- package/src/__tests__/subagent-notify-parent.test.ts +3 -1
- package/src/__tests__/subagent-spawn-tool-fork.test.ts +1 -1
- package/src/__tests__/user-plugin-loader.test.ts +286 -54
- package/src/acp/__tests__/client-handler.test.ts +0 -40
- package/src/acp/__tests__/prepare-agent-env.test.ts +0 -137
- package/src/acp/__tests__/session-manager-persistence.test.ts +28 -95
- package/src/acp/agent-process.ts +1 -61
- package/src/acp/client-handler.ts +0 -31
- package/src/acp/prepare-agent-env.ts +29 -83
- package/src/acp/resolve-agent.test.ts +7 -320
- package/src/acp/resolve-agent.ts +18 -182
- package/src/acp/session-manager.ts +73 -495
- package/src/acp/types.ts +0 -8
- package/src/agent/compaction-circuit.ts +102 -60
- package/src/agent/loop.ts +59 -32
- package/src/api/responses/conversation-message.ts +1 -7
- package/src/approvals/guardian-request-resolvers.ts +1 -1
- package/src/background-wake/next-wake.ts +0 -1
- package/src/config/__tests__/feature-flag-registry-guard.test.ts +2 -2
- package/src/config/acp-defaults.test.ts +0 -10
- package/src/config/acp-defaults.ts +0 -6
- package/src/config/bundled-skills/acp/SKILL.md +31 -83
- package/src/config/bundled-skills/acp/TOOLS.json +4 -4
- package/src/config/bundled-skills/app-builder/SKILL.md +381 -224
- package/src/config/bundled-skills/app-builder/TOOLS.json +0 -29
- package/src/config/bundled-skills/document-editor/SKILL.md +23 -28
- package/src/config/bundled-skills/document-editor/TOOLS.json +1 -1
- package/src/config/bundled-tool-registry.ts +0 -2
- package/src/config/feature-flag-registry.json +5 -14
- package/src/config/schemas/heartbeat.ts +0 -9
- package/src/context/strip-injections.ts +2 -8
- package/src/context/window-manager.ts +1 -2
- package/src/daemon/conversation-agent-loop-handlers.ts +11 -0
- package/src/daemon/conversation-agent-loop.ts +279 -62
- package/src/daemon/conversation-runtime-assembly.ts +69 -106
- package/src/daemon/conversation-store.ts +90 -9
- package/src/daemon/conversation-workspace.ts +0 -17
- package/src/daemon/conversation.ts +6 -0
- package/src/daemon/external-plugins-bootstrap.ts +11 -11
- package/src/daemon/handlers/conversations.ts +1 -3
- package/src/daemon/handlers/skills.ts +1 -4
- package/src/daemon/lifecycle.ts +0 -21
- package/src/daemon/server.ts +0 -2
- package/src/heartbeat/__tests__/heartbeat-service.test.ts +0 -3
- package/src/heartbeat/heartbeat-run-store.ts +1 -23
- package/src/heartbeat/heartbeat-service.ts +0 -26
- 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 +0 -15
- package/src/ipc/skill-routes/memory.ts +2 -4
- package/src/memory/conversation-starter-checkpoints.ts +0 -1
- package/src/memory/db-init.ts +0 -2
- package/src/memory/job-handlers/conversation-starters.ts +2 -13
- package/src/memory/jobs-worker.ts +1 -1
- package/src/memory/migrations/index.ts +0 -1
- package/src/memory/schema/acp.ts +0 -4
- package/src/memory/v2/__tests__/consolidation-job.test.ts +3 -3
- package/src/memory/v2/consolidation-job.ts +4 -13
- package/src/{plugins/defaults/memory-v3-shadow → memory/v3}/__tests__/assign.test.ts +4 -4
- package/src/{plugins/defaults/memory-v3-shadow → memory/v3}/__tests__/live-integration.test.ts +4 -4
- package/src/{plugins/defaults/memory-v3-shadow → memory/v3}/__tests__/maintain-job.test.ts +5 -5
- package/src/{plugins/defaults/memory-v3-shadow → memory/v3}/__tests__/orchestrate.test.ts +3 -3
- package/src/{plugins/defaults/memory-v3-shadow → memory/v3}/__tests__/reconcile.test.ts +2 -2
- package/src/{plugins/defaults/memory-v3-shadow → memory/v3}/__tests__/render-injection.test.ts +1 -1
- package/src/{plugins/defaults/memory-v3-shadow → memory/v3}/__tests__/router.test.ts +3 -3
- package/src/{plugins/defaults/memory-v3-shadow → memory/v3}/__tests__/selection-log-store.test.ts +8 -8
- package/src/{plugins/defaults/memory-v3-shadow → memory/v3}/__tests__/selector.test.ts +3 -3
- package/src/{plugins/defaults/memory-v3-shadow → memory/v3}/__tests__/shadow-plugin.test.ts +12 -12
- package/src/{plugins/defaults/memory-v3-shadow → memory/v3}/assign.ts +5 -5
- package/src/{plugins/defaults/memory-v3-shadow → memory/v3}/capabilities.ts +2 -2
- package/src/{plugins/defaults/memory-v3-shadow → memory/v3}/maintain-job.ts +8 -8
- package/src/{plugins/defaults/memory-v3-shadow → memory/v3}/page-content.ts +2 -2
- package/src/{plugins/defaults/memory-v3-shadow → memory/v3}/provider-blocks.ts +1 -1
- package/src/{plugins/defaults/memory-v3-shadow → memory/v3}/reconcile.ts +3 -3
- package/src/{plugins/defaults/memory-v3-shadow → memory/v3}/render-injection.ts +1 -1
- package/src/{plugins/defaults/memory-v3-shadow → memory/v3}/router.ts +3 -3
- package/src/{plugins/defaults/memory-v3-shadow → memory/v3}/selection-log-store.ts +4 -4
- package/src/{plugins/defaults/memory-v3-shadow → memory/v3}/selector.ts +4 -4
- package/src/{plugins/defaults/memory-v3-shadow → memory/v3}/shadow-plugin.ts +90 -28
- package/src/{plugins/defaults/memory-v3-shadow → memory/v3}/tree.ts +1 -1
- package/src/plugin-api/index.ts +5 -0
- package/src/plugins/defaults/circuit-breaker/middlewares/circuitBreaker.ts +93 -0
- package/src/plugins/defaults/{memory-v3-shadow → circuit-breaker}/package.json +2 -2
- package/src/plugins/defaults/circuit-breaker/register.ts +39 -0
- package/src/plugins/defaults/compaction/middlewares/compaction.ts +25 -0
- package/src/plugins/defaults/compaction/package.json +1 -1
- package/src/plugins/defaults/compaction/register.ts +19 -8
- package/src/plugins/defaults/compaction/terminal.ts +73 -0
- package/src/plugins/defaults/index.ts +5 -3
- package/src/plugins/defaults/{memory-retrieval/injectors.ts → injectors/register.ts} +7 -45
- package/src/plugins/defaults/memory-retrieval/hooks/post-compact.ts +7 -11
- package/src/plugins/defaults/memory-retrieval/injector-chain.ts +2 -2
- package/src/plugins/defaults/overflow-reduce/middlewares/overflowReduce.ts +126 -0
- package/src/plugins/defaults/overflow-reduce/package.json +15 -0
- package/src/plugins/defaults/overflow-reduce/register.ts +42 -0
- package/src/plugins/external-api.ts +2 -2
- package/src/plugins/pipeline.ts +293 -6
- package/src/plugins/registry.ts +37 -9
- package/src/plugins/types.ts +336 -32
- package/src/plugins/user-loader.ts +127 -30
- package/src/proactive-artifact/aux-message-injector.ts +1 -1
- package/src/proactive-artifact/job.test.ts +1 -1
- package/src/prompts/__tests__/system-prompt.test.ts +0 -6
- package/src/prompts/templates/BOOTSTRAP-ACTIVATION-RAIL.md +2 -4
- package/src/runtime/__tests__/agent-wake.test.ts +5 -5
- package/src/runtime/__tests__/interactive-ui.test.ts +1 -1
- package/src/runtime/agent-wake.ts +3 -0
- 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 +55 -283
- package/src/runtime/routes/__tests__/conversation-list-routes.test.ts +1 -1
- package/src/runtime/routes/__tests__/surface-action-routes.test.ts +4 -5
- package/src/runtime/routes/__tests__/surface-content-routes.test.ts +1 -4
- package/src/runtime/routes/acp-routes.test.ts +25 -89
- package/src/runtime/routes/acp-routes.ts +29 -81
- 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 +10 -6
- 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 +2 -15
- package/src/runtime/routes/conversation-starter-routes.ts +7 -13
- package/src/runtime/routes/conversations-import-routes.ts +7 -24
- 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 +3 -18
- package/src/runtime/routes/inbound-message-handler.ts +1 -1
- package/src/runtime/routes/memory-v3-routes.ts +6 -16
- package/src/runtime/routes/playground/helpers.ts +1 -1
- package/src/runtime/routes/surface-conversation-resolver.ts +3 -4
- package/src/runtime/routes/work-items-routes.ts +4 -2
- package/src/runtime/services/conversation-serializer.ts +1 -1
- package/src/signals/cancel.ts +4 -2
- package/src/subagent/manager.ts +5 -17
- package/src/tools/acp/list-agents.test.ts +1 -7
- package/src/tools/acp/spawn.test.ts +55 -158
- package/src/tools/acp/spawn.ts +72 -47
- package/src/tools/acp/steer.test.ts +8 -105
- package/src/tools/acp/steer.ts +17 -48
- package/src/tools/apps/executors.ts +8 -13
- package/src/tools/filesystem/write.ts +0 -34
- package/src/tools/subagent/spawn.ts +4 -2
- package/src/tools/ui-surface/definitions.ts +4 -25
- package/src/workspace/migrations/051-seed-conversation-summarization-callsite.ts +5 -4
- package/src/workspace/migrations/097-enable-adaptive-thinking-managed-profiles.ts +45 -69
- package/examples/plugins/echo/hooks/post-tool-use.ts +0 -18
- package/examples/plugins/echo/hooks/stop.ts +0 -16
- package/examples/plugins/echo/hooks/user-prompt-submit.ts +0 -18
- package/examples/plugins/echo/src/emit.ts +0 -19
- package/src/__tests__/compaction-circuit.test.ts +0 -258
- package/src/__tests__/compaction-direct.test.ts +0 -132
- package/src/__tests__/conversations-import-system-filter.test.ts +0 -101
- package/src/acp/__tests__/agent-process.test.ts +0 -161
- package/src/acp/__tests__/helpers/acp-history-db.ts +0 -82
- package/src/acp/__tests__/helpers/exec-file-stub.ts +0 -101
- package/src/acp/__tests__/session-manager-resume.test.ts +0 -736
- package/src/acp/auto-install.test.ts +0 -196
- package/src/acp/auto-install.ts +0 -177
- package/src/acp/feature-gate.test.ts +0 -48
- package/src/acp/feature-gate.ts +0 -34
- package/src/acp/resume-hint.ts +0 -25
- package/src/config/bundled-skills/app-builder/references/DESIGN_SYSTEM.md +0 -48
- package/src/config/bundled-skills/app-builder/references/RESPONSIVE.md +0 -57
- package/src/config/bundled-skills/app-builder/references/SLIDES.md +0 -38
- package/src/config/bundled-skills/app-builder/tools/app-list.ts +0 -62
- package/src/daemon/conversation-registry.ts +0 -159
- package/src/daemon/overflow-reduction-loop.ts +0 -230
- package/src/memory/migrations/272-acp-session-history-cwd.ts +0 -36
- package/src/plugins/defaults/compaction/compact.ts +0 -59
- package/src/plugins/defaults/memory-v3-shadow/hooks/post-compact.ts +0 -14
- package/src/plugins/defaults/memory-v3-shadow/hooks/user-prompt-submit.ts +0 -19
- package/src/plugins/defaults/memory-v3-shadow/injector.ts +0 -75
- package/src/plugins/defaults/memory-v3-shadow/register.ts +0 -26
- package/src/tools/acp/context.ts +0 -20
- /package/src/{plugins/defaults/memory-v3-shadow → memory/v3}/__tests__/capabilities.test.ts +0 -0
- /package/src/{plugins/defaults/memory-v3-shadow → memory/v3}/__tests__/core.test.ts +0 -0
- /package/src/{plugins/defaults/memory-v3-shadow → memory/v3}/__tests__/fixtures/eval-turns.json +0 -0
- /package/src/{plugins/defaults/memory-v3-shadow → memory/v3}/__tests__/fixtures/live-turns.json +0 -0
- /package/src/{plugins/defaults/memory-v3-shadow → memory/v3}/__tests__/health.test.ts +0 -0
- /package/src/{plugins/defaults/memory-v3-shadow → memory/v3}/__tests__/needle.test.ts +0 -0
- /package/src/{plugins/defaults/memory-v3-shadow → memory/v3}/__tests__/provider-blocks.test.ts +0 -0
- /package/src/{plugins/defaults/memory-v3-shadow → memory/v3}/__tests__/snapshot.test.ts +0 -0
- /package/src/{plugins/defaults/memory-v3-shadow → memory/v3}/__tests__/tree.test.ts +0 -0
- /package/src/{plugins/defaults/memory-v3-shadow → memory/v3}/__tests__/types.test.ts +0 -0
- /package/src/{plugins/defaults/memory-v3-shadow → memory/v3}/__tests__/working-set-eviction.test.ts +0 -0
- /package/src/{plugins/defaults/memory-v3-shadow → memory/v3}/__tests__/working-set-skeleton.test.ts +0 -0
- /package/src/{plugins/defaults/memory-v3-shadow → memory/v3}/core.ts +0 -0
- /package/src/{plugins/defaults/memory-v3-shadow → memory/v3}/data/README.md +0 -0
- /package/src/{plugins/defaults/memory-v3-shadow → memory/v3}/data/assignments.json +0 -0
- /package/src/{plugins/defaults/memory-v3-shadow → memory/v3}/data/core.json +0 -0
- /package/src/{plugins/defaults/memory-v3-shadow → memory/v3}/data/leaves/domain-a/topic-x.md +0 -0
- /package/src/{plugins/defaults/memory-v3-shadow → memory/v3}/data/leaves/domain-a/topic-y.md +0 -0
- /package/src/{plugins/defaults/memory-v3-shadow → memory/v3}/data/leaves/domain-b/topic-z.md +0 -0
- /package/src/{plugins/defaults/memory-v3-shadow → memory/v3}/health.ts +0 -0
- /package/src/{plugins/defaults/memory-v3-shadow → memory/v3}/llm-retry.ts +0 -0
- /package/src/{plugins/defaults/memory-v3-shadow → memory/v3}/needle.ts +0 -0
- /package/src/{plugins/defaults/memory-v3-shadow → memory/v3}/orchestrate.ts +0 -0
- /package/src/{plugins/defaults/memory-v3-shadow → memory/v3}/snapshot.ts +0 -0
- /package/src/{plugins/defaults/memory-v3-shadow → memory/v3}/types.ts +0 -0
- /package/src/{plugins/defaults/memory-v3-shadow → memory/v3}/working-set.ts +0 -0
package/src/subagent/manager.ts
CHANGED
|
@@ -13,11 +13,7 @@ import { v4 as uuid } from "uuid";
|
|
|
13
13
|
import { resolveCallSiteConfig } from "../config/llm-resolver.js";
|
|
14
14
|
import { getConfig } from "../config/loader.js";
|
|
15
15
|
import { Conversation } from "../daemon/conversation.js";
|
|
16
|
-
import {
|
|
17
|
-
findConversation,
|
|
18
|
-
removeSubagentConversation,
|
|
19
|
-
setSubagentConversation,
|
|
20
|
-
} from "../daemon/conversation-registry.js";
|
|
16
|
+
import { findConversation } from "../daemon/conversation-store.js";
|
|
21
17
|
import type { ServerMessage } from "../daemon/message-protocol.js";
|
|
22
18
|
import { bootstrapConversation } from "../memory/conversation-bootstrap.js";
|
|
23
19
|
import { wrapWithCallSiteRouting } from "../providers/call-site-routing.js";
|
|
@@ -338,10 +334,6 @@ export class SubagentManager {
|
|
|
338
334
|
|
|
339
335
|
managed.conversation = conversation;
|
|
340
336
|
this.subagents.set(subagentId, managed);
|
|
341
|
-
// Index the live conversation so the per-conversation injectors (workspace
|
|
342
|
-
// context, disk-pressure warning) can resolve it by id; subagents are not
|
|
343
|
-
// in the eviction-managed conversation store.
|
|
344
|
-
setSubagentConversation(conversationRecord.id, conversation);
|
|
345
337
|
const labelKey = `${config.parentConversationId}:${config.label.toLowerCase().trim()}`;
|
|
346
338
|
if (this.labelIndex.has(labelKey)) {
|
|
347
339
|
log.warn(
|
|
@@ -703,9 +695,7 @@ export class SubagentManager {
|
|
|
703
695
|
*/
|
|
704
696
|
private releaseConversation(managed: ManagedSubagent): void {
|
|
705
697
|
if (!managed.conversation) return;
|
|
706
|
-
|
|
707
|
-
removeSubagentConversation(conversation.conversationId, conversation);
|
|
708
|
-
conversation.dispose();
|
|
698
|
+
managed.conversation.dispose();
|
|
709
699
|
managed.conversation = null;
|
|
710
700
|
managed.retainedUntil = Date.now() + TERMINAL_RETENTION_MS;
|
|
711
701
|
this.ensureSweepRunning();
|
|
@@ -726,18 +716,16 @@ export class SubagentManager {
|
|
|
726
716
|
if (!managed) return;
|
|
727
717
|
|
|
728
718
|
if (managed.conversation) {
|
|
729
|
-
const conversation = managed.conversation;
|
|
730
719
|
if (!TERMINAL_STATUSES.has(managed.state.status)) {
|
|
731
|
-
conversation.abort(
|
|
720
|
+
managed.conversation.abort(
|
|
732
721
|
createAbortReason(
|
|
733
722
|
"subagent_aborted",
|
|
734
723
|
"SubagentManager.dispose",
|
|
735
|
-
conversation.conversationId,
|
|
724
|
+
managed.conversation.conversationId,
|
|
736
725
|
),
|
|
737
726
|
);
|
|
738
727
|
}
|
|
739
|
-
|
|
740
|
-
conversation.dispose();
|
|
728
|
+
managed.conversation.dispose();
|
|
741
729
|
managed.conversation = null;
|
|
742
730
|
}
|
|
743
731
|
this.subagents.delete(subagentId);
|
|
@@ -47,7 +47,7 @@ describe("executeAcpListAgents", () => {
|
|
|
47
47
|
expect(parsed.hint).toContain("config.json");
|
|
48
48
|
});
|
|
49
49
|
|
|
50
|
-
test("enabled, no user config:
|
|
50
|
+
test("enabled, no user config: both defaults present with source 'default' and available based on Bun.which", async () => {
|
|
51
51
|
config.setConfig({ agents: {} });
|
|
52
52
|
|
|
53
53
|
const result = await executeAcpListAgents({}, makeContext());
|
|
@@ -58,7 +58,6 @@ describe("executeAcpListAgents", () => {
|
|
|
58
58
|
expect(parsed.agents.map((a: { id: string }) => a.id)).toEqual([
|
|
59
59
|
"claude",
|
|
60
60
|
"codex",
|
|
61
|
-
"gemini",
|
|
62
61
|
]);
|
|
63
62
|
for (const entry of parsed.agents) {
|
|
64
63
|
expect(entry.source).toBe("default");
|
|
@@ -109,11 +108,6 @@ describe("executeAcpListAgents", () => {
|
|
|
109
108
|
expect(codex.unavailableReason).toBe("'codex-acp' is not on PATH");
|
|
110
109
|
expect(codex.setupHint).toBe("npm i -g @zed-industries/codex-acp");
|
|
111
110
|
|
|
112
|
-
const gemini = parsed.agents.find((a: { id: string }) => a.id === "gemini");
|
|
113
|
-
expect(gemini.available).toBe(false);
|
|
114
|
-
expect(gemini.unavailableReason).toBe("'gemini' is not on PATH");
|
|
115
|
-
expect(gemini.setupHint).toBe("npm i -g @google/gemini-cli");
|
|
116
|
-
|
|
117
111
|
const claude = parsed.agents.find((a: { id: string }) => a.id === "claude");
|
|
118
112
|
expect(claude.available).toBe(true);
|
|
119
113
|
expect(claude.setupHint).toBeUndefined();
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
+
import * as realChildProcess from "node:child_process";
|
|
1
2
|
import { afterAll, beforeEach, describe, expect, mock, test } from "bun:test";
|
|
2
3
|
|
|
3
4
|
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,11 +9,55 @@ import type { ToolContext } from "../types.js";
|
|
|
9
9
|
// Mock infrastructure
|
|
10
10
|
// ---------------------------------------------------------------------------
|
|
11
11
|
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
12
|
+
type ExecCallback = (
|
|
13
|
+
err: Error | null,
|
|
14
|
+
stdout: string | Buffer,
|
|
15
|
+
stderr: string | Buffer,
|
|
16
|
+
) => void;
|
|
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
|
+
}
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Per-call scripted responses for `execFile`. Keyed by `${command} ${args[0]}`
|
|
27
|
+
* so tests can target `npm ls` and `npm view` independently.
|
|
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
|
+
}));
|
|
17
61
|
|
|
18
62
|
// Default ACP config used by these tests: the `unknown-agent` entry is here
|
|
19
63
|
// to give the "no version check" test a configured agent whose binary isn't
|
|
@@ -145,9 +189,6 @@ mock.module("../../acp/index.js", () => ({
|
|
|
145
189
|
|
|
146
190
|
const { executeAcpSpawn, _resetAdapterVersionCacheForTests } =
|
|
147
191
|
await import("./spawn.js");
|
|
148
|
-
const { _resetAdapterInstallCacheForTests } = await import(
|
|
149
|
-
"../../acp/auto-install.js"
|
|
150
|
-
);
|
|
151
192
|
|
|
152
193
|
// ---------------------------------------------------------------------------
|
|
153
194
|
// Helpers
|
|
@@ -163,10 +204,10 @@ function makeContext(): ToolContext {
|
|
|
163
204
|
}
|
|
164
205
|
|
|
165
206
|
beforeEach(() => {
|
|
166
|
-
|
|
207
|
+
execScripts.clear();
|
|
208
|
+
execFileMock.mockClear();
|
|
167
209
|
spawnMock.mockClear();
|
|
168
210
|
_resetAdapterVersionCacheForTests();
|
|
169
|
-
_resetAdapterInstallCacheForTests();
|
|
170
211
|
config.setConfig({ agents: DEFAULT_TEST_AGENTS });
|
|
171
212
|
which.setWhich((cmd) => `/usr/local/bin/${cmd}`);
|
|
172
213
|
// Default: vault has a claude token so the preflight in `prepareAgentEnv`
|
|
@@ -350,9 +391,8 @@ describe("executeAcpSpawn — input validation", () => {
|
|
|
350
391
|
expect(result.content).toContain("acp.enabled");
|
|
351
392
|
});
|
|
352
393
|
|
|
353
|
-
test("missing binary returns install hint
|
|
394
|
+
test("missing binary returns install hint", async () => {
|
|
354
395
|
which.setWhich({});
|
|
355
|
-
execScripts.set("npm i", { error: new Error("npm not installed") });
|
|
356
396
|
const result = await executeAcpSpawn(
|
|
357
397
|
{ agent: "claude", task: "do something" },
|
|
358
398
|
makeContext(),
|
|
@@ -386,149 +426,6 @@ describe("executeAcpSpawn — input validation", () => {
|
|
|
386
426
|
});
|
|
387
427
|
});
|
|
388
428
|
|
|
389
|
-
describe("executeAcpSpawn: auto-install on missing binary", () => {
|
|
390
|
-
test("known command: installs the mapped package and spawn proceeds with a note", async () => {
|
|
391
|
-
// Binary appears on PATH only after `npm i -g` runs, simulating a
|
|
392
|
-
// successful global install.
|
|
393
|
-
let binaryOnPath = false;
|
|
394
|
-
which.setWhich((cmd) => (binaryOnPath ? `/usr/local/bin/${cmd}` : null));
|
|
395
|
-
execScripts.set("npm i", {
|
|
396
|
-
stdout: "",
|
|
397
|
-
onCall: () => {
|
|
398
|
-
binaryOnPath = true;
|
|
399
|
-
},
|
|
400
|
-
});
|
|
401
|
-
// Version probes after the install: best-effort, scripted to skip.
|
|
402
|
-
execScripts.set("npm ls", { error: new Error("skip") });
|
|
403
|
-
execScripts.set("npm view", { error: new Error("skip") });
|
|
404
|
-
|
|
405
|
-
const result = await executeAcpSpawn(
|
|
406
|
-
{ agent: "claude", task: "do something" },
|
|
407
|
-
makeContext(),
|
|
408
|
-
);
|
|
409
|
-
|
|
410
|
-
expect(result.isError).toBe(false);
|
|
411
|
-
expect(spawnMock).toHaveBeenCalledTimes(1);
|
|
412
|
-
const [payloadJson] = result.content.split("\n\n");
|
|
413
|
-
const payload = JSON.parse(payloadJson);
|
|
414
|
-
expect(payload.message).toContain(
|
|
415
|
-
"Installed @agentclientprotocol/claude-agent-acp automatically.",
|
|
416
|
-
);
|
|
417
|
-
const installCalls = execFileMock.mock.calls.filter(
|
|
418
|
-
(call) => (call[1] as string[])[0] === "i",
|
|
419
|
-
);
|
|
420
|
-
expect(installCalls).toHaveLength(1);
|
|
421
|
-
expect(installCalls[0][1]).toEqual([
|
|
422
|
-
"i",
|
|
423
|
-
"-g",
|
|
424
|
-
"@agentclientprotocol/claude-agent-acp",
|
|
425
|
-
]);
|
|
426
|
-
});
|
|
427
|
-
|
|
428
|
-
test("unknown command: no install attempted, plain hint returned", async () => {
|
|
429
|
-
which.setWhich({});
|
|
430
|
-
|
|
431
|
-
const result = await executeAcpSpawn(
|
|
432
|
-
{ agent: "unknown-agent", task: "do something" },
|
|
433
|
-
makeContext(),
|
|
434
|
-
);
|
|
435
|
-
|
|
436
|
-
expect(result.isError).toBe(true);
|
|
437
|
-
expect(result.content).toContain("some-other-binary is not on PATH");
|
|
438
|
-
expect(result.content).toContain("Install 'some-other-binary'");
|
|
439
|
-
expect(result.content).not.toContain("auto-install failed");
|
|
440
|
-
expect(execFileMock).not.toHaveBeenCalled();
|
|
441
|
-
expect(spawnMock).not.toHaveBeenCalled();
|
|
442
|
-
});
|
|
443
|
-
|
|
444
|
-
test("no client connected: no install attempted even when the binary is missing", async () => {
|
|
445
|
-
// The no-client guard is a pure precondition and must run BEFORE the
|
|
446
|
-
// auto-install side effect: without a client the spawn fails anyway, so
|
|
447
|
-
// the host must not be mutated by `npm i -g` (which can also block for
|
|
448
|
-
// up to the install timeout).
|
|
449
|
-
which.setWhich({});
|
|
450
|
-
|
|
451
|
-
const result = await executeAcpSpawn(
|
|
452
|
-
{ agent: "claude", task: "do something" },
|
|
453
|
-
{ ...makeContext(), sendToClient: undefined },
|
|
454
|
-
);
|
|
455
|
-
|
|
456
|
-
expect(result.isError).toBe(true);
|
|
457
|
-
expect(result.content).toContain("No client connected");
|
|
458
|
-
expect(execFileMock).not.toHaveBeenCalled();
|
|
459
|
-
expect(spawnMock).not.toHaveBeenCalled();
|
|
460
|
-
});
|
|
461
|
-
|
|
462
|
-
test("npm failure: hint and install failure both surface", async () => {
|
|
463
|
-
which.setWhich({});
|
|
464
|
-
execScripts.set("npm i", {
|
|
465
|
-
error: new Error("EACCES: permission denied"),
|
|
466
|
-
});
|
|
467
|
-
|
|
468
|
-
const result = await executeAcpSpawn(
|
|
469
|
-
{ agent: "claude", task: "do something" },
|
|
470
|
-
makeContext(),
|
|
471
|
-
);
|
|
472
|
-
|
|
473
|
-
expect(result.isError).toBe(true);
|
|
474
|
-
expect(result.content).toContain("claude-agent-acp is not on PATH");
|
|
475
|
-
expect(result.content).toContain(
|
|
476
|
-
"npm i -g @agentclientprotocol/claude-agent-acp",
|
|
477
|
-
);
|
|
478
|
-
expect(result.content).toContain("auto-install failed");
|
|
479
|
-
expect(result.content).toContain("EACCES");
|
|
480
|
-
expect(spawnMock).not.toHaveBeenCalled();
|
|
481
|
-
});
|
|
482
|
-
});
|
|
483
|
-
|
|
484
|
-
describe("executeAcpSpawn - bunx fallback when binary missing", () => {
|
|
485
|
-
test("binary missing + bun present: spawns via `bun x` with env injection and resume hint, no npm calls", async () => {
|
|
486
|
-
// Only bun is on PATH - the platform-hosted image (bun, no node/npm).
|
|
487
|
-
which.setWhich({ bun: "/usr/local/bin/bun" });
|
|
488
|
-
|
|
489
|
-
const result = await executeAcpSpawn(
|
|
490
|
-
{ agent: "claude", task: "do something" },
|
|
491
|
-
makeContext(),
|
|
492
|
-
);
|
|
493
|
-
|
|
494
|
-
expect(result.isError).toBe(false);
|
|
495
|
-
// No npm install AND no npm version probe: bunx fetches the package on
|
|
496
|
-
// first use and there is no global install to compare.
|
|
497
|
-
expect(execFileMock).not.toHaveBeenCalled();
|
|
498
|
-
expect(result.content).not.toContain("outdated");
|
|
499
|
-
|
|
500
|
-
expect(spawnMock).toHaveBeenCalledTimes(1);
|
|
501
|
-
const agentConfigArg = spawnMock.mock.calls[0][1] as {
|
|
502
|
-
command: string;
|
|
503
|
-
args: string[];
|
|
504
|
-
adapterCommand?: string;
|
|
505
|
-
env?: Record<string, string>;
|
|
506
|
-
};
|
|
507
|
-
expect(agentConfigArg.command).toBe("bun");
|
|
508
|
-
expect(agentConfigArg.args).toEqual([
|
|
509
|
-
"x",
|
|
510
|
-
"--bun",
|
|
511
|
-
"@agentclientprotocol/claude-agent-acp",
|
|
512
|
-
]);
|
|
513
|
-
expect(agentConfigArg.adapterCommand).toBe("claude-agent-acp");
|
|
514
|
-
// CLAUDE_CODE_OAUTH_TOKEN injection still applies to the bunx-resolved
|
|
515
|
-
// claude adapter (gated on adapterCommand, not the spawn command).
|
|
516
|
-
expect(agentConfigArg.env?.CLAUDE_CODE_OAUTH_TOKEN).toBe(
|
|
517
|
-
"default-test-token",
|
|
518
|
-
);
|
|
519
|
-
|
|
520
|
-
const [payloadJson] = result.content.split("\n\n");
|
|
521
|
-
const payload = JSON.parse(payloadJson);
|
|
522
|
-
// No auto-install happened; the claude resume hint still fires.
|
|
523
|
-
expect(payload.message).not.toContain("Installed");
|
|
524
|
-
expect(payload.message).toContain("claude --resume");
|
|
525
|
-
});
|
|
526
|
-
|
|
527
|
-
// The bun-absent npm fallback is covered by the existing auto-install
|
|
528
|
-
// suite below ("known command: installs the mapped package..."), whose
|
|
529
|
-
// which-stub leaves bun off PATH until the install completes.
|
|
530
|
-
});
|
|
531
|
-
|
|
532
429
|
describe("executeAcpSpawn — per-agent resume hint", () => {
|
|
533
430
|
test("claude payload includes the `claude --resume` hint", async () => {
|
|
534
431
|
execScripts.set("npm ls", { error: new Error("npm not installed") });
|
|
@@ -543,7 +440,7 @@ describe("executeAcpSpawn — per-agent resume hint", () => {
|
|
|
543
440
|
const [payloadJson] = result.content.split("\n\n");
|
|
544
441
|
const payload = JSON.parse(payloadJson);
|
|
545
442
|
expect(payload.message).toContain("claude --resume");
|
|
546
|
-
expect(payload.message).toContain("To resume
|
|
443
|
+
expect(payload.message).toContain("To resume this session later");
|
|
547
444
|
});
|
|
548
445
|
|
|
549
446
|
test("non-claude payload omits the `claude --resume` hint", async () => {
|
|
@@ -561,7 +458,7 @@ describe("executeAcpSpawn — per-agent resume hint", () => {
|
|
|
561
458
|
const [payloadJson] = result.content.split("\n\n");
|
|
562
459
|
const payload = JSON.parse(payloadJson);
|
|
563
460
|
expect(payload.message).not.toContain("claude --resume");
|
|
564
|
-
expect(payload.message).not.toContain("To resume
|
|
461
|
+
expect(payload.message).not.toContain("To resume this session later");
|
|
565
462
|
});
|
|
566
463
|
});
|
|
567
464
|
|
package/src/tools/acp/spawn.ts
CHANGED
|
@@ -1,19 +1,11 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
3
|
-
resolveAgentWithAutoInstall,
|
|
4
|
-
} from "../../acp/auto-install.js";
|
|
1
|
+
import { execFile } from "node:child_process";
|
|
2
|
+
|
|
5
3
|
import { getAcpSessionManager } from "../../acp/index.js";
|
|
6
4
|
import { prepareAgentEnv } from "../../acp/prepare-agent-env.js";
|
|
7
|
-
import {
|
|
8
|
-
adapterCommandOf,
|
|
9
|
-
formatResolveFailure,
|
|
10
|
-
runsViaBunx,
|
|
11
|
-
} from "../../acp/resolve-agent.js";
|
|
12
|
-
import { claudeResumeHint } from "../../acp/resume-hint.js";
|
|
5
|
+
import { resolveAcpAgent } from "../../acp/resolve-agent.js";
|
|
13
6
|
import { DEFAULT_AGENT_NPM_PACKAGES } from "../../config/acp-defaults.js";
|
|
14
7
|
import { getLogger } from "../../util/logger.js";
|
|
15
8
|
import type { ToolContext, ToolExecutionResult } from "../types.js";
|
|
16
|
-
import { getSendToClient } from "./context.js";
|
|
17
9
|
|
|
18
10
|
const log = getLogger("acp:spawn");
|
|
19
11
|
|
|
@@ -33,6 +25,35 @@ interface AdapterVersionInfo {
|
|
|
33
25
|
packageName: string;
|
|
34
26
|
}
|
|
35
27
|
|
|
28
|
+
/**
|
|
29
|
+
* Run `execFile` with an AbortController-driven timeout. Returns the stdout
|
|
30
|
+
* on success; throws on error or timeout. Caller treats any throw as a
|
|
31
|
+
* best-effort skip.
|
|
32
|
+
*/
|
|
33
|
+
function execFileWithTimeout(
|
|
34
|
+
command: string,
|
|
35
|
+
args: string[],
|
|
36
|
+
timeoutMs: number,
|
|
37
|
+
): Promise<string> {
|
|
38
|
+
return new Promise((resolve, reject) => {
|
|
39
|
+
const controller = new AbortController();
|
|
40
|
+
const timer = setTimeout(() => controller.abort(), timeoutMs);
|
|
41
|
+
execFile(
|
|
42
|
+
command,
|
|
43
|
+
args,
|
|
44
|
+
{ signal: controller.signal, encoding: "utf8" },
|
|
45
|
+
(err, stdout) => {
|
|
46
|
+
clearTimeout(timer);
|
|
47
|
+
if (err) {
|
|
48
|
+
reject(err);
|
|
49
|
+
return;
|
|
50
|
+
}
|
|
51
|
+
resolve(stdout);
|
|
52
|
+
},
|
|
53
|
+
);
|
|
54
|
+
});
|
|
55
|
+
}
|
|
56
|
+
|
|
36
57
|
/**
|
|
37
58
|
* Checks if the globally-installed ACP adapter for `command` is outdated.
|
|
38
59
|
* Best-effort: any error or timeout returns `null` (skipped). Unknown
|
|
@@ -114,10 +135,34 @@ export async function executeAcpSpawn(
|
|
|
114
135
|
return { content: '"task" is required.', isError: true };
|
|
115
136
|
}
|
|
116
137
|
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
138
|
+
const resolved = resolveAcpAgent(agent);
|
|
139
|
+
if (!resolved.ok) {
|
|
140
|
+
switch (resolved.reason) {
|
|
141
|
+
case "acp_disabled":
|
|
142
|
+
return { content: resolved.hint, isError: true };
|
|
143
|
+
case "unknown_agent":
|
|
144
|
+
return {
|
|
145
|
+
content: `Unknown agent "${agent}". Available: ${resolved.available.join(
|
|
146
|
+
", ",
|
|
147
|
+
)}.`,
|
|
148
|
+
isError: true,
|
|
149
|
+
};
|
|
150
|
+
case "binary_not_found":
|
|
151
|
+
return {
|
|
152
|
+
content: `${resolved.command} is not on PATH. ${resolved.hint}`,
|
|
153
|
+
isError: true,
|
|
154
|
+
};
|
|
155
|
+
default: {
|
|
156
|
+
const _exhaustive: never = resolved;
|
|
157
|
+
throw new Error(
|
|
158
|
+
`Unexpected acp resolver reason: ${(_exhaustive as { reason: string }).reason}`,
|
|
159
|
+
);
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
const sendToClient = context.sendToClient as
|
|
164
|
+
| ((msg: { type: string; [key: string]: unknown }) => void)
|
|
165
|
+
| undefined;
|
|
121
166
|
if (!sendToClient) {
|
|
122
167
|
return {
|
|
123
168
|
content: "No client connected - cannot spawn ACP agent.",
|
|
@@ -125,17 +170,6 @@ export async function executeAcpSpawn(
|
|
|
125
170
|
};
|
|
126
171
|
}
|
|
127
172
|
|
|
128
|
-
// Resolve the agent, silently auto-installing a missing allowlisted
|
|
129
|
-
// adapter binary (see acp/auto-install.ts). Shared with the HTTP route.
|
|
130
|
-
const { resolved, autoInstalledPackage, failureMessage } =
|
|
131
|
-
await resolveAgentWithAutoInstall(agent);
|
|
132
|
-
if (failureMessage) {
|
|
133
|
-
return { content: failureMessage, isError: true };
|
|
134
|
-
}
|
|
135
|
-
if (!resolved.ok) {
|
|
136
|
-
return { content: formatResolveFailure(agent, resolved), isError: true };
|
|
137
|
-
}
|
|
138
|
-
|
|
139
173
|
// Inject required env vars and preflight via the shared helper. Mirrors
|
|
140
174
|
// the HTTP route at `runtime/routes/acp-routes.ts:spawnSession` — both
|
|
141
175
|
// call sites MUST go through `prepareAgentEnv` before `manager.spawn`,
|
|
@@ -151,12 +185,8 @@ export async function executeAcpSpawn(
|
|
|
151
185
|
}
|
|
152
186
|
|
|
153
187
|
// Best-effort version check — never blocks the spawn. If outdated, we
|
|
154
|
-
// append a non-blocking warning to the success payload.
|
|
155
|
-
|
|
156
|
-
// fetches the package on first use), and npm may not exist on the host.
|
|
157
|
-
const versionInfo = runsViaBunx(agentConfig)
|
|
158
|
-
? null
|
|
159
|
-
: await checkAdapterVersion(adapterCommandOf(agentConfig));
|
|
188
|
+
// append a non-blocking warning to the success payload.
|
|
189
|
+
const versionInfo = await checkAdapterVersion(agentConfig.command);
|
|
160
190
|
|
|
161
191
|
try {
|
|
162
192
|
const manager = getAcpSessionManager();
|
|
@@ -167,21 +197,17 @@ export async function executeAcpSpawn(
|
|
|
167
197
|
task,
|
|
168
198
|
cwd,
|
|
169
199
|
context.conversationId,
|
|
170
|
-
sendToClient,
|
|
200
|
+
sendToClient as (msg: unknown) => void,
|
|
171
201
|
);
|
|
172
202
|
|
|
173
|
-
//
|
|
174
|
-
//
|
|
175
|
-
//
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
const resumeHint = hint ? ` ${hint}` : "";
|
|
182
|
-
const installNote = autoInstalledPackage
|
|
183
|
-
? ` Installed ${autoInstalledPackage} automatically.`
|
|
184
|
-
: "";
|
|
203
|
+
// `claude --resume <id>` is Claude Code-specific (the claude-agent-acp
|
|
204
|
+
// adapter binary). Other adapters resume differently or not at all,
|
|
205
|
+
// so the hint is gated by the resolved binary, not the agent id —
|
|
206
|
+
// this stays correct when a user aliases an id to a different binary.
|
|
207
|
+
const resumeHint =
|
|
208
|
+
agentConfig.command === "claude-agent-acp"
|
|
209
|
+
? ` To resume this session later, run: cd ${cwd} && claude --resume ${protocolSessionId}`
|
|
210
|
+
: "";
|
|
185
211
|
const payload = JSON.stringify({
|
|
186
212
|
acpSessionId,
|
|
187
213
|
protocolSessionId,
|
|
@@ -190,8 +216,7 @@ export async function executeAcpSpawn(
|
|
|
190
216
|
status: "running",
|
|
191
217
|
message:
|
|
192
218
|
`ACP agent "${agent}" spawned (session: ${protocolSessionId}). ` +
|
|
193
|
-
`Results stream back via SSE. You will be notified when it completes
|
|
194
|
-
`${installNote}${resumeHint}`,
|
|
219
|
+
`Results stream back via SSE. You will be notified when it completes.${resumeHint}`,
|
|
195
220
|
});
|
|
196
221
|
|
|
197
222
|
let content = payload;
|