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,42 @@
1
+ /**
2
+ * Glob Tool - Find files matching a pattern
3
+ */
4
+
5
+ import fastGlob from 'fast-glob';
6
+ import type { Tool, ToolResult } from '../types.js';
7
+ import { GlobInputSchema, type GlobInput, resolvePath, getErrorMessage } from '../types.js';
8
+
9
+ const MAX_RESULTS = 100;
10
+
11
+ export const globTool: Tool<GlobInput> = {
12
+ name: 'Glob',
13
+ description: 'Find files matching a glob pattern. Returns a list of matching file paths.',
14
+ parameters: GlobInputSchema,
15
+
16
+ async execute(input, context): Promise<ToolResult> {
17
+ try {
18
+ const searchPath = input.path ? resolvePath(input.path, context.cwd) : context.cwd;
19
+
20
+ const files = await fastGlob(input.pattern, {
21
+ cwd: searchPath,
22
+ absolute: true,
23
+ onlyFiles: true,
24
+ ignore: ['**/node_modules/**', '**/.git/**'],
25
+ followSymbolicLinks: false,
26
+ });
27
+
28
+ if (files.length === 0) {
29
+ return { success: true, output: 'No files found matching the pattern.' };
30
+ }
31
+
32
+ const truncated = files.length > MAX_RESULTS;
33
+ const displayFiles = files.slice(0, MAX_RESULTS);
34
+ return {
35
+ success: true,
36
+ output: `Found ${files.length} file(s):\n${displayFiles.join('\n')}${truncated ? '\n... (truncated)' : ''}`,
37
+ };
38
+ } catch (error) {
39
+ return { success: false, output: '', error: `Glob search failed: ${getErrorMessage(error)}` };
40
+ }
41
+ },
42
+ };
@@ -0,0 +1,67 @@
1
+ /**
2
+ * Grep Tool - Search for patterns in files
3
+ */
4
+
5
+ import * as fs from 'fs/promises';
6
+ import * as path from 'path';
7
+ import fastGlob from 'fast-glob';
8
+ import type { Tool, ToolResult } from '../types.js';
9
+ import { GrepInputSchema, type GrepInput, resolvePath, getErrorMessage } from '../types.js';
10
+
11
+ const MAX_MATCHES = 50;
12
+
13
+ export const grepTool: Tool<GrepInput> = {
14
+ name: 'Grep',
15
+ description: 'Search for a regex pattern in files. Returns matching lines with file paths and line numbers.',
16
+ parameters: GrepInputSchema,
17
+
18
+ async execute(input, context): Promise<ToolResult> {
19
+ try {
20
+ const searchPath = input.path ? resolvePath(input.path, context.cwd) : context.cwd;
21
+ const regex = new RegExp(input.pattern, 'gi');
22
+
23
+ const stat = await fs.stat(searchPath).catch(() => null);
24
+ const files = stat?.isFile()
25
+ ? [searchPath]
26
+ : await fastGlob(input.include || '**/*', {
27
+ cwd: searchPath,
28
+ absolute: true,
29
+ onlyFiles: true,
30
+ ignore: ['**/node_modules/**', '**/.git/**', '**/*.min.*'],
31
+ followSymbolicLinks: false,
32
+ });
33
+
34
+ const results: string[] = [];
35
+
36
+ for (const file of files) {
37
+ if (results.length >= MAX_MATCHES) break;
38
+
39
+ try {
40
+ const content = await fs.readFile(file, 'utf-8');
41
+ const lines = content.split('\n');
42
+
43
+ for (let i = 0; i < lines.length && results.length < MAX_MATCHES; i++) {
44
+ if (regex.test(lines[i])) {
45
+ results.push(`${path.relative(context.cwd, file)}:${i + 1}: ${lines[i].trim()}`);
46
+ }
47
+ regex.lastIndex = 0;
48
+ }
49
+ } catch {
50
+ // Skip unreadable files
51
+ }
52
+ }
53
+
54
+ if (results.length === 0) {
55
+ return { success: true, output: 'No matches found.' };
56
+ }
57
+
58
+ const truncated = results.length >= MAX_MATCHES;
59
+ return {
60
+ success: true,
61
+ output: `Found ${results.length} match(es):\n${results.join('\n')}${truncated ? '\n... (truncated)' : ''}`,
62
+ };
63
+ } catch (error) {
64
+ return { success: false, output: '', error: `Grep search failed: ${getErrorMessage(error)}` };
65
+ }
66
+ },
67
+ };
@@ -0,0 +1,34 @@
1
+ /**
2
+ * Read Tool - Read file contents
3
+ */
4
+
5
+ import * as fs from 'fs/promises';
6
+ import type { Tool, ToolResult } from '../types.js';
7
+ import { ReadInputSchema, type ReadInput, resolvePath, getErrorMessage } from '../types.js';
8
+
9
+ export const readTool: Tool<ReadInput> = {
10
+ name: 'Read',
11
+ description: 'Read the contents of a file. Returns the file content with line numbers.',
12
+ parameters: ReadInputSchema,
13
+
14
+ async execute(input, context): Promise<ToolResult> {
15
+ try {
16
+ const filePath = resolvePath(input.file_path, context.cwd);
17
+ const content = await fs.readFile(filePath, 'utf-8');
18
+ const lines = content.split('\n');
19
+
20
+ const offset = input.offset ?? 1;
21
+ const limit = input.limit ?? lines.length;
22
+
23
+ const selectedLines = lines.slice(offset - 1, offset - 1 + limit);
24
+ const numberedLines = selectedLines.map((line, i) => {
25
+ const lineNum = (offset + i).toString().padStart(5, ' ');
26
+ return `${lineNum}│${line}`;
27
+ });
28
+
29
+ return { success: true, output: numberedLines.join('\n') };
30
+ } catch (error) {
31
+ return { success: false, output: '', error: `Failed to read file: ${getErrorMessage(error)}` };
32
+ }
33
+ },
34
+ };
@@ -0,0 +1,27 @@
1
+ /**
2
+ * Write Tool - Write content to a file
3
+ */
4
+
5
+ import * as fs from 'fs/promises';
6
+ import * as path from 'path';
7
+ import type { Tool, ToolResult } from '../types.js';
8
+ import { WriteInputSchema, type WriteInput, resolvePath, getErrorMessage } from '../types.js';
9
+
10
+ export const writeTool: Tool<WriteInput> = {
11
+ name: 'Write',
12
+ description: 'Write content to a file. Creates the file if it does not exist, overwrites if it does.',
13
+ parameters: WriteInputSchema,
14
+
15
+ async execute(input, context): Promise<ToolResult> {
16
+ try {
17
+ const filePath = resolvePath(input.file_path, context.cwd);
18
+ await fs.mkdir(path.dirname(filePath), { recursive: true });
19
+ await fs.writeFile(filePath, input.content, 'utf-8');
20
+
21
+ const lineCount = input.content.split('\n').length;
22
+ return { success: true, output: `Successfully wrote ${lineCount} lines to ${filePath}` };
23
+ } catch (error) {
24
+ return { success: false, output: '', error: `Failed to write file: ${getErrorMessage(error)}` };
25
+ }
26
+ },
27
+ };
@@ -0,0 +1,36 @@
1
+ /**
2
+ * Tools System - Built-in tools and registry
3
+ */
4
+
5
+ export * from './types.js';
6
+ export { ToolRegistry } from './registry.js';
7
+
8
+ // Built-in tools
9
+ export { readTool } from './builtin/read.js';
10
+ export { writeTool } from './builtin/write.js';
11
+ export { editTool } from './builtin/edit.js';
12
+ export { bashTool } from './builtin/bash.js';
13
+ export { globTool } from './builtin/glob.js';
14
+ export { grepTool } from './builtin/grep.js';
15
+
16
+ import { ToolRegistry } from './registry.js';
17
+ import { readTool } from './builtin/read.js';
18
+ import { writeTool } from './builtin/write.js';
19
+ import { editTool } from './builtin/edit.js';
20
+ import { bashTool } from './builtin/bash.js';
21
+ import { globTool } from './builtin/glob.js';
22
+ import { grepTool } from './builtin/grep.js';
23
+
24
+ /**
25
+ * Create a registry with all built-in tools
26
+ */
27
+ export function createDefaultRegistry(): ToolRegistry {
28
+ const registry = new ToolRegistry();
29
+ registry.registerAll([readTool, writeTool, editTool, bashTool, globTool, grepTool]);
30
+ return registry;
31
+ }
32
+
33
+ /**
34
+ * All built-in tools
35
+ */
36
+ export const builtinTools = [readTool, writeTool, editTool, bashTool, globTool, grepTool];
@@ -0,0 +1,83 @@
1
+ /**
2
+ * Tool Registry - Manages available tools
3
+ */
4
+
5
+ import type { Tool, ToolContext, ToolResult } from './types.js';
6
+ import { zodToJsonSchema, getErrorMessage } from './types.js';
7
+ import type { ToolDefinition } from '../providers/types.js';
8
+
9
+ export class ToolRegistry {
10
+ private tools: Map<string, Tool> = new Map();
11
+
12
+ register(tool: Tool): void {
13
+ this.tools.set(tool.name, tool);
14
+ }
15
+
16
+ registerAll(tools: Tool[]): void {
17
+ for (const tool of tools) {
18
+ this.register(tool);
19
+ }
20
+ }
21
+
22
+ get(name: string): Tool | undefined {
23
+ return this.tools.get(name);
24
+ }
25
+
26
+ has(name: string): boolean {
27
+ return this.tools.has(name);
28
+ }
29
+
30
+ list(): string[] {
31
+ return Array.from(this.tools.keys());
32
+ }
33
+
34
+ /**
35
+ * Get tool definitions for LLM
36
+ */
37
+ getDefinitions(toolNames?: string[]): ToolDefinition[] {
38
+ const names = toolNames ?? this.list();
39
+ return names
40
+ .map((name) => {
41
+ const tool = this.tools.get(name);
42
+ if (!tool) return null;
43
+
44
+ return {
45
+ name: tool.name,
46
+ description: tool.description,
47
+ parameters: zodToJsonSchema(tool.parameters),
48
+ };
49
+ })
50
+ .filter((t): t is ToolDefinition => t !== null);
51
+ }
52
+
53
+ /**
54
+ * Execute a tool by name
55
+ */
56
+ async execute(name: string, input: unknown, context: ToolContext): Promise<ToolResult> {
57
+ const tool = this.tools.get(name);
58
+
59
+ if (!tool) {
60
+ return {
61
+ success: false,
62
+ output: '',
63
+ error: `Unknown tool: ${name}`,
64
+ };
65
+ }
66
+
67
+ try {
68
+ // Validate input
69
+ const parsed = tool.parameters.safeParse(input);
70
+ if (!parsed.success) {
71
+ return {
72
+ success: false,
73
+ output: '',
74
+ error: `Invalid input: ${parsed.error.message}`,
75
+ };
76
+ }
77
+
78
+ return await tool.execute(parsed.data, context);
79
+ } catch (error) {
80
+ return { success: false, output: '', error: `Tool execution failed: ${getErrorMessage(error)}` };
81
+ }
82
+ }
83
+ }
@@ -0,0 +1,172 @@
1
+ /**
2
+ * Tool System Type Definitions
3
+ */
4
+
5
+ import * as path from 'path';
6
+ import { z } from 'zod';
7
+
8
+ // ============================================================================
9
+ // Tool Definition Types
10
+ // ============================================================================
11
+
12
+ export interface ToolContext {
13
+ cwd: string;
14
+ abortSignal?: AbortSignal;
15
+ }
16
+
17
+ export interface ToolResult {
18
+ success: boolean;
19
+ output: string;
20
+ error?: string;
21
+ }
22
+
23
+ export interface Tool<TInput = unknown> {
24
+ name: string;
25
+ description: string;
26
+ parameters: z.ZodSchema<TInput>;
27
+ execute(input: TInput, context: ToolContext): Promise<ToolResult>;
28
+ }
29
+
30
+ // ============================================================================
31
+ // Helper Functions
32
+ // ============================================================================
33
+
34
+ /**
35
+ * Resolve a file path relative to the context's working directory
36
+ */
37
+ export function resolvePath(filePath: string, cwd: string): string {
38
+ return path.isAbsolute(filePath) ? filePath : path.resolve(cwd, filePath);
39
+ }
40
+
41
+ /**
42
+ * Extract error message from unknown error
43
+ */
44
+ export function getErrorMessage(error: unknown): string {
45
+ return error instanceof Error ? error.message : String(error);
46
+ }
47
+
48
+ // ============================================================================
49
+ // Built-in Tool Input Types
50
+ // ============================================================================
51
+
52
+ export const ReadInputSchema = z.object({
53
+ file_path: z.string().describe('The absolute path to the file to read'),
54
+ offset: z.number().optional().describe('Line number to start reading from (1-based)'),
55
+ limit: z.number().optional().describe('Number of lines to read'),
56
+ });
57
+ export type ReadInput = z.infer<typeof ReadInputSchema>;
58
+
59
+ export const WriteInputSchema = z.object({
60
+ file_path: z.string().describe('The absolute path to the file to write'),
61
+ content: z.string().describe('The content to write to the file'),
62
+ });
63
+ export type WriteInput = z.infer<typeof WriteInputSchema>;
64
+
65
+ export const EditInputSchema = z.object({
66
+ file_path: z.string().describe('The absolute path to the file to modify'),
67
+ old_string: z.string().describe('The text to replace'),
68
+ new_string: z.string().describe('The replacement text'),
69
+ });
70
+ export type EditInput = z.infer<typeof EditInputSchema>;
71
+
72
+ export const BashInputSchema = z.object({
73
+ command: z.string().describe('The bash command to execute'),
74
+ timeout: z.number().optional().describe('Timeout in milliseconds (default: 30000)'),
75
+ });
76
+ export type BashInput = z.infer<typeof BashInputSchema>;
77
+
78
+ export const GlobInputSchema = z.object({
79
+ pattern: z.string().describe('The glob pattern to match files'),
80
+ path: z.string().optional().describe('The directory to search in'),
81
+ });
82
+ export type GlobInput = z.infer<typeof GlobInputSchema>;
83
+
84
+ export const GrepInputSchema = z.object({
85
+ pattern: z.string().describe('The regex pattern to search for'),
86
+ path: z.string().optional().describe('The file or directory to search in'),
87
+ include: z.string().optional().describe('File pattern to include (e.g., "*.ts")'),
88
+ });
89
+ export type GrepInput = z.infer<typeof GrepInputSchema>;
90
+
91
+ // ============================================================================
92
+ // JSON Schema Conversion
93
+ // ============================================================================
94
+
95
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
96
+ export function zodToJsonSchema(schema: z.ZodSchema<any>): Record<string, unknown> {
97
+ // Use Zod's built-in JSON schema support or manual conversion
98
+ try {
99
+ // Zod v4 approach - check if toJsonSchema exists
100
+ if ('toJsonSchema' in z && typeof z.toJsonSchema === 'function') {
101
+ return z.toJsonSchema(schema) as Record<string, unknown>;
102
+ }
103
+ } catch {
104
+ // Fall through to manual conversion
105
+ }
106
+
107
+ // Manual conversion for object schemas
108
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
109
+ const def = (schema as any)._zod ?? (schema as any)._def;
110
+ if (def?.typeName === 'ZodObject' || def?.def?.typeName === 'object') {
111
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
112
+ const shape = (schema as any).shape ?? (schema as any)._zod?.def?.shape;
113
+ if (shape) {
114
+ const properties: Record<string, unknown> = {};
115
+ const required: string[] = [];
116
+
117
+ for (const [key, value] of Object.entries(shape)) {
118
+ properties[key] = zodFieldToJsonSchema(value);
119
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
120
+ const valDef = (value as any)._zod ?? (value as any)._def;
121
+ const isOptional = valDef?.typeName === 'ZodOptional' || valDef?.def?.typeName === 'optional';
122
+ if (!isOptional) {
123
+ required.push(key);
124
+ }
125
+ }
126
+
127
+ return {
128
+ type: 'object',
129
+ properties,
130
+ required: required.length > 0 ? required : undefined,
131
+ };
132
+ }
133
+ }
134
+
135
+ return { type: 'object' };
136
+ }
137
+
138
+ function zodFieldToJsonSchema(field: unknown): Record<string, unknown> {
139
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
140
+ const f = field as any;
141
+ const def = f._zod ?? f._def;
142
+ const description = def?.def?.description ?? def?.description;
143
+
144
+ // Get the inner type for optionals
145
+ let typeName = def?.typeName ?? def?.def?.typeName ?? 'string';
146
+
147
+ // Unwrap optional
148
+ if (typeName === 'ZodOptional' || typeName === 'optional') {
149
+ const inner = def?.def?.innerType ?? def?.innerType;
150
+ if (inner) {
151
+ const innerDef = inner._zod ?? inner._def;
152
+ typeName = innerDef?.typeName ?? innerDef?.def?.typeName ?? 'string';
153
+ }
154
+ }
155
+
156
+ // Map Zod types to JSON Schema types
157
+ let type = 'string';
158
+ if (typeName === 'ZodNumber' || typeName === 'number') {
159
+ type = 'number';
160
+ } else if (typeName === 'ZodBoolean' || typeName === 'boolean') {
161
+ type = 'boolean';
162
+ } else if (typeName === 'ZodArray' || typeName === 'array') {
163
+ const items = def?.def?.element ?? def?.element;
164
+ return {
165
+ type: 'array',
166
+ items: items ? zodFieldToJsonSchema(items) : { type: 'string' },
167
+ description,
168
+ };
169
+ }
170
+
171
+ return { type, description };
172
+ }
package/tsconfig.json ADDED
@@ -0,0 +1,21 @@
1
+ {
2
+ "compilerOptions": {
3
+ "target": "ES2022",
4
+ "module": "NodeNext",
5
+ "moduleResolution": "NodeNext",
6
+ "lib": ["ES2022"],
7
+ "outDir": "./dist",
8
+ "rootDir": "./src",
9
+ "strict": true,
10
+ "esModuleInterop": true,
11
+ "skipLibCheck": true,
12
+ "forceConsistentCasingInFileNames": true,
13
+ "declaration": true,
14
+ "declarationMap": true,
15
+ "sourceMap": true,
16
+ "resolveJsonModule": true,
17
+ "jsx": "react-jsx"
18
+ },
19
+ "include": ["src/**/*"],
20
+ "exclude": ["node_modules", "dist", "examples"]
21
+ }