@youdie006/prodex 0.40.33 → 0.40.35
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.
- package/dist/chatgpt-browser.js +46 -2
- package/docs/releasing.md +50 -0
- package/package.json +1 -1
package/dist/chatgpt-browser.js
CHANGED
|
@@ -2477,6 +2477,30 @@ export function menuItemRectExpression(label) {
|
|
|
2477
2477
|
return { ...point, role: it.getAttribute("role"), haspopup: it.getAttribute("aria-haspopup") };
|
|
2478
2478
|
})()`;
|
|
2479
2479
|
}
|
|
2480
|
+
/**
|
|
2481
|
+
* The picker's effort view covers its model rows: measured 2026-10-19, the
|
|
2482
|
+
* menu opens on a "Pro ›" label over the slider with GPT-6 and GPT-5.6 Sol
|
|
2483
|
+
* underneath, so a click on a model row hit the slider and was refused.
|
|
2484
|
+
* Clicking the label swaps in the model list. Reports whether that is needed
|
|
2485
|
+
* and where the label is; a row that can already be clicked needs nothing.
|
|
2486
|
+
*/
|
|
2487
|
+
export function pickerModelViewToggleExpression(label) {
|
|
2488
|
+
return `(() => {${CLICK_POINT_SNIPPET}
|
|
2489
|
+
const m = document.querySelector('[data-testid="composer-intelligence-picker-content"],[role="menu"]:has([role="slider"])');
|
|
2490
|
+
if (!m) return { needed: false };
|
|
2491
|
+
const items = [...m.querySelectorAll('[role="menuitemradio"],[role="menuitem"]')];
|
|
2492
|
+
const row = items.filter((item) => item.getAttribute("role") === "menuitemradio").find(${menuLabelMatchPredicate(label)});
|
|
2493
|
+
if (!row) return { needed: false };
|
|
2494
|
+
const r = row.getBoundingClientRect();
|
|
2495
|
+
const hit = document.elementFromPoint(r.x + r.width / 2, r.y + r.height / 2);
|
|
2496
|
+
if (hit && (hit === row || row.contains(hit))) return { needed: false };
|
|
2497
|
+
const toggle = items.find((item) =>
|
|
2498
|
+
item.getAttribute("role") === "menuitem" && item.getClientRects().length > 0 &&
|
|
2499
|
+
!item.querySelector('[role="slider"]') && (item.innerText || "").trim().length > 0);
|
|
2500
|
+
if (!toggle) return { needed: true, ok: false, reason: "the model rows are covered and no view label was found" };
|
|
2501
|
+
return { needed: true, ...clickPoint(toggle) };
|
|
2502
|
+
})()`;
|
|
2503
|
+
}
|
|
2480
2504
|
export function submenuItemRectExpression(label) {
|
|
2481
2505
|
return `(() => {${CLICK_POINT_SNIPPET}
|
|
2482
2506
|
const items = [...document.querySelectorAll('[role="menuitemradio"],[role="menuitem"]')];
|
|
@@ -2860,6 +2884,11 @@ async function selectPickerModel(cdp, requested, warnings = []) {
|
|
|
2860
2884
|
}
|
|
2861
2885
|
throw new Error(hit.reason ?? `ChatGPT's model picker has no "${requested}" model.`);
|
|
2862
2886
|
}
|
|
2887
|
+
const view = await cdp.evaluate(pickerModelViewToggleExpression(requested));
|
|
2888
|
+
if (view.needed && view.ok && view.x !== undefined && view.y !== undefined) {
|
|
2889
|
+
await verifiedClickAt(cdp, view.x, view.y, "the picker's model list");
|
|
2890
|
+
await sleep(400);
|
|
2891
|
+
}
|
|
2863
2892
|
await verifiedClickWithRetry(cdp, () => cdp.evaluate(menuItemRectExpression(requested)), requested);
|
|
2864
2893
|
}
|
|
2865
2894
|
/**
|
|
@@ -6093,8 +6122,23 @@ const NORMALIZED_PROMPT_MATCH_CHARS = 120;
|
|
|
6093
6122
|
// The composer can autolink a url before the send, storing "[url](url)" in
|
|
6094
6123
|
// place of the bare url (measured 2026-10-07, under load).
|
|
6095
6124
|
const AUTOLINKED_URL_PATTERN = /\[(https?:\/\/[^\]\s]+)\]\(\1\)/g;
|
|
6125
|
+
/**
|
|
6126
|
+
* ChatGPT displays a sent turn's HTML entities decoded (measured 2026-10-19:
|
|
6127
|
+
* "& <b>" was shown as "& <b>"), so both sides are compared decoded.
|
|
6128
|
+
*/
|
|
6129
|
+
function decodeHtmlEntities(value) {
|
|
6130
|
+
const named = { amp: "&", lt: "<", gt: ">", quot: '"', apos: "'", nbsp: " " };
|
|
6131
|
+
return value.replace(/&(#x[0-9a-f]+|#\d+|[a-z]+);/gi, (entity, body) => {
|
|
6132
|
+
const lower = body.toLowerCase();
|
|
6133
|
+
if (lower.startsWith("#")) {
|
|
6134
|
+
const code = lower.startsWith("#x") ? Number.parseInt(lower.slice(2), 16) : Number.parseInt(lower.slice(1), 10);
|
|
6135
|
+
return code > 0 && code <= 0x10ffff ? String.fromCodePoint(code) : entity;
|
|
6136
|
+
}
|
|
6137
|
+
return named[lower] ?? entity;
|
|
6138
|
+
});
|
|
6139
|
+
}
|
|
6096
6140
|
function normalizeChatGptPromptText(value) {
|
|
6097
|
-
const unescaped = value.replace(AUTOLINKED_URL_PATTERN, "$1").replace(/\\([\\`*_{}[\]()#+\-.!>~|])/g, "$1");
|
|
6141
|
+
const unescaped = decodeHtmlEntities(value).replace(AUTOLINKED_URL_PATTERN, "$1").replace(/\\([\\`*_{}[\]()#+\-.!>~|])/g, "$1");
|
|
6098
6142
|
const renderedFences = unescaped.replace(/(^|\r?\n)```text[ \t]*\r?\n([\s\S]*?)\r?\n```(?=\r?\n|$)/g, "$1text\n$2");
|
|
6099
6143
|
return renderedFences.replace(/\s+/g, " ").trim();
|
|
6100
6144
|
}
|
|
@@ -6125,7 +6169,7 @@ export function chatGptRequestMatchesUserTurn(userText, sentPrompt, requestId) {
|
|
|
6125
6169
|
return withoutFenceLines(userText).includes(withoutFenceLines(sentPrompt));
|
|
6126
6170
|
}
|
|
6127
6171
|
function withoutFenceLines(value) {
|
|
6128
|
-
return value
|
|
6172
|
+
return decodeHtmlEntities(value)
|
|
6129
6173
|
.replace(AUTOLINKED_URL_PATTERN, "$1")
|
|
6130
6174
|
.replace(/\\([\\`*_{}[\]()#+\-.!>~|])/g, "$1")
|
|
6131
6175
|
.replace(/^[ \t]*```[\w-]*[ \t]*$/gm, "")
|
package/docs/releasing.md
CHANGED
|
@@ -16,6 +16,56 @@ Release target: `v0.40.13` on `main`. The GitHub Release records the resolved co
|
|
|
16
16
|
|
|
17
17
|
The release adds a guarded, opt-in transition and more accurate blocker reporting. It does not claim that headless Pro consultation is verified on either deployment target or that authentication can be retained indefinitely.
|
|
18
18
|
|
|
19
|
+
## 0.40.34 Release Record
|
|
20
|
+
|
|
21
|
+
Release commit `574e5f0` on `main` (cut after PR #28, merge `1d93de4`); tag `v0.40.34`.
|
|
22
|
+
|
|
23
|
+
**Publishing**
|
|
24
|
+
- `publish.yml` run 39201678797 passed all six platforms on the first attempt, then npm publish with SLSA v1 provenance and the GitHub Release (2026-10-19 04:52 UTC).
|
|
25
|
+
- `npm run release:verify` passed on the release commit after a build.
|
|
26
|
+
|
|
27
|
+
**Installed**
|
|
28
|
+
- WSL, M3, Mac mini: `prodex --version` reports 0.40.34. Running services were not restarted: 10 stdio MCP servers on WSL and 2 on M3 keep older code until their clients reconnect. The Mac mini had none running.
|
|
29
|
+
- The maintainer watchdog checkout was pulled to `574e5f0` and rebuilt.
|
|
30
|
+
|
|
31
|
+
**Verified live**
|
|
32
|
+
- Host, installed 0.40.34: `--model "GPT-5.6 Sol" --effort Pro` and then `--model GPT-6 --effort Pro` both answered; the picker ended on GPT-6, 5/5 Pro. Installed 0.40.33 had refused the Sol selection ("another element covers its click point").
|
|
33
|
+
- Before the fix, on ChatGPT build `bfc3a09a` the host matrix passed: `--continue-task`, `--temporary`, `--tool web-search`, `--attach`, `--project`, `recover --request-id`, `--effort High`, `--model Pro`.
|
|
34
|
+
|
|
35
|
+
**Browser container**
|
|
36
|
+
- `container/redesign-patches` `ab1c6e1` ports PR #28. Image `a3746b490dbb`; branch suite 2038 passed, 3 skipped. Swapped under the send lock check; the ChatGPT tab opened on its own. Live: GPT-5.6 Sol then GPT-6 Pro both answered.
|
|
37
|
+
|
|
38
|
+
## 0.40.33 Release Record
|
|
39
|
+
|
|
40
|
+
Release commit `0497134` on `main` (cut after PR #27, merge `6083c6a`); tag `v0.40.33`.
|
|
41
|
+
|
|
42
|
+
**Publishing**
|
|
43
|
+
- `publish.yml` run 39181118204 passed all six platforms on the first attempt, then npm publish with SLSA v1 provenance and the GitHub Release (2026-10-19 00:51 UTC).
|
|
44
|
+
- `npm run release:verify` passed on the release commit after a build.
|
|
45
|
+
|
|
46
|
+
**Installed**
|
|
47
|
+
- WSL, M3, Mac mini: `prodex --version` reports 0.40.33. Running services were not restarted: 10 stdio MCP servers on WSL and 2 on M3 keep older code until their clients reconnect. The Mac mini had none running.
|
|
48
|
+
- The maintainer watchdog checkout was pulled to `0497134` and rebuilt.
|
|
49
|
+
|
|
50
|
+
**Verified live**
|
|
51
|
+
- With 0.40.33 installed, `login --virtual-display` on the affected machine printed the taken-port message for 9333 and left no Chrome running on the profile.
|
|
52
|
+
|
|
53
|
+
## Browser Incident 2026-10-18: Windows reserved port 9333
|
|
54
|
+
|
|
55
|
+
**What happened**
|
|
56
|
+
- The WSL machine restarted at 2026-10-18 18:08 KST. From 19:17 KST the hourly canary logged `skipped - the browser is not available`.
|
|
57
|
+
- The watchdog's first revive (19:17 KST) started Chrome, which loaded ChatGPT logged in but never opened its DevTools port; login reported "did not expose a reachable DevTools endpoint ... check the display, profile lock". Later revives refused the leftover Chrome as wedged (`ui_watchdog_revive=failed ... still running ... stopped answering`).
|
|
58
|
+
- The browser container was unaffected (port 9333 is inside its own network namespace).
|
|
59
|
+
|
|
60
|
+
**Cause**
|
|
61
|
+
- Windows (Hyper-V/WinNAT) reserved TCP ports 9240-9339 at boot (`netsh interface ipv4 show excludedportrange protocol=tcp`). The machine runs WSL with `networkingMode=mirrored`, so the reservation applies inside WSL, and Chrome logged `bind() failed: Address already in use` and `Cannot start http server for devtools`.
|
|
62
|
+
- The Windows TCP dynamic port range starts at 1024 (13,977 ports) instead of the default 49152, which lets these reservations land on 9333.
|
|
63
|
+
|
|
64
|
+
**Recovery and fixes**
|
|
65
|
+
- The leftover Chrome was ended with `prodex pro browser reset --confirm`. PR #27 (0.40.33) makes login close a browser whose control port never appears and name a taken port.
|
|
66
|
+
- Not changed: the Windows port settings. Bringing the host browser back needs an administrator on Windows: `net stop winnat` then `net start winnat` for now, and `netsh int ipv4 set dynamicport tcp start=49152 num=16384` (and `udp`) plus a restart to keep it from recurring. As of this record the range was still reserved and the host browser was down.
|
|
67
|
+
- Resolved 2026-10-19 11:51 KST: the maintainer ran the elevated script (`netsh int ipv4 set dynamicport tcp|udp start=49152 num=16384`, then `net stop winnat` / `net start winnat`). The 9240-9339 reservation was gone and 9333 could be bound. `login --virtual-display` was ready in 2 s; the canary reported the new ChatGPT build `bfc3a09a` as changed; the smoke answered `PRODEX_PRO_SMOKE_OK`, and a 500-line `--file` send on 0.40.33 answered correctly with the request verified.
|
|
68
|
+
|
|
19
69
|
## 0.40.32 Release Record
|
|
20
70
|
|
|
21
71
|
Release commit `e0e260e` on `main` (cut after PR #26, merge `f57f413`); tag `v0.40.32`.
|