@wujie-shell/core
v1.0.0
Published
`@wujie-shell/core` is the runtime and desktop infrastructure layer for `wujie-shell`. It prepares the OpenClaw runtime, generates/syncs OpenClaw configuration, starts the gateway, bridges gateway events, and provides the Electron main/preload implementat
Readme
@wujie-shell/core
@wujie-shell/core is the runtime and desktop infrastructure layer for
wujie-shell. It prepares the OpenClaw runtime, generates/syncs OpenClaw
configuration, starts the gateway, bridges gateway events, and provides the
Electron main/preload implementation used by product UI projects.
Responsibility
- Prepare
apps/<product>/.tmp/runtimefor the product. - Install or validate the configured OpenClaw version.
- Sync product Plugin, Agent, and Skill directories into the runtime.
- Generate and maintain
~/<dataDirName>/openclaw.json. - Start/stop/restart the OpenClaw gateway on product-specific ports.
- Maintain a gateway WebSocket client with device identity auth.
- Expose safe renderer APIs through Electron preload.
This package is shell infrastructure. It must not contain product UI business logic or hard-coded product asset lists.
Public Exports
import {
createConfigController,
createGatewayController,
ensureOpenClawDoctorFixed,
loadRuntimeInfo,
prepareRuntime,
runClawOnce,
spawnClaw,
} from '@wujie-shell/core'Runtime helpers are also exported from @wujie-shell/core/runtime.
Runtime Preparation
prepareRuntime(shellConfig, options?)
Prepares the product runtime at:
apps/<product>/.tmp/runtimeOptions:
{
syncOnly?: boolean
}Behavior:
- Builds or refreshes the product-local runtime base when needed.
- Validates Node runtime version.
- Installs the configured OpenClaw version when
prepareis used and versions differ. - Syncs runtime manifest plugin scope with
shell.config.mjs. - Copies product local plugins into
openclaw/dist/extensions. - Copies product agents into
openclaw/agents. - Copies product global skills into
openclaw/skills. - Writes
bin/wujieclawso OpenClaw uses the product data directory and config. The wrapper plays the Wujie startup logo animation (bin/wujie-logo.mjs, copied fromassets/wujie-logo.mjs) before exec'ing OpenClaw. It only runs on an interactive TTY and can be disabled withWUJIE_NO_LOGO=1. - Updates
runtime-manifest.jsonwith product metadata.
syncOnly: true does not install a new OpenClaw version; it builds any missing
runtime base files, then validates that the prepared runtime already matches the
configured OpenClaw version.
The desktop gateway startup calls ensureOpenClawDoctorFixed() before
launching OpenClaw. That check compares the embedded runtime version with a
shell-owned marker at ~/<dataDirName>/runtime-state/openclaw-doctor.json, then
runs openclaw doctor --fix when the user's persisted product state has not yet
been repaired for the current OpenClaw version. This covers packaged macOS and
Windows upgrades where the embedded resources/runtime/runtime-manifest.json
already belongs to the newly installed app bundle.
loadRuntimeInfo(projectRoot)
Reads and validates runtime-manifest.json, returning absolute paths:
{
runtimeRoot,
manifest,
openclawVersion,
nodeExecutable,
npmCli,
openclawWorkingDir,
openclawBin,
plugins
}spawnClaw(projectRoot, args, options?)
Spawns the prepared OpenClaw binary with runtime-aware env variables.
runClawOnce(projectRoot, args, timeoutMs?)
Runs OpenClaw once and resolves with:
{
code,
signal,
stdout,
stderr
}Config Controller
createConfigController(shellConfig) owns product OpenClaw config at
~/<dataDirName>/openclaw.json.
Important methods:
ensureConfigPathEnv()ensureInitialConfig()ensureGatewaySettings()readConfig()writeConfig(config)syncRuntimePlugins()getModelSettings()setModelSettings(settings, options?)setSelfOperatedModels(params)ensureAskUserQuestionPluginConfig({ callbackUrl, secret })watchConfigChanges()dispose()
The initial config includes:
- product model providers from
shell.config.mjs agents.defaults.workspace- memory and compaction defaults
- runtime plugin bootstrap entries
skills.load.extraDirs- session defaults
Model references must use provider/modelId. Display names must not be used as
request model IDs.
Gateway Controller
createGatewayController({ shellConfig, configController, appVersion }) owns
the OpenClaw gateway lifecycle.
Important methods:
start()stop()restart(reason?)runtimeInfo()getStatus()getRecentLogs(limit?)answerAskUserQuestion(payload)agents.list()skills.status(agentId?)sessions.create(payload?)sessions.list(payload?)sessions.delete(payload)chat.stream(payload)chat.abort(payload)chat.history(payload)
Events:
gateway-statusgateway-logchat-stream-eventsession-updatedagent-eventagents-updatedask-user-question
Gateway ports are allocated from shellConfig.ports.gatewayStart through the
next 99 ports.
Electron Integration
Electron main entry:
packages/shell-core/src/electron/main.mjsPreload entry:
packages/shell-core/src/electron/preload.mjsMain process responsibilities:
- Load product config from
WUJIE_SHELL_PROJECT_ROOT. - Create config and gateway controllers.
- Register IPC handlers.
- Register shell-owned desktop shortcuts.
- Broadcast gateway events to renderer windows.
- Load Vite dev URL or product
dist/index.html.
Renderer code should only use window.wujieShell, which is exposed by preload.
Do not import Electron IPC directly in UI code.
Shell-level DevTools ability:
- Shortcut:
CommandOrControl+Shift+I - Renderer API:
window.wujieShell.window.openDevTools() - Renderer event:
window.wujieShell.window.onDevToolsShortcut(listener)
CLI
The package exposes wujie-shell:
wujie-shell prepare --project apps/playground
wujie-shell sync --project apps/playgroundprepare can install/switch OpenClaw version. sync expects the prepared
runtime version to already match config and only syncs product assets/config
metadata.
Product Runtime Files
Generated files should not be hand-edited:
apps/<product>/.tmp/runtime/**~/<dataDirName>/openclaw.json~/<dataDirName>/runtime-state/**~/<dataDirName>/identity/device.json
Update the product config/assets, then run:
./scripts/desktop.sh --sync-onlyor restart:
./scripts/desktop.sh