main
9 Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
6bb128c804 |
feat(web): automatic dev sharding + bare workspace URL for npm run dev (#4713)
Point OMNIGENT_URL at a bare Databricks workspace origin and npm run dev auto-fills the /api/2.0/omnigent api-proxy mount and emits the host_id slice key on host-scoped traffic (build-time VITE_DATABRICKS_WORKSPACE flag + the unified isDatabricksWorkspace() gate), so the standalone dev bundle shards like the embedded UI. An explicit mount or a local server is unaffected. Signed-off-by: Edwin He <41037314+Edwinhe03@users.noreply.github.com> Co-authored-by: Isaac <isaac@example.com> |
||
|
|
ef8aba3af0 |
refactor(web): retire the PWA service worker and update prompt (#4617)
## Related issue N/A — `Refactor / chore`. ## Summary The PWA landed as one squashed PR (`b6976c1b2`, #116) whose headline was installability. #116 was authored around mid-June, when "installable Omnigent on mobile" was an open problem; it merged 2026-06-30, by which point the iOS shell had shipped (#965, 2026-06-22) and the Android shell landed the next day (#1604/#1704). The native shells took over the installed-app story while the PR was in flight, and the PWA was never re-evaluated. What was left was load-bearing for one thing only — the "new version → Reload" prompt — and inert for everything else: - `web/src` had zero uses of `navigator.serviceWorker`, `caches.*`, `BroadcastChannel`, `pushManager`, `backgroundSync` or `setAppBadge`. Notifications deliberately bypass the worker (`web/src/lib/browserNotifications.ts`) and badges go through `nativeBridge.ts`. - `version.json` was emitted, precached, and read by nobody. - Installability was unadvertised (no `beforeinstallprompt`) and unmeasured (no `display-mode` checks), so the worker's one cache entry existed only to satisfy Chrome's "non-empty fetch handler" install heuristic. Web Push (#1751, P2) is the only thing that would need a worker again, and a push worker needs different handlers, VAPID keys and server infra — the retired file is not useful groundwork. ELI5: the service worker was a doorbell that only rang to say "the app has been updated". Nothing else used it, and three native apps now do the "install Omnigent" job it was built for, so the doorbell and its wiring come out. A worker already registered in a browser stays registered after we stop shipping one, so `sw.js` becomes a tombstone that removes itself: ``` deploy 0.10.0 │ ▼ browser fetches /sw.js (no-cache) → installs tombstone → parks in `waiting` │ ├─ old tab still runs old JS, shows its own update banner one last time │ user clicks Reload → SKIP_WAITING → activate │ ├─ purge omnigent-pwa-* caches │ └─ registration.unregister() │ → tab reloads, PWA-free └─ or all tabs close → activate on next visit → same cleanup, no prompt ``` Deliberately no `skipWaiting()` on install, so nobody's agent session is interrupted by an unprompted reload. The purge matches the retired worker's exact cache-name shape, `/^omnigent-pwa-[0-9a-f]{8}$/` — it only ever created `omnigent-pwa-${(hash >>> 0).toString(16).padStart(8, "0")}` — rather than clearing Cache Storage wholesale or trusting a bare prefix, so a tombstone lingering in some browser cannot delete a future feature's caches even if that feature reuses the prefix. `registration.unregister()` leaves no persistent browser state, so registering a worker at `/sw.js` again later is clean. Two things are kept for that reason: the `no-cache` header for `sw.js` in `app.py` (so a cached tombstone can never shadow a future worker) and the embed-island guard that forbids shipping any service worker into a host origin. Tombstone deletion is targeted at **0.11.0** (marked `@deprecated` in `web/sw-src/sw.js` and in the vite plugin). Not in this PR: `emptyOutDir: true` deletes old hashed chunks on deploy, the app lazy-loads most routes, and there is no `ErrorBoundary` anywhere in `web/src`, so a tab left open across a deploy can white-screen on navigation to a lazy route. The prompt was a proactive nudge, never a guard — it never prevented the 404. The gap pre-dates this change (it already applied to anyone who dismissed the banner) and the fix (ErrorBoundary + reload on failed dynamic import) is independent of the PWA, so it is filed separately. ## Test Plan - `pnpm --filter web run type-check`, `run lint`, `run build` — clean; build output contains `sw.js` only, with no `manifest.webmanifest`, no `version.json` and no `pwa-*.png` (`apple-touch-icon.png` / `favicon.svg` retained). - `uv run pytest tests/server/integration/test_app.py::test_web_ui_serves_service_worker_uncached` — passes. - `pnpm exec vitest run src/components/UpdateBanner.test.tsx` — 5 passed; confirms the similarly-named Electron desktop update banner is untouched. - Exercised the rewritten build guard against the real build output, plus eight negative cases, to prove it is not vacuous: a worker that calls `respondWith`, an unscoped cache purge, a *bare-prefix* cache filter, a worker that never unregisters, a stale `__BUILD_VERSION__` token, a re-emitted manifest, a re-emitted `version.json`, and a missing `sw.js` are each rejected. - Round-tripped the anchored cache pattern against the fingerprints the retired worker could produce (uint32 min, max and typical values all render as 8 lowercase hex chars) to confirm the tightened filter still purges every legacy cache name, while leaving unrelated names in the same namespace alone. - `uv run pre-commit run` — all hooks pass. ## Demo N/A — the only visible effect is the absence of the update banner. ## Type of change - [ ] Bug fix - [ ] Feature - [ ] UI / frontend change - [x] Refactor / chore - [ ] Docs - [ ] Test / CI - [ ] Breaking change ## Test coverage - [ ] Unit tests added / updated - [x] Integration tests added / updated - [x] E2E tests added / updated - [x] Manual verification completed - [ ] Existing tests cover this change - [ ] Not applicable ## Coverage notes `tests/e2e_ui/test_pwa_e2e.py` is deleted (it asserted live PWA behaviour) and `conftest._assert_pwa_build` is replaced by `_assert_service_worker_tombstone`, which now enforces the *dangerous* direction: the worker must unregister itself, must intercept nothing, must not purge caches it does not own, and the manifest/version sentinel must be gone. `tests/e2e_ui/test_pwa_build.py` is renamed to `test_embed_service_worker.py` and kept — "the embed island ships no service worker" outlives the PWA. Manual verification covered the parts a test cannot: the emitted build output was inspected by hand, and the guard was run against both the real output and seven mutated inputs (listed in the Test Plan) to confirm each regression is caught. The deleted unit tests covered only the removed components. ## Changelog Removed the "A new version of Omnigent is available" prompt and browser PWA install support; the desktop and mobile apps remain the installable clients. Signed-off-by: Zeyi (Rice) Fan <zeyi.f@databricks.com> |
||
|
|
6ac1c60454 |
feat(desktop): move the server picker into the sidebar, add a server version manifest (#4551)
The macOS shell hides the native title bar, and the picker filled that freed
strip with a centered "<thread> — <host>" label. But the chat header occupies
the same strip (absolute top-0, taller at h-14), so on a narrow window the
centered label ran straight into the header's action cluster.
Dock the picker at the bottom of the sidebar instead, out of the contested
space: a sidebar row (server glyph + current host + upward chevron) opening a
menu of recent servers plus "Connect to new server…". The drag strip and the
sidebar's traffic-light top margin are unchanged — those keep the OS window
controls off the sidebar card.
The picker now gates on the picker IPC resolving rather than on
isMacElectronShell(), so Windows and Linux desktop gain a picker they never
had; browsers still render nothing.
Also add GET /.well-known/omnigent.json, an unauthed version manifest for
non-browser clients. The desktop shell ships and updates on its own cadence,
so any installed build can meet any server version, and it had no way to learn
what it was talking to before loading the SPA (/v1/info is read by the SPA
after boot, too late to decide how to open a window). The shell fetches it on
every path that loads a server — startup, connect, and server switch — stores
it per window, and forwards it to the SPA.
Compat is the point of the document, in both directions:
* Clients gate on `manifest_version >= N`, never `=== N`, so a newer server
keeps working with an older shell. Adding a field never bumps the version.
* A 404 (every server older than the route), an unreachable host, HTML from
an SPA catch-all, or malformed JSON all resolve to the same pre-manifest
baseline, which means "use existing behavior" — never an error, and never
a blocked connection. The fetch is not awaited before loadURL.
* `.well-known` joins the API-fallback allowlist so an unmatched path under
it returns a JSON 404 instead of index.html. Without that, a shell probing
an older server would get 200 text/html and could parse the SPA shell as a
manifest — the 404 is what makes "no manifest" detectable at all.
The dev proxy forwards /.well-known too; otherwise Vite answers with
index.html and the capability is invisible in local development.
Verified end-to-end in the desktop shell run from source: server route → shell
fetch → per-window store → IPC → renderer, and the baseline fallback when the
manifest is unreachable.
Co-authored-by: Isaac
Signed-off-by: Dhruv Gupta <dhruv.gupta@databricks.com>
|
||
|
|
2ee95e1a3e |
chore(web): require explicit returns (#4028)
Signed-off-by: Pat Sukprasert <pat.sukprasert@databricks.com> |
||
|
|
f63b297508 |
perf(web): load Shiki language grammars lazily instead of in the eager core chunk (#3496)
## Related issue N/A ## Summary - The `manualChunks` guard that keeps Shiki in one chunk (to avoid a cyclic import crash — the language-index ↔ alias-map split that throws "Cannot read properties of undefined (reading 'flatMap')" and blanks the Monaco/file viewer) matched both `/shiki` and `/@shikijs/`. That also swept every `@shikijs/langs/<lang>` grammar — which Shiki loads via dynamic import as per-language chunks — into the single, eagerly `modulepreload`ed core chunk. So ~200 language grammars (~1.68 MB gzip) were downloaded on every initial page load, even though a session uses only a few languages. - Exclude `@shikijs/langs/<lang>` from the `shiki` chunk so grammars stay lazy per-language chunks. Keep Shiki's core, engines, and bundle glue together so the cyclic core stays intra-chunk — the engines must stay too: excluding them re-splits the cycle across chunks and reintroduces the `flatMap` crash. - Initial-load eager JS drops from ~11.8 MB to ~4.37 MB (Shiki 1.68 MB → 466 KB gzip); grammars become 427 on-demand chunks. Layout-independent (same result under pnpm hoisted and isolated). ## Test Plan - `pnpm --filter web run build` succeeds. - Verified the emitted `shiki` chunk statically imports only the rolldown runtime (no cross-chunk cycle) and contains `bundledLanguagesAlias` co-located with its reader — under both hoisted and isolated node_modules. - Verified per-language grammar chunks (python, rust, typescript, …) are emitted separately and are NOT `modulepreload`ed by `index.html`. - Recommended pre-merge smoke test: open the file viewer / Monaco editor and a markdown code block and confirm syntax highlighting renders. ## Demo N/A ## Type of change - [ ] Bug fix - [ ] Feature - [ ] UI / frontend change - [x] Refactor / chore - [ ] Docs - [ ] Test / CI - [ ] Breaking change ## Test coverage - [ ] Unit tests added / updated - [ ] Integration tests added / updated - [ ] E2E tests added / updated - [x] Manual verification completed - [x] Existing tests cover this change - [ ] Not applicable ## Coverage notes Verified via build output analysis: the `shiki` core chunk is acyclic with the alias map co-located (cycle fix preserved), and language grammars are emitted as separate, non-preloaded chunks. Existing Shiki/code-block tests exercise the runtime highlighting path; this change only affects chunk grouping, not module behavior. ## Changelog Faster initial load — syntax-highlighting language grammars now load on demand instead of all upfront. Signed-off-by: Zeyi (Rice) Fan <zeyi.f@databricks.com> |
||
|
|
dc97ade9f5 |
chore(web): migrate web and electron to root pnpm workspace (#3328)
- Define a root pnpm-workspace.yaml with web/ and web/electron/ packages. - Move npm overrides from web/package.json into workspace overrides, using a shared catalog: for react, react-dom, and shiki. - Preserve 7-day dependency cooldown via settings.minimumReleaseAge: 10080. - Delete web/package-lock.json and web/electron/package-lock.json; add the generated root pnpm-lock.yaml. - Update web/electron/package.json scripts to use pnpm --filter web run build:overlay. - Remove web/.npmrc and web/electron/.npmrc; no committed .npmrc (CI forces the public registry via env var). - Add .github/actions/setup-pnpm so all workflows can share a pinned pnpm 11.15.1 + Node setup. - Convert lint.yml and web-tests.yml to pnpm; update ui-snapshot and e2e-ui workflows. - Update the web-prettier pre-commit hook to run web/node_modules/.bin/prettier directly when present. - Update justfile to prefer pnpm for Electron recipes and lockfile normalization. - Ensure remaining npm-based workflows (editors/vscode/, .github/ci-deps/, deploy/cloudflare/) are untouched and continue to work. - Add pdfjs-dist worker URL import so Vite emits the worker asset under pnpm's hoisted node_modules layout. - Force shiki and its first-party packages into a single build chunk to avoid a Cyclic top-level import that produced a 'flatMap' runtime error in Monaco. - Pin build-tool versions to the legacy npm lockfile (vite 8.1.0, tailwindcss 4.3.1, jiti 2.7.0, lightningcss 1.32.0, postcss 8.5.15) so bundler behavior stays consistent with the pre-migration builds. - Update tests/e2e_ui/test_pwa_build.py to omit the now-incorrect -- separator when forwarding --outDir to pnpm run build:embed. Signed-off-by: Zeyi (Rice) Fan <zeyi.f@databricks.com> |
||
|
|
0e4907a812 |
fix(web): keep regex lookbehinds off the boot path for Safari < 16.4 (#2105)
* fix(web): keep regex lookbehinds off the boot path for Safari < 16.4
Safari older than 16.4 cannot parse regex lookbehind, and several
dependencies put one on the startup path, so iPadOS 15 rendered a blank
white page ("SyntaxError: Invalid regular expression: invalid group
specifier name"):
- mdast-util-gfm-autolink-literal (via remark-gfm) ships a lookbehind
regex literal, which fails at parse time of the entry chunk.
- marked feature-detects lookbehind in a try/catch, but rolldown
constant-folds the probe to `true`, hard-enabling the lookbehind path
at module scope.
- remend (via streamdown) constructs its single-tilde repair regex at
module scope with no guard.
Two-part fix: set build.target to the default browser baseline with the
Safari/iOS floor lowered to 15, so unsupported regex literals are
emitted as runtime RegExp() calls instead of parse-time literals, and
add a small transform that keeps marked's probe a runtime check and
gives the two unguarded constructions a never-matching fallback,
degrading email autolinking and tilde repair on those browsers instead
of crashing.
Verified against Playwright WebKit 16.0, which lacks lookbehind: the
default build reproduces the blank page, the fixed build renders the app
shell with no page errors. Modern Chromium renders identically before
and after. Bundle grows 18 KB (+0.08%).
Fixes #1978
Signed-off-by: Enes Yilmaz <115046343+EnesYilmazcode@users.noreply.github.com>
* fix(web): narrow the lookbehind transform to the affected modules
Per review: gate the rewrites to marked, remend, and mdast-util-gfm-autolink-literal by module id so every other module skips the string-replacement pass instead of running it build-wide.
Signed-off-by: Enes Yilmaz <115046343+EnesYilmazcode@users.noreply.github.com>
---------
Signed-off-by: Enes Yilmaz <115046343+EnesYilmazcode@users.noreply.github.com>
|
||
|
|
b6976c1b20 |
feat(ap-web): installable PWA (manifest + service worker + update prompt) (#116)
* feat(web): installable PWA (manifest + service worker + update prompt)
Rebase of PR #116 onto upstream/main (
|
||
|
|
b0348074fa | refactor: rename ap-web/ to web/ and update all references (#1333) |