#!/usr/bin/env bash set -euo pipefail ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)" IMAGE_NAME="clawdbot-plugins-e2e" echo "Building Docker image..." docker build -t "$IMAGE_NAME" -f "$ROOT_DIR/scripts/e2e/Dockerfile" "$ROOT_DIR" echo "Running plugins Docker E2E..." docker run --rm -t "$IMAGE_NAME" bash -lc ' set -euo pipefail home_dir=$(mktemp -d "/tmp/clawdbot-plugins-e2e.XXXXXX") export HOME="$home_dir" mkdir -p "$HOME/.clawdbot/extensions" cat > "$HOME/.clawdbot/extensions/demo-plugin.js" <<'"'"'JS'"'"' module.exports = { id: "demo-plugin", name: "Demo Plugin", description: "Docker E2E demo plugin", register(api) { api.registerTool(() => null, { name: "demo_tool" }); api.registerGatewayMethod("demo.ping", async () => ({ ok: true })); api.registerCli(() => {}, { commands: ["demo"] }); api.registerService({ id: "demo-service", start: () => {} }); }, }; JS node dist/index.js plugins list --json > /tmp/plugins.json node - <<'"'"'NODE'"'"' const fs = require("node:fs"); const data = JSON.parse(fs.readFileSync("/tmp/plugins.json", "utf8")); const plugin = (data.plugins || []).find((entry) => entry.id === "demo-plugin"); if (!plugin) throw new Error("plugin not found"); if (plugin.status !== "loaded") { throw new Error(`unexpected status: ${plugin.status}`); } const assertIncludes = (list, value, label) => { if (!Array.isArray(list) || !list.includes(value)) { throw new Error(`${label} missing: ${value}`); } }; assertIncludes(plugin.toolNames, "demo_tool", "tool"); assertIncludes(plugin.gatewayMethods, "demo.ping", "gateway method"); assertIncludes(plugin.cliCommands, "demo", "cli command"); assertIncludes(plugin.services, "demo-service", "service"); const diagErrors = (data.diagnostics || []).filter((diag) => diag.level === "error"); if (diagErrors.length > 0) { throw new Error(`diagnostics errors: ${diagErrors.map((diag) => diag.message).join("; ")}`); } console.log("ok"); NODE ' echo "OK"