codex-chatgpt-control 0.5.1-alpha.2 → 0.5.1-alpha.3

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 (191) hide show
  1. package/CHANGELOG.md +15 -0
  2. package/README.md +27 -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/operation-action-prepared-event.json +42 -0
  7. package/contracts/v1/fixtures/operation-action.json +13 -0
  8. package/contracts/v1/fixtures/operation-artifact-receipt.json +14 -0
  9. package/contracts/v1/fixtures/operation-artifact-transfer-intent-event.json +24 -0
  10. package/contracts/v1/fixtures/operation-artifact-transfer-receipt-event.json +26 -0
  11. package/contracts/v1/fixtures/operation-artifact-transfer-state.json +178 -0
  12. package/contracts/v1/fixtures/operation-blocker.json +10 -0
  13. package/contracts/v1/fixtures/operation-collect-request.json +17 -0
  14. package/contracts/v1/fixtures/operation-collect-result.json +42 -0
  15. package/contracts/v1/fixtures/operation-control-receipt.json +13 -0
  16. package/contracts/v1/fixtures/operation-control-request.json +18 -0
  17. package/contracts/v1/fixtures/operation-control-result.json +31 -0
  18. package/contracts/v1/fixtures/operation-event.json +18 -0
  19. package/contracts/v1/fixtures/operation-handle.json +10 -0
  20. package/contracts/v1/fixtures/operation-inspect-request.json +13 -0
  21. package/contracts/v1/fixtures/operation-inspect-result.json +205 -0
  22. package/contracts/v1/fixtures/operation-ownership-baseline-event.json +34 -0
  23. package/contracts/v1/fixtures/operation-receipt.json +32 -0
  24. package/contracts/v1/fixtures/operation-recovery-decision.json +7 -0
  25. package/contracts/v1/fixtures/operation-recovery-observation.json +12 -0
  26. package/contracts/v1/fixtures/operation-request.json +33 -0
  27. package/contracts/v1/fixtures/operation-state.json +144 -0
  28. package/contracts/v1/fixtures/operation-submission-witness-event.json +20 -0
  29. package/contracts/v1/fixtures/operation-submission-witness.json +11 -0
  30. package/contracts/v1/fixtures/operation-submit-result.json +16 -0
  31. package/contracts/v1/fixtures/operation-target-established-event.json +21 -0
  32. package/contracts/v1/manifest.json +155 -1
  33. package/contracts/v1/parity-suite.json +96 -1
  34. package/contracts/v1/schemas/backend-compatibility.schema.json +65 -0
  35. package/contracts/v1/schemas/backend-request.schema.json +8 -2
  36. package/contracts/v1/schemas/capabilities.schema.json +81 -1
  37. package/contracts/v1/schemas/manifest.schema.json +57 -0
  38. package/contracts/v1/schemas/operation-action.schema.json +155 -0
  39. package/contracts/v1/schemas/operation-artifact-receipt.schema.json +89 -0
  40. package/contracts/v1/schemas/operation-blocker.schema.json +70 -0
  41. package/contracts/v1/schemas/operation-collect-request.schema.json +46 -0
  42. package/contracts/v1/schemas/operation-collect-result.schema.json +74 -0
  43. package/contracts/v1/schemas/operation-control-receipt.schema.json +108 -0
  44. package/contracts/v1/schemas/operation-control-request.schema.json +111 -0
  45. package/contracts/v1/schemas/operation-control-result.schema.json +112 -0
  46. package/contracts/v1/schemas/operation-event.schema.json +756 -0
  47. package/contracts/v1/schemas/operation-handle.schema.json +55 -0
  48. package/contracts/v1/schemas/operation-inspect-request.schema.json +42 -0
  49. package/contracts/v1/schemas/operation-inspect-result.schema.json +1662 -0
  50. package/contracts/v1/schemas/operation-receipt.schema.json +153 -0
  51. package/contracts/v1/schemas/operation-recovery.schema.json +314 -0
  52. package/contracts/v1/schemas/operation-request.schema.json +158 -0
  53. package/contracts/v1/schemas/operation-state.schema.json +691 -0
  54. package/contracts/v1/schemas/operation-submission-witness.schema.json +48 -0
  55. package/contracts/v1/schemas/operation-submit-result.schema.json +94 -0
  56. package/contracts/v1/surface-drift-policy.json +50 -0
  57. package/contracts/v1/vectors/operation-request-digest-v1.json +43 -0
  58. package/dist/codex-chatgpt-control-backend.mjs +43897 -9094
  59. package/dist/codex-chatgpt-control.bundle.mjs +46360 -10262
  60. package/dist/src/backend/client.d.ts +103 -2
  61. package/dist/src/backend/client.js +1436 -97
  62. package/dist/src/backend/compatibility.d.ts +12 -0
  63. package/dist/src/backend/compatibility.js +208 -0
  64. package/dist/src/backend/protocol.d.ts +84 -1
  65. package/dist/src/backend/protocol.js +31 -5
  66. package/dist/src/backend/runtime-identity.d.ts +10 -0
  67. package/dist/src/backend/runtime-identity.js +141 -0
  68. package/dist/src/backend/session.d.ts +10 -2
  69. package/dist/src/backend/session.js +478 -7
  70. package/dist/src/backend/stdio-server.d.ts +4 -1
  71. package/dist/src/backend/stdio-server.js +240 -28
  72. package/dist/src/browser/active-composer-file-input.d.ts +9 -0
  73. package/dist/src/browser/active-composer-file-input.js +33 -0
  74. package/dist/src/browser/attach.d.ts +4 -1
  75. package/dist/src/browser/attach.js +136 -28
  76. package/dist/src/browser/downloads.d.ts +2 -0
  77. package/dist/src/client.d.ts +38 -0
  78. package/dist/src/client.js +1222 -59
  79. package/dist/src/commands/configuration.js +13 -7
  80. package/dist/src/commands/doctor.d.ts +1 -1
  81. package/dist/src/commands/doctor.js +26 -3
  82. package/dist/src/commands/experience.js +35 -0
  83. package/dist/src/commands/files.js +4 -27
  84. package/dist/src/commands/modes.js +49 -17
  85. package/dist/src/commands/power-discovery.d.ts +130 -0
  86. package/dist/src/commands/power-discovery.js +627 -0
  87. package/dist/src/commands/project-sources.js +325 -31
  88. package/dist/src/commands/sequence.js +59 -32
  89. package/dist/src/commands/session.js +7 -2
  90. package/dist/src/commands/work.js +31 -0
  91. package/dist/src/errors.d.ts +9 -0
  92. package/dist/src/errors.js +22 -0
  93. package/dist/src/index.d.ts +6 -0
  94. package/dist/src/index.js +9 -0
  95. package/dist/src/operations/artifact-output.d.ts +69 -0
  96. package/dist/src/operations/artifact-output.js +1748 -0
  97. package/dist/src/operations/artifact-stream.d.ts +19 -0
  98. package/dist/src/operations/artifact-stream.js +35 -0
  99. package/dist/src/operations/artifact-transfer.d.ts +149 -0
  100. package/dist/src/operations/artifact-transfer.js +1312 -0
  101. package/dist/src/operations/browser-adapter.d.ts +161 -0
  102. package/dist/src/operations/browser-adapter.js +2023 -0
  103. package/dist/src/operations/browser-observation.d.ts +110 -0
  104. package/dist/src/operations/browser-observation.js +1208 -0
  105. package/dist/src/operations/browser-target.d.ts +103 -0
  106. package/dist/src/operations/browser-target.js +489 -0
  107. package/dist/src/operations/canonical.d.ts +4 -0
  108. package/dist/src/operations/canonical.js +412 -0
  109. package/dist/src/operations/chatgpt-runtime.d.ts +72 -0
  110. package/dist/src/operations/chatgpt-runtime.js +1150 -0
  111. package/dist/src/operations/client.d.ts +138 -0
  112. package/dist/src/operations/client.js +1143 -0
  113. package/dist/src/operations/collector.d.ts +195 -0
  114. package/dist/src/operations/collector.js +1039 -0
  115. package/dist/src/operations/control.d.ts +372 -0
  116. package/dist/src/operations/control.js +1498 -0
  117. package/dist/src/operations/file-identity.d.ts +33 -0
  118. package/dist/src/operations/file-identity.js +153 -0
  119. package/dist/src/operations/handle.d.ts +19 -0
  120. package/dist/src/operations/handle.js +727 -0
  121. package/dist/src/operations/index.d.ts +22 -0
  122. package/dist/src/operations/index.js +22 -0
  123. package/dist/src/operations/journal.d.ts +142 -0
  124. package/dist/src/operations/journal.js +1931 -0
  125. package/dist/src/operations/production-attachments.d.ts +116 -0
  126. package/dist/src/operations/production-attachments.js +1018 -0
  127. package/dist/src/operations/production-chatgpt-artifacts.d.ts +74 -0
  128. package/dist/src/operations/production-chatgpt-artifacts.js +1146 -0
  129. package/dist/src/operations/production-chatgpt-attachments.d.ts +71 -0
  130. package/dist/src/operations/production-chatgpt-attachments.js +1563 -0
  131. package/dist/src/operations/production-configuration.d.ts +42 -0
  132. package/dist/src/operations/production-configuration.js +1363 -0
  133. package/dist/src/operations/production-primitives.d.ts +53 -0
  134. package/dist/src/operations/production-primitives.js +1073 -0
  135. package/dist/src/operations/production-work-steer.d.ts +203 -0
  136. package/dist/src/operations/production-work-steer.js +1218 -0
  137. package/dist/src/operations/recovery.d.ts +80 -0
  138. package/dist/src/operations/recovery.js +174 -0
  139. package/dist/src/operations/runtime-adapter.d.ts +118 -0
  140. package/dist/src/operations/runtime-adapter.js +786 -0
  141. package/dist/src/operations/send-once.d.ts +224 -0
  142. package/dist/src/operations/send-once.js +1081 -0
  143. package/dist/src/operations/service.d.ts +281 -0
  144. package/dist/src/operations/service.js +2810 -0
  145. package/dist/src/operations/staging.d.ts +136 -0
  146. package/dist/src/operations/staging.js +630 -0
  147. package/dist/src/operations/state-machine.d.ts +29 -0
  148. package/dist/src/operations/state-machine.js +2047 -0
  149. package/dist/src/operations/submission.d.ts +423 -0
  150. package/dist/src/operations/submission.js +1676 -0
  151. package/dist/src/operations/turn-ownership.d.ts +202 -0
  152. package/dist/src/operations/turn-ownership.js +700 -0
  153. package/dist/src/operations/types.d.ts +454 -0
  154. package/dist/src/operations/types.js +20 -0
  155. package/dist/src/operations/wire-requests.d.ts +21 -0
  156. package/dist/src/operations/wire-requests.js +396 -0
  157. package/dist/src/operations/wire-results.d.ts +97 -0
  158. package/dist/src/operations/wire-results.js +818 -0
  159. package/dist/src/runner/responses.d.ts +3 -1
  160. package/dist/src/runner/responses.js +19 -1
  161. package/dist/src/runner/result.js +227 -55
  162. package/dist/src/runner/types.d.ts +12 -0
  163. package/dist/src/runtime/command-routing.d.ts +149 -0
  164. package/dist/src/runtime/command-routing.js +431 -0
  165. package/dist/src/runtime/coordinated-browser.d.ts +24 -0
  166. package/dist/src/runtime/coordinated-browser.js +315 -0
  167. package/dist/src/runtime/coordinated-page.d.ts +39 -0
  168. package/dist/src/runtime/coordinated-page.js +634 -0
  169. package/dist/src/runtime/operation-context.d.ts +142 -0
  170. package/dist/src/runtime/operation-context.js +410 -0
  171. package/dist/src/runtime/runtime-session.d.ts +95 -0
  172. package/dist/src/runtime/runtime-session.js +314 -0
  173. package/dist/src/runtime/tab-coordinator.d.ts +200 -0
  174. package/dist/src/runtime/tab-coordinator.js +1200 -0
  175. package/dist/src/runtime/value-boundaries.d.ts +18 -0
  176. package/dist/src/runtime/value-boundaries.js +49 -0
  177. package/dist/src/safety/untrusted-output.js +2 -1
  178. package/dist/src/scripts/backend-server.js +4 -1
  179. package/dist/src/scripts/live-smoke/harness.js +79 -7
  180. package/dist/src/scripts/live-smoke/scenarios.d.ts +28 -0
  181. package/dist/src/scripts/live-smoke/scenarios.js +110 -18
  182. package/dist/src/scripts/live-smoke/types.d.ts +3 -0
  183. package/dist/src/scripts/release-canary-module.js +17 -4
  184. package/dist/src/types.d.ts +38 -1
  185. package/package.json +1 -1
  186. package/references/2026-08-16-transactional-operations.md +459 -0
  187. package/references/agents-runner.md +34 -0
  188. package/references/backend-protocol.md +73 -0
  189. package/references/python-parity.md +72 -0
  190. package/references/responses-adapter.md +19 -0
  191. package/references/streaming.md +6 -0
@@ -0,0 +1,1363 @@
1
+ import { createHash } from "node:crypto";
2
+ import { localeLabels } from "../dom/locale-labels.js";
3
+ import { normalizeForLabelMatch, visibleLabelMatches } from "../dom/label-match.js";
4
+ import { discoverPowerSlider, observedPowerSlider, resolvePowerTarget } from "../commands/power-discovery.js";
5
+ import { isPlainDataRecord } from "../runtime/value-boundaries.js";
6
+ /**
7
+ * Provider-specific staging for the reversible configuration surfaces.
8
+ *
9
+ * The caller's configuration is copied into a request-scoped closure. It is
10
+ * never put into a callback result, an exception, a locator diagnostic, or a
11
+ * digest material object. The public staging protocol only carries keyed
12
+ * state/evidence digests and stable blocker codes.
13
+ */
14
+ const DIGEST_PATTERN = /^hmac-sha256:[0-9a-f]{64}$/u;
15
+ const ID_PATTERN = /^[A-Za-z0-9._:-]{1,512}$/u;
16
+ const MAX_CONFIGURATION_FIELDS = 8;
17
+ const MAX_DOM_CONTROLS = 256;
18
+ const MAX_CONTROL_LABEL_LENGTH = 512;
19
+ const MAX_CACHED_ACTIONS = 32;
20
+ const MAX_POWER_STEPS = 32;
21
+ export class ProductionConfigurationPrimitiveError extends Error {
22
+ code;
23
+ constructor(code) {
24
+ super("The provider configuration control could not prove the requested set-to-value action safely.");
25
+ this.name = "ProductionConfigurationPrimitiveError";
26
+ this.code = code;
27
+ }
28
+ }
29
+ /** Create one request-scoped production configuration staging primitive. */
30
+ export function createProductionConfigurationStaging(options) {
31
+ let captured;
32
+ try {
33
+ // Snapshot the provider options once, before validating or cloning any
34
+ // nested data. In particular, do not validate one read of a mutable
35
+ // options object and then capture a later read: a proxy/accessor must not
36
+ // be able to redirect the request after construction.
37
+ const raw = snapshotProductionOptions(options);
38
+ const configuration = copyConfiguration(raw.configuration);
39
+ validateOptions(raw, configuration);
40
+ captured = Object.freeze({
41
+ evidenceDigest: raw.evidenceDigest,
42
+ operationId: raw.operationId,
43
+ requestDigest: raw.requestDigest,
44
+ surface: raw.surface,
45
+ ...(configuration === undefined ? {} : { configuration })
46
+ });
47
+ }
48
+ catch (error) {
49
+ if (error instanceof ProductionConfigurationPrimitiveError)
50
+ throw error;
51
+ throw new ProductionConfigurationPrimitiveError("staging_request_mismatch");
52
+ }
53
+ const state = {
54
+ observations: new Map(),
55
+ attempted: new Set()
56
+ };
57
+ const primitive = Object.freeze({
58
+ readCurrent: request => readCurrent(request, captured, captured.configuration, state),
59
+ observe: request => readCurrent(request, captured, captured.configuration, state),
60
+ mutateOnce: request => mutateOnce(request, captured, captured.configuration, state)
61
+ });
62
+ return primitive;
63
+ }
64
+ /** Descriptive aliases for provider integrations that call this a primitive. */
65
+ export const createProductionConfigurationPrimitive = createProductionConfigurationStaging;
66
+ export const createOperationProductionConfigurationStaging = createProductionConfigurationStaging;
67
+ async function readCurrent(request, options, configuration, state) {
68
+ let input;
69
+ try {
70
+ input = normalizeRequest(request);
71
+ }
72
+ catch (error) {
73
+ return unavailableObservation(request, errorCode(error, "staging_request_mismatch"));
74
+ }
75
+ if (!matchesOperation(input.callback, options)) {
76
+ return unavailableObservation(input.callback, "staging_request_mismatch");
77
+ }
78
+ try {
79
+ const result = input.callback.kind === "power_select"
80
+ ? await observePower(input, options, configuration, state)
81
+ : await observeMenuSurface(input, options, configuration, state);
82
+ return result;
83
+ }
84
+ catch (error) {
85
+ const code = errorCode(error, fallbackUnavailableCode(input.callback.kind));
86
+ return unavailableObservation(input.callback, code);
87
+ }
88
+ }
89
+ async function mutateOnce(request, options, configuration, state) {
90
+ let input;
91
+ try {
92
+ input = normalizeRequest(request);
93
+ if (!matchesOperation(input.callback, options)) {
94
+ throw new ProductionConfigurationPrimitiveError("staging_request_mismatch");
95
+ }
96
+ const { callback, key } = input;
97
+ const previous = state.observations.get(key);
98
+ if (previous === undefined) {
99
+ throw new ProductionConfigurationPrimitiveError("staging_observation_required");
100
+ }
101
+ if (state.attempted.has(key)) {
102
+ throw new ProductionConfigurationPrimitiveError("staging_mutation_already_attempted");
103
+ }
104
+ if (callback.kind === "power_select") {
105
+ return await mutatePower(input, options, configuration, state, previous);
106
+ }
107
+ return await mutateMenuSurface(input, options, configuration, state, previous);
108
+ }
109
+ catch (error) {
110
+ if (error instanceof ProductionConfigurationPrimitiveError)
111
+ throw error;
112
+ const kind = inputOrKind(request);
113
+ throw new ProductionConfigurationPrimitiveError(kind === "power_select" ? "power_state_drift" : kind === "tool_set" ? "tool_state_drift" : "configuration_state_drift");
114
+ }
115
+ }
116
+ function inputOrKind(request) {
117
+ const kind = readOwnDataProperty(request, "kind");
118
+ return kind === "configuration_set" || kind === "tool_set" || kind === "power_select" ? kind : "unknown";
119
+ }
120
+ async function observeMenuSurface(input, options, configuration, state) {
121
+ const { callback, key } = input;
122
+ const kind = callback.kind;
123
+ const needed = requestedValues(configuration, kind);
124
+ if (needed === undefined) {
125
+ return rememberAndReturn(state, key, {
126
+ kind,
127
+ status: "unavailable"
128
+ }, unavailableObservation(callback, kind === "tool_set" ? "tool_not_configured" : "configuration_not_configured"));
129
+ }
130
+ const snapshot = await discoverMenuSnapshot(callback.page, options.surface);
131
+ const stateResult = evaluateMenuState(snapshot, kind, needed, options.surface);
132
+ const currentStateDigest = stateResult.currentStateDigest === undefined
133
+ ? undefined
134
+ : keyedStateDigest(options.evidenceDigest, callback, kind, stateResult.currentStateDigest);
135
+ const digest = observationDigest(options.evidenceDigest, callback, snapshot, stateResult.status);
136
+ const observation = stateResult.status === "satisfied"
137
+ ? satisfiedObservation(callback, currentStateDigest, digest)
138
+ : stateResult.status === "not_satisfied"
139
+ ? notSatisfiedObservation(callback, currentStateDigest, digest)
140
+ : unavailableObservation(callback, stateResult.blockerCode, currentStateDigest, digest);
141
+ const afterAttempt = state.attempted.has(key);
142
+ const final = afterAttempt && observation.status !== "satisfied"
143
+ ? uncertainObservation(callback, "staging_mutation_unreconciled", currentStateDigest, digest)
144
+ : observation;
145
+ return rememberAndReturn(state, key, { kind, snapshot, status: final.status }, final);
146
+ }
147
+ async function observePower(input, options, configuration, state) {
148
+ const { callback, key } = input;
149
+ const requested = requestedValues(configuration, callback.kind);
150
+ if (requested === undefined || requested.length !== 1) {
151
+ return rememberAndReturn(state, key, {
152
+ kind: callback.kind,
153
+ status: "unavailable"
154
+ }, unavailableObservation(callback, "power_not_configured"));
155
+ }
156
+ const discovery = await discoverPowerSlider(callback.page, {
157
+ powerLabels: localeLabels.configurationAxes.power,
158
+ expectedSurface: options.surface
159
+ });
160
+ if (!discovery.ok) {
161
+ const blocker = discovery.reason === "surface_mismatch"
162
+ ? "power_surface_unsupported"
163
+ : discovery.reason === "no_visible_slider" || discovery.reason === "no_semantic_power_slider"
164
+ ? "power_surface_unavailable"
165
+ : discovery.reason === "unsupported_range" || discovery.reason === "invalid_aria_range" || discovery.reason === "missing_menu_relationship"
166
+ ? "power_mapping_incomplete"
167
+ : "power_surface_unavailable";
168
+ if (state.attempted.has(key)) {
169
+ return rememberAndReturn(state, key, { kind: callback.kind, status: "uncertain" }, uncertainObservation(callback, "power_restoration_required"));
170
+ }
171
+ return rememberAndReturn(state, key, { kind: callback.kind, status: "unavailable" }, unavailableObservation(callback, blocker));
172
+ }
173
+ const requestedLabels = valueAliases("power", requested[0].value);
174
+ const target = resolvePowerTarget(discovery, requestedLabels);
175
+ const satisfied = target !== undefined && discovery.range.current === target;
176
+ const mappingComplete = target !== undefined || discovery.valueText !== undefined && requestedLabels.some(label => labelsMatch(discovery.valueText, label));
177
+ if (!mappingComplete) {
178
+ if (state.attempted.has(key)) {
179
+ return rememberAndReturn(state, key, {
180
+ kind: callback.kind,
181
+ power: discovery,
182
+ powerSignature: powerSignature(discovery),
183
+ status: "uncertain"
184
+ }, uncertainObservation(callback, "power_restoration_required"));
185
+ }
186
+ return rememberAndReturn(state, key, {
187
+ kind: callback.kind,
188
+ power: discovery,
189
+ powerSignature: powerSignature(discovery),
190
+ status: "unavailable"
191
+ }, unavailableObservation(callback, "power_mapping_incomplete"));
192
+ }
193
+ const currentDigest = keyedStateDigest(options.evidenceDigest, callback, "power", powerSignature(discovery));
194
+ const evidence = safeDigest(options.evidenceDigest, "configuration-staging-observation", {
195
+ operationId: callback.operationId,
196
+ targetBindingDigest: callback.targetBindingDigest,
197
+ kind: callback.kind,
198
+ status: satisfied ? "satisfied" : "not_satisfied",
199
+ current: currentDigest,
200
+ power: powerSignature(discovery)
201
+ });
202
+ const observation = satisfied
203
+ ? satisfiedObservation(callback, currentDigest, evidence)
204
+ : notSatisfiedObservation(callback, currentDigest, evidence);
205
+ const final = state.attempted.has(key) && observation.status !== "satisfied"
206
+ ? uncertainObservation(callback, "power_restoration_required", currentDigest, evidence)
207
+ : observation;
208
+ return rememberAndReturn(state, key, {
209
+ kind: callback.kind,
210
+ power: discovery,
211
+ powerSignature: powerSignature(discovery),
212
+ status: final.status
213
+ }, final);
214
+ }
215
+ async function mutateMenuSurface(input, options, configuration, state, previous) {
216
+ const { callback, key } = input;
217
+ const needed = requestedValues(configuration, callback.kind);
218
+ if (needed === undefined) {
219
+ throw new ProductionConfigurationPrimitiveError(callback.kind === "tool_set" ? "tool_not_configured" : "configuration_not_configured");
220
+ }
221
+ const snapshot = await discoverMenuSnapshot(callback.page, options.surface);
222
+ const evaluated = evaluateMenuState(snapshot, callback.kind, needed, options.surface);
223
+ if (evaluated.status === "satisfied") {
224
+ // A concurrent actor/user may have satisfied the value after the last
225
+ // observation. Do not issue a redundant browser action.
226
+ remember(state, key, { kind: callback.kind, snapshot, status: "satisfied" });
227
+ return { status: "started" };
228
+ }
229
+ if (evaluated.status === "unavailable") {
230
+ throw new ProductionConfigurationPrimitiveError(evaluated.blockerCode);
231
+ }
232
+ if (previous.snapshot === undefined || previous.snapshot.signature !== snapshot.signature) {
233
+ throw new ProductionConfigurationPrimitiveError(callback.kind === "tool_set" ? "tool_state_drift" : "configuration_state_drift");
234
+ }
235
+ for (const requested of needed) {
236
+ const aliases = callback.kind === "tool_set"
237
+ ? toolAliases(requested.value)
238
+ : valueAliases("configuration", requested.value);
239
+ if (findTarget(snapshot, aliases, callback.kind).status === "ambiguous") {
240
+ throw new ProductionConfigurationPrimitiveError(callback.kind === "tool_set"
241
+ ? "tool_selection_ambiguous"
242
+ : "configuration_control_ambiguous");
243
+ }
244
+ }
245
+ const plan = buildMenuPlan(snapshot, callback.kind, needed, options.surface);
246
+ if (plan.length === 0) {
247
+ throw new ProductionConfigurationPrimitiveError(callback.kind === "tool_set" ? "tool_option_unavailable" : "configuration_option_unavailable");
248
+ }
249
+ state.attempted.add(key);
250
+ trimState(state);
251
+ // Every click below is part of this one bounded plan. Re-discover each
252
+ // distinct set-to-value step because a selection can close/rebuild its
253
+ // menu. Once a click rejects, there is no alternate locator or retry.
254
+ for (const step of plan) {
255
+ const current = await discoverMenuSnapshot(callback.page, options.surface);
256
+ const currentState = evaluateMenuState(current, callback.kind, [step.requested], options.surface);
257
+ if (currentState.status === "satisfied")
258
+ continue;
259
+ if (currentState.status === "unavailable") {
260
+ throw new ProductionConfigurationPrimitiveError(currentState.blockerCode);
261
+ }
262
+ const aliases = callback.kind === "tool_set"
263
+ ? toolAliases(step.requested.value)
264
+ : valueAliases("configuration", step.requested.value);
265
+ const target = findTarget(current, aliases, callback.kind);
266
+ if (target.status === "ambiguous") {
267
+ throw new ProductionConfigurationPrimitiveError(callback.kind === "tool_set" ? "tool_selection_ambiguous" : "configuration_control_ambiguous");
268
+ }
269
+ if (target.status === "found") {
270
+ await clickControl(callback.page, target.control);
271
+ continue;
272
+ }
273
+ const opener = findUniqueOpener(current, callback.kind, options.surface);
274
+ if (opener === undefined) {
275
+ throw new ProductionConfigurationPrimitiveError(callback.kind === "tool_set" ? "tool_option_unavailable" : "configuration_option_unavailable");
276
+ }
277
+ await clickControl(callback.page, opener);
278
+ const afterOpen = await discoverMenuSnapshot(callback.page, options.surface);
279
+ const targetAfterOpen = findTarget(afterOpen, aliases, callback.kind);
280
+ if (targetAfterOpen.status === "ambiguous") {
281
+ throw new ProductionConfigurationPrimitiveError(callback.kind === "tool_set" ? "tool_selection_ambiguous" : "configuration_control_ambiguous");
282
+ }
283
+ if (targetAfterOpen.status !== "found") {
284
+ throw new ProductionConfigurationPrimitiveError(callback.kind === "tool_set" ? "tool_option_unavailable" : "configuration_option_unavailable");
285
+ }
286
+ await clickControl(callback.page, targetAfterOpen.control);
287
+ }
288
+ return { status: "started" };
289
+ }
290
+ async function mutatePower(input, options, configuration, state, previous) {
291
+ const { callback, key } = input;
292
+ const requested = requestedValues(configuration, callback.kind);
293
+ if (requested === undefined || requested.length !== 1) {
294
+ throw new ProductionConfigurationPrimitiveError("power_not_configured");
295
+ }
296
+ const discovery = await discoverPowerSlider(callback.page, {
297
+ powerLabels: localeLabels.configurationAxes.power,
298
+ expectedSurface: options.surface
299
+ });
300
+ if (!discovery.ok)
301
+ throw new ProductionConfigurationPrimitiveError("power_surface_unavailable");
302
+ const target = resolvePowerTarget(discovery, valueAliases("power", requested[0].value));
303
+ if (target === undefined)
304
+ throw new ProductionConfigurationPrimitiveError("power_mapping_incomplete");
305
+ if (previous.power === undefined || previous.powerSignature === undefined
306
+ || previous.powerSignature !== powerSignature(discovery)) {
307
+ if (discovery.range.current === target) {
308
+ remember(state, key, { kind: callback.kind, power: discovery, powerSignature: powerSignature(discovery), status: "satisfied" });
309
+ return { status: "started" };
310
+ }
311
+ throw new ProductionConfigurationPrimitiveError("power_state_drift");
312
+ }
313
+ if (discovery.range.current === target) {
314
+ remember(state, key, { kind: callback.kind, power: discovery, powerSignature: powerSignature(discovery), status: "satisfied" });
315
+ return { status: "started" };
316
+ }
317
+ const slider = observedPowerSlider(callback.page, discovery);
318
+ if (slider === undefined || slider.count === undefined || slider.press === undefined || slider.isVisible === undefined) {
319
+ throw new ProductionConfigurationPrimitiveError("power_control_unavailable");
320
+ }
321
+ if (await slider.count().catch(() => 0) !== 1 || !await slider.isVisible().catch(() => false)) {
322
+ throw new ProductionConfigurationPrimitiveError("power_control_unavailable");
323
+ }
324
+ if (slider.evaluate === undefined)
325
+ throw new ProductionConfigurationPrimitiveError("power_control_unavailable");
326
+ const aria = await slider.evaluate(element => ({
327
+ minimum: element.getAttribute("aria-valuemin"),
328
+ maximum: element.getAttribute("aria-valuemax"),
329
+ current: element.getAttribute("aria-valuenow")
330
+ })).catch(() => undefined);
331
+ if (aria === undefined || Number(aria.minimum) !== discovery.range.minimum
332
+ || Number(aria.maximum) !== discovery.range.maximum || Number(aria.current) !== discovery.range.current) {
333
+ throw new ProductionConfigurationPrimitiveError("power_state_drift");
334
+ }
335
+ const distance = Math.abs(target - discovery.range.current);
336
+ if (!Number.isInteger(distance) || distance < 1 || distance > MAX_POWER_STEPS) {
337
+ throw new ProductionConfigurationPrimitiveError("power_mapping_incomplete");
338
+ }
339
+ state.attempted.add(key);
340
+ trimState(state);
341
+ const direction = target > discovery.range.current ? "ArrowRight" : "ArrowLeft";
342
+ for (let index = 0; index < distance; index += 1) {
343
+ // No wait/poll is permitted while the coordinated tab actor is held.
344
+ await slider.press(direction);
345
+ }
346
+ return { status: "started" };
347
+ }
348
+ function buildMenuPlan(snapshot, kind, needed, surface) {
349
+ const plan = [];
350
+ for (const requested of needed) {
351
+ const aliases = kind === "tool_set"
352
+ ? toolAliases(requested.value)
353
+ : valueAliases("configuration", requested.value);
354
+ const target = findTarget(snapshot, aliases, kind);
355
+ if (target.status === "ambiguous")
356
+ return [];
357
+ if (target.status === "found") {
358
+ plan.push({ requested });
359
+ continue;
360
+ }
361
+ const opener = findUniqueOpener(snapshot, kind, surface);
362
+ if (opener === undefined)
363
+ return [];
364
+ plan.push({ requested });
365
+ }
366
+ return plan;
367
+ }
368
+ function findTarget(snapshot, aliases, kind) {
369
+ const allCandidates = snapshot.controls.filter(control => control.visible
370
+ && (kind === "tool_set" ? control.menuKey !== undefined : true)
371
+ && aliases.some(alias => labelsMatch(control.label, alias)));
372
+ const menuCandidates = allCandidates.filter(control => control.menuKey !== undefined);
373
+ const candidates = menuCandidates.length > 0 ? menuCandidates : allCandidates;
374
+ if (candidates.length === 0)
375
+ return { status: "absent" };
376
+ if (candidates.length !== 1 || candidates[0] === undefined)
377
+ return { status: "ambiguous" };
378
+ return { status: "found", control: candidates[0] };
379
+ }
380
+ function findUniqueOpener(snapshot, kind, surface) {
381
+ const candidates = snapshot.controls.filter(control => control.visible
382
+ && control.menuKey === undefined
383
+ && (kind === "tool_set"
384
+ // The transactional primitive requires the provider's structural plus
385
+ // control. Localized visible text alone is not enough to prove that a
386
+ // button opens the tool menu (it may be an attachment or project action).
387
+ ? control.id === "composer-plus-btn" || control.testId === "composer-plus-btn"
388
+ : /model-switcher|model-selector|mode-selector|configuration/i.test(`${control.testId ?? ""} ${control.id ?? ""}`)
389
+ || labelsMatchAny(control.label, surface === "work"
390
+ ? [...localeLabels.configurationOptions.light, ...localeLabels.configurationOptions.medium, ...localeLabels.configurationOptions.high, ...localeLabels.configurationOptions.standard, ...localeLabels.configurationOptions.fast]
391
+ : [...localeLabels.modeLabels, ...localeLabels.configurationOptions.instant, ...localeLabels.configurationOptions.medium, ...localeLabels.configurationOptions.high, ...localeLabels.configurationOptions.extraHigh, ...localeLabels.configurationOptions.pro])));
392
+ return candidates.length === 1 ? candidates[0] : undefined;
393
+ }
394
+ function evaluateMenuState(snapshot, kind, needed, surface) {
395
+ if (snapshot.surface === "unknown") {
396
+ return { status: "unavailable", blockerCode: kind === "tool_set" ? "tool_surface_unavailable" : "configuration_surface_unavailable" };
397
+ }
398
+ if (snapshot.surface !== surface) {
399
+ return { status: "unavailable", blockerCode: kind === "tool_set" ? "tool_surface_unsupported" : "configuration_surface_unsupported" };
400
+ }
401
+ if (snapshot.controls.length === 0) {
402
+ return { status: "unavailable", blockerCode: kind === "tool_set" ? "tool_surface_unavailable" : "configuration_surface_unavailable" };
403
+ }
404
+ if (needed.length > MAX_CONFIGURATION_FIELDS) {
405
+ return { status: "unavailable", blockerCode: "configuration_observation_limit_exceeded" };
406
+ }
407
+ if (kind === "tool_set") {
408
+ if (needed.length !== 1)
409
+ return { status: "unavailable", blockerCode: "tool_selection_ambiguous" };
410
+ const selected = snapshot.controls.filter(control => control.visible && control.selected
411
+ && labelsMatchAny(control.label, toolAliases(needed[0].value)));
412
+ const selectedTools = snapshot.controls.filter(control => control.visible && control.selected
413
+ && isToolLabel(control.label));
414
+ if (selectedTools.length === 0) {
415
+ return { status: "unavailable", blockerCode: "tool_state_unavailable" };
416
+ }
417
+ const currentStateDigest = opaqueStateDigest(snapshot, selectedTools.map(control => control.label));
418
+ const result = {
419
+ status: selected.length === 1 && selectedTools.length === 1 ? "satisfied" : "not_satisfied",
420
+ blockerCode: "tool_state_unavailable"
421
+ };
422
+ if (currentStateDigest !== undefined)
423
+ result.currentStateDigest = currentStateDigest;
424
+ return result;
425
+ }
426
+ const values = new Map();
427
+ for (const control of snapshot.controls) {
428
+ const axis = axisForControl(control.label);
429
+ if (axis === undefined)
430
+ continue;
431
+ const value = axisValue(control.label, axis);
432
+ if (value === undefined)
433
+ continue;
434
+ const current = values.get(axis) ?? [];
435
+ current.push(value);
436
+ values.set(axis, current);
437
+ }
438
+ const selectedValues = snapshot.controls
439
+ .filter(control => control.visible && control.selected)
440
+ .map(control => control.label)
441
+ .filter(label => !isToolLabel(label));
442
+ const unknown = [...needed].some(requested => {
443
+ if (requested.key === "experience")
444
+ return snapshot.surface === "unknown";
445
+ const axes = axesForDesired(requested.value, requested.axes, configurationForKind(kind));
446
+ const hasAxisValue = axes.some(axis => (values.get(axis)?.length ?? 0) > 0);
447
+ const hasSelectedValue = selectedValues.some(value => labelsMatchAny(value, valueAliases("configuration", requested.value)));
448
+ return axes.length === 0 || (!hasAxisValue && !hasSelectedValue);
449
+ });
450
+ if (unknown) {
451
+ return { status: "unavailable", blockerCode: "configuration_control_ambiguous" };
452
+ }
453
+ const matches = needed.every(requested => {
454
+ if (requested.key === "experience")
455
+ return snapshot.surface === requested.value;
456
+ const axes = axesForDesired(requested.value, requested.axes, configurationForKind(kind));
457
+ return axes.some(axis => {
458
+ const current = values.get(axis) ?? [];
459
+ return current.length === 1 && labelsMatchAny(current[0], valueAliases("configuration", requested.value));
460
+ }) || selectedValues.filter(value => labelsMatchAny(value, valueAliases("configuration", requested.value))).length === 1;
461
+ });
462
+ const currentValues = [...values.entries()].flatMap(([axis, current]) => current.map(value => `${axis}:${value}`));
463
+ const result = {
464
+ status: matches ? "satisfied" : "not_satisfied",
465
+ blockerCode: "configuration_control_ambiguous"
466
+ };
467
+ const currentStateDigest = opaqueStateDigest(snapshot, currentValues);
468
+ if (currentStateDigest !== undefined)
469
+ result.currentStateDigest = currentStateDigest;
470
+ return result;
471
+ }
472
+ function configurationForKind(kind) {
473
+ return kind === "tool_set" ? "tool" : "configuration";
474
+ }
475
+ function axesForDesired(desired, explicitAxes, _kind) {
476
+ if (explicitAxes.length > 0)
477
+ return [...explicitAxes];
478
+ const normalized = normalizeForLabelMatch(desired);
479
+ if (normalized === "model" || normalized.startsWith("gpt ") || normalized.startsWith("gpt-"))
480
+ return ["model", "modelVersion"];
481
+ if (normalized === "model version")
482
+ return ["modelVersion"];
483
+ if (normalized === "reasoning" || normalized === "power")
484
+ return ["power"];
485
+ if (localeLabels.configurationAxes.intelligence.some(label => labelsMatch(desired, label))
486
+ || localeLabels.configurationAxes.effort.some(label => labelsMatch(desired, label)))
487
+ return ["intelligence", "effort"];
488
+ if (localeLabels.configurationAxes.speed.some(label => labelsMatch(desired, label)))
489
+ return ["speed"];
490
+ return ["intelligence", "effort", "speed", "model", "modelVersion"];
491
+ }
492
+ function requestedValues(configuration, kind) {
493
+ if (configuration === undefined)
494
+ return undefined;
495
+ if (kind === "tool_set") {
496
+ const tools = configuration.tools;
497
+ return tools === undefined ? undefined : tools.map(value => ({ key: "tool", value, axes: [] }));
498
+ }
499
+ if (kind === "power_select") {
500
+ return configuration.reasoning === undefined ? undefined : [{ key: "reasoning", value: configuration.reasoning, axes: ["power"] }];
501
+ }
502
+ const values = [];
503
+ if (configuration.experience !== undefined)
504
+ values.push({ key: "experience", value: configuration.experience, axes: ["surface"] });
505
+ if (configuration.model !== undefined)
506
+ values.push({ key: "model", value: configuration.model, axes: ["model"] });
507
+ if (configuration.modelVersion !== undefined)
508
+ values.push({ key: "modelVersion", value: configuration.modelVersion, axes: ["modelVersion"] });
509
+ if (configuration.mode !== undefined)
510
+ values.push({ key: "mode", value: configuration.mode, axes: ["intelligence", "effort"] });
511
+ if (configuration.additional !== undefined) {
512
+ const additional = configuration.additional;
513
+ for (const [key, value] of Object.entries(additional)) {
514
+ if (!["intelligence", "effort", "speed"].includes(key) || typeof value !== "string")
515
+ return undefined;
516
+ values.push({ key, value, axes: [key] });
517
+ }
518
+ }
519
+ return values.length === 0 ? undefined : values;
520
+ }
521
+ function valueAliases(kind, desired) {
522
+ const values = new Set([desired]);
523
+ if (kind === "tool") {
524
+ for (const aliases of Object.values(localeLabels.tools)) {
525
+ if (aliases.some(alias => labelsMatch(alias, desired)))
526
+ aliases.forEach(alias => values.add(alias));
527
+ }
528
+ }
529
+ else if (kind === "power") {
530
+ for (const aliases of [
531
+ ...Object.values(localeLabels.configurationOptions),
532
+ ...Object.values(localeLabels.modeOptions)
533
+ ]) {
534
+ if (aliases.some(alias => labelsMatch(alias, desired)))
535
+ aliases.forEach(alias => values.add(alias));
536
+ }
537
+ }
538
+ else {
539
+ for (const aliases of [
540
+ ...Object.values(localeLabels.configurationOptions),
541
+ ...Object.values(localeLabels.modeOptions)
542
+ ]) {
543
+ if (aliases.some(alias => labelsMatch(alias, desired)))
544
+ aliases.forEach(alias => values.add(alias));
545
+ }
546
+ }
547
+ // Power discovery deliberately bounds the locale label set. Keep the
548
+ // caller's canonical value first, then the first observed translations; an
549
+ // unbounded locale expansion must never disable a proven selector.
550
+ return [...values].slice(0, 64);
551
+ }
552
+ function toolAliases(desired) {
553
+ const aliases = localeLabels.tools[desired];
554
+ return aliases === undefined ? valueAliases("tool", desired) : [desired, ...aliases];
555
+ }
556
+ function isToolLabel(label) {
557
+ return Object.values(localeLabels.tools).some(aliases => aliases.some(alias => labelsMatch(label, alias)));
558
+ }
559
+ function axisForControl(label) {
560
+ for (const [axis, aliases] of Object.entries(localeLabels.configurationAxes)) {
561
+ if (aliases.some(alias => {
562
+ const normalized = normalizeForLabelMatch(label);
563
+ const wanted = normalizeForLabelMatch(alias);
564
+ return normalized === wanted || normalized.startsWith(`${wanted} `);
565
+ }))
566
+ return axis;
567
+ }
568
+ return undefined;
569
+ }
570
+ function axisValue(label, axis) {
571
+ const aliases = localeLabels.configurationAxes[axis] ?? [];
572
+ const normalized = normalizeForLabelMatch(label);
573
+ for (const alias of aliases) {
574
+ const wanted = normalizeForLabelMatch(alias);
575
+ if (normalized === wanted)
576
+ return undefined;
577
+ if (normalized.startsWith(`${wanted} `))
578
+ return label.slice(alias.length).trim();
579
+ }
580
+ return undefined;
581
+ }
582
+ function labelsMatchAny(label, wanted) {
583
+ return wanted.some(candidate => labelsMatch(label, candidate));
584
+ }
585
+ function labelsMatch(label, wanted) {
586
+ const left = normalizeForLabelMatch(label);
587
+ const right = normalizeForLabelMatch(wanted);
588
+ return left === right || visibleLabelMatches(label, wanted);
589
+ }
590
+ async function discoverMenuSnapshot(page, surface) {
591
+ if (typeof page.evaluate !== "function") {
592
+ throw new ProductionConfigurationPrimitiveError("configuration_surface_unavailable");
593
+ }
594
+ const value = await page.evaluate((config) => {
595
+ const normalize = (input) => input.replace(/\s+/g, " ").trim().slice(0, 512);
596
+ const elementParent = (node) => {
597
+ const parent = node.parentNode;
598
+ return parent?.nodeType === 1 ? parent : null;
599
+ };
600
+ const simpleMatch = (element, rawToken) => {
601
+ const checked = rawToken.endsWith(":checked");
602
+ const token = checked ? rawToken.slice(0, -":checked".length) : rawToken;
603
+ let offset = 0;
604
+ const tag = /^[A-Za-z][A-Za-z0-9-]*/u.exec(token);
605
+ if (tag !== null) {
606
+ if (element.tagName.toLocaleLowerCase() !== tag[0].toLocaleLowerCase())
607
+ return false;
608
+ offset = tag[0].length;
609
+ }
610
+ while (offset < token.length) {
611
+ if (token[offset] !== "[")
612
+ return false;
613
+ const close = token.indexOf("]", offset + 1);
614
+ if (close < 0)
615
+ return false;
616
+ const expression = token.slice(offset + 1, close).trim();
617
+ const attribute = /^([A-Za-z0-9_:-]+)(?:(\*=|=)'([^']*)'(?:\s+(i))?)?$/u.exec(expression);
618
+ if (attribute === null)
619
+ return false;
620
+ const actual = element.getAttribute(attribute[1]);
621
+ if (attribute[2] === undefined) {
622
+ if (actual === null)
623
+ return false;
624
+ }
625
+ else {
626
+ if (actual === null)
627
+ return false;
628
+ const insensitive = attribute[4] === "i";
629
+ const left = insensitive ? actual.toLocaleLowerCase() : actual;
630
+ const rightValue = attribute[3] ?? "";
631
+ const right = insensitive ? rightValue.toLocaleLowerCase() : rightValue;
632
+ if (attribute[2] === "=" ? left !== right : !left.includes(right))
633
+ return false;
634
+ }
635
+ offset = close + 1;
636
+ }
637
+ if (checked && element.checked !== true && !element.hasAttribute("checked"))
638
+ return false;
639
+ return true;
640
+ };
641
+ const selectorTokens = (branch) => {
642
+ const tokens = [];
643
+ let depth = 0;
644
+ let start = 0;
645
+ for (let index = 0; index <= branch.length; index += 1) {
646
+ const character = branch[index];
647
+ if (character === "[")
648
+ depth += 1;
649
+ if (character === "]")
650
+ depth -= 1;
651
+ if ((character === undefined || /\s/u.test(character)) && depth === 0) {
652
+ const token = branch.slice(start, index).trim();
653
+ if (token.length > 0)
654
+ tokens.push(token);
655
+ start = index + 1;
656
+ }
657
+ }
658
+ return tokens;
659
+ };
660
+ const selectorMatch = (element, selector) => {
661
+ for (const rawBranch of selector.split(",")) {
662
+ const tokens = selectorTokens(rawBranch.trim());
663
+ if (tokens.length === 0 || !simpleMatch(element, tokens[tokens.length - 1]))
664
+ continue;
665
+ let ancestor = elementParent(element);
666
+ let tokenIndex = tokens.length - 2;
667
+ while (tokenIndex >= 0) {
668
+ while (ancestor !== null && !simpleMatch(ancestor, tokens[tokenIndex])) {
669
+ ancestor = elementParent(ancestor);
670
+ }
671
+ if (ancestor === null)
672
+ break;
673
+ tokenIndex -= 1;
674
+ ancestor = elementParent(ancestor);
675
+ }
676
+ if (tokenIndex < 0)
677
+ return true;
678
+ }
679
+ return false;
680
+ };
681
+ const boundedQuery = (root, selector, maxMatched, maxVisited = 4096) => {
682
+ const matches = [];
683
+ let visited = 0;
684
+ let current = root.firstChild;
685
+ while (current !== null) {
686
+ visited += 1;
687
+ if (visited > maxVisited)
688
+ throw new Error("node limit exceeded");
689
+ const element = current.nodeType === 1 ? current : undefined;
690
+ if (element !== undefined && selectorMatch(element, selector)) {
691
+ matches.push(element);
692
+ if (matches.length > maxMatched)
693
+ throw new Error("node limit exceeded");
694
+ }
695
+ if (current.firstChild !== null) {
696
+ current = current.firstChild;
697
+ continue;
698
+ }
699
+ while (current !== null && current !== root && current.nextSibling === null)
700
+ current = current.parentNode;
701
+ current = current === null || current === root ? null : current.nextSibling;
702
+ }
703
+ return matches;
704
+ };
705
+ const boundedText = (node) => {
706
+ const chunks = [];
707
+ const ancestors = [];
708
+ let visited = 0;
709
+ let total = 0;
710
+ let current = node;
711
+ while (current !== null) {
712
+ visited += 1;
713
+ if (visited > 4096)
714
+ throw new Error("node limit exceeded");
715
+ if (current.nodeType === 3) {
716
+ const value = current.nodeValue ?? "";
717
+ total += value.length;
718
+ if (total > 512)
719
+ throw new Error("text limit exceeded");
720
+ if (value.length > 0)
721
+ chunks.push(value);
722
+ }
723
+ const child = current.firstChild;
724
+ if (child !== null) {
725
+ if (ancestors.length >= 4096)
726
+ throw new Error("node limit exceeded");
727
+ ancestors.push(current);
728
+ current = child;
729
+ continue;
730
+ }
731
+ while (current !== null && current !== node && current.nextSibling === null) {
732
+ current = ancestors.pop() ?? null;
733
+ }
734
+ if (current === node)
735
+ break;
736
+ if (current !== null)
737
+ current = current.nextSibling;
738
+ }
739
+ return chunks.join("").replace(/\s+/g, " ").trim().slice(0, 512);
740
+ };
741
+ const visible = (node) => {
742
+ let current = node;
743
+ let depth = 0;
744
+ while (current !== null && depth < 4096) {
745
+ const html = current;
746
+ if (current.hasAttribute("hidden") || current.getAttribute("aria-hidden") === "true" || current.hasAttribute("inert"))
747
+ return false;
748
+ const style = typeof window !== "undefined" ? window.getComputedStyle?.(html) : undefined;
749
+ if (style?.display === "none" || style?.visibility === "hidden" || style?.opacity === "0")
750
+ return false;
751
+ current = elementParent(current);
752
+ depth += 1;
753
+ }
754
+ if (current !== null)
755
+ throw new Error("node limit exceeded");
756
+ const rect = node.getBoundingClientRect?.();
757
+ return rect === undefined || (rect.width > 0 && rect.height > 0);
758
+ };
759
+ const text = (node) => {
760
+ return normalize(node.getAttribute("aria-label") ?? boundedText(node));
761
+ };
762
+ const surfaceOf = () => {
763
+ const signals = new Set();
764
+ const addMarker = (raw) => {
765
+ const value = normalize(raw).toLocaleLowerCase();
766
+ if (/(?:^|[-_\s/])work(?:$|[-_\s/])/.test(value))
767
+ signals.add("work");
768
+ if (/(?:^|[-_\s/])chat(?:$|[-_\s/])/.test(value))
769
+ signals.add("chat");
770
+ };
771
+ const addLabel = (raw) => {
772
+ const value = normalize(raw).toLocaleLowerCase();
773
+ if (config.workComposerLabels.some(label => value === normalize(label).toLocaleLowerCase())
774
+ || config.workSurfaceLabels.some(label => value === normalize(label).toLocaleLowerCase()))
775
+ signals.add("work");
776
+ if (config.chatComposerLabels.some(label => value === normalize(label).toLocaleLowerCase())
777
+ || config.chatSurfaceLabels.some(label => value === normalize(label).toLocaleLowerCase()))
778
+ signals.add("chat");
779
+ };
780
+ const composerNodes = boundedQuery(document, "main textarea, main [contenteditable='true'], main [role='textbox']", 32).filter(visible);
781
+ for (const node of composerNodes) {
782
+ addLabel(normalize(node.getAttribute("aria-label")
783
+ ?? node.getAttribute("placeholder")
784
+ ?? boundedText(node)
785
+ ?? ""));
786
+ // Surface markers are trusted only on the active, visible composer
787
+ // subtree and its bounded ancestors. Global class/id scans can see a
788
+ // hidden Work launcher while Chat is active (or vice versa).
789
+ let current = node;
790
+ let depth = 0;
791
+ while (current !== null && depth < 8) {
792
+ for (const attribute of ["data-surface", "data-experience", "data-testid", "id", "class"]) {
793
+ const value = current.getAttribute(attribute);
794
+ if (value !== null)
795
+ addMarker(value);
796
+ }
797
+ current = elementParent(current);
798
+ depth += 1;
799
+ }
800
+ }
801
+ for (const node of boundedQuery(document, "[role='radio'][aria-checked='true'], [role='radio'][data-state='checked'], input[type='radio']:checked", 8).filter(visible)) {
802
+ addLabel(normalize(node.getAttribute("aria-label") ?? boundedText(node)));
803
+ }
804
+ if (typeof window !== "undefined" && typeof window.location?.pathname === "string") {
805
+ addMarker(window.location.pathname);
806
+ }
807
+ return signals.size === 1 ? [...signals][0] : "unknown";
808
+ };
809
+ const all = boundedQuery(document, "button, [role='button'], [role='menuitem'], [role='menuitemradio'], [role='option'], [role='radio']", config.maxControls);
810
+ const controls = [];
811
+ const menus = boundedQuery(document, "[role='menu'], [role='listbox'], [data-radix-popper-content-wrapper], [data-radix-menu-content]", config.maxControls);
812
+ const menuIndices = new Map();
813
+ for (let index = 0; index < menus.length; index += 1)
814
+ menuIndices.set(menus[index], index);
815
+ const menuIndex = (node) => {
816
+ const menuSelector = "[role='menu'], [role='listbox'], [data-radix-popper-content-wrapper], [data-radix-menu-content]";
817
+ let owner = node;
818
+ for (let depth = 0; owner !== null && depth < 4096; depth += 1) {
819
+ if (selectorMatch(owner, menuSelector))
820
+ return menuIndices.get(owner) ?? -1;
821
+ owner = elementParent(owner);
822
+ }
823
+ if (owner !== null)
824
+ throw new Error("node limit exceeded");
825
+ return -1;
826
+ };
827
+ for (const node of all) {
828
+ if (!visible(node))
829
+ continue;
830
+ const label = text(node);
831
+ if (label.length === 0 || label.length > 512)
832
+ continue;
833
+ const role = node.getAttribute("role") ?? node.tagName.toLocaleLowerCase();
834
+ const menu = menuIndex(node);
835
+ const selected = node.getAttribute("aria-checked") === "true"
836
+ || node.getAttribute("aria-selected") === "true"
837
+ || node.getAttribute("aria-pressed") === "true"
838
+ || node.getAttribute("data-state") === "checked"
839
+ || node.getAttribute("data-selected") === "true";
840
+ const testId = node.getAttribute("data-testid") ?? undefined;
841
+ const id = node.getAttribute("id") ?? undefined;
842
+ const menuRoot = menu < 0 ? null : menus[menu];
843
+ const menuLabel = menuRoot === null || menuRoot === undefined ? undefined : text(menuRoot);
844
+ controls.push({
845
+ label,
846
+ role,
847
+ ...(testId === undefined ? {} : { testId }),
848
+ ...(id === undefined ? {} : { id }),
849
+ ...(menu < 0 ? {} : { menuKey: `menu:${menu}`, ...(menuLabel === undefined ? {} : { menuLabel }) }),
850
+ ...(selected ? { selected: true } : {})
851
+ });
852
+ }
853
+ return {
854
+ surface: surfaceOf(),
855
+ controls
856
+ };
857
+ }, {
858
+ surface,
859
+ maxControls: MAX_DOM_CONTROLS,
860
+ workComposerLabels: [...localeLabels.workComposerTextbox],
861
+ chatComposerLabels: [...localeLabels.composerTextbox],
862
+ workSurfaceLabels: [...localeLabels.experienceOptions.work],
863
+ chatSurfaceLabels: [...localeLabels.experienceOptions.chat]
864
+ });
865
+ return normalizeSnapshot(value);
866
+ }
867
+ function normalizeSnapshot(value) {
868
+ const source = snapshotDataRecord(value, "configuration_surface_unavailable");
869
+ if (Object.keys(source).some(key => !["surface", "controls", "truncated"].includes(key))) {
870
+ throw new ProductionConfigurationPrimitiveError("configuration_surface_unavailable");
871
+ }
872
+ const surfaceValue = source.surface;
873
+ if (surfaceValue !== "chat" && surfaceValue !== "work" && surfaceValue !== "unknown") {
874
+ throw new ProductionConfigurationPrimitiveError("configuration_surface_unavailable");
875
+ }
876
+ if (source.truncated !== undefined && typeof source.truncated !== "boolean") {
877
+ throw new ProductionConfigurationPrimitiveError("configuration_surface_unavailable");
878
+ }
879
+ if (source.truncated === true)
880
+ throw new ProductionConfigurationPrimitiveError("configuration_observation_limit_exceeded");
881
+ const rawControls = snapshotDataArray(source.controls, "configuration_surface_unavailable");
882
+ if (rawControls.length > MAX_DOM_CONTROLS) {
883
+ throw new ProductionConfigurationPrimitiveError("configuration_observation_limit_exceeded");
884
+ }
885
+ const controls = [];
886
+ for (let index = 0; index < rawControls.length; index += 1) {
887
+ const raw = snapshotDataRecord(rawControls[index], "configuration_surface_unavailable");
888
+ if (Object.keys(raw).some(key => !["label", "role", "testId", "id", "menuKey", "menuLabel", "selected", "visible"].includes(key))
889
+ || typeof raw.label !== "string" || raw.label.length === 0 || raw.label.length > MAX_CONTROL_LABEL_LENGTH) {
890
+ throw new ProductionConfigurationPrimitiveError("configuration_surface_unavailable");
891
+ }
892
+ const role = raw.role === undefined ? "button" : raw.role;
893
+ if (typeof role !== "string" || role.length > 64)
894
+ throw new ProductionConfigurationPrimitiveError("configuration_surface_unavailable");
895
+ for (const field of ["testId", "id", "menuKey", "menuLabel"]) {
896
+ const fieldValue = raw[field];
897
+ if (fieldValue !== undefined && (typeof fieldValue !== "string" || fieldValue.length === 0 || fieldValue.length > MAX_CONTROL_LABEL_LENGTH)) {
898
+ throw new ProductionConfigurationPrimitiveError("configuration_surface_unavailable");
899
+ }
900
+ }
901
+ if ((raw.selected !== undefined && typeof raw.selected !== "boolean")
902
+ || (raw.visible !== undefined && typeof raw.visible !== "boolean")) {
903
+ throw new ProductionConfigurationPrimitiveError("configuration_surface_unavailable");
904
+ }
905
+ controls.push({
906
+ label: raw.label,
907
+ normalized: normalizeForLabelMatch(raw.label),
908
+ role,
909
+ ...(typeof raw.testId === "string" ? { testId: raw.testId } : {}),
910
+ ...(typeof raw.id === "string" ? { id: raw.id } : {}),
911
+ ...(typeof raw.menuKey === "string" ? { menuKey: raw.menuKey } : {}),
912
+ ...(typeof raw.menuLabel === "string" ? { menuLabel: raw.menuLabel } : {}),
913
+ selected: raw.selected === true,
914
+ visible: raw.visible !== false,
915
+ index
916
+ });
917
+ }
918
+ const signature = controls.map(control => [
919
+ control.index,
920
+ control.role,
921
+ control.testId ?? "",
922
+ control.id ?? "",
923
+ control.menuKey ?? "",
924
+ control.label,
925
+ control.selected ? "1" : "0"
926
+ ].join("\u001f")).join("\u001e");
927
+ return {
928
+ surface: surfaceValue,
929
+ controls: Object.freeze(controls),
930
+ signature: `${surfaceValue}\u001d${signature}`,
931
+ opaqueSignature: opaqueFingerprint(`${surfaceValue}\u001d${signature}`)
932
+ };
933
+ }
934
+ async function clickControl(page, control) {
935
+ const locator = await resolveControlLocator(page, control);
936
+ if (locator === undefined || locator.click === undefined) {
937
+ throw new ProductionConfigurationPrimitiveError("configuration_control_ambiguous");
938
+ }
939
+ await locator.click();
940
+ }
941
+ async function resolveControlLocator(page, control) {
942
+ if (control.testId !== undefined && page.locator !== undefined) {
943
+ const locator = page.locator(`[data-testid="${escapeAttribute(control.testId)}"]`);
944
+ const status = await locatorStatus(locator);
945
+ if (status === "unique")
946
+ return locator;
947
+ if (status === "ambiguous" || status === "hidden")
948
+ return undefined;
949
+ }
950
+ if (control.id !== undefined && page.locator !== undefined) {
951
+ const locator = page.locator(`#${escapeAttribute(control.id)}`);
952
+ const status = await locatorStatus(locator);
953
+ if (status === "unique")
954
+ return locator;
955
+ if (status === "ambiguous" || status === "hidden")
956
+ return undefined;
957
+ }
958
+ if (page.getByRole !== undefined) {
959
+ const locator = page.getByRole(control.role, { name: control.label, exact: true });
960
+ const status = await locatorStatus(locator);
961
+ if (status === "unique")
962
+ return locator;
963
+ if (status === "ambiguous" || status === "hidden")
964
+ return undefined;
965
+ }
966
+ if (page.locator !== undefined) {
967
+ const escaped = escapeRegExp(control.label);
968
+ const locator = page.locator("button, [role='button'], [role='menuitem'], [role='menuitemradio'], [role='option'], [role='radio']")
969
+ .filter?.({ hasText: new RegExp(`^\\s*${escaped}\\s*$`, "i") });
970
+ if (locator !== undefined && await locatorStatus(locator) === "unique")
971
+ return locator;
972
+ }
973
+ return undefined;
974
+ }
975
+ async function locatorStatus(locator) {
976
+ try {
977
+ if (locator.count === undefined)
978
+ return "absent";
979
+ const count = await locator.count();
980
+ if (count === 0)
981
+ return "absent";
982
+ if (count !== 1)
983
+ return "ambiguous";
984
+ return locator.isVisible === undefined || await locator.isVisible() ? "unique" : "hidden";
985
+ }
986
+ catch {
987
+ return "absent";
988
+ }
989
+ }
990
+ function rememberAndReturn(state, key, observation, result) {
991
+ remember(state, key, observation);
992
+ return result;
993
+ }
994
+ function remember(state, key, observation) {
995
+ state.observations.delete(key);
996
+ state.observations.set(key, observation);
997
+ trimState(state);
998
+ }
999
+ function trimState(state) {
1000
+ while (state.observations.size > MAX_CACHED_ACTIONS) {
1001
+ const first = state.observations.keys().next().value;
1002
+ if (first === undefined)
1003
+ break;
1004
+ state.observations.delete(first);
1005
+ state.attempted.delete(first);
1006
+ }
1007
+ while (state.attempted.size > MAX_CACHED_ACTIONS) {
1008
+ const first = state.attempted.values().next().value;
1009
+ if (first === undefined)
1010
+ break;
1011
+ state.attempted.delete(first);
1012
+ }
1013
+ }
1014
+ function satisfiedObservation(request, currentStateDigest, evidenceDigest) {
1015
+ if (currentStateDigest === undefined || evidenceDigest === undefined) {
1016
+ return {
1017
+ status: "uncertain",
1018
+ desiredStateDigest: safeDesiredDigest(request),
1019
+ blockerCode: "configuration_evidence_failed"
1020
+ };
1021
+ }
1022
+ return {
1023
+ status: "satisfied",
1024
+ desiredStateDigest: request.desiredStateDigest,
1025
+ currentStateDigest,
1026
+ evidenceDigest
1027
+ };
1028
+ }
1029
+ function notSatisfiedObservation(request, currentStateDigest, evidenceDigest) {
1030
+ if (currentStateDigest === undefined || evidenceDigest === undefined) {
1031
+ return {
1032
+ status: "uncertain",
1033
+ desiredStateDigest: safeDesiredDigest(request),
1034
+ blockerCode: "configuration_evidence_failed"
1035
+ };
1036
+ }
1037
+ return {
1038
+ status: "not_satisfied",
1039
+ desiredStateDigest: request.desiredStateDigest,
1040
+ currentStateDigest,
1041
+ evidenceDigest
1042
+ };
1043
+ }
1044
+ function unavailableObservation(request, blockerCode, currentStateDigest, evidenceDigest) {
1045
+ return {
1046
+ status: "unavailable",
1047
+ desiredStateDigest: safeDesiredDigest(request),
1048
+ blockerCode: isBlockerCode(blockerCode) ? blockerCode : "configuration_surface_unavailable",
1049
+ ...(currentStateDigest === undefined ? {} : { currentStateDigest }),
1050
+ ...(evidenceDigest === undefined ? {} : { evidenceDigest })
1051
+ };
1052
+ }
1053
+ function uncertainObservation(request, blockerCode, currentStateDigest, evidenceDigest) {
1054
+ return {
1055
+ status: "uncertain",
1056
+ desiredStateDigest: safeDesiredDigest(request),
1057
+ blockerCode,
1058
+ ...(currentStateDigest === undefined ? {} : { currentStateDigest }),
1059
+ ...(evidenceDigest === undefined ? {} : { evidenceDigest })
1060
+ };
1061
+ }
1062
+ function observationDigest(evidenceDigest, request, snapshot, status) {
1063
+ const fingerprint = "opaqueSignature" in snapshot && typeof snapshot.opaqueSignature === "string"
1064
+ ? snapshot.opaqueSignature
1065
+ : opaqueFingerprint(JSON.stringify(snapshot));
1066
+ return safeDigest(evidenceDigest, "configuration-staging-observation", {
1067
+ operationId: request.operationId,
1068
+ targetBindingDigest: request.targetBindingDigest,
1069
+ kind: request.kind,
1070
+ status,
1071
+ stateFingerprint: fingerprint
1072
+ });
1073
+ }
1074
+ function keyedStateDigest(evidenceDigest, request, kind, fingerprint) {
1075
+ return safeDigest(evidenceDigest, "configuration-staging-state", {
1076
+ operationId: request.operationId,
1077
+ targetBindingDigest: request.targetBindingDigest,
1078
+ kind,
1079
+ stateFingerprint: fingerprint
1080
+ });
1081
+ }
1082
+ function opaqueStateDigest(snapshot, values) {
1083
+ return `opaque:${opaqueFingerprint(`${snapshot.opaqueSignature}\u001d${values.map(opaqueFingerprint).join("\u001e")}`)}`;
1084
+ }
1085
+ function powerSignature(discovery) {
1086
+ const evidence = discovery.evidence;
1087
+ const options = discovery.options.map(option => `${opaqueFingerprint(option.label)}:${option.value ?? ""}`).join("\u001e");
1088
+ return opaqueFingerprint([
1089
+ discovery.sliderIndex,
1090
+ discovery.range.minimum,
1091
+ discovery.range.maximum,
1092
+ discovery.range.current,
1093
+ evidence.surface,
1094
+ evidence.selectorProfile,
1095
+ evidence.relationship,
1096
+ options,
1097
+ evidence.valueText === undefined ? "" : opaqueFingerprint(evidence.valueText)
1098
+ ].join("\u001d"));
1099
+ }
1100
+ function safeDigest(evidenceDigest, domain, material) {
1101
+ try {
1102
+ const value = evidenceDigest(domain, material);
1103
+ return typeof value === "string" && DIGEST_PATTERN.test(value) ? value : undefined;
1104
+ }
1105
+ catch {
1106
+ return undefined;
1107
+ }
1108
+ }
1109
+ function opaqueFingerprint(value) {
1110
+ return createHash("sha256").update(value, "utf8").digest("hex");
1111
+ }
1112
+ function normalizeRequest(request) {
1113
+ const source = snapshotDataRecord(request, "staging_request_mismatch");
1114
+ const kind = source.kind;
1115
+ if (kind !== "configuration_set" && kind !== "tool_set" && kind !== "power_select") {
1116
+ throw new ProductionConfigurationPrimitiveError("staging_request_mismatch");
1117
+ }
1118
+ const operationId = source.operationId;
1119
+ const requestDigest = source.requestDigest;
1120
+ const targetBindingDigest = source.targetBindingDigest;
1121
+ const actionId = source.actionId;
1122
+ const desiredStateDigest = source.desiredStateDigest;
1123
+ const deadlineAt = source.deadlineAt;
1124
+ const page = source.page;
1125
+ const target = source.target;
1126
+ const signal = source.signal;
1127
+ if (typeof operationId !== "string" || !ID_PATTERN.test(operationId)
1128
+ || typeof requestDigest !== "string" || !DIGEST_PATTERN.test(requestDigest)
1129
+ || typeof targetBindingDigest !== "string" || !DIGEST_PATTERN.test(targetBindingDigest)
1130
+ || typeof actionId !== "string" || !ID_PATTERN.test(actionId)
1131
+ || typeof desiredStateDigest !== "string" || !DIGEST_PATTERN.test(desiredStateDigest)
1132
+ || typeof deadlineAt !== "number" || !Number.isSafeInteger(deadlineAt)
1133
+ || page === null || typeof page !== "object"
1134
+ || target === null || typeof target !== "object") {
1135
+ throw new ProductionConfigurationPrimitiveError("staging_request_mismatch");
1136
+ }
1137
+ const callback = Object.freeze({
1138
+ operationId,
1139
+ requestDigest,
1140
+ targetBindingDigest,
1141
+ actionId,
1142
+ kind,
1143
+ desiredStateDigest,
1144
+ signal: signal,
1145
+ deadlineAt,
1146
+ page: page,
1147
+ target: target
1148
+ });
1149
+ return {
1150
+ callback,
1151
+ key: `${operationId}\u001d${actionId}\u001d${kind}`
1152
+ };
1153
+ }
1154
+ function matchesOperation(request, options) {
1155
+ const expected = safeDigest(options.evidenceDigest, "staging-desired", {
1156
+ requestDigest: request.requestDigest,
1157
+ kind: request.kind
1158
+ });
1159
+ return request.operationId === options.operationId
1160
+ && request.requestDigest === options.requestDigest
1161
+ && expected !== undefined
1162
+ && request.desiredStateDigest === expected;
1163
+ }
1164
+ function safeDesiredDigest(request) {
1165
+ const desiredStateDigest = readOwnDataProperty(request, "desiredStateDigest");
1166
+ return typeof desiredStateDigest === "string" && DIGEST_PATTERN.test(desiredStateDigest)
1167
+ ? desiredStateDigest
1168
+ : "hmac-sha256:" + "0".repeat(64);
1169
+ }
1170
+ function fallbackUnavailableCode(kind) {
1171
+ return kind === "tool_set"
1172
+ ? "tool_surface_unavailable"
1173
+ : kind === "power_select"
1174
+ ? "power_surface_unavailable"
1175
+ : "configuration_surface_unavailable";
1176
+ }
1177
+ function errorCode(error, fallback) {
1178
+ if (error instanceof ProductionConfigurationPrimitiveError && isBlockerCode(error.code))
1179
+ return error.code;
1180
+ return isBlockerCode(fallback) ? fallback : "configuration_surface_unavailable";
1181
+ }
1182
+ function isBlockerCode(value) {
1183
+ return new Set([
1184
+ "staging_request_mismatch", "staging_observation_required", "staging_mutation_already_attempted", "staging_mutation_unreconciled",
1185
+ "configuration_not_configured", "configuration_surface_unavailable", "configuration_surface_unsupported", "configuration_control_ambiguous",
1186
+ "configuration_option_unavailable", "configuration_state_drift", "configuration_observation_limit_exceeded", "tool_not_configured",
1187
+ "tool_surface_unavailable", "tool_surface_unsupported", "tool_selection_ambiguous", "tool_option_unavailable", "tool_state_unavailable",
1188
+ "tool_state_drift", "power_not_configured", "power_surface_unavailable", "power_surface_unsupported", "power_mapping_incomplete",
1189
+ "power_state_drift", "power_restoration_required", "power_control_unavailable", "configuration_evidence_failed"
1190
+ ]).has(value);
1191
+ }
1192
+ function validateOptions(options, configuration) {
1193
+ if (typeof options.evidenceDigest !== "function"
1194
+ || typeof options.operationId !== "string" || !ID_PATTERN.test(options.operationId)
1195
+ || typeof options.requestDigest !== "string" || !DIGEST_PATTERN.test(options.requestDigest)
1196
+ || (options.surface !== "chat" && options.surface !== "work")) {
1197
+ throw new ProductionConfigurationPrimitiveError("staging_request_mismatch");
1198
+ }
1199
+ if (options.configuration !== undefined && configuration === undefined) {
1200
+ throw new ProductionConfigurationPrimitiveError("configuration_not_configured");
1201
+ }
1202
+ if (configuration?.experience !== undefined && configuration.experience !== options.surface) {
1203
+ throw new ProductionConfigurationPrimitiveError("configuration_surface_unsupported");
1204
+ }
1205
+ }
1206
+ function copyConfiguration(configuration) {
1207
+ if (configuration === undefined)
1208
+ return undefined;
1209
+ const source = snapshotDataRecord(configuration, "configuration_not_configured");
1210
+ const allowed = new Set(["experience", "model", "modelVersion", "reasoning", "mode", "tools", "additional"]);
1211
+ if (Object.keys(source).some(key => !allowed.has(key))) {
1212
+ throw new ProductionConfigurationPrimitiveError("configuration_not_configured");
1213
+ }
1214
+ const copy = {};
1215
+ for (const key of ["model", "modelVersion", "reasoning", "mode"]) {
1216
+ const value = source[key];
1217
+ if (value !== undefined && typeof value !== "string") {
1218
+ throw new ProductionConfigurationPrimitiveError("configuration_not_configured");
1219
+ }
1220
+ if (value !== undefined)
1221
+ copy[key] = value;
1222
+ }
1223
+ const experience = source.experience;
1224
+ if (experience !== undefined) {
1225
+ if (experience !== "chat" && experience !== "work") {
1226
+ throw new ProductionConfigurationPrimitiveError("configuration_not_configured");
1227
+ }
1228
+ copy.experience = experience;
1229
+ }
1230
+ const tools = source.tools;
1231
+ if (tools !== undefined) {
1232
+ const values = snapshotDataArray(tools, "configuration_not_configured");
1233
+ if (values.length === 0 || values.length > MAX_CONFIGURATION_FIELDS
1234
+ || values.some(value => typeof value !== "string" || value.length === 0 || value.length > MAX_CONTROL_LABEL_LENGTH)) {
1235
+ throw new ProductionConfigurationPrimitiveError("configuration_not_configured");
1236
+ }
1237
+ copy.tools = values;
1238
+ Object.freeze(copy.tools);
1239
+ }
1240
+ const additional = source.additional;
1241
+ if (additional !== undefined) {
1242
+ copy.additional = copyAdditionalAxes(additional);
1243
+ }
1244
+ if (Object.keys(copy).length === 0) {
1245
+ throw new ProductionConfigurationPrimitiveError("configuration_not_configured");
1246
+ }
1247
+ return Object.freeze(copy);
1248
+ }
1249
+ function copyAdditionalAxes(value) {
1250
+ const source = snapshotDataRecord(value, "configuration_not_configured");
1251
+ if (Object.keys(source).length === 0) {
1252
+ throw new ProductionConfigurationPrimitiveError("configuration_not_configured");
1253
+ }
1254
+ const axes = {};
1255
+ const supported = new Set(["intelligence", "effort", "speed"]);
1256
+ for (const [key, child] of Object.entries(source)) {
1257
+ if (!supported.has(key) || typeof child !== "string"
1258
+ || child.length === 0 || child.length > MAX_CONTROL_LABEL_LENGTH) {
1259
+ throw new ProductionConfigurationPrimitiveError("configuration_not_configured");
1260
+ }
1261
+ axes[key] = child;
1262
+ }
1263
+ Object.freeze(axes);
1264
+ return axes;
1265
+ }
1266
+ function snapshotProductionOptions(value) {
1267
+ const source = snapshotDataRecord(value, "staging_request_mismatch");
1268
+ const allowed = new Set(["evidenceDigest", "operationId", "requestDigest", "surface", "configuration"]);
1269
+ if (Object.keys(source).some(key => !allowed.has(key))) {
1270
+ throw new ProductionConfigurationPrimitiveError("staging_request_mismatch");
1271
+ }
1272
+ return {
1273
+ evidenceDigest: source.evidenceDigest,
1274
+ operationId: source.operationId,
1275
+ requestDigest: source.requestDigest,
1276
+ surface: source.surface,
1277
+ configuration: source.configuration
1278
+ };
1279
+ }
1280
+ function snapshotDataRecord(value, code) {
1281
+ if (!isPlainDataRecord(value))
1282
+ throw new ProductionConfigurationPrimitiveError(code);
1283
+ let descriptors;
1284
+ try {
1285
+ descriptors = Object.getOwnPropertyDescriptors(value);
1286
+ }
1287
+ catch {
1288
+ throw new ProductionConfigurationPrimitiveError(code);
1289
+ }
1290
+ // A null-prototype snapshot prevents a hostile own `__proto__` key from
1291
+ // changing the snapshot object's prototype while it is being copied.
1292
+ const output = Object.create(null);
1293
+ for (const key of Reflect.ownKeys(descriptors)) {
1294
+ if (typeof key !== "string")
1295
+ throw new ProductionConfigurationPrimitiveError(code);
1296
+ const descriptor = descriptors[key];
1297
+ if (descriptor === undefined || !("value" in descriptor)
1298
+ || descriptor.get !== undefined || descriptor.set !== undefined) {
1299
+ throw new ProductionConfigurationPrimitiveError(code);
1300
+ }
1301
+ output[key] = descriptor.value;
1302
+ }
1303
+ return output;
1304
+ }
1305
+ function snapshotDataArray(value, code) {
1306
+ if (!Array.isArray(value))
1307
+ throw new ProductionConfigurationPrimitiveError(code);
1308
+ let descriptors;
1309
+ try {
1310
+ descriptors = Object.getOwnPropertyDescriptors(value);
1311
+ }
1312
+ catch {
1313
+ throw new ProductionConfigurationPrimitiveError(code);
1314
+ }
1315
+ const lengthDescriptor = descriptors.length;
1316
+ if (lengthDescriptor === undefined || !("value" in lengthDescriptor)
1317
+ || lengthDescriptor.get !== undefined || lengthDescriptor.set !== undefined
1318
+ || typeof lengthDescriptor.value !== "number"
1319
+ || !Number.isSafeInteger(lengthDescriptor.value) || lengthDescriptor.value < 0
1320
+ || lengthDescriptor.value > 1024) {
1321
+ throw new ProductionConfigurationPrimitiveError(code);
1322
+ }
1323
+ const length = lengthDescriptor.value;
1324
+ const output = [];
1325
+ for (const key of Reflect.ownKeys(descriptors)) {
1326
+ if (typeof key !== "string")
1327
+ throw new ProductionConfigurationPrimitiveError(code);
1328
+ if (key === "length")
1329
+ continue;
1330
+ if (!/^(?:0|[1-9][0-9]*)$/u.test(key) || Number(key) >= length) {
1331
+ throw new ProductionConfigurationPrimitiveError(code);
1332
+ }
1333
+ }
1334
+ for (let index = 0; index < length; index += 1) {
1335
+ const descriptor = descriptors[String(index)];
1336
+ if (descriptor === undefined || !("value" in descriptor)
1337
+ || descriptor.get !== undefined || descriptor.set !== undefined) {
1338
+ throw new ProductionConfigurationPrimitiveError(code);
1339
+ }
1340
+ output.push(descriptor.value);
1341
+ }
1342
+ return output;
1343
+ }
1344
+ function readOwnDataProperty(value, key) {
1345
+ if (value === null || (typeof value !== "object" && typeof value !== "function"))
1346
+ return undefined;
1347
+ try {
1348
+ const descriptor = Object.getOwnPropertyDescriptor(value, key);
1349
+ return descriptor !== undefined && "value" in descriptor
1350
+ && descriptor.get === undefined && descriptor.set === undefined
1351
+ ? descriptor.value
1352
+ : undefined;
1353
+ }
1354
+ catch {
1355
+ return undefined;
1356
+ }
1357
+ }
1358
+ function escapeRegExp(value) {
1359
+ return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
1360
+ }
1361
+ function escapeAttribute(value) {
1362
+ return value.replace(/[\\"\u0000-\u001f\u007f]/g, "\\$&");
1363
+ }