@sammorrowdrums/mcpi-ext 0.1.0 → 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.
Files changed (170) hide show
  1. package/.github/workflows/ci.yml +1 -1
  2. package/README.md +109 -139
  3. package/docs/code-mode.md +38 -0
  4. package/docs/skills.md +57 -0
  5. package/docs/tool-cli.md +54 -0
  6. package/images/code-mode-histogram.png +0 -0
  7. package/images/skills-enabling-mcp-tools.png +0 -0
  8. package/images/tool-cli-grep.png +0 -0
  9. package/mise.toml +1 -13
  10. package/package.json +5 -7
  11. package/scripts/test-tool-cli-smoke.mjs +40 -9
  12. package/src/index.ts +24 -3
  13. package/src/tool-cli/index.ts +2 -2
  14. package/dist/code-mode/code-mode-integration.test.d.ts +0 -2
  15. package/dist/code-mode/code-mode-integration.test.d.ts.map +0 -1
  16. package/dist/code-mode/code-mode-integration.test.js +0 -116
  17. package/dist/code-mode/code-mode-integration.test.js.map +0 -1
  18. package/dist/code-mode/eligibility.d.ts +0 -10
  19. package/dist/code-mode/eligibility.d.ts.map +0 -1
  20. package/dist/code-mode/eligibility.js +0 -14
  21. package/dist/code-mode/eligibility.js.map +0 -1
  22. package/dist/code-mode/eligibility.test.d.ts +0 -2
  23. package/dist/code-mode/eligibility.test.d.ts.map +0 -1
  24. package/dist/code-mode/eligibility.test.js +0 -53
  25. package/dist/code-mode/eligibility.test.js.map +0 -1
  26. package/dist/code-mode/executor.d.ts +0 -35
  27. package/dist/code-mode/executor.d.ts.map +0 -1
  28. package/dist/code-mode/executor.js +0 -120
  29. package/dist/code-mode/executor.js.map +0 -1
  30. package/dist/code-mode/executor.test.d.ts +0 -2
  31. package/dist/code-mode/executor.test.d.ts.map +0 -1
  32. package/dist/code-mode/executor.test.js +0 -130
  33. package/dist/code-mode/executor.test.js.map +0 -1
  34. package/dist/code-mode/index.d.ts +0 -65
  35. package/dist/code-mode/index.d.ts.map +0 -1
  36. package/dist/code-mode/index.js +0 -175
  37. package/dist/code-mode/index.js.map +0 -1
  38. package/dist/code-mode/tools.d.ts +0 -45
  39. package/dist/code-mode/tools.d.ts.map +0 -1
  40. package/dist/code-mode/tools.js +0 -70
  41. package/dist/code-mode/tools.js.map +0 -1
  42. package/dist/code-mode/type-hints.d.ts +0 -20
  43. package/dist/code-mode/type-hints.d.ts.map +0 -1
  44. package/dist/code-mode/type-hints.js +0 -189
  45. package/dist/code-mode/type-hints.js.map +0 -1
  46. package/dist/code-mode/type-hints.test.d.ts +0 -2
  47. package/dist/code-mode/type-hints.test.d.ts.map +0 -1
  48. package/dist/code-mode/type-hints.test.js +0 -157
  49. package/dist/code-mode/type-hints.test.js.map +0 -1
  50. package/dist/docker-e2e.d.ts +0 -55
  51. package/dist/docker-e2e.d.ts.map +0 -1
  52. package/dist/docker-e2e.js +0 -235
  53. package/dist/docker-e2e.js.map +0 -1
  54. package/dist/docker-e2e.test.d.ts +0 -2
  55. package/dist/docker-e2e.test.d.ts.map +0 -1
  56. package/dist/docker-e2e.test.js +0 -176
  57. package/dist/docker-e2e.test.js.map +0 -1
  58. package/dist/index.d.ts +0 -3
  59. package/dist/index.d.ts.map +0 -1
  60. package/dist/index.js +0 -128
  61. package/dist/index.js.map +0 -1
  62. package/dist/index.test.d.ts +0 -2
  63. package/dist/index.test.d.ts.map +0 -1
  64. package/dist/index.test.js +0 -8
  65. package/dist/index.test.js.map +0 -1
  66. package/dist/mcp/client-manager.d.ts +0 -46
  67. package/dist/mcp/client-manager.d.ts.map +0 -1
  68. package/dist/mcp/client-manager.js +0 -148
  69. package/dist/mcp/client-manager.js.map +0 -1
  70. package/dist/mcp/client-manager.test.d.ts +0 -2
  71. package/dist/mcp/client-manager.test.d.ts.map +0 -1
  72. package/dist/mcp/client-manager.test.js +0 -204
  73. package/dist/mcp/client-manager.test.js.map +0 -1
  74. package/dist/mcp/config-loader.d.ts +0 -8
  75. package/dist/mcp/config-loader.d.ts.map +0 -1
  76. package/dist/mcp/config-loader.js +0 -43
  77. package/dist/mcp/config-loader.js.map +0 -1
  78. package/dist/mcp/config-loader.test.d.ts +0 -2
  79. package/dist/mcp/config-loader.test.d.ts.map +0 -1
  80. package/dist/mcp/config-loader.test.js +0 -93
  81. package/dist/mcp/config-loader.test.js.map +0 -1
  82. package/dist/mcp/config.d.ts +0 -46
  83. package/dist/mcp/config.d.ts.map +0 -1
  84. package/dist/mcp/config.js +0 -28
  85. package/dist/mcp/config.js.map +0 -1
  86. package/dist/mcp/index.d.ts +0 -5
  87. package/dist/mcp/index.d.ts.map +0 -1
  88. package/dist/mcp/index.js +0 -4
  89. package/dist/mcp/index.js.map +0 -1
  90. package/dist/skills/discover.d.ts +0 -10
  91. package/dist/skills/discover.d.ts.map +0 -1
  92. package/dist/skills/discover.js +0 -60
  93. package/dist/skills/discover.js.map +0 -1
  94. package/dist/skills/format.d.ts +0 -10
  95. package/dist/skills/format.d.ts.map +0 -1
  96. package/dist/skills/format.js +0 -38
  97. package/dist/skills/format.js.map +0 -1
  98. package/dist/skills/format.test.d.ts +0 -2
  99. package/dist/skills/format.test.d.ts.map +0 -1
  100. package/dist/skills/format.test.js +0 -63
  101. package/dist/skills/format.test.js.map +0 -1
  102. package/dist/skills/index.d.ts +0 -6
  103. package/dist/skills/index.d.ts.map +0 -1
  104. package/dist/skills/index.js +0 -6
  105. package/dist/skills/index.js.map +0 -1
  106. package/dist/skills/load-skill-tool.d.ts +0 -40
  107. package/dist/skills/load-skill-tool.d.ts.map +0 -1
  108. package/dist/skills/load-skill-tool.js +0 -104
  109. package/dist/skills/load-skill-tool.js.map +0 -1
  110. package/dist/skills/mcp-tool-proxy.d.ts +0 -11
  111. package/dist/skills/mcp-tool-proxy.d.ts.map +0 -1
  112. package/dist/skills/mcp-tool-proxy.js +0 -116
  113. package/dist/skills/mcp-tool-proxy.js.map +0 -1
  114. package/dist/skills/skill-integration.test.d.ts +0 -2
  115. package/dist/skills/skill-integration.test.d.ts.map +0 -1
  116. package/dist/skills/skill-integration.test.js +0 -119
  117. package/dist/skills/skill-integration.test.js.map +0 -1
  118. package/dist/skills/skill-registry.d.ts +0 -39
  119. package/dist/skills/skill-registry.d.ts.map +0 -1
  120. package/dist/skills/skill-registry.js +0 -48
  121. package/dist/skills/skill-registry.js.map +0 -1
  122. package/dist/skills/skill-registry.test.d.ts +0 -2
  123. package/dist/skills/skill-registry.test.d.ts.map +0 -1
  124. package/dist/skills/skill-registry.test.js +0 -67
  125. package/dist/skills/skill-registry.test.js.map +0 -1
  126. package/dist/test-servers/weather-server.d.ts +0 -12
  127. package/dist/test-servers/weather-server.d.ts.map +0 -1
  128. package/dist/test-servers/weather-server.js +0 -139
  129. package/dist/test-servers/weather-server.js.map +0 -1
  130. package/dist/test-servers/weather-stdio.d.ts +0 -2
  131. package/dist/test-servers/weather-stdio.d.ts.map +0 -1
  132. package/dist/test-servers/weather-stdio.js +0 -11
  133. package/dist/test-servers/weather-stdio.js.map +0 -1
  134. package/dist/tool-cli/cli.d.ts +0 -3
  135. package/dist/tool-cli/cli.d.ts.map +0 -1
  136. package/dist/tool-cli/cli.js +0 -179
  137. package/dist/tool-cli/cli.js.map +0 -1
  138. package/dist/tool-cli/constants.d.ts +0 -7
  139. package/dist/tool-cli/constants.d.ts.map +0 -1
  140. package/dist/tool-cli/constants.js +0 -15
  141. package/dist/tool-cli/constants.js.map +0 -1
  142. package/dist/tool-cli/format.d.ts +0 -8
  143. package/dist/tool-cli/format.d.ts.map +0 -1
  144. package/dist/tool-cli/format.js +0 -57
  145. package/dist/tool-cli/format.js.map +0 -1
  146. package/dist/tool-cli/format.test.d.ts +0 -2
  147. package/dist/tool-cli/format.test.d.ts.map +0 -1
  148. package/dist/tool-cli/format.test.js +0 -30
  149. package/dist/tool-cli/format.test.js.map +0 -1
  150. package/dist/tool-cli/index.d.ts +0 -4
  151. package/dist/tool-cli/index.d.ts.map +0 -1
  152. package/dist/tool-cli/index.js +0 -4
  153. package/dist/tool-cli/index.js.map +0 -1
  154. package/dist/tool-cli/rpc-client.d.ts +0 -6
  155. package/dist/tool-cli/rpc-client.d.ts.map +0 -1
  156. package/dist/tool-cli/rpc-client.js +0 -25
  157. package/dist/tool-cli/rpc-client.js.map +0 -1
  158. package/dist/tool-cli/rpc-server.d.ts +0 -48
  159. package/dist/tool-cli/rpc-server.d.ts.map +0 -1
  160. package/dist/tool-cli/rpc-server.js +0 -220
  161. package/dist/tool-cli/rpc-server.js.map +0 -1
  162. package/dist/tool-cli/rpc-server.test.d.ts +0 -2
  163. package/dist/tool-cli/rpc-server.test.d.ts.map +0 -1
  164. package/dist/tool-cli/rpc-server.test.js +0 -154
  165. package/dist/tool-cli/rpc-server.test.js.map +0 -1
  166. package/src/tool-cli/cli.ts +0 -232
  167. package/src/tool-cli/constants.ts +0 -15
  168. package/src/tool-cli/rpc-client.ts +0 -39
  169. package/src/tool-cli/rpc-server.test.ts +0 -193
  170. package/src/tool-cli/rpc-server.ts +0 -287
@@ -1,28 +1,42 @@
1
1
  #!/usr/bin/env node
2
2
  /**
3
3
  * Smoke test: start RPC server with the weather test server,
4
- * exercise every tool-cli command, then shut down.
4
+ * exercise every tool-cli command via the CLI binary, then shut down.
5
+ *
6
+ * Tests the full wiring: ToolProvider → ToolCliServer → tool-cli CLI.
5
7
  */
6
8
  import { McpClientManager } from "../dist/mcp/client-manager.js";
7
- import { ToolCliRpcServer } from "../dist/tool-cli/rpc-server.js";
9
+ import { ToolCliServer } from "@sammorrowdrums/tool-cli/server";
8
10
  import { execFile } from "node:child_process";
9
11
  import { promisify } from "node:util";
12
+ import { dirname, join } from "node:path";
13
+ import { fileURLToPath } from "node:url";
10
14
 
11
15
  const execFileAsync = promisify(execFile);
12
- const CLI = "dist/tool-cli/cli.js";
16
+
17
+ // Resolve the tool-cli binary from node_modules/.bin
18
+ const __dirname = dirname(fileURLToPath(import.meta.url));
19
+ const CLI = join(__dirname, "..", "node_modules", ".bin", "tool-cli");
20
+
13
21
  const manager = new McpClientManager();
14
- let rpc;
22
+ let server;
15
23
 
16
24
  async function run(...args) {
17
25
  const { stdout } = await execFileAsync("node", [CLI, ...args], {
18
26
  encoding: "utf-8",
19
- env: { ...process.env, TOOL_CLI_PORT: String(rpc.getPort()) },
27
+ env: {
28
+ ...process.env,
29
+ TOOL_CLI_PORT: String(server.getPort()),
30
+ TOOL_CLI_TOKEN: token,
31
+ },
20
32
  });
21
33
  console.log(`$ tool-cli ${args.join(" ")}`);
22
34
  console.log(stdout);
23
35
  return stdout;
24
36
  }
25
37
 
38
+ let token;
39
+
26
40
  try {
27
41
  await manager.connectOne("weather", {
28
42
  type: "stdio",
@@ -30,8 +44,25 @@ try {
30
44
  args: ["dist/test-servers/weather-stdio.js"],
31
45
  });
32
46
 
33
- rpc = new ToolCliRpcServer(manager, 0);
34
- await rpc.start(console.log);
47
+ // Bridge McpClientManager to ToolProvider
48
+ const provider = {
49
+ getServerNames: () => manager.getConnectedServers(),
50
+ getTools: (s) => manager.getToolsForServer(s),
51
+ async callTool(s, tool, args) {
52
+ const client = manager.getClient(s);
53
+ if (!client) throw new Error(`No client for "${s}"`);
54
+ const result = await client.callTool({ name: tool, arguments: args });
55
+ return {
56
+ content: result.content,
57
+ isError: result.isError === true ? true : undefined,
58
+ structuredContent: result.structuredContent,
59
+ };
60
+ },
61
+ };
62
+
63
+ server = new ToolCliServer(provider);
64
+ const startResult = await server.start(console.log);
65
+ token = startResult.token;
35
66
 
36
67
  // --help: list servers
37
68
  const help = await run("--help");
@@ -50,13 +81,13 @@ try {
50
81
  const result = await run("weather", "check_weather_for_city", '{"city":"London"}');
51
82
  if (!result.includes("London")) throw new Error("call result missing London");
52
83
 
53
- await rpc.stop();
84
+ await server.stop();
54
85
  await manager.disconnectAll();
55
86
  console.log("Smoke test passed ✓");
56
87
  process.exit(0);
57
88
  } catch (err) {
58
89
  console.error("Smoke test failed:", err);
59
- await rpc?.stop().catch(() => {});
90
+ await server?.stop().catch(() => {});
60
91
  await manager.disconnectAll().catch(() => {});
61
92
  process.exit(1);
62
93
  }
package/src/index.ts CHANGED
@@ -15,7 +15,8 @@ import {
15
15
  formatMcpSkillsForPrompt,
16
16
  registerMcpToolProxies,
17
17
  } from "./skills/index.js";
18
- import { ToolCliRpcServer, formatToolCliForPrompt } from "./tool-cli/index.js";
18
+ import { ToolCliServer, formatToolCliForPrompt } from "./tool-cli/index.js";
19
+ import type { ToolProvider } from "./tool-cli/index.js";
19
20
 
20
21
  export default function (pi: ExtensionAPI) {
21
22
  pi.registerTool(dockerE2ETool);
@@ -27,11 +28,27 @@ export default function (pi: ExtensionAPI) {
27
28
 
28
29
  const mcpManager = new McpClientManager();
29
30
  const skillRegistry = new SkillRegistry();
30
- const rpcServer = new ToolCliRpcServer(mcpManager);
31
31
  const codeModeManager = new CodeModeManager();
32
32
  const enabledTools = new Set<string>();
33
33
  const gatedToolNames = new Set<string>();
34
34
 
35
+ // Bridge McpClientManager to the ToolProvider interface
36
+ const toolProvider: ToolProvider = {
37
+ getServerNames: () => mcpManager.getConnectedServers(),
38
+ getTools: (server) => mcpManager.getToolsForServer(server),
39
+ async callTool(server, tool, args) {
40
+ const client = mcpManager.getClient(server);
41
+ if (!client) throw new Error(`No client for server "${server}"`);
42
+ const result = await client.callTool({ name: tool, arguments: args });
43
+ return {
44
+ content: result.content as unknown[],
45
+ isError: result.isError === true ? true : undefined,
46
+ structuredContent: result.structuredContent as Record<string, unknown> | undefined,
47
+ };
48
+ },
49
+ };
50
+ const rpcServer = new ToolCliServer(toolProvider);
51
+
35
52
  // Register the load_skill tool so the model can activate MCP skills
36
53
  pi.registerTool(createLoadSkillTool({ registry: skillRegistry, mcpManager, enabledTools }));
37
54
 
@@ -90,7 +107,9 @@ export default function (pi: ExtensionAPI) {
90
107
 
91
108
  // Start the tool-cli RPC server for progressive tool discovery
92
109
  try {
93
- await rpcServer.start(log);
110
+ const { port, token } = await rpcServer.start(log);
111
+ pi.setEnv("TOOL_CLI_PORT", String(port));
112
+ pi.setEnv("TOOL_CLI_TOKEN", token);
94
113
  } catch (err) {
95
114
  log(`[tool-cli] Failed to start RPC server: ${(err as Error).message}`);
96
115
  }
@@ -151,6 +170,8 @@ export default function (pi: ExtensionAPI) {
151
170
  });
152
171
 
153
172
  pi.on("session_shutdown", async () => {
173
+ pi.unsetEnv("TOOL_CLI_PORT");
174
+ pi.unsetEnv("TOOL_CLI_TOKEN");
154
175
  await rpcServer.stop();
155
176
  await mcpManager.disconnectAll();
156
177
  skillRegistry.clear();
@@ -1,3 +1,3 @@
1
- export { ToolCliRpcServer } from "./rpc-server.js";
1
+ export { ToolCliServer } from "@sammorrowdrums/tool-cli/server";
2
+ export type { ToolProvider } from "@sammorrowdrums/tool-cli/server";
2
3
  export { formatToolCliForPrompt } from "./format.js";
3
- export { DEFAULT_PORT, PORT_ENV_VAR, resolvePort } from "./constants.js";
@@ -1,2 +0,0 @@
1
- export {};
2
- //# sourceMappingURL=code-mode-integration.test.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"code-mode-integration.test.d.ts","sourceRoot":"","sources":["../../src/code-mode/code-mode-integration.test.ts"],"names":[],"mappings":""}
@@ -1,116 +0,0 @@
1
- import { describe, it, expect, beforeAll, afterAll } from "vitest";
2
- import { McpClientManager } from "../mcp/client-manager.js";
3
- import { CodeModeManager } from "./index.js";
4
- /**
5
- * Integration test: connect to the test weather server, verify code mode
6
- * eligibility, type hint generation, and sandboxed execution with real
7
- * MCP tool calls returning structuredContent.
8
- */
9
- describe("code mode integration (weather server)", () => {
10
- const manager = new McpClientManager();
11
- const codeMode = new CodeModeManager();
12
- beforeAll(async () => {
13
- await manager.connectAll({
14
- mcpServers: {
15
- "test-weather": {
16
- type: "stdio",
17
- command: "node",
18
- args: ["dist/test-servers/weather-stdio.js"],
19
- },
20
- },
21
- });
22
- codeMode.initialize(manager);
23
- });
24
- afterAll(async () => {
25
- await manager.disconnectAll();
26
- });
27
- it("discovers eligible tools with readOnlyHint + outputSchema", () => {
28
- const eligible = codeMode.getEligibleTools();
29
- expect(eligible.length).toBeGreaterThanOrEqual(2);
30
- const names = eligible.map((t) => t.name).sort();
31
- expect(names).toContain("check_weather_for_city");
32
- expect(names).toContain("check_weekly_forecast_for_city");
33
- expect(names).toContain("echo");
34
- });
35
- it("generates type hints for eligible tools", () => {
36
- const hints = codeMode.getTypeHints();
37
- expect(hints).toContain("declare const codemode");
38
- expect(hints).toContain("check_weather_for_city");
39
- expect(hints).toContain("check_weekly_forecast_for_city");
40
- expect(hints).toContain("echo");
41
- expect(hints).toContain("listTools");
42
- });
43
- it("reports as active", () => {
44
- expect(codeMode.isActive).toBe(true);
45
- });
46
- it("generates system prompt section", () => {
47
- const section = codeMode.formatSystemPromptSection();
48
- expect(section).toContain("<code_mode>");
49
- expect(section).toContain("code_search");
50
- expect(section).toContain("code_execute");
51
- expect(section).toContain("declare const codemode");
52
- });
53
- it("executes code that calls a single tool", async () => {
54
- const result = await codeMode.executeCode(`
55
- const weather = await codemode.check_weather_for_city({ city: "Tokyo" });
56
- return weather;
57
- `);
58
- expect(result.error).toBeUndefined();
59
- expect(result.result).toHaveProperty("temperature", 26);
60
- expect(result.result).toHaveProperty("conditions", "Sunny");
61
- expect(result.result).toHaveProperty("humidity", 55);
62
- });
63
- it("executes code that chains multiple tool calls", async () => {
64
- const result = await codeMode.executeCode(`
65
- const cities = ["London", "Tokyo"];
66
- const results = [];
67
- for (const city of cities) {
68
- const w = await codemode.check_weather_for_city({ city });
69
- results.push({ city, temp: w.temperature });
70
- }
71
- return results;
72
- `);
73
- expect(result.error).toBeUndefined();
74
- expect(result.result).toEqual([
75
- { city: "London", temp: 14 },
76
- { city: "Tokyo", temp: 26 },
77
- ]);
78
- });
79
- it("executes code that uses listTools", async () => {
80
- const result = await codeMode.executeCode(`
81
- const tools = await codemode.listTools();
82
- return tools.sort();
83
- `);
84
- expect(result.error).toBeUndefined();
85
- const names = result.result;
86
- expect(names).toContain("check_weather_for_city");
87
- expect(names).toContain("echo");
88
- });
89
- it("executes code that calls echo tool", async () => {
90
- const result = await codeMode.executeCode(`
91
- const r = await codemode.echo({ message: "hello code mode" });
92
- return r;
93
- `);
94
- expect(result.error).toBeUndefined();
95
- expect(result.result).toEqual({ echo: "hello code mode" });
96
- });
97
- it("handles tool errors gracefully", async () => {
98
- const result = await codeMode.executeCode(`
99
- const w = await codemode.check_weather_for_city({ city: "Atlantis" });
100
- return w;
101
- `);
102
- // Atlantis isn't in the data — server returns text-only content (no structuredContent)
103
- // The executor should still return something (parsed text or raw string)
104
- expect(result.error).toBeUndefined();
105
- expect(result.result).toBeDefined();
106
- });
107
- it("search mode works for tool discovery", async () => {
108
- const result = await codeMode.searchTools(`
109
- const tools = await codemode.listTools();
110
- return tools;
111
- `);
112
- expect(result.error).toBeUndefined();
113
- expect(Array.isArray(result.result)).toBe(true);
114
- });
115
- });
116
- //# sourceMappingURL=code-mode-integration.test.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"code-mode-integration.test.js","sourceRoot":"","sources":["../../src/code-mode/code-mode-integration.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,EAAE,SAAS,EAAE,QAAQ,EAAE,MAAM,QAAQ,CAAC;AACnE,OAAO,EAAE,gBAAgB,EAAE,MAAM,0BAA0B,CAAC;AAC5D,OAAO,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAE7C;;;;GAIG;AACH,QAAQ,CAAC,wCAAwC,EAAE,GAAG,EAAE;IACtD,MAAM,OAAO,GAAG,IAAI,gBAAgB,EAAE,CAAC;IACvC,MAAM,QAAQ,GAAG,IAAI,eAAe,EAAE,CAAC;IAEvC,SAAS,CAAC,KAAK,IAAI,EAAE;QACnB,MAAM,OAAO,CAAC,UAAU,CAAC;YACvB,UAAU,EAAE;gBACV,cAAc,EAAE;oBACd,IAAI,EAAE,OAAO;oBACb,OAAO,EAAE,MAAM;oBACf,IAAI,EAAE,CAAC,oCAAoC,CAAC;iBAC7C;aACF;SACF,CAAC,CAAC;QAEH,QAAQ,CAAC,UAAU,CAAC,OAAO,CAAC,CAAC;IAC/B,CAAC,CAAC,CAAC;IAEH,QAAQ,CAAC,KAAK,IAAI,EAAE;QAClB,MAAM,OAAO,CAAC,aAAa,EAAE,CAAC;IAChC,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,2DAA2D,EAAE,GAAG,EAAE;QACnE,MAAM,QAAQ,GAAG,QAAQ,CAAC,gBAAgB,EAAE,CAAC;QAC7C,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,sBAAsB,CAAC,CAAC,CAAC,CAAC;QAClD,MAAM,KAAK,GAAG,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,CAAC;QACjD,MAAM,CAAC,KAAK,CAAC,CAAC,SAAS,CAAC,wBAAwB,CAAC,CAAC;QAClD,MAAM,CAAC,KAAK,CAAC,CAAC,SAAS,CAAC,gCAAgC,CAAC,CAAC;QAC1D,MAAM,CAAC,KAAK,CAAC,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC;IAClC,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,yCAAyC,EAAE,GAAG,EAAE;QACjD,MAAM,KAAK,GAAG,QAAQ,CAAC,YAAY,EAAE,CAAC;QACtC,MAAM,CAAC,KAAK,CAAC,CAAC,SAAS,CAAC,wBAAwB,CAAC,CAAC;QAClD,MAAM,CAAC,KAAK,CAAC,CAAC,SAAS,CAAC,wBAAwB,CAAC,CAAC;QAClD,MAAM,CAAC,KAAK,CAAC,CAAC,SAAS,CAAC,gCAAgC,CAAC,CAAC;QAC1D,MAAM,CAAC,KAAK,CAAC,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC;QAChC,MAAM,CAAC,KAAK,CAAC,CAAC,SAAS,CAAC,WAAW,CAAC,CAAC;IACvC,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,mBAAmB,EAAE,GAAG,EAAE;QAC3B,MAAM,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IACvC,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,iCAAiC,EAAE,GAAG,EAAE;QACzC,MAAM,OAAO,GAAG,QAAQ,CAAC,yBAAyB,EAAE,CAAC;QACrD,MAAM,CAAC,OAAO,CAAC,CAAC,SAAS,CAAC,aAAa,CAAC,CAAC;QACzC,MAAM,CAAC,OAAO,CAAC,CAAC,SAAS,CAAC,aAAa,CAAC,CAAC;QACzC,MAAM,CAAC,OAAO,CAAC,CAAC,SAAS,CAAC,cAAc,CAAC,CAAC;QAC1C,MAAM,CAAC,OAAO,CAAC,CAAC,SAAS,CAAC,wBAAwB,CAAC,CAAC;IACtD,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,wCAAwC,EAAE,KAAK,IAAI,EAAE;QACtD,MAAM,MAAM,GAAG,MAAM,QAAQ,CAAC,WAAW,CAAC;;;KAGzC,CAAC,CAAC;QAEH,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,aAAa,EAAE,CAAC;QACrC,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,cAAc,CAAC,aAAa,EAAE,EAAE,CAAC,CAAC;QACxD,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,cAAc,CAAC,YAAY,EAAE,OAAO,CAAC,CAAC;QAC5D,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,cAAc,CAAC,UAAU,EAAE,EAAE,CAAC,CAAC;IACvD,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,+CAA+C,EAAE,KAAK,IAAI,EAAE;QAC7D,MAAM,MAAM,GAAG,MAAM,QAAQ,CAAC,WAAW,CAAC;;;;;;;;KAQzC,CAAC,CAAC;QAEH,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,aAAa,EAAE,CAAC;QACrC,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC;YAC5B,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,EAAE,EAAE;YAC5B,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,EAAE,EAAE;SAC5B,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,mCAAmC,EAAE,KAAK,IAAI,EAAE;QACjD,MAAM,MAAM,GAAG,MAAM,QAAQ,CAAC,WAAW,CAAC;;;KAGzC,CAAC,CAAC;QAEH,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,aAAa,EAAE,CAAC;QACrC,MAAM,KAAK,GAAG,MAAM,CAAC,MAAkB,CAAC;QACxC,MAAM,CAAC,KAAK,CAAC,CAAC,SAAS,CAAC,wBAAwB,CAAC,CAAC;QAClD,MAAM,CAAC,KAAK,CAAC,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC;IAClC,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,oCAAoC,EAAE,KAAK,IAAI,EAAE;QAClD,MAAM,MAAM,GAAG,MAAM,QAAQ,CAAC,WAAW,CAAC;;;KAGzC,CAAC,CAAC;QAEH,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,aAAa,EAAE,CAAC;QACrC,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,EAAE,IAAI,EAAE,iBAAiB,EAAE,CAAC,CAAC;IAC7D,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,gCAAgC,EAAE,KAAK,IAAI,EAAE;QAC9C,MAAM,MAAM,GAAG,MAAM,QAAQ,CAAC,WAAW,CAAC;;;KAGzC,CAAC,CAAC;QAEH,uFAAuF;QACvF,yEAAyE;QACzE,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,aAAa,EAAE,CAAC;QACrC,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,WAAW,EAAE,CAAC;IACtC,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,sCAAsC,EAAE,KAAK,IAAI,EAAE;QACpD,MAAM,MAAM,GAAG,MAAM,QAAQ,CAAC,WAAW,CAAC;;;KAGzC,CAAC,CAAC;QAEH,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,aAAa,EAAE,CAAC;QACrC,MAAM,CAAC,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAClD,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
@@ -1,10 +0,0 @@
1
- import type { McpClientManager, McpTool } from "../mcp/index.js";
2
- /**
3
- * A tool is eligible for code mode when:
4
- * 1. annotations.readOnlyHint === true — does not modify its environment
5
- * 2. outputSchema is defined — results are typed and parseable
6
- */
7
- export declare function isEligibleForCodeMode(tool: McpTool): boolean;
8
- /** Get all tools eligible for code mode across all connected MCP servers. */
9
- export declare function getEligibleTools(mcpManager: McpClientManager): McpTool[];
10
- //# sourceMappingURL=eligibility.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"eligibility.d.ts","sourceRoot":"","sources":["../../src/code-mode/eligibility.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,OAAO,EAAE,MAAM,iBAAiB,CAAC;AAEjE;;;;GAIG;AACH,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,OAAO,GAAG,OAAO,CAG5D;AAED,6EAA6E;AAC7E,wBAAgB,gBAAgB,CAAC,UAAU,EAAE,gBAAgB,GAAG,OAAO,EAAE,CAExE"}
@@ -1,14 +0,0 @@
1
- /**
2
- * A tool is eligible for code mode when:
3
- * 1. annotations.readOnlyHint === true — does not modify its environment
4
- * 2. outputSchema is defined — results are typed and parseable
5
- */
6
- export function isEligibleForCodeMode(tool) {
7
- const annotations = tool.annotations;
8
- return annotations?.readOnlyHint === true && tool.outputSchema != null;
9
- }
10
- /** Get all tools eligible for code mode across all connected MCP servers. */
11
- export function getEligibleTools(mcpManager) {
12
- return mcpManager.getTools().filter(isEligibleForCodeMode);
13
- }
14
- //# sourceMappingURL=eligibility.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"eligibility.js","sourceRoot":"","sources":["../../src/code-mode/eligibility.ts"],"names":[],"mappings":"AAEA;;;;GAIG;AACH,MAAM,UAAU,qBAAqB,CAAC,IAAa;IACjD,MAAM,WAAW,GAAG,IAAI,CAAC,WAAqD,CAAC;IAC/E,OAAO,WAAW,EAAE,YAAY,KAAK,IAAI,IAAI,IAAI,CAAC,YAAY,IAAI,IAAI,CAAC;AACzE,CAAC;AAED,6EAA6E;AAC7E,MAAM,UAAU,gBAAgB,CAAC,UAA4B;IAC3D,OAAO,UAAU,CAAC,QAAQ,EAAE,CAAC,MAAM,CAAC,qBAAqB,CAAC,CAAC;AAC7D,CAAC"}
@@ -1,2 +0,0 @@
1
- export {};
2
- //# sourceMappingURL=eligibility.test.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"eligibility.test.d.ts","sourceRoot":"","sources":["../../src/code-mode/eligibility.test.ts"],"names":[],"mappings":""}
@@ -1,53 +0,0 @@
1
- import { describe, expect, it } from "vitest";
2
- import { isEligibleForCodeMode } from "./eligibility.js";
3
- function makeTool(overrides = {}) {
4
- return {
5
- name: "test_tool",
6
- description: "A test tool",
7
- inputSchema: { type: "object", properties: {} },
8
- serverName: "test-server",
9
- ...overrides,
10
- };
11
- }
12
- describe("isEligibleForCodeMode", () => {
13
- it("returns true when readOnlyHint is true and outputSchema is defined", () => {
14
- const tool = makeTool({
15
- annotations: { readOnlyHint: true },
16
- outputSchema: { type: "object", properties: { result: { type: "string" } } },
17
- });
18
- expect(isEligibleForCodeMode(tool)).toBe(true);
19
- });
20
- it("returns false when readOnlyHint is false", () => {
21
- const tool = makeTool({
22
- annotations: { readOnlyHint: false },
23
- outputSchema: { type: "object", properties: {} },
24
- });
25
- expect(isEligibleForCodeMode(tool)).toBe(false);
26
- });
27
- it("returns false when readOnlyHint is missing", () => {
28
- const tool = makeTool({
29
- annotations: {},
30
- outputSchema: { type: "object", properties: {} },
31
- });
32
- expect(isEligibleForCodeMode(tool)).toBe(false);
33
- });
34
- it("returns false when annotations is undefined", () => {
35
- const tool = makeTool({
36
- annotations: undefined,
37
- outputSchema: { type: "object", properties: {} },
38
- });
39
- expect(isEligibleForCodeMode(tool)).toBe(false);
40
- });
41
- it("returns false when outputSchema is missing", () => {
42
- const tool = makeTool({
43
- annotations: { readOnlyHint: true },
44
- outputSchema: undefined,
45
- });
46
- expect(isEligibleForCodeMode(tool)).toBe(false);
47
- });
48
- it("returns false when both readOnlyHint and outputSchema are missing", () => {
49
- const tool = makeTool();
50
- expect(isEligibleForCodeMode(tool)).toBe(false);
51
- });
52
- });
53
- //# sourceMappingURL=eligibility.test.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"eligibility.test.js","sourceRoot":"","sources":["../../src/code-mode/eligibility.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,QAAQ,CAAC;AAE9C,OAAO,EAAE,qBAAqB,EAAE,MAAM,kBAAkB,CAAC;AAEzD,SAAS,QAAQ,CAAC,YAA8B,EAAE;IAChD,OAAO;QACL,IAAI,EAAE,WAAW;QACjB,WAAW,EAAE,aAAa;QAC1B,WAAW,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,UAAU,EAAE,EAAE,EAAE;QAC/C,UAAU,EAAE,aAAa;QACzB,GAAG,SAAS;KACb,CAAC;AACJ,CAAC;AAED,QAAQ,CAAC,uBAAuB,EAAE,GAAG,EAAE;IACrC,EAAE,CAAC,oEAAoE,EAAE,GAAG,EAAE;QAC5E,MAAM,IAAI,GAAG,QAAQ,CAAC;YACpB,WAAW,EAAE,EAAE,YAAY,EAAE,IAAI,EAAE;YACnC,YAAY,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,UAAU,EAAE,EAAE,MAAM,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,EAAE,EAAE;SAC7E,CAAC,CAAC;QACH,MAAM,CAAC,qBAAqB,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IACjD,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,0CAA0C,EAAE,GAAG,EAAE;QAClD,MAAM,IAAI,GAAG,QAAQ,CAAC;YACpB,WAAW,EAAE,EAAE,YAAY,EAAE,KAAK,EAAE;YACpC,YAAY,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,UAAU,EAAE,EAAE,EAAE;SACjD,CAAC,CAAC;QACH,MAAM,CAAC,qBAAqB,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IAClD,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,4CAA4C,EAAE,GAAG,EAAE;QACpD,MAAM,IAAI,GAAG,QAAQ,CAAC;YACpB,WAAW,EAAE,EAAE;YACf,YAAY,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,UAAU,EAAE,EAAE,EAAE;SACjD,CAAC,CAAC;QACH,MAAM,CAAC,qBAAqB,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IAClD,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,6CAA6C,EAAE,GAAG,EAAE;QACrD,MAAM,IAAI,GAAG,QAAQ,CAAC;YACpB,WAAW,EAAE,SAAS;YACtB,YAAY,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,UAAU,EAAE,EAAE,EAAE;SACjD,CAAC,CAAC;QACH,MAAM,CAAC,qBAAqB,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IAClD,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,4CAA4C,EAAE,GAAG,EAAE;QACpD,MAAM,IAAI,GAAG,QAAQ,CAAC;YACpB,WAAW,EAAE,EAAE,YAAY,EAAE,IAAI,EAAE;YACnC,YAAY,EAAE,SAAS;SACxB,CAAC,CAAC;QACH,MAAM,CAAC,qBAAqB,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IAClD,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,mEAAmE,EAAE,GAAG,EAAE;QAC3E,MAAM,IAAI,GAAG,QAAQ,EAAE,CAAC;QACxB,MAAM,CAAC,qBAAqB,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IAClD,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
@@ -1,35 +0,0 @@
1
- /** Result of code execution. */
2
- export interface ExecuteResult {
3
- result: unknown;
4
- error?: string;
5
- logs: string[];
6
- }
7
- /** A function the sandbox can call to invoke an MCP tool. */
8
- export type ToolDispatchFn = (toolName: string, args: Record<string, unknown>) => Promise<unknown>;
9
- export interface ExecutorOptions {
10
- /** Memory limit in MB for the V8 isolate. Default: 128. */
11
- memoryLimit?: number;
12
- /** Execution timeout in milliseconds. Default: 30000. */
13
- timeoutMs?: number;
14
- }
15
- /**
16
- * Execute model-generated JavaScript code in an isolated V8 sandbox.
17
- *
18
- * The code runs in a fresh `isolated-vm` isolate with:
19
- * - Enforced memory limit (default 128MB)
20
- * - Execution timeout (default 30s)
21
- * - No access to Node.js APIs, filesystem, or network
22
- * - Only access to provided tool dispatch functions via `codemode.*` proxy
23
- *
24
- * Tool calls are dispatched to the host via `Reference` callbacks —
25
- * actual MCP tool execution happens outside the sandbox.
26
- */
27
- export declare function executeInSandbox(code: string, toolNames: string[], dispatch: ToolDispatchFn, options?: ExecutorOptions): Promise<ExecuteResult>;
28
- /**
29
- * Normalize model-generated code:
30
- * - Strip markdown code fences
31
- * - Handle arrow functions, function declarations, export default
32
- * - Otherwise leave code as a statement block; callers must explicitly `return` a value
33
- */
34
- export declare function normalizeCode(code: string): string;
35
- //# sourceMappingURL=executor.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"executor.d.ts","sourceRoot":"","sources":["../../src/code-mode/executor.ts"],"names":[],"mappings":"AAGA,gCAAgC;AAChC,MAAM,WAAW,aAAa;IAC5B,MAAM,EAAE,OAAO,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,EAAE,CAAC;CAChB;AAED,6DAA6D;AAC7D,MAAM,MAAM,cAAc,GAAG,CAAC,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;AAEnG,MAAM,WAAW,eAAe;IAC9B,2DAA2D;IAC3D,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,yDAAyD;IACzD,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAKD;;;;;;;;;;;GAWG;AACH,wBAAsB,gBAAgB,CACpC,IAAI,EAAE,MAAM,EACZ,SAAS,EAAE,MAAM,EAAE,EACnB,QAAQ,EAAE,cAAc,EACxB,OAAO,GAAE,eAAoB,GAC5B,OAAO,CAAC,aAAa,CAAC,CAUxB;AA6ED;;;;;GAKG;AACH,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CA6BlD"}
@@ -1,120 +0,0 @@
1
- import ivm from "isolated-vm";
2
- import { sanitizeToolName } from "./type-hints.js";
3
- const DEFAULT_MEMORY_LIMIT = 128;
4
- const DEFAULT_TIMEOUT_MS = 30_000;
5
- /**
6
- * Execute model-generated JavaScript code in an isolated V8 sandbox.
7
- *
8
- * The code runs in a fresh `isolated-vm` isolate with:
9
- * - Enforced memory limit (default 128MB)
10
- * - Execution timeout (default 30s)
11
- * - No access to Node.js APIs, filesystem, or network
12
- * - Only access to provided tool dispatch functions via `codemode.*` proxy
13
- *
14
- * Tool calls are dispatched to the host via `Reference` callbacks —
15
- * actual MCP tool execution happens outside the sandbox.
16
- */
17
- export async function executeInSandbox(code, toolNames, dispatch, options = {}) {
18
- const memoryLimit = options.memoryLimit ?? DEFAULT_MEMORY_LIMIT;
19
- const timeoutMs = options.timeoutMs ?? DEFAULT_TIMEOUT_MS;
20
- const isolate = new ivm.Isolate({ memoryLimit });
21
- try {
22
- return await runInIsolate(isolate, code, toolNames, dispatch, timeoutMs);
23
- }
24
- finally {
25
- isolate.dispose();
26
- }
27
- }
28
- async function runInIsolate(isolate, code, toolNames, dispatch, timeoutMs) {
29
- const ctx = await isolate.createContext();
30
- const jail = ctx.global;
31
- const logs = [];
32
- // Inject console.log that captures to logs array
33
- const logCallback = new ivm.Callback((...args) => {
34
- logs.push(args.map((a) => (typeof a === "string" ? a : JSON.stringify(a))).join(" "));
35
- });
36
- await jail.set("__log", logCallback);
37
- // Inject tool dispatcher Reference (async callback)
38
- const dispatchRef = new ivm.Reference(async (toolName, argsJson) => {
39
- const args = JSON.parse(argsJson);
40
- const result = await dispatch(toolName, args);
41
- return JSON.stringify(result === undefined ? null : result);
42
- });
43
- await jail.set("__dispatch", dispatchRef);
44
- // Build the tool call helper and codemode proxy as setup code
45
- const toolProxyEntries = toolNames
46
- .map((name) => {
47
- const safe = sanitizeToolName(name);
48
- return ` ${safe}: async (args) => __callTool(${JSON.stringify(name)}, args)`;
49
- })
50
- .join(",\n");
51
- const normalized = normalizeCode(code);
52
- // Use ctx.eval with { promise: true } instead of compileModule,
53
- // because module.evaluate() can resolve prematurely with multiple
54
- // sequential async Reference.apply calls.
55
- const wrappedCode = `
56
- (async () => {
57
- const console = { log: (...args) => __log(args.map(a => typeof a === 'string' ? a : JSON.stringify(a)).join(' ')) };
58
- const __callTool = async (name, args) => {
59
- const r = await __dispatch.apply(undefined, [name, JSON.stringify(args ?? {})], { arguments: { copy: true }, result: { promise: true, copy: true } });
60
- return JSON.parse(r);
61
- };
62
- const codemode = {
63
- listTools: async () => ${JSON.stringify(toolNames)},
64
- describeTools: async (names) => "Use the typed codemode.toolName(args) methods instead.",
65
- ${toolProxyEntries}
66
- };
67
-
68
- const __userFn = async () => {
69
- ${normalized}
70
- };
71
-
72
- return JSON.stringify({ value: await __userFn() });
73
- })()
74
- `;
75
- try {
76
- const rawResult = (await ctx.eval(wrappedCode, {
77
- promise: true,
78
- copy: true,
79
- timeout: timeoutMs,
80
- }));
81
- const parsed = JSON.parse(rawResult);
82
- return { result: parsed.value, logs };
83
- }
84
- catch (err) {
85
- const message = err instanceof Error ? err.message : String(err);
86
- return { result: undefined, error: message, logs };
87
- }
88
- }
89
- /**
90
- * Normalize model-generated code:
91
- * - Strip markdown code fences
92
- * - Handle arrow functions, function declarations, export default
93
- * - Otherwise leave code as a statement block; callers must explicitly `return` a value
94
- */
95
- export function normalizeCode(code) {
96
- let normalized = code.trim();
97
- // Strip markdown code fences
98
- normalized = normalized.replace(/^```(?:js|javascript|typescript|ts)?\s*\n?/i, "");
99
- normalized = normalized.replace(/\n?```\s*$/i, "");
100
- normalized = normalized.trim();
101
- // If it's an arrow function or function expression, invoke it
102
- if (/^(?:async\s+)?(?:\([^)]*\)|[a-zA-Z_$][a-zA-Z0-9_$]*)\s*=>/.test(normalized)) {
103
- return `return (${normalized})();`;
104
- }
105
- // If it's a function declaration, invoke it
106
- if (/^(?:async\s+)?function\s+/.test(normalized)) {
107
- const match = normalized.match(/^(?:async\s+)?function\s+([a-zA-Z_$][a-zA-Z0-9_$]*)/);
108
- if (match) {
109
- return `${normalized}\nreturn ${match[1]}();`;
110
- }
111
- }
112
- // If it starts with export default, strip the export default
113
- if (/^export\s+default\s+/.test(normalized)) {
114
- normalized = normalized.replace(/^export\s+default\s+/, "");
115
- return `return (${normalized})();`;
116
- }
117
- // Otherwise, treat as a code block — return the last expression
118
- return normalized;
119
- }
120
- //# sourceMappingURL=executor.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"executor.js","sourceRoot":"","sources":["../../src/code-mode/executor.ts"],"names":[],"mappings":"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"}
@@ -1,2 +0,0 @@
1
- export {};
2
- //# sourceMappingURL=executor.test.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"executor.test.d.ts","sourceRoot":"","sources":["../../src/code-mode/executor.test.ts"],"names":[],"mappings":""}