@youdie006/prodex 0.40.34 → 0.40.36

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.
@@ -311,12 +311,19 @@ export const CHATGPT_RENDERED_MESSAGE_TEXT_JS = `
311
311
  }
312
312
  const lines = findAll(node, (n) => hasClass(n, "cm-line")).map((line) => line.textContent || "");
313
313
  const pre = tagOf(node) === "pre" ? node : findAll(node, (n) => tagOf(n) === "pre")[0];
314
- const code = fullCode !== null ? trimEnd(fullCode) : lines.length > 0 ? lines.join(NL) : trimEnd(pre ? pre.textContent || "" : node.textContent || "");
314
+ // Some blocks keep their text in a source element with no <pre>
315
+ // (measured 2026-10-19), and the whole block's text carries the toolbar.
316
+ const source = pre || findAll(node, (n) => attr(n, "data-code-block-source") !== null)[0];
317
+ const code = fullCode !== null ? trimEnd(fullCode) : lines.length > 0 ? lines.join(NL) : trimEnd(source ? source.textContent || "" : node.textContent || "");
315
318
  const editor = findAll(node, (n) => attr(n, "data-language") !== null)[0];
316
319
  const toolbar = findAll(node, (n) => attr(n, "data-markdown-copy") === "exclude")[0];
317
320
  const label = toolbar ? collapse(findAll(toolbar, (n) => n.nodeType === 1 && tagOf(n) === "div" && children(n).every((c) => c.nodeType === 3)).map((n) => n.textContent || "")[0] || "").trim() : "";
318
321
  const language = ((editor && attr(editor, "data-language")) || label).trim().toLowerCase();
319
- return BT + BT + BT + language + NL + code + NL + BT + BT + BT;
322
+ // A fence must be longer than any backtick run inside, or a block that
323
+ // shows a fenced example is closed early by it.
324
+ const longestRun = (code.match(new RegExp(BT + "+", "g")) || []).reduce((most, run) => Math.max(most, run.length), 0);
325
+ const fence = BT.repeat(Math.max(3, longestRun + 1));
326
+ return fence + language + NL + code + NL + fence;
320
327
  };
321
328
  const table = (node) => {
322
329
  const cell = (value) => collapse(value).trim().split("|").join(String.fromCharCode(92) + "|");
@@ -6122,8 +6129,23 @@ const NORMALIZED_PROMPT_MATCH_CHARS = 120;
6122
6129
  // The composer can autolink a url before the send, storing "[url](url)" in
6123
6130
  // place of the bare url (measured 2026-10-07, under load).
6124
6131
  const AUTOLINKED_URL_PATTERN = /\[(https?:\/\/[^\]\s]+)\]\(\1\)/g;
6132
+ /**
6133
+ * ChatGPT displays a sent turn's HTML entities decoded (measured 2026-10-19:
6134
+ * "&amp; &lt;b&gt;" was shown as "& <b>"), so both sides are compared decoded.
6135
+ */
6136
+ function decodeHtmlEntities(value) {
6137
+ const named = { amp: "&", lt: "<", gt: ">", quot: '"', apos: "'", nbsp: " " };
6138
+ return value.replace(/&(#x[0-9a-f]+|#\d+|[a-z]+);/gi, (entity, body) => {
6139
+ const lower = body.toLowerCase();
6140
+ if (lower.startsWith("#")) {
6141
+ const code = lower.startsWith("#x") ? Number.parseInt(lower.slice(2), 16) : Number.parseInt(lower.slice(1), 10);
6142
+ return code > 0 && code <= 0x10ffff ? String.fromCodePoint(code) : entity;
6143
+ }
6144
+ return named[lower] ?? entity;
6145
+ });
6146
+ }
6125
6147
  function normalizeChatGptPromptText(value) {
6126
- const unescaped = value.replace(AUTOLINKED_URL_PATTERN, "$1").replace(/\\([\\`*_{}[\]()#+\-.!>~|])/g, "$1");
6148
+ const unescaped = decodeHtmlEntities(value).replace(AUTOLINKED_URL_PATTERN, "$1").replace(/\\([\\`*_{}[\]()#+\-.!>~|])/g, "$1");
6127
6149
  const renderedFences = unescaped.replace(/(^|\r?\n)```text[ \t]*\r?\n([\s\S]*?)\r?\n```(?=\r?\n|$)/g, "$1text\n$2");
6128
6150
  return renderedFences.replace(/\s+/g, " ").trim();
6129
6151
  }
@@ -6154,7 +6176,7 @@ export function chatGptRequestMatchesUserTurn(userText, sentPrompt, requestId) {
6154
6176
  return withoutFenceLines(userText).includes(withoutFenceLines(sentPrompt));
6155
6177
  }
6156
6178
  function withoutFenceLines(value) {
6157
- return value
6179
+ return decodeHtmlEntities(value)
6158
6180
  .replace(AUTOLINKED_URL_PATTERN, "$1")
6159
6181
  .replace(/\\([\\`*_{}[\]()#+\-.!>~|])/g, "$1")
6160
6182
  .replace(/^[ \t]*```[\w-]*[ \t]*$/gm, "")
package/docs/releasing.md CHANGED
@@ -16,6 +16,43 @@ 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.35 Release Record
20
+
21
+ Release commit `4c711c7` on `main` (cut after PR #29, merge `fdf7501`); tag `v0.40.35`.
22
+
23
+ **Publishing**
24
+ - `publish.yml` run 39211269776 passed all six platforms on the first attempt, then npm publish with SLSA v1 provenance and the GitHub Release (2026-10-19 06:40 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.35. 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 `4c711c7` and rebuilt.
30
+
31
+ **Verified live**
32
+ - Host, installed 0.40.35: the special-character stdin prompt (paths, HTML tags and entities, markdown, a link, `$`, tabs, a table, Korean) answered `SPECIAL_OK`; 0.40.34 had refused it as `request_mismatch`.
33
+
34
+ **Browser container**
35
+ - `container/redesign-patches` `62b713e` ports PR #29. Image `9b46b724ea31`; branch suite 2041 passed, 3 skipped. Swapped under the send lock check. Live: the same prompt answered `SPECIAL_OK` (the previous image refused it); smoke `PRODEX_PRO_SMOKE_OK`.
36
+
37
+ ## 0.40.34 Release Record
38
+
39
+ Release commit `574e5f0` on `main` (cut after PR #28, merge `1d93de4`); tag `v0.40.34`.
40
+
41
+ **Publishing**
42
+ - `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).
43
+ - `npm run release:verify` passed on the release commit after a build.
44
+
45
+ **Installed**
46
+ - 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.
47
+ - The maintainer watchdog checkout was pulled to `574e5f0` and rebuilt.
48
+
49
+ **Verified live**
50
+ - 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").
51
+ - 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`.
52
+
53
+ **Browser container**
54
+ - `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.
55
+
19
56
  ## 0.40.33 Release Record
20
57
 
21
58
  Release commit `0497134` on `main` (cut after PR #27, merge `6083c6a`); tag `v0.40.33`.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@youdie006/prodex",
3
- "version": "0.40.34",
3
+ "version": "0.40.36",
4
4
  "description": "Local receipt bus for coordinating Codex execution with ChatGPT Pro/Projects consultation.",
5
5
  "author": "youdie006",
6
6
  "license": "MIT",