@stan-chen/simple-cli 0.2.3 → 0.2.4

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 (136) hide show
  1. package/README.md +62 -63
  2. package/dist/anyllm.py +62 -0
  3. package/dist/builtins.d.ts +726 -0
  4. package/dist/builtins.js +481 -0
  5. package/dist/cli.d.ts +0 -4
  6. package/dist/cli.js +34 -493
  7. package/dist/engine.d.ts +33 -0
  8. package/dist/engine.js +138 -0
  9. package/dist/learnings.d.ts +15 -0
  10. package/dist/learnings.js +54 -0
  11. package/dist/llm.d.ts +18 -0
  12. package/dist/llm.js +66 -0
  13. package/dist/mcp.d.ts +132 -0
  14. package/dist/mcp.js +43 -0
  15. package/dist/skills.d.ts +5 -16
  16. package/dist/skills.js +91 -253
  17. package/dist/tui.d.ts +1 -0
  18. package/dist/tui.js +10 -0
  19. package/package.json +10 -6
  20. package/dist/claw/jit.d.ts +0 -5
  21. package/dist/claw/jit.js +0 -138
  22. package/dist/claw/management.d.ts +0 -3
  23. package/dist/claw/management.js +0 -107
  24. package/dist/commands/add.d.ts +0 -9
  25. package/dist/commands/add.js +0 -50
  26. package/dist/commands/git/commit.d.ts +0 -12
  27. package/dist/commands/git/commit.js +0 -98
  28. package/dist/commands/git/status.d.ts +0 -6
  29. package/dist/commands/git/status.js +0 -42
  30. package/dist/commands/index.d.ts +0 -16
  31. package/dist/commands/index.js +0 -377
  32. package/dist/commands/mcp/status.d.ts +0 -6
  33. package/dist/commands/mcp/status.js +0 -31
  34. package/dist/commands/swarm.d.ts +0 -36
  35. package/dist/commands/swarm.js +0 -236
  36. package/dist/commands.d.ts +0 -32
  37. package/dist/commands.js +0 -427
  38. package/dist/context.d.ts +0 -116
  39. package/dist/context.js +0 -337
  40. package/dist/index.d.ts +0 -6
  41. package/dist/index.js +0 -109
  42. package/dist/lib/agent.d.ts +0 -99
  43. package/dist/lib/agent.js +0 -313
  44. package/dist/lib/editor.d.ts +0 -74
  45. package/dist/lib/editor.js +0 -441
  46. package/dist/lib/git.d.ts +0 -164
  47. package/dist/lib/git.js +0 -356
  48. package/dist/lib/shim.d.ts +0 -4
  49. package/dist/lib/shim.js +0 -30
  50. package/dist/lib/ui.d.ts +0 -159
  51. package/dist/lib/ui.js +0 -277
  52. package/dist/mcp/client.d.ts +0 -22
  53. package/dist/mcp/client.js +0 -81
  54. package/dist/mcp/manager.d.ts +0 -186
  55. package/dist/mcp/manager.js +0 -446
  56. package/dist/prompts/provider.d.ts +0 -22
  57. package/dist/prompts/provider.js +0 -79
  58. package/dist/providers/index.d.ts +0 -31
  59. package/dist/providers/index.js +0 -93
  60. package/dist/providers/multi.d.ts +0 -12
  61. package/dist/providers/multi.js +0 -28
  62. package/dist/registry.d.ts +0 -29
  63. package/dist/registry.js +0 -443
  64. package/dist/repoMap.d.ts +0 -5
  65. package/dist/repoMap.js +0 -79
  66. package/dist/router.d.ts +0 -41
  67. package/dist/router.js +0 -118
  68. package/dist/swarm/coordinator.d.ts +0 -86
  69. package/dist/swarm/coordinator.js +0 -257
  70. package/dist/swarm/index.d.ts +0 -28
  71. package/dist/swarm/index.js +0 -29
  72. package/dist/swarm/task.d.ts +0 -104
  73. package/dist/swarm/task.js +0 -221
  74. package/dist/swarm/types.d.ts +0 -132
  75. package/dist/swarm/types.js +0 -37
  76. package/dist/swarm/worker.d.ts +0 -109
  77. package/dist/swarm/worker.js +0 -369
  78. package/dist/tools/analyzeFile.d.ts +0 -16
  79. package/dist/tools/analyzeFile.js +0 -43
  80. package/dist/tools/analyze_file.d.ts +0 -16
  81. package/dist/tools/analyze_file.js +0 -43
  82. package/dist/tools/clawBrain.d.ts +0 -23
  83. package/dist/tools/clawBrain.js +0 -136
  84. package/dist/tools/claw_brain.d.ts +0 -23
  85. package/dist/tools/claw_brain.js +0 -139
  86. package/dist/tools/deleteFile.d.ts +0 -19
  87. package/dist/tools/deleteFile.js +0 -36
  88. package/dist/tools/delete_file.d.ts +0 -19
  89. package/dist/tools/delete_file.js +0 -36
  90. package/dist/tools/fileOps.d.ts +0 -22
  91. package/dist/tools/fileOps.js +0 -43
  92. package/dist/tools/file_ops.d.ts +0 -22
  93. package/dist/tools/file_ops.js +0 -43
  94. package/dist/tools/git.d.ts +0 -40
  95. package/dist/tools/git.js +0 -236
  96. package/dist/tools/glob.d.ts +0 -34
  97. package/dist/tools/glob.js +0 -165
  98. package/dist/tools/grep.d.ts +0 -53
  99. package/dist/tools/grep.js +0 -296
  100. package/dist/tools/linter.d.ts +0 -35
  101. package/dist/tools/linter.js +0 -407
  102. package/dist/tools/listDir.d.ts +0 -29
  103. package/dist/tools/listDir.js +0 -50
  104. package/dist/tools/list_dir.d.ts +0 -29
  105. package/dist/tools/list_dir.js +0 -50
  106. package/dist/tools/memory.d.ts +0 -34
  107. package/dist/tools/memory.js +0 -215
  108. package/dist/tools/organizer.d.ts +0 -1
  109. package/dist/tools/organizer.js +0 -65
  110. package/dist/tools/readFiles.d.ts +0 -25
  111. package/dist/tools/readFiles.js +0 -31
  112. package/dist/tools/read_files.d.ts +0 -25
  113. package/dist/tools/read_files.js +0 -31
  114. package/dist/tools/reloadTools.d.ts +0 -11
  115. package/dist/tools/reloadTools.js +0 -22
  116. package/dist/tools/reload_tools.d.ts +0 -11
  117. package/dist/tools/reload_tools.js +0 -22
  118. package/dist/tools/runCommand.d.ts +0 -32
  119. package/dist/tools/runCommand.js +0 -79
  120. package/dist/tools/run_command.d.ts +0 -32
  121. package/dist/tools/run_command.js +0 -103
  122. package/dist/tools/scheduler.d.ts +0 -25
  123. package/dist/tools/scheduler.js +0 -65
  124. package/dist/tools/scraper.d.ts +0 -31
  125. package/dist/tools/scraper.js +0 -211
  126. package/dist/tools/writeFiles.d.ts +0 -63
  127. package/dist/tools/writeFiles.js +0 -87
  128. package/dist/tools/write_files.d.ts +0 -84
  129. package/dist/tools/write_files.js +0 -91
  130. package/dist/tools/write_to_file.d.ts +0 -15
  131. package/dist/tools/write_to_file.js +0 -21
  132. package/dist/ui/server.d.ts +0 -5
  133. package/dist/ui/server.js +0 -74
  134. package/dist/watcher.d.ts +0 -35
  135. package/dist/watcher.js +0 -164
  136. /package/{docs/assets → assets}/logo.jpeg +0 -0
@@ -1,34 +0,0 @@
1
- /**
2
- * Glob Tool - Find files matching patterns
3
- * Uses fast-glob for reliable glob matching (with fallback)
4
- */
5
- import { z } from 'zod';
6
- import type { Tool } from '../registry.js';
7
- export declare const inputSchema: z.ZodObject<{
8
- pattern: z.ZodString;
9
- cwd: z.ZodOptional<z.ZodString>;
10
- maxResults: z.ZodDefault<z.ZodOptional<z.ZodNumber>>;
11
- includeDirectories: z.ZodDefault<z.ZodOptional<z.ZodBoolean>>;
12
- ignore: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
13
- }, "strip", z.ZodTypeAny, {
14
- pattern: string;
15
- maxResults: number;
16
- includeDirectories: boolean;
17
- ignore?: string[] | undefined;
18
- cwd?: string | undefined;
19
- }, {
20
- pattern: string;
21
- ignore?: string[] | undefined;
22
- cwd?: string | undefined;
23
- maxResults?: number | undefined;
24
- includeDirectories?: boolean | undefined;
25
- }>;
26
- type GlobInput = z.infer<typeof inputSchema>;
27
- export declare function execute(input: GlobInput): Promise<{
28
- pattern: string;
29
- matches: string[];
30
- count: number;
31
- truncated: boolean;
32
- }>;
33
- export declare const tool: Tool;
34
- export {};
@@ -1,165 +0,0 @@
1
- /**
2
- * Glob Tool - Find files matching patterns
3
- * Uses fast-glob for reliable glob matching (with fallback)
4
- */
5
- import { z } from 'zod';
6
- import { readdir } from 'fs/promises';
7
- import { join, relative } from 'path';
8
- // Input schema
9
- export const inputSchema = z.object({
10
- pattern: z.string().describe('Glob pattern to match files (e.g., "**/*.ts", "src/**/*.js")'),
11
- cwd: z.string().optional().describe('Working directory to search in'),
12
- maxResults: z.number().optional().default(100).describe('Maximum number of results'),
13
- includeDirectories: z.boolean().optional().default(false).describe('Include directories in results'),
14
- ignore: z.array(z.string()).optional().describe('Patterns to ignore'),
15
- });
16
- // Default ignore patterns
17
- const DEFAULT_IGNORE = [
18
- '**/node_modules/**',
19
- '**/.git/**',
20
- '**/.svn/**',
21
- '**/.hg/**',
22
- '**/dist/**',
23
- '**/build/**',
24
- '**/coverage/**',
25
- '**/.next/**',
26
- '**/.nuxt/**',
27
- '**/__pycache__/**',
28
- '**/.pytest_cache/**',
29
- '**/venv/**',
30
- '**/.venv/**',
31
- '**/env/**',
32
- '**/.env',
33
- '**/.idea/**',
34
- '**/.vscode/**',
35
- '**/*.pyc',
36
- '**/*.pyo',
37
- '**/.DS_Store',
38
- '**/Thumbs.db',
39
- ];
40
- // Simple ignore patterns for fallback (directory names)
41
- const FALLBACK_IGNORE = [
42
- 'node_modules', '.git', '.svn', '.hg', 'dist', 'build', 'coverage',
43
- '.next', '.nuxt', '__pycache__', '.pytest_cache', 'venv', '.venv',
44
- 'env', '.idea', '.vscode',
45
- ];
46
- // Cached fast-glob instance (typed as any to handle missing module)
47
- let fastGlob = null;
48
- let fgLoaded = false;
49
- async function loadFastGlob() {
50
- if (!fgLoaded) {
51
- fgLoaded = true;
52
- try {
53
- fastGlob = (await import('fast-glob')).default;
54
- }
55
- catch {
56
- // fast-glob not installed
57
- }
58
- }
59
- return fastGlob;
60
- }
61
- // Convert glob pattern to regex (for fallback)
62
- function globToRegex(pattern) {
63
- let prefix = '';
64
- let workPattern = pattern;
65
- if (pattern.startsWith('**/')) {
66
- prefix = '(?:^|.*/)?';
67
- workPattern = pattern.slice(3);
68
- }
69
- let regex = workPattern
70
- .replace(/[.+^${}()|[\]\\]/g, '\\$&')
71
- .replace(/\*\*/g, '.*')
72
- .replace(/\*/g, '[^/]*')
73
- .replace(/\?/g, '[^/]');
74
- return new RegExp(`${prefix}${regex}$`, 'i');
75
- }
76
- // Fallback: recursive file finder
77
- async function findFilesFallback(dir, pattern, options, results = []) {
78
- if (results.length >= options.maxResults)
79
- return results;
80
- try {
81
- const entries = await readdir(dir, { withFileTypes: true });
82
- for (const entry of entries) {
83
- if (results.length >= options.maxResults)
84
- break;
85
- // Check ignore
86
- if (options.ignorePatterns.includes(entry.name))
87
- continue;
88
- if (entry.name.startsWith('.'))
89
- continue;
90
- const fullPath = join(dir, entry.name);
91
- const relativePath = relative(options.baseDir, fullPath);
92
- if (entry.isDirectory()) {
93
- if (options.includeDirectories && pattern.test(relativePath)) {
94
- results.push(relativePath);
95
- }
96
- await findFilesFallback(fullPath, pattern, options, results);
97
- }
98
- else if (entry.isFile()) {
99
- if (pattern.test(relativePath)) {
100
- results.push(relativePath);
101
- }
102
- }
103
- }
104
- }
105
- catch {
106
- // Ignore permission errors
107
- }
108
- return results;
109
- }
110
- // Execute glob search
111
- export async function execute(input) {
112
- const { pattern, cwd = process.cwd(), maxResults, includeDirectories, ignore = [], } = inputSchema.parse(input);
113
- const fg = await loadFastGlob();
114
- if (fg) {
115
- // Use fast-glob (preferred)
116
- try {
117
- const ignorePatterns = [...DEFAULT_IGNORE, ...ignore];
118
- const matches = await fg(pattern, {
119
- cwd,
120
- ignore: ignorePatterns,
121
- onlyFiles: !includeDirectories,
122
- onlyDirectories: false,
123
- dot: false,
124
- absolute: false,
125
- suppressErrors: true,
126
- });
127
- const sorted = matches.sort();
128
- const truncated = sorted.length > maxResults;
129
- const finalMatches = sorted.slice(0, maxResults);
130
- return {
131
- pattern,
132
- matches: finalMatches,
133
- count: finalMatches.length,
134
- truncated,
135
- };
136
- }
137
- catch {
138
- // Fall through to fallback
139
- }
140
- }
141
- // Fallback implementation
142
- const regex = globToRegex(pattern);
143
- const matches = await findFilesFallback(cwd, regex, {
144
- maxResults: maxResults + 1,
145
- includeDirectories,
146
- ignorePatterns: FALLBACK_IGNORE,
147
- baseDir: cwd,
148
- });
149
- const truncated = matches.length > maxResults;
150
- const finalMatches = matches.slice(0, maxResults).sort();
151
- return {
152
- pattern,
153
- matches: finalMatches,
154
- count: finalMatches.length,
155
- truncated,
156
- };
157
- }
158
- // Tool definition
159
- export const tool = {
160
- name: 'glob',
161
- description: 'Find files matching a glob pattern. Supports ** for recursive matching, * for wildcards, and ? for single characters.',
162
- inputSchema,
163
- permission: 'read',
164
- execute: async (args) => execute(args),
165
- };
@@ -1,53 +0,0 @@
1
- /**
2
- * Grep Tool - Search for patterns in files
3
- * Uses ripgrep when available, fast-glob + JS regex as fallback
4
- */
5
- import { z } from 'zod';
6
- import type { Tool } from '../registry.js';
7
- export declare const inputSchema: z.ZodObject<{
8
- pattern: z.ZodString;
9
- path: z.ZodOptional<z.ZodString>;
10
- glob: z.ZodOptional<z.ZodString>;
11
- ignoreCase: z.ZodDefault<z.ZodOptional<z.ZodBoolean>>;
12
- maxResults: z.ZodDefault<z.ZodOptional<z.ZodNumber>>;
13
- contextLines: z.ZodDefault<z.ZodOptional<z.ZodNumber>>;
14
- filesOnly: z.ZodDefault<z.ZodOptional<z.ZodBoolean>>;
15
- includeHidden: z.ZodDefault<z.ZodOptional<z.ZodBoolean>>;
16
- }, "strip", z.ZodTypeAny, {
17
- pattern: string;
18
- ignoreCase: boolean;
19
- maxResults: number;
20
- contextLines: number;
21
- filesOnly: boolean;
22
- includeHidden: boolean;
23
- path?: string | undefined;
24
- glob?: string | undefined;
25
- }, {
26
- pattern: string;
27
- path?: string | undefined;
28
- glob?: string | undefined;
29
- ignoreCase?: boolean | undefined;
30
- maxResults?: number | undefined;
31
- contextLines?: number | undefined;
32
- filesOnly?: boolean | undefined;
33
- includeHidden?: boolean | undefined;
34
- }>;
35
- type GrepInput = z.infer<typeof inputSchema>;
36
- interface GrepMatch {
37
- file: string;
38
- line: number;
39
- column: number;
40
- text: string;
41
- match: string;
42
- contextBefore?: string[];
43
- contextAfter?: string[];
44
- }
45
- export declare function execute(input: GrepInput): Promise<{
46
- pattern: string;
47
- matches: GrepMatch[];
48
- files: string[];
49
- count: number;
50
- truncated: boolean;
51
- }>;
52
- export declare const tool: Tool;
53
- export {};
@@ -1,296 +0,0 @@
1
- /**
2
- * Grep Tool - Search for patterns in files
3
- * Uses ripgrep when available, fast-glob + JS regex as fallback
4
- */
5
- import { z } from 'zod';
6
- import { readFile, readdir, stat } from 'fs/promises';
7
- import { join, relative, extname } from 'path';
8
- import { spawnSync } from 'child_process';
9
- // Cached fast-glob instance (typed as any to handle missing module)
10
- let fg = null;
11
- let fgLoaded = false;
12
- async function loadFastGlob() {
13
- if (!fgLoaded) {
14
- fgLoaded = true;
15
- try {
16
- fg = (await import('fast-glob')).default;
17
- }
18
- catch {
19
- // fast-glob not installed
20
- }
21
- }
22
- return fg;
23
- }
24
- // Input schema
25
- export const inputSchema = z.object({
26
- pattern: z.string().describe('Regular expression pattern to search for'),
27
- path: z.string().optional().describe('File or directory to search in'),
28
- glob: z.string().optional().describe('File pattern to filter (e.g., "*.ts")'),
29
- ignoreCase: z.boolean().optional().default(false).describe('Case insensitive search'),
30
- maxResults: z.number().optional().default(100).describe('Maximum number of matches'),
31
- contextLines: z.number().optional().default(0).describe('Number of context lines before and after'),
32
- filesOnly: z.boolean().optional().default(false).describe('Only return file names, not matches'),
33
- includeHidden: z.boolean().optional().default(false).describe('Include hidden files'),
34
- });
35
- // Default ignore patterns
36
- const DEFAULT_IGNORE = [
37
- 'node_modules',
38
- '.git',
39
- 'dist',
40
- 'build',
41
- 'coverage',
42
- '__pycache__',
43
- '.pytest_cache',
44
- 'venv',
45
- '.venv',
46
- ];
47
- // Text file glob patterns for searching
48
- const TEXT_FILE_PATTERNS = [
49
- '**/*.{txt,md,json,yaml,yml,toml,xml,html,htm}',
50
- '**/*.{css,scss,less,js,jsx,ts,tsx,vue,svelte}',
51
- '**/*.{py,rb,php,java,c,cpp,h,hpp,cs,go,rs,swift,kt,scala}',
52
- '**/*.{sh,bash,zsh,fish,sql,graphql,prisma}',
53
- '**/{Makefile,Dockerfile,Containerfile,.gitignore,.dockerignore,.env}',
54
- '**/.{editorconfig,eslintrc,prettierrc,babelrc}*',
55
- ];
56
- // Search a single file
57
- async function searchFile(filePath, regex, contextLines) {
58
- const matches = [];
59
- try {
60
- const content = await readFile(filePath, 'utf-8');
61
- const lines = content.split('\n');
62
- for (let i = 0; i < lines.length; i++) {
63
- const line = lines[i];
64
- let match;
65
- // Reset regex for global searches
66
- regex.lastIndex = 0;
67
- while ((match = regex.exec(line)) !== null) {
68
- const result = {
69
- file: filePath,
70
- line: i + 1,
71
- column: match.index + 1,
72
- text: line,
73
- match: match[0],
74
- };
75
- if (contextLines > 0) {
76
- result.contextBefore = lines.slice(Math.max(0, i - contextLines), i);
77
- result.contextAfter = lines.slice(i + 1, Math.min(lines.length, i + 1 + contextLines));
78
- }
79
- matches.push(result);
80
- // Don't find overlapping matches on same line
81
- if (!regex.global)
82
- break;
83
- }
84
- }
85
- }
86
- catch {
87
- // Ignore files that can't be read
88
- }
89
- return matches;
90
- }
91
- // Text file extensions for fallback matching
92
- const TEXT_EXTENSIONS = new Set([
93
- '.txt', '.md', '.json', '.yaml', '.yml', '.toml', '.xml', '.html', '.htm',
94
- '.css', '.scss', '.less', '.js', '.jsx', '.ts', '.tsx', '.vue', '.svelte',
95
- '.py', '.rb', '.php', '.java', '.c', '.cpp', '.h', '.hpp', '.cs', '.go',
96
- '.rs', '.swift', '.kt', '.scala', '.sh', '.bash', '.zsh', '.fish',
97
- '.sql', '.graphql', '.prisma', '',
98
- ]);
99
- // Fallback: recursive directory search
100
- async function searchDirectoryFallback(dir, regex, options, results = []) {
101
- if (results.length >= options.maxResults)
102
- return results;
103
- try {
104
- const entries = await readdir(dir, { withFileTypes: true });
105
- for (const entry of entries) {
106
- if (results.length >= options.maxResults)
107
- break;
108
- const fullPath = join(dir, entry.name);
109
- const relativePath = relative(options.baseDir, fullPath);
110
- if (entry.isDirectory()) {
111
- if (DEFAULT_IGNORE.includes(entry.name))
112
- continue;
113
- if (!options.includeHidden && entry.name.startsWith('.'))
114
- continue;
115
- await searchDirectoryFallback(fullPath, regex, options, results);
116
- }
117
- else if (entry.isFile()) {
118
- const ext = extname(entry.name).toLowerCase();
119
- if (!TEXT_EXTENSIONS.has(ext))
120
- continue;
121
- if (!options.includeHidden && entry.name.startsWith('.'))
122
- continue;
123
- const fileMatches = await searchFile(fullPath, regex, options.contextLines);
124
- for (const match of fileMatches) {
125
- if (results.length >= options.maxResults)
126
- break;
127
- match.file = relativePath;
128
- results.push(match);
129
- }
130
- }
131
- }
132
- }
133
- catch {
134
- // Ignore permission errors
135
- }
136
- return results;
137
- }
138
- // Search directory using fast-glob for file discovery (with fallback)
139
- async function searchDirectory(dir, regex, options) {
140
- const results = [];
141
- const fastGlob = await loadFastGlob();
142
- if (fastGlob) {
143
- try {
144
- // Build ignore patterns
145
- const ignorePatterns = DEFAULT_IGNORE.map(d => `**/${d}/**`);
146
- // Use user's glob pattern or default to text files
147
- const patterns = options.glob ? [options.glob] : TEXT_FILE_PATTERNS;
148
- // Find files using fast-glob
149
- const files = await fastGlob(patterns, {
150
- cwd: dir,
151
- ignore: ignorePatterns,
152
- dot: options.includeHidden,
153
- absolute: true,
154
- suppressErrors: true,
155
- });
156
- // Search each file
157
- for (const fullPath of files) {
158
- if (results.length >= options.maxResults)
159
- break;
160
- const fileMatches = await searchFile(fullPath, regex, options.contextLines);
161
- for (const match of fileMatches) {
162
- if (results.length >= options.maxResults)
163
- break;
164
- match.file = relative(options.baseDir, fullPath);
165
- results.push(match);
166
- }
167
- }
168
- return results;
169
- }
170
- catch {
171
- // Fall through to fallback
172
- }
173
- }
174
- // Fallback to recursive directory search
175
- return searchDirectoryFallback(dir, regex, options, results);
176
- }
177
- // Try to use ripgrep if available
178
- function tryRipgrep(input) {
179
- try {
180
- // Request one more than maxResults to detect truncation
181
- const maxResults = input.maxResults || 100;
182
- const args = [
183
- '--json',
184
- '--max-count', String(maxResults + 1),
185
- ];
186
- // Ignore common directories by default (matching DEFAULT_IGNORE)
187
- for (const ignore of DEFAULT_IGNORE) {
188
- args.push('-g', `!${ignore}`);
189
- args.push('-g', `!${ignore}/**`);
190
- }
191
- if (input.ignoreCase) {
192
- args.push('-i');
193
- }
194
- if (input.glob) {
195
- args.push('-g', input.glob);
196
- }
197
- if (input.contextLines && input.contextLines > 0) {
198
- args.push('-C', String(input.contextLines));
199
- }
200
- args.push(input.pattern);
201
- if (input.path) {
202
- args.push(input.path);
203
- }
204
- const result = spawnSync('rg', args, {
205
- encoding: 'utf-8',
206
- maxBuffer: 10 * 1024 * 1024,
207
- timeout: 30000,
208
- });
209
- if (result.error) {
210
- return null; // ripgrep not available
211
- }
212
- const matches = [];
213
- const lines = result.stdout.split('\n').filter(Boolean);
214
- for (const line of lines) {
215
- try {
216
- const json = JSON.parse(line);
217
- if (json.type === 'match') {
218
- // Extract all submatches, not just the first one
219
- const submatches = json.data.submatches || [];
220
- for (const submatch of submatches) {
221
- matches.push({
222
- file: json.data.path.text,
223
- line: json.data.line_number,
224
- column: (submatch.start || 0) + 1,
225
- text: json.data.lines.text.replace(/\n$/, ''),
226
- match: submatch.match?.text || '',
227
- });
228
- }
229
- }
230
- }
231
- catch {
232
- // Skip invalid JSON lines
233
- }
234
- }
235
- return matches;
236
- }
237
- catch {
238
- return null;
239
- }
240
- }
241
- // Execute grep search
242
- export async function execute(input) {
243
- const { pattern, path = process.cwd(), glob, ignoreCase, maxResults, contextLines, filesOnly, includeHidden, } = inputSchema.parse(input);
244
- // Try ripgrep first (but skip if context lines requested - ripgrep parsing doesn't support it)
245
- if (!contextLines || contextLines === 0) {
246
- const rgMatches = tryRipgrep(input);
247
- if (rgMatches !== null && rgMatches.length > 0) {
248
- const uniqueFiles = [...new Set(rgMatches.map(m => m.file))];
249
- return {
250
- pattern,
251
- matches: filesOnly ? [] : rgMatches.slice(0, maxResults),
252
- files: uniqueFiles,
253
- count: rgMatches.length,
254
- truncated: rgMatches.length > maxResults,
255
- };
256
- }
257
- }
258
- // Fall back to JavaScript implementation
259
- const flags = ignoreCase ? 'gi' : 'g';
260
- const regex = new RegExp(pattern, flags);
261
- let matches;
262
- const pathStat = await stat(path).catch(() => null);
263
- if (pathStat?.isFile()) {
264
- matches = await searchFile(path, regex, contextLines);
265
- }
266
- else if (pathStat?.isDirectory()) {
267
- matches = await searchDirectory(path, regex, {
268
- glob,
269
- contextLines,
270
- maxResults: maxResults + 1,
271
- includeHidden,
272
- baseDir: path,
273
- });
274
- }
275
- else {
276
- matches = [];
277
- }
278
- const truncated = matches.length > maxResults;
279
- const finalMatches = matches.slice(0, maxResults);
280
- const uniqueFiles = [...new Set(finalMatches.map(m => m.file))];
281
- return {
282
- pattern,
283
- matches: filesOnly ? [] : finalMatches,
284
- files: uniqueFiles,
285
- count: finalMatches.length,
286
- truncated,
287
- };
288
- }
289
- // Tool definition
290
- export const tool = {
291
- name: 'grep',
292
- description: 'Search for a pattern in files using regular expressions. Uses ripgrep if available for better performance.',
293
- inputSchema,
294
- permission: 'read',
295
- execute: async (args) => execute(args),
296
- };
@@ -1,35 +0,0 @@
1
- /**
2
- * Linter Tool - Checks code for syntax errors
3
- * Based on Aider's linter.py
4
- */
5
- import { z } from 'zod';
6
- import type { Tool } from '../registry.js';
7
- export declare const inputSchema: z.ZodObject<{
8
- path: z.ZodString;
9
- fix: z.ZodDefault<z.ZodOptional<z.ZodBoolean>>;
10
- }, "strip", z.ZodTypeAny, {
11
- path: string;
12
- fix: boolean;
13
- }, {
14
- path: string;
15
- fix?: boolean | undefined;
16
- }>;
17
- type LinterInput = z.infer<typeof inputSchema>;
18
- interface LintResult {
19
- file: string;
20
- language: string;
21
- errors: LintError[];
22
- warnings: LintError[];
23
- passed: boolean;
24
- output: string;
25
- }
26
- interface LintError {
27
- line: number;
28
- column?: number;
29
- message: string;
30
- rule?: string;
31
- severity: 'error' | 'warning';
32
- }
33
- export declare function execute(input: LinterInput): Promise<LintResult>;
34
- export declare const tool: Tool;
35
- export {};