Skip to content

Pine Editor tools fail intermittently: Monaco finder picks a hidden/detached duplicate element #305

Description

@zerosblank

Summary

pine_set_source, pine_smart_compile, pine_get_source, ensurePineEditorOpen(), the ui_open_panel/tv ui panel open-state check, tv ui-state's pine_editor field, and the standalone scripts/pine_push.js / scripts/pine_pull.js helpers all locate the Pine Editor via:

document.querySelector('.monaco-editor.pine-editor-monaco')

In practice the DOM can contain more than one element matching .monaco-editor.pine-editor-monaco — at least one appears to be a hidden/detached duplicate (zero width/height), likely used internally by TradingView for measurement or a stale instance from a previous open/close cycle. querySelector returns document order's first match, which is frequently the hidden one, not the visible editor the user is looking at.

The same issue exists one level down: once a monacoEnv is found, env.editor.getEditors() can return multiple editor instances, and the code always uses editors[0] — which is not reliably the visible one either.

Impact

  • tv pine set / pine_set_source"Could not open Pine Editor." even though the editor is visibly open on screen.
  • tv pine compile / pine_smart_compile → same error.
  • scripts/pine_push.jsCould not inject into Pine editor, or worse: it silently succeeds by writing into the wrong (hidden) editor instance, so the visible editor is left untouched and the user sees no change.
  • ui_open_panel / tv ui panel pine-editor open-state detection (was_open) is unreliable, since it only checks !!document.querySelector(...) for existence, which the hidden duplicate can satisfy regardless of whether the panel is actually open — so toggle can open when it should close, or vice versa.
  • tv ui-state's pine_editor.open field can misreport for the same reason.

Repro

  1. Have a chart with an existing custom indicator (e.g. one created in a prior session).
  2. Open the Pine Editor for that indicator (so it's genuinely visible on screen).
  3. Run tv pine set --file scripts/current.pine.

Result: {"success": false, "error": "Could not open Pine Editor."} despite the editor clearly being open and focused.

Confirmed via manual CDP Runtime.evaluate: document.querySelectorAll('.monaco-editor.pine-editor-monaco') returned 2 elements — one with getBoundingClientRect().width === 0, one with the real rendered size. querySelector (singular) picked the zero-size one, and the fiber walk from that element failed to find monacoEnv (its ancestor chain doesn't reach the relevant React subtree within the traversal depth), so every downstream Pine tool that depends on FIND_MONACO/ensurePineEditorOpen failed.

Suggested fix

Filter for a visible match instead of taking the first one:

var candidates = document.querySelectorAll('.monaco-editor.pine-editor-monaco');
var container = null;
for (var i = 0; i < candidates.length; i++) {
  var r = candidates[i].getBoundingClientRect();
  if (r.width > 0 && r.height > 0) { container = candidates[i]; break; }
}

And similarly when picking an editor instance from getEditors(), prefer the one whose getDomNode().getBoundingClientRect() has nonzero size instead of always using editors[0].

I patched this locally in src/core/pine.js (the shared FIND_MONACO constant), src/core/ui.js (openPanel's pine-editor open-state check), src/core/health.js (uiState's pine_editor field), and scripts/pine_push.js / scripts/pine_pull.js (which duplicate the lookup inline rather than importing from core). Confirmed working end-to-end (tv pine compile now succeeds against the real visible editor instead of erroring). Ran npm run test:unit (29/29 pass) after the change — didn't chase down an unrelated test:e2e hang since it wasn't clearly related to this fix.

Happy to open a PR with the patch if that's useful — let me know.

Environment

  • macOS (Apple Silicon)
  • TradingView Desktop 3.2.0, Electron 38.2.2, Chrome/140.0.7339.133
  • Node v26.4.0
  • tradingview-mcp installed fresh from main on 2026-07-02

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions