@@ -189,30 +189,42 @@ async function downloadTarballWithCurl(url: string, dest: string, timeoutMs: num
189189 }
190190}
191191
192+ type OpenclawRootPackageJson = {
193+ dependencies ?: Record < string , string >
194+ optionalDependencies ?: Record < string , string >
195+ }
196+
192197/**
193- * Vite bundles `../src/**` under `openclawRoot/src`. Rolldown resolves bare imports (e.g. `zod`)
194- * from the source file path upward — `node_modules` must exist on `openclawRoot`, not only under `ui/`.
198+ * Vite bundles `../src/**` under `openclawRoot/src`. Rolldown resolves bare imports from the source
199+ * file upward, so `node_modules` must exist on `openclawRoot` (not only under `ui/`). Shared `src/`
200+ * imports the same packages as the OpenClaw CLI root `package.json` (`zod`, `@mariozechner/pi-ai`, …);
201+ * install that full dependency set from the extracted tag to avoid whack-a-mole missing modules.
195202 */
196- async function ensureOpenclawRootDepsForBundledSrc ( openclawRoot : string ) : Promise < void > {
197- const pkgPath = join ( openclawRoot , 'package.json' )
198- type RootPkg = { name ?: string ; private ?: boolean ; dependencies ?: Record < string , string > }
199- let pkg : RootPkg
200- if ( await fileExists ( pkgPath ) ) {
201- const raw = await readFile ( pkgPath , 'utf8' )
202- pkg = JSON . parse ( raw ) as RootPkg
203- pkg . dependencies = { zod : '^4' , ...pkg . dependencies }
204- } else {
205- pkg = {
206- name : 'openclaw-desktop-control-ui-openclawroot' ,
207- private : true ,
208- dependencies : { zod : '^4' } ,
209- }
203+ async function ensureOpenclawRootDepsForBundledSrc (
204+ openclawRoot : string ,
205+ openclawRepoRoot : string ,
206+ ) : Promise < void > {
207+ const upstreamPath = join ( openclawRepoRoot , 'package.json' )
208+ if ( ! ( await fileExists ( upstreamPath ) ) ) {
209+ throw new Error ( `[control-ui] missing OpenClaw package.json: ${ upstreamPath } ` )
210+ }
211+ const upstream = JSON . parse ( await readFile ( upstreamPath , 'utf8' ) ) as OpenclawRootPackageJson
212+ const dependencies = upstream . dependencies ?? { }
213+ if ( Object . keys ( dependencies ) . length === 0 ) {
214+ throw new Error ( `[control-ui] OpenClaw package.json has no dependencies: ${ upstreamPath } ` )
215+ }
216+ const stub : Record < string , unknown > = {
217+ name : 'openclaw-desktop-control-ui-openclawroot' ,
218+ private : true ,
219+ version : '0.0.0' ,
220+ dependencies,
210221 }
211- if ( ! pkg . dependencies ?. zod ) {
212- pkg . dependencies = { ...pkg . dependencies , zod : '^4' }
222+ const optional = upstream . optionalDependencies
223+ if ( optional && Object . keys ( optional ) . length > 0 ) {
224+ stub . optionalDependencies = optional
213225 }
214- await writeFile ( pkgPath , `${ JSON . stringify ( pkg , null , 2 ) } \n` , 'utf8' )
215- execSync ( 'npm install --no-audit --no-fund' , {
226+ await writeFile ( join ( openclawRoot , 'package.json' ) , `${ JSON . stringify ( stub , null , 2 ) } \n` , 'utf8' )
227+ execSync ( 'npm install --no-audit --no-fund --legacy-peer-deps ' , {
216228 cwd : openclawRoot ,
217229 stdio : 'inherit' ,
218230 env : { ...process . env , NODE_ENV : '' } ,
@@ -374,8 +386,8 @@ export async function downloadAndBuildOpenClawControlUiAt(
374386 env : { ...process . env , NODE_ENV : '' } ,
375387 } )
376388
377- console . log ( ' [control-ui] npm install zod at openclaw root (for ../src/** resolution)...' )
378- await ensureOpenclawRootDepsForBundledSrc ( openclawRoot )
389+ console . log ( ' [control-ui] npm install OpenClaw root deps at openclaw root (for ../src/** resolution)...' )
390+ await ensureOpenclawRootDepsForBundledSrc ( openclawRoot , srcRoot )
379391
380392 console . log ( ' [control-ui] vite build → dist/control-ui' )
381393 execSync ( 'npm run build' , {
0 commit comments