| ... | ... | @@ -34,86 +34,18 @@ const ClaudeTextGenerationTestLayer = ServerConfig.ServerConfig.layerTest(proces |
| 34 | 34 | function makeFakeClaudeBinary(dir: string) { |
| 35 | 35 | return Effect.gen(function* () { |
| 36 | 36 | const path = yield* Path.Path; |
| 37 | const fs = yield* FileSystem.FileSystem; |
| 37 | 38 | const platform = yield* HostProcessPlatform; |
| 38 | 39 | const binDir = path.join(dir, "bin"); |
| 40 | const fixturePath = yield* path.fromFileUrl( |
| 41 | new URL("./testing/ClaudeTextGeneration.fixture.mjs", import.meta.url), |
| 42 | ); |
| 43 | const source = yield* fs.readFileString(fixturePath); |
| 39 | 44 | writeFakeCli({ |
| 40 | 45 | directory: binDir, |
| 41 | 46 | name: "claude", |
| 42 | 47 | platform, |
| 43 | | source: [ |
| 44 | | "const argv = process.argv.slice(2);", |
| 45 | | 'const args = argv.join(" ");', |
| 46 | | 'const { realpathSync } = await import("node:fs");', |
| 47 | | "", |
| 48 | | "function fail(message, code) {", |
| 49 | | ' process.stderr.write(message + "\\n");', |
| 50 | | " process.exit(code);", |
| 51 | | "}", |
| 52 | | "", |
| 53 | | 'const permissionIndex = argv.indexOf("--permission-mode");', |
| 54 | | 'if (permissionIndex === -1 || argv[permissionIndex + 1] !== "dontAsk") {', |
| 55 | | ' fail("text generation must deny permission prompts", 12);', |
| 56 | | "}", |
| 57 | | 'const toolsIndex = argv.indexOf("--tools");', |
| 58 | | 'if (toolsIndex === -1 || argv[toolsIndex + 1] !== "") {', |
| 59 | | ' fail("text generation must receive an explicit empty tool set", 6);', |
| 60 | | "}", |
| 61 | | 'if (argv.includes("--dangerously-skip-permissions")) {', |
| 62 | | ' fail("text generation must not bypass permissions", 7);', |
| 63 | | "}", |
| 64 | | 'if (!argv.includes("--disable-slash-commands")) {', |
| 65 | | ' fail("text generation must disable skills", 8);', |
| 66 | | "}", |
| 67 | | 'if (!argv.includes("--strict-mcp-config")) {', |
| 68 | | ' fail("text generation must not load configured MCP servers", 9);', |
| 69 | | "}", |
| 70 | | 'const settingsIndex = argv.indexOf("--settings");', |
| 71 | | "if (settingsIndex === -1 || JSON.parse(argv[settingsIndex + 1]).disableAllHooks !== true) {", |
| 72 | | ' fail("text generation must disable hooks", 10);', |
| 73 | | "}", |
| 74 | | "const cwdMustNotBe = process.env.T3_FAKE_CLAUDE_CWD_MUST_NOT_BE;", |
| 75 | | "if (cwdMustNotBe && realpathSync(process.cwd()) === realpathSync(cwdMustNotBe)) {", |
| 76 | | ' fail("text generation ran in the project directory", 11);', |
| 77 | | "}", |
| 78 | | "", |
| 79 | | 'let stdinContent = "";', |
| 80 | | "if (!process.stdin.isTTY) {", |
| 81 | | " const chunks = [];", |
| 82 | | " for await (const chunk of process.stdin) {", |
| 83 | | " chunks.push(chunk);", |
| 84 | | " }", |
| 85 | | ' stdinContent = Buffer.concat(chunks).toString("utf8");', |
| 86 | | "}", |
| 87 | | "", |
| 88 | | "const argsMustContain = process.env.T3_FAKE_CLAUDE_ARGS_MUST_CONTAIN;", |
| 89 | | "if (argsMustContain && !args.includes(argsMustContain)) {", |
| 90 | | ' fail("args missing expected content", 2);', |
| 91 | | "}", |
| 92 | | "", |
| 93 | | "const argsMustNotContain = process.env.T3_FAKE_CLAUDE_ARGS_MUST_NOT_CONTAIN;", |
| 94 | | "if (argsMustNotContain && args.includes(argsMustNotContain)) {", |
| 95 | | ' fail("args contained forbidden content", 3);', |
| 96 | | "}", |
| 97 | | "", |
| 98 | | "const stdinMustContain = process.env.T3_FAKE_CLAUDE_STDIN_MUST_CONTAIN;", |
| 99 | | "if (stdinMustContain && !stdinContent.includes(stdinMustContain)) {", |
| 100 | | ' fail("stdin missing expected content", 4);', |
| 101 | | "}", |
| 102 | | "", |
| 103 | | "const configDirMustBe = process.env.T3_FAKE_CLAUDE_CONFIG_DIR_MUST_BE;", |
| 104 | | "if (configDirMustBe && process.env.CLAUDE_CONFIG_DIR !== configDirMustBe) {", |
| 105 | | ' fail("CLAUDE_CONFIG_DIR was " + (process.env.CLAUDE_CONFIG_DIR ?? ""), 5);', |
| 106 | | "}", |
| 107 | | "", |
| 108 | | "const stderrText = process.env.T3_FAKE_CLAUDE_STDERR;", |
| 109 | | "if (stderrText) {", |
| 110 | | ' process.stderr.write(stderrText + "\\n");', |
| 111 | | "}", |
| 112 | | "", |
| 113 | | 'process.stdout.write(process.env.T3_FAKE_CLAUDE_OUTPUT ?? "");', |
| 114 | | "process.exitCode = Number(process.env.T3_FAKE_CLAUDE_EXIT_CODE ?? 0);", |
| 115 | | "", |
| 116 | | ].join("\n"), |
| 48 | source, |
| 117 | 49 | }); |
| 118 | 50 | return binDir; |
| 119 | 51 | }); |