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

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 (204) hide show
  1. package/CHANGELOG.md +12 -0
  2. package/contracts/v1/fixtures/backend-capabilities.json +1 -0
  3. package/contracts/v1/fixtures/command-descriptors.json +21 -0
  4. package/contracts/v1/fixtures/doctor-bridge-upload.json +2 -2
  5. package/contracts/v1/fixtures/doctor-scenario-preflight.json +26 -4
  6. package/contracts/v1/fixtures/files-attach-indeterminate.json +30 -0
  7. package/contracts/v1/fixtures/help-root.json +1 -1
  8. package/contracts/v1/fixtures/messages-stop-indeterminate.json +31 -0
  9. package/contracts/v1/fixtures/messages-stop-needs-confirmation.json +20 -0
  10. package/contracts/v1/fixtures/messages-stop-noop.json +19 -0
  11. package/contracts/v1/fixtures/messages-stop-success.json +21 -0
  12. package/contracts/v1/fixtures/primitive-bootstrap-blocker.json +3 -3
  13. package/contracts/v1/fixtures/reports-create-redacted.json +3 -3
  14. package/contracts/v1/fixtures/reports-summarize-redacted.json +1 -1
  15. package/contracts/v1/fixtures/run-browser-bridge-blocker.json +12 -12
  16. package/contracts/v1/fixtures/stream-blocked.ndjson +2 -2
  17. package/contracts/v1/manifest.json +25 -0
  18. package/contracts/v1/parity-suite.json +8 -1
  19. package/dist/codex-chatgpt-control-backend.mjs +2259 -498
  20. package/dist/codex-chatgpt-control.bundle.mjs +2263 -472
  21. package/dist/src/backend/client.d.ts +2 -1
  22. package/dist/src/backend/client.js +1 -0
  23. package/dist/src/backend/protocol.d.ts +1 -1
  24. package/dist/src/backend/protocol.js +1 -0
  25. package/dist/src/backend/session.js +2 -0
  26. package/dist/src/browser/attach.d.ts +1 -0
  27. package/dist/src/browser/attach.js +69 -35
  28. package/dist/src/browser/chatgpt-url.d.ts +8 -0
  29. package/dist/src/browser/chatgpt-url.js +28 -0
  30. package/dist/src/browser/page-state.js +211 -4
  31. package/dist/src/client.d.ts +2 -1
  32. package/dist/src/client.js +2 -1
  33. package/dist/src/commands/configuration.js +46 -12
  34. package/dist/src/commands/context.d.ts +5 -1
  35. package/dist/src/commands/context.js +2 -2
  36. package/dist/src/commands/conversation.js +13 -1
  37. package/dist/src/commands/doctor.js +24 -2
  38. package/dist/src/commands/files.d.ts +1 -0
  39. package/dist/src/commands/files.js +742 -191
  40. package/dist/src/commands/messages.d.ts +2 -1
  41. package/dist/src/commands/messages.js +310 -2
  42. package/dist/src/commands/modes.js +197 -52
  43. package/dist/src/commands/registry.js +3 -0
  44. package/dist/src/commands/sequence.js +3 -1
  45. package/dist/src/commands/session.d.ts +4 -1
  46. package/dist/src/commands/session.js +34 -3
  47. package/dist/src/dom/generation-state.d.ts +6 -1
  48. package/dist/src/dom/generation-state.js +206 -45
  49. package/dist/src/dom/locale/am.d.ts +10 -1
  50. package/dist/src/dom/locale/am.js +10 -1
  51. package/dist/src/dom/locale/ar.d.ts +8 -1
  52. package/dist/src/dom/locale/ar.js +9 -2
  53. package/dist/src/dom/locale/bg.d.ts +6 -1
  54. package/dist/src/dom/locale/bg.js +6 -1
  55. package/dist/src/dom/locale/bn.d.ts +10 -1
  56. package/dist/src/dom/locale/bn.js +10 -1
  57. package/dist/src/dom/locale/bs.d.ts +5 -1
  58. package/dist/src/dom/locale/bs.js +5 -1
  59. package/dist/src/dom/locale/ca.d.ts +8 -1
  60. package/dist/src/dom/locale/ca.js +8 -1
  61. package/dist/src/dom/locale/cs.d.ts +5 -1
  62. package/dist/src/dom/locale/cs.js +6 -2
  63. package/dist/src/dom/locale/da.d.ts +5 -1
  64. package/dist/src/dom/locale/da.js +6 -2
  65. package/dist/src/dom/locale/de.d.ts +4 -1
  66. package/dist/src/dom/locale/de.js +5 -2
  67. package/dist/src/dom/locale/el.d.ts +5 -1
  68. package/dist/src/dom/locale/el.js +6 -2
  69. package/dist/src/dom/locale/en.d.ts +2 -1
  70. package/dist/src/dom/locale/en.js +2 -1
  71. package/dist/src/dom/locale/es-419.d.ts +5 -1
  72. package/dist/src/dom/locale/es-419.js +5 -1
  73. package/dist/src/dom/locale/es-ES.d.ts +5 -1
  74. package/dist/src/dom/locale/es-ES.js +5 -1
  75. package/dist/src/dom/locale/et.d.ts +4 -1
  76. package/dist/src/dom/locale/et.js +5 -2
  77. package/dist/src/dom/locale/fa.d.ts +9 -1
  78. package/dist/src/dom/locale/fa.js +10 -2
  79. package/dist/src/dom/locale/fi.d.ts +5 -1
  80. package/dist/src/dom/locale/fi.js +6 -2
  81. package/dist/src/dom/locale/fr-CA.d.ts +4 -1
  82. package/dist/src/dom/locale/fr-CA.js +4 -1
  83. package/dist/src/dom/locale/fr-FR.d.ts +5 -1
  84. package/dist/src/dom/locale/fr-FR.js +7 -3
  85. package/dist/src/dom/locale/gu.d.ts +10 -1
  86. package/dist/src/dom/locale/gu.js +10 -1
  87. package/dist/src/dom/locale/hi.d.ts +10 -1
  88. package/dist/src/dom/locale/hi.js +11 -2
  89. package/dist/src/dom/locale/hr.d.ts +4 -1
  90. package/dist/src/dom/locale/hr.js +4 -1
  91. package/dist/src/dom/locale/hu.d.ts +4 -1
  92. package/dist/src/dom/locale/hu.js +5 -2
  93. package/dist/src/dom/locale/hy.d.ts +10 -1
  94. package/dist/src/dom/locale/hy.js +11 -2
  95. package/dist/src/dom/locale/id.d.ts +5 -1
  96. package/dist/src/dom/locale/id.js +5 -1
  97. package/dist/src/dom/locale/index.js +1 -0
  98. package/dist/src/dom/locale/is.d.ts +9 -1
  99. package/dist/src/dom/locale/is.js +10 -2
  100. package/dist/src/dom/locale/it.d.ts +4 -1
  101. package/dist/src/dom/locale/it.js +6 -3
  102. package/dist/src/dom/locale/ja.d.ts +6 -1
  103. package/dist/src/dom/locale/ja.js +7 -2
  104. package/dist/src/dom/locale/ka.d.ts +10 -1
  105. package/dist/src/dom/locale/ka.js +11 -2
  106. package/dist/src/dom/locale/kk.d.ts +10 -1
  107. package/dist/src/dom/locale/kk.js +11 -2
  108. package/dist/src/dom/locale/kn.d.ts +9 -1
  109. package/dist/src/dom/locale/kn.js +10 -2
  110. package/dist/src/dom/locale/ko.d.ts +6 -1
  111. package/dist/src/dom/locale/ko.js +7 -2
  112. package/dist/src/dom/locale/lt.d.ts +5 -1
  113. package/dist/src/dom/locale/lt.js +6 -2
  114. package/dist/src/dom/locale/lv.d.ts +5 -1
  115. package/dist/src/dom/locale/lv.js +5 -1
  116. package/dist/src/dom/locale/mk.d.ts +9 -1
  117. package/dist/src/dom/locale/mk.js +10 -2
  118. package/dist/src/dom/locale/ml.d.ts +10 -1
  119. package/dist/src/dom/locale/ml.js +10 -1
  120. package/dist/src/dom/locale/mn.d.ts +10 -1
  121. package/dist/src/dom/locale/mn.js +13 -4
  122. package/dist/src/dom/locale/mr.d.ts +10 -1
  123. package/dist/src/dom/locale/mr.js +10 -1
  124. package/dist/src/dom/locale/ms.d.ts +9 -1
  125. package/dist/src/dom/locale/ms.js +9 -1
  126. package/dist/src/dom/locale/my.d.ts +9 -1
  127. package/dist/src/dom/locale/my.js +9 -1
  128. package/dist/src/dom/locale/nb.d.ts +5 -1
  129. package/dist/src/dom/locale/nb.js +6 -2
  130. package/dist/src/dom/locale/nl.d.ts +8 -2
  131. package/dist/src/dom/locale/nl.js +8 -2
  132. package/dist/src/dom/locale/pa.d.ts +10 -1
  133. package/dist/src/dom/locale/pa.js +10 -1
  134. package/dist/src/dom/locale/pl.d.ts +5 -1
  135. package/dist/src/dom/locale/pl.js +6 -2
  136. package/dist/src/dom/locale/pt-BR.d.ts +5 -1
  137. package/dist/src/dom/locale/pt-BR.js +6 -2
  138. package/dist/src/dom/locale/pt-PT.d.ts +5 -1
  139. package/dist/src/dom/locale/pt-PT.js +5 -1
  140. package/dist/src/dom/locale/ro.d.ts +4 -1
  141. package/dist/src/dom/locale/ro.js +4 -1
  142. package/dist/src/dom/locale/ru.d.ts +8 -1
  143. package/dist/src/dom/locale/ru.js +9 -2
  144. package/dist/src/dom/locale/sk.d.ts +5 -1
  145. package/dist/src/dom/locale/sk.js +5 -1
  146. package/dist/src/dom/locale/sl.d.ts +9 -1
  147. package/dist/src/dom/locale/sl.js +9 -1
  148. package/dist/src/dom/locale/so.d.ts +9 -1
  149. package/dist/src/dom/locale/so.js +9 -1
  150. package/dist/src/dom/locale/sq.d.ts +10 -1
  151. package/dist/src/dom/locale/sq.js +12 -3
  152. package/dist/src/dom/locale/sr.d.ts +9 -1
  153. package/dist/src/dom/locale/sr.js +10 -2
  154. package/dist/src/dom/locale/sv.d.ts +4 -1
  155. package/dist/src/dom/locale/sv.js +4 -1
  156. package/dist/src/dom/locale/sw.d.ts +5 -1
  157. package/dist/src/dom/locale/sw.js +7 -3
  158. package/dist/src/dom/locale/ta.d.ts +10 -1
  159. package/dist/src/dom/locale/ta.js +12 -3
  160. package/dist/src/dom/locale/te.d.ts +10 -1
  161. package/dist/src/dom/locale/te.js +11 -2
  162. package/dist/src/dom/locale/th.d.ts +6 -1
  163. package/dist/src/dom/locale/th.js +6 -1
  164. package/dist/src/dom/locale/tl.d.ts +1 -1
  165. package/dist/src/dom/locale/tl.js +2 -2
  166. package/dist/src/dom/locale/tr.d.ts +9 -1
  167. package/dist/src/dom/locale/tr.js +10 -2
  168. package/dist/src/dom/locale/types.d.ts +1 -1
  169. package/dist/src/dom/locale/uk.d.ts +10 -1
  170. package/dist/src/dom/locale/uk.js +11 -2
  171. package/dist/src/dom/locale/ur.d.ts +9 -1
  172. package/dist/src/dom/locale/ur.js +9 -1
  173. package/dist/src/dom/locale/vi.d.ts +9 -1
  174. package/dist/src/dom/locale/vi.js +10 -2
  175. package/dist/src/dom/locale/zh-HK.d.ts +8 -1
  176. package/dist/src/dom/locale/zh-HK.js +9 -2
  177. package/dist/src/dom/locale/zh-Hans.d.ts +10 -1
  178. package/dist/src/dom/locale/zh-Hans.js +11 -2
  179. package/dist/src/dom/locale/zh-TW.d.ts +10 -1
  180. package/dist/src/dom/locale/zh-TW.js +11 -2
  181. package/dist/src/dom/selectors.d.ts +1 -0
  182. package/dist/src/dom/selectors.js +9 -1
  183. package/dist/src/dom/wait-snapshot.d.ts +1 -0
  184. package/dist/src/dom/wait-snapshot.js +45 -22
  185. package/dist/src/errors.d.ts +1 -1
  186. package/dist/src/errors.js +2 -2
  187. package/dist/src/safety/risk.d.ts +1 -0
  188. package/dist/src/safety/risk.js +1 -0
  189. package/dist/src/scripts/apply-intelligence-locale-captures.d.ts +2 -2
  190. package/dist/src/scripts/apply-intelligence-locale-captures.js +54 -14
  191. package/dist/src/scripts/capture-intelligence-locales.d.ts +114 -1
  192. package/dist/src/scripts/capture-intelligence-locales.js +437 -304
  193. package/dist/src/scripts/live-smoke/scenarios.d.ts +2 -1
  194. package/dist/src/scripts/live-smoke/scenarios.js +9 -10
  195. package/dist/src/scripts/locale-capture/surface-graph.d.ts +7 -2
  196. package/dist/src/scripts/locale-capture/surface-graph.js +7 -0
  197. package/dist/src/types.d.ts +27 -6
  198. package/package.json +2 -1
  199. package/references/2026-08-08-model-selection-locale-sweep.md +32 -0
  200. package/references/backend-protocol.md +11 -3
  201. package/references/language-coverage.md +14 -14
  202. package/references/localization.md +17 -13
  203. package/references/python-parity.md +8 -2
  204. package/references/troubleshooting.md +10 -2
@@ -7,56 +7,109 @@ import { localeLabels } from "./locale-labels.js";
7
7
  * response is complete.
8
8
  */
9
9
  export const EMPTY_GENERATION_STATE = {
10
+ observed: false,
10
11
  active: false,
11
12
  stopped: false,
12
13
  signals: []
13
14
  };
14
- export async function readAssistantGenerationState(page) {
15
+ export async function readAssistantGenerationState(page, options = {}) {
16
+ const expiresAtMs = options.timeoutMs === undefined
17
+ ? undefined
18
+ : Date.now() + Math.max(1, options.timeoutMs);
15
19
  if (typeof page.evaluate === "function") {
16
- return page.evaluate((args) => {
17
- const normalize = (value) => (value ?? "").trim().toLowerCase();
18
- const isVisible = (element) => {
19
- const style = window.getComputedStyle(element);
20
- return style.display !== "none"
21
- && style.visibility !== "hidden"
22
- && style.opacity !== "0"
23
- && element.getAttribute("aria-hidden") !== "true";
24
- };
25
- const visibleButtons = Array.from(document.querySelectorAll("button"))
26
- .filter((button) => isVisible(button)
27
- && button.disabled !== true
28
- && button.getAttribute("aria-disabled") !== "true");
29
- const buttonTexts = visibleButtons
30
- .map(button => [
31
- button.innerText,
32
- button.textContent,
33
- button.getAttribute("aria-label"),
34
- button.getAttribute("title")
35
- ].map(normalize).filter(Boolean).join(" "))
36
- .filter(Boolean);
37
- const bodyText = normalize(document.body?.innerText);
38
- const haystacks = [bodyText, ...buttonTexts];
39
- const matchingSignals = (phrases) => haystacks.flatMap(text => phrases
40
- .map(phrase => phrase.toLowerCase())
41
- .filter(phrase => text.includes(phrase)));
42
- const activeSignals = matchingSignals(args.stop);
43
- const stoppedSignals = matchingSignals(args.stopped);
44
- return {
45
- active: activeSignals.length > 0,
46
- stopped: stoppedSignals.length > 0,
47
- signals: [...new Set([...activeSignals, ...stoppedSignals, ...buttonTexts.filter(text => /stop|cancel|stopped|answering|thinking/i.test(text))])].slice(0, 5)
48
- };
49
- }, {
50
- stop: [...localeLabels.stopControl],
51
- stopped: [...localeLabels.stoppedAssistant]
52
- }).catch(() => EMPTY_GENERATION_STATE);
20
+ const evaluateOptions = remainingGenerationStateOptions(expiresAtMs);
21
+ if (expiresAtMs !== undefined && evaluateOptions === undefined)
22
+ return EMPTY_GENERATION_STATE;
23
+ try {
24
+ return await page.evaluate((args) => {
25
+ const normalize = (value) => (value ?? "").replace(/\s+/g, " ").trim().toLowerCase();
26
+ const isVisible = (element) => {
27
+ if (element.hidden || element.closest("[hidden], [inert], [aria-hidden='true']") !== null) {
28
+ return false;
29
+ }
30
+ const style = window.getComputedStyle(element);
31
+ if (style.display === "none"
32
+ || style.visibility === "hidden"
33
+ || style.opacity === "0"
34
+ || style.pointerEvents === "none") {
35
+ return false;
36
+ }
37
+ const rect = element.getBoundingClientRect();
38
+ return (rect.width > 0 || rect.height > 0)
39
+ && style.display !== "none"
40
+ && style.visibility !== "hidden"
41
+ && style.opacity !== "0";
42
+ };
43
+ const values = (element) => [
44
+ element.getAttribute("aria-label"),
45
+ element.getAttribute("title"),
46
+ element.innerText,
47
+ element.textContent
48
+ ].map(normalize).filter(Boolean);
49
+ const matchingLabels = (element, phrases) => {
50
+ const elementValues = values(element);
51
+ return phrases.filter(phrase => elementValues.includes(normalize(phrase)));
52
+ };
53
+ const textboxes = Array.from(document.querySelectorAll("textarea, [contenteditable='true'], [role='textbox']")).filter(isVisible);
54
+ const activeComposers = [...new Set(textboxes
55
+ .map(textbox => textbox.closest("form")
56
+ ?? textbox.closest("[data-testid*='composer' i]")
57
+ ?? textbox.closest("[aria-label*='composer' i]")
58
+ ?? textbox.closest("[class*='composer' i]"))
59
+ .filter((value) => value !== null))];
60
+ const isScopedStopControl = (button) => activeComposers.length === 1 && activeComposers[0].contains(button);
61
+ const visibleStopButtons = Array.from(document.querySelectorAll("button"))
62
+ .filter((button) => isVisible(button)
63
+ && button.disabled !== true
64
+ && button.getAttribute("aria-disabled") !== "true"
65
+ && isScopedStopControl(button)
66
+ && matchingLabels(button, args.send).length === 0
67
+ && matchingLabels(button, args.stop).length > 0);
68
+ const activeSignals = [...new Set(visibleStopButtons.flatMap(button => matchingLabels(button, args.stop)))];
69
+ const turns = Array.from(document.querySelectorAll("[data-testid^='conversation-turn']"));
70
+ const latestAssistant = Array.from(document.querySelectorAll("[data-message-author-role='assistant']")).at(-1);
71
+ const latestTurn = latestAssistant?.closest("[data-testid^='conversation-turn']") ?? turns.at(-1);
72
+ const stoppedSignals = latestTurn === undefined
73
+ ? []
74
+ : [...new Set(Array.from(latestTurn.querySelectorAll("button, [role='status'], [aria-label], [title], p, span, div"))
75
+ .filter(element => isVisible(element))
76
+ .flatMap(element => matchingLabels(element, args.stopped)))];
77
+ return {
78
+ observed: true,
79
+ active: activeSignals.length > 0,
80
+ stopped: stoppedSignals.length > 0,
81
+ signals: [...new Set([...activeSignals, ...stoppedSignals])].slice(0, 5)
82
+ };
83
+ }, {
84
+ stop: [...localeLabels.stopControl],
85
+ stopped: [...localeLabels.stoppedAssistant],
86
+ send: [...localeLabels.sendButton]
87
+ }, evaluateOptions);
88
+ }
89
+ catch {
90
+ // Fall through to the serialized-DOM fallback when available. A failed
91
+ // evaluate with no fallback remains explicitly unobserved.
92
+ }
53
93
  }
54
94
  if (typeof page.content === "function") {
55
- const html = await page.content().catch(() => "");
56
- return generationStateFromText(html);
95
+ const contentOptions = remainingGenerationStateOptions(expiresAtMs);
96
+ if (expiresAtMs !== undefined && contentOptions === undefined)
97
+ return EMPTY_GENERATION_STATE;
98
+ try {
99
+ return generationStateFromHtml(await page.content(contentOptions));
100
+ }
101
+ catch {
102
+ return EMPTY_GENERATION_STATE;
103
+ }
57
104
  }
58
105
  return EMPTY_GENERATION_STATE;
59
106
  }
107
+ function remainingGenerationStateOptions(expiresAtMs) {
108
+ if (expiresAtMs === undefined)
109
+ return undefined;
110
+ const timeoutMs = expiresAtMs - Date.now();
111
+ return timeoutMs > 0 ? { timeoutMs } : undefined;
112
+ }
60
113
  export async function latestAssistantTurnHasResponseActions(page) {
61
114
  if (typeof page.evaluate === "function") {
62
115
  const scoped = await page.evaluate((phrases) => {
@@ -97,13 +150,121 @@ export async function latestAssistantTurnHasResponseActions(page) {
97
150
  return true;
98
151
  }
99
152
  }
100
- function generationStateFromText(text) {
101
- const normalized = text.toLowerCase();
102
- const activeSignals = localeLabels.stopControl.filter(phrase => normalized.includes(phrase.toLowerCase()));
103
- const stoppedSignals = localeLabels.stoppedAssistant.filter(phrase => normalized.includes(phrase.toLowerCase()));
153
+ function generationStateFromHtml(html) {
154
+ const normalize = (value) => value
155
+ .replace(/<[^>]*>/g, " ")
156
+ .replace(/&nbsp;/gi, " ")
157
+ .replace(/\s+/g, " ")
158
+ .trim()
159
+ .toLowerCase();
160
+ const isHiddenTag = (tag) => /\b(?:hidden|inert)\b/i.test(tag)
161
+ || /\baria-hidden\s*=\s*["']?true/i.test(tag)
162
+ || /\bstyle\s*=\s*["'][^"']*(?:display\s*:\s*none|visibility\s*:\s*hidden|opacity\s*:\s*0)/i.test(tag);
163
+ const candidateValues = (tag, text) => {
164
+ const values = [text];
165
+ for (const attribute of ["aria-label", "title"]) {
166
+ const match = new RegExp(`\\b${attribute}\\s*=\\s*["']([^"']*)["']`, "i").exec(tag);
167
+ if (match?.[1] !== undefined)
168
+ values.push(match[1]);
169
+ }
170
+ return values.map(normalize).filter(Boolean);
171
+ };
172
+ const exactMatches = (values, phrases) => phrases.filter(phrase => values.includes(normalize(phrase)));
173
+ const activeSignals = serializedStopButtonCandidates(html)
174
+ .filter(candidate => candidate.scoped && !candidate.hidden && !candidate.disabled)
175
+ .flatMap(candidate => {
176
+ const values = candidateValues(candidate.attributes, candidate.text);
177
+ return exactMatches(values, localeLabels.sendButton).length > 0
178
+ ? []
179
+ : exactMatches(values, localeLabels.stopControl);
180
+ });
181
+ const latestTurnStart = Math.max(html.toLowerCase().lastIndexOf("data-message-author-role=\"assistant\""), html.toLowerCase().lastIndexOf("data-message-author-role='assistant'"));
182
+ const latestAssistantHtml = latestTurnStart >= 0 ? html.slice(latestTurnStart) : "";
183
+ const stoppedSignals = [...latestAssistantHtml.matchAll(/<(?:button|p|span|div)\b([^>]*)>([\s\S]*?)<\/(?:button|p|span|div)>/gi)]
184
+ .filter(match => !isHiddenTag(match[1] ?? ""))
185
+ .flatMap(match => exactMatches(candidateValues(match[1] ?? "", match[2] ?? ""), localeLabels.stoppedAssistant));
104
186
  return {
187
+ observed: true,
105
188
  active: activeSignals.length > 0,
106
189
  stopped: stoppedSignals.length > 0,
107
- signals: [...activeSignals, ...stoppedSignals].slice(0, 5)
190
+ signals: [...new Set([...activeSignals, ...stoppedSignals])].slice(0, 5)
191
+ };
192
+ }
193
+ function serializedStopButtonCandidates(html) {
194
+ const stack = [];
195
+ const buttons = [];
196
+ const activeComposers = new Set();
197
+ const voidElements = new Set([
198
+ "area", "base", "br", "col", "embed", "hr", "img", "input", "link", "meta", "param", "source", "track", "wbr"
199
+ ]);
200
+ const hidden = (attributes) => /\b(?:hidden|inert)\b/i.test(attributes)
201
+ || /\baria-hidden\s*=\s*["']?true/i.test(attributes)
202
+ || /\bstyle\s*=\s*["'][^"']*(?:display\s*:\s*none|visibility\s*:\s*hidden|opacity\s*:\s*0)/i.test(attributes);
203
+ const hiddenInChain = (node) => {
204
+ for (let current = node; current !== undefined; current = current.parent) {
205
+ if (hidden(current.attributes))
206
+ return true;
207
+ }
208
+ return false;
108
209
  };
210
+ const isComposerMetadata = (node) => /\b(?:data-testid|aria-label|class)\s*=\s*["'][^"']*composer/i.test(node.attributes);
211
+ const isTextbox = (node) => node.tag === "textarea"
212
+ || /\bcontenteditable\s*=\s*["']?true/i.test(node.attributes)
213
+ || /\brole\s*=\s*["']textbox["']/i.test(node.attributes);
214
+ for (const match of html.matchAll(/<!--[\s\S]*?-->|<![^>]*>|<\/?[a-z0-9-]+\b[^>]*>|[^<]+/gi)) {
215
+ const token = match[0];
216
+ const closing = /^<\/([a-z0-9-]+)/i.exec(token);
217
+ if (closing?.[1] !== undefined) {
218
+ const tag = closing[1].toLowerCase();
219
+ const index = stack.map(node => node.tag).lastIndexOf(tag);
220
+ if (index >= 0)
221
+ stack.splice(index);
222
+ continue;
223
+ }
224
+ const opening = /^<([a-z0-9-]+)\b([^>]*)>/i.exec(token);
225
+ if (opening?.[1] !== undefined) {
226
+ const node = {
227
+ tag: opening[1].toLowerCase(),
228
+ attributes: opening[2] ?? "",
229
+ parent: stack.at(-1),
230
+ text: ""
231
+ };
232
+ if (node.tag === "button")
233
+ buttons.push(node);
234
+ if (isTextbox(node) && !hiddenInChain(node)) {
235
+ const ancestors = [...stack].reverse();
236
+ const composer = ancestors.find(ancestor => ancestor.tag === "form")
237
+ ?? ancestors.find(isComposerMetadata);
238
+ if (composer !== undefined && !hiddenInChain(composer))
239
+ activeComposers.add(composer);
240
+ }
241
+ if (!voidElements.has(node.tag) && !/\/\s*>$/.test(token))
242
+ stack.push(node);
243
+ continue;
244
+ }
245
+ for (let index = stack.length - 1; index >= 0; index -= 1) {
246
+ if (stack[index].tag === "button") {
247
+ stack[index].text += ` ${token}`;
248
+ break;
249
+ }
250
+ }
251
+ }
252
+ const activeComposer = activeComposers.size === 1 ? [...activeComposers][0] : undefined;
253
+ return buttons.map(button => {
254
+ let scoped = false;
255
+ for (let current = button.parent; current !== undefined; current = current.parent) {
256
+ if (current === activeComposer) {
257
+ scoped = true;
258
+ break;
259
+ }
260
+ }
261
+ return {
262
+ attributes: button.attributes,
263
+ text: button.text,
264
+ scoped,
265
+ hidden: hiddenInChain(button),
266
+ disabled: /\bdisabled(?:\s|=|$)/i.test(button.attributes)
267
+ || /\baria-disabled\s*=\s*["']?true/i.test(button.attributes)
268
+ };
269
+ });
109
270
  }
@@ -4,19 +4,24 @@
4
4
  *
5
5
  * Some non-Intelligence surfaces may still fall back to English + `selector_drift`.
6
6
  *
7
- * Intelligence picker labels updated 2026-06-10, stop-control labels updated 2026-06-15, and Chat/Work surface labels updated 2026-07-17 from visible ChatGPT sessions.
7
+ * Intelligence picker labels updated 2026-06-10, stop-control labels updated 2026-06-15, Chat/Work surface labels updated 2026-07-17, and Power/Advanced selector labels updated 2026-08-08 from visible ChatGPT sessions.
8
8
  */
9
9
  export declare const am: {
10
10
  configurationAxes: {
11
+ power: string[];
11
12
  model: string[];
12
13
  effort: string[];
13
14
  speed: string[];
15
+ advanced: string[];
14
16
  };
15
17
  configurationOptions: {
18
+ instant: string[];
16
19
  light: string[];
17
20
  medium: string[];
18
21
  high: string[];
19
22
  extraHigh: string[];
23
+ max: string[];
24
+ ultra: string[];
20
25
  standard: string[];
21
26
  fast: string[];
22
27
  };
@@ -37,6 +42,10 @@ export declare const am: {
37
42
  extraHigh: string[];
38
43
  };
39
44
  modeOpenerExtra: string[];
45
+ experienceOptions: {
46
+ chat: string[];
47
+ work: string[];
48
+ };
40
49
  tools: {
41
50
  web_search: string[];
42
51
  deep_research: string[];
@@ -4,19 +4,24 @@
4
4
  *
5
5
  * Some non-Intelligence surfaces may still fall back to English + `selector_drift`.
6
6
  *
7
- * Intelligence picker labels updated 2026-06-10, stop-control labels updated 2026-06-15, and Chat/Work surface labels updated 2026-07-17 from visible ChatGPT sessions.
7
+ * Intelligence picker labels updated 2026-06-10, stop-control labels updated 2026-06-15, Chat/Work surface labels updated 2026-07-17, and Power/Advanced selector labels updated 2026-08-08 from visible ChatGPT sessions.
8
8
  */
9
9
  export const am = {
10
10
  configurationAxes: {
11
+ power: ["አቅም"],
11
12
  model: ["ሞዴል"],
12
13
  effort: ["ጥረት"],
13
14
  speed: ["ፍጥነት"],
15
+ advanced: ["የላቀ"],
14
16
  },
15
17
  configurationOptions: {
18
+ instant: ["ፈጣን"],
16
19
  light: ["ቀላል"],
17
20
  medium: ["መካከለኛ"],
18
21
  high: ["ከፍተኛ"],
19
22
  extraHigh: ["እጅግ ከፍተኛ"],
23
+ max: ["ከፍተኛው"],
24
+ ultra: ["አልትራ"],
20
25
  standard: ["መደበኛ"],
21
26
  fast: ["ፈጣን"],
22
27
  },
@@ -37,6 +42,10 @@ export const am = {
37
42
  extraHigh: ["እጅግ ከፍተኛ"],
38
43
  },
39
44
  modeOpenerExtra: ["ያዋቅሩ"],
45
+ experienceOptions: {
46
+ chat: ["ውይይት"],
47
+ work: ["ሥራ"],
48
+ },
40
49
  tools: {
41
50
  web_search: ["የድር ፍለጋ"],
42
51
  deep_research: ["ጥልቅ ምርምር"],
@@ -4,15 +4,18 @@
4
4
  *
5
5
  * Some non-Intelligence surfaces may still fall back to English + `selector_drift`.
6
6
  *
7
- * Intelligence picker labels updated 2026-06-10, stop-control labels updated 2026-06-15, and Chat/Work surface labels updated 2026-07-17 from visible ChatGPT sessions.
7
+ * Intelligence picker labels updated 2026-06-10, stop-control labels updated 2026-06-15, Chat/Work surface labels updated 2026-07-17, and Power/Advanced selector labels updated 2026-08-08 from visible ChatGPT sessions.
8
8
  */
9
9
  export declare const ar: {
10
10
  configurationAxes: {
11
+ power: string[];
11
12
  model: string[];
12
13
  effort: string[];
13
14
  speed: string[];
15
+ advanced: string[];
14
16
  };
15
17
  configurationOptions: {
18
+ instant: string[];
16
19
  light: string[];
17
20
  medium: string[];
18
21
  high: string[];
@@ -38,6 +41,10 @@ export declare const ar: {
38
41
  pro: string[];
39
42
  };
40
43
  modeOpenerExtra: string[];
44
+ experienceOptions: {
45
+ chat: string[];
46
+ work: string[];
47
+ };
41
48
  tools: {
42
49
  web_search: string[];
43
50
  deep_research: string[];
@@ -4,20 +4,23 @@
4
4
  *
5
5
  * Some non-Intelligence surfaces may still fall back to English + `selector_drift`.
6
6
  *
7
- * Intelligence picker labels updated 2026-06-10, stop-control labels updated 2026-06-15, and Chat/Work surface labels updated 2026-07-17 from visible ChatGPT sessions.
7
+ * Intelligence picker labels updated 2026-06-10, stop-control labels updated 2026-06-15, Chat/Work surface labels updated 2026-07-17, and Power/Advanced selector labels updated 2026-08-08 from visible ChatGPT sessions.
8
8
  */
9
9
  export const ar = {
10
10
  configurationAxes: {
11
+ power: ["القدرة"],
11
12
  model: ["النموذج"],
12
13
  effort: ["الجهد"],
13
14
  speed: ["السرعة"],
15
+ advanced: ["متقدم"],
14
16
  },
15
17
  configurationOptions: {
18
+ instant: ["فوري"],
16
19
  light: ["خفيف"],
17
20
  medium: ["متوسط"],
18
21
  high: ["عالٍ"],
19
22
  extraHigh: ["عالٍ جدًا"],
20
- standard: ["قياسي"],
23
+ standard: ["قياسي", "قياسية"],
21
24
  fast: ["سريع"],
22
25
  },
23
26
  composerTextbox: ["الدردشة مع ChatGPT"],
@@ -38,6 +41,10 @@ export const ar = {
38
41
  pro: ["احترافي"],
39
42
  },
40
43
  modeOpenerExtra: ["تكوين"],
44
+ experienceOptions: {
45
+ chat: ["الدردشة"],
46
+ work: ["العمل"],
47
+ },
41
48
  tools: {
42
49
  web_search: ["البحث في الويب"],
43
50
  deep_research: ["البحث التفصيلي"],
@@ -4,19 +4,24 @@
4
4
  *
5
5
  * Some non-Intelligence surfaces may still fall back to English + `selector_drift`.
6
6
  *
7
- * Intelligence picker labels updated 2026-06-10, stop-control labels updated 2026-06-15, and Chat/Work surface labels updated 2026-07-17 from visible ChatGPT sessions.
7
+ * Intelligence picker labels updated 2026-06-10, stop-control labels updated 2026-06-15, Chat/Work surface labels updated 2026-07-17, and Power/Advanced selector labels updated 2026-08-08 from visible ChatGPT sessions.
8
8
  */
9
9
  export declare const bg: {
10
10
  configurationAxes: {
11
+ power: string[];
11
12
  model: string[];
12
13
  effort: string[];
13
14
  speed: string[];
15
+ advanced: string[];
14
16
  };
15
17
  configurationOptions: {
18
+ instant: string[];
16
19
  light: string[];
17
20
  medium: string[];
18
21
  high: string[];
19
22
  extraHigh: string[];
23
+ max: string[];
24
+ ultra: string[];
20
25
  standard: string[];
21
26
  fast: string[];
22
27
  };
@@ -4,19 +4,24 @@
4
4
  *
5
5
  * Some non-Intelligence surfaces may still fall back to English + `selector_drift`.
6
6
  *
7
- * Intelligence picker labels updated 2026-06-10, stop-control labels updated 2026-06-15, and Chat/Work surface labels updated 2026-07-17 from visible ChatGPT sessions.
7
+ * Intelligence picker labels updated 2026-06-10, stop-control labels updated 2026-06-15, Chat/Work surface labels updated 2026-07-17, and Power/Advanced selector labels updated 2026-08-08 from visible ChatGPT sessions.
8
8
  */
9
9
  export const bg = {
10
10
  configurationAxes: {
11
+ power: ["Мощност"],
11
12
  model: ["Модел"],
12
13
  effort: ["Усилие"],
13
14
  speed: ["Скорост"],
15
+ advanced: ["Разширени"],
14
16
  },
15
17
  configurationOptions: {
18
+ instant: ["Мигновен"],
16
19
  light: ["Кратко"],
17
20
  medium: ["Средно"],
18
21
  high: ["Високо"],
19
22
  extraHigh: ["Много високо"],
23
+ max: ["Максимално"],
24
+ ultra: ["Ултра"],
20
25
  standard: ["Стандартно"],
21
26
  fast: ["Бърза"],
22
27
  },
@@ -4,19 +4,24 @@
4
4
  *
5
5
  * Some non-Intelligence surfaces may still fall back to English + `selector_drift`.
6
6
  *
7
- * Intelligence picker labels updated 2026-06-10, stop-control labels updated 2026-06-15, and Chat/Work surface labels updated 2026-07-17 from visible ChatGPT sessions.
7
+ * Intelligence picker labels updated 2026-06-10, stop-control labels updated 2026-06-15, Chat/Work surface labels updated 2026-07-17, and Power/Advanced selector labels updated 2026-08-08 from visible ChatGPT sessions.
8
8
  */
9
9
  export declare const bn: {
10
10
  configurationAxes: {
11
+ power: string[];
11
12
  model: string[];
12
13
  effort: string[];
13
14
  speed: string[];
15
+ advanced: string[];
14
16
  };
15
17
  configurationOptions: {
18
+ instant: string[];
16
19
  light: string[];
17
20
  medium: string[];
18
21
  high: string[];
19
22
  extraHigh: string[];
23
+ max: string[];
24
+ ultra: string[];
20
25
  standard: string[];
21
26
  fast: string[];
22
27
  };
@@ -38,6 +43,10 @@ export declare const bn: {
38
43
  pro: string[];
39
44
  };
40
45
  modeOpenerExtra: string[];
46
+ experienceOptions: {
47
+ chat: string[];
48
+ work: string[];
49
+ };
41
50
  tools: {
42
51
  web_search: string[];
43
52
  deep_research: string[];
@@ -4,19 +4,24 @@
4
4
  *
5
5
  * Some non-Intelligence surfaces may still fall back to English + `selector_drift`.
6
6
  *
7
- * Intelligence picker labels updated 2026-06-10, stop-control labels updated 2026-06-15, and Chat/Work surface labels updated 2026-07-17 from visible ChatGPT sessions.
7
+ * Intelligence picker labels updated 2026-06-10, stop-control labels updated 2026-06-15, Chat/Work surface labels updated 2026-07-17, and Power/Advanced selector labels updated 2026-08-08 from visible ChatGPT sessions.
8
8
  */
9
9
  export const bn = {
10
10
  configurationAxes: {
11
+ power: ["ক্ষমতা"],
11
12
  model: ["মডেল"],
12
13
  effort: ["প্রচেষ্টা"],
13
14
  speed: ["গতি"],
15
+ advanced: ["উন্নত"],
14
16
  },
15
17
  configurationOptions: {
18
+ instant: ["তাৎক্ষণিক"],
16
19
  light: ["লাইট"],
17
20
  medium: ["মাঝারি"],
18
21
  high: ["উচ্চ"],
19
22
  extraHigh: ["অতি উচ্চ"],
23
+ max: ["সর্বোচ্চ"],
24
+ ultra: ["আল্ট্রা"],
20
25
  standard: ["স্ট্যান্ডার্ড"],
21
26
  fast: ["দ্রুত"],
22
27
  },
@@ -38,6 +43,10 @@ export const bn = {
38
43
  pro: ["প্রো"],
39
44
  },
40
45
  modeOpenerExtra: ["কনফিগার করুন..."],
46
+ experienceOptions: {
47
+ chat: ["চ্যাট"],
48
+ work: ["ওয়ার্ক"],
49
+ },
41
50
  tools: {
42
51
  web_search: ["ওয়েব সন্ধান"],
43
52
  deep_research: ["গভীর অনুসন্ধান"],
@@ -4,18 +4,22 @@
4
4
  *
5
5
  * Some non-Intelligence surfaces may still fall back to English + `selector_drift`.
6
6
  *
7
- * Intelligence picker labels updated 2026-06-10, stop-control labels updated 2026-06-15, and Chat/Work surface labels updated 2026-07-17 from visible ChatGPT sessions.
7
+ * Intelligence picker labels updated 2026-06-10, stop-control labels updated 2026-06-15, Chat/Work surface labels updated 2026-07-17, and Power/Advanced selector labels updated 2026-08-08 from visible ChatGPT sessions.
8
8
  */
9
9
  export declare const bs: {
10
10
  configurationAxes: {
11
+ power: string[];
11
12
  effort: string[];
12
13
  speed: string[];
14
+ advanced: string[];
13
15
  };
14
16
  configurationOptions: {
17
+ instant: string[];
15
18
  light: string[];
16
19
  medium: string[];
17
20
  high: string[];
18
21
  extraHigh: string[];
22
+ max: string[];
19
23
  standard: string[];
20
24
  fast: string[];
21
25
  };
@@ -4,18 +4,22 @@
4
4
  *
5
5
  * Some non-Intelligence surfaces may still fall back to English + `selector_drift`.
6
6
  *
7
- * Intelligence picker labels updated 2026-06-10, stop-control labels updated 2026-06-15, and Chat/Work surface labels updated 2026-07-17 from visible ChatGPT sessions.
7
+ * Intelligence picker labels updated 2026-06-10, stop-control labels updated 2026-06-15, Chat/Work surface labels updated 2026-07-17, and Power/Advanced selector labels updated 2026-08-08 from visible ChatGPT sessions.
8
8
  */
9
9
  export const bs = {
10
10
  configurationAxes: {
11
+ power: ["Snaga"],
11
12
  effort: ["Napor"],
12
13
  speed: ["Brzina"],
14
+ advanced: ["Napredno"],
13
15
  },
14
16
  configurationOptions: {
17
+ instant: ["Brzo"],
15
18
  light: ["Lagano"],
16
19
  medium: ["Srednja"],
17
20
  high: ["Visoka"],
18
21
  extraHigh: ["Veoma visoka"],
22
+ max: ["Maks."],
19
23
  standard: ["Standardno"],
20
24
  fast: ["Brzo"],
21
25
  },
@@ -4,18 +4,22 @@
4
4
  *
5
5
  * Some non-Intelligence surfaces may still fall back to English + `selector_drift`.
6
6
  *
7
- * Intelligence picker labels updated 2026-06-10, stop-control labels updated 2026-06-15, and Chat/Work surface labels updated 2026-07-17 from visible ChatGPT sessions.
7
+ * Intelligence picker labels updated 2026-06-10, stop-control labels updated 2026-06-15, Chat/Work surface labels updated 2026-07-17, and Power/Advanced selector labels updated 2026-08-08 from visible ChatGPT sessions.
8
8
  */
9
9
  export declare const ca: {
10
10
  configurationAxes: {
11
+ power: string[];
11
12
  effort: string[];
12
13
  speed: string[];
14
+ advanced: string[];
13
15
  };
14
16
  configurationOptions: {
17
+ instant: string[];
15
18
  light: string[];
16
19
  medium: string[];
17
20
  high: string[];
18
21
  extraHigh: string[];
22
+ max: string[];
19
23
  standard: string[];
20
24
  fast: string[];
21
25
  };
@@ -36,6 +40,9 @@ export declare const ca: {
36
40
  extraHigh: string[];
37
41
  };
38
42
  modeOpenerExtra: string[];
43
+ experienceOptions: {
44
+ chat: string[];
45
+ };
39
46
  tools: {
40
47
  web_search: string[];
41
48
  deep_research: string[];