* feat(quit): add Quit and Stop All Sessions to the app menu and tray Quit keeps daemon sessions alive for warm reattach. The new item, placed directly above Quit in the macOS app menu and menu bar icon, the Windows File menu and tray, and the Linux File menu, asks for confirmation, runs Settings' Kill all sessions in the renderer, and quits only when every session stopped. Closing the tabs first means nothing reopens or resumes on the next launch. Serve hosts do not offer the item. * fix(quit): keep Orca open when Kill all cannot prove every session stopped - Kill all no longer reads a daemon generation that failed to list as "no sessions": a failed poll keeps the last confirmed remaining set, and a failed initial listing sets listingIncomplete. - Quit and Stop All Sessions stays open on an incomplete listing or a terminal tab opened during the sweep, logs why it stayed open, and reveals the window before the final quit. - Share the main-window message box helper, stub the request on the web client, and add Portuguese strings. - Cover the windowless path, request expiry, the in-flight guard, and failed listings in tests; bound the E2E exit wait. * fix(terminal): count Kill all per daemon generation within a time window - A poll updates only the daemon generations that answered, so one failing generation no longer hides the kills of the others. - Poll for 6.5 s of wall-clock time instead of 65 attempts, because a wedged generation fails each listing only at the request timeout. - Flag a sweep with no daemon provider as listingIncomplete. - Log the leftover-tab exit, share the one-shot window intent with Open Settings, and cover the sender check, the reveal before the final quit, and retries in tests. * fix(quit): stay open while a newer build's daemon is held - Set listingIncomplete while this build holds a newer protocol's daemon, whose sessions it can neither list nor stop. - Reuse getDaemonAdapters in Kill all, type the shared one-shot helper by its flag factory, and move the app-menu quit handlers next to the tray options so both serve/desktop splits are tested. - Cover a quit that outlasts the request expiry and a failed request pull, and fix the docs lead-in for the new quit-time case. * fix(quit): explain, without stopping anything, while a newer version runs terminals - Check the newer-version daemon hold before the confirmation and show an explanation instead, so Kill all no longer closes every tab and then refuses. listingIncomplete stays as the backstop. - Translate the explanation, describe listingIncomplete generically, and assert the single timed-out poll in the Kill all test. * fix(quit): explain before asking whenever Kill all cannot list every session - Show the explanation instead of the confirmation while the daemon provider is missing (still starting or failed) as well as while a newer version's daemon is held. - Name only the steps that work (wait for terminals to open, reopen a terminal opened in a newer version), avoid stating a hold as fact, and label the dialog's button through the catalog. * fix(quit): add the relaunch step to the explanation and align the ja wording * test(pty): keep a confirmed stop when its generation fails a later poll * test(quit): give the E2E timeout bump its reason * fix(quit): stay open when the daemon still lists a session after Kill all Kill all counts only the sessions of its first listing, so a session started since then, for example from the CLI or an automation before its tab reaches the renderer, would outlive the quit. Main now lists every daemon generation again before quitting, and quits only after a listing in which every generation answers and none lists a session. It polls within Kill all's 6.5 s window so the tab sweep's PTY shutdowns can finish; otherwise the renderer shows the existing error and Orca stays open. ui:quitAfterStoppingAllSessions becomes an invoke that answers whether main quits. * feat(quit): rename to Quit Completely with a macOS hover hint, and explain plain Quit in the confirmation * fix(quit): show progress while Quit Completely runs, and refuse at once when the daemon can't be fully listed --------- Co-authored-by: Neil <neil@stably.ai>
@orca/docs
This package contains the product documentation and public media intended to ship alongside Orca's source code.
Open-source product documentation for Orca, served at /docs (same URL shape as https://www.onorca.dev/docs).
This package is a self-contained Next.js app. It is intentionally not a root monorepo workspace member, so installing Electron app dependencies does not pull Next/fumadocs.
Local development
Use Node.js 24 and the pnpm version pinned in package.json. CI reads the
Node.js version from this package's engines.node field.
cd docs/site
pnpm install
pnpm dev
Open http://localhost:3004/docs.
Linting
Run pnpm lint inside this directory. The isolated Oxlint
configuration keeps the native equivalents of the previous Next.js, React,
React hooks and accessibility checks at their existing severities, including
alt text on Next.js Image components. Generated Next.js and MDX output is
excluded. Oxlint also reports its default correctness warnings.
The migration does not provide equivalents for React's deprecated-API check,
React Compiler configuration/gating diagnostics, or Next.js's relative
location.assign advisory. JSX variable-use bookkeeping is handled by Oxlint's
parser. Keep TypeScript and the production Next.js build in the validation
workflow; this is not a claim of complete ESLint rule parity.
Production build
cd docs/site
pnpm install
pnpm build
pnpm start
pnpm start serves the production build on port 3004. Paths:
| Path | Purpose |
|---|---|
/ |
Redirects to /docs |
/docs |
Docs index |
/docs/... |
Nested doc pages from content/docs |
/docs/api/search |
Fumadocs search index |
/docs/og/... |
Per-page Open Graph image route |
Layout
content/docs/— MDX pages +meta.jsonnavigationpublic/docs/— docs-only media, logo, and favicon (GIFs, posters, screenshots)src/app/docs/— fumadocs routes, OG imagessrc/components/— docs-scoped chrome (header/footer/search), not marketing site
Updating content
Treat the documentation tree as a deliberate publication boundary. Before importing source material, review the diff for internal references, credentials, third-party media rights, and feature/version claims, then copy only approved pages and assets. Keep the app shell and deployment configuration in this repository so a docs-only pull request can be reviewed and built independently.
Same-domain routing
The docs app is a separate Vercel project (the docs zone) and keeps the
public /docs URL namespace. The marketing site remains the default zone for
www.onorca.dev; configure its Next/Vercel proxy with these beforeFiles
rewrites, replacing DOCS_ORIGIN with the docs project's production URL:
return {
beforeFiles: [
{
source: '/docs',
destination: `${DOCS_ORIGIN}/docs`
},
{
source: '/docs/:path*',
destination: `${DOCS_ORIGIN}/docs/:path*`
},
{
source: '/docs-static/:path*',
destination: `${DOCS_ORIGIN}/docs-static/:path*`
}
]
}
/docs-static is the docs zone's assetPrefix; it prevents _next asset
collisions with the marketing zone. Keep the rewrites in the default zone and
use ordinary <a> links when navigating between zones. Do not add
basePath: '/docs' to this app: its route tree and Fumadocs baseUrl already
include /docs, so doing so would publish /docs/docs/... URLs. If a future
deployment needs basePath, first move the route tree to an unprefixed
src/app/[[...slug]] shape and update every generated/link URL together.
Deploy (Vercel)
- Create a Vercel project with Root Directory unset (
.). The workflow invokes Vercel fromdocs/site, so that directory is already the deployment root; setting it again would resolvedocs/site/docs/site. Leave automatic Git deployments disabled so this workflow remains the only deployment path. - Framework preset: Next.js. This package's
engines.nodeselects Node.js 24 for Vercel builds and functions.vercel.jsonpins install (pnpm install --frozen-lockfile) and build (pnpm build) over the dashboard settings; this package has its own lockfile beside the root workspace. - Set GitHub Actions secrets (required by the production deploy job):
VERCEL_TOKENVERCEL_ORG_IDVERCEL_PROJECT_ID(docs project, not the marketing site)
- Protect the
docs-productionGitHub environment with required reviewers and custom deployment branch policies formainandv*tags. The release-cut dispatch runs frommain; the direct published-release fallback runs from a stable tag, while the workflow still authorizes only exact stable tags. - Prepare the three rewrites above in the
www.onorca.devmarketing project, but leave them disabled until the docs deployment is verified. A Vercel custom domain cannot delegate only/docsby itself; the default zone must proxy both page/API/media requests and/docs-staticassets. Keep the marketing project's old docs routes available for rollback during the transition; putting the proxy rules inbeforeFilesensures they win once enabled. - Deploy a stable desktop tag that contains
docs/site, verify the docs origin, then enable the marketing rewrites. Tags cut before this package was added cannot bootstrap the docs project because production intentionally checks out the tag's exact commit. Remove the old marketing docs routes in a follow-up after the proxy is stable.
.github/workflows/docs.yml runs credential-free checks for every pull request.
It intentionally does not deploy PR previews: a PR-controlled build must not
receive Vercel credentials. A maintainer can add a separate trusted preview
workflow later. Production deploys only from an authorized stable desktop release: an exact
vX.Y.Z tag, a published non-prerelease release, and the
github-actions[bot] release author. Manual dispatch must run from the default
branch and name an existing release that meets the same checks. Mobile,
prerelease, draft, and human-authored releases are skipped. Fork pull requests
remain build-only because GitHub does not expose deployment secrets to fork
jobs.
Versioning
versioning.config.ts keeps the current unversioned /docs URLs stable while
reserving content/versions/<id> for future snapshots. Versioned routes are not
live yet; when they are needed, add the corresponding loader/routes and a
version entry. The release workflow can then deploy them without a trigger
change.
Isolation from the desktop app
- Own
package.json+pnpm-lock.yamlunderdocs/site/ - Not listed in the root
pnpm-workspace.yaml; its ownpnpm-workspace.yamlmakes it a separate workspace root and holds its pnpm settings, which pnpm 12 ignores under--ignore-workspace - Engineering notes remain in repo-root
docs/— do not confuse with this package