feat(tui): add scriptable statusline command to the footer#2043
feat(tui): add scriptable statusline command to the footer#2043yichensunjoe wants to merge 1 commit into
Conversation
Add an opt-in [statusline] section to tui.toml (command / interval_ms / timeout_ms). When configured, the TUI runs the command periodically with the session context (session id, version, model, working directory, permission mode, plan mode, context token usage) as JSON on stdin, and renders the first stdout line — ANSI SGR colors passed through — as a third footer line. An empty command disables the feature (the default); failed or timed-out runs silently keep the last successful output, and nothing is rendered before the first success. /reload-tui picks up config changes. Refs MoonshotAI#1954
🦋 Changeset detectedLatest commit: be0805d The changes in this PR will be included in the next version bump. This PR includes changesets to release 1 package
Not sure what this means? Click here to learn what changesets are. Click here if you're a maintainer who wants to add another changeset to this PR |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: be0805dab7
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| stop(): void { | ||
| this.generation += 1; | ||
| if (this.timer !== null) { | ||
| clearInterval(this.timer); | ||
| this.timer = null; | ||
| } | ||
| } |
There was a problem hiding this comment.
Kill in-flight statusline commands on stop
When the user exits or /reload-tui disables/replaces a slow statusline, stop() only clears the interval and advances the generation; it does not signal the child spawned by the already-running runOnce(). runShell ultimately calls process.exit() after KimiTUI.stop(), so that child (for example sleep 60 or a slow helper) is orphaned and can keep running after the CLI has exited. Keep a handle to the active process/process group and terminate it from stop().
Useful? React with 👍 / 👎.
| const timeout = setTimeout(() => { | ||
| proc.kill('SIGTERM'); | ||
| const killTimer = setTimeout(() => { | ||
| proc.kill('SIGKILL'); | ||
| }, KILL_GRACE_MS); |
There was a problem hiding this comment.
Kill the whole statusline command tree on timeout
When a configured command times out after spawning a child through the shell (for example sleep 60, a pipeline, or python script.py), these proc.kill() calls target only the /bin/sh -c process created by shell: true; the actual child is left running while the runner settles and schedules the next interval. This can accumulate orphaned helpers every interval_ms for any statusline that repeatedly times out, so start the command in a process group and kill the group, or otherwise track and terminate children, before settling.
Useful? React with 👍 / 👎.
Related Issue
Resolve #1954
Problem
See linked issue. Users want a Claude Code-style, scriptable status line in the
TUI footer instead of requesting individual built-in segments one by one.
What changed
[statusline]section intui.toml:command(empty = disabled, the default),interval_ms(default 2000,min 300),
timeout_ms(default 5000).StatusLineRunnerexecutes the command via the shell, passes asession-context JSON on stdin (field names follow Claude Code's statusline
contract — model.display_name, workspace.current_dir, context tokens,
permission/plan mode, session id, version — so community scripts port over),
enforces the timeout (SIGTERM → SIGKILL), caps stdout at 64 KiB, keeps the
first line, and preserves the last successful output on failure.
sequences through and truncating to width. Nothing renders until the first
successful run.
/reload-tuiapplies config changes live; the runner lifecycle is tied tothe footer;
saveTuiConfigpreserves the new section.Docs (en/zh) and changeset (minor) included.
Checklist