@youdie006/prodex 0.40.29 → 0.40.31
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/README.md +1 -0
- package/dist/chatgpt-browser.js +24 -5
- package/dist/cli-help.js +3 -3
- package/dist/cli-pro.js +7 -1
- package/docs/releasing.md +105 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -253,6 +253,7 @@ prodex pro report-issue # a GitHub issue drafted from the blocked c
|
|
|
253
253
|
prodex pro report-issue --confirm # files it through gh; the prompt and the answer never travel
|
|
254
254
|
PRODEX_BROWSER_DIAGNOSTICS=1 prodex ask "..." # leaves a screenshot and a page-shape snapshot in .bridge/diagnostics/
|
|
255
255
|
node scripts/ui-watchdog.mjs # a real round trip that says ok or broken; --file-issue reports it
|
|
256
|
+
node scripts/ui-watchdog.mjs --canary # canary first, round trip only when the page changed; cheap enough to run hourly
|
|
256
257
|
```
|
|
257
258
|
|
|
258
259
|
Reports are deduplicated by blocker code, so something that stays broken adds to one issue. Captures stay on your machine.
|
package/dist/chatgpt-browser.js
CHANGED
|
@@ -256,6 +256,9 @@ export const CHATGPT_RENDERED_MESSAGE_TEXT_JS = `
|
|
|
256
256
|
const isBlock = (node) => node.nodeType === 1 && !skipped(node) &&
|
|
257
257
|
(BLOCK_TAGS.includes(tagOf(node)) || isCodeBlock(node) || (isMath(node) && isDisplayMath(node)) ||
|
|
258
258
|
(tagOf(node) === "span" && findAll(node, (n) => BLOCK_TAGS.includes(tagOf(n))).length > 0));
|
|
259
|
+
// The renderer web-search answers use since 2026-10-10 marks a source as a
|
|
260
|
+
// badge inside a popover trigger; its urls only exist once it is opened.
|
|
261
|
+
const isSourceBadge = (node) => attr(node, "data-d-component") === "popover-trigger" && findAll(node, (n) => attr(n, "data-pill") !== null).length > 0;
|
|
259
262
|
const pill = (node) => {
|
|
260
263
|
const label = collapse(node.textContent || "").trim();
|
|
261
264
|
if (!label) return "";
|
|
@@ -268,7 +271,7 @@ export const CHATGPT_RENDERED_MESSAGE_TEXT_JS = `
|
|
|
268
271
|
const piece = inlineNode(child);
|
|
269
272
|
if (!piece) continue;
|
|
270
273
|
// A source pill sits right after its sentence; keep one space before it.
|
|
271
|
-
if (child.nodeType === 1 && attr(child, "data-chatgpt-copy-reference") !== null && out && !isSpaceChar(out[out.length - 1])) out += " ";
|
|
274
|
+
if (child.nodeType === 1 && (attr(child, "data-chatgpt-copy-reference") !== null || isSourceBadge(child)) && out && !isSpaceChar(out[out.length - 1])) out += " ";
|
|
272
275
|
out += piece;
|
|
273
276
|
}
|
|
274
277
|
return out;
|
|
@@ -280,11 +283,12 @@ export const CHATGPT_RENDERED_MESSAGE_TEXT_JS = `
|
|
|
280
283
|
// A task list item's box (measured: button[role=checkbox][aria-checked]).
|
|
281
284
|
if (isCheckbox(node)) return (attr(node, "aria-checked") === "true" || attr(node, "checked") !== null ? "[x]" : "[ ]") + " ";
|
|
282
285
|
if (isMath(node)) return isDisplayMath(node) ? "$$" + mathSource(node) + "$$" : "$" + mathSource(node) + "$";
|
|
283
|
-
if (attr(node, "data-chatgpt-copy-reference") !== null) return pill(node);
|
|
286
|
+
if (attr(node, "data-chatgpt-copy-reference") !== null || isSourceBadge(node)) return pill(node);
|
|
284
287
|
if (attr(node, "data-markdown-copy") === "inline-code" || tag === "code") return BT + (node.textContent || "") + BT;
|
|
285
288
|
if (tag === "br") return NL;
|
|
286
289
|
const inner = inline(node);
|
|
287
|
-
|
|
290
|
+
// The newer renderer marks bold as span[data-d-default-strong].
|
|
291
|
+
if (tag === "strong" || tag === "b" || attr(node, "data-d-default-strong") !== null) return inner.trim() ? "**" + inner.trim() + "**" : "";
|
|
288
292
|
if (tag === "em" || tag === "i") return inner.trim() ? "*" + inner.trim() + "*" : "";
|
|
289
293
|
if (tag === "del" || tag === "s") return inner.trim() ? "~~" + inner.trim() + "~~" : "";
|
|
290
294
|
if (tag === "a") {
|
|
@@ -6059,8 +6063,23 @@ function chatGptRequestMarkerMatches(userText, requestId) {
|
|
|
6059
6063
|
}
|
|
6060
6064
|
/** Full prompt and per-send identity; wrappers may contain tool/file labels. */
|
|
6061
6065
|
export function chatGptRequestMatchesUserTurn(userText, sentPrompt, requestId) {
|
|
6062
|
-
|
|
6063
|
-
|
|
6066
|
+
if (!chatGptRequestMarkerMatches(userText, requestId))
|
|
6067
|
+
return false;
|
|
6068
|
+
if (normalizeChatGptPromptText(userText).includes(normalizeChatGptPromptText(sentPrompt)))
|
|
6069
|
+
return true;
|
|
6070
|
+
// The container's ChatGPT renders a sent turn as markdown since 2026-10-10:
|
|
6071
|
+
// a --file prompt's fence lines disappear and the inner fences shift, so
|
|
6072
|
+
// every such send posted and was then refused. Fence lines carry no request
|
|
6073
|
+
// text; everything else, punctuation and inline backticks included, must
|
|
6074
|
+
// still match in order.
|
|
6075
|
+
return withoutFenceLines(userText).includes(withoutFenceLines(sentPrompt));
|
|
6076
|
+
}
|
|
6077
|
+
function withoutFenceLines(value) {
|
|
6078
|
+
return value
|
|
6079
|
+
.replace(AUTOLINKED_URL_PATTERN, "$1")
|
|
6080
|
+
.replace(/\\([\\`*_{}[\]()#+\-.!>~|])/g, "$1")
|
|
6081
|
+
.replace(/^[ \t]*```[\w-]*[ \t]*$/gm, "")
|
|
6082
|
+
.replace(/\s+/g, "");
|
|
6064
6083
|
}
|
|
6065
6084
|
/**
|
|
6066
6085
|
* Does this transcript belong to the consult that is waiting on it?
|
package/dist/cli-help.js
CHANGED
|
@@ -22,7 +22,7 @@ Ask / consult commands:
|
|
|
22
22
|
prodex pro browser login [--cwd /absolute/path/to/repo] [--dry-run] [--source-cli /absolute/path/to/dist/cli.js] [--profile-dir path] [--port 9333] [--url https://chatgpt.com/...] [--launch-timeout-ms 5000] [--wait|--no-wait] [--headed|--headless|--minimized|--virtual-display] [--wait-timeout-ms 300000] [--background] [--recover-visible] # preview/open browser login
|
|
23
23
|
prodex pro browser help [--source-cli /absolute/path/to/dist/cli.js]
|
|
24
24
|
prodex pro browser check [--source-cli /absolute/path/to/dist/cli.js] [--cwd /absolute/path/to/repo] [--port 9333] [--timeout-ms 1500]
|
|
25
|
-
prodex pro browser smoke [--source-cli /absolute/path/to/dist/cli.js] [--cwd /absolute/path/to/repo] [--port 9333] [--timeout-ms
|
|
25
|
+
prodex pro browser smoke [--source-cli /absolute/path/to/dist/cli.js] [--cwd /absolute/path/to/repo] [--port 9333] [--timeout-ms 300000]
|
|
26
26
|
prodex pro browser models [--source-cli /absolute/path/to/dist/cli.js] [--port 9333] [--timeout-ms 15000] # read-only list of model menu options
|
|
27
27
|
prodex pro browser projects [--source-cli /absolute/path/to/dist/cli.js] [--port 9333] [--timeout-ms 15000] # read-only list of sidebar project names (for --project)
|
|
28
28
|
prodex pro browser recover [--source-cli /absolute/path/to/dist/cli.js] [--cwd /absolute/path/to/repo] [--port 9333] --target-url <thread-url> [--request-id 32hex] [--timeout-ms 60000] # recover a finished answer from a timed-out request
|
|
@@ -257,8 +257,8 @@ export function printProBrowserHelp(stdout, sourceCli) {
|
|
|
257
257
|
? `${cli} pro browser check${sourceCliOption} [--cwd /absolute/path/to/repo] [--port 9333] [--timeout-ms 1500]`
|
|
258
258
|
: "prodex pro browser check [--source-cli /absolute/path/to/dist/cli.js] [--cwd /absolute/path/to/repo] [--port 9333] [--timeout-ms 1500]";
|
|
259
259
|
const smokeUsage = sourceCli
|
|
260
|
-
? `${cli} pro browser smoke${sourceCliOption} [--cwd /absolute/path/to/repo] [--port 9333] [--timeout-ms
|
|
261
|
-
: "prodex pro browser smoke [--source-cli /absolute/path/to/dist/cli.js] [--cwd /absolute/path/to/repo] [--port 9333] [--timeout-ms
|
|
260
|
+
? `${cli} pro browser smoke${sourceCliOption} [--cwd /absolute/path/to/repo] [--port 9333] [--timeout-ms 300000]`
|
|
261
|
+
: "prodex pro browser smoke [--source-cli /absolute/path/to/dist/cli.js] [--cwd /absolute/path/to/repo] [--port 9333] [--timeout-ms 300000]";
|
|
262
262
|
const selectionUsage = '[--model Pro] [--pro-mode 기본|확장] [--effort 즉시|중간|높음|"매우 높음"|Max|Ultra|Pro] [--project "name" | --project-new "name"]';
|
|
263
263
|
const askUsage = sourceCli
|
|
264
264
|
? `${cli} pro browser ask${sourceCliOption} [--cwd /absolute/path/to/repo] [--session-key id] [--port 9333] [--timeout-ms 300000] [--busy-wait-ms 600000] [--target-url url --confirm-target] [--new-chat] [--continue | --continue-task task_id] [--temporary] [--allow-model-fallback] [--stdin] [--json] [--auto-login|--no-auto-login] [--file path] [--attach path] [--tool deep-research|web-search|create-image] ${selectionUsage} "prompt"`
|
package/dist/cli-pro.js
CHANGED
|
@@ -58,7 +58,9 @@ export async function runChatgptCommand(rest, io) {
|
|
|
58
58
|
const targetStore = new BridgeStore(targetCwd);
|
|
59
59
|
const sourceCli = resolveOptionalFileFlag(io.cwd, chatgptArgs, "--source-cli");
|
|
60
60
|
const port = resolveCdpPort(readPortFlag(chatgptArgs, "--port"));
|
|
61
|
-
|
|
61
|
+
// 5 minutes: the smoke runs on whatever effort the picker holds, and on a
|
|
62
|
+
// high one the 90 s it had timed out (six watchdog reports on issue #4).
|
|
63
|
+
const timeoutMs = readPositiveIntegerFlag(chatgptArgs, "--timeout-ms") ?? 300000;
|
|
62
64
|
const commandOptions = {
|
|
63
65
|
...(readFlag(chatgptArgs, "--cwd") ? { cwd: targetCwd } : {}),
|
|
64
66
|
...(readFlag(chatgptArgs, "--port") ? { port } : {})
|
|
@@ -103,6 +105,10 @@ export async function runChatgptCommand(rest, io) {
|
|
|
103
105
|
port,
|
|
104
106
|
prompt: smokePrompt,
|
|
105
107
|
timeoutMs,
|
|
108
|
+
// A fresh chat: without it the smoke prompt landed in whatever
|
|
109
|
+
// conversation was open (measured 2026-10-08), which the daily
|
|
110
|
+
// watchdog would do to someone's thread.
|
|
111
|
+
newChat: true,
|
|
106
112
|
onProgress: createBrowserSendProgressPrinter(io.stderr)
|
|
107
113
|
}));
|
|
108
114
|
}
|
package/docs/releasing.md
CHANGED
|
@@ -16,6 +16,111 @@ 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
|
+
## Browser Container Rebuild 2026-10-10
|
|
20
|
+
|
|
21
|
+
**Patches**
|
|
22
|
+
- `container/redesign-patches` `5047ef9` ports 0.40.28-0.40.30 and PR #23 (newer answer renderer, sent turn drawn as markdown) onto the container branch. It is based on `b5eac7d`; `feat/headless-browser-compatibility` itself is unchanged.
|
|
23
|
+
|
|
24
|
+
**Image**
|
|
25
|
+
- `547e852632b5`, built from `5047ef9`; the branch suite passed (2027 passed, 3 skipped).
|
|
26
|
+
- Both swaps were gated on the send lock being free. After the swap the browser had no ChatGPT tab, so `prodex pro browser login --wait` reopened it (logged in, 3 s). MCP clients of the container need `/mcp` reconnects.
|
|
27
|
+
|
|
28
|
+
**Verified live**
|
|
29
|
+
- Image `9b51e0639a37` (the port without the fence fix): web search with bold and `[GitHub+1]` badges, continued and temporary attach, recover, models (the picker now lists GPT-6), smoke in a new chat, `pro list` in 5 s. A Markdown `--file` send posted but was refused as unverified: the container's ChatGPT drew the sent turn as markdown and dropped the ```` ```text ```` fence line.
|
|
30
|
+
- Image `547e852632b5`: the same `--file` send answered 2/2, and the smoke answered `PRODEX_PRO_SMOKE_OK`.
|
|
31
|
+
|
|
32
|
+
**Not a bug**
|
|
33
|
+
- A host 0.40.30 `--file` run failed during this check only because another send held the browser lock past its wait budget; the next run answered.
|
|
34
|
+
|
|
35
|
+
## 0.40.30 Release Record
|
|
36
|
+
|
|
37
|
+
Release commit `e566efc` on `main` (cut after PR #22, merge `c0964f2`, plus the docs commit `09e80bc`); tag `v0.40.30`.
|
|
38
|
+
|
|
39
|
+
**Publishing**
|
|
40
|
+
- `publish.yml` run 37798469373 passed all six platforms on the first attempt, then npm publish with SLSA v1 provenance and the GitHub Release (2026-10-08 15:32 UTC).
|
|
41
|
+
- `npm run release:verify` passed on the release commit after a build.
|
|
42
|
+
|
|
43
|
+
**What it fixes**
|
|
44
|
+
- `pro browser smoke` always uses a fresh chat instead of whatever conversation was open.
|
|
45
|
+
- Its default budget is 5 minutes instead of 90 s.
|
|
46
|
+
- The page canary and the watchdog changes from the same PR are maintainer tooling and are not in the package. See Maintainer Watchdog.
|
|
47
|
+
|
|
48
|
+
**Installation on 2026-10-09**
|
|
49
|
+
- Global npm with `--prefer-online`, each verified with `prodex --version` = 0.40.30.
|
|
50
|
+
- WSL, M3, Mac mini: installed. Running services were not restarted: 21 stdio MCP servers on WSL and 10 on M3 keep older code until their clients reconnect. The Mac mini had none running.
|
|
51
|
+
- M4: not reachable (hostname does not resolve); not updated.
|
|
52
|
+
|
|
53
|
+
**Live check after install (installed 0.40.30, shared WSL browser)**
|
|
54
|
+
- With the tab on an existing conversation, `pro browser smoke` answered `PRODEX_PRO_SMOKE_OK` in a new conversation, not the open one.
|
|
55
|
+
- A new-chat attachment answered.
|
|
56
|
+
- The hourly watchdog had already logged `canary: ok` runs for build `4c511f80`.
|
|
57
|
+
|
|
58
|
+
## Maintainer Watchdog
|
|
59
|
+
|
|
60
|
+
On the maintainer's WSL machine, cron runs the UI watchdog every hour (since 2026-10-08):
|
|
61
|
+
|
|
62
|
+
```
|
|
63
|
+
17 * * * * PATH=<node bin>:/usr/bin:/bin PRODEX_CLI=~/.local/share/prodex-maint/prodex PRODEX_WATCHDOG_CWD=/mnt/d/MyProject/gptprouse <node> ~/.local/share/prodex-maint/repo/scripts/ui-watchdog.mjs --canary --file-issue >> ~/.local/state/prodex-watchdog.log 2>&1
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
**What each run does**
|
|
67
|
+
- It runs `scripts/page-canary.mjs`, which only reads the page:
|
|
68
|
+
- It records ChatGPT's build id and whether each control prodex relies on is present.
|
|
69
|
+
- It compares with `~/.local/share/prodex/page-canary.json`.
|
|
70
|
+
- It skips while a consult holds the send lock.
|
|
71
|
+
- Only when the canary reports changed (3) or broken (2) does the watchdog run `pro browser smoke` (a fresh chat, 5-minute budget). If that fails, it files or extends a GitHub issue by blocker code.
|
|
72
|
+
- A busy browser is logged as skipped and never filed.
|
|
73
|
+
|
|
74
|
+
**Where it runs from**
|
|
75
|
+
- `~/.local/share/prodex-maint/repo` is a clone of `main`, built with `npm ci && npm run build`.
|
|
76
|
+
- `~/.local/share/prodex-maint/prodex` runs its `dist/cli.js`, so the round trip uses current `main` rather than whatever version is installed.
|
|
77
|
+
|
|
78
|
+
**Updating it**
|
|
79
|
+
- After merging watchdog or smoke changes, run `git -C ~/.local/share/prodex-maint/repo pull --ff-only && (cd ~/.local/share/prodex-maint/repo && npm ci && npm run build)`.
|
|
80
|
+
|
|
81
|
+
**What it replaced**
|
|
82
|
+
- A daily 09:23 round trip run from the main checkout:
|
|
83
|
+
- It sent its prompt into whatever conversation was open.
|
|
84
|
+
- It timed out at 90 s on high efforts (issue #4).
|
|
85
|
+
- It filed a busy browser as broken (issue #20, closed as a false positive).
|
|
86
|
+
- The crontab before the change is saved at `~/.local/state/prodex-maint/crontab.backup-20261008`.
|
|
87
|
+
|
|
88
|
+
## 0.40.29 Release Record
|
|
89
|
+
|
|
90
|
+
Release commit `220d609` on `main` (cut after PR #19, merge `d0a7793`); tag `v0.40.29`.
|
|
91
|
+
|
|
92
|
+
**Publishing**
|
|
93
|
+
- `publish.yml` run 37717711177 passed all six platforms on the first attempt, then npm publish with SLSA v1 provenance (job log: `+ @youdie006/prodex@0.40.29` at 02:48:10 UTC) and the GitHub Release (2026-10-08 02:48 UTC).
|
|
94
|
+
- The registry served the new version about four minutes after the publish step.
|
|
95
|
+
- `npm run release:verify` passed on the release commit after a build.
|
|
96
|
+
|
|
97
|
+
**What it fixes**
|
|
98
|
+
- The CHANGELOG lists the full set: fixes found by a live feature hunt from 2026-10-06 to 2026-10-08.
|
|
99
|
+
- Also checked against ChatGPT's new build, which changed `html[data-build]` from `8089c0e4...` to `36d7890c...`. The core selectors still held. Code blocks moved from CodeMirror to plain `<pre><code>`, a `data-markdown-copy="blank-lines"` marker appeared, and a thread keeps its tool token in the composer. All three were exercised live and are handled.
|
|
100
|
+
|
|
101
|
+
**Installation on 2026-10-08**
|
|
102
|
+
- Global npm, each verified with `prodex --version` = 0.40.29.
|
|
103
|
+
- WSL, M3, Mac mini: installed. M3 and the Mac mini first reinstalled 0.40.28 from a stale registry view, and needed `--prefer-online`.
|
|
104
|
+
- Running services were not restarted: 7 stdio MCP servers on WSL and 10 on M3 keep older code until their clients reconnect. The Mac mini had none running.
|
|
105
|
+
- M4: not reachable (hostname does not resolve); not updated.
|
|
106
|
+
- The browser container still runs `container/redesign-patches` `1233603` (image `sha256:ce0240c0e8a4`), and does not have this release's fixes.
|
|
107
|
+
|
|
108
|
+
**Browser incidents on 2026-10-08, during the hunt**
|
|
109
|
+
- **Host tab crash:** the host browser's ChatGPT tab renderer crashed. `pro browser check` reported `browser_tab_crashed`, and the next send reloaded the tab once and answered.
|
|
110
|
+
- **Both browsers stopped at 00:31 UTC:** the host browser stopped entirely, and the browser container exited after its Chromium logged "GPU process exited unexpectedly: exit_code=15" three times and "GPU process isn't usable. Goodbye." The cause was not established.
|
|
111
|
+
- **Recovery:** the container was restarted with `up -d --no-build browser` and found the session READY. The host profile came back logged out; the user logged in through `--headed`, and the browser was relaunched on its virtual display.
|
|
112
|
+
- **Related defect found and fixed in this release:** host-side prodex counted the container's Chromium as its own browser. With the host browser down, `pro browser reset` offered to end 12 container processes. It was previewed only, and nothing was ended. Whether that path caused the 00:31 stop is not established: the host's automatic recovery matches by its recorded profile, which excludes the container.
|
|
113
|
+
|
|
114
|
+
**Live check after install (installed 0.40.29, shared WSL browser, new ChatGPT build)**
|
|
115
|
+
- Answered:
|
|
116
|
+
- new-chat attach
|
|
117
|
+
- project attach
|
|
118
|
+
- `--continue`
|
|
119
|
+
- markdown `--file`
|
|
120
|
+
- a formatted answer, with heading, numbered list and fenced code
|
|
121
|
+
- create-image
|
|
122
|
+
- `pro list` took 2.5 s on a repo with 260 consults; it had taken 238 s before this release.
|
|
123
|
+
|
|
19
124
|
## 0.40.28 Release Record
|
|
20
125
|
|
|
21
126
|
Release commit `8100c37` on `main` (cut after PR #18, merge `8afda89`); tag `v0.40.28`.
|