forked from farhoodlabs/paperclip
Auto-reinstall adapter packages missing from disk on reload and boot
Adapters installed with the old --no-save flag are not tracked in package.json and get pruned when another adapter is installed. This adds ensurePackageOnDisk() which detects missing packages and reinstalls them from npm before reload or server boot attempts to import them, fixing ENOENT errors for previously-pruned adapters. Fixes FAR-47 Co-Authored-By: Paperclip <noreply@paperclip.ing>
This commit is contained in:
@@ -9,11 +9,15 @@
|
||||
* adapter-utils, never registry.ts.
|
||||
*/
|
||||
|
||||
import { execFile } from "node:child_process";
|
||||
import fs from "node:fs";
|
||||
import path from "node:path";
|
||||
import { promisify } from "node:util";
|
||||
import type { ServerAdapterModule } from "./types.js";
|
||||
import { logger } from "../middleware/logger.js";
|
||||
|
||||
const execFileAsync = promisify(execFile);
|
||||
|
||||
import {
|
||||
listAdapterPlugins,
|
||||
getAdapterPluginsDir,
|
||||
@@ -187,8 +191,37 @@ export async function loadExternalAdapterPackage(
|
||||
return adapterModule;
|
||||
}
|
||||
|
||||
/**
|
||||
* Ensure an npm-sourced adapter package exists on disk.
|
||||
* If the package directory is missing (e.g. pruned by a prior --no-save install),
|
||||
* reinstall it from the registry so reload/boot can proceed.
|
||||
*/
|
||||
async function ensurePackageOnDisk(record: AdapterPluginRecord): Promise<void> {
|
||||
if (record.localPath) return; // local-path adapters are managed externally
|
||||
|
||||
const packageDir = resolvePackageDir(record);
|
||||
const pkgJsonPath = path.join(packageDir, "package.json");
|
||||
if (fs.existsSync(pkgJsonPath)) return; // already on disk
|
||||
|
||||
const pluginsDir = getAdapterPluginsDir();
|
||||
const spec = record.version
|
||||
? `${record.packageName}@${record.version}`
|
||||
: record.packageName;
|
||||
|
||||
logger.info(
|
||||
{ packageName: record.packageName, type: record.type, spec },
|
||||
"Adapter package missing from disk — reinstalling from npm",
|
||||
);
|
||||
|
||||
await execFileAsync("npm", ["install", spec], {
|
||||
cwd: pluginsDir,
|
||||
timeout: 120_000,
|
||||
});
|
||||
}
|
||||
|
||||
async function loadFromRecord(record: AdapterPluginRecord): Promise<ServerAdapterModule | null> {
|
||||
try {
|
||||
await ensurePackageOnDisk(record);
|
||||
return await loadExternalAdapterPackage(record.packageName, record.localPath);
|
||||
} catch (err) {
|
||||
logger.warn(
|
||||
@@ -209,6 +242,8 @@ export async function reloadExternalAdapter(
|
||||
const record = getAdapterPluginByType(type);
|
||||
if (!record) return null;
|
||||
|
||||
await ensurePackageOnDisk(record);
|
||||
|
||||
const packageDir = resolvePackageDir(record);
|
||||
const entryPoint = resolvePackageEntryPoint(packageDir);
|
||||
const modulePath = path.resolve(packageDir, entryPoint);
|
||||
|
||||
Reference in New Issue
Block a user