@swarmclawai/swarmclaw 0.7.2 → 0.7.4
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 +116 -50
- package/bin/package-manager.js +157 -0
- package/bin/package-manager.test.js +90 -0
- package/bin/server-cmd.js +38 -7
- package/bin/swarmclaw.js +54 -4
- package/bin/update-cmd.js +48 -10
- package/bin/update-cmd.test.js +55 -0
- package/package.json +8 -3
- package/scripts/postinstall.mjs +26 -0
- package/src/app/api/agents/[id]/route.ts +43 -0
- package/src/app/api/agents/[id]/thread/route.ts +39 -8
- package/src/app/api/agents/route.ts +35 -2
- package/src/app/api/auth/route.ts +77 -8
- package/src/app/api/chatrooms/[id]/chat/route.ts +22 -6
- package/src/app/api/chatrooms/[id]/pins/route.ts +2 -1
- package/src/app/api/chatrooms/[id]/reactions/route.ts +2 -1
- package/src/app/api/chatrooms/[id]/route.ts +6 -0
- package/src/app/api/chats/[id]/browser/route.ts +5 -1
- package/src/app/api/chats/[id]/chat/route.ts +7 -3
- package/src/app/api/chats/[id]/messages/route.ts +19 -13
- package/src/app/api/chats/[id]/route.ts +30 -0
- package/src/app/api/chats/[id]/stop/route.ts +6 -1
- package/src/app/api/chats/heartbeat/route.ts +2 -1
- package/src/app/api/chats/route.ts +23 -1
- package/src/app/api/connectors/[id]/doctor/route.ts +26 -0
- package/src/app/api/connectors/doctor/route.ts +13 -0
- package/src/app/api/external-agents/[id]/heartbeat/route.ts +33 -0
- package/src/app/api/external-agents/[id]/route.ts +31 -0
- package/src/app/api/external-agents/register/route.ts +3 -0
- package/src/app/api/external-agents/route.ts +66 -0
- package/src/app/api/files/open/route.ts +16 -14
- package/src/app/api/gateways/[id]/health/route.ts +28 -0
- package/src/app/api/gateways/[id]/route.ts +79 -0
- package/src/app/api/gateways/route.ts +57 -0
- package/src/app/api/memory/maintenance/route.ts +11 -1
- package/src/app/api/openclaw/agent-files/route.ts +27 -4
- package/src/app/api/openclaw/gateway/route.ts +10 -7
- package/src/app/api/openclaw/skills/route.ts +12 -4
- package/src/app/api/plugins/dependencies/route.ts +24 -0
- package/src/app/api/plugins/install/route.ts +15 -92
- package/src/app/api/plugins/route.ts +3 -26
- package/src/app/api/plugins/settings/route.ts +17 -12
- package/src/app/api/plugins/ui/route.ts +1 -0
- package/src/app/api/providers/[id]/discover-models/route.ts +27 -0
- package/src/app/api/schedules/[id]/route.ts +38 -9
- package/src/app/api/schedules/route.ts +51 -28
- package/src/app/api/settings/route.ts +55 -17
- package/src/app/api/setup/doctor/route.ts +6 -4
- package/src/app/api/tasks/[id]/route.ts +16 -6
- package/src/app/api/tasks/bulk/route.ts +3 -3
- package/src/app/api/tasks/route.ts +9 -4
- package/src/app/api/webhooks/[id]/route.ts +8 -1
- package/src/app/page.tsx +135 -17
- package/src/cli/binary.test.js +142 -0
- package/src/cli/index.js +38 -11
- package/src/cli/index.test.js +195 -0
- package/src/cli/index.ts +21 -12
- package/src/cli/server-cmd.test.js +59 -0
- package/src/cli/spec.js +20 -2
- package/src/components/agents/agent-card.tsx +15 -12
- package/src/components/agents/agent-chat-list.tsx +101 -1
- package/src/components/agents/agent-list.tsx +46 -9
- package/src/components/agents/agent-sheet.tsx +456 -23
- package/src/components/agents/inspector-panel.tsx +110 -49
- package/src/components/agents/sandbox-env-panel.tsx +4 -1
- package/src/components/auth/access-key-gate.tsx +36 -97
- package/src/components/auth/setup-wizard.tsx +970 -275
- package/src/components/chat/chat-area.tsx +70 -27
- package/src/components/chat/chat-card.tsx +6 -21
- package/src/components/chat/chat-header.tsx +263 -366
- package/src/components/chat/chat-list.tsx +62 -26
- package/src/components/chat/checkpoint-timeline.tsx +1 -1
- package/src/components/chat/message-list.tsx +145 -19
- package/src/components/chatrooms/chatroom-input.tsx +96 -33
- package/src/components/chatrooms/chatroom-list.tsx +141 -72
- package/src/components/chatrooms/chatroom-message.tsx +7 -6
- package/src/components/chatrooms/chatroom-sheet.tsx +13 -1
- package/src/components/chatrooms/chatroom-tool-request-banner.tsx +5 -2
- package/src/components/chatrooms/chatroom-view.tsx +422 -209
- package/src/components/chatrooms/reaction-picker.tsx +38 -33
- package/src/components/connectors/connector-list.tsx +265 -127
- package/src/components/connectors/connector-sheet.tsx +217 -0
- package/src/components/gateways/gateway-sheet.tsx +567 -0
- package/src/components/home/home-view.tsx +128 -4
- package/src/components/input/chat-input.tsx +135 -86
- package/src/components/layout/app-layout.tsx +385 -194
- package/src/components/layout/mobile-header.tsx +26 -8
- package/src/components/memory/memory-browser.tsx +71 -6
- package/src/components/memory/memory-card.tsx +18 -0
- package/src/components/memory/memory-detail.tsx +58 -31
- package/src/components/memory/memory-sheet.tsx +32 -4
- package/src/components/plugins/plugin-list.tsx +15 -3
- package/src/components/plugins/plugin-sheet.tsx +118 -9
- package/src/components/projects/project-detail.tsx +189 -1
- package/src/components/providers/provider-list.tsx +158 -2
- package/src/components/providers/provider-sheet.tsx +81 -70
- package/src/components/shared/agent-picker-list.tsx +2 -2
- package/src/components/shared/bottom-sheet.tsx +31 -15
- package/src/components/shared/command-palette.tsx +111 -24
- package/src/components/shared/confirm-dialog.tsx +45 -30
- package/src/components/shared/model-combobox.tsx +90 -8
- package/src/components/shared/settings/plugin-manager.tsx +20 -4
- package/src/components/shared/settings/section-capability-policy.tsx +105 -0
- package/src/components/shared/settings/section-heartbeat.tsx +88 -6
- package/src/components/shared/settings/section-orchestrator.tsx +6 -3
- package/src/components/shared/settings/section-runtime-loop.tsx +5 -5
- package/src/components/shared/settings/section-secrets.tsx +6 -6
- package/src/components/shared/settings/section-user-preferences.tsx +1 -1
- package/src/components/shared/settings/section-voice.tsx +5 -1
- package/src/components/shared/settings/section-web-search.tsx +10 -2
- package/src/components/shared/settings/settings-page.tsx +248 -47
- package/src/components/tasks/approvals-panel.tsx +211 -18
- package/src/components/tasks/task-board.tsx +242 -46
- package/src/components/ui/dialog.tsx +2 -2
- package/src/components/usage/metrics-dashboard.tsx +74 -1
- package/src/components/wallets/wallet-approval-dialog.tsx +59 -54
- package/src/components/wallets/wallet-panel.tsx +17 -5
- package/src/components/webhooks/webhook-sheet.tsx +7 -7
- package/src/lib/auth.ts +17 -0
- package/src/lib/chat-streaming-state.test.ts +108 -0
- package/src/lib/chat-streaming-state.ts +108 -0
- package/src/lib/heartbeat-defaults.ts +48 -0
- package/src/lib/memory-presentation.ts +59 -0
- package/src/lib/openclaw-agent-id.test.ts +14 -0
- package/src/lib/openclaw-agent-id.ts +31 -0
- package/src/lib/provider-model-discovery-client.ts +29 -0
- package/src/lib/providers/index.ts +12 -5
- package/src/lib/runtime-loop.ts +105 -3
- package/src/lib/safe-storage.ts +6 -1
- package/src/lib/server/agent-assignment.test.ts +112 -0
- package/src/lib/server/agent-assignment.ts +169 -0
- package/src/lib/server/agent-runtime-config.test.ts +141 -0
- package/src/lib/server/agent-runtime-config.ts +277 -0
- package/src/lib/server/approval-connector-notify.test.ts +253 -0
- package/src/lib/server/approvals-auto-approve.test.ts +264 -0
- package/src/lib/server/approvals.ts +483 -75
- package/src/lib/server/autonomy-runtime.test.ts +341 -0
- package/src/lib/server/browser-state.test.ts +118 -0
- package/src/lib/server/browser-state.ts +123 -0
- package/src/lib/server/build-llm.test.ts +44 -0
- package/src/lib/server/build-llm.ts +11 -4
- package/src/lib/server/builtin-plugins.ts +34 -0
- package/src/lib/server/chat-execution-heartbeat.test.ts +40 -0
- package/src/lib/server/chat-execution-tool-events.test.ts +219 -0
- package/src/lib/server/chat-execution.ts +402 -125
- package/src/lib/server/chatroom-health.test.ts +26 -0
- package/src/lib/server/chatroom-health.ts +2 -3
- package/src/lib/server/chatroom-helpers.test.ts +74 -2
- package/src/lib/server/chatroom-helpers.ts +144 -11
- package/src/lib/server/chatroom-session-persistence.test.ts +87 -0
- package/src/lib/server/connectors/discord.ts +175 -11
- package/src/lib/server/connectors/doctor.test.ts +80 -0
- package/src/lib/server/connectors/doctor.ts +116 -0
- package/src/lib/server/connectors/manager.ts +994 -130
- package/src/lib/server/connectors/policy.test.ts +222 -0
- package/src/lib/server/connectors/policy.ts +452 -0
- package/src/lib/server/connectors/slack.ts +189 -10
- package/src/lib/server/connectors/telegram.ts +65 -15
- package/src/lib/server/connectors/thread-context.test.ts +44 -0
- package/src/lib/server/connectors/thread-context.ts +72 -0
- package/src/lib/server/connectors/types.ts +41 -11
- package/src/lib/server/daemon-state.ts +62 -3
- package/src/lib/server/data-dir.ts +13 -0
- package/src/lib/server/delegation-jobs.test.ts +140 -0
- package/src/lib/server/delegation-jobs.ts +248 -0
- package/src/lib/server/document-utils.test.ts +47 -0
- package/src/lib/server/document-utils.ts +397 -0
- package/src/lib/server/eval/agent-regression.test.ts +47 -0
- package/src/lib/server/eval/agent-regression.ts +1742 -0
- package/src/lib/server/eval/runner.ts +11 -1
- package/src/lib/server/eval/store.ts +2 -1
- package/src/lib/server/heartbeat-service.ts +23 -43
- package/src/lib/server/heartbeat-source.test.ts +22 -0
- package/src/lib/server/heartbeat-source.ts +7 -0
- package/src/lib/server/identity-continuity.test.ts +77 -0
- package/src/lib/server/identity-continuity.ts +127 -0
- package/src/lib/server/mailbox-utils.ts +347 -0
- package/src/lib/server/main-agent-loop.ts +31 -964
- package/src/lib/server/memory-db.ts +4 -6
- package/src/lib/server/memory-tiers.ts +40 -0
- package/src/lib/server/openclaw-agent-resolver.test.ts +70 -0
- package/src/lib/server/openclaw-agent-resolver.ts +128 -0
- package/src/lib/server/openclaw-exec-config.ts +6 -5
- package/src/lib/server/openclaw-gateway.ts +123 -36
- package/src/lib/server/openclaw-skills-normalize.test.ts +56 -0
- package/src/lib/server/openclaw-skills-normalize.ts +136 -0
- package/src/lib/server/openclaw-sync.ts +3 -2
- package/src/lib/server/orchestrator-lg.ts +18 -8
- package/src/lib/server/orchestrator.ts +5 -4
- package/src/lib/server/playwright-proxy.mjs +27 -3
- package/src/lib/server/plugins.test.ts +215 -0
- package/src/lib/server/plugins.ts +832 -69
- package/src/lib/server/provider-health.ts +33 -3
- package/src/lib/server/provider-model-discovery.ts +481 -0
- package/src/lib/server/queue.ts +4 -21
- package/src/lib/server/runtime-settings.test.ts +119 -0
- package/src/lib/server/runtime-settings.ts +12 -92
- package/src/lib/server/schedule-normalization.ts +187 -0
- package/src/lib/server/scheduler.ts +2 -0
- package/src/lib/server/session-archive-memory.test.ts +85 -0
- package/src/lib/server/session-archive-memory.ts +230 -0
- package/src/lib/server/session-mailbox.ts +8 -18
- package/src/lib/server/session-reset-policy.test.ts +99 -0
- package/src/lib/server/session-reset-policy.ts +311 -0
- package/src/lib/server/session-run-manager.ts +33 -80
- package/src/lib/server/session-tools/autonomy-tools.test.ts +128 -0
- package/src/lib/server/session-tools/calendar.ts +2 -12
- package/src/lib/server/session-tools/connector.ts +109 -8
- package/src/lib/server/session-tools/context.ts +14 -2
- package/src/lib/server/session-tools/crawl.ts +447 -0
- package/src/lib/server/session-tools/crud.ts +96 -34
- package/src/lib/server/session-tools/delegate-fallback.test.ts +219 -0
- package/src/lib/server/session-tools/delegate.ts +406 -20
- package/src/lib/server/session-tools/discovery-approvals.test.ts +170 -0
- package/src/lib/server/session-tools/discovery.ts +40 -12
- package/src/lib/server/session-tools/document.ts +283 -0
- package/src/lib/server/session-tools/email.ts +1 -3
- package/src/lib/server/session-tools/extract.ts +137 -0
- package/src/lib/server/session-tools/file-normalize.test.ts +98 -0
- package/src/lib/server/session-tools/file-send.test.ts +84 -1
- package/src/lib/server/session-tools/file.ts +243 -24
- package/src/lib/server/session-tools/http.ts +9 -3
- package/src/lib/server/session-tools/human-loop.ts +227 -0
- package/src/lib/server/session-tools/image-gen.ts +1 -3
- package/src/lib/server/session-tools/index.ts +87 -2
- package/src/lib/server/session-tools/mailbox.ts +276 -0
- package/src/lib/server/session-tools/manage-schedules.test.ts +137 -0
- package/src/lib/server/session-tools/memory.ts +35 -3
- package/src/lib/server/session-tools/monitor.ts +162 -12
- package/src/lib/server/session-tools/normalize-tool-args.ts +17 -14
- package/src/lib/server/session-tools/openclaw-nodes.test.ts +111 -0
- package/src/lib/server/session-tools/openclaw-nodes.ts +86 -20
- package/src/lib/server/session-tools/platform-normalize.test.ts +142 -0
- package/src/lib/server/session-tools/platform.ts +142 -4
- package/src/lib/server/session-tools/plugin-creator.ts +95 -25
- package/src/lib/server/session-tools/primitive-tools.test.ts +257 -0
- package/src/lib/server/session-tools/replicate.ts +1 -3
- package/src/lib/server/session-tools/sandbox.ts +51 -92
- package/src/lib/server/session-tools/schedule.ts +20 -10
- package/src/lib/server/session-tools/session-info.ts +58 -4
- package/src/lib/server/session-tools/session-tools-wiring.test.ts +54 -17
- package/src/lib/server/session-tools/shell.ts +2 -2
- package/src/lib/server/session-tools/subagent.ts +195 -27
- package/src/lib/server/session-tools/table.ts +587 -0
- package/src/lib/server/session-tools/wallet.ts +13 -10
- package/src/lib/server/session-tools/web-browser-config.test.ts +39 -0
- package/src/lib/server/session-tools/web.ts +947 -108
- package/src/lib/server/storage.ts +255 -10
- package/src/lib/server/stream-agent-chat.test.ts +61 -0
- package/src/lib/server/stream-agent-chat.ts +185 -25
- package/src/lib/server/structured-extract.test.ts +72 -0
- package/src/lib/server/structured-extract.ts +373 -0
- package/src/lib/server/task-mention.test.ts +16 -2
- package/src/lib/server/task-mention.ts +61 -11
- package/src/lib/server/tool-aliases.ts +80 -12
- package/src/lib/server/tool-capability-policy.ts +7 -1
- package/src/lib/server/tool-retry.ts +2 -0
- package/src/lib/server/watch-jobs.test.ts +173 -0
- package/src/lib/server/watch-jobs.ts +532 -0
- package/src/lib/server/ws-hub.ts +5 -3
- package/src/lib/setup-defaults.ts +352 -11
- package/src/lib/tool-definitions.ts +3 -4
- package/src/lib/validation/schemas.test.ts +26 -0
- package/src/lib/validation/schemas.ts +62 -1
- package/src/lib/ws-client.ts +14 -12
- package/src/proxy.ts +5 -5
- package/src/stores/use-app-store.ts +43 -7
- package/src/stores/use-chat-store.ts +31 -2
- package/src/stores/use-chatroom-store.ts +153 -26
- package/src/types/index.ts +470 -44
- package/src/app/api/chats/[id]/main-loop/route.ts +0 -94
- package/src/components/chat/new-chat-sheet.tsx +0 -253
- package/src/lib/server/main-session.ts +0 -17
- package/src/lib/server/session-run-manager.test.ts +0 -26
|
@@ -3,15 +3,24 @@
|
|
|
3
3
|
import { useAppStore } from '@/stores/use-app-store'
|
|
4
4
|
import { IconButton } from '@/components/shared/icon-button'
|
|
5
5
|
import { NotificationCenter } from '@/components/shared/notification-center'
|
|
6
|
+
import { AgentAvatar } from '@/components/agents/agent-avatar'
|
|
6
7
|
|
|
7
8
|
export function MobileHeader() {
|
|
8
9
|
const toggleSidebar = useAppStore((s) => s.toggleSidebar)
|
|
9
10
|
const currentSessionId = useAppStore((s) => s.currentSessionId)
|
|
10
11
|
const sessions = useAppStore((s) => s.sessions)
|
|
12
|
+
const agents = useAppStore((s) => s.agents)
|
|
11
13
|
const session = currentSessionId ? sessions[currentSessionId] : null
|
|
14
|
+
const agent = session?.agentId ? agents[session.agentId] : null
|
|
15
|
+
const title = agent?.name || session?.name || 'SwarmClaw'
|
|
16
|
+
const subtitle = agent
|
|
17
|
+
? 'Agent chat'
|
|
18
|
+
: session
|
|
19
|
+
? 'Direct chat'
|
|
20
|
+
: 'Workspace'
|
|
12
21
|
|
|
13
22
|
return (
|
|
14
|
-
<header className="flex items-center gap-3 px-4 py-2.5 border-b border-white/[0.04] bg-bg/80 backdrop-blur-md shrink-0 min-h-[
|
|
23
|
+
<header className="flex items-center gap-3 px-4 py-2.5 border-b border-white/[0.04] bg-bg/80 backdrop-blur-md shrink-0 min-h-[56px]"
|
|
15
24
|
style={{ paddingTop: 'max(10px, env(safe-area-inset-top))' }}>
|
|
16
25
|
<IconButton onClick={toggleSidebar} aria-label="Toggle sidebar">
|
|
17
26
|
<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round">
|
|
@@ -20,13 +29,22 @@ export function MobileHeader() {
|
|
|
20
29
|
<line x1="3" y1="17" x2="18" y2="17" />
|
|
21
30
|
</svg>
|
|
22
31
|
</IconButton>
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
32
|
+
{agent && (
|
|
33
|
+
<AgentAvatar
|
|
34
|
+
seed={agent.avatarSeed || null}
|
|
35
|
+
avatarUrl={agent.avatarUrl}
|
|
36
|
+
name={agent.name}
|
|
37
|
+
size={28}
|
|
38
|
+
/>
|
|
39
|
+
)}
|
|
40
|
+
<div className="flex-1 min-w-0">
|
|
41
|
+
<h1 className="font-display text-[14px] font-600 tracking-[-0.02em] truncate">
|
|
42
|
+
{title}
|
|
43
|
+
</h1>
|
|
44
|
+
<p className="text-[10px] text-text-3/60 truncate mt-0.5">
|
|
45
|
+
{subtitle}
|
|
46
|
+
</p>
|
|
47
|
+
</div>
|
|
30
48
|
<NotificationCenter />
|
|
31
49
|
</header>
|
|
32
50
|
)
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
import { useCallback, useEffect, useMemo, useRef, useState } from 'react'
|
|
4
4
|
import { searchMemory } from '@/lib/memory'
|
|
5
|
+
import { deriveMemoryScope, getMemoryTier } from '@/lib/memory-presentation'
|
|
5
6
|
import { useAppStore } from '@/stores/use-app-store'
|
|
6
7
|
import { MemoryCard } from './memory-card'
|
|
7
8
|
import { MemoryDetail } from './memory-detail'
|
|
@@ -14,6 +15,10 @@ export function MemoryBrowser() {
|
|
|
14
15
|
const refreshKey = useAppStore((s) => s.memoryRefreshKey)
|
|
15
16
|
const agents = useAppStore((s) => s.agents)
|
|
16
17
|
const memoryAgentFilter = useAppStore((s) => s.memoryAgentFilter)
|
|
18
|
+
const memoryTierFilter = useAppStore((s) => s.memoryTierFilter)
|
|
19
|
+
const setMemoryTierFilter = useAppStore((s) => s.setMemoryTierFilter)
|
|
20
|
+
const memoryScopeFilter = useAppStore((s) => s.memoryScopeFilter)
|
|
21
|
+
const setMemoryScopeFilter = useAppStore((s) => s.setMemoryScopeFilter)
|
|
17
22
|
|
|
18
23
|
const [search, setSearch] = useState('')
|
|
19
24
|
const [entries, setEntries] = useState<MemoryEntry[]>([])
|
|
@@ -32,14 +37,24 @@ export function MemoryBrowser() {
|
|
|
32
37
|
|
|
33
38
|
const load = useCallback(async (query: string) => {
|
|
34
39
|
try {
|
|
35
|
-
const
|
|
40
|
+
const scope = memoryAgentFilter === '_global'
|
|
41
|
+
? 'global'
|
|
42
|
+
: memoryAgentFilter
|
|
43
|
+
? 'auto'
|
|
44
|
+
: 'all'
|
|
45
|
+
const results = await searchMemory({
|
|
46
|
+
q: query || undefined,
|
|
47
|
+
agentId: apiAgentId,
|
|
48
|
+
scope,
|
|
49
|
+
limit: 120,
|
|
50
|
+
})
|
|
36
51
|
setEntries(Array.isArray(results) ? results : [])
|
|
37
52
|
setError(null)
|
|
38
53
|
} catch {
|
|
39
54
|
setError('Unable to load memories right now.')
|
|
40
55
|
}
|
|
41
56
|
setLoaded(true)
|
|
42
|
-
}, [apiAgentId])
|
|
57
|
+
}, [apiAgentId, memoryAgentFilter])
|
|
43
58
|
|
|
44
59
|
useEffect(() => {
|
|
45
60
|
searchRef.current = search
|
|
@@ -70,12 +85,23 @@ export function MemoryBrowser() {
|
|
|
70
85
|
|
|
71
86
|
const filtered = useMemo(() => {
|
|
72
87
|
return entries.filter((e) => {
|
|
73
|
-
// Client-side global filter
|
|
74
88
|
if (memoryAgentFilter === '_global' && e.agentId) return false
|
|
89
|
+
if (memoryAgentFilter && memoryAgentFilter !== '_global') {
|
|
90
|
+
const visibleToAgent = e.agentId === memoryAgentFilter || (Array.isArray(e.sharedWith) && e.sharedWith.includes(memoryAgentFilter)) || !e.agentId
|
|
91
|
+
if (!visibleToAgent) return false
|
|
92
|
+
}
|
|
93
|
+
const scope = deriveMemoryScope(e)
|
|
94
|
+
if (memoryScopeFilter !== 'all') {
|
|
95
|
+
if (memoryScopeFilter === 'global' && scope !== 'global') return false
|
|
96
|
+
if (memoryScopeFilter === 'agent' && scope !== 'agent' && scope !== 'shared') return false
|
|
97
|
+
if (memoryScopeFilter === 'session' && scope !== 'session') return false
|
|
98
|
+
if (memoryScopeFilter === 'project' && scope !== 'project') return false
|
|
99
|
+
}
|
|
100
|
+
if (memoryTierFilter !== 'all' && getMemoryTier(e) !== memoryTierFilter) return false
|
|
75
101
|
if (categoryFilter && (e.category || 'note') !== categoryFilter) return false
|
|
76
102
|
return true
|
|
77
103
|
})
|
|
78
|
-
}, [entries, memoryAgentFilter, categoryFilter])
|
|
104
|
+
}, [entries, memoryAgentFilter, memoryScopeFilter, memoryTierFilter, categoryFilter])
|
|
79
105
|
|
|
80
106
|
const filterLabel = useMemo(() => {
|
|
81
107
|
if (!memoryAgentFilter) return 'All Memories'
|
|
@@ -135,6 +161,41 @@ export function MemoryBrowser() {
|
|
|
135
161
|
text-[13px] outline-none transition-all duration-200 placeholder:text-text-3/70 focus-glow"
|
|
136
162
|
style={{ fontFamily: 'inherit' }}
|
|
137
163
|
/>
|
|
164
|
+
<div className="mt-2.5 flex flex-wrap items-center gap-1.5">
|
|
165
|
+
{(['all', 'global', 'agent', 'session', 'project'] as const).map((scope) => (
|
|
166
|
+
<button
|
|
167
|
+
key={scope}
|
|
168
|
+
type="button"
|
|
169
|
+
onClick={() => setMemoryScopeFilter(scope)}
|
|
170
|
+
className={`px-2.5 py-1 rounded-[8px] text-[10px] font-700 uppercase tracking-[0.08em] border transition-all ${
|
|
171
|
+
memoryScopeFilter === scope
|
|
172
|
+
? 'bg-accent-soft text-accent-bright border-accent-bright/15'
|
|
173
|
+
: 'bg-transparent text-text-3/70 border-white/[0.05] hover:text-text-2 hover:bg-white/[0.03]'
|
|
174
|
+
}`}
|
|
175
|
+
>
|
|
176
|
+
{scope === 'agent' ? 'private/shared' : scope}
|
|
177
|
+
</button>
|
|
178
|
+
))}
|
|
179
|
+
</div>
|
|
180
|
+
<div className="mt-1.5 flex flex-wrap items-center gap-1.5">
|
|
181
|
+
{(['all', 'working', 'durable', 'archive'] as const).map((tier) => (
|
|
182
|
+
<button
|
|
183
|
+
key={tier}
|
|
184
|
+
type="button"
|
|
185
|
+
onClick={() => setMemoryTierFilter(tier)}
|
|
186
|
+
className={`px-2.5 py-1 rounded-[8px] text-[10px] font-700 uppercase tracking-[0.08em] border transition-all ${
|
|
187
|
+
memoryTierFilter === tier
|
|
188
|
+
? 'bg-white/[0.08] text-text-2 border-white/[0.10]'
|
|
189
|
+
: 'bg-transparent text-text-3/70 border-white/[0.05] hover:text-text-2 hover:bg-white/[0.03]'
|
|
190
|
+
}`}
|
|
191
|
+
>
|
|
192
|
+
{tier}
|
|
193
|
+
</button>
|
|
194
|
+
))}
|
|
195
|
+
</div>
|
|
196
|
+
<p className="mt-2 text-[11px] text-text-3/55">
|
|
197
|
+
Scope shows what kind of memory it is. Tier shows how long it should stay salient.
|
|
198
|
+
</p>
|
|
138
199
|
</div>
|
|
139
200
|
|
|
140
201
|
{/* Category chips */}
|
|
@@ -207,8 +268,12 @@ export function MemoryBrowser() {
|
|
|
207
268
|
<path d="M3 5v14c0 1.66 4 3 9 3s9-1.34 9-3V5" />
|
|
208
269
|
</svg>
|
|
209
270
|
</div>
|
|
210
|
-
<p className="font-display text-[14px] font-600 text-text-2">No memories
|
|
211
|
-
<p className="text-[12px] text-text-3/50">
|
|
271
|
+
<p className="font-display text-[14px] font-600 text-text-2">No memories match these filters</p>
|
|
272
|
+
<p className="text-[12px] text-text-3/50">
|
|
273
|
+
{memoryScopeFilter === 'all' && memoryTierFilter === 'all'
|
|
274
|
+
? 'Agents store knowledge here as they learn'
|
|
275
|
+
: `Try a different ${memoryScopeFilter !== 'all' ? 'scope' : 'tier'} filter`}
|
|
276
|
+
</p>
|
|
212
277
|
</div>
|
|
213
278
|
) : null
|
|
214
279
|
) : (
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
import type { MemoryEntry } from '@/types'
|
|
4
4
|
import { AgentAvatar } from '@/components/agents/agent-avatar'
|
|
5
|
+
import { deriveMemoryScope, getMemoryScopeLabel, getMemoryTier } from '@/lib/memory-presentation'
|
|
5
6
|
|
|
6
7
|
function timeAgo(ts: number): string {
|
|
7
8
|
if (!ts) return ''
|
|
@@ -22,6 +23,9 @@ interface Props {
|
|
|
22
23
|
}
|
|
23
24
|
|
|
24
25
|
export function MemoryCard({ entry, active, agentName, agentAvatarSeed, agentAvatarUrl, onClick }: Props) {
|
|
26
|
+
const scope = deriveMemoryScope(entry)
|
|
27
|
+
const tier = getMemoryTier(entry)
|
|
28
|
+
|
|
25
29
|
return (
|
|
26
30
|
<div
|
|
27
31
|
onClick={onClick}
|
|
@@ -51,6 +55,20 @@ export function MemoryCard({ entry, active, agentName, agentAvatarSeed, agentAva
|
|
|
51
55
|
<div className="text-[12px] text-text-2/40 mt-1 line-clamp-3 leading-relaxed">
|
|
52
56
|
{entry.content || '(empty)'}
|
|
53
57
|
</div>
|
|
58
|
+
<div className="mt-2 flex flex-wrap items-center gap-1.5">
|
|
59
|
+
<span className="px-1.5 py-0.5 rounded-[5px] text-[9px] font-700 uppercase tracking-[0.08em] bg-white/[0.04] text-text-3/75">
|
|
60
|
+
{getMemoryScopeLabel(scope)}
|
|
61
|
+
</span>
|
|
62
|
+
<span className={`px-1.5 py-0.5 rounded-[5px] text-[9px] font-700 uppercase tracking-[0.08em] ${
|
|
63
|
+
tier === 'working'
|
|
64
|
+
? 'bg-amber-400/10 text-amber-300'
|
|
65
|
+
: tier === 'archive'
|
|
66
|
+
? 'bg-sky-400/10 text-sky-300'
|
|
67
|
+
: 'bg-emerald-400/10 text-emerald-300'
|
|
68
|
+
}`}>
|
|
69
|
+
{tier}
|
|
70
|
+
</span>
|
|
71
|
+
</div>
|
|
54
72
|
{(entry.image?.path || entry.imagePath) && (
|
|
55
73
|
<div className="mt-2 w-10 h-10 rounded-[6px] overflow-hidden bg-white/[0.04] shrink-0">
|
|
56
74
|
{/* eslint-disable-next-line @next/next/no-img-element */}
|
|
@@ -3,7 +3,9 @@
|
|
|
3
3
|
import { useEffect, useState, useCallback } from 'react'
|
|
4
4
|
import { useAppStore } from '@/stores/use-app-store'
|
|
5
5
|
import { getMemory, updateMemory, deleteMemory } from '@/lib/memory'
|
|
6
|
+
import { deriveMemoryScope, getMemoryScopeLabel, getMemoryTier } from '@/lib/memory-presentation'
|
|
6
7
|
import { AgentAvatar } from '@/components/agents/agent-avatar'
|
|
8
|
+
import { ConfirmDialog } from '@/components/shared/confirm-dialog'
|
|
7
9
|
import type { MemoryEntry } from '@/types'
|
|
8
10
|
|
|
9
11
|
const CATEGORIES = ['note', 'fact', 'preference', 'finding', 'learning', 'general']
|
|
@@ -22,6 +24,7 @@ export function MemoryDetail() {
|
|
|
22
24
|
const [title, setTitle] = useState('')
|
|
23
25
|
const [content, setContent] = useState('')
|
|
24
26
|
const [category, setCategory] = useState('note')
|
|
27
|
+
const [editTier, setEditTier] = useState<'working' | 'durable' | 'archive'>('durable')
|
|
25
28
|
const [editAgentId, setEditAgentId] = useState<string | null>(null)
|
|
26
29
|
const [editSharedWith, setEditSharedWith] = useState<string[]>([])
|
|
27
30
|
const [saving, setSaving] = useState(false)
|
|
@@ -53,6 +56,7 @@ export function MemoryDetail() {
|
|
|
53
56
|
setTitle(resolved.title)
|
|
54
57
|
setContent(resolved.content)
|
|
55
58
|
setCategory(resolved.category || 'note')
|
|
59
|
+
setEditTier(getMemoryTier(resolved))
|
|
56
60
|
setEditAgentId(resolved.agentId || null)
|
|
57
61
|
setEditSharedWith(resolved.sharedWith || [])
|
|
58
62
|
setEditing(false)
|
|
@@ -97,6 +101,12 @@ export function MemoryDetail() {
|
|
|
97
101
|
category,
|
|
98
102
|
agentId: editAgentId,
|
|
99
103
|
sharedWith: editSharedWith.length ? editSharedWith : undefined,
|
|
104
|
+
metadata: {
|
|
105
|
+
...(entry.metadata || {}),
|
|
106
|
+
tier: editTier,
|
|
107
|
+
scope: editAgentId ? 'agent' : 'global',
|
|
108
|
+
visibility: editAgentId ? (editSharedWith.length ? 'shared' : 'private') : 'global',
|
|
109
|
+
},
|
|
100
110
|
})
|
|
101
111
|
setEntry(updated)
|
|
102
112
|
setEditing(false)
|
|
@@ -151,6 +161,8 @@ export function MemoryDetail() {
|
|
|
151
161
|
|
|
152
162
|
const agentName = entry.agentId ? (agents[entry.agentId]?.name || entry.agentId) : null
|
|
153
163
|
const sessionName = entry.sessionId ? (sessions[entry.sessionId]?.name || entry.sessionId) : null
|
|
164
|
+
const scope = deriveMemoryScope(entry)
|
|
165
|
+
const tier = getMemoryTier(entry)
|
|
154
166
|
const imagePath = entry.image?.path || entry.imagePath || null
|
|
155
167
|
const imageUrl = imagePath
|
|
156
168
|
? imagePath.startsWith('data/memory-images/')
|
|
@@ -171,6 +183,18 @@ export function MemoryDetail() {
|
|
|
171
183
|
<span className="shrink-0 text-[10px] font-700 uppercase tracking-wider text-accent-bright/70 bg-accent-soft px-2 py-0.5 rounded-[6px]">
|
|
172
184
|
{entry.category || 'note'}
|
|
173
185
|
</span>
|
|
186
|
+
<span className="shrink-0 text-[10px] font-700 uppercase tracking-wider text-text-3/70 bg-white/[0.04] px-2 py-0.5 rounded-[6px]">
|
|
187
|
+
{getMemoryScopeLabel(scope)}
|
|
188
|
+
</span>
|
|
189
|
+
<span className={`shrink-0 text-[10px] font-700 uppercase tracking-wider px-2 py-0.5 rounded-[6px] ${
|
|
190
|
+
tier === 'working'
|
|
191
|
+
? 'bg-amber-400/10 text-amber-300'
|
|
192
|
+
: tier === 'archive'
|
|
193
|
+
? 'bg-sky-400/10 text-sky-300'
|
|
194
|
+
: 'bg-emerald-400/10 text-emerald-300'
|
|
195
|
+
}`}>
|
|
196
|
+
{tier}
|
|
197
|
+
</span>
|
|
174
198
|
{!editing && (
|
|
175
199
|
<h2 className="font-display text-[16px] font-700 truncate tracking-[-0.02em]">{entry.title || 'Untitled'}</h2>
|
|
176
200
|
)}
|
|
@@ -216,6 +240,7 @@ export function MemoryDetail() {
|
|
|
216
240
|
setTitle(entry.title)
|
|
217
241
|
setContent(entry.content)
|
|
218
242
|
setCategory(entry.category || 'note')
|
|
243
|
+
setEditTier(getMemoryTier(entry))
|
|
219
244
|
setEditAgentId(entry.agentId || null)
|
|
220
245
|
setEditSharedWith(entry.sharedWith || [])
|
|
221
246
|
setEditing(false)
|
|
@@ -301,9 +326,23 @@ export function MemoryDetail() {
|
|
|
301
326
|
</div>
|
|
302
327
|
</div>
|
|
303
328
|
|
|
329
|
+
<div>
|
|
330
|
+
<label className="block text-[11px] font-600 text-text-3/60 uppercase tracking-[0.06em] mb-2">Tier</label>
|
|
331
|
+
<select
|
|
332
|
+
value={editTier}
|
|
333
|
+
onChange={(e) => setEditTier(e.target.value as typeof editTier)}
|
|
334
|
+
className={inputClass}
|
|
335
|
+
style={{ fontFamily: 'inherit' }}
|
|
336
|
+
>
|
|
337
|
+
<option value="working">Working</option>
|
|
338
|
+
<option value="durable">Durable</option>
|
|
339
|
+
<option value="archive">Archive</option>
|
|
340
|
+
</select>
|
|
341
|
+
</div>
|
|
342
|
+
|
|
304
343
|
{/* Agent assignment */}
|
|
305
344
|
<div>
|
|
306
|
-
<label className="block text-[11px] font-600 text-text-3/60 uppercase tracking-[0.06em] mb-2">
|
|
345
|
+
<label className="block text-[11px] font-600 text-text-3/60 uppercase tracking-[0.06em] mb-2">Visibility</label>
|
|
307
346
|
<div className="flex gap-1.5 flex-wrap">
|
|
308
347
|
<button
|
|
309
348
|
onClick={() => setEditAgentId(null)}
|
|
@@ -522,10 +561,18 @@ export function MemoryDetail() {
|
|
|
522
561
|
</div>
|
|
523
562
|
{entry.agentId && (
|
|
524
563
|
<div>
|
|
525
|
-
<span className="text-text-3/70 block mb-1">
|
|
564
|
+
<span className="text-text-3/70 block mb-1">Owner</span>
|
|
526
565
|
<span className="text-text-3/60 font-mono">{agentName}</span>
|
|
527
566
|
</div>
|
|
528
567
|
)}
|
|
568
|
+
<div>
|
|
569
|
+
<span className="text-text-3/70 block mb-1">Scope</span>
|
|
570
|
+
<span className="text-text-3/60 font-mono">{getMemoryScopeLabel(scope)}</span>
|
|
571
|
+
</div>
|
|
572
|
+
<div>
|
|
573
|
+
<span className="text-text-3/70 block mb-1">Tier</span>
|
|
574
|
+
<span className="text-text-3/60 font-mono">{tier}</span>
|
|
575
|
+
</div>
|
|
529
576
|
{entry.sessionId && (
|
|
530
577
|
<div>
|
|
531
578
|
<span className="text-text-3/70 block mb-1">Chat</span>
|
|
@@ -544,35 +591,15 @@ export function MemoryDetail() {
|
|
|
544
591
|
</div>
|
|
545
592
|
</div>
|
|
546
593
|
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
</p>
|
|
557
|
-
<div className="flex gap-3">
|
|
558
|
-
<button
|
|
559
|
-
onClick={() => setConfirmDelete(false)}
|
|
560
|
-
className="flex-1 py-2.5 rounded-[10px] border border-white/[0.08] bg-transparent text-text-2 text-[13px] font-600 cursor-pointer hover:bg-surface-2 transition-all"
|
|
561
|
-
style={{ fontFamily: 'inherit' }}
|
|
562
|
-
>
|
|
563
|
-
Cancel
|
|
564
|
-
</button>
|
|
565
|
-
<button
|
|
566
|
-
onClick={handleDelete}
|
|
567
|
-
className="flex-1 py-2.5 rounded-[10px] border-none bg-red-500/90 text-white text-[13px] font-600 cursor-pointer active:scale-[0.97] transition-all hover:bg-red-500"
|
|
568
|
-
style={{ fontFamily: 'inherit' }}
|
|
569
|
-
>
|
|
570
|
-
Delete
|
|
571
|
-
</button>
|
|
572
|
-
</div>
|
|
573
|
-
</div>
|
|
574
|
-
</div>
|
|
575
|
-
)}
|
|
594
|
+
<ConfirmDialog
|
|
595
|
+
open={confirmDelete}
|
|
596
|
+
title="Delete Memory"
|
|
597
|
+
message={`Delete "${entry.title}"? This cannot be undone.`}
|
|
598
|
+
confirmLabel="Delete"
|
|
599
|
+
danger
|
|
600
|
+
onCancel={() => setConfirmDelete(false)}
|
|
601
|
+
onConfirm={() => { void handleDelete() }}
|
|
602
|
+
/>
|
|
576
603
|
</div>
|
|
577
604
|
)
|
|
578
605
|
}
|
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
import { useState } from 'react'
|
|
4
4
|
import { useAppStore } from '@/stores/use-app-store'
|
|
5
5
|
import { createMemory } from '@/lib/memory'
|
|
6
|
+
import { getMemoryTierForCategory } from '@/lib/memory-presentation'
|
|
6
7
|
import { BottomSheet } from '@/components/shared/bottom-sheet'
|
|
7
8
|
import { AgentAvatar } from '@/components/agents/agent-avatar'
|
|
8
9
|
import { SheetFooter } from '@/components/shared/sheet-footer'
|
|
@@ -24,6 +25,7 @@ export function MemorySheet() {
|
|
|
24
25
|
const [title, setTitle] = useState('')
|
|
25
26
|
const [content, setContent] = useState('')
|
|
26
27
|
const [category, setCategory] = useState('note')
|
|
28
|
+
const [tier, setTier] = useState<'working' | 'durable' | 'archive'>(getMemoryTierForCategory('note'))
|
|
27
29
|
const [agentId, setAgentId] = useState<string | null>(defaultAgentId)
|
|
28
30
|
const [sharedWith, setSharedWith] = useState<string[]>([])
|
|
29
31
|
const [saving, setSaving] = useState(false)
|
|
@@ -36,6 +38,7 @@ export function MemorySheet() {
|
|
|
36
38
|
setTitle('')
|
|
37
39
|
setContent('')
|
|
38
40
|
setCategory('note')
|
|
41
|
+
setTier(getMemoryTierForCategory('note'))
|
|
39
42
|
setSaving(false)
|
|
40
43
|
} else if (!open && prevOpen) {
|
|
41
44
|
setPrevOpen(false)
|
|
@@ -56,6 +59,11 @@ export function MemorySheet() {
|
|
|
56
59
|
agentId,
|
|
57
60
|
sessionId: null,
|
|
58
61
|
sharedWith: sharedWith.length ? sharedWith : undefined,
|
|
62
|
+
metadata: {
|
|
63
|
+
tier,
|
|
64
|
+
scope: agentId ? 'agent' : 'global',
|
|
65
|
+
visibility: agentId ? (sharedWith.length ? 'shared' : 'private') : 'global',
|
|
66
|
+
},
|
|
59
67
|
})
|
|
60
68
|
triggerRefresh()
|
|
61
69
|
onClose()
|
|
@@ -77,7 +85,7 @@ export function MemorySheet() {
|
|
|
77
85
|
|
|
78
86
|
{/* Agent selector */}
|
|
79
87
|
<div className="mb-6">
|
|
80
|
-
<label className="block font-display text-[12px] font-600 text-text-2 uppercase tracking-[0.08em] mb-3">
|
|
88
|
+
<label className="block font-display text-[12px] font-600 text-text-2 uppercase tracking-[0.08em] mb-3">Visibility</label>
|
|
81
89
|
<div className="flex gap-2 flex-wrap">
|
|
82
90
|
<button
|
|
83
91
|
onClick={() => setAgentId(null)}
|
|
@@ -111,12 +119,12 @@ export function MemorySheet() {
|
|
|
111
119
|
</div>
|
|
112
120
|
{selectedAgent && (
|
|
113
121
|
<p className="text-[11px] text-text-3/50 mt-2">
|
|
114
|
-
|
|
122
|
+
Owned by <span className="text-text-2">{selectedAgent.name}</span>. Add collaborators below if other agents should be able to recall it too.
|
|
115
123
|
</p>
|
|
116
124
|
)}
|
|
117
125
|
{!agentId && (
|
|
118
126
|
<p className="text-[11px] text-text-3/50 mt-2">
|
|
119
|
-
Global memories are accessible to
|
|
127
|
+
Global memories are accessible to every agent in the workspace.
|
|
120
128
|
</p>
|
|
121
129
|
)}
|
|
122
130
|
</div>
|
|
@@ -167,7 +175,10 @@ export function MemorySheet() {
|
|
|
167
175
|
{CATEGORIES.map((c) => (
|
|
168
176
|
<button
|
|
169
177
|
key={c}
|
|
170
|
-
onClick={() =>
|
|
178
|
+
onClick={() => {
|
|
179
|
+
setCategory(c)
|
|
180
|
+
setTier(getMemoryTierForCategory(c))
|
|
181
|
+
}}
|
|
171
182
|
className={`px-3 py-1.5 rounded-[8px] text-[12px] font-600 capitalize cursor-pointer transition-all border-none
|
|
172
183
|
${category === c
|
|
173
184
|
? 'bg-accent-soft text-accent-bright'
|
|
@@ -180,6 +191,23 @@ export function MemorySheet() {
|
|
|
180
191
|
</div>
|
|
181
192
|
</div>
|
|
182
193
|
|
|
194
|
+
<div className="mb-6">
|
|
195
|
+
<label className="block font-display text-[12px] font-600 text-text-2 uppercase tracking-[0.08em] mb-3">Tier</label>
|
|
196
|
+
<select
|
|
197
|
+
value={tier}
|
|
198
|
+
onChange={(e) => setTier(e.target.value as typeof tier)}
|
|
199
|
+
className={inputClass}
|
|
200
|
+
style={{ fontFamily: 'inherit' }}
|
|
201
|
+
>
|
|
202
|
+
<option value="working">Working: short-horizon, active context</option>
|
|
203
|
+
<option value="durable">Durable: keep this around as reusable knowledge</option>
|
|
204
|
+
<option value="archive">Archive: preserve, but keep less salient</option>
|
|
205
|
+
</select>
|
|
206
|
+
<p className="text-[11px] text-text-3/50 mt-2">
|
|
207
|
+
Tier controls how aggressively this memory should stay in active recall.
|
|
208
|
+
</p>
|
|
209
|
+
</div>
|
|
210
|
+
|
|
183
211
|
{/* Content */}
|
|
184
212
|
<div className="mb-8">
|
|
185
213
|
<label className="block font-display text-[12px] font-600 text-text-2 uppercase tracking-[0.08em] mb-3">Content</label>
|
|
@@ -62,8 +62,8 @@ export function PluginList({ inSidebar }: { inSidebar?: boolean }) {
|
|
|
62
62
|
}, [tab, inSidebar, loadMarketplace])
|
|
63
63
|
|
|
64
64
|
const pluginList = Object.values(plugins)
|
|
65
|
-
const corePlugins = useMemo(() => pluginList.filter((p) => p.
|
|
66
|
-
const extensionPlugins = useMemo(() => pluginList.filter((p) => p.
|
|
65
|
+
const corePlugins = useMemo(() => pluginList.filter((p) => p.isBuiltin), [pluginList])
|
|
66
|
+
const extensionPlugins = useMemo(() => pluginList.filter((p) => !p.isBuiltin), [pluginList])
|
|
67
67
|
|
|
68
68
|
// Search filtering for installed plugins
|
|
69
69
|
const filterInstalled = useCallback((list: PluginMeta[]) => {
|
|
@@ -293,7 +293,7 @@ function TabButton({ active, onClick, count, children }: {
|
|
|
293
293
|
function pluginDescription(plugin: PluginMeta): string {
|
|
294
294
|
const raw = (plugin.description || '').trim()
|
|
295
295
|
if (raw) return raw
|
|
296
|
-
const sourceLabel = plugin.
|
|
296
|
+
const sourceLabel = plugin.isBuiltin ? 'core plugin' : 'installed plugin'
|
|
297
297
|
return `No description provided. Click to view metadata and controls for this ${sourceLabel}.`
|
|
298
298
|
}
|
|
299
299
|
|
|
@@ -304,6 +304,7 @@ function pluginCapabilityBadges(plugin: PluginMeta): string[] {
|
|
|
304
304
|
if (plugin.hasUI) badges.push('UI')
|
|
305
305
|
if (plugin.providerCount && plugin.providerCount > 0) badges.push(`${plugin.providerCount} provider${plugin.providerCount === 1 ? '' : 's'}`)
|
|
306
306
|
if (plugin.connectorCount && plugin.connectorCount > 0) badges.push(`${plugin.connectorCount} connector${plugin.connectorCount === 1 ? '' : 's'}`)
|
|
307
|
+
if (plugin.hasDependencyManifest) badges.push(`${plugin.dependencyCount ?? 0} dep${plugin.dependencyCount === 1 ? '' : 's'}`)
|
|
307
308
|
return badges
|
|
308
309
|
}
|
|
309
310
|
|
|
@@ -446,6 +447,17 @@ function PluginCard({ plugin, allowDelete, agents, onEdit, onToggle, onDelete, o
|
|
|
446
447
|
{badge}
|
|
447
448
|
</span>
|
|
448
449
|
))}
|
|
450
|
+
{plugin.hasDependencyManifest && (
|
|
451
|
+
<span className={`text-[10px] font-700 px-1.5 py-0.5 rounded-full ${
|
|
452
|
+
plugin.dependencyInstallStatus === 'installed'
|
|
453
|
+
? 'text-emerald-400 bg-emerald-500/10'
|
|
454
|
+
: plugin.dependencyInstallStatus === 'error'
|
|
455
|
+
? 'text-red-400 bg-red-500/10'
|
|
456
|
+
: 'text-amber-400 bg-amber-500/10'
|
|
457
|
+
}`}>
|
|
458
|
+
deps {plugin.dependencyInstallStatus || 'ready'}
|
|
459
|
+
</span>
|
|
460
|
+
)}
|
|
449
461
|
{plugin.author && (
|
|
450
462
|
<span className="text-[10px] text-text-3/40 ml-auto">
|
|
451
463
|
{plugin.author}
|