@wangnanshan/dsh-nanshan-publish-manager 0.0.0-stage → 1.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,3 +1,229 @@
1
- # Temporary Holding Version
1
+ # 【南山】DSH发布管理
2
2
 
3
- This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.
3
+ 把本机开发的 DSH 组件,按 DeepSeek Harness 官方推荐的 npm 包形式发布给其他人安装。
4
+
5
+ - **一个组件清单页**:卡片形式展示本机所有可发布的 DSH 组件(`dsh.bundle` / `dsh.client`),包含版本、发布状态、预检查结果和最近一次发布。
6
+ - **一个组件详情页**:点击卡片进入,用「流程化板块」完成发布——版本与标签 → 发布目标与选项 → 发布预检查 → 确认与执行,右侧常驻该组件的**发布记录列表**。
7
+
8
+ 界面采用现代极简的开发者工具控制台风格(Linear / Vercel / Raycast 一类的浅色克制审美),跟随 Harness 的浅色 / 深色主题。插件图标、侧栏入口和页面标识使用 3D 液态玻璃黑色调;搜索、勾选、关闭等功能图标保持线性,以保证小尺寸下的可读性。
9
+
10
+ ---
11
+
12
+ ## 官方发布形式
13
+
14
+ DSH 组件就是一个 npm 包:
15
+
16
+ ```jsonc
17
+ {
18
+ "name": "@your-scope/your-plugin",
19
+ "version": "1.0.0",
20
+ "type": "module",
21
+ "exports": {
22
+ ".": "./index.js",
23
+ "./client": "./client.js", // 有 UI 时
24
+ "./locale/*.json": "./locale/*.json",
25
+ "./icon": "./icon.svg"
26
+ },
27
+ "files": ["index.js", "client.js", "cordis.patch.yml", "locale/*.json", "icon.svg", "README.md"],
28
+ "dsh": {
29
+ "bundle": { "patch": "./cordis.patch.yml" },
30
+ "client": {
31
+ "platform": "web",
32
+ "immediately": true,
33
+ "inject": ["@deepseek-ai/dsh-client-locale", "@deepseek-ai/dsh-client-ui-layout", "@deepseek-ai/dsh-client-ui-sidebar"]
34
+ }
35
+ }
36
+ }
37
+ ```
38
+
39
+ `cordis.patch.yml` 插入插件行:
40
+
41
+ ```yaml
42
+ - insert:
43
+ - id: your-plugin
44
+ name: '@your-scope/your-plugin'
45
+ ```
46
+
47
+ 发布到 npm 之后,其他人在 DSH 的插件页安装这个包名即可使用。本插件就是按这套形式检查、打包和发布的。
48
+
49
+ ## 发布预检查
50
+
51
+ 静态预检查(进入详情页立即显示):
52
+
53
+ | 预检查项 | 说明 |
54
+ | --- | --- |
55
+ | package.json 可读 | 组件目录必须有可解析的包清单 |
56
+ | 包名符合 npm 规范 | 小写字母、数字与 `- . _ ~`,作用域包为 `@scope/name` |
57
+ | 版本号符合语义化版本 | 如 `1.2.3`、`1.3.0-beta.1` |
58
+ | 未标记 private | `"private": true` 的包无法发布 |
59
+ | 包含描述 / 许可证 | 影响 npm 与插件页展示 |
60
+ | 使用可发布的作用域 | `@local/...` 只是本地占位,发布会提示 |
61
+ | bundle patch 文件存在 | `dsh.bundle.patch` 指向的 `cordis.patch.yml` 必须存在 |
62
+ | patch 的 name 与包名一致 | 官方形式要求 insert 行的 `name` 等于包名 |
63
+ | dsh.client 入口存在 | 声明了 `dsh.client` 就要有 `client.js` |
64
+ | 导出 locale / 图标 | `exports` 中的 `./locale/*.json` 与 `./icon` |
65
+ | files 覆盖运行文件 | `files` 必须覆盖 index / client / patch / 图标 |
66
+ | 图标有效 | SVG / PNG / JPEG / WebP,且不超过 256 KiB |
67
+ | locale 包含标题与描述 | 读取 `meta.title` / `meta.description`(兼容顶层 title) |
68
+ | 包含 README | 说明安装与使用方式 |
69
+
70
+ 完整预检查(点击「发布预检查」)还会执行:
71
+
72
+ | 预检查项 | 说明 |
73
+ | --- | --- |
74
+ | 找到 npm | 自动从 PATH、Homebrew、nvm、Volta 等位置查找 |
75
+ | 已登录 npm registry | 运行 `npm whoami`;演练时只提示不阻断 |
76
+ | registry 可访问 | `npm view <name> versions dist-tags --json`,首次发布 404 视为正常 |
77
+ | 目标版本未被占用 | 已发布版本不能被覆盖 |
78
+ | 版本高于已发布版本 | 低于最新版只提示 |
79
+ | npm 打包内容完整 | `npm pack --dry-run --json`,逐个确认运行文件与资源会进入包 |
80
+ | 构建脚本存在 | 配置了构建脚本时检查 `scripts` 中是否存在 |
81
+
82
+ ## 发布流程
83
+
84
+ 1. **版本与标签** —— 目标版本(写回 `package.json`)、npm tag、`public` / `restricted`。
85
+ 2. **发布目标与选项** —— registry(默认读取你的 `~/.npmrc`)、可选构建脚本(`npm run <script>`)、自动运行发布预检查、先演练、自动写入版本号、发布备注。
86
+ 3. **发布预检查** —— 运行发布预检查;有阻断项时正式发布按钮不可用。
87
+ 4. **确认与执行** —— 选择发布验证方式,勾选确认,先「仅演练」(`npm publish --dry-run`,临时写入的目标版本会在演练后还原)或「正式发布」(带最终确认弹窗);本机会话方式还可以在弹窗里选「在终端发布」。
88
+ 5. **发布记录** —— 每次演练 / 发布 / 失败都会写入本机记录,包含版本、tag、access、验证方式、耗时、预检查摘要和命令输出;终端发布会在记录里标记「终端」。
89
+
90
+ ## 发布验证方式
91
+
92
+ npm 已在 **2025-12-09 永久撤销全部经典 Token**,本插件不再提供该选项,只支持当前仍在使用的三种方式:
93
+
94
+ | 方式 | 适用场景 | 凭据处理 |
95
+ | --- | --- | --- |
96
+ | **本机登录会话 + OTP**(默认) | 本机交互发布;`npm login` 生成 2 小时会话,发布时 npm 强制 2FA | OTP 通过 `npm_config_otp` 环境变量交给 npm,不写命令、不落盘 |
97
+ | **Granular Access Token** | 无人值守、CI 之外的自动化;可在 npm 设置中开启 **Bypass 2FA** | 令牌只用于本次发布,写入权限为 `0600` 的临时 npmrc,发布结束立即删除;不保存、不写日志 |
98
+ | **OIDC 可信发布** | 仅 GitHub Actions(`id-token: write`)或 GitLab CI(`NPM_ID_TOKEN`) | npm 自己用 CI 的 ID Token 换取短期发布令牌,插件不接触任何长期凭据 |
99
+
100
+ 本地 DSH 中 OIDC 选项会显示为不可用;在支持的 CI 环境里会自动变为可用。注意:OIDC 还需要在 npm 包的设置里配置对应的 Trusted Publisher。
101
+
102
+ Granular Access Token 可以在 npm 网站 Settings → Tokens 或 `npm token create` 创建;写令牌最长 90 天,无人值守发布建议开启 Bypass 2FA。
103
+
104
+ 页面内的 OTP 只支持 TOTP(身份验证器 6 位数字)。如果账号使用安全密钥 / 网页型 2FA,npm 需要在交互式终端里打开浏览器授权;这种情况下可以直接在确认弹窗点「在终端发布」,或创建一个开启 Bypass 2FA 的 Granular Access Token 后使用「细粒度令牌」方式。
105
+
106
+ npm 凭据**不经过插件的存储层**:本机会话使用你自己的 `~/.npmrc`;Granular Token 的临时 npmrc 在发布后删除;OTP 只作用于一次子进程。三者都不会写入发布记录。
107
+
108
+ ### 在系统终端发布
109
+
110
+ 在「本机登录会话」方式下,最终确认弹窗提供「在终端发布」:
111
+
112
+ - macOS 打开 Terminal.app;
113
+ - Windows 打开 `cmd.exe`;
114
+ - Linux 尝试 `x-terminal-emulator`、`gnome-terminal`、`konsole`、`xfce4-terminal`、`xterm`。
115
+
116
+ 插件会生成一个临时脚本并自动执行实际发布命令(配置了构建脚本时先执行构建)。你在系统终端里完成 OTP 或浏览器/安全密钥验证;插件等待最多 15 分钟,读取退出码后把结果写入发布记录,记录带「终端」标记。终端输出保留在系统终端窗口,不写入插件记录,避免 OTP 进入日志。
117
+
118
+ 如果终端没有自动出现,或等待超时,插件会弹出居中的错误弹窗;终端窗口里的完整输出仍然保留,可据此排查。
119
+
120
+ ### OTP 的时机
121
+
122
+ OTP 不是插件强制每次都要填写的字段:
123
+
124
+ - **本机会话**:当 npm 对你的账号或这个包要求发布 2FA 时,每一次发布尝试都会发起挑战。填写后才随请求发送;不填时若 npm 挑战,会返回 EOTP,并弹出居中的错误弹窗、清空旧码;关闭弹窗后重新点「正式发布」即可重试。验证码一次性、约 30 秒有效,不能复用。
125
+ - **填写时机**:OTP 只在点击「正式发布」后的确认弹窗里填写。UI 已经运行过发布预检查时,服务端不会在点击后再次执行整套 npm 预检查,因此验证码会在确认后的极短时间内使用,避免被前置预检查拖到过期。
126
+ - **Granular Access Token**:令牌开启 **Bypass 2FA** 时不需要 OTP;未开启时 npm 仍会挑战,建议改用本机会话 + OTP 或换一个开启 Bypass 2FA 的令牌。
127
+ - **OIDC 可信发布**:由 CI 的 ID Token 换发短期令牌,不需要 OTP。
128
+ - **仅演练**:不访问 registry,不需要 OTP。
129
+
130
+ ### 发布命令如何组织
131
+
132
+ 实际执行的命令按场景生成,日志里的命令就是真实 argv,并在末尾用注释标出凭据来源:
133
+
134
+ | 场景 | 命令 |
135
+ | --- | --- |
136
+ | 有作用域包(`@scope/name`) | `npm publish --tag <tag> --access <public\|restricted> --registry <registry>` |
137
+ | 无作用域包 | `npm publish --tag <tag> --registry <registry>`(无作用域包只能是 public,省略 `--access`) |
138
+ | 本机会话 + OTP | 同上,OTP 通过 `npm_config_otp` 环境变量传递,日志注 `# auth: local session + OTP (npm_config_otp)` |
139
+ | 细粒度令牌 | 同上,令牌通过一次性 npmrc(`npm_config_userconfig`)传递,日志注 `# auth: granular access token (temporary npmrc)` |
140
+ | OIDC | 同上,npm 自动完成 OIDC 交换,日志注 `# auth: OIDC trusted publishing` |
141
+ | 在系统终端发布 | 同上,在系统终端里交互完成 OTP / 网页 2FA,日志注 `# auth: local session (system terminal)` |
142
+ | 仅演练 | 追加 `--dry-run`,不注认证信息 |
143
+
144
+ 预发布版本(如 `1.0.0-beta.1`)选择 `latest` 时会给出警告,建议改用 `beta` / `next`;目标版本低于已发布最新版时,npm 会拒绝把 `latest` 指回旧版本,插件会把该错误翻译成明确的提示。
145
+
146
+ ### 如果 OTP 一直失败
147
+
148
+ 按顺序排查:
149
+
150
+ 1. 确认验证码来自**当前登录账号**(`npm whoami` 显示 `wangnanshan`)绑定的身份验证器,并且是刚生成的;旧码不能复用。
151
+ 2. 确认系统时间自动同步。TOTP 依赖本机时钟;当前机器与 npm registry 的偏差约 0.6 秒,属于正常范围。
152
+ 3. 如果账号的 2FA 方式是**安全密钥 / 网页认证**而不是身份验证器 TOTP,页面内输入 6 位码不会成功。请在确认弹窗点「在终端发布」,让 npm 在系统终端里打开浏览器授权;或使用下面的令牌方案。
153
+ 4. 使用 **Granular Access Token** 时,必须在创建令牌时勾选 **Bypass 2FA**(`npm token create --bypass-2fa`);只粘贴一个未开启 Bypass 2FA 的令牌仍会返回 EOTP。
154
+ 5. 如果配置了构建脚本,构建会先于发布执行;构建较慢时验证码可能过期,建议使用开启 Bypass 2FA 的令牌。
155
+
156
+ 失败信息现在会附带「到达发布执行时验证码已输入多少秒」:超过 25 秒更可能是过期;如果只有几秒仍被拒绝,则更可能是验证码不属于当前账号、验证码输错,或账号使用的是安全密钥 / 网页型 2FA 而不是 TOTP。
157
+
158
+ ## 安装
159
+
160
+ 在 Harness 的插件页安装这个 bundle 目录(推荐使用 Harness 的安装入口),安装后左侧栏会出现「【南山】DSH发布管理」图标。
161
+
162
+ 开发时也可以在 profile 里链接:
163
+
164
+ ```jsonc
165
+ // ~/.dsh/profiles/<profile>/package.json
166
+ {
167
+ "dependencies": {
168
+ "@wangnanshan/dsh-nanshan-publish-manager": "link:/path/to/nanshan-publish-manager"
169
+ },
170
+ "dsh": { "profile": { "bundles": ["@wangnanshan/dsh-nanshan-publish-manager"] } }
171
+ }
172
+ ```
173
+
174
+ ## 配置
175
+
176
+ 在 profile 的 `cordis.patch.yml` 中该插件的 `config` 里设置:
177
+
178
+ ```yaml
179
+ - insert:
180
+ - id: nanshan-publish-manager
181
+ name: '@wangnanshan/dsh-nanshan-publish-manager'
182
+ config:
183
+ scanRoots: [] # 额外扫描的组件目录(绝对路径或 ~/...)
184
+ maxScanDepth: 2 # 扫描深度 1–3
185
+ allowPublish: true # false 时禁止正式发布,只能演练
186
+ publishTimeoutMs: 180000
187
+ # registry: https://registry.npmjs.org # 覆盖默认 registry
188
+ ```
189
+
190
+ 组件发现顺序:
191
+
192
+ 1. 当前 profile 中 `link:` / `file:` 依赖指向的本地包;
193
+ 2. `scanRoots` 指定目录(按 `maxScanDepth` 递归);
194
+ 3. 当前工作区(DSH 的当前工作目录,最多两层);
195
+ 4. 在页面上用「添加组件」手动选择的目录(持久保存)。
196
+
197
+ 只收录带 `dsh.bundle` 或 `dsh.client` 的包。
198
+
199
+ ## 数据与接口
200
+
201
+ 数据文件:`$DSH_HOME/nanshan-publish-manager/publish-state.json`
202
+
203
+ - 组件发布设置(按目录保存)
204
+ - 发布记录(每个组件最多 120 条)
205
+ - 手动添加的组件目录
206
+
207
+ HTTP 接口(仅本机、同源写入):
208
+
209
+ | 方法 | 路径 | 作用 |
210
+ | --- | --- | --- |
211
+ | GET | `/api/nanshan-publish-manager` | 组件清单、npm 状态、扫描信息;`?refresh=1` 跳过缓存 |
212
+ | GET | `/api/nanshan-publish-manager/component?dir=` | 组件详情、静态预检查、设置、发布记录 |
213
+ | POST | `/api/nanshan-publish-manager/check` | 运行发布预检查(含 npm 命令) |
214
+ | POST | `/api/nanshan-publish-manager/settings` | 保存发布设置 |
215
+ | POST | `/api/nanshan-publish-manager/targets` | 添加组件目录 |
216
+ | POST | `/api/nanshan-publish-manager/publish` | 演练或正式发布;body 可带 `authMode`(`session` / `token` / `oidc`)与 `accessToken`(仅 token 模式,不落盘) |
217
+
218
+ 接口只接受 loopback 请求;写操作校验同源;组件目录必须是带 `dsh.bundle` / `dsh.client` 的包,避免把任意目录交给 npm。
219
+
220
+ ## 已知限制
221
+
222
+ - 需要本机安装 Node.js 与 npm(版本检查会显示 npm 版本,找不到时页面顶部提示)。
223
+ - 正式发布需要先 `npm login`(2 小时会话,默认网页授权);未登录时只能演练。
224
+ - Granular Access Token 若未开启 Bypass 2FA,发布时仍会被要求 OTP;此时请改用本机会话 + OTP。
225
+ - 发布使用本机 npm 配置,不支持在页面里输入 token;OTP 只用于单次发布,不落盘。
226
+ - 系统终端发布支持 macOS Terminal、Windows `cmd.exe` 和 Linux 常见终端;Windows 的 `npm.cmd` 已做启动适配,但当前环境主要在 macOS 验证。
227
+ - 终端发布最多等待 15 分钟;关闭终端或未完成验证会超时,不会写入成功记录;终端输出不写入插件记录。
228
+ - 页面直接执行 `npm publish`,请在发布前用「仅演练」确认打包内容。
229
+ - `npm publish` 会执行组件 `package.json` 中的 publish 生命周期脚本;请只发布你信任的组件。