@compilr-dev/agents 0.0.1

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 (160) hide show
  1. package/README.md +1277 -0
  2. package/dist/agent.d.ts +1272 -0
  3. package/dist/agent.js +1912 -0
  4. package/dist/anchors/builtin.d.ts +24 -0
  5. package/dist/anchors/builtin.js +61 -0
  6. package/dist/anchors/index.d.ts +6 -0
  7. package/dist/anchors/index.js +5 -0
  8. package/dist/anchors/manager.d.ts +115 -0
  9. package/dist/anchors/manager.js +412 -0
  10. package/dist/anchors/types.d.ts +168 -0
  11. package/dist/anchors/types.js +10 -0
  12. package/dist/context/index.d.ts +12 -0
  13. package/dist/context/index.js +10 -0
  14. package/dist/context/manager.d.ts +224 -0
  15. package/dist/context/manager.js +770 -0
  16. package/dist/context/types.d.ts +377 -0
  17. package/dist/context/types.js +7 -0
  18. package/dist/costs/index.d.ts +8 -0
  19. package/dist/costs/index.js +7 -0
  20. package/dist/costs/tracker.d.ts +121 -0
  21. package/dist/costs/tracker.js +295 -0
  22. package/dist/costs/types.d.ts +157 -0
  23. package/dist/costs/types.js +8 -0
  24. package/dist/errors.d.ts +178 -0
  25. package/dist/errors.js +249 -0
  26. package/dist/guardrails/builtin.d.ts +27 -0
  27. package/dist/guardrails/builtin.js +223 -0
  28. package/dist/guardrails/index.d.ts +6 -0
  29. package/dist/guardrails/index.js +5 -0
  30. package/dist/guardrails/manager.d.ts +117 -0
  31. package/dist/guardrails/manager.js +288 -0
  32. package/dist/guardrails/types.d.ts +159 -0
  33. package/dist/guardrails/types.js +7 -0
  34. package/dist/hooks/index.d.ts +31 -0
  35. package/dist/hooks/index.js +29 -0
  36. package/dist/hooks/manager.d.ts +147 -0
  37. package/dist/hooks/manager.js +600 -0
  38. package/dist/hooks/types.d.ts +368 -0
  39. package/dist/hooks/types.js +12 -0
  40. package/dist/index.d.ts +45 -0
  41. package/dist/index.js +73 -0
  42. package/dist/mcp/client.d.ts +93 -0
  43. package/dist/mcp/client.js +287 -0
  44. package/dist/mcp/errors.d.ts +60 -0
  45. package/dist/mcp/errors.js +78 -0
  46. package/dist/mcp/index.d.ts +43 -0
  47. package/dist/mcp/index.js +45 -0
  48. package/dist/mcp/manager.d.ts +120 -0
  49. package/dist/mcp/manager.js +276 -0
  50. package/dist/mcp/tools.d.ts +54 -0
  51. package/dist/mcp/tools.js +99 -0
  52. package/dist/mcp/types.d.ts +150 -0
  53. package/dist/mcp/types.js +40 -0
  54. package/dist/memory/index.d.ts +8 -0
  55. package/dist/memory/index.js +7 -0
  56. package/dist/memory/loader.d.ts +114 -0
  57. package/dist/memory/loader.js +463 -0
  58. package/dist/memory/types.d.ts +182 -0
  59. package/dist/memory/types.js +8 -0
  60. package/dist/messages/index.d.ts +82 -0
  61. package/dist/messages/index.js +155 -0
  62. package/dist/permissions/index.d.ts +5 -0
  63. package/dist/permissions/index.js +4 -0
  64. package/dist/permissions/manager.d.ts +125 -0
  65. package/dist/permissions/manager.js +379 -0
  66. package/dist/permissions/types.d.ts +162 -0
  67. package/dist/permissions/types.js +7 -0
  68. package/dist/providers/claude.d.ts +90 -0
  69. package/dist/providers/claude.js +348 -0
  70. package/dist/providers/index.d.ts +8 -0
  71. package/dist/providers/index.js +11 -0
  72. package/dist/providers/mock.d.ts +133 -0
  73. package/dist/providers/mock.js +204 -0
  74. package/dist/providers/types.d.ts +168 -0
  75. package/dist/providers/types.js +4 -0
  76. package/dist/rate-limit/index.d.ts +45 -0
  77. package/dist/rate-limit/index.js +47 -0
  78. package/dist/rate-limit/limiter.d.ts +104 -0
  79. package/dist/rate-limit/limiter.js +326 -0
  80. package/dist/rate-limit/provider-wrapper.d.ts +112 -0
  81. package/dist/rate-limit/provider-wrapper.js +201 -0
  82. package/dist/rate-limit/retry.d.ts +108 -0
  83. package/dist/rate-limit/retry.js +287 -0
  84. package/dist/rate-limit/types.d.ts +181 -0
  85. package/dist/rate-limit/types.js +22 -0
  86. package/dist/rehearsal/file-analyzer.d.ts +22 -0
  87. package/dist/rehearsal/file-analyzer.js +351 -0
  88. package/dist/rehearsal/git-analyzer.d.ts +22 -0
  89. package/dist/rehearsal/git-analyzer.js +472 -0
  90. package/dist/rehearsal/index.d.ts +35 -0
  91. package/dist/rehearsal/index.js +36 -0
  92. package/dist/rehearsal/manager.d.ts +100 -0
  93. package/dist/rehearsal/manager.js +290 -0
  94. package/dist/rehearsal/types.d.ts +235 -0
  95. package/dist/rehearsal/types.js +8 -0
  96. package/dist/skills/index.d.ts +160 -0
  97. package/dist/skills/index.js +282 -0
  98. package/dist/state/agent-state.d.ts +41 -0
  99. package/dist/state/agent-state.js +88 -0
  100. package/dist/state/checkpointer.d.ts +110 -0
  101. package/dist/state/checkpointer.js +362 -0
  102. package/dist/state/errors.d.ts +66 -0
  103. package/dist/state/errors.js +88 -0
  104. package/dist/state/index.d.ts +35 -0
  105. package/dist/state/index.js +37 -0
  106. package/dist/state/serializer.d.ts +55 -0
  107. package/dist/state/serializer.js +172 -0
  108. package/dist/state/types.d.ts +312 -0
  109. package/dist/state/types.js +14 -0
  110. package/dist/tools/builtin/bash-output.d.ts +61 -0
  111. package/dist/tools/builtin/bash-output.js +90 -0
  112. package/dist/tools/builtin/bash.d.ts +150 -0
  113. package/dist/tools/builtin/bash.js +354 -0
  114. package/dist/tools/builtin/edit.d.ts +50 -0
  115. package/dist/tools/builtin/edit.js +215 -0
  116. package/dist/tools/builtin/glob.d.ts +62 -0
  117. package/dist/tools/builtin/glob.js +244 -0
  118. package/dist/tools/builtin/grep.d.ts +74 -0
  119. package/dist/tools/builtin/grep.js +363 -0
  120. package/dist/tools/builtin/index.d.ts +44 -0
  121. package/dist/tools/builtin/index.js +69 -0
  122. package/dist/tools/builtin/kill-shell.d.ts +44 -0
  123. package/dist/tools/builtin/kill-shell.js +80 -0
  124. package/dist/tools/builtin/read-file.d.ts +57 -0
  125. package/dist/tools/builtin/read-file.js +184 -0
  126. package/dist/tools/builtin/shell-manager.d.ts +176 -0
  127. package/dist/tools/builtin/shell-manager.js +337 -0
  128. package/dist/tools/builtin/task.d.ts +202 -0
  129. package/dist/tools/builtin/task.js +350 -0
  130. package/dist/tools/builtin/todo.d.ts +207 -0
  131. package/dist/tools/builtin/todo.js +453 -0
  132. package/dist/tools/builtin/utils.d.ts +27 -0
  133. package/dist/tools/builtin/utils.js +70 -0
  134. package/dist/tools/builtin/web-fetch.d.ts +96 -0
  135. package/dist/tools/builtin/web-fetch.js +290 -0
  136. package/dist/tools/builtin/write-file.d.ts +54 -0
  137. package/dist/tools/builtin/write-file.js +147 -0
  138. package/dist/tools/define.d.ts +60 -0
  139. package/dist/tools/define.js +65 -0
  140. package/dist/tools/index.d.ts +10 -0
  141. package/dist/tools/index.js +37 -0
  142. package/dist/tools/registry.d.ts +79 -0
  143. package/dist/tools/registry.js +151 -0
  144. package/dist/tools/types.d.ts +59 -0
  145. package/dist/tools/types.js +4 -0
  146. package/dist/tracing/hooks.d.ts +58 -0
  147. package/dist/tracing/hooks.js +377 -0
  148. package/dist/tracing/index.d.ts +51 -0
  149. package/dist/tracing/index.js +55 -0
  150. package/dist/tracing/logging.d.ts +78 -0
  151. package/dist/tracing/logging.js +310 -0
  152. package/dist/tracing/manager.d.ts +160 -0
  153. package/dist/tracing/manager.js +468 -0
  154. package/dist/tracing/otel.d.ts +102 -0
  155. package/dist/tracing/otel.js +246 -0
  156. package/dist/tracing/types.d.ts +346 -0
  157. package/dist/tracing/types.js +38 -0
  158. package/dist/utils/index.d.ts +23 -0
  159. package/dist/utils/index.js +44 -0
  160. package/package.json +79 -0
@@ -0,0 +1,215 @@
1
+ /**
2
+ * Edit Tool - Perform targeted string replacements in files
3
+ */
4
+ import { readFile, writeFile, access, mkdir } from 'node:fs/promises';
5
+ import { dirname } from 'node:path';
6
+ import { defineTool, createSuccessResult, createErrorResult } from '../define.js';
7
+ import { isNodeError, isExtensionAllowed, atomicWriteFile } from './utils.js';
8
+ /**
9
+ * Edit tool definition
10
+ */
11
+ export const editTool = defineTool({
12
+ name: 'edit',
13
+ description: 'Perform exact string replacements in files. ' +
14
+ 'By default, the old_string must be unique in the file. ' +
15
+ 'Use replaceAll to replace all occurrences.',
16
+ inputSchema: {
17
+ type: 'object',
18
+ properties: {
19
+ filePath: {
20
+ type: 'string',
21
+ description: 'Path to the file to edit',
22
+ },
23
+ oldString: {
24
+ type: 'string',
25
+ description: 'The text to search for and replace',
26
+ },
27
+ newString: {
28
+ type: 'string',
29
+ description: 'The replacement text',
30
+ },
31
+ replaceAll: {
32
+ type: 'boolean',
33
+ description: 'Replace all occurrences instead of requiring uniqueness',
34
+ },
35
+ createIfMissing: {
36
+ type: 'boolean',
37
+ description: 'Create the file with newString content if it does not exist',
38
+ },
39
+ },
40
+ required: ['filePath', 'oldString', 'newString'],
41
+ },
42
+ execute: executeEdit,
43
+ });
44
+ /**
45
+ * Execute the edit tool
46
+ */
47
+ async function executeEdit(input) {
48
+ const { filePath, oldString, newString, replaceAll = false, createIfMissing = false } = input;
49
+ // Validate inputs
50
+ if (oldString === newString) {
51
+ return createErrorResult('oldString and newString are identical - no change needed');
52
+ }
53
+ if (oldString === '') {
54
+ return createErrorResult('oldString cannot be empty');
55
+ }
56
+ // Check if file exists
57
+ let fileExists = true;
58
+ try {
59
+ await access(filePath);
60
+ }
61
+ catch {
62
+ fileExists = false;
63
+ }
64
+ if (!fileExists) {
65
+ if (createIfMissing) {
66
+ // Create new file with the newString content
67
+ try {
68
+ // Create parent directories if they don't exist
69
+ const dir = dirname(filePath);
70
+ if (dir && dir !== '.') {
71
+ await mkdir(dir, { recursive: true });
72
+ }
73
+ await writeFile(filePath, newString, 'utf-8');
74
+ return createSuccessResult({
75
+ filePath,
76
+ created: true,
77
+ replacements: 0,
78
+ message: `Created new file with content`,
79
+ });
80
+ }
81
+ catch (error) {
82
+ return createErrorResult(`Failed to create file: ${error instanceof Error ? error.message : String(error)}`);
83
+ }
84
+ }
85
+ return createErrorResult(`File not found: ${filePath}`);
86
+ }
87
+ // Read the file
88
+ let content;
89
+ try {
90
+ content = await readFile(filePath, 'utf-8');
91
+ }
92
+ catch (error) {
93
+ if (isNodeError(error)) {
94
+ switch (error.code) {
95
+ case 'EACCES':
96
+ return createErrorResult(`Permission denied: ${filePath}`);
97
+ case 'EISDIR':
98
+ return createErrorResult(`Path is a directory: ${filePath}`);
99
+ default:
100
+ return createErrorResult(`Failed to read file: ${error.message}`);
101
+ }
102
+ }
103
+ return createErrorResult(error instanceof Error ? error.message : String(error));
104
+ }
105
+ // Count occurrences
106
+ const occurrences = countOccurrences(content, oldString);
107
+ if (occurrences === 0) {
108
+ return createErrorResult(`String not found in file: "${truncate(oldString, 100)}"`);
109
+ }
110
+ if (!replaceAll && occurrences > 1) {
111
+ return createErrorResult(`The oldString appears ${String(occurrences)} times in the file. ` +
112
+ `Either provide more context to make it unique, or set replaceAll: true`);
113
+ }
114
+ // Perform the replacement
115
+ const newContent = replaceAll
116
+ ? content.split(oldString).join(newString)
117
+ : content.replace(oldString, newString);
118
+ // Write the file atomically (prevents corruption on interruption)
119
+ try {
120
+ await atomicWriteFile(filePath, newContent, 'utf-8');
121
+ }
122
+ catch (error) {
123
+ return createErrorResult(`Failed to write file: ${error instanceof Error ? error.message : String(error)}`);
124
+ }
125
+ return createSuccessResult({
126
+ filePath,
127
+ created: false,
128
+ replacements: replaceAll ? occurrences : 1,
129
+ message: replaceAll ? `Replaced ${String(occurrences)} occurrences` : `Replaced 1 occurrence`,
130
+ });
131
+ }
132
+ /**
133
+ * Count occurrences of a substring
134
+ */
135
+ function countOccurrences(text, search) {
136
+ let count = 0;
137
+ let position = 0;
138
+ let index = text.indexOf(search, position);
139
+ while (index !== -1) {
140
+ count++;
141
+ position = index + 1;
142
+ index = text.indexOf(search, position);
143
+ }
144
+ return count;
145
+ }
146
+ /**
147
+ * Truncate a string for display
148
+ */
149
+ function truncate(str, maxLength) {
150
+ if (str.length <= maxLength)
151
+ return str;
152
+ return str.slice(0, maxLength - 3) + '...';
153
+ }
154
+ /**
155
+ * Factory function to create an edit tool with custom options
156
+ */
157
+ export function createEditTool(options) {
158
+ return defineTool({
159
+ name: 'edit',
160
+ description: 'Perform exact string replacements in files. ' +
161
+ 'By default, the old_string must be unique in the file. ' +
162
+ 'Use replaceAll to replace all occurrences.',
163
+ inputSchema: {
164
+ type: 'object',
165
+ properties: {
166
+ filePath: {
167
+ type: 'string',
168
+ description: 'Path to the file to edit',
169
+ },
170
+ oldString: {
171
+ type: 'string',
172
+ description: 'The text to search for and replace',
173
+ },
174
+ newString: {
175
+ type: 'string',
176
+ description: 'The replacement text',
177
+ },
178
+ replaceAll: {
179
+ type: 'boolean',
180
+ description: 'Replace all occurrences instead of requiring uniqueness',
181
+ },
182
+ createIfMissing: {
183
+ type: 'boolean',
184
+ description: 'Create the file with newString content if it does not exist',
185
+ },
186
+ },
187
+ required: ['filePath', 'oldString', 'newString'],
188
+ },
189
+ execute: async (input) => {
190
+ let targetPath = input.filePath;
191
+ // Resolve relative paths
192
+ if (options?.baseDir && !targetPath.startsWith('/')) {
193
+ targetPath = `${options.baseDir}/${targetPath}`;
194
+ }
195
+ // Check allowed extensions
196
+ if (options?.allowedExtensions && options.allowedExtensions.length > 0) {
197
+ if (!isExtensionAllowed(targetPath, options.allowedExtensions)) {
198
+ return createErrorResult(`File extension not allowed. Allowed: ${options.allowedExtensions.join(', ')}`);
199
+ }
200
+ }
201
+ // Check disallowed paths
202
+ if (options?.disallowedPaths) {
203
+ for (const disallowed of options.disallowedPaths) {
204
+ if (targetPath.includes(disallowed)) {
205
+ return createErrorResult(`Editing files in ${disallowed} is not allowed`);
206
+ }
207
+ }
208
+ }
209
+ return executeEdit({
210
+ ...input,
211
+ filePath: targetPath,
212
+ });
213
+ },
214
+ });
215
+ }
@@ -0,0 +1,62 @@
1
+ /**
2
+ * Glob Tool - Find files matching glob patterns
3
+ */
4
+ import type { Tool } from '../types.js';
5
+ /**
6
+ * Input parameters for glob tool
7
+ */
8
+ export interface GlobInput {
9
+ /**
10
+ * Glob pattern to match files against (e.g., "**\/*.ts", "src/*.js")
11
+ */
12
+ pattern: string;
13
+ /**
14
+ * Base directory to search in (default: current directory)
15
+ */
16
+ path?: string;
17
+ /**
18
+ * Include hidden files and directories (default: false)
19
+ */
20
+ includeHidden?: boolean;
21
+ /**
22
+ * Only match directories (default: false)
23
+ */
24
+ onlyDirectories?: boolean;
25
+ /**
26
+ * Only match files (default: true)
27
+ */
28
+ onlyFiles?: boolean;
29
+ /**
30
+ * Maximum depth to traverse (default: unlimited)
31
+ */
32
+ maxDepth?: number;
33
+ /**
34
+ * Maximum number of results (default: 1000)
35
+ */
36
+ maxResults?: number;
37
+ /**
38
+ * Return absolute paths instead of relative (default: false)
39
+ */
40
+ absolute?: boolean;
41
+ }
42
+ /**
43
+ * Glob tool definition
44
+ */
45
+ export declare const globTool: Tool<GlobInput>;
46
+ /**
47
+ * Factory function to create a glob tool with custom options
48
+ */
49
+ export declare function createGlobTool(options?: {
50
+ /**
51
+ * Base directory to resolve relative paths against
52
+ */
53
+ baseDir?: string;
54
+ /**
55
+ * Default patterns to ignore
56
+ */
57
+ ignorePatterns?: string[];
58
+ /**
59
+ * Always include these patterns regardless of ignore
60
+ */
61
+ alwaysInclude?: string[];
62
+ }): Tool<GlobInput>;
@@ -0,0 +1,244 @@
1
+ /**
2
+ * Glob Tool - Find files matching glob patterns
3
+ */
4
+ import { readdir } from 'node:fs/promises';
5
+ import { join } from 'node:path';
6
+ import { defineTool, createSuccessResult, createErrorResult } from '../define.js';
7
+ import { isNodeError } from './utils.js';
8
+ /**
9
+ * Glob tool definition
10
+ */
11
+ export const globTool = defineTool({
12
+ name: 'glob',
13
+ description: 'Find files matching glob patterns. ' +
14
+ 'Supports common patterns like **/*.ts for recursive matching. ' +
15
+ 'Returns a list of matching file paths.',
16
+ inputSchema: {
17
+ type: 'object',
18
+ properties: {
19
+ pattern: {
20
+ type: 'string',
21
+ description: 'Glob pattern (e.g., "**/*.ts", "src/**/*.js", "*.md")',
22
+ },
23
+ path: {
24
+ type: 'string',
25
+ description: 'Base directory to search in (default: current directory)',
26
+ },
27
+ includeHidden: {
28
+ type: 'boolean',
29
+ description: 'Include hidden files/directories (default: false)',
30
+ },
31
+ onlyDirectories: {
32
+ type: 'boolean',
33
+ description: 'Only match directories',
34
+ },
35
+ onlyFiles: {
36
+ type: 'boolean',
37
+ description: 'Only match files (default: true)',
38
+ },
39
+ maxDepth: {
40
+ type: 'number',
41
+ description: 'Maximum directory depth to traverse',
42
+ },
43
+ maxResults: {
44
+ type: 'number',
45
+ description: 'Maximum number of results (default: 1000)',
46
+ },
47
+ absolute: {
48
+ type: 'boolean',
49
+ description: 'Return absolute paths instead of relative',
50
+ },
51
+ },
52
+ required: ['pattern'],
53
+ },
54
+ execute: executeGlob,
55
+ });
56
+ /**
57
+ * Execute the glob tool
58
+ */
59
+ async function executeGlob(input) {
60
+ const { pattern, path: basePath = '.', includeHidden = false, onlyDirectories = false, onlyFiles = !onlyDirectories, maxDepth, maxResults = 1000, absolute = false, } = input;
61
+ // Check if base path exists
62
+ try {
63
+ await readdir(basePath);
64
+ }
65
+ catch (error) {
66
+ if (isNodeError(error)) {
67
+ switch (error.code) {
68
+ case 'ENOENT':
69
+ return createErrorResult(`Directory not found: ${basePath}`);
70
+ case 'EACCES':
71
+ return createErrorResult(`Permission denied: ${basePath}`);
72
+ default:
73
+ return createErrorResult(`Glob failed: ${error.message}`);
74
+ }
75
+ }
76
+ return createErrorResult(error instanceof Error ? error.message : String(error));
77
+ }
78
+ try {
79
+ // Parse the glob pattern
80
+ const globRegex = patternToRegex(pattern);
81
+ const hasRecursive = pattern.includes('**');
82
+ // Collect matching files
83
+ const matches = [];
84
+ await searchDirectory(basePath, '', 0, {
85
+ pattern: globRegex,
86
+ hasRecursive,
87
+ includeHidden,
88
+ onlyDirectories,
89
+ onlyFiles,
90
+ maxDepth,
91
+ maxResults,
92
+ matches,
93
+ basePath,
94
+ });
95
+ // Format output
96
+ const results = absolute ? matches.map((m) => join(basePath, m)) : matches;
97
+ return createSuccessResult({
98
+ files: results,
99
+ count: results.length,
100
+ truncated: results.length >= maxResults,
101
+ });
102
+ }
103
+ catch (error) {
104
+ return createErrorResult(error instanceof Error ? error.message : String(error));
105
+ }
106
+ }
107
+ /**
108
+ * Recursively search a directory for matching files
109
+ */
110
+ async function searchDirectory(basePath, relativePath, depth, options) {
111
+ // Check if we've reached max results
112
+ if (options.matches.length >= options.maxResults) {
113
+ return;
114
+ }
115
+ // Check max depth
116
+ if (options.maxDepth !== undefined && depth > options.maxDepth) {
117
+ return;
118
+ }
119
+ const currentPath = relativePath ? join(basePath, relativePath) : basePath;
120
+ let entries;
121
+ try {
122
+ entries = await readdir(currentPath, { withFileTypes: true });
123
+ }
124
+ catch {
125
+ // Skip directories we can't read
126
+ return;
127
+ }
128
+ for (const entry of entries) {
129
+ if (options.matches.length >= options.maxResults) {
130
+ break;
131
+ }
132
+ // Skip hidden files unless included
133
+ if (!options.includeHidden && entry.name.startsWith('.')) {
134
+ continue;
135
+ }
136
+ const entryRelativePath = relativePath ? join(relativePath, entry.name) : entry.name;
137
+ const isDir = entry.isDirectory();
138
+ const isFile = entry.isFile();
139
+ // Check if this entry matches the pattern
140
+ if (options.pattern.test(entryRelativePath)) {
141
+ if ((isDir && !options.onlyFiles) || (isFile && !options.onlyDirectories)) {
142
+ options.matches.push(entryRelativePath);
143
+ }
144
+ }
145
+ // Recurse into directories
146
+ if (isDir && (options.hasRecursive || shouldDescend(entryRelativePath, options.pattern))) {
147
+ await searchDirectory(basePath, entryRelativePath, depth + 1, options);
148
+ }
149
+ }
150
+ }
151
+ /**
152
+ * Check if we should descend into a directory based on the pattern
153
+ */
154
+ function shouldDescend(_path, _pattern) {
155
+ // If the pattern might match files in this directory, descend
156
+ // This is a simplified check - just return true for non-** patterns
157
+ // that might have directory prefixes
158
+ return true;
159
+ }
160
+ /**
161
+ * Convert a glob pattern to a regular expression
162
+ */
163
+ function patternToRegex(pattern) {
164
+ // Handle special case: **/* means match anything
165
+ if (pattern === '**/*') {
166
+ return new RegExp('^.+$');
167
+ }
168
+ // Handle **/ at the start first (matches any directory prefix including none)
169
+ let workingPattern = pattern;
170
+ let prefix = '';
171
+ if (workingPattern.startsWith('**/')) {
172
+ prefix = '(?:.*/|)';
173
+ workingPattern = workingPattern.slice(3); // Remove the **/ part
174
+ }
175
+ // Escape special regex characters except glob characters (* and ?)
176
+ let regexStr = workingPattern.replace(/[.+^${}()|[\]\\]/g, '\\$&');
177
+ // Handle remaining ** (matches anything including /)
178
+ regexStr = regexStr.replace(/\*\*/g, '.*');
179
+ // Handle remaining * (matches anything except /)
180
+ regexStr = regexStr.replace(/\*/g, '[^/]*');
181
+ // Handle ? (matches single character except /)
182
+ regexStr = regexStr.replace(/\?/g, '[^/]');
183
+ return new RegExp('^' + prefix + regexStr + '$');
184
+ }
185
+ /**
186
+ * Factory function to create a glob tool with custom options
187
+ */
188
+ export function createGlobTool(options) {
189
+ return defineTool({
190
+ name: 'glob',
191
+ description: 'Find files matching glob patterns. ' +
192
+ 'Supports common patterns like **/*.ts for recursive matching. ' +
193
+ 'Returns a list of matching file paths.',
194
+ inputSchema: {
195
+ type: 'object',
196
+ properties: {
197
+ pattern: {
198
+ type: 'string',
199
+ description: 'Glob pattern (e.g., "**/*.ts", "src/**/*.js", "*.md")',
200
+ },
201
+ path: {
202
+ type: 'string',
203
+ description: 'Base directory to search in (default: current directory)',
204
+ },
205
+ includeHidden: {
206
+ type: 'boolean',
207
+ description: 'Include hidden files/directories (default: false)',
208
+ },
209
+ onlyDirectories: {
210
+ type: 'boolean',
211
+ description: 'Only match directories',
212
+ },
213
+ onlyFiles: {
214
+ type: 'boolean',
215
+ description: 'Only match files (default: true)',
216
+ },
217
+ maxDepth: {
218
+ type: 'number',
219
+ description: 'Maximum directory depth to traverse',
220
+ },
221
+ maxResults: {
222
+ type: 'number',
223
+ description: 'Maximum number of results (default: 1000)',
224
+ },
225
+ absolute: {
226
+ type: 'boolean',
227
+ description: 'Return absolute paths instead of relative',
228
+ },
229
+ },
230
+ required: ['pattern'],
231
+ },
232
+ execute: async (input) => {
233
+ let searchPath = input.path ?? '.';
234
+ // Resolve relative paths
235
+ if (options?.baseDir && !searchPath.startsWith('/')) {
236
+ searchPath = join(options.baseDir, searchPath);
237
+ }
238
+ return executeGlob({
239
+ ...input,
240
+ path: searchPath,
241
+ });
242
+ },
243
+ });
244
+ }
@@ -0,0 +1,74 @@
1
+ /**
2
+ * Grep Tool - Search for patterns in files using regex
3
+ */
4
+ import type { Tool } from '../types.js';
5
+ /**
6
+ * Input parameters for grep tool
7
+ */
8
+ export interface GrepInput {
9
+ /**
10
+ * Regular expression pattern to search for
11
+ */
12
+ pattern: string;
13
+ /**
14
+ * Path to file or directory to search in
15
+ */
16
+ path: string;
17
+ /**
18
+ * Case insensitive search (default: false)
19
+ */
20
+ ignoreCase?: boolean;
21
+ /**
22
+ * Include line numbers in output (default: true)
23
+ */
24
+ lineNumbers?: boolean;
25
+ /**
26
+ * Number of context lines before match (default: 0)
27
+ */
28
+ before?: number;
29
+ /**
30
+ * Number of context lines after match (default: 0)
31
+ */
32
+ after?: number;
33
+ /**
34
+ * Only return filenames with matches (default: false)
35
+ */
36
+ filesOnly?: boolean;
37
+ /**
38
+ * Include hidden files/directories (default: false)
39
+ */
40
+ includeHidden?: boolean;
41
+ /**
42
+ * File extensions to include (e.g., ['.ts', '.js'])
43
+ */
44
+ extensions?: string[];
45
+ /**
46
+ * Maximum number of matches to return (default: 100)
47
+ */
48
+ maxMatches?: number;
49
+ /**
50
+ * Search recursively in directories (default: true)
51
+ */
52
+ recursive?: boolean;
53
+ }
54
+ /**
55
+ * Grep tool definition
56
+ */
57
+ export declare const grepTool: Tool<GrepInput>;
58
+ /**
59
+ * Factory function to create a grep tool with custom options
60
+ *
61
+ * TODO: Future enhancements could include:
62
+ * - maxFileSize: Skip files larger than specified size
63
+ * - excludeDirs: Exclude directories by name (e.g., node_modules, .git)
64
+ */
65
+ export declare function createGrepTool(options?: {
66
+ /**
67
+ * Base directory to resolve relative paths against
68
+ */
69
+ baseDir?: string;
70
+ /**
71
+ * Default file extensions to search
72
+ */
73
+ defaultExtensions?: string[];
74
+ }): Tool<GrepInput>;