Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 6 additions & 7 deletions src/integrations/claude-code/__tests__/run.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -139,7 +139,7 @@ describe("runClaudeCode", () => {
expect(typeof result[Symbol.asyncIterator]).toBe("function")
})

test("should handle platform-specific stdin behavior", async () => {
test("should always pass system prompt and messages via stdin", async () => {
const { runClaudeCode } = await import("../run")
const messages = [{ role: "user" as const, content: "Hello world!" }]
const systemPrompt = "You are a helpful assistant"
Expand All @@ -158,7 +158,7 @@ describe("runClaudeCode", () => {
results.push(chunk)
}

// On Windows, should NOT have --system-prompt in args
// Should NOT have --system-prompt in args on any platform
const [, args] = mockExeca.mock.calls[0]
expect(args).not.toContain("--system-prompt")

Expand All @@ -179,13 +179,12 @@ describe("runClaudeCode", () => {
results2.push(chunk)
}

// On non-Windows, should have --system-prompt in args
// Should NOT have --system-prompt in args on any platform
const [, args2] = mockExeca.mock.calls[0]
expect(args2).toContain("--system-prompt")
expect(args2).toContain(systemPrompt)
expect(args2).not.toContain("--system-prompt")

// Should only pass messages via stdin
expect(mockStdin.write).toHaveBeenCalledWith(JSON.stringify(messages), "utf8", expect.any(Function))
// Should always pass both system prompt and messages via stdin
expect(mockStdin.write).toHaveBeenCalledWith(expectedStdinData, "utf8", expect.any(Function))
})

test("should include model parameter when provided", async () => {
Expand Down
32 changes: 10 additions & 22 deletions src/integrations/claude-code/run.ts
Original file line number Diff line number Diff line change
Expand Up @@ -154,17 +154,10 @@ function runProcess({
maxOutputTokens,
}: ClaudeCodeOptions & { maxOutputTokens?: number }) {
const claudePath = path || "claude"
const isWindows = os.platform() === "win32"

// Build args based on platform
const args = ["-p"]

// Pass system prompt as flag on non-Windows, via stdin on Windows (avoids cmd length limits)
if (!isWindows) {
args.push("--system-prompt", systemPrompt)
}

args.push(
// Build args - no longer passing system prompt as command-line argument
const args = [
"-p",
"--verbose",
"--output-format",
"stream-json",
Expand All @@ -173,7 +166,7 @@ function runProcess({
// Roo Code will handle recursive calls
"--max-turns",
"1",
)
]

if (modelId) {
args.push("--model", modelId)
Expand All @@ -196,17 +189,12 @@ function runProcess({
timeout: CLAUDE_CODE_TIMEOUT,
})

// Prepare stdin data: Windows gets both system prompt & messages (avoids 8191 char limit),
// other platforms get messages only (avoids Linux E2BIG error from ~128KiB execve limit)
let stdinData: string
if (isWindows) {
stdinData = JSON.stringify({
systemPrompt,
messages,
})
} else {
stdinData = JSON.stringify(messages)
}
// Always pass both system prompt and messages via stdin to avoid E2BIG errors
// This prevents issues when system prompts are very large (e.g., with Codebase Indexing)
const stdinData = JSON.stringify({
systemPrompt,
messages,
})

// Use setImmediate to ensure process is spawned before writing (prevents stdin race conditions)
setImmediate(() => {
Expand Down
Loading