@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 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.
@@ -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
- if (tag === "strong" || tag === "b") return inner.trim() ? "**" + inner.trim() + "**" : "";
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
- return chatGptRequestMarkerMatches(userText, requestId) &&
6063
- normalizeChatGptPromptText(userText).includes(normalizeChatGptPromptText(sentPrompt));
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 90000]
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 90000]`
261
- : "prodex pro browser smoke [--source-cli /absolute/path/to/dist/cli.js] [--cwd /absolute/path/to/repo] [--port 9333] [--timeout-ms 90000]";
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
- const timeoutMs = readPositiveIntegerFlag(chatgptArgs, "--timeout-ms") ?? 90000;
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`.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@youdie006/prodex",
3
- "version": "0.40.29",
3
+ "version": "0.40.31",
4
4
  "description": "Local receipt bus for coordinating Codex execution with ChatGPT Pro/Projects consultation.",
5
5
  "author": "youdie006",
6
6
  "license": "MIT",