From da6545848b2c58f8a26f8082073fdebfea415b89 Mon Sep 17 00:00:00 2001 From: Gunju Kim Date: Wed, 18 Feb 2026 09:18:54 +0000 Subject: [PATCH] CLI: show task outputs (PR, branch, cost) when watch completes When using `axon run -w`, the watchTask function previously only printed phase transitions (e.g. "task/xyz Succeeded") with no indication of what the agent actually produced. New users would need to know to separately run `axon get task ` to discover the PR URL, branch name, commit SHA, or token usage. This change makes watchTask print key results (branch, pr, commit, cost-usd, input-tokens, output-tokens) immediately after the task reaches a terminal phase, so the most useful outputs appear right in the terminal where the user is waiting. Co-Authored-By: Claude Sonnet 4.6 --- internal/cli/printer_test.go | 75 ++++++++++++++++++++++++++++++++++++ internal/cli/run.go | 16 ++++++++ 2 files changed, 91 insertions(+) diff --git a/internal/cli/printer_test.go b/internal/cli/printer_test.go index b741b0c9..415822cf 100644 --- a/internal/cli/printer_test.go +++ b/internal/cli/printer_test.go @@ -323,3 +323,78 @@ func TestPrintWorkspaceDetailWithoutOptionalFields(t *testing.T) { t.Errorf("expected no Secret field when secretRef is nil, got %q", output) } } + +func TestPrintTaskResults(t *testing.T) { + tests := []struct { + name string + task *axonv1alpha1.Task + wantKeys []string + noKeys []string + }{ + { + name: "shows pr and branch when present", + task: &axonv1alpha1.Task{ + Status: axonv1alpha1.TaskStatus{ + Results: map[string]string{ + "branch": "axon-task-abc12", + "pr": "https://github.com/org/repo/pull/42", + "commit": "abc1234", + }, + }, + }, + wantKeys: []string{"branch:", "pr:", "commit:"}, + }, + { + name: "shows cost and token usage when present", + task: &axonv1alpha1.Task{ + Status: axonv1alpha1.TaskStatus{ + Results: map[string]string{ + "cost-usd": "1.23", + "input-tokens": "5000", + "output-tokens": "1200", + }, + }, + }, + wantKeys: []string{"cost-usd:", "input-tokens:", "output-tokens:"}, + }, + { + name: "prints nothing when results are empty", + task: &axonv1alpha1.Task{ + Status: axonv1alpha1.TaskStatus{}, + }, + noKeys: []string{"branch:", "pr:", "cost-usd:"}, + }, + { + name: "skips empty result values", + task: &axonv1alpha1.Task{ + Status: axonv1alpha1.TaskStatus{ + Results: map[string]string{ + "branch": "", + "pr": "https://github.com/org/repo/pull/99", + }, + }, + }, + wantKeys: []string{"pr:"}, + noKeys: []string{"branch:"}, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + var buf bytes.Buffer + printTaskResults(&buf, tt.task) + output := buf.String() + + for _, key := range tt.wantKeys { + if !strings.Contains(output, key) { + t.Errorf("expected %q in output, got %q", key, output) + } + } + for _, key := range tt.noKeys { + if strings.Contains(output, key) { + t.Errorf("expected %q NOT in output, got %q", key, output) + } + } + }) + } +} diff --git a/internal/cli/run.go b/internal/cli/run.go index e0b3b278..c84c3862 100644 --- a/internal/cli/run.go +++ b/internal/cli/run.go @@ -3,6 +3,7 @@ package cli import ( "context" "fmt" + "io" "os" "reflect" "strings" @@ -324,6 +325,7 @@ func watchTask(ctx context.Context, cl client.Client, name, namespace string) er } if task.Status.Phase == axonv1alpha1.TaskPhaseSucceeded || task.Status.Phase == axonv1alpha1.TaskPhaseFailed { + printTaskResults(os.Stdout, task) return nil } @@ -331,6 +333,20 @@ func watchTask(ctx context.Context, cl client.Client, name, namespace string) er } } +// printTaskResults prints the key outputs (branch, PR, commit, cost) from a +// completed task. Only fields that are populated are shown. +func printTaskResults(w io.Writer, task *axonv1alpha1.Task) { + if len(task.Status.Results) == 0 { + return + } + keys := []string{"branch", "pr", "commit", "cost-usd", "input-tokens", "output-tokens"} + for _, k := range keys { + if v, ok := task.Status.Results[k]; ok && v != "" { + fmt.Fprintf(w, " %-20s%s\n", k+":", v) + } + } +} + // apiKeySecretKey returns the secret key name for API key credentials // based on the agent type. func apiKeySecretKey(agentType string) string {