@danypops/pi-packed 0.21.0 → 0.21.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.
@@ -0,0 +1,51 @@
1
+ import type { Component } from "malevich-tui-components";
2
+
3
+ /** Keeps a component failure inside its overlay instead of Pi's event loop. */
4
+ export class TuiErrorBoundary implements Component {
5
+ private failed = false;
6
+
7
+ constructor(
8
+ private readonly component: Component,
9
+ private readonly fallback: readonly string[],
10
+ private readonly onError?: () => void,
11
+ ) {}
12
+
13
+ render(width: number): string[] {
14
+ if (this.failed) return this.renderFallback(width);
15
+ try {
16
+ return this.component.render(width);
17
+ } catch {
18
+ this.fail();
19
+ return this.renderFallback(width);
20
+ }
21
+ }
22
+
23
+ invalidate(): void {
24
+ if (this.failed) return;
25
+ try {
26
+ this.component.invalidate();
27
+ } catch {
28
+ this.fail();
29
+ }
30
+ }
31
+
32
+ handleInput(data: string): void {
33
+ if (this.failed) return;
34
+ try {
35
+ this.component.handleInput?.(data);
36
+ } catch {
37
+ this.fail();
38
+ }
39
+ }
40
+
41
+ private fail(): void {
42
+ if (this.failed) return;
43
+ this.failed = true;
44
+ this.onError?.();
45
+ }
46
+
47
+ private renderFallback(width: number): string[] {
48
+ const boundedWidth = Math.max(0, width);
49
+ return this.fallback.map((line) => line.slice(0, boundedWidth));
50
+ }
51
+ }
@@ -67,6 +67,7 @@ import { createFindTab } from "./tabs/discover.js";
67
67
  import { applyResourceToggle, ConfigTab } from "./tabs/resource-config.js";
68
68
  import { SettingsTab } from "./tabs/security-tui.js";
69
69
  import { approvePackageOperation } from "./tools.js";
70
+ import { TuiErrorBoundary } from "./tui-error-boundary.js";
70
71
 
71
72
  export type PackedTabKey = "packages" | "find" | "config" | "settings";
72
73
 
@@ -859,7 +860,7 @@ function renderUnifiedPanel(
859
860
  measure,
860
861
  });
861
862
 
862
- return {
863
+ const panel: Component = {
863
864
  render(width: number): string[] {
864
865
  envelope.setContent(pendingDialog ?? packageInspector ?? tabbedContainer);
865
866
  return envelope.render(width);
@@ -929,6 +930,7 @@ function renderUnifiedPanel(
929
930
  tui.requestRender();
930
931
  },
931
932
  };
933
+ return new TuiErrorBoundary(panel, ["Packed could not render.", "Restart Pi and run /packed again."], () => tui.requestRender());
932
934
  // Pinned to the very top (anchor:"top-center"+offsetY:1 -- a fixed row
933
935
  // count regardless of terminal size), not row:"40%". The percentage
934
936
  // positioning was tried instead but reverted: pi-tui's row-percentage
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@danypops/pi-packed",
3
- "version": "0.21.0",
3
+ "version": "0.21.1",
4
4
  "description": "Pi package lifecycle, validation, daemon, tools, profiles, and TUI",
5
5
  "type": "module",
6
6
  "bin": {