@runfusion/fusion 0.1.3 → 0.2.0
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/dist/bin.js +2113 -1017
- package/dist/client/assets/AgentDetailView-CDZED6Dy.css +1 -0
- package/dist/client/assets/AgentDetailView-zycSdnO8.js +28 -0
- package/dist/client/assets/AgentsView-DoQkkDLf.css +1 -0
- package/dist/client/assets/AgentsView-pO7WiBS5.js +522 -0
- package/dist/client/assets/ChatView-BOd-sxbT.js +1 -0
- package/dist/client/assets/DevServerView-09GQf34f.js +11 -0
- package/dist/client/assets/DevServerView-ZeBGQkLI.css +1 -0
- package/dist/client/assets/DirectoryPicker-CcdN1Zs7.js +1 -0
- package/dist/client/assets/DocumentsView-CS8aiwtz.js +1 -0
- package/dist/client/assets/DocumentsView-Co9to4Zp.css +1 -0
- package/dist/client/assets/InsightsView-Bu9Cv8Ol.js +11 -0
- package/dist/client/assets/InsightsView-Egu71gmh.css +1 -0
- package/dist/client/assets/MemoryView-CtqgDtV9.js +2 -0
- package/dist/client/assets/MemoryView-DhinauGs.css +1 -0
- package/dist/client/assets/NodesView-BInPcedy.js +14 -0
- package/dist/client/assets/NodesView-DlQZHGXA.css +1 -0
- package/dist/client/assets/PiExtensionsManager-COxkYM2m.js +11 -0
- package/dist/client/assets/PiExtensionsManager-CPgmJgDk.css +1 -0
- package/dist/client/assets/PluginManager-CXUWZBOc.js +1 -0
- package/dist/client/assets/PluginManager-D64RIzmL.css +1 -0
- package/dist/client/assets/RoadmapsView-BOYnyMCh.css +1 -0
- package/dist/client/assets/RoadmapsView-BbCexaoi.js +6 -0
- package/dist/client/assets/SetupWizardModal-Cakxqkad.js +1 -0
- package/dist/client/assets/SkillsView-Cytf009Z.css +1 -0
- package/dist/client/assets/SkillsView-D3iqYCVf.js +1 -0
- package/dist/client/assets/folder-open-kO5Hsk66.js +6 -0
- package/dist/client/assets/index-BiSuUXCa.css +1 -0
- package/dist/client/assets/index-y194HxzU.js +644 -0
- package/dist/client/assets/upload-DHBQat92.js +6 -0
- package/dist/client/index.html +2 -2
- package/dist/extension.js +175 -66
- package/dist/pi-claude-cli/src/__tests__/control-handler.test.ts +191 -0
- package/dist/pi-claude-cli/src/__tests__/event-bridge.test.ts +1244 -0
- package/dist/pi-claude-cli/src/__tests__/mcp-config.test.ts +272 -0
- package/dist/pi-claude-cli/src/__tests__/process-manager.test.ts +619 -0
- package/dist/pi-claude-cli/src/__tests__/prompt-builder.test.ts +1067 -0
- package/dist/pi-claude-cli/src/__tests__/provider.test.ts +1902 -0
- package/dist/pi-claude-cli/src/__tests__/stream-parser.test.ts +188 -0
- package/dist/pi-claude-cli/src/__tests__/thinking-config.test.ts +141 -0
- package/dist/pi-claude-cli/src/__tests__/tool-mapping.test.ts +252 -0
- package/package.json +11 -5
- package/dist/client/assets/index-BuenKJX0.css +0 -1
- package/dist/client/assets/index-CjGu8HRV.js +0 -1250
|
@@ -0,0 +1,191 @@
|
|
|
1
|
+
import { describe, it, expect, vi } from "vitest";
|
|
2
|
+
import { PassThrough } from "node:stream";
|
|
3
|
+
import type { ClaudeControlRequest } from "../types";
|
|
4
|
+
import {
|
|
5
|
+
handleControlRequest,
|
|
6
|
+
TOOL_EXECUTION_DENIED_MESSAGE,
|
|
7
|
+
MCP_PREFIX,
|
|
8
|
+
} from "../control-handler";
|
|
9
|
+
|
|
10
|
+
function createMockStdin() {
|
|
11
|
+
const stream = new PassThrough();
|
|
12
|
+
const chunks: string[] = [];
|
|
13
|
+
stream.on("data", (data: Buffer) => chunks.push(data.toString()));
|
|
14
|
+
return { stream, chunks };
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
function makeControlRequest(
|
|
18
|
+
toolName: string,
|
|
19
|
+
requestId = "req-test-001",
|
|
20
|
+
input: Record<string, unknown> = {},
|
|
21
|
+
): ClaudeControlRequest {
|
|
22
|
+
return {
|
|
23
|
+
type: "control_request",
|
|
24
|
+
request_id: requestId,
|
|
25
|
+
request: {
|
|
26
|
+
subtype: "can_use_tool",
|
|
27
|
+
tool_name: toolName,
|
|
28
|
+
input,
|
|
29
|
+
},
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
describe("control-handler", () => {
|
|
34
|
+
describe("exported constants", () => {
|
|
35
|
+
it("exports TOOL_EXECUTION_DENIED_MESSAGE", () => {
|
|
36
|
+
expect(TOOL_EXECUTION_DENIED_MESSAGE).toBe(
|
|
37
|
+
"Tool execution is unavailable in this environment.",
|
|
38
|
+
);
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
it("exports MCP_PREFIX", () => {
|
|
42
|
+
expect(MCP_PREFIX).toBe("mcp__");
|
|
43
|
+
});
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
describe("denies custom MCP tools (mcp__custom-tools__*)", () => {
|
|
47
|
+
it("denies mcp__custom-tools__weather and returns false", () => {
|
|
48
|
+
const { stream, chunks } = createMockStdin();
|
|
49
|
+
const msg = makeControlRequest("mcp__custom-tools__weather");
|
|
50
|
+
|
|
51
|
+
const result = handleControlRequest(msg, stream);
|
|
52
|
+
|
|
53
|
+
expect(result).toBe(false);
|
|
54
|
+
const response = JSON.parse(chunks[0].trim());
|
|
55
|
+
expect(response.response.response.behavior).toBe("deny");
|
|
56
|
+
expect(response.response.response.message).toBe(
|
|
57
|
+
TOOL_EXECUTION_DENIED_MESSAGE,
|
|
58
|
+
);
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
it("denies mcp__custom-tools__deploy", () => {
|
|
62
|
+
const { stream, chunks } = createMockStdin();
|
|
63
|
+
const msg = makeControlRequest("mcp__custom-tools__deploy");
|
|
64
|
+
|
|
65
|
+
const result = handleControlRequest(msg, stream);
|
|
66
|
+
|
|
67
|
+
expect(result).toBe(false);
|
|
68
|
+
const response = JSON.parse(chunks[0].trim());
|
|
69
|
+
expect(response.response.response.behavior).toBe("deny");
|
|
70
|
+
});
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
describe("allows user MCP tools and other tools", () => {
|
|
74
|
+
it("allows user MCP tool mcp__database__query and returns true", () => {
|
|
75
|
+
const { stream, chunks } = createMockStdin();
|
|
76
|
+
const msg = makeControlRequest("mcp__database__query");
|
|
77
|
+
|
|
78
|
+
const result = handleControlRequest(msg, stream);
|
|
79
|
+
|
|
80
|
+
expect(result).toBe(true);
|
|
81
|
+
const response = JSON.parse(chunks[0].trim());
|
|
82
|
+
expect(response.response.response.behavior).toBe("allow");
|
|
83
|
+
});
|
|
84
|
+
|
|
85
|
+
it("allows built-in tool Read", () => {
|
|
86
|
+
const { stream, chunks } = createMockStdin();
|
|
87
|
+
const msg = makeControlRequest("Read");
|
|
88
|
+
|
|
89
|
+
const result = handleControlRequest(msg, stream);
|
|
90
|
+
|
|
91
|
+
expect(result).toBe(true);
|
|
92
|
+
const response = JSON.parse(chunks[0].trim());
|
|
93
|
+
expect(response.response.response.behavior).toBe("allow");
|
|
94
|
+
});
|
|
95
|
+
|
|
96
|
+
it("allows internal tools like ToolSearch", () => {
|
|
97
|
+
const { stream, chunks } = createMockStdin();
|
|
98
|
+
const msg = makeControlRequest("ToolSearch");
|
|
99
|
+
|
|
100
|
+
const result = handleControlRequest(msg, stream);
|
|
101
|
+
|
|
102
|
+
expect(result).toBe(true);
|
|
103
|
+
const response = JSON.parse(chunks[0].trim());
|
|
104
|
+
expect(response.response.response.behavior).toBe("allow");
|
|
105
|
+
});
|
|
106
|
+
|
|
107
|
+
it("allows unknown tools", () => {
|
|
108
|
+
const { stream, chunks } = createMockStdin();
|
|
109
|
+
const msg = makeControlRequest("SomeUnknownTool");
|
|
110
|
+
|
|
111
|
+
const result = handleControlRequest(msg, stream);
|
|
112
|
+
|
|
113
|
+
expect(result).toBe(true);
|
|
114
|
+
const response = JSON.parse(chunks[0].trim());
|
|
115
|
+
expect(response.response.response.behavior).toBe("allow");
|
|
116
|
+
});
|
|
117
|
+
});
|
|
118
|
+
|
|
119
|
+
describe("response format", () => {
|
|
120
|
+
it("includes matching request_id", () => {
|
|
121
|
+
const { stream, chunks } = createMockStdin();
|
|
122
|
+
const msg = makeControlRequest("Read", "custom-req-id-42");
|
|
123
|
+
|
|
124
|
+
handleControlRequest(msg, stream);
|
|
125
|
+
|
|
126
|
+
const response = JSON.parse(chunks[0].trim());
|
|
127
|
+
expect(response.request_id).toBe("custom-req-id-42");
|
|
128
|
+
});
|
|
129
|
+
|
|
130
|
+
it("writes response as NDJSON (JSON + newline)", () => {
|
|
131
|
+
const { stream, chunks } = createMockStdin();
|
|
132
|
+
const msg = makeControlRequest("Read");
|
|
133
|
+
|
|
134
|
+
handleControlRequest(msg, stream);
|
|
135
|
+
|
|
136
|
+
expect(chunks[0].endsWith("\n")).toBe(true);
|
|
137
|
+
expect(() => JSON.parse(chunks[0].trim())).not.toThrow();
|
|
138
|
+
});
|
|
139
|
+
|
|
140
|
+
it("deny response includes message field", () => {
|
|
141
|
+
const { stream, chunks } = createMockStdin();
|
|
142
|
+
const msg = makeControlRequest("mcp__custom-tools__foo");
|
|
143
|
+
|
|
144
|
+
handleControlRequest(msg, stream);
|
|
145
|
+
|
|
146
|
+
const response = JSON.parse(chunks[0].trim());
|
|
147
|
+
expect(response.response.response.message).toBe(
|
|
148
|
+
TOOL_EXECUTION_DENIED_MESSAGE,
|
|
149
|
+
);
|
|
150
|
+
});
|
|
151
|
+
|
|
152
|
+
it("allow response does not include a message field", () => {
|
|
153
|
+
const { stream, chunks } = createMockStdin();
|
|
154
|
+
const msg = makeControlRequest("mcp__database__query");
|
|
155
|
+
|
|
156
|
+
handleControlRequest(msg, stream);
|
|
157
|
+
|
|
158
|
+
const response = JSON.parse(chunks[0].trim());
|
|
159
|
+
expect(response.response.response.message).toBeUndefined();
|
|
160
|
+
});
|
|
161
|
+
});
|
|
162
|
+
|
|
163
|
+
describe("malformed input", () => {
|
|
164
|
+
it("returns false for missing request_id", () => {
|
|
165
|
+
const { stream } = createMockStdin();
|
|
166
|
+
const spy = vi.spyOn(console, "error").mockImplementation(() => {});
|
|
167
|
+
|
|
168
|
+
const msg = {
|
|
169
|
+
type: "control_request",
|
|
170
|
+
} as unknown as ClaudeControlRequest;
|
|
171
|
+
const result = handleControlRequest(msg, stream);
|
|
172
|
+
|
|
173
|
+
expect(result).toBe(false);
|
|
174
|
+
spy.mockRestore();
|
|
175
|
+
});
|
|
176
|
+
|
|
177
|
+
it("returns false for missing request object", () => {
|
|
178
|
+
const { stream } = createMockStdin();
|
|
179
|
+
const spy = vi.spyOn(console, "error").mockImplementation(() => {});
|
|
180
|
+
|
|
181
|
+
const msg = {
|
|
182
|
+
type: "control_request",
|
|
183
|
+
request_id: "req-001",
|
|
184
|
+
} as unknown as ClaudeControlRequest;
|
|
185
|
+
const result = handleControlRequest(msg, stream);
|
|
186
|
+
|
|
187
|
+
expect(result).toBe(false);
|
|
188
|
+
spy.mockRestore();
|
|
189
|
+
});
|
|
190
|
+
});
|
|
191
|
+
});
|