@rozek/nanoclaw 1.2.17

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 (305) hide show
  1. package/.claude/settings.json +1 -0
  2. package/.claude/skills/add-compact/SKILL.md +135 -0
  3. package/.claude/skills/add-discord/SKILL.md +203 -0
  4. package/.claude/skills/add-gmail/SKILL.md +220 -0
  5. package/.claude/skills/add-image-vision/SKILL.md +94 -0
  6. package/.claude/skills/add-ollama-tool/SKILL.md +153 -0
  7. package/.claude/skills/add-parallel/SKILL.md +290 -0
  8. package/.claude/skills/add-pdf-reader/SKILL.md +104 -0
  9. package/.claude/skills/add-reactions/SKILL.md +117 -0
  10. package/.claude/skills/add-slack/SKILL.md +207 -0
  11. package/.claude/skills/add-telegram/SKILL.md +222 -0
  12. package/.claude/skills/add-telegram-swarm/SKILL.md +384 -0
  13. package/.claude/skills/add-voice-transcription/SKILL.md +148 -0
  14. package/.claude/skills/add-whatsapp/SKILL.md +372 -0
  15. package/.claude/skills/convert-to-apple-container/SKILL.md +175 -0
  16. package/.claude/skills/customize/SKILL.md +110 -0
  17. package/.claude/skills/debug/SKILL.md +349 -0
  18. package/.claude/skills/get-qodo-rules/SKILL.md +122 -0
  19. package/.claude/skills/get-qodo-rules/references/output-format.md +41 -0
  20. package/.claude/skills/get-qodo-rules/references/pagination.md +33 -0
  21. package/.claude/skills/get-qodo-rules/references/repository-scope.md +26 -0
  22. package/.claude/skills/qodo-pr-resolver/SKILL.md +326 -0
  23. package/.claude/skills/qodo-pr-resolver/resources/providers.md +329 -0
  24. package/.claude/skills/setup/SKILL.md +218 -0
  25. package/.claude/skills/update-nanoclaw/SKILL.md +235 -0
  26. package/.claude/skills/update-skills/SKILL.md +130 -0
  27. package/.claude/skills/use-local-whisper/SKILL.md +152 -0
  28. package/.claude/skills/x-integration/SKILL.md +417 -0
  29. package/.claude/skills/x-integration/agent.ts +243 -0
  30. package/.claude/skills/x-integration/host.ts +159 -0
  31. package/.claude/skills/x-integration/lib/browser.ts +148 -0
  32. package/.claude/skills/x-integration/lib/config.ts +62 -0
  33. package/.claude/skills/x-integration/scripts/like.ts +56 -0
  34. package/.claude/skills/x-integration/scripts/post.ts +66 -0
  35. package/.claude/skills/x-integration/scripts/quote.ts +80 -0
  36. package/.claude/skills/x-integration/scripts/reply.ts +74 -0
  37. package/.claude/skills/x-integration/scripts/retweet.ts +62 -0
  38. package/.claude/skills/x-integration/scripts/setup.ts +87 -0
  39. package/.env.example +1 -0
  40. package/.github/CODEOWNERS +10 -0
  41. package/.github/PULL_REQUEST_TEMPLATE.md +14 -0
  42. package/.github/workflows/bump-version.yml +32 -0
  43. package/.github/workflows/ci.yml +25 -0
  44. package/.github/workflows/merge-forward-skills.yml +160 -0
  45. package/.github/workflows/update-tokens.yml +42 -0
  46. package/.husky/pre-commit +1 -0
  47. package/.mcp.json +3 -0
  48. package/.nvmrc +1 -0
  49. package/.prettierrc +3 -0
  50. package/CHANGELOG.md +8 -0
  51. package/CLAUDE.md +64 -0
  52. package/CONTRIBUTING.md +23 -0
  53. package/CONTRIBUTORS.md +15 -0
  54. package/LICENSE +21 -0
  55. package/NanoClaw_with_Web-Support.md +290 -0
  56. package/README.md +261 -0
  57. package/README_zh.md +200 -0
  58. package/assets/nanoclaw-favicon.png +0 -0
  59. package/assets/nanoclaw-icon.png +0 -0
  60. package/assets/nanoclaw-logo-dark.png +0 -0
  61. package/assets/nanoclaw-logo.png +0 -0
  62. package/assets/nanoclaw-profile.jpeg +0 -0
  63. package/assets/nanoclaw-sales.png +0 -0
  64. package/assets/social-preview.jpg +0 -0
  65. package/config-examples/mount-allowlist.json +25 -0
  66. package/container/Dockerfile +70 -0
  67. package/container/agent-runner/package-lock.json +1524 -0
  68. package/container/agent-runner/package.json +21 -0
  69. package/container/agent-runner/src/index.ts +558 -0
  70. package/container/agent-runner/src/ipc-mcp-stdio.ts +338 -0
  71. package/container/agent-runner/tsconfig.json +15 -0
  72. package/container/build.sh +23 -0
  73. package/container/skills/agent-browser/SKILL.md +159 -0
  74. package/container/skills/capabilities/SKILL.md +100 -0
  75. package/container/skills/status/SKILL.md +104 -0
  76. package/dist/channels/index.d.ts +2 -0
  77. package/dist/channels/index.d.ts.map +1 -0
  78. package/dist/channels/index.js +9 -0
  79. package/dist/channels/index.js.map +1 -0
  80. package/dist/channels/registry.d.ts +13 -0
  81. package/dist/channels/registry.d.ts.map +1 -0
  82. package/dist/channels/registry.js +11 -0
  83. package/dist/channels/registry.js.map +1 -0
  84. package/dist/channels/registry.test.d.ts +2 -0
  85. package/dist/channels/registry.test.d.ts.map +1 -0
  86. package/dist/channels/registry.test.js +32 -0
  87. package/dist/channels/registry.test.js.map +1 -0
  88. package/dist/channels/web.d.ts +2 -0
  89. package/dist/channels/web.d.ts.map +1 -0
  90. package/dist/channels/web.js +1738 -0
  91. package/dist/channels/web.js.map +1 -0
  92. package/dist/cli.d.ts +11 -0
  93. package/dist/cli.d.ts.map +1 -0
  94. package/dist/cli.js +182 -0
  95. package/dist/cli.js.map +1 -0
  96. package/dist/config.d.ts +19 -0
  97. package/dist/config.d.ts.map +1 -0
  98. package/dist/config.js +36 -0
  99. package/dist/config.js.map +1 -0
  100. package/dist/container-runner.d.ts +44 -0
  101. package/dist/container-runner.d.ts.map +1 -0
  102. package/dist/container-runner.js +467 -0
  103. package/dist/container-runner.js.map +1 -0
  104. package/dist/container-runner.test.d.ts +2 -0
  105. package/dist/container-runner.test.d.ts.map +1 -0
  106. package/dist/container-runner.test.js +150 -0
  107. package/dist/container-runner.test.js.map +1 -0
  108. package/dist/container-runtime.d.ts +22 -0
  109. package/dist/container-runtime.d.ts.map +1 -0
  110. package/dist/container-runtime.js +96 -0
  111. package/dist/container-runtime.js.map +1 -0
  112. package/dist/container-runtime.test.d.ts +2 -0
  113. package/dist/container-runtime.test.d.ts.map +1 -0
  114. package/dist/container-runtime.test.js +93 -0
  115. package/dist/container-runtime.test.js.map +1 -0
  116. package/dist/credential-proxy.d.ts +21 -0
  117. package/dist/credential-proxy.d.ts.map +1 -0
  118. package/dist/credential-proxy.js +95 -0
  119. package/dist/credential-proxy.js.map +1 -0
  120. package/dist/credential-proxy.test.d.ts +2 -0
  121. package/dist/credential-proxy.test.d.ts.map +1 -0
  122. package/dist/credential-proxy.test.js +134 -0
  123. package/dist/credential-proxy.test.js.map +1 -0
  124. package/dist/db.d.ts +115 -0
  125. package/dist/db.d.ts.map +1 -0
  126. package/dist/db.js +549 -0
  127. package/dist/db.js.map +1 -0
  128. package/dist/db.test.d.ts +2 -0
  129. package/dist/db.test.d.ts.map +1 -0
  130. package/dist/db.test.js +360 -0
  131. package/dist/db.test.js.map +1 -0
  132. package/dist/env.d.ts +8 -0
  133. package/dist/env.d.ts.map +1 -0
  134. package/dist/env.js +42 -0
  135. package/dist/env.js.map +1 -0
  136. package/dist/formatting.test.d.ts +2 -0
  137. package/dist/formatting.test.d.ts.map +1 -0
  138. package/dist/formatting.test.js +183 -0
  139. package/dist/formatting.test.js.map +1 -0
  140. package/dist/group-folder.d.ts +5 -0
  141. package/dist/group-folder.d.ts.map +1 -0
  142. package/dist/group-folder.js +44 -0
  143. package/dist/group-folder.js.map +1 -0
  144. package/dist/group-folder.test.d.ts +2 -0
  145. package/dist/group-folder.test.d.ts.map +1 -0
  146. package/dist/group-folder.test.js +29 -0
  147. package/dist/group-folder.test.js.map +1 -0
  148. package/dist/group-queue.d.ts +34 -0
  149. package/dist/group-queue.d.ts.map +1 -0
  150. package/dist/group-queue.js +263 -0
  151. package/dist/group-queue.js.map +1 -0
  152. package/dist/group-queue.test.d.ts +2 -0
  153. package/dist/group-queue.test.d.ts.map +1 -0
  154. package/dist/group-queue.test.js +341 -0
  155. package/dist/group-queue.test.js.map +1 -0
  156. package/dist/index.d.ts +12 -0
  157. package/dist/index.d.ts.map +1 -0
  158. package/dist/index.js +518 -0
  159. package/dist/index.js.map +1 -0
  160. package/dist/ipc-auth.test.d.ts +2 -0
  161. package/dist/ipc-auth.test.d.ts.map +1 -0
  162. package/dist/ipc-auth.test.js +434 -0
  163. package/dist/ipc-auth.test.js.map +1 -0
  164. package/dist/ipc.d.ts +32 -0
  165. package/dist/ipc.d.ts.map +1 -0
  166. package/dist/ipc.js +311 -0
  167. package/dist/ipc.js.map +1 -0
  168. package/dist/logger.d.ts +3 -0
  169. package/dist/logger.d.ts.map +1 -0
  170. package/dist/logger.js +14 -0
  171. package/dist/logger.js.map +1 -0
  172. package/dist/mount-security.d.ts +34 -0
  173. package/dist/mount-security.d.ts.map +1 -0
  174. package/dist/mount-security.js +325 -0
  175. package/dist/mount-security.js.map +1 -0
  176. package/dist/remote-control.d.ts +32 -0
  177. package/dist/remote-control.d.ts.map +1 -0
  178. package/dist/remote-control.js +185 -0
  179. package/dist/remote-control.js.map +1 -0
  180. package/dist/remote-control.test.d.ts +2 -0
  181. package/dist/remote-control.test.d.ts.map +1 -0
  182. package/dist/remote-control.test.js +321 -0
  183. package/dist/remote-control.test.js.map +1 -0
  184. package/dist/router.d.ts +8 -0
  185. package/dist/router.d.ts.map +1 -0
  186. package/dist/router.js +37 -0
  187. package/dist/router.js.map +1 -0
  188. package/dist/routing.test.d.ts +2 -0
  189. package/dist/routing.test.d.ts.map +1 -0
  190. package/dist/routing.test.js +81 -0
  191. package/dist/routing.test.js.map +1 -0
  192. package/dist/sender-allowlist.d.ts +14 -0
  193. package/dist/sender-allowlist.d.ts.map +1 -0
  194. package/dist/sender-allowlist.js +79 -0
  195. package/dist/sender-allowlist.js.map +1 -0
  196. package/dist/sender-allowlist.test.d.ts +2 -0
  197. package/dist/sender-allowlist.test.d.ts.map +1 -0
  198. package/dist/sender-allowlist.test.js +186 -0
  199. package/dist/sender-allowlist.test.js.map +1 -0
  200. package/dist/session-commands.d.ts +47 -0
  201. package/dist/session-commands.d.ts.map +1 -0
  202. package/dist/session-commands.js +102 -0
  203. package/dist/session-commands.js.map +1 -0
  204. package/dist/session-commands.test.d.ts +2 -0
  205. package/dist/session-commands.test.d.ts.map +1 -0
  206. package/dist/session-commands.test.js +190 -0
  207. package/dist/session-commands.test.js.map +1 -0
  208. package/dist/task-scheduler.d.ts +22 -0
  209. package/dist/task-scheduler.d.ts.map +1 -0
  210. package/dist/task-scheduler.js +210 -0
  211. package/dist/task-scheduler.js.map +1 -0
  212. package/dist/task-scheduler.test.d.ts +2 -0
  213. package/dist/task-scheduler.test.d.ts.map +1 -0
  214. package/dist/task-scheduler.test.js +107 -0
  215. package/dist/task-scheduler.test.js.map +1 -0
  216. package/dist/timezone.d.ts +6 -0
  217. package/dist/timezone.d.ts.map +1 -0
  218. package/dist/timezone.js +17 -0
  219. package/dist/timezone.js.map +1 -0
  220. package/dist/timezone.test.d.ts +2 -0
  221. package/dist/timezone.test.d.ts.map +1 -0
  222. package/dist/timezone.test.js +23 -0
  223. package/dist/timezone.test.js.map +1 -0
  224. package/dist/types.d.ts +78 -0
  225. package/dist/types.d.ts.map +1 -0
  226. package/dist/types.js +2 -0
  227. package/dist/types.js.map +1 -0
  228. package/docs/APPLE-CONTAINER-NETWORKING.md +90 -0
  229. package/docs/DEBUG_CHECKLIST.md +143 -0
  230. package/docs/REQUIREMENTS.md +196 -0
  231. package/docs/SDK_DEEP_DIVE.md +643 -0
  232. package/docs/SECURITY.md +122 -0
  233. package/docs/SPEC.md +785 -0
  234. package/docs/docker-sandboxes.md +359 -0
  235. package/docs/nanoclaw-architecture-final.md +1063 -0
  236. package/docs/nanorepo-architecture.md +168 -0
  237. package/docs/skills-as-branches.md +662 -0
  238. package/groups/global/CLAUDE.md +58 -0
  239. package/groups/main/CLAUDE.md +246 -0
  240. package/launchd/com.nanoclaw.plist +32 -0
  241. package/package.json +45 -0
  242. package/repo-tokens/README.md +113 -0
  243. package/repo-tokens/action.yml +186 -0
  244. package/repo-tokens/badge.svg +23 -0
  245. package/repo-tokens/examples/green.svg +14 -0
  246. package/repo-tokens/examples/red.svg +14 -0
  247. package/repo-tokens/examples/yellow-green.svg +14 -0
  248. package/repo-tokens/examples/yellow.svg +14 -0
  249. package/scripts/run-migrations.ts +105 -0
  250. package/setup/container.ts +144 -0
  251. package/setup/environment.test.ts +121 -0
  252. package/setup/environment.ts +94 -0
  253. package/setup/groups.ts +229 -0
  254. package/setup/index.ts +58 -0
  255. package/setup/mounts.ts +115 -0
  256. package/setup/platform.test.ts +120 -0
  257. package/setup/platform.ts +132 -0
  258. package/setup/register.test.ts +257 -0
  259. package/setup/register.ts +177 -0
  260. package/setup/service.test.ts +187 -0
  261. package/setup/service.ts +362 -0
  262. package/setup/status.ts +16 -0
  263. package/setup/verify.ts +192 -0
  264. package/setup.sh +161 -0
  265. package/src/channels/index.ts +12 -0
  266. package/src/channels/registry.test.ts +42 -0
  267. package/src/channels/registry.ts +32 -0
  268. package/src/channels/web.ts +1856 -0
  269. package/src/cli.ts +209 -0
  270. package/src/config.ts +73 -0
  271. package/src/container-runner.test.ts +210 -0
  272. package/src/container-runner.ts +707 -0
  273. package/src/container-runtime.test.ts +149 -0
  274. package/src/container-runtime.ts +127 -0
  275. package/src/credential-proxy.test.ts +192 -0
  276. package/src/credential-proxy.ts +125 -0
  277. package/src/db.test.ts +484 -0
  278. package/src/db.ts +803 -0
  279. package/src/env.ts +42 -0
  280. package/src/formatting.test.ts +256 -0
  281. package/src/group-folder.test.ts +43 -0
  282. package/src/group-folder.ts +44 -0
  283. package/src/group-queue.test.ts +484 -0
  284. package/src/group-queue.ts +365 -0
  285. package/src/index.ts +731 -0
  286. package/src/ipc-auth.test.ts +679 -0
  287. package/src/ipc.ts +461 -0
  288. package/src/logger.ts +16 -0
  289. package/src/mount-security.ts +419 -0
  290. package/src/remote-control.test.ts +397 -0
  291. package/src/remote-control.ts +224 -0
  292. package/src/router.ts +52 -0
  293. package/src/routing.test.ts +170 -0
  294. package/src/sender-allowlist.test.ts +216 -0
  295. package/src/sender-allowlist.ts +128 -0
  296. package/src/session-commands.test.ts +247 -0
  297. package/src/session-commands.ts +163 -0
  298. package/src/task-scheduler.test.ts +129 -0
  299. package/src/task-scheduler.ts +295 -0
  300. package/src/timezone.test.ts +29 -0
  301. package/src/timezone.ts +16 -0
  302. package/src/types.ts +107 -0
  303. package/tsconfig.json +20 -0
  304. package/vitest.config.ts +7 -0
  305. package/vitest.skills.config.ts +7 -0
@@ -0,0 +1,341 @@
1
+ import { describe, it, expect, beforeEach, vi, afterEach } from 'vitest';
2
+ import { GroupQueue } from './group-queue.js';
3
+ // Mock config to control concurrency limit
4
+ vi.mock('./config.js', () => ({
5
+ DATA_DIR: '/tmp/nanoclaw-test-data',
6
+ MAX_CONCURRENT_CONTAINERS: 2,
7
+ }));
8
+ // Mock fs operations used by sendMessage/closeStdin
9
+ vi.mock('fs', async () => {
10
+ const actual = await vi.importActual('fs');
11
+ return {
12
+ ...actual,
13
+ default: {
14
+ ...actual,
15
+ mkdirSync: vi.fn(),
16
+ writeFileSync: vi.fn(),
17
+ renameSync: vi.fn(),
18
+ },
19
+ };
20
+ });
21
+ describe('GroupQueue', () => {
22
+ let queue;
23
+ beforeEach(() => {
24
+ vi.useFakeTimers();
25
+ queue = new GroupQueue();
26
+ });
27
+ afterEach(() => {
28
+ vi.useRealTimers();
29
+ });
30
+ // --- Single group at a time ---
31
+ it('only runs one container per group at a time', async () => {
32
+ let concurrentCount = 0;
33
+ let maxConcurrent = 0;
34
+ const processMessages = vi.fn(async (groupJid) => {
35
+ concurrentCount++;
36
+ maxConcurrent = Math.max(maxConcurrent, concurrentCount);
37
+ // Simulate async work
38
+ await new Promise((resolve) => setTimeout(resolve, 100));
39
+ concurrentCount--;
40
+ return true;
41
+ });
42
+ queue.setProcessMessagesFn(processMessages);
43
+ // Enqueue two messages for the same group
44
+ queue.enqueueMessageCheck('group1@g.us');
45
+ queue.enqueueMessageCheck('group1@g.us');
46
+ // Advance timers to let the first process complete
47
+ await vi.advanceTimersByTimeAsync(200);
48
+ // Second enqueue should have been queued, not concurrent
49
+ expect(maxConcurrent).toBe(1);
50
+ });
51
+ // --- Global concurrency limit ---
52
+ it('respects global concurrency limit', async () => {
53
+ let activeCount = 0;
54
+ let maxActive = 0;
55
+ const completionCallbacks = [];
56
+ const processMessages = vi.fn(async (groupJid) => {
57
+ activeCount++;
58
+ maxActive = Math.max(maxActive, activeCount);
59
+ await new Promise((resolve) => completionCallbacks.push(resolve));
60
+ activeCount--;
61
+ return true;
62
+ });
63
+ queue.setProcessMessagesFn(processMessages);
64
+ // Enqueue 3 groups (limit is 2)
65
+ queue.enqueueMessageCheck('group1@g.us');
66
+ queue.enqueueMessageCheck('group2@g.us');
67
+ queue.enqueueMessageCheck('group3@g.us');
68
+ // Let promises settle
69
+ await vi.advanceTimersByTimeAsync(10);
70
+ // Only 2 should be active (MAX_CONCURRENT_CONTAINERS = 2)
71
+ expect(maxActive).toBe(2);
72
+ expect(activeCount).toBe(2);
73
+ // Complete one — third should start
74
+ completionCallbacks[0]();
75
+ await vi.advanceTimersByTimeAsync(10);
76
+ expect(processMessages).toHaveBeenCalledTimes(3);
77
+ });
78
+ // --- Tasks prioritized over messages ---
79
+ it('drains tasks before messages for same group', async () => {
80
+ const executionOrder = [];
81
+ let resolveFirst;
82
+ const processMessages = vi.fn(async (groupJid) => {
83
+ if (executionOrder.length === 0) {
84
+ // First call: block until we release it
85
+ await new Promise((resolve) => {
86
+ resolveFirst = resolve;
87
+ });
88
+ }
89
+ executionOrder.push('messages');
90
+ return true;
91
+ });
92
+ queue.setProcessMessagesFn(processMessages);
93
+ // Start processing messages (takes the active slot)
94
+ queue.enqueueMessageCheck('group1@g.us');
95
+ await vi.advanceTimersByTimeAsync(10);
96
+ // While active, enqueue both a task and pending messages
97
+ const taskFn = vi.fn(async () => {
98
+ executionOrder.push('task');
99
+ });
100
+ queue.enqueueTask('group1@g.us', 'task-1', taskFn);
101
+ queue.enqueueMessageCheck('group1@g.us');
102
+ // Release the first processing
103
+ resolveFirst();
104
+ await vi.advanceTimersByTimeAsync(10);
105
+ // Task should have run before the second message check
106
+ expect(executionOrder[0]).toBe('messages'); // first call
107
+ expect(executionOrder[1]).toBe('task'); // task runs first in drain
108
+ // Messages would run after task completes
109
+ });
110
+ // --- Retry with backoff on failure ---
111
+ it('retries with exponential backoff on failure', async () => {
112
+ let callCount = 0;
113
+ const processMessages = vi.fn(async () => {
114
+ callCount++;
115
+ return false; // failure
116
+ });
117
+ queue.setProcessMessagesFn(processMessages);
118
+ queue.enqueueMessageCheck('group1@g.us');
119
+ // First call happens immediately
120
+ await vi.advanceTimersByTimeAsync(10);
121
+ expect(callCount).toBe(1);
122
+ // First retry after 5000ms (BASE_RETRY_MS * 2^0)
123
+ await vi.advanceTimersByTimeAsync(5000);
124
+ await vi.advanceTimersByTimeAsync(10);
125
+ expect(callCount).toBe(2);
126
+ // Second retry after 10000ms (BASE_RETRY_MS * 2^1)
127
+ await vi.advanceTimersByTimeAsync(10000);
128
+ await vi.advanceTimersByTimeAsync(10);
129
+ expect(callCount).toBe(3);
130
+ });
131
+ // --- Shutdown prevents new enqueues ---
132
+ it('prevents new enqueues after shutdown', async () => {
133
+ const processMessages = vi.fn(async () => true);
134
+ queue.setProcessMessagesFn(processMessages);
135
+ await queue.shutdown(1000);
136
+ queue.enqueueMessageCheck('group1@g.us');
137
+ await vi.advanceTimersByTimeAsync(100);
138
+ expect(processMessages).not.toHaveBeenCalled();
139
+ });
140
+ // --- Max retries exceeded ---
141
+ it('stops retrying after MAX_RETRIES and resets', async () => {
142
+ let callCount = 0;
143
+ const processMessages = vi.fn(async () => {
144
+ callCount++;
145
+ return false; // always fail
146
+ });
147
+ queue.setProcessMessagesFn(processMessages);
148
+ queue.enqueueMessageCheck('group1@g.us');
149
+ // Run through all 5 retries (MAX_RETRIES = 5)
150
+ // Initial call
151
+ await vi.advanceTimersByTimeAsync(10);
152
+ expect(callCount).toBe(1);
153
+ // Retry 1: 5000ms, Retry 2: 10000ms, Retry 3: 20000ms, Retry 4: 40000ms, Retry 5: 80000ms
154
+ const retryDelays = [5000, 10000, 20000, 40000, 80000];
155
+ for (let i = 0; i < retryDelays.length; i++) {
156
+ await vi.advanceTimersByTimeAsync(retryDelays[i] + 10);
157
+ expect(callCount).toBe(i + 2);
158
+ }
159
+ // After 5 retries (6 total calls), should stop — no more retries
160
+ const countAfterMaxRetries = callCount;
161
+ await vi.advanceTimersByTimeAsync(200000); // Wait a long time
162
+ expect(callCount).toBe(countAfterMaxRetries);
163
+ });
164
+ // --- Waiting groups get drained when slots free up ---
165
+ it('drains waiting groups when active slots free up', async () => {
166
+ const processed = [];
167
+ const completionCallbacks = [];
168
+ const processMessages = vi.fn(async (groupJid) => {
169
+ processed.push(groupJid);
170
+ await new Promise((resolve) => completionCallbacks.push(resolve));
171
+ return true;
172
+ });
173
+ queue.setProcessMessagesFn(processMessages);
174
+ // Fill both slots
175
+ queue.enqueueMessageCheck('group1@g.us');
176
+ queue.enqueueMessageCheck('group2@g.us');
177
+ await vi.advanceTimersByTimeAsync(10);
178
+ // Queue a third
179
+ queue.enqueueMessageCheck('group3@g.us');
180
+ await vi.advanceTimersByTimeAsync(10);
181
+ expect(processed).toEqual(['group1@g.us', 'group2@g.us']);
182
+ // Free up a slot
183
+ completionCallbacks[0]();
184
+ await vi.advanceTimersByTimeAsync(10);
185
+ expect(processed).toContain('group3@g.us');
186
+ });
187
+ // --- Running task dedup (Issue #138) ---
188
+ it('rejects duplicate enqueue of a currently-running task', async () => {
189
+ let resolveTask;
190
+ let taskCallCount = 0;
191
+ const taskFn = vi.fn(async () => {
192
+ taskCallCount++;
193
+ await new Promise((resolve) => {
194
+ resolveTask = resolve;
195
+ });
196
+ });
197
+ // Start the task (runs immediately — slot available)
198
+ queue.enqueueTask('group1@g.us', 'task-1', taskFn);
199
+ await vi.advanceTimersByTimeAsync(10);
200
+ expect(taskCallCount).toBe(1);
201
+ // Scheduler poll re-discovers the same task while it's running —
202
+ // this must be silently dropped
203
+ const dupFn = vi.fn(async () => { });
204
+ queue.enqueueTask('group1@g.us', 'task-1', dupFn);
205
+ await vi.advanceTimersByTimeAsync(10);
206
+ // Duplicate was NOT queued
207
+ expect(dupFn).not.toHaveBeenCalled();
208
+ // Complete the original task
209
+ resolveTask();
210
+ await vi.advanceTimersByTimeAsync(10);
211
+ // Only one execution total
212
+ expect(taskCallCount).toBe(1);
213
+ });
214
+ // --- Idle preemption ---
215
+ it('does NOT preempt active container when not idle', async () => {
216
+ const fs = await import('fs');
217
+ let resolveProcess;
218
+ const processMessages = vi.fn(async () => {
219
+ await new Promise((resolve) => {
220
+ resolveProcess = resolve;
221
+ });
222
+ return true;
223
+ });
224
+ queue.setProcessMessagesFn(processMessages);
225
+ // Start processing (takes the active slot)
226
+ queue.enqueueMessageCheck('group1@g.us');
227
+ await vi.advanceTimersByTimeAsync(10);
228
+ // Register a process so closeStdin has a groupFolder
229
+ queue.registerProcess('group1@g.us', {}, 'container-1', 'test-group');
230
+ // Enqueue a task while container is active but NOT idle
231
+ const taskFn = vi.fn(async () => { });
232
+ queue.enqueueTask('group1@g.us', 'task-1', taskFn);
233
+ // _close should NOT have been written (container is working, not idle)
234
+ const writeFileSync = vi.mocked(fs.default.writeFileSync);
235
+ const closeWrites = writeFileSync.mock.calls.filter((call) => typeof call[0] === 'string' && call[0].endsWith('_close'));
236
+ expect(closeWrites).toHaveLength(0);
237
+ resolveProcess();
238
+ await vi.advanceTimersByTimeAsync(10);
239
+ });
240
+ it('preempts idle container when task is enqueued', async () => {
241
+ const fs = await import('fs');
242
+ let resolveProcess;
243
+ const processMessages = vi.fn(async () => {
244
+ await new Promise((resolve) => {
245
+ resolveProcess = resolve;
246
+ });
247
+ return true;
248
+ });
249
+ queue.setProcessMessagesFn(processMessages);
250
+ // Start processing
251
+ queue.enqueueMessageCheck('group1@g.us');
252
+ await vi.advanceTimersByTimeAsync(10);
253
+ // Register process and mark idle
254
+ queue.registerProcess('group1@g.us', {}, 'container-1', 'test-group');
255
+ queue.notifyIdle('group1@g.us');
256
+ // Clear previous writes, then enqueue a task
257
+ const writeFileSync = vi.mocked(fs.default.writeFileSync);
258
+ writeFileSync.mockClear();
259
+ const taskFn = vi.fn(async () => { });
260
+ queue.enqueueTask('group1@g.us', 'task-1', taskFn);
261
+ // _close SHOULD have been written (container is idle)
262
+ const closeWrites = writeFileSync.mock.calls.filter((call) => typeof call[0] === 'string' && call[0].endsWith('_close'));
263
+ expect(closeWrites).toHaveLength(1);
264
+ resolveProcess();
265
+ await vi.advanceTimersByTimeAsync(10);
266
+ });
267
+ it('sendMessage resets idleWaiting so a subsequent task enqueue does not preempt', async () => {
268
+ const fs = await import('fs');
269
+ let resolveProcess;
270
+ const processMessages = vi.fn(async () => {
271
+ await new Promise((resolve) => {
272
+ resolveProcess = resolve;
273
+ });
274
+ return true;
275
+ });
276
+ queue.setProcessMessagesFn(processMessages);
277
+ queue.enqueueMessageCheck('group1@g.us');
278
+ await vi.advanceTimersByTimeAsync(10);
279
+ queue.registerProcess('group1@g.us', {}, 'container-1', 'test-group');
280
+ // Container becomes idle
281
+ queue.notifyIdle('group1@g.us');
282
+ // A new user message arrives — resets idleWaiting
283
+ queue.sendMessage('group1@g.us', 'hello');
284
+ // Task enqueued after message reset — should NOT preempt (agent is working)
285
+ const writeFileSync = vi.mocked(fs.default.writeFileSync);
286
+ writeFileSync.mockClear();
287
+ const taskFn = vi.fn(async () => { });
288
+ queue.enqueueTask('group1@g.us', 'task-1', taskFn);
289
+ const closeWrites = writeFileSync.mock.calls.filter((call) => typeof call[0] === 'string' && call[0].endsWith('_close'));
290
+ expect(closeWrites).toHaveLength(0);
291
+ resolveProcess();
292
+ await vi.advanceTimersByTimeAsync(10);
293
+ });
294
+ it('sendMessage returns false for task containers so user messages queue up', async () => {
295
+ let resolveTask;
296
+ const taskFn = vi.fn(async () => {
297
+ await new Promise((resolve) => {
298
+ resolveTask = resolve;
299
+ });
300
+ });
301
+ // Start a task (sets isTaskContainer = true)
302
+ queue.enqueueTask('group1@g.us', 'task-1', taskFn);
303
+ await vi.advanceTimersByTimeAsync(10);
304
+ queue.registerProcess('group1@g.us', {}, 'container-1', 'test-group');
305
+ // sendMessage should return false — user messages must not go to task containers
306
+ const result = queue.sendMessage('group1@g.us', 'hello');
307
+ expect(result).toBe(false);
308
+ resolveTask();
309
+ await vi.advanceTimersByTimeAsync(10);
310
+ });
311
+ it('preempts when idle arrives with pending tasks', async () => {
312
+ const fs = await import('fs');
313
+ let resolveProcess;
314
+ const processMessages = vi.fn(async () => {
315
+ await new Promise((resolve) => {
316
+ resolveProcess = resolve;
317
+ });
318
+ return true;
319
+ });
320
+ queue.setProcessMessagesFn(processMessages);
321
+ // Start processing
322
+ queue.enqueueMessageCheck('group1@g.us');
323
+ await vi.advanceTimersByTimeAsync(10);
324
+ // Register process and enqueue a task (no idle yet — no preemption)
325
+ queue.registerProcess('group1@g.us', {}, 'container-1', 'test-group');
326
+ const writeFileSync = vi.mocked(fs.default.writeFileSync);
327
+ writeFileSync.mockClear();
328
+ const taskFn = vi.fn(async () => { });
329
+ queue.enqueueTask('group1@g.us', 'task-1', taskFn);
330
+ let closeWrites = writeFileSync.mock.calls.filter((call) => typeof call[0] === 'string' && call[0].endsWith('_close'));
331
+ expect(closeWrites).toHaveLength(0);
332
+ // Now container becomes idle — should preempt because task is pending
333
+ writeFileSync.mockClear();
334
+ queue.notifyIdle('group1@g.us');
335
+ closeWrites = writeFileSync.mock.calls.filter((call) => typeof call[0] === 'string' && call[0].endsWith('_close'));
336
+ expect(closeWrites).toHaveLength(1);
337
+ resolveProcess();
338
+ await vi.advanceTimersByTimeAsync(10);
339
+ });
340
+ });
341
+ //# sourceMappingURL=group-queue.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"group-queue.test.js","sourceRoot":"","sources":["../src/group-queue.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,12 @@
1
+ import './channels/index.js';
2
+ import { RegisteredGroup } from './types.js';
3
+ export { escapeXml, formatMessages } from './router.js';
4
+ /**
5
+ * Get available groups list for the agent.
6
+ * Returns groups ordered by most recent activity.
7
+ */
8
+ export declare function getAvailableGroups(): import('./container-runner.js').AvailableGroup[];
9
+ /** @internal - exported for testing */
10
+ export declare function _setRegisteredGroups(groups: Record<string, RegisteredGroup>): void;
11
+ export declare function main(): Promise<void>;
12
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAYA,OAAO,qBAAqB,CAAC;AAgD7B,OAAO,EAAuB,eAAe,EAAE,MAAM,YAAY,CAAC;AAIlE,OAAO,EAAE,SAAS,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAyDxD;;;GAGG;AACH,wBAAgB,kBAAkB,IAAI,OAAO,uBAAuB,EAAE,cAAc,EAAE,CAYrF;AAED,uCAAuC;AACvC,wBAAgB,oBAAoB,CAClC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,eAAe,CAAC,GACtC,IAAI,CAEN;AA2XD,wBAAsB,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC,CAwL1C"}