mslxdff 0.1.199 → 0.1.203

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.
Files changed (327) hide show
  1. package/README.md +3 -3
  2. package/bin/mslxdff.js +1 -1
  3. package/package.json +38 -38
  4. package/plugins/README.md +14 -14
  5. package/plugins/prefer-model.mjs.example +14 -14
  6. package/src/anthropic/count-tokens.js +61 -61
  7. package/src/anthropic/request-body.js +126 -126
  8. package/src/anthropic/shared.js +18 -18
  9. package/src/anthropic/sse-aggregate.js +56 -56
  10. package/src/anthropic/translate.js +287 -287
  11. package/src/anthropic/web-search.js +361 -361
  12. package/src/api-kind.js +31 -31
  13. package/src/autostart.js +288 -288
  14. package/src/bench/probe.js +1 -1
  15. package/src/bench/runner.js +1 -1
  16. package/src/bench/via-probe.js +1 -1
  17. package/src/bench/via.js +144 -144
  18. package/src/bench/workbuddy-bench.js +1 -1
  19. package/src/chat/config.js +11 -11
  20. package/src/chat/cooling.js +81 -81
  21. package/src/chat/direct.js +58 -58
  22. package/src/chat/index.js +6 -6
  23. package/src/chat/spinner.js +38 -38
  24. package/src/chat/sse.js +69 -69
  25. package/src/chat/stats.js +247 -247
  26. package/src/chat/store.js +48 -48
  27. package/src/chat/tool-handlers.js +67 -67
  28. package/src/chat/tools.js +1 -1
  29. package/src/chat/upstream.js +59 -59
  30. package/src/chat-pipeline/auto-race.js +158 -158
  31. package/src/chat-pipeline/empty-turn.js +147 -147
  32. package/src/chat-pipeline/engine.js +17 -17
  33. package/src/chat-pipeline/serial-trial.js +283 -283
  34. package/src/chat-pipeline/terminal-verdict.js +147 -147
  35. package/src/chooser.js +54 -54
  36. package/src/claude-desktop/apply.js +101 -101
  37. package/src/claude-desktop/context1m.js +38 -38
  38. package/src/claude-desktop/doctor.js +146 -146
  39. package/src/claude-desktop/slots.js +152 -152
  40. package/src/cli/bootstrap.js +1 -1
  41. package/src/cli/commands/claude-desktop.js +284 -284
  42. package/src/cli/commands/daemon.js +231 -231
  43. package/src/cli/commands/model/list-live.js +22 -22
  44. package/src/cli/commands/model/list-providers.js +76 -76
  45. package/src/cli/commands/model/list-render.js +77 -77
  46. package/src/cli/commands/model/list-sort.js +52 -52
  47. package/src/cli/commands/model/list-tty.js +76 -76
  48. package/src/cli/commands/model/list.js +166 -166
  49. package/src/cli/commands/model/live-models.js +24 -24
  50. package/src/cli/commands/model/stats.js +43 -43
  51. package/src/cli/commands/model/status.js +47 -47
  52. package/src/cli/commands/model.js +51 -51
  53. package/src/cli/commands/provider/add.js +108 -108
  54. package/src/cli/commands/provider/allowlist.js +99 -99
  55. package/src/cli/commands/provider/cline-free.js +99 -99
  56. package/src/cli/commands/provider/cline-login.js +218 -218
  57. package/src/cli/commands/provider/cline-quota.js +65 -65
  58. package/src/cli/commands/provider/codearts-login.js +45 -45
  59. package/src/cli/commands/provider/config.js +119 -119
  60. package/src/cli/commands/provider/globalqwenwork-login.js +126 -126
  61. package/src/cli/commands/provider/keys-guard.js +50 -50
  62. package/src/cli/commands/provider/keys.js +161 -161
  63. package/src/cli/commands/provider/qoder-checkin.js +81 -81
  64. package/src/cli/commands/provider/qoder-login.js +102 -102
  65. package/src/cli/commands/provider/raccoon-login.js +180 -180
  66. package/src/cli/commands/provider/raccoon-password.js +162 -162
  67. package/src/cli/commands/provider/raccoon-quota.js +109 -109
  68. package/src/cli/commands/provider/traework-checkin.js +144 -144
  69. package/src/cli/commands/provider/traework-login.js +164 -164
  70. package/src/cli/commands/provider/workbuddy-login.js +153 -153
  71. package/src/cli/commands/provider/zcode-login.js +77 -77
  72. package/src/cli/commands/provider/zcode-quota.js +55 -55
  73. package/src/cli/commands/provider.js +1 -1
  74. package/src/cli/commands/stats.js +149 -149
  75. package/src/cli/commands/system.js +261 -261
  76. package/src/cli/commands/timezone.js +47 -47
  77. package/src/cli/commands/use-group.js +60 -60
  78. package/src/cli/commands/workbuddy.js +189 -189
  79. package/src/cli/format.js +141 -141
  80. package/src/cli/group-helpers.js +70 -70
  81. package/src/cli/help.js +80 -80
  82. package/src/cli/index.js +70 -70
  83. package/src/cli/interactive.js +121 -121
  84. package/src/cli/join-core.js +99 -99
  85. package/src/cli/join-wizard.js +175 -175
  86. package/src/cli/policy.js +136 -136
  87. package/src/cli/provider-row.js +126 -126
  88. package/src/cli/util.js +24 -24
  89. package/src/compat.js +53 -53
  90. package/src/events.js +38 -38
  91. package/src/free-lane.js +131 -131
  92. package/src/free-watcher.js +63 -63
  93. package/src/groups.js +262 -262
  94. package/src/logs.js +195 -195
  95. package/src/metrics.js +62 -62
  96. package/src/model-capabilities/context-lookup.js +65 -65
  97. package/src/model-capabilities/merge.js +142 -142
  98. package/src/model-trace.js +187 -187
  99. package/src/models.js +1 -1
  100. package/src/opencode-identity.js +72 -72
  101. package/src/peers.js +254 -251
  102. package/src/plugins.js +107 -107
  103. package/src/providers/base.js +164 -164
  104. package/src/providers/classify.js +22 -22
  105. package/src/providers/cline/allowlist-sync.js +93 -93
  106. package/src/providers/cline/free-catalog.js +71 -71
  107. package/src/providers/cline/headers.js +37 -37
  108. package/src/providers/cline/index.js +130 -130
  109. package/src/providers/cline/models.js +150 -150
  110. package/src/providers/cline/usage.js +274 -274
  111. package/src/providers/codearts/auth-pool.js +148 -148
  112. package/src/providers/codearts/concurrency.js +34 -34
  113. package/src/providers/codearts/const.js +65 -65
  114. package/src/providers/codearts/dpop.js +95 -95
  115. package/src/providers/codearts/index.js +175 -175
  116. package/src/providers/codearts/login.js +214 -214
  117. package/src/providers/codearts/models.js +182 -182
  118. package/src/providers/codearts/sign.js +96 -96
  119. package/src/providers/codearts/sse.js +204 -204
  120. package/src/providers/codearts/stream.js +209 -209
  121. package/src/providers/codearts/sts.js +124 -124
  122. package/src/providers/codearts.js +1 -1
  123. package/src/providers/dispatcher.js +146 -146
  124. package/src/providers/generic.js +156 -156
  125. package/src/providers/globalqwenwork/account-store.js +141 -141
  126. package/src/providers/globalqwenwork/constants.js +73 -73
  127. package/src/providers/globalqwenwork/crypto.js +2 -2
  128. package/src/providers/globalqwenwork/http.js +2 -2
  129. package/src/providers/globalqwenwork/index.js +331 -331
  130. package/src/providers/globalqwenwork/payload.js +147 -147
  131. package/src/providers/globalqwenwork/rsa.js +2 -2
  132. package/src/providers/globalqwenwork/sse.js +2 -2
  133. package/src/providers/globalqwenwork/stream.js +2 -2
  134. package/src/providers/globalqwenwork.js +1 -1
  135. package/src/providers/globalworkbuddy/account-store.js +198 -198
  136. package/src/providers/globalworkbuddy/auth.js +97 -97
  137. package/src/providers/globalworkbuddy/catalog.js +138 -138
  138. package/src/providers/globalworkbuddy/constants.js +73 -73
  139. package/src/providers/globalworkbuddy/device-auth.js +120 -120
  140. package/src/providers/globalworkbuddy/errors.js +98 -98
  141. package/src/providers/globalworkbuddy/headers.js +89 -89
  142. package/src/providers/globalworkbuddy/models.js +96 -96
  143. package/src/providers/globalworkbuddy/payload.js +80 -80
  144. package/src/providers/index.js +5 -5
  145. package/src/providers/model-id.js +172 -172
  146. package/src/providers/opencode.js +19 -19
  147. package/src/providers/openrouter.js +31 -31
  148. package/src/providers/qoder/account-store.js +106 -106
  149. package/src/providers/qoder/aggregate.js +60 -60
  150. package/src/providers/qoder/baseprompt.json +591 -591
  151. package/src/providers/qoder/checkin.js +160 -160
  152. package/src/providers/qoder/constants.js +44 -44
  153. package/src/providers/qoder/encode.js +41 -41
  154. package/src/providers/qoder/fingerprint.js +38 -38
  155. package/src/providers/qoder/models.js +77 -77
  156. package/src/providers/qoder/oauth.js +84 -84
  157. package/src/providers/qoder/payload.js +162 -162
  158. package/src/providers/qoder/request.js +27 -27
  159. package/src/providers/qoder/session.js +134 -134
  160. package/src/providers/qoder/sticky.js +38 -38
  161. package/src/providers/qoder/stream.js +116 -116
  162. package/src/providers/qoder.js +1 -1
  163. package/src/providers/raccoon/account-store.js +216 -216
  164. package/src/providers/raccoon/auth.js +67 -67
  165. package/src/providers/raccoon/chat.js +228 -228
  166. package/src/providers/raccoon/const.js +180 -165
  167. package/src/providers/raccoon/credits.js +185 -175
  168. package/src/providers/raccoon/crypto.js +43 -0
  169. package/src/providers/raccoon/envelope.js +31 -31
  170. package/src/providers/raccoon/headers.js +45 -45
  171. package/src/providers/raccoon/index.js +216 -216
  172. package/src/providers/raccoon/login.js +279 -279
  173. package/src/providers/raccoon/models.js +160 -160
  174. package/src/providers/raccoon/password-login.js +102 -87
  175. package/src/providers/raccoon/qr-codewords.js +115 -115
  176. package/src/providers/raccoon/qr.js +236 -236
  177. package/src/providers/raccoon/sse.js +135 -135
  178. package/src/providers/responses-channel.js +120 -120
  179. package/src/providers/share-keys.js +53 -53
  180. package/src/providers/traework/account-store.js +234 -234
  181. package/src/providers/traework/chat.js +217 -217
  182. package/src/providers/traework/checkin.js +77 -77
  183. package/src/providers/traework/constants.js +41 -41
  184. package/src/providers/traework/errors.js +52 -52
  185. package/src/providers/traework/headers.js +79 -79
  186. package/src/providers/traework/index.js +132 -132
  187. package/src/providers/traework/market-identity.js +116 -116
  188. package/src/providers/traework/models.js +98 -98
  189. package/src/providers/traework/payload.js +86 -86
  190. package/src/providers/traework/sse.js +184 -184
  191. package/src/providers/traework/token.js +52 -52
  192. package/src/providers/traework.js +2 -2
  193. package/src/providers/workbuddy/account-store.js +186 -186
  194. package/src/providers/workbuddy/auth.js +158 -158
  195. package/src/providers/workbuddy/balance.js +86 -86
  196. package/src/providers/workbuddy/cat-travel.js +125 -125
  197. package/src/providers/workbuddy/checkin.js +75 -75
  198. package/src/providers/workbuddy/desktop-info.js +78 -78
  199. package/src/providers/workbuddy/growth-api.js +67 -67
  200. package/src/providers/workbuddy/growth-plans.js +63 -63
  201. package/src/providers/workbuddy/growth.js +181 -181
  202. package/src/providers/workbuddy/index.js +217 -217
  203. package/src/providers/workbuddy/models.js +126 -126
  204. package/src/providers/workbuddy/payload.js +141 -141
  205. package/src/providers/workbuddy/rotation-log.js +83 -83
  206. package/src/providers/workbuddy/sanitize-tools.js +61 -61
  207. package/src/providers/workbuddy/sdk-chat.js +26 -26
  208. package/src/providers/workbuddy-balance.js +78 -78
  209. package/src/providers/zcode/account-store.js +129 -129
  210. package/src/providers/zcode/auth.js +28 -28
  211. package/src/providers/zcode/chat.js +179 -179
  212. package/src/providers/zcode/const.js +54 -54
  213. package/src/providers/zcode/context-shape.js +162 -162
  214. package/src/providers/zcode/headers.js +93 -93
  215. package/src/providers/zcode/index.js +124 -124
  216. package/src/providers/zcode/models.js +65 -65
  217. package/src/providers/zcode/oauth.js +120 -120
  218. package/src/providers/zcode/quota.js +176 -176
  219. package/src/providers/zcode/sse.js +196 -196
  220. package/src/readline-compat.js +25 -25
  221. package/src/responses/translate.js +311 -311
  222. package/src/routes/chat/broadband-handler.js +72 -72
  223. package/src/routes/chat/empty-turn-report.js +31 -31
  224. package/src/routes/chat/exhausted-handler.js +87 -87
  225. package/src/routes/chat/hedge-handler.js +130 -130
  226. package/src/routes/chat/index.js +1 -1
  227. package/src/routes/chat/local-handler.js +63 -63
  228. package/src/routes/chat/peer-handler.js +81 -81
  229. package/src/routes/chat.js +3 -3
  230. package/src/routes/fallback.js +88 -88
  231. package/src/routes/groups-relay.js +214 -214
  232. package/src/routes/groups.js +122 -122
  233. package/src/routes/helpers.js +83 -83
  234. package/src/routes/index.js +147 -147
  235. package/src/routes/messages-route.js +365 -365
  236. package/src/routes/peers.js +23 -1
  237. package/src/routes/relay-queue.js +181 -181
  238. package/src/routes/relay.js +60 -60
  239. package/src/routes/responses-route.js +213 -213
  240. package/src/routes/stream-body.js +84 -84
  241. package/src/routes/stream-hold.js +337 -337
  242. package/src/routes/stream-scan.js +366 -366
  243. package/src/routes.js +3 -3
  244. package/src/runtime/auto-update.js +113 -113
  245. package/src/runtime/bootstrap.js +8 -0
  246. package/src/runtime/broadband-stream.js +79 -79
  247. package/src/runtime/broadband.js +103 -103
  248. package/src/runtime/group-sync.js +81 -81
  249. package/src/runtime/keep-warm.js +120 -0
  250. package/src/runtime/lifecycle-forensics.js +116 -116
  251. package/src/runtime/lifecycle-log.js +87 -87
  252. package/src/runtime/log-stamp.js +73 -73
  253. package/src/runtime/proc-info.js +137 -137
  254. package/src/runtime/qoder-checkin.js +93 -93
  255. package/src/runtime/raccoon-checkin.js +126 -126
  256. package/src/runtime/server-lifecycle.js +189 -189
  257. package/src/runtime/traework-checkin.js +118 -118
  258. package/src/runtime/workbuddy-checkin.js +120 -120
  259. package/src/runtime/workbuddy-growth.js +133 -133
  260. package/src/server.js +7 -0
  261. package/src/state/facade.js +58 -58
  262. package/src/state/memory.js +162 -162
  263. package/src/state/merge.js +25 -25
  264. package/src/state/migrations/cline-unify.js +94 -94
  265. package/src/state/migrations.js +33 -33
  266. package/src/state/persist.js +42 -42
  267. package/src/state/provider-config.js +142 -142
  268. package/src/state/schemas/group.js +31 -31
  269. package/src/state/schemas/model.js +94 -94
  270. package/src/state/schemas/peer.js +31 -31
  271. package/src/state/schemas/port.js +10 -10
  272. package/src/state/schemas/provider.js +202 -202
  273. package/src/state/schemas/timezone.js +70 -70
  274. package/src/state/schemas/token.js +48 -48
  275. package/src/state/schemas/use-group.js +102 -102
  276. package/src/state/store.js +176 -176
  277. package/src/state.js +1 -1
  278. package/src/sync-claude-desktop.js +234 -234
  279. package/src/sync-claude.js +152 -152
  280. package/src/sync-codex.js +116 -116
  281. package/src/sync-workbuddy.js +158 -158
  282. package/src/talk-full-redact.js +129 -129
  283. package/src/talk-full.js +131 -131
  284. package/src/talk-log.js +257 -257
  285. package/src/text-tokens.js +52 -52
  286. package/src/thinking-effort.js +67 -67
  287. package/src/time.js +106 -106
  288. package/src/timeline.js +26 -26
  289. package/src/transport/index.js +1 -1
  290. package/src/upstream-engine/index.js +74 -72
  291. package/src/upstream-engine/mode.js +15 -15
  292. package/src/upstream-engine/sdk/attempt.js +221 -221
  293. package/src/upstream-engine/sdk/chat.js +28 -28
  294. package/src/upstream-engine/sdk/convert.js +192 -192
  295. package/src/upstream-engine/sdk/diagnose.js +62 -62
  296. package/src/upstream-engine/sdk/dispatch.js +55 -55
  297. package/src/upstream-engine/sdk/responses.js +176 -176
  298. package/src/upstream-engine/sdk/sse.js +166 -166
  299. package/src/upstream-responses.js +305 -305
  300. package/src/upstream.js +53 -1
  301. package/src/usage/record.js +106 -106
  302. package/src/usage/report.js +195 -195
  303. package/src/v6pool/claim.js +157 -157
  304. package/src/v6pool/config.js +65 -65
  305. package/src/v6pool/detect.js +130 -130
  306. package/src/v6pool/index.js +152 -152
  307. package/src/v6pool/prefix.js +140 -140
  308. package/src/v6pool/probe.js +40 -40
  309. package/src/v6pool/report.js +104 -104
  310. package/src/v6pool/rotate.js +263 -239
  311. package/src/warp-pool/config.js +74 -74
  312. package/src/warp-pool/health.js +106 -106
  313. package/src/warp-pool/identity.js +141 -141
  314. package/src/warp-pool/index.js +358 -358
  315. package/src/warp-pool/keys.js +29 -29
  316. package/src/warp-pool/nodes.js +95 -95
  317. package/src/warp-pool/ports.js +160 -160
  318. package/src/warp-pool/register.js +113 -113
  319. package/src/warp-pool/report.js +232 -232
  320. package/src/warp-pool/revive.js +168 -168
  321. package/src/warp-pool/rotate.js +214 -214
  322. package/src/warp-pool/strategy.js +43 -43
  323. package/src/warp-pool/verdict.js +69 -69
  324. package/src/warp-pool/wireproxy.js +162 -162
  325. package/docs/cli_help_mini.md +0 -146
  326. package/src/providers/AGENTS.md +0 -49
  327. package/src/routes/AGENTS.md +0 -37
@@ -1,162 +1,162 @@
1
- // mslxdff -provider raccoon login --password —— 手机号 + 密码登录(多账号免扫码)。
2
- //
3
- // 为什么需要它:扫码登录一次只能加一个号,且要手机在手边;密码登录可以在同一个终端里
4
- // 连着把多个号加完(脚本化也行),是「批量补号」的正路。
5
- //
6
- // 安全:密码**只经手本进程内存**,绝不落盘、绝不打印、绝不进 argv(除非用户显式 `--password=xxx`,
7
- // 那种情况会在回执里提示一次「密码已进 shell 历史」)。落盘的是 token,与扫码登录同一条路。
8
- import { compatFetch } from "../../../compat.js";
9
- import { loginRaccoonWithPassword, normalizePhone } from "../../../providers/raccoon/password-login.js";
10
- import { finishRaccoonLogin } from "./raccoon-login.js";
11
-
12
- const RELOGIN_HINT = " (可重试:mslxdff -provider raccoon login --password)";
13
-
14
- /**
15
- * 从 rest 里取 `--key=value` 或 `--key value` 两种写法。
16
- * **裸旗标(无值)返回 undefined**,不是空串 —— 这样 `?? deps.x` 才能正常回落,
17
- * 否则 `"" ?? deps.x` 恒取空串,把「只写了 --password 想让程序询问」误判成「显式给了空密码」。
18
- */
19
- function flagValue(rest, ...names) {
20
- for (let i = 0; i < rest.length; i++) {
21
- const cur = String(rest[i]);
22
- for (const name of names) {
23
- if (cur === name) {
24
- const next = rest[i + 1];
25
- return typeof next === "string" && next.length > 0 && !next.startsWith("-") ? next : undefined;
26
- }
27
- if (cur.startsWith(`${name}=`)) {
28
- const v = cur.slice(name.length + 1);
29
- return v.length > 0 ? v : undefined;
30
- }
31
- }
32
- }
33
- return undefined;
34
- }
35
-
36
- /**
37
- * TTY 隐藏输入:**不碰 readline**(它会自己接管 stdin 的原始模式,与我们抢同一份字节),
38
- * 直接开 raw mode 逐字符读,每个键回显一个 `*` 给出「确实收到了」的可见反馈。
39
- * 非 TTY 返回 null(由调用方转成「必须用 flag」的指引,绝不从管道偷读)。
40
- */
41
- async function promptHidden(label) {
42
- if (!process.stdin.isTTY || !process.stdout.isTTY) return null;
43
- return await new Promise((resolve) => {
44
- const wasRaw = Boolean(process.stdin.isRaw);
45
- let buf = "";
46
- const done = (value) => {
47
- process.stdin.removeListener("data", onData);
48
- try { process.stdin.setRawMode(wasRaw); } catch {}
49
- process.stdin.pause();
50
- process.stdout.write("\n");
51
- resolve(value);
52
- };
53
- const onData = (chunk) => {
54
- for (const ch of String(chunk)) {
55
- if (ch === "\r" || ch === "\n") return done(buf);
56
- if (ch === "\u0003") return done(null); // Ctrl-C
57
- if (ch === "\u007f" || ch === "\b") { // 退格
58
- if (buf.length > 0) { buf = buf.slice(0, -1); process.stdout.write("\b \b"); }
59
- continue;
60
- }
61
- if (ch < " ") continue; // 忽略其余控制字符
62
- buf += ch;
63
- process.stdout.write("*");
64
- }
65
- };
66
- process.stdout.write(label);
67
- try { process.stdin.setRawMode(true); } catch {}
68
- process.stdin.resume();
69
- process.stdin.setEncoding("utf8");
70
- process.stdin.on("data", onData);
71
- });
72
- }
73
-
74
- async function promptVisible(label) {
75
- if (!process.stdin.isTTY || !process.stdout.isTTY) return null;
76
- const { createInterface } = await import("../../../readline-compat.js");
77
- const rl = createInterface({ input: process.stdin, output: process.stdout, terminal: true });
78
- try {
79
- return await rl.question(label);
80
- } finally {
81
- rl.close();
82
- }
83
- }
84
-
85
- export async function handleRaccoonPasswordLogin(id, sub, rest = [], deps = {}) {
86
- const fetchImpl = deps.fetchImpl || compatFetch;
87
- const log = deps.log || ((m) => console.log(m));
88
- const exit = deps.exit || ((code) => process.exit(code));
89
-
90
- log("=".repeat(60));
91
- log(" Raccoon 登录(商汤小浣熊 · 手机号 + 密码)");
92
- log("=".repeat(60));
93
- log("");
94
-
95
- let phone = flagValue(rest, "--phone") ?? deps.phone;
96
- // `--password` 既是「模式开关」也可携带值:`--password`(裸)→ 交互询问,`--password=xxx` → 直接用。
97
- let password = flagValue(rest, "--password", "-p") ?? deps.password;
98
- const nationCode = flagValue(rest, "--nation", "--nation-code", "--area") || deps.nationCode || "86";
99
-
100
- if (!phone) {
101
- const asked = await promptVisible(" 手机号: ");
102
- if (asked === null) {
103
- log("❌ 非交互环境(非 TTY)无法询问手机号 —— 请用 --phone 传入");
104
- log(RELOGIN_HINT);
105
- exit(1);
106
- return true;
107
- }
108
- phone = asked;
109
- }
110
- const cleanPhone = normalizePhone(phone);
111
- if (!cleanPhone) {
112
- log("❌ 手机号不能为空(只填数字即可)");
113
- log(RELOGIN_HINT);
114
- exit(1);
115
- return true;
116
- }
117
-
118
- if (!password) {
119
- const asked = await promptHidden(" 密码(输入不回显): ");
120
- if (asked === null) {
121
- log("❌ 非交互环境(非 TTY)无法安全询问密码 —— 请用 --password 传入");
122
- log(RELOGIN_HINT);
123
- exit(1);
124
- return true;
125
- }
126
- password = asked;
127
- }
128
-
129
- if (String(password || "").length === 0) {
130
- log("❌ 密码不能为空");
131
- log(RELOGIN_HINT);
132
- exit(1);
133
- return true;
134
- }
135
-
136
- log("🔐 正在登录…");
137
- let credential;
138
- try {
139
- credential = await loginRaccoonWithPassword(
140
- { phone: cleanPhone, password, nationCode },
141
- { fetchImpl, env: deps.env },
142
- );
143
- } catch (error) {
144
- log("");
145
- log(`❌ 登录失败:${error?.message ?? error}`);
146
- log(RELOGIN_HINT);
147
- exit(1);
148
- return true;
149
- }
150
-
151
- // 密码已用完,立刻从本进程的作用域里抹掉(降内存残留;不是安全边界,是习惯)
152
- password = undefined;
153
-
154
- const masked = cleanPhone.length > 4 ? `${"*".repeat(cleanPhone.length - 4)}${cleanPhone.slice(-4)}` : cleanPhone;
155
- return await finishRaccoonLogin({
156
- credential,
157
- fetchImpl,
158
- deps,
159
- log,
160
- methodNote: ` 登录方式: 密码登录(手机号 ${masked})`,
161
- });
162
- }
1
+ // mslxdff -provider raccoon login --password —— 手机号 + 密码登录(多账号免扫码)。
2
+ //
3
+ // 为什么需要它:扫码登录一次只能加一个号,且要手机在手边;密码登录可以在同一个终端里
4
+ // 连着把多个号加完(脚本化也行),是「批量补号」的正路。
5
+ //
6
+ // 安全:密码**只经手本进程内存**,绝不落盘、绝不打印、绝不进 argv(除非用户显式 `--password=xxx`,
7
+ // 那种情况会在回执里提示一次「密码已进 shell 历史」)。落盘的是 token,与扫码登录同一条路。
8
+ import { compatFetch } from "../../../compat.js";
9
+ import { loginRaccoonWithPassword, normalizePhone } from "../../../providers/raccoon/password-login.js";
10
+ import { finishRaccoonLogin } from "./raccoon-login.js";
11
+
12
+ const RELOGIN_HINT = " (可重试:mslxdff -provider raccoon login --password)";
13
+
14
+ /**
15
+ * 从 rest 里取 `--key=value` 或 `--key value` 两种写法。
16
+ * **裸旗标(无值)返回 undefined**,不是空串 —— 这样 `?? deps.x` 才能正常回落,
17
+ * 否则 `"" ?? deps.x` 恒取空串,把「只写了 --password 想让程序询问」误判成「显式给了空密码」。
18
+ */
19
+ function flagValue(rest, ...names) {
20
+ for (let i = 0; i < rest.length; i++) {
21
+ const cur = String(rest[i]);
22
+ for (const name of names) {
23
+ if (cur === name) {
24
+ const next = rest[i + 1];
25
+ return typeof next === "string" && next.length > 0 && !next.startsWith("-") ? next : undefined;
26
+ }
27
+ if (cur.startsWith(`${name}=`)) {
28
+ const v = cur.slice(name.length + 1);
29
+ return v.length > 0 ? v : undefined;
30
+ }
31
+ }
32
+ }
33
+ return undefined;
34
+ }
35
+
36
+ /**
37
+ * TTY 隐藏输入:**不碰 readline**(它会自己接管 stdin 的原始模式,与我们抢同一份字节),
38
+ * 直接开 raw mode 逐字符读,每个键回显一个 `*` 给出「确实收到了」的可见反馈。
39
+ * 非 TTY 返回 null(由调用方转成「必须用 flag」的指引,绝不从管道偷读)。
40
+ */
41
+ async function promptHidden(label) {
42
+ if (!process.stdin.isTTY || !process.stdout.isTTY) return null;
43
+ return await new Promise((resolve) => {
44
+ const wasRaw = Boolean(process.stdin.isRaw);
45
+ let buf = "";
46
+ const done = (value) => {
47
+ process.stdin.removeListener("data", onData);
48
+ try { process.stdin.setRawMode(wasRaw); } catch {}
49
+ process.stdin.pause();
50
+ process.stdout.write("\n");
51
+ resolve(value);
52
+ };
53
+ const onData = (chunk) => {
54
+ for (const ch of String(chunk)) {
55
+ if (ch === "\r" || ch === "\n") return done(buf);
56
+ if (ch === "\u0003") return done(null); // Ctrl-C
57
+ if (ch === "\u007f" || ch === "\b") { // 退格
58
+ if (buf.length > 0) { buf = buf.slice(0, -1); process.stdout.write("\b \b"); }
59
+ continue;
60
+ }
61
+ if (ch < " ") continue; // 忽略其余控制字符
62
+ buf += ch;
63
+ process.stdout.write("*");
64
+ }
65
+ };
66
+ process.stdout.write(label);
67
+ try { process.stdin.setRawMode(true); } catch {}
68
+ process.stdin.resume();
69
+ process.stdin.setEncoding("utf8");
70
+ process.stdin.on("data", onData);
71
+ });
72
+ }
73
+
74
+ async function promptVisible(label) {
75
+ if (!process.stdin.isTTY || !process.stdout.isTTY) return null;
76
+ const { createInterface } = await import("../../../readline-compat.js");
77
+ const rl = createInterface({ input: process.stdin, output: process.stdout, terminal: true });
78
+ try {
79
+ return await rl.question(label);
80
+ } finally {
81
+ rl.close();
82
+ }
83
+ }
84
+
85
+ export async function handleRaccoonPasswordLogin(id, sub, rest = [], deps = {}) {
86
+ const fetchImpl = deps.fetchImpl || compatFetch;
87
+ const log = deps.log || ((m) => console.log(m));
88
+ const exit = deps.exit || ((code) => process.exit(code));
89
+
90
+ log("=".repeat(60));
91
+ log(" Raccoon 登录(商汤小浣熊 · 手机号 + 密码)");
92
+ log("=".repeat(60));
93
+ log("");
94
+
95
+ let phone = flagValue(rest, "--phone") ?? deps.phone;
96
+ // `--password` 既是「模式开关」也可携带值:`--password`(裸)→ 交互询问,`--password=xxx` → 直接用。
97
+ let password = flagValue(rest, "--password", "-p") ?? deps.password;
98
+ const nationCode = flagValue(rest, "--nation", "--nation-code", "--area") || deps.nationCode || "86";
99
+
100
+ if (!phone) {
101
+ const asked = await promptVisible(" 手机号: ");
102
+ if (asked === null) {
103
+ log("❌ 非交互环境(非 TTY)无法询问手机号 —— 请用 --phone 传入");
104
+ log(RELOGIN_HINT);
105
+ exit(1);
106
+ return true;
107
+ }
108
+ phone = asked;
109
+ }
110
+ const cleanPhone = normalizePhone(phone);
111
+ if (!cleanPhone) {
112
+ log("❌ 手机号不能为空(只填数字即可)");
113
+ log(RELOGIN_HINT);
114
+ exit(1);
115
+ return true;
116
+ }
117
+
118
+ if (!password) {
119
+ const asked = await promptHidden(" 密码(输入不回显): ");
120
+ if (asked === null) {
121
+ log("❌ 非交互环境(非 TTY)无法安全询问密码 —— 请用 --password 传入");
122
+ log(RELOGIN_HINT);
123
+ exit(1);
124
+ return true;
125
+ }
126
+ password = asked;
127
+ }
128
+
129
+ if (String(password || "").length === 0) {
130
+ log("❌ 密码不能为空");
131
+ log(RELOGIN_HINT);
132
+ exit(1);
133
+ return true;
134
+ }
135
+
136
+ log("🔐 正在登录…");
137
+ let credential;
138
+ try {
139
+ credential = await loginRaccoonWithPassword(
140
+ { phone: cleanPhone, password, nationCode },
141
+ { fetchImpl, env: deps.env },
142
+ );
143
+ } catch (error) {
144
+ log("");
145
+ log(`❌ 登录失败:${error?.message ?? error}`);
146
+ log(RELOGIN_HINT);
147
+ exit(1);
148
+ return true;
149
+ }
150
+
151
+ // 密码已用完,立刻从本进程的作用域里抹掉(降内存残留;不是安全边界,是习惯)
152
+ password = undefined;
153
+
154
+ const masked = cleanPhone.length > 4 ? `${"*".repeat(cleanPhone.length - 4)}${cleanPhone.slice(-4)}` : cleanPhone;
155
+ return await finishRaccoonLogin({
156
+ credential,
157
+ fetchImpl,
158
+ deps,
159
+ log,
160
+ methodNote: ` 登录方式: 密码登录(手机号 ${masked})`,
161
+ });
162
+ }
@@ -1,109 +1,109 @@
1
- // mslxdff -provider raccoon quota — 逐号查积分余额(五分项)
2
- // mslxdff -provider raccoon checkin — 领「桌面端登录奖励」
3
- // ⚠ 纠偏(2026-10-10 账单实测):这家**没有每日签到**。三种积分来源里只有登录奖励 3000 需要领,
4
- // 且**每号一次性**;每日 300 与注册礼包 3000 都由服务端自动发(无端点),每日 300 当天 23:59:59 清零。
5
- // 判据一律走账单:上游对重复领取照样回 code:0,只信回执就会谎报到账。
6
- import { normalizeProviderId } from "../../../providers/model-id.js";
7
- import { compatFetch } from "../../../compat.js";
8
- import { listRaccoonAccountDocs, raccoonCredentialFromDoc } from "../../../providers/raccoon/account-store.js";
9
- import { claimRaccoonLoginReward, fetchRaccoonBalance, raccoonClaimStatus } from "../../../providers/raccoon/credits.js";
10
- import { raccoonTokenFingerprint } from "../../../providers/raccoon/auth.js";
11
-
12
- const SUBS = new Set(["quota", "credits", "balance", "checkin", "signin"]);
13
-
14
- /** 逐号列出(旧实现只取 docs[0],多号时会漏看余额、漏领一次性礼包)。 */
15
- function targets(deps) {
16
- if (deps.credential) return [{ name: "", credential: deps.credential }];
17
- return listRaccoonAccountDocs(deps.dir ? { dirs: [deps.dir] } : {})
18
- .filter((d) => d.accessToken)
19
- .map((d) => ({ name: d.name || "", credential: raccoonCredentialFromDoc(d) }));
20
- }
21
-
22
- const STATUS_LINE = {
23
- claimed: (r) => `🎁 已领取 +${r.points} 分 —— 账单已确认入账(每号仅此一次)`,
24
- already: () => `已领过 —— 每号只有一次,没有"明天再来"这回事`,
25
- phantom: () => `⚠ 上游回执「成功」但账单里查不到这笔 → 判定未到账,别当领过`,
26
- unverified: () => `已提交,但账单暂时查不到 → 未确认,稍后用 quota 核对`,
27
- error: (r) => `❌ 领取失败:${r.msg || "未知原因"}`,
28
- };
29
-
30
- // row.account 在构造时已换成 token 指纹(凭据纪律:CLI 只打指纹,绝不打完整 token)
31
- const label = (row) => `[${row.account}${row.uid ? " · " + row.uid : ""}]`;
32
-
33
- function expiredHint(error) {
34
- return error?.authExpired || error?.status === 401 || error?.code === 200001 || error?.code === 200003
35
- ? "登录态已失效(access_token 只有约 3 小时寿命),重新扫码: mslxdff -provider raccoon login"
36
- : "";
37
- }
38
-
39
- export async function handleRaccoonQuota(id, sub, rest = [], deps = {}) {
40
- const pid = normalizeProviderId(id) || String(id || "").toLowerCase();
41
- if (pid !== "raccoon") return false;
42
- if (!SUBS.has(sub)) return false;
43
-
44
- const fetchImpl = deps.fetchImpl || compatFetch;
45
- const log = deps.log || ((m) => console.log(m));
46
- const exit = deps.exit || ((code) => process.exit(code));
47
- const json = rest.includes("--json");
48
- const isCheckin = sub === "checkin" || sub === "signin";
49
- const list = targets(deps);
50
-
51
- if (!list.length) {
52
- if (json) log(JSON.stringify({ error: "not_logged_in", hint: "mslxdff -provider raccoon login" }));
53
- else {
54
- log("未登录:还没有可用的 raccoon 账号");
55
- log(" 先运行: mslxdff -provider raccoon login(登录时会自动领一次性登录奖励)");
56
- }
57
- exit(1);
58
- return true;
59
- }
60
-
61
- const rows = [];
62
- for (const t of list) {
63
- const base = { account: raccoonTokenFingerprint(t.credential.access_token), uid: t.credential.uid, name: t.name };
64
- try {
65
- if (isCheckin) {
66
- const r = await claimRaccoonLoginReward({ credential: t.credential, fetchImpl, env: deps.env });
67
- const status = raccoonClaimStatus(r);
68
- rows.push({ ...base, ok: status === "claimed" || status === "already", status, points: r.points });
69
- } else {
70
- const b = await fetchRaccoonBalance({ credential: t.credential, fetchImpl, env: deps.env });
71
- rows.push({ ...base, ok: true, total: b.total, items: b.items });
72
- }
73
- } catch (e) {
74
- rows.push({ ...base, ok: false, status: "error", msg: String(e?.message ?? e).slice(0, 160), relogin: expiredHint(e) });
75
- }
76
- }
77
- const failed = rows.filter((r) => !r.ok).length;
78
-
79
- if (json) {
80
- log(JSON.stringify({ accounts: rows, ok: rows.length - failed, total: rows.length }));
81
- exit(failed === rows.length ? 1 : 0);
82
- return true;
83
- }
84
-
85
- if (isCheckin) {
86
- log(`raccoon 登录奖励(每号一次性)· 共 ${rows.length} 个号`);
87
- for (const r of rows) log(` ${label(r)} ${STATUS_LINE[r.status]?.(r) || r.status}`);
88
- if (rows.some((r) => r.status === "claimed")) log(` 查看余额: mslxdff -provider raccoon quota`);
89
- exit(failed === rows.length ? 1 : 0);
90
- return true;
91
- }
92
-
93
- log(`raccoon 积分 · 共 ${rows.length} 个号`);
94
- for (const r of rows) {
95
- if (!r.ok) {
96
- log(` ${label(r)} ❌ ${r.msg}`);
97
- if (r.relogin) log(` → ${r.relogin}`);
98
- continue;
99
- }
100
- const detail = r.items.length ? r.items.map((i) => `${i.label} ${i.value}`).join(" · ") : "(上游未返回分项明细)";
101
- log(` ${label(r)} 可用 ${r.total} ${detail}`);
102
- }
103
- log("");
104
- log(" ⚠ 「每日积分」当天 23:59:59 清零,当天不花就作废;奖励/充值积分不过期。上游按倍率自动先扣当日池。");
105
- log(" ⚠ 倍率 0 的模型不扣积分(`mslxdff -provider raccoon models` 看倍率列),想省积分优先用它们。");
106
- log(" 登录奖励每号只有一次,登录时已自动领;本命令的 checkin 只是补领兜底。");
107
- exit(failed === rows.length ? 1 : 0);
108
- return true;
109
- }
1
+ // mslxdff -provider raccoon quota — 逐号查积分余额(五分项)
2
+ // mslxdff -provider raccoon checkin — 领「桌面端登录奖励」
3
+ // ⚠ 纠偏(2026-10-10 账单实测):这家**没有每日签到**。三种积分来源里只有登录奖励 3000 需要领,
4
+ // 且**每号一次性**;每日 300 与注册礼包 3000 都由服务端自动发(无端点),每日 300 当天 23:59:59 清零。
5
+ // 判据一律走账单:上游对重复领取照样回 code:0,只信回执就会谎报到账。
6
+ import { normalizeProviderId } from "../../../providers/model-id.js";
7
+ import { compatFetch } from "../../../compat.js";
8
+ import { listRaccoonAccountDocs, raccoonCredentialFromDoc } from "../../../providers/raccoon/account-store.js";
9
+ import { claimRaccoonLoginReward, fetchRaccoonBalance, raccoonClaimStatus } from "../../../providers/raccoon/credits.js";
10
+ import { raccoonTokenFingerprint } from "../../../providers/raccoon/auth.js";
11
+
12
+ const SUBS = new Set(["quota", "credits", "balance", "checkin", "signin"]);
13
+
14
+ /** 逐号列出(旧实现只取 docs[0],多号时会漏看余额、漏领一次性礼包)。 */
15
+ function targets(deps) {
16
+ if (deps.credential) return [{ name: "", credential: deps.credential }];
17
+ return listRaccoonAccountDocs(deps.dir ? { dirs: [deps.dir] } : {})
18
+ .filter((d) => d.accessToken)
19
+ .map((d) => ({ name: d.name || "", credential: raccoonCredentialFromDoc(d) }));
20
+ }
21
+
22
+ const STATUS_LINE = {
23
+ claimed: (r) => `🎁 已领取 +${r.points} 分 —— 账单已确认入账(每号仅此一次)`,
24
+ already: () => `已领过 —— 每号只有一次,没有"明天再来"这回事`,
25
+ phantom: () => `⚠ 上游回执「成功」但账单里查不到这笔 → 判定未到账,别当领过`,
26
+ unverified: () => `已提交,但账单暂时查不到 → 未确认,稍后用 quota 核对`,
27
+ error: (r) => `❌ 领取失败:${r.msg || "未知原因"}`,
28
+ };
29
+
30
+ // row.account 在构造时已换成 token 指纹(凭据纪律:CLI 只打指纹,绝不打完整 token)
31
+ const label = (row) => `[${row.account}${row.uid ? " · " + row.uid : ""}]`;
32
+
33
+ function expiredHint(error) {
34
+ return error?.authExpired || error?.status === 401 || error?.code === 200001 || error?.code === 200003
35
+ ? "登录态已失效(access_token 只有约 3 小时寿命),重新扫码: mslxdff -provider raccoon login"
36
+ : "";
37
+ }
38
+
39
+ export async function handleRaccoonQuota(id, sub, rest = [], deps = {}) {
40
+ const pid = normalizeProviderId(id) || String(id || "").toLowerCase();
41
+ if (pid !== "raccoon") return false;
42
+ if (!SUBS.has(sub)) return false;
43
+
44
+ const fetchImpl = deps.fetchImpl || compatFetch;
45
+ const log = deps.log || ((m) => console.log(m));
46
+ const exit = deps.exit || ((code) => process.exit(code));
47
+ const json = rest.includes("--json");
48
+ const isCheckin = sub === "checkin" || sub === "signin";
49
+ const list = targets(deps);
50
+
51
+ if (!list.length) {
52
+ if (json) log(JSON.stringify({ error: "not_logged_in", hint: "mslxdff -provider raccoon login" }));
53
+ else {
54
+ log("未登录:还没有可用的 raccoon 账号");
55
+ log(" 先运行: mslxdff -provider raccoon login(登录时会自动领一次性登录奖励)");
56
+ }
57
+ exit(1);
58
+ return true;
59
+ }
60
+
61
+ const rows = [];
62
+ for (const t of list) {
63
+ const base = { account: raccoonTokenFingerprint(t.credential.access_token), uid: t.credential.uid, name: t.name };
64
+ try {
65
+ if (isCheckin) {
66
+ const r = await claimRaccoonLoginReward({ credential: t.credential, fetchImpl, env: deps.env });
67
+ const status = raccoonClaimStatus(r);
68
+ rows.push({ ...base, ok: status === "claimed" || status === "already", status, points: r.points });
69
+ } else {
70
+ const b = await fetchRaccoonBalance({ credential: t.credential, fetchImpl, env: deps.env });
71
+ rows.push({ ...base, ok: true, total: b.total, items: b.items });
72
+ }
73
+ } catch (e) {
74
+ rows.push({ ...base, ok: false, status: "error", msg: String(e?.message ?? e).slice(0, 160), relogin: expiredHint(e) });
75
+ }
76
+ }
77
+ const failed = rows.filter((r) => !r.ok).length;
78
+
79
+ if (json) {
80
+ log(JSON.stringify({ accounts: rows, ok: rows.length - failed, total: rows.length }));
81
+ exit(failed === rows.length ? 1 : 0);
82
+ return true;
83
+ }
84
+
85
+ if (isCheckin) {
86
+ log(`raccoon 登录奖励(每号一次性)· 共 ${rows.length} 个号`);
87
+ for (const r of rows) log(` ${label(r)} ${STATUS_LINE[r.status]?.(r) || r.status}`);
88
+ if (rows.some((r) => r.status === "claimed")) log(` 查看余额: mslxdff -provider raccoon quota`);
89
+ exit(failed === rows.length ? 1 : 0);
90
+ return true;
91
+ }
92
+
93
+ log(`raccoon 积分 · 共 ${rows.length} 个号`);
94
+ for (const r of rows) {
95
+ if (!r.ok) {
96
+ log(` ${label(r)} ❌ ${r.msg}`);
97
+ if (r.relogin) log(` → ${r.relogin}`);
98
+ continue;
99
+ }
100
+ const detail = r.items.length ? r.items.map((i) => `${i.label} ${i.value}`).join(" · ") : "(上游未返回分项明细)";
101
+ log(` ${label(r)} 可用 ${r.total} ${detail}`);
102
+ }
103
+ log("");
104
+ log(" ⚠ 「每日积分」当天 23:59:59 清零,当天不花就作废;奖励/充值积分不过期。上游按倍率自动先扣当日池。");
105
+ log(" ⚠ 倍率 0 的模型不扣积分(`mslxdff -provider raccoon models` 看倍率列),想省积分优先用它们。");
106
+ log(" 登录奖励每号只有一次,登录时已自动领;本命令的 checkin 只是补领兜底。");
107
+ exit(failed === rows.length ? 1 : 0);
108
+ return true;
109
+ }