@youdie006/prodex 0.40.26 → 0.40.27
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 +43 -2
- package/docs/releasing.md +46 -0
- package/package.json +1 -1
package/dist/chatgpt-browser.js
CHANGED
|
@@ -191,7 +191,40 @@ export const CHATGPT_BLOCKER_SCAN_EXCLUDED_ANCESTORS = `${'[data-message-author-
|
|
|
191
191
|
* sat in the thread for ten minutes while prodex waited for it. The model slug
|
|
192
192
|
* attribute went with it; where it is absent the model is simply not known.
|
|
193
193
|
*/
|
|
194
|
-
|
|
194
|
+
/**
|
|
195
|
+
* A message's text with its source pills spelled out.
|
|
196
|
+
*
|
|
197
|
+
* Measured 2026-10-06: ChatGPT renders each source as an inline pill
|
|
198
|
+
* ([data-chatgpt-copy-reference]) and innerText puts its label on a line of
|
|
199
|
+
* its own, so a page-read answer came back as "walnut-9" plus a line
|
|
200
|
+
* "cont-att", or ended in a bare "blog.rust-lang.org" that read as part of
|
|
201
|
+
* the answer. A web source becomes " [label](url)", as the transcript reader
|
|
202
|
+
* writes it; a file source has no link and becomes " [label]". The label is
|
|
203
|
+
* looked for on its own line first, so the same words earlier in the prose
|
|
204
|
+
* are left alone.
|
|
205
|
+
*/
|
|
206
|
+
export const CHATGPT_RENDERED_MESSAGE_TEXT_JS = `
|
|
207
|
+
const renderedMessageText = (root) => {
|
|
208
|
+
let text = root.innerText || "";
|
|
209
|
+
const newline = String.fromCharCode(10);
|
|
210
|
+
const isSpace = (ch) => ch === " " || ch === newline || ch === String.fromCharCode(9) || ch === String.fromCharCode(13);
|
|
211
|
+
let cursor = 0;
|
|
212
|
+
for (const pill of [...root.querySelectorAll('[data-chatgpt-copy-reference]')]) {
|
|
213
|
+
const label = (pill.innerText || "").trim();
|
|
214
|
+
if (!label) continue;
|
|
215
|
+
const onOwnLine = text.indexOf(newline + label, cursor);
|
|
216
|
+
const at = onOwnLine >= 0 ? onOwnLine + 1 : text.indexOf(label, cursor);
|
|
217
|
+
if (at < 0) continue;
|
|
218
|
+
let start = at;
|
|
219
|
+
while (start > cursor && isSpace(text[start - 1])) start -= 1;
|
|
220
|
+
const link = pill.querySelector('a[href^="http"]');
|
|
221
|
+
const rendered = link ? " [" + label + "](" + link.getAttribute("href") + ")" : " [" + label + "]";
|
|
222
|
+
text = text.slice(0, start) + rendered + text.slice(at + label.length);
|
|
223
|
+
cursor = start + rendered.length;
|
|
224
|
+
}
|
|
225
|
+
return text;
|
|
226
|
+
};`;
|
|
227
|
+
const CHATGPT_MESSAGE_NODES_JS = `${CHATGPT_RENDERED_MESSAGE_TEXT_JS}
|
|
195
228
|
// ChatGPT keeps a previously opened conversation mounted but hidden
|
|
196
229
|
// (measured 2026-10-06: two turns without a box on a project home), and
|
|
197
230
|
// counting them made a fresh chat look like an existing conversation.
|
|
@@ -3437,6 +3470,14 @@ export async function recoverChatGptAnswerFromThread(options) {
|
|
|
3437
3470
|
lastAnswer = "";
|
|
3438
3471
|
continue;
|
|
3439
3472
|
}
|
|
3473
|
+
// A thread that is still loading already has the target URL but no
|
|
3474
|
+
// turns (measured 2026-10-06), and judging the request on it refused a
|
|
3475
|
+
// recovery of the very request it was asked for.
|
|
3476
|
+
if (state.userMessageCount === 0) {
|
|
3477
|
+
stableRuns = 0;
|
|
3478
|
+
lastAnswer = "";
|
|
3479
|
+
continue;
|
|
3480
|
+
}
|
|
3440
3481
|
if (options.requestId && !chatGptRequestMarkerMatches(state.lastUserText ?? "", options.requestId)) {
|
|
3441
3482
|
throw new ChatGptBrowserBlockerError({
|
|
3442
3483
|
code: "request_mismatch",
|
|
@@ -6019,7 +6060,7 @@ export function answerExpression() {
|
|
|
6019
6060
|
const tagged = node.closest('[data-message-model-slug]');
|
|
6020
6061
|
if (tagged) modelSlug = tagged.getAttribute('data-message-model-slug') || undefined;
|
|
6021
6062
|
}
|
|
6022
|
-
return { role, node, text: textNode
|
|
6063
|
+
return { role, node, text: renderedMessageText(textNode), modelSlug };
|
|
6023
6064
|
});
|
|
6024
6065
|
const assistantMessages = messages.filter((message) => message.role === "assistant");
|
|
6025
6066
|
const userMessages = messages.filter((message) => message.role === "user");
|
package/docs/releasing.md
CHANGED
|
@@ -16,6 +16,52 @@ 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.26 Release Record
|
|
20
|
+
|
|
21
|
+
Release commit `b413c24` on `main` (cut after PR #16, merge `af5cf20`); tag `v0.40.26`.
|
|
22
|
+
|
|
23
|
+
**Publishing**
|
|
24
|
+
- `publish.yml` run 37405732176 passed all six platforms on the first attempt, then npm publish with SLSA v1 provenance and the GitHub Release (2026-10-06 03:07 UTC).
|
|
25
|
+
- PR #16's own CI needed one rerun on macOS Intel for an unrelated 30 s timeout in `tests/mcp-consult.test.ts`.
|
|
26
|
+
- `npm run release:verify` passed on the release commit after a build.
|
|
27
|
+
|
|
28
|
+
**What it fixes**
|
|
29
|
+
- The ChatGPT page measured on 2026-10-06 broke several flows:
|
|
30
|
+
- Every project send was refused because a hidden, still-mounted conversation was counted.
|
|
31
|
+
- Attachments did not recognize timestamp-renamed uploads, picked a hidden composer form, and ran before the file input existed.
|
|
32
|
+
- Leftover chips were no longer detected.
|
|
33
|
+
- Composer tools were looked up or clicked before they worked.
|
|
34
|
+
- Found by a live matrix against the installed 0.40.25, where `--project` sends, project attachments, new-chat attachments after a repeat upload and `--tool create-image` failed.
|
|
35
|
+
|
|
36
|
+
**Installation on 2026-10-06**
|
|
37
|
+
- Global npm, each verified with `prodex --version` = 0.40.26.
|
|
38
|
+
- WSL, M3, Mac mini: installed. Running services were not restarted: 11 stdio MCP servers on WSL and 6 on M3 keep older code until their clients reconnect. The Mac mini had none running.
|
|
39
|
+
- M4: not reachable (hostname does not resolve); not updated.
|
|
40
|
+
|
|
41
|
+
**Live check after install (installed 0.40.26, shared WSL browser)**
|
|
42
|
+
All eight answered:
|
|
43
|
+
- `--project` plain and with `--attach`
|
|
44
|
+
- `--tool create-image`
|
|
45
|
+
- `--new-chat --attach`
|
|
46
|
+
- `--continue --attach`
|
|
47
|
+
- `--tool web-search --attach`
|
|
48
|
+
- `--temporary --attach`
|
|
49
|
+
- plain `--continue`
|
|
50
|
+
|
|
51
|
+
**Browser container, same day**
|
|
52
|
+
- Before the rebuild, the container build failed the same way: a project send was refused and a new-chat attachment timed out. Its tab then stopped answering CDP.
|
|
53
|
+
- The same fixes were adapted to the branch code, where the transcript reader and the hover-verified tools click differ. The image `sha256:8e5734ee733c` was rebuilt from `b5eac7d` with all patches so far. These are still uncommitted, and nothing was pushed to `feat/headless-browser-compatibility`.
|
|
54
|
+
- Branch suite: 1998 passed. The swap was gated on the send lock being free.
|
|
55
|
+
- Verified in the container, all seven answered:
|
|
56
|
+
- a project send
|
|
57
|
+
- a new-chat attachment
|
|
58
|
+
- an attachment on a continued thread
|
|
59
|
+
- a project attachment
|
|
60
|
+
- create-image
|
|
61
|
+
- web search with an attachment
|
|
62
|
+
- a temporary chat with an attachment
|
|
63
|
+
- An MCP client reconnect was needed after the swap.
|
|
64
|
+
|
|
19
65
|
## 0.40.25 Release Record
|
|
20
66
|
|
|
21
67
|
Release commit `3c66da3` on `main` (cut after PR #15, merge `9bd908c`); tag `v0.40.25`.
|