diff --git a/nodes/image_to_prompt.py b/nodes/image_to_prompt.py index 75c9b87..bc4682c 100644 --- a/nodes/image_to_prompt.py +++ b/nodes/image_to_prompt.py @@ -1,4 +1,5 @@ import logging +from functools import partial from typing import Any, Tuple try: @@ -64,14 +65,11 @@ class OpenClawImageToPrompt: FUNCTION = "generate_prompt" CATEGORY = "moltbot" - def _tensor_to_base64_png(self, tensor_image: Any, max_side: int) -> str: - """ - Convert ComfyUI tensor (Batch, H, W, C) to base64 PNG. - Uses the first image in batch. - """ - return tensor_to_base64_png( - tensor_image=tensor_image, max_side=max_side, context="ImageToPrompt" - ) + # R154: keep the compatibility method name, but bind the shared helper + # directly so node wrappers do not duplicate image conversion logic. + _tensor_to_base64_png = staticmethod( + partial(tensor_to_base64_png, context="ImageToPrompt") + ) def generate_prompt( self, image: Any, goal: str, detail_level: str, max_image_side: int diff --git a/nodes/prompt_refiner.py b/nodes/prompt_refiner.py index e7468eb..2252381 100644 --- a/nodes/prompt_refiner.py +++ b/nodes/prompt_refiner.py @@ -1,5 +1,6 @@ import json import logging +from functools import partial from typing import Any, Tuple try: @@ -76,13 +77,11 @@ class OpenClawPromptRefiner: FUNCTION = "refine_prompt" CATEGORY = "moltbot" - def _tensor_to_base64_png(self, tensor_image: Any, max_side: int) -> str: - """ - Convert ComfyUI tensor (Batch, H, W, C) to base64 PNG. - """ - return tensor_to_base64_png( - tensor_image=tensor_image, max_side=max_side, context="PromptRefiner" - ) + # R154: keep the compatibility method name, but bind the shared helper + # directly so node wrappers do not duplicate image conversion logic. + _tensor_to_base64_png = staticmethod( + partial(tensor_to_base64_png, context="PromptRefiner") + ) def refine_prompt( self, diff --git a/web/openclaw_tabs.js b/web/openclaw_tabs.js index dd04048..ca8282f 100644 --- a/web/openclaw_tabs.js +++ b/web/openclaw_tabs.js @@ -4,7 +4,10 @@ */ import { ErrorBoundary } from "./ErrorBoundary.js"; import { STORAGE_KEYS, getMirroredStorageValue, setMirroredStorageValue } from "./openclaw_compat.js"; -import { normalizeLegacyClassNames } from "./openclaw_utils.js"; +import { + applyLegacyClassAliases, + normalizeLegacyClassNames, +} from "./openclaw_utils.js"; export class TabManager { constructor() { @@ -79,6 +82,8 @@ export class TabManager { normalizeLegacyClassNames(this.tabsEl); normalizeLegacyClassNames(this.contentEl); + applyLegacyClassAliases(this.tabsEl); + applyLegacyClassAliases(this.contentEl); } activateTab(id) { @@ -119,6 +124,7 @@ export class TabManager { if (pane) { normalizeLegacyClassNames(pane); + applyLegacyClassAliases(pane); } } diff --git a/web/openclaw_ui.js b/web/openclaw_ui.js index f5de42d..bf44a29 100644 --- a/web/openclaw_ui.js +++ b/web/openclaw_ui.js @@ -5,7 +5,10 @@ import { tabManager } from "./openclaw_tabs.js"; import { ErrorBoundary } from "./ErrorBoundary.js"; import { openclawApi } from "./openclaw_api.js"; -import { normalizeLegacyClassNames } from "./openclaw_utils.js"; +import { + applyLegacyClassAliases, + normalizeLegacyClassNames, +} from "./openclaw_utils.js"; import { OpenClawActions } from "./openclaw_actions.js"; import { QueueMonitor } from "./openclaw_queue_monitor.js"; import { OpenClawNotificationCenter } from "./openclaw_notification_center.js"; @@ -204,6 +207,7 @@ export class OpenClawUI { tabManager.init(tabBar, contentArea); normalizeLegacyClassNames(container); + applyLegacyClassAliases(container); this.bannerManager.bind(container, (action) => this.handleAction(action)); this.notificationCenter.render(); } @@ -301,6 +305,7 @@ export class OpenClawUI { this.container.appendChild(overlay); normalizeLegacyClassNames(overlay); + applyLegacyClassAliases(overlay); } } diff --git a/web/openclaw_utils.js b/web/openclaw_utils.js index cbab1b3..2ad7e36 100644 --- a/web/openclaw_utils.js +++ b/web/openclaw_utils.js @@ -72,6 +72,54 @@ export function normalizeLegacyClassNames(root) { return root; } +/** + * R154: derive runtime legacy aliases from canonical class tokens so templates + * do not need to hand-author duplicate `openclaw-*` + `moltbot-*` markup. + */ +export function buildLegacyAliasClassTokens(className = "") { + const canonicalTokens = normalizeLegacyClassTokens(className) + .split(/\s+/) + .map((token) => token.trim()) + .filter(Boolean); + const seen = new Set(canonicalTokens); + const combined = [...canonicalTokens]; + + canonicalTokens.forEach((token) => { + if (!token.startsWith("openclaw-")) { + return; + } + const legacy = `moltbot-${token.slice("openclaw-".length)}`; + if (seen.has(legacy)) { + return; + } + seen.add(legacy); + combined.push(legacy); + }); + + return combined.join(" "); +} + +export function applyLegacyClassAliases(root) { + if (!root) return root; + const nodes = []; + if (typeof root.className === "string") { + nodes.push(root); + } + if (typeof root.querySelectorAll === "function") { + nodes.push(...root.querySelectorAll("[class]")); + } + + nodes.forEach((node) => { + if (typeof node.className !== "string") return; + const withAliases = buildLegacyAliasClassTokens(node.className); + if (withAliases !== node.className) { + node.className = withAliases; + } + }); + + return root; +} + /** * Lightweight toast helper for UI feedback. * @param {string} message diff --git a/web/tabs/packs_tab.js b/web/tabs/packs_tab.js index 4fb515e..27a67a0 100644 --- a/web/tabs/packs_tab.js +++ b/web/tabs/packs_tab.js @@ -20,21 +20,21 @@ export const PacksTab = { render(container) { // --- 1. Static Layout --- container.innerHTML = ` -