@rozek/nanoclaw 0.0.5 → 0.0.6

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 (132) hide show
  1. package/container/agent-runner/package-lock.json +1524 -0
  2. package/dist/cli.js +39 -4
  3. package/dist/cli.js.map +1 -1
  4. package/dist/index.d.ts.map +1 -1
  5. package/dist/index.js +34 -0
  6. package/dist/index.js.map +1 -1
  7. package/package.json +7 -1
  8. package/.claude/settings.json +0 -1
  9. package/.claude/skills/add-compact/SKILL.md +0 -135
  10. package/.claude/skills/add-discord/SKILL.md +0 -203
  11. package/.claude/skills/add-gmail/SKILL.md +0 -220
  12. package/.claude/skills/add-image-vision/SKILL.md +0 -94
  13. package/.claude/skills/add-ollama-tool/SKILL.md +0 -153
  14. package/.claude/skills/add-parallel/SKILL.md +0 -290
  15. package/.claude/skills/add-pdf-reader/SKILL.md +0 -104
  16. package/.claude/skills/add-reactions/SKILL.md +0 -117
  17. package/.claude/skills/add-slack/SKILL.md +0 -207
  18. package/.claude/skills/add-telegram/SKILL.md +0 -222
  19. package/.claude/skills/add-telegram-swarm/SKILL.md +0 -384
  20. package/.claude/skills/add-voice-transcription/SKILL.md +0 -148
  21. package/.claude/skills/add-whatsapp/SKILL.md +0 -372
  22. package/.claude/skills/convert-to-apple-container/SKILL.md +0 -175
  23. package/.claude/skills/customize/SKILL.md +0 -110
  24. package/.claude/skills/debug/SKILL.md +0 -349
  25. package/.claude/skills/get-qodo-rules/SKILL.md +0 -122
  26. package/.claude/skills/get-qodo-rules/references/output-format.md +0 -41
  27. package/.claude/skills/get-qodo-rules/references/pagination.md +0 -33
  28. package/.claude/skills/get-qodo-rules/references/repository-scope.md +0 -26
  29. package/.claude/skills/qodo-pr-resolver/SKILL.md +0 -326
  30. package/.claude/skills/qodo-pr-resolver/resources/providers.md +0 -329
  31. package/.claude/skills/setup/SKILL.md +0 -218
  32. package/.claude/skills/update-nanoclaw/SKILL.md +0 -235
  33. package/.claude/skills/update-skills/SKILL.md +0 -130
  34. package/.claude/skills/use-local-whisper/SKILL.md +0 -152
  35. package/.claude/skills/x-integration/SKILL.md +0 -417
  36. package/.claude/skills/x-integration/agent.ts +0 -243
  37. package/.claude/skills/x-integration/host.ts +0 -159
  38. package/.claude/skills/x-integration/lib/browser.ts +0 -148
  39. package/.claude/skills/x-integration/lib/config.ts +0 -62
  40. package/.claude/skills/x-integration/scripts/like.ts +0 -56
  41. package/.claude/skills/x-integration/scripts/post.ts +0 -66
  42. package/.claude/skills/x-integration/scripts/quote.ts +0 -80
  43. package/.claude/skills/x-integration/scripts/reply.ts +0 -74
  44. package/.claude/skills/x-integration/scripts/retweet.ts +0 -62
  45. package/.claude/skills/x-integration/scripts/setup.ts +0 -87
  46. package/.env.example +0 -1
  47. package/.github/CODEOWNERS +0 -10
  48. package/.github/PULL_REQUEST_TEMPLATE.md +0 -14
  49. package/.github/workflows/bump-version.yml +0 -32
  50. package/.github/workflows/ci.yml +0 -25
  51. package/.github/workflows/merge-forward-skills.yml +0 -160
  52. package/.github/workflows/update-tokens.yml +0 -42
  53. package/.husky/pre-commit +0 -1
  54. package/.mcp.json +0 -3
  55. package/.nvmrc +0 -1
  56. package/.prettierrc +0 -3
  57. package/CHANGELOG.md +0 -8
  58. package/CONTRIBUTING.md +0 -23
  59. package/CONTRIBUTORS.md +0 -15
  60. package/NanoClaw_with_Web-Support.md +0 -326
  61. package/README_zh.md +0 -200
  62. package/assets/nanoclaw-favicon.png +0 -0
  63. package/assets/nanoclaw-icon.png +0 -0
  64. package/assets/nanoclaw-logo-dark.png +0 -0
  65. package/assets/nanoclaw-logo.png +0 -0
  66. package/assets/nanoclaw-profile.jpeg +0 -0
  67. package/assets/nanoclaw-sales.png +0 -0
  68. package/assets/social-preview.jpg +0 -0
  69. package/config-examples/mount-allowlist.json +0 -25
  70. package/docs/APPLE-CONTAINER-NETWORKING.md +0 -90
  71. package/docs/DEBUG_CHECKLIST.md +0 -143
  72. package/docs/REQUIREMENTS.md +0 -196
  73. package/docs/SDK_DEEP_DIVE.md +0 -643
  74. package/docs/SECURITY.md +0 -122
  75. package/docs/SPEC.md +0 -785
  76. package/docs/docker-sandboxes.md +0 -359
  77. package/docs/nanoclaw-architecture-final.md +0 -1063
  78. package/docs/nanorepo-architecture.md +0 -168
  79. package/docs/skills-as-branches.md +0 -662
  80. package/groups/global/CLAUDE.md +0 -58
  81. package/groups/main/CLAUDE.md +0 -246
  82. package/launchd/com.nanoclaw.plist +0 -32
  83. package/repo-tokens/README.md +0 -113
  84. package/repo-tokens/action.yml +0 -186
  85. package/repo-tokens/badge.svg +0 -23
  86. package/repo-tokens/examples/green.svg +0 -14
  87. package/repo-tokens/examples/red.svg +0 -14
  88. package/repo-tokens/examples/yellow-green.svg +0 -14
  89. package/repo-tokens/examples/yellow.svg +0 -14
  90. package/scripts/run-migrations.ts +0 -105
  91. package/setup.sh +0 -161
  92. package/src/channels/index.ts +0 -15
  93. package/src/channels/registry.test.ts +0 -42
  94. package/src/channels/registry.ts +0 -32
  95. package/src/channels/web.ts +0 -1931
  96. package/src/cli.ts +0 -254
  97. package/src/config.ts +0 -73
  98. package/src/container-runner.test.ts +0 -210
  99. package/src/container-runner.ts +0 -768
  100. package/src/container-runtime.test.ts +0 -149
  101. package/src/container-runtime.ts +0 -127
  102. package/src/credential-proxy.test.ts +0 -192
  103. package/src/credential-proxy.ts +0 -125
  104. package/src/db.test.ts +0 -484
  105. package/src/db.ts +0 -803
  106. package/src/env.ts +0 -42
  107. package/src/formatting.test.ts +0 -256
  108. package/src/group-folder.test.ts +0 -43
  109. package/src/group-folder.ts +0 -44
  110. package/src/group-queue.test.ts +0 -484
  111. package/src/group-queue.ts +0 -379
  112. package/src/index.ts +0 -854
  113. package/src/ipc-auth.test.ts +0 -679
  114. package/src/ipc.ts +0 -461
  115. package/src/logger.ts +0 -16
  116. package/src/mount-security.ts +0 -419
  117. package/src/remote-control.test.ts +0 -397
  118. package/src/remote-control.ts +0 -224
  119. package/src/router.ts +0 -52
  120. package/src/routing.test.ts +0 -170
  121. package/src/sender-allowlist.test.ts +0 -216
  122. package/src/sender-allowlist.ts +0 -128
  123. package/src/session-commands.test.ts +0 -247
  124. package/src/session-commands.ts +0 -163
  125. package/src/task-scheduler.test.ts +0 -129
  126. package/src/task-scheduler.ts +0 -328
  127. package/src/timezone.test.ts +0 -29
  128. package/src/timezone.ts +0 -16
  129. package/src/types.ts +0 -109
  130. package/tsconfig.json +0 -20
  131. package/vitest.config.ts +0 -7
  132. package/vitest.skills.config.ts +0 -7
package/src/db.test.ts DELETED
@@ -1,484 +0,0 @@
1
- import { describe, it, expect, beforeEach } from 'vitest';
2
-
3
- import {
4
- _initTestDatabase,
5
- createTask,
6
- deleteTask,
7
- getAllChats,
8
- getAllRegisteredGroups,
9
- getMessagesSince,
10
- getNewMessages,
11
- getTaskById,
12
- setRegisteredGroup,
13
- storeChatMetadata,
14
- storeMessage,
15
- updateTask,
16
- } from './db.js';
17
-
18
- beforeEach(() => {
19
- _initTestDatabase();
20
- });
21
-
22
- // Helper to store a message using the normalized NewMessage interface
23
- function store(overrides: {
24
- id: string;
25
- chat_jid: string;
26
- sender: string;
27
- sender_name: string;
28
- content: string;
29
- timestamp: string;
30
- is_from_me?: boolean;
31
- }) {
32
- storeMessage({
33
- id: overrides.id,
34
- chat_jid: overrides.chat_jid,
35
- sender: overrides.sender,
36
- sender_name: overrides.sender_name,
37
- content: overrides.content,
38
- timestamp: overrides.timestamp,
39
- is_from_me: overrides.is_from_me ?? false,
40
- });
41
- }
42
-
43
- // --- storeMessage (NewMessage format) ---
44
-
45
- describe('storeMessage', () => {
46
- it('stores a message and retrieves it', () => {
47
- storeChatMetadata('group@g.us', '2024-01-01T00:00:00.000Z');
48
-
49
- store({
50
- id: 'msg-1',
51
- chat_jid: 'group@g.us',
52
- sender: '123@s.whatsapp.net',
53
- sender_name: 'Alice',
54
- content: 'hello world',
55
- timestamp: '2024-01-01T00:00:01.000Z',
56
- });
57
-
58
- const messages = getMessagesSince(
59
- 'group@g.us',
60
- '2024-01-01T00:00:00.000Z',
61
- 'Andy',
62
- );
63
- expect(messages).toHaveLength(1);
64
- expect(messages[0].id).toBe('msg-1');
65
- expect(messages[0].sender).toBe('123@s.whatsapp.net');
66
- expect(messages[0].sender_name).toBe('Alice');
67
- expect(messages[0].content).toBe('hello world');
68
- });
69
-
70
- it('filters out empty content', () => {
71
- storeChatMetadata('group@g.us', '2024-01-01T00:00:00.000Z');
72
-
73
- store({
74
- id: 'msg-2',
75
- chat_jid: 'group@g.us',
76
- sender: '111@s.whatsapp.net',
77
- sender_name: 'Dave',
78
- content: '',
79
- timestamp: '2024-01-01T00:00:04.000Z',
80
- });
81
-
82
- const messages = getMessagesSince(
83
- 'group@g.us',
84
- '2024-01-01T00:00:00.000Z',
85
- 'Andy',
86
- );
87
- expect(messages).toHaveLength(0);
88
- });
89
-
90
- it('stores is_from_me flag', () => {
91
- storeChatMetadata('group@g.us', '2024-01-01T00:00:00.000Z');
92
-
93
- store({
94
- id: 'msg-3',
95
- chat_jid: 'group@g.us',
96
- sender: 'me@s.whatsapp.net',
97
- sender_name: 'Me',
98
- content: 'my message',
99
- timestamp: '2024-01-01T00:00:05.000Z',
100
- is_from_me: true,
101
- });
102
-
103
- // Message is stored (we can retrieve it — is_from_me doesn't affect retrieval)
104
- const messages = getMessagesSince(
105
- 'group@g.us',
106
- '2024-01-01T00:00:00.000Z',
107
- 'Andy',
108
- );
109
- expect(messages).toHaveLength(1);
110
- });
111
-
112
- it('upserts on duplicate id+chat_jid', () => {
113
- storeChatMetadata('group@g.us', '2024-01-01T00:00:00.000Z');
114
-
115
- store({
116
- id: 'msg-dup',
117
- chat_jid: 'group@g.us',
118
- sender: '123@s.whatsapp.net',
119
- sender_name: 'Alice',
120
- content: 'original',
121
- timestamp: '2024-01-01T00:00:01.000Z',
122
- });
123
-
124
- store({
125
- id: 'msg-dup',
126
- chat_jid: 'group@g.us',
127
- sender: '123@s.whatsapp.net',
128
- sender_name: 'Alice',
129
- content: 'updated',
130
- timestamp: '2024-01-01T00:00:01.000Z',
131
- });
132
-
133
- const messages = getMessagesSince(
134
- 'group@g.us',
135
- '2024-01-01T00:00:00.000Z',
136
- 'Andy',
137
- );
138
- expect(messages).toHaveLength(1);
139
- expect(messages[0].content).toBe('updated');
140
- });
141
- });
142
-
143
- // --- getMessagesSince ---
144
-
145
- describe('getMessagesSince', () => {
146
- beforeEach(() => {
147
- storeChatMetadata('group@g.us', '2024-01-01T00:00:00.000Z');
148
-
149
- store({
150
- id: 'm1',
151
- chat_jid: 'group@g.us',
152
- sender: 'Alice@s.whatsapp.net',
153
- sender_name: 'Alice',
154
- content: 'first',
155
- timestamp: '2024-01-01T00:00:01.000Z',
156
- });
157
- store({
158
- id: 'm2',
159
- chat_jid: 'group@g.us',
160
- sender: 'Bob@s.whatsapp.net',
161
- sender_name: 'Bob',
162
- content: 'second',
163
- timestamp: '2024-01-01T00:00:02.000Z',
164
- });
165
- storeMessage({
166
- id: 'm3',
167
- chat_jid: 'group@g.us',
168
- sender: 'Bot@s.whatsapp.net',
169
- sender_name: 'Bot',
170
- content: 'bot reply',
171
- timestamp: '2024-01-01T00:00:03.000Z',
172
- is_bot_message: true,
173
- });
174
- store({
175
- id: 'm4',
176
- chat_jid: 'group@g.us',
177
- sender: 'Carol@s.whatsapp.net',
178
- sender_name: 'Carol',
179
- content: 'third',
180
- timestamp: '2024-01-01T00:00:04.000Z',
181
- });
182
- });
183
-
184
- it('returns messages after the given timestamp', () => {
185
- const msgs = getMessagesSince(
186
- 'group@g.us',
187
- '2024-01-01T00:00:02.000Z',
188
- 'Andy',
189
- );
190
- // Should exclude m1, m2 (before/at timestamp), m3 (bot message)
191
- expect(msgs).toHaveLength(1);
192
- expect(msgs[0].content).toBe('third');
193
- });
194
-
195
- it('excludes bot messages via is_bot_message flag', () => {
196
- const msgs = getMessagesSince(
197
- 'group@g.us',
198
- '2024-01-01T00:00:00.000Z',
199
- 'Andy',
200
- );
201
- const botMsgs = msgs.filter((m) => m.content === 'bot reply');
202
- expect(botMsgs).toHaveLength(0);
203
- });
204
-
205
- it('returns all non-bot messages when sinceTimestamp is empty', () => {
206
- const msgs = getMessagesSince('group@g.us', '', 'Andy');
207
- // 3 user messages (bot message excluded)
208
- expect(msgs).toHaveLength(3);
209
- });
210
-
211
- it('filters pre-migration bot messages via content prefix backstop', () => {
212
- // Simulate a message written before migration: has prefix but is_bot_message = 0
213
- store({
214
- id: 'm5',
215
- chat_jid: 'group@g.us',
216
- sender: 'Bot@s.whatsapp.net',
217
- sender_name: 'Bot',
218
- content: 'Andy: old bot reply',
219
- timestamp: '2024-01-01T00:00:05.000Z',
220
- });
221
- const msgs = getMessagesSince(
222
- 'group@g.us',
223
- '2024-01-01T00:00:04.000Z',
224
- 'Andy',
225
- );
226
- expect(msgs).toHaveLength(0);
227
- });
228
- });
229
-
230
- // --- getNewMessages ---
231
-
232
- describe('getNewMessages', () => {
233
- beforeEach(() => {
234
- storeChatMetadata('group1@g.us', '2024-01-01T00:00:00.000Z');
235
- storeChatMetadata('group2@g.us', '2024-01-01T00:00:00.000Z');
236
-
237
- store({
238
- id: 'a1',
239
- chat_jid: 'group1@g.us',
240
- sender: 'user@s.whatsapp.net',
241
- sender_name: 'User',
242
- content: 'g1 msg1',
243
- timestamp: '2024-01-01T00:00:01.000Z',
244
- });
245
- store({
246
- id: 'a2',
247
- chat_jid: 'group2@g.us',
248
- sender: 'user@s.whatsapp.net',
249
- sender_name: 'User',
250
- content: 'g2 msg1',
251
- timestamp: '2024-01-01T00:00:02.000Z',
252
- });
253
- storeMessage({
254
- id: 'a3',
255
- chat_jid: 'group1@g.us',
256
- sender: 'user@s.whatsapp.net',
257
- sender_name: 'User',
258
- content: 'bot reply',
259
- timestamp: '2024-01-01T00:00:03.000Z',
260
- is_bot_message: true,
261
- });
262
- store({
263
- id: 'a4',
264
- chat_jid: 'group1@g.us',
265
- sender: 'user@s.whatsapp.net',
266
- sender_name: 'User',
267
- content: 'g1 msg2',
268
- timestamp: '2024-01-01T00:00:04.000Z',
269
- });
270
- });
271
-
272
- it('returns new messages across multiple groups', () => {
273
- const { messages, newTimestamp } = getNewMessages(
274
- ['group1@g.us', 'group2@g.us'],
275
- '2024-01-01T00:00:00.000Z',
276
- 'Andy',
277
- );
278
- // Excludes bot message, returns 3 user messages
279
- expect(messages).toHaveLength(3);
280
- expect(newTimestamp).toBe('2024-01-01T00:00:04.000Z');
281
- });
282
-
283
- it('filters by timestamp', () => {
284
- const { messages } = getNewMessages(
285
- ['group1@g.us', 'group2@g.us'],
286
- '2024-01-01T00:00:02.000Z',
287
- 'Andy',
288
- );
289
- // Only g1 msg2 (after ts, not bot)
290
- expect(messages).toHaveLength(1);
291
- expect(messages[0].content).toBe('g1 msg2');
292
- });
293
-
294
- it('returns empty for no registered groups', () => {
295
- const { messages, newTimestamp } = getNewMessages([], '', 'Andy');
296
- expect(messages).toHaveLength(0);
297
- expect(newTimestamp).toBe('');
298
- });
299
- });
300
-
301
- // --- storeChatMetadata ---
302
-
303
- describe('storeChatMetadata', () => {
304
- it('stores chat with JID as default name', () => {
305
- storeChatMetadata('group@g.us', '2024-01-01T00:00:00.000Z');
306
- const chats = getAllChats();
307
- expect(chats).toHaveLength(1);
308
- expect(chats[0].jid).toBe('group@g.us');
309
- expect(chats[0].name).toBe('group@g.us');
310
- });
311
-
312
- it('stores chat with explicit name', () => {
313
- storeChatMetadata('group@g.us', '2024-01-01T00:00:00.000Z', 'My Group');
314
- const chats = getAllChats();
315
- expect(chats[0].name).toBe('My Group');
316
- });
317
-
318
- it('updates name on subsequent call with name', () => {
319
- storeChatMetadata('group@g.us', '2024-01-01T00:00:00.000Z');
320
- storeChatMetadata('group@g.us', '2024-01-01T00:00:01.000Z', 'Updated Name');
321
- const chats = getAllChats();
322
- expect(chats).toHaveLength(1);
323
- expect(chats[0].name).toBe('Updated Name');
324
- });
325
-
326
- it('preserves newer timestamp on conflict', () => {
327
- storeChatMetadata('group@g.us', '2024-01-01T00:00:05.000Z');
328
- storeChatMetadata('group@g.us', '2024-01-01T00:00:01.000Z');
329
- const chats = getAllChats();
330
- expect(chats[0].last_message_time).toBe('2024-01-01T00:00:05.000Z');
331
- });
332
- });
333
-
334
- // --- Task CRUD ---
335
-
336
- describe('task CRUD', () => {
337
- it('creates and retrieves a task', () => {
338
- createTask({
339
- id: 'task-1',
340
- group_folder: 'main',
341
- chat_jid: 'group@g.us',
342
- prompt: 'do something',
343
- schedule_type: 'once',
344
- schedule_value: '2024-06-01T00:00:00.000Z',
345
- context_mode: 'isolated',
346
- next_run: '2024-06-01T00:00:00.000Z',
347
- status: 'active',
348
- created_at: '2024-01-01T00:00:00.000Z',
349
- });
350
-
351
- const task = getTaskById('task-1');
352
- expect(task).toBeDefined();
353
- expect(task!.prompt).toBe('do something');
354
- expect(task!.status).toBe('active');
355
- });
356
-
357
- it('updates task status', () => {
358
- createTask({
359
- id: 'task-2',
360
- group_folder: 'main',
361
- chat_jid: 'group@g.us',
362
- prompt: 'test',
363
- schedule_type: 'once',
364
- schedule_value: '2024-06-01T00:00:00.000Z',
365
- context_mode: 'isolated',
366
- next_run: null,
367
- status: 'active',
368
- created_at: '2024-01-01T00:00:00.000Z',
369
- });
370
-
371
- updateTask('task-2', { status: 'paused' });
372
- expect(getTaskById('task-2')!.status).toBe('paused');
373
- });
374
-
375
- it('deletes a task and its run logs', () => {
376
- createTask({
377
- id: 'task-3',
378
- group_folder: 'main',
379
- chat_jid: 'group@g.us',
380
- prompt: 'delete me',
381
- schedule_type: 'once',
382
- schedule_value: '2024-06-01T00:00:00.000Z',
383
- context_mode: 'isolated',
384
- next_run: null,
385
- status: 'active',
386
- created_at: '2024-01-01T00:00:00.000Z',
387
- });
388
-
389
- deleteTask('task-3');
390
- expect(getTaskById('task-3')).toBeUndefined();
391
- });
392
- });
393
-
394
- // --- LIMIT behavior ---
395
-
396
- describe('message query LIMIT', () => {
397
- beforeEach(() => {
398
- storeChatMetadata('group@g.us', '2024-01-01T00:00:00.000Z');
399
-
400
- for (let i = 1; i <= 10; i++) {
401
- store({
402
- id: `lim-${i}`,
403
- chat_jid: 'group@g.us',
404
- sender: 'user@s.whatsapp.net',
405
- sender_name: 'User',
406
- content: `message ${i}`,
407
- timestamp: `2024-01-01T00:00:${String(i).padStart(2, '0')}.000Z`,
408
- });
409
- }
410
- });
411
-
412
- it('getNewMessages caps to limit and returns most recent in chronological order', () => {
413
- const { messages, newTimestamp } = getNewMessages(
414
- ['group@g.us'],
415
- '2024-01-01T00:00:00.000Z',
416
- 'Andy',
417
- 3,
418
- );
419
- expect(messages).toHaveLength(3);
420
- expect(messages[0].content).toBe('message 8');
421
- expect(messages[2].content).toBe('message 10');
422
- // Chronological order preserved
423
- expect(messages[1].timestamp > messages[0].timestamp).toBe(true);
424
- // newTimestamp reflects latest returned row
425
- expect(newTimestamp).toBe('2024-01-01T00:00:10.000Z');
426
- });
427
-
428
- it('getMessagesSince caps to limit and returns most recent in chronological order', () => {
429
- const messages = getMessagesSince(
430
- 'group@g.us',
431
- '2024-01-01T00:00:00.000Z',
432
- 'Andy',
433
- 3,
434
- );
435
- expect(messages).toHaveLength(3);
436
- expect(messages[0].content).toBe('message 8');
437
- expect(messages[2].content).toBe('message 10');
438
- expect(messages[1].timestamp > messages[0].timestamp).toBe(true);
439
- });
440
-
441
- it('returns all messages when count is under the limit', () => {
442
- const { messages } = getNewMessages(
443
- ['group@g.us'],
444
- '2024-01-01T00:00:00.000Z',
445
- 'Andy',
446
- 50,
447
- );
448
- expect(messages).toHaveLength(10);
449
- });
450
- });
451
-
452
- // --- RegisteredGroup isMain round-trip ---
453
-
454
- describe('registered group isMain', () => {
455
- it('persists isMain=true through set/get round-trip', () => {
456
- setRegisteredGroup('main@s.whatsapp.net', {
457
- name: 'Main Chat',
458
- folder: 'whatsapp_main',
459
- trigger: '@Andy',
460
- added_at: '2024-01-01T00:00:00.000Z',
461
- isMain: true,
462
- });
463
-
464
- const groups = getAllRegisteredGroups();
465
- const group = groups['main@s.whatsapp.net'];
466
- expect(group).toBeDefined();
467
- expect(group.isMain).toBe(true);
468
- expect(group.folder).toBe('whatsapp_main');
469
- });
470
-
471
- it('omits isMain for non-main groups', () => {
472
- setRegisteredGroup('group@g.us', {
473
- name: 'Family Chat',
474
- folder: 'whatsapp_family-chat',
475
- trigger: '@Andy',
476
- added_at: '2024-01-01T00:00:00.000Z',
477
- });
478
-
479
- const groups = getAllRegisteredGroups();
480
- const group = groups['group@g.us'];
481
- expect(group).toBeDefined();
482
- expect(group.isMain).toBeUndefined();
483
- });
484
- });