# vibe-sketch desktop app

Electron shell for vibe-sketch, forked from vibe-view's with the product
name, the handshake variable and the update-feed path changed. It runs on
macOS, Windows and Linux from one codebase.

## What it does

```
vibe-sketch desktop [file]         (Python CLI, from any directory)
  │  writes a temp JSON config {port, file, python, cwd, version, codename}
  │  and spawns Electron with VIBESKETCH_DESKTOP_CONFIG=<path>
  ▼
Electron main process (main.js)
  │  spawns:  <config.python> -m vibesketch.cli serve --port <port>
  │  waits:   GET http://127.0.0.1:<port>/health
  │  opens:   BrowserWindow → http://127.0.0.1:<port>/
  ▼
vibe-sketch serve (the API the browser shell and agents talk to)
```

Every path into a file, File → Open (Cmd+O), Open Recent, a drop on the
window or the dock icon, or a `.vsk` double-click through the file
association, routes through `openFile()`. The main process reads the file
and imports its contents through REST; the page receives a document id.
Filesystem paths stay in the main process.

Save synchronizes the drawing and writes a fixed revision back to its file;
Save As chooses a destination. For imported or protected QVF files, Save
opens Save Sketch Copy with an explanation and a distinct suggested filename.
The copy requires a different destination so original calculation payloads
stay intact; subsequent saves use the copy. Failed
exports, changed files and cancelled dialogs leave the original untouched.

Downloaded macOS apps use their embedded Python, RDKit and QVF runtime,
independent of PATH, virtual environments or a previous CLI installation.
A missing, mismatched or broken runtime shows a repair page.

In a source install, when no interpreter that imports `vibesketch` is found, the shell shows an
onboarding page (`setup.html`) with the exact install command for an
app-managed virtualenv, and rechecks in place.

Recent files live in `~/.cache/vibe-sketch/recent.json`, and the interpreter
record a `vibe-sketch desktop` run leaves is `~/.cache/vibe-sketch/interpreter.json`.

## Run from source

```bash
cd electron
python3 install-electron.py
npm start
```

`npm start` needs a Python on PATH, or the checkout's `.venv`, that imports
`vibesketch`; `../scripts/install.sh` creates one. The installer downloads the
exact Electron pin in `package.json`, checks it against the lockfile and the
release SHA256 manifest, and replaces the runtime atomically. It provides the
wrappers `npm start` uses. It needs only Python's standard library; `npm ci`
remains available for development and packaging dependencies.

On macOS the installer brands and ad-hoc signs the app, then installs a
source launcher in an Applications folder. Open **vibe-sketch** from Finder
or Spotlight to launch without npm. The launcher follows this checkout;
rerun the installer if it moves. No Apple developer account is needed.

```bash
python3 install-electron.py --check             # read-only runtime health check
python3 install-electron.py --dock              # also pin the macOS app
python3 install-electron.py --refresh-app       # refresh this checkout's app
python3 install-electron.py --uninstall --dry-run
python3 install-electron.py --uninstall
```

Repeated installs reuse the reviewed download and leave an up-to-date desktop
copy alone. Packaged apps, unknown bundles and another checkout's source app
are preserved. Explicit `--refresh-app --adopt-app` transfers a source app
to this checkout. Uninstall removes only this checkout's recognized direct
download and source launcher, retaining npm packages and user data.

## File types

Source and packaged macOS apps advertise `.qvf` and `.vsk` as Editor and
`.mol`, `.sdf`, `.rxn`, `.cdxml`, `.ket` and `.xyz` as Viewer. The Alternate
handler rank leaves the user's preferred app alone. `--refresh-app` refreshes
an already installed source app's declarations.

QVF's canonical files in `file-types/` are vendored unchanged from the CI
`QVF_TAG`, including their Apache-2.0 licence. The source installer imports
the shared QVF UTI; `after-pack.cjs` applies the same declarations to packaged
apps before signing. Python 3 is needed for this packaging hook (`PYTHON`
can select the interpreter). Only vibe-sketch's `.vsk` type is exported.

The Linux desktop entry declares its MIME types through `linux.mimeTypes`.
The matching XML files ship under `resources/file-types/`; the QVF XML stays
separate so electron-builder cannot replace it with a derived declaration.
The installation manual describes MIME registration for extracted AppImages.
Opening and saving use the shared document workflow described above.

## Package

```bash
./build-desktop.sh --dir     # unpacked development build
./build-desktop.sh           # dmg + zip on macOS, AppImage on Linux
```

The self-contained macOS target is **Apple Silicon, macOS 14 or newer**.
The builder runs natively on Apple Silicon with Python 3.12+, Node.js 22+
and Apple's command-line tools. It downloads a pinned standalone CPython,
installs checksum-verified binary wheels, builds QVF from its pinned source,
and installs the Sketch wheel (including the browser). The recipient needs
no Python, pip, RDKit, Git, Node.js or network access to start drawing.

`third_party/notices/macos-runtime-lock.json` pins all runtime inputs and
build-tool wheels. Downloads are cached in `.cache/desktop-runtime/`; an
incorrect checksum fails the build. The assembled runtime is staged under
`electron/.runtime/macos-arm64/`. A build verifies imports, QVF availability,
SVG/PNG drawing, 3D embedding and native library references before replacing
that staging payload. `after-pack.cjs` repeats the checks at the final app
path before signing and refuses Intel or universal packages.

To reuse an already qualified application wheel of the same version:

```bash
VIBESKETCH_WHEEL=/path/to/vibesketch-X.Y.Z-py3-none-any.whl ./build-desktop.sh --mac
```

The runtime manifest records the application wheel and input-lock hashes.
Updating the lock requires reviewing upstream licenses, checking the shipped
notices/source, and rerunning the installed-copy acceptance in the desktop
manual. The current NumPy wheel sets the macOS 14 minimum. Intel needs a
separately qualified dependency set; it must not reuse the ARM runtime.

See `PUBLISHING.md` for the update feed and the bundled licence notices.

## Desktop delivery status

The shell includes file open/save, recent files, onboarding, notices, update
checks and file associations. The [desktop manual](../docs/desktop.md) covers
installation, first run, storage locations and the macOS update path.

Packaged macOS acceptance is tracked by #14 and must be recorded against the
release candidate. The hosted wheel named by source-install onboarding,
`vibesketch-<version>-py3-none-any.whl`, becomes available when that release is
published; release preparation alone does not establish public availability.

## Icon

`icon.png` and `icon.icns` are generated by `make-icon.py` (needs Pillow):

```bash
python3 make-icon.py
```

Linux self-contained packaging uses Python 3.13+, Node.js 22.12+, `readelf`,
`ldd` and `zstd` on a native x86-64 desktop builder. The checked lock is separate
from the Apple Silicon lock. See the Linux section of the desktop manual.
