@@ -287,4 +287,168 @@ describe("runClaudeCode", () => {
287287 consoleErrorSpy . mockRestore ( )
288288 await generator . return ( undefined )
289289 } )
290+
291+ test ( "should use command line argument for short system prompts" , async ( ) => {
292+ const { runClaudeCode } = await import ( "../run" )
293+ const shortSystemPrompt = "You are a helpful assistant"
294+ const options = {
295+ systemPrompt : shortSystemPrompt ,
296+ messages : [ { role : "user" as const , content : "Hello" } ] ,
297+ }
298+
299+ const generator = runClaudeCode ( options )
300+
301+ // Consume at least one item to trigger process spawn
302+ await generator . next ( )
303+
304+ // Clean up the generator
305+ await generator . return ( undefined )
306+
307+ // Verify execa was called with system prompt as command line argument
308+ const [ , args , execaOptions ] = mockExeca . mock . calls [ 0 ]
309+ expect ( args ) . toContain ( "--system-prompt" )
310+ expect ( args ) . toContain ( shortSystemPrompt )
311+
312+ // Verify no environment variable was set for short prompt
313+ expect ( execaOptions . env ?. CLAUDE_CODE_SYSTEM_PROMPT ) . toBeUndefined ( )
314+ } )
315+
316+ test ( "should use environment variable for long system prompts to avoid Windows ENAMETOOLONG error" , async ( ) => {
317+ const { runClaudeCode } = await import ( "../run" )
318+ // Create a system prompt longer than MAX_COMMAND_LINE_LENGTH (7000 chars)
319+ const longSystemPrompt = "You are a helpful assistant. " + "A" . repeat ( 7000 )
320+ const options = {
321+ systemPrompt : longSystemPrompt ,
322+ messages : [ { role : "user" as const , content : "Hello" } ] ,
323+ }
324+
325+ const generator = runClaudeCode ( options )
326+
327+ // Consume at least one item to trigger process spawn
328+ await generator . next ( )
329+
330+ // Clean up the generator
331+ await generator . return ( undefined )
332+
333+ // Verify execa was called without --system-prompt in command line arguments
334+ const [ , args , execaOptions ] = mockExeca . mock . calls [ 0 ]
335+ expect ( args ) . not . toContain ( "--system-prompt" )
336+ expect ( args ) . not . toContain ( longSystemPrompt )
337+
338+ // Verify environment variable was set with the long system prompt
339+ expect ( execaOptions . env ?. CLAUDE_CODE_SYSTEM_PROMPT ) . toBe ( longSystemPrompt )
340+ } )
341+
342+ test ( "should handle exactly MAX_COMMAND_LINE_LENGTH system prompt using command line" , async ( ) => {
343+ const { runClaudeCode } = await import ( "../run" )
344+ // Create a system prompt exactly at the threshold (7000 chars)
345+ const exactLengthPrompt = "A" . repeat ( 7000 )
346+ const options = {
347+ systemPrompt : exactLengthPrompt ,
348+ messages : [ { role : "user" as const , content : "Hello" } ] ,
349+ }
350+
351+ const generator = runClaudeCode ( options )
352+
353+ // Consume at least one item to trigger process spawn
354+ await generator . next ( )
355+
356+ // Clean up the generator
357+ await generator . return ( undefined )
358+
359+ // Verify execa was called with system prompt as command line argument (at threshold)
360+ const [ , args , execaOptions ] = mockExeca . mock . calls [ 0 ]
361+ expect ( args ) . toContain ( "--system-prompt" )
362+ expect ( args ) . toContain ( exactLengthPrompt )
363+
364+ // Verify no environment variable was set
365+ expect ( execaOptions . env ?. CLAUDE_CODE_SYSTEM_PROMPT ) . toBeUndefined ( )
366+ } )
367+
368+ test ( "should handle system prompt one character over threshold using environment variable" , async ( ) => {
369+ const { runClaudeCode } = await import ( "../run" )
370+ // Create a system prompt one character over the threshold (7001 chars)
371+ const overThresholdPrompt = "A" . repeat ( 7001 )
372+ const options = {
373+ systemPrompt : overThresholdPrompt ,
374+ messages : [ { role : "user" as const , content : "Hello" } ] ,
375+ }
376+
377+ const generator = runClaudeCode ( options )
378+
379+ // Consume at least one item to trigger process spawn
380+ await generator . next ( )
381+
382+ // Clean up the generator
383+ await generator . return ( undefined )
384+
385+ // Verify execa was called without --system-prompt in command line arguments
386+ const [ , args , execaOptions ] = mockExeca . mock . calls [ 0 ]
387+ expect ( args ) . not . toContain ( "--system-prompt" )
388+ expect ( args ) . not . toContain ( overThresholdPrompt )
389+
390+ // Verify environment variable was set
391+ expect ( execaOptions . env ?. CLAUDE_CODE_SYSTEM_PROMPT ) . toBe ( overThresholdPrompt )
392+ } )
393+
394+ test ( "should preserve existing environment variables when using CLAUDE_CODE_SYSTEM_PROMPT" , async ( ) => {
395+ const { runClaudeCode } = await import ( "../run" )
396+
397+ // Mock process.env to have some existing variables
398+ const originalEnv = process . env
399+ process . env = {
400+ ...originalEnv ,
401+ EXISTING_VAR : "existing_value" ,
402+ PATH : "/usr/bin:/bin" ,
403+ }
404+
405+ const longSystemPrompt = "You are a helpful assistant. " + "A" . repeat ( 7000 )
406+ const options = {
407+ systemPrompt : longSystemPrompt ,
408+ messages : [ { role : "user" as const , content : "Hello" } ] ,
409+ }
410+
411+ const generator = runClaudeCode ( options )
412+
413+ // Consume at least one item to trigger process spawn
414+ await generator . next ( )
415+
416+ // Clean up the generator
417+ await generator . return ( undefined )
418+
419+ // Verify environment variables include both existing and new ones
420+ const [ , , execaOptions ] = mockExeca . mock . calls [ 0 ]
421+ expect ( execaOptions . env ) . toEqual ( {
422+ ...process . env ,
423+ CLAUDE_CODE_MAX_OUTPUT_TOKENS : expect . any ( String ) , // Always set by the implementation
424+ CLAUDE_CODE_SYSTEM_PROMPT : longSystemPrompt ,
425+ } )
426+
427+ // Restore original environment
428+ process . env = originalEnv
429+ } )
430+
431+ test ( "should work with empty system prompt" , async ( ) => {
432+ const { runClaudeCode } = await import ( "../run" )
433+ const options = {
434+ systemPrompt : "" ,
435+ messages : [ { role : "user" as const , content : "Hello" } ] ,
436+ }
437+
438+ const generator = runClaudeCode ( options )
439+
440+ // Consume at least one item to trigger process spawn
441+ await generator . next ( )
442+
443+ // Clean up the generator
444+ await generator . return ( undefined )
445+
446+ // Verify execa was called with empty system prompt as command line argument
447+ const [ , args , execaOptions ] = mockExeca . mock . calls [ 0 ]
448+ expect ( args ) . toContain ( "--system-prompt" )
449+ expect ( args ) . toContain ( "" )
450+
451+ // Verify no environment variable was set
452+ expect ( execaOptions . env ?. CLAUDE_CODE_SYSTEM_PROMPT ) . toBeUndefined ( )
453+ } )
290454} )
0 commit comments