@sdods/cli 0.2.2 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,170 +0,0 @@
1
- ---
2
- name: sdods-desktop-release
3
- description: Build, test, release and publish the SDODS desktop app (apps/desktop) for macOS, Windows and Linux, and update the download page on sdods.com. Use when asked to build the desktop app, cut a desktop release, tag desktop-v*, publish installers, refresh the download page, or debug a packaged build that will not start.
4
- ---
5
-
6
- # Releasing the SDODS desktop app
7
-
8
- The desktop app is an Electron **supervisor**: it owns a private SDODS workspace, installs
9
- `@sdods/cli` from npm into it, and runs `sdods serve` as a child of a **bundled Node runtime**. It
10
- does not reimplement SDODS and it does not host the server in-process.
11
-
12
- Read this before changing anything in `apps/desktop` — most of it is here because something failed
13
- in a way that produced no error message.
14
-
15
- ## The loop
16
-
17
- ```bash
18
- # 1. Prove the runtime contract (no Electron involved). Catches npm/init/native-module problems.
19
- bun run --cwd apps/desktop probe
20
-
21
- # 2. Develop
22
- bun run desktop:dev
23
-
24
- # 3. Package for this machine
25
- bun run --cwd apps/desktop dist:mac # dist:win · dist:linux
26
-
27
- # 4. Release
28
- git tag desktop-v0.1.0 && git push origin desktop-v0.1.0 # triggers .github/workflows/desktop.yml
29
- # ... workflow drafts a release in the PUBLIC releases repo; publish it by hand ...
30
- bun run desktop:sync-release desktop-v0.1.0 # writes apps/www/lib/desktop-release.ts
31
- git commit -am 'chore(www): desktop 0.1.0 downloads' && merge to main # www workflow deploys
32
- ```
33
-
34
- **Order matters.** Sync the manifest only after the release is *published*, not while it is a
35
- draft — the download page links straight at the asset URLs, and draft assets are not downloadable.
36
- The sync script refuses to run against a draft for exactly this reason.
37
-
38
- ## Where the binaries live, and why not in this repo
39
-
40
- `siri1410/SDODS` is **private**, and **release assets on a private repo are private too** — a
41
- GitHub download link would 404 for every visitor. So installers are published to a separate
42
- **public** repository that holds nothing but releases:
43
-
44
- ```bash
45
- gh repo create siri1410/sdods-releases --public -d 'SDODS desktop installers'
46
- ```
47
-
48
- Then, on the source repo: a `DESKTOP_RELEASE_TOKEN` secret (a fine-grained PAT with
49
- `Contents: read+write` on the releases repo **only** — `GITHUB_TOKEN` cannot write across
50
- repositories), and optionally a `DESKTOP_RELEASE_REPO` variable to point somewhere else.
51
-
52
- Source stays closed; only the built installers are public. This also keeps `electron-updater`
53
- straightforward later, since it reads GitHub releases natively.
54
-
55
- **Beware:** `git ls-remote https://github.com/siri1410/SDODS.git` **succeeds** on a machine with
56
- `gh auth` configured, because its credential helper is global. That is not an anonymous probe and
57
- it has produced the wrong conclusion here twice. Check visibility with
58
- `gh api repos/<slug> --jq .private`.
59
-
60
- ## Naming and versioning
61
-
62
- - **SemVer** on `apps/desktop/package.json`; the tag is `desktop-v<version>`, kept separate from
63
- the `@sdods/*` npm versions because the app ships on its own cadence.
64
- - **Every artifact says what it is**: `<product>-<version>-<platform>-<arch>.<ext>` —
65
- `SDODS-0.1.0-mac-arm64.dmg`, `SDODS-Setup-0.1.0-win-x64.exe`,
66
- `SDODS-0.1.0-linux-x64.AppImage`. electron-builder's defaults omit the platform on macOS, so
67
- `SDODS-0.1.0-arm64.dmg` could equally be a Linux build in a listing of six files.
68
- - **`SHA256SUMS.txt`** ships with every release. It matters more than usual while builds are
69
- unsigned: it is the only way a user can verify what they downloaded.
70
- `sha256sum -c SHA256SUMS.txt --ignore-missing`
71
-
72
- ## Verifying a build actually works
73
-
74
- A packaged build that starts is not the same as one that works. The real test is a run started
75
- from the app's own Runs page — that exercises `process.execPath`, the workspace layout and the
76
- browser cache at once.
77
-
78
- ```bash
79
- # Install like a user, then launch with NOTHING on PATH. This is the zero-prerequisite promise.
80
- env -i HOME="$HOME" USER="$USER" TMPDIR="$TMPDIR" PATH="/usr/bin:/bin:/usr/sbin:/sbin" \
81
- SDODS_DESKTOP_WORKSPACE=/tmp/sdods-test \
82
- /Applications/SDODS.app/Contents/MacOS/SDODS
83
- ```
84
-
85
- Then: Runs → Start run → layer `ui`, browser `chromium`, tags `@smoke` → Run. It should pass 4/0/0.
86
-
87
- Useful env vars:
88
-
89
- | Variable | Purpose |
90
- |---|---|
91
- | `SDODS_DESKTOP_WORKSPACE` | Override the `~/SDODS` default. Always set this when testing, or you litter the real home directory. |
92
- | `SDODS_DESKTOP_NODE` | Point at a specific `node` binary instead of the staged/system one. |
93
-
94
- Logs: `~/Library/Application Support/SDODS/logs/desktop.log` (menu → Open Logs Folder). App state
95
- lives beside it; `rm -rf` that directory for a clean first-run test.
96
-
97
- ## Traps — each one cost a debugging session
98
-
99
- **Never spawn `process.execPath`.** Under Electron that is the Electron binary, so spawning it
100
- launches a second copy of the app, which hits the single-instance lock and dies **silently**. Use
101
- `nodeBin()` from `src/main/runtime.ts`. Same reason the server is a child process rather than
102
- in-process: `packages/server/src/services/cli.ts` builds every child argv from `process.execPath`.
103
-
104
- **Never spawn `npm` by bare name.** Windows has `npm.cmd`, not `npm`, and a GUI app launched from
105
- the Dock inherits a minimal PATH. Use `npmCli()`, which resolves npm's own entry point.
106
-
107
- **A missing `extraResources` source is only a warning.** It once produced an x64 `.dmg` with no
108
- Node runtime and a zero exit code. `scripts/before-pack.mjs` stages the runtime per arch and fails
109
- hard; `desktop.yml` re-checks every packaged app. Do not remove either.
110
-
111
- **Signals do not fire in the packaged app.** A SIGTERM runs none of `before-quit`, `will-quit`,
112
- `exit`, or `process.on('SIGTERM')` — Electron terminates natively — so the detached server child
113
- outlives the app. The guarantee is the pidfile: the server's pid is recorded and the next launch
114
- reaps it. Test it with `kill -9` on the app, not `kill`.
115
-
116
- **Browsers are needed for every layer, not just UI.** SDODS merges one BDD fixture set across
117
- layers, so an api-layer run against an empty `PLAYWRIGHT_BROWSERS_PATH` fails with
118
- `browserType.launch: Executable doesn't exist`. Chromium is fetched after the dashboard loads.
119
-
120
- **`sdods init` needs `--force --no-install --no-browsers`.** It refuses a non-empty directory,
121
- its `--pm` accepts only `bun|pnpm` (neither is on a user machine), and it would pull browsers. It
122
- overwrites `package.json` on purpose — its manifest declares `@playwright/test` and
123
- `playwright-bdd`, which `sdods run` needs — so npm install runs again afterwards.
124
-
125
- **`@sdods/server@0.2.1` hardcodes `cliBin: resolve(rootDir, 'packages/cli/src/bin.ts')`**, a
126
- monorepo-only path, so UI-triggered runs die with ERR_MODULE_NOT_FOUND. `bootstrap.ts` writes a
127
- bridge at that path, but only while the installed server still contains that string. **Publishing a
128
- server newer than 0.2.1 removes the need for it** and fixes `sdods serve` for every npm user.
129
-
130
- **Do not build the macOS `universal` target.** It lipo-merges two packs that each want a different
131
- `node` binary at one path. `before-pack.mjs` rejects it. Ship separate arm64 and x64 artifacts.
132
-
133
- **`apps/desktop` must declare no production dependencies.** electron-builder's dependency collector
134
- has no handling for bun's `node_modules/.bun` symlink layout. Everything is bundled by rollup and
135
- `files` excludes `node_modules` outright. Adding a runtime dependency will break packaging.
136
-
137
- ## Browser architecture detection on the download page
138
-
139
- An Apple silicon Mac reports `Intel Mac OS X` in its user agent. Parsing the UA alone recommends
140
- the Intel build to nearly every modern Mac. `detectArch()` uses
141
- `navigator.userAgentData.getHighEntropyValues(['architecture'])`, which is truthful on Chromium;
142
- Safari and Firefox return nothing, so macOS defaults to Apple silicon deliberately. Every other
143
- build is listed underneath, and the full list is server-rendered so no-JS visitors lose nothing.
144
-
145
- ## Signing
146
-
147
- Builds are unsigned today, so macOS shows "damaged / unidentified developer" and Windows shows
148
- SmartScreen. The download page prints the per-OS workaround automatically while
149
- `DESKTOP_RELEASE.signed` is false.
150
-
151
- Everything is wired behind CI secrets already — supply them and signing turns on with no code
152
- change: `CSC_LINK`, `CSC_KEY_PASSWORD`, `APPLE_ID`, `APPLE_APP_SPECIFIC_PASSWORD`, `APPLE_TEAM_ID`
153
- for macOS; `WIN_CSC_LINK`, `WIN_CSC_KEY_PASSWORD` for Windows. Obtaining the certificates requires
154
- a person: Apple Developer Program ($99/yr), and for Windows **Azure Trusted Signing** (~$10/month)
155
- rather than a traditional OV certificate, which has required an FIPS hardware token since June 2023
156
- and does not fit CI. After signing lands, pass `--signed` to `desktop:sync-release`.
157
-
158
- ## Files
159
-
160
- | Path | What it is |
161
- |---|---|
162
- | `apps/desktop/src/main/index.ts` | Lifecycle: bootstrap → serve → authenticate → load. Pidfile and orphan reaping. |
163
- | `apps/desktop/src/main/runtime.ts` | Bundled Node resolution and the child environment. |
164
- | `apps/desktop/src/main/bootstrap.ts` | The five-step first-run install, and the 0.2.1 CLI bridge. |
165
- | `apps/desktop/src/main/server.ts` | Port choice, `sdods serve` child, health poll, setup-token capture. |
166
- | `apps/desktop/src/main/auth.ts` | Admin creation, safeStorage vault, cookie injection. |
167
- | `apps/desktop/scripts/probe.ts` | The runtime contract, provable without Electron. |
168
- | `apps/desktop/scripts/fetch-node-runtime.ts` | Downloads + SHASUMS-verifies + prunes Node. |
169
- | `scripts/sync-desktop-release.ts` | GitHub release → `apps/www/lib/desktop-release.ts`. |
170
- | `.github/workflows/desktop.yml` | Tag-gated matrix build, artifact verification, draft release. |