/**
 * PluginLoader — discovery, installation, and runtime activation of plugins.
 *
 * This service is the entry point for the plugin system's I/O boundary:
 *
 * 1. **Discovery** — Scans the local plugin directory
 *    (`~/.rudder/plugins/`) and `node_modules` for packages matching
 *    the `rudder-plugin-*` naming convention. Aggregates results with
 *    path-based deduplication.
 *
 * 2. **Installation** — `installPlugin()` downloads from npm (or reads a
 *    local path), validates the manifest, checks capability consistency,
 *    and persists the install record.
 *
 * 3. **Runtime activation** — `activatePlugin()` wires up a loaded plugin
 *    with all runtime services: resolves its entrypoint, builds
 *    capability-gated host handlers, spawns a worker process, syncs job
 *    declarations, registers event subscriptions, and discovers tools.
 *
 * 4. **Shutdown** — `shutdownAll()` gracefully stops all active workers
 *    and unregisters runtime hooks.
 *
 * @see PLUGIN_SPEC.md §8 — Plugin Discovery
 * @see PLUGIN_SPEC.md §10 — Package Contract
 * @see PLUGIN_SPEC.md §12 — Process Model
 */
import { existsSync } from "node:fs";
import path from "node:path";
export function resolveWorkerEntrypoint(plugin, localPluginDir) {
    const manifest = plugin.manifestJson;
    const workerRelPath = manifest.entrypoints.worker;
    // For local-path installs we persist the resolved package path; use it first
    if (plugin.packagePath && existsSync(plugin.packagePath)) {
        const entrypoint = path.resolve(plugin.packagePath, workerRelPath);
        if (entrypoint.startsWith(path.resolve(plugin.packagePath)) && existsSync(entrypoint)) {
            return entrypoint;
        }
    }
    // Try the local plugin directory (standard npm install location)
    const packageName = plugin.packageName;
    let packageDir;
    if (packageName.startsWith("@")) {
        // Scoped package: @scope/plugin-name → localPluginDir/node_modules/@scope/plugin-name
        const [scope, name] = packageName.split("/");
        packageDir = path.join(localPluginDir, "node_modules", scope, name);
    }
    else {
        packageDir = path.join(localPluginDir, "node_modules", packageName);
    }
    // Also check if the package exists directly under localPluginDir
    // (for direct local-path installs or symlinked packages)
    const directDir = path.join(localPluginDir, packageName);
    // Try in order: node_modules path, direct path
    for (const dir of [packageDir, directDir]) {
        const entrypoint = path.resolve(dir, workerRelPath);
        // Security: ensure entrypoint is actually inside the directory (prevent path traversal)
        if (!entrypoint.startsWith(path.resolve(dir))) {
            continue;
        }
        if (existsSync(entrypoint)) {
            return entrypoint;
        }
    }
    // Fallback: try the worker path as-is (absolute or relative to cwd)
    // ONLY if it's already an absolute path and we trust the manifest (which we've already validated)
    if (path.isAbsolute(workerRelPath) && existsSync(workerRelPath)) {
        return workerRelPath;
    }
    throw new Error(`Worker entrypoint not found for plugin "${plugin.pluginKey}". ` +
        `Checked: ${path.resolve(packageDir, workerRelPath)}, ` +
        `${path.resolve(directDir, workerRelPath)}`);
}
export function resolveManagedInstallPackageDir(localPluginDir, packageName) {
    if (packageName.startsWith("@")) {
        return path.join(localPluginDir, "node_modules", ...packageName.split("/"));
    }
    return path.join(localPluginDir, "node_modules", packageName);
}
export function isPathInsideDir(candidatePath, parentDir) {
    const resolvedCandidate = path.resolve(candidatePath);
    const resolvedParent = path.resolve(parentDir);
    const relative = path.relative(resolvedParent, resolvedCandidate);
    return relative === "" || (!relative.startsWith("..") && !path.isAbsolute(relative));
}
//# sourceMappingURL=plugin-loader.worker-paths.js.map