authorgravatar for yordis.prieto@gmail.comYordis Prieto <yordis.prieto@gmail.com> 2026-10-02 23:29:01-04:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2026-10-02 20:29:01-07:00
log858b98b8fa618cf9b9528b5415493fcf0572ac88
treeada919e50e6148c46d33676c16d7447f355acc3d
parent43bd6677392b80cd12742f865c277c9939239543
signature Signed by PGP key B5690EEEBB952194

test(server): the fake Claude CLI is a fixture file, not a generated string (#14950)

Signed-off-by: Yordis Prieto <yordis.prieto@gmail.com>

2 files changed, 69 insertions(+), 63 deletions(-)

apps/server/src/provider/Layers/ClaudeCapabilitiesProbe.test.ts+3-63
...@@ -58,7 +58,9 @@ it.layer(NodeServices.layer)("Claude capability probe SDK boundary", (it) => {...@@ -58,7 +58,9 @@ it.layer(NodeServices.layer)("Claude capability probe SDK boundary", (it) => {
58 const fs = yield* FileSystem.FileSystem;58 const fs = yield* FileSystem.FileSystem;
59 const path = yield* Path.Path;59 const path = yield* Path.Path;
60 const tempDir = yield* fs.makeTempDirectoryScoped({ prefix: "t3-claude-probe-sdk-" });60 const tempDir = yield* fs.makeTempDirectoryScoped({ prefix: "t3-claude-probe-sdk-" });
61 const executablePath = path.join(tempDir, "fake-claude.mjs");61 const executablePath = yield* path.fromFileUrl(
62 new URL("./testing/ClaudeCapabilitiesProbe.fixture.mjs", import.meta.url),
63 );
62 const invocationPath = path.join(tempDir, "invocation.json");64 const invocationPath = path.join(tempDir, "invocation.json");
63 // The probe aborts the SDK without awaiting the child's exit, and on65 // The probe aborts the SDK without awaiting the child's exit, and on
64 // Windows a directory that is still some process's cwd cannot be66 // Windows a directory that is still some process's cwd cannot be
...@@ -80,68 +82,6 @@ it.layer(NodeServices.layer)("Claude capability probe SDK boundary", (it) => {...@@ -80,68 +82,6 @@ it.layer(NodeServices.layer)("Claude capability probe SDK boundary", (it) => {
80 ),82 ),
81 );83 );
8284
83 yield* fs.writeFileString(
84 executablePath,
85 [
86 "#!/usr/bin/env node",
87 'import { existsSync, readFileSync, writeFileSync } from "node:fs";',
88 'import { createInterface } from "node:readline";',
89 "const args = process.argv.slice(2);",
90 'const mcpConfigIndex = args.indexOf("--mcp-config");',
91 "const rawMcpConfig = mcpConfigIndex >= 0 ? args[mcpConfigIndex + 1] : undefined;",
92 "let mcpConfig;",
93 "if (rawMcpConfig) {",
94 ' const contents = existsSync(rawMcpConfig) ? readFileSync(rawMcpConfig, "utf8") : rawMcpConfig;',
95 " try { mcpConfig = JSON.parse(contents); } catch { mcpConfig = contents; }",
96 "}",
97 "writeFileSync(process.env.T3_PROBE_INVOCATION_PATH, JSON.stringify({",
98 " args,",
99 " cwd: process.cwd(),",
100 " connectorEnv: process.env.ENABLE_CLAUDEAI_MCP_SERVERS,",
101 " mcpConfig,",
102 "}));",
103 "const lines = createInterface({ input: process.stdin });",
104 'lines.on("line", (line) => {',
105 " const message = JSON.parse(line);",
106 ' if (message.type !== "control_request") return;',
107 " const reply = (response) => process.stdout.write(JSON.stringify({",
108 ' type: "control_response",',
109 ' response: { subtype: "success", request_id: message.request_id, response },',
110 ' }) + "\\n");',
111 ' if (message.request?.subtype === "initialize") {',
112 " reply({",
113 ' commands: [{ name: "review", description: "Review changes", argumentHint: "[path]" }],',
114 " agents: [],",
115 ' output_style: "default",',
116 ' available_output_styles: ["default"],',
117 " models: [],",
118 ' account: { email: "dev@example.com", subscriptionType: "pro", tokenSource: "oauth" },',
119 " });",
120 " }",
121 " // The probe follows initialize with get_usage on the same process.",
122 ' if (message.request?.subtype === "get_usage") {',
123 " reply({",
124 " session: {},",
125 ' subscription_type: "pro",',
126 " rate_limits_available: true,",
127 ' rate_limits: { five_hour: { utilization: 12, resets_at: "2026-07-18T14:39:00Z" } },',
128 " behaviors: null,",
129 " });",
130 " }",
131 "});",
132 "// Stay alive for follow-up control requests, but never outlive the",
133 "// parent: the probe aborts the SDK without awaiting the child, so an",
134 "// unconditional interval would strand this process until reboot.",
135 "const keepAlive = setInterval(() => {}, 1_000);",
136 'lines.on("close", () => {',
137 " clearInterval(keepAlive);",
138 " process.exit(0);",
139 "});",
140 "",
141 ].join("\n"),
142 );
143 yield* fs.chmod(executablePath, 0o755);
144
145 const capabilities = yield* probeClaudeCapabilities(85 const capabilities = yield* probeClaudeCapabilities(
146 decodeClaudeSettings({ binaryPath: executablePath }),86 decodeClaudeSettings({ binaryPath: executablePath }),
147 {87 {
apps/server/src/provider/Layers/testing/ClaudeCapabilitiesProbe.fixture.mjs created+66
...@@ -0,0 +1,66 @@
1#!/usr/bin/env node
2import * as NodeFS from "node:fs";
3import * as NodeReadline from "node:readline";
4const args = process.argv.slice(2);
5const mcpConfigIndex = args.indexOf("--mcp-config");
6const rawMcpConfig = mcpConfigIndex >= 0 ? args[mcpConfigIndex + 1] : undefined;
7let mcpConfig;
8if (rawMcpConfig) {
9 const contents = NodeFS.existsSync(rawMcpConfig)
10 ? NodeFS.readFileSync(rawMcpConfig, "utf8")
11 : rawMcpConfig;
12 try {
13 mcpConfig = JSON.parse(contents);
14 } catch {
15 mcpConfig = contents;
16 }
17}
18NodeFS.writeFileSync(
19 process.env.T3_PROBE_INVOCATION_PATH,
20 JSON.stringify({
21 args,
22 cwd: process.cwd(),
23 connectorEnv: process.env.ENABLE_CLAUDEAI_MCP_SERVERS,
24 mcpConfig,
25 }),
26);
27const lines = NodeReadline.createInterface({ input: process.stdin });
28lines.on("line", (line) => {
29 const message = JSON.parse(line);
30 if (message.type !== "control_request") return;
31 const reply = (response) =>
32 process.stdout.write(
33 JSON.stringify({
34 type: "control_response",
35 response: { subtype: "success", request_id: message.request_id, response },
36 }) + "\n",
37 );
38 if (message.request?.subtype === "initialize") {
39 reply({
40 commands: [{ name: "review", description: "Review changes", argumentHint: "[path]" }],
41 agents: [],
42 output_style: "default",
43 available_output_styles: ["default"],
44 models: [],
45 account: { email: "dev@example.com", subscriptionType: "pro", tokenSource: "oauth" },
46 });
47 }
48 // The probe follows initialize with get_usage on the same process.
49 if (message.request?.subtype === "get_usage") {
50 reply({
51 session: {},
52 subscription_type: "pro",
53 rate_limits_available: true,
54 rate_limits: { five_hour: { utilization: 12, resets_at: "2026-07-18T14:39:00Z" } },
55 behaviors: null,
56 });
57 }
58});
59// Stay alive for follow-up control requests, but never outlive the
60// parent: the probe aborts the SDK without awaiting the child, so an
61// unconditional interval would strand this process until reboot.
62const keepAlive = setInterval(() => {}, 1_000);
63lines.on("close", () => {
64 clearInterval(keepAlive);
65 process.exit(0);
66});