feat(agent): terminal TUI for forge agent watch (#5) #7

Merged
frank merged 1 commit from agent/issue-5-agent-terminalfüllende-tui-für-forge-a into main 2026-07-12 10:05:59 +02:00
Owner

Summary

  • Adds forge agent watch --tui: full-screen split terminal UI with live queue/stats (left) and agent stdout/stderr (right).
  • Reuses WatchStatus / WatchSnapshot; token and cost show n/a unless the agent prints parseable telemetry.
  • --ui and --tui are mutually exclusive; documented in README, --help, and the Agent Watcher wiki page.

Test plan

  • go test ./... and go vet ./...
  • forge agent watch --label <ready> --agent claude --pr --tui --dry-run --once — TUI starts, stats/queue update, no crash without token/cost data
  • During a real agent run, verify live output appears in the right panel and auto-follows (g to re-enable)
  • Press q or Ctrl+C — watcher and TUI exit cleanly
  • forge agent watch --ui --tui — usage error (mutually exclusive)

Closes #5

## Summary - Adds `forge agent watch --tui`: full-screen split terminal UI with live queue/stats (left) and agent stdout/stderr (right). - Reuses `WatchStatus` / `WatchSnapshot`; token and cost show `n/a` unless the agent prints parseable telemetry. - `--ui` and `--tui` are mutually exclusive; documented in README, `--help`, and the Agent Watcher wiki page. ## Test plan - [x] `go test ./...` and `go vet ./...` - [ ] `forge agent watch --label <ready> --agent claude --pr --tui --dry-run --once` — TUI starts, stats/queue update, no crash without token/cost data - [ ] During a real agent run, verify live output appears in the right panel and auto-follows (`g` to re-enable) - [ ] Press `q` or Ctrl+C — watcher and TUI exit cleanly - [ ] `forge agent watch --ui --tui` — usage error (mutually exclusive) Closes #5
feat(agent): add terminal TUI for forge agent watch
All checks were successful
CI / race (pull_request) Successful in 10m7s
CI / test (pull_request) Successful in 10m12s
97df3f53cd
Introduce --tui split-screen status view with live queue, stats, and agent
output reusing WatchStatus; document in README and Agent Watcher wiki.

Co-authored-by: Cursor <cursoragent@cursor.com>
Author
Owner

🔗 Linked to issue #5. Babysitting CI until green…

🔗 Linked to issue #5. Babysitting CI until green…
Author
Owner

forge agent finished implementation

  • Commit: feat(agent): add terminal TUI for forge agent watch
  • Pull request: #7
  • Next: waiting for CI / babysitting fixes if needed
README.md                                          |    3 +
 go.mod                                             |   19 +-
 go.sum                                             |   41 +-
 internal/agent/pipeline.go                         |    7 +
 internal/agent/status.go                           |  107 +-
 internal/agent/tui.go                              |  344 ++
 internal/agent/tui_test.go                         |  125 +
 internal/agent/watcher.go                          |    1 +
 internal/cmd/agent.go                              |   35 +-
 internal/cmd/agent_test.go                         |   11 +
 vendor/github.com/aymanbagabas/go-osc52/v2/LICENSE |   21 +
 .../github.com/aymanbagabas/go-osc52/v2/README.md  |   83 +
 .../github.com/aymanbagabas/go-osc52/v2/osc52.go   |  305 ++
 vendor/github.com/charmbracelet/bubbles/LICENSE    |   21 +
 vendor/github.com/charmbracelet/bubbles/key/key.go |  140 +
 .../charmbracelet/bubbles/viewport/keymap.go       |   48 +
 .../charmbracelet/bubbles/viewport/viewport.go     |  405 +++
 .../charmbracelet/bubbletea/.gitattributes         |    1 +
 .../github.com/charmbracelet/bubbletea/.gitignore  |   23 +
 .../charmbracelet/bubbletea/.golangci-soft.yml     |   40 +
 .../charmbracelet/bubbletea/.golangci.yml          |   28 +
 .../charmbracelet/bubbletea/.goreleaser.yml        |    5 +
 vendor/github.com/charmbracelet/bubbletea/LICENSE  |   21 +
 .../github.com/charmbracelet/bubbletea/README.md   |  393 +++
 .../github.com/charmbracelet/bubbletea/commands.go |  216 ++
 vendor/github.com/charmbracelet/bubbletea/exec.go  |  129 +
 vendor/github.com/charmbracelet/bubbletea/focus.go |    9 +
 .../charmbracelet/bubbletea/inputreader_other.go   |   14 +
 .../charmbracelet/bubbletea/inputreader_windows.go |  107 +
 vendor/github.com/charmbracelet/bubbletea/key.go   |  715 ++++
 .../charmbracelet/bubbletea/key_other.go           |   13 +
 .../charmbracelet/bubbletea/key_sequences.go       |  131 +
 .../charmbracelet/bubbletea/key_windows.go         |  351 ++
 .../github.com/charmbracelet/bubbletea/logging.go  |   53 +
 vendor/github.com/charmbracelet/bubbletea/mouse.go |  308 ++
 .../charmbracelet/bubbletea/nil_renderer.go        |   28 +
 .../github.com/charmbracelet/bubbletea/options.go  |  252 ++
 .../github.com/charmbracelet/bubbletea/renderer.go |   85 +
 .../github.com/charmbracelet/bubbletea/screen.go   |  248 ++
 .../charmbracelet/bubbletea/signals_unix.go        |   33 +
 .../charmbracelet/bubbletea/signals_windows.go     |   10 +
 .../charmbracelet/bubbletea/standard_renderer.go   |  782 +++++
 vendor/github.com/charmbracelet/bubbletea/tea.go   |  788 +++++
 .../github.com/charmbracelet/bubbletea/tea_init.go |   22 +
 vendor/github.com/charmbracelet/bubbletea/tty.go   |  136 +
 .../github.com/charmbracelet/bubbletea/tty_unix.go |   49 +
 .../charmbracelet/bubbletea/tty_windows.go         |   68 +
 .../github.com/charmbracelet/lipgloss/.gitignore   |    1 +
 .../charmbracelet/lipgloss/.golangci-soft.yml      |   40 +
 .../charmbracelet/lipgloss/.golangci.yml           |   28 +
 .../charmbracelet/lipgloss/.goreleaser.yml         |    5 +
 vendor/github.com/charmbracelet/lipgloss/LICENSE   |   21 +
 vendor/github.com/charmbracelet/lipgloss/README.md |  765 +++++
 vendor/github.com/charmbracelet/lipgloss/align.go  |   83 +
 .../github.com/charmbracelet/lipgloss/ansi_unix.go |    7 +
 .../charmbracelet/lipgloss/ansi_windows.go         |   22 +
 .../github.com/charmbracelet/lipgloss/borders.go   |  443 +++
 vendor/github.com/charmbracelet/lipgloss/color.go  |  172 +
 vendor/github.com/charmbracelet/lipgloss/get.go    |  542 +++
 vendor/github.com/charmbracelet/lipgloss/join.go   |  175 +
 .../github.com/charmbracelet/lipgloss/position.go  |  154 +
 .../github.com/charmbracelet/lipgloss/renderer.go  |  181 +
 vendor/github.com/charmbracelet/lipgloss/runes.go  |   43 +
 vendor/github.com/charmbracelet/lipgloss/set.go    |  799 +++++
 vendor/github.com/charmbracelet/lipgloss/size.go   |   41 +
 vendor/github.com/charmbracelet/lipgloss/style.go  |  587 ++++
 vendor/github.com/charmbracelet/lipgloss/unset.go  |  331 ++
 .../charmbracelet/lipgloss/whitespace.go           |   83 +
 vendor/github.com/charmbracelet/x/ansi/LICENSE     |   21 +
 vendor/github.com/charmbracelet/x/ansi/ansi.go     |   11 +
 vendor/github.com/charmbracelet/x/ansi/ascii.go    |    8 +
 .../github.com/charmbracelet/x/ansi/background.go  |   78 +
 vendor/github.com/charmbracelet/x/ansi/c0.go       |   72 +
 vendor/github.com/charmbracelet/x/ansi/c1.go       |   72 +
 .../github.com/charmbracelet/x/ansi/clipboard.go   |   75 +
 vendor/github.com/charmbracelet/x/ansi/color.go    |  196 ++
 vendor/github.com/charmbracelet/x/ansi/csi.go      |  141 +
 vendor/github.com/charmbracelet/x/ansi/ctrl.go     |   17 +
 vendor/github.com/charmbracelet/x/ansi/cursor.go   |  259 ++
 vendor/github.com/charmbracelet/x/ansi/dcs.go      |  148 +
 vendor/github.com/charmbracelet/x/ansi/doc.go      |    7 +
 .../github.com/charmbracelet/x/ansi/hyperlink.go   |   28 +
 vendor/github.com/charmbracelet/x/ansi/kitty.go    |   90 +
 vendor/github.com/charmbracelet/x/ansi/mode.go     |  197 ++
 .../charmbracelet/x/ansi/notification.go           |   13 +
 vendor/github.com/charmbracelet/x/ansi/osc.go      |   69 +
 vendor/github.com/charmbracelet/x/ansi/params.go   |   45 +
 vendor/github.com/charmbracelet/x/ansi/parser.go   |  363 ++
 .../charmbracelet/x/ansi/parser/const.go           |   78 +
 .../github.com/charmbracelet/x/ansi/parser/seq.go  |  136 +
 .../x/ansi/parser/transition_table.go              |  273 ++
 .../charmbracelet/x/ansi/parser_decode.go          |  450 +++
 .../github.com/charmbracelet/x/ansi/parser_sync.go |   26 +
 .../github.com/charmbracelet/x/ansi/passthrough.go |   63 +
 vendor/github.com/charmbracelet/x/ansi/screen.go   |  129 +
 vendor/github.com/charmbracelet/x/ansi/sequence.go |  199 ++
 vendor/github.com/charmbracelet/x/ansi/style.go    |  496 +++
 vendor/github.com/charmbracelet/x/ansi/termcap.go  |   31 +
 vendor/github.com/charmbracelet/x/ansi/title.go    |   32 +
 vendor/github.com/charmbracelet/x/ansi/truncate.go |  107 +
 vendor/github.com/charmbracelet/x/ansi/util.go     |   29 +
 vendor/github.com/charmbracelet/x/ansi/width.go    |   95 +
 vendor/github.com/charmbracelet/x/ansi/wrap.go     |  400 +++
 vendor/github.com/charmbracelet/x/ansi/xterm.go    |   50 +
 vendor/github.com/charmbracelet/x/term/LICENSE     |   21 +
 vendor/github.com/charmbracelet/x/term/term.go     |   49 +
 .../github.com/charmbracelet/x/term/term_other.go  |   39 +
 .../github.com/charmbracelet/x/term/term_unix.go   |   96 +
 .../charmbracelet/x/term/term_unix_bsd.go          |   11 +
 .../charmbracelet/x/term/term_unix_other.go        |   11 +
 .../charmbracelet/x/term/term_windows.go           |   87 +
 vendor/github.com/charmbracelet/x/term/terminal.go |   12 +
 vendor/github.com/charmbracelet/x/term/util.go     |   47 +
 vendor/github.com/erikgeiser/coninput/.gitignore   |   15 +
 .../github.com/erikgeiser/coninput/.golangci.yml   |   24 +
 vendor/github.com/erikgeiser/coninput/LICENSE      |   21 +
 vendor/github.com/erikgeiser/coninput/README.md    |    2 +
 vendor/github.com/erikgeiser/coninput/keycodes.go  |  205 ++
 vendor/github.com/erikgeiser/coninput/mode.go      |   82 +
 vendor/github.com/erikgeiser/coninput/read.go      |  154 +
 vendor/github.com/erikgeiser/coninput/records.go   |  486 +++
 .../github.com/lucasb-eyer/go-colorful/.gitignore  |  101 +
 .../lucasb-eyer/go-colorful/CHANGELOG.md           |   42 +
 vendor/github.com/lucasb-eyer/go-colorful/LICENSE  |    7 +
 .../github.com/lucasb-eyer/go-colorful/README.md   |  482 +++
 .../lucasb-eyer/go-colorful/colorgens.go           |   55 +
 .../github.com/lucasb-eyer/go-colorful/colors.go   |  979 ++++++
 .../lucasb-eyer/go-colorful/happy_palettegen.go    |   25 +
 .../github.com/lucasb-eyer/go-colorful/hexcolor.go |   67 +
 .../go-colorful/hsluv-snapshot-rev4.json           |    1 +
 vendor/github.com/lucasb-eyer/go-colorful/hsluv.go |  207 ++
 .../lucasb-eyer/go-colorful/soft_palettegen.go     |  185 +
 .../lucasb-eyer/go-colorful/warm_palettegen.go     |   25 +
 vendor/github.com/mattn/go-isatty/LICENSE          |    9 +
 vendor/github.com/mattn/go-isatty/README.md        |   50 +
 vendor/github.com/mattn/go-isatty/doc.go           |    2 +
 vendor/github.com/mattn/go-isatty/go.test.sh       |   12 +
 vendor/github.com/mattn/go-isatty/isatty_bsd.go    |   20 +
 vendor/github.com/mattn/go-isatty/isatty_others.go |   17 +
 vendor/github.com/mattn/go-isatty/isatty_plan9.go  |   23 +
 .../github.com/mattn/go-isatty/isatty_solaris.go   |   21 +
 vendor/github.com/mattn/go-isatty/isatty_tcgets.go |   20 +
 .../github.com/mattn/go-isatty/isatty_windows.go   |  125 +
 vendor/github.com/mattn/go-localereader/README.md  |   23 +
 .../mattn/go-localereader/localereader.go          |   19 +
 .../mattn/go-localereader/localereader_unix.go     |   11 +
 .../mattn/go-localereader/localereader_windows.go  |   85 +
 vendor/github.com/mattn/go-runewidth/LICENSE       |   21 +
 vendor/github.com/mattn/go-runewidth/README.md     |   27 +
 vendor/github.com/mattn/go-runewidth/runewidth.go  |  358 ++
 .../mattn/go-runewidth/runewidth_appengine.go      |    9 +
 .../github.com/mattn/go-runewidth/runewidth_js.go  |    9 +
 .../mattn/go-runewidth/runewidth_posix.go          |   81 +
 .../mattn/go-runewidth/runewidth_table.go          |  450 +++
 .../mattn/go-runewidth/runewidth_windows.go        |   28 +
 vendor/github.com/muesli/ansi/.gitignore           |   15 +
 vendor/github.com/muesli/ansi/.golangci.yml        |   27 +
 vendor/github.com/muesli/ansi/LICENSE              |   21 +
 vendor/github.com/muesli/ansi/README.md            |   31 +
 vendor/github.com/muesli/ansi/ansi.go              |    7 +
 vendor/github.com/muesli/ansi/buffer.go            |   40 +
 vendor/github.com/muesli/ansi/compressor/writer.go |  132 +
 vendor/github.com/muesli/ansi/writer.go            |   76 +
 vendor/github.com/muesli/cancelreader/.gitignore   |   15 +
 .../muesli/cancelreader/.golangci-soft.yml         |   47 +
 .../github.com/muesli/cancelreader/.golangci.yml   |   29 +
 vendor/github.com/muesli/cancelreader/LICENSE      |   21 +
 vendor/github.com/muesli/cancelreader/README.md    |   64 +
 .../github.com/muesli/cancelreader/cancelreader.go |   93 +
 .../muesli/cancelreader/cancelreader_bsd.go        |  146 +
 .../muesli/cancelreader/cancelreader_default.go    |   12 +
 .../muesli/cancelreader/cancelreader_linux.go      |  154 +
 .../muesli/cancelreader/cancelreader_select.go     |  136 +
 .../muesli/cancelreader/cancelreader_unix.go       |   18 +
 .../muesli/cancelreader/cancelreader_windows.go    |  244 ++
 vendor/github.com/muesli/termenv/.gitignore        |   15 +
 .../github.com/muesli/termenv/.golangci-soft.yml   |   47 +
 vendor/github.com/muesli/termenv/.golangci.yml     |   29 +
 vendor/github.com/muesli/termenv/LICENSE           |   21 +
 vendor/github.com/muesli/termenv/README.md         |  431 +++
 vendor/github.com/muesli/termenv/ansi_compat.md    |   65 +
 vendor/github.com/muesli/termenv/ansicolors.go     |  281 ++
 vendor/github.com/muesli/termenv/color.go          |  204 ++
 .../github.com/muesli/termenv/constants_linux.go   |    8 +
 .../github.com/muesli/termenv/constants_solaris.go |    8 +
 vendor/github.com/muesli/termenv/constants_unix.go |   13 +
 vendor/github.com/muesli/termenv/copy.go           |   37 +
 vendor/github.com/muesli/termenv/hyperlink.go      |   11 +
 vendor/github.com/muesli/termenv/notification.go   |   11 +
 vendor/github.com/muesli/termenv/output.go         |  197 ++
 vendor/github.com/muesli/termenv/profile.go        |   97 +
 vendor/github.com/muesli/termenv/screen.go         |  590 ++++
 vendor/github.com/muesli/termenv/style.go          |  126 +
 vendor/github.com/muesli/termenv/templatehelper.go |   86 +
 vendor/github.com/muesli/termenv/termenv.go        |  114 +
 vendor/github.com/muesli/termenv/termenv_other.go  |   30 +
 vendor/github.com/muesli/termenv/termenv_posix.go  |   17 +
 .../github.com/muesli/termenv/termenv_solaris.go   |   22 +
 vendor/github.com/muesli/termenv/termenv_unix.go   |  293 ++
 .../github.com/muesli/termenv/termenv_windows.go   |  139 +
 vendor/github.com/rivo/uniseg/LICENSE.txt          |   21 +
 vendor/github.com/rivo/uniseg/README.md            |  137 +
 vendor/github.com/rivo/uniseg/doc.go               |  108 +
 vendor/github.com/rivo/uniseg/eastasianwidth.go    | 2588 ++++++++++++++
 vendor/github.com/rivo/uniseg/emojipresentation.go |  295 ++
 vendor/github.com/rivo/uniseg/gen_breaktest.go     |  215 ++
 vendor/github.com/rivo/uniseg/gen_properties.go    |  261 ++
 vendor/github.com/rivo/uniseg/grapheme.go          |  331 ++
 .../github.com/rivo/uniseg/graphemeproperties.go   | 1915 +++++++++++
 vendor/github.com/rivo/uniseg/graphemerules.go     |  176 +
 vendor/github.com/rivo/uniseg/line.go              |  134 +
 vendor/github.com/rivo/uniseg/lineproperties.go    | 3554 ++++++++++++++++++++
 vendor/github.com/rivo/uniseg/linerules.go         |  626 ++++
 vendor/github.com/rivo/uniseg/properties.go        |  208 ++
 vendor/github.com/rivo/uniseg/sentence.go          |   90 +
 .../github.com/rivo/uniseg/sentenceproperties.go   | 2845 ++++++++++++++++
 vendor/github.com/rivo/uniseg/sentencerules.go     |  276 ++
 vendor/github.com/rivo/uniseg/step.go              |  242 ++
 vendor/github.com/rivo/uniseg/width.go             |   61 +
 vendor/github.com/rivo/uniseg/word.go              |   89 +
 vendor/github.com/rivo/uniseg/wordproperties.go    | 1883 +++++++++++
 vendor/github.com/rivo/uniseg/wordrules.go         |  282 ++
 vendor/golang.org/x/sync/LICENSE                   |   27 +
 vendor/golang.org/x/sync/PATENTS                   |   22 +
 vendor/golang.org/x/sync/errgroup/errgroup.go      |  135 +
 vendor/golang.org/x/sync/errgroup/go120.go         |   13 +
 vendor/golang.org/x/sync/errgroup/pre_go120.go     |   14 +
 vendor/golang.org/x/sys/unix/ioctl_linux.go        |   96 +
 vendor/golang.org/x/sys/unix/mkerrors.sh           |   12 +
 vendor/golang.org/x/sys/unix/syscall_linux.go      |    1 +
 vendor/golang.org/x/sys/unix/syscall_zos_s390x.go  |  104 +-
 vendor/golang.org/x/sys/unix/zerrors_linux.go      |   22 +
 vendor/golang.org/x/sys/unix/zerrors_linux_386.go  |   14 +
 .../golang.org/x/sys/unix/zerrors_linux_amd64.go   |   14 +
 vendor/golang.org/x/sys/unix/zerrors_linux_arm.go  |   14 +
 .../golang.org/x/sys/unix/zerrors_linux_arm64.go   |   14 +
 .../golang.org/x/sys/unix/zerrors_linux_loong64.go |   14 +
 vendor/golang.org/x/sys/unix/zerrors_linux_mips.go |   14 +
 .../golang.org/x/sys/unix/zerrors_linux_mips64.go  |   14 +
 .../x/sys/unix/zerrors_linux_mips64le.go           |   14 +
 .../golang.org/x/sys/unix/zerrors_linux_mipsle.go  |   14 +
 vendor/golang.org/x/sys/unix/zerrors_linux_ppc.go  |   14 +
 .../golang.org/x/sys/unix/zerrors_linux_ppc64.go   |   14 +
 .../golang.org/x/sys/unix/zerrors_linux_ppc64le.go |   14 +
 .../golang.org/x/sys/unix/zerrors_linux_riscv64.go |   14 +
 .../golang.org/x/sys/unix/zerrors_linux_s390x.go   |   14 +
 .../golang.org/x/sys/unix/zerrors_linux_sparc64.go |   14 +
 vendor/golang.org/x/sys/unix/zsyscall_linux.go     |   10 +
 vendor/golang.org/x/sys/unix/ztypes_linux.go       |  120 +-
 vendor/golang.org/x/sys/unix/ztypes_zos_s390x.go   |    6 +
 vendor/golang.org/x/sys/windows/syscall_windows.go |   34 +-
 vendor/golang.org/x/sys/windows/types_windows.go   |  126 +
 .../golang.org/x/sys/windows/zsyscall_windows.go   |   53 +
 vendor/golang.org/x/text/LICENSE                   |   27 +
 vendor/golang.org/x/text/PATENTS                   |   22 +
 vendor/golang.org/x/text/transform/transform.go    |  709 ++++
 vendor/modules.txt                                 |   56 +-
 257 files changed, 43101 insertions(+), 34 deletions(-)
Agent output (tail)
TODO_DONE: Wiederverwendung bestehender Status-Infrastruktur (`WatchStatus` / `WatchSnapshot`) wo sinnvoll  
TODO_DONE: Token-/Kosten-Metriken nur anzeigen, wenn sie tatsächlich aus Runner-Output/Telemetry ableitbar sind; sonst als Follow-up kennzeichnen  
TODO_DONE: `forge agent watch --tui` (oder gleichwertiges Flag) startet eine terminalfüllende TUI  
TODO_DONE: Queue und Stats aktualisieren sich live mit dem Watcher  
TODO_DONE: Während eines Agent-Laufs ist die Vollausgabe im Live-Panel sichtbar  
TODO_DONE: Ohne verfügbare Token/$-Daten stürzt die TUI nicht ab und zeigt „n/a“  
TODO_DONE: Hilfe/Wiki dokumentiert Flag, Layout und bekannte Metrik-Limits  
TODO_DONE: Smoke-Test oder manueller Testplan in PR-Beschreibung  
PR_TITLE: feat(agent): terminal TUI for forge agent watch (#5)
PR_BODY:
## Summary
- Adds `forge agent watch --tui`: full-screen split terminal UI with live queue/stats (left) and agent stdout/stderr (right).
- Reuses `WatchStatus` / `WatchSnapshot`; token and cost show `n/a` unless the agent prints parseable telemetry.
- `--ui` and `--tui` are mutually exclusive; documented in README, `--help`, and the Agent Watcher wiki page.
## Test plan
- [x] `go test ./...` and `go vet ./...`
- [ ] `forge agent watch --label <ready> --agent claude --pr --tui --dry-run --once` — TUI starts, stats/queue update, no crash without token/cost data
- [ ] During a real agent run, verify live output appears in the right panel and auto-follows (`g` to re-enable)
- [ ] Press `q` or Ctrl+C — watcher and TUI exit cleanly
- [ ] `forge agent watch --ui --tui` — usage error (mutually exclusive)
✅ **forge agent finished implementation** - Commit: `feat(agent): add terminal TUI for forge agent watch` - Pull request: https://repository.hildebrandt.io/frank/forgecli/pulls/7 - Next: waiting for CI / babysitting fixes if needed ``` README.md | 3 + go.mod | 19 +- go.sum | 41 +- internal/agent/pipeline.go | 7 + internal/agent/status.go | 107 +- internal/agent/tui.go | 344 ++ internal/agent/tui_test.go | 125 + internal/agent/watcher.go | 1 + internal/cmd/agent.go | 35 +- internal/cmd/agent_test.go | 11 + vendor/github.com/aymanbagabas/go-osc52/v2/LICENSE | 21 + .../github.com/aymanbagabas/go-osc52/v2/README.md | 83 + .../github.com/aymanbagabas/go-osc52/v2/osc52.go | 305 ++ vendor/github.com/charmbracelet/bubbles/LICENSE | 21 + vendor/github.com/charmbracelet/bubbles/key/key.go | 140 + .../charmbracelet/bubbles/viewport/keymap.go | 48 + .../charmbracelet/bubbles/viewport/viewport.go | 405 +++ .../charmbracelet/bubbletea/.gitattributes | 1 + .../github.com/charmbracelet/bubbletea/.gitignore | 23 + .../charmbracelet/bubbletea/.golangci-soft.yml | 40 + .../charmbracelet/bubbletea/.golangci.yml | 28 + .../charmbracelet/bubbletea/.goreleaser.yml | 5 + vendor/github.com/charmbracelet/bubbletea/LICENSE | 21 + .../github.com/charmbracelet/bubbletea/README.md | 393 +++ .../github.com/charmbracelet/bubbletea/commands.go | 216 ++ vendor/github.com/charmbracelet/bubbletea/exec.go | 129 + vendor/github.com/charmbracelet/bubbletea/focus.go | 9 + .../charmbracelet/bubbletea/inputreader_other.go | 14 + .../charmbracelet/bubbletea/inputreader_windows.go | 107 + vendor/github.com/charmbracelet/bubbletea/key.go | 715 ++++ .../charmbracelet/bubbletea/key_other.go | 13 + .../charmbracelet/bubbletea/key_sequences.go | 131 + .../charmbracelet/bubbletea/key_windows.go | 351 ++ .../github.com/charmbracelet/bubbletea/logging.go | 53 + vendor/github.com/charmbracelet/bubbletea/mouse.go | 308 ++ .../charmbracelet/bubbletea/nil_renderer.go | 28 + .../github.com/charmbracelet/bubbletea/options.go | 252 ++ .../github.com/charmbracelet/bubbletea/renderer.go | 85 + .../github.com/charmbracelet/bubbletea/screen.go | 248 ++ .../charmbracelet/bubbletea/signals_unix.go | 33 + .../charmbracelet/bubbletea/signals_windows.go | 10 + .../charmbracelet/bubbletea/standard_renderer.go | 782 +++++ vendor/github.com/charmbracelet/bubbletea/tea.go | 788 +++++ .../github.com/charmbracelet/bubbletea/tea_init.go | 22 + vendor/github.com/charmbracelet/bubbletea/tty.go | 136 + .../github.com/charmbracelet/bubbletea/tty_unix.go | 49 + .../charmbracelet/bubbletea/tty_windows.go | 68 + .../github.com/charmbracelet/lipgloss/.gitignore | 1 + .../charmbracelet/lipgloss/.golangci-soft.yml | 40 + .../charmbracelet/lipgloss/.golangci.yml | 28 + .../charmbracelet/lipgloss/.goreleaser.yml | 5 + vendor/github.com/charmbracelet/lipgloss/LICENSE | 21 + vendor/github.com/charmbracelet/lipgloss/README.md | 765 +++++ vendor/github.com/charmbracelet/lipgloss/align.go | 83 + .../github.com/charmbracelet/lipgloss/ansi_unix.go | 7 + .../charmbracelet/lipgloss/ansi_windows.go | 22 + .../github.com/charmbracelet/lipgloss/borders.go | 443 +++ vendor/github.com/charmbracelet/lipgloss/color.go | 172 + vendor/github.com/charmbracelet/lipgloss/get.go | 542 +++ vendor/github.com/charmbracelet/lipgloss/join.go | 175 + .../github.com/charmbracelet/lipgloss/position.go | 154 + .../github.com/charmbracelet/lipgloss/renderer.go | 181 + vendor/github.com/charmbracelet/lipgloss/runes.go | 43 + vendor/github.com/charmbracelet/lipgloss/set.go | 799 +++++ vendor/github.com/charmbracelet/lipgloss/size.go | 41 + vendor/github.com/charmbracelet/lipgloss/style.go | 587 ++++ vendor/github.com/charmbracelet/lipgloss/unset.go | 331 ++ .../charmbracelet/lipgloss/whitespace.go | 83 + vendor/github.com/charmbracelet/x/ansi/LICENSE | 21 + vendor/github.com/charmbracelet/x/ansi/ansi.go | 11 + vendor/github.com/charmbracelet/x/ansi/ascii.go | 8 + .../github.com/charmbracelet/x/ansi/background.go | 78 + vendor/github.com/charmbracelet/x/ansi/c0.go | 72 + vendor/github.com/charmbracelet/x/ansi/c1.go | 72 + .../github.com/charmbracelet/x/ansi/clipboard.go | 75 + vendor/github.com/charmbracelet/x/ansi/color.go | 196 ++ vendor/github.com/charmbracelet/x/ansi/csi.go | 141 + vendor/github.com/charmbracelet/x/ansi/ctrl.go | 17 + vendor/github.com/charmbracelet/x/ansi/cursor.go | 259 ++ vendor/github.com/charmbracelet/x/ansi/dcs.go | 148 + vendor/github.com/charmbracelet/x/ansi/doc.go | 7 + .../github.com/charmbracelet/x/ansi/hyperlink.go | 28 + vendor/github.com/charmbracelet/x/ansi/kitty.go | 90 + vendor/github.com/charmbracelet/x/ansi/mode.go | 197 ++ .../charmbracelet/x/ansi/notification.go | 13 + vendor/github.com/charmbracelet/x/ansi/osc.go | 69 + vendor/github.com/charmbracelet/x/ansi/params.go | 45 + vendor/github.com/charmbracelet/x/ansi/parser.go | 363 ++ .../charmbracelet/x/ansi/parser/const.go | 78 + .../github.com/charmbracelet/x/ansi/parser/seq.go | 136 + .../x/ansi/parser/transition_table.go | 273 ++ .../charmbracelet/x/ansi/parser_decode.go | 450 +++ .../github.com/charmbracelet/x/ansi/parser_sync.go | 26 + .../github.com/charmbracelet/x/ansi/passthrough.go | 63 + vendor/github.com/charmbracelet/x/ansi/screen.go | 129 + vendor/github.com/charmbracelet/x/ansi/sequence.go | 199 ++ vendor/github.com/charmbracelet/x/ansi/style.go | 496 +++ vendor/github.com/charmbracelet/x/ansi/termcap.go | 31 + vendor/github.com/charmbracelet/x/ansi/title.go | 32 + vendor/github.com/charmbracelet/x/ansi/truncate.go | 107 + vendor/github.com/charmbracelet/x/ansi/util.go | 29 + vendor/github.com/charmbracelet/x/ansi/width.go | 95 + vendor/github.com/charmbracelet/x/ansi/wrap.go | 400 +++ vendor/github.com/charmbracelet/x/ansi/xterm.go | 50 + vendor/github.com/charmbracelet/x/term/LICENSE | 21 + vendor/github.com/charmbracelet/x/term/term.go | 49 + .../github.com/charmbracelet/x/term/term_other.go | 39 + .../github.com/charmbracelet/x/term/term_unix.go | 96 + .../charmbracelet/x/term/term_unix_bsd.go | 11 + .../charmbracelet/x/term/term_unix_other.go | 11 + .../charmbracelet/x/term/term_windows.go | 87 + vendor/github.com/charmbracelet/x/term/terminal.go | 12 + vendor/github.com/charmbracelet/x/term/util.go | 47 + vendor/github.com/erikgeiser/coninput/.gitignore | 15 + .../github.com/erikgeiser/coninput/.golangci.yml | 24 + vendor/github.com/erikgeiser/coninput/LICENSE | 21 + vendor/github.com/erikgeiser/coninput/README.md | 2 + vendor/github.com/erikgeiser/coninput/keycodes.go | 205 ++ vendor/github.com/erikgeiser/coninput/mode.go | 82 + vendor/github.com/erikgeiser/coninput/read.go | 154 + vendor/github.com/erikgeiser/coninput/records.go | 486 +++ .../github.com/lucasb-eyer/go-colorful/.gitignore | 101 + .../lucasb-eyer/go-colorful/CHANGELOG.md | 42 + vendor/github.com/lucasb-eyer/go-colorful/LICENSE | 7 + .../github.com/lucasb-eyer/go-colorful/README.md | 482 +++ .../lucasb-eyer/go-colorful/colorgens.go | 55 + .../github.com/lucasb-eyer/go-colorful/colors.go | 979 ++++++ .../lucasb-eyer/go-colorful/happy_palettegen.go | 25 + .../github.com/lucasb-eyer/go-colorful/hexcolor.go | 67 + .../go-colorful/hsluv-snapshot-rev4.json | 1 + vendor/github.com/lucasb-eyer/go-colorful/hsluv.go | 207 ++ .../lucasb-eyer/go-colorful/soft_palettegen.go | 185 + .../lucasb-eyer/go-colorful/warm_palettegen.go | 25 + vendor/github.com/mattn/go-isatty/LICENSE | 9 + vendor/github.com/mattn/go-isatty/README.md | 50 + vendor/github.com/mattn/go-isatty/doc.go | 2 + vendor/github.com/mattn/go-isatty/go.test.sh | 12 + vendor/github.com/mattn/go-isatty/isatty_bsd.go | 20 + vendor/github.com/mattn/go-isatty/isatty_others.go | 17 + vendor/github.com/mattn/go-isatty/isatty_plan9.go | 23 + .../github.com/mattn/go-isatty/isatty_solaris.go | 21 + vendor/github.com/mattn/go-isatty/isatty_tcgets.go | 20 + .../github.com/mattn/go-isatty/isatty_windows.go | 125 + vendor/github.com/mattn/go-localereader/README.md | 23 + .../mattn/go-localereader/localereader.go | 19 + .../mattn/go-localereader/localereader_unix.go | 11 + .../mattn/go-localereader/localereader_windows.go | 85 + vendor/github.com/mattn/go-runewidth/LICENSE | 21 + vendor/github.com/mattn/go-runewidth/README.md | 27 + vendor/github.com/mattn/go-runewidth/runewidth.go | 358 ++ .../mattn/go-runewidth/runewidth_appengine.go | 9 + .../github.com/mattn/go-runewidth/runewidth_js.go | 9 + .../mattn/go-runewidth/runewidth_posix.go | 81 + .../mattn/go-runewidth/runewidth_table.go | 450 +++ .../mattn/go-runewidth/runewidth_windows.go | 28 + vendor/github.com/muesli/ansi/.gitignore | 15 + vendor/github.com/muesli/ansi/.golangci.yml | 27 + vendor/github.com/muesli/ansi/LICENSE | 21 + vendor/github.com/muesli/ansi/README.md | 31 + vendor/github.com/muesli/ansi/ansi.go | 7 + vendor/github.com/muesli/ansi/buffer.go | 40 + vendor/github.com/muesli/ansi/compressor/writer.go | 132 + vendor/github.com/muesli/ansi/writer.go | 76 + vendor/github.com/muesli/cancelreader/.gitignore | 15 + .../muesli/cancelreader/.golangci-soft.yml | 47 + .../github.com/muesli/cancelreader/.golangci.yml | 29 + vendor/github.com/muesli/cancelreader/LICENSE | 21 + vendor/github.com/muesli/cancelreader/README.md | 64 + .../github.com/muesli/cancelreader/cancelreader.go | 93 + .../muesli/cancelreader/cancelreader_bsd.go | 146 + .../muesli/cancelreader/cancelreader_default.go | 12 + .../muesli/cancelreader/cancelreader_linux.go | 154 + .../muesli/cancelreader/cancelreader_select.go | 136 + .../muesli/cancelreader/cancelreader_unix.go | 18 + .../muesli/cancelreader/cancelreader_windows.go | 244 ++ vendor/github.com/muesli/termenv/.gitignore | 15 + .../github.com/muesli/termenv/.golangci-soft.yml | 47 + vendor/github.com/muesli/termenv/.golangci.yml | 29 + vendor/github.com/muesli/termenv/LICENSE | 21 + vendor/github.com/muesli/termenv/README.md | 431 +++ vendor/github.com/muesli/termenv/ansi_compat.md | 65 + vendor/github.com/muesli/termenv/ansicolors.go | 281 ++ vendor/github.com/muesli/termenv/color.go | 204 ++ .../github.com/muesli/termenv/constants_linux.go | 8 + .../github.com/muesli/termenv/constants_solaris.go | 8 + vendor/github.com/muesli/termenv/constants_unix.go | 13 + vendor/github.com/muesli/termenv/copy.go | 37 + vendor/github.com/muesli/termenv/hyperlink.go | 11 + vendor/github.com/muesli/termenv/notification.go | 11 + vendor/github.com/muesli/termenv/output.go | 197 ++ vendor/github.com/muesli/termenv/profile.go | 97 + vendor/github.com/muesli/termenv/screen.go | 590 ++++ vendor/github.com/muesli/termenv/style.go | 126 + vendor/github.com/muesli/termenv/templatehelper.go | 86 + vendor/github.com/muesli/termenv/termenv.go | 114 + vendor/github.com/muesli/termenv/termenv_other.go | 30 + vendor/github.com/muesli/termenv/termenv_posix.go | 17 + .../github.com/muesli/termenv/termenv_solaris.go | 22 + vendor/github.com/muesli/termenv/termenv_unix.go | 293 ++ .../github.com/muesli/termenv/termenv_windows.go | 139 + vendor/github.com/rivo/uniseg/LICENSE.txt | 21 + vendor/github.com/rivo/uniseg/README.md | 137 + vendor/github.com/rivo/uniseg/doc.go | 108 + vendor/github.com/rivo/uniseg/eastasianwidth.go | 2588 ++++++++++++++ vendor/github.com/rivo/uniseg/emojipresentation.go | 295 ++ vendor/github.com/rivo/uniseg/gen_breaktest.go | 215 ++ vendor/github.com/rivo/uniseg/gen_properties.go | 261 ++ vendor/github.com/rivo/uniseg/grapheme.go | 331 ++ .../github.com/rivo/uniseg/graphemeproperties.go | 1915 +++++++++++ vendor/github.com/rivo/uniseg/graphemerules.go | 176 + vendor/github.com/rivo/uniseg/line.go | 134 + vendor/github.com/rivo/uniseg/lineproperties.go | 3554 ++++++++++++++++++++ vendor/github.com/rivo/uniseg/linerules.go | 626 ++++ vendor/github.com/rivo/uniseg/properties.go | 208 ++ vendor/github.com/rivo/uniseg/sentence.go | 90 + .../github.com/rivo/uniseg/sentenceproperties.go | 2845 ++++++++++++++++ vendor/github.com/rivo/uniseg/sentencerules.go | 276 ++ vendor/github.com/rivo/uniseg/step.go | 242 ++ vendor/github.com/rivo/uniseg/width.go | 61 + vendor/github.com/rivo/uniseg/word.go | 89 + vendor/github.com/rivo/uniseg/wordproperties.go | 1883 +++++++++++ vendor/github.com/rivo/uniseg/wordrules.go | 282 ++ vendor/golang.org/x/sync/LICENSE | 27 + vendor/golang.org/x/sync/PATENTS | 22 + vendor/golang.org/x/sync/errgroup/errgroup.go | 135 + vendor/golang.org/x/sync/errgroup/go120.go | 13 + vendor/golang.org/x/sync/errgroup/pre_go120.go | 14 + vendor/golang.org/x/sys/unix/ioctl_linux.go | 96 + vendor/golang.org/x/sys/unix/mkerrors.sh | 12 + vendor/golang.org/x/sys/unix/syscall_linux.go | 1 + vendor/golang.org/x/sys/unix/syscall_zos_s390x.go | 104 +- vendor/golang.org/x/sys/unix/zerrors_linux.go | 22 + vendor/golang.org/x/sys/unix/zerrors_linux_386.go | 14 + .../golang.org/x/sys/unix/zerrors_linux_amd64.go | 14 + vendor/golang.org/x/sys/unix/zerrors_linux_arm.go | 14 + .../golang.org/x/sys/unix/zerrors_linux_arm64.go | 14 + .../golang.org/x/sys/unix/zerrors_linux_loong64.go | 14 + vendor/golang.org/x/sys/unix/zerrors_linux_mips.go | 14 + .../golang.org/x/sys/unix/zerrors_linux_mips64.go | 14 + .../x/sys/unix/zerrors_linux_mips64le.go | 14 + .../golang.org/x/sys/unix/zerrors_linux_mipsle.go | 14 + vendor/golang.org/x/sys/unix/zerrors_linux_ppc.go | 14 + .../golang.org/x/sys/unix/zerrors_linux_ppc64.go | 14 + .../golang.org/x/sys/unix/zerrors_linux_ppc64le.go | 14 + .../golang.org/x/sys/unix/zerrors_linux_riscv64.go | 14 + .../golang.org/x/sys/unix/zerrors_linux_s390x.go | 14 + .../golang.org/x/sys/unix/zerrors_linux_sparc64.go | 14 + vendor/golang.org/x/sys/unix/zsyscall_linux.go | 10 + vendor/golang.org/x/sys/unix/ztypes_linux.go | 120 +- vendor/golang.org/x/sys/unix/ztypes_zos_s390x.go | 6 + vendor/golang.org/x/sys/windows/syscall_windows.go | 34 +- vendor/golang.org/x/sys/windows/types_windows.go | 126 + .../golang.org/x/sys/windows/zsyscall_windows.go | 53 + vendor/golang.org/x/text/LICENSE | 27 + vendor/golang.org/x/text/PATENTS | 22 + vendor/golang.org/x/text/transform/transform.go | 709 ++++ vendor/modules.txt | 56 +- 257 files changed, 43101 insertions(+), 34 deletions(-) ``` <details><summary>Agent output (tail)</summary> ``` TODO_DONE: Wiederverwendung bestehender Status-Infrastruktur (`WatchStatus` / `WatchSnapshot`) wo sinnvoll TODO_DONE: Token-/Kosten-Metriken nur anzeigen, wenn sie tatsächlich aus Runner-Output/Telemetry ableitbar sind; sonst als Follow-up kennzeichnen TODO_DONE: `forge agent watch --tui` (oder gleichwertiges Flag) startet eine terminalfüllende TUI TODO_DONE: Queue und Stats aktualisieren sich live mit dem Watcher TODO_DONE: Während eines Agent-Laufs ist die Vollausgabe im Live-Panel sichtbar TODO_DONE: Ohne verfügbare Token/$-Daten stürzt die TUI nicht ab und zeigt „n/a“ TODO_DONE: Hilfe/Wiki dokumentiert Flag, Layout und bekannte Metrik-Limits TODO_DONE: Smoke-Test oder manueller Testplan in PR-Beschreibung PR_TITLE: feat(agent): terminal TUI for forge agent watch (#5) PR_BODY: ## Summary - Adds `forge agent watch --tui`: full-screen split terminal UI with live queue/stats (left) and agent stdout/stderr (right). - Reuses `WatchStatus` / `WatchSnapshot`; token and cost show `n/a` unless the agent prints parseable telemetry. - `--ui` and `--tui` are mutually exclusive; documented in README, `--help`, and the Agent Watcher wiki page. ## Test plan - [x] `go test ./...` and `go vet ./...` - [ ] `forge agent watch --label <ready> --agent claude --pr --tui --dry-run --once` — TUI starts, stats/queue update, no crash without token/cost data - [ ] During a real agent run, verify live output appears in the right panel and auto-follows (`g` to re-enable) - [ ] Press `q` or Ctrl+C — watcher and TUI exit cleanly - [ ] `forge agent watch --ui --tui` — usage error (mutually exclusive) ``` </details>
Author
Owner

☑️ ToDos checked off

  • Arbeitsqueue (wartende Issues) sichtbar und aktualisiert
  • Statusgruppen sinnvoll (z. B. current / queued / done / failed), konsistent mit WatchSnapshot
  • Statistiken soweit verfügbar:
  • Aktueller Agent-Run als Live-Vollausgabe (Debug), scrollbar, auto-follow am Ende
  • Terminalfüllend, Resize-fähig
  • Split-Screen-Layout (mindestens Queue/Stats vs. Live-Output)
  • Aktivierbar über Flag (z. B. --tui) bzw. klar dokumentiertes Default-Verhalten gegenüber --ui / Log-Modus
  • Sauberes Abschalten bei Ctrl+C (Watcher + TUI)
  • Wiederverwendung bestehender Status-Infrastruktur (WatchStatus / WatchSnapshot) wo sinnvoll
  • Token-/Kosten-Metriken nur anzeigen, wenn sie tatsächlich aus Runner-Output/Telemetry ableitbar sind; sonst als Follow-up kennzeichnen
  • forge agent watch --tui (oder gleichwertiges Flag) startet eine terminalfüllende TUI
  • Queue und Stats aktualisieren sich live mit dem Watcher
  • Während eines Agent-Laufs ist die Vollausgabe im Live-Panel sichtbar
  • Ohne verfügbare Token/$-Daten stürzt die TUI nicht ab und zeigt „n/a“
  • Hilfe/Wiki dokumentiert Flag, Layout und bekannte Metrik-Limits
  • Smoke-Test oder manueller Testplan in PR-Beschreibung
☑️ **ToDos checked off** - [x] Arbeitsqueue (wartende Issues) sichtbar und aktualisiert - [x] Statusgruppen sinnvoll (z. B. current / queued / done / failed), konsistent mit `WatchSnapshot` - [x] Statistiken soweit verfügbar: - [x] Aktueller Agent-Run als Live-Vollausgabe (Debug), scrollbar, auto-follow am Ende - [x] Terminalfüllend, Resize-fähig - [x] Split-Screen-Layout (mindestens Queue/Stats vs. Live-Output) - [x] Aktivierbar über Flag (z. B. `--tui`) bzw. klar dokumentiertes Default-Verhalten gegenüber `--ui` / Log-Modus - [x] Sauberes Abschalten bei Ctrl+C (Watcher + TUI) - [x] Wiederverwendung bestehender Status-Infrastruktur (`WatchStatus` / `WatchSnapshot`) wo sinnvoll - [x] Token-/Kosten-Metriken nur anzeigen, wenn sie tatsächlich aus Runner-Output/Telemetry ableitbar sind; sonst als Follow-up kennzeichnen - [x] `forge agent watch --tui` (oder gleichwertiges Flag) startet eine terminalfüllende TUI - [x] Queue und Stats aktualisieren sich live mit dem Watcher - [x] Während eines Agent-Laufs ist die Vollausgabe im Live-Panel sichtbar - [x] Ohne verfügbare Token/$-Daten stürzt die TUI nicht ab und zeigt „n/a“ - [x] Hilfe/Wiki dokumentiert Flag, Layout und bekannte Metrik-Limits - [x] Smoke-Test oder manueller Testplan in PR-Beschreibung
frank merged commit 6cb8ea0ecb into main 2026-07-12 10:05:59 +02:00
frank deleted branch agent/issue-5-agent-terminalfüllende-tui-für-forge-a 2026-07-12 12:06:53 +02:00
Sign in to join this conversation.
No reviewers
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
frank/forgecli!7
No description provided.