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.
Files changed (274) hide show
  1. package/.env.example +11 -0
  2. package/CLAUDE.md +70 -0
  3. package/LICENSE +21 -0
  4. package/README.md +117 -0
  5. package/dist/agent/agent.d.ts +84 -0
  6. package/dist/agent/agent.d.ts.map +1 -0
  7. package/dist/agent/agent.js +233 -0
  8. package/dist/agent/agent.js.map +1 -0
  9. package/dist/agent/index.d.ts +6 -0
  10. package/dist/agent/index.d.ts.map +1 -0
  11. package/dist/agent/index.js +6 -0
  12. package/dist/agent/index.js.map +1 -0
  13. package/dist/agent/types.d.ts +47 -0
  14. package/dist/agent/types.d.ts.map +1 -0
  15. package/dist/agent/types.js +5 -0
  16. package/dist/agent/types.js.map +1 -0
  17. package/dist/cli/components/App.d.ts +14 -0
  18. package/dist/cli/components/App.d.ts.map +1 -0
  19. package/dist/cli/components/App.js +395 -0
  20. package/dist/cli/components/App.js.map +1 -0
  21. package/dist/cli/components/CommandSuggestions.d.ts +13 -0
  22. package/dist/cli/components/CommandSuggestions.d.ts.map +1 -0
  23. package/dist/cli/components/CommandSuggestions.js +32 -0
  24. package/dist/cli/components/CommandSuggestions.js.map +1 -0
  25. package/dist/cli/components/Header.d.ts +9 -0
  26. package/dist/cli/components/Header.d.ts.map +1 -0
  27. package/dist/cli/components/Header.js +13 -0
  28. package/dist/cli/components/Header.js.map +1 -0
  29. package/dist/cli/components/Input.d.ts +13 -0
  30. package/dist/cli/components/Input.d.ts.map +1 -0
  31. package/dist/cli/components/Input.js +27 -0
  32. package/dist/cli/components/Input.js.map +1 -0
  33. package/dist/cli/components/Logo.d.ts +2 -0
  34. package/dist/cli/components/Logo.d.ts.map +1 -0
  35. package/dist/cli/components/Logo.js +8 -0
  36. package/dist/cli/components/Logo.js.map +1 -0
  37. package/dist/cli/components/Messages.d.ts +37 -0
  38. package/dist/cli/components/Messages.d.ts.map +1 -0
  39. package/dist/cli/components/Messages.js +106 -0
  40. package/dist/cli/components/Messages.js.map +1 -0
  41. package/dist/cli/components/ModelSelector.d.ts +13 -0
  42. package/dist/cli/components/ModelSelector.d.ts.map +1 -0
  43. package/dist/cli/components/ModelSelector.js +72 -0
  44. package/dist/cli/components/ModelSelector.js.map +1 -0
  45. package/dist/cli/components/Spinner.d.ts +12 -0
  46. package/dist/cli/components/Spinner.d.ts.map +1 -0
  47. package/dist/cli/components/Spinner.js +45 -0
  48. package/dist/cli/components/Spinner.js.map +1 -0
  49. package/dist/cli/components/index.d.ts +12 -0
  50. package/dist/cli/components/index.d.ts.map +1 -0
  51. package/dist/cli/components/index.js +12 -0
  52. package/dist/cli/components/index.js.map +1 -0
  53. package/dist/cli/components/theme.d.ts +31 -0
  54. package/dist/cli/components/theme.d.ts.map +1 -0
  55. package/dist/cli/components/theme.js +36 -0
  56. package/dist/cli/components/theme.js.map +1 -0
  57. package/dist/cli/index-legacy.d.ts +7 -0
  58. package/dist/cli/index-legacy.d.ts.map +1 -0
  59. package/dist/cli/index-legacy.js +431 -0
  60. package/dist/cli/index-legacy.js.map +1 -0
  61. package/dist/cli/index.d.ts +7 -0
  62. package/dist/cli/index.d.ts.map +1 -0
  63. package/dist/cli/index.js +116 -0
  64. package/dist/cli/index.js.map +1 -0
  65. package/dist/cli/ink-cli.d.ts +7 -0
  66. package/dist/cli/ink-cli.d.ts.map +1 -0
  67. package/dist/cli/ink-cli.js +105 -0
  68. package/dist/cli/ink-cli.js.map +1 -0
  69. package/dist/cli/session-picker.d.ts +16 -0
  70. package/dist/cli/session-picker.d.ts.map +1 -0
  71. package/dist/cli/session-picker.js +280 -0
  72. package/dist/cli/session-picker.js.map +1 -0
  73. package/dist/cli/ui.d.ts +61 -0
  74. package/dist/cli/ui.d.ts.map +1 -0
  75. package/dist/cli/ui.js +364 -0
  76. package/dist/cli/ui.js.map +1 -0
  77. package/dist/config/index.d.ts +7 -0
  78. package/dist/config/index.d.ts.map +1 -0
  79. package/dist/config/index.js +6 -0
  80. package/dist/config/index.js.map +1 -0
  81. package/dist/config/manager.d.ts +31 -0
  82. package/dist/config/manager.d.ts.map +1 -0
  83. package/dist/config/manager.js +65 -0
  84. package/dist/config/manager.js.map +1 -0
  85. package/dist/config/types.d.ts +22 -0
  86. package/dist/config/types.d.ts.map +1 -0
  87. package/dist/config/types.js +6 -0
  88. package/dist/config/types.js.map +1 -0
  89. package/dist/index.d.ts +12 -0
  90. package/dist/index.d.ts.map +1 -0
  91. package/dist/index.js +21 -0
  92. package/dist/index.js.map +1 -0
  93. package/dist/memory/index.d.ts +10 -0
  94. package/dist/memory/index.d.ts.map +1 -0
  95. package/dist/memory/index.js +9 -0
  96. package/dist/memory/index.js.map +1 -0
  97. package/dist/memory/init.d.ts +20 -0
  98. package/dist/memory/init.d.ts.map +1 -0
  99. package/dist/memory/init.js +332 -0
  100. package/dist/memory/init.js.map +1 -0
  101. package/dist/memory/manager.d.ts +85 -0
  102. package/dist/memory/manager.d.ts.map +1 -0
  103. package/dist/memory/manager.js +234 -0
  104. package/dist/memory/manager.js.map +1 -0
  105. package/dist/memory/types.d.ts +74 -0
  106. package/dist/memory/types.d.ts.map +1 -0
  107. package/dist/memory/types.js +6 -0
  108. package/dist/memory/types.js.map +1 -0
  109. package/dist/permissions/index.d.ts +7 -0
  110. package/dist/permissions/index.d.ts.map +1 -0
  111. package/dist/permissions/index.js +6 -0
  112. package/dist/permissions/index.js.map +1 -0
  113. package/dist/permissions/manager.d.ts +32 -0
  114. package/dist/permissions/manager.d.ts.map +1 -0
  115. package/dist/permissions/manager.js +79 -0
  116. package/dist/permissions/manager.js.map +1 -0
  117. package/dist/permissions/types.d.ts +14 -0
  118. package/dist/permissions/types.d.ts.map +1 -0
  119. package/dist/permissions/types.js +17 -0
  120. package/dist/permissions/types.js.map +1 -0
  121. package/dist/providers/anthropic.d.ts +20 -0
  122. package/dist/providers/anthropic.d.ts.map +1 -0
  123. package/dist/providers/anthropic.js +185 -0
  124. package/dist/providers/anthropic.js.map +1 -0
  125. package/dist/providers/gemini.d.ts +21 -0
  126. package/dist/providers/gemini.d.ts.map +1 -0
  127. package/dist/providers/gemini.js +241 -0
  128. package/dist/providers/gemini.js.map +1 -0
  129. package/dist/providers/index.d.ts +34 -0
  130. package/dist/providers/index.d.ts.map +1 -0
  131. package/dist/providers/index.js +72 -0
  132. package/dist/providers/index.js.map +1 -0
  133. package/dist/providers/openai.d.ts +19 -0
  134. package/dist/providers/openai.d.ts.map +1 -0
  135. package/dist/providers/openai.js +221 -0
  136. package/dist/providers/openai.js.map +1 -0
  137. package/dist/providers/types.d.ts +125 -0
  138. package/dist/providers/types.d.ts.map +1 -0
  139. package/dist/providers/types.js +6 -0
  140. package/dist/providers/types.js.map +1 -0
  141. package/dist/session/index.d.ts +6 -0
  142. package/dist/session/index.d.ts.map +1 -0
  143. package/dist/session/index.js +6 -0
  144. package/dist/session/index.js.map +1 -0
  145. package/dist/session/manager.d.ts +101 -0
  146. package/dist/session/manager.d.ts.map +1 -0
  147. package/dist/session/manager.js +295 -0
  148. package/dist/session/manager.js.map +1 -0
  149. package/dist/session/types.d.ts +39 -0
  150. package/dist/session/types.d.ts.map +1 -0
  151. package/dist/session/types.js +10 -0
  152. package/dist/session/types.js.map +1 -0
  153. package/dist/tools/builtin/bash.d.ts +7 -0
  154. package/dist/tools/builtin/bash.d.ts.map +1 -0
  155. package/dist/tools/builtin/bash.js +80 -0
  156. package/dist/tools/builtin/bash.js.map +1 -0
  157. package/dist/tools/builtin/edit.d.ts +7 -0
  158. package/dist/tools/builtin/edit.d.ts.map +1 -0
  159. package/dist/tools/builtin/edit.js +32 -0
  160. package/dist/tools/builtin/edit.js.map +1 -0
  161. package/dist/tools/builtin/glob.d.ts +7 -0
  162. package/dist/tools/builtin/glob.d.ts.map +1 -0
  163. package/dist/tools/builtin/glob.js +36 -0
  164. package/dist/tools/builtin/glob.js.map +1 -0
  165. package/dist/tools/builtin/grep.d.ts +7 -0
  166. package/dist/tools/builtin/grep.d.ts.map +1 -0
  167. package/dist/tools/builtin/grep.js +59 -0
  168. package/dist/tools/builtin/grep.js.map +1 -0
  169. package/dist/tools/builtin/read.d.ts +7 -0
  170. package/dist/tools/builtin/read.d.ts.map +1 -0
  171. package/dist/tools/builtin/read.js +29 -0
  172. package/dist/tools/builtin/read.js.map +1 -0
  173. package/dist/tools/builtin/write.d.ts +7 -0
  174. package/dist/tools/builtin/write.d.ts.map +1 -0
  175. package/dist/tools/builtin/write.js +24 -0
  176. package/dist/tools/builtin/write.js.map +1 -0
  177. package/dist/tools/index.d.ts +38 -0
  178. package/dist/tools/index.d.ts.map +1 -0
  179. package/dist/tools/index.js +32 -0
  180. package/dist/tools/index.js.map +1 -0
  181. package/dist/tools/registry.d.ts +22 -0
  182. package/dist/tools/registry.d.ts.map +1 -0
  183. package/dist/tools/registry.js +71 -0
  184. package/dist/tools/registry.js.map +1 -0
  185. package/dist/tools/types.d.ts +62 -0
  186. package/dist/tools/types.d.ts.map +1 -0
  187. package/dist/tools/types.js +126 -0
  188. package/dist/tools/types.js.map +1 -0
  189. package/docs/README.md +16 -0
  190. package/docs/proposals/0001-web-fetch-tool.md +293 -0
  191. package/docs/proposals/0002-web-search-tool.md +306 -0
  192. package/docs/proposals/0003-task-subagents.md +333 -0
  193. package/docs/proposals/0004-plan-mode.md +338 -0
  194. package/docs/proposals/0005-todo-system.md +299 -0
  195. package/docs/proposals/0006-memory-system.md +539 -0
  196. package/docs/proposals/0007-context-management.md +429 -0
  197. package/docs/proposals/0008-checkpointing.md +327 -0
  198. package/docs/proposals/0009-hooks-system.md +343 -0
  199. package/docs/proposals/0010-mcp-integration.md +382 -0
  200. package/docs/proposals/0011-custom-commands.md +374 -0
  201. package/docs/proposals/0012-ask-user-question.md +317 -0
  202. package/docs/proposals/0013-multi-edit-tool.md +345 -0
  203. package/docs/proposals/0014-lsp-tool.md +478 -0
  204. package/docs/proposals/0015-ls-tool.md +407 -0
  205. package/docs/proposals/0016-kill-shell-tool.md +455 -0
  206. package/docs/proposals/0017-background-tasks.md +489 -0
  207. package/docs/proposals/0018-parallel-tool-execution.md +415 -0
  208. package/docs/proposals/0019-session-enhancements.md +462 -0
  209. package/docs/proposals/0020-session-summarization.md +447 -0
  210. package/docs/proposals/0021-skills-system.md +409 -0
  211. package/docs/proposals/0022-plugin-system.md +467 -0
  212. package/docs/proposals/0023-permission-enhancements.md +470 -0
  213. package/docs/proposals/0024-keyboard-shortcuts.md +443 -0
  214. package/docs/proposals/0025-cost-tracking.md +447 -0
  215. package/docs/proposals/0026-git-integration.md +475 -0
  216. package/docs/proposals/0027-enhanced-read-tool.md +514 -0
  217. package/docs/proposals/0028-enhanced-bash-tool.md +511 -0
  218. package/docs/proposals/0029-notebook-edit-tool.md +413 -0
  219. package/docs/proposals/0030-plugin-marketplace.md +360 -0
  220. package/docs/proposals/0031-command-suggestions.md +295 -0
  221. package/docs/proposals/0032-ide-integrations.md +328 -0
  222. package/docs/proposals/0033-enterprise-deployment.md +221 -0
  223. package/docs/proposals/0034-sandboxing.md +273 -0
  224. package/docs/proposals/0035-auto-updater.md +311 -0
  225. package/docs/proposals/0036-enhanced-glob-tool.md +267 -0
  226. package/docs/proposals/0037-enhanced-grep-tool.md +360 -0
  227. package/docs/proposals/0038-interactive-cli-ui.md +373 -0
  228. package/docs/proposals/0039-streaming-enhancements.md +359 -0
  229. package/docs/proposals/0040-multi-provider-enhancements.md +369 -0
  230. package/docs/proposals/README.md +84 -0
  231. package/docs/proposals/TEMPLATE.md +57 -0
  232. package/docs/proposals/research/claude-code-research.md +307 -0
  233. package/examples/agent-demo.ts +115 -0
  234. package/examples/basic.ts +166 -0
  235. package/package.json +50 -0
  236. package/src/agent/agent.ts +276 -0
  237. package/src/agent/index.ts +6 -0
  238. package/src/agent/types.ts +62 -0
  239. package/src/cli/components/App.tsx +565 -0
  240. package/src/cli/components/CommandSuggestions.tsx +58 -0
  241. package/src/cli/components/Header.tsx +36 -0
  242. package/src/cli/components/Input.tsx +60 -0
  243. package/src/cli/components/Logo.tsx +16 -0
  244. package/src/cli/components/Messages.tsx +210 -0
  245. package/src/cli/components/ModelSelector.tsx +135 -0
  246. package/src/cli/components/Spinner.tsx +72 -0
  247. package/src/cli/components/index.ts +21 -0
  248. package/src/cli/components/theme.ts +36 -0
  249. package/src/cli/index.tsx +136 -0
  250. package/src/config/index.ts +7 -0
  251. package/src/config/manager.ts +77 -0
  252. package/src/config/types.ts +25 -0
  253. package/src/index.ts +86 -0
  254. package/src/permissions/index.ts +7 -0
  255. package/src/permissions/manager.ts +97 -0
  256. package/src/permissions/types.ts +29 -0
  257. package/src/providers/anthropic.ts +224 -0
  258. package/src/providers/gemini.ts +295 -0
  259. package/src/providers/index.ts +97 -0
  260. package/src/providers/openai.ts +261 -0
  261. package/src/providers/types.ts +181 -0
  262. package/src/session/index.ts +6 -0
  263. package/src/session/manager.ts +354 -0
  264. package/src/session/types.ts +49 -0
  265. package/src/tools/builtin/bash.ts +92 -0
  266. package/src/tools/builtin/edit.ts +37 -0
  267. package/src/tools/builtin/glob.ts +42 -0
  268. package/src/tools/builtin/grep.ts +67 -0
  269. package/src/tools/builtin/read.ts +34 -0
  270. package/src/tools/builtin/write.ts +27 -0
  271. package/src/tools/index.ts +36 -0
  272. package/src/tools/registry.ts +83 -0
  273. package/src/tools/types.ts +172 -0
  274. 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)