尧图网络科技YAOTU DIGITAL 获取报价
获取报价
首页 / 资讯中心 / 文章详情

用 Claude Code 从零构建 GitHub Star 管理器:TaoToken 统一 Key 配置与 Chrome 扩展 Manifest V3 骨架

发布时间:2026/9/26 16:21:09

资讯中心
01
ARTICLE

用 Claude Code 从零构建 GitHub Star 管理器:TaoToken 统一 Key 配置与 Chrome 扩展 Manifest V3 骨架

用 Claude Code 从零构建 GitHub Star 管理器:TaoToken 统一 Key 配置与 Chrome 扩展 Manifest V3 骨架
1. 从 Star 堆积到可管理这个扩展要解决什么GitHub 上点 Star 这个动作太顺手了顺手到几年下来列表里躺着几百上千个项目真要用的时候一个都想不起来叫什么。我自己翻 Star 列表找某个工具库经常是滚了十几屏还没找到最后只能靠搜索引擎重新搜一遍——那当初 Star 它干嘛。这个场景的核心痛点其实就三个项目散乱没有分类、查找全靠肉眼扫、换台电脑分类数据就没了。所以这次要做的是一个 Chrome 扩展在 GitHub 页面右侧挂一个吸附式管理面板能拉取你的 Star 列表、打标签分组、本地搜索数据通过 GitHub Gist 做跨设备同步。技术栈选 Manifest V3 原生 JavaScript不引框架保证轻量和加载速度。整个工程起点不是先写界面而是先把项目骨架和统一 API 通道搭好——这一步决定了后面拉数据、调模型、做同步顺不顺。这篇会交付四样东西可复制的扩展目录结构、Manifest V3 配置片段、TaoToken 统一 Key 与 API 通道的配置骨架、以及加载扩展后验证 Star 列表拉取成功的具体动作。适合已经会一点 JavaScript、想用 Claude Code 辅助从零搭一个真实扩展的开发者。全程用 Claude Code 做结对遇到报错直接贴给它改效率比纯手写高不少。2. 前置准备TaoToken 统一 Key 与 Claude Code 接入在写第一行扩展代码之前先把「模型调用通道」这件事定下来。原因很实际Claude Code 在终端里帮你写代码、改报错、生成配置背后需要一个稳定的 API 通道而扩展本身后续如果要加智能分类、自动打标签这类功能也会走同一个通道。与其到处散落 Key不如统一到一处管理。TaoToken 在这里扮演的就是统一入口的角色一个 Key 覆盖多种模型调用配置集中切换模型不用改一堆环境变量。对 Claude Code 这种长期在终端跑的编码工具来说统一 Key 的好处是配置一次、长期复用不会因为换模型就要重新折腾一遍。你需要先拿到 Key。打开控制台页面创建 API Keyhttps://taotoken.net/console?utm_sourcetaotoken_aicg_blog_endutm_contentconsoleutm_campaignrewrite创建完 Key 之后接入文档在这里里面有各语言和各工具的接入示例建议先扫一眼https://taotoken.net/doc?utm_sourcetaotoken_aicg_blog_endutm_contentdocutm_campaignrewriteAPI 基础地址统一用这个注意它不带任何查询参数https://taotoken.net/api如果你主要用 Claude Code 做长期编码建议直接看 Coding Plan 的说明它更适合高频、长时间的 Agent 式开发https://taotoken.net/coding-plan?utm_sourcetaotoken_aicg_blog_endutm_contentcoding-planutm_campaignrewriteClaude Code 的接入配置单独有一页照着填就行https://taotoken.net/claude-code-anthropic?utm_sourcetaotoken_aicg_blog_endutm_contentClaudeCodeAnthropicutm_campaignrewrite注意Key 只存在本地配置文件里不要提交到 Git 仓库也不要在扩展代码里硬编码。后面我们会用 settings.json 和 config.toml 两个文件分别承载「扩展配置」和「工具链配置」职责分开。3. 项目骨架Manifest V3 目录结构与配置先建目录。Manifest V3 和 V2 最大的区别是后台脚本从常驻的 background page 变成了事件驱动的 Service Worker所以文件命名和注册方式都要跟着变。下面是我实测下来比较顺手的结构star-manager/ ├── manifest.json # 扩展清单MV3 格式 ├── background.js # Service Worker处理 API 请求与消息 ├── content.js # 内容脚本注入 GitHub 页面 ├── content.css # 面板样式 ├── popup.html # 点击图标弹出的小面板 ├── popup.js ├── lib/ │ ├── github.js # GitHub API 封装 │ └── storage.js # 本地存储与 Gist 同步 ├── config/ │ ├── settings.json # 扩展运行配置含 API 通道 │ └── config.toml # 工具链配置Claude Code 用 └── icons/ ├── icon16.png ├── icon48.png └── icon128.pngmanifest.json 是 MV3 的核心权限声明要精确别一上来就all_urls。下面这份可以直接用{ manifest_version: 3, name: GitHub Star Manager, version: 0.1.0, description: 在 GitHub 页面右侧管理你的 Star 项目支持标签、搜索与 Gist 同步。, permissions: [storage, activeTab, scripting], host_permissions: [ https://api.github.com/*, https://taotoken.net/* ], background: { service_worker: background.js, type: module }, content_scripts: [ { matches: [https://github.com/*], js: [content.js], css: [content.css], run_at: document_idle } ], action: { default_popup: popup.html, default_icon: { 16: icons/icon16.png, 48: icons/icon48.png, 128: icons/icon128.png } }, icons: { 16: icons/icon16.png, 48: icons/icon48.png, 128: icons/icon128.png } }几个容易踩的点host_permissions里必须显式列出api.github.com否则 fetch 会被 CORS 拦background.type设成module才能用import语法拆分 lib 目录run_at用document_idle避免页面还没渲染完就注入。接下来是 config/settings.json它承载扩展运行时的统一配置包括 TaoToken 的 API 通道地址。注意这里只放地址和模型名Key 不放进来{ api: { baseUrl: https://taotoken.net/api, chatPath: /v1/chat/completions, defaultModel: claude-sonnet }, github: { apiBase: https://api.github.com, perPage: 100 }, ui: { panelWidth: 40%, hotkey: AltS } }config/config.toml 是给 Claude Code 这类终端工具用的和扩展配置分开避免混在一起# Claude Code 工具链配置 [api] base_url https://taotoken.net/api model claude-sonnet [project] name star-manager root ./star-manager提示settings.json 里的 baseUrl 和 config.toml 里的 base_url 指向同一个通道但用途不同——前者给扩展运行时用后者给编码工具用。统一到 TaoToken 的好处就是改一处地址两边都生效。4. 可复制配置background.js 与 GitHub Star 拉取Service Worker 是 MV3 里处理网络请求的中转站。内容脚本直接 fetch 外部 API 容易受页面 CSP 限制所以把请求统一丢给 background 处理通过消息传递拿结果。先写 GitHub API 封装// lib/github.js const GH_API https://api.github.com; export async function fetchStarred(token, page 1, perPage 100) { const url ${GH_API}/user/starred?page${page}per_page${perPage}; const res await fetch(url, { headers: { Authorization: Bearer ${token}, Accept: application/vnd.github.v3json } }); if (!res.ok) { throw new Error(GitHub API ${res.status}: ${await res.text()}); } return res.json(); }background.js 负责监听消息并调用上面的封装同时把结果缓存到 chrome.storage// background.js import { fetchStarred } from ./lib/github.js; chrome.runtime.onMessage.addListener((msg, sender, sendResponse) { if (msg.type FETCH_STARS) { handleFetchStars(msg.token).then(sendResponse); return true; // 异步响应必须返回 true } }); async function handleFetchStars(token) { try { const stars await fetchStarred(token); const simplified stars.map((item) ({ id: item.id, name: item.full_name, url: item.html_url, desc: item.description, lang: item.language, stars: item.stargazers_count })); await chrome.storage.local.set({ stars: simplified, syncedAt: Date.now() }); return { ok: true, count: simplified.length }; } catch (err) { return { ok: false, error: err.message }; } }content.js 里注入右侧面板并触发拉取。这里先做最小可用版本把按钮和消息通道打通// content.js function createPanel() { const panel document.createElement(div); panel.id gsm-panel; panel.innerHTML button idgsm-toggleStar 管理/button div idgsm-body classcollapsed input idgsm-token placeholder粘贴 GitHub Token / button idgsm-sync拉取 Star/button ul idgsm-list/ul /div; document.body.appendChild(panel); document.getElementById(gsm-sync).onclick async () { const token document.getElementById(gsm-token).value.trim(); const resp await chrome.runtime.sendMessage({ type: FETCH_STARS, token }); if (resp.ok) { const { stars } await chrome.storage.local.get(stars); renderList(stars); } else { alert(拉取失败 resp.error); } }; } function renderList(stars) { const ul document.getElementById(gsm-list); ul.innerHTML stars .slice(0, 50) .map((s) lia href${s.url} target_blank${s.name}/a · ${s.lang || N/A}/li) .join(); } createPanel();content.css 里给面板一个吸附式布局初始收起点按钮展开#gsm-panel { position: fixed; top: 0; right: 0; width: 40%; height: 100vh; z-index: 9999; background: #fff; box-shadow: -4px 0 24px rgba(0, 0, 0, 0.12); transform: translateX(100%); transition: transform 0.3s ease; } #gsm-panel.open { transform: translateX(0); } #gsm-toggle { position: absolute; left: -48px; top: 80px; width: 48px; height: 48px; border-radius: 50%; background: linear-gradient(135deg, #667eea, #764ba2); color: #fff; border: none; cursor: pointer; }5. 验证请求加载扩展并确认 Star 列表拉取成功代码写完接下来是把它真正跑起来。Chrome 加载未打包扩展的流程如下打开chrome://extensions/右上角开启「开发者模式」点「加载已解压的扩展程序」选中 star-manager 目录。加载成功后扩展卡片会显示名称和版本号如果 manifest.json 有语法错误这里会直接报红并给出具体行号。加载后打开任意 GitHub 页面比如你的 Star 列表页https://github.com/你的用户名?tabstars。右侧应该出现一个圆形按钮点击展开面板。在输入框粘贴一个有public_repo权限的 GitHub Token点「拉取 Star」。如果一切正常列表会在几秒内渲染出前 50 个项目格式是「项目名 · 语言」。同时打开 DevTools 的 Application 面板在 Storage → Local Storage 里能看到stars和syncedAt两个键说明数据已经落到本地缓存。想确认 API 通道本身是否通可以在终端直接打一条请求把 Key 换成你自己的curl https://taotoken.net/api/v1/chat/completions \ -H Authorization: Bearer $TAOTOKEN_KEY \ -H Content-Type: application/json \ -d { model: claude-sonnet, messages: [{role: user, content: ping}] }返回里带choices字段就说明通道正常。这一步和扩展的 GitHub 拉取是两条独立的链路分开验证能快速定位问题出在哪一侧。注意GitHub Token 建议用 fine-grained token只勾选public_repo读取权限别用全权限的 classic token。Token 存在 chrome.storage.local 里不会上传到任何服务器。6. 本篇常见错排查报错一Uncaught (in promise) TypeError: Failed to fetch八成是 host_permissions 没写全。检查 manifest.json 里有没有https://api.github.com/*改完记得在扩展管理页点「重新加载」光刷新页面不生效。报错二Service worker registration failed通常是 background.js 里用了import但 manifest 没设type: module。补上这个字段或者把 import 改成动态import()。报错三消息发送后 sendResponse 没回调chrome.runtime.onMessage里如果用了异步必须return true否则通道会提前关闭。上面 background.js 里那行注释就是提醒这个。报错四GitHub API 返回 401Token 无效或过期。注意请求头用的是Bearer而不是老的token前缀两者 GitHub 都支持但混用容易出错。重新生成一个 token 再试。报错五面板注入了但样式错乱GitHub 页面本身有全局 CSS可能覆盖你的类名。给所有选择器加#gsm-panel前缀提升优先级或者用 Shadow DOM 隔离。实测加前缀最快。报错六拉取只返回 30 条GitHub 默认 per_page 是 30要在 URL 里显式传per_page100超过 100 需要翻页。上面 github.js 里已经带了参数检查有没有漏。排查顺序建议从「扩展是否重新加载」开始再到「权限是否声明」最后才怀疑代码逻辑。大部分问题都出在前两步。7. 下一步把统一 Key 用起来骨架跑通之后扩展的下一步是加标签分组、本地搜索和 Gist 同步。而智能分类这类功能就可以走已经配好的 TaoToken 通道——比如把 Star 项目的描述批量丢给模型让它自动建议标签。这时候统一 Key 的价值就体现出来了扩展运行时和 Claude Code 编码工具共用一套配置不用维护两份。如果你还在搭环境阶段先去把 Key 建好https://taotoken.net/api-keys?utm_sourcetaotoken_aicg_blog_endutm_contentapi-keysutm_campaignrewrite接入细节和参数说明看文档https://taotoken.net/doc?utm_sourcetaotoken_aicg_blog_endutm_contentdocutm_campaignrewrite想先在网页里试一下模型对话效果可以直接开对话页https://taotoken.net/chat?utm_sourcetaotoken_aicg_blog_endutm_contentmodel-chatutm_campaignrewrite长期用 Claude Code 做这类扩展开发Coding Plan 会更省心https://taotoken.net/coding-plan?utm_sourcetaotoken_aicg_blog_endutm_contentcoding-planutm_campaignrewrite我自己的习惯是骨架阶段用 Claude Code 生成目录和 manifest报错直接贴给它改功能阶段再手动调 UI 细节。这样分工下来一个可用的扩展雏形基本一个下午能跑起来。
02
RELATED NEWS

相关资讯

更多网站建设与数字化升级内容

03
WHY YAOTU

想打造同款高转化官网?

懂行业、懂生意,从建站到增长一站式陪跑

◈

场景化定制

不做模板站,围绕你的业务场景量身设计,小众不撞款。

◐

营销型架构

以转化目标组织内容与路径,让官网真正带来询盘。

▲

全周期服务

设计、开发、运营、运维一体,上线只是开始。

免费获取你的建站方案

留下需求,专属顾问 24 小时内为你输出方案建议。