@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,47 +4,183 @@ import { useState } from 'react'
4
4
  import { useAppStore } from '@/stores/use-app-store'
5
5
  import { createMemory } from '@/lib/memory'
6
6
  import { BottomSheet } from '@/components/shared/bottom-sheet'
7
+ import { AgentAvatar } from '@/components/agents/agent-avatar'
8
+ import { SheetFooter } from '@/components/shared/sheet-footer'
9
+ import { inputClass } from '@/components/shared/form-styles'
10
+
11
+ const CATEGORIES = ['note', 'fact', 'preference', 'finding', 'learning', 'general']
7
12
 
8
13
  export function MemorySheet() {
9
14
  const open = useAppStore((s) => s.memorySheetOpen)
10
15
  const setOpen = useAppStore((s) => s.setMemorySheetOpen)
11
16
  const triggerRefresh = useAppStore((s) => s.triggerMemoryRefresh)
17
+ const agents = useAppStore((s) => s.agents)
18
+ const memoryAgentFilter = useAppStore((s) => s.memoryAgentFilter)
19
+
20
+ // Track open transitions to reset form
21
+ const [prevOpen, setPrevOpen] = useState(false)
22
+ const defaultAgentId = memoryAgentFilter && memoryAgentFilter !== '_global' ? memoryAgentFilter : null
12
23
 
13
24
  const [title, setTitle] = useState('')
14
25
  const [content, setContent] = useState('')
26
+ const [category, setCategory] = useState('note')
27
+ const [agentId, setAgentId] = useState<string | null>(defaultAgentId)
28
+ const [sharedWith, setSharedWith] = useState<string[]>([])
29
+ const [saving, setSaving] = useState(false)
15
30
 
16
- const onClose = () => {
17
- setOpen(false)
31
+ // Reset form when sheet opens (getDerivedStateFromProps pattern)
32
+ if (open && !prevOpen) {
33
+ setPrevOpen(true)
34
+ setAgentId(defaultAgentId)
35
+ setSharedWith([])
18
36
  setTitle('')
19
37
  setContent('')
38
+ setCategory('note')
39
+ setSaving(false)
40
+ } else if (!open && prevOpen) {
41
+ setPrevOpen(false)
42
+ }
43
+
44
+ const onClose = () => {
45
+ setOpen(false)
20
46
  }
21
47
 
22
48
  const handleSave = async () => {
23
- await createMemory({
24
- title: title.trim() || 'Untitled',
25
- category: 'general',
26
- content,
27
- agentId: null,
28
- sessionId: null,
29
- })
30
- triggerRefresh()
31
- onClose()
49
+ if (!title.trim()) return
50
+ setSaving(true)
51
+ try {
52
+ await createMemory({
53
+ title: title.trim(),
54
+ category,
55
+ content,
56
+ agentId,
57
+ sessionId: null,
58
+ sharedWith: sharedWith.length ? sharedWith : undefined,
59
+ })
60
+ triggerRefresh()
61
+ onClose()
62
+ } catch {
63
+ /* ignore */
64
+ }
65
+ setSaving(false)
32
66
  }
33
67
 
34
- const inputClass = "w-full px-4 py-3.5 rounded-[14px] border border-white/[0.08] bg-surface text-text text-[15px] outline-none transition-all duration-200 placeholder:text-text-3/50 focus-glow"
68
+ const agentList = Object.values(agents).sort((a, b) => a.name.localeCompare(b.name))
69
+ const selectedAgent = agentId ? agents[agentId] : null
35
70
 
36
71
  return (
37
72
  <BottomSheet open={open} onClose={onClose}>
38
- <div className="mb-10">
73
+ <div className="mb-8">
39
74
  <h2 className="font-display text-[28px] font-700 tracking-[-0.03em] mb-2">New Memory</h2>
40
- <p className="text-[14px] text-text-3">Store a piece of knowledge</p>
75
+ <p className="text-[14px] text-text-3">Store a piece of knowledge for an agent or globally</p>
41
76
  </div>
42
77
 
43
- <div className="mb-8">
78
+ {/* Agent selector */}
79
+ <div className="mb-6">
80
+ <label className="block font-display text-[12px] font-600 text-text-2 uppercase tracking-[0.08em] mb-3">Assign to</label>
81
+ <div className="flex gap-2 flex-wrap">
82
+ <button
83
+ onClick={() => setAgentId(null)}
84
+ className={`flex items-center gap-2 px-3 py-2 rounded-[10px] text-[13px] font-600 cursor-pointer transition-all border
85
+ ${!agentId
86
+ ? 'bg-accent-soft border-accent-bright/20 text-accent-bright'
87
+ : 'bg-white/[0.02] border-white/[0.06] text-text-3 hover:text-text-2 hover:bg-white/[0.04]'}`}
88
+ style={{ fontFamily: 'inherit' }}
89
+ >
90
+ <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" className={!agentId ? 'text-accent-bright' : 'text-text-3/60'}>
91
+ <circle cx="12" cy="12" r="10" />
92
+ <line x1="2" y1="12" x2="22" y2="12" />
93
+ <path d="M12 2a15.3 15.3 0 0 1 4 10 15.3 15.3 0 0 1-4 10 15.3 15.3 0 0 1-4-10 15.3 15.3 0 0 1 4-10z" />
94
+ </svg>
95
+ Global
96
+ </button>
97
+ {agentList.map((agent) => (
98
+ <button
99
+ key={agent.id}
100
+ onClick={() => setAgentId(agent.id)}
101
+ className={`flex items-center gap-2 px-3 py-2 rounded-[10px] text-[13px] font-600 cursor-pointer transition-all border
102
+ ${agentId === agent.id
103
+ ? 'bg-accent-soft border-accent-bright/20 text-accent-bright'
104
+ : 'bg-white/[0.02] border-white/[0.06] text-text-3 hover:text-text-2 hover:bg-white/[0.04]'}`}
105
+ style={{ fontFamily: 'inherit' }}
106
+ >
107
+ <AgentAvatar seed={agent.avatarSeed || null} name={agent.name} size={20} />
108
+ <span className="truncate max-w-[120px]">{agent.name}</span>
109
+ </button>
110
+ ))}
111
+ </div>
112
+ {selectedAgent && (
113
+ <p className="text-[11px] text-text-3/50 mt-2">
114
+ This memory will be available to <span className="text-text-2">{selectedAgent.name}</span> during conversations
115
+ </p>
116
+ )}
117
+ {!agentId && (
118
+ <p className="text-[11px] text-text-3/50 mt-2">
119
+ Global memories are accessible to all agents
120
+ </p>
121
+ )}
122
+ </div>
123
+
124
+ {/* Share with (only when assigned to an agent) */}
125
+ {agentId && agentList.filter((a) => a.id !== agentId).length > 0 && (
126
+ <div className="mb-6">
127
+ <label className="block font-display text-[12px] font-600 text-text-2 uppercase tracking-[0.08em] mb-3">Share with</label>
128
+ <div className="flex gap-2 flex-wrap">
129
+ {agentList
130
+ .filter((a) => a.id !== agentId)
131
+ .map((agent) => {
132
+ const isShared = sharedWith.includes(agent.id)
133
+ return (
134
+ <button
135
+ key={agent.id}
136
+ onClick={() => setSharedWith(isShared ? sharedWith.filter((id) => id !== agent.id) : [...sharedWith, agent.id])}
137
+ className={`flex items-center gap-2 px-3 py-2 rounded-[10px] text-[13px] font-600 cursor-pointer transition-all border
138
+ ${isShared
139
+ ? 'bg-accent-soft border-accent-bright/20 text-accent-bright'
140
+ : 'bg-white/[0.02] border-white/[0.06] text-text-3 hover:text-text-2 hover:bg-white/[0.04]'}`}
141
+ style={{ fontFamily: 'inherit' }}
142
+ >
143
+ <AgentAvatar seed={agent.avatarSeed || null} name={agent.name} size={20} />
144
+ <span className="truncate max-w-[120px]">{agent.name}</span>
145
+ </button>
146
+ )
147
+ })}
148
+ </div>
149
+ {sharedWith.length > 0 && (
150
+ <p className="text-[11px] text-text-3/50 mt-2">
151
+ Shared with {sharedWith.length} agent{sharedWith.length === 1 ? '' : 's'} in addition to the owner
152
+ </p>
153
+ )}
154
+ </div>
155
+ )}
156
+
157
+ {/* Title */}
158
+ <div className="mb-6">
44
159
  <label className="block font-display text-[12px] font-600 text-text-2 uppercase tracking-[0.08em] mb-3">Title</label>
45
160
  <input type="text" value={title} onChange={(e) => setTitle(e.target.value)} placeholder="Memory title" className={inputClass} style={{ fontFamily: 'inherit' }} />
46
161
  </div>
47
162
 
163
+ {/* Category */}
164
+ <div className="mb-6">
165
+ <label className="block font-display text-[12px] font-600 text-text-2 uppercase tracking-[0.08em] mb-3">Category</label>
166
+ <div className="flex gap-1.5 flex-wrap">
167
+ {CATEGORIES.map((c) => (
168
+ <button
169
+ key={c}
170
+ onClick={() => setCategory(c)}
171
+ className={`px-3 py-1.5 rounded-[8px] text-[12px] font-600 capitalize cursor-pointer transition-all border-none
172
+ ${category === c
173
+ ? 'bg-accent-soft text-accent-bright'
174
+ : 'bg-white/[0.03] text-text-3 hover:text-text-2 hover:bg-white/[0.05]'}`}
175
+ style={{ fontFamily: 'inherit' }}
176
+ >
177
+ {c}
178
+ </button>
179
+ ))}
180
+ </div>
181
+ </div>
182
+
183
+ {/* Content */}
48
184
  <div className="mb-8">
49
185
  <label className="block font-display text-[12px] font-600 text-text-2 uppercase tracking-[0.08em] mb-3">Content</label>
50
186
  <textarea
@@ -57,14 +193,12 @@ export function MemorySheet() {
57
193
  />
58
194
  </div>
59
195
 
60
- <div className="flex gap-3 pt-2 border-t border-white/[0.04]">
61
- <button onClick={onClose} className="flex-1 py-3.5 rounded-[14px] border border-white/[0.08] bg-transparent text-text-2 text-[15px] font-600 cursor-pointer hover:bg-surface-2 transition-all" style={{ fontFamily: 'inherit' }}>
62
- Cancel
63
- </button>
64
- <button onClick={handleSave} disabled={!title.trim()} 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" style={{ fontFamily: 'inherit' }}>
65
- Save
66
- </button>
67
- </div>
196
+ <SheetFooter
197
+ onCancel={onClose}
198
+ onSave={handleSave}
199
+ saveLabel={saving ? 'Saving...' : 'Save'}
200
+ saveDisabled={!title.trim() || saving}
201
+ />
68
202
  </BottomSheet>
69
203
  )
70
204
  }
@@ -224,7 +224,7 @@ export function PluginList({ inSidebar }: { inSidebar?: boolean }) {
224
224
  <div
225
225
  onClick={(e) => handleToggle(e, plugin.filename, plugin.enabled)}
226
226
  className={`w-9 h-5 rounded-full transition-all relative cursor-pointer shrink-0
227
- ${plugin.enabled ? 'bg-[#6366F1]' : 'bg-white/[0.08]'}`}
227
+ ${plugin.enabled ? 'bg-accent-bright' : 'bg-white/[0.08]'}`}
228
228
  >
229
229
  <div className={`absolute top-0.5 w-4 h-4 rounded-full bg-white transition-all
230
230
  ${plugin.enabled ? 'left-[18px]' : 'left-0.5'}`} />
@@ -116,7 +116,7 @@ export function PluginSheet() {
116
116
  <div
117
117
  onClick={() => togglePlugin(editing.filename, !editing.enabled)}
118
118
  className={`w-11 h-6 rounded-full transition-all duration-200 relative cursor-pointer shrink-0
119
- ${editing.enabled ? 'bg-[#6366F1]' : 'bg-white/[0.08]'}`}
119
+ ${editing.enabled ? 'bg-accent-bright' : 'bg-white/[0.08]'}`}
120
120
  >
121
121
  <div className={`absolute top-0.5 w-5 h-5 rounded-full bg-white transition-all duration-200
122
122
  ${editing.enabled ? 'left-[22px]' : 'left-0.5'}`} />