Files
.sune/inline-commit.sune

1 line
15 KiB
Plaintext

[{"id":"jbcwown","name":"1 Click GitHub Commit","pinned":false,"avatar":"data:image/webp;base64,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","url":"gh://multipleof4/.sune/inline-commit.sune","updatedAt":1758898068389,"settings":{"model":"google/gemini-2.5-pro","temperature":"","top_p":"","top_k":"","frequency_penalty":"","repetition_penalty":"","min_p":"","top_a":"","verbosity":"","reasoning_effort":"default","system_prompt":"You include this sune in the extension.html of any sune you use to code with. <sune src=...\nThen use this system prompt and you will get 1 click button to commit your code inside code blocks:\nIn the preceding line to code blocks, apply this format: \n[org/repo@branch/file](https://github.com/org/repo/blob/branch/file \"Fix/Feat/Refactor/etc: Summarize in less than 50chars your following edit\")","html":"<!--\nSune: GitHub Commit & Delete Helper\nVersion: 3.0\n-->\n<div id=\"sune_github_helper\" x-data=\"{v:'3.0'}\" class=\"hidden\"></div>\n<script>\n(()=>{\n const suneEl=document.getElementById('sune_github_helper');\n if(!suneEl){console.error(\"Sune container not found.\");return}\n const SUNE_NAME='[Sune: GitHub Helper]', SUNE_V=suneEl.getAttribute('x-data').match(/v:'(.*?)'/)[1];\n console.log(`${SUNE_NAME} Initializing v${SUNE_V}`);\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 const deleteFile=async(btn,owner,repo,branch,path,commitMsg)=>{\n const token=window.USER?.githubToken;\n if(!token){alert('GitHub token not set in Account Settings > API.');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> Checking...';\n\n const H={'Authorization':`Bearer ${token}`,'Accept':'application/vnd.github.v3+json'};\n try{\n const CONTENTS_URL=`https://api.github.com/repos/${owner}/${repo}/contents/${path}`;\n const fileCheckRes=await fetch(`${CONTENTS_URL}?ref=${branch}`,{headers:H});\n if(fileCheckRes.status===404)throw new Error('File not found. Nothing to delete.');\n if(!fileCheckRes.ok)throw new Error(`Failed to get file info: ${fileCheckRes.statusText}`);\n const {sha}=(await fileCheckRes.json());\n if(!sha)throw new Error('Could not retrieve file SHA.');\n\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> Deleting...';\n\n const msg=commitMsg?.trim()||`Chore: Delete ${path.split('/').pop()}`;\n const body={message:msg,sha,branch};\n\n const deleteRes=await fetch(CONTENTS_URL,{method:'DELETE',headers:H,body:JSON.stringify(body)});\n if(!deleteRes.ok)throw new Error(`DELETE file failed: ${(await deleteRes.json()).message}`);\n \n btn.classList.remove(...defaultClasses);btn.classList.add(...successClasses);\n btn.innerHTML='<i data-lucide=\"check\" class=\"h-3.5 w-3.5\"></i> Deleted';\n }catch(err){\n alert(`${SUNE_NAME} Deletion Failed:\\n\\n${err.message||'An unknown error occurred.'}`);\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=\"trash-2\" class=\"h-3.5 w-3.5\"></i> Delete';\n window.lucide?.createIcons();\n },4e3);\n }finally{window.lucide?.createIcons()}\n };\n\n const commitFile=async(btn,owner,repo,branch,path,content,commitMsg)=>{\n const token=window.USER?.githubToken;\n if(!token){alert('GitHub token not set in Account Settings > API.');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> Authenticating...';\n\n const H={'Authorization':`Bearer ${token}`,'Accept':'application/vnd.github.v3+json'};\n try{\n const userRes=await fetch('https://api.github.com/user',{headers:H});\n if(!userRes.ok)throw new Error('GitHub token invalid or lacks user:read scope.');\n const username=(await userRes.json()).login;\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> Committing...';\n\n const repoCheckRes=await fetch(`https://api.github.com/repos/${owner}/${repo}`,{headers:H});\n if(repoCheckRes.status===404){\n const isOrg=owner.toLowerCase()!==username.toLowerCase(),createRepoUrl=isOrg?`https://api.github.com/orgs/${owner}/repos`:'https://api.github.com/user/repos';\n const createRepoRes=await fetch(createRepoUrl,{method:'POST',headers:H,body:JSON.stringify({name:repo,private:false})});\n if(!createRepoRes.ok){\n let msg=`Repo creation failed: ${(await createRepoRes.json()).message||'Unknown'}`;\n if(createRepoRes.status===403)msg=`Permission Denied. Token needs 'public_repo' scope for personal repos, or 'repo' scope for org repos.`;\n throw new Error(msg);\n }\n }else if(!repoCheckRes.ok)throw new Error(`Repo check failed: ${repoCheckRes.statusText}`);\n\n const CONTENTS_URL=`https://api.github.com/repos/${owner}/${repo}/contents/${path}`;\n let sha;\n const fileCheckRes=await fetch(`${CONTENTS_URL}?ref=${branch}`,{headers:H});\n if(fileCheckRes.ok)sha=(await fileCheckRes.json()).sha;\n else if(fileCheckRes.status!==404)throw new Error(`GET file failed: ${fileCheckRes.statusText}`);\n\n const msg=commitMsg?.trim()||(sha?`Refactor: Update ${path.split('/').pop()}`:`Feat: Add ${path.split('/').pop()}`);\n const b64c=btoa(unescape(encodeURIComponent(content)));\n const body={message:msg,content:b64c,sha,branch};\n \n const putRes=await fetch(CONTENTS_URL,{method:'PUT',headers:H,body:JSON.stringify(body)});\n if(!putRes.ok)throw new Error(`PUT file failed: ${(await putRes.json()).message}`);\n \n btn.classList.remove(...defaultClasses);btn.classList.add(...successClasses);\n btn.innerHTML='<i data-lucide=\"check\" class=\"h-3.5 w-3.5\"></i> Success';\n }catch(err){\n alert(`${SUNE_NAME} Commit Failed:\\n\\n${err.message||'An unknown error occurred.'}`);\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=\"github\" class=\"h-3.5 w-3.5\"></i> Commit';\n window.lucide?.createIcons();\n },4e3);\n }finally{window.lucide?.createIcons()}\n };\n\n const processBubble=bubble=>{\n if(!bubble||bubble.dataset.suneGchProcessed)return;\n let buttonAdded=false;\n bubble.querySelectorAll('p:not(:has(button.commit-btn))').forEach(p=>{\n const link=p.querySelector('a');\n if(!link)return;\n const m=link.textContent.trim().match(/^([^\\/]+)\\/([^\\/]+)@([^\\/]+)\\/(.+)$/);\n if(!m)return;\n\n const[_,owner,repo,branch,path]=m,commitMsg=link.title,isDelete=(commitMsg||'').toLowerCase().startsWith('delete:');\n const btn=document.createElement('button');\n btn.className='commit-btn ml-2 inline-flex items-center gap-1.5 rounded-md bg-slate-100 px-2 py-1 text-xs font-medium text-slate-700 hover:bg-slate-200 transition-colors';\n\n if(isDelete){\n console.log(`${SUNE_NAME} Delete match found for ${path.trim()}`);\n btn.innerHTML='<i data-lucide=\"trash-2\" class=\"h-3.5 w-3.5\"></i> Delete';\n btn.onclick=()=>deleteFile(btn,owner,repo,branch,path.trim(),commitMsg);\n p.append(btn);\n buttonAdded=true;\n }else{\n const preEl=p.nextElementSibling;\n if(preEl?.tagName!=='PRE')return;\n const code=preEl.querySelector('code')?.innerText;\n if(code==null)return;\n console.log(`${SUNE_NAME} Commit match found for ${path.trim()}`);\n btn.innerHTML='<i data-lucide=\"github\" class=\"h-3.5 w-3.5\"></i> Commit';\n btn.onclick=()=>commitFile(btn,owner,repo,branch,path.trim(),code,commitMsg);\n p.append(btn);\n buttonAdded=true;\n }\n });\n if(buttonAdded){bubble.dataset.suneGchProcessed='true';window.lucide?.createIcons()}\n return buttonAdded;\n };\n\n const scanExisting=()=>document.querySelectorAll('#messages .msg-bubble').forEach(processBubble);\n const observer=new MutationObserver(mutations=>{for(const m of mutations)for(const node of m.addedNodes)if(node.nodeType===1){const b=node.matches?.('.msg-bubble')?[node]:node.querySelectorAll?.('.msg-bubble');b?.forEach(processBubble)}});\n \n const newResponseListener=e=>{\n const id=e?.detail?.message?.id; if(!id)return;\n let attempts=0,maxAttempts=8,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} Observer and event listener attached. Initial scan complete.`);\n }\n \n suneEl.addEventListener('sune:unmount',()=>{\n observer.disconnect();\n if(composerEl)composerEl.removeEventListener('sune:newSuneResponse',newResponseListener);\n console.log(`${SUNE_NAME} Unmounted.`);\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":true,"include_thoughts":false,"json_output":false,"ignore_master_prompt":false,"json_schema":""},"storage":{}}]