


























@@ -4,9 +4,44 @@ import path from "node:path";
4455const command = process.argv[2];
66const scratchRoot = process.env.OPENCLAW_PLUGINS_TMP_DIR || os.tmpdir();
7+const CLAWHUB_PREFLIGHT_TIMEOUT_MS = readPositiveInt(
8+process.env.OPENCLAW_PLUGINS_E2E_CLAWHUB_PREFLIGHT_TIMEOUT_MS,
9+30_000,
10+);
711const readJson = (file) => JSON.parse(fs.readFileSync(file, "utf8"));
812const scratchFile = (name) => path.join(scratchRoot, name);
91314+function readPositiveInt(raw, fallback) {
15+const parsed = Number.parseInt(String(raw || ""), 10);
16+return Number.isInteger(parsed) && parsed > 0 ? parsed : fallback;
17+}
18+19+function createTimeoutError(label, timeoutMs) {
20+const error = new Error(`${label} timed out after ${timeoutMs}ms`);
21+error.code = "ETIMEDOUT";
22+return error;
23+}
24+25+async function withTimeout(label, timeoutMs, run) {
26+const controller = new AbortController();
27+const timeoutError = createTimeoutError(label, timeoutMs);
28+let timeout;
29+const timeoutPromise = new Promise((_, reject) => {
30+timeout = setTimeout(() => {
31+controller.abort(timeoutError);
32+reject(timeoutError);
33+}, timeoutMs);
34+timeout.unref?.();
35+});
36+try {
37+return await Promise.race([run(controller.signal), timeoutPromise]);
38+} finally {
39+if (timeout) {
40+clearTimeout(timeout);
41+}
42+}
43+}
44+1045function resolveHomePath(value) {
1146if (value === "~") {
1247return process.env.HOME;
@@ -420,12 +455,18 @@ function assertGitPlugin() {
420455}
421456assertRealPathInside(installPath, dependencyPackagePath, "git plugin installed dependency");
422457fs.writeFileSync(scratchFile("plugins-git-install-path.txt"), installPath, "utf8");
423-fs.writeFileSync(scratchFile("plugins-git-install-parent.txt"), path.dirname(installPath), "utf8");
458+fs.writeFileSync(
459+scratchFile("plugins-git-install-parent.txt"),
460+path.dirname(installPath),
461+"utf8",
462+);
424463}
425464426465function assertGitPluginRemoved() {
427466const installPath = fs.readFileSync(scratchFile("plugins-git-install-path.txt"), "utf8").trim();
428-const installParent = fs.readFileSync(scratchFile("plugins-git-install-parent.txt"), "utf8").trim();
467+const installParent = fs
468+.readFileSync(scratchFile("plugins-git-install-parent.txt"), "utf8")
469+.trim();
429470assertPluginRemoved({
430471pluginId: "demo-plugin-git",
431472listFile: scratchFile("plugins-git-uninstalled.json"),
@@ -597,7 +638,10 @@ function assertNpmPlugin() {
597638}
598639599640function assertNpmPluginUpdateUnchanged() {
600-assertUpdateOutput(scratchFile("plugins-npm-update.log"), "demo-plugin-npm is up to date (0.0.1).");
641+assertUpdateOutput(
642+scratchFile("plugins-npm-update.log"),
643+"demo-plugin-npm is up to date (0.0.1).",
644+);
601645assertNpmPlugin();
602646}
603647@@ -748,16 +792,31 @@ async function assertClawHubPreflight() {
748792process.env.CLAWHUB_TOKEN ||
749793process.env.CLAWHUB_AUTH_TOKEN ||
750794"";
751-const response = await fetch(`${baseUrl}/api/v1/packages/${encodeURIComponent(packageName)}`, {
752-headers: token ? { Authorization: `Bearer ${token}` } : undefined,
753-});
795+const preflightUrl = `${baseUrl}/api/v1/packages/${encodeURIComponent(packageName)}`;
796+const response = await withTimeout(
797+`ClawHub package preflight for ${packageName}`,
798+CLAWHUB_PREFLIGHT_TIMEOUT_MS,
799+(signal) =>
800+fetch(preflightUrl, {
801+headers: token ? { Authorization: `Bearer ${token}` } : undefined,
802+ signal,
803+}),
804+);
754805if (!response.ok) {
755-const body = await response.text().catch(() => "");
806+const body = await withTimeout(
807+`ClawHub package preflight response for ${packageName}`,
808+CLAWHUB_PREFLIGHT_TIMEOUT_MS,
809+() => response.text().catch(() => ""),
810+);
756811throw new Error(
757812`ClawHub package preflight failed for ${packageName}: ${response.status} ${body}`,
758813);
759814}
760-const detail = await response.json();
815+const detail = await withTimeout(
816+`ClawHub package preflight response for ${packageName}`,
817+CLAWHUB_PREFLIGHT_TIMEOUT_MS,
818+() => response.json(),
819+);
761820const family = detail.package?.family;
762821if (family !== "code-plugin" && family !== "bundle-plugin") {
763822throw new Error(`ClawHub package ${packageName} is not installable as a plugin: ${family}`);
@@ -834,7 +893,9 @@ function assertClawHubInstalled() {
834893835894function assertClawHubRemoved() {
836895const pluginId = process.env.CLAWHUB_PLUGIN_ID;
837-const installPath = fs.readFileSync(scratchFile("plugins-clawhub-install-path.txt"), "utf8").trim();
896+const installPath = fs
897+.readFileSync(scratchFile("plugins-clawhub-install-path.txt"), "utf8")
898+.trim();
838899const list = readJson(scratchFile("plugins-clawhub-uninstalled.json"));
839900if ((list.plugins || []).some((entry) => entry.id === pluginId)) {
840901throw new Error(`ClawHub plugin still listed after uninstall: ${pluginId}`);
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。