Skip to content

Add Ratzilla integration to enable Glues in web browsers - #215

Merged
panarch merged 5 commits into
mainfrom
web-ratzilla-integration
Sep 20, 2025
Merged

panarch merged 5 commits into
mainfrom
web-ratzilla-integration

Conversation

@panarch

@panarch panarch commented Sep 19, 2025 •

Copy link
Copy Markdown
Member

Summary by CodeRabbit

  • New Features

    • Web (browser) app added (Instant LocalStorage + Proxy); trunk serve/build support.
    • Unified CLI entrypoint "glues" and renamed server executable "glues-server".
    • CLI theming options (Dark, Light, Pastel, Sunrise, Midnight, Forest).
  • Changes

    • Entry menu simplified: CSV/JSON removed; platform-specific Proxy shortcut and improved File/Git/Mongo prompts (native).
    • Server enables CORS for browser access.
  • Documentation

    • README: Web Build and proxy usage updates.
  • Tests

    • Updated to new cross-platform input API and platform-specific gating.
  • Chores

    • CI: Wasm build workflow added; web dist ignored.

@coderabbitai

coderabbitai Bot commented Sep 19, 2025 •

Copy link
Copy Markdown

Walkthrough

Adds a wasm/web frontend and CI wasm build job, splits backend implementations by target (wasm vs native) with a BackendBox abstraction, removes CSV/JSON backends, introduces a cross-platform input layer, refactors TUI for dual CLI/web targets, and reorganizes server and workspace manifests for unified CLI and server crates.

Changes

Cohort / File(s) Summary
CI / Wasm Build
.github/workflows/rust.yml
Adds wasm_build job (runs after rust_test): installs wasm32-unknown-unknown, caches Rust deps, runs cargo check --target wasm32-unknown-unknown -p glues-tui, installs trunk, and builds tui/web release bundle.
Ignore & Artifacts
.gitignore
Reorders entries and adds tui/web/dist/.
Workspace & new CLI binary
Cargo.toml, bin/glues/Cargo.toml, bin/glues/src/main.rs
Adds bin/glues workspace member/manifest and new unified glues CLI binary that delegates to TUI or server subcommands.
Server crate restructuring
server/Cargo.toml, server/src/main.rs, server/src/lib.rs
Renames package to glues-server, adds library and binary targets, introduces ServerArgs/StorageCommand/run/parse_args, moves server logic into server lib; main delegates to library-run. Adds tower/tower-http deps and CORS-enabled Axum server.
Workspace manifest / features
Cargo.toml
Adds bin/glues to members/default-members and removes certain workspace gluesql feature entries.
Core target-specific deps
core/Cargo.toml
Moves gluesql and reqwest into target-specific dependency blocks (native: memory,csv,file,git,mongo + reqwest rustls; wasm: memory,web + reqwest minimal).
Backend abstraction & boxing
core/src/backend.rs, core/src/backend/proxy/server.rs, core/src/backend/proxy/client.rs
Introduces BackendBox alias (Box on wasm, Box<dyn CoreBackend + Send> on native); updates ProxyServer to accept/hold BackendBox; makes async_trait attrs cfg-aware (?Send on wasm).
Local backend split (native / wasm)
core/src/backend/local.rs, core/src/backend/local/native.rs, core/src/backend/local/wasm.rs, core/src/backend/local/core_backend.rs, core/src/backend/local/directory.rs
Replaces monolithic local backend with architecture-specific modules: native.rs implements Db/Storage (Memory/File/Git/Mongo), Execute trait and sync/pull; wasm.rs provides in-memory Glue Db and Execute with ?Send async trait usage; async attributes gated per-target.
Core Glues & task gating
core/src/glues.rs, core/src/lib.rs, core/src/state/entry.rs
Splits Glues into arch-specific modules (native/wasm), changes Glues.db to Option<BackendBox>, gates task module and exports off wasm, adapts entry state to platform-specific memory_backend and removes CSV/JSON open paths; file/git/mongo branches gated to non-wasm.
Core tests gating
core/tests/backend.rs, core/tests/proxy.rs
Gates several integration tests behind #[cfg(not(target_arch = "wasm32"))].
TUI manifest & targets
tui/Cargo.toml
Renames package to glues-tui, adds library crate-type (rlib,cdylib), features cli/web, and target-specific dependency splits (native vs wasm).
Unified input API
tui/src/input.rs, tui/src/lib.rs, tui/tests/*, tui/tests/tester.rs
Adds cross-platform Input, KeyEvent, KeyCode, KeyModifiers, conversion impls for native/wasm events, to_textarea_input helpers; updates tests and tester helpers to use new input API.
TUI CLI module and mains
tui/src/cli.rs, tui/src/main.rs, tui/src/lib.rs
Adds non-wasm cli module with ThemeArg/TuiArgs and run/parse functions; main delegates to cli on native and is a no-op on wasm; input and web modules exported conditionally.
TUI actions, contexts, views
tui/src/action.rs, tui/src/context.rs, tui/src/context/entry.rs, tui/src/context/notebook.rs, tui/src/transitions.rs, tui/src/views/dialog/help.rs
Removes OpenCsv/OpenJson actions and CSV/JSON menu items; gates file/git/mongo flows to non-wasm; adds new notebook action constants; adapts prompts, help text, and menu items per-arch; consolidates imports.
TUI input & editor integration
tui/src/context.rs, tui/src/context/notebook.rs, tui/src/input.rs
Integrates textarea input mapping (to_textarea_input) and routes inputs through the new Input abstraction; clipboard usage and shortcuts gated per-target.
TUI config & logger
tui/src/config.rs, tui/src/logger.rs
Introduces platform module for config (Csv on native, WebStorage on wasm); get_glue visibility reduced to platform scope; logger writes to DB on native and console on wasm; adds LogExpectExt and LogUnwrapExt.
TUI web frontend & Trunk
tui/src/web.rs, tui/web/Trunk.toml, tui/web/index.html
Adds wasm-bindgen start entrypoint, DomBackend terminal, spawn_local handlers for input, rendering loop, and Trunk config + HTML shell for web bundle.
TUI refactors & small changes
tui/src/app.rs, tui/src/logger.rs, tui/src/transitions.rs, tui/src/views/dialog/help.rs, tests under tui/tests/*
Gating App::run to native, wiring logger/config changes, import consolidations, help text adjusted to reference glues-server and web notes; tests updated to new input types and some gated per-arch.
Documentation
README.md
Updates CLI/server commands and adds a Web Build section describing trunk, wasm target, serve/build commands, and storage notes (Instant/Proxy).

Sequence Diagram(s)

sequenceDiagram
  autonumber
  actor Browser as User (Browser)
  participant Host as WASM Host
  participant Web as tui::web
  participant Term as DomTerminal
  participant App as Glues App
  participant Backend as BackendBox

  Browser->>Host: load index.html
  Host->>Web: wasm_bindgen start()
  Web->>Term: create Dom terminal + key handler
  Term-->>Web: KeyEvent
  Web->>App: consume(Input)
  App->>Backend: dispatch operation (Instant or Proxy)
  Backend-->>App: Result / Transition
  App-->>Term: render frame
Loading
sequenceDiagram
  autonumber
  actor Client as TUI/Web
  participant ClientProxy as ProxyClient
  participant Server as ProxyServer
  participant DB as BackendBox

  Client->>ClientProxy: Proxy request (fetch_notes)
  ClientProxy->>Server: HTTP POST
  Server->>DB: CoreBackend call
  DB-->>Server: Result
  Server-->>ClientProxy: Response
  ClientProxy-->>Client: Data
Loading

Estimated code review effort

🎯 5 (Critical) | ⏱️ ~120+ minutes

Possibly related PRs

Suggested labels

codex

Poem

Hopping through crates with a trunk and a grin,
I stitched TUI to web and trimmed CSV bin.
BackendBox tucked the backends in place,
Trunk built a bundle to run in the space.
Bun applauds the build — a tiny deploy-hop win! 🐇✨

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 51.61% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title Check ✅ Passed The title "Add Ratzilla integration to enable Glues in web browsers" accurately and concisely captures the primary change: adding a Ratzilla-powered web frontend and WASM/web build support (tui/web, Trunk config, wasm CI, target-specific gating across crates). It is specific, short, and relevant to the changeset so a reviewer can quickly grasp the main intent.
✨ Finishing touches
  • 📝 Generate Docstrings
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch web-ratzilla-integration

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@panarch panarch self-assigned this Sep 19, 2025

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 7

🧹 Nitpick comments (35)
tui/web/index.html (2)

9-12: Add SRI to CDN stylesheet

Include integrity and crossorigin on the Fira Code CDN link for supply-chain hardening.

-    <link
-      rel="stylesheet"
-      href="https://cdnjs.cloudflare.com/ajax/libs/firacode/6.2.0/fira_code.min.css"
-    />
+    <link
+      rel="stylesheet"
+      href="https://cdnjs.cloudflare.com/ajax/libs/firacode/6.2.0/fira_code.min.css"
+      integrity="<!-- fill SRI hash here -->"
+      crossorigin="anonymous"
+      referrerpolicy="no-referrer"
+    />

6-8: Remove user-scalable=no for accessibility

Disabling zoom impairs accessibility; omit user-scalable.

-      content="width=device-width, initial-scale=1.0, user-scalable=no"
+      content="width=device-width, initial-scale=1.0"
.github/workflows/rust.yml (1)

50-67: Wasm build in CI: LGTM; minor hardening ideas

  • Consider installing trunk via a pinned action/binary for reproducibility rather than cargo install latest.
  • Optionally upload tui/web/dist as an artifact for preview.

Example pin using taiki-e/install-action:

-      - name: Install trunk
-        run: cargo install trunk --locked --force
+      - name: Install trunk
+        uses: taiki-e/install-action@v2
+        with:
+          tool: trunk@0.20.3
tui/src/web.rs (3)

13-24: Consider better error reporting beyond console logging.

The current implementation logs errors to the console but doesn't provide structured error handling or recovery mechanisms. Consider implementing a more robust error reporting system that could notify users of initialization failures through the UI.


36-49: Verify error handling in event callbacks.

The keyboard event handler silently discards errors with let _ on Lines 45-46. Critical errors during input processing or state saving could go unnoticed.

Consider logging errors or implementing a user-visible error notification system:

-                let action = guard.context.consume(&input).await;
-                let _ = guard.handle_action(action, input).await;
-                guard.save().await;
+                let action = guard.context.consume(&input).await;
+                if let Err(e) = guard.handle_action(action, input).await {
+                    console::error_1(&JsValue::from_str(&format!("Error handling action: {}", e)));
+                }
+                guard.save().await;

51-55: Consider handling lock contention more gracefully.

Using try_lock() prevents blocking but silently skips render frames when the lock is held. This could lead to UI inconsistencies during heavy input processing.

Consider implementing a frame-skip counter or warning mechanism to detect rendering issues:

 terminal.draw_web(move |frame| {
     if let Ok(mut guard) = draw_app.try_lock() {
         guard.draw(frame);
+    } else {
+        // Log frame skip for debugging purposes
+        console::warn_1(&JsValue::from_str("Frame skipped due to lock contention"));
     }
 });
tui/src/config.rs (3)

38-45: Add error handling for missing HOME directory.

The fallback to current directory when HOME is unavailable is reasonable, but silently falling back with expect() could crash in restricted environments.

Consider logging the fallback:

 pub(crate) fn get_glue() -> Glue<CsvStorage> {
     let path = home_dir()
-        .unwrap_or(std::env::current_dir().expect("failed to get current directory"))
+        .unwrap_or_else(|| {
+            let cwd = std::env::current_dir().expect("failed to get current directory");
+            eprintln!("Warning: HOME directory not found, using current directory: {:?}", cwd);
+            cwd
+        })
         .join(PATH);

47-138: Significant code duplication between native and WASM implementations.

Lines 47-99 and 119-171 contain nearly identical logic for init(), update(), and get() functions, with only the storage type differing. This violates DRY principles and makes maintenance harder.

Consider extracting shared logic using a trait or macro:

// Define a trait for storage operations
trait ConfigStorage: Execute {
    fn new_glue() -> Self;
}

// Implement shared logic generically
async fn init_generic<S: ConfigStorage>() {
    let mut glue = S::new_glue();
    // ... rest of the shared logic
}

// Platform-specific implementations just provide the glue creation
#[cfg(not(target_arch = "wasm32"))]
impl ConfigStorage for Glue<CsvStorage> {
    fn new_glue() -> Self {
        // existing get_glue() logic
    }
}

#[cfg(target_arch = "wasm32")]
impl ConfigStorage for Glue<WebStorage> {
    fn new_glue() -> Self {
        Glue::new(WebStorage::new(WebStorageType::Local))
    }
}

58-65: Silent error handling in config initialization.

The let _ = pattern on Lines 59 and 131 silently ignores insertion errors. If default values fail to insert, the application might behave unexpectedly.

Consider at least logging failures:

 for (key, value) in DEFAULTS {
-    let _ = table("config")
+    if let Err(e) = table("config")
         .insert()
         .columns(vec!["key", "value"])
         .values(vec![vec![text(*key), text(*value)]])
         .execute(&mut glue)
-        .await;
+        .await {
+        eprintln!("Warning: Failed to insert default config {}: {}", key, e);
+    }
 }

Also applies to: 130-137

core/src/backend/local/wasm.rs (1)

25-27: No-op sync method may cause confusion.

The sync() method always returns Ok(()) without performing any actual synchronization. This could lead to data consistency issues if callers expect synchronization to occur.

Consider either:

  1. Document clearly that sync is not supported in WASM
  2. Return an error indicating sync is unsupported
  3. Remove the method if it's not required by the interface
 pub fn sync(&self) -> Result<()> {
+    // Sync is a no-op for in-memory storage in WASM environment
     Ok(())
 }
tui/Cargo.toml (1)

26-29: Empty feature flags may cause confusion.

The cli and web features are defined but don't actually enable any dependencies or conditional compilation beyond the binary target gating.

Consider documenting the purpose of these features or removing them if they're only used for binary gating:

 [features]
 default = ["cli"]
+# Feature flag to enable CLI binary compilation
 cli = []
+# Feature flag reserved for future web-specific functionality
 web = []
tui/src/input.rs (2)

86-87: Unexpected Input variant for unhandled events.

Line 86 maps unhandled event types to Input::Resize(0, 0), which could be misleading. A resize event with zero dimensions might be processed incorrectly by downstream code.

Consider adding a dedicated variant for unhandled events or documenting this behavior:

 pub enum Input {
     Key(KeyEvent),
     Paste(String),
     Resize(u16, u16),
+    Unknown,
 }

 // In the From implementation:
-                _ => Input::Resize(0, 0),
+                _ => Input::Unknown,

162-162: Hardcoded KeyEventKind::Press for WASM events.

Line 162 always sets kind: KeyEventKind::Press regardless of the actual event type. This could cause issues if release or repeat events need to be handled differently in the future.

Consider documenting this limitation or checking if ratzilla provides event kind information:

 KeyEvent {
     code,
     modifiers: KeyModifiers::new(event.ctrl, event.alt, event.shift),
+    // TODO: ratzilla doesn't currently expose event kind, defaulting to Press
     kind: KeyEventKind::Press,
 }
tui/src/context.rs (1)

147-153: Forward paste/text events (Input::Paste) to TextArea

to_textarea_input currently only matches Input::Key while enum Input defines Paste(String); update fn to_textarea_input (tui/src/input.rs) to map Input::Paste(s) → the equivalent tui_textarea::Input carrying s so the TextArea used in tui/src/context.rs (lines 147–153) receives pasted/IME/text input.

core/src/backend/proxy/client.rs (1)

18-43: Add client timeouts on native builds; preserve wasm behavior.

core/Cargo.toml already configures reqwest per target, so cfg-gating a Client::builder timeout is safe — apply the patch below.

 use async_trait::async_trait;
+#[cfg(not(target_arch = "wasm32"))]
+use std::time::Duration;
@@
     pub async fn connect<U: Into<String>>(url: U) -> Result<Self> {
         let url = url.into();
-        let client = Client::new();
+        #[cfg(not(target_arch = "wasm32"))]
+        let client = Client::builder()
+            .timeout(Duration::from_secs(10))
+            .build()?;
+        #[cfg(target_arch = "wasm32")]
+        let client = Client::new();
core/src/backend/proxy/server.rs (3)

3-3: Drop unused CoreBackend import.

CoreBackend isn't referenced in this file; keep the import surface minimal.

-use crate::backend::{BackendBox, CoreBackend};
+use crate::backend::BackendBox;

14-14: Relax receiver mutability on handle (enables concurrency).

handle doesn't mutate self; switching to &self removes an unnecessary exclusive borrow and allows concurrent calls.

-    pub async fn handle(&mut self, req: ProxyRequest) -> ProxyResponse {
+    pub async fn handle(&self, req: ProxyRequest) -> ProxyResponse {

Please confirm that BackendBox methods only need &self.


17-88: Deduplicate Ok/Err response mapping.

Many match arms repeat the same Result → ProxyResponse boilerplate. Extract a small helper to reduce repetition and future drift.

 impl ProxyServer {
+    fn map<T, E, F>(res: Result<T, E>, f: F) -> ProxyResponse
+    where
+        E: std::fmt::Display,
+        F: FnOnce(T) -> ResultPayload,
+    {
+        match res {
+            Ok(v) => ProxyResponse::Ok(f(v)),
+            Err(e) => ProxyResponse::Err(e.to_string()),
+        }
+    }
@@
-            FetchDirectory { directory_id } => match self.db.fetch_directory(directory_id).await {
-                Ok(dir) => ProxyResponse::Ok(ResultPayload::Directory(dir)),
-                Err(e) => ProxyResponse::Err(e.to_string()),
-            },
+            FetchDirectory { directory_id } => {
+                Self::map(self.db.fetch_directory(directory_id).await, ResultPayload::Directory)
+            },
@@
-            FetchDirectories { parent_id } => match self.db.fetch_directories(parent_id).await {
-                Ok(dirs) => ProxyResponse::Ok(ResultPayload::Directories(dirs)),
-                Err(e) => ProxyResponse::Err(e.to_string()),
-            },
+            FetchDirectories { parent_id } => {
+                Self::map(self.db.fetch_directories(parent_id).await, ResultPayload::Directories)
+            },

(Apply similarly to other arms.)

tui/tests/entry.rs (1)

74-83: Avoid hardcoded per-arch hotkeys in tests.

Tie the test to a single source of truth (e.g., re-export a PROXY_HOTKEY constant from tui/src/context/entry.rs for tests) to prevent drift when keymaps change.

If no public constant exists, consider adding one behind cfg(test) or a test-only re-export.

tui/tests/tester.rs (1)

38-41: Remove unnecessary unsafe block.

std::env::set_var is safe; the unsafe block is misleading and may trip linters.

-        unsafe {
-            std::env::set_var("HOME", &cwd);
-        }
+        std::env::set_var("HOME", &cwd);
README.md (2)

53-57: Add a brief CORS note for browser → proxy usage.

Wasm builds require the proxy to send CORS headers for cross-origin access; calling this out helps first‑time users.

-  - In the TUI entry menu choose `Proxy`, enter the proxy URL (e.g. `http://127.0.0.1:4000`), and Glues will talk to the remote backend just like it does locally.
+  - In the TUI entry menu choose `Proxy`, enter the proxy URL (e.g. `http://127.0.0.1:4000`), and Glues will talk to the remote backend just like it does locally.
+  - For the web build, ensure the proxy sends appropriate CORS headers (e.g., Access-Control-Allow-Origin) so the browser can reach it.

121-126: Fix markdownlint MD004: use asterisks for unordered list.

Align bullet style to the rest of the doc to satisfy markdownlint.

-- `cargo coverage` - run the workspace under coverage and emit an HTML report at `target/llvm-cov/html/index.html`
-- `cargo coverage-report` - print a text summary (run after `cargo coverage --no-report`; append `--fail-under-lines <N>` to guard CI)
-- `cargo coverage-lcov` - export `target/llvm-cov/lcov.info` for external services
-- `cargo coverage-clean` - remove coverage artifacts
+* `cargo coverage` - run the workspace under coverage and emit an HTML report at `target/llvm-cov/html/index.html`
+* `cargo coverage-report` - print a text summary (run after `cargo coverage --no-report`; append `--fail-under-lines <N>` to guard CI)
+* `cargo coverage-lcov` - export `target/llvm-cov/lcov.info` for external services
+* `cargo coverage-clean` - remove coverage artifacts
tui/src/app.rs (2)

17-20: Dead import due to contradictory cfg; remove.

#[cfg(target_arch = "wasm32")] and #[cfg(not(target_arch = "wasm32"))] stacked together make this use unreachable.

-#[cfg(target_arch = "wasm32")]
-#[cfg(not(target_arch = "wasm32"))]
-use crate::logger::*;

56-72: Throttle autosaves on idle.

Saving on every idle tick can cause needless I/O. Gate on a dirty flag or minimum interval.

Example: track last_save: Instant and only save if state is dirty and elapsed > N secs.

core/src/backend.rs (2)

62-196: Deduplicate Box<...> forwarding impls with a single generic impl

Three nearly identical impls can drift. Replace them with cfg’d generic impls for Box.

Apply this diff to replace the two wasm impls and the non-wasm impl with generic ones:

-#[cfg(target_arch = "wasm32")]
-#[async_trait(?Send)]
-impl CoreBackend for Box<dyn CoreBackend> { … all fns forwarding … }
-
-#[cfg(target_arch = "wasm32")]
-#[async_trait(?Send)]
-impl CoreBackend for Box<dyn CoreBackend + Send> { … all fns forwarding … }
-
-#[cfg(not(target_arch = "wasm32"))]
-#[async_trait]
-impl CoreBackend for Box<dyn CoreBackend + Send> { … all fns forwarding … }
+#[cfg(target_arch = "wasm32")]
+#[async_trait(?Send)]
+impl<T: ?Sized + CoreBackend> CoreBackend for Box<T> {
+    fn root_id(&self) -> DirectoryId { (**self).root_id() }
+    async fn fetch_directory(&mut self, directory_id: DirectoryId) -> Result<Directory> { (**self).fetch_directory(directory_id).await }
+    async fn fetch_directories(&mut self, parent_id: DirectoryId) -> Result<Vec<Directory>> { (**self).fetch_directories(parent_id).await }
+    async fn add_directory(&mut self, parent_id: DirectoryId, name: String) -> Result<Directory> { (**self).add_directory(parent_id, name).await }
+    async fn remove_directory(&mut self, directory_id: DirectoryId) -> Result<()> { (**self).remove_directory(directory_id).await }
+    async fn move_directory(&mut self, directory_id: DirectoryId, parent_id: DirectoryId) -> Result<()> { (**self).move_directory(directory_id, parent_id).await }
+    async fn rename_directory(&mut self, directory_id: DirectoryId, name: String) -> Result<()> { (**self).rename_directory(directory_id, name).await }
+    async fn fetch_notes(&mut self, directory_id: DirectoryId) -> Result<Vec<Note>> { (**self).fetch_notes(directory_id).await }
+    async fn fetch_note_content(&mut self, note_id: NoteId) -> Result<String> { (**self).fetch_note_content(note_id).await }
+    async fn add_note(&mut self, directory_id: DirectoryId, name: String) -> Result<Note> { (**self).add_note(directory_id, name).await }
+    async fn remove_note(&mut self, note_id: NoteId) -> Result<()> { (**self).remove_note(note_id).await }
+    async fn rename_note(&mut self, note_id: NoteId, name: String) -> Result<()> { (**self).rename_note(note_id, name).await }
+    async fn update_note_content(&mut self, note_id: NoteId, content: String) -> Result<()> { (**self).update_note_content(note_id, content).await }
+    async fn move_note(&mut self, note_id: NoteId, directory_id: DirectoryId) -> Result<()> { (**self).move_note(note_id, directory_id).await }
+    async fn log(&mut self, category: String, message: String) -> Result<()> { (**self).log(category, message).await }
+}
+
+#[cfg(not(target_arch = "wasm32"))]
+#[async_trait]
+impl<T: ?Sized + CoreBackend> CoreBackend for Box<T> {
+    fn root_id(&self) -> DirectoryId { (**self).root_id() }
+    async fn fetch_directory(&mut self, directory_id: DirectoryId) -> Result<Directory> { (**self).fetch_directory(directory_id).await }
+    async fn fetch_directories(&mut self, parent_id: DirectoryId) -> Result<Vec<Directory>> { (**self).fetch_directories(parent_id).await }
+    async fn add_directory(&mut self, parent_id: DirectoryId, name: String) -> Result<Directory> { (**self).add_directory(parent_id, name).await }
+    async fn remove_directory(&mut self, directory_id: DirectoryId) -> Result<()> { (**self).remove_directory(directory_id).await }
+    async fn move_directory(&mut self, directory_id: DirectoryId, parent_id: DirectoryId) -> Result<()> { (**self).move_directory(directory_id, parent_id).await }
+    async fn rename_directory(&mut self, directory_id: DirectoryId, name: String) -> Result<()> { (**self).rename_directory(directory_id, name).await }
+    async fn fetch_notes(&mut self, directory_id: DirectoryId) -> Result<Vec<Note>> { (**self).fetch_notes(directory_id).await }
+    async fn fetch_note_content(&mut self, note_id: NoteId) -> Result<String> { (**self).fetch_note_content(note_id).await }
+    async fn add_note(&mut self, directory_id: DirectoryId, name: String) -> Result<Note> { (**self).add_note(directory_id, name).await }
+    async fn remove_note(&mut self, note_id: NoteId) -> Result<()> { (**self).remove_note(note_id).await }
+    async fn rename_note(&mut self, note_id: NoteId, name: String) -> Result<()> { (**self).rename_note(note_id, name).await }
+    async fn update_note_content(&mut self, note_id: NoteId, content: String) -> Result<()> { (**self).update_note_content(note_id, content).await }
+    async fn move_note(&mut self, note_id: NoteId, directory_id: DirectoryId) -> Result<()> { (**self).move_note(note_id, directory_id).await }
+    async fn log(&mut self, category: String, message: String) -> Result<()> { (**self).log(category, message).await }
+}

Also applies to: 198-264


32-33: Ensure log() persistence semantics are consistent

Directory/note operations call sync() after writes; log() may also need sync to persist. Consider updating core/src/backend/local/log.rs to call self.sync(), matching others.

Suggested change in core/src/backend/local/log.rs:

 pub async fn log(&mut self, category: String, message: String) -> Result<()> {
     table("Log")
         .insert()
         .columns(vec!["category", "message"])
         .values(vec![vec![text(category), text(message)]])
         .execute(&mut self.storage)
         .await?;
-
-    Ok(())
+    self.sync()
 }

Also applies to: 59-60

tui/src/main.rs (1)

29-51: Initialize color-eyre before other subsystems

Install error handlers first to capture early failures.

-    config::init().await;
-    logger::init().await;
-    color_eyre::install()?;
+    color_eyre::install()?;
+    config::init().await;
+    logger::init().await;
tui/src/context/entry.rs (1)

65-77: Minor copy edit in Git prompt

Grammar tweak for clarity.

-                    Line::from("The path must contain an existing .git repository.".fg(THEME.hint)),
-                    Line::from("otherwise, an error will occur.".fg(THEME.hint)),
+                    Line::from("The path must contain an existing .git repository;".fg(THEME.hint)),
+                    Line::from("otherwise, an error will occur.".fg(THEME.hint)),
tui/src/action.rs (2)

13-17: Consider using #[cfg(not(target_arch = "wasm32"))] for conditional imports instead of allow(unused_imports).

Using cfg directly would be more idiomatic and clearer about the intent:

-#[cfg_attr(target_arch = "wasm32", allow(unused_imports))]
-use ratatui::style::Stylize;
-
-#[cfg_attr(target_arch = "wasm32", allow(unused_imports))]
-use super::theme::THEME;
+#[cfg(not(target_arch = "wasm32"))]
+use ratatui::style::Stylize;
+
+#[cfg(not(target_arch = "wasm32"))]  
+use super::theme::THEME;

226-229: Consider logging or providing feedback for unsupported operations on wasm32.

Currently, these actions silently do nothing on wasm32. Consider adding a log message or user feedback to indicate that these operations are not supported in the web environment:

 #[cfg(target_arch = "wasm32")]
 Action::Tui(TuiAction::OpenFile)
 | Action::Tui(TuiAction::OpenGit(_))
-| Action::Tui(TuiAction::OpenMongo(_)) => {}
+| Action::Tui(TuiAction::OpenMongo(_)) => {
+    log_warn("File, Git, and MongoDB operations are not supported in the web environment");
+}
core/src/backend/local/native.rs (4)

27-38: Consider adding connection validation for the memory backend.

While the memory backend is simple, consider adding a basic validation or initialization check to ensure the storage is properly set up before returning:

 pub async fn memory(task_tx: Sender<Task>) -> Result<Self> {
     let glue = Glue::new(MemoryStorage::default());
     let mut storage = Storage::Memory(glue);
 
     let root_id = setup(&mut storage).await?;
+    
+    // Validate that the root directory was properly created
+    if root_id.0.is_nil() {
+        return Err(Error::BackendError("Failed to initialize root directory".to_string()));
+    }
 
     Ok(Self {
         storage,
         root_id,
         task_tx,
     })
 }

40-50: Add path validation for file backend.

Consider validating the file path before creating the storage to provide better error messages:

 pub async fn file(task_tx: Sender<Task>, path: &str) -> Result<Self> {
+    if path.is_empty() {
+        return Err(Error::BackendError("File path cannot be empty".to_string()));
+    }
+    
     let mut storage = FileStorage::new(path).map(Glue::new).map(Storage::File)?;
 
     let root_id = setup(&mut storage).await?;

52-70: Consider validating Git remote and branch parameters.

The function accepts remote and branch as parameters but doesn't validate them. Consider adding basic validation:

 pub async fn git(
     task_tx: Sender<Task>,
     path: &str,
     remote: String,
     branch: String,
 ) -> Result<Self> {
+    if path.is_empty() {
+        return Err(Error::BackendError("Git path cannot be empty".to_string()));
+    }
+    if remote.is_empty() {
+        return Err(Error::BackendError("Git remote cannot be empty".to_string()));
+    }
+    if branch.is_empty() {
+        return Err(Error::BackendError("Git branch cannot be empty".to_string()));
+    }
+    
     let mut storage = GitStorage::open(path, StorageType::File)?;
     storage.set_remote(remote);
     storage.set_branch(branch);

107-110: Consider using a more specific error variant for channel send failures.

The error conversion loses context about what type of operation failed:

 self.task_tx
     .clone()
     .send(task)
-    .map_err(|e| Error::BackendError(e.to_string()))?;
+    .map_err(|e| Error::BackendError(format!("Failed to send Git sync task: {}", e)))?;
core/src/glues.rs (1)

37-47: Consider adding cleanup handling for the task system.

The native implementation spawns a background thread but doesn't provide a way to cleanly shut it down. Consider adding a shutdown mechanism:

 impl Glues {
     pub fn new() -> Self {
         let transition_queue = Arc::new(Mutex::new(VecDeque::new()));
         let (task_tx, task_rx) = channel();
         let task_handle = handle_tasks(task_rx, &transition_queue);
 
         Self {
             db: None,
             state: EntryState.into(),
             task_tx,
             task_handle,
             transition_queue,
         }
     }
+    
+    pub fn shutdown(self) -> Result<()> {
+        // Send a shutdown signal to the task handler
+        drop(self.task_tx); // This will cause recv() to return Err in the task handler
+        self.task_handle.join()
+            .map_err(|_| Error::BackendError("Task handler thread panicked".to_string()))?;
+        Ok(())
+    }
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between dc525d7 and cdc0a8b.

⛔ Files ignored due to path filters (6)
  • Cargo.lock is excluded by !**/*.lock
  • tui/tests/snapshots/entry__csv_alert.snap is excluded by !**/*.snap
  • tui/tests/snapshots/entry__help_closed.snap is excluded by !**/*.snap
  • tui/tests/snapshots/entry__help_open.snap is excluded by !**/*.snap
  • tui/tests/snapshots/entry__local_prompt.snap is excluded by !**/*.snap
  • tui/tests/snapshots/entry__proxy_prompt_open.snap is excluded by !**/*.snap
📒 Files selected for processing (45)
  • .github/workflows/rust.yml (1 hunks)
  • .gitignore (1 hunks)
  • Cargo.toml (0 hunks)
  • README.md (3 hunks)
  • core/Cargo.toml (1 hunks)
  • core/src/backend.rs (3 hunks)
  • core/src/backend/local.rs (1 hunks)
  • core/src/backend/local/core_backend.rs (1 hunks)
  • core/src/backend/local/directory.rs (1 hunks)
  • core/src/backend/local/native.rs (1 hunks)
  • core/src/backend/local/wasm.rs (1 hunks)
  • core/src/backend/proxy/client.rs (1 hunks)
  • core/src/backend/proxy/server.rs (1 hunks)
  • core/src/event.rs (0 hunks)
  • core/src/glues.rs (1 hunks)
  • core/src/lib.rs (2 hunks)
  • core/src/state/entry.rs (4 hunks)
  • core/tests/backend.rs (1 hunks)
  • core/tests/proxy.rs (1 hunks)
  • server/Cargo.toml (1 hunks)
  • server/src/main.rs (2 hunks)
  • tui/Cargo.toml (1 hunks)
  • tui/src/action.rs (8 hunks)
  • tui/src/app.rs (4 hunks)
  • tui/src/config.rs (1 hunks)
  • tui/src/context.rs (2 hunks)
  • tui/src/context/entry.rs (6 hunks)
  • tui/src/context/notebook.rs (3 hunks)
  • tui/src/input.rs (1 hunks)
  • tui/src/lib.rs (1 hunks)
  • tui/src/logger.rs (2 hunks)
  • tui/src/main.rs (3 hunks)
  • tui/src/transitions.rs (1 hunks)
  • tui/src/views/body/entry.rs (1 hunks)
  • tui/src/views/dialog/help.rs (1 hunks)
  • tui/src/web.rs (1 hunks)
  • tui/tests/editor_insert.rs (1 hunks)
  • tui/tests/editor_normal.rs (1 hunks)
  • tui/tests/editor_visual.rs (1 hunks)
  • tui/tests/entry.rs (3 hunks)
  • tui/tests/notebook_tree.rs (1 hunks)
  • tui/tests/notebook_views.rs (1 hunks)
  • tui/tests/tester.rs (4 hunks)
  • tui/web/Trunk.toml (1 hunks)
  • tui/web/index.html (1 hunks)
💤 Files with no reviewable changes (2)
  • core/src/event.rs
  • Cargo.toml
🧰 Additional context used
🧠 Learnings (1)
📚 Learning: 2025-09-19T06:56:17.849Z
Learnt from: panarch
PR: gluesql/glues#213
File: server/src/main.rs:118-125
Timestamp: 2025-09-19T06:56:17.849Z
Learning: The gluesql backends that CoreBackend implementations are built on top of rely on &mut self access patterns and aren't designed for concurrent callers.

Applied to files:

  • core/tests/backend.rs
  • core/src/state/entry.rs
  • core/src/backend/local.rs
🧬 Code graph analysis (14)
tui/src/web.rs (4)
tui/src/app.rs (2)
  • run (41-105)
  • new (33-38)
tui/src/config.rs (2)
  • init (47-66)
  • init (119-138)
tui/src/logger.rs (1)
  • init (14-26)
tui/src/theme.rs (1)
  • set_theme (64-66)
core/src/state/entry.rs (3)
core/src/backend/local/native.rs (2)
  • file (40-50)
  • memory (27-38)
core/src/glues.rs (2)
  • new (36-48)
  • new (78-83)
core/src/backend/local/wasm.rs (1)
  • memory (18-23)
tui/tests/entry.rs (1)
tui/tests/tester.rs (1)
  • key (67-69)
core/src/backend.rs (7)
core/src/backend/local/core_backend.rs (15)
  • root_id (14-16)
  • fetch_directory (18-20)
  • fetch_directories (22-24)
  • add_directory (26-28)
  • remove_directory (30-32)
  • move_directory (34-40)
  • rename_directory (42-44)
  • fetch_notes (46-48)
  • fetch_note_content (50-52)
  • add_note (54-56)
  • remove_note (58-60)
  • rename_note (62-64)
  • update_note_content (66-68)
  • move_note (70-72)
  • log (74-76)
core/src/backend/proxy/client.rs (15)
  • root_id (49-51)
  • fetch_directory (53-62)
  • fetch_directories (64-73)
  • add_directory (75-84)
  • remove_directory (86-95)
  • move_directory (97-113)
  • rename_directory (115-124)
  • fetch_notes (126-132)
  • fetch_note_content (134-140)
  • add_note (142-151)
  • remove_note (153-159)
  • rename_note (161-167)
  • update_note_content (169-178)
  • move_note (180-192)
  • log (194-200)
core/src/backend/local/directory.rs (6)
  • fetch_directory (11-44)
  • fetch_directories (46-77)
  • add_directory (79-99)
  • remove_directory (103-122)
  • move_directory (124-138)
  • rename_directory (140-154)
core/src/state/notebook/consume/directory.rs (1)
  • move_directory (230-257)
core/src/backend/local/note.rs (7)
  • fetch_notes (33-64)
  • fetch_note_content (14-31)
  • add_note (66-82)
  • remove_note (84-92)
  • rename_note (106-116)
  • update_note_content (94-104)
  • move_note (118-128)
core/src/state/notebook/consume/note.rs (1)
  • move_note (200-226)
core/src/backend/local/log.rs (1)
  • log (8-17)
tui/src/context.rs (1)
tui/src/input.rs (1)
  • to_textarea_input (168-173)
server/src/main.rs (2)
core/src/backend/proxy/server.rs (1)
  • new (10-12)
core/src/glues.rs (2)
  • new (36-48)
  • new (78-83)
core/src/backend/local/native.rs (3)
core/src/schema.rs (1)
  • setup (11-105)
core/src/backend/local/wasm.rs (4)
  • sync (25-27)
  • memory (18-23)
  • execute (35-35)
  • execute (43-46)
core/src/glues.rs (4)
  • new (36-48)
  • new (78-83)
  • default (30-32)
  • default (72-74)
tui/src/config.rs (2)
tui/tests/tester.rs (1)
  • new (35-48)
tui/src/logger.rs (1)
  • init (14-26)
core/src/backend/local/wasm.rs (4)
core/src/schema.rs (1)
  • setup (11-105)
core/src/backend/local/native.rs (4)
  • memory (27-38)
  • sync (95-114)
  • execute (122-122)
  • execute (130-140)
core/src/backend.rs (5)
  • root_id (11-11)
  • root_id (38-38)
  • root_id (65-67)
  • root_id (133-135)
  • root_id (201-203)
core/src/backend/local/core_backend.rs (1)
  • root_id (14-16)
tui/src/logger.rs (1)
tui/src/config.rs (2)
  • get_glue (38-45)
  • get_glue (115-117)
tui/src/action.rs (1)
tui/tests/tester.rs (2)
  • ctrl (61-64)
  • key (67-69)
tui/src/context/notebook.rs (1)
tui/src/input.rs (1)
  • to_textarea_input (168-173)
tui/src/main.rs (1)
server/src/main.rs (1)
  • main (61-97)
core/src/glues.rs (5)
core/src/task.rs (1)
  • handle_tasks (21-42)
core/src/backend/proxy/server.rs (1)
  • new (10-12)
core/src/state/notebook.rs (2)
  • new (44-74)
  • consume (300-308)
core/src/state/entry.rs (1)
  • consume (11-65)
core/src/state.rs (1)
  • consume (22-41)
🪛 markdownlint-cli2 (0.17.2)
README.md

53-53: Unordered list style
Expected: asterisk; Actual: dash

(MD004, ul-style)


54-54: Unordered list style
Expected: asterisk; Actual: dash

(MD004, ul-style)

🔇 Additional comments (52)
.gitignore (1)

2-4: Ignore web dist: LGTM

Adding tui/web/dist/ is correct for Trunk output; reorder is harmless.

server/src/main.rs (1)

86-87: Layer ordering is fine

with_state before layer(cors) is OK; the layer applies router‑wide.

core/src/backend/local/directory.rs (1)

101-103: Correct use of async_recursion(?Send) on wasm32

This avoids unnecessary Send bounds on single‑threaded wasm. Nice.

tui/src/views/dialog/help.rs (1)

53-101: Help content looks aligned per-target

Non‑wasm section correctly documents memory/file/git/mongo + proxy; no action needed.

tui/web/Trunk.toml (1)

6-9: Serve section key naming — 'addresses' is correct in current Trunk

Current Trunk docs use addresses (list) — older releases used address (string); no change required.

tui/web/index.html (1)

18-21: Confirm data-target-name="glues" maps to a cdylib crate when --features web is enabled

Verification script returned no matches in the repository; cannot confirm. Action items:

  • Ensure a crate named "glues" (or a lib that produces an artifact named "glues") declares crate-type = ["cdylib"] in its Cargo.toml.
  • Ensure that crate is built when --features web is passed (feature gating or workspace membership).

Location: tui/web/index.html Lines 18-21

      data-target-name="glues"
      data-target-kind="cdylib"
      data-cargo-args="--lib --no-default-features --features web"
server/Cargo.toml (1)

15-16: Remove unused tower = "0.5.2" from server/Cargo.toml; verify dependency tree

File: server/Cargo.toml (lines 15–16). rg found no direct tower:: usage in server/; cargo tree failed in the sandbox (error: "no /proc/self/exe available") so dependency-tree verification must be run locally.

Apply this diff:

- tower = "0.5.2"
- tower-http = { version = "0.5", features = ["cors"] }
+ tower-http = { version = "0.5", features = ["cors"] }

Run locally to confirm no mixed tower majors:
cargo tree -p glues-proxy-server | rg -nP '\btower v'
If you see both tower v0.4 and v0.5 in the graph, remove the direct tower = "0.5.2" or align versions; otherwise apply the diff.

tui/src/web.rs (1)

60-62: LGTM!

The error conversion utility is well-implemented and follows standard patterns for WASM error handling.

core/Cargo.toml (1)

25-41: Platform-specific dependencies look good.

The separation of dependencies by target architecture is well-structured. The WASM target appropriately excludes file-based storage backends and uses default-features = false for reqwest to avoid incompatible features.

tui/src/input.rs (1)

175-203: LGTM! Well-structured input conversion utilities.

The conversion functions provide clean abstractions for converting between different input representations, maintaining consistency across the codebase.

tui/Cargo.toml (1)

14-14: cdylib is required for wasm-bindgen/wasm-pack — keep it.
The "cdylib" crate-type is needed to emit the .wasm artifact that wasm-bindgen/wasm-pack expect; keeping crate-type = ["rlib", "cdylib"] is correct.

core/src/backend/local/wasm.rs (1)

30-36: Confirmed: keep #[async_trait(?Send)] for WASM — no change required

Repo intentionally disables the Send bound for wasm targets (cfg_attr(target_arch = "wasm32", async_trait(?Send)) is used elsewhere such as core/src/backend/local/core_backend.rs and core/src/backend/proxy/client.rs); the impl still requiring T: Send mirrors the native implementation and is not a blocker.

core/tests/proxy.rs (1)

13-13: Appropriate wasm32 target gating for proxy tests.

The conditional compilation attribute #[cfg(not(target_arch = "wasm32"))] correctly excludes this test from wasm32 builds, which is appropriate since proxy backend operations likely require native networking capabilities not available in WebAssembly environments.

tui/tests/notebook_tree.rs (1)

6-6: Import path updated for cross-platform input handling.

The import has been correctly updated from ratatui::crossterm::event::KeyCode to glues::input::KeyCode to align with the new cross-platform input module. This ensures consistent input handling across native and WebAssembly targets.

tui/tests/editor_visual.rs (1)

6-6: Import path updated for cross-platform input handling.

The import has been correctly updated from ratatui::crossterm::event::KeyCode to glues::input::KeyCode to align with the new cross-platform input module. This ensures consistent input handling across native and WebAssembly targets.

tui/tests/editor_normal.rs (1)

6-6: Import path updated for cross-platform input handling.

The import has been correctly updated from ratatui::crossterm::event::KeyCode to glues::input::KeyCode to align with the new cross-platform input module. This ensures consistent input handling across native and WebAssembly targets.

tui/src/lib.rs (2)

6-6: Cross-platform input module added.

The new input module provides a unified abstraction for input handling across native and WebAssembly targets. This is well-architected for supporting multiple platforms.


13-15: WebAssembly-specific web module appropriately gated.

The conditional compilation #[cfg(target_arch = "wasm32")] correctly limits the web module to WebAssembly builds only. This ensures the web frontend code is only compiled for the appropriate target.

core/tests/backend.rs (1)

4-4: Appropriate wasm32 target gating for backend tests.

The conditional compilation attribute #[cfg(not(target_arch = "wasm32"))] correctly excludes this test from wasm32 builds. This is appropriate since backend operations involving channels and native database functionality are not suitable for WebAssembly environments.

tui/tests/editor_insert.rs (1)

6-6: Import path updated for cross-platform input handling.

The import has been correctly updated from ratatui::crossterm::event::KeyCode to glues::input::KeyCode to align with the new cross-platform input module. This ensures consistent input handling across native and WebAssembly targets.

tui/src/views/body/entry.rs (1)

35-35: Simplified uniform coloring for menu items.

The code now applies uniform coloring (THEME.menu) to all menu items, removing the conditional logic that previously applied different colors to CSV/JSON items. This simplification aligns with the removal of CSV/JSON menu options from the entry context.

core/src/backend/proxy/client.rs (1)

46-47: Correct: async_trait gating for wasm vs. native.

The cfg_attr split avoids unnecessary Send bounds on wasm while preserving native behavior. Good alignment with the CoreBackend split.

core/src/lib.rs (1)

19-19: Public re-exports gated consistently.

Re-exporting Task/handle_tasks only for non‑wasm keeps the public API clean across targets.

tui/src/context.rs (1)

5-11: Good: centralized input abstraction.

Using crate::input::{...} decouples TUI from crossterm and aligns with wasm builds.

core/src/backend/local/core_backend.rs (1)

11-12: Correct: async_trait(?Send) on wasm, default on native.

Matches the trait’s threading model and the prior learning that CoreBackend impls are not designed for concurrent callers.

core/src/state/entry.rs (3)

17-17: Nice: platform-aware memory backend helper.

Centralizing Db::memory selection by target reduces cfg noise at call sites.


94-102: WASM vs native Db::memory split is clean.

Signatures line up; wasm path doesn’t depend on task_tx, native path does.


26-53: Non‑wasm storage gates mostly correct — EntryEvent missing OpenMongo

core/src/event.rs defines EntryEvent::{OpenMemory, OpenFile(String), OpenGit{...}} (no OpenMongo); core/src/state/entry.rs has a #[cfg(not(target_arch = "wasm32"))] match arm for Entry(OpenMongo{...}). Add a cfg‑gated EntryEvent::OpenMongo in core/src/event.rs or gate/remove the Entry::OpenMongo arm so event and state variants stay consistent.

tui/src/transitions.rs (1)

6-6: No action required — log! is #[macro_export].
#[macro_export] is declared on the log! macro in tui/src/logger.rs, so the macro is globally exported and no use crate::logger::*; is necessary.

tui/tests/notebook_views.rs (1)

6-8: Approve — Tester already uses glues::input::KeyCode.
tui/tests/tester.rs imports and uses KeyCode from glues::input (Tester::key and helpers), so no change required.

tui/tests/entry.rs (1)

55-67: Good wasm gating for native-only test.

open_local_prompt is correctly hidden on wasm32.

tui/tests/tester.rs (1)

16-22: Nice: unified key_press helper.

Keeps tests concise and aligned with the new input API.

tui/src/app.rs (1)

74-76: Good: centralizing crossterm → Input conversion.

Keeps platform abstraction in one place.

core/src/backend.rs (3)

8-33: WASM trait split looks correct

Non-Send futures via async_trait(?Send) are appropriate for wasm32 and match the rest of the codebase’s &mut self model.


35-60: Native trait bound on Send is appropriate

Requiring Send on non-wasm aligns with server/task usage and BackendBox aliasing.


266-270: BackendBox aliases look good

This unifies types across targets and simplifies callers.

tui/src/logger.rs (4)

66-81: panic formatting change is fine

Switch to panic!("{e}") is okay; retains Display.


8-12: Fix import: use crate::config::get_glue (not crate::config::platform::get_glue)
get_glue is defined in tui/src/config.rs (lines 38 and 115); update the use to crate::config::get_glue or add a config::platform module.

Likely an incorrect or invalid review comment.


3-6: Confirm ratzilla re-export of web_sys::console; keep wasm_bindgen::JsValue import.
ratzilla::web_sys::console is referenced in tui/src/web.rs:6 and tui/src/logger.rs:4 (so ratzilla provides console); there is no ratzilla::JsValue in the repo, so importing JsValue from wasm_bindgen is correct.


45-49: Macro awaits require async context — ensure call sites are async or add a sync variant

tui/src/logger.rs (lines 45–49) defines log! which expands to .await; this forces every call site to be inside an async fn/async block. Verify all call sites are async, or apply one of:

  • remove the .await so the macro returns the Future (callers await), or
  • add a sync variant (e.g., log_now!) for non-async contexts.
tui/src/main.rs (1)

53-54: WASM no-op main is correct

Keeps wasm build happy without pulling in tokio/clap.

tui/src/context/entry.rs (1)

33-37: Menu gating and key mappings look consistent

Proxy at [5] for native and [2] for wasm matches MENU_ITEMS.

Also applies to: 115-124

core/src/backend/local.rs (1)

1-10: Arch split via re-exports — looks good; files present, verify target builds.
core/src/backend/local/native.rs and core/src/backend/local/wasm.rs exist; re-exports match the cfgs. Run CI or locally: cargo check (native) and cargo check --target wasm32-unknown-unknown (wasm).

tui/src/action.rs (2)

8-8: LGTM! Clean migration to the unified input module.

The import change from separate ratatui imports to the consolidated crate::input module aligns well with the cross-platform input handling approach.


376-376: LGTM! Proper use of the new field-based modifier check.

The change from comparing against KeyModifiers::CONTROL to using key.modifiers.ctrl is correct and aligns with the new input handling approach.

tui/src/context/notebook.rs (4)

6-6: LGTM! Clean integration with the unified input module.

The import properly leverages the new cross-platform input abstraction, including the to_textarea_input helper function for mapping inputs to textarea commands.


20-21: Good platform-specific handling of clipboard functionality.

The conditional compilation properly gates the clipboard dependency for non-wasm32 targets, acknowledging that clipboard operations aren't available in web environments.


451-454: LGTM! Correct modifier check pattern.

The change to use modifiers.ctrl directly is consistent with the new input handling approach.


461-463: Good use of the input mapping helper function.

The integration with to_textarea_input properly filters inputs before forwarding them to the editor, ensuring only valid textarea inputs are processed.

Also applies to: 467-469

core/src/backend/local/native.rs (1)

117-141: LGTM! Clean async trait implementation with proper error handling.

The Execute trait and its blanket implementation provide a clean abstraction over the different storage backends. The pattern matching on storage variants and consistent error handling is well done.

core/src/glues.rs (2)

1-96: LGTM! Well-structured platform-specific module organization.

The separation of native and wasm implementations with a unified public interface through conditional compilation is clean and maintainable. The use of type aliases (Inner) and re-exports provides a seamless API regardless of the target platform.


21-22: Good abstraction with BackendBox for unified backend handling.

The change from Box<dyn CoreBackend + Send> to BackendBox simplifies the type signatures and provides better abstraction across both native and wasm targets.

Also applies to: 67-68

Comment thread core/src/lib.rs Resolved
Comment thread server/src/main.rs Outdated
Comment on lines +78 to +81
let cors = CorsLayer::new()
.allow_origin(Any)
.allow_methods(Any)
.allow_headers(Any);

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

❓ Verification inconclusive

CORS is fully open; restrict via env and cache preflights

allow_origin(Any)/methods(Any)/headers(Any) is too permissive for production. Gate via CORS_ALLOWED_ORIGIN and set a sane max_age.

-    let cors = CorsLayer::new()
-        .allow_origin(Any)
-        .allow_methods(Any)
-        .allow_headers(Any);
+    use axum::http::HeaderValue;
+    let cors = if let Ok(origin) = std::env::var("CORS_ALLOWED_ORIGIN") {
+        if let Ok(val) = HeaderValue::from_str(&origin) {
+            CorsLayer::new()
+                .allow_origin(val)
+                .allow_methods(Any)
+                .allow_headers(Any)
+                .max_age(Duration::from_secs(300))
+        } else {
+            CorsLayer::new()
+                .allow_origin(Any)
+                .allow_methods(Any)
+                .allow_headers(Any)
+                .max_age(Duration::from_secs(300))
+        }
+    } else {
+        // Dev default; lock down via env in CI/prod.
+        CorsLayer::new()
+            .allow_origin(Any)
+            .allow_methods(Any)
+            .allow_headers(Any)
+            .max_age(Duration::from_secs(300))
+    };

If the web client uses credentials (cookies/authorization headers), add:

// .allow_credentials(true)

and ensure allowed origin is not wildcard.


Restrict CORS in production (server/src/main.rs:78–81)

allow_origin(Any)/allow_methods(Any)/allow_headers(Any) is too permissive — require a CORS_ALLOWED_ORIGIN whitelist (parse to HeaderValue or use AllowedOrigins), set CorsLayer::max_age (e.g., 300–3600s) to cache preflights, and only enable .allow_credentials(true) when using a specific origin (not Any). (docs.rs)

🤖 Prompt for AI Agents
In server/src/main.rs around lines 78–81 the CORS layer is currently fully
permissive; replace the Any origin/methods/headers with a whitelist sourced from
a CORS_ALLOWED_ORIGIN env var (parse into a HeaderValue or use
tower_http::cors::AllowOrigin/AllowedOrigins) and validate/fallback to a safe
default, restrict allowed methods and headers to the app's required set instead
of Any, set CorsLayer::max_age to e.g. 300–3600 seconds to cache preflight
responses, and only call .allow_credentials(true) when the configured origin is
a specific origin (not Any); ensure errors parsing the env var are handled and
logged and that the production build uses the whitelist.

Comment thread tui/src/context/entry.rs
Comment on lines 125 to 126
KeyCode::Char('a') => TuiAction::Help.into(),

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Keybinding bug: Help is on 'h' but code listens to 'a'

Displayed as “[h] Help” but handler uses KeyCode::Char('a'). Fix to 'h'.

-            KeyCode::Char('a') => TuiAction::Help.into(),
+            KeyCode::Char('h') => TuiAction::Help.into(),
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
KeyCode::Char('a') => TuiAction::Help.into(),
KeyCode::Char('h') => TuiAction::Help.into(),
🤖 Prompt for AI Agents
In tui/src/context/entry.rs around lines 125-126, the keybinding for Help is
incorrect: the code matches KeyCode::Char('a') while the UI displays “[h] Help”.
Change the pattern to KeyCode::Char('h') (and optionally also handle
KeyCode::Char('H') if you want case-insensitive input) so the handler matches
the displayed keybinding.

Comment thread tui/src/logger.rs Resolved
Comment thread tui/src/logger.rs Resolved
Comment on lines +32 to +50
let message = {
#[cfg(target_arch = "wasm32")]
{
vec![
Line::from("Glues keeps storage simple:"),
Line::raw(""),
Line::from("Instant".fg(THEME.accent_text).bg(THEME.accent)),
Line::raw("Volatile in-memory storage that resets when Glues exits."),
Line::raw("Great for quick scratch notes or testing."),
Line::raw(""),
Line::from("Proxy".fg(THEME.accent_text).bg(THEME.accent)),
Line::raw("Bridge to a Glues proxy server for persistence."),
Line::raw(
"Start it with `cargo run -p glues-proxy-server` (use `--listen` to change the address).",
),
Line::raw("Both the web and TUI clients can connect to the same proxy."),
Line::raw(""),
]
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Fix proxy start command (missing required storage subcommand)

server/src/main.rs requires a StorageCommand; the wasm help text omits it.

-                Line::raw(
-                    "Start it with `cargo run -p glues-proxy-server` (use `--listen` to change the address).",
-                ),
+                Line::raw(
+                    "Start it with `cargo run -p glues-proxy-server -- memory` (use `--listen` to change the address).",
+                ),
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
let message = {
#[cfg(target_arch = "wasm32")]
{
vec![
Line::from("Glues keeps storage simple:"),
Line::raw(""),
Line::from("Instant".fg(THEME.accent_text).bg(THEME.accent)),
Line::raw("Volatile in-memory storage that resets when Glues exits."),
Line::raw("Great for quick scratch notes or testing."),
Line::raw(""),
Line::from("Proxy".fg(THEME.accent_text).bg(THEME.accent)),
Line::raw("Bridge to a Glues proxy server for persistence."),
Line::raw(
"Start it with `cargo run -p glues-proxy-server` (use `--listen` to change the address).",
),
Line::raw("Both the web and TUI clients can connect to the same proxy."),
Line::raw(""),
]
}
let message = {
#[cfg(target_arch = "wasm32")]
{
vec![
Line::from("Glues keeps storage simple:"),
Line::raw(""),
Line::from("Instant".fg(THEME.accent_text).bg(THEME.accent)),
Line::raw("Volatile in-memory storage that resets when Glues exits."),
Line::raw("Great for quick scratch notes or testing."),
Line::raw(""),
Line::from("Proxy".fg(THEME.accent_text).bg(THEME.accent)),
Line::raw("Bridge to a Glues proxy server for persistence."),
Line::raw(
"Start it with `cargo run -p glues-proxy-server -- memory` (use `--listen` to change the address).",
),
Line::raw("Both the web and TUI clients can connect to the same proxy."),
Line::raw(""),
]
}
🤖 Prompt for AI Agents
In tui/src/views/dialog/help.rs around lines 32 to 50, the wasm help text shows
an incorrect start command for the proxy server missing the required storage
subcommand; update the string to include the storage subcommand (e.g., change
the instruction to "Start it with `cargo run -p glues-proxy-server -- storage
proxy` (use `--listen` to change the address).") so the example matches
server/src/main.rs' required command structure.

Comment thread tui/web/Trunk.toml
Comment on lines +1 to +4
[build]
release = true
manifest = "../Cargo.toml"
dist = "dist"

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

🧩 Analysis chain

Double-check Trunk [build] keys: ‘manifest’ name may be off

Trunk’s config has evolved; some docs use workspace_manifest_path (or cargo-manifest attr in HTML). Using an unknown key is silently ignored. Ensure the key matches your Trunk version.


🌐 Web query:

What are the valid keys under the [build] section of Trunk.toml as of the latest Trunk release? Is 'workspace_manifest_path' supported, and is 'manifest' a valid key?

💡 Result:

Short answer

  • Valid [build] keys include: target, html_output, release, dist, public_url, filehash, inject_scripts, offline, frozen, locked, minify, no_sri (as shown in the official Trunk configuration docs). [1]
  • Neither workspace_manifest_path nor manifest appear as supported keys in the documented Trunk.toml build schema — they are not listed in the official config/examples. Use the documented keys above (or generate the current JSON schema via trunk config generate-schema to confirm your installed Trunk version). [1][2]

Sources

  • Trunk configuration / Trunk.toml documentation. [1]
  • Example Trunk.toml in the Trunk repo (config/schema reference). [2]

Trunk [build] key 'manifest' is not supported — remove or replace it

Trunk.toml’s [build] keys do not include "manifest" or "workspace_manifest_path" and unknown keys are silently ignored; remove/replace this key or use Trunk’s cargo-manifest HTML attribute. Verify against your Trunk version with trunk config generate-schema.

File: tui/web/Trunk.toml (lines 1–4)

🤖 Prompt for AI Agents
In tui/web/Trunk.toml around lines 1 to 4, the [build] key "manifest" is
unsupported by Trunk and should be removed or replaced; delete the manifest =
"../Cargo.toml" line from this file and, if you need to point Trunk at a
non-default Cargo manifest, move that setting into your HTML via Trunk's
cargo-manifest attribute (or run `trunk config generate-schema` to confirm
supported keys and use the correct Trunk configuration key). Ensure the
remaining [build] keys are valid (e.g., release and dist) and validate the file
against your Trunk version.

# Conflicts:
#	Cargo.toml
#	README.md
#	core/src/backend/local.rs
#	core/src/state/entry.rs
#	tui/Cargo.toml
#	tui/src/action.rs
#	tui/src/context/entry.rs
#	tui/src/views/dialog/help.rs
#	tui/tests/entry.rs
@gluesql-coverage-bot

gluesql-coverage-bot Bot commented Sep 19, 2025 •

Copy link
Copy Markdown

Glues Coverage Report

  • Commit: 94b26044aaa5c20fb91fd4695c323c16cc718cef
  • Timestamp: 2025-09-19T151715Z
  • Report: View report

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🧹 Nitpick comments (4)
README.md (4)

54-54: Avoid hardcoding menu index; fix list marker to satisfy markdownlint (MD004).

Hardcoded “[5]” is brittle as menu ordering can change across builds. Also, switch “-” to “*” to match the repo’s unordered list style.

-  - In the TUI entry menu choose `Proxy` (option `[5]` on the native build), enter the proxy URL (e.g. `http://127.0.0.1:4000`), and Glues will talk to the remote backend just like it does locally.
+  * In the TUI entry menu choose `Proxy`, enter the proxy URL (e.g. `http://127.0.0.1:4000`), and Glues will talk to the remote backend just like it does locally.

56-56: Clarify browser persistence scope and available backends.

Make it explicit that Instant is ephemeral in the browser and that Local/Git/Mongo aren’t available on web.

- > **Web build:** The browser version of Glues persists configuration through GlueSQL WebStorage (LocalStorage) and currently exposes the **Instant** and **Proxy** backends. Point the Proxy option at a running Glues proxy server to keep data outside the browser sandbox.
+ > **Web build:** Configuration is stored in WebStorage (LocalStorage). **Instant** notes are in-memory and ephemeral; use the **Proxy** backend to persist data to a running Glues proxy server. Local/Git/Mongo are not available in the browser build.

74-74: Be explicit about the output path of the static bundle.

Small clarity boost by showing the repo-relative path.

- To produce a static bundle instead, run `trunk build --release` from the same directory; the optimized artifacts will be emitted under `dist/`.
+ To produce a static bundle instead, run `trunk build --release` from the same directory; the optimized artifacts will be emitted under `tui/web/dist/`.

29-29: Typo: “user” → “use”.

Minor copy fix.

-paru -S glues # user your favorite AUR helper
+paru -S glues # use your favorite AUR helper
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between cdc0a8b and ed1ee3e.

📒 Files selected for processing (1)
  • README.md (1 hunks)
🧰 Additional context used
🪛 markdownlint-cli2 (0.17.2)
README.md

54-54: Unordered list style
Expected: asterisk; Actual: dash

(MD004, ul-style)

⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: coverage

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🧹 Nitpick comments (6)
README.md (6)

54-54: Fix markdownlint MD004: use asterisks for list bullets.

Line 54 uses "-" while the rest of the doc prefers "". Switch to "" to satisfy MD004 and keep style consistent. Also consider updating lines 52–53 for consistency.

-  - In the TUI entry menu choose `Proxy` (option `[5]` on the native build), enter the proxy URL (e.g. `http://127.0.0.1:4000`), and Glues will talk to the remote backend just like it does locally.
+  * In the TUI entry menu choose `Proxy` (option `[5]` on the native build), enter the proxy URL (e.g. `http://127.0.0.1:4000`), and Glues will talk to the remote backend just like it does locally.

56-57: Add a brief security note for browser storage and remote proxy.

Make risks explicit: LocalStorage isn’t suitable for secrets; prefer Proxy for persistence and HTTPS when not on localhost.

- > **Web build:** The browser version of Glues persists configuration through GlueSQL WebStorage (LocalStorage) and currently exposes the **Instant** and **Proxy** backends. Point the Proxy option at a running Glues proxy server to keep data outside the browser sandbox.
+ > **Web build:** The browser version of Glues persists configuration through GlueSQL WebStorage (LocalStorage) and currently exposes the **Instant** and **Proxy** backends. Point the Proxy option at a running Glues proxy server to keep data outside the browser sandbox. Avoid storing sensitive data in the browser; use Proxy for persistence, and prefer HTTPS when the proxy is not localhost.

60-66: Consider pinning/documenting Trunk version for reproducible builds.

Add a known-good Trunk version (or note CI’s version) to avoid local/CI mismatches.


69-71: Tiny UX hint: tell users how to change the serve port.

Useful when 8080 is busy.

-   trunk serve --release
+   trunk serve --release  # use --port <N> if 8080 is occupied

72-72: Mention CORS when proxying to another origin.

Users will otherwise hit blocked requests.

-3. Open [http://localhost:8080](http://localhost:8080) in your browser. Use **Instant** for ephemeral notes, or connect to a running proxy server via the **Proxy** option for persistence.
+3. Open [http://localhost:8080](http://localhost:8080) in your browser. Use **Instant** for ephemeral notes, or connect to a running proxy server via the **Proxy** option for persistence. If the proxy is on another origin, ensure CORS is allowed on the server.

74-74: Clarify exact output path.

State “tui/web/dist/” to match the project layout.

-To produce a static bundle instead, run `trunk build --release` from the same directory; the optimized artifacts will be emitted under `dist/`.
+To produce a static bundle instead, run `trunk build --release` from the same directory; the optimized artifacts will be emitted under `tui/web/dist/`.
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between cdc0a8b and c51572d.

📒 Files selected for processing (2)
  • .github/workflows/rust.yml (1 hunks)
  • README.md (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • .github/workflows/rust.yml
🧰 Additional context used
🪛 markdownlint-cli2 (0.17.2)
README.md

54-54: Unordered list style
Expected: asterisk; Actual: dash

(MD004, ul-style)

⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: Wasm Build
  • GitHub Check: coverage

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

♻️ Duplicate comments (1)
server/Cargo.toml (1)

25-26: Verify tower-http CORS security configuration.

The addition of tower-http with CORS features is necessary for the web client integration, but based on the existing review comment, the CORS configuration in server/src/lib.rs appears to use overly permissive settings that could pose security risks in production.

Based on the past review comments and security best practices, the current CORS configuration using allow_origin(Any), allow_methods(Any), and allow_headers(Any) is too permissive and should be restricted via environment variables, with explicit origin whitelisting, method restrictions, and max_age configuration for preflight caching.

The existing review comment provides a comprehensive solution - please implement the suggested CORS restrictions before production deployment.

🧹 Nitpick comments (8)
.github/workflows/rust.yml (3)

59-60: Remove redundant wasm32 target addition

Line 60 duplicates the target installation that's already performed by dtolnay/rust-toolchain@stable on lines 56-58.

Apply this diff to remove the redundant step:

-      - name: Ensure wasm32 target
-        run: rustup target add wasm32-unknown-unknown

50-54: Consider making wasm_build independent of rust_test

The wasm_build job depends on rust_test, which could unnecessarily delay feedback if tests fail. Since wasm compilation checks different aspects (target compatibility) than functional tests, these could run in parallel.

Consider removing the dependency or making it conditional:

   wasm_build:
     name: Wasm Build
     runs-on: ubuntu-latest
-    needs: [rust_test]

65-66: Consider using cargo-binstall for faster trunk installation

Installing trunk from source with --force can be slow. Consider using cargo-binstall first to download a pre-built binary, falling back to source only if necessary.

       - name: Install trunk
-        run: cargo install trunk --locked --force
+        run: |
+          cargo install cargo-binstall
+          cargo binstall trunk -y --locked || cargo install trunk --locked
README.md (1)

53-55: Fix inconsistent unordered list style

The markdown uses dashes instead of asterisks for list items, which is inconsistent with the rest of the document.

Apply this diff to maintain consistency:

-  - Run the bundled proxy server with `cargo run -p glues-server -- memory` (replace `memory` with `file`, `git`, or `mongo` as needed). The server listens on `127.0.0.1:4000` by default; use `--listen` to change the address.
-  - In the TUI entry menu choose `Proxy` (option `[5]` on the native build), enter the proxy URL (e.g. `http://127.0.0.1:4000`), and Glues will talk to the remote backend just like it does locally.
-  - After installing via `cargo install glues`, start the proxy with `glues server memory` (or `file`, `git`, `mongo`) to use the same executable for both client and server flows.
+  * Run the bundled proxy server with `cargo run -p glues-server -- memory` (replace `memory` with `file`, `git`, or `mongo` as needed). The server listens on `127.0.0.1:4000` by default; use `--listen` to change the address.
+  * In the TUI entry menu choose `Proxy` (option `[5]` on the native build), enter the proxy URL (e.g. `http://127.0.0.1:4000`), and Glues will talk to the remote backend just like it does locally.
+  * After installing via `cargo install glues`, start the proxy with `glues server memory` (or `file`, `git`, `mongo`) to use the same executable for both client and server flows.
server/src/lib.rs (3)

110-128: Consider extracting backend creation to a factory pattern

The build_backend function mixes async I/O operations with factory logic. Consider extracting this into a proper factory pattern for better testability and separation of concerns.

Additionally, ensure all backends handle connection failures gracefully. The MongoDB backend might benefit from connection retry logic.


85-88: CORS configuration may be too permissive for production

Using Any for all CORS settings allows any origin to access the server. While this may be intentional for development, consider making this configurable for production deployments.

Would you like me to implement configurable CORS settings based on environment variables or CLI arguments?


143-153: Avoid silently clearing the transition queue — process or bound it.

core/src/task.rs pushes transitions; tui/src/app.rs consumes them by popping (tui/src/app.rs:59–61). server/src/lib.rs currently clears the queue every 500ms in spawn_transition_drain (server/src/lib.rs:143–153), which silently drops transitions in server/headless mode instead of processing them. Replace clear() with draining+processing/forwarding, or use a bounded queue/channel to prevent unbounded growth and lost events.

tui/Cargo.toml (1)

27-30: Consider documenting the feature flags

The cli and web features are defined but not documented. Consider adding doc comments to explain their purpose and when to use each.

 [features]
 default = ["cli"]
+## Enables CLI-specific functionality for terminal-based usage
 cli = []
+## Enables web-specific functionality for browser-based WASM deployment  
 web = []
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between c51572d and 94b2604.

⛔ Files ignored due to path filters (2)
  • Cargo.lock is excluded by !**/*.lock
  • tui/tests/snapshots/entry__help_open.snap is excluded by !**/*.snap
📒 Files selected for processing (21)
  • .github/workflows/rust.yml (1 hunks)
  • Cargo.toml (1 hunks)
  • README.md (1 hunks)
  • bin/glues/Cargo.toml (1 hunks)
  • bin/glues/src/main.rs (1 hunks)
  • server/Cargo.toml (1 hunks)
  • server/src/lib.rs (1 hunks)
  • server/src/main.rs (1 hunks)
  • tui/Cargo.toml (1 hunks)
  • tui/src/cli.rs (1 hunks)
  • tui/src/lib.rs (1 hunks)
  • tui/src/main.rs (1 hunks)
  • tui/src/views/dialog/help.rs (1 hunks)
  • tui/tests/editor_insert.rs (1 hunks)
  • tui/tests/editor_normal.rs (1 hunks)
  • tui/tests/editor_visual.rs (1 hunks)
  • tui/tests/entry.rs (3 hunks)
  • tui/tests/notebook_tree.rs (1 hunks)
  • tui/tests/notebook_views.rs (1 hunks)
  • tui/tests/tester.rs (4 hunks)
  • tui/web/index.html (1 hunks)
✅ Files skipped from review due to trivial changes (1)
  • tui/tests/editor_normal.rs
🚧 Files skipped from review as they are similar to previous changes (8)
  • tui/src/lib.rs
  • tui/tests/editor_insert.rs
  • tui/tests/notebook_views.rs
  • tui/src/views/dialog/help.rs
  • tui/tests/entry.rs
  • tui/tests/tester.rs
  • tui/web/index.html
  • Cargo.toml
🧰 Additional context used
🧬 Code graph analysis (5)
bin/glues/src/main.rs (4)
server/src/main.rs (1)
  • main (4-7)
tui/src/main.rs (2)
  • main (6-8)
  • main (11-11)
server/src/lib.rs (1)
  • run (70-104)
tui/src/cli.rs (1)
  • run (44-62)
tui/src/cli.rs (3)
server/src/lib.rs (3)
  • parse_args (66-68)
  • run (70-104)
  • run_cli (106-108)
tui/src/theme.rs (1)
  • set_theme (64-66)
tui/tests/tester.rs (1)
  • new (35-48)
server/src/lib.rs (2)
core/src/task.rs (1)
  • handle_tasks (21-42)
core/src/backend/local/native.rs (3)
  • file (40-50)
  • git (52-70)
  • mongo (72-85)
server/src/main.rs (1)
server/src/lib.rs (2)
  • parse_args (66-68)
  • run (70-104)
tui/src/main.rs (2)
server/src/lib.rs (1)
  • run_cli (106-108)
tui/src/cli.rs (1)
  • run_cli (64-66)
🪛 markdownlint-cli2 (0.17.2)
README.md

53-53: Unordered list style
Expected: asterisk; Actual: dash

(MD004, ul-style)


54-54: Unordered list style
Expected: asterisk; Actual: dash

(MD004, ul-style)


55-55: Unordered list style
Expected: asterisk; Actual: dash

(MD004, ul-style)

⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: Wasm Build
🔇 Additional comments (18)
tui/tests/editor_visual.rs (1)

6-6: Unified KeyCode import — LGTM; double‑check variant naming

Switch to glues_tui::input::KeyCode is consistent with the new input API. Please confirm KeyCode::Esc exists (not Escape) to match the calls below.

You can reuse the verification script from the other comment; it will also cover this file.

tui/tests/notebook_tree.rs (1)

6-6: Approve KeyCode import migration — verified

No legacy ratatui/crossterm KeyCode imports remain; KeyCode variants (Char, Esc, Enter, Backspace, etc.) are defined and mapped in tui/src/input.rs; [lib] name is "glues_tui" in tui/Cargo.toml.

README.md (1)

59-75: Excellent documentation for the web build feature

The Web Build section provides clear prerequisites, step-by-step instructions, and helpful context about the browser-based version's capabilities and limitations. The documentation effectively guides users through both development (trunk serve) and production (trunk build) workflows.

server/src/lib.rs (1)

1-32: Well-structured imports and module organization

The imports are properly organized with clear separation between external and internal dependencies. The use of type aliases for AsyncMutex helps disambiguate between sync and async mutex types.

tui/Cargo.toml (2)

14-15: Good choice of crate types for dual-target support

Including both rlib and cdylib crate types enables the library to work as a regular Rust dependency and as a WASM module, which aligns well with the dual CLI/web architecture.


40-63: Well-structured target-specific dependencies

The separation of dependencies by target architecture is clean and appropriate. The native target gets file system and database backends while WASM gets web storage and browser-specific utilities.

bin/glues/src/main.rs (2)

8-28: Clean and intuitive CLI structure

The CLI design with optional subcommands is well-structured, allowing glues to run the TUI by default while glues server runs the proxy server. This provides a good user experience.


30-38: Approve — error propagation and color_eyre initialization verified

main() propagates errors and both subcommands call color_eyre::install() (server/src/lib.rs:71, tui/src/cli.rs:56).

server/src/main.rs (1)

1-7: Clean refactoring to thin main entry point.

The refactoring successfully extracts server startup logic to glues_server library, creating a clean separation between the binary entry point and core server functionality. This aligns well with the PR's goal of creating a unified CLI and server architecture.

server/Cargo.toml (2)

2-2: Package name change looks appropriate.

The renaming from glues-proxy-server to glues-server is more concise and better reflects the server's broader functionality beyond just proxying.


11-17: Well-structured library and binary targets.

The dual lib/bin configuration is correctly structured with appropriate naming conventions (glues_server library, glues-server binary) and proper path specification.

bin/glues/Cargo.toml (1)

1-19: Well-organized unified CLI manifest.

The new CLI entry point effectively consolidates access to both TUI and server functionality. The dependency structure is appropriate, using local path dependencies with proper feature gating (glues-tui with default-features = false and features = ["cli"]).

tui/src/main.rs (2)

1-8: Proper platform-specific conditional compilation.

The #[cfg(not(target_arch = "wasm32"))] guards appropriately isolate CLI functionality from WASM builds, delegating to the centralized cli::run_cli() function.


10-11: WASM compatibility handled correctly.

The no-op main() for WASM targets satisfies the entry point requirement while avoiding unsupported functionality.

tui/src/cli.rs (4)

1-7: Proper platform gating and imports.

The file-level #[cfg(not(target_arch = "wasm32"))] guard and imports are correctly structured for non-WASM builds only.


9-31: Well-designed CLI argument structure.

The ThemeArg enum covers comprehensive theme options, and the TuiArgs struct properly integrates with Clap's derive macros. The Default implementation is consistent with the Clap default.


44-62: Comprehensive theme initialization and terminal setup.

The run function properly maps theme arguments to constants, initializes necessary subsystems (config, logger, color_eyre), and handles Ratatui terminal lifecycle with proper cleanup via ratatui::restore().


64-66: Consistent API pattern with server module.

The run_cli() convenience function matches the pattern used in server/src/lib.rs, providing a unified interface for CLI execution across modules.

@panarch panarch changed the title feat: add web client and wasm CI Add Ratzilla integration to enable Glues in web browsers Sep 20, 2025
@panarch
panarch merged commit 61ad028 into main Sep 20, 2025
1 check passed
@panarch
panarch deleted the web-ratzilla-integration branch September 20, 2025 02:42
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.

1 participant