@tomflow/proflow-execution-browser-extension 0.1.40 → 0.1.42
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 +12 -0
- 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 +59 -18
- package/dist/src/bridge.js +16 -1
- package/dist/src/task-observer.d.ts +2 -0
- package/dist/src/task-observer.js +20 -3
- package/extension/background.ts +65 -28
- package/manifest.json +1 -1
- package/package.json +4 -4
- package/proflow.module.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,17 @@
|
|
|
1
1
|
# @tomflow/proflow-execution-browser-extension
|
|
2
2
|
|
|
3
|
+
## 0.1.42
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- Close Real-3 node generation identity fencing across Platform Host admission, durable Execution idempotency, and Observer/Approval resume provenance.
|
|
8
|
+
|
|
9
|
+
## 0.1.41
|
|
10
|
+
|
|
11
|
+
### Patch Changes
|
|
12
|
+
|
|
13
|
+
- Resume the existing Task Observer after successful Tasks web mutations so READY nodes receive their normal NODE_READY or REOPEN wake without manual recovery.
|
|
14
|
+
|
|
3
15
|
## 0.1.40
|
|
4
16
|
|
|
5
17
|
### Patch Changes
|
|
@@ -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.42";
|
|
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.42";
|
|
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.42";
|
|
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.42";
|
|
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.42";
|
|
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.42";
|
|
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.42";
|
|
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.42";
|
|
184
184
|
} | {
|
|
185
185
|
contract: "deployment.result.v1";
|
|
186
186
|
moduleRef: "execution-browser-extension";
|
|
187
|
-
moduleVersion: "0.1.
|
|
187
|
+
moduleVersion: "0.1.42";
|
|
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.42";
|
|
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.42";
|
|
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.42",
|
|
7
7
|
kind: "browser-extension",
|
|
8
8
|
templateVersion: "1.0.0",
|
|
9
9
|
platformCompatibility: ">=1.0.0 <2.0.0",
|
|
@@ -14090,6 +14090,8 @@ var NODE_READY_TRIGGER = "NODE_READY";
|
|
|
14090
14090
|
var REOPEN_TRIGGER = "REOPEN";
|
|
14091
14091
|
function createTaskObserver(options) {
|
|
14092
14092
|
const advance = async (taskId, resumeSignal, anomalySignal) => {
|
|
14093
|
+
if (resumeSignal && (typeof resumeSignal.nodeId !== "string" || resumeSignal.nodeId.length === 0 || !Number.isInteger(resumeSignal.runNo) || resumeSignal.runNo <= 0))
|
|
14094
|
+
return { kind: "NOOP", taskId, reason: "RESUME_GENERATION_REQUIRED" };
|
|
14093
14095
|
const projection = await options.owner.getTaskDriveProjection(taskId);
|
|
14094
14096
|
if (projection.terminal || projection.currentNode === null)
|
|
14095
14097
|
return { kind: "STOP_DRIVING", taskId, reason: "TERMINAL" };
|
|
@@ -14119,9 +14121,11 @@ function createTaskObserver(options) {
|
|
|
14119
14121
|
};
|
|
14120
14122
|
}
|
|
14121
14123
|
const binding = projection.roleBinding;
|
|
14122
|
-
if (!
|
|
14124
|
+
if (!binding?.workerRef || !binding.conversationLocator || binding.agentPackageRef !== node.requiredAgentPackageRef)
|
|
14123
14125
|
return { kind: "NOOP", taskId, reason: "BINDING_NOT_READY" };
|
|
14124
14126
|
if (node.status === "READY") {
|
|
14127
|
+
if (!projection.canDrive)
|
|
14128
|
+
return { kind: "NOOP", taskId, reason: "BINDING_NOT_READY" };
|
|
14125
14129
|
return {
|
|
14126
14130
|
kind: "WAKE",
|
|
14127
14131
|
taskId,
|
|
@@ -14134,6 +14138,14 @@ function createTaskObserver(options) {
|
|
|
14134
14138
|
};
|
|
14135
14139
|
}
|
|
14136
14140
|
if (resumeSignal) {
|
|
14141
|
+
if (projection.taskStatus !== "ACTIVE" || node.status !== "IN_PROGRESS")
|
|
14142
|
+
return { kind: "NOOP", taskId, reason: "BINDING_NOT_READY" };
|
|
14143
|
+
if (resumeSignal.nodeId !== node.nodeId || resumeSignal.runNo !== node.runNo)
|
|
14144
|
+
return {
|
|
14145
|
+
kind: "NOOP",
|
|
14146
|
+
taskId,
|
|
14147
|
+
reason: "RESUME_GENERATION_MISMATCH"
|
|
14148
|
+
};
|
|
14137
14149
|
if (resumeSignal.targetWorkerRef !== binding.workerRef)
|
|
14138
14150
|
return {
|
|
14139
14151
|
kind: "NOOP",
|
|
@@ -14445,6 +14457,20 @@ var taskObserver = createTaskObserver({
|
|
|
14445
14457
|
}
|
|
14446
14458
|
}
|
|
14447
14459
|
});
|
|
14460
|
+
async function resumeAfterApprovalDecision(approvalRef) {
|
|
14461
|
+
const context = await invokeObserverApplication("approval.executionContext", {
|
|
14462
|
+
approvalRef
|
|
14463
|
+
});
|
|
14464
|
+
if (!isRecord(context) || typeof context.executionRef !== "string" || typeof context.taskId !== "string" || typeof context.nodeId !== "string" || !Number.isInteger(context.runNo) || Number(context.runNo) <= 0 || typeof context.roleRef !== "string" || typeof context.workerRef !== "string")
|
|
14465
|
+
throw new Error("APPROVAL_EXECUTION_GENERATION_REQUIRED");
|
|
14466
|
+
return taskObserver.drive(context.taskId, {
|
|
14467
|
+
trigger: "RECOVERY_RESUME",
|
|
14468
|
+
ref: approvalRef,
|
|
14469
|
+
targetWorkerRef: context.workerRef,
|
|
14470
|
+
nodeId: context.nodeId,
|
|
14471
|
+
runNo: Number(context.runNo)
|
|
14472
|
+
});
|
|
14473
|
+
}
|
|
14448
14474
|
var collaborationCarrier = createCollaborationCarrierApplication({
|
|
14449
14475
|
task: {
|
|
14450
14476
|
async getWorkerBinding(taskId, roleRef) {
|
|
@@ -14558,18 +14584,31 @@ function runObserverRecovery() {
|
|
|
14558
14584
|
(denial) => denial.taskId === candidate.taskId && denial.workerRef === candidate.workerRef
|
|
14559
14585
|
))
|
|
14560
14586
|
continue;
|
|
14561
|
-
|
|
14562
|
-
|
|
14563
|
-
|
|
14564
|
-
|
|
14565
|
-
|
|
14566
|
-
|
|
14567
|
-
|
|
14568
|
-
facts: {
|
|
14569
|
-
executionRef: candidate.executionRef,
|
|
14570
|
-
summary: `Execution ${candidate.executionRef} recovery remains UNKNOWN`
|
|
14587
|
+
let decision;
|
|
14588
|
+
if (candidate.kind === "RECOVERY_RESUME") {
|
|
14589
|
+
if (typeof candidate.nodeId !== "string" || typeof candidate.runNo !== "number") {
|
|
14590
|
+
await invokeObserverApplication("execution.ackSignal", {
|
|
14591
|
+
signalRef: candidate.signalRef
|
|
14592
|
+
});
|
|
14593
|
+
continue;
|
|
14571
14594
|
}
|
|
14572
|
-
|
|
14595
|
+
decision = await taskObserver.drive(candidate.taskId, {
|
|
14596
|
+
trigger: "RECOVERY_RESUME",
|
|
14597
|
+
ref: candidate.executionRef,
|
|
14598
|
+
targetWorkerRef: candidate.workerRef,
|
|
14599
|
+
nodeId: candidate.nodeId,
|
|
14600
|
+
runNo: candidate.runNo
|
|
14601
|
+
});
|
|
14602
|
+
} else if (candidate.kind === "UNKNOWN_REALITY")
|
|
14603
|
+
decision = await taskObserver.drive(candidate.taskId, void 0, {
|
|
14604
|
+
kind: "UNKNOWN_REALITY",
|
|
14605
|
+
ref: candidate.executionRef,
|
|
14606
|
+
facts: {
|
|
14607
|
+
executionRef: candidate.executionRef,
|
|
14608
|
+
summary: `Execution ${candidate.executionRef} recovery remains UNKNOWN`
|
|
14609
|
+
}
|
|
14610
|
+
});
|
|
14611
|
+
else decision = null;
|
|
14573
14612
|
if (!decision) continue;
|
|
14574
14613
|
if (decision.kind === "NOOP" && (decision.reason === "BINDING_NOT_READY" || decision.reason === "RESUME_TARGET_NOT_CURRENT_WORKER" || decision.reason === "DIAGNOSTIC_UNAVAILABLE" || decision.reason.startsWith("DIAGNOSTIC_DEFERRED:")))
|
|
14575
14614
|
continue;
|
|
@@ -14999,6 +15038,10 @@ function text(value, name) {
|
|
|
14999
15038
|
return value;
|
|
15000
15039
|
}
|
|
15001
15040
|
async function executeCommand(command) {
|
|
15041
|
+
if (command.type === "TASK_OBSERVER_RECOVER") {
|
|
15042
|
+
void runObserverRecovery();
|
|
15043
|
+
return { scheduled: true };
|
|
15044
|
+
}
|
|
15002
15045
|
if (command.type === "CARRIER_ATTENTION_ACTION") {
|
|
15003
15046
|
if (command.action !== "allowOnce" && command.action !== "deny")
|
|
15004
15047
|
throw new Error("ATTENTION_ACTION_INVALID");
|
|
@@ -15458,12 +15501,10 @@ chrome.runtime.onMessage.addListener((message, sender, sendResponse) => {
|
|
|
15458
15501
|
}
|
|
15459
15502
|
void invokeApprovalApplication(message.operation, message.input).then(
|
|
15460
15503
|
(value) => {
|
|
15461
|
-
if ((message.operation === "approval.allow" || message.operation === "approval.deny" || message.operation === "approval.revoke") && isRecord(value) && typeof value.approvalRef === "string"
|
|
15462
|
-
void
|
|
15463
|
-
|
|
15464
|
-
|
|
15465
|
-
targetWorkerRef: value.workerRef
|
|
15466
|
-
}).catch(() => void 0);
|
|
15504
|
+
if ((message.operation === "approval.allow" || message.operation === "approval.deny" || message.operation === "approval.revoke") && isRecord(value) && typeof value.approvalRef === "string")
|
|
15505
|
+
void resumeAfterApprovalDecision(value.approvalRef).catch(
|
|
15506
|
+
() => void 0
|
|
15507
|
+
);
|
|
15467
15508
|
sendResponse({ ok: true, value });
|
|
15468
15509
|
},
|
|
15469
15510
|
(error46) => sendResponse({
|
package/dist/src/bridge.js
CHANGED
|
@@ -1,6 +1,12 @@
|
|
|
1
1
|
import { randomUUID, timingSafeEqual } from "node:crypto";
|
|
2
2
|
import { createServer, } from "node:http";
|
|
3
3
|
import { parseCarrierAttentionViews, } from "./carrier-attention-view.js";
|
|
4
|
+
const taskWebObserverRecoveryOperations = new Set([
|
|
5
|
+
"task.create",
|
|
6
|
+
"task.start",
|
|
7
|
+
"task.ensureWorkers",
|
|
8
|
+
"node.reopen",
|
|
9
|
+
]);
|
|
4
10
|
export class BrowserRealityBridgeError extends Error {
|
|
5
11
|
code;
|
|
6
12
|
constructor(code, message) {
|
|
@@ -257,9 +263,18 @@ export async function createBrowserRealityBridgeServer(options) {
|
|
|
257
263
|
typeof body.operation !== "string" ||
|
|
258
264
|
!isRecord(body.input))
|
|
259
265
|
throw new BrowserRealityBridgeError("BRIDGE_INPUT_INVALID", "task web request is invalid");
|
|
260
|
-
const
|
|
266
|
+
const taskRequest = url.pathname.endsWith("/task");
|
|
267
|
+
const value = taskRequest
|
|
261
268
|
? await options.taskWeb.invokeTask(body.operation, body.input)
|
|
262
269
|
: await options.taskWeb.invokeApproval(body.operation, body.input);
|
|
270
|
+
if (taskRequest &&
|
|
271
|
+
taskWebObserverRecoveryOperations.has(body.operation) &&
|
|
272
|
+
commandConsumerReady()) {
|
|
273
|
+
// The Task mutation is already durable and must not be coupled to
|
|
274
|
+
// transient Browser delivery. Notify the Extension asynchronously so
|
|
275
|
+
// its existing Task Observer can derive the next NODE_READY/REOPEN wake.
|
|
276
|
+
void requestCommand({ type: "TASK_OBSERVER_RECOVER" }).catch(() => undefined);
|
|
277
|
+
}
|
|
263
278
|
send(response, 200, { ok: true, value });
|
|
264
279
|
return;
|
|
265
280
|
}
|
|
@@ -32,6 +32,8 @@ export type TaskObserverResumeSignal = {
|
|
|
32
32
|
trigger: "EXECUTION_RESULT_READY" | "PEER_REPLY_READY" | "RECOVERY_RESUME";
|
|
33
33
|
ref: string;
|
|
34
34
|
targetWorkerRef: string;
|
|
35
|
+
nodeId: string;
|
|
36
|
+
runNo: number;
|
|
35
37
|
};
|
|
36
38
|
export type TaskObserverAnomalySignal = {
|
|
37
39
|
kind: "FACT_CONFLICT" | "UNKNOWN_REALITY" | "STALLED" | "RECOVERY_FAILED";
|
|
@@ -11,6 +11,12 @@ const NODE_READY_TRIGGER = "NODE_READY";
|
|
|
11
11
|
const REOPEN_TRIGGER = "REOPEN";
|
|
12
12
|
export function createTaskObserver(options) {
|
|
13
13
|
const advance = async (taskId, resumeSignal, anomalySignal) => {
|
|
14
|
+
if (resumeSignal &&
|
|
15
|
+
(typeof resumeSignal.nodeId !== "string" ||
|
|
16
|
+
resumeSignal.nodeId.length === 0 ||
|
|
17
|
+
!Number.isInteger(resumeSignal.runNo) ||
|
|
18
|
+
resumeSignal.runNo <= 0))
|
|
19
|
+
return { kind: "NOOP", taskId, reason: "RESUME_GENERATION_REQUIRED" };
|
|
14
20
|
const projection = await options.owner.getTaskDriveProjection(taskId);
|
|
15
21
|
// Terminal Tasks stop driving; history and bindings are retained.
|
|
16
22
|
if (projection.terminal || projection.currentNode === null)
|
|
@@ -43,11 +49,13 @@ export function createTaskObserver(options) {
|
|
|
43
49
|
};
|
|
44
50
|
}
|
|
45
51
|
const binding = projection.roleBinding;
|
|
46
|
-
if (!
|
|
47
|
-
!binding
|
|
48
|
-
|
|
52
|
+
if (!binding?.workerRef ||
|
|
53
|
+
!binding.conversationLocator ||
|
|
54
|
+
binding.agentPackageRef !== node.requiredAgentPackageRef)
|
|
49
55
|
return { kind: "NOOP", taskId, reason: "BINDING_NOT_READY" };
|
|
50
56
|
if (node.status === "READY") {
|
|
57
|
+
if (!projection.canDrive)
|
|
58
|
+
return { kind: "NOOP", taskId, reason: "BINDING_NOT_READY" };
|
|
51
59
|
// WAKE the correct Worker with a minimal trigger; the Worker then
|
|
52
60
|
// performs formal work acceptance through the Task owner. A reopened
|
|
53
61
|
// run reuses the same TaskRoleBinding/Conversation but keeps the reason
|
|
@@ -64,6 +72,15 @@ export function createTaskObserver(options) {
|
|
|
64
72
|
};
|
|
65
73
|
}
|
|
66
74
|
if (resumeSignal) {
|
|
75
|
+
if (projection.taskStatus !== "ACTIVE" || node.status !== "IN_PROGRESS")
|
|
76
|
+
return { kind: "NOOP", taskId, reason: "BINDING_NOT_READY" };
|
|
77
|
+
if (resumeSignal.nodeId !== node.nodeId ||
|
|
78
|
+
resumeSignal.runNo !== node.runNo)
|
|
79
|
+
return {
|
|
80
|
+
kind: "NOOP",
|
|
81
|
+
taskId,
|
|
82
|
+
reason: "RESUME_GENERATION_MISMATCH",
|
|
83
|
+
};
|
|
67
84
|
if (resumeSignal.targetWorkerRef !== binding.workerRef)
|
|
68
85
|
return {
|
|
69
86
|
kind: "NOOP",
|
package/extension/background.ts
CHANGED
|
@@ -76,7 +76,8 @@ type BridgeCommand = {
|
|
|
76
76
|
| "VERIFY"
|
|
77
77
|
| "SCREENSHOT"
|
|
78
78
|
| "PERFORM"
|
|
79
|
-
| "CARRIER_ATTENTION_ACTION"
|
|
79
|
+
| "CARRIER_ATTENTION_ACTION"
|
|
80
|
+
| "TASK_OBSERVER_RECOVER";
|
|
80
81
|
tabId?: number;
|
|
81
82
|
url?: string;
|
|
82
83
|
text?: string;
|
|
@@ -539,6 +540,30 @@ const taskObserver = createTaskObserver({
|
|
|
539
540
|
},
|
|
540
541
|
});
|
|
541
542
|
|
|
543
|
+
async function resumeAfterApprovalDecision(approvalRef: string) {
|
|
544
|
+
const context = await invokeObserverApplication("approval.executionContext", {
|
|
545
|
+
approvalRef,
|
|
546
|
+
});
|
|
547
|
+
if (
|
|
548
|
+
!isRecord(context) ||
|
|
549
|
+
typeof context.executionRef !== "string" ||
|
|
550
|
+
typeof context.taskId !== "string" ||
|
|
551
|
+
typeof context.nodeId !== "string" ||
|
|
552
|
+
!Number.isInteger(context.runNo) ||
|
|
553
|
+
Number(context.runNo) <= 0 ||
|
|
554
|
+
typeof context.roleRef !== "string" ||
|
|
555
|
+
typeof context.workerRef !== "string"
|
|
556
|
+
)
|
|
557
|
+
throw new Error("APPROVAL_EXECUTION_GENERATION_REQUIRED");
|
|
558
|
+
return taskObserver.drive(context.taskId, {
|
|
559
|
+
trigger: "RECOVERY_RESUME",
|
|
560
|
+
ref: approvalRef,
|
|
561
|
+
targetWorkerRef: context.workerRef,
|
|
562
|
+
nodeId: context.nodeId,
|
|
563
|
+
runNo: Number(context.runNo),
|
|
564
|
+
});
|
|
565
|
+
}
|
|
566
|
+
|
|
542
567
|
const collaborationCarrier = createCollaborationCarrierApplication({
|
|
543
568
|
task: {
|
|
544
569
|
async getWorkerBinding(taskId, roleRef) {
|
|
@@ -709,23 +734,37 @@ function runObserverRecovery() {
|
|
|
709
734
|
)
|
|
710
735
|
)
|
|
711
736
|
continue;
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
737
|
+
let decision;
|
|
738
|
+
if (candidate.kind === "RECOVERY_RESUME") {
|
|
739
|
+
if (
|
|
740
|
+
typeof candidate.nodeId !== "string" ||
|
|
741
|
+
typeof candidate.runNo !== "number"
|
|
742
|
+
) {
|
|
743
|
+
// Missing generation is a permanent malformed resume intent, not a
|
|
744
|
+
// transient binding condition. Dispose it without ever waking a Worker
|
|
745
|
+
// so an old signal cannot occupy the bounded pending queue forever.
|
|
746
|
+
await invokeObserverApplication("execution.ackSignal", {
|
|
747
|
+
signalRef: candidate.signalRef,
|
|
748
|
+
});
|
|
749
|
+
continue;
|
|
750
|
+
}
|
|
751
|
+
decision = await taskObserver.drive(candidate.taskId, {
|
|
752
|
+
trigger: "RECOVERY_RESUME",
|
|
753
|
+
ref: candidate.executionRef,
|
|
754
|
+
targetWorkerRef: candidate.workerRef,
|
|
755
|
+
nodeId: candidate.nodeId,
|
|
756
|
+
runNo: candidate.runNo,
|
|
757
|
+
});
|
|
758
|
+
} else if (candidate.kind === "UNKNOWN_REALITY")
|
|
759
|
+
decision = await taskObserver.drive(candidate.taskId, undefined, {
|
|
760
|
+
kind: "UNKNOWN_REALITY",
|
|
761
|
+
ref: candidate.executionRef,
|
|
762
|
+
facts: {
|
|
763
|
+
executionRef: candidate.executionRef,
|
|
764
|
+
summary: `Execution ${candidate.executionRef} recovery remains UNKNOWN`,
|
|
765
|
+
},
|
|
766
|
+
});
|
|
767
|
+
else decision = null;
|
|
729
768
|
if (!decision) continue;
|
|
730
769
|
if (
|
|
731
770
|
decision.kind === "NOOP" &&
|
|
@@ -1312,6 +1351,10 @@ function text(value: unknown, name: string): string {
|
|
|
1312
1351
|
}
|
|
1313
1352
|
|
|
1314
1353
|
async function executeCommand(command: BridgeCommand): Promise<unknown> {
|
|
1354
|
+
if (command.type === "TASK_OBSERVER_RECOVER") {
|
|
1355
|
+
void runObserverRecovery();
|
|
1356
|
+
return { scheduled: true };
|
|
1357
|
+
}
|
|
1315
1358
|
if (command.type === "CARRIER_ATTENTION_ACTION") {
|
|
1316
1359
|
if (command.action !== "allowOnce" && command.action !== "deny")
|
|
1317
1360
|
throw new Error("ATTENTION_ACTION_INVALID");
|
|
@@ -1869,17 +1912,11 @@ chrome.runtime.onMessage.addListener((message, sender, sendResponse) => {
|
|
|
1869
1912
|
message.operation === "approval.deny" ||
|
|
1870
1913
|
message.operation === "approval.revoke") &&
|
|
1871
1914
|
isRecord(value) &&
|
|
1872
|
-
typeof value.approvalRef === "string"
|
|
1873
|
-
typeof value.taskId === "string" &&
|
|
1874
|
-
typeof value.workerRef === "string"
|
|
1915
|
+
typeof value.approvalRef === "string"
|
|
1875
1916
|
)
|
|
1876
|
-
void
|
|
1877
|
-
|
|
1878
|
-
|
|
1879
|
-
ref: value.approvalRef,
|
|
1880
|
-
targetWorkerRef: value.workerRef,
|
|
1881
|
-
})
|
|
1882
|
-
.catch(() => undefined);
|
|
1917
|
+
void resumeAfterApprovalDecision(value.approvalRef).catch(
|
|
1918
|
+
() => undefined,
|
|
1919
|
+
);
|
|
1883
1920
|
sendResponse({ ok: true, value });
|
|
1884
1921
|
},
|
|
1885
1922
|
(error: unknown) =>
|
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.42",
|
|
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
34
|
"@tomflow/proflow-deployment-conformance": "^0.1.13",
|
|
35
|
-
"@tomflow/proflow-execution-runtime": "^0.1.
|
|
35
|
+
"@tomflow/proflow-execution-runtime": "^0.1.18"
|
|
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.42",
|
|
7
7
|
"kind": "browser-extension",
|
|
8
8
|
"templateVersion": "1.0.0",
|
|
9
9
|
"platformCompatibility": ">=1.0.0 <2.0.0",
|