fix: early Session-ID output + Gemini -p display correction

- Output Session-ID to stderr immediately when backend reports
  session_started, so Claude can capture it even if task times out
- Fix Command: display line to show actual task text instead of
  misleading -p - for Gemini backend (geminiDirect logic)
- Bump codeagent-wrapper 5.8.0 → 5.9.0
- Bump EXPECTED_BINARY_VERSION to 5.9.0
This commit is contained in:
li committed 2026-03-26 13:23:52 +08:00
1 parent 88ac6a9a2f
commit 32a5043bdb
9 files changed
+61 -15

No files matched your search

+18 -1
View File
@@ -1069,6 +1069,23 @@ func runCodexTaskWithContext(parentCtx context.Context, taskSpec TaskSpec, backe
}
}
// Emit Session-ID to stderr as soon as the backend reports it.
// This lets Claude Code capture the real session ID even if the
// task later times out or fails (where the final SESSION_ID: line
// in stdout would never be printed).
// Skip in silent mode (parallel tasks) to avoid polluting stderr.
var sessionIDEmitted bool
var onSessionStartedCallback func(string)
if !silent {
onSessionStartedCallback = func(id string) {
if sessionIDEmitted || id == "" {
return
}
sessionIDEmitted = true
fmt.Fprintf(os.Stderr, " Session-ID: %s\n", id)
}
}
go func() {
msg, tid := parseJSONStreamInternalWithContent(stdoutReader, logWarnFn, logInfoFn, func() {
select {
@@ -1084,7 +1101,7 @@ func runCodexTaskWithContext(parentCtx context.Context, taskSpec TaskSpec, backe
if globalWebServer != nil && webSessionID != "" {
globalWebServer.EndSession(webSessionID, cfg.Backend)
}
}, onContentCallback, onProgressCallback)
}, onContentCallback, onProgressCallback, onSessionStartedCallback)
select {
case completeSeen <- struct{}{}:
default:
+5 -2
View File
@@ -14,7 +14,7 @@ import (
)
const (
version = "5.8.0"
version = "5.9.0"
defaultWorkdir = "."
defaultTimeout = 7200 // seconds (2 hours)
defaultCoverageTarget = 90.0
@@ -417,7 +417,10 @@ func run() (exitCode int) {
useStdin := cfg.ExplicitStdin || shouldUseStdin(taskText, piped)
targetArg := taskText
if useStdin {
// Gemini CLI does not support "-" as stdin marker for -p flag.
// Match the geminiDirect logic in executor.go so the display is accurate.
geminiDirect := useStdin && cfg.Backend == "gemini"
if useStdin && !geminiDirect {
targetArg = "-"
}
codexArgs := buildCodexArgsFn(cfg, targetArg)
+8 -7
View File
@@ -2601,13 +2601,14 @@ func TestRunSilentMode(t *testing.T) {
verbose := capture(false)
quiet := capture(true)
// After refactoring, logs are only written to file, not stderr
// Both silent and non-silent modes should produce no stderr output
// Silent mode (parallel tasks): no stderr output at all
if quiet != "" {
t.Fatalf("silent mode should suppress stderr, got: %q", quiet)
}
if verbose != "" {
t.Fatalf("non-silent mode should also suppress stderr (logs go to file), got: %q", verbose)
// Non-silent mode (single task): Session-ID is emitted to stderr
// so Claude Code can capture it even if the task later fails/times out
if !strings.Contains(verbose, "Session-ID: silent-session") {
t.Fatalf("non-silent mode should emit Session-ID to stderr, got: %q", verbose)
}
}
@@ -3051,7 +3052,7 @@ func TestVersionFlag(t *testing.T) {
}
})
want := "codeagent-wrapper version 5.8.0\n"
want := "codeagent-wrapper version 5.9.0\n"
if output != want {
t.Fatalf("output = %q, want %q", output, want)
@@ -3067,7 +3068,7 @@ func TestVersionShortFlag(t *testing.T) {
}
})
want := "codeagent-wrapper version 5.8.0\n"
want := "codeagent-wrapper version 5.9.0\n"
if output != want {
t.Fatalf("output = %q, want %q", output, want)
@@ -3083,7 +3084,7 @@ func TestVersionLegacyAlias(t *testing.T) {
}
})
want := "codex-wrapper version 5.8.0\n"
want := "codex-wrapper version 5.9.0\n"
if output != want {
t.Fatalf("output = %q, want %q", output, want)
+8 -2
View File
@@ -97,10 +97,10 @@ type ItemContent struct {
}
func parseJSONStreamInternal(r io.Reader, warnFn func(string), infoFn func(string), onMessage func(), onComplete func()) (message, threadID string) {
return parseJSONStreamInternalWithContent(r, warnFn, infoFn, onMessage, onComplete, nil, nil)
return parseJSONStreamInternalWithContent(r, warnFn, infoFn, onMessage, onComplete, nil, nil, nil)
}
func parseJSONStreamInternalWithContent(r io.Reader, warnFn func(string), infoFn func(string), onMessage func(), onComplete func(), onContent func(content, contentType string), onProgress func(line string)) (message, threadID string) {
func parseJSONStreamInternalWithContent(r io.Reader, warnFn func(string), infoFn func(string), onMessage func(), onComplete func(), onContent func(content, contentType string), onProgress func(line string), onSessionStarted func(id string)) (message, threadID string) {
reader := bufio.NewReaderSize(r, jsonLineReaderSize)
if warnFn == nil {
@@ -168,6 +168,9 @@ func parseJSONStreamInternalWithContent(r io.Reader, warnFn func(string), infoFn
// Extract session_id early (works for all backends)
if event.SessionID != "" && threadID == "" {
threadID = event.SessionID
if onSessionStarted != nil {
onSessionStarted(threadID)
}
}
// Detect backend type by field presence
@@ -205,6 +208,9 @@ func parseJSONStreamInternalWithContent(r io.Reader, warnFn func(string), infoFn
threadID = event.ThreadID
infoFn(fmt.Sprintf("thread.started event thread_id=%s", threadID))
emitProgress(formatProgressLine("session_started", map[string]string{"id": threadID}))
if onSessionStarted != nil {
onSessionStarted(threadID)
}
case "turn.started":
emitProgress(formatProgressLine("turn_started", nil))
@@ -52,6 +52,7 @@ func TestParseJSONStreamInternalWithContent_EmitsProgressLines(t *testing.T) {
nil,
nil,
func(line string) { progress = append(progress, line) },
nil,
)
if message != "Done with changes" {