| feat(ui): rewrite ui/ with EdgeClaw-derived front-end and pilotdeck bridge backend
Replaces the 4-file Vite demo (gateway-browser-client, main.tsx,
styles.css, vite.config.ts) with the full EdgeClaw-derived UI plus an
Express bridge that talks to src/gateway through pilotdeck-bridge.js,
unblocking dev-mode HMR and parity testing while the migration to the
gateway-only architecture (docs/old-ui-adaptation/04-implementation-plan)
is in flight.
- ui/server: Express bridge serving /api/* and /ws, providers / agent /
git / mcp / memory / projects / sessions routes, cron + always-on
daemon plumbing, vapid push, plugin process manager.
- ui/src: React 18 app — chat-v2 UI, app-shell, code editor, files,
git, mcp, memory, projects, settings, skills, tasks, terminals,
i18n, contexts, hooks, stores, etc.
- ui/src/stores/useSessionStore.ts: session-keyed message store with a
same-turn streaming dedup guard — fixes a bug where a NEW turn's
__streaming_<sid> message would splice out the PREVIOUS turn's
legitimate assistant tail in computeMerged, dropping the prior
assistant reply and reordering the new user message after the new
streaming row.
- ui/public: PWA manifest, icons, screenshots, service worker.
- Build/lint/typecheck config: vite.config.js (with /api /ws /shell
proxy + manualChunks split), tailwind, postcss, eslint, tsconfig,
.nvmrc (v22), node-pty postinstall fixup.
Co-authored-by: Cursor <cursoragent@cursor.com>
| 24 天前 |
| fix(editor): never let a failed load overwrite the real file on save
Previously, when /api/projects/:projectName/file returned a non-2xx
(e.g. during a transient race right after a dev-stack restart), the
useCodeEditorDocument hook caught the error and called
setContent(// Error loading file: ${message}\n// File: ...)
That placeholder text quietly became the editor's authoritative buffer.
A subsequent Ctrl+S — or any other save trigger — then PUT the
placeholder through to fsPromises.writeFile, destroying the real file
on disk. Because writeFile follows symlinks, this also wiped out the
target of any symlinked entry the user happened to be viewing.
The fix decouples error state from buffer state:
- useCodeEditorDocument now tracks loadError separately and leaves
content empty on failure; it also exposes a reload() callback and
cancels stale loads on unmount via a captured cancelled flag.
- handleSave refuses to run while loading or loadError != null,
surfacing the reason via saveError instead of writing stale buffer
contents.
- New CodeEditorLoadError subcomponent renders an error panel with
Retry / Close — it intentionally does not mount a CodeMirror surface
or a Save button, so the failure mode has no path to disk.
- CodeEditor branches on loadError before isBinary; locale strings
added for en + zh-CN.
Co-authored-by: Cursor <cursoragent@cursor.com>
| 19 天前 |
| feat(ui): rewrite ui/ with EdgeClaw-derived front-end and pilotdeck bridge backend
Replaces the 4-file Vite demo (gateway-browser-client, main.tsx,
styles.css, vite.config.ts) with the full EdgeClaw-derived UI plus an
Express bridge that talks to src/gateway through pilotdeck-bridge.js,
unblocking dev-mode HMR and parity testing while the migration to the
gateway-only architecture (docs/old-ui-adaptation/04-implementation-plan)
is in flight.
- ui/server: Express bridge serving /api/* and /ws, providers / agent /
git / mcp / memory / projects / sessions routes, cron + always-on
daemon plumbing, vapid push, plugin process manager.
- ui/src: React 18 app — chat-v2 UI, app-shell, code editor, files,
git, mcp, memory, projects, settings, skills, tasks, terminals,
i18n, contexts, hooks, stores, etc.
- ui/src/stores/useSessionStore.ts: session-keyed message store with a
same-turn streaming dedup guard — fixes a bug where a NEW turn's
__streaming_<sid> message would splice out the PREVIOUS turn's
legitimate assistant tail in computeMerged, dropping the prior
assistant reply and reordering the new user message after the new
streaming row.
- ui/public: PWA manifest, icons, screenshots, service worker.
- Build/lint/typecheck config: vite.config.js (with /api /ws /shell
proxy + manualChunks split), tailwind, postcss, eslint, tsconfig,
.nvmrc (v22), node-pty postinstall fixup.
Co-authored-by: Cursor <cursoragent@cursor.com>
| 24 天前 |
| feat(ui): rewrite ui/ with EdgeClaw-derived front-end and pilotdeck bridge backend
Replaces the 4-file Vite demo (gateway-browser-client, main.tsx,
styles.css, vite.config.ts) with the full EdgeClaw-derived UI plus an
Express bridge that talks to src/gateway through pilotdeck-bridge.js,
unblocking dev-mode HMR and parity testing while the migration to the
gateway-only architecture (docs/old-ui-adaptation/04-implementation-plan)
is in flight.
- ui/server: Express bridge serving /api/* and /ws, providers / agent /
git / mcp / memory / projects / sessions routes, cron + always-on
daemon plumbing, vapid push, plugin process manager.
- ui/src: React 18 app — chat-v2 UI, app-shell, code editor, files,
git, mcp, memory, projects, settings, skills, tasks, terminals,
i18n, contexts, hooks, stores, etc.
- ui/src/stores/useSessionStore.ts: session-keyed message store with a
same-turn streaming dedup guard — fixes a bug where a NEW turn's
__streaming_<sid> message would splice out the PREVIOUS turn's
legitimate assistant tail in computeMerged, dropping the prior
assistant reply and reordering the new user message after the new
streaming row.
- ui/public: PWA manifest, icons, screenshots, service worker.
- Build/lint/typecheck config: vite.config.js (with /api /ws /shell
proxy + manualChunks split), tailwind, postcss, eslint, tsconfig,
.nvmrc (v22), node-pty postinstall fixup.
Co-authored-by: Cursor <cursoragent@cursor.com>
| 24 天前 |
| fix(editor): never let a failed load overwrite the real file on save
Previously, when /api/projects/:projectName/file returned a non-2xx
(e.g. during a transient race right after a dev-stack restart), the
useCodeEditorDocument hook caught the error and called
setContent(// Error loading file: ${message}\n// File: ...)
That placeholder text quietly became the editor's authoritative buffer.
A subsequent Ctrl+S — or any other save trigger — then PUT the
placeholder through to fsPromises.writeFile, destroying the real file
on disk. Because writeFile follows symlinks, this also wiped out the
target of any symlinked entry the user happened to be viewing.
The fix decouples error state from buffer state:
- useCodeEditorDocument now tracks loadError separately and leaves
content empty on failure; it also exposes a reload() callback and
cancels stale loads on unmount via a captured cancelled flag.
- handleSave refuses to run while loading or loadError != null,
surfacing the reason via saveError instead of writing stale buffer
contents.
- New CodeEditorLoadError subcomponent renders an error panel with
Retry / Close — it intentionally does not mount a CodeMirror surface
or a Save button, so the failure mode has no path to disk.
- CodeEditor branches on loadError before isBinary; locale strings
added for en + zh-CN.
Co-authored-by: Cursor <cursoragent@cursor.com>
| 19 天前 |