pi-cockpit 0.17.0 → 0.18.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -35,7 +35,7 @@ pi -e ./packages/pi-cockpit
35
35
  - **SIDEBAR** — Workflow Session/Run progress, Goal state and budget, Todo tasks, Teammate roster, background jobs, and read-only Team Swarm progress. Empty sections disappear and constrained heights retain current or failed work before secondary detail.
36
36
  - **AGENTS** — every running teammate as a table row (status spinner · role · id · label · live tail), sorted running-first. Completed/failed agents show their total duration. On narrow terminals this returns to the below-editor widget.
37
37
  - **TODO** — the active plan as numbered rows with four states (done ✓ / in-progress spinner / blocked ! / pending ·). On narrow terminals this returns to the above-editor widget.
38
- - **Footer** — `provider/model · context gauge · ↑in ↓out · $cost · elapsed · git branch`. `bash_bg` background-job state lives on a **dedicated second footer row** so it no longer competes with the primary line.
38
+ - **Footer** — `provider/model · context gauge · ↑in ↓out · $cost · elapsed · git branch`. `bash_bg` background-job state lives on a **dedicated second footer row** so it no longer competes with the primary line. **Usage bars** (quota/balance/spend for the active provider, ported from `hknet/pi-usage-bars`) live on their own footer line when `usage.footer` is on — e.g. `Codex 5h [████░░░░] 42% · W [██░░░░░░] 25% · $20.00`.
39
39
  - **Thinking timer** — while the model is thinking, the folded thinking row shows a spinner and running elapsed time; when the run ends, it settles to the actual duration (e.g. `thoughts · 8.4s`).
40
40
  - **Quiet mode** — compresses the seven built-in tool calls (read/bash/edit/write/grep/find/ls) into single-line ✓/✗/⋯ summaries and folds thinking blocks. Two glyph sets available: `check` (✓/✗/⋯) and `dot` (●/○/◌). Toggle with `/cockpit quiet`; turning off requires `/reload` to restore native tool renderers.
41
41
 
@@ -49,6 +49,7 @@ Toggle each block between list and compact with `/cockpit`.
49
49
  | AGENTS | `pi.events` channels `teammate:started` / `teammate:message` / `teammate:complete`, broadcast by **pi-maestro-teammate** | **No** — without that extension no events fire, the block stays hidden |
50
50
  | TODO | the `todo-state` snapshot the **pi-maestro-flow** `todo` tool persists after every mutation (re-read on each `tool_execution_end` and on `session_start`) | **No** — without the `todo` tool the block stays hidden |
51
51
  | Footer | `ctx.model`, `ctx.getContextUsage()`, session usage totals, `footerData.getGitBranch()` | **Yes** |
52
+ | Usage bars | the active provider's quota/balance/spend fetched directly from each provider's usage API, resolved through `ctx.modelRegistry.getProviderAuth`/`getProviderAuthStatus` (Codex, Claude, ZAI×2, Kimi, MiniMax×2, OpenRouter, DeepSeek, Moonshot×2); the `/usage` overlay's per-provider 7-day token trend additionally reads the `pi-maestro-flow` usage-history JSONL store at `~/.pi/agent/usage-history` | **Yes** — quota/balance/spend on bare Pi (no credentials → renders nothing); the 7-day trend needs `pi-maestro-flow` to have recorded turns |
52
53
 
53
54
  So on a stock Pi the extension loads without error, the Maestro sections stay empty, and the footer remains available. The roster is **self-accumulated from event deltas**; Todo is back-filled from the latest durable `todo-state`. Workflow, Goal, and Swarm use a versioned full-replacement snapshot with generation fencing and a query path for cold-start recovery.
54
55
 
@@ -84,7 +85,14 @@ Cockpit has no package dependency on `pi-maestro-flow`. It observes optional pro
84
85
  "showMaestro": false,
85
86
  "maxLength": 80
86
87
  },
87
- "theme": ""
88
+ "theme": "",
89
+ "usage": {
90
+ "enabled": true,
91
+ "footer": true,
92
+ "pollIntervalMs": 120000,
93
+ "barWidth": 8,
94
+ "commandKey": "usage"
95
+ }
88
96
  }
89
97
  ```
90
98
 
@@ -110,9 +118,16 @@ Cockpit has no package dependency on `pi-maestro-flow`. It observes optional pro
110
118
 
111
119
  The tab title is `frame + pi - <session> - <working state>`. The session part follows Claude Code's chain (`sessionTitle ?? agentTitle ?? haikuTitle ?? default`): the `/session name` title wins, otherwise the generated title, otherwise a short session id. The frame is Claude Code's title chrome: `⠂`/`⠐` braille spinner while a turn runs, static `✳` when idle; failure replaces it with `✗`. On quit, Cockpit clears the title so no stale tab label lingers (Claude Code's `CLEAR_TERMINAL_TITLE`).
112
120
  - `theme`: named theme override; empty string follows the Pi session theme.
121
+ - `usage.enabled`: master switch for the usage bars (quota, balance, spend). On by default; off hides the footer segment and disables the `/usage` command. Ports the [`hknet/pi-usage-bars`](https://github.com/hknet/pi-usage-bars) extension.
122
+ - `usage.footer`: when `true`, render the live quota bar on a dedicated footer line. The `/usage` command works regardless of this toggle. On by default.
123
+ - `usage.pollIntervalMs`: how often to refresh usage data, in milliseconds. Clamped to `30000`..`1800000` (30s..30min). Default `120000` (2min). Lower values hit provider APIs more often.
124
+ - `usage.barWidth`: characters per quota bar in the footer. Clamped to `4`..`16`. Default `8`.
125
+ - `usage.commandKey`: the `/`-command that opens the usage selector overlay. Default `"usage"`. Requires `/reload` to take effect (commands register at session start).
113
126
 
114
127
  ## Commands
115
128
 
129
+ > **macOS:** every `Alt+…` shortcut is the **option** key, and the hints render as `Option+…` there. The terminal has to deliver option as Meta or the keystroke inserts a character instead of firing the shortcut — iTerm2: *Profiles → Keys → Left/Right Option key → `Esc+`*; Terminal.app: *Settings → Profiles → Keyboard → Use Option as Meta key*. The registered binding is `alt+…` on every platform; only its name changes.
130
+
116
131
  - `/cockpit` — opens the settings overlay.
117
132
  - `/maestro-settings` — opens the unified settings shell (Cockpit, Flow, Teammate and integrations).
118
133
  - `Alt+J` — opens the background Bash jobs overlay (live status, command, cwd, duration, output tail).
@@ -121,6 +136,7 @@ The tab title is `frame + pi - <session> - <working state>`. The session part fo
121
136
  - `/cockpit sidebar auto|on|off` — selects dock behavior.
122
137
  - `/cockpit sidebar resize` or `Ctrl+Shift+R` — enters temporary Resize mode. Left/Right adjusts one column, Shift+Left/Shift+Right adjusts four, Enter accepts, and Escape rolls back. Mouse reporting is active only during Resize mode.
123
138
  - `/cockpit quiet` — toggles quiet mode; `/cockpit bg` shows background jobs.
139
+ - `/usage` — opens the usage selector overlay: quota, balance, and spend for every configured provider, with the active one marked `✓`. Search filters by name; arrows/`j`/`k` move, Enter expands the selected provider, Esc closes. Expanding a provider also shows its **7-day token trend** — a sparkline of daily token usage, a `total tok · $cost · turns/day` summary, and the top 2 models by token share — read from the optional `pi-maestro-flow` usage-history store (`~/.pi/agent/usage-history`), so it appears once that extension has recorded turns and is omitted on bare Pi. The command key is configurable via `usage.commandKey` (default `"usage"`, requires `/reload`). Disabled while `usage.enabled` is off.
124
140
  - `/theme` — switch theme with live preview; `/theme <name>` applies directly. `cockpit-zen` is the restrained warm-gold theme designed for the Zen stack; selecting it does not change `stackStyle`. Pi ships no standalone theme command; cockpit provides one.
125
141
 
126
142
  ## Sidebar compatibility
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pi-maestro-settings-core",
3
- "version": "0.2.0",
3
+ "version": "0.2.1",
4
4
  "description": "Versioned Settings and i18n contracts shared by Pi Maestro plugins.",
5
5
  "type": "module",
6
6
  "engines": {
@@ -193,3 +193,39 @@ export function checkCatalogCompleteness(
193
193
  issues,
194
194
  };
195
195
  }
196
+
197
+ /**
198
+ * What to call the modifier that terminals deliver as Meta, on this platform.
199
+ *
200
+ * Every `alt+…` shortcut this product registers is delivered by the key macOS
201
+ * labels **option** — there is no key called Alt on a Mac keyboard, so a hint
202
+ * reading `Alt+R` sends a Mac user looking for a key that is not there. The
203
+ * binding is unchanged and stays `alt+…`; only its name differs.
204
+ *
205
+ * Lives beside the locale helpers because it answers the same question they do
206
+ * — what to show this user for a fixed underlying value — and both packages
207
+ * that render shortcut hints already depend on this module. The axis is the
208
+ * platform rather than the locale, so it is a separate function rather than a
209
+ * catalog entry: the label is identical in every language.
210
+ *
211
+ * `⌥` is deliberately not used: U+2325 is East-Asian Ambiguous, so a terminal
212
+ * rendering the zh-CN locale may give it two columns and break hint widths this
213
+ * product computes.
214
+ *
215
+ * @param platform - platform to name the modifier for; defaults to the running one.
216
+ * @returns `Option` on macOS, `Alt` everywhere else.
217
+ */
218
+ export function altModifierLabel(platform: string = process.platform): string {
219
+ return platform === "darwin" ? "Option" : "Alt";
220
+ }
221
+
222
+ /**
223
+ * Name one `alt+…` shortcut the way this platform's keyboard labels it.
224
+ *
225
+ * @param key - the rest of the chord, such as `R` or `Shift+P`.
226
+ * @param platform - platform to name it for; defaults to the running one.
227
+ * @returns the hint text, e.g. `Option+R` on macOS and `Alt+R` elsewhere.
228
+ */
229
+ export function altKey(key: string, platform?: string): string {
230
+ return `${altModifierLabel(platform ?? process.platform)}+${key}`;
231
+ }
package/package.json CHANGED
@@ -1,85 +1,85 @@
1
- {
2
- "name": "pi-cockpit",
3
- "version": "0.17.0",
4
- "description": "Responsive Maestro operations sidebar, fallback status widgets, and footer for Pi.",
5
- "type": "module",
6
- "keywords": [
7
- "pi-package",
8
- "pi",
9
- "pi-extension",
10
- "tui",
11
- "teammate",
12
- "todo"
13
- ],
14
- "license": "MIT",
15
- "files": [
16
- "src/",
17
- "themes/",
18
- "README.md"
19
- ],
20
- "scripts": {
21
- "test": "node --test --experimental-transform-types tests/config.test.ts tests/public-events.test.ts tests/maestro-store.test.ts tests/split-pane.test.ts tests/editor-bottom.test.ts tests/sidebar-render.test.ts tests/sidebar-controller.test.ts tests/viewport-stability.test.ts tests/quiet-tools.test.ts tests/edit-guard.test.ts tests/agents-store.test.ts tests/endpoint-store.test.ts tests/session-ui-state.test.ts tests/session-tabs.test.ts tests/agent-bar.test.ts tests/supervision-store.test.ts tests/bash-bg-store.test.ts tests/bash-bg-widget.test.ts tests/bash-bg-overlay.test.ts tests/todo-overlay.test.ts tests/agent-overlay.test.ts tests/todo-store.test.ts tests/render.test.ts tests/agent-scroll.test.ts tests/session-bar.test.ts tests/session-detail.test.ts tests/footer.test.ts tests/extension-status.test.ts tests/input-routing.test.ts tests/input-history-store.test.ts tests/unified-editor.test.ts tests/integration-contract.test.ts tests/stack-widget.test.ts tests/zen-render.test.ts tests/zen-browse.test.ts tests/zen-sheet.test.ts tests/settings-view.test.ts tests/thinking-fold.test.ts tests/thinking-timer.test.ts tests/tick-policy.test.ts tests/ambient.test.ts tests/viewport.test.ts tests/theme-picker.test.ts tests/model-picker.test.ts tests/title-gen.test.ts tests/title-llm.test.ts tests/settings-registry.test.ts tests/settings-coordinator.test.ts tests/settings-locale.test.ts tests/tui-i18n.test.ts tests/settings-shell.test.ts tests/settings-cockpit-provider.test.ts tests/settings-cross-package.test.ts tests/ui-primitives.test.ts tests/settings-shell-secret.test.ts tests/settings-shell-listcrud.test.ts tests/capturing-overlay.test.ts tests/claude-editor.test.ts tests/fullscreen-controller.test.ts tests/transcript-selection.test.ts tests/terminal-cleanup.test.ts tests/terminal-capability.test.ts",
22
- "typecheck": "tsc --noEmit",
23
- "prepack": "node ../../scripts/bundle-settings-core.mjs",
24
- "postpack": "node ../../scripts/bundle-settings-core.mjs --clean"
25
- },
26
- "pi": {
27
- "extensions": [
28
- "./src/extension/index.ts"
29
- ],
30
- "themes": [
31
- "./themes"
32
- ]
33
- },
34
- "dependencies": {
35
- "pi-maestro-settings-core": "0.2.0",
36
- "proper-lockfile": "4.1.2"
37
- },
38
- "bundledDependencies": [
39
- "pi-maestro-settings-core"
40
- ],
41
- "peerDependencies": {
42
- "@earendil-works/pi-agent-core": "*",
43
- "@earendil-works/pi-ai": "*",
44
- "@earendil-works/pi-coding-agent": "*",
45
- "@earendil-works/pi-tui": "*",
46
- "pi-maestro-teammate": "^2.0.0",
47
- "typebox": "*"
48
- },
49
- "peerDependenciesMeta": {
50
- "@earendil-works/pi-agent-core": {
51
- "optional": true
52
- },
53
- "@earendil-works/pi-ai": {
54
- "optional": true
55
- },
56
- "@earendil-works/pi-coding-agent": {
57
- "optional": true
58
- },
59
- "@earendil-works/pi-tui": {
60
- "optional": true
61
- },
62
- "pi-maestro-teammate": {
63
- "optional": true
64
- },
65
- "typebox": {
66
- "optional": true
67
- }
68
- },
69
- "devDependencies": {
70
- "@earendil-works/pi-agent-core": "0.83.0",
71
- "@earendil-works/pi-ai": "0.83.0",
72
- "@earendil-works/pi-coding-agent": "0.83.0",
73
- "@earendil-works/pi-tui": "0.83.0",
74
- "@types/node": "^22.0.0",
75
- "pi-maestro-teammate": "2.0.0",
76
- "typebox": "1.3.7",
77
- "typescript": "^5.5.0"
78
- },
79
- "main": "./src/index.ts",
80
- "exports": {
81
- ".": "./src/index.ts",
82
- "./v1/events": "./src/public/v1/events.ts",
83
- "./src/*": "./src/*"
84
- }
85
- }
1
+ {
2
+ "name": "pi-cockpit",
3
+ "version": "0.18.0",
4
+ "description": "Responsive Maestro operations sidebar, fallback status widgets, and footer for Pi.",
5
+ "type": "module",
6
+ "keywords": [
7
+ "pi-package",
8
+ "pi",
9
+ "pi-extension",
10
+ "tui",
11
+ "teammate",
12
+ "todo"
13
+ ],
14
+ "license": "MIT",
15
+ "files": [
16
+ "src/",
17
+ "themes/",
18
+ "README.md"
19
+ ],
20
+ "scripts": {
21
+ "test": "node --test --experimental-transform-types tests/config.test.ts tests/public-events.test.ts tests/maestro-store.test.ts tests/split-pane.test.ts tests/editor-bottom.test.ts tests/sidebar-render.test.ts tests/sidebar-controller.test.ts tests/viewport-stability.test.ts tests/quiet-tools.test.ts tests/edit-guard.test.ts tests/agents-store.test.ts tests/endpoint-store.test.ts tests/session-ui-state.test.ts tests/session-tabs.test.ts tests/agent-bar.test.ts tests/supervision-store.test.ts tests/bash-bg-store.test.ts tests/bash-bg-widget.test.ts tests/bash-bg-overlay.test.ts tests/todo-overlay.test.ts tests/agent-overlay.test.ts tests/todo-store.test.ts tests/render.test.ts tests/agent-scroll.test.ts tests/session-bar.test.ts tests/session-detail.test.ts tests/footer.test.ts tests/extension-status.test.ts tests/teammate-message.test.ts tests/input-routing.test.ts tests/input-history-store.test.ts tests/unified-editor.test.ts tests/integration-contract.test.ts tests/stack-widget.test.ts tests/zen-render.test.ts tests/zen-browse.test.ts tests/zen-sheet.test.ts tests/settings-view.test.ts tests/thinking-fold.test.ts tests/thinking-timer.test.ts tests/tick-policy.test.ts tests/ambient.test.ts tests/viewport.test.ts tests/theme-picker.test.ts tests/model-picker.test.ts tests/title-gen.test.ts tests/title-llm.test.ts tests/settings-registry.test.ts tests/settings-coordinator.test.ts tests/settings-locale.test.ts tests/tui-i18n.test.ts tests/settings-shell.test.ts tests/settings-cockpit-provider.test.ts tests/settings-cross-package.test.ts tests/ui-primitives.test.ts tests/settings-shell-secret.test.ts tests/settings-shell-listcrud.test.ts tests/capturing-overlay.test.ts tests/claude-editor.test.ts tests/fullscreen-controller.test.ts tests/transcript-selection.test.ts tests/terminal-cleanup.test.ts tests/terminal-capability.test.ts tests/usage-core.test.ts tests/usage-extension.test.ts tests/usage-history.test.ts tests/usage-sparkline.test.ts",
22
+ "typecheck": "tsc --noEmit",
23
+ "prepack": "node ../../scripts/bundle-settings-core.mjs",
24
+ "postpack": "node ../../scripts/bundle-settings-core.mjs --clean"
25
+ },
26
+ "pi": {
27
+ "extensions": [
28
+ "./src/extension/index.ts"
29
+ ],
30
+ "themes": [
31
+ "./themes"
32
+ ]
33
+ },
34
+ "dependencies": {
35
+ "pi-maestro-settings-core": "0.2.1",
36
+ "proper-lockfile": "4.1.2"
37
+ },
38
+ "bundledDependencies": [
39
+ "pi-maestro-settings-core"
40
+ ],
41
+ "peerDependencies": {
42
+ "@earendil-works/pi-agent-core": "*",
43
+ "@earendil-works/pi-ai": "*",
44
+ "@earendil-works/pi-coding-agent": "*",
45
+ "@earendil-works/pi-tui": "*",
46
+ "pi-maestro-teammate": "^2.1.0",
47
+ "typebox": "*"
48
+ },
49
+ "peerDependenciesMeta": {
50
+ "@earendil-works/pi-agent-core": {
51
+ "optional": true
52
+ },
53
+ "@earendil-works/pi-ai": {
54
+ "optional": true
55
+ },
56
+ "@earendil-works/pi-coding-agent": {
57
+ "optional": true
58
+ },
59
+ "@earendil-works/pi-tui": {
60
+ "optional": true
61
+ },
62
+ "pi-maestro-teammate": {
63
+ "optional": true
64
+ },
65
+ "typebox": {
66
+ "optional": true
67
+ }
68
+ },
69
+ "devDependencies": {
70
+ "@earendil-works/pi-agent-core": "0.83.0",
71
+ "@earendil-works/pi-ai": "0.83.0",
72
+ "@earendil-works/pi-coding-agent": "0.83.0",
73
+ "@earendil-works/pi-tui": "0.83.0",
74
+ "@types/node": "^22.0.0",
75
+ "pi-maestro-teammate": "2.1.0",
76
+ "typebox": "1.3.7",
77
+ "typescript": "^5.5.0"
78
+ },
79
+ "main": "./src/index.ts",
80
+ "exports": {
81
+ ".": "./src/index.ts",
82
+ "./v1/events": "./src/public/v1/events.ts",
83
+ "./src/*": "./src/*"
84
+ }
85
+ }
package/src/agent-bar.ts CHANGED
@@ -12,7 +12,7 @@ import { formatAgentMetric } from "./render.ts";
12
12
  import type { SessionUiState } from "./session-ui-state.ts";
13
13
  import { formatUnreadCount, type SessionTab } from "./session-tabs.ts";
14
14
  import type { AgentRow } from "./types.ts";
15
- import { effectiveAgentStatus, type AgentDisplayStatus } from "./agents-store.ts";
15
+ import { effectiveAgentStatus, isCliAgent, type AgentDisplayStatus } from "./agents-store.ts";
16
16
  import { visibleAgentRows } from "./stack-widget.ts";
17
17
  import { tuiT } from "./tui-i18n.ts";
18
18
 
@@ -99,8 +99,10 @@ function chip(
99
99
  activity?: string,
100
100
  attention = false,
101
101
  outcome?: { status: "completed" | "failed" | "terminated"; message?: string },
102
+ cli = false,
102
103
  ): string {
103
104
  const text = `@${label}`;
105
+ const cliBadge = cli ? theme.fg("accent", ` ${tuiT("widget.agent.cli")}`) : "";
104
106
  const badge = unread > 0 ? theme.fg("warning", ` •${formatUnreadCount(unread)}`) : "";
105
107
  const activitySuffix = activity ? theme.fg("dim", ` · ${activity}`) : "";
106
108
  const attentionPrefix = attention ? theme.fg("error", "!") : "";
@@ -112,8 +114,8 @@ function chip(
112
114
  : theme.fg("success", " ✓")
113
115
  : "";
114
116
  return active
115
- ? `${attentionPrefix}${theme.fg(color, "▸")} ${theme.fg(color, theme.bold(text))}${outcomeSuffix}${activitySuffix}${badge}`
116
- : `${attentionPrefix}${theme.fg(color, text)}${outcomeSuffix}${activitySuffix}${badge}`;
117
+ ? `${attentionPrefix}${theme.fg(color, "▸")} ${theme.fg(color, theme.bold(text))}${cliBadge}${outcomeSuffix}${activitySuffix}${badge}`
118
+ : `${attentionPrefix}${theme.fg(color, text)}${cliBadge}${outcomeSuffix}${activitySuffix}${badge}`;
117
119
  }
118
120
 
119
121
  export type AgentBarStatus = AgentDisplayStatus | "idle";
@@ -128,6 +130,8 @@ interface AgentBarTab extends SessionTab {
128
130
  attention?: boolean;
129
131
  /** Terminal outcome badge: ✓ completed, ✗ failed (with reason) or terminated. */
130
132
  outcome?: { status: "completed" | "failed" | "terminated"; message?: string };
133
+ /** External CLI backend (ACP `cli/<tool>` route): shown as an accent badge after the label. */
134
+ cli?: boolean;
131
135
  }
132
136
 
133
137
  function endpointStatus(endpoint: CockpitEndpoint, now: number, mainRunning: boolean): AgentBarStatus {
@@ -177,6 +181,7 @@ function renderAgentChipLine(tabs: AgentBarTab[], selectedId: string, width: num
177
181
  tab.outcome
178
182
  ? { status: tab.outcome.status, message: tab.outcome.message ? truncateToWidth(tab.outcome.message, 24, "…") : undefined }
179
183
  : undefined,
184
+ tab.cli,
180
185
  ));
181
186
  const chipWidths = chips.map((text) => visibleWidth(text));
182
187
  const sepWidth = visibleWidth(CHIP_SEPARATOR);
@@ -281,6 +286,7 @@ export function renderAgentBar(
281
286
  : {}),
282
287
  ...(status === "stalled" ? { attention: true } : {}),
283
288
  ...(outcome ? { outcome } : {}),
289
+ ...(endpoint.agentRow && isCliAgent(endpoint.agentRow) ? { cli: true } : {}),
284
290
  };
285
291
  });
286
292
  // Selected-session metrics summary, appended only when the chip line leaves
@@ -9,7 +9,7 @@ import {
9
9
  truncateToWidth,
10
10
  visibleWidth,
11
11
  } from "@earendil-works/pi-tui";
12
- import { effectiveAgentStatus, isExpertLeader, type AgentDisplayStatus } from "./agents-store.ts";
12
+ import { effectiveAgentStatus, isCliAgent, isExpertLeader, type AgentDisplayStatus } from "./agents-store.ts";
13
13
  import { scrollBy, type AgentScrollState } from "./agent-scroll.ts";
14
14
  import type { IconGlyphs } from "./icons.ts";
15
15
  import { visibleStart } from "./layout.ts";
@@ -454,8 +454,11 @@ export class AgentOverlay implements Component, Focusable {
454
454
  const expertTag = isExpertLeader(row)
455
455
  ? `${this.params.theme.fg("accent", tuiT("widget.agent.expert"))} `
456
456
  : "";
457
+ const cliTag = isCliAgent(row)
458
+ ? `${this.params.theme.fg("accent", tuiT("widget.agent.cli"))} `
459
+ : "";
457
460
  return fit(
458
- `${prefix}${marker} ${this.params.theme.fg(visual.color, visual.glyph)} ${expertTag}${this.params.theme.bold(agentLabel(row))}${task}`,
461
+ `${prefix}${marker} ${this.params.theme.fg(visual.color, visual.glyph)} ${expertTag}${cliTag}${this.params.theme.bold(agentLabel(row))}${task}`,
459
462
  width,
460
463
  );
461
464
  });