dsh-github-token-injector
DSH Web client plugin: auto-inject GitHub Authorization header on api.github.com requests to defeat shared-IP rate limits.
- Stars
- 1
- Language
- JavaScript
- Created
- Aug 24, 2026
- Updated
- Aug 25, 2026
Introduction
dsh-github-token-injector
DeepSeek Harness (DSH) Web 客户端插件:自动给所有发往 api.github.com 的浏览器请求
注入 Authorization: Bearer <token> 头,解决共享代理 IP 触发的 GitHub API 限流问题
(匿名访问每小时仅 60 次,配 PAT 后提升至 5000 次/小时)。
免去手动给浏览器扩展或代理工具配置 header。Token 仅保存在浏览器 localStorage,
不上传任何服务端。

为什么需要
- DSH Web 内的皮肤管理器、插件市场等模块会从
api.github.com拉元数据判断更新 - 共享出口 IP 的代理环境容易被 GitHub 限流(HTTP 403),UI 一直显示「无法判断更新」
- 配一个 GitHub PAT(Personal Access Token)可立刻绕过这个限制
安装
推荐:从 npm 安装
npx @deepseek-ai/dsh plugin --profile web add dsh-github-token-injector
web 换成你的 profile 名。装完 重启 DSH。
⚠️ 别用
npx dsh plugin——npm 上dsh这个名字早在 2016 年就被一个不相关的 JS shell 包占了(dsh@1.0.1,作者infusion),它没暴露 CLI bin,会报could not determine executable to run。DSH 的 CLI 在 scoped 包@deepseek-ai/dsh下,必须用完整名。
备选:从 GitHub 装
# 锁定版本
npx @deepseek-ai/dsh plugin --profile web add github:pan17/dsh-github-token-injector#v0.1.0
# 或默认分支最新
npx @deepseek-ai/dsh plugin --profile web add github:pan17/dsh-github-token-injector
本地 link 安装(开发场景)
把插件目录用 link: 装到 web profile:
# 1. 确认插件目录在
# <your-repo-dir>/dsh-github-token-injector
# 2. 编辑 web profile 的 package.json:
# a) dependencies 加:
# "dsh-github-token-injector": "link:<your-repo-dir>/dsh-github-token-injector"
# b) dsh.profile.bundles 在皮肤管理器之前插入:
# "dsh-github-token-injector"
# 关键:bundles 顺序决定 cordis loader 创建 entry 的先后,
# 把 token injector 放在皮肤管理器之前能保证 window.fetch 在
# skin-manager 的 githubJson() 调用前已经被 patch。
# 3. 安装并重启
cd $DSH_HOME/profiles/web
pnpm install
npx @deepseek-ai/dsh web --no-open
### 构建脚本授权
如果 pnpm 提示不允许跑构建脚本(`ERR_PNPM_GIT_DEP_PREPARE_NOT_ALLOWED`),在该 profile 的 `pnpm-workspace.yaml` 加上:
```yaml
allowBuilds:
dsh-github-token-injector: true
配置 Token
⚠️ 每次修改配置后请重启 DSH 并刷新浏览器 — DSH 主进程的 token 缓存不会热更新,必须重启 host 进程才能生效;浏览器刷新一次让客户端 factory 重新把 localStorage 里的 token 推到 host 进程(DSH 重启会清空 host 缓存)。
方式一:Settings UI(推荐)
- 打开 Web UI(默认
http://127.0.0.1:3080) - 进入 设置 → GitHub Token 卡片
- 粘入 PAT,点击「保存」
- 点「立即测试」主动验证(状态点变绿 = 有效)
方式二:浏览器 Console
// 设置
localStorage.setItem('DSH_GITHUB_TOKEN', '<your-pat>')
// 读当前 token
window.__githubTokenInjector.getToken()
// 看状态
window.__githubTokenInjector.getStatus()
// → { state: "ok" | "invalid" | "forbidden" | "rate-limited" | "no-token" | "unknown", ... }
// 清空
window.__githubTokenInjector.clearToken()
// 主动触发鉴权探针
window.__githubTokenInjector.forcePrecheck()
方式三:环境变量注入(高级)
任何 DSH 客户端插件在启动时给 window.__DSH_GITHUB_TOKEN__ = '<your-pat>' 即可被读取
(适用于多 profile 共用同一 token 的场景)。
方式四:host 端环境变量(无人值守)
DSH 主进程(Node.js)启动前设:
# Linux / macOS
export DSH_GITHUB_TOKEN='ghp_xxx'
npx @deepseek-ai/dsh web --no-open
# PowerShell
$env:DSH_GITHUB_TOKEN = 'ghp_xxx'
npx @deepseek-ai/dsh web --no-open
也接受 GH_TOKEN 别名。env 优先级高于 UI 配的 token(运维设定优先)。
拿一个 PAT
GitHub 两种 PAT 都接受,patch 只看 Authorization: Bearer <token> 形式,跟前缀无关:
Classic PAT(ghp_ 开头,40 字符)
- 打开 https://github.com/settings/tokens
- Generate new token → Generate new token (classic)
- 选 expiration(90 天或不过期)
- 不需要勾选任何 scope——纯公共数据请求
- 复制
ghp_xxx...(共 40 字符)
Fine-grained PAT(github_pat_ 开头,约 90+ 字符)—新版 GitHub 默认推荐这种
- 打开 https://github.com/settings/personal-access-tokens
- Generate new token → Fine-grained, personal access token
- Token name 随便填;Expiration 选 90 天或不过期
- Resource owner:留默认(你自己)即可——这个 PAT 只用来读你自己的皮肤 / 插件仓库的公开元数据
- Permissions → Repository access:Public Repositories (read-only) 就行。不要勾 "All repositories" 或任何 private 权限——用不到
- 生成后复制
github_pat_11XXX_xxx...(约 90+ 字符)
哪种都行。classic 创建快、scope 全空;fine-grained 权限最小化、token 更长更显眼、GitHub 现在主推这种。两者都不需要任何勾选就能解 GitHub API 60次/小时的匿名限流。
工作原理
- 早期 patch:插件 factory 在 DSH 客户端模块表中第一个物化(依赖 bundles 顺序),立即用
Symbol.for("dsh-github-token-injector.patched")标记位对window.fetch与XMLHttpRequest进行 monkey patch - 目标过滤:通过
URL解析只对api.github.com与raw.githubusercontent.com起作用,其他域名的 fetch 完全不改动 - Header 注入:每次目标请求把 token 写进
Authorization: Bearer xxx,若调用方已自带Authorization头则尊重调用方 - 响应监控:在
fetch().then()与 XHRreadystatechange=4里检查 status,401 →invalid,403 +X-RateLimit-Remaining === 0→rate-limited - 状态广播:通过
dispatchEvent(new CustomEvent("dsh-github-token-injector:status", { detail }))让 UI 与其他插件订阅 - HMR 安全:cordis
ctx.effect()注册副作用,dispose 时还原原始window.fetch引用,不污染全局 - Host 端 patch:
src/index.ts在 DSH 主进程(Node.js)层面同时 patchglobalThis.fetch,对发往api.github.com/raw.githubusercontent.com的服务端请求(如 skin-manager 的/api/dsh/skins、插件市场的 update 检查)注入Authorization,解决共享代理 IP 上 server-side fetches 同样被限流的问题 - Token 同步:浏览器侧的
setToken/clearToken通过POST /dsh-github-token-injector/api/token把 token 推到 host 进程内的内存缓存;DSH 重启时 host 清空,浏览器侧的localStorage有现成 token 时会在 plugin 启动时主动同步一次
接口
window.__githubTokenInjector
| 方法 | 用途 |
|---|---|
getToken() | 返回当前生效 token(trim 后)或 null |
setToken(t) | 写入 localStorage.DSH_GITHUB_TOKEN,null/空串 = 清除 |
getStatus() | 返回 { state, checkedAt, message } |
clearToken() | 清掉 token + 重置状态 |
forcePrecheck() | 主动发起 /octocat 鉴权探针,返回 Promise<Response | null> |
cordis service dsh-github-token-injector
其他插件 inject(['dsh-github-token-injector']) 后可拿到:
interface TokenProvider {
getToken(): string | null
getStatus(): { state: TokenStatus; checkedAt: number; message?: string }
setToken(t: string | null): void
}
CustomEvent dsh-github-token-injector:status
window.addEventListener('dsh-github-token-injector:status', (ev) => {
console.log(ev.detail) // { state, checkedAt, message }
})
状态机
| 状态 | 触发条件 | UI 表现 |
|---|---|---|
ok | 任何 2xx/3xx 响应 | 🟢 绿点 "有效" |
invalid | 401 响应 | 🔴 红点 "已失效" |
forbidden | 403 响应(非限流) | 🟡 黄点 "无权限" |
rate-limited | 403 + X-RateLimit-Remaining: 0 | 🟡 黄点 "限流" |
no-token | 未配置 token | ⚪ 灰点 "未配置" |
unknown | 网络错误 / 启动后未发过请求 | ⚪ 灰点 "未知" |
安全与隐私
- Token 仅存在浏览器
localStorage,不写入 DSH 服务端文件、不上传网络 - Patch 只对
api.github.com/raw.githubusercontent.com域名生效,其他请求零改动 - 卸载插件 / 清浏览器数据会一并删除 token
发布
参见 PUBLISH.md:tag push 触发 GitHub Actions,自动 pack → GitHub Release → 等 CI green → publish 到 npm。
开发
npm install
npm run build # tsc → dist/index.js + copy src/client.js → dist/client.js
npm test # vitest
HMR 调试:在 web profile 跑 pnpm run dev:web 同时开新终端跑本插件的 npm run dev,
修改 src/client.js 后浏览器自动 reload。
本地未推送时也可以按路径装:
npx @deepseek-ai/dsh plugin --profile web add /path/to/dsh-github-token-injector