codemaxxing 1.0.0 → 1.0.2

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 (47) hide show
  1. package/README.md +18 -12
  2. package/dist/agent.d.ts +4 -0
  3. package/dist/agent.js +91 -16
  4. package/dist/commands/git.d.ts +2 -0
  5. package/dist/commands/git.js +50 -0
  6. package/dist/commands/ollama.d.ts +27 -0
  7. package/dist/commands/ollama.js +171 -0
  8. package/dist/commands/output.d.ts +2 -0
  9. package/dist/commands/output.js +18 -0
  10. package/dist/commands/registry.d.ts +2 -0
  11. package/dist/commands/registry.js +8 -0
  12. package/dist/commands/skills.d.ts +18 -0
  13. package/dist/commands/skills.js +121 -0
  14. package/dist/commands/types.d.ts +5 -0
  15. package/dist/commands/types.js +1 -0
  16. package/dist/commands/ui.d.ts +16 -0
  17. package/dist/commands/ui.js +79 -0
  18. package/dist/config.d.ts +9 -0
  19. package/dist/config.js +13 -3
  20. package/dist/exec.js +4 -1
  21. package/dist/index.js +75 -401
  22. package/dist/tools/files.js +58 -3
  23. package/dist/utils/context.js +6 -0
  24. package/dist/utils/mcp.d.ts +7 -2
  25. package/dist/utils/mcp.js +34 -6
  26. package/package.json +8 -5
  27. package/src/agent.ts +0 -894
  28. package/src/auth-cli.ts +0 -287
  29. package/src/cli.ts +0 -37
  30. package/src/config.ts +0 -352
  31. package/src/exec.ts +0 -183
  32. package/src/index.tsx +0 -2647
  33. package/src/skills/registry.ts +0 -1436
  34. package/src/themes.ts +0 -335
  35. package/src/tools/files.ts +0 -374
  36. package/src/utils/auth.ts +0 -606
  37. package/src/utils/context.ts +0 -174
  38. package/src/utils/git.ts +0 -117
  39. package/src/utils/hardware.ts +0 -131
  40. package/src/utils/lint.ts +0 -116
  41. package/src/utils/mcp.ts +0 -307
  42. package/src/utils/models.ts +0 -218
  43. package/src/utils/ollama.ts +0 -352
  44. package/src/utils/repomap.ts +0 -220
  45. package/src/utils/sessions.ts +0 -254
  46. package/src/utils/skills.ts +0 -241
  47. package/tsconfig.json +0 -16
package/src/themes.ts DELETED
@@ -1,335 +0,0 @@
1
- export interface Theme {
2
- name: string;
3
- description: string;
4
- colors: {
5
- primary: string; // Main accent (borders, highlights)
6
- secondary: string; // Secondary accent (banner, headings)
7
- muted: string; // Dimmed text (hints, timestamps)
8
- text: string; // Normal text
9
- userInput: string; // User input text
10
- response: string; // AI response marker
11
- tool: string; // Tool call text
12
- toolResult: string; // Tool result text
13
- error: string; // Error messages
14
- success: string; // Success messages
15
- warning: string; // Warning/approval prompts
16
- spinner: string; // Spinner color
17
- border: string; // Border color
18
- suggestion: string; // Highlighted suggestion
19
- };
20
- }
21
-
22
- export const THEMES: Record<string, Theme> = {
23
- "cyberpunk-neon": {
24
- name: "Cyberpunk Neon",
25
- description: "Electric cyan & magenta — Night City terminal",
26
- colors: {
27
- primary: "#00FFFF",
28
- secondary: "#FF00FF",
29
- muted: "#008B8B",
30
- text: "",
31
- userInput: "#008B8B",
32
- response: "#00FFFF",
33
- tool: "#FF00FF",
34
- toolResult: "#008B8B",
35
- error: "red",
36
- success: "#00FF00",
37
- warning: "#FF8C00",
38
- spinner: "#00FFFF",
39
- border: "#00FFFF",
40
- suggestion: "#FF00FF",
41
- },
42
- },
43
- dracula: {
44
- name: "Dracula",
45
- description: "Dark purple tones",
46
- colors: {
47
- primary: "#BD93F9",
48
- secondary: "#FF79C6",
49
- muted: "#6272A4",
50
- text: "#F8F8F2",
51
- userInput: "#8BE9FD",
52
- response: "#BD93F9",
53
- tool: "#FF79C6",
54
- toolResult: "#6272A4",
55
- error: "#FF5555",
56
- success: "#50FA7B",
57
- warning: "#FFB86C",
58
- spinner: "#BD93F9",
59
- border: "#BD93F9",
60
- suggestion: "#FF79C6",
61
- },
62
- },
63
- gruvbox: {
64
- name: "Gruvbox",
65
- description: "Warm retro tones",
66
- colors: {
67
- primary: "#FE8019",
68
- secondary: "#FABD2F",
69
- muted: "#928374",
70
- text: "#EBDBB2",
71
- userInput: "#83A598",
72
- response: "#FE8019",
73
- tool: "#FABD2F",
74
- toolResult: "#928374",
75
- error: "#FB4934",
76
- success: "#B8BB26",
77
- warning: "#FABD2F",
78
- spinner: "#FE8019",
79
- border: "#FE8019",
80
- suggestion: "#FABD2F",
81
- },
82
- },
83
- nord: {
84
- name: "Nord",
85
- description: "Cool arctic blues",
86
- colors: {
87
- primary: "#88C0D0",
88
- secondary: "#81A1C1",
89
- muted: "#4C566A",
90
- text: "#ECEFF4",
91
- userInput: "#88C0D0",
92
- response: "#81A1C1",
93
- tool: "#5E81AC",
94
- toolResult: "#4C566A",
95
- error: "#BF616A",
96
- success: "#A3BE8C",
97
- warning: "#EBCB8B",
98
- spinner: "#88C0D0",
99
- border: "#81A1C1",
100
- suggestion: "#88C0D0",
101
- },
102
- },
103
- mono: {
104
- name: "Mono",
105
- description: "Clean monochrome — easy on the eyes",
106
- colors: {
107
- primary: "#AAAAAA",
108
- secondary: "#FFFFFF",
109
- muted: "#666666",
110
- text: "#CCCCCC",
111
- userInput: "#AAAAAA",
112
- response: "#FFFFFF",
113
- tool: "#CCCCCC",
114
- toolResult: "#666666",
115
- error: "#FF6666",
116
- success: "#66FF66",
117
- warning: "#FFAA66",
118
- spinner: "#AAAAAA",
119
- border: "#888888",
120
- suggestion: "#FFFFFF",
121
- },
122
- },
123
- solarized: {
124
- name: "Solarized",
125
- description: "Solarized dark",
126
- colors: {
127
- primary: "#268BD2",
128
- secondary: "#2AA198",
129
- muted: "#586E75",
130
- text: "#839496",
131
- userInput: "#2AA198",
132
- response: "#268BD2",
133
- tool: "#B58900",
134
- toolResult: "#586E75",
135
- error: "#DC322F",
136
- success: "#859900",
137
- warning: "#CB4B16",
138
- spinner: "#268BD2",
139
- border: "#268BD2",
140
- suggestion: "#2AA198",
141
- },
142
- },
143
- hacker: {
144
- name: "Hacker",
145
- description: "Green on black — classic terminal",
146
- colors: {
147
- primary: "#00FF00",
148
- secondary: "#00CC00",
149
- muted: "#006600",
150
- text: "#00DD00",
151
- userInput: "#00FF00",
152
- response: "#00FF00",
153
- tool: "#00CC00",
154
- toolResult: "#006600",
155
- error: "#FF0000",
156
- success: "#00FF00",
157
- warning: "#FFFF00",
158
- spinner: "#00FF00",
159
- border: "#00FF00",
160
- suggestion: "#00CC00",
161
- },
162
- },
163
- catppuccin: {
164
- name: "Catppuccin",
165
- description: "Soothing pastel — Mocha flavor",
166
- colors: {
167
- primary: "#CBA6F7",
168
- secondary: "#F5C2E7",
169
- muted: "#6C7086",
170
- text: "#CDD6F4",
171
- userInput: "#89DCEB",
172
- response: "#CBA6F7",
173
- tool: "#F5C2E7",
174
- toolResult: "#6C7086",
175
- error: "#F38BA8",
176
- success: "#A6E3A1",
177
- warning: "#FAB387",
178
- spinner: "#CBA6F7",
179
- border: "#CBA6F7",
180
- suggestion: "#F5C2E7",
181
- },
182
- },
183
- "tokyo-night": {
184
- name: "Tokyo Night",
185
- description: "Rain-soaked Shibuya — neon signs in the dark",
186
- colors: {
187
- primary: "#FF7AC6",
188
- secondary: "#7DCFFF",
189
- muted: "#3B4261",
190
- text: "#A9B1D6",
191
- userInput: "#FF9E64",
192
- response: "#FF7AC6",
193
- tool: "#7DCFFF",
194
- toolResult: "#3B4261",
195
- error: "#F7768E",
196
- success: "#73DACA",
197
- warning: "#FF9E64",
198
- spinner: "#FF7AC6",
199
- border: "#FF7AC6",
200
- suggestion: "#7DCFFF",
201
- },
202
- },
203
- "one-dark": {
204
- name: "One Dark",
205
- description: "Atom editor classic",
206
- colors: {
207
- primary: "#61AFEF",
208
- secondary: "#C678DD",
209
- muted: "#5C6370",
210
- text: "#ABB2BF",
211
- userInput: "#56B6C2",
212
- response: "#61AFEF",
213
- tool: "#C678DD",
214
- toolResult: "#5C6370",
215
- error: "#E06C75",
216
- success: "#98C379",
217
- warning: "#E5C07B",
218
- spinner: "#61AFEF",
219
- border: "#61AFEF",
220
- suggestion: "#C678DD",
221
- },
222
- },
223
- "rose-pine": {
224
- name: "Rosé Pine",
225
- description: "Elegant dark florals",
226
- colors: {
227
- primary: "#EBBCBA",
228
- secondary: "#C4A7E7",
229
- muted: "#6E6A86",
230
- text: "#E0DEF4",
231
- userInput: "#9CCFD8",
232
- response: "#EBBCBA",
233
- tool: "#C4A7E7",
234
- toolResult: "#6E6A86",
235
- error: "#EB6F92",
236
- success: "#31748F",
237
- warning: "#F6C177",
238
- spinner: "#EBBCBA",
239
- border: "#EBBCBA",
240
- suggestion: "#C4A7E7",
241
- },
242
- },
243
-
244
- synthwave: {
245
- name: "Synthwave",
246
- description: "Retro 80s sunset — outrun aesthetics",
247
- colors: {
248
- primary: "#F92AAD",
249
- secondary: "#E9F501",
250
- muted: "#614D85",
251
- text: "#F4EEFF",
252
- userInput: "#36F9F6",
253
- response: "#F92AAD",
254
- tool: "#E9F501",
255
- toolResult: "#614D85",
256
- error: "#FE4450",
257
- success: "#72F1B8",
258
- warning: "#FF7F11",
259
- spinner: "#F92AAD",
260
- border: "#F92AAD",
261
- suggestion: "#36F9F6",
262
- },
263
- },
264
- "blood-moon": {
265
- name: "Blood Moon",
266
- description: "Dark crimson — for the night coders",
267
- colors: {
268
- primary: "#FF4444",
269
- secondary: "#CC2936",
270
- muted: "#5C2626",
271
- text: "#E0C4C4",
272
- userInput: "#FF6B6B",
273
- response: "#FF4444",
274
- tool: "#CC2936",
275
- toolResult: "#5C2626",
276
- error: "#FF0000",
277
- success: "#4CAF50",
278
- warning: "#FF8C00",
279
- spinner: "#FF4444",
280
- border: "#FF4444",
281
- suggestion: "#CC2936",
282
- },
283
- },
284
-
285
- "hot-dog": {
286
- name: "Hot Dog",
287
- description: "Cursed ketchup & mustard — you asked for it",
288
- colors: {
289
- primary: "#FF0000",
290
- secondary: "#FFFF00",
291
- muted: "#AA6600",
292
- text: "#FFFF00",
293
- userInput: "#FF0000",
294
- response: "#FFFF00",
295
- tool: "#FF6600",
296
- toolResult: "#AA6600",
297
- error: "#FF0000",
298
- success: "#00FF00",
299
- warning: "#FFFF00",
300
- spinner: "#FF0000",
301
- border: "#FF0000",
302
- suggestion: "#FFFF00",
303
- },
304
- },
305
- acid: {
306
- name: "Acid",
307
- description: "Every color at once — sensory overload",
308
- colors: {
309
- primary: "#FF00FF",
310
- secondary: "#00FF88",
311
- muted: "#FF6B00",
312
- text: "#FFFF00",
313
- userInput: "#00FFFF",
314
- response: "#FF3399",
315
- tool: "#33FF00",
316
- toolResult: "#FF6B00",
317
- error: "#FF0044",
318
- success: "#00FF66",
319
- warning: "#FFD700",
320
- spinner: "#BF00FF",
321
- border: "#FF00AA",
322
- suggestion: "#00FFCC",
323
- },
324
- },
325
- };
326
-
327
- export const DEFAULT_THEME = "nord";
328
-
329
- export function getTheme(name: string): Theme {
330
- return THEMES[name] ?? THEMES[DEFAULT_THEME];
331
- }
332
-
333
- export function listThemes(): string[] {
334
- return Object.keys(THEMES);
335
- }
@@ -1,374 +0,0 @@
1
- import { readFileSync, writeFileSync, existsSync, readdirSync, statSync } from "fs";
2
- import { join, relative } from "path";
3
- import type { ChatCompletionTool } from "openai/resources/chat/completions";
4
-
5
- /**
6
- * Tool definitions for the OpenAI function calling API
7
- */
8
- export const FILE_TOOLS: ChatCompletionTool[] = [
9
- {
10
- type: "function",
11
- function: {
12
- name: "read_file",
13
- description: "Read the contents of a file at the given path",
14
- parameters: {
15
- type: "object",
16
- properties: {
17
- path: {
18
- type: "string",
19
- description: "Path to the file to read (relative to project root)",
20
- },
21
- },
22
- required: ["path"],
23
- },
24
- },
25
- },
26
- {
27
- type: "function",
28
- function: {
29
- name: "write_file",
30
- description:
31
- "Write content to a file. Creates the file if it doesn't exist, overwrites if it does.",
32
- parameters: {
33
- type: "object",
34
- properties: {
35
- path: {
36
- type: "string",
37
- description: "Path to the file to write (relative to project root)",
38
- },
39
- content: {
40
- type: "string",
41
- description: "Content to write to the file",
42
- },
43
- },
44
- required: ["path", "content"],
45
- },
46
- },
47
- },
48
- {
49
- type: "function",
50
- function: {
51
- name: "list_files",
52
- description:
53
- "List files and directories in the given path. Returns file names and types.",
54
- parameters: {
55
- type: "object",
56
- properties: {
57
- path: {
58
- type: "string",
59
- description:
60
- "Directory path to list (relative to project root, defaults to '.')",
61
- },
62
- recursive: {
63
- type: "boolean",
64
- description: "Whether to list files recursively (default: false)",
65
- },
66
- },
67
- },
68
- },
69
- },
70
- {
71
- type: "function",
72
- function: {
73
- name: "search_files",
74
- description: "Search for a text pattern across files in the project",
75
- parameters: {
76
- type: "object",
77
- properties: {
78
- pattern: {
79
- type: "string",
80
- description: "Text or regex pattern to search for",
81
- },
82
- path: {
83
- type: "string",
84
- description: "Directory to search in (defaults to project root)",
85
- },
86
- },
87
- required: ["pattern"],
88
- },
89
- },
90
- },
91
- {
92
- type: "function",
93
- function: {
94
- name: "run_command",
95
- description:
96
- "Execute a shell command and return the output. Use for running tests, builds, linters, etc.",
97
- parameters: {
98
- type: "object",
99
- properties: {
100
- command: {
101
- type: "string",
102
- description: "Shell command to execute",
103
- },
104
- },
105
- required: ["command"],
106
- },
107
- },
108
- },
109
- ];
110
-
111
- /**
112
- * Execute a tool call and return the result
113
- */
114
- export async function executeTool(
115
- name: string,
116
- args: Record<string, unknown>,
117
- cwd: string
118
- ): Promise<string> {
119
- switch (name) {
120
- case "read_file": {
121
- const filePath = join(cwd, args.path as string);
122
- if (!existsSync(filePath)) return `Error: File not found: ${args.path}`;
123
- try {
124
- return readFileSync(filePath, "utf-8");
125
- } catch (e) {
126
- return `Error reading file: ${e}`;
127
- }
128
- }
129
-
130
- case "write_file": {
131
- const filePath = join(cwd, args.path as string);
132
- try {
133
- writeFileSync(filePath, args.content as string, "utf-8");
134
- return `✅ Wrote ${(args.content as string).length} bytes to ${args.path}`;
135
- } catch (e) {
136
- return `Error writing file: ${e}`;
137
- }
138
- }
139
-
140
- case "list_files": {
141
- const dirPath = join(cwd, (args.path as string) || ".");
142
- if (!existsSync(dirPath)) return `Error: Directory not found: ${args.path}`;
143
- try {
144
- const entries = listDir(dirPath, cwd, args.recursive as boolean);
145
- return entries.join("\n");
146
- } catch (e) {
147
- return `Error listing files: ${e}`;
148
- }
149
- }
150
-
151
- case "search_files": {
152
- const searchPath = join(cwd, (args.path as string) || ".");
153
- try {
154
- return searchInFiles(searchPath, args.pattern as string, cwd);
155
- } catch (e) {
156
- return `Error searching: ${e}`;
157
- }
158
- }
159
-
160
- case "run_command": {
161
- try {
162
- const { execSync } = await import("child_process");
163
- const output = execSync(args.command as string, {
164
- cwd,
165
- encoding: "utf-8",
166
- timeout: 30000,
167
- maxBuffer: 1024 * 1024,
168
- });
169
- return output || "(no output)";
170
- } catch (e: any) {
171
- return `Command failed: ${e.stderr || e.message}`;
172
- }
173
- }
174
-
175
- default:
176
- return `Unknown tool: ${name}`;
177
- }
178
- }
179
-
180
- /**
181
- * Generate a simple unified diff between two strings
182
- */
183
- export function generateDiff(oldContent: string, newContent: string, filePath: string): string {
184
- const oldLines = oldContent.split("\n");
185
- const newLines = newContent.split("\n");
186
- const output: string[] = [`--- a/${filePath}`, `+++ b/${filePath}`];
187
-
188
- const lcs = computeLCS(oldLines, newLines);
189
-
190
- let oi = 0, ni = 0, li = 0;
191
- let hunkLines: string[] = [];
192
- let hunkOldCount = 0;
193
- let hunkNewCount = 0;
194
- let hunkStartOld = 1;
195
- let hunkStartNew = 1;
196
- let pendingContext: string[] = [];
197
- let hasHunk = false;
198
-
199
- function flushHunk() {
200
- if (hasHunk && hunkLines.length > 0) {
201
- output.push(`@@ -${hunkStartOld},${hunkOldCount} +${hunkStartNew},${hunkNewCount} @@`);
202
- output.push(...hunkLines);
203
- }
204
- hunkLines = [];
205
- hunkOldCount = 0;
206
- hunkNewCount = 0;
207
- hasHunk = false;
208
- pendingContext = [];
209
- }
210
-
211
- function startHunk() {
212
- if (!hasHunk) {
213
- hasHunk = true;
214
- hunkStartOld = Math.max(1, oi + 1 - 3);
215
- hunkStartNew = Math.max(1, ni + 1 - 3);
216
- const contextStart = Math.max(0, oi - 3);
217
- for (let c = contextStart; c < oi; c++) {
218
- hunkLines.push(` ${oldLines[c]}`);
219
- hunkOldCount++;
220
- hunkNewCount++;
221
- }
222
- }
223
- if (pendingContext.length > 0) {
224
- hunkLines.push(...pendingContext);
225
- pendingContext = [];
226
- }
227
- }
228
-
229
- while (oi < oldLines.length || ni < newLines.length) {
230
- if (li < lcs.length && oi < oldLines.length && ni < newLines.length &&
231
- oldLines[oi] === lcs[li] && newLines[ni] === lcs[li]) {
232
- // Matching line
233
- if (hasHunk) {
234
- pendingContext.push(` ${oldLines[oi]}`);
235
- hunkOldCount++;
236
- hunkNewCount++;
237
- if (pendingContext.length > 6) flushHunk();
238
- }
239
- oi++; ni++; li++;
240
- } else if (oi < oldLines.length && (li >= lcs.length || oldLines[oi] !== lcs[li])) {
241
- startHunk();
242
- hunkLines.push(`-${oldLines[oi]}`);
243
- hunkOldCount++;
244
- oi++;
245
- } else if (ni < newLines.length && (li >= lcs.length || newLines[ni] !== lcs[li])) {
246
- startHunk();
247
- hunkLines.push(`+${newLines[ni]}`);
248
- hunkNewCount++;
249
- ni++;
250
- } else {
251
- break;
252
- }
253
- }
254
-
255
- flushHunk();
256
-
257
- if (output.length <= 2) return "(no changes)";
258
-
259
- const maxDiffLines = 60;
260
- if (output.length > maxDiffLines + 2) {
261
- return output.slice(0, maxDiffLines + 2).join("\n") + `\n... (${output.length - maxDiffLines - 2} more lines)`;
262
- }
263
- return output.join("\n");
264
- }
265
-
266
- function computeLCS(a: string[], b: string[]): string[] {
267
- if (a.length > 500 || b.length > 500) {
268
- // For large files, just return common lines in order
269
- const result: string[] = [];
270
- let bi = 0;
271
- for (const line of a) {
272
- while (bi < b.length && b[bi] !== line) bi++;
273
- if (bi < b.length) { result.push(line); bi++; }
274
- }
275
- return result;
276
- }
277
- const m = a.length, n = b.length;
278
- const dp: number[][] = Array.from({ length: m + 1 }, () => new Array(n + 1).fill(0));
279
- for (let i = 1; i <= m; i++) {
280
- for (let j = 1; j <= n; j++) {
281
- dp[i][j] = a[i - 1] === b[j - 1] ? dp[i - 1][j - 1] + 1 : Math.max(dp[i - 1][j], dp[i][j - 1]);
282
- }
283
- }
284
- const result: string[] = [];
285
- let i = m, j = n;
286
- while (i > 0 && j > 0) {
287
- if (a[i - 1] === b[j - 1]) { result.unshift(a[i - 1]); i--; j--; }
288
- else if (dp[i - 1][j] > dp[i][j - 1]) { i--; }
289
- else { j--; }
290
- }
291
- return result;
292
- }
293
-
294
- /**
295
- * Get existing file content for diff preview (returns null if file doesn't exist)
296
- */
297
- export function getExistingContent(filePath: string, cwd: string): string | null {
298
- const fullPath = join(cwd, filePath);
299
- if (!existsSync(fullPath)) return null;
300
- try {
301
- return readFileSync(fullPath, "utf-8");
302
- } catch {
303
- return null;
304
- }
305
- }
306
-
307
- function listDir(
308
- dirPath: string,
309
- cwd: string,
310
- recursive: boolean = false,
311
- depth: number = 0
312
- ): string[] {
313
- const entries: string[] = [];
314
- const IGNORE = ["node_modules", ".git", "dist", ".next", "__pycache__"];
315
-
316
- for (const entry of readdirSync(dirPath)) {
317
- if (IGNORE.includes(entry)) continue;
318
- const fullPath = join(dirPath, entry);
319
- const rel = relative(cwd, fullPath);
320
- const stat = statSync(fullPath);
321
- const prefix = " ".repeat(depth);
322
-
323
- if (stat.isDirectory()) {
324
- entries.push(`${prefix}📁 ${rel}/`);
325
- if (recursive && depth < 3) {
326
- entries.push(...listDir(fullPath, cwd, true, depth + 1));
327
- }
328
- } else {
329
- const size = stat.size > 1024 ? `${(stat.size / 1024).toFixed(1)}KB` : `${stat.size}B`;
330
- entries.push(`${prefix}📄 ${rel} (${size})`);
331
- }
332
- }
333
- return entries;
334
- }
335
-
336
- function searchInFiles(
337
- dirPath: string,
338
- pattern: string,
339
- cwd: string
340
- ): string {
341
- const results: string[] = [];
342
- const IGNORE = ["node_modules", ".git", "dist", ".next", "__pycache__"];
343
- const regex = new RegExp(pattern, "gi");
344
-
345
- function search(dir: string) {
346
- for (const entry of readdirSync(dir)) {
347
- if (IGNORE.includes(entry)) continue;
348
- const fullPath = join(dir, entry);
349
- const stat = statSync(fullPath);
350
-
351
- if (stat.isDirectory()) {
352
- search(fullPath);
353
- } else if (stat.size < 100000) {
354
- try {
355
- const content = readFileSync(fullPath, "utf-8");
356
- const lines = content.split("\n");
357
- for (let i = 0; i < lines.length; i++) {
358
- if (regex.test(lines[i])) {
359
- results.push(`${relative(cwd, fullPath)}:${i + 1}: ${lines[i].trim()}`);
360
- }
361
- regex.lastIndex = 0;
362
- }
363
- } catch {
364
- // skip binary files
365
- }
366
- }
367
- }
368
- }
369
-
370
- search(dirPath);
371
- return results.length > 0
372
- ? results.slice(0, 50).join("\n")
373
- : "No matches found.";
374
- }