您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Greasy Fork is available in English.
为 GitHub 仓库添加 AI 驱动的代码分析按钮,支持 zread.ai 和 deepwiki.com 智能解读代码
当前为
// ==UserScript== // @name GitHub AI 代码分析助手 // @namespace http://tampermonkey.net/ // @version 2.2 // @description 为 GitHub 仓库添加 AI 驱动的代码分析按钮,支持 zread.ai 和 deepwiki.com 智能解读代码 // @match https://github.com/*/* // @grant none // @license MIT // ==/UserScript== (function () { 'use strict'; function insertButton() { try { // 提取用户名和仓库名 const pathParts = window.location.pathname.split('/').filter(Boolean); if (pathParts.length < 2) { console.log('AI Code Analysis: Not a repository page'); return; } const user = pathParts[0]; const repo = pathParts[1]; // 只在仓库主页、Code 页面插入 const subPath = pathParts[2] || ''; if (subPath && subPath !== 'tree' && subPath !== 'blob') { console.log('AI Code Analysis: Not on main repository page'); return; } // 避免重复插入 if (document.querySelector('#zread-ai-btn') || document.querySelector('#code-reader-dropdown')) { console.log('AI Code Analysis: Button already exists'); return; } // 更简单的策略:查找所有可能的按钮容器 let targetContainer = null; // 方法1: 直接查找 ul.pagehead-actions (这是最正确的容器) targetContainer = document.querySelector('ul.pagehead-actions'); if (targetContainer) { // 创建li包装 const li = document.createElement('li'); // 创建按钮组容器 const btnGroup = document.createElement('div'); btnGroup.className = 'BtnGroup d-flex'; btnGroup.style.marginLeft = '8px'; // 创建主按钮 const mainBtn = document.createElement('button'); mainBtn.id = 'zread-ai-btn'; mainBtn.type = 'button'; mainBtn.className = 'btn btn-sm BtnGroup-item'; mainBtn.innerHTML = '🤖 AI Analysis'; // GitHub 原生按钮样式 mainBtn.style.cssText = ` position: relative; display: inline-block; padding: 5px 16px; font-size: 12px; font-weight: 500; line-height: 20px; white-space: nowrap; vertical-align: middle; cursor: pointer; user-select: none; background-repeat: repeat-x; background-position: -1px -1px; background-size: 110% 110%; border: 1px solid rgba(31,35,40,0.15); border-radius: 6px 0 0 6px; appearance: none; color: #24292f; background-color: #f6f8fa; background-image: linear-gradient(180deg,#f9fbfc,#f6f8fa 90%); box-shadow: rgba(31, 35, 40, 0.04) 0px 1px 0px, rgba(255, 255, 255, 0.25) 0px 1px 0px inset; `; // 创建下拉按钮 const dropdownBtn = document.createElement('button'); dropdownBtn.type = 'button'; dropdownBtn.className = 'btn btn-sm BtnGroup-item px-2'; dropdownBtn.innerHTML = `<svg aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-triangle-down"> <path d="m4.427 7.427 3.396 3.396a.25.25 0 0 0 .354 0l3.396-3.396A.25.25 0 0 0 11.396 7H4.604a.25.25 0 0 0-.177.427Z"></path> </svg>`; dropdownBtn.style.cssText = ` position: relative; display: inline-block; padding: 5px 8px; font-size: 12px; font-weight: 500; line-height: 20px; white-space: nowrap; vertical-align: middle; cursor: pointer; user-select: none; background-repeat: repeat-x; background-position: -1px -1px; background-size: 110% 110%; border: 1px solid rgba(31,35,40,0.15); border-radius: 0 6px 6px 0; border-left: 0; appearance: none; color: #24292f; background-color: #f6f8fa; background-image: linear-gradient(180deg,#f9fbfc,#f6f8fa 90%); box-shadow: rgba(31, 35, 40, 0.04) 0px 1px 0px, rgba(255, 255, 255, 0.25) 0px 1px 0px inset; `; // 创建下拉菜单 const dropdown = document.createElement('div'); dropdown.id = 'code-reader-dropdown'; dropdown.style.cssText = ` position: absolute; top: 100%; right: 0; z-index: 100; width: 200px; margin-top: 5px; background-color: #ffffff; border: 1px solid rgba(31,35,40,0.15); border-radius: 6px; box-shadow: 0 8px 24px rgba(31,35,40,0.12); display: none; `; // 菜单选项 const options = [ { name: 'zread.ai', url: 'https://zread.ai', icon: '<svg aria-hidden="true" viewBox="0 0 32 32" version="1.1" width="16" height="16" data-view-component="true" class="v-align-middle" style="display: inline-block; vertical-align: middle;"><path d="M9.91922 3.2002H4.47922C3.77229 3.2002 3.19922 3.77327 3.19922 4.4802V9.9202C3.19922 10.6271 3.77229 11.2002 4.47922 11.2002H9.91922C10.6261 11.2002 11.1992 10.6271 11.1992 9.9202V4.4802C11.1992 3.77327 10.6261 3.2002 9.91922 3.2002Z" fill="currentColor"></path><path d="M9.91922 20.7998H4.47922C3.77229 20.7998 3.19922 21.3729 3.19922 22.0798V27.5198C3.19922 28.2267 3.77229 28.7998 4.47922 28.7998H9.91922C10.6261 28.7998 11.1992 28.2267 11.1992 27.5198V22.0798C11.1992 21.3729 10.6261 20.7998 9.91922 20.7998Z" fill="currentColor"></path><path d="M27.5208 3.2002H22.0808C21.3739 3.2002 20.8008 3.77327 20.8008 4.4802V9.9202C20.8008 10.6271 21.3739 11.2002 22.0808 11.2002H27.5208C28.2277 11.2002 28.8008 10.6271 28.8008 9.9202V4.4802C28.8008 3.77327 28.2277 3.2002 27.5208 3.2002Z" fill="currentColor"></path><path d="M8 24L24 8L8 24Z" fill="currentColor"></path><path d="M8 24L24 8" stroke="currentColor" stroke-width="2" stroke-linecap="round"></path></svg>', desc: 'Powered by Z.ai' }, { name: 'deepwiki.com', url: 'https://deepwiki.com', icon: '<svg viewBox="0 0 44 50" width="16" height="16" style="display: inline-block; vertical-align: middle; stroke: none;"><path style="fill: #2A6DCE;" d="M1.117,20.553l5.351,3.089c0.192,0.111,0.406,0.165,0.621,0.165c0.214,0,0.429-0.057,0.621-0.165l5.351-3.089 c0,0,0.015-0.012,0.022-0.017c0.081-0.049,0.158-0.108,0.227-0.175c0.01-0.01,0.02-0.022,0.03-0.032 c0.059-0.064,0.113-0.133,0.158-0.207c0.007-0.012,0.017-0.022,0.022-0.035c0.047-0.081,0.081-0.167,0.108-0.259 c0.005-0.02,0.01-0.039,0.015-0.059c0.022-0.094,0.039-0.19,0.039-0.291v-3.089c0-1.192,0.643-2.303,1.675-2.9s2.316-0.596,3.35,0 l2.675,1.545c0.086,0.049,0.177,0.084,0.271,0.111c0.02,0.005,0.04,0.012,0.059,0.017c0.091,0.022,0.185,0.035,0.278,0.037 c0.005,0,0.01,0,0.012,0c0.01,0,0.02-0.005,0.029-0.005c0.086,0,0.173-0.012,0.256-0.035c0.015-0.003,0.03-0.005,0.044-0.01 c0.091-0.025,0.18-0.062,0.264-0.108c0.007-0.005,0.017-0.005,0.025-0.01l5.351-3.089c0.384-0.222,0.621-0.631,0.621-1.074V4.69 c0-0.443-0.236-0.852-0.621-1.074l-5.356-3.087c-0.384-0.222-0.855-0.222-1.239,0l-5.351,3.089c0,0-0.015,0.012-0.022,0.017 c-0.081,0.049-0.158,0.108-0.227,0.175c-0.01,0.01-0.02,0.022-0.03,0.032c-0.059,0.064-0.113,0.133-0.158,0.207 c-0.007,0.012-0.017,0.022-0.022,0.034c-0.047,0.081-0.081,0.168-0.108,0.259c-0.005,0.02-0.01,0.039-0.015,0.059 c-0.022,0.094-0.039,0.19-0.039,0.291v3.089c0,1.192-0.643,2.303-1.675,2.902c-1.032,0.596-2.316,0.596-3.35,0L7.705,9.139 C7.618,9.09,7.527,9.055,7.434,9.028c-0.02-0.005-0.039-0.012-0.059-0.017C7.283,8.989,7.19,8.977,7.096,8.974 c-0.015,0-0.027,0-0.042,0c-0.089,0-0.175,0.012-0.259,0.034c-0.015,0.002-0.027,0.005-0.042,0.01 C6.663,9.043,6.574,9.08,6.49,9.127c-0.007,0.005-0.017,0.005-0.025,0.01l-5.348,3.092c-0.384,0.222-0.621,0.631-0.621,1.074v6.178 c0,0.444,0.236,0.852,0.621,1.074V20.553z"></path><path style="fill: #1DC19C;" d="M30.262,22.097c1.032-0.596,2.316-0.596,3.35,0l2.675,1.545c0.086,0.049,0.177,0.084,0.271,0.111 c0.02,0.005,0.039,0.012,0.059,0.017c0.091,0.022,0.185,0.034,0.278,0.037c0.005,0,0.01,0,0.012,0c0.01,0,0.02-0.003,0.029-0.005 c0.086,0,0.173-0.012,0.256-0.034c0.015-0.003,0.03-0.005,0.044-0.01c0.091-0.025,0.177-0.062,0.264-0.108 c0.007-0.005,0.017-0.005,0.027-0.01l5.351-3.089c0.384-0.222,0.621-0.631,0.621-1.074v-6.179c0-0.443-0.237-0.852-0.621-1.074 L37.53,9.134c-0.384-0.222-0.855-0.222-1.239,0l-5.351,3.089c0,0-0.015,0.012-0.022,0.017c-0.081,0.049-0.158,0.108-0.227,0.175 c-0.01,0.01-0.02,0.022-0.029,0.032c-0.059,0.064-0.113,0.133-0.158,0.207c-0.007,0.012-0.017,0.022-0.022,0.035 c-0.047,0.081-0.081,0.168-0.108,0.259c-0.005,0.02-0.01,0.039-0.015,0.059c-0.022,0.094-0.039,0.19-0.039,0.291v3.089 c0,1.192-0.643,2.303-1.675,2.902c-1.032,0.596-2.316,0.596-3.35,0l-2.675-1.545c-0.086-0.049-0.177-0.084-0.271-0.111 c-0.02-0.005-0.039-0.012-0.059-0.017c-0.091-0.022-0.185-0.035-0.278-0.037c-0.015,0-0.027,0-0.042,0 c-0.089,0-0.175,0.012-0.259,0.035c-0.015,0.003-0.027,0.005-0.042,0.01c-0.091,0.025-0.18,0.062-0.264,0.108 c-0.007,0.005-0.017,0.005-0.025,0.01l-5.351,3.089c-0.384,0.222-0.621,0.631-0.621,1.074v6.179c0,0.443,0.236,0.852,0.621,1.074 l5.351,3.089c0,0,0.017,0.005,0.025,0.01c0.084,0.047,0.173,0.084,0.264,0.108c0.015,0.005,0.03,0.005,0.044,0.01 c0.084,0.02,0.17,0.032,0.256,0.035c0.01,0,0.02,0.005,0.03,0.005c0.005,0,0.01,0,0.012,0c0.094,0,0.185-0.015,0.278-0.037 c0.02-0.005,0.039-0.01,0.059-0.017c0.094-0.027,0.185-0.062,0.271-0.111l2.675-1.545c1.032-0.596,2.316-0.596,3.35,0 c1.032,0.596,1.675,1.707,1.675,2.9v3.089c0,0.101,0.015,0.197,0.039,0.291c0.005,0.02,0.01,0.039,0.015,0.059 c0.027,0.091,0.061,0.177,0.108,0.259c0.007,0.012,0.015,0.022,0.022,0.034c0.044,0.074,0.099,0.143,0.158,0.207 c0.01,0.01,0.02,0.022,0.029,0.032c0.067,0.066,0.143,0.123,0.227,0.175c0.007,0.005,0.012,0.012,0.022,0.017l5.351,3.089 c0.192,0.111,0.407,0.165,0.621,0.165c0.214,0,0.429-0.057,0.621-0.165l5.351-3.089c0.384-0.222,0.621-0.631,0.621-1.074v-6.179 c0-0.443-0.236-0.852-0.621-1.074l-5.351-3.089c0,0-0.017-0.005-0.025-0.01c-0.084-0.047-0.173-0.084-0.264-0.108 c-0.015-0.005-0.027-0.005-0.042-0.01c-0.086-0.02-0.172-0.032-0.261-0.035c-0.012,0-0.027,0-0.039,0 c-0.094,0-0.187,0.015-0.278,0.037c-0.02,0.005-0.037,0.01-0.057,0.017c-0.094,0.027-0.185,0.062-0.271,0.111l-2.675,1.545 c-1.032,0.596-2.316,0.596-3.348,0c-1.032-0.596-1.675-1.707-1.675-2.902c0-1.195,0.643-2.303,1.675-2.9H30.262z"></path><path style="fill: #1796E2;" d="M27.967,38.054l-5.351-3.089c0,0-0.017-0.005-0.025-0.01c-0.084-0.047-0.172-0.084-0.264-0.108 c-0.015-0.005-0.03-0.005-0.044-0.01c-0.086-0.02-0.172-0.032-0.259-0.035c-0.015,0-0.027,0-0.042,0 c-0.094,0-0.187,0.015-0.278,0.037c-0.02,0.005-0.037,0.01-0.057,0.017c-0.094,0.027-0.185,0.062-0.271,0.111l-2.675,1.545 c-1.032,0.596-2.316,0.596-3.348,0c-1.032-0.596-1.675-1.707-1.675-2.902V30.52c0-0.101-0.015-0.197-0.039-0.291 c-0.005-0.02-0.01-0.039-0.015-0.059c-0.027-0.091-0.062-0.177-0.108-0.259c-0.007-0.012-0.015-0.022-0.022-0.035 c-0.044-0.074-0.099-0.143-0.158-0.207c-0.01-0.01-0.02-0.022-0.03-0.032c-0.066-0.066-0.143-0.123-0.227-0.175 c-0.007-0.005-0.012-0.012-0.022-0.017l-5.351-3.089c-0.384-0.222-0.855-0.222-1.239,0l-5.351,3.089 c-0.384,0.222-0.621,0.631-0.621,1.074v6.179c0,0.443,0.236,0.852,0.621,1.074l5.351,3.089c0,0,0.017,0.007,0.025,0.01 c0.084,0.047,0.17,0.084,0.261,0.108c0.015,0.005,0.03,0.007,0.044,0.01c0.084,0.02,0.17,0.032,0.256,0.035 c0.01,0,0.02,0.005,0.032,0.005c0.005,0,0.01,0,0.015,0c0.094,0,0.185-0.015,0.276-0.037c0.02-0.005,0.039-0.01,0.059-0.017 c0.094-0.027,0.185-0.062,0.271-0.111l2.675-1.545c1.032-0.596,2.316-0.596,3.35,0c1.032,0.596,1.675,1.707,1.675,2.9v3.089 c0,0.101,0.015,0.197,0.039,0.291c0.005,0.02,0.01,0.039,0.015,0.059c0.027,0.091,0.062,0.177,0.108,0.259 c0.007,0.012,0.015,0.022,0.022,0.035c0.044,0.074,0.099,0.143,0.158,0.207c0.01,0.01,0.02,0.022,0.03,0.032 c0.067,0.067,0.143,0.123,0.227,0.175c0.007,0.005,0.012,0.012,0.022,0.017l5.351,3.089c0.192,0.111,0.406,0.165,0.621,0.165 s0.429-0.057,0.621-0.165l5.351-3.089c0.384-0.222,0.621-0.631,0.621-1.074V39.13c0-0.443-0.236-0.852-0.621-1.074L27.967,38.054z"></path></svg>', desc: 'Powered by Devin.ai' } ]; options.forEach(option => { const menuItem = document.createElement('a'); menuItem.href = '#'; menuItem.innerHTML = ` <div style="display: flex; align-items: center; justify-content: space-between;"> <div style="display: flex; align-items: center;"> <span style="margin-right: 8px;">${option.icon}</span> <div> <div style="font-weight: 500;">${option.name}</div> <div style="font-size: 11px; color: #656d76; margin-top: 2px;">${option.desc}</div> </div> </div> </div> `; menuItem.style.cssText = ` display: block; padding: 12px 16px; color: #24292f; text-decoration: none; border-bottom: 1px solid rgba(31,35,40,0.06); font-size: 14px; line-height: 20px; transition: background-color 0.2s ease; `; menuItem.addEventListener('mouseenter', function () { this.style.backgroundColor = '#f6f8fa'; }); menuItem.addEventListener('mouseleave', function () { this.style.backgroundColor = 'transparent'; }); menuItem.addEventListener('click', function (e) { e.preventDefault(); window.open(`${option.url}/${user}/${repo}`, '_blank'); dropdown.style.display = 'none'; }); dropdown.appendChild(menuItem); }); // 默认点击事件 (使用 zread.ai) mainBtn.addEventListener('click', function (e) { e.preventDefault(); window.open(`https://zread.ai/${user}/${repo}`, '_blank'); }); // 下拉按钮点击事件 dropdownBtn.addEventListener('click', function (e) { e.preventDefault(); e.stopPropagation(); const isVisible = dropdown.style.display === 'block'; dropdown.style.display = isVisible ? 'none' : 'block'; }); // 点击其他地方隐藏下拉菜单 document.addEventListener('click', function (e) { if (!btnGroup.contains(e.target)) { dropdown.style.display = 'none'; } }); // 按钮悬停效果 [mainBtn, dropdownBtn].forEach(btn => { btn.addEventListener('mouseenter', function () { this.style.backgroundColor = '#f3f4f6'; this.style.borderColor = 'rgba(31,35,40,0.25)'; }); btn.addEventListener('mouseleave', function () { this.style.backgroundColor = '#f6f8fa'; this.style.borderColor = 'rgba(31,35,40,0.15)'; }); }); // 组装元素 btnGroup.appendChild(mainBtn); btnGroup.appendChild(dropdownBtn); btnGroup.appendChild(dropdown); btnGroup.style.position = 'relative'; li.appendChild(btnGroup); targetContainer.appendChild(li); console.log('AI Code Analysis: Button group inserted into pagehead-actions!'); return; } // 方法2: 查找 Star 按钮并找到其容器 const starButtons = document.querySelectorAll('[aria-label*="Star"]'); for (let starBtn of starButtons) { if (starBtn.textContent && starBtn.textContent.includes('Star')) { targetContainer = starBtn.closest('div[class*="d-flex"], div[data-view-component="true"]'); if (targetContainer) break; } } // 方法3: 查找包含 "Fork" 文本的按钮 if (!targetContainer) { const forkButtons = document.querySelectorAll('*'); for (let element of forkButtons) { if (element.textContent && element.textContent.trim() === 'Fork' && element.tagName === 'BUTTON') { targetContainer = element.parentElement?.parentElement; if (targetContainer) break; } } } // 方法4: 查找包含 "Watch" 文本的按钮 if (!targetContainer) { const watchButtons = document.querySelectorAll('*'); for (let element of watchButtons) { if (element.textContent && element.textContent.includes('Watch') && element.tagName === 'BUTTON') { targetContainer = element.closest('div'); if (targetContainer && targetContainer.querySelector('[aria-label*="Star"]')) { break; } } } } if (!targetContainer) { console.log('AI Code Analysis: Could not find target container'); return; } console.log('AI Code Analysis: Found target container:', targetContainer); // 创建按钮(用于非 ul.pagehead-actions 容器) const btn = document.createElement('button'); btn.id = 'zread-ai-btn-fallback'; btn.type = 'button'; btn.innerHTML = '🤖 AI Analysis'; // 模拟 GitHub 按钮样式 btn.style.cssText = ` position: relative; display: inline-flex; align-items: center; justify-content: center; padding: 5px 16px; font-size: 14px; font-weight: 600; line-height: 20px; white-space: nowrap; vertical-align: middle; cursor: pointer; user-select: none; border: 1px solid #0969da; border-radius: 6px; margin-left: 8px; background-color: #0969da; color: #ffffff; text-decoration: none; transition: 80ms cubic-bezier(0.65, 0, 0.35, 1); font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "Noto Sans", Helvetica, Arial, sans-serif; box-shadow: 0 1px 0 rgba(31, 35, 40, 0.1); `; // 添加悬停效果 btn.addEventListener('mouseenter', function () { this.style.backgroundColor = '#0860ca'; this.style.borderColor = '#0860ca'; this.style.transform = 'translateY(-1px)'; this.style.boxShadow = '0 3px 6px rgba(9, 105, 218, 0.15)'; }); btn.addEventListener('mouseleave', function () { this.style.backgroundColor = '#0969da'; this.style.borderColor = '#0969da'; this.style.transform = 'translateY(0)'; this.style.boxShadow = '0 1px 0 rgba(31, 35, 40, 0.1)'; }); // 点击事件 btn.addEventListener('click', function (e) { e.preventDefault(); window.open(`https://zread.ai/${user}/${repo}`, '_blank'); }); // 插入按钮 targetContainer.appendChild(btn); console.log('AI Code Analysis: Fallback button inserted successfully!'); } catch (error) { console.error('AI Code Analysis: Error inserting button:', error); } } // 使用更健壮的页面监听 let lastUrl = location.href; // 页面变化监听 const observer = new MutationObserver((mutations) => { const currentUrl = location.href; if (currentUrl !== lastUrl) { lastUrl = currentUrl; console.log('AI Code Analysis: URL changed to:', currentUrl); setTimeout(insertButton, 1500); } // 检查是否有新的按钮容器出现 for (let mutation of mutations) { if (mutation.addedNodes) { for (let node of mutation.addedNodes) { if (node.nodeType === 1 && (node.querySelector && node.querySelector('[aria-label*="Star"]'))) { setTimeout(insertButton, 500); break; } } } } }); observer.observe(document.body, { childList: true, subtree: true, attributes: false }); // 多次尝试初始化 document.addEventListener('DOMContentLoaded', () => { setTimeout(insertButton, 1000); }); setTimeout(insertButton, 1000); setTimeout(insertButton, 2000); setTimeout(insertButton, 3000); // 如果页面已经加载完成 if (document.readyState === 'complete' || document.readyState === 'interactive') { setTimeout(insertButton, 500); } })();