@youdie006/prodex 0.40.36 → 0.40.37

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.
@@ -499,6 +499,17 @@ const CHATGPT_GENERATING_CONTROL_PATTERN = /\bstop\s+(?:generating|responding|re
499
499
  // is matched only inside the composer's form, where the send control lives,
500
500
  // so a "Stop" elsewhere on the page cannot answer for it.
501
501
  export const CHATGPT_STREAMING_SELECTOR = '[data-testid="stop-button"],form button[aria-label="Stop"],form button[aria-label="중지"],[data-message-author-role="assistant"][aria-busy="true"],[data-message-author-role="assistant"] [aria-busy="true"]';
502
+ /**
503
+ * Whether a streaming signal is actually on screen. Measured 2026-10-20: after
504
+ * a Pro answer finished, the composer kept a zero-size, undisplayed "Stop"
505
+ * button, and its mere presence held a finished answer as "generating" for
506
+ * the whole budget. A message drawn through display: contents has no box of
507
+ * its own, so its children decide.
508
+ */
509
+ export const CHATGPT_STREAMING_SIGNAL_JS = `
510
+ const streamingSignalVisible = () =>
511
+ [...document.querySelectorAll(${JSON.stringify(CHATGPT_STREAMING_SELECTOR)})].some((node) =>
512
+ node.getClientRects().length > 0 || [...(node.children || [])].some((child) => child.getClientRects().length > 0));`;
502
513
  export function defaultChatGptProfileDir() {
503
514
  return path.join(os.homedir(), ".local", "share", "prodex", "chrome-chatgpt-pro");
504
515
  }
@@ -5332,11 +5343,10 @@ export const CHATGPT_THINKING_PLACEHOLDER_JS = `ansLines.length <= 1 && (/^(생
5332
5343
  export function statusExpression() {
5333
5344
  const excludedTextSelector = JSON.stringify(CHATGPT_RUNTIME_BLOCKER_TEXT_EXCLUDED_ANCESTORS);
5334
5345
  const blockerScanExcludedSelector = JSON.stringify(CHATGPT_BLOCKER_SCAN_EXCLUDED_ANCESTORS);
5335
- const streamingSelector = JSON.stringify(CHATGPT_STREAMING_SELECTOR);
5336
5346
  const responseChoiceSelector = JSON.stringify(CHATGPT_RESPONSE_CHOICE_SELECTOR);
5337
5347
  const generatingControlPattern = JSON.stringify(CHATGPT_GENERATING_CONTROL_PATTERN.source);
5338
5348
  const generatingControlFlags = JSON.stringify(CHATGPT_GENERATING_CONTROL_PATTERN.flags);
5339
- return `(() => {${CHATGPT_MODEL_HINTS_JS}
5349
+ return `(() => {${CHATGPT_MODEL_HINTS_JS}${CHATGPT_STREAMING_SIGNAL_JS}
5340
5350
  ${composerExpressionHelpers()}
5341
5351
  const text = document.body?.innerText || "";
5342
5352
  const runtimeExcludedTextSelector = ${excludedTextSelector};
@@ -5387,7 +5397,7 @@ export function statusExpression() {
5387
5397
  blockerScanTextSample: blockerScanText.slice(0, 12000),
5388
5398
  visibleButtonLabels,
5389
5399
  hasComposer,
5390
- generating: placeholder || Boolean(document.querySelector(${streamingSelector})) || visibleButtonLabels.some((label) => generatingControlPattern.test(label)),
5400
+ generating: placeholder || streamingSignalVisible() || visibleButtonLabels.some((label) => generatingControlPattern.test(label)),
5391
5401
  awaitingResponseChoice: Boolean(document.querySelector(${responseChoiceSelector})),
5392
5402
  modelHints: modelHintLines(),
5393
5403
  openDialogText: (([...document.querySelectorAll('[role="dialog"]')].find((d) => d.offsetWidth || d.offsetHeight || d.getClientRects().length)?.innerText) || "").trim().slice(0, 200)
@@ -6433,11 +6443,10 @@ function composerExpressionHelpers() {
6433
6443
  export function answerExpression() {
6434
6444
  const excludedTextSelector = JSON.stringify(CHATGPT_RUNTIME_BLOCKER_TEXT_EXCLUDED_ANCESTORS);
6435
6445
  const blockerScanExcludedSelector = JSON.stringify(CHATGPT_BLOCKER_SCAN_EXCLUDED_ANCESTORS);
6436
- const streamingSelector = JSON.stringify(CHATGPT_STREAMING_SELECTOR);
6437
6446
  const responseChoiceSelector = JSON.stringify(CHATGPT_RESPONSE_CHOICE_SELECTOR);
6438
6447
  const generatingControlPattern = JSON.stringify(CHATGPT_GENERATING_CONTROL_PATTERN.source);
6439
6448
  const generatingControlFlags = JSON.stringify(CHATGPT_GENERATING_CONTROL_PATTERN.flags);
6440
- return `(() => {${CHATGPT_MODEL_HINTS_JS}
6449
+ return `(() => {${CHATGPT_MODEL_HINTS_JS}${CHATGPT_STREAMING_SIGNAL_JS}
6441
6450
  const text = document.body?.innerText || "";
6442
6451
  const excludedTextSelector = ${excludedTextSelector};
6443
6452
  const blockerScanExcludedSelector = ${blockerScanExcludedSelector};
@@ -6504,7 +6513,7 @@ export function answerExpression() {
6504
6513
  blockerTextSample: visibleTextOutsideMessages(excludedTextSelector).slice(0, 12000),
6505
6514
  blockerScanTextSample: visibleTextOutsideMessages(blockerScanExcludedSelector).slice(0, 12000),
6506
6515
  visibleButtonLabels: buttons,
6507
- generating: placeholder || Boolean(document.querySelector(${streamingSelector})) || buttons.some((label) => generatingControlPattern.test(label)),
6516
+ generating: placeholder || streamingSignalVisible() || buttons.some((label) => generatingControlPattern.test(label)),
6508
6517
  awaitingResponseChoice: Boolean(document.querySelector(${responseChoiceSelector})),
6509
6518
  assistantMessageCount: assistantMessages.length,
6510
6519
  userMessageCount: userMessages.length,
package/docs/releasing.md CHANGED
@@ -16,6 +16,27 @@ 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.36 Release Record
20
+
21
+ Release commit `eee7a7c` on `main` (cut after PR #30, merge `1e53f4e`); tag `v0.40.36`.
22
+
23
+ **Publishing**
24
+ - `publish.yml` run 39220885039 passed all six platforms on the first attempt, then npm publish with SLSA v1 provenance and the GitHub Release (2026-10-19 08:10 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.36. Running services were not restarted: 9 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 `eee7a7c` and rebuilt.
30
+
31
+ **Verified live**
32
+ - Host, installed 0.40.36: an answer with a markdown code block showing a fenced `js` example was saved with a four-backtick fence and no toolbar label line. Code blocks with HTML entities and backslashes, a table with an escaped pipe, and inline and display math were saved intact.
33
+
34
+ **Browser container**
35
+ - `container/redesign-patches` `3233bdc` ports PR #30 by hand. Image `3945d3d38af0`; branch suite 2042 passed, 3 skipped. Swapped under the send lock check. Live: the same nested block was saved intact.
36
+
37
+ **Known and left as is**
38
+ - An answer's text `&lt;tag&gt;` is saved as `<tag>`, as displayed; rendering the saved markdown again may treat it as an HTML tag.
39
+
19
40
  ## 0.40.35 Release Record
20
41
 
21
42
  Release commit `4c711c7` on `main` (cut after PR #29, merge `fdf7501`); tag `v0.40.35`.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@youdie006/prodex",
3
- "version": "0.40.36",
3
+ "version": "0.40.37",
4
4
  "description": "Local receipt bus for coordinating Codex execution with ChatGPT Pro/Projects consultation.",
5
5
  "author": "youdie006",
6
6
  "license": "MIT",