@wenathlan/devthink 1.1.15 → 2.0.2
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/CHANGELOG.md +1299 -0
- package/README.md +6 -0
- package/bridge.d.ts +698 -0
- package/bridge.d.ts.map +1 -0
- package/bridge.js +1877 -0
- package/bun.d.ts +8 -0
- package/bun.d.ts.map +1 -0
- package/bun.js +52329 -0
- package/caps/background.json +712 -0
- package/caps/cli.json +360 -0
- package/caps/library.json +3611 -0
- package/caps/mcp.json +126 -0
- package/caps/pagebridge.json +377 -0
- package/caps/popup.json +51 -0
- package/caps/sidepanel.json +522 -0
- package/checksums.txt +142 -0
- package/cli.d.ts +187 -0
- package/cli.d.ts.map +1 -0
- package/cli.js +18197 -0
- package/companion.d.ts +19 -0
- package/companion.d.ts.map +1 -0
- package/companion.js +389 -0
- package/crossbrowser.d.ts +277 -0
- package/crossbrowser.d.ts.map +1 -0
- package/crossbrowser.js +1191 -0
- package/dashdone.d.ts +273 -0
- package/dashdone.d.ts.map +1 -0
- package/dashdone.js +368 -0
- package/deno.d.ts +11 -0
- package/deno.d.ts.map +1 -0
- package/deno.js +52325 -0
- package/devthink.umd.js +52346 -0
- package/fixtures/bun.ts +7 -0
- package/fixtures/cjs.js +6 -0
- package/fixtures/deno.ts +6 -0
- package/fixtures/example-org-pagestate.json +22 -0
- package/fixtures/importers/automa-workflow.json +18 -0
- package/fixtures/importers/selenium-side.json +20 -0
- package/fixtures/importers/tabular-plan.csv +7 -0
- package/fixtures/importers/uivision-macro.json +10 -0
- package/fixtures/importers/v1-plan.json +13 -0
- package/fixtures/mcp-client.mjs +14 -0
- package/fixtures/pages/checkout.html +192 -0
- package/fixtures/pages/dashboard.html +110 -0
- package/fixtures/pages/feed.html +113 -0
- package/fixtures/pages/product-grid.html +150 -0
- package/fixtures/plans/form-inventory-plan.json +11 -0
- package/fixtures/plans/release-notes-plan.json +11 -0
- package/fixtures/recipes/agentscompete.json +11 -0
- package/fixtures/recipes/agentsforms.json +11 -0
- package/fixtures/recipes/agentsmonitor.json +11 -0
- package/fixtures/recipes/agentsreview.json +29 -0
- package/fixtures/recipes/agentswarm.json +11 -0
- package/fixtures/recipes/fillcalendar.json +12 -0
- package/fixtures/recipes/fillcheckout.json +13 -0
- package/fixtures/recipes/filldependentdropdowns.json +12 -0
- package/fixtures/recipes/fillfromcsv.json +13 -0
- package/fixtures/recipes/fillloginform.json +12 -0
- package/fixtures/recipes/fillmultistepwizard.json +13 -0
- package/fixtures/recipes/fillregistration.json +12 -0
- package/fixtures/recipes/fillsearchfilters.json +12 -0
- package/fixtures/recipes/filltypeahead.json +11 -0
- package/fixtures/recipes/monitoralerts.json +12 -0
- package/fixtures/recipes/monitoravailability.json +11 -0
- package/fixtures/recipes/monitornetworkquiet.json +12 -0
- package/fixtures/recipes/monitorpagechanges.json +11 -0
- package/fixtures/recipes/monitorpricechange.json +11 -0
- package/fixtures/recipes/monitorschedule.json +12 -0
- package/fixtures/recipes/scrapedynamicprices.json +13 -0
- package/fixtures/recipes/scrapeimagegallery.json +12 -0
- package/fixtures/recipes/scrapeinfinitefeed.json +13 -0
- package/fixtures/recipes/scrapenestedlists.json +12 -0
- package/fixtures/recipes/scrapeproductgrid.json +12 -0
- package/fixtures/recipes/scrapereviews.json +12 -0
- package/fixtures/recipes/scrapesearchresults.json +12 -0
- package/fixtures/recipes/scrapetablepagination.json +12 -0
- package/fixtures/recipes/testaccessibility.json +34 -0
- package/fixtures/recipes/testconsoleerrors.json +12 -0
- package/fixtures/recipes/testdeeplinks.json +12 -0
- package/fixtures/recipes/testformvalidation.json +13 -0
- package/fixtures/recipes/testlayoutshift.json +12 -0
- package/fixtures/recipes/testlinkcheck.json +12 -0
- package/fixtures/recipes/testloadtiming.json +12 -0
- package/fixtures/recipes/testvisualdiff.json +12 -0
- package/fixtures/workflows/changelog-digest-workflow.json +13 -0
- package/fixtures/workflows/form-survey-workflow.json +13 -0
- package/gallery.json +706 -0
- package/hardening.d.ts +81 -0
- package/hardening.d.ts.map +1 -0
- package/hardening.js +188 -0
- package/headless.d.ts +114 -0
- package/headless.d.ts.map +1 -0
- package/headless.js +11522 -0
- package/http.d.ts +636 -0
- package/http.d.ts.map +1 -0
- package/http.js +2165 -0
- package/index.cjs +54682 -0
- package/index.d.ts +40 -0
- package/index.d.ts.map +1 -0
- package/index.js +52310 -0
- package/index.neutral.js +46343 -0
- package/manifest.json +199 -0
- package/mcp.d.ts +501 -0
- package/mcp.d.ts.map +1 -0
- package/mcp.js +20515 -0
- package/memory.d.ts +2397 -0
- package/memory.d.ts.map +1 -0
- package/memory.js +5782 -0
- package/nativehost.template.json +10 -0
- package/node.cjs +54686 -0
- package/node.d.ts +8 -0
- package/node.d.ts.map +1 -0
- package/pack.d.ts +211 -0
- package/pack.d.ts.map +1 -0
- package/pack.js +805 -0
- package/package.json +101 -51
- package/policy.d.ts +1854 -0
- package/policy.d.ts.map +1 -0
- package/policy.js +12580 -0
- package/progress.d.ts +390 -0
- package/progress.d.ts.map +1 -0
- package/progress.js +645 -0
- package/protocol.d.ts +2336 -0
- package/protocol.d.ts.map +1 -0
- package/protocol.js +8334 -0
- package/schemas/audit.schema.json +226 -0
- package/schemas/capability.schema.json +113 -0
- package/schemas/envelope.schema.json +162 -0
- package/schemas/memory.schema.json +51 -0
- package/schemas/observation.schema.json +113 -0
- package/schemas/plan.schema.json +208 -0
- package/schemas/progress.schema.json +126 -0
- package/schemas/proposal.schema.json +68 -0
- package/schemas/session.schema.json +82 -0
- package/schemas/tool.schema.json +94 -0
- package/server.d.ts +435 -0
- package/server.d.ts.map +1 -0
- package/server.js +28872 -0
- package/umd-example.html +18 -0
- package/umd.d.ts +6 -0
- package/umd.d.ts.map +1 -0
- package/build.ts +0 -41
- package/check-secrets.ts +0 -52
- package/compatibility.ts +0 -37
- package/config.ts +0 -246
- package/devthink.ts +0 -397
- package/identity.ts +0 -156
- package/ids.ts +0 -22
- package/memory.ts +0 -95
- package/modes.ts +0 -43
- package/plugin.ts +0 -68
- package/providers.ts +0 -179
- package/server.ts +0 -264
- package/session.ts +0 -155
- package/storage.ts +0 -82
- package/stream.ts +0 -130
- package/sync.ts +0 -27
- package/terminal-ui.tsx +0 -155
- package/ui.ts +0 -143
- package/workspace.ts +0 -20
package/companion.d.ts
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/** The companion module of the 1.1.98 consolidation: the native host runtime interned in this one typescript module, so the companion family carries one source file the plain node recipe of the build compiles, stamps and ships beside the dist targets — never a binary blob, never a hand maintained runtime file. */
|
|
2
|
+
/** The host manifest template the build stamps and emits as dist/nativehost.template.json: the chromium native messaging host manifest of the optional companion process, with the placeholders the installer fills (the host name, the companion path and the generated extension id) and the version placeholder the build stamps. */
|
|
3
|
+
export declare const nativehosttemplatejson = "{\n \"name\": \"__native_host_name__\",\n \"description\": \"The devthink companion process: an optional native host that speaks length prefixed json over stdio and never runs until the user installs it.\",\n \"path\": \"__companion_path__\",\n \"type\": \"stdio\",\n \"allowed_origins\": [\n \"chrome-extension://__generated_extension_id__/\"\n ],\n \"devthinkBanner\": \"devthink __devthink_version__ native host manifest template \u2014 GPL-3.0-only \u2014 the chromium host manifest of the optional companion process\"\n}\n";
|
|
4
|
+
/** The native frame shape the companion speaks: every frame carries its kind and correlation id with an optional body. */
|
|
5
|
+
interface nativeframe {
|
|
6
|
+
kind: string;
|
|
7
|
+
correlationid: string;
|
|
8
|
+
body?: Record<string, unknown>;
|
|
9
|
+
}
|
|
10
|
+
/** The build stamp of the companion: the build recipe replaces the source marker with the package version, so the handshake reports the version of the build that shipped. */
|
|
11
|
+
export declare const companionbuild = "source";
|
|
12
|
+
/** The native bridge protocol major version this companion speaks: the handshake reports it and the upgrade path keeps compatibility for exactly one major version. */
|
|
13
|
+
export declare const companionprotocol = 1;
|
|
14
|
+
/** The native surfaces this companion exposes behind consent: the os dialog surface of the sensitive call class and the notification surface of the interaction call class. */
|
|
15
|
+
export declare const companionsurfaces: readonly string[];
|
|
16
|
+
/** Encodes one native message as the length prefixed json the chromium native messaging protocol carries: the four byte little endian length rides ahead of the utf8 payload. */
|
|
17
|
+
export declare function encodenativemessage(frame: nativeframe): Buffer;
|
|
18
|
+
export {};
|
|
19
|
+
//# sourceMappingURL=companion.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"companion.d.ts","sourceRoot":"","sources":["../companion.ts"],"names":[],"mappings":"AAAA,2TAA2T;AAE3T,wUAAwU;AACxU,eAAO,MAAM,sBAAsB,8hBAUlC,CAAC;AAQF,0HAA0H;AAC1H,UAAU,WAAW;IACnB,IAAI,EAAE,MAAM,CAAC;IACb,aAAa,EAAE,MAAM,CAAC;IACtB,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CAChC;AAED,8KAA8K;AAC9K,eAAO,MAAM,cAAc,WAAW,CAAC;AAEvC,uKAAuK;AACvK,eAAO,MAAM,iBAAiB,IAAI,CAAC;AAEnC,+KAA+K;AAC/K,eAAO,MAAM,iBAAiB,EAAE,SAAS,MAAM,EAAiC,CAAC;AA+BjF,iLAAiL;AACjL,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,WAAW,GAAG,MAAM,CAK9D"}
|
package/companion.js
ADDED
|
@@ -0,0 +1,389 @@
|
|
|
1
|
+
/*! devthink 2.0.2 companion — the optional native host of the native bridge — GPL-3.0-only — built with plain node, no native compiler */
|
|
2
|
+
|
|
3
|
+
// companion.ts
|
|
4
|
+
import { createHash, randomBytes } from "node:crypto";
|
|
5
|
+
import { appendFileSync, renameSync, statSync } from "node:fs";
|
|
6
|
+
import { createServer } from "node:net";
|
|
7
|
+
import { pathToFileURL } from "node:url";
|
|
8
|
+
var nativehosttemplatejson = `{
|
|
9
|
+
"name": "__native_host_name__",
|
|
10
|
+
"description": "The devthink companion process: an optional native host that speaks length prefixed json over stdio and never runs until the user installs it.",
|
|
11
|
+
"path": "__companion_path__",
|
|
12
|
+
"type": "stdio",
|
|
13
|
+
"allowed_origins": [
|
|
14
|
+
"chrome-extension://__generated_extension_id__/"
|
|
15
|
+
],
|
|
16
|
+
"devthinkBanner": "devthink __devthink_version__ native host manifest template \u2014 GPL-3.0-only \u2014 the chromium host manifest of the optional companion process"
|
|
17
|
+
}
|
|
18
|
+
`;
|
|
19
|
+
var companionbuild = "2.0.2";
|
|
20
|
+
var companionprotocol = 1;
|
|
21
|
+
var companionsurfaces = ["osdialog", "notification"];
|
|
22
|
+
var maxnativemessage = 1024 * 1024;
|
|
23
|
+
var websocketguid = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11";
|
|
24
|
+
var logpath = process.env.DEVTHINKCOMPANIONLOG ?? "";
|
|
25
|
+
var logbound = Number.parseInt(process.env.DEVTHINKCOMPANIONLOGBOUND ?? "", 10);
|
|
26
|
+
function logline(line) {
|
|
27
|
+
if (logpath === "") return;
|
|
28
|
+
const text = `${line}
|
|
29
|
+
`;
|
|
30
|
+
try {
|
|
31
|
+
if (Number.isFinite(logbound) && logbound > 0) {
|
|
32
|
+
try {
|
|
33
|
+
const size = statSync(logpath).size;
|
|
34
|
+
if (size + text.length > logbound) renameSync(logpath, `${logpath}.1`);
|
|
35
|
+
} catch {
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
appendFileSync(logpath, text);
|
|
39
|
+
} catch {
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
function encodenativemessage(frame) {
|
|
43
|
+
const payload = Buffer.from(JSON.stringify(frame), "utf8");
|
|
44
|
+
const head = Buffer.alloc(4);
|
|
45
|
+
head.writeUInt32LE(payload.length, 0);
|
|
46
|
+
return Buffer.concat([head, payload]);
|
|
47
|
+
}
|
|
48
|
+
function encodeframe(text) {
|
|
49
|
+
const payload = Buffer.from(text, "utf8");
|
|
50
|
+
if (payload.length < 126) return Buffer.concat([Buffer.from([129, payload.length]), payload]);
|
|
51
|
+
if (payload.length < 65536) {
|
|
52
|
+
const head2 = Buffer.alloc(4);
|
|
53
|
+
head2[0] = 129;
|
|
54
|
+
head2[1] = 126;
|
|
55
|
+
head2.writeUInt16BE(payload.length, 2);
|
|
56
|
+
return Buffer.concat([head2, payload]);
|
|
57
|
+
}
|
|
58
|
+
const head = Buffer.alloc(10);
|
|
59
|
+
head[0] = 129;
|
|
60
|
+
head[1] = 127;
|
|
61
|
+
head.writeBigUInt64BE(BigInt(payload.length), 2);
|
|
62
|
+
return Buffer.concat([head, payload]);
|
|
63
|
+
}
|
|
64
|
+
function decodeframes(buffer) {
|
|
65
|
+
const frames = [];
|
|
66
|
+
let rest = buffer;
|
|
67
|
+
while (rest.length >= 2) {
|
|
68
|
+
const opcode = (rest[0] ?? 0) & 15;
|
|
69
|
+
const masked = ((rest[1] ?? 0) & 128) !== 0;
|
|
70
|
+
let length = (rest[1] ?? 0) & 127;
|
|
71
|
+
let offset = 2;
|
|
72
|
+
if (length === 126) {
|
|
73
|
+
if (rest.length < 4) break;
|
|
74
|
+
length = rest.readUInt16BE(2);
|
|
75
|
+
offset = 4;
|
|
76
|
+
} else if (length === 127) {
|
|
77
|
+
if (rest.length < 10) break;
|
|
78
|
+
length = Number(rest.readBigUInt64BE(2));
|
|
79
|
+
offset = 10;
|
|
80
|
+
}
|
|
81
|
+
let mask = Buffer.alloc(0);
|
|
82
|
+
if (masked) {
|
|
83
|
+
if (rest.length < offset + 4) break;
|
|
84
|
+
mask = rest.subarray(offset, offset + 4);
|
|
85
|
+
offset += 4;
|
|
86
|
+
}
|
|
87
|
+
if (rest.length < offset + length) break;
|
|
88
|
+
const payload = Buffer.from(rest.subarray(offset, offset + length));
|
|
89
|
+
if (masked)
|
|
90
|
+
for (let index = 0; index < payload.length; index += 1)
|
|
91
|
+
payload[index] = (payload[index] ?? 0) ^ (mask[index % 4] ?? 0);
|
|
92
|
+
frames.push({ opcode, payload });
|
|
93
|
+
rest = rest.subarray(offset + length);
|
|
94
|
+
}
|
|
95
|
+
return { frames, rest };
|
|
96
|
+
}
|
|
97
|
+
var bridge = {
|
|
98
|
+
port: 0,
|
|
99
|
+
token: "",
|
|
100
|
+
idlewindow: void 0,
|
|
101
|
+
started: false,
|
|
102
|
+
extension: null,
|
|
103
|
+
clients: /* @__PURE__ */ new Set(),
|
|
104
|
+
lastframeat: Date.now()
|
|
105
|
+
};
|
|
106
|
+
function bridgerelay(text) {
|
|
107
|
+
for (const client of bridge.clients) {
|
|
108
|
+
try {
|
|
109
|
+
client.write(encodeframe(text));
|
|
110
|
+
} catch {
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
function startbridge(advertise) {
|
|
115
|
+
if (bridge.started) return;
|
|
116
|
+
const server = createServer((socket) => {
|
|
117
|
+
let buffer = Buffer.alloc(0);
|
|
118
|
+
let handshaked = false;
|
|
119
|
+
let authenticated = false;
|
|
120
|
+
let role = "client";
|
|
121
|
+
socket.on("data", (chunk) => {
|
|
122
|
+
buffer = Buffer.concat([buffer, chunk]);
|
|
123
|
+
if (!handshaked) {
|
|
124
|
+
const head = buffer.toString("latin1");
|
|
125
|
+
const split = head.indexOf("\r\n\r\n");
|
|
126
|
+
if (split < 0) return;
|
|
127
|
+
const request = head.slice(0, split);
|
|
128
|
+
const keymatch = request.match(/sec-websocket-key:\s*(.+)/i);
|
|
129
|
+
if (keymatch === null) {
|
|
130
|
+
socket.destroy();
|
|
131
|
+
return;
|
|
132
|
+
}
|
|
133
|
+
const accept = createHash("sha1").update(`${keymatch[1]?.trim() ?? ""}${websocketguid}`).digest("base64");
|
|
134
|
+
socket.write(
|
|
135
|
+
`HTTP/1.1 101 Switching Protocols\r
|
|
136
|
+
Upgrade: websocket\r
|
|
137
|
+
Connection: Upgrade\r
|
|
138
|
+
Sec-WebSocket-Accept: ${accept}\r
|
|
139
|
+
\r
|
|
140
|
+
`
|
|
141
|
+
);
|
|
142
|
+
buffer = buffer.subarray(Buffer.byteLength(`${request}\r
|
|
143
|
+
\r
|
|
144
|
+
`, "latin1"));
|
|
145
|
+
handshaked = true;
|
|
146
|
+
}
|
|
147
|
+
const { frames, rest } = decodeframes(buffer);
|
|
148
|
+
buffer = rest;
|
|
149
|
+
for (const frame of frames) {
|
|
150
|
+
if (frame.opcode === 8) {
|
|
151
|
+
socket.destroy();
|
|
152
|
+
return;
|
|
153
|
+
}
|
|
154
|
+
if (frame.opcode !== 1) continue;
|
|
155
|
+
let envelope;
|
|
156
|
+
try {
|
|
157
|
+
envelope = JSON.parse(frame.payload.toString("utf8"));
|
|
158
|
+
} catch {
|
|
159
|
+
socket.destroy();
|
|
160
|
+
return;
|
|
161
|
+
}
|
|
162
|
+
if (!authenticated) {
|
|
163
|
+
const token = typeof envelope.token === "string" ? envelope.token : "";
|
|
164
|
+
const wantedrole = envelope.role === "extension" ? "extension" : "client";
|
|
165
|
+
if (token === "" || createHash("sha256").update(token).digest("hex") !== createHash("sha256").update(bridge.token).digest("hex")) {
|
|
166
|
+
try {
|
|
167
|
+
socket.write(
|
|
168
|
+
encodeframe(JSON.stringify({ error: "The wsbridge frame token failed the session authentication." }))
|
|
169
|
+
);
|
|
170
|
+
} catch {
|
|
171
|
+
}
|
|
172
|
+
socket.destroy();
|
|
173
|
+
return;
|
|
174
|
+
}
|
|
175
|
+
if (wantedrole === "extension") {
|
|
176
|
+
if (bridge.extension !== null && bridge.extension.writable) {
|
|
177
|
+
try {
|
|
178
|
+
socket.write(
|
|
179
|
+
encodeframe(
|
|
180
|
+
JSON.stringify({ error: "The wsbridge session holds one extension connection at a time." })
|
|
181
|
+
)
|
|
182
|
+
);
|
|
183
|
+
} catch {
|
|
184
|
+
}
|
|
185
|
+
socket.destroy();
|
|
186
|
+
return;
|
|
187
|
+
}
|
|
188
|
+
bridge.extension = socket;
|
|
189
|
+
role = "extension";
|
|
190
|
+
}
|
|
191
|
+
authenticated = true;
|
|
192
|
+
bridge.clients.add(socket);
|
|
193
|
+
bridge.lastframeat = Date.now();
|
|
194
|
+
continue;
|
|
195
|
+
}
|
|
196
|
+
bridge.lastframeat = Date.now();
|
|
197
|
+
bridgerelay(JSON.stringify(envelope));
|
|
198
|
+
writeframe({
|
|
199
|
+
kind: "event",
|
|
200
|
+
correlationid: typeof envelope.correlationid === "string" ? envelope.correlationid : "run-bridge-1",
|
|
201
|
+
body: { relayed: true, role }
|
|
202
|
+
});
|
|
203
|
+
}
|
|
204
|
+
});
|
|
205
|
+
socket.on("close", () => {
|
|
206
|
+
bridge.clients.delete(socket);
|
|
207
|
+
if (bridge.extension === socket) bridge.extension = null;
|
|
208
|
+
});
|
|
209
|
+
socket.on("error", () => {
|
|
210
|
+
bridge.clients.delete(socket);
|
|
211
|
+
});
|
|
212
|
+
});
|
|
213
|
+
server.listen(0, "127.0.0.1", () => {
|
|
214
|
+
const address = server.address();
|
|
215
|
+
bridge.port = typeof address === "object" && address !== null ? address.port : 0;
|
|
216
|
+
bridge.token = randomBytes(24).toString("hex");
|
|
217
|
+
bridge.started = true;
|
|
218
|
+
logline(`wsbridge bound 127.0.0.1:${bridge.port}`);
|
|
219
|
+
advertise();
|
|
220
|
+
});
|
|
221
|
+
const sweep = setInterval(() => {
|
|
222
|
+
if (bridge.idlewindow !== void 0 && Date.now() - bridge.lastframeat > bridge.idlewindow) {
|
|
223
|
+
for (const client of bridge.clients) client.destroy();
|
|
224
|
+
bridge.clients.clear();
|
|
225
|
+
bridge.extension = null;
|
|
226
|
+
bridge.lastframeat = Date.now();
|
|
227
|
+
logline("wsbridge idle expiry closed the quiet session");
|
|
228
|
+
}
|
|
229
|
+
}, 1e3);
|
|
230
|
+
sweep.unref();
|
|
231
|
+
}
|
|
232
|
+
function writeframe(frame) {
|
|
233
|
+
process.stdout.write(encodenativemessage(frame));
|
|
234
|
+
logline(`native ${frame.kind} ${frame.correlationid}`);
|
|
235
|
+
}
|
|
236
|
+
function runsurface(frame) {
|
|
237
|
+
const body = frame.body ?? {};
|
|
238
|
+
const surface = typeof body.surface === "string" ? body.surface : "";
|
|
239
|
+
if (!companionsurfaces.includes(surface)) {
|
|
240
|
+
return {
|
|
241
|
+
kind: "error",
|
|
242
|
+
correlationid: frame.correlationid,
|
|
243
|
+
body: {
|
|
244
|
+
family: "surface",
|
|
245
|
+
message: `The native surface ${surface} sits outside the surface catalog.`,
|
|
246
|
+
retry: "none"
|
|
247
|
+
}
|
|
248
|
+
};
|
|
249
|
+
}
|
|
250
|
+
if (body.classconsent !== true || body.surfaceconsent !== true) {
|
|
251
|
+
return {
|
|
252
|
+
kind: "error",
|
|
253
|
+
correlationid: frame.correlationid,
|
|
254
|
+
body: {
|
|
255
|
+
family: "surface",
|
|
256
|
+
message: `The ${surface} surface refuses execution without an active consent grant.`,
|
|
257
|
+
retry: "none"
|
|
258
|
+
}
|
|
259
|
+
};
|
|
260
|
+
}
|
|
261
|
+
const presenter = typeof body.presenter === "string" ? body.presenter.trim() : "";
|
|
262
|
+
if (presenter === "") {
|
|
263
|
+
return {
|
|
264
|
+
kind: "call",
|
|
265
|
+
correlationid: frame.correlationid,
|
|
266
|
+
body: {
|
|
267
|
+
surface,
|
|
268
|
+
delivered: false,
|
|
269
|
+
reason: "No presenter configured for the surface; the user configured presenter command stays the only execution path."
|
|
270
|
+
}
|
|
271
|
+
};
|
|
272
|
+
}
|
|
273
|
+
return {
|
|
274
|
+
kind: "call",
|
|
275
|
+
correlationid: frame.correlationid,
|
|
276
|
+
body: {
|
|
277
|
+
surface,
|
|
278
|
+
delivered: false,
|
|
279
|
+
reason: `The presenter ${presenter} stays a user choice the companion records; the source build runs the presenter only through the user reviewed launch.`
|
|
280
|
+
}
|
|
281
|
+
};
|
|
282
|
+
}
|
|
283
|
+
async function handleframe(frame) {
|
|
284
|
+
if (frame === null || typeof frame !== "object" || typeof frame.kind !== "string" || typeof frame.correlationid !== "string" || frame.correlationid === "") {
|
|
285
|
+
writeframe({
|
|
286
|
+
kind: "error",
|
|
287
|
+
correlationid: "run-unknown-1",
|
|
288
|
+
body: {
|
|
289
|
+
family: "port",
|
|
290
|
+
message: "The native frame carries its kind and its correlation id.",
|
|
291
|
+
retry: "reconnect"
|
|
292
|
+
}
|
|
293
|
+
});
|
|
294
|
+
return;
|
|
295
|
+
}
|
|
296
|
+
const typed = frame;
|
|
297
|
+
const body = typed.body;
|
|
298
|
+
if (typed.kind === "handshake") {
|
|
299
|
+
const asked = typeof body?.protocol === "number" ? body.protocol : Number.parseInt(String(body?.protocol ?? ""), 10);
|
|
300
|
+
if (bridge.idlewindow === void 0 && typeof body?.idlewindow === "number" && body.idlewindow > 0)
|
|
301
|
+
bridge.idlewindow = body.idlewindow;
|
|
302
|
+
startbridge(() => {
|
|
303
|
+
writeframe({
|
|
304
|
+
kind: "advertisement",
|
|
305
|
+
correlationid: typed.correlationid,
|
|
306
|
+
body: {
|
|
307
|
+
port: bridge.port,
|
|
308
|
+
token: bridge.token,
|
|
309
|
+
...bridge.idlewindow !== void 0 ? { idlewindow: bridge.idlewindow } : {}
|
|
310
|
+
}
|
|
311
|
+
});
|
|
312
|
+
});
|
|
313
|
+
writeframe({
|
|
314
|
+
kind: "handshake",
|
|
315
|
+
correlationid: typed.correlationid,
|
|
316
|
+
body: {
|
|
317
|
+
build: companionbuild,
|
|
318
|
+
protocol: companionprotocol,
|
|
319
|
+
surfaces: [...companionsurfaces],
|
|
320
|
+
wsbridgeport: bridge.port,
|
|
321
|
+
...Number.isInteger(asked) && asked !== companionprotocol ? {
|
|
322
|
+
mismatch: `The extension speaks the native bridge protocol major version ${asked} while this companion speaks ${companionprotocol}; the upgrade path keeps compatibility for one major version.`
|
|
323
|
+
} : {}
|
|
324
|
+
}
|
|
325
|
+
});
|
|
326
|
+
return;
|
|
327
|
+
}
|
|
328
|
+
if (typed.kind === "heartbeat") {
|
|
329
|
+
writeframe({ kind: "heartbeat", correlationid: typed.correlationid, body: { at: Date.now() } });
|
|
330
|
+
return;
|
|
331
|
+
}
|
|
332
|
+
if (typed.kind === "call") {
|
|
333
|
+
writeframe(runsurface(typed));
|
|
334
|
+
return;
|
|
335
|
+
}
|
|
336
|
+
writeframe({
|
|
337
|
+
kind: "error",
|
|
338
|
+
correlationid: typed.correlationid,
|
|
339
|
+
body: {
|
|
340
|
+
family: "port",
|
|
341
|
+
message: `The native frame kind ${typed.kind} stays outside the companion surface.`,
|
|
342
|
+
retry: "none"
|
|
343
|
+
}
|
|
344
|
+
});
|
|
345
|
+
}
|
|
346
|
+
function main() {
|
|
347
|
+
let buffer = Buffer.alloc(0);
|
|
348
|
+
process.stdin.on("data", (chunk) => {
|
|
349
|
+
buffer = Buffer.concat([buffer, chunk]);
|
|
350
|
+
for (; ; ) {
|
|
351
|
+
if (buffer.length < 4) return;
|
|
352
|
+
const length = buffer.readUInt32LE(0);
|
|
353
|
+
if (length > maxnativemessage) {
|
|
354
|
+
writeframe({
|
|
355
|
+
kind: "error",
|
|
356
|
+
correlationid: "run-unknown-1",
|
|
357
|
+
body: {
|
|
358
|
+
family: "port",
|
|
359
|
+
message: "The native message exceeds the one megabyte cap of the native messaging protocol.",
|
|
360
|
+
retry: "none"
|
|
361
|
+
}
|
|
362
|
+
});
|
|
363
|
+
buffer = Buffer.alloc(0);
|
|
364
|
+
return;
|
|
365
|
+
}
|
|
366
|
+
if (buffer.length < 4 + length) return;
|
|
367
|
+
const payload = buffer.subarray(4, 4 + length);
|
|
368
|
+
buffer = buffer.subarray(4 + length);
|
|
369
|
+
let frame;
|
|
370
|
+
try {
|
|
371
|
+
frame = JSON.parse(payload.toString("utf8"));
|
|
372
|
+
} catch {
|
|
373
|
+
continue;
|
|
374
|
+
}
|
|
375
|
+
void handleframe(frame);
|
|
376
|
+
}
|
|
377
|
+
});
|
|
378
|
+
process.stdin.on("end", () => process.exit(0));
|
|
379
|
+
logline(`companion source build ${companionbuild} protocol ${companionprotocol} listening`);
|
|
380
|
+
}
|
|
381
|
+
if (process.argv[1] !== void 0 && import.meta.url === pathToFileURL(process.argv[1]).href) main();
|
|
382
|
+
export {
|
|
383
|
+
companionbuild,
|
|
384
|
+
companionprotocol,
|
|
385
|
+
companionsurfaces,
|
|
386
|
+
encodenativemessage,
|
|
387
|
+
nativehosttemplatejson
|
|
388
|
+
};
|
|
389
|
+
//# sourceMappingURL=companion.js.map
|