CONTRIBUTING.md
Rama main · réplica de lectura del repositorio original.
# Contributing to Prismical Desktop
Thanks for helping. This file covers how the repository is put together and what a pull
request needs; the README covers setup.
## Where things live
- `apps/desktop` — the Electron app. `src/main` (Effect services, IPC, native helper hosts,
the local data plane, transcription and AI providers), `src/preload`, `src/renderer` (the
main, widget, float and notify windows), `e2e` (Playwright, packaged or bundle target) and
`tests` (vitest).
- `packages/desktop-contracts` — IPC channel and window contracts (zod). Change these with the
main-process handlers and the preload buffers together; `tests/contracts` pins the surface.
- `packages/native-helpers/*` — Swift (macOS) and C# (Windows) helper processes with a
line-delimited JSON wire protocol; golden fixtures live in `apps/desktop/tests/native`.
- `packages/whisper-wrapper` — the whisper.cpp addon. Upstream changes go in as `.patch` files
under `patches/` (applied by `preinstall`); bump the submodule pin and
`WHISPER_CPP_VERSION` together.
- The shared packages (`packages/{app-ui,app-client,app-i18n,api-contracts,app-contracts,
app-workflow,silence,editor-markdown,editor-schema,id,note-derive,ai-prompts}`) — the screens, data layer,
i18n catalogues and contract packages shared with the Prismical web app. They are updated
here in batches; a pull request that changes one of them is welcome, and the maintainers
carry the change across to the web app. New user-visible strings in the desktop are checked
by the `@prismical/app-i18n` source-coverage test.
## Conventions
- Workspace `tsc` builds and type checks use TypeScript 7.0.2 through the root `@typescript/native`
alias (`pnpm exec tsc --version` verifies it). The `typescript` catalog aliases
`@typescript/typescript6` for tools that use the JavaScript compiler API, including ESLint,
declaration bundling, and the localization source scan. That package exposes `tsc6`, so
workspace `tsc` commands use v7. See the [TypeScript compatibility guidance](https://devblogs.microsoft.com/typescript/announcing-typescript-7-0/#running-side-by-side-with-typescript-6-0).
The shared presets are in `packages/config-typescript`; the
`prismical-source` export condition lets `tsc` see package sources while Vite and vitest
consume built `dist/` (run `pnpm build` after a shared-package update or a package change).
- Every renderer-graph package declares `"zod": "catalog:"` — a stray `^3` pin poisons the
shared Vite chunk for everyone.
- Lint with `pnpm lint` (eslint 9, flat config from `packages/config-eslint`). Prettier's config
is at the root; format the files you touch (`pnpm exec prettier --write <files>`) rather than
the whole tree — not every inherited file is prettier-clean yet, and the shared packages
are excluded.
- Main-process code is Effect: services are layers, errors are `Data.TaggedError`, nothing
is `Effect.die`d for an expected failure. `apps/desktop/tests/static-gate.test.ts` enforces
the rails.
- Playwright specs use `expect()` assertions only — never `if`/`else` around an assertion.
- Anything on the audio path (`src/main/domains/recording`, capture, the note-body relay)
must be bounded work; do not put CRDT or editor logic in the main process.
## Development gotchas
- **The dev app is "Electron" in the macOS Dock, not "Prismical".** "Prismical" in Spotlight or
the Dock is the installed build.
- **Blank renderer while the main-process log says `boot complete`** → open DevTools (⌘⌥I):
`Cannot read properties of undefined (reading 'datetime')` means a `zod` v3 pin somewhere in
the renderer graph. Vite keys bare imports by package name, so one package pinning `"zod": "^3"`
poisons the shared chunk. Every renderer-graph package must use `"zod": "catalog:"`; after
fixing, `rm -rf apps/desktop/node_modules/.vite` and restart.
- **Dev sign-in uses portless** (`https://prismical-desktop.localhost/oauth/callback`).
`pnpm dev` starts Forge through portless, which assigns the loopback listener's `PORT`.
Custom schemes cannot work unpackaged because every Electron checkout shares the `com.github.Electron`
bundle id; packaged builds use `prismical://`.
- **Sign-in fails `invalid_redirect`** → the loopback URI is missing from the OAuth client's
redirect allow-list on the backend you sign in against.
- **Sign-in returns to the app, then bounces back to the gate** with
`oauth exchange failed { reason: 'network' }` → check the backend connection and certificate
chain. Startup adds OS-trusted certificates to Node's defaults; use `NODE_EXTRA_CA_CERTS`
for a dev CA that is not installed in the OS trust store.
- **"Microphone access was denied"** → grant Microphone to **Electron** in System Settings →
Privacy & Security.
- **Second launch silently exits** → single-instance lock: `pkill -f "electron-forge start"`.
- **No local transcription after a plain clone** → the whisper.cpp submodule was absent when
`pnpm install` ran: `pnpm --filter @prismical/whisper-wrapper dev:prepare && pnpm install`.
- **Stale `dist/` after a shared-package update** → `pnpm build`.
- Renderer edits hot-reload; main-process edits need a full restart.
## Before you open a pull request
```bash
pnpm lint && pnpm type:check && pnpm test
pnpm --filter @prismical/desktop test:e2e:fresh # when you touched main/preload/renderer wiring
```
CI runs lint, type-check and the unit tests, a bundle-target smoke spec
(the real main/preload/renderer booted on an isolated profile), the native helper builds on macOS
and Windows, and a whisper addon build from the submodule. The packaged `test:e2e:fresh` suite is
NOT run in CI — run it locally when you touch main/preload/renderer wiring. Native helper changes
need a build on the target platform; the Windows helpers can be exercised through CI if you have
no Windows machine.
## Commits and pull requests
- Conventional commits (`feat(desktop): …`, `fix(whisper): …`, `chore: …`); the release
changelog is generated from them.
- One logical change per pull request, with the tests that prove it.
- No AI co-author trailers in commit messages.
## Security
Report vulnerabilities privately through a GitHub security advisory on this repository rather
than in a public issue.
Third-party components and their licenses are recorded in `NOTICE.md`.