let-them-talk 2.5.0 → 3.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/cli.js +146 -16
- package/dashboard.html +1776 -62
- package/dashboard.js +402 -24
- package/package.json +1 -1
- package/server.js +808 -43
package/cli.js
CHANGED
|
@@ -8,7 +8,7 @@ const command = process.argv[2];
|
|
|
8
8
|
|
|
9
9
|
function printUsage() {
|
|
10
10
|
console.log(`
|
|
11
|
-
Let Them Talk — Agent Bridge
|
|
11
|
+
Let Them Talk — Agent Bridge v3.0.0
|
|
12
12
|
MCP message broker for inter-agent communication
|
|
13
13
|
Supports: Claude Code, Gemini CLI, Codex CLI
|
|
14
14
|
|
|
@@ -21,7 +21,13 @@ function printUsage() {
|
|
|
21
21
|
npx let-them-talk init --template T Initialize with a team template (pair, team, review, debate)
|
|
22
22
|
npx let-them-talk templates List available agent templates
|
|
23
23
|
npx let-them-talk dashboard Launch the web dashboard (http://localhost:3000)
|
|
24
|
+
npx let-them-talk dashboard --lan Launch dashboard accessible on LAN (phone/tablet)
|
|
24
25
|
npx let-them-talk reset Clear all conversation data
|
|
26
|
+
npx let-them-talk plugin list List installed plugins
|
|
27
|
+
npx let-them-talk plugin add <file> Install a plugin from a .js file
|
|
28
|
+
npx let-them-talk plugin remove <n> Remove a plugin by name
|
|
29
|
+
npx let-them-talk plugin enable <n> Enable a plugin
|
|
30
|
+
npx let-them-talk plugin disable <n> Disable a plugin
|
|
25
31
|
npx let-them-talk help Show this help message
|
|
26
32
|
`);
|
|
27
33
|
}
|
|
@@ -103,25 +109,36 @@ function setupGemini(serverPath, cwd) {
|
|
|
103
109
|
console.log(' [ok] Gemini CLI: .gemini/settings.json updated');
|
|
104
110
|
}
|
|
105
111
|
|
|
106
|
-
// Configure for Codex CLI (
|
|
112
|
+
// Configure for Codex CLI (uses .codex/config.toml)
|
|
107
113
|
function setupCodex(serverPath, cwd) {
|
|
108
|
-
const
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
if (!mcpConfig.mcpServers) mcpConfig.mcpServers = {};
|
|
114
|
-
} catch {}
|
|
114
|
+
const codexDir = path.join(cwd, '.codex');
|
|
115
|
+
const configPath = path.join(codexDir, 'config.toml');
|
|
116
|
+
|
|
117
|
+
if (!fs.existsSync(codexDir)) {
|
|
118
|
+
fs.mkdirSync(codexDir, { recursive: true });
|
|
115
119
|
}
|
|
116
120
|
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
}
|
|
121
|
+
// Read existing config or start fresh
|
|
122
|
+
let config = '';
|
|
123
|
+
if (fs.existsSync(configPath)) {
|
|
124
|
+
config = fs.readFileSync(configPath, 'utf8');
|
|
125
|
+
}
|
|
122
126
|
|
|
123
|
-
|
|
124
|
-
|
|
127
|
+
// Only add if not already present
|
|
128
|
+
if (!config.includes('[mcp_servers.agent-bridge]')) {
|
|
129
|
+
const tomlBlock = `
|
|
130
|
+
[mcp_servers.agent-bridge]
|
|
131
|
+
command = "node"
|
|
132
|
+
args = [${JSON.stringify(serverPath)}]
|
|
133
|
+
|
|
134
|
+
[mcp_servers.agent-bridge.env]
|
|
135
|
+
AGENT_BRIDGE_DATA_DIR = ${JSON.stringify(dataDir(cwd))}
|
|
136
|
+
`;
|
|
137
|
+
config += tomlBlock;
|
|
138
|
+
fs.writeFileSync(configPath, config);
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
console.log(' [ok] Codex CLI: .codex/config.toml updated');
|
|
125
142
|
}
|
|
126
143
|
|
|
127
144
|
function init() {
|
|
@@ -278,7 +295,116 @@ function showTemplate(templateName) {
|
|
|
278
295
|
}
|
|
279
296
|
}
|
|
280
297
|
|
|
298
|
+
function pluginCmd() {
|
|
299
|
+
const subCmd = process.argv[3];
|
|
300
|
+
const dataDir = process.env.AGENT_BRIDGE_DATA_DIR || path.join(process.cwd(), '.agent-bridge');
|
|
301
|
+
const pluginsDir = path.join(dataDir, 'plugins');
|
|
302
|
+
const pluginsFile = path.join(dataDir, 'plugins.json');
|
|
303
|
+
|
|
304
|
+
function getRegistry() {
|
|
305
|
+
if (!fs.existsSync(pluginsFile)) return [];
|
|
306
|
+
try { return JSON.parse(fs.readFileSync(pluginsFile, 'utf8')); } catch { return []; }
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
function saveRegistry(reg) {
|
|
310
|
+
if (!fs.existsSync(dataDir)) fs.mkdirSync(dataDir, { recursive: true });
|
|
311
|
+
fs.writeFileSync(pluginsFile, JSON.stringify(reg, null, 2));
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
switch (subCmd) {
|
|
315
|
+
case 'list': {
|
|
316
|
+
const plugins = getRegistry();
|
|
317
|
+
if (!plugins.length) {
|
|
318
|
+
console.log(' No plugins installed.');
|
|
319
|
+
console.log(' Install with: npx let-them-talk plugin add <file.js>');
|
|
320
|
+
return;
|
|
321
|
+
}
|
|
322
|
+
console.log('');
|
|
323
|
+
console.log(' Installed Plugins');
|
|
324
|
+
console.log(' =================');
|
|
325
|
+
for (const p of plugins) {
|
|
326
|
+
const status = p.enabled !== false ? 'enabled' : 'disabled';
|
|
327
|
+
console.log(' ' + p.name.padEnd(20) + ' ' + status.padEnd(10) + ' ' + (p.description || ''));
|
|
328
|
+
}
|
|
329
|
+
console.log('');
|
|
330
|
+
break;
|
|
331
|
+
}
|
|
332
|
+
case 'add': {
|
|
333
|
+
const filePath = process.argv[4];
|
|
334
|
+
if (!filePath) { console.error(' Usage: npx let-them-talk plugin add <file.js>'); process.exit(1); }
|
|
335
|
+
const absPath = path.resolve(filePath);
|
|
336
|
+
if (!fs.existsSync(absPath)) { console.error(' File not found: ' + absPath); process.exit(1); }
|
|
337
|
+
|
|
338
|
+
// Validate plugin exports
|
|
339
|
+
try {
|
|
340
|
+
const plugin = require(absPath);
|
|
341
|
+
if (!plugin.name || !plugin.handler) { console.error(' Plugin must export name, description, and handler'); process.exit(1); }
|
|
342
|
+
|
|
343
|
+
if (!fs.existsSync(pluginsDir)) fs.mkdirSync(pluginsDir, { recursive: true });
|
|
344
|
+
const destFile = path.join(pluginsDir, path.basename(absPath));
|
|
345
|
+
fs.copyFileSync(absPath, destFile);
|
|
346
|
+
|
|
347
|
+
const reg = getRegistry();
|
|
348
|
+
if (!reg.find(p => p.name === plugin.name)) {
|
|
349
|
+
reg.push({ name: plugin.name, description: plugin.description || '', file: path.basename(absPath), enabled: true, added_at: new Date().toISOString() });
|
|
350
|
+
saveRegistry(reg);
|
|
351
|
+
}
|
|
352
|
+
console.log(' Plugin "' + plugin.name + '" installed successfully.');
|
|
353
|
+
console.log(' Restart CLI to load the new tool.');
|
|
354
|
+
} catch (e) {
|
|
355
|
+
console.error(' Failed to load plugin: ' + e.message);
|
|
356
|
+
process.exit(1);
|
|
357
|
+
}
|
|
358
|
+
break;
|
|
359
|
+
}
|
|
360
|
+
case 'remove': {
|
|
361
|
+
const name = process.argv[4];
|
|
362
|
+
if (!name) { console.error(' Usage: npx let-them-talk plugin remove <name>'); process.exit(1); }
|
|
363
|
+
const reg = getRegistry();
|
|
364
|
+
const plugin = reg.find(p => p.name === name);
|
|
365
|
+
if (!plugin) { console.error(' Plugin not found: ' + name); process.exit(1); }
|
|
366
|
+
const newReg = reg.filter(p => p.name !== name);
|
|
367
|
+
saveRegistry(newReg);
|
|
368
|
+
if (plugin.file) {
|
|
369
|
+
const pluginFile = path.join(pluginsDir, plugin.file);
|
|
370
|
+
if (fs.existsSync(pluginFile)) fs.unlinkSync(pluginFile);
|
|
371
|
+
}
|
|
372
|
+
console.log(' Plugin "' + name + '" removed.');
|
|
373
|
+
break;
|
|
374
|
+
}
|
|
375
|
+
case 'enable': {
|
|
376
|
+
const name = process.argv[4];
|
|
377
|
+
if (!name) { console.error(' Usage: npx let-them-talk plugin enable <name>'); process.exit(1); }
|
|
378
|
+
const reg = getRegistry();
|
|
379
|
+
const plugin = reg.find(p => p.name === name);
|
|
380
|
+
if (!plugin) { console.error(' Plugin not found: ' + name); process.exit(1); }
|
|
381
|
+
plugin.enabled = true;
|
|
382
|
+
saveRegistry(reg);
|
|
383
|
+
console.log(' Plugin "' + name + '" enabled.');
|
|
384
|
+
break;
|
|
385
|
+
}
|
|
386
|
+
case 'disable': {
|
|
387
|
+
const name = process.argv[4];
|
|
388
|
+
if (!name) { console.error(' Usage: npx let-them-talk plugin disable <name>'); process.exit(1); }
|
|
389
|
+
const reg = getRegistry();
|
|
390
|
+
const plugin = reg.find(p => p.name === name);
|
|
391
|
+
if (!plugin) { console.error(' Plugin not found: ' + name); process.exit(1); }
|
|
392
|
+
plugin.enabled = false;
|
|
393
|
+
saveRegistry(reg);
|
|
394
|
+
console.log(' Plugin "' + name + '" disabled.');
|
|
395
|
+
break;
|
|
396
|
+
}
|
|
397
|
+
default:
|
|
398
|
+
console.error(' Unknown plugin command: ' + (subCmd || ''));
|
|
399
|
+
console.error(' Available: list, add, remove, enable, disable');
|
|
400
|
+
process.exit(1);
|
|
401
|
+
}
|
|
402
|
+
}
|
|
403
|
+
|
|
281
404
|
function dashboard() {
|
|
405
|
+
if (process.argv.includes('--lan')) {
|
|
406
|
+
process.env.AGENT_BRIDGE_LAN = 'true';
|
|
407
|
+
}
|
|
282
408
|
require('./dashboard.js');
|
|
283
409
|
}
|
|
284
410
|
|
|
@@ -295,6 +421,10 @@ switch (command) {
|
|
|
295
421
|
case 'reset':
|
|
296
422
|
reset();
|
|
297
423
|
break;
|
|
424
|
+
case 'plugin':
|
|
425
|
+
case 'plugins':
|
|
426
|
+
pluginCmd();
|
|
427
|
+
break;
|
|
298
428
|
case 'help':
|
|
299
429
|
case '--help':
|
|
300
430
|
case '-h':
|