mirror of
https://github.com/paperclipai/paperclip.git
synced 2026-10-22 00:30:19 +02:00
Fix plugin SDK worker entrypoint symlink check
Co-Authored-By: Paperclip <noreply@paperclip.ing>
This commit is contained in:
1 parent
6a6a69e5c3
commit
047bb2940f
5 files changed
+84
-3
No files matched your search
@@ -34,6 +34,7 @@
|
||||
* @see PLUGIN_SPEC.md §14 — SDK Surface
|
||||
*/
|
||||
|
||||
import fs from "node:fs";
|
||||
import path from "node:path";
|
||||
import { createInterface, type Interface as ReadlineInterface } from "node:readline";
|
||||
import { fileURLToPath } from "node:url";
|
||||
@@ -175,6 +176,21 @@ interface EventRegistration {
|
||||
/** Default timeout for worker→host RPC calls. */
|
||||
const DEFAULT_RPC_TIMEOUT_MS = 30_000;
|
||||
|
||||
function realpathOrResolvedPath(filePath: string): string {
|
||||
const resolvedPath = path.resolve(filePath);
|
||||
try {
|
||||
return fs.realpathSync.native(resolvedPath);
|
||||
} catch {
|
||||
return resolvedPath;
|
||||
}
|
||||
}
|
||||
|
||||
export function isWorkerEntrypoint(entry: string, moduleUrl: string): boolean {
|
||||
const thisFile = realpathOrResolvedPath(fileURLToPath(moduleUrl));
|
||||
const entryPath = realpathOrResolvedPath(entry);
|
||||
return thisFile === entryPath;
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// startWorkerRpcHost
|
||||
// ---------------------------------------------------------------------------
|
||||
@@ -223,9 +239,7 @@ export function runWorker(
|
||||
}
|
||||
const entry = process.argv[1];
|
||||
if (typeof entry !== "string") return;
|
||||
const thisFile = path.resolve(fileURLToPath(moduleUrl));
|
||||
const entryPath = path.resolve(entry);
|
||||
if (thisFile === entryPath) {
|
||||
if (isWorkerEntrypoint(entry, moduleUrl)) {
|
||||
startWorkerRpcHost({ plugin });
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,57 @@
|
||||
import fs from "node:fs";
|
||||
import os from "node:os";
|
||||
import path from "node:path";
|
||||
import { pathToFileURL } from "node:url";
|
||||
|
||||
import { afterEach, describe, expect, it } from "vitest";
|
||||
|
||||
import { isWorkerEntrypoint } from "../src/worker-rpc-host.js";
|
||||
|
||||
describe("isWorkerEntrypoint", () => {
|
||||
const tempRoots: string[] = [];
|
||||
|
||||
afterEach(() => {
|
||||
for (const tempRoot of tempRoots.splice(0)) {
|
||||
fs.rmSync(tempRoot, { recursive: true, force: true });
|
||||
}
|
||||
});
|
||||
|
||||
function createTempRoot(): string {
|
||||
const tempRoot = fs.mkdtempSync(path.join(os.tmpdir(), "paperclip-sdk-worker-"));
|
||||
tempRoots.push(tempRoot);
|
||||
return tempRoot;
|
||||
}
|
||||
|
||||
it("matches an entrypoint reached through a symlinked directory", () => {
|
||||
const tempRoot = createTempRoot();
|
||||
const realDir = path.join(tempRoot, "real");
|
||||
const linkDir = path.join(tempRoot, "link");
|
||||
fs.mkdirSync(realDir);
|
||||
fs.symlinkSync(realDir, linkDir, "dir");
|
||||
|
||||
const workerPath = path.join(realDir, "worker.js");
|
||||
fs.writeFileSync(workerPath, "");
|
||||
|
||||
expect(
|
||||
isWorkerEntrypoint(
|
||||
path.join(linkDir, "worker.js"),
|
||||
pathToFileURL(workerPath).toString(),
|
||||
),
|
||||
).toBe(true);
|
||||
});
|
||||
|
||||
it("does not match a different entrypoint", () => {
|
||||
const tempRoot = createTempRoot();
|
||||
const workerPath = path.join(tempRoot, "worker.js");
|
||||
const otherPath = path.join(tempRoot, "other.js");
|
||||
fs.writeFileSync(workerPath, "");
|
||||
fs.writeFileSync(otherPath, "");
|
||||
|
||||
expect(
|
||||
isWorkerEntrypoint(
|
||||
otherPath,
|
||||
pathToFileURL(workerPath).toString(),
|
||||
),
|
||||
).toBe(false);
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,8 @@
|
||||
import { defineConfig } from "vitest/config";
|
||||
|
||||
export default defineConfig({
|
||||
test: {
|
||||
environment: "node",
|
||||
include: ["tests/**/*.test.ts"],
|
||||
},
|
||||
});
|
||||
@@ -14,6 +14,7 @@ const nonServerProjects = [
|
||||
"@paperclipai/adapter-acpx-local",
|
||||
"@paperclipai/adapter-codex-local",
|
||||
"@paperclipai/adapter-opencode-local",
|
||||
"@paperclipai/plugin-sdk",
|
||||
"@paperclipai/ui",
|
||||
"paperclipai",
|
||||
];
|
||||
|
||||
@@ -14,6 +14,7 @@ export default defineConfig({
|
||||
"packages/adapters/gemini-local",
|
||||
"packages/adapters/opencode-local",
|
||||
"packages/adapters/pi-local",
|
||||
"packages/plugins/sdk",
|
||||
"server",
|
||||
"ui",
|
||||
"cli",
|
||||
|
||||
Reference in new issue
Block a user