tlnt
Version:
TLNT - HMS-Powered Multi-Agent Platform with Government Agency Analysis, Deep Research, and Enterprise-Ready Deployment. Self-optimizing multi-domain AI agent with continuous learning and enterprise-grade performance monitoring.
168 lines • 5.8 kB
JavaScript
import { readdir, stat } from 'fs/promises';
import { resolve, join } from 'path';
import { pathToFileURL } from 'url';
import { homedir } from 'os';
export class PluginLoader {
agentHub;
loadedPlugins = new Map();
pluginPaths = [];
constructor(agentHub) {
this.agentHub = agentHub;
this.setupPluginPaths();
}
setupPluginPaths() {
this.pluginPaths = [
resolve(homedir(), '.tlnt', 'plugins'),
resolve(process.cwd(), '.tlnt', 'plugins'),
];
}
async loadPlugins() {
for (const pluginPath of this.pluginPaths) {
try {
await this.loadPluginsFromDirectory(pluginPath);
}
catch (error) {
continue;
}
}
await this.loadNpmPlugins();
}
async loadPluginsFromDirectory(pluginDir) {
try {
const entries = await readdir(pluginDir);
for (const entry of entries) {
const entryPath = join(pluginDir, entry);
const stats = await stat(entryPath);
if (stats.isDirectory()) {
await this.loadPluginFromPath(entryPath);
}
else if (entry.endsWith('.js') || entry.endsWith('.ts')) {
await this.loadPluginFromFile(entryPath);
}
}
}
catch (error) {
// Directory doesn't exist or can't be read
}
}
async loadPluginFromPath(pluginPath) {
const possibleFiles = ['index.js', 'index.ts', 'plugin.js', 'plugin.ts'];
for (const file of possibleFiles) {
const filePath = join(pluginPath, file);
try {
await stat(filePath);
await this.loadPluginFromFile(filePath);
return;
}
catch {
continue;
}
}
}
async loadPluginFromFile(filePath) {
try {
const fileUrl = pathToFileURL(filePath).href;
const module = await import(fileUrl);
let plugin;
if (typeof module.default === 'function') {
const pluginId = this.getPluginIdFromPath(filePath);
plugin = {
id: pluginId,
name: pluginId,
version: '1.0.0',
setup: module.default
};
}
else if (module.default && typeof module.default.setup === 'function') {
plugin = module.default;
}
else {
console.warn(`Plugin at ${filePath} does not export a valid plugin`);
return;
}
await this.loadPlugin(plugin);
}
catch (error) {
console.error(`Failed to load plugin from ${filePath}:`, error);
}
}
async loadNpmPlugins() {
try {
const nodeModulesPath = resolve(process.cwd(), 'node_modules');
const entries = await readdir(nodeModulesPath);
for (const entry of entries) {
if (entry.startsWith('tlnt-plugin-')) {
await this.loadNpmPlugin(entry);
}
}
}
catch (error) {
// node_modules doesn't exist or can't be read
}
}
async loadNpmPlugin(packageName) {
try {
const packageJsonPath = resolve(process.cwd(), 'node_modules', packageName, 'package.json');
const packageJson = JSON.parse(await import('fs').then(fs => fs.readFileSync(packageJsonPath, 'utf-8')));
let pluginPath;
if (packageJson.plugin) {
pluginPath = resolve(process.cwd(), 'node_modules', packageName, packageJson.plugin);
}
else if (packageJson.main) {
pluginPath = resolve(process.cwd(), 'node_modules', packageName, packageJson.main);
}
else {
pluginPath = resolve(process.cwd(), 'node_modules', packageName, 'index.js');
}
await this.loadPluginFromFile(pluginPath);
}
catch (error) {
console.error(`Failed to load npm plugin ${packageName}:`, error);
}
}
async loadPlugin(plugin) {
if (this.loadedPlugins.has(plugin.id)) {
console.warn(`Plugin ${plugin.id} is already loaded`);
return;
}
try {
await plugin.setup(this.agentHub);
this.loadedPlugins.set(plugin.id, plugin);
console.log(`Loaded plugin: ${plugin.name} v${plugin.version}`);
}
catch (error) {
console.error(`Failed to setup plugin ${plugin.id}:`, error);
}
}
async unloadPlugin(pluginId) {
const plugin = this.loadedPlugins.get(pluginId);
if (!plugin) {
throw new Error(`Plugin ${pluginId} is not loaded`);
}
if (plugin.teardown) {
try {
await plugin.teardown();
}
catch (error) {
console.error(`Error during plugin ${pluginId} teardown:`, error);
}
}
this.loadedPlugins.delete(pluginId);
}
async reloadPlugin(pluginId) {
await this.unloadPlugin(pluginId);
await this.loadPlugins();
}
listPlugins() {
return Array.from(this.loadedPlugins.values());
}
getPlugin(pluginId) {
return this.loadedPlugins.get(pluginId);
}
getPluginIdFromPath(filePath) {
const parts = filePath.split(/[/\\]/);
const fileName = parts[parts.length - 1];
return fileName.replace(/\.(js|ts)$/, '');
}
}
//# sourceMappingURL=pluginLoader.js.map