ask-pro 0.1.41 → 0.1.47

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.
@@ -385,7 +385,7 @@ async function pollAssistantCompletion(Runtime, timeoutMs, minTurnIndex, expecte
385
385
  async function isStopButtonVisible(Runtime) {
386
386
  try {
387
387
  const { result } = await Runtime.evaluate({
388
- expression: `Boolean(document.querySelector('${STOP_BUTTON_SELECTOR}'))`,
388
+ expression: visibleStopButtonExpression(JSON.stringify(STOP_BUTTON_SELECTOR)),
389
389
  returnByValue: true,
390
390
  });
391
391
  return Boolean(result?.value);
@@ -394,6 +394,13 @@ async function isStopButtonVisible(Runtime) {
394
394
  return false;
395
395
  }
396
396
  }
397
+ function visibleStopButtonExpression(selector) {
398
+ return `Array.from(document.querySelectorAll(${selector})).some((node) => {
399
+ const style = getComputedStyle(node);
400
+ const rect = node.getBoundingClientRect();
401
+ return rect.width > 0 && rect.height > 0 && style.visibility !== 'hidden' && style.display !== 'none' && style.opacity !== '0';
402
+ })`;
403
+ }
397
404
  async function isCompletionVisible(Runtime) {
398
405
  try {
399
406
  const { result } = await Runtime.evaluate({
@@ -676,7 +683,7 @@ function buildResponseObserverExpression(timeoutMs, minTurnIndex, expectedConver
676
683
  } else {
677
684
  stableCycles += 1;
678
685
  }
679
- const stopVisible = Boolean(document.querySelector(STOP_SELECTOR));
686
+ const stopVisible = ${visibleStopButtonExpression("STOP_SELECTOR")};
680
687
  const finishedVisible = isLastAssistantTurnFinished();
681
688
 
682
689
  if (finishedVisible || (!stopVisible && stableCycles >= stableTarget)) {
@@ -772,7 +779,7 @@ function buildAssistantExtractor(functionName) {
772
779
  button => (button.textContent || '').trim().toLowerCase() === 'stopped thinking',
773
780
  );
774
781
  if (index === turns.length - 1 && stopped && turnText.toLowerCase() === 'stopped thinking' &&
775
- !document.querySelector('${STOP_BUTTON_SELECTOR}')) {
782
+ !(${visibleStopButtonExpression(JSON.stringify(STOP_BUTTON_SELECTOR))})) {
776
783
  return { text: '', stoppedWithoutAnswer: true, turnIndex: index };
777
784
  }
778
785
  expandCollapsibles(messageRoot);
@@ -868,7 +875,7 @@ function buildMarkdownFallbackExtractor(minTurnLiteral) {
868
875
  document.querySelector('[role="main"]'),
869
876
  ].filter(Boolean);
870
877
  if (roots.length === 0) return null;
871
- const markdownSelector = '.markdown,[data-message-content],[data-testid*="message"],.prose,[class*="markdown"]';
878
+ const markdownSelector = 'div[class*="MarkdownRoot-"],.markdown,[data-message-content],[data-testid*="message"],.prose,[class*="markdown"]';
872
879
  const isExcluded = (node) =>
873
880
  Boolean(
874
881
  node?.querySelector?.('[data-streaming-response-status]') || node?.closest?.(
@@ -923,6 +930,7 @@ function buildMarkdownFallbackExtractor(minTurnLiteral) {
923
930
  };
924
931
  const markdowns = Array.from(root.querySelectorAll(markdownSelector))
925
932
  .filter((node) => !isExcluded(node))
933
+ .filter((node) => !node.closest('div[class*="MarkdownRoot-"]') || node.matches('div[class*="MarkdownRoot-"]'))
926
934
  .filter((node) => {
927
935
  const container = node.closest('[data-message-author-role], [data-turn]');
928
936
  if (!container) return true;
@@ -942,6 +950,7 @@ function buildMarkdownFallbackExtractor(minTurnLiteral) {
942
950
  if (!container || container === root || container === document.body) continue;
943
951
  const scoped = Array.from(container.querySelectorAll(markdownSelector))
944
952
  .filter((node) => !isExcluded(node))
953
+ .filter((node) => !node.closest('div[class*="MarkdownRoot-"]') || node.matches('div[class*="MarkdownRoot-"]'))
945
954
  .filter((node) => {
946
955
  const roleNode = node.closest('[data-message-author-role], [data-turn]');
947
956
  if (!roleNode) return true;
@@ -1242,4 +1251,5 @@ function cleanAssistantText(text) {
1242
1251
  export const __test__ = {
1243
1252
  buildResponseObserverExpression,
1244
1253
  recoverAssistantResponse,
1254
+ visibleStopButtonExpression,
1245
1255
  };
@@ -655,7 +655,8 @@ async function verifyPromptCommitted(Runtime, prompt, timeoutMs, logger, baselin
655
655
  const isVisible = (node) => {
656
656
  if (!node || typeof node.getBoundingClientRect !== 'function') return false;
657
657
  const rect = node.getBoundingClientRect();
658
- return rect.width > 0 && rect.height > 0;
658
+ const style = window.getComputedStyle(node);
659
+ return rect.width > 0 && rect.height > 0 && style.visibility !== 'hidden' && style.display !== 'none';
659
660
  };
660
661
  const inputs = inputSelectors
661
662
  .map((selector) => document.querySelector(selector))
@@ -674,7 +675,7 @@ async function verifyPromptCommitted(Runtime, prompt, timeoutMs, logger, baselin
674
675
  (normalizedPromptPrefix.length > 30 && lastTurn.includes(normalizedPromptPrefix)));
675
676
  const baseline = ${baselineLiteral};
676
677
  const hasNewTurn = baseline < 0 ? false : normalizedTurns.length > baseline;
677
- const stopVisible = Boolean(document.querySelector(${stopSelectorLiteral}));
678
+ const stopVisible = isVisible(document.querySelector(${stopSelectorLiteral}));
678
679
  const assistantVisible = Boolean(
679
680
  document.querySelector(${assistantSelectorLiteral}) ||
680
681
  document.querySelector('[data-testid*="assistant"]'),
@@ -737,8 +738,7 @@ async function verifyPromptCommitted(Runtime, prompt, timeoutMs, logger, baselin
737
738
  return typeof turnsCount === "number" && Number.isFinite(turnsCount) ? turnsCount : null;
738
739
  }
739
740
  const fallbackCommit = info?.composerCleared &&
740
- Boolean(info?.hasNewTurn) &&
741
- ((info?.stopVisible ?? false) || info?.assistantVisible || info?.inConversation);
741
+ (info?.stopVisible || (info?.hasNewTurn && (info?.assistantVisible || info?.inConversation)));
742
742
  if (fallbackCommit) {
743
743
  return typeof turnsCount === "number" && Number.isFinite(turnsCount) ? turnsCount : null;
744
744
  }
@@ -281,6 +281,7 @@ function buildThinkingTimeExpression(level) {
281
281
  const text = normalize(menu.textContent ?? '');
282
282
  const testId = normalize(menu.getAttribute?.('data-testid') ?? '');
283
283
  return (
284
+ Boolean(menu.querySelector('[data-reasoning-slider="true"] [role="slider"][aria-valuemax]')) ||
284
285
  testId.includes('composer intelligence picker content') ||
285
286
  (
286
287
  text.includes('intelligence') &&
@@ -297,22 +298,21 @@ function buildThinkingTimeExpression(level) {
297
298
  if (!menu) return null;
298
299
  const target = findOptionInMenu(menu, { currentIntelligence: true });
299
300
  if (!target) {
300
- const slider = menu.querySelector(
301
- '[data-model-reasoning-effort-slider] [role="slider"][aria-valuemax]'
302
- );
301
+ const slider = menu.querySelector('[role="slider"][aria-valuemax]');
303
302
  if (TARGET_LEVEL !== 'pro' || !slider) return null;
304
303
  const max = Number(slider.getAttribute('aria-valuemax'));
305
304
  const before = Number(slider.getAttribute('aria-valuenow'));
306
305
  if (!Number.isFinite(max) || !Number.isFinite(before)) return null;
307
306
  if (before < max) {
308
- slider.focus?.();
309
- slider.dispatchEvent(new KeyboardEvent('keydown', { key: 'End', code: 'End', bubbles: true }));
310
- slider.dispatchEvent(new KeyboardEvent('keyup', { key: 'End', code: 'End', bubbles: true }));
311
- await sleep(STEP_WAIT_MS);
312
- const updated = findCurrentIntelligenceMenu()?.querySelector(
313
- '[data-model-reasoning-effort-slider] [role="slider"][aria-valuemax]'
314
- ) ?? slider;
315
- if (Number(updated.getAttribute('aria-valuenow')) < max) return null;
307
+ const control = slider.closest?.('[data-reasoning-slider="true"]') ?? slider;
308
+ control.focus?.();
309
+ for (let step = 0; step < 5; step++) {
310
+ if (Number(menu.querySelector('[role="slider"][aria-valuemax]')?.getAttribute('aria-valuenow')) >= max) break;
311
+ control.dispatchEvent(new KeyboardEvent('keydown', { key: 'ArrowRight', code: 'ArrowRight', bubbles: true }));
312
+ control.dispatchEvent(new KeyboardEvent('keyup', { key: 'ArrowRight', code: 'ArrowRight', bubbles: true }));
313
+ await sleep(STEP_WAIT_MS);
314
+ }
315
+ if (Number(menu.querySelector('[role="slider"][aria-valuemax]')?.getAttribute('aria-valuenow')) < max) return null;
316
316
  }
317
317
  return { status: before >= max ? 'already-selected' : 'switched', label: 'Pro' };
318
318
  }
@@ -63,7 +63,7 @@ export const UPLOAD_STATUS_SELECTORS = [
63
63
  '[aria-live="polite"]',
64
64
  '[aria-live="assertive"]',
65
65
  ];
66
- export const STOP_BUTTON_SELECTOR = '[data-testid="stop-button"]';
66
+ export const STOP_BUTTON_SELECTOR = '[data-testid="stop-button"], button[aria-label="Stop"]';
67
67
  export const SEND_BUTTON_SELECTORS = [
68
68
  'button[data-testid="send-button"]',
69
69
  'button[data-testid*="composer-send"]',
@@ -72,7 +72,7 @@ export const SEND_BUTTON_SELECTORS = [
72
72
  'button[aria-label*="Send"]',
73
73
  ];
74
74
  export const SEND_BUTTON_SELECTOR = SEND_BUTTON_SELECTORS[0];
75
- export const MODEL_BUTTON_SELECTOR = '[data-testid="model-switcher-dropdown-button"], button.__composer-pill[aria-haspopup="menu"], button.__composer-pill';
75
+ export const MODEL_BUTTON_SELECTOR = 'button[aria-label="Select ChatGPT model"], [data-testid="model-switcher-dropdown-button"], button.__composer-pill[aria-haspopup="menu"], button.__composer-pill';
76
76
  export const COPY_BUTTON_SELECTORS = [
77
77
  'button[data-testid="copy-turn-action-button"]',
78
78
  'button[aria-label="Copy response"]',
@@ -851,13 +851,7 @@ export async function runBrowserMode(options) {
851
851
  logger(`[retry] Model picker attempt ${attempt + 1}: ${error instanceof Error ? error.message : error}`);
852
852
  }
853
853
  },
854
- })).catch((error) => {
855
- const base = error instanceof Error ? error.message : String(error);
856
- const hint = appliedCookies === 0
857
- ? " No cookies were applied; sign in to ChatGPT in the opened browser, then resume."
858
- : "";
859
- throw new Error(`${base}${hint}`);
860
- });
854
+ }));
861
855
  await raceWithDisconnect(ensurePromptReady(Runtime, config.inputTimeoutMs, logger));
862
856
  logger(`Prompt textarea ready (after model switch, ${promptText.length.toLocaleString()} chars queued)`);
863
857
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ask-pro",
3
- "version": "0.1.41",
3
+ "version": "0.1.47",
4
4
  "description": "Browser-backed ChatGPT Pro escalation for hard engineering questions.",
5
5
  "keywords": [
6
6
  "agents",