codex-chatgpt-control 0.5.1-alpha.2 → 0.5.1-alpha.4
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 +42 -0
- package/README.md +43 -0
- package/contracts/v1/fixtures/backend-capabilities.json +40 -1
- package/contracts/v1/fixtures/backend-compatibility.json +21 -0
- package/contracts/v1/fixtures/backend-version.json +6 -1
- package/contracts/v1/fixtures/download-blocked-by-browser.json +22 -0
- package/contracts/v1/fixtures/download-receipt-failed.json +22 -0
- package/contracts/v1/fixtures/download-receipt-timeout.json +22 -0
- package/contracts/v1/fixtures/journal-rpc-indeterminate.json +32 -0
- package/contracts/v1/fixtures/journal-rpc-unsupported-platform.json +32 -0
- package/contracts/v1/fixtures/journal-runtime-unavailable.json +32 -0
- package/contracts/v1/fixtures/operation-action-prepared-event.json +42 -0
- package/contracts/v1/fixtures/operation-action.json +13 -0
- package/contracts/v1/fixtures/operation-artifact-receipt.json +14 -0
- package/contracts/v1/fixtures/operation-artifact-transfer-intent-event.json +24 -0
- package/contracts/v1/fixtures/operation-artifact-transfer-receipt-event.json +26 -0
- package/contracts/v1/fixtures/operation-artifact-transfer-state.json +178 -0
- package/contracts/v1/fixtures/operation-blocker.json +10 -0
- package/contracts/v1/fixtures/operation-collect-request.json +17 -0
- package/contracts/v1/fixtures/operation-collect-result.json +42 -0
- package/contracts/v1/fixtures/operation-control-receipt.json +13 -0
- package/contracts/v1/fixtures/operation-control-request.json +18 -0
- package/contracts/v1/fixtures/operation-control-result.json +31 -0
- package/contracts/v1/fixtures/operation-event.json +18 -0
- package/contracts/v1/fixtures/operation-handle.json +10 -0
- package/contracts/v1/fixtures/operation-inspect-request.json +13 -0
- package/contracts/v1/fixtures/operation-inspect-result.json +205 -0
- package/contracts/v1/fixtures/operation-ownership-baseline-event.json +34 -0
- package/contracts/v1/fixtures/operation-receipt.json +32 -0
- package/contracts/v1/fixtures/operation-recovery-decision.json +7 -0
- package/contracts/v1/fixtures/operation-recovery-observation.json +12 -0
- package/contracts/v1/fixtures/operation-request.json +33 -0
- package/contracts/v1/fixtures/operation-state.json +144 -0
- package/contracts/v1/fixtures/operation-submission-witness-event.json +20 -0
- package/contracts/v1/fixtures/operation-submission-witness.json +11 -0
- package/contracts/v1/fixtures/operation-submit-result.json +16 -0
- package/contracts/v1/fixtures/operation-target-established-event.json +21 -0
- package/contracts/v1/manifest.json +185 -1
- package/contracts/v1/parity-suite.json +106 -8
- package/contracts/v1/schemas/backend-compatibility.schema.json +65 -0
- package/contracts/v1/schemas/backend-request.schema.json +8 -2
- package/contracts/v1/schemas/capabilities.schema.json +81 -1
- package/contracts/v1/schemas/manifest.schema.json +57 -0
- package/contracts/v1/schemas/operation-action.schema.json +155 -0
- package/contracts/v1/schemas/operation-artifact-receipt.schema.json +89 -0
- package/contracts/v1/schemas/operation-blocker.schema.json +70 -0
- package/contracts/v1/schemas/operation-collect-request.schema.json +46 -0
- package/contracts/v1/schemas/operation-collect-result.schema.json +74 -0
- package/contracts/v1/schemas/operation-control-receipt.schema.json +108 -0
- package/contracts/v1/schemas/operation-control-request.schema.json +111 -0
- package/contracts/v1/schemas/operation-control-result.schema.json +112 -0
- package/contracts/v1/schemas/operation-event.schema.json +756 -0
- package/contracts/v1/schemas/operation-handle.schema.json +55 -0
- package/contracts/v1/schemas/operation-inspect-request.schema.json +42 -0
- package/contracts/v1/schemas/operation-inspect-result.schema.json +1662 -0
- package/contracts/v1/schemas/operation-receipt.schema.json +153 -0
- package/contracts/v1/schemas/operation-recovery.schema.json +314 -0
- package/contracts/v1/schemas/operation-request.schema.json +158 -0
- package/contracts/v1/schemas/operation-state.schema.json +691 -0
- package/contracts/v1/schemas/operation-submission-witness.schema.json +48 -0
- package/contracts/v1/schemas/operation-submit-result.schema.json +94 -0
- package/contracts/v1/surface-drift-policy.json +50 -0
- package/contracts/v1/vectors/operation-request-digest-v1.json +43 -0
- package/dist/codex-chatgpt-control-backend.mjs +45882 -9361
- package/dist/codex-chatgpt-control-journal.mjs +5547 -0
- package/dist/codex-chatgpt-control-live-smoke.bundle.mjs +51677 -0
- package/dist/codex-chatgpt-control-release-canary.bundle.mjs +52104 -0
- package/dist/codex-chatgpt-control.bundle.mjs +48392 -10260
- package/dist/src/backend/client.d.ts +103 -2
- package/dist/src/backend/client.js +1436 -97
- package/dist/src/backend/compatibility.d.ts +12 -0
- package/dist/src/backend/compatibility.js +208 -0
- package/dist/src/backend/protocol.d.ts +84 -1
- package/dist/src/backend/protocol.js +31 -5
- package/dist/src/backend/runtime-identity.d.ts +10 -0
- package/dist/src/backend/runtime-identity.js +141 -0
- package/dist/src/backend/session.d.ts +10 -2
- package/dist/src/backend/session.js +478 -7
- package/dist/src/backend/stdio-server.d.ts +4 -1
- package/dist/src/backend/stdio-server.js +240 -28
- package/dist/src/browser/active-composer-file-input.d.ts +9 -0
- package/dist/src/browser/active-composer-file-input.js +33 -0
- package/dist/src/browser/attach.d.ts +4 -1
- package/dist/src/browser/attach.js +136 -28
- package/dist/src/browser/chatgpt-url.d.ts +2 -0
- package/dist/src/browser/chatgpt-url.js +9 -0
- package/dist/src/browser/downloads.d.ts +17 -1
- package/dist/src/browser/downloads.js +150 -28
- package/dist/src/browser/page-state.js +6 -0
- package/dist/src/client.d.ts +43 -0
- package/dist/src/client.js +1279 -59
- package/dist/src/commands/artifacts.js +6 -4
- package/dist/src/commands/chat-popover.d.ts +37 -0
- package/dist/src/commands/chat-popover.js +537 -0
- package/dist/src/commands/configuration.d.ts +5 -0
- package/dist/src/commands/configuration.js +134 -21
- package/dist/src/commands/context.js +10 -3
- package/dist/src/commands/doctor.d.ts +1 -1
- package/dist/src/commands/doctor.js +27 -4
- package/dist/src/commands/experience.d.ts +5 -0
- package/dist/src/commands/experience.js +104 -21
- package/dist/src/commands/files.js +14 -33
- package/dist/src/commands/modes.js +85 -21
- package/dist/src/commands/power-discovery.d.ts +130 -0
- package/dist/src/commands/power-discovery.js +669 -0
- package/dist/src/commands/project-sources.js +325 -31
- package/dist/src/commands/sequence.js +59 -32
- package/dist/src/commands/session.js +19 -6
- package/dist/src/commands/work.js +31 -0
- package/dist/src/dom/composer-text.d.ts +6 -0
- package/dist/src/dom/composer-text.js +85 -0
- package/dist/src/errors.d.ts +9 -0
- package/dist/src/errors.js +22 -0
- package/dist/src/index.d.ts +6 -0
- package/dist/src/index.js +9 -0
- package/dist/src/operations/artifact-output.d.ts +69 -0
- package/dist/src/operations/artifact-output.js +1748 -0
- package/dist/src/operations/artifact-stream.d.ts +19 -0
- package/dist/src/operations/artifact-stream.js +35 -0
- package/dist/src/operations/artifact-transfer.d.ts +149 -0
- package/dist/src/operations/artifact-transfer.js +1312 -0
- package/dist/src/operations/browser-adapter.d.ts +167 -0
- package/dist/src/operations/browser-adapter.js +2103 -0
- package/dist/src/operations/browser-observation.d.ts +110 -0
- package/dist/src/operations/browser-observation.js +1256 -0
- package/dist/src/operations/browser-target.d.ts +105 -0
- package/dist/src/operations/browser-target.js +531 -0
- package/dist/src/operations/canonical.d.ts +4 -0
- package/dist/src/operations/canonical.js +412 -0
- package/dist/src/operations/chatgpt-runtime.d.ts +72 -0
- package/dist/src/operations/chatgpt-runtime.js +1232 -0
- package/dist/src/operations/client.d.ts +138 -0
- package/dist/src/operations/client.js +1145 -0
- package/dist/src/operations/collector.d.ts +195 -0
- package/dist/src/operations/collector.js +1039 -0
- package/dist/src/operations/configuration-routing.d.ts +4 -0
- package/dist/src/operations/configuration-routing.js +14 -0
- package/dist/src/operations/control.d.ts +372 -0
- package/dist/src/operations/control.js +1498 -0
- package/dist/src/operations/file-identity.d.ts +33 -0
- package/dist/src/operations/file-identity.js +153 -0
- package/dist/src/operations/handle.d.ts +19 -0
- package/dist/src/operations/handle.js +727 -0
- package/dist/src/operations/index.d.ts +25 -0
- package/dist/src/operations/index.js +25 -0
- package/dist/src/operations/journal-authority.d.ts +12 -0
- package/dist/src/operations/journal-authority.js +1 -0
- package/dist/src/operations/journal-rpc-client.d.ts +12 -0
- package/dist/src/operations/journal-rpc-client.js +225 -0
- package/dist/src/operations/journal-rpc-protocol.d.ts +32 -0
- package/dist/src/operations/journal-rpc-protocol.js +214 -0
- package/dist/src/operations/journal-rpc-server.d.ts +15 -0
- package/dist/src/operations/journal-rpc-server.js +272 -0
- package/dist/src/operations/journal.d.ts +143 -0
- package/dist/src/operations/journal.js +1957 -0
- package/dist/src/operations/production-attachments.d.ts +118 -0
- package/dist/src/operations/production-attachments.js +1035 -0
- package/dist/src/operations/production-chatgpt-artifacts.d.ts +74 -0
- package/dist/src/operations/production-chatgpt-artifacts.js +1146 -0
- package/dist/src/operations/production-chatgpt-attachments.d.ts +80 -0
- package/dist/src/operations/production-chatgpt-attachments.js +1639 -0
- package/dist/src/operations/production-configuration.d.ts +42 -0
- package/dist/src/operations/production-configuration.js +1544 -0
- package/dist/src/operations/production-primitives.d.ts +53 -0
- package/dist/src/operations/production-primitives.js +856 -0
- package/dist/src/operations/production-work-steer.d.ts +203 -0
- package/dist/src/operations/production-work-steer.js +1218 -0
- package/dist/src/operations/recovery.d.ts +80 -0
- package/dist/src/operations/recovery.js +174 -0
- package/dist/src/operations/runtime-adapter.d.ts +126 -0
- package/dist/src/operations/runtime-adapter.js +802 -0
- package/dist/src/operations/send-once.d.ts +224 -0
- package/dist/src/operations/send-once.js +1081 -0
- package/dist/src/operations/service.d.ts +286 -0
- package/dist/src/operations/service.js +2831 -0
- package/dist/src/operations/staging.d.ts +136 -0
- package/dist/src/operations/staging.js +630 -0
- package/dist/src/operations/state-machine.d.ts +29 -0
- package/dist/src/operations/state-machine.js +2047 -0
- package/dist/src/operations/submission.d.ts +423 -0
- package/dist/src/operations/submission.js +1676 -0
- package/dist/src/operations/transactional-chat-power.d.ts +17 -0
- package/dist/src/operations/transactional-chat-power.js +212 -0
- package/dist/src/operations/turn-ownership.d.ts +202 -0
- package/dist/src/operations/turn-ownership.js +700 -0
- package/dist/src/operations/types.d.ts +454 -0
- package/dist/src/operations/types.js +20 -0
- package/dist/src/operations/wire-requests.d.ts +21 -0
- package/dist/src/operations/wire-requests.js +396 -0
- package/dist/src/operations/wire-results.d.ts +97 -0
- package/dist/src/operations/wire-results.js +818 -0
- package/dist/src/runner/responses.d.ts +3 -1
- package/dist/src/runner/responses.js +19 -1
- package/dist/src/runner/result.js +227 -55
- package/dist/src/runner/types.d.ts +12 -0
- package/dist/src/runtime/command-routing.d.ts +149 -0
- package/dist/src/runtime/command-routing.js +431 -0
- package/dist/src/runtime/coordinated-browser.d.ts +24 -0
- package/dist/src/runtime/coordinated-browser.js +315 -0
- package/dist/src/runtime/coordinated-page.d.ts +41 -0
- package/dist/src/runtime/coordinated-page.js +651 -0
- package/dist/src/runtime/operation-context.d.ts +142 -0
- package/dist/src/runtime/operation-context.js +410 -0
- package/dist/src/runtime/runtime-session.d.ts +95 -0
- package/dist/src/runtime/runtime-session.js +314 -0
- package/dist/src/runtime/tab-coordinator.d.ts +200 -0
- package/dist/src/runtime/tab-coordinator.js +1200 -0
- package/dist/src/runtime/value-boundaries.d.ts +18 -0
- package/dist/src/runtime/value-boundaries.js +49 -0
- package/dist/src/safety/blockers.js +8 -1
- package/dist/src/safety/untrusted-output.js +2 -1
- package/dist/src/scripts/backend-server.js +4 -1
- package/dist/src/scripts/capture-surface-profile.js +7 -2
- package/dist/src/scripts/journal-server.d.ts +2 -0
- package/dist/src/scripts/journal-server.js +37 -0
- package/dist/src/scripts/live-smoke/harness.js +79 -7
- package/dist/src/scripts/live-smoke/scenarios.d.ts +42 -1
- package/dist/src/scripts/live-smoke/scenarios.js +147 -30
- package/dist/src/scripts/live-smoke/transactional.d.ts +17 -0
- package/dist/src/scripts/live-smoke/transactional.js +254 -0
- package/dist/src/scripts/live-smoke/types.d.ts +3 -0
- package/dist/src/scripts/release-canary-module.js +17 -4
- package/dist/src/types.d.ts +38 -1
- package/package.json +8 -3
- package/references/2026-08-16-transactional-operations.md +459 -0
- package/references/2026-09-06-journal-service.md +140 -0
- package/references/agents-runner.md +34 -0
- package/references/backend-protocol.md +176 -0
- package/references/python-parity.md +137 -0
- package/references/responses-adapter.md +19 -0
- package/references/streaming.md +6 -0
|
@@ -0,0 +1,431 @@
|
|
|
1
|
+
import { coordinateRuntimeEnv } from "./coordinated-browser.js";
|
|
2
|
+
/** The complete routing inventory is intentionally explicit and reviewable. */
|
|
3
|
+
export const COMMAND_ROUTING_INVENTORY = Object.freeze({
|
|
4
|
+
browserFree: Object.freeze([
|
|
5
|
+
"backend.version",
|
|
6
|
+
"backend.health",
|
|
7
|
+
"backend.capabilities",
|
|
8
|
+
"backend.hello",
|
|
9
|
+
"runner.plan",
|
|
10
|
+
"createReport",
|
|
11
|
+
"reports.create",
|
|
12
|
+
"reports.redact",
|
|
13
|
+
"reports.summarize",
|
|
14
|
+
"commands",
|
|
15
|
+
"describe",
|
|
16
|
+
"help",
|
|
17
|
+
"redacted-run-report",
|
|
18
|
+
"files.preflight",
|
|
19
|
+
"projects.sources.planAdd",
|
|
20
|
+
"operations.inspect"
|
|
21
|
+
]),
|
|
22
|
+
/**
|
|
23
|
+
* These commands opt into the operation facade only when an operation
|
|
24
|
+
* identity is present. With no identity they retain their legacy path.
|
|
25
|
+
*/
|
|
26
|
+
operationOptIn: Object.freeze([
|
|
27
|
+
"runner.run",
|
|
28
|
+
"runner.stream",
|
|
29
|
+
"responses.create",
|
|
30
|
+
"ask",
|
|
31
|
+
"askInThread",
|
|
32
|
+
"askWithFiles",
|
|
33
|
+
"askAndDownload",
|
|
34
|
+
"work.start",
|
|
35
|
+
"work.steer",
|
|
36
|
+
"operations.submit",
|
|
37
|
+
"operations.collect",
|
|
38
|
+
"operations.control"
|
|
39
|
+
]),
|
|
40
|
+
/**
|
|
41
|
+
* Legacy commands retain their public workflow and now receive a
|
|
42
|
+
* coordinator-backed PageLike/BrowserLike facade. This is a method-level
|
|
43
|
+
* guarantee: it does not turn the whole command or its polling loop into a
|
|
44
|
+
* single actor callback.
|
|
45
|
+
*/
|
|
46
|
+
legacyPageFacade: Object.freeze([
|
|
47
|
+
"runMessages",
|
|
48
|
+
"openThread",
|
|
49
|
+
"copyLatest",
|
|
50
|
+
"readLatest",
|
|
51
|
+
"downloadLatest",
|
|
52
|
+
"runPlan",
|
|
53
|
+
"new-ask-read",
|
|
54
|
+
"find-open-ask-read",
|
|
55
|
+
"find-open-copy-latest",
|
|
56
|
+
"attach-ask-read",
|
|
57
|
+
"ask-and-download",
|
|
58
|
+
"two-turn",
|
|
59
|
+
"doctor-upload",
|
|
60
|
+
"doctor",
|
|
61
|
+
"session.bootstrap",
|
|
62
|
+
"experience.detect",
|
|
63
|
+
"experience.open",
|
|
64
|
+
"configuration.inspect",
|
|
65
|
+
"configuration.apply",
|
|
66
|
+
"work.status",
|
|
67
|
+
"work.wait",
|
|
68
|
+
"work.readLatest",
|
|
69
|
+
"threads.new",
|
|
70
|
+
"threads.search",
|
|
71
|
+
"threads.open",
|
|
72
|
+
"messages.compose",
|
|
73
|
+
"messages.submit",
|
|
74
|
+
"messages.ask",
|
|
75
|
+
"messages.wait",
|
|
76
|
+
"messages.readLatest",
|
|
77
|
+
"messages.status",
|
|
78
|
+
"messages.stop",
|
|
79
|
+
"messages.waitAndRead",
|
|
80
|
+
"artifacts.listLatest",
|
|
81
|
+
"artifacts.wait",
|
|
82
|
+
"artifacts.downloadLatest",
|
|
83
|
+
"files.attach",
|
|
84
|
+
"files.downloadLatest",
|
|
85
|
+
"projects.sources.list",
|
|
86
|
+
"projects.sources.add",
|
|
87
|
+
"response.copy",
|
|
88
|
+
"modes.set",
|
|
89
|
+
"modes.get",
|
|
90
|
+
"tools.select"
|
|
91
|
+
]),
|
|
92
|
+
/**
|
|
93
|
+
* Browser acquisition seams not covered by the facade remain explicit
|
|
94
|
+
* migration gaps. The current command surface has none; discovery is
|
|
95
|
+
* coordinated in browser/attach.ts.
|
|
96
|
+
*/
|
|
97
|
+
legacyBrowserUnrouted: Object.freeze([]),
|
|
98
|
+
/**
|
|
99
|
+
* No backend or sequence command currently invokes
|
|
100
|
+
* routeCommandBrowserTransaction. Keep this category explicit so a future
|
|
101
|
+
* migration cannot silently turn a classification into an enforcement
|
|
102
|
+
* claim. A command may enter this list only after its own bounded DOM seam
|
|
103
|
+
* is implemented and tested.
|
|
104
|
+
*/
|
|
105
|
+
coordinatorEntrypoint: Object.freeze([])
|
|
106
|
+
});
|
|
107
|
+
/**
|
|
108
|
+
* The operation-aware public dispatch seams currently implemented by the
|
|
109
|
+
* client/backend path. This is separate from the coordinator entrypoint
|
|
110
|
+
* inventory: these commands route into the operation facade, whose adapter
|
|
111
|
+
* owns its own short tab transactions, rather than calling the generic helper
|
|
112
|
+
* below around the whole command.
|
|
113
|
+
*/
|
|
114
|
+
export const OPERATION_AWARE_DISPATCH_COMMANDS = Object.freeze([
|
|
115
|
+
...COMMAND_ROUTING_INVENTORY.operationOptIn
|
|
116
|
+
]);
|
|
117
|
+
/**
|
|
118
|
+
* Precise migration ownership for every legacy browser command. The values
|
|
119
|
+
* intentionally name source seams rather than claiming that the command is
|
|
120
|
+
* safe merely because it appears in the inventory.
|
|
121
|
+
*/
|
|
122
|
+
const LEGACY_PAGE_FACADE_OWNERS = Object.freeze({
|
|
123
|
+
runMessages: "src/client.ts -> src/commands/sequence.ts",
|
|
124
|
+
openThread: "src/client.ts -> src/commands/sequence.ts -> src/commands/threads.ts",
|
|
125
|
+
copyLatest: "src/client.ts -> src/commands/response-actions.ts",
|
|
126
|
+
readLatest: "src/client.ts -> src/commands/messages.ts",
|
|
127
|
+
downloadLatest: "src/client.ts -> src/commands/files.ts",
|
|
128
|
+
runPlan: "src/client.ts -> src/commands/sequence.ts",
|
|
129
|
+
"new-ask-read": "src/client.ts -> src/commands/sequence.ts -> src/commands/messages.ts",
|
|
130
|
+
"find-open-ask-read": "src/client.ts -> src/commands/sequence.ts -> src/commands/messages.ts",
|
|
131
|
+
"find-open-copy-latest": "src/client.ts -> src/commands/sequence.ts -> src/commands/response-actions.ts",
|
|
132
|
+
"attach-ask-read": "src/client.ts -> src/commands/sequence.ts -> src/commands/files.ts",
|
|
133
|
+
"ask-and-download": "src/client.ts -> src/commands/sequence.ts -> src/commands/files.ts",
|
|
134
|
+
"two-turn": "src/client.ts -> src/commands/sequence.ts -> src/commands/messages.ts",
|
|
135
|
+
"doctor-upload": "src/client.ts -> src/commands/doctor.ts",
|
|
136
|
+
doctor: "src/commands/doctor.ts",
|
|
137
|
+
"session.bootstrap": "src/commands/session.ts",
|
|
138
|
+
"experience.detect": "src/commands/experience.ts",
|
|
139
|
+
"experience.open": "src/commands/experience.ts",
|
|
140
|
+
"configuration.inspect": "src/commands/configuration.ts",
|
|
141
|
+
"configuration.apply": "src/commands/configuration.ts",
|
|
142
|
+
"work.status": "src/commands/work.ts",
|
|
143
|
+
"work.wait": "src/commands/work.ts",
|
|
144
|
+
"work.readLatest": "src/commands/work.ts",
|
|
145
|
+
"threads.new": "src/commands/threads.ts",
|
|
146
|
+
"threads.search": "src/commands/threads.ts",
|
|
147
|
+
"threads.open": "src/commands/threads.ts",
|
|
148
|
+
"messages.compose": "src/commands/messages.ts",
|
|
149
|
+
"messages.submit": "src/commands/messages.ts",
|
|
150
|
+
"messages.ask": "src/commands/messages.ts",
|
|
151
|
+
"messages.wait": "src/commands/messages.ts",
|
|
152
|
+
"messages.readLatest": "src/commands/messages.ts",
|
|
153
|
+
"messages.status": "src/commands/messages.ts",
|
|
154
|
+
"messages.stop": "src/commands/messages.ts",
|
|
155
|
+
"messages.waitAndRead": "src/commands/messages.ts",
|
|
156
|
+
"artifacts.listLatest": "src/commands/artifacts.ts",
|
|
157
|
+
"artifacts.wait": "src/commands/artifacts.ts",
|
|
158
|
+
"artifacts.downloadLatest": "src/commands/artifacts.ts",
|
|
159
|
+
"files.attach": "src/commands/files.ts",
|
|
160
|
+
"files.downloadLatest": "src/commands/files.ts",
|
|
161
|
+
"projects.sources.list": "src/commands/project-sources.ts",
|
|
162
|
+
"projects.sources.add": "src/commands/project-sources.ts",
|
|
163
|
+
"response.copy": "src/commands/response-actions.ts",
|
|
164
|
+
"modes.set": "src/commands/modes.ts",
|
|
165
|
+
"modes.get": "src/commands/modes.ts",
|
|
166
|
+
"tools.select": "src/commands/modes.ts"
|
|
167
|
+
});
|
|
168
|
+
export const COMMAND_ROUTING_GAPS = Object.freeze(COMMAND_ROUTING_INVENTORY.legacyBrowserUnrouted.map(command => Object.freeze({
|
|
169
|
+
command,
|
|
170
|
+
status: "legacy_browser_unrouted",
|
|
171
|
+
owner: LEGACY_PAGE_FACADE_OWNERS[command] ?? "src/browser/attach.ts -> coordinated browser/page facade",
|
|
172
|
+
requiredSeam: "bounded_tab_transaction",
|
|
173
|
+
reason: "legacy_command_dispatch_has_no_operation_aware_tab_seam"
|
|
174
|
+
})));
|
|
175
|
+
const commandRoutingClasses = new Map();
|
|
176
|
+
for (const name of COMMAND_ROUTING_INVENTORY.browserFree) {
|
|
177
|
+
if (commandRoutingClasses.has(name))
|
|
178
|
+
throw new Error("Duplicate command routing inventory entry.");
|
|
179
|
+
commandRoutingClasses.set(name, "browser_free");
|
|
180
|
+
}
|
|
181
|
+
for (const name of COMMAND_ROUTING_INVENTORY.operationOptIn) {
|
|
182
|
+
if (commandRoutingClasses.has(name))
|
|
183
|
+
throw new Error("Duplicate command routing inventory entry.");
|
|
184
|
+
commandRoutingClasses.set(name, "operation_opt_in");
|
|
185
|
+
}
|
|
186
|
+
for (const name of COMMAND_ROUTING_INVENTORY.legacyPageFacade) {
|
|
187
|
+
if (commandRoutingClasses.has(name))
|
|
188
|
+
throw new Error("Duplicate command routing inventory entry.");
|
|
189
|
+
commandRoutingClasses.set(name, "legacy_page_facade");
|
|
190
|
+
}
|
|
191
|
+
for (const name of COMMAND_ROUTING_INVENTORY.legacyBrowserUnrouted) {
|
|
192
|
+
if (commandRoutingClasses.has(name))
|
|
193
|
+
throw new Error("Duplicate command routing inventory entry.");
|
|
194
|
+
commandRoutingClasses.set(name, "legacy_browser_unrouted");
|
|
195
|
+
}
|
|
196
|
+
for (const name of COMMAND_ROUTING_INVENTORY.coordinatorEntrypoint) {
|
|
197
|
+
if (commandRoutingClasses.has(name))
|
|
198
|
+
throw new Error("Duplicate command routing inventory entry.");
|
|
199
|
+
commandRoutingClasses.set(name, "coordinator_entrypoint");
|
|
200
|
+
}
|
|
201
|
+
/** Return undefined for a command that has not been explicitly classified. */
|
|
202
|
+
export function classifyCommandRouting(command) {
|
|
203
|
+
return commandRoutingClasses.get(command);
|
|
204
|
+
}
|
|
205
|
+
export function isBrowserFreeCommand(command) {
|
|
206
|
+
return classifyCommandRouting(command) === "browser_free";
|
|
207
|
+
}
|
|
208
|
+
export function isOperationOptInCommand(command) {
|
|
209
|
+
return classifyCommandRouting(command) === "operation_opt_in";
|
|
210
|
+
}
|
|
211
|
+
export function isLegacyBrowserUnroutedCommand(command) {
|
|
212
|
+
return classifyCommandRouting(command) === "legacy_browser_unrouted";
|
|
213
|
+
}
|
|
214
|
+
export function isLegacyPageFacadeCommand(command) {
|
|
215
|
+
return classifyCommandRouting(command) === "legacy_page_facade";
|
|
216
|
+
}
|
|
217
|
+
export function isCoordinatorEntrypointCommand(command) {
|
|
218
|
+
return classifyCommandRouting(command) === "coordinator_entrypoint";
|
|
219
|
+
}
|
|
220
|
+
export function commandRoutingDisposition(command) {
|
|
221
|
+
const classification = classifyCommandRouting(command);
|
|
222
|
+
if (classification === undefined || classification === "legacy_browser_unrouted")
|
|
223
|
+
return undefined;
|
|
224
|
+
return classification === "browser_free" ? "browser_free" : "coordinator_routed";
|
|
225
|
+
}
|
|
226
|
+
export function isCoordinatorRoutedCommand(command) {
|
|
227
|
+
return commandRoutingDisposition(command) === "coordinator_routed";
|
|
228
|
+
}
|
|
229
|
+
/**
|
|
230
|
+
* Prepare the environment for one command invocation.
|
|
231
|
+
*
|
|
232
|
+
* This is deliberately an adapter rather than a whole-command coordinator
|
|
233
|
+
* transaction. `coordinateRuntimeEnv` returns PageLike/BrowserLike facades
|
|
234
|
+
* whose individual browser calls acquire the process-scoped actor for a
|
|
235
|
+
* bounded operation and release it before the next await. Consequently a
|
|
236
|
+
* command may wait for generation, poll, write a journal, or invoke caller
|
|
237
|
+
* code without retaining a tab actor. The coordinated browser/page values
|
|
238
|
+
* are copied back into the supplied invocation environment so legacy command
|
|
239
|
+
* mutations (notably `session.bootstrap`) remain visible to later sequence
|
|
240
|
+
* steps. Calling this on an already-coordinated environment is idempotent
|
|
241
|
+
* through the wrapper caches.
|
|
242
|
+
*/
|
|
243
|
+
export function routeCommandRuntimeEnv(command, env, options) {
|
|
244
|
+
const classification = classifyCommandRouting(command);
|
|
245
|
+
if (classification === undefined) {
|
|
246
|
+
throw new CommandRoutingError("unclassified_command");
|
|
247
|
+
}
|
|
248
|
+
if (classification === "legacy_browser_unrouted") {
|
|
249
|
+
throw new CommandRoutingError("legacy_command_unrouted");
|
|
250
|
+
}
|
|
251
|
+
if (classification === "browser_free") {
|
|
252
|
+
// Browser-free work must not even inspect provider members.
|
|
253
|
+
return env;
|
|
254
|
+
}
|
|
255
|
+
// An operation-opt-in command still has a supported legacy path when its
|
|
256
|
+
// caller omits an operation identity. Coordinate that path as well. When an
|
|
257
|
+
// operation identity is present the public client dispatches through the
|
|
258
|
+
// operation facade, whose capture boundary deliberately unwraps these
|
|
259
|
+
// compatibility facades before establishing its exact tab resource. This
|
|
260
|
+
// therefore cannot nest the operation's own coordinator transaction.
|
|
261
|
+
const coordinated = coordinateRuntimeEnv(env, options);
|
|
262
|
+
try {
|
|
263
|
+
if (coordinated.browser !== undefined && env.browser !== coordinated.browser) {
|
|
264
|
+
env.browser = coordinated.browser;
|
|
265
|
+
}
|
|
266
|
+
if (coordinated.page !== undefined && env.page !== coordinated.page) {
|
|
267
|
+
env.page = coordinated.page;
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
catch {
|
|
271
|
+
// A caller may pass a frozen compatibility snapshot. Preserve the
|
|
272
|
+
// command's ability to use the coordinated facade even though later
|
|
273
|
+
// legacy mutations cannot be committed to that snapshot.
|
|
274
|
+
return coordinated;
|
|
275
|
+
}
|
|
276
|
+
return env;
|
|
277
|
+
}
|
|
278
|
+
/**
|
|
279
|
+
* Run one command with the bounded legacy environment adapter.
|
|
280
|
+
*
|
|
281
|
+
* The callback is invoked outside any coordinator callback. The returned
|
|
282
|
+
* PageLike/BrowserLike values enforce short method-level transactions, so a
|
|
283
|
+
* caller callback or a generation/poll sleep cannot deadlock a nested actor.
|
|
284
|
+
*/
|
|
285
|
+
export function routeCommandExecution(command, env, callback, options) {
|
|
286
|
+
if (typeof callback !== "function") {
|
|
287
|
+
return Promise.reject(new CommandRoutingError("coordinator_context_required"));
|
|
288
|
+
}
|
|
289
|
+
return Promise.resolve().then(() => callback(routeCommandRuntimeEnv(command, env, options)));
|
|
290
|
+
}
|
|
291
|
+
/** Stable error for callers that try to route without enough ownership proof. */
|
|
292
|
+
export class CommandRoutingError extends Error {
|
|
293
|
+
code;
|
|
294
|
+
constructor(code) {
|
|
295
|
+
super(commandRoutingErrorMessage(code));
|
|
296
|
+
this.name = "CommandRoutingError";
|
|
297
|
+
this.code = code;
|
|
298
|
+
}
|
|
299
|
+
}
|
|
300
|
+
/**
|
|
301
|
+
* Execute one already-bounded browser transaction for an explicit coordinator
|
|
302
|
+
* entrypoint. The callback is intentionally the transaction boundary, not
|
|
303
|
+
* the command or request boundary. Callers must keep generation waits,
|
|
304
|
+
* polling sleeps, file hashing/transfers, journal writes, and report/caller
|
|
305
|
+
* callbacks outside this helper.
|
|
306
|
+
*/
|
|
307
|
+
export function routeCommandBrowserTransaction(command, context, callback) {
|
|
308
|
+
const classification = classifyCommandRouting(command);
|
|
309
|
+
if (classification === undefined) {
|
|
310
|
+
return Promise.reject(new CommandRoutingError("unclassified_command"));
|
|
311
|
+
}
|
|
312
|
+
if (typeof callback !== "function") {
|
|
313
|
+
return Promise.reject(new CommandRoutingError("coordinator_context_required"));
|
|
314
|
+
}
|
|
315
|
+
if (classification === "browser_free") {
|
|
316
|
+
return Promise.resolve().then(() => callback(undefined));
|
|
317
|
+
}
|
|
318
|
+
if (classification === "legacy_browser_unrouted") {
|
|
319
|
+
return Promise.reject(new CommandRoutingError("legacy_command_unrouted"));
|
|
320
|
+
}
|
|
321
|
+
if (classification === "legacy_page_facade") {
|
|
322
|
+
return Promise.reject(new CommandRoutingError("legacy_page_facade"));
|
|
323
|
+
}
|
|
324
|
+
if (classification === "operation_opt_in") {
|
|
325
|
+
return Promise.reject(new CommandRoutingError("operation_facade_managed"));
|
|
326
|
+
}
|
|
327
|
+
if (context === undefined) {
|
|
328
|
+
return Promise.reject(new CommandRoutingError("coordinator_context_required"));
|
|
329
|
+
}
|
|
330
|
+
const resource = context.runtimeContext.coordinatorResource();
|
|
331
|
+
if (!resource.exactTabOwnership || resource.resourceKind !== "tab") {
|
|
332
|
+
return Promise.reject(new CommandRoutingError("exact_ownership_unavailable"));
|
|
333
|
+
}
|
|
334
|
+
const requestOptions = {
|
|
335
|
+
// The immutable operation context is the sole owner authority. Do not
|
|
336
|
+
// allow a caller-supplied diagnostic owner to acquire the exact tab under
|
|
337
|
+
// different ownership metadata.
|
|
338
|
+
owner: context.runtimeContext.owner,
|
|
339
|
+
...(context.priority === undefined ? {} : { priority: context.priority }),
|
|
340
|
+
...(context.signal === undefined ? {} : { signal: context.signal }),
|
|
341
|
+
...(context.deadlineAt === undefined ? {} : { deadlineAt: context.deadlineAt }),
|
|
342
|
+
...(context.timeoutMs === undefined ? {} : { timeoutMs: context.timeoutMs }),
|
|
343
|
+
...(context.label === undefined ? {} : { label: context.label })
|
|
344
|
+
};
|
|
345
|
+
if (resource.resourceKind === "tab") {
|
|
346
|
+
return context.coordinator.withTabTransaction(resource.resourceKey, requestOptions, callback);
|
|
347
|
+
}
|
|
348
|
+
// The exact-ownership check above currently makes this branch unreachable;
|
|
349
|
+
// retain the defensive fallback so a future resource implementation cannot
|
|
350
|
+
// accidentally run a tab transaction against the browser actor.
|
|
351
|
+
return Promise.reject(new CommandRoutingError("exact_ownership_unavailable"));
|
|
352
|
+
}
|
|
353
|
+
/** Return a readonly snapshot useful for diagnostics and inventory tests. */
|
|
354
|
+
export function commandRoutingInventory() {
|
|
355
|
+
return Object.freeze(Object.fromEntries(commandRoutingClasses.entries()));
|
|
356
|
+
}
|
|
357
|
+
/**
|
|
358
|
+
* Return true when a request carries one of the reserved caller-owned
|
|
359
|
+
* operation identity fields. This is intentionally structural and never
|
|
360
|
+
* reads or serializes prompt/instruction values.
|
|
361
|
+
*/
|
|
362
|
+
export function hasOperationIdentity(value) {
|
|
363
|
+
try {
|
|
364
|
+
return hasOperationIdentityInner(value, new Set(), 0);
|
|
365
|
+
}
|
|
366
|
+
catch {
|
|
367
|
+
// Routing inspection is a caller-controlled boundary. Proxies, accessors,
|
|
368
|
+
// and descriptor traps must never be invoked merely to decide whether a
|
|
369
|
+
// legacy browser handler is safe. An unreadable shape could conceal an
|
|
370
|
+
// operation locator, so fail closed and keep it away from the legacy path.
|
|
371
|
+
return true;
|
|
372
|
+
}
|
|
373
|
+
}
|
|
374
|
+
/**
|
|
375
|
+
* Backend and sequence dispatchers call this before direct command dispatch.
|
|
376
|
+
* Legacy callers without an operation identity remain byte-for-byte on the
|
|
377
|
+
* existing path. An operation-aware request is allowed only for explicitly
|
|
378
|
+
* migrated facade commands (or browser-free diagnostics); all other browser
|
|
379
|
+
* commands fail before their handler can touch the browser.
|
|
380
|
+
*/
|
|
381
|
+
export function assertOperationAwareDispatchAllowed(command, payload) {
|
|
382
|
+
const classification = classifyCommandRouting(command);
|
|
383
|
+
if (classification === undefined) {
|
|
384
|
+
throw new CommandRoutingError("unclassified_command");
|
|
385
|
+
}
|
|
386
|
+
if (!hasOperationIdentity(payload))
|
|
387
|
+
return;
|
|
388
|
+
if (classification === "browser_free"
|
|
389
|
+
|| classification === "operation_opt_in"
|
|
390
|
+
|| classification === "coordinator_entrypoint")
|
|
391
|
+
return;
|
|
392
|
+
throw new CommandRoutingError("operation_routing_unavailable");
|
|
393
|
+
}
|
|
394
|
+
function commandRoutingErrorMessage(code) {
|
|
395
|
+
switch (code) {
|
|
396
|
+
case "unclassified_command":
|
|
397
|
+
return "The command has no explicit browser-routing classification.";
|
|
398
|
+
case "coordinator_context_required":
|
|
399
|
+
return "An operation runtime context is required for a bounded coordinator browser transaction.";
|
|
400
|
+
case "exact_ownership_unavailable":
|
|
401
|
+
return "Exact claimed-tab ownership is required for a bounded coordinator browser transaction.";
|
|
402
|
+
case "legacy_command_unrouted":
|
|
403
|
+
return "This legacy browser command has no bounded coordinator transaction seam.";
|
|
404
|
+
case "legacy_page_facade":
|
|
405
|
+
return "This legacy browser command coordinates individual PageLike/BrowserLike calls and cannot be wrapped as a whole-command transaction.";
|
|
406
|
+
case "operation_facade_managed":
|
|
407
|
+
return "This operation-aware command is managed by its operation facade and cannot be wrapped as a whole-command transaction.";
|
|
408
|
+
case "operation_routing_unavailable":
|
|
409
|
+
return "An operation identity was supplied to a legacy browser command without an operation-aware dispatch seam.";
|
|
410
|
+
}
|
|
411
|
+
}
|
|
412
|
+
function hasOperationIdentityInner(value, seen, depth) {
|
|
413
|
+
if (value === null || typeof value !== "object")
|
|
414
|
+
return false;
|
|
415
|
+
if (seen.has(value))
|
|
416
|
+
return false;
|
|
417
|
+
if (depth > 8)
|
|
418
|
+
return true;
|
|
419
|
+
seen.add(value);
|
|
420
|
+
const descriptors = Object.getOwnPropertyDescriptors(value);
|
|
421
|
+
for (const [key, descriptor] of Object.entries(descriptors)) {
|
|
422
|
+
if (key === "operationId" || key === "controlActionId" || key === "handle" || key === "parentHandle") {
|
|
423
|
+
return true;
|
|
424
|
+
}
|
|
425
|
+
if (!("value" in descriptor))
|
|
426
|
+
return true;
|
|
427
|
+
if (hasOperationIdentityInner(descriptor.value, seen, depth + 1))
|
|
428
|
+
return true;
|
|
429
|
+
}
|
|
430
|
+
return false;
|
|
431
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import type { BrowserLike, PageLike, RuntimeEnv } from "../types.js";
|
|
2
|
+
import { type BrowserResourceKey, type CoordinatorOwner, type ProcessTabCoordinator } from "./tab-coordinator.js";
|
|
3
|
+
export declare const MAX_BROWSER_TAB_CANDIDATES = 256;
|
|
4
|
+
export type CoordinatedBrowserOptions = Readonly<{
|
|
5
|
+
coordinator?: ProcessTabCoordinator;
|
|
6
|
+
owner?: CoordinatorOwner;
|
|
7
|
+
}>;
|
|
8
|
+
export declare class CoordinatedBrowserError extends Error {
|
|
9
|
+
readonly code = "coordinated_browser_invalid";
|
|
10
|
+
constructor(message: string, options?: {
|
|
11
|
+
cause?: unknown;
|
|
12
|
+
});
|
|
13
|
+
}
|
|
14
|
+
export declare function coordinatedBrowserResource(browser?: BrowserLike): Readonly<{
|
|
15
|
+
kind: "browser";
|
|
16
|
+
key: BrowserResourceKey;
|
|
17
|
+
}>;
|
|
18
|
+
/** Wrap a browser using one browser-wide actor; no per-tab capability is inferred. */
|
|
19
|
+
export declare function createCoordinatedBrowser(browser: BrowserLike, options?: CoordinatedBrowserOptions): BrowserLike;
|
|
20
|
+
/** Wrap one initial/captured page with the browser-wide legacy actor. */
|
|
21
|
+
export declare function createCoordinatedPageForBrowser(page: PageLike, browser?: BrowserLike, options?: CoordinatedBrowserOptions): PageLike;
|
|
22
|
+
/** Make a fresh RuntimeEnv snapshot with only browser/page values coordinated. */
|
|
23
|
+
export declare function coordinateRuntimeEnv(env: RuntimeEnv, options?: CoordinatedBrowserOptions): RuntimeEnv;
|
|
24
|
+
export declare function unwrapCoordinatedBrowser(browser: BrowserLike): BrowserLike;
|