feat(app): edit source files on mobile

Use one source-editor contract and shared editing runtime across browser and native hosts so file-pane persistence, conflicts, and line endings keep the same semantics on every platform.
This commit is contained in:
Mohamed Boudra
2026-08-30 21:21:48 +02:00
parent 8533c5c06f
commit 95b7ef823a
23 changed files with 1128 additions and 210 deletions
+1
View File
@@ -109,6 +109,7 @@ Cross-platform React Native app that connects to one or more daemons.
- `workspace-labels` owns one sequenced catalog replica per connected host, the deterministic cross-host projection that surfaces spanning hosts use (the filter page, the manager), and the per-host resolution a workspace row's chips use. Two hosts may give one name different colors, so a row resolves against its own host's catalog and a merged answer would be wrong there. Catalogs never synchronize between hosts; assignment creates a missing definition only on the target host. On the daemon, catalog and assignment rewrites share a journaled commit boundary. Startup recovery completes that commit before workspace or catalog publication.
- `SessionContext` wraps the daemon client for the active session
- Composer UI and submit/draft behavior live in `packages/app/src/composer/`; screens and panels should integrate it from there instead of dropping composer internals into `components/`, `hooks/`, or `screens/workspace/`
- Source editing uses one CodeMirror runtime on web and in an offline native WebView. Its ownership and bridge constraints are documented in [docs/source-editor.md](source-editor.md).
- Timeline reducers in `timeline/session-stream-reducers.ts` handle compaction, gap detection, sequence-based deduplication
- Timeline sync correctness is documented in [docs/timeline-sync.md](timeline-sync.md): live streams are for immediacy, `fetch_agent_timeline_request` is authoritative, and catch-up is paged but complete.
- Voice features: dictation (STT) and voice agent (realtime)
+35
View File
@@ -0,0 +1,35 @@
# Source editor
The source editor has one CodeMirror runtime and two hosts:
- Web mounts the runtime directly into the page.
- iOS and Android mount the same runtime from a generated, offline HTML document in a WebView.
Keep editor mechanics in `packages/app/src/source-editor/`. File loading, conflict handling, and
persistence belong to the file pane's `FileEditorModel`. The source editor receives a document and
emits edits; it does not know about workspaces or daemon RPCs.
## Native bridge
The native bridge sends compact change ranges in normalized LF coordinates. The host-side document
mirror validates and applies them, then restores the file's original line separator before calling
the file model. Full document replacements cross the bridge only for mount and external changes.
Every message carries an editor key. Ignore messages from an old key after remounting or switching
files. Keep the bridge protocol private to this module; React components outside it use
`SourceEditorProps`.
Do not expose raw CodeMirror extensions as the cross-platform API. Add named capabilities to the
source editor contract, then implement them once in the shared runtime or explicitly in each host.
## Embedded bundle
After changing the CodeMirror runtime, bridge protocol, or WebView entry point, run:
```bash
npm --prefix packages/app run build:source-editor-webview
```
The generated `webview-html.ts` is committed so native builds do not need a runtime bundler or
network access. `build:source-editor-webview:check` fails when the committed artifact is stale, and
EAS post-install rebuilds all embedded WebViews.