From f4a59eb5d8a19bb04212f975279df7e70b95436c Mon Sep 17 00:00:00 2001 From: Vincent Koc Date: Sat, 21 Feb 2026 02:46:31 -0500 Subject: [PATCH] Chore: harden A2UI bundle dependency resolution (#22507) Merged via /review-pr -> /prepare-pr -> /merge-pr. Prepared head SHA: d84c5bde518a4b2f3d192b0446672afeecf3fa3d Co-authored-by: vincentkoc <25068+vincentkoc@users.noreply.github.com> Co-authored-by: obviyus <22031114+obviyus@users.noreply.github.com> Reviewed-by: @obviyus --- CHANGELOG.md | 1 + .../Tools/CanvasA2UI/rolldown.config.mjs | 45 +++++++++++-------- extensions/msteams/package.json | 2 - package.json | 5 +++ pnpm-lock.yaml | 44 +++++++----------- scripts/bundle-a2ui.sh | 2 +- 6 files changed, 49 insertions(+), 50 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4e5f62a60..0ac27e224 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,6 +14,7 @@ Docs: https://docs.openclaw.ai - Security/Unused Dependencies: remove unused root devDependencies `@lit/context` and `@lit-labs/signals` flagged as unused by Knip dead-code reports. (#22471) Thanks @vincentkoc. - Security/Unused Dependencies: remove unused root dependency `lit` that is now scoped to `ui/` package dependencies. (#22471) Thanks @vincentkoc. - Security/Unused Dependencies: remove unused root dependencies `long` and `rolldown`; keep A2UI bundling functional by falling back to `pnpm dlx rolldown` when the binary is not locally installed. (#22481) Thanks @vincentkoc. +- Security/Unused Dependencies: harden A2UI bundling dependency resolution by resolving `lit`, `@lit/context`, `@lit-labs/signals`, and `signal-utils` from UI workspace or repo-root dependency locations to tolerate Docker layout differences without root-only assumptions. (#22507) Thanks @vincentkoc. - Security/Unused Dependencies: fix A2UI bundle resolution for removed root `lit` deps by resolving `lit`, `@lit/context`, `@lit-labs/signals`, and `signal-utils` from UI workspace dependencies in `rolldown.config.mjs` during bundling. (#22481) Thanks @vincentkoc. - Security/Unused Dependencies: simplify `canvas-a2ui` bundling script by removing temporary vendored `node_modules` symlink logic now that `ui` workspace dependencies are explicit. (#22481) Thanks @vincentkoc. - Security/Unused Dependencies: remove unused `@microsoft/agents-hosting-express` and `@microsoft/agents-hosting-extensions-teams` from `extensions/msteams` because current code only uses `@microsoft/agents-hosting`. Thanks @vincentkoc. diff --git a/apps/shared/OpenClawKit/Tools/CanvasA2UI/rolldown.config.mjs b/apps/shared/OpenClawKit/Tools/CanvasA2UI/rolldown.config.mjs index bd8677d5f..ccf1683d5 100644 --- a/apps/shared/OpenClawKit/Tools/CanvasA2UI/rolldown.config.mjs +++ b/apps/shared/OpenClawKit/Tools/CanvasA2UI/rolldown.config.mjs @@ -1,10 +1,10 @@ import path from "node:path"; import { existsSync } from "node:fs"; import { fileURLToPath } from "node:url"; -import { defineConfig } from "rolldown"; const here = path.dirname(fileURLToPath(import.meta.url)); const repoRoot = path.resolve(here, "../../../../.."); +const uiRoot = path.resolve(repoRoot, "ui"); const fromHere = (p) => path.resolve(here, p); const outputFile = path.resolve( here, @@ -17,19 +17,28 @@ const outputFile = path.resolve( const a2uiLitDist = path.resolve(repoRoot, "vendor/a2ui/renderers/lit/dist/src"); const a2uiThemeContext = path.resolve(a2uiLitDist, "0.8/ui/context/theme.js"); -const a2uiNodeModules = path.resolve(repoRoot, "ui/node_modules"); -const rootNodeModules = path.resolve(repoRoot, "node_modules"); +const uiNodeModules = path.resolve(uiRoot, "node_modules"); +const repoNodeModules = path.resolve(repoRoot, "node_modules"); -const resolveA2uiDep = (pkg, rel = "") => { - const uiPath = path.resolve(a2uiNodeModules, pkg, rel); - if (existsSync(uiPath)) { - return uiPath; +function resolveUiDependency(moduleId) { + const candidates = [ + path.resolve(uiNodeModules, moduleId), + path.resolve(repoNodeModules, moduleId), + ]; + for (const candidate of candidates) { + if (existsSync(candidate)) { + return candidate; + } } - return path.resolve(rootNodeModules, pkg, rel); -}; + const fallbackCandidates = candidates.join(", "); + throw new Error( + `A2UI bundle config cannot resolve ${moduleId}. Checked: ${fallbackCandidates}. ` + + "Keep dependency installed in ui workspace or repo root before bundling.", + ); +} -export default defineConfig({ +export default { input: fromHere("bootstrap.js"), experimental: { attachDebugInfo: "none", @@ -40,13 +49,13 @@ export default defineConfig({ "@a2ui/lit": path.resolve(a2uiLitDist, "index.js"), "@a2ui/lit/ui": path.resolve(a2uiLitDist, "0.8/ui/ui.js"), "@openclaw/a2ui-theme-context": a2uiThemeContext, - "@lit/context": resolveA2uiDep("@lit/context", "index.js"), - "@lit/context/": resolveA2uiDep("@lit/context"), - "@lit-labs/signals": resolveA2uiDep("@lit-labs/signals", "index.js"), - "@lit-labs/signals/": resolveA2uiDep("@lit-labs/signals"), - lit: resolveA2uiDep("lit", "index.js"), - "lit/": resolveA2uiDep("lit"), - "signal-utils/": resolveA2uiDep("signal-utils"), + "@lit/context": resolveUiDependency("@lit/context"), + "@lit/context/": resolveUiDependency("@lit/context/"), + "@lit-labs/signals": resolveUiDependency("@lit-labs/signals"), + "@lit-labs/signals/": resolveUiDependency("@lit-labs/signals/"), + lit: resolveUiDependency("lit"), + "lit/": resolveUiDependency("lit/"), + "signal-utils/": resolveUiDependency("signal-utils/"), }, }, output: { @@ -55,4 +64,4 @@ export default defineConfig({ codeSplitting: false, sourcemap: false, }, -}); +}; diff --git a/extensions/msteams/package.json b/extensions/msteams/package.json index b39c6bdb4..ebd598988 100644 --- a/extensions/msteams/package.json +++ b/extensions/msteams/package.json @@ -5,8 +5,6 @@ "type": "module", "dependencies": { "@microsoft/agents-hosting": "^1.2.3", - "@microsoft/agents-hosting-express": "^1.2.3", - "@microsoft/agents-hosting-extensions-teams": "^1.2.3", "express": "^5.2.1" }, "devDependencies": { diff --git a/package.json b/package.json index 41f7a3bd1..8b1660e9c 100644 --- a/package.json +++ b/package.json @@ -174,6 +174,7 @@ "json5": "^2.2.3", "jszip": "^3.10.1", "linkedom": "^0.18.12", + "long": "^5.3.2", "markdown-it": "^14.1.1", "node-edge-tts": "^1.2.10", "opusscript": "^0.0.8", @@ -192,6 +193,8 @@ }, "devDependencies": { "@grammyjs/types": "^3.24.0", + "@lit-labs/signals": "^0.1.3", + "@lit/context": "^1.1.6", "@types/express": "^5.0.6", "@types/markdown-it": "^14.1.2", "@types/node": "^25.3.0", @@ -199,9 +202,11 @@ "@types/ws": "^8.18.1", "@typescript/native-preview": "7.0.0-dev.20260219.1", "@vitest/coverage-v8": "^4.0.18", + "lit": "^3.3.2", "oxfmt": "0.33.0", "oxlint": "^1.48.0", "oxlint-tsgolint": "^0.14.1", + "signal-utils": "0.21.1", "tsdown": "^0.20.3", "tsx": "^4.21.0", "typescript": "^5.9.3", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 83ef0ba64..c89c7f677 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -131,6 +131,9 @@ importers: linkedom: specifier: ^0.18.12 version: 0.18.12 + long: + specifier: ^5.3.2 + version: 5.3.2 markdown-it: specifier: ^14.1.1 version: 14.1.1 @@ -183,6 +186,12 @@ importers: '@grammyjs/types': specifier: ^3.24.0 version: 3.24.0 + '@lit-labs/signals': + specifier: ^0.1.3 + version: 0.1.3 + '@lit/context': + specifier: ^1.1.6 + version: 1.1.6 '@types/express': specifier: ^5.0.6 version: 5.0.6 @@ -204,6 +213,9 @@ importers: '@vitest/coverage-v8': specifier: ^4.0.18 version: 4.0.18(@vitest/browser@4.0.18(vite@7.3.1(@types/node@25.3.0)(jiti@2.6.1)(lightningcss@1.30.2)(tsx@4.21.0)(yaml@2.8.2))(vitest@4.0.18))(vitest@4.0.18) + lit: + specifier: ^3.3.2 + version: 3.3.2 oxfmt: specifier: 0.33.0 version: 0.33.0 @@ -213,6 +225,9 @@ importers: oxlint-tsgolint: specifier: ^0.14.1 version: 0.14.1 + signal-utils: + specifier: 0.21.1 + version: 0.21.1(signal-polyfill@0.2.2) tsdown: specifier: ^0.20.3 version: 0.20.3(@typescript/native-preview@7.0.0-dev.20260219.1)(typescript@5.9.3) @@ -405,12 +420,6 @@ importers: '@microsoft/agents-hosting': specifier: ^1.2.3 version: 1.2.3 - '@microsoft/agents-hosting-express': - specifier: ^1.2.3 - version: 1.2.3 - '@microsoft/agents-hosting-extensions-teams': - specifier: ^1.2.3 - version: 1.2.3 express: specifier: ^5.2.1 version: 5.2.1 @@ -1561,14 +1570,6 @@ packages: resolution: {integrity: sha512-XRQF+AVn6f9sGDUsfDQFiwLtmqqWNhM9JIwZRzK9XQLPTQmoWwjoWz8KMKc5fuvj5Ybly3974VrqYUbDOeMyTg==} engines: {node: '>=20.0.0'} - '@microsoft/agents-hosting-express@1.2.3': - resolution: {integrity: sha512-aBgvyDJ+3ifeUKy/56qQuLJPAizN9UfGV3/1GVrhmyAqUKvphusK3LMxiRTpHDhAaUvuzFOr1AJ8XiRhOl9l3w==} - engines: {node: '>=20.0.0'} - - '@microsoft/agents-hosting-extensions-teams@1.2.3': - resolution: {integrity: sha512-fZcn8JcU50VfjBgz6jTlCRiQReAZzj2f2Atudwa+ymxJQhfBb7NToJcY7OdLqM8hlnQhzAg71HJtGhPR/L2p1g==} - engines: {node: '>=20.0.0'} - '@microsoft/agents-hosting@1.2.3': resolution: {integrity: sha512-8paXuxdbRc9X6tccYoR3lk0DSglt1SxpJG+6qDa8TVTuGiTvIuhnN4st9JZhIiazxPiFPTJAkhK5JSsOk+wLVQ==} engines: {node: '>=20.0.0'} @@ -7402,21 +7403,6 @@ snapshots: transitivePeerDependencies: - supports-color - '@microsoft/agents-hosting-express@1.2.3': - dependencies: - '@microsoft/agents-hosting': 1.2.3 - express: 5.2.1 - transitivePeerDependencies: - - debug - - supports-color - - '@microsoft/agents-hosting-extensions-teams@1.2.3': - dependencies: - '@microsoft/agents-hosting': 1.2.3 - transitivePeerDependencies: - - debug - - supports-color - '@microsoft/agents-hosting@1.2.3': dependencies: '@azure/core-auth': 1.10.1 diff --git a/scripts/bundle-a2ui.sh b/scripts/bundle-a2ui.sh index ff85dd044..3278e1d35 100755 --- a/scripts/bundle-a2ui.sh +++ b/scripts/bundle-a2ui.sh @@ -89,7 +89,7 @@ pnpm -s exec tsc -p "$A2UI_RENDERER_DIR/tsconfig.json" if command -v rolldown >/dev/null 2>&1; then rolldown -c "$A2UI_APP_DIR/rolldown.config.mjs" else - pnpm dlx "rolldown@1.0.0-rc.5" -c "$A2UI_APP_DIR/rolldown.config.mjs" + pnpm -s dlx rolldown -c "$A2UI_APP_DIR/rolldown.config.mjs" fi echo "$current_hash" > "$HASH_FILE"