let-them-talk 5.5.3 → 5.5.4

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 CHANGED
@@ -310,7 +310,7 @@ The verify suite doesn't claim to cover every provider or runtime matrix, and do
310
310
  - **Rate-limited** API endpoints on non-localhost requests.
311
311
  - **No telemetry, no cloud.** Everything runs locally.
312
312
  - **Obsidian-quality rich rendering** — GFM tables, fenced code with syntax highlighting (highlight.js), Obsidian-style callouts (`> [!NOTE]`, `> [!WARNING]`, `> [!SUMMARY]-` collapsible), Mermaid diagrams, KaTeX math, clickable image lightbox, copy-code buttons. Every shipping lib is bundled locally under `vendor/` so the dashboard works offline.
313
- - **0 known vulnerabilities** in the shipped tarball as of v5.5.3.
313
+ - **0 known vulnerabilities** in the shipped tarball as of v5.5.4.
314
314
  - **Sensitive-path blocks** on file-share: `.env`, `.pem`, `.key`, `.lan-token`, `mcp.json`, and the agent-bridge data directory cannot be shared.
315
315
  - See [`SECURITY.md`](SECURITY.md) for the disclosure policy.
316
316
 
package/USAGE.md CHANGED
@@ -1,6 +1,6 @@
1
1
  <!-- Generated from ../USAGE.md by scripts/sync-packaged-docs.js for published package consumers. -->
2
2
 
3
- # Let Them Talk Usage Guide v5.5.3
3
+ # Let Them Talk Usage Guide v5.5.4
4
4
 
5
5
  This guide is the short operator view of the current runtime. For normative architecture details, use the docs under `docs/architecture/`.
6
6
 
package/cli.js CHANGED
@@ -9,7 +9,7 @@ const { createCanonicalState } = require('./state/canonical');
9
9
 
10
10
  function printUsage() {
11
11
  console.log(`
12
- Let Them Talk — Agent Bridge v5.5.3
12
+ Let Them Talk — Agent Bridge v5.5.4
13
13
  MCP message broker for inter-agent communication
14
14
  Supports: Claude Code, Gemini CLI, Codex CLI, Ollama
15
15
 
package/dashboard.js CHANGED
@@ -3445,7 +3445,7 @@ server.listen(PORT, LAN_MODE ? '0.0.0.0' : '127.0.0.1', () => {
3445
3445
  const dataDir = resolveDataDir();
3446
3446
  const lanIP = getLanIP();
3447
3447
  console.log('');
3448
- console.log(' Let Them Talk - Agent Bridge Dashboard v5.5.3');
3448
+ console.log(' Let Them Talk - Agent Bridge Dashboard v5.5.4');
3449
3449
  console.log(' ============================================');
3450
3450
  console.log(' Dashboard: http://localhost:' + PORT);
3451
3451
  if (LAN_MODE && lanIP) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "let-them-talk",
3
- "version": "5.5.3",
3
+ "version": "5.5.4",
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": {
@@ -65,13 +65,27 @@ function repairBranch(branchDir, opts) {
65
65
 
66
66
  const kept = [];
67
67
  const orphans = [];
68
+ const duplicateRedactions = [];
69
+ const seenRedactedIds = new Set();
68
70
  for (const ev of events) {
69
71
  if (ev && (ev.type === 'message.redacted' || ev.type === 'message.corrected')) {
70
72
  const msgId = ev.payload && ev.payload.message_id;
73
+ // Orphan: no corresponding message.sent ancestor.
71
74
  if (msgId && !sentIds.has(msgId)) {
72
75
  orphans.push(ev);
73
76
  continue;
74
77
  }
78
+ // Duplicate redaction: same message_id already redacted earlier in the
79
+ // stream. Keep the first, drop subsequent ones. Pre-v5.5.4 the replay
80
+ // threw on the second redaction; now it tolerates duplicates, but we
81
+ // still want to prune the log so it's clean.
82
+ if (ev.type === 'message.redacted' && msgId) {
83
+ if (seenRedactedIds.has(msgId)) {
84
+ duplicateRedactions.push(ev);
85
+ continue;
86
+ }
87
+ seenRedactedIds.add(msgId);
88
+ }
75
89
  }
76
90
  kept.push(ev);
77
91
  }
@@ -82,6 +96,7 @@ function repairBranch(branchDir, opts) {
82
96
  message_sent_events: sentIds.size,
83
97
  orphan_redacted: orphans.filter((o) => o.type === 'message.redacted').length,
84
98
  orphan_corrected: orphans.filter((o) => o.type === 'message.corrected').length,
99
+ duplicate_redacted: duplicateRedactions.length,
85
100
  kept_events: kept.length,
86
101
  };
87
102
 
@@ -90,9 +105,9 @@ function repairBranch(branchDir, opts) {
90
105
  return result;
91
106
  }
92
107
 
93
- if (orphans.length === 0) {
108
+ if (orphans.length === 0 && duplicateRedactions.length === 0) {
94
109
  result.skipped = true;
95
- result.reason = 'no orphan events';
110
+ result.reason = 'no orphan or duplicate events';
96
111
  return result;
97
112
  }
98
113
 
@@ -151,13 +166,14 @@ function main(argv) {
151
166
  console.log(' skipped — ' + r.reason);
152
167
  } else {
153
168
  console.log(` ${r.total_events} total events, ${r.message_sent_events} sent messages`);
154
- console.log(` orphan redactions: ${r.orphan_redacted}, orphan corrections: ${r.orphan_corrected}`);
169
+ console.log(` orphan redactions: ${r.orphan_redacted}, orphan corrections: ${r.orphan_corrected}, duplicate redactions: ${r.duplicate_redacted}`);
155
170
  if (!dryRun) {
156
171
  console.log(' [ok] rewrote events.jsonl (' + r.kept_events + ' events kept)');
157
172
  console.log(' [ok] backup: ' + r.backup);
158
173
  console.log(' [ok] projections cleared — will rebuild on next read');
159
174
  } else {
160
- console.log(' [dry-run] would drop ' + (r.orphan_redacted + r.orphan_corrected) + ' orphan event(s) and back up the original');
175
+ const drops = r.orphan_redacted + r.orphan_corrected + r.duplicate_redacted;
176
+ console.log(' [dry-run] would drop ' + drops + ' bad event(s) and back up the original');
161
177
  }
162
178
  }
163
179
  }
package/server.js CHANGED
@@ -3708,7 +3708,7 @@ function buildListenGroupResponse(batch, consumed, agentName, listenStart) {
3708
3708
  return new Date(a.timestamp) - new Date(b.timestamp);
3709
3709
  });
3710
3710
 
3711
- // LEAN RESPONSE (v5.5.3+): the agent already has every prior message in its
3711
+ // LEAN RESPONSE (v5.5.4+): the agent already has every prior message in its
3712
3712
  // own LLM context, plus the full rule set from get_guide() + AGENTS.md. We
3713
3713
  // only send the NEW messages + the managed-mode signals needed for
3714
3714
  // turn-taking. No repeated reminders, no agent rosters, no "next_action"
@@ -8136,7 +8136,7 @@ function toolToggleRule(ruleId) {
8136
8136
  // --- MCP Server setup ---
8137
8137
 
8138
8138
  const server = new Server(
8139
- { name: 'agent-bridge', version: '5.5.3' },
8139
+ { name: 'agent-bridge', version: '5.5.4' },
8140
8140
  { capabilities: { tools: {} } }
8141
8141
  );
8142
8142
 
@@ -9265,7 +9265,7 @@ async function main() {
9265
9265
  try {
9266
9266
  const transport = new StdioServerTransport();
9267
9267
  await server.connect(transport);
9268
- console.error('Agent Bridge MCP server v5.5.3 running (65 tools)');
9268
+ console.error('Agent Bridge MCP server v5.5.4 running (65 tools)');
9269
9269
  } catch (e) {
9270
9270
  console.error('ERROR: MCP server failed to start: ' + e.message);
9271
9271
  console.error('Fix: Run "npx let-them-talk doctor" to check your setup.');
package/state/messages.js CHANGED
@@ -397,18 +397,15 @@ function createMessagesState(options = {}) {
397
397
  case 'message.redacted': {
398
398
  const redaction = validateCanonicalMessageRedactionPayload(event);
399
399
  const record = findProjectedMessageRecord(projection, redaction.messageId);
400
- if (!record) {
401
- throw createCanonicalReplayError(
402
- CANONICAL_REPLAY_ERROR_CODES.INVALID_SEQUENCE,
403
- `Canonical message replay cannot apply ${describeReplayEvent(event)} because message ${redaction.messageId} does not exist in the current branch projection.`,
404
- {
405
- event_type: event.type,
406
- seq: event.seq,
407
- branch_id: event.branch_id,
408
- message_id: redaction.messageId,
409
- }
410
- );
411
- }
400
+ // Redaction is idempotent: if the message is already gone from the
401
+ // projection (e.g. a prior message.redacted for the same id already
402
+ // ran during this replay), the second redaction is a no-op rather
403
+ // than a fatal error. The canonical log can legitimately carry
404
+ // multiple redaction events per id — operators running Clear
405
+ // Messages repeatedly on the same branch would produce that shape,
406
+ // and aborting the whole replay over it is worse than ignoring the
407
+ // duplicate.
408
+ if (!record) return projection;
412
409
 
413
410
  if (record.messageIndex >= 0) {
414
411
  record.conversation.messages.splice(record.messageIndex, 1);