Skip to content

fixing/merge-conflict - #1

Open
Pavitra-programmers wants to merge 4096 commits into
Pavitra-programmers:merge-conflictfrom
different-ai:dev
Open

fixing/merge-conflict#1
Pavitra-programmers wants to merge 4096 commits into
Pavitra-programmers:merge-conflictfrom
different-ai:dev

Conversation

@Pavitra-programmers

Copy link
Copy Markdown
Owner

Summary

Why

Issue

  • Closes #

Scope

Out of scope

Testing

Ran

  • ...

Result

  • pass/fail:
  • if fail, exact files/errors:

CI status

  • pass:
  • code-related failures:
  • external/env/auth blockers:

Manual verification

Evidence

  • video/screenshot link, or N/A (docs-only)

Risk

Rollback

benjaminshafii and others added 30 commits July 24, 2026 15:58
…nfra failures as revocation (#3080)

Two verified prod failure classes behind 'Server returned 401 after
successful authentication' loops and unfixable Degraded states:

1. Refresh grants outlived the session that authorized them. The token
   endpoint kept minting 45-min tokens carrying a dead sid, which the
   resource rejected with mcp_session_revoked forever. Census at fix
   time: 24 live zombie grants across 16 users (10 deleted sessions,
   14 expired). The token endpoint now checks session liveness for
   refresh_token grants: dead session => 400 invalid_grant + grant
   family cleanup, so clients fall into clean re-authorization.

2. hasActiveMcpSession ended in catch { return false }, reporting any
   DB/infra error as REVOKED (observed in prod: ~2h of rejections for
   a provably alive session, self-healing afterwards, with clients
   pointlessly rotating grants on every retry). Session liveness is now
   three-state (alive / missing / check_failed): check_failed maps to a
   retryable 503 mcp_session_check_unavailable (Retry-After, no
   WWW-Authenticate challenge) on the resource and fails open at the
   refresh gate, with a stable mcp_session_liveness_check_failed log
   marker. Rolling-touch failures alone no longer affect verdicts.
… chip (#3082)

* feat(shell): Arc-style card shell with header panel toggle and background rail

- Main content and side panel render as elevated rounded cards floating
  over the sidebar-colored background (seamless with left sidebar, no
  divider borders).
- Session header gains a PanelRight toggle next to the notification bell
  to open/close the right side panel; active state highlighted.
- Right icon rail (browser/voice/artifacts/extensions) now sits directly
  on the background instead of a bordered strip.
- Resizable handle between cards is transparent so the background gutter
  shows through.

Co-authored-by: Cursor <cursoragent@cursor.com>

* feat(shell): denser chrome, account chip in sidebar footer, no resize grips

- Header: 36px tall with 13px medium title (was 40px/15px semibold).
- Right rail: 36px wide with 15px icons (was 44px/17px).
- Composer panel radius tightened to 18px.
- Resizable handles no longer render the floating grip pill.
- Sidebar footer now shows a profile chip: signed-in Den user with
  initials avatar, name and email (opens settings), or a 'Sign in'
  chip that launches OpenWork Cloud auth when signed out.

Co-authored-by: Cursor <cursoragent@cursor.com>

* fix(shell): remove opaque paint from sidebar resize rail

The rail painted a sidebar-colored overlay to mask the old sidebar
border. With the seamless Arc shell background this rendered as a
thick dark strip between the sidebar and the content card. The rail
is now an invisible drag area with only its subtle hover line.

Co-authored-by: Cursor <cursoragent@cursor.com>

* feat(shell): system UI font stack and 13px max body text

- Body and --font-sans/--font-heading now lead with -apple-system /
  system-ui instead of IBM Plex Sans / Geist.
- Base body size 14px -> 13px; Tailwind text-sm token remapped to 13px.
- Composer editor 15px -> 13px; empty-state hero textarea 14px -> 13px.
- Sidebar section labels (PINNED, WORKSPACES, groups, archived, split
  view) normalized to 12px uppercase.

Co-authored-by: Cursor <cursoragent@cursor.com>

* feat(sidebar): tighter chevron-to-label gap with matching session indent

Group headers use gap-1.5 (was gap-3.5) between the expander chevron
and the group name; session rows shift from ps-3 to ps-1 (nested ps-7
to ps-5) so their titles stay aligned with the group label lane.

* fix(shell): drop sidebar right border; account chip opens a menu

- The shadcn sidebar container's variant-scoped border-e survived the
  earlier plain border-e-0 override and rendered as a 1px black line
  between the sidebar and the content card. Override now uses the same
  group-data-[side=left] variant.
- The sidebar account chip now opens a dropdown: email header, Settings
  (opens settings), and Log out (server sign-out best effort, clears the
  stored Den session, refreshes auth state). Signed-out users get
  Sign in instead of Log out.

Co-authored-by: Cursor <cursoragent@cursor.com>

* feat(sidebar): fade out overflowing labels instead of ellipsis

New .ow-fade-truncate utility masks the last 18px of the label with a
linear-gradient so long session, workspace, group, and split-pill names
fade out Arc-style; short labels are unaffected.

Co-authored-by: Cursor <cursoragent@cursor.com>

* fix(browser): round native WebContentsView corners to match panel card

The browser WebContentsView is a native layer that CSS overflow cannot
clip, so its square corners poked out past the rounded side-panel card.
Electron 35 setBorderRadius(14) matches the card radius.

Co-authored-by: Cursor <cursoragent@cursor.com>

* fix(shell): match side-panel gutter to outer gutter width

The 4px gap between the center card and the side panel card made the
rounded-corner junction read as a notch; use the same 8px gutter as the
shell edges.

Co-authored-by: Cursor <cursoragent@cursor.com>

* Revert "fix(browser): round native WebContentsView corners to match panel card"

This reverts commit 0c11542.

* fix(shell): round the shell panel group so overflow clip matches the cards

react-resizable-panels forces overflow:hidden on the group, which
square-clipped the rounded panel cards at the shell corners. Give the
outer group the same 14px radius so the clip follows the card shape.

Co-authored-by: Cursor <cursoragent@cursor.com>

---------

Co-authored-by: Cursor <cursoragent@cursor.com>
…e icon (#3083)

The dashboard already swapped the favicon to the managed square app icon
client-side, but the tab flashed the default OpenWork mark until the org
context loaded. The dashboard layout now resolves the active org's managed
icon during SSR (via /v1/me/orgs with the request cookies) and ships it in
the initial <link rel="icon">, and WorkspaceFavicon no longer resets the
favicon while the org context is still loading.
…ks (#3087)

The installer returned Bun's runtime CA list as soon as it was non-empty,
which skipped the thorough platform store enumeration. On a network that
re-signs HTTPS, a runtime reporting a partial set of public roots therefore
never picked up the corporate CA, and resolving an install link failed with
"the secure connection isn't trusted on this computer yet".

Union the runtime list, the platform stores, and NODE_EXTRA_CA_CERTS instead
of preferring one, so a partial source can no longer mask a complete one.
NODE_EXTRA_CA_CERTS gives IT a deterministic override matching what the
desktop shell already honors. macOS also reads SystemRootCertificates; the
user-writable login keychain stays out, because `security find-certificate`
ignores trust settings and any local process can write there.

Startup logs and the TLS rejection now carry per-source counts, so an
untrusted certificate is distinguishable from a trust store that could not
be read.

Co-authored-by: Cursor <cursoragent@cursor.com>
A capability that outran the bounded deadline was reported as an
unrecognized provider error, telling the member to look up a JSON-RPC
code with a provider that never sent one.

The abort reason was a plain Error, and the SDK only rethrows an McpError
untouched -- everything else becomes String(reason) on a RequestTimeout,
so the deadline reached diagnostics indistinguishable from a
provider-declared -32001. Abort with a marked McpError instead and check
that marker before any JSON-RPC code is read as the provider's.

Co-authored-by: Cursor <cursoragent@cursor.com>
…on launch (#3085)

* feat(composer): render connect skills as /slug pills; land on empty state on default load

- New [connect-skill ...] draft token keeps the OpenWork Cloud skill
  invocation self-contained; composer shows a compact violet /slug pill
  and the full connect prompt is expanded only at send time.
- Skill pills (local + connect) now display /name to match the slash menu.
- Remove startup last-session restore: a fresh app load with no session
  in the URL lands on the empty new-task state; workspace switching
  still restores the last opened session.

Co-authored-by: Cursor <cursoragent@cursor.com>

* feat(hero): reuse the full session composer in the empty-state hero

The 'What do you need done?' empty state now renders ReactSessionComposer
(skills/commands/MCP menu, agent picker, model picker, mentions) instead of
a plain textarea. A new NewTaskComposer wrapper wires workspace-scoped data
from route-level state, so agent/model choices made before the session
exists carry into the created session. The draft (including skill pill
tokens) is seeded into the session composer on Run task, as before.
Attachments stay disabled pre-session with an explanatory tooltip.

Co-authored-by: Cursor <cursoragent@cursor.com>

* feat(hero): one-step run — auto-send the seeded draft in the created session

Run task from the empty-state hero previously seeded the draft into the new
session's composer and required a second Enter to send. The route now marks
the created session for auto-send (both the workspace path and the
chat-first path), and the session surface consumes the mark and fires its
normal send path once the composer is usable (model idle, not streaming,
model available). If those conditions never hold, the mark is simply never
consumed and the seeded draft stays for manual sending — same one code path
as the send button, so token expansion, analytics, and remote endpoints all
behave identically.

Co-authored-by: Cursor <cursoragent@cursor.com>

* fix(session): stop loading pane takeovers and add quiet cloud-worker shimmer

- Route refreshes no longer replace an already-rendered session surface
  with the full loading pane; the pane only gates the first paint.
- Each blocking step of a route refresh now has a 15s watchdog so a hung
  desktop bridge or unresponsive server surfaces an error instead of an
  indefinite loading state.
- Remote (cloud worker) sessions show a quiet text shimmer instead of
  the dot-ticker loading pane.

Co-authored-by: Cursor <cursoragent@cursor.com>

* fix(chat): even vertical rhythm between transcript step rows

Step messages rendered inside a plain block scroll container, so two rows
in different messages sat flush (0px) while rows within one message were
8px apart. The result was tool/Thought pairs visually glued together with
larger gaps between them, tracking message boundaries rather than
meaning. The scroll area is now a flex column with the same 8px gap.

Co-authored-by: Cursor <cursoragent@cursor.com>

* feat(chat): collapse a finished turn's steps into one "Worked for" line

A completed turn now shows a single muted "Worked for 1m 19s" row that
expands back into the full step run; only the live turn streams its steps
in place. Duration comes from server message timestamps so it survives a
reload, falling back to a step count when they are missing.

Co-authored-by: Cursor <cursoragent@cursor.com>

* feat(chat): fold the answer message's thinking into the collapsed run

The final message carries both its reasoning and the answer text, so its
"Thought" row used to sit above the answer even once the run collapsed.
A collapsed run now renders that reasoning and the message below shows
text only, leaving just the summary line and the answer.

Co-authored-by: Cursor <cursoragent@cursor.com>

* feat(chat): only fold long finished runs; short ones stay listed

A finished turn with a handful of step rows reads fine as a list, so the
"Worked for" summary now appears only above four rows. Live turns always
stream their steps in place.

Co-authored-by: Cursor <cursoragent@cursor.com>

* fix(chat): name org MCP capability calls and recover their ask

"mcp:<connection-id>:<tool>" capability names matched neither the dotted
nor the plugin: shape, so every org MCP call read "Ran a capability";
the trailing tool name carries the meaning. extractQuery also required an
object body, dropping the ask whenever it arrived as a JSON string, which
left the failed-call card without its quote.

Co-authored-by: Cursor <cursoragent@cursor.com>

---------

Co-authored-by: Cursor <cursoragent@cursor.com>
The union fix is only observable where the runtime returns a partial
non-empty CA list, which is Windows: Bun reports 0 system certificates on
macOS, so the short-circuit it replaced never triggered there.

Adds a cross-platform corporate-CA repro (root -> re-signing intermediate
-> leaf, none of it in Bun's bundled roots) that drives the compiled
binary's real /api/resolve-link route, plus a windows-2022 job that runs it
twice: once with the root untrusted, then again with nothing changed except
an Import-Certificate into LocalMachine\Root.

Co-authored-by: Cursor <cursoragent@cursor.com>
* feat(den): expose desktop activation status

Co-authored-by: Cursor <cursoragent@cursor.com>

* feat(installer): recover failed browser activation

Co-authored-by: Cursor <cursoragent@cursor.com>

* feat(den-web): guide organization desktop activation

Co-authored-by: Cursor <cursoragent@cursor.com>

* test(installer): support deterministic activation demos

Co-authored-by: Cursor <cursoragent@cursor.com>

* test(evals): prove organization activation journey

Co-authored-by: Cursor <cursoragent@cursor.com>

* feat(den-web): apply the Paper install-guide design

Rework the organization install guide to match the approved Paper flow:
step cards carry complete/active/pending styling with chevrons, step 2
splits into an already-installed panel plus a preview of the installer as
it appears on this computer, and step 3 pairs the return button with an
explicit waiting or connected state.

Co-authored-by: Cursor <cursoragent@cursor.com>

---------

Co-authored-by: Cursor <cursoragent@cursor.com>
The nuke manifest left three kinds of state behind, so workspaces and
sessions reappeared after a fresh start:

- $XDG_STATE_HOME/opencode (prompt history, frecency, kv, locks) was
  never targeted; only the opencode data/config/cache dirs were.
- ~/.openwork/openwork-server holds per-workspace audit logs and is a
  sibling of the orchestrator dir, which was the only ~/.openwork entry.
- Each workspace's .opencode/openwork state survived by design.

Workspace registry files in userData are now named individually so a
single locked file can no longer leave the registry intact, and the
known workspace paths are threaded from the workspace store through the
preview IPC, the execute IPC, and the cleanup-worker payload.

Workspace folders and user files inside them stay untouched.

Also drops the redundant building icon from the org onboarding headers.

Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
…#3096)

* feat(shell): fold the bottom status bar into the sidebar account menu

Co-authored-by: Cursor <cursoragent@cursor.com>

* fix(shell): drop the heavy status pill background in the sidebar footer

Co-authored-by: Cursor <cursoragent@cursor.com>

* docs(evals): point Settings selectors at the sidebar account menu

Co-authored-by: Cursor <cursoragent@cursor.com>

---------

Co-authored-by: Cursor <cursoragent@cursor.com>
The installer artifact shipped in v0.18.1 reported 1.0.0 because the mac
Info.plist hardcoded it and nothing else carried a version at all, so a
user or support engineer could not tell which build they had.

- resolve one version from the release tag (local builds fall back to
  apps/installer/package.json) and stamp it into the compiled binary,
  the mac Info.plist, the DMG volume name, and the Windows version
  resource
- add `--version` to the installer CLI and a quiet footer in the window
- keep apps/installer/package.json on the release train via bump-version

Published asset filenames are unchanged.
…o three primitives (#3097)

* refactor(paths): resolve OpenWork and OpenCode paths from one primitive

Path resolution was duplicated ~35 times across the server, desktop shell,
installer and bootstrap CLI. Three copies even carried a comment saying they
"must agree byte-for-byte" with each other, which is what a shared module is
for. Four of the copies had already drifted into real defects:

- The Settings global-opencode-config route hardcoded ~/.config/opencode and
  honored neither OPENCODE_CONFIG_DIR nor XDG_CONFIG_HOME, while the MCP
  subsystem honored both. Since the desktop runtime sets OPENCODE_CONFIG_DIR
  under OPENWORK_DEV_MODE=1, editing global config in the app read and wrote
  the developer's real config instead of the dev sandbox, escaping isolation.
- server.json resolution on the server ignored APPDATA and XDG_CONFIG_HOME,
  so the server and the desktop shell disagreed on the path on Windows.
- runtimeDbPath repeated the same wrong ~/.config/openwork default.
- The desktop checked only root-level opencode.json(c) while the server also
  checked .opencode/, so the runtime created a shadowing root config for
  workspaces that already had a hidden one.

packages/paths ships raw ESM plus hand-written declarations so the Electron
main process can import it directly, and every resolver takes injectable
env/homeDir/platform so it is testable without touching the real filesystem.
The hardened OPENCODE_CONFIG_DIR validation from the MCP resolver is preserved
as the canonical behaviour.

Also makes the runtime-config store test hermetic: it merged the global MCP
layer, so it observed whatever MCP servers the developer had configured. It
fails on dev on any machine with a global MCP entry.

* refactor(url): normalize base URLs from one primitive and honor OPENCODE_MODELS_URL

The embedded server inlined its own dev/prod models-URL branch, so an operator
setting OPENCODE_MODELS_URL was silently ignored on that path and a dev session
without the local inference stack running got a dead catalog URL and an empty
model list. It now uses the resolver that honors the override and probes the
local stack before falling back to production. apps/server/src/cli.ts spawned
the engine without setting the models URL or sweeping legacy config at all;
both boot paths now agree.

Adds @openwork/types/url and collapses the byte-identical copies onto it:
DEN_API_BASE had four independent readers in den-web (one of which was a bare
inline expression in a layout), and the app had two identical server-URL
normalizers.

Note for a follow-up: apps/orchestrator and packages/openwork-bootstrap strip a
single trailing slash (/\/$/) where the rest of the monorepo strips all of them
(/\/+$/), so "http://host//" normalizes differently across process boundaries
and breaks origin equality and cache keys. Both are left untouched here — the
orchestrator is out of scope for this change and the bootstrap CLI ships as raw
.mjs that cannot import this package's source.

* refactor(server): build workspace-keyed SQLite stores from one factory

Four stores (runtime_opencode_configs, openwork_workspace_configs,
cloud_plugin_install_configs, session_group_states) each carried their own copy
of the same ~50 lines: the table definition, a bun branch using drizzle upsert,
a node branch using raw ON CONFLICT SQL, the CREATE TABLE DDL written out twice
per file so it could be used from both branches, a local isRecord, and a private
dbByPath cache.

That last part was the actual hazard: four independent connection caches
pointing at the same SQLite file. They now share one cache and one connection,
and the DDL is generated once per table instead of eight times in total.

session_group_states keeps its extra schema_version column through the factory's
extraColumns option rather than being forced into a lossy shape. All four stores
keep their existing exported names and signatures, so callers are untouched and
no migration is involved.

* fix(evals): make the core flow require a real assistant reply

The canonical proof could pass without the agent ever responding. The prompt is
"Reply with exactly: core-flow ok", so asserting that the page contains
"core-flow ok" is satisfied by the echoed user bubble alone — waitForText and
the screenshot's requireText were both tautologies.

Observed on a real Daytona run: the step passed in 1.4s with a frame showing
only the user message and no reply. Scoping the assertion to an assistant
message makes the same step wait 5.9s for the response to stream in.

Verified against a user-only transcript: the previous predicate passes, the new
one fails, and it still passes on a transcript that has a real reply.

* fix(build): make the new paths package resolvable in every build context

Adding a workspace package is not free: three build contexts resolve the
workspace by hand and each needed teaching about it.

- apps/installer declares its own bun `workspaces` array, so `bun install`
  reported "@openwork/paths@workspace:* failed to resolve" and the Windows
  compile step failed outright. Added the package to that array.
- The Windows trust job already carries a copy fallback for install-config
  because bun 1.3.9 on Windows can fail to create the parent-relative workspace
  symlink. @openwork/paths hits the same case, so it now uses the same fallback.
- Dockerfile.den copies apps/desktop/package.json for version metadata, which
  drags apps/desktop's dependencies into pnpm workspace resolution. That failed
  with ERR_PNPM_WORKSPACE_PKG_NOT_FOUND while building packages/email, so the
  image now copies packages/paths too.

Also verified the packaged desktop app, since the Electron main process had no
non-builtin runtime imports before this change and a missing module there would
only show up as a boot failure in a real build: electron-builder resolves the
pnpm workspace symlink and ships /node_modules/@openwork/paths/index.mjs inside
app.asar, and the packaged app boots with no module-resolution errors.
…apsed chip (#3100)

Co-authored-by: Cursor <cursoragent@cursor.com>
Rebuilds step 2 of the organization install guide around the fresh-install
case, matching the approved Paper design:

- Eyebrow, "Open the file you just downloaded" heading, a file chip naming
  the real installer artifact, two numbered actions, a calm amber OS trust
  note, a handoff note, an OR divider, the demoted already-installed row
  with the single dark primary button, and a quiet manual-paste disclosure.
- Copy is per-OS (macOS / Windows / Linux) and follows the platform the user
  actually downloaded, falling back to browser platform detection.
- The file chip shows the real published artifact name from
  genericInstallerArtifactName() (no version, because the published assets
  carry none) and is omitted when the platform or arch is unknown, so the
  page never invents a filename.
- The handoff note describes what the installer really does instead of
  promising that this page auto-advances to step 3, which it cannot observe:
  the installer resolves its own activation grant from the install token, so
  the web page's code is a different code.
- Installer preview: fake CTA flattened to a hairline outline, badge
  relabelled "PREVIEW · WHAT YOU'LL SEE ON YOUR COMPUTER" with a neutral
  dot, and the column stretches to match the left column height.

Eval flows are updated for the new copy and for the manual-paste disclosure.

Co-authored-by: Cursor <cursoragent@cursor.com>
…#3107)

The expired-install-link assertion pinned copy that no longer shipped, so
the suite failed on a clean checkout. Assert the actual contract (no raw
API error code leaks, the message names the link, expiry, and who to ask)
so wording can improve without breaking the test.
The installer artifact shipped in v0.18.1 reported 1.0.0 because the mac
Info.plist hardcoded it and nothing else carried a version at all, so a
user or support engineer could not tell which build they had.

- resolve one version from the release tag (local builds fall back to
  apps/installer/package.json) and stamp it into the compiled binary,
  the mac Info.plist, the DMG volume name, and the Windows version
  resource
- add `--version` to the installer CLI and a quiet footer in the window
- keep apps/installer/package.json on the release train via bump-version

Published asset filenames are unchanged.
benjaminshafii and others added 30 commits July 30, 2026 12:34
…otstrap, self-diagnosing failures (#3344)

* fix(evals): bootstrap den app specs reliably

* fix(evals): define app readiness as an interactive UI, share the predicate, resolve workspace id from product state

* fix(evals): rename shadowed route binding
* feat: Add a useful right-panel action chooser

Open-Work-Snacks-Run: e9cf7d72-908a-42f2-884b-ba24ae0422db:b7b433ddc491c04a22aedcef4b450d3dcee8f989d260f43d0179e4b61f769033

* test(evals): detect current right-panel chooser

---------

Co-authored-by: open-work-snacks <open-work-snacks@users.noreply.github.com>
* fix(release): respect protected dev workflow

* docs(release): require AUR PR merge confirmation
Open-Work-Snacks-Run: b4c2b9fa-471a-4e08-ac32-d2a4d3bf42b1:7c64e983a335d6f0304e3eacd7dc2350309a6a7bd427ca2b1d95a91725de1696

Co-authored-by: open-work-snacks <open-work-snacks@users.noreply.github.com>
* feat: Add platform-number shortcuts for visible chat sessions

Open-Work-Snacks-Run: acb7f568-3f18-4119-a164-75f92b5be370:4aa2d15810291d5c4e67fdd411d5266237d1bd97f03c33691c20898c46da7f69

* fix: keep session number shortcuts global

* fix: allow session jumps through select popovers

---------

Co-authored-by: open-work-snacks <open-work-snacks@users.noreply.github.com>
Open-Work-Snacks-Run: 024e0020-9163-4b43-9471-6703dca8c034:b3d42022a8e50740946186f9815c8272402d78b39d1df89d63764ee13aaf1abf

Co-authored-by: open-work-snacks <open-work-snacks@users.noreply.github.com>
* fix(den): harden email sign-in resolution

* test(lab): avoid reserved port reuse
* feat: Animate overflowing chat titles on hover and focus

Open-Work-Snacks-Run: 5608fb1b-df16-45af-8993-bfd5b562a3df:1d9b982f8426b8991c95edb816b8f9ab286e7da4941aefe4d30095ef7f8b65eb

* test(evals): target current session title marquee

* fix(app): suppress tooltip during title reveal

---------

Co-authored-by: open-work-snacks <open-work-snacks@users.noreply.github.com>
* build(deps-dev): bump vite from 6.4.1 to 6.4.3

Bumps [vite](https://github.com/vitejs/vite/tree/HEAD/packages/vite) from 6.4.1 to 6.4.3.
- [Release notes](https://github.com/vitejs/vite/releases)
- [Changelog](https://github.com/vitejs/vite/blob/v6.4.3/packages/vite/CHANGELOG.md)
- [Commits](https://github.com/vitejs/vite/commits/v6.4.3/packages/vite)

---
updated-dependencies:
- dependency-name: vite
  dependency-version: 6.4.3
  dependency-type: direct:development
...

Signed-off-by: dependabot[bot] <support@github.com>

* fix: allow dependabot vite transitive deps

---------

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: OmarMcAdam <gh@mcadam.io>
Bumps [postcss](https://github.com/postcss/postcss) from 8.4.38 to 8.5.18.
- [Release notes](https://github.com/postcss/postcss/releases)
- [Changelog](https://github.com/postcss/postcss/blob/main/CHANGELOG.md)
- [Commits](postcss/postcss@8.4.38...8.5.18)

---
updated-dependencies:
- dependency-name: postcss
  dependency-version: 8.5.18
  dependency-type: direct:development
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Bumps [@better-auth/scim](https://github.com/better-auth/better-auth/tree/HEAD/packages/scim) from 1.6.11 to 1.6.25.
- [Release notes](https://github.com/better-auth/better-auth/releases)
- [Changelog](https://github.com/better-auth/better-auth/blob/main/packages/scim/CHANGELOG.md)
- [Commits](https://github.com/better-auth/better-auth/commits/v1.6.25/packages/scim)

---
updated-dependencies:
- dependency-name: "@better-auth/scim"
  dependency-version: 1.6.25
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Bumps [tailwind-merge](https://github.com/dcastil/tailwind-merge) from 3.5.0 to 3.6.0.
- [Release notes](https://github.com/dcastil/tailwind-merge/releases)
- [Commits](dcastil/tailwind-merge@v3.5.0...v3.6.0)

---
updated-dependencies:
- dependency-name: tailwind-merge
  dependency-version: 3.6.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Bumps [minimatch](https://github.com/isaacs/minimatch) from 10.1.1 to 10.2.5.
- [Changelog](https://github.com/isaacs/minimatch/blob/main/changelog.md)
- [Commits](isaacs/minimatch@v10.1.1...v10.2.5)

---
updated-dependencies:
- dependency-name: minimatch
  dependency-version: 10.2.5
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Bumps [tsx](https://github.com/privatenumber/tsx) from 4.21.0 to 4.23.1.
- [Release notes](https://github.com/privatenumber/tsx/releases)
- [Changelog](https://github.com/privatenumber/tsx/blob/master/release.config.cjs)
- [Commits](privatenumber/tsx@v4.21.0...v4.23.1)

---
updated-dependencies:
- dependency-name: tsx
  dependency-version: 4.23.1
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Bumps [@codemirror/lang-markdown](https://github.com/codemirror/lang-markdown) from 6.5.0 to 6.5.1.
- [Changelog](https://github.com/codemirror/lang-markdown/blob/main/CHANGELOG.md)
- [Commits](https://github.com/codemirror/lang-markdown/commits)

---
updated-dependencies:
- dependency-name: "@codemirror/lang-markdown"
  dependency-version: 6.5.1
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
* build(deps): bump next from 16.2.1 to 16.2.11

Bumps [next](https://github.com/vercel/next.js) from 16.2.1 to 16.2.11.
- [Release notes](https://github.com/vercel/next.js/releases)
- [Commits](vercel/next.js@v16.2.1...v16.2.11)

---
updated-dependencies:
- dependency-name: next
  dependency-version: 16.2.11
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>

* fix: pin next browser mapping transitive

---------

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: OmarMcAdam <gh@mcadam.io>
* build(deps): bump react-dom and @types/react-dom

Bumps [react-dom](https://github.com/react/react/tree/HEAD/packages/react-dom) and [@types/react-dom](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/react-dom). These dependencies needed to be updated together.

Updates `react-dom` from 18.2.0 to 19.2.8
- [Release notes](https://github.com/react/react/releases)
- [Changelog](https://github.com/react/react/blob/main/CHANGELOG.md)
- [Commits](https://github.com/react/react/commits/v19.2.8/packages/react-dom)

Updates `@types/react-dom` from 18.2.25 to 19.2.3
- [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases)
- [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/react-dom)

---
updated-dependencies:
- dependency-name: "@types/react-dom"
  dependency-version: 19.2.3
  dependency-type: direct:development
  update-type: version-update:semver-major
- dependency-name: react-dom
  dependency-version: 19.2.8
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>

* fix: align react catalog with react dom

---------

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: OmarMcAdam <gh@mcadam.io>
…3376)

The boot takeover showed a progress bar hardcoded to two thirds that only
pulsed, so a slow sandbox read as frozen at 66%. It also ran two spinners
at once, and Retry appeared only after a hard failure, leaving a slow but
healthy boot with nothing to do.

Progress is now derived from the status we already poll, so it can never
claim more than we can prove: a provisioning sandbox is still being
reserved, while a waking or updating one demonstrably exists. Only the
active checkpoint animates. At 45s the copy escalates and Retry / Sign out
appear.

Also fixes the dot ticker, which computed to fully transparent: the
--dls-*-rgb tokens are space-separated but the rules used legacy comma
rgba(), so the indicator was invisible everywhere it was used, including
the composer wait state.

Co-authored-by: Cursor <cursoragent@cursor.com>
…3375)

Providers were identifiable only by a two-letter monogram unless they were
one of the three brands with a bundled inline SVG, which made the connect
dialog read as a wall of grey initials.

Adds a logo resolution ladder (inline SVG, Simple Icons, favicon, monogram
last) so a provider only falls back to initials once every source is
exhausted. Long-tail catalog ids are slugified domains, so unslugging
"302ai" to "302.ai" recovers a real mark instead of "30".

Builds on that to group the dialog into Connected and All providers, lead
the API-key step with the provider's own logo, and make the model picker's
API-keys row reflect whether any keys exist yet.

Co-authored-by: Cursor <cursoragent@cursor.com>
better-sqlite3 11.10.0 ships no `node-v137` (Node 24) prebuild, so every CI
install fell through `prebuild-install` to `node-gyp rebuild`, which downloads
the Node headers from nodejs.org mid-install. When that request stalls the whole
install dies:

    prebuild-install warn install No prebuilt binaries found (target=24.13.0 ...)
    gyp ERR! stack AggregateError [ETIMEDOUT]
    [ELIFECYCLE] Command failed with exit code 1

Bump better-sqlite3 to ^12.11.1, which publishes node-v137 (and v127/v141/v147)
prebuilds, so installs fetch a binary instead of compiling. 12.0.0 was a
build-matrix-only major (dropped EOL Node 18 / Electron 26-28); the JS API is
unchanged and Electron 35 (ABI 133) prebuilds are still published.

Also cache the pnpm store in the tests workflow, matching the release/alpha
workflows: OpenWork Tests was re-downloading all 1453 packages every run
("reused 0"), which is both slow and extra network surface to flake on.
…ehind its components, timeline observability (#3359)

* feat(evals): timeline primitive, workspace seeding, and honest visual expectations

* fix(evals): seed completes onboarding and engine boot; wait on product state not route shapes

* fix(evals): keep app-smoke on the product's own workspace creation path

* test(evals): app pointed at a TLS-broken den must name the fault (welcome surface, no onboarding needed)

* chore(evals): single-spec sandbox runner

* test(evals): adapt the TLS-fault spec to the real pre-workspace surface

* test(evals): choose the sign-in control from real buttons

* test(evals): TLS-intercepted den — no false 'connected', and diagnostics name the interception

* test(evals): one frame — sign-in against a broken den changes nothing visually

* test(evals): name the TLS spec after what it actually proves

* fix(evals): short per-probe timeouts so busy renderers are retried, not waited on

* fix(evals): read the created workspace via the proven in-page server call, not an unverified bridge channel

* test(evals): poll patiently through the cold-profile renderer block

* fix(evals): poll for the created workspace record through renderer blocks

* fix(evals): resolve the workspace id from product state after onboarding instead of a hanging server fetch

* fix(evals): idempotent reads retry through renderer blocks

* fix(evals): retry reads to a deadline, not a fixed attempt count

* fix(evals): re-attach to the app's current page target when evaluations stop answering

* fix(evals): background prep does not make the welcome surface un-interactive

* chore(evals): verify the X display actually answers before spawning Electron

* chore(evals): clear stale Electron processes before each sandbox spec run

* fix(evals): resolve the workspace id after onboarding completes, not before

* fix(evals): report the workspace id even while the welcome surface is showing

* test(evals): assert the first-run workspace id after onboarding adopts it

* test(evals): use the resolved workspace id; report loaded skills on failure

* fix(evals): parse the skill name from the row, and drop a regex that never compiled

* test(evals): wait for the assistant to settle; use the session control when the button is not text

* test(evals): wait for output to stabilise; stop assuming session ids appear in the route

* fix(evals): settings and extensions surfaces are interactive too

* test(evals): read the created session id from the product's session list

* test(evals): drop an exact timing threshold that can flake by a millisecond

* test(evals): first run signs in through a real browser, then shares a skill via a marketplace

* chore(evals): verify the display in the full runner; give single-spec runs den env

* refactor(evals): move environment healing behind the components that own it

Target re-attach now lives in @openwork/cdp (evaluateOnSurface), display liveness
and stale-surface cleanup in @openwork/hosts (spawnElectron), and resolveHost no
longer picks the Daytona host when the caller is already inside a sandbox. The
sandbox runner scripts drop the logic they were carrying.

* test(evals): match the real desktop-auth handoff URL and read Den's deep link from the browser

* test(evals): switch the browser from sign-up to sign-in for a seeded account

* chore(evals): let a single-spec run ensure the Den stack when the spec needs it

* test(evals): collapse workspace arrangement to the proven onboarding path

seedWorkspace arranged a workspace over the local server API and left the
engine unconfigured and the model catalog empty — a state the product's own
onboarding never produces, so specs failed on arrangement instead of their
subject. Every spec now goes through createAndSelectWorkspace, the path the
passing journeys already proved.

Also read the created session id from the field session.list_sessions really
returns: items carry sessionId, not id (probed live; the old extraction never
matched, so the wait timed out even with sessions present).

* test(evals): drive den web's real two-step sign-in and read the sign-in code input

Probed live on a running den: auth is an email-only step (Next) that routes
to a password step (Sign in) — there is no single form and no sign-up/sign-in
toggle. After sign-in the deep link is not an anchor or page text; it is a
readonly input holding the openwork://den-auth?grant=… sign-in code next to
Open OpenWork, so read it from there.

* fix(evals): keep pnpm version redirection warm inside isolated Electron profiles

Each surface's fresh HOME hides the host's pnpm tool cache, so the pinned
pnpm (packageManager) is re-downloaded from the network on every spawn
(21MB). On the eval sandbox one failed download degenerated into a
self-sustaining recursive 'pnpm add pnpm' cascade that outlived the run and
starved later spawns. Point PNPM_HOME at the host's real pnpm home; the
redirect is then local and instant (verified: fresh HOME resolves in 0.75s
with no downloads).

* chore(evals): export den eval env only when a den actually answers

Exporting OPENWORK_EVAL_DEN_API_URL unconditionally made den-gated specs run
against nothing and die in 3ms with 'fetch failed' instead of skipping with
their own reason. Probe /health first; with OPENWORK_SPEC_NEEDS_DEN=1 the
stack is still ensured before the probe.

* test(evals): scroll the claimed skill row into view before its screenshot

The skills menu is a scrollable list: /browser-automation was loaded (the
DOM assertions passed) while the screenshot showed only the rows above it,
so the visual validator honestly reported it absent.

* fix(evals): survive renderer freeze bursts while reading the skills menu

The workspace engine boot blocks the renderer JS thread in bursts. Bare
20s evaluations (plug-menu clicks) died with raw CDP timeouts, and the
measure evaluations gave their outer CDP call the same 20s deadline as the
in-page poll, so the two raced under load. Fold the menu clicks into a
guarded, retried wait and give the measures headroom over their inner
deadlines.

* test(evals): reveal the menu row a visual claim names before its screenshot

The capability menu is a scrollable popover: all four sections were in the
DOM (the code assertion passed) while Agents sat above the fold, so the
validator honestly reported it invisible. Scroll the named row into view and
let the code assertion carry section completeness.

* test(evals): assert the capability menu visuals a person can actually see

The vision loop caught a real product defect: with a long command list the
capability popover extends under the window header, so its first section row
(Agents) is covered and unclickable (repo workspace, popover top at y=17
under the title bar). Keep four-section completeness as the DOM assertion,
scope the visual claim to the visible sections, and record the defect where
the claim is made.

* test(evals): arm the slow-cloud scenario separately and drive the menu with retried waits

The scenario opened the plug menu inside its own evaluate with fixed
100/300ms delays right after a reload; under load those clicks land before
React handlers attach and the whole block times out. Arm the fetch delay and
the connect witness in one small mutation, open the menu with the guarded
retried helper, then measure.

* test(evals): arrange the real cloud-connected desktop state for slow-cloud skills

The scenario set window.__OPENWORK_GATEWAY__, which flips the app into the
hosted gateway runtime and rewires the local openwork-server client to the
page origin — so client.listSkills hit the Vite dev server and local skills
never rendered, a state no desktop user can reach. The den auth token and
active org id it also set are the real cloud-connected desktop arrangement,
so keep only those. Drop the unused resetSkillsCloudState.

* test(evals): drop the slow-cloud skills block whose arrangement cannot be faithful

On desktop, den traffic goes through the main process, so the renderer
fetch hook never delayed anything (denRequestCount stayed 0), and the
gateway marker it used instead rewired the local server to the page origin.
The block therefore only ever measured an impossible state. Cloud latency
belongs in a den-boundary fault spec like app-den-tls-fault, where the
fault is injected for real.
#3387)

* feat(evals): timeline primitive, workspace seeding, and honest visual expectations

* fix(evals): seed completes onboarding and engine boot; wait on product state not route shapes

* fix(evals): keep app-smoke on the product's own workspace creation path

* test(evals): app pointed at a TLS-broken den must name the fault (welcome surface, no onboarding needed)

* chore(evals): single-spec sandbox runner

* test(evals): adapt the TLS-fault spec to the real pre-workspace surface

* test(evals): choose the sign-in control from real buttons

* test(evals): TLS-intercepted den — no false 'connected', and diagnostics name the interception

* test(evals): one frame — sign-in against a broken den changes nothing visually

* test(evals): name the TLS spec after what it actually proves

* fix(evals): short per-probe timeouts so busy renderers are retried, not waited on

* fix(evals): read the created workspace via the proven in-page server call, not an unverified bridge channel

* test(evals): poll patiently through the cold-profile renderer block

* fix(evals): poll for the created workspace record through renderer blocks

* fix(evals): resolve the workspace id from product state after onboarding instead of a hanging server fetch

* fix(evals): idempotent reads retry through renderer blocks

* fix(evals): retry reads to a deadline, not a fixed attempt count

* fix(evals): re-attach to the app's current page target when evaluations stop answering

* fix(evals): background prep does not make the welcome surface un-interactive

* chore(evals): verify the X display actually answers before spawning Electron

* chore(evals): clear stale Electron processes before each sandbox spec run

* fix(evals): resolve the workspace id after onboarding completes, not before

* fix(evals): report the workspace id even while the welcome surface is showing

* test(evals): assert the first-run workspace id after onboarding adopts it

* test(evals): use the resolved workspace id; report loaded skills on failure

* fix(evals): parse the skill name from the row, and drop a regex that never compiled

* test(evals): wait for the assistant to settle; use the session control when the button is not text

* test(evals): wait for output to stabilise; stop assuming session ids appear in the route

* fix(evals): settings and extensions surfaces are interactive too

* test(evals): read the created session id from the product's session list

* test(evals): drop an exact timing threshold that can flake by a millisecond

* test(evals): first run signs in through a real browser, then shares a skill via a marketplace

* chore(evals): verify the display in the full runner; give single-spec runs den env

* refactor(evals): move environment healing behind the components that own it

Target re-attach now lives in @openwork/cdp (evaluateOnSurface), display liveness
and stale-surface cleanup in @openwork/hosts (spawnElectron), and resolveHost no
longer picks the Daytona host when the caller is already inside a sandbox. The
sandbox runner scripts drop the logic they were carrying.

* test(evals): match the real desktop-auth handoff URL and read Den's deep link from the browser

* test(evals): switch the browser from sign-up to sign-in for a seeded account

* chore(evals): let a single-spec run ensure the Den stack when the spec needs it

* test(evals): collapse workspace arrangement to the proven onboarding path

seedWorkspace arranged a workspace over the local server API and left the
engine unconfigured and the model catalog empty — a state the product's own
onboarding never produces, so specs failed on arrangement instead of their
subject. Every spec now goes through createAndSelectWorkspace, the path the
passing journeys already proved.

Also read the created session id from the field session.list_sessions really
returns: items carry sessionId, not id (probed live; the old extraction never
matched, so the wait timed out even with sessions present).

* test(evals): drive den web's real two-step sign-in and read the sign-in code input

Probed live on a running den: auth is an email-only step (Next) that routes
to a password step (Sign in) — there is no single form and no sign-up/sign-in
toggle. After sign-in the deep link is not an anchor or page text; it is a
readonly input holding the openwork://den-auth?grant=… sign-in code next to
Open OpenWork, so read it from there.

* fix(evals): keep pnpm version redirection warm inside isolated Electron profiles

Each surface's fresh HOME hides the host's pnpm tool cache, so the pinned
pnpm (packageManager) is re-downloaded from the network on every spawn
(21MB). On the eval sandbox one failed download degenerated into a
self-sustaining recursive 'pnpm add pnpm' cascade that outlived the run and
starved later spawns. Point PNPM_HOME at the host's real pnpm home; the
redirect is then local and instant (verified: fresh HOME resolves in 0.75s
with no downloads).

* chore(evals): export den eval env only when a den actually answers

Exporting OPENWORK_EVAL_DEN_API_URL unconditionally made den-gated specs run
against nothing and die in 3ms with 'fetch failed' instead of skipping with
their own reason. Probe /health first; with OPENWORK_SPEC_NEEDS_DEN=1 the
stack is still ensured before the probe.

* test(evals): scroll the claimed skill row into view before its screenshot

The skills menu is a scrollable list: /browser-automation was loaded (the
DOM assertions passed) while the screenshot showed only the rows above it,
so the visual validator honestly reported it absent.

* fix(evals): survive renderer freeze bursts while reading the skills menu

The workspace engine boot blocks the renderer JS thread in bursts. Bare
20s evaluations (plug-menu clicks) died with raw CDP timeouts, and the
measure evaluations gave their outer CDP call the same 20s deadline as the
in-page poll, so the two raced under load. Fold the menu clicks into a
guarded, retried wait and give the measures headroom over their inner
deadlines.

* test(evals): reveal the menu row a visual claim names before its screenshot

The capability menu is a scrollable popover: all four sections were in the
DOM (the code assertion passed) while Agents sat above the fold, so the
validator honestly reported it invisible. Scroll the named row into view and
let the code assertion carry section completeness.

* test(evals): assert the capability menu visuals a person can actually see

The vision loop caught a real product defect: with a long command list the
capability popover extends under the window header, so its first section row
(Agents) is covered and unclickable (repo workspace, popover top at y=17
under the title bar). Keep four-section completeness as the DOM assertion,
scope the visual claim to the visible sections, and record the defect where
the claim is made.

* test(evals): arm the slow-cloud scenario separately and drive the menu with retried waits

The scenario opened the plug menu inside its own evaluate with fixed
100/300ms delays right after a reload; under load those clicks land before
React handlers attach and the whole block times out. Arm the fetch delay and
the connect witness in one small mutation, open the menu with the guarded
retried helper, then measure.

* test(evals): arrange the real cloud-connected desktop state for slow-cloud skills

The scenario set window.__OPENWORK_GATEWAY__, which flips the app into the
hosted gateway runtime and rewires the local openwork-server client to the
page origin — so client.listSkills hit the Vite dev server and local skills
never rendered, a state no desktop user can reach. The den auth token and
active org id it also set are the real cloud-connected desktop arrangement,
so keep only those. Drop the unused resetSkillsCloudState.

* test(evals): drop the slow-cloud skills block whose arrangement cannot be faithful

On desktop, den traffic goes through the main process, so the renderer
fetch hook never delayed anything (denRequestCount stayed 0), and the
gateway marker it used instead rewired the local server to the page origin.
The block therefore only ever measured an impossible state. Cloud latency
belongs in a den-boundary fault spec like app-den-tls-fault, where the
fault is injected for real.

* test(evals): wait for the sign-in outcome, and give org specs a workspace before sign-in

signInInBrowser returned right after clicking Sign in, so the next frame
honestly showed 'Working...'. Wait for the signed-in outcome (or the
sign-in code) before returning.

The signed-in org shell offers no Add workspace entry, and the
workspace.create control there reports ok while creating nothing (its error
lands in closed-modal state) — probed live twice. Arrange org specs the way
a member actually gets there: create the workspace on the proven welcome
path first, then sign in; organization onboarding is completed when it
appears and the existing workspace is reselected either way.

* test(evals): send the role the marketplace access grant API requires

POST /v1/marketplaces/:id/access rejects a grant without role
(viewer|editor|manager). Viewer is what sharing with a colleague means.

* test(evals): read shared skill names from the plugin's resolved components

The resolved marketplace payload carries plugins with component counts only;
skill names live on GET /v1/plugins/:id/resolved as items[].configObject
(objectType skill, title). Read them as the member so visibility stays the
colleague's, not the admin's.

* test(evals): poll the model catalog past its first paint, and pin the managed-recovery defect

The picker can paint 'No models' before the engine's catalog lands (observed
live: 0 models on first read, 7 shortly after on the same boot), so the
primary test polls up to 90s before asserting.

The managed test now pins today's truth: after an admin publishes a
provider, Retry does not deliver it to the composer even though the API
already entitles the member (probed live, 201 + readable as the member, empty
notice survives 90s+). The spec asserts the notice stays honest and the
composer stays usable; when live recovery ships, the pinned wait fails
loudly and the recovery assertions come back from history.

* test(evals): pin the managed defect without typing (no editor without a model)

With no selectable model the composer renders no contenteditable editor, so
the pinned block asserts what is really there: the persistent notice with
Retry and no crash.

* test(evals): pin only the persistent notice after Retry (the button reads Refreshing mid-flight)

* feat(evals): make surface placement explicit, and own browser disposal

resolveHost() reads one ambient env var, so a whole process got one host:
everything local, or everything in one sandbox. A spec could not say 'app
here, browser there' or 'two desktops in two sandboxes' — the topology was
inherited from the environment instead of declared.

- desktop({ host }) and the new chrome({ host }) take a placement.
- localHost() / daytonaSandbox(id) name one, with REPO_ROOT wiring kept
  inside the package. daytonaSandbox() fails loudly from inside a sandbox,
  where the CLI indirection has nothing to target.
- resolveHost() default behaviour is unchanged, so existing specs are
  untouched.

chrome() also fixes a real leak: attachSurface only closes the CDP socket, so
the hand-rolled spawnChrome + attachSurface in first-run-cloud-share left a
browser process running after every run. Disposing now stops the client and
then disposes the surface, which is what kills it.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

8 participants