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.
Files changed (231) hide show
  1. package/CHANGELOG.md +42 -0
  2. package/README.md +43 -0
  3. package/contracts/v1/fixtures/backend-capabilities.json +40 -1
  4. package/contracts/v1/fixtures/backend-compatibility.json +21 -0
  5. package/contracts/v1/fixtures/backend-version.json +6 -1
  6. package/contracts/v1/fixtures/download-blocked-by-browser.json +22 -0
  7. package/contracts/v1/fixtures/download-receipt-failed.json +22 -0
  8. package/contracts/v1/fixtures/download-receipt-timeout.json +22 -0
  9. package/contracts/v1/fixtures/journal-rpc-indeterminate.json +32 -0
  10. package/contracts/v1/fixtures/journal-rpc-unsupported-platform.json +32 -0
  11. package/contracts/v1/fixtures/journal-runtime-unavailable.json +32 -0
  12. package/contracts/v1/fixtures/operation-action-prepared-event.json +42 -0
  13. package/contracts/v1/fixtures/operation-action.json +13 -0
  14. package/contracts/v1/fixtures/operation-artifact-receipt.json +14 -0
  15. package/contracts/v1/fixtures/operation-artifact-transfer-intent-event.json +24 -0
  16. package/contracts/v1/fixtures/operation-artifact-transfer-receipt-event.json +26 -0
  17. package/contracts/v1/fixtures/operation-artifact-transfer-state.json +178 -0
  18. package/contracts/v1/fixtures/operation-blocker.json +10 -0
  19. package/contracts/v1/fixtures/operation-collect-request.json +17 -0
  20. package/contracts/v1/fixtures/operation-collect-result.json +42 -0
  21. package/contracts/v1/fixtures/operation-control-receipt.json +13 -0
  22. package/contracts/v1/fixtures/operation-control-request.json +18 -0
  23. package/contracts/v1/fixtures/operation-control-result.json +31 -0
  24. package/contracts/v1/fixtures/operation-event.json +18 -0
  25. package/contracts/v1/fixtures/operation-handle.json +10 -0
  26. package/contracts/v1/fixtures/operation-inspect-request.json +13 -0
  27. package/contracts/v1/fixtures/operation-inspect-result.json +205 -0
  28. package/contracts/v1/fixtures/operation-ownership-baseline-event.json +34 -0
  29. package/contracts/v1/fixtures/operation-receipt.json +32 -0
  30. package/contracts/v1/fixtures/operation-recovery-decision.json +7 -0
  31. package/contracts/v1/fixtures/operation-recovery-observation.json +12 -0
  32. package/contracts/v1/fixtures/operation-request.json +33 -0
  33. package/contracts/v1/fixtures/operation-state.json +144 -0
  34. package/contracts/v1/fixtures/operation-submission-witness-event.json +20 -0
  35. package/contracts/v1/fixtures/operation-submission-witness.json +11 -0
  36. package/contracts/v1/fixtures/operation-submit-result.json +16 -0
  37. package/contracts/v1/fixtures/operation-target-established-event.json +21 -0
  38. package/contracts/v1/manifest.json +185 -1
  39. package/contracts/v1/parity-suite.json +106 -8
  40. package/contracts/v1/schemas/backend-compatibility.schema.json +65 -0
  41. package/contracts/v1/schemas/backend-request.schema.json +8 -2
  42. package/contracts/v1/schemas/capabilities.schema.json +81 -1
  43. package/contracts/v1/schemas/manifest.schema.json +57 -0
  44. package/contracts/v1/schemas/operation-action.schema.json +155 -0
  45. package/contracts/v1/schemas/operation-artifact-receipt.schema.json +89 -0
  46. package/contracts/v1/schemas/operation-blocker.schema.json +70 -0
  47. package/contracts/v1/schemas/operation-collect-request.schema.json +46 -0
  48. package/contracts/v1/schemas/operation-collect-result.schema.json +74 -0
  49. package/contracts/v1/schemas/operation-control-receipt.schema.json +108 -0
  50. package/contracts/v1/schemas/operation-control-request.schema.json +111 -0
  51. package/contracts/v1/schemas/operation-control-result.schema.json +112 -0
  52. package/contracts/v1/schemas/operation-event.schema.json +756 -0
  53. package/contracts/v1/schemas/operation-handle.schema.json +55 -0
  54. package/contracts/v1/schemas/operation-inspect-request.schema.json +42 -0
  55. package/contracts/v1/schemas/operation-inspect-result.schema.json +1662 -0
  56. package/contracts/v1/schemas/operation-receipt.schema.json +153 -0
  57. package/contracts/v1/schemas/operation-recovery.schema.json +314 -0
  58. package/contracts/v1/schemas/operation-request.schema.json +158 -0
  59. package/contracts/v1/schemas/operation-state.schema.json +691 -0
  60. package/contracts/v1/schemas/operation-submission-witness.schema.json +48 -0
  61. package/contracts/v1/schemas/operation-submit-result.schema.json +94 -0
  62. package/contracts/v1/surface-drift-policy.json +50 -0
  63. package/contracts/v1/vectors/operation-request-digest-v1.json +43 -0
  64. package/dist/codex-chatgpt-control-backend.mjs +45882 -9361
  65. package/dist/codex-chatgpt-control-journal.mjs +5547 -0
  66. package/dist/codex-chatgpt-control-live-smoke.bundle.mjs +51677 -0
  67. package/dist/codex-chatgpt-control-release-canary.bundle.mjs +52104 -0
  68. package/dist/codex-chatgpt-control.bundle.mjs +48392 -10260
  69. package/dist/src/backend/client.d.ts +103 -2
  70. package/dist/src/backend/client.js +1436 -97
  71. package/dist/src/backend/compatibility.d.ts +12 -0
  72. package/dist/src/backend/compatibility.js +208 -0
  73. package/dist/src/backend/protocol.d.ts +84 -1
  74. package/dist/src/backend/protocol.js +31 -5
  75. package/dist/src/backend/runtime-identity.d.ts +10 -0
  76. package/dist/src/backend/runtime-identity.js +141 -0
  77. package/dist/src/backend/session.d.ts +10 -2
  78. package/dist/src/backend/session.js +478 -7
  79. package/dist/src/backend/stdio-server.d.ts +4 -1
  80. package/dist/src/backend/stdio-server.js +240 -28
  81. package/dist/src/browser/active-composer-file-input.d.ts +9 -0
  82. package/dist/src/browser/active-composer-file-input.js +33 -0
  83. package/dist/src/browser/attach.d.ts +4 -1
  84. package/dist/src/browser/attach.js +136 -28
  85. package/dist/src/browser/chatgpt-url.d.ts +2 -0
  86. package/dist/src/browser/chatgpt-url.js +9 -0
  87. package/dist/src/browser/downloads.d.ts +17 -1
  88. package/dist/src/browser/downloads.js +150 -28
  89. package/dist/src/browser/page-state.js +6 -0
  90. package/dist/src/client.d.ts +43 -0
  91. package/dist/src/client.js +1279 -59
  92. package/dist/src/commands/artifacts.js +6 -4
  93. package/dist/src/commands/chat-popover.d.ts +37 -0
  94. package/dist/src/commands/chat-popover.js +537 -0
  95. package/dist/src/commands/configuration.d.ts +5 -0
  96. package/dist/src/commands/configuration.js +134 -21
  97. package/dist/src/commands/context.js +10 -3
  98. package/dist/src/commands/doctor.d.ts +1 -1
  99. package/dist/src/commands/doctor.js +27 -4
  100. package/dist/src/commands/experience.d.ts +5 -0
  101. package/dist/src/commands/experience.js +104 -21
  102. package/dist/src/commands/files.js +14 -33
  103. package/dist/src/commands/modes.js +85 -21
  104. package/dist/src/commands/power-discovery.d.ts +130 -0
  105. package/dist/src/commands/power-discovery.js +669 -0
  106. package/dist/src/commands/project-sources.js +325 -31
  107. package/dist/src/commands/sequence.js +59 -32
  108. package/dist/src/commands/session.js +19 -6
  109. package/dist/src/commands/work.js +31 -0
  110. package/dist/src/dom/composer-text.d.ts +6 -0
  111. package/dist/src/dom/composer-text.js +85 -0
  112. package/dist/src/errors.d.ts +9 -0
  113. package/dist/src/errors.js +22 -0
  114. package/dist/src/index.d.ts +6 -0
  115. package/dist/src/index.js +9 -0
  116. package/dist/src/operations/artifact-output.d.ts +69 -0
  117. package/dist/src/operations/artifact-output.js +1748 -0
  118. package/dist/src/operations/artifact-stream.d.ts +19 -0
  119. package/dist/src/operations/artifact-stream.js +35 -0
  120. package/dist/src/operations/artifact-transfer.d.ts +149 -0
  121. package/dist/src/operations/artifact-transfer.js +1312 -0
  122. package/dist/src/operations/browser-adapter.d.ts +167 -0
  123. package/dist/src/operations/browser-adapter.js +2103 -0
  124. package/dist/src/operations/browser-observation.d.ts +110 -0
  125. package/dist/src/operations/browser-observation.js +1256 -0
  126. package/dist/src/operations/browser-target.d.ts +105 -0
  127. package/dist/src/operations/browser-target.js +531 -0
  128. package/dist/src/operations/canonical.d.ts +4 -0
  129. package/dist/src/operations/canonical.js +412 -0
  130. package/dist/src/operations/chatgpt-runtime.d.ts +72 -0
  131. package/dist/src/operations/chatgpt-runtime.js +1232 -0
  132. package/dist/src/operations/client.d.ts +138 -0
  133. package/dist/src/operations/client.js +1145 -0
  134. package/dist/src/operations/collector.d.ts +195 -0
  135. package/dist/src/operations/collector.js +1039 -0
  136. package/dist/src/operations/configuration-routing.d.ts +4 -0
  137. package/dist/src/operations/configuration-routing.js +14 -0
  138. package/dist/src/operations/control.d.ts +372 -0
  139. package/dist/src/operations/control.js +1498 -0
  140. package/dist/src/operations/file-identity.d.ts +33 -0
  141. package/dist/src/operations/file-identity.js +153 -0
  142. package/dist/src/operations/handle.d.ts +19 -0
  143. package/dist/src/operations/handle.js +727 -0
  144. package/dist/src/operations/index.d.ts +25 -0
  145. package/dist/src/operations/index.js +25 -0
  146. package/dist/src/operations/journal-authority.d.ts +12 -0
  147. package/dist/src/operations/journal-authority.js +1 -0
  148. package/dist/src/operations/journal-rpc-client.d.ts +12 -0
  149. package/dist/src/operations/journal-rpc-client.js +225 -0
  150. package/dist/src/operations/journal-rpc-protocol.d.ts +32 -0
  151. package/dist/src/operations/journal-rpc-protocol.js +214 -0
  152. package/dist/src/operations/journal-rpc-server.d.ts +15 -0
  153. package/dist/src/operations/journal-rpc-server.js +272 -0
  154. package/dist/src/operations/journal.d.ts +143 -0
  155. package/dist/src/operations/journal.js +1957 -0
  156. package/dist/src/operations/production-attachments.d.ts +118 -0
  157. package/dist/src/operations/production-attachments.js +1035 -0
  158. package/dist/src/operations/production-chatgpt-artifacts.d.ts +74 -0
  159. package/dist/src/operations/production-chatgpt-artifacts.js +1146 -0
  160. package/dist/src/operations/production-chatgpt-attachments.d.ts +80 -0
  161. package/dist/src/operations/production-chatgpt-attachments.js +1639 -0
  162. package/dist/src/operations/production-configuration.d.ts +42 -0
  163. package/dist/src/operations/production-configuration.js +1544 -0
  164. package/dist/src/operations/production-primitives.d.ts +53 -0
  165. package/dist/src/operations/production-primitives.js +856 -0
  166. package/dist/src/operations/production-work-steer.d.ts +203 -0
  167. package/dist/src/operations/production-work-steer.js +1218 -0
  168. package/dist/src/operations/recovery.d.ts +80 -0
  169. package/dist/src/operations/recovery.js +174 -0
  170. package/dist/src/operations/runtime-adapter.d.ts +126 -0
  171. package/dist/src/operations/runtime-adapter.js +802 -0
  172. package/dist/src/operations/send-once.d.ts +224 -0
  173. package/dist/src/operations/send-once.js +1081 -0
  174. package/dist/src/operations/service.d.ts +286 -0
  175. package/dist/src/operations/service.js +2831 -0
  176. package/dist/src/operations/staging.d.ts +136 -0
  177. package/dist/src/operations/staging.js +630 -0
  178. package/dist/src/operations/state-machine.d.ts +29 -0
  179. package/dist/src/operations/state-machine.js +2047 -0
  180. package/dist/src/operations/submission.d.ts +423 -0
  181. package/dist/src/operations/submission.js +1676 -0
  182. package/dist/src/operations/transactional-chat-power.d.ts +17 -0
  183. package/dist/src/operations/transactional-chat-power.js +212 -0
  184. package/dist/src/operations/turn-ownership.d.ts +202 -0
  185. package/dist/src/operations/turn-ownership.js +700 -0
  186. package/dist/src/operations/types.d.ts +454 -0
  187. package/dist/src/operations/types.js +20 -0
  188. package/dist/src/operations/wire-requests.d.ts +21 -0
  189. package/dist/src/operations/wire-requests.js +396 -0
  190. package/dist/src/operations/wire-results.d.ts +97 -0
  191. package/dist/src/operations/wire-results.js +818 -0
  192. package/dist/src/runner/responses.d.ts +3 -1
  193. package/dist/src/runner/responses.js +19 -1
  194. package/dist/src/runner/result.js +227 -55
  195. package/dist/src/runner/types.d.ts +12 -0
  196. package/dist/src/runtime/command-routing.d.ts +149 -0
  197. package/dist/src/runtime/command-routing.js +431 -0
  198. package/dist/src/runtime/coordinated-browser.d.ts +24 -0
  199. package/dist/src/runtime/coordinated-browser.js +315 -0
  200. package/dist/src/runtime/coordinated-page.d.ts +41 -0
  201. package/dist/src/runtime/coordinated-page.js +651 -0
  202. package/dist/src/runtime/operation-context.d.ts +142 -0
  203. package/dist/src/runtime/operation-context.js +410 -0
  204. package/dist/src/runtime/runtime-session.d.ts +95 -0
  205. package/dist/src/runtime/runtime-session.js +314 -0
  206. package/dist/src/runtime/tab-coordinator.d.ts +200 -0
  207. package/dist/src/runtime/tab-coordinator.js +1200 -0
  208. package/dist/src/runtime/value-boundaries.d.ts +18 -0
  209. package/dist/src/runtime/value-boundaries.js +49 -0
  210. package/dist/src/safety/blockers.js +8 -1
  211. package/dist/src/safety/untrusted-output.js +2 -1
  212. package/dist/src/scripts/backend-server.js +4 -1
  213. package/dist/src/scripts/capture-surface-profile.js +7 -2
  214. package/dist/src/scripts/journal-server.d.ts +2 -0
  215. package/dist/src/scripts/journal-server.js +37 -0
  216. package/dist/src/scripts/live-smoke/harness.js +79 -7
  217. package/dist/src/scripts/live-smoke/scenarios.d.ts +42 -1
  218. package/dist/src/scripts/live-smoke/scenarios.js +147 -30
  219. package/dist/src/scripts/live-smoke/transactional.d.ts +17 -0
  220. package/dist/src/scripts/live-smoke/transactional.js +254 -0
  221. package/dist/src/scripts/live-smoke/types.d.ts +3 -0
  222. package/dist/src/scripts/release-canary-module.js +17 -4
  223. package/dist/src/types.d.ts +38 -1
  224. package/package.json +8 -3
  225. package/references/2026-08-16-transactional-operations.md +459 -0
  226. package/references/2026-09-06-journal-service.md +140 -0
  227. package/references/agents-runner.md +34 -0
  228. package/references/backend-protocol.md +176 -0
  229. package/references/python-parity.md +137 -0
  230. package/references/responses-adapter.md +19 -0
  231. package/references/streaming.md +6 -0
@@ -0,0 +1,314 @@
1
+ const MUTABLE_FIELDS = Object.freeze([
2
+ "browser",
3
+ "page",
4
+ "expectedTabId"
5
+ ]);
6
+ const BASE_FIELDS = Object.freeze([
7
+ "agent",
8
+ "clipboard",
9
+ "now"
10
+ ]);
11
+ const ALLOWED_OPTION_FIELDS = new Set([...BASE_FIELDS, ...MUTABLE_FIELDS]);
12
+ const STATIC_ERROR_MESSAGES = Object.freeze({
13
+ invalid_options: "RuntimeEnvSession options are invalid.",
14
+ invalid_capture: "RuntimeEnvSession capture contains an unsupported value.",
15
+ capture_closed: "RuntimeEnvSession capture is already closed.",
16
+ commit_conflict: "RuntimeEnvSession commit conflicts with a newer invocation.",
17
+ revision_exhausted: "RuntimeEnvSession revision capacity is exhausted."
18
+ });
19
+ /**
20
+ * Errors intentionally have a fixed message. In particular, no browser,
21
+ * page, tab id, caller object, or native error is interpolated into a
22
+ * RuntimeEnvSession diagnostic.
23
+ */
24
+ export class RuntimeEnvSessionError extends Error {
25
+ code;
26
+ constructor(code) {
27
+ super(STATIC_ERROR_MESSAGES[code]);
28
+ this.name = "RuntimeEnvSessionError";
29
+ this.code = code;
30
+ }
31
+ }
32
+ function invalidOptions() {
33
+ return new RuntimeEnvSessionError("invalid_options");
34
+ }
35
+ function invalidCapture() {
36
+ return new RuntimeEnvSessionError("invalid_capture");
37
+ }
38
+ function readDataOptions(options) {
39
+ if (options === undefined)
40
+ return {};
41
+ if (options === null || typeof options !== "object" || Array.isArray(options)) {
42
+ throw invalidOptions();
43
+ }
44
+ let descriptors;
45
+ try {
46
+ // Reading descriptors does not invoke accessor values. A hostile proxy
47
+ // may still reject reflection; that is converted to the fixed error.
48
+ descriptors = Object.getOwnPropertyDescriptors(options);
49
+ }
50
+ catch {
51
+ throw invalidOptions();
52
+ }
53
+ const result = {};
54
+ for (const key of Reflect.ownKeys(descriptors)) {
55
+ if (typeof key !== "string" || !ALLOWED_OPTION_FIELDS.has(key)) {
56
+ throw invalidOptions();
57
+ }
58
+ const descriptor = descriptors[key];
59
+ if (descriptor === undefined || descriptor.get !== undefined || descriptor.set !== undefined || !("value" in descriptor)) {
60
+ throw invalidOptions();
61
+ }
62
+ result[key] = descriptor;
63
+ }
64
+ return result;
65
+ }
66
+ function readOption(descriptors, key) {
67
+ return descriptors[key]?.value;
68
+ }
69
+ function validateOptions(options) {
70
+ const descriptors = readDataOptions(options);
71
+ const expectedTabId = readOption(descriptors, "expectedTabId");
72
+ if (expectedTabId !== undefined && typeof expectedTabId !== "string")
73
+ throw invalidOptions();
74
+ const now = readOption(descriptors, "now");
75
+ if (now !== undefined && typeof now !== "function")
76
+ throw invalidOptions();
77
+ return {
78
+ agent: readOption(descriptors, "agent"),
79
+ browser: readOption(descriptors, "browser"),
80
+ page: readOption(descriptors, "page"),
81
+ clipboard: readOption(descriptors, "clipboard"),
82
+ now,
83
+ expectedTabId
84
+ };
85
+ }
86
+ function presence(value) {
87
+ return value === undefined ? "unset" : "set";
88
+ }
89
+ function sameValue(left, right) {
90
+ return Object.is(left, right);
91
+ }
92
+ function freezeFields(fields) {
93
+ return Object.freeze([...fields]);
94
+ }
95
+ function createInvocationEnv(base, snapshot) {
96
+ const env = {};
97
+ // Base/provider references are copied once and cannot be overwritten by a
98
+ // legacy command. Snapshot values are writable and are committed through
99
+ // the owning session's CAS path only.
100
+ for (const key of BASE_FIELDS) {
101
+ Object.defineProperty(env, key, {
102
+ configurable: false,
103
+ enumerable: true,
104
+ value: base[key],
105
+ writable: false
106
+ });
107
+ }
108
+ for (const key of MUTABLE_FIELDS) {
109
+ Object.defineProperty(env, key, {
110
+ configurable: false,
111
+ enumerable: true,
112
+ value: snapshot[key],
113
+ writable: true
114
+ });
115
+ }
116
+ return env;
117
+ }
118
+ function readInvocationSnapshot(env) {
119
+ const snapshot = {};
120
+ for (const key of MUTABLE_FIELDS) {
121
+ let descriptor;
122
+ try {
123
+ descriptor = Object.getOwnPropertyDescriptor(env, key);
124
+ }
125
+ catch {
126
+ throw invalidCapture();
127
+ }
128
+ // The fields are installed as data properties. Treat any attempted
129
+ // descriptor/prototype tampering as invalid without invoking a getter.
130
+ if (descriptor === undefined || descriptor.get !== undefined || descriptor.set !== undefined || !("value" in descriptor)) {
131
+ throw invalidCapture();
132
+ }
133
+ const value = descriptor.value;
134
+ if (key === "expectedTabId" && value !== undefined && typeof value !== "string") {
135
+ throw invalidCapture();
136
+ }
137
+ snapshot[key] = value;
138
+ }
139
+ return snapshot;
140
+ }
141
+ function freezeCommitResult(revision, changedFields, appliedFields, converged) {
142
+ return Object.freeze({
143
+ revision,
144
+ changedFields: freezeFields(changedFields),
145
+ appliedFields: freezeFields(appliedFields),
146
+ converged
147
+ });
148
+ }
149
+ /**
150
+ * Owns the mutable browser/page/tab snapshot used by invocation-scoped
151
+ * RuntimeEnv captures. It intentionally performs no browser locking or
152
+ * command dispatch; this is the synchronous in-process snapshot/CAS boundary
153
+ * used by `createChatGPT` to isolate concurrent legacy invocations.
154
+ */
155
+ export class RuntimeEnvSession {
156
+ base;
157
+ state;
158
+ captureCount = 0;
159
+ openCaptureCount = 0;
160
+ constructor(options) {
161
+ const validated = validateOptions(options);
162
+ this.base = Object.freeze({
163
+ agent: validated.agent,
164
+ clipboard: validated.clipboard,
165
+ now: validated.now
166
+ });
167
+ this.state = {
168
+ browser: validated.browser,
169
+ page: validated.page,
170
+ expectedTabId: validated.expectedTabId,
171
+ revision: 0
172
+ };
173
+ }
174
+ /** Current revision; no browser or page value is exposed. */
175
+ get revision() {
176
+ return this.state.revision;
177
+ }
178
+ /** Return frozen, redacted state diagnostics. */
179
+ diagnostics() {
180
+ return Object.freeze({
181
+ revision: this.state.revision,
182
+ captures: this.captureCount,
183
+ openCaptures: this.openCaptureCount,
184
+ base: Object.freeze({
185
+ agent: presence(this.base.agent),
186
+ clipboard: presence(this.base.clipboard),
187
+ now: presence(this.base.now)
188
+ }),
189
+ snapshot: Object.freeze({
190
+ browser: presence(this.state.browser),
191
+ page: presence(this.state.page),
192
+ expectedTabId: presence(this.state.expectedTabId)
193
+ })
194
+ });
195
+ }
196
+ capture() {
197
+ const capturedRevision = this.state.revision;
198
+ const baseline = {
199
+ browser: this.state.browser,
200
+ page: this.state.page,
201
+ expectedTabId: this.state.expectedTabId
202
+ };
203
+ const env = createInvocationEnv(this.base, baseline);
204
+ let status = "open";
205
+ this.captureCount += 1;
206
+ this.openCaptureCount += 1;
207
+ const close = (nextStatus) => {
208
+ if (status !== "open")
209
+ throw new RuntimeEnvSessionError("capture_closed");
210
+ status = nextStatus;
211
+ this.openCaptureCount -= 1;
212
+ };
213
+ const commit = () => {
214
+ // A commit attempt is one-shot, including invalid captures and CAS
215
+ // conflicts. Retrying a mutated stale environment would be ambiguous.
216
+ close("committed");
217
+ const candidate = readInvocationSnapshot(env);
218
+ const changedFields = MUTABLE_FIELDS.filter((key) => !sameValue(candidate[key], baseline[key]));
219
+ // Read-only invocations never clobber a newer snapshot, regardless of
220
+ // how many commits occurred after this capture was made.
221
+ if (changedFields.length === 0) {
222
+ return freezeCommitResult(this.state.revision, changedFields, [], false);
223
+ }
224
+ const stale = capturedRevision !== this.state.revision;
225
+ if (stale) {
226
+ // Merge only fields intentionally changed by this invocation. A
227
+ // stale commit converges only if each such field already has the same
228
+ // reference/value in the current session state.
229
+ for (const key of changedFields) {
230
+ if (!sameValue(candidate[key], this.state[key])) {
231
+ throw new RuntimeEnvSessionError("commit_conflict");
232
+ }
233
+ }
234
+ }
235
+ const appliedFields = changedFields.filter((key) => !sameValue(candidate[key], this.state[key]));
236
+ if (appliedFields.length === 0) {
237
+ return freezeCommitResult(this.state.revision, changedFields, appliedFields, stale);
238
+ }
239
+ if (this.state.revision >= Number.MAX_SAFE_INTEGER) {
240
+ throw new RuntimeEnvSessionError("revision_exhausted");
241
+ }
242
+ // The state object is replaced once, after every field has passed the
243
+ // CAS checks. Consumers can therefore never observe a partial tuple.
244
+ const nextState = {
245
+ browser: this.state.browser,
246
+ page: this.state.page,
247
+ expectedTabId: this.state.expectedTabId,
248
+ revision: this.state.revision + 1
249
+ };
250
+ for (const key of appliedFields) {
251
+ if (key === "browser")
252
+ nextState.browser = candidate.browser;
253
+ else if (key === "page")
254
+ nextState.page = candidate.page;
255
+ else
256
+ nextState.expectedTabId = candidate.expectedTabId;
257
+ }
258
+ this.state = nextState;
259
+ return freezeCommitResult(this.state.revision, changedFields, appliedFields, stale);
260
+ };
261
+ const abandon = () => {
262
+ close("abandoned");
263
+ };
264
+ const diagnostics = () => Object.freeze({
265
+ status,
266
+ revision: capturedRevision
267
+ });
268
+ return Object.freeze({
269
+ env,
270
+ revision: capturedRevision,
271
+ commit,
272
+ abandon,
273
+ diagnostics
274
+ });
275
+ }
276
+ /** Capture, run one invocation, and publish its snapshot only on success. */
277
+ async run(callback) {
278
+ if (typeof callback !== "function")
279
+ throw new RuntimeEnvSessionError("invalid_options");
280
+ const capture = this.capture();
281
+ try {
282
+ const result = await callback(capture.env);
283
+ try {
284
+ capture.commit();
285
+ }
286
+ catch (error) {
287
+ // The snapshot is only a convenience default for a later invocation;
288
+ // it is not part of the browser command's outcome. A newer invocation
289
+ // may legitimately publish a different tab while this callback is in
290
+ // flight. Never turn an already-completed browser action into a
291
+ // rejected promise (and a tempting caller retry) merely because that
292
+ // stale convenience snapshot could not be published.
293
+ if (!(error instanceof RuntimeEnvSessionError) || error.code !== "commit_conflict") {
294
+ throw error;
295
+ }
296
+ }
297
+ return result;
298
+ }
299
+ catch (error) {
300
+ // Preserve the callback/commit error exactly. Abandon is best effort
301
+ // and has a fixed error if the callback already closed the capture.
302
+ try {
303
+ capture.abandon();
304
+ }
305
+ catch {
306
+ // The original callback or commit error is the useful result.
307
+ }
308
+ throw error;
309
+ }
310
+ }
311
+ }
312
+ export function createRuntimeEnvSession(options) {
313
+ return new RuntimeEnvSession(options);
314
+ }
@@ -0,0 +1,200 @@
1
+ /** A stable provider/browser identity. Ephemeral tab labels are not accepted. */
2
+ export type StableBrowserIdentity = Readonly<{
3
+ providerId: string;
4
+ browserId: string;
5
+ }>;
6
+ /** A stable provider/browser/tab identity. The tab id must come from the provider. */
7
+ export type StableTabIdentity = Readonly<StableBrowserIdentity & {
8
+ tabId: string;
9
+ }>;
10
+ declare const browserResourceKeyBrand: unique symbol;
11
+ declare const tabResourceKeyBrand: unique symbol;
12
+ /** Opaque key for the short browser acquisition actor. */
13
+ export type BrowserResourceKey = string & {
14
+ readonly [browserResourceKeyBrand]: "BrowserResourceKey";
15
+ };
16
+ /** Opaque key for the process-scoped tab actor. */
17
+ export type TabResourceKey = string & {
18
+ readonly [tabResourceKeyBrand]: "TabResourceKey";
19
+ };
20
+ export type CoordinatorResourceKind = "browser" | "tab";
21
+ export type CoordinatorPriority = "read" | "mutation" | "control";
22
+ export type CoordinatorOwner = Readonly<{
23
+ /** Backend process/session that owns this SDK call. */
24
+ backendSessionId: string;
25
+ /** Optional operation or caller id used only for diagnostics. */
26
+ ownerId?: string;
27
+ operationId?: string;
28
+ }>;
29
+ export type CoordinatorTimingDiagnostics = {
30
+ readonly requestId: string;
31
+ readonly resourceKind: CoordinatorResourceKind;
32
+ readonly resourceKey: string;
33
+ readonly priority: CoordinatorPriority;
34
+ readonly owner: CoordinatorOwner;
35
+ readonly label?: string;
36
+ readonly enqueuedAt: number;
37
+ readonly deadlineAt?: number;
38
+ startedAt?: number;
39
+ /** Time the hierarchical browser gate admitted the callback. */
40
+ admittedAt?: number;
41
+ settledAt?: number;
42
+ queueDelayMs?: number;
43
+ /** Time spent waiting at the parent browser gate after this actor started. */
44
+ admissionDelayMs?: number;
45
+ executionMs?: number;
46
+ totalMs?: number;
47
+ queuedCancellation?: boolean;
48
+ queuedDeadlineExceeded?: boolean;
49
+ aborted?: boolean;
50
+ deadlineExceededInFlight?: boolean;
51
+ quarantinedUntilSettled?: boolean;
52
+ outcome?: "fulfilled" | "rejected";
53
+ };
54
+ export type CoordinatorAcquisitionContext = Readonly<{
55
+ resourceKind: CoordinatorResourceKind;
56
+ resourceKey: string;
57
+ acquisitionToken: string;
58
+ owner: CoordinatorOwner;
59
+ priority: CoordinatorPriority;
60
+ signal: AbortSignal;
61
+ timing: CoordinatorTimingDiagnostics;
62
+ }>;
63
+ export type CoordinatorQueueDiagnostics = Readonly<{
64
+ resourceKind: CoordinatorResourceKind;
65
+ resourceKey: string;
66
+ queueDepth: number;
67
+ active: boolean;
68
+ activeRequestId?: string;
69
+ activeOwner?: CoordinatorOwner;
70
+ completedCount: number;
71
+ rejectedCount: number;
72
+ lastCompleted?: CoordinatorTimingDiagnostics;
73
+ lastRejected?: CoordinatorTimingDiagnostics;
74
+ /** Present while a deadline-aborted callback is still settling. */
75
+ quarantinedUntilSettled?: CoordinatorTimingDiagnostics;
76
+ /**
77
+ * The browser-level parent gate for tab diagnostics, or the gate backing a
78
+ * browser actor's own diagnostics. This is intentionally a detached
79
+ * summary: callers must not be able to mutate scheduler state through
80
+ * diagnostics.
81
+ */
82
+ browserGate?: CoordinatorBrowserGateDiagnostics;
83
+ }>;
84
+ export type CoordinatorBrowserGateDiagnostics = Readonly<{
85
+ resourceKind: "browser";
86
+ resourceKey: BrowserResourceKey;
87
+ queueDepth: number;
88
+ active: boolean;
89
+ activeSharedCount: number;
90
+ queuedExclusiveCount: number;
91
+ queuedSharedCount: number;
92
+ rejectedCount: number;
93
+ activeExclusiveRequestId?: string;
94
+ activeExclusiveOwner?: CoordinatorOwner;
95
+ }>;
96
+ export type CoordinatorRequestOptions = Readonly<{
97
+ owner: CoordinatorOwner;
98
+ priority?: CoordinatorPriority;
99
+ signal?: AbortSignal;
100
+ /** An absolute epoch-millisecond deadline. */
101
+ deadlineAt?: number;
102
+ /** A relative deadline. Cannot be combined with deadlineAt. */
103
+ timeoutMs?: number;
104
+ label?: string;
105
+ /** Explicit parent context for re-entry detection across async boundaries. */
106
+ acquisitionContext?: CoordinatorAcquisitionContext;
107
+ }>;
108
+ export type TabCoordinatorOptions = Readonly<{
109
+ /** Maximum number of queued (not active) calls per resource actor. */
110
+ maxQueueSize?: number;
111
+ /** Maximum consecutive reads before a waiting mutation is selected. */
112
+ maxConsecutiveReads?: number;
113
+ /** Maximum consecutive mutations before a waiting control is selected. */
114
+ maxConsecutiveMutations?: number;
115
+ /** Maximum consecutive controls before a waiting mutation is selected. */
116
+ maxConsecutiveControls?: number;
117
+ /** A waiting request older than this is selected by age, regardless of priority. */
118
+ maxWaitMs?: number;
119
+ /** Maximum consecutive browser-exclusive turns before a queued shared turn. */
120
+ maxConsecutiveBrowserExclusives?: number;
121
+ /** Maximum number of detached idle diagnostics retained for later inspection. */
122
+ maxIdleDiagnostics?: number;
123
+ now?: () => number;
124
+ }>;
125
+ export declare function createBrowserResourceKey(identity: StableBrowserIdentity): BrowserResourceKey;
126
+ export declare function createBrowserResourceKey(providerId: string, browserId: string): BrowserResourceKey;
127
+ export declare function createTabResourceKey(identity: StableTabIdentity): TabResourceKey;
128
+ export declare function createTabResourceKey(providerId: string, browserId: string, tabId: string): TabResourceKey;
129
+ export declare class CoordinatorError extends Error {
130
+ readonly code: string;
131
+ readonly diagnostics?: CoordinatorTimingDiagnostics | CoordinatorQueueDiagnostics;
132
+ constructor(code: string, message: string, diagnostics?: CoordinatorTimingDiagnostics | CoordinatorQueueDiagnostics);
133
+ }
134
+ export declare class InvalidResourceKeyError extends CoordinatorError {
135
+ constructor(message: string);
136
+ }
137
+ export declare class InvalidCoordinatorRequestError extends CoordinatorError {
138
+ constructor(message: string);
139
+ }
140
+ export declare class CoordinatorQueueFullError extends CoordinatorError {
141
+ constructor(diagnostics: CoordinatorQueueDiagnostics);
142
+ }
143
+ export type CoordinatorCancellationPhase = "queued" | "in_flight";
144
+ export declare class CoordinatorAbortedError extends CoordinatorError {
145
+ readonly phase: CoordinatorCancellationPhase;
146
+ constructor(phase: CoordinatorCancellationPhase, diagnostics: CoordinatorTimingDiagnostics);
147
+ }
148
+ export declare class CoordinatorDeadlineExceededError extends CoordinatorError {
149
+ readonly phase: CoordinatorCancellationPhase;
150
+ constructor(phase: CoordinatorCancellationPhase, diagnostics: CoordinatorTimingDiagnostics);
151
+ }
152
+ export declare class ReentrantAcquisitionError extends CoordinatorError {
153
+ readonly resourceKind: CoordinatorResourceKind;
154
+ readonly resourceKey: string;
155
+ constructor(context: CoordinatorAcquisitionContext);
156
+ }
157
+ type Callback<T, Context extends CoordinatorAcquisitionContext> = (context: Context) => T | PromiseLike<T>;
158
+ /**
159
+ * Process-local actors for short browser acquisition and tab transactions.
160
+ *
161
+ * The class intentionally coordinates only cooperating callers in this
162
+ * process. It does not advertise provider-level or cross-process tab
163
+ * concurrency; a provider claim/fencing capability must be integrated before
164
+ * those guarantees can be made. Callback code should perform one short
165
+ * browser operation. Polling, sleeps, journal I/O, hashing, and report work
166
+ * belong outside this API so no scheduler actor is held by those waits.
167
+ */
168
+ export declare class ProcessTabCoordinator {
169
+ private readonly browserActors;
170
+ private readonly tabActors;
171
+ private readonly browserGates;
172
+ private readonly idleDiagnostics;
173
+ private readonly options;
174
+ constructor(options?: TabCoordinatorOptions);
175
+ withBrowserAcquisition<T>(resourceKey: BrowserResourceKey, options: CoordinatorRequestOptions, callback: Callback<T, CoordinatorAcquisitionContext>): Promise<T>;
176
+ withTabTransaction<T>(resourceKey: TabResourceKey, options: CoordinatorRequestOptions, callback: Callback<T, CoordinatorAcquisitionContext>): Promise<T>;
177
+ getBrowserDiagnostics(resourceKey: BrowserResourceKey): CoordinatorQueueDiagnostics;
178
+ getTabDiagnostics(resourceKey: TabResourceKey): CoordinatorQueueDiagnostics;
179
+ private getActor;
180
+ private createActor;
181
+ private diagnosticsKey;
182
+ private emptyDiagnostics;
183
+ private onActorIdle;
184
+ private getBrowserGate;
185
+ private maybeCleanupGate;
186
+ private enqueue;
187
+ }
188
+ /** Explicit factory to make process/runtime ownership visible at call sites. */
189
+ export declare function createProcessTabCoordinator(options?: TabCoordinatorOptions): ProcessTabCoordinator;
190
+ /**
191
+ * Return the lifecycle-wide coordinator used by default SDK/runtime services.
192
+ *
193
+ * Constructing a coordinator per client would make each queue internally
194
+ * correct while allowing two clients in the same backend process to overlap
195
+ * on the same tab. Callers that need deterministic test limits may still
196
+ * inject an explicitly constructed coordinator; production integration should
197
+ * use this shared instance.
198
+ */
199
+ export declare function getProcessTabCoordinator(): ProcessTabCoordinator;
200
+ export {};