From 71d7a14b18d48ef9ebf1e0d6a9c897f88cf53a74 Mon Sep 17 00:00:00 2001 From: scutifer Date: Sun, 1 Feb 2026 13:50:58 +0530 Subject: [PATCH] feat(coding-agent): add a spinner extension (#1131) When the agent is running, we prefix an animated braille spinner to the title to show busy state. Its cleared when the agent is done --- packages/coding-agent/CHANGELOG.md | 4 ++ .../examples/extensions/README.md | 1 + .../examples/extensions/titlebar-spinner.ts | 58 +++++++++++++++++++ 3 files changed, 63 insertions(+) create mode 100644 packages/coding-agent/examples/extensions/titlebar-spinner.ts diff --git a/packages/coding-agent/CHANGELOG.md b/packages/coding-agent/CHANGELOG.md index fac98476..e4b5f94d 100644 --- a/packages/coding-agent/CHANGELOG.md +++ b/packages/coding-agent/CHANGELOG.md @@ -2,6 +2,10 @@ ## [Unreleased] +### Added + +- Added `titlebar-spinner.ts` example extension that shows a braille spinner animation in the terminal title while the agent is working. + ## [0.50.8] - 2026-02-01 ### Added diff --git a/packages/coding-agent/examples/extensions/README.md b/packages/coding-agent/examples/extensions/README.md index 65de402a..c1011c39 100644 --- a/packages/coding-agent/examples/extensions/README.md +++ b/packages/coding-agent/examples/extensions/README.md @@ -56,6 +56,7 @@ cp permission-gate.ts ~/.pi/agent/extensions/ | `modal-editor.ts` | Custom vim-like modal editor via `ctx.ui.setEditorComponent()` | | `rainbow-editor.ts` | Animated rainbow text effect via custom editor | | `notify.ts` | Desktop notifications via OSC 777 when agent finishes (Ghostty, iTerm2, WezTerm) | +| `titlebar-spinner.ts` | Braille spinner animation in terminal title while the agent is working | | `summarize.ts` | Summarize conversation with GPT-5.2 and show in transient UI | | `custom-footer.ts` | Custom footer with git branch and token stats via `ctx.ui.setFooter()` | | `custom-header.ts` | Custom header via `ctx.ui.setHeader()` | diff --git a/packages/coding-agent/examples/extensions/titlebar-spinner.ts b/packages/coding-agent/examples/extensions/titlebar-spinner.ts new file mode 100644 index 00000000..728c4d17 --- /dev/null +++ b/packages/coding-agent/examples/extensions/titlebar-spinner.ts @@ -0,0 +1,58 @@ +/** + * Titlebar Spinner Extension + * + * Shows a braille spinner animation in the terminal title while the agent is working. + * Uses `ctx.ui.setTitle()` to update the terminal title via the extension API. + * + * Usage: + * pi --extension examples/extensions/titlebar-spinner.ts + */ + +import type { ExtensionAPI, ExtensionContext } from "@mariozechner/pi-coding-agent"; +import path from "node:path"; + +const BRAILLE_FRAMES = ["⠋", "⠙", "⠹", "⠸", "⠼", "⠴", "⠦", "⠧", "⠇", "⠏"]; + +function getBaseTitle(pi: ExtensionAPI): string { + const cwd = path.basename(process.cwd()); + const session = pi.getSessionName(); + return session ? `π - ${session} - ${cwd}` : `π - ${cwd}`; +} + +export default function (pi: ExtensionAPI) { + let timer: ReturnType | null = null; + let frameIndex = 0; + + function stopAnimation(ctx: ExtensionContext) { + if (timer) { + clearInterval(timer); + timer = null; + } + frameIndex = 0; + ctx.ui.setTitle(getBaseTitle(pi)); + } + + function startAnimation(ctx: ExtensionContext) { + stopAnimation(ctx); + timer = setInterval(() => { + const frame = BRAILLE_FRAMES[frameIndex % BRAILLE_FRAMES.length]; + const cwd = path.basename(process.cwd()); + const session = pi.getSessionName(); + const title = session ? `${frame} π - ${session} - ${cwd}` : `${frame} π - ${cwd}`; + ctx.ui.setTitle(title); + frameIndex++; + }, 80); + } + + pi.on("agent_start", async (_event, ctx) => { + startAnimation(ctx); + }); + + pi.on("agent_end", async (_event, ctx) => { + stopAnimation(ctx); + }); + + pi.on("session_shutdown", async (_event, ctx) => { + stopAnimation(ctx); + }); +}