@swarmclawai/swarmclaw 1.2.3 → 1.2.5

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 (273) hide show
  1. package/README.md +20 -0
  2. package/bin/daemon-cmd.js +169 -0
  3. package/bin/server-cmd.js +3 -0
  4. package/bin/swarmclaw.js +11 -0
  5. package/package.json +17 -16
  6. package/src/app/api/agents/[id]/clone/route.ts +3 -32
  7. package/src/app/api/agents/[id]/route.ts +6 -158
  8. package/src/app/api/agents/[id]/status/route.ts +2 -3
  9. package/src/app/api/agents/[id]/thread/route.ts +4 -17
  10. package/src/app/api/agents/bulk/route.ts +5 -47
  11. package/src/app/api/agents/route.ts +5 -119
  12. package/src/app/api/agents/trash/route.ts +13 -24
  13. package/src/app/api/auth/route.ts +3 -9
  14. package/src/app/api/autonomy/estop/route.ts +5 -5
  15. package/src/app/api/chatrooms/[id]/chat/route.ts +11 -5
  16. package/src/app/api/chatrooms/[id]/route.ts +23 -2
  17. package/src/app/api/chatrooms/route.ts +13 -2
  18. package/src/app/api/chats/[id]/clear/route.ts +2 -13
  19. package/src/app/api/chats/[id]/deploy/route.ts +2 -3
  20. package/src/app/api/chats/[id]/edit-resend/route.ts +7 -13
  21. package/src/app/api/chats/[id]/mailbox/route.ts +6 -8
  22. package/src/app/api/chats/[id]/queue/route.ts +17 -64
  23. package/src/app/api/chats/[id]/retry/route.ts +4 -22
  24. package/src/app/api/chats/[id]/route.ts +10 -138
  25. package/src/app/api/chats/heartbeat/route.ts +2 -1
  26. package/src/app/api/chats/migrate-messages/route.ts +7 -0
  27. package/src/app/api/chats/route.ts +13 -134
  28. package/src/app/api/connectors/[id]/access/route.ts +12 -229
  29. package/src/app/api/connectors/[id]/doctor/route.ts +1 -1
  30. package/src/app/api/connectors/[id]/health/route.ts +12 -39
  31. package/src/app/api/connectors/[id]/route.ts +14 -122
  32. package/src/app/api/connectors/[id]/webhook/route.ts +1 -1
  33. package/src/app/api/connectors/doctor/route.ts +1 -1
  34. package/src/app/api/connectors/route.ts +12 -70
  35. package/src/app/api/credentials/[id]/route.ts +2 -4
  36. package/src/app/api/credentials/route.ts +10 -19
  37. package/src/app/api/daemon/health-check/route.ts +3 -4
  38. package/src/app/api/daemon/route.ts +10 -8
  39. package/src/app/api/documents/route.ts +11 -10
  40. package/src/app/api/external-agents/route.ts +3 -3
  41. package/src/app/api/gateways/[id]/health/route.ts +2 -3
  42. package/src/app/api/gateways/[id]/route.ts +7 -122
  43. package/src/app/api/gateways/route.ts +3 -103
  44. package/src/app/api/mcp-servers/[id]/tools/route.ts +5 -5
  45. package/src/app/api/openclaw/dashboard-url/route.ts +8 -16
  46. package/src/app/api/openclaw/directory/route.ts +2 -2
  47. package/src/app/api/openclaw/history/route.ts +3 -5
  48. package/src/app/api/providers/[id]/models/route.test.ts +60 -0
  49. package/src/app/api/providers/[id]/models/route.ts +33 -1
  50. package/src/app/api/providers/[id]/route.test.ts +49 -0
  51. package/src/app/api/providers/[id]/route.ts +30 -1
  52. package/src/app/api/providers/ollama/route.ts +6 -5
  53. package/src/app/api/schedules/[id]/route.ts +14 -108
  54. package/src/app/api/schedules/[id]/run/route.ts +6 -67
  55. package/src/app/api/schedules/route.ts +9 -51
  56. package/src/app/api/settings/route.ts +4 -3
  57. package/src/app/api/setup/check-provider/route.ts +15 -1
  58. package/src/app/api/setup/openclaw-device/route.ts +2 -2
  59. package/src/app/api/system/status/route.ts +2 -2
  60. package/src/app/api/tasks/[id]/route.ts +16 -202
  61. package/src/app/api/tasks/bulk/route.ts +5 -86
  62. package/src/app/api/tasks/metrics/route.ts +2 -1
  63. package/src/app/api/tasks/route.ts +11 -171
  64. package/src/app/api/upload/route.ts +1 -1
  65. package/src/app/api/uploads/[filename]/route.ts +1 -1
  66. package/src/app/api/uploads/route.ts +1 -1
  67. package/src/app/api/webhooks/[id]/history/route.ts +2 -2
  68. package/src/app/layout.tsx +9 -6
  69. package/src/app/protocols/page.tsx +71 -89
  70. package/src/app/tasks/page.tsx +32 -32
  71. package/src/cli/index.js +1 -0
  72. package/src/cli/spec.js +1 -0
  73. package/src/components/agents/agent-sheet.tsx +51 -25
  74. package/src/components/agents/inspector-panel.tsx +15 -4
  75. package/src/components/auth/setup-wizard/index.tsx +27 -18
  76. package/src/components/auth/setup-wizard/shared.tsx +2 -2
  77. package/src/components/auth/setup-wizard/step-agents.tsx +51 -38
  78. package/src/components/auth/setup-wizard/step-connect.tsx +48 -17
  79. package/src/components/auth/setup-wizard/types.ts +6 -4
  80. package/src/components/auth/setup-wizard/utils.test.ts +38 -8
  81. package/src/components/auth/setup-wizard/utils.ts +14 -8
  82. package/src/components/chatrooms/chatroom-sheet.tsx +16 -276
  83. package/src/components/connectors/connector-list.tsx +26 -40
  84. package/src/components/connectors/connector-sheet.tsx +95 -149
  85. package/src/components/gateways/gateway-sheet.tsx +61 -110
  86. package/src/components/layout/live-query-sync.tsx +121 -0
  87. package/src/components/protocols/structured-session-launcher.tsx +24 -45
  88. package/src/components/providers/app-query-provider.tsx +17 -0
  89. package/src/components/providers/provider-list.tsx +150 -77
  90. package/src/components/providers/provider-sheet.tsx +102 -77
  91. package/src/components/shared/model-combobox.tsx +5 -4
  92. package/src/components/skills/skill-list.tsx +5 -18
  93. package/src/components/skills/skill-sheet.tsx +21 -20
  94. package/src/components/skills/skills-workspace.tsx +48 -87
  95. package/src/components/tasks/task-card.tsx +20 -13
  96. package/src/components/tasks/task-column.tsx +22 -7
  97. package/src/components/tasks/task-list.tsx +8 -11
  98. package/src/components/tasks/task-sheet.tsx +111 -103
  99. package/src/features/agents/queries.ts +20 -0
  100. package/src/features/chatrooms/queries.ts +20 -0
  101. package/src/features/chats/queries.ts +27 -0
  102. package/src/features/connectors/queries.ts +145 -0
  103. package/src/features/credentials/queries.ts +37 -0
  104. package/src/features/extensions/queries.ts +26 -0
  105. package/src/features/external-agents/queries.ts +36 -0
  106. package/src/features/gateways/queries.ts +274 -0
  107. package/src/features/missions/queries.ts +23 -0
  108. package/src/features/projects/queries.ts +20 -0
  109. package/src/features/protocols/queries.ts +149 -0
  110. package/src/features/providers/queries.ts +142 -0
  111. package/src/features/settings/queries.ts +20 -0
  112. package/src/features/skills/queries.ts +182 -0
  113. package/src/features/tasks/queries.ts +189 -0
  114. package/src/hooks/use-ws.ts +3 -2
  115. package/src/lib/agent-provider-options.test.ts +152 -0
  116. package/src/lib/agent-provider-options.ts +84 -0
  117. package/src/lib/app/api-client.ts +2 -2
  118. package/src/lib/providers/index.test.ts +78 -0
  119. package/src/lib/providers/index.ts +13 -10
  120. package/src/lib/query/client.ts +17 -0
  121. package/src/lib/server/agents/agent-runtime-config.ts +6 -6
  122. package/src/lib/server/agents/agent-service.ts +429 -0
  123. package/src/lib/server/agents/agent-thread-session.ts +6 -5
  124. package/src/lib/server/agents/autonomy-contract.ts +1 -4
  125. package/src/lib/server/agents/delegation-advisory.test.ts +206 -0
  126. package/src/lib/server/agents/delegation-advisory.ts +251 -0
  127. package/src/lib/server/agents/main-agent-loop.ts +98 -40
  128. package/src/lib/server/agents/subagent-runtime.ts +12 -0
  129. package/src/lib/server/autonomy/supervisor-reflection.test.ts +20 -1
  130. package/src/lib/server/autonomy/supervisor-reflection.ts +39 -19
  131. package/src/lib/server/build-llm.ts +7 -15
  132. package/src/lib/server/capability-router.test.ts +70 -1
  133. package/src/lib/server/capability-router.ts +24 -99
  134. package/src/lib/server/chat-execution/chat-execution-utils.ts +0 -15
  135. package/src/lib/server/chat-execution/chat-streaming-utils.ts +2 -4
  136. package/src/lib/server/chat-execution/chat-turn-finalization.ts +77 -12
  137. package/src/lib/server/chat-execution/chat-turn-partial-persistence.ts +4 -4
  138. package/src/lib/server/chat-execution/chat-turn-preflight.ts +2 -2
  139. package/src/lib/server/chat-execution/chat-turn-preparation.ts +41 -17
  140. package/src/lib/server/chat-execution/chat-turn-stream-execution.ts +4 -2
  141. package/src/lib/server/chat-execution/chat-turn-tool-routing.test.ts +45 -0
  142. package/src/lib/server/chat-execution/chat-turn-tool-routing.ts +48 -17
  143. package/src/lib/server/chat-execution/continuation-evaluator.ts +4 -1
  144. package/src/lib/server/chat-execution/direct-memory-intent.test.ts +9 -0
  145. package/src/lib/server/chat-execution/direct-memory-intent.ts +12 -2
  146. package/src/lib/server/chat-execution/message-classifier.test.ts +35 -23
  147. package/src/lib/server/chat-execution/message-classifier.ts +74 -32
  148. package/src/lib/server/chat-execution/prompt-builder.test.ts +29 -0
  149. package/src/lib/server/chat-execution/prompt-builder.ts +37 -2
  150. package/src/lib/server/chat-execution/prompt-sections.test.ts +56 -0
  151. package/src/lib/server/chat-execution/prompt-sections.ts +193 -0
  152. package/src/lib/server/chat-execution/stream-agent-chat.ts +63 -7
  153. package/src/lib/server/chat-execution/stream-continuation.test.ts +36 -0
  154. package/src/lib/server/chat-execution/stream-continuation.ts +28 -13
  155. package/src/lib/server/chatrooms/chatroom-agent-signals.ts +26 -18
  156. package/src/lib/server/chatrooms/chatroom-helpers.ts +19 -18
  157. package/src/lib/server/chatrooms/chatroom-repository.ts +16 -0
  158. package/src/lib/server/chatrooms/chatroom-routing.test.ts +96 -0
  159. package/src/lib/server/chatrooms/chatroom-routing.ts +207 -53
  160. package/src/lib/server/chatrooms/mailbox-utils.ts +4 -2
  161. package/src/lib/server/chatrooms/session-mailbox.ts +50 -40
  162. package/src/lib/server/chats/chat-session-service.ts +410 -0
  163. package/src/lib/server/connectors/access.ts +1 -1
  164. package/src/lib/server/connectors/commands.ts +7 -6
  165. package/src/lib/server/connectors/connector-inbound.ts +14 -7
  166. package/src/lib/server/connectors/connector-outbound.ts +16 -11
  167. package/src/lib/server/connectors/connector-service.ts +453 -0
  168. package/src/lib/server/connectors/delivery.ts +17 -12
  169. package/src/lib/server/connectors/inbound-audio-transcription.ts +5 -14
  170. package/src/lib/server/connectors/media.ts +1 -1
  171. package/src/lib/server/connectors/response-media.ts +1 -1
  172. package/src/lib/server/connectors/session-consolidation.ts +11 -7
  173. package/src/lib/server/connectors/session.ts +9 -7
  174. package/src/lib/server/connectors/voice-note.ts +2 -1
  175. package/src/lib/server/context-manager.ts +20 -1
  176. package/src/lib/server/cost.ts +2 -3
  177. package/src/lib/server/credentials/credential-repository.ts +43 -4
  178. package/src/lib/server/credentials/credential-service.ts +112 -0
  179. package/src/lib/server/daemon/admin-metadata.ts +64 -0
  180. package/src/lib/server/daemon/controller.ts +577 -0
  181. package/src/lib/server/daemon/daemon-runtime.ts +352 -0
  182. package/src/lib/server/daemon/daemon-status-repository.ts +63 -0
  183. package/src/lib/server/daemon/types.ts +101 -0
  184. package/src/lib/server/embeddings.ts +3 -9
  185. package/src/lib/server/eval/agent-regression.ts +3 -2
  186. package/src/lib/server/eval/runner.ts +2 -2
  187. package/src/lib/server/execution-brief.test.ts +167 -0
  188. package/src/lib/server/execution-brief.ts +295 -0
  189. package/src/lib/server/execution-engine/chat-turn.ts +9 -0
  190. package/src/lib/server/execution-engine/import-boundary.test.ts +44 -0
  191. package/src/lib/server/execution-engine/index.ts +35 -0
  192. package/src/lib/server/execution-engine/task-attempt.ts +303 -0
  193. package/src/lib/server/execution-engine/types.ts +33 -0
  194. package/src/lib/server/gateways/gateway-profile-repository.ts +47 -3
  195. package/src/lib/server/gateways/gateway-profile-service.ts +200 -0
  196. package/src/lib/server/memory/session-archive-memory.ts +12 -10
  197. package/src/lib/server/messages/message-repository.ts +330 -0
  198. package/src/lib/server/missions/mission-service/core.ts +8 -6
  199. package/src/lib/server/openclaw/agent-resolver.ts +2 -3
  200. package/src/lib/server/openclaw/doctor.ts +1 -1
  201. package/src/lib/server/openclaw/gateway.test.ts +10 -1
  202. package/src/lib/server/openclaw/gateway.ts +5 -14
  203. package/src/lib/server/openclaw/health.ts +3 -11
  204. package/src/lib/server/openclaw/sync.ts +8 -6
  205. package/src/lib/server/persistence/storage-context.ts +3 -0
  206. package/src/lib/server/protocols/protocol-agent-turn.ts +25 -17
  207. package/src/lib/server/protocols/protocol-normalization.ts +1 -1
  208. package/src/lib/server/protocols/protocol-queries.ts +13 -7
  209. package/src/lib/server/protocols/protocol-run-lifecycle.ts +16 -20
  210. package/src/lib/server/protocols/protocol-run-repository.ts +81 -0
  211. package/src/lib/server/protocols/protocol-step-processors.ts +23 -31
  212. package/src/lib/server/protocols/protocol-swarm.ts +8 -8
  213. package/src/lib/server/protocols/protocol-template-repository.ts +42 -0
  214. package/src/lib/server/protocols/protocol-templates.ts +4 -2
  215. package/src/lib/server/protocols/protocol-types.ts +10 -7
  216. package/src/lib/server/provider-endpoint.ts +7 -12
  217. package/src/lib/server/provider-model-discovery.ts +2 -11
  218. package/src/lib/server/query-expansion.ts +5 -6
  219. package/src/lib/server/run-context.test.ts +365 -0
  220. package/src/lib/server/run-context.ts +367 -0
  221. package/src/lib/server/runtime/heartbeat-service.ts +7 -5
  222. package/src/lib/server/runtime/queue/core.ts +61 -190
  223. package/src/lib/server/runtime/run-ledger.ts +8 -0
  224. package/src/lib/server/runtime/session-run-manager/drain.ts +2 -2
  225. package/src/lib/server/runtime/session-run-manager/enqueue.ts +6 -0
  226. package/src/lib/server/runtime/session-run-manager/state.ts +4 -0
  227. package/src/lib/server/schedules/schedule-route-service.ts +230 -0
  228. package/src/lib/server/service-result.ts +16 -0
  229. package/src/lib/server/session-note.ts +2 -3
  230. package/src/lib/server/session-reset-policy.ts +4 -3
  231. package/src/lib/server/session-tools/connector.ts +9 -6
  232. package/src/lib/server/session-tools/context-mgmt.ts +58 -9
  233. package/src/lib/server/session-tools/crud.ts +162 -10
  234. package/src/lib/server/session-tools/delegate.ts +1 -1
  235. package/src/lib/server/session-tools/manage-tasks.test.ts +152 -0
  236. package/src/lib/server/session-tools/memory.ts +6 -4
  237. package/src/lib/server/session-tools/session-info.test.ts +56 -0
  238. package/src/lib/server/session-tools/session-info.ts +119 -12
  239. package/src/lib/server/session-tools/skill-runtime.ts +3 -1
  240. package/src/lib/server/session-tools/skills.ts +15 -15
  241. package/src/lib/server/session-tools/subagent.test.ts +115 -1
  242. package/src/lib/server/session-tools/subagent.ts +125 -7
  243. package/src/lib/server/session-tools/team-context.ts +4 -3
  244. package/src/lib/server/session-tools/wallet.ts +0 -58
  245. package/src/lib/server/sessions/session-lineage.ts +55 -0
  246. package/src/lib/server/sessions/session-repository.ts +2 -2
  247. package/src/lib/server/skills/learned-skills.ts +24 -23
  248. package/src/lib/server/skills/runtime-skill-resolver.ts +2 -1
  249. package/src/lib/server/skills/skill-repository.ts +136 -13
  250. package/src/lib/server/skills/skill-suggestions.ts +25 -28
  251. package/src/lib/server/storage-normalization.test.ts +42 -215
  252. package/src/lib/server/storage-normalization.ts +98 -0
  253. package/src/lib/server/storage.ts +19 -0
  254. package/src/lib/server/structured-extract.ts +3 -14
  255. package/src/lib/server/tasks/task-followups.ts +16 -11
  256. package/src/lib/server/tasks/task-result.test.ts +25 -29
  257. package/src/lib/server/tasks/task-result.ts +5 -9
  258. package/src/lib/server/tasks/task-route-service.ts +449 -0
  259. package/src/lib/server/text-normalization.ts +41 -0
  260. package/src/lib/server/tool-planning.ts +6 -42
  261. package/src/lib/server/upload-path.ts +5 -0
  262. package/src/lib/server/working-state/extraction.ts +614 -0
  263. package/src/lib/server/working-state/normalization.ts +866 -0
  264. package/src/lib/server/working-state/prompt.ts +60 -0
  265. package/src/lib/server/working-state/repository.ts +38 -0
  266. package/src/lib/server/working-state/service.test.ts +253 -0
  267. package/src/lib/server/working-state/service.ts +293 -0
  268. package/src/lib/validation/schemas.ts +1 -0
  269. package/src/lib/ws-client.ts +3 -3
  270. package/src/stores/slices/task-slice.ts +1 -4
  271. package/src/stores/use-chatroom-store.ts +2 -2
  272. package/src/types/index.ts +288 -22
  273. package/src/views/settings/section-providers.tsx +2 -2
@@ -1,64 +1,37 @@
1
1
  import { NextResponse } from 'next/server'
2
- import { loadConnectors, loadConnectorHealth } from '@/lib/server/storage'
3
2
  import { notFound } from '@/lib/server/collection-helpers'
3
+ import { getConnectorHealthForApi } from '@/lib/server/connectors/connector-service'
4
4
  import type { ConnectorHealthEvent } from '@/types'
5
5
 
6
6
  export async function GET(req: Request, { params }: { params: Promise<{ id: string }> }) {
7
7
  const { id } = await params
8
- const connectors = loadConnectors()
9
- if (!connectors[id]) return notFound()
10
-
8
+ const result = getConnectorHealthForApi(id)
9
+ if (!result) return notFound()
11
10
  const url = new URL(req.url)
12
11
  const since = url.searchParams.get('since')
13
-
14
- const allHealth = loadConnectorHealth()
15
- const events: ConnectorHealthEvent[] = []
16
-
17
- for (const raw of Object.values(allHealth)) {
18
- const entry = raw as ConnectorHealthEvent
19
- if (entry.connectorId !== id) continue
20
- if (since && entry.timestamp < since) continue
21
- events.push(entry)
22
- }
23
-
24
- // Sort by timestamp ascending
25
- events.sort((a, b) => a.timestamp.localeCompare(b.timestamp))
26
-
27
- // Compute uptime percentage
28
- const uptimePercent = computeUptime(events)
29
-
30
- return NextResponse.json({ events, uptimePercent })
12
+ const events = since ? result.events.filter((entry) => entry.timestamp >= since) : result.events
13
+ return NextResponse.json({ events, uptimePercent: computeUptime(events) })
31
14
  }
32
15
 
33
16
  function computeUptime(events: ConnectorHealthEvent[]): number {
34
17
  if (events.length === 0) return 0
35
-
36
18
  const firstTime = new Date(events[0].timestamp).getTime()
37
19
  const now = Date.now()
38
20
  const totalMs = now - firstTime
39
21
  if (totalMs <= 0) return 100
40
-
41
22
  let uptimeMs = 0
42
23
  let lastUpAt: number | null = null
43
-
44
- for (const ev of events) {
45
- const t = new Date(ev.timestamp).getTime()
46
- if (ev.event === 'started' || ev.event === 'reconnected') {
47
- if (lastUpAt === null) {
48
- lastUpAt = t
49
- }
50
- } else if (ev.event === 'stopped' || ev.event === 'error' || ev.event === 'disconnected') {
24
+ for (const event of events) {
25
+ const time = new Date(event.timestamp).getTime()
26
+ if (event.event === 'started' || event.event === 'reconnected') {
27
+ if (lastUpAt === null) lastUpAt = time
28
+ } else if (event.event === 'stopped' || event.event === 'error' || event.event === 'disconnected') {
51
29
  if (lastUpAt !== null) {
52
- uptimeMs += t - lastUpAt
30
+ uptimeMs += time - lastUpAt
53
31
  lastUpAt = null
54
32
  }
55
33
  }
56
34
  }
57
-
58
- // If still up, count time until now
59
- if (lastUpAt !== null) {
60
- uptimeMs += now - lastUpAt
61
- }
62
-
35
+ if (lastUpAt !== null) uptimeMs += now - lastUpAt
63
36
  return Math.round((uptimeMs / totalMs) * 10000) / 100
64
37
  }
@@ -1,141 +1,33 @@
1
1
  import { NextResponse } from 'next/server'
2
2
  import { safeParseBody } from '@/lib/server/safe-parse-body'
3
- import { loadConnectors, logActivity, upsertStoredItem, deleteStoredItem } from '@/lib/server/storage'
4
- import { notify } from '@/lib/server/ws-hub'
5
3
  import { notFound } from '@/lib/server/collection-helpers'
6
- import { ensureDaemonStarted } from '@/lib/server/runtime/daemon-state'
7
- import { errorMessage } from '@/lib/shared-utils'
4
+ import {
5
+ deleteConnectorFromRoute,
6
+ getConnectorWithRuntime,
7
+ updateConnectorFromRoute,
8
+ } from '@/lib/server/connectors/connector-service'
8
9
 
9
10
  export async function GET(_req: Request, { params }: { params: Promise<{ id: string }> }) {
10
- ensureDaemonStarted('api/connectors/[id]:get')
11
11
  const { id } = await params
12
- const connectors = loadConnectors()
13
- const connector = connectors[id]
12
+ const connector = await getConnectorWithRuntime(id)
14
13
  if (!connector) return notFound()
15
-
16
- // Merge runtime status, QR code, and presence
17
- try {
18
- const { getConnectorStatus, getConnectorQR, isConnectorAuthenticated, hasConnectorCredentials, getConnectorPresence, getReconnectState } = await import('@/lib/server/connectors/manager')
19
- const runtimeStatus = getConnectorStatus(id)
20
- connector.status = runtimeStatus === 'running'
21
- ? 'running'
22
- : connector.lastError
23
- ? 'error'
24
- : 'stopped'
25
- const rState = getReconnectState(id)
26
- if (rState) {
27
- const ext = connector as unknown as Record<string, unknown>
28
- ext.reconnectAttempts = rState.attempts
29
- ext.nextRetryAt = rState.nextRetryAt
30
- ext.reconnectError = rState.error
31
- ext.reconnectExhausted = rState.exhausted
32
- }
33
- const qr = getConnectorQR(id)
34
- if (qr) connector.qrDataUrl = qr
35
- connector.authenticated = isConnectorAuthenticated(id)
36
- connector.hasCredentials = hasConnectorCredentials(id)
37
- if (connector.status === 'running') {
38
- connector.presence = getConnectorPresence(id)
39
- }
40
- } catch { /* ignore */ }
41
-
42
14
  return NextResponse.json(connector)
43
15
  }
44
16
 
45
17
  export async function PUT(req: Request, { params }: { params: Promise<{ id: string }> }) {
46
- ensureDaemonStarted('api/connectors/[id]:put')
47
18
  const { id } = await params
48
19
  const { data: body, error } = await safeParseBody<Record<string, unknown>>(req)
49
20
  if (error) return error
50
- const connectors = loadConnectors()
51
- const connector = connectors[id]
52
- if (!connector) return notFound()
53
-
54
- // Handle start/stop/repair actions these modify connector state internally,
55
- // so re-read from storage after to avoid overwriting with stale data
56
- if (body.action === 'start' || body.action === 'stop' || body.action === 'repair') {
57
- try {
58
- const manager = await import('@/lib/server/connectors/manager')
59
- if (body.action === 'start') {
60
- manager.clearReconnectState(id)
61
- await manager.startConnector(id)
62
- logActivity({ entityType: 'connector', entityId: id, action: 'started', actor: 'user', summary: `Connector started: "${connector.name}"` })
63
- } else if (body.action === 'stop') {
64
- await manager.stopConnector(id)
65
- logActivity({ entityType: 'connector', entityId: id, action: 'stopped', actor: 'user', summary: `Connector stopped: "${connector.name}"` })
66
- } else {
67
- manager.clearReconnectState(id)
68
- await manager.repairConnector(id)
69
- logActivity({ entityType: 'connector', entityId: id, action: 'started', actor: 'user', summary: `Connector repaired: "${connector.name}"` })
70
- }
71
- } catch (err: unknown) {
72
- // Re-read to get the error state saved by startConnector
73
- const fresh = loadConnectors()
74
- return NextResponse.json(fresh[id] || { error: errorMessage(err) }, { status: 500 })
75
- }
76
- // Re-read the connector after manager modified it
77
- const fresh = loadConnectors()
78
- notify('connectors')
79
- return NextResponse.json(fresh[id])
80
- }
81
-
82
- // Regular update — guard types at the boundary
83
- if (body.name !== undefined) connector.name = typeof body.name === 'string' ? body.name : connector.name
84
- if (body.agentId !== undefined) connector.agentId = typeof body.agentId === 'string' || body.agentId === null ? body.agentId : connector.agentId
85
- if (body.chatroomId !== undefined) connector.chatroomId = typeof body.chatroomId === 'string' || body.chatroomId === null ? body.chatroomId : connector.chatroomId
86
- if (body.credentialId !== undefined) connector.credentialId = typeof body.credentialId === 'string' || body.credentialId === null ? body.credentialId : connector.credentialId
87
- if (body.config !== undefined) connector.config = body.config && typeof body.config === 'object' && !Array.isArray(body.config) ? body.config as Record<string, string> : connector.config
88
- if (body.isEnabled !== undefined) connector.isEnabled = typeof body.isEnabled === 'boolean' ? body.isEnabled : connector.isEnabled
89
- connector.updatedAt = Date.now()
90
-
91
- upsertStoredItem('connectors', id, connector)
92
-
93
- try {
94
- const manager = await import('@/lib/server/connectors/manager')
95
- const wasRunning = manager.getConnectorStatus(id) === 'running'
96
- const shouldStop = body.isEnabled === false
97
- const shouldReload = wasRunning && (
98
- body.name !== undefined
99
- || body.agentId !== undefined
100
- || body.chatroomId !== undefined
101
- || body.credentialId !== undefined
102
- || body.config !== undefined
103
- || body.isEnabled !== undefined
104
- )
105
- const shouldStart = body.isEnabled === true && !wasRunning
106
-
107
- if (shouldStop) {
108
- await manager.stopConnector(id)
109
- } else if (shouldReload || shouldStart) {
110
- manager.clearReconnectState(id)
111
- await manager.startConnector(id)
112
- }
113
- } catch {
114
- // Keep the saved connector update even if the runtime reload fails.
115
- }
116
-
117
- notify('connectors')
118
- return NextResponse.json(loadConnectors()[id] || connector)
21
+ const result = await updateConnectorFromRoute(id, body)
22
+ if (!result.ok && result.status === 404) return notFound()
23
+ return result.ok
24
+ ? NextResponse.json(result.payload)
25
+ : NextResponse.json(result.payload, { status: result.status })
119
26
  }
120
27
 
121
28
  export async function DELETE(_req: Request, { params }: { params: Promise<{ id: string }> }) {
122
29
  const { id } = await params
123
- const connectors = loadConnectors()
124
- if (!connectors[id]) return notFound()
125
-
126
- // Stop if running
127
- try {
128
- const { stopConnector } = await import('@/lib/server/connectors/manager')
129
- await stopConnector(id)
130
- } catch { /* ignore */ }
131
-
132
- // Clear persisted pairing state when connector is deleted.
133
- try {
134
- const { clearConnectorPairingState } = await import('@/lib/server/connectors/pairing')
135
- clearConnectorPairingState(id)
136
- } catch { /* ignore */ }
137
-
138
- deleteStoredItem('connectors', id)
139
- notify('connectors')
140
- return NextResponse.json({ ok: true })
30
+ const result = await deleteConnectorFromRoute(id)
31
+ if (!result.ok) return notFound()
32
+ return NextResponse.json(result.payload)
141
33
  }
@@ -1,5 +1,5 @@
1
1
  import { NextResponse } from 'next/server'
2
- import { loadConnectors } from '@/lib/server/storage'
2
+ import { loadConnectors } from '@/lib/server/connectors/connector-repository'
3
3
 
4
4
  export const dynamic = 'force-dynamic'
5
5
 
@@ -1,6 +1,6 @@
1
1
  import { NextResponse } from 'next/server'
2
2
  import { buildConnectorDoctorPreview, buildConnectorDoctorReport, type ConnectorDoctorPreviewInput } from '@/lib/server/connectors/doctor'
3
- import { loadConnectors } from '@/lib/server/storage'
3
+ import { loadConnectors } from '@/lib/server/connectors/connector-repository'
4
4
 
5
5
  export const dynamic = 'force-dynamic'
6
6
 
@@ -1,91 +1,33 @@
1
1
  import { NextResponse } from 'next/server'
2
2
  import { safeParseBody } from '@/lib/server/safe-parse-body'
3
- import { genId } from '@/lib/id'
4
3
  import { perf } from '@/lib/server/runtime/perf'
5
- import { loadConnectors, upsertStoredItem } from '@/lib/server/storage'
6
- import { notify } from '@/lib/server/ws-hub'
7
- import { ensureDaemonStarted } from '@/lib/server/runtime/daemon-state'
8
4
  import { ConnectorCreateSchema, formatZodError } from '@/lib/validation/schemas'
9
5
  import { z } from 'zod'
10
- import type { Connector } from '@/types'
6
+ import {
7
+ autoStartConnectorIfNeeded,
8
+ createConnector,
9
+ listConnectorsWithRuntime,
10
+ } from '@/lib/server/connectors/connector-service'
11
+ import { ensureDaemonProcessRunning } from '@/lib/server/daemon/controller'
12
+ import { loadConnector } from '@/lib/server/connectors/connector-repository'
11
13
  export const dynamic = 'force-dynamic'
12
14
 
13
-
14
15
  export async function GET() {
15
16
  const endPerf = perf.start('api', 'GET /api/connectors')
16
- ensureDaemonStarted('api/connectors:get')
17
- const connectors = loadConnectors()
18
- // Merge runtime status from manager
19
- try {
20
- const { getConnectorStatus, isConnectorAuthenticated, hasConnectorCredentials, getConnectorQR, getReconnectState } = await import('@/lib/server/connectors/manager')
21
- for (const c of Object.values(connectors) as Connector[]) {
22
- const runtimeStatus = getConnectorStatus(c.id)
23
- c.status = runtimeStatus === 'running'
24
- ? 'running'
25
- : c.lastError
26
- ? 'error'
27
- : 'stopped'
28
- if (c.platform === 'whatsapp') {
29
- c.authenticated = isConnectorAuthenticated(c.id)
30
- c.hasCredentials = hasConnectorCredentials(c.id)
31
- const qr = getConnectorQR(c.id)
32
- if (qr) c.qrDataUrl = qr
33
- }
34
- // Surface reconnect state if connector is in a recovery cycle
35
- const rState = getReconnectState(c.id)
36
- if (rState) {
37
- const ext = c as unknown as Record<string, unknown>
38
- ext.reconnectAttempts = rState.attempts
39
- ext.nextRetryAt = rState.nextRetryAt
40
- ext.reconnectError = rState.error
41
- ext.reconnectExhausted = rState.exhausted
42
- }
43
- }
44
- } catch { /* manager not loaded yet */ }
17
+ const connectors = await listConnectorsWithRuntime()
45
18
  endPerf({ count: Object.keys(connectors).length })
46
19
  return NextResponse.json(connectors)
47
20
  }
48
21
 
49
22
  export async function POST(req: Request) {
50
- ensureDaemonStarted('api/connectors:post')
23
+ await ensureDaemonProcessRunning('api/connectors:post')
51
24
  const { data: raw, error } = await safeParseBody<Record<string, unknown>>(req)
52
25
  if (error) return error
53
26
  const parsed = ConnectorCreateSchema.safeParse(raw)
54
27
  if (!parsed.success) {
55
28
  return NextResponse.json(formatZodError(parsed.error as z.ZodError), { status: 400 })
56
29
  }
57
- const body = parsed.data
58
- const id = genId()
59
-
60
- const connector: Connector = {
61
- id,
62
- name: body.name || `${body.platform} Connector`,
63
- platform: body.platform,
64
- agentId: body.agentId || null,
65
- chatroomId: body.chatroomId || null,
66
- credentialId: body.credentialId || null,
67
- config: body.config || {},
68
- isEnabled: false,
69
- status: 'stopped',
70
- lastError: null,
71
- createdAt: Date.now(),
72
- updatedAt: Date.now(),
73
- }
74
-
75
- upsertStoredItem('connectors', id, connector)
76
- notify('connectors')
77
-
78
- // Auto-start if connector has credentials (or is WhatsApp which uses QR)
79
- const hasCredentials = connector.platform === 'whatsapp'
80
- || connector.platform === 'openclaw'
81
- || (connector.platform === 'bluebubbles' && (!!connector.credentialId || !!connector.config.password))
82
- || !!connector.credentialId
83
- if (hasCredentials && body.autoStart !== false) {
84
- try {
85
- const { startConnector } = await import('@/lib/server/connectors/manager')
86
- await startConnector(id)
87
- } catch { /* auto-start is best-effort */ }
88
- }
89
-
90
- return NextResponse.json(loadConnectors()[id] || connector)
30
+ const connector = createConnector(parsed.data as unknown as Record<string, unknown>)
31
+ await autoStartConnectorIfNeeded(connector, parsed.data as unknown as Record<string, unknown>)
32
+ return NextResponse.json(loadConnector(connector.id) || connector)
91
33
  }
@@ -1,5 +1,5 @@
1
1
  import { NextResponse } from 'next/server'
2
- import { loadCredentials, deleteCredential } from '@/lib/server/storage'
2
+ import { deleteCredentialRecord } from '@/lib/server/credentials/credential-service'
3
3
  import { notFound } from '@/lib/server/collection-helpers'
4
4
  import { log } from '@/lib/server/logger'
5
5
 
@@ -7,11 +7,9 @@ const TAG = 'api-credentials'
7
7
 
8
8
  export async function DELETE(_req: Request, { params }: { params: Promise<{ id: string }> }) {
9
9
  const { id: credId } = await params
10
- const creds = loadCredentials()
11
- if (!creds[credId]) {
10
+ if (!deleteCredentialRecord(credId)) {
12
11
  return notFound()
13
12
  }
14
- deleteCredential(credId)
15
13
  log.info(TAG, `deleted ${credId}`)
16
14
  return new NextResponse('OK')
17
15
  }
@@ -1,17 +1,11 @@
1
1
  import { NextResponse } from 'next/server'
2
- import { genId } from '@/lib/id'
3
- import { loadCredentials, saveCredentials, encryptKey } from '@/lib/server/storage'
2
+ import { createCredentialRecord, listCredentialSummaries } from '@/lib/server/credentials/credential-service'
4
3
  import { safeParseBody } from '@/lib/server/safe-parse-body'
5
4
  export const dynamic = 'force-dynamic'
6
5
 
7
6
 
8
- export async function GET(_req: Request) {
9
- const creds = loadCredentials()
10
- const safe: Record<string, Record<string, unknown>> = {}
11
- for (const [id, c] of Object.entries(creds) as [string, Record<string, unknown>][]) {
12
- safe[id] = { id: c.id, provider: c.provider, name: c.name, createdAt: c.createdAt }
13
- }
14
- return NextResponse.json(safe)
7
+ export async function GET() {
8
+ return NextResponse.json(listCredentialSummaries())
15
9
  }
16
10
 
17
11
  export async function POST(req: Request) {
@@ -21,15 +15,12 @@ export async function POST(req: Request) {
21
15
  if (!provider || !apiKey) {
22
16
  return NextResponse.json({ error: 'provider and apiKey are required' }, { status: 400 })
23
17
  }
24
- const id = 'cred_' + genId(6)
25
- const creds = loadCredentials()
26
- creds[id] = {
27
- id,
28
- provider,
29
- name: name || `${provider} key`,
30
- encryptedKey: encryptKey(apiKey),
31
- createdAt: Date.now(),
18
+ try {
19
+ return NextResponse.json(createCredentialRecord({ provider, name, apiKey }))
20
+ } catch (err: unknown) {
21
+ return NextResponse.json(
22
+ { error: err instanceof Error ? err.message : 'Failed to create credential' },
23
+ { status: 500 },
24
+ )
32
25
  }
33
- saveCredentials(creds)
34
- return NextResponse.json({ id, provider, name: creds[id].name, createdAt: creds[id].createdAt })
35
26
  }
@@ -1,11 +1,10 @@
1
1
  import { NextResponse } from 'next/server'
2
- import { ensureDaemonStarted, getDaemonStatus, runDaemonHealthCheckNow } from '@/lib/server/runtime/daemon-state'
2
+ import { runDaemonHealthCheckViaAdmin } from '@/lib/server/daemon/controller'
3
3
 
4
4
  export async function POST() {
5
- ensureDaemonStarted('api/daemon/health-check:post')
6
- await runDaemonHealthCheckNow()
5
+ const snapshot = await runDaemonHealthCheckViaAdmin('api/daemon/health-check:post')
7
6
  return NextResponse.json({
8
7
  ok: true,
9
- status: getDaemonStatus(),
8
+ status: snapshot.status,
10
9
  })
11
10
  }
@@ -1,11 +1,15 @@
1
1
  import { NextResponse } from 'next/server'
2
+ import {
3
+ ensureDaemonProcessRunning,
4
+ getDaemonStatusSnapshot,
5
+ stopDaemonProcess,
6
+ } from '@/lib/server/daemon/controller'
2
7
  import { notify } from '@/lib/server/ws-hub'
3
8
  export const dynamic = 'force-dynamic'
4
9
 
5
10
 
6
11
  export async function GET() {
7
- const { getDaemonStatus } = await import('@/lib/server/runtime/daemon-state')
8
- return NextResponse.json(getDaemonStatus())
12
+ return NextResponse.json(await getDaemonStatusSnapshot())
9
13
  }
10
14
 
11
15
  export async function POST(req: Request) {
@@ -13,15 +17,13 @@ export async function POST(req: Request) {
13
17
  const action = body.action
14
18
 
15
19
  if (action === 'start') {
16
- const { startDaemon } = await import('@/lib/server/runtime/daemon-state')
17
- startDaemon({ source: 'api/daemon:post:start', manualStart: true })
20
+ await ensureDaemonProcessRunning('api/daemon:post:start', { manualStart: true })
18
21
  notify('daemon')
19
- return NextResponse.json({ ok: true, status: 'running' })
22
+ return NextResponse.json(await getDaemonStatusSnapshot())
20
23
  } else if (action === 'stop') {
21
- const { stopDaemon } = await import('@/lib/server/runtime/daemon-state')
22
- await stopDaemon({ source: 'api/daemon:post:stop', manualStop: true })
24
+ await stopDaemonProcess({ source: 'api/daemon:post:stop', manualStop: true })
23
25
  notify('daemon')
24
- return NextResponse.json({ ok: true, status: 'stopped' })
26
+ return NextResponse.json(await getDaemonStatusSnapshot())
25
27
  }
26
28
 
27
29
  return NextResponse.json({ error: 'Invalid action. Use "start" or "stop".' }, { status: 400 })
@@ -26,9 +26,10 @@ export async function GET(req: Request) {
26
26
  const terms = q.split(/\s+/).filter(Boolean)
27
27
  const limit = normalizeLimit(searchParams.get('limit'), 10, 100)
28
28
  const rows = Object.values(docs)
29
- .map((doc: any) => {
30
- const title = String(doc.title || '')
31
- const content = String(doc.content || '')
29
+ .map((doc) => {
30
+ const d = doc as Record<string, unknown>
31
+ const title = String(d.title || '')
32
+ const content = String(d.content || '')
32
33
  const hay = `${title}\n${content}`.toLowerCase()
33
34
  if (!terms.every((term) => hay.includes(term))) return null
34
35
 
@@ -48,18 +49,18 @@ export async function GET(req: Request) {
48
49
  const snippet = content.slice(snippetStart, snippetEnd).replace(/\s+/g, ' ').trim()
49
50
 
50
51
  return {
51
- id: doc.id,
52
- title: doc.title,
53
- fileName: doc.fileName,
54
- sourcePath: doc.sourcePath,
55
- textLength: doc.textLength || content.length,
56
- updatedAt: doc.updatedAt,
52
+ id: d.id,
53
+ title: d.title,
54
+ fileName: d.fileName,
55
+ sourcePath: d.sourcePath,
56
+ textLength: (d.textLength as number) || content.length,
57
+ updatedAt: d.updatedAt,
57
58
  score,
58
59
  snippet,
59
60
  }
60
61
  })
61
62
  .filter(Boolean)
62
- .sort((a: any, b: any) => b.score - a.score)
63
+ .sort((a, b) => (b as { score: number }).score - (a as { score: number }).score)
63
64
  .slice(0, limit)
64
65
 
65
66
  return NextResponse.json(rows)
@@ -3,7 +3,7 @@ import { genId } from '@/lib/id'
3
3
  import { formatZodError, ExternalAgentRegisterSchema } from '@/lib/validation/schemas'
4
4
  import { loadExternalAgents, loadGatewayProfiles, saveExternalAgents } from '@/lib/server/storage'
5
5
  import { notify } from '@/lib/server/ws-hub'
6
- import type { ExternalAgentRuntime } from '@/types'
6
+ import type { ExternalAgentRuntime, GatewayProfile } from '@/types'
7
7
  import { z } from 'zod'
8
8
  export const dynamic = 'force-dynamic'
9
9
 
@@ -14,9 +14,9 @@ function withDerivedStatus(record: ExternalAgentRuntime): ExternalAgentRuntime {
14
14
  if (!lastSeenAt) return { ...record, status: record.status || 'offline' }
15
15
  if (record.status === 'offline') return record
16
16
  const gateways = loadGatewayProfiles()
17
- const gateway = record.gatewayProfileId ? gateways[record.gatewayProfileId] as any : undefined
17
+ const gateway = record.gatewayProfileId ? gateways[record.gatewayProfileId] as GatewayProfile | undefined : undefined
18
18
  const gatewayTags = Array.isArray(gateway?.tags)
19
- ? (gateway as any)?.tags?.filter((tag: any): tag is string => typeof tag === 'string' && tag.trim().length > 0)
19
+ ? gateway.tags.filter((tag): tag is string => typeof tag === 'string' && tag.trim().length > 0)
20
20
  : []
21
21
  const gatewayUseCase = gateway?.deployment && typeof gateway.deployment === 'object' && typeof (gateway.deployment as Record<string, unknown>).useCase === 'string'
22
22
  ? (gateway.deployment as Record<string, unknown>).useCase as string
@@ -1,13 +1,12 @@
1
1
  import { NextResponse } from 'next/server'
2
2
  import { probeOpenClawHealth, persistGatewayHealthResult } from '@/lib/server/openclaw/health'
3
- import { loadGatewayProfiles } from '@/lib/server/storage'
3
+ import { loadGatewayProfile } from '@/lib/server/gateways/gateway-profile-repository'
4
4
  import { notFound } from '@/lib/server/collection-helpers'
5
5
  export const dynamic = 'force-dynamic'
6
6
 
7
7
  export async function GET(_req: Request, { params }: { params: Promise<{ id: string }> }) {
8
8
  const { id } = await params
9
- const gateways = loadGatewayProfiles()
10
- const gateway = gateways[id]
9
+ const gateway = loadGatewayProfile(id)
11
10
  if (!gateway) return notFound()
12
11
 
13
12
  const result = await probeOpenClawHealth({