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
@@ -47,6 +47,7 @@ export async function inspectConfiguration(env, args = {}) {
47
47
  };
48
48
  }
49
49
  const experience = detected.data.experience;
50
+ const initialPanel = await readConfigurationPanel(page);
50
51
  const rootOpened = experience !== "unknown" && await waitForConfigurationRoot(page, experience, args.timeoutMs);
51
52
  if (rootOpened) {
52
53
  await page.waitForTimeout?.(150);
@@ -57,6 +58,9 @@ export async function inspectConfiguration(env, args = {}) {
57
58
  await page.waitForTimeout?.(150);
58
59
  }
59
60
  const panel = await readConfigurationPanel(page);
61
+ if (panel.openerLabel === undefined && initialPanel.openerLabel !== undefined) {
62
+ panel.openerLabel = initialPanel.openerLabel;
63
+ }
60
64
  const rootItems = rootOpened ? await enumerateVisibleMenuItems(page) : [];
61
65
  const data = configurationInspectionFromSurface(experience, detected.data.selectorProfile, detected.data.evidence, panel, rootItems);
62
66
  if (args.includeOptions !== false && experience === "work" && panel.axisRows.length > 0) {
@@ -468,12 +472,18 @@ async function openConfigurationRoot(page, experience) {
468
472
  }
469
473
  return true;
470
474
  };
471
- const composerRoots = Array.from(document.querySelectorAll("main form, main [data-testid*='composer' i], main [class*='composer' i]"));
475
+ const formRoots = Array.from(document.querySelectorAll("main form"));
476
+ const testIdRoots = Array.from(document.querySelectorAll("main [data-testid*='composer' i]"));
477
+ const classRoots = Array.from(document.querySelectorAll("main [class*='composer' i]"));
478
+ const composerRoots = formRoots.length > 0
479
+ ? formRoots
480
+ : testIdRoots.length > 0
481
+ ? testIdRoots
482
+ : classRoots;
472
483
  const main = document.querySelector("main");
473
- const roots = Array.from(new Set([
474
- ...composerRoots,
475
- ...(main === null ? [] : [main])
476
- ]));
484
+ const roots = Array.from(new Set(composerRoots.length > 0
485
+ ? composerRoots
486
+ : (main === null ? [] : [main])));
477
487
  const controls = Array.from(new Set(roots.flatMap(root => Array.from(root.querySelectorAll("button, [role='button']")))))
478
488
  .filter(visible);
479
489
  const matches = controls.filter(control => {
@@ -620,12 +630,18 @@ async function readConfigurationPanel(page) {
620
630
  break;
621
631
  }
622
632
  }
623
- const composerRoots = Array.from(document.querySelectorAll("main form, main [data-testid*='composer' i], main [class*='composer' i]"));
633
+ const formRoots = Array.from(document.querySelectorAll("main form"));
634
+ const testIdRoots = Array.from(document.querySelectorAll("main [data-testid*='composer' i]"));
635
+ const classRoots = Array.from(document.querySelectorAll("main [class*='composer' i]"));
636
+ const composerRoots = formRoots.length > 0
637
+ ? formRoots
638
+ : testIdRoots.length > 0
639
+ ? testIdRoots
640
+ : classRoots;
624
641
  const main = document.querySelector("main");
625
- const openerRoots = Array.from(new Set([
626
- ...composerRoots,
627
- ...(main === null ? [] : [main])
628
- ]));
642
+ const openerRoots = Array.from(new Set(composerRoots.length > 0
643
+ ? composerRoots
644
+ : (main === null ? [] : [main])));
629
645
  const openerCandidates = Array.from(new Set(openerRoots.flatMap(root => Array.from(root.querySelectorAll("button, [role='button']")))))
630
646
  .filter(visible)
631
647
  .map(control => {
@@ -665,12 +681,30 @@ async function clickVisibleMenuItem(page, item) {
665
681
  if (item.testId !== undefined && await clickIfUnique(page.locator?.(`[data-testid="${escapeAttributeValue(item.testId)}"]`))) {
666
682
  return true;
667
683
  }
668
- for (const role of ["menuitemradio", "menuitem", "option"]) {
684
+ const roles = [...new Set([
685
+ item.role,
686
+ "menuitemradio",
687
+ "menuitem",
688
+ "option"
689
+ ].filter((role) => role !== undefined))];
690
+ // Current Chat can expose visible text such as "Advanced" while assigning
691
+ // the actionable menu item a different accessible name (for example,
692
+ // "Show compact options"). Prefer that enumerated accessible name so the
693
+ // bridge clicks the menu item itself rather than a nested text span.
694
+ if (item.ariaLabel !== undefined) {
695
+ for (const role of roles) {
696
+ if (await clickIfUnique(page.getByRole?.(role, { name: item.ariaLabel, exact: true }))) {
697
+ return true;
698
+ }
699
+ }
700
+ }
701
+ for (const role of roles) {
669
702
  if (await clickIfUnique(page.getByRole?.(role, { name: item.label, exact: true }))) {
670
703
  return true;
671
704
  }
672
705
  }
673
- return clickIfUnique(page.getByText?.(item.label, { exact: true }));
706
+ const exactText = new RegExp(`^\\s*${escapeRegExp(item.label)}\\s*$`, "i");
707
+ return clickIfUnique(page.locator?.("button, [role='button'], [role='menuitem'], [role='menuitemradio'], [role='option']")?.filter?.({ hasText: exactText }));
674
708
  }
675
709
  function findConfigurationOption(items, requested) {
676
710
  const normalizedRequested = normalizeConfigurationId(requested);
@@ -1,2 +1,6 @@
1
1
  import type { CommandContext, PageLike } from "../types.js";
2
- export declare function contextFromPage(page: PageLike | undefined, partial?: Partial<CommandContext>): Promise<CommandContext>;
2
+ export type ContextReadOptions = {
3
+ /** Avoid all optional browser probes on mutation/deadline result paths. */
4
+ minimal?: boolean;
5
+ };
6
+ export declare function contextFromPage(page: PageLike | undefined, partial?: Partial<CommandContext>, options?: ContextReadOptions): Promise<CommandContext>;
@@ -1,8 +1,8 @@
1
1
  import { countPageMessages } from "../dom/messages.js";
2
2
  import { parseConversationId } from "../browser/page-state.js";
3
3
  import { withTimeout } from "./timeouts.js";
4
- export async function contextFromPage(page, partial = {}) {
5
- if (page === undefined) {
4
+ export async function contextFromPage(page, partial = {}, options = {}) {
5
+ if (page === undefined || options.minimal === true) {
6
6
  return { timestamp: new Date().toISOString(), ...partial };
7
7
  }
8
8
  const url = typeof page.url === "function" ? await Promise.resolve(page.url()).catch(() => partial.url) : partial.url;
@@ -1,17 +1,29 @@
1
1
  import { parseConversationId } from "../browser/page-state.js";
2
+ import { isChatGPTUrl, requireChatGPTUrl } from "../browser/chatgpt-url.js";
2
3
  import { countPageMessages, readLatestMessageText } from "../dom/messages.js";
3
4
  const CHATGPT_HOME = "https://chatgpt.com/";
4
5
  export async function ensureConversationTarget(page, target, options) {
5
6
  const targetUrl = absoluteConversationUrl(target);
7
+ requireChatGPTUrl(targetUrl, "Conversation target URL");
6
8
  const expectedConversationId = parseConversationId(targetUrl);
7
9
  const currentUrl = typeof page.url === "function" ? await Promise.resolve(page.url()).catch(() => "") : "";
8
- if (expectedConversationId !== undefined
10
+ if (isChatGPTUrl(typeof currentUrl === "string" ? currentUrl : "")
11
+ &&
12
+ expectedConversationId !== undefined
9
13
  && parseConversationId(typeof currentUrl === "string" ? currentUrl : "") === expectedConversationId) {
10
14
  await waitForConversationHydrated(page, options.timeoutMs, expectedConversationId);
11
15
  return ensureResult(false, targetUrl, expectedConversationId);
12
16
  }
13
17
  await page.goto?.(targetUrl, { waitUntil: "domcontentloaded", timeout: options.timeoutMs });
18
+ const navigatedUrl = typeof page.url === "function" ? await Promise.resolve(page.url()).catch(() => "") : "";
19
+ requireChatGPTUrl(typeof navigatedUrl === "string" ? navigatedUrl : "", "Conversation navigation result");
14
20
  await waitForConversationHydrated(page, options.timeoutMs, expectedConversationId);
21
+ const finalUrl = typeof page.url === "function" ? await Promise.resolve(page.url()).catch(() => "") : "";
22
+ requireChatGPTUrl(typeof finalUrl === "string" ? finalUrl : "", "Hydrated conversation URL");
23
+ if (expectedConversationId !== undefined
24
+ && parseConversationId(typeof finalUrl === "string" ? finalUrl : "") !== expectedConversationId) {
25
+ throw new Error(`Visible Chat navigation did not reach conversation ${expectedConversationId}.`);
26
+ }
15
27
  return ensureResult(true, targetUrl, expectedConversationId);
16
28
  }
17
29
  export async function waitForConversationHydrated(page, timeoutMs, expectedConversationId) {
@@ -33,6 +33,8 @@ const REQUIRED_LOCALE_KEYS = [
33
33
  ];
34
34
  const REQUIRED_TOOL_IDS = ["web_search", "deep_research", "create_image"];
35
35
  const REQUIRED_MODE_OPTION_IDS = ["latest", "instant", "thinking", "extended", "medium", "high", "extraHigh", "pro"];
36
+ const REQUIRED_CONFIGURATION_AXIS_IDS = ["power", "model", "intelligence", "effort", "speed", "advanced"];
37
+ const REQUIRED_CONFIGURATION_OPTION_IDS = ["instant", "light", "medium", "high", "extraHigh", "max", "ultra", "pro", "standard", "fast"];
36
38
  export async function doctor(env, args = {}) {
37
39
  const wanted = args.check ?? DEFAULT_CHECKS;
38
40
  const checks = {};
@@ -232,8 +234,14 @@ function localizationCheck(env) {
232
234
  const requiredKeysMissing = REQUIRED_LOCALE_KEYS.filter(key => localeLabels[key].length === 0);
233
235
  const missingToolIds = REQUIRED_TOOL_IDS.filter(id => (localeLabels.tools[id]?.length ?? 0) === 0);
234
236
  const missingModeOptionIds = REQUIRED_MODE_OPTION_IDS.filter(id => (localeLabels.modeOptions[id]?.length ?? 0) === 0);
237
+ const missingConfigurationAxisIds = REQUIRED_CONFIGURATION_AXIS_IDS
238
+ .filter(id => (localeLabels.configurationAxes[id]?.length ?? 0) === 0);
239
+ const missingConfigurationOptionIds = REQUIRED_CONFIGURATION_OPTION_IDS
240
+ .filter(id => (localeLabels.configurationOptions[id]?.length ?? 0) === 0);
235
241
  const toolIds = Object.keys(localeLabels.tools);
236
242
  const modeOptionIds = Object.keys(localeLabels.modeOptions);
243
+ const configurationAxisIds = Object.keys(localeLabels.configurationAxes);
244
+ const configurationOptionIds = Object.keys(localeLabels.configurationOptions);
237
245
  const proAliases = [...localeLabels.modeOptions.pro];
238
246
  const supportsProExtendedAlias = proAliases.some(alias => /pro\s*(?:•\s*)?extended/i.test(alias))
239
247
  && proAliases.some(alias => /extended\s+pro/i.test(alias));
@@ -250,17 +258,26 @@ function localizationCheck(env) {
250
258
  && localeLabels.sendButton[0] === "Send prompt"
251
259
  && localeLabels.modeLabels.includes("Thinking")
252
260
  && localeLabels.modeOptions.pro?.[0] === "Pro"
261
+ && localeLabels.configurationAxes.power?.[0] === "Power"
262
+ && localeLabels.configurationAxes.advanced?.[0] === "Advanced"
263
+ && localeLabels.configurationOptions.ultra?.[0] === "Ultra"
253
264
  && localeLabels.tools.web_search?.[0] === "Web search";
254
265
  const labelCandidateCount = REQUIRED_LOCALE_KEYS.reduce((total, key) => total + localeLabels[key].length, 0)
255
266
  + Object.values(localeLabels.tools).reduce((total, values) => total + values.length, 0)
256
- + Object.values(localeLabels.modeOptions).reduce((total, values) => total + values.length, 0);
267
+ + Object.values(localeLabels.modeOptions).reduce((total, values) => total + values.length, 0)
268
+ + Object.values(localeLabels.configurationAxes).reduce((total, values) => total + values.length, 0)
269
+ + Object.values(localeLabels.configurationOptions).reduce((total, values) => total + values.length, 0);
257
270
  const details = {
258
271
  englishCanonicalPresent,
259
272
  requiredKeysMissing,
260
273
  missingToolIds,
261
274
  missingModeOptionIds,
275
+ missingConfigurationAxisIds,
276
+ missingConfigurationOptionIds,
262
277
  toolIds,
263
278
  modeOptionIds,
279
+ configurationAxisIds,
280
+ configurationOptionIds,
264
281
  proAliases,
265
282
  supportsProExtendedAlias,
266
283
  runningStateLabelCoverage,
@@ -268,7 +285,12 @@ function localizationCheck(env) {
268
285
  pageAvailable: env.page !== undefined,
269
286
  runtimeSelectorCoverage: "registry_only_stage_2"
270
287
  };
271
- if (englishCanonicalPresent && requiredKeysMissing.length === 0 && missingToolIds.length === 0 && missingModeOptionIds.length === 0) {
288
+ if (englishCanonicalPresent
289
+ && requiredKeysMissing.length === 0
290
+ && missingToolIds.length === 0
291
+ && missingModeOptionIds.length === 0
292
+ && missingConfigurationAxisIds.length === 0
293
+ && missingConfigurationOptionIds.length === 0) {
272
294
  const runningStateMessage = runningStateLocalizationSupport === "complete"
273
295
  ? "running-state labels are present for every registered non-English locale"
274
296
  : runningStateLocalizationSupport === "partial"
@@ -3,3 +3,4 @@ export declare function validateAttachPaths(paths: string[]): Promise<AttachedFi
3
3
  export declare function preflightFiles(env: RuntimeEnv, args: FilePreflightArgs): Promise<CommandResult<FilePreflightData>>;
4
4
  export declare function attachFiles(env: RuntimeEnv, args: AttachFilesArgs): Promise<CommandResult<AttachFilesData>>;
5
5
  export declare function downloadLatestFile(env: RuntimeEnv, args: DownloadLatestArgs): Promise<CommandResult<DownloadedFile>>;
6
+ export declare function stripLocalizedDownloadPrefix(value: string, labels: readonly string[]): string;