diff --git a/bin/muse-chat-api.py b/bin/muse-chat-api.py index 21238fd..e64ab2e 100755 --- a/bin/muse-chat-api.py +++ b/bin/muse-chat-api.py @@ -341,26 +341,26 @@ def cmd_upload(ws, filepath, message=None, dry_run=False): cdp_call(ws, "DOM.setFileInputFiles", {"nodeId": node_id, "files": [os.path.abspath(filepath)]}) time.sleep(2) - # Read-back: the attachment chip must appear. Match on the - # element's OWN text: React swaps the file input after change, so - # input.files is unreliable, and innerText on ancestors over-matches. + # Read-back: the attachment must be staged. React removes the + # file input after change, so input.files is unreliable — the + # composer's own signal is the "Remove attachment" button plus the + # chip text beside it. base = os.path.basename(filepath) preview = ev1(ws, """(() => { - const needle = %s; - const own = e => [...e.childNodes].filter(n => n.nodeType === 3) - .map(n => n.nodeValue).join(''); - const hits = [...document.querySelectorAll('*')] - .filter(e => own(e).includes(needle)) - .map(e => e.tagName + ': ' + own(e).slice(0, 80)); - return JSON.stringify(hits.slice(0, 5)); - })()""" % json.dumps(base)) + const btns = [...document.querySelectorAll('button')].filter(b => + (b.getAttribute('aria-label') || '') === 'Remove attachment'); + if (!btns.length) return JSON.stringify([]); + const chip = btns[0].closest('div'); + const text = chip ? chip.innerText.slice(0, 120) : ''; + return JSON.stringify([{button: true, chip: text}]); + })()""") print("preview: %s" % preview) try: hits = json.loads(preview) if preview else [] except Exception: hits = [] if not hits: - print("ERROR: attachment preview not visible after attach", + print("ERROR: attachment not staged (no Remove-attachment button)", file=sys.stderr) sys.exit(1) if dry_run: