Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
<!-- Generated by SpecStory, Markdown v2.1.0 -->

<!-- cursor Session e1e9239a-c980-49bb-9d93-9a048b088b44 (2026-02-23 16:43Z) -->

# Produire une description de Pull Request pour la branche Git (2026-02-23 16:43Z)

_**User**_

Produire une description de Pull Request pour la branche Git actuelle en analysant les derniers commit effectués sur celle-ci et en respectant les standards GitHub de nommage, syntaxe et formatage. Ne pas inclure de captures d'écrans et ne pas indiquer de clotures d'issue GitHub.

---

_**Agent (model default, mode Agent)**_
Comment on lines +9 to +13
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 | 🟡 Minor

Fix minor French typos and phrasing.

These are small but user-visible text issues.

✍️ Suggested edits
-Produire une description de Pull Request pour la branche Git actuelle en analysant les derniers commit effectués sur celle-ci et en respectant les standards GitHub de nommage, syntaxe et formatage. Ne pas inclure de captures d'écrans et ne pas indiquer de clotures d'issue GitHub.
+Produire une description de Pull Request pour la branche Git actuelle en analysant les derniers commits effectués sur celle-ci et en respectant les standards GitHub de nommage, syntaxe et formatage. Ne pas inclure de captures d'écrans et ne pas indiquer de clôtures d'issue GitHub.

-_**Agent (model default, mode Agent)**_
+_**Agent (modèle par défaut, mode Agent)**_
📝 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
Produire une description de Pull Request pour la branche Git actuelle en analysant les derniers commit effectués sur celle-ci et en respectant les standards GitHub de nommage, syntaxe et formatage. Ne pas inclure de captures d'écrans et ne pas indiquer de clotures d'issue GitHub.
---
_**Agent (model default, mode Agent)**_
Produire une description de Pull Request pour la branche Git actuelle en analysant les derniers commits effectués sur celle-ci et en respectant les standards GitHub de nommage, syntaxe et formatage. Ne pas inclure de captures d'écrans et ne pas indiquer de clôtures d'issue GitHub.
---
_**Agent (modèle par défaut, mode Agent)**_
🧰 Tools
🪛 LanguageTool

[grammar] ~9-~9: Le mot «  commits  » est plus probable.
Context: ... Git actuelle en analysant les derniers commit effectués sur celle-ci et en respectant...

(QB_NEW_FR_OTHER_ERROR_IDS_REPLACEMENT_CONFUSION_COMMIT_COMMITS)


[grammar] ~9-~9: Utilisez les accents correctement
Context: ...captures d'écrans et ne pas indiquer de clotures d'issue GitHub. --- _**Agent (model d...

(QB_NEW_FR_OTHER_ERROR_IDS_MISSING_ORTHOGRAPHY_DIACRITIC_CIRCUMFLEX)


[grammar] ~13-~13: Essayez «  modèle par défaut  »
Context: ...lotures d'issue GitHub. --- Agent (model default, mode Agent) ---

(QB_NEW_FR_OTHER_ERROR_IDS_REPLACEMENT_MULTITOKEN)


[grammar] ~13-~13: Essayez «  modèle par défaut  »
Context: ...s d'issue GitHub. --- Agent (model default, mode Agent) ---

(QB_NEW_FR_OTHER_ERROR_IDS_REPLACEMENT_MULTITOKEN)

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
@.specstory/history/2026-02-23_16-43Z-produire-une-description-de-pull-request-pour-la-branche-git.md
around lines 9 - 13, Corrigez les fautes et améliorez la formulation du texte
affiché (repérez la ligne commençant par "Produire une description de Pull
Request pour la branche Git actuelle...") : appliquez les accents corrects (ex.
"clôtures"), remplacez formulations maladroites par des équivalents naturels en
français (par ex. "branche Git courante" ou "conformément aux conventions GitHub
de nommage, syntaxe et formatage"), enlevez éléments superflus/markers inutiles
(ex. underscores autour de "Agent") et assurez une phrase concise qui conserve
l'instruction "Ne pas inclure de captures d'écrans et ne pas indiquer de
clôtures d'issue GitHub."




---

2 changes: 1 addition & 1 deletion index.html
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
<title>SuperFlux</title>
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Playfair+Display:ital,wght@0,400;0,500;0,600;0,700;1,400;1,500&family=DM+Sans:ital,opsz,wght@0,9..40,300;0,9..40,400;0,9..40,500;0,9..40,600;1,9..40,300;1,9..40,400&display=swap" rel="stylesheet">
<link href="https://fonts.googleapis.com/css2?family=Caveat:wght@400;500;600;700&family=Playfair+Display:ital,wght@0,400;0,500;0,600;0,700;1,400;1,500&family=DM+Sans:ital,opsz,wght@0,9..40,300;0,9..40,400;0,9..40,500;0,9..40,600;1,9..40,300;1,9..40,400&display=swap" rel="stylesheet">
<script>
(function() {
var t = localStorage.getItem('theme');
Expand Down
116 changes: 116 additions & 0 deletions src-tauri/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions src-tauri/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -21,3 +21,4 @@ url = "2"
open = "5.3.3"
tts = "0.26"
base64 = "0.22"
sysinfo = "0.32"
4 changes: 3 additions & 1 deletion src-tauri/capabilities/default.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,11 @@
"$schema": "https://raw.githubusercontent.com/nicegui-org/nicegui/main/tauri-capabilities-schema.json",
"identifier": "default",
"description": "Capability for the main window",
"windows": ["main"],
"windows": ["main", "auth"],
"permissions": [
"core:default",
"core:event:default",
"core:webview:allow-create-webview-window",
"core:window:allow-minimize",
Comment on lines +5 to 10
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 | 🟠 Major

Avoid granting default capabilities to the auth window.

If the auth webview loads remote OAuth pages, inheriting core:default (and other window permissions) exposes sensitive APIs to untrusted content. Move auth into a minimal, dedicated capability file instead of the default set.

🔒 Suggested fix (remove auth from default capability)
-  "windows": ["main", "auth"],
+  "windows": ["main"],
📝 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
"windows": ["main", "auth"],
"permissions": [
"core:default",
"core:event:default",
"core:webview:allow-create-webview-window",
"core:window:allow-minimize",
"windows": ["main"],
"permissions": [
"core:default",
"core:event:default",
"core:webview:allow-create-webview-window",
"core:window:allow-minimize",
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src-tauri/capabilities/default.json` around lines 5 - 10, Remove "auth" from
the default capability set so the auth webview does not inherit broad
permissions; update the "windows" array that currently contains ["main", "auth"]
to only include "main" and create a new minimal capability file (or capability
entry) for the auth window that omits "core:default" and other sensitive
permissions (keep only explicitly required permissions for OAuth webviews such
as safe webview-specific entries). Ensure references to the auth window
everywhere (the "auth" window name) point to the new minimal capability instead
of the default.

"core:window:allow-toggle-maximize",
"core:window:allow-close",
Expand Down
2 changes: 1 addition & 1 deletion src-tauri/gen/schemas/capabilities.json
Original file line number Diff line number Diff line change
@@ -1 +1 @@
{"default":{"identifier":"default","description":"Capability for the main window","local":true,"windows":["main"],"permissions":["core:default","core:window:allow-minimize","core:window:allow-toggle-maximize","core:window:allow-close","core:window:allow-is-maximized","core:window:allow-start-dragging","core:window:allow-set-minimizable","core:window:allow-set-size","core:window:allow-inner-size","core:window:allow-set-min-size","core:window:allow-set-resizable","core:window:allow-outer-position","core:window:allow-set-position","core:window:allow-set-focus","core:window:allow-set-always-on-top","core:window:allow-set-effects"]}}
{"default":{"identifier":"default","description":"Capability for the main window","local":true,"windows":["main","auth"],"permissions":["core:default","core:event:default","core:webview:allow-create-webview-window","core:window:allow-minimize","core:window:allow-toggle-maximize","core:window:allow-close","core:window:allow-is-maximized","core:window:allow-start-dragging","core:window:allow-set-minimizable","core:window:allow-set-size","core:window:allow-inner-size","core:window:allow-set-min-size","core:window:allow-set-resizable","core:window:allow-outer-position","core:window:allow-set-position","core:window:allow-set-focus","core:window:allow-set-always-on-top","core:window:allow-set-effects"]}}
121 changes: 120 additions & 1 deletion src-tauri/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -261,6 +261,88 @@ async fn http_request(
})
}

#[tauri::command]
fn get_cpu_usage() -> f32 {
use sysinfo::System;
static SYS: OnceLock<Mutex<System>> = OnceLock::new();
let mtx = SYS.get_or_init(|| {
let mut sys = System::new();
sys.refresh_cpu_usage();
Mutex::new(sys)
});
let mut sys = mtx.lock().unwrap();
sys.refresh_cpu_usage();
sys.global_cpu_usage()
Comment on lines +267 to +275
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Action required

5. mtx.lock().unwrap() may panic 📘 Rule violation ⛯ Reliability

The new sysinfo Tauri commands use unwrap() on mutex locks, which can crash the app if the mutex
is poisoned or unavailable. This is a new failure mode without graceful error handling or fallback
behavior.
Agent Prompt
## Issue description
Sysinfo commands use `unwrap()` on mutex locks, which can panic and crash the app under error conditions.

## Issue Context
Robust error handling requires graceful degradation and actionable diagnostics rather than panics.

## Fix Focus Areas
- src-tauri/src/lib.rs[267-275]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

}

#[derive(Serialize)]
struct MemoryInfo {
used_gb: f64,
total_gb: f64,
percent: f32,
}

#[tauri::command]
fn get_memory_usage() -> MemoryInfo {
use sysinfo::System;
let mut sys = System::new();
sys.refresh_memory();
let total = sys.total_memory() as f64;
let used = sys.used_memory() as f64;
let gb = 1_073_741_824.0; // 1 GiB
MemoryInfo {
used_gb: (used / gb * 10.0).round() / 10.0,
total_gb: (total / gb * 10.0).round() / 10.0,
percent: if total > 0.0 { (used / total * 100.0) as f32 } else { 0.0 },
}
}

#[derive(Serialize)]
struct NetSpeed {
download_kbps: f64,
upload_kbps: f64,
}

#[tauri::command]
fn get_net_speed() -> NetSpeed {
use sysinfo::Networks;
use std::time::Instant;

static NET: OnceLock<Mutex<(Networks, Instant, u64, u64)>> = OnceLock::new();
let mtx = NET.get_or_init(|| {
let mut nets = Networks::new_with_refreshed_list();
nets.refresh();
let (rx, tx) = nets.iter().fold((0u64, 0u64), |(r, t), (_name, data)| {
(r + data.total_received(), t + data.total_transmitted())
});
Mutex::new((nets, Instant::now(), rx, tx))
});

let mut guard = mtx.lock().unwrap();
let (ref mut nets, ref mut last_time, ref mut last_rx, ref mut last_tx) = *guard;

nets.refresh();
let now = Instant::now();
let elapsed = now.duration_since(*last_time);
let secs = elapsed.as_secs_f64().max(0.1);

let (rx, tx) = nets.iter().fold((0u64, 0u64), |(r, t), (_name, data)| {
(r + data.total_received(), t + data.total_transmitted())
});

let dl = (rx.saturating_sub(*last_rx) as f64) / secs / 1024.0; // KB/s
let ul = (tx.saturating_sub(*last_tx) as f64) / secs / 1024.0;

*last_time = now;
*last_rx = rx;
*last_tx = tx;

NetSpeed {
download_kbps: (dl * 10.0).round() / 10.0,
upload_kbps: (ul * 10.0).round() / 10.0,
}
}

#[tauri::command]
fn open_external(url: String) -> Result<(), String> {
open::that(&url).map_err(|e| format!("Failed to open URL: {e}"))
Expand Down Expand Up @@ -507,14 +589,51 @@ async fn tts_speak_elevenlabs(
Ok(STANDARD.encode(&bytes))
}

#[cfg(not(target_os = "android"))]
#[tauri::command]
async fn open_auth_window(app: tauri::AppHandle, url: String) -> Result<(), String> {
use tauri::{Emitter, WebviewUrl, WebviewWindowBuilder};

// Close any existing auth window
if let Some(existing) = app.get_webview_window("auth") {
let _ = existing.close();
}

let parsed_url: Url = url.parse().map_err(|e: url::ParseError| format!("Invalid URL: {e}"))?;
let app_handle = app.clone();

WebviewWindowBuilder::new(&app, "auth", WebviewUrl::External(parsed_url))
.title("Sign in")
Comment on lines +594 to +606
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Action required

4. open_auth_window accepts any url 📘 Rule violation ⛨ Security

The new open_auth_window command builds an external webview window from a caller-provided URL
without allowlisting/validation. This can enable opening arbitrary external content inside the app
if the command is invoked with a malicious URL.
Agent Prompt
## Issue description
`open_auth_window` opens an external webview for any parsed URL without allowlisting, which is unsafe for externally-influenced input.

## Issue Context
Security-first input validation requires validating/sanitizing external inputs and preventing unsafe navigation to arbitrary domains.

## Fix Focus Areas
- src-tauri/src/lib.rs[594-606]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

.inner_size(500.0, 700.0)
.on_navigation(move |nav_url| {
let url_str = nav_url.as_str();
// Intercept redirect to our callback URL
if url_str.starts_with("http://localhost/auth/callback") {
let _ = app_handle.emit("auth-callback", url_str.to_string());
return false; // Block navigation to localhost
}
true
})
.build()
.map_err(|e| format!("Failed to create auth window: {e}"))?;

Ok(())
}

#[cfg(target_os = "android")]
#[tauri::command]
async fn open_auth_window(_url: String) -> Result<(), String> {
Ok(())
Comment on lines +623 to +626
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Action required

7. Android auth invoke mismatch 🐞 Bug ✓ Correctness

On Android, the Rust open_auth_window command parameter is named _url, but the frontend invokes
it with { url: ... }. Tauri matches parameters by name, so OAuth will likely fail to open the auth
window on Android.
Agent Prompt
## Issue description
Android build likely fails to invoke `open_auth_window` because the Rust parameter name is `_url` but the frontend sends `{ url: ... }`.

## Issue Context
Tauri `invoke()` payload keys must match the command function parameter names.

## Fix Focus Areas
- src-tauri/src/lib.rs[623-627]
- src/contexts/AuthContext.tsx[57-94]

## Suggested change
- Change Android implementation to:
  - `async fn open_auth_window(url: String) -> Result<(), String> { let _ = url; Ok(()) }`
- Keep frontend invocation as-is (`{ url: data.url }`).

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

}

#[cfg_attr(mobile, tauri::mobile_entry_point)]
pub fn run() {
tauri::Builder::default()
.manage(AppState {
#[cfg(not(target_os = "android"))]
saved: Mutex::new(None),
})
.invoke_handler(tauri::generate_handler![fetch_url, http_request, open_external, collapse_window, expand_window, check_network, set_window_effect, tts_speak, tts_stop, tts_speak_elevenlabs])
.invoke_handler(tauri::generate_handler![fetch_url, http_request, open_external, get_cpu_usage, get_memory_usage, get_net_speed, collapse_window, expand_window, check_network, set_window_effect, tts_speak, tts_stop, tts_speak_elevenlabs, open_auth_window])
.setup(|_app| {
#[cfg(not(target_os = "android"))]
{
Expand Down
2 changes: 1 addition & 1 deletion src-tauri/tauri.conf.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"$schema": "https://raw.githubusercontent.com/tauri-apps/tauri/dev/crates/tauri-config-schema/schema.json",
"productName": "SuperFlux",
"version": "0.4.0",
"version": "0.5.0",
"identifier": "com.ohmycode.superflux",
"build": {
"beforeDevCommand": "npm run dev:app",
Expand Down
Loading