@youdie006/prodex 0.37.1 → 0.38.0

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.
@@ -1736,6 +1736,31 @@ async function dispatchArrowKey(cdp, key) {
1736
1736
  await cdp.send("Input.dispatchKeyEvent", { type: "rawKeyDown", key, code, windowsVirtualKeyCode: virtualKey });
1737
1737
  await cdp.send("Input.dispatchKeyEvent", { type: "keyUp", key, code, windowsVirtualKeyCode: virtualKey });
1738
1738
  }
1739
+ /**
1740
+ * How to read every step of the slider and leave it as it was.
1741
+ *
1742
+ * The control shows one step at a time, and that single visible label was all
1743
+ * `pro browser models` ever reported - which is how a machine on this same
1744
+ * account concluded "Pro does not exist here" from five listings that each read
1745
+ * Instant / GPT-5.6 Sol / GPT-5.5, with the slider parked on Instant every
1746
+ * time. Seeing the rest means walking it, and walking someone's setting is only
1747
+ * acceptable if it is put back, so the plan always ends where it started.
1748
+ *
1749
+ * Refuses bounds that do not look like this control, so a misread never becomes
1750
+ * thousands of keystrokes in someone's browser.
1751
+ */
1752
+ export function sliderWalkPlan(state) {
1753
+ const { position, min, max } = state;
1754
+ if (!Number.isInteger(position) || !Number.isInteger(min) || !Number.isInteger(max))
1755
+ return undefined;
1756
+ const steps = max - min;
1757
+ if (steps < 1 || steps > 12)
1758
+ return undefined;
1759
+ if (position < min || position > max)
1760
+ return undefined;
1761
+ const offset = position - min;
1762
+ return { toBottom: offset, climb: steps, back: offset };
1763
+ }
1739
1764
  async function selectModelReasoning(cdp, options, selectionWarnings = []) {
1740
1765
  if (!options.model && !options.proMode && !options.effort)
1741
1766
  return;
@@ -3228,6 +3253,52 @@ export async function listChatGptSidebarProjects(input = {}) {
3228
3253
  }
3229
3254
  return { url: status.url, projects };
3230
3255
  }
3256
+ /**
3257
+ * Every step of the effort slider, read by walking it and putting it back.
3258
+ *
3259
+ * Best effort: a slider that cannot be focused, read or walked leaves the
3260
+ * listing exactly as it was rather than failing a read-only command.
3261
+ */
3262
+ async function readEffortSteps(cdp) {
3263
+ try {
3264
+ const focused = await cdp.evaluate(focusPowerSliderExpression());
3265
+ if (!focused?.ok)
3266
+ return undefined;
3267
+ const start = await cdp.evaluate(powerSliderStateExpression());
3268
+ if (!start?.ok)
3269
+ return undefined;
3270
+ const plan = sliderWalkPlan({ position: start.position, min: start.min, max: start.max });
3271
+ if (!plan)
3272
+ return undefined;
3273
+ const current = start.effort ?? null;
3274
+ for (let i = 0; i < plan.toBottom; i += 1) {
3275
+ await dispatchArrowKey(cdp, "ArrowLeft");
3276
+ await sleep(120);
3277
+ }
3278
+ const labels = [];
3279
+ const record = async () => {
3280
+ const state = await cdp.evaluate(powerSliderStateExpression());
3281
+ const label = state?.effort?.trim();
3282
+ if (label && !labels.includes(label))
3283
+ labels.push(label);
3284
+ };
3285
+ await record();
3286
+ for (let i = 0; i < plan.climb; i += 1) {
3287
+ await dispatchArrowKey(cdp, "ArrowRight");
3288
+ await sleep(120);
3289
+ await record();
3290
+ }
3291
+ // Put it back. Reading someone's setting must not change it.
3292
+ for (let i = 0; i < plan.climb - plan.back; i += 1) {
3293
+ await dispatchArrowKey(cdp, "ArrowLeft");
3294
+ await sleep(120);
3295
+ }
3296
+ return labels.length > 0 ? { labels, current } : undefined;
3297
+ }
3298
+ catch {
3299
+ return undefined;
3300
+ }
3301
+ }
3231
3302
  export async function listChatGptModelOptions(input = {}) {
3232
3303
  const port = resolveCdpPort(input.port);
3233
3304
  const timeoutMs = input.timeoutMs ?? 15_000;
@@ -3261,7 +3332,8 @@ export async function listChatGptModelOptions(input = {}) {
3261
3332
  if (!opened)
3262
3333
  throw new Error("ChatGPT model menu did not open after clicking the selector");
3263
3334
  const options = await cdp.evaluate(modelMenuOptionsExpression());
3264
- return { url: status.url, options };
3335
+ const effortSteps = await readEffortSteps(cdp);
3336
+ return { url: status.url, options, ...(effortSteps ? { effortSteps } : {}) };
3265
3337
  }
3266
3338
  finally {
3267
3339
  try {
package/dist/cli-pro.js CHANGED
@@ -447,7 +447,17 @@ export async function runProCommand(rest, io, runCliFn) {
447
447
  for (const option of listed.options) {
448
448
  io.stdout(formatModelMenuOption(option));
449
449
  }
450
- io.stdout("An arrow shows what that row is set to now; --model / --effort reach into those submenus (e.g. --model Pro).");
450
+ if (listed.effortSteps) {
451
+ io.stdout("");
452
+ io.stdout("Effort steps on this account (the slider was walked and put back):");
453
+ for (const label of listed.effortSteps.labels) {
454
+ io.stdout(`${label === listed.effortSteps.current ? "*" : " "} ${label}`);
455
+ }
456
+ io.stdout("Pass any of these to --effort. The list is complete: the slider shows one step at a time, so reading it any other way sees only the current one.");
457
+ }
458
+ else {
459
+ io.stdout("An arrow shows what that row is set to now; --model / --effort reach into those submenus (e.g. --model Pro).");
460
+ }
451
461
  return 0;
452
462
  }
453
463
  if (browserSubcommand === "projects") {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@youdie006/prodex",
3
- "version": "0.37.1",
3
+ "version": "0.38.0",
4
4
  "description": "Local receipt bus for coordinating Codex execution with ChatGPT Pro/Projects consultation.",
5
5
  "author": "youdie006",
6
6
  "license": "MIT",