macro-agent 0.0.14 → 0.0.16

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.
Files changed (154) hide show
  1. package/.claude/settings.local.json +59 -0
  2. package/dist/acp/index.d.ts +1 -1
  3. package/dist/acp/index.d.ts.map +1 -1
  4. package/dist/acp/index.js.map +1 -1
  5. package/dist/acp/macro-agent.d.ts +21 -0
  6. package/dist/acp/macro-agent.d.ts.map +1 -1
  7. package/dist/acp/macro-agent.js +182 -0
  8. package/dist/acp/macro-agent.js.map +1 -1
  9. package/dist/acp/types.d.ts +31 -2
  10. package/dist/acp/types.d.ts.map +1 -1
  11. package/dist/acp/types.js.map +1 -1
  12. package/dist/agent/agent-manager.d.ts.map +1 -1
  13. package/dist/agent/agent-manager.js +10 -4
  14. package/dist/agent/agent-manager.js.map +1 -1
  15. package/dist/cli/acp.d.ts +6 -0
  16. package/dist/cli/acp.d.ts.map +1 -1
  17. package/dist/cli/acp.js +16 -2
  18. package/dist/cli/acp.js.map +1 -1
  19. package/dist/map/adapter/acp-over-map.d.ts +5 -0
  20. package/dist/map/adapter/acp-over-map.d.ts.map +1 -1
  21. package/dist/map/adapter/acp-over-map.js +47 -4
  22. package/dist/map/adapter/acp-over-map.js.map +1 -1
  23. package/dist/map/utils/address-translation.d.ts +99 -0
  24. package/dist/map/utils/address-translation.d.ts.map +1 -0
  25. package/dist/map/utils/address-translation.js +285 -0
  26. package/dist/map/utils/address-translation.js.map +1 -0
  27. package/dist/map/utils/index.d.ts +7 -0
  28. package/dist/map/utils/index.d.ts.map +1 -0
  29. package/dist/map/utils/index.js +7 -0
  30. package/dist/map/utils/index.js.map +1 -0
  31. package/dist/store/event-store.js +9 -2
  32. package/dist/store/event-store.js.map +1 -1
  33. package/dist/store/types/agents.d.ts +2 -0
  34. package/dist/store/types/agents.d.ts.map +1 -1
  35. package/package.json +4 -4
  36. package/references/acp-factory-ref/CHANGELOG.md +33 -0
  37. package/references/acp-factory-ref/LICENSE +21 -0
  38. package/references/acp-factory-ref/README.md +341 -0
  39. package/references/acp-factory-ref/package-lock.json +3102 -0
  40. package/references/acp-factory-ref/package.json +96 -0
  41. package/references/acp-factory-ref/python/CHANGELOG.md +33 -0
  42. package/references/acp-factory-ref/python/LICENSE +21 -0
  43. package/references/acp-factory-ref/python/Makefile +57 -0
  44. package/references/acp-factory-ref/python/README.md +253 -0
  45. package/references/acp-factory-ref/python/pyproject.toml +73 -0
  46. package/references/acp-factory-ref/python/tests/__init__.py +0 -0
  47. package/references/acp-factory-ref/python/tests/e2e/__init__.py +1 -0
  48. package/references/acp-factory-ref/python/tests/e2e/test_codex_e2e.py +349 -0
  49. package/references/acp-factory-ref/python/tests/e2e/test_gemini_e2e.py +165 -0
  50. package/references/acp-factory-ref/python/tests/e2e/test_opencode_e2e.py +296 -0
  51. package/references/acp-factory-ref/python/tests/test_client_handler.py +543 -0
  52. package/references/acp-factory-ref/python/tests/test_pushable.py +199 -0
  53. package/references/claude-code-acp/.github/workflows/ci.yml +45 -0
  54. package/references/claude-code-acp/.github/workflows/publish.yml +34 -0
  55. package/references/claude-code-acp/.prettierrc.json +4 -0
  56. package/references/claude-code-acp/CHANGELOG.md +249 -0
  57. package/references/claude-code-acp/LICENSE +222 -0
  58. package/references/claude-code-acp/README.md +53 -0
  59. package/references/claude-code-acp/docs/RELEASES.md +24 -0
  60. package/references/claude-code-acp/eslint.config.js +48 -0
  61. package/references/claude-code-acp/package-lock.json +4570 -0
  62. package/references/claude-code-acp/package.json +88 -0
  63. package/references/claude-code-acp/scripts/release.sh +119 -0
  64. package/references/claude-code-acp/src/acp-agent.ts +2079 -0
  65. package/references/claude-code-acp/src/index.ts +26 -0
  66. package/references/claude-code-acp/src/lib.ts +38 -0
  67. package/references/claude-code-acp/src/mcp-server.ts +911 -0
  68. package/references/claude-code-acp/src/settings.ts +522 -0
  69. package/references/claude-code-acp/src/tests/.claude/commands/quick-math.md +5 -0
  70. package/references/claude-code-acp/src/tests/.claude/commands/say-hello.md +6 -0
  71. package/references/claude-code-acp/src/tests/acp-agent-fork.test.ts +479 -0
  72. package/references/claude-code-acp/src/tests/acp-agent.test.ts +1502 -0
  73. package/references/claude-code-acp/src/tests/extract-lines.test.ts +103 -0
  74. package/references/claude-code-acp/src/tests/fork-session.test.ts +335 -0
  75. package/references/claude-code-acp/src/tests/replace-and-calculate-location.test.ts +334 -0
  76. package/references/claude-code-acp/src/tests/settings.test.ts +617 -0
  77. package/references/claude-code-acp/src/tests/skills-options.test.ts +187 -0
  78. package/references/claude-code-acp/src/tests/tools.test.ts +318 -0
  79. package/references/claude-code-acp/src/tests/typescript-declarations.test.ts +558 -0
  80. package/references/claude-code-acp/src/tools.ts +819 -0
  81. package/references/claude-code-acp/src/utils.ts +171 -0
  82. package/references/claude-code-acp/tsconfig.json +18 -0
  83. package/references/claude-code-acp/vitest.config.ts +19 -0
  84. package/references/multi-agent-protocol/.sudocode/issues.jsonl +111 -0
  85. package/references/multi-agent-protocol/.sudocode/specs.jsonl +13 -0
  86. package/references/multi-agent-protocol/LICENSE +21 -0
  87. package/references/multi-agent-protocol/README.md +113 -0
  88. package/references/multi-agent-protocol/docs/00-design-specification.md +496 -0
  89. package/references/multi-agent-protocol/docs/01-open-questions.md +1050 -0
  90. package/references/multi-agent-protocol/docs/02-wire-protocol.md +296 -0
  91. package/references/multi-agent-protocol/docs/03-streaming-semantics.md +252 -0
  92. package/references/multi-agent-protocol/docs/04-error-handling.md +231 -0
  93. package/references/multi-agent-protocol/docs/05-connection-model.md +244 -0
  94. package/references/multi-agent-protocol/docs/06-visibility-permissions.md +243 -0
  95. package/references/multi-agent-protocol/docs/07-federation.md +259 -0
  96. package/references/multi-agent-protocol/docs/08-macro-agent-migration.md +253 -0
  97. package/references/multi-agent-protocol/docs/09-authentication.md +680 -0
  98. package/references/multi-agent-protocol/docs/10-mail-protocol.md +553 -0
  99. package/references/multi-agent-protocol/docs/agent-iam-integration.md +877 -0
  100. package/references/multi-agent-protocol/docs/agentic-mesh-integration-draft.md +459 -0
  101. package/references/multi-agent-protocol/docs/git-transport-draft.md +251 -0
  102. package/references/multi-agent-protocol/docs-site/Gemfile +22 -0
  103. package/references/multi-agent-protocol/docs-site/README.md +82 -0
  104. package/references/multi-agent-protocol/docs-site/_config.yml +91 -0
  105. package/references/multi-agent-protocol/docs-site/_includes/head_custom.html +20 -0
  106. package/references/multi-agent-protocol/docs-site/_sass/color_schemes/map.scss +42 -0
  107. package/references/multi-agent-protocol/docs-site/_sass/custom/custom.scss +34 -0
  108. package/references/multi-agent-protocol/docs-site/examples/full-integration.md +510 -0
  109. package/references/multi-agent-protocol/docs-site/examples/index.md +138 -0
  110. package/references/multi-agent-protocol/docs-site/examples/simple-chat.md +282 -0
  111. package/references/multi-agent-protocol/docs-site/examples/task-queue.md +399 -0
  112. package/references/multi-agent-protocol/docs-site/getting-started/index.md +98 -0
  113. package/references/multi-agent-protocol/docs-site/getting-started/installation.md +219 -0
  114. package/references/multi-agent-protocol/docs-site/getting-started/overview.md +172 -0
  115. package/references/multi-agent-protocol/docs-site/getting-started/quickstart.md +237 -0
  116. package/references/multi-agent-protocol/docs-site/index.md +136 -0
  117. package/references/multi-agent-protocol/docs-site/protocol/authentication.md +391 -0
  118. package/references/multi-agent-protocol/docs-site/protocol/connection-model.md +376 -0
  119. package/references/multi-agent-protocol/docs-site/protocol/design.md +284 -0
  120. package/references/multi-agent-protocol/docs-site/protocol/error-handling.md +312 -0
  121. package/references/multi-agent-protocol/docs-site/protocol/federation.md +449 -0
  122. package/references/multi-agent-protocol/docs-site/protocol/index.md +129 -0
  123. package/references/multi-agent-protocol/docs-site/protocol/permissions.md +398 -0
  124. package/references/multi-agent-protocol/docs-site/protocol/streaming.md +353 -0
  125. package/references/multi-agent-protocol/docs-site/protocol/wire-protocol.md +369 -0
  126. package/references/multi-agent-protocol/docs-site/sdk/api/agent.md +357 -0
  127. package/references/multi-agent-protocol/docs-site/sdk/api/client.md +380 -0
  128. package/references/multi-agent-protocol/docs-site/sdk/api/index.md +62 -0
  129. package/references/multi-agent-protocol/docs-site/sdk/api/server.md +453 -0
  130. package/references/multi-agent-protocol/docs-site/sdk/api/types.md +468 -0
  131. package/references/multi-agent-protocol/docs-site/sdk/guides/agent.md +375 -0
  132. package/references/multi-agent-protocol/docs-site/sdk/guides/authentication.md +405 -0
  133. package/references/multi-agent-protocol/docs-site/sdk/guides/client.md +352 -0
  134. package/references/multi-agent-protocol/docs-site/sdk/guides/index.md +89 -0
  135. package/references/multi-agent-protocol/docs-site/sdk/guides/server.md +360 -0
  136. package/references/multi-agent-protocol/docs-site/sdk/guides/testing.md +446 -0
  137. package/references/multi-agent-protocol/docs-site/sdk/guides/transports.md +363 -0
  138. package/references/multi-agent-protocol/docs-site/sdk/index.md +206 -0
  139. package/references/multi-agent-protocol/package-lock.json +3886 -0
  140. package/references/multi-agent-protocol/package.json +56 -0
  141. package/references/multi-agent-protocol/schema/meta.json +467 -0
  142. package/references/multi-agent-protocol/schema/schema.json +2558 -0
  143. package/src/acp/__tests__/history.test.ts +526 -0
  144. package/src/acp/__tests__/integration.test.ts +2 -1
  145. package/src/acp/index.ts +4 -0
  146. package/src/acp/macro-agent.ts +329 -85
  147. package/src/acp/types.ts +39 -2
  148. package/src/agent/__tests__/agent-manager.test.ts +67 -1
  149. package/src/agent/agent-manager.ts +10 -4
  150. package/src/cli/__tests__/stable-instance-id.test.ts +57 -0
  151. package/src/cli/acp.ts +17 -2
  152. package/src/map/adapter/acp-over-map.ts +57 -2
  153. package/src/store/event-store.ts +10 -3
  154. package/src/store/types/agents.ts +2 -0
@@ -0,0 +1,187 @@
1
+ /**
2
+ * Tests for skills and plugins options handling.
3
+ *
4
+ * Run with: npx vitest run src/tests/skills-options.test.ts
5
+ */
6
+ import { describe, it, expect, beforeEach, vi } from "vitest";
7
+ import type { ClaudeAcpAgent } from "../acp-agent.js";
8
+
9
+ // Mock client for testing
10
+ const mockClient = {
11
+ sessionUpdate: vi.fn(),
12
+ extNotification: vi.fn(),
13
+ } as any;
14
+
15
+ describe("skills and plugins options", () => {
16
+ let agent: ClaudeAcpAgent;
17
+
18
+ beforeEach(async () => {
19
+ const { ClaudeAcpAgent } = await import("../acp-agent.js");
20
+ agent = new ClaudeAcpAgent(mockClient);
21
+ // Initialize the agent
22
+ await agent.initialize({
23
+ protocolVersion: 1,
24
+ clientInfo: { name: "test-client", version: "1.0.0" },
25
+ });
26
+ });
27
+
28
+ describe("settingSources option", () => {
29
+ it("should use default settingSources when not provided", async () => {
30
+ // We can't easily test the internal options object, but we can verify
31
+ // that the agent accepts a session request without settingSources
32
+ // This test mainly validates the code path doesn't throw
33
+ expect(agent).toBeDefined();
34
+ });
35
+
36
+ it("should accept custom settingSources in _meta", async () => {
37
+ // Verify that the NewSessionMeta type accepts settingSources
38
+ const meta = {
39
+ claudeCode: {
40
+ options: {
41
+ settingSources: ["project"] as const,
42
+ },
43
+ },
44
+ };
45
+ expect(meta.claudeCode.options.settingSources).toEqual(["project"]);
46
+ });
47
+
48
+ it("should accept all valid settingSources values", async () => {
49
+ const validSources = ["user", "project", "local"] as const;
50
+ const meta = {
51
+ claudeCode: {
52
+ options: {
53
+ settingSources: validSources,
54
+ },
55
+ },
56
+ };
57
+ expect(meta.claudeCode.options.settingSources).toHaveLength(3);
58
+ });
59
+ });
60
+
61
+ describe("plugins option", () => {
62
+ it("should accept plugins array in _meta", async () => {
63
+ const meta = {
64
+ claudeCode: {
65
+ options: {
66
+ plugins: [
67
+ { type: "local" as const, path: "./my-plugin" },
68
+ { type: "local" as const, path: "/absolute/path/to/plugin" },
69
+ ],
70
+ },
71
+ },
72
+ };
73
+ expect(meta.claudeCode.options.plugins).toHaveLength(2);
74
+ expect(meta.claudeCode.options.plugins[0].type).toBe("local");
75
+ expect(meta.claudeCode.options.plugins[0].path).toBe("./my-plugin");
76
+ });
77
+
78
+ it("should accept empty plugins array", async () => {
79
+ const meta = {
80
+ claudeCode: {
81
+ options: {
82
+ plugins: [],
83
+ },
84
+ },
85
+ };
86
+ expect(meta.claudeCode.options.plugins).toHaveLength(0);
87
+ });
88
+ });
89
+
90
+ describe("allowedTools option", () => {
91
+ it("should accept allowedTools array in _meta", async () => {
92
+ const meta = {
93
+ claudeCode: {
94
+ options: {
95
+ allowedTools: ["Skill", "Read", "Write", "Bash"],
96
+ },
97
+ },
98
+ };
99
+ expect(meta.claudeCode.options.allowedTools).toContain("Skill");
100
+ expect(meta.claudeCode.options.allowedTools).toHaveLength(4);
101
+ });
102
+
103
+ it("should accept Skill tool for enabling skills", async () => {
104
+ const meta = {
105
+ claudeCode: {
106
+ options: {
107
+ allowedTools: ["Skill"],
108
+ },
109
+ },
110
+ };
111
+ expect(meta.claudeCode.options.allowedTools).toContain("Skill");
112
+ });
113
+ });
114
+
115
+ describe("disallowedTools option", () => {
116
+ it("should accept disallowedTools array in _meta", async () => {
117
+ const meta = {
118
+ claudeCode: {
119
+ options: {
120
+ disallowedTools: ["WebSearch", "WebFetch"],
121
+ },
122
+ },
123
+ };
124
+ expect(meta.claudeCode.options.disallowedTools).toHaveLength(2);
125
+ });
126
+ });
127
+
128
+ describe("combined options", () => {
129
+ it("should accept full skills configuration", async () => {
130
+ const meta = {
131
+ claudeCode: {
132
+ options: {
133
+ settingSources: ["user", "project"] as const,
134
+ plugins: [{ type: "local" as const, path: "~/.claude/plugins/my-plugin" }],
135
+ allowedTools: ["Skill", "Read", "Write"],
136
+ disallowedTools: ["WebSearch"],
137
+ },
138
+ compaction: {
139
+ enabled: true,
140
+ contextTokenThreshold: 50000,
141
+ },
142
+ },
143
+ };
144
+
145
+ expect(meta.claudeCode.options.settingSources).toEqual(["user", "project"]);
146
+ expect(meta.claudeCode.options.plugins).toHaveLength(1);
147
+ expect(meta.claudeCode.options.allowedTools).toContain("Skill");
148
+ expect(meta.claudeCode.options.disallowedTools).toContain("WebSearch");
149
+ expect(meta.claudeCode.compaction?.enabled).toBe(true);
150
+ });
151
+ });
152
+ });
153
+
154
+ describe("SkillInfo type", () => {
155
+ it("should have correct structure", async () => {
156
+ const { SkillInfo } = await import("../acp-agent.js") as any;
157
+
158
+ // Test that the type structure is correct by creating a valid object
159
+ const skill = {
160
+ name: "test-skill",
161
+ description: "A test skill",
162
+ source: "project" as const,
163
+ };
164
+
165
+ expect(skill.name).toBe("test-skill");
166
+ expect(skill.description).toBe("A test skill");
167
+ expect(skill.source).toBe("project");
168
+ });
169
+
170
+ it("should allow optional fields", async () => {
171
+ const skill = {
172
+ name: "minimal-skill",
173
+ };
174
+
175
+ expect(skill.name).toBe("minimal-skill");
176
+ expect((skill as any).description).toBeUndefined();
177
+ expect((skill as any).source).toBeUndefined();
178
+ });
179
+
180
+ it("should accept all valid source values", async () => {
181
+ const sources = ["user", "project", "plugin"] as const;
182
+ sources.forEach((source) => {
183
+ const skill = { name: "test", source };
184
+ expect(skill.source).toBe(source);
185
+ });
186
+ });
187
+ });
@@ -0,0 +1,318 @@
1
+ import { describe, it, expect } from "vitest";
2
+ import { AgentSideConnection } from "@agentclientprotocol/sdk";
3
+ import { ToolResultBlockParam } from "@anthropic-ai/sdk/resources";
4
+ import {
5
+ BetaMCPToolResultBlock,
6
+ BetaTextBlock,
7
+ BetaWebSearchResultBlock,
8
+ BetaWebSearchToolResultBlock,
9
+ BetaBashCodeExecutionToolResultBlock,
10
+ BetaBashCodeExecutionResultBlock,
11
+ } from "@anthropic-ai/sdk/resources/beta.mjs";
12
+ import { toAcpNotifications, ToolUseCache, Logger } from "../acp-agent.js";
13
+
14
+ describe("rawOutput in tool call updates", () => {
15
+ const mockClient = {} as AgentSideConnection;
16
+ const mockLogger: Logger = { log: () => {}, error: () => {} };
17
+
18
+ it("should include rawOutput with string content for tool_result", () => {
19
+ const toolUseCache: ToolUseCache = {
20
+ toolu_123: {
21
+ type: "tool_use",
22
+ id: "toolu_123",
23
+ name: "Bash",
24
+ input: { command: "echo hello" },
25
+ },
26
+ };
27
+
28
+ const toolResult: ToolResultBlockParam = {
29
+ type: "tool_result",
30
+ tool_use_id: "toolu_123",
31
+ content: "hello\n",
32
+ is_error: false,
33
+ };
34
+
35
+ const notifications = toAcpNotifications(
36
+ [toolResult],
37
+ "assistant",
38
+ "test-session",
39
+ toolUseCache,
40
+ mockClient,
41
+ mockLogger,
42
+ );
43
+
44
+ expect(notifications).toHaveLength(1);
45
+ expect(notifications[0].update).toMatchObject({
46
+ sessionUpdate: "tool_call_update",
47
+ toolCallId: "toolu_123",
48
+ status: "completed",
49
+ rawOutput: "hello\n",
50
+ });
51
+ });
52
+
53
+ it("should include rawOutput with array content for tool_result", () => {
54
+ const toolUseCache: ToolUseCache = {
55
+ toolu_456: {
56
+ type: "tool_use",
57
+ id: "toolu_456",
58
+ name: "Read",
59
+ input: { file_path: "/test/file.txt" },
60
+ },
61
+ };
62
+
63
+ // ToolResultBlockParam content can be string or array of TextBlockParam
64
+ const toolResult: ToolResultBlockParam = {
65
+ type: "tool_result",
66
+ tool_use_id: "toolu_456",
67
+ content: [{ type: "text", text: "Line 1\nLine 2\nLine 3" }],
68
+ is_error: false,
69
+ };
70
+
71
+ const notifications = toAcpNotifications(
72
+ [toolResult],
73
+ "assistant",
74
+ "test-session",
75
+ toolUseCache,
76
+ mockClient,
77
+ mockLogger,
78
+ );
79
+
80
+ expect(notifications).toHaveLength(1);
81
+ expect(notifications[0].update).toMatchObject({
82
+ sessionUpdate: "tool_call_update",
83
+ toolCallId: "toolu_456",
84
+ status: "completed",
85
+ rawOutput: [{ type: "text", text: "Line 1\nLine 2\nLine 3" }],
86
+ });
87
+ });
88
+
89
+ it("should include rawOutput for mcp_tool_result with string content", () => {
90
+ const toolUseCache: ToolUseCache = {
91
+ toolu_789: {
92
+ type: "tool_use",
93
+ id: "toolu_789",
94
+ name: "mcp__server__tool",
95
+ input: { query: "test" },
96
+ },
97
+ };
98
+
99
+ // BetaMCPToolResultBlock content can be string or Array<BetaTextBlock>
100
+ const toolResult: BetaMCPToolResultBlock = {
101
+ type: "mcp_tool_result",
102
+ tool_use_id: "toolu_789",
103
+ content: '{"result": "success", "data": [1, 2, 3]}',
104
+ is_error: false,
105
+ };
106
+
107
+ const notifications = toAcpNotifications(
108
+ [toolResult],
109
+ "assistant",
110
+ "test-session",
111
+ toolUseCache,
112
+ mockClient,
113
+ mockLogger,
114
+ );
115
+
116
+ expect(notifications).toHaveLength(1);
117
+ expect(notifications[0].update).toMatchObject({
118
+ sessionUpdate: "tool_call_update",
119
+ toolCallId: "toolu_789",
120
+ status: "completed",
121
+ rawOutput: '{"result": "success", "data": [1, 2, 3]}',
122
+ });
123
+ });
124
+
125
+ it("should include rawOutput for mcp_tool_result with array content", () => {
126
+ const toolUseCache: ToolUseCache = {
127
+ toolu_abc: {
128
+ type: "tool_use",
129
+ id: "toolu_abc",
130
+ name: "mcp__server__search",
131
+ input: { term: "test" },
132
+ },
133
+ };
134
+
135
+ // BetaTextBlock requires citations field
136
+ const arrayContent: BetaTextBlock[] = [
137
+ { type: "text", text: "Result 1", citations: null },
138
+ { type: "text", text: "Result 2", citations: null },
139
+ ];
140
+
141
+ const toolResult: BetaMCPToolResultBlock = {
142
+ type: "mcp_tool_result",
143
+ tool_use_id: "toolu_abc",
144
+ content: arrayContent,
145
+ is_error: false,
146
+ };
147
+
148
+ const notifications = toAcpNotifications(
149
+ [toolResult],
150
+ "assistant",
151
+ "test-session",
152
+ toolUseCache,
153
+ mockClient,
154
+ mockLogger,
155
+ );
156
+
157
+ expect(notifications).toHaveLength(1);
158
+ expect(notifications[0].update).toMatchObject({
159
+ sessionUpdate: "tool_call_update",
160
+ toolCallId: "toolu_abc",
161
+ status: "completed",
162
+ rawOutput: arrayContent,
163
+ });
164
+ });
165
+
166
+ it("should include rawOutput for web_search_tool_result", () => {
167
+ const toolUseCache: ToolUseCache = {
168
+ toolu_web: {
169
+ type: "tool_use",
170
+ id: "toolu_web",
171
+ name: "WebSearch",
172
+ input: { query: "test search" },
173
+ },
174
+ };
175
+
176
+ // BetaWebSearchResultBlock from SDK
177
+ const searchResults: BetaWebSearchResultBlock[] = [
178
+ {
179
+ type: "web_search_result",
180
+ url: "https://example.com",
181
+ title: "Example",
182
+ encrypted_content: "encrypted content here",
183
+ page_age: "2 days ago",
184
+ },
185
+ ];
186
+
187
+ const toolResult: BetaWebSearchToolResultBlock = {
188
+ type: "web_search_tool_result",
189
+ tool_use_id: "toolu_web",
190
+ content: searchResults,
191
+ };
192
+
193
+ const notifications = toAcpNotifications(
194
+ [toolResult],
195
+ "assistant",
196
+ "test-session",
197
+ toolUseCache,
198
+ mockClient,
199
+ mockLogger,
200
+ );
201
+
202
+ expect(notifications).toHaveLength(1);
203
+ expect(notifications[0].update).toMatchObject({
204
+ sessionUpdate: "tool_call_update",
205
+ toolCallId: "toolu_web",
206
+ status: "completed",
207
+ rawOutput: searchResults,
208
+ });
209
+ });
210
+
211
+ it("should include rawOutput for bash_code_execution_tool_result", () => {
212
+ const toolUseCache: ToolUseCache = {
213
+ toolu_bash: {
214
+ type: "tool_use",
215
+ id: "toolu_bash",
216
+ name: "Bash",
217
+ input: { command: "ls -la" },
218
+ },
219
+ };
220
+
221
+ // BetaBashCodeExecutionResultBlock from SDK
222
+ const bashResult: BetaBashCodeExecutionResultBlock = {
223
+ type: "bash_code_execution_result",
224
+ stdout: "file1.txt\nfile2.txt",
225
+ stderr: "",
226
+ return_code: 0,
227
+ content: [],
228
+ };
229
+
230
+ const toolResult: BetaBashCodeExecutionToolResultBlock = {
231
+ type: "bash_code_execution_tool_result",
232
+ tool_use_id: "toolu_bash",
233
+ content: bashResult,
234
+ };
235
+
236
+ const notifications = toAcpNotifications(
237
+ [toolResult],
238
+ "assistant",
239
+ "test-session",
240
+ toolUseCache,
241
+ mockClient,
242
+ mockLogger,
243
+ );
244
+
245
+ expect(notifications).toHaveLength(1);
246
+ expect(notifications[0].update).toMatchObject({
247
+ sessionUpdate: "tool_call_update",
248
+ toolCallId: "toolu_bash",
249
+ status: "completed",
250
+ rawOutput: bashResult,
251
+ });
252
+ });
253
+
254
+ it("should set status to failed when is_error is true", () => {
255
+ const toolUseCache: ToolUseCache = {
256
+ toolu_err: {
257
+ type: "tool_use",
258
+ id: "toolu_err",
259
+ name: "Bash",
260
+ input: { command: "invalid_command" },
261
+ },
262
+ };
263
+
264
+ const toolResult: ToolResultBlockParam = {
265
+ type: "tool_result",
266
+ tool_use_id: "toolu_err",
267
+ content: "command not found: invalid_command",
268
+ is_error: true,
269
+ };
270
+
271
+ const notifications = toAcpNotifications(
272
+ [toolResult],
273
+ "assistant",
274
+ "test-session",
275
+ toolUseCache,
276
+ mockClient,
277
+ mockLogger,
278
+ );
279
+
280
+ expect(notifications).toHaveLength(1);
281
+ expect(notifications[0].update).toMatchObject({
282
+ sessionUpdate: "tool_call_update",
283
+ toolCallId: "toolu_err",
284
+ status: "failed",
285
+ rawOutput: "command not found: invalid_command",
286
+ });
287
+ });
288
+
289
+ it("should not emit tool_call_update for TodoWrite (emits plan instead)", () => {
290
+ const toolUseCache: ToolUseCache = {
291
+ toolu_todo: {
292
+ type: "tool_use",
293
+ id: "toolu_todo",
294
+ name: "TodoWrite",
295
+ input: { todos: [{ content: "Test task", status: "pending" }] },
296
+ },
297
+ };
298
+
299
+ const toolResult: ToolResultBlockParam = {
300
+ type: "tool_result",
301
+ tool_use_id: "toolu_todo",
302
+ content: "Todos updated successfully",
303
+ is_error: false,
304
+ };
305
+
306
+ const notifications = toAcpNotifications(
307
+ [toolResult],
308
+ "assistant",
309
+ "test-session",
310
+ toolUseCache,
311
+ mockClient,
312
+ mockLogger,
313
+ );
314
+
315
+ // TodoWrite should not emit tool_call_update - it emits plan updates instead
316
+ expect(notifications).toHaveLength(0);
317
+ });
318
+ });