From d8608b798a90e683a43d0caddc68727feac65570 Mon Sep 17 00:00:00 2001 From: Beforerr Date: Tue, 14 Jul 2026 14:09:35 +0900 Subject: [PATCH] feat: address saved traces by session ID --- go/daemon.go | 9 +++++---- go/engine_test.go | 9 ++++++++- go/julia_integration_test.go | 8 +++++--- skills/repld/SKILL.md | 5 +++-- 4 files changed, 21 insertions(+), 10 deletions(-) diff --git a/go/daemon.go b/go/daemon.go index 0ff6e41..f78a41d 100644 --- a/go/daemon.go +++ b/go/daemon.go @@ -130,21 +130,22 @@ func normalizedTraceLevel(level string) string { } } -func formatError(err *evalError, level string) string { +func formatError(err *evalError, level, sessionID string) string { traceHint := strings.TrimSpace(err.smart) != strings.TrimSpace(err.short) + hint := fmt.Sprintf("Trace saved: `repld trace %s`.", sessionID) switch normalizedTraceLevel(level) { case "short": if !traceHint { return err.short } - return err.short + "\n\nTrace saved: run `trace --trace [smart|full]` to inspect" + return err.short + "\n\n" + hint case "full": return err.full default: if !traceHint { return err.short } - return err.smart + "Trace saved: run `trace` to inspect" + return err.smart + hint } } @@ -243,7 +244,7 @@ func handleStreamingEval(state *daemonState, req protocolRequest, conn net.Conn) } if evalErr, ok := err.(*evalError); ok { state.manager.recordError(req.Lang, req.Session, req.Cwd, disc, evalErr) - emit(streamFrame{Done: true, Error: formatError(evalErr, req.TraceLevel)}) + emit(streamFrame{Done: true, Error: formatError(evalErr, req.TraceLevel, sess.id)}) return } emit(streamFrame{Done: true, Error: err.Error()}) diff --git a/go/engine_test.go b/go/engine_test.go index bd76687..97a598f 100644 --- a/go/engine_test.go +++ b/go/engine_test.go @@ -75,6 +75,13 @@ func TestHandleRequest_UnknownAction(t *testing.T) { require.NotEmpty(t, resp.Error) } +func TestFormatErrorTraceHintIncludesSessionID(t *testing.T) { + err := &evalError{short: "short", smart: "smart\n", full: "full"} + require.Equal(t, "smart\nTrace saved: `repld trace klmnopqr`.", formatError(err, "smart", "klmnopqr")) + require.Equal(t, "short\n\nTrace saved: `repld trace klmnopqr`.", formatError(err, "short", "klmnopqr")) + require.Equal(t, "full", formatError(err, "full", "klmnopqr")) +} + func TestHandleRequest_Stop(t *testing.T) { state := newTestState() resp := handleRequest(state, protocolRequest{Action: "stop"}) @@ -206,4 +213,4 @@ func TestSessionManagerKey(t *testing.T) { // a --session label is global: same key regardless of language/project. require.Equal(t, sessionKey{label: "scratch"}, m.key("julia", "scratch", "/w", "@.")) require.Equal(t, sessionKey{label: "scratch"}, m.key("python", "scratch", "/other", "")) -} \ No newline at end of file +} diff --git a/go/julia_integration_test.go b/go/julia_integration_test.go index 99e75a7..6d18e33 100644 --- a/go/julia_integration_test.go +++ b/go/julia_integration_test.go @@ -9,6 +9,7 @@ import ( "os" "os/exec" "path/filepath" + "regexp" "strings" "testing" "time" @@ -110,15 +111,16 @@ func TestJuliaWarmSession(t *testing.T) { require.Empty(t, res.stdout) require.Contains(t, res.stderr, "boom") require.Contains(t, res.stderr, "Stacktrace:") - require.Contains(t, res.stderr, "run `trace") + hint := regexp.MustCompile("Trace saved: `repld trace ([k-z]{8})`\\.").FindStringSubmatch(res.stderr) + require.Len(t, hint, 2) require.NotContains(t, res.stderr, "eval_user_input") - res = repldOK(t, socketPath, cwd, "trace", "--trace", "smart", "julia") + res = repldOK(t, socketPath, cwd, "trace", "--trace", "smart", hint[1]) require.Contains(t, res.stdout, "Stacktrace:") require.Contains(t, res.stdout, "repld-eval") require.NotContains(t, res.stdout, "eval_user_input") - res = repldOK(t, socketPath, cwd, "trace", "--trace", "full", "julia") + res = repldOK(t, socketPath, cwd, "trace", "--trace", "full", hint[1]) require.Contains(t, res.stdout, "include_string") res = repldErr(t, socketPath, cwd, "--trace", "full", "julia", "-e", `let f = () -> error("boom"); g = () -> f(); g(); end`) diff --git a/skills/repld/SKILL.md b/skills/repld/SKILL.md index a336e65..6f85066 100644 --- a/skills/repld/SKILL.md +++ b/skills/repld/SKILL.md @@ -40,8 +40,9 @@ See [julia.md](references/julia.md), [python.md](references/python.md), [r.md](r ```bash repld sessions # list active sessions, show IDs -repld trace [id | exe | --session=LABEL] # last saved traceback -repld [interrupt | close] [id | exe | --session=LABEL] +repld trace # last saved traceback +repld interrupt +repld close repld stop # shut down daemon timeout 30 repld julia -e 'might_hang()' # client death interrupts eval