@heyhuynhgiabuu/pi-pretty 0.6.7 → 0.6.8
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 +14 -0
- package/dist/tools/bash.d.ts.map +1 -1
- package/dist/tools/bash.js +37 -15
- package/dist/tools/bash.js.map +1 -1
- package/dist/tools/find.d.ts.map +1 -1
- package/dist/tools/find.js +38 -16
- package/dist/tools/find.js.map +1 -1
- package/dist/tools/grep.d.ts.map +1 -1
- package/dist/tools/grep.js +2 -5
- package/dist/tools/grep.js.map +1 -1
- package/dist/tools/ls.d.ts.map +1 -1
- package/dist/tools/ls.js +20 -9
- package/dist/tools/ls.js.map +1 -1
- package/dist/tools/multi-grep.d.ts.map +1 -1
- package/dist/tools/multi-grep.js +118 -22
- package/dist/tools/multi-grep.js.map +1 -1
- package/dist/tools/read.d.ts.map +1 -1
- package/dist/tools/read.js +33 -13
- package/dist/tools/read.js.map +1 -1
- package/dist/tui-text.d.ts +25 -0
- package/dist/tui-text.d.ts.map +1 -0
- package/dist/tui-text.js +55 -0
- package/dist/tui-text.js.map +1 -0
- package/package.json +1 -1
- package/src/tools/bash.ts +77 -22
- package/src/tools/find.ts +91 -40
- package/src/tools/grep.ts +2 -8
- package/src/tools/ls.ts +42 -14
- package/src/tools/multi-grep.ts +162 -32
- package/src/tools/read.ts +79 -25
- package/src/tui-text.ts +56 -0
package/src/tools/bash.ts
CHANGED
|
@@ -1,10 +1,25 @@
|
|
|
1
1
|
/* pi-pretty: bash tool -- command execution with styled output. */
|
|
2
2
|
|
|
3
|
-
import {
|
|
3
|
+
import {
|
|
4
|
+
type ToolDefinition,
|
|
5
|
+
type ExtensionAPI,
|
|
6
|
+
type ExtensionContext,
|
|
7
|
+
type AgentToolResult,
|
|
8
|
+
} from "@earendil-works/pi-coding-agent";
|
|
4
9
|
import type { SdkToolDef, BashDetails, TextContent, ComponentLike, ThemeLike, RenderCtxLike } from "../types.js";
|
|
5
|
-
import {
|
|
10
|
+
import {
|
|
11
|
+
resolveBaseBackground,
|
|
12
|
+
termWidth,
|
|
13
|
+
MAX_PREVIEW_LINES,
|
|
14
|
+
BG_BASE,
|
|
15
|
+
BG_ERROR,
|
|
16
|
+
FG_DIM,
|
|
17
|
+
FG_RULE,
|
|
18
|
+
RST,
|
|
19
|
+
} from "../config.js";
|
|
6
20
|
import { wrapExecuteWithMetrics } from "./metrics.js";
|
|
7
21
|
import { renderBashOutput, renderToolError, renderToolMetrics, fillToolBackground } from "../render.js";
|
|
22
|
+
import { resolveTextCtor } from "../tui-text.js";
|
|
8
23
|
import { stripBashExitStatusLine, inferBashExitCode, compactErrorLines } from "../helpers.js";
|
|
9
24
|
|
|
10
25
|
type Result = AgentToolResult<Record<string, unknown>>;
|
|
@@ -16,10 +31,7 @@ export function registerBashTool(
|
|
|
16
31
|
sdkTool: SdkToolDef,
|
|
17
32
|
TextComp?: new (t?: string, x?: number, y?: number) => { setText(v: string): void },
|
|
18
33
|
): void {
|
|
19
|
-
const TC = TextComp
|
|
20
|
-
const { Text } = require("@earendil-works/pi-tui") as { Text: new (t?: string, x?: number, y?: number) => { setText(v: string): void } };
|
|
21
|
-
return Text;
|
|
22
|
-
})();
|
|
34
|
+
const TC = resolveTextCtor(TextComp);
|
|
23
35
|
|
|
24
36
|
pi.registerTool({
|
|
25
37
|
name: "bash",
|
|
@@ -30,10 +42,19 @@ export function registerBashTool(
|
|
|
30
42
|
|
|
31
43
|
execute: wrapExecuteWithMetrics(async (tid, params, sig, _upd, ctx: ExtensionContext) => {
|
|
32
44
|
try {
|
|
33
|
-
return await sdkTool.execute(tid, params, sig, undefined, ctx) as Result;
|
|
45
|
+
return (await sdkTool.execute(tid, params, sig, undefined, ctx)) as Result;
|
|
34
46
|
} catch (error: unknown) {
|
|
35
47
|
const msg = error instanceof Error ? error.message : String(error);
|
|
36
|
-
return {
|
|
48
|
+
return {
|
|
49
|
+
content: [{ type: "text" as const, text: msg }],
|
|
50
|
+
isError: true,
|
|
51
|
+
details: {
|
|
52
|
+
_type: "bashResult",
|
|
53
|
+
text: msg,
|
|
54
|
+
exitCode: 1,
|
|
55
|
+
command: String((params as any).command ?? ""),
|
|
56
|
+
} as BashDetails,
|
|
57
|
+
};
|
|
37
58
|
}
|
|
38
59
|
}),
|
|
39
60
|
|
|
@@ -43,23 +64,40 @@ export function registerBashTool(
|
|
|
43
64
|
const t = typeof args.timeout === "number" ? ` ${theme.fg("muted", `(timeout ${args.timeout}s)`)}` : "";
|
|
44
65
|
const tw = termWidth() || 80;
|
|
45
66
|
const rawCmd = String(args.command ?? "");
|
|
46
|
-
const cmd =
|
|
67
|
+
const cmd =
|
|
68
|
+
rawCmd.length === 0
|
|
69
|
+
? theme.fg("toolOutput", "...")
|
|
70
|
+
: rawCmd.length > tw - 20
|
|
71
|
+
? rawCmd.slice(0, Math.max(1, tw - 20)) + "…"
|
|
72
|
+
: rawCmd;
|
|
47
73
|
const toolWidth = ctx.expanded ? undefined : tw;
|
|
48
|
-
text.setText(
|
|
74
|
+
text.setText(
|
|
75
|
+
fillToolBackground(
|
|
76
|
+
`\n ${theme.fg("toolTitle", theme.bold(`$ ${cmd}`))}${t}`,
|
|
77
|
+
ctx.isError ? BG_ERROR : undefined,
|
|
78
|
+
toolWidth,
|
|
79
|
+
),
|
|
80
|
+
);
|
|
49
81
|
return text;
|
|
50
82
|
},
|
|
51
83
|
|
|
52
84
|
renderResult(result: Result, _opt: unknown, theme: ThemeLike, ctx: RenderCtxLike) {
|
|
53
85
|
resolveBaseBackground(theme);
|
|
54
|
-
|
|
86
|
+
|
|
55
87
|
const text = ctx.lastComponent ?? new TC("", 0, 0);
|
|
56
88
|
|
|
57
89
|
const details = result.details;
|
|
58
90
|
const tc = getText(result);
|
|
59
91
|
const d: BashDetails | undefined =
|
|
60
|
-
(details as BashDetails)?._type === "bashResult"
|
|
92
|
+
(details as BashDetails)?._type === "bashResult"
|
|
93
|
+
? (details as BashDetails)
|
|
61
94
|
: tc || ctx.isError
|
|
62
|
-
? {
|
|
95
|
+
? {
|
|
96
|
+
_type: "bashResult",
|
|
97
|
+
text: tc || "Error",
|
|
98
|
+
exitCode: inferBashExitCode(tc, ctx.isError ? 1 : 0),
|
|
99
|
+
command: "",
|
|
100
|
+
}
|
|
63
101
|
: undefined;
|
|
64
102
|
|
|
65
103
|
if (d?._type === "bashResult") {
|
|
@@ -69,7 +107,10 @@ export function registerBashTool(
|
|
|
69
107
|
const output = isErr ? compactErrorLines(cleaned).join("\n") : cleaned;
|
|
70
108
|
const { summary } = renderBashOutput(output, d.exitCode);
|
|
71
109
|
const lineCount = output.split("\n").length;
|
|
72
|
-
const info =
|
|
110
|
+
const info =
|
|
111
|
+
lineCount > 1
|
|
112
|
+
? ` ${FG_DIM}(${lineCount} lines)${RST} ${renderToolMetrics(result)}`
|
|
113
|
+
: ` ${renderToolMetrics(result)}`;
|
|
73
114
|
const header = ` ${summary}${info}`;
|
|
74
115
|
const rw = termWidth();
|
|
75
116
|
|
|
@@ -83,30 +124,44 @@ export function registerBashTool(
|
|
|
83
124
|
};
|
|
84
125
|
|
|
85
126
|
text.setText(renderFn(rw));
|
|
86
|
-
const baseRender =
|
|
87
|
-
? (text as ComponentLike).render.bind(text)
|
|
88
|
-
: null;
|
|
127
|
+
const baseRender =
|
|
128
|
+
typeof (text as ComponentLike).render === "function" ? (text as ComponentLike).render.bind(text) : null;
|
|
89
129
|
if (baseRender) {
|
|
90
130
|
let key: string | undefined;
|
|
91
131
|
(text as unknown as Record<string, unknown>).render = (w: number) => {
|
|
92
132
|
const width = Math.max(1, Math.floor(w || termWidth()));
|
|
93
133
|
const k = `bash:${ctx.expanded ? "1" : "0"}:${width}:${d.exitCode ?? "killed"}:${output.length}:${renderToolMetrics(result)}`;
|
|
94
|
-
if (key !== k) {
|
|
134
|
+
if (key !== k) {
|
|
135
|
+
text.setText(renderFn(width));
|
|
136
|
+
key = k;
|
|
137
|
+
}
|
|
95
138
|
return baseRender(width);
|
|
96
139
|
};
|
|
97
140
|
}
|
|
98
141
|
return text;
|
|
99
142
|
}
|
|
100
143
|
|
|
101
|
-
if (ctx.isError) {
|
|
144
|
+
if (ctx.isError) {
|
|
145
|
+
text.setText(renderToolError(tc || "Error", theme));
|
|
146
|
+
return text;
|
|
147
|
+
}
|
|
102
148
|
const fc = result.content?.[0];
|
|
103
|
-
text.setText(
|
|
149
|
+
text.setText(
|
|
150
|
+
fillToolBackground(` ${theme.fg("dim", fc && "text" in fc ? String(fc.text).slice(0, 120) : "done")}`),
|
|
151
|
+
);
|
|
104
152
|
return text;
|
|
105
153
|
},
|
|
106
154
|
} as unknown as ToolDefinition<any, any, any>);
|
|
107
155
|
}
|
|
108
156
|
|
|
109
|
-
function rule(w: number): string {
|
|
157
|
+
function rule(w: number): string {
|
|
158
|
+
return `${FG_RULE}${"\u2500".repeat(w)}${RST}`;
|
|
159
|
+
}
|
|
110
160
|
function getText(result: Result): string {
|
|
111
|
-
return (
|
|
161
|
+
return (
|
|
162
|
+
((result.content ?? []) as TextContent[])
|
|
163
|
+
.filter((c) => c.type === "text")
|
|
164
|
+
.map((c) => c.text)
|
|
165
|
+
.join("\n") ?? ""
|
|
166
|
+
);
|
|
112
167
|
}
|
package/src/tools/find.ts
CHANGED
|
@@ -1,12 +1,27 @@
|
|
|
1
1
|
/* pi-pretty: find tool -- FFF-backed file search with SDK fallback. */
|
|
2
2
|
|
|
3
|
-
import {
|
|
3
|
+
import {
|
|
4
|
+
type ToolDefinition,
|
|
5
|
+
type ExtensionAPI,
|
|
6
|
+
type ExtensionContext,
|
|
7
|
+
type AgentToolResult,
|
|
8
|
+
} from "@earendil-works/pi-coding-agent";
|
|
4
9
|
import { isAbsolute, relative as toRelative } from "node:path";
|
|
5
|
-
import type {
|
|
10
|
+
import type {
|
|
11
|
+
SdkToolDef,
|
|
12
|
+
FindDetails,
|
|
13
|
+
FffServiceLike,
|
|
14
|
+
FileItem,
|
|
15
|
+
TextContent,
|
|
16
|
+
ThemeLike,
|
|
17
|
+
RenderCtxLike,
|
|
18
|
+
ComponentLike,
|
|
19
|
+
} from "../types.js";
|
|
6
20
|
import { resolveBaseBackground, BG_ERROR, FG_DIM, RST } from "../config.js";
|
|
7
21
|
import { shortPath } from "../helpers.js";
|
|
8
22
|
import { wrapExecuteWithMetrics } from "./metrics.js";
|
|
9
23
|
import { renderFindResults, renderToolError, renderToolMetrics, fillToolBackground } from "../render.js";
|
|
24
|
+
import { resolveTextCtor } from "../tui-text.js";
|
|
10
25
|
import { NOTICE_PARTIAL_FILE_INDEX } from "../notices.js";
|
|
11
26
|
|
|
12
27
|
type Result = AgentToolResult<Record<string, unknown>>;
|
|
@@ -18,10 +33,7 @@ export function registerFindTool(
|
|
|
18
33
|
sdkTool: SdkToolDef,
|
|
19
34
|
TextComp?: new (t?: string, x?: number, y?: number) => { setText(v: string): void },
|
|
20
35
|
): void {
|
|
21
|
-
|
|
22
|
-
const { Text } = require("@earendil-works/pi-tui") as { Text: new (t?: string, x?: number, y?: number) => { setText(v: string): void; render(w: number): string[]; invalidate(): void } };
|
|
23
|
-
TextComp = Text;
|
|
24
|
-
}
|
|
36
|
+
const TC = resolveTextCtor(TextComp);
|
|
25
37
|
const home = process.env.HOME ?? "";
|
|
26
38
|
|
|
27
39
|
pi.registerTool({
|
|
@@ -49,33 +61,49 @@ export function registerFindTool(
|
|
|
49
61
|
}
|
|
50
62
|
cleanPath = cleanPath.replace(/\/$/, "");
|
|
51
63
|
const cleanPattern = pattern.startsWith("/") ? pattern.slice(1) : pattern;
|
|
52
|
-
const globPattern = cleanPath
|
|
53
|
-
? `${cleanPath}/**/${cleanPattern}`
|
|
54
|
-
: `**/${cleanPattern}`;
|
|
64
|
+
const globPattern = cleanPath ? `${cleanPath}/**/${cleanPattern}` : `**/${cleanPattern}`;
|
|
55
65
|
const searchResult = fff.glob(globPattern, { pageSize: effectiveLimit });
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
+
if (searchResult.ok) {
|
|
67
|
+
const items: FileItem[] = searchResult.value.items.slice(0, effectiveLimit);
|
|
68
|
+
const notices: string[] = [];
|
|
69
|
+
if (fffService?.partialIndex) notices.push(NOTICE_PARTIAL_FILE_INDEX);
|
|
70
|
+
if (items.length >= effectiveLimit) notices.push(`${effectiveLimit} limit reached`);
|
|
71
|
+
if (searchResult.value.totalMatched > items.length)
|
|
72
|
+
notices.push(`${searchResult.value.totalMatched} total matches`);
|
|
73
|
+
const paths = items.map((i) => i.relativePath).join("\n");
|
|
74
|
+
return {
|
|
75
|
+
content: [{ type: "text" as const, text: paths }],
|
|
76
|
+
details: {
|
|
77
|
+
_type: "findResult",
|
|
78
|
+
text: paths,
|
|
79
|
+
pattern,
|
|
80
|
+
matchCount: items.length,
|
|
81
|
+
notices,
|
|
82
|
+
} as FindDetails,
|
|
83
|
+
};
|
|
84
|
+
}
|
|
85
|
+
} catch {
|
|
86
|
+
/* fall through to SDK */
|
|
87
|
+
}
|
|
66
88
|
}
|
|
67
89
|
|
|
68
|
-
const result = await sdkTool.execute(tid, params, sig, undefined, ctx) as Result;
|
|
90
|
+
const result = (await sdkTool.execute(tid, params, sig, undefined, ctx)) as Result;
|
|
69
91
|
const tc = getText(result);
|
|
70
|
-
result.details = {
|
|
92
|
+
result.details = {
|
|
93
|
+
_type: "findResult",
|
|
94
|
+
text: tc,
|
|
95
|
+
pattern,
|
|
96
|
+
matchCount: tc ? tc.trim().split("\n").filter(Boolean).length : 0,
|
|
97
|
+
} as FindDetails;
|
|
71
98
|
return result;
|
|
72
99
|
}),
|
|
73
100
|
|
|
74
|
-
|
|
101
|
+
renderCall(args: any, theme: ThemeLike, ctx: RenderCtxLike) {
|
|
75
102
|
resolveBaseBackground(theme);
|
|
76
|
-
const text = ctx.lastComponent ?? new
|
|
103
|
+
const text = ctx.lastComponent ?? new TC("", 0, 0);
|
|
77
104
|
const pattern = args.pattern === null || args.pattern === undefined ? "" : String(args.pattern);
|
|
78
|
-
const path =
|
|
105
|
+
const path =
|
|
106
|
+
args.path === null || args.path === undefined ? "<missing>" : shortPath(cwd, home, String(args.path));
|
|
79
107
|
const limit = args.limit;
|
|
80
108
|
const glob = args.glob;
|
|
81
109
|
const findLabel = theme.fg("toolTitle", theme.bold("find"));
|
|
@@ -90,28 +118,51 @@ export function registerFindTool(
|
|
|
90
118
|
|
|
91
119
|
renderResult(result: Result, _opt: unknown, theme: ThemeLike, ctx: RenderCtxLike) {
|
|
92
120
|
resolveBaseBackground(theme);
|
|
93
|
-
const text = ctx.lastComponent ?? new
|
|
94
|
-
if (ctx.isError) {
|
|
121
|
+
const text = ctx.lastComponent ?? new TC("", 0, 0);
|
|
122
|
+
if (ctx.isError) {
|
|
123
|
+
text.setText(renderToolError(getText(result) || "Error", theme));
|
|
124
|
+
return text;
|
|
125
|
+
}
|
|
95
126
|
const d = result.details as FindDetails | undefined;
|
|
96
127
|
if (d?._type === "findResult") {
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
128
|
+
if (!d.text.trim()) {
|
|
129
|
+
const notices = (d as any).notices as string[] | undefined;
|
|
130
|
+
const noticeStr = notices?.length ? `\n ${theme.fg("warning", `[${notices.join(". ")}]`)}` : "";
|
|
131
|
+
text.setText(fillToolBackground(` \n ${theme.fg("dim", "0 files")}${noticeStr}\n `));
|
|
132
|
+
return text;
|
|
133
|
+
}
|
|
134
|
+
const rendered = renderFindResults(d.text, theme)
|
|
135
|
+
.split("\n")
|
|
136
|
+
.map((l) => ` ${l}`)
|
|
137
|
+
.join("\n");
|
|
138
|
+
const notices = (d as any).notices as string[] | undefined;
|
|
139
|
+
const noticeStr = notices?.length ? `\n ${theme.fg("warning", `[${notices.join(". ")}]`)}` : "";
|
|
140
|
+
text.setText(
|
|
141
|
+
fillToolBackground(
|
|
142
|
+
` \n ${theme.fg("dim", `${d.matchCount} files`)}${renderToolMetrics(result)}\n${rendered}${noticeStr}\n `,
|
|
143
|
+
),
|
|
144
|
+
);
|
|
145
|
+
return text;
|
|
108
146
|
}
|
|
109
147
|
const fc = result.content?.[0];
|
|
110
|
-
text.setText(
|
|
148
|
+
text.setText(
|
|
149
|
+
fillToolBackground(
|
|
150
|
+
` \n ${theme.fg("dim", fc && "text" in fc ? String(fc.text).slice(0, 120) : "0 files")}\n `,
|
|
151
|
+
),
|
|
152
|
+
);
|
|
111
153
|
return text;
|
|
112
154
|
},
|
|
113
155
|
} as unknown as ToolDefinition<any, any, any>);
|
|
114
156
|
}
|
|
115
157
|
|
|
116
|
-
function appendNotices(text: string, notices: string[]): string {
|
|
117
|
-
|
|
158
|
+
function appendNotices(text: string, notices: string[]): string {
|
|
159
|
+
return notices.length ? `${text}\n\n[${notices.join(". ")}]` : text;
|
|
160
|
+
}
|
|
161
|
+
function getText(result: Result): string {
|
|
162
|
+
return (
|
|
163
|
+
((result.content ?? []) as TextContent[])
|
|
164
|
+
.filter((c) => c.type === "text")
|
|
165
|
+
.map((c) => c.text ?? "")
|
|
166
|
+
.join("\n") ?? ""
|
|
167
|
+
);
|
|
168
|
+
}
|
package/src/tools/grep.ts
CHANGED
|
@@ -11,6 +11,7 @@ import { MAX_PREVIEW_LINES, BG_ERROR, resolveBaseBackground } from "../config.js
|
|
|
11
11
|
import { shortPath, normalizeLineEndings } from "../helpers.js";
|
|
12
12
|
import { wrapExecuteWithMetrics } from "./metrics.js";
|
|
13
13
|
import { renderToolError, fillToolBackground } from "../render.js";
|
|
14
|
+
import { resolveTextCtor } from "../tui-text.js";
|
|
14
15
|
import { fffFormatGrepText } from "../fff-helpers.js";
|
|
15
16
|
import { NOTICE_PARTIAL_FILE_INDEX } from "../notices.js";
|
|
16
17
|
|
|
@@ -25,14 +26,7 @@ export function registerGrepTool(
|
|
|
25
26
|
sdkTool: SdkToolDef,
|
|
26
27
|
TextComp?: new (t?: string, x?: number, y?: number) => { setText(v: string): void },
|
|
27
28
|
): void {
|
|
28
|
-
const T =
|
|
29
|
-
TextComp ??
|
|
30
|
-
(() => {
|
|
31
|
-
const m = require("@earendil-works/pi-tui") as {
|
|
32
|
-
Text: new (t?: string, x?: number, y?: number) => { setText(v: string): void };
|
|
33
|
-
};
|
|
34
|
-
return m.Text;
|
|
35
|
-
})();
|
|
29
|
+
const T = resolveTextCtor(TextComp);
|
|
36
30
|
const home = process.env.HOME ?? "";
|
|
37
31
|
|
|
38
32
|
pi.registerTool({
|
package/src/tools/ls.ts
CHANGED
|
@@ -1,11 +1,17 @@
|
|
|
1
1
|
/* pi-pretty: ls tool -- directory listing with styled output. */
|
|
2
2
|
|
|
3
|
-
import {
|
|
3
|
+
import {
|
|
4
|
+
type ToolDefinition,
|
|
5
|
+
type ExtensionAPI,
|
|
6
|
+
type ExtensionContext,
|
|
7
|
+
type AgentToolResult,
|
|
8
|
+
} from "@earendil-works/pi-coding-agent";
|
|
4
9
|
import type { SdkToolDef, LsDetails, TextContent, ComponentLike, ThemeLike, RenderCtxLike } from "../types.js";
|
|
5
10
|
import { resolveBaseBackground, termWidth, MAX_PREVIEW_LINES, BG_BASE, BG_ERROR, FG_DIM, RST } from "../config.js";
|
|
6
11
|
import { shortPath } from "../helpers.js";
|
|
7
12
|
import { wrapExecuteWithMetrics } from "./metrics.js";
|
|
8
13
|
import { renderTree, renderToolError, renderToolMetrics, fillToolBackground } from "../render.js";
|
|
14
|
+
import { resolveTextCtor } from "../tui-text.js";
|
|
9
15
|
|
|
10
16
|
type Result = AgentToolResult<Record<string, unknown>>;
|
|
11
17
|
|
|
@@ -17,10 +23,7 @@ export function registerLsTool(
|
|
|
17
23
|
TextComp?: new (t?: string, x?: number, y?: number) => { setText(v: string): void },
|
|
18
24
|
): void {
|
|
19
25
|
const home = process.env.HOME ?? "";
|
|
20
|
-
const TC = TextComp
|
|
21
|
-
const { Text } = require("@earendil-works/pi-tui") as { Text: new (t?: string, x?: number, y?: number) => { setText(v: string): void } };
|
|
22
|
-
return Text;
|
|
23
|
-
})();
|
|
26
|
+
const TC = resolveTextCtor(TextComp);
|
|
24
27
|
|
|
25
28
|
pi.registerTool({
|
|
26
29
|
name: "ls",
|
|
@@ -30,9 +33,14 @@ export function registerLsTool(
|
|
|
30
33
|
renderShell: "self",
|
|
31
34
|
|
|
32
35
|
execute: wrapExecuteWithMetrics(async (tid, params, sig, _upd, ctx: ExtensionContext) => {
|
|
33
|
-
const result = await sdkTool.execute(tid, params, sig, undefined, ctx) as Result;
|
|
36
|
+
const result = (await sdkTool.execute(tid, params, sig, undefined, ctx)) as Result;
|
|
34
37
|
const tc = getText(result);
|
|
35
|
-
result.details = {
|
|
38
|
+
result.details = {
|
|
39
|
+
_type: "lsResult",
|
|
40
|
+
text: tc,
|
|
41
|
+
path: String((params as any).path ?? ""),
|
|
42
|
+
entryCount: tc ? tc.trim().split("\n").filter(Boolean).length : 0,
|
|
43
|
+
} as LsDetails;
|
|
36
44
|
return result;
|
|
37
45
|
}),
|
|
38
46
|
|
|
@@ -40,7 +48,10 @@ export function registerLsTool(
|
|
|
40
48
|
resolveBaseBackground(theme);
|
|
41
49
|
const text = ctx.lastComponent ?? new TC("", 0, 0);
|
|
42
50
|
const rawPath = args.path;
|
|
43
|
-
const path =
|
|
51
|
+
const path =
|
|
52
|
+
rawPath === null || rawPath === undefined || String(rawPath).length === 0
|
|
53
|
+
? ""
|
|
54
|
+
: shortPath(cwd, home, String(rawPath));
|
|
44
55
|
const limit = args.limit;
|
|
45
56
|
let out = theme.fg("toolTitle", theme.bold("ls"));
|
|
46
57
|
if (path) out += ` ${theme.fg("accent", path)}`;
|
|
@@ -51,22 +62,39 @@ export function registerLsTool(
|
|
|
51
62
|
|
|
52
63
|
renderResult(result: Result, _opt: unknown, theme: ThemeLike, ctx: RenderCtxLike) {
|
|
53
64
|
resolveBaseBackground(theme);
|
|
54
|
-
|
|
65
|
+
|
|
55
66
|
const text = ctx.lastComponent ?? new TC("", 0, 0);
|
|
56
|
-
if (ctx.isError) {
|
|
67
|
+
if (ctx.isError) {
|
|
68
|
+
text.setText(renderToolError(getText(result) || "Error", theme));
|
|
69
|
+
return text;
|
|
70
|
+
}
|
|
57
71
|
const d = result.details as LsDetails | undefined;
|
|
58
72
|
if (d?._type === "lsResult" && d.text) {
|
|
59
|
-
const rendered = renderTree(d.text, d.path)
|
|
60
|
-
|
|
73
|
+
const rendered = renderTree(d.text, d.path)
|
|
74
|
+
.split("\n")
|
|
75
|
+
.map((l) => ` ${l}`)
|
|
76
|
+
.join("\n");
|
|
77
|
+
text.setText(
|
|
78
|
+
fillToolBackground(
|
|
79
|
+
` \n ${FG_DIM}${d.entryCount} entries${RST}${renderToolMetrics(result)}\n${rendered}\n `,
|
|
80
|
+
),
|
|
81
|
+
);
|
|
61
82
|
return text;
|
|
62
83
|
}
|
|
63
84
|
const fc = result.content?.[0];
|
|
64
|
-
text.setText(
|
|
85
|
+
text.setText(
|
|
86
|
+
fillToolBackground(` ${theme.fg("dim", fc && "text" in fc ? String(fc.text).slice(0, 120) : "done")}`),
|
|
87
|
+
);
|
|
65
88
|
return text;
|
|
66
89
|
},
|
|
67
90
|
} as unknown as ToolDefinition<any, any, any>);
|
|
68
91
|
}
|
|
69
92
|
|
|
70
93
|
function getText(result: Result): string {
|
|
71
|
-
return (
|
|
94
|
+
return (
|
|
95
|
+
((result.content ?? []) as TextContent[])
|
|
96
|
+
.filter((c) => c.type === "text")
|
|
97
|
+
.map((c) => c.text)
|
|
98
|
+
.join("\n") ?? ""
|
|
99
|
+
);
|
|
72
100
|
}
|