@pi-unipi/unipi 2.0.13 → 2.1.1

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 (168) hide show
  1. package/LICENSE +0 -0
  2. package/package.json +28 -28
  3. package/packages/ask-user/handoff.ts +0 -0
  4. package/packages/ask-user/index.ts +3 -1
  5. package/packages/ask-user/launcher-ui.ts +0 -0
  6. package/packages/ask-user/package.json +5 -5
  7. package/packages/ask-user/tools.ts +20 -11
  8. package/packages/autocomplete/README.md +0 -0
  9. package/packages/autocomplete/package.json +4 -4
  10. package/packages/autocomplete/src/__tests__/command-registry.audit.test.ts +0 -0
  11. package/packages/autocomplete/src/__tests__/provider.sorting.test.ts +0 -0
  12. package/packages/autocomplete/src/constants.ts +0 -0
  13. package/packages/autocomplete/src/provider.ts +0 -0
  14. package/packages/autocomplete/src/sorting.ts +0 -0
  15. package/packages/btw/package.json +6 -6
  16. package/packages/cocoindex/README.md +0 -0
  17. package/packages/cocoindex/bridge.ts +0 -0
  18. package/packages/cocoindex/commands.ts +0 -0
  19. package/packages/cocoindex/index.ts +0 -0
  20. package/packages/cocoindex/installer.ts +0 -0
  21. package/packages/cocoindex/package.json +6 -6
  22. package/packages/cocoindex/skills/cocoindex/SKILL.md +0 -0
  23. package/packages/cocoindex/tools.ts +0 -0
  24. package/packages/compactor/package.json +7 -7
  25. package/packages/compactor/src/commands/index.ts +0 -0
  26. package/packages/compactor/src/compaction/auto-trigger.ts +0 -0
  27. package/packages/compactor/src/compaction/hooks.ts +0 -0
  28. package/packages/compactor/src/config/manager.ts +0 -0
  29. package/packages/compactor/src/config/presets.ts +0 -0
  30. package/packages/compactor/src/config/schema.ts +0 -0
  31. package/packages/compactor/src/display/diff-presentation.ts +0 -0
  32. package/packages/compactor/src/display/diff-renderer.ts +0 -0
  33. package/packages/compactor/src/display/diff-width-safety.ts +0 -0
  34. package/packages/compactor/src/display/line-width-safety.ts +0 -0
  35. package/packages/compactor/src/index.ts +0 -0
  36. package/packages/compactor/src/info-screen.ts +0 -0
  37. package/packages/compactor/src/session/analytics.ts +0 -0
  38. package/packages/compactor/src/session/db.ts +0 -0
  39. package/packages/compactor/src/session/recall-blocks.ts +0 -0
  40. package/packages/compactor/src/tools/ctx-batch-execute.ts +0 -0
  41. package/packages/compactor/src/tools/ctx-doctor.ts +0 -0
  42. package/packages/compactor/src/tools/ctx-stats.ts +0 -0
  43. package/packages/compactor/src/tools/register.ts +0 -0
  44. package/packages/compactor/src/tui/settings-overlay.ts +0 -0
  45. package/packages/compactor/src/types.ts +0 -0
  46. package/packages/core/constants.ts +0 -0
  47. package/packages/core/events.ts +0 -0
  48. package/packages/core/global-types.ts +0 -0
  49. package/packages/core/global.d.ts +0 -0
  50. package/packages/core/package.json +3 -3
  51. package/packages/core/sandbox.ts +0 -0
  52. package/packages/core/utils.ts +26 -0
  53. package/packages/footer/README.md +0 -0
  54. package/packages/footer/index.ts +0 -0
  55. package/packages/footer/package.json +5 -5
  56. package/packages/footer/src/commands.ts +0 -0
  57. package/packages/footer/src/config.ts +0 -0
  58. package/packages/footer/src/events.ts +0 -0
  59. package/packages/footer/src/help.ts +0 -0
  60. package/packages/footer/src/index.ts +71 -4
  61. package/packages/footer/src/presets.ts +0 -0
  62. package/packages/footer/src/registry/index.ts +0 -0
  63. package/packages/footer/src/rendering/icons.ts +0 -0
  64. package/packages/footer/src/rendering/renderer.ts +0 -0
  65. package/packages/footer/src/rendering/separators.ts +0 -0
  66. package/packages/footer/src/rendering/theme.ts +0 -0
  67. package/packages/footer/src/segments/compactor.ts +0 -0
  68. package/packages/footer/src/segments/core.ts +0 -0
  69. package/packages/footer/src/segments/kanboard.ts +0 -0
  70. package/packages/footer/src/segments/mcp.ts +0 -0
  71. package/packages/footer/src/segments/memory.ts +0 -0
  72. package/packages/footer/src/segments/notify.ts +0 -0
  73. package/packages/footer/src/segments/ralph.ts +0 -0
  74. package/packages/footer/src/segments/status-ext.ts +0 -0
  75. package/packages/footer/src/segments/workflow.ts +0 -0
  76. package/packages/footer/src/tps-tracker.ts +109 -33
  77. package/packages/footer/src/tui/settings-tui.ts +0 -0
  78. package/packages/footer/src/types.ts +0 -0
  79. package/packages/footer/types.ts +0 -0
  80. package/packages/info-screen/index.ts +3 -1
  81. package/packages/info-screen/package.json +5 -5
  82. package/packages/info-screen/tui/info-overlay.ts +16 -7
  83. package/packages/input-shortcuts/README.md +0 -0
  84. package/packages/input-shortcuts/index.ts +0 -0
  85. package/packages/input-shortcuts/package.json +5 -5
  86. package/packages/input-shortcuts/src/chord-overlay.ts +0 -0
  87. package/packages/input-shortcuts/src/clipboard.ts +0 -0
  88. package/packages/input-shortcuts/src/index.ts +0 -0
  89. package/packages/input-shortcuts/src/registers.ts +0 -0
  90. package/packages/input-shortcuts/src/settings-overlay.ts +0 -0
  91. package/packages/input-shortcuts/src/status.ts +0 -0
  92. package/packages/input-shortcuts/src/types.ts +0 -0
  93. package/packages/input-shortcuts/src/undo-redo.ts +0 -0
  94. package/packages/kanboard/index.ts +0 -0
  95. package/packages/kanboard/package.json +5 -5
  96. package/packages/mcp/package.json +5 -5
  97. package/packages/mcp/src/index.ts +3 -1
  98. package/packages/mcp/src/tui/settings-overlay.ts +0 -0
  99. package/packages/memory/README.md +51 -7
  100. package/packages/memory/index.ts +7 -4
  101. package/packages/memory/mempalace.ts +260 -0
  102. package/packages/memory/package.json +8 -5
  103. package/packages/memory/storage.ts +253 -22
  104. package/packages/memory/tools.ts +0 -0
  105. package/packages/milestone/commands.ts +3 -2
  106. package/packages/milestone/package.json +5 -5
  107. package/packages/notify/ask-user-prompt-message.ts +0 -0
  108. package/packages/notify/commands.ts +0 -0
  109. package/packages/notify/events.ts +0 -0
  110. package/packages/notify/index.ts +3 -1
  111. package/packages/notify/ntfy-config.ts +0 -0
  112. package/packages/notify/package.json +8 -6
  113. package/packages/notify/platforms/focus-win.ts +0 -0
  114. package/packages/notify/platforms/focus.ts +0 -0
  115. package/packages/notify/platforms/native.ts +0 -0
  116. package/packages/notify/settings.ts +0 -0
  117. package/packages/notify/src/__tests__/ask-user-prompt-message.test.ts +0 -0
  118. package/packages/notify/src/__tests__/event-bus.test.ts +0 -0
  119. package/packages/notify/tui/settings-overlay.ts +0 -0
  120. package/packages/notify/types.ts +0 -0
  121. package/packages/ralph/index.ts +3 -1
  122. package/packages/ralph/package.json +6 -6
  123. package/packages/subagents/package.json +8 -8
  124. package/packages/subagents/src/index.ts +27 -23
  125. package/packages/unipi/index.ts +0 -0
  126. package/packages/updater/README.md +0 -0
  127. package/packages/updater/index.ts +0 -0
  128. package/packages/updater/package.json +5 -5
  129. package/packages/updater/skills/configure-updater/SKILL.md +0 -0
  130. package/packages/updater/src/cache.ts +0 -0
  131. package/packages/updater/src/changelog.ts +0 -0
  132. package/packages/updater/src/checker.ts +0 -0
  133. package/packages/updater/src/commands.ts +0 -0
  134. package/packages/updater/src/installer.ts +0 -0
  135. package/packages/updater/src/markdown.ts +0 -0
  136. package/packages/updater/src/readme.ts +3 -1
  137. package/packages/updater/src/settings.ts +0 -0
  138. package/packages/updater/src/tui/changelog-overlay.ts +0 -0
  139. package/packages/updater/src/tui/readme-overlay.ts +0 -0
  140. package/packages/updater/src/tui/settings-overlay.ts +0 -0
  141. package/packages/updater/src/tui/update-overlay.ts +0 -0
  142. package/packages/updater/src/version.ts +0 -0
  143. package/packages/updater/types.ts +0 -0
  144. package/packages/utility/package.json +4 -4
  145. package/packages/utility/src/diff/renderer.ts +0 -0
  146. package/packages/utility/src/diff/theme.ts +0 -0
  147. package/packages/utility/src/diff/wrapper.ts +0 -0
  148. package/packages/utility/src/display/capabilities.ts +0 -0
  149. package/packages/utility/src/index.ts +3 -1
  150. package/packages/web-api/package.json +4 -4
  151. package/packages/web-api/skills/web/SKILL.md +0 -0
  152. package/packages/web-api/src/engine/constants.ts +0 -0
  153. package/packages/web-api/src/engine/dependencies.ts +0 -0
  154. package/packages/web-api/src/engine/dom.ts +0 -0
  155. package/packages/web-api/src/engine/extract.ts +0 -0
  156. package/packages/web-api/src/engine/format.ts +0 -0
  157. package/packages/web-api/src/engine/profiles.ts +0 -0
  158. package/packages/web-api/src/engine/types.ts +0 -0
  159. package/packages/web-api/src/index.ts +3 -1
  160. package/packages/web-api/src/providers/base.ts +0 -0
  161. package/packages/web-api/src/settings.ts +0 -0
  162. package/packages/web-api/src/tools.ts +0 -0
  163. package/packages/web-api/src/tui/progress.ts +0 -0
  164. package/packages/web-api/src/tui/result.ts +0 -0
  165. package/packages/web-api/src/tui/settings-dialog.ts +0 -0
  166. package/packages/workflow/commands.ts +0 -0
  167. package/packages/workflow/index.ts +3 -1
  168. package/packages/workflow/package.json +5 -5
package/LICENSE CHANGED
File without changes
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pi-unipi/unipi",
3
- "version": "2.0.13",
3
+ "version": "2.1.1",
4
4
  "description": "All-in-one extension suite for Pi coding agent",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -59,38 +59,38 @@
59
59
  ]
60
60
  },
61
61
  "peerDependencies": {
62
- "@earendil-works/pi-ai": "^0.78.0",
63
- "@earendil-works/pi-coding-agent": "^0.78.0",
64
- "@earendil-works/pi-tui": "^0.78.0",
62
+ "@earendil-works/pi-ai": "^0.80.0",
63
+ "@earendil-works/pi-coding-agent": "^0.80.0",
64
+ "@earendil-works/pi-tui": "^0.80.0",
65
65
  "typebox": "^1.1.38"
66
66
  },
67
67
  "dependencies": {
68
- "@pi-unipi/ask-user": "2.0.13",
69
- "@pi-unipi/btw": "2.0.13",
70
- "@pi-unipi/compactor": "2.0.13",
71
- "@pi-unipi/notify": "2.0.13",
72
- "@pi-unipi/command-enchantment": "2.0.13",
73
- "@pi-unipi/core": "2.0.13",
74
- "@pi-unipi/info-screen": "2.0.13",
75
- "@pi-unipi/mcp": "2.0.13",
76
- "@pi-unipi/memory": "2.0.13",
77
- "@pi-unipi/ralph": "2.0.13",
78
- "@pi-unipi/subagents": "2.0.13",
79
- "@pi-unipi/utility": "2.0.13",
80
- "@pi-unipi/milestone": "2.0.13",
81
- "@pi-unipi/kanboard": "2.0.13",
82
- "@pi-unipi/web-api": "2.0.13",
83
- "@pi-unipi/workflow": "2.0.13",
84
- "@pi-unipi/footer": "2.0.13",
85
- "@pi-unipi/updater": "2.0.13",
86
- "@pi-unipi/input-shortcuts": "2.0.13",
87
- "@pi-unipi/cocoindex": "2.0.13"
68
+ "@pi-unipi/ask-user": "2.1.1",
69
+ "@pi-unipi/btw": "2.1.1",
70
+ "@pi-unipi/compactor": "2.1.1",
71
+ "@pi-unipi/notify": "2.1.1",
72
+ "@pi-unipi/command-enchantment": "2.1.1",
73
+ "@pi-unipi/core": "2.1.1",
74
+ "@pi-unipi/info-screen": "2.1.1",
75
+ "@pi-unipi/mcp": "2.1.1",
76
+ "@pi-unipi/memory": "2.1.1",
77
+ "@pi-unipi/ralph": "2.1.1",
78
+ "@pi-unipi/subagents": "2.1.1",
79
+ "@pi-unipi/utility": "2.1.1",
80
+ "@pi-unipi/milestone": "2.1.1",
81
+ "@pi-unipi/kanboard": "2.1.1",
82
+ "@pi-unipi/web-api": "2.1.1",
83
+ "@pi-unipi/workflow": "2.1.1",
84
+ "@pi-unipi/footer": "2.1.1",
85
+ "@pi-unipi/updater": "2.1.1",
86
+ "@pi-unipi/input-shortcuts": "2.1.1",
87
+ "@pi-unipi/cocoindex": "2.1.1"
88
88
  },
89
89
  "devDependencies": {
90
- "@earendil-works/pi-agent-core": "^0.78.0",
91
- "@earendil-works/pi-ai": "^0.78.0",
92
- "@earendil-works/pi-coding-agent": "^0.78.0",
93
- "@earendil-works/pi-tui": "^0.78.0",
90
+ "@earendil-works/pi-agent-core": "^0.80.0",
91
+ "@earendil-works/pi-ai": "^0.80.0",
92
+ "@earendil-works/pi-coding-agent": "^0.80.0",
93
+ "@earendil-works/pi-tui": "^0.80.0",
94
94
  "@types/node": "^25.6.0",
95
95
  "tsx": "^4.21.0",
96
96
  "typescript": "^6.0.0"
File without changes
@@ -5,6 +5,8 @@
5
5
  * multi-select, and freeform modes. Includes bundled skill for agent guidance.
6
6
  */
7
7
 
8
+ import { dirname } from "node:path";
9
+ import { fileURLToPath } from "node:url";
8
10
  import type { ExtensionAPI } from "@earendil-works/pi-coding-agent";
9
11
  import {
10
12
  UNIPI_EVENTS,
@@ -17,7 +19,7 @@ import { registerAskUserTools } from "./tools.js";
17
19
  import { registerAskUserCommands } from "./commands.js";
18
20
 
19
21
  /** Package version */
20
- const VERSION = getPackageVersion(new URL(".", import.meta.url).pathname);
22
+ const VERSION = getPackageVersion(dirname(fileURLToPath(import.meta.url)));
21
23
 
22
24
  export default function (pi: ExtensionAPI) {
23
25
 
File without changes
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@pi-unipi/ask-user",
3
- "version": "2.0.13",
4
- "description": "Structured user input tool for Pi coding agent \u2014 single-select, multi-select, freeform",
3
+ "version": "2.1.1",
4
+ "description": "Structured user input tool for Pi coding agent single-select, multi-select, freeform",
5
5
  "type": "module",
6
6
  "main": "index.ts",
7
7
  "license": "MIT",
@@ -40,11 +40,11 @@
40
40
  "access": "public"
41
41
  },
42
42
  "dependencies": {
43
- "@pi-unipi/core": "2.0.13"
43
+ "@pi-unipi/core": "2.1.1"
44
44
  },
45
45
  "peerDependencies": {
46
- "@earendil-works/pi-coding-agent": "^0.78.0",
47
- "@earendil-works/pi-tui": "^0.78.0",
46
+ "@earendil-works/pi-coding-agent": "^0.80.0",
47
+ "@earendil-works/pi-tui": "^0.80.0",
48
48
  "typebox": "^1.1.38"
49
49
  },
50
50
  "pi": {
@@ -11,6 +11,7 @@ import {
11
11
  COMPACTOR_INSTRUCTION,
12
12
  UNIPI_EVENTS,
13
13
  emitEvent,
14
+ withHerdrBlocked,
14
15
  } from "@pi-unipi/core";
15
16
  import type { NormalizedOption, AskUserResponse, SessionLauncherResult } from "./types.js";
16
17
  import { renderAskUI, createRenderCall, createRenderResult } from "./ask-ui.js";
@@ -272,15 +273,19 @@ export function registerAskUserTools(pi: ExtensionAPI): void {
272
273
  }
273
274
 
274
275
  // Render interactive UI
275
- const result = await ctx.ui.custom<{ response: AskUserResponse } | null>(
276
- renderAskUI({
277
- question,
278
- context,
279
- options: normalizedOptions,
280
- allowMultiple,
281
- allowFreeform,
282
- timeout,
283
- }),
276
+ const result = await withHerdrBlocked(
277
+ pi,
278
+ "ask_user",
279
+ () => ctx.ui.custom<{ response: AskUserResponse } | null>(
280
+ renderAskUI({
281
+ question,
282
+ context,
283
+ options: normalizedOptions,
284
+ allowMultiple,
285
+ allowFreeform,
286
+ timeout,
287
+ }),
288
+ ),
284
289
  );
285
290
 
286
291
  // Handle cancel
@@ -346,8 +351,12 @@ export function registerAskUserTools(pi: ExtensionAPI): void {
346
351
  // Session launcher intercept: when user selects new_session, offer compact/direct/cancel
347
352
  if (response.kind === "new_session") {
348
353
  const prefill = response.prefill || "";
349
- const launcherResult = await ctx.ui.custom<SessionLauncherResult | null>(
350
- renderLauncherUI({ prefill }),
354
+ const launcherResult = await withHerdrBlocked(
355
+ pi,
356
+ "ask_user: launch",
357
+ () => ctx.ui.custom<SessionLauncherResult | null>(
358
+ renderLauncherUI({ prefill }),
359
+ ),
351
360
  );
352
361
 
353
362
  if (!launcherResult || launcherResult.action === "cancel") {
File without changes
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@pi-unipi/command-enchantment",
3
- "version": "2.0.13",
4
- "description": "Enhanced TUI autocomplete for /unipi:* commands \u2014 colored, sorted, and grouped by package",
3
+ "version": "2.1.1",
4
+ "description": "Enhanced TUI autocomplete for /unipi:* commands colored, sorted, and grouped by package",
5
5
  "type": "module",
6
6
  "main": "src/index.ts",
7
7
  "license": "MIT",
@@ -27,8 +27,8 @@
27
27
  "README.md"
28
28
  ],
29
29
  "peerDependencies": {
30
- "@earendil-works/pi-coding-agent": "^0.78.0",
31
- "@earendil-works/pi-tui": "^0.78.0"
30
+ "@earendil-works/pi-coding-agent": "^0.80.0",
31
+ "@earendil-works/pi-tui": "^0.80.0"
32
32
  },
33
33
  "scripts": {
34
34
  "test": "vitest run"
File without changes
File without changes
File without changes
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@pi-unipi/btw",
3
- "version": "2.0.13",
4
- "description": "A pi extension for parallel side conversations with /unipi:btw \u2014 part of the Unipi suite",
3
+ "version": "2.1.1",
4
+ "description": "A pi extension for parallel side conversations with /unipi:btw part of the Unipi suite",
5
5
  "type": "module",
6
6
  "main": "extensions/btw.ts",
7
7
  "license": "MIT",
@@ -32,12 +32,12 @@
32
32
  "access": "public"
33
33
  },
34
34
  "peerDependencies": {
35
- "@earendil-works/pi-ai": "^0.78.0",
36
- "@earendil-works/pi-coding-agent": "^0.78.0",
37
- "@earendil-works/pi-tui": "^0.78.0"
35
+ "@earendil-works/pi-ai": "^0.80.0",
36
+ "@earendil-works/pi-coding-agent": "^0.80.0",
37
+ "@earendil-works/pi-tui": "^0.80.0"
38
38
  },
39
39
  "dependencies": {
40
- "@pi-unipi/core": "2.0.13"
40
+ "@pi-unipi/core": "2.1.1"
41
41
  },
42
42
  "pi": {
43
43
  "extensions": [],
File without changes
File without changes
File without changes
File without changes
File without changes
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@pi-unipi/cocoindex",
3
- "version": "2.0.13",
4
- "description": "CocoIndex integration for Pi \u2014 AST-aware content indexing, semantic vector search, and incremental pipeline management",
3
+ "version": "2.1.1",
4
+ "description": "CocoIndex integration for Pi AST-aware content indexing, semantic vector search, and incremental pipeline management",
5
5
  "type": "module",
6
6
  "main": "index.ts",
7
7
  "types": "index.ts",
@@ -19,13 +19,13 @@
19
19
  "typecheck": "tsc --noEmit"
20
20
  },
21
21
  "peerDependencies": {
22
- "@earendil-works/pi-coding-agent": "^0.78.0",
23
- "@earendil-works/pi-ai": "^0.78.0",
24
- "@earendil-works/pi-tui": "^0.78.0",
22
+ "@earendil-works/pi-coding-agent": "^0.80.0",
23
+ "@earendil-works/pi-ai": "^0.80.0",
24
+ "@earendil-works/pi-tui": "^0.80.0",
25
25
  "typebox": "^1.1.38"
26
26
  },
27
27
  "dependencies": {
28
- "@pi-unipi/core": "2.0.13"
28
+ "@pi-unipi/core": "2.1.1"
29
29
  },
30
30
  "optionalDependencies": {
31
31
  "@lancedb/lancedb": "^0.21.0"
File without changes
File without changes
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@pi-unipi/compactor",
3
- "version": "2.0.13",
4
- "description": "Context engine for Pi \u2014 zero-LLM compaction, session continuity, sandbox execution, and tool display optimization",
3
+ "version": "2.1.1",
4
+ "description": "Context engine for Pi zero-LLM compaction, session continuity, sandbox execution, and tool display optimization",
5
5
  "type": "module",
6
6
  "main": "src/index.ts",
7
7
  "license": "MIT",
@@ -34,13 +34,13 @@
34
34
  "access": "public"
35
35
  },
36
36
  "dependencies": {
37
- "@pi-unipi/core": "2.0.13",
38
- "@pi-unipi/info-screen": "2.0.13",
39
- "@earendil-works/pi-agent-core": "^0.78.0"
37
+ "@pi-unipi/core": "2.1.1",
38
+ "@pi-unipi/info-screen": "2.1.1",
39
+ "@earendil-works/pi-agent-core": "^0.80.0"
40
40
  },
41
41
  "peerDependencies": {
42
- "@earendil-works/pi-coding-agent": "^0.78.0",
43
- "@earendil-works/pi-tui": "^0.78.0",
42
+ "@earendil-works/pi-coding-agent": "^0.80.0",
43
+ "@earendil-works/pi-tui": "^0.80.0",
44
44
  "typebox": "^1.1.38"
45
45
  },
46
46
  "devDependencies": {
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pi-unipi/core",
3
- "version": "2.0.13",
3
+ "version": "2.1.1",
4
4
  "description": "Shared utilities, event types, and constants for Unipi extension suite",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -23,11 +23,11 @@
23
23
  "access": "public"
24
24
  },
25
25
  "peerDependencies": {
26
- "@earendil-works/pi-coding-agent": "^0.78.0",
26
+ "@earendil-works/pi-coding-agent": "^0.80.0",
27
27
  "typebox": "^1.1.38"
28
28
  },
29
29
  "devDependencies": {
30
- "@earendil-works/pi-coding-agent": "^0.78.0",
30
+ "@earendil-works/pi-coding-agent": "^0.80.0",
31
31
  "typebox": "^1.1.38",
32
32
  "@types/node": "^22.0.0"
33
33
  },
File without changes
@@ -240,3 +240,29 @@ export function emitEvent(
240
240
  return false;
241
241
  }
242
242
  }
243
+
244
+ /**
245
+ * Wrap an awaitable blocking-UI operation with herdr `blocked` state reporting.
246
+ *
247
+ * Emits `herdr:blocked` active (with a label) before awaiting `fn`, and
248
+ * inactive (with matching label) afterwards — including on throw. This lets
249
+ * the herdr integration surface `blocked` agent status for ask_user and other
250
+ * stop-and-continue UIs instead of `working`.
251
+ *
252
+ * The label should match what's shown to the user so herdr's sidebar reads
253
+ * meaningfully (e.g. "ask_user", "helper viewer").
254
+ */
255
+ export async function withHerdrBlocked<T>(
256
+ pi: { events: { emit: (name: string, payload: unknown) => void } },
257
+ label: string,
258
+ fn: () => Promise<T>,
259
+ ): Promise<T> {
260
+ const event = (active: boolean) =>
261
+ emitEvent(pi, "herdr:blocked", { active, label });
262
+ event(true);
263
+ try {
264
+ return await fn();
265
+ } finally {
266
+ event(false);
267
+ }
268
+ }
File without changes
File without changes
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@pi-unipi/footer",
3
- "version": "2.0.13",
4
- "description": "Persistent status bar for Unipi \u2014 subscribes to UNIPI_EVENTS and renders key stats from all unipi packages",
3
+ "version": "2.1.1",
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": "src/index.ts",
7
7
  "license": "MIT",
@@ -32,11 +32,11 @@
32
32
  "access": "public"
33
33
  },
34
34
  "dependencies": {
35
- "@pi-unipi/core": "2.0.13"
35
+ "@pi-unipi/core": "2.1.1"
36
36
  },
37
37
  "peerDependencies": {
38
- "@earendil-works/pi-coding-agent": "^0.78.0",
39
- "@earendil-works/pi-tui": "^0.78.0"
38
+ "@earendil-works/pi-coding-agent": "^0.80.0",
39
+ "@earendil-works/pi-tui": "^0.80.0"
40
40
  },
41
41
  "devDependencies": {
42
42
  "@types/node": "^25.6.0",
File without changes
File without changes
File without changes
File without changes
@@ -96,6 +96,14 @@ export default function footerExtension(pi: ExtensionAPI): void {
96
96
  state.registry.registerGroup(group);
97
97
  }
98
98
 
99
+ // ─── TPS streaming-event hooks (registered once) ────────────────────────
100
+ // pi.on() has no unsubscribe, so we register these exactly once at factory
101
+ // time (not per session_start) to avoid duplicate handlers accumulating
102
+ // across session restarts. The streamingIndex counter is reset on each
103
+ // session_shutdown. These hooks feed the TPS tracker in real time; the
104
+ // 1s branch-scan in the refresh timer only reconciles persisted messages.
105
+ wireTpsStreamingEvents(pi);
106
+
99
107
  // ─── Session lifecycle ──────────────────────────────────────────────────
100
108
 
101
109
  pi.on("session_start", async (_event, ctx) => {
@@ -127,6 +135,7 @@ export default function footerExtension(pi: ExtensionAPI): void {
127
135
  }
128
136
  state.tuiRef = null;
129
137
  tpsTracker.reset();
138
+ resetTpsStreamingIndex();
130
139
  });
131
140
 
132
141
  // ─── Register commands ──────────────────────────────────────────────────
@@ -152,10 +161,14 @@ function setupFooterUI(pi: ExtensionAPI, ctx: ExtensionContext, state: FooterSta
152
161
  ctx.ui.setFooter((tui, _theme, footerData) => {
153
162
  state.tuiRef = tui;
154
163
 
155
- // Start periodic refresh for time-sensitive segments (e.g. clock)
164
+ // Start periodic refresh for time-sensitive segments (e.g. clock, TPS)
156
165
  if (!state.refreshTimer) {
157
166
  state.refreshTimer = setInterval(() => {
158
- // Feed TPS tracker with per-message data
167
+ // Re-seed TPS tracker from the session branch on each tick.
168
+ // Streaming events (message_start/update/end) handle live updates
169
+ // in real time; this scan reconciles the tracker with persisted
170
+ // messages after compactions, branch switches, or session reloads
171
+ // where in-flight streaming state may have been lost.
159
172
  try {
160
173
  const piCtx = state.piContext as Record<string, unknown> | undefined;
161
174
  if (piCtx?.sessionManager) {
@@ -168,9 +181,10 @@ function setupFooterUI(pi: ExtensionAPI, ctx: ExtensionContext, state: FooterSta
168
181
  const m = e.message;
169
182
  if (!m || m.role !== "assistant") continue;
170
183
  if (m.stopReason === "error" || m.stopReason === "aborted") continue;
171
- const output = m.usage?.output ?? 0;
172
184
  const hasStop = !!m.stopReason;
173
- tpsTracker.onMessageUpdate(msgIndex, output, hasStop);
185
+ // Pass the whole message: TPS tracker counts tokens from content,
186
+ // not from usage.output (which is 0 during streaming).
187
+ tpsTracker.onMessageUpdate(msgIndex, m, hasStop);
174
188
  msgIndex++;
175
189
  }
176
190
  }
@@ -251,3 +265,56 @@ function setupFooterUI(pi: ExtensionAPI, ctx: ExtensionContext, state: FooterSta
251
265
  };
252
266
  }, { placement: "belowEditor" });
253
267
  }
268
+
269
+ // ─── TPS streaming-event hooks ──────────────────────────────────────────────
270
+
271
+ /**
272
+ * Sequential index of the currently-streaming assistant message. Tracked
273
+ * locally because pi does not expose a stable message index on streaming
274
+ * events, and the TPS tracker keys records off this index.
275
+ */
276
+ let tpsStreamingIndex = -1;
277
+
278
+ /** Reset the streaming index (called on session_shutdown). */
279
+ function resetTpsStreamingIndex(): void {
280
+ tpsStreamingIndex = -1;
281
+ }
282
+
283
+ /**
284
+ * Subscribe to pi's message streaming events and feed the TPS tracker in real
285
+ * time. This complements the 1s branch-scan in the refresh timer, which only
286
+ * sees persisted (completed) messages. Without these hooks the tracker would
287
+ * never observe an in-flight assistant message, so live TPS would stay frozen
288
+ * at the last completed message's value.
289
+ *
290
+ * Registered once at extension-factory time (pi.on has no unsubscribe, so we
291
+ * must not re-register per session_start or handlers would accumulate).
292
+ */
293
+ function wireTpsStreamingEvents(pi: ExtensionAPI): void {
294
+ const safe = (fn: () => void) => {
295
+ try { fn(); } catch { /* TPS is best-effort */ }
296
+ };
297
+
298
+ pi.on("message_start", ((event: { message: unknown }) => safe(() => {
299
+ const m = event.message as Record<string, unknown> | undefined;
300
+ if (!m || m.role !== "assistant") return;
301
+ if (m.stopReason === "error" || m.stopReason === "aborted") return;
302
+ tpsStreamingIndex++;
303
+ tpsTracker.onMessageUpdate(tpsStreamingIndex, m, false);
304
+ })) as (event: unknown) => void);
305
+
306
+ pi.on("message_update", ((event: { message: unknown }) => safe(() => {
307
+ if (tpsStreamingIndex < 0) return;
308
+ const m = event.message as Record<string, unknown> | undefined;
309
+ if (!m || m.role !== "assistant") return;
310
+ tpsTracker.onMessageUpdate(tpsStreamingIndex, m, false);
311
+ })) as (event: unknown) => void);
312
+
313
+ pi.on("message_end", ((event: { message: unknown }) => safe(() => {
314
+ if (tpsStreamingIndex < 0) return;
315
+ const m = event.message as Record<string, unknown> | undefined;
316
+ if (!m || m.role !== "assistant") return;
317
+ if (m.stopReason === "error" || m.stopReason === "aborted") return;
318
+ tpsTracker.onMessageUpdate(tpsStreamingIndex, m, true);
319
+ })) as (event: unknown) => void);
320
+ }
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes