@spotpatch/bridge 0.1.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.
@@ -0,0 +1,502 @@
1
+ import { ExternalHandoffActiveAdapterKind, ExternalHandoffReportableDispatchPhase, ExternalHandoffSummary } from '@spotpatch/shared';
2
+ import { z } from 'zod';
3
+ import { McpServer } from '@modelcontextprotocol/server';
4
+ import { StdioServerHandle } from '@modelcontextprotocol/server/stdio';
5
+
6
+ type ActiveAdapterKind = ExternalHandoffActiveAdapterKind;
7
+ type ActiveReportPhase = ExternalHandoffReportableDispatchPhase;
8
+ /**
9
+ * Lease data is connector-private. It must never be included in MCP output,
10
+ * Channel metadata, diagnostics, or browser-facing state.
11
+ */
12
+ interface ActiveBridgeLease {
13
+ readonly adapterKind: ActiveAdapterKind;
14
+ readonly baselineCursor: string | undefined;
15
+ readonly heartbeatIntervalMs: number;
16
+ readonly leaseToken: string;
17
+ readonly sessionId: string;
18
+ }
19
+ /**
20
+ * The event pump deliberately depends on a narrow structural interface. The
21
+ * production BridgeClient and deterministic test doubles both implement it.
22
+ */
23
+ interface ActiveBridgeClient {
24
+ readonly activeClaim: (adapterKind: ActiveAdapterKind, sessionId?: string, signal?: AbortSignal) => Promise<ActiveBridgeLease>;
25
+ readonly activeHeartbeat: (lease: ActiveBridgeLease, signal?: AbortSignal) => Promise<void>;
26
+ readonly activeRelease: (lease: ActiveBridgeLease, signal?: AbortSignal) => Promise<void>;
27
+ readonly activeReport: (lease: ActiveBridgeLease, cursor: string, phase: ActiveReportPhase, signal?: AbortSignal) => Promise<void>;
28
+ }
29
+
30
+ declare const sessionListItemSchema: z.ZodObject<{
31
+ sessionId: z.ZodString;
32
+ framework: z.ZodEnum<{
33
+ vite: "vite";
34
+ next: "next";
35
+ }>;
36
+ current: z.ZodNullable<z.ZodObject<{
37
+ sessionId: z.ZodString;
38
+ framework: z.ZodEnum<{
39
+ vite: "vite";
40
+ next: "next";
41
+ }>;
42
+ revision: z.ZodNumber;
43
+ cursor: z.ZodString;
44
+ targetCount: z.ZodNumber;
45
+ page: z.ZodObject<{
46
+ origin: z.ZodString;
47
+ pathname: z.ZodString;
48
+ }, z.core.$strict>;
49
+ publishedAt: z.ZodISODateTime;
50
+ expiresAt: z.ZodISODateTime;
51
+ state: z.ZodEnum<{
52
+ expired: "expired";
53
+ available: "available";
54
+ superseded: "superseded";
55
+ }>;
56
+ pickupCount: z.ZodNumber;
57
+ pickedUpAt: z.ZodOptional<z.ZodISODateTime>;
58
+ }, z.core.$strict>>;
59
+ }, z.core.$strict>;
60
+ declare const handoffDeliverySchema: z.ZodObject<{
61
+ outcome: z.ZodLiteral<"handoff">;
62
+ snapshot: z.ZodObject<{
63
+ schemaVersion: z.ZodLiteral<1>;
64
+ cursor: z.ZodString;
65
+ session: z.ZodObject<{
66
+ id: z.ZodString;
67
+ framework: z.ZodEnum<{
68
+ vite: "vite";
69
+ next: "next";
70
+ }>;
71
+ }, z.core.$strict>;
72
+ revision: z.ZodNumber;
73
+ publishedAt: z.ZodISODateTime;
74
+ expiresAt: z.ZodISODateTime;
75
+ annotation: z.ZodObject<{
76
+ schemaVersion: z.ZodLiteral<3>;
77
+ id: z.ZodString;
78
+ locale: z.ZodEnum<{
79
+ "en-US": "en-US";
80
+ "zh-CN": "zh-CN";
81
+ }>;
82
+ page: z.ZodObject<{
83
+ url: z.ZodString;
84
+ pathname: z.ZodString;
85
+ title: z.ZodString;
86
+ viewportWidth: z.ZodNumber;
87
+ viewportHeight: z.ZodNumber;
88
+ devicePixelRatio: z.ZodNumber;
89
+ }, z.core.$strict>;
90
+ targets: z.ZodArray<z.ZodObject<{
91
+ instruction: z.ZodString;
92
+ page: z.ZodOptional<z.ZodObject<{
93
+ url: z.ZodString;
94
+ pathname: z.ZodString;
95
+ title: z.ZodString;
96
+ viewportWidth: z.ZodNumber;
97
+ viewportHeight: z.ZodNumber;
98
+ devicePixelRatio: z.ZodNumber;
99
+ }, z.core.$strict>>;
100
+ source: z.ZodObject<{
101
+ fileId: z.ZodOptional<z.ZodString>;
102
+ relativePath: z.ZodOptional<z.ZodString>;
103
+ line: z.ZodOptional<z.ZodNumber>;
104
+ column: z.ZodOptional<z.ZodNumber>;
105
+ origin: z.ZodEnum<{
106
+ "jsx-host": "jsx-host";
107
+ "react-fiber": "react-fiber";
108
+ "dom-ancestor": "dom-ancestor";
109
+ none: "none";
110
+ }>;
111
+ confidence: z.ZodEnum<{
112
+ exact: "exact";
113
+ probable: "probable";
114
+ approximate: "approximate";
115
+ unknown: "unknown";
116
+ }>;
117
+ }, z.core.$strict>;
118
+ react: z.ZodObject<{
119
+ supported: z.ZodBoolean;
120
+ version: z.ZodOptional<z.ZodString>;
121
+ componentName: z.ZodOptional<z.ZodString>;
122
+ componentSourceId: z.ZodOptional<z.ZodString>;
123
+ sourceVersion: z.ZodOptional<z.ZodString>;
124
+ componentStack: z.ZodArray<z.ZodString>;
125
+ source: z.ZodOptional<z.ZodObject<{
126
+ fileId: z.ZodOptional<z.ZodString>;
127
+ relativePath: z.ZodOptional<z.ZodString>;
128
+ line: z.ZodOptional<z.ZodNumber>;
129
+ column: z.ZodOptional<z.ZodNumber>;
130
+ origin: z.ZodEnum<{
131
+ "jsx-host": "jsx-host";
132
+ "react-fiber": "react-fiber";
133
+ "dom-ancestor": "dom-ancestor";
134
+ none: "none";
135
+ }>;
136
+ confidence: z.ZodEnum<{
137
+ exact: "exact";
138
+ probable: "probable";
139
+ approximate: "approximate";
140
+ unknown: "unknown";
141
+ }>;
142
+ }, z.core.$strict>>;
143
+ }, z.core.$strict>;
144
+ element: z.ZodObject<{
145
+ tagName: z.ZodString;
146
+ selector: z.ZodString;
147
+ sanitizedHtml: z.ZodString;
148
+ textPreview: z.ZodOptional<z.ZodString>;
149
+ role: z.ZodOptional<z.ZodString>;
150
+ rect: z.ZodObject<{
151
+ x: z.ZodNumber;
152
+ y: z.ZodNumber;
153
+ width: z.ZodNumber;
154
+ height: z.ZodNumber;
155
+ }, z.core.$strict>;
156
+ }, z.core.$strict>;
157
+ styles: z.ZodObject<{
158
+ classNames: z.ZodArray<z.ZodString>;
159
+ inlineStyle: z.ZodOptional<z.ZodString>;
160
+ matchedRules: z.ZodArray<z.ZodObject<{
161
+ selector: z.ZodString;
162
+ declarations: z.ZodString;
163
+ source: z.ZodOptional<z.ZodString>;
164
+ media: z.ZodOptional<z.ZodString>;
165
+ }, z.core.$strict>>;
166
+ computed: z.ZodRecord<z.ZodString, z.ZodString>;
167
+ warnings: z.ZodArray<z.ZodString>;
168
+ }, z.core.$strict>;
169
+ code: z.ZodOptional<z.ZodObject<{
170
+ relativePath: z.ZodString;
171
+ language: z.ZodEnum<{
172
+ tsx: "tsx";
173
+ jsx: "jsx";
174
+ }>;
175
+ startLine: z.ZodNumber;
176
+ endLine: z.ZodNumber;
177
+ excerpt: z.ZodString;
178
+ boundary: z.ZodEnum<{
179
+ component: "component";
180
+ "nearby-lines": "nearby-lines";
181
+ }>;
182
+ }, z.core.$strict>>;
183
+ warnings: z.ZodArray<z.ZodString>;
184
+ }, z.core.$strict>>;
185
+ createdAt: z.ZodISODateTime;
186
+ }, z.core.$strict>;
187
+ }, z.core.$strict>;
188
+ receiptRecorded: z.ZodBoolean;
189
+ }, z.core.$strict>;
190
+ declare const currentHandoffDeliverySchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
191
+ outcome: z.ZodLiteral<"handoff">;
192
+ snapshot: z.ZodObject<{
193
+ schemaVersion: z.ZodLiteral<1>;
194
+ cursor: z.ZodString;
195
+ session: z.ZodObject<{
196
+ id: z.ZodString;
197
+ framework: z.ZodEnum<{
198
+ vite: "vite";
199
+ next: "next";
200
+ }>;
201
+ }, z.core.$strict>;
202
+ revision: z.ZodNumber;
203
+ publishedAt: z.ZodISODateTime;
204
+ expiresAt: z.ZodISODateTime;
205
+ annotation: z.ZodObject<{
206
+ schemaVersion: z.ZodLiteral<3>;
207
+ id: z.ZodString;
208
+ locale: z.ZodEnum<{
209
+ "en-US": "en-US";
210
+ "zh-CN": "zh-CN";
211
+ }>;
212
+ page: z.ZodObject<{
213
+ url: z.ZodString;
214
+ pathname: z.ZodString;
215
+ title: z.ZodString;
216
+ viewportWidth: z.ZodNumber;
217
+ viewportHeight: z.ZodNumber;
218
+ devicePixelRatio: z.ZodNumber;
219
+ }, z.core.$strict>;
220
+ targets: z.ZodArray<z.ZodObject<{
221
+ instruction: z.ZodString;
222
+ page: z.ZodOptional<z.ZodObject<{
223
+ url: z.ZodString;
224
+ pathname: z.ZodString;
225
+ title: z.ZodString;
226
+ viewportWidth: z.ZodNumber;
227
+ viewportHeight: z.ZodNumber;
228
+ devicePixelRatio: z.ZodNumber;
229
+ }, z.core.$strict>>;
230
+ source: z.ZodObject<{
231
+ fileId: z.ZodOptional<z.ZodString>;
232
+ relativePath: z.ZodOptional<z.ZodString>;
233
+ line: z.ZodOptional<z.ZodNumber>;
234
+ column: z.ZodOptional<z.ZodNumber>;
235
+ origin: z.ZodEnum<{
236
+ "jsx-host": "jsx-host";
237
+ "react-fiber": "react-fiber";
238
+ "dom-ancestor": "dom-ancestor";
239
+ none: "none";
240
+ }>;
241
+ confidence: z.ZodEnum<{
242
+ exact: "exact";
243
+ probable: "probable";
244
+ approximate: "approximate";
245
+ unknown: "unknown";
246
+ }>;
247
+ }, z.core.$strict>;
248
+ react: z.ZodObject<{
249
+ supported: z.ZodBoolean;
250
+ version: z.ZodOptional<z.ZodString>;
251
+ componentName: z.ZodOptional<z.ZodString>;
252
+ componentSourceId: z.ZodOptional<z.ZodString>;
253
+ sourceVersion: z.ZodOptional<z.ZodString>;
254
+ componentStack: z.ZodArray<z.ZodString>;
255
+ source: z.ZodOptional<z.ZodObject<{
256
+ fileId: z.ZodOptional<z.ZodString>;
257
+ relativePath: z.ZodOptional<z.ZodString>;
258
+ line: z.ZodOptional<z.ZodNumber>;
259
+ column: z.ZodOptional<z.ZodNumber>;
260
+ origin: z.ZodEnum<{
261
+ "jsx-host": "jsx-host";
262
+ "react-fiber": "react-fiber";
263
+ "dom-ancestor": "dom-ancestor";
264
+ none: "none";
265
+ }>;
266
+ confidence: z.ZodEnum<{
267
+ exact: "exact";
268
+ probable: "probable";
269
+ approximate: "approximate";
270
+ unknown: "unknown";
271
+ }>;
272
+ }, z.core.$strict>>;
273
+ }, z.core.$strict>;
274
+ element: z.ZodObject<{
275
+ tagName: z.ZodString;
276
+ selector: z.ZodString;
277
+ sanitizedHtml: z.ZodString;
278
+ textPreview: z.ZodOptional<z.ZodString>;
279
+ role: z.ZodOptional<z.ZodString>;
280
+ rect: z.ZodObject<{
281
+ x: z.ZodNumber;
282
+ y: z.ZodNumber;
283
+ width: z.ZodNumber;
284
+ height: z.ZodNumber;
285
+ }, z.core.$strict>;
286
+ }, z.core.$strict>;
287
+ styles: z.ZodObject<{
288
+ classNames: z.ZodArray<z.ZodString>;
289
+ inlineStyle: z.ZodOptional<z.ZodString>;
290
+ matchedRules: z.ZodArray<z.ZodObject<{
291
+ selector: z.ZodString;
292
+ declarations: z.ZodString;
293
+ source: z.ZodOptional<z.ZodString>;
294
+ media: z.ZodOptional<z.ZodString>;
295
+ }, z.core.$strict>>;
296
+ computed: z.ZodRecord<z.ZodString, z.ZodString>;
297
+ warnings: z.ZodArray<z.ZodString>;
298
+ }, z.core.$strict>;
299
+ code: z.ZodOptional<z.ZodObject<{
300
+ relativePath: z.ZodString;
301
+ language: z.ZodEnum<{
302
+ tsx: "tsx";
303
+ jsx: "jsx";
304
+ }>;
305
+ startLine: z.ZodNumber;
306
+ endLine: z.ZodNumber;
307
+ excerpt: z.ZodString;
308
+ boundary: z.ZodEnum<{
309
+ component: "component";
310
+ "nearby-lines": "nearby-lines";
311
+ }>;
312
+ }, z.core.$strict>>;
313
+ warnings: z.ZodArray<z.ZodString>;
314
+ }, z.core.$strict>>;
315
+ createdAt: z.ZodISODateTime;
316
+ }, z.core.$strict>;
317
+ }, z.core.$strict>;
318
+ receiptRecorded: z.ZodBoolean;
319
+ }, z.core.$strict>, z.ZodObject<{
320
+ outcome: z.ZodLiteral<"not-found">;
321
+ reason: z.ZodEnum<{
322
+ expired: "expired";
323
+ empty: "empty";
324
+ }>;
325
+ }, z.core.$strict>], "outcome">;
326
+ declare const handoffWaitDeliverySchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
327
+ outcome: z.ZodLiteral<"handoff">;
328
+ snapshot: z.ZodObject<{
329
+ schemaVersion: z.ZodLiteral<1>;
330
+ cursor: z.ZodString;
331
+ session: z.ZodObject<{
332
+ id: z.ZodString;
333
+ framework: z.ZodEnum<{
334
+ vite: "vite";
335
+ next: "next";
336
+ }>;
337
+ }, z.core.$strict>;
338
+ revision: z.ZodNumber;
339
+ publishedAt: z.ZodISODateTime;
340
+ expiresAt: z.ZodISODateTime;
341
+ annotation: z.ZodObject<{
342
+ schemaVersion: z.ZodLiteral<3>;
343
+ id: z.ZodString;
344
+ locale: z.ZodEnum<{
345
+ "en-US": "en-US";
346
+ "zh-CN": "zh-CN";
347
+ }>;
348
+ page: z.ZodObject<{
349
+ url: z.ZodString;
350
+ pathname: z.ZodString;
351
+ title: z.ZodString;
352
+ viewportWidth: z.ZodNumber;
353
+ viewportHeight: z.ZodNumber;
354
+ devicePixelRatio: z.ZodNumber;
355
+ }, z.core.$strict>;
356
+ targets: z.ZodArray<z.ZodObject<{
357
+ instruction: z.ZodString;
358
+ page: z.ZodOptional<z.ZodObject<{
359
+ url: z.ZodString;
360
+ pathname: z.ZodString;
361
+ title: z.ZodString;
362
+ viewportWidth: z.ZodNumber;
363
+ viewportHeight: z.ZodNumber;
364
+ devicePixelRatio: z.ZodNumber;
365
+ }, z.core.$strict>>;
366
+ source: z.ZodObject<{
367
+ fileId: z.ZodOptional<z.ZodString>;
368
+ relativePath: z.ZodOptional<z.ZodString>;
369
+ line: z.ZodOptional<z.ZodNumber>;
370
+ column: z.ZodOptional<z.ZodNumber>;
371
+ origin: z.ZodEnum<{
372
+ "jsx-host": "jsx-host";
373
+ "react-fiber": "react-fiber";
374
+ "dom-ancestor": "dom-ancestor";
375
+ none: "none";
376
+ }>;
377
+ confidence: z.ZodEnum<{
378
+ exact: "exact";
379
+ probable: "probable";
380
+ approximate: "approximate";
381
+ unknown: "unknown";
382
+ }>;
383
+ }, z.core.$strict>;
384
+ react: z.ZodObject<{
385
+ supported: z.ZodBoolean;
386
+ version: z.ZodOptional<z.ZodString>;
387
+ componentName: z.ZodOptional<z.ZodString>;
388
+ componentSourceId: z.ZodOptional<z.ZodString>;
389
+ sourceVersion: z.ZodOptional<z.ZodString>;
390
+ componentStack: z.ZodArray<z.ZodString>;
391
+ source: z.ZodOptional<z.ZodObject<{
392
+ fileId: z.ZodOptional<z.ZodString>;
393
+ relativePath: z.ZodOptional<z.ZodString>;
394
+ line: z.ZodOptional<z.ZodNumber>;
395
+ column: z.ZodOptional<z.ZodNumber>;
396
+ origin: z.ZodEnum<{
397
+ "jsx-host": "jsx-host";
398
+ "react-fiber": "react-fiber";
399
+ "dom-ancestor": "dom-ancestor";
400
+ none: "none";
401
+ }>;
402
+ confidence: z.ZodEnum<{
403
+ exact: "exact";
404
+ probable: "probable";
405
+ approximate: "approximate";
406
+ unknown: "unknown";
407
+ }>;
408
+ }, z.core.$strict>>;
409
+ }, z.core.$strict>;
410
+ element: z.ZodObject<{
411
+ tagName: z.ZodString;
412
+ selector: z.ZodString;
413
+ sanitizedHtml: z.ZodString;
414
+ textPreview: z.ZodOptional<z.ZodString>;
415
+ role: z.ZodOptional<z.ZodString>;
416
+ rect: z.ZodObject<{
417
+ x: z.ZodNumber;
418
+ y: z.ZodNumber;
419
+ width: z.ZodNumber;
420
+ height: z.ZodNumber;
421
+ }, z.core.$strict>;
422
+ }, z.core.$strict>;
423
+ styles: z.ZodObject<{
424
+ classNames: z.ZodArray<z.ZodString>;
425
+ inlineStyle: z.ZodOptional<z.ZodString>;
426
+ matchedRules: z.ZodArray<z.ZodObject<{
427
+ selector: z.ZodString;
428
+ declarations: z.ZodString;
429
+ source: z.ZodOptional<z.ZodString>;
430
+ media: z.ZodOptional<z.ZodString>;
431
+ }, z.core.$strict>>;
432
+ computed: z.ZodRecord<z.ZodString, z.ZodString>;
433
+ warnings: z.ZodArray<z.ZodString>;
434
+ }, z.core.$strict>;
435
+ code: z.ZodOptional<z.ZodObject<{
436
+ relativePath: z.ZodString;
437
+ language: z.ZodEnum<{
438
+ tsx: "tsx";
439
+ jsx: "jsx";
440
+ }>;
441
+ startLine: z.ZodNumber;
442
+ endLine: z.ZodNumber;
443
+ excerpt: z.ZodString;
444
+ boundary: z.ZodEnum<{
445
+ component: "component";
446
+ "nearby-lines": "nearby-lines";
447
+ }>;
448
+ }, z.core.$strict>>;
449
+ warnings: z.ZodArray<z.ZodString>;
450
+ }, z.core.$strict>>;
451
+ createdAt: z.ZodISODateTime;
452
+ }, z.core.$strict>;
453
+ }, z.core.$strict>;
454
+ receiptRecorded: z.ZodBoolean;
455
+ }, z.core.$strict>, z.ZodObject<{
456
+ outcome: z.ZodLiteral<"timeout">;
457
+ }, z.core.$strict>], "outcome">;
458
+ type ExternalAgentSessionListItem = z.infer<typeof sessionListItemSchema>;
459
+ type HandoffDelivery = z.infer<typeof handoffDeliverySchema>;
460
+ type CurrentHandoffDelivery = z.infer<typeof currentHandoffDeliverySchema>;
461
+ type HandoffWaitDelivery = z.infer<typeof handoffWaitDeliverySchema>;
462
+ interface SpotPatchBridgeClient extends ActiveBridgeClient {
463
+ readonly ack: (cursor: string, sessionId?: string, signal?: AbortSignal) => Promise<ExternalHandoffSummary>;
464
+ readonly current: (sessionId?: string, cursor?: string, signal?: AbortSignal) => Promise<CurrentHandoffDelivery>;
465
+ readonly sessions: () => Promise<readonly ExternalAgentSessionListItem[]>;
466
+ readonly wait: (sessionId?: string, afterCursor?: string, timeoutMs?: number, signal?: AbortSignal) => Promise<HandoffWaitDelivery>;
467
+ }
468
+ declare function createSpotPatchBridgeClient(cwd?: string): SpotPatchBridgeClient;
469
+
470
+ type BridgeCliAdapter = "bridge" | "next" | "vite";
471
+ type BridgeSetupClient = "claude" | "codex" | "cursor";
472
+ type BridgeSetupMode = "active" | "inbox";
473
+ interface BridgeMcpServerConfiguration {
474
+ readonly args: readonly string[];
475
+ readonly command: "node";
476
+ }
477
+ interface BridgeSetupPlan {
478
+ readonly client: BridgeSetupClient;
479
+ readonly content: string;
480
+ readonly legacyCodexContent?: string;
481
+ readonly legacySpotPatch?: BridgeMcpServerConfiguration;
482
+ readonly mode: BridgeSetupMode;
483
+ readonly path: string;
484
+ }
485
+ declare function createBridgeSetupPlan(client: BridgeSetupClient, adapter: BridgeCliAdapter, cwd?: string, mode?: BridgeSetupMode): BridgeSetupPlan;
486
+ declare function applyBridgeSetupPlan(plan: BridgeSetupPlan): Promise<"created" | "unchanged" | "updated">;
487
+
488
+ interface RunSpotPatchBridgeCliOptions {
489
+ readonly adapter?: BridgeCliAdapter;
490
+ readonly cwd?: string;
491
+ readonly stderr?: Pick<NodeJS.WriteStream, "write">;
492
+ readonly stdout?: Pick<NodeJS.WriteStream, "write">;
493
+ }
494
+ declare function runSpotPatchBridgeCli(arguments_: readonly string[], options?: RunSpotPatchBridgeCliOptions): Promise<number>;
495
+
496
+ interface SpotPatchMcpScope {
497
+ readonly sessionId?: string | undefined;
498
+ }
499
+ declare function createSpotPatchMcpServer(cwd?: string, scope?: SpotPatchMcpScope): McpServer;
500
+ declare function serveSpotPatchMcp(cwd?: string, scope?: SpotPatchMcpScope): StdioServerHandle;
501
+
502
+ export { type BridgeCliAdapter, type BridgeSetupClient, type BridgeSetupMode, type BridgeSetupPlan, type ExternalAgentSessionListItem, type HandoffDelivery, type HandoffWaitDelivery, type RunSpotPatchBridgeCliOptions, type SpotPatchBridgeClient, applyBridgeSetupPlan, createBridgeSetupPlan, createSpotPatchBridgeClient, createSpotPatchMcpServer, runSpotPatchBridgeCli, serveSpotPatchMcp };