0.1.3
Fixes the Windows window (blank / "not responding"), adds the Linux → Windows
cross-compilation toolchain, titleBarOverlay (native window buttons inside
the custom titlebar) on Linux, and a Node bridge to expose Node to the UI
without IPC by default. It also adds Block A of execution/IPC: Node workers
with a channel, windowId in handlers, targeted webContents.send and
MessageChannel/MessagePort. Plus Block B: protocol (custom schemes),
safeStorage (DPAPI / AES-GCM), theme (nativeTheme) and session permissions;
and the Node sidecar now dies with the kernel. And Block C (app shell): C1
full app (paths/identity/commandLine/events), C2 full dialog, C3
webContents (objects + events + capturePage), C4 nativeImage (PNG codec
with no deps), C5 Menu/MenuItem, C6 Tray, C7 nativeTheme,
C8 print/printToPDF, C9 full BrowserWindow (options/state/geometry/
events) and C10 screen/Display (multi-monitor + events) and
powerMonitor (power).
Added
- Linux → Windows cross-compilation:
clang-cl+lld-linkwith the MSVC/Windows SDK fetched byxwin(cmake/windows-cross.cmake). Producesowear.exe+ modules from Linux, with no Visual Studio and no CI. The.exeis built with a static CRT (/MT) and static deps → no VCRUNTIME or extra DLLs. OW_WITH_OPENSSLoption (default ON): withOFFthe kernel uses a TLS-less HTTP stub (Runtime/Http_nossl.cpp) and omits thenet/updatermodules. Meant for the development cross-build.tools/windows-cross/build-deps.sh(cross-build of zlib),build.sh,serve.shandtools/windows/dev-pull.ps1(push to Windows over HTTP).titleBarOverlay— native buttons inside the custom titlebar (Linux + Windows):- API:
titleBarOverlay: true | { height, color, symbolColor, buttonColor }inBrowserWindowOptionsandwin.setTitleBarOverlay(...); control commandwindow.setTitleBarOverlay. The reserved gap is exposed to the renderer aswindow.__owTitlebarOverlay = { enabled, height, width }. - On Linux they are the theme's buttons (
titlebuttonclass, freedesktop symbolic icons): size, style, hover and spacing come from the distro (nothing hardcoded). They are overlaid with aGtkOverlay. - Glyph color (
symbolColor), band background (color) and inner circle background (buttonColor) are configurable; by default, the theme's. - Theme window shadow via CSD (empty 0px titlebar) and rounded corners
on the web content (
clip-path+border-radius) with the radius read from the theme (decoration { border-radius: N }). - Resize on Wayland:
GtkEventBoxzones on edges/corners (the GDK filter is X11-only, it doesn't fire on Wayland). - Windows (WebView2): WORKS NOW. The min/max/close buttons are drawn by
hand with GDI+, identical to Electron (
windows_icon_painter.cc): icon 10px, min/max/restore without anti-aliasing and a 0.5-inset rect, restore = two 8px squares offset by 2, close = X with AA. They are drawn in a top-level layered popup (UpdateLayeredWindow) with an alpha=1 background (imperceptible) so the hit-test covers the whole rect → exact hover/press. Real transparent background (the titlebar shows through).
- API:
- Node bridge (
node) — the renderer can use Node without IPC by default:ow.invoke('node', 'call', { fn, args })runs a main-process handler registered withapp.handle(fn, handler); the main replies and can push events withapp.send(name, payload?, windowId?)→ow.on(name).- Asynchronous resolution (the kernel forwards
node.requestto the main over the control socket; the main answers withnode.respond). Modularized with theapi/node/owear.module.jsonmanifest (builtinnode,callfunction). - Opt-in: hot paths (fs, terminal/PTY…) still go straight renderer → kernel → native module, with no Node in between. Meant to expose Node to the UI (e.g. VS Code's extension host).
- Block A — execution and IPC (workers, context, webContents, MessagePort):
- Node workers with a channel (
app.forkWorker) — a replacement forutilityProcess.fork: the main process (already real Node) spawns a child with an IPC channel (child_process.fork) and aprocess.parentPortshim so workers ported from Electron work unchanged. CLI:app/workers/**is compiled toworkers/and exposed inOW_APP_WORKERS(ow dev/ow build);app.workersDir(). API:postMessage/on(message|exit)/kill/pid. windowIdin Node handlers — the kernel propagates the source window to the main and the SDK exposes it withapp.handleContext(fn, (ctx, ...args) => …)(ctx.windowId).app.handleis unchanged (additive).- Targeted
webContents.send—win.webContents.send(name, payload)in the SDK (Electron parity) sends ONLY to that window; the renderer receives it withow.on(name, cb). MessageChannel/MessagePort(app.createChannel) — a bidirectional main ↔ renderer channel without registering per-call handlers:app.sendPort(windowId, name, port)transfers one end; in the rendererow.port(id)(bridge) receives it withow.on(name, ({ port }) => …). Routed by the bridge; the zero-copy binary transport kernel→renderer is stillow-shm://.- N-API native modules: documented in
docs/NATIVE.md(real Node runtime → N-API addons and Node prebuilds load as-is; Electron binaries must be rebuilt for Node). - Tests:
@owear/corenow usesnode --test(packages/core/test:forkWorkerround-trip/exit andcreateChannelmain↔main). Also verified E2E on Linux (Xvfb): worker,windowId,webContents.sendand the renderer↔main port.
- Node workers with a channel (
- Block B — protocol / data / OS (
protocol,safestorage,theme,session):protocol(custom schemes) — the main registers a scheme and the kernel serves it with a main-process handler or a directory:app.protocol(name, { privileged, serve, handler }). The handler may return aResponse,{status, headers, body}or astring. Linux: dynamic registration in WebKitGTK with asyncfinish; Windows:WebResourceRequested+ deferral. Verified on Linux (handler andserve).safeStorage(api/safestoragemodule) —isAvailable,encrypt→{data, encrypted},decrypt(accepts plain text). Windows: DPAPI; Linux: AES-256-GCM with a local 0600 key in the app data dir. SDK:ow.safeStorage. Verified on Linux (round-trip + key persistence).theme(nativeTheme) (api/thememodule) —get/isDark/setSource(system|light|dark)/watch/unwatch+ thetheme.changedevent. Linux: GSettingscolor-scheme+ GTK theme; Windows: theAppsUseLightThemeregistry (watch by polling). Forcing the content:theme.setSource→ kernelwindow.setColorScheme→ Windows WebView2PreferredColorScheme(changes the realprefers-color-scheme); on Linux WebKitGTK does not expose forcing it (the app reacts totheme.changed). SDK:ow.theme(+ aliasow.nativeTheme). Verified on Linux (read/events); Windows compiles.session— WebView permissions —session.onPermissionRequest(handler)(denies if there is no handler).PermissionBrokerin the kernel + thesession.setPermissionHandler/session.respondPermissioncommands. Linux: WebKitGTK'spermission-requestsignal; Windows:add_PermissionRequestedwith deferral. Verified on Linux (geolocation).session— partitions (profiles) —session.fromPartition(name)+BrowserWindow({ session })isolate cookies/localStorage/IndexedDB/cache per profile. Linux: a data dir per partition (…/webkit/<partition>/{data,cache}); Windows: a profile per partition (…\owear\WebView2\<partition>). Verified on Linux:persist:aandpersist:bdo not sharelocalStorage; two windows of the same partition do.session—webRequest(onBeforeRequest: cancel/redirect) —webRequest.onBeforeRequest({ urls }, handler). Windows: all requests (WebResourceRequested+ deferral). Linux: navigations (decide-policy); WebKitGTK 2.52 no longer exposessend-request, so subresources cannot be intercepted on Linux (documented). Verified on Linux (navigation blocking).- Pending for session (roadmap):
webRequest.onHeadersReceivedand (Linux) subresources — blocked by the WebKitGTK API.
- Sidecar lifecycle — the Node process dies with the kernel:
Linux/macOS
PR_SET_PDEATHSIG(SIGTERM)+NodeManager::ShutdownSidecar()(SIGTERM and, if it doesn't exit, SIGKILL); Windows Job ObjectKILL_ON_JOB_CLOSE+TerminateProcess. Verified on Linux: afterapp.quit()the sidecar PID is gone. docs/extra/probar-en-starter.md— a living guide (WIP) on how to test each system in the starter (Linux + Windows), to be filled in over time.- Block C — app shell (started with C1):
- Full
app—getPath/setPath(home, appData, userData, temp, cache, logs, downloads, documents, desktop, pictures, music, videos, exe, appPath),getName/setName,getVersion(frompackage.json),isPackaged,getAppPath,commandLine(appendSwitch/appendArgument/getSwitchValue/hasSwitch, applied when creating the WebView: WindowsAdditionalBrowserArguments; Linux best-effort) and events (window-all-closed,before-quit,will-quit,second-instance,child-process-gone). Kernel: extendedapp.info(name/appPath/exePath/ packaged),app.setName,app.commandLine.*. SDK:appis an EventEmitter. Verified on Linux (paths, identity,commandLineand the 3 events); Windows compiles. - Full
dialog(C2) —showOpenDialog(properties:openFile/openDirectory/multiSelections/showHiddenFiles,filters,defaultPath,buttonLabel→{ canceled, filePaths }),showSaveDialog(filters,defaultPath→{ canceled, filePath }) andshowMessageBox(type,message/detail,buttons,defaultId,cancelId,checkboxLabel→{ response, checkboxChecked }). Linux: GtkFileChooser + GtkMessageDialog (with checkbox); Windows:IFileOpenDialog/IFileSaveDialogTaskDialogIndirect. SDK:ow.dialog. Registered on Linux (5 functions); Windows compiles. (open/messageBoxare kept.)
webContents(C3) —win.webContentsis an Electron-style object:send,capturePage()(PNG →{toPNG(), toDataURL()}; the kernel returns base64 with{base64:true}),loadURL,reload,openDevTools,getURL,getTitle,executeJavaScript, andsetWindowOpenHandler(allow/denywindow.open). Events with Electron names:did-finish-load,did-fail-load,did-start-navigation,did-navigate,page-title-updated,before-input-event(keyboard: WebKitGTKkey-press/release-event; WebView2AcceleratorKeyPressed). Kernel: an event sink in the backend + a popup broker (WindowOpenBroker) +capturePage{base64}. Verified on Linux (did-finish-load,capturePage,getURL); Windows compiles.nativeImage(C4) — no native dependencies: a PNG codec in the SDK (Nodezlib) supporting colorType 0/2/3/4/6 and bitDepth 1/2/4/8/16.nativeImage.createFromPath/createFromBuffer/createFromDataURL(synchronous like Electron) +getSize,isEmpty,toPNG,toDataURL,resize(bilinear),crop. JPEG:getSize(SOF) andtoJPEG(if the source is already JPEG).webContents.capturePage()now returns aNativeImage. Verified (SDK tests).Menu/MenuItem(C5) — polished Electron-style API in the main:Menu.buildFromTemplate([...]),setApplicationMenu/getApplicationMenu,menu.popup({ window, x, y }).MenuItem:id,label,role(quit, minimize, close, reload, toggleDevTools, undo/cut/copy/paste/selectAll…),type(normal/separator/submenu/checkbox/radio),checked,enabled,visible,accelerator(display),submenu,click(item, window). Clicks go to the main (clickhandlers + roles). Kernel: a shared template (ow/Menu.hpp) with types/states; Linux GTK (GtkCheck/RadioMenuItem) and WindowsHMENU(popupTrackPopupMenu+ menubar viawindow.setApplicationMenu+WM_COMMAND). SDK tests; Windows compiles.Tray(C6) — full tray icon (Tauri/Electron intermediate API):new Tray(image?),setImage,setPressedImage,setToolTip,setTitle,setContextMenu(Menu),popupContextMenu,destroy, andclick/right-click/double-clickevents. Icon =NativeImageor a path → PNG base64 to the kernel. Linux: native SNI (GDBus) —org.kde.StatusNotifierItem+com.canonical.dbusmenuimplemented by hand (no libraries), registered with theStatusNotifierWatcher(GNOME/Zorin with the extension, KDE, XFCE+plugin) →docs/extra/GNOME.md. Windows:Shell_NotifyIconwith a context menu (TrackPopupMenu), events and PNG→HICON via GDI+. The menu reuses the C5 template. Verified on Linux (registration + lifecycle); Windows compiles.print/printToPDF(C8) —win.webContents.print()(system dialog) andwin.webContents.printToPDF()(→ PDFBuffervia the asyncwindow.printToPDFcommand). Windows: WebView2PrintToPdf+ShowPrintUI(vector). Linux:printwithWebKitPrintOperation(dialog) andprintToPDFvia a full-page snapshot → Cairo PDF (rasterized; WebKitGTK exposes no PDF API, and GTK's "Print to File" backend blocks). Verified on Linux (%PDF, ~2.4 KB); Windows compiles.- Full
BrowserWindow(C9) — options:parent,modal,transparent,backgroundColor,movable,minimizable,maximizable,closable,fullscreenable,skipTaskbar,alwaysOnTop,hasShadow,min/maxWidth/Height,aspectRatio,show. Methods: getters (isVisible,isFocused,isResizable,isMovable,isMinimizable,isMaximizable,isClosable,isAlwaysOnTop,isKiosk,isDestroyed,isFullScreen), setters (setResizable/Movable/Minimizable/Maximizable/Closable,setAlwaysOnTop(flag,level),setSkipTaskbar,setHasShadow,setKiosk,setIgnoreMouseEvents,setProgressBar,setBackgroundColor,moveTop,setAspectRatio), geometry (getContentBounds/Size,setContentSize,get/setMinimumSize,get/setMaximumSize) and the staticsgetAllWindows,getFocusedWindow,fromId. Events with Electron names (dashed):enter-full-screen,leave-full-screen,always-on-top-changed,page-title-updated,show,hide,restore,minimize,resized,moved(+ the earlier camelCase ones). Linux (GTK) and Windows (Win32: styles,SetWindowPos,ITaskbarList3,WS_EX_TRANSPARENT,WM_SIZING/WM_GETMINMAXINFO). Verified on Linux; Windows compiles.
- Full
- Embedded webviews (
webview, Linux) — each window can have N child WebViews, each with its own process, embedded and controllable via API:- Builtin
webview(api/webview/owear.module.json, Linux + Windows):create, destroy, setBounds, load, back, forward, reload, stop, canBack, canForward, getURL, getTitle, eval, setVisible, setZoom, devtools, findInPage, findStop. - Renderer:
ow.invoke('webview', 'create', { url, x, y, width, height })+ow.on('webview.loadChanged|urlChanged|titleChanged|loadFailed')events. - Linux (WebKitGTK): each child in its own overlay container (it only intercepts its rectangle) + a shared WebKit context with a per-app data dir and one WebProcess per view; the base for Windows/macOS.
- Windows (WebView2): each child in its own child HWND + a WebView2
controller parented there (reliable z-order/bounds); an environment with its
own user data dir.
titleBarOverlayon Windows draws the Win10/11-style buttons (GDI+, layered window: only glyphs/hover over the titlebar) and exposes__owTitlebarOverlayto the renderer. - Automatic focus: children do not steal focus while loading (they start
with
can_focus=FALSE); a click on a child gives it focus and a click outside the children returns it to the main one.
- Builtin
examples/starter: redesign in progress (WIP) — fonts, a container-based layout and use of the new APIs (titleBarOverlay, embedded browser).- Block C — C10
screen/Display+powerMonitor(multi-monitor and power):screen(module, Linux + Windows):getAllDisplays,getPrimaryDisplay,getCursorScreenPointwith a full Display (id,bounds,size,workArea,workAreaSize,scaleFactor,rotation,internal,label,displayFrequency,colorDepth,depthPerComponent,colorSpace,monochrome,touchSupport,accelerometerSupport,detected,nativeOrigin), a stable id (Windows: hash ofszDevice; Linux: fromGdkMonitor*) andscreen.added/screen.removed/screen.changedevents withwatch/unwatch. Windows: a hidden top-level window on its own thread forWM_DISPLAYCHANGE; Linux:GdkDisplaysignals andnotify::geometry|workarea|scale-factor.power(module, Linux + Windows):monitorStart/monitorStopandpower.suspend/resume/shutdown/lock/unlock/ac/batteryevents;idleTime,idleStateandisOnBattery;inhibitStart/inhibitStopinhibitors. Linux: logind (PrepareForSleep/PrepareForShutdown/Session Lock/Unlock) + UPower (with a/sysfallback) + X11 Xss (dlopen, Wayland →unknown). Windows: a hidden window withWM_POWERBROADCAST/WM_ENDSESSION+WTSRegisterSessionNotification(lock/unlock) +GetLastInputInfo+GetSystemPowerStatus.- SDK:
screen(EventEmitter:added/removed/changed,getAllDisplays,getPrimaryDisplay,getCursorScreenPoint,getDisplayNearestPoint,getDisplayMatching,screenToDipPoint/dipToScreenPoint+ aliases),powerMonitor(EventEmitter:suspend/resume/shutdown/lock/unlock/ac/battery,getIdleTime,getIdleState,isOnBatteryPower,onBatteryPower) andpowerSaveBlocker(start/stop/isStarted). Lazy watch on first use. Module events are re-emitted by name on the channel (app.__channel.on('screen.added', …)).
- Dev:
OW_TITLEBAR_OVERLAY[=_HEIGHT]to test the overlay withOW_DEMO=1. - A build marker in the kernel log (
OWEAR KERNEL BUILD ...) andPCreate: style=... custom=...for diagnostics.
Fixed
- Blank / "not responding" window on Windows: the WebView2 controller
was not resized on
WM_SIZE(it kept invalid bounds). It now callsResizeon everyWM_SIZE. WM_NCCALCSIZEwith a custom titlebar now applies the frame insets (the Electron technique) instead of returning0outright, which broke the edge hit-testing on Windows 10.- DPI awareness (
PER_MONITOR_AWARE_V2before creating windows). - Modules loaded twice:
ModuleLoader::SearchPathsdeduplicatesOW_MODULES_DIRvs<exe>/modules. - WebView2 lifecycle diagnostics:
environment → controller → navigate(URL, bounds,nav completed,ProcessFailed) andput_IsVisible(TRUE). - Windows 10: the native caption still showed with a custom titlebar. It now
keeps
WS_OVERLAPPEDWINDOW(so Win11 corners/shadow aren't lost) and the caption is removed withWM_NCCALCSIZEre-applied withSWP_FRAMECHANGED(the firstWM_NCCALCSIZEruns insideCreateWindowEx, before the window state exists). - Linux: ghost gap above the content (the theme applies its
min-heightto the empty CSD.titlebarclass) → cancelled with CSS in the titlebar's own context. - Linux: the content rounding wasn't visible → the
bodybackground propagates to the canvas and is painted square; the root is now clipped withclip-path: inset(0 round Npx)(N = theme radius). - Linux: the overlay colors didn't apply → in GTK3 a style provider on a
widget only affects that widget (not its children); it is now registered at the
screen level with per-
idselectors. - Linux: WebView storage isolated per app → the WebKitGTK backend used the
default
WebsiteDataManager(shared between apps), solocalStorage/IndexedDB/cache could mix. It now uses a data manager with a per-app base dir ($XDG_DATA_HOME/owear/<app-id>/webkit/{data,cache}) and registersapp://as a secure + CORS scheme (stable origin). - Slow close on Linux and Windows: the veto flow (
closeRequested) always waited forOW_CLOSE_TIMEOUT_MS(~1s) even when the app wasn't listening. Now, if the renderer has no listener forcloseRequested, it answersallowinstantly → the window disappears immediately. With a listener, the veto keeps its timeout. - Windows:
dialog.dlldid not load (STATUS_ENTRYPOINT_NOT_FOUND/ err 182): it importedTaskDialogIndirect(comctl32) statically and, without a v6 manifest, the whole DLL failed. It is now resolved dynamically (GetProcAddress) and falls back toMessageBox. - Windows: stale / double-loaded modules →
ModuleLoadernow prefers<exe>/modules(same build as the kernel) and deduplicates by name, so an old runtime package inOW_MODULES_DIRno longer wins (no more "unknown function"). - Dev in the monorepo: stale modules → the CLI (
stockModulesPath) prefers the local build over the prebuilt runtime package (a git-ignored artifact that may be old). - Windows:
capturePagecrashed (ACCESS_VIOLATION): the synchronouscapturePagedid a nested message pump that re-entered. Capture is now asynchronous via a control command (window.capturePage), with no nested loop. - Linux:
menu.popupgaveGtk-CRITICAL: no trigger event(the popup arrives from an async click, with no GDK event): it is now placed withgtk_menu_popup_at_rectover the root window with a synthetic trigger event. - Orphan Node sidecar: the main process's Node process now dies with the
kernel (
PR_SET_PDEATHSIGon Linux/macOS +ShutdownSidecar; Job ObjectKILL_ON_JOB_CLOSEon Windows), with room to deliverbefore-quit/will-quitbefore terminating it. - Windows: hang/crash on repeated theme changes → a data race in the
thememodule (g_source, astd::string, written by the main and read by thewatchthread) → now guarded with a mutex. Andwindow.setColorSchemewas after the block requiringwindowId(which the SDK doesn't pass) → it never appliedPreferredColorScheme; moved → it now really changes the actualprefers-color-scheme. BrowserWindow.getAllWindows/getFocusedWindowwere local to the SDK → now synchronous and resolved from the SDK's registry (focus viafocus/blurevents), like Electron. They previously used new kernel commands that hung the window on Windows (the starter's "Ventanas" button).- Windows: hang with fast clicks (high load) — two causes:
- The control pipe called
CancelIoEx(pipe, nullptr)when queueing each response, which cancels all I/O on the handle, including in-flight writes from the reader thread → truncated responses that desync the SDK's protocol (aninvokethat never resolves = a hung window). Also, if the reader wasn't yet blocked inReadFile, the response was stranded. The reader now polls withPeekNamedPipe(drains the outbox in ~1 ms) and only writes when there is no pending read. - The main loop queued one
kWmOwPumpper callback → a burst of N callbacks produced NGetMessagepasses (N-1 empty). There is now a single pump in flight (atomic+ re-arm after draining).
- The control pipe called
Optimization (Owear vs Electron vs Tauri benchmarks)
Measured with our own harness (benchmarks/). Performance changes:
- Bridge without
eval— RPC over theow-rpc://scheme: the renderer calls native modules (.owm) withfetch(args in the POST body, response in the body) → removes the requestpostMessageand theexecuteJavaScriptresponse (the engine no longer compiles code per call). Linux and Windows (WebView2). Sequential IPC ~2×, concurrent ~4-5×, 5 MB payload ~1.5×. - Large payload over SHM (
_applyShm+ow-shm://) on the postMessage path. - Span-scanner codec: without building the message DOM or re-serializing the
args on every
invoke. - Startup:
OW_GPU=auto|on|off(WebKit acceleration policy);offdisables the DMABUF renderer → −~300 ms and −30 MB headless (defaultauto).T+msmarks (Log::StartupBegin/StartupMark) to profile startup withoutstrace.- Window visible earlier before injecting/loading (
PShowmoved): fromT+371toT+183 ms.
- SHM fix: immediate
unlinkaftermmap(Linux) + sweeping orphan regions. A crash leftowear-shm-*inXDG_RUNTIME_DIR; 543 files filledtmpfs→ SIGBUS when reading a 5 MB SHM block.
Distribution — D1 (single binary) — in progress
- A single binary:
tools/owear-pack.mjspacks a bundle (app/,modules/,manifest.json) inside the kernel → one file (MiApp;.exeon Windows). Format:[kernel][payload.tar.gz][OWPK1 footer]. src/Pack: the kernel reads its own image, extracts the payload to cache (idempotent) and exposesOW_MODULES_DIR/OW_ASSETS_DIR/OW_APP_MAINto the content → the rest of the kernel is unchanged. Node is NOT embedded: it is resolved/installed separately (system detection or download).- fix(tar): the extractor put the 512 B padding inside the file (broke
.js; Node "worked" because it's an ELF with trailing zeros). - fix(app://):
app://index.htmltreated the name as a host and relative resources 404'd; nowapp://host/pathservespath. - D1 pending:
installermodule + SDK, custom UI (owear.installer),ow package(Linux/Windows installers, same binary = installer + app),owear.pack.order/protect(API order/security inside the binary).
D1 — Modular installers (included in 0.1.3)
The installer is a separate Owear app that embeds the app payload and a
contract bridge; it is built into an installer binary and the installed
result can be a single binary (minimal) or an organized tree (layout). The
uninstaller is another binary with the same bridge.
Added
installerbuiltin (src/api/installer,kind=builtin): native API for installer/uninstaller mode.mode·info·bridge·payloadList·payloadReadplan·install·uninstall·verify·stateshortcuts·launch·elevate- Platform integration: Linux (
.desktopin applications/desktop/autostart) and Windows (IShellLink+ uninstall registry entry underHKCU\...\Uninstall).
- Installer mode in the kernel: on startup, if the embedded payload contains
installer.jsonoruninstaller.json, the kernel setsOW_MODE(installer/uninstaller), servesui/as assets (OW_ASSETS_DIR), exposes the installer sidecar (OW_APP_MAIN) and publishes metadata (OW_APP_VERSION/OW_APP_ID/OW_APP_NAME). - Bridge (
owear.bridge.ts): a data-only contract app ↔ installer ↔ uninstaller. It is written withdefineBridge()from@owear/core(with validation) andow build installercompiles it and embeds it asbridge.jsonin the installer binary. It defines the app, per-platformtargets(format, layout, preset, dir, shortcuts, scope),order,protect,nodeandhooks. - SDK
@owear/core: a newinstallerAPI (mode/info/bridge/payloadList/ payloadRead/plan/install/uninstall/verify/state/shortcuts/launch/elevate) anddefineBridgewith full types. - CLI:
ow create installer [dir]andow create uninstaller [dir](templates).ow build app [--format binary|deb|appimage](app payload).ow build installer [--mode minimal|layout]→ installer binary.ow build uninstaller→ uninstaller binary.
tools/owear-installer.mjs: assembles the installer payload (ui/,payload/,bridge.json,installer.json,modules/) and packs it inside the kernel using the existingOWPK1format.- Templates:
packages/cli/template-installer/(vanilla UI + Node sidecar) and itsuninstaller/sub-template (same bridge, uninstalls). - Schemas:
schemas/owear.bridge.schema.jsonandschemas/owear.pack.schema.json. - Linux app formats (
ow build app --format):deb: a real.deb(ar +control.tar.gz+data.tar.gz) generated in Node, with no external dependencies; installs to/opt/<slug>+ a launcher in/usr/bin+.desktop.appimage: anAppDir(AppRun +.desktop+ icon) packed withappimagetoolif available.
- Windows
.MSI:ow build app --format msigenerates a WiX v3 source from the stage and compiles it withwixl(msitools) orwix; if there is no toolchain, it leaves the.wxsready. protect(integrity + flags) applied by theinstallerbuiltin:hiddenhides groups from the plan/listing andreadonlysets read-only permissions on install (on top of the manifest integrity hashes).- Bridge hooks:
preInstall/postInstall/preUninstall/postUninstallare emitted as theinstaller.hookevent during install and uninstall.
Payload modes
minimal(default): the payload is a single binary (kernel + app), produced withowear-pack; the installer copies it and creates shortcuts.layout(aliasdivider): a folder tree (app/,modules/,manifest.json, …) placed at the destination, with order/preset viaorderandlayout(flat/tree).
Changed
src/Core/App/Internal.cpp: payload startup distinguishes installer / uninstaller / single-binary app.ow --help: documentscreate installer|uninstallerandbuild app|installer|uninstaller.tools/gen-apis.mjsregenerated (24 APIs: 17 modules + 7 builtins).
Fixed
- The
installerbuiltin unwraps the dispatcher args (they arrive as an array; the first object is used).
Notes
- Verified end-to-end over the control socket:
mode → plan → install → state → verify → uninstall(it really installs/uninstalls at the destination), andprotect/hooks(hides + read-only +installer.hookevents). - Pending: optional real payload encryption (
protectis currently integrity- flags), and macOS (no toolchain in the dev environment).