@swarmclawai/swarmclaw 1.2.0 → 1.2.1

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 (123) hide show
  1. package/README.md +10 -0
  2. package/package.json +4 -1
  3. package/src/app/api/chats/[id]/deploy/route.ts +11 -6
  4. package/src/app/api/chats/[id]/devserver/route.ts +5 -2
  5. package/src/app/api/chats/[id]/messages/route.ts +7 -1
  6. package/src/app/api/credentials/[id]/route.ts +4 -1
  7. package/src/app/api/extensions/marketplace/route.ts +5 -2
  8. package/src/app/api/memory/maintenance/route.ts +5 -2
  9. package/src/app/api/preview-server/route.ts +14 -11
  10. package/src/app/api/system/status/route.ts +11 -0
  11. package/src/app/api/upload/route.ts +4 -1
  12. package/src/cli/index.js +7 -0
  13. package/src/cli/spec.js +1 -0
  14. package/src/components/agents/agent-files-editor.tsx +44 -32
  15. package/src/components/agents/personality-builder.tsx +13 -7
  16. package/src/components/agents/trash-list.tsx +1 -1
  17. package/src/components/chat/message-bubble.tsx +1 -0
  18. package/src/components/chat/message-list.tsx +25 -39
  19. package/src/components/chat/swarm-status-card.tsx +10 -3
  20. package/src/components/layout/daemon-indicator.tsx +7 -8
  21. package/src/components/layout/update-banner.tsx +8 -13
  22. package/src/components/logs/log-list.tsx +1 -1
  23. package/src/components/memory/memory-card.tsx +3 -1
  24. package/src/components/org-chart/org-chart-view.tsx +4 -0
  25. package/src/components/projects/project-list.tsx +4 -2
  26. package/src/components/projects/tabs/overview-tab.tsx +3 -2
  27. package/src/components/secrets/secret-sheet.tsx +1 -1
  28. package/src/components/secrets/secrets-list.tsx +1 -1
  29. package/src/components/shared/agent-switch-dialog.tsx +12 -6
  30. package/src/components/shared/dir-browser.tsx +22 -18
  31. package/src/components/skills/skill-sheet.tsx +2 -3
  32. package/src/components/tasks/task-list.tsx +1 -1
  33. package/src/components/tasks/task-sheet.tsx +1 -1
  34. package/src/hooks/use-openclaw-gateway.ts +46 -27
  35. package/src/instrumentation.ts +10 -7
  36. package/src/lib/chat/chat.ts +18 -2
  37. package/src/lib/providers/anthropic.ts +6 -3
  38. package/src/lib/providers/claude-cli.ts +9 -3
  39. package/src/lib/providers/cli-utils.ts +15 -0
  40. package/src/lib/providers/codex-cli.ts +9 -3
  41. package/src/lib/providers/gemini-cli.ts +6 -2
  42. package/src/lib/providers/index.ts +4 -1
  43. package/src/lib/providers/ollama.ts +5 -2
  44. package/src/lib/providers/openai.ts +8 -5
  45. package/src/lib/providers/opencode-cli.ts +6 -2
  46. package/src/lib/server/agents/agent-registry.ts +20 -3
  47. package/src/lib/server/agents/main-agent-loop.ts +4 -3
  48. package/src/lib/server/autonomy/supervisor-reflection.ts +14 -1
  49. package/src/lib/server/chat-execution/chat-execution.ts +14 -2
  50. package/src/lib/server/chat-execution/continuation-evaluator.ts +4 -3
  51. package/src/lib/server/chat-execution/continuation-limits.ts +6 -3
  52. package/src/lib/server/chat-execution/message-classifier.ts +5 -2
  53. package/src/lib/server/chat-execution/post-stream-finalization.ts +4 -1
  54. package/src/lib/server/chat-execution/prompt-builder.ts +11 -1
  55. package/src/lib/server/chat-execution/prompt-sections.ts +52 -9
  56. package/src/lib/server/chat-execution/response-completeness.ts +5 -2
  57. package/src/lib/server/chat-execution/stream-agent-chat.ts +42 -12
  58. package/src/lib/server/chatrooms/chatroom-memory-bridge.ts +6 -3
  59. package/src/lib/server/connectors/bluebubbles.ts +7 -4
  60. package/src/lib/server/connectors/connector-inbound.ts +16 -13
  61. package/src/lib/server/connectors/connector-lifecycle.ts +11 -8
  62. package/src/lib/server/connectors/connector-outbound.ts +6 -3
  63. package/src/lib/server/connectors/discord.ts +10 -7
  64. package/src/lib/server/connectors/email.ts +17 -14
  65. package/src/lib/server/connectors/googlechat.ts +7 -4
  66. package/src/lib/server/connectors/inbound-audio-transcription.ts +5 -2
  67. package/src/lib/server/connectors/matrix.ts +6 -3
  68. package/src/lib/server/connectors/openclaw.ts +20 -17
  69. package/src/lib/server/connectors/outbox.ts +4 -1
  70. package/src/lib/server/connectors/runtime-state.ts +19 -0
  71. package/src/lib/server/connectors/session-consolidation.ts +5 -2
  72. package/src/lib/server/connectors/signal.ts +9 -6
  73. package/src/lib/server/connectors/slack.ts +13 -10
  74. package/src/lib/server/connectors/teams.ts +8 -5
  75. package/src/lib/server/connectors/telegram.ts +15 -12
  76. package/src/lib/server/connectors/whatsapp.ts +32 -29
  77. package/src/lib/server/embeddings.ts +4 -1
  78. package/src/lib/server/link-understanding.ts +4 -1
  79. package/src/lib/server/memory/memory-abstract.ts +59 -0
  80. package/src/lib/server/memory/memory-db.ts +40 -14
  81. package/src/lib/server/missions/mission-service.ts +6 -3
  82. package/src/lib/server/openclaw/gateway.ts +8 -5
  83. package/src/lib/server/project-utils.ts +13 -0
  84. package/src/lib/server/protocols/protocol-agent-turn.ts +5 -2
  85. package/src/lib/server/protocols/protocol-run-lifecycle.ts +5 -2
  86. package/src/lib/server/protocols/protocol-step-helpers.ts +4 -1
  87. package/src/lib/server/provider-health.ts +18 -0
  88. package/src/lib/server/query-expansion.ts +4 -1
  89. package/src/lib/server/runtime/alert-dispatch.ts +7 -6
  90. package/src/lib/server/runtime/daemon-state.ts +189 -50
  91. package/src/lib/server/runtime/heartbeat-service.ts +23 -0
  92. package/src/lib/server/runtime/idle-window.ts +4 -1
  93. package/src/lib/server/runtime/perf.ts +4 -1
  94. package/src/lib/server/runtime/process-manager.ts +7 -4
  95. package/src/lib/server/runtime/queue.ts +31 -28
  96. package/src/lib/server/runtime/scheduler.ts +9 -6
  97. package/src/lib/server/runtime/session-run-manager.ts +3 -0
  98. package/src/lib/server/sandbox/bridge-auth-registry.ts +6 -0
  99. package/src/lib/server/sandbox/novnc-auth.ts +10 -0
  100. package/src/lib/server/session-tools/context.ts +14 -0
  101. package/src/lib/server/session-tools/discovery.ts +9 -6
  102. package/src/lib/server/session-tools/index.ts +3 -1
  103. package/src/lib/server/session-tools/platform.ts +1 -1
  104. package/src/lib/server/session-tools/subagent.ts +23 -2
  105. package/src/lib/server/session-tools/wallet.ts +4 -1
  106. package/src/lib/server/skills/clawhub-client.ts +4 -1
  107. package/src/lib/server/skills/runtime-skill-resolver.ts +8 -2
  108. package/src/lib/server/skills/skill-eligibility.ts +6 -0
  109. package/src/lib/server/solana.ts +6 -0
  110. package/src/lib/server/storage-auth.ts +5 -5
  111. package/src/lib/server/storage-normalization.ts +4 -0
  112. package/src/lib/server/storage.ts +19 -8
  113. package/src/lib/server/tasks/task-followups.ts +4 -1
  114. package/src/lib/server/tool-loop-detection.ts +8 -3
  115. package/src/lib/server/tool-planning.ts +226 -0
  116. package/src/lib/server/tool-retry.ts +4 -3
  117. package/src/lib/server/wallet/wallet-portfolio.ts +29 -0
  118. package/src/lib/server/ws-hub.ts +5 -2
  119. package/src/lib/strip-internal-metadata.test.ts +44 -4
  120. package/src/lib/strip-internal-metadata.ts +20 -6
  121. package/src/stores/use-approval-store.ts +7 -1
  122. package/src/stores/use-chat-store.ts +5 -1
  123. package/src/types/index.ts +6 -0
@@ -1,6 +1,9 @@
1
+ import { log } from '@/lib/server/logger'
1
2
  import type { PlatformConnector, ConnectorInstance, InboundMessage } from './types'
2
3
  import { resolveConnectorIngressReply } from './ingress-delivery'
3
4
 
5
+ const TAG = 'googlechat'
6
+
4
7
  const googlechat: PlatformConnector = {
5
8
  async start(connector, botToken, onMessage): Promise<ConnectorInstance> {
6
9
  const pkg = 'googleapis'
@@ -29,11 +32,11 @@ const googlechat: PlatformConnector = {
29
32
  const handlerKey = `__swarmclaw_googlechat_handler_${connector.id}__`
30
33
  let stopped = false
31
34
 
32
- console.log(`[googlechat] Bot authenticated via service account`)
35
+ log.info(TAG, 'Bot authenticated via service account')
33
36
  if (allowedSpaces) {
34
- console.log(`[googlechat] Filtering to spaces: ${allowedSpaces.join(', ')}`)
37
+ log.info(TAG, `Filtering to spaces: ${allowedSpaces.join(', ')}`)
35
38
  }
36
- console.log(`[googlechat] Inbound webhook endpoint: /api/connectors/${connector.id}/webhook`)
39
+ log.info(TAG, `Inbound webhook endpoint: /api/connectors/${connector.id}/webhook`)
37
40
 
38
41
  function cleanInboundText(raw: unknown): string {
39
42
  const txt = typeof raw === 'string' ? raw : ''
@@ -100,7 +103,7 @@ const googlechat: PlatformConnector = {
100
103
  stopped = true
101
104
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
102
105
  delete (globalThis as any)[handlerKey]
103
- console.log(`[googlechat] Bot disconnected`)
106
+ log.info(TAG, 'Bot disconnected')
104
107
  },
105
108
  }
106
109
  },
@@ -1,3 +1,4 @@
1
+ import { log } from '@/lib/server/logger'
1
2
  import fs from 'node:fs'
2
3
  import path from 'node:path'
3
4
  import { decryptKey, loadCredentials, loadSettings } from '../storage'
@@ -5,6 +6,8 @@ import { mimeFromPath } from './media'
5
6
  import type { InboundMessage, InboundMedia } from './types'
6
7
  import { errorMessage } from '@/lib/shared-utils'
7
8
 
9
+ const TAG = 'audio-transcription'
10
+
8
11
  const PLACEHOLDER_TEXT = new Set([
9
12
  '',
10
13
  '(media message)',
@@ -250,11 +253,11 @@ export async function enrichInboundMessageWithAudioTranscript(params: {
250
253
  try {
251
254
  const transcript = (await attempt.run()).replace(/\s+/g, ' ').trim()
252
255
  if (!transcript) continue
253
- console.log(`[connector] Inbound audio transcribed via ${attempt.provider}: ${path.basename(localPath)}`)
256
+ log.info(TAG, `Inbound audio transcribed via ${attempt.provider}: ${path.basename(localPath)}`)
254
257
  return { ...msg, text: transcript }
255
258
  } catch (err: unknown) {
256
259
  const reason = errorMessage(err)
257
- console.warn(`[connector] Inbound audio transcription failed via ${attempt.provider}: ${reason}`)
260
+ log.warn(TAG, `Inbound audio transcription failed via ${attempt.provider}: ${reason}`)
258
261
  }
259
262
  }
260
263
 
@@ -1,9 +1,12 @@
1
+ import { log } from '@/lib/server/logger'
1
2
  import fs from 'fs'
2
3
  import path from 'path'
3
4
  import { DATA_DIR } from '../data-dir'
4
5
  import type { PlatformConnector, ConnectorInstance, InboundMessage } from './types'
5
6
  import { resolveConnectorIngressReply } from './ingress-delivery'
6
7
 
8
+ const TAG = 'matrix'
9
+
7
10
  const matrix: PlatformConnector = {
8
11
  async start(connector, botToken, onMessage): Promise<ConnectorInstance> {
9
12
  const pkg = 'matrix-bot-sdk'
@@ -52,7 +55,7 @@ const matrix: PlatformConnector = {
52
55
  if (!reply) return
53
56
  await client.sendText(roomId, reply.visibleText)
54
57
  } catch (err: any) {
55
- console.error(`[matrix] Error handling message:`, err.message)
58
+ log.error(TAG, 'Error handling message:', err.message)
56
59
  try {
57
60
  await client.sendText(roomId, 'Sorry, I encountered an error processing your message.')
58
61
  } catch { /* ignore */ }
@@ -60,7 +63,7 @@ const matrix: PlatformConnector = {
60
63
  })
61
64
 
62
65
  await client.start()
63
- console.log(`[matrix] Bot connected to ${homeserverUrl}`)
66
+ log.info(TAG, `Bot connected to ${homeserverUrl}`)
64
67
 
65
68
  return {
66
69
  connector,
@@ -69,7 +72,7 @@ const matrix: PlatformConnector = {
69
72
  },
70
73
  async stop() {
71
74
  client.stop()
72
- console.log(`[matrix] Bot disconnected`)
75
+ log.info(TAG, 'Bot disconnected')
73
76
  },
74
77
  }
75
78
  },
@@ -12,6 +12,9 @@ import {
12
12
  type GatewayFrame,
13
13
  type GatewayResponseFrame,
14
14
  } from '../gateway/protocol'
15
+ import { log } from '@/lib/server/logger'
16
+
17
+ const TAG = 'openclaw'
15
18
 
16
19
  /**
17
20
  * OpenClaw gateway connector using the current WS protocol:
@@ -443,7 +446,7 @@ async function buildOutboundAttachments(options?: OutboundSendOptions): Promise<
443
446
  })
444
447
  return { attachments: [attachment], fallbackUrl: null }
445
448
  } catch (err) {
446
- console.warn(`[openclaw] Failed to inline media URL, falling back to link send: ${getErrorMessage(err)}`)
449
+ log.warn(TAG, `Failed to inline media URL, falling back to link send: ${getErrorMessage(err)}`)
447
450
  return { attachments: [], fallbackUrl: mediaUrl }
448
451
  }
449
452
  }
@@ -705,8 +708,8 @@ const openclaw: PlatformConnector = {
705
708
  if (lastTickAtMs <= 0) return
706
709
  const delta = Date.now() - lastTickAtMs
707
710
  if (delta <= toleranceMs) return
708
- console.error(
709
- `[openclaw] Tick missed (${delta}ms > ${toleranceMs}ms), forcing reconnect`,
711
+ log.error(
712
+ TAG, `Tick missed (${delta}ms > ${toleranceMs}ms), forcing reconnect`,
710
713
  )
711
714
  try { ws.close(4000, 'tick missed') } catch { /* ignore */ }
712
715
  }, pollMs)
@@ -740,7 +743,7 @@ const openclaw: PlatformConnector = {
740
743
  const previous = historyErrorLogBySession.get(sessionKey) || 0
741
744
  if (now - previous < HISTORY_ERROR_LOG_INTERVAL_MS) return
742
745
  historyErrorLogBySession.set(sessionKey, now)
743
- console.warn(`[openclaw] chat.history poll failed for "${sessionKey}": ${message}`)
746
+ log.warn(TAG, `chat.history poll failed for "${sessionKey}": ${message}`)
744
747
  }
745
748
 
746
749
  function cleanupSocket() {
@@ -764,7 +767,7 @@ const openclaw: PlatformConnector = {
764
767
  if (stopped) return
765
768
  const delay = Math.min(RECONNECT_BASE_MS * 2 ** reconnectAttempt, RECONNECT_MAX_MS)
766
769
  reconnectAttempt++
767
- console.log(`[openclaw] Reconnecting in ${delay}ms (attempt ${reconnectAttempt})`)
770
+ log.info(TAG, `Reconnecting in ${delay}ms (attempt ${reconnectAttempt})`)
768
771
  clearReconnectTimer()
769
772
  reconnectTimer = setTimeout(() => connect(), delay)
770
773
  }
@@ -838,7 +841,7 @@ const openclaw: PlatformConnector = {
838
841
  const lowerReason = (reason || '').toLowerCase()
839
842
  if (!lowerReason.includes('device token mismatch')) return
840
843
  if (!identity.deviceToken) return
841
- console.warn('[openclaw] Clearing stale stored device token after mismatch')
844
+ log.warn(TAG, 'Clearing stale stored device token after mismatch')
842
845
  persistIdentityToken(undefined)
843
846
  }
844
847
 
@@ -918,11 +921,11 @@ const openclaw: PlatformConnector = {
918
921
  }
919
922
  if (tickWatchdogEnabled) startTickWatchdog()
920
923
  startHistoryPoller()
921
- console.log(`[openclaw] Connected + authenticated (${wsUrl})`)
924
+ log.info(TAG, `Connected + authenticated (${wsUrl})`)
922
925
  })
923
926
  .catch((err: unknown) => {
924
927
  clearConnectHelloTimer()
925
- console.error(`[openclaw] Connect handshake failed: ${getErrorMessage(err)}`)
928
+ log.error(TAG, `Connect handshake failed: ${getErrorMessage(err)}`)
926
929
  try { ws?.close(1008, 'connect failed') } catch { /* ignore */ }
927
930
  })
928
931
  }
@@ -962,7 +965,7 @@ const openclaw: PlatformConnector = {
962
965
  await sendChat(inbound.channelId, reply.visibleText)
963
966
  } catch (err: unknown) {
964
967
  const message = getErrorMessage(err)
965
- console.error('[openclaw] Error routing inbound chat event:', message)
968
+ log.error(TAG, 'Error routing inbound chat event:', message)
966
969
  await sendChat(inbound.channelId, `[Error] ${message}`)
967
970
  }
968
971
  }
@@ -1025,7 +1028,7 @@ const openclaw: PlatformConnector = {
1025
1028
  ) {
1026
1029
  historyPollingUnsupported = true
1027
1030
  clearHistoryPollTimer()
1028
- console.warn('[openclaw] chat.history is unavailable; disabling history polling fallback')
1031
+ log.warn(TAG, 'chat.history is unavailable; disabling history polling fallback')
1029
1032
  return
1030
1033
  }
1031
1034
  maybeLogHistoryError(sessionKey, message)
@@ -1059,18 +1062,18 @@ const openclaw: PlatformConnector = {
1059
1062
  function connect() {
1060
1063
  if (stopped) return
1061
1064
  cleanupSocket()
1062
- console.log(`[openclaw] Connecting to ${wsUrl}`)
1065
+ log.info(TAG, `Connecting to ${wsUrl}`)
1063
1066
  ws = new WebSocket(wsUrl)
1064
1067
 
1065
1068
  ws.onopen = () => {
1066
- console.log(`[openclaw] Socket open: ${wsUrl}`)
1069
+ log.info(TAG, `Socket open: ${wsUrl}`)
1067
1070
  connectSent = false
1068
1071
  connected = false
1069
1072
  lastTickAtMs = 0
1070
1073
  clearConnectHelloTimer()
1071
1074
  connectHelloTimer = setTimeout(() => {
1072
1075
  if (stopped || connected) return
1073
- console.warn(`[openclaw] Connect handshake timed out after ${CONNECT_HELLO_TIMEOUT_MS}ms`)
1076
+ log.warn(TAG, `Connect handshake timed out after ${CONNECT_HELLO_TIMEOUT_MS}ms`)
1074
1077
  try { ws?.close(4001, 'connect timeout') } catch { /* ignore */ }
1075
1078
  }, CONNECT_HELLO_TIMEOUT_MS)
1076
1079
  connectHelloTimer.unref?.()
@@ -1080,7 +1083,7 @@ const openclaw: PlatformConnector = {
1080
1083
  ws.onmessage = (event) => {
1081
1084
  const frame = parseGatewayFrame(event.data)
1082
1085
  if (!frame) {
1083
- console.warn('[openclaw] Ignoring malformed gateway frame')
1086
+ log.warn(TAG, 'Ignoring malformed gateway frame')
1084
1087
  return
1085
1088
  }
1086
1089
 
@@ -1124,14 +1127,14 @@ const openclaw: PlatformConnector = {
1124
1127
 
1125
1128
  ws.onclose = (event) => {
1126
1129
  const reason = event.reason || 'none'
1127
- console.log(`[openclaw] Disconnected (code=${event.code}, reason=${reason})`)
1130
+ log.info(TAG, `Disconnected (code=${event.code}, reason=${reason})`)
1128
1131
  clearStaleTokenIfNeeded(reason)
1129
1132
  cleanupSocket()
1130
1133
  if (!stopped) scheduleReconnect()
1131
1134
  }
1132
1135
 
1133
1136
  ws.onerror = () => {
1134
- console.error('[openclaw] WebSocket error')
1137
+ log.error(TAG, 'WebSocket error')
1135
1138
  }
1136
1139
  }
1137
1140
 
@@ -1189,7 +1192,7 @@ const openclaw: PlatformConnector = {
1189
1192
  async stop() {
1190
1193
  stopped = true
1191
1194
  cleanupSocket()
1192
- console.log('[openclaw] Connector stopped')
1195
+ log.info(TAG, 'Connector stopped')
1193
1196
  },
1194
1197
  }
1195
1198
  },
@@ -6,6 +6,9 @@ import {
6
6
  } from '../storage'
7
7
  import { notify } from '../ws-hub'
8
8
  import { errorMessage, hmrSingleton } from '@/lib/shared-utils'
9
+ import { log } from '@/lib/server/logger'
10
+
11
+ const TAG = 'connector-outbox'
9
12
 
10
13
 
11
14
  export type ConnectorOutboxStatus =
@@ -151,7 +154,7 @@ function scheduleTimer(delayMs: number): void {
151
154
  outboxState.timer = null
152
155
  outboxState.dueAt = null
153
156
  void runConnectorOutboxNow().catch((err: unknown) => {
154
- console.warn(`[connector-outbox] Worker tick failed: ${errorMessage(err)}`)
157
+ log.warn(TAG, `Worker tick failed: ${errorMessage(err)}`)
155
158
  })
156
159
  }, Math.max(0, delayMs))
157
160
  outboxState.timer.unref?.()
@@ -66,4 +66,23 @@ export const connectorRuntimeState = getConnectorRuntimeState()
66
66
 
67
67
  export const runningConnectors = connectorRuntimeState.running
68
68
 
69
+ /**
70
+ * Remove tracking entries for connectors that no longer exist in storage.
71
+ * Called periodically by the daemon health sweep.
72
+ */
73
+ export function pruneConnectorTrackingState(liveConnectorIds: Set<string>): number {
74
+ const st = getConnectorRuntimeState()
75
+ let removed = 0
76
+ for (const id of st.lastInboundChannelByConnector.keys()) {
77
+ if (!liveConnectorIds.has(id)) { st.lastInboundChannelByConnector.delete(id); removed++ }
78
+ }
79
+ for (const id of st.lastInboundTimeByConnector.keys()) {
80
+ if (!liveConnectorIds.has(id)) { st.lastInboundTimeByConnector.delete(id); removed++ }
81
+ }
82
+ for (const id of st.generationCounter.keys()) {
83
+ if (!liveConnectorIds.has(id)) { st.generationCounter.delete(id); removed++ }
84
+ }
85
+ return removed
86
+ }
87
+
69
88
  export type ConnectorThreadSession = Session
@@ -2,10 +2,13 @@
2
2
  * One-time migration: backfill allKnownPeerIds on existing connector sessions.
3
3
  * Populates the field from existing senderId, senderIdAlt, channelId, channelIdAlt, peerKey.
4
4
  */
5
+ import { log } from '@/lib/server/logger'
5
6
  import { loadSessions, loadSettings, saveSettings, upsertStoredItem } from '../storage'
6
7
  import type { Session } from '@/types'
7
8
  import { isDirectConnectorSession } from './session-kind'
8
9
 
10
+ const TAG = 'session-consolidation'
11
+
9
12
  const ALL_KNOWN_PEER_IDS_MIGRATION_FLAG = '_migration_allKnownPeerIds'
10
13
  const THREAD_CONNECTOR_MIRROR_CLEANUP_FLAG = '_migration_pruneThreadConnectorMirrors'
11
14
 
@@ -43,7 +46,7 @@ export function backfillAllKnownPeerIds(): { migrated: number; skipped: boolean
43
46
  updated[ALL_KNOWN_PEER_IDS_MIGRATION_FLAG] = true
44
47
  saveSettings(updated)
45
48
  if (migrated > 0) {
46
- console.log(`[session-consolidation] Backfilled allKnownPeerIds on ${migrated} sessions`)
49
+ log.info(TAG, `Backfilled allKnownPeerIds on ${migrated} sessions`)
47
50
  }
48
51
  return { migrated, skipped: false }
49
52
  }
@@ -81,7 +84,7 @@ export function pruneThreadConnectorMirrors(): { cleanedSessions: number; remove
81
84
  updated[THREAD_CONNECTOR_MIRROR_CLEANUP_FLAG] = true
82
85
  saveSettings(updated)
83
86
  if (removedMessages > 0) {
84
- console.log(`[session-consolidation] Pruned ${removedMessages} mirrored connector message(s) from ${cleanedSessions} main session(s)`)
87
+ log.info(TAG, `Pruned ${removedMessages} mirrored connector message(s) from ${cleanedSessions} main session(s)`)
85
88
  }
86
89
  return { cleanedSessions, removedMessages, skipped: false }
87
90
  }
@@ -1,9 +1,12 @@
1
+ import { log } from '@/lib/server/logger'
1
2
  import { spawn, execSync } from 'child_process'
2
3
  import type { ChildProcess } from 'child_process'
3
4
  import type { Connector } from '@/types'
4
5
  import type { PlatformConnector, ConnectorInstance, InboundMessage, ConnectorIngressResult } from './types'
5
6
  import { resolveConnectorIngressReply } from './ingress-delivery'
6
7
 
8
+ const TAG = 'signal'
9
+
7
10
  const signal: PlatformConnector = {
8
11
  async start(connector, _botToken, onMessage): Promise<ConnectorInstance> {
9
12
  const phoneNumber = connector.config.phoneNumber
@@ -43,16 +46,16 @@ const signal: PlatformConnector = {
43
46
 
44
47
  daemonProc.stderr?.on('data', (chunk: Buffer) => {
45
48
  const msg = chunk.toString().trim()
46
- if (msg) console.error(`[signal] stderr: ${msg}`)
49
+ if (msg) log.error(TAG, `stderr: ${msg}`)
47
50
  })
48
51
 
49
52
  daemonProc.on('exit', (code) => {
50
53
  if (!stopped) {
51
- console.error(`[signal] daemon exited unexpectedly with code ${code}`)
54
+ log.error(TAG, `daemon exited unexpectedly with code ${code}`)
52
55
  }
53
56
  })
54
57
 
55
- console.log(`[signal] Daemon started in stdio mode for ${phoneNumber}`)
58
+ log.info(TAG, `Daemon started in stdio mode for ${phoneNumber}`)
56
59
  } else if (mode === 'http') {
57
60
  // Poll the signal-cli REST API for incoming messages
58
61
  const pollInterval = 2000
@@ -74,7 +77,7 @@ const signal: PlatformConnector = {
74
77
  }
75
78
 
76
79
  pollTimer = setInterval(poll, pollInterval)
77
- console.log(`[signal] Polling ${httpUrl} for ${phoneNumber} every ${pollInterval}ms`)
80
+ log.info(TAG, `Polling ${httpUrl} for ${phoneNumber} every ${pollInterval}ms`)
78
81
  } else {
79
82
  throw new Error(`Unknown signalCliMode: ${mode}. Use 'stdio' or 'http'.`)
80
83
  }
@@ -119,7 +122,7 @@ const signal: PlatformConnector = {
119
122
  daemonProc.kill('SIGTERM')
120
123
  daemonProc = null
121
124
  }
122
- console.log(`[signal] Connector stopped for ${phoneNumber}`)
125
+ log.info(TAG, `Connector stopped for ${phoneNumber}`)
123
126
  },
124
127
  }
125
128
  },
@@ -177,7 +180,7 @@ export async function handleSignalEvent(
177
180
  )
178
181
  }
179
182
  } catch (err: any) {
180
- console.error(`[signal] Error handling message:`, err.message)
183
+ log.error(TAG, 'Error handling message:', err.message)
181
184
  }
182
185
  }
183
186
 
@@ -7,6 +7,9 @@ import { resolveConnectorIngressReply } from './ingress-delivery'
7
7
  import { deliverChunkedConnectorText } from './delivery'
8
8
  import { downloadInboundMediaToUpload, inferInboundMediaType, mimeFromPath, isImageMime } from './media'
9
9
  import { dedup, errorMessage } from '@/lib/shared-utils'
10
+ import { log } from '@/lib/server/logger'
11
+
12
+ const TAG = 'slack'
10
13
 
11
14
  function normalizeSlackEmoji(input: string): string {
12
15
  const raw = input.trim().replace(/^:|:$/g, '')
@@ -99,7 +102,7 @@ async function hydrateSlackThreadContext(params: {
99
102
  params.inbound.threadPersonaLabel = params.inbound.threadTitle
100
103
  params.inbound.threadHistory = history.length ? history : undefined
101
104
  } catch (err: unknown) {
102
- console.warn(`[slack] Thread context bootstrap failed: ${errorMessage(err)}`)
105
+ log.warn(TAG, `Thread context bootstrap failed: ${errorMessage(err)}`)
103
106
  }
104
107
  }
105
108
 
@@ -141,7 +144,7 @@ const slack: PlatformConnector = {
141
144
  throw new Error('Auth test returned empty — the bot token may be revoked or the app uninstalled')
142
145
  }
143
146
  botUserId = auth.user_id as string
144
- console.log(`[slack] Authenticated as @${auth.user} in workspace "${auth.team}"`)
147
+ log.info(TAG, `Authenticated as @${auth.user} in workspace "${auth.team}"`)
145
148
  } catch (err: any) {
146
149
  const hint = err.code === 'slack_webapi_platform_error'
147
150
  ? '. Check that your Bot Token (xoxb-...) is correct and the app is installed to the workspace.'
@@ -159,7 +162,7 @@ const slack: PlatformConnector = {
159
162
 
160
163
  // Catch global errors so they don't become unhandled rejections
161
164
  app.error(async (error) => {
162
- console.error(`[slack] App error:`, error)
165
+ log.error(TAG, 'App error:', error)
163
166
  })
164
167
 
165
168
  // Optional: restrict to specific channels
@@ -177,7 +180,7 @@ const slack: PlatformConnector = {
177
180
  const channelId = msg.channel
178
181
  if (allowedChannels && !allowedChannels.includes(channelId)) return
179
182
 
180
- console.log(`[slack] Message in ${channelId} from ${msg.user}: ${(msg.text || '').slice(0, 80)}`)
183
+ log.info(TAG, `Message in ${channelId} from ${msg.user}: ${(msg.text || '').slice(0, 80)}`)
181
184
 
182
185
  // Get user info for display name
183
186
  let senderName = msg.user || 'unknown'
@@ -213,7 +216,7 @@ const slack: PlatformConnector = {
213
216
  continue
214
217
  }
215
218
  } catch (err: any) {
216
- console.warn(`[slack] Media download failed (${f?.name || 'file'}):`, err?.message || String(err))
219
+ log.warn(TAG, `Media download failed (${f?.name || 'file'}):`, err?.message || String(err))
217
220
  }
218
221
  }
219
222
  media.push({
@@ -262,7 +265,7 @@ const slack: PlatformConnector = {
262
265
  },
263
266
  })
264
267
  } catch (err: any) {
265
- console.error(`[slack] Error handling message:`, err.message)
268
+ log.error(TAG, 'Error handling message:', err.message)
266
269
  try {
267
270
  await say('Sorry, I encountered an error processing your message.')
268
271
  } catch { /* ignore */ }
@@ -320,12 +323,12 @@ const slack: PlatformConnector = {
320
323
  },
321
324
  })
322
325
  } catch (err: any) {
323
- console.error(`[slack] Error handling mention:`, err.message)
326
+ log.error(TAG, 'Error handling mention:', err.message)
324
327
  }
325
328
  })
326
329
 
327
330
  await app.start()
328
- console.log(`[slack] Bot connected (socket mode)`)
331
+ log.info(TAG, 'Bot connected (socket mode)')
329
332
 
330
333
  let appStopped = false
331
334
 
@@ -423,14 +426,14 @@ const slack: PlatformConnector = {
423
426
  async stop() {
424
427
  appStopped = true
425
428
  await app.stop()
426
- console.log(`[slack] Bot disconnected`)
429
+ log.info(TAG, 'Bot disconnected')
427
430
  },
428
431
  }
429
432
 
430
433
  // Bolt emits 'error' on unrecoverable failures (auth revoked, socket closed permanently)
431
434
  app.error(async (error) => {
432
435
  const errMsg = error.original?.message || error.message || String(error)
433
- console.error(`[slack] App error:`, errMsg)
436
+ log.error(TAG, 'App error:', errMsg)
434
437
  if (appStopped) return
435
438
  appStopped = true
436
439
  instance.onCrash?.(`Slack error: ${errMsg}`)
@@ -1,6 +1,9 @@
1
+ import { log } from '@/lib/server/logger'
1
2
  import type { PlatformConnector, ConnectorInstance, InboundMessage } from './types'
2
3
  import { resolveConnectorIngressReply } from './ingress-delivery'
3
4
 
5
+ const TAG = 'teams'
6
+
4
7
  const teams: PlatformConnector = {
5
8
  async start(connector, botToken, onMessage): Promise<ConnectorInstance> {
6
9
  const pkg = 'botbuilder'
@@ -15,7 +18,7 @@ const teams: PlatformConnector = {
15
18
  })
16
19
 
17
20
  adapter.onTurnError = async (_context: unknown, error: Error) => {
18
- console.error(`[teams] Turn error:`, error.message)
21
+ log.error(TAG, 'Turn error:', error.message)
19
22
  }
20
23
 
21
24
  // Store conversation references for proactive messaging
@@ -49,7 +52,7 @@ const teams: PlatformConnector = {
49
52
  if (!reply) return
50
53
  await context.sendActivity(reply.visibleText)
51
54
  } catch (err: any) {
52
- console.error(`[teams] Error handling message:`, err.message)
55
+ log.error(TAG, 'Error handling message:', err.message)
53
56
  try {
54
57
  await context.sendActivity('Sorry, I encountered an error processing your message.')
55
58
  } catch { /* ignore */ }
@@ -61,8 +64,8 @@ const teams: PlatformConnector = {
61
64
  const handlerKey = `__swarmclaw_teams_handler_${connector.id}__`
62
65
  ;(globalThis as any)[handlerKey] = processActivity
63
66
 
64
- console.log(`[teams] Bot registered (appId: ${appId})`)
65
- console.log(`[teams] Configure your bot's messaging endpoint to POST to /api/connectors/${connector.id}/webhook`)
67
+ log.info(TAG, `Bot registered (appId: ${appId})`)
68
+ log.info(TAG, `Configure your bot's messaging endpoint to POST to /api/connectors/${connector.id}/webhook`)
66
69
 
67
70
  return {
68
71
  connector,
@@ -85,7 +88,7 @@ const teams: PlatformConnector = {
85
88
  stopped = true
86
89
  delete (globalThis as any)[handlerKey]
87
90
  conversationReferences.clear()
88
- console.log(`[teams] Bot disconnected`)
91
+ log.info(TAG, 'Bot disconnected')
89
92
  },
90
93
  }
91
94
  },
@@ -7,6 +7,9 @@ import { resolveConnectorIngressReply } from './ingress-delivery'
7
7
  import { deliverChunkedConnectorText } from './delivery'
8
8
  import { downloadInboundMediaToUpload, inferInboundMediaType, mimeFromPath, isImageMime, isAudioMime } from './media'
9
9
  import { errorMessage } from '@/lib/shared-utils'
10
+ import { log } from '@/lib/server/logger'
11
+
12
+ const TAG = 'telegram'
10
13
 
11
14
  const telegram: PlatformConnector = {
12
15
  async start(connector, botToken, onMessage): Promise<ConnectorInstance> {
@@ -20,23 +23,23 @@ const telegram: PlatformConnector = {
20
23
 
21
24
  // Log all errors
22
25
  bot.catch((err) => {
23
- console.error(`[telegram] Bot error:`, err.message || err)
26
+ log.error(TAG, 'Bot error:', err.message || err)
24
27
  })
25
28
 
26
29
  // Delete any existing webhook so long polling works
27
30
  await bot.api.deleteWebhook().catch((err) => {
28
- console.error('[telegram] Failed to delete webhook:', err.message)
31
+ log.error(TAG, 'Failed to delete webhook:', err.message)
29
32
  })
30
33
 
31
34
  // Log all incoming updates for debugging
32
35
  bot.use(async (ctx, next) => {
33
- console.log(`[telegram] Update received: chat=${ctx.chat?.id}, from=${ctx.from?.first_name}, hasText=${!!ctx.message?.text}`)
36
+ log.info(TAG, `Update received: chat=${ctx.chat?.id}, from=${ctx.from?.first_name}, hasText=${!!ctx.message?.text}`)
34
37
  await next()
35
38
  })
36
39
 
37
40
  // Handle /start command (required for new conversations)
38
41
  bot.command('start', async (ctx) => {
39
- console.log(`[telegram] /start from ${ctx.from?.first_name} (chat=${ctx.chat.id})`)
42
+ log.info(TAG, `/start from ${ctx.from?.first_name} (chat=${ctx.chat.id})`)
40
43
  await ctx.reply('Hello! I\'m ready to chat. Send me a message.')
41
44
  })
42
45
 
@@ -51,15 +54,15 @@ const telegram: PlatformConnector = {
51
54
  // that appear as short bracketed strings like [rr], [e], [read] etc.
52
55
  const hasMedia = raw.photo || raw.video || raw.audio || raw.voice || raw.document || raw.animation
53
56
  if (!hasMedia && /^\[.{1,5}\]$/.test(text.trim())) {
54
- console.log(`[telegram] Ignoring system event from ${ctx.from.first_name}: ${text}`)
57
+ log.info(TAG, `Ignoring system event from ${ctx.from.first_name}: ${text}`)
55
58
  return
56
59
  }
57
60
 
58
- console.log(`[telegram] Message from ${ctx.from.first_name} (chat=${chatId}): ${String(text).slice(0, 80)}`)
61
+ log.info(TAG, `Message from ${ctx.from.first_name} (chat=${chatId}): ${String(text).slice(0, 80)}`)
59
62
 
60
63
  // Filter by allowed chats if configured
61
64
  if (allowedChats && !allowedChats.includes(chatId)) {
62
- console.log(`[telegram] Skipping — chat ${chatId} not in allowed list: ${allowedChats.join(',')}`)
65
+ log.info(TAG, `Skipping — chat ${chatId} not in allowed list: ${allowedChats.join(',')}`)
63
66
  return
64
67
  }
65
68
 
@@ -125,7 +128,7 @@ const telegram: PlatformConnector = {
125
128
  })
126
129
  if (stored) media.push(stored)
127
130
  } catch (err: any) {
128
- console.warn(`[telegram] Failed to fetch media ${m.fileId}:`, err?.message || String(err))
131
+ log.warn(TAG, `Failed to fetch media ${m.fileId}:`, err?.message || String(err))
129
132
  media.push({
130
133
  type: m.type,
131
134
  fileName: m.fileName,
@@ -175,7 +178,7 @@ const telegram: PlatformConnector = {
175
178
  },
176
179
  })
177
180
  } catch (err: any) {
178
- console.error(`[telegram] Error handling message:`, err.message)
181
+ log.error(TAG, 'Error handling message:', err.message)
179
182
  try {
180
183
  await ctx.reply('Sorry, I encountered an error processing your message.')
181
184
  } catch { /* ignore */ }
@@ -268,7 +271,7 @@ const telegram: PlatformConnector = {
268
271
  async stop() {
269
272
  botRunning = false
270
273
  await bot.stop()
271
- console.log(`[telegram] Bot stopped`)
274
+ log.info(TAG, 'Bot stopped')
272
275
  },
273
276
  }
274
277
 
@@ -277,12 +280,12 @@ const telegram: PlatformConnector = {
277
280
  allowed_updates: ['message', 'edited_message'],
278
281
  onStart: (botInfo) => {
279
282
  botUsername = botInfo.username || ''
280
- console.log(`[telegram] Bot started as @${botInfo.username} — polling for updates`)
283
+ log.info(TAG, `Bot started as @${botInfo.username} — polling for updates`)
281
284
  },
282
285
  }).catch((err: unknown) => {
283
286
  botRunning = false
284
287
  const errMsg = errorMessage(err)
285
- console.error(`[telegram] Polling stopped with error:`, errMsg)
288
+ log.error(TAG, 'Polling stopped with error:', errMsg)
286
289
  instance.onCrash?.(`Polling stopped: ${errMsg}`)
287
290
  })
288
291