@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.
- package/README.md +42 -7
- package/bin/swarmclaw.js +76 -16
- package/next.config.ts +11 -1
- package/package.json +4 -2
- package/public/screenshots/agents.png +0 -0
- package/public/screenshots/dashboard.png +0 -0
- package/public/screenshots/providers.png +0 -0
- package/public/screenshots/tasks.png +0 -0
- package/scripts/postinstall.mjs +18 -0
- package/src/app/api/chatrooms/[id]/chat/route.ts +410 -0
- package/src/app/api/chatrooms/[id]/members/route.ts +82 -0
- package/src/app/api/chatrooms/[id]/pins/route.ts +39 -0
- package/src/app/api/chatrooms/[id]/reactions/route.ts +42 -0
- package/src/app/api/chatrooms/[id]/route.ts +84 -0
- package/src/app/api/chatrooms/route.ts +50 -0
- package/src/app/api/credentials/route.ts +2 -3
- package/src/app/api/knowledge/[id]/route.ts +13 -2
- package/src/app/api/knowledge/route.ts +8 -1
- package/src/app/api/memory/route.ts +8 -0
- package/src/app/api/notifications/[id]/route.ts +27 -0
- package/src/app/api/notifications/route.ts +68 -0
- package/src/app/api/orchestrator/run/route.ts +1 -1
- package/src/app/api/plugins/install/route.ts +2 -2
- package/src/app/api/search/route.ts +155 -0
- package/src/app/api/sessions/[id]/chat/route.ts +2 -0
- package/src/app/api/sessions/[id]/edit-resend/route.ts +1 -1
- package/src/app/api/sessions/[id]/fork/route.ts +1 -1
- package/src/app/api/sessions/route.ts +3 -3
- package/src/app/api/settings/route.ts +9 -0
- package/src/app/api/setup/check-provider/route.ts +3 -16
- package/src/app/api/skills/[id]/route.ts +6 -0
- package/src/app/api/skills/route.ts +6 -0
- package/src/app/api/tasks/[id]/route.ts +20 -0
- package/src/app/api/tasks/bulk/route.ts +100 -0
- package/src/app/api/tasks/route.ts +1 -0
- package/src/app/api/usage/route.ts +45 -0
- package/src/app/api/webhooks/[id]/route.ts +15 -1
- package/src/app/globals.css +58 -15
- package/src/app/page.tsx +142 -13
- package/src/cli/index.js +42 -0
- package/src/cli/index.test.js +30 -0
- package/src/cli/spec.js +32 -0
- package/src/components/agents/agent-avatar.tsx +57 -10
- package/src/components/agents/agent-card.tsx +48 -15
- package/src/components/agents/agent-chat-list.tsx +123 -10
- package/src/components/agents/agent-list.tsx +50 -19
- package/src/components/agents/agent-sheet.tsx +56 -63
- package/src/components/auth/access-key-gate.tsx +10 -3
- package/src/components/auth/setup-wizard.tsx +2 -2
- package/src/components/auth/user-picker.tsx +31 -3
- package/src/components/chat/activity-moment.tsx +169 -0
- package/src/components/chat/chat-header.tsx +2 -0
- package/src/components/chat/chat-tool-toggles.tsx +1 -1
- package/src/components/chat/file-path-chip.tsx +125 -0
- package/src/components/chat/markdown-utils.ts +9 -0
- package/src/components/chat/message-bubble.tsx +46 -295
- package/src/components/chat/message-list.tsx +50 -1
- package/src/components/chat/streaming-bubble.tsx +36 -46
- package/src/components/chat/suggestions-bar.tsx +1 -1
- package/src/components/chat/thinking-indicator.tsx +72 -10
- package/src/components/chat/tool-call-bubble.tsx +66 -70
- package/src/components/chat/tool-request-banner.tsx +31 -7
- package/src/components/chat/transfer-agent-picker.tsx +63 -0
- package/src/components/chatrooms/agent-hover-card.tsx +124 -0
- package/src/components/chatrooms/chatroom-input.tsx +320 -0
- package/src/components/chatrooms/chatroom-list.tsx +123 -0
- package/src/components/chatrooms/chatroom-message.tsx +427 -0
- package/src/components/chatrooms/chatroom-sheet.tsx +215 -0
- package/src/components/chatrooms/chatroom-tool-request-banner.tsx +134 -0
- package/src/components/chatrooms/chatroom-typing-bar.tsx +88 -0
- package/src/components/chatrooms/chatroom-view.tsx +344 -0
- package/src/components/chatrooms/reaction-picker.tsx +273 -0
- package/src/components/connectors/connector-sheet.tsx +34 -47
- package/src/components/home/home-view.tsx +501 -0
- package/src/components/input/chat-input.tsx +79 -41
- package/src/components/knowledge/knowledge-list.tsx +31 -1
- package/src/components/knowledge/knowledge-sheet.tsx +83 -2
- package/src/components/layout/app-layout.tsx +209 -83
- package/src/components/layout/mobile-header.tsx +2 -0
- package/src/components/layout/update-banner.tsx +2 -2
- package/src/components/logs/log-list.tsx +2 -2
- package/src/components/mcp-servers/mcp-server-sheet.tsx +1 -1
- package/src/components/memory/memory-agent-list.tsx +143 -0
- package/src/components/memory/memory-browser.tsx +205 -0
- package/src/components/memory/memory-card.tsx +34 -7
- package/src/components/memory/memory-detail.tsx +359 -120
- package/src/components/memory/memory-sheet.tsx +157 -23
- package/src/components/plugins/plugin-list.tsx +1 -1
- package/src/components/plugins/plugin-sheet.tsx +1 -1
- package/src/components/projects/project-detail.tsx +509 -0
- package/src/components/projects/project-list.tsx +195 -59
- package/src/components/providers/provider-list.tsx +2 -2
- package/src/components/providers/provider-sheet.tsx +3 -3
- package/src/components/schedules/schedule-card.tsx +3 -2
- package/src/components/schedules/schedule-list.tsx +1 -1
- package/src/components/schedules/schedule-sheet.tsx +25 -25
- package/src/components/secrets/secret-sheet.tsx +47 -24
- package/src/components/secrets/secrets-list.tsx +18 -8
- package/src/components/sessions/new-session-sheet.tsx +33 -65
- package/src/components/sessions/session-card.tsx +45 -14
- package/src/components/sessions/session-list.tsx +35 -18
- package/src/components/shared/agent-picker-list.tsx +90 -0
- package/src/components/shared/agent-switch-dialog.tsx +156 -0
- package/src/components/shared/attachment-chip.tsx +165 -0
- package/src/components/shared/avatar.tsx +10 -1
- package/src/components/shared/check-icon.tsx +12 -0
- package/src/components/shared/confirm-dialog.tsx +1 -1
- package/src/components/shared/empty-state.tsx +32 -0
- package/src/components/shared/file-preview.tsx +34 -0
- package/src/components/shared/form-styles.ts +2 -0
- package/src/components/shared/keyboard-shortcuts-dialog.tsx +116 -0
- package/src/components/shared/notification-center.tsx +223 -0
- package/src/components/shared/profile-sheet.tsx +115 -0
- package/src/components/shared/reply-quote.tsx +26 -0
- package/src/components/shared/search-dialog.tsx +296 -0
- package/src/components/shared/section-label.tsx +12 -0
- package/src/components/shared/settings/plugin-manager.tsx +1 -1
- package/src/components/shared/settings/section-providers.tsx +1 -1
- package/src/components/shared/settings/section-secrets.tsx +1 -1
- package/src/components/shared/settings/section-theme.tsx +95 -0
- package/src/components/shared/settings/section-user-preferences.tsx +39 -0
- package/src/components/shared/settings/settings-page.tsx +180 -27
- package/src/components/shared/settings/settings-sheet.tsx +9 -73
- package/src/components/shared/sheet-footer.tsx +33 -0
- package/src/components/skills/skill-list.tsx +61 -30
- package/src/components/skills/skill-sheet.tsx +81 -2
- package/src/components/tasks/task-board.tsx +448 -26
- package/src/components/tasks/task-card.tsx +46 -9
- package/src/components/tasks/task-column.tsx +62 -3
- package/src/components/tasks/task-list.tsx +12 -4
- package/src/components/tasks/task-sheet.tsx +89 -72
- package/src/components/ui/hover-card.tsx +52 -0
- package/src/components/usage/metrics-dashboard.tsx +78 -0
- package/src/components/usage/usage-list.tsx +1 -1
- package/src/components/webhooks/webhook-sheet.tsx +1 -1
- package/src/hooks/use-view-router.ts +69 -19
- package/src/instrumentation.ts +15 -1
- package/src/lib/chat.ts +2 -0
- package/src/lib/cron-human.ts +114 -0
- package/src/lib/memory.ts +3 -0
- package/src/lib/server/chat-execution.ts +24 -4
- package/src/lib/server/connectors/manager.ts +11 -0
- package/src/lib/server/context-manager.ts +225 -13
- package/src/lib/server/create-notification.ts +42 -0
- package/src/lib/server/daemon-state.ts +165 -10
- package/src/lib/server/execution-log.ts +1 -0
- package/src/lib/server/heartbeat-service.ts +40 -5
- package/src/lib/server/heartbeat-wake.ts +110 -0
- package/src/lib/server/langgraph-checkpoint.ts +1 -0
- package/src/lib/server/memory-consolidation.ts +92 -0
- package/src/lib/server/memory-db.ts +51 -6
- package/src/lib/server/openclaw-gateway.ts +9 -1
- package/src/lib/server/provider-health.ts +125 -0
- package/src/lib/server/queue.ts +5 -4
- package/src/lib/server/scheduler.ts +8 -0
- package/src/lib/server/session-run-manager.ts +4 -0
- package/src/lib/server/session-tools/chatroom.ts +136 -0
- package/src/lib/server/session-tools/context-mgmt.ts +36 -18
- package/src/lib/server/session-tools/index.ts +2 -0
- package/src/lib/server/session-tools/memory.ts +6 -1
- package/src/lib/server/storage.ts +80 -29
- package/src/lib/server/stream-agent-chat.ts +153 -47
- package/src/lib/server/system-events.ts +49 -0
- package/src/lib/server/ws-hub.ts +11 -0
- package/src/lib/soul-suggestions.ts +109 -0
- package/src/lib/tasks.ts +4 -1
- package/src/lib/view-routes.ts +36 -1
- package/src/lib/ws-client.ts +14 -4
- package/src/proxy.ts +79 -2
- package/src/stores/use-app-store.ts +94 -3
- package/src/stores/use-chat-store.ts +48 -3
- package/src/stores/use-chatroom-store.ts +276 -0
- package/src/types/index.ts +69 -2
|
@@ -2,7 +2,6 @@
|
|
|
2
2
|
|
|
3
3
|
import { Component, useState, useEffect, useCallback } from 'react'
|
|
4
4
|
import type { ReactNode, ErrorInfo } from 'react'
|
|
5
|
-
import { Dialog, DialogContent, DialogHeader, DialogTitle } from '@/components/ui/dialog'
|
|
6
5
|
import { useAppStore } from '@/stores/use-app-store'
|
|
7
6
|
import { useMediaQuery } from '@/hooks/use-media-query'
|
|
8
7
|
import { Avatar } from '@/components/shared/avatar'
|
|
@@ -12,9 +11,9 @@ import { AgentChatList } from '@/components/agents/agent-chat-list'
|
|
|
12
11
|
import { AgentSheet } from '@/components/agents/agent-sheet'
|
|
13
12
|
import { ScheduleList } from '@/components/schedules/schedule-list'
|
|
14
13
|
import { ScheduleSheet } from '@/components/schedules/schedule-sheet'
|
|
15
|
-
import {
|
|
14
|
+
import { MemoryAgentList } from '@/components/memory/memory-agent-list'
|
|
16
15
|
import { MemorySheet } from '@/components/memory/memory-sheet'
|
|
17
|
-
import {
|
|
16
|
+
import { MemoryBrowser } from '@/components/memory/memory-browser'
|
|
18
17
|
import { TaskList } from '@/components/tasks/task-list'
|
|
19
18
|
import { TaskSheet } from '@/components/tasks/task-sheet'
|
|
20
19
|
import { TaskBoard } from '@/components/tasks/task-board'
|
|
@@ -26,6 +25,10 @@ import { SkillList } from '@/components/skills/skill-list'
|
|
|
26
25
|
import { SkillSheet } from '@/components/skills/skill-sheet'
|
|
27
26
|
import { ConnectorList } from '@/components/connectors/connector-list'
|
|
28
27
|
import { ConnectorSheet } from '@/components/connectors/connector-sheet'
|
|
28
|
+
import { ChatroomList } from '@/components/chatrooms/chatroom-list'
|
|
29
|
+
import { ChatroomView } from '@/components/chatrooms/chatroom-view'
|
|
30
|
+
import { ChatroomSheet } from '@/components/chatrooms/chatroom-sheet'
|
|
31
|
+
import { useChatroomStore } from '@/stores/use-chatroom-store'
|
|
29
32
|
import { WebhookList } from '@/components/webhooks/webhook-list'
|
|
30
33
|
import { WebhookSheet } from '@/components/webhooks/webhook-sheet'
|
|
31
34
|
import { LogList } from '@/components/logs/log-list'
|
|
@@ -39,16 +42,26 @@ import { RunList } from '@/components/runs/run-list'
|
|
|
39
42
|
import { ActivityFeed } from '@/components/activity/activity-feed'
|
|
40
43
|
import { MetricsDashboard } from '@/components/usage/metrics-dashboard'
|
|
41
44
|
import { ProjectList } from '@/components/projects/project-list'
|
|
45
|
+
import { ProjectDetail } from '@/components/projects/project-detail'
|
|
42
46
|
import { ProjectSheet } from '@/components/projects/project-sheet'
|
|
47
|
+
import { SearchDialog } from '@/components/shared/search-dialog'
|
|
48
|
+
import { AgentSwitchDialog } from '@/components/shared/agent-switch-dialog'
|
|
49
|
+
import { KeyboardShortcutsDialog } from '@/components/shared/keyboard-shortcuts-dialog'
|
|
50
|
+
import { ProfileSheet } from '@/components/shared/profile-sheet'
|
|
51
|
+
import { HomeView } from '@/components/home/home-view'
|
|
43
52
|
import { NetworkBanner } from './network-banner'
|
|
44
53
|
import { UpdateBanner } from './update-banner'
|
|
45
54
|
import { MobileHeader } from './mobile-header'
|
|
46
55
|
import { DaemonIndicator } from './daemon-indicator'
|
|
56
|
+
import { NotificationCenter } from '@/components/shared/notification-center'
|
|
47
57
|
import { ChatArea } from '@/components/chat/chat-area'
|
|
48
58
|
import { Tooltip, TooltipTrigger, TooltipContent } from '@/components/ui/tooltip'
|
|
59
|
+
import { api } from '@/lib/api-client'
|
|
49
60
|
import type { AppView } from '@/types'
|
|
50
61
|
|
|
51
62
|
const RAIL_EXPANDED_KEY = 'sc_rail_expanded'
|
|
63
|
+
const STAR_NOTIFICATION_KEY = 'sc_star_notification_v1'
|
|
64
|
+
const GITHUB_REPO_URL = 'https://github.com/swarmclawai/swarmclaw'
|
|
52
65
|
|
|
53
66
|
export function AppLayout() {
|
|
54
67
|
const currentUser = useAppStore((s) => s.currentUser)
|
|
@@ -56,8 +69,6 @@ export function AppLayout() {
|
|
|
56
69
|
const currentSessionId = useAppStore((s) => s.currentSessionId)
|
|
57
70
|
const sidebarOpen = useAppStore((s) => s.sidebarOpen)
|
|
58
71
|
const setSidebarOpen = useAppStore((s) => s.setSidebarOpen)
|
|
59
|
-
const setUser = useAppStore((s) => s.setUser)
|
|
60
|
-
const setCurrentSession = useAppStore((s) => s.setCurrentSession)
|
|
61
72
|
const activeView = useAppStore((s) => s.activeView)
|
|
62
73
|
const setActiveView = useAppStore((s) => s.setActiveView)
|
|
63
74
|
const setAgentSheetOpen = useAppStore((s) => s.setAgentSheetOpen)
|
|
@@ -77,23 +88,25 @@ export function AppLayout() {
|
|
|
77
88
|
const hasSelectedSession = !!(currentSessionId && sessions[currentSessionId])
|
|
78
89
|
const pendingApprovalCount = Object.values(tasks).filter((t) => t.pendingApproval).length
|
|
79
90
|
|
|
91
|
+
const appSettings = useAppStore((s) => s.appSettings)
|
|
80
92
|
const [agentViewMode, setAgentViewMode] = useState<'chat' | 'config'>('chat')
|
|
81
|
-
const [
|
|
93
|
+
const [profileSheetOpen, setProfileSheetOpen] = useState(false)
|
|
82
94
|
|
|
83
95
|
const handleShortcutKey = useCallback((e: KeyboardEvent) => {
|
|
84
|
-
|
|
85
|
-
|
|
96
|
+
const mod = e.metaKey || e.ctrlKey
|
|
97
|
+
// Cmd+N / Ctrl+N — new chat
|
|
98
|
+
if (mod && !e.shiftKey && e.key.toLowerCase() === 'n') {
|
|
86
99
|
e.preventDefault()
|
|
87
|
-
|
|
100
|
+
const state = useAppStore.getState()
|
|
101
|
+
const allAgents = Object.values(state.agents).filter((a) => !a.trashedAt)
|
|
102
|
+
const target = allAgents.find((a) => a.id === 'default') || allAgents[0]
|
|
103
|
+
if (target) void state.setCurrentAgent(target.id)
|
|
88
104
|
return
|
|
89
105
|
}
|
|
90
|
-
//
|
|
91
|
-
if (
|
|
92
|
-
const tag = (e.target as HTMLElement)?.tagName?.toLowerCase()
|
|
93
|
-
const editable = (e.target as HTMLElement)?.isContentEditable
|
|
94
|
-
if (tag === 'input' || tag === 'textarea' || editable) return
|
|
106
|
+
// Cmd+Shift+T / Ctrl+Shift+T — jump to tasks
|
|
107
|
+
if (mod && e.shiftKey && e.key.toLowerCase() === 't') {
|
|
95
108
|
e.preventDefault()
|
|
96
|
-
|
|
109
|
+
useAppStore.getState().setActiveView('tasks')
|
|
97
110
|
}
|
|
98
111
|
}, [])
|
|
99
112
|
|
|
@@ -102,6 +115,31 @@ export function AppLayout() {
|
|
|
102
115
|
return () => window.removeEventListener('keydown', handleShortcutKey)
|
|
103
116
|
}, [handleShortcutKey])
|
|
104
117
|
|
|
118
|
+
useEffect(() => {
|
|
119
|
+
if (typeof window === 'undefined') return
|
|
120
|
+
if (localStorage.getItem(STAR_NOTIFICATION_KEY)) return
|
|
121
|
+
localStorage.setItem(STAR_NOTIFICATION_KEY, '1')
|
|
122
|
+
void api('POST', '/notifications', {
|
|
123
|
+
type: 'info',
|
|
124
|
+
title: 'Enjoying SwarmClaw?',
|
|
125
|
+
message: 'If SwarmClaw helps your workflow, please star the GitHub repo to support the project.',
|
|
126
|
+
actionLabel: 'Star on GitHub',
|
|
127
|
+
actionUrl: GITHUB_REPO_URL,
|
|
128
|
+
entityType: 'support',
|
|
129
|
+
entityId: 'github-star',
|
|
130
|
+
}).then(() => {
|
|
131
|
+
void useAppStore.getState().loadNotifications()
|
|
132
|
+
}).catch(() => {})
|
|
133
|
+
}, [])
|
|
134
|
+
|
|
135
|
+
// Apply theme hue on mount/change
|
|
136
|
+
useEffect(() => {
|
|
137
|
+
const hue = appSettings.themeHue
|
|
138
|
+
if (hue) {
|
|
139
|
+
document.documentElement.style.setProperty('--neutral-tint', hue)
|
|
140
|
+
}
|
|
141
|
+
}, [appSettings.themeHue])
|
|
142
|
+
|
|
105
143
|
const [railExpanded, setRailExpanded] = useState(() => {
|
|
106
144
|
if (typeof window === 'undefined') return true
|
|
107
145
|
const stored = localStorage.getItem(RAIL_EXPANDED_KEY)
|
|
@@ -115,8 +153,7 @@ export function AppLayout() {
|
|
|
115
153
|
}
|
|
116
154
|
|
|
117
155
|
const handleSwitchUser = () => {
|
|
118
|
-
|
|
119
|
-
setCurrentSession(null)
|
|
156
|
+
setProfileSheetOpen(true)
|
|
120
157
|
}
|
|
121
158
|
|
|
122
159
|
const openNewSheet = () => {
|
|
@@ -127,6 +164,7 @@ export function AppLayout() {
|
|
|
127
164
|
else if (activeView === 'providers') setProviderSheetOpen(true)
|
|
128
165
|
else if (activeView === 'skills') setSkillSheetOpen(true)
|
|
129
166
|
else if (activeView === 'connectors') setConnectorSheetOpen(true)
|
|
167
|
+
else if (activeView === 'chatrooms') useChatroomStore.getState().setChatroomSheetOpen(true)
|
|
130
168
|
else if (activeView === 'webhooks') setWebhookSheetOpen(true)
|
|
131
169
|
else if (activeView === 'mcp_servers') setMcpServerSheetOpen(true)
|
|
132
170
|
else if (activeView === 'knowledge') setKnowledgeSheetOpen(true)
|
|
@@ -149,11 +187,14 @@ export function AppLayout() {
|
|
|
149
187
|
const agents = useAppStore((s) => s.agents)
|
|
150
188
|
const currentAgentId = useAppStore((s) => s.currentAgentId)
|
|
151
189
|
const setCurrentAgent = useAppStore((s) => s.setCurrentAgent)
|
|
190
|
+
const defaultAgentId = appSettings.defaultAgentId && agents[appSettings.defaultAgentId]
|
|
191
|
+
? appSettings.defaultAgentId
|
|
192
|
+
: Object.values(agents)[0]?.id || null
|
|
193
|
+
const isMainChat = activeView === 'agents' && currentAgentId === defaultAgentId
|
|
194
|
+
|
|
152
195
|
const goToMainChat = async () => {
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
if (defaultAgent) {
|
|
156
|
-
await setCurrentAgent(defaultAgent.id)
|
|
196
|
+
if (defaultAgentId) {
|
|
197
|
+
await setCurrentAgent(defaultAgentId)
|
|
157
198
|
}
|
|
158
199
|
setActiveView('agents')
|
|
159
200
|
setSidebarOpen(false)
|
|
@@ -167,7 +208,7 @@ export function AppLayout() {
|
|
|
167
208
|
{/* Desktop: Navigation rail (expandable) */}
|
|
168
209
|
{isDesktop && (
|
|
169
210
|
<div
|
|
170
|
-
className="shrink-0 bg-raised border-r border-white/[0.04] flex flex-col py-4 transition-all duration-200 overflow-
|
|
211
|
+
className="shrink-0 bg-raised border-r border-white/[0.04] flex flex-col py-4 transition-all duration-200 overflow-visible"
|
|
171
212
|
style={{ width: railExpanded ? 180 : 60 }}
|
|
172
213
|
>
|
|
173
214
|
{/* Logo + collapse toggle */}
|
|
@@ -214,9 +255,9 @@ export function AppLayout() {
|
|
|
214
255
|
<button
|
|
215
256
|
onClick={goToMainChat}
|
|
216
257
|
className={`w-full flex items-center gap-2.5 px-3 py-2.5 rounded-[10px] text-[13px] font-600 cursor-pointer transition-all
|
|
217
|
-
${
|
|
218
|
-
? 'bg-
|
|
219
|
-
: 'bg-
|
|
258
|
+
${isMainChat
|
|
259
|
+
? 'bg-accent-bright/15 border border-[#6366F1]/25 text-accent-bright'
|
|
260
|
+
: 'bg-accent-bright/10 border border-[#6366F1]/20 text-accent-bright hover:bg-accent-bright/15'}`}
|
|
220
261
|
style={{ fontFamily: 'inherit' }}
|
|
221
262
|
>
|
|
222
263
|
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round">
|
|
@@ -229,7 +270,7 @@ export function AppLayout() {
|
|
|
229
270
|
<RailTooltip label="Main Chat" description="Your persistent assistant chat">
|
|
230
271
|
<button
|
|
231
272
|
onClick={goToMainChat}
|
|
232
|
-
className={`rail-btn self-center mb-2 ${
|
|
273
|
+
className={`rail-btn self-center mb-2 ${isMainChat ? 'active' : ''}`}
|
|
233
274
|
>
|
|
234
275
|
<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round">
|
|
235
276
|
<path d="M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z" />
|
|
@@ -238,13 +279,55 @@ export function AppLayout() {
|
|
|
238
279
|
</RailTooltip>
|
|
239
280
|
)}
|
|
240
281
|
|
|
282
|
+
{/* Search */}
|
|
283
|
+
{railExpanded ? (
|
|
284
|
+
<div className="px-3 mb-2">
|
|
285
|
+
<button
|
|
286
|
+
onClick={() => window.dispatchEvent(new CustomEvent('swarmclaw:open-search'))}
|
|
287
|
+
className="w-full flex items-center gap-2.5 px-3 py-2 rounded-[10px] text-[13px] font-500 cursor-pointer transition-all
|
|
288
|
+
bg-transparent text-text-3 hover:text-text hover:bg-white/[0.04] border-none"
|
|
289
|
+
style={{ fontFamily: 'inherit' }}
|
|
290
|
+
>
|
|
291
|
+
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round">
|
|
292
|
+
<circle cx="11" cy="11" r="8" /><line x1="21" y1="21" x2="16.65" y2="16.65" />
|
|
293
|
+
</svg>
|
|
294
|
+
Search
|
|
295
|
+
<kbd className="ml-auto px-1.5 py-0.5 rounded-[5px] bg-white/[0.06] border border-white/[0.08] text-[10px] font-mono text-text-3">
|
|
296
|
+
⌘K
|
|
297
|
+
</kbd>
|
|
298
|
+
</button>
|
|
299
|
+
</div>
|
|
300
|
+
) : (
|
|
301
|
+
<RailTooltip label="Search" description="Search across all entities (⌘K)">
|
|
302
|
+
<button
|
|
303
|
+
onClick={() => window.dispatchEvent(new CustomEvent('swarmclaw:open-search'))}
|
|
304
|
+
className="rail-btn self-center mb-2"
|
|
305
|
+
>
|
|
306
|
+
<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round">
|
|
307
|
+
<circle cx="11" cy="11" r="8" /><line x1="21" y1="21" x2="16.65" y2="16.65" />
|
|
308
|
+
</svg>
|
|
309
|
+
</button>
|
|
310
|
+
</RailTooltip>
|
|
311
|
+
)}
|
|
312
|
+
|
|
241
313
|
{/* Nav items */}
|
|
242
314
|
<div className={`flex flex-col gap-0.5 ${railExpanded ? 'px-3' : 'items-center'}`}>
|
|
315
|
+
<NavItem view="home" label="Home" expanded={railExpanded} active={activeView} sidebarOpen={sidebarOpen} onClick={() => handleNavClick('home')}>
|
|
316
|
+
<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round">
|
|
317
|
+
<path d="M3 9l9-7 9 7v11a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2z" /><polyline points="9 22 9 12 15 12 15 22" />
|
|
318
|
+
</svg>
|
|
319
|
+
</NavItem>
|
|
243
320
|
<NavItem view="agents" label="Agents" expanded={railExpanded} active={activeView} sidebarOpen={sidebarOpen} onClick={() => handleNavClick('agents')}>
|
|
244
321
|
<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round">
|
|
245
322
|
<path d="M20 21v-2a4 4 0 0 0-4-4H8a4 4 0 0 0-4 4v2" /><circle cx="12" cy="7" r="4" />
|
|
246
323
|
</svg>
|
|
247
324
|
</NavItem>
|
|
325
|
+
<NavItem view="chatrooms" label="Chatrooms" expanded={railExpanded} active={activeView} sidebarOpen={sidebarOpen} onClick={() => handleNavClick('chatrooms')}>
|
|
326
|
+
<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
|
|
327
|
+
<path d="M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z" />
|
|
328
|
+
<path d="M8 10h8" /><path d="M8 14h4" />
|
|
329
|
+
</svg>
|
|
330
|
+
</NavItem>
|
|
248
331
|
<NavItem view="projects" label="Projects" expanded={railExpanded} active={activeView} sidebarOpen={sidebarOpen} onClick={() => handleNavClick('projects')}>
|
|
249
332
|
<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round">
|
|
250
333
|
<path d="M2 20a2 2 0 0 0 2 2h16a2 2 0 0 0 2-2V8l-7-7H4a2 2 0 0 0-2 2v17Z" /><path d="M14 2v7h7" />
|
|
@@ -362,30 +445,53 @@ export function AppLayout() {
|
|
|
362
445
|
</a>
|
|
363
446
|
</RailTooltip>
|
|
364
447
|
)}
|
|
365
|
-
{railExpanded && <DaemonIndicator />}
|
|
366
448
|
{railExpanded ? (
|
|
367
|
-
<
|
|
368
|
-
|
|
449
|
+
<a
|
|
450
|
+
href={GITHUB_REPO_URL}
|
|
451
|
+
target="_blank"
|
|
452
|
+
rel="noopener noreferrer"
|
|
369
453
|
className="w-full flex items-center gap-2.5 px-3 py-2 rounded-[10px] text-[13px] font-500 cursor-pointer transition-all
|
|
370
|
-
bg-transparent text-text-3 hover:text-text hover:bg-white/[0.04]
|
|
454
|
+
bg-transparent text-text-3 hover:text-text hover:bg-white/[0.04] no-underline"
|
|
371
455
|
style={{ fontFamily: 'inherit' }}
|
|
372
456
|
>
|
|
373
457
|
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" className="shrink-0">
|
|
374
|
-
<
|
|
375
|
-
<path d="M19.4 15a1.65 1.65 0 0 0 .33 1.82l.06.06a2 2 0 0 1-2.83 2.83l-.06-.06a1.65 1.65 0 0 0-1.82-.33 1.65 1.65 0 0 0-1 1.51V21a2 2 0 0 1-4 0v-.09A1.65 1.65 0 0 0 9 19.4a1.65 1.65 0 0 0-1.82.33l-.06.06a2 2 0 0 1-2.83-2.83l.06-.06A1.65 1.65 0 0 0 4.68 15a1.65 1.65 0 0 0-1.51-1H3a2 2 0 0 1 0-4h.09A1.65 1.65 0 0 0 4.6 9a1.65 1.65 0 0 0-.33-1.82l-.06-.06a2 2 0 0 1 2.83-2.83l.06.06A1.65 1.65 0 0 0 9 4.68a1.65 1.65 0 0 0 1-1.51V3a2 2 0 0 1 4 0v.09a1.65 1.65 0 0 0 1 1.51 1.65 1.65 0 0 0 1.82-.33l.06-.06a2 2 0 0 1 2.83 2.83l-.06.06A1.65 1.65 0 0 0 19.4 9a1.65 1.65 0 0 0 1.51 1H21a2 2 0 0 1 0 4h-.09a1.65 1.65 0 0 0-1.51 1z" />
|
|
458
|
+
<polygon points="12 2 15.09 8.26 22 9.27 17 14.14 18.18 21.02 12 17.77 5.82 21.02 7 14.14 2 9.27 8.91 8.26 12 2" />
|
|
376
459
|
</svg>
|
|
377
|
-
|
|
378
|
-
|
|
460
|
+
Star on GitHub
|
|
461
|
+
<svg width="10" height="10" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.5" strokeLinecap="round" className="ml-auto opacity-40">
|
|
462
|
+
<path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6" /><polyline points="15 3 21 3 21 9" /><line x1="10" y1="14" x2="21" y2="3" />
|
|
463
|
+
</svg>
|
|
464
|
+
</a>
|
|
379
465
|
) : (
|
|
380
|
-
<RailTooltip label="
|
|
381
|
-
<
|
|
466
|
+
<RailTooltip label="Star on GitHub" description="Support SwarmClaw with a GitHub star">
|
|
467
|
+
<a
|
|
468
|
+
href={GITHUB_REPO_URL}
|
|
469
|
+
target="_blank"
|
|
470
|
+
rel="noopener noreferrer"
|
|
471
|
+
className="rail-btn"
|
|
472
|
+
>
|
|
382
473
|
<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round">
|
|
383
|
-
<
|
|
384
|
-
<path d="M19.4 15a1.65 1.65 0 0 0 .33 1.82l.06.06a2 2 0 0 1-2.83 2.83l-.06-.06a1.65 1.65 0 0 0-1.82-.33 1.65 1.65 0 0 0-1 1.51V21a2 2 0 0 1-4 0v-.09A1.65 1.65 0 0 0 9 19.4a1.65 1.65 0 0 0-1.82.33l-.06.06a2 2 0 0 1-2.83-2.83l.06-.06A1.65 1.65 0 0 0 4.68 15a1.65 1.65 0 0 0-1.51-1H3a2 2 0 0 1 0-4h.09A1.65 1.65 0 0 0 4.6 9a1.65 1.65 0 0 0-.33-1.82l-.06-.06a2 2 0 0 1 2.83-2.83l.06.06A1.65 1.65 0 0 0 9 4.68a1.65 1.65 0 0 0 1-1.51V3a2 2 0 0 1 4 0v.09a1.65 1.65 0 0 0 1 1.51 1.65 1.65 0 0 0 1.82-.33l.06-.06a2 2 0 0 1 2.83 2.83l-.06.06A1.65 1.65 0 0 0 19.4 9a1.65 1.65 0 0 0 1.51 1H21a2 2 0 0 1 0 4h-.09a1.65 1.65 0 0 0-1.51 1z" />
|
|
474
|
+
<polygon points="12 2 15.09 8.26 22 9.27 17 14.14 18.18 21.02 12 17.77 5.82 21.02 7 14.14 2 9.27 8.91 8.26 12 2" />
|
|
385
475
|
</svg>
|
|
386
|
-
</
|
|
476
|
+
</a>
|
|
477
|
+
</RailTooltip>
|
|
478
|
+
)}
|
|
479
|
+
{railExpanded && <DaemonIndicator />}
|
|
480
|
+
{railExpanded ? (
|
|
481
|
+
<NotificationCenter variant="row" align="left" direction="up" />
|
|
482
|
+
) : (
|
|
483
|
+
<RailTooltip label="Notifications" description="View system notifications">
|
|
484
|
+
<div className="rail-btn flex items-center justify-center">
|
|
485
|
+
<NotificationCenter align="left" direction="up" />
|
|
486
|
+
</div>
|
|
387
487
|
</RailTooltip>
|
|
388
488
|
)}
|
|
489
|
+
<NavItem view="settings" label="Settings" expanded={railExpanded} active={activeView} sidebarOpen={sidebarOpen} onClick={() => handleNavClick('settings')}>
|
|
490
|
+
<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round">
|
|
491
|
+
<circle cx="12" cy="12" r="3" />
|
|
492
|
+
<path d="M19.4 15a1.65 1.65 0 0 0 .33 1.82l.06.06a2 2 0 0 1-2.83 2.83l-.06-.06a1.65 1.65 0 0 0-1.82-.33 1.65 1.65 0 0 0-1 1.51V21a2 2 0 0 1-4 0v-.09A1.65 1.65 0 0 0 9 19.4a1.65 1.65 0 0 0-1.82.33l-.06.06a2 2 0 0 1-2.83-2.83l.06-.06A1.65 1.65 0 0 0 4.68 15a1.65 1.65 0 0 0-1.51-1H3a2 2 0 0 1 0-4h.09A1.65 1.65 0 0 0 4.6 9a1.65 1.65 0 0 0-.33-1.82l-.06-.06a2 2 0 0 1 2.83-2.83l.06.06A1.65 1.65 0 0 0 9 4.68a1.65 1.65 0 0 0 1-1.51V3a2 2 0 0 1 4 0v.09a1.65 1.65 0 0 0 1 1.51 1.65 1.65 0 0 0 1.82-.33l.06-.06a2 2 0 0 1 2.83 2.83l-.06.06A1.65 1.65 0 0 0 19.4 9a1.65 1.65 0 0 0 1.51 1H21a2 2 0 0 1 0 4h-.09a1.65 1.65 0 0 0-1.51 1z" />
|
|
493
|
+
</svg>
|
|
494
|
+
</NavItem>
|
|
389
495
|
|
|
390
496
|
{railExpanded ? (
|
|
391
497
|
<button
|
|
@@ -394,13 +500,13 @@ export function AppLayout() {
|
|
|
394
500
|
bg-transparent hover:bg-white/[0.04] border-none"
|
|
395
501
|
style={{ fontFamily: 'inherit' }}
|
|
396
502
|
>
|
|
397
|
-
<Avatar user={currentUser!} size="sm" />
|
|
503
|
+
<Avatar user={currentUser!} size="sm" avatarSeed={appSettings.userAvatarSeed} />
|
|
398
504
|
<span className="text-[13px] font-500 text-text-2 capitalize truncate">{currentUser}</span>
|
|
399
505
|
</button>
|
|
400
506
|
) : (
|
|
401
|
-
<RailTooltip label="
|
|
507
|
+
<RailTooltip label="Profile" description="Edit your profile">
|
|
402
508
|
<button onClick={handleSwitchUser} className="mt-2 bg-transparent border-none cursor-pointer shrink-0">
|
|
403
|
-
<Avatar user={currentUser!} size="sm" />
|
|
509
|
+
<Avatar user={currentUser!} size="sm" avatarSeed={appSettings.userAvatarSeed} />
|
|
404
510
|
</button>
|
|
405
511
|
</RailTooltip>
|
|
406
512
|
)}
|
|
@@ -419,7 +525,7 @@ export function AppLayout() {
|
|
|
419
525
|
{activeView === 'logs' || activeView === 'usage' || activeView === 'runs' ? null : activeView === 'memory' ? (
|
|
420
526
|
<button
|
|
421
527
|
onClick={() => useAppStore.getState().setMemorySheetOpen(true)}
|
|
422
|
-
className="flex items-center gap-1.5 px-2.5 py-1.5 rounded-[8px] text-[11px] font-600 text-accent-bright bg-accent-soft hover:bg-
|
|
528
|
+
className="flex items-center gap-1.5 px-2.5 py-1.5 rounded-[8px] text-[11px] font-600 text-accent-bright bg-accent-soft hover:bg-accent-bright/15 transition-all cursor-pointer"
|
|
423
529
|
style={{ fontFamily: 'inherit' }}
|
|
424
530
|
>
|
|
425
531
|
<svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.5" strokeLinecap="round">
|
|
@@ -430,7 +536,7 @@ export function AppLayout() {
|
|
|
430
536
|
) : (
|
|
431
537
|
<button
|
|
432
538
|
onClick={openNewSheet}
|
|
433
|
-
className="flex items-center gap-1.5 px-2.5 py-1.5 rounded-[8px] text-[11px] font-600 text-accent-bright bg-accent-soft hover:bg-
|
|
539
|
+
className="flex items-center gap-1.5 px-2.5 py-1.5 rounded-[8px] text-[11px] font-600 text-accent-bright bg-accent-soft hover:bg-accent-bright/15 transition-all cursor-pointer"
|
|
434
540
|
style={{ fontFamily: 'inherit' }}
|
|
435
541
|
>
|
|
436
542
|
<svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.5" strokeLinecap="round">
|
|
@@ -460,7 +566,7 @@ export function AppLayout() {
|
|
|
460
566
|
</>
|
|
461
567
|
)}
|
|
462
568
|
{activeView === 'schedules' && <ScheduleList inSidebar />}
|
|
463
|
-
{activeView === 'memory' && <
|
|
569
|
+
{activeView === 'memory' && <MemoryAgentList />}
|
|
464
570
|
{activeView === 'tasks' && <TaskList inSidebar />}
|
|
465
571
|
{activeView === 'secrets' && <SecretsList inSidebar />}
|
|
466
572
|
{activeView === 'providers' && <ProviderList inSidebar />}
|
|
@@ -495,19 +601,19 @@ export function AppLayout() {
|
|
|
495
601
|
<path d="M2 3h6a4 4 0 0 1 4 4v14a3 3 0 0 0-3-3H2z" /><path d="M22 3h-6a4 4 0 0 0-4 4v14a3 3 0 0 1 3-3h7z" />
|
|
496
602
|
</svg>
|
|
497
603
|
</a>
|
|
498
|
-
<button onClick={() => handleNavClick('settings')} className=
|
|
604
|
+
<button onClick={() => handleNavClick('settings')} className={`rail-btn ${activeView === 'settings' ? 'active' : ''}`}>
|
|
499
605
|
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round">
|
|
500
606
|
<circle cx="12" cy="12" r="3" />
|
|
501
607
|
<path d="M19.4 15a1.65 1.65 0 0 0 .33 1.82l.06.06a2 2 0 0 1-2.83 2.83l-.06-.06a1.65 1.65 0 0 0-1.82-.33 1.65 1.65 0 0 0-1 1.51V21a2 2 0 0 1-4 0v-.09A1.65 1.65 0 0 0 9 19.4a1.65 1.65 0 0 0-1.82.33l-.06.06a2 2 0 0 1-2.83-2.83l.06-.06A1.65 1.65 0 0 0 4.68 15a1.65 1.65 0 0 0-1.51-1H3a2 2 0 0 1 0-4h.09A1.65 1.65 0 0 0 4.6 9a1.65 1.65 0 0 0-.33-1.82l-.06-.06a2 2 0 0 1 2.83-2.83l.06.06A1.65 1.65 0 0 0 9 4.68a1.65 1.65 0 0 0 1-1.51V3a2 2 0 0 1 4 0v.09a1.65 1.65 0 0 0 1 1.51 1.65 1.65 0 0 0 1.82-.33l.06-.06a2 2 0 0 1 2.83 2.83l-.06.06A1.65 1.65 0 0 0 19.4 9a1.65 1.65 0 0 0 1.51 1H21a2 2 0 0 1 0 4h-.09a1.65 1.65 0 0 0-1.51 1z" />
|
|
502
608
|
</svg>
|
|
503
609
|
</button>
|
|
504
610
|
<button onClick={handleSwitchUser} className="bg-transparent border-none cursor-pointer shrink-0">
|
|
505
|
-
<Avatar user={currentUser!} size="sm" />
|
|
611
|
+
<Avatar user={currentUser!} size="sm" avatarSeed={appSettings.userAvatarSeed} />
|
|
506
612
|
</button>
|
|
507
613
|
</div>
|
|
508
614
|
{/* View selector tabs */}
|
|
509
615
|
<div className="flex px-4 py-2 gap-1 shrink-0 flex-wrap">
|
|
510
|
-
{(['agents', 'schedules', 'memory', 'tasks', 'secrets', 'providers', 'skills', 'connectors', 'webhooks', 'mcp_servers', 'knowledge', 'plugins', 'usage', 'runs', 'logs'] as AppView[]).map((v) => (
|
|
616
|
+
{(['agents', 'chatrooms', 'schedules', 'memory', 'tasks', 'secrets', 'providers', 'skills', 'connectors', 'webhooks', 'mcp_servers', 'knowledge', 'plugins', 'usage', 'runs', 'logs'] as AppView[]).map((v) => (
|
|
511
617
|
<button
|
|
512
618
|
key={v}
|
|
513
619
|
onClick={() => setActiveView(v)}
|
|
@@ -528,7 +634,7 @@ export function AppLayout() {
|
|
|
528
634
|
setSidebarOpen(false)
|
|
529
635
|
openNewSheet()
|
|
530
636
|
}}
|
|
531
|
-
className="w-full py-3 rounded-[12px] border-none bg-
|
|
637
|
+
className="w-full py-3 rounded-[12px] border-none bg-accent-bright text-white text-[14px] font-600 cursor-pointer
|
|
532
638
|
hover:brightness-110 active:scale-[0.98] transition-all
|
|
533
639
|
shadow-[0_2px_12px_rgba(99,102,241,0.15)]"
|
|
534
640
|
style={{ fontFamily: 'inherit' }}
|
|
@@ -556,7 +662,7 @@ export function AppLayout() {
|
|
|
556
662
|
</>
|
|
557
663
|
)}
|
|
558
664
|
{activeView === 'schedules' && <ScheduleList inSidebar />}
|
|
559
|
-
{activeView === 'memory' && <
|
|
665
|
+
{activeView === 'memory' && <MemoryAgentList />}
|
|
560
666
|
{activeView === 'tasks' && <TaskList inSidebar />}
|
|
561
667
|
{activeView === 'secrets' && <SecretsList inSidebar />}
|
|
562
668
|
{activeView === 'providers' && <ProviderList inSidebar />}
|
|
@@ -566,7 +672,6 @@ export function AppLayout() {
|
|
|
566
672
|
{activeView === 'mcp_servers' && <McpServerList />}
|
|
567
673
|
{activeView === 'knowledge' && <KnowledgeList />}
|
|
568
674
|
{activeView === 'plugins' && <PluginList inSidebar />}
|
|
569
|
-
{activeView === 'projects' && <ProjectList />}
|
|
570
675
|
{activeView === 'runs' && <RunList />}
|
|
571
676
|
{activeView === 'logs' && <LogList />}
|
|
572
677
|
</div>
|
|
@@ -577,7 +682,9 @@ export function AppLayout() {
|
|
|
577
682
|
<ErrorBoundary>
|
|
578
683
|
<div className="flex-1 flex flex-col h-full min-w-0 bg-bg">
|
|
579
684
|
{!isDesktop && <MobileHeader />}
|
|
580
|
-
{activeView === '
|
|
685
|
+
{activeView === 'home' ? (
|
|
686
|
+
<HomeView />
|
|
687
|
+
) : activeView === 'agents' && hasSelectedSession ? (
|
|
581
688
|
<ChatArea />
|
|
582
689
|
) : activeView === 'agents' ? (
|
|
583
690
|
<div className="flex-1 flex flex-col">
|
|
@@ -599,11 +706,38 @@ export function AppLayout() {
|
|
|
599
706
|
) : activeView === 'tasks' && isDesktop ? (
|
|
600
707
|
<TaskBoard />
|
|
601
708
|
) : activeView === 'memory' ? (
|
|
602
|
-
<
|
|
709
|
+
<MemoryBrowser />
|
|
603
710
|
) : activeView === 'activity' ? (
|
|
604
711
|
<ActivityFeed />
|
|
605
712
|
) : activeView === 'usage' ? (
|
|
606
713
|
<MetricsDashboard />
|
|
714
|
+
) : activeView === 'chatrooms' ? (
|
|
715
|
+
<div className="flex-1 flex h-full min-w-0">
|
|
716
|
+
<div className="w-[280px] shrink-0 border-r border-white/[0.06] flex flex-col">
|
|
717
|
+
<div className="flex items-center px-4 pt-4 pb-2 shrink-0">
|
|
718
|
+
<h2 className="font-display text-[14px] font-600 text-text-2 tracking-[-0.01em] flex-1">Chatrooms</h2>
|
|
719
|
+
<button
|
|
720
|
+
onClick={() => { useChatroomStore.getState().setEditingChatroomId(null); useChatroomStore.getState().setChatroomSheetOpen(true) }}
|
|
721
|
+
className="flex items-center gap-1 px-2 py-1 rounded-[6px] text-[11px] font-600 text-accent-bright bg-accent-soft hover:bg-accent-bright/15 transition-all cursor-pointer"
|
|
722
|
+
style={{ fontFamily: 'inherit' }}
|
|
723
|
+
>
|
|
724
|
+
<svg width="10" height="10" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.5" strokeLinecap="round">
|
|
725
|
+
<line x1="12" y1="5" x2="12" y2="19" /><line x1="5" y1="12" x2="19" y2="12" />
|
|
726
|
+
</svg>
|
|
727
|
+
New
|
|
728
|
+
</button>
|
|
729
|
+
</div>
|
|
730
|
+
<ChatroomList />
|
|
731
|
+
</div>
|
|
732
|
+
<ChatroomView />
|
|
733
|
+
</div>
|
|
734
|
+
) : activeView === 'projects' ? (
|
|
735
|
+
<div className="flex-1 flex h-full min-w-0">
|
|
736
|
+
<div className="w-[280px] shrink-0 border-r border-white/[0.06] flex flex-col">
|
|
737
|
+
<ProjectList />
|
|
738
|
+
</div>
|
|
739
|
+
<ProjectDetail />
|
|
740
|
+
</div>
|
|
607
741
|
) : activeView === 'settings' ? (
|
|
608
742
|
<SettingsPage />
|
|
609
743
|
) : !sidebarOpen && FULL_WIDTH_VIEWS.has(activeView) ? (
|
|
@@ -615,13 +749,13 @@ export function AppLayout() {
|
|
|
615
749
|
{activeView !== 'runs' && activeView !== 'logs' && (
|
|
616
750
|
<button
|
|
617
751
|
onClick={openNewSheet}
|
|
618
|
-
className="flex items-center gap-1.5 px-2.5 py-1.5 rounded-[8px] text-[11px] font-600 text-accent-bright bg-accent-soft hover:bg-
|
|
752
|
+
className="flex items-center gap-1.5 px-2.5 py-1.5 rounded-[8px] text-[11px] font-600 text-accent-bright bg-accent-soft hover:bg-accent-bright/15 transition-all cursor-pointer"
|
|
619
753
|
style={{ fontFamily: 'inherit' }}
|
|
620
754
|
>
|
|
621
755
|
<svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.5" strokeLinecap="round">
|
|
622
756
|
<line x1="12" y1="5" x2="12" y2="19" /><line x1="5" y1="12" x2="19" y2="12" />
|
|
623
757
|
</svg>
|
|
624
|
-
{activeView === 'schedules' ? 'Schedule' : activeView === 'secrets' ? 'Secret' : activeView === 'providers' ? 'Provider' : activeView === 'skills' ? 'Skill' : activeView === 'connectors' ? 'Connector' : activeView === 'webhooks' ? 'Webhook' : activeView === 'mcp_servers' ? 'MCP Server' : activeView === 'knowledge' ? 'Knowledge' : activeView === 'plugins' ? 'Plugin' :
|
|
758
|
+
{activeView === 'schedules' ? 'Schedule' : activeView === 'secrets' ? 'Secret' : activeView === 'providers' ? 'Provider' : activeView === 'skills' ? 'Skill' : activeView === 'connectors' ? 'Connector' : activeView === 'webhooks' ? 'Webhook' : activeView === 'mcp_servers' ? 'MCP Server' : activeView === 'knowledge' ? 'Knowledge' : activeView === 'plugins' ? 'Plugin' : 'New'}
|
|
625
759
|
</button>
|
|
626
760
|
)}
|
|
627
761
|
</div>
|
|
@@ -634,7 +768,6 @@ export function AppLayout() {
|
|
|
634
768
|
{activeView === 'mcp_servers' && <McpServerList />}
|
|
635
769
|
{activeView === 'knowledge' && <KnowledgeList />}
|
|
636
770
|
{activeView === 'plugins' && <PluginList />}
|
|
637
|
-
{activeView === 'projects' && <ProjectList />}
|
|
638
771
|
{activeView === 'runs' && <RunList />}
|
|
639
772
|
{activeView === 'logs' && <LogList />}
|
|
640
773
|
</div>
|
|
@@ -644,6 +777,9 @@ export function AppLayout() {
|
|
|
644
777
|
</div>
|
|
645
778
|
</ErrorBoundary>
|
|
646
779
|
|
|
780
|
+
<SearchDialog />
|
|
781
|
+
<AgentSwitchDialog />
|
|
782
|
+
<KeyboardShortcutsDialog />
|
|
647
783
|
<AgentSheet />
|
|
648
784
|
<ScheduleSheet />
|
|
649
785
|
<MemorySheet />
|
|
@@ -652,32 +788,14 @@ export function AppLayout() {
|
|
|
652
788
|
<ProviderSheet />
|
|
653
789
|
<SkillSheet />
|
|
654
790
|
<ConnectorSheet />
|
|
791
|
+
<ChatroomSheet />
|
|
655
792
|
<WebhookSheet />
|
|
656
793
|
<McpServerSheet />
|
|
657
794
|
<KnowledgeSheet />
|
|
658
795
|
<PluginSheet />
|
|
659
796
|
<ProjectSheet />
|
|
797
|
+
<ProfileSheet open={profileSheetOpen} onClose={() => setProfileSheetOpen(false)} />
|
|
660
798
|
|
|
661
|
-
<Dialog open={shortcutsOpen} onOpenChange={setShortcutsOpen}>
|
|
662
|
-
<DialogContent className="sm:max-w-[380px] bg-raised border-white/[0.08]">
|
|
663
|
-
<DialogHeader>
|
|
664
|
-
<DialogTitle className="text-text">Keyboard Shortcuts</DialogTitle>
|
|
665
|
-
</DialogHeader>
|
|
666
|
-
<div className="space-y-3 py-2">
|
|
667
|
-
{([
|
|
668
|
-
['Enter', 'Send message'],
|
|
669
|
-
['Shift + Enter', 'New line'],
|
|
670
|
-
['Ctrl + F', 'Search in chat'],
|
|
671
|
-
['Ctrl + /', 'Show shortcuts'],
|
|
672
|
-
] as const).map(([keys, desc]) => (
|
|
673
|
-
<div key={keys} className="flex items-center justify-between">
|
|
674
|
-
<span className="text-[13px] text-text-2">{desc}</span>
|
|
675
|
-
<kbd className="px-2 py-1 rounded-[6px] bg-white/[0.06] border border-white/[0.08] text-[11px] font-mono text-text-3">{keys}</kbd>
|
|
676
|
-
</div>
|
|
677
|
-
))}
|
|
678
|
-
</div>
|
|
679
|
-
</DialogContent>
|
|
680
|
-
</Dialog>
|
|
681
799
|
</div>
|
|
682
800
|
)
|
|
683
801
|
}
|
|
@@ -716,7 +834,7 @@ class ErrorBoundary extends Component<{ children: ReactNode }, { hasError: boole
|
|
|
716
834
|
</p>
|
|
717
835
|
<button
|
|
718
836
|
onClick={() => window.location.reload()}
|
|
719
|
-
className="inline-flex items-center gap-2 px-6 py-3 rounded-[12px] border-none bg-
|
|
837
|
+
className="inline-flex items-center gap-2 px-6 py-3 rounded-[12px] border-none bg-accent-bright text-white text-[14px] font-600 cursor-pointer
|
|
720
838
|
hover:brightness-110 active:scale-[0.97] transition-all shadow-[0_4px_16px_rgba(99,102,241,0.2)]"
|
|
721
839
|
style={{ fontFamily: 'inherit' }}
|
|
722
840
|
>
|
|
@@ -736,7 +854,9 @@ class ErrorBoundary extends Component<{ children: ReactNode }, { hasError: boole
|
|
|
736
854
|
}
|
|
737
855
|
|
|
738
856
|
const VIEW_DESCRIPTIONS: Record<AppView, string> = {
|
|
857
|
+
home: 'Dashboard overview',
|
|
739
858
|
agents: 'Chat with & configure your AI agents',
|
|
859
|
+
chatrooms: 'Multi-agent collaborative chatrooms',
|
|
740
860
|
schedules: 'Automated task schedules',
|
|
741
861
|
memory: 'Long-term agent memory store',
|
|
742
862
|
tasks: 'Task board for orchestrator jobs',
|
|
@@ -757,12 +877,18 @@ const VIEW_DESCRIPTIONS: Record<AppView, string> = {
|
|
|
757
877
|
}
|
|
758
878
|
|
|
759
879
|
const FULL_WIDTH_VIEWS = new Set<AppView>([
|
|
760
|
-
'schedules', 'secrets', 'providers', 'skills',
|
|
880
|
+
'home', 'chatrooms', 'schedules', 'secrets', 'providers', 'skills',
|
|
761
881
|
'connectors', 'webhooks', 'mcp_servers', 'knowledge', 'plugins',
|
|
762
|
-
'usage', 'runs', 'logs', 'settings', '
|
|
882
|
+
'usage', 'runs', 'logs', 'settings', 'activity', 'projects',
|
|
763
883
|
])
|
|
764
884
|
|
|
765
|
-
const VIEW_EMPTY_STATES: Record<Exclude<AppView, 'agents'>, { icon: string; title: string; description: string; features: string[] }> = {
|
|
885
|
+
const VIEW_EMPTY_STATES: Record<Exclude<AppView, 'agents' | 'home'>, { icon: string; title: string; description: string; features: string[] }> = {
|
|
886
|
+
chatrooms: {
|
|
887
|
+
icon: 'message-square',
|
|
888
|
+
title: 'Chatrooms',
|
|
889
|
+
description: 'Multi-agent chatrooms for collaborative conversations. Add agents and use @mentions to trigger responses.',
|
|
890
|
+
features: ['Create chatrooms with multiple AI agents', 'Use @AgentName to trigger specific agents', '@all mentions trigger all agents sequentially', 'Agents can chain by mentioning each other'],
|
|
891
|
+
},
|
|
766
892
|
schedules: {
|
|
767
893
|
icon: 'clock',
|
|
768
894
|
title: 'Schedules',
|
|
@@ -868,8 +994,8 @@ const VIEW_EMPTY_STATES: Record<Exclude<AppView, 'agents'>, { icon: string; titl
|
|
|
868
994
|
}
|
|
869
995
|
|
|
870
996
|
function ViewEmptyState({ view }: { view: AppView }) {
|
|
871
|
-
if (view === 'agents') return null
|
|
872
|
-
const config = VIEW_EMPTY_STATES[view as Exclude<AppView, 'agents'>]
|
|
997
|
+
if (view === 'agents' || view === 'home') return null
|
|
998
|
+
const config = VIEW_EMPTY_STATES[view as Exclude<AppView, 'agents' | 'home'>]
|
|
873
999
|
if (!config) return null
|
|
874
1000
|
|
|
875
1001
|
return (
|
|
@@ -1056,7 +1182,7 @@ function DesktopEmptyState({ userName }: { userName: string | null }) {
|
|
|
1056
1182
|
</p>
|
|
1057
1183
|
<button
|
|
1058
1184
|
onClick={() => setNewSessionOpen(true)}
|
|
1059
|
-
className="inline-flex items-center gap-2.5 px-12 py-4 rounded-[16px] border-none bg-
|
|
1185
|
+
className="inline-flex items-center gap-2.5 px-12 py-4 rounded-[16px] border-none bg-accent-bright text-white text-[16px] font-display font-600
|
|
1060
1186
|
cursor-pointer hover:brightness-110 active:scale-[0.97] transition-all duration-200
|
|
1061
1187
|
shadow-[0_6px_28px_rgba(99,102,241,0.3)]"
|
|
1062
1188
|
style={{ fontFamily: 'inherit' }}
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
import { useAppStore } from '@/stores/use-app-store'
|
|
4
4
|
import { IconButton } from '@/components/shared/icon-button'
|
|
5
|
+
import { NotificationCenter } from '@/components/shared/notification-center'
|
|
5
6
|
|
|
6
7
|
export function MobileHeader() {
|
|
7
8
|
const toggleSidebar = useAppStore((s) => s.toggleSidebar)
|
|
@@ -26,6 +27,7 @@ export function MobileHeader() {
|
|
|
26
27
|
<span className="font-700">SwarmClaw</span>
|
|
27
28
|
)}
|
|
28
29
|
</h1>
|
|
30
|
+
<NotificationCenter />
|
|
29
31
|
</header>
|
|
30
32
|
)
|
|
31
33
|
}
|
|
@@ -63,7 +63,7 @@ export function UpdateBanner() {
|
|
|
63
63
|
if (dismissed === version.remoteSha && updateState === 'idle') return null
|
|
64
64
|
|
|
65
65
|
return (
|
|
66
|
-
<div className="px-4 py-1.5 border-b border-white/[0.04] text-[10px] flex items-center gap-2 shrink-0 bg-
|
|
66
|
+
<div className="px-4 py-1.5 border-b border-white/[0.04] text-[10px] flex items-center gap-2 shrink-0 bg-accent-bright/[0.04]">
|
|
67
67
|
{updateState === 'idle' && (
|
|
68
68
|
<>
|
|
69
69
|
<svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" className="text-accent-bright shrink-0">
|
|
@@ -74,7 +74,7 @@ export function UpdateBanner() {
|
|
|
74
74
|
</span>
|
|
75
75
|
<button
|
|
76
76
|
onClick={handleUpdate}
|
|
77
|
-
className="text-[10px] font-600 text-accent-bright hover:text-white bg-
|
|
77
|
+
className="text-[10px] font-600 text-accent-bright hover:text-white bg-accent-bright/20 hover:bg-accent-bright/30 px-2 py-0.5 rounded-[6px] border-none cursor-pointer transition-all shrink-0"
|
|
78
78
|
style={{ fontFamily: 'inherit' }}
|
|
79
79
|
>
|
|
80
80
|
Update
|