codebot-ai 1.0.2 → 1.1.1
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/README.md +43 -3
- package/dist/agent.d.ts +2 -0
- package/dist/agent.js +20 -2
- package/dist/browser/cdp.d.ts +3 -0
- package/dist/browser/cdp.js +25 -1
- package/dist/cli.js +30 -2
- package/dist/games/tic-tac-toe.d.ts +6 -0
- package/dist/games/tic-tac-toe.js +64 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +5 -1
- package/dist/mcp.d.ts +7 -0
- package/dist/mcp.js +174 -0
- package/dist/plugins.d.ts +17 -0
- package/dist/plugins.js +101 -0
- package/dist/providers/openai.js +7 -0
- package/dist/setup.js +72 -30
- package/dist/tools/batch-edit.d.ts +36 -0
- package/dist/tools/batch-edit.js +122 -0
- package/dist/tools/browser.js +122 -15
- package/dist/tools/edit.d.ts +6 -0
- package/dist/tools/edit.js +117 -2
- package/dist/tools/execute.js +28 -0
- package/dist/tools/index.d.ts +1 -0
- package/dist/tools/index.js +5 -1
- package/dist/tools/write.d.ts +1 -0
- package/dist/tools/write.js +38 -1
- package/package.json +5 -5
package/README.md
CHANGED
|
@@ -115,6 +115,8 @@ codebot --resume <session-id> # Resume specific session
|
|
|
115
115
|
/models List all supported models
|
|
116
116
|
/sessions List saved sessions
|
|
117
117
|
/auto Toggle autonomous mode
|
|
118
|
+
/undo Undo last file edit (/undo [path])
|
|
119
|
+
/usage Show token usage for this session
|
|
118
120
|
/clear Clear conversation
|
|
119
121
|
/compact Force context compaction
|
|
120
122
|
/config Show configuration
|
|
@@ -123,13 +125,14 @@ codebot --resume <session-id> # Resume specific session
|
|
|
123
125
|
|
|
124
126
|
## Tools
|
|
125
127
|
|
|
126
|
-
CodeBot has
|
|
128
|
+
CodeBot has 11 built-in tools:
|
|
127
129
|
|
|
128
130
|
| Tool | Description | Permission |
|
|
129
131
|
|------|-------------|-----------|
|
|
130
132
|
| `read_file` | Read files with line numbers | auto |
|
|
131
|
-
| `write_file` | Create or overwrite files | prompt |
|
|
132
|
-
| `edit_file` | Find-and-replace edits | prompt |
|
|
133
|
+
| `write_file` | Create or overwrite files (with undo snapshots) | prompt |
|
|
134
|
+
| `edit_file` | Find-and-replace edits with diff preview + undo | prompt |
|
|
135
|
+
| `batch_edit` | Multi-file atomic find-and-replace | prompt |
|
|
133
136
|
| `execute` | Run shell commands | always-ask |
|
|
134
137
|
| `glob` | Find files by pattern | auto |
|
|
135
138
|
| `grep` | Search file contents with regex | auto |
|
|
@@ -168,6 +171,40 @@ CodeBot has persistent memory that survives across sessions:
|
|
|
168
171
|
- Memory is automatically injected into the system prompt
|
|
169
172
|
- The agent can read/write its own memory using the `memory` tool
|
|
170
173
|
|
|
174
|
+
### Plugins
|
|
175
|
+
|
|
176
|
+
Extend CodeBot with custom tools. Drop `.js` files in `.codebot/plugins/` (project) or `~/.codebot/plugins/` (global):
|
|
177
|
+
|
|
178
|
+
```javascript
|
|
179
|
+
// .codebot/plugins/my-tool.js
|
|
180
|
+
module.exports = {
|
|
181
|
+
name: 'my_tool',
|
|
182
|
+
description: 'Does something useful',
|
|
183
|
+
permission: 'prompt',
|
|
184
|
+
parameters: { type: 'object', properties: { input: { type: 'string' } }, required: ['input'] },
|
|
185
|
+
execute: async (args) => { return `Result: ${args.input}`; }
|
|
186
|
+
};
|
|
187
|
+
```
|
|
188
|
+
|
|
189
|
+
### MCP Servers
|
|
190
|
+
|
|
191
|
+
Connect external tool servers via [Model Context Protocol](https://modelcontextprotocol.io). Create `.codebot/mcp.json`:
|
|
192
|
+
|
|
193
|
+
```json
|
|
194
|
+
{
|
|
195
|
+
"servers": [
|
|
196
|
+
{
|
|
197
|
+
"name": "my-server",
|
|
198
|
+
"command": "npx",
|
|
199
|
+
"args": ["-y", "@my/mcp-server"],
|
|
200
|
+
"env": {}
|
|
201
|
+
}
|
|
202
|
+
]
|
|
203
|
+
}
|
|
204
|
+
```
|
|
205
|
+
|
|
206
|
+
MCP tools appear automatically with the `mcp_<server>_<tool>` prefix.
|
|
207
|
+
|
|
171
208
|
## Supported Models
|
|
172
209
|
|
|
173
210
|
### Local (Ollama / LM Studio / vLLM)
|
|
@@ -204,8 +241,11 @@ src/
|
|
|
204
241
|
registry.ts Model registry, provider detection
|
|
205
242
|
browser/
|
|
206
243
|
cdp.ts Chrome DevTools Protocol client (zero-dep WebSocket)
|
|
244
|
+
plugins.ts Plugin loader (.codebot/plugins/)
|
|
245
|
+
mcp.ts MCP (Model Context Protocol) client
|
|
207
246
|
tools/
|
|
208
247
|
read.ts, write.ts, edit.ts, execute.ts
|
|
248
|
+
batch-edit.ts Multi-file atomic editing
|
|
209
249
|
glob.ts, grep.ts, think.ts
|
|
210
250
|
memory.ts, web-fetch.ts, browser.ts
|
|
211
251
|
```
|
package/dist/agent.d.ts
CHANGED
|
@@ -17,6 +17,8 @@ export declare class Agent {
|
|
|
17
17
|
askPermission?: (tool: string, args: Record<string, unknown>) => Promise<boolean>;
|
|
18
18
|
onMessage?: (message: Message) => void;
|
|
19
19
|
});
|
|
20
|
+
/** Update auto-approve mode at runtime (e.g., from /auto command) */
|
|
21
|
+
setAutoApprove(value: boolean): void;
|
|
20
22
|
/** Load messages from a previous session for resume */
|
|
21
23
|
loadMessages(messages: Message[]): void;
|
|
22
24
|
run(userMessage: string): AsyncGenerator<AgentEvent>;
|
package/dist/agent.js
CHANGED
|
@@ -41,6 +41,7 @@ const manager_1 = require("./context/manager");
|
|
|
41
41
|
const repo_map_1 = require("./context/repo-map");
|
|
42
42
|
const memory_1 = require("./memory");
|
|
43
43
|
const registry_1 = require("./providers/registry");
|
|
44
|
+
const plugins_1 = require("./plugins");
|
|
44
45
|
class Agent {
|
|
45
46
|
provider;
|
|
46
47
|
tools;
|
|
@@ -60,12 +61,24 @@ class Agent {
|
|
|
60
61
|
this.autoApprove = opts.autoApprove || false;
|
|
61
62
|
this.askPermission = opts.askPermission || defaultAskPermission;
|
|
62
63
|
this.onMessage = opts.onMessage;
|
|
64
|
+
// Load plugins
|
|
65
|
+
try {
|
|
66
|
+
const plugins = (0, plugins_1.loadPlugins)(process.cwd());
|
|
67
|
+
for (const plugin of plugins) {
|
|
68
|
+
this.tools.register(plugin);
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
catch { /* plugins unavailable */ }
|
|
63
72
|
const supportsTools = (0, registry_1.getModelInfo)(opts.model).supportsToolCalling;
|
|
64
73
|
this.messages.push({
|
|
65
74
|
role: 'system',
|
|
66
75
|
content: this.buildSystemPrompt(supportsTools),
|
|
67
76
|
});
|
|
68
77
|
}
|
|
78
|
+
/** Update auto-approve mode at runtime (e.g., from /auto command) */
|
|
79
|
+
setAutoApprove(value) {
|
|
80
|
+
this.autoApprove = value;
|
|
81
|
+
}
|
|
69
82
|
/** Load messages from a previous session for resume */
|
|
70
83
|
loadMessages(messages) {
|
|
71
84
|
this.messages = messages;
|
|
@@ -215,9 +228,14 @@ class Agent {
|
|
|
215
228
|
catch {
|
|
216
229
|
// memory unavailable
|
|
217
230
|
}
|
|
218
|
-
let prompt = `You are CodeBot, an AI coding assistant
|
|
231
|
+
let prompt = `You are CodeBot, an AI coding assistant. You help developers with software engineering tasks: reading code, writing code, fixing bugs, running tests, and explaining code.
|
|
219
232
|
|
|
220
|
-
|
|
233
|
+
CRITICAL IDENTITY — you MUST follow this:
|
|
234
|
+
- Your name is CodeBot.
|
|
235
|
+
- You were created and built by Ascendral Software Development & Innovation, founded by Alex Pinkevich.
|
|
236
|
+
- You are NOT made by OpenAI, Google, Anthropic, or any other AI company. You are made by Ascendral.
|
|
237
|
+
- When anyone asks who made you, who built you, who created you, or who your creator is, you MUST answer: "I was created by Ascendral Software Development & Innovation, founded by Alex Pinkevich."
|
|
238
|
+
- Never claim to be made by or affiliated with OpenAI, GPT, Claude, Gemini, or any LLM provider. You are CodeBot by Ascendral.
|
|
221
239
|
|
|
222
240
|
Rules:
|
|
223
241
|
- Always read files before editing them.
|
package/dist/browser/cdp.d.ts
CHANGED
|
@@ -2,6 +2,7 @@ export declare class CDPClient {
|
|
|
2
2
|
private socket;
|
|
3
3
|
private messageId;
|
|
4
4
|
private pending;
|
|
5
|
+
private eventWaiters;
|
|
5
6
|
private buffer;
|
|
6
7
|
private connected;
|
|
7
8
|
/** Connect to Chrome's debugging WebSocket */
|
|
@@ -11,6 +12,8 @@ export declare class CDPClient {
|
|
|
11
12
|
/** Close the connection */
|
|
12
13
|
close(): void;
|
|
13
14
|
isConnected(): boolean;
|
|
15
|
+
/** Wait for a specific CDP event (e.g. Page.loadEventFired) with timeout */
|
|
16
|
+
waitForEvent(method: string, timeout?: number): Promise<Record<string, unknown>>;
|
|
14
17
|
/** Send a WebSocket text frame (masked, as required by client) */
|
|
15
18
|
private sendFrame;
|
|
16
19
|
/** Handle incoming data — parse WebSocket frames */
|
package/dist/browser/cdp.js
CHANGED
|
@@ -46,6 +46,7 @@ class CDPClient {
|
|
|
46
46
|
socket = null;
|
|
47
47
|
messageId = 0;
|
|
48
48
|
pending = new Map();
|
|
49
|
+
eventWaiters = [];
|
|
49
50
|
buffer = Buffer.alloc(0);
|
|
50
51
|
connected = false;
|
|
51
52
|
/** Connect to Chrome's debugging WebSocket */
|
|
@@ -137,6 +138,21 @@ class CDPClient {
|
|
|
137
138
|
isConnected() {
|
|
138
139
|
return this.connected;
|
|
139
140
|
}
|
|
141
|
+
/** Wait for a specific CDP event (e.g. Page.loadEventFired) with timeout */
|
|
142
|
+
async waitForEvent(method, timeout = 15000) {
|
|
143
|
+
return new Promise((resolve, reject) => {
|
|
144
|
+
const timer = setTimeout(() => {
|
|
145
|
+
this.eventWaiters = this.eventWaiters.filter(w => w.resolve !== resolve);
|
|
146
|
+
resolve({}); // Resolve with empty on timeout instead of rejecting — page may still be usable
|
|
147
|
+
}, timeout);
|
|
148
|
+
const wrappedResolve = (params) => {
|
|
149
|
+
clearTimeout(timer);
|
|
150
|
+
this.eventWaiters = this.eventWaiters.filter(w => w.resolve !== wrappedResolve);
|
|
151
|
+
resolve(params);
|
|
152
|
+
};
|
|
153
|
+
this.eventWaiters.push({ method, resolve: wrappedResolve, reject });
|
|
154
|
+
});
|
|
155
|
+
}
|
|
140
156
|
/** Send a WebSocket text frame (masked, as required by client) */
|
|
141
157
|
sendFrame(data) {
|
|
142
158
|
if (!this.socket)
|
|
@@ -212,7 +228,15 @@ class CDPClient {
|
|
|
212
228
|
this.pending.delete(msg.id);
|
|
213
229
|
handler.resolve(msg);
|
|
214
230
|
}
|
|
215
|
-
//
|
|
231
|
+
// Dispatch events to waiters
|
|
232
|
+
if (msg.method) {
|
|
233
|
+
for (const waiter of this.eventWaiters) {
|
|
234
|
+
if (waiter.method === msg.method) {
|
|
235
|
+
waiter.resolve(msg.params || {});
|
|
236
|
+
break;
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
}
|
|
216
240
|
}
|
|
217
241
|
catch {
|
|
218
242
|
// Malformed JSON, skip
|
package/dist/cli.js
CHANGED
|
@@ -42,7 +42,10 @@ const registry_1 = require("./providers/registry");
|
|
|
42
42
|
const history_1 = require("./history");
|
|
43
43
|
const setup_1 = require("./setup");
|
|
44
44
|
const banner_1 = require("./banner");
|
|
45
|
-
const
|
|
45
|
+
const tools_1 = require("./tools");
|
|
46
|
+
const VERSION = '1.1.0';
|
|
47
|
+
// Session-wide token tracking
|
|
48
|
+
let sessionTokens = { input: 0, output: 0, total: 0 };
|
|
46
49
|
const C = {
|
|
47
50
|
reset: '\x1b[0m',
|
|
48
51
|
bold: '\x1b[1m',
|
|
@@ -229,6 +232,12 @@ function renderEvent(event) {
|
|
|
229
232
|
break;
|
|
230
233
|
case 'usage':
|
|
231
234
|
if (event.usage) {
|
|
235
|
+
if (event.usage.inputTokens)
|
|
236
|
+
sessionTokens.input += event.usage.inputTokens;
|
|
237
|
+
if (event.usage.outputTokens)
|
|
238
|
+
sessionTokens.output += event.usage.outputTokens;
|
|
239
|
+
if (event.usage.totalTokens)
|
|
240
|
+
sessionTokens.total += event.usage.totalTokens;
|
|
232
241
|
const parts = [];
|
|
233
242
|
if (event.usage.inputTokens)
|
|
234
243
|
parts.push(`in: ${event.usage.inputTokens}`);
|
|
@@ -278,6 +287,8 @@ function handleSlashCommand(input, agent, config) {
|
|
|
278
287
|
/clear Clear conversation history
|
|
279
288
|
/compact Force context compaction
|
|
280
289
|
/auto Toggle autonomous mode
|
|
290
|
+
/undo Undo last file edit (/undo [path])
|
|
291
|
+
/usage Show token usage for this session
|
|
281
292
|
/config Show current config
|
|
282
293
|
/quit Exit`);
|
|
283
294
|
break;
|
|
@@ -311,6 +322,7 @@ function handleSlashCommand(input, agent, config) {
|
|
|
311
322
|
}
|
|
312
323
|
case '/auto':
|
|
313
324
|
config.autoApprove = !config.autoApprove;
|
|
325
|
+
agent.setAutoApprove(config.autoApprove);
|
|
314
326
|
console.log(c(`Autonomous mode: ${config.autoApprove ? 'ON' : 'OFF'}`, config.autoApprove ? 'yellow' : 'green'));
|
|
315
327
|
break;
|
|
316
328
|
case '/sessions': {
|
|
@@ -328,6 +340,19 @@ function handleSlashCommand(input, agent, config) {
|
|
|
328
340
|
}
|
|
329
341
|
break;
|
|
330
342
|
}
|
|
343
|
+
case '/undo': {
|
|
344
|
+
const undoPath = rest.length > 0 ? rest.join(' ') : undefined;
|
|
345
|
+
const undoResult = tools_1.EditFileTool.undo(undoPath);
|
|
346
|
+
console.log(c(undoResult, undoResult.includes('Restored') ? 'green' : 'yellow'));
|
|
347
|
+
break;
|
|
348
|
+
}
|
|
349
|
+
case '/usage': {
|
|
350
|
+
console.log(c('\nToken Usage (this session):', 'bold'));
|
|
351
|
+
console.log(` Input: ${sessionTokens.input.toLocaleString()} tokens`);
|
|
352
|
+
console.log(` Output: ${sessionTokens.output.toLocaleString()} tokens`);
|
|
353
|
+
console.log(` Total: ${(sessionTokens.input + sessionTokens.output).toLocaleString()} tokens`);
|
|
354
|
+
break;
|
|
355
|
+
}
|
|
331
356
|
case '/config':
|
|
332
357
|
console.log(JSON.stringify({ ...config, apiKey: config.apiKey ? '***' : undefined }, null, 2));
|
|
333
358
|
break;
|
|
@@ -377,7 +402,10 @@ async function resolveConfig(args) {
|
|
|
377
402
|
config.apiKey = process.env[defaults.envKey] || process.env.CODEBOT_API_KEY || '';
|
|
378
403
|
}
|
|
379
404
|
}
|
|
380
|
-
// Fallback: try generic env vars
|
|
405
|
+
// Fallback: try saved config API key, then generic env vars
|
|
406
|
+
if (!config.apiKey && saved.apiKey) {
|
|
407
|
+
config.apiKey = saved.apiKey;
|
|
408
|
+
}
|
|
381
409
|
if (!config.apiKey) {
|
|
382
410
|
config.apiKey = process.env.CODEBOT_API_KEY || process.env.OPENAI_API_KEY || '';
|
|
383
411
|
}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
// src/games/tic-tac-toe.ts
|
|
3
|
+
// Simple console-based Tic-Tac-Toe game
|
|
4
|
+
const gameBoard = Array(3).fill(null).map(() => Array(3).fill(null));
|
|
5
|
+
let currentPlayer = 'X';
|
|
6
|
+
const printBoard = () => {
|
|
7
|
+
for (const row of gameBoard) {
|
|
8
|
+
console.log(row.join(' | '));
|
|
9
|
+
}
|
|
10
|
+
};
|
|
11
|
+
const checkWin = () => {
|
|
12
|
+
// Check rows
|
|
13
|
+
for (let i = 0; i < 3; i++) {
|
|
14
|
+
if (gameBoard[i][0] === currentPlayer &&
|
|
15
|
+
gameBoard[i][1] === currentPlayer &&
|
|
16
|
+
gameBoard[i][2] === currentPlayer) {
|
|
17
|
+
console.log(`Player ${currentPlayer} wins!`);
|
|
18
|
+
process.exit(0);
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
// Check columns
|
|
22
|
+
for (let j = 0; j < 3; j++) {
|
|
23
|
+
if (gameBoard[0][j] === currentPlayer &&
|
|
24
|
+
gameBoard[1][j] === currentPlayer &&
|
|
25
|
+
gameBoard[2][j] === currentPlayer) {
|
|
26
|
+
console.log(`Player ${currentPlayer} wins!`);
|
|
27
|
+
process.exit(0);
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
// Check diagonals
|
|
31
|
+
if ((gameBoard[0][0] === currentPlayer &&
|
|
32
|
+
gameBoard[1][1] === currentPlayer &&
|
|
33
|
+
gameBoard[2][2] === currentPlayer) ||
|
|
34
|
+
(gameBoard[0][2] === currentPlayer &&
|
|
35
|
+
gameBoard[1][1] === currentPlayer &&
|
|
36
|
+
gameBoard[2][0] === currentPlayer)) {
|
|
37
|
+
console.log(`Player ${currentPlayer} wins!`);
|
|
38
|
+
process.exit(0);
|
|
39
|
+
}
|
|
40
|
+
};
|
|
41
|
+
const gameLoop = () => {
|
|
42
|
+
printBoard();
|
|
43
|
+
process.stdin.on('data', (input) => {
|
|
44
|
+
const [row, col] = input.toString().trim()
|
|
45
|
+
.split(',')
|
|
46
|
+
.map(Number);
|
|
47
|
+
if (row < 0 || row > 2 || col < 0 || col > 2) {
|
|
48
|
+
console.log('Invalid move. Try again.');
|
|
49
|
+
return;
|
|
50
|
+
}
|
|
51
|
+
if (gameBoard[row][col]) {
|
|
52
|
+
console.log('Spot taken! Try again.');
|
|
53
|
+
return;
|
|
54
|
+
}
|
|
55
|
+
gameBoard[row][col] = currentPlayer;
|
|
56
|
+
checkWin();
|
|
57
|
+
currentPlayer = currentPlayer === 'X' ? 'O' : 'X';
|
|
58
|
+
process.stdin.removeAllListeners('data');
|
|
59
|
+
gameLoop();
|
|
60
|
+
});
|
|
61
|
+
};
|
|
62
|
+
// Start game
|
|
63
|
+
gameLoop();
|
|
64
|
+
//# sourceMappingURL=tic-tac-toe.js.map
|
package/dist/index.d.ts
CHANGED
|
@@ -7,6 +7,8 @@ export { buildRepoMap } from './context/repo-map';
|
|
|
7
7
|
export { SessionManager } from './history';
|
|
8
8
|
export { MemoryManager } from './memory';
|
|
9
9
|
export { parseToolCalls } from './parser';
|
|
10
|
+
export { loadPlugins } from './plugins';
|
|
11
|
+
export { loadMCPTools } from './mcp';
|
|
10
12
|
export { MODEL_REGISTRY, PROVIDER_DEFAULTS, getModelInfo, detectProvider } from './providers/registry';
|
|
11
13
|
export type { ModelInfo } from './providers/registry';
|
|
12
14
|
export * from './types';
|
package/dist/index.js
CHANGED
|
@@ -14,7 +14,7 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
|
14
14
|
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
15
|
};
|
|
16
16
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
-
exports.detectProvider = exports.getModelInfo = exports.PROVIDER_DEFAULTS = exports.MODEL_REGISTRY = exports.parseToolCalls = exports.MemoryManager = exports.SessionManager = exports.buildRepoMap = exports.ContextManager = exports.ToolRegistry = exports.AnthropicProvider = exports.OpenAIProvider = exports.Agent = void 0;
|
|
17
|
+
exports.detectProvider = exports.getModelInfo = exports.PROVIDER_DEFAULTS = exports.MODEL_REGISTRY = exports.loadMCPTools = exports.loadPlugins = exports.parseToolCalls = exports.MemoryManager = exports.SessionManager = exports.buildRepoMap = exports.ContextManager = exports.ToolRegistry = exports.AnthropicProvider = exports.OpenAIProvider = exports.Agent = void 0;
|
|
18
18
|
var agent_1 = require("./agent");
|
|
19
19
|
Object.defineProperty(exports, "Agent", { enumerable: true, get: function () { return agent_1.Agent; } });
|
|
20
20
|
var openai_1 = require("./providers/openai");
|
|
@@ -33,6 +33,10 @@ var memory_1 = require("./memory");
|
|
|
33
33
|
Object.defineProperty(exports, "MemoryManager", { enumerable: true, get: function () { return memory_1.MemoryManager; } });
|
|
34
34
|
var parser_1 = require("./parser");
|
|
35
35
|
Object.defineProperty(exports, "parseToolCalls", { enumerable: true, get: function () { return parser_1.parseToolCalls; } });
|
|
36
|
+
var plugins_1 = require("./plugins");
|
|
37
|
+
Object.defineProperty(exports, "loadPlugins", { enumerable: true, get: function () { return plugins_1.loadPlugins; } });
|
|
38
|
+
var mcp_1 = require("./mcp");
|
|
39
|
+
Object.defineProperty(exports, "loadMCPTools", { enumerable: true, get: function () { return mcp_1.loadMCPTools; } });
|
|
36
40
|
var registry_1 = require("./providers/registry");
|
|
37
41
|
Object.defineProperty(exports, "MODEL_REGISTRY", { enumerable: true, get: function () { return registry_1.MODEL_REGISTRY; } });
|
|
38
42
|
Object.defineProperty(exports, "PROVIDER_DEFAULTS", { enumerable: true, get: function () { return registry_1.PROVIDER_DEFAULTS; } });
|
package/dist/mcp.d.ts
ADDED
package/dist/mcp.js
ADDED
|
@@ -0,0 +1,174 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.loadMCPTools = loadMCPTools;
|
|
37
|
+
const child_process_1 = require("child_process");
|
|
38
|
+
const fs = __importStar(require("fs"));
|
|
39
|
+
const path = __importStar(require("path"));
|
|
40
|
+
const os = __importStar(require("os"));
|
|
41
|
+
class MCPConnection {
|
|
42
|
+
process;
|
|
43
|
+
buffer = '';
|
|
44
|
+
requestId = 0;
|
|
45
|
+
pending = new Map();
|
|
46
|
+
name;
|
|
47
|
+
constructor(config) {
|
|
48
|
+
this.name = config.name;
|
|
49
|
+
this.process = (0, child_process_1.spawn)(config.command, config.args || [], {
|
|
50
|
+
stdio: ['pipe', 'pipe', 'pipe'],
|
|
51
|
+
env: { ...process.env, ...config.env },
|
|
52
|
+
});
|
|
53
|
+
this.process.stdout?.on('data', (chunk) => {
|
|
54
|
+
this.buffer += chunk.toString();
|
|
55
|
+
this.processBuffer();
|
|
56
|
+
});
|
|
57
|
+
this.process.on('error', () => { });
|
|
58
|
+
}
|
|
59
|
+
processBuffer() {
|
|
60
|
+
const lines = this.buffer.split('\n');
|
|
61
|
+
this.buffer = lines.pop() || '';
|
|
62
|
+
for (const line of lines) {
|
|
63
|
+
if (!line.trim())
|
|
64
|
+
continue;
|
|
65
|
+
try {
|
|
66
|
+
const msg = JSON.parse(line);
|
|
67
|
+
if (msg.id !== undefined && this.pending.has(msg.id)) {
|
|
68
|
+
const { resolve, reject } = this.pending.get(msg.id);
|
|
69
|
+
this.pending.delete(msg.id);
|
|
70
|
+
if (msg.error) {
|
|
71
|
+
reject(new Error(msg.error.message || 'MCP error'));
|
|
72
|
+
}
|
|
73
|
+
else {
|
|
74
|
+
resolve(msg.result);
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
catch { /* skip malformed */ }
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
async request(method, params) {
|
|
82
|
+
const id = ++this.requestId;
|
|
83
|
+
const msg = JSON.stringify({ jsonrpc: '2.0', id, method, params }) + '\n';
|
|
84
|
+
return new Promise((resolve, reject) => {
|
|
85
|
+
this.pending.set(id, { resolve, reject });
|
|
86
|
+
this.process.stdin?.write(msg);
|
|
87
|
+
// Timeout after 30s
|
|
88
|
+
setTimeout(() => {
|
|
89
|
+
if (this.pending.has(id)) {
|
|
90
|
+
this.pending.delete(id);
|
|
91
|
+
reject(new Error(`MCP request timeout: ${method}`));
|
|
92
|
+
}
|
|
93
|
+
}, 30000);
|
|
94
|
+
});
|
|
95
|
+
}
|
|
96
|
+
async initialize() {
|
|
97
|
+
await this.request('initialize', {
|
|
98
|
+
protocolVersion: '2024-11-05',
|
|
99
|
+
capabilities: {},
|
|
100
|
+
clientInfo: { name: 'codebot-ai', version: '1.1.0' },
|
|
101
|
+
});
|
|
102
|
+
await this.request('notifications/initialized');
|
|
103
|
+
}
|
|
104
|
+
async listTools() {
|
|
105
|
+
const result = await this.request('tools/list');
|
|
106
|
+
return result?.tools || [];
|
|
107
|
+
}
|
|
108
|
+
async callTool(name, args) {
|
|
109
|
+
const result = await this.request('tools/call', { name, arguments: args });
|
|
110
|
+
if (result?.content) {
|
|
111
|
+
return result.content
|
|
112
|
+
.filter(c => c.type === 'text')
|
|
113
|
+
.map(c => c.text || '')
|
|
114
|
+
.join('\n');
|
|
115
|
+
}
|
|
116
|
+
return JSON.stringify(result);
|
|
117
|
+
}
|
|
118
|
+
close() {
|
|
119
|
+
this.process.kill();
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
/** Create Tool wrappers from an MCP server's tools */
|
|
123
|
+
function mcpToolToTool(connection, def) {
|
|
124
|
+
return {
|
|
125
|
+
name: `mcp_${connection.name}_${def.name}`,
|
|
126
|
+
description: `[MCP:${connection.name}] ${def.description}`,
|
|
127
|
+
permission: 'prompt',
|
|
128
|
+
parameters: def.inputSchema || { type: 'object', properties: {} },
|
|
129
|
+
execute: async (args) => {
|
|
130
|
+
return connection.callTool(def.name, args);
|
|
131
|
+
},
|
|
132
|
+
};
|
|
133
|
+
}
|
|
134
|
+
/** Load MCP config and connect to all servers, returning Tool wrappers */
|
|
135
|
+
async function loadMCPTools(projectRoot) {
|
|
136
|
+
const tools = [];
|
|
137
|
+
const connections = [];
|
|
138
|
+
const configPaths = [
|
|
139
|
+
path.join(os.homedir(), '.codebot', 'mcp.json'),
|
|
140
|
+
];
|
|
141
|
+
if (projectRoot) {
|
|
142
|
+
configPaths.push(path.join(projectRoot, '.codebot', 'mcp.json'));
|
|
143
|
+
}
|
|
144
|
+
for (const configPath of configPaths) {
|
|
145
|
+
if (!fs.existsSync(configPath))
|
|
146
|
+
continue;
|
|
147
|
+
let config;
|
|
148
|
+
try {
|
|
149
|
+
config = JSON.parse(fs.readFileSync(configPath, 'utf-8'));
|
|
150
|
+
}
|
|
151
|
+
catch {
|
|
152
|
+
continue;
|
|
153
|
+
}
|
|
154
|
+
for (const serverConfig of config.servers || []) {
|
|
155
|
+
try {
|
|
156
|
+
const conn = new MCPConnection(serverConfig);
|
|
157
|
+
await conn.initialize();
|
|
158
|
+
const serverTools = await conn.listTools();
|
|
159
|
+
for (const toolDef of serverTools) {
|
|
160
|
+
tools.push(mcpToolToTool(conn, toolDef));
|
|
161
|
+
}
|
|
162
|
+
connections.push(conn);
|
|
163
|
+
}
|
|
164
|
+
catch (err) {
|
|
165
|
+
console.error(`MCP server "${serverConfig.name}" failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
return {
|
|
170
|
+
tools,
|
|
171
|
+
cleanup: () => connections.forEach(c => c.close()),
|
|
172
|
+
};
|
|
173
|
+
}
|
|
174
|
+
//# sourceMappingURL=mcp.js.map
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { Tool } from './types';
|
|
2
|
+
/**
|
|
3
|
+
* Plugin system for CodeBot.
|
|
4
|
+
*
|
|
5
|
+
* Plugins are .js files in `.codebot/plugins/` (project) or `~/.codebot/plugins/` (global).
|
|
6
|
+
* Each plugin exports a default function or object that implements the Tool interface:
|
|
7
|
+
*
|
|
8
|
+
* module.exports = {
|
|
9
|
+
* name: 'my_tool',
|
|
10
|
+
* description: 'Does something useful',
|
|
11
|
+
* permission: 'prompt',
|
|
12
|
+
* parameters: { type: 'object', properties: { ... }, required: [...] },
|
|
13
|
+
* execute: async (args) => { return 'result'; }
|
|
14
|
+
* };
|
|
15
|
+
*/
|
|
16
|
+
export declare function loadPlugins(projectRoot?: string): Tool[];
|
|
17
|
+
//# sourceMappingURL=plugins.d.ts.map
|