Skip to content

Commit 29a53fb

Browse files
Merge pull request #1420 from CapSoftware/cursor/add-circle-cursor-option-to-settings-claude-4.5-opus-high-thinking-64f7
Add circle cursor option to settings
2 parents 245111c + cea939a commit 29a53fb

File tree

78 files changed

+3680
-1186
lines changed

Some content is hidden

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

78 files changed

+3680
-1186
lines changed

.github/workflows/ci.yml

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -103,9 +103,8 @@ jobs:
103103
settings:
104104
- target: aarch64-apple-darwin
105105
runner: macos-latest
106-
# Windows can't take the disk usage lol
107-
# - target: x86_64-pc-windows-msvc
108-
# runner: windows-latest
106+
- target: x86_64-pc-windows-msvc
107+
runner: windows-latest
109108
runs-on: ${{ matrix.settings.runner }}
110109
permissions:
111110
contents: read

.vscode/extensions.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
11
{
2-
"recommendations": ["tauri-apps.tauri-vscode", "rust-lang.rust-analyzer"]
2+
"recommendations": ["biomejs.biome", "rust-lang.rust-analyzer"]
33
}

AGENTS.md

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,26 @@
2222
- Runtime: Node 20, pnpm 10.x, Rust 1.88+, Docker for MySQL/MinIO.
2323
- **NO COMMENTS**: Never add comments to code (`//`, `/* */`, `///`, `//!`, `#`, etc.). Code must be self-explanatory through naming, types, and structure. This applies to all languages (TypeScript, Rust, JavaScript, etc.).
2424

25+
## Rust Clippy Rules (Workspace Lints)
26+
All Rust code must respect these workspace-level lints defined in `Cargo.toml`:
27+
28+
**Rust compiler lints:**
29+
- `unused_must_use = "deny"` — Always handle `Result`/`Option` or types marked `#[must_use]`; never ignore them.
30+
31+
**Clippy lints (all denied):**
32+
- `dbg_macro` — Never use `dbg!()` in code; use proper logging instead.
33+
- `let_underscore_future` — Never write `let _ = async_fn()` which silently drops futures; await or explicitly handle them.
34+
- `unchecked_duration_subtraction` — Use `saturating_sub` instead of `-` for `Duration` to avoid panics.
35+
- `collapsible_if` — Merge nested `if` statements: use `if a && b { }` instead of `if a { if b { } }`.
36+
- `clone_on_copy` — Don't call `.clone()` on `Copy` types; just copy them directly.
37+
- `redundant_closure` — Use function references directly: `iter.map(foo)` instead of `iter.map(|x| foo(x))`.
38+
- `ptr_arg` — Accept `&[T]` or `&str` instead of `&Vec<T>` or `&String` in function parameters.
39+
- `len_zero` — Use `.is_empty()` instead of `.len() == 0` or `.len() > 0`.
40+
- `let_unit_value` — Don't assign `()` to a variable: write `foo();` instead of `let _ = foo();` when return is unit.
41+
- `unnecessary_lazy_evaluations` — Use `.unwrap_or(val)` instead of `.unwrap_or_else(|| val)` for cheap values.
42+
- `needless_range_loop` — Use `for item in &collection` instead of `for i in 0..collection.len()` when index isn't needed.
43+
- `manual_clamp` — Use `.clamp(min, max)` instead of manual `if` chains or `.min().max()` patterns.
44+
2545
## Testing
2646
- TS/JS: Vitest where present (e.g., desktop). Name tests `*.test.ts(x)` near sources.
2747
- Rust: `cargo test` per crate; tests in `src` or `tests`.

CLAUDE.md

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -371,6 +371,66 @@ Minimize `useEffect` usage: compute during render, handle logic in event handler
371371
- Strict TypeScript; avoid `any`; leverage shared types
372372
- Use Biome for linting/formatting; match existing formatting
373373

374+
## Rust Clippy Rules (Workspace Lints)
375+
All Rust code must respect these workspace-level lints defined in `Cargo.toml`. Violating any of these will fail CI:
376+
377+
**Rust compiler lints:**
378+
- `unused_must_use = "deny"` — Always handle `Result`/`Option` or types marked `#[must_use]`; never ignore them.
379+
380+
**Clippy lints (all denied — code MUST NOT contain these patterns):**
381+
- `dbg_macro` — Never use `dbg!()` in code; use proper logging (`tracing::debug!`, etc.) instead.
382+
- `let_underscore_future` — Never write `let _ = async_fn()` which silently drops futures; await or explicitly handle them.
383+
- `unchecked_duration_subtraction` — Use `duration.saturating_sub(other)` instead of `duration - other` to avoid panics on underflow.
384+
- `collapsible_if` — Merge nested `if` statements: write `if a && b { }` instead of `if a { if b { } }`.
385+
- `clone_on_copy` — Don't call `.clone()` on `Copy` types (integers, bools, etc.); just copy them directly.
386+
- `redundant_closure` — Use function references directly: `iter.map(foo)` instead of `iter.map(|x| foo(x))`.
387+
- `ptr_arg` — Accept `&[T]` or `&str` instead of `&Vec<T>` or `&String` in function parameters for flexibility.
388+
- `len_zero` — Use `.is_empty()` instead of `.len() == 0` or `.len() > 0` / `.len() != 0`.
389+
- `let_unit_value` — Don't assign `()` to a variable: write `foo();` instead of `let _ = foo();` or `let x = foo();` when return is unit.
390+
- `unnecessary_lazy_evaluations` — Use `.unwrap_or(val)` instead of `.unwrap_or_else(|| val)` when the default is a simple/cheap value.
391+
- `needless_range_loop` — Use `for item in &collection` or `for (i, item) in collection.iter().enumerate()` instead of `for i in 0..collection.len()`.
392+
- `manual_clamp` — Use `value.clamp(min, max)` instead of manual `if` chains or `.min(max).max(min)` patterns.
393+
394+
**Examples of violations to avoid:**
395+
396+
```rust
397+
dbg!(value);
398+
let _ = some_async_function();
399+
let duration = duration_a - duration_b;
400+
if condition {
401+
if other_condition {
402+
do_something();
403+
}
404+
}
405+
let x = 5.clone();
406+
vec.iter().map(|x| process(x))
407+
fn example(v: &Vec<i32>) { }
408+
if vec.len() == 0 { }
409+
let _ = returns_unit();
410+
option.unwrap_or_else(|| 42)
411+
for i in 0..vec.len() { println!("{}", vec[i]); }
412+
value.min(max).max(min)
413+
```
414+
415+
**Correct alternatives:**
416+
417+
```rust
418+
tracing::debug!(?value);
419+
some_async_function().await;
420+
let duration = duration_a.saturating_sub(duration_b);
421+
if condition && other_condition {
422+
do_something();
423+
}
424+
let x = 5;
425+
vec.iter().map(process)
426+
fn example(v: &[i32]) { }
427+
if vec.is_empty() { }
428+
returns_unit();
429+
option.unwrap_or(42)
430+
for item in &vec { println!("{}", item); }
431+
value.clamp(min, max)
432+
```
433+
374434
## Security & Privacy Considerations
375435

376436
### Data Handling

Cargo.lock

Lines changed: 17 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,11 @@
11
[workspace]
22
resolver = "2"
3-
members = ["apps/cli", "apps/desktop/src-tauri", "crates/*", "crates/workspace-hack"]
3+
members = [
4+
"apps/cli",
5+
"apps/desktop/src-tauri",
6+
"crates/*",
7+
"crates/workspace-hack",
8+
]
49

510
[workspace.dependencies]
611
anyhow = { version = "1.0.86" }
@@ -22,6 +27,7 @@ specta = { version = "=2.0.0-rc.20", features = [
2227
"derive",
2328
"serde_json",
2429
"uuid",
30+
"chrono"
2531
] }
2632
serde = { version = "1", features = ["derive"] }
2733

@@ -40,6 +46,7 @@ sentry = { version = "0.42.0", features = [
4046
] }
4147
tracing = "0.1.41"
4248
futures = "0.3.31"
49+
aho-corasick = "1.1.4"
4350

4451
cidre = { git = "https://github.com/CapSoftware/cidre", rev = "bf84b67079a8", features = [
4552
"macos_12_7",

apps/desktop/src-tauri/Cargo.toml

Lines changed: 16 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -20,11 +20,11 @@ swift-rs = { version = "1.0.6", features = ["build"] }
2020

2121
[dependencies]
2222
tauri = { workspace = true, features = [
23-
"macos-private-api",
24-
"protocol-asset",
25-
"tray-icon",
26-
"image-png",
27-
"devtools",
23+
"macos-private-api",
24+
"protocol-asset",
25+
"tray-icon",
26+
"image-png",
27+
"devtools",
2828
] }
2929
tauri-specta = { version = "=2.0.0-rc.20", features = ["derive", "typescript"] }
3030
tauri-plugin-dialog = "2.2.0"
@@ -60,6 +60,7 @@ tracing.workspace = true
6060
tempfile = "3.9.0"
6161
ffmpeg.workspace = true
6262
chrono = { version = "0.4.31", features = ["serde"] }
63+
regex = "1.10.4"
6364
rodio = "0.19.0"
6465
png = "0.17.13"
6566
device_query = "4.0.1"
@@ -106,22 +107,24 @@ tauri-plugin-sentry = "0.5.0"
106107
thiserror.workspace = true
107108
bytes = "1.10.1"
108109
async-stream = "0.3.6"
110+
sanitize-filename = "0.6.0"
109111
tracing-futures = { version = "0.2.5", features = ["futures-03"] }
110112
tracing-opentelemetry = "0.32.0"
111113
opentelemetry = "0.31.0"
112-
opentelemetry-otlp = "0.31.0" #{ version = , features = ["http-proto", "reqwest-client"] }
114+
opentelemetry-otlp = "0.31.0" #{ version = , features = ["http-proto", "reqwest-client"] }
113115
opentelemetry_sdk = { version = "0.31.0", features = ["rt-tokio", "trace"] }
114116
posthog-rs = "0.3.7"
115117
workspace-hack = { version = "0.1", path = "../../../crates/workspace-hack" }
118+
aho-corasick.workspace = true
116119

117120

118121
[target.'cfg(target_os = "macos")'.dependencies]
119122
core-graphics = "0.24.0"
120123
core-foundation = "0.10.0"
121124
objc2-app-kit = { version = "0.3.0", features = [
122-
"NSWindow",
123-
"NSResponder",
124-
"NSHapticFeedback",
125+
"NSWindow",
126+
"NSResponder",
127+
"NSHapticFeedback",
125128
] }
126129
cocoa = "0.26.0"
127130
objc = "0.2.7"
@@ -131,10 +134,10 @@ cidre = { workspace = true }
131134

132135
[target.'cfg(target_os= "windows")'.dependencies]
133136
windows = { workspace = true, features = [
134-
"Win32_Foundation",
135-
"Win32_System",
136-
"Win32_UI_WindowsAndMessaging",
137-
"Win32_Graphics_Gdi",
137+
"Win32_Foundation",
138+
"Win32_System",
139+
"Win32_UI_WindowsAndMessaging",
140+
"Win32_Graphics_Gdi",
138141
] }
139142
windows-sys = { workspace = true }
140143

apps/desktop/src-tauri/src/audio_meter.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -140,6 +140,6 @@ fn samples_to_f64(samples: &MicrophoneSamples) -> impl Iterator<Item = f64> + us
140140
SampleFormat::F64 => f64::from_ne_bytes([
141141
data[0], data[1], data[2], data[3], data[4], data[5], data[6], data[7],
142142
]),
143-
_ => todo!(),
143+
_ => 0.0,
144144
})
145145
}

apps/desktop/src-tauri/src/camera.rs

Lines changed: 25 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,9 @@ use tokio::{
1717
runtime::Runtime,
1818
sync::{broadcast, oneshot},
1919
task::LocalSet,
20+
time::{Duration, Instant},
2021
};
21-
use tracing::{error, info, trace};
22+
use tracing::{error, info, trace, warn};
2223
use wgpu::{CompositeAlphaMode, SurfaceTexture};
2324

2425
static TOOLBAR_HEIGHT: f32 = 56.0; // also defined in Typescript
@@ -43,9 +44,9 @@ pub enum CameraPreviewShape {
4344

4445
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, Type)]
4546
pub struct CameraPreviewState {
46-
size: f32,
47-
shape: CameraPreviewShape,
48-
mirrored: bool,
47+
pub size: f32,
48+
pub shape: CameraPreviewShape,
49+
pub mirrored: bool,
4950
}
5051

5152
impl Default for CameraPreviewState {
@@ -496,8 +497,23 @@ impl Renderer {
496497
return;
497498
};
498499

500+
let start_time = Instant::now();
501+
let startup_timeout = Duration::from_secs(5);
502+
let mut received_first_frame = false;
503+
499504
let mut state = default_state;
500505
while let Some(event) = loop {
506+
let timeout_remaining = if received_first_frame {
507+
Duration::MAX
508+
} else {
509+
startup_timeout.saturating_sub(start_time.elapsed())
510+
};
511+
512+
if timeout_remaining.is_zero() {
513+
warn!("Camera preview timed out waiting for first frame, closing window");
514+
break None;
515+
}
516+
501517
tokio::select! {
502518
frame = camera_rx.recv_async() => break frame.ok().map(Ok),
503519
result = reconfigure.recv() => {
@@ -507,10 +523,15 @@ impl Renderer {
507523
continue;
508524
}
509525
},
526+
_ = tokio::time::sleep(timeout_remaining) => {
527+
warn!("Camera preview timed out waiting for first frame, closing window");
528+
break None;
529+
}
510530
}
511531
} {
512532
match event {
513533
Ok(frame) => {
534+
received_first_frame = true;
514535
let aspect_ratio = frame.inner.width() as f32 / frame.inner.height() as f32;
515536
self.sync_ratio_uniform_and_resize_window_to_it(&window, &state, aspect_ratio);
516537

0 commit comments

Comments
 (0)