@swarmclawai/swarmclaw 0.6.8 → 0.7.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 +70 -45
- package/next.config.ts +31 -6
- package/package.json +3 -2
- package/src/app/api/agents/[id]/thread/route.ts +1 -0
- package/src/app/api/agents/route.ts +18 -5
- package/src/app/api/approvals/route.ts +22 -0
- package/src/app/api/clawhub/install/route.ts +2 -2
- package/src/app/api/mcp-servers/[id]/conformance/route.ts +26 -0
- package/src/app/api/mcp-servers/[id]/invoke/route.ts +81 -0
- package/src/app/api/memory/route.ts +36 -5
- package/src/app/api/notifications/route.ts +3 -0
- package/src/app/api/plugins/install/route.ts +57 -5
- package/src/app/api/plugins/marketplace/route.ts +73 -22
- package/src/app/api/plugins/route.ts +61 -1
- package/src/app/api/plugins/ui/route.ts +34 -0
- package/src/app/api/settings/route.ts +62 -0
- package/src/app/api/setup/doctor/route.ts +22 -5
- package/src/app/api/tasks/[id]/approve/route.ts +4 -3
- package/src/app/api/tasks/[id]/route.ts +11 -3
- package/src/app/api/tasks/route.ts +8 -2
- package/src/app/globals.css +27 -0
- package/src/app/page.tsx +10 -5
- package/src/cli/index.js +13 -0
- package/src/components/activity/activity-feed.tsx +9 -2
- package/src/components/agents/agent-avatar.tsx +5 -1
- package/src/components/agents/agent-card.tsx +55 -9
- package/src/components/agents/agent-sheet.tsx +86 -29
- package/src/components/agents/inspector-panel.tsx +1 -1
- package/src/components/auth/access-key-gate.tsx +63 -54
- package/src/components/auth/user-picker.tsx +37 -32
- package/src/components/chat/chat-area.tsx +11 -0
- package/src/components/chat/chat-header.tsx +69 -25
- package/src/components/chat/chat-tool-toggles.tsx +2 -2
- package/src/components/chat/code-block.tsx +3 -1
- package/src/components/chat/exec-approval-card.tsx +8 -1
- package/src/components/chat/message-bubble.tsx +164 -4
- package/src/components/chat/message-list.tsx +30 -4
- package/src/components/chat/session-approval-card.tsx +80 -0
- package/src/components/chat/streaming-bubble.tsx +6 -5
- package/src/components/chat/thinking-indicator.tsx +48 -12
- package/src/components/chat/tool-request-banner.tsx +39 -20
- package/src/components/chatrooms/chatroom-list.tsx +11 -4
- package/src/components/chatrooms/chatroom-sheet.tsx +7 -2
- package/src/components/connectors/connector-list.tsx +33 -11
- package/src/components/connectors/connector-sheet.tsx +29 -6
- package/src/components/home/home-view.tsx +20 -14
- package/src/components/input/chat-input.tsx +22 -1
- package/src/components/knowledge/knowledge-list.tsx +17 -18
- package/src/components/knowledge/knowledge-sheet.tsx +9 -5
- package/src/components/layout/app-layout.tsx +73 -21
- package/src/components/mcp-servers/mcp-server-list.tsx +352 -50
- package/src/components/mcp-servers/mcp-server-sheet.tsx +25 -9
- package/src/components/memory/memory-list.tsx +20 -13
- package/src/components/plugins/plugin-list.tsx +213 -59
- package/src/components/plugins/plugin-sheet.tsx +119 -24
- package/src/components/projects/project-list.tsx +17 -9
- package/src/components/providers/provider-list.tsx +21 -6
- package/src/components/providers/provider-sheet.tsx +42 -25
- package/src/components/runs/run-list.tsx +17 -13
- package/src/components/schedules/schedule-card.tsx +10 -3
- package/src/components/schedules/schedule-list.tsx +2 -2
- package/src/components/schedules/schedule-sheet.tsx +19 -7
- package/src/components/secrets/secret-sheet.tsx +7 -2
- package/src/components/secrets/secrets-list.tsx +18 -5
- package/src/components/sessions/new-session-sheet.tsx +183 -376
- package/src/components/sessions/session-card.tsx +10 -2
- package/src/components/settings/gateway-connection-panel.tsx +9 -8
- package/src/components/shared/command-palette.tsx +13 -5
- package/src/components/shared/empty-state.tsx +20 -8
- package/src/components/shared/notification-center.tsx +134 -86
- package/src/components/shared/profile-sheet.tsx +4 -0
- package/src/components/shared/settings/plugin-manager.tsx +360 -135
- package/src/components/shared/settings/section-capability-policy.tsx +3 -3
- package/src/components/shared/settings/section-runtime-loop.tsx +144 -0
- package/src/components/skills/clawhub-browser.tsx +1 -0
- package/src/components/skills/skill-list.tsx +31 -12
- package/src/components/skills/skill-sheet.tsx +20 -7
- package/src/components/tasks/approvals-panel.tsx +170 -66
- package/src/components/tasks/task-board.tsx +20 -12
- package/src/components/tasks/task-card.tsx +21 -7
- package/src/components/tasks/task-column.tsx +4 -3
- package/src/components/tasks/task-list.tsx +1 -1
- package/src/components/tasks/task-sheet.tsx +130 -1
- package/src/components/ui/dialog.tsx +1 -0
- package/src/components/ui/sheet.tsx +1 -0
- package/src/components/usage/metrics-dashboard.tsx +66 -64
- package/src/components/wallets/wallet-panel.tsx +65 -41
- package/src/components/wallets/wallet-section.tsx +9 -3
- package/src/components/webhooks/webhook-list.tsx +21 -12
- package/src/components/webhooks/webhook-sheet.tsx +13 -3
- package/src/lib/approval-display.test.ts +45 -0
- package/src/lib/approval-display.ts +62 -0
- package/src/lib/clipboard.ts +38 -0
- package/src/lib/memory.ts +8 -0
- package/src/lib/providers/claude-cli.ts +5 -3
- package/src/lib/providers/index.ts +67 -21
- package/src/lib/runtime-loop.ts +3 -2
- package/src/lib/server/approvals.ts +150 -0
- package/src/lib/server/chat-execution.ts +223 -62
- package/src/lib/server/clawhub-client.ts +82 -6
- package/src/lib/server/connectors/manager.ts +27 -1
- package/src/lib/server/cost.test.ts +73 -0
- package/src/lib/server/cost.ts +165 -34
- package/src/lib/server/daemon-state.ts +42 -0
- package/src/lib/server/data-dir.ts +18 -1
- package/src/lib/server/integrity-monitor.ts +208 -0
- package/src/lib/server/llm-response-cache.test.ts +102 -0
- package/src/lib/server/llm-response-cache.ts +227 -0
- package/src/lib/server/main-agent-loop.ts +1 -1
- package/src/lib/server/main-session.ts +6 -3
- package/src/lib/server/mcp-conformance.test.ts +18 -0
- package/src/lib/server/mcp-conformance.ts +233 -0
- package/src/lib/server/memory-db.ts +180 -17
- package/src/lib/server/memory-retrieval.test.ts +56 -0
- package/src/lib/server/orchestrator-lg.ts +4 -1
- package/src/lib/server/orchestrator.ts +4 -3
- package/src/lib/server/plugins.ts +650 -142
- package/src/lib/server/process-manager.ts +18 -0
- package/src/lib/server/queue.ts +253 -11
- package/src/lib/server/runtime-settings.ts +9 -0
- package/src/lib/server/session-run-manager.test.ts +23 -0
- package/src/lib/server/session-run-manager.ts +11 -1
- package/src/lib/server/session-tools/canvas.ts +85 -50
- package/src/lib/server/session-tools/chatroom.ts +130 -127
- package/src/lib/server/session-tools/connector.ts +233 -454
- package/src/lib/server/session-tools/context-mgmt.ts +87 -105
- package/src/lib/server/session-tools/crud.ts +84 -7
- package/src/lib/server/session-tools/delegate.ts +351 -752
- package/src/lib/server/session-tools/discovery.ts +198 -0
- package/src/lib/server/session-tools/edit_file.ts +82 -0
- package/src/lib/server/session-tools/file-send.test.ts +39 -0
- package/src/lib/server/session-tools/file.ts +257 -425
- package/src/lib/server/session-tools/git.ts +87 -47
- package/src/lib/server/session-tools/http.ts +85 -33
- package/src/lib/server/session-tools/index.ts +205 -160
- package/src/lib/server/session-tools/memory.ts +152 -265
- package/src/lib/server/session-tools/monitor.ts +126 -0
- package/src/lib/server/session-tools/normalize-tool-args.test.ts +61 -0
- package/src/lib/server/session-tools/normalize-tool-args.ts +48 -0
- package/src/lib/server/session-tools/openclaw-nodes.ts +82 -99
- package/src/lib/server/session-tools/openclaw-workspace.ts +103 -93
- package/src/lib/server/session-tools/platform.ts +86 -0
- package/src/lib/server/session-tools/plugin-creator.ts +239 -0
- package/src/lib/server/session-tools/sample-ui.ts +97 -0
- package/src/lib/server/session-tools/sandbox.ts +175 -148
- package/src/lib/server/session-tools/schedule.ts +66 -31
- package/src/lib/server/session-tools/session-info.ts +104 -410
- package/src/lib/server/session-tools/shell-normalize.test.ts +43 -0
- package/src/lib/server/session-tools/shell.ts +171 -143
- package/src/lib/server/session-tools/subagent.ts +77 -77
- package/src/lib/server/session-tools/wallet.ts +182 -106
- package/src/lib/server/session-tools/web.ts +179 -349
- package/src/lib/server/storage.ts +24 -0
- package/src/lib/server/stream-agent-chat.ts +301 -244
- package/src/lib/server/task-quality-gate.test.ts +44 -0
- package/src/lib/server/task-quality-gate.ts +67 -0
- package/src/lib/server/task-validation.test.ts +78 -0
- package/src/lib/server/task-validation.ts +67 -2
- package/src/lib/server/tool-aliases.ts +68 -0
- package/src/lib/server/tool-capability-policy.ts +23 -5
- package/src/lib/tasks.ts +7 -1
- package/src/lib/tool-definitions.ts +23 -23
- package/src/lib/validation/schemas.ts +12 -0
- package/src/lib/view-routes.ts +2 -24
- package/src/stores/use-app-store.ts +23 -1
- package/src/types/index.ts +121 -7
|
@@ -5,6 +5,7 @@ import { api } from '@/lib/api-client'
|
|
|
5
5
|
import { useAppStore } from '@/stores/use-app-store'
|
|
6
6
|
import { Badge } from '@/components/ui/badge'
|
|
7
7
|
import { AgentAvatar } from '@/components/agents/agent-avatar'
|
|
8
|
+
import { EmptyState } from '@/components/shared/empty-state'
|
|
8
9
|
import type { MemoryEntry } from '@/types'
|
|
9
10
|
|
|
10
11
|
export function KnowledgeList() {
|
|
@@ -81,7 +82,7 @@ export function KnowledgeList() {
|
|
|
81
82
|
<div className="flex-1 flex flex-col overflow-y-auto">
|
|
82
83
|
{/* Search — only show when there are entries */}
|
|
83
84
|
{entries.length > 0 && (
|
|
84
|
-
<div className="px-5 py-2 shrink-0">
|
|
85
|
+
<div className="px-5 py-2 shrink-0" style={{ animation: 'fade-up 0.4s var(--ease-spring)' }}>
|
|
85
86
|
<input
|
|
86
87
|
type="text"
|
|
87
88
|
value={search}
|
|
@@ -96,7 +97,7 @@ export function KnowledgeList() {
|
|
|
96
97
|
|
|
97
98
|
{/* Tag filters */}
|
|
98
99
|
{uniqueTags.length > 0 && (
|
|
99
|
-
<div className="px-5 pb-1.5 shrink-0">
|
|
100
|
+
<div className="px-5 pb-1.5 shrink-0" style={{ animation: 'fade-up 0.4s var(--ease-spring) 0.05s both' }}>
|
|
100
101
|
<div className="flex gap-1 flex-wrap">
|
|
101
102
|
<button
|
|
102
103
|
onClick={() => setActiveTag(null)}
|
|
@@ -124,7 +125,7 @@ export function KnowledgeList() {
|
|
|
124
125
|
{/* Entries */}
|
|
125
126
|
{entries.length > 0 ? (
|
|
126
127
|
<div className="grid grid-cols-1 md:grid-cols-2 gap-3 px-5 pb-6">
|
|
127
|
-
{entries.map((entry) => {
|
|
128
|
+
{entries.map((entry, idx) => {
|
|
128
129
|
const meta = entry.metadata as { tags?: string[]; scope?: 'global' | 'agent'; agentIds?: string[] } | undefined
|
|
129
130
|
const tags = meta?.tags || []
|
|
130
131
|
const entryScope = meta?.scope || 'global'
|
|
@@ -136,7 +137,11 @@ export function KnowledgeList() {
|
|
|
136
137
|
return (
|
|
137
138
|
<div
|
|
138
139
|
key={entry.id}
|
|
139
|
-
className="p-3 rounded-[12px] border border-white/[0.04] bg-transparent hover:bg-surface-2 transition-all relative group"
|
|
140
|
+
className="p-3 rounded-[12px] border border-white/[0.04] bg-transparent hover:bg-surface-2 transition-all relative group hover:scale-[1.01] hover:border-white/[0.1]"
|
|
141
|
+
style={{
|
|
142
|
+
animation: 'spring-in 0.5s var(--ease-spring) both',
|
|
143
|
+
animationDelay: `${0.1 + idx * 0.03}s`
|
|
144
|
+
}}
|
|
140
145
|
>
|
|
141
146
|
<div className="flex items-start justify-between gap-2 mb-1">
|
|
142
147
|
<span className="font-display text-[13px] font-600 text-text truncate">{entry.title}</span>
|
|
@@ -197,7 +202,7 @@ export function KnowledgeList() {
|
|
|
197
202
|
})}
|
|
198
203
|
</div>
|
|
199
204
|
) : error ? (
|
|
200
|
-
<div className="flex-1 flex flex-col items-center justify-center gap-3 text-text-3 p-8 text-center">
|
|
205
|
+
<div className="flex-1 flex flex-col items-center justify-center gap-3 text-text-3 p-8 text-center" style={{ animation: 'fade-up 0.5s var(--ease-spring)' }}>
|
|
201
206
|
<p className="font-display text-[14px] font-600 text-text-2">Couldn't load knowledge</p>
|
|
202
207
|
<p className="text-[12px] text-text-3/60">{error}</p>
|
|
203
208
|
<button
|
|
@@ -209,23 +214,17 @@ export function KnowledgeList() {
|
|
|
209
214
|
</button>
|
|
210
215
|
</div>
|
|
211
216
|
) : loaded ? (
|
|
212
|
-
<
|
|
213
|
-
|
|
217
|
+
<EmptyState
|
|
218
|
+
icon={
|
|
214
219
|
<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" className="text-accent-bright">
|
|
215
220
|
<path d="M4 19.5A2.5 2.5 0 0 1 6.5 17H20" />
|
|
216
221
|
<path d="M6.5 2H20v20H6.5A2.5 2.5 0 0 1 4 19.5v-15A2.5 2.5 0 0 1 6.5 2z" />
|
|
217
222
|
</svg>
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
className="mt-1 px-4 py-2 rounded-[10px] bg-transparent text-accent-bright text-[13px] font-600 cursor-pointer border border-accent-bright/20 hover:bg-accent-soft transition-all"
|
|
224
|
-
style={{ fontFamily: 'inherit' }}
|
|
225
|
-
>
|
|
226
|
-
+ Add Knowledge
|
|
227
|
-
</button>
|
|
228
|
-
</div>
|
|
223
|
+
}
|
|
224
|
+
title="No knowledge entries yet"
|
|
225
|
+
subtitle="Add shared knowledge for your agents"
|
|
226
|
+
action={{ label: '+ Add Knowledge', onClick: () => openSheet() }}
|
|
227
|
+
/>
|
|
229
228
|
) : null}
|
|
230
229
|
</div>
|
|
231
230
|
)
|
|
@@ -6,6 +6,7 @@ import { useAppStore } from '@/stores/use-app-store'
|
|
|
6
6
|
import { BottomSheet } from '@/components/shared/bottom-sheet'
|
|
7
7
|
import { AgentAvatar } from '@/components/agents/agent-avatar'
|
|
8
8
|
import type { MemoryEntry } from '@/types'
|
|
9
|
+
import { toast } from 'sonner'
|
|
9
10
|
|
|
10
11
|
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'
|
|
11
12
|
|
|
@@ -91,21 +92,22 @@ export function KnowledgeSheet() {
|
|
|
91
92
|
})
|
|
92
93
|
if (!res.ok) {
|
|
93
94
|
const err = await res.json().catch(() => ({ error: 'Upload failed' }))
|
|
94
|
-
|
|
95
|
+
toast.error(err.error || 'Upload failed')
|
|
95
96
|
return
|
|
96
97
|
}
|
|
97
98
|
const result: UploadResult = await res.json()
|
|
98
99
|
if (!title.trim()) setTitle(result.title)
|
|
99
100
|
setContent(result.content)
|
|
100
101
|
setUploadedFile({ name: result.filename, url: result.url, size: result.size })
|
|
102
|
+
toast.success('Document content extracted')
|
|
101
103
|
|
|
102
104
|
// Auto-tag based on file extension
|
|
103
105
|
const ext = file.name.split('.').pop()?.toLowerCase() || ''
|
|
104
106
|
if (ext && !tags.includes(ext)) {
|
|
105
107
|
setTags((prev) => prev ? `${prev}, ${ext}` : ext)
|
|
106
108
|
}
|
|
107
|
-
} catch (err) {
|
|
108
|
-
|
|
109
|
+
} catch (err: unknown) {
|
|
110
|
+
toast.error(err instanceof Error ? err.message : 'Upload failed')
|
|
109
111
|
} finally {
|
|
110
112
|
setUploading(false)
|
|
111
113
|
}
|
|
@@ -168,13 +170,15 @@ export function KnowledgeSheet() {
|
|
|
168
170
|
|
|
169
171
|
if (editingId) {
|
|
170
172
|
await api('PUT', `/knowledge/${editingId}`, payload)
|
|
173
|
+
toast.success('Knowledge entry updated')
|
|
171
174
|
} else {
|
|
172
175
|
await api('POST', '/knowledge', payload)
|
|
176
|
+
toast.success('Knowledge entry created')
|
|
173
177
|
}
|
|
174
178
|
|
|
175
179
|
onClose()
|
|
176
|
-
} catch {
|
|
177
|
-
|
|
180
|
+
} catch (err: unknown) {
|
|
181
|
+
toast.error(err instanceof Error ? err.message : 'Failed to save knowledge')
|
|
178
182
|
} finally {
|
|
179
183
|
setSaving(false)
|
|
180
184
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
'use client'
|
|
2
2
|
|
|
3
|
-
import { Component, useState, useEffect, useCallback } from 'react'
|
|
3
|
+
import { Component, useState, useEffect, useCallback, useMemo } from 'react'
|
|
4
4
|
import type { ReactNode, ErrorInfo } from 'react'
|
|
5
5
|
import { useAppStore } from '@/stores/use-app-store'
|
|
6
6
|
import { useMediaQuery } from '@/hooks/use-media-query'
|
|
@@ -63,6 +63,8 @@ import { CanvasPanel } from '@/components/canvas/canvas-panel'
|
|
|
63
63
|
import { Tooltip, TooltipTrigger, TooltipContent } from '@/components/ui/tooltip'
|
|
64
64
|
import { api } from '@/lib/api-client'
|
|
65
65
|
import { safeStorageGet, safeStorageSet } from '@/lib/safe-storage'
|
|
66
|
+
import { useApprovalStore } from '@/stores/use-approval-store'
|
|
67
|
+
import { useWs } from '@/hooks/use-ws'
|
|
66
68
|
import type { AppView } from '@/types'
|
|
67
69
|
|
|
68
70
|
const RAIL_EXPANDED_KEY = 'sc_rail_expanded'
|
|
@@ -90,9 +92,37 @@ export function AppLayout() {
|
|
|
90
92
|
const setPluginSheetOpen = useAppStore((s) => s.setPluginSheetOpen)
|
|
91
93
|
const setProjectSheetOpen = useAppStore((s) => s.setProjectSheetOpen)
|
|
92
94
|
const tasks = useAppStore((s) => s.tasks)
|
|
95
|
+
const approvals = useAppStore((s) => s.approvals)
|
|
96
|
+
const loadApprovals = useAppStore((s) => s.loadApprovals)
|
|
97
|
+
const execApprovals = useApprovalStore((s) => s.approvals)
|
|
98
|
+
const loadExecApprovals = useApprovalStore((s) => s.loadApprovals)
|
|
99
|
+
const pruneExecApprovals = useApprovalStore((s) => s.pruneExpired)
|
|
93
100
|
const isDesktop = useMediaQuery('(min-width: 768px)')
|
|
94
101
|
const hasSelectedSession = !!(currentSessionId && sessions[currentSessionId])
|
|
95
|
-
|
|
102
|
+
|
|
103
|
+
const pendingApprovalCount = useMemo(() => {
|
|
104
|
+
const taskCount = Object.values(tasks).filter((t) => t.pendingApproval).length
|
|
105
|
+
const sessionCount = Object.values(approvals).filter((a) => a.status === 'pending').length
|
|
106
|
+
const execCount = Object.keys(execApprovals).length
|
|
107
|
+
return taskCount + sessionCount + execCount
|
|
108
|
+
}, [tasks, approvals, execApprovals])
|
|
109
|
+
|
|
110
|
+
useEffect(() => {
|
|
111
|
+
loadApprovals()
|
|
112
|
+
void loadExecApprovals()
|
|
113
|
+
const interval = setInterval(() => {
|
|
114
|
+
loadApprovals()
|
|
115
|
+
void loadExecApprovals()
|
|
116
|
+
pruneExecApprovals()
|
|
117
|
+
}, 10000)
|
|
118
|
+
return () => clearInterval(interval)
|
|
119
|
+
}, [loadApprovals, loadExecApprovals, pruneExecApprovals])
|
|
120
|
+
|
|
121
|
+
useWs('approvals', loadApprovals, 10000)
|
|
122
|
+
useWs('openclaw:approvals', () => {
|
|
123
|
+
void loadExecApprovals()
|
|
124
|
+
pruneExecApprovals()
|
|
125
|
+
}, 10000)
|
|
96
126
|
|
|
97
127
|
const appSettings = useAppStore((s) => s.appSettings)
|
|
98
128
|
const [agentViewMode, setAgentViewMode] = useState<'chat' | 'config'>('chat')
|
|
@@ -146,6 +176,14 @@ export function AppLayout() {
|
|
|
146
176
|
}
|
|
147
177
|
}, [appSettings.themeHue])
|
|
148
178
|
|
|
179
|
+
const [pluginSidebarItems, setPluginSidebarItems] = useState<Array<{ id: string; label: string; href: string }>>([])
|
|
180
|
+
|
|
181
|
+
useEffect(() => {
|
|
182
|
+
api<Array<{ id: string; label: string; href: string }>>('GET', '/plugins/ui?type=sidebar').then(items => {
|
|
183
|
+
if (Array.isArray(items)) setPluginSidebarItems(items)
|
|
184
|
+
}).catch(() => {})
|
|
185
|
+
}, [])
|
|
186
|
+
|
|
149
187
|
const [railExpanded, setRailExpanded] = useState(() => {
|
|
150
188
|
const stored = safeStorageGet(RAIL_EXPANDED_KEY)
|
|
151
189
|
return stored === null ? true : stored === 'true'
|
|
@@ -199,10 +237,11 @@ export function AppLayout() {
|
|
|
199
237
|
|
|
200
238
|
const swipeHandlers = useSwipe({
|
|
201
239
|
onSwipe: (dir) => {
|
|
240
|
+
if (isDesktop) return
|
|
202
241
|
if (dir === 'right') setSidebarOpen(true)
|
|
203
242
|
else setSidebarOpen(false)
|
|
204
243
|
},
|
|
205
|
-
leftSwipeEnabled: sidebarOpen,
|
|
244
|
+
leftSwipeEnabled: !isDesktop && sidebarOpen,
|
|
206
245
|
})
|
|
207
246
|
|
|
208
247
|
const currentSession = currentSessionId ? sessions[currentSessionId] : null
|
|
@@ -223,15 +262,15 @@ export function AppLayout() {
|
|
|
223
262
|
return (
|
|
224
263
|
<div
|
|
225
264
|
className="h-full flex overflow-hidden"
|
|
226
|
-
onTouchStart={swipeHandlers.onTouchStart}
|
|
227
|
-
onTouchMove={swipeHandlers.onTouchMove}
|
|
228
|
-
onTouchEnd={swipeHandlers.onTouchEnd}
|
|
265
|
+
onTouchStart={isDesktop ? undefined : swipeHandlers.onTouchStart}
|
|
266
|
+
onTouchMove={isDesktop ? undefined : swipeHandlers.onTouchMove}
|
|
267
|
+
onTouchEnd={isDesktop ? undefined : swipeHandlers.onTouchEnd}
|
|
229
268
|
>
|
|
230
269
|
{/* Desktop: Navigation rail (expandable) */}
|
|
231
270
|
{isDesktop && (
|
|
232
271
|
<div
|
|
233
|
-
className="shrink-0 bg-raised border-r border-white/[0.04] flex flex-col py-4 transition-all duration-
|
|
234
|
-
style={{ width: railExpanded ? 180 : 60 }}
|
|
272
|
+
className="shrink-0 bg-raised border-r border-white/[0.04] flex flex-col py-4 min-h-0 transition-all duration-300 overflow-visible"
|
|
273
|
+
style={{ width: railExpanded ? 180 : 60, transitionTimingFunction: 'var(--ease-spring)' }}
|
|
235
274
|
>
|
|
236
275
|
{/* Logo + collapse toggle */}
|
|
237
276
|
<div className={`flex items-center mb-4 shrink-0 ${railExpanded ? 'px-4 gap-3' : 'justify-center'}`}>
|
|
@@ -332,8 +371,9 @@ export function AppLayout() {
|
|
|
332
371
|
</RailTooltip>
|
|
333
372
|
)}
|
|
334
373
|
|
|
335
|
-
|
|
336
|
-
|
|
374
|
+
<div className="flex-1 min-h-0 flex flex-col overflow-y-auto overscroll-contain touch-pan-y">
|
|
375
|
+
{/* Nav items */}
|
|
376
|
+
<div className={`flex flex-col gap-0.5 ${railExpanded ? 'px-3' : 'items-center'}`}>
|
|
337
377
|
<NavItem view="home" label="Home" expanded={railExpanded} active={activeView} sidebarOpen={sidebarOpen} onClick={() => handleNavClick('home')}>
|
|
338
378
|
<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round">
|
|
339
379
|
<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" />
|
|
@@ -441,12 +481,12 @@ export function AppLayout() {
|
|
|
441
481
|
<path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z" /><polyline points="14 2 14 8 20 8" /><line x1="16" y1="13" x2="8" y2="13" /><line x1="16" y1="17" x2="8" y2="17" /><polyline points="10 9 9 9 8 9" />
|
|
442
482
|
</svg>
|
|
443
483
|
</NavItem>
|
|
444
|
-
|
|
484
|
+
</div>
|
|
445
485
|
|
|
446
|
-
|
|
486
|
+
<div className="flex-1" />
|
|
447
487
|
|
|
448
|
-
|
|
449
|
-
|
|
488
|
+
{/* Bottom: Docs + Daemon + Settings + User */}
|
|
489
|
+
<div className={`flex flex-col gap-1 ${railExpanded ? 'px-3' : 'items-center'}`}>
|
|
450
490
|
{railExpanded ? (
|
|
451
491
|
<a
|
|
452
492
|
href="https://swarmclaw.ai/docs"
|
|
@@ -543,19 +583,20 @@ export function AppLayout() {
|
|
|
543
583
|
</button>
|
|
544
584
|
</RailTooltip>
|
|
545
585
|
)}
|
|
586
|
+
</div>
|
|
546
587
|
</div>
|
|
547
588
|
</div>
|
|
548
589
|
)}
|
|
549
590
|
|
|
550
591
|
{/* Desktop: Side panel (wallets has its own built-in sidebar) */}
|
|
551
|
-
{isDesktop && sidebarOpen && activeView !== 'wallets' && (
|
|
592
|
+
{isDesktop && sidebarOpen && activeView !== 'wallets' && activeView !== 'approvals' && (
|
|
552
593
|
<div
|
|
553
|
-
className="w-[280px] shrink-0 bg-raised border-r border-white/[0.04] flex flex-col h-full"
|
|
554
|
-
style={{ animation: 'panel-in 0.
|
|
594
|
+
className="w-[280px] shrink-0 bg-raised border-r border-white/[0.04] flex flex-col h-full min-h-0 overflow-hidden touch-pan-y"
|
|
595
|
+
style={{ animation: 'panel-in 0.3s var(--ease-spring)' }}
|
|
555
596
|
>
|
|
556
597
|
<div className="flex items-center px-5 pt-5 pb-3 shrink-0">
|
|
557
598
|
<h2 className="font-display text-[14px] font-600 text-text-2 tracking-[-0.01em] capitalize flex-1">{activeView}</h2>
|
|
558
|
-
{activeView === 'logs' || activeView === 'usage' || activeView === 'runs'
|
|
599
|
+
{activeView === 'logs' || activeView === 'usage' || activeView === 'runs' ? null : activeView === 'memory' ? (
|
|
559
600
|
<button
|
|
560
601
|
onClick={() => useAppStore.getState().setMemorySheetOpen(true)}
|
|
561
602
|
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"
|
|
@@ -618,7 +659,7 @@ export function AppLayout() {
|
|
|
618
659
|
<div className="fixed inset-0 z-50">
|
|
619
660
|
<div className="absolute inset-0 bg-black/80 backdrop-blur-sm" onClick={() => setSidebarOpen(false)} />
|
|
620
661
|
<div
|
|
621
|
-
className="absolute inset-y-0 left-0 w-[300px] bg-raised shadow-[4px_0_60px_rgba(0,0,0,0.7)] flex flex-col"
|
|
662
|
+
className="absolute inset-y-0 left-0 w-[300px] bg-raised shadow-[4px_0_60px_rgba(0,0,0,0.7)] flex flex-col min-h-0 overflow-hidden touch-pan-y"
|
|
622
663
|
style={{ animation: 'slide-in-left 0.25s cubic-bezier(0.16, 1, 0.3, 1)' }}
|
|
623
664
|
>
|
|
624
665
|
<div className="flex items-center gap-3 px-5 py-4 shrink-0">
|
|
@@ -659,8 +700,19 @@ export function AppLayout() {
|
|
|
659
700
|
{v}
|
|
660
701
|
</button>
|
|
661
702
|
))}
|
|
703
|
+
{/* Dynamic Plugin Items */}
|
|
704
|
+
{pluginSidebarItems.map((item) => (
|
|
705
|
+
<button
|
|
706
|
+
key={item.id}
|
|
707
|
+
onClick={() => window.open(item.href, '_blank')}
|
|
708
|
+
className="py-2 px-2.5 rounded-[10px] text-[11px] font-600 capitalize cursor-pointer transition-all bg-emerald-500/[0.05] text-emerald-400/80 hover:text-emerald-400 border border-emerald-400/10"
|
|
709
|
+
style={{ fontFamily: 'inherit' }}
|
|
710
|
+
>
|
|
711
|
+
{item.label}
|
|
712
|
+
</button>
|
|
713
|
+
))}
|
|
662
714
|
</div>
|
|
663
|
-
{activeView !== 'logs' && activeView !== 'usage' && activeView !== 'runs' && activeView !== 'settings' &&
|
|
715
|
+
{activeView !== 'logs' && activeView !== 'usage' && activeView !== 'runs' && activeView !== 'settings' && (
|
|
664
716
|
<div className="px-4 py-2.5 shrink-0">
|
|
665
717
|
<button
|
|
666
718
|
onClick={() => {
|
|
@@ -1170,7 +1222,7 @@ function NavItem({ view, label, expanded, active, sidebarOpen, onClick, badge, c
|
|
|
1170
1222
|
</span>
|
|
1171
1223
|
)}
|
|
1172
1224
|
</span>
|
|
1173
|
-
<span className="truncate">{label}</span>
|
|
1225
|
+
<span className="truncate" style={{ animation: 'spring-in 0.4s var(--ease-spring)' }}>{label}</span>
|
|
1174
1226
|
</button>
|
|
1175
1227
|
)
|
|
1176
1228
|
}
|