@gonrocca/zero-pi 0.1.32 → 0.1.34
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/extensions/zero-banner.ts +58 -10
- package/package.json +1 -1
|
@@ -125,27 +125,75 @@ function ornament(width: number): string {
|
|
|
125
125
|
return center(line, width);
|
|
126
126
|
}
|
|
127
127
|
|
|
128
|
-
/**
|
|
128
|
+
/**
|
|
129
|
+
* The full banner block, centered to the given width.
|
|
130
|
+
*
|
|
131
|
+
* Wide layout = exactly **10 lines**: top ornament + 7 logo rows (6 + cast
|
|
132
|
+
* shadow) + tag + bottom ornament. Pi's `setWidget` caps managed widgets at
|
|
133
|
+
* `MAX_WIDGET_LINES = 10` (hardcoded in interactive-mode.js); anything taller
|
|
134
|
+
* is rendered with a `... (widget truncated)` line. Inner blank-line padding
|
|
135
|
+
* was removed to fit that cap exactly — adding blanks back would re-truncate.
|
|
136
|
+
*/
|
|
129
137
|
export function bannerBlock(width: number): string[] {
|
|
130
138
|
if (width < 64) {
|
|
131
139
|
return [center(fg(VIOLET, "ZERO SDD"), width), center(fg(MUTED, "pi.dev · spec-driven work"), width)];
|
|
132
140
|
}
|
|
133
141
|
const tag = fg(VIOLET, "ZERO SDD") + fg(MUTED, " explore → plan → build → veredicto");
|
|
134
|
-
return [ornament(width),
|
|
142
|
+
return [ornament(width), ...renderLogo(width), center(tag, width), ornament(width)];
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
/** The slice of pi's UI surface this extension uses. */
|
|
146
|
+
interface PiUI {
|
|
147
|
+
setWidget(id: string, lines: string[]): void;
|
|
148
|
+
}
|
|
149
|
+
interface PiSessionContext {
|
|
150
|
+
ui?: PiUI;
|
|
151
|
+
}
|
|
152
|
+
interface PiAPI {
|
|
153
|
+
on(event: string, handler: (event: unknown, ctx: PiSessionContext) => void): void;
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
/** Stable widget id — re-installing with the same id replaces the previous lines. */
|
|
157
|
+
const WIDGET_ID = "zero-banner";
|
|
158
|
+
|
|
159
|
+
/**
|
|
160
|
+
* Install (or refresh) the banner as a pi-managed widget above the editor.
|
|
161
|
+
*
|
|
162
|
+
* Using `ctx.ui.setWidget` instead of a one-shot `stdout.write` means pi owns
|
|
163
|
+
* the lines and redraws them on every resize, every reload, every session
|
|
164
|
+
* restart — so the banner survives maximize/minimize instead of vanishing into
|
|
165
|
+
* scrollback. The crash this file's earlier comment warned about was the
|
|
166
|
+
* animated 140 ms re-render loop; a static widget set once per `session_start`
|
|
167
|
+
* has no timer and re-uses the same id, so it never spams.
|
|
168
|
+
*/
|
|
169
|
+
function installWidget(ctx: PiSessionContext): void {
|
|
170
|
+
if (!ctx?.ui || typeof ctx.ui.setWidget !== "function") return;
|
|
171
|
+
if (process.env.NO_COLOR) return;
|
|
172
|
+
const cols = process.stdout?.columns && process.stdout.columns > 0 ? process.stdout.columns : 80;
|
|
173
|
+
ctx.ui.setWidget(WIDGET_ID, bannerBlock(cols));
|
|
135
174
|
}
|
|
136
175
|
|
|
137
176
|
/**
|
|
138
|
-
* The pi extension entry point.
|
|
139
|
-
*
|
|
177
|
+
* The pi extension entry point.
|
|
178
|
+
*
|
|
179
|
+
* Hooks `session_start` (fires on startup, reload, new, resume, fork) and
|
|
180
|
+
* installs the banner as a pi-managed widget above the editor — so pi keeps it
|
|
181
|
+
* rendered and redraws it on resize. Disabled with `ZERO_HEADER=off`.
|
|
182
|
+
* Defensive: any failure of registration or the widget install is swallowed —
|
|
183
|
+
* a banner must never break a pi session.
|
|
140
184
|
*/
|
|
141
|
-
export default function register(
|
|
185
|
+
export default function register(pi?: unknown): void {
|
|
142
186
|
try {
|
|
143
187
|
if ((process.env.ZERO_HEADER ?? "").trim().toLowerCase() === "off") return;
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
188
|
+
if (!pi || typeof (pi as PiAPI).on !== "function") return;
|
|
189
|
+
(pi as PiAPI).on("session_start", (_event, ctx) => {
|
|
190
|
+
try {
|
|
191
|
+
installWidget(ctx);
|
|
192
|
+
} catch {
|
|
193
|
+
// A widget install failure must never break a pi session.
|
|
194
|
+
}
|
|
195
|
+
});
|
|
148
196
|
} catch {
|
|
149
|
-
//
|
|
197
|
+
// Registration itself must never break a pi session.
|
|
150
198
|
}
|
|
151
199
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@gonrocca/zero-pi",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.34",
|
|
4
4
|
"description": "zero-pi — an installable layer for pi (pi.dev): the zero spec-driven development workflow, per-phase model autotune, and skill auto-learning. Adds capability to pi without modifying pi.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"keywords": [
|