From 4d8b74a0b90da94d18cd4449afb7e5644c4bef14 Mon Sep 17 00:00:00 2001 From: Odilitime Date: Sat, 1 Mar 2025 20:43:29 -0800 Subject: [PATCH] fix: CLI handle plugin dependencies / trusdb (#3737) * lower logging * add json5 * bump lockfile for json5 * allow Plugin to store actual npm name * allow character file to be json5, adjust logging, handle improper/failed to load plugins better * remove wrongly added plugin * properly handle paths with spaces * audit fix * bump turbo * don't await on async returns, note * attempt ci typing fix * try what claude says to fix CI * try what claude says to fix CI * try what claude says to fix CI * claude ci fix * go back to any * cursor attempt * cursor attempt * clean up output * sync with the other concurrent build better * sync lockfile * pnpm (biome) format, mainly import type tweaks * favor local paths for consistency * move vitest * remove tsup/readline/ws, include @jest/globals because useESM is true in jest config * move tsup to dev deps * bump lockfile * handle dependencies/handle trustdb --- packages/cli/index.js | 116 +++++++++++++++++++++++++++++++----------- 1 file changed, 86 insertions(+), 30 deletions(-) diff --git a/packages/cli/index.js b/packages/cli/index.js index c240ee2940c..9b001064b18 100755 --- a/packages/cli/index.js +++ b/packages/cli/index.js @@ -79,40 +79,88 @@ pluginsCmd // ensure prefix const pluginName = '@elizaos-plugins/' + plugin.replace(/^@elizaos-plugins\//, '') + const namePart = pluginName.replace(/^@elizaos-plugins\//, '') + const elizaOSroot = pathUtil.resolve(__dirname, '../..') - const repoData = plugins[pluginName]?.split(':') - if (!repoData) { - console.error('Plugin', plugin, 'not found') - return - } - // repo type - if (repoData[0] !== 'github') { - console.error('Plugin', plugin, 'uses', repoData[0], ' but this utility currently only support github') - return + let repo = '' + if (namePart === 'plugin-trustdb') { + repo = 'elizaos-plugins/plugin-trustdb' + } else { + const repoData = plugins[pluginName]?.split(':') + if (!repoData) { + console.error('Plugin', plugin, 'not found') + return + } + // repo type + if (repoData[0] !== 'github') { + console.error('Plugin', plugin, 'uses', repoData[0], ' but this utility only currently support github') + return + } + repo = repoData[1] } - const parts = repoData[1].split('/') - const elizaOSroot = pathUtil.resolve(__dirname, '../..') - const pkgPath = elizaOSroot + '/packages/' + parts[1] + const pkgPath = elizaOSroot + '/packages/' + namePart // add to packages - if (!fs.existsSync(pkgPath)) { + if (!fs.existsSync(pkgPath + '/package.json')) { // clone it - console.log('cloning', parts[1], 'to', pkgPath) - const gitOutput = execSync('git clone https://github.com/' + repoData[1] + ' "' + pkgPath + '"', { stdio: 'pipe' }).toString().trim(); + console.log('cloning', namePart, 'to', pkgPath) + const gitOutput = execSync('git clone https://github.com/' + repo + ' "' + pkgPath + '"', { stdio: 'pipe' }).toString().trim(); + // submodule init & update? } - // add core to plugin - // # pnpm add @elizaos/core@workspace:* --filter ./packages/client-twitter - console.log('Making sure plugin has access to @elizaos/core') - const pluginAddCoreOutput = execSync('pnpm add @elizaos/core@workspace:* --filter ./packages/' + parts[1], { cwd: elizaOSroot, stdio: 'pipe' }).toString().trim(); + // we need to check for dependencies // Read the current package.json const packageJsonPath = pkgPath + '/package.json' const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, 'utf-8')) - if (packageJson.name !== '@elizaos-plugins/' + parts[1]) { + const updateDependencies = (deps) => { + if (!deps) return false + let changed = false + const okPackages = ['@elizaos/client-direct', '@elizaos/core', '@elizaos/plugin-bootstrap'] + for (const dep in deps) { + if (okPackages.indexOf(dep) !== -1) continue // skip these, they're fine + // do we want/need to perserve local packages like core? + if (dep.startsWith("@elizaos/")) { + const newDep = dep.replace("@elizaos/", "@elizaos-plugins/") + deps[newDep] = deps[dep] + delete deps[dep] + changed = true + } + } + return changed + } + + // normalize @elizaos => @elizaos-plugins + if (updateDependencies(packageJson.dependencies)) { + console.log('updating plugin\'s package.json to not use @elizos/ for dependencies') + fs.writeFileSync(packageJsonPath, JSON.stringify(packageJson, null, 2) + "\n") + // I don't think will cause the lockfile from getting out of date + } + //console.log('packageJson', packageJson.dependencies) + for(const d in packageJson.dependencies) { + if (d.match(/@elizaos-plugins/)) { + // do we have this plugin? + console.log('attempting installation of dependency', d) + try { + const pluginAddDepOutput = execSync('npx elizaos plugins add ' + d, { cwd: elizaOSroot, stdio: 'pipe' }).toString().trim(); + //console.log('pluginAddDepOutput', pluginAddDepOutput) + } catch (e) { + console.error('pluginAddDepOutput error', e) + } + } + } + + // add core to plugin + // # pnpm add @elizaos/core@workspace:* --filter ./packages/client-twitter + + // ok this can be an issue if it's referencing a plugin it couldn't be + console.log('Making sure plugin has access to @elizaos/core') + const pluginAddCoreOutput = execSync('pnpm add @elizaos/core@workspace:* --filter ./packages/' + namePart, { cwd: elizaOSroot, stdio: 'pipe' }).toString().trim(); + + if (packageJson.name !== '@elizaos-plugins/' + namePart) { // Update the name field - packageJson.name = '@elizaos-plugins/' + parts[1] + packageJson.name = '@elizaos-plugins/' + namePart console.log('Updating plugins package.json name to', packageJson.name) // Write the updated package.json back to disk @@ -148,20 +196,28 @@ pluginsCmd .action(async (plugin, opts) => { // ensure prefix const pluginName = '@elizaos-plugins/' + plugin.replace(/^@elizaos-plugins\//, '') + const namePart = pluginName.replace(/^@elizaos-plugins\//, '') + const elizaOSroot = pathUtil.resolve(__dirname, '../..') + const pkgPath = elizaOSroot + '/packages/' + namePart const plugins = await getPlugins() - //console.log('loaded', plugins.length, plugins) - const repoData = plugins[pluginName]?.split(':') - if (!repoData) { - console.error('Plugin', pluginName, 'not found') - return + + let repo = '' + if (namePart === 'plugin-trustdb') { + repo = 'elizaos-plugins/plugin-trustdb' + } else { + //console.log('loaded', plugins.length, plugins) + const repoData = plugins[pluginName]?.split(':') + if (!repoData) { + console.error('Plugin', pluginName, 'not found') + return + } + const parts = repoData[1].split('/') + repo = parts[1] } - const parts = repoData[1].split('/') - const elizaOSroot = pathUtil.resolve(__dirname, '../..') - const pkgPath = elizaOSroot + '/packages/' + parts[1] // remove from agent: pnpm remove some-plugin --filter ./agent try { - console.log('Removing plugin from agent') + console.log('Removing', pluginName, 'from agent') const pluginRemoveAgentOutput = execSync('pnpm remove ' + pluginName + ' --filter ./agent', { cwd: elizaOSroot, stdio: 'pipe' }).toString().trim(); } catch (e) { console.error('removal from agent, error', e)