gencode-ai 0.1.0
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.
- package/.env.example +11 -0
- package/CLAUDE.md +70 -0
- package/LICENSE +21 -0
- package/README.md +117 -0
- package/dist/agent/agent.d.ts +84 -0
- package/dist/agent/agent.d.ts.map +1 -0
- package/dist/agent/agent.js +233 -0
- package/dist/agent/agent.js.map +1 -0
- package/dist/agent/index.d.ts +6 -0
- package/dist/agent/index.d.ts.map +1 -0
- package/dist/agent/index.js +6 -0
- package/dist/agent/index.js.map +1 -0
- package/dist/agent/types.d.ts +47 -0
- package/dist/agent/types.d.ts.map +1 -0
- package/dist/agent/types.js +5 -0
- package/dist/agent/types.js.map +1 -0
- package/dist/cli/components/App.d.ts +14 -0
- package/dist/cli/components/App.d.ts.map +1 -0
- package/dist/cli/components/App.js +395 -0
- package/dist/cli/components/App.js.map +1 -0
- package/dist/cli/components/CommandSuggestions.d.ts +13 -0
- package/dist/cli/components/CommandSuggestions.d.ts.map +1 -0
- package/dist/cli/components/CommandSuggestions.js +32 -0
- package/dist/cli/components/CommandSuggestions.js.map +1 -0
- package/dist/cli/components/Header.d.ts +9 -0
- package/dist/cli/components/Header.d.ts.map +1 -0
- package/dist/cli/components/Header.js +13 -0
- package/dist/cli/components/Header.js.map +1 -0
- package/dist/cli/components/Input.d.ts +13 -0
- package/dist/cli/components/Input.d.ts.map +1 -0
- package/dist/cli/components/Input.js +27 -0
- package/dist/cli/components/Input.js.map +1 -0
- package/dist/cli/components/Logo.d.ts +2 -0
- package/dist/cli/components/Logo.d.ts.map +1 -0
- package/dist/cli/components/Logo.js +8 -0
- package/dist/cli/components/Logo.js.map +1 -0
- package/dist/cli/components/Messages.d.ts +37 -0
- package/dist/cli/components/Messages.d.ts.map +1 -0
- package/dist/cli/components/Messages.js +106 -0
- package/dist/cli/components/Messages.js.map +1 -0
- package/dist/cli/components/ModelSelector.d.ts +13 -0
- package/dist/cli/components/ModelSelector.d.ts.map +1 -0
- package/dist/cli/components/ModelSelector.js +72 -0
- package/dist/cli/components/ModelSelector.js.map +1 -0
- package/dist/cli/components/Spinner.d.ts +12 -0
- package/dist/cli/components/Spinner.d.ts.map +1 -0
- package/dist/cli/components/Spinner.js +45 -0
- package/dist/cli/components/Spinner.js.map +1 -0
- package/dist/cli/components/index.d.ts +12 -0
- package/dist/cli/components/index.d.ts.map +1 -0
- package/dist/cli/components/index.js +12 -0
- package/dist/cli/components/index.js.map +1 -0
- package/dist/cli/components/theme.d.ts +31 -0
- package/dist/cli/components/theme.d.ts.map +1 -0
- package/dist/cli/components/theme.js +36 -0
- package/dist/cli/components/theme.js.map +1 -0
- package/dist/cli/index-legacy.d.ts +7 -0
- package/dist/cli/index-legacy.d.ts.map +1 -0
- package/dist/cli/index-legacy.js +431 -0
- package/dist/cli/index-legacy.js.map +1 -0
- package/dist/cli/index.d.ts +7 -0
- package/dist/cli/index.d.ts.map +1 -0
- package/dist/cli/index.js +116 -0
- package/dist/cli/index.js.map +1 -0
- package/dist/cli/ink-cli.d.ts +7 -0
- package/dist/cli/ink-cli.d.ts.map +1 -0
- package/dist/cli/ink-cli.js +105 -0
- package/dist/cli/ink-cli.js.map +1 -0
- package/dist/cli/session-picker.d.ts +16 -0
- package/dist/cli/session-picker.d.ts.map +1 -0
- package/dist/cli/session-picker.js +280 -0
- package/dist/cli/session-picker.js.map +1 -0
- package/dist/cli/ui.d.ts +61 -0
- package/dist/cli/ui.d.ts.map +1 -0
- package/dist/cli/ui.js +364 -0
- package/dist/cli/ui.js.map +1 -0
- package/dist/config/index.d.ts +7 -0
- package/dist/config/index.d.ts.map +1 -0
- package/dist/config/index.js +6 -0
- package/dist/config/index.js.map +1 -0
- package/dist/config/manager.d.ts +31 -0
- package/dist/config/manager.d.ts.map +1 -0
- package/dist/config/manager.js +65 -0
- package/dist/config/manager.js.map +1 -0
- package/dist/config/types.d.ts +22 -0
- package/dist/config/types.d.ts.map +1 -0
- package/dist/config/types.js +6 -0
- package/dist/config/types.js.map +1 -0
- package/dist/index.d.ts +12 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +21 -0
- package/dist/index.js.map +1 -0
- package/dist/memory/index.d.ts +10 -0
- package/dist/memory/index.d.ts.map +1 -0
- package/dist/memory/index.js +9 -0
- package/dist/memory/index.js.map +1 -0
- package/dist/memory/init.d.ts +20 -0
- package/dist/memory/init.d.ts.map +1 -0
- package/dist/memory/init.js +332 -0
- package/dist/memory/init.js.map +1 -0
- package/dist/memory/manager.d.ts +85 -0
- package/dist/memory/manager.d.ts.map +1 -0
- package/dist/memory/manager.js +234 -0
- package/dist/memory/manager.js.map +1 -0
- package/dist/memory/types.d.ts +74 -0
- package/dist/memory/types.d.ts.map +1 -0
- package/dist/memory/types.js +6 -0
- package/dist/memory/types.js.map +1 -0
- package/dist/permissions/index.d.ts +7 -0
- package/dist/permissions/index.d.ts.map +1 -0
- package/dist/permissions/index.js +6 -0
- package/dist/permissions/index.js.map +1 -0
- package/dist/permissions/manager.d.ts +32 -0
- package/dist/permissions/manager.d.ts.map +1 -0
- package/dist/permissions/manager.js +79 -0
- package/dist/permissions/manager.js.map +1 -0
- package/dist/permissions/types.d.ts +14 -0
- package/dist/permissions/types.d.ts.map +1 -0
- package/dist/permissions/types.js +17 -0
- package/dist/permissions/types.js.map +1 -0
- package/dist/providers/anthropic.d.ts +20 -0
- package/dist/providers/anthropic.d.ts.map +1 -0
- package/dist/providers/anthropic.js +185 -0
- package/dist/providers/anthropic.js.map +1 -0
- package/dist/providers/gemini.d.ts +21 -0
- package/dist/providers/gemini.d.ts.map +1 -0
- package/dist/providers/gemini.js +241 -0
- package/dist/providers/gemini.js.map +1 -0
- package/dist/providers/index.d.ts +34 -0
- package/dist/providers/index.d.ts.map +1 -0
- package/dist/providers/index.js +72 -0
- package/dist/providers/index.js.map +1 -0
- package/dist/providers/openai.d.ts +19 -0
- package/dist/providers/openai.d.ts.map +1 -0
- package/dist/providers/openai.js +221 -0
- package/dist/providers/openai.js.map +1 -0
- package/dist/providers/types.d.ts +125 -0
- package/dist/providers/types.d.ts.map +1 -0
- package/dist/providers/types.js +6 -0
- package/dist/providers/types.js.map +1 -0
- package/dist/session/index.d.ts +6 -0
- package/dist/session/index.d.ts.map +1 -0
- package/dist/session/index.js +6 -0
- package/dist/session/index.js.map +1 -0
- package/dist/session/manager.d.ts +101 -0
- package/dist/session/manager.d.ts.map +1 -0
- package/dist/session/manager.js +295 -0
- package/dist/session/manager.js.map +1 -0
- package/dist/session/types.d.ts +39 -0
- package/dist/session/types.d.ts.map +1 -0
- package/dist/session/types.js +10 -0
- package/dist/session/types.js.map +1 -0
- package/dist/tools/builtin/bash.d.ts +7 -0
- package/dist/tools/builtin/bash.d.ts.map +1 -0
- package/dist/tools/builtin/bash.js +80 -0
- package/dist/tools/builtin/bash.js.map +1 -0
- package/dist/tools/builtin/edit.d.ts +7 -0
- package/dist/tools/builtin/edit.d.ts.map +1 -0
- package/dist/tools/builtin/edit.js +32 -0
- package/dist/tools/builtin/edit.js.map +1 -0
- package/dist/tools/builtin/glob.d.ts +7 -0
- package/dist/tools/builtin/glob.d.ts.map +1 -0
- package/dist/tools/builtin/glob.js +36 -0
- package/dist/tools/builtin/glob.js.map +1 -0
- package/dist/tools/builtin/grep.d.ts +7 -0
- package/dist/tools/builtin/grep.d.ts.map +1 -0
- package/dist/tools/builtin/grep.js +59 -0
- package/dist/tools/builtin/grep.js.map +1 -0
- package/dist/tools/builtin/read.d.ts +7 -0
- package/dist/tools/builtin/read.d.ts.map +1 -0
- package/dist/tools/builtin/read.js +29 -0
- package/dist/tools/builtin/read.js.map +1 -0
- package/dist/tools/builtin/write.d.ts +7 -0
- package/dist/tools/builtin/write.d.ts.map +1 -0
- package/dist/tools/builtin/write.js +24 -0
- package/dist/tools/builtin/write.js.map +1 -0
- package/dist/tools/index.d.ts +38 -0
- package/dist/tools/index.d.ts.map +1 -0
- package/dist/tools/index.js +32 -0
- package/dist/tools/index.js.map +1 -0
- package/dist/tools/registry.d.ts +22 -0
- package/dist/tools/registry.d.ts.map +1 -0
- package/dist/tools/registry.js +71 -0
- package/dist/tools/registry.js.map +1 -0
- package/dist/tools/types.d.ts +62 -0
- package/dist/tools/types.d.ts.map +1 -0
- package/dist/tools/types.js +126 -0
- package/dist/tools/types.js.map +1 -0
- package/docs/README.md +16 -0
- package/docs/proposals/0001-web-fetch-tool.md +293 -0
- package/docs/proposals/0002-web-search-tool.md +306 -0
- package/docs/proposals/0003-task-subagents.md +333 -0
- package/docs/proposals/0004-plan-mode.md +338 -0
- package/docs/proposals/0005-todo-system.md +299 -0
- package/docs/proposals/0006-memory-system.md +539 -0
- package/docs/proposals/0007-context-management.md +429 -0
- package/docs/proposals/0008-checkpointing.md +327 -0
- package/docs/proposals/0009-hooks-system.md +343 -0
- package/docs/proposals/0010-mcp-integration.md +382 -0
- package/docs/proposals/0011-custom-commands.md +374 -0
- package/docs/proposals/0012-ask-user-question.md +317 -0
- package/docs/proposals/0013-multi-edit-tool.md +345 -0
- package/docs/proposals/0014-lsp-tool.md +478 -0
- package/docs/proposals/0015-ls-tool.md +407 -0
- package/docs/proposals/0016-kill-shell-tool.md +455 -0
- package/docs/proposals/0017-background-tasks.md +489 -0
- package/docs/proposals/0018-parallel-tool-execution.md +415 -0
- package/docs/proposals/0019-session-enhancements.md +462 -0
- package/docs/proposals/0020-session-summarization.md +447 -0
- package/docs/proposals/0021-skills-system.md +409 -0
- package/docs/proposals/0022-plugin-system.md +467 -0
- package/docs/proposals/0023-permission-enhancements.md +470 -0
- package/docs/proposals/0024-keyboard-shortcuts.md +443 -0
- package/docs/proposals/0025-cost-tracking.md +447 -0
- package/docs/proposals/0026-git-integration.md +475 -0
- package/docs/proposals/0027-enhanced-read-tool.md +514 -0
- package/docs/proposals/0028-enhanced-bash-tool.md +511 -0
- package/docs/proposals/0029-notebook-edit-tool.md +413 -0
- package/docs/proposals/0030-plugin-marketplace.md +360 -0
- package/docs/proposals/0031-command-suggestions.md +295 -0
- package/docs/proposals/0032-ide-integrations.md +328 -0
- package/docs/proposals/0033-enterprise-deployment.md +221 -0
- package/docs/proposals/0034-sandboxing.md +273 -0
- package/docs/proposals/0035-auto-updater.md +311 -0
- package/docs/proposals/0036-enhanced-glob-tool.md +267 -0
- package/docs/proposals/0037-enhanced-grep-tool.md +360 -0
- package/docs/proposals/0038-interactive-cli-ui.md +373 -0
- package/docs/proposals/0039-streaming-enhancements.md +359 -0
- package/docs/proposals/0040-multi-provider-enhancements.md +369 -0
- package/docs/proposals/README.md +84 -0
- package/docs/proposals/TEMPLATE.md +57 -0
- package/docs/proposals/research/claude-code-research.md +307 -0
- package/examples/agent-demo.ts +115 -0
- package/examples/basic.ts +166 -0
- package/package.json +50 -0
- package/src/agent/agent.ts +276 -0
- package/src/agent/index.ts +6 -0
- package/src/agent/types.ts +62 -0
- package/src/cli/components/App.tsx +565 -0
- package/src/cli/components/CommandSuggestions.tsx +58 -0
- package/src/cli/components/Header.tsx +36 -0
- package/src/cli/components/Input.tsx +60 -0
- package/src/cli/components/Logo.tsx +16 -0
- package/src/cli/components/Messages.tsx +210 -0
- package/src/cli/components/ModelSelector.tsx +135 -0
- package/src/cli/components/Spinner.tsx +72 -0
- package/src/cli/components/index.ts +21 -0
- package/src/cli/components/theme.ts +36 -0
- package/src/cli/index.tsx +136 -0
- package/src/config/index.ts +7 -0
- package/src/config/manager.ts +77 -0
- package/src/config/types.ts +25 -0
- package/src/index.ts +86 -0
- package/src/permissions/index.ts +7 -0
- package/src/permissions/manager.ts +97 -0
- package/src/permissions/types.ts +29 -0
- package/src/providers/anthropic.ts +224 -0
- package/src/providers/gemini.ts +295 -0
- package/src/providers/index.ts +97 -0
- package/src/providers/openai.ts +261 -0
- package/src/providers/types.ts +181 -0
- package/src/session/index.ts +6 -0
- package/src/session/manager.ts +354 -0
- package/src/session/types.ts +49 -0
- package/src/tools/builtin/bash.ts +92 -0
- package/src/tools/builtin/edit.ts +37 -0
- package/src/tools/builtin/glob.ts +42 -0
- package/src/tools/builtin/grep.ts +67 -0
- package/src/tools/builtin/read.ts +34 -0
- package/src/tools/builtin/write.ts +27 -0
- package/src/tools/index.ts +36 -0
- package/src/tools/registry.ts +83 -0
- package/src/tools/types.ts +172 -0
- package/tsconfig.json +21 -0
|
@@ -0,0 +1,267 @@
|
|
|
1
|
+
# Proposal: Enhanced Glob Tool
|
|
2
|
+
|
|
3
|
+
- **Proposal ID**: 0036
|
|
4
|
+
- **Author**: mycode team
|
|
5
|
+
- **Status**: Draft
|
|
6
|
+
- **Created**: 2025-01-15
|
|
7
|
+
- **Updated**: 2025-01-15
|
|
8
|
+
|
|
9
|
+
## Summary
|
|
10
|
+
|
|
11
|
+
Enhance the Glob tool with advanced pattern matching, file metadata, sorting options, and result formatting for more powerful file discovery.
|
|
12
|
+
|
|
13
|
+
## Motivation
|
|
14
|
+
|
|
15
|
+
The current Glob tool is basic:
|
|
16
|
+
|
|
17
|
+
1. **Pattern only**: No metadata in results
|
|
18
|
+
2. **No sorting**: Results in arbitrary order
|
|
19
|
+
3. **Limited patterns**: Basic glob only
|
|
20
|
+
4. **No exclusions**: Can't ignore patterns
|
|
21
|
+
5. **Flat output**: Just file paths
|
|
22
|
+
|
|
23
|
+
Enhanced glob enables sophisticated file discovery.
|
|
24
|
+
|
|
25
|
+
## Claude Code Reference
|
|
26
|
+
|
|
27
|
+
Claude Code's Glob tool provides fast pattern matching:
|
|
28
|
+
|
|
29
|
+
### From Tool Description
|
|
30
|
+
```
|
|
31
|
+
- Fast file pattern matching for any codebase size
|
|
32
|
+
- Supports glob patterns like "**/*.js" or "src/**/*.ts"
|
|
33
|
+
- Returns matching file paths sorted by modification time
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
### Key Features
|
|
37
|
+
- Sort by modification time
|
|
38
|
+
- Size-based filtering
|
|
39
|
+
- Exclusion patterns
|
|
40
|
+
|
|
41
|
+
## Detailed Design
|
|
42
|
+
|
|
43
|
+
### API Design
|
|
44
|
+
|
|
45
|
+
```typescript
|
|
46
|
+
// src/tools/glob/types.ts
|
|
47
|
+
interface GlobInput {
|
|
48
|
+
pattern: string;
|
|
49
|
+
path?: string; // Base directory
|
|
50
|
+
ignore?: string[]; // Exclusion patterns
|
|
51
|
+
type?: 'file' | 'directory' | 'all';
|
|
52
|
+
sort?: 'name' | 'modified' | 'size' | 'type';
|
|
53
|
+
reverse?: boolean;
|
|
54
|
+
limit?: number;
|
|
55
|
+
includeMetadata?: boolean; // Include file stats
|
|
56
|
+
dot?: boolean; // Include dotfiles
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
interface GlobMatch {
|
|
60
|
+
path: string; // Relative path
|
|
61
|
+
absolutePath: string;
|
|
62
|
+
type: 'file' | 'directory' | 'symlink';
|
|
63
|
+
// Metadata (when includeMetadata=true)
|
|
64
|
+
size?: number;
|
|
65
|
+
modified?: string;
|
|
66
|
+
created?: string;
|
|
67
|
+
permissions?: string;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
interface GlobOutput {
|
|
71
|
+
success: boolean;
|
|
72
|
+
matches: GlobMatch[];
|
|
73
|
+
pattern: string;
|
|
74
|
+
total: number;
|
|
75
|
+
truncated: boolean;
|
|
76
|
+
error?: string;
|
|
77
|
+
}
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
### Enhanced Glob Implementation
|
|
81
|
+
|
|
82
|
+
```typescript
|
|
83
|
+
// src/tools/glob/glob-tool.ts
|
|
84
|
+
const globTool: Tool<GlobInput> = {
|
|
85
|
+
name: 'Glob',
|
|
86
|
+
description: `Fast file pattern matching.
|
|
87
|
+
|
|
88
|
+
Parameters:
|
|
89
|
+
- pattern: Glob pattern (e.g., "**/*.ts", "src/**/*.{js,jsx}")
|
|
90
|
+
- path: Base directory (default: cwd)
|
|
91
|
+
- ignore: Patterns to exclude (e.g., ["node_modules/**"])
|
|
92
|
+
- type: Match files, directories, or all
|
|
93
|
+
- sort: Sort by name, modified, size, or type (default: modified)
|
|
94
|
+
- reverse: Reverse sort order
|
|
95
|
+
- limit: Maximum results
|
|
96
|
+
- includeMetadata: Include file stats (size, modified, etc.)
|
|
97
|
+
- dot: Include dotfiles (default: false)
|
|
98
|
+
|
|
99
|
+
Returns matching file paths sorted by modification time.
|
|
100
|
+
`,
|
|
101
|
+
parameters: z.object({
|
|
102
|
+
pattern: z.string(),
|
|
103
|
+
path: z.string().optional(),
|
|
104
|
+
ignore: z.array(z.string()).optional(),
|
|
105
|
+
type: z.enum(['file', 'directory', 'all']).optional(),
|
|
106
|
+
sort: z.enum(['name', 'modified', 'size', 'type']).optional(),
|
|
107
|
+
reverse: z.boolean().optional(),
|
|
108
|
+
limit: z.number().int().positive().optional(),
|
|
109
|
+
includeMetadata: z.boolean().optional(),
|
|
110
|
+
dot: z.boolean().optional()
|
|
111
|
+
}),
|
|
112
|
+
execute: async (input, context) => {
|
|
113
|
+
const basePath = input.path
|
|
114
|
+
? path.resolve(context.cwd, input.path)
|
|
115
|
+
: context.cwd;
|
|
116
|
+
|
|
117
|
+
const options: GlobOptions = {
|
|
118
|
+
cwd: basePath,
|
|
119
|
+
ignore: input.ignore || ['**/node_modules/**', '**/.git/**'],
|
|
120
|
+
dot: input.dot || false,
|
|
121
|
+
onlyFiles: input.type === 'file',
|
|
122
|
+
onlyDirectories: input.type === 'directory'
|
|
123
|
+
};
|
|
124
|
+
|
|
125
|
+
try {
|
|
126
|
+
const paths = await glob(input.pattern, options);
|
|
127
|
+
|
|
128
|
+
// Build matches with optional metadata
|
|
129
|
+
let matches: GlobMatch[] = await Promise.all(
|
|
130
|
+
paths.map(async (p) => {
|
|
131
|
+
const absolutePath = path.join(basePath, p);
|
|
132
|
+
const match: GlobMatch = {
|
|
133
|
+
path: p,
|
|
134
|
+
absolutePath,
|
|
135
|
+
type: 'file'
|
|
136
|
+
};
|
|
137
|
+
|
|
138
|
+
if (input.includeMetadata) {
|
|
139
|
+
const stats = await fs.stat(absolutePath);
|
|
140
|
+
match.size = stats.size;
|
|
141
|
+
match.modified = stats.mtime.toISOString();
|
|
142
|
+
match.created = stats.birthtime.toISOString();
|
|
143
|
+
match.type = stats.isDirectory() ? 'directory'
|
|
144
|
+
: stats.isSymbolicLink() ? 'symlink' : 'file';
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
return match;
|
|
148
|
+
})
|
|
149
|
+
);
|
|
150
|
+
|
|
151
|
+
// Sort
|
|
152
|
+
matches = sortMatches(matches, input.sort || 'modified', input.reverse);
|
|
153
|
+
|
|
154
|
+
// Limit
|
|
155
|
+
const truncated = input.limit ? matches.length > input.limit : false;
|
|
156
|
+
if (input.limit) {
|
|
157
|
+
matches = matches.slice(0, input.limit);
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
return {
|
|
161
|
+
success: true,
|
|
162
|
+
matches,
|
|
163
|
+
pattern: input.pattern,
|
|
164
|
+
total: paths.length,
|
|
165
|
+
truncated
|
|
166
|
+
};
|
|
167
|
+
} catch (error) {
|
|
168
|
+
return {
|
|
169
|
+
success: false,
|
|
170
|
+
matches: [],
|
|
171
|
+
pattern: input.pattern,
|
|
172
|
+
total: 0,
|
|
173
|
+
truncated: false,
|
|
174
|
+
error: error instanceof Error ? error.message : 'Unknown error'
|
|
175
|
+
};
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
};
|
|
179
|
+
|
|
180
|
+
function sortMatches(
|
|
181
|
+
matches: GlobMatch[],
|
|
182
|
+
sortBy: string,
|
|
183
|
+
reverse?: boolean
|
|
184
|
+
): GlobMatch[] {
|
|
185
|
+
const sorted = [...matches];
|
|
186
|
+
|
|
187
|
+
sorted.sort((a, b) => {
|
|
188
|
+
switch (sortBy) {
|
|
189
|
+
case 'name':
|
|
190
|
+
return a.path.localeCompare(b.path);
|
|
191
|
+
case 'modified':
|
|
192
|
+
return (b.modified || '').localeCompare(a.modified || '');
|
|
193
|
+
case 'size':
|
|
194
|
+
return (b.size || 0) - (a.size || 0);
|
|
195
|
+
case 'type':
|
|
196
|
+
return a.type.localeCompare(b.type);
|
|
197
|
+
default:
|
|
198
|
+
return 0;
|
|
199
|
+
}
|
|
200
|
+
});
|
|
201
|
+
|
|
202
|
+
return reverse ? sorted.reverse() : sorted;
|
|
203
|
+
}
|
|
204
|
+
```
|
|
205
|
+
|
|
206
|
+
### File Changes
|
|
207
|
+
|
|
208
|
+
| File | Action | Description |
|
|
209
|
+
|------|--------|-------------|
|
|
210
|
+
| `src/tools/glob/types.ts` | Create | Type definitions |
|
|
211
|
+
| `src/tools/glob/glob-tool.ts` | Modify | Enhanced implementation |
|
|
212
|
+
| `src/tools/glob/utils.ts` | Create | Sorting utilities |
|
|
213
|
+
|
|
214
|
+
## User Experience
|
|
215
|
+
|
|
216
|
+
### Basic Pattern
|
|
217
|
+
```
|
|
218
|
+
Agent: [Glob: pattern="src/**/*.ts"]
|
|
219
|
+
|
|
220
|
+
Found 24 TypeScript files:
|
|
221
|
+
src/index.ts
|
|
222
|
+
src/cli/index.ts
|
|
223
|
+
src/agent/agent.ts
|
|
224
|
+
...
|
|
225
|
+
```
|
|
226
|
+
|
|
227
|
+
### With Metadata
|
|
228
|
+
```
|
|
229
|
+
Agent: [Glob: pattern="*.md", includeMetadata=true, sort="modified"]
|
|
230
|
+
|
|
231
|
+
┌─ Markdown Files ──────────────────────────────────┐
|
|
232
|
+
│ File Size Modified │
|
|
233
|
+
├───────────────────────────────────────────────────┤
|
|
234
|
+
│ README.md 4.2 KB 2025-01-15 10:30 │
|
|
235
|
+
│ CHANGELOG.md 12.8 KB 2025-01-14 16:45 │
|
|
236
|
+
│ CONTRIBUTING.md 2.1 KB 2025-01-10 09:15 │
|
|
237
|
+
└───────────────────────────────────────────────────┘
|
|
238
|
+
```
|
|
239
|
+
|
|
240
|
+
### With Exclusions
|
|
241
|
+
```
|
|
242
|
+
Agent: [Glob: pattern="**/*.js", ignore=["node_modules/**", "dist/**"]]
|
|
243
|
+
|
|
244
|
+
Found 15 JavaScript files (excluding node_modules, dist):
|
|
245
|
+
scripts/build.js
|
|
246
|
+
scripts/deploy.js
|
|
247
|
+
...
|
|
248
|
+
```
|
|
249
|
+
|
|
250
|
+
## Security Considerations
|
|
251
|
+
|
|
252
|
+
1. Path traversal prevention
|
|
253
|
+
2. Symlink loop detection
|
|
254
|
+
3. Result size limits
|
|
255
|
+
4. Performance limits
|
|
256
|
+
|
|
257
|
+
## Migration Path
|
|
258
|
+
|
|
259
|
+
1. **Phase 1**: Sorting and limits
|
|
260
|
+
2. **Phase 2**: Metadata support
|
|
261
|
+
3. **Phase 3**: Advanced patterns
|
|
262
|
+
4. **Phase 4**: Performance optimization
|
|
263
|
+
|
|
264
|
+
## References
|
|
265
|
+
|
|
266
|
+
- [fast-glob](https://github.com/mrmlnc/fast-glob)
|
|
267
|
+
- [Glob Patterns](https://en.wikipedia.org/wiki/Glob_(programming))
|
|
@@ -0,0 +1,360 @@
|
|
|
1
|
+
# Proposal: Enhanced Grep Tool
|
|
2
|
+
|
|
3
|
+
- **Proposal ID**: 0037
|
|
4
|
+
- **Author**: mycode team
|
|
5
|
+
- **Status**: Draft
|
|
6
|
+
- **Created**: 2025-01-15
|
|
7
|
+
- **Updated**: 2025-01-15
|
|
8
|
+
|
|
9
|
+
## Summary
|
|
10
|
+
|
|
11
|
+
Enhance the Grep tool with advanced regex features, context lines, multiline matching, output modes, and performance optimizations for powerful content searching.
|
|
12
|
+
|
|
13
|
+
## Motivation
|
|
14
|
+
|
|
15
|
+
The current Grep tool has limitations:
|
|
16
|
+
|
|
17
|
+
1. **Basic regex**: No multiline support
|
|
18
|
+
2. **No context**: Just matching lines
|
|
19
|
+
3. **Single mode**: Only line output
|
|
20
|
+
4. **No pagination**: All results at once
|
|
21
|
+
5. **Limited control**: Few options
|
|
22
|
+
|
|
23
|
+
Enhanced grep enables sophisticated content search.
|
|
24
|
+
|
|
25
|
+
## Claude Code Reference
|
|
26
|
+
|
|
27
|
+
Claude Code's Grep tool provides comprehensive search:
|
|
28
|
+
|
|
29
|
+
### From Tool Description
|
|
30
|
+
```
|
|
31
|
+
- Supports full regex syntax (e.g., "log.*Error", "function\\s+\\w+")
|
|
32
|
+
- Filter files with glob or type parameter
|
|
33
|
+
- Output modes: "content", "files_with_matches", "count"
|
|
34
|
+
- Context lines with -A/-B/-C
|
|
35
|
+
- Multiline matching with multiline: true
|
|
36
|
+
- Line numbers with -n
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
### Key Features
|
|
40
|
+
- Multiple output modes
|
|
41
|
+
- Context lines (before/after)
|
|
42
|
+
- File type filtering
|
|
43
|
+
- Multiline patterns
|
|
44
|
+
- Offset/limit pagination
|
|
45
|
+
|
|
46
|
+
## Detailed Design
|
|
47
|
+
|
|
48
|
+
### API Design
|
|
49
|
+
|
|
50
|
+
```typescript
|
|
51
|
+
// src/tools/grep/types.ts
|
|
52
|
+
type OutputMode = 'content' | 'files_with_matches' | 'count';
|
|
53
|
+
|
|
54
|
+
interface GrepInput {
|
|
55
|
+
pattern: string;
|
|
56
|
+
path?: string;
|
|
57
|
+
glob?: string; // File pattern filter
|
|
58
|
+
type?: string; // File type (js, py, etc.)
|
|
59
|
+
output_mode?: OutputMode;
|
|
60
|
+
'-A'?: number; // Lines after match
|
|
61
|
+
'-B'?: number; // Lines before match
|
|
62
|
+
'-C'?: number; // Context lines (both)
|
|
63
|
+
'-i'?: boolean; // Case insensitive
|
|
64
|
+
'-n'?: boolean; // Show line numbers
|
|
65
|
+
multiline?: boolean; // Cross-line matching
|
|
66
|
+
head_limit?: number; // Limit results
|
|
67
|
+
offset?: number; // Skip results
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
interface GrepMatch {
|
|
71
|
+
file: string;
|
|
72
|
+
line: number;
|
|
73
|
+
column: number;
|
|
74
|
+
content: string;
|
|
75
|
+
context?: {
|
|
76
|
+
before: string[];
|
|
77
|
+
after: string[];
|
|
78
|
+
};
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
interface GrepOutput {
|
|
82
|
+
success: boolean;
|
|
83
|
+
mode: OutputMode;
|
|
84
|
+
matches?: GrepMatch[];
|
|
85
|
+
files?: string[];
|
|
86
|
+
counts?: Record<string, number>;
|
|
87
|
+
total: number;
|
|
88
|
+
truncated: boolean;
|
|
89
|
+
error?: string;
|
|
90
|
+
}
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
### Enhanced Grep Implementation
|
|
94
|
+
|
|
95
|
+
```typescript
|
|
96
|
+
// src/tools/grep/grep-tool.ts
|
|
97
|
+
const grepTool: Tool<GrepInput> = {
|
|
98
|
+
name: 'Grep',
|
|
99
|
+
description: `Search file contents with regex patterns.
|
|
100
|
+
|
|
101
|
+
Parameters:
|
|
102
|
+
- pattern: Regex pattern to search for
|
|
103
|
+
- path: Directory or file to search (default: cwd)
|
|
104
|
+
- glob: Filter files by glob pattern (e.g., "*.ts")
|
|
105
|
+
- type: Filter by file type (js, py, rust, go, etc.)
|
|
106
|
+
- output_mode: "content", "files_with_matches", or "count"
|
|
107
|
+
- -A: Lines to show after match
|
|
108
|
+
- -B: Lines to show before match
|
|
109
|
+
- -C: Lines to show before and after match
|
|
110
|
+
- -i: Case insensitive search
|
|
111
|
+
- -n: Show line numbers (default: true)
|
|
112
|
+
- multiline: Enable cross-line matching
|
|
113
|
+
- head_limit: Limit number of results
|
|
114
|
+
- offset: Skip first N results
|
|
115
|
+
|
|
116
|
+
Output modes:
|
|
117
|
+
- content: Show matching lines with context
|
|
118
|
+
- files_with_matches: Show only file paths
|
|
119
|
+
- count: Show match counts per file
|
|
120
|
+
`,
|
|
121
|
+
parameters: z.object({
|
|
122
|
+
pattern: z.string(),
|
|
123
|
+
path: z.string().optional(),
|
|
124
|
+
glob: z.string().optional(),
|
|
125
|
+
type: z.string().optional(),
|
|
126
|
+
output_mode: z.enum(['content', 'files_with_matches', 'count']).optional(),
|
|
127
|
+
'-A': z.number().int().nonnegative().optional(),
|
|
128
|
+
'-B': z.number().int().nonnegative().optional(),
|
|
129
|
+
'-C': z.number().int().nonnegative().optional(),
|
|
130
|
+
'-i': z.boolean().optional(),
|
|
131
|
+
'-n': z.boolean().optional().default(true),
|
|
132
|
+
multiline: z.boolean().optional(),
|
|
133
|
+
head_limit: z.number().int().positive().optional(),
|
|
134
|
+
offset: z.number().int().nonnegative().optional()
|
|
135
|
+
}),
|
|
136
|
+
execute: async (input, context) => {
|
|
137
|
+
return grepExecutor.search(input, context);
|
|
138
|
+
}
|
|
139
|
+
};
|
|
140
|
+
|
|
141
|
+
class GrepExecutor {
|
|
142
|
+
async search(input: GrepInput, context: ToolContext): Promise<GrepOutput> {
|
|
143
|
+
const basePath = input.path
|
|
144
|
+
? path.resolve(context.cwd, input.path)
|
|
145
|
+
: context.cwd;
|
|
146
|
+
|
|
147
|
+
// Build regex
|
|
148
|
+
let flags = 'g';
|
|
149
|
+
if (input['-i']) flags += 'i';
|
|
150
|
+
if (input.multiline) flags += 'ms';
|
|
151
|
+
|
|
152
|
+
const regex = new RegExp(input.pattern, flags);
|
|
153
|
+
|
|
154
|
+
// Find files to search
|
|
155
|
+
const files = await this.findFiles(basePath, input.glob, input.type);
|
|
156
|
+
|
|
157
|
+
// Search based on output mode
|
|
158
|
+
const mode = input.output_mode || 'files_with_matches';
|
|
159
|
+
|
|
160
|
+
switch (mode) {
|
|
161
|
+
case 'content':
|
|
162
|
+
return this.searchContent(files, regex, input);
|
|
163
|
+
case 'files_with_matches':
|
|
164
|
+
return this.searchFilesOnly(files, regex, input);
|
|
165
|
+
case 'count':
|
|
166
|
+
return this.searchCount(files, regex, input);
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
private async searchContent(
|
|
171
|
+
files: string[],
|
|
172
|
+
regex: RegExp,
|
|
173
|
+
input: GrepInput
|
|
174
|
+
): Promise<GrepOutput> {
|
|
175
|
+
const matches: GrepMatch[] = [];
|
|
176
|
+
const contextBefore = input['-B'] || input['-C'] || 0;
|
|
177
|
+
const contextAfter = input['-A'] || input['-C'] || 0;
|
|
178
|
+
|
|
179
|
+
for (const file of files) {
|
|
180
|
+
const content = await fs.readFile(file, 'utf-8');
|
|
181
|
+
const lines = content.split('\n');
|
|
182
|
+
|
|
183
|
+
for (let i = 0; i < lines.length; i++) {
|
|
184
|
+
const line = lines[i];
|
|
185
|
+
let match = regex.exec(line);
|
|
186
|
+
|
|
187
|
+
while (match) {
|
|
188
|
+
const grepMatch: GrepMatch = {
|
|
189
|
+
file: path.relative(process.cwd(), file),
|
|
190
|
+
line: i + 1,
|
|
191
|
+
column: match.index + 1,
|
|
192
|
+
content: line
|
|
193
|
+
};
|
|
194
|
+
|
|
195
|
+
if (contextBefore > 0 || contextAfter > 0) {
|
|
196
|
+
grepMatch.context = {
|
|
197
|
+
before: lines.slice(Math.max(0, i - contextBefore), i),
|
|
198
|
+
after: lines.slice(i + 1, i + 1 + contextAfter)
|
|
199
|
+
};
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
matches.push(grepMatch);
|
|
203
|
+
match = regex.exec(line);
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
// Reset regex for next line
|
|
207
|
+
regex.lastIndex = 0;
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
// Apply offset and limit
|
|
212
|
+
const offset = input.offset || 0;
|
|
213
|
+
const limit = input.head_limit;
|
|
214
|
+
const truncated = limit ? matches.length > offset + limit : false;
|
|
215
|
+
const paginatedMatches = limit
|
|
216
|
+
? matches.slice(offset, offset + limit)
|
|
217
|
+
: matches.slice(offset);
|
|
218
|
+
|
|
219
|
+
return {
|
|
220
|
+
success: true,
|
|
221
|
+
mode: 'content',
|
|
222
|
+
matches: paginatedMatches,
|
|
223
|
+
total: matches.length,
|
|
224
|
+
truncated
|
|
225
|
+
};
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
private async findFiles(
|
|
229
|
+
basePath: string,
|
|
230
|
+
glob?: string,
|
|
231
|
+
type?: string
|
|
232
|
+
): Promise<string[]> {
|
|
233
|
+
let pattern = '**/*';
|
|
234
|
+
|
|
235
|
+
if (glob) {
|
|
236
|
+
pattern = glob;
|
|
237
|
+
} else if (type) {
|
|
238
|
+
const extensions = this.getExtensionsForType(type);
|
|
239
|
+
pattern = `**/*.{${extensions.join(',')}}`;
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
return globby(pattern, {
|
|
243
|
+
cwd: basePath,
|
|
244
|
+
absolute: true,
|
|
245
|
+
ignore: ['**/node_modules/**', '**/.git/**']
|
|
246
|
+
});
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
private getExtensionsForType(type: string): string[] {
|
|
250
|
+
const typeMap: Record<string, string[]> = {
|
|
251
|
+
js: ['js', 'mjs', 'cjs'],
|
|
252
|
+
ts: ['ts', 'tsx', 'mts', 'cts'],
|
|
253
|
+
py: ['py', 'pyi'],
|
|
254
|
+
go: ['go'],
|
|
255
|
+
rust: ['rs'],
|
|
256
|
+
java: ['java'],
|
|
257
|
+
c: ['c', 'h'],
|
|
258
|
+
cpp: ['cpp', 'cxx', 'cc', 'hpp', 'hxx'],
|
|
259
|
+
md: ['md', 'markdown'],
|
|
260
|
+
json: ['json'],
|
|
261
|
+
yaml: ['yaml', 'yml']
|
|
262
|
+
};
|
|
263
|
+
return typeMap[type] || [type];
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
```
|
|
267
|
+
|
|
268
|
+
### File Changes
|
|
269
|
+
|
|
270
|
+
| File | Action | Description |
|
|
271
|
+
|------|--------|-------------|
|
|
272
|
+
| `src/tools/grep/types.ts` | Create | Type definitions |
|
|
273
|
+
| `src/tools/grep/grep-tool.ts` | Modify | Enhanced implementation |
|
|
274
|
+
| `src/tools/grep/executor.ts` | Create | Search logic |
|
|
275
|
+
| `src/tools/grep/utils.ts` | Create | Utilities |
|
|
276
|
+
|
|
277
|
+
## User Experience
|
|
278
|
+
|
|
279
|
+
### Content with Context
|
|
280
|
+
```
|
|
281
|
+
Agent: [Grep: pattern="TODO", -C=2, output_mode="content"]
|
|
282
|
+
|
|
283
|
+
Found 5 matches:
|
|
284
|
+
|
|
285
|
+
src/agent/agent.ts:45
|
|
286
|
+
43: async function processMessage() {
|
|
287
|
+
44: // Setup connection
|
|
288
|
+
> 45: // TODO: Add retry logic
|
|
289
|
+
46: const response = await fetch(url);
|
|
290
|
+
47: }
|
|
291
|
+
|
|
292
|
+
src/cli/ui.ts:112
|
|
293
|
+
110: function renderOutput() {
|
|
294
|
+
111: // Format the response
|
|
295
|
+
> 112: // TODO: Add syntax highlighting
|
|
296
|
+
113: console.log(output);
|
|
297
|
+
114: }
|
|
298
|
+
...
|
|
299
|
+
```
|
|
300
|
+
|
|
301
|
+
### Files Only Mode
|
|
302
|
+
```
|
|
303
|
+
Agent: [Grep: pattern="import.*React", output_mode="files_with_matches", type="ts"]
|
|
304
|
+
|
|
305
|
+
Files containing pattern:
|
|
306
|
+
src/components/Button.tsx
|
|
307
|
+
src/components/Modal.tsx
|
|
308
|
+
src/pages/Home.tsx
|
|
309
|
+
src/pages/Settings.tsx
|
|
310
|
+
src/App.tsx
|
|
311
|
+
|
|
312
|
+
5 files matched
|
|
313
|
+
```
|
|
314
|
+
|
|
315
|
+
### Count Mode
|
|
316
|
+
```
|
|
317
|
+
Agent: [Grep: pattern="console\\.log", output_mode="count"]
|
|
318
|
+
|
|
319
|
+
Match counts:
|
|
320
|
+
src/cli/index.ts 12
|
|
321
|
+
src/tools/bash.ts 8
|
|
322
|
+
src/agent/agent.ts 5
|
|
323
|
+
src/utils/debug.ts 23
|
|
324
|
+
|
|
325
|
+
Total: 48 matches in 4 files
|
|
326
|
+
```
|
|
327
|
+
|
|
328
|
+
### Multiline Match
|
|
329
|
+
```
|
|
330
|
+
Agent: [Grep: pattern="function\\s+\\w+\\([^)]*\\)\\s*\\{[\\s\\S]*?return", multiline=true]
|
|
331
|
+
|
|
332
|
+
Multiline matches found:
|
|
333
|
+
src/utils/helpers.ts:15-22
|
|
334
|
+
function calculateTotal(items) {
|
|
335
|
+
let sum = 0;
|
|
336
|
+
for (const item of items) {
|
|
337
|
+
sum += item.price;
|
|
338
|
+
}
|
|
339
|
+
return sum;
|
|
340
|
+
}
|
|
341
|
+
```
|
|
342
|
+
|
|
343
|
+
## Security Considerations
|
|
344
|
+
|
|
345
|
+
1. Regex DoS prevention (ReDoS)
|
|
346
|
+
2. File access restrictions
|
|
347
|
+
3. Output size limits
|
|
348
|
+
4. Search timeout
|
|
349
|
+
|
|
350
|
+
## Migration Path
|
|
351
|
+
|
|
352
|
+
1. **Phase 1**: Output modes
|
|
353
|
+
2. **Phase 2**: Context lines
|
|
354
|
+
3. **Phase 3**: Multiline support
|
|
355
|
+
4. **Phase 4**: Performance optimization
|
|
356
|
+
|
|
357
|
+
## References
|
|
358
|
+
|
|
359
|
+
- [ripgrep](https://github.com/BurntSushi/ripgrep)
|
|
360
|
+
- [ReDoS Prevention](https://owasp.org/www-community/attacks/Regular_expression_Denial_of_Service_-_ReDoS)
|