codegrunt 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 (89) hide show
  1. package/README.md +351 -0
  2. package/dist/cli/at-resolver.d.ts +10 -0
  3. package/dist/cli/at-resolver.js +138 -0
  4. package/dist/cli/at-resolver.js.map +1 -0
  5. package/dist/cli/banner.d.ts +1 -0
  6. package/dist/cli/banner.js +111 -0
  7. package/dist/cli/banner.js.map +1 -0
  8. package/dist/cli/commands.d.ts +25 -0
  9. package/dist/cli/commands.js +799 -0
  10. package/dist/cli/commands.js.map +1 -0
  11. package/dist/cli/index.d.ts +2 -0
  12. package/dist/cli/index.js +142 -0
  13. package/dist/cli/index.js.map +1 -0
  14. package/dist/cli/input.d.ts +14 -0
  15. package/dist/cli/input.js +742 -0
  16. package/dist/cli/input.js.map +1 -0
  17. package/dist/cli/repl.d.ts +2 -0
  18. package/dist/cli/repl.js +217 -0
  19. package/dist/cli/repl.js.map +1 -0
  20. package/dist/cli/setup.d.ts +7 -0
  21. package/dist/cli/setup.js +82 -0
  22. package/dist/cli/setup.js.map +1 -0
  23. package/dist/cli/skills.d.ts +28 -0
  24. package/dist/cli/skills.js +299 -0
  25. package/dist/cli/skills.js.map +1 -0
  26. package/dist/cli/update.d.ts +7 -0
  27. package/dist/cli/update.js +135 -0
  28. package/dist/cli/update.js.map +1 -0
  29. package/dist/config.d.ts +19 -0
  30. package/dist/config.js +93 -0
  31. package/dist/config.js.map +1 -0
  32. package/dist/core/agent/loop.d.ts +17 -0
  33. package/dist/core/agent/loop.js +353 -0
  34. package/dist/core/agent/loop.js.map +1 -0
  35. package/dist/core/context/manager.d.ts +26 -0
  36. package/dist/core/context/manager.js +98 -0
  37. package/dist/core/context/manager.js.map +1 -0
  38. package/dist/core/context/project-guide.d.ts +1 -0
  39. package/dist/core/context/project-guide.js +17 -0
  40. package/dist/core/context/project-guide.js.map +1 -0
  41. package/dist/core/tools/edit_file.d.ts +2 -0
  42. package/dist/core/tools/edit_file.js +54 -0
  43. package/dist/core/tools/edit_file.js.map +1 -0
  44. package/dist/core/tools/execute_shell.d.ts +2 -0
  45. package/dist/core/tools/execute_shell.js +67 -0
  46. package/dist/core/tools/execute_shell.js.map +1 -0
  47. package/dist/core/tools/executor.d.ts +3 -0
  48. package/dist/core/tools/executor.js +86 -0
  49. package/dist/core/tools/executor.js.map +1 -0
  50. package/dist/core/tools/list_directory.d.ts +2 -0
  51. package/dist/core/tools/list_directory.js +74 -0
  52. package/dist/core/tools/list_directory.js.map +1 -0
  53. package/dist/core/tools/read_file.d.ts +2 -0
  54. package/dist/core/tools/read_file.js +40 -0
  55. package/dist/core/tools/read_file.js.map +1 -0
  56. package/dist/core/tools/registry.d.ts +4 -0
  57. package/dist/core/tools/registry.js +24 -0
  58. package/dist/core/tools/registry.js.map +1 -0
  59. package/dist/core/tools/search_files.d.ts +2 -0
  60. package/dist/core/tools/search_files.js +88 -0
  61. package/dist/core/tools/search_files.js.map +1 -0
  62. package/dist/core/tools/write_file.d.ts +2 -0
  63. package/dist/core/tools/write_file.js +43 -0
  64. package/dist/core/tools/write_file.js.map +1 -0
  65. package/dist/providers/deepseek/client.d.ts +8 -0
  66. package/dist/providers/deepseek/client.js +27 -0
  67. package/dist/providers/deepseek/client.js.map +1 -0
  68. package/dist/providers/deepseek/provider.d.ts +8 -0
  69. package/dist/providers/deepseek/provider.js +165 -0
  70. package/dist/providers/deepseek/provider.js.map +1 -0
  71. package/dist/types.d.ts +111 -0
  72. package/dist/types.js +3 -0
  73. package/dist/types.js.map +1 -0
  74. package/dist/utils/billing.d.ts +40 -0
  75. package/dist/utils/billing.js +165 -0
  76. package/dist/utils/billing.js.map +1 -0
  77. package/dist/utils/confirm.d.ts +3 -0
  78. package/dist/utils/confirm.js +242 -0
  79. package/dist/utils/confirm.js.map +1 -0
  80. package/dist/utils/display.d.ts +10 -0
  81. package/dist/utils/display.js +121 -0
  82. package/dist/utils/display.js.map +1 -0
  83. package/dist/utils/interrupt.d.ts +5 -0
  84. package/dist/utils/interrupt.js +13 -0
  85. package/dist/utils/interrupt.js.map +1 -0
  86. package/dist/utils/markdown.d.ts +18 -0
  87. package/dist/utils/markdown.js +223 -0
  88. package/dist/utils/markdown.js.map +1 -0
  89. package/package.json +42 -0
@@ -0,0 +1,67 @@
1
+ import { spawn } from 'child_process';
2
+ const DEFAULT_TIMEOUT_MS = 30_000;
3
+ export const executeShellTool = {
4
+ definition: {
5
+ type: 'function',
6
+ function: {
7
+ name: 'execute_shell',
8
+ description: 'Execute a shell command and return its output. The working directory is already set to the project root — do NOT prepend "cd <path> &&" to commands. Use for running tests, builds, installing packages, git commands, etc.',
9
+ parameters: {
10
+ type: 'object',
11
+ properties: {
12
+ command: {
13
+ type: 'string',
14
+ description: 'The shell command to execute',
15
+ },
16
+ cwd: {
17
+ type: 'string',
18
+ description: 'Working directory for the command (optional, defaults to current directory)',
19
+ },
20
+ timeout_ms: {
21
+ type: 'number',
22
+ description: `Timeout in milliseconds (default: ${DEFAULT_TIMEOUT_MS})`,
23
+ },
24
+ },
25
+ required: ['command'],
26
+ },
27
+ },
28
+ },
29
+ async execute(args) {
30
+ const command = args.command;
31
+ const cwd = args.cwd ?? process.cwd();
32
+ const timeoutMs = args.timeout_ms ?? DEFAULT_TIMEOUT_MS;
33
+ return new Promise((resolve) => {
34
+ const chunks = [];
35
+ let timedOut = false;
36
+ const child = spawn(command, {
37
+ shell: true,
38
+ cwd,
39
+ stdio: ['ignore', 'pipe', 'pipe'],
40
+ });
41
+ child.stdout.on('data', (data) => chunks.push(data.toString()));
42
+ child.stderr.on('data', (data) => chunks.push(data.toString()));
43
+ const timer = setTimeout(() => {
44
+ timedOut = true;
45
+ child.kill('SIGTERM');
46
+ }, timeoutMs);
47
+ child.on('close', (code) => {
48
+ clearTimeout(timer);
49
+ const output = chunks.join('');
50
+ if (timedOut) {
51
+ resolve({ success: false, output, error: `Command timed out after ${timeoutMs}ms` });
52
+ }
53
+ else if (code !== 0) {
54
+ resolve({ success: false, output, error: `Command exited with code ${code}` });
55
+ }
56
+ else {
57
+ resolve({ success: true, output: output || '(no output)' });
58
+ }
59
+ });
60
+ child.on('error', (err) => {
61
+ clearTimeout(timer);
62
+ resolve({ success: false, output: '', error: err.message });
63
+ });
64
+ });
65
+ },
66
+ };
67
+ //# sourceMappingURL=execute_shell.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"execute_shell.js","sourceRoot":"","sources":["../../../src/core/tools/execute_shell.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ import type { ToolResult } from '../../types.js';
2
+ export declare function resetYesAll(): void;
3
+ export declare function executeTool(name: string, argsJson: string, cwd?: string): Promise<ToolResult>;
@@ -0,0 +1,86 @@
1
+ import { readFile } from 'fs/promises';
2
+ import { existsSync } from 'fs';
3
+ import { resolve } from 'path';
4
+ import { getToolByName } from './registry.js';
5
+ import { confirmEdit, applyEdit } from '../../utils/confirm.js';
6
+ // Module-level state for "yes for all" across tool calls
7
+ // yesAllSession — resets at the start of each new user turn
8
+ let yesAllSessionActive = false;
9
+ export function resetYesAll() {
10
+ yesAllSessionActive = false;
11
+ }
12
+ async function confirmOrSkip(filePath, newContent) {
13
+ if (yesAllSessionActive)
14
+ return true;
15
+ const choice = await confirmEdit(filePath, newContent);
16
+ if (choice === 'yes_all_session') {
17
+ yesAllSessionActive = true;
18
+ return true;
19
+ }
20
+ return choice === 'yes';
21
+ }
22
+ export async function executeTool(name, argsJson, cwd) {
23
+ const tool = getToolByName(name);
24
+ if (!tool) {
25
+ return { success: false, output: '', error: `Unknown tool: ${name}` };
26
+ }
27
+ let args;
28
+ try {
29
+ args = JSON.parse(argsJson);
30
+ }
31
+ catch {
32
+ return { success: false, output: '', error: `Invalid JSON arguments for tool ${name}: ${argsJson}` };
33
+ }
34
+ // Validate required parameters for each tool to avoid confusing Node.js errors
35
+ // (e.g., path.resolve(undefined) → "paths[0] must be of type string")
36
+ const requiredParams = {
37
+ read_file: ['path'],
38
+ write_file: ['path', 'content'],
39
+ edit_file: ['path', 'old_string', 'new_string'],
40
+ execute_shell: ['command'],
41
+ search_files: ['pattern'],
42
+ };
43
+ const required = requiredParams[name];
44
+ if (required) {
45
+ for (const p of required) {
46
+ if (args[p] === undefined || args[p] === null) {
47
+ return { success: false, output: '', error: `Missing required parameter "${p}" for tool ${name}` };
48
+ }
49
+ }
50
+ }
51
+ // Show diff and require confirmation before writing files
52
+ if (name === 'edit_file') {
53
+ const filePath = resolve(args.path);
54
+ const oldString = args.old_string;
55
+ const newString = args.new_string;
56
+ const original = existsSync(filePath) ? await readFile(filePath, 'utf-8') : '';
57
+ const preview = applyEdit(original, oldString, newString);
58
+ if (preview === null) {
59
+ return { success: false, output: '', error: `old_string not found in ${filePath}.` };
60
+ }
61
+ const accepted = await confirmOrSkip(filePath, preview);
62
+ if (!accepted) {
63
+ return { success: false, output: '', error: 'Edit rejected by user.', userRejected: true };
64
+ }
65
+ }
66
+ else if (name === 'write_file') {
67
+ const filePath = resolve(args.path);
68
+ const content = args.content;
69
+ const accepted = await confirmOrSkip(filePath, content);
70
+ if (!accepted) {
71
+ return { success: false, output: '', error: 'Write rejected by user.', userRejected: true };
72
+ }
73
+ }
74
+ // Inject cwd into execute_shell if the model didn't provide one
75
+ if (name === 'execute_shell' && cwd && !args.cwd) {
76
+ args.cwd = cwd;
77
+ }
78
+ try {
79
+ return await tool.execute(args);
80
+ }
81
+ catch (err) {
82
+ const message = err instanceof Error ? err.message : String(err);
83
+ return { success: false, output: '', error: `Tool ${name} threw an error: ${message}` };
84
+ }
85
+ }
86
+ //# sourceMappingURL=executor.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"executor.js","sourceRoot":"","sources":["../../../src/core/tools/executor.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ import type { Tool } from '../../types.js';
2
+ export declare const listDirectoryTool: Tool;
@@ -0,0 +1,74 @@
1
+ import { readdir } from 'fs/promises';
2
+ import { join, resolve, relative } from 'path';
3
+ const MAX_ENTRIES = 200;
4
+ export const listDirectoryTool = {
5
+ definition: {
6
+ type: 'function',
7
+ function: {
8
+ name: 'list_directory',
9
+ description: 'List files and directories in a path. Returns a tree-like structure.',
10
+ parameters: {
11
+ type: 'object',
12
+ properties: {
13
+ path: {
14
+ type: 'string',
15
+ description: 'The directory path to list (defaults to current directory)',
16
+ },
17
+ depth: {
18
+ type: 'number',
19
+ description: 'Maximum depth to recurse (default: 2)',
20
+ },
21
+ },
22
+ required: [],
23
+ },
24
+ },
25
+ },
26
+ async execute(args) {
27
+ const dirPath = resolve(args.path ?? '.');
28
+ const maxDepth = args.depth ?? 2;
29
+ try {
30
+ const lines = [];
31
+ await walk(dirPath, dirPath, 0, maxDepth, lines);
32
+ if (lines.length === 0) {
33
+ return { success: true, output: '(empty directory)' };
34
+ }
35
+ const truncated = lines.length > MAX_ENTRIES;
36
+ const output = lines.slice(0, MAX_ENTRIES).join('\n') +
37
+ (truncated ? `\n… (${lines.length - MAX_ENTRIES} more entries not shown)` : '');
38
+ return { success: true, output };
39
+ }
40
+ catch (err) {
41
+ const message = err instanceof Error ? err.message : String(err);
42
+ return { success: false, output: '', error: `Failed to list ${dirPath}: ${message}` };
43
+ }
44
+ },
45
+ };
46
+ const SKIP_DIRS = new Set(['node_modules', '.git', 'dist', '.next', '__pycache__', '.cache']);
47
+ async function walk(root, dir, depth, maxDepth, lines) {
48
+ if (depth > maxDepth)
49
+ return;
50
+ const entries = await readdir(dir, { withFileTypes: true });
51
+ entries.sort((a, b) => {
52
+ if (a.isDirectory() !== b.isDirectory())
53
+ return a.isDirectory() ? -1 : 1;
54
+ return a.name.localeCompare(b.name);
55
+ });
56
+ for (const entry of entries) {
57
+ if (entry.name.startsWith('.') && depth > 0)
58
+ continue;
59
+ const indent = ' '.repeat(depth);
60
+ const rel = relative(root, join(dir, entry.name));
61
+ if (entry.isDirectory()) {
62
+ if (SKIP_DIRS.has(entry.name)) {
63
+ lines.push(`${indent}${entry.name}/ (skipped)`);
64
+ continue;
65
+ }
66
+ lines.push(`${indent}${entry.name}/`);
67
+ await walk(root, join(dir, entry.name), depth + 1, maxDepth, lines);
68
+ }
69
+ else {
70
+ lines.push(`${indent}${entry.name}`);
71
+ }
72
+ }
73
+ }
74
+ //# sourceMappingURL=list_directory.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"list_directory.js","sourceRoot":"","sources":["../../../src/core/tools/list_directory.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ import type { Tool } from '../../types.js';
2
+ export declare const readFileTool: Tool;
@@ -0,0 +1,40 @@
1
+ import { readFile as fsReadFile } from 'fs/promises';
2
+ import { resolve } from 'path';
3
+ const MAX_CHARS = 30_000;
4
+ export const readFileTool = {
5
+ definition: {
6
+ type: 'function',
7
+ function: {
8
+ name: 'read_file',
9
+ description: 'Read the contents of a file. Returns the file content as a string. Large files are truncated.',
10
+ parameters: {
11
+ type: 'object',
12
+ properties: {
13
+ path: {
14
+ type: 'string',
15
+ description: 'The path to the file to read (absolute or relative to cwd)',
16
+ },
17
+ },
18
+ required: ['path'],
19
+ },
20
+ },
21
+ },
22
+ async execute(args) {
23
+ const filePath = resolve(args.path);
24
+ try {
25
+ const content = await fsReadFile(filePath, 'utf-8');
26
+ if (content.length > MAX_CHARS) {
27
+ return {
28
+ success: true,
29
+ output: content.slice(0, MAX_CHARS) + `\n\n[File truncated — ${content.length} total chars, showing first ${MAX_CHARS}]`,
30
+ };
31
+ }
32
+ return { success: true, output: content };
33
+ }
34
+ catch (err) {
35
+ const message = err instanceof Error ? err.message : String(err);
36
+ return { success: false, output: '', error: `Failed to read ${filePath}: ${message}` };
37
+ }
38
+ },
39
+ };
40
+ //# sourceMappingURL=read_file.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"read_file.js","sourceRoot":"","sources":["../../../src/core/tools/read_file.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,IAAI,UAAU,EAAE,MAAM,aAAa,CAAC;AACrD,OAAO,EAAE,OAAO,EAAE,MAAM,MAAM,CAAC;AAG/B,MAAM,SAAS,GAAG,MAAM,CAAC;AAEzB,MAAM,CAAC,MAAM,YAAY,GAAS;IAChC,UAAU,EAAE;QACV,IAAI,EAAE,UAAU;QAChB,QAAQ,EAAE;YACR,IAAI,EAAE,WAAW;YACjB,WAAW,EAAE,+FAA+F;YAC5G,UAAU,EAAE;gBACV,IAAI,EAAE,QAAQ;gBACd,UAAU,EAAE;oBACV,IAAI,EAAE;wBACJ,IAAI,EAAE,QAAQ;wBACd,WAAW,EAAE,4DAA4D;qBAC1E;iBACF;gBACD,QAAQ,EAAE,CAAC,MAAM,CAAC;aACnB;SACF;KACF;IAED,KAAK,CAAC,OAAO,CAAC,IAAI;QAChB,MAAM,QAAQ,GAAG,OAAO,CAAC,IAAI,CAAC,IAAc,CAAC,CAAC;QAC9C,IAAI,CAAC;YACH,MAAM,OAAO,GAAG,MAAM,UAAU,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;YACpD,IAAI,OAAO,CAAC,MAAM,GAAG,SAAS,EAAE,CAAC;gBAC/B,OAAO;oBACL,OAAO,EAAE,IAAI;oBACb,MAAM,EAAE,OAAO,CAAC,KAAK,CAAC,CAAC,EAAE,SAAS,CAAC,GAAG,yBAAyB,OAAO,CAAC,MAAM,+BAA+B,SAAS,GAAG;iBACzH,CAAC;YACJ,CAAC;YACD,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,CAAC;QAC5C,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,MAAM,OAAO,GAAG,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;YACjE,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,MAAM,EAAE,EAAE,EAAE,KAAK,EAAE,kBAAkB,QAAQ,KAAK,OAAO,EAAE,EAAE,CAAC;QACzF,CAAC;IACH,CAAC;CACF,CAAC"}
@@ -0,0 +1,4 @@
1
+ import type { Tool, ToolDefinition } from '../../types.js';
2
+ export declare function getAllTools(): Tool[];
3
+ export declare function getToolDefinitions(): ToolDefinition[];
4
+ export declare function getToolByName(name: string): Tool | undefined;
@@ -0,0 +1,24 @@
1
+ import { readFileTool } from './read_file.js';
2
+ import { writeFileTool } from './write_file.js';
3
+ import { editFileTool } from './edit_file.js';
4
+ import { executeShellTool } from './execute_shell.js';
5
+ import { listDirectoryTool } from './list_directory.js';
6
+ import { searchFilesTool } from './search_files.js';
7
+ const ALL_TOOLS = [
8
+ readFileTool,
9
+ writeFileTool,
10
+ editFileTool,
11
+ executeShellTool,
12
+ listDirectoryTool,
13
+ searchFilesTool,
14
+ ];
15
+ export function getAllTools() {
16
+ return ALL_TOOLS;
17
+ }
18
+ export function getToolDefinitions() {
19
+ return ALL_TOOLS.map((t) => t.definition);
20
+ }
21
+ export function getToolByName(name) {
22
+ return ALL_TOOLS.find((t) => t.definition.function.name === name);
23
+ }
24
+ //# sourceMappingURL=registry.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"registry.js","sourceRoot":"","sources":["../../../src/core/tools/registry.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAC9C,OAAO,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAChD,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAC9C,OAAO,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AACtD,OAAO,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAC;AACxD,OAAO,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AAEpD,MAAM,SAAS,GAAW;IACxB,YAAY;IACZ,aAAa;IACb,YAAY;IACZ,gBAAgB;IAChB,iBAAiB;IACjB,eAAe;CAChB,CAAC;AAEF,MAAM,UAAU,WAAW;IACzB,OAAO,SAAS,CAAC;AACnB,CAAC;AAED,MAAM,UAAU,kBAAkB;IAChC,OAAO,SAAS,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC;AAC5C,CAAC;AAED,MAAM,UAAU,aAAa,CAAC,IAAY;IACxC,OAAO,SAAS,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,UAAU,CAAC,QAAQ,CAAC,IAAI,KAAK,IAAI,CAAC,CAAC;AACpE,CAAC"}
@@ -0,0 +1,2 @@
1
+ import type { Tool } from '../../types.js';
2
+ export declare const searchFilesTool: Tool;
@@ -0,0 +1,88 @@
1
+ import { readdir, readFile } from 'fs/promises';
2
+ import { join, resolve, relative } from 'path';
3
+ const MAX_RESULTS = 50;
4
+ const SKIP_DIRS = new Set(['node_modules', '.git', 'dist', '.next', '__pycache__', '.cache']);
5
+ export const searchFilesTool = {
6
+ definition: {
7
+ type: 'function',
8
+ function: {
9
+ name: 'search_files',
10
+ description: 'Search for a pattern in files. Returns matching file paths and line snippets.',
11
+ parameters: {
12
+ type: 'object',
13
+ properties: {
14
+ pattern: {
15
+ type: 'string',
16
+ description: 'The text pattern to search for',
17
+ },
18
+ path: {
19
+ type: 'string',
20
+ description: 'Directory to search in (defaults to current directory)',
21
+ },
22
+ file_pattern: {
23
+ type: 'string',
24
+ description: 'Glob-like file extension filter, e.g. ".ts" or ".py" (optional)',
25
+ },
26
+ },
27
+ required: ['pattern'],
28
+ },
29
+ },
30
+ },
31
+ async execute(args) {
32
+ const pattern = args.pattern;
33
+ const searchPath = resolve(args.path ?? '.');
34
+ const filePattern = args.file_pattern;
35
+ const results = [];
36
+ try {
37
+ await searchDir(searchPath, searchPath, pattern, filePattern, results);
38
+ if (results.length === 0) {
39
+ return { success: true, output: `No matches found for "${pattern}"` };
40
+ }
41
+ const truncated = results.length > MAX_RESULTS;
42
+ const output = results.slice(0, MAX_RESULTS).join('\n') +
43
+ (truncated ? `\n… (showing first ${MAX_RESULTS} of ${results.length} matches)` : '');
44
+ return { success: true, output };
45
+ }
46
+ catch (err) {
47
+ const message = err instanceof Error ? err.message : String(err);
48
+ return { success: false, output: '', error: `Search failed: ${message}` };
49
+ }
50
+ },
51
+ };
52
+ async function searchDir(root, dir, pattern, filePattern, results) {
53
+ if (results.length >= MAX_RESULTS)
54
+ return;
55
+ const entries = await readdir(dir, { withFileTypes: true });
56
+ for (const entry of entries) {
57
+ if (results.length >= MAX_RESULTS)
58
+ return;
59
+ if (entry.name.startsWith('.'))
60
+ continue;
61
+ const fullPath = join(dir, entry.name);
62
+ if (entry.isDirectory()) {
63
+ if (SKIP_DIRS.has(entry.name))
64
+ continue;
65
+ await searchDir(root, fullPath, pattern, filePattern, results);
66
+ }
67
+ else {
68
+ if (filePattern && !entry.name.endsWith(filePattern))
69
+ continue;
70
+ try {
71
+ const content = await readFile(fullPath, 'utf-8');
72
+ const lines = content.split('\n');
73
+ const rel = relative(root, fullPath);
74
+ for (let i = 0; i < lines.length; i++) {
75
+ if (lines[i].includes(pattern)) {
76
+ results.push(`${rel}:${i + 1}: ${lines[i].trim()}`);
77
+ if (results.length >= MAX_RESULTS)
78
+ return;
79
+ }
80
+ }
81
+ }
82
+ catch {
83
+ // skip unreadable files
84
+ }
85
+ }
86
+ }
87
+ }
88
+ //# sourceMappingURL=search_files.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"search_files.js","sourceRoot":"","sources":["../../../src/core/tools/search_files.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ import type { Tool } from '../../types.js';
2
+ export declare const writeFileTool: Tool;
@@ -0,0 +1,43 @@
1
+ import { writeFile as fsWriteFile, mkdir, readFile } from 'fs/promises';
2
+ import { dirname, resolve } from 'path';
3
+ import { printDiff } from '../../utils/display.js';
4
+ export const writeFileTool = {
5
+ definition: {
6
+ type: 'function',
7
+ function: {
8
+ name: 'write_file',
9
+ description: 'Write content to a file, creating parent directories if needed. Overwrites existing content.',
10
+ parameters: {
11
+ type: 'object',
12
+ properties: {
13
+ path: {
14
+ type: 'string',
15
+ description: 'The path to the file to write',
16
+ },
17
+ content: {
18
+ type: 'string',
19
+ description: 'The content to write to the file',
20
+ },
21
+ },
22
+ required: ['path', 'content'],
23
+ },
24
+ },
25
+ },
26
+ async execute(args) {
27
+ const filePath = resolve(args.path);
28
+ const content = args.content;
29
+ try {
30
+ await mkdir(dirname(filePath), { recursive: true });
31
+ // Read existing content for diff (empty string if file doesn't exist yet)
32
+ const oldContent = await readFile(filePath, 'utf-8').catch(() => '');
33
+ await fsWriteFile(filePath, content, 'utf-8');
34
+ printDiff(filePath, oldContent, content);
35
+ return { success: true, output: `Wrote ${content.length} chars to ${filePath}` };
36
+ }
37
+ catch (err) {
38
+ const message = err instanceof Error ? err.message : String(err);
39
+ return { success: false, output: '', error: `Failed to write ${filePath}: ${message}` };
40
+ }
41
+ },
42
+ };
43
+ //# sourceMappingURL=write_file.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"write_file.js","sourceRoot":"","sources":["../../../src/core/tools/write_file.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,IAAI,WAAW,EAAE,KAAK,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AACxE,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,MAAM,CAAC;AAExC,OAAO,EAAE,SAAS,EAAE,MAAM,wBAAwB,CAAC;AAEnD,MAAM,CAAC,MAAM,aAAa,GAAS;IACjC,UAAU,EAAE;QACV,IAAI,EAAE,UAAU;QAChB,QAAQ,EAAE;YACR,IAAI,EAAE,YAAY;YAClB,WAAW,EAAE,8FAA8F;YAC3G,UAAU,EAAE;gBACV,IAAI,EAAE,QAAQ;gBACd,UAAU,EAAE;oBACV,IAAI,EAAE;wBACJ,IAAI,EAAE,QAAQ;wBACd,WAAW,EAAE,+BAA+B;qBAC7C;oBACD,OAAO,EAAE;wBACP,IAAI,EAAE,QAAQ;wBACd,WAAW,EAAE,kCAAkC;qBAChD;iBACF;gBACD,QAAQ,EAAE,CAAC,MAAM,EAAE,SAAS,CAAC;aAC9B;SACF;KACF;IAED,KAAK,CAAC,OAAO,CAAC,IAAI;QAChB,MAAM,QAAQ,GAAG,OAAO,CAAC,IAAI,CAAC,IAAc,CAAC,CAAC;QAC9C,MAAM,OAAO,GAAG,IAAI,CAAC,OAAiB,CAAC;QACvC,IAAI,CAAC;YACH,MAAM,KAAK,CAAC,OAAO,CAAC,QAAQ,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;YACpD,0EAA0E;YAC1E,MAAM,UAAU,GAAG,MAAM,QAAQ,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,EAAE,CAAC,CAAC;YACrE,MAAM,WAAW,CAAC,QAAQ,EAAE,OAAO,EAAE,OAAO,CAAC,CAAC;YAC9C,SAAS,CAAC,QAAQ,EAAE,UAAU,EAAE,OAAO,CAAC,CAAC;YACzC,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,SAAS,OAAO,CAAC,MAAM,aAAa,QAAQ,EAAE,EAAE,CAAC;QACnF,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,MAAM,OAAO,GAAG,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;YACjE,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,MAAM,EAAE,EAAE,EAAE,KAAK,EAAE,mBAAmB,QAAQ,KAAK,OAAO,EAAE,EAAE,CAAC;QAC1F,CAAC;IACH,CAAC;CACF,CAAC"}
@@ -0,0 +1,8 @@
1
+ import OpenAI from 'openai';
2
+ import type { CodeGruntConfig } from '../../types.js';
3
+ export declare function createOpenAIClient(config: CodeGruntConfig): OpenAI;
4
+ /**
5
+ * Validates an API key by hitting the /models endpoint.
6
+ * Returns null on success, or an error message string on failure.
7
+ */
8
+ export declare function validateApiKey(apiKey: string, baseURL: string): Promise<string | null>;
@@ -0,0 +1,27 @@
1
+ import OpenAI from 'openai';
2
+ export function createOpenAIClient(config) {
3
+ return new OpenAI({
4
+ apiKey: config.apiKey,
5
+ baseURL: config.baseURL,
6
+ });
7
+ }
8
+ /**
9
+ * Validates an API key by hitting the /models endpoint.
10
+ * Returns null on success, or an error message string on failure.
11
+ */
12
+ export async function validateApiKey(apiKey, baseURL) {
13
+ const client = new OpenAI({ apiKey, baseURL });
14
+ try {
15
+ await client.models.list();
16
+ return null;
17
+ }
18
+ catch (err) {
19
+ if (err instanceof OpenAI.APIError) {
20
+ if (err.status === 401)
21
+ return 'Invalid API key (authentication failed).';
22
+ return `API error ${err.status}: ${err.message}`;
23
+ }
24
+ return `Network error: ${err instanceof Error ? err.message : String(err)}`;
25
+ }
26
+ }
27
+ //# sourceMappingURL=client.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client.js","sourceRoot":"","sources":["../../../src/providers/deepseek/client.ts"],"names":[],"mappings":"AAAA,OAAO,MAAM,MAAM,QAAQ,CAAC;AAG5B,MAAM,UAAU,kBAAkB,CAAC,MAAuB;IACxD,OAAO,IAAI,MAAM,CAAC;QAChB,MAAM,EAAE,MAAM,CAAC,MAAM;QACrB,OAAO,EAAE,MAAM,CAAC,OAAO;KACxB,CAAC,CAAC;AACL,CAAC;AAED;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,cAAc,CAAC,MAAc,EAAE,OAAe;IAClE,MAAM,MAAM,GAAG,IAAI,MAAM,CAAC,EAAE,MAAM,EAAE,OAAO,EAAE,CAAC,CAAC;IAC/C,IAAI,CAAC;QACH,MAAM,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC;QAC3B,OAAO,IAAI,CAAC;IACd,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,IAAI,GAAG,YAAY,MAAM,CAAC,QAAQ,EAAE,CAAC;YACnC,IAAI,GAAG,CAAC,MAAM,KAAK,GAAG;gBAAE,OAAO,0CAA0C,CAAC;YAC1E,OAAO,aAAa,GAAG,CAAC,MAAM,KAAK,GAAG,CAAC,OAAO,EAAE,CAAC;QACnD,CAAC;QACD,OAAO,kBAAkB,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC;IAC9E,CAAC;AACH,CAAC"}
@@ -0,0 +1,8 @@
1
+ import type { LLMProvider, Message, RequestOptions, StreamChunk } from '../../types.js';
2
+ import type { CodeGruntConfig } from '../../types.js';
3
+ export declare class DeepSeekProvider implements LLMProvider {
4
+ readonly id = "deepseek";
5
+ private client;
6
+ constructor(config: CodeGruntConfig);
7
+ stream(messages: Message[], options: RequestOptions): AsyncIterable<StreamChunk>;
8
+ }