@swarmclawai/swarmclaw 0.5.2 → 0.6.0

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 (173) hide show
  1. package/README.md +42 -7
  2. package/bin/swarmclaw.js +76 -16
  3. package/next.config.ts +11 -1
  4. package/package.json +4 -2
  5. package/public/screenshots/agents.png +0 -0
  6. package/public/screenshots/dashboard.png +0 -0
  7. package/public/screenshots/providers.png +0 -0
  8. package/public/screenshots/tasks.png +0 -0
  9. package/scripts/postinstall.mjs +18 -0
  10. package/src/app/api/chatrooms/[id]/chat/route.ts +410 -0
  11. package/src/app/api/chatrooms/[id]/members/route.ts +82 -0
  12. package/src/app/api/chatrooms/[id]/pins/route.ts +39 -0
  13. package/src/app/api/chatrooms/[id]/reactions/route.ts +42 -0
  14. package/src/app/api/chatrooms/[id]/route.ts +84 -0
  15. package/src/app/api/chatrooms/route.ts +50 -0
  16. package/src/app/api/credentials/route.ts +2 -3
  17. package/src/app/api/knowledge/[id]/route.ts +13 -2
  18. package/src/app/api/knowledge/route.ts +8 -1
  19. package/src/app/api/memory/route.ts +8 -0
  20. package/src/app/api/notifications/[id]/route.ts +27 -0
  21. package/src/app/api/notifications/route.ts +68 -0
  22. package/src/app/api/orchestrator/run/route.ts +1 -1
  23. package/src/app/api/plugins/install/route.ts +2 -2
  24. package/src/app/api/search/route.ts +155 -0
  25. package/src/app/api/sessions/[id]/chat/route.ts +2 -0
  26. package/src/app/api/sessions/[id]/edit-resend/route.ts +1 -1
  27. package/src/app/api/sessions/[id]/fork/route.ts +1 -1
  28. package/src/app/api/sessions/route.ts +3 -3
  29. package/src/app/api/settings/route.ts +9 -0
  30. package/src/app/api/setup/check-provider/route.ts +3 -16
  31. package/src/app/api/skills/[id]/route.ts +6 -0
  32. package/src/app/api/skills/route.ts +6 -0
  33. package/src/app/api/tasks/[id]/route.ts +20 -0
  34. package/src/app/api/tasks/bulk/route.ts +100 -0
  35. package/src/app/api/tasks/route.ts +1 -0
  36. package/src/app/api/usage/route.ts +45 -0
  37. package/src/app/api/webhooks/[id]/route.ts +15 -1
  38. package/src/app/globals.css +58 -15
  39. package/src/app/page.tsx +142 -13
  40. package/src/cli/index.js +42 -0
  41. package/src/cli/index.test.js +30 -0
  42. package/src/cli/spec.js +32 -0
  43. package/src/components/agents/agent-avatar.tsx +57 -10
  44. package/src/components/agents/agent-card.tsx +48 -15
  45. package/src/components/agents/agent-chat-list.tsx +123 -10
  46. package/src/components/agents/agent-list.tsx +50 -19
  47. package/src/components/agents/agent-sheet.tsx +56 -63
  48. package/src/components/auth/access-key-gate.tsx +10 -3
  49. package/src/components/auth/setup-wizard.tsx +2 -2
  50. package/src/components/auth/user-picker.tsx +31 -3
  51. package/src/components/chat/activity-moment.tsx +169 -0
  52. package/src/components/chat/chat-header.tsx +2 -0
  53. package/src/components/chat/chat-tool-toggles.tsx +1 -1
  54. package/src/components/chat/file-path-chip.tsx +125 -0
  55. package/src/components/chat/markdown-utils.ts +9 -0
  56. package/src/components/chat/message-bubble.tsx +46 -295
  57. package/src/components/chat/message-list.tsx +50 -1
  58. package/src/components/chat/streaming-bubble.tsx +36 -46
  59. package/src/components/chat/suggestions-bar.tsx +1 -1
  60. package/src/components/chat/thinking-indicator.tsx +72 -10
  61. package/src/components/chat/tool-call-bubble.tsx +66 -70
  62. package/src/components/chat/tool-request-banner.tsx +31 -7
  63. package/src/components/chat/transfer-agent-picker.tsx +63 -0
  64. package/src/components/chatrooms/agent-hover-card.tsx +124 -0
  65. package/src/components/chatrooms/chatroom-input.tsx +320 -0
  66. package/src/components/chatrooms/chatroom-list.tsx +123 -0
  67. package/src/components/chatrooms/chatroom-message.tsx +427 -0
  68. package/src/components/chatrooms/chatroom-sheet.tsx +215 -0
  69. package/src/components/chatrooms/chatroom-tool-request-banner.tsx +134 -0
  70. package/src/components/chatrooms/chatroom-typing-bar.tsx +88 -0
  71. package/src/components/chatrooms/chatroom-view.tsx +344 -0
  72. package/src/components/chatrooms/reaction-picker.tsx +273 -0
  73. package/src/components/connectors/connector-sheet.tsx +34 -47
  74. package/src/components/home/home-view.tsx +501 -0
  75. package/src/components/input/chat-input.tsx +79 -41
  76. package/src/components/knowledge/knowledge-list.tsx +31 -1
  77. package/src/components/knowledge/knowledge-sheet.tsx +83 -2
  78. package/src/components/layout/app-layout.tsx +209 -83
  79. package/src/components/layout/mobile-header.tsx +2 -0
  80. package/src/components/layout/update-banner.tsx +2 -2
  81. package/src/components/logs/log-list.tsx +2 -2
  82. package/src/components/mcp-servers/mcp-server-sheet.tsx +1 -1
  83. package/src/components/memory/memory-agent-list.tsx +143 -0
  84. package/src/components/memory/memory-browser.tsx +205 -0
  85. package/src/components/memory/memory-card.tsx +34 -7
  86. package/src/components/memory/memory-detail.tsx +359 -120
  87. package/src/components/memory/memory-sheet.tsx +157 -23
  88. package/src/components/plugins/plugin-list.tsx +1 -1
  89. package/src/components/plugins/plugin-sheet.tsx +1 -1
  90. package/src/components/projects/project-detail.tsx +509 -0
  91. package/src/components/projects/project-list.tsx +195 -59
  92. package/src/components/providers/provider-list.tsx +2 -2
  93. package/src/components/providers/provider-sheet.tsx +3 -3
  94. package/src/components/schedules/schedule-card.tsx +3 -2
  95. package/src/components/schedules/schedule-list.tsx +1 -1
  96. package/src/components/schedules/schedule-sheet.tsx +25 -25
  97. package/src/components/secrets/secret-sheet.tsx +47 -24
  98. package/src/components/secrets/secrets-list.tsx +18 -8
  99. package/src/components/sessions/new-session-sheet.tsx +33 -65
  100. package/src/components/sessions/session-card.tsx +45 -14
  101. package/src/components/sessions/session-list.tsx +35 -18
  102. package/src/components/shared/agent-picker-list.tsx +90 -0
  103. package/src/components/shared/agent-switch-dialog.tsx +156 -0
  104. package/src/components/shared/attachment-chip.tsx +165 -0
  105. package/src/components/shared/avatar.tsx +10 -1
  106. package/src/components/shared/check-icon.tsx +12 -0
  107. package/src/components/shared/confirm-dialog.tsx +1 -1
  108. package/src/components/shared/empty-state.tsx +32 -0
  109. package/src/components/shared/file-preview.tsx +34 -0
  110. package/src/components/shared/form-styles.ts +2 -0
  111. package/src/components/shared/keyboard-shortcuts-dialog.tsx +116 -0
  112. package/src/components/shared/notification-center.tsx +223 -0
  113. package/src/components/shared/profile-sheet.tsx +115 -0
  114. package/src/components/shared/reply-quote.tsx +26 -0
  115. package/src/components/shared/search-dialog.tsx +296 -0
  116. package/src/components/shared/section-label.tsx +12 -0
  117. package/src/components/shared/settings/plugin-manager.tsx +1 -1
  118. package/src/components/shared/settings/section-providers.tsx +1 -1
  119. package/src/components/shared/settings/section-secrets.tsx +1 -1
  120. package/src/components/shared/settings/section-theme.tsx +95 -0
  121. package/src/components/shared/settings/section-user-preferences.tsx +39 -0
  122. package/src/components/shared/settings/settings-page.tsx +180 -27
  123. package/src/components/shared/settings/settings-sheet.tsx +9 -73
  124. package/src/components/shared/sheet-footer.tsx +33 -0
  125. package/src/components/skills/skill-list.tsx +61 -30
  126. package/src/components/skills/skill-sheet.tsx +81 -2
  127. package/src/components/tasks/task-board.tsx +448 -26
  128. package/src/components/tasks/task-card.tsx +46 -9
  129. package/src/components/tasks/task-column.tsx +62 -3
  130. package/src/components/tasks/task-list.tsx +12 -4
  131. package/src/components/tasks/task-sheet.tsx +89 -72
  132. package/src/components/ui/hover-card.tsx +52 -0
  133. package/src/components/usage/metrics-dashboard.tsx +78 -0
  134. package/src/components/usage/usage-list.tsx +1 -1
  135. package/src/components/webhooks/webhook-sheet.tsx +1 -1
  136. package/src/hooks/use-view-router.ts +69 -19
  137. package/src/instrumentation.ts +15 -1
  138. package/src/lib/chat.ts +2 -0
  139. package/src/lib/cron-human.ts +114 -0
  140. package/src/lib/memory.ts +3 -0
  141. package/src/lib/server/chat-execution.ts +24 -4
  142. package/src/lib/server/connectors/manager.ts +11 -0
  143. package/src/lib/server/context-manager.ts +225 -13
  144. package/src/lib/server/create-notification.ts +42 -0
  145. package/src/lib/server/daemon-state.ts +165 -10
  146. package/src/lib/server/execution-log.ts +1 -0
  147. package/src/lib/server/heartbeat-service.ts +40 -5
  148. package/src/lib/server/heartbeat-wake.ts +110 -0
  149. package/src/lib/server/langgraph-checkpoint.ts +1 -0
  150. package/src/lib/server/memory-consolidation.ts +92 -0
  151. package/src/lib/server/memory-db.ts +51 -6
  152. package/src/lib/server/openclaw-gateway.ts +9 -1
  153. package/src/lib/server/provider-health.ts +125 -0
  154. package/src/lib/server/queue.ts +5 -4
  155. package/src/lib/server/scheduler.ts +8 -0
  156. package/src/lib/server/session-run-manager.ts +4 -0
  157. package/src/lib/server/session-tools/chatroom.ts +136 -0
  158. package/src/lib/server/session-tools/context-mgmt.ts +36 -18
  159. package/src/lib/server/session-tools/index.ts +2 -0
  160. package/src/lib/server/session-tools/memory.ts +6 -1
  161. package/src/lib/server/storage.ts +80 -29
  162. package/src/lib/server/stream-agent-chat.ts +153 -47
  163. package/src/lib/server/system-events.ts +49 -0
  164. package/src/lib/server/ws-hub.ts +11 -0
  165. package/src/lib/soul-suggestions.ts +109 -0
  166. package/src/lib/tasks.ts +4 -1
  167. package/src/lib/view-routes.ts +36 -1
  168. package/src/lib/ws-client.ts +14 -4
  169. package/src/proxy.ts +79 -2
  170. package/src/stores/use-app-store.ts +94 -3
  171. package/src/stores/use-chat-store.ts +48 -3
  172. package/src/stores/use-chatroom-store.ts +276 -0
  173. package/src/types/index.ts +69 -2
@@ -4,6 +4,7 @@ import { useCallback, useEffect, useMemo, useRef, useState } from 'react'
4
4
  import { api } from '@/lib/api-client'
5
5
  import { useAppStore } from '@/stores/use-app-store'
6
6
  import { Badge } from '@/components/ui/badge'
7
+ import { AgentAvatar } from '@/components/agents/agent-avatar'
7
8
  import type { MemoryEntry } from '@/types'
8
9
 
9
10
  export function KnowledgeList() {
@@ -13,6 +14,8 @@ export function KnowledgeList() {
13
14
  const [error, setError] = useState<string | null>(null)
14
15
  const [activeTag, setActiveTag] = useState<string | null>(null)
15
16
  const searchRef = useRef(search)
17
+ const agents = useAppStore((s) => s.agents)
18
+ const loadAgents = useAppStore((s) => s.loadAgents)
16
19
  const setKnowledgeSheetOpen = useAppStore((s) => s.setKnowledgeSheetOpen)
17
20
  const setEditingKnowledgeId = useAppStore((s) => s.setEditingKnowledgeId)
18
21
 
@@ -40,8 +43,10 @@ export function KnowledgeList() {
40
43
 
41
44
  // Initial load
42
45
  useEffect(() => {
46
+ loadAgents()
43
47
  const timer = setTimeout(() => { void load(searchRef.current, activeTag) }, 0)
44
48
  return () => clearTimeout(timer)
49
+ // eslint-disable-next-line react-hooks/exhaustive-deps
45
50
  }, [load, activeTag])
46
51
 
47
52
  // Debounced search
@@ -120,8 +125,14 @@ export function KnowledgeList() {
120
125
  {entries.length > 0 ? (
121
126
  <div className="grid grid-cols-1 md:grid-cols-2 gap-3 px-5 pb-6">
122
127
  {entries.map((entry) => {
123
- const meta = entry.metadata as { tags?: string[] } | undefined
128
+ const meta = entry.metadata as { tags?: string[]; scope?: 'global' | 'agent'; agentIds?: string[] } | undefined
124
129
  const tags = meta?.tags || []
130
+ const entryScope = meta?.scope || 'global'
131
+ const entryAgentIds = meta?.agentIds || []
132
+ const scopeLabel = entryScope === 'global' ? 'Global' : `${entryAgentIds.length} agent(s)`
133
+ const scopedAgents = entryScope === 'agent'
134
+ ? entryAgentIds.map((id) => agents[id]).filter(Boolean)
135
+ : []
125
136
  return (
126
137
  <div
127
138
  key={entry.id}
@@ -162,6 +173,25 @@ export function KnowledgeList() {
162
173
  ))}
163
174
  </div>
164
175
  )}
176
+ <div className="flex items-center gap-2 mt-1.5">
177
+ <span className={`text-[10px] font-600 ${
178
+ entryScope === 'global' ? 'text-emerald-400' : 'text-amber-400'
179
+ }`}>
180
+ {scopeLabel}
181
+ </span>
182
+ {scopedAgents.length > 0 && (
183
+ <div className="flex items-center gap-1.5">
184
+ <div className="flex items-center -space-x-1.5">
185
+ {scopedAgents.slice(0, 5).map((agent) => (
186
+ <AgentAvatar key={agent.id} seed={agent.avatarSeed} name={agent.name} size={16} className="ring-1 ring-surface" />
187
+ ))}
188
+ </div>
189
+ {scopedAgents.length > 5 && (
190
+ <span className="text-[10px] font-600 text-text-3/60 ml-0.5">+{scopedAgents.length - 5}</span>
191
+ )}
192
+ </div>
193
+ )}
194
+ </div>
165
195
  </div>
166
196
  )
167
197
  })}
@@ -4,6 +4,7 @@ import { useCallback, useEffect, useRef, useState } from 'react'
4
4
  import { api } from '@/lib/api-client'
5
5
  import { useAppStore } from '@/stores/use-app-store'
6
6
  import { BottomSheet } from '@/components/shared/bottom-sheet'
7
+ import { AgentAvatar } from '@/components/agents/agent-avatar'
7
8
  import type { MemoryEntry } from '@/types'
8
9
 
9
10
  const ACCEPTED_TYPES = '.txt,.md,.csv,.json,.jsonl,.html,.xml,.yaml,.yml,.toml,.py,.js,.ts,.tsx,.jsx,.go,.rs,.java,.c,.cpp,.h,.rb,.php,.sh,.sql,.log,.pdf'
@@ -21,16 +22,26 @@ export function KnowledgeSheet() {
21
22
  const open = useAppStore((s) => s.knowledgeSheetOpen)
22
23
  const setOpen = useAppStore((s) => s.setKnowledgeSheetOpen)
23
24
  const editingId = useAppStore((s) => s.editingKnowledgeId)
25
+ const agents = useAppStore((s) => s.agents)
26
+ const loadAgents = useAppStore((s) => s.loadAgents)
24
27
 
25
28
  const [title, setTitle] = useState('')
26
29
  const [content, setContent] = useState('')
27
30
  const [tags, setTags] = useState('')
31
+ const [scope, setScope] = useState<'global' | 'agent'>('global')
32
+ const [agentIds, setAgentIds] = useState<string[]>([])
28
33
  const [saving, setSaving] = useState(false)
29
34
  const [uploadedFile, setUploadedFile] = useState<{ name: string; url: string; size: number } | null>(null)
30
35
  const [uploading, setUploading] = useState(false)
31
36
  const [isDragging, setIsDragging] = useState(false)
32
37
  const dragCounter = useRef(0)
33
38
  const fileInputRef = useRef<HTMLInputElement>(null)
39
+ const agentList = Object.values(agents)
40
+
41
+ useEffect(() => {
42
+ if (open) loadAgents()
43
+ // eslint-disable-next-line react-hooks/exhaustive-deps
44
+ }, [open])
34
45
 
35
46
  useEffect(() => {
36
47
  if (!open) return
@@ -38,8 +49,10 @@ export function KnowledgeSheet() {
38
49
  void api<MemoryEntry>('GET', `/knowledge/${editingId}`).then((entry) => {
39
50
  setTitle(entry.title)
40
51
  setContent(entry.content)
41
- const meta = entry.metadata as { tags?: string[] } | undefined
52
+ const meta = entry.metadata as { tags?: string[]; scope?: 'global' | 'agent'; agentIds?: string[] } | undefined
42
53
  setTags(meta?.tags?.join(', ') || '')
54
+ setScope(meta?.scope || 'global')
55
+ setAgentIds(meta?.agentIds || [])
43
56
  }).catch(() => {
44
57
  setOpen(false)
45
58
  })
@@ -47,6 +60,8 @@ export function KnowledgeSheet() {
47
60
  setTitle('')
48
61
  setContent('')
49
62
  setTags('')
63
+ setScope('global')
64
+ setAgentIds([])
50
65
  setUploadedFile(null)
51
66
  }
52
67
  }, [open, editingId, setOpen])
@@ -56,6 +71,8 @@ export function KnowledgeSheet() {
56
71
  setTitle('')
57
72
  setContent('')
58
73
  setTags('')
74
+ setScope('global')
75
+ setAgentIds([])
59
76
  setUploadedFile(null)
60
77
  setIsDragging(false)
61
78
  dragCounter.current = 0
@@ -128,6 +145,16 @@ export function KnowledgeSheet() {
128
145
  if (file) void handleUpload(file)
129
146
  }, [handleUpload])
130
147
 
148
+ const toggleAgent = (id: string) => {
149
+ setAgentIds((prev) => prev.includes(id) ? prev.filter((x) => x !== id) : [...prev, id])
150
+ }
151
+
152
+ const scopeHelperText = scope === 'global'
153
+ ? 'This knowledge will be accessible to all agents'
154
+ : agentIds.length === 0
155
+ ? 'Select which agents can access this knowledge'
156
+ : `${agentIds.length} agent(s) selected`
157
+
131
158
  const handleSave = async () => {
132
159
  setSaving(true)
133
160
  try {
@@ -135,6 +162,8 @@ export function KnowledgeSheet() {
135
162
  title: title.trim() || 'Untitled',
136
163
  content,
137
164
  tags: parseTags(tags),
165
+ scope,
166
+ agentIds: scope === 'agent' ? agentIds : [],
138
167
  }
139
168
 
140
169
  if (editingId) {
@@ -294,6 +323,58 @@ export function KnowledgeSheet() {
294
323
  />
295
324
  </div>
296
325
 
326
+ <div className="mb-8">
327
+ <label className="block font-display text-[12px] font-600 text-text-2 uppercase tracking-[0.08em] mb-3">Scope</label>
328
+ <div className="flex p-1 rounded-[12px] bg-bg border border-white/[0.06]">
329
+ {(['global', 'agent'] as const).map((s) => (
330
+ <button
331
+ key={s}
332
+ onClick={() => setScope(s)}
333
+ className={`flex-1 py-2.5 rounded-[10px] text-center cursor-pointer transition-all text-[13px] font-600 border-none ${
334
+ scope === s ? 'bg-accent-soft text-accent-bright' : 'bg-transparent text-text-3 hover:text-text-2'
335
+ }`}
336
+ style={{ fontFamily: 'inherit' }}
337
+ >
338
+ {s === 'global' ? 'Global' : 'Specific'}
339
+ </button>
340
+ ))}
341
+ </div>
342
+ <p className="text-[11px] text-text-3/60 mt-1.5 pl-1">{scopeHelperText}</p>
343
+ </div>
344
+
345
+ {scope === 'agent' && (
346
+ <div className="mb-8">
347
+ <label className="block font-display text-[12px] font-600 text-text-2 uppercase tracking-[0.08em] mb-3">Agents</label>
348
+ <div className="max-h-[240px] overflow-y-auto rounded-[12px] border border-white/[0.06] bg-white/[0.03]">
349
+ {agentList.length === 0 ? (
350
+ <p className="p-3 text-[12px] text-text-3">No agents available</p>
351
+ ) : (
352
+ agentList.map((agent) => {
353
+ const selected = agentIds.includes(agent.id)
354
+ return (
355
+ <button
356
+ key={agent.id}
357
+ onClick={() => toggleAgent(agent.id)}
358
+ className={`w-full flex items-center gap-2.5 px-3 py-2 text-left transition-all cursor-pointer ${
359
+ selected ? 'bg-accent-soft/40' : 'hover:bg-white/[0.04]'
360
+ }`}
361
+ style={{ fontFamily: 'inherit' }}
362
+ >
363
+ <AgentAvatar seed={agent.avatarSeed} name={agent.name} size={24} />
364
+ <span className="text-[13px] text-text flex-1 truncate">{agent.name}</span>
365
+ {selected && (
366
+ <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.5" strokeLinecap="round" strokeLinejoin="round" className="text-accent-bright shrink-0">
367
+ <polyline points="20 6 9 17 4 12" />
368
+ </svg>
369
+ )}
370
+ </button>
371
+ )
372
+ })
373
+ )}
374
+ </div>
375
+ </div>
376
+ )}
377
+
297
378
  <div className="flex gap-3 pt-2 border-t border-white/[0.04]">
298
379
  <button
299
380
  onClick={onClose}
@@ -305,7 +386,7 @@ export function KnowledgeSheet() {
305
386
  <button
306
387
  onClick={() => { void handleSave() }}
307
388
  disabled={!title.trim() || saving}
308
- className="flex-1 py-3.5 rounded-[14px] border-none bg-[#6366F1] text-white text-[15px] font-600 cursor-pointer active:scale-[0.97] disabled:opacity-30 transition-all shadow-[0_4px_20px_rgba(99,102,241,0.25)] hover:brightness-110"
389
+ className="flex-1 py-3.5 rounded-[14px] border-none bg-accent-bright text-white text-[15px] font-600 cursor-pointer active:scale-[0.97] disabled:opacity-30 transition-all shadow-[0_4px_20px_rgba(99,102,241,0.25)] hover:brightness-110"
309
390
  style={{ fontFamily: 'inherit' }}
310
391
  >
311
392
  {saving ? 'Saving...' : 'Save'}