dou-cl 0.0.0-stage → 1.0.1
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/LICENSE +21 -0
- package/PUBLISH.md +429 -0
- package/README.md +104 -2
- package/bin/dou-cl.js +215 -0
- package/package.json +62 -4
- package/src/app.js +356 -0
- package/src/bot.js +263 -0
- package/src/color.js +26 -0
- package/src/core/cards.js +152 -0
- package/src/core/combo.js +569 -0
- package/src/core/rules.js +92 -0
- package/src/exercise.js +682 -0
- package/src/games/base.js +280 -0
- package/src/games/doudizhu.js +146 -0
- package/src/games/fivek.js +77 -0
- package/src/games/index.js +25 -0
- package/src/games/paodekuai.js +48 -0
- package/src/net/client.js +262 -0
- package/src/net/server.js +432 -0
- package/src/runner.js +61 -0
- package/src/skins/diff.js +147 -0
- package/src/skins/hex.js +174 -0
- package/src/skins/index.js +116 -0
- package/src/skins/json.js +151 -0
- package/src/skins/log.js +111 -0
- package/src/skins/packet.js +144 -0
- package/src/ui.js +395 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 iguangyu
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/PUBLISH.md
ADDED
|
@@ -0,0 +1,429 @@
|
|
|
1
|
+
# 发布到 npm —— 让别人的机器 `npx dou-cl` 直接开玩
|
|
2
|
+
|
|
3
|
+
> 本文只讲怎么把这个包发上 npm。玩法说明看 [README.md](README.md)。
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## 0. 先说名字:`dou-cli` 已经被占了
|
|
8
|
+
|
|
9
|
+
你要的 `npx dou-cli` 用不了,因为 npm 上已经有这个包:
|
|
10
|
+
|
|
11
|
+
```
|
|
12
|
+
dou-cli@1.0.12
|
|
13
|
+
author: Andoni Arbulu Lozano <andoni.arbulu@digitalonus.com>
|
|
14
|
+
maintainers: andoni-arb, richardhern
|
|
15
|
+
last modified: 2022-04-29
|
|
16
|
+
description: A simple cli for creating and setting up projects ... [Digital On Us]
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
是家美国公司 2022 年发的脚手架工具,虽然早就没人维护了,但包名还是人家的。
|
|
20
|
+
npm 没有"抢名字"的正规途径(除非走商标争议,不值当)。
|
|
21
|
+
|
|
22
|
+
**所以用 `dou-cl`**,这名字是空的,而且正好是这个仓库的名字,一样短:
|
|
23
|
+
|
|
24
|
+
| 方案 | 别人怎么运行 | 说明 |
|
|
25
|
+
| --- | --- | --- |
|
|
26
|
+
| **`dou-cl`(推荐)** | `npx dou-cl` | 名字已确认空闲,和仓库同名 |
|
|
27
|
+
| 带 scope | `npx @iguangyu/dou-cli` | 一定能用,但每次要多敲一截 |
|
|
28
|
+
| `doucli` | `npx doucli` | 也空闲,但少个连字符看着怪 |
|
|
29
|
+
|
|
30
|
+
`package.json` 里现在就是 `"name": "dou-cl"`,`bin` 里也有 `dou-cl`,所以发上去就是 `npx dou-cl`。
|
|
31
|
+
|
|
32
|
+
---
|
|
33
|
+
|
|
34
|
+
## 1. 一次性准备
|
|
35
|
+
|
|
36
|
+
### 1.1 注册 npm 账号
|
|
37
|
+
|
|
38
|
+
没有账号就去 <https://www.npmjs.com/signup> 注册。注册完**去邮箱点验证链接**,
|
|
39
|
+
没验证的账号发布时会报 `E403`。
|
|
40
|
+
|
|
41
|
+
### 1.2 登录(注意要指向官方源)
|
|
42
|
+
|
|
43
|
+
你这台机器默认 registry 是淘宝镜像,所以**登录必须显式指定官方源**:
|
|
44
|
+
|
|
45
|
+
```bash
|
|
46
|
+
npm login --registry=https://registry.npmjs.org/
|
|
47
|
+
# Username / Password / Email / 一次性验证码(如果开了 2FA)
|
|
48
|
+
npm whoami --registry=https://registry.npmjs.org/ # 能打印出用户名就成功了
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
> token 会写进 `~/.npmrc`,并且**只对 npmjs 生效** —— 你平时 `npm i` 还是走淘宝镜像,不受影响。
|
|
52
|
+
|
|
53
|
+
**发布目标已经在 `package.json` 里锁死了**,不用你每次加参数:
|
|
54
|
+
|
|
55
|
+
```json
|
|
56
|
+
"publishConfig": { "registry": "https://registry.npmjs.org/", "access": "public" }
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
---
|
|
60
|
+
|
|
61
|
+
## 2. 发布(两条命令)
|
|
62
|
+
|
|
63
|
+
```bash
|
|
64
|
+
cd C:\Users\lgy\WorkBuddy\Dou_CL
|
|
65
|
+
|
|
66
|
+
npm publish --dry-run # 先干跑一遍:列文件、算体积,不会真发
|
|
67
|
+
npm publish # 真发
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
`--dry-run` 应该看到这样的输出(已经验证过):
|
|
71
|
+
|
|
72
|
+
```
|
|
73
|
+
npm notice name: dou-cl
|
|
74
|
+
npm notice version: 1.0.0
|
|
75
|
+
npm notice package size: 46.3 kB
|
|
76
|
+
npm notice unpacked size: 150.3 kB
|
|
77
|
+
npm notice total files: 25
|
|
78
|
+
npm notice Publishing to https://registry.npmjs.org/ with tag latest and public access (dry-run)
|
|
79
|
+
+ dou-cl@1.0.0
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
注意 `Publishing to https://registry.npmjs.org/` 这行 —— 说明 `publishConfig` 生效了,
|
|
83
|
+
没跑到淘宝镜像上去。
|
|
84
|
+
|
|
85
|
+
真发的时候会自动先跑测试(`prepublishOnly` → `npm test`,97 条断言)。
|
|
86
|
+
**测试挂了就不会发出去**,这是故意的。
|
|
87
|
+
|
|
88
|
+
### 2.1 账号开了 2FA 的话(大概率会撞上)
|
|
89
|
+
|
|
90
|
+
现在 npm 强制 2FA,很多人都开了。症状是发布直接 403:
|
|
91
|
+
|
|
92
|
+
```
|
|
93
|
+
npm error code E403
|
|
94
|
+
npm error 403 403 Forbidden - PUT https://registry.npmjs.org/dou-cl - Two-factor
|
|
95
|
+
authentication or granular access token with bypass 2fa enabled is required to publish packages.
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
意思是:**你手上这个 token 没有「Bypass 2FA」权限**。
|
|
99
|
+
|
|
100
|
+
> 顺带一个坑:2025 年 11 月起 npm 只支持 **Granular access token**,老的 Legacy token 已经下线。
|
|
101
|
+
> Granular token 长这样:`npm_` + 36 位(共 40 字符)。
|
|
102
|
+
> 如果你早先建的 token 没勾 Bypass 2FA(**该选项默认不勾**),就会正好撞上这个 403。
|
|
103
|
+
|
|
104
|
+
两条路,任选:
|
|
105
|
+
|
|
106
|
+
#### 路 A:发布时补一次性验证码(最快)
|
|
107
|
+
|
|
108
|
+
```bash
|
|
109
|
+
npm publish --otp=123456
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
验证码来自你绑定 2FA 的验证器 App,**30 秒失效**,过期就重新跑一次。
|
|
113
|
+
缺点:每次发布都要掏手机。
|
|
114
|
+
|
|
115
|
+
> 如果你的 2FA 是 **passkey / 安全密钥**(不是 6 位数字),那没码可输,只能走路 B。
|
|
116
|
+
|
|
117
|
+
#### 路 B:重建一个勾了 Bypass 2FA 的 token(一劳永逸)
|
|
118
|
+
|
|
119
|
+
1. 打开 <https://www.npmjs.com/settings/~/tokens> → **Generate New Token → Granular Access Token**
|
|
120
|
+
2. 逐项这么选(**这四项选错任何一个都会继续 403**):
|
|
121
|
+
|
|
122
|
+
| 项目 | 选什么 | 为什么 |
|
|
123
|
+
| --- | --- | --- |
|
|
124
|
+
| Expiration | 自定,比如 90 天 | 到期要重建,记得加提醒 |
|
|
125
|
+
| Packages and scopes | **All packages** | 第一次发新包时 `dou-cl` 还不存在,列表里根本勾不到它 |
|
|
126
|
+
| Permission | **Read and write** → 再选 **Publish and stage** | 选成 *Stage only* 会报 `E_STAGE_REQUIRED`,那是另一套审核流程 |
|
|
127
|
+
| **Bypass 2FA** | **☑ 必须勾上** | 就是这次 403 的根因 |
|
|
128
|
+
|
|
129
|
+
> 「Bypass 2FA」这个勾选框**只在 token 有写权限时才出现**,默认是**不勾**的。
|
|
130
|
+
> 它一旦勾上,优先级高于账号级/包级的 2FA 设置 —— 也就是说这个 token 能做发布这类"自动化动作"而不用再掏验证码。
|
|
131
|
+
> 但注意:**账号安全类操作(改密码、改 2FA、管 token、加维护者)永远要交互式 2FA**,token 绕不过去。
|
|
132
|
+
|
|
133
|
+
3. 复制 token(**只显示这一次**),替换掉本地那个:
|
|
134
|
+
|
|
135
|
+
直接编辑 `C:\Users\lgy\.npmrc`,把这一行
|
|
136
|
+
```
|
|
137
|
+
//registry.npmjs.org/:_authToken=npm_旧token
|
|
138
|
+
```
|
|
139
|
+
换成新的。或者:
|
|
140
|
+
```bash
|
|
141
|
+
npm config set //registry.npmjs.org/:_authToken npm_新的token
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
4. 验证一下换成功了、然后发:
|
|
145
|
+
```bash
|
|
146
|
+
npm whoami --registry=https://registry.npmjs.org/
|
|
147
|
+
npm publish
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
> ⚠️ token 是密码级别的凭证:只放在 `~/.npmrc`,**别写进项目里的任何文件**,别提交,别贴聊天里。
|
|
151
|
+
> 泄露了就回上面的页面 Revoke 掉重建。
|
|
152
|
+
|
|
153
|
+
#### 路 C:将来换 trusted publishing(推荐,但要 CI)
|
|
154
|
+
|
|
155
|
+
npm 已经公告:**Bypass 2FA token 的"直接发布"能力会在 2027 年 1 月移除**。
|
|
156
|
+
长期方案是 trusted publishing(OIDC),**完全不需要 token**,也就没有 2FA 这档事 —— 见 §7。
|
|
157
|
+
|
|
158
|
+
### 2.2 换手机 / 丢了手机怎么办
|
|
159
|
+
|
|
160
|
+
先说结论:**TOTP 验证码不绑手机,绑的是那串密钥(secret)。**
|
|
161
|
+
6 位数字是用 `HMAC-SHA1(secret, 当前时间/30)` 算出来的 —— 只要新手机里有同一串 secret,
|
|
162
|
+
算出来的码一模一样,npm 那边什么都不用改。
|
|
163
|
+
|
|
164
|
+
所以关键只有一个:**那串 secret 能不能跟着你到新手机。**
|
|
165
|
+
|
|
166
|
+
| 你用的验证器 | 换机后 |
|
|
167
|
+
| --- | --- |
|
|
168
|
+
| iPhone 自带「密码」App | 存在 **iCloud 钥匙串**(端到端加密),同一 Apple ID 的新机自动同步,大概率直接能用 |
|
|
169
|
+
| Google Authenticator | 默认**不同步**。要么它自己的 Cloud sync 开了(需 Google 账号),要么用「转移账号」扫码手动搬 |
|
|
170
|
+
| 微软 Authenticator / Authy 等 | 多数有云备份,看有没有开 |
|
|
171
|
+
| 小众 / 国产验证器 | 多数不同步,**必须自己抄出 secret** |
|
|
172
|
+
|
|
173
|
+
> 登录时是**打开 App 看 6 位数字** = TOTP(上面这张表适用);
|
|
174
|
+
> 如果是**弹一下 Face ID 就直接过** = security key / passkey,那是另一套 ——
|
|
175
|
+
> Apple 的 passkey 走 iCloud 钥匙串也会同步,但不保证,恢复码照样是兜底。
|
|
176
|
+
|
|
177
|
+
⚠️ **别指望用 Apple「快速开始」迁移就万事大吉** —— 不少验证器 App 故意不把 secret 放进设备备份(安全考虑)。
|
|
178
|
+
|
|
179
|
+
#### 现在就去做的三件事(按性价比排序)
|
|
180
|
+
|
|
181
|
+
1. **存下恢复码**:登录 npm → 头像 → **Account** → Two-Factor Authentication →
|
|
182
|
+
**Modify 2FA** → **Manage Recovery Codes**。能看到就抄到密码管理器;
|
|
183
|
+
看不到就 **Regenerate Code** 重新生成一套(**旧的会立刻全部失效**)。
|
|
184
|
+
|
|
185
|
+
2. **关联 GitHub 账号**:Account → **Linked Accounts & Recovery Option** → **Link with GitHub**。
|
|
186
|
+
这是丢了设备、又丢了恢复码之后**唯一能加速找回**的东西 ——
|
|
187
|
+
npm 的账号恢复表单里就有一个 "Connect to GitHub" 按钮,专门用来让客服核验你。
|
|
188
|
+
|
|
189
|
+
3. **把 secret 本身也备份**:光有恢复码只能救账号,救不了"顺手发个版"。
|
|
190
|
+
把 npm 的 TOTP secret(或直接换成走 iCloud 钥匙串的验证器)放进密码管理器,
|
|
191
|
+
以后换机是自动跟过去的。
|
|
192
|
+
|
|
193
|
+
#### ⚠️ 恢复码有个大坑:用一次触发 72 小时冻结
|
|
194
|
+
|
|
195
|
+
用恢复码登录后,npm 会给账号加一个**安全冻结**,**不能提前解除**,自动到期。
|
|
196
|
+
冻结期内:
|
|
197
|
+
|
|
198
|
+
- ✅ 能登录、浏览/下载/安装包、改密码、**添加新的 2FA 方式**
|
|
199
|
+
- ❌ **不能发布/取消发布、不能建 token、不能改包设置和维护者、不能改组织成员**
|
|
200
|
+
|
|
201
|
+
也就是说:**手机丢了当天别想发版,至少等 3 天。** 这也是为什么下面这条路更值得走。
|
|
202
|
+
|
|
203
|
+
#### 设备 + 恢复码都丢了
|
|
204
|
+
|
|
205
|
+
走 npm 的账号恢复流程:
|
|
206
|
+
|
|
207
|
+
1. <https://www.npmjs.com/login> → 在 2FA 页面点 **Use a recovery code or request a reset**
|
|
208
|
+
2. 点 **Try recovering your account** → **Start Account Recovery**
|
|
209
|
+
3. 填注册邮箱收到的**一次性验证码**(邮箱也进不去就选 **Skip email verification**)
|
|
210
|
+
4. 开 support ticket,**How can we help?** 选 **Reset my two-factor authentication (2FA)**;
|
|
211
|
+
之前关联过 GitHub 就点 **Connect to GitHub** 帮客服核验
|
|
212
|
+
5. **Submit Support Ticket**
|
|
213
|
+
|
|
214
|
+
#### 真正根治:发布这件事根本不需要手机
|
|
215
|
+
|
|
216
|
+
对你的 `dou-cl` 来说,最省心的不是"怎么保住手机",而是**让发布流程不依赖 2FA**:
|
|
217
|
+
|
|
218
|
+
- **短期**:建一个勾了 **Bypass 2FA** 的 granular token(§2.1 路 B),发布不用输验证码。
|
|
219
|
+
代价是 token 有有效期,且 2027-01 之后不能直接发布。
|
|
220
|
+
- **长期**:**trusted publishing(OIDC)**(§7)—— CI 里 `git push` 一个 tag 就发版,
|
|
221
|
+
**不需要 2FA、不需要 token、不需要手机上任何东西**。换手机、丢手机、人在外面都不影响。
|
|
222
|
+
|
|
223
|
+
---
|
|
224
|
+
|
|
225
|
+
## 3. 别人怎么玩
|
|
226
|
+
|
|
227
|
+
发完之后,**任何装了 Node 16+ 的机器**,一行就够:
|
|
228
|
+
|
|
229
|
+
```bash
|
|
230
|
+
npx dou-cl
|
|
231
|
+
```
|
|
232
|
+
|
|
233
|
+
第一次会下载(46 kB,加上 `ws` 依赖也就 100 KB 出头),之后走 npx 缓存。
|
|
234
|
+
|
|
235
|
+
常用几种:
|
|
236
|
+
|
|
237
|
+
```bash
|
|
238
|
+
npx dou-cl -g doudizhu # 跳过菜单,直接开一局(最隐蔽)
|
|
239
|
+
npx dou-cl -g fivek # 510K
|
|
240
|
+
npx dou-cl --skin hex # 换个伪装皮肤
|
|
241
|
+
npx dou-cl --serve --port 8080 # 当服务器,别人连你
|
|
242
|
+
npx dou-cl --join 192.168.1.10:8080 --code ABCD
|
|
243
|
+
npx dou-cl --match doudizhu --server 1.2.3.4:8080
|
|
244
|
+
```
|
|
245
|
+
|
|
246
|
+
### ⚠️ 刚发完那几分钟,npx 会拉不到
|
|
247
|
+
|
|
248
|
+
发布命令**返回成功 ≠ 立刻全网点都能下**。registry 上先出现一个占位版本,真正的版本号
|
|
249
|
+
要再过一会儿才生效;CDN 和淘宝镜像还要再传播一轮。这期间 `npx` 会拉到空壳,
|
|
250
|
+
报的是这句:
|
|
251
|
+
|
|
252
|
+
```
|
|
253
|
+
npm error could not determine executable to run
|
|
254
|
+
```
|
|
255
|
+
|
|
256
|
+
**看到这句先别慌,八成不是包的问题,是时间差。** 实测时间线(本包第一次发布):
|
|
257
|
+
|
|
258
|
+
```
|
|
259
|
+
10:07:40 registry 上出现占位版本 0.0.0-stage
|
|
260
|
+
10:09:48 真正的 1.0.0 才生效 ← 这之后才下得到
|
|
261
|
+
10:09:10 在另一个窗口跑 npx ← 早了 38 秒,于是报错
|
|
262
|
+
```
|
|
263
|
+
|
|
264
|
+
#### 怎么确认到底是"时间差"还是"包真的坏了"
|
|
265
|
+
|
|
266
|
+
```bash
|
|
267
|
+
# 1. 官方源上有没有你的版本、bin 对不对
|
|
268
|
+
npm view dou-cl version bin --registry=https://registry.npmjs.org/
|
|
269
|
+
# version = '1.0.0'
|
|
270
|
+
# bin = { doucl: 'bin/dou-cl.js', 'dou-cl': 'bin/dou-cl.js' }
|
|
271
|
+
|
|
272
|
+
# 2. 把已发布的 tarball 拉下来,确认 bin 文件真的在里面
|
|
273
|
+
curl -sSL -o pkg.tgz https://registry.npmjs.org/dou-cl/-/dou-cl-1.0.0.tgz
|
|
274
|
+
tar -tzf pkg.tgz | grep bin/
|
|
275
|
+
|
|
276
|
+
# 3. 直接装一遍跑
|
|
277
|
+
npx --yes ./pkg.tgz --version
|
|
278
|
+
```
|
|
279
|
+
|
|
280
|
+
第 1 步有正确的 `bin`、第 2 步能看到 `package/bin/dou-cl.js`、第 3 步能跑 ——
|
|
281
|
+
那包就是好的,纯粹是等的时间不够。
|
|
282
|
+
|
|
283
|
+
#### 两个加速办法
|
|
284
|
+
|
|
285
|
+
```bash
|
|
286
|
+
# 绕开镜像,直接走官方源(最快)
|
|
287
|
+
npx --registry=https://registry.npmjs.org/ dou-cl
|
|
288
|
+
|
|
289
|
+
# 或者直接等几分钟再试
|
|
290
|
+
npx dou-cl
|
|
291
|
+
```
|
|
292
|
+
|
|
293
|
+
> 如果等了很久还是这句,而且 `npm view dou-cl bin` **也**看不到 `bin` 字段,
|
|
294
|
+
> 那才是真的发错了(比如从别的目录发的、或者 `package.json` 里的 `bin` 名字和包名不一致),
|
|
295
|
+
> 去看 §5 的错误对照表。
|
|
296
|
+
>
|
|
297
|
+
> 另外:如果试过好几次,npx 可能把空壳缓存下来了,清一下再试:
|
|
298
|
+
> `npm cache clean --force`(或者删掉 `%LOCALAPPDATA%\npm-cache\_npx` 下相关目录)。
|
|
299
|
+
|
|
300
|
+
---
|
|
301
|
+
|
|
302
|
+
## 4. 以后更新版本
|
|
303
|
+
|
|
304
|
+
改完代码,**必须升版本号**再发,否则 npm 会报 `EPUBLISHCONFLICT` / `E403`:
|
|
305
|
+
|
|
306
|
+
```bash
|
|
307
|
+
npm version patch # 1.0.0 → 1.0.1 修 bug
|
|
308
|
+
npm version minor # 1.0.0 → 1.1.0 加功能
|
|
309
|
+
npm version major # 1.0.0 → 2.0.0 不兼容改动
|
|
310
|
+
|
|
311
|
+
npm publish
|
|
312
|
+
```
|
|
313
|
+
|
|
314
|
+
`npm version` 会自动改 `package.json`、打一个 git tag(`v1.0.1`)、并提交。
|
|
315
|
+
顺手把 tag 推上去,GitHub 上就能看到版本:
|
|
316
|
+
|
|
317
|
+
```bash
|
|
318
|
+
git push --follow-tags
|
|
319
|
+
```
|
|
320
|
+
|
|
321
|
+
---
|
|
322
|
+
|
|
323
|
+
## 5. 常见错误对照
|
|
324
|
+
|
|
325
|
+
| 报错 | 原因 / 怎么办 |
|
|
326
|
+
| --- | --- |
|
|
327
|
+
| `E403 ... you must be logged in` | 没登录。`npm login --registry=https://registry.npmjs.org/` |
|
|
328
|
+
| `E403 ... verify your email` | 账号邮箱没验证,去邮箱点链接 |
|
|
329
|
+
| `E403 ... Two-factor authentication or granular access token with bypass 2fa enabled is required` | **token 没勾 Bypass 2FA** —— 最常撞的一个。`npm publish --otp=123456`,或按 §2.1 重建 token |
|
|
330
|
+
| `E403 You do not have permission to publish "dou-cli"` | 名字被占用(就是本文第 0 节那事)。换名或改 `package.json` 的 `name` |
|
|
331
|
+
| `E403 You do not have permission to publish "dou-cl"` | token 的 Packages and scopes 没勾「All packages」,勾不到还不存在的包 |
|
|
332
|
+
| `E_STAGE_REQUIRED` | token 建成了 *Stage only*,重建时改选 **Read and write → Publish and stage** |
|
|
333
|
+
| `could not determine executable to run` | **九成是时间差**:发布命令刚返回、registry 还没传播完,npx 拉到了占位版本。等几分钟或加 `--registry=https://registry.npmjs.org/`(见 §3)。也可能是包名和 bin 名不一致,用 `npm view dou-cl bin` 确认 |
|
|
334
|
+
| `EPUBLISHCONFLICT` / `cannot publish over the previously published versions` | 版本号没升。`npm version patch` |
|
|
335
|
+
| `EOTP` | 开了 2FA,命令会提示你输一次性验证码 |
|
|
336
|
+
| `npm notice Publishing to https://registry.npmmirror.com` | 说明 `publishConfig` 被改掉了,**千万别发到镜像**,改回来 |
|
|
337
|
+
| 发布成功但 `npx dou-cl` 找不到 | 镜像同步延迟,见第 3 节 |
|
|
338
|
+
| `402 Payment Required` | 想发到别人的 scope 下,或 scope 未授权 |
|
|
339
|
+
|
|
340
|
+
### 发错了想撤
|
|
341
|
+
|
|
342
|
+
```bash
|
|
343
|
+
npm unpublish dou-cl@1.0.0 --force
|
|
344
|
+
```
|
|
345
|
+
|
|
346
|
+
**限制很严**:只有发布后 **72 小时内**、且没有别的包依赖它、且不是被大量下载过的版本才能撤。
|
|
347
|
+
所以发布前务必先用 `--dry-run` 看一眼文件列表。
|
|
348
|
+
|
|
349
|
+
---
|
|
350
|
+
|
|
351
|
+
## 6. 发布前检查清单
|
|
352
|
+
|
|
353
|
+
- [ ] `npm whoami --registry=https://registry.npmjs.org/` 能打印用户名
|
|
354
|
+
- [ ] `npm test` 全绿(97 条断言)
|
|
355
|
+
- [ ] `npm publish --dry-run` 输出的 `Publishing to` 是 **registry.npmjs.org**
|
|
356
|
+
- [ ] `--dry-run` 的文件列表里**没有** `test/`、`预览.html`、`.workbuddy/`、`node_modules/`
|
|
357
|
+
(`package.json` 的 `files` 白名单控制,现在只有 `bin` / `src` / `README.md` / `PUBLISH.md` / `LICENSE`)
|
|
358
|
+
- [ ] **token 勾了 Bypass 2FA,或者你准备好输 `--otp=`**(见 §2.1,这是最容易卡住的一步)
|
|
359
|
+
- [ ] 升过版本号了(重复发同一个版本会被拒)
|
|
360
|
+
- [ ] `git status` 干净、改动的代码都提交了
|
|
361
|
+
|
|
362
|
+
---
|
|
363
|
+
|
|
364
|
+
## 7. 可选:推 tag 自动发布(GitHub Actions + trusted publishing)
|
|
365
|
+
|
|
366
|
+
npm 已经公告 **2027 年 1 月会移除 bypass-2FA token 的"直接发布"能力**,
|
|
367
|
+
所以 CI 这条路现在推荐走 **trusted publishing(OIDC)**:**完全不用 token**,
|
|
368
|
+
也就没有 2FA 那档子事,而且顺带拿到 provenance 签名。
|
|
369
|
+
|
|
370
|
+
在仓库里建 `.github/workflows/publish.yml`:
|
|
371
|
+
|
|
372
|
+
```yaml
|
|
373
|
+
name: publish
|
|
374
|
+
on:
|
|
375
|
+
push:
|
|
376
|
+
tags: ['v*'] # 只有推 v1.2.3 这种 tag 才触发,平时 push 不会跑
|
|
377
|
+
jobs:
|
|
378
|
+
npm:
|
|
379
|
+
runs-on: ubuntu-latest
|
|
380
|
+
permissions:
|
|
381
|
+
contents: read
|
|
382
|
+
id-token: write # trusted publishing / provenance 都要这个
|
|
383
|
+
steps:
|
|
384
|
+
- uses: actions/checkout@v4
|
|
385
|
+
- uses: actions/setup-node@v4
|
|
386
|
+
with:
|
|
387
|
+
node-version: 20
|
|
388
|
+
registry-url: https://registry.npmjs.org/
|
|
389
|
+
- run: npm ci
|
|
390
|
+
- run: npm publish --provenance --access public
|
|
391
|
+
# 注意:这里没有 NODE_AUTH_TOKEN,靠 OIDC 换临时凭证
|
|
392
|
+
```
|
|
393
|
+
|
|
394
|
+
用之前要到 npm 上把仓库挂上去:
|
|
395
|
+
|
|
396
|
+
1. 打开 <https://www.npmjs.com/package/dou-cl/access>(包发出来之后才有这一页)
|
|
397
|
+
→ **Trusted Publisher** → 选 **GitHub Actions**
|
|
398
|
+
2. 填:Organization/user = `iguangyu`,Repository = `dou-cl`,
|
|
399
|
+
Workflow filename = `publish.yml`(**只写文件名,不带路径**),Environment 留空
|
|
400
|
+
3. 保存。之后 `npm version patch && git push --follow-tags`,tag 一推就自动发。
|
|
401
|
+
|
|
402
|
+
> 这套的前提是包**已经存在**(第一次还是得用 `npm publish` 手动发一次)。
|
|
403
|
+
> 所以顺序是:先按 §2 手动发布成功 → 再去配 trusted publisher。
|
|
404
|
+
|
|
405
|
+
> 注意:`publish.yml` 我**没有**替你建。因为没配 trusted publisher 之前,
|
|
406
|
+
> 一旦有 tag 推上去 CI 就会红。你要用的话自己建,或者让我建。
|
|
407
|
+
|
|
408
|
+
---
|
|
409
|
+
|
|
410
|
+
## 8. 附:这个包现在的发布配置
|
|
411
|
+
|
|
412
|
+
```jsonc
|
|
413
|
+
{
|
|
414
|
+
"name": "dou-cl", // 发布后的包名 → npx dou-cl
|
|
415
|
+
"version": "1.0.0",
|
|
416
|
+
"bin": {
|
|
417
|
+
"dou-cl": "bin/dou-cl.js", // npx 找的就是这个
|
|
418
|
+
"doucl": "bin/dou-cl.js" // 顺手给的短别名(本地安装可用)
|
|
419
|
+
},
|
|
420
|
+
"files": ["bin", "src", "README.md", "PUBLISH.md", "LICENSE"], // 只发这些
|
|
421
|
+
"engines": { "node": ">=16" },
|
|
422
|
+
"dependencies": { "ws": "^8.18.0" }, // 联网用的,就这一个
|
|
423
|
+
"scripts": { "prepublishOnly": "npm test" }, // 发布前自动跑测试
|
|
424
|
+
"publishConfig": { "registry": "https://registry.npmjs.org/", "access": "public" }
|
|
425
|
+
}
|
|
426
|
+
```
|
|
427
|
+
|
|
428
|
+
`ws` 这个依赖已经在 tarball 里装好验证过了:本地 `npm i dou-cl-1.0.0.tgz`
|
|
429
|
+
之后 `npx ../dou-cl-1.0.0.tgz` 能正常起菜单、开对局、出牌,所以发出去别人也一样能跑。
|
package/README.md
CHANGED
|
@@ -1,3 +1,105 @@
|
|
|
1
|
-
|
|
1
|
+
<p align="center">
|
|
2
|
+
<img src="https://raw.githubusercontent.com/iguangyu/dou-cl/main/docs/logo.png" alt="dou-cl" width="782">
|
|
3
|
+
</p>
|
|
2
4
|
|
|
3
|
-
|
|
5
|
+
<p align="center">
|
|
6
|
+
<a href="https://www.npmjs.com/package/dou-cl"><img src="https://img.shields.io/npm/v/dou-cl?color=2ea44f&label=npm" alt="npm version"></a>
|
|
7
|
+
<a href="https://www.npmjs.com/package/dou-cl"><img src="https://img.shields.io/badge/license-MIT-blue" alt="license"></a>
|
|
8
|
+
<img src="https://img.shields.io/badge/node-%3E%3D16-3c873a" alt="node">
|
|
9
|
+
</p>
|
|
10
|
+
|
|
11
|
+
<p align="center"><b>一个伪装成开发控制台的命令行牌桌。</b></p>
|
|
12
|
+
|
|
13
|
+
跑起来就是一屏正常的开发输出:服务端日志、`xxd` 转储、JSON 帧、git diff。
|
|
14
|
+
里面是**斗地主 / 跑得快 / 510K**,牌局信息一条不删,只是换了层壳。
|
|
15
|
+
工位上扫一眼屏幕的人,只会觉得你在看构建日志。
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
npx dou-cl # 进菜单
|
|
19
|
+
npx dou-cl -g doudizhu # 跳过菜单直接开一局
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
---
|
|
23
|
+
|
|
24
|
+
## 四种伪装
|
|
25
|
+
|
|
26
|
+
**`log`(默认)** —— 服务端日志流。看 `hand[...]` / `peers=[...]` / `table=`。
|
|
27
|
+
|
|
28
|
+
<p align="center">
|
|
29
|
+
<img src="https://raw.githubusercontent.com/iguangyu/dou-cl/main/docs/skin-log.png" alt="日志流" width="753">
|
|
30
|
+
</p>
|
|
31
|
+
|
|
32
|
+
时间戳单调递增,还混着几行无关的噪声日志,整屏就是某个服务在正常打日志。
|
|
33
|
+
|
|
34
|
+
**`hex`** —— `xxd` 十六进制转储。**只读右边 ASCII 列。**
|
|
35
|
+
|
|
36
|
+
<p align="center">
|
|
37
|
+
<img src="https://raw.githubusercontent.com/iguangyu/dou-cl/main/docs/skin-hex.png" alt="hexdump" width="567">
|
|
38
|
+
</p>
|
|
39
|
+
|
|
40
|
+
左边是真 hex、跟右列逐字节对应,不是随便编的。
|
|
41
|
+
|
|
42
|
+
**`json`** —— WS 收到的 JSON 帧。看 `"hand"` / `"peers"` / `"table"`。
|
|
43
|
+
|
|
44
|
+
<p align="center">
|
|
45
|
+
<img src="https://raw.githubusercontent.com/iguangyu/dou-cl/main/docs/skin-json.png" alt="JSON" width="579">
|
|
46
|
+
</p>
|
|
47
|
+
|
|
48
|
+
去掉颜色就是一份合法 JSON,能直接 `JSON.parse`。
|
|
49
|
+
|
|
50
|
+
**`diff`** —— YAML 的 git diff。**只读绿色 `+` 行。**
|
|
51
|
+
|
|
52
|
+
<p align="center">
|
|
53
|
+
<img src="https://raw.githubusercontent.com/iguangyu/dou-cl/main/docs/skin-diff.png" alt="git diff" width="506">
|
|
54
|
+
</p>
|
|
55
|
+
|
|
56
|
+
是真 diff,能 `git apply` 回去;红色 `-` 是上一帧,不用看。
|
|
57
|
+
|
|
58
|
+
四种壳都是**真货**:hex 逐字节对应、JSON 能解析、diff 能 apply。
|
|
59
|
+
输出也全是 **ASCII** —— 不出现中文,玩家名是 `self` / `mei`,角色是 `landlord` / `farmer`,
|
|
60
|
+
输入提示符也是伪装的(`dev@ws:~/svc$ `、`node > `、`[tail -f] $ `),敲的 `34567` 看起来就是条命令。
|
|
61
|
+
|
|
62
|
+
```bash
|
|
63
|
+
npx dou-cl --skin hex # 启动时就换
|
|
64
|
+
npx dou-cl --skins # 列出全部
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
游戏里敲 `skin <名>` 随时换,`reveal` 看一眼原生牌桌,`redraw` 重画一屏。
|
|
68
|
+
|
|
69
|
+
---
|
|
70
|
+
|
|
71
|
+
## 操作
|
|
72
|
+
|
|
73
|
+
牌面**一个字符表示点数**:`3 4 5 6 7 8 9 0(=10) J Q K A 2`,`w`=小王 `W`=大王;花色 `s h c d`。
|
|
74
|
+
|
|
75
|
+
| 操作 | 写法 |
|
|
76
|
+
| --- | --- |
|
|
77
|
+
| 出牌 | 直接敲点数:`34567` 或 `3 4 5 6 7`;指定花色 `5s 5h` |
|
|
78
|
+
| 不要 / 提示 / 帮助 / 退出 | `p` / `h` / `?` / `quit` |
|
|
79
|
+
| 看真身 / 换皮肤 / 重画 | `reveal` / `skin <名>` / `redraw` |
|
|
80
|
+
|
|
81
|
+
同花顺、五十K **不用管花色**,直接敲 `56789` / `50K`,程序自动挑同花色那组。
|
|
82
|
+
|
|
83
|
+
---
|
|
84
|
+
|
|
85
|
+
## 三种玩法
|
|
86
|
+
|
|
87
|
+
| 玩法 | 人数 | 简介 |
|
|
88
|
+
| --- | --- | --- |
|
|
89
|
+
| **斗地主** | 3 | 叫分 1/2/3 抢地主,拿 3 张底牌;炸弹 / 春天各 ×2 |
|
|
90
|
+
| **跑得快** | 3 | 一副牌去大小王,持 ♠3 者先出且首手必带 ♠3 |
|
|
91
|
+
| **510K** | 4 | 两副牌,5/10/K 计分;五十K 是通吃牌型 |
|
|
92
|
+
|
|
93
|
+
都可以联网:一个人 `--serve` 开服务器,其他人 `--join <地址> --code <房间号>` 进来,
|
|
94
|
+
或 `--match <玩法>` 快速匹配,人数不够由电脑补齐。
|
|
95
|
+
|
|
96
|
+
```bash
|
|
97
|
+
npx dou-cl --serve --port 8080
|
|
98
|
+
npx dou-cl --join 192.168.1.10:8080 --code ABCD
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
---
|
|
102
|
+
|
|
103
|
+
## License
|
|
104
|
+
|
|
105
|
+
MIT
|