@pi-unipi/unipi 2.6.0 → 2.6.2

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.
Files changed (205) hide show
  1. package/CHANGELOG.md +19 -0
  2. package/package.json +21 -22
  3. package/packages/ask-user/package.json +2 -2
  4. package/packages/ask-user/settings-tui.ts +18 -34
  5. package/packages/autocomplete/package.json +1 -1
  6. package/packages/autocomplete/src/constants.ts +2 -15
  7. package/packages/autocomplete/src/provider.ts +3 -17
  8. package/packages/btw/extensions/btw.ts +18 -45
  9. package/packages/btw/package.json +2 -2
  10. package/packages/compactor/README.md +2 -2
  11. package/packages/compactor/package.json +3 -3
  12. package/packages/compactor/skills/compactor/SKILL.md +1 -1
  13. package/packages/compactor/skills/compactor-detail/SKILL.md +3 -5
  14. package/packages/compactor/skills/compactor-doctor/SKILL.md +1 -1
  15. package/packages/compactor/skills/compactor-stats/SKILL.md +1 -1
  16. package/packages/compactor/src/commands/index.ts +47 -78
  17. package/packages/compactor/src/compaction/brief.ts +161 -90
  18. package/packages/compactor/src/compaction/build-sections.ts +3 -4
  19. package/packages/compactor/src/compaction/compact-args.ts +86 -0
  20. package/packages/compactor/src/compaction/cut.ts +270 -28
  21. package/packages/compactor/src/compaction/drill-down.ts +261 -0
  22. package/packages/compactor/src/compaction/format-recall.ts +96 -0
  23. package/packages/compactor/src/compaction/format.ts +8 -3
  24. package/packages/compactor/src/compaction/hooks.ts +248 -72
  25. package/packages/compactor/src/compaction/merge.ts +34 -4
  26. package/packages/compactor/src/compaction/rank.ts +270 -0
  27. package/packages/compactor/src/compaction/recall-scope.ts +28 -0
  28. package/packages/compactor/src/compaction/search-entries.ts +333 -96
  29. package/packages/compactor/src/compaction/skill-collapse.ts +35 -0
  30. package/packages/compactor/src/compaction/summarize.ts +37 -6
  31. package/packages/compactor/src/compaction/token-estimate.ts +104 -0
  32. package/packages/compactor/src/compaction/touched-files.ts +35 -0
  33. package/packages/compactor/src/config/manager.ts +2 -27
  34. package/packages/compactor/src/config/presets.ts +0 -2
  35. package/packages/compactor/src/config/schema.ts +2 -16
  36. package/packages/compactor/src/executor/executor.ts +6 -15
  37. package/packages/compactor/src/executor/runtime.ts +2 -12
  38. package/packages/compactor/src/index.ts +4 -121
  39. package/packages/compactor/src/info-screen.ts +3 -10
  40. package/packages/compactor/src/security/evaluator.ts +0 -53
  41. package/packages/compactor/src/security/policy.ts +7 -8
  42. package/packages/compactor/src/session/db.ts +0 -6
  43. package/packages/compactor/src/tools/ctx-execute-file.ts +0 -5
  44. package/packages/compactor/src/tools/register.ts +27 -50
  45. package/packages/compactor/src/tools/vcc-recall.ts +86 -48
  46. package/packages/compactor/src/tui/settings-overlay.ts +20 -40
  47. package/packages/compactor/src/types.ts +43 -100
  48. package/packages/core/constants.ts +1 -28
  49. package/packages/core/events.ts +1 -83
  50. package/packages/core/index.ts +1 -0
  51. package/packages/core/model-cache.ts +18 -12
  52. package/packages/core/package.json +3 -1
  53. package/packages/core/tui-overlay.ts +89 -0
  54. package/packages/core/tui-width.ts +18 -0
  55. package/packages/core/utils.ts +43 -0
  56. package/packages/footer/package.json +2 -2
  57. package/packages/footer/src/help.ts +2 -2
  58. package/packages/footer/src/index.ts +9 -10
  59. package/packages/footer/src/presets.ts +1 -27
  60. package/packages/footer/src/registry/index.ts +0 -23
  61. package/packages/footer/src/rendering/icons.ts +0 -13
  62. package/packages/footer/src/rendering/renderer.ts +5 -40
  63. package/packages/footer/src/rendering/separators.ts +0 -10
  64. package/packages/footer/src/rendering/theme.ts +1 -15
  65. package/packages/footer/src/segments/compactor.ts +7 -14
  66. package/packages/footer/src/segments/core.ts +15 -54
  67. package/packages/footer/src/segments/kanboard.ts +5 -5
  68. package/packages/footer/src/segments/mcp.ts +5 -5
  69. package/packages/footer/src/segments/memory.ts +4 -4
  70. package/packages/footer/src/segments/notify.ts +2 -2
  71. package/packages/footer/src/segments/ralph.ts +3 -3
  72. package/packages/footer/src/segments/status-ext.ts +1 -1
  73. package/packages/footer/src/segments/workflow.ts +3 -3
  74. package/packages/footer/src/tps-tracker.ts +0 -8
  75. package/packages/footer/src/tui/settings-tui.ts +14 -31
  76. package/packages/footer/src/types.ts +0 -15
  77. package/packages/image/package.json +2 -2
  78. package/packages/image/src/register-providers.ts +0 -11
  79. package/packages/image/src/tools.ts +0 -3
  80. package/packages/image/src/tui/model-selector.ts +36 -71
  81. package/packages/info-screen/config.ts +0 -16
  82. package/packages/info-screen/core-groups.ts +0 -10
  83. package/packages/info-screen/index.ts +22 -13
  84. package/packages/info-screen/package.json +2 -2
  85. package/packages/info-screen/registry.ts +1 -72
  86. package/packages/info-screen/tui/info-overlay.ts +85 -100
  87. package/packages/info-screen/usage-parser.ts +12 -47
  88. package/packages/input-shortcuts/package.json +2 -2
  89. package/packages/input-shortcuts/src/index.ts +3 -3
  90. package/packages/input-shortcuts/src/registers.ts +0 -8
  91. package/packages/input-shortcuts/src/settings-overlay.ts +4 -13
  92. package/packages/input-shortcuts/src/undo-redo.ts +0 -12
  93. package/packages/kanboard/package.json +2 -2
  94. package/packages/mcp/package.json +2 -2
  95. package/packages/mcp/src/bridge/client.ts +0 -15
  96. package/packages/mcp/src/config/manager.ts +0 -38
  97. package/packages/mcp/src/config/schema.ts +0 -27
  98. package/packages/mcp/src/config/sync.ts +0 -29
  99. package/packages/mcp/src/index.ts +1 -1
  100. package/packages/mcp/src/tui/add-overlay.ts +6 -6
  101. package/packages/mcp/src/types.ts +0 -6
  102. package/packages/memory/embedding.ts +0 -31
  103. package/packages/memory/mempalace.ts +0 -16
  104. package/packages/memory/package.json +4 -8
  105. package/packages/memory/storage.ts +56 -753
  106. package/packages/milestone/hooks.ts +1 -6
  107. package/packages/milestone/milestone.ts +2 -41
  108. package/packages/milestone/package.json +2 -2
  109. package/packages/notify/README.md +1 -0
  110. package/packages/notify/commands.ts +61 -3
  111. package/packages/notify/events.ts +0 -10
  112. package/packages/notify/package.json +2 -2
  113. package/packages/notify/settings.ts +0 -19
  114. package/packages/notify/tui/gotify-setup.ts +108 -143
  115. package/packages/notify/tui/ntfy-setup.ts +137 -172
  116. package/packages/notify/tui/recap-model-selector.ts +107 -101
  117. package/packages/notify/tui/settings-overlay.ts +94 -117
  118. package/packages/notify/tui/telegram-setup.ts +48 -79
  119. package/packages/notify/types.ts +0 -2
  120. package/packages/ralph/index.ts +11 -35
  121. package/packages/ralph/package.json +3 -3
  122. package/packages/ralph/ralph-loop.ts +3 -44
  123. package/packages/subagents/package.json +2 -1
  124. package/packages/subagents/src/agent-manager.ts +0 -51
  125. package/packages/subagents/src/agent-runner.ts +6 -80
  126. package/packages/subagents/src/conversation-viewer.ts +1 -19
  127. package/packages/subagents/src/core-compat.ts +8 -25
  128. package/packages/subagents/src/custom-agents.ts +0 -1
  129. package/packages/subagents/src/index.ts +3 -48
  130. package/packages/subagents/src/types.ts +0 -11
  131. package/packages/subagents/src/widget.ts +5 -5
  132. package/packages/unipi/bundled.js +4468 -7769
  133. package/packages/unipi/index.ts +6 -3
  134. package/packages/updater/package.json +2 -2
  135. package/packages/updater/src/changelog.ts +1 -16
  136. package/packages/updater/src/index.ts +0 -5
  137. package/packages/updater/src/installer.ts +4 -26
  138. package/packages/updater/src/markdown.ts +6 -152
  139. package/packages/updater/src/settings.ts +0 -15
  140. package/packages/updater/src/tui/changelog-overlay.ts +42 -234
  141. package/packages/updater/src/tui/list-detail-overlay.ts +260 -0
  142. package/packages/updater/src/tui/readme-overlay.ts +53 -210
  143. package/packages/updater/src/tui/settings-overlay.ts +13 -26
  144. package/packages/updater/src/version.ts +2 -31
  145. package/packages/utility/package.json +2 -4
  146. package/packages/utility/src/commands.ts +4 -5
  147. package/packages/utility/src/herdr-sync.ts +136 -0
  148. package/packages/utility/src/index.ts +11 -68
  149. package/packages/utility/src/lifecycle/cleanup.ts +2 -16
  150. package/packages/utility/src/{diff/settings.ts → settings.ts} +42 -80
  151. package/packages/utility/src/tools/env.ts +0 -0
  152. package/packages/utility/src/tui/name-badge-state.ts +18 -2
  153. package/packages/utility/src/tui/name-badge.ts +5 -4
  154. package/packages/utility/src/tui/util-settings-tui.ts +41 -224
  155. package/packages/web-api/package.json +2 -6
  156. package/packages/web-api/src/engine/dependencies.ts +13 -134
  157. package/packages/web-api/src/engine/extract.ts +9 -99
  158. package/packages/web-api/src/engine/format.ts +0 -75
  159. package/packages/web-api/src/engine/types.ts +0 -39
  160. package/packages/web-api/src/index.ts +1 -2
  161. package/packages/web-api/src/providers/base.ts +0 -10
  162. package/packages/web-api/src/providers/duckduckgo.ts +0 -1
  163. package/packages/web-api/src/providers/firecrawl.ts +0 -9
  164. package/packages/web-api/src/providers/jina-reader.ts +0 -9
  165. package/packages/web-api/src/providers/jina-search.ts +0 -9
  166. package/packages/web-api/src/providers/perplexity.ts +0 -9
  167. package/packages/web-api/src/providers/registry.ts +0 -80
  168. package/packages/web-api/src/providers/serpapi.ts +0 -9
  169. package/packages/web-api/src/providers/tavily.ts +0 -9
  170. package/packages/web-api/src/providers/wigolo-client.ts +0 -30
  171. package/packages/web-api/src/providers/wigolo.ts +0 -1
  172. package/packages/web-api/src/settings.ts +17 -77
  173. package/packages/web-api/src/tools.ts +21 -24
  174. package/packages/web-api/src/tui/settings-dialog.ts +0 -1
  175. package/packages/workflow/commands.ts +38 -122
  176. package/packages/workflow/index.ts +1 -5
  177. package/packages/workflow/package.json +2 -2
  178. package/packages/cocoindex/README.md +0 -94
  179. package/packages/cocoindex/bridge.ts +0 -842
  180. package/packages/cocoindex/commands.ts +0 -175
  181. package/packages/cocoindex/index.ts +0 -48
  182. package/packages/cocoindex/installer.ts +0 -397
  183. package/packages/cocoindex/package.json +0 -49
  184. package/packages/cocoindex/skills/cocoindex/SKILL.md +0 -88
  185. package/packages/cocoindex/tools.ts +0 -157
  186. package/packages/compactor/src/display/diff-renderer.ts +0 -281
  187. package/packages/compactor/src/display/line-width-safety.ts +0 -28
  188. package/packages/compactor/src/display/render-utils.ts +0 -52
  189. package/packages/compactor/src/display/thinking-label.ts +0 -18
  190. package/packages/compactor/src/display/tool-overrides.ts +0 -136
  191. package/packages/compactor/src/tools/compact.ts +0 -20
  192. package/packages/subagents/src/file-lock.ts +0 -102
  193. package/packages/utility/src/cache/ttl-cache.ts +0 -311
  194. package/packages/utility/src/diff/highlighter.ts +0 -352
  195. package/packages/utility/src/diff/parser.ts +0 -191
  196. package/packages/utility/src/diff/renderer.ts +0 -395
  197. package/packages/utility/src/diff/theme.ts +0 -316
  198. package/packages/utility/src/diff/wrapper.ts +0 -339
  199. package/packages/utility/src/display/capabilities.ts +0 -214
  200. package/packages/utility/src/display/width.ts +0 -226
  201. package/packages/utility/src/tools/batch.ts +0 -229
  202. package/packages/utility/src/tui/badge-settings-tui.ts +0 -388
  203. package/packages/utility/src/tui/badge-settings.ts +0 -67
  204. package/packages/utility/src/tui/settings-inspector.ts +0 -303
  205. package/packages/web-api/src/providers/llm-summarize.ts +0 -71
@@ -303,3 +303,46 @@ export async function withHerdrBlocked<T>(
303
303
  event(false);
304
304
  }
305
305
  }
306
+
307
+ /** Format a token count for display (e.g. 1234 → "1.2k", 1500000 → "1.5M"). */
308
+ export function formatTokens(n: number): string {
309
+ if (n < 1000) return String(n);
310
+ if (n < 10_000) return `${(n / 1000).toFixed(1)}k`;
311
+ if (n < 1_000_000) return `${Math.round(n / 1000)}k`;
312
+ if (n < 10_000_000) return `${(n / 1_000_000).toFixed(1)}M`;
313
+ return `${Math.round(n / 1_000_000)}M`;
314
+ }
315
+
316
+ /** Check if a snapshot is active by checking its details.active field or content. */
317
+ export function isActiveSnapshot(snapshot: { content: unknown; details?: { active?: boolean } }): boolean {
318
+ if (typeof snapshot.details?.active === "boolean") return snapshot.details.active;
319
+ return typeof snapshot.content === "string" && snapshot.content.includes("Status: active");
320
+ }
321
+
322
+ /** Compare two semver-ish version strings.
323
+ * Returns 1 when a > b, -1 when a < b, 0 when equal.
324
+ * Handles `v` prefix, splits on `.` or `-`, ignores non-numeric suffixes. */
325
+ export function compareVersions(a: string, b: string): number {
326
+ const parse = (version: string): number[] => version
327
+ .replace(/^v/, "")
328
+ .split(/[.-]/)
329
+ .slice(0, 3)
330
+ .map((part) => {
331
+ const parsed = Number.parseInt(part, 10);
332
+ return Number.isNaN(parsed) ? 0 : parsed;
333
+ });
334
+
335
+ const left = parse(a);
336
+ const right = parse(b);
337
+ for (let i = 0; i < 3; i++) {
338
+ const diff = (left[i] ?? 0) - (right[i] ?? 0);
339
+ if (diff > 0) return 1;
340
+ if (diff < 0) return -1;
341
+ }
342
+ return 0;
343
+ }
344
+
345
+ /** Return true only when `latest` is newer than `current`. */
346
+ export function isNewerVersion(latest: string, current: string): boolean {
347
+ return compareVersions(latest, current) > 0;
348
+ }
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pi-unipi/footer",
3
- "version": "2.6.0",
3
+ "version": "2.6.1",
4
4
  "description": "Persistent status bar for Unipi — subscribes to UNIPI_EVENTS and renders key stats from all unipi packages",
5
5
  "type": "module",
6
6
  "main": "index.ts",
@@ -32,7 +32,7 @@
32
32
  "access": "public"
33
33
  },
34
34
  "dependencies": {
35
- "@pi-unipi/core": "2.6.0"
35
+ "@pi-unipi/core": "2.6.1"
36
36
  },
37
37
  "peerDependencies": {
38
38
  "@earendil-works/pi-coding-agent": "^0.80.0",
@@ -72,10 +72,10 @@ function buildHelpLines(
72
72
  }
73
73
 
74
74
  /** Simple group lookup for help */
75
- function getGroupForSegment(segId: string): string {
75
+ export function getGroupForSegment(segId: string): string {
76
76
  const coreIds = ["model", "api_state", "tool_count", "git", "context_pct", "cost", "tokens_total", "tokens_in", "tokens_out", "session", "hostname", "time", "tps", "clock", "duration", "thinking_level"];
77
77
  if (coreIds.includes(segId)) return "core";
78
- const compactorIds = ["session_events", "compactions", "tokens_saved", "compression_ratio", "cocoindex_status", "sandbox_runs", "search_queries"];
78
+ const compactorIds = ["session_events", "compactions", "tokens_saved", "compression_ratio", "sandbox_runs", "search_queries"];
79
79
  if (compactorIds.includes(segId)) return "compactor";
80
80
  if (["project_count", "total_count", "consolidations"].includes(segId)) return "memory";
81
81
  if (["servers_total", "servers_active", "tools_total", "servers_failed"].includes(segId)) return "mcp";
@@ -27,20 +27,19 @@ import { NOTIFY_SEGMENTS } from "./segments/notify.js";
27
27
  import { STATUS_EXT_SEGMENTS } from "./segments/status-ext.js";
28
28
 
29
29
  import type { FooterGroup, FooterSegment } from "./types.js";
30
- import { rainbowBorder } from "./segments/core.js";
31
30
  import { tpsTracker } from "./tps-tracker.js";
32
31
 
33
32
  /** All segment groups */
34
33
  const ALL_GROUPS: FooterGroup[] = [
35
- { id: "core", name: "Core", icon: "", segments: CORE_SEGMENTS, defaultShow: true },
36
- { id: "compactor", name: "Compactor", icon: "", segments: COMPACTOR_SEGMENTS, defaultShow: true },
37
- { id: "memory", name: "Memory", icon: "", segments: MEMORY_SEGMENTS, defaultShow: true },
38
- { id: "mcp", name: "MCP", icon: "", segments: MCP_SEGMENTS, defaultShow: true },
39
- { id: "ralph", name: "Ralph", icon: "", segments: RALPH_SEGMENTS, defaultShow: true },
40
- { id: "workflow", name: "Workflow", icon: "", segments: WORKFLOW_SEGMENTS, defaultShow: true },
41
- { id: "kanboard", name: "Kanboard", icon: "", segments: KANBOARD_SEGMENTS, defaultShow: true },
42
- { id: "notify", name: "Notify", icon: "", segments: NOTIFY_SEGMENTS, defaultShow: false },
43
- { id: "status_ext", name: "Extensions", icon: "", segments: STATUS_EXT_SEGMENTS, defaultShow: true },
34
+ { id: "core", name: "Core", segments: CORE_SEGMENTS, defaultShow: true },
35
+ { id: "compactor", name: "Compactor", segments: COMPACTOR_SEGMENTS, defaultShow: true },
36
+ { id: "memory", name: "Memory", segments: MEMORY_SEGMENTS, defaultShow: true },
37
+ { id: "mcp", name: "MCP", segments: MCP_SEGMENTS, defaultShow: true },
38
+ { id: "ralph", name: "Ralph", segments: RALPH_SEGMENTS, defaultShow: true },
39
+ { id: "workflow", name: "Workflow", segments: WORKFLOW_SEGMENTS, defaultShow: true },
40
+ { id: "kanboard", name: "Kanboard", segments: KANBOARD_SEGMENTS, defaultShow: true },
41
+ { id: "notify", name: "Notify", segments: NOTIFY_SEGMENTS, defaultShow: false },
42
+ { id: "status_ext", name: "Extensions", segments: STATUS_EXT_SEGMENTS, defaultShow: true },
44
43
  ];
45
44
 
46
45
  /** Build a segment lookup from all groups */
@@ -73,32 +73,7 @@ const FULL_PRESET: PresetDef = {
73
73
  secondarySegments: [
74
74
  "hostname",
75
75
  "tokens_in", "tokens_out",
76
- "compression_ratio", "cocoindex_status",
77
- "platforms_enabled", "last_sent",
78
- "thinking_level",
79
- ],
80
- colors: getDefaultColors(),
81
- };
82
-
83
- /** Nerd preset — maximum detail for Nerd Font users */
84
- const NERD_PRESET: PresetDef = {
85
- leftSegments: [
86
- "model", "api_state", "tool_count", "git", "current_command", "session",
87
- ],
88
- rightSegments: [
89
- "tps", "context_pct", "cost", "tokens_total",
90
- "session_events", "compactions", "tokens_saved",
91
- "project_count", "total_count",
92
- "servers_total", "servers_active", "tools_total",
93
- "active_loops", "loop_status",
94
- "docs_count", "tasks_done", "task_pct",
95
- "extension_statuses",
96
- "clock", "duration",
97
- ],
98
- secondarySegments: [
99
- "hostname",
100
- "tokens_in", "tokens_out",
101
- "compression_ratio", "cocoindex_status",
76
+ "compression_ratio",
102
77
  "platforms_enabled", "last_sent",
103
78
  "thinking_level",
104
79
  ],
@@ -124,7 +99,6 @@ export const PRESETS: Record<string, PresetDef> = {
124
99
  minimal: MINIMAL_PRESET,
125
100
  compact: COMPACT_PRESET,
126
101
  full: FULL_PRESET,
127
- nerd: NERD_PRESET,
128
102
  ascii: ASCII_PRESET,
129
103
  };
130
104
 
@@ -87,15 +87,6 @@ export class FooterRegistry {
87
87
  this.notifySubscribers();
88
88
  }
89
89
 
90
- /**
91
- * Clear cached data for a specific group.
92
- */
93
- invalidateGroup(groupId: string): void {
94
- this.dataCache.delete(groupId);
95
- this.log("invalidateGroup", groupId);
96
- this.notifySubscribers();
97
- }
98
-
99
90
  // ─── Reactive Subscriptions ───────────────────────────────────────────────
100
91
 
101
92
  /**
@@ -144,17 +135,3 @@ export function getFooterRegistry(): FooterRegistry {
144
135
  }
145
136
  return registryInstance;
146
137
  }
147
-
148
- /**
149
- * Reset the global registry (for testing).
150
- */
151
- export function resetFooterRegistry(): void {
152
- registryInstance = null;
153
- }
154
-
155
- // ─── Global reference ───────────────────────────────────────────────────────
156
-
157
- // Expose on globalThis for cross-package access
158
- if (typeof globalThis !== "undefined") {
159
- globalThis.__unipi_footer_registry = getFooterRegistry();
160
- }
@@ -321,16 +321,3 @@ export function getIcon(segmentId: string, overrideStyle?: "nerd" | "emoji" | "t
321
321
  const key = segmentId as keyof IconSet;
322
322
  return icons[key] ?? "";
323
323
  }
324
-
325
- /**
326
- * Get the full icon set based on the configured style.
327
- */
328
- export function getIcons(iconStyle?: "nerd" | "emoji" | "text"): IconSet {
329
- const style = iconStyle ?? currentIconStyle ?? resolveIconStyle();
330
- const sets: Record<string, IconSet> = {
331
- nerd: NERD_ICONS,
332
- emoji: EMOJI_ICONS,
333
- text: TEXT_ICONS,
334
- };
335
- return sets[style];
336
- }
@@ -10,7 +10,8 @@ import type { Theme } from "@earendil-works/pi-coding-agent";
10
10
  import type { PresetDef, FooterSegmentContext, FooterSegment, ColorScheme, RenderedSegment, SegmentZone } from "../types.js";
11
11
  import type { FooterRegistry } from "../registry/index.js";
12
12
  import { visibleWidth as piVisibleWidth, truncateToWidth } from "@earendil-works/pi-tui";
13
- import { getSeparator, separatorVisibleWidth } from "./separators.js";
13
+ import { getSeparator } from "./separators.js";
14
+ import { getGroupForSegment } from "../help.js";
14
15
  import { getDefaultColors, setColorMode, refreshColorMode } from "./theme.js";
15
16
  import { setIconStyle } from "./icons.js";
16
17
  import { getPreset } from "../presets.js";
@@ -27,7 +28,6 @@ interface SegmentLookup {
27
28
  interface RenderedSegmentWithWidth {
28
29
  content: string;
29
30
  width: number;
30
- visible: boolean;
31
31
  }
32
32
 
33
33
  // ─── ANSI helpers ───────────────────────────────────────────────────────────
@@ -183,7 +183,7 @@ export class FooterRenderer {
183
183
  if (this.segmentLookup.allIds) {
184
184
  for (const segId of this.segmentLookup.allIds()) {
185
185
  if (primaryIds.includes(segId) || secondaryIds.includes(segId)) continue;
186
- const groupId = this.getGroupForSegment(segId);
186
+ const groupId = getGroupForSegment(segId);
187
187
  if (isSegmentExplicitlyEnabled(groupId, segId)) {
188
188
  primaryIds.push(segId);
189
189
  }
@@ -309,7 +309,7 @@ export class FooterRenderer {
309
309
  fullWidth: number,
310
310
  labelMode: "compact" | "labeled",
311
311
  ): RenderedSegmentWithWidth | null {
312
- if (!isSegmentEnabled(this.getGroupForSegment(segId), segId)) return null;
312
+ if (!isSegmentEnabled(getGroupForSegment(segId), segId)) return null;
313
313
 
314
314
  const segment = this.segmentLookup.get(segId);
315
315
  if (!segment) return null;
@@ -317,7 +317,7 @@ export class FooterRenderer {
317
317
  const ctx: FooterSegmentContext = {
318
318
  theme: this.getThemeLike(),
319
319
  colors,
320
- data: this.registry.getGroupData(this.getGroupForSegment(segId)),
320
+ data: this.registry.getGroupData(getGroupForSegment(segId)),
321
321
  width: fullWidth,
322
322
  piContext: this.piContext,
323
323
  footerData: this.footerData,
@@ -330,7 +330,6 @@ export class FooterRenderer {
330
330
  return {
331
331
  content: rendered.content,
332
332
  width: visibleWidth(rendered.content),
333
- visible: true,
334
333
  };
335
334
  }
336
335
 
@@ -441,40 +440,6 @@ export class FooterRenderer {
441
440
  return truncateToWidth(result, 200);
442
441
  }
443
442
 
444
- /** Map a segment ID to its group ID */
445
- private getGroupForSegment(segId: string): string {
446
- // Core segments
447
- const coreIds = ["model", "api_state", "tool_count", "git", "context_pct", "cost", "tokens_total", "tokens_in", "tokens_out", "session", "hostname", "time", "tps", "clock", "duration", "thinking_level"];
448
- if (coreIds.includes(segId)) return "core";
449
-
450
- // Compactor segments
451
- const compactorIds = ["session_events", "compactions", "tokens_saved", "compression_ratio", "cocoindex_status", "sandbox_runs", "search_queries"];
452
- if (compactorIds.includes(segId)) return "compactor";
453
-
454
- // Memory segments
455
- if (["project_count", "total_count", "consolidations"].includes(segId)) return "memory";
456
-
457
- // MCP segments
458
- if (["servers_total", "servers_active", "tools_total", "servers_failed"].includes(segId)) return "mcp";
459
-
460
- // Ralph segments
461
- if (["active_loops", "total_iterations", "loop_status"].includes(segId)) return "ralph";
462
-
463
- // Workflow segments
464
- if (["current_command", "sandbox_level", "command_duration"].includes(segId)) return "workflow";
465
-
466
- // Kanboard segments
467
- if (["docs_count", "tasks_done", "tasks_total", "task_pct"].includes(segId)) return "kanboard";
468
-
469
- // Notify segments
470
- if (["platforms_enabled", "last_sent"].includes(segId)) return "notify";
471
-
472
- // Status extension
473
- if (segId === "extension_statuses") return "status_ext";
474
-
475
- return "core";
476
- }
477
-
478
443
  /** Get a ThemeLike object for rendering context */
479
444
  private getThemeLike(): { fg: (color: string, text: string) => string } {
480
445
  // Use a minimal theme-like that applies ANSI codes based on color names
@@ -100,13 +100,3 @@ export function getSeparator(style: SeparatorStyle): SeparatorDef {
100
100
  return getSeparator("powerline-thin");
101
101
  }
102
102
  }
103
-
104
- /**
105
- * Get the visible width of a separator (ANSI-stripped length).
106
- */
107
- export function separatorVisibleWidth(style: SeparatorStyle): number {
108
- const sep = getSeparator(style);
109
- // Strip ANSI codes and measure
110
- const stripped = sep.left.replace(/\x1b\[[0-9;]*m/g, "");
111
- return stripped.length;
112
- }
@@ -12,7 +12,7 @@
12
12
  */
13
13
 
14
14
  import type { Theme, ThemeColor } from "@earendil-works/pi-coding-agent";
15
- import type { ColorScheme, ColorValue, SemanticColor, ThemeLike } from "../types.js";
15
+ import type { ColorScheme, SemanticColor, ThemeLike } from "../types.js";
16
16
 
17
17
  // ─── Color mode detection ──────────────────────────────────────────────────
18
18
 
@@ -244,20 +244,6 @@ export function getDefaultColors(): ColorScheme {
244
244
  return scheme;
245
245
  }
246
246
 
247
- /**
248
- * Resolve a ColorValue to an actual color string using the theme.
249
- * If the value is a theme color name, uses theme.fg().
250
- * If it's a hex string, returns it directly.
251
- */
252
- export function resolveColor(color: ColorValue, theme: ThemeLike): string {
253
- // Check if it's a hex color (starts with #)
254
- if (color.startsWith("#")) {
255
- return color;
256
- }
257
- // It's a ThemeColor — use theme.fg
258
- return theme.fg(color as ThemeColor, "").replace(/\x1b\[0m$/, "");
259
- }
260
-
261
247
  /**
262
248
  * Wrap `text` in an ANSI escape for the given hex value, chosen to match
263
249
  * the active colour mode (truecolor / 256 / none).
@@ -2,7 +2,7 @@
2
2
  * @pi-unipi/footer — Compactor segments
3
3
  *
4
4
  * Segment renderers for the compactor group: session_events, compactions,
5
- * tokens_saved, compression_ratio, cocoindex_status, sandbox_runs, search_queries.
5
+ * tokens_saved, compression_ratio, sandbox_runs, search_queries.
6
6
  *
7
7
  * Data sourced from piContext.sessionManager (live session data).
8
8
  * Segments without a reliable data source are hidden (visible: false)
@@ -129,12 +129,6 @@ function renderCompressionRatioSegment(ctx: FooterSegmentContext): RenderedSegme
129
129
  return { content: applyColor("compactor", content, ctx.theme, ctx.colors), visible: true };
130
130
  }
131
131
 
132
- function renderCocoindexStatusSegment(_ctx: FooterSegmentContext): RenderedSegment {
133
- // CocoIndex status — would need to query cocoindex bridge at render time.
134
- // For now, hidden. Use /unipi:cocoindex-status for live status.
135
- return hidden();
136
- }
137
-
138
132
  function renderSandboxRunsSegment(ctx: FooterSegmentContext): RenderedSegment {
139
133
  // Count sandbox events from session manager branch
140
134
  const events = getSessionEvents(ctx);
@@ -171,11 +165,10 @@ function renderSearchQueriesSegment(ctx: FooterSegmentContext): RenderedSegment
171
165
  }
172
166
 
173
167
  export const COMPACTOR_SEGMENTS: FooterSegment[] = [
174
- { id: "session_events", label: "Session Events", shortLabel: "EVT", description: "Number of session events", zone: "center", icon: "", render: renderSessionEventsSegment, defaultShow: true },
175
- { id: "compactions", label: "Compactions", shortLabel: "CMP", description: "Number of context compactions", zone: "center", icon: "", render: renderCompactionsSegment, defaultShow: true },
176
- { id: "tokens_saved", label: "Tokens Saved", shortLabel: "SVD", description: "Tokens saved by compaction", zone: "center", icon: "", render: renderTokensSavedSegment, defaultShow: true },
177
- { id: "compression_ratio", label: "Compression Ratio", shortLabel: "RAT", description: "Last compaction compression ratio", zone: "center", icon: "", render: renderCompressionRatioSegment, defaultShow: false },
178
- { id: "cocoindex_status", label: "CocoIndex", shortLabel: "CIDX", description: "CocoIndex indexing status", zone: "center", icon: "", render: renderCocoindexStatusSegment, defaultShow: false },
179
- { id: "sandbox_runs", label: "Sandbox Runs", shortLabel: "SBX", description: "Number of sandbox code runs", zone: "center", icon: "", render: renderSandboxRunsSegment, defaultShow: false },
180
- { id: "search_queries", label: "Search Queries", shortLabel: "QRY", description: "Number of search queries", zone: "center", icon: "", render: renderSearchQueriesSegment, defaultShow: false },
168
+ { id: "session_events", label: "Session Events", shortLabel: "EVT", description: "Number of session events", zone: "center", render: renderSessionEventsSegment, defaultShow: true },
169
+ { id: "compactions", label: "Compactions", shortLabel: "CMP", description: "Number of context compactions", zone: "center", render: renderCompactionsSegment, defaultShow: true },
170
+ { id: "tokens_saved", label: "Tokens Saved", shortLabel: "SVD", description: "Tokens saved by compaction", zone: "center", render: renderTokensSavedSegment, defaultShow: true },
171
+ { id: "compression_ratio", label: "Compression Ratio", shortLabel: "RAT", description: "Last compaction compression ratio", zone: "center", render: renderCompressionRatioSegment, defaultShow: false },
172
+ { id: "sandbox_runs", label: "Sandbox Runs", shortLabel: "SBX", description: "Number of sandbox code runs", zone: "center", render: renderSandboxRunsSegment, defaultShow: false },
173
+ { id: "search_queries", label: "Search Queries", shortLabel: "QRY", description: "Number of search queries", zone: "center", render: renderSearchQueriesSegment, defaultShow: false },
181
174
  ];
@@ -61,45 +61,6 @@ function getUsageStats(piContext: unknown): UsageStats {
61
61
  return { input, output, cacheRead, cacheWrite, cost };
62
62
  }
63
63
 
64
- // ─── Rainbow helpers (kept for potential future use) ─────────────────────────
65
-
66
- /** ANSI 256-color rainbow palette */
67
- const RAINBOW_COLORS = [
68
- "\x1b[38;5;196m", // red
69
- "\x1b[38;5;202m", // orange
70
- "\x1b[38;5;226m", // yellow
71
- "\x1b[38;5;82m", // green
72
- "\x1b[38;5;45m", // blue
73
- "\x1b[38;5;129m", // indigo
74
- "\x1b[38;5;171m", // violet
75
- ];
76
-
77
- const ANSI_RESET = "\x1b[0m";
78
-
79
- /** Apply rainbow coloring to text, cycling through colors per character */
80
- export function rainbowText(text: string): string {
81
- let result = "";
82
- let colorIdx = 0;
83
- for (const char of text) {
84
- if (char === " ") {
85
- result += char;
86
- } else {
87
- result += `${RAINBOW_COLORS[colorIdx % RAINBOW_COLORS.length]}${char}${ANSI_RESET}`;
88
- colorIdx++;
89
- }
90
- }
91
- return result;
92
- }
93
-
94
- /** Render a rainbow border line of the given width */
95
- export function rainbowBorder(width: number): string {
96
- let result = "";
97
- for (let i = 0; i < width; i++) {
98
- result += `${RAINBOW_COLORS[i % RAINBOW_COLORS.length]}─${ANSI_RESET}`;
99
- }
100
- return result;
101
- }
102
-
103
64
  // ─── Segment Renderers ──────────────────────────────────────────────────────
104
65
 
105
66
  function renderModelSegment(ctx: FooterSegmentContext): RenderedSegment {
@@ -324,19 +285,19 @@ function renderThinkingLevelSegment(ctx: FooterSegmentContext): RenderedSegment
324
285
  // ─── Core segments array ────────────────────────────────────────────────────
325
286
 
326
287
  export const CORE_SEGMENTS: FooterSegment[] = [
327
- { id: "model", label: "Model", shortLabel: "MDL", description: "Current model name", zone: "left", icon: "", render: renderModelSegment, defaultShow: true },
328
- { id: "api_state", label: "API", shortLabel: "API", description: "API connection state", zone: "left", icon: "", render: renderApiStateSegment, defaultShow: true },
329
- { id: "tool_count", label: "Tool Count", shortLabel: "TLS", description: "Number of tools available", zone: "left", icon: "", render: renderToolCountSegment, defaultShow: true },
330
- { id: "git", label: "Git", shortLabel: "GIT", description: "Current git branch + dirty/clean status", zone: "left", icon: "", render: renderGitSegment, defaultShow: true },
331
- { id: "tps", label: "TPS", shortLabel: "TPS", description: "Tokens per second \u2014 live during generation", zone: "center", icon: "", render: renderTpsSegment, defaultShow: true },
332
- { id: "context_pct", label: "Context %", shortLabel: "CTX", description: "Context window usage percentage", zone: "center", icon: "", render: renderContextPctSegment, defaultShow: true },
333
- { id: "cost", label: "Cost", shortLabel: "CST", description: "Session cost in USD", zone: "center", icon: "", render: renderCostSegment, defaultShow: true },
334
- { id: "tokens_total", label: "Tokens Total", shortLabel: "TOK", description: "Total tokens used this session", zone: "center", icon: "", render: renderTokensSegment("total"), defaultShow: false },
335
- { id: "tokens_in", label: "Tokens In", shortLabel: "TIN", description: "Input tokens consumed", zone: "center", icon: "", render: renderTokensSegment("in"), defaultShow: false },
336
- { id: "tokens_out", label: "Tokens Out", shortLabel: "TOUT", description: "Output tokens generated", zone: "center", icon: "", render: renderTokensSegment("out"), defaultShow: false },
337
- { id: "session", label: "Session", shortLabel: "SES", description: "Session identifier", zone: "left", icon: "", render: renderSessionSegment, defaultShow: false },
338
- { id: "hostname", label: "Hostname", shortLabel: "HST", description: "Machine hostname", zone: "left", icon: "", render: renderHostnameSegment, defaultShow: false },
339
- { id: "clock", label: "Clock", shortLabel: "CLK", description: "Current wall time (HH:MM:SS)", zone: "right", icon: "", render: renderClockSegment, defaultShow: true },
340
- { id: "duration", label: "Duration", shortLabel: "DUR", description: "Session duration", zone: "right", icon: "", render: renderDurationSegment, defaultShow: true },
341
- { id: "thinking_level", label: "Thinking", shortLabel: "THK", description: "Current model thinking level", zone: "center", icon: "", render: renderThinkingLevelSegment, defaultShow: false },
288
+ { id: "model", label: "Model", shortLabel: "MDL", description: "Current model name", zone: "left", render: renderModelSegment, defaultShow: true },
289
+ { id: "api_state", label: "API", shortLabel: "API", description: "API connection state", zone: "left", render: renderApiStateSegment, defaultShow: true },
290
+ { id: "tool_count", label: "Tool Count", shortLabel: "TLS", description: "Number of tools available", zone: "left", render: renderToolCountSegment, defaultShow: true },
291
+ { id: "git", label: "Git", shortLabel: "GIT", description: "Current git branch + dirty/clean status", zone: "left", render: renderGitSegment, defaultShow: true },
292
+ { id: "tps", label: "TPS", shortLabel: "TPS", description: "Tokens per second \u2014 live during generation", zone: "center", render: renderTpsSegment, defaultShow: true },
293
+ { id: "context_pct", label: "Context %", shortLabel: "CTX", description: "Context window usage percentage", zone: "center", render: renderContextPctSegment, defaultShow: true },
294
+ { id: "cost", label: "Cost", shortLabel: "CST", description: "Session cost in USD", zone: "center", render: renderCostSegment, defaultShow: true },
295
+ { id: "tokens_total", label: "Tokens Total", shortLabel: "TOK", description: "Total tokens used this session", zone: "center", render: renderTokensSegment("total"), defaultShow: false },
296
+ { id: "tokens_in", label: "Tokens In", shortLabel: "TIN", description: "Input tokens consumed", zone: "center", render: renderTokensSegment("in"), defaultShow: false },
297
+ { id: "tokens_out", label: "Tokens Out", shortLabel: "TOUT", description: "Output tokens generated", zone: "center", render: renderTokensSegment("out"), defaultShow: false },
298
+ { id: "session", label: "Session", shortLabel: "SES", description: "Session identifier", zone: "left", render: renderSessionSegment, defaultShow: false },
299
+ { id: "hostname", label: "Hostname", shortLabel: "HST", description: "Machine hostname", zone: "left", render: renderHostnameSegment, defaultShow: false },
300
+ { id: "clock", label: "Clock", shortLabel: "CLK", description: "Current wall time (HH:MM:SS)", zone: "right", render: renderClockSegment, defaultShow: true },
301
+ { id: "duration", label: "Duration", shortLabel: "DUR", description: "Session duration", zone: "right", render: renderDurationSegment, defaultShow: true },
302
+ { id: "thinking_level", label: "Thinking", shortLabel: "THK", description: "Current model thinking level", zone: "center", render: renderThinkingLevelSegment, defaultShow: false },
342
303
  ];
@@ -22,7 +22,7 @@ function withIcon(segmentId: string, text: string): string {
22
22
  */
23
23
  function getKanboardData(): Record<string, unknown> | null {
24
24
  try {
25
- const registry = globalThis.__unipi_kanboard_registry;
25
+ const registry = (globalThis as Record<string, unknown>).__unipi_kanboard_registry;
26
26
  if (!registry || typeof registry !== "object") return null;
27
27
  return registry as Record<string, unknown>;
28
28
  } catch {
@@ -84,8 +84,8 @@ function renderTaskPctSegment(ctx: FooterSegmentContext): RenderedSegment {
84
84
  }
85
85
 
86
86
  export const KANBOARD_SEGMENTS: FooterSegment[] = [
87
- { id: "docs_count", label: "Docs", shortLabel: "DOC", description: "Workflow documents count", zone: "center", icon: "", render: renderDocsCountSegment, defaultShow: true },
88
- { id: "tasks_done", label: "Done", shortLabel: "DNE", description: "Completed tasks", zone: "center", icon: "", render: renderTasksDoneSegment, defaultShow: true },
89
- { id: "tasks_total", label: "Total", shortLabel: "TSK", description: "Total tasks", zone: "center", icon: "", render: renderTasksTotalSegment, defaultShow: true },
90
- { id: "task_pct", label: "Progress", shortLabel: "PCT", description: "Task completion percentage", zone: "center", icon: "", render: renderTaskPctSegment, defaultShow: true },
87
+ { id: "docs_count", label: "Docs", shortLabel: "DOC", description: "Workflow documents count", zone: "center", render: renderDocsCountSegment, defaultShow: true },
88
+ { id: "tasks_done", label: "Done", shortLabel: "DNE", description: "Completed tasks", zone: "center", render: renderTasksDoneSegment, defaultShow: true },
89
+ { id: "tasks_total", label: "Total", shortLabel: "TSK", description: "Total tasks", zone: "center", render: renderTasksTotalSegment, defaultShow: true },
90
+ { id: "task_pct", label: "Progress", shortLabel: "PCT", description: "Task completion percentage", zone: "center", render: renderTaskPctSegment, defaultShow: true },
91
91
  ];
@@ -37,7 +37,7 @@ function withIcon(segmentId: string, text: string): string {
37
37
  */
38
38
  function getMcpStats(ctx: FooterSegmentContext): McpStats {
39
39
  // Source 1: globalThis escape hatch (future: MCP registry may expose this)
40
- const global = globalThis.__unipi_mcp_stats;
40
+ const global = (globalThis as Record<string, unknown>).__unipi_mcp_stats;
41
41
  if (global && typeof global === "object") {
42
42
  return global;
43
43
  }
@@ -102,8 +102,8 @@ function renderServersFailedSegment(ctx: FooterSegmentContext): RenderedSegment
102
102
  }
103
103
 
104
104
  export const MCP_SEGMENTS: FooterSegment[] = [
105
- { id: "servers_total", label: "Servers", shortLabel: "SRV", description: "Total MCP servers configured", zone: "center", icon: "", render: renderServersTotalSegment, defaultShow: true },
106
- { id: "servers_active", label: "Active", shortLabel: "ACT", description: "Currently connected MCP servers", zone: "center", icon: "", render: renderServersActiveSegment, defaultShow: true },
107
- { id: "tools_total", label: "Tools", shortLabel: "TLS", description: "Total MCP tools available", zone: "center", icon: "", render: renderToolsTotalSegment, defaultShow: true },
108
- { id: "servers_failed", label: "Failed", shortLabel: "ERR", description: "Failed MCP server connections", zone: "center", icon: "", render: renderServersFailedSegment, defaultShow: true },
105
+ { id: "servers_total", label: "Servers", shortLabel: "SRV", description: "Total MCP servers configured", zone: "center", render: renderServersTotalSegment, defaultShow: true },
106
+ { id: "servers_active", label: "Active", shortLabel: "ACT", description: "Currently connected MCP servers", zone: "center", render: renderServersActiveSegment, defaultShow: true },
107
+ { id: "tools_total", label: "Tools", shortLabel: "TLS", description: "Total MCP tools available", zone: "center", render: renderToolsTotalSegment, defaultShow: true },
108
+ { id: "servers_failed", label: "Failed", shortLabel: "ERR", description: "Failed MCP server connections", zone: "center", render: renderServersFailedSegment, defaultShow: true },
109
109
  ];
@@ -51,7 +51,7 @@ interface InfoRegistryLike {
51
51
  */
52
52
  function getInfoRegistryMemoryData(): InfoMemoryData | null {
53
53
  try {
54
- const registry = globalThis.__unipi_info_registry;
54
+ const registry = (globalThis as Record<string, unknown>).__unipi_info_registry;
55
55
  if (!registry || typeof registry !== "object") return null;
56
56
 
57
57
  // The info registry exposes getCachedData(groupId) synchronously
@@ -139,7 +139,7 @@ function renderConsolidationsSegment(ctx: FooterSegmentContext): RenderedSegment
139
139
  }
140
140
 
141
141
  export const MEMORY_SEGMENTS: FooterSegment[] = [
142
- { id: "project_count", label: "Project Memory", shortLabel: "MEM", description: "Memory entries for this project", zone: "center", icon: "", render: renderProjectCountSegment, defaultShow: true },
143
- { id: "total_count", label: "Total Memory", shortLabel: "TOT", description: "Total memory entries across projects", zone: "center", icon: "", render: renderTotalCountSegment, defaultShow: true },
144
- { id: "consolidations", label: "Consolidations", shortLabel: "CNS", description: "Number of memory consolidations", zone: "center", icon: "", render: renderConsolidationsSegment, defaultShow: false },
142
+ { id: "project_count", label: "Project Memory", shortLabel: "MEM", description: "Memory entries for this project", zone: "center", render: renderProjectCountSegment, defaultShow: true },
143
+ { id: "total_count", label: "Total Memory", shortLabel: "TOT", description: "Total memory entries across projects", zone: "center", render: renderTotalCountSegment, defaultShow: true },
144
+ { id: "consolidations", label: "Consolidations", shortLabel: "CNS", description: "Number of memory consolidations", zone: "center", render: renderConsolidationsSegment, defaultShow: false },
145
145
  ];
@@ -56,6 +56,6 @@ function renderLastSentSegment(ctx: FooterSegmentContext): RenderedSegment {
56
56
  }
57
57
 
58
58
  export const NOTIFY_SEGMENTS: FooterSegment[] = [
59
- { id: "platforms_enabled", label: "Platforms", shortLabel: "NTF", description: "Active notification platforms", zone: "center", icon: "", render: renderPlatformsEnabledSegment, defaultShow: true },
60
- { id: "last_sent", label: "Last Sent", shortLabel: "LST", description: "Time of last notification sent", zone: "center", icon: "", render: renderLastSentSegment, defaultShow: true },
59
+ { id: "platforms_enabled", label: "Platforms", shortLabel: "NTF", description: "Active notification platforms", zone: "center", render: renderPlatformsEnabledSegment, defaultShow: true },
60
+ { id: "last_sent", label: "Last Sent", shortLabel: "LST", description: "Time of last notification sent", zone: "center", render: renderLastSentSegment, defaultShow: true },
61
61
  ];
@@ -117,7 +117,7 @@ function renderLoopStatusSegment(ctx: FooterSegmentContext): RenderedSegment {
117
117
  }
118
118
 
119
119
  export const RALPH_SEGMENTS: FooterSegment[] = [
120
- { id: "active_loops", label: "Loops", shortLabel: "RL", description: "Active Ralph loops", zone: "center", icon: "", render: renderActiveLoopsSegment, defaultShow: true },
121
- { id: "total_iterations", label: "Iterations", shortLabel: "ITR", description: "Total Ralph loop iterations", zone: "center", icon: "", render: renderTotalIterationsSegment, defaultShow: true },
122
- { id: "loop_status", label: "Status", shortLabel: "STS", description: "Current loop status", zone: "center", icon: "", render: renderLoopStatusSegment, defaultShow: true },
120
+ { id: "active_loops", label: "Loops", shortLabel: "RL", description: "Active Ralph loops", zone: "center", render: renderActiveLoopsSegment, defaultShow: true },
121
+ { id: "total_iterations", label: "Iterations", shortLabel: "ITR", description: "Total Ralph loop iterations", zone: "center", render: renderTotalIterationsSegment, defaultShow: true },
122
+ { id: "loop_status", label: "Status", shortLabel: "STS", description: "Current loop status", zone: "center", render: renderLoopStatusSegment, defaultShow: true },
123
123
  ];
@@ -120,5 +120,5 @@ function renderExtensionStatusesSegment(ctx: FooterSegmentContext): RenderedSegm
120
120
  }
121
121
 
122
122
  export const STATUS_EXT_SEGMENTS: FooterSegment[] = [
123
- { id: "extension_statuses", label: "Extensions", shortLabel: "EXT", description: "Extension statuses overview", zone: "center", icon: "", render: renderExtensionStatusesSegment, defaultShow: true },
123
+ { id: "extension_statuses", label: "Extensions", shortLabel: "EXT", description: "Extension statuses overview", zone: "center", render: renderExtensionStatusesSegment, defaultShow: true },
124
124
  ];
@@ -118,7 +118,7 @@ function formatDuration(ms: number): string {
118
118
  }
119
119
 
120
120
  export const WORKFLOW_SEGMENTS: FooterSegment[] = [
121
- { id: "current_command", label: "Command", shortLabel: "WRK", description: "Active workflow command", zone: "left", icon: "", render: renderCurrentCommandSegment, defaultShow: true },
122
- { id: "sandbox_level", label: "Sandbox", shortLabel: "SBX", description: "Sandbox permission level", zone: "center", icon: "", render: renderSandboxLevelSegment, defaultShow: false },
123
- { id: "command_duration", label: "Duration", shortLabel: "CDUR", description: "Current command duration", zone: "center", icon: "", render: renderCommandDurationSegment, defaultShow: true },
121
+ { id: "current_command", label: "Command", shortLabel: "WRK", description: "Active workflow command", zone: "left", render: renderCurrentCommandSegment, defaultShow: true },
122
+ { id: "sandbox_level", label: "Sandbox", shortLabel: "SBX", description: "Sandbox permission level", zone: "center", render: renderSandboxLevelSegment, defaultShow: false },
123
+ { id: "command_duration", label: "Duration", shortLabel: "CDUR", description: "Current command duration", zone: "center", render: renderCommandDurationSegment, defaultShow: true },
124
124
  ];
@@ -245,14 +245,6 @@ export class TpsTracker {
245
245
  return last.startedAt > 0 && last.completedAt === 0;
246
246
  }
247
247
 
248
- /**
249
- * Whether the model was recently generating tokens.
250
- * Kept for backward compatibility with renderer.
251
- */
252
- isGenerating(): boolean {
253
- return this.isStreaming();
254
- }
255
-
256
248
  /**
257
249
  * Get total output tokens for the session (estimated).
258
250
  */