@phuetz/code-buddy 0.1.13 → 0.1.14

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 (258) hide show
  1. package/README.md +228 -13
  2. package/dist/agent/architect-mode.d.ts +11 -0
  3. package/dist/agent/architect-mode.js +133 -25
  4. package/dist/agent/architect-mode.js.map +1 -1
  5. package/dist/agent/codebuddy-agent.d.ts +24 -0
  6. package/dist/agent/codebuddy-agent.js +118 -16
  7. package/dist/agent/codebuddy-agent.js.map +1 -1
  8. package/dist/agent/execution/agent-executor.d.ts +9 -0
  9. package/dist/agent/execution/agent-executor.js +61 -0
  10. package/dist/agent/execution/agent-executor.js.map +1 -1
  11. package/dist/agent/message-queue.d.ts +77 -0
  12. package/dist/agent/message-queue.js +116 -0
  13. package/dist/agent/message-queue.js.map +1 -0
  14. package/dist/agent/middleware/auto-observation.d.ts +37 -0
  15. package/dist/agent/middleware/auto-observation.js +231 -0
  16. package/dist/agent/middleware/auto-observation.js.map +1 -0
  17. package/dist/agent/middleware/index.d.ts +2 -0
  18. package/dist/agent/middleware/index.js +1 -0
  19. package/dist/agent/middleware/index.js.map +1 -1
  20. package/dist/agent/tool-handler.js +3 -2
  21. package/dist/agent/tool-handler.js.map +1 -1
  22. package/dist/agent/types.d.ts +7 -2
  23. package/dist/analytics/budget-alerts.d.ts +81 -0
  24. package/dist/analytics/budget-alerts.js +126 -0
  25. package/dist/analytics/budget-alerts.js.map +1 -0
  26. package/dist/analytics/cost-predictor.d.ts +79 -0
  27. package/dist/analytics/cost-predictor.js +150 -0
  28. package/dist/analytics/cost-predictor.js.map +1 -0
  29. package/dist/analytics/index.d.ts +2 -0
  30. package/dist/analytics/index.js +2 -0
  31. package/dist/analytics/index.js.map +1 -1
  32. package/dist/auth/profile-manager.d.ts +205 -0
  33. package/dist/auth/profile-manager.js +484 -0
  34. package/dist/auth/profile-manager.js.map +1 -0
  35. package/dist/browser-automation/browser-manager.d.ts +79 -1
  36. package/dist/browser-automation/browser-manager.js +265 -2
  37. package/dist/browser-automation/browser-manager.js.map +1 -1
  38. package/dist/browser-automation/profile-manager.d.ts +32 -0
  39. package/dist/browser-automation/profile-manager.js +83 -0
  40. package/dist/browser-automation/profile-manager.js.map +1 -0
  41. package/dist/browser-automation/route-interceptor.d.ts +29 -0
  42. package/dist/browser-automation/route-interceptor.js +103 -0
  43. package/dist/browser-automation/route-interceptor.js.map +1 -0
  44. package/dist/browser-automation/screenshot-annotator.d.ts +23 -0
  45. package/dist/browser-automation/screenshot-annotator.js +86 -0
  46. package/dist/browser-automation/screenshot-annotator.js.map +1 -0
  47. package/dist/browser-automation/types.d.ts +47 -0
  48. package/dist/channels/discord/client.d.ts +2 -1
  49. package/dist/channels/discord/client.js +28 -16
  50. package/dist/channels/discord/client.js.map +1 -1
  51. package/dist/channels/google-chat/index.d.ts +210 -0
  52. package/dist/channels/google-chat/index.js +505 -0
  53. package/dist/channels/google-chat/index.js.map +1 -0
  54. package/dist/channels/group-security.d.ts +182 -0
  55. package/dist/channels/group-security.js +407 -0
  56. package/dist/channels/group-security.js.map +1 -0
  57. package/dist/channels/index.d.ts +17 -1
  58. package/dist/channels/index.js +16 -0
  59. package/dist/channels/index.js.map +1 -1
  60. package/dist/channels/matrix/index.d.ts +181 -0
  61. package/dist/channels/matrix/index.js +643 -0
  62. package/dist/channels/matrix/index.js.map +1 -0
  63. package/dist/channels/offline-queue.d.ts +92 -0
  64. package/dist/channels/offline-queue.js +112 -0
  65. package/dist/channels/offline-queue.js.map +1 -0
  66. package/dist/channels/reconnection-manager.d.ts +117 -0
  67. package/dist/channels/reconnection-manager.js +171 -0
  68. package/dist/channels/reconnection-manager.js.map +1 -0
  69. package/dist/channels/signal/index.d.ts +184 -0
  70. package/dist/channels/signal/index.js +488 -0
  71. package/dist/channels/signal/index.js.map +1 -0
  72. package/dist/channels/slack/client.d.ts +2 -1
  73. package/dist/channels/slack/client.js +30 -20
  74. package/dist/channels/slack/client.js.map +1 -1
  75. package/dist/channels/teams/index.d.ts +196 -0
  76. package/dist/channels/teams/index.js +477 -0
  77. package/dist/channels/teams/index.js.map +1 -0
  78. package/dist/channels/telegram/client.d.ts +3 -1
  79. package/dist/channels/telegram/client.js +29 -2
  80. package/dist/channels/telegram/client.js.map +1 -1
  81. package/dist/channels/webchat/index.d.ts +103 -0
  82. package/dist/channels/webchat/index.js +697 -0
  83. package/dist/channels/webchat/index.js.map +1 -0
  84. package/dist/channels/whatsapp/index.d.ts +105 -0
  85. package/dist/channels/whatsapp/index.js +533 -0
  86. package/dist/channels/whatsapp/index.js.map +1 -0
  87. package/dist/codebuddy/client.js +6 -3
  88. package/dist/codebuddy/client.js.map +1 -1
  89. package/dist/codebuddy/tool-definitions/advanced-tools.d.ts +1 -0
  90. package/dist/codebuddy/tool-definitions/advanced-tools.js +103 -3
  91. package/dist/codebuddy/tool-definitions/advanced-tools.js.map +1 -1
  92. package/dist/codebuddy/tool-definitions/index.d.ts +1 -1
  93. package/dist/codebuddy/tool-definitions/index.js +1 -1
  94. package/dist/codebuddy/tool-definitions/index.js.map +1 -1
  95. package/dist/codebuddy/tools.js +3 -1
  96. package/dist/codebuddy/tools.js.map +1 -1
  97. package/dist/commands/cli/config-command.d.ts +8 -0
  98. package/dist/commands/cli/config-command.js +90 -0
  99. package/dist/commands/cli/config-command.js.map +1 -0
  100. package/dist/commands/cli/openclaw-commands.d.ts +12 -0
  101. package/dist/commands/cli/openclaw-commands.js +446 -0
  102. package/dist/commands/cli/openclaw-commands.js.map +1 -0
  103. package/dist/commands/cli/utility-commands.js +30 -0
  104. package/dist/commands/cli/utility-commands.js.map +1 -1
  105. package/dist/commands/client-dispatcher.js +22 -2
  106. package/dist/commands/client-dispatcher.js.map +1 -1
  107. package/dist/commands/enhanced-command-handler.js +21 -2
  108. package/dist/commands/enhanced-command-handler.js.map +1 -1
  109. package/dist/commands/handlers/extra-handlers.d.ts +30 -0
  110. package/dist/commands/handlers/extra-handlers.js +547 -0
  111. package/dist/commands/handlers/extra-handlers.js.map +1 -0
  112. package/dist/commands/handlers/index.d.ts +1 -0
  113. package/dist/commands/handlers/index.js +2 -0
  114. package/dist/commands/handlers/index.js.map +1 -1
  115. package/dist/commands/slash/builtin-commands.js +41 -34
  116. package/dist/commands/slash/builtin-commands.js.map +1 -1
  117. package/dist/config/env-schema.d.ts +58 -0
  118. package/dist/config/env-schema.js +789 -0
  119. package/dist/config/env-schema.js.map +1 -0
  120. package/dist/config/feature-flags.js +2 -1
  121. package/dist/config/feature-flags.js.map +1 -1
  122. package/dist/context/bootstrap-loader.d.ts +48 -0
  123. package/dist/context/bootstrap-loader.js +123 -0
  124. package/dist/context/bootstrap-loader.js.map +1 -0
  125. package/dist/copilot/copilot-proxy.d.ts +15 -1
  126. package/dist/copilot/copilot-proxy.js +81 -22
  127. package/dist/copilot/copilot-proxy.js.map +1 -1
  128. package/dist/daemon/heartbeat.d.ts +112 -0
  129. package/dist/daemon/heartbeat.js +339 -0
  130. package/dist/daemon/heartbeat.js.map +1 -0
  131. package/dist/desktop-automation/smart-snapshot.d.ts +11 -0
  132. package/dist/desktop-automation/smart-snapshot.js +28 -0
  133. package/dist/desktop-automation/smart-snapshot.js.map +1 -1
  134. package/dist/identity/identity-manager.d.ts +95 -0
  135. package/dist/identity/identity-manager.js +242 -0
  136. package/dist/identity/identity-manager.js.map +1 -0
  137. package/dist/index.js +147 -17
  138. package/dist/index.js.map +1 -1
  139. package/dist/integrations/github-integration.js +1 -1
  140. package/dist/integrations/github-integration.js.map +1 -1
  141. package/dist/persistence/conversation-branches.js +2 -1
  142. package/dist/persistence/conversation-branches.js.map +1 -1
  143. package/dist/persistence/session-store.d.ts +1 -1
  144. package/dist/persistence/session-store.js +1 -1
  145. package/dist/persistence/session-store.js.map +1 -1
  146. package/dist/sandbox/auto-sandbox.d.ts +59 -0
  147. package/dist/sandbox/auto-sandbox.js +145 -0
  148. package/dist/sandbox/auto-sandbox.js.map +1 -0
  149. package/dist/security/audit-logger.d.ts +127 -0
  150. package/dist/security/audit-logger.js +194 -0
  151. package/dist/security/audit-logger.js.map +1 -0
  152. package/dist/security/bash-allowlist/allowlist-store.js +3 -2
  153. package/dist/security/bash-allowlist/allowlist-store.js.map +1 -1
  154. package/dist/security/bash-parser.js +0 -2
  155. package/dist/security/bash-parser.js.map +1 -1
  156. package/dist/security/code-validator.d.ts +51 -0
  157. package/dist/security/code-validator.js +185 -0
  158. package/dist/security/code-validator.js.map +1 -0
  159. package/dist/security/dangerous-patterns.d.ts +68 -0
  160. package/dist/security/dangerous-patterns.js +218 -0
  161. package/dist/security/dangerous-patterns.js.map +1 -0
  162. package/dist/security/remote-approval.d.ts +65 -0
  163. package/dist/security/remote-approval.js +138 -0
  164. package/dist/security/remote-approval.js.map +1 -0
  165. package/dist/security/security-audit.d.ts +7 -0
  166. package/dist/security/security-audit.js +23 -0
  167. package/dist/security/security-audit.js.map +1 -1
  168. package/dist/security/syntax-validator.d.ts +17 -0
  169. package/dist/security/syntax-validator.js +292 -0
  170. package/dist/security/syntax-validator.js.map +1 -0
  171. package/dist/server/index.js +277 -2
  172. package/dist/server/index.js.map +1 -1
  173. package/dist/services/prompt-builder.js +16 -0
  174. package/dist/services/prompt-builder.js.map +1 -1
  175. package/dist/skills/hub.d.ts +231 -0
  176. package/dist/skills/hub.js +694 -0
  177. package/dist/skills/hub.js.map +1 -0
  178. package/dist/skills/skill-loader.js +1 -1
  179. package/dist/skills/skill-loader.js.map +1 -1
  180. package/dist/skills/skill-manager.js +2 -1
  181. package/dist/skills/skill-manager.js.map +1 -1
  182. package/dist/tools/apply-patch.d.ts +1 -0
  183. package/dist/tools/apply-patch.js +57 -10
  184. package/dist/tools/apply-patch.js.map +1 -1
  185. package/dist/tools/bash/bash-tool.d.ts +123 -0
  186. package/dist/tools/bash/bash-tool.js +549 -0
  187. package/dist/tools/bash/bash-tool.js.map +1 -0
  188. package/dist/tools/bash/command-validator.d.ts +49 -0
  189. package/dist/tools/bash/command-validator.js +223 -0
  190. package/dist/tools/bash/command-validator.js.map +1 -0
  191. package/dist/tools/bash/index.d.ts +7 -0
  192. package/dist/tools/bash/index.js +8 -0
  193. package/dist/tools/bash/index.js.map +1 -0
  194. package/dist/tools/bash/security-patterns.d.ts +44 -0
  195. package/dist/tools/bash/security-patterns.js +234 -0
  196. package/dist/tools/bash/security-patterns.js.map +1 -0
  197. package/dist/tools/bash/streaming-executor.d.ts +23 -0
  198. package/dist/tools/bash/streaming-executor.js +134 -0
  199. package/dist/tools/bash/streaming-executor.js.map +1 -0
  200. package/dist/tools/code-formatter.js +41 -27
  201. package/dist/tools/code-formatter.js.map +1 -1
  202. package/dist/tools/code-review.js +1 -1
  203. package/dist/tools/code-review.js.map +1 -1
  204. package/dist/tools/computer-control-tool.js +21 -0
  205. package/dist/tools/computer-control-tool.js.map +1 -1
  206. package/dist/tools/document-tool.js +3 -2
  207. package/dist/tools/document-tool.js.map +1 -1
  208. package/dist/tools/git-tool.d.ts +45 -0
  209. package/dist/tools/git-tool.js +222 -0
  210. package/dist/tools/git-tool.js.map +1 -1
  211. package/dist/tools/index.d.ts +1 -1
  212. package/dist/tools/index.js +1 -1
  213. package/dist/tools/index.js.map +1 -1
  214. package/dist/tools/multi-edit.js +31 -3
  215. package/dist/tools/multi-edit.js.map +1 -1
  216. package/dist/tools/process-tool.d.ts +69 -0
  217. package/dist/tools/process-tool.js +222 -0
  218. package/dist/tools/process-tool.js.map +1 -0
  219. package/dist/tools/registry/git-tools.d.ts +32 -0
  220. package/dist/tools/registry/git-tools.js +211 -0
  221. package/dist/tools/registry/git-tools.js.map +1 -0
  222. package/dist/tools/registry/index.d.ts +2 -0
  223. package/dist/tools/registry/index.js +8 -0
  224. package/dist/tools/registry/index.js.map +1 -1
  225. package/dist/tools/registry/misc-tools.d.ts +32 -4
  226. package/dist/tools/registry/misc-tools.js +230 -90
  227. package/dist/tools/registry/misc-tools.js.map +1 -1
  228. package/dist/tools/registry/process-tools.d.ts +20 -0
  229. package/dist/tools/registry/process-tools.js +141 -0
  230. package/dist/tools/registry/process-tools.js.map +1 -0
  231. package/dist/tools/registry/types.d.ts +2 -0
  232. package/dist/ui/components/ChatInterface.js +9 -0
  233. package/dist/ui/components/ChatInterface.js.map +1 -1
  234. package/dist/utils/autonomy-manager.js +3 -2
  235. package/dist/utils/autonomy-manager.js.map +1 -1
  236. package/dist/utils/config-validation/schema.d.ts +15 -15
  237. package/dist/utils/confirmation-service.d.ts +16 -0
  238. package/dist/utils/confirmation-service.js +37 -3
  239. package/dist/utils/confirmation-service.js.map +1 -1
  240. package/dist/utils/custom-instructions.js +2 -1
  241. package/dist/utils/custom-instructions.js.map +1 -1
  242. package/dist/utils/graceful-shutdown.js +9 -9
  243. package/dist/utils/graceful-shutdown.js.map +1 -1
  244. package/dist/utils/head-tail-truncation.d.ts +18 -0
  245. package/dist/utils/head-tail-truncation.js +127 -0
  246. package/dist/utils/head-tail-truncation.js.map +1 -1
  247. package/dist/utils/history-manager.js +3 -2
  248. package/dist/utils/history-manager.js.map +1 -1
  249. package/dist/utils/performance.js +16 -15
  250. package/dist/utils/performance.js.map +1 -1
  251. package/dist/utils/update-notifier.js +2 -1
  252. package/dist/utils/update-notifier.js.map +1 -1
  253. package/dist/workflows/pipeline.d.ts +54 -1
  254. package/dist/workflows/pipeline.js +128 -7
  255. package/dist/workflows/pipeline.js.map +1 -1
  256. package/dist/workflows/step-manager.js +2 -1
  257. package/dist/workflows/step-manager.js.map +1 -1
  258. package/package.json +6 -3
@@ -0,0 +1,488 @@
1
+ /**
2
+ * Signal Channel Adapter
3
+ *
4
+ * Signal integration via signal-cli REST API.
5
+ * Requires a running signal-cli-rest-api instance
6
+ * (https://github.com/bbernhard/signal-cli-rest-api).
7
+ *
8
+ * Supports text messages, attachments, group messaging,
9
+ * and message reactions via the REST API.
10
+ */
11
+ import { BaseChannel, getSessionKey, checkDMPairing } from '../index.js';
12
+ import { ReconnectionManager } from '../reconnection-manager.js';
13
+ import { logger } from '../../utils/logger.js';
14
+ // ============================================================================
15
+ // Channel Implementation
16
+ // ============================================================================
17
+ /**
18
+ * Signal channel via signal-cli REST API
19
+ */
20
+ export class SignalChannel extends BaseChannel {
21
+ pollTimer = null;
22
+ polling = false;
23
+ groupCache = new Map();
24
+ reconnectionManager;
25
+ consecutiveErrors = 0;
26
+ constructor(config) {
27
+ super('signal', config);
28
+ if (!config.phoneNumber) {
29
+ throw new Error('Signal phone number is required');
30
+ }
31
+ // Apply defaults
32
+ if (!config.apiUrl) {
33
+ this.config.apiUrl = 'http://localhost:8080';
34
+ }
35
+ if (config.pollInterval === undefined) {
36
+ this.config.pollInterval = 2000;
37
+ }
38
+ this.reconnectionManager = new ReconnectionManager('signal', {
39
+ maxRetries: 10,
40
+ initialDelayMs: 2000,
41
+ maxDelayMs: 60000,
42
+ });
43
+ }
44
+ get signalConfig() {
45
+ return this.config;
46
+ }
47
+ get apiBase() {
48
+ return (this.signalConfig.apiUrl ?? 'http://localhost:8080').replace(/\/$/, '');
49
+ }
50
+ get encodedNumber() {
51
+ return encodeURIComponent(this.signalConfig.phoneNumber);
52
+ }
53
+ // ==========================================================================
54
+ // REST API Helper
55
+ // ==========================================================================
56
+ /**
57
+ * Make a request to the signal-cli REST API
58
+ */
59
+ async apiRequest(method, endpoint, body) {
60
+ const url = `${this.apiBase}${endpoint}`;
61
+ const headers = {
62
+ 'Content-Type': 'application/json',
63
+ };
64
+ const response = await fetch(url, {
65
+ method,
66
+ headers,
67
+ body: body ? JSON.stringify(body) : undefined,
68
+ });
69
+ if (!response.ok) {
70
+ const text = await response.text();
71
+ throw new Error(`Signal API error: ${response.status} ${text}`);
72
+ }
73
+ const contentType = response.headers.get('content-type') ?? '';
74
+ if (contentType.includes('application/json')) {
75
+ return (await response.json());
76
+ }
77
+ const text = await response.text();
78
+ if (!text)
79
+ return {};
80
+ try {
81
+ return JSON.parse(text);
82
+ }
83
+ catch {
84
+ return text;
85
+ }
86
+ }
87
+ // ==========================================================================
88
+ // Lifecycle
89
+ // ==========================================================================
90
+ /**
91
+ * Connect to Signal by verifying the phone number is registered
92
+ * and starting the message polling loop
93
+ */
94
+ async connect() {
95
+ try {
96
+ // Verify the signal-cli API is reachable
97
+ await this.apiRequest('GET', '/v1/about');
98
+ // Verify the phone number is registered
99
+ // The accounts endpoint varies by signal-cli version
100
+ try {
101
+ await this.apiRequest('GET', `/v1/accounts/${this.encodedNumber}`);
102
+ }
103
+ catch {
104
+ // Some versions use /v2/accounts
105
+ logger.debug('Signal: /v1/accounts check failed, trying health check instead');
106
+ await this.apiRequest('GET', '/v1/health');
107
+ }
108
+ // Optionally trust all known identities
109
+ if (this.signalConfig.trustAllIdentities) {
110
+ try {
111
+ await this.apiRequest('PUT', `/v1/configuration/${this.encodedNumber}/settings`, {
112
+ trust_mode: 'always',
113
+ });
114
+ }
115
+ catch {
116
+ logger.debug('Signal: could not set trust_mode (non-critical)');
117
+ }
118
+ }
119
+ this.status.connected = true;
120
+ this.status.authenticated = true;
121
+ this.status.info = {
122
+ phoneNumber: this.signalConfig.phoneNumber,
123
+ apiUrl: this.apiBase,
124
+ };
125
+ // Pre-load group cache
126
+ await this.loadGroups();
127
+ // Start polling
128
+ this.startPolling();
129
+ logger.debug('Signal connected', {
130
+ phoneNumber: this.signalConfig.phoneNumber,
131
+ apiUrl: this.apiBase,
132
+ });
133
+ this.emit('connected', 'signal');
134
+ }
135
+ catch (error) {
136
+ this.status.error = error instanceof Error ? error.message : String(error);
137
+ this.emit('error', 'signal', error instanceof Error ? error : new Error(String(error)));
138
+ throw error;
139
+ }
140
+ }
141
+ /**
142
+ * Disconnect: stop polling
143
+ */
144
+ async disconnect() {
145
+ this.reconnectionManager.cancel();
146
+ this.consecutiveErrors = 0;
147
+ this.stopPolling();
148
+ this.status.connected = false;
149
+ this.status.authenticated = false;
150
+ this.groupCache.clear();
151
+ this.emit('disconnected', 'signal');
152
+ }
153
+ /**
154
+ * Send a Signal message
155
+ */
156
+ async send(message) {
157
+ if (!this.status.connected) {
158
+ return { success: false, error: 'Signal not connected', timestamp: new Date() };
159
+ }
160
+ try {
161
+ const isGroup = this.isGroupId(message.channelId);
162
+ const payload = {
163
+ message: message.content,
164
+ number: this.signalConfig.phoneNumber,
165
+ text_mode: message.parseMode === 'plain' ? 'normal' : undefined,
166
+ };
167
+ if (isGroup) {
168
+ payload.recipients = [];
169
+ payload.group_id = message.channelId;
170
+ }
171
+ else {
172
+ payload.recipients = [message.channelId];
173
+ }
174
+ // Handle attachments
175
+ if (message.attachments && message.attachments.length > 0) {
176
+ payload.base64_attachments = message.attachments
177
+ .filter((a) => a.data)
178
+ .map((a) => ({
179
+ filename: a.fileName ?? 'attachment',
180
+ content_type: a.mimeType ?? 'application/octet-stream',
181
+ data: a.data,
182
+ }));
183
+ }
184
+ // Quote/reply
185
+ if (message.replyTo) {
186
+ payload.quote_timestamp = parseInt(message.replyTo, 10) || undefined;
187
+ }
188
+ const result = await this.apiRequest('POST', `/v2/send`, payload);
189
+ const messageId = result.timestamp
190
+ ? String(result.timestamp)
191
+ : String(Date.now());
192
+ return {
193
+ success: true,
194
+ messageId,
195
+ timestamp: new Date(),
196
+ };
197
+ }
198
+ catch (error) {
199
+ logger.debug('Signal send error', {
200
+ error: error instanceof Error ? error.message : String(error),
201
+ });
202
+ return {
203
+ success: false,
204
+ error: error instanceof Error ? error.message : String(error),
205
+ timestamp: new Date(),
206
+ };
207
+ }
208
+ }
209
+ /**
210
+ * Send a typing indicator
211
+ */
212
+ async sendTyping(recipient) {
213
+ try {
214
+ const payload = {
215
+ recipient,
216
+ };
217
+ await this.apiRequest('PUT', `/v1/typing-indicator/${this.encodedNumber}`, payload);
218
+ }
219
+ catch {
220
+ // Typing indicators are non-critical
221
+ }
222
+ }
223
+ /**
224
+ * React to a message with an emoji
225
+ */
226
+ async react(recipient, targetAuthor, timestamp, emoji) {
227
+ try {
228
+ await this.apiRequest('POST', `/v1/reactions/${this.encodedNumber}`, {
229
+ recipient,
230
+ reaction: {
231
+ emoji,
232
+ target_author: targetAuthor,
233
+ target_sent_timestamp: timestamp,
234
+ },
235
+ });
236
+ }
237
+ catch (err) {
238
+ logger.debug('Signal react error', {
239
+ error: err instanceof Error ? err.message : String(err),
240
+ });
241
+ }
242
+ }
243
+ /**
244
+ * List groups the registered number is a member of
245
+ */
246
+ async listGroups() {
247
+ try {
248
+ return await this.apiRequest('GET', `/v1/groups/${this.encodedNumber}`);
249
+ }
250
+ catch {
251
+ return [];
252
+ }
253
+ }
254
+ // ==========================================================================
255
+ // Polling
256
+ // ==========================================================================
257
+ /**
258
+ * Start the message polling loop with reconnection support
259
+ */
260
+ startPolling() {
261
+ if (this.polling)
262
+ return;
263
+ this.polling = true;
264
+ const pollFn = async () => {
265
+ if (!this.polling)
266
+ return;
267
+ try {
268
+ const messages = await this.apiRequest('GET', `/v1/receive/${this.encodedNumber}`);
269
+ // Reset consecutive error count on success
270
+ this.consecutiveErrors = 0;
271
+ this.reconnectionManager.onConnected();
272
+ if (Array.isArray(messages)) {
273
+ for (const msg of messages) {
274
+ try {
275
+ await this.handleIncoming(msg);
276
+ }
277
+ catch (err) {
278
+ logger.debug('Signal: error processing message', {
279
+ error: err instanceof Error ? err.message : String(err),
280
+ });
281
+ }
282
+ }
283
+ }
284
+ }
285
+ catch (err) {
286
+ this.consecutiveErrors++;
287
+ logger.debug('Signal polling error', {
288
+ error: err instanceof Error ? err.message : String(err),
289
+ consecutiveErrors: this.consecutiveErrors,
290
+ });
291
+ if (this.consecutiveErrors >= 5) {
292
+ // Too many consecutive errors -- use reconnection manager
293
+ logger.debug('Signal: too many consecutive polling errors, attempting reconnect');
294
+ this.polling = false;
295
+ this.status.connected = false;
296
+ this.reconnectionManager.scheduleReconnect(async () => {
297
+ this.consecutiveErrors = 0;
298
+ await this.connect();
299
+ this.reconnectionManager.onConnected();
300
+ });
301
+ return;
302
+ }
303
+ }
304
+ if (this.polling) {
305
+ this.pollTimer = setTimeout(pollFn, this.signalConfig.pollInterval ?? 2000);
306
+ }
307
+ };
308
+ pollFn();
309
+ }
310
+ /**
311
+ * Stop polling
312
+ */
313
+ stopPolling() {
314
+ this.polling = false;
315
+ if (this.pollTimer) {
316
+ clearTimeout(this.pollTimer);
317
+ this.pollTimer = null;
318
+ }
319
+ }
320
+ // ==========================================================================
321
+ // Message Handling
322
+ // ==========================================================================
323
+ /**
324
+ * Handle a received Signal message
325
+ */
326
+ async handleIncoming(msg) {
327
+ const envelope = msg.envelope;
328
+ if (!envelope)
329
+ return;
330
+ // Handle typing indicators
331
+ if (envelope.typingMessage) {
332
+ const sender = envelope.sourceNumber ?? envelope.source ?? '';
333
+ this.emit('typing', {
334
+ id: envelope.typingMessage.groupId ?? sender,
335
+ type: 'signal',
336
+ }, { id: sender });
337
+ return;
338
+ }
339
+ // Handle reactions
340
+ if (envelope.dataMessage?.reaction) {
341
+ const reaction = envelope.dataMessage.reaction;
342
+ if (!reaction.isRemove) {
343
+ this.emit('reaction', {
344
+ id: envelope.dataMessage.groupInfo?.groupId ?? envelope.sourceNumber ?? '',
345
+ type: 'signal',
346
+ }, String(reaction.targetSentTimestamp), reaction.emoji, {
347
+ id: envelope.sourceNumber ?? envelope.source ?? '',
348
+ });
349
+ }
350
+ return;
351
+ }
352
+ // Only process data messages with text or attachments
353
+ const data = envelope.dataMessage;
354
+ if (!data)
355
+ return;
356
+ if (!data.message && (!data.attachments || data.attachments.length === 0))
357
+ return;
358
+ const sourceNumber = envelope.sourceNumber ?? envelope.source ?? '';
359
+ if (!sourceNumber)
360
+ return;
361
+ // Check user allowlist
362
+ if (!this.isUserAllowed(sourceNumber))
363
+ return;
364
+ // Determine channel ID (group or DM)
365
+ const isGroup = !!data.groupInfo;
366
+ const channelId = data.groupInfo?.groupId ?? sourceNumber;
367
+ // Check channel allowlist
368
+ if (!this.isChannelAllowed(channelId))
369
+ return;
370
+ // Build InboundMessage
371
+ const groupInfo = isGroup ? this.groupCache.get(channelId) : null;
372
+ const inbound = {
373
+ id: String(data.timestamp ?? envelope.timestamp ?? Date.now()),
374
+ channel: {
375
+ id: channelId,
376
+ type: 'signal',
377
+ name: groupInfo?.name ?? (isGroup ? channelId : sourceNumber),
378
+ isDM: !isGroup,
379
+ isGroup,
380
+ participantCount: groupInfo?.members.length,
381
+ description: groupInfo?.description,
382
+ },
383
+ sender: {
384
+ id: sourceNumber,
385
+ username: sourceNumber,
386
+ displayName: envelope.sourceName ?? sourceNumber,
387
+ },
388
+ content: data.message ?? '',
389
+ contentType: this.determineContentType(data),
390
+ attachments: this.convertAttachments(data.attachments),
391
+ replyTo: data.quote ? String(data.quote.id) : undefined,
392
+ timestamp: data.timestamp ? new Date(data.timestamp) : new Date(),
393
+ raw: msg,
394
+ };
395
+ const parsed = this.parseCommand(inbound);
396
+ parsed.sessionKey = getSessionKey(parsed);
397
+ // DM pairing check
398
+ const pairingStatus = await checkDMPairing(parsed);
399
+ if (!pairingStatus.approved) {
400
+ const { getDMPairing } = await import('../dm-pairing.js');
401
+ const pairingMessage = getDMPairing().getPairingMessage(pairingStatus);
402
+ if (pairingMessage) {
403
+ await this.send({ channelId: sourceNumber, content: pairingMessage });
404
+ }
405
+ return;
406
+ }
407
+ this.status.lastActivity = new Date();
408
+ this.emit('message', parsed);
409
+ if (parsed.isCommand) {
410
+ this.emit('command', parsed);
411
+ }
412
+ }
413
+ /**
414
+ * Convert Signal attachments to MessageAttachment format
415
+ */
416
+ convertAttachments(attachments) {
417
+ if (!attachments || attachments.length === 0)
418
+ return undefined;
419
+ return attachments.map((a) => {
420
+ const type = a.voiceNote
421
+ ? 'voice'
422
+ : this.mimeToContentType(a.contentType);
423
+ return {
424
+ type,
425
+ fileName: a.filename,
426
+ mimeType: a.contentType,
427
+ size: a.size,
428
+ width: a.width,
429
+ height: a.height,
430
+ caption: a.caption,
431
+ // signal-cli stores attachments by id; the URL is available at GET /v1/attachments/{id}
432
+ url: a.id ? `${this.apiBase}/v1/attachments/${a.id}` : undefined,
433
+ };
434
+ });
435
+ }
436
+ /**
437
+ * Determine content type from a Signal data message
438
+ */
439
+ determineContentType(data) {
440
+ if (data.attachments && data.attachments.length > 0) {
441
+ const first = data.attachments[0];
442
+ if (first.voiceNote)
443
+ return 'voice';
444
+ return this.mimeToContentType(first.contentType);
445
+ }
446
+ if (data.message?.startsWith('/'))
447
+ return 'command';
448
+ return 'text';
449
+ }
450
+ /**
451
+ * Map MIME type to ContentType
452
+ */
453
+ mimeToContentType(mime) {
454
+ if (!mime)
455
+ return 'file';
456
+ if (mime.startsWith('image/'))
457
+ return 'image';
458
+ if (mime.startsWith('audio/'))
459
+ return 'audio';
460
+ if (mime.startsWith('video/'))
461
+ return 'video';
462
+ return 'file';
463
+ }
464
+ /**
465
+ * Check if an ID looks like a Signal group ID (base64)
466
+ */
467
+ isGroupId(id) {
468
+ // Signal group IDs are base64-encoded and typically 44 chars
469
+ return /^[A-Za-z0-9+/=]{20,}$/.test(id);
470
+ }
471
+ /**
472
+ * Pre-load groups into the cache
473
+ */
474
+ async loadGroups() {
475
+ try {
476
+ const groups = await this.listGroups();
477
+ for (const group of groups) {
478
+ this.groupCache.set(group.id, group);
479
+ }
480
+ logger.debug('Signal: loaded groups', { count: groups.length });
481
+ }
482
+ catch {
483
+ logger.debug('Signal: failed to load groups (non-critical)');
484
+ }
485
+ }
486
+ }
487
+ export default SignalChannel;
488
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/channels/signal/index.ts"],"names":[],"mappings":"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"}
@@ -17,6 +17,7 @@ export declare class SlackChannel extends BaseChannel {
17
17
  private pingInterval;
18
18
  private userCache;
19
19
  private channelCache;
20
+ private reconnectionManager;
20
21
  constructor(config: SlackConfig);
21
22
  private get slackConfig();
22
23
  /**
@@ -71,7 +72,7 @@ export declare class SlackChannel extends BaseChannel {
71
72
  */
72
73
  private handleClose;
73
74
  /**
74
- * Reconnect to Socket Mode
75
+ * Reconnect to Socket Mode using ReconnectionManager for backoff
75
76
  */
76
77
  private reconnect;
77
78
  /**
@@ -7,6 +7,7 @@
7
7
  import WebSocket from 'ws';
8
8
  import crypto from 'crypto';
9
9
  import { BaseChannel, getSessionKey, checkDMPairing } from '../index.js';
10
+ import { ReconnectionManager } from '../reconnection-manager.js';
10
11
  const SLACK_API_BASE = 'https://slack.com/api';
11
12
  const SLACK_SOCKET_URL = 'wss://wss-primary.slack.com/websocket';
12
13
  /**
@@ -19,11 +20,17 @@ export class SlackChannel extends BaseChannel {
19
20
  pingInterval = null;
20
21
  userCache = new Map();
21
22
  channelCache = new Map();
23
+ reconnectionManager;
22
24
  constructor(config) {
23
25
  super('slack', config);
24
26
  if (!config.token) {
25
27
  throw new Error('Slack bot token is required');
26
28
  }
29
+ this.reconnectionManager = new ReconnectionManager('slack', {
30
+ maxRetries: 10,
31
+ initialDelayMs: 1000,
32
+ maxDelayMs: 60000,
33
+ });
27
34
  }
28
35
  get slackConfig() {
29
36
  return this.config;
@@ -334,36 +341,39 @@ export class SlackChannel extends BaseChannel {
334
341
  }
335
342
  }
336
343
  /**
337
- * Reconnect to Socket Mode
344
+ * Reconnect to Socket Mode using ReconnectionManager for backoff
338
345
  */
339
- async reconnect() {
346
+ reconnect() {
340
347
  if (this.reconnecting)
341
348
  return;
342
- this.reconnecting = true;
343
- try {
344
- // Clear ping interval before reconnecting to prevent duplicates
345
- if (this.pingInterval) {
346
- clearInterval(this.pingInterval);
347
- this.pingInterval = null;
348
- }
349
- if (this.ws) {
350
- this.ws.removeAllListeners();
351
- if (this.ws.readyState === WebSocket.OPEN) {
352
- this.ws.close();
349
+ this.reconnectionManager.scheduleReconnect(async () => {
350
+ this.reconnecting = true;
351
+ try {
352
+ // Clear ping interval before reconnecting to prevent duplicates
353
+ if (this.pingInterval) {
354
+ clearInterval(this.pingInterval);
355
+ this.pingInterval = null;
356
+ }
357
+ if (this.ws) {
358
+ this.ws.removeAllListeners();
359
+ if (this.ws.readyState === WebSocket.OPEN) {
360
+ this.ws.close();
361
+ }
362
+ this.ws = null;
353
363
  }
354
- this.ws = null;
364
+ await this.connect();
365
+ this.reconnectionManager.onConnected();
355
366
  }
356
- await new Promise((r) => setTimeout(r, 5000));
357
- await this.connect();
358
- }
359
- finally {
360
- this.reconnecting = false;
361
- }
367
+ finally {
368
+ this.reconnecting = false;
369
+ }
370
+ });
362
371
  }
363
372
  /**
364
373
  * Disconnect from Slack
365
374
  */
366
375
  async disconnect() {
376
+ this.reconnectionManager.cancel();
367
377
  if (this.pingInterval) {
368
378
  clearInterval(this.pingInterval);
369
379
  this.pingInterval = null;