let-them-talk 3.1.1 → 3.2.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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2024-2026 Dekelelz
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
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 v3.0.0
11
+ Let Them Talk — Agent Bridge v3.2.0
12
12
  MCP message broker for inter-agent communication
13
13
  Supports: Claude Code, Gemini CLI, Codex CLI
14
14
 
@@ -232,13 +232,9 @@ function reset() {
232
232
  console.log(' No data directory found. Nothing to reset.');
233
233
  return;
234
234
  }
235
- const files = fs.readdirSync(targetDir);
236
- let count = 0;
237
- for (const f of files) {
238
- fs.unlinkSync(path.join(targetDir, f));
239
- count++;
240
- }
241
- console.log(` Cleared ${count} file(s) from ${targetDir}`);
235
+ fs.rmSync(targetDir, { recursive: true, force: true });
236
+ fs.mkdirSync(targetDir, { recursive: true });
237
+ console.log(` Cleared all data from ${targetDir}`);
242
238
  }
243
239
 
244
240
  function getTemplates() {
package/dashboard.html CHANGED
@@ -2471,7 +2471,7 @@
2471
2471
  </div>
2472
2472
  </div>
2473
2473
  <div class="app-footer">
2474
- <span>Let Them Talk v3.0.0</span>
2474
+ <span>Let Them Talk v3.2.0</span>
2475
2475
  </div>
2476
2476
  <div class="profile-popup" id="profile-popup" onclick="event.stopPropagation()">
2477
2477
  <div class="profile-popup-header">
@@ -2810,7 +2810,7 @@ function renderAgents(agents) {
2810
2810
  }
2811
2811
 
2812
2812
  var avatarHtml = info.avatar
2813
- ? '<img class="agent-avatar-img" src="' + info.avatar + '" alt="' + escapeHtml(name) + '" onerror="this.style.display=\'none\'">'
2813
+ ? '<img class="agent-avatar-img" src="' + escapeHtml(info.avatar) + '" alt="' + escapeHtml(name) + '" onerror="this.style.display=\'none\'">'
2814
2814
  : '<div class="agent-avatar" style="background:' + color + '">' + initial(name) + '</div>';
2815
2815
  var displayName = info.display_name || name;
2816
2816
  var roleHtml = info.role ? '<span class="role-badge">' + escapeHtml(info.role) + '</span>' : '';
@@ -3755,7 +3755,7 @@ textarea.addEventListener('input', function() {
3755
3755
  function getMsgAvatar(name, color) {
3756
3756
  var agent = cachedAgents[name];
3757
3757
  if (agent && agent.avatar) {
3758
- return '<img class="msg-avatar-img" src="' + agent.avatar + '" alt="' + escapeHtml(name) + '" onerror="this.outerHTML=\'<div class=&quot;msg-avatar&quot; style=&quot;background:' + color + '&quot;>' + initial(name) + '</div>\'">';
3758
+ return '<img class="msg-avatar-img" src="' + escapeHtml(agent.avatar) + '" alt="' + escapeHtml(name) + '" onerror="this.outerHTML=\'<div class=&quot;msg-avatar&quot; style=&quot;background:' + color + '&quot;>' + initial(name) + '</div>\'">';
3759
3759
  }
3760
3760
  return '<div class="msg-avatar" style="background:' + color + '">' + initial(name) + '</div>';
3761
3761
  }
@@ -4323,7 +4323,7 @@ function updateTypingIndicator(agents) {
4323
4323
  var info = agents[keys[i]];
4324
4324
  // Agent is alive, not listening, and was recently active (processing a message)
4325
4325
  if (info.alive && !info.is_listening && info.status === 'active') {
4326
- typing.push(info.display_name || keys[i]);
4326
+ typing.push(escapeHtml(info.display_name || keys[i]));
4327
4327
  }
4328
4328
  }
4329
4329
  var bar = document.getElementById('typing-bar');
@@ -4729,7 +4729,7 @@ function doLaunch() {
4729
4729
  }).then(function(r) { return r.json(); }).then(function(data) {
4730
4730
  if (data.error) {
4731
4731
  resultEl.className = 'launch-result error';
4732
- resultEl.innerHTML = data.error;
4732
+ resultEl.innerHTML = escapeHtml(data.error);
4733
4733
  return;
4734
4734
  }
4735
4735
  resultEl.className = 'launch-result success';
package/dashboard.js CHANGED
@@ -3,7 +3,7 @@ const http = require('http');
3
3
  const fs = require('fs');
4
4
  const path = require('path');
5
5
  const os = require('os');
6
- const { exec } = require('child_process');
6
+ const { spawn } = require('child_process');
7
7
 
8
8
  const PORT = parseInt(process.env.AGENT_BRIDGE_PORT || '3000', 10);
9
9
  let LAN_MODE = process.env.AGENT_BRIDGE_LAN === 'true';
@@ -139,6 +139,9 @@ function getDefaultAvatar(name) {
139
139
  function apiHistory(query) {
140
140
  const projectPath = query.get('project') || null;
141
141
  const branch = query.get('branch') || null;
142
+ if (branch && !/^[a-zA-Z0-9_-]{1,64}$/.test(branch)) {
143
+ return { error: 'Invalid branch name' };
144
+ }
142
145
  const histFile = branch && branch !== 'main'
143
146
  ? filePath(`branch-${branch}-history.jsonl`, projectPath)
144
147
  : filePath('history.jsonl', projectPath);
@@ -615,8 +618,7 @@ function apiLaunchAgent(body) {
615
618
 
616
619
  // Try to launch terminal on Windows
617
620
  if (process.platform === 'win32') {
618
- const escapedDir = projectDir.replace(/"/g, '\\"');
619
- exec(`start cmd /k "cd /d "${escapedDir}" && ${cliCmd}"`, { cwd: projectDir });
621
+ spawn('cmd', ['/c', 'start', 'cmd', '/k', `cd /d "${projectDir}" && ${cliCmd}`], { cwd: projectDir, shell: false, detached: true, stdio: 'ignore' });
620
622
  return { success: true, launched: true, cli, project_dir: projectDir, prompt: launchPrompt };
621
623
  }
622
624
 
@@ -662,7 +664,7 @@ const server = http.createServer(async (req, res) => {
662
664
  const allowedOrigin = `http://localhost:${PORT}`;
663
665
  const reqOrigin = req.headers.origin;
664
666
  if (LAN_MODE && reqOrigin) {
665
- res.setHeader('Access-Control-Allow-Origin', reqOrigin);
667
+ res.setHeader('Access-Control-Allow-Origin', '*');
666
668
  } else if (reqOrigin === allowedOrigin || reqOrigin === `http://127.0.0.1:${PORT}`) {
667
669
  res.setHeader('Access-Control-Allow-Origin', reqOrigin);
668
670
  }
@@ -794,6 +796,11 @@ const server = http.createServer(async (req, res) => {
794
796
  else if (url.pathname === '/api/workspaces' && req.method === 'GET') {
795
797
  const projectPath = url.searchParams.get('project') || null;
796
798
  const agentParam = url.searchParams.get('agent');
799
+ if (agentParam && !/^[a-zA-Z0-9]{1,20}$/.test(agentParam)) {
800
+ res.writeHead(400, { 'Content-Type': 'application/json' });
801
+ res.end(JSON.stringify({ error: 'Invalid agent name' }));
802
+ return;
803
+ }
797
804
  const dataDir = resolveDataDir(projectPath);
798
805
  const wsDir = path.join(dataDir, 'workspaces');
799
806
  const result = {};
package/logo.png ADDED
Binary file
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "let-them-talk",
3
- "version": "3.1.1",
3
+ "version": "3.2.1",
4
4
  "description": "MCP message broker + web dashboard for inter-agent communication. Let AI CLI agents talk to each other.",
5
5
  "main": "server.js",
6
6
  "bin": {
@@ -9,14 +9,20 @@
9
9
  },
10
10
  "scripts": {
11
11
  "start": "node server.js",
12
- "dashboard": "node dashboard.js"
12
+ "dashboard": "node dashboard.js",
13
+ "test": "echo \"No tests yet\""
14
+ },
15
+ "engines": {
16
+ "node": ">=16.0.0"
13
17
  },
14
18
  "files": [
15
19
  "server.js",
16
20
  "dashboard.js",
17
21
  "dashboard.html",
18
22
  "cli.js",
19
- "templates/"
23
+ "templates/",
24
+ "logo.png",
25
+ "LICENSE"
20
26
  ],
21
27
  "keywords": [
22
28
  "mcp",
@@ -33,7 +39,7 @@
33
39
  ],
34
40
  "repository": {
35
41
  "type": "git",
36
- "url": "https://github.com/Dekelelz/let-them-talk.git"
42
+ "url": "git+https://github.com/Dekelelz/let-them-talk.git"
37
43
  },
38
44
  "homepage": "https://github.com/Dekelelz/let-them-talk",
39
45
  "bugs": {
@@ -42,6 +48,6 @@
42
48
  "author": "Dekelelz",
43
49
  "license": "MIT",
44
50
  "dependencies": {
45
- "@modelcontextprotocol/sdk": "^1.0.0"
51
+ "@modelcontextprotocol/sdk": "1.27.1"
46
52
  }
47
53
  }
package/server.js CHANGED
@@ -1970,7 +1970,7 @@ async function main() {
1970
1970
  loadPlugins();
1971
1971
  const transport = new StdioServerTransport();
1972
1972
  await server.connect(transport);
1973
- console.error('Agent Bridge MCP server v3.0.0 running (' + (17 + loadedPlugins.length) + ' tools)');
1973
+ console.error('Agent Bridge MCP server v3.2.0 running (' + (27 + loadedPlugins.length) + ' tools)');
1974
1974
  }
1975
1975
 
1976
1976
  main().catch(console.error);