@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 { useEffect, useState, useCallback } from 'react'
4
4
  import { useAppStore } from '@/stores/use-app-store'
5
5
  import { api } from '@/lib/api-client'
6
6
  import { Badge } from '@/components/ui/badge'
7
+ import { AgentAvatar } from '@/components/agents/agent-avatar'
7
8
  import { ClawHubBrowser } from './clawhub-browser'
8
9
  import { toast } from 'sonner'
9
10
 
@@ -27,6 +28,8 @@ interface SearchResponse {
27
28
  export function SkillList({ inSidebar }: { inSidebar?: boolean }) {
28
29
  const skills = useAppStore((s) => s.skills)
29
30
  const loadSkills = useAppStore((s) => s.loadSkills)
31
+ const agents = useAppStore((s) => s.agents)
32
+ const loadAgents = useAppStore((s) => s.loadAgents)
30
33
  const setSkillSheetOpen = useAppStore((s) => s.setSkillSheetOpen)
31
34
  const setEditingSkillId = useAppStore((s) => s.setEditingSkillId)
32
35
  const activeProjectFilter = useAppStore((s) => s.activeProjectFilter)
@@ -45,6 +48,8 @@ export function SkillList({ inSidebar }: { inSidebar?: boolean }) {
45
48
 
46
49
  useEffect(() => {
47
50
  loadSkills()
51
+ loadAgents()
52
+ // eslint-disable-next-line react-hooks/exhaustive-deps
48
53
  }, [])
49
54
 
50
55
  const skillList = Object.values(skills).filter((s) => !activeProjectFilter || s.projectId === activeProjectFilter)
@@ -258,37 +263,63 @@ export function SkillList({ inSidebar }: { inSidebar?: boolean }) {
258
263
  </div>
259
264
  ) : (
260
265
  <div className={inSidebar ? 'space-y-2' : 'grid grid-cols-1 md:grid-cols-2 xl:grid-cols-3 gap-3'}>
261
- {skillList.map((skill) => (
262
- <button
263
- key={skill.id}
264
- onClick={() => handleEdit(skill.id)}
265
- className="w-full text-left p-4 rounded-[14px] border border-white/[0.06] bg-surface hover:bg-surface-2 transition-all cursor-pointer"
266
- >
267
- <div className="flex items-center justify-between mb-1">
268
- <span className="font-display text-[14px] font-600 text-text truncate">{skill.name}</span>
269
- <div className="flex items-center gap-2 shrink-0 ml-2">
270
- <span className="text-[10px] font-mono text-text-3/50">{skill.filename}</span>
271
- {!inSidebar && (
272
- <button
273
- onClick={(e) => handleDelete(e, skill.id)}
274
- className="text-text-3/40 hover:text-red-400 transition-colors p-0.5"
275
- title="Delete"
276
- >
277
- <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round">
278
- <path d="M3 6h18M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6m3 0V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2" />
279
- </svg>
280
- </button>
281
- )}
266
+ {skillList.map((skill) => {
267
+ const skillScope = skill.scope || 'global'
268
+ const skillAgentIds = skill.agentIds || []
269
+ const scopeLabel = skillScope === 'global' ? 'Global' : `${skillAgentIds.length} agent(s)`
270
+ const scopedAgents = skillScope === 'agent'
271
+ ? skillAgentIds.map((id) => agents[id]).filter(Boolean)
272
+ : []
273
+ return (
274
+ <button
275
+ key={skill.id}
276
+ onClick={() => handleEdit(skill.id)}
277
+ className="w-full text-left p-4 rounded-[14px] border border-white/[0.06] bg-surface hover:bg-surface-2 transition-all cursor-pointer"
278
+ >
279
+ <div className="flex items-center justify-between mb-1">
280
+ <span className="font-display text-[14px] font-600 text-text truncate">{skill.name}</span>
281
+ <div className="flex items-center gap-2 shrink-0 ml-2">
282
+ <span className="text-[10px] font-mono text-text-3/50">{skill.filename}</span>
283
+ {!inSidebar && (
284
+ <button
285
+ onClick={(e) => handleDelete(e, skill.id)}
286
+ className="text-text-3/40 hover:text-red-400 transition-colors p-0.5"
287
+ title="Delete"
288
+ >
289
+ <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round">
290
+ <path d="M3 6h18M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6m3 0V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2" />
291
+ </svg>
292
+ </button>
293
+ )}
294
+ </div>
282
295
  </div>
283
- </div>
284
- {skill.description && (
285
- <p className="text-[12px] text-text-3/60 line-clamp-2">{skill.description}</p>
286
- )}
287
- <div className="text-[11px] text-text-3/70 mt-1.5">
288
- {skill.content.length} chars
289
- </div>
290
- </button>
291
- ))}
296
+ {skill.description && (
297
+ <p className="text-[12px] text-text-3/60 line-clamp-2">{skill.description}</p>
298
+ )}
299
+ <div className="flex items-center gap-2 mt-1.5">
300
+ <span className="text-[11px] text-text-3/70">{skill.content.length} chars</span>
301
+ <span className="text-[11px] text-text-3/60">·</span>
302
+ <span className={`text-[10px] font-600 ${
303
+ skillScope === 'global' ? 'text-emerald-400' : 'text-amber-400'
304
+ }`}>
305
+ {scopeLabel}
306
+ </span>
307
+ </div>
308
+ {scopedAgents.length > 0 && (
309
+ <div className="flex items-center gap-1.5 mt-1.5">
310
+ <div className="flex items-center -space-x-1.5">
311
+ {scopedAgents.slice(0, 5).map((agent) => (
312
+ <AgentAvatar key={agent.id} seed={agent.avatarSeed} name={agent.name} size={16} className="ring-1 ring-surface" />
313
+ ))}
314
+ </div>
315
+ {scopedAgents.length > 5 && (
316
+ <span className="text-[10px] font-600 text-text-3/60 ml-0.5">+{scopedAgents.length - 5}</span>
317
+ )}
318
+ </div>
319
+ )}
320
+ </button>
321
+ )
322
+ })}
292
323
  </div>
293
324
  )
294
325
  )}
@@ -3,6 +3,7 @@
3
3
  import { useEffect, useState, useRef } from 'react'
4
4
  import { useAppStore } from '@/stores/use-app-store'
5
5
  import { BottomSheet } from '@/components/shared/bottom-sheet'
6
+ import { AgentAvatar } from '@/components/agents/agent-avatar'
6
7
  import { api } from '@/lib/api-client'
7
8
 
8
9
  export function SkillSheet() {
@@ -12,18 +13,23 @@ export function SkillSheet() {
12
13
  const setEditingId = useAppStore((s) => s.setEditingSkillId)
13
14
  const skills = useAppStore((s) => s.skills)
14
15
  const loadSkills = useAppStore((s) => s.loadSkills)
16
+ const agents = useAppStore((s) => s.agents)
17
+ const loadAgents = useAppStore((s) => s.loadAgents)
15
18
  const fileRef = useRef<HTMLInputElement>(null)
16
19
 
17
20
  const [name, setName] = useState('')
18
21
  const [filename, setFilename] = useState('')
19
22
  const [description, setDescription] = useState('')
20
23
  const [content, setContent] = useState('')
24
+ const [scope, setScope] = useState<'global' | 'agent'>('global')
25
+ const [agentIds, setAgentIds] = useState<string[]>([])
21
26
  const [importUrl, setImportUrl] = useState('')
22
27
  const [importingUrl, setImportingUrl] = useState(false)
23
28
  const [importError, setImportError] = useState('')
24
29
  const [importNotice, setImportNotice] = useState('')
25
30
 
26
31
  const editing = editingId ? skills[editingId] : null
32
+ const agentList = Object.values(agents)
27
33
 
28
34
  const handleImportFromUrl = async () => {
29
35
  if (!importUrl.trim()) return
@@ -48,6 +54,11 @@ export function SkillSheet() {
48
54
  }
49
55
  }
50
56
 
57
+ useEffect(() => {
58
+ if (open) loadAgents()
59
+ // eslint-disable-next-line react-hooks/exhaustive-deps
60
+ }, [open])
61
+
51
62
  useEffect(() => {
52
63
  if (open) {
53
64
  setImportUrl('')
@@ -59,11 +70,15 @@ export function SkillSheet() {
59
70
  setFilename(editing.filename)
60
71
  setDescription(editing.description || '')
61
72
  setContent(editing.content)
73
+ setScope(editing.scope || 'global')
74
+ setAgentIds(editing.agentIds || [])
62
75
  } else {
63
76
  setName('')
64
77
  setFilename('')
65
78
  setDescription('')
66
79
  setContent('')
80
+ setScope('global')
81
+ setAgentIds([])
67
82
  }
68
83
  }
69
84
  }, [open, editingId])
@@ -87,12 +102,24 @@ export function SkillSheet() {
87
102
  e.target.value = ''
88
103
  }
89
104
 
105
+ const toggleAgent = (id: string) => {
106
+ setAgentIds((prev) => prev.includes(id) ? prev.filter((x) => x !== id) : [...prev, id])
107
+ }
108
+
109
+ const scopeHelperText = scope === 'global'
110
+ ? 'This skill will be accessible to all agents'
111
+ : agentIds.length === 0
112
+ ? 'Select which agents can access this skill'
113
+ : `${agentIds.length} agent(s) selected`
114
+
90
115
  const handleSave = async () => {
91
116
  const data = {
92
117
  name: name.trim() || 'Unnamed Skill',
93
118
  filename: filename.trim() || `${name.trim().toLowerCase().replace(/\s+/g, '-')}.md`,
94
119
  description,
95
120
  content,
121
+ scope,
122
+ agentIds: scope === 'agent' ? agentIds : [],
96
123
  }
97
124
  if (editing) {
98
125
  await api('PUT', `/skills/${editing.id}`, data)
@@ -155,7 +182,7 @@ export function SkillSheet() {
155
182
  <button
156
183
  onClick={handleImportFromUrl}
157
184
  disabled={importingUrl || !importUrl.trim()}
158
- className="px-4 py-3 rounded-[12px] border-none bg-[#6366F1] text-white text-[13px] font-600 cursor-pointer disabled:opacity-30 transition-all hover:brightness-110"
185
+ className="px-4 py-3 rounded-[12px] border-none bg-accent-bright text-white text-[13px] font-600 cursor-pointer disabled:opacity-30 transition-all hover:brightness-110"
159
186
  style={{ fontFamily: 'inherit' }}
160
187
  >
161
188
  {importingUrl ? 'Importing...' : 'Import'}
@@ -191,6 +218,58 @@ export function SkillSheet() {
191
218
  <p className="text-[11px] text-text-3/70 mt-2">{content.length} characters</p>
192
219
  </div>
193
220
 
221
+ <div className="mb-8">
222
+ <label className="block font-display text-[12px] font-600 text-text-2 uppercase tracking-[0.08em] mb-3">Scope</label>
223
+ <div className="flex p-1 rounded-[12px] bg-bg border border-white/[0.06]">
224
+ {(['global', 'agent'] as const).map((s) => (
225
+ <button
226
+ key={s}
227
+ onClick={() => setScope(s)}
228
+ className={`flex-1 py-2.5 rounded-[10px] text-center cursor-pointer transition-all text-[13px] font-600 border-none ${
229
+ scope === s ? 'bg-accent-soft text-accent-bright' : 'bg-transparent text-text-3 hover:text-text-2'
230
+ }`}
231
+ style={{ fontFamily: 'inherit' }}
232
+ >
233
+ {s === 'global' ? 'Global' : 'Specific'}
234
+ </button>
235
+ ))}
236
+ </div>
237
+ <p className="text-[11px] text-text-3/60 mt-1.5 pl-1">{scopeHelperText}</p>
238
+ </div>
239
+
240
+ {scope === 'agent' && (
241
+ <div className="mb-8">
242
+ <label className="block font-display text-[12px] font-600 text-text-2 uppercase tracking-[0.08em] mb-3">Agents</label>
243
+ <div className="max-h-[240px] overflow-y-auto rounded-[12px] border border-white/[0.06] bg-white/[0.03]">
244
+ {agentList.length === 0 ? (
245
+ <p className="p-3 text-[12px] text-text-3">No agents available</p>
246
+ ) : (
247
+ agentList.map((agent) => {
248
+ const selected = agentIds.includes(agent.id)
249
+ return (
250
+ <button
251
+ key={agent.id}
252
+ onClick={() => toggleAgent(agent.id)}
253
+ className={`w-full flex items-center gap-2.5 px-3 py-2 text-left transition-all cursor-pointer ${
254
+ selected ? 'bg-accent-soft/40' : 'hover:bg-white/[0.04]'
255
+ }`}
256
+ style={{ fontFamily: 'inherit' }}
257
+ >
258
+ <AgentAvatar seed={agent.avatarSeed} name={agent.name} size={24} />
259
+ <span className="text-[13px] text-text flex-1 truncate">{agent.name}</span>
260
+ {selected && (
261
+ <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">
262
+ <polyline points="20 6 9 17 4 12" />
263
+ </svg>
264
+ )}
265
+ </button>
266
+ )
267
+ })
268
+ )}
269
+ </div>
270
+ </div>
271
+ )}
272
+
194
273
  <div className="flex gap-3 pt-2 border-t border-white/[0.04]">
195
274
  {editing && (
196
275
  <button onClick={handleDelete} className="py-3.5 px-6 rounded-[14px] border border-red-500/20 bg-transparent text-red-400 text-[15px] font-600 cursor-pointer hover:bg-red-500/10 transition-all" style={{ fontFamily: 'inherit' }}>
@@ -200,7 +279,7 @@ export function SkillSheet() {
200
279
  <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' }}>
201
280
  Cancel
202
281
  </button>
203
- <button onClick={handleSave} disabled={!name.trim() || !content.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' }}>
282
+ <button onClick={handleSave} disabled={!name.trim() || !content.trim()} 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" style={{ fontFamily: 'inherit' }}>
204
283
  {editing ? 'Save' : 'Create'}
205
284
  </button>
206
285
  </div>