Skip to content

Commit 5012846

Browse files
hyperpolymathclaude
andcommitted
feat: complete Tauri removal — 270 commands migrated to Gossamer
Removed src-tauri/ (3.5 GB). Deleted TauriCmd.res. New gossamer-rs backend (src-gossamer/) with 270 command registrations across 105 .rs modules. Compat shim provides AppHandle/Emitter for event-emitting modules. RuntimeBridge cleaned to Gossamer-only. @tauri-apps deps removed. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent 5308d96 commit 5012846

125 files changed

Lines changed: 2638 additions & 15938 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

Cargo.toml

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
# SPDX-License-Identifier: PMPL-1.0-or-later
2+
#
3+
# PanLL eNSAID — Gossamer backend
4+
#
5+
# This replaces the former src-tauri/ Tauri 2.0 backend with a Gossamer-native
6+
# binary. All 103 command handlers are registered via gossamer_rs::App::command()
7+
# instead of #[tauri::command] macros. Business logic is unchanged — only the
8+
# IPC dispatch layer changed.
9+
#
10+
# The gossamer-rs crate links to libgossamer.so (Zig FFI) at runtime, providing
11+
# the same webview + IPC channel that Tauri provided, but without the Tauri
12+
# runtime dependency.
13+
14+
[package]
15+
name = "panll"
16+
version = "0.2.0"
17+
description = "PanLL eNSAID - Environment for NeSy-Agentic Integrated Development (Gossamer backend)"
18+
authors = ["Jonathan D.A. Jewell <j.d.a.jewell@open.ac.uk>"]
19+
edition = "2021"
20+
license = "PMPL-1.0-or-later"
21+
repository = "https://github.com/hyperpolymath/panll"
22+
23+
[[bin]]
24+
name = "panll-gossamer"
25+
path = "src-gossamer/src/main.rs"
26+
27+
[dependencies]
28+
# Gossamer webview shell — replaces tauri
29+
gossamer-rs = { path = "../gossamer/bindings/rust" }
30+
31+
# Serialisation — used by every command handler
32+
serde = { version = "1", features = ["derive"] }
33+
serde_json = "1"
34+
35+
# Shared state (replaces Tauri State<> extractor)
36+
once_cell = "1"
37+
38+
# HTTP clients for service bridges (BoJ, VeriSimDB, ECHIDNA, Fleet, Hypatia, etc.)
39+
reqwest = { version = "0.12", features = ["json", "blocking", "stream"] }
40+
futures = "0.3"
41+
tokio = { version = "1", features = ["macros", "rt", "rt-multi-thread"] }
42+
43+
# Filesystem — dirs, watcher, walker
44+
dirs = "6"
45+
notify = { version = "7", features = ["serde"] }
46+
notify-debouncer-mini = "0.5"
47+
walkdir = "2"
48+
49+
# Text processing
50+
regex = "1"
51+
52+
# System
53+
libc = "0.2"
54+
which = "7"
55+
uuid = { version = "1.22.0", features = ["v4"] }
56+
57+
[dev-dependencies]
58+
tokio = { version = "1", features = ["macros", "rt"] }
59+
60+
[profile.release]
61+
panic = "abort"
62+
codegen-units = 1
63+
lto = true
64+
opt-level = "s"
65+
strip = true

deno.json

Lines changed: 5 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,11 @@
55
"description": "Panel workspace framework — TEA (The Elm Architecture) for ReScript with tiling layout, smart routing, keyboard navigation, undo engine, and security-hardened DOM. Build panel-based UIs for desktop and web.",
66
"exports": "./mod.js",
77
"tasks": {
8-
"dev": "cargo tauri dev",
9-
"build": "cargo tauri build",
10-
"gossamer:dev": "cd src-gossamer && zig build && cd .. && deno task bundle && deno task serve:dev",
11-
"gossamer:build": "cd src-gossamer && zig build -Doptimize=ReleaseSafe && cd .. && deno task bundle && deno task css:build",
12-
"gossamer:run": "cd src-gossamer && zig build && zig-out/bin/panll-gossamer",
8+
"dev": "cargo build && cargo run --bin panll-gossamer & deno task bundle && deno task serve:dev",
9+
"build": "cargo build --release && deno task bundle && deno task css:build",
10+
"gossamer:dev": "cargo build && cargo run --bin panll-gossamer & deno task bundle && deno task serve:dev",
11+
"gossamer:build": "cargo build --release && deno task bundle && deno task css:build",
12+
"gossamer:run": "cargo run --bin panll-gossamer",
1313
"bundle": "DENO_NO_PACKAGE_JSON=1 deno run -A scripts/bundle.ts",
1414
"bundle:watch": "DENO_NO_PACKAGE_JSON=1 deno run -A scripts/bundle.ts --watch",
1515
"css:build": "deno run -A npm:tailwindcss -i ./src/styles/input.css -o ./public/styles.css --minify",
@@ -28,9 +28,6 @@
2828
"imports": {
2929
"@std/": "jsr:@std/",
3030
"@gossamer/api": "./src-gossamer/bindings/rescript/src/Gossamer.res.js",
31-
"@tauri-apps/api": "npm:@tauri-apps/api@^2.10.0",
32-
"@tauri-apps/plugin-dialog": "npm:@tauri-apps/plugin-dialog",
33-
"@tauri-apps/plugin-fs": "npm:@tauri-apps/plugin-fs",
3431
"rescript": "npm:rescript@^12.0.0",
3532
"@rescript/core/": "npm:@rescript/core@1.6.1/",
3633
"@rescript/runtime/": "npm:@rescript/runtime@12.2.0/"

package.json

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,6 @@
55
"type": "module",
66
"devDependencies": {
77
"@rescript/core": "^1.6.1",
8-
"@tauri-apps/api": "^2.10.0",
9-
"@tauri-apps/cli": "^2.0.0",
108
"rescript": "^12.0.0",
119
"tailwindcss": "^3.4.19"
1210
},
@@ -16,13 +14,11 @@
1614
"htmi",
1715
"eNSAID",
1816
"rescript",
19-
"tauri"
17+
"gossamer"
2018
],
2119
"author": "Jonathan D.A. Jewell <j.d.a.jewell@open.ac.uk>",
2220
"license": "PMPL-1.0-or-later",
2321
"dependencies": {
24-
"@rescript/runtime": "^12.2.0",
25-
"@tauri-apps/plugin-dialog": "^2.6.0",
26-
"@tauri-apps/plugin-fs": "^2.4.5"
22+
"@rescript/runtime": "^12.2.0"
2723
}
2824
}
Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@ fn collect_a2ml_files(dir: &Path, results: &mut Vec<String>, root: &Path) {
6666
///
6767
/// Returns the file content as a JSON object with `path` and `content` fields.
6868
/// The ReScript A2mlEngine handles the actual parsing.
69-
#[tauri::command]
69+
7070
pub fn a2ml_load_manifest(path: String) -> Result<String, String> {
7171
let file_path = if Path::new(&path).is_absolute() {
7272
PathBuf::from(&path)
@@ -100,7 +100,7 @@ pub fn a2ml_load_manifest(path: String) -> Result<String, String> {
100100
/// - File contains recognisable A2ML markers (sections, S-expressions, or headers)
101101
///
102102
/// Returns a JSON object with `valid`, `errors`, and `warnings` fields.
103-
#[tauri::command]
103+
104104
pub fn a2ml_validate(path: String) -> Result<String, String> {
105105
let file_path = if Path::new(&path).is_absolute() {
106106
PathBuf::from(&path)
@@ -185,7 +185,7 @@ pub fn a2ml_validate(path: String) -> Result<String, String> {
185185
/// Recursively searches the repository tree (excluding `node_modules`, `target`,
186186
/// `lib`, and hidden directories other than `.machine_readable`). Returns a
187187
/// JSON array of relative file paths.
188-
#[tauri::command]
188+
189189
pub fn a2ml_list() -> Result<String, String> {
190190
let root = find_repo_root()?;
191191
let mut files: Vec<String> = Vec::new();
Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ fn speed_test_url() -> String {
3737
/// runtime for too long. For a truly non-blocking version, this would need
3838
/// tokio::net::TcpStream, but the timeout keeps it safe enough for a panel
3939
/// probe that runs on user action.
40-
#[tauri::command]
40+
4141
pub async fn aerie_get_latency() -> Result<String, String> {
4242
let target = latency_target();
4343
let addr: std::net::SocketAddr = target
@@ -72,7 +72,7 @@ pub async fn aerie_get_latency() -> Result<String, String> {
7272
/// Downloads a 1 MB payload from the configured URL and measures throughput.
7373
/// Returns JSON with `speed_mbps`, `bytes_downloaded`, `duration_ms`, and
7474
/// `status` fields. On failure, returns `status: "failed"` with the error.
75-
#[tauri::command]
75+
7676
pub async fn aerie_speed_test() -> Result<String, String> {
7777
let url = speed_test_url();
7878
let client = reqwest::Client::builder()
Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ fn save_config(config: &AiProvidersFile) -> Result<(), String> {
5757
/// Returns the provider's response as a JSON-serialised `SendMessageResponse`.
5858
/// If the provider returns 429, the response has `quota_exhausted: true` and
5959
/// the frontend should retry with the next provider.
60-
#[tauri::command]
60+
6161
pub async fn ai_send_message(request: SendMessageRequest) -> Result<String, String> {
6262
let config_file = load_config()?;
6363

@@ -99,7 +99,7 @@ pub async fn ai_send_message(request: SendMessageRequest) -> Result<String, Stri
9999
///
100100
/// Sends a minimal request to verify the API key works.
101101
/// Returns a JSON object with `{ "status": "ready"|"error"|"no_key", "detail": "..." }`.
102-
#[tauri::command]
102+
103103
pub async fn ai_check_provider(provider_id: String) -> Result<String, String> {
104104
let config_file = load_config()?;
105105
let pid: ProviderId =
@@ -168,7 +168,7 @@ pub async fn ai_check_provider(provider_id: String) -> Result<String, String> {
168168
}
169169

170170
/// Change the selected model for a provider.
171-
#[tauri::command]
171+
172172
pub async fn ai_set_model(provider_id: String, model: String) -> Result<String, String> {
173173
let mut config_file = load_config()?;
174174
let pid: ProviderId =
@@ -188,7 +188,7 @@ pub async fn ai_set_model(provider_id: String, model: String) -> Result<String,
188188
}
189189

190190
/// Change a provider's precedence ranking.
191-
#[tauri::command]
191+
192192
pub async fn ai_set_priority(provider_id: String, priority: u32) -> Result<String, String> {
193193
let mut config_file = load_config()?;
194194
let pid: ProviderId =
@@ -208,7 +208,7 @@ pub async fn ai_set_priority(provider_id: String, priority: u32) -> Result<Strin
208208
}
209209

210210
/// Enable or disable a provider (mute/unmute without losing the API key).
211-
#[tauri::command]
211+
212212
pub async fn ai_toggle_provider(provider_id: String) -> Result<String, String> {
213213
let mut config_file = load_config()?;
214214
let pid: ProviderId =
@@ -231,7 +231,7 @@ pub async fn ai_toggle_provider(provider_id: String) -> Result<String, String> {
231231
/// Clear the conversation history. This is a frontend-only operation;
232232
/// this command exists as a hook for any backend cleanup needed later
233233
/// (e.g., clearing cached token counts).
234-
#[tauri::command]
234+
235235
pub async fn ai_clear_history() -> Result<String, String> {
236236
Ok(serde_json::json!({ "cleared": true }).to_string())
237237
}
@@ -240,7 +240,7 @@ pub async fn ai_clear_history() -> Result<String, String> {
240240
///
241241
/// Reads SCM files, AI manifest, detected languages, and assembles a
242242
/// structured context string for the AI system prompt.
243-
#[tauri::command]
243+
244244
pub async fn ai_build_context(repo_path: String) -> Result<String, String> {
245245
let context_str = context::build_repo_context(&repo_path)?;
246246
Ok(serde_json::json!({ "context": context_str }).to_string())
@@ -250,7 +250,7 @@ pub async fn ai_build_context(repo_path: String) -> Result<String, String> {
250250
///
251251
/// Returns the full `AiProvidersFile` as JSON. The frontend uses this
252252
/// to initialise the provider key ring on panel open.
253-
#[tauri::command]
253+
254254
pub async fn ai_get_state() -> Result<String, String> {
255255
let config_file = load_config()?;
256256
serde_json::to_string(&config_file).map_err(|e| format!("Serialisation error: {e}"))
@@ -265,9 +265,9 @@ pub async fn ai_get_state() -> Result<String, String> {
265265
///
266266
/// Returns `"streaming_started"` immediately. Errors during streaming are
267267
/// emitted as `StreamChunk::Error` events rather than returned here.
268-
#[tauri::command]
268+
269269
pub async fn ai_send_message_streaming(
270-
app_handle: tauri::AppHandle,
270+
app_handle: crate::compat::AppHandle,
271271
request: StreamingRequest,
272272
) -> Result<String, String> {
273273
let config_file = load_config()?;
@@ -312,7 +312,7 @@ pub async fn ai_send_message_streaming(
312312
let content = request.content.clone();
313313

314314
// Spawn the streaming task so we can return immediately.
315-
tauri::async_runtime::spawn(async move {
315+
crate::compat::spawn_async(async move {
316316
let tools_ref = tools_owned.as_deref();
317317
let tool_results_ref = tool_results_owned.as_deref();
318318

@@ -327,7 +327,7 @@ pub async fn ai_send_message_streaming(
327327
)
328328
.await
329329
{
330-
use tauri::Emitter;
330+
use crate::compat::Emitter;
331331
let _ = app_handle.emit(
332332
"ai:stream-chunk",
333333
&StreamChunk::Error(e),

0 commit comments

Comments
 (0)