@standardagents/code 0.14.1-issue.650.d27328-linux-x64-gnu → 0.14.1-issue.650.d27328

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.
@@ -1,1561 +0,0 @@
1
- import { createRequire as __standardCreateRequire } from 'node:module'; import { fileURLToPath as __standardFileURLToPath } from 'node:url'; import { dirname as __standardDirname } from 'node:path'; const require = __standardCreateRequire(import.meta.url); const __filename = __standardFileURLToPath(import.meta.url); const __dirname = __standardDirname(__filename);
2
-
3
- // src/worker.mjs
4
- import { parentPort, workerData } from "node:worker_threads";
5
- import { pathToFileURL } from "node:url";
6
-
7
- // ../plugin-sdk/src/manifest.mjs
8
- var CAPABILITIES = Object.freeze([
9
- "surfaces",
10
- "events",
11
- "hooks",
12
- "panes",
13
- "projects",
14
- "notifications",
15
- "url",
16
- "fetch",
17
- "secrets",
18
- "webhook"
19
- ]);
20
- var SURFACE_KINDS = Object.freeze([
21
- "section",
22
- "card",
23
- "slot",
24
- "badge",
25
- "panel",
26
- "overlay",
27
- "menu",
28
- "command",
29
- "key",
30
- "link"
31
- ]);
32
- var PRESENTATIONS = Object.freeze(["popover", "column", "pane"]);
33
- var ANCHORS = Object.freeze([
34
- "plugins",
35
- "machine.before",
36
- "machine.after",
37
- "project.before",
38
- "project.after",
39
- "pane.header",
40
- "pane.footer",
41
- "account",
42
- "machine",
43
- "project",
44
- "pane",
45
- "section"
46
- ]);
47
- var LIMITS = Object.freeze({
48
- manifestBytes: 65536,
49
- frameBytes: 262144,
50
- responseFrameBytes: 64 * 1024 * 1024,
51
- pendingRequests: 128,
52
- subscriptions: 256,
53
- schedules: 128,
54
- contributions: 256,
55
- queuedBytes: 4 * 1024 * 1024,
56
- hookTimeoutMs: 6e4,
57
- requestTimeoutMs: 3e4,
58
- canvasColumns: 512,
59
- canvasRows: 256,
60
- canvasHoverBytes: 512,
61
- stateKeys: 256,
62
- stateValueBytes: 64 * 1024
63
- });
64
- var PluginError = class extends Error {
65
- constructor(code, message) {
66
- super(message);
67
- this.name = "PluginError";
68
- this.code = code;
69
- }
70
- };
71
- function ensure(condition, code, message) {
72
- if (!condition) throw new PluginError(code, message);
73
- }
74
- function object(value) {
75
- return value !== null && typeof value === "object" && !Array.isArray(value);
76
- }
77
- function identifier(value) {
78
- return typeof value === "string" && /^[a-zA-Z0-9][a-zA-Z0-9._-]{0,127}$/.test(value);
79
- }
80
- function jsonBytes(value, limit = LIMITS.frameBytes) {
81
- const seen = /* @__PURE__ */ new Set();
82
- function visit(item, depth) {
83
- ensure(depth <= 32, "invalid_payload", "JSON nesting exceeds 32 levels");
84
- if (item === null || typeof item === "string" || typeof item === "boolean") return;
85
- if (typeof item === "number") {
86
- ensure(Number.isFinite(item), "invalid_payload", "JSON numbers must be finite");
87
- return;
88
- }
89
- ensure(object(item) || Array.isArray(item), "invalid_payload", "Payload must contain JSON values");
90
- ensure(!seen.has(item), "invalid_payload", "Payload contains a cycle");
91
- ensure(Array.isArray(item) || [Object.prototype, null].includes(Object.getPrototypeOf(item)), "invalid_payload", "Payload must contain plain objects");
92
- seen.add(item);
93
- for (const child of Object.values(item)) visit(child, depth + 1);
94
- seen.delete(item);
95
- }
96
- visit(value, 0);
97
- const text2 = JSON.stringify(value);
98
- ensure(Buffer.byteLength(text2) <= limit, "payload_too_large", `Payload exceeds ${limit} bytes`);
99
- return text2;
100
- }
101
- function freeze(value) {
102
- if (value && typeof value === "object") {
103
- Object.values(value).forEach(freeze);
104
- Object.freeze(value);
105
- }
106
- return value;
107
- }
108
- function validateManifest(value) {
109
- ensure(object(value), "invalid_manifest", "package.json must contain a standardPlugin object");
110
- jsonBytes(value, LIMITS.manifestBytes);
111
- const allowed = [
112
- "apiVersion",
113
- "id",
114
- "name",
115
- "version",
116
- "entry",
117
- "singleton",
118
- "order",
119
- "capabilities",
120
- "contributions",
121
- "configSchema",
122
- "hookTimeoutMs"
123
- ];
124
- ensure(Object.keys(value).every((key) => allowed.includes(key)), "invalid_manifest", "Unknown manifest field");
125
- const manifest = structuredClone({ singleton: false, order: 0, capabilities: [], contributions: [], hookTimeoutMs: 5e3, ...value });
126
- ensure(manifest.apiVersion === 1, "incompatible_version", "Plugin requires a different SDK API version");
127
- ensure(identifier(manifest.id), "invalid_manifest", "Plugin id must be a stable identifier");
128
- ensure(
129
- typeof manifest.name === "string" && manifest.name.trim().length > 0 && manifest.name.length <= 128,
130
- "invalid_manifest",
131
- "Plugin name is required and bounded to 128 characters"
132
- );
133
- ensure(
134
- typeof manifest.version === "string" && /^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(?:-[0-9A-Za-z.-]+)?$/.test(manifest.version),
135
- "invalid_manifest",
136
- "Plugin version must be semantic"
137
- );
138
- ensure(
139
- typeof manifest.entry === "string" && manifest.entry.length <= 512 && !/[\\\u0000?#]/.test(manifest.entry) && !manifest.entry.startsWith("/") && manifest.entry.split("/").every((part) => part && part !== "..") && /\.(?:mjs|cjs|js|mts|ts)$/.test(manifest.entry),
140
- "invalid_manifest",
141
- "Plugin entry must be a relative JavaScript or TypeScript file"
142
- );
143
- ensure(
144
- typeof manifest.singleton === "boolean" && Number.isSafeInteger(manifest.order) && Math.abs(manifest.order) <= 2147483647,
145
- "invalid_manifest",
146
- "Invalid singleton or order"
147
- );
148
- ensure(
149
- Number.isSafeInteger(manifest.hookTimeoutMs) && manifest.hookTimeoutMs > 0 && manifest.hookTimeoutMs <= LIMITS.hookTimeoutMs,
150
- "invalid_manifest",
151
- "Hook timeout must be between 1 and 60000 ms"
152
- );
153
- ensure(Array.isArray(manifest.capabilities) && manifest.capabilities.every((item) => CAPABILITIES.includes(item)) && new Set(manifest.capabilities).size === manifest.capabilities.length, "invalid_manifest", "Unknown or repeated capability");
154
- ensure(
155
- Array.isArray(manifest.contributions) && manifest.contributions.length <= LIMITS.contributions,
156
- "invalid_manifest",
157
- "Too many contributions"
158
- );
159
- const ids = /* @__PURE__ */ new Set();
160
- for (const declaration of manifest.contributions) {
161
- ensure(object(declaration) && identifier(declaration.id) && !ids.has(declaration.id) && SURFACE_KINDS.includes(declaration.kind) && ANCHORS.includes(declaration.anchor), "invalid_manifest", "Invalid contribution declaration");
162
- ids.add(declaration.id);
163
- ensure(
164
- declaration.icon === void 0 || ["card", "panel"].includes(declaration.kind) && typeof declaration.icon === "string" && /^[\uE000-\uF8FF\u{F0000}-\u{FFFFD}\u{100000}-\u{10FFFD}]$/u.test(declaration.icon),
165
- "invalid_manifest",
166
- "Card or panel icon must be one Nerd Font private-use glyph"
167
- );
168
- ensure(
169
- declaration.border === void 0 || typeof declaration.border === "boolean" && declaration.kind === "card",
170
- "invalid_manifest",
171
- "Only sidebar cards declare a boolean border preference"
172
- );
173
- for (const [key, choices] of Object.entries({
174
- merge: ["by-machine", "by-identity"],
175
- width: ["full", "half"],
176
- position: ["top", "after-open", "before-danger", "bottom"],
177
- presentation: PRESENTATIONS
178
- })) {
179
- ensure(declaration[key] === void 0 || choices.includes(declaration[key]), "invalid_manifest", `Invalid contribution ${key}`);
180
- }
181
- for (const key of ["title", "group", "chord", "pattern", "actionId"]) {
182
- ensure(
183
- declaration[key] === void 0 || typeof declaration[key] === "string" && declaration[key].length <= 512,
184
- "invalid_manifest",
185
- `Invalid contribution ${key}`
186
- );
187
- }
188
- ensure(declaration.opens === void 0 || identifier(declaration.opens), "invalid_manifest", "Invalid contribution opens");
189
- ensure(
190
- declaration.presentation === void 0 || ["panel", "card", "command"].includes(declaration.kind),
191
- "invalid_manifest",
192
- "Only panels, cards, and commands declare a presentation"
193
- );
194
- ensure(declaration.kind !== "card" || declaration.anchor === "plugins", "invalid_manifest", "Cards use the plugins anchor");
195
- }
196
- for (const declaration of manifest.contributions) {
197
- ensure(
198
- declaration.opens === void 0 || manifest.contributions.some((item) => item.id === declaration.opens && item.kind === "panel"),
199
- "invalid_manifest",
200
- "Contribution opens must name a declared panel"
201
- );
202
- }
203
- ensure(!manifest.contributions.length || manifest.capabilities.includes("surfaces"), "invalid_manifest", "Contributions require surfaces capability");
204
- ensure(manifest.configSchema === void 0 || object(manifest.configSchema), "invalid_manifest", "Configuration schema must be an object");
205
- return freeze(manifest);
206
- }
207
-
208
- // ../plugin-sdk/src/protocol.mjs
209
- var RUNNER_PROTOCOL_VERSION = 1;
210
- var OPERATIONS = Object.freeze({
211
- "pane.create": "panes",
212
- "pane.close": "panes",
213
- "pane.restart": "panes",
214
- "pane.input": "panes",
215
- "pane.focus": "panes",
216
- "pane.wait": "panes",
217
- "project.create": "projects",
218
- "project.remove": "projects",
219
- "notification.show": "notifications",
220
- "url.open": "url",
221
- fetch: "fetch",
222
- "secret.get": "secrets",
223
- "config.get": null,
224
- "state.get": null,
225
- "state.set": null,
226
- "state.keys": null,
227
- "panel.open": "surfaces",
228
- "context.get": null,
229
- "popover.open": "surfaces",
230
- "canvas.write": "surfaces",
231
- "remote.request": "surfaces",
232
- "canvas.focus": "surfaces",
233
- "subscription.add": null,
234
- "subscription.remove": null,
235
- "health.set": null,
236
- "webhook.ack": "webhook"
237
- });
238
- var HOST_OPERATIONS = Object.freeze([
239
- "runner.start",
240
- "runner.stop",
241
- "runner.reload",
242
- "runner.diagnose",
243
- "runner.ping",
244
- "runtime.invoke",
245
- "runtime.visibility"
246
- ]);
247
- function authorize(operation, capabilities) {
248
- ensure(
249
- object(operation) && Object.hasOwn(OPERATIONS, operation.op) && object(operation.args),
250
- "unsupported_operation",
251
- "Unknown SDK operation or invalid arguments"
252
- );
253
- let capability = OPERATIONS[operation.op];
254
- if (operation.op === "subscription.add") {
255
- const { id, kind, name } = operation.args;
256
- ensure(
257
- identifier(id) && typeof name === "string" && name.length <= 256 && ["event", "hook", "action", "input", "select", "resize", "activate", "deactivate", "visibility"].includes(kind),
258
- "invalid_payload",
259
- "Invalid subscription"
260
- );
261
- capability = kind === "hook" ? "hooks" : kind === "event" ? name === "webhook" ? "webhook" : "events" : "surfaces";
262
- }
263
- ensure(!capability || capabilities.includes(capability), "capability_denied", `Operation requires ${capability} capability`);
264
- jsonBytes(operation);
265
- }
266
- function validateProducer(producer) {
267
- ensure(
268
- object(producer) && identifier(producer.pluginId) && typeof producer.machineId === "string" && producer.machineId.length > 0 && producer.machineId.length <= 128 && typeof producer.epoch === "string" && /^(0|[1-9]\d{0,19})$/.test(producer.epoch) && BigInt(producer.epoch) <= 18446744073709551615n,
269
- "invalid_payload",
270
- "Invalid plugin producer identity"
271
- );
272
- return producer;
273
- }
274
- function sameProducer(a, b) {
275
- return a.pluginId === b.pluginId && a.machineId === b.machineId && a.epoch === b.epoch;
276
- }
277
- function frameLimit(frame, inbound) {
278
- return inbound && object(frame) && frame.kind === "response" ? LIMITS.responseFrameBytes : LIMITS.frameBytes;
279
- }
280
- function validateEnvelope(frame, { inbound = false } = {}) {
281
- jsonBytes(frame, frameLimit(frame, inbound));
282
- ensure(object(frame) && frame.version === RUNNER_PROTOCOL_VERSION, "incompatible_version", "Daemon and runner protocol versions differ");
283
- validateProducer(frame.producer);
284
- ensure(["request", "response", "cancel", "surface", "report"].includes(frame.kind), "invalid_payload", "Unknown runner frame kind");
285
- if (frame.kind === "report") {
286
- ensure(
287
- identifier(frame.name) && object(frame.entity) && typeof frame.sequence === "string" && /^(0|[1-9]\d{0,19})$/.test(frame.sequence) && BigInt(frame.sequence) <= 18446744073709551615n && Number.isInteger(frame.schemaVersion) && frame.schemaVersion > 0 && frame.schemaVersion <= 65535 && Object.hasOwn(frame, "value") && frame.value !== void 0,
288
- "invalid_payload",
289
- "Invalid report replacement"
290
- );
291
- } else if (frame.kind === "surface") {
292
- ensure(object(frame.key) && identifier(frame.key.contributionId) && typeof frame.sequence === "string" && /^(0|[1-9]\d{0,19})$/.test(frame.sequence) && BigInt(frame.sequence) <= 18446744073709551615n && Object.hasOwn(frame, "content"), "invalid_payload", "Invalid surface replacement");
293
- } else {
294
- ensure(typeof frame.id === "string" && frame.id.length > 0 && frame.id.length <= 128, "invalid_payload", "Missing correlation id");
295
- if (frame.kind === "request") {
296
- ensure(
297
- object(frame.operation) && (Object.hasOwn(OPERATIONS, frame.operation.op) || HOST_OPERATIONS.includes(frame.operation.op)) && object(frame.operation.args) && Number.isSafeInteger(frame.timeoutMs) && frame.timeoutMs > 0 && frame.timeoutMs <= LIMITS.hookTimeoutMs,
298
- "invalid_payload",
299
- "Invalid runner request"
300
- );
301
- }
302
- if (frame.kind === "response") {
303
- ensure(
304
- object(frame.result) && typeof frame.result.ok === "boolean" && (frame.result.ok ? Object.hasOwn(frame.result, "value") : object(frame.result.error) && typeof frame.result.error.code === "string" && typeof frame.result.error.message === "string"),
305
- "invalid_payload",
306
- "Invalid runner response"
307
- );
308
- }
309
- }
310
- return frame;
311
- }
312
- function wireError(error) {
313
- return {
314
- code: error instanceof PluginError ? error.code : "plugin_error",
315
- message: String(error?.message ?? "Plugin operation failed").slice(0, 1024)
316
- };
317
- }
318
- var realClock = Object.freeze({ now: () => Date.now(), setTimeout: (fn, ms) => setTimeout(fn, ms), clearTimeout: (id) => clearTimeout(id) });
319
- var RpcPeer = class {
320
- constructor({ producer, send, clock = realClock, onRequest, onSurface, onReport, onError = () => {
321
- }, idPrefix = "host" }) {
322
- this.producer = Object.freeze({ ...validateProducer(producer) });
323
- this.send = send;
324
- this.clock = clock;
325
- this.onRequest = onRequest;
326
- this.onSurface = onSurface;
327
- this.onReport = onReport;
328
- this.onError = onError;
329
- this.pending = /* @__PURE__ */ new Map();
330
- this.incoming = /* @__PURE__ */ new Map();
331
- this.nextId = 0;
332
- this.idPrefix = idPrefix;
333
- this.closed = false;
334
- }
335
- frame(kind, values) {
336
- return { version: RUNNER_PROTOCOL_VERSION, producer: this.producer, kind, ...values };
337
- }
338
- transmit(frame) {
339
- validateEnvelope(frame);
340
- this.send(frame);
341
- }
342
- request(operation, { signal, timeoutMs = LIMITS.requestTimeoutMs } = {}) {
343
- if (this.closed) return Promise.reject(new PluginError("disposed", "Plugin runtime is disposed"));
344
- if (signal?.aborted) return Promise.reject(new PluginError("cancelled", "Request was cancelled"));
345
- if (this.pending.size >= LIMITS.pendingRequests) return Promise.reject(new PluginError("queue_full", "Too many pending requests"));
346
- const id = `${this.idPrefix}-${++this.nextId}`;
347
- return new Promise((resolve2, reject) => {
348
- let timer;
349
- const finish = (error, value) => {
350
- if (!this.pending.delete(id)) return;
351
- this.clock.clearTimeout(timer);
352
- signal?.removeEventListener("abort", cancel);
353
- error ? reject(error) : resolve2(value);
354
- };
355
- const cancelWith = (code) => {
356
- finish(new PluginError(code, code === "timeout" ? "Request deadline elapsed" : "Request was cancelled"));
357
- try {
358
- this.transmit(this.frame("cancel", { id }));
359
- } catch (error) {
360
- this.onError(error);
361
- }
362
- };
363
- const cancel = () => cancelWith("cancelled");
364
- this.pending.set(id, { finish });
365
- signal?.addEventListener("abort", cancel, { once: true });
366
- timer = this.clock.setTimeout(() => cancelWith("timeout"), timeoutMs);
367
- try {
368
- this.transmit(this.frame("request", { id, operation, timeoutMs }));
369
- } catch (error) {
370
- finish(error);
371
- }
372
- });
373
- }
374
- receive(frame) {
375
- if (this.closed) return;
376
- validateEnvelope(frame, { inbound: true });
377
- ensure(sameProducer(frame.producer, this.producer), "stale_producer", "Frame belongs to another plugin instance");
378
- if (frame.kind === "surface") {
379
- this.onSurface?.(frame);
380
- return;
381
- }
382
- if (frame.kind === "report") {
383
- this.onReport?.(frame);
384
- return;
385
- }
386
- if (frame.kind === "response") {
387
- const result = frame.result;
388
- this.pending.get(frame.id)?.finish(result.ok ? null : new PluginError(result.error.code, result.error.message), result.value);
389
- return;
390
- }
391
- if (frame.kind === "cancel") {
392
- this.incoming.get(frame.id)?.cancel();
393
- return;
394
- }
395
- ensure(!this.incoming.has(frame.id), "duplicate_request", "Request id is still in flight");
396
- const respond = (result) => {
397
- if (!this.closed) {
398
- try {
399
- this.transmit(this.frame("response", { id: frame.id, result }));
400
- } catch (error) {
401
- this.onError(error);
402
- }
403
- }
404
- };
405
- if (this.incoming.size >= LIMITS.pendingRequests) {
406
- respond({ ok: false, error: { code: "queue_full", message: "Too many incoming requests" } });
407
- return;
408
- }
409
- const controller = new AbortController();
410
- const cancel = () => {
411
- controller.abort();
412
- this.clock.clearTimeout(timer);
413
- };
414
- const timer = this.clock.setTimeout(() => {
415
- cancel();
416
- respond({ ok: false, error: { code: "timeout", message: "Handler deadline elapsed" } });
417
- }, frame.timeoutMs);
418
- this.incoming.set(frame.id, { cancel });
419
- Promise.resolve().then(() => {
420
- ensure(!controller.signal.aborted, "cancelled", "Request was cancelled");
421
- ensure(typeof this.onRequest === "function", "unsupported_operation", "No request handler");
422
- return this.onRequest(frame.operation, { signal: controller.signal, timeoutMs: frame.timeoutMs });
423
- }).then((value) => {
424
- if (!controller.signal.aborted) respond({ ok: true, value: value ?? null });
425
- }, (error) => {
426
- if (!controller.signal.aborted) respond({ ok: false, error: wireError(error) });
427
- }).finally(() => {
428
- this.clock.clearTimeout(timer);
429
- this.incoming.delete(frame.id);
430
- });
431
- }
432
- dispose() {
433
- if (this.closed) return;
434
- for (const [id, request] of this.pending) {
435
- request.finish(new PluginError("disposed", "Plugin runtime was disposed"));
436
- try {
437
- this.transmit(this.frame("cancel", { id }));
438
- } catch (error) {
439
- this.onError(error);
440
- }
441
- }
442
- this.closed = true;
443
- for (const request of this.incoming.values()) request.cancel();
444
- }
445
- };
446
-
447
- // ../plugin-sdk/src/view.mjs
448
- var VIEW_LIMITS = Object.freeze({
449
- depth: 8,
450
- nodes: 4096,
451
- tableRows: 512,
452
- tableColumns: 12,
453
- items: 512,
454
- logLines: 2048,
455
- cardLines: 6,
456
- actionValueBytes: 512
457
- });
458
- var TONES = Object.freeze(["ok", "info", "warn", "error", "muted", "accent", "pending", "bright"]);
459
- var WEIGHTS = ["normal", "bold", "dim"];
460
- var ALIGNS = ["start", "center", "end"];
461
- var FORBIDDEN = /[\u0000-\u001f\u007f-\u009f\u061c\u200e\u200f\u202a-\u202e\u2066-\u2069]/;
462
- var invalid = (message) => ensure(false, "invalid_payload", message);
463
- function text(value, field) {
464
- if (typeof value !== "string") invalid(`Plugin view ${field} must be a string`);
465
- ensure(!FORBIDDEN.test(value), "invalid_payload", "Plugin view text contains a control or bidirectional character");
466
- }
467
- function optionalText(value, field) {
468
- if (value !== void 0) text(value, field);
469
- }
470
- function choice(value, choices, field) {
471
- ensure(value === void 0 || choices.includes(value), "invalid_payload", `Invalid plugin view ${field}`);
472
- }
473
- function tone(value) {
474
- choice(value, TONES, "tone");
475
- }
476
- function integer(value, max, field) {
477
- ensure(value === void 0 || Number.isInteger(value) && value >= 0 && value <= max, "invalid_payload", `Invalid plugin view ${field}`);
478
- }
479
- function flag(value, field) {
480
- ensure(value === void 0 || typeof value === "boolean", "invalid_payload", `Invalid plugin view ${field}`);
481
- }
482
- function number(value) {
483
- ensure(typeof value === "number" && Number.isFinite(value), "invalid_payload", "Plugin view number is not finite");
484
- }
485
- function list(value, field, optional = false) {
486
- if (optional && value === void 0) return [];
487
- ensure(Array.isArray(value), "invalid_payload", `Plugin view ${field} must be an array`);
488
- return value;
489
- }
490
- function entries(value, field, optional, check) {
491
- for (const item of list(value, field, optional)) {
492
- ensure(object(item), "invalid_payload", `Plugin view ${field} must contain objects`);
493
- check(item);
494
- }
495
- }
496
- function bounded(value, field, limit, optional = false) {
497
- const values = list(value, field, optional);
498
- ensure(values.length <= limit, "invalid_payload", `Plugin view ${field} has more than ${limit} entries`);
499
- return values;
500
- }
501
- function boundedEntries(value, field, check) {
502
- entries(bounded(value, field, VIEW_LIMITS.items), field, false, check);
503
- }
504
- function spans(value, optional) {
505
- entries(value, "spans", optional, (span) => {
506
- text(span.text, "span text");
507
- tone(span.tone);
508
- choice(span.weight, WEIGHTS, "weight");
509
- flag(span.mono, "mono");
510
- });
511
- }
512
- function action(value, optional = true) {
513
- if (optional && value === void 0) return;
514
- ensure(object(value), "invalid_payload", "Plugin view action must be an object");
515
- text(value.actionId, "action id");
516
- optionalText(value.value, "action value");
517
- optionalText(value.opens, "action opens");
518
- if (value.agentPicker !== void 0) {
519
- ensure(object(value.agentPicker), "invalid_payload", "Agent picker needs a project and machine");
520
- text(value.agentPicker.machineId, "agent picker machine");
521
- text(value.agentPicker.projectId, "agent picker project");
522
- }
523
- }
524
- function meter(item) {
525
- number(item.value);
526
- number(item.max);
527
- tone(item.tone);
528
- optionalText(item.label, "label");
529
- }
530
- function children(node2, depth, count) {
531
- for (const child of list(node2.children, "children", true)) walk(child, depth + 1, count);
532
- }
533
- var NODES = {
534
- stack(node2, depth, count) {
535
- integer(node2.gap, 255, "gap");
536
- children(node2, depth, count);
537
- },
538
- row(node2, depth, count) {
539
- choice(node2.align, ALIGNS, "align");
540
- children(node2, depth, count);
541
- },
542
- divider(node2) {
543
- optionalText(node2.label, "label");
544
- },
545
- text(node2) {
546
- optionalText(node2.text, "text");
547
- spans(node2.spans, true);
548
- tone(node2.tone);
549
- choice(node2.weight, WEIGHTS, "weight");
550
- flag(node2.mono, "mono");
551
- },
552
- badge(node2) {
553
- text(node2.label, "label");
554
- tone(node2.tone);
555
- },
556
- dot(node2) {
557
- tone(node2.tone);
558
- },
559
- progress: meter,
560
- segments(node2) {
561
- boundedEntries(node2.items, "items", meter);
562
- },
563
- card(node2, depth, count) {
564
- optionalText(node2.title, "title");
565
- optionalText(node2.footer, "footer");
566
- tone(node2.tone);
567
- action(node2.action);
568
- action(node2.externalAction);
569
- boundedEntries(node2.tags ?? [], "tags", (tag) => {
570
- text(tag.label, "tag label");
571
- tone(tag.tone);
572
- });
573
- children(node2, depth, count);
574
- },
575
- input(node2) {
576
- text(node2.id, "id");
577
- text(node2.value, "value");
578
- optionalText(node2.placeholder, "placeholder");
579
- action(node2.action, false);
580
- integer(node2.maxLength, 4096, "maxLength");
581
- },
582
- stat(node2) {
583
- text(node2.label, "label");
584
- text(node2.value, "value");
585
- tone(node2.tone);
586
- optionalText(node2.hint, "hint");
587
- },
588
- kv(node2) {
589
- boundedEntries(node2.items, "items", (item) => {
590
- text(item.label, "label");
591
- text(item.value, "value");
592
- flag(item.mono, "mono");
593
- flag(item.copy, "copy");
594
- });
595
- },
596
- tabs(node2) {
597
- text(node2.id, "id");
598
- optionalText(node2.filters, "filters");
599
- action(node2.action);
600
- boundedEntries(node2.items, "items", (item) => {
601
- text(item.id, "id");
602
- text(item.label, "label");
603
- optionalText(item.sublabel, "sublabel");
604
- tone(item.tone);
605
- integer(item.count, 4294967295, "count");
606
- optionalText(item.tag, "tag");
607
- });
608
- },
609
- select(node2) {
610
- text(node2.id, "id");
611
- text(node2.label, "label");
612
- optionalText(node2.filters, "filters");
613
- action(node2.action);
614
- boundedEntries(node2.options, "options", (option) => {
615
- text(option.id, "id");
616
- text(option.label, "label");
617
- optionalText(option.group, "group");
618
- integer(option.count, 4294967295, "count");
619
- optionalText(option.tag, "tag");
620
- });
621
- },
622
- table(node2, depth, count) {
623
- const columns = list(node2.columns, "columns");
624
- const rows = list(node2.rows, "rows", true);
625
- ensure(columns.length <= VIEW_LIMITS.tableColumns, "invalid_payload", "Plugin table has more than 12 columns");
626
- ensure(rows.length <= VIEW_LIMITS.tableRows, "invalid_payload", "Plugin table has more than 512 rows");
627
- text(node2.id, "id");
628
- entries(columns, "columns", false, (column) => {
629
- text(column.id, "column id");
630
- optionalText(column.label, "column label");
631
- if (column.width !== "fill") integer(column.width, 65535, "column width");
632
- integer(column.maxWidth, 65535, "column maxWidth");
633
- choice(column.align, ALIGNS, "align");
634
- integer(column.priority, 255, "column priority");
635
- });
636
- entries(rows, "rows", false, (row) => {
637
- text(row.id, "row id");
638
- tone(row.tone);
639
- spans(row.note, true);
640
- for (const tag of bounded(row.tags, "tags", VIEW_LIMITS.items, true)) text(tag, "tag");
641
- action(row.action);
642
- ensure(row.cells === void 0 || object(row.cells), "invalid_payload", "Plugin table cells must be an object");
643
- for (const [column, cell] of Object.entries(row.cells ?? {})) {
644
- text(column, "cell column");
645
- walk(cell, depth + 1, count);
646
- }
647
- });
648
- },
649
- log(node2) {
650
- for (const line of bounded(node2.lines, "lines", VIEW_LIMITS.logLines)) text(line, "log line");
651
- },
652
- button(node2) {
653
- text(node2.label, "label");
654
- action(node2.action, false);
655
- flag(node2.sticky, "sticky");
656
- }
657
- };
658
- function walk(node2, depth, count) {
659
- ensure(depth <= VIEW_LIMITS.depth, "invalid_payload", "Plugin view nests deeper than 8 nodes");
660
- ensure(++count.nodes <= VIEW_LIMITS.nodes, "invalid_payload", "Plugin view has more than 4096 nodes");
661
- ensure(object(node2) && typeof node2.type === "string", "invalid_payload", "Plugin view node requires a type");
662
- if (Object.hasOwn(NODES, node2.type)) NODES[node2.type](node2, depth, count);
663
- }
664
- function visitActions(node2, visit) {
665
- switch (node2.type) {
666
- case "stack":
667
- case "row":
668
- case "card":
669
- if (node2.type === "card") {
670
- if (node2.action !== void 0) visit(node2.action);
671
- if (node2.externalAction !== void 0) visit(node2.externalAction);
672
- }
673
- for (const child of node2.children ?? []) visitActions(child, visit);
674
- break;
675
- case "button":
676
- case "input":
677
- visit(node2.action);
678
- break;
679
- case "tabs":
680
- case "select":
681
- if (node2.action !== void 0) visit(node2.action);
682
- break;
683
- case "table":
684
- for (const row of node2.rows ?? []) {
685
- if (row.action !== void 0) visit(row.action);
686
- for (const cell of Object.values(row.cells ?? {})) visitActions(cell, visit);
687
- }
688
- break;
689
- }
690
- }
691
- var ONE_LINE = ["text", "badge", "dot", "progress", "segments", "stat", "divider"];
692
- var PANEL_ONLY = ["card", "kv", "tabs", "select", "table", "log", "button", "input"];
693
- function cardLines(node2) {
694
- if (node2.type === "stack") {
695
- const children2 = node2.children ?? [];
696
- return children2.reduce((total, child) => total + cardLines(child), (node2.gap ?? 0) * Math.max(children2.length - 1, 0));
697
- }
698
- if (node2.type === "row") return (node2.children ?? []).reduce((tallest, child) => Math.max(tallest, cardLines(child)), 0);
699
- if (ONE_LINE.includes(node2.type)) return 1;
700
- ensure(!PANEL_ONLY.includes(node2.type), "invalid_payload", `A card view cannot contain a ${node2.type} node`);
701
- return 0;
702
- }
703
- function validateView(root, { kind, manifest } = {}) {
704
- walk(root, 1, { nodes: 0 });
705
- jsonBytes(root, LIMITS.frameBytes);
706
- visitActions(root, (action2) => {
707
- ensure(identifier(action2.actionId), "invalid_payload", "Plugin view action id must be a plugin identifier");
708
- ensure(
709
- action2.value === void 0 || Buffer.byteLength(action2.value) <= VIEW_LIMITS.actionValueBytes,
710
- "payload_too_large",
711
- "Plugin view action value exceeds 512 bytes"
712
- );
713
- ensure(action2.opens === void 0 || identifier(action2.opens), "invalid_payload", "Plugin view action opens must be a plugin identifier");
714
- ensure(
715
- action2.opens === void 0 || !manifest || manifest.contributions.some((item) => item.id === action2.opens && item.kind === "panel"),
716
- "invalid_payload",
717
- "Plugin view action opens must name a declared panel"
718
- );
719
- });
720
- if (kind === "card") {
721
- ensure(cardLines(root) <= VIEW_LIMITS.cardLines, "payload_too_large", "A card view is taller than 6 lines");
722
- }
723
- }
724
- function compact(value) {
725
- return Object.fromEntries(Object.entries(value).filter(([, item]) => item !== void 0));
726
- }
727
- var node = (type, fields) => compact({ type, ...fields });
728
- var ui = Object.freeze({
729
- view: (root, { title } = {}) => compact({ kind: "view", root, title }),
730
- action: (actionId, { value, opens, agentPicker } = {}) => compact({ actionId, value, opens, agentPicker }),
731
- span: (value, { tone: tone2, weight, mono } = {}) => compact({ text: value, tone: tone2, weight, mono }),
732
- stack: (items, { gap } = {}) => node("stack", { gap, children: items }),
733
- row: (items, { align } = {}) => node("row", { children: items, align }),
734
- divider: (label) => node("divider", { label }),
735
- /** A string sets `text`; an array of spans sets `spans`. */
736
- text: (content, { tone: tone2, weight, mono } = {}) => node("text", { ...Array.isArray(content) ? { spans: content.map(compact) } : { text: content }, tone: tone2, weight, mono }),
737
- badge: (label, tone2) => node("badge", { label, tone: tone2 }),
738
- dot: (tone2) => node("dot", { tone: tone2 }),
739
- progress: (value, max, { tone: tone2, label } = {}) => node("progress", { value, max, tone: tone2, label }),
740
- segments: (items) => node("segments", { items: items.map(compact) }),
741
- card: (items, { title, tone: tone2, tags, action: action2, externalAction, footer } = {}) => node("card", { title, tone: tone2, tags, action: action2, externalAction, footer, children: items }),
742
- stat: (label, value, { tone: tone2, hint } = {}) => node("stat", { label, value, tone: tone2, hint }),
743
- kv: (items) => node("kv", { items: items.map(compact) }),
744
- tabs: (id, items, { filters, action: action2 } = {}) => node("tabs", { id, items: items.map(compact), filters, action: action2 }),
745
- select: (id, label, options, { filters, action: action2 } = {}) => node("select", { id, label, options: options.map(compact), filters, action: action2 }),
746
- table: (id, columns, rows = []) => node("table", { id, columns: columns.map(compact), rows: rows.map(compact) }),
747
- log: (lines) => node("log", { lines }),
748
- /** `action` is an action object or an action id. */
749
- button: (label, action2) => node("button", { label, action: typeof action2 === "string" ? { actionId: action2 } : action2 }),
750
- input: (id, value, action2, { placeholder, maxLength } = {}) => node("input", { id, value, placeholder, maxLength, action: typeof action2 === "string" ? { actionId: action2 } : action2 })
751
- });
752
-
753
- // ../plugin-sdk/src/row-layout.mjs
754
- var forbidden = /[\u0000-\u001f\u007f-\u009f\u061c\u200e\u200f\u202a-\u202e\u2066-\u2069]/;
755
- var validText = (v, n) => typeof v === "string" && Buffer.byteLength(v) <= n && !forbidden.test(v);
756
- var only = (v, keys) => Object.keys(v).every((key) => keys.includes(key));
757
- function validateRowLayout(layout) {
758
- const valid = object(layout) && only(layout, ["projectTint", "fields"]) && (layout.projectTint === void 0 || typeof layout.projectTint === "boolean") && Array.isArray(layout.fields) && layout.fields.length > 0 && layout.fields.length <= 32;
759
- ensure(valid, "invalid_payload", "Invalid row layout");
760
- let bytes = 0;
761
- for (const f of layout.fields) {
762
- ensure(
763
- object(f) && only(f, ["text", "icon", "fallback", "tone", "surface", "bold", "gap", "flex", "shrink"]) && validText(f.text, 2048) && (f.icon === void 0 || typeof f.icon === "string" && /^[\uE000-\uF8FF\u{F0000}-\u{FFFFD}\u{100000}-\u{10FFFD}]$/u.test(f.icon)) && (f.fallback === void 0 || validText(f.fallback, 16) && /^[\x20-\x7e]*$/.test(f.fallback)) && (f.tone === void 0 || ["muted", "ok", "error", "info", "warning", "project"].includes(f.tone)) && ["surface", "bold", "flex"].every((k) => f[k] === void 0 || typeof f[k] === "boolean") && (f.gap === void 0 || Number.isInteger(f.gap) && f.gap >= 0 && f.gap <= 8),
764
- "invalid_payload",
765
- "Invalid row field"
766
- );
767
- bytes += Buffer.byteLength(f.text);
768
- if (f.shrink !== void 0) {
769
- const s = f.shrink;
770
- ensure(
771
- object(s) && only(s, ["priority", "min", "mode"]) && Number.isInteger(s.priority) && s.priority >= 0 && s.priority <= 255 && Number.isInteger(s.min) && s.min >= 0 && s.min <= 2048 && ["start", "middle", "end", "hide"].includes(s.mode),
772
- "invalid_payload",
773
- "Invalid row shrink policy"
774
- );
775
- }
776
- }
777
- ensure(bytes <= 8192, "payload_too_large", "Row layout text exceeds 8192 bytes");
778
- }
779
-
780
- // ../plugin-sdk/src/runtime.mjs
781
- var always = Object.freeze({ kind: "always" });
782
- var menuPositions = ["top", "after-open", "before-danger", "bottom"];
783
- var entityKinds = ["account", "machine", "project", "pane", "section"];
784
- function boundedText(value, label, limit = 512) {
785
- ensure(typeof value === "string" && value.trim().length > 0 && value.length <= limit && !/[\u0000-\u001f\u007f]/.test(value), "invalid_payload", `Invalid ${label}`);
786
- return value;
787
- }
788
- var HOVER_FORBIDDEN = /[\u0000-\u001f\u007f-\u009f\u061c\u200e\u200f\u202a-\u202e\u2066-\u2069]/;
789
- function validatePassiveText(value, limit = LIMITS.canvasHoverBytes, label = "canvas hover") {
790
- if (typeof value === "string") {
791
- ensure(
792
- value.trim().length > 0 && !HOVER_FORBIDDEN.test(value),
793
- "invalid_payload",
794
- `Invalid ${label} text`
795
- );
796
- ensure(
797
- Buffer.byteLength(value) <= limit,
798
- "payload_too_large",
799
- `${label} text exceeds ${limit} bytes`
800
- );
801
- return;
802
- }
803
- ensure(Array.isArray(value), "invalid_payload", `Invalid ${label} spans`);
804
- ensure(value.length > 0, "invalid_payload", `${label} spans must contain text`);
805
- ensure(value.length <= 32, "payload_too_large", `${label} spans exceed 32 spans`);
806
- let text2 = "";
807
- for (const span of value) {
808
- ensure(object(span), "invalid_payload", `Invalid ${label} span`);
809
- ensure(
810
- typeof span.text === "string" && !HOVER_FORBIDDEN.test(span.text),
811
- "invalid_payload",
812
- `Invalid ${label} span text`
813
- );
814
- for (const field of ["foreground", "background"]) {
815
- if (span[field] !== void 0) {
816
- ensure(typeof span[field] === "string" && span[field].trim().length > 0 && !HOVER_FORBIDDEN.test(span[field]), "invalid_payload", `Invalid ${label} span ${field}`);
817
- ensure(
818
- Buffer.byteLength(span[field]) <= 64,
819
- "payload_too_large",
820
- `${label} span ${field} exceeds 64 bytes`
821
- );
822
- }
823
- }
824
- for (const field of ["bold", "italic", "underline"]) {
825
- ensure(
826
- span[field] === void 0 || typeof span[field] === "boolean",
827
- "invalid_payload",
828
- `Invalid ${label} span ${field}`
829
- );
830
- }
831
- ensure(span.actionId === void 0, "invalid_payload", `${label} spans cannot contain actionId`);
832
- text2 += span.text;
833
- }
834
- ensure(
835
- text2.trim().length > 0 && !HOVER_FORBIDDEN.test(text2),
836
- "invalid_payload",
837
- `Invalid ${label} text`
838
- );
839
- ensure(
840
- Buffer.byteLength(text2) <= limit,
841
- "payload_too_large",
842
- `${label} text exceeds ${limit} bytes`
843
- );
844
- }
845
- function validateEntity(entity) {
846
- ensure(object(entity) && entityKinds.includes(entity.kind), "invalid_payload", "Invalid registration entity");
847
- boundedText(entity.id, "entity id", 128);
848
- if (entity.machineId !== void 0) boundedText(entity.machineId, "machine id", 128);
849
- if (entity.generation !== void 0) {
850
- ensure(typeof entity.generation === "string" && /^(0|[1-9]\d{0,19})$/.test(entity.generation) && BigInt(entity.generation) <= 18446744073709551615n, "invalid_payload", "Invalid entity generation");
851
- }
852
- return {
853
- kind: entity.kind,
854
- id: entity.id,
855
- ...entity.machineId !== void 0 ? { machineId: entity.machineId } : {},
856
- ...entity.generation !== void 0 ? { generation: entity.generation } : {}
857
- };
858
- }
859
- function validateChord(chord) {
860
- boundedText(chord, "key chord", 128);
861
- const presses = chord.split(" ");
862
- const namedKeys = ["space", "enter", "esc", "tab", "backspace", "left", "right", "up", "down", "pageup", "pagedown", "home", "end"];
863
- ensure(presses.length <= 2 && presses.every((press) => {
864
- const parts = press.split("+");
865
- const modifiers = parts.filter((part) => ["shift", "alt", "ctrl"].includes(part));
866
- const keys = parts.filter((part) => !["shift", "alt", "ctrl"].includes(part));
867
- return new Set(modifiers).size === modifiers.length && keys.length === 1 && (namedKeys.includes(keys[0]) || Array.from(keys[0]).length === 1);
868
- }), "invalid_payload", "Invalid native key chord");
869
- return chord;
870
- }
871
- function conditionKey(condition) {
872
- return JSON.stringify([condition.kind, condition.contributionId ?? null, condition.entity ?? null]);
873
- }
874
- function validateCondition(condition) {
875
- ensure(condition && ["always", "section-visible", "slot-visible", "panel-open"].includes(condition.kind) && (condition.kind === "always" || identifier(condition.contributionId)), "invalid_payload", "Invalid schedule condition");
876
- return structuredClone(condition);
877
- }
878
- var CONTENT_KINDS = ["rows", "text", "badge", "canvas", "view"];
879
- function acceptsContent(kind, content) {
880
- if (["menu", "command", "key", "link"].includes(kind)) return false;
881
- if (kind === "badge") return content.kind === "badge";
882
- if (content.kind === "badge") return false;
883
- return content.kind !== "view" || ["section", "card", "panel"].includes(kind);
884
- }
885
- function validateContent(content, declaration, manifest) {
886
- const { kind } = declaration;
887
- ensure(object(content) && CONTENT_KINDS.includes(content.kind), "invalid_payload", "Invalid surface content");
888
- ensure(acceptsContent(kind, content), "invalid_payload", `A ${kind} contribution cannot show ${content.kind} content`);
889
- if (content.kind === "view") {
890
- validateView(content.root, { kind: declaration.kind, manifest });
891
- if (content.title !== void 0) {
892
- ensure(["card", "panel"].includes(kind) && Array.isArray(content.title), "invalid_payload", "Styled titles belong to card or panel views");
893
- validatePassiveText(content.title, 512, "card title");
894
- }
895
- }
896
- if (content.kind === "rows") {
897
- for (const row of content.rows ?? []) if (row.layout !== void 0) {
898
- ensure(["pane.header", "pane.footer"].includes(declaration.anchor), "invalid_payload", "Row layouts require a pane header or footer");
899
- validateRowLayout(row.layout);
900
- }
901
- }
902
- jsonBytes(content);
903
- if (content.kind === "canvas") {
904
- const { columns, rows, shade = 0, hover, themeColors, titleRight } = content.canvas ?? {};
905
- ensure(Number.isSafeInteger(columns) && columns > 0 && columns <= LIMITS.canvasColumns && Number.isSafeInteger(rows) && rows > 0 && rows <= LIMITS.canvasRows && Number.isFinite(shade) && shade >= 0 && shade <= 1, "invalid_payload", "Invalid canvas dimensions or shade");
906
- if (themeColors !== void 0) {
907
- ensure(object(themeColors) && Object.keys(themeColors).length <= 32, "invalid_payload", "Invalid canvas theme colors");
908
- for (const [index, recipe] of Object.entries(themeColors)) {
909
- ensure(
910
- /^(0|[1-9][0-9]{0,2})$/.test(index) && Number(index) <= 255 && object(recipe) && Object.keys(recipe).every((key) => ["source", "mix", "opacity"].includes(key)) && ["source", "mix"].every((key) => recipe[key] === void 0 || Number.isInteger(recipe[key]) && recipe[key] >= 0 && recipe[key] < 16) && Number.isFinite(recipe.opacity) && recipe.opacity >= 0 && recipe.opacity <= 1,
911
- "invalid_payload",
912
- "Invalid canvas theme color recipe"
913
- );
914
- }
915
- }
916
- if (titleRight !== void 0) {
917
- ensure(declaration.kind === "card" && typeof titleRight === "string", "invalid_payload", "Canvas titleRight requires a card and string");
918
- validatePassiveText(titleRight, 512, "card header");
919
- }
920
- if (hover !== void 0) validatePassiveText(hover);
921
- }
922
- }
923
- function createRuntime({ manifest: input, producer, send, clock = realClock, onError = () => {
924
- }, instanceId = "0" }) {
925
- const manifest = validateManifest(input);
926
- ensure(producer.pluginId === manifest.id, "identity_mismatch", "Manifest and producer ids differ");
927
- const lifetime = new AbortController();
928
- const subscriptions = /* @__PURE__ */ new Map();
929
- const schedules = /* @__PURE__ */ new Set();
930
- const cleanups = /* @__PURE__ */ new Set();
931
- const publishers = /* @__PURE__ */ new Map();
932
- const reports = /* @__PURE__ */ new Map();
933
- let visibility = /* @__PURE__ */ new Set();
934
- let counter = 0;
935
- let sequence = 0n;
936
- let disposal;
937
- ensure(identifier(instanceId), "invalid_payload", "Invalid runtime instance id");
938
- const peer = new RpcPeer({ producer, send, clock, onError, idPrefix: "sdk", onRequest: async (operation, options) => {
939
- if (operation.op === "runtime.visibility") {
940
- ensure(
941
- Array.isArray(operation.args.conditions) && operation.args.conditions.length <= LIMITS.contributions,
942
- "invalid_payload",
943
- "Invalid visibility snapshot"
944
- );
945
- visibility = new Set(operation.args.conditions.map((condition) => conditionKey(validateCondition(condition))));
946
- for (const schedule2 of schedules) schedule2.visibilityChanged(visibility);
947
- return null;
948
- }
949
- ensure(operation.op === "runtime.invoke", "unsupported_operation", "Unsupported worker operation");
950
- const subscription = subscriptions.get(operation.args.subscriptionId);
951
- ensure(subscription, "subscription_missing", "Subscription was disposed");
952
- if (subscription.condition.kind !== "always" && !visibility.has(conditionKey(subscription.condition))) return null;
953
- const result = await subscription.handler(operation.args.event, { signal: options.signal });
954
- if (subscription.kind === "hook") {
955
- ensure(result && ["proceed", "cancel"].includes(result.decision), "invalid_payload", "Hook must return proceed or cancel");
956
- }
957
- return result ?? null;
958
- } });
959
- function active() {
960
- ensure(!lifetime.signal.aborted, "disposed", "Plugin runtime is disposed");
961
- }
962
- function request(op, args, options) {
963
- try {
964
- active();
965
- authorize({ op, args }, manifest.capabilities);
966
- } catch (error) {
967
- onError(error);
968
- return Promise.reject(error);
969
- }
970
- return peer.request({ op, args }, options);
971
- }
972
- function publish(kind, id, entity) {
973
- active();
974
- ensure(manifest.capabilities.includes("surfaces"), "capability_denied", "Publishing requires surfaces capability");
975
- const declaration = manifest.contributions.find((item) => item.id === id);
976
- ensure(
977
- declaration && (!kind || declaration.kind === kind) && ANCHORS.includes(declaration.anchor),
978
- "contribution_missing",
979
- "Surface must match its static contribution declaration"
980
- );
981
- const key = { contributionId: id, anchor: declaration.anchor, ...entity ? { entity: structuredClone(entity) } : {} };
982
- const identity = JSON.stringify(key);
983
- ensure(!publishers.has(identity), "duplicate_contribution", "Contribution publisher exists");
984
- ensure(publishers.size < LIMITS.contributions, "queue_full", "Too many contribution publishers");
985
- let disposed = false;
986
- const replace = (content) => {
987
- active();
988
- ensure(!disposed, "disposed", "Contribution publisher is disposed");
989
- if (content !== null) validateContent(content, declaration, manifest);
990
- peer.transmit(peer.frame("surface", { key, sequence: String(++sequence), content }));
991
- };
992
- const publisher = { replace, clear: () => replace(null), dispose() {
993
- if (disposed) return;
994
- try {
995
- if (!lifetime.signal.aborted) replace(null);
996
- } finally {
997
- disposed = true;
998
- publishers.delete(identity);
999
- }
1000
- } };
1001
- publishers.set(identity, publisher);
1002
- return { publisher, key };
1003
- }
1004
- function report(name, entity) {
1005
- active();
1006
- ensure(
1007
- manifest.capabilities.includes("surfaces") && identifier(name),
1008
- "capability_denied",
1009
- "Reports require surfaces capability and a valid name"
1010
- );
1011
- const owner = validateEntity(entity);
1012
- ensure(
1013
- ["account", "machine", "project", "pane"].includes(owner.kind),
1014
- "invalid_payload",
1015
- "Reports need an owned entity"
1016
- );
1017
- if (owner.kind === "machine") {
1018
- ensure(
1019
- owner.id === producer.machineId && (owner.machineId === void 0 || owner.machineId === producer.machineId),
1020
- "invalid_payload",
1021
- "Report machine must be the local machine"
1022
- );
1023
- }
1024
- if (owner.kind === "project" || owner.kind === "pane") {
1025
- ensure(
1026
- owner.machineId === producer.machineId && owner.generation !== void 0 && owner.generation !== "0",
1027
- "invalid_payload",
1028
- "Report entity needs its local machine and generation"
1029
- );
1030
- }
1031
- const key = JSON.stringify([name, owner]);
1032
- ensure(
1033
- !reports.has(key) && reports.size < LIMITS.contributions,
1034
- "queue_full",
1035
- "Report publisher exists or capacity is full"
1036
- );
1037
- let disposed = false;
1038
- const sendReport = (value, schemaVersion) => {
1039
- active();
1040
- ensure(!disposed, "disposed", "Report publisher is disposed");
1041
- ensure(
1042
- Number.isInteger(schemaVersion) && schemaVersion > 0 && schemaVersion <= 65535,
1043
- "invalid_payload",
1044
- "Invalid report schema version"
1045
- );
1046
- if (value !== null) jsonBytes(value);
1047
- peer.transmit(peer.frame("report", {
1048
- name,
1049
- entity: owner,
1050
- sequence: String(++sequence),
1051
- schemaVersion,
1052
- value
1053
- }));
1054
- };
1055
- const publisher = {
1056
- replace: (value, schemaVersion = 1) => {
1057
- ensure(value !== null && value !== void 0, "invalid_payload", "Report value is required");
1058
- sendReport(value, schemaVersion);
1059
- },
1060
- clear: () => sendReport(null, 1),
1061
- dispose() {
1062
- if (disposed) return;
1063
- try {
1064
- if (!lifetime.signal.aborted) sendReport(null, 1);
1065
- } finally {
1066
- disposed = true;
1067
- reports.delete(key);
1068
- }
1069
- }
1070
- };
1071
- reports.set(key, publisher);
1072
- return publisher;
1073
- }
1074
- function subscribe(kind, name, handler, condition = always, registration) {
1075
- active();
1076
- ensure(typeof handler === "function", "invalid_payload", "Subscription requires a handler");
1077
- ensure(subscriptions.size < LIMITS.subscriptions, "queue_full", "Too many subscriptions");
1078
- condition = validateCondition(condition);
1079
- const id = `subscription-${instanceId}-${++counter}`;
1080
- const args = { id, kind, name, condition, ...registration ? { registration } : {} };
1081
- authorize({ op: "subscription.add", args }, manifest.capabilities);
1082
- const entry = { kind, handler, condition, registration };
1083
- subscriptions.set(id, entry);
1084
- let disposed = false;
1085
- let updating = false;
1086
- const remove = () => {
1087
- if (!lifetime.signal.aborted) request("subscription.remove", { id }).catch(onError);
1088
- };
1089
- const ready = request("subscription.add", args);
1090
- ready.then(() => {
1091
- if (disposed) remove();
1092
- }, (error) => {
1093
- disposed = true;
1094
- subscriptions.delete(id);
1095
- remove();
1096
- onError(error);
1097
- });
1098
- const subscription = { ready, dispose() {
1099
- if (disposed) return;
1100
- disposed = true;
1101
- subscriptions.delete(id);
1102
- remove();
1103
- } };
1104
- if (registration?.kind === "key") subscription.update = async (chord, options) => {
1105
- active();
1106
- ensure(!disposed, "disposed", "Key registration is disposed");
1107
- validateChord(chord);
1108
- ensure(!updating, "request_in_flight", "A key registration update is pending");
1109
- updating = true;
1110
- try {
1111
- await ready;
1112
- active();
1113
- ensure(!disposed, "disposed", "Key registration is disposed");
1114
- const next = { ...entry.registration, chord };
1115
- await request("subscription.add", { ...args, registration: next }, options);
1116
- if (!disposed) entry.registration = next;
1117
- return null;
1118
- } finally {
1119
- updating = false;
1120
- if (disposed) remove();
1121
- }
1122
- };
1123
- return subscription;
1124
- }
1125
- function prepareRegistration(kind, id, options, handler) {
1126
- active();
1127
- if (typeof options === "function" && handler === void 0) {
1128
- handler = options;
1129
- options = {};
1130
- }
1131
- ensure(identifier(id) && object(options) && typeof handler === "function", "invalid_payload", "Invalid contribution registration");
1132
- jsonBytes(options, LIMITS.manifestBytes);
1133
- const declaration = manifest.contributions.find((item) => item.id === id && item.kind === kind);
1134
- ensure(declaration, "contribution_missing", "Registration must match its static contribution declaration");
1135
- const actionId = options.actionId ?? declaration.actionId ?? id;
1136
- ensure(identifier(actionId), "invalid_payload", "Invalid registration action id");
1137
- const registration = {
1138
- contributionId: id,
1139
- kind,
1140
- anchor: declaration.anchor,
1141
- actionId,
1142
- title: boundedText(options.title ?? declaration.title ?? id, "registration title"),
1143
- ...options.entity !== void 0 ? { entity: validateEntity(options.entity) } : {}
1144
- };
1145
- if (kind === "menu") {
1146
- registration.position = options.position ?? declaration.position ?? "bottom";
1147
- ensure(menuPositions.includes(registration.position), "invalid_payload", "Invalid menu position");
1148
- } else if (kind === "command") {
1149
- const group = options.group ?? declaration.group;
1150
- if (group !== void 0) registration.group = boundedText(group, "command group");
1151
- } else if (kind === "key") {
1152
- registration.chord = validateChord(options.chord ?? declaration.chord);
1153
- } else if (kind === "link") {
1154
- registration.pattern = boundedText(options.pattern ?? declaration.pattern, "link pattern");
1155
- }
1156
- const condition = validateCondition(options.condition ?? always);
1157
- if (condition.entity !== void 0) condition.entity = validateEntity(condition.entity);
1158
- jsonBytes({ registration, condition }, LIMITS.manifestBytes);
1159
- const invoke = async (event, context2) => {
1160
- ensure(object(event) && event.actionId === actionId, "invalid_payload", "Invalid registered action selection");
1161
- if (event.entity !== void 0) validateEntity(event.entity);
1162
- if (kind === "link") boundedText(event.url, "link URL", 8192);
1163
- const result = await handler(event, context2);
1164
- if (kind === "link") ensure(typeof result === "boolean", "invalid_payload", "Link handlers must return a boolean");
1165
- return result;
1166
- };
1167
- return { registration, handler: invoke, condition };
1168
- }
1169
- const registrationKey = (registration) => JSON.stringify([registration.contributionId, registration.entity ?? null]);
1170
- function registerPrepared({ registration, handler, condition }) {
1171
- const identity = registrationKey(registration);
1172
- ensure(
1173
- ![...subscriptions.values()].some((entry) => entry.registration && registrationKey(entry.registration) === identity),
1174
- "duplicate_contribution",
1175
- "Contribution registration exists"
1176
- );
1177
- return subscribe("action", registration.actionId, handler, condition, registration);
1178
- }
1179
- function commandGroup(group, commands) {
1180
- active();
1181
- boundedText(group, "command group");
1182
- ensure(Array.isArray(commands) && commands.length > 0 && commands.length <= LIMITS.contributions && subscriptions.size + commands.length <= LIMITS.subscriptions, "queue_full", "Invalid or excessive group commands");
1183
- const prepared = commands.map((command) => {
1184
- ensure(object(command), "invalid_payload", "Invalid group command");
1185
- const { id, handler, ...options } = command;
1186
- return prepareRegistration("command", id, { ...options, group }, handler);
1187
- });
1188
- const identities = new Set([...subscriptions.values()].filter((entry) => entry.registration).map((entry) => registrationKey(entry.registration)));
1189
- for (const { registration } of prepared) {
1190
- const identity = registrationKey(registration);
1191
- ensure(!identities.has(identity), "duplicate_contribution", "Contribution registration exists");
1192
- identities.add(identity);
1193
- }
1194
- const members = [];
1195
- const dispose = () => {
1196
- for (const member of members) member.dispose();
1197
- };
1198
- try {
1199
- for (const item of prepared) members.push(registerPrepared(item));
1200
- } catch (error) {
1201
- dispose();
1202
- throw error;
1203
- }
1204
- const ready = Promise.all(members.map((member) => member.ready)).then(() => null);
1205
- ready.catch(dispose);
1206
- return { ready, dispose };
1207
- }
1208
- function schedule(intervalMs, handler, { condition = always, immediate = false } = {}) {
1209
- active();
1210
- ensure(
1211
- Number.isFinite(intervalMs) && intervalMs >= 1e3 / 30 && intervalMs <= 2147483647,
1212
- "invalid_payload",
1213
- "Schedule interval must be between 1000/30 and 2147483647 ms"
1214
- );
1215
- ensure(typeof handler === "function" && schedules.size < LIMITS.schedules, "queue_full", "Invalid or excessive schedules");
1216
- condition = validateCondition(condition);
1217
- const interest = condition.kind === "always" ? null : subscribe("visibility", condition.contributionId, () => {
1218
- }, condition);
1219
- const conditionIdentity = conditionKey(condition);
1220
- const controller = new AbortController();
1221
- let activeRun = null;
1222
- let timer;
1223
- const beginRun = () => {
1224
- const runController = new AbortController();
1225
- const cancelFromSchedule = () => runController.abort();
1226
- const cancelFromLifetime = () => runController.abort();
1227
- controller.signal.addEventListener("abort", cancelFromSchedule, { once: true });
1228
- lifetime.signal.addEventListener("abort", cancelFromLifetime, { once: true });
1229
- const run = {
1230
- controller: runController,
1231
- finish() {
1232
- controller.signal.removeEventListener("abort", cancelFromSchedule);
1233
- lifetime.signal.removeEventListener("abort", cancelFromLifetime);
1234
- if (activeRun?.controller === runController) activeRun = null;
1235
- }
1236
- };
1237
- activeRun = run;
1238
- return run;
1239
- };
1240
- const tick = async () => {
1241
- if (controller.signal.aborted || lifetime.signal.aborted) return;
1242
- const visible = condition.kind === "always" || visibility.has(conditionIdentity);
1243
- if (!visible) {
1244
- timer = clock.setTimeout(tick, intervalMs);
1245
- return;
1246
- }
1247
- const run = beginRun();
1248
- try {
1249
- await handler({ signal: run.controller.signal });
1250
- } catch (error) {
1251
- if (!run.controller.signal.aborted || condition.kind === "always") onError(error);
1252
- } finally {
1253
- run.finish();
1254
- }
1255
- if (!controller.signal.aborted && !lifetime.signal.aborted) timer = clock.setTimeout(tick, intervalMs);
1256
- };
1257
- const disposable = {
1258
- visibilityChanged(nextVisibility) {
1259
- if (condition.kind !== "always" && !nextVisibility.has(conditionIdentity)) activeRun?.controller.abort();
1260
- },
1261
- dispose() {
1262
- controller.abort();
1263
- activeRun?.controller.abort();
1264
- clock.clearTimeout(timer);
1265
- interest?.dispose();
1266
- schedules.delete(disposable);
1267
- }
1268
- };
1269
- schedules.add(disposable);
1270
- timer = clock.setTimeout(tick, immediate ? 0 : intervalMs);
1271
- return disposable;
1272
- }
1273
- const method = (op) => (args, options) => request(op, args, options);
1274
- const context = Object.freeze({
1275
- manifest,
1276
- producer: peer.producer,
1277
- signal: lifetime.signal,
1278
- request,
1279
- ...Object.fromEntries(["section", "card", "slot", "badge", "panel", "overlay"].map((kind) => [
1280
- kind,
1281
- (id, entity) => publish(kind, id, entity).publisher
1282
- ])),
1283
- report,
1284
- remote: Object.freeze({ request(remoteReport, operation, payload, options) {
1285
- active();
1286
- ensure(object(remoteReport) && object(remoteReport.source), "invalid_payload", "A current source report is required");
1287
- const source = validateProducer(remoteReport.source.producer);
1288
- ensure(
1289
- source.pluginId === manifest.id && identifier(remoteReport.name) && identifier(operation),
1290
- "invalid_payload",
1291
- "Invalid remote report request"
1292
- );
1293
- const entity = validateEntity(remoteReport.entity);
1294
- ensure(typeof remoteReport.sequence === "string" && /^(0|[1-9]\d{0,19})$/.test(remoteReport.sequence) && BigInt(remoteReport.sequence) > 0n, "invalid_payload", "Invalid report sequence");
1295
- jsonBytes(payload, 224 * 1024);
1296
- return request("remote.request", {
1297
- source,
1298
- name: remoteReport.name,
1299
- entity,
1300
- sequence: remoteReport.sequence,
1301
- operation,
1302
- payload
1303
- }, options);
1304
- } }),
1305
- canvas(id, spec, entity) {
1306
- const { publisher, key } = publish(null, id, entity);
1307
- try {
1308
- publisher.replace({ kind: "canvas", canvas: spec });
1309
- } catch (error) {
1310
- publisher.dispose();
1311
- throw error;
1312
- }
1313
- return {
1314
- ...publisher,
1315
- write: (ansi, options) => request("canvas.write", { key, ansi }, options),
1316
- focus: (capture, options) => request("canvas.focus", { key, capture }, options)
1317
- };
1318
- },
1319
- ...Object.fromEntries(["Event", "Hook", "Action", "Input", "Select", "Resize", "Activate", "Deactivate"].map((name) => [`on${name}`, (event, handler, condition) => subscribe(name.toLowerCase(), event, handler, condition)])),
1320
- ...Object.fromEntries(["menu", "command", "key", "link"].map((kind) => [
1321
- kind,
1322
- (id, options, handler) => registerPrepared(prepareRegistration(kind, id, options, handler))
1323
- ])),
1324
- commandGroup,
1325
- schedule,
1326
- onDispose(cleanup) {
1327
- active();
1328
- ensure(typeof cleanup === "function" && cleanups.size < LIMITS.subscriptions, "queue_full", "Invalid or excessive cleanup callbacks");
1329
- cleanups.add(cleanup);
1330
- return { dispose: () => {
1331
- cleanups.delete(cleanup);
1332
- } };
1333
- },
1334
- panes: Object.freeze(Object.fromEntries(["create", "close", "restart", "input", "focus", "wait"].map((name) => [name, method(`pane.${name}`)]))),
1335
- projects: Object.freeze({ create: method("project.create"), remove: method("project.remove") }),
1336
- notifications: Object.freeze({ show: method("notification.show") }),
1337
- panels: Object.freeze({ open: (contributionId, options) => request("panel.open", { contributionId }, options) }),
1338
- url: Object.freeze({ open: (url, options) => request("url.open", { url }, options) }),
1339
- fetch: method("fetch"),
1340
- secrets: Object.freeze({ get: (name, options) => request("secret.get", { name }, options) }),
1341
- config: Object.freeze({ get: (options) => request("config.get", {}, options) }),
1342
- state: Object.freeze({
1343
- get: (key, options) => request("state.get", { key }, options),
1344
- set: (key, value, options) => request("state.set", { key, value }, options),
1345
- keys: (options) => request("state.keys", {}, options)
1346
- }),
1347
- context: Object.freeze({ get: (options) => request("context.get", {}, options) }),
1348
- popover: Object.freeze({ open: method("popover.open") }),
1349
- health: Object.freeze({ set: method("health.set") }),
1350
- webhook: Object.freeze({ ack: (deliveryId, options) => request("webhook.ack", { deliveryId }, options) })
1351
- });
1352
- return {
1353
- context,
1354
- receive: (frame) => peer.receive(frame),
1355
- async activate(definition) {
1356
- active();
1357
- ensure(definition?.id === manifest.id && typeof definition.activate === "function", "identity_mismatch", "Runtime plugin must match static manifest id");
1358
- const cleanup = await definition.activate(context);
1359
- if (typeof cleanup === "function") {
1360
- if (lifetime.signal.aborted) await cleanup();
1361
- else context.onDispose(cleanup);
1362
- }
1363
- },
1364
- dispose() {
1365
- if (disposal) return disposal;
1366
- for (const publisher of publishers.values()) {
1367
- try {
1368
- publisher.dispose();
1369
- } catch (error) {
1370
- onError(error);
1371
- }
1372
- }
1373
- for (const publisher of reports.values()) {
1374
- try {
1375
- publisher.dispose();
1376
- } catch (error) {
1377
- onError(error);
1378
- }
1379
- }
1380
- lifetime.abort();
1381
- for (const disposable of schedules) disposable.dispose();
1382
- peer.dispose();
1383
- subscriptions.clear();
1384
- disposal = Promise.allSettled([...cleanups].reverse().map((cleanup) => Promise.resolve().then(cleanup))).then((results) => {
1385
- for (const result of results) if (result.status === "rejected") onError(result.reason);
1386
- cleanups.clear();
1387
- });
1388
- return disposal;
1389
- }
1390
- };
1391
- }
1392
-
1393
- // src/prepare.mjs
1394
- import { constants } from "node:fs";
1395
- import { open, realpath, stat } from "node:fs/promises";
1396
- import { createHash } from "node:crypto";
1397
- import { isAbsolute, join, relative, resolve, sep } from "node:path";
1398
- function contained(root, path) {
1399
- const part = relative(root, path);
1400
- return part !== ".." && !part.startsWith(`..${sep}`) && !isAbsolute(part);
1401
- }
1402
- async function inspectPlugin(root) {
1403
- ensure(typeof root === "string" && isAbsolute(root), "invalid_source", "Plugin root must be absolute");
1404
- root = await realpath(root);
1405
- const file = await open(join(root, "package.json"), constants.O_RDONLY | constants.O_NOFOLLOW);
1406
- let source;
1407
- try {
1408
- const metadata = await file.stat();
1409
- ensure(metadata.isFile() && metadata.size > 0 && metadata.size <= LIMITS.manifestBytes, "invalid_manifest", "Package metadata exceeds its size limit");
1410
- const buffer = Buffer.alloc(LIMITS.manifestBytes + 1);
1411
- let size = 0;
1412
- while (size < buffer.length) {
1413
- const read = await file.read(buffer, size, buffer.length - size, size);
1414
- if (!read.bytesRead) break;
1415
- size += read.bytesRead;
1416
- }
1417
- ensure(size <= LIMITS.manifestBytes, "invalid_manifest", "Package metadata exceeds its size limit");
1418
- source = buffer.subarray(0, size).toString("utf8");
1419
- } finally {
1420
- await file.close();
1421
- }
1422
- const packageMetadata = JSON.parse(source);
1423
- const manifest = validateManifest(packageMetadata.standardPlugin);
1424
- const entry = await realpath(resolve(root, manifest.entry));
1425
- ensure(contained(root, entry) && (await stat(entry)).isFile(), "invalid_source", "Plugin entry must remain inside its source directory");
1426
- const manifestDigest = createHash("sha256").update(source).digest("hex");
1427
- return Object.freeze({ root, entry, manifest, manifestDigest });
1428
- }
1429
- async function preparePlugin({ root, manifestDigest, capabilities }) {
1430
- const prepared = await inspectPlugin(root);
1431
- ensure(prepared.manifestDigest === manifestDigest, "manifest_changed", "Plugin metadata changed after preparation or consent");
1432
- ensure(
1433
- Array.isArray(capabilities) && prepared.manifest.capabilities.every((capability) => capabilities.includes(capability)),
1434
- "consent_required",
1435
- "Plugin capabilities require installation consent"
1436
- );
1437
- return prepared;
1438
- }
1439
-
1440
- // src/channel.mjs
1441
- var framed = (message) => message?.type === "frame" ? message.frame : message;
1442
- var Outbox = class {
1443
- constructor(write) {
1444
- this.write = write;
1445
- this.queue = [];
1446
- this.bytes = 0;
1447
- this.closed = false;
1448
- }
1449
- push(message) {
1450
- ensure(!this.closed, "disposed", "Output channel is closed");
1451
- const frame = framed(message);
1452
- const serialized = jsonBytes(message, frameLimit(frame, true));
1453
- const size = Buffer.byteLength(serialized);
1454
- const key = frame.kind === "surface" ? JSON.stringify(["surface", frame.producer, frame.key]) : frame.kind === "report" ? JSON.stringify(["report", frame.producer, frame.name, frame.entity]) : null;
1455
- const previous = key === null ? -1 : this.queue.findIndex((item2) => item2.key === key);
1456
- const replaced = previous < 0 ? 0 : this.queue[previous].size;
1457
- const budget = LIMITS.queuedBytes + (frame.kind === "response" ? LIMITS.responseFrameBytes : 0);
1458
- ensure(
1459
- this.bytes - replaced + size <= budget && (previous >= 0 || this.queue.length < 256),
1460
- "queue_full",
1461
- "Runner output queue is full"
1462
- );
1463
- const item = { message: JSON.parse(serialized), size, key };
1464
- if (previous >= 0) this.queue.splice(previous, 1);
1465
- this.queue.push(item);
1466
- this.bytes += size - replaced;
1467
- this.flush();
1468
- }
1469
- flush() {
1470
- while (!this.closed && this.queue.length && this.write(this.queue[0].message)) {
1471
- this.bytes -= this.queue.shift().size;
1472
- }
1473
- }
1474
- dispose() {
1475
- this.closed = true;
1476
- this.queue.length = 0;
1477
- this.bytes = 0;
1478
- }
1479
- };
1480
- function portChannel(port, receive, onError) {
1481
- let credits = 16;
1482
- let closed = false;
1483
- const outbox = new Outbox((message) => {
1484
- if (!credits) return false;
1485
- port.postMessage({ type: "delivery", message });
1486
- credits--;
1487
- return true;
1488
- });
1489
- function listener(envelope) {
1490
- if (closed) return;
1491
- try {
1492
- if (envelope?.type === "credit") {
1493
- ensure(credits < 16, "invalid_payload", "Unexpected port credit");
1494
- credits++;
1495
- outbox.flush();
1496
- } else {
1497
- ensure(envelope?.type === "delivery", "invalid_payload", "Invalid port message");
1498
- jsonBytes(envelope.message, frameLimit(framed(envelope.message), true));
1499
- receive(envelope.message);
1500
- port.postMessage({ type: "credit" });
1501
- }
1502
- } catch (error) {
1503
- onError(error);
1504
- }
1505
- }
1506
- port.on("message", listener);
1507
- return { send: (message) => outbox.push(message), dispose() {
1508
- closed = true;
1509
- outbox.dispose();
1510
- port.off("message", listener);
1511
- } };
1512
- }
1513
-
1514
- // src/worker.mjs
1515
- var runtime;
1516
- var stopping = false;
1517
- function fatal(error) {
1518
- try {
1519
- channel.send({ type: "failure", error: wireError(error) });
1520
- } finally {
1521
- process.exitCode = 1;
1522
- void stop();
1523
- }
1524
- }
1525
- async function stop() {
1526
- if (stopping) return;
1527
- stopping = true;
1528
- try {
1529
- await runtime?.dispose();
1530
- } finally {
1531
- channel.send({ type: "stopped" });
1532
- }
1533
- }
1534
- var channel = portChannel(parentPort, (message) => {
1535
- if (message.type === "stop") {
1536
- void stop().catch(fatal);
1537
- return;
1538
- }
1539
- ensure(message.type === "frame" && runtime, "invalid_payload", "Worker runtime is unavailable");
1540
- runtime.receive(message.frame);
1541
- }, fatal);
1542
- try {
1543
- ensure(workerData.version === RUNNER_PROTOCOL_VERSION, "incompatible_version", "Daemon and runner protocol versions differ");
1544
- const prepared = await preparePlugin(workerData.source);
1545
- ensure(prepared.manifest.id === workerData.producer.pluginId, "identity_mismatch", "Prepared plugin identity differs from its producer");
1546
- runtime = createRuntime({
1547
- manifest: prepared.manifest,
1548
- producer: workerData.producer,
1549
- instanceId: String(workerData.generation),
1550
- send: (frame) => channel.send({ type: "frame", frame }),
1551
- onError: (error) => channel.send({ type: "diagnostic", error: wireError(error) })
1552
- });
1553
- ensure(!stopping, "cancelled", "Plugin loading was cancelled");
1554
- const module = await import(pathToFileURL(prepared.entry).href);
1555
- if (!stopping) {
1556
- await runtime.activate(module.default);
1557
- if (!stopping) channel.send({ type: "ready" });
1558
- }
1559
- } catch (error) {
1560
- fatal(error);
1561
- }