diff --git a/apps/desktop/layer/renderer/src/atoms/settings/ai.ts b/apps/desktop/layer/renderer/src/atoms/settings/ai.ts index c7a70d733..c851fb1c3 100644 --- a/apps/desktop/layer/renderer/src/atoms/settings/ai.ts +++ b/apps/desktop/layer/renderer/src/atoms/settings/ai.ts @@ -1,6 +1,6 @@ import { createSettingAtom } from "@follow/atoms/helper/setting.js" import { defaultAISettings } from "@follow/shared/settings/defaults" -import type { AISettings } from "@follow/shared/settings/interface" +import type { AISettings, MCPService } from "@follow/shared/settings/interface" import { jotaiStore } from "@follow/utils" import { atom, useAtomValue } from "jotai" @@ -70,6 +70,37 @@ export const setAIPanelVisibility = (visibility: boolean) => { } export const getAIPanelVisibility = () => jotaiStore.get(aiPanelVisibilityAtom) +////////// MCP Services +export const useMCPEnabled = () => useAISettingKey("mcpEnabled") +export const setMCPEnabled = (enabled: boolean) => { + setAISetting("mcpEnabled", enabled) +} + +export const useMCPServices = () => useAISettingKey("mcpServices") +export const addMCPService = (service: Omit) => { + const services = getAISettings().mcpServices + const newService = { + ...service, + id: Date.now().toString(), + } + setAISetting("mcpServices", [...services, newService]) + return newService.id +} + +export const updateMCPService = (id: string, updates: Partial) => { + const services = getAISettings().mcpServices + const updatedServices = services.map((service) => + service.id === id ? { ...service, ...updates } : service, + ) + setAISetting("mcpServices", updatedServices) +} + +export const removeMCPService = (id: string) => { + const services = getAISettings().mcpServices + const filteredServices = services.filter((service) => service.id !== id) + setAISetting("mcpServices", filteredServices) +} + //// Enhance Init Ai Settings export const initializeDefaultAISettings = () => { initializeDefaultSettings() diff --git a/apps/desktop/layer/renderer/src/modules/ai-chat/components/layouts/ChatInterface.tsx b/apps/desktop/layer/renderer/src/modules/ai-chat/components/layouts/ChatInterface.tsx index 8ac379de1..82233f5ed 100644 --- a/apps/desktop/layer/renderer/src/modules/ai-chat/components/layouts/ChatInterface.tsx +++ b/apps/desktop/layer/renderer/src/modules/ai-chat/components/layouts/ChatInterface.tsx @@ -215,8 +215,8 @@ const ChatInterfaceContent = () => { onClick={() => resetScrollState()} className={cn( "backdrop-blur-background group flex items-center gap-2 rounded-full border px-3.5 py-2 transition-all", - "border-border/40 bg-material-ultra-thin/70 shadow-[0_1px_2px_rgba(0,0,0,0.06),0_8px_24px_rgba(0,0,0,0.08)]", - "hover:bg-material-thin/70 hover:border-border/60 active:scale-[0.98]", + "border-border/40 bg-material-ultra-thin shadow-[0_1px_2px_rgba(0,0,0,0.06),0_8px_24px_rgba(0,0,0,0.08)]", + "hover:bg-material-medium hover:border-border/60 active:scale-[0.98]", )} > diff --git a/apps/desktop/layer/renderer/src/modules/ai-chat/components/message/ToolInvocationComponent.tsx b/apps/desktop/layer/renderer/src/modules/ai-chat/components/message/ToolInvocationComponent.tsx index f37b7e27e..f2a986539 100644 --- a/apps/desktop/layer/renderer/src/modules/ai-chat/components/message/ToolInvocationComponent.tsx +++ b/apps/desktop/layer/renderer/src/modules/ai-chat/components/message/ToolInvocationComponent.tsx @@ -16,9 +16,14 @@ interface ToolInvocationComponentProps { export const ToolInvocationComponent: React.FC = React.memo( ({ part }) => { const toolName = getToolName(part) + const hasError = "errorText" in part && part.errorText return ( -
+
@@ -26,9 +31,15 @@ export const ToolInvocationComponent: React.FC = R {/* Tool Info */}
- - Tool Calling: -

{toolName}

+ + + {hasError ? "Tool Failed:" : "Tool Calling:"} + +

+ {toolName} +

@@ -44,7 +55,7 @@ export const ToolInvocationComponent: React.FC = R
)} - {"output" in part && ( + {"output" in part && !!part.output && (
Result @@ -52,6 +63,25 @@ export const ToolInvocationComponent: React.FC = R
)} + + {hasError && ( +
+
+ Error +
+
+
+ +
+
Tool Execution Failed
+
+ {"errorText" in part ? part.errorText : ""} +
+
+
+
+
+ )}
diff --git a/apps/desktop/layer/renderer/src/modules/settings/modal/context.tsx b/apps/desktop/layer/renderer/src/modules/settings/modal/context.tsx index 96f1f1645..be75864a1 100644 --- a/apps/desktop/layer/renderer/src/modules/settings/modal/context.tsx +++ b/apps/desktop/layer/renderer/src/modules/settings/modal/context.tsx @@ -1,7 +1,13 @@ +import type { PrimitiveAtom } from "jotai" import { atom } from "jotai" +import { createContext } from "react" import { createAtomHooks } from "~/lib/jotai" export const [, , useSettingTab, useSetSettingTab, getSettingTab, setSettingTab] = createAtomHooks( atom(""), ) + +export const SettingModalContentPortalableContext = createContext>( + atom(null as any), +) diff --git a/apps/desktop/layer/renderer/src/modules/settings/modal/layout.tsx b/apps/desktop/layer/renderer/src/modules/settings/modal/layout.tsx index b6873b8e5..c730d4db3 100644 --- a/apps/desktop/layer/renderer/src/modules/settings/modal/layout.tsx +++ b/apps/desktop/layer/renderer/src/modules/settings/modal/layout.tsx @@ -5,10 +5,12 @@ import { LetsIconsResizeDownRightLight } from "@follow/components/icons/resize.j import { IN_ELECTRON } from "@follow/shared/constants" import { preventDefault } from "@follow/utils/dom" import { cn, getOS } from "@follow/utils/utils" +import { atom, useAtomValue, useSetAtom } from "jotai" import type { BoundingBox } from "motion/react" import { Resizable } from "re-resizable" import type { PropsWithChildren } from "react" -import { memo, Suspense, useCallback, useEffect, useRef } from "react" +import { memo, Suspense, use, useCallback, useEffect, useMemo, useRef } from "react" +import { createPortal } from "react-dom" import { useUISettingSelector } from "~/atoms/settings/ui" import { m } from "~/components/common/Motion" @@ -24,7 +26,7 @@ import { useAvailableSettings, useSettingPageContext } from "../hooks/use-settin import { SettingsSidebarTitle } from "../title" import type { SettingPageConfig } from "../utils" import { DisableWhy } from "../utils" -import { useSetSettingTab, useSettingTab } from "./context" +import { SettingModalContentPortalableContext, useSetSettingTab, useSettingTab } from "./context" import { defaultCtx, SettingContext } from "./hooks" export function SettingModalLayout( @@ -77,6 +79,10 @@ export function SettingModalLayout( return constraints }).current + const portalableCtxValue = useMemo(() => { + return atom(null as any) + }, []) + return (
- {children} + + {children} + +
@@ -154,6 +163,11 @@ export function SettingModalLayout( ) } +const SettingModalContentPortalable = () => { + const setElement = useSetAtom(use(SettingModalContentPortalableContext)) + return
+} + const SettingItemButtonImpl = (props: { setTab: (tab: string) => void item: SettingPageConfig @@ -220,3 +234,8 @@ export const SidebarItems = memo((props: { onChange?: (tab: string) => void }) = ) }) }) + +export const SettingModalContentPortal: Component = ({ children }) => { + const element = useAtomValue(use(SettingModalContentPortalableContext)) + return createPortal(children, element) +} diff --git a/apps/desktop/layer/renderer/src/modules/settings/tabs/ai.tsx b/apps/desktop/layer/renderer/src/modules/settings/tabs/ai.tsx index 8b2dcaebf..d0abd9693 100644 --- a/apps/desktop/layer/renderer/src/modules/settings/tabs/ai.tsx +++ b/apps/desktop/layer/renderer/src/modules/settings/tabs/ai.tsx @@ -1,9 +1,21 @@ +import { Spring } from "@follow/components/constants/spring.js" import { Button } from "@follow/components/ui/button/index.js" import { Input, TextArea } from "@follow/components/ui/input/index.js" import { KbdCombined } from "@follow/components/ui/kbd/Kbd.js" +import { KeyValueEditor } from "@follow/components/ui/key-value-editor/index.js" import { Label } from "@follow/components/ui/label/index.jsx" +import { + Select, + SelectContent, + SelectItem, + SelectTrigger, + SelectValue, +} from "@follow/components/ui/select/index.js" import { Switch } from "@follow/components/ui/switch/index.jsx" -import type { AIShortcut } from "@follow/shared/settings/interface" +import type { AIShortcut, MCPService } from "@follow/shared/settings/interface" +import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query" +import { AnimatePresence } from "motion/react" +import * as React from "react" import { useState } from "react" import { useTranslation } from "react-i18next" import { toast } from "sonner" @@ -12,13 +24,26 @@ import { AIChatPanelStyle, setAIChatPanelStyle, setAISetting, + setMCPEnabled, useAIChatPanelStyle, useAISettingValue, + useMCPEnabled, } from "~/atoms/settings/ai" +import { m } from "~/components/common/Motion" +import { useDialog, useModalStack } from "~/components/ui/modal/stacked/hooks" +import { + createMCPConnection, + deleteMCPConnection, + fetchMCPConnections, + mcpQueryKeys, + refreshMCPTools, + updateMCPConnection, +} from "~/queries/mcp" import { SettingActionItem, SettingDescription, SettingTabbedSegment } from "../control" import { createDefineSettingItem } from "../helper/builder" import { createSettingBuilder } from "../helper/setting-builder" +import { SettingModalContentPortal } from "../modal/layout" const SettingBuilder = createSettingBuilder(useAISettingValue) const defineSettingItem = createDefineSettingItem(useAISettingValue, setAISetting) @@ -53,6 +78,12 @@ export const SettingAI = () => { value: t("shortcuts.title"), }, AIShortcutsSection, + + { + type: "title", + value: t("integration.title"), + }, + MCPServicesSection, ]} />
@@ -126,17 +157,31 @@ const PersonalizePromptSetting = () => {
-
- -
+ + {hasChanges && ( + + +
+ Unsaved changes + +
+
+
+ )} +
) } @@ -144,20 +189,49 @@ const PersonalizePromptSetting = () => { const AIShortcutsSection = () => { const { t } = useTranslation("ai") const { shortcuts } = useAISettingValue() - const [isCreating, setIsCreating] = useState(false) + const { present } = useModalStack() const handleAddShortcut = () => { - setIsCreating(true) + present({ + title: "Add AI Shortcut", + content: ({ dismiss }: { dismiss: () => void }) => ( + { + const newShortcut: AIShortcut = { + ...shortcut, + id: Date.now().toString(), + } + setAISetting("shortcuts", [...shortcuts, newShortcut]) + toast.success(t("shortcuts.added")) + dismiss() + }} + onCancel={dismiss} + /> + ), + }) } - const handleSaveShortcut = (shortcut: Omit) => { - const newShortcut: AIShortcut = { - ...shortcut, - id: Date.now().toString(), - } - setAISetting("shortcuts", [...shortcuts, newShortcut]) - setIsCreating(false) - toast.success(t("shortcuts.added")) + const handleEditShortcut = (shortcut: AIShortcut) => { + present({ + title: "Edit AI Shortcut", + content: ({ dismiss }: { dismiss: () => void }) => ( + { + setAISetting( + "shortcuts", + shortcuts.map((s) => + s.id === shortcut.id ? { ...updatedShortcut, id: shortcut.id } : s, + ), + ) + toast.success(t("shortcuts.updated")) + dismiss() + }} + onCancel={dismiss} + /> + ), + }) } const handleDeleteShortcut = (id: string) => { @@ -175,29 +249,15 @@ const AIShortcutsSection = () => { ) } - const handleUpdateShortcut = (id: string, updatedShortcut: Omit) => { - setAISetting( - "shortcuts", - shortcuts.map((s) => (s.id === id ? { ...updatedShortcut, id } : s)), - ) - toast.success(t("shortcuts.updated")) - } - return (
- {t("shortcuts.description")} - - {isCreating && ( - setIsCreating(false)} /> - )} - - {shortcuts.length === 0 && !isCreating && ( + {shortcuts.length === 0 && (
@@ -213,7 +273,7 @@ const AIShortcutsSection = () => { shortcut={shortcut} onDelete={handleDeleteShortcut} onToggle={handleToggleShortcut} - onUpdate={handleUpdateShortcut} + onEdit={handleEditShortcut} /> ))}
@@ -224,29 +284,10 @@ interface ShortcutItemProps { shortcut: AIShortcut onDelete: (id: string) => void onToggle: (id: string, enabled: boolean) => void - onUpdate: (id: string, shortcut: Omit) => void + onEdit: (shortcut: AIShortcut) => void } -const ShortcutItem = ({ shortcut, onDelete, onToggle, onUpdate }: ShortcutItemProps) => { - const [isEditing, setIsEditing] = useState(false) - - const handleSave = (updatedShortcut: Omit) => { - onUpdate(shortcut.id, updatedShortcut) - setIsEditing(false) - } - - if (isEditing) { - return ( -
- setIsEditing(false)} - /> -
- ) - } - +const ShortcutItem = ({ shortcut, onDelete, onToggle, onEdit }: ShortcutItemProps) => { return (
@@ -266,7 +307,7 @@ const ShortcutItem = ({ shortcut, onDelete, onToggle, onUpdate }: ShortcutItemPr
- + +
+
+ + {mcpServices.length === 0 && ( +
+
+ +
+

+ {t("integration.mcp.services.empty.title")} +

+

+ {t("integration.mcp.services.empty.description")} +

+
+ )} + + {isLoading && ( +
+ +
+ )} + + {mcpServices.map((service) => ( + + ))} +
+ )} +
+ ) +} + +interface MCPServiceItemProps { + service: MCPService + onDelete: (id: string) => void + onRefresh: (connectionId: string) => void + onEdit: (service: MCPService) => void + isDeleting?: boolean + isRefreshing?: boolean +} + +const MCPServiceItem = ({ + service, + onDelete, + onRefresh, + onEdit, + isDeleting = false, + isRefreshing = false, +}: MCPServiceItemProps) => { + const { t } = useTranslation("ai") + + const getConnectionStatusColor = (isConnected: boolean) => { + return isConnected ? "bg-green/10 text-green" : "bg-gray/10 text-text-tertiary" + } + + const getConnectionStatusText = (isConnected: boolean) => { + return isConnected + ? t("integration.mcp.service.connected") + : t("integration.mcp.service.disconnected") + } + + const formatDate = (dateString: string | null) => { + if (!dateString) return "Never" + return new Date(dateString).toLocaleDateString() + } + + return ( +
+
+
+
+

{service.name}

+
+ {getConnectionStatusText(service.isConnected)} +
+
+ {service.transportType} +
+
+
+ {service.url && ( +

+ URL: {service.url} +

+ )} + +

+ Tools: {service.toolCount} + Created:{" "} + {formatDate(service.createdAt)} + Last Used:{" "} + {formatDate(service.lastUsed)} +

+ {service.lastError && ( +

+ Error: {service.lastError} +

+ )} +
+
+ +
+ + + +
+
+
+ ) +} + +interface MCPServiceModalContentProps { + service?: MCPService | null + onSave: (service: { + name: string + transportType: "streamable-http" | "sse" + url: string + headers?: Record + }) => void + onCancel: () => void + isLoading?: boolean +} + +const MCPServiceModalContent = ({ + service, + onSave, + onCancel, + isLoading = false, +}: MCPServiceModalContentProps) => { + const { t } = useTranslation("ai") + const [name, setName] = useState(service?.name || "") + const [url, setUrl] = useState(service?.url || "") + const [transportType, setTransportType] = useState<"streamable-http" | "sse">( + service?.transportType || "streamable-http", + ) + const [headers, setHeaders] = useState>(service?.headers || {}) + + const handleSave = () => { + if (!name.trim()) { + toast.error(t("integration.mcp.service.validation.name_required")) + return + } + + if (!url.trim()) { + toast.error(t("integration.mcp.service.validation.baseUrl_required")) + return + } + + // Basic URL validation + try { + new URL(url.trim()) + } catch { + toast.error(t("integration.mcp.service.validation.invalid_url")) + return + } + + onSave({ + name: name.trim(), + transportType, + url: url.trim(), + headers: Object.keys(headers).length > 0 ? headers : undefined, + }) + } + + return ( +
+
+
+
+ + setName(e.target.value)} + placeholder={t("integration.mcp.service.name_placeholder")} + /> +
+ +
+ + +
+ +
+ + setUrl(e.target.value)} + placeholder="https://example.com/mcp" + /> +
+ +
+ + +
+
+
+ +
+
+
+ + +
+
+
+ ) +} + export const PanelStyleSegment = () => { const { t } = useTranslation("ai") const panelStyle = useAIChatPanelStyle() diff --git a/apps/desktop/layer/renderer/src/queries/mcp.ts b/apps/desktop/layer/renderer/src/queries/mcp.ts new file mode 100644 index 000000000..a896195c1 --- /dev/null +++ b/apps/desktop/layer/renderer/src/queries/mcp.ts @@ -0,0 +1,52 @@ +import type { MCPService } from "@follow/shared/settings/interface" + +import { followApi } from "~/lib/api-client" + +// MCP Service API calls - these connect to the actual server endpoints via followClient +export const createMCPConnection = async (connectionData: { + name: string + transportType: "streamable-http" | "sse" + url: string + headers?: Record +}): Promise<{ authorizationUrl?: string }> => { + const res = await followApi.mcp.createConnection(connectionData) + return { authorizationUrl: res.authorizationUrl } +} + +export const fetchMCPConnections = async (): Promise => { + const response = await followApi.mcp.getConnections() + return response.data +} + +export const updateMCPConnection = async ( + connectionId: string, + updateData: { + name?: string + transportType?: "streamable-http" | "sse" + url?: string + headers?: Record + }, +): Promise<{ authorizationUrl?: string }> => { + const res = await followApi.mcp.updateConnection({ connectionId, ...updateData }) + return { authorizationUrl: res.authorizationUrl } +} + +export const deleteMCPConnection = async (connectionId: string): Promise => { + await followApi.mcp.deleteConnection({ connectionId }) +} + +export const refreshMCPTools = async (connectionIds?: string[]): Promise => { + await followApi.mcp.refreshTools({ connectionIds }) +} + +export const getMCPTools = async (connectionId: string) => { + const response = await followApi.mcp.getTools({ connectionId }) + return response.data +} + +// Query key factory for MCP queries +export const mcpQueryKeys = { + all: ["mcp"] as const, + connections: () => [...mcpQueryKeys.all, "connections"] as const, + tools: (connectionId: string) => [...mcpQueryKeys.all, "tools", connectionId] as const, +} diff --git a/apps/ssr/note.md b/apps/ssr/note.md index 9860a09b6..8e74500d5 100644 --- a/apps/ssr/note.md +++ b/apps/ssr/note.md @@ -2,9 +2,6 @@ Rewrite: Test url: -https://css-spring-generator.vercel.app/share/feeds/1 -https://css-spring-generator.vercel.app/og/feed/1 - http://localhost:2234/share/feeds/41223694984583197 http://localhost:2234/share/feeds/41375451836487680?view=2 http://localhost:2234/share/feeds/41147805276726317?view=2 diff --git a/apps/ssr/package.json b/apps/ssr/package.json index cf2f2470f..3b1a7cca6 100644 --- a/apps/ssr/package.json +++ b/apps/ssr/package.json @@ -65,7 +65,7 @@ "masonic": "4.1.0", "nanoid": "5.1.5", "path-to-regexp": "8.2.0", - "tailwindcss-uikit-colors": "1.0.0-alpha.1", + "tailwindcss-uikit-colors": "catalog:", "tsdown": "0.12.9", "tsx": "4.20.3", "typescript": "catalog:", diff --git a/icons/mgc/plugin_2_cute_re.svg b/icons/mgc/plugin_2_cute_re.svg new file mode 100644 index 000000000..8d2d9312a --- /dev/null +++ b/icons/mgc/plugin_2_cute_re.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/locales/ai/en.json b/locales/ai/en.json index ab8d97957..a466be52c 100644 --- a/locales/ai/en.json +++ b/locales/ai/en.json @@ -13,6 +13,47 @@ "export_error": "Failed to export chat", "export_success": "Chat exported successfully", "features.title": "Features", + "integration.mcp.description": "Connect to MCP-compatible services that extend AI capabilities through secure OAuth integration", + "integration.mcp.enabled": "Enable MCP Services", + "integration.mcp.service.active": "Active", + "integration.mcp.service.added": "MCP service added successfully", + "integration.mcp.service.auth_message": "This service requires OAuth authorization. Click 'Open Authorization' to proceed with authentication in a new window.", + "integration.mcp.service.auth_required": "Authorization Required", + "integration.mcp.service.auth_window_opened": "Authorization window opened. Please complete authentication.", + "integration.mcp.service.baseUrl": "Service Base URL", + "integration.mcp.service.baseUrl_placeholder": "e.g. https://api.example.com", + "integration.mcp.service.connect": "Connect", + "integration.mcp.service.connected": "Connected", + "integration.mcp.service.connected_success": "Successfully connected to MCP service", + "integration.mcp.service.connecting": "Connecting...", + "integration.mcp.service.connection_failed": "Failed to connect to MCP service", + "integration.mcp.service.degraded": "Degraded", + "integration.mcp.service.deleted": "MCP service deleted successfully", + "integration.mcp.service.disconnect": "Disconnect", + "integration.mcp.service.disconnected": "Disconnected", + "integration.mcp.service.discover": "Discover Service", + "integration.mcp.service.discovery_failed": "Failed to discover service endpoints", + "integration.mcp.service.endpoints": "OAuth Endpoints", + "integration.mcp.service.error": "Connection Error", + "integration.mcp.service.healthy": "Healthy", + "integration.mcp.service.inactive": "Inactive", + "integration.mcp.service.name": "Service Name", + "integration.mcp.service.name_placeholder": "e.g. GitHub Tools, Slack Integration", + "integration.mcp.service.open_auth": "Open Authorization", + "integration.mcp.service.open_manually": "Open Authorization", + "integration.mcp.service.popup_blocked": "Authorization popup was blocked by your browser", + "integration.mcp.service.reconnect": "Reconnect", + "integration.mcp.service.scopes": "Required Scopes", + "integration.mcp.service.unhealthy": "Unhealthy", + "integration.mcp.service.updated": "MCP service updated successfully", + "integration.mcp.service.validation.baseUrl_required": "Base URL is required", + "integration.mcp.service.validation.invalid_url": "Please enter a valid URL", + "integration.mcp.service.validation.name_required": "Service name is required", + "integration.mcp.services.add": "Add Service", + "integration.mcp.services.empty.description": "Connect MCP services to extend AI capabilities with external tools, APIs, and data sources.", + "integration.mcp.services.empty.title": "No MCP Services Connected", + "integration.mcp.services.title": "MCP Services", + "integration.title": "Integration", "personalize.description": "Tell me about yourself to get personalized AI responses", "personalize.prompt.help": "This helps AI provide personalized responses based on your preferences.", "personalize.prompt.label": "Personal Prompt", @@ -35,7 +76,6 @@ "shortcuts.added": "Shortcut added successfully", "shortcuts.create_first": "Create your first shortcut", "shortcuts.deleted": "Shortcut deleted successfully", - "shortcuts.description": "Create custom AI shortcuts for quick actions", "shortcuts.empty.description": "Create custom AI shortcuts to quickly perform common tasks and get instant AI assistance.", "shortcuts.empty.title": "No Shortcuts Yet", "shortcuts.enabled": "Enabled", diff --git a/locales/ai/ja.json b/locales/ai/ja.json index 87dc53f20..36c026216 100644 --- a/locales/ai/ja.json +++ b/locales/ai/ja.json @@ -13,6 +13,47 @@ "export_error": "Chat のエクスポートに失敗しました", "export_success": "Chatが正常にエクスポートされました", "features.title": "機能", + "integration.mcp.description": "安全なOAuth統合により、AI機能を拡張するMCP対応サービスに接続", + "integration.mcp.enabled": "MCPサービスを有効にする", + "integration.mcp.service.active": "アクティブ", + "integration.mcp.service.added": "MCPサービスが正常に追加されました", + "integration.mcp.service.auth_message": "このサービスはOAuth認証が必要です。新しいウィンドウで認証を進めるには「認証を開く」をクリックしてください。", + "integration.mcp.service.auth_required": "認証が必要", + "integration.mcp.service.auth_window_opened": "認証ウィンドウが開きました。認証を完了してください。", + "integration.mcp.service.baseUrl": "サービスベースURL", + "integration.mcp.service.baseUrl_placeholder": "例:https://api.example.com", + "integration.mcp.service.connect": "接続", + "integration.mcp.service.connected": "接続済み", + "integration.mcp.service.connected_success": "MCPサービスに正常に接続されました", + "integration.mcp.service.connecting": "接続中...", + "integration.mcp.service.connection_failed": "MCPサービスへの接続に失敗しました", + "integration.mcp.service.degraded": "劣化", + "integration.mcp.service.deleted": "MCPサービスが正常に削除されました", + "integration.mcp.service.disconnect": "切断", + "integration.mcp.service.disconnected": "切断済み", + "integration.mcp.service.discover": "サービスを発見", + "integration.mcp.service.discovery_failed": "サービスエンドポイントの発見に失敗しました", + "integration.mcp.service.endpoints": "OAuthエンドポイント", + "integration.mcp.service.error": "接続エラー", + "integration.mcp.service.healthy": "正常", + "integration.mcp.service.inactive": "非アクティブ", + "integration.mcp.service.name": "サービス名", + "integration.mcp.service.name_placeholder": "例:GitHub Tools、Slack Integration", + "integration.mcp.service.open_auth": "認証を開く", + "integration.mcp.service.open_manually": "認証を開く", + "integration.mcp.service.popup_blocked": "認証ポップアップがブラウザによってブロックされました", + "integration.mcp.service.reconnect": "再接続", + "integration.mcp.service.scopes": "必要なスコープ", + "integration.mcp.service.unhealthy": "異常", + "integration.mcp.service.updated": "MCPサービスが正常に更新されました", + "integration.mcp.service.validation.baseUrl_required": "ベースURLは必須です", + "integration.mcp.service.validation.invalid_url": "有効なURLを入力してください", + "integration.mcp.service.validation.name_required": "サービス名は必須です", + "integration.mcp.services.add": "サービスを追加", + "integration.mcp.services.empty.description": "MCPサービスに接続して、外部ツール、API、データソースでAI機能を拡張します。", + "integration.mcp.services.empty.title": "MCPサービスが接続されていません", + "integration.mcp.services.title": "MCPサービス", + "integration.title": "統合", "personalize.description": "あなた自身について教えてください。そうすれば、パーソナライズされたAIの応答が得られます。", "personalize.prompt.help": "これにより、AIはあなたの好みに基づいてパーソナライズされた応答を提供できます。", "personalize.prompt.label": "個人用プロンプト", @@ -35,7 +76,6 @@ "shortcuts.added": "ショートカットが正常に追加されました", "shortcuts.create_first": "最初のショートカットを作成", "shortcuts.deleted": "ショートカットが正常に削除されました", - "shortcuts.description": "クイックアクションのためのカスタムAIショートカットを作成します", "shortcuts.empty.description": "一般的なタスクを迅速に実行し、即座にAIアシスタンスを得るためのカスタムAIショートカットを作成します。", "shortcuts.empty.title": "ショートカットはまだありません", "shortcuts.enabled": "有効", diff --git a/locales/ai/zh-CN.json b/locales/ai/zh-CN.json index 9b570b8d2..aecc84f84 100644 --- a/locales/ai/zh-CN.json +++ b/locales/ai/zh-CN.json @@ -35,7 +35,6 @@ "shortcuts.added": "快捷方式添加成功", "shortcuts.create_first": "创建您的第一个快捷方式", "shortcuts.deleted": "快捷方式删除成功", - "shortcuts.description": "创建自定义AI快捷方式以快速执行操作", "shortcuts.empty.description": "创建自定义AI快捷方式,快速执行常见任务并获得即时AI协助。", "shortcuts.empty.title": "暂无快捷方式", "shortcuts.enabled": "已启用", diff --git a/locales/errors/en.json b/locales/errors/en.json index 483f9455b..096d2c990 100644 --- a/locales/errors/en.json +++ b/locales/errors/en.json @@ -73,5 +73,12 @@ "14002": "Upload failed", "15000": "AI token limit exceeded. Please try again later.", "15001": "You are not allowed to access AI chat", - "undefined": "MCP configuration error" + "16000": "MCP OAuth error", + "16001": "MCP discovery error", + "16002": "MCP service not found", + "16003": "Invalid or expired OAuth state", + "16004": "Token exchange failed", + "16005": "User MCP service not found", + "16006": "MCP configuration error", + "16007": "MCP tool execution failed" } diff --git a/packages/configs/package.json b/packages/configs/package.json index 1df51373f..f9fc2dc81 100644 --- a/packages/configs/package.json +++ b/packages/configs/package.json @@ -24,7 +24,7 @@ "tailwindcss-motion": "1.1.1", "tailwindcss-multi": "0.4.6", "tailwindcss-safe-area": "0.6.0", - "tailwindcss-uikit-colors": "1.0.0-alpha.1" + "tailwindcss-uikit-colors": "catalog:" }, "devDependencies": { "postcss": "8.5.6", diff --git a/packages/internal/components/package.json b/packages/internal/components/package.json index 70f4ff732..284f8d660 100644 --- a/packages/internal/components/package.json +++ b/packages/internal/components/package.json @@ -86,7 +86,7 @@ "remark-gh-alerts": "0.0.3", "remark-rehype": "11.1.2", "sonner": "2.0.6", - "tailwindcss-uikit-colors": "1.0.0-alpha.1", + "tailwindcss-uikit-colors": "catalog:", "unified": "11.0.5", "unist-util-visit": "5.0.0", "unist-util-visit-parents": "5.1.3", diff --git a/packages/internal/components/src/ui/json-highlighter/index.tsx b/packages/internal/components/src/ui/json-highlighter/index.tsx index e6e45e7c5..c86e4ba4b 100644 --- a/packages/internal/components/src/ui/json-highlighter/index.tsx +++ b/packages/internal/components/src/ui/json-highlighter/index.tsx @@ -96,7 +96,7 @@ interface Token { function highlightJson(jsonString: string): string { // Escape HTML entities first const escaped = jsonString - .replaceAll("&", "&") + ?.replaceAll("&", "&") .replaceAll("<", "<") .replaceAll(">", ">") diff --git a/packages/internal/shared/src/settings/defaults.ts b/packages/internal/shared/src/settings/defaults.ts index be2158999..6c6bcf73b 100644 --- a/packages/internal/shared/src/settings/defaults.ts +++ b/packages/internal/shared/src/settings/defaults.ts @@ -156,6 +156,10 @@ export const defaultAISettings: AISettings = { personalizePrompt: "", shortcuts: [], + // MCP Services + mcpEnabled: false, + mcpServices: [], + // Features autoScrollWhenStreaming: true, } diff --git a/packages/internal/shared/src/settings/interface.ts b/packages/internal/shared/src/settings/interface.ts index c827740b6..0a492182a 100644 --- a/packages/internal/shared/src/settings/interface.ts +++ b/packages/internal/shared/src/settings/interface.ts @@ -178,10 +178,31 @@ export interface AIShortcut { hotkey?: string } +export type MCPTransportType = "streamable-http" | "sse" + +export interface MCPService { + id: string + name: string + transportType: MCPTransportType + url?: string + headers?: Record + isConnected: boolean + lastError?: string + toolCount: number + resourceCount: number + promptCount: number + createdAt: string + lastUsed: string | null +} + export interface AISettings { personalizePrompt: string shortcuts: AIShortcut[] + // MCP Services (stored locally, actual connections managed via server API) + mcpEnabled: boolean + mcpServices: MCPService[] + // Features autoScrollWhenStreaming: boolean } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 3466db906..b03cba188 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -7,8 +7,11 @@ settings: catalogs: default: '@follow-app/client-sdk': - specifier: 0.3.29 - version: 0.3.29 + specifier: 0.3.38 + version: 0.3.38 + tailwindcss-uikit-colors: + specifier: 1.0.0 + version: 1.0.0 typescript: specifier: 5.8.3 version: 5.8.3 @@ -462,7 +465,7 @@ importers: version: 3.0.2(electron@37.2.0) '@follow-app/client-sdk': specifier: 'catalog:' - version: 0.3.29(@opentelemetry/api@1.9.0)(@types/pg@8.6.1)(expo-sqlite@15.2.12(expo@53.0.12(@babel/core@7.28.0)(@expo/metro-runtime@5.0.4(react-native@0.79.1(@babel/core@7.28.0)(@types/react@19.1.8)(bufferutil@4.0.9)(react@19.0.0)))(bufferutil@4.0.9)(graphql@16.8.1)(react-native-webview@13.15.0(react-native@0.79.1(@babel/core@7.28.0)(@types/react@19.1.8)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(react-native@0.79.1(@babel/core@7.28.0)(@types/react@19.1.8)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(react-native@0.79.1(@babel/core@7.28.0)(@types/react@19.1.8)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(kysely@0.28.2)(pg@8.16.3) + version: 0.3.38(@opentelemetry/api@1.9.0)(@types/pg@8.6.1)(expo-sqlite@15.2.12(expo@53.0.12(@babel/core@7.28.0)(@expo/metro-runtime@5.0.4(react-native@0.79.1(@babel/core@7.28.0)(@types/react@19.1.8)(bufferutil@4.0.9)(react@19.0.0)))(bufferutil@4.0.9)(graphql@16.8.1)(react-native-webview@13.15.0(react-native@0.79.1(@babel/core@7.28.0)(@types/react@19.1.8)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(react-native@0.79.1(@babel/core@7.28.0)(@types/react@19.1.8)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(react-native@0.79.1(@babel/core@7.28.0)(@types/react@19.1.8)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(kysely@0.28.2)(pg@8.16.3) '@follow/database': specifier: workspace:* version: link:../../../../packages/internal/database @@ -1330,8 +1333,8 @@ importers: specifier: 8.2.0 version: 8.2.0 tailwindcss-uikit-colors: - specifier: 1.0.0-alpha.1 - version: 1.0.0-alpha.1 + specifier: 'catalog:' + version: 1.0.0 tsdown: specifier: 0.12.9 version: 0.12.9(typescript@5.8.3) @@ -1409,8 +1412,8 @@ importers: specifier: 0.6.0 version: 0.6.0(tailwindcss@3.4.17(ts-node@10.9.2(@types/node@24.0.10)(typescript@5.8.3))) tailwindcss-uikit-colors: - specifier: 1.0.0-alpha.1 - version: 1.0.0-alpha.1 + specifier: 'catalog:' + version: 1.0.0 devDependencies: postcss: specifier: 8.5.6 @@ -1635,8 +1638,8 @@ importers: specifier: 2.0.6 version: 2.0.6(react-dom@19.0.0(react@19.0.0))(react@19.0.0) tailwindcss-uikit-colors: - specifier: 1.0.0-alpha.1 - version: 1.0.0-alpha.1 + specifier: 'catalog:' + version: 1.0.0 unified: specifier: 11.0.5 version: 11.0.5 @@ -1670,7 +1673,7 @@ importers: dependencies: '@follow-app/client-sdk': specifier: 'catalog:' - version: 0.3.29(@opentelemetry/api@1.9.0)(@types/pg@8.6.1)(expo-sqlite@15.2.12(expo@53.0.12(@babel/core@7.28.0)(@expo/metro-runtime@5.0.4(react-native@0.79.1(@babel/core@7.28.0)(@types/react@19.1.8)(bufferutil@4.0.9)(react@19.0.0)))(bufferutil@4.0.9)(graphql@16.8.1)(react-native-webview@13.15.0(react-native@0.79.1(@babel/core@7.28.0)(@types/react@19.1.8)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(react-native@0.79.1(@babel/core@7.28.0)(@types/react@19.1.8)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(react-native@0.79.1(@babel/core@7.28.0)(@types/react@19.1.8)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(kysely@0.28.2)(pg@8.16.3) + version: 0.3.38(@opentelemetry/api@1.9.0)(@types/pg@8.6.1)(expo-sqlite@15.2.12(expo@53.0.12(@babel/core@7.28.0)(@expo/metro-runtime@5.0.4(react-native@0.79.1(@babel/core@7.28.0)(@types/react@19.1.8)(bufferutil@4.0.9)(react@19.0.0)))(bufferutil@4.0.9)(graphql@16.8.1)(react-native-webview@13.15.0(react-native@0.79.1(@babel/core@7.28.0)(@types/react@19.1.8)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(react-native@0.79.1(@babel/core@7.28.0)(@types/react@19.1.8)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(react-native@0.79.1(@babel/core@7.28.0)(@types/react@19.1.8)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(kysely@0.28.2)(pg@8.16.3) '@follow/configs': specifier: workspace:* version: link:../../configs @@ -1682,7 +1685,7 @@ importers: dependencies: '@follow-app/client-sdk': specifier: 'catalog:' - version: 0.3.29(@opentelemetry/api@1.9.0)(@types/pg@8.6.1)(expo-sqlite@15.2.12(expo@53.0.12(@babel/core@7.28.0)(@expo/metro-runtime@5.0.4(react-native@0.79.1(@babel/core@7.28.0)(@types/react@19.1.8)(bufferutil@4.0.9)(react@19.0.0)))(bufferutil@4.0.9)(graphql@16.8.1)(react-native-webview@13.15.0(react-native@0.79.1(@babel/core@7.28.0)(@types/react@19.1.8)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(react-native@0.79.1(@babel/core@7.28.0)(@types/react@19.1.8)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(react-native@0.79.1(@babel/core@7.28.0)(@types/react@19.1.8)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(kysely@0.28.2)(pg@8.16.3) + version: 0.3.38(@opentelemetry/api@1.9.0)(@types/pg@8.6.1)(expo-sqlite@15.2.12(expo@53.0.12(@babel/core@7.28.0)(@expo/metro-runtime@5.0.4(react-native@0.79.1(@babel/core@7.28.0)(@types/react@19.1.8)(bufferutil@4.0.9)(react@19.0.0)))(bufferutil@4.0.9)(graphql@16.8.1)(react-native-webview@13.15.0(react-native@0.79.1(@babel/core@7.28.0)(@types/react@19.1.8)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(react-native@0.79.1(@babel/core@7.28.0)(@types/react@19.1.8)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(react-native@0.79.1(@babel/core@7.28.0)(@types/react@19.1.8)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(kysely@0.28.2)(pg@8.16.3) '@follow/constants': specifier: workspace:* version: link:../constants @@ -1760,7 +1763,7 @@ importers: dependencies: '@follow-app/client-sdk': specifier: 'catalog:' - version: 0.3.29(@opentelemetry/api@1.9.0)(@types/pg@8.6.1)(expo-sqlite@15.2.12(expo@53.0.12(@babel/core@7.28.0)(@expo/metro-runtime@5.0.4(react-native@0.79.1(@babel/core@7.28.0)(@types/react@19.1.8)(bufferutil@4.0.9)(react@19.0.0)))(bufferutil@4.0.9)(graphql@16.8.1)(react-native-webview@13.15.0(react-native@0.79.1(@babel/core@7.28.0)(@types/react@19.1.8)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(react-native@0.79.1(@babel/core@7.28.0)(@types/react@19.1.8)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(react-native@0.79.1(@babel/core@7.28.0)(@types/react@19.1.8)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(kysely@0.28.2)(pg@8.16.3) + version: 0.3.38(@opentelemetry/api@1.9.0)(@types/pg@8.6.1)(expo-sqlite@15.2.12(expo@53.0.12(@babel/core@7.28.0)(@expo/metro-runtime@5.0.4(react-native@0.79.1(@babel/core@7.28.0)(@types/react@19.1.8)(bufferutil@4.0.9)(react@19.0.0)))(bufferutil@4.0.9)(graphql@16.8.1)(react-native-webview@13.15.0(react-native@0.79.1(@babel/core@7.28.0)(@types/react@19.1.8)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(react-native@0.79.1(@babel/core@7.28.0)(@types/react@19.1.8)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(react-native@0.79.1(@babel/core@7.28.0)(@types/react@19.1.8)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(kysely@0.28.2)(pg@8.16.3) '@follow/constants': specifier: workspace:* version: link:../constants @@ -1824,7 +1827,7 @@ importers: dependencies: '@follow-app/client-sdk': specifier: 'catalog:' - version: 0.3.29(@opentelemetry/api@1.9.0)(@types/pg@8.6.1)(expo-sqlite@15.2.12(expo@53.0.12(@babel/core@7.28.0)(@expo/metro-runtime@5.0.4(react-native@0.79.1(@babel/core@7.28.0)(@types/react@19.1.8)(bufferutil@4.0.9)(react@19.0.0)))(bufferutil@4.0.9)(graphql@16.8.1)(react-native-webview@13.15.0(react-native@0.79.1(@babel/core@7.28.0)(@types/react@19.1.8)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(react-native@0.79.1(@babel/core@7.28.0)(@types/react@19.1.8)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(react-native@0.79.1(@babel/core@7.28.0)(@types/react@19.1.8)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(kysely@0.28.2)(pg@8.16.3) + version: 0.3.38(@opentelemetry/api@1.9.0)(@types/pg@8.6.1)(expo-sqlite@15.2.12(expo@53.0.12(@babel/core@7.28.0)(@expo/metro-runtime@5.0.4(react-native@0.79.1(@babel/core@7.28.0)(@types/react@19.1.8)(bufferutil@4.0.9)(react@19.0.0)))(bufferutil@4.0.9)(graphql@16.8.1)(react-native-webview@13.15.0(react-native@0.79.1(@babel/core@7.28.0)(@types/react@19.1.8)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(react-native@0.79.1(@babel/core@7.28.0)(@types/react@19.1.8)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(react-native@0.79.1(@babel/core@7.28.0)(@types/react@19.1.8)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(kysely@0.28.2)(pg@8.16.3) '@follow/configs': specifier: workspace:* version: link:../../configs @@ -4048,23 +4051,29 @@ packages: '@floating-ui/utils@0.2.10': resolution: {integrity: sha512-aGTxbpbg8/b5JfU1HXSrbH3wXZuLPJcNEcZQFMxLs3oSzgtVu6nFPkbbGGUvBcUjKV2YyB9Wxxabo+HEH9tcRQ==} - '@follow-app/client-sdk@0.3.29': - resolution: {integrity: sha512-bQgY0S6xrWO0iLO4eeptU4vxcmQ36iSrLl6omNscK6SCXzlebCYRmqQy7dsFHU4+bditADjjLulCGWmbDX9IJQ==} + '@follow-app/client-sdk@0.3.38': + resolution: {integrity: sha512-dewSXei/nLfwY+S6a4P8B9xlAgh4LhORyBWphN87b54Lbs3kX3ydx6esrcXliUTwOFH+TkpxbIQR16zPR/ApBw==} '@folo-services/ai-tools@0.2.20': resolution: {integrity: sha512-1AJI48H2g64JhuTruSqQKUrn4Tc353hMFdKAbohh65AxTAMN/1pIw9w17Dtjm+g5BVlZUXYKaiIvaN9tHsXLNA==} - '@folo-services/constants@0.1.18': - resolution: {integrity: sha512-3LDxX4Ebvr6GLdL5Ce2ZkAJwfNjfsdqOLpuFRZ3bq2gVwQZbIGsln+qYnInmR5+1i3DtebglrAj/IktnT3BsIg==} + '@folo-services/constants@0.1.21': + resolution: {integrity: sha512-4ws5nXxYjvm204rHH03ohUAhll5oWXgvlRnVGzxe9BkW+f64kJOshFxEeTxMDm2SMj0cnjEblsGvA29xJfXs/A==} '@folo-services/drizzle@0.1.13': resolution: {integrity: sha512-h6tndGnTLrAmfvxK5XsXGdZaMi2GBmFZBFiBqtabC7Y05A1ZSOaWg/d9f60Ydh586LmVonz5VGrhvzTdn5ukhg==} + '@folo-services/drizzle@0.1.16': + resolution: {integrity: sha512-ieo0vAf3KRlz6GZ9WY2BRut80qB9nxplTHS8rRtUJVnrsqP6mXDgChjAoX32vy3YKHk6xJfrzgWLoAlqfsvxyQ==} + '@folo-services/exceptions@0.1.11': resolution: {integrity: sha512-OMKat8KcIxjw9pBfG3pC1kRcIs0YiuaYmMDA2MRy8AEGcki8F9u5e5QH7OKgP/LlNR7Fs2Csz1XetvcC4nB+RQ==} - '@folo-services/shared@0.0.8': - resolution: {integrity: sha512-rfl1vvGMxUnchckGSKOkeT5hS1NAzZTJ8gPF6yFR+TuSe2SZzq1a10/66nK9OxmqaDFaHdOpQfNXz2vp0gRJpg==} + '@folo-services/exceptions@0.1.14': + resolution: {integrity: sha512-VFVRkzXg7BytEvdg7iyUXc6qaAudTTtOU8PrTkRUG4ZB9udLE/uVT5q+6poS1CkwMi2GroH27AFC4fnfVp6Fvw==} + + '@folo-services/shared@0.0.11': + resolution: {integrity: sha512-WS0OVoswUfPr4X8SCPYdyxx4XL7Khh63NCk0pilCtci3XtO2kMPWlLEM4gJAfg6g5GAs4oVNvsJiNEKEa3Lo1g==} '@fontsource/sn-pro@5.2.5': resolution: {integrity: sha512-rBdBv/0ygj6bkO7xDMMFpwobLdSrcQ2Jncb6DIwdeYGoAgeWkQRwVYhGDKasfLjEYCNYxrqr6wsXsM9+aU39RA==} @@ -7119,6 +7128,9 @@ packages: apple-uikit-colors@0.6.2: resolution: {integrity: sha512-sv0b92krbTZGNt4AJQLAPioUvuEI/wW2cLqGuEBWl3KpU2JK/odOftx8+dGSC5jGWhdB5qnwBqF96X2FA8FUQA==} + apple-uikit-colors@1.0.0: + resolution: {integrity: sha512-G2Ti2ogMOOC1phfHacSrLacDiE0RcLI7IG3aNoaw7Ack23WI8/9QczmUuhxxkU9BoIR2euCZ2G4lD5qJ+OknwA==} + archiver-utils@2.1.0: resolution: {integrity: sha512-bEL/yUb/fNNiNTuUz979Z0Yg5L+LzLxGJz8x79lYmR54fmTIb6ob/hNQgkQnIUDWIFjZVQwl9Xs356I6BAMHfw==} engines: {node: '>= 6'} @@ -14571,8 +14583,8 @@ packages: tailwindcss-uikit-colors@0.6.2: resolution: {integrity: sha512-RfF3VVB2nHvJwPZ2ZSTMgKYbZjRny/KW3rP6ufg6/bopxINDQ9TpN/fJXxvKnD86hIU0F2oLIfAv2r6o/ZWcZw==} - tailwindcss-uikit-colors@1.0.0-alpha.1: - resolution: {integrity: sha512-akeDIVZMRO6tFbr6x4YsRkx24xx/ofEfsJdL2lq7AE/sDBnUbs5Pr8by4ngBbxJ2U2eam000B/eJrb6r6YzLmw==} + tailwindcss-uikit-colors@1.0.0: + resolution: {integrity: sha512-18MGdMVSoXFKjcVkUIu7Q5USqdenAvgFJT9DEocPmdS94b8d/z3s0Uw8LvaNDINfDN9ls24hfg6/hyFqpcZpxw==} tailwindcss@3.4.17: resolution: {integrity: sha512-w33E2aCvSDP0tW9RZuNXadXlkHXqFzSkQew/aIa2i/Sj8fThxwovwlXHSPXTbAHwEIhBFXAedUhP2tueAKP8Og==} @@ -18921,12 +18933,12 @@ snapshots: '@floating-ui/utils@0.2.10': {} - '@follow-app/client-sdk@0.3.29(@opentelemetry/api@1.9.0)(@types/pg@8.6.1)(expo-sqlite@15.2.12(expo@53.0.12(@babel/core@7.28.0)(@expo/metro-runtime@5.0.4(react-native@0.79.1(@babel/core@7.28.0)(@types/react@19.1.8)(bufferutil@4.0.9)(react@19.0.0)))(bufferutil@4.0.9)(graphql@16.8.1)(react-native-webview@13.15.0(react-native@0.79.1(@babel/core@7.28.0)(@types/react@19.1.8)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(react-native@0.79.1(@babel/core@7.28.0)(@types/react@19.1.8)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(react-native@0.79.1(@babel/core@7.28.0)(@types/react@19.1.8)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(kysely@0.28.2)(pg@8.16.3)': + '@follow-app/client-sdk@0.3.38(@opentelemetry/api@1.9.0)(@types/pg@8.6.1)(expo-sqlite@15.2.12(expo@53.0.12(@babel/core@7.28.0)(@expo/metro-runtime@5.0.4(react-native@0.79.1(@babel/core@7.28.0)(@types/react@19.1.8)(bufferutil@4.0.9)(react@19.0.0)))(bufferutil@4.0.9)(graphql@16.8.1)(react-native-webview@13.15.0(react-native@0.79.1(@babel/core@7.28.0)(@types/react@19.1.8)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(react-native@0.79.1(@babel/core@7.28.0)(@types/react@19.1.8)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(react-native@0.79.1(@babel/core@7.28.0)(@types/react@19.1.8)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(kysely@0.28.2)(pg@8.16.3)': dependencies: - '@folo-services/constants': 0.1.18 - '@folo-services/drizzle': 0.1.13(@opentelemetry/api@1.9.0)(@types/pg@8.6.1)(expo-sqlite@15.2.12(expo@53.0.12(@babel/core@7.28.0)(@expo/metro-runtime@5.0.4(react-native@0.79.1(@babel/core@7.28.0)(@types/react@19.1.8)(bufferutil@4.0.9)(react@19.0.0)))(bufferutil@4.0.9)(graphql@16.8.1)(react-native-webview@13.15.0(react-native@0.79.1(@babel/core@7.28.0)(@types/react@19.1.8)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(react-native@0.79.1(@babel/core@7.28.0)(@types/react@19.1.8)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(react-native@0.79.1(@babel/core@7.28.0)(@types/react@19.1.8)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(kysely@0.28.2) - '@folo-services/exceptions': 0.1.11 - '@folo-services/shared': 0.0.8(@opentelemetry/api@1.9.0)(@types/pg@8.6.1)(expo-sqlite@15.2.12(expo@53.0.12(@babel/core@7.28.0)(@expo/metro-runtime@5.0.4(react-native@0.79.1(@babel/core@7.28.0)(@types/react@19.1.8)(bufferutil@4.0.9)(react@19.0.0)))(bufferutil@4.0.9)(graphql@16.8.1)(react-native-webview@13.15.0(react-native@0.79.1(@babel/core@7.28.0)(@types/react@19.1.8)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(react-native@0.79.1(@babel/core@7.28.0)(@types/react@19.1.8)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(react-native@0.79.1(@babel/core@7.28.0)(@types/react@19.1.8)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(kysely@0.28.2)(pg@8.16.3) + '@folo-services/constants': 0.1.21 + '@folo-services/drizzle': 0.1.16(@opentelemetry/api@1.9.0)(@types/pg@8.6.1)(expo-sqlite@15.2.12(expo@53.0.12(@babel/core@7.28.0)(@expo/metro-runtime@5.0.4(react-native@0.79.1(@babel/core@7.28.0)(@types/react@19.1.8)(bufferutil@4.0.9)(react@19.0.0)))(bufferutil@4.0.9)(graphql@16.8.1)(react-native-webview@13.15.0(react-native@0.79.1(@babel/core@7.28.0)(@types/react@19.1.8)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(react-native@0.79.1(@babel/core@7.28.0)(@types/react@19.1.8)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(react-native@0.79.1(@babel/core@7.28.0)(@types/react@19.1.8)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(kysely@0.28.2) + '@folo-services/exceptions': 0.1.14 + '@folo-services/shared': 0.0.11(@opentelemetry/api@1.9.0)(@types/pg@8.6.1)(expo-sqlite@15.2.12(expo@53.0.12(@babel/core@7.28.0)(@expo/metro-runtime@5.0.4(react-native@0.79.1(@babel/core@7.28.0)(@types/react@19.1.8)(bufferutil@4.0.9)(react@19.0.0)))(bufferutil@4.0.9)(graphql@16.8.1)(react-native-webview@13.15.0(react-native@0.79.1(@babel/core@7.28.0)(@types/react@19.1.8)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(react-native@0.79.1(@babel/core@7.28.0)(@types/react@19.1.8)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(react-native@0.79.1(@babel/core@7.28.0)(@types/react@19.1.8)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(kysely@0.28.2)(pg@8.16.3) zod: 3.25.76 transitivePeerDependencies: - '@aws-sdk/client-rds-data' @@ -18999,7 +19011,7 @@ snapshots: - sql.js - sqlite3 - '@folo-services/constants@0.1.18': + '@folo-services/constants@0.1.21': dependencies: zod: 3.25.76 @@ -19042,11 +19054,52 @@ snapshots: - sql.js - sqlite3 + '@folo-services/drizzle@0.1.16(@opentelemetry/api@1.9.0)(@types/pg@8.6.1)(expo-sqlite@15.2.12(expo@53.0.12(@babel/core@7.28.0)(@expo/metro-runtime@5.0.4(react-native@0.79.1(@babel/core@7.28.0)(@types/react@19.1.8)(bufferutil@4.0.9)(react@19.0.0)))(bufferutil@4.0.9)(graphql@16.8.1)(react-native-webview@13.15.0(react-native@0.79.1(@babel/core@7.28.0)(@types/react@19.1.8)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(react-native@0.79.1(@babel/core@7.28.0)(@types/react@19.1.8)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(react-native@0.79.1(@babel/core@7.28.0)(@types/react@19.1.8)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(kysely@0.28.2)': + dependencies: + '@folo-services/exceptions': 0.1.14 + drizzle-orm: 0.44.3(@opentelemetry/api@1.9.0)(@types/pg@8.6.1)(expo-sqlite@15.2.12(expo@53.0.12(@babel/core@7.28.0)(@expo/metro-runtime@5.0.4(react-native@0.79.1(@babel/core@7.28.0)(@types/react@19.1.8)(bufferutil@4.0.9)(react@19.0.0)))(bufferutil@4.0.9)(graphql@16.8.1)(react-native-webview@13.15.0(react-native@0.79.1(@babel/core@7.28.0)(@types/react@19.1.8)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(react-native@0.79.1(@babel/core@7.28.0)(@types/react@19.1.8)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(react-native@0.79.1(@babel/core@7.28.0)(@types/react@19.1.8)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(kysely@0.28.2)(pg@8.16.3) + drizzle-zod: 0.7.1(drizzle-orm@0.44.3(@opentelemetry/api@1.9.0)(@types/pg@8.6.1)(expo-sqlite@15.2.12(expo@53.0.12(@babel/core@7.28.0)(@expo/metro-runtime@5.0.4(react-native@0.79.1(@babel/core@7.28.0)(@types/react@19.1.8)(bufferutil@4.0.9)(react@19.0.0)))(bufferutil@4.0.9)(graphql@16.8.1)(react-native-webview@13.15.0(react-native@0.79.1(@babel/core@7.28.0)(@types/react@19.1.8)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(react-native@0.79.1(@babel/core@7.28.0)(@types/react@19.1.8)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(react-native@0.79.1(@babel/core@7.28.0)(@types/react@19.1.8)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(kysely@0.28.2)(pg@8.16.3))(zod@3.25.76) + nanoid: 5.1.5 + pg: 8.16.3 + zod: 3.25.76 + transitivePeerDependencies: + - '@aws-sdk/client-rds-data' + - '@cloudflare/workers-types' + - '@electric-sql/pglite' + - '@libsql/client' + - '@libsql/client-wasm' + - '@neondatabase/serverless' + - '@op-engineering/op-sqlite' + - '@opentelemetry/api' + - '@planetscale/database' + - '@prisma/client' + - '@tidbcloud/serverless' + - '@types/better-sqlite3' + - '@types/pg' + - '@types/sql.js' + - '@upstash/redis' + - '@vercel/postgres' + - '@xata.io/client' + - better-sqlite3 + - bun-types + - expo-sqlite + - gel + - knex + - kysely + - mysql2 + - pg-native + - postgres + - prisma + - sql.js + - sqlite3 + '@folo-services/exceptions@0.1.11': {} - '@folo-services/shared@0.0.8(@opentelemetry/api@1.9.0)(@types/pg@8.6.1)(expo-sqlite@15.2.12(expo@53.0.12(@babel/core@7.28.0)(@expo/metro-runtime@5.0.4(react-native@0.79.1(@babel/core@7.28.0)(@types/react@19.1.8)(bufferutil@4.0.9)(react@19.0.0)))(bufferutil@4.0.9)(graphql@16.8.1)(react-native-webview@13.15.0(react-native@0.79.1(@babel/core@7.28.0)(@types/react@19.1.8)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(react-native@0.79.1(@babel/core@7.28.0)(@types/react@19.1.8)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(react-native@0.79.1(@babel/core@7.28.0)(@types/react@19.1.8)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(kysely@0.28.2)(pg@8.16.3)': + '@folo-services/exceptions@0.1.14': {} + + '@folo-services/shared@0.0.11(@opentelemetry/api@1.9.0)(@types/pg@8.6.1)(expo-sqlite@15.2.12(expo@53.0.12(@babel/core@7.28.0)(@expo/metro-runtime@5.0.4(react-native@0.79.1(@babel/core@7.28.0)(@types/react@19.1.8)(bufferutil@4.0.9)(react@19.0.0)))(bufferutil@4.0.9)(graphql@16.8.1)(react-native-webview@13.15.0(react-native@0.79.1(@babel/core@7.28.0)(@types/react@19.1.8)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(react-native@0.79.1(@babel/core@7.28.0)(@types/react@19.1.8)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(react-native@0.79.1(@babel/core@7.28.0)(@types/react@19.1.8)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(kysely@0.28.2)(pg@8.16.3)': dependencies: - '@folo-services/drizzle': 0.1.13(@opentelemetry/api@1.9.0)(@types/pg@8.6.1)(expo-sqlite@15.2.12(expo@53.0.12(@babel/core@7.28.0)(@expo/metro-runtime@5.0.4(react-native@0.79.1(@babel/core@7.28.0)(@types/react@19.1.8)(bufferutil@4.0.9)(react@19.0.0)))(bufferutil@4.0.9)(graphql@16.8.1)(react-native-webview@13.15.0(react-native@0.79.1(@babel/core@7.28.0)(@types/react@19.1.8)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(react-native@0.79.1(@babel/core@7.28.0)(@types/react@19.1.8)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(react-native@0.79.1(@babel/core@7.28.0)(@types/react@19.1.8)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(kysely@0.28.2) + '@folo-services/drizzle': 0.1.16(@opentelemetry/api@1.9.0)(@types/pg@8.6.1)(expo-sqlite@15.2.12(expo@53.0.12(@babel/core@7.28.0)(@expo/metro-runtime@5.0.4(react-native@0.79.1(@babel/core@7.28.0)(@types/react@19.1.8)(bufferutil@4.0.9)(react@19.0.0)))(bufferutil@4.0.9)(graphql@16.8.1)(react-native-webview@13.15.0(react-native@0.79.1(@babel/core@7.28.0)(@types/react@19.1.8)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(react-native@0.79.1(@babel/core@7.28.0)(@types/react@19.1.8)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(react-native@0.79.1(@babel/core@7.28.0)(@types/react@19.1.8)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(kysely@0.28.2) drizzle-orm: 0.44.3(@opentelemetry/api@1.9.0)(@types/pg@8.6.1)(expo-sqlite@15.2.12(expo@53.0.12(@babel/core@7.28.0)(@expo/metro-runtime@5.0.4(react-native@0.79.1(@babel/core@7.28.0)(@types/react@19.1.8)(bufferutil@4.0.9)(react@19.0.0)))(bufferutil@4.0.9)(graphql@16.8.1)(react-native-webview@13.15.0(react-native@0.79.1(@babel/core@7.28.0)(@types/react@19.1.8)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(react-native@0.79.1(@babel/core@7.28.0)(@types/react@19.1.8)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(react-native@0.79.1(@babel/core@7.28.0)(@types/react@19.1.8)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(kysely@0.28.2)(pg@8.16.3) drizzle-zod: 0.7.1(drizzle-orm@0.44.3(@opentelemetry/api@1.9.0)(@types/pg@8.6.1)(expo-sqlite@15.2.12(expo@53.0.12(@babel/core@7.28.0)(@expo/metro-runtime@5.0.4(react-native@0.79.1(@babel/core@7.28.0)(@types/react@19.1.8)(bufferutil@4.0.9)(react@19.0.0)))(bufferutil@4.0.9)(graphql@16.8.1)(react-native-webview@13.15.0(react-native@0.79.1(@babel/core@7.28.0)(@types/react@19.1.8)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(react-native@0.79.1(@babel/core@7.28.0)(@types/react@19.1.8)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(react-native@0.79.1(@babel/core@7.28.0)(@types/react@19.1.8)(bufferutil@4.0.9)(react@19.0.0))(react@19.0.0))(kysely@0.28.2)(pg@8.16.3))(zod@3.25.76) zod: 3.25.76 @@ -22755,6 +22808,8 @@ snapshots: apple-uikit-colors@0.6.2: {} + apple-uikit-colors@1.0.0: {} + archiver-utils@2.1.0: dependencies: glob: 7.2.3 @@ -31549,9 +31604,9 @@ snapshots: dependencies: apple-uikit-colors: 0.6.2 - tailwindcss-uikit-colors@1.0.0-alpha.1: + tailwindcss-uikit-colors@1.0.0: dependencies: - apple-uikit-colors: 0.6.2 + apple-uikit-colors: 1.0.0 tailwindcss@3.4.17(ts-node@10.9.2(@types/node@24.0.10)(typescript@5.8.3)): dependencies: diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml index aa757362d..2b8811de5 100644 --- a/pnpm-workspace.yaml +++ b/pnpm-workspace.yaml @@ -58,4 +58,5 @@ overrides: catalog: typescript: "5.8.3" - "@follow-app/client-sdk": "0.3.29" + "@follow-app/client-sdk": "0.3.38" + tailwindcss-uikit-colors: "1.0.0"