Skip to content

Commit 6990d67

Browse files
committed
Simplify tmux cli agent slightly
1 parent b28479c commit 6990d67

File tree

2 files changed

+52
-102
lines changed

2 files changed

+52
-102
lines changed

agents/base2/base2.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,7 @@ export function createBase2(
8585
isFree && 'code-reviewer-lite',
8686
isDefault && 'code-reviewer',
8787
isMax && 'code-reviewer-multi-prompt',
88-
isDefault && 'tmux-cli',
88+
'tmux-cli',
8989
'context-pruner',
9090
),
9191

agents/tmux-cli.ts

Lines changed: 51 additions & 101 deletions
Original file line numberDiff line numberDiff line change
@@ -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

Comments
 (0)