mirror of
https://github.com/alkimake/paperclip.git
synced 2026-06-16 19:00:38 +09:00
feat: add OpenClaw adapter type
Introduce openclaw adapter package with server execution, CLI stream formatting, and UI config fields. Register the adapter across CLI, server, and UI registries. Add adapter label in all relevant pages. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
39d7f5d196
commit
b0f3f04ac6
26 changed files with 502 additions and 7 deletions
122
packages/adapters/openclaw/src/server/test.ts
Normal file
122
packages/adapters/openclaw/src/server/test.ts
Normal file
|
|
@ -0,0 +1,122 @@
|
|||
import type {
|
||||
AdapterEnvironmentCheck,
|
||||
AdapterEnvironmentTestContext,
|
||||
AdapterEnvironmentTestResult,
|
||||
} from "@paperclip/adapter-utils";
|
||||
import { asString, parseObject } from "@paperclip/adapter-utils/server-utils";
|
||||
|
||||
function summarizeStatus(checks: AdapterEnvironmentCheck[]): AdapterEnvironmentTestResult["status"] {
|
||||
if (checks.some((check) => check.level === "error")) return "fail";
|
||||
if (checks.some((check) => check.level === "warn")) return "warn";
|
||||
return "pass";
|
||||
}
|
||||
|
||||
function isLoopbackHost(hostname: string): boolean {
|
||||
const value = hostname.trim().toLowerCase();
|
||||
return value === "localhost" || value === "127.0.0.1" || value === "::1";
|
||||
}
|
||||
|
||||
export async function testEnvironment(
|
||||
ctx: AdapterEnvironmentTestContext,
|
||||
): Promise<AdapterEnvironmentTestResult> {
|
||||
const checks: AdapterEnvironmentCheck[] = [];
|
||||
const config = parseObject(ctx.config);
|
||||
const urlValue = asString(config.url, "");
|
||||
|
||||
if (!urlValue) {
|
||||
checks.push({
|
||||
code: "openclaw_url_missing",
|
||||
level: "error",
|
||||
message: "OpenClaw adapter requires a webhook URL.",
|
||||
hint: "Set adapterConfig.url to your OpenClaw webhook endpoint.",
|
||||
});
|
||||
return {
|
||||
adapterType: ctx.adapterType,
|
||||
status: summarizeStatus(checks),
|
||||
checks,
|
||||
testedAt: new Date().toISOString(),
|
||||
};
|
||||
}
|
||||
|
||||
let url: URL | null = null;
|
||||
try {
|
||||
url = new URL(urlValue);
|
||||
} catch {
|
||||
checks.push({
|
||||
code: "openclaw_url_invalid",
|
||||
level: "error",
|
||||
message: `Invalid URL: ${urlValue}`,
|
||||
});
|
||||
}
|
||||
|
||||
if (url && url.protocol !== "http:" && url.protocol !== "https:") {
|
||||
checks.push({
|
||||
code: "openclaw_url_protocol_invalid",
|
||||
level: "error",
|
||||
message: `Unsupported URL protocol: ${url.protocol}`,
|
||||
hint: "Use an http:// or https:// endpoint.",
|
||||
});
|
||||
}
|
||||
|
||||
if (url) {
|
||||
checks.push({
|
||||
code: "openclaw_url_valid",
|
||||
level: "info",
|
||||
message: `Configured endpoint: ${url.toString()}`,
|
||||
});
|
||||
|
||||
if (isLoopbackHost(url.hostname)) {
|
||||
checks.push({
|
||||
code: "openclaw_loopback_endpoint",
|
||||
level: "warn",
|
||||
message: "Endpoint uses loopback hostname. Remote OpenClaw workers cannot reach localhost on the Paperclip host.",
|
||||
hint: "Use a reachable hostname/IP (for example Tailscale/private hostname or public domain).",
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
const method = asString(config.method, "POST").trim().toUpperCase() || "POST";
|
||||
checks.push({
|
||||
code: "openclaw_method_configured",
|
||||
level: "info",
|
||||
message: `Configured method: ${method}`,
|
||||
});
|
||||
|
||||
if (url && (url.protocol === "http:" || url.protocol === "https:")) {
|
||||
const controller = new AbortController();
|
||||
const timeout = setTimeout(() => controller.abort(), 3000);
|
||||
try {
|
||||
const response = await fetch(url, { method: "HEAD", signal: controller.signal });
|
||||
if (!response.ok && response.status !== 405 && response.status !== 501) {
|
||||
checks.push({
|
||||
code: "openclaw_endpoint_probe_unexpected_status",
|
||||
level: "warn",
|
||||
message: `Endpoint probe returned HTTP ${response.status}.`,
|
||||
hint: "Verify OpenClaw webhook reachability and auth/network settings.",
|
||||
});
|
||||
} else {
|
||||
checks.push({
|
||||
code: "openclaw_endpoint_probe_ok",
|
||||
level: "info",
|
||||
message: "Endpoint responded to a HEAD probe.",
|
||||
});
|
||||
}
|
||||
} catch (err) {
|
||||
checks.push({
|
||||
code: "openclaw_endpoint_probe_failed",
|
||||
level: "warn",
|
||||
message: err instanceof Error ? err.message : "Endpoint probe failed",
|
||||
hint: "This may be expected in restricted networks; validate from the Paperclip server host.",
|
||||
});
|
||||
} finally {
|
||||
clearTimeout(timeout);
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
adapterType: ctx.adapterType,
|
||||
status: summarizeStatus(checks),
|
||||
checks,
|
||||
testedAt: new Date().toISOString(),
|
||||
};
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue