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,407 @@
|
|
|
1
|
+
# Proposal: LS Tool
|
|
2
|
+
|
|
3
|
+
- **Proposal ID**: 0015
|
|
4
|
+
- **Author**: mycode team
|
|
5
|
+
- **Status**: Draft
|
|
6
|
+
- **Created**: 2025-01-15
|
|
7
|
+
- **Updated**: 2025-01-15
|
|
8
|
+
|
|
9
|
+
## Summary
|
|
10
|
+
|
|
11
|
+
Implement a dedicated LS (List) tool for directory listing that provides structured output with file metadata, sorting, filtering, and tree visualization. This replaces ad-hoc Bash `ls` commands with a purpose-built tool optimized for agent consumption.
|
|
12
|
+
|
|
13
|
+
## Motivation
|
|
14
|
+
|
|
15
|
+
Currently, mycode uses Bash with `ls` for directory listing. This causes issues:
|
|
16
|
+
|
|
17
|
+
1. **Parsing complexity**: Agent must parse varied `ls` output formats
|
|
18
|
+
2. **Platform differences**: `ls` flags differ between macOS, Linux, BSD
|
|
19
|
+
3. **No structured data**: Text output requires manual extraction
|
|
20
|
+
4. **Limited features**: Basic `ls` lacks tree view, size summaries
|
|
21
|
+
5. **Security concerns**: Bash command injection risks
|
|
22
|
+
|
|
23
|
+
A dedicated LS tool provides safe, structured, consistent directory listing.
|
|
24
|
+
|
|
25
|
+
## Claude Code Reference
|
|
26
|
+
|
|
27
|
+
Claude Code recommends using the Read tool for directory operations rather than Bash:
|
|
28
|
+
|
|
29
|
+
### From Claude Code Guidelines
|
|
30
|
+
```
|
|
31
|
+
- This tool can only read files, not directories.
|
|
32
|
+
To read a directory, use an ls command via the Bash tool.
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
### Observed Behavior
|
|
36
|
+
Claude Code agents frequently use:
|
|
37
|
+
```bash
|
|
38
|
+
ls -la /path/to/dir
|
|
39
|
+
ls -1 src/
|
|
40
|
+
find . -type f -name "*.ts" | head -20
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
### Desired Improvement
|
|
44
|
+
A native LS tool would provide:
|
|
45
|
+
- Consistent JSON/structured output
|
|
46
|
+
- Cross-platform behavior
|
|
47
|
+
- Integrated filtering
|
|
48
|
+
- No command injection risk
|
|
49
|
+
|
|
50
|
+
## Detailed Design
|
|
51
|
+
|
|
52
|
+
### API Design
|
|
53
|
+
|
|
54
|
+
```typescript
|
|
55
|
+
// src/tools/ls/types.ts
|
|
56
|
+
interface LSInput {
|
|
57
|
+
path?: string; // Directory path (default: cwd)
|
|
58
|
+
all?: boolean; // Include hidden files (default: false)
|
|
59
|
+
long?: boolean; // Include metadata (default: false)
|
|
60
|
+
recursive?: boolean; // List recursively (default: false)
|
|
61
|
+
depth?: number; // Max recursion depth (default: 3)
|
|
62
|
+
pattern?: string; // Filter by glob pattern
|
|
63
|
+
sort?: 'name' | 'size' | 'modified' | 'type'; // Sort order
|
|
64
|
+
reverse?: boolean; // Reverse sort order
|
|
65
|
+
directories_only?: boolean; // Only show directories
|
|
66
|
+
files_only?: boolean; // Only show files
|
|
67
|
+
limit?: number; // Max entries to return
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
interface FileEntry {
|
|
71
|
+
name: string;
|
|
72
|
+
path: string; // Relative to input path
|
|
73
|
+
type: 'file' | 'directory' | 'symlink' | 'other';
|
|
74
|
+
size?: number; // In bytes (when long=true)
|
|
75
|
+
modified?: string; // ISO timestamp (when long=true)
|
|
76
|
+
permissions?: string; // Unix permissions (when long=true)
|
|
77
|
+
target?: string; // Symlink target (when applicable)
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
interface LSOutput {
|
|
81
|
+
success: boolean;
|
|
82
|
+
path: string; // Absolute path listed
|
|
83
|
+
entries: FileEntry[];
|
|
84
|
+
summary?: {
|
|
85
|
+
total_files: number;
|
|
86
|
+
total_directories: number;
|
|
87
|
+
total_size: number;
|
|
88
|
+
};
|
|
89
|
+
truncated?: boolean; // True if limit was applied
|
|
90
|
+
error?: string;
|
|
91
|
+
}
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
```typescript
|
|
95
|
+
// src/tools/ls/ls-tool.ts
|
|
96
|
+
const lsTool: Tool<LSInput> = {
|
|
97
|
+
name: 'LS',
|
|
98
|
+
description: `List directory contents with structured output.
|
|
99
|
+
|
|
100
|
+
Parameters:
|
|
101
|
+
- path: Directory to list (default: current working directory)
|
|
102
|
+
- all: Include hidden files starting with . (default: false)
|
|
103
|
+
- long: Include file metadata (size, modified, permissions)
|
|
104
|
+
- recursive: List subdirectories recursively
|
|
105
|
+
- depth: Maximum recursion depth (default: 3)
|
|
106
|
+
- pattern: Glob pattern to filter results (e.g., "*.ts")
|
|
107
|
+
- sort: Sort by name, size, modified, or type
|
|
108
|
+
- directories_only: Only show directories
|
|
109
|
+
- files_only: Only show files
|
|
110
|
+
- limit: Maximum number of entries to return
|
|
111
|
+
|
|
112
|
+
Returns structured list of files and directories with optional metadata.
|
|
113
|
+
Use this instead of Bash ls commands for reliable, structured output.
|
|
114
|
+
`,
|
|
115
|
+
parameters: z.object({
|
|
116
|
+
path: z.string().optional(),
|
|
117
|
+
all: z.boolean().optional().default(false),
|
|
118
|
+
long: z.boolean().optional().default(false),
|
|
119
|
+
recursive: z.boolean().optional().default(false),
|
|
120
|
+
depth: z.number().int().positive().optional().default(3),
|
|
121
|
+
pattern: z.string().optional(),
|
|
122
|
+
sort: z.enum(['name', 'size', 'modified', 'type']).optional().default('name'),
|
|
123
|
+
reverse: z.boolean().optional().default(false),
|
|
124
|
+
directories_only: z.boolean().optional().default(false),
|
|
125
|
+
files_only: z.boolean().optional().default(false),
|
|
126
|
+
limit: z.number().int().positive().optional()
|
|
127
|
+
}),
|
|
128
|
+
execute: async (input, context) => { ... }
|
|
129
|
+
};
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
### Implementation Approach
|
|
133
|
+
|
|
134
|
+
1. **Path Resolution**: Resolve relative to cwd, validate existence
|
|
135
|
+
2. **Directory Reading**: Use fs.readdir with file types
|
|
136
|
+
3. **Filtering**: Apply pattern matching and type filters
|
|
137
|
+
4. **Metadata Collection**: Gather stats when long=true
|
|
138
|
+
5. **Sorting**: Apply requested sort order
|
|
139
|
+
6. **Recursion**: Process subdirectories with depth limit
|
|
140
|
+
|
|
141
|
+
```typescript
|
|
142
|
+
// Core implementation
|
|
143
|
+
async function listDirectory(
|
|
144
|
+
input: LSInput,
|
|
145
|
+
context: ToolContext
|
|
146
|
+
): Promise<LSOutput> {
|
|
147
|
+
const targetPath = path.resolve(context.cwd, input.path || '.');
|
|
148
|
+
|
|
149
|
+
// Validate path exists and is directory
|
|
150
|
+
const stats = await fs.stat(targetPath);
|
|
151
|
+
if (!stats.isDirectory()) {
|
|
152
|
+
return { success: false, path: targetPath, entries: [], error: 'Not a directory' };
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
// Read directory entries
|
|
156
|
+
let entries = await readDirectoryEntries(targetPath, {
|
|
157
|
+
recursive: input.recursive,
|
|
158
|
+
depth: input.depth,
|
|
159
|
+
includeHidden: input.all
|
|
160
|
+
});
|
|
161
|
+
|
|
162
|
+
// Apply filters
|
|
163
|
+
if (input.pattern) {
|
|
164
|
+
entries = entries.filter(e => minimatch(e.name, input.pattern!));
|
|
165
|
+
}
|
|
166
|
+
if (input.directories_only) {
|
|
167
|
+
entries = entries.filter(e => e.type === 'directory');
|
|
168
|
+
}
|
|
169
|
+
if (input.files_only) {
|
|
170
|
+
entries = entries.filter(e => e.type === 'file');
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
// Gather metadata if requested
|
|
174
|
+
if (input.long) {
|
|
175
|
+
entries = await Promise.all(entries.map(async e => ({
|
|
176
|
+
...e,
|
|
177
|
+
...await getFileMetadata(path.join(targetPath, e.path))
|
|
178
|
+
})));
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
// Sort entries
|
|
182
|
+
entries = sortEntries(entries, input.sort, input.reverse);
|
|
183
|
+
|
|
184
|
+
// Apply limit
|
|
185
|
+
let truncated = false;
|
|
186
|
+
if (input.limit && entries.length > input.limit) {
|
|
187
|
+
entries = entries.slice(0, input.limit);
|
|
188
|
+
truncated = true;
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
// Calculate summary
|
|
192
|
+
const summary = input.long ? calculateSummary(entries) : undefined;
|
|
193
|
+
|
|
194
|
+
return {
|
|
195
|
+
success: true,
|
|
196
|
+
path: targetPath,
|
|
197
|
+
entries,
|
|
198
|
+
summary,
|
|
199
|
+
truncated
|
|
200
|
+
};
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
async function readDirectoryEntries(
|
|
204
|
+
dir: string,
|
|
205
|
+
options: { recursive: boolean; depth: number; includeHidden: boolean },
|
|
206
|
+
currentDepth = 0,
|
|
207
|
+
basePath = ''
|
|
208
|
+
): Promise<FileEntry[]> {
|
|
209
|
+
const dirents = await fs.readdir(dir, { withFileTypes: true });
|
|
210
|
+
const entries: FileEntry[] = [];
|
|
211
|
+
|
|
212
|
+
for (const dirent of dirents) {
|
|
213
|
+
// Skip hidden unless requested
|
|
214
|
+
if (!options.includeHidden && dirent.name.startsWith('.')) continue;
|
|
215
|
+
|
|
216
|
+
const relativePath = path.join(basePath, dirent.name);
|
|
217
|
+
const entry: FileEntry = {
|
|
218
|
+
name: dirent.name,
|
|
219
|
+
path: relativePath,
|
|
220
|
+
type: getEntryType(dirent)
|
|
221
|
+
};
|
|
222
|
+
|
|
223
|
+
entries.push(entry);
|
|
224
|
+
|
|
225
|
+
// Recurse into directories
|
|
226
|
+
if (options.recursive && dirent.isDirectory() && currentDepth < options.depth) {
|
|
227
|
+
const subEntries = await readDirectoryEntries(
|
|
228
|
+
path.join(dir, dirent.name),
|
|
229
|
+
options,
|
|
230
|
+
currentDepth + 1,
|
|
231
|
+
relativePath
|
|
232
|
+
);
|
|
233
|
+
entries.push(...subEntries);
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
return entries;
|
|
238
|
+
}
|
|
239
|
+
```
|
|
240
|
+
|
|
241
|
+
### File Changes
|
|
242
|
+
|
|
243
|
+
| File | Action | Description |
|
|
244
|
+
|------|--------|-------------|
|
|
245
|
+
| `src/tools/ls/types.ts` | Create | Type definitions |
|
|
246
|
+
| `src/tools/ls/ls-tool.ts` | Create | Tool implementation |
|
|
247
|
+
| `src/tools/ls/index.ts` | Create | Module exports |
|
|
248
|
+
| `src/tools/index.ts` | Modify | Register LS tool |
|
|
249
|
+
|
|
250
|
+
## User Experience
|
|
251
|
+
|
|
252
|
+
### Basic Directory Listing
|
|
253
|
+
```
|
|
254
|
+
User: What files are in the src directory?
|
|
255
|
+
|
|
256
|
+
Agent: [LS: path="src"]
|
|
257
|
+
|
|
258
|
+
Contents of src/:
|
|
259
|
+
├── index.ts
|
|
260
|
+
├── cli/
|
|
261
|
+
├── agent/
|
|
262
|
+
├── providers/
|
|
263
|
+
├── session/
|
|
264
|
+
└── tools/
|
|
265
|
+
|
|
266
|
+
6 items (1 file, 5 directories)
|
|
267
|
+
```
|
|
268
|
+
|
|
269
|
+
### Detailed Listing with Metadata
|
|
270
|
+
```
|
|
271
|
+
Agent: [LS: path="src/tools", long=true]
|
|
272
|
+
|
|
273
|
+
┌─ src/tools/ ──────────────────────────────────────┐
|
|
274
|
+
│ Name Type Size Modified │
|
|
275
|
+
├───────────────────────────────────────────────────┤
|
|
276
|
+
│ index.ts file 1.2 KB 2024-01-15 10:30 │
|
|
277
|
+
│ types.ts file 2.8 KB 2024-01-14 15:45 │
|
|
278
|
+
│ registry.ts file 4.1 KB 2024-01-15 09:20 │
|
|
279
|
+
│ builtin/ dir - 2024-01-15 11:00 │
|
|
280
|
+
└───────────────────────────────────────────────────┘
|
|
281
|
+
|
|
282
|
+
Summary: 3 files, 1 directory, 8.1 KB total
|
|
283
|
+
```
|
|
284
|
+
|
|
285
|
+
### Recursive with Pattern Filter
|
|
286
|
+
```
|
|
287
|
+
Agent: [LS: path="src", recursive=true, pattern="*.ts", limit=10]
|
|
288
|
+
|
|
289
|
+
TypeScript files in src/:
|
|
290
|
+
src/index.ts
|
|
291
|
+
src/cli/index.ts
|
|
292
|
+
src/cli/ui.ts
|
|
293
|
+
src/agent/agent.ts
|
|
294
|
+
src/agent/types.ts
|
|
295
|
+
src/providers/index.ts
|
|
296
|
+
src/providers/types.ts
|
|
297
|
+
src/providers/openai.ts
|
|
298
|
+
src/providers/anthropic.ts
|
|
299
|
+
src/providers/gemini.ts
|
|
300
|
+
|
|
301
|
+
Showing 10 of 24 files (truncated)
|
|
302
|
+
```
|
|
303
|
+
|
|
304
|
+
### Tree View for Recursive Listing
|
|
305
|
+
```
|
|
306
|
+
Agent: [LS: path="src", recursive=true, depth=2]
|
|
307
|
+
|
|
308
|
+
src/
|
|
309
|
+
├── index.ts
|
|
310
|
+
├── cli/
|
|
311
|
+
│ ├── index.ts
|
|
312
|
+
│ ├── ui.ts
|
|
313
|
+
│ └── session-picker.ts
|
|
314
|
+
├── agent/
|
|
315
|
+
│ ├── agent.ts
|
|
316
|
+
│ ├── types.ts
|
|
317
|
+
│ └── index.ts
|
|
318
|
+
├── providers/
|
|
319
|
+
│ ├── index.ts
|
|
320
|
+
│ ├── types.ts
|
|
321
|
+
│ ├── openai.ts
|
|
322
|
+
│ ├── anthropic.ts
|
|
323
|
+
│ └── gemini.ts
|
|
324
|
+
└── tools/
|
|
325
|
+
├── index.ts
|
|
326
|
+
├── types.ts
|
|
327
|
+
└── builtin/
|
|
328
|
+
```
|
|
329
|
+
|
|
330
|
+
## Alternatives Considered
|
|
331
|
+
|
|
332
|
+
### Alternative 1: Extend Read Tool
|
|
333
|
+
Add directory listing to Read tool.
|
|
334
|
+
|
|
335
|
+
**Pros**: Fewer tools to manage
|
|
336
|
+
**Cons**: Overloads Read semantics, complex parameters
|
|
337
|
+
**Decision**: Rejected - Separate concern
|
|
338
|
+
|
|
339
|
+
### Alternative 2: Use Bash with Parsing
|
|
340
|
+
Parse Bash ls output programmatically.
|
|
341
|
+
|
|
342
|
+
**Pros**: No new tool needed
|
|
343
|
+
**Cons**: Platform differences, parsing fragility
|
|
344
|
+
**Decision**: Rejected - Not reliable cross-platform
|
|
345
|
+
|
|
346
|
+
### Alternative 3: Return JSON Only
|
|
347
|
+
No formatted tree output, just JSON.
|
|
348
|
+
|
|
349
|
+
**Pros**: Simpler implementation
|
|
350
|
+
**Cons**: Harder for agent to present to user
|
|
351
|
+
**Decision**: Rejected - Tree view is valuable UX
|
|
352
|
+
|
|
353
|
+
## Security Considerations
|
|
354
|
+
|
|
355
|
+
1. **Path Traversal**: Prevent `../` escaping workspace
|
|
356
|
+
2. **Symlink Loops**: Detect and prevent infinite recursion
|
|
357
|
+
3. **Large Directories**: Enforce entry limits
|
|
358
|
+
4. **Permission Errors**: Handle gracefully
|
|
359
|
+
5. **No Command Injection**: Pure filesystem operations
|
|
360
|
+
|
|
361
|
+
```typescript
|
|
362
|
+
const LIMITS = {
|
|
363
|
+
maxEntries: 1000,
|
|
364
|
+
maxDepth: 10,
|
|
365
|
+
maxSymlinkDepth: 5
|
|
366
|
+
};
|
|
367
|
+
|
|
368
|
+
function validatePath(target: string, cwd: string): boolean {
|
|
369
|
+
const resolved = path.resolve(cwd, target);
|
|
370
|
+
return resolved.startsWith(cwd) || !target.includes('..');
|
|
371
|
+
}
|
|
372
|
+
```
|
|
373
|
+
|
|
374
|
+
## Testing Strategy
|
|
375
|
+
|
|
376
|
+
1. **Unit Tests**:
|
|
377
|
+
- Basic listing
|
|
378
|
+
- Hidden file filtering
|
|
379
|
+
- Pattern matching
|
|
380
|
+
- Sorting options
|
|
381
|
+
- Depth limiting
|
|
382
|
+
|
|
383
|
+
2. **Integration Tests**:
|
|
384
|
+
- Large directories
|
|
385
|
+
- Symlinks
|
|
386
|
+
- Permission denied scenarios
|
|
387
|
+
- Cross-platform paths
|
|
388
|
+
|
|
389
|
+
3. **Manual Testing**:
|
|
390
|
+
- Various project structures
|
|
391
|
+
- Edge cases (empty dirs, special characters)
|
|
392
|
+
|
|
393
|
+
## Migration Path
|
|
394
|
+
|
|
395
|
+
1. **Phase 1**: Basic listing with filtering
|
|
396
|
+
2. **Phase 2**: Long format with metadata
|
|
397
|
+
3. **Phase 3**: Recursive listing
|
|
398
|
+
4. **Phase 4**: Tree visualization
|
|
399
|
+
5. **Phase 5**: Performance optimization for large dirs
|
|
400
|
+
|
|
401
|
+
The Bash tool remains available for special cases.
|
|
402
|
+
|
|
403
|
+
## References
|
|
404
|
+
|
|
405
|
+
- [Node.js fs.readdir](https://nodejs.org/api/fs.html#fsreaddirpath-options-callback)
|
|
406
|
+
- [Minimatch - Glob Matching](https://github.com/isaacs/minimatch)
|
|
407
|
+
- [eza - Modern ls replacement](https://github.com/eza-community/eza)
|