mslxdff 0.1.200 → 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 (326) 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 -74
  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/usage/record.js +106 -106
  301. package/src/usage/report.js +195 -195
  302. package/src/v6pool/claim.js +157 -157
  303. package/src/v6pool/config.js +65 -65
  304. package/src/v6pool/detect.js +130 -130
  305. package/src/v6pool/index.js +152 -152
  306. package/src/v6pool/prefix.js +140 -140
  307. package/src/v6pool/probe.js +40 -40
  308. package/src/v6pool/report.js +104 -104
  309. package/src/v6pool/rotate.js +263 -263
  310. package/src/warp-pool/config.js +74 -74
  311. package/src/warp-pool/health.js +106 -106
  312. package/src/warp-pool/identity.js +141 -141
  313. package/src/warp-pool/index.js +358 -358
  314. package/src/warp-pool/keys.js +29 -29
  315. package/src/warp-pool/nodes.js +95 -95
  316. package/src/warp-pool/ports.js +160 -160
  317. package/src/warp-pool/register.js +113 -113
  318. package/src/warp-pool/report.js +232 -232
  319. package/src/warp-pool/revive.js +168 -168
  320. package/src/warp-pool/rotate.js +214 -214
  321. package/src/warp-pool/strategy.js +43 -43
  322. package/src/warp-pool/verdict.js +69 -69
  323. package/src/warp-pool/wireproxy.js +162 -162
  324. package/docs/cli_help_mini.md +0 -146
  325. package/src/providers/AGENTS.md +0 -49
  326. package/src/routes/AGENTS.md +0 -37
@@ -1,103 +1,103 @@
1
- // mslxdff -provider qoder login — Qoder 设备授权(PKCE + poll),对齐 cline-login/traework-login。
2
- // 授权后落盘 auths/qoder-<uid>.json + state.json,完成后进程退出。
3
- import { compatFetch, timeoutSignal } from "../../../compat.js";
4
- import { normalizeProviderId } from "../../../providers/model-id.js";
5
- import { pkce, hex16, buildLoginUrl, waitForAuth, fetchUserInfo } from "../../../providers/qoder/oauth.js";
6
-
7
- const REGIONS = ["global", "cn"];
8
-
9
- export async function handleQoderLogin(id, sub, rest = [], deps = {}) {
10
- if (normalizeProviderId(id) !== "qoder") return false;
11
- if (sub !== "login" && sub !== "auth" && sub !== "oauth") return false;
12
- const fetchImpl = deps.fetchImpl || compatFetch;
13
- const log = deps.log || ((m) => console.log(m));
14
-
15
- // 可选参数:--region cn 或 --region global(默认 global)
16
- const regionIdx = rest.indexOf("--region") >= 0 ? rest.indexOf("--region") : rest.indexOf("-r");
17
- const region = regionIdx >= 0 ? String(rest[regionIdx + 1] || "global").trim() : "global";
18
- const normRegion = region === "cn" ? "cn" : "global";
19
-
20
- const { verifier, challenge } = pkce();
21
- const nonce = hex16();
22
- const loginUrl = buildLoginUrl({ region: normRegion, nonce, challenge });
23
-
24
- log("=".repeat(60));
25
- log(" Qoder 登录");
26
- log(` Region: ${normRegion === "cn" ? "中国站 (qoder.com.cn)" : "国际站 (qoder.com)"}`);
27
- log("=".repeat(60));
28
- log("");
29
- log(" 1. 在浏览器打开下面链接,用 Qoder 账号登录(OAuth 授权)");
30
- log(" 2. 登录成功后会自动完成授权,请等待回显");
31
- log("");
32
- log(` ${loginUrl}`);
33
- log("");
34
- log("🔄 等待你授权(自动轮询,每 3 秒,最多 10 分钟)...");
35
-
36
- let bundle;
37
- try {
38
- bundle = await waitForAuth({ region: normRegion, nonce, verifier, fetchImpl, log });
39
- } catch (e) {
40
- console.error(`\n❌ ${e.message}`);
41
- process.exit(1);
42
- }
43
- if (!bundle || !bundle.deviceToken) {
44
- console.error("\n❌ 未获取到 device token");
45
- process.exit(1);
46
- }
47
-
48
- log(`\n✅ 授权成功!deviceToken=${bundle.deviceToken.slice(0, 12)}...`);
49
- if (bundle.refreshToken) log(` refreshToken=${bundle.refreshToken.slice(0, 12)}...`);
50
-
51
- // 取 userinfo
52
- let user = { uid: "", name: "", email: "", userType: "personal_standard", organizationId: "", organizationName: "" };
53
- try {
54
- user = await fetchUserInfo({ region: normRegion, deviceToken: bundle.deviceToken, fetchImpl });
55
- log(` UID: ${user.uid} 昵称: ${user.name || "(空)"} 邮箱: ${user.email || "(空)"}`);
56
- } catch (e) {
57
- log(` ⚠️ userinfo 失败: ${e.message}(使用 device token 前 8 位兜底 uid)`);
58
- user.uid = bundle.deviceToken.slice(0, 8);
59
- }
60
- if (!user.uid) {
61
- console.error("❌ 无法获取用户标识");
62
- process.exit(1);
63
- }
64
-
65
- // 落盘
66
- const { saveQoderAccount } = await import("../../../providers/qoder/account-store.js");
67
- const save = deps.saveAccount || saveQoderAccount;
68
- const saved = await save({
69
- uid: user.uid,
70
- deviceToken: bundle.deviceToken,
71
- refreshToken: bundle.refreshToken || "",
72
- region: normRegion,
73
- name: user.name,
74
- email: user.email,
75
- userType: user.userType,
76
- organizationId: user.organizationId,
77
- organizationName: user.organizationName,
78
- });
79
-
80
- log("");
81
- log("=".repeat(60));
82
- log(`✅ 登录完成!`);
83
- log(` UID: ${user.uid}`);
84
- log(` 账号数: ${saved.accounts}${saved.updated ? "(旧号凭证已更新)" : ""}`);
85
- log(` 数据文件: ${saved.file}`);
86
- log("=".repeat(60));
87
- // 默认 allowAny on(免费福利供应商,对齐 codearts 惯例)
88
- try {
89
- const { saveProviderAllowAnyModels } = await import("../../../state.js");
90
- saveProviderAllowAnyModels("qoder", true);
91
- log(" allowAnyModels=on(免费福利供应商默认放行;收紧:mslxdff -provider qoder allowAny off)");
92
- } catch {}
93
-
94
- log("下一步:");
95
- log(" mslxdff -provider qoder models 列模型列表");
96
- log(" mslxdff -restart(用户终端跑) 重启网关使新账号生效");
97
- log(" 然后 curl http://localhost:8989/v1/chat/completions -d '{\"model\":\"qoder/auto\",\"messages\":[{\"role\":\"user\",\"content\":\"hi\"}]}'");
98
- log("");
99
- log("多账号:重复 `mslxdff -provider qoder login` 追加,每号独立 uid,对话自动轮换");
100
-
101
- if (!deps.noExit) process.exit(0);
102
- return true;
1
+ // mslxdff -provider qoder login — Qoder 设备授权(PKCE + poll),对齐 cline-login/traework-login。
2
+ // 授权后落盘 auths/qoder-<uid>.json + state.json,完成后进程退出。
3
+ import { compatFetch, timeoutSignal } from "../../../compat.js";
4
+ import { normalizeProviderId } from "../../../providers/model-id.js";
5
+ import { pkce, hex16, buildLoginUrl, waitForAuth, fetchUserInfo } from "../../../providers/qoder/oauth.js";
6
+
7
+ const REGIONS = ["global", "cn"];
8
+
9
+ export async function handleQoderLogin(id, sub, rest = [], deps = {}) {
10
+ if (normalizeProviderId(id) !== "qoder") return false;
11
+ if (sub !== "login" && sub !== "auth" && sub !== "oauth") return false;
12
+ const fetchImpl = deps.fetchImpl || compatFetch;
13
+ const log = deps.log || ((m) => console.log(m));
14
+
15
+ // 可选参数:--region cn 或 --region global(默认 global)
16
+ const regionIdx = rest.indexOf("--region") >= 0 ? rest.indexOf("--region") : rest.indexOf("-r");
17
+ const region = regionIdx >= 0 ? String(rest[regionIdx + 1] || "global").trim() : "global";
18
+ const normRegion = region === "cn" ? "cn" : "global";
19
+
20
+ const { verifier, challenge } = pkce();
21
+ const nonce = hex16();
22
+ const loginUrl = buildLoginUrl({ region: normRegion, nonce, challenge });
23
+
24
+ log("=".repeat(60));
25
+ log(" Qoder 登录");
26
+ log(` Region: ${normRegion === "cn" ? "中国站 (qoder.com.cn)" : "国际站 (qoder.com)"}`);
27
+ log("=".repeat(60));
28
+ log("");
29
+ log(" 1. 在浏览器打开下面链接,用 Qoder 账号登录(OAuth 授权)");
30
+ log(" 2. 登录成功后会自动完成授权,请等待回显");
31
+ log("");
32
+ log(` ${loginUrl}`);
33
+ log("");
34
+ log("🔄 等待你授权(自动轮询,每 3 秒,最多 10 分钟)...");
35
+
36
+ let bundle;
37
+ try {
38
+ bundle = await waitForAuth({ region: normRegion, nonce, verifier, fetchImpl, log });
39
+ } catch (e) {
40
+ console.error(`\n❌ ${e.message}`);
41
+ process.exit(1);
42
+ }
43
+ if (!bundle || !bundle.deviceToken) {
44
+ console.error("\n❌ 未获取到 device token");
45
+ process.exit(1);
46
+ }
47
+
48
+ log(`\n✅ 授权成功!deviceToken=${bundle.deviceToken.slice(0, 12)}...`);
49
+ if (bundle.refreshToken) log(` refreshToken=${bundle.refreshToken.slice(0, 12)}...`);
50
+
51
+ // 取 userinfo
52
+ let user = { uid: "", name: "", email: "", userType: "personal_standard", organizationId: "", organizationName: "" };
53
+ try {
54
+ user = await fetchUserInfo({ region: normRegion, deviceToken: bundle.deviceToken, fetchImpl });
55
+ log(` UID: ${user.uid} 昵称: ${user.name || "(空)"} 邮箱: ${user.email || "(空)"}`);
56
+ } catch (e) {
57
+ log(` ⚠️ userinfo 失败: ${e.message}(使用 device token 前 8 位兜底 uid)`);
58
+ user.uid = bundle.deviceToken.slice(0, 8);
59
+ }
60
+ if (!user.uid) {
61
+ console.error("❌ 无法获取用户标识");
62
+ process.exit(1);
63
+ }
64
+
65
+ // 落盘
66
+ const { saveQoderAccount } = await import("../../../providers/qoder/account-store.js");
67
+ const save = deps.saveAccount || saveQoderAccount;
68
+ const saved = await save({
69
+ uid: user.uid,
70
+ deviceToken: bundle.deviceToken,
71
+ refreshToken: bundle.refreshToken || "",
72
+ region: normRegion,
73
+ name: user.name,
74
+ email: user.email,
75
+ userType: user.userType,
76
+ organizationId: user.organizationId,
77
+ organizationName: user.organizationName,
78
+ });
79
+
80
+ log("");
81
+ log("=".repeat(60));
82
+ log(`✅ 登录完成!`);
83
+ log(` UID: ${user.uid}`);
84
+ log(` 账号数: ${saved.accounts}${saved.updated ? "(旧号凭证已更新)" : ""}`);
85
+ log(` 数据文件: ${saved.file}`);
86
+ log("=".repeat(60));
87
+ // 默认 allowAny on(免费福利供应商,对齐 codearts 惯例)
88
+ try {
89
+ const { saveProviderAllowAnyModels } = await import("../../../state.js");
90
+ saveProviderAllowAnyModels("qoder", true);
91
+ log(" allowAnyModels=on(免费福利供应商默认放行;收紧:mslxdff -provider qoder allowAny off)");
92
+ } catch {}
93
+
94
+ log("下一步:");
95
+ log(" mslxdff -provider qoder models 列模型列表");
96
+ log(" mslxdff -restart(用户终端跑) 重启网关使新账号生效");
97
+ log(" 然后 curl http://localhost:8989/v1/chat/completions -d '{\"model\":\"qoder/auto\",\"messages\":[{\"role\":\"user\",\"content\":\"hi\"}]}'");
98
+ log("");
99
+ log("多账号:重复 `mslxdff -provider qoder login` 追加,每号独立 uid,对话自动轮换");
100
+
101
+ if (!deps.noExit) process.exit(0);
102
+ return true;
103
103
  }
@@ -1,180 +1,180 @@
1
- // mslxdff -provider raccoon login — 扫码登录(终端二维码 + 轮询)。
2
- // ⚠ 2026-10 上游改版:二维码必须**先由服务端签发**(POST /api/iam/v1/auth/mp/qrcode),
3
- // 拿到 qrcode_code + scan_path 才能渲染。旧的「本地自造 code」在新通道下没有服务端会话,
4
- // 微信扫码后查不到该码 → 手机端报「二维码已过期或已被使用」。详见 src/providers/raccoon/login.js。
5
- // 该链路匿名可达且**不需要验证码**;成功后落盘 auths/raccoon-<uid>.json(0600)
6
- // 并把兜底目录只增不减补齐进 allowlist(避免「登录成功却处处 403」)。
7
- import { normalizeProviderId } from "../../../providers/model-id.js";
8
- import { compatFetch } from "../../../compat.js";
9
- import {
10
- buildQrUrl,
11
- cancelQrSession,
12
- confirmRaccoonSession,
13
- createQrSession,
14
- fetchRaccoonUserInfo,
15
- pollQrLogin,
16
- } from "../../../providers/raccoon/login.js";
17
- import { encodeQr, renderTerminal } from "../../../providers/raccoon/qr.js";
18
- import { ensureRaccoonDeviceId, saveRaccoonAccount } from "../../../providers/raccoon/account-store.js";
19
- import { seedRaccoonAllowlist } from "../../../providers/raccoon/models.js";
20
- import { raccoonTokenFingerprint, resolveRaccoonUid } from "../../../providers/raccoon/auth.js";
21
- import { claimRaccoonLoginReward, raccoonClaimStatus } from "../../../providers/raccoon/credits.js";
22
-
23
- const LOGIN_SUBS = new Set(["login", "auth", "oauth"]);
24
-
25
- const RELOGIN_HINT = " (可重试:mslxdff -provider raccoon login)";
26
-
27
- export async function handleRaccoonLogin(id, sub, rest = [], deps = {}) {
28
- const pid = normalizeProviderId(id) || String(id || "").toLowerCase();
29
- if (pid !== "raccoon") return false;
30
- // `login --password` 走手机号+密码(多账号免扫码);无该旗标仍是扫码。分派必须在
31
- // LOGIN_SUBS 判定之前,且只在此处转交 —— 扫码路径本身零改动。
32
- if (LOGIN_SUBS.has(sub) && rest.some((x) => {
33
- const s = String(x);
34
- return s === "--password" || s.startsWith("--password=") || s === "-p" || s === "--phone" || s.startsWith("--phone=");
35
- })) {
36
- const { handleRaccoonPasswordLogin } = await import("./raccoon-password.js");
37
- return handleRaccoonPasswordLogin(id, sub, rest, deps);
38
- }
39
- if (!LOGIN_SUBS.has(sub)) return false;
40
-
41
- const fetchImpl = deps.fetchImpl || compatFetch;
42
- const log = deps.log || ((m) => console.log(m));
43
- const exit = deps.exit || ((code) => process.exit(code));
44
-
45
- log("=".repeat(60));
46
- log(" Raccoon 登录(商汤小浣熊 · 积分制模型池)");
47
- log("=".repeat(60));
48
- log("");
49
- log(" 1. 用微信「扫一扫」扫描下方二维码,并在微信里点确认(浏览器直接打开会 404)");
50
- log(" 2. 确认后本机自动继续(CLI 轮询,无需回调)");
51
- log("");
52
-
53
- // 签发二维码:这一步失败就没有可扫的码,必须当场说清楚,不能拿一个假码糊过去
54
- let session;
55
- try {
56
- session = deps.qrSession || await createQrSession({ fetchImpl });
57
- } catch (error) {
58
- log(`❌ 无法获取二维码:${error?.message ?? error}`);
59
- log(" (多为网络不通或上游改版;可重试:mslxdff -provider raccoon login)");
60
- exit(1);
61
- return true;
62
- }
63
- const code = deps.qrCode || session.qrcodeCode;
64
- const url = deps.qrUrl || buildQrUrl(code, session.scanPath);
65
-
66
- const art = renderTerminal(encodeQr(url));
67
- if (art) {
68
- log(art);
69
- log("");
70
- }
71
- log(` 登录链接:${url}`);
72
- log(` 有效期:${Math.round(session.expiresInMs / 1000)} 秒(过期请重跑本命令)`);
73
- log("");
74
- log("🔄 等待扫码确认…");
75
-
76
- let out;
77
- try {
78
- out = await pollQrLogin(code, {
79
- fetchImpl,
80
- sleepFn: deps.sleepFn,
81
- intervalMs: deps.intervalMs ?? session.pollIntervalMs,
82
- timeoutMs: deps.timeoutMs ?? session.expiresInMs,
83
- onTick: deps.onTick,
84
- });
85
- } catch (error) {
86
- log("");
87
- log(`❌ 登录失败:${error?.message ?? error}`);
88
- log(RELOGIN_HINT);
89
- exit(1);
90
- return true;
91
- }
92
-
93
- if (out.status !== "success") {
94
- // 非终态失败:回收服务端会话(失败也不打断),并对每种结局给一句人话
95
- await cancelQrSession(code, { fetchImpl });
96
- log("");
97
- if (out.status === "canceled") log("❌ 已在手机端取消登录(未写入任何凭据)");
98
- else if (out.status === "expired") log("❌ 二维码已过期(上游作废了本次会话)");
99
- else log("❌ 登录已超时");
100
- log(RELOGIN_HINT);
101
- exit(1);
102
- return true;
103
- }
104
-
105
- return await finishRaccoonLogin({ credential: out.credential, fetchImpl, deps, log });
106
- }
107
-
108
- /**
109
- * 登录成功后的收尾四步(**扫码与密码两条路共用,单一源**):
110
- * confirm 会话 → 取用户信息 → 落盘 + 补 allowlist → 领一次性登录奖励 → 打印回执。
111
- *
112
- * 抽出来的理由不只是省行数:这四步的顺序有硬约束(必须先 confirm 才能用 token;领奖必须在
113
- * access_token 刚签发的窗口内),任何一条路径自己重写一遍都会漏掉其中一步且难以察觉。
114
- *
115
- * @param {object} a
116
- * @param {object} a.credential 已签发的凭据(两种登录方式同形)
117
- * @param {Function} a.fetchImpl
118
- * @param {object} a.deps 与原 CLI 依赖注入同形(dir/file/deviceId/saveAccount/claimReward/skipReward/env)
119
- * @param {Function} a.log
120
- * @param {string} [a.methodNote] 登录方式说明行(如密码登录标注手机号),纯展示
121
- * @returns {Promise<boolean>} 恒 true(表示「已处理」,交还 CLI 派发链)
122
- */
123
- export async function finishRaccoonLogin({ credential, fetchImpl, deps = {}, log, methodNote = "" }) {
124
- // 新登录的会话是「未确认」状态:不先 POST /iam/confirm,此后所有业务端点(含下面的领奖励、
125
- // 以及 daemon 的 chat)都会撞 `400 code 200901 iam_confirm_required`。登录时当场确认一次,
126
- // 让落盘的凭据从一开始就是可用的;确认失败不阻断(chat.js 有懒重试兜底),只在末尾如实提示。
127
- const confirmed = await confirmRaccoonSession(credential, { fetchImpl });
128
- const info = await fetchRaccoonUserInfo(credential, { fetchImpl });
129
- const uid = resolveRaccoonUid({
130
- userId: info.userId,
131
- officeIdentity: info.officeIdentity || credential.office_identity,
132
- token: credential.access_token,
133
- });
134
- const deviceId = deps.deviceId || ensureRaccoonDeviceId({ uid, dir: deps.dir });
135
- const save = deps.saveAccount || saveRaccoonAccount;
136
- const saved = await save({
137
- uid,
138
- accessToken: credential.access_token,
139
- refreshToken: credential.refresh_token || "",
140
- expiresAt: credential.expires_at || "",
141
- officeIdentity: info.officeIdentity || credential.office_identity || "",
142
- deviceId,
143
- name: info.name || "",
144
- phone: info.phone || "",
145
- dir: deps.dir,
146
- file: deps.file,
147
- });
148
- const allow = seedRaccoonAllowlist({ file: deps.file });
149
-
150
- // 一次性新手礼包只能在这儿领:此刻 access_token 刚签发(寿命约 3 小时),是全程唯一稳的窗口。
151
- // 刻意不交给 daemon 定时去做 —— 那时 token 多半已过期,要续期就得和网关请求抢同一条一次性 refresh_token。
152
- let reward;
153
- if (!deps.skipReward) {
154
- const claim = deps.claimReward || claimRaccoonLoginReward;
155
- try {
156
- reward = await claim({ credential, fetchImpl, env: deps.env });
157
- } catch (e) {
158
- reward = { status: "error", msg: String(e?.message || e).slice(0, 120) };
159
- }
160
- }
161
-
162
- log("");
163
- log(`✅ 登录成功!uid=${uid} 昵称=${info.name || "(空)"} token=${raccoonTokenFingerprint(credential.access_token)}…`);
164
- if (methodNote) log(methodNote);
165
- log(` 凭据: ${saved.file}`);
166
- if (!confirmed) log(" ⚠ 会话确认(iam/confirm)暂未成功 —— 不影响使用(调用时会自动重试确认),若持续报错请重跑 login");
167
- if (allow.added.length) log(` allowlist 已补齐 ${allow.added.length} 个模型:${allow.added.join(", ")}`);
168
- if (reward) {
169
- const line = {
170
- claimed: `🎁 已领取登录奖励 +${reward.points} 分(每号仅此一次,账单已确认入账)`,
171
- already: ` 登录奖励此前已领过 —— 这家每号只有一次,不是每日签到`,
172
- phantom: ` ⚠ 上游回执「成功」但账单里没有这笔 —— 实为未到账,可稍后用 -provider raccoon checkin 复核`,
173
- unverified: ` 已提交领取,但账单暂时查不到,稍后用 -provider raccoon quota 核对`,
174
- error: ` 领取登录奖励失败:${reward.msg || "未知原因"}`,
175
- }[reward.status || raccoonClaimStatus(reward)];
176
- if (line) log(line);
177
- }
178
- log(" 下一步: mslxdff -provider raccoon quota 查看积分 · mslxdff -provider raccoon models 查看模型(含积分倍率)");
179
- return true;
180
- }
1
+ // mslxdff -provider raccoon login — 扫码登录(终端二维码 + 轮询)。
2
+ // ⚠ 2026-10 上游改版:二维码必须**先由服务端签发**(POST /api/iam/v1/auth/mp/qrcode),
3
+ // 拿到 qrcode_code + scan_path 才能渲染。旧的「本地自造 code」在新通道下没有服务端会话,
4
+ // 微信扫码后查不到该码 → 手机端报「二维码已过期或已被使用」。详见 src/providers/raccoon/login.js。
5
+ // 该链路匿名可达且**不需要验证码**;成功后落盘 auths/raccoon-<uid>.json(0600)
6
+ // 并把兜底目录只增不减补齐进 allowlist(避免「登录成功却处处 403」)。
7
+ import { normalizeProviderId } from "../../../providers/model-id.js";
8
+ import { compatFetch } from "../../../compat.js";
9
+ import {
10
+ buildQrUrl,
11
+ cancelQrSession,
12
+ confirmRaccoonSession,
13
+ createQrSession,
14
+ fetchRaccoonUserInfo,
15
+ pollQrLogin,
16
+ } from "../../../providers/raccoon/login.js";
17
+ import { encodeQr, renderTerminal } from "../../../providers/raccoon/qr.js";
18
+ import { ensureRaccoonDeviceId, saveRaccoonAccount } from "../../../providers/raccoon/account-store.js";
19
+ import { seedRaccoonAllowlist } from "../../../providers/raccoon/models.js";
20
+ import { raccoonTokenFingerprint, resolveRaccoonUid } from "../../../providers/raccoon/auth.js";
21
+ import { claimRaccoonLoginReward, raccoonClaimStatus } from "../../../providers/raccoon/credits.js";
22
+
23
+ const LOGIN_SUBS = new Set(["login", "auth", "oauth"]);
24
+
25
+ const RELOGIN_HINT = " (可重试:mslxdff -provider raccoon login)";
26
+
27
+ export async function handleRaccoonLogin(id, sub, rest = [], deps = {}) {
28
+ const pid = normalizeProviderId(id) || String(id || "").toLowerCase();
29
+ if (pid !== "raccoon") return false;
30
+ // `login --password` 走手机号+密码(多账号免扫码);无该旗标仍是扫码。分派必须在
31
+ // LOGIN_SUBS 判定之前,且只在此处转交 —— 扫码路径本身零改动。
32
+ if (LOGIN_SUBS.has(sub) && rest.some((x) => {
33
+ const s = String(x);
34
+ return s === "--password" || s.startsWith("--password=") || s === "-p" || s === "--phone" || s.startsWith("--phone=");
35
+ })) {
36
+ const { handleRaccoonPasswordLogin } = await import("./raccoon-password.js");
37
+ return handleRaccoonPasswordLogin(id, sub, rest, deps);
38
+ }
39
+ if (!LOGIN_SUBS.has(sub)) return false;
40
+
41
+ const fetchImpl = deps.fetchImpl || compatFetch;
42
+ const log = deps.log || ((m) => console.log(m));
43
+ const exit = deps.exit || ((code) => process.exit(code));
44
+
45
+ log("=".repeat(60));
46
+ log(" Raccoon 登录(商汤小浣熊 · 积分制模型池)");
47
+ log("=".repeat(60));
48
+ log("");
49
+ log(" 1. 用微信「扫一扫」扫描下方二维码,并在微信里点确认(浏览器直接打开会 404)");
50
+ log(" 2. 确认后本机自动继续(CLI 轮询,无需回调)");
51
+ log("");
52
+
53
+ // 签发二维码:这一步失败就没有可扫的码,必须当场说清楚,不能拿一个假码糊过去
54
+ let session;
55
+ try {
56
+ session = deps.qrSession || await createQrSession({ fetchImpl });
57
+ } catch (error) {
58
+ log(`❌ 无法获取二维码:${error?.message ?? error}`);
59
+ log(" (多为网络不通或上游改版;可重试:mslxdff -provider raccoon login)");
60
+ exit(1);
61
+ return true;
62
+ }
63
+ const code = deps.qrCode || session.qrcodeCode;
64
+ const url = deps.qrUrl || buildQrUrl(code, session.scanPath);
65
+
66
+ const art = renderTerminal(encodeQr(url));
67
+ if (art) {
68
+ log(art);
69
+ log("");
70
+ }
71
+ log(` 登录链接:${url}`);
72
+ log(` 有效期:${Math.round(session.expiresInMs / 1000)} 秒(过期请重跑本命令)`);
73
+ log("");
74
+ log("🔄 等待扫码确认…");
75
+
76
+ let out;
77
+ try {
78
+ out = await pollQrLogin(code, {
79
+ fetchImpl,
80
+ sleepFn: deps.sleepFn,
81
+ intervalMs: deps.intervalMs ?? session.pollIntervalMs,
82
+ timeoutMs: deps.timeoutMs ?? session.expiresInMs,
83
+ onTick: deps.onTick,
84
+ });
85
+ } catch (error) {
86
+ log("");
87
+ log(`❌ 登录失败:${error?.message ?? error}`);
88
+ log(RELOGIN_HINT);
89
+ exit(1);
90
+ return true;
91
+ }
92
+
93
+ if (out.status !== "success") {
94
+ // 非终态失败:回收服务端会话(失败也不打断),并对每种结局给一句人话
95
+ await cancelQrSession(code, { fetchImpl });
96
+ log("");
97
+ if (out.status === "canceled") log("❌ 已在手机端取消登录(未写入任何凭据)");
98
+ else if (out.status === "expired") log("❌ 二维码已过期(上游作废了本次会话)");
99
+ else log("❌ 登录已超时");
100
+ log(RELOGIN_HINT);
101
+ exit(1);
102
+ return true;
103
+ }
104
+
105
+ return await finishRaccoonLogin({ credential: out.credential, fetchImpl, deps, log });
106
+ }
107
+
108
+ /**
109
+ * 登录成功后的收尾四步(**扫码与密码两条路共用,单一源**):
110
+ * confirm 会话 → 取用户信息 → 落盘 + 补 allowlist → 领一次性登录奖励 → 打印回执。
111
+ *
112
+ * 抽出来的理由不只是省行数:这四步的顺序有硬约束(必须先 confirm 才能用 token;领奖必须在
113
+ * access_token 刚签发的窗口内),任何一条路径自己重写一遍都会漏掉其中一步且难以察觉。
114
+ *
115
+ * @param {object} a
116
+ * @param {object} a.credential 已签发的凭据(两种登录方式同形)
117
+ * @param {Function} a.fetchImpl
118
+ * @param {object} a.deps 与原 CLI 依赖注入同形(dir/file/deviceId/saveAccount/claimReward/skipReward/env)
119
+ * @param {Function} a.log
120
+ * @param {string} [a.methodNote] 登录方式说明行(如密码登录标注手机号),纯展示
121
+ * @returns {Promise<boolean>} 恒 true(表示「已处理」,交还 CLI 派发链)
122
+ */
123
+ export async function finishRaccoonLogin({ credential, fetchImpl, deps = {}, log, methodNote = "" }) {
124
+ // 新登录的会话是「未确认」状态:不先 POST /iam/confirm,此后所有业务端点(含下面的领奖励、
125
+ // 以及 daemon 的 chat)都会撞 `400 code 200901 iam_confirm_required`。登录时当场确认一次,
126
+ // 让落盘的凭据从一开始就是可用的;确认失败不阻断(chat.js 有懒重试兜底),只在末尾如实提示。
127
+ const confirmed = await confirmRaccoonSession(credential, { fetchImpl });
128
+ const info = await fetchRaccoonUserInfo(credential, { fetchImpl });
129
+ const uid = resolveRaccoonUid({
130
+ userId: info.userId,
131
+ officeIdentity: info.officeIdentity || credential.office_identity,
132
+ token: credential.access_token,
133
+ });
134
+ const deviceId = deps.deviceId || ensureRaccoonDeviceId({ uid, dir: deps.dir });
135
+ const save = deps.saveAccount || saveRaccoonAccount;
136
+ const saved = await save({
137
+ uid,
138
+ accessToken: credential.access_token,
139
+ refreshToken: credential.refresh_token || "",
140
+ expiresAt: credential.expires_at || "",
141
+ officeIdentity: info.officeIdentity || credential.office_identity || "",
142
+ deviceId,
143
+ name: info.name || "",
144
+ phone: info.phone || "",
145
+ dir: deps.dir,
146
+ file: deps.file,
147
+ });
148
+ const allow = seedRaccoonAllowlist({ file: deps.file });
149
+
150
+ // 一次性新手礼包只能在这儿领:此刻 access_token 刚签发(寿命约 3 小时),是全程唯一稳的窗口。
151
+ // 刻意不交给 daemon 定时去做 —— 那时 token 多半已过期,要续期就得和网关请求抢同一条一次性 refresh_token。
152
+ let reward;
153
+ if (!deps.skipReward) {
154
+ const claim = deps.claimReward || claimRaccoonLoginReward;
155
+ try {
156
+ reward = await claim({ credential, fetchImpl, env: deps.env });
157
+ } catch (e) {
158
+ reward = { status: "error", msg: String(e?.message || e).slice(0, 120) };
159
+ }
160
+ }
161
+
162
+ log("");
163
+ log(`✅ 登录成功!uid=${uid} 昵称=${info.name || "(空)"} token=${raccoonTokenFingerprint(credential.access_token)}…`);
164
+ if (methodNote) log(methodNote);
165
+ log(` 凭据: ${saved.file}`);
166
+ if (!confirmed) log(" ⚠ 会话确认(iam/confirm)暂未成功 —— 不影响使用(调用时会自动重试确认),若持续报错请重跑 login");
167
+ if (allow.added.length) log(` allowlist 已补齐 ${allow.added.length} 个模型:${allow.added.join(", ")}`);
168
+ if (reward) {
169
+ const line = {
170
+ claimed: `🎁 已领取登录奖励 +${reward.points} 分(每号仅此一次,账单已确认入账)`,
171
+ already: ` 登录奖励此前已领过 —— 这家每号只有一次,不是每日签到`,
172
+ phantom: ` ⚠ 上游回执「成功」但账单里没有这笔 —— 实为未到账,可稍后用 -provider raccoon checkin 复核`,
173
+ unverified: ` 已提交领取,但账单暂时查不到,稍后用 -provider raccoon quota 核对`,
174
+ error: ` 领取登录奖励失败:${reward.msg || "未知原因"}`,
175
+ }[reward.status || raccoonClaimStatus(reward)];
176
+ if (line) log(line);
177
+ }
178
+ log(" 下一步: mslxdff -provider raccoon quota 查看积分 · mslxdff -provider raccoon models 查看模型(含积分倍率)");
179
+ return true;
180
+ }