From 1d83e783776440e77c9bc73921d5d21ce882b1fa Mon Sep 17 00:00:00 2001 From: Gareth Jones Date: Thu, 29 Jan 2026 21:00:18 -0800 Subject: [PATCH] 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 --- .github/workflows/ci.yml | 9 +++---- scripts/bundle-a2ui.sh | 55 ++++++++++--------------------------- src/canvas-host/a2ui.ts | 58 +++++++++++++++++++--------------------- 3 files changed, 44 insertions(+), 78 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 3bda11de7..cd647d6e3 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -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: diff --git a/scripts/bundle-a2ui.sh b/scripts/bundle-a2ui.sh index ed78b3c20..b0bcce221 100755 --- a/scripts/bundle-a2ui.sh +++ b/scripts/bundle-a2ui.sh @@ -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" diff --git a/src/canvas-host/a2ui.ts b/src/canvas-host/a2ui.ts index 772339a9a..0b35832d2 100644 --- a/src/canvas-host/a2ui.ts +++ b/src/canvas-host/a2ui.ts @@ -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 | null = null; @@ -53,8 +51,8 @@ async function resolveA2uiRoot(): Promise { 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;