@brainferno/mcp-bridge-protocol 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.
package/dist/apps.d.ts ADDED
@@ -0,0 +1,50 @@
1
+ /**
2
+ * The five Creative Cloud hosts this server drives: which *lane* reaches each
3
+ * one, which in-app *panel* (if any) it needs, and which scripting *engine*
4
+ * runs the work.
5
+ *
6
+ * There is no single automation surface across all five, so the server routes
7
+ * each app down one of three lanes:
8
+ * - "socket": an in-app panel dials out to the bridge hub. Photoshop and
9
+ * Premiere Pro use a UXP panel; After Effects and Audition use
10
+ * a CEP panel. UXP plugins cannot listen on a socket, so the
11
+ * panel is always the client and the hub the server.
12
+ * - "os-script": no panel — the server injects ExtendScript from outside via
13
+ * `osascript 'do javascript'` (macOS) or COM `DoJavaScript`
14
+ * (Windows). Illustrator has no public UXP, so this is its only
15
+ * complete surface.
16
+ *
17
+ * This mapping is deliberate and current (2026): Illustrator UXP is Adobe
18
+ * internal-only, and Premiere's ExtendScript/CEP surface is being removed in
19
+ * favor of UXP — so Premiere is UXP and Illustrator is os-script ExtendScript,
20
+ * not the other way around.
21
+ */
22
+ export declare const APP_IDS: readonly ["after_effects", "premiere", "photoshop", "illustrator", "audition"];
23
+ export type AppId = (typeof APP_IDS)[number];
24
+ /** How the server reaches a host. */
25
+ export type Lane = "socket" | "os-script";
26
+ /** Which in-app panel technology hosts the bridge client, when there is one. */
27
+ export type PanelKind = "uxp" | "cep";
28
+ /** Which scripting engine the host's commands ultimately run in. */
29
+ export type ScriptEngine = "uxp-batchplay" | "premierepro-api" | "extendscript";
30
+ export interface AppInfo {
31
+ id: AppId;
32
+ /** Human-readable name, used in tool descriptions and error messages. */
33
+ displayName: string;
34
+ lane: Lane;
35
+ /** The panel that dials into the hub, for socket-lane apps. */
36
+ panel?: PanelKind;
37
+ engine: ScriptEngine;
38
+ /**
39
+ * Application name as AppleScript sees it, for the macOS os-script lane.
40
+ * Undefined where no such lane exists.
41
+ */
42
+ appleScriptName?: string;
43
+ /**
44
+ * Windows COM ProgID for the os-script lane. Bind a versioned ProgID at
45
+ * runtime (e.g. "Illustrator.Application.30") when multiple versions coexist.
46
+ */
47
+ winProgId?: string;
48
+ }
49
+ export declare const APPS: Record<AppId, AppInfo>;
50
+ export declare function appInfo(id: AppId): AppInfo;
package/dist/apps.js ADDED
@@ -0,0 +1,71 @@
1
+ /**
2
+ * The five Creative Cloud hosts this server drives: which *lane* reaches each
3
+ * one, which in-app *panel* (if any) it needs, and which scripting *engine*
4
+ * runs the work.
5
+ *
6
+ * There is no single automation surface across all five, so the server routes
7
+ * each app down one of three lanes:
8
+ * - "socket": an in-app panel dials out to the bridge hub. Photoshop and
9
+ * Premiere Pro use a UXP panel; After Effects and Audition use
10
+ * a CEP panel. UXP plugins cannot listen on a socket, so the
11
+ * panel is always the client and the hub the server.
12
+ * - "os-script": no panel — the server injects ExtendScript from outside via
13
+ * `osascript 'do javascript'` (macOS) or COM `DoJavaScript`
14
+ * (Windows). Illustrator has no public UXP, so this is its only
15
+ * complete surface.
16
+ *
17
+ * This mapping is deliberate and current (2026): Illustrator UXP is Adobe
18
+ * internal-only, and Premiere's ExtendScript/CEP surface is being removed in
19
+ * favor of UXP — so Premiere is UXP and Illustrator is os-script ExtendScript,
20
+ * not the other way around.
21
+ */
22
+ export const APP_IDS = ["after_effects", "premiere", "photoshop", "illustrator", "audition"];
23
+ export const APPS = {
24
+ after_effects: {
25
+ id: "after_effects",
26
+ displayName: "After Effects",
27
+ lane: "socket",
28
+ panel: "cep",
29
+ engine: "extendscript",
30
+ // os-script is a documented emergency fallback, not the primary lane.
31
+ appleScriptName: "Adobe After Effects",
32
+ },
33
+ premiere: {
34
+ id: "premiere",
35
+ displayName: "Premiere Pro",
36
+ lane: "socket",
37
+ panel: "uxp",
38
+ engine: "premierepro-api",
39
+ // No appleScriptName / winProgId: Premiere has no AppleScript or COM DOM.
40
+ },
41
+ audition: {
42
+ id: "audition",
43
+ displayName: "Audition",
44
+ lane: "socket",
45
+ panel: "cep",
46
+ engine: "extendscript",
47
+ // No appleScriptName / winProgId: Audition has no AppleScript or COM DOM.
48
+ },
49
+ photoshop: {
50
+ id: "photoshop",
51
+ displayName: "Photoshop",
52
+ lane: "socket",
53
+ panel: "uxp",
54
+ engine: "uxp-batchplay",
55
+ // COM/AppleScript ExtendScript is a possible fallback lane, not primary.
56
+ appleScriptName: "Adobe Photoshop",
57
+ winProgId: "Photoshop.Application",
58
+ },
59
+ illustrator: {
60
+ id: "illustrator",
61
+ displayName: "Illustrator",
62
+ lane: "os-script",
63
+ engine: "extendscript",
64
+ appleScriptName: "Adobe Illustrator",
65
+ winProgId: "Illustrator.Application",
66
+ },
67
+ };
68
+ export function appInfo(id) {
69
+ return APPS[id];
70
+ }
71
+ //# sourceMappingURL=apps.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"apps.js","sourceRoot":"","sources":["../src/apps.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AAEH,MAAM,CAAC,MAAM,OAAO,GAAG,CAAC,eAAe,EAAE,UAAU,EAAE,WAAW,EAAE,aAAa,EAAE,UAAU,CAAU,CAAC;AA+BtG,MAAM,CAAC,MAAM,IAAI,GAA2B;IAC1C,aAAa,EAAE;QACb,EAAE,EAAE,eAAe;QACnB,WAAW,EAAE,eAAe;QAC5B,IAAI,EAAE,QAAQ;QACd,KAAK,EAAE,KAAK;QACZ,MAAM,EAAE,cAAc;QACtB,sEAAsE;QACtE,eAAe,EAAE,qBAAqB;KACvC;IACD,QAAQ,EAAE;QACR,EAAE,EAAE,UAAU;QACd,WAAW,EAAE,cAAc;QAC3B,IAAI,EAAE,QAAQ;QACd,KAAK,EAAE,KAAK;QACZ,MAAM,EAAE,iBAAiB;QACzB,0EAA0E;KAC3E;IACD,QAAQ,EAAE;QACR,EAAE,EAAE,UAAU;QACd,WAAW,EAAE,UAAU;QACvB,IAAI,EAAE,QAAQ;QACd,KAAK,EAAE,KAAK;QACZ,MAAM,EAAE,cAAc;QACtB,0EAA0E;KAC3E;IACD,SAAS,EAAE;QACT,EAAE,EAAE,WAAW;QACf,WAAW,EAAE,WAAW;QACxB,IAAI,EAAE,QAAQ;QACd,KAAK,EAAE,KAAK;QACZ,MAAM,EAAE,eAAe;QACvB,yEAAyE;QACzE,eAAe,EAAE,iBAAiB;QAClC,SAAS,EAAE,uBAAuB;KACnC;IACD,WAAW,EAAE;QACX,EAAE,EAAE,aAAa;QACjB,WAAW,EAAE,aAAa;QAC1B,IAAI,EAAE,WAAW;QACjB,MAAM,EAAE,cAAc;QACtB,eAAe,EAAE,mBAAmB;QACpC,SAAS,EAAE,yBAAyB;KACrC;CACF,CAAC;AAEF,MAAM,UAAU,OAAO,CAAC,EAAS;IAC/B,OAAO,IAAI,CAAC,EAAE,CAAC,CAAC;AAClB,CAAC"}
@@ -0,0 +1,7 @@
1
+ /**
2
+ * @brainferno/mcp-bridge-protocol — the frozen contract shared by the server and every
3
+ * in-app panel: the five hosts, and the v2 wire frames (zod-validated).
4
+ * See docs/protocol.md. Changes here ripple into every panel.
5
+ */
6
+ export * from "./apps.js";
7
+ export * from "./protocol.js";
package/dist/index.js ADDED
@@ -0,0 +1,8 @@
1
+ /**
2
+ * @brainferno/mcp-bridge-protocol — the frozen contract shared by the server and every
3
+ * in-app panel: the five hosts, and the v2 wire frames (zod-validated).
4
+ * See docs/protocol.md. Changes here ripple into every panel.
5
+ */
6
+ export * from "./apps.js";
7
+ export * from "./protocol.js";
8
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,cAAc,WAAW,CAAC;AAC1B,cAAc,eAAe,CAAC"}
@@ -0,0 +1,341 @@
1
+ /**
2
+ * Wire protocol (v2) between this server's hub and the companion panel running
3
+ * inside each Creative Cloud application.
4
+ *
5
+ * The panel is the client: it dials in to the bridge port, announces which
6
+ * application it lives in (and authenticates), then waits for commands. Keeping
7
+ * the panel on the connecting side is not a preference — UXP plugins cannot
8
+ * listen on a socket, only dial out — and it keeps the one listener the whole
9
+ * system trusts on the server side, where it can be hardened.
10
+ *
11
+ * Commands are *named*, not raw script: the server sends `{name, params}` and
12
+ * the panel maps the name to a local function. UXP restricts `eval`, and the
13
+ * Premiere UXP API has no script engine at all, so shipping script strings does
14
+ * not work there. The generic `eval` command (params `{script}`) is the escape
15
+ * hatch panels on an ExtendScript engine implement via `evalScript`, which is a
16
+ * host API rather than JS `eval`.
17
+ *
18
+ * Every panel->server frame is validated against a zod schema before use; the
19
+ * hub never trusts the shape of a frame from the wire.
20
+ */
21
+ import { z } from "zod";
22
+ export declare const PROTOCOL_VERSION = 2;
23
+ /** How long the server will wait for a command result, by command weight. */
24
+ export type TimeoutClass = "fast" | "slow" | "render";
25
+ /** Panel -> server, the first frame on every connection (within the deadline). */
26
+ export declare const helloFrameSchema: z.ZodObject<{
27
+ type: z.ZodLiteral<"hello">;
28
+ protocolVersion: z.ZodNumber;
29
+ appId: z.ZodEnum<["after_effects", "premiere", "photoshop", "illustrator", "audition"]>;
30
+ /** Host build string, e.g. "24.6.1" — informational. */
31
+ hostVersion: z.ZodOptional<z.ZodString>;
32
+ /** Panel plugin version, so the server can detect version drift. */
33
+ panelVersion: z.ZodOptional<z.ZodString>;
34
+ /** Shared secret; may instead ride the upgrade URL as `?token=`. */
35
+ token: z.ZodOptional<z.ZodString>;
36
+ /** Command names this panel implements, for capability gating. */
37
+ capabilities: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
38
+ }, "strip", z.ZodTypeAny, {
39
+ type: "hello";
40
+ protocolVersion: number;
41
+ appId: "after_effects" | "premiere" | "photoshop" | "illustrator" | "audition";
42
+ hostVersion?: string | undefined;
43
+ panelVersion?: string | undefined;
44
+ token?: string | undefined;
45
+ capabilities?: string[] | undefined;
46
+ }, {
47
+ type: "hello";
48
+ protocolVersion: number;
49
+ appId: "after_effects" | "premiere" | "photoshop" | "illustrator" | "audition";
50
+ hostVersion?: string | undefined;
51
+ panelVersion?: string | undefined;
52
+ token?: string | undefined;
53
+ capabilities?: string[] | undefined;
54
+ }>;
55
+ /** Panel -> server, the outcome of one command. */
56
+ export declare const resultFrameSchema: z.ZodObject<{
57
+ type: z.ZodLiteral<"result">;
58
+ id: z.ZodString;
59
+ ok: z.ZodBoolean;
60
+ value: z.ZodOptional<z.ZodUnknown>;
61
+ error: z.ZodOptional<z.ZodObject<{
62
+ code: z.ZodString;
63
+ message: z.ZodString;
64
+ line: z.ZodOptional<z.ZodNumber>;
65
+ }, "strip", z.ZodTypeAny, {
66
+ code: string;
67
+ message: string;
68
+ line?: number | undefined;
69
+ }, {
70
+ code: string;
71
+ message: string;
72
+ line?: number | undefined;
73
+ }>>;
74
+ /** Cheap state snapshot returned on mutations, to keep the agent oriented. */
75
+ appState: z.ZodOptional<z.ZodObject<{
76
+ activeDocument: z.ZodOptional<z.ZodNullable<z.ZodString>>;
77
+ selection: z.ZodOptional<z.ZodUnknown>;
78
+ dirty: z.ZodOptional<z.ZodBoolean>;
79
+ }, "strip", z.ZodTypeAny, {
80
+ dirty?: boolean | undefined;
81
+ activeDocument?: string | null | undefined;
82
+ selection?: unknown;
83
+ }, {
84
+ dirty?: boolean | undefined;
85
+ activeDocument?: string | null | undefined;
86
+ selection?: unknown;
87
+ }>>;
88
+ }, "strip", z.ZodTypeAny, {
89
+ type: "result";
90
+ id: string;
91
+ ok: boolean;
92
+ value?: unknown;
93
+ error?: {
94
+ code: string;
95
+ message: string;
96
+ line?: number | undefined;
97
+ } | undefined;
98
+ appState?: {
99
+ dirty?: boolean | undefined;
100
+ activeDocument?: string | null | undefined;
101
+ selection?: unknown;
102
+ } | undefined;
103
+ }, {
104
+ type: "result";
105
+ id: string;
106
+ ok: boolean;
107
+ value?: unknown;
108
+ error?: {
109
+ code: string;
110
+ message: string;
111
+ line?: number | undefined;
112
+ } | undefined;
113
+ appState?: {
114
+ dirty?: boolean | undefined;
115
+ activeDocument?: string | null | undefined;
116
+ selection?: unknown;
117
+ } | undefined;
118
+ }>;
119
+ /** Panel -> server, incremental progress for a long-running command. */
120
+ export declare const progressFrameSchema: z.ZodObject<{
121
+ type: z.ZodLiteral<"progress">;
122
+ id: z.ZodString;
123
+ progress: z.ZodOptional<z.ZodNumber>;
124
+ total: z.ZodOptional<z.ZodNumber>;
125
+ message: z.ZodOptional<z.ZodString>;
126
+ }, "strip", z.ZodTypeAny, {
127
+ type: "progress";
128
+ id: string;
129
+ message?: string | undefined;
130
+ progress?: number | undefined;
131
+ total?: number | undefined;
132
+ }, {
133
+ type: "progress";
134
+ id: string;
135
+ message?: string | undefined;
136
+ progress?: number | undefined;
137
+ total?: number | undefined;
138
+ }>;
139
+ /** Panel -> server, liveness. */
140
+ export declare const pongFrameSchema: z.ZodObject<{
141
+ type: z.ZodLiteral<"pong">;
142
+ ts: z.ZodOptional<z.ZodNumber>;
143
+ }, "strip", z.ZodTypeAny, {
144
+ type: "pong";
145
+ ts?: number | undefined;
146
+ }, {
147
+ type: "pong";
148
+ ts?: number | undefined;
149
+ }>;
150
+ export declare const pingFrameSchema: z.ZodObject<{
151
+ type: z.ZodLiteral<"ping">;
152
+ ts: z.ZodOptional<z.ZodNumber>;
153
+ }, "strip", z.ZodTypeAny, {
154
+ type: "ping";
155
+ ts?: number | undefined;
156
+ }, {
157
+ type: "ping";
158
+ ts?: number | undefined;
159
+ }>;
160
+ /** Panel -> server, graceful shutdown (e.g. the kill switch was engaged). */
161
+ export declare const byeFrameSchema: z.ZodObject<{
162
+ type: z.ZodLiteral<"bye">;
163
+ reason: z.ZodOptional<z.ZodString>;
164
+ }, "strip", z.ZodTypeAny, {
165
+ type: "bye";
166
+ reason?: string | undefined;
167
+ }, {
168
+ type: "bye";
169
+ reason?: string | undefined;
170
+ }>;
171
+ declare const panelFrameSchema: z.ZodDiscriminatedUnion<"type", [z.ZodObject<{
172
+ type: z.ZodLiteral<"hello">;
173
+ protocolVersion: z.ZodNumber;
174
+ appId: z.ZodEnum<["after_effects", "premiere", "photoshop", "illustrator", "audition"]>;
175
+ /** Host build string, e.g. "24.6.1" — informational. */
176
+ hostVersion: z.ZodOptional<z.ZodString>;
177
+ /** Panel plugin version, so the server can detect version drift. */
178
+ panelVersion: z.ZodOptional<z.ZodString>;
179
+ /** Shared secret; may instead ride the upgrade URL as `?token=`. */
180
+ token: z.ZodOptional<z.ZodString>;
181
+ /** Command names this panel implements, for capability gating. */
182
+ capabilities: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
183
+ }, "strip", z.ZodTypeAny, {
184
+ type: "hello";
185
+ protocolVersion: number;
186
+ appId: "after_effects" | "premiere" | "photoshop" | "illustrator" | "audition";
187
+ hostVersion?: string | undefined;
188
+ panelVersion?: string | undefined;
189
+ token?: string | undefined;
190
+ capabilities?: string[] | undefined;
191
+ }, {
192
+ type: "hello";
193
+ protocolVersion: number;
194
+ appId: "after_effects" | "premiere" | "photoshop" | "illustrator" | "audition";
195
+ hostVersion?: string | undefined;
196
+ panelVersion?: string | undefined;
197
+ token?: string | undefined;
198
+ capabilities?: string[] | undefined;
199
+ }>, z.ZodObject<{
200
+ type: z.ZodLiteral<"result">;
201
+ id: z.ZodString;
202
+ ok: z.ZodBoolean;
203
+ value: z.ZodOptional<z.ZodUnknown>;
204
+ error: z.ZodOptional<z.ZodObject<{
205
+ code: z.ZodString;
206
+ message: z.ZodString;
207
+ line: z.ZodOptional<z.ZodNumber>;
208
+ }, "strip", z.ZodTypeAny, {
209
+ code: string;
210
+ message: string;
211
+ line?: number | undefined;
212
+ }, {
213
+ code: string;
214
+ message: string;
215
+ line?: number | undefined;
216
+ }>>;
217
+ /** Cheap state snapshot returned on mutations, to keep the agent oriented. */
218
+ appState: z.ZodOptional<z.ZodObject<{
219
+ activeDocument: z.ZodOptional<z.ZodNullable<z.ZodString>>;
220
+ selection: z.ZodOptional<z.ZodUnknown>;
221
+ dirty: z.ZodOptional<z.ZodBoolean>;
222
+ }, "strip", z.ZodTypeAny, {
223
+ dirty?: boolean | undefined;
224
+ activeDocument?: string | null | undefined;
225
+ selection?: unknown;
226
+ }, {
227
+ dirty?: boolean | undefined;
228
+ activeDocument?: string | null | undefined;
229
+ selection?: unknown;
230
+ }>>;
231
+ }, "strip", z.ZodTypeAny, {
232
+ type: "result";
233
+ id: string;
234
+ ok: boolean;
235
+ value?: unknown;
236
+ error?: {
237
+ code: string;
238
+ message: string;
239
+ line?: number | undefined;
240
+ } | undefined;
241
+ appState?: {
242
+ dirty?: boolean | undefined;
243
+ activeDocument?: string | null | undefined;
244
+ selection?: unknown;
245
+ } | undefined;
246
+ }, {
247
+ type: "result";
248
+ id: string;
249
+ ok: boolean;
250
+ value?: unknown;
251
+ error?: {
252
+ code: string;
253
+ message: string;
254
+ line?: number | undefined;
255
+ } | undefined;
256
+ appState?: {
257
+ dirty?: boolean | undefined;
258
+ activeDocument?: string | null | undefined;
259
+ selection?: unknown;
260
+ } | undefined;
261
+ }>, z.ZodObject<{
262
+ type: z.ZodLiteral<"progress">;
263
+ id: z.ZodString;
264
+ progress: z.ZodOptional<z.ZodNumber>;
265
+ total: z.ZodOptional<z.ZodNumber>;
266
+ message: z.ZodOptional<z.ZodString>;
267
+ }, "strip", z.ZodTypeAny, {
268
+ type: "progress";
269
+ id: string;
270
+ message?: string | undefined;
271
+ progress?: number | undefined;
272
+ total?: number | undefined;
273
+ }, {
274
+ type: "progress";
275
+ id: string;
276
+ message?: string | undefined;
277
+ progress?: number | undefined;
278
+ total?: number | undefined;
279
+ }>, z.ZodObject<{
280
+ type: z.ZodLiteral<"pong">;
281
+ ts: z.ZodOptional<z.ZodNumber>;
282
+ }, "strip", z.ZodTypeAny, {
283
+ type: "pong";
284
+ ts?: number | undefined;
285
+ }, {
286
+ type: "pong";
287
+ ts?: number | undefined;
288
+ }>, z.ZodObject<{
289
+ type: z.ZodLiteral<"ping">;
290
+ ts: z.ZodOptional<z.ZodNumber>;
291
+ }, "strip", z.ZodTypeAny, {
292
+ type: "ping";
293
+ ts?: number | undefined;
294
+ }, {
295
+ type: "ping";
296
+ ts?: number | undefined;
297
+ }>, z.ZodObject<{
298
+ type: z.ZodLiteral<"bye">;
299
+ reason: z.ZodOptional<z.ZodString>;
300
+ }, "strip", z.ZodTypeAny, {
301
+ type: "bye";
302
+ reason?: string | undefined;
303
+ }, {
304
+ type: "bye";
305
+ reason?: string | undefined;
306
+ }>]>;
307
+ export type HelloFrame = z.infer<typeof helloFrameSchema>;
308
+ export type ResultFrame = z.infer<typeof resultFrameSchema>;
309
+ export type ProgressFrame = z.infer<typeof progressFrameSchema>;
310
+ export type PanelFrame = z.infer<typeof panelFrameSchema>;
311
+ /** Server -> panel, accepting the hello. */
312
+ export interface WelcomeFrame {
313
+ type: "welcome";
314
+ protocolVersion: number;
315
+ serverVersion: string;
316
+ heartbeatIntervalMs: number;
317
+ }
318
+ /** Server -> panel, a named command to run. */
319
+ export interface CmdFrame {
320
+ type: "cmd";
321
+ id: string;
322
+ name: string;
323
+ params: unknown;
324
+ timeoutClass: TimeoutClass;
325
+ }
326
+ export interface ServerPingFrame {
327
+ type: "ping";
328
+ ts: number;
329
+ }
330
+ export interface ServerByeFrame {
331
+ type: "bye";
332
+ reason: string;
333
+ }
334
+ export type ServerFrame = WelcomeFrame | CmdFrame | ServerPingFrame | ServerByeFrame;
335
+ /**
336
+ * Parses and validates a raw text frame from a panel. Throws a descriptive
337
+ * Error on anything that is not a well-formed panel frame — callers drop the
338
+ * frame rather than trusting a partially-shaped object.
339
+ */
340
+ export declare function parsePanelFrame(raw: string): PanelFrame;
341
+ export {};
@@ -0,0 +1,98 @@
1
+ /**
2
+ * Wire protocol (v2) between this server's hub and the companion panel running
3
+ * inside each Creative Cloud application.
4
+ *
5
+ * The panel is the client: it dials in to the bridge port, announces which
6
+ * application it lives in (and authenticates), then waits for commands. Keeping
7
+ * the panel on the connecting side is not a preference — UXP plugins cannot
8
+ * listen on a socket, only dial out — and it keeps the one listener the whole
9
+ * system trusts on the server side, where it can be hardened.
10
+ *
11
+ * Commands are *named*, not raw script: the server sends `{name, params}` and
12
+ * the panel maps the name to a local function. UXP restricts `eval`, and the
13
+ * Premiere UXP API has no script engine at all, so shipping script strings does
14
+ * not work there. The generic `eval` command (params `{script}`) is the escape
15
+ * hatch panels on an ExtendScript engine implement via `evalScript`, which is a
16
+ * host API rather than JS `eval`.
17
+ *
18
+ * Every panel->server frame is validated against a zod schema before use; the
19
+ * hub never trusts the shape of a frame from the wire.
20
+ */
21
+ import { z } from "zod";
22
+ import { APP_IDS } from "./apps.js";
23
+ export const PROTOCOL_VERSION = 2;
24
+ const errorSchema = z.object({
25
+ code: z.string(),
26
+ message: z.string(),
27
+ line: z.number().int().optional(),
28
+ });
29
+ const appStateSchema = z.object({
30
+ activeDocument: z.string().nullable().optional(),
31
+ selection: z.unknown().optional(),
32
+ dirty: z.boolean().optional(),
33
+ });
34
+ /** Panel -> server, the first frame on every connection (within the deadline). */
35
+ export const helloFrameSchema = z.object({
36
+ type: z.literal("hello"),
37
+ protocolVersion: z.number().int(),
38
+ appId: z.enum(APP_IDS),
39
+ /** Host build string, e.g. "24.6.1" — informational. */
40
+ hostVersion: z.string().optional(),
41
+ /** Panel plugin version, so the server can detect version drift. */
42
+ panelVersion: z.string().optional(),
43
+ /** Shared secret; may instead ride the upgrade URL as `?token=`. */
44
+ token: z.string().optional(),
45
+ /** Command names this panel implements, for capability gating. */
46
+ capabilities: z.array(z.string()).optional(),
47
+ });
48
+ /** Panel -> server, the outcome of one command. */
49
+ export const resultFrameSchema = z.object({
50
+ type: z.literal("result"),
51
+ id: z.string(),
52
+ ok: z.boolean(),
53
+ value: z.unknown().optional(),
54
+ error: errorSchema.optional(),
55
+ /** Cheap state snapshot returned on mutations, to keep the agent oriented. */
56
+ appState: appStateSchema.optional(),
57
+ });
58
+ /** Panel -> server, incremental progress for a long-running command. */
59
+ export const progressFrameSchema = z.object({
60
+ type: z.literal("progress"),
61
+ id: z.string(),
62
+ progress: z.number().optional(),
63
+ total: z.number().optional(),
64
+ message: z.string().optional(),
65
+ });
66
+ /** Panel -> server, liveness. */
67
+ export const pongFrameSchema = z.object({ type: z.literal("pong"), ts: z.number().optional() });
68
+ export const pingFrameSchema = z.object({ type: z.literal("ping"), ts: z.number().optional() });
69
+ /** Panel -> server, graceful shutdown (e.g. the kill switch was engaged). */
70
+ export const byeFrameSchema = z.object({ type: z.literal("bye"), reason: z.string().optional() });
71
+ const panelFrameSchema = z.discriminatedUnion("type", [
72
+ helloFrameSchema,
73
+ resultFrameSchema,
74
+ progressFrameSchema,
75
+ pongFrameSchema,
76
+ pingFrameSchema,
77
+ byeFrameSchema,
78
+ ]);
79
+ /**
80
+ * Parses and validates a raw text frame from a panel. Throws a descriptive
81
+ * Error on anything that is not a well-formed panel frame — callers drop the
82
+ * frame rather than trusting a partially-shaped object.
83
+ */
84
+ export function parsePanelFrame(raw) {
85
+ let parsed;
86
+ try {
87
+ parsed = JSON.parse(raw);
88
+ }
89
+ catch {
90
+ throw new Error("frame was not valid JSON");
91
+ }
92
+ const result = panelFrameSchema.safeParse(parsed);
93
+ if (!result.success) {
94
+ throw new Error(`invalid panel frame: ${result.error.issues.map((i) => i.message).join("; ")}`);
95
+ }
96
+ return result.data;
97
+ }
98
+ //# sourceMappingURL=protocol.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"protocol.js","sourceRoot":"","sources":["../src/protocol.ts"],"names":[],"mappings":"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"}
package/package.json ADDED
@@ -0,0 +1,33 @@
1
+ {
2
+ "name": "@brainferno/mcp-bridge-protocol",
3
+ "version": "0.1.0",
4
+ "description": "Shared hosts + wire protocol (v2) for brainferno-mcp-bridge",
5
+ "type": "module",
6
+ "main": "./dist/index.js",
7
+ "types": "./dist/index.d.ts",
8
+ "exports": {
9
+ ".": {
10
+ "types": "./dist/index.d.ts",
11
+ "import": "./dist/index.js"
12
+ }
13
+ },
14
+ "files": [
15
+ "dist"
16
+ ],
17
+ "scripts": {
18
+ "build": "tsc -p tsconfig.build.json"
19
+ },
20
+ "dependencies": {
21
+ "zod": "^3.25.76"
22
+ },
23
+ "license": "Apache-2.0",
24
+ "author": "Vincent Parker (Brainferno, LLC)",
25
+ "repository": {
26
+ "type": "git",
27
+ "url": "git+https://github.com/Brainferno/brainferno-mcp-bridge.git",
28
+ "directory": "packages/protocol"
29
+ },
30
+ "publishConfig": {
31
+ "access": "public"
32
+ }
33
+ }