@heyhuynhgiabuu/pi-pretty 0.3.2 → 0.3.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 +10 -0
- package/package.json +1 -1
- package/release-notes/v0.3.3.md +48 -0
- package/src/index.ts +77 -41
- package/test/fff-integration.test.ts +16 -3
package/README.md
CHANGED
|
@@ -51,6 +51,16 @@ When running in **tmux**, pi-pretty uses passthrough escape sequences.
|
|
|
51
51
|
>
|
|
52
52
|
> (or run once in a session: `tmux set -g allow-passthrough on`)
|
|
53
53
|
|
|
54
|
+
## FFF data directory
|
|
55
|
+
|
|
56
|
+
When FFF is available, pi-pretty now stores its frecency/history data under a pi-pretty-specific path:
|
|
57
|
+
|
|
58
|
+
```text
|
|
59
|
+
~/.pi/agent/pi-pretty/fff/
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
This makes it clear that the cache belongs to this extension rather than Pi core.
|
|
63
|
+
|
|
54
64
|
## Configuration
|
|
55
65
|
|
|
56
66
|
Optional environment variables:
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@heyhuynhgiabuu/pi-pretty",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.3",
|
|
4
4
|
"description": "Pretty terminal output for pi — syntax-highlighted file reads, colored bash output, tree-view directory listings, and more.",
|
|
5
5
|
"author": "huynhgiabuu",
|
|
6
6
|
"license": "MIT",
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
# pi-pretty v0.3.3
|
|
2
|
+
|
|
3
|
+
## Summary
|
|
4
|
+
This patch release combines the recent rendering and FFF-path fixes into a single `v0.3.3` release.
|
|
5
|
+
|
|
6
|
+
## What changed
|
|
7
|
+
- Fixed themed tool background rendering so `toolSuccessBg` and `toolErrorBg` fill the full rendered width for core tool output.
|
|
8
|
+
- Preserved the active tool background across ANSI reset sequences to avoid broken background bands inside highlighted output.
|
|
9
|
+
- Kept error rendering on `theme.fg("error", ...)` while switching error panels to `toolErrorBg`.
|
|
10
|
+
- Moved pi-pretty FFF data from:
|
|
11
|
+
- `~/.pi/agent/fff`
|
|
12
|
+
- To:
|
|
13
|
+
- `~/.pi/agent/pi-pretty/fff`
|
|
14
|
+
- Added a helper to resolve the pi-pretty-specific FFF directory under `getAgentDir()`.
|
|
15
|
+
- Updated README to document the pi-pretty-owned FFF data location.
|
|
16
|
+
- Added a test that verifies the generated frecency/history DB paths use the new per-extension location.
|
|
17
|
+
|
|
18
|
+
## Files
|
|
19
|
+
- `src/index.ts`
|
|
20
|
+
- `test/fff-integration.test.ts`
|
|
21
|
+
- `README.md`
|
|
22
|
+
- `package.json`
|
|
23
|
+
- `package-lock.json`
|
|
24
|
+
|
|
25
|
+
## Verification
|
|
26
|
+
- `npm run typecheck` ✅
|
|
27
|
+
- `npm test` ✅ (47 tests)
|
|
28
|
+
- `npm run lint` ⚠️ still reports pre-existing Biome diagnostics in legacy code paths; no new release-blocking failure was introduced for this patch.
|
|
29
|
+
|
|
30
|
+
## Upgrade notes
|
|
31
|
+
If your Pi theme defines:
|
|
32
|
+
|
|
33
|
+
```json
|
|
34
|
+
{
|
|
35
|
+
"toolSuccessBg": "#1e2e1e",
|
|
36
|
+
"toolErrorBg": "#2e1e1e"
|
|
37
|
+
}
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
core tool panels now render those backgrounds across the full line width instead of only behind printed characters.
|
|
41
|
+
|
|
42
|
+
When FFF is available, pi-pretty now stores frecency/history data under:
|
|
43
|
+
|
|
44
|
+
```text
|
|
45
|
+
~/.pi/agent/pi-pretty/fff/
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
Existing data under `~/.pi/agent/fff` is not migrated automatically by this release.
|
package/src/index.ts
CHANGED
|
@@ -71,28 +71,41 @@ const FG_PURPLE = "\x1b[38;2;170;120;200m";
|
|
|
71
71
|
const BG_STDERR = "\x1b[48;2;40;25;25m";
|
|
72
72
|
|
|
73
73
|
const BG_DEFAULT = "\x1b[49m";
|
|
74
|
-
let BG_BASE = BG_DEFAULT; // tool box base bg — updated from theme's toolSuccessBg
|
|
74
|
+
let BG_BASE = BG_DEFAULT; // tool box success/base bg — updated from theme's toolSuccessBg
|
|
75
|
+
let BG_ERROR = BG_DEFAULT; // tool box error bg — updated from theme's toolErrorBg
|
|
76
|
+
|
|
77
|
+
type BgTheme = { getBgAnsi?: (key: string) => string };
|
|
78
|
+
type FgTheme = { fg: (key: string, text: string) => string };
|
|
75
79
|
|
|
76
80
|
/** Parse an ANSI 24-bit color escape into { r, g, b }. Handles both fg (38;2) and bg (48;2). */
|
|
77
81
|
function parseAnsiRgb(ansi: string): { r: number; g: number; b: number } | null {
|
|
78
|
-
const m = ansi.match(
|
|
82
|
+
const m = ansi.match(new RegExp(`${ESC_RE}\\[(?:38|48);2;(\\d+);(\\d+);(\\d+)m`));
|
|
79
83
|
return m ? { r: +m[1], g: +m[2], b: +m[3] } : null;
|
|
80
84
|
}
|
|
81
85
|
|
|
82
|
-
|
|
86
|
+
function getThemeBgAnsi(theme: BgTheme, key: string): string | null {
|
|
87
|
+
try {
|
|
88
|
+
const bgAnsi = theme.getBgAnsi?.(key);
|
|
89
|
+
return bgAnsi && parseAnsiRgb(bgAnsi) ? bgAnsi : null;
|
|
90
|
+
} catch {
|
|
91
|
+
return null;
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
/** Read themed tool backgrounds and update BG_BASE / BG_ERROR + RST.
|
|
83
96
|
* Call once when theme is first available. Idempotent. */
|
|
84
97
|
let _bgBaseResolved = false;
|
|
85
|
-
function resolveBaseBackground(theme:
|
|
98
|
+
function resolveBaseBackground(theme: BgTheme | null | undefined): void {
|
|
86
99
|
if (_bgBaseResolved || !theme?.getBgAnsi) return;
|
|
87
100
|
_bgBaseResolved = true;
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
101
|
+
|
|
102
|
+
BG_BASE = getThemeBgAnsi(theme, "toolSuccessBg") ?? BG_DEFAULT;
|
|
103
|
+
BG_ERROR = getThemeBgAnsi(theme, "toolErrorBg") ?? BG_BASE;
|
|
104
|
+
RST = `\x1b[0m${BG_BASE}`;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
function renderToolError(error: string, theme: FgTheme): string {
|
|
108
|
+
return fillToolBackground(`\n${theme.fg("error", error)}`, BG_ERROR);
|
|
96
109
|
}
|
|
97
110
|
|
|
98
111
|
const ESC_RE = "\u001b";
|
|
@@ -126,6 +139,25 @@ function strip(s: string): string {
|
|
|
126
139
|
return s.replace(ANSI_RE, "");
|
|
127
140
|
}
|
|
128
141
|
|
|
142
|
+
function preserveToolBackground(ansi: string, bg: string): string {
|
|
143
|
+
return ansi.replace(ANSI_CAPTURE_RE, (seq, params: string) => {
|
|
144
|
+
const codes = params.split(";");
|
|
145
|
+
return params === "0" || codes.includes("49") ? `${seq}${bg}` : seq;
|
|
146
|
+
});
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
function fillToolBackground(text: string, bg = BG_BASE): string {
|
|
150
|
+
const width = termW();
|
|
151
|
+
return text
|
|
152
|
+
.split("\n")
|
|
153
|
+
.map((line) => {
|
|
154
|
+
const normalized = preserveToolBackground(line, bg);
|
|
155
|
+
const padding = Math.max(0, width - strip(normalized).length);
|
|
156
|
+
return `${bg}${normalized}${" ".repeat(padding)}${RST}`;
|
|
157
|
+
})
|
|
158
|
+
.join("\n");
|
|
159
|
+
}
|
|
160
|
+
|
|
129
161
|
function termW(): number {
|
|
130
162
|
const raw =
|
|
131
163
|
process.stdout.columns || (process.stderr as any).columns || Number.parseInt(process.env.COLUMNS ?? "", 10) || 200;
|
|
@@ -780,6 +812,10 @@ let _fffPartialIndex = false;
|
|
|
780
812
|
let _fffDbDir: string | null = null;
|
|
781
813
|
const FFF_SCAN_TIMEOUT = 15_000;
|
|
782
814
|
|
|
815
|
+
function getPiPrettyFffDir(agentDir: string): string {
|
|
816
|
+
return join(agentDir, "pi-pretty", "fff");
|
|
817
|
+
}
|
|
818
|
+
|
|
783
819
|
async function fffEnsureFinder(cwd: string): Promise<any> {
|
|
784
820
|
if (_fffFinder && !_fffFinder.isDestroyed) return _fffFinder;
|
|
785
821
|
if (!_fffModule || !_fffDbDir) return null;
|
|
@@ -874,7 +910,7 @@ export default function piPrettyExtension(pi: any, deps?: PiPrettyDeps): void {
|
|
|
874
910
|
try {
|
|
875
911
|
_fffModule = require("@ff-labs/fff-node");
|
|
876
912
|
if (getAgentDir) {
|
|
877
|
-
_fffDbDir =
|
|
913
|
+
_fffDbDir = getPiPrettyFffDir(getAgentDir());
|
|
878
914
|
try {
|
|
879
915
|
mkdirSync(_fffDbDir, { recursive: true });
|
|
880
916
|
} catch {}
|
|
@@ -883,7 +919,7 @@ export default function piPrettyExtension(pi: any, deps?: PiPrettyDeps): void {
|
|
|
883
919
|
/* FFF not installed — SDK tools will be used */
|
|
884
920
|
}
|
|
885
921
|
} else if (_fffModule && getAgentDir) {
|
|
886
|
-
_fffDbDir =
|
|
922
|
+
_fffDbDir = getPiPrettyFffDir(getAgentDir());
|
|
887
923
|
try {
|
|
888
924
|
mkdirSync(_fffDbDir, { recursive: true });
|
|
889
925
|
} catch {}
|
|
@@ -901,7 +937,7 @@ export default function piPrettyExtension(pi: any, deps?: PiPrettyDeps): void {
|
|
|
901
937
|
|
|
902
938
|
if (!_fffDbDir) {
|
|
903
939
|
const agentDir = getAgentDir?.() ?? join(home, ".pi/agent");
|
|
904
|
-
_fffDbDir =
|
|
940
|
+
_fffDbDir = getPiPrettyFffDir(agentDir);
|
|
905
941
|
try {
|
|
906
942
|
mkdirSync(_fffDbDir, { recursive: true });
|
|
907
943
|
} catch {}
|
|
@@ -978,7 +1014,7 @@ export default function piPrettyExtension(pi: any, deps?: PiPrettyDeps): void {
|
|
|
978
1014
|
const text = ctx.lastComponent ?? new TextComponent("", 0, 0);
|
|
979
1015
|
const offset = args?.offset ? ` ${theme.fg("muted", `from line ${args.offset}`)}` : "";
|
|
980
1016
|
const limit = args?.limit ? ` ${theme.fg("muted", `(${args.limit} lines)`)}` : "";
|
|
981
|
-
text.setText(`${theme.fg("toolTitle", theme.bold("read"))} ${theme.fg("accent", sp(fp))}${offset}${limit}`);
|
|
1017
|
+
text.setText(fillToolBackground(`${theme.fg("toolTitle", theme.bold("read"))} ${theme.fg("accent", sp(fp))}${offset}${limit}`));
|
|
982
1018
|
return text;
|
|
983
1019
|
},
|
|
984
1020
|
|
|
@@ -992,7 +1028,7 @@ export default function piPrettyExtension(pi: any, deps?: PiPrettyDeps): void {
|
|
|
992
1028
|
?.filter((c: any) => c.type === "text")
|
|
993
1029
|
.map((c: any) => c.text || "")
|
|
994
1030
|
.join("\n") ?? "Error";
|
|
995
|
-
text.setText(
|
|
1031
|
+
text.setText(renderToolError(e, theme));
|
|
996
1032
|
return text;
|
|
997
1033
|
}
|
|
998
1034
|
|
|
@@ -1034,7 +1070,7 @@ export default function piPrettyExtension(pi: any, deps?: PiPrettyDeps): void {
|
|
|
1034
1070
|
}
|
|
1035
1071
|
|
|
1036
1072
|
out.push(rule(tw));
|
|
1037
|
-
text.setText(out.join("\n"));
|
|
1073
|
+
text.setText(fillToolBackground(out.join("\n")));
|
|
1038
1074
|
return text;
|
|
1039
1075
|
}
|
|
1040
1076
|
|
|
@@ -1043,24 +1079,24 @@ export default function piPrettyExtension(pi: any, deps?: PiPrettyDeps): void {
|
|
|
1043
1079
|
if (ctx.state._rk !== key) {
|
|
1044
1080
|
ctx.state._rk = key;
|
|
1045
1081
|
const info = `${FG_DIM}${d.lineCount} lines${RST}`;
|
|
1046
|
-
ctx.state._rt = ` ${info}
|
|
1082
|
+
ctx.state._rt = fillToolBackground(` ${info}`);
|
|
1047
1083
|
|
|
1048
1084
|
const maxShow = ctx.expanded ? d.lineCount : MAX_PREVIEW_LINES;
|
|
1049
1085
|
renderFileContent(d.content, d.filePath, d.offset, maxShow)
|
|
1050
1086
|
.then((rendered: string) => {
|
|
1051
1087
|
if (ctx.state._rk !== key) return;
|
|
1052
|
-
ctx.state._rt = ` ${info}\n${rendered}
|
|
1088
|
+
ctx.state._rt = fillToolBackground(` ${info}\n${rendered}`);
|
|
1053
1089
|
ctx.invalidate();
|
|
1054
1090
|
})
|
|
1055
1091
|
.catch(() => {});
|
|
1056
1092
|
}
|
|
1057
|
-
text.setText(ctx.state._rt ?? ` ${FG_DIM}${d.lineCount} lines${RST}`);
|
|
1093
|
+
text.setText(ctx.state._rt ?? fillToolBackground(` ${FG_DIM}${d.lineCount} lines${RST}`));
|
|
1058
1094
|
return text;
|
|
1059
1095
|
}
|
|
1060
1096
|
|
|
1061
1097
|
// Fallback
|
|
1062
1098
|
const fallback = result.content?.[0]?.text ?? "read";
|
|
1063
|
-
text.setText(` ${theme.fg("dim", String(fallback).slice(0, 120))}`);
|
|
1099
|
+
text.setText(fillToolBackground(` ${theme.fg("dim", String(fallback).slice(0, 120))}`));
|
|
1064
1100
|
return text;
|
|
1065
1101
|
},
|
|
1066
1102
|
});
|
|
@@ -1111,7 +1147,7 @@ export default function piPrettyExtension(pi: any, deps?: PiPrettyDeps): void {
|
|
|
1111
1147
|
const text = ctx.lastComponent ?? new TextComponent("", 0, 0);
|
|
1112
1148
|
const timeout = args?.timeout ? ` ${theme.fg("muted", `(${args.timeout}s timeout)`)}` : "";
|
|
1113
1149
|
text.setText(
|
|
1114
|
-
`${theme.fg("toolTitle", theme.bold("bash"))} ${theme.fg("accent", cmd.length > 80 ? cmd.slice(0, 77) + "…" : cmd)}${timeout}
|
|
1150
|
+
fillToolBackground(`${theme.fg("toolTitle", theme.bold("bash"))} ${theme.fg("accent", cmd.length > 80 ? cmd.slice(0, 77) + "…" : cmd)}${timeout}`),
|
|
1115
1151
|
);
|
|
1116
1152
|
return text;
|
|
1117
1153
|
},
|
|
@@ -1126,7 +1162,7 @@ export default function piPrettyExtension(pi: any, deps?: PiPrettyDeps): void {
|
|
|
1126
1162
|
?.filter((c: any) => c.type === "text")
|
|
1127
1163
|
.map((c: any) => c.text || "")
|
|
1128
1164
|
.join("\n") ?? "Error";
|
|
1129
|
-
text.setText(
|
|
1165
|
+
text.setText(renderToolError(e, theme));
|
|
1130
1166
|
return text;
|
|
1131
1167
|
}
|
|
1132
1168
|
|
|
@@ -1151,15 +1187,15 @@ export default function piPrettyExtension(pi: any, deps?: PiPrettyDeps): void {
|
|
|
1151
1187
|
if (lineCount > maxShow) {
|
|
1152
1188
|
out.push(`${FG_DIM} … ${lineCount - maxShow} more lines${RST}`);
|
|
1153
1189
|
}
|
|
1154
|
-
text.setText(out.join("\n"));
|
|
1190
|
+
text.setText(fillToolBackground(out.join("\n")));
|
|
1155
1191
|
} else {
|
|
1156
|
-
text.setText(header);
|
|
1192
|
+
text.setText(fillToolBackground(header));
|
|
1157
1193
|
}
|
|
1158
1194
|
return text;
|
|
1159
1195
|
}
|
|
1160
1196
|
|
|
1161
1197
|
const fallback = result.content?.[0]?.text ?? "done";
|
|
1162
|
-
text.setText(` ${theme.fg("dim", String(fallback).slice(0, 120))}`);
|
|
1198
|
+
text.setText(fillToolBackground(` ${theme.fg("dim", String(fallback).slice(0, 120))}`));
|
|
1163
1199
|
return text;
|
|
1164
1200
|
},
|
|
1165
1201
|
});
|
|
@@ -1201,7 +1237,7 @@ export default function piPrettyExtension(pi: any, deps?: PiPrettyDeps): void {
|
|
|
1201
1237
|
resolveBaseBackground(theme);
|
|
1202
1238
|
const fp = args?.path ?? ".";
|
|
1203
1239
|
const text = ctx.lastComponent ?? new TextComponent("", 0, 0);
|
|
1204
|
-
text.setText(`${theme.fg("toolTitle", theme.bold("ls"))} ${theme.fg("accent", sp(fp))}`);
|
|
1240
|
+
text.setText(fillToolBackground(`${theme.fg("toolTitle", theme.bold("ls"))} ${theme.fg("accent", sp(fp))}`));
|
|
1205
1241
|
return text;
|
|
1206
1242
|
},
|
|
1207
1243
|
|
|
@@ -1215,7 +1251,7 @@ export default function piPrettyExtension(pi: any, deps?: PiPrettyDeps): void {
|
|
|
1215
1251
|
?.filter((c: any) => c.type === "text")
|
|
1216
1252
|
.map((c: any) => c.text || "")
|
|
1217
1253
|
.join("\n") ?? "Error";
|
|
1218
|
-
text.setText(
|
|
1254
|
+
text.setText(renderToolError(e, theme));
|
|
1219
1255
|
return text;
|
|
1220
1256
|
}
|
|
1221
1257
|
|
|
@@ -1223,12 +1259,12 @@ export default function piPrettyExtension(pi: any, deps?: PiPrettyDeps): void {
|
|
|
1223
1259
|
if (d?._type === "lsResult" && d.text) {
|
|
1224
1260
|
const tree = renderTree(d.text, d.path);
|
|
1225
1261
|
const info = `${FG_DIM}${d.entryCount} entries${RST}`;
|
|
1226
|
-
text.setText(` ${info}\n${tree}`);
|
|
1262
|
+
text.setText(fillToolBackground(` ${info}\n${tree}`));
|
|
1227
1263
|
return text;
|
|
1228
1264
|
}
|
|
1229
1265
|
|
|
1230
1266
|
const fallback = result.content?.[0]?.text ?? "listed";
|
|
1231
|
-
text.setText(` ${theme.fg("dim", String(fallback).slice(0, 120))}`);
|
|
1267
|
+
text.setText(fillToolBackground(` ${theme.fg("dim", String(fallback).slice(0, 120))}`));
|
|
1232
1268
|
return text;
|
|
1233
1269
|
},
|
|
1234
1270
|
});
|
|
@@ -1307,7 +1343,7 @@ export default function piPrettyExtension(pi: any, deps?: PiPrettyDeps): void {
|
|
|
1307
1343
|
const pattern = args?.pattern ?? "";
|
|
1308
1344
|
const path = args?.path ? ` ${theme.fg("muted", `in ${sp(args.path)}`)}` : "";
|
|
1309
1345
|
const text = ctx.lastComponent ?? new TextComponent("", 0, 0);
|
|
1310
|
-
text.setText(`${theme.fg("toolTitle", theme.bold("find"))} ${theme.fg("accent", pattern)}${path}`);
|
|
1346
|
+
text.setText(fillToolBackground(`${theme.fg("toolTitle", theme.bold("find"))} ${theme.fg("accent", pattern)}${path}`));
|
|
1311
1347
|
return text;
|
|
1312
1348
|
},
|
|
1313
1349
|
|
|
@@ -1321,7 +1357,7 @@ export default function piPrettyExtension(pi: any, deps?: PiPrettyDeps): void {
|
|
|
1321
1357
|
?.filter((c: any) => c.type === "text")
|
|
1322
1358
|
.map((c: any) => c.text || "")
|
|
1323
1359
|
.join("\n") ?? "Error";
|
|
1324
|
-
text.setText(
|
|
1360
|
+
text.setText(renderToolError(e, theme));
|
|
1325
1361
|
return text;
|
|
1326
1362
|
}
|
|
1327
1363
|
|
|
@@ -1329,12 +1365,12 @@ export default function piPrettyExtension(pi: any, deps?: PiPrettyDeps): void {
|
|
|
1329
1365
|
if (d?._type === "findResult" && d.text) {
|
|
1330
1366
|
const rendered = renderFindResults(d.text);
|
|
1331
1367
|
const info = `${FG_DIM}${d.matchCount} files${RST}`;
|
|
1332
|
-
text.setText(` ${info}\n${rendered}`);
|
|
1368
|
+
text.setText(fillToolBackground(` ${info}\n${rendered}`));
|
|
1333
1369
|
return text;
|
|
1334
1370
|
}
|
|
1335
1371
|
|
|
1336
1372
|
const fallback = result.content?.[0]?.text ?? "found";
|
|
1337
|
-
text.setText(` ${theme.fg("dim", String(fallback).slice(0, 120))}`);
|
|
1373
|
+
text.setText(fillToolBackground(` ${theme.fg("dim", String(fallback).slice(0, 120))}`));
|
|
1338
1374
|
return text;
|
|
1339
1375
|
},
|
|
1340
1376
|
});
|
|
@@ -1434,7 +1470,7 @@ export default function piPrettyExtension(pi: any, deps?: PiPrettyDeps): void {
|
|
|
1434
1470
|
const path = args?.path ? ` ${theme.fg("muted", `in ${sp(args.path)}`)}` : "";
|
|
1435
1471
|
const glob = args?.glob ? ` ${theme.fg("muted", `(${args.glob})`)}` : "";
|
|
1436
1472
|
const text = ctx.lastComponent ?? new TextComponent("", 0, 0);
|
|
1437
|
-
text.setText(`${theme.fg("toolTitle", theme.bold("grep"))} ${theme.fg("accent", pattern)}${path}${glob}`);
|
|
1473
|
+
text.setText(fillToolBackground(`${theme.fg("toolTitle", theme.bold("grep"))} ${theme.fg("accent", pattern)}${path}${glob}`));
|
|
1438
1474
|
return text;
|
|
1439
1475
|
},
|
|
1440
1476
|
|
|
@@ -1448,7 +1484,7 @@ export default function piPrettyExtension(pi: any, deps?: PiPrettyDeps): void {
|
|
|
1448
1484
|
?.filter((c: any) => c.type === "text")
|
|
1449
1485
|
.map((c: any) => c.text || "")
|
|
1450
1486
|
.join("\n") ?? "Error";
|
|
1451
|
-
text.setText(
|
|
1487
|
+
text.setText(renderToolError(e, theme));
|
|
1452
1488
|
return text;
|
|
1453
1489
|
}
|
|
1454
1490
|
|
|
@@ -1458,22 +1494,22 @@ export default function piPrettyExtension(pi: any, deps?: PiPrettyDeps): void {
|
|
|
1458
1494
|
if (ctx.state._gk !== key) {
|
|
1459
1495
|
ctx.state._gk = key;
|
|
1460
1496
|
const info = `${FG_DIM}${d.matchCount} matches${RST}`;
|
|
1461
|
-
ctx.state._gt = ` ${info}
|
|
1497
|
+
ctx.state._gt = fillToolBackground(` ${info}`);
|
|
1462
1498
|
|
|
1463
1499
|
renderGrepResults(d.text, d.pattern)
|
|
1464
1500
|
.then((rendered: string) => {
|
|
1465
1501
|
if (ctx.state._gk !== key) return;
|
|
1466
|
-
ctx.state._gt = ` ${info}\n${rendered}
|
|
1502
|
+
ctx.state._gt = fillToolBackground(` ${info}\n${rendered}`);
|
|
1467
1503
|
ctx.invalidate();
|
|
1468
1504
|
})
|
|
1469
1505
|
.catch(() => {});
|
|
1470
1506
|
}
|
|
1471
|
-
text.setText(ctx.state._gt ?? ` ${FG_DIM}${d.matchCount} matches${RST}`);
|
|
1507
|
+
text.setText(ctx.state._gt ?? fillToolBackground(` ${FG_DIM}${d.matchCount} matches${RST}`));
|
|
1472
1508
|
return text;
|
|
1473
1509
|
}
|
|
1474
1510
|
|
|
1475
1511
|
const fallback = result.content?.[0]?.text ?? "searched";
|
|
1476
|
-
text.setText(` ${theme.fg("dim", String(fallback).slice(0, 120))}`);
|
|
1512
|
+
text.setText(fillToolBackground(` ${theme.fg("dim", String(fallback).slice(0, 120))}`));
|
|
1477
1513
|
return text;
|
|
1478
1514
|
},
|
|
1479
1515
|
});
|
|
@@ -175,6 +175,9 @@ describe("piPrettyExtension integration", () => {
|
|
|
175
175
|
|
|
176
176
|
function makeDeps(withFFF: boolean, finderOverrides?: Record<string, any>): PiPrettyDeps {
|
|
177
177
|
const finder = mkFinder(finderOverrides);
|
|
178
|
+
const fffModule = finderOverrides?.FileFinder
|
|
179
|
+
? { FileFinder: finderOverrides.FileFinder }
|
|
180
|
+
: { FileFinder: { create: vi.fn().mockReturnValue({ ok: true, value: finder }) } };
|
|
178
181
|
return {
|
|
179
182
|
sdk: {
|
|
180
183
|
createReadToolDefinition: mockToolFactory(readExec),
|
|
@@ -185,9 +188,7 @@ describe("piPrettyExtension integration", () => {
|
|
|
185
188
|
getAgentDir: () => "/tmp/pi-pretty-test",
|
|
186
189
|
},
|
|
187
190
|
TextComponent: class { private t = ""; setText(v: string) { this.t = v; } getText() { return this.t; } },
|
|
188
|
-
fffModule: withFFF
|
|
189
|
-
? { FileFinder: { create: vi.fn().mockReturnValue({ ok: true, value: finder }) } }
|
|
190
|
-
: undefined,
|
|
191
|
+
fffModule: withFFF ? fffModule : undefined,
|
|
191
192
|
};
|
|
192
193
|
}
|
|
193
194
|
|
|
@@ -445,6 +446,18 @@ describe("piPrettyExtension integration", () => {
|
|
|
445
446
|
// ---- session lifecycle ---------------------------------------------
|
|
446
447
|
|
|
447
448
|
describe("session lifecycle", () => {
|
|
449
|
+
it("stores FFF data under a pi-pretty-specific directory", async () => {
|
|
450
|
+
const create = vi.fn().mockReturnValue({ ok: true, value: mkFinder() });
|
|
451
|
+
load(true, { FileFinder: { create } });
|
|
452
|
+
const start = events.get("session_start")!;
|
|
453
|
+
expect(start, "session_start not registered").toBeDefined();
|
|
454
|
+
await start({}, { cwd: "/tmp/test" });
|
|
455
|
+
expect(create).toHaveBeenCalledWith(expect.objectContaining({
|
|
456
|
+
frecencyDbPath: "/tmp/pi-pretty-test/pi-pretty/fff/frecency.mdb",
|
|
457
|
+
historyDbPath: "/tmp/pi-pretty-test/pi-pretty/fff/history.mdb",
|
|
458
|
+
}));
|
|
459
|
+
});
|
|
460
|
+
|
|
448
461
|
it("shutdown → subsequent find falls back to SDK", async () => {
|
|
449
462
|
await loadWithFFF();
|
|
450
463
|
await events.get("session_shutdown")!();
|