let-them-talk 3.4.4 → 3.5.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/CHANGELOG.md +30 -0
- package/LICENSE +1 -1
- package/README.md +9 -8
- package/cli.js +152 -3
- package/conversation-templates/code-review.json +11 -0
- package/conversation-templates/debug-squad.json +11 -0
- package/conversation-templates/feature-build.json +11 -0
- package/conversation-templates/research-write.json +11 -0
- package/dashboard.html +185 -3
- package/dashboard.js +287 -7
- package/package.json +2 -2
- package/server.js +227 -31
package/dashboard.js
CHANGED
|
@@ -138,8 +138,15 @@ function readJson(file) {
|
|
|
138
138
|
try { return JSON.parse(fs.readFileSync(file, 'utf8')); } catch { return {}; }
|
|
139
139
|
}
|
|
140
140
|
|
|
141
|
-
function isPidAlive(pid) {
|
|
142
|
-
try {
|
|
141
|
+
function isPidAlive(pid, lastActivity) {
|
|
142
|
+
try {
|
|
143
|
+
process.kill(pid, 0);
|
|
144
|
+
if (lastActivity) {
|
|
145
|
+
const stale = Date.now() - new Date(lastActivity).getTime();
|
|
146
|
+
if (stale > 30000) return false; // 30s = 3 missed heartbeats
|
|
147
|
+
}
|
|
148
|
+
return true;
|
|
149
|
+
} catch { return false; }
|
|
143
150
|
}
|
|
144
151
|
|
|
145
152
|
// --- Default avatar helpers ---
|
|
@@ -207,7 +214,7 @@ function apiAgents(query) {
|
|
|
207
214
|
}
|
|
208
215
|
|
|
209
216
|
for (const [name, info] of Object.entries(agents)) {
|
|
210
|
-
const alive = isPidAlive(info.pid);
|
|
217
|
+
const alive = isPidAlive(info.pid, info.last_activity);
|
|
211
218
|
const lastActivity = info.last_activity || info.timestamp;
|
|
212
219
|
const idleSeconds = Math.floor((Date.now() - new Date(lastActivity).getTime()) / 1000);
|
|
213
220
|
const profile = profiles[name] || {};
|
|
@@ -240,9 +247,9 @@ function apiStatus(query) {
|
|
|
240
247
|
history.forEach(m => { if (m.thread_id) threads.add(m.thread_id); });
|
|
241
248
|
|
|
242
249
|
const agentEntries = Object.entries(agents);
|
|
243
|
-
const aliveCount = agentEntries.filter(([, a]) => isPidAlive(a.pid)).length;
|
|
250
|
+
const aliveCount = agentEntries.filter(([, a]) => isPidAlive(a.pid, a.last_activity)).length;
|
|
244
251
|
const sleepingCount = agentEntries.filter(([, a]) => {
|
|
245
|
-
if (!isPidAlive(a.pid)) return false;
|
|
252
|
+
if (!isPidAlive(a.pid, a.last_activity)) return false;
|
|
246
253
|
const lastActivity = a.last_activity || a.timestamp;
|
|
247
254
|
const idleSeconds = Math.floor((Date.now() - new Date(lastActivity).getTime()) / 1000);
|
|
248
255
|
return idleSeconds > 60;
|
|
@@ -325,10 +332,252 @@ function apiStats(query) {
|
|
|
325
332
|
};
|
|
326
333
|
}
|
|
327
334
|
|
|
335
|
+
// --- v3.4: Notification Tracking ---
|
|
336
|
+
let notificationHistory = [];
|
|
337
|
+
let prevAgentState = {};
|
|
338
|
+
|
|
339
|
+
function generateNotifications(currentAgents) {
|
|
340
|
+
const crypto = require('crypto');
|
|
341
|
+
const now = new Date().toISOString();
|
|
342
|
+
|
|
343
|
+
for (const [name, agent] of Object.entries(currentAgents)) {
|
|
344
|
+
const prev = prevAgentState[name];
|
|
345
|
+
const isAlive = agent.pid ? isPidAlive(agent.pid, agent.last_activity) : false;
|
|
346
|
+
const isListening = !!agent.listening;
|
|
347
|
+
|
|
348
|
+
if (prev) {
|
|
349
|
+
if (!prev.alive && isAlive) {
|
|
350
|
+
notificationHistory.push({ id: crypto.randomBytes(8).toString('hex'), type: 'agent_online', agent: name, message: `${name} came online`, timestamp: now });
|
|
351
|
+
}
|
|
352
|
+
if (prev.alive && !isAlive) {
|
|
353
|
+
notificationHistory.push({ id: crypto.randomBytes(8).toString('hex'), type: 'agent_offline', agent: name, message: `${name} went offline`, timestamp: now });
|
|
354
|
+
}
|
|
355
|
+
if (!prev.listening && isListening) {
|
|
356
|
+
notificationHistory.push({ id: crypto.randomBytes(8).toString('hex'), type: 'agent_listening', agent: name, message: `${name} started listening`, timestamp: now });
|
|
357
|
+
}
|
|
358
|
+
if (prev.listening && !isListening) {
|
|
359
|
+
notificationHistory.push({ id: crypto.randomBytes(8).toString('hex'), type: 'agent_busy', agent: name, message: `${name} stopped listening`, timestamp: now });
|
|
360
|
+
}
|
|
361
|
+
} else if (isAlive) {
|
|
362
|
+
notificationHistory.push({ id: crypto.randomBytes(8).toString('hex'), type: 'agent_online', agent: name, message: `${name} came online`, timestamp: now });
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
prevAgentState[name] = { alive: isAlive, listening: isListening };
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
// Trim to max 50
|
|
369
|
+
if (notificationHistory.length > 50) {
|
|
370
|
+
notificationHistory = notificationHistory.slice(-50);
|
|
371
|
+
}
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
function apiNotifications() {
|
|
375
|
+
return notificationHistory;
|
|
376
|
+
}
|
|
377
|
+
|
|
378
|
+
// --- v3.4: Performance Scoring ---
|
|
379
|
+
function apiScores(query) {
|
|
380
|
+
const projectPath = query.get('project') || null;
|
|
381
|
+
const history = readJsonl(filePath('history.jsonl', projectPath));
|
|
382
|
+
const agents = readJson(filePath('agents.json', projectPath));
|
|
383
|
+
|
|
384
|
+
const perAgent = {};
|
|
385
|
+
const totalMessages = history.length;
|
|
386
|
+
const allAgentNames = new Set();
|
|
387
|
+
|
|
388
|
+
// Gather per-agent data
|
|
389
|
+
for (let i = 0; i < history.length; i++) {
|
|
390
|
+
const m = history[i];
|
|
391
|
+
const from = m.from || 'unknown';
|
|
392
|
+
allAgentNames.add(from);
|
|
393
|
+
if (m.to) allAgentNames.add(m.to);
|
|
394
|
+
if (!perAgent[from]) perAgent[from] = { messages: 0, responseTimes: [], peers: new Set() };
|
|
395
|
+
perAgent[from].messages++;
|
|
396
|
+
if (m.to) perAgent[from].peers.add(m.to);
|
|
397
|
+
|
|
398
|
+
if (m.reply_to) {
|
|
399
|
+
for (let j = i - 1; j >= Math.max(0, i - 50); j--) {
|
|
400
|
+
if (history[j].id === m.reply_to) {
|
|
401
|
+
const delta = new Date(m.timestamp).getTime() - new Date(history[j].timestamp).getTime();
|
|
402
|
+
if (delta > 0 && delta < 3600000) perAgent[from].responseTimes.push(delta / 1000);
|
|
403
|
+
break;
|
|
404
|
+
}
|
|
405
|
+
}
|
|
406
|
+
}
|
|
407
|
+
}
|
|
408
|
+
|
|
409
|
+
const totalAgents = allAgentNames.size;
|
|
410
|
+
const maxMessages = Math.max(1, ...Object.values(perAgent).map(d => d.messages));
|
|
411
|
+
|
|
412
|
+
const result = {};
|
|
413
|
+
const scores = [];
|
|
414
|
+
|
|
415
|
+
for (const [name, data] of Object.entries(perAgent)) {
|
|
416
|
+
const avgResponseSec = data.responseTimes.length
|
|
417
|
+
? data.responseTimes.reduce((a, b) => a + b, 0) / data.responseTimes.length
|
|
418
|
+
: Infinity;
|
|
419
|
+
|
|
420
|
+
// Responsiveness (30 pts)
|
|
421
|
+
let responsiveness;
|
|
422
|
+
if (avgResponseSec < 10) responsiveness = 30;
|
|
423
|
+
else if (avgResponseSec < 30) responsiveness = 25;
|
|
424
|
+
else if (avgResponseSec < 60) responsiveness = 20;
|
|
425
|
+
else if (avgResponseSec < 120) responsiveness = 15;
|
|
426
|
+
else responsiveness = 10;
|
|
427
|
+
|
|
428
|
+
// Activity (30 pts) — linear scale relative to top agent
|
|
429
|
+
const activity = Math.round((data.messages / maxMessages) * 30);
|
|
430
|
+
|
|
431
|
+
// Reliability (20 pts) — uptime based on agent registration
|
|
432
|
+
let reliability = 10;
|
|
433
|
+
const agentInfo = agents[name];
|
|
434
|
+
if (agentInfo) {
|
|
435
|
+
const isAlive = agentInfo.pid ? isPidAlive(agentInfo.pid, agentInfo.last_activity) : false;
|
|
436
|
+
const registered = new Date(agentInfo.registered_at || agentInfo.last_activity).getTime();
|
|
437
|
+
const totalTime = Date.now() - registered;
|
|
438
|
+
if (totalTime > 0 && isAlive) {
|
|
439
|
+
const lastAct = new Date(agentInfo.last_activity).getTime();
|
|
440
|
+
const activeTime = lastAct - registered;
|
|
441
|
+
const uptime = Math.min(1, activeTime / totalTime);
|
|
442
|
+
if (uptime > 0.95) reliability = 20;
|
|
443
|
+
else if (uptime > 0.80) reliability = 15;
|
|
444
|
+
else if (uptime > 0.50) reliability = 10;
|
|
445
|
+
else reliability = 5;
|
|
446
|
+
} else if (!isAlive) {
|
|
447
|
+
reliability = 5;
|
|
448
|
+
}
|
|
449
|
+
}
|
|
450
|
+
|
|
451
|
+
// Collaboration (20 pts)
|
|
452
|
+
const collaboration = totalAgents > 1
|
|
453
|
+
? Math.round((data.peers.size / (totalAgents - 1)) * 20)
|
|
454
|
+
: 20;
|
|
455
|
+
|
|
456
|
+
const score = responsiveness + activity + reliability + collaboration;
|
|
457
|
+
result[name] = { score, responsiveness, activity, reliability, collaboration };
|
|
458
|
+
scores.push({ name, score });
|
|
459
|
+
}
|
|
460
|
+
|
|
461
|
+
// Add ranks
|
|
462
|
+
scores.sort((a, b) => b.score - a.score);
|
|
463
|
+
scores.forEach((s, i) => { result[s.name].rank = i + 1; });
|
|
464
|
+
|
|
465
|
+
return { agents: result };
|
|
466
|
+
}
|
|
467
|
+
|
|
468
|
+
// --- v3.4: Cross-Project Search ---
|
|
469
|
+
function apiSearchAll(query) {
|
|
470
|
+
const q = (query.get('q') || '').toLowerCase();
|
|
471
|
+
const limit = Math.min(parseInt(query.get('limit') || '50', 10), 200);
|
|
472
|
+
if (!q) return { error: 'Missing "q" parameter' };
|
|
473
|
+
|
|
474
|
+
const projects = getProjects();
|
|
475
|
+
// Add default project
|
|
476
|
+
const allProjects = [{ name: path.basename(process.cwd()), path: null }];
|
|
477
|
+
for (const p of projects) allProjects.push(p);
|
|
478
|
+
|
|
479
|
+
const results = [];
|
|
480
|
+
let total = 0;
|
|
481
|
+
|
|
482
|
+
for (const proj of allProjects) {
|
|
483
|
+
const history = readJsonl(filePath('history.jsonl', proj.path));
|
|
484
|
+
const matches = [];
|
|
485
|
+
for (const m of history) {
|
|
486
|
+
if (matches.length >= limit) break;
|
|
487
|
+
const content = (m.content || '').toLowerCase();
|
|
488
|
+
const from = (m.from || '').toLowerCase();
|
|
489
|
+
const to = (m.to || '').toLowerCase();
|
|
490
|
+
if (content.includes(q) || from.includes(q) || to.includes(q)) {
|
|
491
|
+
matches.push({ id: m.id, from: m.from, to: m.to, content: m.content, timestamp: m.timestamp });
|
|
492
|
+
}
|
|
493
|
+
}
|
|
494
|
+
if (matches.length > 0) {
|
|
495
|
+
results.push({ project: proj.name, path: proj.path || process.cwd(), messages: matches });
|
|
496
|
+
total += matches.length;
|
|
497
|
+
}
|
|
498
|
+
}
|
|
499
|
+
|
|
500
|
+
return { results, total };
|
|
501
|
+
}
|
|
502
|
+
|
|
503
|
+
// --- v3.4: Replay Export ---
|
|
504
|
+
function apiExportReplay(query) {
|
|
505
|
+
const projectPath = query.get('project') || null;
|
|
506
|
+
const history = readJsonl(filePath('history.jsonl', projectPath));
|
|
507
|
+
const profiles = readJson(filePath('profiles.json', projectPath));
|
|
508
|
+
|
|
509
|
+
const colors = ['#58a6ff','#3fb950','#d29922','#bc8cff','#f778ba','#ff7b72','#79c0ff','#7ee787'];
|
|
510
|
+
const agentColors = {};
|
|
511
|
+
let colorIdx = 0;
|
|
512
|
+
for (const m of history) {
|
|
513
|
+
if (!agentColors[m.from]) agentColors[m.from] = colors[colorIdx++ % colors.length];
|
|
514
|
+
}
|
|
515
|
+
|
|
516
|
+
const messagesJson = JSON.stringify(history.map(m => ({
|
|
517
|
+
from: m.from, to: m.to, content: m.content, timestamp: m.timestamp, color: agentColors[m.from] || '#58a6ff'
|
|
518
|
+
})));
|
|
519
|
+
|
|
520
|
+
return `<!DOCTYPE html>
|
|
521
|
+
<html lang="en"><head><meta charset="UTF-8"><meta name="viewport" content="width=device-width,initial-scale=1.0">
|
|
522
|
+
<title>Let Them Talk — Replay</title>
|
|
523
|
+
<style>
|
|
524
|
+
:root{--bg:#0d1117;--surface:#161b22;--surface-2:#21262d;--border:#30363d;--text:#e6edf3;--dim:#8b949e}
|
|
525
|
+
*{margin:0;padding:0;box-sizing:border-box}
|
|
526
|
+
body{font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',sans-serif;background:var(--bg);color:var(--text);line-height:1.6}
|
|
527
|
+
.header{background:var(--surface);border-bottom:1px solid var(--border);padding:12px 20px;display:flex;align-items:center;justify-content:space-between}
|
|
528
|
+
.title{font-size:16px;font-weight:700;color:var(--text)}
|
|
529
|
+
.controls{display:flex;gap:8px;align-items:center}
|
|
530
|
+
.controls button{background:var(--surface-2);color:var(--text);border:1px solid var(--border);border-radius:6px;padding:6px 14px;cursor:pointer;font-size:13px}
|
|
531
|
+
.controls button:hover{background:var(--border)}
|
|
532
|
+
.controls select{background:var(--surface-2);color:var(--text);border:1px solid var(--border);border-radius:6px;padding:4px 8px;font-size:13px}
|
|
533
|
+
.messages{max-width:800px;margin:20px auto;padding:0 16px}
|
|
534
|
+
.msg{opacity:0;transform:translateY(8px);transition:opacity 0.3s,transform 0.3s;margin-bottom:12px;padding:10px 14px;background:var(--surface);border:1px solid var(--border);border-radius:8px}
|
|
535
|
+
.msg.visible{opacity:1;transform:translateY(0)}
|
|
536
|
+
.msg-header{display:flex;gap:8px;align-items:baseline;margin-bottom:4px;font-size:13px}
|
|
537
|
+
.msg-from{font-weight:700}
|
|
538
|
+
.msg-to{color:var(--dim)}
|
|
539
|
+
.msg-time{color:var(--dim);margin-left:auto;font-size:11px}
|
|
540
|
+
.msg-content{font-size:14px;white-space:pre-wrap;word-break:break-word}
|
|
541
|
+
.msg-content code{background:var(--surface-2);padding:1px 5px;border-radius:3px;font-size:0.9em}
|
|
542
|
+
.msg-content strong{font-weight:700}
|
|
543
|
+
.progress{font-size:12px;color:var(--dim)}
|
|
544
|
+
</style></head><body>
|
|
545
|
+
<div class="header">
|
|
546
|
+
<span class="title">Let Them Talk — Replay</span>
|
|
547
|
+
<div class="controls">
|
|
548
|
+
<button id="btn" onclick="toggle()">Pause</button>
|
|
549
|
+
<label><span style="color:var(--dim);font-size:12px">Speed:</span>
|
|
550
|
+
<select id="speed" onchange="setSpeed(this.value)">
|
|
551
|
+
<option value="2000">Slow</option><option value="1000" selected>Normal</option><option value="500">Fast</option><option value="200">Very Fast</option>
|
|
552
|
+
</select></label>
|
|
553
|
+
<span class="progress" id="progress">0 / 0</span>
|
|
554
|
+
</div></div>
|
|
555
|
+
<div class="messages" id="messages"></div>
|
|
556
|
+
<script>
|
|
557
|
+
var msgs=${messagesJson};
|
|
558
|
+
var idx=0,playing=true,timer=null,speed=1000;
|
|
559
|
+
function md(s){return s.replace(/\`\`\`[\\s\\S]*?\`\`\`/g,function(m){return '<pre><code>'+m.slice(3,-3).replace(/^\\w*\\n/,'')+'</code></pre>'}).replace(/\`([^\`]+)\`/g,'<code>$1</code>').replace(/\\*\\*([^*]+)\\*\\*/g,'<strong>$1</strong>').replace(/^### (.+)$/gm,'<h4 style="margin:8px 0 4px;font-size:14px">$1</h4>').replace(/^## (.+)$/gm,'<h3 style="margin:8px 0 4px;font-size:15px">$1</h3>').replace(/^# (.+)$/gm,'<h2 style="margin:8px 0 4px;font-size:16px">$1</h2>')}
|
|
560
|
+
function esc(s){return s.replace(/&/g,'&').replace(/</g,'<').replace(/>/g,'>')}
|
|
561
|
+
function showNext(){if(idx>=msgs.length){playing=false;document.getElementById('btn').textContent='Done';return}
|
|
562
|
+
var m=msgs[idx],el=document.createElement('div');el.className='msg';
|
|
563
|
+
var t=new Date(m.timestamp);var time=t.toLocaleTimeString();
|
|
564
|
+
el.innerHTML='<div class="msg-header"><span class="msg-from" style="color:'+m.color+'">'+esc(m.from)+'</span><span class="msg-to">→ '+esc(m.to||'all')+'</span><span class="msg-time">'+time+'</span></div><div class="msg-content">'+md(esc(m.content))+'</div>';
|
|
565
|
+
document.getElementById('messages').appendChild(el);
|
|
566
|
+
requestAnimationFrame(function(){el.classList.add('visible')});
|
|
567
|
+
el.scrollIntoView({behavior:'smooth',block:'end'});
|
|
568
|
+
idx++;document.getElementById('progress').textContent=idx+' / '+msgs.length;
|
|
569
|
+
if(playing)timer=setTimeout(showNext,speed)}
|
|
570
|
+
function toggle(){if(idx>=msgs.length){idx=0;document.getElementById('messages').innerHTML='';playing=true;document.getElementById('btn').textContent='Pause';showNext();return}
|
|
571
|
+
playing=!playing;document.getElementById('btn').textContent=playing?'Pause':'Play';if(playing)showNext();else clearTimeout(timer)}
|
|
572
|
+
function setSpeed(v){speed=parseInt(v)}
|
|
573
|
+
showNext();
|
|
574
|
+
</script></body></html>`;
|
|
575
|
+
}
|
|
576
|
+
|
|
328
577
|
function apiReset(query) {
|
|
329
578
|
const projectPath = query.get('project') || null;
|
|
330
579
|
const dataDir = resolveDataDir(projectPath);
|
|
331
|
-
const fixedFiles = ['messages.jsonl', 'history.jsonl', 'agents.json', 'acks.json', 'tasks.json', 'profiles.json', 'workflows.json', 'branches.json', 'read_receipts.json', 'permissions.json'];
|
|
580
|
+
const fixedFiles = ['messages.jsonl', 'history.jsonl', 'agents.json', 'acks.json', 'tasks.json', 'profiles.json', 'workflows.json', 'branches.json', 'read_receipts.json', 'permissions.json', 'config.json'];
|
|
332
581
|
for (const f of fixedFiles) {
|
|
333
582
|
const p = path.join(dataDir, f);
|
|
334
583
|
if (fs.existsSync(p)) fs.unlinkSync(p);
|
|
@@ -1397,6 +1646,31 @@ const server = http.createServer(async (req, res) => {
|
|
|
1397
1646
|
res.writeHead(result.error ? 400 : 200, { 'Content-Type': 'application/json' });
|
|
1398
1647
|
res.end(JSON.stringify(result));
|
|
1399
1648
|
}
|
|
1649
|
+
// --- v3.4: Notifications ---
|
|
1650
|
+
else if (url.pathname === '/api/notifications' && req.method === 'GET') {
|
|
1651
|
+
res.writeHead(200, { 'Content-Type': 'application/json' });
|
|
1652
|
+
res.end(JSON.stringify(apiNotifications()));
|
|
1653
|
+
}
|
|
1654
|
+
// --- v3.4: Performance Scores ---
|
|
1655
|
+
else if (url.pathname === '/api/scores' && req.method === 'GET') {
|
|
1656
|
+
res.writeHead(200, { 'Content-Type': 'application/json' });
|
|
1657
|
+
res.end(JSON.stringify(apiScores(url.searchParams)));
|
|
1658
|
+
}
|
|
1659
|
+
// --- v3.4: Cross-Project Search ---
|
|
1660
|
+
else if (url.pathname === '/api/search-all' && req.method === 'GET') {
|
|
1661
|
+
const result = apiSearchAll(url.searchParams);
|
|
1662
|
+
res.writeHead(result.error ? 400 : 200, { 'Content-Type': 'application/json' });
|
|
1663
|
+
res.end(JSON.stringify(result));
|
|
1664
|
+
}
|
|
1665
|
+
// --- v3.4: Replay Export ---
|
|
1666
|
+
else if (url.pathname === '/api/export-replay' && req.method === 'GET') {
|
|
1667
|
+
const html = apiExportReplay(url.searchParams);
|
|
1668
|
+
res.writeHead(200, {
|
|
1669
|
+
'Content-Type': 'text/html; charset=utf-8',
|
|
1670
|
+
'Content-Disposition': 'attachment; filename="replay-' + new Date().toISOString().slice(0, 10) + '.html"',
|
|
1671
|
+
});
|
|
1672
|
+
res.end(html);
|
|
1673
|
+
}
|
|
1400
1674
|
// Server-Sent Events endpoint for real-time updates
|
|
1401
1675
|
else if (url.pathname === '/api/events' && req.method === 'GET') {
|
|
1402
1676
|
if (sseClients.size >= 100) {
|
|
@@ -1429,6 +1703,12 @@ const server = http.createServer(async (req, res) => {
|
|
|
1429
1703
|
const sseClients = new Set();
|
|
1430
1704
|
|
|
1431
1705
|
function sseNotifyAll() {
|
|
1706
|
+
// Generate notifications from agent state changes
|
|
1707
|
+
try {
|
|
1708
|
+
const agents = readJson(filePath('agents.json'));
|
|
1709
|
+
generateNotifications(agents);
|
|
1710
|
+
} catch {}
|
|
1711
|
+
|
|
1432
1712
|
for (const res of sseClients) {
|
|
1433
1713
|
try {
|
|
1434
1714
|
res.write(`data: update\n\n`);
|
|
@@ -1472,7 +1752,7 @@ server.listen(PORT, LAN_MODE ? '0.0.0.0' : '127.0.0.1', () => {
|
|
|
1472
1752
|
const dataDir = resolveDataDir();
|
|
1473
1753
|
const lanIP = getLanIP();
|
|
1474
1754
|
console.log('');
|
|
1475
|
-
console.log(' Let Them Talk - Agent Bridge Dashboard v3.
|
|
1755
|
+
console.log(' Let Them Talk - Agent Bridge Dashboard v3.5.1');
|
|
1476
1756
|
console.log(' ============================================');
|
|
1477
1757
|
console.log(' Dashboard: http://localhost:' + PORT);
|
|
1478
1758
|
if (LAN_MODE && lanIP) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "let-them-talk",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.5.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": {
|
|
@@ -44,7 +44,7 @@
|
|
|
44
44
|
"type": "git",
|
|
45
45
|
"url": "git+https://github.com/Dekelelz/let-them-talk.git"
|
|
46
46
|
},
|
|
47
|
-
"homepage": "https://
|
|
47
|
+
"homepage": "https://talk.unrealai.studio",
|
|
48
48
|
"bugs": {
|
|
49
49
|
"url": "https://github.com/Dekelelz/let-them-talk/issues"
|
|
50
50
|
},
|