# dsh-github-upload [English](README.md) | 中文 给 DeepSeek Harness 用的**动态 Cordis 插件**:在界面右下角加一个按钮,把本地项目一键推送到 GitHub —— 绑定账号、选/建仓库、挑要上传的文件、改仓库公开或私密,全程点鼠标,**不消耗模型 Token**。 界面中英双语(面板右上角可切换)。[English README](README.md) - 插件 ID:`ghpush-1` - 前端资源目录:`src/`(宿主运行时按需读取) - 不需要本机装 `git`,也不会在你的项目里生成 `.git` 目录 --- ## 1. 功能 | 面板标签 | 能做什么 | | --- | --- | | **账号** | 粘贴 GitHub Personal Access Token → 校验并绑定;显示令牌类型 / 权限 / 过期时间,并在令牌看不到仓库时给出可执行的提示;可选「记住令牌」;一键环境自检 | | **仓库** | 列出账号可见仓库(自有 + 协作 + 组织成员 + 所属组织 + 公开兜底),搜索、选择;新建仓库并选择公开/私有;**新建 / 改名 / 改可见性后列表自动刷新**;列表不可用时可直接指定 `owner/repo` | | **上传** | **项目目录由聊天本身识别** —— 打开这一页时,这次对话正在做的文件夹已经填好了(不需要先去选文件夹)→ 扫描(内置忽略规则 + `.gitignore`)→ **一键「未上传的改动」勾选所有与远程分支不一致的文件**(跨多轮对话累计,按内容比对;本会话改动的文件在树上还带标记)→ 提交信息 / 目标分支 → 上传并显示进度与日志。「选择文件夹」(内置浏览器 + 系统对话框两个入口)与手填路径仍然可用。 | > **「勾选」到底是什么语义?** 勾选的文件在 GitHub 上**新增或覆盖**;未勾选的文件**在远程保持原样**。只有打开「完全同步」(删除远程未选中的文件)才会真的删远程文件。所以「就是想推整个项目」时点**全选**才是对的 —— 按聊天勾选适合做一次聚焦的提交,或者省掉大仓库里没动过的文件。 | **仓库信息** | 改名、描述、主页、话题标签、公开↔私密切换、Issues/Wiki 开关、归档、删除仓库 | > **面板是浮层,不是贴边抽屉。** 桌面端的窗口关闭 / 退出键就在窗口右上角,所以面板四边都留空隙 > (顶部默认 52px,见 `src/client.css` 里的 `--ghu-top`):关闭键在面板**右下角**,头部最左侧是「收起」键, > 点面板以外或按 Esc 也会收起。窗口右上角永远不会被面板覆盖。 > > **右下角入口按钮是一枚 46×46 的正圆,表面走 DSH 主题、里面是 GitHub logo(30px)+ 一枚状态点。** > 没有文字(说明只在悬停提示 / 无障碍名里)。可以拖到界面最边上(只允许停在下半屏,避开标题栏), > 并且**尺寸永远不变**:hover 不展开、面板打开也不展开。 > 这么设计是因为:按钮能贴到边上,一旦 hover 会变宽,贴边时就会「超出视口 → 被夹回 → 指针脱离 → 收起」 > 来回抖动,既拖不动也点不准。 > > 注意它**不是** GitHub 官网那种深色丸子:深色是 GitHub 的品牌语言,贴在 DSH 的浅色界面上会像一张外来贴纸。 > 所以表面用 `--dsw-alias-bg-layer-2` + elevation 阴影 + 1px 细描边,图标用 `--dsw-alias-label-primary`, > hover 用 `--dsw-alias-interactive-bg-hover-solid` —— 它是「DSH 里的一枚浮层按钮」,恰好印着 GitHub 的标记。 > > ⚠️ **按钮和状态点都必须显式写 `corner-shape:round`。** DSH 主题里有一条全局规则 > (`dsh-client-ui-theme` → `corner-shape.css`)把所有元素的圆角改成「超椭圆(squircle)」: > 对卡片是好设计,但会把 `border-radius:50%` 的正圆压成**圆角方块**。 > 只有支持该属性的浏览器(Chrome/Edge 139+)才会这样,删掉这两行就会「看起来不是圆的」。 --- ## 2. 目录结构 ``` dsh-github-upload/ ├─ index.js 包入口:再导出 src/host.js ├─ client.js 自动生成的 ModuleLoader 工件(UI + CSS),注册到 shell.overlay ├─ src/ │ ├─ host.js 宿主半边:API 路由、GitHub 调用、文件扫描、上传任务(真正的 ES 模块) │ ├─ client.js 浏览器端 UI(右下角按钮 + 浮层面板),含双语文案表 │ └─ client.css 面板样式(全部走 DSH 主题变量,自动适配明暗色;`--ghu-top` 控制顶部让位高度) ├─ cordis.patch.yml bundle 补丁:插入插件行 ├─ locale/ 插件管理器用的展示信息(中英各一份) ├─ icon.svg bundle 图标 ├─ build/ │ └─ bundle.mjs 把 src/client.js + src/client.css 拼成 client.js ├─ README.md English README ├─ README.zh.md 本文件(中文) ├─ README.i18n.yaml 双语配对一致性记录(blob 哈希) ├─ CHANGELOG.md 更新记录(中文) └─ package.json bundle 清单(dsh.bundle.patch + dsh.client) ``` --- ## 3. 双语实现 两份文案表都是最简单的定位表,每条 `[中文, English]`: | 位置 | 在哪 | 覆盖范围 | | --- | --- | --- | | 浏览器 | `src/client.js` → `var M = { ... }` | 面板里所有标签、按钮、提示、toast | | 宿主 | `src/host.js` → `const M = { ... }` | 报错、扫描忽略原因、上传任务日志、仓库来源统计、令牌权限提示 | `{1}` / `{2}` 是位置占位符(用 `split`/`join` 替换,不走正则,因此没有转义坑)。 前端**每次请求都带 `lang`**(`zh` / `en`),宿主按它回话。切换开关在面板头部,选择存在 `localStorage`(`dsh.ghu.lang`),首次按浏览器语言猜。 GitHub 自己的报错原样透传 —— 它们本来就是英文。 --- ## 4. 开发流程 ### 安装 ```bash npm run build # 从 src/ 重新生成 client.js(改过 src/ 就必须跑一次) ``` 然后把**本目录的绝对路径**作为 bundle 安装进当前 profile(对所有会话生效,且重启后仍在): ``` plugin_manager action: install_bundle target: <本目录的绝对路径> ``` 判断是否生效要看返回结果里的 `application` 和 `warnings` 字段,而不是服务端日志。 ### 改动生效时机 | 改了什么 | 什么时候生效 | | --- | --- | | `src/client.js`、`src/client.css` | `npm run build`,然后**重启 DSH**(见下面的坑;只刷新页面不一定够) | | `src/host.js`、`index.js`、`cordis.patch.yml`、`package.json` | 重新 `install_bundle`,再重启 Harness 以装载新的模块代 | > **坑:重建客户端后只刷新页面,可能仍然跑旧界面。** > DSH 给客户端模块发的响应头是 `cache-control: public, max-age=31536000, immutable`, > 模块 URL 形如 `/plugins/??<包名>/client.js&rev=<内容哈希>`,而这个 `rev` **只有 HMR 重算时才会变** > (`dsh-client-modules` 里的 `rebuilt(id)`)。HMR 没重算 → URL 不变 → 浏览器直接用那份 > 「immutable」的旧缓存,刷新多少次都是旧包。 > **所以要重启 DSH**(服务端重新组合,交出新的 `rev`)。 > 想确认页面到底跑的是哪一版:打开面板 →「账号」→「本机环境」→「界面版本」,形如 `1.0.1+252bba5a`, > 由 `build/bundle.mjs` 按素材指纹生成,构建时会打印出来。 > > **排查插件没挂上**:设 `DSH_GHU_DIAG=1` 再启动 DSH,宿主会在模块被加载时以及 `apply()` 的每一步 > 各写一行记录到 `DSH_GHU_DIAG_FILE`(未指定则用系统临时目录下的 `dsh-github-upload-diag.jsonl`), > 并同时打印到控制台。默认关闭,关闭时不产生任何文件。它能一刀切开「新代码没被加载」和 > 「加载了但某一步静默失败」这两种情况。 profile 是把本包装成**软链**接进 `node_modules` 的(`link:/path/to/dsh-github-upload`,在 Windows 上落成 `node_modules/@local/` 下的 junction),所以磁盘上的文件就是真正在跑的文件,改完不用重装。 > **注意**:profile 里的依赖也可能是 GitHub 写法(`github:/`)。那种装法是**快照副本**而不是软链,本地改了也不生效 —— 「明明修好了却还是老样子」通常就是这么来的(面板挡住窗口退出键那次就是)。用 `plugin_manager install_bundle <本目录绝对路径>` 可以把它换回软链形式。 ### 为什么 UI 变成了生成产物 早期版本用 HTTP 路由下发界面、再 tap `index.html` 注入 `