§
    	ÊjQ  ã            
      ó\  — d Z ddlmZ ddlZdZdZdZdZdZd	Z	d
Z
dZdZd(d„Zd ee¦  «        › d ee¦  «        › d�Zd ee¦  «        › d ee¦  «        › d ee¦  «        › d ee¦  «        › d�	Zd ee¦  «        › d�Zd ee¦  «        › d�Zd)d„ZdZd  ee¦  «        › d!�Zd*d%„Zd+d'„ZdS ),a$  DOM selectors and in-page scripts for the muse.ai web client.

All knowledge about the page structure lives here. When muse.ai ships a UI
change, this is normally the only file that needs updating. Scripts return
JSON-serialisable values and never throw (errors are reported in the payload).
é    )ÚannotationsNÚtextareaz#div[class*="hatch-agent-bubble-bg"]z4[data-testid^="hatch-chat-attachment-presentation-"]zbutton[aria-label*="Stop" i]z*[data-testid="hatch-inline-approval-card"]zinput[type="file"])zlog inzsign inzcreate an accountzuse another account)zout of creditszusage limitzlimit reachedztoken limit)zStill sendingzConnecting...ÚvalueÚstrÚreturnc                ó*   — t          j        | ¦  «        S )z:JSON-quote a Python string for safe interpolation into JS.)ÚjsonÚdumps)r   s    ú8C:\Projects\Muse2API\src\muse2api\drivers\browser\dom.pyÚqr      s   € åŒ:�eÑÔÐó    zí(() => {
  const body = document.body ? document.body.innerText : '';
  const hydration = document.querySelector('[data-hatch-shell-hydration-state]');
  return {
    ready: document.readyState === 'complete' && !!document.querySelector(zÀ)
           && (!hydration || hydration.getAttribute('data-hatch-shell-hydration-state') === 'hydrated')
           && !body.includes('Connecting...'),
    hasInput: !!document.querySelector(zG),
    path: location.pathname,
    head: body.slice(0, 800),
  };
})()aN  (() => {
  const scrollers = [...document.querySelectorAll('*')].filter(e => {
    const s = getComputedStyle(e);
    return (s.overflowY === 'auto' || s.overflowY === 'scroll') && e.scrollHeight > e.clientHeight + 50;
  });
  scrollers.forEach(e => { e.scrollTop = e.scrollHeight; });
  const bubbles = [...document.querySelectorAll(zŒ)];
  const last = bubbles.length ? (bubbles[bubbles.length - 1].innerText || '').trim() : '';
  const atts = [...document.querySelectorAll(a=  )].map(a => {
    const v = a.querySelector('video'), i = a.querySelector('img');
    const m = v || i;
    return {
      tid: a.getAttribute('data-testid') || '',
      kind: v ? 'video' : (i ? 'image' : 'unknown'),
      src: m ? (m.currentSrc || m.src || '') : '',
      w: m ? (m.videoWidth || m.naturalWidth || 0) : 0,
      h: m ? (m.videoHeight || m.naturalHeight || 0) : 0,
    };
  });
  const tail = document.body ? document.body.innerText.slice(-600) : '';
  return { agentCount: bubbles.length, lastText: last,
            generating: !!document.querySelector(z2),
            approval: !!document.querySelector(z.),
            attachments: atts, tail };
})()zM(() => {
  const denied = [];
  for (const card of document.querySelectorAll(a?  )) {
    const btn = [...card.querySelectorAll('button,[role=button]')]
      .find(b => /^(deny|decline|reject|don.t allow)$/i.test((b.innerText || '').trim()));
    if (btn && !btn.disabled) {
      btn.click();
      denied.push(card.getAttribute('aria-label') || 'approval request');
    }
  }
  return denied;
})()z9(() => {
  const bubbles = [...document.querySelectorAll(as  )];
  const b = bubbles.length ? bubbles[bubbles.length - 1] : null;
  if (!b) return { links: [], html: '' };
  const urls = [];
  const push = (u) => { if (u && !urls.includes(u)) urls.push(u); };
  b.querySelectorAll('video, source').forEach(m => push(m.currentSrc || m.src || ''));
  b.querySelectorAll('a[href]').forEach(a => push(a.href || ''));
  b.querySelectorAll('img').forEach(m => push(m.currentSrc || m.src || ''));
  const text = b.innerText || '';
  const re = /https?:\/\/[^\s)<>"']+/g;
  let mm; while ((mm = re.exec(text))) push(mm[0]);
  return { links: urls, html: (b.outerHTML || '').slice(0, 2000) };
})()Útextc                óR   — dt          t          ¦  «        › dt          | ¦  «        › d�S )zFSet the textarea value through the native setter so React picks it up.z-(() => {
  const ta = document.querySelector(z³);
  if (!ta) return { ok: false, err: 'no-input' };
  ta.focus();
  const setter = Object.getOwnPropertyDescriptor(HTMLTextAreaElement.prototype, 'value').set;
  setter.call(ta, zo);
  ta.dispatchEvent(new Event('input', { bubbles: true }));
  return { ok: true, len: ta.value.length };
})())r   ÚINPUT)r   s    r   Ú
fill_inputr   l   s9   € ð	Ý%&¥u¡X¤Xð	ð 	õ
 �T‘7”7ð	ð 	ð 	ð 	r   u]  (() => {
  const btn = [...document.querySelectorAll('button,[role=button]')]
    .filter(b => b.offsetParent !== null)
    .find(b => /send|å�‘é€�/i.test((b.getAttribute('aria-label') || '') + ' ' + (b.getAttribute('data-testid') || '')));
  if (!btn) return 'missing';
  if (btn.disabled) return 'disabled';
  btn.click();
  return 'clicked';
})()z!(document.querySelector(z) || {value: ''}).valueÚb64ÚmimeÚfilenamec           
     ó’   — dt          t          ¦  «        › dt          | ¦  «        › dt          |¦  «        › dt          |¦  «        › d�	S )Nz:(() => {
  try {
    const input = document.querySelector(zT);
    if (!input) return { ok: false, err: 'no-file-input' };
    const bin = atob(z¾);
    const bytes = new Uint8Array(bin.length);
    for (let i = 0; i < bin.length; i++) bytes[i] = bin.charCodeAt(i);
    const dt = new DataTransfer();
    dt.items.add(new File([bytes], z
, { type: z¸ }));
    input.files = dt.files;
    input.dispatchEvent(new Event('change', { bubbles: true }));
    return { ok: true };
  } catch (e) { return { ok: false, err: String(e) }; }
})())r   Ú
FILE_INPUT)r   r   r   s      r   Úattach_filer   †   sc   € ð	å*+­J©-¬-ð	ð 	õ ˜‘f”fð		ð 	õ %& h¡K¤Kð	ð 	õ =>¸d¹G¼Gð	ð 	ð 	ð 	r   Úurlc                ó(   — dt          | ¦  «        › d�S )zMFetch a (possibly blob:) URL inside the page context and return base64 bytes.z1(async () => {
  try {
    const r = await fetch(aS  );
    const b = await r.blob();
    const buf = new Uint8Array(await b.arrayBuffer());
    let s = '';
    for (let i = 0; i < buf.length; i += 0x8000) s += String.fromCharCode.apply(null, buf.subarray(i, i + 0x8000));
    return { ok: true, mime: b.type || '', b64: btoa(s) };
  } catch (e) { return { ok: false, err: String(e) }; }
})())r   )r   s    r   Úfetch_as_base64r   —   s$   € ð		å˜S™6œ6ð		ð 		ð 		ð 		r   )r   r   r   r   )r   r   r   r   )r   r   r   r   r   r   r   r   )r   r   r   r   )Ú__doc__Ú
__future__r   r	   r   ÚAGENT_BUBBLEÚ
ATTACHMENTÚSTOP_BUTTONÚAPPROVAL_CARDr   ÚLOGIN_HINTSÚQUOTA_HINTSÚSTALL_HINTSr   Ú
PAGE_STATEÚ
CHAT_STATEÚDENY_APPROVALSÚLAST_BUBBLE_MEDIAr   Ú
CLICK_SENDÚINPUT_EMPTYr   r   © r   r   ú<module>r+      sÂ  ððð ð #Ð "Ð "Ð "Ð "Ð "à €€€à€Ø4€ØC€
Ø,€ð =€Ø!€
àO€ØO€Ø0€ðð ð ð ð
	ð LMÈ1ÈUÉ8Ì8ð		ð 	ð )*¨¨%©¬ð	ð 	ð 	€
ð	ð 23°°<±´ð	ð 	ð /0¨a°
©m¬mð	ð 	ð* 34°!°K±.´.ð+	ð 	ð, 12°°-Ñ0@Ô0@ð-	ð 	ð 	€
ð:	à01°°-Ñ0@Ô0@ð	ð 	ð 	€ð$	Ø12°°<±´ð	ð 	ð 	Ð ð 
	ð 
	ð 
	ð 
	ð€
ð N¨!¨!¨E©(¬(ÐMÐMÐM€ð	ð 	ð 	ð 	ð"	ð 	ð 	ð 	ð 	ð 	r   