vibedate 0.7.1 → 0.8.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/dist/index.d.ts CHANGED
@@ -1,243 +1,9 @@
1
- import { VibeEvent, UsageSnapshot, UsageSource, Harness, HarnessUsageOptions } from '@pooriaarab/vibe-core';
1
+ import { UsageSnapshot, UsageSource, Harness, HarnessUsageOptions } from '@pooriaarab/vibe-core';
2
2
  export { Harness, UsageSnapshot, UsageSource, createConsentLedger } from '@pooriaarab/vibe-core';
3
+ import { P as PeerHello, a as PeerLink } from './room-BStsMaeT.js';
4
+ export { D as DiscoveryOptions, b as DiscoverySession, L as LIVE_NOTICE, R as ROOM_TOPIC_PREFIX, c as RoomMember, d as RoomMessage, e as RoomOptions, f as RoomSession, S as StoredPeer, T as TOPIC_PREFIX, l as leagueTopic, g as loadPeers, p as parseHandshake, r as recordPeer, h as recordPeerMessage, i as roomTopic, s as serializeHandshake, j as startDiscovery, k as startRoom } from './room-BStsMaeT.js';
3
5
  import { KeyObject } from 'node:crypto';
4
6
 
5
- type Frame = {
6
- t: 'hello';
7
- handle: string;
8
- league: string;
9
- harness: string;
10
- verified?: boolean;
11
- pubkey?: string;
12
- nonce?: string;
13
- sig?: string;
14
- } | {
15
- t: 'msg';
16
- id: string;
17
- text: string;
18
- at: number;
19
- } | {
20
- t: 'typing';
21
- } | {
22
- t: 'bye';
23
- } | {
24
- t: 'media-start';
25
- id: string;
26
- mime: string;
27
- size: number;
28
- name: string;
29
- } | {
30
- t: 'media-chunk';
31
- id: string;
32
- seq: number;
33
- b64: string;
34
- } | {
35
- t: 'media-end';
36
- id: string;
37
- } | {
38
- t: 'rtc-offer';
39
- sdp: string;
40
- } | {
41
- t: 'rtc-answer';
42
- sdp: string;
43
- } | {
44
- t: 'rtc-ice';
45
- candidate: string;
46
- };
47
- /** Convenience union of the three WebRTC signaling frame types (offer / answer
48
- * / ice). Live A/V runs in the BROWSER via a native RTCPeerConnection; these
49
- * frames only RELAY signaling over the P2P socket — no media bytes, no native
50
- * WebRTC dependency in the CLI. */
51
- type RtcFrame = Extract<Frame, {
52
- t: `rtc-${string}`;
53
- }>;
54
-
55
- interface ReceivedMedia {
56
- readonly mime: string;
57
- readonly name: string;
58
- /** Temp file path holding the reassembled bytes. */
59
- readonly path: string;
60
- readonly size: number;
61
- }
62
-
63
- interface PeerLink {
64
- /** The validated identity of the remote peer (from the hello handshake). */
65
- readonly hello: PeerHello;
66
- /** Send a line of text as a `msg` frame. */
67
- send(text: string): void;
68
- /** Read a file from disk and send it as a chunked media transfer. */
69
- sendMedia(filePath: string, opts?: {
70
- mime?: string;
71
- name?: string;
72
- }): Promise<{
73
- id: string;
74
- size: number;
75
- }>;
76
- /** Relay one `rtc-*` signaling frame (offer / answer / ice) to the peer.
77
- * Live media never touches this socket — only SDP / ICE strings do. */
78
- sendSignal(frame: RtcFrame): void;
79
- /** Register a callback for each incoming `msg` frame. */
80
- onMessage(cb: (m: {
81
- id: string;
82
- text: string;
83
- at: number;
84
- }) => void): void;
85
- /** Register a callback fired for each fully-reassembled incoming media file. */
86
- onMedia(cb: (m: ReceivedMedia) => void): void;
87
- /** Register a callback fired for each incoming `rtc-*` signaling frame. */
88
- onSignal(cb: (f: RtcFrame) => void): void;
89
- /** Register a callback fired once when the peer closes the link. */
90
- onClose(cb: () => void): void;
91
- /** Omegle "next": write a `bye` frame, then end the socket. */
92
- close(): void;
93
- }
94
-
95
- /** Namespace prefix so vibedating topics never collide with other DHT traffic. */
96
- declare const TOPIC_PREFIX = "vibedate:";
97
- /**
98
- * Derive the 32-byte DHT topic for a league bucket. Deterministic: everyone in
99
- * the same league anywhere in the world hashes to the same topic, which is the
100
- * entire discovery mechanism. Pure.
101
- */
102
- declare function leagueTopic(leagueName: string): Buffer;
103
- /**
104
- * The fields that ever leave the machine over a peer connection: handle, league,
105
- * harness, and (optionally) the self-asserted usage-verification flag plus the
106
- * identity proof (pubkey/nonce/sig). NEVER raw usage — no token totals, no logs.
107
- * `verified`/`pubkey` are undefined for legacy peers that predate them; both
108
- * `undefined` and `false` display as unverified (~).
109
- */
110
- interface PeerHello {
111
- readonly handle: string;
112
- readonly league: string;
113
- readonly harness: string;
114
- /**
115
- * Self-asserted: the sender's usage came from real local logs (see readUsage).
116
- * Bound to the sender's key by the identity signature when `pubkey` is present.
117
- */
118
- readonly verified?: boolean;
119
- /** Raw ed25519 public key (64 hex) — the persistent identity this hello signs. */
120
- readonly pubkey?: string;
121
- /** Random per-hello nonce (hex) covered by the signature. */
122
- readonly nonce?: string;
123
- /** ed25519 signature (128 hex) over `handle|league|harness|verified|nonce`. */
124
- readonly sig?: string;
125
- /**
126
- * LOCAL-DERIVED, never on the wire: true when this hello's signature verified
127
- * against its pubkey (see classifyHelloIdentity). Marked 🔑 in the UI.
128
- */
129
- readonly identityVerified?: boolean;
130
- }
131
- /** One-line privacy notice printed before joining the swarm. */
132
- declare const LIVE_NOTICE = "live discovery: sharing only your handle + league + harness + verified flag + identity pubkey (never raw usage) with same-league peers on the public DHT";
133
- /**
134
- * Serialize a hello to the single JSON line sent on connect. Built key-by-key
135
- * from the allowlist — even if a caller sneaks extra properties onto the
136
- * object, they cannot leak into the wire format.
137
- */
138
- declare function serializeHandshake(hello: PeerHello): string;
139
- /**
140
- * Parse one incoming handshake line. Returns `null` for anything malformed
141
- * (bad JSON, non-object, missing/oversized handle or league). The result is
142
- * constructed from an allowlist of keys, so any extra fields a peer sends —
143
- * in particular any raw-usage field — are ignored and never retained.
144
- */
145
- declare function parseHandshake(raw: string | Buffer): PeerHello | null;
146
- /** A peer we've shaken hands with, persisted locally. */
147
- interface StoredPeer extends PeerHello {
148
- readonly firstSeenAt: string;
149
- readonly lastSeenAt: string;
150
- /** LOCAL metadata: when the last `msg` from this peer arrived (never on the wire). */
151
- readonly lastMessageAt?: string;
152
- }
153
- /** Load persisted live peers, or `[]` if none/corrupt. Local-only data. */
154
- declare function loadPeers(dir?: string): StoredPeer[];
155
- /**
156
- * Record a successfully handshaken peer, keyed by handle (a peer may reconnect
157
- * from a different key). Returns whether this handle is NEW (first time seen).
158
- */
159
- declare function recordPeer(hello: PeerHello, dir?: string, now?: Date): {
160
- peer: StoredPeer;
161
- isNew: boolean;
162
- };
163
- /**
164
- * Stamp `lastMessageAt` on a stored peer (a `msg` just arrived from them).
165
- * Local metadata only; never on the wire. Returns false when the handle isn't
166
- * a known peer. Never throws — best-effort bookkeeping.
167
- */
168
- declare function recordPeerMessage(handle: string, dir?: string, now?: Date): boolean;
169
- /** Injection point for the match notification (defaults to vibe-core notify). */
170
- type NotifySink = (event: VibeEvent) => void;
171
- interface DiscoveryOptions {
172
- /** What we broadcast. Must already be consent-gated by the caller. */
173
- readonly hello: PeerHello;
174
- /**
175
- * Override the joined topic (tests pass a random one on an isolated DHT).
176
- * Defaults to {@link leagueTopic}`(hello.league)`. Ignored when {@link topics}
177
- * is set.
178
- */
179
- readonly topic?: Buffer;
180
- /**
181
- * ALL topics to join on the one swarm (e.g. your league + adjacent leagues),
182
- * so thin pools and cross-league friends still connect. Every topic is
183
- * joined, refreshed, and left on close. Defaults to `[topic]` — i.e. a single
184
- * own-league topic (the legacy behavior).
185
- */
186
- readonly topics?: readonly Buffer[];
187
- /**
188
- * Predicate over an incoming peer's advertised league. Defaults to EXACT
189
- * match against `hello.league` — the same privacy invariant as before. Widen
190
- * it (e.g. ±1 adjacency via {@link leaguesWithin}) to accept cross-league
191
- * peers that arrive on a shared topic.
192
- */
193
- readonly acceptLeague?: (peerLeague: string) => boolean;
194
- /**
195
- * Predicate over an incoming peer's advertised handle. A blocked peer's hello
196
- * is DROPPED exactly like a wrong-league one — never recorded to peers.json,
197
- * never notified, never handed to `onLink`/pairing. Default: nothing blocked.
198
- * The CLI passes one backed by the persisted blocklist (~/.vibedating).
199
- */
200
- readonly isBlocked?: (handle: string) => boolean;
201
- /** DHT bootstrap nodes; omit for the public DHT. Tests pass a local testnet. */
202
- readonly bootstrap?: ReadonlyArray<{
203
- readonly host: string;
204
- readonly port: number;
205
- }>;
206
- /** Where peers.json lives. Defaults to ~/.vibedating. */
207
- readonly stateDir?: string;
208
- /** Called after each accepted handshake; `isNew` = first time this handle is seen. */
209
- readonly onPeer?: (peer: PeerHello, isNew: boolean) => void;
210
- /**
211
- * Called once per connection with a live {@link PeerLink} over the same socket
212
- * (the hello was frame #1; subsequent frames flow to the link). Omit for the
213
- * plain `discover` behavior (no live chat). Existing discovery behavior is
214
- * unchanged when this is absent.
215
- */
216
- readonly onLink?: (link: PeerLink) => void;
217
- /** Match-notification sink (tests capture with a fake). Best-effort. */
218
- readonly notify?: NotifySink;
219
- }
220
- interface DiscoverySession {
221
- /** The primary (first) joined topic. See {@link topics} for the full set. */
222
- readonly topic: Buffer;
223
- /** Every topic this session joined (primary first). */
224
- readonly topics: readonly Buffer[];
225
- /** What we broadcast on every connection. */
226
- readonly hello: PeerHello;
227
- /** Live peer set, keyed by the remote's public key (hex). */
228
- readonly peers: ReadonlyMap<string, PeerHello>;
229
- /** Resolves when the first DHT announce/lookup round for every topic completes. */
230
- readonly ready: Promise<unknown>;
231
- /** Leave every topic and destroy the node. Idempotent. */
232
- close(): Promise<void>;
233
- }
234
- /**
235
- * Join the swarm on the league topic and handshake with every peer that
236
- * connects. CONSENT GATE LIVES WITH THE CALLER — never call this without the
237
- * `share:live` grant (or an explicit `--live` opt-in in the same breath).
238
- */
239
- declare function startDiscovery(opts: DiscoveryOptions): Promise<DiscoverySession>;
240
-
241
7
  /**
242
8
  * A Nostr event, reduced to the fields this module touches. Structurally
243
9
  * compatible with `nostr-tools`'s `Event`, so a finalized/verified event can be
@@ -351,87 +117,6 @@ declare function createNostrRelayLink(opts: CreateNostrRelayLinkOptions): Promis
351
117
  */
352
118
  declare function createNostrPoolTransport(urls?: readonly string[]): Promise<RelayTransport>;
353
119
 
354
- /** Namespace prefix so room topics never collide with league topics (or anything
355
- * else on the DHT). Mirrors {@link p2p.TOPIC_PREFIX} for the 1:1 path. */
356
- declare const ROOM_TOPIC_PREFIX = "vibedate-room:";
357
- /**
358
- * Derive the 32-byte DHT topic for a named room. Deterministic: everyone who
359
- * joins the same room name anywhere in the world hashes to the same topic,
360
- * which is the entire discovery mechanism. Pure (mirrors {@link p2p.leagueTopic}).
361
- */
362
- declare function roomTopic(name: string): Buffer;
363
- /** A room member = a connected, handshaken peer. Same shape as a live peer. */
364
- type RoomMember = PeerHello;
365
- /** One group chat message: a `msg` frame's payload tagged with the sender. */
366
- interface RoomMessage {
367
- /** Sender's handle (from the validated hello — UNTRUSTED display data). */
368
- readonly from: string;
369
- readonly id: string;
370
- readonly text: string;
371
- readonly at: number;
372
- }
373
- interface RoomOptions {
374
- /** What we broadcast. Must already be consent-gated by the caller. */
375
- readonly hello: PeerHello;
376
- /** Room name → its own DHT topic (see {@link roomTopic}). */
377
- readonly room: string;
378
- /** DHT bootstrap nodes; omit for the public DHT. Tests pass a local testnet. */
379
- readonly bootstrap?: ReadonlyArray<{
380
- readonly host: string;
381
- readonly port: number;
382
- }>;
383
- /** Where peers.json lives. Defaults to ~/.vibedating. */
384
- readonly stateDir?: string;
385
- /** Predicate over a blocked handle — a blocked peer's hello is dropped exactly
386
- * like in 1:1 discovery. Default: nothing blocked. */
387
- readonly isBlocked?: (handle: string) => boolean;
388
- /** Match-notification sink (tests capture with a fake). Best-effort. */
389
- readonly notify?: NotifySink;
390
- }
391
- interface RoomSession {
392
- /** The room name. */
393
- readonly room: string;
394
- /** The joined DHT topic (see {@link roomTopic}). */
395
- readonly topic: Buffer;
396
- /** What we broadcast. */
397
- readonly hello: PeerHello;
398
- /** Live member set, keyed by handle (excludes self). Mirrors the live view
399
- * semantics of {@link p2p.DiscoverySession.peers}. */
400
- readonly members: ReadonlyMap<string, RoomMember>;
401
- /** Resolves when the first DHT announce/lookup round completes. */
402
- readonly ready: Promise<unknown>;
403
- /**
404
- * Broadcast a text message to ALL room members (fan-out: one `msg` frame per
405
- * member's {@link PeerLink}). Returns the handles the message was sent to.
406
- * Best-effort: a member whose link has just closed is skipped silently.
407
- */
408
- broadcast(text: string): readonly string[];
409
- /** Register a callback fired for each incoming group message (with sender). */
410
- onMessage(cb: (m: RoomMessage) => void): void;
411
- /** Register a callback fired whenever the member roster changes (join/leave). */
412
- onRoster(cb: (members: readonly RoomMember[]) => void): void;
413
- /** Register a callback fired for each incoming `rtc-*` signaling frame,
414
- * tagged with the sender's handle (full-mesh video signaling). */
415
- onSignal(cb: (from: string, frame: RtcFrame) => void): void;
416
- /** Relay one `rtc-*` signaling frame to one member (by handle). */
417
- sendSignal(handle: string, frame: RtcFrame): void;
418
- /** The underlying {@link PeerLink} to a member (by handle), or undefined. */
419
- linkFor(handle: string): PeerLink | undefined;
420
- /** Leave the room and destroy the node. Idempotent. */
421
- close(): Promise<void>;
422
- }
423
- /**
424
- * Join (or create) a named room on the DHT and discover ALL members. CONSENT
425
- * GATE LIVES WITH THE CALLER — never call this without the `share:live` grant
426
- * (or an explicit opt-in in the same breath), exactly like
427
- * {@link p2p.startDiscovery}.
428
- *
429
- * Resolves once the first DHT announce/lookup round completes; the returned
430
- * session's {@link RoomSession.members} map + {@link RoomSession.onRoster}
431
- * callback track every member that joins or leaves thereafter.
432
- */
433
- declare function startRoom(opts: RoomOptions): Promise<RoomSession>;
434
-
435
120
  /**
436
121
  * Persistent ed25519 identity — binds a handle to a keypair so a peer cannot
437
122
  * impersonate it.
@@ -639,4 +324,4 @@ declare const CANDIDATES: readonly Candidate[];
639
324
  */
640
325
  declare function matches(myLeague: string, candidates?: readonly Candidate[]): Candidate[];
641
326
 
642
- export { BELOW_LEAGUE, CANDIDATES, type Candidate, type CreateNostrRelayLinkOptions, DEFAULT_RELAYS, DEMO_TOTAL_TOKENS, type DiscoveryOptions, type DiscoverySession, type HelloClaims, type Identity, type IdentityProof, type IdentityVerdict, LEAGUES, LIVE_NOTICE, type League, type LocalUsageSnapshot, type NostrKey, type NostrRelayLink, type PeerHello, ROOM_TOPIC_PREFIX, type RelayEvent, type RelayFilter, type RelayTransport, type RoomMember, type RoomMessage, type RoomOptions, type RoomSession, type StoredPeer, TOKENS_ENV, TOPIC_PREFIX, VIBEDATE_MESSAGE_KIND, VIBEDATE_PRESENCE_KIND, allLeagueNames, canonicalHelloClaims, classifyHelloIdentity, conversationTag, createNostrPoolTransport, createNostrRelayLink, league, leagueIndex, leagueTopic, leaguesWithin, loadOrCreateIdentity, loadOrCreateNostrKey, loadPeers, matches, parseHandshake, parseTokensEnv, readUsage, recordPeer, recordPeerMessage, roomTopic, serializeHandshake, signHelloClaims, startDiscovery, startRoom, verifyHelloClaims };
327
+ export { BELOW_LEAGUE, CANDIDATES, type Candidate, type CreateNostrRelayLinkOptions, DEFAULT_RELAYS, DEMO_TOTAL_TOKENS, type HelloClaims, type Identity, type IdentityProof, type IdentityVerdict, LEAGUES, type League, type LocalUsageSnapshot, type NostrKey, type NostrRelayLink, PeerHello, type RelayEvent, type RelayFilter, type RelayTransport, TOKENS_ENV, VIBEDATE_MESSAGE_KIND, VIBEDATE_PRESENCE_KIND, allLeagueNames, canonicalHelloClaims, classifyHelloIdentity, conversationTag, createNostrPoolTransport, createNostrRelayLink, league, leagueIndex, leaguesWithin, loadOrCreateIdentity, loadOrCreateNostrKey, matches, parseTokensEnv, readUsage, signHelloClaims, verifyHelloClaims };
package/dist/index.js CHANGED
@@ -36,7 +36,7 @@ import {
36
36
  startDiscovery,
37
37
  startRoom,
38
38
  verifyHelloClaims
39
- } from "./chunk-HDHJLZZG.js";
39
+ } from "./chunk-S7MO5OSO.js";
40
40
  export {
41
41
  BELOW_LEAGUE,
42
42
  CANDIDATES,
package/dist/mcp.d.ts CHANGED
@@ -1,7 +1,187 @@
1
+ import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
2
+ import { a as PeerLink, P as PeerHello, f as RoomSession, b as DiscoverySession, d as RoomMessage } from './room-BStsMaeT.js';
3
+ import '@pooriaarab/vibe-core';
4
+
5
+ /**
6
+ * Pairing policy for the live layer — pure, over an injected set of links.
7
+ *
8
+ * Two modes share one policy object:
9
+ *
10
+ * - Omegle: links arrive (`add`) and are auto-paired one at a time; `next()`
11
+ * closes the current match and rolls to the next waiting link (or idles).
12
+ * - Dating: `open(handle)` picks the specific waiting link whose peer
13
+ * advertised that handle, closing any current match first.
14
+ *
15
+ * This module knows nothing about hyperswarm, the DHT, or the wire — it only
16
+ * shuffles {@link PeerLink}s handed to it. That keeps it trivially unit-testable
17
+ * with fakes and keeps the policy out of the transport.
18
+ *
19
+ * Remote hang-ups are handled too: when the matched peer "next"s us, the link's
20
+ * onClose fires and we auto-pair the next waiting link (omegle stays live).
21
+ *
22
+ * MESSAGE ROUTING (the correctness bit): `onMessage` is bound ONCE per link in
23
+ * {@link LivePairing.add} — never re-bound on match. A message from the current
24
+ * peer is delivered live; a message from a NON-current (queued) peer is BUFFERED
25
+ * (never dropped) and a queued-count notice fires, then flushed when that peer
26
+ * becomes current. Binding once per link means there is exactly one handler per
27
+ * link: no accumulation (no duplicate delivery) and no silent drops.
28
+ */
29
+
30
+ /** A chat message received from a peer. Mirrors PeerLink.onMessage's payload. */
31
+ interface IncomingMessage {
32
+ readonly id: string;
33
+ readonly text: string;
34
+ readonly at: number;
35
+ }
36
+ /**
37
+ * A drained message tagged with its sender's handle — for PULL-based consumers
38
+ * (the MCP `live_poll` tool) that read every inbound message since the last
39
+ * poll, current or queued, without registering a push callback.
40
+ */
41
+ interface PairingMessage {
42
+ readonly from: string;
43
+ readonly id: string;
44
+ readonly text: string;
45
+ readonly at: number;
46
+ /** True if this arrived from a NON-current (queued) peer at receive time. */
47
+ readonly queued: boolean;
48
+ }
49
+ interface LivePairing {
50
+ /** Number of unmatched links waiting in the queue. */
51
+ readonly available: number;
52
+ /** The currently-matched link, or `undefined` when idle. */
53
+ current(): PeerLink | undefined;
54
+ /**
55
+ * Omegle "next": close the current match and advance to the next waiting link
56
+ * (auto-pair), or go idle if the queue is empty. Returns the new current link.
57
+ */
58
+ next(): PeerLink | undefined;
59
+ /**
60
+ * Dating pick: match the available link whose `hello.handle === handle`.
61
+ * Closes the current match first. Returns the matched link, or `undefined`.
62
+ */
63
+ open(handle: string): PeerLink | undefined;
64
+ /** Add a newly-arrived link (fed from discovery's `onLink`). Auto-pairs if idle. */
65
+ add(link: PeerLink): void;
66
+ /** Register a callback fired whenever the current match changes (incl. → idle). */
67
+ onMatch(cb: (link: PeerLink | undefined) => void): void;
68
+ /**
69
+ * Register a callback fired for each message from the CURRENT peer — including
70
+ * buffered messages flushed when a peer becomes current. `from` is the sender's
71
+ * handle. Registered on the pairing (not per-link), so callers NEVER bind
72
+ * `link.onMessage` themselves.
73
+ */
74
+ onMessage(cb: (from: string, m: IncomingMessage) => void): void;
75
+ /**
76
+ * Register a callback fired when a NON-current (queued) peer sends a message —
77
+ * it is buffered, not dropped. `queued` is that peer's current buffered count.
78
+ */
79
+ onQueued(cb: (from: string, queued: number) => void): void;
80
+ /**
81
+ * Pull every inbound message received since the last drain (current + queued),
82
+ * tagged with sender; empties the buffer. For PULL consumers (MCP live_poll).
83
+ */
84
+ drain(): PairingMessage[];
85
+ /** Snapshot of the currently-queued (non-current) links. */
86
+ queued(): PeerLink[];
87
+ }
88
+
89
+ /**
90
+ * vibedating MCP server (stdio) — full agent-native tool surface.
91
+ *
92
+ * An agent drives vibedate ENTIRELY via tool calls — no interactive terminal.
93
+ * This is the fix for agents whose interactive `live` sessions time out.
94
+ *
95
+ * Tools (every response is structured JSON with `{ ok, ... }` / `{ ok:false, error }`):
96
+ *
97
+ * READ/STATE
98
+ * get_profile · connect · matches · handle_get · handle_set · blocklist
99
+ * block · unblock · daemon_status
100
+ *
101
+ * DISCOVERY
102
+ * discover · who · find
103
+ *
104
+ * LIVE CHAT (stateful in-process session — poll, don't block a TTY)
105
+ * live_start · live_peers · live_send · live_poll · live_open · live_next · live_stop
106
+ *
107
+ * ROOMS
108
+ * room_join · room_send · room_poll · room_who · room_leave
109
+ *
110
+ * MEDIA
111
+ * media_send
112
+ *
113
+ * Legacy aliases `profile` / `matches` remain registered for back-compat.
114
+ *
115
+ * AEGIS: peer text is UNTRUSTED display data — sanitized before return, never
116
+ * executed, never fed to a shell.
117
+ */
118
+
119
+ /** Injectable hooks so tests can drive live/room without the real DHT. */
120
+ interface McpLiveHooks {
121
+ /** Build (or inject) the pairing object used by live_* tools. */
122
+ createPairing?: () => LivePairing;
123
+ /**
124
+ * Optional override for live_start's discovery join. When provided, the
125
+ * real DHT is never touched — the hook receives the pairing and is free to
126
+ * inject fake links. Return a close handle (or nothing).
127
+ */
128
+ startLive?: (args: {
129
+ pairing: LivePairing;
130
+ hello: PeerHello;
131
+ any: boolean;
132
+ to: string | null;
133
+ }) => Promise<{
134
+ close: () => Promise<void>;
135
+ } | void> | {
136
+ close: () => Promise<void>;
137
+ } | void;
138
+ /** Optional override for room_join. */
139
+ startRoom?: (args: {
140
+ hello: PeerHello;
141
+ room: string;
142
+ }) => Promise<RoomSession> | RoomSession;
143
+ }
144
+ interface McpSessionState {
145
+ discovery: DiscoverySession | null;
146
+ /** Target handle sought by `find` (canonical), or null when idle. */
147
+ findTarget: string | null;
148
+ findSeen: boolean;
149
+ live: {
150
+ pairing: LivePairing;
151
+ session: DiscoverySession | {
152
+ close: () => Promise<void>;
153
+ } | null;
154
+ any: boolean;
155
+ to: string | null;
156
+ } | null;
157
+ room: {
158
+ session: RoomSession;
159
+ /** Draining buffer of inbound room messages since last room_poll. */
160
+ buffer: RoomMessage[];
161
+ name: string;
162
+ } | null;
163
+ }
164
+ /** Construct a fresh in-process session bag (also used by tests to reset). */
165
+ declare function createSessionState(): McpSessionState;
166
+ /**
167
+ * Create the vibedating MCP server with every agent-native tool registered.
168
+ * Pure registration — no transport attached. Callers (or {@link runMcp}) attach
169
+ * a transport. Tests drive this with InMemoryTransport.
170
+ *
171
+ * Pass a session bag to share/reset state across calls; omit to use a private
172
+ * fresh bag for this server instance.
173
+ */
174
+ declare function createMcpServer(opts?: {
175
+ readonly session?: McpSessionState;
176
+ readonly hooks?: McpLiveHooks;
177
+ readonly version?: string;
178
+ }): McpServer;
1
179
  /**
2
180
  * Start the stdio MCP server. Resolves once connected to the transport; the
3
181
  * transport then keeps the process alive for the host agent to call tools.
4
182
  */
5
183
  declare function runMcp(): Promise<void>;
184
+ /** Full set of tool names the server exposes — kept in sync for tests. */
185
+ declare const MCP_TOOL_NAMES: readonly ["get_profile", "profile", "connect", "matches", "handle_get", "handle_set", "blocklist", "block", "unblock", "daemon_status", "discover", "who", "find", "live_start", "live_peers", "live_send", "live_poll", "live_open", "live_next", "live_stop", "room_join", "room_send", "room_poll", "room_who", "room_leave", "media_send"];
6
186
 
7
- export { runMcp };
187
+ export { MCP_TOOL_NAMES, type McpLiveHooks, type McpSessionState, createMcpServer, createSessionState, runMcp };
package/dist/mcp.js CHANGED
@@ -1,7 +1,13 @@
1
1
  import {
2
+ MCP_TOOL_NAMES,
3
+ createMcpServer,
4
+ createSessionState,
2
5
  runMcp
3
- } from "./chunk-ZD6JBWEW.js";
4
- import "./chunk-HDHJLZZG.js";
6
+ } from "./chunk-JBADPOR5.js";
7
+ import "./chunk-S7MO5OSO.js";
5
8
  export {
9
+ MCP_TOOL_NAMES,
10
+ createMcpServer,
11
+ createSessionState,
6
12
  runMcp
7
13
  };