mslxdff 0.1.203 → 0.1.207

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 (330) hide show
  1. package/README.md +3 -3
  2. package/bin/mslxdff.js +1 -1
  3. package/docs/cli_help_mini.md +146 -0
  4. package/package.json +38 -38
  5. package/plugins/README.md +14 -14
  6. package/plugins/prefer-model.mjs.example +14 -14
  7. package/src/anthropic/canonical-json.js +55 -0
  8. package/src/anthropic/count-tokens.js +61 -61
  9. package/src/anthropic/request-body.js +183 -126
  10. package/src/anthropic/request-shape.js +60 -0
  11. package/src/anthropic/session-id.js +58 -0
  12. package/src/anthropic/shared.js +18 -18
  13. package/src/anthropic/sse-aggregate.js +56 -56
  14. package/src/anthropic/tool-media.js +75 -0
  15. package/src/anthropic/translate.js +296 -287
  16. package/src/anthropic/web-search.js +361 -361
  17. package/src/api-kind.js +31 -31
  18. package/src/autostart.js +288 -288
  19. package/src/bench/probe.js +1 -1
  20. package/src/bench/runner.js +1 -1
  21. package/src/bench/via-probe.js +1 -1
  22. package/src/bench/via.js +144 -144
  23. package/src/bench/workbuddy-bench.js +1 -1
  24. package/src/chat/config.js +11 -11
  25. package/src/chat/cooling.js +81 -81
  26. package/src/chat/direct.js +58 -58
  27. package/src/chat/index.js +6 -6
  28. package/src/chat/spinner.js +38 -38
  29. package/src/chat/sse.js +69 -69
  30. package/src/chat/stats.js +247 -247
  31. package/src/chat/store.js +48 -48
  32. package/src/chat/tool-handlers.js +67 -67
  33. package/src/chat/tools.js +1 -1
  34. package/src/chat/upstream.js +59 -59
  35. package/src/chat-pipeline/auto-race.js +158 -158
  36. package/src/chat-pipeline/empty-turn.js +147 -147
  37. package/src/chat-pipeline/engine.js +17 -17
  38. package/src/chat-pipeline/index.js +8 -40
  39. package/src/chat-pipeline/serial-trial.js +279 -283
  40. package/src/chat-pipeline/terminal-verdict.js +132 -147
  41. package/src/chooser.js +54 -54
  42. package/src/claude-desktop/apply.js +101 -101
  43. package/src/claude-desktop/context1m.js +38 -38
  44. package/src/claude-desktop/doctor.js +146 -146
  45. package/src/claude-desktop/slots.js +152 -152
  46. package/src/cli/bootstrap.js +1 -1
  47. package/src/cli/commands/claude-desktop.js +284 -284
  48. package/src/cli/commands/daemon.js +231 -231
  49. package/src/cli/commands/model/list-live.js +22 -22
  50. package/src/cli/commands/model/list-providers.js +76 -76
  51. package/src/cli/commands/model/list-render.js +77 -77
  52. package/src/cli/commands/model/list-sort.js +52 -52
  53. package/src/cli/commands/model/list-tty.js +76 -76
  54. package/src/cli/commands/model/list.js +166 -166
  55. package/src/cli/commands/model/live-models.js +24 -24
  56. package/src/cli/commands/model/stats.js +43 -43
  57. package/src/cli/commands/model/status.js +47 -47
  58. package/src/cli/commands/model.js +51 -51
  59. package/src/cli/commands/provider/add.js +108 -108
  60. package/src/cli/commands/provider/allowlist.js +99 -99
  61. package/src/cli/commands/provider/cline-free.js +99 -99
  62. package/src/cli/commands/provider/cline-login.js +218 -218
  63. package/src/cli/commands/provider/cline-quota.js +65 -65
  64. package/src/cli/commands/provider/codearts-login.js +45 -45
  65. package/src/cli/commands/provider/config.js +119 -119
  66. package/src/cli/commands/provider/globalqwenwork-login.js +126 -126
  67. package/src/cli/commands/provider/keys-guard.js +50 -50
  68. package/src/cli/commands/provider/keys.js +161 -161
  69. package/src/cli/commands/provider/qoder-checkin.js +81 -81
  70. package/src/cli/commands/provider/qoder-login.js +102 -102
  71. package/src/cli/commands/provider/raccoon-login.js +180 -180
  72. package/src/cli/commands/provider/raccoon-password.js +162 -162
  73. package/src/cli/commands/provider/raccoon-quota.js +109 -109
  74. package/src/cli/commands/provider/traework-checkin.js +144 -144
  75. package/src/cli/commands/provider/traework-login.js +164 -164
  76. package/src/cli/commands/provider/workbuddy-login.js +153 -153
  77. package/src/cli/commands/provider/zcode-login.js +77 -77
  78. package/src/cli/commands/provider/zcode-quota.js +55 -55
  79. package/src/cli/commands/provider.js +1 -1
  80. package/src/cli/commands/stats.js +158 -149
  81. package/src/cli/commands/system.js +261 -261
  82. package/src/cli/commands/timezone.js +47 -47
  83. package/src/cli/commands/use-group.js +60 -60
  84. package/src/cli/commands/workbuddy.js +189 -189
  85. package/src/cli/format.js +141 -141
  86. package/src/cli/group-helpers.js +70 -70
  87. package/src/cli/help.js +80 -80
  88. package/src/cli/index.js +70 -70
  89. package/src/cli/interactive.js +121 -121
  90. package/src/cli/join-core.js +99 -99
  91. package/src/cli/join-wizard.js +175 -175
  92. package/src/cli/policy.js +136 -136
  93. package/src/cli/provider-row.js +126 -126
  94. package/src/cli/util.js +24 -24
  95. package/src/compat.js +53 -53
  96. package/src/events.js +38 -38
  97. package/src/free-lane.js +131 -131
  98. package/src/free-watcher.js +63 -63
  99. package/src/groups.js +262 -262
  100. package/src/logs.js +195 -195
  101. package/src/metrics.js +71 -62
  102. package/src/model-capabilities/context-lookup.js +65 -65
  103. package/src/model-capabilities/merge.js +142 -142
  104. package/src/model-trace.js +187 -187
  105. package/src/models.js +1 -1
  106. package/src/opencode-identity.js +72 -72
  107. package/src/peers.js +254 -254
  108. package/src/plugins.js +107 -107
  109. package/src/providers/AGENTS.md +49 -0
  110. package/src/providers/base.js +164 -164
  111. package/src/providers/classify.js +22 -22
  112. package/src/providers/cline/allowlist-sync.js +93 -93
  113. package/src/providers/cline/free-catalog.js +71 -71
  114. package/src/providers/cline/headers.js +37 -37
  115. package/src/providers/cline/index.js +130 -130
  116. package/src/providers/cline/models.js +150 -150
  117. package/src/providers/cline/usage.js +274 -274
  118. package/src/providers/codearts/auth-pool.js +148 -148
  119. package/src/providers/codearts/concurrency.js +34 -34
  120. package/src/providers/codearts/const.js +65 -65
  121. package/src/providers/codearts/dpop.js +95 -95
  122. package/src/providers/codearts/index.js +175 -175
  123. package/src/providers/codearts/login.js +214 -214
  124. package/src/providers/codearts/models.js +182 -182
  125. package/src/providers/codearts/sign.js +96 -96
  126. package/src/providers/codearts/sse.js +204 -204
  127. package/src/providers/codearts/stream.js +209 -209
  128. package/src/providers/codearts/sts.js +124 -124
  129. package/src/providers/codearts.js +1 -1
  130. package/src/providers/dispatcher.js +146 -146
  131. package/src/providers/generic.js +156 -156
  132. package/src/providers/globalqwenwork/account-store.js +141 -141
  133. package/src/providers/globalqwenwork/constants.js +73 -73
  134. package/src/providers/globalqwenwork/crypto.js +2 -2
  135. package/src/providers/globalqwenwork/http.js +2 -2
  136. package/src/providers/globalqwenwork/index.js +331 -331
  137. package/src/providers/globalqwenwork/payload.js +147 -147
  138. package/src/providers/globalqwenwork/rsa.js +2 -2
  139. package/src/providers/globalqwenwork/sse.js +2 -2
  140. package/src/providers/globalqwenwork/stream.js +2 -2
  141. package/src/providers/globalqwenwork.js +1 -1
  142. package/src/providers/globalworkbuddy/account-store.js +198 -198
  143. package/src/providers/globalworkbuddy/auth.js +97 -97
  144. package/src/providers/globalworkbuddy/catalog.js +138 -138
  145. package/src/providers/globalworkbuddy/constants.js +73 -73
  146. package/src/providers/globalworkbuddy/device-auth.js +120 -120
  147. package/src/providers/globalworkbuddy/errors.js +98 -98
  148. package/src/providers/globalworkbuddy/headers.js +89 -89
  149. package/src/providers/globalworkbuddy/models.js +96 -96
  150. package/src/providers/globalworkbuddy/payload.js +80 -80
  151. package/src/providers/index.js +5 -5
  152. package/src/providers/model-id.js +172 -172
  153. package/src/providers/opencode.js +19 -19
  154. package/src/providers/openrouter.js +31 -31
  155. package/src/providers/qoder/account-store.js +106 -106
  156. package/src/providers/qoder/aggregate.js +60 -60
  157. package/src/providers/qoder/baseprompt.json +591 -591
  158. package/src/providers/qoder/checkin.js +160 -160
  159. package/src/providers/qoder/constants.js +44 -44
  160. package/src/providers/qoder/encode.js +41 -41
  161. package/src/providers/qoder/fingerprint.js +38 -38
  162. package/src/providers/qoder/models.js +77 -77
  163. package/src/providers/qoder/oauth.js +84 -84
  164. package/src/providers/qoder/payload.js +162 -162
  165. package/src/providers/qoder/request.js +27 -27
  166. package/src/providers/qoder/session.js +134 -134
  167. package/src/providers/qoder/sticky.js +38 -38
  168. package/src/providers/qoder/stream.js +116 -116
  169. package/src/providers/qoder.js +1 -1
  170. package/src/providers/raccoon/account-store.js +216 -216
  171. package/src/providers/raccoon/auth.js +67 -67
  172. package/src/providers/raccoon/chat.js +228 -228
  173. package/src/providers/raccoon/const.js +180 -180
  174. package/src/providers/raccoon/credits.js +185 -185
  175. package/src/providers/raccoon/crypto.js +43 -43
  176. package/src/providers/raccoon/envelope.js +31 -31
  177. package/src/providers/raccoon/headers.js +45 -45
  178. package/src/providers/raccoon/index.js +216 -216
  179. package/src/providers/raccoon/login.js +279 -279
  180. package/src/providers/raccoon/models.js +160 -160
  181. package/src/providers/raccoon/password-login.js +102 -102
  182. package/src/providers/raccoon/qr-codewords.js +115 -115
  183. package/src/providers/raccoon/qr.js +236 -236
  184. package/src/providers/raccoon/sse.js +135 -135
  185. package/src/providers/responses-channel.js +120 -120
  186. package/src/providers/share-keys.js +53 -53
  187. package/src/providers/traework/account-store.js +234 -234
  188. package/src/providers/traework/chat.js +217 -217
  189. package/src/providers/traework/checkin.js +77 -77
  190. package/src/providers/traework/constants.js +41 -41
  191. package/src/providers/traework/errors.js +52 -52
  192. package/src/providers/traework/headers.js +79 -79
  193. package/src/providers/traework/index.js +132 -132
  194. package/src/providers/traework/market-identity.js +116 -116
  195. package/src/providers/traework/models.js +98 -98
  196. package/src/providers/traework/payload.js +86 -86
  197. package/src/providers/traework/sse.js +184 -184
  198. package/src/providers/traework/token.js +52 -52
  199. package/src/providers/traework.js +2 -2
  200. package/src/providers/workbuddy/account-store.js +186 -186
  201. package/src/providers/workbuddy/auth.js +158 -158
  202. package/src/providers/workbuddy/balance.js +86 -86
  203. package/src/providers/workbuddy/cat-travel.js +125 -125
  204. package/src/providers/workbuddy/checkin.js +75 -75
  205. package/src/providers/workbuddy/desktop-info.js +78 -78
  206. package/src/providers/workbuddy/growth-api.js +67 -67
  207. package/src/providers/workbuddy/growth-plans.js +63 -63
  208. package/src/providers/workbuddy/growth.js +181 -181
  209. package/src/providers/workbuddy/index.js +217 -217
  210. package/src/providers/workbuddy/models.js +126 -126
  211. package/src/providers/workbuddy/payload.js +141 -141
  212. package/src/providers/workbuddy/rotation-log.js +83 -83
  213. package/src/providers/workbuddy/sanitize-tools.js +61 -61
  214. package/src/providers/workbuddy/sdk-chat.js +26 -26
  215. package/src/providers/workbuddy-balance.js +78 -78
  216. package/src/providers/zcode/account-store.js +129 -129
  217. package/src/providers/zcode/auth.js +28 -28
  218. package/src/providers/zcode/chat.js +179 -179
  219. package/src/providers/zcode/const.js +54 -54
  220. package/src/providers/zcode/context-shape.js +162 -162
  221. package/src/providers/zcode/headers.js +93 -93
  222. package/src/providers/zcode/index.js +124 -124
  223. package/src/providers/zcode/models.js +65 -65
  224. package/src/providers/zcode/oauth.js +120 -120
  225. package/src/providers/zcode/quota.js +176 -176
  226. package/src/providers/zcode/sse.js +196 -196
  227. package/src/readline-compat.js +25 -25
  228. package/src/responses/translate.js +311 -311
  229. package/src/routes/AGENTS.md +37 -0
  230. package/src/routes/chat/broadband-handler.js +72 -72
  231. package/src/routes/chat/empty-turn-report.js +31 -31
  232. package/src/routes/chat/exhausted-handler.js +87 -87
  233. package/src/routes/chat/hedge-handler.js +130 -130
  234. package/src/routes/chat/index.js +1 -1
  235. package/src/routes/chat/local-handler.js +63 -63
  236. package/src/routes/chat/peer-handler.js +81 -81
  237. package/src/routes/chat.js +3 -3
  238. package/src/routes/fallback.js +88 -88
  239. package/src/routes/groups-relay.js +214 -214
  240. package/src/routes/groups.js +122 -122
  241. package/src/routes/helpers.js +93 -83
  242. package/src/routes/index.js +147 -147
  243. package/src/routes/messages-route.js +375 -365
  244. package/src/routes/peers.js +10 -2
  245. package/src/routes/relay-queue.js +181 -181
  246. package/src/routes/relay.js +60 -60
  247. package/src/routes/responses-route.js +213 -213
  248. package/src/routes/stream-body.js +84 -84
  249. package/src/routes/stream-hold.js +337 -337
  250. package/src/routes/stream-scan.js +366 -366
  251. package/src/routes.js +3 -3
  252. package/src/runtime/auto-update.js +113 -113
  253. package/src/runtime/broadband-stream.js +79 -79
  254. package/src/runtime/broadband.js +103 -103
  255. package/src/runtime/group-sync.js +81 -81
  256. package/src/runtime/keep-warm.js +120 -120
  257. package/src/runtime/lifecycle-forensics.js +116 -116
  258. package/src/runtime/lifecycle-log.js +87 -87
  259. package/src/runtime/log-stamp.js +73 -73
  260. package/src/runtime/proc-info.js +137 -137
  261. package/src/runtime/qoder-checkin.js +93 -93
  262. package/src/runtime/raccoon-checkin.js +126 -126
  263. package/src/runtime/server-lifecycle.js +189 -189
  264. package/src/runtime/traework-checkin.js +118 -118
  265. package/src/runtime/workbuddy-checkin.js +120 -120
  266. package/src/runtime/workbuddy-growth.js +133 -133
  267. package/src/state/facade.js +58 -58
  268. package/src/state/memory.js +162 -162
  269. package/src/state/merge.js +25 -25
  270. package/src/state/migrations/cline-unify.js +94 -94
  271. package/src/state/migrations.js +33 -33
  272. package/src/state/persist.js +42 -42
  273. package/src/state/provider-config.js +142 -142
  274. package/src/state/schemas/group.js +31 -31
  275. package/src/state/schemas/model.js +94 -94
  276. package/src/state/schemas/peer.js +31 -31
  277. package/src/state/schemas/port.js +10 -10
  278. package/src/state/schemas/provider.js +202 -202
  279. package/src/state/schemas/timezone.js +70 -70
  280. package/src/state/schemas/token.js +48 -48
  281. package/src/state/schemas/use-group.js +102 -102
  282. package/src/state/store.js +176 -176
  283. package/src/state.js +1 -1
  284. package/src/sync-claude-desktop.js +234 -234
  285. package/src/sync-claude.js +152 -152
  286. package/src/sync-codex.js +116 -116
  287. package/src/sync-workbuddy.js +158 -158
  288. package/src/talk-full-redact.js +129 -129
  289. package/src/talk-full.js +131 -131
  290. package/src/talk-log.js +257 -257
  291. package/src/text-tokens.js +52 -52
  292. package/src/thinking-effort.js +67 -67
  293. package/src/time.js +106 -106
  294. package/src/timeline.js +26 -26
  295. package/src/transport/index.js +1 -1
  296. package/src/upstream-engine/index.js +74 -74
  297. package/src/upstream-engine/mode.js +15 -15
  298. package/src/upstream-engine/sdk/attempt.js +221 -221
  299. package/src/upstream-engine/sdk/chat.js +28 -28
  300. package/src/upstream-engine/sdk/convert.js +192 -192
  301. package/src/upstream-engine/sdk/diagnose.js +62 -62
  302. package/src/upstream-engine/sdk/dispatch.js +55 -55
  303. package/src/upstream-engine/sdk/responses.js +176 -176
  304. package/src/upstream-engine/sdk/sse.js +166 -166
  305. package/src/upstream-responses.js +305 -305
  306. package/src/usage/cache-fields.js +58 -0
  307. package/src/usage/record.js +109 -106
  308. package/src/usage/report.js +209 -195
  309. package/src/v6pool/claim.js +157 -157
  310. package/src/v6pool/config.js +65 -65
  311. package/src/v6pool/detect.js +130 -130
  312. package/src/v6pool/index.js +152 -152
  313. package/src/v6pool/prefix.js +140 -140
  314. package/src/v6pool/probe.js +40 -40
  315. package/src/v6pool/report.js +104 -104
  316. package/src/v6pool/rotate.js +263 -263
  317. package/src/warp-pool/config.js +74 -74
  318. package/src/warp-pool/health.js +106 -106
  319. package/src/warp-pool/identity.js +141 -141
  320. package/src/warp-pool/index.js +358 -358
  321. package/src/warp-pool/keys.js +29 -29
  322. package/src/warp-pool/nodes.js +95 -95
  323. package/src/warp-pool/ports.js +160 -160
  324. package/src/warp-pool/register.js +113 -113
  325. package/src/warp-pool/report.js +232 -232
  326. package/src/warp-pool/revive.js +168 -168
  327. package/src/warp-pool/rotate.js +214 -214
  328. package/src/warp-pool/strategy.js +43 -43
  329. package/src/warp-pool/verdict.js +69 -69
  330. package/src/warp-pool/wireproxy.js +162 -162
@@ -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
+ }