revert: remove A2UI test fix changes from this branch

Restore ci.yml, a2ui.ts, and bundle-a2ui.sh to main branch versions.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
Gareth Jones 2026-01-29 21:00:18 -08:00
parent f6288de625
commit 1d83e78377
3 changed files with 44 additions and 78 deletions

View File

@ -76,7 +76,7 @@ jobs:
command: pnpm lint
- runtime: node
task: test
command: pnpm canvas:a2ui:bundle && pnpm test
command: pnpm test
- runtime: node
task: build
command: pnpm build
@ -88,7 +88,7 @@ jobs:
command: pnpm format
- runtime: bun
task: test
command: pnpm canvas:a2ui:bundle && bunx vitest run
command: bunx vitest run
- runtime: bun
task: build
command: bunx tsc -p tsconfig.json
@ -188,7 +188,6 @@ jobs:
runs-on: blacksmith-4vcpu-windows-2025
env:
NODE_OPTIONS: --max-old-space-size=4096
CLAWDBOT_TEST_WORKERS: 1
defaults:
run:
shell: bash
@ -201,7 +200,7 @@ jobs:
command: pnpm lint
- runtime: node
task: test
command: pnpm canvas:a2ui:bundle && pnpm test
command: pnpm test
- runtime: node
task: build
command: pnpm build
@ -345,8 +344,6 @@ jobs:
pnpm install --frozen-lockfile --ignore-scripts=false --config.engine-strict=false --config.enable-pre-post-scripts=true || pnpm install --frozen-lockfile --ignore-scripts=false --config.engine-strict=false --config.enable-pre-post-scripts=true
- name: Run ${{ matrix.task }}
env:
NODE_OPTIONS: --max-old-space-size=4096
run: ${{ matrix.command }}
macos-app:

View File

@ -1,52 +1,25 @@
#!/usr/bin/env bash
set -euo pipefail
on_error() {
echo "A2UI bundling failed. Re-run with: pnpm canvas:a2ui:bundle" >&2
echo "If this persists, verify pnpm deps and try again." >&2
}
trap on_error ERR
ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
HASH_FILE="$ROOT_DIR/src/canvas-host/a2ui/.bundle.hash"
OUTPUT_FILE="$ROOT_DIR/src/canvas-host/a2ui/a2ui.bundle.js"
A2UI_RENDERER_DIR="$ROOT_DIR/vendor/a2ui/renderers/lit"
A2UI_APP_DIR="$ROOT_DIR/apps/shared/OpenClawKit/Tools/CanvasA2UI"
# Docker builds exclude vendor/apps via .dockerignore.
# In that environment we must keep the prebuilt bundle.
if [[ ! -d "$A2UI_RENDERER_DIR" || ! -d "$A2UI_APP_DIR" ]]; then
echo "A2UI sources missing; keeping prebuilt bundle."
exit 0
fi
INPUT_PATHS=(
"$ROOT_DIR/package.json"
"$ROOT_DIR/pnpm-lock.yaml"
"$A2UI_RENDERER_DIR"
"$A2UI_APP_DIR"
"$ROOT_DIR/vendor/a2ui/renderers/lit"
"$ROOT_DIR/apps/shared/ClawdbotKit/Tools/CanvasA2UI"
)
compute_hash() {
ROOT_DIR="$ROOT_DIR" node --input-type=module - "${INPUT_PATHS[@]}" <<'NODE'
import { createHash } from "node:crypto";
import { promises as fs } from "node:fs";
import path from "node:path";
const rootDir = process.env.ROOT_DIR ?? process.cwd();
const inputs = process.argv.slice(2);
const files = [];
async function walk(entryPath) {
const st = await fs.stat(entryPath);
if (st.isDirectory()) {
const entries = await fs.readdir(entryPath);
for (const entry of entries) {
await walk(path.join(entryPath, entry));
}
return;
}
files.push(entryPath);
collect_files() {
local path
for path in "${INPUT_PATHS[@]}"; do
if [[ -d "$path" ]]; then
find "$path" -type f -print0
else
printf '%s\0' "$path"
fi
done
}
compute_hash() {
@ -70,13 +43,13 @@ compute_hash() {
current_hash="$(compute_hash)"
if [[ -f "$HASH_FILE" ]]; then
previous_hash="$(cat "$HASH_FILE")"
if [[ "$previous_hash" == "$current_hash" && -f "$OUTPUT_FILE" ]]; then
if [[ "$previous_hash" == "$current_hash" ]]; then
echo "A2UI bundle up to date; skipping."
exit 0
fi
fi
pnpm -s exec tsc -p "$A2UI_RENDERER_DIR/tsconfig.json"
rolldown -c "$A2UI_APP_DIR/rolldown.config.mjs"
pnpm -s exec tsc -p vendor/a2ui/renderers/lit/tsconfig.json
rolldown -c apps/shared/ClawdbotKit/Tools/CanvasA2UI/rolldown.config.mjs
echo "$current_hash" > "$HASH_FILE"

View File

@ -5,11 +5,9 @@ import { fileURLToPath } from "node:url";
import { detectMime } from "../media/mime.js";
export const A2UI_PATH = "/__openclaw__/a2ui";
export const CANVAS_HOST_PATH = "/__openclaw__/canvas";
export const CANVAS_WS_PATH = "/__openclaw__/ws";
export const A2UI_PATH = "/__clawdbot__/a2ui";
export const CANVAS_HOST_PATH = "/__clawdbot__/canvas";
export const CANVAS_WS_PATH = "/__clawdbot/ws";
let cachedA2uiRootReal: string | null | undefined;
let resolvingA2uiRoot: Promise<string | null> | null = null;
@ -53,8 +51,8 @@ async function resolveA2uiRoot(): Promise<string | null> {
if (process.execPath) {
candidates.unshift(path.resolve(path.dirname(process.execPath), "a2ui"));
}
// Find repo root by walking up from `here` or cwd (handles vitest/vite transforms).
const repoRoot = (await findRepoRoot(here)) ?? (await findRepoRoot(process.cwd()));
// Find repo root by walking up from `here` (handles vitest/vite transforms).
const repoRoot = await findRepoRoot(here);
if (repoRoot) {
candidates.push(path.resolve(repoRoot, "src/canvas-host/a2ui"));
candidates.push(path.resolve(repoRoot, "dist/canvas-host/a2ui"));
@ -129,24 +127,22 @@ export function injectCanvasLiveReload(html: string): string {
(() => {
// Cross-platform action bridge helper.
// Works on:
// - iOS: window.webkit.messageHandlers.openclawCanvasA2UIAction.postMessage(...)
// - Android: window.openclawCanvasA2UIAction.postMessage(...)
const handlerNames = ["openclawCanvasA2UIAction"];
// - iOS: window.webkit.messageHandlers.clawdbotCanvasA2UIAction.postMessage(...)
// - Android: window.clawdbotCanvasA2UIAction.postMessage(...)
const actionHandlerName = "clawdbotCanvasA2UIAction";
function postToNode(payload) {
try {
const raw = typeof payload === "string" ? payload : JSON.stringify(payload);
for (const name of handlerNames) {
const iosHandler = globalThis.webkit?.messageHandlers?.[name];
if (iosHandler && typeof iosHandler.postMessage === "function") {
iosHandler.postMessage(raw);
return true;
}
const androidHandler = globalThis[name];
if (androidHandler && typeof androidHandler.postMessage === "function") {
// Important: call as a method on the interface object (binding matters on Android WebView).
androidHandler.postMessage(raw);
return true;
}
const iosHandler = globalThis.webkit?.messageHandlers?.[actionHandlerName];
if (iosHandler && typeof iosHandler.postMessage === "function") {
iosHandler.postMessage(raw);
return true;
}
const androidHandler = globalThis[actionHandlerName];
if (androidHandler && typeof androidHandler.postMessage === "function") {
// Important: call as a method on the interface object (binding matters on Android WebView).
androidHandler.postMessage(raw);
return true;
}
} catch {}
return false;
@ -158,11 +154,11 @@ export function injectCanvasLiveReload(html: string): string {
const action = { ...userAction, id };
return postToNode({ userAction: action });
}
globalThis.OpenClaw = globalThis.OpenClaw ?? {};
globalThis.OpenClaw.postMessage = postToNode;
globalThis.OpenClaw.sendUserAction = sendUserAction;
globalThis.openclawPostMessage = postToNode;
globalThis.openclawSendUserAction = sendUserAction;
globalThis.Clawdbot = globalThis.Clawdbot ?? {};
globalThis.Clawdbot.postMessage = postToNode;
globalThis.Clawdbot.sendUserAction = sendUserAction;
globalThis.clawdbotPostMessage = postToNode;
globalThis.clawdbotSendUserAction = sendUserAction;
try {
const proto = location.protocol === "https:" ? "wss" : "ws";
@ -190,9 +186,9 @@ export async function handleA2uiHttpRequest(
if (!urlRaw) return false;
const url = new URL(urlRaw, "http://localhost");
const basePath =
url.pathname === A2UI_PATH || url.pathname.startsWith(`${A2UI_PATH}/`) ? A2UI_PATH : undefined;
if (!basePath) return false;
if (url.pathname !== A2UI_PATH && !url.pathname.startsWith(`${A2UI_PATH}/`)) {
return false;
}
if (req.method !== "GET" && req.method !== "HEAD") {
res.statusCode = 405;
@ -209,7 +205,7 @@ export async function handleA2uiHttpRequest(
return true;
}
const rel = url.pathname.slice(basePath.length);
const rel = url.pathname.slice(A2UI_PATH.length);
const filePath = await resolveA2uiFilePath(a2uiRootReal, rel || "/");
if (!filePath) {
res.statusCode = 404;