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
42 changes: 28 additions & 14 deletions .github/workflows/rust.yml
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
# Rust Code Quality CI
# Created by Vetcoders (c)2026
#
# NOTE: Full build requires macOS with Swift 6.0 (CoreML, Metal).
# GitHub runners have Swift 5.10, so we only run format checks here.
# Full quality gate (clippy, tests) runs locally via: make check
# Or via pre-commit hooks: make hooks
# Runs on self-hosted macOS runners (Swift 6.0 / CoreML / Metal available).
# format: cargo fmt --check
# quality: cargo clippy -D warnings + cargo test (workspace).
# Full local gate (incl. real-API / heavy e2e tests) still via: make check

name: Rust Quality

Expand Down Expand Up @@ -35,13 +35,27 @@ jobs:
- name: cargo fmt --check
run: cargo fmt --all -- --check

# NOTE: clippy and check disabled - requires macOS + Swift 6.0
# Run locally: make lint
#
# To enable full CI, use a self-hosted macOS runner:
# quality:
# runs-on: [self-hosted, macos, arm64]
# steps:
# - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
# - run: cargo clippy -- -D warnings
# - run: cargo test --lib
quality:
name: Clippy + Tests
runs-on: self-hosted
steps:
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4

- uses: dtolnay/rust-toolchain@4be7066ada62dd38de10e7b70166bc74ed198c30 # stable
with:
components: clippy

- name: cargo clippy --workspace --all-targets -- -D warnings
run: cargo clippy --workspace --all-targets -- -D warnings

# Runs the default (non-#[ignore]) workspace test set.
# CODESCRIBE_DISABLE_KEYCHAIN=1: keychain-backed tests must bypass the
# macOS Keychain (no interactive unlock / signed host on the runner) —
# see core/config/keychain.rs and the Makefile `test` target.
# #[ignore]-gated tests (real LLM APIs, Whisper/STT models, audio devices,
# live SSE) are intentionally NOT run here — they need secrets/hardware
# absent on CI and stay behind `make test` / `make test-e2e-real` locally.
- name: cargo test --workspace
env:
CODESCRIBE_DISABLE_KEYCHAIN: "1"
run: cargo test --workspace
8 changes: 8 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## [Unreleased]

### Added

- **API key liveness probe in Settings → Keys** (PR #50) — per-key **Test** button runs a background probe and shows a result chip (`Key OK` / `Invalid key` / `No credits (check billing)` / `Network error` / `Not set` / `Unsupported`). LLM keys are probed with a minimal generation request rather than an auth-only endpoint, so exhausted billing (`insufficient_quota`) is distinguished from an invalid key.
- **Guided MCP onboarding + reset app data** (PR #52) — fresh installs with no `mcp.json` now get a short explainer with **Set up MCP servers** (deep-links into Settings → Engine) and **Skip for now**, instead of a dead-end wall; Settings → Engine gains a danger-zone **Reset app data…** action with a two-step destructive confirmation and an opt-in checkbox to also remove API keys from the Keychain.

### Changed

- **Public release hygiene** — release packaging, repository metadata, and public-facing docs are being aligned for a current `v0.12.x` public release.
Expand All @@ -15,6 +20,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

### Fixed

- **Legacy fallback threads persisted on AI failure** (PR #51) — when the AI runtime is unavailable, the legacy assistive fallback no longer persists a conversation thread for `Failed`/`Skipped` attempts (previously created repeated "AI Failed" junk threads cluttering the history rail); `Applied`/`AiNoop` outcomes are still persisted as before.
- **MCP setup prompt never appeared** (PR #53) — `probe_mcp_status` now reports a `configured` flag so onboarding can tell "no `mcp.json`" apart from "servers configured," fixing the guided MCP setup prompt from PR #52 that was dead code because the row-count check was always true.
- **MCP setup deep-link did nothing** (PR #54) — the onboarding "Set up MCP servers" action now opens Settings via the SwiftUI `openSettings` environment action instead of a dead AppKit `showSettingsWindow:` selector that has no responder in this accessory (LSUIElement) app.
- **Silero VAD reload leak** — the Silero ONNX session is now compiled once and shared process-wide instead of being rebuilt per recording (which leaked native ORT memory over long sessions).
- **Allocator retention** — freed transient buffers are returned to the OS after each recording (`malloc_zone_pressure_relief` on macOS) instead of inflating the resident footprint across a session.

Expand Down
33 changes: 23 additions & 10 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -264,17 +264,21 @@ test-quick:

test-e2e:
@$(TEST_SETUP); \
set -o pipefail; \
echo "=== E2E Tests (mock) ===" | tee -a "$$LOG"; \
$(ENV_LOAD); $(APPLY_TEST_LLM); \
cargo test e2e --release -- --nocapture 2>&1 | tee -a "$$LOG"; \
cargo test e2e --release -- --nocapture 2>&1 | tee -a "$$LOG"; test_rc=$${PIPESTATUS[0]}; \
if [[ $$test_rc -ne 0 ]]; then exit $$test_rc; fi; \
echo "Done. Log: $$LOG" | tee -a "$$LOG"

test-e2e-real:
@$(TEST_SETUP); \
set -o pipefail; \
echo "=== E2E Tests (real API) ===" | tee -a "$$LOG"; \
echo "Requires: LLM_API_KEY, LLM_ASSISTIVE_API_KEY" | tee -a "$$LOG"; \
$(ENV_LOAD); $(APPLY_TEST_LLM); \
cargo test e2e --release -- --ignored --nocapture 2>&1 | tee -a "$$LOG"; \
cargo test e2e --release -- --ignored --nocapture 2>&1 | tee -a "$$LOG"; test_rc=$${PIPESTATUS[0]}; \
if [[ $$test_rc -ne 0 ]]; then exit $$test_rc; fi; \
echo "Done. Log: $$LOG" | tee -a "$$LOG"

test-sse:
Expand All @@ -284,11 +288,13 @@ test-sse:
TEST_SSE_PROFILE="$(TEST_SSE_PROFILE)" CARGO_BUILD_JOBS="$(TEST_SSE_CARGO_JOBS)" ./scripts/test-sse-preflight.sh 2>&1 | tee -a "$$LOG"; \
$(ENV_LOAD); $(APPLY_TEST_LLM); \
CARGO_BUILD_JOBS="$(TEST_SSE_CARGO_JOBS)" \
cargo test --test e2e_sse_streaming $(TEST_SSE_PROFILE_ARGS) -- --ignored --nocapture 2>&1 | tee -a "$$LOG"; \
cargo test --test e2e_sse_streaming $(TEST_SSE_PROFILE_ARGS) -- --ignored --nocapture 2>&1 | tee -a "$$LOG"; test_rc=$${PIPESTATUS[0]}; \
if [[ $$test_rc -ne 0 ]]; then exit $$test_rc; fi; \
if [[ "$${CODESCRIBE_TEST_SSE_RESPONSES:-0}" == "1" ]]; then \
echo "=== Responses Live Chain/Resume Tests ===" | tee -a "$$LOG"; \
$(ENV_LOAD); CODESCRIBE_E2E_RESPONSES=1 CARGO_BUILD_JOBS="$(TEST_SSE_CARGO_JOBS)" \
cargo test --test e2e_retry_responses -- --nocapture 2>&1 | tee -a "$$LOG"; \
cargo test --test e2e_retry_responses -- --nocapture 2>&1 | tee -a "$$LOG"; test_rc=$${PIPESTATUS[0]}; \
if [[ $$test_rc -ne 0 ]]; then exit $$test_rc; fi; \
else \
echo "Skipping Responses Live Chain/Resume Tests (set CODESCRIBE_TEST_SSE_RESPONSES=1)." | tee -a "$$LOG"; \
fi; \
Expand All @@ -305,25 +311,32 @@ test-sse-heavy:

test-formatting:
@$(TEST_SETUP); \
set -o pipefail; \
echo "=== AI Formatting Tests ===" | tee -a "$$LOG"; \
$(ENV_LOAD); $(APPLY_TEST_LLM); \
cargo test formatting --release -- --nocapture 2>&1 | tee -a "$$LOG"; \
cargo test formatting --release -- --nocapture 2>&1 | tee -a "$$LOG"; test_rc=$${PIPESTATUS[0]}; \
if [[ $$test_rc -ne 0 ]]; then exit $$test_rc; fi; \
echo "Done. Log: $$LOG" | tee -a "$$LOG"

test-all:
@$(TEST_SETUP); \
set -o pipefail; \
echo "=== Full Test Suite ===" | tee -a "$$LOG"; \
$(ENV_LOAD); $(APPLY_TEST_LLM); \
cargo test --workspace --all-targets -- --nocapture 2>&1 | tee -a "$$LOG"; \
cargo test --workspace --all-targets -- --nocapture 2>&1 | tee -a "$$LOG"; test_rc=$${PIPESTATUS[0]}; \
if [[ $$test_rc -ne 0 ]]; then exit $$test_rc; fi; \
echo "=== Ignored / Real API ===" | tee -a "$$LOG"; \
$(ENV_LOAD); $(APPLY_TEST_LLM); \
cargo test --workspace --all-targets -- --ignored --nocapture 2>&1 | tee -a "$$LOG"; \
cargo test --workspace --all-targets -- --ignored --nocapture 2>&1 | tee -a "$$LOG"; test_rc=$${PIPESTATUS[0]}; \
if [[ $$test_rc -ne 0 ]]; then exit $$test_rc; fi; \
echo "=== Full Pipeline (STT) ===" | tee -a "$$LOG"; \
$(ENV_LOAD); CODESCRIBE_E2E_STT=1 \
cargo test --test e2e_full_pipeline -- --nocapture 2>&1 | tee -a "$$LOG"; \
cargo test --test e2e_full_pipeline -- --nocapture 2>&1 | tee -a "$$LOG"; test_rc=$${PIPESTATUS[0]}; \
if [[ $$test_rc -ne 0 ]]; then exit $$test_rc; fi; \
echo "=== SSE Streaming ===" | tee -a "$$LOG"; \
$(ENV_LOAD); $(APPLY_TEST_LLM); \
cargo test e2e_sse --release -- --ignored --nocapture 2>&1 | tee -a "$$LOG"; \
cargo test e2e_sse --release -- --ignored --nocapture 2>&1 | tee -a "$$LOG"; test_rc=$${PIPESTATUS[0]}; \
if [[ $$test_rc -ne 0 ]]; then exit $$test_rc; fi; \
echo "Done. Log: $$LOG" | tee -a "$$LOG"

demo:
Expand All @@ -342,7 +355,7 @@ check:
@echo "=== Format Check (Rust) ==="
@cargo fmt --all -- --check
@echo "=== Format Check (non-Rust) ==="
@npx --yes prettier@2.7.1 --check . --ignore-path .prettierignore --ignore-unknown || true
@npx --yes prettier@2.7.1 --check . --ignore-path .prettierignore --ignore-unknown
@echo "=== Clippy (workspace, all targets) ==="
@cargo clippy --workspace --all-targets -- -D warnings
@echo "=== Semgrep ==="
Expand Down
4 changes: 2 additions & 2 deletions NOTICE
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
CodeScribe Notices
Codescribe Notices
==================

Portions of the account authentication foundation are derived from
Expand All @@ -10,5 +10,5 @@ Derived files:
- core/llm/account_auth/device_code.rs
- core/llm/account_auth/server.rs

The derived portions retain Apache-2.0 attribution. CodeScribe's repository
The derived portions retain Apache-2.0 attribution. Codescribe's repository
license metadata remains authoritative for this project.
66 changes: 56 additions & 10 deletions app/os/clipboard.rs
Original file line number Diff line number Diff line change
Expand Up @@ -414,9 +414,15 @@ mod tests {
fn test_set_and_get_clipboard() {
let _guard = ClipboardTestGuard::capture();
let test_text = "Test clipboard content";
set_clipboard(test_text).expect("Failed to set clipboard");

let retrieved = get_clipboard().expect("Failed to get clipboard");
let Some(()) = skip_if_clipboard_unavailable(set_clipboard(test_text), "set clipboard")
else {
return;
};

let Some(retrieved) = skip_if_clipboard_unavailable(get_clipboard(), "get clipboard")
else {
return;
};
assert_eq!(retrieved, test_text);
}

Expand All @@ -434,10 +440,19 @@ mod tests {
fn test_clipboard_snapshot_capture() {
let _guard = ClipboardTestGuard::capture();
// Set some text
set_clipboard("Test snapshot content").expect("Failed to set clipboard");
let Some(()) = skip_if_clipboard_unavailable(
set_clipboard("Test snapshot content"),
"set snapshot clipboard",
) else {
return;
};

// Capture snapshot
let snapshot = ClipboardSnapshot::capture().expect("Failed to capture snapshot");
let Some(snapshot) =
skip_if_clipboard_unavailable(ClipboardSnapshot::capture(), "capture snapshot")
else {
return;
};

// Should have text
assert!(snapshot.text.is_some());
Expand All @@ -451,22 +466,53 @@ mod tests {
let _guard = ClipboardTestGuard::capture();
// Set original content
let original = "Original clipboard text";
set_clipboard(original).expect("Failed to set clipboard");
let Some(()) =
skip_if_clipboard_unavailable(set_clipboard(original), "set original clipboard")
else {
return;
};

// Capture snapshot
let snapshot = ClipboardSnapshot::capture().expect("Failed to capture snapshot");
let Some(snapshot) =
skip_if_clipboard_unavailable(ClipboardSnapshot::capture(), "capture snapshot")
else {
return;
};

// Change clipboard
set_clipboard("Different text").expect("Failed to change clipboard");
let Some(()) =
skip_if_clipboard_unavailable(set_clipboard("Different text"), "change clipboard")
else {
return;
};

// Restore snapshot
snapshot.restore().expect("Failed to restore snapshot");
let Some(()) = skip_if_clipboard_unavailable(snapshot.restore(), "restore snapshot") else {
return;
};

// Should match original
let restored = get_clipboard().expect("Failed to get clipboard");
let Some(restored) = skip_if_clipboard_unavailable(get_clipboard(), "get clipboard") else {
return;
};
assert_eq!(restored, original);
}

fn skip_if_clipboard_unavailable<T>(result: Result<T>, action: &str) -> Option<T> {
match result {
Ok(value) => Some(value),
Err(error) if is_clipboard_unavailable(&error) => {
eprintln!("skipping clipboard integration test: {action}: {error:#}");
None
}
Err(error) => panic!("{action}: {error:#}"),
}
}

fn is_clipboard_unavailable(error: &anyhow::Error) -> bool {
format!("{error:#}").contains("not supported with the current system configuration")
}

struct ClipboardTestGuard(Option<ClipboardSnapshot>);

impl ClipboardTestGuard {
Expand Down
12 changes: 10 additions & 2 deletions bridge/src/recording.rs
Original file line number Diff line number Diff line change
Expand Up @@ -742,15 +742,23 @@ mod tests {
/// composer UI can never hang indefinitely on a stalled scheduler.
#[test]
fn compose_stop_timeout_scales_and_clamps() {
fn assert_duration_close(actual: Duration, expected: Duration) {
let drift = actual.abs_diff(expected);
assert!(
drift <= Duration::from_micros(1),
"duration drift {drift:?} exceeded tolerance: actual={actual:?}, expected={expected:?}"
);
}

// Short note: floored so a cold commit + tail patch still fits.
assert_eq!(
compose_stop_timeout(Duration::from_secs(3)),
Duration::from_secs(8)
);
// Mid-length: proportional (20s * 0.6 = 12s) inside the band.
assert_eq!(
assert_duration_close(
compose_stop_timeout(Duration::from_secs(20)),
Duration::from_secs(12)
Duration::from_secs(12),
);
// Long note: capped so the UI never waits unboundedly.
assert_eq!(
Expand Down
Loading
Loading