From 57b77daf64fa1cf8bee488169d1cacba2f3168b8 Mon Sep 17 00:00:00 2001 From: aksops Date: Sat, 16 May 2026 19:19:43 +0000 Subject: [PATCH] feat(hermes): always pass --tui when launching hermes ctm only ever drives hermes through its TUI surface; bake --tui into BuildCommand so every spawn (new/yolo/yolo!/safe/resume) and every resume fallback gets it without callers having to remember. Co-Authored-By: Claude Opus 4.7 (1M context) --- internal/agent/hermes/command.go | 17 ++++++++++------- internal/agent/hermes/command_test.go | 18 +++++++++--------- 2 files changed, 19 insertions(+), 16 deletions(-) diff --git a/internal/agent/hermes/command.go b/internal/agent/hermes/command.go index b7e9423..d906715 100644 --- a/internal/agent/hermes/command.go +++ b/internal/agent/hermes/command.go @@ -15,14 +15,17 @@ func shellQuote(s string) string { // // agentSessionID is the hermes session ID (Session.AgentSessionID). On // resume: -// - if non-empty: `hermes --resume ` -// - if empty: `hermes -c` (continue most-recent) +// - if non-empty: `hermes --tui --resume ` +// - if empty: `hermes --tui -c` (continue most-recent) // -// In both resume branches the command falls back to a fresh `hermes` on -// non-zero exit — matches codex's pattern for crash/Ctrl-C parity. +// In both resume branches the command falls back to a fresh `hermes --tui` +// on non-zero exit — matches codex's pattern for crash/Ctrl-C parity. // (Hermes itself exits 0 even on bad ID, so this fallback is purely // defensive against crashes during resume.) // +// --tui is always passed: ctm only ever drives hermes through its TUI +// surface. +// // envExports, when non-empty, is prepended verbatim as a shell prelude. func BuildCommand(agentSessionID, mode string, resume bool, envExports string) string { var yoloFlag string @@ -30,17 +33,17 @@ func BuildCommand(agentSessionID, mode string, resume bool, envExports string) s yoloFlag = " --yolo" } - freshCmd := "hermes" + yoloFlag + freshCmd := "hermes --tui" + yoloFlag var core string switch { case !resume: core = freshCmd case agentSessionID != "": - core = fmt.Sprintf("hermes --resume %s%s || %s", + core = fmt.Sprintf("hermes --tui --resume %s%s || %s", shellQuote(agentSessionID), yoloFlag, freshCmd) default: - core = "hermes -c" + yoloFlag + " || " + freshCmd + core = "hermes --tui -c" + yoloFlag + " || " + freshCmd } if envExports != "" { diff --git a/internal/agent/hermes/command_test.go b/internal/agent/hermes/command_test.go index 6e865e7..5ed2f3a 100644 --- a/internal/agent/hermes/command_test.go +++ b/internal/agent/hermes/command_test.go @@ -14,53 +14,53 @@ func TestBuildCommand(t *testing.T) { { name: "fresh-safe", mode: "safe", resume: false, - want: "hermes", + want: "hermes --tui", }, { name: "fresh-yolo", mode: "yolo", resume: false, - want: "hermes --yolo", + want: "hermes --tui --yolo", }, { name: "resume-with-id-safe", agentSessionID: "20260515_152727_9da209", mode: "safe", resume: true, - want: "hermes --resume '20260515_152727_9da209' || hermes", + want: "hermes --tui --resume '20260515_152727_9da209' || hermes --tui", }, { name: "resume-with-id-yolo", agentSessionID: "20260515_152727_9da209", mode: "yolo", resume: true, - want: "hermes --resume '20260515_152727_9da209' --yolo || hermes --yolo", + want: "hermes --tui --resume '20260515_152727_9da209' --yolo || hermes --tui --yolo", }, { name: "resume-no-id-safe", mode: "safe", resume: true, - want: "hermes -c || hermes", + want: "hermes --tui -c || hermes --tui", }, { name: "resume-no-id-yolo", mode: "yolo", resume: true, - want: "hermes -c --yolo || hermes --yolo", + want: "hermes --tui -c --yolo || hermes --tui --yolo", }, { name: "env-prelude-fresh-safe", mode: "safe", resume: false, envExports: "export FOO='bar'", - want: "export FOO='bar'; hermes", + want: "export FOO='bar'; hermes --tui", }, { name: "env-prelude-resume-yolo", agentSessionID: "id1", mode: "yolo", resume: true, envExports: "export FOO='bar'", - want: "export FOO='bar'; hermes --resume 'id1' --yolo || hermes --yolo", + want: "export FOO='bar'; hermes --tui --resume 'id1' --yolo || hermes --tui --yolo", }, { name: "shell-quote-escapes-single-quote", agentSessionID: `weird'id`, mode: "safe", resume: true, - want: `hermes --resume 'weird'\''id' || hermes`, + want: `hermes --tui --resume 'weird'\''id' || hermes --tui`, }, } for _, tt := range tests {