@anthodev/pi-tools-style 0.1.0 → 0.1.3
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 +26 -32
- package/package.json +7 -2
- package/src/render-decorator.ts +68 -8
package/README.md
CHANGED
|
@@ -2,6 +2,12 @@
|
|
|
2
2
|
|
|
3
3
|
<p align="center"><strong>Give Pi tool activity clear, theme-aware structure without changing how tools run.</strong></p>
|
|
4
4
|
|
|
5
|
+
<p align="center">
|
|
6
|
+
<a href="https://github.com/Anthodev/pi-tools-style/actions/workflows/ci.yml?query=branch%3Adevelop"><img alt="Tests" src="https://img.shields.io/github/actions/workflow/status/Anthodev/pi-tools-style/ci.yml?branch=develop&style=for-the-badge&label=tests&labelColor=101418"></a>
|
|
7
|
+
<a href="https://github.com/Anthodev/pi-tools-style/releases/latest"><img alt="Latest stable release" src="https://img.shields.io/github/v/release/Anthodev/pi-tools-style?style=for-the-badge&label=release&labelColor=101418&color=9ccbfb"></a>
|
|
8
|
+
<a href="https://github.com/Anthodev/pi-tools-style/blob/develop/LICENSE"><img alt="MIT License" src="https://img.shields.io/github/license/Anthodev/pi-tools-style?style=for-the-badge&labelColor=101418&color=b9c8da"></a>
|
|
9
|
+
</p>
|
|
10
|
+
|
|
5
11
|
`pi-tools-style` adds rounded frames, tool-specific icons, and live running indicators to Pi tool calls and direct shell commands. It decorates the output Pi already produces instead of replacing tool definitions or renderers.
|
|
6
12
|
|
|
7
13
|
Built-in tools, MCP integrations, AFT, and third-party extensions keep control of their schemas, permissions, prompts, execution backends, and rendered content. When an output cannot be framed safely, the extension leaves it untouched.
|
|
@@ -17,6 +23,26 @@ Built-in tools, MCP integrations, AFT, and third-party extensions keep control o
|
|
|
17
23
|
- **Image-safe fallback** — skips Kitty, iTerm2, and Sixel rows instead of corrupting terminal image sequences.
|
|
18
24
|
- **Reload-safe state** — keeps wrappers and runtime configuration idempotent across `/reload`.
|
|
19
25
|
|
|
26
|
+
## Installation
|
|
27
|
+
|
|
28
|
+
The current release targets Pi `0.84.x` and requires Node.js 22 or newer.2
|
|
29
|
+
|
|
30
|
+
To install it, use the following command:
|
|
31
|
+
|
|
32
|
+
```bash
|
|
33
|
+
pi install npm:@anthodev/pi-tools-style
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
To install this checkout as a local Pi package:
|
|
37
|
+
|
|
38
|
+
```bash
|
|
39
|
+
cd /absolute/path/to/pi-tools-style
|
|
40
|
+
npm install --legacy-peer-deps
|
|
41
|
+
pi install "$(pwd)"
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
Pi stores the package in user settings and references the directory directly, so local changes become available after `/reload` or a restart.
|
|
45
|
+
|
|
20
46
|
## What it looks like
|
|
21
47
|
|
|
22
48
|
ASCII mode stays readable in any terminal:
|
|
@@ -45,38 +71,6 @@ Once execution finishes, the spinner disappears and the title remains stable:
|
|
|
45
71
|
|
|
46
72
|
Direct `!` and `!!` commands use the same frame with a `shell` title. Slash-command output remains unchanged because Pi does not expose one uniform transcript component for slash commands.
|
|
47
73
|
|
|
48
|
-
## Installation
|
|
49
|
-
|
|
50
|
-
The current release targets Pi `0.84.x` and requires Node.js 22 or newer.
|
|
51
|
-
|
|
52
|
-
To install this checkout as a local Pi package:
|
|
53
|
-
|
|
54
|
-
```bash
|
|
55
|
-
cd /absolute/path/to/pi-tools-style
|
|
56
|
-
npm install --legacy-peer-deps
|
|
57
|
-
pi install "$(pwd)"
|
|
58
|
-
```
|
|
59
|
-
|
|
60
|
-
Pi stores the package in user settings and references the directory directly, so local changes become available after `/reload` or a restart.
|
|
61
|
-
|
|
62
|
-
To install it only for the current project, run this from that project:
|
|
63
|
-
|
|
64
|
-
```bash
|
|
65
|
-
pi install -l /absolute/path/to/pi-tools-style
|
|
66
|
-
```
|
|
67
|
-
|
|
68
|
-
To try the extension without installing it:
|
|
69
|
-
|
|
70
|
-
```bash
|
|
71
|
-
pi -e /absolute/path/to/pi-tools-style/index.ts
|
|
72
|
-
```
|
|
73
|
-
|
|
74
|
-
Once the package is published to npm, it can also be installed with:
|
|
75
|
-
|
|
76
|
-
```bash
|
|
77
|
-
pi install npm:@anthodev/pi-tools-style
|
|
78
|
-
```
|
|
79
|
-
|
|
80
74
|
## Usage
|
|
81
75
|
|
|
82
76
|
Boxes start enabled. Manage them from Pi with:
|
package/package.json
CHANGED
|
@@ -1,8 +1,13 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@anthodev/pi-tools-style",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.3",
|
|
4
4
|
"description": "Presentation-only boxes for Pi tool calls and shell commands",
|
|
5
|
-
"keywords": [
|
|
5
|
+
"keywords": [
|
|
6
|
+
"pi-package",
|
|
7
|
+
"pi-extension",
|
|
8
|
+
"tui",
|
|
9
|
+
"tools"
|
|
10
|
+
],
|
|
6
11
|
"type": "module",
|
|
7
12
|
"license": "MIT",
|
|
8
13
|
"repository": {
|
package/src/render-decorator.ts
CHANGED
|
@@ -34,6 +34,23 @@ interface StoredConfig extends Omit<RenderDecoratorConfig, "enabled"> {
|
|
|
34
34
|
enabled: boolean;
|
|
35
35
|
}
|
|
36
36
|
|
|
37
|
+
interface ResolvedFrameOptions {
|
|
38
|
+
options: FrameOptions;
|
|
39
|
+
styleSignature: string | undefined;
|
|
40
|
+
title: string | undefined;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
interface RenderCacheEntry {
|
|
44
|
+
config: StoredConfig;
|
|
45
|
+
output: string[];
|
|
46
|
+
rendered: readonly string[];
|
|
47
|
+
styleSignature: string | undefined;
|
|
48
|
+
title: string | undefined;
|
|
49
|
+
width: number;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
const BORDER_STYLE_PROBE = "╭─╮│╰─╯";
|
|
53
|
+
|
|
37
54
|
export function installRenderDecorator<T extends Renderable>(
|
|
38
55
|
component: RenderableConstructor<T>,
|
|
39
56
|
config: RenderDecoratorConfig<T>,
|
|
@@ -96,6 +113,8 @@ function createDecoratedRenderer(
|
|
|
96
113
|
key: symbol,
|
|
97
114
|
renderOriginal: RenderFunction,
|
|
98
115
|
): RenderFunction {
|
|
116
|
+
const cache = new WeakMap<Renderable, RenderCacheEntry>();
|
|
117
|
+
|
|
99
118
|
return function decoratedRender(width: number): string[] {
|
|
100
119
|
const current = readConfig(key);
|
|
101
120
|
if (!current?.enabled) return renderOriginal.call(this, width);
|
|
@@ -109,22 +128,38 @@ function createDecoratedRenderer(
|
|
|
109
128
|
}
|
|
110
129
|
|
|
111
130
|
try {
|
|
112
|
-
|
|
131
|
+
const resolved = resolveFrameOptions(this, current);
|
|
132
|
+
const cached = cache.get(this);
|
|
133
|
+
if (
|
|
134
|
+
cached?.config === current &&
|
|
135
|
+
cached.width === width &&
|
|
136
|
+
cached.title === resolved.title &&
|
|
137
|
+
cached.styleSignature === resolved.styleSignature &&
|
|
138
|
+
linesEqual(cached.rendered, rendered)
|
|
139
|
+
) {
|
|
140
|
+
return cached.output;
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
const output = decorateLines(rendered, width, current, resolved.options);
|
|
144
|
+
cache.set(this, {
|
|
145
|
+
config: current,
|
|
146
|
+
output,
|
|
147
|
+
rendered: [...rendered],
|
|
148
|
+
styleSignature: resolved.styleSignature,
|
|
149
|
+
title: resolved.title,
|
|
150
|
+
width,
|
|
151
|
+
});
|
|
152
|
+
return output;
|
|
113
153
|
} catch {
|
|
114
154
|
return renderOriginal.call(this, width);
|
|
115
155
|
}
|
|
116
156
|
};
|
|
117
157
|
}
|
|
118
158
|
|
|
119
|
-
function
|
|
159
|
+
function resolveFrameOptions(
|
|
120
160
|
instance: Renderable,
|
|
121
|
-
rendered: readonly string[],
|
|
122
|
-
width: number,
|
|
123
161
|
config: StoredConfig,
|
|
124
|
-
):
|
|
125
|
-
const lines = config.trimOuterRules
|
|
126
|
-
? trimOuterRules(rendered)
|
|
127
|
-
: [...rendered];
|
|
162
|
+
): ResolvedFrameOptions {
|
|
128
163
|
const title = config.title?.(instance);
|
|
129
164
|
const options: FrameOptions = {};
|
|
130
165
|
|
|
@@ -137,9 +172,34 @@ function decorateLines(
|
|
|
137
172
|
}
|
|
138
173
|
if (title) options.title = title;
|
|
139
174
|
|
|
175
|
+
return {
|
|
176
|
+
options,
|
|
177
|
+
// Theme providers can change border output without changing component content.
|
|
178
|
+
styleSignature: styleBorder?.(BORDER_STYLE_PROBE),
|
|
179
|
+
title,
|
|
180
|
+
};
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
function decorateLines(
|
|
184
|
+
rendered: readonly string[],
|
|
185
|
+
width: number,
|
|
186
|
+
config: StoredConfig,
|
|
187
|
+
options: FrameOptions,
|
|
188
|
+
): string[] {
|
|
189
|
+
const lines = config.trimOuterRules
|
|
190
|
+
? trimOuterRules(rendered)
|
|
191
|
+
: [...rendered];
|
|
192
|
+
|
|
140
193
|
return frameLines(lines, width, options);
|
|
141
194
|
}
|
|
142
195
|
|
|
196
|
+
function linesEqual(left: readonly string[], right: readonly string[]): boolean {
|
|
197
|
+
return (
|
|
198
|
+
left.length === right.length &&
|
|
199
|
+
left.every((line, index) => line === right[index])
|
|
200
|
+
);
|
|
201
|
+
}
|
|
202
|
+
|
|
143
203
|
function storeConfig<T extends Renderable>(
|
|
144
204
|
config: RenderDecoratorConfig<T>,
|
|
145
205
|
): void {
|