diff --git a/apps/desktop/package.json b/apps/desktop/package.json
index f9411f11..d09a1e98 100644
--- a/apps/desktop/package.json
+++ b/apps/desktop/package.json
@@ -13,13 +13,12 @@
"lint": "eslint . --ext ts,tsx --report-unused-disable-directives --max-warnings 0"
},
"dependencies": {
- "@hugeicons/core-free-icons": "catalog:",
- "@hugeicons/react": "catalog:",
"@multica/core": "workspace:*",
"@multica/hooks": "workspace:*",
"@multica/sdk": "workspace:*",
"@multica/store": "workspace:*",
"@multica/ui": "workspace:*",
+ "lucide-react": "^0.563.0",
"qrcode.react": "^4.2.0",
"react": "catalog:",
"react-dom": "catalog:",
diff --git a/apps/desktop/src/renderer/src/components/agent-settings-dialog.tsx b/apps/desktop/src/renderer/src/components/agent-settings-dialog.tsx
index bcd28a17..a8223bee 100644
--- a/apps/desktop/src/renderer/src/components/agent-settings-dialog.tsx
+++ b/apps/desktop/src/renderer/src/components/agent-settings-dialog.tsx
@@ -11,8 +11,7 @@ import { Button } from '@multica/ui/components/ui/button'
import { Input } from '@multica/ui/components/ui/input'
import { Textarea } from '@multica/ui/components/ui/textarea'
import { Label } from '@multica/ui/components/ui/label'
-import { HugeiconsIcon } from '@hugeicons/react'
-import { Loading03Icon } from '@hugeicons/core-free-icons'
+import { Loader2 } from 'lucide-react'
interface AgentSettingsDialogProps {
open: boolean
@@ -72,7 +71,7 @@ export function AgentSettingsDialog({ open, onOpenChange }: AgentSettingsDialogP
{loading ? (
-
+
No scheduled tasks
Use the cron tool in Chat to create one.
@@ -189,13 +189,13 @@ export function CronJobList({
disabled={isRemoving}
>
{isRemoving ? (
-
+
) : (
-
+
)}
{isToggling && (
-
+
)}
-
+
{displayName}
@@ -80,9 +79,9 @@ function DeviceItem({
disabled={revoking}
>
{revoking ? (
-
+
) : (
-
+
)}
@@ -112,7 +111,7 @@ export function DeviceList() {
className="h-7 px-2 text-xs gap-1"
onClick={refresh}
>
-
+
Refresh
diff --git a/apps/desktop/src/renderer/src/components/mode-toggle.tsx b/apps/desktop/src/renderer/src/components/mode-toggle.tsx
index 443a8f69..b65c5995 100644
--- a/apps/desktop/src/renderer/src/components/mode-toggle.tsx
+++ b/apps/desktop/src/renderer/src/components/mode-toggle.tsx
@@ -1,5 +1,4 @@
-import { HugeiconsIcon } from "@hugeicons/react"
-import { Sun03Icon, Moon02Icon, ComputerIcon } from "@hugeicons/core-free-icons"
+import { Sun, Moon, Monitor } from "lucide-react"
import {
DropdownMenu,
DropdownMenuContent,
@@ -11,25 +10,25 @@ import { useTheme } from "./theme-provider"
export function ModeToggle() {
const { theme, setTheme } = useTheme()
- const icon = theme === "light" ? Sun03Icon : theme === "dark" ? Moon02Icon : ComputerIcon
+ const Icon = theme === "light" ? Sun : theme === "dark" ? Moon : Monitor
return (
-
+
Toggle theme
setTheme("light")}>
-
+
Light
setTheme("dark")}>
-
+
Dark
setTheme("system")}>
-
+
System
diff --git a/apps/desktop/src/renderer/src/components/oauth-dialog.tsx b/apps/desktop/src/renderer/src/components/oauth-dialog.tsx
index e6573cf0..3631bbd9 100644
--- a/apps/desktop/src/renderer/src/components/oauth-dialog.tsx
+++ b/apps/desktop/src/renderer/src/components/oauth-dialog.tsx
@@ -8,8 +8,7 @@ import {
DialogDescription,
} from '@multica/ui/components/ui/dialog'
import { Button } from '@multica/ui/components/ui/button'
-import { HugeiconsIcon } from '@hugeicons/react'
-import { Loading03Icon, CommandLineIcon, RefreshIcon, Tick02Icon } from '@hugeicons/core-free-icons'
+import { Loader2, Terminal, RefreshCw, Check } from 'lucide-react'
interface OAuthDialogProps {
open: boolean
@@ -82,7 +81,7 @@ export function OAuthDialog({
-
+
Configure {providerName}
@@ -116,7 +115,7 @@ export function OAuthDialog({
{success && (
-
+
Credentials imported successfully!
{expiresAt && ` (expires in ${formatExpiry(expiresAt)})`}
@@ -131,9 +130,9 @@ export function OAuthDialog({
{importing ? (
-
+
) : (
-
+
)}
Refresh
diff --git a/apps/desktop/src/renderer/src/components/onboarding/permission-item.tsx b/apps/desktop/src/renderer/src/components/onboarding/permission-item.tsx
index d11ebdcd..dc07a94f 100644
--- a/apps/desktop/src/renderer/src/components/onboarding/permission-item.tsx
+++ b/apps/desktop/src/renderer/src/components/onboarding/permission-item.tsx
@@ -1,9 +1,8 @@
import { Switch } from '@multica/ui/components/ui/switch'
-import { HugeiconsIcon } from '@hugeicons/react'
-import type { IconSvgElement } from '@hugeicons/react'
+import type { LucideIcon } from 'lucide-react'
interface AcknowledgementItemProps {
- icon: IconSvgElement
+ icon: LucideIcon
title: string
description: string
checked: boolean
@@ -11,7 +10,7 @@ interface AcknowledgementItemProps {
}
export function AcknowledgementItem({
- icon,
+ icon: Icon,
title,
description,
checked,
@@ -20,7 +19,7 @@ export function AcknowledgementItem({
return (
-
+
{title}
diff --git a/apps/desktop/src/renderer/src/components/onboarding/privacy-panel.tsx b/apps/desktop/src/renderer/src/components/onboarding/privacy-panel.tsx
index e3f4c2cf..50eb287b 100644
--- a/apps/desktop/src/renderer/src/components/onboarding/privacy-panel.tsx
+++ b/apps/desktop/src/renderer/src/components/onboarding/privacy-panel.tsx
@@ -1,25 +1,20 @@
-import { HugeiconsIcon } from '@hugeicons/react'
-import {
- Key01Icon,
- Database01Icon,
- CommandLineIcon,
-} from '@hugeicons/core-free-icons'
+import { Key, Database, Terminal } from 'lucide-react'
const privacyItems = [
{
- icon: Database01Icon,
+ icon: Database,
title: 'Everything stays local',
description:
'All sessions, history, and profiles are stored on your device. Nothing leaves your computer.',
},
{
- icon: Key01Icon,
+ icon: Key,
title: 'Your data, your control',
description:
'API keys and credentials are saved locally in ~/.super-multica/. We never access them.',
},
{
- icon: CommandLineIcon,
+ icon: Terminal,
title: 'Transparent execution',
description:
'Every shell command the agent wants to run requires your explicit approval first.',
@@ -32,7 +27,7 @@ export function PrivacyPanel() {
{privacyItems.map((item) => (
-
+
{item.title}
diff --git a/apps/desktop/src/renderer/src/components/onboarding/provider-setup.tsx b/apps/desktop/src/renderer/src/components/onboarding/provider-setup.tsx
index a5af721c..bec86f5d 100644
--- a/apps/desktop/src/renderer/src/components/onboarding/provider-setup.tsx
+++ b/apps/desktop/src/renderer/src/components/onboarding/provider-setup.tsx
@@ -1,6 +1,5 @@
import { Button } from '@multica/ui/components/ui/button'
-import { HugeiconsIcon } from '@hugeicons/react'
-import { Tick02Icon } from '@hugeicons/core-free-icons'
+import { Check } from 'lucide-react'
import { cn } from '@multica/ui/lib/utils'
interface ProviderSetupProps {
@@ -64,7 +63,7 @@ function ProviderCard({
{provider.available ? (
-
+
)
}
diff --git a/apps/desktop/src/renderer/src/components/onboarding/stepper.tsx b/apps/desktop/src/renderer/src/components/onboarding/stepper.tsx
index 1b154054..1c28b2df 100644
--- a/apps/desktop/src/renderer/src/components/onboarding/stepper.tsx
+++ b/apps/desktop/src/renderer/src/components/onboarding/stepper.tsx
@@ -1,6 +1,5 @@
import { cn } from '@multica/ui/lib/utils'
-import { HugeiconsIcon } from '@hugeicons/react'
-import { Tick02Icon } from '@hugeicons/core-free-icons'
+import { Check } from 'lucide-react'
const steps = [
{ label: 'Privacy' },
@@ -49,10 +48,7 @@ export function Stepper({ currentStep }: StepperProps) {
)}
>
{isCompleted && (
-
+
)}
{step.label}
diff --git a/apps/desktop/src/renderer/src/components/qr-code.tsx b/apps/desktop/src/renderer/src/components/qr-code.tsx
index 17dd2dc1..28026d49 100644
--- a/apps/desktop/src/renderer/src/components/qr-code.tsx
+++ b/apps/desktop/src/renderer/src/components/qr-code.tsx
@@ -1,12 +1,7 @@
import { useState, useEffect, useCallback, useMemo } from 'react'
import { QRCodeSVG } from 'qrcode.react'
import { Button } from '@multica/ui/components/ui/button'
-import { HugeiconsIcon } from '@hugeicons/react'
-import {
- RefreshIcon,
- CheckmarkCircle02Icon,
- Copy01Icon,
-} from '@hugeicons/core-free-icons'
+import { RefreshCw, CheckCircle, Copy } from 'lucide-react'
export interface QRCodeData {
type: 'multica-connect'
@@ -177,7 +172,7 @@ export function ConnectionQRCode({
{isExpired && (
-
+
Refresh
@@ -204,10 +199,13 @@ export function ConnectionQRCode({
size="sm"
onClick={isExpired ? handleRefresh : handleCopyLink}
>
-
+ {isExpired ? (
+
+ ) : copied ? (
+
+ ) : (
+
+ )}
{isExpired ? 'Refresh' : (copied ? 'Copied!' : 'Copy Link')}
diff --git a/apps/desktop/src/renderer/src/components/skill-list.tsx b/apps/desktop/src/renderer/src/components/skill-list.tsx
index c74dc2c9..64210948 100644
--- a/apps/desktop/src/renderer/src/components/skill-list.tsx
+++ b/apps/desktop/src/renderer/src/components/skill-list.tsx
@@ -2,13 +2,12 @@ import { useState } from 'react'
import { Button } from '@multica/ui/components/ui/button'
import { Badge } from '@multica/ui/components/ui/badge'
import { Switch } from '@multica/ui/components/ui/switch'
-import { HugeiconsIcon } from '@hugeicons/react'
import {
- RotateClockwiseIcon,
- Loading03Icon,
- CheckmarkCircle02Icon,
- Cancel01Icon,
-} from '@hugeicons/core-free-icons'
+ RotateCw,
+ Loader2,
+ CheckCircle,
+ X,
+} from 'lucide-react'
import type { SkillInfo, SkillSource } from '../stores/skills'
// Source badge colors
@@ -69,7 +68,7 @@ export function SkillList({
if (loading && skills.length === 0) {
return (
-
+
Loading skills...
)
@@ -89,10 +88,11 @@ export function SkillList({
disabled={loading}
className="gap-1.5"
>
-
+ {loading ? (
+
+ ) : (
+
+ )}
Refresh
@@ -175,10 +175,11 @@ export function SkillList({
: 'text-muted-foreground'
}`}
>
-
+ {skill.enabled ? (
+
+ ) : (
+
+ )}
{skill.enabled ? 'Enabled' : 'Disabled'}
@@ -188,10 +189,7 @@ export function SkillList({
{/* Right: Toggle */}
{isToggling && (
-
+
)}
- ),
- info: (
-
- ),
- warning: (
-
- ),
- error: (
-
- ),
- loading: (
-
- ),
+ success:
,
+ info:
,
+ warning:
,
+ error:
,
+ loading:
,
}}
style={
{
diff --git a/apps/desktop/src/renderer/src/components/tool-list.tsx b/apps/desktop/src/renderer/src/components/tool-list.tsx
index 9c4f556d..9b2501fd 100644
--- a/apps/desktop/src/renderer/src/components/tool-list.tsx
+++ b/apps/desktop/src/renderer/src/components/tool-list.tsx
@@ -1,19 +1,18 @@
import { useState, useMemo } from 'react'
import { Switch } from '@multica/ui/components/ui/switch'
import { Button } from '@multica/ui/components/ui/button'
-import { HugeiconsIcon } from '@hugeicons/react'
import {
- RotateClockwiseIcon,
- FolderOpenIcon,
- CodeIcon,
- GlobalIcon,
- AiBrainIcon,
- ArrowDown01Icon,
- ArrowUp01Icon,
- Loading03Icon,
- Time04Icon,
- UserMultipleIcon,
-} from '@hugeicons/core-free-icons'
+ RotateCw,
+ FolderOpen,
+ Code,
+ Globe,
+ Brain,
+ ChevronDown,
+ ChevronUp,
+ Loader2,
+ Clock,
+ Users,
+} from 'lucide-react'
import type { ToolInfo } from '../stores/tools'
// Group display names
@@ -28,14 +27,14 @@ const GROUP_NAMES: Record
= {
}
// Group icons
-const GROUP_ICONS: Record = {
- fs: FolderOpenIcon,
- runtime: CodeIcon,
- web: GlobalIcon,
- memory: AiBrainIcon,
- subagent: UserMultipleIcon,
- cron: Time04Icon,
- other: CodeIcon,
+const GROUP_ICONS: Record = {
+ fs: FolderOpen,
+ runtime: Code,
+ web: Globe,
+ memory: Brain,
+ subagent: Users,
+ cron: Clock,
+ other: Code,
}
interface ToolListProps {
@@ -101,7 +100,7 @@ export function ToolList({
if (loading && tools.length === 0) {
return (
-
+
Loading tools...
)
@@ -122,10 +121,11 @@ export function ToolList({
className="gap-1.5"
disabled={loading}
>
-
+ {loading ? (
+
+ ) : (
+
+ )}
Refresh
@@ -141,7 +141,7 @@ export function ToolList({
{groups.map((group) => {
const isExpanded = expandedGroups.has(group.id)
- const GroupIcon = GROUP_ICONS[group.id] || CodeIcon
+ const GroupIcon = GROUP_ICONS[group.id] || Code
return (
-
+
{group.name}
{group.enabledCount}/{group.totalCount} enabled
-
+ {isExpanded ? (
+
+ ) : (
+
+ )}
{/* Group tools */}
@@ -196,7 +197,7 @@ export function ToolList({
{isToggling && (
-
+
)}
-
+
Connecting to Hub...
@@ -101,7 +100,7 @@ export default function HomePage() {
return (
-
+
Connection Error
{error}
@@ -180,7 +179,7 @@ export default function HomePage() {
size="icon-sm"
onClick={() => setSettingsOpen(true)}
>
-
+
{agentName || 'Unnamed Agent'}
@@ -198,17 +197,16 @@ export default function HomePage() {
>
{current?.available ? (
-
+
) : (
-
+
)}
{current?.providerName ?? current?.provider ?? 'Loading...'}
{current?.model ?? '-'}
-
@@ -389,7 +387,7 @@ export default function HomePage() {
onClick={() => navigate('/chat')}
disabled={!isConnected}
>
-
+
Open Chat
@@ -399,7 +397,7 @@ export default function HomePage() {
size="sm"
className="text-muted-foreground gap-1.5"
>
-
+
Connect to Remote Agent
diff --git a/apps/desktop/src/renderer/src/pages/home.tsx b/apps/desktop/src/renderer/src/pages/home.tsx
index 98de475c..70b92d1a 100644
--- a/apps/desktop/src/renderer/src/pages/home.tsx
+++ b/apps/desktop/src/renderer/src/pages/home.tsx
@@ -11,23 +11,21 @@ import {
TooltipTrigger,
TooltipContent,
} from '@multica/ui/components/ui/tooltip'
-import { HugeiconsIcon } from '@hugeicons/react'
import {
- Comment01Icon,
- Loading03Icon,
- ArrowDown01Icon,
- Tick02Icon,
- Alert02Icon,
- ArrowRight01Icon,
- QrCodeIcon,
- Edit02Icon,
- PlugIcon,
- CodeIcon,
- Share08Icon,
- Time04Icon,
- AiBrain01Icon,
- ArrowReloadHorizontalIcon,
-} from '@hugeicons/core-free-icons'
+ Loader2,
+ ChevronDown,
+ Check,
+ AlertCircle,
+ ArrowRight,
+ QrCode,
+ Pencil,
+ Plug,
+ Code,
+ Share,
+ Clock,
+ Brain,
+ RefreshCw,
+} from 'lucide-react'
import { ConnectionQRCode } from '../components/qr-code'
import { DeviceList } from '../components/device-list'
import { AgentSettingsDialog } from '../components/agent-settings-dialog'
@@ -127,7 +125,7 @@ export default function HomePage() {
return (
@@ -139,10 +137,10 @@ export default function HomePage() {
setCapabilitiesRefreshing(true)
try {
await Promise.all([
- useSkillsStore.getState().refresh(),
- useToolsStore.getState().refresh(),
- useChannelsStore.getState().refresh(),
- useCronJobsStore.getState().refresh(),
+ useSkillsStore.getState().refresh({ silent: true }),
+ useToolsStore.getState().refresh({ silent: true }),
+ useChannelsStore.getState().refresh({ silent: true }),
+ useCronJobsStore.getState().refresh({ silent: true }),
])
toast.success('Status refreshed')
} catch (err) {
@@ -153,7 +151,7 @@ export default function HomePage() {
}
}
- // Build capability summary (always show all, even if zero)
+ // Build capability summary
const capabilitySummary = `${skillStats.enabled} skills, ${enabledTools} tools, ${connectedChannels} channels, ${cronCount} scheduled tasks`
return (
@@ -202,13 +200,14 @@ export default function HomePage() {
navigate('/chat')}
disabled={!agentReady}
>
-
Start Chat
+
@@ -226,7 +225,7 @@ export default function HomePage() {
onClick={() => setSettingsOpen(true)}
>
{agentName || 'Unnamed Agent'}
-
+
@@ -241,16 +240,15 @@ export default function HomePage() {
>
{current?.available ? (
-
+
) : (
-
+
)}
{current?.providerName ?? 'Loading...'}
·
{current?.model ?? '-'}
-
-
+
-
+
Your agent has {capabilitySummary}
{
- e.stopPropagation()
- refreshCapabilities()
- }}
+ onClick={refreshCapabilities}
disabled={capabilitiesRefreshing}
className="p-1 text-muted-foreground hover:text-foreground transition-colors disabled:opacity-50"
>
-
+ {capabilitiesRefreshing ? (
+
+ ) : (
+
+ )}
Refresh status
-
+
{capabilitiesOpen ? 'Hide' : 'Details'}
-
-
-
+
+
{/* Skills */}
-
+
Skills ({skillStats.enabled})
navigate('/skills')}
>
View all
-
+
{skillStats.enabled > 0 ? (
@@ -445,7 +440,7 @@ export default function HomePage() {
-
+
Tools ({enabledTools})
navigate('/tools')}
>
View all
-
+
{enabledTools > 0 ? (
@@ -484,7 +479,7 @@ export default function HomePage() {
-
+
Channels ({connectedChannels})
navigate('/channels')}
>
View all
-
+
{connectedChannels > 0 ? (
@@ -522,7 +517,7 @@ export default function HomePage() {
-
+
Scheduled Tasks ({cronCount})
navigate('/crons')}
>
View all
-
+
{cronCount > 0 ? (
@@ -574,7 +569,7 @@ export default function HomePage() {
size="sm"
onClick={() => setQrCodeExpanded(!qrCodeExpanded)}
>
-
+
{qrCodeExpanded ? 'Hide' : 'Show'}
@@ -597,7 +592,7 @@ export default function HomePage() {
onClick={() => setQrCodeExpanded(true)}
className="flex flex-col items-center justify-center gap-3 p-8 rounded-xl border-2 border-dashed border-muted-foreground/25 hover:border-muted-foreground/50 transition-colors cursor-pointer"
>
-
+
Click to show QR code
)}
diff --git a/apps/desktop/src/renderer/src/pages/layout.tsx b/apps/desktop/src/renderer/src/pages/layout.tsx
index 01921318..e9cf256d 100644
--- a/apps/desktop/src/renderer/src/pages/layout.tsx
+++ b/apps/desktop/src/renderer/src/pages/layout.tsx
@@ -1,17 +1,15 @@
import { Outlet, NavLink, useLocation, useNavigate } from 'react-router-dom'
-import { Toaster } from '@multica/ui/components/ui/sonner'
import { Button } from '@multica/ui/components/ui/button'
-import { HugeiconsIcon } from '@hugeicons/react'
import {
- Home01Icon,
- Comment01Icon,
- PuzzleIcon,
- Wrench01Icon,
- Message01Icon,
- RepeatIcon,
- ArrowLeft02Icon,
- ArrowRight02Icon,
-} from '@hugeicons/core-free-icons'
+ Home,
+ MessageSquare,
+ Puzzle,
+ Wrench,
+ Mail,
+ Repeat,
+ ChevronLeft,
+ ChevronRight,
+} from 'lucide-react'
import {
Sidebar,
SidebarContent,
@@ -31,15 +29,15 @@ import { ModeToggle } from '../components/mode-toggle'
import { DeviceConfirmDialog } from '../components/device-confirm-dialog'
const mainNavItems = [
- { path: '/', label: 'Home', icon: Home01Icon },
- { path: '/chat', label: 'Chat', icon: Comment01Icon },
+ { path: '/', label: 'Home', icon: Home },
+ { path: '/chat', label: 'Chat', icon: MessageSquare },
]
const configNavItems = [
- { path: '/skills', label: 'Skills', icon: PuzzleIcon },
- { path: '/tools', label: 'Tools', icon: Wrench01Icon },
- { path: '/channels', label: 'Channels', icon: Message01Icon },
- { path: '/crons', label: 'Crons', icon: RepeatIcon },
+ { path: '/skills', label: 'Skills', icon: Puzzle },
+ { path: '/tools', label: 'Tools', icon: Wrench },
+ { path: '/channels', label: 'Channels', icon: Mail },
+ { path: '/crons', label: 'Crons', icon: Repeat },
]
// All nav items for header lookup
@@ -65,7 +63,7 @@ function NavigationButtons() {
onClick={() => navigate(-1)}
disabled={!canGoBack}
>
-
+
navigate(1)}
disabled={!canGoForward}
>
-
+
)
@@ -108,7 +106,7 @@ function MainHeader() {
{currentPage && (
-
+
{currentPage.label}
)}
@@ -147,8 +145,7 @@ export default function Layout() {
-
-
-
diff --git a/apps/desktop/src/renderer/src/pages/onboarding/components/connect-step.tsx b/apps/desktop/src/renderer/src/pages/onboarding/components/connect-step.tsx
index bdabb52a..1ab0198a 100644
--- a/apps/desktop/src/renderer/src/pages/onboarding/components/connect-step.tsx
+++ b/apps/desktop/src/renderer/src/pages/onboarding/components/connect-step.tsx
@@ -8,15 +8,14 @@ import {
HoverCardContent,
HoverCardTrigger,
} from '@multica/ui/components/ui/hover-card'
-import { HugeiconsIcon } from '@hugeicons/react'
import {
- ArrowLeft02Icon,
- Loading03Icon,
- HelpCircleIcon,
- Share08Icon,
- Tick02Icon,
- InformationCircleIcon,
-} from '@hugeicons/core-free-icons'
+ ChevronLeft,
+ Loader2,
+ HelpCircle,
+ Share2,
+ Check,
+ Info,
+} from 'lucide-react'
import { useChannelsStore } from '../../../stores/channels'
import { StepDots } from './step-dots'
@@ -78,7 +77,7 @@ export default function ConnectStep({ onNext, onBack }: ConnectStepProps) {
onClick={onBack}
className="flex items-center gap-1.5 text-sm text-muted-foreground hover:text-foreground transition-colors"
>
-
+
Back
@@ -99,7 +98,7 @@ export default function ConnectStep({ onNext, onBack }: ConnectStepProps) {
chat from your phone, tablet, or any device.
-
+
Telegram now. Discord, Slack, Mobile app coming soon.
@@ -109,10 +108,7 @@ export default function ConnectStep({ onNext, onBack }: ConnectStepProps) {
-
+
Telegram
@@ -133,7 +129,7 @@ export default function ConnectStep({ onNext, onBack }: ConnectStepProps) {
{/* Help hover card */}
-
+
@@ -161,10 +157,7 @@ export default function ConnectStep({ onNext, onBack }: ConnectStepProps) {
{hasToken ? (
-
+
{isRunning
? 'Bot is running. Send it a message to test.'
@@ -190,10 +183,7 @@ export default function ConnectStep({ onNext, onBack }: ConnectStepProps) {
disabled={saving || !token.trim()}
>
{saving && (
-
+
)}
Connect
diff --git a/apps/desktop/src/renderer/src/pages/onboarding/components/permissions-step.tsx b/apps/desktop/src/renderer/src/pages/onboarding/components/permissions-step.tsx
index e9832b00..c51057b5 100644
--- a/apps/desktop/src/renderer/src/pages/onboarding/components/permissions-step.tsx
+++ b/apps/desktop/src/renderer/src/pages/onboarding/components/permissions-step.tsx
@@ -2,33 +2,32 @@ import { useState } from 'react'
import { Button } from '@multica/ui/components/ui/button'
import { Checkbox } from '@multica/ui/components/ui/checkbox'
import { Separator } from '@multica/ui/components/ui/separator'
-import { HugeiconsIcon } from '@hugeicons/react'
import {
- FolderOpenIcon,
- CommandLineIcon,
- AiBrainIcon,
- Database01Icon,
-} from '@hugeicons/core-free-icons'
+ FolderOpen,
+ Terminal,
+ Brain,
+ Database,
+} from 'lucide-react'
import { StepDots } from './step-dots'
const capabilities = [
{
- icon: FolderOpenIcon,
+ icon: FolderOpen,
title: 'File access',
description: 'Read & write files to complete tasks you assign',
},
{
- icon: CommandLineIcon,
+ icon: Terminal,
title: 'Shell commands',
description: 'Run commands — every one requires your approval',
},
{
- icon: AiBrainIcon,
+ icon: Brain,
title: 'LLM requests',
description: 'Send prompts using your API key directly',
},
{
- icon: Database01Icon,
+ icon: Database,
title: 'Local storage',
description: 'Sessions & credentials saved in ~/.super-multica/',
},
@@ -59,10 +58,7 @@ export default function PermissionsStep({ onNext }: PermissionsStepProps) {
{capabilities.map((item) => (
-
+
{item.title}
diff --git a/apps/desktop/src/renderer/src/pages/onboarding/components/setup-step.tsx b/apps/desktop/src/renderer/src/pages/onboarding/components/setup-step.tsx
index b5423a7f..81831024 100644
--- a/apps/desktop/src/renderer/src/pages/onboarding/components/setup-step.tsx
+++ b/apps/desktop/src/renderer/src/pages/onboarding/components/setup-step.tsx
@@ -7,8 +7,7 @@ import {
HoverCardTrigger,
} from '@multica/ui/components/ui/hover-card'
import { Link } from '@multica/ui/components/ui/link'
-import { HugeiconsIcon } from '@hugeicons/react'
-import { ArrowLeft02Icon, HelpCircleIcon } from '@hugeicons/core-free-icons'
+import { ChevronLeft, HelpCircle } from 'lucide-react'
import { cn } from '@multica/ui/lib/utils'
import { useProviderStore } from '../../../stores/provider'
import { ApiKeyDialog } from '../../../components/api-key-dialog'
@@ -70,7 +69,7 @@ export default function SetupStep({ onNext, onBack }: SetupStepProps) {
onClick={onBack}
className="flex items-center gap-1.5 text-sm text-muted-foreground hover:text-foreground transition-colors"
>
-
+
Back
@@ -214,7 +213,7 @@ function ProviderRow({
onClick={(e) => e.stopPropagation()}
className="p-1 text-muted-foreground hover:text-foreground transition-colors"
>
-
+
Setup {provider.name}
diff --git a/apps/desktop/src/renderer/src/pages/onboarding/components/try-it-step.tsx b/apps/desktop/src/renderer/src/pages/onboarding/components/try-it-step.tsx
index 0ccf8a8a..69ef582c 100644
--- a/apps/desktop/src/renderer/src/pages/onboarding/components/try-it-step.tsx
+++ b/apps/desktop/src/renderer/src/pages/onboarding/components/try-it-step.tsx
@@ -1,31 +1,30 @@
import { useNavigate } from 'react-router-dom'
import { Button } from '@multica/ui/components/ui/button'
import { Separator } from '@multica/ui/components/ui/separator'
-import { HugeiconsIcon } from '@hugeicons/react'
import {
- ArrowLeft02Icon,
- ArrowRight01Icon,
- Search01Icon,
- FolderOpenIcon,
- CommandLineIcon,
-} from '@hugeicons/core-free-icons'
+ ChevronLeft,
+ ArrowRight,
+ Search,
+ FolderOpen,
+ Terminal,
+} from 'lucide-react'
import { StepDots } from './step-dots'
const tryPrompts = [
{
- icon: Search01Icon,
+ icon: Search,
title: 'Search the web',
description: "Get today's AI news",
prompt: "Search the web for today's top AI news and give me a 3-bullet summary with sources.",
},
{
- icon: FolderOpenIcon,
+ icon: FolderOpen,
title: 'Read your files',
description: 'Summarize this directory',
prompt: 'Look at the files in my current directory and give me a brief summary of what this project is about.',
},
{
- icon: CommandLineIcon,
+ icon: Terminal,
title: 'Run a command',
description: 'Show system info',
prompt: 'Write a one-liner shell command that shows my system info (OS, CPU cores, memory) and run it.',
@@ -55,7 +54,7 @@ export default function TryItStep({ onComplete, onBack }: TryItStepProps) {
onClick={onBack}
className="flex items-center gap-1.5 text-sm text-muted-foreground hover:text-foreground transition-colors"
>
-
+
Back
@@ -83,10 +82,7 @@ export default function TryItStep({ onComplete, onBack }: TryItStepProps) {
>
-
+
{item.title}
@@ -95,10 +91,7 @@ export default function TryItStep({ onComplete, onBack }: TryItStepProps) {
-
+
))}
diff --git a/apps/desktop/src/renderer/src/stores/channels.ts b/apps/desktop/src/renderer/src/stores/channels.ts
index ea6e1be8..1c7e9f0d 100644
--- a/apps/desktop/src/renderer/src/stores/channels.ts
+++ b/apps/desktop/src/renderer/src/stores/channels.ts
@@ -14,7 +14,7 @@ interface ChannelsStore {
// Actions
fetch: () => Promise
- refresh: () => Promise
+ refresh: (options?: { silent?: boolean }) => Promise
saveToken: (channelId: string, accountId: string, token: string) => Promise<{ ok: boolean; error?: string }>
removeToken: (channelId: string, accountId: string) => Promise<{ ok: boolean; error?: string }>
stopChannel: (channelId: string, accountId: string) => Promise<{ ok: boolean; error?: string }>
@@ -54,7 +54,7 @@ export const useChannelsStore = create()((set, get) => ({
}
},
- refresh: async () => {
+ refresh: async (options?: { silent?: boolean }) => {
set({ loading: true, error: null })
const startTime = Date.now()
@@ -75,6 +75,7 @@ export const useChannelsStore = create()((set, get) => ({
states: stateList,
config: channelConfig,
})
+ if (!options?.silent) toast.success('Channels refreshed')
} catch (err) {
const message = err instanceof Error ? err.message : String(err)
set({ error: message })
diff --git a/apps/desktop/src/renderer/src/stores/cron-jobs.ts b/apps/desktop/src/renderer/src/stores/cron-jobs.ts
index b27fdf5c..9257ff9c 100644
--- a/apps/desktop/src/renderer/src/stores/cron-jobs.ts
+++ b/apps/desktop/src/renderer/src/stores/cron-jobs.ts
@@ -28,7 +28,7 @@ interface CronJobsStore {
// Actions
fetch: () => Promise
- refresh: () => Promise
+ refresh: (options?: { silent?: boolean }) => Promise
toggleJob: (jobId: string) => Promise
removeJob: (jobId: string) => Promise
}
@@ -65,7 +65,7 @@ export const useCronJobsStore = create()((set, get) => ({
}
},
- refresh: async () => {
+ refresh: async (options?: { silent?: boolean }) => {
set({ loading: true, error: null })
const startTime = Date.now()
@@ -81,6 +81,7 @@ export const useCronJobsStore = create()((set, get) => ({
if (Array.isArray(result)) {
set({ jobs: result as CronJobInfo[] })
+ if (!options?.silent) toast.success('Tasks refreshed')
} else {
set({ error: 'Invalid response from cron:list' })
}
diff --git a/apps/desktop/src/renderer/src/stores/skills.ts b/apps/desktop/src/renderer/src/stores/skills.ts
index d26658e4..64a5fceb 100644
--- a/apps/desktop/src/renderer/src/stores/skills.ts
+++ b/apps/desktop/src/renderer/src/stores/skills.ts
@@ -26,7 +26,7 @@ interface SkillsStore {
// Actions
fetch: () => Promise
- refresh: () => Promise
+ refresh: (options?: { silent?: boolean }) => Promise
toggleSkill: (skillId: string) => Promise
setSkillStatus: (skillId: string, enabled: boolean) => Promise
}
@@ -63,7 +63,7 @@ export const useSkillsStore = create()((set, get) => ({
}
},
- refresh: async () => {
+ refresh: async (options?: { silent?: boolean }) => {
set({ loading: true, error: null })
const startTime = Date.now()
@@ -79,6 +79,7 @@ export const useSkillsStore = create()((set, get) => ({
if (Array.isArray(result)) {
set({ skills: result })
+ if (!options?.silent) toast.success('Skills refreshed')
} else {
set({ error: 'Invalid response from skills:list' })
}
diff --git a/apps/desktop/src/renderer/src/stores/tools.ts b/apps/desktop/src/renderer/src/stores/tools.ts
index 6069f245..9bbb14a7 100644
--- a/apps/desktop/src/renderer/src/stores/tools.ts
+++ b/apps/desktop/src/renderer/src/stores/tools.ts
@@ -39,7 +39,7 @@ interface ToolsStore {
// Actions
fetch: () => Promise
- refresh: () => Promise
+ refresh: (options?: { silent?: boolean }) => Promise
toggleTool: (toolName: string) => Promise
setToolStatus: (toolName: string, enabled: boolean) => Promise
}
@@ -81,7 +81,7 @@ export const useToolsStore = create()((set, get) => ({
}
},
- refresh: async () => {
+ refresh: async (options?: { silent?: boolean }) => {
set({ loading: true, error: null })
const startTime = Date.now()
@@ -101,6 +101,7 @@ export const useToolsStore = create()((set, get) => ({
description: TOOL_DESCRIPTIONS[tool.name],
}))
set({ tools: toolsWithDesc })
+ if (!options?.silent) toast.success('Tools refreshed')
} else {
set({ error: 'Invalid response from tools:list' })
}
diff --git a/apps/mobile/app/index.tsx b/apps/mobile/app/index.tsx
index 4cb92f6e..dd1ad038 100644
--- a/apps/mobile/app/index.tsx
+++ b/apps/mobile/app/index.tsx
@@ -11,8 +11,7 @@ import {
} from "react-native";
import { SafeAreaView } from "react-native-safe-area-context";
import { Text } from "@/components/ui/text";
-import { HugeiconsIcon } from "@hugeicons/react-native";
-import { ArrowUp01Icon } from "@hugeicons/core-free-icons";
+import { ArrowUp } from "lucide-react-native";
// Enable LayoutAnimation on Android
if (Platform.OS === "android" && UIManager.setLayoutAnimationEnabledExperimental) {
@@ -152,11 +151,9 @@ export default function Index() {
className="ml-1.5 h-8 w-8 items-center justify-center rounded-full bg-primary"
style={{ opacity: canSend ? 1 : 0.5 }}
>
-
diff --git a/apps/mobile/package.json b/apps/mobile/package.json
index 34086249..9d8c3828 100644
--- a/apps/mobile/package.json
+++ b/apps/mobile/package.json
@@ -12,8 +12,6 @@
},
"dependencies": {
"@expo/vector-icons": "^15.0.3",
- "@hugeicons/core-free-icons": "^3.1.1",
- "@hugeicons/react-native": "^1.0.11",
"@react-navigation/bottom-tabs": "^7.4.0",
"@react-navigation/elements": "^2.6.3",
"@react-navigation/native": "^7.1.8",
diff --git a/apps/web/app/theme-toggle.tsx b/apps/web/app/theme-toggle.tsx
index 70eb691e..84d24590 100644
--- a/apps/web/app/theme-toggle.tsx
+++ b/apps/web/app/theme-toggle.tsx
@@ -2,8 +2,7 @@
import { useTheme } from "next-themes";
import { Button } from "@multica/ui/components/ui/button";
-import { HugeiconsIcon } from "@hugeicons/react";
-import { Sun01Icon, Moon01Icon } from "@hugeicons/core-free-icons";
+import { Sun, Moon } from "lucide-react";
export function ThemeToggle() {
const { theme, setTheme } = useTheme();
@@ -15,8 +14,8 @@ export function ThemeToggle() {
onClick={() => setTheme(theme === "dark" ? "light" : "dark")}
className="size-8 text-muted-foreground"
>
-
-
+
+
);
}
diff --git a/apps/web/components.json b/apps/web/components.json
index 38168ef0..663cf01d 100644
--- a/apps/web/components.json
+++ b/apps/web/components.json
@@ -9,7 +9,7 @@
"baseColor": "zinc",
"cssVariables": true
},
- "iconLibrary": "hugeicons",
+ "iconLibrary": "lucide",
"aliases": {
"components": "@/components",
"hooks": "@/hooks",
diff --git a/apps/web/package.json b/apps/web/package.json
index 2104dc0a..1141dec3 100644
--- a/apps/web/package.json
+++ b/apps/web/package.json
@@ -13,14 +13,12 @@
"@multica/sdk": "workspace:*",
"@multica/store": "workspace:*",
"@multica/ui": "workspace:*",
- "uuid": "catalog:",
- "zustand": "catalog:",
- "@hugeicons/core-free-icons": "catalog:",
- "@hugeicons/react": "catalog:",
"next": "16.1.6",
"next-themes": "^0.4.6",
"react": "catalog:",
- "react-dom": "catalog:"
+ "react-dom": "catalog:",
+ "uuid": "catalog:",
+ "zustand": "catalog:"
},
"devDependencies": {
"@types/node": "catalog:",
diff --git a/package.json b/package.json
index 7708d8c7..3a629fad 100644
--- a/package.json
+++ b/package.json
@@ -73,6 +73,7 @@
"grammy": "^1.39.3",
"json5": "^2.2.3",
"linkedom": "^0.18.12",
+ "lucide-react": "^0.563.0",
"mysql2": "^3.14.1",
"nestjs-pino": "^4.5.0",
"pino": "^10.3.0",
diff --git a/packages/ui/components.json b/packages/ui/components.json
index b439442e..2f8a9e36 100644
--- a/packages/ui/components.json
+++ b/packages/ui/components.json
@@ -9,7 +9,7 @@
"baseColor": "zinc",
"cssVariables": true
},
- "iconLibrary": "hugeicons",
+ "iconLibrary": "lucide",
"aliases": {
"components": "@multica/ui/components",
"utils": "@multica/ui/lib/utils",
diff --git a/packages/ui/package.json b/packages/ui/package.json
index 09023c17..b33bd59a 100644
--- a/packages/ui/package.json
+++ b/packages/ui/package.json
@@ -27,8 +27,6 @@
"@fontsource-variable/playfair-display": "^5.2.8",
"@fontsource/geist-mono": "^5.2.7",
"@fontsource/geist-sans": "^5.2.5",
- "@hugeicons/core-free-icons": "catalog:",
- "@hugeicons/react": "catalog:",
"@multica/store": "workspace:*",
"@tiptap/extension-placeholder": "^3.19.0",
"@tiptap/pm": "^3.19.0",
@@ -37,6 +35,7 @@
"class-variance-authority": "catalog:",
"clsx": "catalog:",
"linkify-it": "^5.0.0",
+ "lucide-react": "^0.563.0",
"next-themes": "^0.4.6",
"qr-scanner": "^1.4.2",
"react": "catalog:",
diff --git a/packages/ui/src/components/chat-input.tsx b/packages/ui/src/components/chat-input.tsx
index 9bd51fd4..f0bbe44f 100644
--- a/packages/ui/src/components/chat-input.tsx
+++ b/packages/ui/src/components/chat-input.tsx
@@ -4,8 +4,7 @@ import { useEditor, EditorContent } from "@tiptap/react";
import StarterKit from "@tiptap/starter-kit";
import Placeholder from "@tiptap/extension-placeholder";
import { Button } from "@multica/ui/components/ui/button";
-import { ArrowUp02Icon } from "@hugeicons/core-free-icons";
-import { HugeiconsIcon } from "@hugeicons/react";
+import { ArrowUp } from "lucide-react";
import { cn } from "@multica/ui/lib/utils";
import "./chat-input.css";
@@ -124,7 +123,7 @@ export const ChatInput = forwardRef(
diff --git a/packages/ui/src/components/device-pairing.tsx b/packages/ui/src/components/device-pairing.tsx
index 27d95807..afae275f 100644
--- a/packages/ui/src/components/device-pairing.tsx
+++ b/packages/ui/src/components/device-pairing.tsx
@@ -5,13 +5,7 @@ import { Button } from "@multica/ui/components/ui/button";
import { Textarea } from "@multica/ui/components/ui/textarea";
import { Spinner } from "@multica/ui/components/spinner";
import { useIsMobile } from "@multica/ui/hooks/use-mobile";
-import { HugeiconsIcon } from "@hugeicons/react";
-import {
- Camera01Icon,
- TextIcon,
- CheckmarkCircle02Icon,
- Alert02Icon,
-} from "@hugeicons/core-free-icons";
+import { Camera, Type, CheckCircle, AlertCircle } from "lucide-react";
import { QrScannerView } from "@multica/ui/components/qr-scanner-view";
import { MulticaIcon } from "@multica/ui/components/multica-icon";
import { parseConnectionCode } from "@multica/store";
@@ -107,8 +101,7 @@ function RejectedStatus({
return (
-
@@ -249,7 +242,7 @@ export function DevicePairing({
className="text-xs gap-1.5 h-7 px-3"
onClick={() => setMode("scan")}
>
-
+
Scan
setMode("paste")}
>
-
+
Paste
@@ -287,16 +280,14 @@ export function DevicePairing({
)}
{pasteState === "success" && (
-
)}
{pasteState === "error" && (
-
{pasteError && (
diff --git a/packages/ui/src/components/exec-approval-item.tsx b/packages/ui/src/components/exec-approval-item.tsx
index 662d6136..8421edb8 100644
--- a/packages/ui/src/components/exec-approval-item.tsx
+++ b/packages/ui/src/components/exec-approval-item.tsx
@@ -1,13 +1,7 @@
"use client"
import { memo, useState, useEffect, useCallback } from "react"
-import { HugeiconsIcon } from "@hugeicons/react"
-import {
- Tick01Icon,
- TickDouble01Icon,
- Cancel01Icon,
- CommandLineIcon,
-} from "@hugeicons/core-free-icons"
+import { Check, CheckCheck, X, Terminal } from "lucide-react"
import { cn } from "@multica/ui/lib/utils"
import { Button } from "@multica/ui/components/ui/button"
@@ -75,7 +69,7 @@ export const ExecApprovalItem = memo(function ExecApprovalItem({
{/* Header: icon + risk label + countdown */}
-
+
{riskLabel}
{remaining !== null && remaining > 0 && !decided && (
@@ -113,7 +107,7 @@ export const ExecApprovalItem = memo(function ExecApprovalItem({
className="h-7 text-xs gap-1.5 px-2.5"
onClick={() => handleDecision("allow-once")}
>
-
+
Allow
handleDecision("allow-always")}
>
-
+
Always
handleDecision("deny")}
>
-
+
Deny
diff --git a/packages/ui/src/components/qr-scanner-view.tsx b/packages/ui/src/components/qr-scanner-view.tsx
index 41dcaef8..bc446475 100644
--- a/packages/ui/src/components/qr-scanner-view.tsx
+++ b/packages/ui/src/components/qr-scanner-view.tsx
@@ -5,14 +5,7 @@ import "./qr-scanner.css"
import { useState, useCallback, useRef, useEffect } from "react"
import { useQrScanner } from "@multica/ui/hooks/use-qr-scanner"
import { Spinner } from "@multica/ui/components/spinner"
-import { HugeiconsIcon } from "@hugeicons/react"
-import {
- Camera01Icon,
- Cancel01Icon,
- CheckmarkCircle02Icon,
- Alert02Icon,
- FlashlightIcon,
-} from "@hugeicons/core-free-icons"
+import { Camera, X, CheckCircle, AlertCircle, Flashlight } from "lucide-react"
type ScannerState =
| "idle"
@@ -203,8 +196,7 @@ export function QrScannerView({
onClick={handleStart}
className="flex items-center justify-center size-16 rounded-full bg-foreground/10 hover:bg-foreground/20 transition-colors"
>
-
@@ -252,10 +244,8 @@ export function QrScannerView({
onClick={handleClose}
className="absolute top-3 left-3 flex items-center justify-center size-8 rounded-full bg-black/40 hover:bg-black/60 transition-colors z-10"
>
-
)}
@@ -267,8 +257,7 @@ export function QrScannerView({
onClick={toggleFlash}
className="absolute top-3 right-3 flex items-center justify-center size-8 rounded-full bg-black/40 hover:bg-black/60 transition-colors"
>
-
@@ -277,8 +266,7 @@ export function QrScannerView({
{/* Success — full overlay */}
{state === "success" && (
-
@@ -287,8 +275,7 @@ export function QrScannerView({
{/* Error — full overlay */}
{state === "error" && (
-
{errorMessage && (
diff --git a/packages/ui/src/components/theme-toggle.tsx b/packages/ui/src/components/theme-toggle.tsx
index 45aa42dc..865269ac 100644
--- a/packages/ui/src/components/theme-toggle.tsx
+++ b/packages/ui/src/components/theme-toggle.tsx
@@ -1,8 +1,7 @@
"use client"
import { useTheme } from "next-themes"
-import { HugeiconsIcon } from "@hugeicons/react"
-import { Sun01Icon, Moon01Icon, ComputerIcon } from "@hugeicons/core-free-icons"
+import { Sun, Moon, Monitor } from "lucide-react"
import {
DropdownMenu,
DropdownMenuTrigger,
@@ -19,21 +18,21 @@ export function ThemeToggle() {
-
-
+
+
Theme
}
/>
setTheme("light")}>
- Light
+ Light
setTheme("dark")}>
- Dark
+ Dark
setTheme("system")}>
- System
+ System
diff --git a/packages/ui/src/components/thinking-item.tsx b/packages/ui/src/components/thinking-item.tsx
index 417fa362..4ad9ca91 100644
--- a/packages/ui/src/components/thinking-item.tsx
+++ b/packages/ui/src/components/thinking-item.tsx
@@ -1,11 +1,7 @@
"use client"
import { memo, useState } from "react"
-import { HugeiconsIcon } from "@hugeicons/react"
-import {
- AiBrain01Icon,
- ArrowRight01Icon,
-} from "@hugeicons/core-free-icons"
+import { Brain, ChevronRight } from "lucide-react"
import { cn } from "@multica/ui/lib/utils"
interface ThinkingItemProps {
@@ -47,9 +43,7 @@ export const ThinkingItem = memo(function ThinkingItem({ thinking, isStreaming }
/>
{/* Icon */}
-
@@ -67,9 +61,7 @@ export const ThinkingItem = memo(function ThinkingItem({ thinking, isStreaming }
{/* Chevron — visible on hover when expandable */}
{hasContent && (
- = {
- read: { label: "Read", icon: File01Icon },
- write: { label: "Write", icon: FloppyDiskIcon },
- edit: { label: "Edit", icon: FileEditIcon },
- exec: { label: "Exec", icon: CommandLineIcon },
- bash: { label: "Exec", icon: CommandLineIcon },
- process: { label: "Process", icon: CommandLineIcon },
- grep: { label: "Grep", icon: Search01Icon },
- find: { label: "Find", icon: Search01Icon },
- ls: { label: "ListDir", icon: FolderOpenIcon },
- glob: { label: "Glob", icon: Search01Icon },
- web_search: { label: "WebSearch", icon: GlobeIcon },
- web_fetch: { label: "WebFetch", icon: GlobeIcon },
- memory_get: { label: "MemoryGet", icon: DatabaseIcon },
- memory_set: { label: "MemorySet", icon: DatabaseIcon },
- memory_delete: { label: "MemoryDelete", icon: DatabaseIcon },
- memory_list: { label: "MemoryList", icon: DatabaseIcon },
- sessions_spawn: { label: "SpawnSession", icon: GitBranchIcon },
+const TOOL_DISPLAY: Record = {
+ read: { label: "Read", icon: File },
+ write: { label: "Write", icon: Save },
+ edit: { label: "Edit", icon: FileEdit },
+ exec: { label: "Exec", icon: Terminal },
+ bash: { label: "Exec", icon: Terminal },
+ process: { label: "Process", icon: Terminal },
+ grep: { label: "Grep", icon: Search },
+ find: { label: "Find", icon: Search },
+ ls: { label: "ListDir", icon: FolderOpen },
+ glob: { label: "Glob", icon: Search },
+ web_search: { label: "WebSearch", icon: Globe },
+ web_fetch: { label: "WebFetch", icon: Globe },
+ memory_get: { label: "MemoryGet", icon: Database },
+ memory_set: { label: "MemorySet", icon: Database },
+ memory_delete: { label: "MemoryDelete", icon: Database },
+ memory_list: { label: "MemoryList", icon: Database },
+ sessions_spawn: { label: "SpawnSession", icon: GitBranch },
}
// ---------------------------------------------------------------------------
@@ -125,7 +125,7 @@ export const ToolCallItem = memo(function ToolCallItem({ message }: { message: M
const [expanded, setExpanded] = useState(false)
const { toolName = "", toolStatus = "running", toolArgs, content } = message
- const display = TOOL_DISPLAY[toolName] ?? { label: toolName, icon: CommandLineIcon }
+ const display = TOOL_DISPLAY[toolName] ?? { label: toolName, icon: Terminal }
const isFinished = toolStatus !== "running"
const resultText = getTextContent(content)
const hasDetails = isFinished && !!resultText
@@ -161,9 +161,7 @@ export const ToolCallItem = memo(function ToolCallItem({ message }: { message: M
/>
{/* Tool icon */}
-
@@ -196,9 +194,7 @@ export const ToolCallItem = memo(function ToolCallItem({ message }: { message: M
{/* Chevron — visible on hover when expandable */}
{hasDetails && (
-
-
+
)
diff --git a/packages/ui/src/components/ui/combobox.tsx b/packages/ui/src/components/ui/combobox.tsx
index e660471d..bf7e3c5d 100644
--- a/packages/ui/src/components/ui/combobox.tsx
+++ b/packages/ui/src/components/ui/combobox.tsx
@@ -11,8 +11,7 @@ import {
InputGroupButton,
InputGroupInput,
} from "@multica/ui/components/ui/input-group"
-import { HugeiconsIcon } from "@hugeicons/react"
-import { ArrowDown01Icon, Cancel01Icon, Tick02Icon } from "@hugeicons/core-free-icons"
+import { ChevronDown, X, Check } from "lucide-react"
const Combobox = ComboboxPrimitive.Root
@@ -32,7 +31,7 @@ function ComboboxTrigger({
{...props}
>
{children}
-
+
)
}
@@ -45,7 +44,7 @@ function ComboboxClear({ className, ...props }: ComboboxPrimitive.Clear.Props) {
className={cn(className)}
{...props}
>
-
+
)
}
@@ -150,7 +149,7 @@ function ComboboxItem({
}
>
-
+
)
@@ -246,7 +245,7 @@ function ComboboxChip({
className="-ml-1 opacity-50 hover:opacity-100"
data-slot="combobox-chip-remove"
>
-
+
)}
diff --git a/packages/ui/src/components/ui/dialog.tsx b/packages/ui/src/components/ui/dialog.tsx
index 1e14624a..44ab7937 100644
--- a/packages/ui/src/components/ui/dialog.tsx
+++ b/packages/ui/src/components/ui/dialog.tsx
@@ -5,8 +5,7 @@ import { Dialog as DialogPrimitive } from "@base-ui/react/dialog"
import { cn } from "@multica/ui/lib/utils"
import { Button } from "@multica/ui/components/ui/button"
-import { HugeiconsIcon } from "@hugeicons/react"
-import { Cancel01Icon } from "@hugeicons/core-free-icons"
+import { X } from "lucide-react"
function Dialog({ ...props }: DialogPrimitive.Root.Props) {
return
@@ -71,7 +70,7 @@ function DialogContent({
/>
}
>
-
+
Close
)}
diff --git a/packages/ui/src/components/ui/dropdown-menu.tsx b/packages/ui/src/components/ui/dropdown-menu.tsx
index 158d0b27..e09f7756 100644
--- a/packages/ui/src/components/ui/dropdown-menu.tsx
+++ b/packages/ui/src/components/ui/dropdown-menu.tsx
@@ -4,8 +4,7 @@ import * as React from "react"
import { Menu as MenuPrimitive } from "@base-ui/react/menu"
import { cn } from "@multica/ui/lib/utils"
-import { HugeiconsIcon } from "@hugeicons/react"
-import { ArrowRight01Icon, Tick02Icon } from "@hugeicons/core-free-icons"
+import { ChevronRight, Check } from "lucide-react"
function DropdownMenu({ ...props }: MenuPrimitive.Root.Props) {
return
@@ -117,7 +116,7 @@ function DropdownMenuSubTrigger({
{...props}
>
{children}
-
+
)
}
@@ -164,7 +163,7 @@ function DropdownMenuCheckboxItem({
data-slot="dropdown-menu-checkbox-item-indicator"
>
-
+
{children}
@@ -200,7 +199,7 @@ function DropdownMenuRadioItem({
data-slot="dropdown-menu-radio-item-indicator"
>
-
+
{children}
diff --git a/packages/ui/src/components/ui/select.tsx b/packages/ui/src/components/ui/select.tsx
index d52c2333..f7a2f127 100644
--- a/packages/ui/src/components/ui/select.tsx
+++ b/packages/ui/src/components/ui/select.tsx
@@ -4,8 +4,7 @@ import * as React from "react"
import { Select as SelectPrimitive } from "@base-ui/react/select"
import { cn } from "@multica/ui/lib/utils"
-import { HugeiconsIcon } from "@hugeicons/react"
-import { UnfoldMoreIcon, Tick02Icon, ArrowUp01Icon, ArrowDown01Icon } from "@hugeicons/core-free-icons"
+import { ChevronsUpDown, Check, ChevronUp, ChevronDown } from "lucide-react"
const Select = SelectPrimitive.Root
@@ -50,7 +49,7 @@ function SelectTrigger({
{children}
+
}
/>
@@ -129,7 +128,7 @@ function SelectItem({
}
>
-
+
)
@@ -158,7 +157,7 @@ function SelectScrollUpButton({
className={cn("bg-popover z-10 flex cursor-default items-center justify-center py-1 [&_svg:not([class*='size-'])]:size-4 top-0 w-full", className)}
{...props}
>
-
+
)
}
@@ -173,7 +172,7 @@ function SelectScrollDownButton({
className={cn("bg-popover z-10 flex cursor-default items-center justify-center py-1 [&_svg:not([class*='size-'])]:size-4 bottom-0 w-full", className)}
{...props}
>
-
+
)
}
diff --git a/packages/ui/src/components/ui/sheet.tsx b/packages/ui/src/components/ui/sheet.tsx
index 69aea14e..297f083c 100644
--- a/packages/ui/src/components/ui/sheet.tsx
+++ b/packages/ui/src/components/ui/sheet.tsx
@@ -5,8 +5,7 @@ import { Dialog as SheetPrimitive } from "@base-ui/react/dialog"
import { cn } from "@multica/ui/lib/utils"
import { Button } from "@multica/ui/components/ui/button"
-import { HugeiconsIcon } from "@hugeicons/react"
-import { Cancel01Icon } from "@hugeicons/core-free-icons"
+import { X } from "lucide-react"
function Sheet({ ...props }: SheetPrimitive.Root.Props) {
return
@@ -65,7 +64,7 @@ function SheetContent({
/>
}
>
-
+
Close
)}
diff --git a/packages/ui/src/components/ui/sidebar.tsx b/packages/ui/src/components/ui/sidebar.tsx
index 50992c67..07469808 100644
--- a/packages/ui/src/components/ui/sidebar.tsx
+++ b/packages/ui/src/components/ui/sidebar.tsx
@@ -23,8 +23,7 @@ import {
TooltipContent,
TooltipTrigger,
} from "@multica/ui/components/ui/tooltip"
-import { HugeiconsIcon } from "@hugeicons/react"
-import { SidebarLeftIcon } from "@hugeicons/core-free-icons"
+import { PanelLeft } from "lucide-react"
const SIDEBAR_COOKIE_NAME = "sidebar_state"
const SIDEBAR_COOKIE_MAX_AGE = 60 * 60 * 24 * 7
@@ -272,7 +271,7 @@ function SidebarTrigger({
}}
{...props}
>
-
+
Toggle Sidebar
)
diff --git a/packages/ui/src/components/ui/sonner.tsx b/packages/ui/src/components/ui/sonner.tsx
index 8aa1ce36..a1940823 100644
--- a/packages/ui/src/components/ui/sonner.tsx
+++ b/packages/ui/src/components/ui/sonner.tsx
@@ -2,8 +2,7 @@
import { useTheme } from "next-themes"
import { Toaster as Sonner, toast, type ToasterProps } from "sonner"
-import { HugeiconsIcon } from "@hugeicons/react"
-import { CheckmarkCircle02Icon, InformationCircleIcon, Alert02Icon, MultiplicationSignCircleIcon, Loading03Icon } from "@hugeicons/core-free-icons"
+import { CheckCircle, Info, AlertCircle, XCircle, Loader2 } from "lucide-react"
const Toaster = ({ ...props }: ToasterProps) => {
const { theme = "system" } = useTheme()
@@ -14,19 +13,19 @@ const Toaster = ({ ...props }: ToasterProps) => {
className="toaster group"
icons={{
success: (
-
+
),
info: (
-
+
),
warning: (
-
+
),
error: (
-
+
),
loading: (
-
+
),
}}
style={
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index c136db71..fc9cc0d1 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -6,12 +6,6 @@ settings:
catalogs:
default:
- '@hugeicons/core-free-icons':
- specifier: ^3.1.1
- version: 3.1.1
- '@hugeicons/react':
- specifier: ^1.1.4
- version: 1.1.5
'@mariozechner/pi-agent-core':
specifier: ^0.52.9
version: 0.52.9
@@ -135,6 +129,9 @@ importers:
linkedom:
specifier: ^0.18.12
version: 0.18.12
+ lucide-react:
+ specifier: ^0.563.0
+ version: 0.563.0(react@19.2.3)
mysql2:
specifier: ^3.14.1
version: 3.16.3
@@ -230,12 +227,6 @@ importers:
apps/desktop:
dependencies:
- '@hugeicons/core-free-icons':
- specifier: 'catalog:'
- version: 3.1.1
- '@hugeicons/react':
- specifier: 'catalog:'
- version: 1.1.5(react@19.2.3)
'@multica/core':
specifier: workspace:*
version: link:../../packages/core
@@ -251,6 +242,9 @@ importers:
'@multica/ui':
specifier: workspace:*
version: link:../../packages/ui
+ lucide-react:
+ specifier: ^0.563.0
+ version: 0.563.0(react@19.2.3)
qrcode.react:
specifier: ^4.2.0
version: 4.2.0(react@19.2.3)
@@ -370,12 +364,6 @@ importers:
'@expo/vector-icons':
specifier: ^15.0.3
version: 15.0.3(expo-font@14.0.11(expo@54.0.33)(react-native@0.81.5(@babel/core@7.29.0)(@types/react@19.2.13)(react@19.1.0))(react@19.1.0))(react-native@0.81.5(@babel/core@7.29.0)(@types/react@19.2.13)(react@19.1.0))(react@19.1.0)
- '@hugeicons/core-free-icons':
- specifier: ^3.1.1
- version: 3.1.1
- '@hugeicons/react-native':
- specifier: ^1.0.11
- version: 1.0.11(react-native-svg@15.15.3(react-native@0.81.5(@babel/core@7.29.0)(@types/react@19.2.13)(react@19.1.0))(react@19.1.0))(react-native@0.81.5(@babel/core@7.29.0)(@types/react@19.2.13)(react@19.1.0))(react@19.1.0)
'@react-navigation/bottom-tabs':
specifier: ^7.4.0
version: 7.12.0(@react-navigation/native@7.1.28(react-native@0.81.5(@babel/core@7.29.0)(@types/react@19.2.13)(react@19.1.0))(react@19.1.0))(react-native-safe-area-context@5.6.2(react-native@0.81.5(@babel/core@7.29.0)(@types/react@19.2.13)(react@19.1.0))(react@19.1.0))(react-native-screens@4.16.0(react-native@0.81.5(@babel/core@7.29.0)(@types/react@19.2.13)(react@19.1.0))(react@19.1.0))(react-native@0.81.5(@babel/core@7.29.0)(@types/react@19.2.13)(react@19.1.0))(react@19.1.0)
@@ -537,12 +525,6 @@ importers:
apps/web:
dependencies:
- '@hugeicons/core-free-icons':
- specifier: 'catalog:'
- version: 3.1.1
- '@hugeicons/react':
- specifier: 'catalog:'
- version: 1.1.5(react@19.2.3)
'@multica/hooks':
specifier: workspace:*
version: link:../../packages/hooks
@@ -740,12 +722,6 @@ importers:
'@fontsource/geist-sans':
specifier: ^5.2.5
version: 5.2.5
- '@hugeicons/core-free-icons':
- specifier: 'catalog:'
- version: 3.1.1
- '@hugeicons/react':
- specifier: 'catalog:'
- version: 1.1.5(react@19.2.3)
'@multica/store':
specifier: workspace:*
version: link:../store
@@ -770,6 +746,9 @@ importers:
linkify-it:
specifier: ^5.0.0
version: 5.0.0
+ lucide-react:
+ specifier: ^0.563.0
+ version: 0.563.0(react@19.2.3)
next-themes:
specifier: ^0.4.6
version: 0.4.6(react-dom@19.2.3(react@19.2.3))(react@19.2.3)
@@ -2270,21 +2249,6 @@ packages:
peerDependencies:
hono: ^4
- '@hugeicons/core-free-icons@3.1.1':
- resolution: {integrity: sha512-UpS2lUQFi5sKyJSWwM6rO+BnPLvVz1gsyCpPHeZyVuZqi89YH8ksliza4cwaODqKOZyeXmG8juo1ty4QtQofkg==}
-
- '@hugeicons/react-native@1.0.11':
- resolution: {integrity: sha512-HCUhHrFbL30ArN7tWV7+udnd1Qotu/eKcys63PELui3XVxP0DPPEvgFJqgbdig2afrLltroP7QCAdBNWOorWSg==}
- peerDependencies:
- react: '>=16.0.0'
- react-native: '>=0.60.0'
- react-native-svg: '>=12.0.0'
-
- '@hugeicons/react@1.1.5':
- resolution: {integrity: sha512-JX/iDz3oO7hWdVqbjwFwRrAjHk8h2vI+mBkNzp4JcXG3t4idoupfjon73nLOA7cr27m0M8hrRC1Q2h6nEBGKVA==}
- peerDependencies:
- react: '>=16.0.0'
-
'@humanfs/core@0.19.1':
resolution: {integrity: sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA==}
engines: {node: '>=18.18.0'}
@@ -7243,6 +7207,11 @@ packages:
react-native: '*'
react-native-svg: ^12.0.0 || ^13.0.0 || ^14.0.0 || ^15.0.0
+ lucide-react@0.563.0:
+ resolution: {integrity: sha512-8dXPB2GI4dI8jV4MgUDGBeLdGk8ekfqVZ0BdLcrRzocGgG75ltNEmWS+gE7uokKF/0oSUuczNDT+g9hFJ23FkA==}
+ peerDependencies:
+ react: ^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0
+
magic-string@0.30.21:
resolution: {integrity: sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==}
@@ -12083,18 +12052,6 @@ snapshots:
dependencies:
hono: 4.11.9
- '@hugeicons/core-free-icons@3.1.1': {}
-
- '@hugeicons/react-native@1.0.11(react-native-svg@15.15.3(react-native@0.81.5(@babel/core@7.29.0)(@types/react@19.2.13)(react@19.1.0))(react@19.1.0))(react-native@0.81.5(@babel/core@7.29.0)(@types/react@19.2.13)(react@19.1.0))(react@19.1.0)':
- dependencies:
- react: 19.1.0
- react-native: 0.81.5(@babel/core@7.29.0)(@types/react@19.2.13)(react@19.1.0)
- react-native-svg: 15.15.3(react-native@0.81.5(@babel/core@7.29.0)(@types/react@19.2.13)(react@19.1.0))(react@19.1.0)
-
- '@hugeicons/react@1.1.5(react@19.2.3)':
- dependencies:
- react: 19.2.3
-
'@humanfs/core@0.19.1': {}
'@humanfs/node@0.16.7':
@@ -15957,7 +15914,7 @@ snapshots:
transitivePeerDependencies:
- supports-color
- eslint-module-utils@2.12.1(@typescript-eslint/parser@8.55.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.10.1(eslint-plugin-import@2.32.0)(eslint@9.39.2(jiti@2.6.1)))(eslint@9.39.2(jiti@2.6.1)):
+ eslint-module-utils@2.12.1(@typescript-eslint/parser@8.55.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.10.1)(eslint@9.39.2(jiti@2.6.1)):
dependencies:
debug: 3.2.7
optionalDependencies:
@@ -15988,7 +15945,7 @@ snapshots:
doctrine: 2.1.0
eslint: 9.39.2(jiti@2.6.1)
eslint-import-resolver-node: 0.3.9
- eslint-module-utils: 2.12.1(@typescript-eslint/parser@8.55.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.10.1(eslint-plugin-import@2.32.0)(eslint@9.39.2(jiti@2.6.1)))(eslint@9.39.2(jiti@2.6.1))
+ eslint-module-utils: 2.12.1(@typescript-eslint/parser@8.55.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.10.1)(eslint@9.39.2(jiti@2.6.1))
hasown: 2.0.2
is-core-module: 2.16.1
is-glob: 4.0.3
@@ -17852,6 +17809,10 @@ snapshots:
react-native: 0.81.5(@babel/core@7.29.0)(@types/react@19.2.13)(react@19.1.0)
react-native-svg: 15.15.3(react-native@0.81.5(@babel/core@7.29.0)(@types/react@19.2.13)(react@19.1.0))(react@19.1.0)
+ lucide-react@0.563.0(react@19.2.3):
+ dependencies:
+ react: 19.2.3
+
magic-string@0.30.21:
dependencies:
'@jridgewell/sourcemap-codec': 1.5.5
diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml
index 8147ccb1..6bbd51a2 100644
--- a/pnpm-workspace.yaml
+++ b/pnpm-workspace.yaml
@@ -25,8 +25,7 @@ catalog:
clsx: "^2.1.1"
# Icons
- "@hugeicons/react": "^1.1.4"
- "@hugeicons/core-free-icons": "^3.1.1"
+ lucide-react: "^0.511.0"
# Networking
socket.io-client: "^4.8.3"