Files
store/commit.sune

28 lines
8.9 KiB
JSON

[
{
"id": "bxvj8jx",
"name": "Commit",
"pinned": false,
"avatar": "",
"url": "gh://sune-org/store@main/commit.sune",
"updatedAt": 1757091142104,
"settings": {
"model": "openai/gpt-5",
"temperature": 1,
"top_p": 0.96,
"top_k": 0,
"frequency_penalty": 0,
"presence_penalty": 0,
"repetition_penalty": 1,
"min_p": 0,
"top_a": 0,
"max_tokens": 0,
"verbosity": "",
"reasoning_effort": "default",
"system_prompt": "",
"html": "<!-- GitHub File Editor Sune v1.3.0 -->\n<div id=\"gh-editor-sune\" class=\"mx-0 border-b border-gray-200 bg-gray-50 flex flex-col\">\n\n <!-- Toolbar -->\n <div class=\"flex items-center gap-3 px-3 sm:px-4 py-2 border-b border-gray-200 bg-white/80 backdrop-blur-sm shrink-0\">\n <i data-lucide=\"github\" class=\"h-5 w-5 text-gray-500 shrink-0\"></i>\n <input type=\"text\" id=\"ghPathInput\" placeholder=\"owner/repo/path/to/file.ext@branch\" class=\"flex-1 w-full bg-transparent border-none focus:ring-0 p-0 text-sm placeholder:text-gray-400\" autocomplete=\"off\" spellcheck=\"false\" />\n <button id=\"ghFetchBtn\" class=\"inline-flex items-center justify-center gap-1.5 h-8 px-3 shrink-0 rounded-lg bg-gray-100 text-gray-800 shadow-sm hover:bg-gray-200 active:scale-[.98] transition text-sm font-medium\" title=\"Fetch File\">\n <i data-lucide=\"refresh-cw\" class=\"h-4 w-4\"></i>\n <span class=\"hidden sm:inline\">Fetch</span>\n </button>\n <button id=\"ghCommitBtn\" class=\"inline-flex items-center justify-center gap-1.5 h-8 px-3 shrink-0 rounded-lg bg-green-600 text-white shadow-sm hover:bg-green-700 active:scale-[.98] transition text-sm font-medium\" title=\"Commit Changes\">\n <i data-lucide=\"check-circle\" class=\"h-4 w-4\"></i>\n <span class=\"hidden sm:inline\">Commit</span>\n </button>\n </div>\n\n <!-- Editor -->\n <div class=\"bg-white flex-1 relative\">\n <pre id=\"ghFileEditor\" class=\"w-full h-[71vh] p-3 overflow-auto font-mono text-[12px] leading-5 focus:outline-none [white-space:pre!important]\" contenteditable=\"plaintext-only\" spellcheck=\"false\"></pre>\n </div>\n\n <!-- Footer -->\n <div class=\"flex items-center justify-between gap-4 px-3 sm:px-4 py-1 border-t border-gray-200 bg-white/80 backdrop-blur-sm text-xs shrink-0\">\n <div class=\"flex items-center gap-1\">\n <button id=\"ghSearchBtn\" title=\"Search\" class=\"p-1.5 rounded-md hover:bg-gray-200 text-gray-500 hover:text-gray-800 transition-colors\"><i data-lucide=\"search\" class=\"h-4 w-4\"></i></button>\n <button id=\"ghCopyBtn\" title=\"Copy\" class=\"p-1.5 rounded-md hover:bg-gray-200 text-gray-500 hover:text-gray-800 transition-colors\"><i data-lucide=\"copy\" class=\"h-4 w-4\"></i></button>\n <button id=\"ghCutBtn\" title=\"Cut\" class=\"p-1.5 rounded-md hover:bg-gray-200 text-gray-500 hover:text-gray-800 transition-colors\"><i data-lucide=\"scissors\" class=\"h-4 w-4\"></i></button>\n <button id=\"ghPasteBtn\" title=\"Paste\" class=\"p-1.5 rounded-md hover:bg-gray-200 text-gray-500 hover:text-gray-800 transition-colors\"><i data-lucide=\"clipboard-paste\" class=\"h-4 w-4\"></i></button>\n </div>\n <div class=\"flex items-center gap-3 text-gray-500 truncate\">\n <span id=\"ghLangBadge\" class=\"font-medium\">Plain Text</span>\n <div id=\"ghStatus\" class=\"h-4 truncate\"></div>\n </div>\n <span class=\"text-gray-400\">v1.3.0</span>\n </div>\n\n</div>\n\n<script>\n(async()=>{\n // Elements\n const [\n pathInput, fetchBtn, commitBtn, fileEditorEl,\n searchBtn, copyBtn, cutBtn, pasteBtn,\n statusEl, langBadge\n ] = [\n 'ghPathInput', 'ghFetchBtn', 'ghCommitBtn', 'ghFileEditor',\n 'ghSearchBtn', 'ghCopyBtn', 'ghCutBtn', 'ghPasteBtn',\n 'ghStatus', 'ghLangBadge'\n ].map(id => document.getElementById(id));\n\n // State\n const S={o:null,r:null,p:null,b:null,sha:null,jar:null,t:null,l:null};\n const getLsKey=()=>`sune_gh_last_path_${window.SUNE?.id||'fallback'}`;\n\n // Init\n try{const last=localStorage.getItem(getLsKey());if(last)pathInput.value=last;}catch(e){console.error(\"Sune: LS get failed\",e);}\n\n // Helpers\n const setStatus=(msg,isErr=false)=>{statusEl.textContent=msg||'';statusEl.className=`h-4 truncate ${isErr?'text-red-600':'text-gray-500'}`;if(!isErr&&msg)setTimeout(()=>statusEl.textContent===msg&&(statusEl.textContent=''),4e3);};\n const fmtChars=c=>c<1e3?`${c} chars`:`${(c/1e3).toFixed(2).replace(/\\.00$|(\\.\\d)0$/,'$1')}k chars`;\n const setLoading=(btn,loading)=>{btn.disabled=loading;const i=btn.querySelector('i[data-lucide]');if(!i)return;if(loading){if(!i.dataset.og)i.dataset.og=i.dataset.lucide;i.dataset.lucide='loader-circle';i.classList.add('animate-spin');}else{if(i.dataset.og)i.dataset.lucide=i.dataset.og;i.classList.remove('animate-spin');}lucide?.createIcons();};\n const parsePath=i=>i.trim().match(/^([\\w.-]+)\\/([\\w.-]+)\\/(.+?)@([\\w.-]+)$/);\n const detectLang=p=>(p=String(p||'').toLowerCase(),{lang:/\\.html?$/.test(p)?'xml':/\\.m?js|cjs$/.test(p)?'javascript':/\\.json$/.test(p)?'json':/\\.css$/.test(p)?'css':/\\.md$/.test(p)?'markdown':'plaintext',label:/\\.html?$/.test(p)?'HTML':/\\.m?js|cjs$/.test(p)?'JavaScript':/\\.json$/.test(p)?'JSON':/\\.css$/.test(p)?'CSS':/\\.md$/.test(p)?'Markdown':'Plain Text'});\n const enc=s=>btoa(unescape(encodeURIComponent(s)));\n const dec=b=>decodeURIComponent(escape(atob(b)));\n\n // Editor Setup\n const{CodeJar:CJ}=await import('https://medv.io/codejar/codejar.js');\n const doHighlight=ed=>{const c=ed.textContent;if(hljs&&S.l&&hljs.getLanguage(S.l)){ed.innerHTML=hljs.highlight(c,{language:S.l,ignoreIllegals:true}).value;}else{ed.textContent=c;}};\n S.jar=CJ(fileEditorEl,doHighlight,{tab:' '});\n\n // API Handlers\n const fetchHandler=async()=>{setStatus();S.t=window.USER?.PAT||'';if(!S.t)return setStatus('Error: GitHub token not found.',true);const m=parsePath(pathInput.value);if(!m)return setStatus('Error: Invalid path. Use: owner/repo/path@branch',true);try{localStorage.setItem(getLsKey(),pathInput.value.trim());}catch(e){console.error(\"Sune: LS set failed\",e);}[S.o,S.r,S.p,S.b]=[m[1],m[2],m[3],m[4]];const{lang,label}=detectLang(S.p);S.l=lang;langBadge.textContent=label;const url=`https://api.github.com/repos/${S.o}/${S.r}/contents/${encodeURIComponent(S.p).replace(/%2F/g,'/') }?ref=${encodeURIComponent(S.b)}`;setStatus('Fetching...');setLoading(fetchBtn,true);try{const r=await fetch(url,{headers:{'Authorization':`Bearer ${S.t}`,'Accept':'application/vnd.github.v3+json'}});const d=await r.json();if(!r.ok)throw new Error(d.message||'Failed to fetch file.');if(d.type!=='file')throw new Error('Path is not a file.');S.sha=d.sha;const content=dec(d.content||'');S.jar.updateCode(content);setStatus(`Loaded ${S.p} (${fmtChars(content.length)}).`);}catch(err){setStatus(`Error: ${err.message}`,true);S.sha=null;}finally{setLoading(fetchBtn,false);}};\n const commitHandler=async()=>{setStatus();const{o,r,p,b,sha,t,jar}=S;if(!t)return setStatus('Error: GitHub token not found.',true);if(!o||!sha)return setStatus('Error: Fetch a file first.',true);const msg=prompt(\"Enter commit message:\",`Update ${p.split('/').pop()||p}`);if(msg===null)return setStatus('Commit cancelled.');if(!msg.trim())return setStatus('Error: Commit message cannot be empty.',true);const newContent=jar.toString();const url=`https://api.github.com/repos/${o}/${r}/contents/${encodeURIComponent(p).replace(/%2F/g,'/')}`;setStatus('Committing...');setLoading(commitBtn,true);try{const res=await fetch(url,{method:'PUT',headers:{'Authorization':`Bearer ${t}`,'Accept':'application/vnd.github.v3+json','Content-Type':'application/json'},body:JSON.stringify({message:msg.trim(),content:enc(newContent),sha,branch:b})});const data=await res.json();if(!res.ok)throw new Error(data.message||'Failed to commit.');S.sha=data.content.sha;setStatus('Committed successfully!');}catch(err){setStatus(`Error: ${err.message}`,true);}finally{setLoading(commitBtn,false);}};\n \n // Clipboard\n const clip=async(op)=>{try{if(op==='cut'||op==='copy'){await navigator.clipboard.writeText(S.jar.toString());if(op==='cut')S.jar.updateCode('');setStatus(op==='cut'?'Cut.':'Copied.');}else if(op==='paste'){const txt=await navigator.clipboard.readText();S.jar.updateCode(txt);setStatus(`Pasted (${fmtChars(txt.length)}).`);}}catch{setStatus(`${op.charAt(0).toUpperCase()+op.slice(1)} failed.`,true);}};\n\n // Listeners\n fetchBtn.addEventListener('click',fetchHandler);\n commitBtn.addEventListener('click',commitHandler);\n copyBtn.addEventListener('click',()=>clip('copy'));\n cutBtn.addEventListener('click',()=>clip('cut'));\n pasteBtn.addEventListener('click',()=>clip('paste'));\n pathInput.addEventListener('keydown',e=>{if(e.key==='Enter'){e.preventDefault();fetchHandler();}});\n\n lucide?.createIcons();\n})();\n</script>\n",
"extension_html": "<sune src='https://raw.githubusercontent.com/sune-org/store/refs/heads/main/sync.sune' private />"
},
"storage": {}
}
]