@quandev104/pi-style 0.2.7 → 0.2.9
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 +7 -0
- package/README.md +1 -1
- package/dist/extensions/pi-style.js +137 -35
- package/dist/extensions/pi-style.js.map +1 -1
- package/extension-src/pi-style/features/messages/index.ts +15 -2
- package/extension-src/pi-style/features/startup/index.ts +24 -4
- package/extension-src/pi-style/features/startup/logo.ts +22 -18
- package/extension-src/pi-style/pi/compatibility-probe.ts +77 -19
- package/extension-src/pi-style/shared/ansi.ts +45 -0
- package/package.json +10 -9
|
@@ -567,9 +567,21 @@ function isSpacerChild(child: unknown): boolean {
|
|
|
567
567
|
* rendered content is empty. Duck-typed on the public shape because
|
|
568
568
|
* pi-coding-agent may resolve its own nested pi-tui copy, so `instanceof`
|
|
569
569
|
* across that module boundary is unreliable.
|
|
570
|
+
*
|
|
571
|
+
* Pi 0.85.0 wraps every thinking-run component (the hidden label Text or the
|
|
572
|
+
* visible thinking Markdown) in a `MouseRegion` for click-to-toggle visibility.
|
|
573
|
+
* `MouseRegion` is render-transparent, so the placeholder check unwraps it first
|
|
574
|
+
* (duck-typed: a `handleMouse` function plus a `child`), keeping the same
|
|
575
|
+
* Text detection for the pre-0.85 bare-Text layout.
|
|
570
576
|
*/
|
|
577
|
+
function unwrapMouseRegion(child: unknown): unknown {
|
|
578
|
+
const candidate = child as { handleMouse?: unknown; child?: unknown } | undefined;
|
|
579
|
+
if (typeof candidate?.handleMouse !== "function" || candidate.child === undefined) return child;
|
|
580
|
+
return candidate.child;
|
|
581
|
+
}
|
|
582
|
+
|
|
571
583
|
function isBlankTextChild(child: unknown): boolean {
|
|
572
|
-
const candidate = child as
|
|
584
|
+
const candidate = unwrapMouseRegion(child) as
|
|
573
585
|
| { setCustomBgFn?: unknown; render?: (width: number) => string[]; text?: unknown }
|
|
574
586
|
| undefined;
|
|
575
587
|
if (typeof candidate?.setCustomBgFn !== "function" || typeof candidate.render !== "function") return false;
|
|
@@ -605,7 +617,8 @@ function markChildrenScanned(instance: object, children: readonly unknown[]): vo
|
|
|
605
617
|
*
|
|
606
618
|
* Native `AssistantMessageComponent.updateContent` renders the thinking block as
|
|
607
619
|
* `Text(theme.italic(theme.fg("thinkingText", label)), outputPad, 0)` plus a
|
|
608
|
-
* trailing `Spacer(1)
|
|
620
|
+
* trailing `Spacer(1)` — wrapped in a render-transparent `MouseRegion` since
|
|
621
|
+
* Pi 0.85.0. An empty label is still wrapped in ANSI SGR codes, so
|
|
609
622
|
* `Text.render` cannot treat it as empty (its check is `text.trim() === ""`,
|
|
610
623
|
* and trim does not strip escape sequences) and emits one full-width invisible
|
|
611
624
|
* line. That invisible row plus the surrounding spacers is the "gap" left when
|
|
@@ -2,8 +2,9 @@ import type { Component, OverlayHandle, OverlayOptions } from "@earendil-works/p
|
|
|
2
2
|
import type { NormalizedPiStyleConfig } from "../../domain/config-types.js";
|
|
3
3
|
import type { StatusSnapshot } from "../../domain/status.js";
|
|
4
4
|
import { type ActiveTheme, type ResolvedTheme, resolveTheme } from "../../domain/theme.js";
|
|
5
|
-
import { fitAnsiWidth, truncateAnsi, visibleWidth } from "../../shared/ansi.js";
|
|
6
|
-
import {
|
|
5
|
+
import { fitAnsiWidth, fitAnsiWidthTail, truncateAnsi, visibleWidth } from "../../shared/ansi.js";
|
|
6
|
+
import { shortenPath } from "../../shared/box.js";
|
|
7
|
+
import { compactLogoHeader, logoDetailWidth } from "./logo.js";
|
|
7
8
|
|
|
8
9
|
export type StartupReason = "startup" | "reload" | "new" | "resume" | "fork";
|
|
9
10
|
|
|
@@ -302,6 +303,16 @@ const STARTUP_PADDING_TOP = 2;
|
|
|
302
303
|
/** Blank rows below the block, separating it from the editor / chat. */
|
|
303
304
|
const STARTUP_PADDING_BOTTOM = 2;
|
|
304
305
|
|
|
306
|
+
/**
|
|
307
|
+
* Startup heading title: the working directory of the session (home-contracted
|
|
308
|
+
* to `~`) — i.e. the path of the repo currently being worked in. Falls back to
|
|
309
|
+
* the directory basename, then the brand, when the runtime reports no cwd.
|
|
310
|
+
*/
|
|
311
|
+
function startupProjectTitle(snapshot: StartupSnapshot): string {
|
|
312
|
+
if (snapshot.cwd) return shortenPath(snapshot.cwd);
|
|
313
|
+
return snapshot.project ?? "pi-style";
|
|
314
|
+
}
|
|
315
|
+
|
|
305
316
|
function styledLines(
|
|
306
317
|
theme: ActiveTheme,
|
|
307
318
|
config: NormalizedPiStyleConfig,
|
|
@@ -319,13 +330,22 @@ function styledLines(
|
|
|
319
330
|
// Breathing room above the block (separates it from the status line / terminal top).
|
|
320
331
|
lines.push(...Array.from({ length: STARTUP_PADDING_TOP }, () => ""));
|
|
321
332
|
|
|
322
|
-
|
|
333
|
+
// Heading: the π glyph followed by the current project path (never the
|
|
334
|
+
// package name — the heading identifies WHERE you are, not what styles it).
|
|
335
|
+
// The path is tail-fitted so the repo name survives narrow terminals.
|
|
336
|
+
const asciiMode = resolved.mode === "ascii";
|
|
337
|
+
const glyph = resolved.glyph("pi");
|
|
338
|
+
const projectTitle = startupProjectTitle(snapshot);
|
|
339
|
+
const titleBudget = Math.max(0, logoDetailWidth(bodyWidth) - (asciiMode ? 0 : visibleWidth(glyph) + 1));
|
|
340
|
+
const fittedTitle = fitAnsiWidthTail(projectTitle, titleBudget, asciiMode ? "..." : "…");
|
|
341
|
+
const logoTitle = asciiMode ? fittedTitle : `${glyph} ${fittedTitle}`;
|
|
323
342
|
lines.push(
|
|
324
343
|
...compactLogoHeader(
|
|
325
344
|
resolved,
|
|
326
345
|
[
|
|
327
346
|
resolved.apply("accent", logoTitle),
|
|
328
|
-
resolved.apply("muted", "/ commands
|
|
347
|
+
resolved.apply("muted", "/ commands"),
|
|
348
|
+
resolved.apply("muted", "! bash"),
|
|
329
349
|
resolved.apply("success", "● ready"),
|
|
330
350
|
],
|
|
331
351
|
bodyWidth,
|
|
@@ -9,15 +9,14 @@ import { fitAnsiWidth, parseAnsiFgToRgb, visibleWidth } from "../../shared/ansi.
|
|
|
9
9
|
*/
|
|
10
10
|
|
|
11
11
|
export const PI_LOGO_LINES = [
|
|
12
|
-
"
|
|
13
|
-
"
|
|
14
|
-
"
|
|
15
|
-
"
|
|
16
|
-
"
|
|
17
|
-
"
|
|
18
|
-
"
|
|
19
|
-
"
|
|
20
|
-
"╚═══╝ ╚═══╝",
|
|
12
|
+
"████████████",
|
|
13
|
+
"████████████",
|
|
14
|
+
"████ ████",
|
|
15
|
+
"████ ████",
|
|
16
|
+
"████████ ████",
|
|
17
|
+
"████████ ████",
|
|
18
|
+
"████ ████",
|
|
19
|
+
"████ ████",
|
|
21
20
|
] as const;
|
|
22
21
|
|
|
23
22
|
const LOGO_PALETTE_STEPS = 24;
|
|
@@ -117,20 +116,25 @@ export function styledLogoLines(resolved: ResolvedTheme): string[] {
|
|
|
117
116
|
return logoGradientCacheLines;
|
|
118
117
|
}
|
|
119
118
|
|
|
119
|
+
/** Width of the side-detail column next to the block-art logo at a given content width. */
|
|
120
|
+
export function logoDetailWidth(width: number): number {
|
|
121
|
+
const logoWidth = Math.max(...PI_LOGO_LINES.map((line) => visibleWidth(line)));
|
|
122
|
+
return Math.max(0, width - logoWidth - visibleWidth(LOGO_GAP));
|
|
123
|
+
}
|
|
124
|
+
|
|
120
125
|
/**
|
|
121
126
|
* Assemble the compact startup header: gradient logo with side details when
|
|
122
127
|
* wide enough, stacked logo + details next, and a minimal title/status pair
|
|
123
|
-
* for very narrow terminals.
|
|
128
|
+
* for very narrow terminals. `details` is a column of detail rows — the first
|
|
129
|
+
* is the title, the last is the status, and the rows between are hints — each
|
|
130
|
+
* rendered on its own line, vertically centered beside the logo. Every
|
|
131
|
+
* returned line fits within `width`.
|
|
124
132
|
*/
|
|
125
|
-
export function compactLogoHeader(
|
|
126
|
-
resolved: ResolvedTheme,
|
|
127
|
-
details: readonly [title: string, hints: string, status: string],
|
|
128
|
-
width: number,
|
|
129
|
-
): string[] {
|
|
133
|
+
export function compactLogoHeader(resolved: ResolvedTheme, details: readonly string[], width: number): string[] {
|
|
130
134
|
const logoLines = styledLogoLines(resolved);
|
|
131
|
-
const logoWidth = Math.max(...PI_LOGO_LINES.map((line) => visibleWidth(line)));
|
|
132
135
|
const safeWidth = Math.max(1, width);
|
|
133
|
-
const
|
|
136
|
+
const logoWidth = Math.max(...PI_LOGO_LINES.map((line) => visibleWidth(line)));
|
|
137
|
+
const detailWidth = logoDetailWidth(safeWidth);
|
|
134
138
|
|
|
135
139
|
if (detailWidth >= LOGO_SIDE_DETAIL_MIN_WIDTH) {
|
|
136
140
|
const detailStartRow = Math.max(0, Math.floor((PI_LOGO_LINES.length - details.length) / 2));
|
|
@@ -147,5 +151,5 @@ export function compactLogoHeader(
|
|
|
147
151
|
return [...logoLines, ...details.map((detail) => fitAnsiWidth(detail, safeWidth))];
|
|
148
152
|
}
|
|
149
153
|
|
|
150
|
-
return [details[0], details[
|
|
154
|
+
return [details[0] ?? "", details[details.length - 1] ?? ""].map((detail) => fitAnsiWidth(detail, safeWidth));
|
|
151
155
|
}
|
|
@@ -35,13 +35,15 @@ import {
|
|
|
35
35
|
* changes the identity degrades that single surface to its native fallback while
|
|
36
36
|
* every other surface continues.
|
|
37
37
|
*/
|
|
38
|
-
export const SUPPORTED_VERSION_RANGE = ">=0.83.0 <0.
|
|
38
|
+
export const SUPPORTED_VERSION_RANGE = ">=0.83.0 <0.86.0";
|
|
39
39
|
export const SUPPORTED_PI_VERSIONS: readonly string[] = Object.freeze([
|
|
40
40
|
"0.83.0",
|
|
41
41
|
"0.84.0",
|
|
42
42
|
"0.84.1",
|
|
43
43
|
"0.84.2",
|
|
44
44
|
"0.84.3",
|
|
45
|
+
"0.84.4",
|
|
46
|
+
"0.85.0",
|
|
45
47
|
]);
|
|
46
48
|
|
|
47
49
|
/** A recorded native identity for one certified surface. */
|
|
@@ -71,6 +73,17 @@ export interface KnownNativeIdentity {
|
|
|
71
73
|
* identity (0.83.0–0.84.2) and the bundled identity (0.84.3). The modular
|
|
72
74
|
* `dist/index.js` itself is unchanged in 0.84.3 — the switch is which class
|
|
73
75
|
* objects the running CLI actually serves to extensions.
|
|
76
|
+
*
|
|
77
|
+
* 0.84.4 rebuilds both artifact families byte-identically for every surface
|
|
78
|
+
* below, so it shares the 0.84.3 identities. 0.85.0 drifts exactly three
|
|
79
|
+
* surfaces (in both families) while preserving name/arity and the adapter
|
|
80
|
+
* contracts, so each carries a re-recorded 0.85.0 identity:
|
|
81
|
+
* - `AssistantMessageComponent.updateContent` adds per-run thinking visibility
|
|
82
|
+
* overrides (`thinkingVisibilityOverrides` + a `MouseRegion` click toggle per
|
|
83
|
+
* thinking run; the `isStreaming` default parameter and arity 1 are unchanged).
|
|
84
|
+
* - `ToolExecutionComponent.getCallRenderer`/`getResultRenderer` drop the
|
|
85
|
+
* `builtInToolDefinition` fallback branches and simply return
|
|
86
|
+
* `this.toolDefinition?.renderCall`/`renderResult` (still renderer-or-undefined).
|
|
74
87
|
*/
|
|
75
88
|
export const KNOWN_NATIVE_IDENTITIES: Readonly<Record<string, readonly KnownNativeIdentity[]>> = Object.freeze({
|
|
76
89
|
"native-assistant-message:render": Object.freeze([
|
|
@@ -78,13 +91,13 @@ export const KNOWN_NATIVE_IDENTITIES: Readonly<Record<string, readonly KnownNati
|
|
|
78
91
|
name: "render",
|
|
79
92
|
arity: 1,
|
|
80
93
|
fingerprint: "2a39243f",
|
|
81
|
-
versions: Object.freeze(["0.83.0", "0.84.0", "0.84.1", "0.84.2"]),
|
|
94
|
+
versions: Object.freeze(["0.83.0", "0.84.0", "0.84.1", "0.84.2", "0.84.4", "0.85.0"]),
|
|
82
95
|
}),
|
|
83
96
|
Object.freeze({
|
|
84
97
|
name: "render",
|
|
85
98
|
arity: 1,
|
|
86
99
|
fingerprint: "a9be09a3",
|
|
87
|
-
versions: Object.freeze(["0.84.3"]),
|
|
100
|
+
versions: Object.freeze(["0.84.3", "0.84.4", "0.85.0"]),
|
|
88
101
|
}),
|
|
89
102
|
]),
|
|
90
103
|
"native-assistant-message:updateContent": Object.freeze([
|
|
@@ -101,7 +114,7 @@ export const KNOWN_NATIVE_IDENTITIES: Readonly<Record<string, readonly KnownNati
|
|
|
101
114
|
name: "updateContent",
|
|
102
115
|
arity: 1,
|
|
103
116
|
fingerprint: "d2114491",
|
|
104
|
-
versions: Object.freeze(["0.84.0", "0.84.1", "0.84.2"]),
|
|
117
|
+
versions: Object.freeze(["0.84.0", "0.84.1", "0.84.2", "0.84.4"]),
|
|
105
118
|
}),
|
|
106
119
|
// 0.84.3: the CLI loads a minified bundled runtime and extensions receive
|
|
107
120
|
// the in-bundle class objects, so this method's toString() is the minified
|
|
@@ -111,7 +124,22 @@ export const KNOWN_NATIVE_IDENTITIES: Readonly<Record<string, readonly KnownNati
|
|
|
111
124
|
name: "updateContent",
|
|
112
125
|
arity: 1,
|
|
113
126
|
fingerprint: "356b7e83",
|
|
114
|
-
versions: Object.freeze(["0.84.3"]),
|
|
127
|
+
versions: Object.freeze(["0.84.3", "0.84.4"]),
|
|
128
|
+
}),
|
|
129
|
+
// 0.85.0 modular: adds per-run thinking visibility overrides and a
|
|
130
|
+
// MouseRegion click toggle per thinking run (arity stays 1).
|
|
131
|
+
Object.freeze({
|
|
132
|
+
name: "updateContent",
|
|
133
|
+
arity: 1,
|
|
134
|
+
fingerprint: "80e338d2",
|
|
135
|
+
versions: Object.freeze(["0.85.0"]),
|
|
136
|
+
}),
|
|
137
|
+
// 0.85.0 bundled: same drift, minified.
|
|
138
|
+
Object.freeze({
|
|
139
|
+
name: "updateContent",
|
|
140
|
+
arity: 1,
|
|
141
|
+
fingerprint: "c3d72f2b",
|
|
142
|
+
versions: Object.freeze(["0.85.0"]),
|
|
115
143
|
}),
|
|
116
144
|
]),
|
|
117
145
|
"native-compaction-message:updateDisplay": Object.freeze([
|
|
@@ -119,13 +147,13 @@ export const KNOWN_NATIVE_IDENTITIES: Readonly<Record<string, readonly KnownNati
|
|
|
119
147
|
name: "updateDisplay",
|
|
120
148
|
arity: 0,
|
|
121
149
|
fingerprint: "f8c44e78",
|
|
122
|
-
versions: Object.freeze(["0.83.0", "0.84.0", "0.84.1", "0.84.2"]),
|
|
150
|
+
versions: Object.freeze(["0.83.0", "0.84.0", "0.84.1", "0.84.2", "0.84.4", "0.85.0"]),
|
|
123
151
|
}),
|
|
124
152
|
Object.freeze({
|
|
125
153
|
name: "updateDisplay",
|
|
126
154
|
arity: 0,
|
|
127
155
|
fingerprint: "5118a51d",
|
|
128
|
-
versions: Object.freeze(["0.84.3"]),
|
|
156
|
+
versions: Object.freeze(["0.84.3", "0.84.4", "0.85.0"]),
|
|
129
157
|
}),
|
|
130
158
|
]),
|
|
131
159
|
"native-branch-message:updateDisplay": Object.freeze([
|
|
@@ -133,13 +161,13 @@ export const KNOWN_NATIVE_IDENTITIES: Readonly<Record<string, readonly KnownNati
|
|
|
133
161
|
name: "updateDisplay",
|
|
134
162
|
arity: 0,
|
|
135
163
|
fingerprint: "415d57b7",
|
|
136
|
-
versions: Object.freeze(["0.83.0", "0.84.0", "0.84.1", "0.84.2"]),
|
|
164
|
+
versions: Object.freeze(["0.83.0", "0.84.0", "0.84.1", "0.84.2", "0.84.4", "0.85.0"]),
|
|
137
165
|
}),
|
|
138
166
|
Object.freeze({
|
|
139
167
|
name: "updateDisplay",
|
|
140
168
|
arity: 0,
|
|
141
169
|
fingerprint: "2185274e",
|
|
142
|
-
versions: Object.freeze(["0.84.3"]),
|
|
170
|
+
versions: Object.freeze(["0.84.3", "0.84.4", "0.85.0"]),
|
|
143
171
|
}),
|
|
144
172
|
]),
|
|
145
173
|
"native-skill-message:updateDisplay": Object.freeze([
|
|
@@ -147,13 +175,13 @@ export const KNOWN_NATIVE_IDENTITIES: Readonly<Record<string, readonly KnownNati
|
|
|
147
175
|
name: "updateDisplay",
|
|
148
176
|
arity: 0,
|
|
149
177
|
fingerprint: "48099ea6",
|
|
150
|
-
versions: Object.freeze(["0.83.0", "0.84.0", "0.84.1", "0.84.2"]),
|
|
178
|
+
versions: Object.freeze(["0.83.0", "0.84.0", "0.84.1", "0.84.2", "0.84.4", "0.85.0"]),
|
|
151
179
|
}),
|
|
152
180
|
Object.freeze({
|
|
153
181
|
name: "updateDisplay",
|
|
154
182
|
arity: 0,
|
|
155
183
|
fingerprint: "4051fd65",
|
|
156
|
-
versions: Object.freeze(["0.84.3"]),
|
|
184
|
+
versions: Object.freeze(["0.84.3", "0.84.4", "0.85.0"]),
|
|
157
185
|
}),
|
|
158
186
|
]),
|
|
159
187
|
"native-custom-message:rebuild": Object.freeze([
|
|
@@ -161,13 +189,13 @@ export const KNOWN_NATIVE_IDENTITIES: Readonly<Record<string, readonly KnownNati
|
|
|
161
189
|
name: "rebuild",
|
|
162
190
|
arity: 0,
|
|
163
191
|
fingerprint: "76ae2e3a",
|
|
164
|
-
versions: Object.freeze(["0.83.0", "0.84.0", "0.84.1", "0.84.2"]),
|
|
192
|
+
versions: Object.freeze(["0.83.0", "0.84.0", "0.84.1", "0.84.2", "0.84.4", "0.85.0"]),
|
|
165
193
|
}),
|
|
166
194
|
Object.freeze({
|
|
167
195
|
name: "rebuild",
|
|
168
196
|
arity: 0,
|
|
169
197
|
fingerprint: "b89987cc",
|
|
170
|
-
versions: Object.freeze(["0.84.3"]),
|
|
198
|
+
versions: Object.freeze(["0.84.3", "0.84.4", "0.85.0"]),
|
|
171
199
|
}),
|
|
172
200
|
]),
|
|
173
201
|
"tool-call-renderer:getCallRenderer": Object.freeze([
|
|
@@ -175,13 +203,28 @@ export const KNOWN_NATIVE_IDENTITIES: Readonly<Record<string, readonly KnownNati
|
|
|
175
203
|
name: "getCallRenderer",
|
|
176
204
|
arity: 0,
|
|
177
205
|
fingerprint: "951ea0e0",
|
|
178
|
-
versions: Object.freeze(["0.83.0", "0.84.0", "0.84.1", "0.84.2"]),
|
|
206
|
+
versions: Object.freeze(["0.83.0", "0.84.0", "0.84.1", "0.84.2", "0.84.4"]),
|
|
179
207
|
}),
|
|
180
208
|
Object.freeze({
|
|
181
209
|
name: "getCallRenderer",
|
|
182
210
|
arity: 0,
|
|
183
211
|
fingerprint: "e50613b7",
|
|
184
|
-
versions: Object.freeze(["0.84.3"]),
|
|
212
|
+
versions: Object.freeze(["0.84.3", "0.84.4"]),
|
|
213
|
+
}),
|
|
214
|
+
// 0.85.0 modular: drops the `builtInToolDefinition` fallback branches
|
|
215
|
+
// and returns `this.toolDefinition?.renderCall` directly.
|
|
216
|
+
Object.freeze({
|
|
217
|
+
name: "getCallRenderer",
|
|
218
|
+
arity: 0,
|
|
219
|
+
fingerprint: "e0a9ed86",
|
|
220
|
+
versions: Object.freeze(["0.85.0"]),
|
|
221
|
+
}),
|
|
222
|
+
// 0.85.0 bundled: same drift, minified.
|
|
223
|
+
Object.freeze({
|
|
224
|
+
name: "getCallRenderer",
|
|
225
|
+
arity: 0,
|
|
226
|
+
fingerprint: "73116365",
|
|
227
|
+
versions: Object.freeze(["0.85.0"]),
|
|
185
228
|
}),
|
|
186
229
|
]),
|
|
187
230
|
"tool-result-renderer:getResultRenderer": Object.freeze([
|
|
@@ -189,13 +232,28 @@ export const KNOWN_NATIVE_IDENTITIES: Readonly<Record<string, readonly KnownNati
|
|
|
189
232
|
name: "getResultRenderer",
|
|
190
233
|
arity: 0,
|
|
191
234
|
fingerprint: "8a25cd71",
|
|
192
|
-
versions: Object.freeze(["0.83.0", "0.84.0", "0.84.1", "0.84.2"]),
|
|
235
|
+
versions: Object.freeze(["0.83.0", "0.84.0", "0.84.1", "0.84.2", "0.84.4"]),
|
|
193
236
|
}),
|
|
194
237
|
Object.freeze({
|
|
195
238
|
name: "getResultRenderer",
|
|
196
239
|
arity: 0,
|
|
197
240
|
fingerprint: "28c4dc22",
|
|
198
|
-
versions: Object.freeze(["0.84.3"]),
|
|
241
|
+
versions: Object.freeze(["0.84.3", "0.84.4"]),
|
|
242
|
+
}),
|
|
243
|
+
// 0.85.0 modular: drops the `builtInToolDefinition` fallback branches
|
|
244
|
+
// and returns `this.toolDefinition?.renderResult` directly.
|
|
245
|
+
Object.freeze({
|
|
246
|
+
name: "getResultRenderer",
|
|
247
|
+
arity: 0,
|
|
248
|
+
fingerprint: "1567dcf4",
|
|
249
|
+
versions: Object.freeze(["0.85.0"]),
|
|
250
|
+
}),
|
|
251
|
+
// 0.85.0 bundled: same drift, minified.
|
|
252
|
+
Object.freeze({
|
|
253
|
+
name: "getResultRenderer",
|
|
254
|
+
arity: 0,
|
|
255
|
+
fingerprint: "d613a2a3",
|
|
256
|
+
versions: Object.freeze(["0.85.0"]),
|
|
199
257
|
}),
|
|
200
258
|
]),
|
|
201
259
|
"native-bash-execution:render": Object.freeze([
|
|
@@ -207,13 +265,13 @@ export const KNOWN_NATIVE_IDENTITIES: Readonly<Record<string, readonly KnownNati
|
|
|
207
265
|
name: "BashExecutionComponent",
|
|
208
266
|
arity: 2,
|
|
209
267
|
fingerprint: "a5b5abca",
|
|
210
|
-
versions: Object.freeze(["0.83.0", "0.84.0", "0.84.1", "0.84.2"]),
|
|
268
|
+
versions: Object.freeze(["0.83.0", "0.84.0", "0.84.1", "0.84.2", "0.84.4", "0.85.0"]),
|
|
211
269
|
}),
|
|
212
270
|
Object.freeze({
|
|
213
271
|
name: "BashExecutionComponent",
|
|
214
272
|
arity: 2,
|
|
215
273
|
fingerprint: "98d22d96",
|
|
216
|
-
versions: Object.freeze(["0.84.3"]),
|
|
274
|
+
versions: Object.freeze(["0.84.3", "0.84.4", "0.85.0"]),
|
|
217
275
|
}),
|
|
218
276
|
]),
|
|
219
277
|
});
|
|
@@ -108,6 +108,51 @@ export function resetAnsi(value: string): string {
|
|
|
108
108
|
export function fitAnsiWidth(value: string, width: number, ellipsis = "…"): string {
|
|
109
109
|
return visibleWidth(value) <= width ? value : truncateAnsi(value, width, ellipsis);
|
|
110
110
|
}
|
|
111
|
+
/**
|
|
112
|
+
* Fit a string by dropping the HEAD (keeping the tail): for path-like values
|
|
113
|
+
* whose meaningful part is the end (the repo name). ANSI-aware — an escape run
|
|
114
|
+
* belongs to the visible character it precedes, so dropped characters drop
|
|
115
|
+
* their styling with them and the first kept character keeps its own escape.
|
|
116
|
+
*/
|
|
117
|
+
export function fitAnsiWidthTail(value: string, width: number, ellipsis = "…"): string {
|
|
118
|
+
if (width <= 0) return "";
|
|
119
|
+
if (visibleWidth(value) <= width) return resetAnsi(value);
|
|
120
|
+
const ellipsisWidth = visibleWidth(ellipsis);
|
|
121
|
+
if (width <= ellipsisWidth) return resetAnsi(ellipsis);
|
|
122
|
+
type Unit = { ansi: string; char: string; charWidth: number };
|
|
123
|
+
const units: Unit[] = [];
|
|
124
|
+
let pending = "";
|
|
125
|
+
for (let i = 0; i < value.length; i++) {
|
|
126
|
+
const code = value.charCodeAt(i);
|
|
127
|
+
if (code === 27) {
|
|
128
|
+
const start = i;
|
|
129
|
+
i++;
|
|
130
|
+
while (i + 1 < value.length && !isFinal(value[i + 1] ?? "")) i++;
|
|
131
|
+
i++;
|
|
132
|
+
pending += value.slice(start, i + 1);
|
|
133
|
+
continue;
|
|
134
|
+
}
|
|
135
|
+
let char = value[i] ?? "";
|
|
136
|
+
// Keep surrogate pairs (emoji etc.) as one unit.
|
|
137
|
+
if (code >= 0xd800 && code <= 0xdbff && i + 1 < value.length) char += value[++i];
|
|
138
|
+
units.push({ ansi: pending, char, charWidth: visibleWidth(char) || 1 });
|
|
139
|
+
pending = "";
|
|
140
|
+
}
|
|
141
|
+
let kept = 0;
|
|
142
|
+
let used = ellipsisWidth;
|
|
143
|
+
while (kept < units.length) {
|
|
144
|
+
const unit = units[units.length - 1 - kept];
|
|
145
|
+
if (!unit || used + unit.charWidth > width) break;
|
|
146
|
+
used += unit.charWidth;
|
|
147
|
+
kept++;
|
|
148
|
+
}
|
|
149
|
+
let output = ellipsis;
|
|
150
|
+
for (let index = units.length - kept; index < units.length; index++) {
|
|
151
|
+
const unit = units[index];
|
|
152
|
+
if (unit) output += unit.ansi + unit.char;
|
|
153
|
+
}
|
|
154
|
+
return resetAnsi(output);
|
|
155
|
+
}
|
|
111
156
|
export function truncateAnsi(value: string, width: number, ellipsis = "…"): string {
|
|
112
157
|
if (width <= 0) return "";
|
|
113
158
|
if (visibleWidth(value) <= width) return resetAnsi(value);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@quandev104/pi-style",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.9",
|
|
4
4
|
"description": "A native-layout, cohesive visual style package for Pi.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
@@ -42,18 +42,19 @@
|
|
|
42
42
|
"check": "npm run typecheck && npm run lint && npm run depcruise && npm run test && npm run build && npm run package:smoke"
|
|
43
43
|
},
|
|
44
44
|
"peerDependencies": {
|
|
45
|
-
"@earendil-works/pi-agent-core": ">=0.83.0 <0.
|
|
46
|
-
"@earendil-works/pi-ai": ">=0.83.0 <0.
|
|
47
|
-
"@earendil-works/pi-coding-agent": ">=0.83.0 <0.
|
|
48
|
-
"@earendil-works/pi-tui": ">=0.83.0 <0.
|
|
45
|
+
"@earendil-works/pi-agent-core": ">=0.83.0 <0.86.0",
|
|
46
|
+
"@earendil-works/pi-ai": ">=0.83.0 <0.86.0",
|
|
47
|
+
"@earendil-works/pi-coding-agent": ">=0.83.0 <0.86.0",
|
|
48
|
+
"@earendil-works/pi-tui": ">=0.83.0 <0.86.0",
|
|
49
49
|
"typebox": ">=1.3.9 <2.0.0"
|
|
50
50
|
},
|
|
51
51
|
"devDependencies": {
|
|
52
52
|
"@biomejs/biome": "^2.5.0",
|
|
53
|
-
"@earendil-works/pi-agent-core": "^0.
|
|
54
|
-
"@earendil-works/pi-ai": "^0.
|
|
55
|
-
"@earendil-works/pi-coding-agent": "^0.
|
|
56
|
-
"@earendil-works/pi-
|
|
53
|
+
"@earendil-works/pi-agent-core": "^0.85.0",
|
|
54
|
+
"@earendil-works/pi-ai": "^0.85.0",
|
|
55
|
+
"@earendil-works/pi-coding-agent": "^0.85.0",
|
|
56
|
+
"@earendil-works/pi-server": "^0.85.0",
|
|
57
|
+
"@earendil-works/pi-tui": "^0.85.0",
|
|
57
58
|
"@types/node": "^24.0.0",
|
|
58
59
|
"dependency-cruiser": "^17.4.3",
|
|
59
60
|
"git-cliff": "^2.13.1",
|