@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.
@@ -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.47";
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.47";
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.47";
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.47";
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.47";
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.47";
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.47";
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.47";
189
+ readonly moduleVersion: "0.1.49";
184
190
  } | {
185
191
  contract: "deployment.result.v1";
186
192
  moduleRef: "execution-browser-extension";
187
- moduleVersion: "0.1.47";
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.47";
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: descriptor.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
- : "Chrome 扩展已重新启动,需要自动刷新当前运行会话证据",
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.47";
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.47",
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
- void runObserverRecovery();
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
- void runObserverRecovery();
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
- void runObserverRecovery();
15682
+ observerRecoveryRearm.startupReady();
15652
15683
  });
15653
15684
  });
15654
15685
  void startBackgroundRuntime();
@@ -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
- if (session?.extensionInstanceId !== extensionInstanceId) {
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,4 @@
1
+ export declare function createObserverRecoveryRearm(recover: () => void): Readonly<{
2
+ startupReady: () => void;
3
+ bridgeSessionEstablished: (epoch: number) => boolean;
4
+ }>;
@@ -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
+ }
@@ -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>;
@@ -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() {
@@ -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
- void runObserverRecovery();
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
- void runObserverRecovery();
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
- void runObserverRecovery();
2081
+ observerRecoveryRearm.startupReady();
2071
2082
  });
2072
2083
  });
2073
2084
  void startBackgroundRuntime();
package/manifest.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "manifest_version": 3,
3
3
  "name": "ProFlow Execution Browser",
4
- "version": "0.1.47",
4
+ "version": "0.1.49",
5
5
  "permissions": [
6
6
  "tabs",
7
7
  "storage"
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tomflow/proflow-execution-browser-extension",
3
- "version": "0.1.47",
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-execution-contracts": "^0.1.10",
31
- "@tomflow/proflow-module-contract": "^0.1.13"
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",
@@ -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.47",
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.