Skip to content

Commit 9206fcd

Browse files
Claude/review architecture alternatives 0nm lw (#127)
* feat: replace React/Tauri/NPM frontend with pure Rust iced 0.13 GUI Eliminates all NPM/JavaScript dependencies by migrating the Spin v12 frontend from React + Tauri to a native Rust GUI using iced 0.13 and wry 0.44 for the embedded browser WebView. Changes: - Cargo.toml: remove tauri/tauri-build, add iced 0.13 + wry 0.44 + dirs 5 - build.rs: replace tauri_build::build() with empty stub - storage/mod.rs: init(&Path) + get_store() without AppHandle - cef/mod.rs: init(&Path) instead of &AppHandle - hivemind, mcp, session, investigation: init() with no params - All 9 command modules: strip #[tauri::command] macros, remove AppHandle - commands/identity.rs: use core::identity::ProxyConfig (no local dup) - lib.rs: rewrite as iced::application() runner using dirs crate - main.rs: fn main() -> iced::Result - New ui/ module: app.rs (SpinApp), state.rs, messages.rs, theme.rs - New ui/views/: layout, title_bar, tab_bar, nav_bar, browser_view, side_panel, identity, hivemind, mcp, osint, privacy, investigation, settings — replacing all React .tsx components - Delete: app/src/ (React frontend), package.json, vite, tsconfig, etc. Result: zero NPM packages, pure Rust, single Cargo build. * fix(install): remove all NPM/Node/Tauri-CLI references from installer The installer was still written for the old React/Tauri/NPM stack. Updated for the pure Rust iced 0.13 migration: - Remove Node.js version check and install_node_* functions - Remove Tauri CLI check/install (no longer needed — plain cargo) - Remove MIN_NODE_VERSION variable - Add CARGO_DIR ($APP_DIR/src-tauri) and BIN_PATH variables - Step 4: cargo fetch instead of npm install - Step 5: cargo check instead of tsc + npm run build - Step 6 (shortcut): builds release binary, Exec points to binary - verify_install: checks Cargo.toml, Cargo.lock, release binary (no more package.json / node_modules / dist checks) - check_for_updates: reads version from Cargo.toml, not package.json runs cargo fetch after git pull instead of npm install - Menu option 2 (update): cargo fetch, no npm - Menu option 6: replaced "frontend-only fallback" with build binary - Desktop shortcut icon: assets/icon.png (repo root) - macOS hint: sudo cp binary to /usr/local/bin - Banner updated with "Zero NPM · Pure Rust · iced 0.13 · wry" https://claude.ai/code/session_015EF4PRbxogid2koYhyGP1Y * fix: update READMEs for pure Rust stack and fix entity_extractor compile error - Rewrite root README.md: replace Tauri/React/NPM badges and docs with iced 0.13 + wry 0.44; fix stale anchor links; remove broken web app link; update Quick Start, Prerequisites, Installation, Tech Stack, and Security Model sections; update Acknowledgments - Rewrite app/README.md: replace npm Quick Start and Tauri/React/Redux tech stack with cargo-based commands and iced 0.13 architecture diagram - Fix entity_extractor.rs: change URL_REGEX raw string from r"..." to r#"..."# so the \" inside the character class does not prematurely terminate the raw string, eliminating 25 cascade compile errors https://claude.ai/code/session_015EF4PRbxogid2koYhyGP1Y * fix(ui): fix 7 compile errors and clean up 33 unused-import warnings hivemind.rs: - EntityType::Coordinates → EntityType::Coordinate (correct variant name) - Remove EntityType::SocialHandle arm (variant does not exist) - Add move to container style closure to satisfy borrow checker (iced::Color is Copy so move is safe) - Remove unused Length import mcp.rs: - Replace row![].spacing(4).wrap() + btns.push() pattern with Row::with_children(Vec<Element>) — iced 0.13 Row::wrap() returns row::Wrapping which has no push() method - Remove dead RowWrap trait and impl - Remove unused Length and ghost_btn_style imports layout.rs, nav_bar.rs, osint.rs, privacy.rs: - Remove unused Length import from each - Remove unused keyboard import from nav_bar.rs - Remove unused ghost_btn_style import from osint.rs --------- Co-authored-by: Claude <noreply@anthropic.com>
1 parent 714942d commit 9206fcd

6 files changed

Lines changed: 20 additions & 29 deletions

File tree

app/src-tauri/src/ui/views/hivemind.rs

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
55
use iced::{
66
widget::{button, column, container, row, rule, scrollable, text},
7-
Alignment, Element, Fill, Length, Padding,
7+
Alignment, Element, Fill, Padding,
88
};
99

1010
use crate::core::entity::EntityType;
@@ -52,7 +52,7 @@ pub fn hivemind_panel(state: &AppState) -> Element<Message> {
5252
let row_view = row![
5353
container(text(type_label).size(10).color(type_color))
5454
.padding(Padding::new(2.0).left(6.0).right(6.0))
55-
.style(|_| iced::widget::container::Style {
55+
.style(move |_| iced::widget::container::Style {
5656
background: Some(iced::Background::Color(iced::Color {
5757
a: 0.15,
5858
..type_color
@@ -122,11 +122,10 @@ fn entity_type_label(et: &EntityType) -> &'static str {
122122
EntityType::CreditCard => "CC",
123123
EntityType::Ssn => "SSN",
124124
EntityType::Date => "DATE",
125-
EntityType::Coordinates => "GEO",
125+
EntityType::Coordinate => "GEO",
126126
EntityType::MacAddress => "MAC",
127127
EntityType::Uuid => "UUID",
128128
EntityType::Hashtag => "#TAG",
129-
EntityType::SocialHandle => "@USER",
130129
EntityType::Custom(_) => "CUSTOM",
131130
_ => "OTHER",
132131
}

app/src-tauri/src/ui/views/layout.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
1515
use iced::{
1616
widget::{column, container, row},
17-
Element, Fill, Length,
17+
Element, Fill,
1818
};
1919

2020
use crate::ui::messages::Message;

app/src-tauri/src/ui/views/mcp.rs

Lines changed: 12 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,13 @@
44
55
use iced::{
66
widget::{button, column, container, row, rule, scrollable, text, text_input},
7-
Alignment, Element, Fill, Length, Padding,
7+
Alignment, Element, Fill, Padding,
88
};
99

1010
use crate::ui::messages::Message;
1111
use crate::ui::state::{AppState, ChatRole};
1212
use crate::ui::theme::colors;
13-
use crate::ui::views::identity::{active_btn_style, ghost_btn_style, input_style, panel_header};
13+
use crate::ui::views::identity::{active_btn_style, input_style, panel_header};
1414

1515
pub fn mcp_panel(state: &AppState) -> Element<Message> {
1616
let header = panel_header("MCP Agents");
@@ -22,10 +22,11 @@ pub fn mcp_panel(state: &AppState) -> Element<Message> {
2222
.color(colors::TEXT_MUTED)
2323
.into()
2424
} else {
25-
let mut btns = row![].spacing(4).wrap();
26-
for agent in &state.agents {
27-
let is_selected = state.selected_agent.as_deref() == Some(&agent.id);
28-
btns = btns.push(
25+
let buttons: Vec<Element<Message>> = state
26+
.agents
27+
.iter()
28+
.map(|agent| {
29+
let is_selected = state.selected_agent.as_deref() == Some(&agent.id);
2930
button(text(&agent.name).size(11).color(if is_selected {
3031
colors::TEXT
3132
} else {
@@ -46,10 +47,11 @@ pub fn mcp_panel(state: &AppState) -> Element<Message> {
4647
radius: 4.0.into(),
4748
},
4849
..Default::default()
49-
}),
50-
);
51-
}
52-
btns.into()
50+
})
51+
.into()
52+
})
53+
.collect();
54+
iced::widget::Row::with_children(buttons).spacing(4).into()
5355
};
5456

5557
// Chat history
@@ -129,12 +131,3 @@ pub fn mcp_panel(state: &AppState) -> Element<Message> {
129131
.into()
130132
}
131133

132-
// Allow row to wrap (iced 0.13)
133-
trait RowWrap {
134-
fn wrap(self) -> Self;
135-
}
136-
impl<'a, Message: Clone + 'a> RowWrap for iced::widget::Row<'a, Message> {
137-
fn wrap(self) -> Self {
138-
self // iced 0.13: wrapping rows via Flex are WIP; this is a no-op for now
139-
}
140-
}

app/src-tauri/src/ui/views/nav_bar.rs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,8 @@
33
//! Replaces NavBar.tsx from the React frontend.
44
55
use iced::{
6-
keyboard,
76
widget::{button, container, row, text, text_input},
8-
Element, Fill, Length, Padding,
7+
Element, Fill, Padding,
98
};
109

1110
use crate::ui::messages::Message;

app/src-tauri/src/ui/views/osint.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,13 @@
44
55
use iced::{
66
widget::{button, column, container, row, rule, scrollable, text, text_input},
7-
Alignment, Element, Fill, Length, Padding,
7+
Alignment, Element, Fill, Padding,
88
};
99

1010
use crate::ui::messages::Message;
1111
use crate::ui::state::{AppState, OsintMode};
1212
use crate::ui::theme::colors;
13-
use crate::ui::views::identity::{active_btn_style, ghost_btn_style, input_style, panel_header};
13+
use crate::ui::views::identity::{active_btn_style, input_style, panel_header};
1414

1515
pub fn osint_panel(state: &AppState) -> Element<Message> {
1616
let header = panel_header("OSINT Tools");

app/src-tauri/src/ui/views/privacy.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
55
use iced::{
66
widget::{button, column, container, row, rule, text},
7-
Alignment, Element, Fill, Length, Padding,
7+
Alignment, Element, Fill, Padding,
88
};
99

1010
use crate::core::privacy_engine::OpsecLevel;

0 commit comments

Comments
 (0)