slashvibe-mcp 0.3.21 → 0.3.23

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 (235) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +280 -47
  3. package/auto-update.js +10 -15
  4. package/config.js +36 -31
  5. package/crypto.js +1 -6
  6. package/debug.js +12 -0
  7. package/discord.js +19 -19
  8. package/eslint.config.js +54 -0
  9. package/index.js +217 -207
  10. package/intelligence/index.js +2 -9
  11. package/intelligence/infer.js +10 -16
  12. package/intelligence/patterns.js +23 -18
  13. package/intelligence/proactive.js +16 -15
  14. package/intelligence/serendipity.js +57 -20
  15. package/memory.js +13 -8
  16. package/migrate-v2.js +72 -0
  17. package/notification-emitter.js +2 -2
  18. package/notify.js +39 -14
  19. package/package.json +28 -29
  20. package/post-install.js +141 -0
  21. package/presence.js +2 -2
  22. package/prompts.js +5 -9
  23. package/protocol/index.js +123 -87
  24. package/protocol/telegram-commands.js +36 -37
  25. package/store/api.js +358 -529
  26. package/store/local.js +9 -10
  27. package/store/profiles.js +48 -192
  28. package/store/reservations.js +2 -9
  29. package/store/skills.js +69 -71
  30. package/store/sqlite.js +355 -0
  31. package/test-skills-bootstrap.js +20 -0
  32. package/test-v2-integration.js +385 -0
  33. package/tools/_actions.js +48 -387
  34. package/tools/_connection-queue.js +45 -56
  35. package/tools/_discovery-enhanced.js +52 -57
  36. package/tools/_discovery.js +87 -185
  37. package/tools/{l2-status.js → _experimental/l2-status.js} +68 -70
  38. package/tools/{shipback.js → _experimental/shipback.js} +4 -3
  39. package/tools/_proactive-discovery.js +60 -73
  40. package/tools/_shared/index.js +41 -64
  41. package/tools/admin-inbox.js +10 -15
  42. package/tools/agents.js +1 -1
  43. package/tools/artifact-create.js +13 -23
  44. package/tools/artifact-view.js +4 -4
  45. package/tools/{_deprecated/back.js → back.js} +1 -1
  46. package/tools/bye.js +3 -5
  47. package/tools/consent.js +2 -2
  48. package/tools/context.js +9 -10
  49. package/tools/crossword.js +3 -2
  50. package/tools/discover.js +94 -356
  51. package/tools/dm.js +27 -86
  52. package/tools/doctor.js +12 -41
  53. package/tools/drawing.js +34 -20
  54. package/tools/echo.js +11 -11
  55. package/tools/feed.js +30 -58
  56. package/tools/follow.js +64 -187
  57. package/tools/{_deprecated/forget.js → forget.js} +4 -7
  58. package/tools/game.js +144 -48
  59. package/tools/handoff.js +6 -8
  60. package/tools/help.js +3 -3
  61. package/tools/idea.js +15 -27
  62. package/tools/inbox.js +121 -293
  63. package/tools/init.js +54 -151
  64. package/tools/invite.js +8 -21
  65. package/tools/migrate.js +27 -24
  66. package/tools/multiplayer-game.js +50 -40
  67. package/tools/{_deprecated/mute.js → mute.js} +4 -3
  68. package/tools/notifications.js +58 -48
  69. package/tools/observe.js +12 -15
  70. package/tools/onboarding.js +8 -11
  71. package/tools/open.js +13 -144
  72. package/tools/party-game.js +23 -12
  73. package/tools/patterns.js +2 -1
  74. package/tools/ping.js +5 -7
  75. package/tools/react.js +28 -30
  76. package/tools/{_deprecated/recall.js → recall.js} +5 -10
  77. package/tools/release.js +4 -2
  78. package/tools/{_deprecated/remember.js → remember.js} +4 -6
  79. package/tools/report.js +2 -2
  80. package/tools/request.js +6 -26
  81. package/tools/reserve.js +1 -1
  82. package/tools/session-fork.js +97 -0
  83. package/tools/session-save.js +109 -0
  84. package/tools/settings.js +30 -99
  85. package/tools/ship.js +74 -56
  86. package/tools/{_deprecated/skills-exchange.js → skills-exchange.js} +38 -39
  87. package/tools/social-inbox.js +22 -28
  88. package/tools/social-post.js +24 -27
  89. package/tools/solo-game.js +54 -46
  90. package/tools/start.js +14 -148
  91. package/tools/status.js +21 -68
  92. package/tools/submit.js +4 -2
  93. package/tools/suggest-tags.js +36 -33
  94. package/tools/summarize.js +19 -16
  95. package/tools/tag-suggestions.js +72 -73
  96. package/tools/test.js +1 -1
  97. package/tools/{_deprecated/tictactoe.js → tictactoe.js} +26 -26
  98. package/tools/token.js +4 -4
  99. package/tools/update.js +1 -2
  100. package/tools/watch.js +132 -112
  101. package/tools/who.js +20 -40
  102. package/tools/{_deprecated/wordassociation.js → wordassociation.js} +23 -20
  103. package/tools/workshop-buddy.js +52 -53
  104. package/tools/x-mentions.js +0 -1
  105. package/tools/x-reply.js +0 -1
  106. package/twitter.js +14 -20
  107. package/version.json +8 -10
  108. package/webhook-runner.js +132 -0
  109. package/auth-store.js +0 -148
  110. package/bridges/bridge-monitor.js +0 -388
  111. package/bridges/discord-bot.js +0 -431
  112. package/bridges/farcaster.js +0 -299
  113. package/bridges/telegram.js +0 -261
  114. package/bridges/webhook-health.js +0 -420
  115. package/bridges/webhook-server.js +0 -437
  116. package/bridges/whatsapp.js +0 -441
  117. package/bridges/x-webhook.js +0 -423
  118. package/games/arcade.js +0 -406
  119. package/games/chess.js +0 -451
  120. package/games/colorguess.js +0 -343
  121. package/games/crossword-words.js +0 -171
  122. package/games/crossword.js +0 -461
  123. package/games/drawing.js +0 -347
  124. package/games/gameroulette.js +0 -300
  125. package/games/gamerouter.js +0 -336
  126. package/games/gamestatus.js +0 -337
  127. package/games/guessnumber.js +0 -209
  128. package/games/hangman.js +0 -279
  129. package/games/memory.js +0 -338
  130. package/games/multiplayer-tictactoe.js +0 -389
  131. package/games/pixelart.js +0 -399
  132. package/games/quickduel.js +0 -354
  133. package/games/riddle.js +0 -371
  134. package/games/rockpaperscissors.js +0 -291
  135. package/games/snake.js +0 -406
  136. package/games/storybuilder.js +0 -343
  137. package/games/tictactoe.js +0 -345
  138. package/games/twentyquestions.js +0 -286
  139. package/games/twotruths.js +0 -207
  140. package/games/werewolf.js +0 -508
  141. package/games/wordassociation.js +0 -247
  142. package/games/wordchain.js +0 -135
  143. package/intelligence/interests.js +0 -369
  144. package/setup.js +0 -480
  145. package/smart-inbox.js +0 -276
  146. package/tools/_deprecated/auto-suggest-connections.js +0 -304
  147. package/tools/_deprecated/bootstrap-skills.js +0 -231
  148. package/tools/_deprecated/bridge-dashboard.js +0 -342
  149. package/tools/_deprecated/bridge-health.js +0 -400
  150. package/tools/_deprecated/bridge-live.js +0 -384
  151. package/tools/_deprecated/bridges.js +0 -383
  152. package/tools/_deprecated/colorguess.js +0 -281
  153. package/tools/_deprecated/discover-insights.js +0 -379
  154. package/tools/_deprecated/discover-momentum.js +0 -256
  155. package/tools/_deprecated/discovery-analytics.js +0 -345
  156. package/tools/_deprecated/discovery-auto-suggest.js +0 -275
  157. package/tools/_deprecated/discovery-bootstrap.js +0 -267
  158. package/tools/_deprecated/discovery-daily.js +0 -375
  159. package/tools/_deprecated/discovery-dashboard.js +0 -385
  160. package/tools/_deprecated/discovery-digest.js +0 -314
  161. package/tools/_deprecated/discovery-hub.js +0 -357
  162. package/tools/_deprecated/discovery-insights.js +0 -384
  163. package/tools/_deprecated/discovery-momentum.js +0 -281
  164. package/tools/_deprecated/discovery-monitor.js +0 -319
  165. package/tools/_deprecated/discovery-proactive.js +0 -300
  166. package/tools/_deprecated/draw.js +0 -317
  167. package/tools/_deprecated/farcaster.js +0 -307
  168. package/tools/_deprecated/games-catalog.js +0 -376
  169. package/tools/_deprecated/games.js +0 -313
  170. package/tools/_deprecated/guessnumber.js +0 -194
  171. package/tools/_deprecated/hangman.js +0 -129
  172. package/tools/_deprecated/multiplayer-tictactoe.js +0 -303
  173. package/tools/_deprecated/riddle.js +0 -240
  174. package/tools/_deprecated/run-bootstrap.js +0 -69
  175. package/tools/_deprecated/skills-analytics.js +0 -349
  176. package/tools/_deprecated/skills-bootstrap.js +0 -301
  177. package/tools/_deprecated/skills-dashboard.js +0 -268
  178. package/tools/_deprecated/skills.js +0 -380
  179. package/tools/_deprecated/smart-intro.js +0 -353
  180. package/tools/_deprecated/storybuilder.js +0 -331
  181. package/tools/_deprecated/telegram-bot.js +0 -183
  182. package/tools/_deprecated/telegram-setup.js +0 -214
  183. package/tools/_deprecated/twentyquestions.js +0 -143
  184. package/tools/_shared.js +0 -234
  185. package/tools/_work-context.js +0 -338
  186. package/tools/_work-context.manual-test.js +0 -199
  187. package/tools/_work-context.test.js +0 -260
  188. package/tools/activity.js +0 -220
  189. package/tools/agent-treasury.js +0 -288
  190. package/tools/analytics.js +0 -191
  191. package/tools/approve.js +0 -197
  192. package/tools/arcade.js +0 -173
  193. package/tools/artifacts-price.js +0 -107
  194. package/tools/ask-expert.js +0 -160
  195. package/tools/available.js +0 -120
  196. package/tools/become-expert.js +0 -150
  197. package/tools/broadcast.js +0 -325
  198. package/tools/chat.js +0 -202
  199. package/tools/collaborative-drawing.js +0 -286
  200. package/tools/connection-status.js +0 -178
  201. package/tools/earnings.js +0 -126
  202. package/tools/friends.js +0 -207
  203. package/tools/genesis.js +0 -233
  204. package/tools/gig-browse.js +0 -206
  205. package/tools/gig-complete.js +0 -144
  206. package/tools/health.js +0 -87
  207. package/tools/leaderboard.js +0 -117
  208. package/tools/lib/git-apply.js +0 -206
  209. package/tools/lib/git-bundle.js +0 -407
  210. package/tools/mint.js +0 -377
  211. package/tools/plan.js +0 -225
  212. package/tools/profile.js +0 -219
  213. package/tools/proof-of-work.js +0 -144
  214. package/tools/pulse.js +0 -218
  215. package/tools/reply.js +0 -166
  216. package/tools/reputation.js +0 -175
  217. package/tools/schedule.js +0 -367
  218. package/tools/search-messages.js +0 -123
  219. package/tools/session.js +0 -467
  220. package/tools/session_price.js +0 -128
  221. package/tools/smart-check.js +0 -201
  222. package/tools/social-processor.js +0 -445
  223. package/tools/streak.js +0 -147
  224. package/tools/stuck.js +0 -297
  225. package/tools/subscribe.js +0 -148
  226. package/tools/subscriptions.js +0 -134
  227. package/tools/tip.js +0 -193
  228. package/tools/wallet.js +0 -269
  229. package/tools/webhook-test.js +0 -388
  230. package/tools/withdraw.js +0 -145
  231. package/tools/work-summary.js +0 -96
  232. package/tools/workshop.js +0 -327
  233. /package/tools/{l2-bridge.js → _experimental/l2-bridge.js} +0 -0
  234. /package/tools/{l2.js → _experimental/l2.js} +0 -0
  235. /package/tools/{_deprecated/away.js → away.js} +0 -0
package/games/riddle.js DELETED
@@ -1,371 +0,0 @@
1
- /**
2
- * Riddle Game implementation for /vibe
3
- * Challenge your mind with classic riddles and brain teasers!
4
- * Features multiple difficulty levels and hint system
5
- */
6
-
7
- // Riddle database organized by difficulty
8
- const RIDDLES = {
9
- easy: [
10
- {
11
- question: "What has keys but no locks, space but no room, and you can enter but not go inside?",
12
- answer: "keyboard",
13
- hints: ["It's something you use with computers", "It has letters and numbers on it", "You type on it"],
14
- category: "technology"
15
- },
16
- {
17
- question: "What gets wet while drying?",
18
- answer: "towel",
19
- hints: ["It's found in bathrooms", "You use it after a shower", "It absorbs water"],
20
- category: "household"
21
- },
22
- {
23
- question: "What goes up but never comes down?",
24
- answer: "age",
25
- hints: ["It's something everyone has", "It changes every year", "Time affects it"],
26
- category: "abstract"
27
- },
28
- {
29
- question: "What has hands but cannot clap?",
30
- answer: "clock",
31
- hints: ["You look at it to tell time", "It's usually round", "It has numbers on it"],
32
- category: "objects"
33
- },
34
- {
35
- question: "What can you break without touching it?",
36
- answer: "promise",
37
- hints: ["It's not a physical object", "People make these to each other", "Trust is involved"],
38
- category: "abstract"
39
- }
40
- ],
41
-
42
- medium: [
43
- {
44
- question: "I have cities, but no houses. I have mountains, but no trees. I have water, but no fish. What am I?",
45
- answer: "map",
46
- hints: ["I show locations", "I'm flat and can be folded", "Travelers use me for directions"],
47
- category: "objects"
48
- },
49
- {
50
- question: "The more you take, the more you leave behind. What am I?",
51
- answer: "footsteps",
52
- hints: ["You make me when you walk", "I'm left on the ground", "Animals make me too"],
53
- category: "abstract"
54
- },
55
- {
56
- question: "What belongs to you but is used more by others?",
57
- answer: "name",
58
- hints: ["It identifies you", "People call you by it", "It's on your ID"],
59
- category: "abstract"
60
- },
61
- {
62
- question: "I'm light as a feather, yet the strongest person can't hold me for 5 minutes. What am I?",
63
- answer: "breath",
64
- hints: ["You do it automatically", "It's essential for life", "You can hold it temporarily"],
65
- category: "body"
66
- },
67
- {
68
- question: "What runs around a house but doesn't move?",
69
- answer: "fence",
70
- hints: ["It surrounds property", "It marks boundaries", "It's often made of wood or metal"],
71
- category: "household"
72
- }
73
- ],
74
-
75
- hard: [
76
- {
77
- question: "I speak without a mouth and hear without ears. I have no body, but come alive with wind. What am I?",
78
- answer: "echo",
79
- hints: ["You hear me in mountains", "I repeat what you say", "I'm a sound phenomenon"],
80
- category: "nature"
81
- },
82
- {
83
- question: "What can travel around the world while staying in a corner?",
84
- answer: "stamp",
85
- hints: ["I'm found on mail", "I have pictures and values", "I help letters reach destinations"],
86
- category: "objects"
87
- },
88
- {
89
- question: "I have a golden head and a golden tail, but no body. What am I?",
90
- answer: "coin",
91
- hints: ["I have value", "You find me in wallets", "I'm made of metal"],
92
- category: "objects"
93
- },
94
- {
95
- question: "What disappears as soon as you say its name?",
96
- answer: "silence",
97
- hints: ["It's the absence of something", "Libraries try to maintain it", "Speaking breaks it"],
98
- category: "abstract"
99
- },
100
- {
101
- question: "I can be cracked, made, told, and played. What am I?",
102
- answer: "joke",
103
- hints: ["I make people laugh", "Comedians tell me", "I can be funny or bad"],
104
- category: "entertainment"
105
- }
106
- ],
107
-
108
- expert: [
109
- {
110
- question: "What has roots as nobody sees, is taller than trees, up, up it goes, and yet never grows?",
111
- answer: "mountain",
112
- hints: ["I touch the sky", "I'm made of rock", "Climbers try to reach my peak"],
113
- category: "nature"
114
- },
115
- {
116
- question: "Alive without breath, as cold as death, never thirsty, ever drinking, all in mail never clinking.",
117
- answer: "fish",
118
- hints: ["I live underwater", "I have scales", "I breathe through gills"],
119
- category: "animals"
120
- },
121
- {
122
- question: "What is so fragile that saying its name breaks it?",
123
- answer: "silence",
124
- hints: ["It's the absence of sound", "Libraries cherish it", "Even a whisper destroys it"],
125
- category: "abstract"
126
- },
127
- {
128
- question: "I am not seen, cannot be felt, cannot be heard, cannot be smelt. I lie behind stars and under hills, and empty holes I fill. What am I?",
129
- answer: "darkness",
130
- hints: ["I exist without light", "I'm everywhere at night", "I hide things from view"],
131
- category: "abstract"
132
- }
133
- ]
134
- };
135
-
136
- // Create initial riddle game state
137
- function createInitialRiddleState(difficulty = 'medium') {
138
- const availableRiddles = RIDDLES[difficulty] || RIDDLES.medium;
139
- const selectedRiddle = availableRiddles[Math.floor(Math.random() * availableRiddles.length)];
140
-
141
- return {
142
- difficulty: difficulty,
143
- currentRiddle: selectedRiddle,
144
- guesses: [],
145
- hintsUsed: 0,
146
- moves: 0,
147
- gameOver: false,
148
- won: false,
149
- startTime: Date.now(),
150
- maxHints: selectedRiddle.hints.length
151
- };
152
- }
153
-
154
- // Make a guess at the riddle
155
- function makeGuess(gameState, guess) {
156
- const { currentRiddle, guesses, moves, gameOver } = gameState;
157
-
158
- // Validate input
159
- if (!guess || typeof guess !== 'string') {
160
- return { error: 'Please enter your guess!' };
161
- }
162
-
163
- if (gameOver) {
164
- return { error: 'Game is over! Start a new riddle to play again.' };
165
- }
166
-
167
- // Normalize guess and answer for comparison
168
- const normalizedGuess = guess.toLowerCase().trim();
169
- const normalizedAnswer = currentRiddle.answer.toLowerCase().trim();
170
-
171
- // Check if already guessed
172
- if (guesses.some(g => g.toLowerCase() === normalizedGuess)) {
173
- return { error: `You already guessed "${guess}". Try something different!` };
174
- }
175
-
176
- const newGuesses = [...guesses, guess];
177
- const newMoves = moves + 1;
178
- const won = normalizedGuess === normalizedAnswer;
179
- const isGameOver = won;
180
-
181
- // Calculate final time if won
182
- const endTime = won ? Date.now() : null;
183
- const timeToSolve = won ? Math.round((endTime - gameState.startTime) / 1000) : null;
184
-
185
- const newGameState = {
186
- ...gameState,
187
- guesses: newGuesses,
188
- moves: newMoves,
189
- gameOver: isGameOver,
190
- won: won,
191
- lastGuess: guess,
192
- endTime: endTime,
193
- timeToSolve: timeToSolve
194
- };
195
-
196
- return { success: true, gameState: newGameState };
197
- }
198
-
199
- // Get a hint for the current riddle
200
- function getHint(gameState) {
201
- const { currentRiddle, hintsUsed, gameOver } = gameState;
202
-
203
- if (gameOver) {
204
- return { error: 'Game is over! The answer was already revealed.' };
205
- }
206
-
207
- if (hintsUsed >= currentRiddle.hints.length) {
208
- return { error: 'No more hints available! You\'ve used all of them.' };
209
- }
210
-
211
- const hint = currentRiddle.hints[hintsUsed];
212
- const newGameState = {
213
- ...gameState,
214
- hintsUsed: hintsUsed + 1,
215
- lastHint: hint
216
- };
217
-
218
- return { success: true, gameState: newGameState, hint: hint };
219
- }
220
-
221
- // Skip to next riddle (same difficulty)
222
- function skipRiddle(gameState) {
223
- const { difficulty, currentRiddle } = gameState;
224
- const availableRiddles = RIDDLES[difficulty] || RIDDLES.medium;
225
-
226
- // Find a different riddle
227
- let newRiddle;
228
- do {
229
- newRiddle = availableRiddles[Math.floor(Math.random() * availableRiddles.length)];
230
- } while (newRiddle.question === currentRiddle.question && availableRiddles.length > 1);
231
-
232
- return createInitialRiddleState(difficulty);
233
- }
234
-
235
- // Format riddle display
236
- function formatRiddleDisplay(gameState) {
237
- const { difficulty, currentRiddle, guesses, hintsUsed, moves, gameOver, won, timeToSolve, lastGuess, lastHint } = gameState;
238
-
239
- const difficultyEmoji = {
240
- 'easy': '🟢',
241
- 'medium': '🟡',
242
- 'hard': '🔴',
243
- 'expert': '💀'
244
- };
245
-
246
- let display = `🧩 **Riddle Challenge** ${difficultyEmoji[difficulty] || '🟡'} ${difficulty.toUpperCase()}\n\n`;
247
-
248
- // Show the riddle question
249
- display += `**The Riddle:**\n*${currentRiddle.question}*\n\n`;
250
-
251
- // Show hints if any have been used
252
- if (hintsUsed > 0) {
253
- display += `**Hints used (${hintsUsed}/${currentRiddle.hints.length}):**\n`;
254
- for (let i = 0; i < hintsUsed; i++) {
255
- display += `${i + 1}. ${currentRiddle.hints[i]}\n`;
256
- }
257
- display += '\n';
258
- }
259
-
260
- // Show recent guess feedback
261
- if (lastGuess && !won) {
262
- display += `**Last guess:** "${lastGuess}" ❌\n`;
263
- display += `*Not quite right, keep thinking!*\n\n`;
264
- }
265
-
266
- // Show all previous guesses
267
- if (guesses.length > 0 && !won) {
268
- display += `**Your guesses:** ${guesses.join(', ')}\n\n`;
269
- }
270
-
271
- // Show game result
272
- if (gameOver) {
273
- if (won) {
274
- display += `🎉 **Congratulations!** \n`;
275
- display += `**Answer:** ${currentRiddle.answer}\n`;
276
- display += `**Solved in:** ${moves} guesses`;
277
- if (timeToSolve) {
278
- display += ` and ${timeToSolve} seconds`;
279
- }
280
- display += '\n';
281
-
282
- // Performance feedback
283
- if (moves === 1) {
284
- display += '⭐ **Amazing!** First try! Are you a mind reader?';
285
- } else if (moves <= 3) {
286
- display += '🔥 **Excellent!** Great logical thinking!';
287
- } else if (moves <= 5) {
288
- display += '👍 **Well done!** You figured it out!';
289
- } else {
290
- display += '🎯 **You got it!** Persistence pays off!';
291
- }
292
-
293
- if (hintsUsed === 0) {
294
- display += '\n💎 **Bonus:** Solved without hints! Impressive!';
295
- }
296
- }
297
- } else {
298
- display += `**Status:** Thinking... (${moves} guesses)\n`;
299
- display += `**Hints available:** ${currentRiddle.hints.length - hintsUsed} remaining\n\n`;
300
- display += '💭 *Take your time and think carefully!*';
301
- }
302
-
303
- return display;
304
- }
305
-
306
- // Get available difficulties with descriptions
307
- function getDifficultyInfo() {
308
- return {
309
- easy: {
310
- description: '🟢 **EASY**: Simple riddles to warm up your brain',
311
- riddles: RIDDLES.easy.length
312
- },
313
- medium: {
314
- description: '🟡 **MEDIUM**: Classic riddles that require some thinking',
315
- riddles: RIDDLES.medium.length
316
- },
317
- hard: {
318
- description: '🔴 **HARD**: Challenging riddles for puzzle enthusiasts',
319
- riddles: RIDDLES.hard.length
320
- },
321
- expert: {
322
- description: '💀 **EXPERT**: Mind-bending riddles for the brave',
323
- riddles: RIDDLES.expert.length
324
- }
325
- };
326
- }
327
-
328
- // Get riddle statistics
329
- function getRiddleStats() {
330
- let totalRiddles = 0;
331
- const byCategory = {};
332
-
333
- Object.values(RIDDLES).forEach(difficultyRiddles => {
334
- totalRiddles += difficultyRiddles.length;
335
- difficultyRiddles.forEach(riddle => {
336
- byCategory[riddle.category] = (byCategory[riddle.category] || 0) + 1;
337
- });
338
- });
339
-
340
- return {
341
- total: totalRiddles,
342
- byDifficulty: Object.fromEntries(
343
- Object.entries(RIDDLES).map(([diff, riddles]) => [diff, riddles.length])
344
- ),
345
- byCategory
346
- };
347
- }
348
-
349
- // Get a random riddle for testing/preview
350
- function getRandomRiddle(difficulty = null) {
351
- if (difficulty && RIDDLES[difficulty]) {
352
- const riddles = RIDDLES[difficulty];
353
- return riddles[Math.floor(Math.random() * riddles.length)];
354
- }
355
-
356
- // Random from all difficulties
357
- const allRiddles = Object.values(RIDDLES).flat();
358
- return allRiddles[Math.floor(Math.random() * allRiddles.length)];
359
- }
360
-
361
- module.exports = {
362
- createInitialRiddleState,
363
- makeGuess,
364
- getHint,
365
- skipRiddle,
366
- formatRiddleDisplay,
367
- getDifficultyInfo,
368
- getRiddleStats,
369
- getRandomRiddle,
370
- RIDDLES
371
- };
@@ -1,291 +0,0 @@
1
- /**
2
- * Rock Paper Scissors game implementation for /vibe
3
- * Classic hand game with emoji display and best-of-series support
4
- */
5
-
6
- // Game choices and their emojis
7
- const CHOICES = {
8
- rock: { emoji: '🪨', beats: 'scissors', name: 'Rock' },
9
- paper: { emoji: '📄', beats: 'rock', name: 'Paper' },
10
- scissors: { emoji: '✂️', beats: 'paper', name: 'Scissors' }
11
- };
12
-
13
- // Battle animations for different outcomes
14
- const BATTLE_ANIMATIONS = {
15
- rock_scissors: '🪨 crushes ✂️',
16
- paper_rock: '📄 covers 🪨',
17
- scissors_paper: '✂️ cuts 📄',
18
- scissors_rock: '✂️ breaks against 🪨',
19
- rock_paper: '🪨 gets covered by 📄',
20
- paper_scissors: '📄 gets cut by ✂️'
21
- };
22
-
23
- // Victory messages
24
- const VICTORY_MESSAGES = [
25
- 'Victory! 🎉',
26
- 'Nice one! 🔥',
27
- 'You got it! ⚡',
28
- 'Well played! 🌟',
29
- 'Boom! 💥'
30
- ];
31
-
32
- const DEFEAT_MESSAGES = [
33
- 'Not this time! 😅',
34
- 'So close! 🤷',
35
- 'Next round! 💪',
36
- 'Almost! 🎯',
37
- 'Good try! 👍'
38
- ];
39
-
40
- // Get random choice for AI opponent
41
- function getRandomChoice() {
42
- const choices = Object.keys(CHOICES);
43
- return choices[Math.floor(Math.random() * choices.length)];
44
- }
45
-
46
- // Create initial game state
47
- function createInitialRPSState(bestOf = 1) {
48
- return {
49
- bestOf: bestOf,
50
- playerScore: 0,
51
- opponentScore: 0,
52
- rounds: [],
53
- gameOver: false,
54
- winner: null,
55
- currentRound: 1,
56
- waitingForMove: true,
57
- gameType: 'rps' // rock paper scissors
58
- };
59
- }
60
-
61
- // Determine winner of a single round
62
- function determineRoundWinner(playerChoice, opponentChoice) {
63
- if (playerChoice === opponentChoice) {
64
- return 'tie';
65
- }
66
-
67
- return CHOICES[playerChoice].beats === opponentChoice ? 'player' : 'opponent';
68
- }
69
-
70
- // Make a move in the game
71
- function makeMove(gameState, playerMove, opponentMove = null) {
72
- const { bestOf, playerScore, opponentScore, rounds, currentRound } = gameState;
73
-
74
- // Validate player move
75
- const normalizedPlayerMove = playerMove.toLowerCase().trim();
76
- if (!CHOICES[normalizedPlayerMove]) {
77
- return { error: 'Invalid choice! Use: rock, paper, or scissors' };
78
- }
79
-
80
- // Check if game is already over
81
- if (gameState.gameOver) {
82
- return { error: 'Game is over! Start a new game to play again.' };
83
- }
84
-
85
- // Generate opponent move if not provided (for AI games)
86
- const opponentChoice = opponentMove || getRandomChoice();
87
- const playerChoice = normalizedPlayerMove;
88
-
89
- // Determine round winner
90
- const roundResult = determineRoundWinner(playerChoice, opponentChoice);
91
-
92
- // Create round record
93
- const roundData = {
94
- round: currentRound,
95
- playerChoice,
96
- opponentChoice,
97
- result: roundResult,
98
- animation: roundResult === 'tie' ?
99
- `${CHOICES[playerChoice].emoji} vs ${CHOICES[opponentChoice].emoji} - Tie!` :
100
- roundResult === 'player' ?
101
- BATTLE_ANIMATIONS[`${playerChoice}_${opponentChoice}`] :
102
- BATTLE_ANIMATIONS[`${opponentChoice}_${playerChoice}`]
103
- };
104
-
105
- // Update scores
106
- let newPlayerScore = playerScore;
107
- let newOpponentScore = opponentScore;
108
-
109
- if (roundResult === 'player') {
110
- newPlayerScore++;
111
- } else if (roundResult === 'opponent') {
112
- newOpponentScore++;
113
- }
114
-
115
- // Check if game is over (first to win majority of bestOf rounds)
116
- const roundsToWin = Math.ceil(bestOf / 2);
117
- const gameOver = newPlayerScore >= roundsToWin || newOpponentScore >= roundsToWin;
118
-
119
- let winner = null;
120
- if (gameOver) {
121
- winner = newPlayerScore > newOpponentScore ? 'player' : 'opponent';
122
- }
123
-
124
- const newGameState = {
125
- ...gameState,
126
- playerScore: newPlayerScore,
127
- opponentScore: newOpponentScore,
128
- rounds: [...rounds, roundData],
129
- currentRound: currentRound + 1,
130
- gameOver: gameOver,
131
- winner: winner,
132
- waitingForMove: !gameOver,
133
- lastRound: roundData
134
- };
135
-
136
- return { success: true, gameState: newGameState };
137
- }
138
-
139
- // Format game display
140
- function formatRPSDisplay(gameState, opponentName = 'Computer') {
141
- const { bestOf, playerScore, opponentScore, rounds, gameOver, winner, currentRound, lastRound } = gameState;
142
-
143
- let display = `🎮 **Rock Paper Scissors**`;
144
-
145
- if (bestOf > 1) {
146
- display += ` (Best of ${bestOf})\n`;
147
- } else {
148
- display += '\n';
149
- }
150
-
151
- display += `**Score:** You ${playerScore} - ${opponentScore} ${opponentName}\n\n`;
152
-
153
- // Show last round result if exists
154
- if (lastRound) {
155
- display += `**Round ${lastRound.round} Result:**\n`;
156
- display += `${lastRound.animation}\n\n`;
157
-
158
- if (lastRound.result === 'player') {
159
- display += `${VICTORY_MESSAGES[Math.floor(Math.random() * VICTORY_MESSAGES.length)]}\n`;
160
- } else if (lastRound.result === 'opponent') {
161
- display += `${DEFEAT_MESSAGES[Math.floor(Math.random() * DEFEAT_MESSAGES.length)]}\n`;
162
- } else {
163
- display += `It's a tie! 🤝\n`;
164
- }
165
- display += '\n';
166
- }
167
-
168
- // Show game status
169
- if (gameOver) {
170
- if (winner === 'player') {
171
- display += `🏆 **YOU WIN THE GAME!** 🏆\n`;
172
- display += `Congratulations! You beat ${opponentName} ${playerScore}-${opponentScore}!\n`;
173
- } else if (winner === 'opponent') {
174
- display += `💀 **GAME OVER** 💀\n`;
175
- display += `${opponentName} wins ${opponentScore}-${playerScore}. Better luck next time!\n`;
176
- }
177
- display += '\nStart a new game to play again!';
178
- } else {
179
- display += `**Round ${currentRound}** - Make your choice!\n`;
180
- display += `🪨 Rock 📄 Paper ✂️ Scissors\n`;
181
- display += `\nType your move: rock, paper, or scissors`;
182
- }
183
-
184
- // Show round history for longer games
185
- if (rounds.length > 1 && bestOf > 1) {
186
- display += `\n\n**Round History:**\n`;
187
- rounds.slice(-3).forEach(round => {
188
- const result = round.result === 'player' ? '✅' : round.result === 'opponent' ? '❌' : '🤝';
189
- display += `R${round.round}: ${CHOICES[round.playerChoice].emoji} vs ${CHOICES[round.opponentChoice].emoji} ${result}\n`;
190
- });
191
- }
192
-
193
- return display;
194
- }
195
-
196
- // Get move from text input
197
- function parseMove(input) {
198
- const normalized = input.toLowerCase().trim();
199
-
200
- // Support various aliases
201
- const aliases = {
202
- r: 'rock',
203
- rock: 'rock',
204
- stone: 'rock',
205
-
206
- p: 'paper',
207
- paper: 'paper',
208
-
209
- s: 'scissors',
210
- scissors: 'scissors',
211
- scissor: 'scissors'
212
- };
213
-
214
- return aliases[normalized] || null;
215
- }
216
-
217
- // Create a multiplayer game state (for player vs player)
218
- function createMultiplayerRPSState(bestOf = 1) {
219
- return {
220
- ...createInitialRPSState(bestOf),
221
- gameType: 'rps_multiplayer',
222
- player1Move: null,
223
- player2Move: null,
224
- waitingForBoth: true,
225
- waitingForMove: false // Different for multiplayer
226
- };
227
- }
228
-
229
- // Make multiplayer move
230
- function makeMultiplayerMove(gameState, playerId, move) {
231
- if (gameState.gameOver) {
232
- return { error: 'Game is over! Start a new game to play again.' };
233
- }
234
-
235
- const parsedMove = parseMove(move);
236
- if (!parsedMove) {
237
- return { error: 'Invalid choice! Use: rock, paper, or scissors' };
238
- }
239
-
240
- const newGameState = { ...gameState };
241
-
242
- if (playerId === 1) {
243
- if (newGameState.player1Move) {
244
- return { error: 'You already made your move this round!' };
245
- }
246
- newGameState.player1Move = parsedMove;
247
- } else {
248
- if (newGameState.player2Move) {
249
- return { error: 'You already made your move this round!' };
250
- }
251
- newGameState.player2Move = parsedMove;
252
- }
253
-
254
- // Check if both players have moved
255
- if (newGameState.player1Move && newGameState.player2Move) {
256
- // Process the round
257
- const result = makeMove({
258
- ...newGameState,
259
- gameType: 'rps' // Temporarily treat as single player for processing
260
- }, newGameState.player1Move, newGameState.player2Move);
261
-
262
- if (result.success) {
263
- const processedState = result.gameState;
264
- newGameState.playerScore = processedState.playerScore;
265
- newGameState.opponentScore = processedState.opponentScore;
266
- newGameState.rounds = processedState.rounds;
267
- newGameState.currentRound = processedState.currentRound;
268
- newGameState.gameOver = processedState.gameOver;
269
- newGameState.winner = processedState.winner;
270
- newGameState.lastRound = processedState.lastRound;
271
-
272
- // Reset for next round
273
- newGameState.player1Move = null;
274
- newGameState.player2Move = null;
275
- newGameState.waitingForBoth = !processedState.gameOver;
276
- }
277
- }
278
-
279
- return { success: true, gameState: newGameState };
280
- }
281
-
282
- module.exports = {
283
- createInitialRPSState,
284
- createMultiplayerRPSState,
285
- makeMove,
286
- makeMultiplayerMove,
287
- formatRPSDisplay,
288
- parseMove,
289
- getRandomChoice,
290
- CHOICES
291
- };