@pi-unipi/unipi 2.14.1 → 2.14.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.
package/CHANGELOG.md CHANGED
@@ -6,6 +6,13 @@ 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.2] — 2026-08-31
10
+
11
+ ### Fixed
12
+
13
+ - `footer`: **glance frame no longer writes the terminal's last column** (GitHub [#31](https://github.com/Neuron-Mr-White/UniPi/issues/31)) — the glance frame, session strip, process one-liner, and classic status line now cap emitted lines at `width - 1` instead of exactly `width`. pi-tui joins per-tick rewrites with `\r\n`; a line at EXACTLY the terminal width trips auto-wrap on terminals that wrap immediately (or whose glyph widths disagree with `visibleWidth()`, e.g. missing Nerd Fonts / ambiguous-width settings), silently desyncing the differential renderer so every 1s footer refresh painted a fresh input-box copy one block lower until the screen filled. Verified by PTY capture + VT replay: identical byte stream renders 1 stable frame on deferred-wrap terminals vs 12 stacked frames on immediate-wrap ones; the cap removes the footer's contribution entirely. Full resolution of terminal-side drift from pi's own boot/info lines is upstream (pi-tui main-screen wrap-safe bookkeeping).
14
+ - `web-api`: **fetch errors surface their real cause instead of "[object Object]"** — engine errors were plain objects (`{ error, code, phase, retryable }`), so every tool-level catch serialized them via `String()` and both the agent and the user saw only "Read failed: [object Object]" with no diagnosis. `createError()` now returns a real `Error` instance carrying the FetchError fields (interface-compatible: `.error`/`.code`/`.phase`/`.retryable` preserved, classification untouched), and a new `describeError()` normalizes Error instances, FetchError-shaped objects, `{message}`/`{reason}`/`{detail}` shapes, strings, and unserializable values at every tool boundary and in the provider fallthrough. Regression tests cover all shapes; a provider throwing `{ error: "HTTP 429" }` now reports the 429 instead of nothing.
15
+
9
16
  ## [2.14.1] — 2026-08-28
10
17
 
11
18
  ### Added
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pi-unipi/unipi",
3
- "version": "2.14.1",
3
+ "version": "2.14.2",
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.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"
85
+ "@pi-unipi/ask-user": "2.14.2",
86
+ "@pi-unipi/background-tasks": "2.14.2",
87
+ "@pi-unipi/btw": "2.14.2",
88
+ "@pi-unipi/command-enchantment": "2.14.2",
89
+ "@pi-unipi/compactor": "2.14.2",
90
+ "@pi-unipi/core": "2.14.2",
91
+ "@pi-unipi/footer": "2.14.2",
92
+ "@pi-unipi/image": "2.14.2",
93
+ "@pi-unipi/info-screen": "2.14.2",
94
+ "@pi-unipi/input-shortcuts": "2.14.2",
95
+ "@pi-unipi/kanboard": "2.14.2",
96
+ "@pi-unipi/mcp": "2.14.2",
97
+ "@pi-unipi/memory": "2.14.2",
98
+ "@pi-unipi/milestone": "2.14.2",
99
+ "@pi-unipi/notify": "2.14.2",
100
+ "@pi-unipi/ralph": "2.14.2",
101
+ "@pi-unipi/subagents": "2.14.2",
102
+ "@pi-unipi/trajectory": "2.14.2",
103
+ "@pi-unipi/updater": "2.14.2",
104
+ "@pi-unipi/utility": "2.14.2",
105
+ "@pi-unipi/web-api": "2.14.2",
106
+ "@pi-unipi/workflow": "2.14.2"
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.1",
4
- "description": "Structured user input tool for Pi coding agent \u2014 single-select, multi-select, freeform",
3
+ "version": "2.14.2",
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,7 +40,7 @@
40
40
  "access": "public"
41
41
  },
42
42
  "dependencies": {
43
- "@pi-unipi/core": "2.14.1"
43
+ "@pi-unipi/core": "2.14.2"
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.1",
3
+ "version": "2.14.2",
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",
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@pi-unipi/background-tasks",
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",
3
+ "version": "2.14.2",
4
+ "description": "Background tasks for UniPi 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.1",
13
+ "@pi-unipi/core": "2.14.2",
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.1",
4
- "description": "A pi extension for parallel side conversations with /unipi:btw \u2014 part of the Unipi suite",
3
+ "version": "2.14.2",
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",
@@ -37,7 +37,7 @@
37
37
  "@earendil-works/pi-tui": "^0.84.0"
38
38
  },
39
39
  "dependencies": {
40
- "@pi-unipi/core": "2.14.1"
40
+ "@pi-unipi/core": "2.14.2"
41
41
  },
42
42
  "pi": {
43
43
  "extensions": [
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@pi-unipi/compactor",
3
- "version": "2.14.1",
4
- "description": "Context engine for Pi \u2014 zero-LLM compaction, session continuity, sandbox execution, and tool display optimization",
3
+ "version": "2.14.2",
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,8 +34,8 @@
34
34
  "access": "public"
35
35
  },
36
36
  "dependencies": {
37
- "@pi-unipi/core": "2.14.1",
38
- "@pi-unipi/info-screen": "2.14.1",
37
+ "@pi-unipi/core": "2.14.2",
38
+ "@pi-unipi/info-screen": "2.14.2",
39
39
  "@earendil-works/pi-agent-core": "^0.84.0"
40
40
  },
41
41
  "peerDependencies": {
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pi-unipi/core",
3
- "version": "2.14.1",
3
+ "version": "2.14.2",
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.1",
4
- "description": "Persistent status bar for Unipi \u2014 subscribes to UNIPI_EVENTS and renders key stats from all unipi packages",
3
+ "version": "2.14.2",
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",
7
7
  "license": "MIT",
@@ -32,8 +32,8 @@
32
32
  "access": "public"
33
33
  },
34
34
  "dependencies": {
35
- "@pi-unipi/core": "2.14.1",
36
- "@pi-unipi/background-tasks": "2.14.1"
35
+ "@pi-unipi/core": "2.14.2",
36
+ "@pi-unipi/background-tasks": "2.14.2"
37
37
  },
38
38
  "peerDependencies": {
39
39
  "@earendil-works/pi-coding-agent": "^0.84.0",
@@ -63,6 +63,24 @@ function repeat(s: string, n: number): string {
63
63
  return s.repeat(Math.max(0, n));
64
64
  }
65
65
 
66
+ /**
67
+ * Frame width for a terminal of `terminalWidth` columns: one column SHORT of
68
+ * the terminal (legacy 8-column floor preserved below 9 columns).
69
+ *
70
+ * Issue #31 invariant — the frame is repainted every second and pi-tui joins
71
+ * the rewritten lines with "\r\n". A line at EXACTLY the terminal width hits
72
+ * the auto-wrap threshold: on terminals that wrap immediately (and whenever
73
+ * a glyph renders wider than visibleWidth() assumed) the cursor silently
74
+ * advances one extra row per line, desyncing the differential renderer —
75
+ * every refresh then paints a fresh frame copy one block lower until the
76
+ * screen fills. Never writing the last column keeps every frame line below
77
+ * the wrap threshold on every terminal.
78
+ */
79
+ export function glanceFrameWidth(terminalWidth: number): number {
80
+ if (!Number.isFinite(terminalWidth)) return 8;
81
+ return Math.max(8, terminalWidth - 1);
82
+ }
83
+
66
84
  function padLine(line: string, width: number): string {
67
85
  const w = visibleWidth(line);
68
86
  if (w === width) return line;
@@ -160,7 +178,8 @@ export class GlanceEditor extends CustomEditor {
160
178
  }
161
179
 
162
180
  override render(width: number): string[] {
163
- const safe = Math.max(8, width);
181
+ // One column short of the terminal — see glanceFrameWidth() / issue #31.
182
+ const safe = glanceFrameWidth(width);
164
183
  const inner = Math.max(0, safe - 2);
165
184
 
166
185
  // Base render at inner width: harvest content rows only (rules dropped).
@@ -354,8 +354,11 @@ function setupFooterUI(pi: ExtensionAPI, ctx: ExtensionContext, state: FooterSta
354
354
  // Hard safety net: never return a line wider than the terminal.
355
355
  // This catches any edge cases in layout math or visibleWidth()
356
356
  // inconsistencies with PUA characters + ANSI codes.
357
+ // Cap at width - 1 (issue #31): a line at EXACTLY the terminal width
358
+ // trips immediate-wrap terminals and desyncs the diff renderer.
357
359
  const line = layout.topContent;
358
- return [visibleWidth(line) > width ? truncateToWidth(line, width) : line];
360
+ const cap = Math.max(1, width - 1);
361
+ return [visibleWidth(line) > cap ? truncateToWidth(line, cap) : line];
359
362
  },
360
363
  };
361
364
  }, { placement: "aboveEditor" });
@@ -373,7 +376,9 @@ function setupFooterUI(pi: ExtensionAPI, ctx: ExtensionContext, state: FooterSta
373
376
  if (!strip) return [];
374
377
  // Centered under the input box.
375
378
  const w = visibleWidth(strip);
376
- if (w >= width) return [truncateToWidth(strip, width)];
379
+ // Truncate one column short of the terminal (issue #31 — same wrap
380
+ // desync as the glance frame; see glanceFrameWidth()).
381
+ if (w >= width) return [truncateToWidth(strip, Math.max(1, width - 1))];
377
382
  const leftPad = Math.floor((width - w) / 2);
378
383
  return [" ".repeat(leftPad) + strip];
379
384
  },
@@ -55,7 +55,9 @@ export function countBgProcesses(): BgProcessCounts | null {
55
55
  * Returns [] when there is nothing to show.
56
56
  */
57
57
  export function renderProcessLine(width: number): string[] {
58
- if (width <= 0) return [];
58
+ // One column can never host a meaningful one-liner, and any content would
59
+ // be exactly-full-width (issue #31 wrap desync) — render nothing.
60
+ if (width <= 1) return [];
59
61
  const counts = countBgProcesses();
60
62
  if (!counts) return [];
61
63
 
@@ -68,7 +70,9 @@ export function renderProcessLine(width: number): string[] {
68
70
 
69
71
  const line = parts.join(" ");
70
72
  const w = visibleWidth(line);
71
- if (w >= width) return [truncateToWidth(line, width)];
73
+ // One column short of the terminal (issue #31 — same wrap desync as the
74
+ // glance frame; see glanceFrameWidth() in glance-editor.ts).
75
+ if (w >= width) return [truncateToWidth(line, Math.max(1, width - 1))];
72
76
  const leftPad = Math.floor((width - w) / 2);
73
77
  return [" ".repeat(leftPad) + line];
74
78
  }
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pi-unipi/image",
3
- "version": "2.14.1",
3
+ "version": "2.14.2",
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.1"
37
+ "@pi-unipi/core": "2.14.2"
38
38
  },
39
39
  "peerDependencies": {
40
40
  "@earendil-works/pi-ai": "^0.84.0",
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@pi-unipi/info-screen",
3
- "version": "2.14.1",
4
- "description": "Dashboard and module registry for Unipi \u2014 configurable info overlay with tabbed groups",
3
+ "version": "2.14.2",
4
+ "description": "Dashboard and module registry for Unipi 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.1"
36
+ "@pi-unipi/core": "2.14.2"
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/input-shortcuts",
3
- "version": "2.14.1",
4
- "description": "Keyboard shortcuts for stash/restore, undo/redo, clipboard, and thinking toggle \u2014 chord-based overlay system",
3
+ "version": "2.14.2",
4
+ "description": "Keyboard shortcuts for stash/restore, undo/redo, clipboard, and thinking toggle 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.1"
36
+ "@pi-unipi/core": "2.14.2"
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.1",
4
- "description": "Visualization layer for unipi workflow \u2014 HTTP server with htmx/Alpine.js UI, modular parsers, TUI overlay, and kanban board",
3
+ "version": "2.14.2",
4
+ "description": "Visualization layer for unipi workflow 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.1"
42
+ "@pi-unipi/core": "2.14.2"
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.1",
4
- "description": "MCP server management extension for Pi coding agent \u2014 browse, add, configure, and use MCP servers",
3
+ "version": "2.14.2",
4
+ "description": "MCP server management extension for Pi coding agent 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.1"
33
+ "@pi-unipi/core": "2.14.2"
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.1",
3
+ "version": "2.14.2",
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.1",
43
- "@pi-unipi/info-screen": "2.14.1",
42
+ "@pi-unipi/core": "2.14.2",
43
+ "@pi-unipi/info-screen": "2.14.2",
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.1",
4
- "description": "Lifecycle layer for project-level goals \u2014 MILESTONES.md tracking, session hooks, auto-sync",
3
+ "version": "2.14.2",
4
+ "description": "Lifecycle layer for project-level goals 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.1"
35
+ "@pi-unipi/core": "2.14.2"
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.1",
4
- "description": "Cross-platform notification extension for Pi \u2014 native OS, Gotify, and Telegram notifications for agent lifecycle events",
3
+ "version": "2.14.2",
4
+ "description": "Cross-platform notification extension for Pi 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.1",
37
+ "@pi-unipi/core": "2.14.2",
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.1",
3
+ "version": "2.14.2",
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.1",
35
- "@pi-unipi/info-screen": "2.14.1"
34
+ "@pi-unipi/core": "2.14.2",
35
+ "@pi-unipi/info-screen": "2.14.2"
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.1",
4
- "description": "Subagents for UniPi \u2014 parallel execution, file locking, workflow integration",
3
+ "version": "2.14.2",
4
+ "description": "Subagents for UniPi 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.1",
12
+ "@pi-unipi/core": "2.14.2",
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.1",
3
+ "version": "2.14.2",
4
4
  "description": "Live UniPi trajectory inspector for Pi sessions",
5
5
  "type": "module",
6
6
  "main": "index.ts",