@nils.del/supergrok 1.0.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 (59) hide show
  1. package/.env +45 -0
  2. package/.grok/settings.json +13 -0
  3. package/dist/agent/index.d.ts +35 -0
  4. package/dist/agent/index.d.ts.map +1 -0
  5. package/dist/agent/index.js +244 -0
  6. package/dist/agent/index.js.map +1 -0
  7. package/dist/index.d.ts +3 -0
  8. package/dist/index.d.ts.map +1 -0
  9. package/dist/index.js +242 -0
  10. package/dist/index.js.map +1 -0
  11. package/dist/mcp/client.d.ts +33 -0
  12. package/dist/mcp/client.d.ts.map +1 -0
  13. package/dist/mcp/client.js +134 -0
  14. package/dist/mcp/client.js.map +1 -0
  15. package/dist/mcp/config.d.ts +15 -0
  16. package/dist/mcp/config.d.ts.map +1 -0
  17. package/dist/mcp/config.js +123 -0
  18. package/dist/mcp/config.js.map +1 -0
  19. package/dist/mcp/transports.d.ts +24 -0
  20. package/dist/mcp/transports.d.ts.map +1 -0
  21. package/dist/mcp/transports.js +91 -0
  22. package/dist/mcp/transports.js.map +1 -0
  23. package/dist/tools/bash.d.ts +28 -0
  24. package/dist/tools/bash.d.ts.map +1 -0
  25. package/dist/tools/bash.js +70 -0
  26. package/dist/tools/bash.js.map +1 -0
  27. package/dist/tools/index.d.ts +77 -0
  28. package/dist/tools/index.d.ts.map +1 -0
  29. package/dist/tools/index.js +80 -0
  30. package/dist/tools/index.js.map +1 -0
  31. package/dist/tools/text-editor.d.ts +69 -0
  32. package/dist/tools/text-editor.d.ts.map +1 -0
  33. package/dist/tools/text-editor.js +178 -0
  34. package/dist/tools/text-editor.js.map +1 -0
  35. package/dist/tools/types.d.ts +14 -0
  36. package/dist/tools/types.d.ts.map +1 -0
  37. package/dist/tools/types.js +2 -0
  38. package/dist/tools/types.js.map +1 -0
  39. package/dist/ui/readline-ui.d.ts +32 -0
  40. package/dist/ui/readline-ui.d.ts.map +1 -0
  41. package/dist/ui/readline-ui.js +256 -0
  42. package/dist/ui/readline-ui.js.map +1 -0
  43. package/dist/utils/settings.d.ts +20 -0
  44. package/dist/utils/settings.d.ts.map +1 -0
  45. package/dist/utils/settings.js +101 -0
  46. package/dist/utils/settings.js.map +1 -0
  47. package/package.json +51 -0
  48. package/src/agent/index.ts +302 -0
  49. package/src/index.ts +275 -0
  50. package/src/mcp/client.ts +178 -0
  51. package/src/mcp/config.ts +149 -0
  52. package/src/mcp/transports.ts +142 -0
  53. package/src/tools/bash.ts +84 -0
  54. package/src/tools/index.ts +91 -0
  55. package/src/tools/text-editor.ts +222 -0
  56. package/src/tools/types.ts +14 -0
  57. package/src/ui/readline-ui.ts +294 -0
  58. package/src/utils/settings.ts +129 -0
  59. package/tsconfig.json +20 -0
@@ -0,0 +1,142 @@
1
+ import { StdioClientTransport } from "@modelcontextprotocol/sdk/client/stdio.js";
2
+ import { SSEClientTransport } from "@modelcontextprotocol/sdk/client/sse.js";
3
+ import { StreamableHTTPClientTransport } from "@modelcontextprotocol/sdk/client/streamableHttp.js";
4
+ import type { Transport } from "@modelcontextprotocol/sdk/shared/transport.js";
5
+
6
+ export type TransportType = 'stdio' | 'http' | 'sse';
7
+
8
+ export interface StdioTransportConfig {
9
+ type: 'stdio';
10
+ command: string;
11
+ args?: string[];
12
+ env?: Record<string, string>;
13
+ }
14
+
15
+ export interface HttpTransportConfig {
16
+ type: 'http';
17
+ url: string;
18
+ }
19
+
20
+ export interface SSETransportConfig {
21
+ type: 'sse';
22
+ url: string;
23
+ }
24
+
25
+ export type TransportConfig = StdioTransportConfig | HttpTransportConfig | SSETransportConfig;
26
+
27
+ export interface MCPTransport {
28
+ connect(): Promise<Transport>;
29
+ disconnect(): Promise<void>;
30
+ getType(): TransportType;
31
+ }
32
+
33
+ class StdioMCPTransport implements MCPTransport {
34
+ private config: StdioTransportConfig;
35
+ private transport: StdioClientTransport | null = null;
36
+
37
+ constructor(config: StdioTransportConfig) {
38
+ this.config = config;
39
+ }
40
+
41
+ async connect(): Promise<Transport> {
42
+ const env: Record<string, string> = {};
43
+
44
+ // Copy process.env, filtering out undefined values
45
+ for (const [key, value] of Object.entries(process.env)) {
46
+ if (value !== undefined) {
47
+ env[key] = value;
48
+ }
49
+ }
50
+
51
+ // Merge with config env
52
+ if (this.config.env) {
53
+ Object.assign(env, this.config.env);
54
+ }
55
+
56
+ this.transport = new StdioClientTransport({
57
+ command: this.config.command,
58
+ args: this.config.args || [],
59
+ env
60
+ });
61
+
62
+ return this.transport;
63
+ }
64
+
65
+ async disconnect(): Promise<void> {
66
+ if (this.transport) {
67
+ await this.transport.close();
68
+ this.transport = null;
69
+ }
70
+ }
71
+
72
+ getType(): TransportType {
73
+ return 'stdio';
74
+ }
75
+ }
76
+
77
+ class HttpMCPTransport implements MCPTransport {
78
+ private config: HttpTransportConfig;
79
+ private transport: StreamableHTTPClientTransport | null = null;
80
+
81
+ constructor(config: HttpTransportConfig) {
82
+ this.config = config;
83
+ }
84
+
85
+ async connect(): Promise<Transport> {
86
+ this.transport = new StreamableHTTPClientTransport(
87
+ new URL(this.config.url)
88
+ );
89
+ return this.transport;
90
+ }
91
+
92
+ async disconnect(): Promise<void> {
93
+ if (this.transport) {
94
+ await this.transport.close();
95
+ this.transport = null;
96
+ }
97
+ }
98
+
99
+ getType(): TransportType {
100
+ return 'http';
101
+ }
102
+ }
103
+
104
+ class SSEMCPTransport implements MCPTransport {
105
+ private config: SSETransportConfig;
106
+ private transport: SSEClientTransport | null = null;
107
+
108
+ constructor(config: SSETransportConfig) {
109
+ this.config = config;
110
+ }
111
+
112
+ async connect(): Promise<Transport> {
113
+ this.transport = new SSEClientTransport(
114
+ new URL(this.config.url)
115
+ );
116
+ return this.transport;
117
+ }
118
+
119
+ async disconnect(): Promise<void> {
120
+ if (this.transport) {
121
+ await this.transport.close();
122
+ this.transport = null;
123
+ }
124
+ }
125
+
126
+ getType(): TransportType {
127
+ return 'sse';
128
+ }
129
+ }
130
+
131
+ export function createTransport(config: TransportConfig): MCPTransport {
132
+ switch (config.type) {
133
+ case 'stdio':
134
+ return new StdioMCPTransport(config);
135
+ case 'http':
136
+ return new HttpMCPTransport(config);
137
+ case 'sse':
138
+ return new SSEMCPTransport(config);
139
+ default:
140
+ throw new Error(`Unknown transport type: ${(config as any).type}`);
141
+ }
142
+ }
@@ -0,0 +1,84 @@
1
+ import { spawn } from 'child_process';
2
+ import { ToolResult } from './types.js';
3
+
4
+ export interface BashToolArgs {
5
+ command: string;
6
+ timeout?: number;
7
+ }
8
+
9
+ export async function executeBashCommand(args: BashToolArgs): Promise<ToolResult> {
10
+ const { command, timeout = 120000 } = args;
11
+
12
+ return new Promise((resolve) => {
13
+ const childProcess = spawn('bash', ['-c', command], {
14
+ cwd: process.cwd(),
15
+ env: process.env,
16
+ stdio: ['pipe', 'pipe', 'pipe']
17
+ });
18
+
19
+ let stdout = '';
20
+ let stderr = '';
21
+
22
+ const timer = setTimeout(() => {
23
+ childProcess.kill('SIGTERM');
24
+ resolve({
25
+ success: false,
26
+ error: `Command timed out after ${timeout}ms`
27
+ });
28
+ }, timeout);
29
+
30
+ childProcess.stdout.on('data', (data) => {
31
+ stdout += data.toString();
32
+ });
33
+
34
+ childProcess.stderr.on('data', (data) => {
35
+ stderr += data.toString();
36
+ });
37
+
38
+ childProcess.on('close', (code) => {
39
+ clearTimeout(timer);
40
+
41
+ if (code === 0) {
42
+ resolve({
43
+ success: true,
44
+ output: stdout.trim() || stderr.trim() || 'Command completed successfully'
45
+ });
46
+ } else {
47
+ resolve({
48
+ success: false,
49
+ error: stderr.trim() || stdout.trim() || `Command failed with exit code ${code}`
50
+ });
51
+ }
52
+ });
53
+
54
+ childProcess.on('error', (error) => {
55
+ clearTimeout(timer);
56
+ resolve({
57
+ success: false,
58
+ error: `Failed to execute command: ${error.message}`
59
+ });
60
+ });
61
+ });
62
+ }
63
+
64
+ export const bashToolDefinition = {
65
+ type: "function" as const,
66
+ function: {
67
+ name: "bash",
68
+ description: "Execute a bash command and return the output. Use this for running shell commands, file operations, git commands, etc.",
69
+ parameters: {
70
+ type: "object",
71
+ properties: {
72
+ command: {
73
+ type: "string",
74
+ description: "The bash command to execute"
75
+ },
76
+ timeout: {
77
+ type: "number",
78
+ description: "Optional timeout in milliseconds (default: 120000)"
79
+ }
80
+ },
81
+ required: ["command"]
82
+ }
83
+ }
84
+ };
@@ -0,0 +1,91 @@
1
+ import { ToolResult, ToolCall } from './types.js';
2
+ import { executeBashCommand, bashToolDefinition } from './bash.js';
3
+ import { viewFile, createFile, strReplace, insertText, textEditorToolDefinition } from './text-editor.js';
4
+ import { getMCPManager } from '../mcp/client.js';
5
+
6
+ export { ToolResult, ToolCall };
7
+
8
+ export function getBuiltInTools() {
9
+ return [bashToolDefinition, textEditorToolDefinition];
10
+ }
11
+
12
+ export async function getAllTools() {
13
+ const builtInTools = getBuiltInTools();
14
+ const mcpManager = getMCPManager();
15
+
16
+ // Ensure MCP servers are initialized
17
+ await mcpManager.ensureServersInitialized();
18
+
19
+ const mcpTools = mcpManager.getTools().map(tool => ({
20
+ type: "function" as const,
21
+ function: {
22
+ name: tool.name,
23
+ description: tool.description,
24
+ parameters: tool.inputSchema
25
+ }
26
+ }));
27
+
28
+ return [...builtInTools, ...mcpTools];
29
+ }
30
+
31
+ export async function executeToolCall(toolCall: ToolCall): Promise<ToolResult> {
32
+ const { function: fn } = toolCall;
33
+ const args = JSON.parse(fn.arguments || '{}');
34
+
35
+ // Handle MCP tools
36
+ if (fn.name.startsWith('mcp__')) {
37
+ try {
38
+ const mcpManager = getMCPManager();
39
+ const result = await mcpManager.callTool(fn.name, args);
40
+
41
+ // Convert MCP result to our format
42
+ const content = result.content
43
+ .map((c: any) => {
44
+ if (c.type === 'text') return c.text;
45
+ if (c.type === 'image') return `[Image: ${c.mimeType}]`;
46
+ return JSON.stringify(c);
47
+ })
48
+ .join('\n');
49
+
50
+ return {
51
+ success: !result.isError,
52
+ output: result.isError ? undefined : content,
53
+ error: result.isError ? content : undefined
54
+ };
55
+ } catch (error: any) {
56
+ return {
57
+ success: false,
58
+ error: `MCP tool error: ${error.message}`
59
+ };
60
+ }
61
+ }
62
+
63
+ // Handle built-in tools
64
+ switch (fn.name) {
65
+ case 'bash':
66
+ return await executeBashCommand(args);
67
+
68
+ case 'str_replace_editor':
69
+ switch (args.command) {
70
+ case 'view':
71
+ return await viewFile({ path: args.path, view_range: args.view_range });
72
+ case 'create':
73
+ return await createFile({ path: args.path, file_text: args.file_text });
74
+ case 'str_replace':
75
+ return await strReplace({ path: args.path, old_str: args.old_str, new_str: args.new_str });
76
+ case 'insert':
77
+ return await insertText({ path: args.path, insert_line: args.insert_line, new_str: args.new_str });
78
+ default:
79
+ return {
80
+ success: false,
81
+ error: `Unknown editor command: ${args.command}`
82
+ };
83
+ }
84
+
85
+ default:
86
+ return {
87
+ success: false,
88
+ error: `Unknown tool: ${fn.name}`
89
+ };
90
+ }
91
+ }
@@ -0,0 +1,222 @@
1
+ import fs from 'fs';
2
+ import path from 'path';
3
+ import { ToolResult } from './types.js';
4
+
5
+ export interface ViewArgs {
6
+ path: string;
7
+ view_range?: [number, number];
8
+ }
9
+
10
+ export interface CreateArgs {
11
+ path: string;
12
+ file_text: string;
13
+ }
14
+
15
+ export interface StrReplaceArgs {
16
+ path: string;
17
+ old_str: string;
18
+ new_str: string;
19
+ }
20
+
21
+ export interface InsertArgs {
22
+ path: string;
23
+ insert_line: number;
24
+ new_str: string;
25
+ }
26
+
27
+ export async function viewFile(args: ViewArgs): Promise<ToolResult> {
28
+ try {
29
+ const filePath = path.resolve(process.cwd(), args.path);
30
+
31
+ if (!fs.existsSync(filePath)) {
32
+ return {
33
+ success: false,
34
+ error: `File not found: ${args.path}`
35
+ };
36
+ }
37
+
38
+ const content = fs.readFileSync(filePath, 'utf-8');
39
+ const lines = content.split('\n');
40
+
41
+ if (args.view_range) {
42
+ const [start, end] = args.view_range;
43
+ const startIdx = Math.max(0, start - 1);
44
+ const endIdx = Math.min(lines.length, end);
45
+
46
+ const numberedLines = lines
47
+ .slice(startIdx, endIdx)
48
+ .map((line, i) => `${startIdx + i + 1}: ${line}`)
49
+ .join('\n');
50
+
51
+ return {
52
+ success: true,
53
+ output: `File: ${args.path} (lines ${start}-${end})\n\n${numberedLines}`
54
+ };
55
+ }
56
+
57
+ const numberedLines = lines
58
+ .map((line, i) => `${i + 1}: ${line}`)
59
+ .join('\n');
60
+
61
+ return {
62
+ success: true,
63
+ output: `File: ${args.path} (${lines.length} lines)\n\n${numberedLines}`
64
+ };
65
+ } catch (error: any) {
66
+ return {
67
+ success: false,
68
+ error: `Failed to read file: ${error.message}`
69
+ };
70
+ }
71
+ }
72
+
73
+ export async function createFile(args: CreateArgs): Promise<ToolResult> {
74
+ try {
75
+ const filePath = path.resolve(process.cwd(), args.path);
76
+ const dir = path.dirname(filePath);
77
+
78
+ if (!fs.existsSync(dir)) {
79
+ fs.mkdirSync(dir, { recursive: true });
80
+ }
81
+
82
+ fs.writeFileSync(filePath, args.file_text);
83
+
84
+ return {
85
+ success: true,
86
+ output: `File created successfully: ${args.path}`
87
+ };
88
+ } catch (error: any) {
89
+ return {
90
+ success: false,
91
+ error: `Failed to create file: ${error.message}`
92
+ };
93
+ }
94
+ }
95
+
96
+ export async function strReplace(args: StrReplaceArgs): Promise<ToolResult> {
97
+ try {
98
+ const filePath = path.resolve(process.cwd(), args.path);
99
+
100
+ if (!fs.existsSync(filePath)) {
101
+ return {
102
+ success: false,
103
+ error: `File not found: ${args.path}`
104
+ };
105
+ }
106
+
107
+ const content = fs.readFileSync(filePath, 'utf-8');
108
+
109
+ if (!content.includes(args.old_str)) {
110
+ return {
111
+ success: false,
112
+ error: `String not found in file: "${args.old_str.substring(0, 50)}..."`
113
+ };
114
+ }
115
+
116
+ const occurrences = content.split(args.old_str).length - 1;
117
+ if (occurrences > 1) {
118
+ return {
119
+ success: false,
120
+ error: `Found ${occurrences} occurrences of the string. Please provide a more specific string to replace.`
121
+ };
122
+ }
123
+
124
+ const newContent = content.replace(args.old_str, args.new_str);
125
+ fs.writeFileSync(filePath, newContent);
126
+
127
+ return {
128
+ success: true,
129
+ output: `Successfully replaced text in ${args.path}`
130
+ };
131
+ } catch (error: any) {
132
+ return {
133
+ success: false,
134
+ error: `Failed to replace text: ${error.message}`
135
+ };
136
+ }
137
+ }
138
+
139
+ export async function insertText(args: InsertArgs): Promise<ToolResult> {
140
+ try {
141
+ const filePath = path.resolve(process.cwd(), args.path);
142
+
143
+ if (!fs.existsSync(filePath)) {
144
+ return {
145
+ success: false,
146
+ error: `File not found: ${args.path}`
147
+ };
148
+ }
149
+
150
+ const content = fs.readFileSync(filePath, 'utf-8');
151
+ const lines = content.split('\n');
152
+
153
+ if (args.insert_line < 0 || args.insert_line > lines.length) {
154
+ return {
155
+ success: false,
156
+ error: `Invalid line number: ${args.insert_line}. File has ${lines.length} lines.`
157
+ };
158
+ }
159
+
160
+ lines.splice(args.insert_line, 0, args.new_str);
161
+ const newContent = lines.join('\n');
162
+ fs.writeFileSync(filePath, newContent);
163
+
164
+ return {
165
+ success: true,
166
+ output: `Successfully inserted text at line ${args.insert_line} in ${args.path}`
167
+ };
168
+ } catch (error: any) {
169
+ return {
170
+ success: false,
171
+ error: `Failed to insert text: ${error.message}`
172
+ };
173
+ }
174
+ }
175
+
176
+ export const textEditorToolDefinition = {
177
+ type: "function" as const,
178
+ function: {
179
+ name: "str_replace_editor",
180
+ description: `A powerful text editor tool for viewing and modifying files. Commands:
181
+ - view: View file contents with line numbers
182
+ - create: Create a new file with specified content
183
+ - str_replace: Replace a specific string in a file (must be unique)
184
+ - insert: Insert text at a specific line number`,
185
+ parameters: {
186
+ type: "object",
187
+ properties: {
188
+ command: {
189
+ type: "string",
190
+ enum: ["view", "create", "str_replace", "insert"],
191
+ description: "The editing command to execute"
192
+ },
193
+ path: {
194
+ type: "string",
195
+ description: "The file path to operate on"
196
+ },
197
+ file_text: {
198
+ type: "string",
199
+ description: "For create command: the content of the new file"
200
+ },
201
+ old_str: {
202
+ type: "string",
203
+ description: "For str_replace command: the exact string to replace"
204
+ },
205
+ new_str: {
206
+ type: "string",
207
+ description: "For str_replace/insert commands: the new string to insert"
208
+ },
209
+ insert_line: {
210
+ type: "number",
211
+ description: "For insert command: the line number to insert at (0-indexed)"
212
+ },
213
+ view_range: {
214
+ type: "array",
215
+ items: { type: "number" },
216
+ description: "For view command: optional [start, end] line range"
217
+ }
218
+ },
219
+ required: ["command", "path"]
220
+ }
221
+ }
222
+ };
@@ -0,0 +1,14 @@
1
+ export interface ToolResult {
2
+ success: boolean;
3
+ output?: string;
4
+ error?: string;
5
+ }
6
+
7
+ export interface ToolCall {
8
+ id: string;
9
+ type: string;
10
+ function: {
11
+ name: string;
12
+ arguments: string;
13
+ };
14
+ }