feat: enhance desktop packaging process with self-contained harness verification
- Updated README and README.zh to clarify packaging commands and added verification step. - Improved packaging scripts to automatically build the self-contained runtime and verify its integrity. - Introduced new scripts for verifying harness self-containment and booting the web profile. - Added comprehensive tests for relinking harness symlinks and ensuring self-containment. - Updated package.json scripts to reflect new build and verification processes.
This commit is contained in:
+54
-10
@@ -101,11 +101,17 @@ override the spawned Node or `dsh` entry with `DSH_NODE` / `DSH_ENTRY`.
|
||||
## Packaging
|
||||
|
||||
```sh
|
||||
pnpm --filter @deepseek-ai/dsh-desktop run build:harness # (re)assemble the bundled runtime
|
||||
pnpm desktop:pack # electron-builder: mac .dmg / win .nsis
|
||||
pnpm desktop:pack # build lib+web, assemble the self-contained harness, then electron-builder: mac .dmg / win .nsis
|
||||
pnpm desktop:verify # prove the packaged app's harness is self-contained and boots
|
||||
```
|
||||
|
||||
Artifacts land in `apps/desktop/dist`.
|
||||
`desktop:pack` runs `build:harness` (assembling `build/harness`) automatically,
|
||||
so a stale or missing runtime can never be shipped. Artifacts land in
|
||||
`apps/desktop/dist`. `desktop:verify` rebuilds an unpacked app
|
||||
(`electron-builder --dir`) and checks that every symlink inside the packaged
|
||||
`resources/harness` resolves inside the bundle, then boots the web profile from
|
||||
it — the check that the installer is genuinely detached from the development
|
||||
machine.
|
||||
|
||||
### The self-contained harness (`build/harness`)
|
||||
|
||||
@@ -145,7 +151,9 @@ Each target platform needs its own harness: the bundled `bin/node` and the
|
||||
native addons are OS/arch-specific. Regenerate `build/harness` on each target
|
||||
platform (or per-target in CI) before packaging that platform. The current
|
||||
configuration targets **macOS arm64** (`mac.target: dmg`); `win.target: nsis`
|
||||
is declared but needs a Windows-built harness.
|
||||
is declared but needs a Windows-built harness. On Windows the harness build
|
||||
additionally needs Developer Mode enabled or an admin shell so workspace links
|
||||
can be rewritten to relative in-tree symlinks (see *Link correctness*).
|
||||
|
||||
### Signing
|
||||
|
||||
@@ -161,6 +169,38 @@ The bundled harness is multi-GB uncompressed (≈2 GB), dominated by
|
||||
~1 GB. This is the inherent footprint of shipping the full harness runtime
|
||||
standalone, and is the accepted trade-off for a zero-external-dependency app.
|
||||
|
||||
### Link correctness
|
||||
|
||||
The harness is held together by symlinks inside `node_modules` (pnpm workspace
|
||||
links). On **Windows**, pnpm often records those as **junctions — absolute-path
|
||||
reparse points pointing at the build machine's dev tree**. A plain directory
|
||||
copy keeps them verbatim, so a packaged app built that way reads the
|
||||
*development* tree when run on the build machine and dangles on any other
|
||||
machine.
|
||||
|
||||
`scripts/build-harness.mjs` therefore runs a relink pass
|
||||
(`scripts/harness-relink.mjs`) after copying, re-running it until no link changes
|
||||
(rewriting one link can expose another, so a single pass may not converge):
|
||||
every symlink/junction is rewritten to a **relative target inside
|
||||
`build/harness`** (mirroring the dev layout), any genuinely external target is
|
||||
dereferenced (copied in as real files), and a link to a workspace package the
|
||||
harness does not ship (e.g. the desktop shell itself, or a dependency-resolution
|
||||
member like `python/sdk-runtime`) is **dropped** — it cannot be mirrored and is
|
||||
not part of the runtime closure. The pass is followed by a self-containment
|
||||
check that **fails the build if any link still escapes the bundle**, and by a
|
||||
`dsh --version` smoke test.
|
||||
|
||||
To build you must be able to create directory symlinks: **Windows — enable
|
||||
Developer Mode or use an admin shell** (macOS/Linux need nothing). Without that
|
||||
capability `build:harness` refuses, because the only fallback (dereferencing the
|
||||
whole pnpm store) would balloon the ≈2 GB runtime to many times its size. A
|
||||
locked-down machine can opt into that anyway with `--dereference-ok`.
|
||||
|
||||
`pnpm desktop:verify` is the end-to-end check: it packs an unpacked app
|
||||
(`electron-builder --dir`) and re-runs the same link check against the packaged
|
||||
`resources/harness`, proving electron-builder's own `extraResources` copy kept
|
||||
the relative links intact, then boots the web profile straight from the bundle.
|
||||
|
||||
## Release process
|
||||
|
||||
The app is **not code-signed**, so updates are a manual-download flow rather
|
||||
@@ -192,14 +232,18 @@ bump it too if you keep them in sync, but only the desktop one is user-visible.
|
||||
### 2. Build and package
|
||||
|
||||
```sh
|
||||
pnpm --filter @deepseek-ai/dsh-desktop run build:harness # assemble the self-contained runtime
|
||||
pnpm desktop:pack # electron-builder: .dmg (mac) / .nsis .exe (win)
|
||||
pnpm desktop:pack # build lib+web, assemble the self-contained harness, then electron-builder: .dmg (mac) / .nsis .exe (win)
|
||||
pnpm desktop:verify # check the packaged harness is self-contained and boots
|
||||
```
|
||||
|
||||
Artifacts land in `apps/desktop/dist/`. Each target OS/arch needs its own
|
||||
harness (`build/harness` bundles a platform Node + native addons), so regenerate
|
||||
it on the target platform before packing that platform. Building the Windows
|
||||
`.exe` on macOS needs wine (or build on a Windows host).
|
||||
Artifacts land in `apps/desktop/dist/`. `desktop:pack` assembles `build/harness`
|
||||
first (`build:harness`), so a stale or missing runtime cannot be shipped. Each
|
||||
target OS/arch needs its own harness (`build/harness` bundles a platform Node +
|
||||
native addons), so regenerate it on the target platform before packing that
|
||||
platform. Building the Windows `.exe` on macOS needs wine (or build on a Windows
|
||||
host). Run `desktop:verify` on each platform you package: it rebuilds an
|
||||
unpacked app and proves the packaged `resources/harness` has no link escaping
|
||||
the bundle and the web profile boots from it.
|
||||
|
||||
### 3. Generate the update manifest
|
||||
|
||||
|
||||
Reference in New Issue
Block a user