@heyhuynhgiabuu/pi-pretty 0.5.3 → 0.6.0
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/bun.lock +598 -0
- package/package.json +6 -8
- package/src/config.ts +250 -0
- package/src/fff.ts +147 -0
- package/src/helpers.ts +124 -0
- package/src/image.ts +129 -0
- package/src/index.ts +157 -2161
- package/src/render.ts +402 -0
- package/src/tools/bash.ts +115 -0
- package/src/tools/find.ts +87 -0
- package/src/tools/grep.ts +99 -0
- package/src/tools/ls.ts +66 -0
- package/src/tools/metrics.ts +40 -0
- package/src/tools/multi-grep.ts +171 -0
- package/src/tools/read.ts +112 -0
- package/src/types.ts +227 -0
- package/test/bash-rendering.test.ts +3 -3
package/src/types.ts
ADDED
|
@@ -0,0 +1,227 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* pi-pretty shared types.
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import type { TextContent, ImageContent } from "@earendil-works/pi-ai";
|
|
6
|
+
import type { AgentToolResult } from "@earendil-works/pi-coding-agent";
|
|
7
|
+
|
|
8
|
+
// ---------------------------------------------------------------------------
|
|
9
|
+
// Re-export FFF types needed by tools
|
|
10
|
+
// ---------------------------------------------------------------------------
|
|
11
|
+
|
|
12
|
+
export type { FileFinder, FileItem, GrepResult, SearchResult, GrepMatch, GrepCursor } from "@ff-labs/fff-node";
|
|
13
|
+
|
|
14
|
+
// ---------------------------------------------------------------------------
|
|
15
|
+
// Content / Result types
|
|
16
|
+
// ---------------------------------------------------------------------------
|
|
17
|
+
|
|
18
|
+
export type ToolContent = TextContent | ImageContent;
|
|
19
|
+
export type { TextContent, ImageContent };
|
|
20
|
+
// ---------------------------------------------------------------------------
|
|
21
|
+
// Theme / rendering context types
|
|
22
|
+
// ---------------------------------------------------------------------------
|
|
23
|
+
|
|
24
|
+
export interface ThemeLike {
|
|
25
|
+
fg: (key: string, text: string) => string;
|
|
26
|
+
bold: (text: string) => string;
|
|
27
|
+
getBgAnsi?: (key: string) => string;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export interface RenderCtxLike {
|
|
31
|
+
lastComponent?: ComponentLike;
|
|
32
|
+
isError?: boolean;
|
|
33
|
+
state: Record<string, string | undefined>;
|
|
34
|
+
expanded?: boolean;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export interface TextLike {
|
|
38
|
+
setText(v: string): void;
|
|
39
|
+
getText?(): string;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/** Minimal Component interface matching pi-tui's Component. */
|
|
43
|
+
export interface ComponentLike {
|
|
44
|
+
setText(v: string): void;
|
|
45
|
+
render(width: number): string[];
|
|
46
|
+
invalidate?(): void;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
// ---------------------------------------------------------------------------
|
|
50
|
+
// Render detail types
|
|
51
|
+
// ---------------------------------------------------------------------------
|
|
52
|
+
|
|
53
|
+
export type ReadDetails =
|
|
54
|
+
| { _type: "readImage"; filePath: string; data: string; mimeType: string }
|
|
55
|
+
| { _type: "readFile"; filePath: string; content: string; offset: number; lineCount: number };
|
|
56
|
+
|
|
57
|
+
export interface BashDetails extends Record<string, unknown> {
|
|
58
|
+
_type: "bashResult";
|
|
59
|
+
text: string;
|
|
60
|
+
exitCode: number | null;
|
|
61
|
+
command: string;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
export interface LsDetails extends Record<string, unknown> {
|
|
65
|
+
_type: "lsResult";
|
|
66
|
+
text: string;
|
|
67
|
+
path: string;
|
|
68
|
+
entryCount: number;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
export interface FindDetails extends Record<string, unknown> {
|
|
72
|
+
_type: "findResult";
|
|
73
|
+
text: string;
|
|
74
|
+
pattern: string;
|
|
75
|
+
matchCount: number;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
export interface GrepDetails extends Record<string, unknown> {
|
|
79
|
+
_type: "grepResult";
|
|
80
|
+
text: string;
|
|
81
|
+
pattern: string;
|
|
82
|
+
matchCount: number;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
export type AnyDetails = ReadDetails | BashDetails | LsDetails | FindDetails | GrepDetails;
|
|
86
|
+
|
|
87
|
+
// ---------------------------------------------------------------------------
|
|
88
|
+
// Tool input types
|
|
89
|
+
// ---------------------------------------------------------------------------
|
|
90
|
+
|
|
91
|
+
export interface ReadInput {
|
|
92
|
+
path: string;
|
|
93
|
+
offset?: number;
|
|
94
|
+
limit?: number;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
export interface BashInput {
|
|
98
|
+
command: string;
|
|
99
|
+
timeout?: number;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
export interface LsInput {
|
|
103
|
+
path?: string;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
export interface FindInput {
|
|
107
|
+
pattern: string;
|
|
108
|
+
path?: string;
|
|
109
|
+
limit?: number;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
export interface GrepInput {
|
|
113
|
+
pattern: string;
|
|
114
|
+
path?: string;
|
|
115
|
+
glob?: string;
|
|
116
|
+
context?: number;
|
|
117
|
+
limit?: number;
|
|
118
|
+
literal?: boolean;
|
|
119
|
+
ignoreCase?: boolean;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
export interface MultiGrepInput {
|
|
123
|
+
patterns: string[];
|
|
124
|
+
path?: string;
|
|
125
|
+
constraints?: string;
|
|
126
|
+
context?: number;
|
|
127
|
+
limit?: number;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
// ---------------------------------------------------------------------------
|
|
131
|
+
// SDK tool definition shape (DI-friendly — accepts both mock and real SDK)
|
|
132
|
+
// ---------------------------------------------------------------------------
|
|
133
|
+
|
|
134
|
+
/**
|
|
135
|
+
* Minimal structural type for an SDK-produced tool definition.
|
|
136
|
+
* Accepts both the real SDK's ToolDefinition<> return type and test mocks.
|
|
137
|
+
*/
|
|
138
|
+
export interface SdkToolDef {
|
|
139
|
+
name?: string;
|
|
140
|
+
description?: string;
|
|
141
|
+
label?: string;
|
|
142
|
+
parameters?: unknown;
|
|
143
|
+
execute: (...args: any[]) => Promise<AgentToolResult<any>>;
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
export interface SdkTools {
|
|
147
|
+
createReadTool?: (cwd: string) => SdkToolDef;
|
|
148
|
+
createBashTool?: (cwd: string) => SdkToolDef;
|
|
149
|
+
createLsTool?: (cwd: string) => SdkToolDef;
|
|
150
|
+
createFindTool?: (cwd: string) => SdkToolDef;
|
|
151
|
+
createGrepTool?: (cwd: string) => SdkToolDef;
|
|
152
|
+
getAgentDir?: () => string;
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
// ---------------------------------------------------------------------------
|
|
156
|
+
// Multi-grep fallback types
|
|
157
|
+
// ---------------------------------------------------------------------------
|
|
158
|
+
|
|
159
|
+
export interface MultiGrepFallbackParams {
|
|
160
|
+
cwd: string;
|
|
161
|
+
patterns: string[];
|
|
162
|
+
path?: string;
|
|
163
|
+
constraints?: string;
|
|
164
|
+
context?: number;
|
|
165
|
+
limit: number;
|
|
166
|
+
ignoreCase: boolean;
|
|
167
|
+
signal?: AbortSignal;
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
export interface MultiGrepFallbackResult {
|
|
171
|
+
text: string;
|
|
172
|
+
matchCount: number;
|
|
173
|
+
limitReached: boolean;
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
export type MultiGrepFallback = (params: MultiGrepFallbackParams) => Promise<MultiGrepFallbackResult>;
|
|
177
|
+
|
|
178
|
+
// ---------------------------------------------------------------------------
|
|
179
|
+
// FFF service interfaces
|
|
180
|
+
// ---------------------------------------------------------------------------
|
|
181
|
+
|
|
182
|
+
/** Minimal FFF service shape for tools that only need fileSearch. */
|
|
183
|
+
export interface FffServiceLike {
|
|
184
|
+
readonly isAvailable: boolean;
|
|
185
|
+
readonly partialIndex: boolean;
|
|
186
|
+
getFinder(): import("@ff-labs/fff-node").FileFinder | null;
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
/** Full FFF service for grep tools that also need cursor store. */
|
|
190
|
+
export interface FffServiceWithCursor extends FffServiceLike {
|
|
191
|
+
getCursorStore(): CursorStore;
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
/** FFF lifecycle interface (used by session lifecycle code). */
|
|
195
|
+
export interface FffService extends FffServiceWithCursor {
|
|
196
|
+
ensureFinder(cwd: string): Promise<void>;
|
|
197
|
+
destroy(): void;
|
|
198
|
+
isModuleLoaded(): boolean;
|
|
199
|
+
tryLoadModule(): Promise<boolean>;
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
export interface CursorStore {
|
|
203
|
+
store(cursor: unknown): string;
|
|
204
|
+
get(id: string): unknown | undefined;
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
// ---------------------------------------------------------------------------
|
|
208
|
+
// Constraint parsing
|
|
209
|
+
// ---------------------------------------------------------------------------
|
|
210
|
+
|
|
211
|
+
export interface ConstraintParseResult {
|
|
212
|
+
ok: boolean;
|
|
213
|
+
globs: string[];
|
|
214
|
+
tokens: string[];
|
|
215
|
+
error?: string;
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
// ---------------------------------------------------------------------------
|
|
219
|
+
// DI
|
|
220
|
+
// ---------------------------------------------------------------------------
|
|
221
|
+
|
|
222
|
+
export interface PiPrettyDeps {
|
|
223
|
+
sdk?: SdkTools;
|
|
224
|
+
TextComponent?: new (text?: string, x?: number, y?: number) => ComponentLike;
|
|
225
|
+
fffModule?: typeof import("@ff-labs/fff-node");
|
|
226
|
+
multiGrepRipgrepFallback?: MultiGrepFallback;
|
|
227
|
+
}
|
|
@@ -184,7 +184,7 @@ describe("bash renderCall expansion", () => {
|
|
|
184
184
|
});
|
|
185
185
|
|
|
186
186
|
const lines = stripAnsi(rendered.getText()).split("\n");
|
|
187
|
-
expect(lines[
|
|
187
|
+
expect(lines[1]).toMatch(/^ bash false/);
|
|
188
188
|
});
|
|
189
189
|
});
|
|
190
190
|
|
|
@@ -215,7 +215,7 @@ describe("bash renderCall expansion", () => {
|
|
|
215
215
|
});
|
|
216
216
|
});
|
|
217
217
|
|
|
218
|
-
it("
|
|
218
|
+
it("applies tool background correctly to bash results without unnecessary resets", () => {
|
|
219
219
|
withStdoutColumns(64, () => {
|
|
220
220
|
const bashTool = loadBashTool();
|
|
221
221
|
const rendered = bashTool.renderResult(
|
|
@@ -234,7 +234,7 @@ describe("bash renderCall expansion", () => {
|
|
|
234
234
|
},
|
|
235
235
|
);
|
|
236
236
|
|
|
237
|
-
expect(rendered.getText()).
|
|
237
|
+
expect(rendered.getText()).toMatch(/\x1b\[48;/); // tool background is applied
|
|
238
238
|
expect(rendered.getText()).not.toContain("\x1b[0m");
|
|
239
239
|
expect(rendered.getText()).not.toContain("\x1b[49m");
|
|
240
240
|
for (const line of rendered.getText().split("\n")) {
|