# 插件安装规范(Installation Spec) > 本文件定义 `dsh-ezcommit-plugin` 的安装、更新、移除与版本发布规范。目标:任何使用者都能用 DSH 官方 CLI 以标准方式完成安装与升级。 ## 1. 背景:DSH 的插件模型与本包定位 DSH(DeepSeek Harness)当前(`@deepseek-ai/dsh@0.1.1-rc.2`)的 profile 由「bundle 补丁层」组装(`cordis.patch.yml` 列表,由 Loader 加载)。一个 bundle 包可以是**双面包**:包内 `dsh.client` 声明 + `exports "./client"` 让 `dsh-client-modules` 把客户端 bundle 打进 web 启动图,浏览器按 `window.__ModuleLoader__` 工厂格式加载为客户端 Cordis 插件——`dsh-skin-market`、maid-atelier 等第三方皮肤包即此机制。 **本插件是静态双面 bundle**: - **Host 半**(`main` / `exports "."` → `src/index.js`):在本进程加载,向 `webServer` 注册 `/ezcommit/api` 前缀路由(git 采集、模型裁决、分批提交),启动时打印安装公告与自检。 - **Client 半**(`exports "./client"` → `src/client.js`):浏览器模块工厂,导出 `apply(ctx)` 注册会话标题栏按钮与确认弹窗,经同源 HTTP 调用 Host 半。 安装并**重启 profile** 后即生效:会话标题栏自动出现 `[分支名] [一键 Commit]`。**无需 cordis preset,无需 `cordis_define` / `cordis_run`。** ## 2. 包结构规范(DSH bundle 契约) `dsh plugin add` 的实现是「pnpm 转发器」:在 profile 目录执行 `pnpm add `,然后扫描依赖清单——**依赖解析到的包若在 `package.json` 中声明了 `dsh.bundle.patch`,就加入 profile 的 bundle 层列表**;否则按普通依赖安装并告警。本包据此声明: ```jsonc // package.json(节选) { "name": "dsh-ezcommit-plugin", "main": "./src/index.js", // Host 半入口:默认导出 Cordis Plugin "exports": { ".": "./src/index.js", "./client": "./src/client.js", // Client 半:浏览器模块工厂(dsh.client 消费) "./package.json": "./package.json" }, "dsh": { "engines": { "dsh": ">=0.1.1-rc.1" }, "bundle": { "patch": "./cordis.patch.yml" }, // 关键字段:bundle 层补丁 "client": { "inject": [], "platform": "web" } // 关键字段:静态 Client 半声明 } } ``` ```yaml # cordis.patch.yml(本包根目录) - insert: - id: ezcommit name: 'dsh-ezcommit-plugin' # 模块名:由 profile 目录的 node_modules 解析 ``` 契约要点(对照官方 in-box bundle 与 `dsh-skin-market` / maid-atelier 实测): - `dsh.bundle.patch` 指向一个 **loader patch 列表**(YAML 数组):每项 `{id, name, config?}` 插入/覆盖 composition 行;`name` 是模块说明符,按「DSH 安装锚点 → profile 目录」两锚点解析; - 入口模块默认导出必须是 Cordis Plugin(`apply` 函数或对象带 `apply`); - `dsh.client`(`platform: "web"` + `inject` 数组)声明该包有静态客户端半;`exports["./client"]` 必须是客户端 bundle 路径(模块工厂格式,`id` = 包名); - `cordis.patch.yml` 与 `src/**` 必须进入 npm 包(`files` 字段显式包含),否则安装后 bundle 层解析失败; - bundle 行应保持**容错**:本包 Host 半对可选服务(`webServer` / `shell` / `llm` 等)做缺失检查,任何情况不拖垮 profile 启动。 ## 3. 安装 ### 3.1 从 npm registry(发布后推荐) ```bash dsh plugin --profile web add dsh-ezcommit-plugin ``` ### 3.2 从 git 仓库 ```bash dsh plugin --profile web add git+https://github.com/PenguinAndy/dsh-ezcommit-plugin.git ``` > 若包带 `prepare` 构建脚本,pnpm 默认会拦截并要求在 profile 目录的 `pnpm-workspace.yaml` 中允许;本包零依赖、无构建脚本,不会触发该提示。 ### 3.3 本地开发(file:/link: 安装当前 checkout) ```bash dsh plugin --profile web add file:/path/to/dsh-ezcommit-plugin # 或 link: 形式(改动即时可见) dsh plugin --profile web add link:/path/to/dsh-ezcommit-plugin ``` 相对路径(`file:.`、`link:../dsh-ezcommit-plugin`)会被 CLI 自动锚定到调用目录,与绝对路径等价。 ### 3.4 验证安装 ```bash # 安装后 profile 组合中应出现 ezcommit 行与本包 bundle 层: dsh --profile web --dump-config | grep -A2 ezcommit # profile 清单中应登记 bundle 与依赖: cat "$DSH_HOME/profiles/web/package.json" ``` **重启 profile**(`dsh web`)后: - 启动日志打印 `[dsh-ezcommit-plugin] v 已安装(静态双面包…)` 与「已挂载 /ezcommit/api/* 路由」; - 浏览器刷新后,web 会话标题栏出现 `[分支名] [一键 Commit]`(非 git 仓库或无改动时置灰); - 客户端 bundle 位于 `/plugins/dsh-ezcommit-plugin/client.js`。 ## 4. 更新与移除 ```bash dsh plugin --profile web update dsh-ezcommit-plugin # 升级到 latest dsh plugin --profile web remove dsh-ezcommit-plugin # 卸载(bundle 层自动移除) ``` 更新/移除后同样需要**重启 profile** 才在运行中的进程生效。 ## 5. 版本与发布 - 版本号遵循 [SemVer](https://semver.org/);`package.json.version` 是唯一版本源。 - 发布流程:推送 `v` 标签触发 GitHub Action [`.github/workflows/release.yml`](../.github/workflows/release.yml): 1. 断言标签与 `package.json.version` 一致; 2. `pnpm verify`(包契约 + HTTP 路由集成(真实 git)+ client 工厂冒烟); 3. `npm pack` 产出 tarball; 4. 创建 GitHub Release(自动生成 release notes)并附上 tarball; 5. 配置了 `NPM_TOKEN` secret 时,将同一 tarball 发布到 npm(`npm publish --access public`)。 - 本地发布命令:`npm version ` → `git push --tags`(或手动打 tag 后推送)。 ## 6. 疑难排查 | 现象 | 原因与处理 | |------|-----------| | 安装后界面没有按钮 | 先确认已**重启 profile**(运行中的进程不热加载 bundle);再看启动日志有无 `[dsh-ezcommit-plugin]` 公告与「已挂载 /ezcommit/api/* 路由」 | | 启动日志出现「路由挂载失败」 | profile 不是 web 型(无 `webServer` 服务)或端口路由冲突;确认 profile 组合里有 `webserver` 行,且无其它包占用 `/ezcommit/api` 前缀 | | 按钮出现但始终置灰 | 工作区不是 git 仓库或无改动(符合设计);把会话工作区切到有改动的 git 仓库 | | 点击「开始分析」报 `NO_MODEL` / `SERVICE_MISSING` | 会话尚未路由模型或 profile 缺 `llm`/`agents` 等服务;先在会话中正常发起一次模型对话再试 | | 浏览器控制台出现 client bundle 报错 | 确认 profile 已重启且客户端 bundle 可访问(`/plugins/dsh-ezcommit-plugin/client.js` 应返回 JS);必要时硬刷新页面 | | `dsh: cannot resolve profile bundle ...` | 包未装进 profile(安装被中断/未联网);重跑 `dsh plugin --profile add ` | | `warning: declares no dsh.bundle — installed as a plain dependency` | 装错了不带 `dsh.bundle.patch` 的同名包,或旧版本包;升级到声明 bundle 的版本 | | `pnpm blocks build scripts ... allowBuilds` | git 源安装触发 prepare 脚本拦截;按提示在 profile 目录 `pnpm-workspace.yaml` 添加 allowBuilds 后重跑(本包不涉及) | | 启动日志出现「启动自检发现 N 个问题」 | 安装包内的 `src/client.js` 损坏或缺失;重装或改从 git 源安装 | | npm 发布 404 / E403 | 首次发布需 `--access public` 与 npm 账号权限;确认 `NPM_TOKEN` 为 Automation/CI token |