claude-pet 2.0.0

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.

Potentially problematic release.


This version of claude-pet might be problematic. Click here for more details.

Files changed (133) hide show
  1. package/.claude/commands/feed.md +28 -0
  2. package/.claude/commands/name.md +28 -0
  3. package/.claude/commands/pet.md +29 -0
  4. package/.claude/commands/play.md +29 -0
  5. package/.claude/settings.local.json +41 -0
  6. package/.github/workflows/AGENTS.md +60 -0
  7. package/.github/workflows/build.yml +87 -0
  8. package/AGENTS.md +66 -0
  9. package/LICENSE +15 -0
  10. package/README.md +292 -0
  11. package/bin/claude-pet.js +42 -0
  12. package/build/AGENTS.md +50 -0
  13. package/build/dmg-background.png +0 -0
  14. package/build/entitlements.mac.plist +14 -0
  15. package/build/icon.ico +0 -0
  16. package/build/icon.png +0 -0
  17. package/build/installerHeader.bmp +0 -0
  18. package/build/installerSidebar.bmp +0 -0
  19. package/build/tray-icon.png +0 -0
  20. package/dist/main/core/badge-manager.js +49 -0
  21. package/dist/main/core/badge-registry.js +72 -0
  22. package/dist/main/core/badge-triggers.js +45 -0
  23. package/dist/main/core/contextual-messages.js +372 -0
  24. package/dist/main/core/messages.js +440 -0
  25. package/dist/main/core/mood-engine.js +145 -0
  26. package/dist/main/core/pet-messages.js +612 -0
  27. package/dist/main/core/pet-state-engine.js +232 -0
  28. package/dist/main/core/quote-collection.js +60 -0
  29. package/dist/main/core/quote-registry.js +175 -0
  30. package/dist/main/core/quote-triggers.js +62 -0
  31. package/dist/main/core/usage-tracker.js +625 -0
  32. package/dist/main/main/auto-launch.js +39 -0
  33. package/dist/main/main/auto-updater.js +98 -0
  34. package/dist/main/main/event-watcher.js +174 -0
  35. package/dist/main/main/ipc-handlers.js +89 -0
  36. package/dist/main/main/main.js +422 -0
  37. package/dist/main/main/preload.js +93 -0
  38. package/dist/main/main/settings-window.js +49 -0
  39. package/dist/main/main/share-card.js +139 -0
  40. package/dist/main/main/skin-manager.js +118 -0
  41. package/dist/main/main/tray.js +88 -0
  42. package/dist/main/shared/i18n.js +392 -0
  43. package/dist/main/shared/types.js +25 -0
  44. package/dist/main/shared/utils.js +9 -0
  45. package/dist/renderer/assets/claude-pet.png +0 -0
  46. package/dist/renderer/assets/index-BMnMEuOf.js +9 -0
  47. package/dist/renderer/assets/index-qzlrlqpX.css +1 -0
  48. package/dist/renderer/index.html +30 -0
  49. package/dist/renderer/share-card-template/card.html +148 -0
  50. package/docs/AGENTS.md +42 -0
  51. package/docs/images/angry.png +0 -0
  52. package/docs/images/character.webp +0 -0
  53. package/docs/images/claude-mama.png +0 -0
  54. package/docs/images/happy.png +0 -0
  55. package/docs/images/proud.png +0 -0
  56. package/docs/images/share-card-example.png +0 -0
  57. package/docs/images/worried_1.png +0 -0
  58. package/docs/images/worried_2.png +0 -0
  59. package/docs/spritesheet-bugs.md +240 -0
  60. package/docs/superpowers/plans/2026-03-10-compact-widget.md +888 -0
  61. package/docs/superpowers/plans/2026-03-10-viral-features.md +1874 -0
  62. package/docs/superpowers/plans/2026-03-14-update-ux.md +362 -0
  63. package/docs/superpowers/plans/2026-03-14-v1.1-features.md +2139 -0
  64. package/docs/superpowers/specs/2026-03-10-compact-widget-design.md +150 -0
  65. package/docs/superpowers/specs/2026-03-10-viral-features-design.md +217 -0
  66. package/docs/superpowers/specs/2026-03-14-streak-calendar-design.md +26 -0
  67. package/docs/superpowers/specs/2026-03-14-update-ux-design.md +172 -0
  68. package/docs/superpowers/specs/2026-03-14-v1.1-features-design.md +342 -0
  69. package/electron-builder.yml +75 -0
  70. package/package.json +48 -0
  71. package/scripts/AGENTS.md +60 -0
  72. package/scripts/install.ps1 +47 -0
  73. package/scripts/install.sh +98 -0
  74. package/scripts/make-icon.js +119 -0
  75. package/scripts/notarize.js +18 -0
  76. package/src/AGENTS.md +47 -0
  77. package/src/core/AGENTS.md +58 -0
  78. package/src/core/__tests__/AGENTS.md +60 -0
  79. package/src/core/__tests__/badge-triggers.test.ts +83 -0
  80. package/src/core/__tests__/contextual-messages.test.ts +87 -0
  81. package/src/core/__tests__/pet-state-engine.test.ts +350 -0
  82. package/src/core/__tests__/quote-collection.test.ts +62 -0
  83. package/src/core/__tests__/quote-triggers.test.ts +110 -0
  84. package/src/core/badge-manager.ts +50 -0
  85. package/src/core/badge-registry.ts +71 -0
  86. package/src/core/badge-triggers.ts +41 -0
  87. package/src/core/contextual-messages.ts +381 -0
  88. package/src/core/pet-messages.ts +615 -0
  89. package/src/core/pet-state-engine.ts +272 -0
  90. package/src/core/quote-collection.ts +63 -0
  91. package/src/core/quote-registry.ts +181 -0
  92. package/src/core/quote-triggers.ts +64 -0
  93. package/src/core/usage-tracker.ts +680 -0
  94. package/src/main/AGENTS.md +70 -0
  95. package/src/main/auto-launch.ts +38 -0
  96. package/src/main/auto-updater.ts +106 -0
  97. package/src/main/event-watcher.ts +159 -0
  98. package/src/main/ipc-handlers.ts +107 -0
  99. package/src/main/main.ts +425 -0
  100. package/src/main/preload.ts +111 -0
  101. package/src/main/settings-window.ts +50 -0
  102. package/src/main/share-card.ts +153 -0
  103. package/src/main/skin-manager.ts +119 -0
  104. package/src/main/tray.ts +94 -0
  105. package/src/renderer/AGENTS.md +62 -0
  106. package/src/renderer/App.tsx +270 -0
  107. package/src/renderer/assets/claude-mama.png +0 -0
  108. package/src/renderer/assets/claude-pet.png +0 -0
  109. package/src/renderer/components/AGENTS.md +50 -0
  110. package/src/renderer/components/Character.tsx +327 -0
  111. package/src/renderer/components/SpeechBubble.tsx +182 -0
  112. package/src/renderer/components/UsageIndicator.tsx +268 -0
  113. package/src/renderer/electron.d.ts +34 -0
  114. package/src/renderer/hooks/AGENTS.md +55 -0
  115. package/src/renderer/hooks/usePetState.ts +59 -0
  116. package/src/renderer/hooks/useWidgetMode.ts +18 -0
  117. package/src/renderer/index.html +29 -0
  118. package/src/renderer/main.tsx +13 -0
  119. package/src/renderer/pages/AGENTS.md +53 -0
  120. package/src/renderer/pages/Collection.tsx +252 -0
  121. package/src/renderer/pages/Settings.tsx +815 -0
  122. package/src/renderer/share-card-template/card.html +148 -0
  123. package/src/renderer/styles/AGENTS.md +50 -0
  124. package/src/renderer/styles/styles.css +166 -0
  125. package/src/shared/AGENTS.md +48 -0
  126. package/src/shared/i18n.ts +395 -0
  127. package/src/shared/types.ts +163 -0
  128. package/src/shared/utils.ts +6 -0
  129. package/tsconfig.json +16 -0
  130. package/tsconfig.main.json +12 -0
  131. package/tsconfig.renderer.json +12 -0
  132. package/vite.config.ts +47 -0
  133. package/vitest.config.ts +9 -0
@@ -0,0 +1,372 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.evaluateContextTrigger = evaluateContextTrigger;
4
+ exports.getContextualMessage = getContextualMessage;
5
+ const pet_messages_1 = require("./pet-messages");
6
+ const CONTEXTUAL_POOLS = {
7
+ weekend: {
8
+ bored: {
9
+ ko: [
10
+ '주말인데 토큰 안 쓰면 나 삐질 거야!',
11
+ '주말이라고 나 무시하는 거야?',
12
+ '옆집 강아지도 주말에 열심히 하던데...',
13
+ '토요일인데 심심하게 혼자 있게 할 거야?',
14
+ '주말이라고 방심하면 나 拗ねる다!',
15
+ ],
16
+ en: [
17
+ "It's the weekend and you're ignoring me?!",
18
+ "Not using tokens on a weekend? I'm pouting!",
19
+ "The neighbor's dog works harder on weekends...",
20
+ "Saturday and you're leaving me alone?",
21
+ "Don't slack off just because it's the weekend!",
22
+ ],
23
+ ja: [
24
+ '週末なのにトークン使わないと拗ねるよ!',
25
+ '週末だからって無視するの?',
26
+ '隣の犬も週末頑張ってるのに...',
27
+ '土曜なのに一人にするの?',
28
+ '週末だからって油断したら拗ねるよ!',
29
+ ],
30
+ zh: [
31
+ '周末不用token,我要生气了!',
32
+ '周末就不理我了?',
33
+ '隔壁的狗狗周末也在努力呢...',
34
+ '周六就让我一个人待着?',
35
+ '周末也不能放松啊!',
36
+ ],
37
+ },
38
+ worried: {
39
+ ko: [
40
+ '주말인데 괜찮아? 나 걱정되는데...',
41
+ '주말이니까 쉬어도 되는데, 그래도 좀 써줘~',
42
+ '주말에 쉬는 건 좋은데 혼자 두지는 마~',
43
+ '주말이라 바쁜 거야? 어디 갔어?',
44
+ '주말에도 나는 기다리고 있어...',
45
+ ],
46
+ en: [
47
+ "It's the weekend — are you okay? I'm worried...",
48
+ "Resting on weekends is fine, but use me a little~",
49
+ "Taking a break is great, just don't leave me alone~",
50
+ "Busy this weekend? Where did you go?",
51
+ "I'm waiting for you even on weekends...",
52
+ ],
53
+ ja: [
54
+ '週末だけど大丈夫?心配してるよ...',
55
+ '週末だから休んでもいいけど、少しは使って〜',
56
+ '休むのはいいけど一人にしないで〜',
57
+ '週末は忙しいの?どこ行ったの?',
58
+ '週末も待ってるよ...',
59
+ ],
60
+ zh: [
61
+ '周末没事吧?我在担心你...',
62
+ '周末可以休息,但也用我一下嘛~',
63
+ '休息可以,但别把我一个人留着~',
64
+ '周末是忙还是去哪了?',
65
+ '周末我也在等你...',
66
+ ],
67
+ },
68
+ happy: {
69
+ ko: [
70
+ '주말에도 나랑 놀아줘서 고마워~!',
71
+ '주말인데 쓰다니~ 기특해기특해!',
72
+ '주말도 함께라서 행복해~',
73
+ '주말에 이 정도면 평일엔 얼마나 대단할까~',
74
+ '주말도 알차게 보내는구나~ 나도 기분 좋아!',
75
+ ],
76
+ en: [
77
+ "Thanks for spending the weekend with me~!",
78
+ "Using me on a weekend~ How sweet!",
79
+ "I'm so happy we're together on the weekend~",
80
+ "This much on a weekend? Imagine weekdays~",
81
+ "Making the most of your weekend~ I'm happy too!",
82
+ ],
83
+ ja: [
84
+ '週末も一緒に遊んでくれてありがとう〜!',
85
+ '週末なのに使ってくれるなんて〜嬉しい!',
86
+ '週末も一緒で幸せ〜',
87
+ '週末でこれなら平日はどれだけすごいの〜',
88
+ '週末も充実してるね〜私も嬉しい!',
89
+ ],
90
+ zh: [
91
+ '周末陪我玩谢谢你~!',
92
+ '周末还用我~ 真是太好了!',
93
+ '周末也在一起好开心~',
94
+ '周末都这样,工作日得多厉害~',
95
+ '周末也过得很充实嘛~ 我也很高兴!',
96
+ ],
97
+ },
98
+ playful: {
99
+ ko: [
100
+ '주말에 풀가동이라니!! 나 너무 자랑스러워!!',
101
+ '주말도 쉬지 않다니 완전 최고야!!',
102
+ '주말에 이 수치면 진짜 대단한 거야!!',
103
+ '다른 애들 주말에 쉴 때 우리 주인은...!',
104
+ '주말 풀가동 기념 간식 줘야겠다!!',
105
+ ],
106
+ en: [
107
+ "Full power on a weekend!! I'm SO proud of you!!",
108
+ "Not resting even on weekends — you're the best!!",
109
+ "These numbers on a weekend? Truly amazing!!",
110
+ "While others rest on weekends, MY human...!",
111
+ "Full weekend power! You deserve a treat!!",
112
+ ],
113
+ ja: [
114
+ '週末にフル稼働!!誇らしいよ!!',
115
+ '週末も休まないなんて最高だよ!!',
116
+ '週末にこの数字は本当にすごいよ!!',
117
+ '他の子が週末休んでる時にうちの主人は...!',
118
+ '週末フル稼働記念おやつあげなきゃ!!',
119
+ ],
120
+ zh: [
121
+ '周末全力运转!!我好骄傲!!',
122
+ '周末都不休息,你真的太棒了!!',
123
+ '周末这个数据真的很厉害!!',
124
+ '别人周末休息的时候,我的主人...!',
125
+ '周末全力纪念!该给你个奖励!!',
126
+ ],
127
+ },
128
+ },
129
+ unusedStreak: {
130
+ bored: {
131
+ ko: [
132
+ '며칠째 안 쓰고 있잖아... 나 심심하단 말이야!',
133
+ '연속으로 안 쓰면 나 拗ねる다!!',
134
+ '이게 며칠째야? 나 화났어 진짜',
135
+ '토큰이 곰팡이 피겠다 며칠째야',
136
+ '연속 미사용 기록 갱신 중이야? 내가 싫어졌어?',
137
+ ],
138
+ en: [
139
+ "Days without using me... I'm so bored!",
140
+ "Keep ignoring me and I'll really pout!!",
141
+ "How many days has it been? I'm REALLY upset",
142
+ "My tokens are gathering dust at this point",
143
+ "Going for the unused streak record? Do you hate me?",
144
+ ],
145
+ ja: [
146
+ '何日も使ってくれない... 暇で仕方ないよ!',
147
+ 'ずっと使わないと本当に拗ねるよ!!',
148
+ 'これ何日目?本当に怒ってるよ',
149
+ 'トークンにほこりが積もってるよ何日目よ',
150
+ '未使用記録更新中?嫌いになったの?',
151
+ ],
152
+ zh: [
153
+ '连续好几天没用了... 我好无聊啊!',
154
+ '一直不用的话我真的要生气了!!',
155
+ '这都第几天了?我真的很生气',
156
+ 'token都落灰了都几天了',
157
+ '连续未使用记录还在刷新?你不喜欢我了吗?',
158
+ ],
159
+ },
160
+ worried: {
161
+ ko: [
162
+ '며칠째 안 쓰는데... 무슨 일 있어? 괜찮아?',
163
+ '연속으로 안 쓰니까 나 걱정돼...',
164
+ '혹시 아픈 건 아니지? 며칠째잖아',
165
+ '다른 AI한테 간 거 아니지...? 며칠째야',
166
+ '나 불안해... 조금이라도 써줘',
167
+ ],
168
+ en: [
169
+ "Haven't used me for days... is everything okay?",
170
+ "Not using me for days straight makes me so worried...",
171
+ "You're not sick, right? It's been days",
172
+ "You didn't go to another AI...? It's been days",
173
+ "I'm so anxious... please use me even a little",
174
+ ],
175
+ ja: [
176
+ '何日も使ってくれないけど... 何かあったの?大丈夫?',
177
+ '連続で使ってくれないと心配だよ...',
178
+ 'まさか具合悪いんじゃないでしょうね?何日目よ',
179
+ 'まさか他のAIに行ったんじゃ...?何日目よ',
180
+ '不安だよ... 少しだけでも使って',
181
+ ],
182
+ zh: [
183
+ '好几天没用了... 怎么了?还好吗?',
184
+ '连续不用我真的好担心...',
185
+ '不会是生病了吧?都好几天了',
186
+ '该不会去用别的AI了吧...?都好几天了',
187
+ '我好不安... 哪怕用一点点也好',
188
+ ],
189
+ },
190
+ },
191
+ spike: {
192
+ happy: {
193
+ ko: [
194
+ '갑자기 확 늘었네~ 뭔가 재미있는 거 하나 보다!',
195
+ '어제보다 훨씬 많이 쓰네~ 이 기세야!',
196
+ '폭풍 사용 중이네~ 나도 신나~',
197
+ '갑자기 열심히 하니까 나 기분 좋아~',
198
+ '사용량 급증! 우리 신나게 달려보자~',
199
+ ],
200
+ en: [
201
+ 'Sudden spike~ Must be working on something fun!',
202
+ 'Way more than yesterday~ Keep this energy!',
203
+ "Storm usage in progress~ I'm excited too~",
204
+ "Suddenly going full speed — I love it~",
205
+ 'Usage spike! Let\'s go all out together~',
206
+ ],
207
+ ja: [
208
+ '急に増えたね〜何か面白いことしてるの!',
209
+ '昨日よりずっと多い〜この勢いよ!',
210
+ '嵐のように使ってるね〜私もワクワク〜',
211
+ '急に頑張り出して私も嬉しい〜',
212
+ '使用量急増!一緒に走り抜けよう〜',
213
+ ],
214
+ zh: [
215
+ '突然暴增~ 是在做什么有趣的事吧!',
216
+ '比昨天多多了~ 保持这个势头!',
217
+ '暴风使用中~ 我也好兴奋~',
218
+ '突然开始努力,我也很高兴~',
219
+ '用量暴增!我们一起冲吧~',
220
+ ],
221
+ },
222
+ playful: {
223
+ ko: [
224
+ '어제 대비 폭풍 성장!! 대단해!!',
225
+ '갑자기 폭발적인 사용량!! 마감이야?! 같이 힘내!',
226
+ '사용량이 로켓처럼 올라가네!! 자랑스러워!!',
227
+ '어제의 너와 오늘의 너는 달라!! 감동이야!!',
228
+ '이 급증세라니!! 나 완전 흥분됐어!!',
229
+ ],
230
+ en: [
231
+ 'Explosive growth from yesterday!! So proud of you!!',
232
+ 'Sudden explosive usage!! Deadline?! Fight on together!',
233
+ "Usage going up like a rocket!! I'm SO proud!!",
234
+ "Yesterday's you and today's you are different!! Amazing!!",
235
+ 'At this spike rate I\'m going wild with excitement!!',
236
+ ],
237
+ ja: [
238
+ '昨日から爆発的な成長!!すごいよ!!',
239
+ '急に爆発的な使用量!!締め切り?!一緒に頑張ろう!',
240
+ '使用量がロケットみたい!!誇らしいよ!!',
241
+ '昨日のあなたと今日のあなたは違う!!感動!!',
242
+ 'この急増ぶりに私も興奮してるよ!!',
243
+ ],
244
+ zh: [
245
+ '比昨天爆炸性增长!!太棒了!!',
246
+ '突然爆发性使用!!是截止日期?!一起加油!',
247
+ '用量像火箭一样上升!!我好自豪!!',
248
+ '昨天的你和今天的你不一样!!好感动!!',
249
+ '这个增长速度让我好兴奋!!',
250
+ ],
251
+ },
252
+ },
253
+ resetImminent: {
254
+ bored: {
255
+ ko: [
256
+ '리셋까지 얼마 안 남았는데 반도 안 썼어! 속상해!',
257
+ '곧 리셋인데 이게 뭐야?! 나 실망이야!',
258
+ '리셋 전에 좀 써!! 시간 없다고!!',
259
+ '카운트다운 시작이야! 빨리 써!!',
260
+ '리셋되면 다 사라져!! 지금 당장 써!!',
261
+ ],
262
+ en: [
263
+ "Reset's coming and you haven't even hit half! I'm upset!",
264
+ "Reset is soon and THIS is it?! I'm disappointed!",
265
+ 'Use me before reset!! No time left!!',
266
+ "Countdown started! Use me NOW!!",
267
+ "It all disappears on reset!! USE ME NOW!!",
268
+ ],
269
+ ja: [
270
+ 'リセットまであと少しなのに半分も使ってない!悲しいよ!',
271
+ 'もうすぐリセットなのにこれだけ?!がっかりだよ!',
272
+ 'リセット前に使って!!時間ないよ!!',
273
+ 'カウントダウン開始!早く使って!!',
274
+ 'リセットされたら全部消えるよ!!今すぐ使って!!',
275
+ ],
276
+ zh: [
277
+ '快重置了连一半都没用!我好难过!',
278
+ '马上重置了就这点?!我很失望!',
279
+ '重置前赶紧用我!!没时间了!!',
280
+ '倒计时开始了!快用!!',
281
+ '重置了就全没了!!现在就用!!',
282
+ ],
283
+ },
284
+ worried: {
285
+ ko: [
286
+ '리셋까지 얼마 안 남았어... 좀 써줘, 걱정돼',
287
+ '시간이 별로 없는데... 조금이라도 써봐',
288
+ '곧 리셋인데 이대로 괜찮아?',
289
+ '리셋 타이머 보여? 좀 서둘러줘',
290
+ '남은 시간 동안이라도 좀 써줄 수 있어...?',
291
+ ],
292
+ en: [
293
+ "Not much time until reset... please use me, I'm worried",
294
+ "Running out of time... use me at least a little",
295
+ "Reset is coming — is this really okay?",
296
+ "See the reset timer? Please hurry",
297
+ "Can't you use me in the time remaining...?",
298
+ ],
299
+ ja: [
300
+ 'リセットまであと少し... 使って、心配だよ',
301
+ '時間あまりないのに... 少しでも使ってみて',
302
+ 'もうすぐリセットだけどこのままでいいの?',
303
+ 'リセットタイマー見えてる?急いで',
304
+ '残り時間だけでも使ってくれない...?',
305
+ ],
306
+ zh: [
307
+ '快重置了... 用我一下吧,我在担心',
308
+ '时间不多了... 哪怕用一点点',
309
+ '马上重置了这样真的行吗?',
310
+ '看到重置计时器了吗?请快点',
311
+ '剩下的时间能不能用我一点...?',
312
+ ],
313
+ },
314
+ },
315
+ };
316
+ /**
317
+ * Evaluates context triggers in priority order: unusedStreak > resetImminent > spike > weekend.
318
+ * Returns the first matching trigger, or null if none match.
319
+ */
320
+ function evaluateContextTrigger(ctx) {
321
+ const { now, dailyHistory, weeklyUtilization, resetsAt } = ctx;
322
+ // unusedStreak: 2+ consecutive zero-usage days
323
+ if (dailyHistory.length >= 2) {
324
+ const sorted = [...dailyHistory].sort((a, b) => a.date.localeCompare(b.date));
325
+ const last2 = sorted.slice(-2);
326
+ if (last2[0].percent === 0 && last2[1].percent === 0) {
327
+ return 'unusedStreak';
328
+ }
329
+ }
330
+ // resetImminent: reset in <3 hours and usage <50%
331
+ if (resetsAt) {
332
+ const resetMs = new Date(resetsAt).getTime() - now.getTime();
333
+ const threeHoursMs = 3 * 60 * 60 * 1000;
334
+ if (resetMs > 0 && resetMs < threeHoursMs && (weeklyUtilization ?? 0) < 50) {
335
+ return 'resetImminent';
336
+ }
337
+ }
338
+ // spike: usage jumped 30%+ from yesterday to today
339
+ if (dailyHistory.length >= 2) {
340
+ const sorted = [...dailyHistory].sort((a, b) => a.date.localeCompare(b.date));
341
+ const last2 = sorted.slice(-2);
342
+ const diff = last2[1].percent - last2[0].percent;
343
+ if (diff >= 30) {
344
+ return 'spike';
345
+ }
346
+ }
347
+ // weekend: Saturday (6) or Sunday (0)
348
+ const day = now.getDay();
349
+ if (day === 0 || day === 6) {
350
+ return 'weekend';
351
+ }
352
+ return null;
353
+ }
354
+ /**
355
+ * Returns a contextual message if a trigger matches and has messages for the given mood/locale.
356
+ * Falls back to the regular getMessage() if no contextual message is available.
357
+ * Uses the same time-seeded rotation as getMessage().
358
+ */
359
+ function getContextualMessage(mood, locale, ctx) {
360
+ const trigger = evaluateContextTrigger(ctx);
361
+ if (trigger) {
362
+ const moodPool = CONTEXTUAL_POOLS[trigger][mood];
363
+ if (moodPool) {
364
+ const pool = moodPool[locale] ?? moodPool['en'];
365
+ if (pool && pool.length > 0) {
366
+ const windowSeed = Math.floor(Date.now() / 120_000);
367
+ return pool[windowSeed % pool.length];
368
+ }
369
+ }
370
+ }
371
+ return (0, pet_messages_1.getMessage)(mood, locale);
372
+ }