@tomflow/proflow-execution-browser-extension 0.1.25 → 0.1.27
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 +10 -10
- package/dist/deployment/descriptor.d.ts +1 -1
- package/dist/deployment/descriptor.js +1 -1
- package/dist/extension/background.js +43 -11
- package/dist/extension/content.js +5 -1
- package/dist/src/index.js +3 -1
- package/dist/src/recovery-trigger.d.ts +8 -0
- package/dist/src/recovery-trigger.js +10 -0
- package/dist/src/submitted-message.d.ts +5 -0
- package/dist/src/submitted-message.js +10 -0
- package/extension/background.ts +45 -11
- package/extension/content.ts +11 -1
- package/manifest.json +1 -1
- package/package.json +5 -5
- package/proflow.module.json +1 -1
- package/CHANGELOG.md +0 -25
|
@@ -47,7 +47,7 @@ export declare const behaviorAdapter: {
|
|
|
47
47
|
ok: true;
|
|
48
48
|
status: "SUCCEEDED";
|
|
49
49
|
moduleRef: "execution-browser-extension";
|
|
50
|
-
moduleVersion: "0.1.
|
|
50
|
+
moduleVersion: "0.1.27";
|
|
51
51
|
data: {
|
|
52
52
|
loadDir: string;
|
|
53
53
|
};
|
|
@@ -60,7 +60,7 @@ export declare const behaviorAdapter: {
|
|
|
60
60
|
readonly ok: true;
|
|
61
61
|
readonly status: "SUCCEEDED";
|
|
62
62
|
readonly moduleRef: "execution-browser-extension";
|
|
63
|
-
readonly moduleVersion: "0.1.
|
|
63
|
+
readonly moduleVersion: "0.1.27";
|
|
64
64
|
};
|
|
65
65
|
observedEffects: never[];
|
|
66
66
|
}>;
|
|
@@ -70,7 +70,7 @@ export declare const behaviorAdapter: {
|
|
|
70
70
|
ok: true;
|
|
71
71
|
status: "SUCCEEDED";
|
|
72
72
|
moduleRef: "execution-browser-extension";
|
|
73
|
-
moduleVersion: "0.1.
|
|
73
|
+
moduleVersion: "0.1.27";
|
|
74
74
|
data: {
|
|
75
75
|
setupStatus: "ACTION_REQUIRED" | "READY";
|
|
76
76
|
runtimeStatus: "NOT_APPLICABLE";
|
|
@@ -95,7 +95,7 @@ export declare const behaviorAdapter: {
|
|
|
95
95
|
result: {
|
|
96
96
|
contract: "deployment.result.v1";
|
|
97
97
|
moduleRef: "execution-browser-extension";
|
|
98
|
-
moduleVersion: "0.1.
|
|
98
|
+
moduleVersion: "0.1.27";
|
|
99
99
|
ok: false;
|
|
100
100
|
status: "ACTION_REQUIRED";
|
|
101
101
|
data: {
|
|
@@ -127,14 +127,14 @@ export declare const behaviorAdapter: {
|
|
|
127
127
|
readonly ok: true;
|
|
128
128
|
readonly status: "SUCCEEDED";
|
|
129
129
|
readonly moduleRef: "execution-browser-extension";
|
|
130
|
-
readonly moduleVersion: "0.1.
|
|
130
|
+
readonly moduleVersion: "0.1.27";
|
|
131
131
|
};
|
|
132
132
|
observedEffects: string[];
|
|
133
133
|
} | {
|
|
134
134
|
result: {
|
|
135
135
|
contract: "deployment.result.v1";
|
|
136
136
|
moduleRef: "execution-browser-extension";
|
|
137
|
-
moduleVersion: "0.1.
|
|
137
|
+
moduleVersion: "0.1.27";
|
|
138
138
|
ok: false;
|
|
139
139
|
status: "FAILED";
|
|
140
140
|
error: {
|
|
@@ -167,7 +167,7 @@ export declare const behaviorAdapter: {
|
|
|
167
167
|
ok: true;
|
|
168
168
|
status: "SUCCEEDED";
|
|
169
169
|
moduleRef: "execution-browser-extension";
|
|
170
|
-
moduleVersion: "0.1.
|
|
170
|
+
moduleVersion: "0.1.27";
|
|
171
171
|
data: {
|
|
172
172
|
docs: string;
|
|
173
173
|
};
|
|
@@ -180,11 +180,11 @@ export declare const behaviorAdapter: {
|
|
|
180
180
|
readonly ok: true;
|
|
181
181
|
readonly status: "SUCCEEDED";
|
|
182
182
|
readonly moduleRef: "execution-browser-extension";
|
|
183
|
-
readonly moduleVersion: "0.1.
|
|
183
|
+
readonly moduleVersion: "0.1.27";
|
|
184
184
|
} | {
|
|
185
185
|
contract: "deployment.result.v1";
|
|
186
186
|
moduleRef: "execution-browser-extension";
|
|
187
|
-
moduleVersion: "0.1.
|
|
187
|
+
moduleVersion: "0.1.27";
|
|
188
188
|
ok: false;
|
|
189
189
|
status: "FAILED";
|
|
190
190
|
error: {
|
|
@@ -201,7 +201,7 @@ export declare const behaviorAdapter: {
|
|
|
201
201
|
readonly ok: true;
|
|
202
202
|
readonly status: "SUCCEEDED";
|
|
203
203
|
readonly moduleRef: "execution-browser-extension";
|
|
204
|
-
readonly moduleVersion: "0.1.
|
|
204
|
+
readonly moduleVersion: "0.1.27";
|
|
205
205
|
};
|
|
206
206
|
observedEffects: never[];
|
|
207
207
|
}>;
|
|
@@ -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.27";
|
|
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.27",
|
|
7
7
|
kind: "browser-extension",
|
|
8
8
|
templateVersion: "1.0.0",
|
|
9
9
|
platformCompatibility: ">=1.0.0 <2.0.0",
|
|
@@ -13866,6 +13866,13 @@ function createTaskObserver(options) {
|
|
|
13866
13866
|
return Object.freeze({ advance, drive });
|
|
13867
13867
|
}
|
|
13868
13868
|
|
|
13869
|
+
// packages/execution-browser-extension/src/recovery-trigger.ts
|
|
13870
|
+
function shouldTriggerObserverRecovery(previous, current) {
|
|
13871
|
+
if (current.pageState !== "IDLE") return false;
|
|
13872
|
+
if (!previous) return true;
|
|
13873
|
+
return previous.pageState !== "IDLE" || previous.url !== current.url || previous.contentInstanceId !== current.contentInstanceId || previous.activityKind !== current.activityKind;
|
|
13874
|
+
}
|
|
13875
|
+
|
|
13869
13876
|
// packages/execution-browser-extension/extension/background.ts
|
|
13870
13877
|
var extensionInstanceId = `extension:${crypto.randomUUID()}`;
|
|
13871
13878
|
var sessions = /* @__PURE__ */ new Map();
|
|
@@ -14190,6 +14197,7 @@ var observerRecoveryRetryCount = 0;
|
|
|
14190
14197
|
function runObserverRecovery() {
|
|
14191
14198
|
if (observerRecoveryInFlight) return observerRecoveryInFlight;
|
|
14192
14199
|
observerRecoveryInFlight = (async () => {
|
|
14200
|
+
let recoveryNeedsRetry = false;
|
|
14193
14201
|
await collaborationCarrier.recoverPending(50).catch(() => void 0);
|
|
14194
14202
|
const signalBatch = await invokeObserverApplication(
|
|
14195
14203
|
"execution.listSignals",
|
|
@@ -14219,18 +14227,14 @@ function runObserverRecovery() {
|
|
|
14219
14227
|
signalRef: candidate.signalRef
|
|
14220
14228
|
});
|
|
14221
14229
|
} catch {
|
|
14230
|
+
recoveryNeedsRetry = true;
|
|
14222
14231
|
}
|
|
14223
14232
|
}
|
|
14224
14233
|
}
|
|
14225
14234
|
const listed = await invokeTaskApplication("task.list", {}).catch(
|
|
14226
14235
|
() => null
|
|
14227
14236
|
);
|
|
14228
|
-
if (listed === null
|
|
14229
|
-
observerRecoveryRetryCount += 1;
|
|
14230
|
-
setTimeout(() => void runObserverRecovery(), 2e3);
|
|
14231
|
-
} else if (listed !== null) {
|
|
14232
|
-
observerRecoveryRetryCount = 0;
|
|
14233
|
-
}
|
|
14237
|
+
if (listed === null) recoveryNeedsRetry = true;
|
|
14234
14238
|
if (isRecord(listed) && Array.isArray(listed.tasks)) {
|
|
14235
14239
|
for (const candidate of listed.tasks.slice(0, 100)) {
|
|
14236
14240
|
if (!isRecord(candidate) || typeof candidate.taskId !== "string")
|
|
@@ -14239,10 +14243,20 @@ function runObserverRecovery() {
|
|
|
14239
14243
|
continue;
|
|
14240
14244
|
await invokeTaskApplication("task.ensureWorkers", {
|
|
14241
14245
|
taskId: candidate.taskId
|
|
14242
|
-
}).catch(() =>
|
|
14243
|
-
|
|
14246
|
+
}).catch(() => {
|
|
14247
|
+
recoveryNeedsRetry = true;
|
|
14248
|
+
});
|
|
14249
|
+
await taskObserver.drive(candidate.taskId).catch(() => {
|
|
14250
|
+
recoveryNeedsRetry = true;
|
|
14251
|
+
});
|
|
14244
14252
|
}
|
|
14245
14253
|
}
|
|
14254
|
+
if (recoveryNeedsRetry && observerRecoveryRetryCount < 6) {
|
|
14255
|
+
observerRecoveryRetryCount += 1;
|
|
14256
|
+
setTimeout(() => void runObserverRecovery(), 2e3);
|
|
14257
|
+
} else if (!recoveryNeedsRetry) {
|
|
14258
|
+
observerRecoveryRetryCount = 0;
|
|
14259
|
+
}
|
|
14246
14260
|
const previousSystemState = await loadSystemObserverState().catch(
|
|
14247
14261
|
() => null
|
|
14248
14262
|
);
|
|
@@ -14285,6 +14299,21 @@ async function contentCommand(tabId, command) {
|
|
|
14285
14299
|
}
|
|
14286
14300
|
return response.value;
|
|
14287
14301
|
}
|
|
14302
|
+
async function waitForSubmittedMessage(tabId, fingerprint) {
|
|
14303
|
+
for (let attempt = 0; attempt < 60; attempt += 1) {
|
|
14304
|
+
try {
|
|
14305
|
+
const value = await contentCommand(tabId, {
|
|
14306
|
+
operation: "verify",
|
|
14307
|
+
fingerprint
|
|
14308
|
+
});
|
|
14309
|
+
if (isRecord(value) && value.verified === true)
|
|
14310
|
+
return observationFor(tabId);
|
|
14311
|
+
} catch {
|
|
14312
|
+
}
|
|
14313
|
+
await sleep(250);
|
|
14314
|
+
}
|
|
14315
|
+
throw new Error("MESSAGE_SUBMIT_REALITY_UNCONFIRMED");
|
|
14316
|
+
}
|
|
14288
14317
|
function numeric(value, name) {
|
|
14289
14318
|
if (!Number.isInteger(value)) throw new Error(`${name}_INVALID`);
|
|
14290
14319
|
return value;
|
|
@@ -14312,11 +14341,12 @@ async function executeCommand(command) {
|
|
|
14312
14341
|
return contentCommand(tabId, { operation: "observe" });
|
|
14313
14342
|
if (command.type === "SUBMIT") {
|
|
14314
14343
|
const before = observationFor(tabId);
|
|
14344
|
+
const fingerprint = text(command.fingerprint, "FINGERPRINT");
|
|
14315
14345
|
try {
|
|
14316
14346
|
await contentCommand(tabId, {
|
|
14317
14347
|
operation: "submit",
|
|
14318
14348
|
value: text(command.text, "TEXT"),
|
|
14319
|
-
fingerprint
|
|
14349
|
+
fingerprint
|
|
14320
14350
|
});
|
|
14321
14351
|
} catch (error46) {
|
|
14322
14352
|
const replacement = await waitForObservation(
|
|
@@ -14325,7 +14355,7 @@ async function executeCommand(command) {
|
|
|
14325
14355
|
).catch(() => null);
|
|
14326
14356
|
if (!replacement) throw error46;
|
|
14327
14357
|
}
|
|
14328
|
-
return
|
|
14358
|
+
return waitForSubmittedMessage(tabId, fingerprint);
|
|
14329
14359
|
}
|
|
14330
14360
|
if (command.type === "VERIFY")
|
|
14331
14361
|
return contentCommand(tabId, {
|
|
@@ -14670,6 +14700,7 @@ chrome.runtime.onMessage.addListener((message, sender, sendResponse) => {
|
|
|
14670
14700
|
return true;
|
|
14671
14701
|
}
|
|
14672
14702
|
if (message.type === "PROFLOW_CONTENT_OBSERVATION" && message.observation && sender.tab?.id !== void 0 && sender.tab.windowId !== void 0) {
|
|
14703
|
+
const previous = sessions.get(sender.tab.id);
|
|
14673
14704
|
const observed = {
|
|
14674
14705
|
...message.observation,
|
|
14675
14706
|
tabId: sender.tab.id,
|
|
@@ -14677,7 +14708,8 @@ chrome.runtime.onMessage.addListener((message, sender, sendResponse) => {
|
|
|
14677
14708
|
};
|
|
14678
14709
|
sessions.set(sender.tab.id, observed);
|
|
14679
14710
|
void persistSnapshot();
|
|
14680
|
-
if (observed
|
|
14711
|
+
if (shouldTriggerObserverRecovery(previous, observed))
|
|
14712
|
+
void runObserverRecovery();
|
|
14681
14713
|
sendResponse({ accepted: true, extensionInstanceId });
|
|
14682
14714
|
return;
|
|
14683
14715
|
}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { containsSubmittedFingerprint } from "../src/submitted-message.js";
|
|
1
2
|
const contentInstanceId = `content:${crypto.randomUUID()}`;
|
|
2
3
|
function pageState() {
|
|
3
4
|
if (document.querySelector('[role="dialog"]'))
|
|
@@ -25,7 +26,10 @@ function safeElement(selector) {
|
|
|
25
26
|
return element;
|
|
26
27
|
}
|
|
27
28
|
function hasFingerprint(fingerprint) {
|
|
28
|
-
return
|
|
29
|
+
return containsSubmittedFingerprint([...document.querySelectorAll('[data-message-author-role="user"]')].map((element) => ({
|
|
30
|
+
authorRole: element.getAttribute("data-message-author-role"),
|
|
31
|
+
textContent: element.textContent,
|
|
32
|
+
})), fingerprint);
|
|
29
33
|
}
|
|
30
34
|
chrome.runtime.onMessage.addListener((command, _sender, sendResponse) => {
|
|
31
35
|
void (async () => {
|
package/dist/src/index.js
CHANGED
|
@@ -240,7 +240,9 @@ export function createExecutionBrowserExtension(options) {
|
|
|
240
240
|
throw new ExecutionBrowserError("PRECONDITION_FAILED", "ROLE_URL_MISMATCH");
|
|
241
241
|
const precondition = await effectStarted(raw);
|
|
242
242
|
const opened = await options.browser.open(request.input.roleUrl);
|
|
243
|
-
await options.browser.submit(opened.tabId, `WORKER_BIND ${request.input.bootstrapFingerprint}`, request.input.bootstrapFingerprint);
|
|
243
|
+
const submitted = await options.browser.submit(opened.tabId, `WORKER_BIND ${request.input.bootstrapFingerprint}`, request.input.bootstrapFingerprint);
|
|
244
|
+
if (!(await options.browser.hasMessage(submitted.tabId, request.input.bootstrapFingerprint)))
|
|
245
|
+
throw new ExecutionBrowserError("UNKNOWN_SIDE_EFFECT", "CREATE_MESSAGE_REALITY_UNCONFIRMED");
|
|
244
246
|
const observed = await options.browser.observe(opened.tabId);
|
|
245
247
|
const identity = parseCarrierIdentity(observed.url);
|
|
246
248
|
if (identity.roleRef !== request.input.roleRef || !identity.workerRef)
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
type RecoveryObservation = {
|
|
2
|
+
url: string;
|
|
3
|
+
contentInstanceId: string;
|
|
4
|
+
pageState: "IDLE" | "BUSY" | "BLOCKED" | "UNKNOWN";
|
|
5
|
+
activityKind: string | null;
|
|
6
|
+
};
|
|
7
|
+
export declare function shouldTriggerObserverRecovery(previous: RecoveryObservation | undefined, current: RecoveryObservation): boolean;
|
|
8
|
+
export {};
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
export function shouldTriggerObserverRecovery(previous, current) {
|
|
2
|
+
if (current.pageState !== "IDLE")
|
|
3
|
+
return false;
|
|
4
|
+
if (!previous)
|
|
5
|
+
return true;
|
|
6
|
+
return (previous.pageState !== "IDLE" ||
|
|
7
|
+
previous.url !== current.url ||
|
|
8
|
+
previous.contentInstanceId !== current.contentInstanceId ||
|
|
9
|
+
previous.activityKind !== current.activityKind);
|
|
10
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
export function containsSubmittedFingerprint(candidates, fingerprint) {
|
|
2
|
+
if (!fingerprint)
|
|
3
|
+
return false;
|
|
4
|
+
for (const candidate of candidates) {
|
|
5
|
+
if (candidate.authorRole === "user" &&
|
|
6
|
+
candidate.textContent?.includes(fingerprint))
|
|
7
|
+
return true;
|
|
8
|
+
}
|
|
9
|
+
return false;
|
|
10
|
+
}
|
package/extension/background.ts
CHANGED
|
@@ -12,6 +12,7 @@ import {
|
|
|
12
12
|
type TaskObserverDiagnosticAssessment,
|
|
13
13
|
type TaskObserverDiagnosticFailure,
|
|
14
14
|
} from "../src/task-observer.js";
|
|
15
|
+
import { shouldTriggerObserverRecovery } from "../src/recovery-trigger.js";
|
|
15
16
|
|
|
16
17
|
type PageState = "IDLE" | "BUSY" | "BLOCKED" | "UNKNOWN";
|
|
17
18
|
type ActivityKind =
|
|
@@ -587,6 +588,7 @@ let observerRecoveryRetryCount = 0;
|
|
|
587
588
|
function runObserverRecovery() {
|
|
588
589
|
if (observerRecoveryInFlight) return observerRecoveryInFlight;
|
|
589
590
|
observerRecoveryInFlight = (async () => {
|
|
591
|
+
let recoveryNeedsRetry = false;
|
|
590
592
|
await collaborationCarrier.recoverPending(50).catch(() => undefined);
|
|
591
593
|
const signalBatch = await invokeObserverApplication(
|
|
592
594
|
"execution.listSignals",
|
|
@@ -634,18 +636,14 @@ function runObserverRecovery() {
|
|
|
634
636
|
});
|
|
635
637
|
} catch {
|
|
636
638
|
// Leave the durable signal unacknowledged for the next bounded recovery pass.
|
|
639
|
+
recoveryNeedsRetry = true;
|
|
637
640
|
}
|
|
638
641
|
}
|
|
639
642
|
}
|
|
640
643
|
const listed = await invokeTaskApplication("task.list", {}).catch(
|
|
641
644
|
() => null,
|
|
642
645
|
);
|
|
643
|
-
if (listed === null
|
|
644
|
-
observerRecoveryRetryCount += 1;
|
|
645
|
-
setTimeout(() => void runObserverRecovery(), 2_000);
|
|
646
|
-
} else if (listed !== null) {
|
|
647
|
-
observerRecoveryRetryCount = 0;
|
|
648
|
-
}
|
|
646
|
+
if (listed === null) recoveryNeedsRetry = true;
|
|
649
647
|
if (isRecord(listed) && Array.isArray(listed.tasks)) {
|
|
650
648
|
for (const candidate of listed.tasks.slice(0, 100)) {
|
|
651
649
|
if (!isRecord(candidate) || typeof candidate.taskId !== "string")
|
|
@@ -663,10 +661,22 @@ function runObserverRecovery() {
|
|
|
663
661
|
// missing roles are re-provisioned by the Host/Execution path.
|
|
664
662
|
await invokeTaskApplication("task.ensureWorkers", {
|
|
665
663
|
taskId: candidate.taskId,
|
|
666
|
-
}).catch(() =>
|
|
667
|
-
|
|
664
|
+
}).catch(() => {
|
|
665
|
+
recoveryNeedsRetry = true;
|
|
666
|
+
});
|
|
667
|
+
await taskObserver.drive(candidate.taskId).catch(() => {
|
|
668
|
+
recoveryNeedsRetry = true;
|
|
669
|
+
});
|
|
668
670
|
}
|
|
669
671
|
}
|
|
672
|
+
// A bounded retry continues the same stable Execution identities. Execution
|
|
673
|
+
// remains the no-blind-replay authority for APPLIED/NOT_APPLIED/UNKNOWN.
|
|
674
|
+
if (recoveryNeedsRetry && observerRecoveryRetryCount < 6) {
|
|
675
|
+
observerRecoveryRetryCount += 1;
|
|
676
|
+
setTimeout(() => void runObserverRecovery(), 2_000);
|
|
677
|
+
} else if (!recoveryNeedsRetry) {
|
|
678
|
+
observerRecoveryRetryCount = 0;
|
|
679
|
+
}
|
|
670
680
|
const previousSystemState = await loadSystemObserverState().catch(
|
|
671
681
|
() => null,
|
|
672
682
|
);
|
|
@@ -724,6 +734,27 @@ async function contentCommand(
|
|
|
724
734
|
return response.value;
|
|
725
735
|
}
|
|
726
736
|
|
|
737
|
+
async function waitForSubmittedMessage(
|
|
738
|
+
tabId: number,
|
|
739
|
+
fingerprint: string,
|
|
740
|
+
): Promise<ContentObservation> {
|
|
741
|
+
for (let attempt = 0; attempt < 60; attempt += 1) {
|
|
742
|
+
try {
|
|
743
|
+
const value = await contentCommand(tabId, {
|
|
744
|
+
operation: "verify",
|
|
745
|
+
fingerprint,
|
|
746
|
+
});
|
|
747
|
+
if (isRecord(value) && value.verified === true)
|
|
748
|
+
return observationFor(tabId);
|
|
749
|
+
} catch {
|
|
750
|
+
// Navigation can replace the content instance after submit. The next
|
|
751
|
+
// bounded observation/verification pass uses the newly published session.
|
|
752
|
+
}
|
|
753
|
+
await sleep(250);
|
|
754
|
+
}
|
|
755
|
+
throw new Error("MESSAGE_SUBMIT_REALITY_UNCONFIRMED");
|
|
756
|
+
}
|
|
757
|
+
|
|
727
758
|
function numeric(value: unknown, name: string): number {
|
|
728
759
|
if (!Number.isInteger(value)) throw new Error(`${name}_INVALID`);
|
|
729
760
|
return value as number;
|
|
@@ -757,11 +788,12 @@ async function executeCommand(command: BridgeCommand): Promise<unknown> {
|
|
|
757
788
|
return contentCommand(tabId, { operation: "observe" });
|
|
758
789
|
if (command.type === "SUBMIT") {
|
|
759
790
|
const before = observationFor(tabId);
|
|
791
|
+
const fingerprint = text(command.fingerprint, "FINGERPRINT");
|
|
760
792
|
try {
|
|
761
793
|
await contentCommand(tabId, {
|
|
762
794
|
operation: "submit",
|
|
763
795
|
value: text(command.text, "TEXT"),
|
|
764
|
-
fingerprint
|
|
796
|
+
fingerprint,
|
|
765
797
|
});
|
|
766
798
|
} catch (error) {
|
|
767
799
|
const replacement = await waitForObservation(
|
|
@@ -770,7 +802,7 @@ async function executeCommand(command: BridgeCommand): Promise<unknown> {
|
|
|
770
802
|
).catch(() => null);
|
|
771
803
|
if (!replacement) throw error;
|
|
772
804
|
}
|
|
773
|
-
return
|
|
805
|
+
return waitForSubmittedMessage(tabId, fingerprint);
|
|
774
806
|
}
|
|
775
807
|
if (command.type === "VERIFY")
|
|
776
808
|
return contentCommand(tabId, {
|
|
@@ -1187,6 +1219,7 @@ chrome.runtime.onMessage.addListener((message, sender, sendResponse) => {
|
|
|
1187
1219
|
sender.tab?.id !== undefined &&
|
|
1188
1220
|
sender.tab.windowId !== undefined
|
|
1189
1221
|
) {
|
|
1222
|
+
const previous = sessions.get(sender.tab.id);
|
|
1190
1223
|
const observed: ContentObservation = {
|
|
1191
1224
|
...message.observation,
|
|
1192
1225
|
tabId: sender.tab.id,
|
|
@@ -1194,7 +1227,8 @@ chrome.runtime.onMessage.addListener((message, sender, sendResponse) => {
|
|
|
1194
1227
|
};
|
|
1195
1228
|
sessions.set(sender.tab.id, observed);
|
|
1196
1229
|
void persistSnapshot();
|
|
1197
|
-
if (observed
|
|
1230
|
+
if (shouldTriggerObserverRecovery(previous, observed))
|
|
1231
|
+
void runObserverRecovery();
|
|
1198
1232
|
sendResponse({ accepted: true, extensionInstanceId });
|
|
1199
1233
|
return;
|
|
1200
1234
|
}
|
package/extension/content.ts
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { containsSubmittedFingerprint } from "../src/submitted-message.js";
|
|
2
|
+
|
|
1
3
|
type PageState = "IDLE" | "BUSY" | "BLOCKED" | "UNKNOWN";
|
|
2
4
|
type ContentCommand = {
|
|
3
5
|
type: "PROFLOW_PAGE_COMMAND";
|
|
@@ -61,7 +63,15 @@ function safeElement(selector: string | undefined): HTMLElement {
|
|
|
61
63
|
}
|
|
62
64
|
|
|
63
65
|
function hasFingerprint(fingerprint: string | undefined): boolean {
|
|
64
|
-
return
|
|
66
|
+
return containsSubmittedFingerprint(
|
|
67
|
+
[...document.querySelectorAll('[data-message-author-role="user"]')].map(
|
|
68
|
+
(element) => ({
|
|
69
|
+
authorRole: element.getAttribute("data-message-author-role"),
|
|
70
|
+
textContent: element.textContent,
|
|
71
|
+
}),
|
|
72
|
+
),
|
|
73
|
+
fingerprint,
|
|
74
|
+
);
|
|
65
75
|
}
|
|
66
76
|
|
|
67
77
|
chrome.runtime.onMessage.addListener((command, _sender, sendResponse) => {
|
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.27",
|
|
4
4
|
"description": "Execution-owned MV3 Browser executor, evidence provider and browser application surface.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"publishConfig": {
|
|
@@ -27,12 +27,12 @@
|
|
|
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
|
-
"@tomflow/proflow-
|
|
35
|
-
"@tomflow/proflow-
|
|
34
|
+
"@tomflow/proflow-execution-runtime": "^0.1.15",
|
|
35
|
+
"@tomflow/proflow-deployment-conformance": "^0.1.13"
|
|
36
36
|
},
|
|
37
37
|
"keywords": [
|
|
38
38
|
"proflow",
|
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.27",
|
|
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,25 +0,0 @@
|
|
|
1
|
-
# @tomflow/proflow-execution-browser-extension
|
|
2
|
-
|
|
3
|
-
## 0.1.25
|
|
4
|
-
|
|
5
|
-
### Patch Changes
|
|
6
|
-
|
|
7
|
-
- Preserve irreversible Custom GPT role authority and revalidate existing roles without duplicate creation
|
|
8
|
-
|
|
9
|
-
## 0.1.24
|
|
10
|
-
|
|
11
|
-
### Patch Changes
|
|
12
|
-
|
|
13
|
-
- Cover Chrome's observed delayed Secure Preferences flush while waiting for unpacked-extension registration to become enabled after pairing.
|
|
14
|
-
|
|
15
|
-
## 0.1.23
|
|
16
|
-
|
|
17
|
-
### Patch Changes
|
|
18
|
-
|
|
19
|
-
- Wait for Chrome unpacked-extension registration to become observably enabled after heartbeat pairing before Browser setup reports success.
|
|
20
|
-
|
|
21
|
-
## 0.1.22
|
|
22
|
-
|
|
23
|
-
### Patch Changes
|
|
24
|
-
|
|
25
|
-
- Make Browser Extension static materialization version-idempotent, freeze real-user install/remove acceptance paths, and remove unsupported Reload/Disable-Enable test scenarios.
|