@leo-alvarenga/pi-zen-frame 0.16.0 → 0.17.0

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/README.md CHANGED
@@ -6,8 +6,8 @@ A [`pi-coding-agent`](https://github.com/earendil-works/pi) extension that gives
6
6
 
7
7
  ## Features
8
8
 
9
- - **Clean Frame**: Clean editor frame with segments placed above and below it to easily see relevant info
10
- - **Header Box**: Optional Claude-style welcome panel displaying a logo, model/provider info, current working directory, and Git status
9
+ - **Clean Frame**: Clean editor frame with status segments rendered below the editor
10
+ - **Header Box**: Optional welcome panel with a logo and "Welcome back!" heading, model name, current working directory, Git status, and a random tip
11
11
  - **Working Messages**: Randomized loading status messages during response generation, updated on a configurable timer
12
12
  - **Native Theme Support**: Uses pi `ThemeColor` tokens to automatically align with your active theme
13
13
 
@@ -18,7 +18,7 @@ A [`pi-coding-agent`](https://github.com/earendil-works/pi) extension that gives
18
18
  Run the following command:
19
19
 
20
20
  ```bash
21
- pi install @leo-alvarenga/pi-zen-frame
21
+ pi install npm:@leo-alvarenga/pi-zen-frame
22
22
  ```
23
23
 
24
24
  Or add `pi-zen-frame` to your pi packages list in `~/.pi/agent/settings.json`:
@@ -42,14 +42,15 @@ Configuration is loaded from `~/.pi/agent/pi-zen-frame.json`. All properties are
42
42
  // Fallback accent color for frame border and active segments
43
43
  "accentColor": "accent",
44
44
 
45
- // Master mute: renders all segments in muted tones except agent-mode
46
- "zenMode": true,
45
+ // Master mute: renders all segments in muted tones except agent-mode (default: false)
46
+ "zenMode": false,
47
47
 
48
48
  // Editor-frame renderer by registered name (built-in: "blocky")
49
49
  "editorFrame": "blocky",
50
50
 
51
51
  "header": {
52
- "enable": true,
52
+ // Welcome panel is opt-in (default: false)
53
+ "enable": false,
53
54
  // Header renderer by registered name (built-in: "basic")
54
55
  "type": "basic",
55
56
  },
@@ -73,6 +74,7 @@ Configuration is loaded from `~/.pi/agent/pi-zen-frame.json`. All properties are
73
74
  "workingMessage": {
74
75
  "enable": true,
75
76
  "intervalMs": 3000,
77
+ // Omit to use the built-in message pool
76
78
  "messages": [
77
79
  "Exploring the seas",
78
80
  "Tinkering with strange objects",
@@ -86,16 +88,16 @@ Configuration is loaded from `~/.pi/agent/pi-zen-frame.json`. All properties are
86
88
 
87
89
  ## Structure & Status Segments
88
90
 
89
- The editor window features status indicators embedded along the frame borders:
91
+ The editor frame shows status indicators in two rows below the editor:
90
92
 
91
- | Location | Segment | Description |
92
- | ---------------- | -------------- | --------------------------------------------------------------------- |
93
- | **Top Left** | **model** | Active model name and provider |
94
- | | **reasoning** | Current reasoning effort level, tinted with pi thinking tokens |
95
- | | **spinner** | Active phase indicator (`thinking`, `outputting`, `toolcall`, `exec`) |
96
- | **Top Right** | **ctx** | Context usage percentage and token counts with color alerts |
97
- | **Bottom Left** | **agent mode** | Active agent indicator pill from `pi-agent-manager` |
98
- | **Bottom Right** | **cwd** | Shortened path, active Git branch, and uncommitted file counts |
93
+ | Location | Segment | Description |
94
+ | ------------------ | -------------- | --------------------------------------------------------------------- |
95
+ | Editor band (left) | **agent mode** | Active agent indicator pill from `pi-agent-manager` |
96
+ | | **model** | Active model name and provider |
97
+ | | **reasoning** | Current reasoning effort level, tinted with pi thinking tokens |
98
+ | | **spinner** | Active phase indicator (`thinking`, `outputting`, `toolcall`, `exec`); replaces the row while streaming when `showSpinner` is enabled (default off) |
99
+ | Footer (left) | **cwd** | Shortened path, active Git branch, and uncommitted file counts |
100
+ | Footer (right) | **ctx** | Context usage percentage and token counts with color alerts |
99
101
 
100
102
  ---
101
103
 
@@ -122,9 +124,9 @@ Run `/reload` after modifying your keybindings.
122
124
  extensions/
123
125
  ├── index.ts # Extension entry point: config initialization and events
124
126
  ├── config/ # Types, defaults, and settings normalization
125
- ├── components/ # Header (BasicHeader), frame border, and status segment modules
127
+ ├── components/ # Status segments, header, and frame layout helpers
126
128
  ├── editor/ # BlockyEditor editor-frame renderer
127
129
  ├── renderers/ # Renderer registry + swap-in API (blocky / basic)
128
- └── utils/ # Helpers for Git status, paths, and agent modes
130
+ └── utils/ # Helpers for Git status, paths, agent modes, and token usage
129
131
 
130
132
  ```
@@ -0,0 +1,13 @@
1
+ import type { SegmentDef } from "./types";
2
+
3
+ /** Box bottom (left): pi-notify bell, right before the model segment.
4
+ * Accent when notifications are on, muted bell-off otherwise */
5
+ export const notifySegment: SegmentDef = {
6
+ id: "notify",
7
+ slot: "topLeft",
8
+ render: (d, { icons, theme }) => {
9
+ const color = d.notifyEnabled && !d.zenMode ? d.accentColor : "muted";
10
+
11
+ return theme.fg(color, ` ${d.notifyEnabled ? icons.bell : icons.bellOff} `);
12
+ },
13
+ };
@@ -5,6 +5,7 @@
5
5
  * The frame calls `segmentsFor(slot, ...)` and handles all width/joining.
6
6
  */
7
7
  import { modelSegment } from "./model";
8
+ import { notifySegment } from "./notify";
8
9
  import { reasoningSegment } from "./reasoning";
9
10
  import { spinnerSegment } from "./spinner";
10
11
  import { tokenCountSegment } from "./token-count";
@@ -14,6 +15,7 @@ import type { FrameData, SegmentContext, SegmentDef, Slot } from "./types";
14
15
 
15
16
  export const segments: SegmentDef[] = [
16
17
  agentModeSegment,
18
+ notifySegment,
17
19
  modelSegment,
18
20
  reasoningSegment,
19
21
  spinnerSegment,
@@ -56,6 +56,9 @@ export interface FrameData {
56
56
  agentMode: AgentMode;
57
57
 
58
58
  context: TokenUsage | null;
59
+
60
+ /** pi-notify toggle state (true = notifications enabled). */
61
+ notifyEnabled: boolean;
59
62
  }
60
63
 
61
64
  /** Data + rendering helpers handed to every segment. */
@@ -94,4 +97,5 @@ export interface ExternalData {
94
97
  modelProvider: string | undefined;
95
98
  thinkingLevel: string | undefined;
96
99
  spinnerPhase: SpinnerPhase | null;
100
+ notifyEnabled: boolean;
97
101
  }
@@ -5,6 +5,9 @@
5
5
  export const PI_AGENT_MANAGER_AGENT_EVENT = "pi-agent-manager:agent-changed";
6
6
  export const PI_AGENT_MANAGER_AGENT_DATA_KEY = "pi-agent-manager-agent";
7
7
 
8
+ /** pi-notify integration (optional — no hard dependency). */
9
+ export const PI_NOTIFY_TOGGLE_EVENT = "pi-notify:toggle-changed";
10
+
8
11
  /** Keybinding id users bind in keybindings.json to toggle zen mode. */
9
12
  export const ZEN_MODE_SHORTCUT_ID = "piZenFrame.zenMode";
10
13
  /** Default key when the user hasn't bound one (override or disable via
@@ -21,6 +21,8 @@ export const DEFAULT_ICONS: FrameIcons = {
21
21
  gitDirty: "",
22
22
  thinking: "󰌶",
23
23
  gitBranch: "",
24
+ bell: "󰂚",
25
+ bellOff: "󰂛",
24
26
  };
25
27
 
26
28
  /** Thinking level → theme token, mirroring pi's own border-color mapping. */
@@ -19,6 +19,8 @@ export interface FrameIcons {
19
19
  thinking: string;
20
20
  gitDirty: string;
21
21
  gitBranch: string;
22
+ bell: string;
23
+ bellOff: string;
22
24
  }
23
25
 
24
26
  /**
@@ -98,6 +98,7 @@ export class BlockyEditor extends CustomEditor {
98
98
  thinkingLevel: ext.thinkingLevel,
99
99
  spinnerFrame: this.spinnerFrame(),
100
100
  accentColor: this.opts.accentColor,
101
+ notifyEnabled: ext.notifyEnabled,
101
102
  };
102
103
 
103
104
  let prefix = "┃";
@@ -21,6 +21,7 @@ import type { KeyId } from "@earendil-works/pi-tui";
21
21
  import {
22
22
  DEFAULT_SETTINGS,
23
23
  PI_AGENT_MANAGER_AGENT_EVENT,
24
+ PI_NOTIFY_TOGGLE_EVENT,
24
25
  SPINNER_FRAMES,
25
26
  ZEN_MODE_DEFAULT_KEY,
26
27
  ZEN_MODE_SHORTCUT_ID,
@@ -44,6 +45,7 @@ let currentCtx: ExtensionContext | null = null;
44
45
  let settings: Settings = DEFAULT_SETTINGS;
45
46
  let spinnerPhase: SpinnerPhase | null = null;
46
47
  let agentMode: AgentMode = null;
48
+ let notifyEnabled = false;
47
49
  let zenMode = true;
48
50
  let git: GitInfo = {
49
51
  branch: undefined,
@@ -99,6 +101,7 @@ function provideExternal(pi: ExtensionAPI): ExternalData {
99
101
  thinkingLevel: pi.getThinkingLevel(),
100
102
  modelName: model?.name ?? model?.id ?? "Unknown",
101
103
  modelProvider: capitalize(model?.provider ?? "unknown"),
104
+ notifyEnabled,
102
105
  };
103
106
  }
104
107
 
@@ -174,6 +177,13 @@ export default async function (pi: ExtensionAPI) {
174
177
  editor?.refresh();
175
178
  });
176
179
 
180
+ // Optional pi-notify integration (no hard dependency).
181
+ pi.events.on(PI_NOTIFY_TOGGLE_EVENT, (event) => {
182
+ const enabled = (event as { enabled?: unknown } | undefined)?.enabled;
183
+ if (typeof enabled === "boolean") notifyEnabled = enabled;
184
+ editor?.refresh();
185
+ });
186
+
177
187
  pi.on("session_start", async (_event, ctx) => {
178
188
  currentCtx = ctx;
179
189
  agentMode = readAgentModeFromSession(ctx) || agentMode;
package/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "name": "@leo-alvarenga/pi-zen-frame",
3
3
  "description": "A pi-coding-agent extension that gives the TUI editor a simple yet polished look and feel",
4
4
  "author": "Leonardo A. Alvarenga",
5
- "version": "0.16.0",
5
+ "version": "0.17.0",
6
6
  "license": "MIT",
7
7
  "repository": "github.com/leo-alvarenga/pi-mono",
8
8
  "publishConfig": {