@swarmclawai/swarmclaw 1.2.4 → 1.2.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (262) hide show
  1. package/README.md +14 -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]/route.test.ts +49 -0
  49. package/src/app/api/providers/ollama/route.ts +6 -5
  50. package/src/app/api/schedules/[id]/route.ts +14 -108
  51. package/src/app/api/schedules/[id]/run/route.ts +6 -67
  52. package/src/app/api/schedules/route.ts +9 -51
  53. package/src/app/api/settings/route.ts +4 -3
  54. package/src/app/api/setup/check-provider/route.ts +23 -1
  55. package/src/app/api/setup/openclaw-device/route.ts +2 -2
  56. package/src/app/api/system/status/route.ts +2 -2
  57. package/src/app/api/tasks/[id]/route.ts +16 -202
  58. package/src/app/api/tasks/bulk/route.ts +5 -86
  59. package/src/app/api/tasks/metrics/route.ts +2 -1
  60. package/src/app/api/tasks/route.ts +11 -171
  61. package/src/app/api/upload/route.ts +1 -1
  62. package/src/app/api/uploads/[filename]/route.ts +1 -1
  63. package/src/app/api/uploads/route.ts +1 -1
  64. package/src/app/api/webhooks/[id]/history/route.ts +2 -2
  65. package/src/app/layout.tsx +9 -6
  66. package/src/app/protocols/page.tsx +71 -89
  67. package/src/app/tasks/page.tsx +32 -32
  68. package/src/cli/index.js +1 -0
  69. package/src/cli/spec.js +1 -0
  70. package/src/components/agents/agent-sheet.tsx +5 -5
  71. package/src/components/auth/setup-wizard/index.tsx +4 -4
  72. package/src/components/auth/setup-wizard/step-agents.tsx +1 -1
  73. package/src/components/auth/setup-wizard/step-connect.tsx +1 -1
  74. package/src/components/auth/setup-wizard/utils.ts +1 -1
  75. package/src/components/chatrooms/chatroom-sheet.tsx +16 -276
  76. package/src/components/connectors/connector-list.tsx +26 -40
  77. package/src/components/connectors/connector-sheet.tsx +95 -149
  78. package/src/components/gateways/gateway-sheet.tsx +61 -110
  79. package/src/components/layout/live-query-sync.tsx +121 -0
  80. package/src/components/protocols/structured-session-launcher.tsx +24 -45
  81. package/src/components/providers/app-query-provider.tsx +17 -0
  82. package/src/components/providers/provider-list.tsx +60 -61
  83. package/src/components/providers/provider-sheet.tsx +74 -56
  84. package/src/components/skills/skill-list.tsx +5 -18
  85. package/src/components/skills/skill-sheet.tsx +21 -20
  86. package/src/components/skills/skills-workspace.tsx +48 -87
  87. package/src/components/tasks/task-card.tsx +20 -13
  88. package/src/components/tasks/task-column.tsx +22 -7
  89. package/src/components/tasks/task-list.tsx +8 -11
  90. package/src/components/tasks/task-sheet.tsx +111 -103
  91. package/src/features/agents/queries.ts +20 -0
  92. package/src/features/chatrooms/queries.ts +20 -0
  93. package/src/features/chats/queries.ts +27 -0
  94. package/src/features/connectors/queries.ts +145 -0
  95. package/src/features/credentials/queries.ts +37 -0
  96. package/src/features/extensions/queries.ts +26 -0
  97. package/src/features/external-agents/queries.ts +36 -0
  98. package/src/features/gateways/queries.ts +274 -0
  99. package/src/features/missions/queries.ts +23 -0
  100. package/src/features/projects/queries.ts +20 -0
  101. package/src/features/protocols/queries.ts +149 -0
  102. package/src/features/providers/queries.ts +142 -0
  103. package/src/features/settings/queries.ts +20 -0
  104. package/src/features/skills/queries.ts +182 -0
  105. package/src/features/tasks/queries.ts +189 -0
  106. package/src/hooks/use-ws.ts +3 -2
  107. package/src/lib/app/api-client.ts +2 -2
  108. package/src/lib/providers/index.test.ts +108 -0
  109. package/src/lib/providers/index.ts +38 -15
  110. package/src/lib/query/client.ts +17 -0
  111. package/src/lib/server/agents/agent-runtime-config.ts +1 -1
  112. package/src/lib/server/agents/agent-service.ts +429 -0
  113. package/src/lib/server/agents/agent-thread-session.ts +6 -5
  114. package/src/lib/server/agents/autonomy-contract.ts +1 -4
  115. package/src/lib/server/agents/delegation-advisory.test.ts +206 -0
  116. package/src/lib/server/agents/delegation-advisory.ts +251 -0
  117. package/src/lib/server/agents/main-agent-loop.ts +98 -40
  118. package/src/lib/server/agents/subagent-runtime.ts +12 -0
  119. package/src/lib/server/autonomy/supervisor-reflection.test.ts +20 -1
  120. package/src/lib/server/autonomy/supervisor-reflection.ts +39 -19
  121. package/src/lib/server/build-llm.ts +7 -15
  122. package/src/lib/server/capability-router.test.ts +70 -1
  123. package/src/lib/server/capability-router.ts +24 -99
  124. package/src/lib/server/chat-execution/chat-execution-utils.ts +0 -15
  125. package/src/lib/server/chat-execution/chat-streaming-utils.ts +2 -4
  126. package/src/lib/server/chat-execution/chat-turn-finalization.ts +77 -12
  127. package/src/lib/server/chat-execution/chat-turn-partial-persistence.ts +4 -4
  128. package/src/lib/server/chat-execution/chat-turn-preflight.ts +2 -2
  129. package/src/lib/server/chat-execution/chat-turn-preparation.ts +41 -17
  130. package/src/lib/server/chat-execution/chat-turn-stream-execution.ts +4 -2
  131. package/src/lib/server/chat-execution/chat-turn-tool-routing.test.ts +45 -0
  132. package/src/lib/server/chat-execution/chat-turn-tool-routing.ts +48 -17
  133. package/src/lib/server/chat-execution/continuation-evaluator.ts +4 -1
  134. package/src/lib/server/chat-execution/direct-memory-intent.test.ts +9 -0
  135. package/src/lib/server/chat-execution/direct-memory-intent.ts +12 -2
  136. package/src/lib/server/chat-execution/message-classifier.test.ts +35 -23
  137. package/src/lib/server/chat-execution/message-classifier.ts +74 -32
  138. package/src/lib/server/chat-execution/prompt-builder.test.ts +29 -0
  139. package/src/lib/server/chat-execution/prompt-builder.ts +37 -2
  140. package/src/lib/server/chat-execution/prompt-sections.test.ts +56 -0
  141. package/src/lib/server/chat-execution/prompt-sections.ts +193 -0
  142. package/src/lib/server/chat-execution/stream-agent-chat.ts +63 -7
  143. package/src/lib/server/chat-execution/stream-continuation.test.ts +36 -0
  144. package/src/lib/server/chat-execution/stream-continuation.ts +28 -13
  145. package/src/lib/server/chatrooms/chatroom-agent-signals.ts +26 -18
  146. package/src/lib/server/chatrooms/chatroom-helpers.ts +19 -18
  147. package/src/lib/server/chatrooms/chatroom-repository.ts +16 -0
  148. package/src/lib/server/chatrooms/chatroom-routing.test.ts +96 -0
  149. package/src/lib/server/chatrooms/chatroom-routing.ts +207 -53
  150. package/src/lib/server/chatrooms/mailbox-utils.ts +4 -2
  151. package/src/lib/server/chatrooms/session-mailbox.ts +50 -40
  152. package/src/lib/server/chats/chat-session-service.ts +410 -0
  153. package/src/lib/server/connectors/access.ts +1 -1
  154. package/src/lib/server/connectors/commands.ts +7 -6
  155. package/src/lib/server/connectors/connector-inbound.ts +14 -7
  156. package/src/lib/server/connectors/connector-outbound.ts +16 -11
  157. package/src/lib/server/connectors/connector-service.ts +453 -0
  158. package/src/lib/server/connectors/delivery.ts +17 -12
  159. package/src/lib/server/connectors/inbound-audio-transcription.ts +5 -14
  160. package/src/lib/server/connectors/media.ts +1 -1
  161. package/src/lib/server/connectors/response-media.ts +1 -1
  162. package/src/lib/server/connectors/session-consolidation.ts +11 -7
  163. package/src/lib/server/connectors/session.ts +9 -7
  164. package/src/lib/server/connectors/voice-note.ts +2 -1
  165. package/src/lib/server/context-manager.ts +20 -1
  166. package/src/lib/server/cost.ts +2 -3
  167. package/src/lib/server/credentials/credential-repository.ts +43 -4
  168. package/src/lib/server/credentials/credential-service.ts +112 -0
  169. package/src/lib/server/daemon/admin-metadata.ts +64 -0
  170. package/src/lib/server/daemon/controller.ts +577 -0
  171. package/src/lib/server/daemon/daemon-runtime.ts +352 -0
  172. package/src/lib/server/daemon/daemon-status-repository.ts +63 -0
  173. package/src/lib/server/daemon/types.ts +101 -0
  174. package/src/lib/server/embeddings.ts +3 -9
  175. package/src/lib/server/eval/agent-regression.ts +3 -2
  176. package/src/lib/server/eval/runner.ts +2 -2
  177. package/src/lib/server/execution-brief.test.ts +167 -0
  178. package/src/lib/server/execution-brief.ts +295 -0
  179. package/src/lib/server/execution-engine/chat-turn.ts +9 -0
  180. package/src/lib/server/execution-engine/import-boundary.test.ts +44 -0
  181. package/src/lib/server/execution-engine/index.ts +35 -0
  182. package/src/lib/server/execution-engine/task-attempt.ts +303 -0
  183. package/src/lib/server/execution-engine/types.ts +33 -0
  184. package/src/lib/server/gateways/gateway-profile-repository.ts +47 -3
  185. package/src/lib/server/gateways/gateway-profile-service.ts +200 -0
  186. package/src/lib/server/memory/session-archive-memory.ts +12 -10
  187. package/src/lib/server/messages/message-repository.ts +330 -0
  188. package/src/lib/server/missions/mission-service/core.ts +8 -6
  189. package/src/lib/server/openclaw/agent-resolver.ts +2 -3
  190. package/src/lib/server/openclaw/doctor.ts +1 -1
  191. package/src/lib/server/openclaw/gateway.test.ts +10 -1
  192. package/src/lib/server/openclaw/gateway.ts +5 -14
  193. package/src/lib/server/openclaw/health.ts +3 -11
  194. package/src/lib/server/openclaw/sync.ts +8 -6
  195. package/src/lib/server/persistence/storage-context.ts +3 -0
  196. package/src/lib/server/protocols/protocol-agent-turn.ts +25 -17
  197. package/src/lib/server/protocols/protocol-normalization.ts +1 -1
  198. package/src/lib/server/protocols/protocol-queries.ts +13 -7
  199. package/src/lib/server/protocols/protocol-run-lifecycle.ts +16 -20
  200. package/src/lib/server/protocols/protocol-run-repository.ts +81 -0
  201. package/src/lib/server/protocols/protocol-step-processors.ts +23 -31
  202. package/src/lib/server/protocols/protocol-swarm.ts +8 -8
  203. package/src/lib/server/protocols/protocol-template-repository.ts +42 -0
  204. package/src/lib/server/protocols/protocol-templates.ts +4 -2
  205. package/src/lib/server/protocols/protocol-types.ts +10 -7
  206. package/src/lib/server/provider-endpoint.ts +7 -12
  207. package/src/lib/server/provider-model-discovery.ts +2 -11
  208. package/src/lib/server/query-expansion.ts +5 -6
  209. package/src/lib/server/run-context.test.ts +365 -0
  210. package/src/lib/server/run-context.ts +367 -0
  211. package/src/lib/server/runtime/heartbeat-service.ts +7 -5
  212. package/src/lib/server/runtime/queue/core.ts +61 -190
  213. package/src/lib/server/runtime/run-ledger.ts +8 -0
  214. package/src/lib/server/runtime/session-run-manager/drain.ts +2 -2
  215. package/src/lib/server/runtime/session-run-manager/enqueue.ts +6 -0
  216. package/src/lib/server/runtime/session-run-manager/state.ts +4 -0
  217. package/src/lib/server/schedules/schedule-route-service.ts +230 -0
  218. package/src/lib/server/service-result.ts +16 -0
  219. package/src/lib/server/session-note.ts +2 -3
  220. package/src/lib/server/session-reset-policy.ts +4 -3
  221. package/src/lib/server/session-tools/connector.ts +9 -6
  222. package/src/lib/server/session-tools/context-mgmt.ts +58 -9
  223. package/src/lib/server/session-tools/crud.ts +162 -10
  224. package/src/lib/server/session-tools/delegate.ts +1 -1
  225. package/src/lib/server/session-tools/manage-tasks.test.ts +152 -0
  226. package/src/lib/server/session-tools/memory.ts +6 -4
  227. package/src/lib/server/session-tools/session-info.test.ts +56 -0
  228. package/src/lib/server/session-tools/session-info.ts +119 -12
  229. package/src/lib/server/session-tools/skill-runtime.ts +3 -1
  230. package/src/lib/server/session-tools/skills.ts +15 -15
  231. package/src/lib/server/session-tools/subagent.test.ts +115 -1
  232. package/src/lib/server/session-tools/subagent.ts +125 -7
  233. package/src/lib/server/session-tools/team-context.ts +4 -3
  234. package/src/lib/server/session-tools/wallet.ts +0 -58
  235. package/src/lib/server/sessions/session-lineage.ts +55 -0
  236. package/src/lib/server/sessions/session-repository.ts +2 -2
  237. package/src/lib/server/skills/learned-skills.ts +24 -23
  238. package/src/lib/server/skills/runtime-skill-resolver.ts +2 -1
  239. package/src/lib/server/skills/skill-repository.ts +136 -13
  240. package/src/lib/server/skills/skill-suggestions.ts +25 -28
  241. package/src/lib/server/storage-normalization.test.ts +44 -267
  242. package/src/lib/server/storage-normalization.ts +75 -0
  243. package/src/lib/server/storage.ts +19 -0
  244. package/src/lib/server/structured-extract.ts +3 -14
  245. package/src/lib/server/tasks/task-followups.ts +16 -11
  246. package/src/lib/server/tasks/task-result.test.ts +25 -29
  247. package/src/lib/server/tasks/task-result.ts +5 -9
  248. package/src/lib/server/tasks/task-route-service.ts +449 -0
  249. package/src/lib/server/text-normalization.ts +41 -0
  250. package/src/lib/server/tool-planning.ts +6 -42
  251. package/src/lib/server/upload-path.ts +5 -0
  252. package/src/lib/server/working-state/extraction.ts +614 -0
  253. package/src/lib/server/working-state/normalization.ts +866 -0
  254. package/src/lib/server/working-state/prompt.ts +60 -0
  255. package/src/lib/server/working-state/repository.ts +38 -0
  256. package/src/lib/server/working-state/service.test.ts +253 -0
  257. package/src/lib/server/working-state/service.ts +293 -0
  258. package/src/lib/validation/schemas.ts +1 -0
  259. package/src/lib/ws-client.ts +3 -3
  260. package/src/stores/slices/task-slice.ts +1 -4
  261. package/src/stores/use-chatroom-store.ts +2 -2
  262. package/src/types/index.ts +277 -12
@@ -6,10 +6,8 @@ import ReactMarkdown from 'react-markdown'
6
6
  import rehypeHighlight from 'rehype-highlight'
7
7
  import remarkGfm from 'remark-gfm'
8
8
  import { toast } from 'sonner'
9
- import { api } from '@/lib/app/api-client'
10
9
  import { dedup } from '@/lib/shared-utils'
11
10
  import { useMountedRef } from '@/hooks/use-mounted-ref'
12
- import { useWs } from '@/hooks/use-ws'
13
11
  import { useAppStore } from '@/stores/use-app-store'
14
12
  import { AgentAvatar } from '@/components/agents/agent-avatar'
15
13
  import { CodeBlock } from '@/components/chat/code-block'
@@ -18,51 +16,54 @@ import type {
18
16
  Agent,
19
17
  ClawHubSkill,
20
18
  Skill,
21
- SkillCommandDispatch,
22
- SkillInvocationConfig,
23
19
  SkillSuggestion,
24
20
  } from '@/types'
21
+ import { useAgentsQuery } from '@/features/agents/queries'
22
+ import {
23
+ useApproveSkillSuggestionMutation,
24
+ useClawHubPreviewMutation,
25
+ useClawHubSearchMutation,
26
+ useDeleteSkillMutation,
27
+ useGenerateSkillSuggestionMutation,
28
+ useInstallClawHubSkillMutation,
29
+ useRejectSkillSuggestionMutation,
30
+ useSkillsQuery,
31
+ useSkillSuggestionsQuery,
32
+ type ClawHubPreview,
33
+ } from '@/features/skills/queries'
25
34
 
26
35
  type SkillScopeFilter = 'all' | 'global' | 'agent'
27
36
  type SkillSort = 'updated' | 'name'
28
37
  type HubSort = 'popular' | 'name' | 'updated'
29
38
 
30
- interface ClawHubSearchResponse {
31
- skills: ClawHubSkill[]
32
- total: number
33
- page: number
34
- nextCursor?: string | null
35
- error?: string
36
- }
37
-
38
- type ClawHubPreview = Partial<Skill> & {
39
- name: string
40
- content: string
41
- description?: string
42
- invocation?: SkillInvocationConfig | null
43
- commandDispatch?: SkillCommandDispatch | null
44
- }
45
-
46
39
  const HUB_PAGE_SIZE = 18
47
40
 
48
41
  export function SkillsWorkspace() {
49
42
  const router = useRouter()
50
43
  const searchParams = useSearchParams()
51
44
  const mountedRef = useMountedRef()
52
-
53
- const skills = useAppStore((s) => s.skills)
54
- const loadSkills = useAppStore((s) => s.loadSkills)
55
- const agents = useAppStore((s) => s.agents)
56
- const loadAgents = useAppStore((s) => s.loadAgents)
45
+ const skillsQuery = useSkillsQuery()
46
+ const skills = useMemo(() => skillsQuery.data ?? {}, [skillsQuery.data])
47
+ const agentsQuery = useAgentsQuery()
48
+ const suggestionsQuery = useSkillSuggestionsQuery()
49
+ const generateSuggestionMutation = useGenerateSkillSuggestionMutation()
50
+ const approveSuggestionMutation = useApproveSkillSuggestionMutation()
51
+ const rejectSuggestionMutation = useRejectSkillSuggestionMutation()
52
+ const clawHubSearchMutation = useClawHubSearchMutation()
53
+ const clawHubPreviewMutation = useClawHubPreviewMutation()
54
+ const installClawHubSkillMutation = useInstallClawHubSkillMutation()
55
+ const deleteSkillMutation = useDeleteSkillMutation()
57
56
  const currentAgentId = useAppStore((s) => s.currentAgentId)
58
57
  const activeProjectFilter = useAppStore((s) => s.activeProjectFilter)
59
58
  const setSkillSheetOpen = useAppStore((s) => s.setSkillSheetOpen)
60
59
  const setEditingSkillId = useAppStore((s) => s.setEditingSkillId)
61
60
 
61
+ const suggestions = suggestionsQuery.data ?? []
62
+ const agents = agentsQuery.data ?? {}
63
+
62
64
  const activeTab = searchParams.get('tab') === 'clawhub' ? 'clawhub' : 'skills'
63
65
  const selectedSkillId = activeTab === 'skills' ? searchParams.get('skill') : null
64
66
 
65
- const [ready, setReady] = useState(false)
66
67
  const [libraryQuery, setLibraryQuery] = useState('')
67
68
  const [libraryScope, setLibraryScope] = useState<SkillScopeFilter>('all')
68
69
  const [librarySort, setLibrarySort] = useState<SkillSort>('updated')
@@ -70,8 +71,6 @@ export function SkillsWorkspace() {
70
71
  const [deleteTarget, setDeleteTarget] = useState<Skill | null>(null)
71
72
  const [deletingSkillId, setDeletingSkillId] = useState<string | null>(null)
72
73
 
73
- const [suggestions, setSuggestions] = useState<SkillSuggestion[]>([])
74
- const [suggestionsLoading, setSuggestionsLoading] = useState(false)
75
74
  const [suggestionActionId, setSuggestionActionId] = useState<string | null>(null)
76
75
  const [generatingSuggestion, setGeneratingSuggestion] = useState(false)
77
76
 
@@ -93,16 +92,6 @@ export function SkillsWorkspace() {
93
92
  const [installingHubId, setInstallingHubId] = useState<string | null>(null)
94
93
  const hubSearchRequestIdRef = useRef(0)
95
94
 
96
- useEffect(() => {
97
- let active = true
98
- void Promise.all([loadSkills(), loadAgents()]).finally(() => {
99
- if (active && mountedRef.current) setReady(true)
100
- })
101
- return () => {
102
- active = false
103
- }
104
- }, [loadAgents, loadSkills, mountedRef])
105
-
106
95
  useEffect(() => {
107
96
  if (activeTab !== 'clawhub') {
108
97
  setSelectedHubSkill(null)
@@ -110,8 +99,6 @@ export function SkillsWorkspace() {
110
99
  }
111
100
  }, [activeTab])
112
101
 
113
- useWs('skills', () => { void loadSkills() })
114
-
115
102
  const skillList = useMemo(() => {
116
103
  return Object.values(skills).filter((skill) => !activeProjectFilter || skill.projectId === activeProjectFilter)
117
104
  }, [activeProjectFilter, skills])
@@ -141,26 +128,6 @@ export function SkillsWorkspace() {
141
128
  setSkillSheetOpen(true)
142
129
  }, [setEditingSkillId, setSkillSheetOpen])
143
130
 
144
- const loadSuggestions = useCallback(async () => {
145
- setSuggestionsLoading(true)
146
- try {
147
- const result = await api<SkillSuggestion[]>('GET', '/skill-suggestions')
148
- if (!mountedRef.current) return
149
- setSuggestions(Array.isArray(result) ? result : [])
150
- } catch (err) {
151
- if (!mountedRef.current) return
152
- toast.error(err instanceof Error ? err.message : 'Failed to load skill suggestions')
153
- } finally {
154
- if (mountedRef.current) setSuggestionsLoading(false)
155
- }
156
- }, [mountedRef])
157
-
158
- useEffect(() => {
159
- void loadSuggestions()
160
- }, [loadSuggestions])
161
-
162
- useWs('skill_suggestions', () => { void loadSuggestions() })
163
-
164
131
  const handleGenerateSuggestion = useCallback(async () => {
165
132
  if (!currentSessionId) {
166
133
  toast.error('Open a chat first so SwarmClaw has a session to learn from.')
@@ -168,41 +135,38 @@ export function SkillsWorkspace() {
168
135
  }
169
136
  setGeneratingSuggestion(true)
170
137
  try {
171
- await api<SkillSuggestion>('POST', '/skill-suggestions', { sessionId: currentSessionId })
138
+ await generateSuggestionMutation.mutateAsync(currentSessionId)
172
139
  toast.success('Drafted a skill suggestion from the current conversation.')
173
- await loadSuggestions()
174
140
  } catch (err) {
175
141
  toast.error(err instanceof Error ? err.message : 'Failed to generate a skill suggestion')
176
142
  } finally {
177
143
  if (mountedRef.current) setGeneratingSuggestion(false)
178
144
  }
179
- }, [currentSessionId, loadSuggestions, mountedRef])
145
+ }, [currentSessionId, generateSuggestionMutation, mountedRef])
180
146
 
181
147
  const handleApproveSuggestion = useCallback(async (id: string) => {
182
148
  setSuggestionActionId(id)
183
149
  try {
184
- await api('POST', `/skill-suggestions/${id}/approve`)
150
+ await approveSuggestionMutation.mutateAsync(id)
185
151
  toast.success('Skill suggestion approved and saved.')
186
- await Promise.all([loadSuggestions(), loadSkills()])
187
152
  } catch (err) {
188
153
  toast.error(err instanceof Error ? err.message : 'Failed to approve the skill suggestion')
189
154
  } finally {
190
155
  if (mountedRef.current) setSuggestionActionId(null)
191
156
  }
192
- }, [loadSkills, loadSuggestions, mountedRef])
157
+ }, [approveSuggestionMutation, mountedRef])
193
158
 
194
159
  const handleRejectSuggestion = useCallback(async (id: string) => {
195
160
  setSuggestionActionId(id)
196
161
  try {
197
- await api('POST', `/skill-suggestions/${id}/reject`)
162
+ await rejectSuggestionMutation.mutateAsync(id)
198
163
  toast.success('Skill suggestion dismissed.')
199
- await loadSuggestions()
200
164
  } catch (err) {
201
165
  toast.error(err instanceof Error ? err.message : 'Failed to dismiss the skill suggestion')
202
166
  } finally {
203
167
  if (mountedRef.current) setSuggestionActionId(null)
204
168
  }
205
- }, [loadSuggestions, mountedRef])
169
+ }, [mountedRef, rejectSuggestionMutation])
206
170
 
207
171
  const searchHub = useCallback(async (query: string, page: number, append = false, cursor?: string | null) => {
208
172
  const requestId = hubSearchRequestIdRef.current + 1
@@ -211,13 +175,12 @@ export function SkillsWorkspace() {
211
175
  setHubError(null)
212
176
 
213
177
  try {
214
- const params = new URLSearchParams({
215
- q: query,
216
- page: String(page),
217
- limit: String(HUB_PAGE_SIZE),
178
+ const response = await clawHubSearchMutation.mutateAsync({
179
+ query,
180
+ page,
181
+ limit: HUB_PAGE_SIZE,
182
+ cursor,
218
183
  })
219
- if (cursor) params.set('cursor', cursor)
220
- const response = await api<ClawHubSearchResponse>('GET', `/clawhub/search?${params.toString()}`)
221
184
  if (!mountedRef.current || requestId !== hubSearchRequestIdRef.current) return
222
185
 
223
186
  if (response.error) setHubError(response.error)
@@ -233,7 +196,7 @@ export function SkillsWorkspace() {
233
196
  } finally {
234
197
  if (mountedRef.current && requestId === hubSearchRequestIdRef.current) setHubLoading(false)
235
198
  }
236
- }, [mountedRef])
199
+ }, [clawHubSearchMutation, mountedRef])
237
200
 
238
201
  useEffect(() => {
239
202
  if (activeTab !== 'clawhub' || selectedHubSkill) return
@@ -252,7 +215,7 @@ export function SkillsWorkspace() {
252
215
  setHubPreviewLoadingId(selectedHubSkill.id)
253
216
  setHubPreviewError(null)
254
217
 
255
- void api<ClawHubPreview>('POST', '/clawhub/preview', {
218
+ void clawHubPreviewMutation.mutateAsync({
256
219
  name: selectedHubSkill.name,
257
220
  description: selectedHubSkill.description,
258
221
  author: selectedHubSkill.author,
@@ -271,7 +234,7 @@ export function SkillsWorkspace() {
271
234
  return () => {
272
235
  active = false
273
236
  }
274
- }, [hubPreviewCache, mountedRef, selectedHubSkill])
237
+ }, [clawHubPreviewMutation, hubPreviewCache, mountedRef, selectedHubSkill])
275
238
 
276
239
  const installedHubIds = useMemo(() => {
277
240
  const ids = new Set<string>()
@@ -335,7 +298,7 @@ export function SkillsWorkspace() {
335
298
  const handleInstallHubSkill = useCallback(async (skill: ClawHubSkill) => {
336
299
  setInstallingHubId(skill.id)
337
300
  try {
338
- await api('POST', '/clawhub/install', {
301
+ await installClawHubSkillMutation.mutateAsync({
339
302
  name: skill.name,
340
303
  description: skill.description,
341
304
  url: skill.url,
@@ -344,21 +307,19 @@ export function SkillsWorkspace() {
344
307
  content: hubPreviewCache[skill.id]?.content,
345
308
  })
346
309
  toast.success(`Installed "${skill.name}"`)
347
- await loadSkills()
348
310
  } catch (err) {
349
311
  toast.error(err instanceof Error ? err.message : 'Install failed')
350
312
  } finally {
351
313
  if (mountedRef.current) setInstallingHubId(null)
352
314
  }
353
- }, [hubPreviewCache, loadSkills, mountedRef])
315
+ }, [hubPreviewCache, installClawHubSkillMutation, mountedRef])
354
316
 
355
317
  const confirmDeleteSkill = useCallback(async () => {
356
318
  if (!deleteTarget) return
357
319
  setDeletingSkillId(deleteTarget.id)
358
320
  try {
359
- await api('DELETE', `/skills/${deleteTarget.id}`)
321
+ await deleteSkillMutation.mutateAsync(deleteTarget.id)
360
322
  toast.success('Skill deleted')
361
- await loadSkills()
362
323
  if (selectedSkillId === deleteTarget.id) {
363
324
  setPageState({ skill: null }, 'replace')
364
325
  }
@@ -368,9 +329,9 @@ export function SkillsWorkspace() {
368
329
  } finally {
369
330
  if (mountedRef.current) setDeletingSkillId(null)
370
331
  }
371
- }, [deleteTarget, loadSkills, mountedRef, selectedSkillId, setPageState])
332
+ }, [deleteSkillMutation, deleteTarget, mountedRef, selectedSkillId, setPageState])
372
333
 
373
- if (!ready) {
334
+ if (skillsQuery.isPending || agentsQuery.isPending) {
374
335
  return (
375
336
  <div className="flex-1 flex items-center justify-center px-6">
376
337
  <div className="flex items-center gap-3 text-[13px] text-text-3/65">
@@ -573,10 +534,10 @@ export function SkillsWorkspace() {
573
534
  </div>
574
535
  )}
575
536
 
576
- {(suggestionsLoading || draftCount > 0) ? (
537
+ {(suggestionsQuery.isPending || draftCount > 0) ? (
577
538
  <SuggestionsPanel
578
539
  suggestions={suggestions}
579
- loading={suggestionsLoading}
540
+ loading={suggestionsQuery.isPending}
580
541
  busyId={suggestionActionId}
581
542
  onApprove={handleApproveSuggestion}
582
543
  onReject={handleRejectSuggestion}
@@ -4,30 +4,40 @@ import { useState, useCallback, useEffect } from 'react'
4
4
  import { useRouter } from 'next/navigation'
5
5
  import { useAppStore } from '@/stores/use-app-store'
6
6
  import { getMissionPath, useNavigate } from '@/lib/app/navigation'
7
- import { updateTask, archiveTask } from '@/lib/tasks'
7
+ import { useUpdateTaskMutation } from '@/features/tasks/queries'
8
8
  import { ConfirmDialog } from '@/components/shared/confirm-dialog'
9
9
  import { AgentAvatar } from '@/components/agents/agent-avatar'
10
10
  import { timeAgo } from '@/lib/time-format'
11
11
  import { InfoChip } from '@/components/ui/info-chip'
12
- import type { BoardTask } from '@/types'
12
+ import type { Agent, BoardTask, Project } from '@/types'
13
13
 
14
14
  interface TaskCardProps {
15
15
  task: BoardTask
16
+ agents: Record<string, Agent>
17
+ projects: Record<string, Project>
18
+ tasksById: Record<string, BoardTask>
16
19
  selectionMode?: boolean
17
20
  selected?: boolean
18
21
  onToggleSelect?: (id: string) => void
19
22
  index?: number
20
23
  }
21
24
 
22
- export function TaskCard({ task, selectionMode, selected, onToggleSelect, index = 0 }: TaskCardProps) {
23
- const agents = useAppStore((s) => s.agents)
24
- const projects = useAppStore((s) => s.projects)
25
+ export function TaskCard({
26
+ task,
27
+ agents,
28
+ projects,
29
+ tasksById,
30
+ selectionMode,
31
+ selected,
32
+ onToggleSelect,
33
+ index = 0,
34
+ }: TaskCardProps) {
25
35
  const setEditingTaskId = useAppStore((s) => s.setEditingTaskId)
26
36
  const setTaskSheetOpen = useAppStore((s) => s.setTaskSheetOpen)
27
- const loadTasks = useAppStore((s) => s.loadTasks)
28
37
  const setCurrentAgent = useAppStore((s) => s.setCurrentAgent)
29
38
  const navigateTo = useNavigate()
30
39
  const router = useRouter()
40
+ const updateTaskMutation = useUpdateTaskMutation()
31
41
  const [dragging, setDragging] = useState(false)
32
42
  const [confirmArchive, setConfirmArchive] = useState(false)
33
43
  const [allowDrag, setAllowDrag] = useState(false)
@@ -48,7 +58,6 @@ export function TaskCard({ task, selectionMode, selected, onToggleSelect, index
48
58
  }
49
59
  }, [])
50
60
 
51
- const tasks = useAppStore((s) => s.tasks)
52
61
  const agent = agents[task.agentId]
53
62
  const project = task.projectId ? projects[task.projectId] : null
54
63
  const creatorAgent = task.createdByAgentId ? agents[task.createdByAgentId] : null
@@ -78,14 +87,12 @@ export function TaskCard({ task, selectionMode, selected, onToggleSelect, index
78
87
 
79
88
  const handleQueue = async (e: React.MouseEvent) => {
80
89
  e.stopPropagation()
81
- await updateTask(task.id, { status: 'queued' })
82
- await loadTasks()
90
+ await updateTaskMutation.mutateAsync({ id: task.id, patch: { status: 'queued' } })
83
91
  }
84
92
 
85
93
  const handleArchive = async (e: React.MouseEvent) => {
86
94
  e.stopPropagation()
87
- await archiveTask(task.id)
88
- await loadTasks()
95
+ await updateTaskMutation.mutateAsync({ id: task.id, patch: { status: 'archived' } })
89
96
  }
90
97
 
91
98
  const handleViewSession = (e: React.MouseEvent) => {
@@ -147,7 +154,7 @@ export function TaskCard({ task, selectionMode, selected, onToggleSelect, index
147
154
  )}
148
155
  {isBlocked && (
149
156
  <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" className="text-rose-400 shrink-0 mt-0.5">
150
- <title>{`Blocked by: ${(task.blockedBy || []).map((bid) => tasks[bid]?.title || bid).join(', ')}`}</title>
157
+ <title>{`Blocked by: ${(task.blockedBy || []).map((bid) => tasksById[bid]?.title || bid).join(', ')}`}</title>
151
158
  <rect x="3" y="11" width="18" height="11" rx="2" /><path d="M7 11V7a5 5 0 0 1 10 0v4" />
152
159
  </svg>
153
160
  )}
@@ -325,7 +332,7 @@ export function TaskCard({ task, selectionMode, selected, onToggleSelect, index
325
332
  {Array.isArray(task.blocks) && task.blocks.length > 0 && (
326
333
  <span
327
334
  className="px-1.5 py-0.5 rounded-[5px] bg-amber-500/10 text-amber-400 text-[10px] font-600"
328
- title={`Blocks: ${task.blocks.map((bid) => tasks[bid]?.title || bid).join(', ')}`}
335
+ title={`Blocks: ${task.blocks.map((bid) => tasksById[bid]?.title || bid).join(', ')}`}
329
336
  >
330
337
  blocks {task.blocks.length}
331
338
  </span>
@@ -2,9 +2,8 @@
2
2
 
3
3
  import { useState, useCallback } from 'react'
4
4
  import { TaskCard } from './task-card'
5
- import { createTask } from '@/lib/tasks'
6
- import { useAppStore } from '@/stores/use-app-store'
7
- import type { BoardTask, BoardTaskStatus } from '@/types'
5
+ import { useCreateTaskMutation } from '@/features/tasks/queries'
6
+ import type { Agent, BoardTask, BoardTaskStatus, Project } from '@/types'
8
7
 
9
8
  const COLUMN_CONFIG: Record<BoardTaskStatus, { label: string; color: string; dot: string }> = {
10
9
  backlog: { label: 'Backlog', color: 'text-text-3', dot: 'bg-white/20' },
@@ -20,6 +19,9 @@ const COLUMN_CONFIG: Record<BoardTaskStatus, { label: string; color: string; dot
20
19
  interface Props {
21
20
  status: BoardTaskStatus
22
21
  tasks: BoardTask[]
22
+ agents: Record<string, Agent>
23
+ projects: Record<string, Project>
24
+ tasksById: Record<string, BoardTask>
23
25
  onDrop: (taskId: string, newStatus: BoardTaskStatus) => void
24
26
  selectionMode?: boolean
25
27
  selectedIds?: Set<string>
@@ -27,12 +29,23 @@ interface Props {
27
29
  onSelectAll?: () => void
28
30
  }
29
31
 
30
- export function TaskColumn({ status, tasks, onDrop, selectionMode, selectedIds, onToggleSelect, onSelectAll }: Props) {
32
+ export function TaskColumn({
33
+ status,
34
+ tasks,
35
+ agents,
36
+ projects,
37
+ tasksById,
38
+ onDrop,
39
+ selectionMode,
40
+ selectedIds,
41
+ onToggleSelect,
42
+ onSelectAll,
43
+ }: Props) {
31
44
  const config = COLUMN_CONFIG[status]
32
45
  const [dragOver, setDragOver] = useState(false)
33
46
  const [quickAddValue, setQuickAddValue] = useState('')
34
47
  const [adding, setAdding] = useState(false)
35
- const loadTasks = useAppStore((s) => s.loadTasks)
48
+ const createTaskMutation = useCreateTaskMutation()
36
49
 
37
50
  const handleDragOver = useCallback((e: React.DragEvent) => {
38
51
  e.preventDefault()
@@ -58,8 +71,7 @@ export function TaskColumn({ status, tasks, onDrop, selectionMode, selectedIds,
58
71
  if (!title || adding) return
59
72
  setAdding(true)
60
73
  try {
61
- await createTask({ title, description: '', agentId: '', status })
62
- await loadTasks()
74
+ await createTaskMutation.mutateAsync({ title, description: '', agentId: '', status })
63
75
  setQuickAddValue('')
64
76
  } finally {
65
77
  setAdding(false)
@@ -116,6 +128,9 @@ export function TaskColumn({ status, tasks, onDrop, selectionMode, selectedIds,
116
128
  <TaskCard
117
129
  key={task.id}
118
130
  task={task}
131
+ agents={agents}
132
+ projects={projects}
133
+ tasksById={tasksById}
119
134
  index={idx}
120
135
  selectionMode={selectionMode}
121
136
  selected={selectedIds?.has(task.id)}
@@ -1,9 +1,9 @@
1
1
  'use client'
2
2
 
3
- import { useEffect, useMemo, useState } from 'react'
3
+ import { useMemo, useState } from 'react'
4
4
  import { useAppStore } from '@/stores/use-app-store'
5
- import { useWs } from '@/hooks/use-ws'
6
- import { api } from '@/lib/app/api-client'
5
+ import { useAgentsQuery } from '@/features/agents/queries'
6
+ import { useClearDoneTasksMutation, useTasksQuery } from '@/features/tasks/queries'
7
7
  import type { BoardTaskStatus } from '@/types'
8
8
  import { EmptyState } from '@/components/shared/empty-state'
9
9
  import { SearchInput } from '@/components/ui/search-input'
@@ -20,20 +20,18 @@ const STATUS_DOT: Record<BoardTaskStatus, string> = {
20
20
  }
21
21
 
22
22
  export function TaskList({ inSidebar }: { inSidebar?: boolean }) {
23
- const tasks = useAppStore((s) => s.tasks)
24
- const loadTasks = useAppStore((s) => s.loadTasks)
25
- const agents = useAppStore((s) => s.agents)
26
23
  const setEditingTaskId = useAppStore((s) => s.setEditingTaskId)
27
24
  const setTaskSheetOpen = useAppStore((s) => s.setTaskSheetOpen)
28
25
  const activeProjectFilter = useAppStore((s) => s.activeProjectFilter)
26
+ const { data: tasks = {} } = useTasksQuery({ includeArchived: true })
27
+ const { data: agents = {} } = useAgentsQuery()
28
+ const clearDoneMutation = useClearDoneTasksMutation()
29
29
  const [search, setSearch] = useState('')
30
30
  const [clearing, setClearing] = useState(false)
31
31
 
32
- useEffect(() => { loadTasks() }, [loadTasks])
33
- useWs('tasks', loadTasks, 5000)
34
-
35
32
  const sorted = useMemo(() =>
36
33
  Object.values(tasks)
34
+ .filter((t) => t.status !== 'archived')
37
35
  .filter((t) => !activeProjectFilter || t.projectId === activeProjectFilter)
38
36
  .sort((a, b) => b.updatedAt - a.updatedAt),
39
37
  [tasks, activeProjectFilter],
@@ -58,8 +56,7 @@ export function TaskList({ inSidebar }: { inSidebar?: boolean }) {
58
56
  const handleClearDone = async () => {
59
57
  setClearing(true)
60
58
  try {
61
- await api('DELETE', '/tasks?filter=done')
62
- await loadTasks()
59
+ await clearDoneMutation.mutateAsync()
63
60
  } catch { /* silent */ }
64
61
  setClearing(false)
65
62
  }