grokcodecli 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/.claude/settings.local.json +32 -0
- package/README.md +1464 -0
- package/dist/cli.d.ts +3 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +61 -0
- package/dist/cli.js.map +1 -0
- package/dist/commands/loader.d.ts +34 -0
- package/dist/commands/loader.d.ts.map +1 -0
- package/dist/commands/loader.js +192 -0
- package/dist/commands/loader.js.map +1 -0
- package/dist/config/manager.d.ts +21 -0
- package/dist/config/manager.d.ts.map +1 -0
- package/dist/config/manager.js +203 -0
- package/dist/config/manager.js.map +1 -0
- package/dist/conversation/chat.d.ts +50 -0
- package/dist/conversation/chat.d.ts.map +1 -0
- package/dist/conversation/chat.js +1145 -0
- package/dist/conversation/chat.js.map +1 -0
- package/dist/conversation/history.d.ts +24 -0
- package/dist/conversation/history.d.ts.map +1 -0
- package/dist/conversation/history.js +103 -0
- package/dist/conversation/history.js.map +1 -0
- package/dist/grok/client.d.ts +86 -0
- package/dist/grok/client.d.ts.map +1 -0
- package/dist/grok/client.js +106 -0
- package/dist/grok/client.js.map +1 -0
- package/dist/index.d.ts +7 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +8 -0
- package/dist/index.js.map +1 -0
- package/dist/permissions/manager.d.ts +26 -0
- package/dist/permissions/manager.d.ts.map +1 -0
- package/dist/permissions/manager.js +170 -0
- package/dist/permissions/manager.js.map +1 -0
- package/dist/tools/bash.d.ts +8 -0
- package/dist/tools/bash.d.ts.map +1 -0
- package/dist/tools/bash.js +102 -0
- package/dist/tools/bash.js.map +1 -0
- package/dist/tools/edit.d.ts +9 -0
- package/dist/tools/edit.d.ts.map +1 -0
- package/dist/tools/edit.js +61 -0
- package/dist/tools/edit.js.map +1 -0
- package/dist/tools/glob.d.ts +7 -0
- package/dist/tools/glob.d.ts.map +1 -0
- package/dist/tools/glob.js +38 -0
- package/dist/tools/glob.js.map +1 -0
- package/dist/tools/grep.d.ts +8 -0
- package/dist/tools/grep.d.ts.map +1 -0
- package/dist/tools/grep.js +78 -0
- package/dist/tools/grep.js.map +1 -0
- package/dist/tools/read.d.ts +8 -0
- package/dist/tools/read.d.ts.map +1 -0
- package/dist/tools/read.js +96 -0
- package/dist/tools/read.js.map +1 -0
- package/dist/tools/registry.d.ts +42 -0
- package/dist/tools/registry.d.ts.map +1 -0
- package/dist/tools/registry.js +230 -0
- package/dist/tools/registry.js.map +1 -0
- package/dist/tools/webfetch.d.ts +10 -0
- package/dist/tools/webfetch.d.ts.map +1 -0
- package/dist/tools/webfetch.js +108 -0
- package/dist/tools/webfetch.js.map +1 -0
- package/dist/tools/websearch.d.ts +7 -0
- package/dist/tools/websearch.d.ts.map +1 -0
- package/dist/tools/websearch.js +180 -0
- package/dist/tools/websearch.js.map +1 -0
- package/dist/tools/write.d.ts +7 -0
- package/dist/tools/write.d.ts.map +1 -0
- package/dist/tools/write.js +80 -0
- package/dist/tools/write.js.map +1 -0
- package/dist/utils/security.d.ts +36 -0
- package/dist/utils/security.d.ts.map +1 -0
- package/dist/utils/security.js +227 -0
- package/dist/utils/security.js.map +1 -0
- package/dist/utils/ui.d.ts +49 -0
- package/dist/utils/ui.d.ts.map +1 -0
- package/dist/utils/ui.js +302 -0
- package/dist/utils/ui.js.map +1 -0
- package/package.json +45 -0
- package/src/cli.ts +68 -0
- package/src/commands/loader.ts +244 -0
- package/src/config/manager.ts +239 -0
- package/src/conversation/chat.ts +1294 -0
- package/src/conversation/history.ts +131 -0
- package/src/grok/client.ts +192 -0
- package/src/index.ts +8 -0
- package/src/permissions/manager.ts +208 -0
- package/src/tools/bash.ts +119 -0
- package/src/tools/edit.ts +73 -0
- package/src/tools/glob.ts +49 -0
- package/src/tools/grep.ts +96 -0
- package/src/tools/read.ts +116 -0
- package/src/tools/registry.ts +248 -0
- package/src/tools/webfetch.ts +127 -0
- package/src/tools/websearch.ts +219 -0
- package/src/tools/write.ts +94 -0
- package/src/utils/security.ts +259 -0
- package/src/utils/ui.ts +382 -0
- package/tsconfig.json +22 -0
|
@@ -0,0 +1,170 @@
|
|
|
1
|
+
import * as readline from 'readline';
|
|
2
|
+
import chalk from 'chalk';
|
|
3
|
+
const TOOL_RISK_LEVELS = {
|
|
4
|
+
Read: 'read',
|
|
5
|
+
Glob: 'read',
|
|
6
|
+
Grep: 'read',
|
|
7
|
+
Write: 'write',
|
|
8
|
+
Edit: 'write',
|
|
9
|
+
Bash: 'execute',
|
|
10
|
+
WebFetch: 'read',
|
|
11
|
+
};
|
|
12
|
+
const RISK_COLORS = {
|
|
13
|
+
read: chalk.green,
|
|
14
|
+
write: chalk.yellow,
|
|
15
|
+
execute: chalk.red,
|
|
16
|
+
};
|
|
17
|
+
const RISK_ICONS = {
|
|
18
|
+
read: '📖',
|
|
19
|
+
write: '✏️',
|
|
20
|
+
execute: '⚡',
|
|
21
|
+
};
|
|
22
|
+
export class PermissionManager {
|
|
23
|
+
config;
|
|
24
|
+
rl = null;
|
|
25
|
+
constructor(autoApprove = []) {
|
|
26
|
+
this.config = {
|
|
27
|
+
autoApprove,
|
|
28
|
+
alwaysDeny: [],
|
|
29
|
+
sessionApproved: new Set(),
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
setReadlineInterface(rl) {
|
|
33
|
+
this.rl = rl;
|
|
34
|
+
}
|
|
35
|
+
async requestPermission(request) {
|
|
36
|
+
const { tool, description, riskLevel, details } = request;
|
|
37
|
+
// Check if always denied
|
|
38
|
+
if (this.config.alwaysDeny.includes(tool)) {
|
|
39
|
+
console.log(chalk.red(`\n⛔ Tool "${tool}" is blocked by configuration.\n`));
|
|
40
|
+
return false;
|
|
41
|
+
}
|
|
42
|
+
// Check if auto-approved
|
|
43
|
+
if (this.config.autoApprove.includes(tool) || this.config.autoApprove.includes('*')) {
|
|
44
|
+
return true;
|
|
45
|
+
}
|
|
46
|
+
// Check if approved for this session
|
|
47
|
+
const sessionKey = this.getSessionKey(tool, details);
|
|
48
|
+
if (this.config.sessionApproved.has(sessionKey)) {
|
|
49
|
+
return true;
|
|
50
|
+
}
|
|
51
|
+
// Read-only operations can be auto-approved with lower risk
|
|
52
|
+
if (riskLevel === 'read' && this.config.autoApprove.includes('read')) {
|
|
53
|
+
return true;
|
|
54
|
+
}
|
|
55
|
+
// Prompt user for permission
|
|
56
|
+
return this.promptUser(request);
|
|
57
|
+
}
|
|
58
|
+
async promptUser(request) {
|
|
59
|
+
const { tool, description, riskLevel, details } = request;
|
|
60
|
+
const color = RISK_COLORS[riskLevel];
|
|
61
|
+
const icon = RISK_ICONS[riskLevel];
|
|
62
|
+
console.log(chalk.cyan('\n┌─────────────────────────────────────────────────────┐'));
|
|
63
|
+
console.log(chalk.cyan('│') + ` ${icon} ${color(`Permission Request: ${tool}`)}`.padEnd(60) + chalk.cyan('│'));
|
|
64
|
+
console.log(chalk.cyan('├─────────────────────────────────────────────────────┤'));
|
|
65
|
+
console.log(chalk.cyan('│') + ` ${description}`.padEnd(52) + chalk.cyan('│'));
|
|
66
|
+
// Show details
|
|
67
|
+
if (details) {
|
|
68
|
+
console.log(chalk.cyan('├─────────────────────────────────────────────────────┤'));
|
|
69
|
+
for (const [key, value] of Object.entries(details)) {
|
|
70
|
+
const valueStr = typeof value === 'string'
|
|
71
|
+
? value.length > 45 ? value.slice(0, 42) + '...' : value
|
|
72
|
+
: String(value);
|
|
73
|
+
console.log(chalk.cyan('│') + chalk.gray(` ${key}: `) + valueStr.padEnd(42 - key.length) + chalk.cyan('│'));
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
console.log(chalk.cyan('└─────────────────────────────────────────────────────┘'));
|
|
77
|
+
console.log();
|
|
78
|
+
console.log(` ${chalk.green('[y]')} Yes, allow once`);
|
|
79
|
+
console.log(` ${chalk.green('[a]')} Allow for this session`);
|
|
80
|
+
console.log(` ${chalk.red('[n]')} No, deny`);
|
|
81
|
+
console.log(` ${chalk.red('[!]')} Deny and block for session`);
|
|
82
|
+
console.log();
|
|
83
|
+
const answer = await this.question(chalk.cyan('Choice [y/a/n/!]: '));
|
|
84
|
+
const choice = answer.toLowerCase().trim();
|
|
85
|
+
switch (choice) {
|
|
86
|
+
case 'y':
|
|
87
|
+
case 'yes':
|
|
88
|
+
return true;
|
|
89
|
+
case 'a':
|
|
90
|
+
case 'always':
|
|
91
|
+
this.config.sessionApproved.add(this.getSessionKey(tool, details));
|
|
92
|
+
console.log(chalk.green(`✓ "${tool}" approved for this session.\n`));
|
|
93
|
+
return true;
|
|
94
|
+
case 'n':
|
|
95
|
+
case 'no':
|
|
96
|
+
case '':
|
|
97
|
+
console.log(chalk.yellow('⊘ Denied.\n'));
|
|
98
|
+
return false;
|
|
99
|
+
case '!':
|
|
100
|
+
case 'block':
|
|
101
|
+
this.config.alwaysDeny.push(tool);
|
|
102
|
+
console.log(chalk.red(`⛔ "${tool}" blocked for this session.\n`));
|
|
103
|
+
return false;
|
|
104
|
+
default:
|
|
105
|
+
console.log(chalk.gray('Invalid choice, defaulting to deny.\n'));
|
|
106
|
+
return false;
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
getSessionKey(tool, details) {
|
|
110
|
+
// For some tools, scope approval to specific paths/commands
|
|
111
|
+
if (tool === 'Bash' && details?.command) {
|
|
112
|
+
// Approve specific command patterns
|
|
113
|
+
const cmd = String(details.command);
|
|
114
|
+
if (cmd.startsWith('git '))
|
|
115
|
+
return `${tool}:git`;
|
|
116
|
+
if (cmd.startsWith('npm '))
|
|
117
|
+
return `${tool}:npm`;
|
|
118
|
+
if (cmd.startsWith('ls ') || cmd === 'ls')
|
|
119
|
+
return `${tool}:ls`;
|
|
120
|
+
return tool;
|
|
121
|
+
}
|
|
122
|
+
if ((tool === 'Read' || tool === 'Write' || tool === 'Edit') && details?.file_path) {
|
|
123
|
+
// Could scope to directory
|
|
124
|
+
return tool;
|
|
125
|
+
}
|
|
126
|
+
return tool;
|
|
127
|
+
}
|
|
128
|
+
question(prompt) {
|
|
129
|
+
return new Promise((resolve) => {
|
|
130
|
+
if (this.rl) {
|
|
131
|
+
this.rl.question(prompt, resolve);
|
|
132
|
+
}
|
|
133
|
+
else {
|
|
134
|
+
// Fallback if no readline interface
|
|
135
|
+
const tempRl = readline.createInterface({
|
|
136
|
+
input: process.stdin,
|
|
137
|
+
output: process.stdout,
|
|
138
|
+
});
|
|
139
|
+
tempRl.question(prompt, (answer) => {
|
|
140
|
+
tempRl.close();
|
|
141
|
+
resolve(answer);
|
|
142
|
+
});
|
|
143
|
+
}
|
|
144
|
+
});
|
|
145
|
+
}
|
|
146
|
+
getToolRiskLevel(tool) {
|
|
147
|
+
return TOOL_RISK_LEVELS[tool] || 'execute';
|
|
148
|
+
}
|
|
149
|
+
formatToolDetails(tool, params) {
|
|
150
|
+
switch (tool) {
|
|
151
|
+
case 'Read':
|
|
152
|
+
return `Read file: ${params.file_path}`;
|
|
153
|
+
case 'Write':
|
|
154
|
+
return `Write to file: ${params.file_path}`;
|
|
155
|
+
case 'Edit':
|
|
156
|
+
return `Edit file: ${params.file_path}`;
|
|
157
|
+
case 'Bash':
|
|
158
|
+
return `Execute command: ${params.command}`;
|
|
159
|
+
case 'Glob':
|
|
160
|
+
return `Search for files: ${params.pattern}`;
|
|
161
|
+
case 'Grep':
|
|
162
|
+
return `Search in files: ${params.pattern}`;
|
|
163
|
+
case 'WebFetch':
|
|
164
|
+
return `Fetch URL: ${params.url}`;
|
|
165
|
+
default:
|
|
166
|
+
return `Execute ${tool}`;
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
//# sourceMappingURL=manager.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"manager.js","sourceRoot":"","sources":["../../src/permissions/manager.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"bash.d.ts","sourceRoot":"","sources":["../../src/tools/bash.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAI3C,MAAM,WAAW,cAAc;IAC7B,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,GAAG,CAAC,EAAE,MAAM,CAAC;CACd;AAKD,wBAAsB,QAAQ,CAAC,MAAM,EAAE,cAAc,GAAG,OAAO,CAAC,UAAU,CAAC,CAwG1E"}
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
import { spawn } from 'child_process';
|
|
2
|
+
import { validateCommand, sanitizeOutput } from '../utils/security.js';
|
|
3
|
+
import chalk from 'chalk';
|
|
4
|
+
// Maximum output size to prevent memory issues
|
|
5
|
+
const MAX_OUTPUT_SIZE = 1024 * 1024; // 1MB
|
|
6
|
+
export async function bashTool(params) {
|
|
7
|
+
const timeout = params.timeout ?? 120000; // 2 minutes default
|
|
8
|
+
// Security validation
|
|
9
|
+
const security = validateCommand(params.command);
|
|
10
|
+
if (!security.allowed) {
|
|
11
|
+
return {
|
|
12
|
+
success: false,
|
|
13
|
+
output: '',
|
|
14
|
+
error: `Security: ${security.reason}${security.suggestion ? ` - ${security.suggestion}` : ''}`,
|
|
15
|
+
};
|
|
16
|
+
}
|
|
17
|
+
// Warn about risky commands but allow them
|
|
18
|
+
let warning = '';
|
|
19
|
+
if (security.severity === 'medium') {
|
|
20
|
+
warning = chalk.yellow(`⚠️ ${security.reason}\n`);
|
|
21
|
+
}
|
|
22
|
+
return new Promise((resolve) => {
|
|
23
|
+
let stdout = '';
|
|
24
|
+
let stderr = '';
|
|
25
|
+
let killed = false;
|
|
26
|
+
let outputTruncated = false;
|
|
27
|
+
const child = spawn('bash', ['-c', params.command], {
|
|
28
|
+
cwd: params.cwd || process.cwd(),
|
|
29
|
+
env: {
|
|
30
|
+
...process.env,
|
|
31
|
+
// Prevent color codes from commands that might interfere
|
|
32
|
+
FORCE_COLOR: '0',
|
|
33
|
+
NO_COLOR: '1',
|
|
34
|
+
},
|
|
35
|
+
});
|
|
36
|
+
const timer = setTimeout(() => {
|
|
37
|
+
killed = true;
|
|
38
|
+
child.kill('SIGTERM');
|
|
39
|
+
// Force kill after 5 seconds if still running
|
|
40
|
+
setTimeout(() => {
|
|
41
|
+
try {
|
|
42
|
+
child.kill('SIGKILL');
|
|
43
|
+
}
|
|
44
|
+
catch {
|
|
45
|
+
// Already dead
|
|
46
|
+
}
|
|
47
|
+
}, 5000);
|
|
48
|
+
}, timeout);
|
|
49
|
+
child.stdout.on('data', (data) => {
|
|
50
|
+
if (stdout.length < MAX_OUTPUT_SIZE) {
|
|
51
|
+
stdout += data.toString();
|
|
52
|
+
}
|
|
53
|
+
else if (!outputTruncated) {
|
|
54
|
+
outputTruncated = true;
|
|
55
|
+
stdout += '\n... (output truncated)';
|
|
56
|
+
}
|
|
57
|
+
});
|
|
58
|
+
child.stderr.on('data', (data) => {
|
|
59
|
+
if (stderr.length < MAX_OUTPUT_SIZE) {
|
|
60
|
+
stderr += data.toString();
|
|
61
|
+
}
|
|
62
|
+
});
|
|
63
|
+
child.on('close', (code, signal) => {
|
|
64
|
+
clearTimeout(timer);
|
|
65
|
+
if (killed) {
|
|
66
|
+
resolve({
|
|
67
|
+
success: false,
|
|
68
|
+
output: sanitizeOutput(stdout),
|
|
69
|
+
error: `Command timed out after ${timeout / 1000}s and was terminated`,
|
|
70
|
+
});
|
|
71
|
+
return;
|
|
72
|
+
}
|
|
73
|
+
// Combine and sanitize output
|
|
74
|
+
let output = sanitizeOutput(stdout);
|
|
75
|
+
if (stderr && code !== 0) {
|
|
76
|
+
output += (output ? '\n' : '') + chalk.red('stderr: ') + sanitizeOutput(stderr);
|
|
77
|
+
}
|
|
78
|
+
if (code === 0) {
|
|
79
|
+
resolve({
|
|
80
|
+
success: true,
|
|
81
|
+
output: warning + (output.trim() || '(command completed with no output)'),
|
|
82
|
+
});
|
|
83
|
+
}
|
|
84
|
+
else {
|
|
85
|
+
resolve({
|
|
86
|
+
success: false,
|
|
87
|
+
output: output.trim(),
|
|
88
|
+
error: sanitizeOutput(stderr.trim()) || `Command exited with code ${code}${signal ? ` (signal: ${signal})` : ''}`,
|
|
89
|
+
});
|
|
90
|
+
}
|
|
91
|
+
});
|
|
92
|
+
child.on('error', (error) => {
|
|
93
|
+
clearTimeout(timer);
|
|
94
|
+
resolve({
|
|
95
|
+
success: false,
|
|
96
|
+
output: '',
|
|
97
|
+
error: `Failed to execute command: ${error.message}`,
|
|
98
|
+
});
|
|
99
|
+
});
|
|
100
|
+
});
|
|
101
|
+
}
|
|
102
|
+
//# sourceMappingURL=bash.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"bash.js","sourceRoot":"","sources":["../../src/tools/bash.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { ToolResult } from './registry.js';
|
|
2
|
+
export interface EditToolParams {
|
|
3
|
+
file_path: string;
|
|
4
|
+
old_string: string;
|
|
5
|
+
new_string: string;
|
|
6
|
+
replace_all?: boolean;
|
|
7
|
+
}
|
|
8
|
+
export declare function editTool(params: EditToolParams): Promise<ToolResult>;
|
|
9
|
+
//# sourceMappingURL=edit.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"edit.d.ts","sourceRoot":"","sources":["../../src/tools/edit.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAE3C,MAAM,WAAW,cAAc;IAC7B,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC;IACnB,WAAW,CAAC,EAAE,OAAO,CAAC;CACvB;AAED,wBAAsB,QAAQ,CAAC,MAAM,EAAE,cAAc,GAAG,OAAO,CAAC,UAAU,CAAC,CA6D1E"}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import * as fs from 'fs/promises';
|
|
2
|
+
import * as path from 'path';
|
|
3
|
+
export async function editTool(params) {
|
|
4
|
+
try {
|
|
5
|
+
const filePath = path.resolve(params.file_path);
|
|
6
|
+
// Read existing content
|
|
7
|
+
let content;
|
|
8
|
+
try {
|
|
9
|
+
content = await fs.readFile(filePath, 'utf-8');
|
|
10
|
+
}
|
|
11
|
+
catch (error) {
|
|
12
|
+
const err = error;
|
|
13
|
+
if (err.code === 'ENOENT') {
|
|
14
|
+
return { success: false, output: '', error: `File not found: ${params.file_path}` };
|
|
15
|
+
}
|
|
16
|
+
throw error;
|
|
17
|
+
}
|
|
18
|
+
// Check if old_string exists
|
|
19
|
+
if (!content.includes(params.old_string)) {
|
|
20
|
+
return {
|
|
21
|
+
success: false,
|
|
22
|
+
output: '',
|
|
23
|
+
error: `String not found in file. Make sure the old_string matches exactly including whitespace.`,
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
// Check for uniqueness if not replace_all
|
|
27
|
+
if (!params.replace_all) {
|
|
28
|
+
const occurrences = content.split(params.old_string).length - 1;
|
|
29
|
+
if (occurrences > 1) {
|
|
30
|
+
return {
|
|
31
|
+
success: false,
|
|
32
|
+
output: '',
|
|
33
|
+
error: `Found ${occurrences} occurrences of the string. Use replace_all: true to replace all, or provide a more specific string.`,
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
// Perform replacement
|
|
38
|
+
let newContent;
|
|
39
|
+
let replacements;
|
|
40
|
+
if (params.replace_all) {
|
|
41
|
+
const parts = content.split(params.old_string);
|
|
42
|
+
replacements = parts.length - 1;
|
|
43
|
+
newContent = parts.join(params.new_string);
|
|
44
|
+
}
|
|
45
|
+
else {
|
|
46
|
+
newContent = content.replace(params.old_string, params.new_string);
|
|
47
|
+
replacements = 1;
|
|
48
|
+
}
|
|
49
|
+
// Write back
|
|
50
|
+
await fs.writeFile(filePath, newContent, 'utf-8');
|
|
51
|
+
return {
|
|
52
|
+
success: true,
|
|
53
|
+
output: `File edited successfully: ${filePath} (${replacements} replacement${replacements > 1 ? 's' : ''})`,
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
catch (error) {
|
|
57
|
+
const err = error;
|
|
58
|
+
return { success: false, output: '', error: `Error editing file: ${err.message}` };
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
//# sourceMappingURL=edit.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"edit.js","sourceRoot":"","sources":["../../src/tools/edit.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,aAAa,CAAC;AAClC,OAAO,KAAK,IAAI,MAAM,MAAM,CAAC;AAU7B,MAAM,CAAC,KAAK,UAAU,QAAQ,CAAC,MAAsB;IACnD,IAAI,CAAC;QACH,MAAM,QAAQ,GAAG,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC;QAEhD,wBAAwB;QACxB,IAAI,OAAe,CAAC;QACpB,IAAI,CAAC;YACH,OAAO,GAAG,MAAM,EAAE,CAAC,QAAQ,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;QACjD,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,MAAM,GAAG,GAAG,KAA8B,CAAC;YAC3C,IAAI,GAAG,CAAC,IAAI,KAAK,QAAQ,EAAE,CAAC;gBAC1B,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,MAAM,EAAE,EAAE,EAAE,KAAK,EAAE,mBAAmB,MAAM,CAAC,SAAS,EAAE,EAAE,CAAC;YACtF,CAAC;YACD,MAAM,KAAK,CAAC;QACd,CAAC;QAED,6BAA6B;QAC7B,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAC,UAAU,CAAC,EAAE,CAAC;YACzC,OAAO;gBACL,OAAO,EAAE,KAAK;gBACd,MAAM,EAAE,EAAE;gBACV,KAAK,EAAE,0FAA0F;aAClG,CAAC;QACJ,CAAC;QAED,0CAA0C;QAC1C,IAAI,CAAC,MAAM,CAAC,WAAW,EAAE,CAAC;YACxB,MAAM,WAAW,GAAG,OAAO,CAAC,KAAK,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC;YAChE,IAAI,WAAW,GAAG,CAAC,EAAE,CAAC;gBACpB,OAAO;oBACL,OAAO,EAAE,KAAK;oBACd,MAAM,EAAE,EAAE;oBACV,KAAK,EAAE,SAAS,WAAW,sGAAsG;iBAClI,CAAC;YACJ,CAAC;QACH,CAAC;QAED,sBAAsB;QACtB,IAAI,UAAkB,CAAC;QACvB,IAAI,YAAoB,CAAC;QAEzB,IAAI,MAAM,CAAC,WAAW,EAAE,CAAC;YACvB,MAAM,KAAK,GAAG,OAAO,CAAC,KAAK,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC;YAC/C,YAAY,GAAG,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC;YAChC,UAAU,GAAG,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC;QAC7C,CAAC;aAAM,CAAC;YACN,UAAU,GAAG,OAAO,CAAC,OAAO,CAAC,MAAM,CAAC,UAAU,EAAE,MAAM,CAAC,UAAU,CAAC,CAAC;YACnE,YAAY,GAAG,CAAC,CAAC;QACnB,CAAC;QAED,aAAa;QACb,MAAM,EAAE,CAAC,SAAS,CAAC,QAAQ,EAAE,UAAU,EAAE,OAAO,CAAC,CAAC;QAElD,OAAO;YACL,OAAO,EAAE,IAAI;YACb,MAAM,EAAE,6BAA6B,QAAQ,KAAK,YAAY,eAAe,YAAY,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,GAAG;SAC5G,CAAC;IACJ,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,MAAM,GAAG,GAAG,KAAc,CAAC;QAC3B,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,MAAM,EAAE,EAAE,EAAE,KAAK,EAAE,uBAAuB,GAAG,CAAC,OAAO,EAAE,EAAE,CAAC;IACrF,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"glob.d.ts","sourceRoot":"","sources":["../../src/tools/glob.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAE3C,MAAM,WAAW,cAAc;IAC7B,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED,wBAAsB,QAAQ,CAAC,MAAM,EAAE,cAAc,GAAG,OAAO,CAAC,UAAU,CAAC,CAuC1E"}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { glob } from 'glob';
|
|
2
|
+
import * as path from 'path';
|
|
3
|
+
export async function globTool(params) {
|
|
4
|
+
try {
|
|
5
|
+
const cwd = params.path ? path.resolve(params.path) : process.cwd();
|
|
6
|
+
const matches = await glob(params.pattern, {
|
|
7
|
+
cwd,
|
|
8
|
+
nodir: true,
|
|
9
|
+
absolute: false,
|
|
10
|
+
ignore: ['node_modules/**', '.git/**', 'dist/**', 'build/**'],
|
|
11
|
+
});
|
|
12
|
+
if (matches.length === 0) {
|
|
13
|
+
return {
|
|
14
|
+
success: true,
|
|
15
|
+
output: 'No files found matching the pattern.',
|
|
16
|
+
};
|
|
17
|
+
}
|
|
18
|
+
// Sort by path
|
|
19
|
+
matches.sort();
|
|
20
|
+
// Limit output to prevent overwhelming responses
|
|
21
|
+
const maxResults = 100;
|
|
22
|
+
const limited = matches.slice(0, maxResults);
|
|
23
|
+
const remaining = matches.length - maxResults;
|
|
24
|
+
let output = limited.join('\n');
|
|
25
|
+
if (remaining > 0) {
|
|
26
|
+
output += `\n\n... and ${remaining} more files`;
|
|
27
|
+
}
|
|
28
|
+
return {
|
|
29
|
+
success: true,
|
|
30
|
+
output: `Found ${matches.length} file(s):\n${output}`,
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
catch (error) {
|
|
34
|
+
const err = error;
|
|
35
|
+
return { success: false, output: '', error: `Glob error: ${err.message}` };
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
//# sourceMappingURL=glob.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"glob.js","sourceRoot":"","sources":["../../src/tools/glob.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAC5B,OAAO,KAAK,IAAI,MAAM,MAAM,CAAC;AAQ7B,MAAM,CAAC,KAAK,UAAU,QAAQ,CAAC,MAAsB;IACnD,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,GAAG,EAAE,CAAC;QAEpE,MAAM,OAAO,GAAG,MAAM,IAAI,CAAC,MAAM,CAAC,OAAO,EAAE;YACzC,GAAG;YACH,KAAK,EAAE,IAAI;YACX,QAAQ,EAAE,KAAK;YACf,MAAM,EAAE,CAAC,iBAAiB,EAAE,SAAS,EAAE,SAAS,EAAE,UAAU,CAAC;SAC9D,CAAC,CAAC;QAEH,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YACzB,OAAO;gBACL,OAAO,EAAE,IAAI;gBACb,MAAM,EAAE,sCAAsC;aAC/C,CAAC;QACJ,CAAC;QAED,eAAe;QACf,OAAO,CAAC,IAAI,EAAE,CAAC;QAEf,iDAAiD;QACjD,MAAM,UAAU,GAAG,GAAG,CAAC;QACvB,MAAM,OAAO,GAAG,OAAO,CAAC,KAAK,CAAC,CAAC,EAAE,UAAU,CAAC,CAAC;QAC7C,MAAM,SAAS,GAAG,OAAO,CAAC,MAAM,GAAG,UAAU,CAAC;QAE9C,IAAI,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAChC,IAAI,SAAS,GAAG,CAAC,EAAE,CAAC;YAClB,MAAM,IAAI,eAAe,SAAS,aAAa,CAAC;QAClD,CAAC;QAED,OAAO;YACL,OAAO,EAAE,IAAI;YACb,MAAM,EAAE,SAAS,OAAO,CAAC,MAAM,cAAc,MAAM,EAAE;SACtD,CAAC;IACJ,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,MAAM,GAAG,GAAG,KAAc,CAAC;QAC3B,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,MAAM,EAAE,EAAE,EAAE,KAAK,EAAE,eAAe,GAAG,CAAC,OAAO,EAAE,EAAE,CAAC;IAC7E,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"grep.d.ts","sourceRoot":"","sources":["../../src/tools/grep.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAE3C,MAAM,WAAW,cAAc;IAC7B,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,wBAAsB,QAAQ,CAAC,MAAM,EAAE,cAAc,GAAG,OAAO,CAAC,UAAU,CAAC,CAsF1E"}
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import { spawn } from 'child_process';
|
|
2
|
+
export async function grepTool(params) {
|
|
3
|
+
return new Promise((resolve) => {
|
|
4
|
+
const args = [
|
|
5
|
+
'--color=never',
|
|
6
|
+
'-r',
|
|
7
|
+
'-n',
|
|
8
|
+
'-H',
|
|
9
|
+
'--include=*.{ts,tsx,js,jsx,json,md,py,go,rs,java,kt,swift,c,cpp,h,hpp,css,scss,html,xml,yaml,yml,toml}',
|
|
10
|
+
];
|
|
11
|
+
if (params.include) {
|
|
12
|
+
args.push(`--include=${params.include}`);
|
|
13
|
+
}
|
|
14
|
+
// Exclude common directories
|
|
15
|
+
args.push('--exclude-dir=node_modules');
|
|
16
|
+
args.push('--exclude-dir=.git');
|
|
17
|
+
args.push('--exclude-dir=dist');
|
|
18
|
+
args.push('--exclude-dir=build');
|
|
19
|
+
args.push('--exclude-dir=.next');
|
|
20
|
+
args.push('-E'); // Extended regex
|
|
21
|
+
args.push(params.pattern);
|
|
22
|
+
args.push(params.path || '.');
|
|
23
|
+
const child = spawn('grep', args, {
|
|
24
|
+
cwd: process.cwd(),
|
|
25
|
+
});
|
|
26
|
+
let stdout = '';
|
|
27
|
+
let stderr = '';
|
|
28
|
+
child.stdout.on('data', (data) => {
|
|
29
|
+
stdout += data.toString();
|
|
30
|
+
});
|
|
31
|
+
child.stderr.on('data', (data) => {
|
|
32
|
+
stderr += data.toString();
|
|
33
|
+
});
|
|
34
|
+
child.on('close', (code) => {
|
|
35
|
+
// grep returns 1 if no matches, which is not an error
|
|
36
|
+
if (code === 1 && !stderr) {
|
|
37
|
+
resolve({
|
|
38
|
+
success: true,
|
|
39
|
+
output: 'No matches found.',
|
|
40
|
+
});
|
|
41
|
+
return;
|
|
42
|
+
}
|
|
43
|
+
if (code !== 0 && code !== 1) {
|
|
44
|
+
resolve({
|
|
45
|
+
success: false,
|
|
46
|
+
output: '',
|
|
47
|
+
error: stderr || `grep exited with code ${code}`,
|
|
48
|
+
});
|
|
49
|
+
return;
|
|
50
|
+
}
|
|
51
|
+
// Limit output
|
|
52
|
+
const lines = stdout.trim().split('\n').filter(Boolean);
|
|
53
|
+
const maxResults = 50;
|
|
54
|
+
if (lines.length > maxResults) {
|
|
55
|
+
const output = lines.slice(0, maxResults).join('\n');
|
|
56
|
+
resolve({
|
|
57
|
+
success: true,
|
|
58
|
+
output: `Found ${lines.length} matches (showing first ${maxResults}):\n${output}`,
|
|
59
|
+
});
|
|
60
|
+
}
|
|
61
|
+
else {
|
|
62
|
+
resolve({
|
|
63
|
+
success: true,
|
|
64
|
+
output: lines.length > 0 ? `Found ${lines.length} match(es):\n${stdout.trim()}` : 'No matches found.',
|
|
65
|
+
});
|
|
66
|
+
}
|
|
67
|
+
});
|
|
68
|
+
child.on('error', (error) => {
|
|
69
|
+
// Fall back to ripgrep if grep is not available
|
|
70
|
+
resolve({
|
|
71
|
+
success: false,
|
|
72
|
+
output: '',
|
|
73
|
+
error: `grep error: ${error.message}`,
|
|
74
|
+
});
|
|
75
|
+
});
|
|
76
|
+
});
|
|
77
|
+
}
|
|
78
|
+
//# sourceMappingURL=grep.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"grep.js","sourceRoot":"","sources":["../../src/tools/grep.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"read.d.ts","sourceRoot":"","sources":["../../src/tools/read.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAI3C,MAAM,WAAW,cAAc;IAC7B,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAQD,wBAAsB,QAAQ,CAAC,MAAM,EAAE,cAAc,GAAG,OAAO,CAAC,UAAU,CAAC,CAiG1E"}
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
import * as fs from 'fs/promises';
|
|
2
|
+
import * as path from 'path';
|
|
3
|
+
import { validatePath } from '../utils/security.js';
|
|
4
|
+
import chalk from 'chalk';
|
|
5
|
+
// Maximum file size to read (10MB)
|
|
6
|
+
const MAX_FILE_SIZE = 10 * 1024 * 1024;
|
|
7
|
+
// Maximum lines to return
|
|
8
|
+
const MAX_LINES = 2000;
|
|
9
|
+
export async function readTool(params) {
|
|
10
|
+
try {
|
|
11
|
+
const filePath = path.resolve(params.file_path);
|
|
12
|
+
// Security validation
|
|
13
|
+
const security = validatePath(filePath);
|
|
14
|
+
if (!security.allowed) {
|
|
15
|
+
return {
|
|
16
|
+
success: false,
|
|
17
|
+
output: '',
|
|
18
|
+
error: `Security: ${security.reason}`,
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
// Check file stats first
|
|
22
|
+
let stats;
|
|
23
|
+
try {
|
|
24
|
+
stats = await fs.stat(filePath);
|
|
25
|
+
}
|
|
26
|
+
catch (error) {
|
|
27
|
+
const err = error;
|
|
28
|
+
if (err.code === 'ENOENT') {
|
|
29
|
+
return { success: false, output: '', error: `File not found: ${params.file_path}` };
|
|
30
|
+
}
|
|
31
|
+
throw error;
|
|
32
|
+
}
|
|
33
|
+
if (stats.isDirectory()) {
|
|
34
|
+
return { success: false, output: '', error: `Path is a directory: ${params.file_path}` };
|
|
35
|
+
}
|
|
36
|
+
if (stats.size > MAX_FILE_SIZE) {
|
|
37
|
+
return {
|
|
38
|
+
success: false,
|
|
39
|
+
output: '',
|
|
40
|
+
error: `File too large (${(stats.size / 1024 / 1024).toFixed(1)}MB). Maximum is ${MAX_FILE_SIZE / 1024 / 1024}MB. Use offset/limit to read portions.`,
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
// Read the file
|
|
44
|
+
const content = await fs.readFile(filePath, 'utf-8');
|
|
45
|
+
// Handle binary files
|
|
46
|
+
if (content.includes('\0')) {
|
|
47
|
+
return {
|
|
48
|
+
success: false,
|
|
49
|
+
output: '',
|
|
50
|
+
error: 'File appears to be binary. Cannot display binary content.',
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
const lines = content.split('\n');
|
|
54
|
+
const totalLines = lines.length;
|
|
55
|
+
const offset = Math.max(0, (params.offset ?? 1) - 1);
|
|
56
|
+
const limit = Math.min(params.limit ?? MAX_LINES, MAX_LINES);
|
|
57
|
+
const selectedLines = lines.slice(offset, offset + limit);
|
|
58
|
+
// Format with line numbers like cat -n
|
|
59
|
+
const padding = String(totalLines).length;
|
|
60
|
+
const output = selectedLines
|
|
61
|
+
.map((line, i) => {
|
|
62
|
+
const lineNum = offset + i + 1;
|
|
63
|
+
// Truncate very long lines
|
|
64
|
+
const displayLine = line.length > 2000 ? line.slice(0, 2000) + '...' : line;
|
|
65
|
+
return `${String(lineNum).padStart(padding)}${chalk.gray('│')} ${displayLine}`;
|
|
66
|
+
})
|
|
67
|
+
.join('\n');
|
|
68
|
+
// Add metadata
|
|
69
|
+
let header = '';
|
|
70
|
+
if (offset > 0 || selectedLines.length < totalLines) {
|
|
71
|
+
header = chalk.gray(`Showing lines ${offset + 1}-${offset + selectedLines.length} of ${totalLines}\n`);
|
|
72
|
+
}
|
|
73
|
+
// Security warning if applicable
|
|
74
|
+
if (security.severity === 'medium') {
|
|
75
|
+
header = chalk.yellow(`⚠️ ${security.suggestion}\n`) + header;
|
|
76
|
+
}
|
|
77
|
+
return {
|
|
78
|
+
success: true,
|
|
79
|
+
output: header + (output || '(empty file)'),
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
catch (error) {
|
|
83
|
+
const err = error;
|
|
84
|
+
if (err.code === 'ENOENT') {
|
|
85
|
+
return { success: false, output: '', error: `File not found: ${params.file_path}` };
|
|
86
|
+
}
|
|
87
|
+
if (err.code === 'EACCES') {
|
|
88
|
+
return { success: false, output: '', error: `Permission denied: ${params.file_path}` };
|
|
89
|
+
}
|
|
90
|
+
if (err.code === 'EISDIR') {
|
|
91
|
+
return { success: false, output: '', error: `Path is a directory: ${params.file_path}` };
|
|
92
|
+
}
|
|
93
|
+
return { success: false, output: '', error: `Error reading file: ${err.message}` };
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
//# sourceMappingURL=read.js.map
|