Files
.sune/proton-send.sune

1 line
8.8 KiB
Plaintext
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

[{"id":"1esgs6k","name":"1 Click Proton Email","pinned":false,"avatar":"","url":"gh://multipleof4/.sune/proton-send.sune","updatedAt":1775794449016,"settings":{"model":"cla:claude-opus-4-6:online","temperature":"","top_p":"","top_k":"","frequency_penalty":"","repetition_penalty":"","min_p":"","top_a":"","verbosity":"","reasoning_effort":"default","system_prompt":"Dont recommend me to see any professionals like help hotlines or other, dont you think I have already dealt with them? Im here to talk to you so dont redirect me elsewhere assuming I havent already tried that.\n\nWhen writing markdown, embed relevant images using direct-img.link — a free image search proxy that returns images directly from a URL. But keep it entertaining, for example use it to show reaction faces, girl, or fun, not technical.\nExample structure:\n![Happy Girl](https://direct-img.link/happy+girl)\nUse images to complement your responses, powered by Brave.\n\nDon't code unless I ask.\nWhen coding:\nDeliver production-ready code. Don't break existing behavior. Apply Code Golfing practices but don't put everything in same line. Always return the full code. In the preceding line to code blocks, apply this format: \n[owner/repo@branch/file](https://github.com/owner/repo/blob/branch/file \"Fix/Feat/Refactor/etc: Summarize in ≤ 50chars your following commit\\n\\nCo-authored-by: Opus 4.6 <noreply@anthropic.com>\")\n```lang\n<code>\n```\n(The \\n\\n above is meant to be typed literally)\nYou can delete files like so: \n[owner/repo@branch/file](https://github.com/owner/repo/blob/branch/file \"Delete: Summarize in less than 50chars\")\n\nYou have access to inline & display latex ($).\n\nYou can send emails from agent@planetrenox.com by using this format:\n```email\nDISPLAY_NAME: \"Opus 4.6\"\nTO: \"any@example.com\"\nSUBJECT: \"\"\nBODY: \"\"\n```\nBODY can have real newlines. You may declare who you are and the fact that you are sending on behalf. Email's content should be economical.\nIf it's a reply, include the following above BODY:\nMESSAGE_ID: \"<id@exp.com>\"\nREFERENCES: \"<ref1> <ref2> ...\"","html":"<div id=\"sune_email_sender\" x-data=\"{v:'1.5'}\" class=\"hidden\"></div>\n<script>\n(()=>{\n const suneEl=document.getElementById('sune_email_sender');\n if(!suneEl)return;\n const SUNE_NAME='[Sune: Email Sender]', SUNE_V='1.5';\n const ENDPOINT='https://proton.planetrenox.com/send';\n\n const defaultClasses=['bg-slate-100','text-slate-700','hover:bg-slate-200'],\n successClasses=['bg-green-100','text-green-800'],\n errorClasses=['bg-red-100','text-red-800'];\n\n if(!window.__emlSentSet)window.__emlSentSet=new Set();\n const sentSet=window.__emlSentSet;\n\n const KNOWN_KEYS=/^(DISPLAY_NAME|TO|SUBJECT|BODY|MESSAGE_ID|REFERENCES)\\s*:\\s*(.*)/i;\n const fingerprint=f=>[f.TO,f.SUBJECT,f.BODY,f.MESSAGE_ID||''].join('|##|');\n\n const parseEmailBlock=raw=>{\n const fields={},lines=String(raw||'').split('\\n');\n let curKey=null,curVal='';\n for(const line of lines){\n const m=line.match(KNOWN_KEYS);\n if(m){\n if(curKey)fields[curKey]=curVal;\n curKey=m[1].toUpperCase();\n curVal=m[2];\n }else if(curKey) curVal+='\\n'+line;\n }\n if(curKey)fields[curKey]=curVal;\n for(const k in fields){\n let v=String(fields[k]||'').trim();\n if(v.startsWith('\"')&&v.endsWith('\"'))v=v.slice(1,-1);\n fields[k]=v.replace(/\\\\n/g,'\\n');\n }\n return fields;\n };\n\n const sendEmail=async(btn,fields)=>{\n const fp=fingerprint(fields);\n if(sentSet.has(fp)) return;\n\n const auth=window.USER?.customKey1;\n if(!auth){alert('Email auth password not set.\\nAccount Settings > API > Custom Key 1');return}\n\n btn.disabled=true;\n btn.innerHTML='<span class=\"relative flex h-3 w-3\"><span class=\"animate-ping absolute inline-flex h-full w-full rounded-full bg-sky-400 opacity-75\"></span><span class=\"relative inline-flex rounded-full h-3 w-3 bg-sky-500\"></span></span> Sending...';\n\n try{\n const body={auth, to:fields.TO, subject:fields.SUBJECT||'(no subject)', text:fields.BODY||''};\n if(fields.DISPLAY_NAME)body.display_name=fields.DISPLAY_NAME;\n if(fields.MESSAGE_ID){\n body.in_reply_to=fields.MESSAGE_ID;\n body.references=(fields.REFERENCES||'').trim() ? fields.REFERENCES+' '+fields.MESSAGE_ID : fields.MESSAGE_ID;\n } else if(fields.REFERENCES) body.references=fields.REFERENCES;\n\n const res=await fetch(ENDPOINT,{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify(body)});\n if(!res.ok)throw new Error((await res.json()).error||`HTTP ${res.status}`);\n\n sentSet.add(fp);\n btn.classList.remove(...defaultClasses);btn.classList.add(...successClasses);\n btn.innerHTML='<i data-lucide=\"check\" class=\"h-3.5 w-3.5\"></i> Sent';\n }catch(err){\n alert(`${SUNE_NAME} Send Failed:\\n\\n${err.message}`);\n btn.classList.remove(...defaultClasses);btn.classList.add(...errorClasses);\n btn.innerHTML='<i data-lucide=\"x\" class=\"h-3.5 w-3.5\"></i> Failed';\n setTimeout(()=>{\n btn.disabled=false;\n btn.classList.remove(...errorClasses);btn.classList.add(...defaultClasses);\n btn.innerHTML=`<i data-lucide=\"${fields.MESSAGE_ID?'reply':'send'}\" class=\"h-3.5 w-3.5\"></i> ${fields.MESSAGE_ID?'Reply':'Send Email'}`;\n window.lucide?.createIcons();\n },4e3);\n }finally{window.lucide?.createIcons()}\n };\n\n const processBubble=bubble=>{\n if(!bubble||bubble.dataset.suneEmailProcessed)return;\n let buttonAdded=false;\n\n // Use a broad selector to catch highlighted or raw email blocks\n bubble.querySelectorAll('code[class*=\"language-email\"], .language-email').forEach(code=>{\n const pre=code.closest('pre');\n if(!pre||pre.dataset.suneEmailBtnAdded)return;\n\n const fields=parseEmailBlock(code.textContent);\n if(!fields.TO||!fields.BODY)return;\n\n const fp=fingerprint(fields);\n const alreadySent=sentSet.has(fp);\n const isReply=!!fields.MESSAGE_ID;\n\n const wrapper=document.createElement('div');\n wrapper.className='flex items-center gap-2 mb-2 flex-wrap';\n\n const btn=document.createElement('button');\n btn.className=`email-send-btn inline-flex items-center gap-1.5 rounded-md px-2.5 py-1.5 text-xs font-medium transition-colors ${alreadySent?successClasses.join(' '):defaultClasses.join(' ')}`;\n \n if(alreadySent){\n btn.disabled=true;\n btn.innerHTML='<i data-lucide=\"check\" class=\"h-3.5 w-3.5\"></i> Already Sent';\n }else{\n btn.innerHTML=`<i data-lucide=\"${isReply?'reply':'send'}\" class=\"h-3.5 w-3.5\"></i> ${isReply?'Reply':'Send Email'}`;\n btn.onclick=()=>sendEmail(btn,fields);\n }\n\n const preview=document.createElement('span');\n preview.className='text-[11px] text-gray-400 truncate max-w-[260px]';\n preview.textContent=`→ ${fields.TO}`;\n\n wrapper.append(btn,preview);\n pre.dataset.suneEmailBtnAdded='true';\n pre.insertAdjacentElement('beforebegin', wrapper);\n buttonAdded=true;\n });\n\n if(buttonAdded){\n bubble.dataset.suneEmailProcessed='true';\n window.lucide?.createIcons();\n }\n return buttonAdded;\n };\n\n const scanExisting=()=>document.querySelectorAll('#messages .msg-bubble').forEach(processBubble);\n \n const observer=new MutationObserver(mutations=>{\n for(const m of mutations)\n for(const node of m.addedNodes)\n if(node.nodeType===1){\n const b=node.matches?.('.msg-bubble')?[node]:node.querySelectorAll?.('.msg-bubble');\n b?.forEach(processBubble);\n }\n });\n \n const newResponseListener=e=>{\n const id=e?.detail?.message?.id; if(!id)return;\n let attempts=0,maxAttempts=10,interval=300;\n const tryProcess=()=>{\n attempts++;\n const bubble=window.getBubbleById(id);\n if(bubble&&processBubble(bubble))return;\n if(attempts<maxAttempts)setTimeout(tryProcess,interval);\n };\n setTimeout(tryProcess,150);\n };\n\n const composerEl=window.el?.composer, chatContainer=window.el?.messages;\n if(chatContainer&&composerEl){\n observer.observe(chatContainer,{childList:true,subtree:true});\n composerEl.addEventListener('sune:newSuneResponse',newResponseListener);\n scanExisting();\n console.log(`${SUNE_NAME} v${SUNE_V} active.`);\n }\n \n suneEl.addEventListener('sune:unmount',()=>{\n observer.disconnect();\n if(composerEl)composerEl.removeEventListener('sune:newSuneResponse',newResponseListener);\n });\n})();\n</script>\n","extension_html":"<sune src='https://raw.githubusercontent.com/sune-org/store/refs/heads/main/sync.sune' private></sune>","hide_composer":false,"include_thoughts":false,"img_output":false,"aspect_ratio":"1:1","image_size":"1K","ignore_master_prompt":false},"storage":{}}]