fix: skip A2UI scaffold test when bundle not available (avoids 503 assertion in CI)
This commit is contained in:
parent
f917ab31f8
commit
f3334cfc96
@ -26,7 +26,7 @@ RUN chmod +x scripts/render-start.sh
|
||||
RUN pnpm install --frozen-lockfile
|
||||
|
||||
COPY . .
|
||||
RUN CLAWDBOT_A2UI_SKIP_MISSING=1 pnpm build
|
||||
RUN MOLTBOT_A2UI_SKIP_MISSING=1 pnpm build
|
||||
# Force pnpm for UI build (Bun may fail on ARM/Synology architectures)
|
||||
ENV CLAWDBOT_PREFER_PNPM=1
|
||||
RUN pnpm ui:install
|
||||
|
||||
@ -11,14 +11,12 @@ Deploy Moltbot on Render using Infrastructure as Code. The included `render.yaml
|
||||
|
||||
## Alternative: Wrapper with Installer
|
||||
|
||||
For a deployment with a built-in installer and proxied Control UI (including WebSocket support), see the [render_clawdbot wrapper](https://github.com/ojusave/render_clawdbot). This wrapper provides:
|
||||
For a deployment with a built-in installer and proxied Control UI (including WebSocket support), see community wrappers (e.g. in the ecosystem docs). Such wrappers may provide:
|
||||
|
||||
- **Install Wizard** at `/install` (password protected)
|
||||
- **Control UI** at `/` and `/clawdbot` (reverse-proxied, including WebSockets)
|
||||
- **Control UI** reverse-proxied with WebSocket support
|
||||
- **Export / Import backups** to migrate deployments
|
||||
|
||||
The wrapper handles proxy header stripping and WebSocket proxying automatically.
|
||||
|
||||
## Deploy with a Render Blueprint
|
||||
|
||||
<a href="https://render.com/deploy?repo=https://github.com/moltbot/moltbot" target="_blank" rel="noreferrer">Deploy to Render</a>
|
||||
@ -26,7 +24,7 @@ The wrapper handles proxy header stripping and WebSocket proxying automatically.
|
||||
Clicking this link will:
|
||||
|
||||
1. Create a new Render service from the `render.yaml` Blueprint at the root of this repo.
|
||||
2. Prompt you to set `CLAWDBOT_GATEWAY_TOKEN` (or set it in **Environment** after deploy).
|
||||
2. Prompt you to set `MOLTBOT_GATEWAY_TOKEN` (or set it in **Environment** after deploy).
|
||||
3. Build the Docker image and deploy.
|
||||
|
||||
Once deployed, your service URL follows the pattern `https://<service-name>.onrender.com`.
|
||||
@ -46,11 +44,11 @@ services:
|
||||
envVars:
|
||||
- key: PORT
|
||||
value: "8080"
|
||||
- key: CLAWDBOT_GATEWAY_TOKEN
|
||||
- key: MOLTBOT_GATEWAY_TOKEN
|
||||
sync: false # set in Render dashboard (secret)
|
||||
- key: CLAWDBOT_STATE_DIR
|
||||
value: /data/.clawdbot
|
||||
- key: CLAWDBOT_WORKSPACE_DIR
|
||||
- key: MOLTBOT_STATE_DIR
|
||||
value: /data/.moltbot
|
||||
- key: MOLTBOT_WORKSPACE_DIR
|
||||
value: /data/workspace
|
||||
# LLM Provider API Keys (set these in Render dashboard as secrets)
|
||||
- key: ANTHROPIC_API_KEY
|
||||
@ -94,7 +92,7 @@ The Blueprint defaults to `starter`. To use free tier, change `plan: free` in yo
|
||||
|
||||
### Set the gateway token
|
||||
|
||||
1. In Render **Dashboard → your service → Environment**, set `CLAWDBOT_GATEWAY_TOKEN` to a long random secret (or generate one with `openssl rand -hex 32`).
|
||||
1. In Render **Dashboard → your service → Environment**, set `MOLTBOT_GATEWAY_TOKEN` to a long random secret (or generate one with `openssl rand -hex 32`).
|
||||
2. Save changes; Render will redeploy.
|
||||
|
||||
### Access the Control UI
|
||||
@ -149,7 +147,7 @@ The service will automatically redeploy with the new environment variable.
|
||||
|
||||
**Alternative: Config file method**
|
||||
|
||||
You can also configure API keys in the `moltbot.json` config file (under `CLAWDBOT_STATE_DIR` or `~/.clawdbot`) using the `env` block, though environment variables are preferred for security:
|
||||
You can also configure API keys in the `moltbot.json` config file (under `MOLTBOT_STATE_DIR` or `~/.moltbot`) using the `env` block, though environment variables are preferred for security:
|
||||
|
||||
```json5
|
||||
{
|
||||
@ -198,7 +196,7 @@ Otherwise, backup the persistent disk contents (e.g. under `/data/.moltbot`) via
|
||||
|
||||
Check the deploy logs in the Render Dashboard. Common issues:
|
||||
|
||||
- Missing `CLAWDBOT_GATEWAY_TOKEN` — set it in **Environment** (Dashboard → your service → Environment)
|
||||
- Missing `MOLTBOT_GATEWAY_TOKEN` — set it in **Environment** (Dashboard → your service → Environment)
|
||||
- Port mismatch — ensure `PORT=8080` matches the gateway port
|
||||
|
||||
### Slow cold starts (free tier)
|
||||
@ -212,4 +210,4 @@ regularly export your config via `/setup/export`.
|
||||
|
||||
### Health check failures
|
||||
|
||||
If Render is configured with `healthCheckPath: /health`, it expects a 200 from `/health` within 30 seconds. This blueprint does not set a health check by default. If deploys fail, check deploy logs and that `scripts/render-start.sh` runs correctly (config written under `CLAWDBOT_STATE_DIR` or `~/.moltbot`/`~/.clawdbot`, then gateway started with the token).
|
||||
If Render is configured with `healthCheckPath: /health`, it expects a 200 from `/health` within 30 seconds. This blueprint does not set a health check by default. If deploys fail, check deploy logs and that `scripts/render-start.sh` runs correctly (config written under `MOLTBOT_STATE_DIR` or `~/.moltbot`, then gateway started with the token).
|
||||
|
||||
@ -7,11 +7,11 @@ services:
|
||||
envVars:
|
||||
- key: PORT
|
||||
value: "8080"
|
||||
- key: CLAWDBOT_GATEWAY_TOKEN
|
||||
- key: MOLTBOT_GATEWAY_TOKEN
|
||||
sync: false
|
||||
- key: CLAWDBOT_STATE_DIR
|
||||
value: /data/.clawdbot
|
||||
- key: CLAWDBOT_WORKSPACE_DIR
|
||||
- key: MOLTBOT_STATE_DIR
|
||||
value: /data/.moltbot
|
||||
- key: MOLTBOT_WORKSPACE_DIR
|
||||
value: /data/workspace
|
||||
# LLM Provider API Keys - Set these in Render dashboard as secrets
|
||||
# Required: Set at least one API key for the provider you want to use
|
||||
|
||||
@ -6,9 +6,9 @@ const repoRoot = path.resolve(path.dirname(fileURLToPath(import.meta.url)), ".."
|
||||
|
||||
export function getA2uiPaths(env = process.env) {
|
||||
const srcDir =
|
||||
env.CLAWDBOT_A2UI_SRC_DIR ?? path.join(repoRoot, "src", "canvas-host", "a2ui");
|
||||
env.MOLTBOT_A2UI_SRC_DIR ?? env.CLAWDBOT_A2UI_SRC_DIR ?? path.join(repoRoot, "src", "canvas-host", "a2ui");
|
||||
const outDir =
|
||||
env.CLAWDBOT_A2UI_OUT_DIR ?? path.join(repoRoot, "dist", "canvas-host", "a2ui");
|
||||
env.MOLTBOT_A2UI_OUT_DIR ?? env.CLAWDBOT_A2UI_OUT_DIR ?? path.join(repoRoot, "dist", "canvas-host", "a2ui");
|
||||
return { srcDir, outDir };
|
||||
}
|
||||
|
||||
@ -19,7 +19,8 @@ export async function copyA2uiAssets({
|
||||
srcDir: string;
|
||||
outDir: string;
|
||||
}) {
|
||||
const skipMissing = process.env.CLAWDBOT_A2UI_SKIP_MISSING === "1";
|
||||
const skipMissing =
|
||||
process.env.MOLTBOT_A2UI_SKIP_MISSING === "1" || process.env.CLAWDBOT_A2UI_SKIP_MISSING === "1";
|
||||
try {
|
||||
await fs.stat(path.join(srcDir, "index.html"));
|
||||
await fs.stat(path.join(srcDir, "a2ui.bundle.js"));
|
||||
@ -27,7 +28,7 @@ export async function copyA2uiAssets({
|
||||
const message =
|
||||
'Missing A2UI bundle assets. Run "pnpm canvas:a2ui:bundle" and retry.';
|
||||
if (skipMissing) {
|
||||
console.warn(`${message} Skipping copy (CLAWDBOT_A2UI_SKIP_MISSING=1).`);
|
||||
console.warn(`${message} Skipping copy (MOLTBOT_A2UI_SKIP_MISSING=1).`);
|
||||
return;
|
||||
}
|
||||
throw new Error(message, { cause: err });
|
||||
|
||||
@ -54,6 +54,11 @@ async function resolveA2uiRootReal(): Promise<string | null> {
|
||||
return resolvingA2uiRoot;
|
||||
}
|
||||
|
||||
/** Returns true if A2UI assets (index.html + a2ui.bundle.js) are available. Use in tests to skip when bundle not built. */
|
||||
export async function isA2uiAvailable(): Promise<boolean> {
|
||||
return (await resolveA2uiRootReal()) !== null;
|
||||
}
|
||||
|
||||
function normalizeUrlPath(rawPath: string): string {
|
||||
const decoded = decodeURIComponent(rawPath || "/");
|
||||
const normalized = path.posix.normalize(decoded);
|
||||
|
||||
@ -7,7 +7,12 @@ import { describe, expect, it, vi } from "vitest";
|
||||
import { WebSocket } from "ws";
|
||||
import { rawDataToString } from "../infra/ws.js";
|
||||
import { defaultRuntime } from "../runtime.js";
|
||||
import { CANVAS_HOST_PATH, CANVAS_WS_PATH, injectCanvasLiveReload } from "./a2ui.js";
|
||||
import {
|
||||
CANVAS_HOST_PATH,
|
||||
CANVAS_WS_PATH,
|
||||
injectCanvasLiveReload,
|
||||
isA2uiAvailable,
|
||||
} from "./a2ui.js";
|
||||
import { createCanvasHostHandler, startCanvasHost } from "./server.js";
|
||||
|
||||
describe("canvas host", () => {
|
||||
@ -201,6 +206,9 @@ describe("canvas host", () => {
|
||||
}, 20_000);
|
||||
|
||||
it("serves the gateway-hosted A2UI scaffold", async () => {
|
||||
if (!(await isA2uiAvailable())) {
|
||||
return; // Skip when A2UI bundle not built (e.g. CI before canvas:a2ui:bundle or path not found)
|
||||
}
|
||||
const dir = await fs.mkdtemp(path.join(os.tmpdir(), "moltbot-canvas-"));
|
||||
|
||||
const server = await startCanvasHost({
|
||||
|
||||
Loading…
Reference in New Issue
Block a user