@rune-kit/rune 2.10.0 → 2.11.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.
Files changed (205) hide show
  1. package/LICENSE +21 -21
  2. package/README.md +8 -6
  3. package/commands/rune.md +168 -168
  4. package/contexts/dev.md +34 -34
  5. package/contexts/research.md +43 -43
  6. package/contexts/review.md +55 -55
  7. package/extensions/ai-ml/PACK.md +88 -88
  8. package/extensions/ai-ml/skills/ai-agents.md +172 -172
  9. package/extensions/ai-ml/skills/code-sandbox.md +187 -187
  10. package/extensions/ai-ml/skills/deep-research.md +146 -146
  11. package/extensions/ai-ml/skills/embedding-search.md +66 -66
  12. package/extensions/ai-ml/skills/fine-tuning-guide.md +74 -74
  13. package/extensions/ai-ml/skills/llm-architect.md +125 -125
  14. package/extensions/ai-ml/skills/llm-integration.md +64 -64
  15. package/extensions/ai-ml/skills/prompt-patterns.md +72 -72
  16. package/extensions/ai-ml/skills/rag-patterns.md +66 -66
  17. package/extensions/ai-ml/skills/web-extraction.md +114 -114
  18. package/extensions/analytics/PACK.md +92 -92
  19. package/extensions/analytics/skills/ab-testing.md +72 -72
  20. package/extensions/analytics/skills/dashboard-patterns.md +83 -83
  21. package/extensions/analytics/skills/data-validation.md +68 -68
  22. package/extensions/analytics/skills/funnel-analysis.md +81 -81
  23. package/extensions/analytics/skills/sql-patterns.md +57 -57
  24. package/extensions/analytics/skills/statistical-analysis.md +79 -79
  25. package/extensions/analytics/skills/tracking-setup.md +71 -71
  26. package/extensions/backend/PACK.md +104 -104
  27. package/extensions/backend/skills/api-patterns.md +84 -84
  28. package/extensions/backend/skills/async-pipeline.md +193 -193
  29. package/extensions/backend/skills/auth-patterns.md +97 -97
  30. package/extensions/backend/skills/background-jobs.md +133 -133
  31. package/extensions/backend/skills/caching-patterns.md +108 -108
  32. package/extensions/backend/skills/cli-generation.md +133 -133
  33. package/extensions/backend/skills/database-patterns.md +87 -87
  34. package/extensions/backend/skills/middleware-patterns.md +104 -104
  35. package/extensions/chrome-ext/PACK.md +93 -93
  36. package/extensions/chrome-ext/skills/cws-preflight.md +143 -143
  37. package/extensions/chrome-ext/skills/cws-publish.md +104 -104
  38. package/extensions/chrome-ext/skills/ext-ai-integration.md +251 -251
  39. package/extensions/chrome-ext/skills/ext-messaging.md +139 -139
  40. package/extensions/chrome-ext/skills/ext-storage.md +133 -133
  41. package/extensions/chrome-ext/skills/mv3-scaffold.md +164 -164
  42. package/extensions/content/PACK.md +96 -96
  43. package/extensions/content/skills/blog-patterns.md +88 -88
  44. package/extensions/content/skills/cms-integration.md +131 -131
  45. package/extensions/content/skills/content-scoring.md +107 -107
  46. package/extensions/content/skills/i18n.md +83 -83
  47. package/extensions/content/skills/mdx-authoring.md +137 -137
  48. package/extensions/content/skills/reference.md +1014 -1014
  49. package/extensions/content/skills/seo-patterns.md +67 -67
  50. package/extensions/content/skills/video-repurpose.md +153 -153
  51. package/extensions/devops/PACK.md +101 -101
  52. package/extensions/devops/skills/chaos-testing.md +67 -67
  53. package/extensions/devops/skills/ci-cd.md +75 -75
  54. package/extensions/devops/skills/docker.md +58 -58
  55. package/extensions/devops/skills/edge-serverless.md +163 -163
  56. package/extensions/devops/skills/infra-as-code.md +158 -158
  57. package/extensions/devops/skills/kubernetes.md +110 -110
  58. package/extensions/devops/skills/monitoring.md +57 -57
  59. package/extensions/devops/skills/server-setup.md +64 -64
  60. package/extensions/devops/skills/ssl-domain.md +42 -42
  61. package/extensions/ecommerce/PACK.md +116 -116
  62. package/extensions/ecommerce/skills/cart-system.md +79 -79
  63. package/extensions/ecommerce/skills/inventory-mgmt.md +102 -102
  64. package/extensions/ecommerce/skills/order-management.md +126 -126
  65. package/extensions/ecommerce/skills/payment-integration.md +472 -472
  66. package/extensions/ecommerce/skills/shopify-dev.md +69 -69
  67. package/extensions/ecommerce/skills/subscription-billing.md +93 -93
  68. package/extensions/ecommerce/skills/tax-compliance.md +117 -117
  69. package/extensions/gamedev/PACK.md +142 -142
  70. package/extensions/gamedev/skills/asset-pipeline.md +74 -74
  71. package/extensions/gamedev/skills/audio-system.md +129 -129
  72. package/extensions/gamedev/skills/camera-system.md +87 -87
  73. package/extensions/gamedev/skills/ecs.md +98 -98
  74. package/extensions/gamedev/skills/game-loops.md +72 -72
  75. package/extensions/gamedev/skills/input-system.md +199 -199
  76. package/extensions/gamedev/skills/multiplayer.md +180 -180
  77. package/extensions/gamedev/skills/particles.md +105 -105
  78. package/extensions/gamedev/skills/physics-engine.md +89 -89
  79. package/extensions/gamedev/skills/scene-management.md +146 -146
  80. package/extensions/gamedev/skills/threejs-patterns.md +90 -90
  81. package/extensions/gamedev/skills/webgl.md +71 -71
  82. package/extensions/mobile/PACK.md +106 -106
  83. package/extensions/mobile/skills/app-store-connect.md +152 -152
  84. package/extensions/mobile/skills/app-store-prep.md +66 -66
  85. package/extensions/mobile/skills/deep-linking.md +109 -109
  86. package/extensions/mobile/skills/flutter.md +60 -60
  87. package/extensions/mobile/skills/ios-build-pipeline.md +142 -142
  88. package/extensions/mobile/skills/native-bridge.md +66 -66
  89. package/extensions/mobile/skills/ota-updates.md +97 -97
  90. package/extensions/mobile/skills/push-notifications.md +111 -111
  91. package/extensions/mobile/skills/react-native.md +82 -82
  92. package/extensions/saas/PACK.md +116 -116
  93. package/extensions/saas/skills/billing-integration.md +200 -200
  94. package/extensions/saas/skills/feature-flags.md +130 -130
  95. package/extensions/saas/skills/multi-tenant.md +103 -103
  96. package/extensions/saas/skills/onboarding-flow.md +139 -139
  97. package/extensions/saas/skills/subscription-flow.md +95 -95
  98. package/extensions/saas/skills/team-management.md +144 -144
  99. package/extensions/security/PACK.md +99 -99
  100. package/extensions/security/skills/api-security.md +140 -140
  101. package/extensions/security/skills/compliance.md +68 -68
  102. package/extensions/security/skills/owasp-audit.md +64 -64
  103. package/extensions/security/skills/pentest-patterns.md +77 -77
  104. package/extensions/security/skills/secret-mgmt.md +65 -65
  105. package/extensions/security/skills/supply-chain.md +65 -65
  106. package/extensions/trading/PACK.md +80 -80
  107. package/extensions/trading/skills/chart-components.md +55 -55
  108. package/extensions/trading/skills/experiment-loop.md +125 -125
  109. package/extensions/trading/skills/fintech-patterns.md +47 -47
  110. package/extensions/trading/skills/indicator-library.md +58 -58
  111. package/extensions/trading/skills/quant-analysis.md +111 -111
  112. package/extensions/trading/skills/realtime-data.md +58 -58
  113. package/extensions/trading/skills/trade-logic.md +104 -104
  114. package/extensions/ui/PACK.md +130 -130
  115. package/extensions/ui/skills/a11y-audit.md +91 -91
  116. package/extensions/ui/skills/animation-patterns.md +127 -127
  117. package/extensions/ui/skills/component-patterns.md +100 -100
  118. package/extensions/ui/skills/design-decision.md +108 -108
  119. package/extensions/ui/skills/design-system.md +68 -68
  120. package/extensions/ui/skills/landing-patterns.md +155 -155
  121. package/extensions/ui/skills/palette-picker.md +173 -173
  122. package/extensions/ui/skills/react-health.md +90 -90
  123. package/extensions/ui/skills/type-system.md +125 -125
  124. package/extensions/ui/skills/web-vitals.md +153 -153
  125. package/extensions/zalo/PACK.md +145 -145
  126. package/extensions/zalo/skills/zalo-oa-mcp.md +317 -317
  127. package/extensions/zalo/skills/zalo-oa-messaging.md +429 -429
  128. package/extensions/zalo/skills/zalo-oa-setup.md +236 -236
  129. package/extensions/zalo/skills/zalo-oa-webhook.md +189 -189
  130. package/extensions/zalo/skills/zalo-personal-messaging.md +194 -194
  131. package/extensions/zalo/skills/zalo-personal-setup.md +153 -153
  132. package/extensions/zalo/skills/zalo-rate-guard.md +219 -219
  133. package/hooks/auto-format/index.cjs +48 -48
  134. package/hooks/hooks.json +111 -111
  135. package/hooks/post-session-reflect/index.cjs +189 -189
  136. package/hooks/pre-compact/index.cjs +95 -95
  137. package/hooks/run-hook.cmd +1 -1
  138. package/hooks/secrets-scan/index.cjs +100 -100
  139. package/hooks/session-start/index.cjs +71 -71
  140. package/hooks/typecheck/index.cjs +65 -65
  141. package/package.json +63 -63
  142. package/references/ui-pro-max-data/LICENSE-UI-PRO-MAX +21 -21
  143. package/references/ui-pro-max-data/charts.csv +26 -26
  144. package/references/ui-pro-max-data/colors.csv +161 -161
  145. package/references/ui-pro-max-data/styles.csv +68 -68
  146. package/references/ui-pro-max-data/typography.csv +74 -74
  147. package/references/ui-pro-max-data/ui-reasoning.csv +162 -162
  148. package/references/ui-pro-max-data/ux-guidelines.csv +99 -99
  149. package/skills/adversary/SKILL.md +283 -283
  150. package/skills/asset-creator/SKILL.md +157 -157
  151. package/skills/audit/SKILL.md +147 -2
  152. package/skills/autopsy/SKILL.md +335 -335
  153. package/skills/brainstorm/SKILL.md +342 -342
  154. package/skills/browser-pilot/SKILL.md +168 -168
  155. package/skills/constraint-check/SKILL.md +165 -165
  156. package/skills/context-engine/SKILL.md +404 -404
  157. package/skills/cook/SKILL.md +917 -863
  158. package/skills/db/SKILL.md +273 -273
  159. package/skills/debug/SKILL.md +465 -465
  160. package/skills/dependency-doctor/SKILL.md +265 -235
  161. package/skills/deploy/SKILL.md +274 -231
  162. package/skills/design/DESIGN-REFERENCE.md +365 -365
  163. package/skills/design/SKILL.md +589 -589
  164. package/skills/doc-processor/SKILL.md +254 -254
  165. package/skills/docs/SKILL.md +374 -374
  166. package/skills/docs-seeker/SKILL.md +177 -177
  167. package/skills/fix/SKILL.md +330 -330
  168. package/skills/git/SKILL.md +339 -339
  169. package/skills/hallucination-guard/SKILL.md +219 -219
  170. package/skills/incident/SKILL.md +254 -253
  171. package/skills/integrity-check/SKILL.md +169 -169
  172. package/skills/journal/SKILL.md +240 -240
  173. package/skills/launch/SKILL.md +344 -344
  174. package/skills/logic-guardian/SKILL.md +251 -251
  175. package/skills/marketing/SKILL.md +290 -289
  176. package/skills/mcp-builder/SKILL.md +425 -425
  177. package/skills/neural-memory/SKILL.md +362 -362
  178. package/skills/onboard/SKILL.md +404 -403
  179. package/skills/perf/SKILL.md +346 -346
  180. package/skills/plan/SKILL.md +433 -428
  181. package/skills/preflight/SKILL.md +415 -415
  182. package/skills/problem-solver/SKILL.md +380 -284
  183. package/skills/rescue/SKILL.md +474 -474
  184. package/skills/retro/SKILL.md +3 -1
  185. package/skills/review/SKILL.md +612 -588
  186. package/skills/review-intake/SKILL.md +249 -249
  187. package/skills/safeguard/SKILL.md +200 -200
  188. package/skills/sast/SKILL.md +190 -190
  189. package/skills/scaffold/SKILL.md +328 -287
  190. package/skills/scope-guard/SKILL.md +180 -180
  191. package/skills/scout/SKILL.md +263 -263
  192. package/skills/sentinel/SKILL.md +382 -381
  193. package/skills/sentinel-env/SKILL.md +254 -254
  194. package/skills/sequential-thinking/SKILL.md +234 -234
  195. package/skills/session-bridge/SKILL.md +543 -543
  196. package/skills/skill-forge/SKILL.md +581 -581
  197. package/skills/skill-router/SKILL.md +3 -0
  198. package/skills/surgeon/SKILL.md +215 -215
  199. package/skills/team/SKILL.md +556 -537
  200. package/skills/test/SKILL.md +614 -614
  201. package/skills/trend-scout/SKILL.md +145 -145
  202. package/skills/verification/SKILL.md +326 -326
  203. package/skills/video-creator/SKILL.md +201 -201
  204. package/skills/watchdog/SKILL.md +168 -168
  205. package/skills/worktree/SKILL.md +140 -140
@@ -1,194 +1,194 @@
1
- ---
2
- name: zalo-personal-messaging
3
- pack: "@rune/zalo"
4
- description: Personal and group messaging via zca-js — text, media, reactions, group management, mention gating, message buffer for context. UNOFFICIAL — risk-gated.
5
- model: sonnet
6
- tools: "Read, Glob, Grep, Bash, Write, Edit"
7
- ---
8
-
9
- # zalo-personal-messaging
10
-
11
- > ⚠️ Track B (unofficial). See zalo-personal-setup for full risk disclaimer.
12
- > This skill assumes you have completed zalo-personal-setup and have an active API instance.
13
-
14
- ## Overview
15
-
16
- Send messages, media, and reactions to Zalo personal accounts and groups via zca-js. Covers 1:1 DMs, group messaging, mention-gated bot patterns, and context buffering.
17
-
18
- ---
19
-
20
- ## Direct Messages (1:1)
21
-
22
- ```typescript
23
- // Send text
24
- await api.sendMessage('Hello!', threadId, 'User')
25
-
26
- // Send image (local file path — download first if URL)
27
- await api.sendMessage({
28
- body: 'Check this image',
29
- attachments: [imagePath]
30
- }, threadId, 'User')
31
-
32
- // Chunk long messages (2000-char limit applies to DMs too)
33
- async function sendLong(text: string, threadId: string, type: 'User' | 'Group') {
34
- const chunks = text.match(/.{1,1900}/gs) ?? [text]
35
- for (const chunk of chunks) {
36
- await api.sendMessage(chunk, threadId, type)
37
- }
38
- }
39
- ```
40
-
41
- ---
42
-
43
- ## Group Messaging
44
-
45
- ```typescript
46
- // Send to group
47
- await api.sendMessage('Hello group!', groupId, 'Group')
48
-
49
- // Send with mention
50
- await api.sendMessage({
51
- body: '@John check this',
52
- mentions: [{ pos: 0, len: 5, uid: johnUserId }]
53
- }, groupId, 'Group')
54
-
55
- // Group management
56
- await api.createGroup('Bot Test Group', [userId1, userId2]) // min 3 members incl. self
57
- await api.addGroupMembers(groupId, [newMemberId])
58
- await api.removeGroupMembers(groupId, [memberId])
59
- await api.changeGroupName(groupId, 'New Name')
60
- ```
61
-
62
- ---
63
-
64
- ## Media Types
65
-
66
- | Type | Notes |
67
- |------|-------|
68
- | Text | 2000-char limit — chunk if needed |
69
- | Image | Local file path only — download URL first |
70
- | Video | Local file path |
71
- | Voice | Local file path |
72
- | Sticker | By sticker ID — IDs undocumented, capture from received msgs |
73
- | File | Local file path |
74
- | Contact card | User ID reference |
75
- | Link | Auto-generates preview |
76
-
77
- ---
78
-
79
- ## Reactions
80
-
81
- ```typescript
82
- // React to a message (11 types)
83
- await api.sendReaction(messageId, threadId, '❤️', 'User')
84
-
85
- // Available: ❤️ 😆 😮 😢 😠 👍 👎 ✊ 🎉 😏 🥰
86
- ```
87
-
88
- ---
89
-
90
- ## Mention Gating Pattern
91
-
92
- For group bots — only process when @mentioned, buffer other messages for context:
93
-
94
- ```typescript
95
- function isMentioned(msg: GroupMessage, botId: string): boolean {
96
- return msg.data.mentions?.some(m => m.uid === botId) ?? false
97
- }
98
-
99
- listener.on('group_message', async (msg) => {
100
- if (!isMentioned(msg, BOT_USER_ID)) {
101
- messageBuffer.push(msg) // buffer for context
102
- return
103
- }
104
- // Bot was mentioned — process with buffered context
105
- const context = messageBuffer.getRecent(msg.threadId, 20)
106
- const response = await processWithContext(msg, context)
107
- await api.sendMessage(response, msg.threadId, 'Group')
108
- })
109
- ```
110
-
111
- > Use `msg.data.mentions` array — never parse `@` from message text (unreliable).
112
-
113
- ---
114
-
115
- ## Message Buffer
116
-
117
- Buffer recent group messages per thread for context injection:
118
-
119
- ```typescript
120
- class MessageBuffer {
121
- private buffer: Map<string, Message[]> = new Map()
122
- private maxPerThread = 50
123
-
124
- push(msg: Message) {
125
- const threadId = msg.threadId
126
- const msgs = this.buffer.get(threadId) ?? []
127
- msgs.push(msg)
128
- if (msgs.length > this.maxPerThread) msgs.shift() // cap to avoid unbounded growth
129
- this.buffer.set(threadId, msgs)
130
- }
131
-
132
- getRecent(threadId: string, count: number): Message[] {
133
- return (this.buffer.get(threadId) ?? []).slice(-count)
134
- }
135
- }
136
- ```
137
-
138
- ---
139
-
140
- ## Name Cache
141
-
142
- Resolve user IDs to display names with TTL to avoid API hammering:
143
-
144
- ```typescript
145
- class NameCache {
146
- private cache = new Map<string, { name: string; expiresAt: number }>()
147
- private ttl = 60 * 60 * 1000 // 1 hour
148
-
149
- async resolve(userId: string, api: ZaloApi): Promise<string> {
150
- const cached = this.cache.get(userId)
151
- if (cached && cached.expiresAt > Date.now()) return cached.name
152
- try {
153
- const profile = await api.getUserInfo(userId)
154
- const name = profile.displayName || 'Unknown'
155
- this.cache.set(userId, { name, expiresAt: Date.now() + this.ttl })
156
- return name
157
- } catch {
158
- return 'Unknown'
159
- }
160
- }
161
- }
162
- ```
163
-
164
- ---
165
-
166
- ## Event Listeners
167
-
168
- ```typescript
169
- // DM and group events are SEPARATE — wire both
170
- listener.on('message', async (msg) => {
171
- // 1:1 personal messages
172
- const senderId = msg.data.uidFrom
173
- await handleDM(msg, senderId)
174
- })
175
-
176
- listener.on('group_message', async (msg) => {
177
- // Group messages — includes mention data
178
- const senderId = msg.data.uidFrom
179
- await handleGroup(msg, senderId)
180
- })
181
- ```
182
-
183
- ---
184
-
185
- ## Sharp Edges
186
-
187
- - **Separate events**: `message` (DM) vs `group_message` (group) — missing one = silent drop
188
- - **Mention detection**: check `msg.data.mentions` array, not text `@` parsing
189
- - **2000-char limit**: applies to both DM and group — always chunk
190
- - **Image upload**: local file path only — download remote URLs before sending
191
- - **Sticker IDs**: undocumented — sniff from received sticker messages to build your own map
192
- - **Group create**: minimum 3 members including self — 2-member call throws
193
- - **Buffer cap**: always set `maxPerThread` — unbounded growth crashes long-running bots
194
- - **Name cache TTL**: don't skip — `getUserInfo` rate-limited aggressively on personal accounts
1
+ ---
2
+ name: zalo-personal-messaging
3
+ pack: "@rune/zalo"
4
+ description: Personal and group messaging via zca-js — text, media, reactions, group management, mention gating, message buffer for context. UNOFFICIAL — risk-gated.
5
+ model: sonnet
6
+ tools: "Read, Glob, Grep, Bash, Write, Edit"
7
+ ---
8
+
9
+ # zalo-personal-messaging
10
+
11
+ > ⚠️ Track B (unofficial). See zalo-personal-setup for full risk disclaimer.
12
+ > This skill assumes you have completed zalo-personal-setup and have an active API instance.
13
+
14
+ ## Overview
15
+
16
+ Send messages, media, and reactions to Zalo personal accounts and groups via zca-js. Covers 1:1 DMs, group messaging, mention-gated bot patterns, and context buffering.
17
+
18
+ ---
19
+
20
+ ## Direct Messages (1:1)
21
+
22
+ ```typescript
23
+ // Send text
24
+ await api.sendMessage('Hello!', threadId, 'User')
25
+
26
+ // Send image (local file path — download first if URL)
27
+ await api.sendMessage({
28
+ body: 'Check this image',
29
+ attachments: [imagePath]
30
+ }, threadId, 'User')
31
+
32
+ // Chunk long messages (2000-char limit applies to DMs too)
33
+ async function sendLong(text: string, threadId: string, type: 'User' | 'Group') {
34
+ const chunks = text.match(/.{1,1900}/gs) ?? [text]
35
+ for (const chunk of chunks) {
36
+ await api.sendMessage(chunk, threadId, type)
37
+ }
38
+ }
39
+ ```
40
+
41
+ ---
42
+
43
+ ## Group Messaging
44
+
45
+ ```typescript
46
+ // Send to group
47
+ await api.sendMessage('Hello group!', groupId, 'Group')
48
+
49
+ // Send with mention
50
+ await api.sendMessage({
51
+ body: '@John check this',
52
+ mentions: [{ pos: 0, len: 5, uid: johnUserId }]
53
+ }, groupId, 'Group')
54
+
55
+ // Group management
56
+ await api.createGroup('Bot Test Group', [userId1, userId2]) // min 3 members incl. self
57
+ await api.addGroupMembers(groupId, [newMemberId])
58
+ await api.removeGroupMembers(groupId, [memberId])
59
+ await api.changeGroupName(groupId, 'New Name')
60
+ ```
61
+
62
+ ---
63
+
64
+ ## Media Types
65
+
66
+ | Type | Notes |
67
+ |------|-------|
68
+ | Text | 2000-char limit — chunk if needed |
69
+ | Image | Local file path only — download URL first |
70
+ | Video | Local file path |
71
+ | Voice | Local file path |
72
+ | Sticker | By sticker ID — IDs undocumented, capture from received msgs |
73
+ | File | Local file path |
74
+ | Contact card | User ID reference |
75
+ | Link | Auto-generates preview |
76
+
77
+ ---
78
+
79
+ ## Reactions
80
+
81
+ ```typescript
82
+ // React to a message (11 types)
83
+ await api.sendReaction(messageId, threadId, '❤️', 'User')
84
+
85
+ // Available: ❤️ 😆 😮 😢 😠 👍 👎 ✊ 🎉 😏 🥰
86
+ ```
87
+
88
+ ---
89
+
90
+ ## Mention Gating Pattern
91
+
92
+ For group bots — only process when @mentioned, buffer other messages for context:
93
+
94
+ ```typescript
95
+ function isMentioned(msg: GroupMessage, botId: string): boolean {
96
+ return msg.data.mentions?.some(m => m.uid === botId) ?? false
97
+ }
98
+
99
+ listener.on('group_message', async (msg) => {
100
+ if (!isMentioned(msg, BOT_USER_ID)) {
101
+ messageBuffer.push(msg) // buffer for context
102
+ return
103
+ }
104
+ // Bot was mentioned — process with buffered context
105
+ const context = messageBuffer.getRecent(msg.threadId, 20)
106
+ const response = await processWithContext(msg, context)
107
+ await api.sendMessage(response, msg.threadId, 'Group')
108
+ })
109
+ ```
110
+
111
+ > Use `msg.data.mentions` array — never parse `@` from message text (unreliable).
112
+
113
+ ---
114
+
115
+ ## Message Buffer
116
+
117
+ Buffer recent group messages per thread for context injection:
118
+
119
+ ```typescript
120
+ class MessageBuffer {
121
+ private buffer: Map<string, Message[]> = new Map()
122
+ private maxPerThread = 50
123
+
124
+ push(msg: Message) {
125
+ const threadId = msg.threadId
126
+ const msgs = this.buffer.get(threadId) ?? []
127
+ msgs.push(msg)
128
+ if (msgs.length > this.maxPerThread) msgs.shift() // cap to avoid unbounded growth
129
+ this.buffer.set(threadId, msgs)
130
+ }
131
+
132
+ getRecent(threadId: string, count: number): Message[] {
133
+ return (this.buffer.get(threadId) ?? []).slice(-count)
134
+ }
135
+ }
136
+ ```
137
+
138
+ ---
139
+
140
+ ## Name Cache
141
+
142
+ Resolve user IDs to display names with TTL to avoid API hammering:
143
+
144
+ ```typescript
145
+ class NameCache {
146
+ private cache = new Map<string, { name: string; expiresAt: number }>()
147
+ private ttl = 60 * 60 * 1000 // 1 hour
148
+
149
+ async resolve(userId: string, api: ZaloApi): Promise<string> {
150
+ const cached = this.cache.get(userId)
151
+ if (cached && cached.expiresAt > Date.now()) return cached.name
152
+ try {
153
+ const profile = await api.getUserInfo(userId)
154
+ const name = profile.displayName || 'Unknown'
155
+ this.cache.set(userId, { name, expiresAt: Date.now() + this.ttl })
156
+ return name
157
+ } catch {
158
+ return 'Unknown'
159
+ }
160
+ }
161
+ }
162
+ ```
163
+
164
+ ---
165
+
166
+ ## Event Listeners
167
+
168
+ ```typescript
169
+ // DM and group events are SEPARATE — wire both
170
+ listener.on('message', async (msg) => {
171
+ // 1:1 personal messages
172
+ const senderId = msg.data.uidFrom
173
+ await handleDM(msg, senderId)
174
+ })
175
+
176
+ listener.on('group_message', async (msg) => {
177
+ // Group messages — includes mention data
178
+ const senderId = msg.data.uidFrom
179
+ await handleGroup(msg, senderId)
180
+ })
181
+ ```
182
+
183
+ ---
184
+
185
+ ## Sharp Edges
186
+
187
+ - **Separate events**: `message` (DM) vs `group_message` (group) — missing one = silent drop
188
+ - **Mention detection**: check `msg.data.mentions` array, not text `@` parsing
189
+ - **2000-char limit**: applies to both DM and group — always chunk
190
+ - **Image upload**: local file path only — download remote URLs before sending
191
+ - **Sticker IDs**: undocumented — sniff from received sticker messages to build your own map
192
+ - **Group create**: minimum 3 members including self — 2-member call throws
193
+ - **Buffer cap**: always set `maxPerThread` — unbounded growth crashes long-running bots
194
+ - **Name cache TTL**: don't skip — `getUserInfo` rate-limited aggressively on personal accounts