Commit 33e2b72
* fix(terminal): clamp resize to minimum 1 col/row to prevent panic
Prevents alacritty from panicking when receiving zero-dimension resize
events, which can occur during layout transitions on mobile.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* feat(core): add terminal size propagation in layout tree
Add collect_terminal_sizes() to walk the layout tree and build a size
map. Update ConnectionHandler::create_terminal to accept cols/rows.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* feat(desktop): include folders, project order, and terminal sizes in state response
Build terminal size map from registry and use to_api_with_sizes() to
populate cols/rows in layout nodes. Include folders and project_order
in state responses for mobile/web clients.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* chore(mobile/ios): configure iOS project with CocoaPods and signing
Set up CocoaPods integration, development team, scene manifest,
local networking permissions, and rename native library to
okena_mobile_native.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* feat(mobile): add design system with OkenaColors and OkenaTypography
Introduce centralized color palette (backgrounds, borders, accent, text
hierarchy, glass effects) and typography system (SF Pro Text) for
iOS-native dark theme.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* feat(mobile): add terminal scroll, resize, and display offset FFI
Add scroll_terminal, get_display_offset, and resize_local functions.
Improve wide char spacer handling and move inverse flag to painter.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* feat(mobile): add folders, project ordering, and terminal management FFI
Add folder info, project ordering, server terminal size, and
create/close/focus terminal actions. Update handler to use server
terminal dimensions when creating terminals.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* feat(mobile): redesign app with iOS-native dark theme and terminal improvements
Rewrite all screens and widgets with Cupertino-inspired design:
frosted glass headers, card-based layouts, haptic feedback, animated
status indicators. Add pinch-to-zoom, scroll support, auto-fit font
sizing, modifier key system, and text batching optimization to
terminal rendering.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* chore(mobile): regenerate flutter_rust_bridge bindings
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* chore(mobile): remove google_fonts dependency and add devtools config
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* feat(mobile): add LayoutNode sealed class model and update tests
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* refactor(mobile): extract send_action_with_response in ConnectionManager
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* feat(mobile): add fullscreen, git, services, and terminal management FFI
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* chore(mobile): regenerate flutter_rust_bridge bindings
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* feat(mobile): add fullscreen, services, git status, and layout management UI
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* feat(mobile): add terminal selection and scroll info APIs
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* feat(mobile): add layout management, project reorder, and git file contents FFI
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* chore(mobile): regenerate flutter_rust_bridge bindings
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* feat(mobile): add resizable splits, tab management, and minimized terminal UI
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* feat(mobile): add project drawer enhancements (add project, reorder, color picker)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* feat(mobile): add git diff viewer and file contents viewer
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix(ui): make find_word_boundaries work with byte offsets for UTF-8 correctness
Rewrite to operate on byte offsets with char boundary checks instead of
collecting into a Vec<char>, which gave wrong results for multi-byte
characters.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix(terminal): deregister inactive tab panes and add tab-aware navigation
Deregister pane map entries for inactive tabs so stale bounds don't
interfere with spatial navigation. Add try_switch_tab() so Left/Right
keys cycle tabs before falling through to cross-pane navigation.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix(rebase): pass window_id to deregister_pane_bounds in tabs container
The tab-pane deregistration added in feat/ios predates main's multi-window
support, which gave deregister_pane_bounds a leading WindowId parameter.
Adapt the inactive-tab cleanup callsite to main's signature so the rebased
branch compiles.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* docs(mobile): add React Native migration plan (uniffi + native Skia rendering)
Plan to replace the Flutter UI with React Native while keeping okena-core
and alacritty emulation. Primary path: uniffi-bindgen-react-native (JSI)
+ react-native-skia for native terminal rendering; xterm.js explicitly
rejected. Documents the FFI seam, the hot-path packed-buffer bridge, a
spike-gated phased plan, and the "drop Rust" fallback (reuse the web TS
protocol client, still native rendering).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* feat(mobile-ffi): uniffi binding crate for the React Native migration (Phase 1)
New crate `crates/okena-mobile-ffi` re-expresses mobile/native's ~60-function
FFI surface via uniffi proc-macros (uniffi 0.29, JSI/ubrn-ready) — no logic
duplication: every fn delegates to okena_mobile_native's ConnectionManager,
which is reused verbatim (its crate-type gains "lib" so it can be a path dep).
- 31 genuinely-async fns exported with #[uniffi::export(async_runtime="tokio")]
→ JS Promises; sync getters (cells/cursor/scroll/selection/state) stay sync
for the render hot path.
- Adds get_visible_cells_packed(): the visible grid as a compact little-endian
buffer (4B cols/rows header + 13B/cell: codepoint u32, fg u32, bg u32, flags
u8) for the RN Skia renderer (RN_MIGRATION.md Decision C).
- connect() accepts tls + pinned cert fingerprint at the boundary, but they are
a documented no-op pass-through: client-side TLS lives on arch-review-fixes
(PR #134), not on this branch's okena-core. Wiring is a follow-up.
Verified: cargo check passes for okena-mobile-ffi AND okena_mobile_native
(Flutter Rust side intact). Does not touch okena-core, Dart, or frb codegen.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* feat(mobile-rn): RN binding contract + native Skia terminal renderer (Phase 2/3 scaffold)
Scaffolds the React Native side under mobile/rn/ — the two technically-meaty
pieces, not a full app:
- src/native/okena.ts — the native↔TS binding contract: typed OkenaNative
interface for all ~60 FFI fns + record/enum types, sync/async split mirroring
the Rust side. ubrn generates the real impl from crates/okena-mobile-ffi.
- src/native/cells.ts — packed cell-buffer decoder, byte-for-byte matching the
Rust get_visible_cells_packed format (+ a zero-alloc PackedCells view).
- src/components/TerminalView.tsx — terminal_painter.dart's 3-pass paint ported
to @shopify/react-native-skia (no xterm.js): bg rects, style-batched glyph
runs, cursor; rAF repaint gated on isDirty (Decision C); onLayout sizing.
- src/theme.ts, package.json, tsconfig.json, README.md (exact local build steps).
Verified on this box: npm install + tsc --noEmit (strict) pass; Skia APIs
type-checked against @shopify/react-native-skia@1.5.x. Device build is not
possible here (no Android/iOS SDK, no ubrn-generated module) — README documents
the local steps. node_modules gitignored.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* feat(mobile-rn): app shell — state, navigation, screens, drawer, toolbar, layout (Phase 2)
Builds the RN UI on the existing contract + Skia renderer:
- Foundation: SavedServer + LayoutNode models (parseLayout mirrors the Flutter
parser), zustand connection/workspace stores (polling cadence ported from the
Flutter providers, native module injectable for tests), AsyncStorage-backed
persistence behind a swappable interface, and a minimal state-driven router
(no react-navigation native deps). App.tsx wires connection status → nav and
drives workspace polling.
- Screens: ServerList (list + add-server sheet), Pairing (connect→code→paired
with TLS-fingerprint footnote), Workspace (app bar + drawer + layout + toolbar).
- Widgets: ProjectDrawer (custom slide-in; projects/folders, add/reorder/color),
KeyToolbar (ESC/TAB + sticky CTRL/ALT/CMD with control-char + CSI encoding,
shared modifier store), LayoutRenderer (recursive split/tabs with portrait
rotation), TerminalPane (hidden TextInput, tap-focus, scroll/selection gestures
around the Skia TerminalView), StatusIndicator.
Ported from mobile/lib/src/{models,providers,screens,widgets}. Verified:
npm install + npx tsc --noEmit (strict) pass over all 22 RN source files.
No device build here (no SDK / ubrn module) — see mobile/rn/README.md.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* refactor(mobile-ffi): make okena-mobile-ffi self-contained on uniffi 0.31
Move the plain-Rust engine (ConnectionManager, MobileConnectionHandler,
TerminalHolder) and the api data structs out of the retired flutter_rust_bridge
crate mobile/native into crates/okena-mobile-ffi, stripping the #[frb] attributes.
Drop the okena_mobile_native path dependency (and the transitive
flutter_rust_bridge build) so the crate depends only on okena-core + uniffi.
Remove the now-dead execute_action/spawn helpers, and bump uniffi 0.29 -> 0.31
to match uniffi-bindgen-react-native 0.31 used by mobile/rn. Drop mobile/native
from the workspace members.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* feat(mobile-rn): add RN host project, tooling, and ubrn wiring
Turn the mobile/rn scaffold into a complete React Native 0.76 project (minus the
machine-generated native host dirs): index.js, app.json, metro/babel/
react-native config, jest + eslint + prettier, and the RN 0.76 devDependency set.
Add ubrn.config.yaml and ubrn:* scripts, and wire getOkenaNative() to load the
generated module from src/generated. Relocate the JetBrainsMono fonts to
mobile/rn/assets. npm run typecheck + lint + test all pass.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* chore(mobile): remove the Flutter app; update workspace, CI, and docs
Delete the retired Flutter client (lib, ios/android/linux shells, tests,
cargokit, pubspec/flutter configs). Replace the Flutter build-mobile CI job with
a mobile-rn job (npm typecheck + lint) and drop it from the release deps. Update
the root README/CLAUDE, docs/mobile-status.md, .gitignore, and the RN_MIGRATION
status to describe the React Native + uniffi stack.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* fix(ci): make clippy --all-targets green on the branch
Pre-existing breakage surfaced by `cargo clippy --workspace --all-targets`
(CI's "Check compilation" runs `cargo check --release`, which skips tests,
so these test-only failures slipped through):
- remote_apply.rs / client/state.rs test helpers: add the `cols`/`rows`
fields added in ac0a91b, plus the missing ApiProject fields and the
`is_visible` → `show_in_overview` rename.
- text_utils.rs: silence newer clippy lints (is_some_and, drop unwrap()).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* fix(remote-client): use rustls `ring` provider instead of `aws-lc-rs`
`aws-lc-rs`'s jitter-entropy init (`jent_entropy_init`) segfaults on Android
when rustls builds a TLS client connection, crashing the mobile app on
connect (SIGSEGV in libokena-mobile-ffi during the TLS handshake setup).
Switch the rustls crypto provider to `ring`, which is portable on every
target (incl. the Android NDK) and is already what reqwest 0.12's
`rustls-tls` feature pulls in for hyper/tokio-rustls — so a single provider
is shared across reqwest + tungstenite. Applied to both the shared client
(okena-core) and the desktop remote server (src/remote/tls.rs) so the whole
workspace uses one provider; this also drops aws-lc-rs/aws-lc-sys from the
build entirely.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* fix(mobile-rn): ubrn enum/record adapters, skia setEmbolden, @ubjs/core alias
Reconcile the hand-written `OkenaNative` contract with the shapes ubrn 0.31
actually emits, plus two build/render fixes surfaced by running the app:
- okena.ts: translate at the `getOkenaNative` boundary — ConnectionStatus
(PascalCase `.tag` → lowercase `.kind`, Error payload from `.inner.message`),
CursorShape (numeric enum → string union), and ProjectInfo.terminalNames
(JS `Map` → plain object). Without these the status pill and terminal
cursor crash on render (`Cannot read property 'color' of undefined`).
- TerminalView.tsx: drop the synthetic `setEmbolden` calls. react-native-skia
1.12.4's native binding rejects the (typed `boolean`) arg with "Value is
false, expected a number"; all four JetBrainsMono variants are bundled so
the fallback is unused, and italic is still synthesized via `setSkewX`.
- metro.config.js: alias `@ubjs/core` (ubrn's renamed TS runtime, imported by
the generated bindings) to the runtime already shipped inside
uniffi-bindgen-react-native, avoiding a second, version-skewed copy.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* chore(mobile-rn): commit okena-mobile-ffi package manifest + document Android integration
The ubrn turbo module is kept as a local package (`modules/okena-mobile-ffi/`,
a `file:` dependency of the app) rather than letting ubrn clobber the app's
root `android/build.gradle`. Track only its hand-authored `package.json` (so the
`file:` dep resolves on a fresh checkout / in CI — `npm ci` no longer fails);
everything else under it is ubrn-generated and stays gitignored (incl. the
multi-hundred-MB Rust static lib — must never be committed).
README: add a "Verified Android run" section documenting what the end-to-end
run actually required — the local-package layout, the committed fixes (rustls
`ring`, ubrn enum/record adapters, dropped Skia `setEmbolden`, `@ubjs/core`
Metro alias), the post-generation fixups (Node≥20 CMakeLists `require.resolve`,
missing `AndroidManifestNew.xml`), `okena pair` for the pairing code, and the
emulator GL-present crash that makes a physical device necessary for rendering.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* fix(rebase): adapt mobile-ffi and CLI to rebased main API
Post-rebase fixes for API changes that landed on main under the branch:
- send_special_key: bind to_bytes() result before borrowing, since
SpecialKey::to_bytes() now returns Cow<'static, [u8]> (Ctrl(char) support).
- FocusTerminal / SetFullscreen: pass window: None, matching the new
Option<String> window field added for multi-window targeting.
- render_layout / render_terminal_line + resolve.rs test helper: account for
the new cols/rows fields on ApiLayoutNode::Terminal (terminal-size propagation).
- code_view test_col_beyond_length: update expectation to the byte-offset
find_word_boundaries behavior (clicking past end-of-line selects nothing).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* fix(ci): satisfy clippy manual_checked_ops in mobile-ffi
Clippy (-D warnings) flags the manual zero-check before division in the
cols computation. Use checked_div().unwrap_or(0) — behavior-identical
(visible == 0 still yields 0 cols), lint-clean.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: jonasnobile <mesons_rates0p@icloud.com>
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
1 parent ca0d3fc commit 33e2b72
236 files changed
Lines changed: 21855 additions & 14995 deletions
File tree
- .github/workflows
- crates
- okena-core
- src
- client
- okena-files/src
- okena-layout/src
- okena-mobile-ffi
- src
- api
- client
- okena-remote-client/src
- okena-terminal/src/terminal
- okena-ui/src
- okena-views-terminal/src/layout
- tabs
- terminal_pane
- okena-workspace/src
- docs
- mobile
- android
- app
- src
- debug
- main
- kotlin/com/example/mobile
- res
- drawable-v21
- drawable
- mipmap-hdpi
- mipmap-mdpi
- mipmap-xhdpi
- mipmap-xxhdpi
- mipmap-xxxhdpi
- values-night
- values
- profile
- gradle/wrapper
- integration_test
- ios
- Flutter
- Runner.xcodeproj
- project.xcworkspace
- Runner.xcworkspace
- RunnerTests
- Runner
- Assets.xcassets
- AppIcon.appiconset
- LaunchImage.imageset
- Base.lproj
- lib
- src
- models
- providers
- rust
- api
- screens
- theme
- widgets
- linux
- flutter
- runner
- native
- src
- api
- rn
- __tests__
- assets
- modules/okena-mobile-ffi
- src
- components
- models
- native
- screens
- state
- rust_builder
- android
- src/main
- cargokit
- build_tool
- bin
- lib
- src
- cmake
- gradle
- ios
- Classes
- linux
- macos
- Classes
- windows
- test_driver
- test
- models
- src
- app
- cli
- remote
Some content is hidden
Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
67 | 67 | | |
68 | 68 | | |
69 | 69 | | |
70 | | - | |
71 | | - | |
72 | | - | |
73 | | - | |
74 | | - | |
75 | | - | |
76 | | - | |
77 | | - | |
78 | | - | |
79 | | - | |
80 | | - | |
81 | | - | |
82 | | - | |
83 | | - | |
84 | | - | |
85 | | - | |
| 70 | + | |
| 71 | + | |
| 72 | + | |
| 73 | + | |
| 74 | + | |
| 75 | + | |
| 76 | + | |
| 77 | + | |
| 78 | + | |
| 79 | + | |
| 80 | + | |
| 81 | + | |
| 82 | + | |
| 83 | + | |
86 | 84 | | |
87 | 85 | | |
88 | 86 | | |
89 | | - | |
90 | | - | |
91 | | - | |
92 | | - | |
93 | | - | |
94 | | - | |
95 | | - | |
96 | | - | |
97 | | - | |
98 | | - | |
99 | | - | |
100 | | - | |
101 | | - | |
102 | | - | |
103 | | - | |
104 | | - | |
105 | | - | |
106 | | - | |
107 | | - | |
108 | | - | |
109 | | - | |
| 87 | + | |
| 88 | + | |
110 | 89 | | |
111 | | - | |
112 | | - | |
113 | | - | |
114 | | - | |
115 | | - | |
116 | | - | |
117 | | - | |
118 | | - | |
119 | | - | |
120 | | - | |
121 | | - | |
122 | | - | |
123 | | - | |
124 | | - | |
125 | | - | |
126 | | - | |
127 | | - | |
128 | | - | |
| 90 | + | |
| 91 | + | |
| 92 | + | |
129 | 93 | | |
130 | | - | |
131 | | - | |
132 | | - | |
133 | | - | |
134 | | - | |
135 | | - | |
| 94 | + | |
| 95 | + | |
136 | 96 | | |
137 | | - | |
138 | | - | |
139 | | - | |
140 | | - | |
141 | | - | |
142 | | - | |
143 | | - | |
144 | | - | |
145 | | - | |
146 | | - | |
147 | | - | |
148 | | - | |
149 | | - | |
150 | | - | |
151 | | - | |
152 | | - | |
153 | | - | |
154 | | - | |
155 | | - | |
156 | | - | |
| 97 | + | |
| 98 | + | |
157 | 99 | | |
158 | | - | |
159 | | - | |
160 | | - | |
161 | | - | |
162 | | - | |
163 | | - | |
| 100 | + | |
| 101 | + | |
164 | 102 | | |
165 | 103 | | |
166 | 104 | | |
| |||
260 | 198 | | |
261 | 199 | | |
262 | 200 | | |
263 | | - | |
| 201 | + | |
264 | 202 | | |
265 | 203 | | |
266 | 204 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
18 | 18 | | |
19 | 19 | | |
20 | 20 | | |
21 | | - | |
22 | | - | |
23 | | - | |
24 | | - | |
25 | | - | |
26 | | - | |
27 | | - | |
| 21 | + | |
| 22 | + | |
| 23 | + | |
| 24 | + | |
| 25 | + | |
| 26 | + | |
| 27 | + | |
| 28 | + | |
| 29 | + | |
| 30 | + | |
| 31 | + | |
| 32 | + | |
28 | 33 | | |
29 | 34 | | |
30 | 35 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
20 | 20 | | |
21 | 21 | | |
22 | 22 | | |
23 | | - | |
24 | | - | |
| 23 | + | |
| 24 | + | |
25 | 25 | | |
26 | 26 | | |
27 | 27 | | |
| |||
56 | 56 | | |
57 | 57 | | |
58 | 58 | | |
| 59 | + | |
59 | 60 | | |
60 | 61 | | |
61 | 62 | | |
| |||
68 | 69 | | |
69 | 70 | | |
70 | 71 | | |
71 | | - | |
| 72 | + | |
72 | 73 | | |
0 commit comments