@tomflow/proflow-execution-browser-extension 0.1.47 → 0.1.49
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/deployment/adapter.d.ts +17 -11
- package/dist/deployment/adapter.js +17 -4
- package/dist/deployment/descriptor.d.ts +1 -1
- package/dist/deployment/descriptor.js +1 -1
- package/dist/extension/background.js +35 -4
- package/dist/src/bridge.js +6 -1
- package/dist/src/install-workflow.d.ts +2 -0
- package/dist/src/observer-recovery-rearm.d.ts +4 -0
- package/dist/src/observer-recovery-rearm.js +23 -0
- package/dist/src/pairing.d.ts +2 -0
- package/dist/src/pairing.js +3 -1
- package/extension/background.ts +14 -3
- package/manifest.json +1 -1
- package/package.json +3 -3
- package/proflow.module.json +1 -1
- package/CHANGELOG.md +0 -49
|
@@ -14,11 +14,13 @@ export type RunningBridgeProbe = {
|
|
|
14
14
|
identity?: {
|
|
15
15
|
extensionId: string;
|
|
16
16
|
extensionInstanceId: string;
|
|
17
|
+
moduleVersion: string;
|
|
17
18
|
};
|
|
18
19
|
};
|
|
19
20
|
export declare function classifyBrowserLiveSetup(input: {
|
|
20
21
|
baseSetupReady: boolean;
|
|
21
22
|
evidenceInstanceId?: string;
|
|
23
|
+
expectedModuleVersion: string;
|
|
22
24
|
bridgeProbe: RunningBridgeProbe;
|
|
23
25
|
}): {
|
|
24
26
|
readonly setupReady: boolean;
|
|
@@ -26,6 +28,9 @@ export declare function classifyBrowserLiveSetup(input: {
|
|
|
26
28
|
} | {
|
|
27
29
|
setupReady: boolean;
|
|
28
30
|
issueCode: "EXTENSION_SESSION_OFFLINE";
|
|
31
|
+
} | {
|
|
32
|
+
setupReady: boolean;
|
|
33
|
+
issueCode: "EXTENSION_VERSION_MISMATCH";
|
|
29
34
|
} | {
|
|
30
35
|
setupReady: boolean;
|
|
31
36
|
issueCode: "EXTENSION_SESSION_REVALIDATION_REQUIRED";
|
|
@@ -39,6 +44,7 @@ export declare function pairBrowserExtensionSetup(context: ModuleCommandContext,
|
|
|
39
44
|
}): Promise<{
|
|
40
45
|
extensionId: string;
|
|
41
46
|
extensionInstanceId: string;
|
|
47
|
+
moduleVersion: string;
|
|
42
48
|
}>;
|
|
43
49
|
export declare const behaviorAdapter: {
|
|
44
50
|
readonly install: (context: ModuleCommandContext) => Promise<{
|
|
@@ -47,7 +53,7 @@ export declare const behaviorAdapter: {
|
|
|
47
53
|
ok: true;
|
|
48
54
|
status: "SUCCEEDED";
|
|
49
55
|
moduleRef: "execution-browser-extension";
|
|
50
|
-
moduleVersion: "0.1.
|
|
56
|
+
moduleVersion: "0.1.49";
|
|
51
57
|
data: {
|
|
52
58
|
loadDir: string;
|
|
53
59
|
};
|
|
@@ -60,7 +66,7 @@ export declare const behaviorAdapter: {
|
|
|
60
66
|
readonly ok: true;
|
|
61
67
|
readonly status: "SUCCEEDED";
|
|
62
68
|
readonly moduleRef: "execution-browser-extension";
|
|
63
|
-
readonly moduleVersion: "0.1.
|
|
69
|
+
readonly moduleVersion: "0.1.49";
|
|
64
70
|
};
|
|
65
71
|
observedEffects: never[];
|
|
66
72
|
}>;
|
|
@@ -70,7 +76,7 @@ export declare const behaviorAdapter: {
|
|
|
70
76
|
ok: true;
|
|
71
77
|
status: "SUCCEEDED";
|
|
72
78
|
moduleRef: "execution-browser-extension";
|
|
73
|
-
moduleVersion: "0.1.
|
|
79
|
+
moduleVersion: "0.1.49";
|
|
74
80
|
data: {
|
|
75
81
|
setupStatus: "ACTION_REQUIRED" | "READY";
|
|
76
82
|
runtimeStatus: "NOT_APPLICABLE";
|
|
@@ -82,7 +88,7 @@ export declare const behaviorAdapter: {
|
|
|
82
88
|
nextCommand: string;
|
|
83
89
|
} | {
|
|
84
90
|
scope: "SETUP";
|
|
85
|
-
code: "EXTENSION_SESSION_OFFLINE" | "EXTENSION_SESSION_REVALIDATION_REQUIRED" | undefined;
|
|
91
|
+
code: "EXTENSION_SESSION_OFFLINE" | "EXTENSION_SESSION_REVALIDATION_REQUIRED" | "EXTENSION_VERSION_MISMATCH" | undefined;
|
|
86
92
|
message: string;
|
|
87
93
|
relatedModuleRefs: string[];
|
|
88
94
|
nextCommand: string;
|
|
@@ -95,7 +101,7 @@ export declare const behaviorAdapter: {
|
|
|
95
101
|
result: {
|
|
96
102
|
contract: "deployment.result.v1";
|
|
97
103
|
moduleRef: "execution-browser-extension";
|
|
98
|
-
moduleVersion: "0.1.
|
|
104
|
+
moduleVersion: "0.1.49";
|
|
99
105
|
ok: false;
|
|
100
106
|
status: "ACTION_REQUIRED";
|
|
101
107
|
data: {
|
|
@@ -127,14 +133,14 @@ export declare const behaviorAdapter: {
|
|
|
127
133
|
readonly ok: true;
|
|
128
134
|
readonly status: "SUCCEEDED";
|
|
129
135
|
readonly moduleRef: "execution-browser-extension";
|
|
130
|
-
readonly moduleVersion: "0.1.
|
|
136
|
+
readonly moduleVersion: "0.1.49";
|
|
131
137
|
};
|
|
132
138
|
observedEffects: string[];
|
|
133
139
|
} | {
|
|
134
140
|
result: {
|
|
135
141
|
contract: "deployment.result.v1";
|
|
136
142
|
moduleRef: "execution-browser-extension";
|
|
137
|
-
moduleVersion: "0.1.
|
|
143
|
+
moduleVersion: "0.1.49";
|
|
138
144
|
ok: false;
|
|
139
145
|
status: "FAILED";
|
|
140
146
|
error: {
|
|
@@ -167,7 +173,7 @@ export declare const behaviorAdapter: {
|
|
|
167
173
|
ok: true;
|
|
168
174
|
status: "SUCCEEDED";
|
|
169
175
|
moduleRef: "execution-browser-extension";
|
|
170
|
-
moduleVersion: "0.1.
|
|
176
|
+
moduleVersion: "0.1.49";
|
|
171
177
|
data: {
|
|
172
178
|
docs: string;
|
|
173
179
|
};
|
|
@@ -180,11 +186,11 @@ export declare const behaviorAdapter: {
|
|
|
180
186
|
readonly ok: true;
|
|
181
187
|
readonly status: "SUCCEEDED";
|
|
182
188
|
readonly moduleRef: "execution-browser-extension";
|
|
183
|
-
readonly moduleVersion: "0.1.
|
|
189
|
+
readonly moduleVersion: "0.1.49";
|
|
184
190
|
} | {
|
|
185
191
|
contract: "deployment.result.v1";
|
|
186
192
|
moduleRef: "execution-browser-extension";
|
|
187
|
-
moduleVersion: "0.1.
|
|
193
|
+
moduleVersion: "0.1.49";
|
|
188
194
|
ok: false;
|
|
189
195
|
status: "FAILED";
|
|
190
196
|
error: {
|
|
@@ -201,7 +207,7 @@ export declare const behaviorAdapter: {
|
|
|
201
207
|
readonly ok: true;
|
|
202
208
|
readonly status: "SUCCEEDED";
|
|
203
209
|
readonly moduleRef: "execution-browser-extension";
|
|
204
|
-
readonly moduleVersion: "0.1.
|
|
210
|
+
readonly moduleVersion: "0.1.49";
|
|
205
211
|
};
|
|
206
212
|
observedEffects: never[];
|
|
207
213
|
}>;
|
|
@@ -263,6 +263,8 @@ async function materializeExecutorConfig(context, setup, prepared) {
|
|
|
263
263
|
});
|
|
264
264
|
}
|
|
265
265
|
async function persistPairedBrowserExtension(context, prepared, identity) {
|
|
266
|
+
if (identity.moduleVersion !== descriptor.moduleVersion)
|
|
267
|
+
throw new Error("EXTENSION_VERSION_MISMATCH");
|
|
266
268
|
const setup = { extensionId: identity.extensionId };
|
|
267
269
|
await writeFile(setupFile(context), `${JSON.stringify(setup, null, 2)}\n`, {
|
|
268
270
|
mode: 0o600,
|
|
@@ -270,7 +272,7 @@ async function persistPairedBrowserExtension(context, prepared, identity) {
|
|
|
270
272
|
await materializeExecutorConfig(context, setup, prepared);
|
|
271
273
|
const evidence = {
|
|
272
274
|
contract: "proflow.browser-extension-verification.v1",
|
|
273
|
-
moduleVersion:
|
|
275
|
+
moduleVersion: identity.moduleVersion,
|
|
274
276
|
loadDir: prepared.loadDir,
|
|
275
277
|
extensionId: identity.extensionId,
|
|
276
278
|
extensionInstanceId: identity.extensionInstanceId,
|
|
@@ -289,6 +291,11 @@ export function classifyBrowserLiveSetup(input) {
|
|
|
289
291
|
setupReady: false,
|
|
290
292
|
issueCode: "EXTENSION_SESSION_OFFLINE",
|
|
291
293
|
};
|
|
294
|
+
if (input.bridgeProbe.identity.moduleVersion !== input.expectedModuleVersion)
|
|
295
|
+
return {
|
|
296
|
+
setupReady: false,
|
|
297
|
+
issueCode: "EXTENSION_VERSION_MISMATCH",
|
|
298
|
+
};
|
|
292
299
|
if (input.bridgeProbe.identity.extensionInstanceId !== input.evidenceInstanceId)
|
|
293
300
|
return {
|
|
294
301
|
setupReady: false,
|
|
@@ -321,12 +328,15 @@ async function probeRunningBridgeSession(prepared, extensionId, timeoutMs) {
|
|
|
321
328
|
if (Reflect.get(body, "online") !== true)
|
|
322
329
|
return { kind: "PRESENT" };
|
|
323
330
|
const extensionInstanceId = Reflect.get(body, "extensionInstanceId");
|
|
331
|
+
const moduleVersion = Reflect.get(body, "moduleVersion");
|
|
324
332
|
if (typeof extensionInstanceId !== "string" ||
|
|
325
|
-
extensionInstanceId.length === 0
|
|
333
|
+
extensionInstanceId.length === 0 ||
|
|
334
|
+
typeof moduleVersion !== "string" ||
|
|
335
|
+
moduleVersion.length === 0)
|
|
326
336
|
throw new Error("RUNNING_BRIDGE_STATUS_INVALID");
|
|
327
337
|
return {
|
|
328
338
|
kind: "PRESENT",
|
|
329
|
-
identity: { extensionId, extensionInstanceId },
|
|
339
|
+
identity: { extensionId, extensionInstanceId, moduleVersion },
|
|
330
340
|
};
|
|
331
341
|
}
|
|
332
342
|
catch (error) {
|
|
@@ -454,6 +464,7 @@ export const behaviorAdapter = {
|
|
|
454
464
|
const live = classifyBrowserLiveSetup({
|
|
455
465
|
baseSetupReady,
|
|
456
466
|
...(evidence ? { evidenceInstanceId: evidence.extensionInstanceId } : {}),
|
|
467
|
+
expectedModuleVersion: descriptor.moduleVersion,
|
|
457
468
|
bridgeProbe,
|
|
458
469
|
});
|
|
459
470
|
const issue = !baseSetupReady
|
|
@@ -471,7 +482,9 @@ export const behaviorAdapter = {
|
|
|
471
482
|
code: live.issueCode,
|
|
472
483
|
message: live.issueCode === "EXTENSION_SESSION_OFFLINE"
|
|
473
484
|
? "Chrome 扩展已加载,但当前运行会话未在线"
|
|
474
|
-
:
|
|
485
|
+
: live.issueCode === "EXTENSION_VERSION_MISMATCH"
|
|
486
|
+
? "Chrome 当前运行的扩展版本与 Workspace 物化版本不一致"
|
|
487
|
+
: "Chrome 扩展已重新启动,需要自动刷新当前运行会话证据",
|
|
475
488
|
relatedModuleRefs: ["execution-runtime"],
|
|
476
489
|
nextCommand: "platform setup",
|
|
477
490
|
};
|
|
@@ -3,7 +3,7 @@ export declare const descriptor: {
|
|
|
3
3
|
readonly contractVersion: "1.0.0";
|
|
4
4
|
readonly moduleRef: "execution-browser-extension";
|
|
5
5
|
readonly packageName: "@tomflow/proflow-execution-browser-extension";
|
|
6
|
-
readonly moduleVersion: "0.1.
|
|
6
|
+
readonly moduleVersion: "0.1.49";
|
|
7
7
|
readonly kind: "browser-extension";
|
|
8
8
|
readonly templateVersion: "1.0.0";
|
|
9
9
|
readonly platformCompatibility: ">=1.0.0 <2.0.0";
|
|
@@ -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.49",
|
|
7
7
|
kind: "browser-extension",
|
|
8
8
|
templateVersion: "1.0.0",
|
|
9
9
|
platformCompatibility: ">=1.0.0 <2.0.0",
|
|
@@ -13843,6 +13843,29 @@ function createCollaborationCarrierApplication(options) {
|
|
|
13843
13843
|
return Object.freeze({ deliverMessage, recoverPending });
|
|
13844
13844
|
}
|
|
13845
13845
|
|
|
13846
|
+
// packages/execution-browser-extension/src/observer-recovery-rearm.ts
|
|
13847
|
+
function createObserverRecoveryRearm(recover) {
|
|
13848
|
+
let startupReady = false;
|
|
13849
|
+
let latestBridgeSessionEpoch = 0;
|
|
13850
|
+
const startupReadyAfterDenialRestore = () => {
|
|
13851
|
+
startupReady = true;
|
|
13852
|
+
recover();
|
|
13853
|
+
};
|
|
13854
|
+
const bridgeSessionEstablished = (epoch) => {
|
|
13855
|
+
if (!Number.isInteger(epoch) || epoch <= 0)
|
|
13856
|
+
throw new TypeError("bridge session epoch must be a positive integer");
|
|
13857
|
+
if (epoch <= latestBridgeSessionEpoch) return false;
|
|
13858
|
+
latestBridgeSessionEpoch = epoch;
|
|
13859
|
+
if (!startupReady) return false;
|
|
13860
|
+
recover();
|
|
13861
|
+
return true;
|
|
13862
|
+
};
|
|
13863
|
+
return Object.freeze({
|
|
13864
|
+
startupReady: startupReadyAfterDenialRestore,
|
|
13865
|
+
bridgeSessionEstablished
|
|
13866
|
+
});
|
|
13867
|
+
}
|
|
13868
|
+
|
|
13846
13869
|
// packages/execution-browser-extension/src/recovery-trigger.ts
|
|
13847
13870
|
async function boundedRecoveryObservation(observe, timeoutMs) {
|
|
13848
13871
|
if (!Number.isFinite(timeoutMs) || timeoutMs <= 0)
|
|
@@ -14206,6 +14229,7 @@ function createTaskObserver(options) {
|
|
|
14206
14229
|
|
|
14207
14230
|
// packages/execution-browser-extension/extension/background.ts
|
|
14208
14231
|
var extensionInstanceId = `extension:${crypto.randomUUID()}`;
|
|
14232
|
+
var extensionModuleVersion = chrome.runtime.getManifest().version;
|
|
14209
14233
|
var sessions = /* @__PURE__ */ new Map();
|
|
14210
14234
|
var browserOpenObservationGate = createBrowserOpenObservationGate();
|
|
14211
14235
|
var permissionHandling = /* @__PURE__ */ new Map();
|
|
@@ -14694,6 +14718,9 @@ function runObserverRecovery() {
|
|
|
14694
14718
|
});
|
|
14695
14719
|
return observerRecoveryInFlight;
|
|
14696
14720
|
}
|
|
14721
|
+
var observerRecoveryRearm = createObserverRecoveryRearm(() => {
|
|
14722
|
+
void runObserverRecovery();
|
|
14723
|
+
});
|
|
14697
14724
|
function observationFor(tabId) {
|
|
14698
14725
|
const observed = sessions.get(tabId);
|
|
14699
14726
|
if (!observed) throw new Error("CONTENT_SESSION_NOT_READY");
|
|
@@ -15273,6 +15300,7 @@ async function bridgeFetch(config2, path, init = {}) {
|
|
|
15273
15300
|
});
|
|
15274
15301
|
}
|
|
15275
15302
|
var bridgeLoopStarted = false;
|
|
15303
|
+
var bridgeSessionEpoch = 0;
|
|
15276
15304
|
async function runBridgeLoop() {
|
|
15277
15305
|
if (bridgeLoopStarted) return;
|
|
15278
15306
|
bridgeLoopStarted = true;
|
|
@@ -15288,10 +15316,13 @@ async function runBridgeLoop() {
|
|
|
15288
15316
|
method: "POST",
|
|
15289
15317
|
body: JSON.stringify({
|
|
15290
15318
|
extensionId: chrome.runtime.id,
|
|
15291
|
-
extensionInstanceId
|
|
15319
|
+
extensionInstanceId,
|
|
15320
|
+
moduleVersion: extensionModuleVersion
|
|
15292
15321
|
})
|
|
15293
15322
|
});
|
|
15294
15323
|
if (!hello.ok) throw new Error("BRIDGE_HELLO_REJECTED");
|
|
15324
|
+
bridgeSessionEpoch += 1;
|
|
15325
|
+
observerRecoveryRearm.bridgeSessionEstablished(bridgeSessionEpoch);
|
|
15295
15326
|
await publishCarrierAttentions();
|
|
15296
15327
|
let lastHeartbeatAt = Date.now();
|
|
15297
15328
|
let lastExtensionKeepaliveAt = Date.now();
|
|
@@ -15625,7 +15656,7 @@ async function startBackgroundRuntime() {
|
|
|
15625
15656
|
void runProvisioningBridgeLoop();
|
|
15626
15657
|
const suppressedContinuations = await rebuildCarrierAttentionsFromTabs();
|
|
15627
15658
|
suppressNextObserverRecovery(suppressedContinuations);
|
|
15628
|
-
|
|
15659
|
+
observerRecoveryRearm.startupReady();
|
|
15629
15660
|
}
|
|
15630
15661
|
chrome.action.onClicked.addListener(() => {
|
|
15631
15662
|
void openTaskPage();
|
|
@@ -15637,7 +15668,7 @@ chrome.runtime.onInstalled.addListener(() => {
|
|
|
15637
15668
|
void runBridgeLoop();
|
|
15638
15669
|
const suppressedContinuations = await rebuildCarrierAttentionsFromTabs();
|
|
15639
15670
|
suppressNextObserverRecovery(suppressedContinuations);
|
|
15640
|
-
|
|
15671
|
+
observerRecoveryRearm.startupReady();
|
|
15641
15672
|
});
|
|
15642
15673
|
});
|
|
15643
15674
|
chrome.runtime.onStartup.addListener(() => {
|
|
@@ -15648,7 +15679,7 @@ chrome.runtime.onStartup.addListener(() => {
|
|
|
15648
15679
|
void runBridgeLoop();
|
|
15649
15680
|
const suppressedContinuations = await rebuildCarrierAttentionsFromTabs();
|
|
15650
15681
|
suppressNextObserverRecovery(suppressedContinuations);
|
|
15651
|
-
|
|
15682
|
+
observerRecoveryRearm.startupReady();
|
|
15652
15683
|
});
|
|
15653
15684
|
});
|
|
15654
15685
|
void startBackgroundRuntime();
|
package/dist/src/bridge.js
CHANGED
|
@@ -217,6 +217,7 @@ export async function createBrowserRealityBridgeServer(options) {
|
|
|
217
217
|
sessionOnline: sessionOnline(),
|
|
218
218
|
commandConsumerReady: commandConsumerReady(),
|
|
219
219
|
extensionInstanceId: session?.extensionInstanceId ?? null,
|
|
220
|
+
moduleVersion: session?.moduleVersion ?? null,
|
|
220
221
|
queuedCommands: queue.length,
|
|
221
222
|
pendingCommands: pending.size,
|
|
222
223
|
lastCommandPollAt,
|
|
@@ -317,7 +318,9 @@ export async function createBrowserRealityBridgeServer(options) {
|
|
|
317
318
|
stringField(body, "extensionId") !== options.extensionId)
|
|
318
319
|
throw new BrowserRealityBridgeError("BRIDGE_AUTH_INVALID", "extension identity mismatch");
|
|
319
320
|
const extensionInstanceId = stringField(body, "extensionInstanceId");
|
|
320
|
-
|
|
321
|
+
const moduleVersion = stringField(body, "moduleVersion");
|
|
322
|
+
if (session?.extensionInstanceId !== extensionInstanceId ||
|
|
323
|
+
session?.moduleVersion !== moduleVersion) {
|
|
321
324
|
lastCommandPollAt = null;
|
|
322
325
|
lastCommandDeliveredAt = null;
|
|
323
326
|
lastCommandResultAt = null;
|
|
@@ -325,6 +328,7 @@ export async function createBrowserRealityBridgeServer(options) {
|
|
|
325
328
|
}
|
|
326
329
|
session = {
|
|
327
330
|
extensionInstanceId,
|
|
331
|
+
moduleVersion,
|
|
328
332
|
lastHeartbeatAt: now().getTime(),
|
|
329
333
|
};
|
|
330
334
|
send(response, 200, { accepted: true });
|
|
@@ -336,6 +340,7 @@ export async function createBrowserRealityBridgeServer(options) {
|
|
|
336
340
|
sessionOnline: sessionOnline(),
|
|
337
341
|
commandConsumerReady: commandConsumerReady(),
|
|
338
342
|
extensionInstanceId: session?.extensionInstanceId ?? null,
|
|
343
|
+
moduleVersion: session?.moduleVersion ?? null,
|
|
339
344
|
});
|
|
340
345
|
return;
|
|
341
346
|
}
|
|
@@ -14,6 +14,7 @@ export type BrowserExtensionPair = (context: {
|
|
|
14
14
|
}) => Promise<{
|
|
15
15
|
extensionId: string;
|
|
16
16
|
extensionInstanceId: string;
|
|
17
|
+
moduleVersion: string;
|
|
17
18
|
}>;
|
|
18
19
|
export declare function browserExtensionInstallInstruction(loadDir: string): string;
|
|
19
20
|
export declare function browserExtensionSetupSuccessMessage(): string;
|
|
@@ -27,4 +28,5 @@ export declare function runInteractiveBrowserExtensionSetup(input: {
|
|
|
27
28
|
}): Promise<{
|
|
28
29
|
extensionId: string;
|
|
29
30
|
extensionInstanceId: string;
|
|
31
|
+
moduleVersion: string;
|
|
30
32
|
}>;
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
export function createObserverRecoveryRearm(recover) {
|
|
2
|
+
let startupReady = false;
|
|
3
|
+
let latestBridgeSessionEpoch = 0;
|
|
4
|
+
const startupReadyAfterDenialRestore = () => {
|
|
5
|
+
startupReady = true;
|
|
6
|
+
recover();
|
|
7
|
+
};
|
|
8
|
+
const bridgeSessionEstablished = (epoch) => {
|
|
9
|
+
if (!Number.isInteger(epoch) || epoch <= 0)
|
|
10
|
+
throw new TypeError("bridge session epoch must be a positive integer");
|
|
11
|
+
if (epoch <= latestBridgeSessionEpoch)
|
|
12
|
+
return false;
|
|
13
|
+
latestBridgeSessionEpoch = epoch;
|
|
14
|
+
if (!startupReady)
|
|
15
|
+
return false;
|
|
16
|
+
recover();
|
|
17
|
+
return true;
|
|
18
|
+
};
|
|
19
|
+
return Object.freeze({
|
|
20
|
+
startupReady: startupReadyAfterDenialRestore,
|
|
21
|
+
bridgeSessionEstablished,
|
|
22
|
+
});
|
|
23
|
+
}
|
package/dist/src/pairing.d.ts
CHANGED
|
@@ -7,6 +7,7 @@ export interface BrowserExtensionPairingOptions {
|
|
|
7
7
|
export type BrowserExtensionPairingResult = {
|
|
8
8
|
extensionId: string;
|
|
9
9
|
extensionInstanceId: string;
|
|
10
|
+
moduleVersion: string;
|
|
10
11
|
};
|
|
11
12
|
export declare function createBrowserExtensionPairingServer(options: BrowserExtensionPairingOptions): Promise<Readonly<{
|
|
12
13
|
endpoint: string;
|
|
@@ -14,6 +15,7 @@ export declare function createBrowserExtensionPairingServer(options: BrowserExte
|
|
|
14
15
|
paired: boolean;
|
|
15
16
|
extensionId: string | null;
|
|
16
17
|
extensionInstanceId: string | null;
|
|
18
|
+
moduleVersion: string | null;
|
|
17
19
|
};
|
|
18
20
|
waitForPairing(): Promise<BrowserExtensionPairingResult>;
|
|
19
21
|
close(): Promise<void>;
|
package/dist/src/pairing.js
CHANGED
|
@@ -93,12 +93,13 @@ export async function createBrowserExtensionPairingServer(options) {
|
|
|
93
93
|
const body = await readJson(request);
|
|
94
94
|
const extensionId = text(body.extensionId);
|
|
95
95
|
const extensionInstanceId = text(body.extensionInstanceId);
|
|
96
|
+
const moduleVersion = text(body.moduleVersion);
|
|
96
97
|
if (!originId || extensionId !== originId)
|
|
97
98
|
throw new Error("PAIRING_AUTH_INVALID");
|
|
98
99
|
if (identity && identity.extensionId !== extensionId) {
|
|
99
100
|
throw new Error("PAIRING_AUTH_INVALID");
|
|
100
101
|
}
|
|
101
|
-
identity = { extensionId, extensionInstanceId };
|
|
102
|
+
identity = { extensionId, extensionInstanceId, moduleVersion };
|
|
102
103
|
send(response, 200, { accepted: true });
|
|
103
104
|
return;
|
|
104
105
|
}
|
|
@@ -160,6 +161,7 @@ export async function createBrowserExtensionPairingServer(options) {
|
|
|
160
161
|
paired: paired !== undefined,
|
|
161
162
|
extensionId: identity?.extensionId ?? null,
|
|
162
163
|
extensionInstanceId: identity?.extensionInstanceId ?? null,
|
|
164
|
+
moduleVersion: identity?.moduleVersion ?? null,
|
|
163
165
|
};
|
|
164
166
|
},
|
|
165
167
|
waitForPairing() {
|
package/extension/background.ts
CHANGED
|
@@ -18,6 +18,7 @@ import {
|
|
|
18
18
|
resolveRoutineCarrierPermission,
|
|
19
19
|
} from "../src/carrier-permission-lifecycle.js";
|
|
20
20
|
import { createCollaborationCarrierApplication } from "../src/collaboration-carrier.js";
|
|
21
|
+
import { createObserverRecoveryRearm } from "../src/observer-recovery-rearm.js";
|
|
21
22
|
import {
|
|
22
23
|
boundedRecoveryObservation,
|
|
23
24
|
shouldTriggerObserverRecovery,
|
|
@@ -132,6 +133,7 @@ type ChromeTab = {
|
|
|
132
133
|
type ChromeRuntime = {
|
|
133
134
|
runtime: {
|
|
134
135
|
id: string;
|
|
136
|
+
getManifest(): { version: string };
|
|
135
137
|
getURL(path: string): string;
|
|
136
138
|
onMessage: {
|
|
137
139
|
addListener(
|
|
@@ -186,6 +188,7 @@ type ChromeRuntime = {
|
|
|
186
188
|
declare const chrome: ChromeRuntime;
|
|
187
189
|
|
|
188
190
|
const extensionInstanceId = `extension:${crypto.randomUUID()}`;
|
|
191
|
+
const extensionModuleVersion = chrome.runtime.getManifest().version;
|
|
189
192
|
const sessions = new Map<number, ContentObservation>();
|
|
190
193
|
const browserOpenObservationGate = createBrowserOpenObservationGate();
|
|
191
194
|
const permissionHandling = new Map<number, string>();
|
|
@@ -865,6 +868,10 @@ function runObserverRecovery() {
|
|
|
865
868
|
return observerRecoveryInFlight;
|
|
866
869
|
}
|
|
867
870
|
|
|
871
|
+
const observerRecoveryRearm = createObserverRecoveryRearm(() => {
|
|
872
|
+
void runObserverRecovery();
|
|
873
|
+
});
|
|
874
|
+
|
|
868
875
|
function observationFor(tabId: number): ContentObservation {
|
|
869
876
|
const observed = sessions.get(tabId);
|
|
870
877
|
if (!observed) throw new Error("CONTENT_SESSION_NOT_READY");
|
|
@@ -1621,6 +1628,7 @@ async function bridgeFetch(
|
|
|
1621
1628
|
}
|
|
1622
1629
|
|
|
1623
1630
|
let bridgeLoopStarted = false;
|
|
1631
|
+
let bridgeSessionEpoch = 0;
|
|
1624
1632
|
async function runBridgeLoop() {
|
|
1625
1633
|
if (bridgeLoopStarted) return;
|
|
1626
1634
|
bridgeLoopStarted = true;
|
|
@@ -1637,9 +1645,12 @@ async function runBridgeLoop() {
|
|
|
1637
1645
|
body: JSON.stringify({
|
|
1638
1646
|
extensionId: chrome.runtime.id,
|
|
1639
1647
|
extensionInstanceId,
|
|
1648
|
+
moduleVersion: extensionModuleVersion,
|
|
1640
1649
|
}),
|
|
1641
1650
|
});
|
|
1642
1651
|
if (!hello.ok) throw new Error("BRIDGE_HELLO_REJECTED");
|
|
1652
|
+
bridgeSessionEpoch += 1;
|
|
1653
|
+
observerRecoveryRearm.bridgeSessionEstablished(bridgeSessionEpoch);
|
|
1643
1654
|
await publishCarrierAttentions();
|
|
1644
1655
|
// Hello only establishes a session. The first inner-loop action must be
|
|
1645
1656
|
// a real command poll so Runtime readiness cannot be granted by hello alone.
|
|
@@ -2043,7 +2054,7 @@ async function startBackgroundRuntime(): Promise<void> {
|
|
|
2043
2054
|
void runProvisioningBridgeLoop();
|
|
2044
2055
|
const suppressedContinuations = await rebuildCarrierAttentionsFromTabs();
|
|
2045
2056
|
suppressNextObserverRecovery(suppressedContinuations);
|
|
2046
|
-
|
|
2057
|
+
observerRecoveryRearm.startupReady();
|
|
2047
2058
|
}
|
|
2048
2059
|
|
|
2049
2060
|
chrome.action.onClicked.addListener(() => {
|
|
@@ -2056,7 +2067,7 @@ chrome.runtime.onInstalled.addListener(() => {
|
|
|
2056
2067
|
void runBridgeLoop();
|
|
2057
2068
|
const suppressedContinuations = await rebuildCarrierAttentionsFromTabs();
|
|
2058
2069
|
suppressNextObserverRecovery(suppressedContinuations);
|
|
2059
|
-
|
|
2070
|
+
observerRecoveryRearm.startupReady();
|
|
2060
2071
|
});
|
|
2061
2072
|
});
|
|
2062
2073
|
chrome.runtime.onStartup.addListener(() => {
|
|
@@ -2067,7 +2078,7 @@ chrome.runtime.onStartup.addListener(() => {
|
|
|
2067
2078
|
void runBridgeLoop();
|
|
2068
2079
|
const suppressedContinuations = await rebuildCarrierAttentionsFromTabs();
|
|
2069
2080
|
suppressNextObserverRecovery(suppressedContinuations);
|
|
2070
|
-
|
|
2081
|
+
observerRecoveryRearm.startupReady();
|
|
2071
2082
|
});
|
|
2072
2083
|
});
|
|
2073
2084
|
void startBackgroundRuntime();
|
package/manifest.json
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tomflow/proflow-execution-browser-extension",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.49",
|
|
4
4
|
"description": "Execution-owned MV3 Browser executor, evidence provider and browser application surface.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"publishConfig": {
|
|
@@ -27,8 +27,8 @@
|
|
|
27
27
|
"SETUP.md"
|
|
28
28
|
],
|
|
29
29
|
"dependencies": {
|
|
30
|
-
"@tomflow/proflow-
|
|
31
|
-
"@tomflow/proflow-
|
|
30
|
+
"@tomflow/proflow-module-contract": "^0.1.13",
|
|
31
|
+
"@tomflow/proflow-execution-contracts": "^0.1.10"
|
|
32
32
|
},
|
|
33
33
|
"devDependencies": {
|
|
34
34
|
"@tomflow/proflow-deployment-conformance": "^0.1.13",
|
package/proflow.module.json
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
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.49",
|
|
7
7
|
"kind": "browser-extension",
|
|
8
8
|
"templateVersion": "1.0.0",
|
|
9
9
|
"platformCompatibility": ">=1.0.0 <2.0.0",
|
package/CHANGELOG.md
DELETED
|
@@ -1,49 +0,0 @@
|
|
|
1
|
-
# @tomflow/proflow-execution-browser-extension
|
|
2
|
-
|
|
3
|
-
## 0.1.47
|
|
4
|
-
|
|
5
|
-
### Patch Changes
|
|
6
|
-
|
|
7
|
-
- Bound startup Carrier snapshot reconstruction so a hung ChatGPT tab cannot block durable Observer recovery, while preserving restored human-denial suppression and no-blind-replay semantics.
|
|
8
|
-
|
|
9
|
-
## 0.1.46
|
|
10
|
-
|
|
11
|
-
### Patch Changes
|
|
12
|
-
|
|
13
|
-
- Allow the durable TASK_RESUMED observer signal to use the bounded worker.wake trigger contract while preserving arbitrary-trigger rejection and browser delivery verification.
|
|
14
|
-
|
|
15
|
-
## 0.1.45
|
|
16
|
-
|
|
17
|
-
### Patch Changes
|
|
18
|
-
|
|
19
|
-
- Release the verified Real-3 B1 task recovery, exact execution identity, durable observer resume, bounded gateway error, and matching Agent Action contract fixes.
|
|
20
|
-
|
|
21
|
-
## 0.1.44
|
|
22
|
-
|
|
23
|
-
### Patch Changes
|
|
24
|
-
|
|
25
|
-
- Prefer the canonical ChatGPT prompt editor over earlier fallback textareas so worker wake messages are submitted through the real composer.
|
|
26
|
-
|
|
27
|
-
## 0.1.43
|
|
28
|
-
|
|
29
|
-
### Patch Changes
|
|
30
|
-
|
|
31
|
-
- Enrich Browser OBSERVE responses with Chrome-owned tab and window identity before returning the page observation.
|
|
32
|
-
|
|
33
|
-
## 0.1.42
|
|
34
|
-
|
|
35
|
-
### Patch Changes
|
|
36
|
-
|
|
37
|
-
- Close Real-3 node generation identity fencing across Platform Host admission, durable Execution idempotency, and Observer/Approval resume provenance.
|
|
38
|
-
|
|
39
|
-
## 0.1.41
|
|
40
|
-
|
|
41
|
-
### Patch Changes
|
|
42
|
-
|
|
43
|
-
- Resume the existing Task Observer after successful Tasks web mutations so READY nodes receive their normal NODE_READY or REOPEN wake without manual recovery.
|
|
44
|
-
|
|
45
|
-
## 0.1.40
|
|
46
|
-
|
|
47
|
-
### Patch Changes
|
|
48
|
-
|
|
49
|
-
- Make the authenticated ProFlow Tasks web app self-contained so its published browser module no longer escapes the `/tasks` session surface through a runtime relative import.
|