← 返回列表
未验证
一个原生 DeepSeek Harness 插件,让智能体能够访问你的…
尚未跑自动兼容性验证,可查看页面内的依赖与入口分析。 · 最近上游提交 2026/8/25 · 已提供中文文档
综合分
27.4
GitHub 分
27.4
用户评分
—
★ Stars
0
周下载量
—
安装插件(需先安装 dsh CLI 引擎:npm install -g @deepseek-ai/dsh)
dsh plugin --profile web add takasurazeem/gmail-dsh该插件未发布到 npm,走 GitHub 源安装(pnpm 若拦截 prepare 脚本,按其提示在 pnpm-workspace.yaml 的 allowBuilds 中放行后重跑)
数据截至 2026/9/19(元数据每日更新 · 实装验证按队列轮转,单条结论的验证时间见上方)
依赖的 DSH / Cordis 模块
@deepseek-ai/cordis@deepseek-ai/dsh-credentials@deepseek-ai/dsh-tools用户评分
还没有人投票,来当第一个
订阅周报,不错过优质插件更新
每周一封 · 高评分插件 + 新用户活动
README
gmail-dsh
一个原生 DeepSeek Harness 插件,让智能体能够访问你的 Gmail:搜索和阅读邮箱、发送邮件(包括感知会话的回复),以及管理标签——具备基于浏览器的 Google OAuth 流程、DSH 凭据存储中的按账户授权,以及每次变更操作前的审批提示。
MIT 许可。姊妹插件:websearch-dsh。
没有 MCP 服务器,没有第三方运行时依赖:它直接注册到 harness 的工具运行时、凭据存储、命令系统和系统提示上。
你能获得什么
| 接口 | 功能 |
| --- | --- |
| gmail_search | Gmail 查询搜索(is:unread、from:x、newer_than:1w……),最新优先,分页 |
| gmail_read | 完整邮件:纯文本(可选 HTML)、标头、附件、标签、会话 |
| gmail_send | 发送纯文本邮件;replyTo 将回复归入现有邮件会话下——先询问用户 |
| gmail_labels | 在单封邮件或整个会话上添加/移除标签——先询问用户 |
| gmail_status | 授权状态:账户、默认账户、作用域、OAuth 客户端状态 |
| /gmail 命令 | /gmail status、/gmail auth [email]、/gmail unauth [email] |
| 系统提示部分 | 一段话告知模型 Gmail 已连接(在账户授权前零 token 消耗) |
审批语义:读取从不提示。gmail_send 和 gmail_labels 从工具预执行钩子返回 ask 决定,harness 审批服务将其转化为用户提示(收件人 + 主题 / 标签变更 + 目标)。如果未挂载审批服务,ask 会降级为拒绝,因此该插件在该部署中为只读——没有能够表示同意的用户时,它绝不会发送。
工作原理
/gmail auth
└─ PKCE (S256) + state → 浏览器 → accounts.google.com
└─ 回调到 http://127.0.0.1:/gmail/callback
└─ code → https://oauth2.googleapis.com/token (+client secret)
└─ refresh_token ── 存储 ──▶ 凭据存储
~/.dsh/.credentials.yaml
记录:gmail-dsh/
└─ 访问令牌:仅进程内缓存,401 时刷新
- OAuth 使用 Google 的桌面(已安装应用)客户端类型,它接受任何 http://127.0.0.1: 重定向——插件在一次授权期间在随机空闲端口上打开一个回环服务器。只有短时有效的授权码经过该服务器;之后立即关闭。access_type=offline&prompt=consent 参数使 Google 返回刷新令牌。
- 机密仅存在于 DSH 凭据存储中:OAuth 客户端 id/secret 以引用形式存在(GMAIL_OAUTH_CLIENT_ID / GMAIL_OAUTH_CLIENT_SECRET),每个账户的 refresh token 则作为授权记录存在于插件自己的作用域下(gmail-dsh/;规范邮箱位于记录负载中)。modifyRecord 是唯一的写入路径,它会在多个进程间串行化 refresh-token 轮换。
- 多账户:想授权多少个就授权多少个;工具接受一个可选的 account 参数,默认使用单个账户(当有多个账户时则默认为 defaultAccount)。
设置
1. Google Cloud 项目
1. 在 Google Cloud Console 中:创建一个(或选择一个)项目。
2. APIs & Services → Enable APIs and Services → 启用 Gmail API。
3. OAuth consent screen:选择 External(如果你有 Google Workspace,则选择 Internal),填写应用名称,并在该屏幕处于 Testing 状态时将你的账户添加到测试用户列表中。
4. Credentials → Create Credentials → OAuth client ID → Desktop application。下载 JSON;你需要其中的 client_id 和 client_secret。
2. 存储客户端凭据
可以存储在凭据存储中(推荐——Web GUI 的凭据界面会写入这些内容),也可以手动写入 ~/.dsh/.credentials.yaml:
version: 1
refs:
GMAIL_OAUTH_CLIENT_ID:
GMAIL_OAUTH_CLIENT_SECRET:
或者作为同名进程环境变量。(直接使用 clientId/clientSecret 配置值也可以,但不推荐;当两者同时存在时,引用优先。)
3. 安装到 profile 中
在此目录下(例如在 git clone https://github.com/takasurazeem/gmail-dsh 之后):
dsh plugin --profile web add file:$PWD
并将该 bundle 添加到位于 ~/.dsh/profiles/web 的 profile 的 package.json 中:
"dsh": {
"profile": {
"bundles": [
"@deepseek-ai/dsh-base",
"@deepseek-ai/dsh-web-app",
"yolo-mode",
"gmail-dsh"
]
}
}
重启 dsh web(或者在开发监听器运行时让 profile 的 HMR 自动加载它)。该插件会贡献自己的 cordis.patch.yml 行,因此 profile 中不需要编辑其他任何内容。
关于从开发检出目录进行 file: 安装的说明: Node 会从包的真实路径解析包的 import "@deepseek-ai/…" 说明符,因此该检出目录需要一个可供向上查找的 node_modules。此仓库附带了一个指向 dsh 安装自身包集合的 node_modules/@deepseek-ai 符号链接(它被 git 忽略;如果缺失,可用 mkdir -p node_modules && ln -s "$(npm root -g)/@deepseek-ai/dsh/node_modules/@deepseek-ai" node_modules/@deepseek-ai 重新创建)。安装到 profile 自身 node_modules 中的包(通常情况)永远不需要这样做。
稍后更新插件: pnpm 在安装时会将 file: 包复制到配置文件的 node_modules 中,因此安装后的副本是一个冻结的快照——之后对检出目录的编辑不会影响到正在运行的应用(而且重新运行相同的 pnpm add 可能也不会刷新它)。要进行实时开发,请将该副本替换为指向检出目录的符号链接,并重启 dsh web:
cd ~/.dsh/profiles/web
rm -rf node_modules/gmail-dsh
ln -s /path/to/this/checkout node_modules/gmail-dsh
此后每次重启都会运行磁盘上检出目录的当前状态。
4. 授权
在会话中,运行:
/gmail auth
你的浏览器会打开 Google 的同意屏幕(或者该命令会打印 URL)。在你批准后,一次性回环服务器会接收代码、交换代码、通过 OIDC userinfo 端点验证你的电子邮件,并存储刷新令牌。/gmail status 可确认。要移除账户:/gmail unauth [email](如果你想收回授权,也请在 Google 侧撤销:)。
配置
gmail 行的行配置(完全行替换语义——补丁会重述每个字段):
| 字段 | 默认值 | 含义 |
| --- | --- | --- |
| clientIdEnv | GMAIL_OAUTH_CLIENT_ID | 客户端 id 的凭据存储引用 / 环境变量名 |
| clientSecretEnv | GMAIL_OAUTH_CLIENT_SECRET | 客户端密钥的凭据存储引用 / 环境变量名 |
| clientId | '' | 未设置引用时的字面量回退值(不推荐) |
| clientSecret | '' | 字面量回退值(不推荐) |
| scopes | [openid, email, gmail.modify] | OAuth 作用域;https://www.googleapis.com/auth/gmail.modify 涵盖读取 + 发送 + 标签。openid/email 作用域是必需的——没有它们令牌交换也能工作,但 Google 的 userinfo 端点(读取账户电子邮件的地方)会以 401 "Invalid Credentials" 拒绝缺少 openid 的令牌。更窄的作用域(gmail.readonly)可用于读取工具;发送需要 modify 作用域。事实来源是 src/config.js 中的 DEFAULT_SCOPES——该 bundle 自身的补丁层有意省略此键(显式补丁值会覆盖默认值,而一个过时的重述列表曾在每次重启时悄悄使 openid 修复失效);如果你需要,请在你自己的配置文件补丁层中覆盖它 |
| callbackHost | 127.0.0.1 | 回环回调主机(桌面客户端接受任何本地端口) |
| callbackPath | /gmail/callback | 回调路径 |
| defaultAccount | '' | 当工具省略 account 时使用的账户(当恰好授权一个账户时自动解析) |
| authTimeoutMs | 300000 | /gmail auth 等待浏览器回调的时长 |
| requireApproval.send | true | 在 gmail_send 之前询问用户 |
| requireApproval.labels | true | 在 gmail_labels 之前询问用户 |
| context.enabled | true | 授权后发出模型上下文部分 |
| context.order | 117 | 系统提示中的部分顺序(避开内置 bundle) |
安全说明
- 回调服务器仅限回环地址,且仅在一次授权期间存活;令牌绝不会出现在 URL、日志或配置中。
- 持久化密钥是刷新令牌,存储在 ~/.dsh/.credentials.yaml 中的 gmail-dsh/ 记录作用域下(凭据存储文件的常规保护措施适用)。
- OAuth 作用域就是你的边界:gmail.modify 允许智能体以你的身份发送邮件并在标签之间移动邮件——它无法以超过 API 配额允许的速度批量导出邮箱,而且每次发送仍需要你的明确批准。
- 如果你的部署没有审批服务,变更类工具会失败关闭(被拒绝),而不是静默运行。
故障排除
| 症状 | 修复 |
| --- | --- |
| /gmail auth 提示客户端未配置 | 设置 GMAIL_OAUTH_CLIENT_ID / GMAIL_OAUTH_CLIENT_SECRET(凭据存储或环境变量),然后再次检查 /gmail status |
| 成功同意后出现“no refresh token” | 你的浏览器已为此应用持有非交互式令牌:在 撤销它(或在隐私窗口中授权)并重试 |
| 稍后刷新时出现 invalid_grant | 刷新令牌已被撤销或同意已变更:执行 /gmail unauth 然后再次 /gmail auth |
| Gmail API 返回 403 … quota | 项目级 API 配额;参见 Gmail API quotas |
| 工具提示“Multiple Gmail accounts are authorized” | 向工具传入 account 或设置 defaultAccount |
| 检出代码的修改未生效(例如重启后旧错误仍然存在) | 配置文件的 node_modules/gmail-dsh 是安装时的快照副本——将其替换为指向检出代码的符号链接(Setup §3 注释)并重启 |
| /gmail auth 同意通过,但出现 userinfo request failed (401) "Invalid Credentials" | 正在运行的代码请求的作用域不含 openid;Google 签发的令牌无法调用 userinfo 端点。确保检出代码的 src/config.js 作用域(openid、email、gmail.modify)就是应用实际加载的内容——过期的快照副本会正好以这种方式失败 |
| 读取工具失败并提示 credential key segment "" must match ... | 插件构建早于 0.1.2:工具解析了账户,但从未将其转发给令牌获取流程,因此凭据键为空。更新检出代码并重启 |
测试
node test.mjs
纯 Node,无框架,无网络(OAuth 令牌端点被桩替换;回环回调测试使用真实的临时端口)。测试套件会适应其环境:从裸检出代码运行时,它运行纯逻辑测试并跳过依赖 dsh 运行时的测试;从能够解析 @deepseek-ai/ 包的目录(配置文件的 node_modules,或本仓库符号链接进来的 node_modules 农场)运行时,它还会针对真实的 defineTool 验证全部五个工具定义,并针对伪造对象执行它们。
要针对真实配置文件布局进行完整组合检查:
DSH_HOME=$PWD/.dsh-home dsh --profile gmail-dev --dump-config # 组合后的树
DSH_HOME=$PWD/.dsh-home dsh --profile gmail-dev "…" # 无头启动(在 .dsh-home/ 下创建一个临时 profile)
开发说明
- 零运行时依赖。 仅对 harness 包(@deepseek-ai/cordis、dsh-credentials、dsh-tools)有 peerDependencies,因此对该包执行 pnpm add 永远不会拉取任何内容;导入点是惰性的,并且在 dsh 运行时之外会以可操作的错误降级。
- 配置契约。 cordis 运行时同步调用 Config['~standard'].validate(raw)(它会拒绝 promise),并期望得到 {value} 或 {issues};加载器另外读取 Config.simplify 用于 HMR 回写。两者都委托给 normalizeConfig。
- 工具 schema DSL。 值 schema DSL 按属性标记必填字段(在属性上设置 required: true)——没有根级别的 required 数组。运行时会根据编译后的输出 schema 校验每个工具结果,并在违反时抛出 ToolOutputError,因此 required 标记必须与 execute 实际返回的内容一致。
- 凭据键语法。 credentialKey 各段匹配 ^[a-z][a-z0-9-]$,因此电子邮件地址会被 slug 化(me@gmail.com → gmail-dsh/me-gmail-com);规范电子邮件保存在记录负载中,listAccounts 依据它进行匹配。
- 无自定义会话事件(避免可忽略陷阱),并且命令服务是机会性地访问的,因此没有它的组合永远不会让插件处于挂起状态。
卸载
dsh plugin --profile web remove gmail-dsh
从 profile 的 dsh.profile.bundles 中移除 "gmail-dsh",重启,并对每个账户执行 /gmail unauth(或从 ~/.dsh/.credentials.yaml 中删除 gmail-dsh/… 记录)。
许可证
MIT — 参见 LICENSE。同作者(takasurazeem)的其他插件
扫码进群