Merge branch 'dev' of https://github.com/A-Dawn/MaiBot into dev
This commit is contained in:
@@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"name": "maibot-dashboard",
|
"name": "maibot-dashboard",
|
||||||
"private": true,
|
"private": true,
|
||||||
"version": "1.0.9",
|
"version": "1.0.10",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"main": "./out/main/index.js",
|
"main": "./out/main/index.js",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
|
|||||||
@@ -21,6 +21,7 @@ interface PluginApiResponse {
|
|||||||
id: string
|
id: string
|
||||||
manifest: {
|
manifest: {
|
||||||
manifest_version: number
|
manifest_version: number
|
||||||
|
id?: string
|
||||||
name: string
|
name: string
|
||||||
version: string
|
version: string
|
||||||
description: string
|
description: string
|
||||||
@@ -56,6 +57,7 @@ function normalizePluginManifest(manifest: PluginApiResponse['manifest']): Plugi
|
|||||||
|
|
||||||
return {
|
return {
|
||||||
manifest_version: manifest.manifest_version || 1,
|
manifest_version: manifest.manifest_version || 1,
|
||||||
|
id: manifest.id,
|
||||||
name: manifest.name,
|
name: manifest.name,
|
||||||
version: manifest.version,
|
version: manifest.version,
|
||||||
description: manifest.description || '',
|
description: manifest.description || '',
|
||||||
@@ -104,10 +106,15 @@ export async function fetchPluginList(): Promise<ApiResponse<PluginInfo[]>> {
|
|||||||
|
|
||||||
const pluginList = data
|
const pluginList = data
|
||||||
.filter(item => {
|
.filter(item => {
|
||||||
if (!item?.id || !item?.manifest) {
|
if (!item?.manifest) {
|
||||||
console.warn('跳过无效插件数据:', item)
|
console.warn('跳过无效插件数据:', item)
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
const pluginId = item.manifest.id || item.id
|
||||||
|
if (!pluginId) {
|
||||||
|
console.warn('跳过缺少 ID 的插件:', item)
|
||||||
|
return false
|
||||||
|
}
|
||||||
if (!item.manifest.name || !item.manifest.version) {
|
if (!item.manifest.name || !item.manifest.version) {
|
||||||
console.warn('跳过缺少必需字段的插件:', item.id)
|
console.warn('跳过缺少必需字段的插件:', item.id)
|
||||||
return false
|
return false
|
||||||
@@ -115,7 +122,7 @@ export async function fetchPluginList(): Promise<ApiResponse<PluginInfo[]>> {
|
|||||||
return true
|
return true
|
||||||
})
|
})
|
||||||
.map((item) => ({
|
.map((item) => ({
|
||||||
id: item.id,
|
id: item.manifest.id || item.id,
|
||||||
manifest: normalizePluginManifest(item.manifest),
|
manifest: normalizePluginManifest(item.manifest),
|
||||||
downloads: 0,
|
downloads: 0,
|
||||||
rating: 0,
|
rating: 0,
|
||||||
|
|||||||
@@ -25,6 +25,7 @@ export interface InstalledPlugin {
|
|||||||
id: string
|
id: string
|
||||||
manifest: {
|
manifest: {
|
||||||
manifest_version: number
|
manifest_version: number
|
||||||
|
id?: string
|
||||||
name: string
|
name: string
|
||||||
version: string
|
version: string
|
||||||
description: string
|
description: string
|
||||||
|
|||||||
@@ -5,7 +5,7 @@
|
|||||||
* 修改此处的版本号后,所有展示版本的地方都会自动更新
|
* 修改此处的版本号后,所有展示版本的地方都会自动更新
|
||||||
*/
|
*/
|
||||||
|
|
||||||
export const APP_VERSION = '1.0.9'
|
export const APP_VERSION = '1.0.10'
|
||||||
export const APP_NAME = 'MaiBot Dashboard'
|
export const APP_NAME = 'MaiBot Dashboard'
|
||||||
export const APP_FULL_NAME = `${APP_NAME} v${APP_VERSION}`
|
export const APP_FULL_NAME = `${APP_NAME} v${APP_VERSION}`
|
||||||
|
|
||||||
|
|||||||
@@ -104,21 +104,23 @@ export function PluginDetailPage() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const pluginList = JSON.parse(result.data)
|
const pluginList = JSON.parse(result.data)
|
||||||
const foundPlugin = pluginList.find((p: any) => p.id === search.pluginId)
|
const foundPlugin = pluginList.find((p: any) => (p.manifest?.id || p.id) === search.pluginId)
|
||||||
|
|
||||||
if (!foundPlugin) {
|
if (!foundPlugin) {
|
||||||
throw new Error('未找到该插件')
|
throw new Error('未找到该插件')
|
||||||
}
|
}
|
||||||
|
|
||||||
const rawManifest = foundPlugin.manifest || {}
|
const rawManifest = foundPlugin.manifest || {}
|
||||||
|
const pluginId = rawManifest.id || foundPlugin.id
|
||||||
const repositoryUrl = rawManifest.repository_url || rawManifest.urls?.repository
|
const repositoryUrl = rawManifest.repository_url || rawManifest.urls?.repository
|
||||||
const homepageUrl = rawManifest.homepage_url || rawManifest.urls?.homepage
|
const homepageUrl = rawManifest.homepage_url || rawManifest.urls?.homepage
|
||||||
|
|
||||||
// 转换为 PluginInfo 格式
|
// 转换为 PluginInfo 格式
|
||||||
const pluginInfo: PluginInfo = {
|
const pluginInfo: PluginInfo = {
|
||||||
id: foundPlugin.id,
|
id: pluginId,
|
||||||
manifest: {
|
manifest: {
|
||||||
...rawManifest,
|
...rawManifest,
|
||||||
|
id: pluginId,
|
||||||
homepage_url: homepageUrl,
|
homepage_url: homepageUrl,
|
||||||
repository_url: repositoryUrl,
|
repository_url: repositoryUrl,
|
||||||
default_locale: rawManifest.default_locale || rawManifest.i18n?.default_locale || 'zh-CN',
|
default_locale: rawManifest.default_locale || rawManifest.i18n?.default_locale || 'zh-CN',
|
||||||
@@ -170,8 +172,8 @@ export function PluginDetailPage() {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
setIsInstalled(checkPluginInstalled(search.pluginId, installedPlugins.data))
|
setIsInstalled(checkPluginInstalled(pluginId, installedPlugins.data))
|
||||||
setInstalledVersion(getInstalledPluginVersion(search.pluginId, installedPlugins.data))
|
setInstalledVersion(getInstalledPluginVersion(pluginId, installedPlugins.data))
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
setError(err instanceof Error ? err.message : '加载失败')
|
setError(err instanceof Error ? err.message : '加载失败')
|
||||||
} finally {
|
} finally {
|
||||||
@@ -196,7 +198,7 @@ export function PluginDetailPage() {
|
|||||||
// 如果插件已安装,优先尝试从本地读取 README
|
// 如果插件已安装,优先尝试从本地读取 README
|
||||||
if (isInstalled && search.pluginId) {
|
if (isInstalled && search.pluginId) {
|
||||||
try {
|
try {
|
||||||
const localResponse = await fetchWithAuth(`/api/webui/plugins/local-readme/${search.pluginId}`)
|
const localResponse = await fetchWithAuth(`/api/webui/plugins/local-readme/${plugin.id}`)
|
||||||
|
|
||||||
if (localResponse.ok) {
|
if (localResponse.ok) {
|
||||||
const localResult = await localResponse.json()
|
const localResult = await localResponse.json()
|
||||||
|
|||||||
@@ -67,7 +67,7 @@ export function InstalledTab({
|
|||||||
})
|
})
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6">
|
<div className="grid grid-cols-1 md:grid-cols-2 xl:grid-cols-3 2xl:grid-cols-4 gap-5">
|
||||||
{filteredPlugins.map((plugin) => (
|
{filteredPlugins.map((plugin) => (
|
||||||
<PluginCard
|
<PluginCard
|
||||||
key={plugin.id}
|
key={plugin.id}
|
||||||
|
|||||||
@@ -68,7 +68,7 @@ export function MarketplaceTab({
|
|||||||
})
|
})
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6">
|
<div className="grid grid-cols-1 md:grid-cols-2 xl:grid-cols-3 2xl:grid-cols-4 gap-5">
|
||||||
{filteredPlugins.map((plugin) => (
|
{filteredPlugins.map((plugin) => (
|
||||||
<PluginCard
|
<PluginCard
|
||||||
key={plugin.id}
|
key={plugin.id}
|
||||||
|
|||||||
@@ -44,10 +44,10 @@ export function PluginCard({
|
|||||||
key={plugin.id}
|
key={plugin.id}
|
||||||
className="flex flex-col hover:shadow-lg transition-shadow h-full"
|
className="flex flex-col hover:shadow-lg transition-shadow h-full"
|
||||||
>
|
>
|
||||||
<CardHeader>
|
<CardHeader className="p-5 pb-3">
|
||||||
<div className="flex items-start justify-between gap-2">
|
<div className="flex items-start justify-between gap-3">
|
||||||
<CardTitle className="text-xl">{plugin.manifest?.name || plugin.id}</CardTitle>
|
<CardTitle className="text-lg leading-snug">{plugin.manifest?.name || plugin.id}</CardTitle>
|
||||||
<div className="flex flex-col gap-1">
|
<div className="flex flex-col items-end gap-1 shrink-0">
|
||||||
{plugin.manifest?.categories && plugin.manifest.categories[0] && (
|
{plugin.manifest?.categories && plugin.manifest.categories[0] && (
|
||||||
<Badge variant="secondary" className="text-xs whitespace-nowrap">
|
<Badge variant="secondary" className="text-xs whitespace-nowrap">
|
||||||
{CATEGORY_NAMES[plugin.manifest.categories[0]] || plugin.manifest.categories[0]}
|
{CATEGORY_NAMES[plugin.manifest.categories[0]] || plugin.manifest.categories[0]}
|
||||||
@@ -56,18 +56,18 @@ export function PluginCard({
|
|||||||
{getStatusBadge(plugin)}
|
{getStatusBadge(plugin)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<CardDescription className="line-clamp-2">{plugin.manifest?.description || '无描述'}</CardDescription>
|
<CardDescription className="line-clamp-2 text-sm leading-snug">{plugin.manifest?.description || '无描述'}</CardDescription>
|
||||||
</CardHeader>
|
</CardHeader>
|
||||||
<CardContent className="flex-1">
|
<CardContent className="px-5 pb-3">
|
||||||
<div className="space-y-3">
|
<div className="space-y-2.5">
|
||||||
{/* 统计信息 */}
|
{/* 统计信息 */}
|
||||||
<div className="flex items-center gap-4 text-sm text-muted-foreground">
|
<div className="flex items-center gap-3 text-sm text-muted-foreground">
|
||||||
<div className="flex items-center gap-1">
|
<div className="flex items-center gap-1">
|
||||||
<Download className="h-4 w-4" />
|
<Download className="h-3.5 w-3.5" />
|
||||||
<span>{(pluginStats[plugin.id]?.downloads ?? plugin.downloads ?? 0).toLocaleString()}</span>
|
<span>{(pluginStats[plugin.id]?.downloads ?? plugin.downloads ?? 0).toLocaleString()}</span>
|
||||||
</div>
|
</div>
|
||||||
<div className="flex items-center gap-1">
|
<div className="flex items-center gap-1">
|
||||||
<Star className="h-4 w-4 fill-yellow-400 text-yellow-400" />
|
<Star className="h-3.5 w-3.5 fill-yellow-400 text-yellow-400" />
|
||||||
<span>{(pluginStats[plugin.id]?.rating ?? plugin.rating ?? 0).toFixed(1)}</span>
|
<span>{(pluginStats[plugin.id]?.rating ?? plugin.rating ?? 0).toFixed(1)}</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -85,7 +85,7 @@ export function PluginCard({
|
|||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
{/* 版本和作者 */}
|
{/* 版本和作者 */}
|
||||||
<div className="text-xs text-muted-foreground pt-2 border-t space-y-1">
|
<div className="text-xs text-muted-foreground pt-2.5 border-t space-y-1">
|
||||||
<div>v{plugin.manifest?.version || 'unknown'} · {plugin.manifest?.author?.name || 'Unknown'}</div>
|
<div>v{plugin.manifest?.version || 'unknown'} · {plugin.manifest?.author?.name || 'Unknown'}</div>
|
||||||
{/* 支持版本 */}
|
{/* 支持版本 */}
|
||||||
{plugin.manifest?.host_application && (
|
{plugin.manifest?.host_application && (
|
||||||
@@ -103,7 +103,7 @@ export function PluginCard({
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</CardContent>
|
</CardContent>
|
||||||
<CardFooter className="pt-4">
|
<CardFooter className="px-5 pt-2 pb-5">
|
||||||
<div className="flex items-center justify-end gap-2 w-full">
|
<div className="flex items-center justify-end gap-2 w-full">
|
||||||
<Button
|
<Button
|
||||||
variant="outline"
|
variant="outline"
|
||||||
@@ -169,7 +169,7 @@ export function PluginCard({
|
|||||||
(loadProgress.stage === 'loading' || loadProgress.stage === 'success' || loadProgress.stage === 'error') &&
|
(loadProgress.stage === 'loading' || loadProgress.stage === 'success' || loadProgress.stage === 'error') &&
|
||||||
loadProgress.operation !== 'fetch' &&
|
loadProgress.operation !== 'fetch' &&
|
||||||
loadProgress.plugin_id === plugin.id && (
|
loadProgress.plugin_id === plugin.id && (
|
||||||
<div className="px-6 pb-4 -mt-2">
|
<div className="px-5 pb-5 -mt-1">
|
||||||
<div className={`space-y-2 p-3 rounded-lg border ${
|
<div className={`space-y-2 p-3 rounded-lg border ${
|
||||||
loadProgress.stage === 'success'
|
loadProgress.stage === 'success'
|
||||||
? 'bg-green-50 dark:bg-green-950/20 border-green-200 dark:border-green-900'
|
? 'bg-green-50 dark:bg-green-950/20 border-green-200 dark:border-green-900'
|
||||||
|
|||||||
@@ -48,6 +48,9 @@ export function PluginsPage() {
|
|||||||
function PluginsPageContent() {
|
function PluginsPageContent() {
|
||||||
const navigate = useNavigate()
|
const navigate = useNavigate()
|
||||||
const { triggerRestart, isRestarting } = useRestart()
|
const { triggerRestart, isRestarting } = useRestart()
|
||||||
|
const [restartNoticeVisible, setRestartNoticeVisible] = useState(
|
||||||
|
() => localStorage.getItem('plugins-restart-notice-dismissed') !== 'true'
|
||||||
|
)
|
||||||
const [searchQuery, setSearchQuery] = useState('')
|
const [searchQuery, setSearchQuery] = useState('')
|
||||||
const [categoryFilter, setCategoryFilter] = useState('all')
|
const [categoryFilter, setCategoryFilter] = useState('all')
|
||||||
const [activeTab, setActiveTab] = useState('all') // all | installed | updates
|
const [activeTab, setActiveTab] = useState('all') // all | installed | updates
|
||||||
@@ -67,6 +70,11 @@ function PluginsPageContent() {
|
|||||||
|
|
||||||
const { toast } = useToast()
|
const { toast } = useToast()
|
||||||
|
|
||||||
|
const dismissRestartNotice = () => {
|
||||||
|
localStorage.setItem('plugins-restart-notice-dismissed', 'true')
|
||||||
|
setRestartNoticeVisible(false)
|
||||||
|
}
|
||||||
|
|
||||||
// 加载插件统计数据
|
// 加载插件统计数据
|
||||||
const loadPluginStats = async (pluginList: PluginInfo[]) => {
|
const loadPluginStats = async (pluginList: PluginInfo[]) => {
|
||||||
const statsPromises = pluginList.map(async (plugin) => {
|
const statsPromises = pluginList.map(async (plugin) => {
|
||||||
@@ -220,6 +228,7 @@ function PluginsPageContent() {
|
|||||||
id: installedPlugin.id,
|
id: installedPlugin.id,
|
||||||
manifest: {
|
manifest: {
|
||||||
manifest_version: installedPlugin.manifest.manifest_version || 1,
|
manifest_version: installedPlugin.manifest.manifest_version || 1,
|
||||||
|
id: installedPlugin.manifest.id || installedPlugin.id,
|
||||||
name: installedPlugin.manifest.name,
|
name: installedPlugin.manifest.name,
|
||||||
version: installedPlugin.manifest.version,
|
version: installedPlugin.manifest.version,
|
||||||
description: installedPlugin.manifest.description || '',
|
description: installedPlugin.manifest.description || '',
|
||||||
@@ -704,16 +713,23 @@ function PluginsPageContent() {
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* 安装提示 */}
|
{/* 安装提示 */}
|
||||||
<Card className="border-blue-200 bg-blue-50 dark:bg-blue-950/20 dark:border-blue-900">
|
{restartNoticeVisible && (
|
||||||
<CardContent className="py-3">
|
<Card className="border-blue-200 bg-blue-50 dark:bg-blue-950/20 dark:border-blue-900">
|
||||||
<div className="flex items-center gap-2">
|
<CardContent className="py-3">
|
||||||
<Info className="h-4 w-4 text-blue-600 flex-shrink-0" />
|
<div className="flex flex-col gap-3 sm:flex-row sm:items-center sm:justify-between">
|
||||||
<p className="text-sm text-blue-800 dark:text-blue-200">
|
<div className="flex items-center gap-2">
|
||||||
安装、卸载或更新插件后,需要<span className="font-semibold">重启麦麦</span>才能使更改生效
|
<Info className="h-4 w-4 text-blue-600 flex-shrink-0" />
|
||||||
</p>
|
<p className="text-sm text-blue-800 dark:text-blue-200">
|
||||||
</div>
|
安装、卸载或更新插件后,部分插件需要<span className="font-semibold">重启麦麦</span>才能生效
|
||||||
</CardContent>
|
</p>
|
||||||
</Card>
|
</div>
|
||||||
|
<Button type="button" variant="outline" size="sm" onClick={dismissRestartNotice}>
|
||||||
|
我知道了
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
</CardContent>
|
||||||
|
</Card>
|
||||||
|
)}
|
||||||
|
|
||||||
{/* Git 状态警告 */}
|
{/* Git 状态警告 */}
|
||||||
{gitStatus && !gitStatus.installed && (
|
{gitStatus && !gitStatus.installed && (
|
||||||
|
|||||||
@@ -20,6 +20,8 @@ export interface HostApplication {
|
|||||||
export interface PluginManifest {
|
export interface PluginManifest {
|
||||||
/** 清单文件版本 */
|
/** 清单文件版本 */
|
||||||
manifest_version: number
|
manifest_version: number
|
||||||
|
/** Manifest 声明的插件唯一标识 */
|
||||||
|
id?: string
|
||||||
/** 插件名称 */
|
/** 插件名称 */
|
||||||
name: string
|
name: string
|
||||||
/** 插件版本 */
|
/** 插件版本 */
|
||||||
|
|||||||
@@ -10,4 +10,6 @@ if [ ! -e "$ADAPTER_TARGET" ] && [ -d "$ADAPTER_TEMPLATE" ]; then
|
|||||||
cp -a "$ADAPTER_TEMPLATE" "$ADAPTER_TARGET"
|
cp -a "$ADAPTER_TEMPLATE" "$ADAPTER_TARGET"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
uv pip install --python "/MaiMBot/.venv/bin/python" --upgrade maibot-dashboard
|
||||||
|
|
||||||
exec /MaiMBot/.venv/bin/python bot.py "$@"
|
exec /MaiMBot/.venv/bin/python bot.py "$@"
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ dependencies = [
|
|||||||
"jieba>=0.42.1",
|
"jieba>=0.42.1",
|
||||||
"json-repair>=0.47.6",
|
"json-repair>=0.47.6",
|
||||||
"maim-message>=0.6.2",
|
"maim-message>=0.6.2",
|
||||||
"maibot-dashboard>=1.0.8",
|
"maibot-dashboard>=1.0.10",
|
||||||
"maibot-plugin-sdk>=2.4.0",
|
"maibot-plugin-sdk>=2.4.0",
|
||||||
"matplotlib>=3.10.5",
|
"matplotlib>=3.10.5",
|
||||||
"mcp",
|
"mcp",
|
||||||
|
|||||||
@@ -47,3 +47,17 @@ def test_installed_plugins_only_scan_plugins_dir_and_exclude_a_memorix(client: T
|
|||||||
assert ids == ["test.demo"]
|
assert ids == ["test.demo"]
|
||||||
assert "a-dawn.a-memorix" not in ids
|
assert "a-dawn.a-memorix" not in ids
|
||||||
assert all("/src/plugins/built_in/" not in plugin["path"] for plugin in payload["plugins"])
|
assert all("/src/plugins/built_in/" not in plugin["path"] for plugin in payload["plugins"])
|
||||||
|
|
||||||
|
|
||||||
|
def test_resolve_installed_plugin_path_falls_back_to_manifest_id(client: TestClient):
|
||||||
|
plugin_path = support_module.resolve_installed_plugin_path("test.demo")
|
||||||
|
|
||||||
|
assert plugin_path is not None
|
||||||
|
assert plugin_path.name == "demo_plugin"
|
||||||
|
|
||||||
|
|
||||||
|
def test_resolve_installed_plugin_path_accepts_manifest_id_case_mismatch(client: TestClient):
|
||||||
|
plugin_path = support_module.resolve_installed_plugin_path("Test.Demo")
|
||||||
|
|
||||||
|
assert plugin_path is not None
|
||||||
|
assert plugin_path.name == "demo_plugin"
|
||||||
|
|||||||
@@ -33,4 +33,4 @@ tomlkit>=0.13.3
|
|||||||
typing-extensions
|
typing-extensions
|
||||||
uvicorn>=0.35.0
|
uvicorn>=0.35.0
|
||||||
watchfiles>=1.1.1
|
watchfiles>=1.1.1
|
||||||
maibot-dashboard>=1.0.8
|
maibot-dashboard>=1.0.10
|
||||||
@@ -56,7 +56,7 @@ BOT_CONFIG_PATH: Path = (CONFIG_DIR / "bot_config.toml").resolve().absolute()
|
|||||||
MODEL_CONFIG_PATH: Path = (CONFIG_DIR / "model_config.toml").resolve().absolute()
|
MODEL_CONFIG_PATH: Path = (CONFIG_DIR / "model_config.toml").resolve().absolute()
|
||||||
LEGACY_ENV_PATH: Path = (PROJECT_ROOT / ".env").resolve().absolute()
|
LEGACY_ENV_PATH: Path = (PROJECT_ROOT / ".env").resolve().absolute()
|
||||||
A_MEMORIX_LEGACY_CONFIG_PATH: Path = (CONFIG_DIR / "a_memorix.toml").resolve().absolute()
|
A_MEMORIX_LEGACY_CONFIG_PATH: Path = (CONFIG_DIR / "a_memorix.toml").resolve().absolute()
|
||||||
MMC_VERSION: str = "1.0.0-pre.15"
|
MMC_VERSION: str = "1.0.0-pre.16"
|
||||||
CONFIG_VERSION: str = "8.10.15"
|
CONFIG_VERSION: str = "8.10.15"
|
||||||
MODEL_CONFIG_VERSION: str = "1.16.1"
|
MODEL_CONFIG_VERSION: str = "1.16.1"
|
||||||
|
|
||||||
|
|||||||
@@ -388,7 +388,6 @@ class EmojiManager:
|
|||||||
if existing_record := session.exec(statement).first():
|
if existing_record := session.exec(statement).first():
|
||||||
existing_record.full_path = str(emoji.full_path)
|
existing_record.full_path = str(emoji.full_path)
|
||||||
existing_record.no_file_flag = False
|
existing_record.no_file_flag = False
|
||||||
existing_record.is_banned = False
|
|
||||||
existing_record.last_used_time = datetime.now()
|
existing_record.last_used_time = datetime.now()
|
||||||
existing_record.query_count += 1
|
existing_record.query_count += 1
|
||||||
session.add(existing_record)
|
session.add(existing_record)
|
||||||
@@ -473,7 +472,6 @@ class EmojiManager:
|
|||||||
image_record.full_path = str(new_emoji.full_path)
|
image_record.full_path = str(new_emoji.full_path)
|
||||||
image_record.description = new_emoji.description
|
image_record.description = new_emoji.description
|
||||||
image_record.no_file_flag = False
|
image_record.no_file_flag = False
|
||||||
image_record.is_banned = False
|
|
||||||
session.add(image_record)
|
session.add(image_record)
|
||||||
except Exception as exc:
|
except Exception as exc:
|
||||||
logger.error(f"Update cached emoji description failed: {exc}")
|
logger.error(f"Update cached emoji description failed: {exc}")
|
||||||
@@ -531,6 +529,9 @@ class EmojiManager:
|
|||||||
statement = select(Images).filter_by(image_hash=emoji.file_hash, image_type=ImageType.EMOJI).limit(1)
|
statement = select(Images).filter_by(image_hash=emoji.file_hash, image_type=ImageType.EMOJI).limit(1)
|
||||||
existing_record = session.exec(statement).first()
|
existing_record = session.exec(statement).first()
|
||||||
if existing_record:
|
if existing_record:
|
||||||
|
if existing_record.is_banned:
|
||||||
|
logger.info(f"[register_emoji] Emoji is banned, skipping: {emoji.file_hash}")
|
||||||
|
return "skipped"
|
||||||
if existing_record.is_registered and _is_available_emoji_record(existing_record):
|
if existing_record.is_registered and _is_available_emoji_record(existing_record):
|
||||||
# logger.info(f"[register_emoji] Emoji already registered, skipping: {emoji.file_hash}")
|
# logger.info(f"[register_emoji] Emoji already registered, skipping: {emoji.file_hash}")
|
||||||
return "skipped"
|
return "skipped"
|
||||||
@@ -1085,6 +1086,10 @@ class EmojiManager:
|
|||||||
return "failed"
|
return "failed"
|
||||||
|
|
||||||
if existing_record is not None:
|
if existing_record is not None:
|
||||||
|
if existing_record.is_banned:
|
||||||
|
logger.info(f"[register_emoji] Emoji is banned, skipping: {target_emoji.file_name}")
|
||||||
|
return "skipped"
|
||||||
|
|
||||||
if existing_record.is_registered and _is_available_emoji_record(existing_record):
|
if existing_record.is_registered and _is_available_emoji_record(existing_record):
|
||||||
logger.info(f"[register_emoji] Emoji already registered, skipping: {target_emoji.file_name}")
|
logger.info(f"[register_emoji] Emoji already registered, skipping: {target_emoji.file_name}")
|
||||||
return "skipped"
|
return "skipped"
|
||||||
|
|||||||
@@ -213,7 +213,7 @@ def resolve_installed_plugin_path(plugin_id: str) -> Optional[Path]:
|
|||||||
return _resolve_safe_plugin_directory(new_format_path, plugins_dir, strict=True)
|
return _resolve_safe_plugin_directory(new_format_path, plugins_dir, strict=True)
|
||||||
if old_format_path.exists():
|
if old_format_path.exists():
|
||||||
return _resolve_safe_plugin_directory(old_format_path, plugins_dir, strict=True)
|
return _resolve_safe_plugin_directory(old_format_path, plugins_dir, strict=True)
|
||||||
return None
|
return find_plugin_path_by_id(plugin_id)
|
||||||
|
|
||||||
|
|
||||||
def parse_repository_url(repository_url: str) -> Tuple[str, str, str]:
|
def parse_repository_url(repository_url: str) -> Tuple[str, str, str]:
|
||||||
@@ -256,11 +256,29 @@ def iter_plugin_directories() -> List[Path]:
|
|||||||
|
|
||||||
|
|
||||||
def find_plugin_path_by_id(plugin_id: str) -> Optional[Path]:
|
def find_plugin_path_by_id(plugin_id: str) -> Optional[Path]:
|
||||||
|
casefold_matched_path: Optional[Path] = None
|
||||||
|
normalized_plugin_id = plugin_id.casefold()
|
||||||
|
|
||||||
for plugin_path in iter_plugin_directories():
|
for plugin_path in iter_plugin_directories():
|
||||||
manifest_path = resolve_plugin_file_path(plugin_path, "_manifest.json")
|
manifest_path = resolve_plugin_file_path(plugin_path, "_manifest.json")
|
||||||
manifest = load_manifest_json(manifest_path)
|
manifest = load_manifest_json(manifest_path)
|
||||||
if manifest is not None and (manifest.get("id") == plugin_id or plugin_path.name == plugin_id):
|
if manifest is None:
|
||||||
|
continue
|
||||||
|
|
||||||
|
manifest_id = str(manifest.get("id", ""))
|
||||||
|
if manifest_id == plugin_id or plugin_path.name == plugin_id:
|
||||||
return plugin_path
|
return plugin_path
|
||||||
|
|
||||||
|
if (
|
||||||
|
casefold_matched_path is None
|
||||||
|
and (manifest_id.casefold() == normalized_plugin_id or plugin_path.name.casefold() == normalized_plugin_id)
|
||||||
|
):
|
||||||
|
casefold_matched_path = plugin_path
|
||||||
|
|
||||||
|
if casefold_matched_path is not None:
|
||||||
|
logger.warning(f"插件 ID 大小写不一致,已按大小写不敏感匹配: {plugin_id} -> {casefold_matched_path}")
|
||||||
|
return casefold_matched_path
|
||||||
|
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
8
uv.lock
generated
8
uv.lock
generated
@@ -1511,7 +1511,7 @@ requires-dist = [
|
|||||||
{ name = "httpx", extras = ["socks"] },
|
{ name = "httpx", extras = ["socks"] },
|
||||||
{ name = "jieba", specifier = ">=0.42.1" },
|
{ name = "jieba", specifier = ">=0.42.1" },
|
||||||
{ name = "json-repair", specifier = ">=0.47.6" },
|
{ name = "json-repair", specifier = ">=0.47.6" },
|
||||||
{ name = "maibot-dashboard", specifier = ">=1.0.8" },
|
{ name = "maibot-dashboard", specifier = ">=1.0.9" },
|
||||||
{ name = "maibot-plugin-sdk", specifier = ">=2.4.0" },
|
{ name = "maibot-plugin-sdk", specifier = ">=2.4.0" },
|
||||||
{ name = "maim-message", specifier = ">=0.6.2" },
|
{ name = "maim-message", specifier = ">=0.6.2" },
|
||||||
{ name = "matplotlib", specifier = ">=3.10.5" },
|
{ name = "matplotlib", specifier = ">=3.10.5" },
|
||||||
@@ -1549,11 +1549,11 @@ dev = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "maibot-dashboard"
|
name = "maibot-dashboard"
|
||||||
version = "1.0.8"
|
version = "1.0.9"
|
||||||
source = { registry = "https://pypi.tuna.tsinghua.edu.cn/simple" }
|
source = { registry = "https://pypi.tuna.tsinghua.edu.cn/simple" }
|
||||||
sdist = { url = "https://pypi.tuna.tsinghua.edu.cn/packages/13/9f/e59b1a6299cc4f8c9ac16c7c2774581220fdd27227ac9c2fdfb947dfc2f5/maibot_dashboard-1.0.8.tar.gz", hash = "sha256:a47309072d8154905738d02ccad17a543d5159a1e62ca87076ac4dce39e6c922", size = 2496374, upload-time = "2026-05-07T13:58:39.386Z" }
|
sdist = { url = "https://pypi.tuna.tsinghua.edu.cn/packages/ac/5b/e90896cbdddc89ec5586873de07a3d70c0107e4dc76db8666a0c0fde6ae8/maibot_dashboard-1.0.9.tar.gz", hash = "sha256:0e5c00be021419686105238cded501024f0383a3815bd85f9a1e747f3f04d0cd", size = 2496957, upload-time = "2026-05-07T18:37:51.291Z" }
|
||||||
wheels = [
|
wheels = [
|
||||||
{ url = "https://pypi.tuna.tsinghua.edu.cn/packages/0f/60/fde671bf332133f1403673096eefcd49f36133141a6b9229e72c2588b221/maibot_dashboard-1.0.8-py3-none-any.whl", hash = "sha256:39da973fed56f1491245109615d81ea79add859467798af92d4ace7d8a5d7557", size = 2563243, upload-time = "2026-05-07T13:58:37.868Z" },
|
{ url = "https://pypi.tuna.tsinghua.edu.cn/packages/8c/27/ab227a84e55356039004a375e78031e5e8aaf4192e11908a568498816d5e/maibot_dashboard-1.0.9-py3-none-any.whl", hash = "sha256:197b26c5c3d0e6ba1238b91d12c88e57db71c65303cc602fcccdca84ce4db582", size = 2563281, upload-time = "2026-05-07T18:37:49.648Z" },
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
|||||||
Reference in New Issue
Block a user