@@ -450,137 +450,84 @@ esac
450450 const sessionName = 'tui-test-' + Date . now ( ) + '-' + Math . random ( ) . toString ( 36 ) . slice ( 2 , 6 )
451451 const helperPath = '/tmp/tmux-helper-' + sessionName + '.sh'
452452
453- logger . info ( 'Writing helper script to ' + helperPath )
453+ logger . info ( 'Setting up tmux session: ' + sessionName )
454454
455- // Write the self-contained helper script to /tmp
456- const { toolResult : writeResult } = yield {
457- toolName : 'run_terminal_command' ,
458- input : {
459- command : 'cat > ' + helperPath + " << 'TMUX_HELPER_EOF'\n" + helperScript + "TMUX_HELPER_EOF\nchmod +x " + helperPath ,
460- timeout_seconds : 10 ,
461- } ,
462- }
463-
464- const writeOutput = writeResult ?. [ 0 ]
465- if ( writeOutput && writeOutput . type === 'json' ) {
466- const value = writeOutput . value as Record < string , unknown >
467- const exitCode = typeof value ?. exitCode === 'number' ? value . exitCode : undefined
468- if ( exitCode !== 0 ) {
469- const stderr = typeof value ?. stderr === 'string' ? value . stderr . trim ( ) : 'unknown error'
470- logger . error ( 'Failed to write helper script: ' + stderr )
471- yield {
472- toolName : 'set_output' ,
473- input : {
474- overallStatus : 'failure' ,
475- summary : 'Failed to write helper script to /tmp. ' + stderr ,
476- sessionName : '' ,
477- scriptIssues : [ { script : helperPath , issue : stderr , suggestedFix : 'Check /tmp is writable' } ] ,
478- captures : [ ] ,
479- } ,
480- }
481- return
482- }
483- }
484-
485- logger . info ( 'Starting tmux session (bash)' )
486-
487- // Start the tmux session with bash (not the user's command directly)
488- const { toolResult } = yield {
455+ // Combined setup: write helper script, start session, send command (single yield to reduce round-trips)
456+ const escapedCommand = startCommand . replace ( / ' / g, "'\\''" )
457+ const setupScript =
458+ 'set -e\n' +
459+ 'cat > ' + helperPath + " << 'TMUX_HELPER_EOF'\n" + helperScript + 'TMUX_HELPER_EOF\n' +
460+ 'chmod +x ' + helperPath + '\n' +
461+ 'OUTPUT=$(' + helperPath + " start '" + sessionName + "') || { echo \"FAIL_START\" >&2; exit 1; }\n" +
462+ helperPath + " send '" + sessionName + "' '" + escapedCommand + "' || { " + helperPath + " stop '" + sessionName + "' 2>/dev/null; echo \"FAIL_SEND\" >&2; exit 1; }\n" +
463+ 'echo "$OUTPUT"'
464+
465+ const { toolResult : setupResult } = yield {
489466 toolName : 'run_terminal_command' ,
490467 input : {
491- command : helperPath + " start '" + sessionName + "'" ,
468+ command : setupScript ,
492469 timeout_seconds : 30 ,
493470 } ,
471+ includeToolCall : false ,
494472 }
495473
496- let started = false
497- let parseError = ''
474+ let setupSuccess = false
475+ let setupError = ''
498476
499- const result = toolResult ?. [ 0 ]
500- if ( result && result . type === 'json' ) {
501- const value = result . value as Record < string , unknown >
477+ const setupOutput = setupResult ?. [ 0 ]
478+ if ( setupOutput && setupOutput . type === 'json' ) {
479+ const value = setupOutput . value as Record < string , unknown >
502480 const stdout = typeof value ?. stdout === 'string' ? value . stdout . trim ( ) : ''
503481 const stderr = typeof value ?. stderr === 'string' ? value . stderr . trim ( ) : ''
504482 const exitCode = typeof value ?. exitCode === 'number' ? value . exitCode : undefined
505483
506- if ( exitCode !== 0 ) {
507- parseError = stderr || 'Helper script failed with no error message'
508- } else if ( stdout === sessionName ) {
509- started = true
484+ if ( exitCode === 0 && stdout === sessionName ) {
485+ setupSuccess = true
510486 } else {
511- parseError = 'Unexpected output: ' + stdout
487+ setupError = stderr || stdout || 'Setup failed with no error message'
512488 }
513489 } else {
514- parseError = 'Unexpected result type from run_terminal_command'
490+ setupError = 'Unexpected result type from run_terminal_command'
515491 }
516492
517- if ( ! started ) {
518- const errorMsg = parseError || 'Failed to start session'
519- logger . error ( { parseError : errorMsg } , 'Failed to start tmux session' )
493+ if ( ! setupSuccess ) {
494+ const isSendFailure = setupError . includes ( 'FAIL_SEND' )
495+ const isStartFailure = setupError . includes ( 'FAIL_START' )
496+
497+ let summary : string
498+ let suggestedFix : string
499+ if ( isSendFailure ) {
500+ summary = 'Started session but failed to send command. ' + setupError
501+ suggestedFix = 'Check that the command is valid.'
502+ } else if ( isStartFailure ) {
503+ summary = 'Failed to start tmux session. ' + setupError
504+ suggestedFix = 'Ensure tmux is installed and the command is valid.'
505+ } else {
506+ summary = 'Failed to write helper script to /tmp. ' + setupError
507+ suggestedFix = 'Check /tmp is writable'
508+ }
509+
510+ logger . error ( setupError , 'Setup failed' )
520511 yield {
521512 toolName : 'set_output' ,
522513 input : {
523514 overallStatus : 'failure' ,
524- summary : 'Failed to start tmux session. ' + errorMsg ,
525- sessionName : '' ,
526- scriptIssues : [
527- {
528- script : helperPath ,
529- issue : errorMsg ,
530- errorOutput : JSON . stringify ( toolResult ) ,
531- suggestedFix : 'Ensure tmux is installed and the command is valid.' ,
532- } ,
533- ] ,
515+ summary,
516+ sessionName : isSendFailure ? sessionName : '' ,
517+ scriptIssues : [ { script : helperPath , issue : setupError , suggestedFix } ] ,
534518 captures : [ ] ,
535519 } ,
536520 }
537521 return
538522 }
539523
540- logger . info ( 'Successfully started tmux session: ' + sessionName )
541-
542- // Send the user's command to the bash session
543- const escapedCommand = startCommand . replace ( / ' / g, "'\\''" )
544- const { toolResult : sendResult } = yield {
545- toolName : 'run_terminal_command' ,
546- input : {
547- command : helperPath + " send '" + sessionName + "' '" + escapedCommand + "'" ,
548- timeout_seconds : 15 ,
549- } ,
550- }
551-
552- const sendOutput = sendResult ?. [ 0 ]
553- if ( sendOutput && sendOutput . type === 'json' ) {
554- const value = sendOutput . value as Record < string , unknown >
555- const exitCode = typeof value ?. exitCode === 'number' ? value . exitCode : undefined
556- if ( exitCode !== 0 ) {
557- const stderr = typeof value ?. stderr === 'string' ? value . stderr . trim ( ) : 'send failed'
558- logger . error ( 'Failed to send command: ' + stderr )
559- yield {
560- toolName : 'run_terminal_command' ,
561- input : { command : helperPath + " stop '" + sessionName + "'" , timeout_seconds : 5 } ,
562- }
563- yield {
564- toolName : 'set_output' ,
565- input : {
566- overallStatus : 'failure' ,
567- summary : 'Started session but failed to send command. ' + stderr ,
568- sessionName,
569- scriptIssues : [ { script : helperPath , issue : stderr , suggestedFix : 'Check that the command is valid.' } ] ,
570- captures : [ ] ,
571- } ,
572- }
573- return
574- }
575- }
576-
577- logger . info ( 'Sent command to session: ' + startCommand )
524+ logger . info ( 'Session ready: ' + sessionName )
578525
579- // Wait briefly then capture initial state so the agent starts with context
526+ // Capture initial state so the agent starts with context (0.5s is enough since send already waits ~0.6s)
580527 const { toolResult : initCapture } = yield {
581528 toolName : 'run_terminal_command' ,
582529 input : {
583- command : 'sleep 1 .5 && ' + helperPath + " capture '" + sessionName + "' --wait 0 --label startup-check" ,
530+ command : 'sleep 0 .5 && ' + helperPath + " capture '" + sessionName + "' --wait 0 --label startup-check" ,
584531 timeout_seconds : 10 ,
585532 } ,
586533 }
@@ -606,7 +553,10 @@ esac
606553 '**Captures dir:** `' + captureDir + '/`\n\n' +
607554 '**Initial terminal output:**\n```\n' + initialOutput + '\n```\n\n' +
608555 'Check the initial output above — if you see errors like "command not found" or "No such file", report failure immediately.\n\n' +
609- 'Commands:\n' +
556+ '## Helper Script Implementation\n\n' +
557+ 'The helper script at `' + helperPath + '` is a Bash script that wraps tmux commands to interact with the CLI. Here is its full implementation:\n\n' +
558+ '```bash\n' + helperScript . replace ( / ` ` ` / g, '\\`\\`\\`' ) + '\n```\n\n' +
559+ '## Quick Reference\n\n' +
610560 '- Send input: `' + helperPath + ' send "' + sessionName + '" "..."`\n' +
611561 '- Send with paste mode: `' + helperPath + ' send "' + sessionName + '" "..." --paste`\n' +
612562 '- Send + wait for output: `' + helperPath + ' send "' + sessionName + '" "..." --wait-idle 3`\n' +
0 commit comments