@pi-unipi/unipi 2.14.0 → 2.14.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 (33) hide show
  1. package/CHANGELOG.md +11 -0
  2. package/package.json +23 -23
  3. package/packages/ask-user/package.json +3 -3
  4. package/packages/autocomplete/package.json +1 -1
  5. package/packages/autocomplete/src/constants.ts +2 -0
  6. package/packages/background-tasks/package.json +3 -3
  7. package/packages/btw/package.json +3 -3
  8. package/packages/compactor/package.json +4 -4
  9. package/packages/core/constants.ts +1 -0
  10. package/packages/core/package.json +1 -1
  11. package/packages/footer/package.json +4 -4
  12. package/packages/image/package.json +2 -2
  13. package/packages/info-screen/index.ts +49 -10
  14. package/packages/info-screen/package.json +3 -3
  15. package/packages/info-screen/tui/info-overlay.ts +54 -22
  16. package/packages/input-shortcuts/package.json +3 -3
  17. package/packages/kanboard/package.json +3 -3
  18. package/packages/mcp/package.json +3 -3
  19. package/packages/memory/package.json +3 -3
  20. package/packages/milestone/package.json +3 -3
  21. package/packages/notify/package.json +3 -3
  22. package/packages/ralph/package.json +3 -3
  23. package/packages/subagents/package.json +3 -3
  24. package/packages/trajectory/package.json +1 -1
  25. package/packages/unipi/bundled.js +886 -687
  26. package/packages/updater/package.json +3 -3
  27. package/packages/utility/README.md +20 -0
  28. package/packages/utility/package.json +3 -3
  29. package/packages/utility/src/commands.ts +54 -0
  30. package/packages/utility/src/index.ts +15 -0
  31. package/packages/utility/src/skill-discovery.ts +178 -0
  32. package/packages/web-api/package.json +2 -2
  33. package/packages/workflow/package.json +2 -2
package/CHANGELOG.md CHANGED
@@ -6,6 +6,17 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/).
6
6
 
7
7
  ## [Unreleased]
8
8
 
9
+ ## [2.14.1] — 2026-08-28
10
+
11
+ ### Added
12
+
13
+ - `utility`: **skill startup discovery toggle** (`/unipi:skills-settings`, default on) — controls whether Unipi's built-in skills are cataloged in the agent's system prompt at startup. When off (`unipi.skills.discovery: false` in pi settings.json), Unipi's bundled skills are removed from the `<available_skills>` section every turn while user-owned skills (global, project, settings-mounted, third-party packages) stay cataloged; `/skill:name` invocation keeps working since pi expands those commands by reading SKILL.md directly from disk. Filtering is anchor-based (agentskills.io tags) and applied consistently per turn, preserving provider prefix cache.
14
+ - `autocomplete`: registered `/unipi:skills-settings` in COMMAND_REGISTRY + COMMAND_DESCRIPTIONS so the command autosuggests.
15
+
16
+ ### Fixed
17
+
18
+ - `info-screen`: **boot splash no longer eats keystrokes or strands the session** — the auto-close boot dashboard was a capturing overlay during its 2s window: typing during boot was swallowed (worse, its vim-style keys interpreted command text as tab switches), the first-keypress-cancels-auto-close rule left it on screen forever as an unclosable input-eating zombie, and prompts appeared to never send (the agent actually responded behind the overlay). The splash is now non-capturing (typing always reaches the editor) and dismisses itself via a stack-safe `handle.hide()` that only fires while it is the topmost visible overlay entry — if the user opens any dialog during the splash window (e.g. `/unipi:skills-settings`), dismissal defers until it closes, so the overlay can no longer be orphaned with a pending interaction (previously the covered overlay vanished while its `ctx.ui.select` promise hung forever). Interactive (`bootMode: "on"`) dashboards are unchanged; splash footer now reads "auto-dismissing…" instead of keyboard hints that could never reach it.
19
+
9
20
  ## [2.14.0] — 2026-08-29
10
21
 
11
22
  ### Changed
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pi-unipi/unipi",
3
- "version": "2.14.0",
3
+ "version": "2.14.1",
4
4
  "description": "All-in-one extension suite for Pi coding agent",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -82,28 +82,28 @@
82
82
  "typebox": "^1.1.38"
83
83
  },
84
84
  "dependencies": {
85
- "@pi-unipi/ask-user": "2.14.0",
86
- "@pi-unipi/background-tasks": "2.14.0",
87
- "@pi-unipi/btw": "2.14.0",
88
- "@pi-unipi/command-enchantment": "2.14.0",
89
- "@pi-unipi/compactor": "2.14.0",
90
- "@pi-unipi/core": "2.14.0",
91
- "@pi-unipi/footer": "2.14.0",
92
- "@pi-unipi/image": "2.14.0",
93
- "@pi-unipi/info-screen": "2.14.0",
94
- "@pi-unipi/input-shortcuts": "2.14.0",
95
- "@pi-unipi/kanboard": "2.14.0",
96
- "@pi-unipi/mcp": "2.14.0",
97
- "@pi-unipi/memory": "2.14.0",
98
- "@pi-unipi/milestone": "2.14.0",
99
- "@pi-unipi/notify": "2.14.0",
100
- "@pi-unipi/ralph": "2.14.0",
101
- "@pi-unipi/subagents": "2.14.0",
102
- "@pi-unipi/trajectory": "2.14.0",
103
- "@pi-unipi/updater": "2.14.0",
104
- "@pi-unipi/utility": "2.14.0",
105
- "@pi-unipi/web-api": "2.14.0",
106
- "@pi-unipi/workflow": "2.14.0"
85
+ "@pi-unipi/ask-user": "2.14.1",
86
+ "@pi-unipi/background-tasks": "2.14.1",
87
+ "@pi-unipi/btw": "2.14.1",
88
+ "@pi-unipi/command-enchantment": "2.14.1",
89
+ "@pi-unipi/compactor": "2.14.1",
90
+ "@pi-unipi/core": "2.14.1",
91
+ "@pi-unipi/footer": "2.14.1",
92
+ "@pi-unipi/image": "2.14.1",
93
+ "@pi-unipi/info-screen": "2.14.1",
94
+ "@pi-unipi/input-shortcuts": "2.14.1",
95
+ "@pi-unipi/kanboard": "2.14.1",
96
+ "@pi-unipi/mcp": "2.14.1",
97
+ "@pi-unipi/memory": "2.14.1",
98
+ "@pi-unipi/milestone": "2.14.1",
99
+ "@pi-unipi/notify": "2.14.1",
100
+ "@pi-unipi/ralph": "2.14.1",
101
+ "@pi-unipi/subagents": "2.14.1",
102
+ "@pi-unipi/trajectory": "2.14.1",
103
+ "@pi-unipi/updater": "2.14.1",
104
+ "@pi-unipi/utility": "2.14.1",
105
+ "@pi-unipi/web-api": "2.14.1",
106
+ "@pi-unipi/workflow": "2.14.1"
107
107
  },
108
108
  "devDependencies": {
109
109
  "@earendil-works/pi-agent-core": "^0.84.0",
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@pi-unipi/ask-user",
3
- "version": "2.14.0",
4
- "description": "Structured user input tool for Pi coding agent single-select, multi-select, freeform",
3
+ "version": "2.14.1",
4
+ "description": "Structured user input tool for Pi coding agent \u2014 single-select, multi-select, freeform",
5
5
  "type": "module",
6
6
  "main": "index.ts",
7
7
  "license": "MIT",
@@ -40,7 +40,7 @@
40
40
  "access": "public"
41
41
  },
42
42
  "dependencies": {
43
- "@pi-unipi/core": "2.14.0"
43
+ "@pi-unipi/core": "2.14.1"
44
44
  },
45
45
  "peerDependencies": {
46
46
  "@earendil-works/pi-coding-agent": "^0.84.0",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pi-unipi/command-enchantment",
3
- "version": "2.14.0",
3
+ "version": "2.14.1",
4
4
  "description": "Enhanced TUI autocomplete for /unipi:* commands — colored, sorted, and grouped by package",
5
5
  "type": "module",
6
6
  "main": "src/index.ts",
@@ -131,6 +131,7 @@ export const COMMAND_REGISTRY: Record<string, string> = {
131
131
  "unipi:badge-toggle": "utility",
132
132
  "unipi:badge-settings": "utility",
133
133
  "unipi:util-settings": "utility",
134
+ "unipi:skills-settings": "utility",
134
135
 
135
136
  // ask-user (1 command)
136
137
  "unipi:ask-user-settings": "ask-user",
@@ -270,6 +271,7 @@ export const COMMAND_DESCRIPTIONS: Record<string, string> = {
270
271
  "unipi:badge-toggle": "Configure badge settings (autoGen, badgeEnabled, agentTool)",
271
272
  "unipi:badge-settings": "Configure badge settings via TUI overlay",
272
273
  "unipi:util-settings": "Unified settings — badge + diff rendering config",
274
+ "unipi:skills-settings": "Toggle skill startup discovery (skills catalog in system prompt)",
273
275
  "unipi:kanboard": "Start the kanboard visualization server",
274
276
  "unipi:kanboard-doctor": "Diagnose and fix kanboard parser issues",
275
277
  "unipi:trajectory": "Open/reuse trajectory; add stop/off or toggle to close it",
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@pi-unipi/background-tasks",
3
- "version": "2.14.0",
4
- "description": "Background tasks for UniPi durable shell jobs, delegated agents, attested Pi runs, and fixed-purpose Fusion workflows",
3
+ "version": "2.14.1",
4
+ "description": "Background tasks for UniPi \u2014 durable shell jobs, delegated agents, attested Pi runs, and fixed-purpose Fusion workflows",
5
5
  "type": "module",
6
6
  "main": "src/index.ts",
7
7
  "types": "src/index.ts",
@@ -10,7 +10,7 @@
10
10
  },
11
11
  "dependencies": {
12
12
  "@earendil-works/pi-ai": "^0.84.0",
13
- "@pi-unipi/core": "2.14.0",
13
+ "@pi-unipi/core": "2.14.1",
14
14
  "turndown": "^7.2.4"
15
15
  },
16
16
  "devDependencies": {
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@pi-unipi/btw",
3
- "version": "2.14.0",
4
- "description": "A pi extension for parallel side conversations with /unipi:btw part of the Unipi suite",
3
+ "version": "2.14.1",
4
+ "description": "A pi extension for parallel side conversations with /unipi:btw \u2014 part of the Unipi suite",
5
5
  "type": "module",
6
6
  "main": "extensions/btw.ts",
7
7
  "license": "MIT",
@@ -37,7 +37,7 @@
37
37
  "@earendil-works/pi-tui": "^0.84.0"
38
38
  },
39
39
  "dependencies": {
40
- "@pi-unipi/core": "2.14.0"
40
+ "@pi-unipi/core": "2.14.1"
41
41
  },
42
42
  "pi": {
43
43
  "extensions": [
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@pi-unipi/compactor",
3
- "version": "2.14.0",
4
- "description": "Context engine for Pi zero-LLM compaction, session continuity, sandbox execution, and tool display optimization",
3
+ "version": "2.14.1",
4
+ "description": "Context engine for Pi \u2014 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,8 +34,8 @@
34
34
  "access": "public"
35
35
  },
36
36
  "dependencies": {
37
- "@pi-unipi/core": "2.14.0",
38
- "@pi-unipi/info-screen": "2.14.0",
37
+ "@pi-unipi/core": "2.14.1",
38
+ "@pi-unipi/info-screen": "2.14.1",
39
39
  "@earendil-works/pi-agent-core": "^0.84.0"
40
40
  },
41
41
  "peerDependencies": {
@@ -161,6 +161,7 @@ export const UTILITY_COMMANDS = {
161
161
  BADGE_SETTINGS: "badge-settings",
162
162
  UTIL_SETTINGS: "util-settings",
163
163
  PREFIX_CACHE: "prefix-cache",
164
+ SKILLS_SETTINGS: "skills-settings",
164
165
  } as const;
165
166
 
166
167
  /** Utility tool names */
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pi-unipi/core",
3
- "version": "2.14.0",
3
+ "version": "2.14.1",
4
4
  "description": "Shared utilities, event types, and constants for Unipi extension suite",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@pi-unipi/footer",
3
- "version": "2.14.0",
4
- "description": "Persistent status bar for Unipi subscribes to UNIPI_EVENTS and renders key stats from all unipi packages",
3
+ "version": "2.14.1",
4
+ "description": "Persistent status bar for Unipi \u2014 subscribes to UNIPI_EVENTS and renders key stats from all unipi packages",
5
5
  "type": "module",
6
6
  "main": "index.ts",
7
7
  "license": "MIT",
@@ -32,8 +32,8 @@
32
32
  "access": "public"
33
33
  },
34
34
  "dependencies": {
35
- "@pi-unipi/core": "2.14.0",
36
- "@pi-unipi/background-tasks": "2.14.0"
35
+ "@pi-unipi/core": "2.14.1",
36
+ "@pi-unipi/background-tasks": "2.14.1"
37
37
  },
38
38
  "peerDependencies": {
39
39
  "@earendil-works/pi-coding-agent": "^0.84.0",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pi-unipi/image",
3
- "version": "2.14.0",
3
+ "version": "2.14.1",
4
4
  "description": "Image generation and image recognition tools for the Pi coding agent",
5
5
  "type": "module",
6
6
  "main": "src/index.ts",
@@ -34,7 +34,7 @@
34
34
  "access": "public"
35
35
  },
36
36
  "dependencies": {
37
- "@pi-unipi/core": "2.14.0"
37
+ "@pi-unipi/core": "2.14.1"
38
38
  },
39
39
  "peerDependencies": {
40
40
  "@earendil-works/pi-ai": "^0.84.0",
@@ -113,10 +113,19 @@ export default function (pi: ExtensionAPI) {
113
113
  */
114
114
  function showOverlay(ctx: ExtensionContext, autoCloseMs?: number): void {
115
115
  let overlay: InfoOverlay;
116
+ // Splash mode (auto-close): the overlay must NEVER take keyboard focus —
117
+ // it lives exactly during the window where the user starts typing their
118
+ // first prompt. A capturing overlay here eats those keystrokes (worse: its
119
+ // vim-style keys "work", so command text vanishes into tab switches), and
120
+ // its first-keypress-cancels-auto-close rule strands it on screen forever
121
+ // as an unclosable, input-eating zombie. Non-capturing + stack-safe
122
+ // self-dismiss (see startBootTimer) makes it pure eye-candy.
123
+ const splashMode = autoCloseMs !== undefined && autoCloseMs > 0;
116
124
  ctx.ui.custom<void>(
117
125
  (tui, theme, _keybindings, done) => {
118
126
  overlay = new InfoOverlay();
119
127
  overlay.setTheme(theme);
128
+ overlay.interactive = !splashMode;
120
129
  overlayVisible = true;
121
130
  overlay.onClose = () => {
122
131
  overlayVisible = false;
@@ -127,14 +136,37 @@ export default function (pi: ExtensionAPI) {
127
136
  const component = {
128
137
  render: (w: number) => overlay.render(w),
129
138
  invalidate: () => overlay.invalidate(),
139
+ // In splash mode the overlay is non-capturing and never receives
140
+ // input; keep handleInput wired for interactive ("on") mode.
130
141
  handleInput: (data: string) => {
131
142
  overlay.handleInput(data);
132
143
  tui.requestRender();
133
144
  },
134
145
  };
135
- // Boot dashboard dismisses itself; any keypress cancels the timer.
146
+ // Splash self-dismiss may only run while this overlay is the topmost
147
+ // VISIBLE entry of the TUI overlay stack. If the user opens anything
148
+ // during the splash window (a /unipi:… settings dialog, the updater's
149
+ // update prompt, …), dismissal must wait — removing a covered entry
150
+ // breaks the covering overlay (pi retargets focus and orphans its
151
+ // pending interaction, e.g. a hung ctx.ui.select promise). Re-check
152
+ // on every timer tick; once the stack clears we dismiss as usual.
153
+ const isTopmostVisible = (): boolean => {
154
+ try {
155
+ const stack = (tui as unknown as { overlayStack?: Array<{ component?: unknown; hidden?: boolean }> }).overlayStack;
156
+ if (!stack || stack.length === 0) return true;
157
+ for (let i = stack.length - 1; i >= 0; i--) {
158
+ const entry = stack[i];
159
+ if (entry?.hidden) continue;
160
+ return entry?.component === component;
161
+ }
162
+ return true;
163
+ } catch {
164
+ return true; // Stack unreadable — assume topmost (legacy behavior).
165
+ }
166
+ };
167
+ // Boot dashboard dismisses itself (splash mode).
136
168
  if (autoCloseMs && autoCloseMs > 0) {
137
- overlay.startBootTimer(autoCloseMs);
169
+ overlay.startBootTimer(autoCloseMs, isTopmostVisible);
138
170
  }
139
171
  return component;
140
172
  },
@@ -145,17 +177,24 @@ export default function (pi: ExtensionAPI) {
145
177
  minWidth: 60,
146
178
  anchor: "center" as const,
147
179
  margin: 2,
180
+ nonCapturing: splashMode,
148
181
  },
149
- // `done()` (the extension UI's close callback) pops the *topmost* overlay
150
- // in the TUI stack, not this one specifically. When another overlay (e.g.
151
- // the updater's "Update Available" prompt) is stacked on top, the boot
152
- // auto-close timer must not fire `done()` that would pop the covering
153
- // overlay and strand this dashboard with a spent one-shot close the user
154
- // can no longer dismiss. `isTopmostOverlay` lets the boot timer defer
155
- // until we are the focused (topmost) entry; the user can still press
156
- // q/Esc to close once the covering overlay is gone.
182
+ // In splash mode the timer uses `selfHide` (handle.hide() splices this
183
+ // entry out by identity) guarded by the topmost-visible check above
184
+ // never `done()`, which pops whatever is TOPMOST. `isTopmostOverlay`
185
+ // remains as the focused-done() fallback for interactive ("on") mode,
186
+ // where the user drives the dashboard directly: it is topmost while
187
+ // being driven, so the q/Esc done() path is correct there.
157
188
  onHandle: (handle) => {
158
189
  overlay.isTopmostOverlay = () => handle.isFocused();
190
+ overlay.selfHide = () => {
191
+ overlayVisible = false;
192
+ if (typeof handle.hide === "function") {
193
+ handle.hide();
194
+ } else if (typeof (handle as { setHidden?: (v: boolean) => void }).setHidden === "function") {
195
+ (handle as { setHidden: (v: boolean) => void }).setHidden(true);
196
+ }
197
+ };
159
198
  },
160
199
  }
161
200
  );
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@pi-unipi/info-screen",
3
- "version": "2.14.0",
4
- "description": "Dashboard and module registry for Unipi configurable info overlay with tabbed groups",
3
+ "version": "2.14.1",
4
+ "description": "Dashboard and module registry for Unipi \u2014 configurable info overlay with tabbed groups",
5
5
  "type": "module",
6
6
  "main": "index.ts",
7
7
  "license": "MIT",
@@ -33,7 +33,7 @@
33
33
  "access": "public"
34
34
  },
35
35
  "dependencies": {
36
- "@pi-unipi/core": "2.14.0"
36
+ "@pi-unipi/core": "2.14.1"
37
37
  },
38
38
  "peerDependencies": {
39
39
  "@earendil-works/pi-coding-agent": "^0.84.0",
@@ -69,6 +69,21 @@ export class InfoOverlay implements Component {
69
69
  * `startBootTimer` for why.
70
70
  */
71
71
  isTopmostOverlay?: () => boolean;
72
+ /**
73
+ * Stack-safe self-removal via the overlay handle (`handle.hide()` splices
74
+ * this entry out of the TUI stack by identity, unlike `done()` which pops
75
+ * whatever is TOPMOST). Set from `onHandle` in index.ts. When available,
76
+ * the boot auto-close timer prefers this over `done()` so a splash that
77
+ * lingers while another overlay opens can never dismiss that overlay
78
+ * instead of itself.
79
+ */
80
+ selfHide?: () => void;
81
+ /**
82
+ * False when running as a non-capturing boot splash (auto-close): the
83
+ * overlay never receives keyboard input, so interactive hints like
84
+ * "q/Esc close" would be misleading and are replaced accordingly.
85
+ */
86
+ interactive = true;
72
87
 
73
88
  private overlay = new OverlayTheme();
74
89
 
@@ -232,31 +247,46 @@ export class InfoOverlay implements Component {
232
247
  }
233
248
 
234
249
  /**
235
- * Auto-close the overlay after `ms`, unless the user interacts first.
250
+ * Auto-close the overlay after `ms`.
236
251
  *
237
- * Used when the overlay is shown on boot: the dashboard is informational, so
238
- * it should get out of the way on its own rather than requiring a keypress.
252
+ * Used when the overlay is shown as a boot splash: the dashboard is
253
+ * informational, so it should get out of the way on its own rather than
254
+ * requiring a keypress.
239
255
  *
240
- * The close callback (`onClose` → `done`) pops the *topmost* overlay in the
241
- * TUI stack, not this one specifically. When another overlay (e.g. the
242
- * updater's "Update Available" prompt) is stacked on top, firing `done()`
243
- * here would remove the covering overlay and strand this dashboard with a
244
- * spent one-shot close the user can no longer trigger — leaving the starting
245
- * screen stuck. So we defer the auto-close until we are actually the
246
- * focused/topmost overlay; the user can still press q/Esc to dismiss it once
247
- * the covering overlay is gone.
256
+ * Dismissal uses `selfHide` (handle.hide() removes THIS entry from the
257
+ * TUI overlay stack by identity) and only fires while `isTopmostVisible`
258
+ * confirms nothing is stacked above: dismissing a covered overlay breaks
259
+ * the covering one (pi retargets focus and orphans its pending
260
+ * interaction, e.g. a ctx.ui.select promise that never resolves while its
261
+ * overlay vanishes). If covered, the timer re-arms and retries.
262
+ *
263
+ * If `selfHide` is unavailable (older host), falls back to the guarded
264
+ * `onClose` (`done()`) path, which requires focus (topmost) for the same
265
+ * reason.
248
266
  */
249
- startBootTimer(ms: number): void {
267
+ startBootTimer(ms: number, isTopmostVisible?: () => boolean): void {
250
268
  this.cancelBootTimer();
251
269
  if (!Number.isFinite(ms) || ms <= 0) return;
252
270
  const arm = (): void => {
253
271
  this.bootTimer = setTimeout(() => {
254
272
  this.bootTimer = null;
255
273
  if (this._destroyed) return;
274
+ if (this.selfHide) {
275
+ if (isTopmostVisible && !isTopmostVisible()) {
276
+ // Something is stacked on top of us — dismissing now would break
277
+ // it (orphaned select promise, focus retarget). Retry shortly;
278
+ // once the stack clears we dismiss as usual.
279
+ arm();
280
+ return;
281
+ }
282
+ this.selfHide();
283
+ this.destroy();
284
+ return;
285
+ }
256
286
  if (this.isTopmostOverlay && !this.isTopmostOverlay()) {
257
- // Something is stacked on top of us — closing now would pop it
258
- // instead of this dashboard. Retry shortly; once the covering
259
- // overlay closes we'll be topmost and can auto-close safely.
287
+ // Fallback (no selfHide available): closing now would pop the
288
+ // covering overlay instead of this dashboard. Retry shortly; once
289
+ // we are topmost the close is safe.
260
290
  arm();
261
291
  return;
262
292
  }
@@ -346,7 +376,7 @@ export class InfoOverlay implements Component {
346
376
  lines.push(this.overlay.frameLine(this.overlay.fg("dim", "Modules will register groups on startup."), innerWidth));
347
377
  for (let i = 0; i < 4; i++) lines.push(this.overlay.frameLine("", innerWidth));
348
378
  lines.push(this.overlay.ruleLine(innerWidth));
349
- lines.push(this.overlay.frameLine(this.overlay.fg("dim", "q/Esc close · r refresh"), innerWidth));
379
+ lines.push(this.overlay.frameLine(this.overlay.fg("dim", this.interactive ? "q/Esc close · r refresh" : "auto-dismissing…"), innerWidth));
350
380
  lines.push(this.overlay.borderLine(innerWidth, "bottom"));
351
381
  return lines;
352
382
  }
@@ -529,12 +559,14 @@ export class InfoOverlay implements Component {
529
559
  const lastUp = infoRegistry.getLastUpdated(group?.id ?? "");
530
560
  const age = lastUp > 0 ? humanizeAge(Date.now() - lastUp) : "loading…";
531
561
 
532
- const hints = [
533
- `${this.overlay.fg("accent", "←/→")} tabs`,
534
- `${this.overlay.fg("success", "↑/↓")} scroll`,
535
- `${this.overlay.fg("warning", "r")} refresh`,
536
- `${this.overlay.fg("error", "q/Esc")} close`,
537
- ];
562
+ const hints = this.interactive
563
+ ? [
564
+ `${this.overlay.fg("accent", "←/→")} tabs`,
565
+ `${this.overlay.fg("success", "↑/↓")} scroll`,
566
+ `${this.overlay.fg("warning", "r")} refresh`,
567
+ `${this.overlay.fg("error", "q/Esc")} close`,
568
+ ]
569
+ : [`${this.overlay.fg("dim", "auto-dismissing…")}`];
538
570
 
539
571
  const hintStr = hints.join(` ${this.overlay.fg("borderMuted", "•")} `);
540
572
 
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@pi-unipi/input-shortcuts",
3
- "version": "2.14.0",
4
- "description": "Keyboard shortcuts for stash/restore, undo/redo, clipboard, and thinking toggle chord-based overlay system",
3
+ "version": "2.14.1",
4
+ "description": "Keyboard shortcuts for stash/restore, undo/redo, clipboard, and thinking toggle \u2014 chord-based overlay system",
5
5
  "type": "module",
6
6
  "main": "src/index.ts",
7
7
  "license": "MIT",
@@ -33,7 +33,7 @@
33
33
  "access": "public"
34
34
  },
35
35
  "dependencies": {
36
- "@pi-unipi/core": "2.14.0"
36
+ "@pi-unipi/core": "2.14.1"
37
37
  },
38
38
  "peerDependencies": {
39
39
  "@earendil-works/pi-coding-agent": "^0.84.0",
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@pi-unipi/kanboard",
3
- "version": "2.14.0",
4
- "description": "Visualization layer for unipi workflow HTTP server with htmx/Alpine.js UI, modular parsers, TUI overlay, and kanban board",
3
+ "version": "2.14.1",
4
+ "description": "Visualization layer for unipi workflow \u2014 HTTP server with htmx/Alpine.js UI, modular parsers, TUI overlay, and kanban board",
5
5
  "type": "module",
6
6
  "main": "index.ts",
7
7
  "license": "MIT",
@@ -39,7 +39,7 @@
39
39
  "access": "public"
40
40
  },
41
41
  "dependencies": {
42
- "@pi-unipi/core": "2.14.0"
42
+ "@pi-unipi/core": "2.14.1"
43
43
  },
44
44
  "peerDependencies": {
45
45
  "@earendil-works/pi-coding-agent": "^0.84.0",
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@pi-unipi/mcp",
3
- "version": "2.14.0",
4
- "description": "MCP server management extension for Pi coding agent browse, add, configure, and use MCP servers",
3
+ "version": "2.14.1",
4
+ "description": "MCP server management extension for Pi coding agent \u2014 browse, add, configure, and use MCP servers",
5
5
  "type": "module",
6
6
  "main": "src/index.ts",
7
7
  "license": "MIT",
@@ -30,7 +30,7 @@
30
30
  "test": "npx tsx --test tests/**/*.test.ts"
31
31
  },
32
32
  "dependencies": {
33
- "@pi-unipi/core": "2.14.0"
33
+ "@pi-unipi/core": "2.14.1"
34
34
  },
35
35
  "peerDependencies": {
36
36
  "@earendil-works/pi-coding-agent": "^0.84.0",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pi-unipi/memory",
3
- "version": "2.14.0",
3
+ "version": "2.14.1",
4
4
  "description": "Persistent cross-session memory with MemPalace backend (auto-installed) and SQLite fallback for Pi coding agent",
5
5
  "type": "module",
6
6
  "main": "index.ts",
@@ -39,8 +39,8 @@
39
39
  "README.md"
40
40
  ],
41
41
  "dependencies": {
42
- "@pi-unipi/core": "2.14.0",
43
- "@pi-unipi/info-screen": "2.14.0",
42
+ "@pi-unipi/core": "2.14.1",
43
+ "@pi-unipi/info-screen": "2.14.1",
44
44
  "js-yaml": "^4.1.0"
45
45
  },
46
46
  "peerDependencies": {
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@pi-unipi/milestone",
3
- "version": "2.14.0",
4
- "description": "Lifecycle layer for project-level goals MILESTONES.md tracking, session hooks, auto-sync",
3
+ "version": "2.14.1",
4
+ "description": "Lifecycle layer for project-level goals \u2014 MILESTONES.md tracking, session hooks, auto-sync",
5
5
  "type": "module",
6
6
  "main": "index.ts",
7
7
  "scripts": {
@@ -32,7 +32,7 @@
32
32
  "access": "public"
33
33
  },
34
34
  "dependencies": {
35
- "@pi-unipi/core": "2.14.0"
35
+ "@pi-unipi/core": "2.14.1"
36
36
  },
37
37
  "peerDependencies": {
38
38
  "@earendil-works/pi-coding-agent": "^0.84.0",
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@pi-unipi/notify",
3
- "version": "2.14.0",
4
- "description": "Cross-platform notification extension for Pi native OS, Gotify, and Telegram notifications for agent lifecycle events",
3
+ "version": "2.14.1",
4
+ "description": "Cross-platform notification extension for Pi \u2014 native OS, Gotify, and Telegram notifications for agent lifecycle events",
5
5
  "type": "module",
6
6
  "main": "index.ts",
7
7
  "license": "MIT",
@@ -34,7 +34,7 @@
34
34
  "access": "public"
35
35
  },
36
36
  "dependencies": {
37
- "@pi-unipi/core": "2.14.0",
37
+ "@pi-unipi/core": "2.14.1",
38
38
  "node-notifier": "^10.0.1"
39
39
  },
40
40
  "peerDependencies": {
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pi-unipi/ralph",
3
- "version": "2.14.0",
3
+ "version": "2.14.1",
4
4
  "description": "Long-running iterative development loops for Pi coding agent",
5
5
  "type": "module",
6
6
  "main": "index.ts",
@@ -31,8 +31,8 @@
31
31
  "test": "npx tsx --test reminder.test.ts"
32
32
  },
33
33
  "dependencies": {
34
- "@pi-unipi/core": "2.14.0",
35
- "@pi-unipi/info-screen": "2.14.0"
34
+ "@pi-unipi/core": "2.14.1",
35
+ "@pi-unipi/info-screen": "2.14.1"
36
36
  },
37
37
  "peerDependencies": {
38
38
  "@earendil-works/pi-ai": "^0.84.0",
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@pi-unipi/subagents",
3
- "version": "2.14.0",
4
- "description": "Subagents for UniPi parallel execution, file locking, workflow integration",
3
+ "version": "2.14.1",
4
+ "description": "Subagents for UniPi \u2014 parallel execution, file locking, workflow integration",
5
5
  "type": "module",
6
6
  "main": "src/index.ts",
7
7
  "types": "src/index.ts",
@@ -9,7 +9,7 @@
9
9
  "test": "npx tsx --test src/__tests__/*.test.ts"
10
10
  },
11
11
  "dependencies": {
12
- "@pi-unipi/core": "2.14.0",
12
+ "@pi-unipi/core": "2.14.1",
13
13
  "@earendil-works/pi-agent-core": "^0.84.0",
14
14
  "acorn": "8.18.0"
15
15
  },
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pi-unipi/trajectory",
3
- "version": "2.14.0",
3
+ "version": "2.14.1",
4
4
  "description": "Live UniPi trajectory inspector for Pi sessions",
5
5
  "type": "module",
6
6
  "main": "index.ts",