@heyhuynhgiabuu/pi-pretty 0.6.15 → 0.6.17

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.
Files changed (84) hide show
  1. package/CHANGELOG.md +19 -116
  2. package/README.md +8 -16
  3. package/dist/collapsed-hint.d.ts +7 -0
  4. package/dist/collapsed-hint.d.ts.map +1 -0
  5. package/dist/collapsed-hint.js +17 -0
  6. package/dist/collapsed-hint.js.map +1 -0
  7. package/dist/config.d.ts +3 -0
  8. package/dist/config.d.ts.map +1 -1
  9. package/dist/config.js +64 -19
  10. package/dist/config.js.map +1 -1
  11. package/dist/expand.d.ts +7 -0
  12. package/dist/expand.d.ts.map +1 -0
  13. package/dist/expand.js +11 -0
  14. package/dist/expand.js.map +1 -0
  15. package/dist/find-glob.d.ts +9 -0
  16. package/dist/find-glob.d.ts.map +1 -0
  17. package/dist/find-glob.js +29 -0
  18. package/dist/find-glob.js.map +1 -0
  19. package/dist/image.js +1 -1
  20. package/dist/index.d.ts +1 -1
  21. package/dist/index.d.ts.map +1 -1
  22. package/dist/index.js +18 -19
  23. package/dist/index.js.map +1 -1
  24. package/dist/render.d.ts +3 -5
  25. package/dist/render.d.ts.map +1 -1
  26. package/dist/render.js +24 -19
  27. package/dist/render.js.map +1 -1
  28. package/dist/tools/bash.d.ts +1 -1
  29. package/dist/tools/bash.d.ts.map +1 -1
  30. package/dist/tools/bash.js +22 -26
  31. package/dist/tools/bash.js.map +1 -1
  32. package/dist/tools/find.d.ts +3 -3
  33. package/dist/tools/find.d.ts.map +1 -1
  34. package/dist/tools/find.js +99 -50
  35. package/dist/tools/find.js.map +1 -1
  36. package/dist/tools/grep.d.ts +2 -2
  37. package/dist/tools/grep.d.ts.map +1 -1
  38. package/dist/tools/grep.js +12 -8
  39. package/dist/tools/grep.js.map +1 -1
  40. package/dist/tools/labels.d.ts +2 -0
  41. package/dist/tools/labels.d.ts.map +1 -0
  42. package/dist/tools/labels.js +7 -0
  43. package/dist/tools/labels.js.map +1 -0
  44. package/dist/tools/ls.d.ts +1 -1
  45. package/dist/tools/ls.d.ts.map +1 -1
  46. package/dist/tools/ls.js +9 -5
  47. package/dist/tools/ls.js.map +1 -1
  48. package/dist/tools/read.d.ts +1 -1
  49. package/dist/tools/read.d.ts.map +1 -1
  50. package/dist/tools/read.js +34 -48
  51. package/dist/tools/read.js.map +1 -1
  52. package/dist/tui-text.d.ts.map +1 -1
  53. package/dist/tui-text.js +1 -5
  54. package/dist/tui-text.js.map +1 -1
  55. package/dist/types.d.ts +4 -27
  56. package/dist/types.d.ts.map +1 -1
  57. package/package.json +5 -4
  58. package/src/collapsed-hint.ts +14 -0
  59. package/src/config.ts +70 -22
  60. package/src/expand.ts +10 -0
  61. package/src/find-glob.ts +21 -0
  62. package/src/image.ts +1 -1
  63. package/src/index.ts +25 -32
  64. package/src/notices.ts +1 -1
  65. package/src/render.ts +50 -41
  66. package/src/tools/bash.ts +27 -48
  67. package/src/tools/find.ts +131 -86
  68. package/src/tools/grep.ts +23 -17
  69. package/src/tools/labels.ts +3 -0
  70. package/src/tools/ls.ts +27 -13
  71. package/src/tools/metrics.ts +1 -1
  72. package/src/tools/read.ts +55 -66
  73. package/src/tui-text.ts +1 -5
  74. package/src/types.ts +4 -35
  75. package/dist/multi-grep-fallback.d.ts +0 -30
  76. package/dist/multi-grep-fallback.d.ts.map +0 -1
  77. package/dist/multi-grep-fallback.js +0 -205
  78. package/dist/multi-grep-fallback.js.map +0 -1
  79. package/dist/tools/multi-grep.d.ts +0 -7
  80. package/dist/tools/multi-grep.d.ts.map +0 -1
  81. package/dist/tools/multi-grep.js +0 -294
  82. package/dist/tools/multi-grep.js.map +0 -1
  83. package/src/multi-grep-fallback.ts +0 -248
  84. package/src/tools/multi-grep.ts +0 -331
package/src/tools/grep.ts CHANGED
@@ -1,19 +1,14 @@
1
1
  /* pi-pretty: grep tool -- FFF-backed text search with SDK fallback. */
2
2
 
3
- import {
4
- type ToolDefinition,
5
- type ExtensionAPI,
6
- type ExtensionContext,
7
- type AgentToolResult,
8
- } from "@earendil-works/pi-coding-agent";
9
- import type { SdkToolDef, GrepDetails, FffServiceWithCursor, TextContent, ThemeLike, RenderCtxLike } from "../types.js";
10
- import { MAX_PREVIEW_LINES, BG_ERROR, resolveBaseBackground } from "../config.js";
11
- import { shortPath, normalizeLineEndings } from "../helpers.js";
12
- import { wrapExecuteWithMetrics } from "./metrics.js";
13
- import { renderToolError, fillToolBackground } from "../render.js";
14
- import { resolveTextCtor } from "../tui-text.js";
3
+ import type { AgentToolResult, ExtensionAPI, ExtensionContext, ToolDefinition } from "@earendil-works/pi-coding-agent";
4
+ import { BG_ERROR, FG_DIM, MAX_PREVIEW_LINES, RST, resolveBaseBackground, TOOL_RESULT_INDENT } from "../config.js";
15
5
  import { fffFormatGrepText } from "../fff-helpers.js";
6
+ import { normalizeLineEndings, shortPath } from "../helpers.js";
16
7
  import { NOTICE_PARTIAL_FILE_INDEX } from "../notices.js";
8
+ import { fillToolBackground, renderToolError } from "../render.js";
9
+ import { resolveTextCtor } from "../tui-text.js";
10
+ import type { FffServiceWithCursor, GrepDetails, RenderCtxLike, SdkToolDef, TextContent, ThemeLike } from "../types.js";
11
+ import { wrapExecuteWithMetrics } from "./metrics.js";
17
12
 
18
13
  const invalidArg = "<missing>";
19
14
 
@@ -111,12 +106,12 @@ export function registerGrepTool(
111
106
  const limit = args.limit;
112
107
  const literal = args.literal === true;
113
108
  const caseInsensitive = args.caseInsensitive === true || args.ignoreCase === true;
114
- let out = `${theme.fg("toolTitle", theme.bold("grep"))} ${theme.fg("accent", `/${pattern || ""}/`)}${theme.fg("toolOutput", ` in ${path}`)}`;
109
+ let out = `${theme.fg(ctx.isError ? "error" : "toolTitle", theme.bold("✱ grep"))} ${theme.fg("toolTitle", `/${pattern || ""}/`)}${theme.fg("toolOutput", ` in ${path}`)}`;
115
110
  if (glob) out += theme.fg("dim", ` (${String(glob)})`);
116
111
  if (limit !== undefined && limit !== null) out += theme.fg("dim", ` limit ${limit}`);
117
112
  if (literal) out += theme.fg("dim", ` (literal)`);
118
113
  if (caseInsensitive) out += theme.fg("dim", ` (case-insensitive)`);
119
- text.setText(fillToolBackground(`\n ${out}`, ctx.isError ? BG_ERROR : undefined));
114
+ text.setText(fillToolBackground(`\n${TOOL_RESULT_INDENT}${out}`, ctx.isError ? BG_ERROR : undefined));
120
115
  return text;
121
116
  },
122
117
 
@@ -138,7 +133,16 @@ export function registerGrepTool(
138
133
  const d = result.details as GrepDetails | undefined;
139
134
  if (d?._type === "grepResult" && d.text) {
140
135
  const lines = d.text.split("\n");
141
- const maxShow = ctx.expanded ? lines.length : Math.min(lines.length, MAX_PREVIEW_LINES);
136
+ if (!ctx.expanded) {
137
+ text.setText(
138
+ fillToolBackground(
139
+ `${TOOL_RESULT_INDENT}${FG_DIM}${lines.length} lines — ctrl+o to expand${RST}\n`,
140
+ ctx.isError ? BG_ERROR : undefined,
141
+ ),
142
+ );
143
+ return text;
144
+ }
145
+ const maxShow = lines.length;
142
146
  const show = lines.slice(0, maxShow);
143
147
  const remaining = lines.length - maxShow;
144
148
  const out: string[] = [];
@@ -149,13 +153,15 @@ export function registerGrepTool(
149
153
  if (remaining > 0) {
150
154
  out.push(theme.fg("muted", `… (${remaining} more ${remaining === 1 ? "line" : "lines"}, to expand)`));
151
155
  }
152
- const body = out.map((l) => ` ${l}`).join("\n") + "\n\n";
156
+ const body = `${out.map((l) => `${TOOL_RESULT_INDENT}${l}`).join("\n")}\n\n`;
153
157
  text.setText(fillToolBackground(body, ctx.isError ? BG_ERROR : undefined));
154
158
  return text;
155
159
  }
156
160
  const fc = result.content?.[0];
157
161
  const fallback = fc && "text" in fc ? String(fc.text).slice(0, 120) : "no matches";
158
- text.setText(fillToolBackground(` ${theme.fg("dim", fallback)}`, ctx.isError ? BG_ERROR : undefined));
162
+ text.setText(
163
+ fillToolBackground(`${TOOL_RESULT_INDENT}${theme.fg("dim", fallback)}`, ctx.isError ? BG_ERROR : undefined),
164
+ );
159
165
  return text;
160
166
  },
161
167
  } as unknown as ToolDefinition<any, any, any>);
@@ -0,0 +1,3 @@
1
+ export function customToolTitle(name: string): string {
2
+ return `⚙ ${name}`;
3
+ }
package/src/tools/ls.ts CHANGED
@@ -1,17 +1,21 @@
1
1
  /* pi-pretty: ls tool -- directory listing with styled output. */
2
2
 
3
+ import type { AgentToolResult, ExtensionAPI, ExtensionContext, ToolDefinition } from "@earendil-works/pi-coding-agent";
3
4
  import {
4
- type ToolDefinition,
5
- type ExtensionAPI,
6
- type ExtensionContext,
7
- type AgentToolResult,
8
- } from "@earendil-works/pi-coding-agent";
9
- import type { SdkToolDef, LsDetails, TextContent, ComponentLike, ThemeLike, RenderCtxLike } from "../types.js";
10
- import { resolveBaseBackground, termWidth, MAX_PREVIEW_LINES, BG_BASE, BG_ERROR, FG_DIM, RST } from "../config.js";
5
+ BG_BASE,
6
+ BG_ERROR,
7
+ FG_DIM,
8
+ MAX_PREVIEW_LINES,
9
+ RST,
10
+ resolveBaseBackground,
11
+ TOOL_RESULT_INDENT,
12
+ termWidth,
13
+ } from "../config.js";
11
14
  import { shortPath } from "../helpers.js";
12
- import { wrapExecuteWithMetrics } from "./metrics.js";
13
- import { renderTree, renderToolError, renderToolMetrics, fillToolBackground } from "../render.js";
15
+ import { fillToolBackground, renderToolError, renderToolMetrics, renderTree } from "../render.js";
14
16
  import { resolveTextCtor } from "../tui-text.js";
17
+ import type { ComponentLike, LsDetails, RenderCtxLike, SdkToolDef, TextContent, ThemeLike } from "../types.js";
18
+ import { wrapExecuteWithMetrics } from "./metrics.js";
15
19
 
16
20
  type Result = AgentToolResult<Record<string, unknown>>;
17
21
 
@@ -56,7 +60,7 @@ export function registerLsTool(
56
60
  let out = theme.fg("toolTitle", theme.bold("ls"));
57
61
  if (path) out += ` ${theme.fg("accent", path)}`;
58
62
  if (limit !== undefined && limit !== null) out += theme.fg("toolOutput", ` (limit ${limit})`);
59
- text.setText(fillToolBackground(` \n ${out}`, ctx.isError ? BG_ERROR : undefined));
63
+ text.setText(fillToolBackground(`\n${TOOL_RESULT_INDENT}${out}`, ctx.isError ? BG_ERROR : undefined));
60
64
  return text;
61
65
  },
62
66
 
@@ -70,20 +74,30 @@ export function registerLsTool(
70
74
  }
71
75
  const d = result.details as LsDetails | undefined;
72
76
  if (d?._type === "lsResult" && d.text) {
77
+ if (!ctx.expanded) {
78
+ text.setText(
79
+ fillToolBackground(
80
+ `${TOOL_RESULT_INDENT}${FG_DIM}${d.entryCount} entries — ctrl+o to expand${RST}${renderToolMetrics(result)}\n`,
81
+ ),
82
+ );
83
+ return text;
84
+ }
73
85
  const rendered = renderTree(d.text, d.path)
74
86
  .split("\n")
75
- .map((l) => ` ${l}`)
87
+ .map((l) => `${TOOL_RESULT_INDENT}${l}`)
76
88
  .join("\n");
77
89
  text.setText(
78
90
  fillToolBackground(
79
- ` \n ${FG_DIM}${d.entryCount} entries${RST}${renderToolMetrics(result)}\n${rendered}\n `,
91
+ `\n${TOOL_RESULT_INDENT}${FG_DIM}${d.entryCount} entries${RST}${renderToolMetrics(result)}\n${rendered}\n`,
80
92
  ),
81
93
  );
82
94
  return text;
83
95
  }
84
96
  const fc = result.content?.[0];
85
97
  text.setText(
86
- fillToolBackground(` ${theme.fg("dim", fc && "text" in fc ? String(fc.text).slice(0, 120) : "done")}`),
98
+ fillToolBackground(
99
+ `${TOOL_RESULT_INDENT}${theme.fg("dim", fc && "text" in fc ? String(fc.text).slice(0, 120) : "done")}`,
100
+ ),
87
101
  );
88
102
  return text;
89
103
  },
@@ -5,7 +5,7 @@
5
5
  */
6
6
 
7
7
  import type { AgentToolResult, ExtensionContext } from "@earendil-works/pi-coding-agent";
8
- import { ELAPSED_KEY, CHARS_KEY } from "../helpers.js";
8
+ import { CHARS_KEY, ELAPSED_KEY } from "../helpers.js";
9
9
 
10
10
  type ExecuteFn = (
11
11
  tid: string,
package/src/tools/read.ts CHANGED
@@ -1,39 +1,24 @@
1
1
  /* pi-pretty: read tool -- file reading with syntax highlighting and inline image support. */
2
2
 
3
+ import type { AgentToolResult, ExtensionAPI, ExtensionContext, ToolDefinition } from "@earendil-works/pi-coding-agent";
4
+ import { Image as TuiImage } from "@earendil-works/pi-tui";
3
5
  import {
4
- type ToolDefinition,
5
- type ExtensionAPI,
6
- type ExtensionContext,
7
- type AgentToolResult,
8
- } from "@earendil-works/pi-coding-agent";
9
- import type { SdkToolDef, ReadDetails, TextContent, ComponentLike, ThemeLike, RenderCtxLike } from "../types.js";
10
- import {
11
- resolveBaseBackground,
12
- termWidth,
13
- MAX_PREVIEW_LINES,
14
6
  BG_BASE,
15
7
  BG_ERROR,
16
8
  FG_DIM,
17
9
  FG_LNUM,
18
10
  FG_RULE,
11
+ MAX_PREVIEW_LINES,
19
12
  RST,
13
+ resolveBaseBackground,
14
+ TOOL_RESULT_INDENT,
15
+ termWidth,
20
16
  } from "../config.js";
21
- import { shortPath, normalizeLineEndings } from "../helpers.js";
22
- import { wrapExecuteWithMetrics } from "./metrics.js";
23
- import { renderToolError, renderToolMetrics, fillToolBackground, renderFileContent } from "../render.js";
17
+ import { normalizeLineEndings, shortPath } from "../helpers.js";
18
+ import { fillToolBackground, renderFileContent, renderToolError, renderToolMetrics } from "../render.js";
24
19
  import { resolveTextCtor } from "../tui-text.js";
25
-
26
- // Simple terminal image support check
27
- function isImageTerminal(): boolean {
28
- const term = (process.env.TERM_PROGRAM ?? process.env.TERM ?? "").toLowerCase();
29
- const proto = (process.env.PRETTY_IMAGE_PROTOCOL ?? "").toLowerCase();
30
- if (proto === "kitty" || proto === "iterm2") return true;
31
- if (proto === "none") return false;
32
- return (
33
- ["ghostty", "kitty", "iterm.app", "wezterm", "mintty"].some((t) => term.includes(t)) ||
34
- process.env.LC_TERMINAL === "iTerm2"
35
- );
36
- }
20
+ import type { ReadDetails, RenderCtxLike, SdkToolDef, TextContent, ThemeLike } from "../types.js";
21
+ import { wrapExecuteWithMetrics } from "./metrics.js";
37
22
 
38
23
  type Result = AgentToolResult<Record<string, unknown>>;
39
24
 
@@ -84,7 +69,14 @@ export function registerReadTool(
84
69
  resolveBaseBackground(theme);
85
70
 
86
71
  const text = ctx.lastComponent ?? new TC("", 0, 0);
87
- text.setText("");
72
+ if (!ctx.isError) {
73
+ text.setText("");
74
+ return text;
75
+ }
76
+
77
+ const path = String(args.path ?? "");
78
+ const label = theme.fg("error", theme.bold("→ read"));
79
+ text.setText(fillToolBackground(`\n${TOOL_RESULT_INDENT}${label} ${theme.fg("toolTitle", path)}`, BG_ERROR));
88
80
  return text;
89
81
  },
90
82
 
@@ -94,40 +86,25 @@ export function registerReadTool(
94
86
  const text = ctx.lastComponent ?? new TC("", 0, 0);
95
87
 
96
88
  if (ctx.isError) {
97
- text.setText(renderToolError(getText(result) || "Error", theme));
89
+ text.setText(fillToolBackground(renderToolError(getText(result) || "Error", theme), BG_ERROR));
98
90
  return text;
99
91
  }
100
92
 
101
93
  const d = result.details as ReadDetails | undefined;
102
94
 
103
- // Image rendering
95
+ // Image rendering — use pi-tui Image component
104
96
  if (d?._type === "readImage") {
105
- if ((ctx as any).showImages && isImageTerminal()) {
106
- try {
107
- const T = require("@earendil-works/pi-tui").Text as new (
108
- t?: string,
109
- x?: number,
110
- y?: number,
111
- ) => ComponentLike;
112
- const img = new T("", 0, 0);
113
- if (d.mimeType.startsWith("image/svg")) {
114
- img.setText(d.data);
115
- } else {
116
- const pngData = (require("@earendil-works/pi-coding-agent") as any).convertToPng?.(d.data) ?? d.data;
117
- img.setText(`\x1b_Ga=T,f=100,m=${d.mimeType === "image/png" ? "1" : "0"};${pngData}\x1b\\\\`);
118
- }
119
- return img;
120
- } catch {
121
- /* fall through */
122
- }
123
- }
124
- const fc = result.content?.[0];
125
- text.setText(
126
- fillToolBackground(
127
- ` ${theme.fg("dim", fc && "text" in fc ? String(fc.text).slice(0, 80) : `[image: ${d.filePath}]`)}`,
128
- ),
97
+ const mimeType = d.mimeType.startsWith("image/svg") ? "image/svg+xml" : d.mimeType;
98
+ return new TuiImage(
99
+ d.data,
100
+ mimeType,
101
+ {
102
+ fallbackColor: (text) => theme.fg("toolTitle", text),
103
+ },
104
+ {
105
+ filename: d.filePath,
106
+ },
129
107
  );
130
- return text;
131
108
  }
132
109
 
133
110
  // File content — line-numbered display
@@ -135,32 +112,41 @@ export function registerReadTool(
135
112
  const tw = termWidth();
136
113
  const lines = d.content.split("\n");
137
114
  const total = lines.length;
138
- const maxShow = ctx.expanded ? lines.length : Math.min(lines.length, MAX_PREVIEW_LINES);
115
+ const p2 = shortPath(cwd, home, String(d.filePath ?? ""));
116
+ const off2 = typeof d.offset === "number" ? `:${d.offset}` : "";
117
+ if (!ctx.expanded) {
118
+ text.setText(
119
+ fillToolBackground(
120
+ `\n${TOOL_RESULT_INDENT}${theme.fg("toolTitle", theme.bold("→ read"))} ${theme.fg("toolTitle", p2)}${theme.fg("dim", off2)}\n${TOOL_RESULT_INDENT}${FG_DIM}${total} lines — ctrl+o to expand${RST}\n`,
121
+ BG_BASE,
122
+ ),
123
+ );
124
+ return text;
125
+ }
126
+ const maxShow = lines.length;
139
127
  const show = lines.slice(0, maxShow);
140
128
  const nw = Math.max(3, String(total).length);
141
129
  const gw = nw + 3;
142
130
  const cw = Math.max(1, tw - gw);
143
131
 
144
- const p2 = shortPath(cwd, home, String(d.filePath ?? ""));
145
- const off2 = typeof d.offset === "number" ? `:${d.offset}` : "";
146
- const header = `${theme.fg("toolTitle", theme.bold("read"))} ${theme.fg("accent", p2)}${theme.fg("dim", off2)}`;
147
- const out: string[] = ["", ` ${header}`];
148
- out.push(` ${FG_RULE}${"─".repeat(tw - 2)}${RST}`);
132
+ const header = `${theme.fg("toolTitle", theme.bold("→ read"))} ${theme.fg("toolTitle", p2)}${theme.fg("dim", off2)}`;
133
+ const out: string[] = ["", `${TOOL_RESULT_INDENT}${header}`];
134
+ out.push(`${TOOL_RESULT_INDENT}${FG_RULE}${"─".repeat(tw - 1)}${RST}`);
149
135
  for (let i = 0; i < show.length; i++) {
150
136
  const ln = (d.offset || 0) + i + 1;
151
137
  const code = show[i] ?? "";
152
138
  const display = code.length > cw ? code.slice(0, cw) + `${FG_DIM}›${RST}` : code;
153
139
  const lineNo = String(ln);
154
140
  out.push(
155
- ` ${FG_LNUM}${" ".repeat(Math.max(0, nw - lineNo.length))}${lineNo}${RST} ${FG_RULE}│${RST} ${display}${RST}`,
141
+ `${TOOL_RESULT_INDENT}${FG_LNUM}${" ".repeat(Math.max(0, nw - lineNo.length))}${lineNo}${RST} ${FG_RULE}│${RST} ${display}${RST}`,
156
142
  );
157
143
  }
158
144
  if (total > maxShow) {
159
- out.push(` ${FG_DIM} … ${total - maxShow} more lines (${total} total)${RST}`);
145
+ out.push(`${TOOL_RESULT_INDENT}${FG_DIM}… ${total - maxShow} more lines (${total} total)${RST}`);
160
146
  }
161
147
  out.push("");
162
148
  const rendered = out.join("\n");
163
- text.setText(fillToolBackground(rendered));
149
+ text.setText(fillToolBackground(rendered, BG_BASE));
164
150
  (ctx as any).state._rt = rendered;
165
151
 
166
152
  // Async syntax highlighting via Shiki
@@ -168,10 +154,10 @@ export function registerReadTool(
168
154
  .then((hl) => {
169
155
  const padded = hl
170
156
  .split("\n")
171
- .map((l) => ` ${l}`)
157
+ .map((l) => `${TOOL_RESULT_INDENT}${l}`)
172
158
  .join("\n");
173
- const rendered = `\n ${header}\n${padded}\n`;
174
- text.setText(fillToolBackground(rendered));
159
+ const rendered = `\n${TOOL_RESULT_INDENT}${header}\n${padded}\n`;
160
+ text.setText(fillToolBackground(rendered, BG_BASE));
175
161
  (ctx as any).state._rt = rendered;
176
162
  })
177
163
  .catch(() => {});
@@ -181,7 +167,10 @@ export function registerReadTool(
181
167
 
182
168
  const fc = result.content?.[0];
183
169
  text.setText(
184
- fillToolBackground(` ${theme.fg("dim", fc && "text" in fc ? String(fc.text).slice(0, 120) : "done")}`),
170
+ fillToolBackground(
171
+ `${TOOL_RESULT_INDENT}${theme.fg("dim", fc && "text" in fc ? String(fc.text).slice(0, 120) : "done")}`,
172
+ BG_BASE,
173
+ ),
185
174
  );
186
175
  return text;
187
176
  },
package/src/tui-text.ts CHANGED
@@ -13,10 +13,6 @@ type TextCtor = new (t?: string, x?: number, y?: number) => { setText(v: string)
13
13
 
14
14
  /** No-op stub that satisfies the Text interface so rendering doesn't crash. */
15
15
  class StubText {
16
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
17
- constructor(_t?: string, _x?: number, _y?: number) {
18
- // no-op
19
- }
20
16
  setText(_v: string): void {
21
17
  // no-op — pi-tui not available
22
18
  }
@@ -26,7 +22,7 @@ let _ctor: TextCtor | null = null;
26
22
  let _resolved = false;
27
23
 
28
24
  function resolve(): TextCtor {
29
- if (_resolved) return _ctor!;
25
+ if (_ctor) return _ctor;
30
26
  _resolved = true;
31
27
  try {
32
28
  // eslint-disable-next-line @typescript-eslint/no-var-requires
package/src/types.ts CHANGED
@@ -2,21 +2,21 @@
2
2
  * pi-pretty shared types.
3
3
  */
4
4
 
5
- import type { TextContent, ImageContent } from "@earendil-works/pi-ai";
5
+ import type { ImageContent, TextContent } from "@earendil-works/pi-ai";
6
6
  import type { AgentToolResult } from "@earendil-works/pi-coding-agent";
7
7
 
8
8
  // ---------------------------------------------------------------------------
9
9
  // Re-export FFF types needed by tools
10
10
  // ---------------------------------------------------------------------------
11
11
 
12
- export type { FileFinder, FileItem, GrepResult, SearchResult, GrepMatch, GrepCursor } from "@ff-labs/fff-node";
12
+ export type { FileFinder, FileItem, GrepCursor, GrepMatch, GrepResult, SearchResult } from "@ff-labs/fff-node";
13
13
 
14
14
  // ---------------------------------------------------------------------------
15
15
  // Content / Result types
16
16
  // ---------------------------------------------------------------------------
17
17
 
18
18
  export type ToolContent = TextContent | ImageContent;
19
- export type { TextContent, ImageContent };
19
+ export type { ImageContent, TextContent };
20
20
  // ---------------------------------------------------------------------------
21
21
  // Theme / rendering context types
22
22
  // ---------------------------------------------------------------------------
@@ -73,6 +73,7 @@ export interface FindDetails extends Record<string, unknown> {
73
73
  text: string;
74
74
  pattern: string;
75
75
  matchCount: number;
76
+ notices?: string[];
76
77
  }
77
78
 
78
79
  export interface GrepDetails extends Record<string, unknown> {
@@ -119,14 +120,6 @@ export interface GrepInput {
119
120
  ignoreCase?: boolean;
120
121
  }
121
122
 
122
- export interface MultiGrepInput {
123
- patterns: string[];
124
- path?: string;
125
- constraints?: string;
126
- context?: number;
127
- limit?: number;
128
- }
129
-
130
123
  // ---------------------------------------------------------------------------
131
124
  // SDK tool definition shape (DI-friendly — accepts both mock and real SDK)
132
125
  // ---------------------------------------------------------------------------
@@ -152,29 +145,6 @@ export interface SdkTools {
152
145
  getAgentDir?: () => string;
153
146
  }
154
147
 
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
148
  // ---------------------------------------------------------------------------
179
149
  // FFF service interfaces
180
150
  // ---------------------------------------------------------------------------
@@ -223,5 +193,4 @@ export interface PiPrettyDeps {
223
193
  sdk?: SdkTools;
224
194
  TextComponent?: new (text?: string, x?: number, y?: number) => ComponentLike;
225
195
  fffModule?: typeof import("@ff-labs/fff-node");
226
- multiGrepRipgrepFallback?: MultiGrepFallback;
227
196
  }
@@ -1,30 +0,0 @@
1
- export type ConstraintParseResult = {
2
- ok: true;
3
- globs: string[];
4
- tokens: string[];
5
- } | {
6
- ok: false;
7
- error: string;
8
- };
9
- export type MultiGrepRipgrepFallbackParams = {
10
- cwd: string;
11
- patterns: string[];
12
- path?: string;
13
- constraints?: string;
14
- context?: number;
15
- limit: number;
16
- ignoreCase: boolean;
17
- signal?: AbortSignal;
18
- };
19
- export type MultiGrepRipgrepFallbackResult = {
20
- text: string;
21
- matchCount: number;
22
- limitReached: boolean;
23
- };
24
- export type MultiGrepRipgrepFallback = (params: MultiGrepRipgrepFallbackParams) => Promise<MultiGrepRipgrepFallbackResult>;
25
- export declare function parseMultiGrepConstraints(constraints: string | undefined): ConstraintParseResult;
26
- export declare function getMultiGrepRipgrepArgs(params: MultiGrepRipgrepFallbackParams): ConstraintParseResult & {
27
- args?: string[];
28
- };
29
- export declare function runMultiGrepRipgrepFallback(params: MultiGrepRipgrepFallbackParams): Promise<MultiGrepRipgrepFallbackResult>;
30
- //# sourceMappingURL=multi-grep-fallback.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"multi-grep-fallback.d.ts","sourceRoot":"","sources":["../src/multi-grep-fallback.ts"],"names":[],"mappings":"AAEA,MAAM,MAAM,qBAAqB,GAAG;IAAE,EAAE,EAAE,IAAI,CAAC;IAAC,KAAK,EAAE,MAAM,EAAE,CAAC;IAAC,MAAM,EAAE,MAAM,EAAE,CAAA;CAAE,GAAG;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAAC;AAEnH,MAAM,MAAM,8BAA8B,GAAG;IAC5C,GAAG,EAAE,MAAM,CAAC;IACZ,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,MAAM,CAAC;IACd,UAAU,EAAE,OAAO,CAAC;IACpB,MAAM,CAAC,EAAE,WAAW,CAAC;CACrB,CAAC;AAEF,MAAM,MAAM,8BAA8B,GAAG;IAC5C,IAAI,EAAE,MAAM,CAAC;IACb,UAAU,EAAE,MAAM,CAAC;IACnB,YAAY,EAAE,OAAO,CAAC;CACtB,CAAC;AAEF,MAAM,MAAM,wBAAwB,GAAG,CACtC,MAAM,EAAE,8BAA8B,KAClC,OAAO,CAAC,8BAA8B,CAAC,CAAC;AA8E7C,wBAAgB,yBAAyB,CAAC,WAAW,EAAE,MAAM,GAAG,SAAS,GAAG,qBAAqB,CAehG;AAqBD,wBAAgB,uBAAuB,CACtC,MAAM,EAAE,8BAA8B,GACpC,qBAAqB,GAAG;IAAE,IAAI,CAAC,EAAE,MAAM,EAAE,CAAA;CAAE,CAI7C;AAED,wBAAsB,2BAA2B,CAChD,MAAM,EAAE,8BAA8B,GACpC,OAAO,CAAC,8BAA8B,CAAC,CAoGzC"}