@jeik/dingtalk-connector 0.8.21-fix1

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 (154) hide show
  1. package/CHANGELOG.md +686 -0
  2. package/LICENSE +21 -0
  3. package/README.en.md +181 -0
  4. package/README.md +221 -0
  5. package/bin/dingtalk-connector.js +858 -0
  6. package/bin/wizard-config.mjs +110 -0
  7. package/dist/accounts-BAzdqkAV.mjs +268 -0
  8. package/dist/accounts-BQptOmgB.mjs +2 -0
  9. package/dist/chunk-upload-BBQgGtcZ.mjs +193 -0
  10. package/dist/chunk-upload-DaLXXZH3.mjs +2 -0
  11. package/dist/common-C8pYKU_y.mjs +2 -0
  12. package/dist/common-Dt9n6fQN.mjs +101 -0
  13. package/dist/connection-DHHFFNQJ.mjs +423 -0
  14. package/dist/entry-bundled.d.mts +16 -0
  15. package/dist/entry-bundled.mjs +31 -0
  16. package/dist/game-xiyou-CqHt-6Q1.mjs +4271 -0
  17. package/dist/gateway-methods-C4tcgI7P.mjs +771 -0
  18. package/dist/gateway-methods-Ci31A3vg.mjs +2 -0
  19. package/dist/http-client-CpnJHB89.mjs +2 -0
  20. package/dist/http-client-DFWZgO1n.mjs +33 -0
  21. package/dist/index.d.mts +193 -0
  22. package/dist/index.mjs +45 -0
  23. package/dist/logger-BmJkQkm1.mjs +2 -0
  24. package/dist/logger-mZ9OSbmD.mjs +58 -0
  25. package/dist/media-C_SVin7s.mjs +2 -0
  26. package/dist/media-cz72EVS3.mjs +509 -0
  27. package/dist/message-handler-DESzFFDc.mjs +1971 -0
  28. package/dist/messaging-B6l1sRvX.mjs +1044 -0
  29. package/dist/runtime-DUgpo5zC.mjs +1422 -0
  30. package/dist/session-DJ4jYqPv.mjs +114 -0
  31. package/dist/utils-Bjh4r_qS.mjs +4 -0
  32. package/dist/utils-CIfI_3Jh.mjs +63 -0
  33. package/dist/utils-legacy-CALCPP1t.mjs +230 -0
  34. package/dist/utils-legacy-CFYDBM4r.mjs +3 -0
  35. package/docs/DEAP_AGENT_GUIDE.en.md +115 -0
  36. package/docs/DEAP_AGENT_GUIDE.md +115 -0
  37. package/docs/DINGTALK_MANUAL_SETUP.md +50 -0
  38. package/docs/MULTI_AGENT_SETUP.md +306 -0
  39. package/docs/RELEASE_NOTES_V0.7.10.md +40 -0
  40. package/docs/RELEASE_NOTES_V0.7.2.md +143 -0
  41. package/docs/RELEASE_NOTES_V0.7.3.md +149 -0
  42. package/docs/RELEASE_NOTES_V0.7.4.md +206 -0
  43. package/docs/RELEASE_NOTES_V0.7.5.md +267 -0
  44. package/docs/RELEASE_NOTES_V0.7.6.md +219 -0
  45. package/docs/RELEASE_NOTES_V0.7.7.md +122 -0
  46. package/docs/RELEASE_NOTES_V0.7.8.md +101 -0
  47. package/docs/RELEASE_NOTES_V0.7.9.md +65 -0
  48. package/docs/RELEASE_NOTES_V0.8.0.md +53 -0
  49. package/docs/RELEASE_NOTES_V0.8.1.md +47 -0
  50. package/docs/RELEASE_NOTES_V0.8.10.md +49 -0
  51. package/docs/RELEASE_NOTES_V0.8.11.md +51 -0
  52. package/docs/RELEASE_NOTES_V0.8.12.md +63 -0
  53. package/docs/RELEASE_NOTES_V0.8.13-beta.0.md +69 -0
  54. package/docs/RELEASE_NOTES_V0.8.13.md +62 -0
  55. package/docs/RELEASE_NOTES_V0.8.14.md +86 -0
  56. package/docs/RELEASE_NOTES_V0.8.16.md +40 -0
  57. package/docs/RELEASE_NOTES_V0.8.17.md +87 -0
  58. package/docs/RELEASE_NOTES_V0.8.18.md +64 -0
  59. package/docs/RELEASE_NOTES_V0.8.19.md +62 -0
  60. package/docs/RELEASE_NOTES_V0.8.2.md +55 -0
  61. package/docs/RELEASE_NOTES_V0.8.20.md +49 -0
  62. package/docs/RELEASE_NOTES_V0.8.3.md +63 -0
  63. package/docs/RELEASE_NOTES_V0.8.4.md +45 -0
  64. package/docs/RELEASE_NOTES_V0.8.7.md +49 -0
  65. package/docs/RELEASE_NOTES_V0.8.8.md +63 -0
  66. package/docs/RELEASE_NOTES_V0.8.9.md +81 -0
  67. package/docs/RELEASE_NOTES_v0.7.0.md +142 -0
  68. package/docs/RELEASE_NOTES_v0.7.1.md +74 -0
  69. package/docs/TROUBLESHOOTING.md +122 -0
  70. package/index.ts +77 -0
  71. package/openclaw.plugin.json +551 -0
  72. package/package.json +147 -0
  73. package/skills/dingtalk-channel-rules/SKILL.md +91 -0
  74. package/skills/dingtalk-troubleshoot/SKILL.md +93 -0
  75. package/skills/dws-cli/SKILL.md +129 -0
  76. package/skills/dws-cli/references/error-codes.md +95 -0
  77. package/skills/dws-cli/references/field-rules.md +105 -0
  78. package/skills/dws-cli/references/global-reference.md +104 -0
  79. package/skills/dws-cli/references/intent-guide.md +114 -0
  80. package/skills/dws-cli/references/products/aitable.md +452 -0
  81. package/skills/dws-cli/references/products/attendance.md +93 -0
  82. package/skills/dws-cli/references/products/calendar.md +217 -0
  83. package/skills/dws-cli/references/products/chat.md +292 -0
  84. package/skills/dws-cli/references/products/contact.md +108 -0
  85. package/skills/dws-cli/references/products/ding.md +57 -0
  86. package/skills/dws-cli/references/products/report.md +162 -0
  87. package/skills/dws-cli/references/products/simple.md +128 -0
  88. package/skills/dws-cli/references/products/todo.md +138 -0
  89. package/skills/dws-cli/references/products/workbench.md +39 -0
  90. package/skills/dws-cli/references/recovery-guide.md +94 -0
  91. package/src/channel.ts +588 -0
  92. package/src/config/accounts.ts +242 -0
  93. package/src/config/schema.ts +180 -0
  94. package/src/core/connection.ts +741 -0
  95. package/src/core/message-handler.ts +1788 -0
  96. package/src/core/provider.ts +111 -0
  97. package/src/core/state.ts +54 -0
  98. package/src/device-auth-config.ts +14 -0
  99. package/src/device-auth.ts +197 -0
  100. package/src/directory.ts +95 -0
  101. package/src/docs.ts +293 -0
  102. package/src/game-xiyou/achievement-engine.ts +252 -0
  103. package/src/game-xiyou/bounty-system.ts +315 -0
  104. package/src/game-xiyou/commands.ts +223 -0
  105. package/src/game-xiyou/drop-engine.ts +241 -0
  106. package/src/game-xiyou/encounter-system.ts +135 -0
  107. package/src/game-xiyou/escape-engine.ts +164 -0
  108. package/src/game-xiyou/exp-calculator.ts +139 -0
  109. package/src/game-xiyou/index.ts +479 -0
  110. package/src/game-xiyou/level-system.ts +91 -0
  111. package/src/game-xiyou/monster-pool.ts +180 -0
  112. package/src/game-xiyou/pity-counter.ts +114 -0
  113. package/src/game-xiyou/random-event-engine.ts +648 -0
  114. package/src/game-xiyou/renderer.ts +679 -0
  115. package/src/game-xiyou/storage.ts +218 -0
  116. package/src/game-xiyou/treasure-system.ts +105 -0
  117. package/src/game-xiyou/types.ts +582 -0
  118. package/src/game-xiyou/uid-resolver.ts +49 -0
  119. package/src/gateway-methods.ts +740 -0
  120. package/src/onboarding.ts +553 -0
  121. package/src/policy.ts +32 -0
  122. package/src/probe.ts +210 -0
  123. package/src/reply-dispatcher.ts +874 -0
  124. package/src/runtime.ts +32 -0
  125. package/src/sdk/helpers.ts +322 -0
  126. package/src/sdk/types.ts +519 -0
  127. package/src/secret-input.ts +19 -0
  128. package/src/services/media/audio.ts +54 -0
  129. package/src/services/media/chunk-upload.ts +296 -0
  130. package/src/services/media/common.ts +155 -0
  131. package/src/services/media/file.ts +75 -0
  132. package/src/services/media/image.ts +81 -0
  133. package/src/services/media/index.ts +10 -0
  134. package/src/services/media/video.ts +162 -0
  135. package/src/services/media.ts +1143 -0
  136. package/src/services/messaging/card.ts +604 -0
  137. package/src/services/messaging/index.ts +18 -0
  138. package/src/services/messaging/mentions.ts +267 -0
  139. package/src/services/messaging/send.ts +141 -0
  140. package/src/services/messaging.ts +1191 -0
  141. package/src/services/reply-markers.ts +55 -0
  142. package/src/targets.ts +45 -0
  143. package/src/types/index.ts +59 -0
  144. package/src/types/pdf-parse.d.ts +3 -0
  145. package/src/utils/agent.ts +63 -0
  146. package/src/utils/async.ts +51 -0
  147. package/src/utils/constants.ts +27 -0
  148. package/src/utils/http-client.ts +38 -0
  149. package/src/utils/index.ts +8 -0
  150. package/src/utils/logger.ts +78 -0
  151. package/src/utils/session.ts +147 -0
  152. package/src/utils/token.ts +93 -0
  153. package/src/utils/utils-legacy.ts +454 -0
  154. package/tsconfig.json +20 -0
@@ -0,0 +1,582 @@
1
+ /**
2
+ * 西游妖魔榜养成系统 - 类型定义
3
+ *
4
+ * 核心概念:每次通过 agent 成功调用 dws CLI,就是一次"降妖除魔"。
5
+ * 妖怪按品质随机掉落,神仙按机缘随机现身,所有数据与用户 UID 强绑定。
6
+ */
7
+
8
+ // ============ 品质与分级 ============
9
+
10
+ export type MonsterQuality = 'normal' | 'fine' | 'rare' | 'epic' | 'legendary' | 'shiny';
11
+
12
+ export const QUALITY_LABELS: Record<MonsterQuality, string> = {
13
+ normal: '🪨 普通',
14
+ fine: '🌿 精良',
15
+ rare: '💎 稀有',
16
+ epic: '🔮 史诗',
17
+ legendary: '👑 传说',
18
+ shiny: '✨ 闪光',
19
+ };
20
+
21
+ export const QUALITY_ORDER: MonsterQuality[] = [
22
+ 'normal', 'fine', 'rare', 'epic', 'legendary', 'shiny',
23
+ ];
24
+
25
+ // ============ 妖怪 ============
26
+
27
+ export interface Monster {
28
+ id: string;
29
+ name: string;
30
+ emoji: string;
31
+ quality: MonsterQuality;
32
+ origin: string;
33
+ relatedProduct: string | null;
34
+ captureQuote: string;
35
+ }
36
+
37
+ export interface CapturedMonster {
38
+ monsterId: string;
39
+ capturedAt: number;
40
+ isShiny: boolean;
41
+ commandHash: string;
42
+ comboCount: number;
43
+ }
44
+
45
+ // ============ 神仙 ============
46
+
47
+ export type EncounterType = 'guidance' | 'treasure' | 'apprentice';
48
+
49
+ export interface Immortal {
50
+ id: string;
51
+ name: string;
52
+ guidanceQuote: string;
53
+ treasureId: string;
54
+ apprenticeBuff: Buff;
55
+ }
56
+
57
+ export interface Encounter {
58
+ immortalId: string;
59
+ type: EncounterType;
60
+ treasureId?: string;
61
+ buffId?: string;
62
+ occurredAt: number;
63
+ }
64
+
65
+ // ============ 法宝 ============
66
+
67
+ export type BuffEffect =
68
+ | 'comboBonus'
69
+ | 'expMultiplier'
70
+ | 'pityReduction'
71
+ | 'epicRateBonus'
72
+ | 'rareRateBonus'
73
+ | 'legendaryRateBonus'
74
+ | 'shinyRateBonus'
75
+ | 'allRateBonus'
76
+ | 'signInMultiplier'
77
+ | 'comboLimitBonus'
78
+ | 'normalUpgrade'
79
+ | 'instantExp'
80
+ | 'extraDrop'
81
+ | 'pitySpeed'
82
+ | 'previewNextQuality'
83
+ | 'cliRetry';
84
+
85
+ export interface Buff {
86
+ id: string;
87
+ source: 'treasure' | 'apprentice' | 'achievement';
88
+ effect: BuffEffect;
89
+ value: number;
90
+ }
91
+
92
+ export interface Treasure {
93
+ id: string;
94
+ name: string;
95
+ source: string;
96
+ description: string;
97
+ effect: BuffEffect;
98
+ value: number;
99
+ consumable: boolean;
100
+ }
101
+
102
+ // ============ 成就 ============
103
+
104
+ export type AchievementCategory = 'cultivation' | 'collection' | 'product' | 'hidden';
105
+
106
+ export interface Achievement {
107
+ id: string;
108
+ name: string;
109
+ emoji: string;
110
+ description: string;
111
+ category: AchievementCategory;
112
+ condition: AchievementCondition;
113
+ expReward: number;
114
+ titleReward?: string;
115
+ }
116
+
117
+ export type AchievementCondition =
118
+ | { type: 'totalOperations'; count: number }
119
+ | { type: 'consecutiveSignIn'; days: number }
120
+ | { type: 'maxCombo'; count: number }
121
+ | { type: 'totalRecoveries'; count: number }
122
+ | { type: 'uniqueMonsters'; count: number }
123
+ | { type: 'shinyMonsters'; count: number }
124
+ | { type: 'productUsage'; product: string; count: number }
125
+ | { type: 'allProducts' }
126
+ | { type: 'dailyOperations'; count: number }
127
+ | { type: 'nightOwl' }
128
+ | { type: 'pityTriggered' }
129
+ | { type: 'consecutiveFailThenSuccess'; failCount: number }
130
+ | { type: 'dailyRareOrAbove'; count: number }
131
+ | { type: 'birthday' }
132
+ | { type: 'consecutiveReport'; days: number }
133
+ // v2: 逃跑相关
134
+ | { type: 'totalEscapes'; count: number }
135
+ | { type: 'consecutiveNoEscape'; count: number }
136
+ // v2: 悬赏令相关
137
+ | { type: 'totalBountiesCompleted'; count: number }
138
+ | { type: 'goldBountiesCompleted'; count: number }
139
+ | { type: 'consecutiveFullClear'; days: number }
140
+ // v2: 随机事件相关
141
+ | { type: 'totalEventsTriggered'; count: number }
142
+ | { type: 'challengesCompleted'; count: number }
143
+ | { type: 'survivedMadness' }
144
+ | { type: 'specificEventCount'; eventId: string; count: number }
145
+ | { type: 'specificChallengeSuccess'; eventId: string }
146
+ | { type: 'disasterThenBlessing' }
147
+ | { type: 'disastersResolved'; count: number };
148
+
149
+ // ============ 等级 ============
150
+
151
+ export interface LevelDefinition {
152
+ level: number;
153
+ title: string;
154
+ requiredExp: number;
155
+ unlockDescription?: string;
156
+ }
157
+
158
+ export const LEVEL_DEFINITIONS: LevelDefinition[] = [
159
+ { level: 1, title: '凡人', requiredExp: 0, unlockDescription: '基础掉落池' },
160
+ { level: 2, title: '樵夫', requiredExp: 120 },
161
+ { level: 3, title: '修行者', requiredExp: 320, unlockDescription: '解锁"机缘"系统(神仙随机现身)' },
162
+ { level: 4, title: '散仙', requiredExp: 800, unlockDescription: '掉落池扩展:加入稀有妖怪' },
163
+ { level: 5, title: '天兵', requiredExp: 2000, unlockDescription: '解锁"法宝"系统' },
164
+ { level: 6, title: '天将', requiredExp: 4000, unlockDescription: '掉落池扩展:加入史诗妖怪' },
165
+ { level: 7, title: '哪吒', requiredExp: 8000, unlockDescription: '连击加成上限提升至 ×4.0' },
166
+ { level: 8, title: '二郎神', requiredExp: 16000, unlockDescription: '掉落池扩展:加入传说妖怪' },
167
+ { level: 9, title: '齐天大圣', requiredExp: 32000, unlockDescription: '解锁"闪光"掉落' },
168
+ { level: 10, title: '斗战胜佛', requiredExp: 60000, unlockDescription: '全图鉴解锁提示、专属称号色' },
169
+ ];
170
+
171
+ // ============ 产品修行值 ============
172
+
173
+ export const PRODUCT_BASE_EXP: Record<string, number> = {
174
+ aitable: 3,
175
+ calendar: 2,
176
+ chat: 2,
177
+ contact: 1,
178
+ todo: 2,
179
+ approval: 4,
180
+ attendance: 2,
181
+ report: 3,
182
+ ding: 1,
183
+ workbench: 3,
184
+ devdoc: 1,
185
+ };
186
+
187
+ // ============ 保底计数器 ============
188
+
189
+ export interface PityCounters {
190
+ sinceLastRare: number;
191
+ sinceLastEpic: number;
192
+ sinceLastLegendary: number;
193
+ totalDropsWithoutShiny: number;
194
+ }
195
+
196
+ /** v2: 保底阈值上调 */
197
+ export const PITY_THRESHOLDS = {
198
+ rare: 30,
199
+ epic: 80,
200
+ legendary: 150,
201
+ shiny: 800,
202
+ } as const;
203
+
204
+ /** v2: 软保底起始点 — 接近硬保底时概率逐步提升 */
205
+ export const SOFT_PITY_START = {
206
+ rare: 20,
207
+ epic: 60,
208
+ legendary: 120,
209
+ shiny: 600,
210
+ } as const;
211
+
212
+ /** v2: 软保底每次额外增加的概率 */
213
+ export const SOFT_PITY_RATE_PER_STEP = {
214
+ rare: 0.03,
215
+ epic: 0.02,
216
+ legendary: 0.01,
217
+ shiny: 0.0005,
218
+ } as const;
219
+
220
+ // ============ 逃跑机制 (v2) ============
221
+
222
+ /** 各品质的基础逃跑率 */
223
+ export const BASE_ESCAPE_RATES: Record<MonsterQuality, number> = {
224
+ normal: 0,
225
+ fine: 0.10,
226
+ rare: 0.25,
227
+ epic: 0.40,
228
+ legendary: 0.60,
229
+ shiny: 0.75,
230
+ };
231
+
232
+ /** 逃跑率的最低下限 */
233
+ export const MIN_ESCAPE_RATE = 0.05;
234
+
235
+ export interface EscapeModifier {
236
+ source: string;
237
+ value: number;
238
+ description: string;
239
+ }
240
+
241
+ // ============ 悬赏令 (v2) ============
242
+
243
+ export type BountyTier = 'bronze' | 'silver' | 'gold';
244
+
245
+ export type BountyConditionType =
246
+ | 'capture'
247
+ | 'combo'
248
+ | 'command'
249
+ | 'encounter'
250
+ | 'product_variety'
251
+ | 'quality_variety';
252
+
253
+ export interface BountyCondition {
254
+ type: BountyConditionType;
255
+ qualityMin?: MonsterQuality;
256
+ product?: string;
257
+ count: number;
258
+ isUpMonster?: boolean;
259
+ isNew?: boolean;
260
+ }
261
+
262
+ export interface BountyReward {
263
+ exp: number;
264
+ treasureFragment?: string;
265
+ buff?: TemporaryBuff;
266
+ }
267
+
268
+ export interface TemporaryBuff {
269
+ effect: BuffEffect;
270
+ value: number;
271
+ description: string;
272
+ durationOperations?: number;
273
+ }
274
+
275
+ export interface Bounty {
276
+ id: string;
277
+ tier: BountyTier;
278
+ description: string;
279
+ target: number;
280
+ current: number;
281
+ completed: boolean;
282
+ reward: BountyReward;
283
+ condition: BountyCondition;
284
+ }
285
+
286
+ export interface DailyBountyState {
287
+ date: string;
288
+ bounties: Bounty[];
289
+ completedCount: number;
290
+ }
291
+
292
+ export interface BountyHistory {
293
+ totalCompleted: number;
294
+ bronzeCompleted: number;
295
+ silverCompleted: number;
296
+ goldCompleted: number;
297
+ consecutiveFullClear: number;
298
+ }
299
+
300
+ // ============ 随机事件 (v2) ============
301
+
302
+ export type EventCategory = 'blessing' | 'challenge' | 'disaster';
303
+
304
+ export type EventEffectType =
305
+ | 'exp_multiplier'
306
+ | 'quality_boost'
307
+ | 'extra_drop'
308
+ | 'product_weight'
309
+ | 'escape_rate_mod'
310
+ | 'exp_flat'
311
+ | 'treasure_grant'
312
+ | 'monster_escape'
313
+ | 'quality_cap'
314
+ | 'exp_halve'
315
+ | 'combo_reset'
316
+ | 'no_drop'
317
+ | 'exp_loss'
318
+ | 'pity_loss';
319
+
320
+ export interface EventEffect {
321
+ type: EventEffectType;
322
+ value: number;
323
+ targetCount?: number;
324
+ }
325
+
326
+ export interface EventDuration {
327
+ type: 'instant' | 'operation_count' | 'drop_count';
328
+ total: number;
329
+ remaining: number;
330
+ }
331
+
332
+ export interface EventResolution {
333
+ type: 'consecutive_success' | 'use_treasure' | 'complete_bounty' | 'trigger_encounter';
334
+ count?: number;
335
+ treasureId?: string;
336
+ description: string;
337
+ }
338
+
339
+ export interface RandomEvent {
340
+ id: string;
341
+ name: string;
342
+ category: EventCategory;
343
+ triggerRate: number;
344
+ description: string;
345
+ flavorText: string;
346
+ effect: EventEffect;
347
+ duration: EventDuration;
348
+ resolution?: EventResolution;
349
+ }
350
+
351
+ export type ChallengeConditionType =
352
+ | 'consecutive_success'
353
+ | 'product_variety'
354
+ | 'capture_count'
355
+ | 'success_rate'
356
+ | 'pick_correct';
357
+
358
+ export interface ChallengeCondition {
359
+ type: ChallengeConditionType;
360
+ target: number;
361
+ current: number;
362
+ }
363
+
364
+ export interface ChallengeProgress {
365
+ operationsUsed: number;
366
+ operationLimit: number;
367
+ conditionMet: boolean;
368
+ /** 挑战期间使用过的不同产品(用于 product_variety 条件) */
369
+ usedProducts?: string[];
370
+ }
371
+
372
+ export interface EventReward {
373
+ exp: number;
374
+ pityBonus?: number;
375
+ escapeRateMod?: number;
376
+ extraDrop?: boolean;
377
+ treasureFragment?: string;
378
+ monster?: { qualityMin: MonsterQuality };
379
+ }
380
+
381
+ export interface EventPenalty {
382
+ expLoss: number;
383
+ comboReset?: boolean;
384
+ pityLoss?: number;
385
+ }
386
+
387
+ export interface ChallengeEvent extends RandomEvent {
388
+ category: 'challenge';
389
+ challengeCondition: ChallengeCondition;
390
+ successReward: EventReward;
391
+ failurePenalty: EventPenalty;
392
+ operationLimit: number;
393
+ progress: ChallengeProgress;
394
+ }
395
+
396
+ export interface ActiveEventState {
397
+ currentEvents: RandomEvent[];
398
+ activeChallenge: ChallengeEvent | null;
399
+ lastEventTriggerTime: Record<string, number>;
400
+ }
401
+
402
+ export interface EventHistoryEntry {
403
+ eventId: string;
404
+ triggeredAt: number;
405
+ outcome?: 'success' | 'failure' | 'resolved' | 'expired';
406
+ }
407
+
408
+ export interface EventStats {
409
+ totalTriggered: number;
410
+ challengesCompleted: number;
411
+ challengesFailed: number;
412
+ disastersResolved: number;
413
+ }
414
+
415
+ // ============ 用户档案 ============
416
+
417
+ export interface GamificationSettings {
418
+ enabled: boolean;
419
+ showDropAnimation: boolean;
420
+ muteNormalDrops: boolean;
421
+ }
422
+
423
+ export interface UserProfile {
424
+ uidHash: string;
425
+ level: number;
426
+ title: string;
427
+ totalExp: number;
428
+ totalOperations: number;
429
+ currentCombo: number;
430
+ maxCombo: number;
431
+ consecutiveSignInDays: number;
432
+ lastSignInDate: string;
433
+ totalRecoveries: number;
434
+ consecutiveFailures: number;
435
+ productUsage: Record<string, number>;
436
+ pityCounters: PityCounters;
437
+ buffs: Buff[];
438
+ settings: GamificationSettings;
439
+ encounters: Encounter[];
440
+ unlockedAchievements: string[];
441
+ treasures: string[];
442
+ consumedTreasures: string[];
443
+ createdAt: number;
444
+ checksum: string;
445
+ /** v2: 妖怪逃跑追踪 — monsterId → 连续逃跑次数 */
446
+ escapeHistory: Record<string, number>;
447
+ /** v2: 累计逃跑次数 */
448
+ totalEscapes: number;
449
+ /** v2: 每日悬赏令状态 */
450
+ dailyBounty: DailyBountyState | null;
451
+ /** v2: 悬赏令历史统计 */
452
+ bountyHistory: BountyHistory;
453
+ /** v2: 当前活跃的随机事件 */
454
+ activeEvents: ActiveEventState;
455
+ /** v2: 事件统计 */
456
+ eventStats: EventStats;
457
+ /** v2: 事件历史记录 */
458
+ eventHistory: EventHistoryEntry[];
459
+ }
460
+
461
+ export interface CollectionEntry {
462
+ monsterId: string;
463
+ firstCapturedAt: number;
464
+ captureCount: number;
465
+ isShiny: boolean;
466
+ }
467
+
468
+ export interface UserCollection {
469
+ uidHash: string;
470
+ entries: CollectionEntry[];
471
+ }
472
+
473
+ export interface HistoryRecord {
474
+ timestamp: number;
475
+ product: string;
476
+ commandHash: string;
477
+ success: boolean;
478
+ expGained: number;
479
+ monsterId?: string;
480
+ isShiny?: boolean;
481
+ encounterId?: string;
482
+ achievementIds?: string[];
483
+ /** v2: 妖怪是否逃跑 */
484
+ escaped?: boolean;
485
+ /** v2: 触发的事件 ID */
486
+ eventId?: string;
487
+ /** v2: 完成的悬赏令 ID 列表 */
488
+ completedBountyIds?: string[];
489
+ }
490
+
491
+ export interface UserHistory {
492
+ uidHash: string;
493
+ records: HistoryRecord[];
494
+ }
495
+
496
+ // ============ 掉落结果 ============
497
+
498
+ export interface DropResult {
499
+ monster: Monster;
500
+ isShiny: boolean;
501
+ isNew: boolean;
502
+ expGained: number;
503
+ isPityTriggered: boolean;
504
+ isUpMonster: boolean;
505
+ /** v2: 是否逃跑 */
506
+ escaped: boolean;
507
+ /** v2: 实际逃跑率(含修正) */
508
+ escapeRate: number;
509
+ /** v2: 应用的修正因子列表 */
510
+ escapeModifiers: EscapeModifier[];
511
+ }
512
+
513
+ export interface ExpResult {
514
+ baseExp: number;
515
+ comboMultiplier: number;
516
+ firstUseMultiplier: number;
517
+ signInBonus: number;
518
+ consecutiveSignInBonus: number;
519
+ buffMultiplier: number;
520
+ totalExp: number;
521
+ }
522
+
523
+ export interface LevelUpResult {
524
+ previousLevel: number;
525
+ previousTitle: string;
526
+ newLevel: number;
527
+ newTitle: string;
528
+ unlockDescription?: string;
529
+ }
530
+
531
+ // ============ 引擎输出 ============
532
+
533
+ export interface GamificationOutput {
534
+ expResult: ExpResult;
535
+ dropResult: DropResult;
536
+ encounter: Encounter | null;
537
+ newAchievements: Achievement[];
538
+ levelUp: LevelUpResult | null;
539
+ /** v2: 完成的悬赏令列表 */
540
+ completedBounties: Bounty[];
541
+ /** v2: 触发的随机事件 */
542
+ triggeredEvent: RandomEvent | null;
543
+ }
544
+
545
+ // ============ 掉落概率配置 ============
546
+
547
+ export const DROP_RATES: Record<MonsterQuality, number> = {
548
+ shiny: 0.001,
549
+ legendary: 0.009,
550
+ epic: 0.04,
551
+ rare: 0.10,
552
+ fine: 0.25,
553
+ normal: 0.60,
554
+ };
555
+
556
+ /** 等级门槛:低于此等级的品质会降级 */
557
+ export const QUALITY_LEVEL_GATES: Partial<Record<MonsterQuality, number>> = {
558
+ rare: 4,
559
+ epic: 6,
560
+ legendary: 8,
561
+ shiny: 9,
562
+ };
563
+
564
+ /** 连击加成倍率 */
565
+ export const COMBO_MULTIPLIERS: Array<{ threshold: number; multiplier: number }> = [
566
+ { threshold: 10, multiplier: 3.0 },
567
+ { threshold: 5, multiplier: 2.0 },
568
+ { threshold: 3, multiplier: 1.5 },
569
+ ];
570
+
571
+ /** 机缘触发概率 */
572
+ export const ENCOUNTER_RATES: Record<EncounterType, number> = {
573
+ guidance: 0.08,
574
+ treasure: 0.03,
575
+ apprentice: 0.005,
576
+ };
577
+
578
+ /** 产品关联权重倍数 */
579
+ export const PRODUCT_WEIGHT_MULTIPLIER = 3;
580
+
581
+ /** UP 池权重倍数 */
582
+ export const UP_WEIGHT_MULTIPLIER = 5;
@@ -0,0 +1,49 @@
1
+ /**
2
+ * UID 解析与绑定
3
+ *
4
+ * 优先级链:
5
+ * 1. 钉钉 userId(通过 connector 的 device-auth 获取)
6
+ * 2. 本机 fingerprint(兜底,基于 hostname + username 的 SHA256)
7
+ */
8
+
9
+ import { createHash } from 'crypto';
10
+ import * as os from 'os';
11
+
12
+ const SALT = 'xiyou-salt-2026';
13
+
14
+ /**
15
+ * 根据原始 UID 生成稳定的哈希标识
16
+ */
17
+ export function hashUid(rawUid: string): string {
18
+ return createHash('sha256')
19
+ .update(rawUid + SALT)
20
+ .digest('hex')
21
+ .slice(0, 16);
22
+ }
23
+
24
+ /**
25
+ * 生成本机指纹作为兜底 UID
26
+ */
27
+ function generateMachineFingerprint(): string {
28
+ const hostname = os.hostname();
29
+ const username = os.userInfo().username;
30
+ return `machine:${hostname}:${username}`;
31
+ }
32
+
33
+ /**
34
+ * 解析用户 UID
35
+ *
36
+ * @param senderId - 钉钉消息的发送者 ID(优先使用)
37
+ * @returns 稳定的 UID 哈希值(16 位 hex)
38
+ */
39
+ export function resolveUid(senderId?: string): string {
40
+ const rawUid = senderId || generateMachineFingerprint();
41
+ return hashUid(rawUid);
42
+ }
43
+
44
+ /**
45
+ * 获取 UID 的短标识(用于展示)
46
+ */
47
+ export function getShortUid(uidHash: string): string {
48
+ return uidHash.slice(0, 8);
49
+ }