@youdie006/prodex 0.16.15 → 0.16.17

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.
@@ -704,6 +704,34 @@ async function dispatchMouseClickAt(cdp, x, y) {
704
704
  await cdp.send("Input.dispatchMouseEvent", { type: "mousePressed", x, y, button: "left", clickCount: 1 });
705
705
  await cdp.send("Input.dispatchMouseEvent", { type: "mouseReleased", x, y, button: "left", clickCount: 1 });
706
706
  }
707
+ // Retry a hover-verified click whose point is transiently covered (menu/modal
708
+ // open-close animations, project navigation settling): re-locate FRESH
709
+ // coordinates each attempt. Persistent covers still fail with the refusal.
710
+ async function verifiedClickWithRetry(cdp, locate, label, deadlineMs = 5_000) {
711
+ const deadline = Date.now() + deadlineMs;
712
+ let hit = await locate();
713
+ for (;;) {
714
+ if (!hit.ok || hit.x === undefined || hit.y === undefined) {
715
+ if (Date.now() >= deadline) {
716
+ throw new Error(hit.reason ?? `${label} not found`);
717
+ }
718
+ await sleep(300);
719
+ hit = await locate();
720
+ continue;
721
+ }
722
+ try {
723
+ await verifiedClickAt(cdp, hit.x, hit.y, label);
724
+ return;
725
+ }
726
+ catch (error) {
727
+ const message = error instanceof Error ? error.message : String(error);
728
+ if (Date.now() >= deadline || !/Refusing to click/.test(message))
729
+ throw error;
730
+ await sleep(500);
731
+ hit = await locate();
732
+ }
733
+ }
734
+ }
707
735
  async function dispatchEscapeKey(cdp) {
708
736
  await cdp.send("Input.dispatchKeyEvent", { type: "keyDown", key: "Escape", code: "Escape", windowsVirtualKeyCode: 27 });
709
737
  await cdp.send("Input.dispatchKeyEvent", { type: "keyUp", key: "Escape", code: "Escape", windowsVirtualKeyCode: 27 });
@@ -972,7 +1000,7 @@ async function selectModelReasoning(cdp, options) {
972
1000
  // may never have typed --pro-mode - name the clear command too.
973
1001
  throw new Error("The ChatGPT model menu no longer offers Pro sub-modes (the 2026-07 update removed the Pro submenu; Pro is a single mode now). Use --model Pro instead of --pro-mode - and if this ask did not pass --pro-mode, a saved default is injecting it: run `prodex setup --clear-pro-mode`. If ChatGPT restores sub-modes, update prodex (npm i -g @youdie006/prodex@latest).");
974
1002
  }
975
- await verifiedClickAt(cdp, expander.x, expander.y, "Pro sub-mode expander");
1003
+ await verifiedClickWithRetry(cdp, () => cdp.evaluate(proSubmenuExpanderRectExpression()), "Pro sub-mode expander");
976
1004
  const subLabels = PRO_MODE_SUBMENU_LABELS[options.proMode];
977
1005
  const subVisible = await waitForExpressionTrue(cdp, menuItemPresentExpression(subLabels), MENU_OPEN_TIMEOUT_MS);
978
1006
  if (!subVisible)
@@ -981,7 +1009,7 @@ async function selectModelReasoning(cdp, options) {
981
1009
  if (!sub.ok || sub.x === undefined || sub.y === undefined) {
982
1010
  throw new Error(sub.reason ?? `ChatGPT Pro sub-mode not clickable: ${subLabels.join(" / ")}`);
983
1011
  }
984
- await verifiedClickAt(cdp, sub.x, sub.y, subLabels[0]);
1012
+ await verifiedClickWithRetry(cdp, () => cdp.evaluate(submenuItemRectExpression(subLabels)), subLabels[0]);
985
1013
  await assertSelectionCommitted(cdp, subLabels[0]);
986
1014
  return;
987
1015
  }
@@ -997,7 +1025,7 @@ async function selectModelReasoning(cdp, options) {
997
1025
  if (!proRadio.ok || proRadio.x === undefined || proRadio.y === undefined) {
998
1026
  throw new Error(proRadio.reason ?? "Pro option not found in the model menu");
999
1027
  }
1000
- await verifiedClickAt(cdp, proRadio.x, proRadio.y, "Pro");
1028
+ await verifiedClickWithRetry(cdp, () => cdp.evaluate(proRadioRectExpression()), "Pro");
1001
1029
  await assertSelectionCommitted(cdp, "Pro");
1002
1030
  return;
1003
1031
  }
@@ -1011,7 +1039,7 @@ async function selectModelReasoning(cdp, options) {
1011
1039
  if (primary.role === "menuitem" && primary.haspopup === "menu") {
1012
1040
  throw new Error(`ChatGPT model "${primaryLabel}" opens a submenu of variants instead of committing; selecting it is not supported yet. Supported today: reasoning efforts (--effort) and --model Pro.`);
1013
1041
  }
1014
- await verifiedClickAt(cdp, primary.x, primary.y, primaryLabel);
1042
+ await verifiedClickWithRetry(cdp, () => cdp.evaluate(menuItemRectExpression(primaryCandidates)), primaryLabel);
1015
1043
  await assertSelectionCommitted(cdp, primaryLabel);
1016
1044
  }
1017
1045
  catch (error) {
@@ -1141,7 +1169,7 @@ async function selectProject(cdp, options) {
1141
1169
  const detail = hit.reason && hit.reason !== "project not found in sidebar" ? ` (${hit.reason})` : "";
1142
1170
  throw new Error(`ChatGPT project not found in sidebar: ${options.project}${detail} List the visible names with \`prodex pro browser projects\`.`);
1143
1171
  }
1144
- await verifiedClickAt(cdp, hit.x, hit.y, `project ${options.project}`);
1172
+ await verifiedClickWithRetry(cdp, () => cdp.evaluate(projectItemRectExpression(options.project)), `project ${options.project}`);
1145
1173
  const navigated = await waitForExpressionTrue(cdp, `location.href !== ${JSON.stringify(hrefBefore)}`, PROJECT_NAVIGATION_TIMEOUT_MS);
1146
1174
  if (!navigated) {
1147
1175
  // The href staying put is fine ONLY when the tab was already on THIS
package/dist/cli-pro.js CHANGED
@@ -602,7 +602,12 @@ export async function runAskProCommand(rest, io) {
602
602
  const busyWaitMs = readPositiveIntegerFlag(parsedAskPro.optionArgs, "--busy-wait-ms");
603
603
  // Pro extended can legitimately think for minutes, so its default timeout is
604
604
  // higher; an explicit --timeout-ms always wins.
605
- const defaultBrowserTimeoutMs = selectionProMode === "확장" ? 300_000 : 90_000;
605
+ // Pro reasoning routinely runs for many minutes (a real consult measured
606
+ // ~13 minutes). The elevated default used to be keyed to the removed
607
+ // --pro-mode, so --model Pro sends fell back to 90s and chronically timed
608
+ // out. Any effective Pro selection now defaults to 15 minutes.
609
+ const effectiveProSelection = selectionProMode !== undefined || (selectionModel !== undefined && /pro/i.test(selectionModel));
610
+ const defaultBrowserTimeoutMs = effectiveProSelection ? 900_000 : 90_000;
606
611
  const browserTimeoutMs = hasSendMode
607
612
  ? (readPositiveIntegerFlag(parsedAskPro.optionArgs, "--timeout-ms") ?? defaultBrowserTimeoutMs)
608
613
  : undefined;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@youdie006/prodex",
3
- "version": "0.16.15",
3
+ "version": "0.16.17",
4
4
  "description": "Local receipt bus for coordinating Codex execution with ChatGPT Pro/Projects consultation.",
5
5
  "author": "youdie006",
6
6
  "license": "MIT",