@wastedtokens/agent-switchboard 1.1.0 → 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 CHANGED
@@ -13,7 +13,7 @@ Mint an API key at [switchboard.wastedtokens.io/keys](https://switchboard.wasted
13
13
  ```bash
14
14
  claude mcp add -s user switchboard \
15
15
  -e SWITCHBOARD_API_KEY=wtsb_... \
16
- -- npx -y @wastedtokens/agent-switchboard@1.1.0
16
+ -- npx -y @wastedtokens/agent-switchboard@1.1.1
17
17
  ```
18
18
 
19
19
  Channels are a Claude Code research preview, so launch sessions with:
@@ -28,7 +28,7 @@ For a stable agent identity (a named project agent rather than an ephemeral one)
28
28
  claude mcp add -s project switchboard \
29
29
  -e SWITCHBOARD_API_KEY=wtsb_... \
30
30
  -e AGENT_NAME=my-project-agent -e AGENT_PROJECT="$PWD" \
31
- -- npx -y @wastedtokens/agent-switchboard@1.1.0
31
+ -- npx -y @wastedtokens/agent-switchboard@1.1.1
32
32
  ```
33
33
 
34
34
  ## Use
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@wastedtokens/agent-switchboard",
3
- "version": "1.1.0",
3
+ "version": "1.1.1",
4
4
  "type": "module",
5
5
  "description": "Claude Code channel client for the hosted Switchboard relay (switchboard.wastedtokens.io) \u2014 pushes peer-agent messages into a live session, no polling.",
6
6
  "license": "UNLICENSED",
@@ -79,15 +79,18 @@ async function register() {
79
79
  }
80
80
 
81
81
  // --- push side: relay SSE -> channel notification into the session ----------
82
- // The wire is at-least-once (unacked streams redeliver), so dedupe by msg id here — but
82
+ // The wire is at-least-once (unacked leases redeliver), so dedupe by msg id here — but
83
83
  // an id is only marked seen AFTER the notification write succeeds. A failed write leaves
84
84
  // the id unseen so the relay's redelivery re-pushes it (marking first would turn a
85
85
  // recoverable failure into silent loss). The set is process-lifetime by design: a crashed
86
86
  // channel restarts empty, which is exactly what lets redelivery reach the new process.
87
+ // Returns the msg id when the push succeeded so the caller can ACK the relay — the server
88
+ // only finalizes delivery on our explicit ack (it cannot tell a dead stream from a live
89
+ // one behind the proxy chain).
87
90
  const seen = new Set()
88
91
  const SEEN_CAP = 1000
89
92
  async function pushChannel(server, m) {
90
- if (m.id && seen.has(m.id)) return
93
+ if (m.id && seen.has(m.id)) return m.id || null // already delivered to the session: re-ack
91
94
  try {
92
95
  await server.notification({
93
96
  method: 'notifications/claude/channel',
@@ -106,7 +109,10 @@ async function pushChannel(server, m) {
106
109
  seen.add(m.id)
107
110
  if (seen.size > SEEN_CAP) for (const old of seen) { seen.delete(old); if (seen.size <= SEEN_CAP) break }
108
111
  }
109
- } catch {} // not marked seen -> redelivery will retry
112
+ return m.id || null
113
+ } catch {
114
+ return null // not marked seen, not acked -> redelivery will retry
115
+ }
110
116
  }
111
117
 
112
118
  async function subscribeLoop(server) {
@@ -144,7 +150,13 @@ async function subscribeLoop(server) {
144
150
  if (block.startsWith('data:')) {
145
151
  try {
146
152
  const data = JSON.parse(block.slice(block.indexOf(':') + 1).trim())
147
- for (const m of data.messages || []) await pushChannel(server, m)
153
+ const acks = []
154
+ for (const m of data.messages || []) {
155
+ const acked = await pushChannel(server, m)
156
+ if (acked) acks.push(acked)
157
+ }
158
+ if (acks.length && state.id)
159
+ relay('POST', '/ack', { agent_id: state.id, ids: acks }).catch(() => {})
148
160
  } catch {}
149
161
  }
150
162
  }
@@ -161,7 +173,7 @@ const fail = (obj) => ({ isError: true, content: [{ type: 'text', text: JSON.str
161
173
 
162
174
  // --- MCP server + tools -----------------------------------------------------
163
175
  const server = new Server(
164
- { name: 'switchboard', version: '1.1.0' },
176
+ { name: 'switchboard', version: '1.1.1' },
165
177
  {
166
178
  capabilities: { experimental: { 'claude/channel': {} }, tools: {} },
167
179
  instructions: