@tomflow/proflow-execution-browser-extension 0.1.12 → 0.1.13
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 +6 -0
- package/DOCS.md +12 -4
- package/SETUP.md +10 -14
- package/dist/deployment/adapter.d.ts +42 -50
- package/dist/deployment/adapter.js +125 -103
- package/dist/deployment/descriptor.d.ts +4 -1
- package/dist/deployment/descriptor.js +5 -1
- package/dist/extension/background.js +189 -0
- package/dist/extension/provisioning-content.d.ts +1 -0
- package/dist/extension/provisioning-content.js +936 -0
- package/dist/src/configure-args.d.ts +3 -0
- package/dist/src/configure-args.js +23 -0
- package/dist/src/configure.js +8 -71
- package/dist/src/custom-gpt-editor-driver.d.ts +51 -0
- package/dist/src/custom-gpt-editor-driver.js +116 -0
- package/dist/src/custom-gpt-knowledge.d.ts +21 -0
- package/dist/src/custom-gpt-knowledge.js +148 -0
- package/dist/src/custom-gpt-provisioner.d.ts +78 -0
- package/dist/src/custom-gpt-provisioner.js +225 -0
- package/dist/src/custom-gpt-role.d.ts +66 -0
- package/dist/src/custom-gpt-role.js +98 -0
- package/dist/src/install-workflow.d.ts +29 -0
- package/dist/src/install-workflow.js +64 -0
- package/dist/src/pairing.d.ts +20 -0
- package/dist/src/pairing.js +176 -0
- package/dist/src/provisioning-bridge.d.ts +46 -0
- package/dist/src/provisioning-bridge.js +314 -0
- package/extension/background.ts +264 -3
- package/extension/provisioning-content.ts +1033 -0
- package/manifest.json +9 -1
- package/package.json +7 -5
- package/proflow.module.json +5 -1
|
@@ -3,7 +3,7 @@ export const descriptor = {
|
|
|
3
3
|
contractVersion: "1.0.0",
|
|
4
4
|
moduleRef: "execution-browser-extension",
|
|
5
5
|
packageName: "@tomflow/proflow-execution-browser-extension",
|
|
6
|
-
moduleVersion: "0.1.
|
|
6
|
+
moduleVersion: "0.1.13",
|
|
7
7
|
kind: "browser-extension",
|
|
8
8
|
templateVersion: "1.0.0",
|
|
9
9
|
platformCompatibility: ">=1.0.0 <2.0.0",
|
|
@@ -16,6 +16,10 @@ export const descriptor = {
|
|
|
16
16
|
contractRef: "execution-browser-executor",
|
|
17
17
|
version: "1.0.0",
|
|
18
18
|
},
|
|
19
|
+
{
|
|
20
|
+
contractRef: "custom-gpt-web-provisioning",
|
|
21
|
+
version: "1.0.0",
|
|
22
|
+
},
|
|
19
23
|
],
|
|
20
24
|
requires: [
|
|
21
25
|
{
|
|
@@ -13912,6 +13912,7 @@ async function bootstrapManagedRuntimeConfig() {
|
|
|
13912
13912
|
if (!isRecord(raw)) return;
|
|
13913
13913
|
const managed = raw;
|
|
13914
13914
|
const bridge = parseConfig(managed.proflowRuntimeBridge);
|
|
13915
|
+
const provisioning = parseConfig(managed.proflowProvisioningBridge);
|
|
13915
13916
|
const task = parseConfig(managed.proflowTaskApplication);
|
|
13916
13917
|
const approval = parseConfig(managed.proflowApprovalApplication);
|
|
13917
13918
|
if (!bridge || !task || !approval) {
|
|
@@ -13919,6 +13920,7 @@ async function bootstrapManagedRuntimeConfig() {
|
|
|
13919
13920
|
}
|
|
13920
13921
|
await chrome.storage.local.set({
|
|
13921
13922
|
proflowRuntimeBridge: bridge,
|
|
13923
|
+
...provisioning ? { proflowProvisioningBridge: provisioning } : {},
|
|
13922
13924
|
proflowTaskApplication: task,
|
|
13923
13925
|
proflowApprovalApplication: approval
|
|
13924
13926
|
});
|
|
@@ -13927,6 +13929,10 @@ async function bridgeConfig() {
|
|
|
13927
13929
|
const stored = await chrome.storage.local.get("proflowRuntimeBridge");
|
|
13928
13930
|
return parseConfig(stored.proflowRuntimeBridge);
|
|
13929
13931
|
}
|
|
13932
|
+
async function provisioningBridgeConfig() {
|
|
13933
|
+
const stored = await chrome.storage.local.get("proflowProvisioningBridge");
|
|
13934
|
+
return parseConfig(stored.proflowProvisioningBridge);
|
|
13935
|
+
}
|
|
13930
13936
|
async function taskApplicationConfig() {
|
|
13931
13937
|
const stored = await chrome.storage.local.get("proflowTaskApplication");
|
|
13932
13938
|
return parseConfig(stored.proflowTaskApplication);
|
|
@@ -14379,6 +14385,68 @@ async function executeCommand(command) {
|
|
|
14379
14385
|
}
|
|
14380
14386
|
throw new Error("BROWSER_PRIMITIVE_UNAVAILABLE");
|
|
14381
14387
|
}
|
|
14388
|
+
function missingProvisioningReceiver(error46) {
|
|
14389
|
+
const message = error46 instanceof Error ? error46.message : String(error46);
|
|
14390
|
+
return message.includes("Could not establish connection") || message.includes("Receiving end does not exist");
|
|
14391
|
+
}
|
|
14392
|
+
function isEditorUrl(url2) {
|
|
14393
|
+
return url2 === "https://chatgpt.com/gpts/editor" || Boolean(url2?.startsWith("https://chatgpt.com/gpts/editor/"));
|
|
14394
|
+
}
|
|
14395
|
+
async function provisioningContentCommand(tabId, operation, request) {
|
|
14396
|
+
let receiverReloaded = false;
|
|
14397
|
+
for (let attempt = 0; attempt < 60; attempt += 1) {
|
|
14398
|
+
let response;
|
|
14399
|
+
try {
|
|
14400
|
+
response = await chrome.tabs.sendMessage(tabId, {
|
|
14401
|
+
type: "PROFLOW_PROVISIONING_COMMAND",
|
|
14402
|
+
operation,
|
|
14403
|
+
request
|
|
14404
|
+
});
|
|
14405
|
+
} catch (error46) {
|
|
14406
|
+
if (!receiverReloaded && missingProvisioningReceiver(error46)) {
|
|
14407
|
+
try {
|
|
14408
|
+
const tab = await chrome.tabs.get(tabId);
|
|
14409
|
+
if (tab.status === "complete" && isEditorUrl(tab.url)) {
|
|
14410
|
+
await chrome.tabs.reload(tabId);
|
|
14411
|
+
receiverReloaded = true;
|
|
14412
|
+
}
|
|
14413
|
+
} catch {
|
|
14414
|
+
}
|
|
14415
|
+
}
|
|
14416
|
+
if (attempt === 59) throw error46;
|
|
14417
|
+
await sleep(250);
|
|
14418
|
+
continue;
|
|
14419
|
+
}
|
|
14420
|
+
if (!isRecord(response) || response.ok !== true) {
|
|
14421
|
+
const detail = isRecord(response) && typeof response.error === "string" ? response.error : "PROVISIONING_CONTENT_FAILED";
|
|
14422
|
+
if ((detail === "PROVISIONING_SURFACE_NOT_READY" || detail === "GPT_EDITOR_CONFIGURE_SURFACE_NOT_READY") && attempt < 59) {
|
|
14423
|
+
await sleep(250);
|
|
14424
|
+
continue;
|
|
14425
|
+
}
|
|
14426
|
+
throw new Error(detail);
|
|
14427
|
+
}
|
|
14428
|
+
return response.value;
|
|
14429
|
+
}
|
|
14430
|
+
throw new Error("PROVISIONING_CONTENT_TIMEOUT");
|
|
14431
|
+
}
|
|
14432
|
+
async function executeProvisioningCommand(command) {
|
|
14433
|
+
if (!isRecord(command.request))
|
|
14434
|
+
throw new Error("PROVISIONING_COMMAND_INVALID");
|
|
14435
|
+
let editorUrl = "https://chatgpt.com/gpts/editor";
|
|
14436
|
+
if (command.type === "FINALIZE_CUSTOM_GPT_AUTH") {
|
|
14437
|
+
const carrierUrl = new URL(text(command.request.carrierUrl, "CARRIER_URL"));
|
|
14438
|
+
const match = /^\/g\/(g-[A-Za-z0-9_-]+)$/.exec(carrierUrl.pathname);
|
|
14439
|
+
if (carrierUrl.origin !== "https://chatgpt.com" || carrierUrl.username !== "" || carrierUrl.password !== "" || carrierUrl.search !== "" || carrierUrl.hash !== "" || !match?.[1])
|
|
14440
|
+
throw new Error("PROVISIONING_CARRIER_URL_INVALID");
|
|
14441
|
+
editorUrl = `https://chatgpt.com/gpts/editor/${match[1]}`;
|
|
14442
|
+
}
|
|
14443
|
+
const tab = await chrome.tabs.create({ url: editorUrl, active: true });
|
|
14444
|
+
return provisioningContentCommand(
|
|
14445
|
+
numeric(tab.id, "TAB_ID"),
|
|
14446
|
+
command.type,
|
|
14447
|
+
command.request
|
|
14448
|
+
);
|
|
14449
|
+
}
|
|
14382
14450
|
async function bridgeFetch(config2, path, init = {}) {
|
|
14383
14451
|
return fetch(`${config2.endpoint}${path}`, {
|
|
14384
14452
|
...init,
|
|
@@ -14471,7 +14539,127 @@ async function runBridgeLoop() {
|
|
|
14471
14539
|
}
|
|
14472
14540
|
}
|
|
14473
14541
|
}
|
|
14542
|
+
var provisioningBridgeLoopStarted = false;
|
|
14543
|
+
async function runProvisioningBridgeLoop() {
|
|
14544
|
+
if (provisioningBridgeLoopStarted) return;
|
|
14545
|
+
provisioningBridgeLoopStarted = true;
|
|
14546
|
+
while (true) {
|
|
14547
|
+
const config2 = await provisioningBridgeConfig();
|
|
14548
|
+
if (!config2) {
|
|
14549
|
+
await sleep(1e3);
|
|
14550
|
+
continue;
|
|
14551
|
+
}
|
|
14552
|
+
const query = `?extensionInstanceId=${encodeURIComponent(extensionInstanceId)}`;
|
|
14553
|
+
try {
|
|
14554
|
+
const hello = await bridgeFetch(
|
|
14555
|
+
config2,
|
|
14556
|
+
"/v1/provisioning/session/hello",
|
|
14557
|
+
{
|
|
14558
|
+
method: "POST",
|
|
14559
|
+
body: JSON.stringify({
|
|
14560
|
+
extensionId: chrome.runtime.id,
|
|
14561
|
+
extensionInstanceId
|
|
14562
|
+
})
|
|
14563
|
+
}
|
|
14564
|
+
);
|
|
14565
|
+
if (!hello.ok) throw new Error("PROVISIONING_BRIDGE_HELLO_REJECTED");
|
|
14566
|
+
let lastHeartbeatAt = 0;
|
|
14567
|
+
while (true) {
|
|
14568
|
+
if (Date.now() - lastHeartbeatAt >= 5e3) {
|
|
14569
|
+
const heartbeat = await bridgeFetch(
|
|
14570
|
+
config2,
|
|
14571
|
+
`/v1/provisioning/session/heartbeat${query}`,
|
|
14572
|
+
{ method: "POST", body: "{}" }
|
|
14573
|
+
);
|
|
14574
|
+
if (!heartbeat.ok)
|
|
14575
|
+
throw new Error("PROVISIONING_BRIDGE_HEARTBEAT_REJECTED");
|
|
14576
|
+
lastHeartbeatAt = Date.now();
|
|
14577
|
+
}
|
|
14578
|
+
const response = await bridgeFetch(
|
|
14579
|
+
config2,
|
|
14580
|
+
`/v1/provisioning/commands/next${query}`
|
|
14581
|
+
);
|
|
14582
|
+
if (response.status === 204) {
|
|
14583
|
+
await sleep(250);
|
|
14584
|
+
continue;
|
|
14585
|
+
}
|
|
14586
|
+
if (!response.ok) throw new Error("PROVISIONING_BRIDGE_POLL_REJECTED");
|
|
14587
|
+
const command = await response.json();
|
|
14588
|
+
const commandHeartbeat = setInterval(() => {
|
|
14589
|
+
void bridgeFetch(
|
|
14590
|
+
config2,
|
|
14591
|
+
`/v1/provisioning/session/heartbeat${query}`,
|
|
14592
|
+
{ method: "POST", body: "{}" }
|
|
14593
|
+
).catch(() => void 0);
|
|
14594
|
+
}, 2e3);
|
|
14595
|
+
let result;
|
|
14596
|
+
try {
|
|
14597
|
+
result = {
|
|
14598
|
+
commandId: command.commandId,
|
|
14599
|
+
ok: true,
|
|
14600
|
+
value: await executeProvisioningCommand(command)
|
|
14601
|
+
};
|
|
14602
|
+
} catch (error46) {
|
|
14603
|
+
result = {
|
|
14604
|
+
commandId: command.commandId,
|
|
14605
|
+
ok: false,
|
|
14606
|
+
error: error46 instanceof Error ? error46.message : "PROVISIONING_EXTENSION_COMMAND_FAILED"
|
|
14607
|
+
};
|
|
14608
|
+
} finally {
|
|
14609
|
+
clearInterval(commandHeartbeat);
|
|
14610
|
+
}
|
|
14611
|
+
const reported = await bridgeFetch(
|
|
14612
|
+
config2,
|
|
14613
|
+
`/v1/provisioning/commands/result${query}`,
|
|
14614
|
+
{ method: "POST", body: JSON.stringify(result) }
|
|
14615
|
+
);
|
|
14616
|
+
if (!reported.ok)
|
|
14617
|
+
throw new Error("PROVISIONING_BRIDGE_RESULT_REJECTED");
|
|
14618
|
+
}
|
|
14619
|
+
} catch {
|
|
14620
|
+
await sleep(1e3);
|
|
14621
|
+
}
|
|
14622
|
+
}
|
|
14623
|
+
}
|
|
14624
|
+
function provisioningRelayBase64(bytes) {
|
|
14625
|
+
let binary = "";
|
|
14626
|
+
for (let offset = 0; offset < bytes.length; offset += 32768)
|
|
14627
|
+
binary += String.fromCharCode(...bytes.subarray(offset, offset + 32768));
|
|
14628
|
+
return btoa(binary);
|
|
14629
|
+
}
|
|
14474
14630
|
chrome.runtime.onMessage.addListener((message, sender, sendResponse) => {
|
|
14631
|
+
if (message.type === "PROFLOW_PROVISIONING_RELAY_FETCH") {
|
|
14632
|
+
const rawUrl = typeof message.url === "string" ? message.url : "";
|
|
14633
|
+
let parsed;
|
|
14634
|
+
try {
|
|
14635
|
+
parsed = new URL(rawUrl);
|
|
14636
|
+
} catch {
|
|
14637
|
+
sendResponse({ ok: false, error: "KNOWLEDGE_RELAY_URL_INVALID" });
|
|
14638
|
+
return;
|
|
14639
|
+
}
|
|
14640
|
+
if (parsed.protocol !== "http:" || parsed.hostname !== "127.0.0.1" || !parsed.pathname.startsWith("/v1/provisioning/files/") || parsed.username !== "" || parsed.password !== "" || parsed.search !== "" || parsed.hash !== "") {
|
|
14641
|
+
sendResponse({ ok: false, error: "KNOWLEDGE_RELAY_URL_INVALID" });
|
|
14642
|
+
return;
|
|
14643
|
+
}
|
|
14644
|
+
void fetch(parsed.toString(), { cache: "no-store" }).then(
|
|
14645
|
+
async (response) => {
|
|
14646
|
+
if (!response.ok) {
|
|
14647
|
+
sendResponse({
|
|
14648
|
+
ok: false,
|
|
14649
|
+
error: `KNOWLEDGE_RELAY_FETCH_FAILED:${response.status}`
|
|
14650
|
+
});
|
|
14651
|
+
return;
|
|
14652
|
+
}
|
|
14653
|
+
const bytes = new Uint8Array(await response.arrayBuffer());
|
|
14654
|
+
sendResponse({ ok: true, base64: provisioningRelayBase64(bytes) });
|
|
14655
|
+
},
|
|
14656
|
+
(error46) => sendResponse({
|
|
14657
|
+
ok: false,
|
|
14658
|
+
error: error46 instanceof Error ? `KNOWLEDGE_RELAY_FETCH_FAILED:${error46.message}` : "KNOWLEDGE_RELAY_FETCH_FAILED"
|
|
14659
|
+
})
|
|
14660
|
+
);
|
|
14661
|
+
return true;
|
|
14662
|
+
}
|
|
14475
14663
|
if (message.type === "PROFLOW_CONTENT_OBSERVATION" && message.observation && sender.tab?.id !== void 0 && sender.tab.windowId !== void 0) {
|
|
14476
14664
|
const observed = {
|
|
14477
14665
|
...message.observation,
|
|
@@ -14554,6 +14742,7 @@ async function startBackgroundRuntime() {
|
|
|
14554
14742
|
await bootstrapManagedRuntimeConfig();
|
|
14555
14743
|
await persistSnapshot();
|
|
14556
14744
|
void runBridgeLoop();
|
|
14745
|
+
void runProvisioningBridgeLoop();
|
|
14557
14746
|
void runObserverRecovery();
|
|
14558
14747
|
}
|
|
14559
14748
|
chrome.runtime.onInstalled.addListener(() => {
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|