@rosetears/aili-pi 0.1.0 → 0.1.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.
- package/README.md +7 -1
- package/THIRD_PARTY_NOTICES.md +11 -0
- package/extensions/header/index.ts +92 -0
- package/extensions/matrix/index.ts +375 -0
- package/extensions/zentui/config.ts +1014 -0
- package/extensions/zentui/extension-status.ts +96 -0
- package/extensions/zentui/fixed-editor/cluster.ts +98 -0
- package/extensions/zentui/fixed-editor/compositor.ts +719 -0
- package/extensions/zentui/fixed-editor/index.ts +223 -0
- package/extensions/zentui/fixed-editor/input.ts +85 -0
- package/extensions/zentui/fixed-editor/pi-compat.ts +296 -0
- package/extensions/zentui/fixed-editor/selection.ts +217 -0
- package/extensions/zentui/fixed-editor/terminal-modes.ts +75 -0
- package/extensions/zentui/fixed-editor/types.ts +37 -0
- package/extensions/zentui/footer-format.ts +279 -0
- package/extensions/zentui/footer.ts +595 -0
- package/extensions/zentui/format.ts +434 -0
- package/extensions/zentui/git.ts +384 -0
- package/extensions/zentui/gradient.ts +70 -0
- package/extensions/zentui/icons.ts +252 -0
- package/extensions/zentui/index.ts +577 -0
- package/extensions/zentui/live-context.ts +75 -0
- package/extensions/zentui/package-version.ts +650 -0
- package/extensions/zentui/project-refresh.ts +104 -0
- package/extensions/zentui/project-state.ts +59 -0
- package/extensions/zentui/prototype-patch-registry.ts +111 -0
- package/extensions/zentui/runtime.ts +841 -0
- package/extensions/zentui/selector-border.ts +77 -0
- package/extensions/zentui/session-lifecycle.ts +60 -0
- package/extensions/zentui/settings-command.ts +897 -0
- package/extensions/zentui/state.ts +55 -0
- package/extensions/zentui/style.ts +332 -0
- package/extensions/zentui/thinking-message.ts +159 -0
- package/extensions/zentui/tool-execution.ts +189 -0
- package/extensions/zentui/ui.ts +618 -0
- package/extensions/zentui/user-message.ts +252 -0
- package/licenses/pi-sakura-cyberdeck-MIT.txt +21 -0
- package/licenses/pi-zentui-MIT.txt +21 -0
- package/manifests/provenance.json +11 -0
- package/manifests/sbom.json +17 -1
- package/notices/pi-sakura-cyberdeck-NOTICE.txt +6 -0
- package/package.json +11 -2
- package/src/runtime/doctor.ts +1 -1
- package/src/runtime/registry.ts +1 -1
- package/src/runtime/rem-head.txt +38 -0
- package/themes/rem-cyberdeck.json +32 -0
|
@@ -0,0 +1,189 @@
|
|
|
1
|
+
import { type Theme, ToolExecutionComponent } from "@earendil-works/pi-coding-agent";
|
|
2
|
+
import { visibleWidth } from "@earendil-works/pi-tui";
|
|
3
|
+
import { renderBoxedLine, renderSakuraGradient } from "./gradient.js";
|
|
4
|
+
import { installPrototypePatch } from "./prototype-patch-registry.js";
|
|
5
|
+
|
|
6
|
+
const SETTLED_CACHE_MAX_LINES = 80;
|
|
7
|
+
const SETTLED_CACHE_MAX_CHARS = 64 * 1024;
|
|
8
|
+
|
|
9
|
+
type Cleanup = () => void;
|
|
10
|
+
type ToolExecutionRuntime = {
|
|
11
|
+
isPartial?: boolean;
|
|
12
|
+
result?: {
|
|
13
|
+
isError?: boolean;
|
|
14
|
+
content?: Array<{ type?: string }>;
|
|
15
|
+
};
|
|
16
|
+
toolName?: string;
|
|
17
|
+
hideComponent?: boolean;
|
|
18
|
+
expanded?: boolean;
|
|
19
|
+
showImages?: boolean;
|
|
20
|
+
getRenderShell?: () => "default" | "self";
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
type SettledRender = {
|
|
24
|
+
width: number;
|
|
25
|
+
result: ToolExecutionRuntime["result"];
|
|
26
|
+
expanded: boolean;
|
|
27
|
+
showImages: boolean;
|
|
28
|
+
lines: string[];
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
function isBlank(line: string): boolean {
|
|
32
|
+
return line.replace(/\x1b\[[0-?]*[ -/]*[@-~]/g, "").trim().length === 0;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
function containsTerminalImage(lines: readonly string[]): boolean {
|
|
36
|
+
return lines.some((line) => line.includes("\x1b_G") || line.includes("\x1b]1337;File="));
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
function truncatePlainText(text: string, maxWidth: number): string {
|
|
40
|
+
let result = "";
|
|
41
|
+
let width = 0;
|
|
42
|
+
for (const char of text) {
|
|
43
|
+
const charWidth = visibleWidth(char);
|
|
44
|
+
if (width + charWidth > maxWidth) break;
|
|
45
|
+
result += char;
|
|
46
|
+
width += charWidth;
|
|
47
|
+
}
|
|
48
|
+
return result;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
function fitBorderLabel(label: string, width: number): string {
|
|
52
|
+
if (width <= 0) return "";
|
|
53
|
+
if (width === 1) return "╭";
|
|
54
|
+
const innerWidth = Math.max(0, width - 2);
|
|
55
|
+
const lead = truncatePlainText(`─ ${label} `, innerWidth);
|
|
56
|
+
return `╭${lead}${"─".repeat(Math.max(0, innerWidth - visibleWidth(lead)))}╮`;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
function bottomBorder(width: number): string {
|
|
60
|
+
if (width <= 0) return "";
|
|
61
|
+
if (width === 1) return "╰";
|
|
62
|
+
return `╰${"─".repeat(Math.max(0, width - 2))}╯`;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
function statusLabel(runtime: ToolExecutionRuntime): string {
|
|
66
|
+
const name = (runtime.toolName || "tool").replaceAll("_", " ").toUpperCase();
|
|
67
|
+
if (runtime.isPartial !== false) return `◆ ${name} · RUNNING`;
|
|
68
|
+
return runtime.result?.isError ? `× ${name} · FAILED` : `✓ ${name} · COMPLETE`;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
function containsResultImage(runtime: ToolExecutionRuntime): boolean {
|
|
72
|
+
return runtime.result?.content?.some((item) => item.type === "image") ?? false;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
function isCacheableSettledRender(lines: readonly string[]): boolean {
|
|
76
|
+
if (lines.length > SETTLED_CACHE_MAX_LINES) return false;
|
|
77
|
+
let chars = 0;
|
|
78
|
+
for (const line of lines) {
|
|
79
|
+
chars += line.length;
|
|
80
|
+
if (chars > SETTLED_CACHE_MAX_CHARS) return false;
|
|
81
|
+
}
|
|
82
|
+
return true;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* Give built-in/default-shell tool rows a compact status rail. Settled rows are
|
|
87
|
+
* cached because animation renders otherwise rebuild every historical tool box;
|
|
88
|
+
* success/error stays on the rail instead of a full green/red background.
|
|
89
|
+
*/
|
|
90
|
+
export function installToolExecutionStyle(getTheme: () => Theme | undefined): Cleanup {
|
|
91
|
+
const settledRenders = new WeakMap<object, SettledRender>();
|
|
92
|
+
|
|
93
|
+
const cleanupRenderPatch = installPrototypePatch(
|
|
94
|
+
ToolExecutionComponent.prototype,
|
|
95
|
+
"render",
|
|
96
|
+
"tool-execution-render",
|
|
97
|
+
({ predecessor, receiver, args }) => {
|
|
98
|
+
const width = args[0];
|
|
99
|
+
const runtime = receiver as ToolExecutionRuntime;
|
|
100
|
+
if (
|
|
101
|
+
typeof width === "number" &&
|
|
102
|
+
runtime.isPartial === false &&
|
|
103
|
+
!runtime.hideComponent &&
|
|
104
|
+
!containsResultImage(runtime)
|
|
105
|
+
) {
|
|
106
|
+
const cached = settledRenders.get(receiver as object);
|
|
107
|
+
if (
|
|
108
|
+
cached?.width === width &&
|
|
109
|
+
cached.result === runtime.result &&
|
|
110
|
+
cached.expanded === Boolean(runtime.expanded) &&
|
|
111
|
+
cached.showImages === Boolean(runtime.showImages)
|
|
112
|
+
) {
|
|
113
|
+
return cached.lines;
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
const rendered = Reflect.apply(predecessor, receiver, args);
|
|
118
|
+
if (!Array.isArray(rendered) || !rendered.every((line) => typeof line === "string")) {
|
|
119
|
+
return rendered;
|
|
120
|
+
}
|
|
121
|
+
const lines = rendered as string[];
|
|
122
|
+
if (
|
|
123
|
+
typeof width !== "number" ||
|
|
124
|
+
width <= 2 ||
|
|
125
|
+
lines.length === 0 ||
|
|
126
|
+
runtime.hideComponent ||
|
|
127
|
+
runtime.getRenderShell?.() === "self" ||
|
|
128
|
+
containsTerminalImage(lines)
|
|
129
|
+
) {
|
|
130
|
+
return lines;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
const theme = getTheme();
|
|
134
|
+
if (!theme) return lines;
|
|
135
|
+
const pending = runtime.isPartial !== false;
|
|
136
|
+
|
|
137
|
+
const prefix: string[] = [];
|
|
138
|
+
const body = [...lines];
|
|
139
|
+
if (body[0] !== undefined && isBlank(body[0])) {
|
|
140
|
+
const blank = body.shift();
|
|
141
|
+
if (blank !== undefined) prefix.push(blank);
|
|
142
|
+
}
|
|
143
|
+
const label = fitBorderLabel(statusLabel(runtime), width);
|
|
144
|
+
const top = renderSakuraGradient(label);
|
|
145
|
+
// Keep only the status rail slightly heavier. State is expressed in the
|
|
146
|
+
// native macaron palette rather than traffic-light red/green: lavender
|
|
147
|
+
// while running, sky blue when complete, and Sakura pink when failed.
|
|
148
|
+
const leftRail = pending
|
|
149
|
+
? theme.fg("thinkingXhigh", "┃ ")
|
|
150
|
+
: runtime.result?.isError
|
|
151
|
+
? theme.fg("accent", "┃ ")
|
|
152
|
+
: theme.fg("syntaxFunction", "┃ ");
|
|
153
|
+
const rightRail = renderSakuraGradient(" │");
|
|
154
|
+
const bottom = renderSakuraGradient(bottomBorder(width));
|
|
155
|
+
|
|
156
|
+
const boxed = [
|
|
157
|
+
...prefix,
|
|
158
|
+
top,
|
|
159
|
+
...body.map((line) => renderBoxedLine(line, width, leftRail, rightRail)),
|
|
160
|
+
bottom,
|
|
161
|
+
];
|
|
162
|
+
if (!pending && !containsResultImage(runtime) && isCacheableSettledRender(boxed)) {
|
|
163
|
+
settledRenders.set(receiver as object, {
|
|
164
|
+
width,
|
|
165
|
+
result: runtime.result,
|
|
166
|
+
expanded: Boolean(runtime.expanded),
|
|
167
|
+
showImages: Boolean(runtime.showImages),
|
|
168
|
+
lines: boxed,
|
|
169
|
+
});
|
|
170
|
+
}
|
|
171
|
+
return boxed;
|
|
172
|
+
},
|
|
173
|
+
);
|
|
174
|
+
|
|
175
|
+
const cleanupInvalidatePatch = installPrototypePatch(
|
|
176
|
+
ToolExecutionComponent.prototype,
|
|
177
|
+
"invalidate",
|
|
178
|
+
"tool-execution-invalidate",
|
|
179
|
+
({ predecessor, receiver, args }) => {
|
|
180
|
+
settledRenders.delete(receiver as object);
|
|
181
|
+
return Reflect.apply(predecessor, receiver, args);
|
|
182
|
+
},
|
|
183
|
+
);
|
|
184
|
+
|
|
185
|
+
return () => {
|
|
186
|
+
cleanupInvalidatePatch();
|
|
187
|
+
cleanupRenderPatch();
|
|
188
|
+
};
|
|
189
|
+
}
|