Skip to content

Commit 631d8fb

Browse files
arul28cursoragentclaude
authored
Desktop UI cleanup and Linear issue resolve flows (#368)
* Desktop UI cleanup and Linear issue resolve flows. Refresh Work, Lanes, chat, and shell surfaces with shared lane/VCS chrome, add Linear quick-view resolve actions with confirmation modals and Work navigation, and land related dev/runtime helpers on the branch. Co-authored-by: Cursor <cursoragent@cursor.com> * ship: prepare lane for review Desktop UI cleanup — simplify control flow, DRY repeated patterns, fix Linear addedLabelIds mutation, update tests for new drawer selectors, and align docs with orchestration rename. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * ship: iteration 1 — fix test-desktop (2), address #3307474740 - Remove test for deliberately-removed Refresh button in UsageQuotaPanel - Add 60s TTL to pending Linear issue work context to prevent stale consumption Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Cursor <cursoragent@cursor.com> Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1 parent 5e38243 commit 631d8fb

98 files changed

Lines changed: 5398 additions & 2346 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

README.md

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -176,6 +176,16 @@ npm run dev:stop # stop the dev runtime
176176
npm stop dev # same as dev:stop
177177
```
178178

179+
Browser preview of the desktop renderer (UI work without Electron):
180+
181+
```bash
182+
cd apps/desktop
183+
npm run dev:vite # mock-only: synthetic window.ade, fast shell
184+
ADE_PROJECT_ROOT=/path/to/project npm run dev:vite:live # mock + live runtime bridge (Linear, sync, lanes)
185+
```
186+
187+
`dev:vite:live` starts the ADE dev runtime, a localhost HTTP bridge to the runtime socket, and Vite with a proxy so the browser can call real backend methods on top of the mock. Set `ADE_PROJECT_ROOT` to your primary project checkout (where `.ade/` and secrets live), especially when working from a lane worktree. Full details: [apps/desktop/README.md](apps/desktop/README.md).
188+
179189
The dev commands intentionally use a temp socket and a separate Electron profile so they do not collide with the installed ADE app:
180190

181191
```text

apps/ade-cli/src/tuiClient/app.tsx

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -345,7 +345,6 @@ export function mergeOptimisticChatSessions(
345345
optimisticSessions.delete(sessionId);
346346
}
347347
const pending = [...optimisticSessions.values()]
348-
.filter((session) => !seen.has(session.sessionId))
349348
.sort((left, right) => {
350349
const rightMs = Date.parse(right.lastActivityAt ?? right.startedAt);
351350
const leftMs = Date.parse(left.lastActivityAt ?? left.startedAt);
@@ -1417,8 +1416,7 @@ export function isPromptWordBackspace(input: string, key: { ctrl?: boolean; meta
14171416
}
14181417

14191418
export function isPromptLineBackspace(input: string, key: { ctrl?: boolean; meta?: boolean; backspace?: boolean; delete?: boolean }): boolean {
1420-
if (isCtrlInput(input, key, "u")) return true;
1421-
return false;
1419+
return isCtrlInput(input, key, "u");
14221420
}
14231421

14241422
type PromptEditResult = { value: string; cursor: number };

apps/desktop/README.md

Lines changed: 158 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,158 @@
1+
# ADE Desktop
2+
3+
Electron client for ADE. The renderer is also runnable in a regular browser for fast UI iteration.
4+
5+
## Surfaces
6+
7+
| Surface | Command | `window.ade` source | Backend |
8+
|--------|---------|---------------------|---------|
9+
| **Desktop dev** | `npm run dev` (repo root) | Electron preload → main IPC → runtime socket | Full |
10+
| **Browser preview (mock)** | `npm run dev:vite` | `browserMock.ts` only | Synthetic demo data |
11+
| **Browser preview (live)** | `npm run dev:vite:live` | Mock + runtime bridge patches | Partial live (see below) |
12+
13+
`apps/web` is the public marketing site. This document covers the **desktop renderer in a browser** (`localhost:5173`), not the marketing app.
14+
15+
## How the browser preview works
16+
17+
Opening `http://localhost:5173` without Electron loads the same React renderer as the desktop app, but there is no preload bridge. On startup:
18+
19+
1. **`browserMock.ts`** (imported first in `main.tsx`) installs a full `window.ade` stub so the UI can render without crashing. It returns built-in demo data for PRs, lanes, sessions, git, and so on.
20+
2. **`attachBrowserRuntimeBridge()`** (called at the end of the mock install) probes `GET /ade-dev-rpc/health`. If the browser runtime bridge is running, it **patches** selected methods on top of the mock and dispatches `ade:runtime-bridge-ready`.
21+
22+
```text
23+
Browser tab
24+
└─ window.ade (mock baseline)
25+
└─ patched methods → fetch /ade-dev-rpc/*
26+
└─ Vite proxy
27+
└─ browser-runtime-bridge.mjs (127.0.0.1:18765)
28+
└─ JSON-RPC → /tmp/ade-runtime-dev.sock
29+
└─ ade serve (same daemon as desktop dev)
30+
```
31+
32+
The mock stays the fallback for everything the bridge does not override. UI work that only reads mock data still works with `dev:vite` alone.
33+
34+
## Launch
35+
36+
### Mock-only (fast UI shell)
37+
38+
From `apps/desktop`:
39+
40+
```bash
41+
npm run dev:vite
42+
```
43+
44+
Optional: export SQLite snapshot so lanes, PRs, sessions, and run-tab config mirror a real project:
45+
46+
```bash
47+
ADE_PROJECT_ROOT=/path/to/your/project npm run export:browser-mock-ade
48+
npm run dev:vite
49+
```
50+
51+
The export runs automatically (best-effort) before `dev:vite` via `predev:vite`. Output:
52+
53+
`src/renderer/browser-mock-ade-snapshot.generated.json`
54+
55+
That file is gitignored. It seeds **read-only** mock data from `.ade/ade.db` at export time. It does **not** include secrets (Linear tokens, API keys).
56+
57+
### Live bridge (real Linear, sync, lanes)
58+
59+
From `apps/desktop`:
60+
61+
```bash
62+
ADE_PROJECT_ROOT=/path/to/your/project npm run dev:vite:live
63+
```
64+
65+
This script:
66+
67+
1. Builds/refreshes the ADE CLI runtime if needed
68+
2. Ensures the dev runtime is listening on `/tmp/ade-runtime-dev.sock` (override with `ADE_DEV_RUNTIME_SOCKET_PATH`)
69+
3. Starts `browser-runtime-bridge.mjs` on `127.0.0.1:18765` (`ADE_BROWSER_BRIDGE_PORT` to override)
70+
4. Starts Vite on port 5173 with a proxy from `/ade-dev-rpc` → the bridge
71+
72+
Open `http://localhost:5173` (or `http://127.0.0.1:5173`).
73+
74+
**Lane worktrees:** if you run from `.ade/worktrees/<lane>`, set `ADE_PROJECT_ROOT` to the primary project checkout (where `.ade/ade.db` and secrets live), not the worktree path. Same rule as `npm run dev`.
75+
76+
Skip runtime rebuild when the CLI is already fresh:
77+
78+
```bash
79+
ADE_PROJECT_ROOT=/path/to/your/project npm run dev:vite:live -- --skip-runtime-build
80+
```
81+
82+
Bridge only (Vite already running):
83+
84+
```bash
85+
ADE_PROJECT_ROOT=/path/to/your/project npm run dev:browser-bridge
86+
```
87+
88+
Verify the bridge:
89+
90+
```bash
91+
curl -s http://127.0.0.1:18765/health | jq .
92+
```
93+
94+
## What the live bridge covers today
95+
96+
When the bridge attaches, these `window.ade` methods call the real runtime instead of the mock:
97+
98+
| Area | Methods |
99+
|------|---------|
100+
| **Project** | `app.getProject`, `app.getWindowSession` — real `projectRoot` / `projectId` from `projects.add` |
101+
| **Linear** | `cto.getLinearConnectionStatus`, `getLinearQuickView`, `getLinearIssuePickerData`, `searchLinearIssues`, `getLinearProjects`, `setLinearToken`, `clearLinearToken` |
102+
| **Sync / mobile** | `sync.getStatus`, `refreshDiscovery`, `listDevices`, `updateLocalDevice`, `connectToBrain`, `disconnectFromBrain`, `forgetDevice`, `getTransferReadiness`, `transferBrainToLocal`, `getPin`, `setPin`, `generatePin`, `clearPin` |
103+
| **Lanes** | `lanes.create`, `lanes.list` (e.g. Linear quick view → create lane) |
104+
105+
Linear must already be connected in that project (Settings → Linear, or token in encrypted store under `.ade/secrets`). The bridge uses the same credentials as desktop dev.
106+
107+
## Still mock-only in the browser
108+
109+
Even with `dev:vite:live`, these stay on the mock until wired to the bridge or another backend:
110+
111+
- Terminals / PTY / live chat sessions
112+
- PR list/detail/actions, git read/write, files on disk
113+
- Remote runtime connection UI (Electron IPC)
114+
- Computer use, App Control, iOS simulator, Mac VM
115+
- Agent chat send/receive, orchestration runs
116+
- Most settings persistence beyond Linear token via bridge
117+
118+
For full product behavior, use **`npm run dev`** (Electron + preload).
119+
120+
## Seeding mock data
121+
122+
Three layers, from lightest to richest:
123+
124+
1. **Built-in demo** — no setup; synthetic lanes, PRs, sessions in `browserMock.ts`.
125+
2. **Snapshot export**`npm run export:browser-mock-ade` with `ADE_PROJECT_ROOT` set; replaces demo rows with data from `.ade/ade.db` and optional disk walks for the Files tab.
126+
3. **Live bridge** — real runtime for Linear, sync, and lane create/list; mock still backs everything else unless you also export a snapshot for read-only parity.
127+
128+
Re-export the snapshot after local DB changes you want reflected in mock-only mode:
129+
130+
```bash
131+
ADE_PROJECT_ROOT=/path/to/your/project npm run export:browser-mock-ade
132+
```
133+
134+
## Environment variables
135+
136+
| Variable | Purpose |
137+
|----------|---------|
138+
| `ADE_PROJECT_ROOT` | Project opened by the bridge and snapshot export (primary checkout, not lane worktree) |
139+
| `ADE_DEV_RUNTIME_SOCKET_PATH` | Dev runtime socket (default `/tmp/ade-runtime-dev.sock`) |
140+
| `ADE_BROWSER_BRIDGE_PORT` | Bridge HTTP port (default `18765`) |
141+
142+
## Related files
143+
144+
| File | Role |
145+
|------|------|
146+
| `src/renderer/browserMock.ts` | Full `window.ade` stub for browser |
147+
| `src/renderer/browserRuntimeBridge.ts` | Patches live methods when bridge is up |
148+
| `scripts/browser-runtime-bridge.mjs` | HTTP → runtime JSON-RPC |
149+
| `scripts/dev-vite-live.mjs` | Orchestrates runtime + bridge + Vite |
150+
| `scripts/export-browser-mock-ade-snapshot.mjs` | SQLite → mock snapshot JSON |
151+
| `vite.config.ts` | Proxies `/ade-dev-rpc` to the bridge |
152+
153+
## Validation
154+
155+
```bash
156+
npm run typecheck
157+
npm run test:unit -- src/renderer/components/app/TopBar.test.tsx
158+
```

apps/desktop/package.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@
1313
"dev:clean": "node ./scripts/clear-vite-cache.cjs && node ./scripts/normalize-runtime-binaries.cjs && node ./scripts/ensure-electron.cjs && node ./scripts/dev.cjs --force-vite",
1414
"predev:vite": "node ./scripts/export-browser-mock-ade-snapshot.mjs --optional",
1515
"dev:vite": "vite --port 5173 --strictPort",
16+
"dev:vite:live": "node ./scripts/dev-vite-live.mjs",
17+
"dev:browser-bridge": "node ./scripts/browser-runtime-bridge.mjs",
1618
"export:browser-mock-ade": "node ./scripts/export-browser-mock-ade-snapshot.mjs",
1719
"build": "tsup && vite build",
1820
"dist:win": "npm run materialize:runtime-resources && npm run validate:runtime-resources && npm run validate:win:artifacts && npm run build && electron-builder --win --x64 --publish never && npm run validate:win:release",

apps/desktop/resources/agent-skills/ade-app-control/SKILL.md

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,3 +49,25 @@ ade --socket app-control terminal signal --signal SIGINT
4949
5050
Only fall back to `ade --socket terminal list --text` and `ade --socket terminal read ...` when no App Control terminal is active.
5151
52+
## Launching ADE itself from inside ADE
53+
54+
If you are an agent running inside one ADE instance (e.g. ADE Beta or stable) and you need to launch the ADE dev desktop app under App Control, the dev launcher is already isolated and safe to run:
55+
56+
```bash
57+
ade --socket app-control launch --command "npm run dev" --text
58+
```
59+
60+
`npm run dev` uses its own runtime socket (`/tmp/ade-runtime-dev.sock`) and a separate Electron profile (`ade-desktop-dev`), so it will not collide with the runtime/socket that is hosting you. Confirm with `ade runtime status --text` before launching — that tells you which socket the CLI is currently attached to.
61+
62+
### Survive Electron restarts
63+
64+
`npm run dev` watches `apps/desktop/src/main/**` and restarts Electron whenever the main bundle rebuilds. After a restart, the App Control drawer UI in the parent ADE window can show stale `Waiting for CDP on 127.0.0.1:<port>` even though the new renderer is already exposed on the same port. From the CLI you can confirm and re-bind:
65+
66+
```bash
67+
ade --socket app-control targets --text # find the new page target id
68+
ade --socket app-control attach-target --target <id> --text
69+
ade --socket app-control snapshot --text # forces the drawer to repaint
70+
```
71+
72+
If `targets` shows a `/devtools/page/<id>` entry with the dev URL (`http://localhost:5173/...`), CDP is healthy — the drawer banner is just lagging until the next snapshot.
73+

0 commit comments

Comments
 (0)