[package]
name = "clips-tray"
version = "0.1.1"
description = "Clips — cross-platform tray app (Tauri 2)"
authors = ["Clips"]
license = "MIT"
edition = "2021"
rust-version = "1.88"

# See https://doc.rust-lang.org/cargo/reference/manifest.html

[lib]
name = "clips_tray_lib"
crate-type = ["lib", "cdylib", "staticlib"]

# Force the dev binary name so macOS shows "Clips" in the Dock / app switcher
# (macOS derives the display name from the executable filename when the app
# is unbundled — e.g. during `tauri dev`). Bundled .app builds read the name
# from `productName` in tauri.conf.json instead.
[[bin]]
name = "Clips"
path = "src/main.rs"

[build-dependencies]
tauri-build = { version = "2", features = [] }

[dependencies]
tauri = { version = "2", features = [
  "devtools",
  "tray-icon",
  "image-png",
  "macos-private-api",
] }
tauri-plugin-shell = "2"
tauri-plugin-global-shortcut = "2"
tauri-plugin-single-instance = "2"
# Registers the `clips://` custom URL scheme so a web "Open desktop app"
# click can launch/focus the running tray app. macOS registration is baked
# into Info.plist at build time from `plugins.deep-link` in tauri.conf.json;
# Windows/Linux register at runtime via `register_all()`.
tauri-plugin-deep-link = "2"
tauri-plugin-updater = "2"
tauri-plugin-process = "2"
tauri-plugin-autostart = "2.5.1"
tauri-plugin-fs = "2.5.1"
# Native macOS / cross-platform desktop notifications. v2.3.x is the
# current latest at the time of writing (verified via `cargo search
# tauri-plugin-notification`). Powers the Granola-style "Meeting starting
# in N min — Join + Record" banners.
tauri-plugin-notification = "2"
# System clipboard writes from Rust (arboard). The share link is copied when a
# recording finishes, at which point the popover webview is usually unfocused —
# `navigator.clipboard.writeText` rejects with `NotAllowedError: Document is not
# focused` in exactly that case, so the write has to happen native-side. v2.3.2
# is the current latest (verified via `cargo info
# tauri-plugin-clipboard-manager`).
tauri-plugin-clipboard-manager = "2.3.2"
serde = { version = "1", features = ["derive"] }
serde_json = "1"
sentry = "0.48.3"
url = "2"
# Used by meetings_watcher.rs to poll the backend on a background tokio
# task. Tauri 2 already pulls reqwest in transitively, but we declare it
# here so the `json` feature is available regardless of dep resolution.
reqwest = { version = "0.12", default-features = false, features = [
  "rustls-tls",
  "json",
] }
tokio = { version = "1", features = ["rt", "rt-multi-thread", "time", "sync"] }
chrono = { version = "0.4", features = ["serde"] }
# Verify the integrity of the Whisper model we download from HuggingFace.
sha2 = "0.10"
# Low-level dup2/open so we can redirect stdout+stderr into a persistent log
# file in release builds (see logfile.rs). Tauri already pulls libc in
# transitively; declaring it here just makes the API available directly.
libc = "0.2"

# macOS-only: raw Objective-C messaging so we can flip NSWindow's sharingType
# to NSWindowSharingNone and hide every overlay window (popover, bubble,
# toolbar, countdown, signin) from screen-capture APIs. Same technique Loom,
# 1Password, and CleanShot use. Tauri already pulls objc2 0.6 in transitively,
# so requesting it here is a no-op in terms of the final dep graph.
[target."cfg(target_os = \"macos\")".dependencies]
core-foundation = "0.10"
core-graphics = "0.25"
objc2 = { version = "0.6", features = ["exception"] }
objc2-app-kit = { version = "0.3", default-features = false, features = [
  "std",
  "NSEvent",
  "block2",
] }
# Grapheme-cluster-aware chunking for voice-dictation Unicode typing in
# terminal apps, so a chunk boundary never splits a multi-scalar emoji/
# combining-mark sequence across two synthetic keyboard events. Already
# present transitively (via keyboard-types) at 1.13.2, the current latest
# minor at the time of writing (verified via `cargo info unicode-segmentation`).
unicode-segmentation = "1.13"
# Native on-device dictation via SFSpeechRecognizer + AVAudioEngine.
# Powers the "browser" voice-dictation provider (free, instant, no API
# key, no server round-trip — same engine WisprFlow uses for offline).
objc2-foundation = { version = "0.3", features = [
  "NSString",
  "NSError",
  "NSLocale",
  "NSURL",
  "NSValue",
  "NSProcessInfo",
] }
objc2-speech = { version = "0.3", features = [
  "SFSpeechRecognizer",
  "SFSpeechRecognitionRequest",
  "SFSpeechRecognitionResult",
  "SFSpeechRecognitionTask",
  "SFTranscription",
  "SFTranscriptionSegment",
  "SFErrors",
] }
objc2-avf-audio = { version = "0.3", features = [
  "AVAudioEngine",
  "AVAudioFormat",
  "AVAudioIONode",
  "AVAudioNode",
  "AVAudioBuffer",
  "AVAudioSession",
  "AVAudioTypes",
  "block2",
  "objc2-core-audio-types",
  "objc2-audio-toolbox",
] }
objc2-audio-toolbox = { version = "0.3.2", features = [
  "AUComponent",
  "AudioComponent",
] }
objc2-core-audio = { version = "0.3.2", features = ["AudioHardware"] }
block2 = "0.6"
# System-audio capture via Apple's ScreenCaptureKit (macOS 13+) and direct
# full-screen MP4 recording via SCRecordingOutput (macOS 15+). v2.0.0 is the
# current latest at the time of writing (verified via `cargo info
# screencapturekit`).
screencapturekit = { version = "2.0.0", features = ["macos_15_0"] }
# AudioBufferList type so we can hand SCK's CMSampleBuffer audio bytes to
# AVAudioPCMBuffer for the speech recognizer.
objc2-core-audio-types = "0.3"
# `metal` builds whisper.cpp's ggml-metal backend and links it in (the sys
# crate's build script embeds the compiled metallib, so no app-bundle/runtime
# asset changes are needed). Without it, whisper.cpp decode runs CPU-only.
# `use_gpu` is still set explicitly per-arch in whisper_speech.rs so Intel
# Macs don't exercise Metal even though the feature is compiled in.
whisper-rs = { version = "0.16.0", features = ["metal"] }
# NOTE: We hand-roll the few EventKit selectors we need via raw `objc2`
# msg_send! in `eventkit.rs` rather than depending on the `objc2-event-kit`
# crate. Its API surface drifts between minor 0.3.x releases (and not
# every version exposes `EKEventStore::eventsMatchingPredicate`); the
# slice we need is small enough that hand-rolling is more durable.

[profile.release]
panic = "abort"
codegen-units = 1
lto = true
opt-level = "s"
strip = true
