diff --git a/package/package.json b/package/package.json deleted file mode 100644 index 3780b4c8..00000000 --- a/package/package.json +++ /dev/null @@ -1,24 +0,0 @@ -{ - "name": "napcat-types", - "version": "0.0.1", - "type": "module", - "types": "./napcat-types/index.d.ts", - "files": [ - "**/*" - ], - "dependencies": { - "@types/node": "^22.10.7", - "@types/express": "^4.17.21", - "@types/ws": "^8.5.12", - "@types/cors": "^2.8.17", - "@types/multer": "^1.4.12", - "@types/winston": "^2.4.4", - "@types/yaml": "^1.9.7", - "@types/ip": "^1.1.3" - }, - "publishConfig": { - "registry": "https://registry.npmjs.org/", - "access": "public", - "tag": "latest" - } -} \ No newline at end of file diff --git a/packages/napcat-onebot/network/plugin-manger.ts b/packages/napcat-onebot/network/plugin-manger.ts index a83d4ee7..99a26ef3 100644 --- a/packages/napcat-onebot/network/plugin-manger.ts +++ b/packages/napcat-onebot/network/plugin-manger.ts @@ -88,6 +88,7 @@ export interface PluginModule { } const plugin: LoadedPlugin = { - name: pluginId, // Use Directory Name as Internal Plugin Name/ID + name: packageJson?.name || pluginId, // Use package.json name for API lookups, fallback to dir name + dirname: pluginId, // Keep track of actual directory name for path resolution version: packageJson?.version, pluginPath: pluginDir, entryPath, @@ -325,15 +327,15 @@ export class OB11PluginMangerAdapter extends IOB11NetworkAdapter { } // Create Context - const id = plugin.name; // directory name as ID - const dataPath = path.join(this.pluginPath, id, 'data'); + // Use dirname for path resolution, name for identification + const dataPath = path.join(this.pluginPath, plugin.dirname, 'data'); const configPath = path.join(dataPath, 'config.json'); const context: NapCatPluginContext = { core: this.core, oneBot: this.obContext, actions: this.actions, - pluginName: id, + pluginName: plugin.name, // Use package name for identification pluginPath: plugin.pluginPath, dataPath: dataPath, configPath: configPath, @@ -404,20 +406,18 @@ export class OB11PluginMangerAdapter extends IOB11NetworkAdapter { } public setPluginStatus (pluginName: string, enable: boolean): void { + // Try to find plugin by package name first + const plugin = this.loadedPlugins.get(pluginName); + // Use dirname for config storage (if plugin is loaded), otherwise assume pluginName is dirname + const configKey = plugin?.dirname || pluginName; + const config = this.loadPluginConfig(); - config[pluginName] = enable; + config[configKey] = enable; this.savePluginConfig(config); - if (!enable) { - for (const [_, loaded] of this.loadedPlugins.entries()) { - const dirOrFile = path.basename(loaded.pluginPath === this.pluginPath ? loaded.entryPath : loaded.pluginPath); - const ext = path.extname(dirOrFile); - const simpleName = ext ? path.parse(dirOrFile).name : dirOrFile; - - if (pluginName === simpleName) { - this.unloadPlugin(loaded.name).catch(e => this.logger.logError('Error unloading', e)); - } - } + if (!enable && plugin) { + // Unload by plugin.name (package name, which is the key in loadedPlugins) + this.unloadPlugin(plugin.name).catch(e => this.logger.logError('Error unloading', e)); } } @@ -539,13 +539,14 @@ export class OB11PluginMangerAdapter extends IOB11NetworkAdapter { return false; } + const dirname = plugin.dirname; + try { // 卸载插件 await this.unloadPlugin(pluginName); - // 重新加载插件 - // We assume pluginName IS the directory name (the ID) - await this.loadDirectoryPlugin(pluginName); + // 重新加载插件 - use dirname for directory loading + await this.loadDirectoryPlugin(dirname); this.logger.log( `[Plugin Adapter] Plugin ${pluginName} reloaded successfully` @@ -560,7 +561,10 @@ export class OB11PluginMangerAdapter extends IOB11NetworkAdapter { } } public getPluginDataPath (pluginName: string): string { - return path.join(this.pluginPath, pluginName, 'data'); + // Lookup plugin by name (package name) and use dirname for path + const plugin = this.loadedPlugins.get(pluginName); + const dirname = plugin?.dirname || pluginName; // fallback to pluginName if not found + return path.join(this.pluginPath, dirname, 'data'); } public getPluginConfigPath (pluginName: string): string { diff --git a/packages/napcat-plugin-builtin/index.ts b/packages/napcat-plugin-builtin/index.ts index 82e973de..35c21fd3 100644 --- a/packages/napcat-plugin-builtin/index.ts +++ b/packages/napcat-plugin-builtin/index.ts @@ -97,7 +97,7 @@ const plugin_onmessage: PluginModule['plugin_onmessage'] = async (_ctx, event) = console.log('[Plugin: builtin] 已回复版本信息'); } catch (error) { - console.error('[Plugin: builtin] 处理消息时发生错误:', error); + console.log('[Plugin: builtin] 处理消息时发生错误:', error); } }; @@ -150,7 +150,7 @@ async function sendMessage (actions: ActionMap, event: OB11Message, message: str try { await actions.call('send_msg', params, adapter, config); } catch (error) { - console.error('[Plugin: builtin] 发送消息失败:', error); + console.log('[Plugin: builtin] 发送消息失败:', error); } } diff --git a/packages/napcat-webui-backend/src/api/Plugin.ts b/packages/napcat-webui-backend/src/api/Plugin.ts index 221dd703..653855fe 100644 --- a/packages/napcat-webui-backend/src/api/Plugin.ts +++ b/packages/napcat-webui-backend/src/api/Plugin.ts @@ -33,21 +33,19 @@ export const GetPluginListHandler: RequestHandler = async (_req, res) => { // 1. 整理已加载的插件 for (const p of loadedPlugins) { - // 计算 ID:需要回溯到加载时的入口信息 - // 对于已加载的插件,我们通过判断 pluginPath 是否等于根 pluginPath 来判断它是单文件还是目录 - const isFilePlugin = p.pluginPath === pluginManager.getPluginPath(); - const fsName = isFilePlugin ? path.basename(p.entryPath) : path.basename(p.pluginPath); - const id = getPluginId(fsName, isFilePlugin); + // Use dirname for map key (matches filesystem scan) + const id = p.dirname; + const fsName = p.dirname; // dirname is the actual filesystem directory name loadedPluginMap.set(id, { - name: p.packageJson?.name || p.name, // 优先使用 package.json 的 name + name: p.name, // This is now package name (from packageJson.name || dirname) id: id, version: p.version || '0.0.0', description: p.packageJson?.description || '', author: p.packageJson?.author || '', status: 'active', filename: fsName, // 真实文件/目录名 - loadedName: p.name, // 运行时注册的名称,用于重载/卸载 + loadedName: p.name, // 运行时注册的名称,用于重载/卸载 (package name) hasConfig: !!(p.module.plugin_config_schema || p.module.plugin_config_ui) }); } @@ -121,40 +119,40 @@ export const GetPluginListHandler: RequestHandler = async (_req, res) => { // ReloadPluginHandler removed export const SetPluginStatusHandler: RequestHandler = async (req, res) => { - const { enable, filename } = req.body; - // We Use filename / id to control config - // Front-end should pass the 'filename' or 'id' as the key identifier + const { enable, filename, name } = req.body; + // filename is the directory name (used for fs checks) + // name is the package name (used for plugin manager API, if provided) + // We need to determine: which to use for setPluginStatus call - if (!filename) return sendError(res, 'Plugin Filename/ID is required'); + if (!filename && !name) return sendError(res, 'Plugin Filename or Name is required'); const pluginManager = getPluginManager(); if (!pluginManager) { return sendError(res, 'Plugin Manager not found'); } - // ID IS the filename (directory name) now - const id = filename; + // Determine which ID to use + // If 'name' (package name) is provided, use it for pluginManager calls + // But 'filename' (dirname) is needed for filesystem operations + const dirname = filename || name; // fallback + const pluginName = name || filename; // fallback try { - pluginManager.setPluginStatus(id, enable); + // setPluginStatus now handles both package name and dirname lookup internally + pluginManager.setPluginStatus(pluginName, enable); // If enabling, trigger load if (enable) { const pluginPath = pluginManager.getPluginPath(); - const fullPath = path.join(pluginPath, filename); + const fullPath = path.join(pluginPath, dirname); if (fs.existsSync(fullPath) && fs.statSync(fullPath).isDirectory()) { - await pluginManager.loadDirectoryPlugin(filename); + await pluginManager.loadDirectoryPlugin(dirname); } else { - return sendError(res, 'Plugin directory not found: ' + filename); + return sendError(res, 'Plugin directory not found: ' + dirname); } - } else { - // Disabling behavior is managed by setPluginStatus which updates config - // If we want to unload immediately? - // The config update will prevent load on next startup. - // Does pluginManager.setPluginStatus unload it? - // Inspecting pluginManager.setPluginStatus... it iterates and unloads if match found. } + // Disabling is handled by setPluginStatus return sendSuccess(res, { message: 'Status updated successfully' }); } catch (e: any) {