@heyhuynhgiabuu/pi-pretty 0.6.16 → 0.6.18

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 (77) hide show
  1. package/CHANGELOG.md +26 -0
  2. package/README.md +6 -16
  3. package/dist/config.d.ts +1 -0
  4. package/dist/config.d.ts.map +1 -1
  5. package/dist/config.js +61 -18
  6. package/dist/config.js.map +1 -1
  7. package/dist/expand.d.ts +0 -6
  8. package/dist/expand.d.ts.map +1 -1
  9. package/dist/expand.js +0 -13
  10. package/dist/expand.js.map +1 -1
  11. package/dist/image.js +1 -1
  12. package/dist/index.d.ts +1 -1
  13. package/dist/index.d.ts.map +1 -1
  14. package/dist/index.js +18 -21
  15. package/dist/index.js.map +1 -1
  16. package/dist/render.d.ts +5 -7
  17. package/dist/render.d.ts.map +1 -1
  18. package/dist/render.js +16 -16
  19. package/dist/render.js.map +1 -1
  20. package/dist/tools/bash.d.ts +1 -1
  21. package/dist/tools/bash.d.ts.map +1 -1
  22. package/dist/tools/bash.js +18 -23
  23. package/dist/tools/bash.js.map +1 -1
  24. package/dist/tools/find.d.ts +2 -2
  25. package/dist/tools/find.d.ts.map +1 -1
  26. package/dist/tools/find.js +12 -8
  27. package/dist/tools/find.js.map +1 -1
  28. package/dist/tools/grep.d.ts +2 -2
  29. package/dist/tools/grep.d.ts.map +1 -1
  30. package/dist/tools/grep.js +5 -5
  31. package/dist/tools/grep.js.map +1 -1
  32. package/dist/tools/labels.d.ts +2 -0
  33. package/dist/tools/labels.d.ts.map +1 -0
  34. package/dist/tools/labels.js +7 -0
  35. package/dist/tools/labels.js.map +1 -0
  36. package/dist/tools/ls.d.ts +1 -1
  37. package/dist/tools/ls.d.ts.map +1 -1
  38. package/dist/tools/ls.js +1 -1
  39. package/dist/tools/ls.js.map +1 -1
  40. package/dist/tools/read.d.ts +1 -1
  41. package/dist/tools/read.d.ts.map +1 -1
  42. package/dist/tools/read.js +22 -40
  43. package/dist/tools/read.js.map +1 -1
  44. package/dist/tui-text.d.ts +2 -20
  45. package/dist/tui-text.d.ts.map +1 -1
  46. package/dist/tui-text.js +3 -46
  47. package/dist/tui-text.js.map +1 -1
  48. package/dist/types.d.ts +3 -27
  49. package/dist/types.d.ts.map +1 -1
  50. package/package.json +4 -4
  51. package/src/collapsed-hint.ts +1 -1
  52. package/src/config.ts +67 -22
  53. package/src/expand.ts +0 -14
  54. package/src/find-glob.ts +1 -1
  55. package/src/image.ts +1 -1
  56. package/src/index.ts +25 -34
  57. package/src/notices.ts +1 -1
  58. package/src/render.ts +44 -43
  59. package/src/tools/bash.ts +24 -48
  60. package/src/tools/find.ts +22 -36
  61. package/src/tools/grep.ts +12 -15
  62. package/src/tools/labels.ts +3 -0
  63. package/src/tools/ls.ts +16 -10
  64. package/src/tools/metrics.ts +1 -1
  65. package/src/tools/read.ts +39 -59
  66. package/src/tui-text.ts +10 -49
  67. package/src/types.ts +3 -35
  68. package/dist/multi-grep-fallback.d.ts +0 -30
  69. package/dist/multi-grep-fallback.d.ts.map +0 -1
  70. package/dist/multi-grep-fallback.js +0 -205
  71. package/dist/multi-grep-fallback.js.map +0 -1
  72. package/dist/tools/multi-grep.d.ts +0 -7
  73. package/dist/tools/multi-grep.d.ts.map +0 -1
  74. package/dist/tools/multi-grep.js +0 -298
  75. package/dist/tools/multi-grep.js.map +0 -1
  76. package/src/multi-grep-fallback.ts +0 -248
  77. package/src/tools/multi-grep.ts +0 -339
package/src/tools/read.ts CHANGED
@@ -1,40 +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
- TOOL_RESULT_INDENT,
12
- resolveBaseBackground,
13
- termWidth,
14
- MAX_PREVIEW_LINES,
15
6
  BG_BASE,
16
7
  BG_ERROR,
17
8
  FG_DIM,
18
9
  FG_LNUM,
19
10
  FG_RULE,
11
+ MAX_PREVIEW_LINES,
20
12
  RST,
13
+ resolveBaseBackground,
14
+ TOOL_RESULT_INDENT,
15
+ termWidth,
21
16
  } from "../config.js";
22
- import { shortPath, normalizeLineEndings } from "../helpers.js";
23
- import { wrapExecuteWithMetrics } from "./metrics.js";
24
- import { renderToolError, renderToolMetrics, fillToolBackground, renderFileContent } from "../render.js";
17
+ import { normalizeLineEndings, shortPath } from "../helpers.js";
18
+ import { fillToolBackground, renderFileContent, renderToolError, renderToolMetrics } from "../render.js";
25
19
  import { resolveTextCtor } from "../tui-text.js";
26
-
27
- // Simple terminal image support check
28
- function isImageTerminal(): boolean {
29
- const term = (process.env.TERM_PROGRAM ?? process.env.TERM ?? "").toLowerCase();
30
- const proto = (process.env.PRETTY_IMAGE_PROTOCOL ?? "").toLowerCase();
31
- if (proto === "kitty" || proto === "iterm2") return true;
32
- if (proto === "none") return false;
33
- return (
34
- ["ghostty", "kitty", "iterm.app", "wezterm", "mintty"].some((t) => term.includes(t)) ||
35
- process.env.LC_TERMINAL === "iTerm2"
36
- );
37
- }
20
+ import type { ReadDetails, RenderCtxLike, SdkToolDef, TextContent, ThemeLike } from "../types.js";
21
+ import { wrapExecuteWithMetrics } from "./metrics.js";
38
22
 
39
23
  type Result = AgentToolResult<Record<string, unknown>>;
40
24
 
@@ -85,7 +69,14 @@ export function registerReadTool(
85
69
  resolveBaseBackground(theme);
86
70
 
87
71
  const text = ctx.lastComponent ?? new TC("", 0, 0);
88
- 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));
89
80
  return text;
90
81
  },
91
82
 
@@ -95,40 +86,25 @@ export function registerReadTool(
95
86
  const text = ctx.lastComponent ?? new TC("", 0, 0);
96
87
 
97
88
  if (ctx.isError) {
98
- text.setText(renderToolError(getText(result) || "Error", theme));
89
+ text.setText(fillToolBackground(renderToolError(getText(result) || "Error", theme), BG_ERROR));
99
90
  return text;
100
91
  }
101
92
 
102
93
  const d = result.details as ReadDetails | undefined;
103
94
 
104
- // Image rendering
95
+ // Image rendering — use pi-tui Image component
105
96
  if (d?._type === "readImage") {
106
- if ((ctx as any).showImages && isImageTerminal()) {
107
- try {
108
- const T = require("@earendil-works/pi-tui").Text as new (
109
- t?: string,
110
- x?: number,
111
- y?: number,
112
- ) => ComponentLike;
113
- const img = new T("", 0, 0);
114
- if (d.mimeType.startsWith("image/svg")) {
115
- img.setText(d.data);
116
- } else {
117
- const pngData = (require("@earendil-works/pi-coding-agent") as any).convertToPng?.(d.data) ?? d.data;
118
- img.setText(`\x1b_Ga=T,f=100,m=${d.mimeType === "image/png" ? "1" : "0"};${pngData}\x1b\\\\`);
119
- }
120
- return img;
121
- } catch {
122
- /* fall through */
123
- }
124
- }
125
- const fc = result.content?.[0];
126
- text.setText(
127
- fillToolBackground(
128
- `${TOOL_RESULT_INDENT}${theme.fg("dim", fc && "text" in fc ? String(fc.text).slice(0, 80) : `[image: ${d.filePath}]`)}`,
129
- ),
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
+ },
130
107
  );
131
- return text;
132
108
  }
133
109
 
134
110
  // File content — line-numbered display
@@ -141,7 +117,8 @@ export function registerReadTool(
141
117
  if (!ctx.expanded) {
142
118
  text.setText(
143
119
  fillToolBackground(
144
- `\n${TOOL_RESULT_INDENT}${theme.fg("toolTitle", theme.bold("read"))} ${theme.fg("accent", p2)}${theme.fg("dim", off2)}\n${TOOL_RESULT_INDENT}${FG_DIM}${total} lines — ctrl+o to expand${RST}\n`,
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,
145
122
  ),
146
123
  );
147
124
  return text;
@@ -152,7 +129,7 @@ export function registerReadTool(
152
129
  const gw = nw + 3;
153
130
  const cw = Math.max(1, tw - gw);
154
131
 
155
- const header = `${theme.fg("toolTitle", theme.bold("read"))} ${theme.fg("accent", p2)}${theme.fg("dim", off2)}`;
132
+ const header = `${theme.fg("toolTitle", theme.bold("→ read"))} ${theme.fg("toolTitle", p2)}${theme.fg("dim", off2)}`;
156
133
  const out: string[] = ["", `${TOOL_RESULT_INDENT}${header}`];
157
134
  out.push(`${TOOL_RESULT_INDENT}${FG_RULE}${"─".repeat(tw - 1)}${RST}`);
158
135
  for (let i = 0; i < show.length; i++) {
@@ -169,7 +146,7 @@ export function registerReadTool(
169
146
  }
170
147
  out.push("");
171
148
  const rendered = out.join("\n");
172
- text.setText(fillToolBackground(rendered));
149
+ text.setText(fillToolBackground(rendered, BG_BASE));
173
150
  (ctx as any).state._rt = rendered;
174
151
 
175
152
  // Async syntax highlighting via Shiki
@@ -180,7 +157,7 @@ export function registerReadTool(
180
157
  .map((l) => `${TOOL_RESULT_INDENT}${l}`)
181
158
  .join("\n");
182
159
  const rendered = `\n${TOOL_RESULT_INDENT}${header}\n${padded}\n`;
183
- text.setText(fillToolBackground(rendered));
160
+ text.setText(fillToolBackground(rendered, BG_BASE));
184
161
  (ctx as any).state._rt = rendered;
185
162
  })
186
163
  .catch(() => {});
@@ -190,7 +167,10 @@ export function registerReadTool(
190
167
 
191
168
  const fc = result.content?.[0];
192
169
  text.setText(
193
- fillToolBackground(`${TOOL_RESULT_INDENT}${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
+ ),
194
174
  );
195
175
  return text;
196
176
  },
package/src/tui-text.ts CHANGED
@@ -1,56 +1,17 @@
1
- /**
2
- * Lazy resolver for pi-tui Text constructor.
3
- *
4
- * Returns the real Text class from @earendil-works/pi-tui, or a stub when
5
- * pi-tui is unavailable (e.g. not in jiti's alias map). This avoids crashing
6
- * during tool registration when pi-tui isn't aliased.
7
- *
8
- * The resolution is cached — the require() call happens at most once.
9
- */
1
+ import { Text } from "@earendil-works/pi-tui";
10
2
 
11
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
12
- type TextCtor = new (t?: string, x?: number, y?: number) => { setText(v: string): void; [k: string]: any };
3
+ type TextCtor = new (
4
+ text?: string,
5
+ paddingX?: number,
6
+ paddingY?: number,
7
+ ) => {
8
+ setText(value: string): void;
9
+ };
13
10
 
14
- /** No-op stub that satisfies the Text interface so rendering doesn't crash. */
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
- setText(_v: string): void {
21
- // no-op — pi-tui not available
22
- }
23
- }
24
-
25
- let _ctor: TextCtor | null = null;
26
- let _resolved = false;
27
-
28
- function resolve(): TextCtor {
29
- if (_resolved) return _ctor!;
30
- _resolved = true;
31
- try {
32
- // eslint-disable-next-line @typescript-eslint/no-var-requires
33
- const { Text } = require("@earendil-works/pi-tui") as { Text: TextCtor };
34
- _ctor = Text;
35
- return _ctor;
36
- } catch {
37
- _ctor = StubText;
38
- return _ctor;
39
- }
40
- }
41
-
42
- /**
43
- * Returns a Text constructor, always valid. Falls back to StubText if
44
- * @earendil-works/pi-tui is unavailable (caught and cached).
45
- */
46
11
  export function getTextCtor(): TextCtor {
47
- return resolve();
12
+ return Text;
48
13
  }
49
14
 
50
- /**
51
- * Returns TextComp if provided, otherwise the lazy-resolved Text constructor.
52
- * Always returns a valid constructor (never undefined/null).
53
- */
54
15
  export function resolveTextCtor(TextComp?: TextCtor): TextCtor {
55
- return TextComp ?? resolve();
16
+ return TextComp ?? Text;
56
17
  }
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
  // ---------------------------------------------------------------------------
@@ -120,14 +120,6 @@ export interface GrepInput {
120
120
  ignoreCase?: boolean;
121
121
  }
122
122
 
123
- export interface MultiGrepInput {
124
- patterns: string[];
125
- path?: string;
126
- constraints?: string;
127
- context?: number;
128
- limit?: number;
129
- }
130
-
131
123
  // ---------------------------------------------------------------------------
132
124
  // SDK tool definition shape (DI-friendly — accepts both mock and real SDK)
133
125
  // ---------------------------------------------------------------------------
@@ -153,29 +145,6 @@ export interface SdkTools {
153
145
  getAgentDir?: () => string;
154
146
  }
155
147
 
156
- // ---------------------------------------------------------------------------
157
- // Multi-grep fallback types
158
- // ---------------------------------------------------------------------------
159
-
160
- export interface MultiGrepFallbackParams {
161
- cwd: string;
162
- patterns: string[];
163
- path?: string;
164
- constraints?: string;
165
- context?: number;
166
- limit: number;
167
- ignoreCase: boolean;
168
- signal?: AbortSignal;
169
- }
170
-
171
- export interface MultiGrepFallbackResult {
172
- text: string;
173
- matchCount: number;
174
- limitReached: boolean;
175
- }
176
-
177
- export type MultiGrepFallback = (params: MultiGrepFallbackParams) => Promise<MultiGrepFallbackResult>;
178
-
179
148
  // ---------------------------------------------------------------------------
180
149
  // FFF service interfaces
181
150
  // ---------------------------------------------------------------------------
@@ -224,5 +193,4 @@ export interface PiPrettyDeps {
224
193
  sdk?: SdkTools;
225
194
  TextComponent?: new (text?: string, x?: number, y?: number) => ComponentLike;
226
195
  fffModule?: typeof import("@ff-labs/fff-node");
227
- multiGrepRipgrepFallback?: MultiGrepFallback;
228
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"}
@@ -1,205 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.parseMultiGrepConstraints = parseMultiGrepConstraints;
4
- exports.getMultiGrepRipgrepArgs = getMultiGrepRipgrepArgs;
5
- exports.runMultiGrepRipgrepFallback = runMultiGrepRipgrepFallback;
6
- const node_child_process_1 = require("node:child_process");
7
- const GLOB_META_RE = /[*?[{]/;
8
- function trimSlashes(value) {
9
- return value.replace(/^\/+/, "").replace(/\/+$/, "");
10
- }
11
- function normalizeConstraintPath(value) {
12
- let normalized = value.replace(/\\/g, "/").trim();
13
- while (normalized.startsWith("./"))
14
- normalized = normalized.slice(2);
15
- return normalized;
16
- }
17
- function tokenizeConstraints(constraints) {
18
- const tokens = [];
19
- let current = "";
20
- let quote = null;
21
- for (let i = 0; i < constraints.length; i++) {
22
- const char = constraints[i];
23
- if (quote) {
24
- if (char === quote)
25
- quote = null;
26
- else
27
- current += char;
28
- continue;
29
- }
30
- if (char === '"' || char === "'") {
31
- quote = char;
32
- continue;
33
- }
34
- if (/\s/.test(char)) {
35
- if (current) {
36
- tokens.push(current);
37
- current = "";
38
- }
39
- continue;
40
- }
41
- current += char;
42
- }
43
- if (quote)
44
- return { ok: false, error: "unterminated quoted constraint" };
45
- if (current)
46
- tokens.push(current);
47
- return { ok: true, globs: [], tokens };
48
- }
49
- function tokenToRipgrepGlob(token) {
50
- let negated = false;
51
- let body = token;
52
- if (body.startsWith("!")) {
53
- negated = true;
54
- body = body.slice(1);
55
- }
56
- body = normalizeConstraintPath(body);
57
- if (!body)
58
- return { ok: false, error: `empty constraint token: ${token}` };
59
- if (body.includes("\0"))
60
- return { ok: false, error: `invalid NUL byte in constraint token: ${token}` };
61
- let glob;
62
- if (body.endsWith("/")) {
63
- const dir = trimSlashes(body);
64
- if (!dir)
65
- return { ok: false, error: `empty directory constraint: ${token}` };
66
- glob = `**/${dir}/**`;
67
- }
68
- else if (GLOB_META_RE.test(body) || body.includes("/")) {
69
- glob = body.replace(/^\/+/, "");
70
- }
71
- else if (body.includes(".")) {
72
- glob = `**/${body}`;
73
- }
74
- else {
75
- glob = `**/${body}/**`;
76
- }
77
- return { ok: true, glob: negated ? `!${glob}` : glob };
78
- }
79
- function parseMultiGrepConstraints(constraints) {
80
- const trimmed = constraints?.trim();
81
- if (!trimmed)
82
- return { ok: true, globs: [], tokens: [] };
83
- const tokenized = tokenizeConstraints(trimmed);
84
- if (!tokenized.ok)
85
- return tokenized;
86
- const globs = [];
87
- for (const token of tokenized.tokens) {
88
- const parsed = tokenToRipgrepGlob(token);
89
- if (!parsed.ok)
90
- return parsed;
91
- globs.push(parsed.glob);
92
- }
93
- return { ok: true, globs, tokens: tokenized.tokens };
94
- }
95
- function isRipgrepMatchLine(line) {
96
- return /^.+?:\d+:/.test(line);
97
- }
98
- function buildRipgrepArgs(params, globs) {
99
- const args = ["--line-number", "--with-filename", "--color=never", "--hidden", "--fixed-strings"];
100
- if (params.ignoreCase)
101
- args.push("--ignore-case");
102
- if (params.context && params.context > 0)
103
- args.push("--context", String(params.context));
104
- for (const glob of globs)
105
- args.push("--glob", glob);
106
- for (const pattern of params.patterns)
107
- args.push("-e", pattern);
108
- const searchPath = params.path?.trim();
109
- if (searchPath)
110
- args.push("--", searchPath);
111
- return args;
112
- }
113
- function getMultiGrepRipgrepArgs(params) {
114
- const parsed = parseMultiGrepConstraints(params.constraints);
115
- if (!parsed.ok)
116
- return parsed;
117
- return { ...parsed, args: buildRipgrepArgs(params, parsed.globs) };
118
- }
119
- async function runMultiGrepRipgrepFallback(params) {
120
- const parsed = parseMultiGrepConstraints(params.constraints);
121
- if (!parsed.ok)
122
- throw new Error(`unsupported constraints: ${parsed.error}`);
123
- const args = buildRipgrepArgs(params, parsed.globs);
124
- return new Promise((resolve, reject) => {
125
- if (params.signal?.aborted) {
126
- reject(new Error("Operation aborted"));
127
- return;
128
- }
129
- const child = (0, node_child_process_1.spawn)("rg", args, { cwd: params.cwd, stdio: ["ignore", "pipe", "pipe"] });
130
- const outputLines = [];
131
- let stderr = "";
132
- let buffer = "";
133
- let matchCount = 0;
134
- let limitReached = false;
135
- let killedForLimit = false;
136
- let settled = false;
137
- const settle = (fn) => {
138
- if (settled)
139
- return;
140
- settled = true;
141
- fn();
142
- };
143
- const stopChild = (dueToLimit = false) => {
144
- if (!child.killed) {
145
- killedForLimit = dueToLimit;
146
- child.kill();
147
- }
148
- };
149
- const onAbort = () => stopChild(false);
150
- params.signal?.addEventListener("abort", onAbort, { once: true });
151
- const cleanup = () => {
152
- params.signal?.removeEventListener("abort", onAbort);
153
- };
154
- const handleLine = (line) => {
155
- if (limitReached)
156
- return;
157
- outputLines.push(line);
158
- if (isRipgrepMatchLine(line)) {
159
- matchCount++;
160
- if (matchCount >= params.limit) {
161
- limitReached = true;
162
- stopChild(true);
163
- }
164
- }
165
- };
166
- child.stdout?.on("data", (chunk) => {
167
- buffer += chunk.toString("utf8");
168
- let newlineIndex = buffer.indexOf("\n");
169
- while (newlineIndex >= 0) {
170
- const line = buffer.slice(0, newlineIndex).replace(/\r$/, "");
171
- buffer = buffer.slice(newlineIndex + 1);
172
- handleLine(line);
173
- newlineIndex = buffer.indexOf("\n");
174
- }
175
- });
176
- child.stderr?.on("data", (chunk) => {
177
- stderr += chunk.toString("utf8");
178
- });
179
- child.on("error", (error) => {
180
- cleanup();
181
- const message = error.code === "ENOENT" ? "ripgrep (rg) is not available" : `Failed to run ripgrep: ${error.message}`;
182
- settle(() => reject(new Error(message)));
183
- });
184
- child.on("close", (code) => {
185
- cleanup();
186
- if (params.signal?.aborted) {
187
- settle(() => reject(new Error("Operation aborted")));
188
- return;
189
- }
190
- if (buffer && !limitReached)
191
- handleLine(buffer.replace(/\r$/, ""));
192
- if (!killedForLimit && code !== 0 && code !== 1) {
193
- const message = stderr.trim() || `ripgrep exited with code ${code}`;
194
- settle(() => reject(new Error(message)));
195
- return;
196
- }
197
- settle(() => resolve({
198
- text: outputLines.length ? outputLines.join("\n") : "No matches found",
199
- matchCount,
200
- limitReached,
201
- }));
202
- });
203
- });
204
- }
205
- //# sourceMappingURL=multi-grep-fallback.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"multi-grep-fallback.js","sourceRoot":"","sources":["../src/multi-grep-fallback.ts"],"names":[],"mappings":"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"}
@@ -1,7 +0,0 @@
1
- import { type ExtensionAPI } from "@earendil-works/pi-coding-agent";
2
- import type { SdkToolDef, FffServiceWithCursor } from "../types.js";
3
- import type { MultiGrepFallback } from "../types.js";
4
- export declare function registerMultiGrepTool(pi: ExtensionAPI, cwd: string, fffService: FffServiceWithCursor | null | undefined, sdkGrepTool?: SdkToolDef, ripgrepFallback?: MultiGrepFallback, TextComp?: new (t?: string, x?: number, y?: number) => {
5
- setText(v: string): void;
6
- }): void;
7
- //# sourceMappingURL=multi-grep.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"multi-grep.d.ts","sourceRoot":"","sources":["../../src/tools/multi-grep.ts"],"names":[],"mappings":"AAEA,OAAO,EAEN,KAAK,YAAY,EAGjB,MAAM,iCAAiC,CAAC;AAEzC,OAAO,KAAK,EACX,UAAU,EAEV,oBAAoB,EAKpB,MAAM,aAAa,CAAC;AASrB,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AAUrD,wBAAgB,qBAAqB,CACpC,EAAE,EAAE,YAAY,EAChB,GAAG,EAAE,MAAM,EACX,UAAU,EAAE,oBAAoB,GAAG,IAAI,GAAG,SAAS,EACnD,WAAW,CAAC,EAAE,UAAU,EACxB,eAAe,GAAE,iBAAgC,EACjD,QAAQ,CAAC,EAAE,KAAK,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,CAAC,EAAE,MAAM,KAAK;IAAE,OAAO,CAAC,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;CAAE,GACjF,IAAI,CAwRN"}