Commit 04b26cf
authored
fix(desktop): pin the Host port and stop reporting non-updatable builds as errors (#87)
## Related Issue
No issue — both defects were reported directly from the packaged app.
## Problem
**1. Every launch was a fresh browser profile.**
`spawnPythinkerServer` started the Host with `--port 0`, so the window
loaded
`http://127.0.0.1:<random>` on every launch. `localStorage` is keyed by
origin, so the web UI read an
empty store each time.
The visible symptom was the first-run onboarding dialog appearing on
every launch, but it was never
an onboarding bug — **every** persisted preference was being discarded:
theme, colour scheme, UI font
size, permission mode, thinking level, plan mode, dynamic-workflow and
goal mode, starred models,
unread state, and the active workspace.
**2. Settings showed a red update error.**
```
Update error: ENOENT: no such file or directory, open '.../Pythinker.app/Contents/Resources/app-update.yml'
```
A locally packed build (`electron-builder --dir`) sets `app.isPackaged =
true` but carries no
`app-update.yml`, so the first check threw and surfaced as a failure. A
build that simply cannot
self-update should say so calmly.
## What changed
- **Fixed Host port**: 24827 packaged, 24828 in development, with a
validated `PYTHINKER_DESKTOP_PORT`
override that fails loudly on a bad value rather than silently reverting
to a default.
- **No fallback port, by design.** A fallback would reintroduce the same
silent data loss on exactly
the machines most likely to hit a collision. A bind failure now shows a
dialog naming the port and
the override, offering **Retry** (rebuilds the supervisor and retries
the same port, so the user can
free it and continue) or **Quit**.
- **Development pins a port too.** Otherwise "works in dev, loses
settings in prod" stays invisible
during normal development, which is the divergence that produced this
report.
- **Updater precheck**: `initUpdater`, `checkForUpdatesNow` and
`quitAndInstallNow` all check for
`app-update.yml` under `resourcesPath` first and report `disabled` when
it is absent. No listeners
are wired and no timers are scheduled on such a build.
### Design alternatives considered and rejected
These were argued out before implementing, and the reasons are recorded
here so they are not
re-litigated later:
- **Move preferences out of `localStorage`** into desktop-owned storage
via IPC. Fixes today's keys,
but leaves the next `localStorage` use silently broken and forks
behaviour between the browser and
Electron.
- **Serve the renderer from a custom `app://` scheme.**
`apps/pythinker-web/src/api/config.ts` derives
both the HTTP base and the WebSocket URL from `window.location.origin`,
so this forces endpoint
injection plus a CORS and WebSocket-origin story into a client that has
none — an architecture
change to fix a storage bug. Worth revisiting only if fixed ports prove
to fail in the field.
- **A bounded fallback (try N, N+1, N+2).** Rejected above.
## Verification
Run in this branch's worktree:
- `pnpm --filter @pymodel/pythinker-desktop exec vitest run` — **85
passed** (79 on the base plus 6
new). Each new test was watched failing against the old behaviour before
the source changed.
- `pnpm --filter @pymodel/pythinker-desktop run typecheck` — exit 0.
- `pnpm run lint` — exit 0.
New coverage: `resolveDesktopPort` defaults per build type, a valid
override winning, invalid
overrides (non-numeric and out-of-range) throwing rather than falling
back, `isPortInUseError`
classification, the port reaching the spawned argv, and `initUpdater`
staying `disabled` with no
events wired when `app-update.yml` is absent.
## Known follow-up (not in this PR)
Auto-update is still broken in **shipped** builds for a separate reason:
`pythinker-code` publishes
CLI releases continuously, so `/releases/latest` resolves to a CLI
release with no `latest-mac.yml`,
and electron-updater's public GitHub provider follows exactly that. The
fix is to publish desktop
releases to their own repository; that lands separately because it needs
a cross-repo publishing
credential.
## Checklist
- [x] I have read the CONTRIBUTING document.
- [x] I have linked a related issue, or explained the problem above.
- [x] I have added tests that prove my feature works.
- [x] Ran `gen-changesets` skill, or this PR needs no changeset. —
`@pymodel/pythinker-desktop` is private and changeset-ignored.
- [ ] Ran `gen-docs` skill, or this PR needs no doc update.1 parent fa82753 commit 04b26cf
5 files changed
Lines changed: 168 additions & 26 deletions
File tree
- apps/desktop
- src
- tests
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
9 | 9 | | |
10 | 10 | | |
11 | 11 | | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
| 20 | + | |
| 21 | + | |
| 22 | + | |
| 23 | + | |
| 24 | + | |
| 25 | + | |
| 26 | + | |
| 27 | + | |
| 28 | + | |
| 29 | + | |
| 30 | + | |
| 31 | + | |
12 | 32 | | |
13 | 33 | | |
14 | 34 | | |
| |||
257 | 277 | | |
258 | 278 | | |
259 | 279 | | |
| 280 | + | |
| 281 | + | |
260 | 282 | | |
261 | 283 | | |
262 | 284 | | |
| |||
272 | 294 | | |
273 | 295 | | |
274 | 296 | | |
275 | | - | |
| 297 | + | |
276 | 298 | | |
277 | 299 | | |
278 | 300 | | |
| |||
286 | 308 | | |
287 | 309 | | |
288 | 310 | | |
289 | | - | |
| 311 | + | |
290 | 312 | | |
291 | 313 | | |
292 | 314 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
23 | 23 | | |
24 | 24 | | |
25 | 25 | | |
26 | | - | |
| 26 | + | |
| 27 | + | |
| 28 | + | |
| 29 | + | |
| 30 | + | |
| 31 | + | |
| 32 | + | |
27 | 33 | | |
28 | 34 | | |
29 | 35 | | |
| |||
303 | 309 | | |
304 | 310 | | |
305 | 311 | | |
| 312 | + | |
306 | 313 | | |
307 | 314 | | |
308 | 315 | | |
| |||
313 | 320 | | |
314 | 321 | | |
315 | 322 | | |
316 | | - | |
317 | | - | |
318 | | - | |
319 | | - | |
320 | | - | |
321 | | - | |
| 323 | + | |
| 324 | + | |
| 325 | + | |
| 326 | + | |
| 327 | + | |
| 328 | + | |
| 329 | + | |
| 330 | + | |
| 331 | + | |
| 332 | + | |
| 333 | + | |
| 334 | + | |
| 335 | + | |
| 336 | + | |
322 | 337 | | |
323 | | - | |
324 | | - | |
325 | | - | |
326 | | - | |
327 | | - | |
328 | | - | |
329 | | - | |
330 | | - | |
331 | | - | |
332 | | - | |
333 | | - | |
334 | | - | |
335 | | - | |
| 338 | + | |
| 339 | + | |
| 340 | + | |
| 341 | + | |
| 342 | + | |
| 343 | + | |
| 344 | + | |
| 345 | + | |
| 346 | + | |
| 347 | + | |
| 348 | + | |
| 349 | + | |
| 350 | + | |
| 351 | + | |
| 352 | + | |
| 353 | + | |
| 354 | + | |
| 355 | + | |
| 356 | + | |
| 357 | + | |
| 358 | + | |
| 359 | + | |
336 | 360 | | |
337 | 361 | | |
338 | 362 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
1 | | - | |
| 1 | + | |
2 | 2 | | |
3 | 3 | | |
4 | 4 | | |
5 | 5 | | |
6 | 6 | | |
7 | 7 | | |
| 8 | + | |
8 | 9 | | |
9 | 10 | | |
10 | 11 | | |
| |||
117 | 118 | | |
118 | 119 | | |
119 | 120 | | |
| 121 | + | |
| 122 | + | |
| 123 | + | |
| 124 | + | |
| 125 | + | |
| 126 | + | |
| 127 | + | |
| 128 | + | |
| 129 | + | |
| 130 | + | |
| 131 | + | |
| 132 | + | |
| 133 | + | |
| 134 | + | |
120 | 135 | | |
121 | 136 | | |
122 | 137 | | |
| |||
181 | 196 | | |
182 | 197 | | |
183 | 198 | | |
| 199 | + | |
| 200 | + | |
| 201 | + | |
| 202 | + | |
184 | 203 | | |
185 | 204 | | |
186 | 205 | | |
| |||
232 | 251 | | |
233 | 252 | | |
234 | 253 | | |
| 254 | + | |
235 | 255 | | |
236 | 256 | | |
237 | 257 | | |
| |||
251 | 271 | | |
252 | 272 | | |
253 | 273 | | |
| 274 | + | |
254 | 275 | | |
255 | 276 | | |
256 | 277 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
5 | 5 | | |
6 | 6 | | |
7 | 7 | | |
| 8 | + | |
8 | 9 | | |
9 | 10 | | |
10 | 11 | | |
| |||
112 | 113 | | |
113 | 114 | | |
114 | 115 | | |
| 116 | + | |
| 117 | + | |
| 118 | + | |
| 119 | + | |
| 120 | + | |
| 121 | + | |
| 122 | + | |
| 123 | + | |
| 124 | + | |
| 125 | + | |
| 126 | + | |
| 127 | + | |
| 128 | + | |
| 129 | + | |
| 130 | + | |
| 131 | + | |
| 132 | + | |
| 133 | + | |
| 134 | + | |
| 135 | + | |
| 136 | + | |
| 137 | + | |
| 138 | + | |
| 139 | + | |
| 140 | + | |
| 141 | + | |
| 142 | + | |
| 143 | + | |
115 | 144 | | |
116 | 145 | | |
117 | 146 | | |
| |||
296 | 325 | | |
297 | 326 | | |
298 | 327 | | |
| 328 | + | |
299 | 329 | | |
300 | 330 | | |
301 | 331 | | |
| |||
307 | 337 | | |
308 | 338 | | |
309 | 339 | | |
310 | | - | |
| 340 | + | |
311 | 341 | | |
312 | 342 | | |
313 | 343 | | |
| |||
341 | 371 | | |
342 | 372 | | |
343 | 373 | | |
| 374 | + | |
344 | 375 | | |
345 | 376 | | |
346 | 377 | | |
| |||
379 | 410 | | |
380 | 411 | | |
381 | 412 | | |
| 413 | + | |
382 | 414 | | |
383 | 415 | | |
384 | 416 | | |
| |||
404 | 436 | | |
405 | 437 | | |
406 | 438 | | |
| 439 | + | |
407 | 440 | | |
408 | 441 | | |
409 | 442 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
6 | 6 | | |
7 | 7 | | |
8 | 8 | | |
9 | | - | |
| 9 | + | |
| 10 | + | |
10 | 11 | | |
11 | 12 | | |
12 | 13 | | |
13 | 14 | | |
14 | | - | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
| 20 | + | |
| 21 | + | |
15 | 22 | | |
16 | 23 | | |
| 24 | + | |
| 25 | + | |
17 | 26 | | |
| 27 | + | |
| 28 | + | |
18 | 29 | | |
19 | 30 | | |
20 | 31 | | |
21 | 32 | | |
22 | 33 | | |
23 | 34 | | |
24 | 35 | | |
| 36 | + | |
| 37 | + | |
25 | 38 | | |
26 | 39 | | |
27 | 40 | | |
28 | 41 | | |
29 | 42 | | |
| 43 | + | |
| 44 | + | |
| 45 | + | |
| 46 | + | |
| 47 | + | |
| 48 | + | |
| 49 | + | |
| 50 | + | |
| 51 | + | |
30 | 52 | | |
31 | 53 | | |
32 | 54 | | |
| |||
76 | 98 | | |
77 | 99 | | |
78 | 100 | | |
| 101 | + | |
| 102 | + | |
| 103 | + | |
| 104 | + | |
| 105 | + | |
| 106 | + | |
| 107 | + | |
| 108 | + | |
| 109 | + | |
| 110 | + | |
| 111 | + | |
| 112 | + | |
| 113 | + | |
| 114 | + | |
| 115 | + | |
| 116 | + | |
| 117 | + | |
| 118 | + | |
| 119 | + | |
| 120 | + | |
0 commit comments