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,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
|
+
}
|