Files
store/github-utilities/git-reset.sune

1 line
16 KiB
JSON

[{"id":"pyaok99","name":"Reset Hard Force Push","pinned":false,"avatar":"data:image/webp;base64,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","url":"gh://sune-org/store/github-utilities/git-reset.sune","updatedAt":1757365793347,"settings":{"model":"openai/gpt-5","temperature":"1","top_p":"0.97","top_k":"0","frequency_penalty":"0","repetition_penalty":"1","min_p":"0","top_a":"0","verbosity":"","reasoning_effort":"default","system_prompt":"","html":"<!-- Sune: GitHub Time Machine -->\n<div id=\"gitReverterSune\" class=\"w-full max-w-3xl mx-auto p-4 md:p-6 bg-slate-100 rounded-2xl font-sans text-gray-700\">\n\n<!-- Styles for this Sune -->\n<style>\n/* Neumorphism classes */\n.neu-outset { box-shadow: 5px 5px 10px #c5cdd8, -5px -5px 10px #ffffff; }\n.neu-inset { box-shadow: inset 5px 5px 10px #c5cdd8, inset -5px -5px 10px #ffffff; }\n.neu-outset-sm { box-shadow: 2px 2px 5px #c5cdd8, -2px -2px 5px #ffffff; }\n.neu-inset-sm { box-shadow: inset 2px 2px 5px #c5cdd8, inset -2px -2px 5px #ffffff; }\n.neu-outset-red { box-shadow: 5px 5px 10px #fca5a5, -5px -5px 10px #ffffff; }\n\n/* Custom scrollbar */\n#gr_commitsList::-webkit-scrollbar { width: 6px; }\n#gr_commitsList::-webkit-scrollbar-track { background: transparent; }\n#gr_commitsList::-webkit-scrollbar-thumb { background: #cbd5e1; border-radius: 3px; }\n#gr_commitsList::-webkit-scrollbar-thumb:hover { background: #94a3b8; }\n\n/* Modal animations */\n@keyframes fadeIn { from { opacity: 0; } to { opacity: 1; } }\n@keyframes scaleIn { from { opacity: 0; transform: scale(0.95); } to { opacity: 1; transform: scale(1); } }\n#gr_confirmModal .modal-bg { animation: fadeIn 0.2s ease-out forwards; }\n#gr_confirmModal .modal-content { animation: scaleIn 0.2s ease-out forwards; }\n</style>\n\n<!-- Sune Header -->\n<div class=\"flex items-center justify-between pb-4\">\n <h1 class=\"text-xl font-bold flex items-center gap-3 text-slate-600\">\n <i data-lucide=\"history\" class=\"w-6 h-6\"></i>\n GitHub Reset Hard Force Push\n </h1>\n <span class=\"text-xs font-mono bg-slate-200 text-slate-500 px-2 py-1 rounded-full\">v1.1</span>\n</div>\n\n<!-- Input Form -->\n<div class=\"mt-4\">\n <label for=\"gr_repoPathInput\" class=\"text-sm font-medium text-slate-600 mb-2 block\">Repository Path</label>\n <div class=\"flex flex-col sm:flex-row items-stretch gap-3\">\n <input type=\"text\" id=\"gr_repoPathInput\" placeholder=\"owner/repo@branch\" class=\"flex-grow w-full px-4 py-3 bg-slate-100 rounded-xl focus:outline-none transition-all duration-200 neu-outset focus:neu-inset\">\n <button id=\"gr_loadCommitsBtn\" class=\"w-full sm:w-auto px-6 py-3 bg-slate-100 text-slate-800 font-semibold rounded-xl hover:text-black active:neu-inset transition-all duration-200 flex items-center justify-center gap-2 disabled:opacity-50 disabled:cursor-not-allowed neu-outset\">\n <i data-lucide=\"arrow-down-circle\" class=\"w-4 h-4\"></i>\n <span>Load Commits</span>\n </button>\n </div>\n</div>\n\n<!-- Status Display -->\n<div id=\"gr_statusDisplay\" class=\"mt-4\"></div>\n\n<!-- Commits List -->\n<div id=\"gr_commitsContainer\" class=\"mt-4 hidden\">\n <h2 class=\"text-md font-semibold text-slate-500 mb-2\">Commit History</h2>\n <div id=\"gr_commitsList\" class=\"max-h-[50vh] overflow-y-auto rounded-lg p-2 neu-inset divide-y divide-slate-200/80\">\n <!-- Commit items injected here -->\n </div>\n</div>\n\n<!-- Confirmation Modal -->\n<div id=\"gr_confirmModal\" class=\"hidden fixed inset-0 z-[100] p-4 flex items-center justify-center\">\n <div class=\"modal-bg absolute inset-0 bg-black/40 backdrop-blur-sm\"></div>\n <div class=\"modal-content relative w-full max-w-md bg-slate-100 rounded-2xl p-6 neu-outset\">\n <div class=\"text-center\">\n <div class=\"mx-auto flex items-center justify-center h-12 w-12 rounded-full bg-red-100 neu-outset-sm\">\n <i data-lucide=\"alert-triangle\" class=\"h-6 w-6 text-red-600\"></i>\n </div>\n <h3 class=\"mt-4 text-lg font-bold text-gray-900\">Confirm Branch Rewind</h3>\n <div class=\"mt-2 text-sm text-gray-600 space-y-2\">\n <p>This is a highly destructive action. You are about to <strong class=\"font-bold text-red-700\">permanently repoint the tip</strong> of the branch:</p>\n <p id=\"gr_confirmBranchInfo\" class=\"font-mono bg-slate-200 p-2 rounded-md text-xs neu-inset-sm\"></p>\n <p>This will rewrite public history. Please type the repository name <strong id=\"gr_confirmRepoName\" class=\"font-bold\"></strong> to confirm.</p>\n </div>\n </div>\n <div class=\"mt-4\">\n <input type=\"text\" id=\"gr_confirmRepoInput\" autocomplete=\"off\" class=\"w-full text-center px-4 py-3 bg-slate-100 rounded-xl focus:outline-none transition-all duration-200 neu-outset focus:neu-inset focus:ring-2 focus:ring-red-400\">\n </div>\n <div class=\"mt-5 grid grid-cols-1 sm:grid-cols-2 gap-3\">\n <button id=\"gr_cancelBtn\" type=\"button\" class=\"w-full justify-center rounded-xl px-4 py-2.5 bg-slate-100 text-base font-medium text-gray-700 neu-outset hover:text-black active:neu-inset transition-all duration-200\">Cancel</button>\n <button id=\"gr_confirmBtn\" type=\"button\" class=\"w-full justify-center rounded-xl px-4 py-2.5 bg-red-500 text-base font-medium text-white shadow-md hover:bg-red-600 focus:outline-none disabled:bg-red-300 disabled:cursor-not-allowed transition-all\">Repoint & Force Push</button>\n </div>\n </div>\n</div>\n\n<!-- Sune Script -->\n<script>\n(() => {\nconst SUNE_ID = window.SUNE?.id || 'git_reverter_sune';\nconst $ = (s, p=document) => p.querySelector(s);\nconst root = $('#gitReverterSune');\nconst pathIn = $('#gr_repoPathInput', root);\nconst loadBtn = $('#gr_loadCommitsBtn', root);\nconst statusEl = $('#gr_statusDisplay', root);\nconst commitsCont = $('#gr_commitsContainer', root);\nconst commitsList = $('#gr_commitsList', root);\nconst modal = $('#gr_confirmModal', root);\nconst confirmBranchInfo = $('#gr_confirmBranchInfo', root);\nconst confirmRepoName = $('#gr_confirmRepoName', root);\nconst confirmRepoIn = $('#gr_confirmRepoInput', root);\nconst cancelBtn = $('#gr_cancelBtn', root);\nconst confirmBtn = $('#gr_confirmBtn', root);\n\nlet worker, isLoading = false, resetTarget = null;\n\nconst workerCode = `\nself.onmessage = async e => {\n const { action, payload } = e.data;\n const { path, token, sha } = payload;\n const [owner, repoBranch] = (path || '').split('/');\n const [repo, branch] = (repoBranch || '').split('@');\n\n if (!token) return self.postMessage({ type: 'error', message: 'GitHub token not found. Please set it in Account Settings.' });\n if (!owner || !repo || !branch) return self.postMessage({ type: 'error', message: 'Invalid format. Use: owner/repo@branch' });\n\n const headers = { 'Authorization': \\`Bearer \\${token}\\`, 'Accept': 'application/vnd.github.v3+json', 'X-GitHub-Api-Version': '2022-11-28' };\n try {\n if (action === 'getCommits') {\n const res = await fetch(\\`https://api.github.com/repos/\\${owner}/\\${repo}/commits?sha=\\${branch}\\`, { headers });\n const data = await res.json();\n if (!res.ok) throw new Error(data.message || \\`HTTP \\${res.status}\\`);\n self.postMessage({ type: 'commitsResult', data });\n } else if (action === 'repointBranch') {\n if (!sha) throw new Error('Commit SHA missing.');\n const res = await fetch(\\`https://api.github.com/repos/\\${owner}/\\${repo}/git/refs/heads/\\${branch}\\`, {\n method: 'PATCH',\n headers: { ...headers, 'Content-Type': 'application/json' },\n body: JSON.stringify({ sha, force: true })\n });\n const data = await res.json();\n if (!res.ok) throw new Error(data.message || \\`Failed to repoint branch. Status: \\${res.status}\\`);\n self.postMessage({ type: 'repointSuccess', message: 'Branch tip repointed successfully.' });\n }\n } catch (error) { self.postMessage({ type: 'error', message: error.message }); }\n};\n`;\n\nconst renderStatus = (type, msg) => {\n const C = { e: 'red', s: 'green', l: 'blue' };\n const I = { e: 'alert-circle', s: 'check-circle-2', l: 'loader-2' };\n const t = type.charAt(0);\n statusEl.innerHTML = `<div class=\"flex items-center gap-3 p-3 text-sm font-medium rounded-lg border bg-${C[t]}-100 border-${C[t]}-300 text-${C[t]}-800\"><i data-lucide=\"${I[t]}\" class=\"w-5 h-5 flex-shrink-0 ${t==='l'?'animate-spin':''}\"></i><span>${msg}</span></div>`;\n window.lucide?.createIcons();\n};\n\nconst renderCommits = (data) => {\n if (!data?.length) {\n commitsList.innerHTML = `<div class=\"p-4 text-center text-gray-500\">No commits found.</div>`;\n return;\n }\n commitsList.innerHTML = data.map(c => {\n const msg = c.commit.message.split('\\\\n')[0];\n const author = c.commit.author;\n const date = new Date(author.date).toLocaleString([], { year:'numeric',month:'short',day:'numeric',hour:'2-digit',minute:'2-digit' });\n return `\n <div class=\"p-3 first:pt-1 last:pb-1\">\n <div class=\"flex items-center justify-between gap-2\">\n <div class=\"flex items-center gap-3 min-w-0\">\n ${c.author ? `<img src=\"${c.author.avatar_url}\" class=\"w-8 h-8 rounded-full bg-gray-200\" alt=\"${author.name}\">` : ''}\n <div class=\"min-w-0\">\n <p class=\"font-semibold text-gray-800 truncate\" title=\"${msg}\">${msg}</p>\n <p class=\"text-xs text-gray-500\"><strong>${author.name}</strong> on ${date}</p>\n </div>\n </div>\n <button data-sha=\"${c.sha}\" title=\"Point branch tip to this commit\" class=\"repoint-btn ml-2 flex-shrink-0 px-3 py-1.5 text-xs font-semibold text-slate-700 bg-slate-100 rounded-md active:neu-inset-sm hover:text-black transition-all neu-outset-sm\">\n Point branch tip here\n </button>\n </div>\n <div class=\"mt-2 text-xs text-gray-600 font-mono bg-slate-200/80 inline-block px-2 py-0.5 rounded neu-inset-sm\">${c.sha.substring(0, 7)}</div>\n </div>`;\n }).join('');\n};\n\nconst loadCommits = () => {\n if (isLoading) return;\n const path = pathIn.value.trim();\n if (!path) return renderStatus('error', 'Please enter a repository path.');\n const token = localStorage.getItem('gh_token') || '';\n if (!token) return renderStatus('error', 'GitHub token not found. Set in Account Settings.');\n\n isLoading = true;\n loadBtn.disabled = true;\n commitsCont.classList.add('hidden');\n renderStatus('loading', `Fetching commits for ${path}...`);\n \n localStorage.setItem(`${SUNE_ID}_last_path`, path);\n worker.postMessage({ action: 'getCommits', payload: { path, token } });\n};\n\nconst toggleModal = (show, sha) => {\n if (show) {\n const [owner, repoBranch] = (pathIn.value.trim() || '').split('/');\n const [repo, branch] = (repoBranch || '').split('@');\n if (!owner || !repo || !branch) return;\n \n resetTarget = { sha, repo };\n confirmBranchInfo.textContent = `${owner}/${repo}@${branch}`;\n confirmRepoName.textContent = repo;\n confirmRepoIn.value = '';\n confirmBtn.disabled = true;\n modal.classList.remove('hidden');\n document.body.style.overflow = 'hidden';\n confirmRepoIn.focus();\n } else {\n modal.classList.add('hidden');\n document.body.style.overflow = '';\n resetTarget = null;\n }\n};\n\nconst handleRepoint = () => {\n if (!resetTarget || isLoading) return;\n \n isLoading = true;\n confirmBtn.disabled = true;\n confirmBtn.innerHTML = '<i data-lucide=\"loader-2\" class=\"w-5 h-5 animate-spin mx-auto\"></i>';\n window.lucide?.createIcons();\n\n const token = localStorage.getItem('gh_token');\n const path = pathIn.value.trim();\n worker.postMessage({ action: 'repointBranch', payload: { path, token, sha: resetTarget.sha } });\n};\n\n// --- Init & Listeners ---\nworker = new Worker(URL.createObjectURL(new Blob([workerCode],{type:'application/javascript'})));\n\nworker.onmessage = e => {\n const { type, data, message } = e.data;\n isLoading = false;\n loadBtn.disabled = false;\n \n if (type === 'commitsResult') {\n statusEl.innerHTML = '';\n commitsCont.classList.remove('hidden');\n renderCommits(data);\n } else if (type === 'repointSuccess') {\n toggleModal(false);\n renderStatus('success', message);\n setTimeout(loadCommits, 1000);\n } else if (type === 'error') {\n renderStatus('error', message);\n commitsCont.classList.add('hidden');\n }\n};\n\nloadBtn.addEventListener('click', loadCommits);\npathIn.addEventListener('keydown', e => e.key === 'Enter' && loadCommits());\ncommitsList.addEventListener('click', e => {\n const btn = e.target.closest('.repoint-btn');\n if (btn?.dataset.sha) toggleModal(true, btn.dataset.sha);\n});\ncancelBtn.addEventListener('click', () => toggleModal(false));\nmodal.querySelector('.modal-bg').addEventListener('click', () => toggleModal(false));\nconfirmBtn.addEventListener('click', handleRepoint);\nconfirmRepoIn.addEventListener('input', () => {\n confirmBtn.disabled = confirmRepoIn.value !== resetTarget?.repo;\n});\n\npathIn.value = localStorage.getItem(`${SUNE_ID}_last_path`) || '';\nwindow.lucide?.createIcons();\n})();\n</script>\n</div>\n","extension_html":"<sune src='https://raw.githubusercontent.com/sune-org/store/refs/heads/main/sync.sune' private />","hide_composer":false,"presence_penalty":0,"max_tokens":0,"script":""},"storage":{}}]