vibeshare-live 0.1.1 → 0.2.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,61 +1,120 @@
1
- export { a as AccessGate, b as AccessGateOptions, A as AccessMode, C as ConsentError, c as ControlRequestResult, D as DEFAULT_ACCESS, d as DenialReason, E as ExpirySpec, H as HOST_PARTICIPANT_NAME, R as RevokeReason, S as SHARE_SESSION_SCOPE, e as ShareHandle, f as ShareOptions, V as Viewer, g as ViewerRole, h as ViewerRoster, i as createAccessGate, j as createShare, p as parseExpiry } from './share-t_zYXkQB.js';
2
- import 'vibelive';
3
- import '@pooriaarab/vibe-core';
1
+ import { ConsentStore, ConsentGrant, ConsentLedger } from '@pooriaarab/vibe-core';
2
+ import { S as ShareTransport, a as Share, b as SessionFeed, V as ViewerRegistry, C as CreateShareOptions, c as ShareManager, d as CreatedShare } from './manager-uhMBJXtu.js';
3
+ export { e as ConsentRequiredError, F as FeedEntry, J as JoinRequestStatus, P as PublishOptions, f as SHARE_SCOPE, g as ShareAccess, h as ShareError, i as ShareErrorCode, j as ShareManagerDeps, k as ShareState, l as Viewer, m as ViewerRole } from './manager-uhMBJXtu.js';
4
+ import 'node:events';
4
5
 
5
- /** vibeshare package version (single source of truth for CLI + MCP). */
6
- declare const VERSION = "0.1.0";
6
+ interface LocalHttpTransportOptions {
7
+ /** Bind address. Default 127.0.0.1 (loopback-only). Use 0.0.0.0 for LAN. */
8
+ readonly host?: string;
9
+ /** Port. Default 0 = ephemeral. */
10
+ readonly port?: number;
11
+ /**
12
+ * Public base URL to print instead of `http://host:port` — the seam where
13
+ * a future RelayTransport hands out `https://vibeshare.io` URLs. Routing
14
+ * still happens locally.
15
+ */
16
+ readonly baseUrl?: string;
17
+ /** Bearer token for the loopback control API. Generated when omitted. */
18
+ readonly hostToken?: string;
19
+ /**
20
+ * Called when the control API asks to stop a share (e.g. `vibeshare stop`
21
+ * from another process). When absent, the transport unserves + closes the
22
+ * feed itself.
23
+ */
24
+ readonly onStopRequested?: (shareId: string) => void;
25
+ }
26
+ declare class LocalHttpTransport implements ShareTransport {
27
+ #private;
28
+ readonly kind = "local-http";
29
+ readonly hostToken: string;
30
+ constructor(opts?: LocalHttpTransportOptions);
31
+ /** Bind the listener. Must be called before serve(). Idempotent. */
32
+ listen(): Promise<void>;
33
+ /** The port actually bound (useful with port 0). */
34
+ get port(): number;
35
+ serve(share: Share, feed: SessionFeed, viewers: ViewerRegistry): Promise<string>;
36
+ unserve(shareId: string): Promise<void>;
37
+ close(): Promise<void>;
38
+ /** Number of shares currently served (diagnostics/tests). */
39
+ get shareCount(): number;
40
+ }
41
+
42
+ declare function vibeHome(): string;
43
+ /** Durable ConsentStore backing the vibe-core consent ledger. */
44
+ declare class FileConsentStore implements ConsentStore {
45
+ readonly file: string;
46
+ constructor(file?: string);
47
+ load(): ConsentGrant[];
48
+ save(grants: ConsentGrant[]): void;
49
+ }
50
+ /** A consent ledger backed by the host's `~/.vibeshare/consent.json`. */
51
+ declare function loadLedger(store?: ConsentStore): ConsentLedger;
7
52
 
8
53
  /**
9
- * The URL / capability-id layer of vibeshare.
10
- *
11
- * Pure logic no IO so every function here is directly unit-tested in
12
- * `src/url.test.ts`. A share link is a **capability URL**: the id is the only
13
- * thing that grants access, so it must be unguessable. The human-facing host is
14
- * vibeshare's own domain (`vibeshare.stream`); the actual transport is the
15
- * local/LAN ws relay owned by vibelive, which the URL only *represents*.
16
- */
17
- /**
18
- * The display origin for vibeshare share links. This is vibeshare's OWN domain —
19
- * not vibe.live — so a shared link reads as vibeshare even though the bytes flow
20
- * over a self-hostable e2e relay (see docs/spec.md · "its OWN domain, not
21
- * vibe.live").
54
+ * The web spectator view: a minimal, self-contained read-only client served
55
+ * straight from the host machine — no install, no build, no external assets
56
+ * (local-first holds for viewers too; the page phones nowhere).
22
57
  */
23
- declare const SHARE_ORIGIN = "https://vibeshare.stream";
24
- /** Path prefix for share links: `<origin>/s/<id>`. */
25
- declare const SHARE_PATH_PREFIX = "/s/";
58
+
59
+ declare function spectatorPage(share: Share): string;
60
+
61
+ /** A 12-char base64url id (72 bits of entropy) — unguessable, URL-safe. */
62
+ declare function newShareId(): string;
63
+ /** A random hex token (viewer bearer tokens, host control token). */
64
+ declare function newToken(bytes?: number): string;
26
65
  /**
27
- * Mint an unguessable capability id. Uses the platform CSPRNG (`crypto.randomUUID`,
28
- * 122 bits of entropy) so a link is a genuine capability — guessing it is
29
- * infeasible, which is the whole basis of the access model.
66
+ * Parse an expiry spec into milliseconds.
67
+ * 'stop' | 'never' → null (lasts until explicitly stopped)
68
+ * '<n>m' | '<n>h' | '<n>d' that duration ('1h', '24h', '7d', …)
69
+ * Anything else throws — callers (CLI) turn this into a usage error.
30
70
  */
31
- declare function newShareId(): string;
71
+ declare function parseExpiry(spec: string): number | null;
72
+ /** Hash a passphrase for storage: `scrypt$<saltHex>$<hashHex>`. */
73
+ declare function hashPassphrase(passphrase: string): string;
74
+ /** Verify a candidate against a stored `scrypt$…` hash, timing-safe. */
75
+ declare function verifyPassphrase(passphrase: string, stored: string): boolean;
76
+
77
+ declare const VERSION = "0.1.0";
78
+
32
79
  /**
33
- * Build the human-facing share URL for a capability id.
80
+ * vibeshare npm library surface.
34
81
  *
35
- * The URL is for *display and parsing only* — opening it resolves to the
36
- * vibeshare spectator view, which then connects to the host's local/LAN relay.
37
- * The relay URL is carried out-of-band (printed next to the share URL by the CLI).
82
+ * ```ts
83
+ * import { createShare, grantConsent } from 'vibeshare';
84
+ *
85
+ * grantConsent('share this session from my app'); // once, recorded locally
86
+ * const { url, feed, viewers, revoke } = await createShare({
87
+ * session: 'npm test',
88
+ * access: 'spectate',
89
+ * expiry: '1h',
90
+ * });
91
+ * feed.publish('tests starting…');
92
+ * await revoke();
93
+ * ```
94
+ *
95
+ * Consent is enforced by the vibe-core ledger: no `share:session` grant →
96
+ * `createShare` throws `ConsentRequiredError`. The default transport serves
97
+ * the spectator view + stream from this machine; the relay/p2p seam is the
98
+ * `ShareTransport` interface (see transport.ts).
38
99
  */
39
- declare function buildShareUrl(id: string, origin?: string): string;
40
- /** Error thrown when a string cannot be parsed as a vibeshare share URL. */
41
- declare class ShareUrlParseError extends Error {
42
- constructor(message: string);
100
+
101
+ interface CreateShareLibraryOptions extends CreateShareOptions {
102
+ /** Serve on a specific consent ledger (default: ~/.vibeshare file ledger). */
103
+ readonly consent?: ConsentLedger;
104
+ /** Transport options for the default local transport (host, port, baseUrl). */
105
+ readonly transport?: LocalHttpTransportOptions;
106
+ /** Bring your own manager (tests, embedders) instead of the shared default. */
107
+ readonly manager?: ShareManager;
43
108
  }
44
109
  /**
45
- * Parse a vibeshare share URL (or bare `/s/<id>` path) back into its capability id.
46
- *
47
- * Accepts:
48
- * - full URLs: `https://vibeshare.stream/s/<id>`, `http://...`, with or without
49
- * a trailing slash or query string;
50
- * - bare paths: `/s/<id>`;
51
- * - any origin host (we key off the `/s/` segment, not the host, so self-hosted
52
- * / vanity domains round-trip too).
110
+ * Create a share `{share, url, feed, viewers, revoke}`.
53
111
  *
54
- * Pure and total: throws {@link ShareUrlParseError} on input with no `/s/` segment.
55
- * Round-trips {@link buildShareUrl}: `parseShareUrl(buildShareUrl(id)).id === id`.
112
+ * @throws ConsentRequiredError when the ledger has no `share:session` grant.
56
113
  */
57
- declare function parseShareUrl(url: string): {
58
- readonly id: string;
59
- };
114
+ declare function createShare(opts?: CreateShareLibraryOptions): Promise<CreatedShare>;
115
+ /** Grant the `share:session` scope on the host's local consent ledger. */
116
+ declare function grantConsent(note?: string): void;
117
+ /** Revoke the `share:session` scope. */
118
+ declare function revokeConsent(): void;
60
119
 
61
- export { SHARE_ORIGIN, SHARE_PATH_PREFIX, ShareUrlParseError, VERSION, buildShareUrl, newShareId, parseShareUrl };
120
+ export { type CreateShareLibraryOptions, CreateShareOptions, CreatedShare, FileConsentStore, LocalHttpTransport, type LocalHttpTransportOptions, SessionFeed, Share, ShareManager, ShareTransport, VERSION, ViewerRegistry, createShare, grantConsent, hashPassphrase, loadLedger, newShareId, newToken, parseExpiry, revokeConsent, spectatorPage, verifyPassphrase, vibeHome };
package/dist/index.js CHANGED
@@ -1,32 +1,63 @@
1
1
  import {
2
- ConsentError,
3
- DEFAULT_ACCESS,
4
- HOST_PARTICIPANT_NAME,
5
- SHARE_ORIGIN,
6
- SHARE_PATH_PREFIX,
7
- SHARE_SESSION_SCOPE,
8
- ShareUrlParseError,
2
+ ConsentRequiredError,
3
+ FileConsentStore,
4
+ LocalHttpTransport,
5
+ SHARE_SCOPE,
6
+ SessionFeed,
7
+ ShareError,
8
+ ShareManager,
9
9
  VERSION,
10
- buildShareUrl,
11
- createAccessGate,
12
- createShare,
10
+ ViewerRegistry,
11
+ hashPassphrase,
12
+ loadLedger,
13
13
  newShareId,
14
+ newToken,
14
15
  parseExpiry,
15
- parseShareUrl
16
- } from "./chunk-SBAGPPGC.js";
16
+ spectatorPage,
17
+ verifyPassphrase,
18
+ vibeHome
19
+ } from "./chunk-RY2ANOPC.js";
20
+
21
+ // src/index.ts
22
+ import "@pooriaarab/vibe-core";
23
+ var defaultManager = null;
24
+ function getDefaultManager(transportOpts) {
25
+ defaultManager ??= new ShareManager({
26
+ consent: loadLedger(),
27
+ transport: new LocalHttpTransport(transportOpts)
28
+ });
29
+ return defaultManager;
30
+ }
31
+ async function createShare(opts = {}) {
32
+ const manager = opts.manager ?? (opts.consent ? new ShareManager({ consent: opts.consent, transport: new LocalHttpTransport(opts.transport) }) : getDefaultManager(opts.transport));
33
+ const { consent: _c, transport: _t, manager: _m, ...shareOpts } = opts;
34
+ return manager.createShare(shareOpts);
35
+ }
36
+ function grantConsent(note) {
37
+ loadLedger().grant(SHARE_SCOPE, note ?? "granted via vibeshare library");
38
+ }
39
+ function revokeConsent() {
40
+ loadLedger().revoke(SHARE_SCOPE);
41
+ }
17
42
  export {
18
- ConsentError,
19
- DEFAULT_ACCESS,
20
- HOST_PARTICIPANT_NAME,
21
- SHARE_ORIGIN,
22
- SHARE_PATH_PREFIX,
23
- SHARE_SESSION_SCOPE,
24
- ShareUrlParseError,
43
+ ConsentRequiredError,
44
+ FileConsentStore,
45
+ LocalHttpTransport,
46
+ SHARE_SCOPE,
47
+ SessionFeed,
48
+ ShareError,
49
+ ShareManager,
25
50
  VERSION,
26
- buildShareUrl,
27
- createAccessGate,
51
+ ViewerRegistry,
28
52
  createShare,
53
+ grantConsent,
54
+ hashPassphrase,
55
+ loadLedger,
29
56
  newShareId,
57
+ newToken,
30
58
  parseExpiry,
31
- parseShareUrl
59
+ revokeConsent,
60
+ spectatorPage,
61
+ verifyPassphrase,
62
+ vibeHome
32
63
  };
@@ -0,0 +1,259 @@
1
+ import { VibeEvent, ConsentLedger } from '@pooriaarab/vibe-core';
2
+ import { EventEmitter } from 'node:events';
3
+
4
+ /**
5
+ * vibeshare — shared types.
6
+ *
7
+ * vibeshare is the URL / identity / access layer for sharing a live agent
8
+ * coding session. It owns the *link and the gate*; the session content is an
9
+ * ordered feed of entries that spectators receive live. vibelive (the
10
+ * multiplayer engine) owns any future collaborator write path — see
11
+ * `transport.ts` for that seam.
12
+ */
13
+ /** Access policy for a share link. */
14
+ type ShareAccess =
15
+ /** Recipients can only watch. Genuinely read-only: there is no write route. */
16
+ 'spectate'
17
+ /** Recipients may request to join; host approval promotes them to collaborator. */
18
+ | 'invite';
19
+ type ShareState = 'live' | 'revoked' | 'expired';
20
+ /** A live (or formerly live) share link. */
21
+ interface Share {
22
+ /** Unguessable capability id — appears in the URL. */
23
+ readonly id: string;
24
+ /** Human label, e.g. the command being shared or the agent name. */
25
+ readonly name: string;
26
+ access: ShareAccess;
27
+ readonly createdAt: string;
28
+ /** ISO timestamp, or null when the share lasts "until I stop". */
29
+ readonly expiresAt: string | null;
30
+ state: ShareState;
31
+ /** scrypt hash (`scrypt$<salt>$<hash>`); never the plaintext passphrase. */
32
+ readonly passphraseHash: string | null;
33
+ }
34
+ type ViewerRole = 'spectator' | 'collaborator';
35
+ type JoinRequestStatus = 'none' | 'pending' | 'approved' | 'denied';
36
+ /** Someone who opened the link and joined as a viewer. */
37
+ interface Viewer {
38
+ readonly id: string;
39
+ name: string;
40
+ role: ViewerRole;
41
+ /** Bearer token issued at join; required for stream/request/leave calls. */
42
+ readonly token: string;
43
+ readonly joinedAt: string;
44
+ joinRequest: JoinRequestStatus;
45
+ }
46
+ /** One entry in the shared session's ordered log. */
47
+ interface FeedEntry {
48
+ /** Monotonic sequence number — also the SSE event id. */
49
+ readonly seq: number;
50
+ readonly ts: number;
51
+ readonly type: 'output' | 'milestone' | 'system';
52
+ /** Which host stream produced an `output` entry. */
53
+ readonly stream?: 'stdout' | 'stderr';
54
+ readonly text: string;
55
+ }
56
+ /** Options for creating a share (CLI, library, and MCP all funnel here). */
57
+ interface CreateShareOptions {
58
+ /** Label for what is being shared (command line, agent name, …). */
59
+ readonly session?: string;
60
+ /** Access policy. Default `'spectate'`. */
61
+ readonly access?: ShareAccess;
62
+ /**
63
+ * How long the link lives: `'1h'`, `'24h'`, `'stop'` (until stopped), or
64
+ * any `<n>m` / `<n>h` / `<n>d`. Default `'stop'`.
65
+ */
66
+ readonly expiry?: string;
67
+ /** Passphrase second factor. Optional; stored only as a scrypt hash. */
68
+ readonly passphrase?: string;
69
+ /** Override the display name (defaults to `session`). */
70
+ readonly name?: string;
71
+ /**
72
+ * Direct millisecond expiry override (takes precedence over `expiry`).
73
+ * Mainly for tests and embedders that already hold a duration.
74
+ */
75
+ readonly expiryMs?: number;
76
+ }
77
+ /** vibeshare error with a machine-readable code (mapped to HTTP by transports). */
78
+ declare class ShareError extends Error {
79
+ readonly code: ShareErrorCode;
80
+ constructor(code: ShareErrorCode, message: string);
81
+ }
82
+ type ShareErrorCode = 'not-live' | 'not-found' | 'passphrase-required' | 'passphrase-invalid' | 'invite-disabled' | 'already-pending' | 'not-pending' | 'consent-required' | 'bad-request';
83
+
84
+ /**
85
+ * SessionFeed — the ordered log of everything a share broadcasts.
86
+ *
87
+ * The host (and only the host) publishes; spectators subscribe. Late joiners
88
+ * get a bounded replay of recent entries, then live entries in order. This is
89
+ * vibeshare's half of vibelive's "ordered-log channel": the log is the source
90
+ * of record, held on the host machine only.
91
+ */
92
+
93
+ interface PublishOptions {
94
+ readonly type?: FeedEntry['type'];
95
+ readonly stream?: FeedEntry['stream'];
96
+ }
97
+ declare interface SessionFeed {
98
+ on(event: 'entry', listener: (entry: FeedEntry) => void): this;
99
+ on(event: 'close', listener: () => void): this;
100
+ once(event: 'close', listener: () => void): this;
101
+ }
102
+ declare class SessionFeed extends EventEmitter {
103
+ #private;
104
+ constructor(capacity?: number);
105
+ get closed(): boolean;
106
+ /** Append a line to the log and fan it out to subscribers. */
107
+ publish(text: string, opts?: PublishOptions): FeedEntry;
108
+ /** Publish a normalized vibe-core milestone event as a feed line. */
109
+ publishEvent(e: VibeEvent): FeedEntry;
110
+ /** Publish a host-side status line (share opened, viewer joined, …). */
111
+ system(text: string): FeedEntry;
112
+ /** Recent entries for late-joiner replay, oldest first. */
113
+ backlog(): readonly FeedEntry[];
114
+ /** Subscribe to live entries. Returns an unsubscribe function. */
115
+ subscribe(listener: (entry: FeedEntry) => void): () => void;
116
+ /** End the feed: notifies subscribers, refuses further publishes. */
117
+ close(): void;
118
+ }
119
+
120
+ /**
121
+ * ViewerRegistry — who is watching a share, and who may write.
122
+ *
123
+ * Write-arbitration invariant (shared with vibelive §4): the host is the
124
+ * server of record, and `canWrite()` is the single gate any input path must
125
+ * consult. A spectator can never pass it; promotion happens only through a
126
+ * host-approved join request on an `invite`-access share. v0 exposes no
127
+ * remote input route at all — the gate exists so the vibelive handoff has
128
+ * exactly one choke point when it lands.
129
+ */
130
+
131
+ interface RegistryEvents {
132
+ join: (v: Viewer) => void;
133
+ leave: (v: Viewer) => void;
134
+ request: (v: Viewer) => void;
135
+ approve: (v: Viewer) => void;
136
+ deny: (v: Viewer) => void;
137
+ kick: (v: Viewer) => void;
138
+ }
139
+ declare interface ViewerRegistry {
140
+ on<K extends keyof RegistryEvents>(event: K, listener: RegistryEvents[K]): this;
141
+ }
142
+ declare class ViewerRegistry extends EventEmitter {
143
+ #private;
144
+ constructor(getAccess: () => ShareAccess);
145
+ /** Register a new spectator. Everyone enters read-only — no exceptions. */
146
+ add(name?: string): Viewer;
147
+ get(id: string): Viewer | undefined;
148
+ getByToken(token: string): Viewer | undefined;
149
+ list(): Viewer[];
150
+ count(): number;
151
+ /**
152
+ * A spectator asks to be promoted to collaborator. Only possible on an
153
+ * `invite`-access share; the host still has to approve.
154
+ */
155
+ requestJoin(id: string): Viewer;
156
+ /** Host approves a pending request → the viewer becomes a collaborator. */
157
+ approve(id: string): Viewer;
158
+ /** Host denies a pending request; the viewer stays a spectator. */
159
+ deny(id: string): Viewer;
160
+ /** Remove a viewer entirely (their streams are closed by the transport). */
161
+ kick(id: string): Viewer;
162
+ /** A viewer leaves on their own. */
163
+ leave(id: string): void;
164
+ /**
165
+ * The write-arbitration gate. The host writes by definition; a remote
166
+ * participant writes only as an approved collaborator. Any future input
167
+ * channel (vibelive cursors, shared terminal input) MUST consult this.
168
+ */
169
+ canWrite(viewerId: string): boolean;
170
+ }
171
+
172
+ /**
173
+ * ShareTransport — the one seam vibeshare deliberately leaves open.
174
+ *
175
+ * vibeshare owns the link + the gate. How feed bytes reach viewers is a
176
+ * pluggable transport behind this interface:
177
+ *
178
+ * - `LocalHttpTransport` (implemented, the default): serves the spectator
179
+ * web view + an SSE stream directly from the host machine over
180
+ * loopback/LAN. Fully local-first — bytes go straight from host to
181
+ * viewer; nothing is stored on any server.
182
+ *
183
+ * - `RelayTransport` (NOT implemented — lands with vibelive): a dumb,
184
+ * e2e-encrypted relay that forwards opaque blobs so viewers behind NAT
185
+ * can reach the host, returning a public `https://vibeshare.io/s/<id>`
186
+ * URL. The relay never sees plaintext and stores nothing; vibelive owns
187
+ * the encryption and the p2p mesh. Everything in vibeshare (access
188
+ * policy, consent, the viewer registry, write-arbitration) is transport-
189
+ * agnostic and already works — swapping this interface in is the only
190
+ * change a relay requires.
191
+ *
192
+ * The collaborator *input* channel is part of the same vibelive seam: a
193
+ * transport that accepts remote input MUST route it through
194
+ * `ViewerRegistry.canWrite()` before applying anything to the session.
195
+ */
196
+
197
+ interface ShareTransport {
198
+ /** Transport label for diagnostics, e.g. 'local-http'. */
199
+ readonly kind: string;
200
+ /**
201
+ * Begin serving a share. Returns the URL viewers open. Called once per
202
+ * share; a transport may serve many shares concurrently.
203
+ */
204
+ serve(share: Share, feed: SessionFeed, viewers: ViewerRegistry): Promise<string>;
205
+ /**
206
+ * Stop serving one share: disconnect its viewers and make its URL answer
207
+ * as gone. Idempotent.
208
+ */
209
+ unserve(shareId: string): Promise<void>;
210
+ /** Tear the whole transport down (all shares, listeners, sockets). */
211
+ close(): Promise<void>;
212
+ }
213
+
214
+ /**
215
+ * ShareManager — creates, tracks, expires, and revokes shares.
216
+ *
217
+ * The consent ledger from @pooriaarab/vibe-core is the enforcement point for
218
+ * local-first: no grant for the `share:session` scope → no share. Expiry is
219
+ * enforced here with real timers that tear the share down (the transport
220
+ * disconnects viewers and the URL goes 410) — not just a filter on reads.
221
+ */
222
+
223
+ /** The consent scope the suite reserves for sharing features. */
224
+ declare const SHARE_SCOPE = "share:session";
225
+ declare class ConsentRequiredError extends ShareError {
226
+ constructor();
227
+ }
228
+ interface CreatedShare {
229
+ readonly share: Share;
230
+ /** The URL viewers open. */
231
+ readonly url: string;
232
+ readonly feed: SessionFeed;
233
+ readonly viewers: ViewerRegistry;
234
+ /** End the share now (same as manager.revokeShare(share.id)). */
235
+ revoke(): Promise<void>;
236
+ }
237
+ interface ShareManagerDeps {
238
+ readonly consent: ConsentLedger;
239
+ readonly transport: ShareTransport;
240
+ }
241
+ declare class ShareManager {
242
+ #private;
243
+ constructor(deps: ShareManagerDeps);
244
+ /**
245
+ * Create a share: `createShare({session, access, expiry, passphrase})`
246
+ * → `{share, url, feed, viewers, revoke}`.
247
+ *
248
+ * @throws ConsentRequiredError when the ledger has no `share:session` grant.
249
+ */
250
+ createShare(opts?: CreateShareOptions): Promise<CreatedShare>;
251
+ /** End a share: disconnect viewers, 410 the URL, close the feed. */
252
+ revokeShare(id: string, reason?: 'revoked' | 'expired'): Promise<void>;
253
+ get(id: string): CreatedShare | undefined;
254
+ list(): CreatedShare[];
255
+ /** Revoke every live share and close the transport. */
256
+ stopAll(): Promise<void>;
257
+ }
258
+
259
+ export { type CreateShareOptions as C, type FeedEntry as F, type JoinRequestStatus as J, type PublishOptions as P, type ShareTransport as S, ViewerRegistry as V, type Share as a, SessionFeed as b, ShareManager as c, type CreatedShare as d, ConsentRequiredError as e, SHARE_SCOPE as f, type ShareAccess as g, ShareError as h, type ShareErrorCode as i, type ShareManagerDeps as j, type ShareState as k, type Viewer as l, type ViewerRole as m };
package/dist/mcp.d.ts CHANGED
@@ -1,41 +1,30 @@
1
- import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
2
- import { RelayHandle } from 'vibelive';
3
- import { e as ShareHandle } from './share-t_zYXkQB.js';
4
- import '@pooriaarab/vibe-core';
1
+ #!/usr/bin/env node
2
+ import { ConsentLedger } from '@pooriaarab/vibe-core';
3
+ import { c as ShareManager } from './manager-uhMBJXtu.js';
4
+ import 'node:events';
5
5
 
6
- /**
7
- * vibeshare MCP server (stdio). Exposes two tools an agent can call:
8
- *
9
- * - create_share — host a vibelive session wrapping a command, mint a share URL
10
- * with an access policy (+ optional expiry/passphrase), and
11
- * return the capability URL + relay URL. Lives for the MCP
12
- * process lifetime (or until the wrapped agent exits).
13
- * - viewers — list active shares and their viewer rosters (connected
14
- * spectators/participants + pending join requests).
15
- *
16
- * Uses the high-level `McpServer` API from `@modelcontextprotocol/sdk`. Input
17
- * schemas are Zod raw shapes (the SDK's expected form); zod is a transitive
18
- * dependency of the SDK and gets bundled into dist/mcp.js by tsup.
19
- */
20
-
21
- interface ActiveShare {
22
- readonly id: string;
23
- readonly url: string;
24
- readonly relayUrl: string;
25
- readonly access: string;
26
- readonly command: readonly string[];
27
- readonly share: ShareHandle;
28
- readonly relay: RelayHandle;
6
+ interface JsonRpcRequest {
7
+ jsonrpc?: string;
8
+ id?: string | number | null;
9
+ method?: string;
10
+ params?: Record<string, unknown>;
11
+ }
12
+ interface JsonRpcResponse {
13
+ jsonrpc: '2.0';
14
+ id: string | number | null;
15
+ result?: unknown;
16
+ error?: {
17
+ code: number;
18
+ message: string;
19
+ };
20
+ }
21
+ interface McpServerDeps {
22
+ manager: ShareManager;
23
+ consent: ConsentLedger;
24
+ }
25
+ interface McpServer {
26
+ handleMessage(msg: JsonRpcRequest): Promise<JsonRpcResponse | null>;
29
27
  }
30
- /**
31
- * Build the vibeshare MCP server (tools registered, not yet connected).
32
- *
33
- * `sessions` defaults to a fresh module-level map so independent `createMcpServer`
34
- * calls don't share state, but a single stdio process keeps one map for its
35
- * lifetime (so `viewers` sees shares started via `create_share`).
36
- */
37
- declare function createMcpServer(sessions?: Map<string, ActiveShare>): McpServer;
38
- /** Create the server, wire it to stdio, and run until the client disconnects. */
39
- declare function runMcpStdio(): Promise<void>;
28
+ declare function createMcpServer(deps: McpServerDeps): McpServer;
40
29
 
41
- export { createMcpServer, runMcpStdio };
30
+ export { type McpServer, type McpServerDeps, createMcpServer };