diff --git a/.claude/settings.local.json b/.claude/settings.local.json new file mode 100644 index 0000000..74b2e23 --- /dev/null +++ b/.claude/settings.local.json @@ -0,0 +1,14 @@ +{ + "permissions": { + "allow": [ + "Bash(rsync -av --exclude='node_modules' --exclude='target' --exclude='build' --exclude='.git' \"/c/Users/jakea/Obsidian/CORBEL/Projects/Transcriber/kon/\" \"/c/Users/jakea/CORBEL-Projects/kon/\")", + "Bash(cp -r \"/c/Users/jakea/Obsidian/CORBEL/Projects/Transcriber/kon/\"* \"/c/Users/jakea/CORBEL-Projects/kon/\")", + "Bash(cp -r \"/c/Users/jakea/Obsidian/CORBEL/Projects/Transcriber/kon/\".* \"/c/Users/jakea/CORBEL-Projects/kon/\")", + "Bash(cp \"/c/Users/jakea/Obsidian/CORBEL/Projects/Transcriber/kon/vite.config.js\" \"/c/Users/jakea/CORBEL-Projects/kon/vite.config.js\")", + "Bash(cp \"/c/Users/jakea/Obsidian/CORBEL/Projects/Transcriber/kon/.gitignore\" \"/c/Users/jakea/CORBEL-Projects/kon/.gitignore\")", + "Bash(cp -r \"/c/Users/jakea/Obsidian/CORBEL/Projects/Transcriber/kon/.svelte-kit\" \"/c/Users/jakea/CORBEL-Projects/kon/.svelte-kit\")", + "Bash(npm install:*)", + "Bash(npm run:*)" + ] + } +} diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..eddb85b --- /dev/null +++ b/.gitignore @@ -0,0 +1,6 @@ +node_modules/ +target/ +build/ +dist/ +.svelte-kit/ +Cargo.lock diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 0000000..efef861 --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,3 @@ +[workspace] +members = ["src-tauri", "crates/*"] +resolver = "2" diff --git a/crates/ai-formatting/Cargo.toml b/crates/ai-formatting/Cargo.toml new file mode 100644 index 0000000..754a14a --- /dev/null +++ b/crates/ai-formatting/Cargo.toml @@ -0,0 +1,9 @@ +[package] +name = "kon-ai-formatting" +version = "0.1.0" +edition = "2021" +description = "Text post-processing pipeline: filler removal, British English conversion, formatting for Kon" + +[dependencies] +kon-core = { path = "../core" } +regex-lite = "0.1" diff --git a/crates/ai-formatting/src/lib.rs b/crates/ai-formatting/src/lib.rs new file mode 100644 index 0000000..733bb2f --- /dev/null +++ b/crates/ai-formatting/src/lib.rs @@ -0,0 +1,6 @@ +mod llm_client; +pub mod pipeline; +pub mod rule_based; + +pub use pipeline::{post_process_segments, FormatMode, PostProcessOptions}; +pub use rule_based::{format_text, is_hallucination, remove_fillers, to_british_english}; diff --git a/crates/ai-formatting/src/llm_client.rs b/crates/ai-formatting/src/llm_client.rs new file mode 100644 index 0000000..76b710c --- /dev/null +++ b/crates/ai-formatting/src/llm_client.rs @@ -0,0 +1,5 @@ +//! Placeholder for future LLM sidecar integration (e.g., mistral.rs for smart formatting). +//! +//! When implemented, this module will expose a client that sends transcription +//! segments to a local LLM for context-aware punctuation, paragraph splitting, +//! and stylistic cleanup beyond what the rule-based pipeline can achieve. diff --git a/crates/ai-formatting/src/pipeline.rs b/crates/ai-formatting/src/pipeline.rs new file mode 100644 index 0000000..8f24878 --- /dev/null +++ b/crates/ai-formatting/src/pipeline.rs @@ -0,0 +1,119 @@ +use kon_core::constants::SMART_PARAGRAPH_GAP_SECS; +use kon_core::types::Segment; + +use crate::rule_based; + +/// Post-processing options for a transcription pipeline run. +pub struct PostProcessOptions { + pub remove_fillers: bool, + pub british_english: bool, + pub anti_hallucination: bool, + pub format_mode: FormatMode, +} + +/// How aggressively to format the transcript text. +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub enum FormatMode { + Raw, + Clean, + Smart, +} + +impl FormatMode { + pub fn parse(s: &str) -> Self { + match s { + "Clean" => Self::Clean, + "Smart" => Self::Smart, + _ => Self::Raw, + } + } +} + +/// Apply all post-processing steps to a list of segments. +/// Modifies segments in place. Composed from individual pure functions. +pub fn post_process_segments(segments: &mut Vec, options: &PostProcessOptions) { + if options.anti_hallucination { + segments.retain(|seg| !rule_based::is_hallucination(&seg.text)); + } + + for seg in segments.iter_mut() { + if options.remove_fillers { + seg.text = rule_based::remove_fillers(&seg.text); + } + if options.british_english { + seg.text = rule_based::to_british_english(&seg.text); + } + if options.format_mode != FormatMode::Raw { + seg.text = rule_based::format_text(&seg.text); + } + } + + if options.format_mode == FormatMode::Smart && segments.len() > 1 { + for i in (1..segments.len()).rev() { + let gap = segments[i].start - segments[i - 1].end; + if gap > SMART_PARAGRAPH_GAP_SECS { + segments[i].text = format!("\n\n{}", segments[i].text.trim_start()); + } + } + } +} + +#[cfg(test)] +mod tests { + use super::*; + + fn make_segments() -> Vec { + vec![ + Segment { + start: 0.0, + end: 1.0, + text: "um hello world".into(), + }, + Segment { + start: 1.0, + end: 2.0, + text: "[blank_audio]".into(), + }, + Segment { + start: 5.0, + end: 6.0, + text: "organize the color scheme".into(), + }, + ] + } + + #[test] + fn post_process_applies_all_filters() { + let mut segments = make_segments(); + let options = PostProcessOptions { + remove_fillers: true, + british_english: true, + anti_hallucination: true, + format_mode: FormatMode::Clean, + }; + + post_process_segments(&mut segments, &options); + + assert_eq!(segments.len(), 2); + let lower0 = segments[0].text.to_lowercase(); + let lower1 = segments[1].text.to_lowercase(); + assert!(!lower0.contains("um")); + assert!(lower1.contains("organise")); + assert!(lower1.contains("colour")); + } + + #[test] + fn post_process_adds_paragraph_breaks_on_long_pauses() { + let mut segments = make_segments(); + let options = PostProcessOptions { + remove_fillers: false, + british_english: false, + anti_hallucination: false, + format_mode: FormatMode::Smart, + }; + + post_process_segments(&mut segments, &options); + + assert!(segments[2].text.starts_with("\n\n")); + } +} diff --git a/crates/ai-formatting/src/rule_based.rs b/crates/ai-formatting/src/rule_based.rs new file mode 100644 index 0000000..7613260 --- /dev/null +++ b/crates/ai-formatting/src/rule_based.rs @@ -0,0 +1,291 @@ +use std::sync::LazyLock; + +/// Compiled filler word regexes (built once, reused across calls). +/// Uses \b word boundaries instead of lookbehinds (regex-lite does not +/// support lookaround assertions). +static FILLER_REGEXES: LazyLock> = LazyLock::new(|| { + let fillers = [ + "um", + "uh", + "er", + "ah", + "like", + "you know", + "sort of", + "kind of", + "I mean", + "basically", + "actually", + "literally", + ]; + fillers + .iter() + .filter_map(|filler| { + let escaped = regex_lite::escape(filler); + let pattern = format!(r"(?i)\b{escaped}\b[,.]?\s*"); + regex_lite::Regex::new(&pattern).ok() + }) + .collect() +}); + +/// Remove common filler words from transcription text (case-insensitive). +pub fn remove_fillers(text: &str) -> String { + let mut result = text.to_string(); + + for re in FILLER_REGEXES.iter() { + result = re.replace_all(&result, " ").to_string(); + } + + // Collapse runs of whitespace in a single pass. + let mut collapsed = String::with_capacity(result.len()); + let mut prev_space = false; + for ch in result.chars() { + if ch == ' ' { + if !prev_space { + collapsed.push(' '); + } + prev_space = true; + } else { + prev_space = false; + collapsed.push(ch); + } + } + + collapsed.trim().to_string() +} + +/// Replacement pairs for American to British English conversion. +/// +/// All entries are plain base words (no regex metacharacters). The +/// `to_british_english` function wraps every entry with `\b` word +/// boundaries and optional suffix matching automatically. +static BRITISH_REPLACEMENTS: &[(&str, &str)] = &[ + // -ize → -ise (and inflected forms) + ("organize", "organise"), + ("recognize", "recognise"), + ("realize", "realise"), + ("analyze", "analyse"), + ("apologize", "apologise"), + ("authorize", "authorise"), + ("categorize", "categorise"), + ("characterize", "characterise"), + ("customize", "customise"), + ("digitize", "digitise"), + ("emphasize", "emphasise"), + ("finalize", "finalise"), + ("generalize", "generalise"), + ("harmonize", "harmonise"), + ("initialize", "initialise"), + ("maximize", "maximise"), + ("minimize", "minimise"), + ("modernize", "modernise"), + ("normalize", "normalise"), + ("optimize", "optimise"), + ("prioritize", "prioritise"), + ("revolutionize", "revolutionise"), + ("specialize", "specialise"), + ("standardize", "standardise"), + ("summarize", "summarise"), + ("utilize", "utilise"), + // -or → -our + ("color", "colour"), + ("favor", "favour"), + ("honor", "honour"), + ("humor", "humour"), + ("labor", "labour"), + ("neighbor", "neighbour"), + ("behavior", "behaviour"), + // -er → -re + ("center", "centre"), + ("fiber", "fibre"), + ("liter", "litre"), + ("meter", "metre"), + ("theater", "theatre"), + // -ense → -ence + ("defense", "defence"), + ("offense", "offence"), + // Other + ("catalog", "catalogue"), + ("dialog", "dialogue"), +]; + +/// Convert American English spelling to British English (word-boundary aware). +pub fn to_british_english(text: &str) -> String { + let mut result = text.to_string(); + + for (us, uk) in BRITISH_REPLACEMENTS { + // Every entry in BRITISH_REPLACEMENTS is a plain ASCII base word. + // We wrap it with \b boundaries and optional suffix matching here. + let pattern = format!("(?i)\\b{}(?:d|s|r|rs)?\\b", regex_lite::escape(us)); + + if let Ok(re) = regex_lite::Regex::new(&pattern) { + result = re + .replace_all(&result, |caps: ®ex_lite::Captures| { + let Some(m) = caps.get(0) else { + return String::new(); + }; + let matched = m.as_str(); + let base_len = us.len(); + // SAFETY: byte indexing is correct here because both + // the US base word and the suffix characters (d, s, r) + // are guaranteed ASCII by the BRITISH_REPLACEMENTS table. + debug_assert!(us.is_ascii(), "BRITISH_REPLACEMENTS entries must be ASCII"); + debug_assert!(matched.is_ascii(), "matched text expected to be ASCII"); + let suffix = if matched.len() > base_len { + &matched[base_len..] + } else { + "" + }; + let Some(first_char) = matched.chars().next() else { + return String::new(); + }; + if first_char.is_uppercase() { + let mut chars = uk.chars(); + let Some(first_uk) = chars.next() else { + return String::new(); + }; + let upper_first: String = first_uk.to_uppercase().collect(); + format!("{}{}{}", upper_first, chars.collect::(), suffix) + } else { + format!("{uk}{suffix}") + } + }) + .to_string(); + } + } + + result +} + +/// Basic formatting: capitalise sentences, fix spacing, clean punctuation. +pub fn format_text(text: &str) -> String { + if text.is_empty() { + return String::new(); + } + + let mut result = String::with_capacity(text.len()); + let mut capitalise_next = true; + + let chars: Vec = text.chars().collect(); + let mut i = 0; + + while i < chars.len() { + let c = chars[i]; + + if c == ' ' && i + 1 < chars.len() && chars[i + 1] == ' ' { + i += 1; + continue; + } + + if capitalise_next && c.is_alphabetic() { + result.extend(c.to_uppercase()); + capitalise_next = false; + } else { + result.push(c); + } + + if c == '.' || c == '!' || c == '?' { + capitalise_next = true; + } + if c == '\n' { + capitalise_next = true; + } + + i += 1; + } + + result +} + +/// Known hallucination markers that should be filtered from transcriptions. +static HALLUCINATION_MARKERS: &[&str] = &["[blank_audio]", "[music]", "[silence]"]; + +static AUTO_THANKS_PHRASES: &[&str] = &["thank you.", "thanks.", "you.", "thank you for watching."]; + +/// Returns true if a segment's text looks like a hallucination. +pub fn is_hallucination(text: &str) -> bool { + let trimmed = text.trim().to_lowercase(); + if trimmed.is_empty() { + return true; + } + for marker in HALLUCINATION_MARKERS { + if trimmed.contains(marker) { + return true; + } + } + if trimmed.len() < 15 { + for phrase in AUTO_THANKS_PHRASES { + if trimmed == *phrase { + return true; + } + } + } + false +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn remove_fillers_strips_um_and_uh() { + let input = "So um I was thinking uh about this"; + let result = remove_fillers(input); + assert!(!result.contains("um")); + assert!(!result.contains("uh")); + } + + #[test] + fn remove_fillers_preserves_legitimate_words() { + let input = "The umbrella was actually useful"; + let result = remove_fillers(input); + assert!(result.contains("umbrella")); + assert!(result.contains("useful")); + } + + #[test] + fn to_british_english_converts_ize_to_ise() { + assert!(to_british_english("organize").contains("organise")); + assert!(to_british_english("realize").contains("realise")); + } + + #[test] + fn to_british_english_preserves_case() { + let result = to_british_english("Organize the files"); + assert!(result.starts_with("Organise")); + } + + #[test] + fn to_british_english_handles_colour() { + assert!(to_british_english("the color is red").contains("colour")); + } + + #[test] + fn format_text_capitalises_after_full_stops() { + let result = format_text("hello world. this is a test"); + assert!(result.starts_with('H')); + assert!(result.contains(". T")); + } + + #[test] + fn format_text_handles_empty_string() { + assert_eq!(format_text(""), ""); + } + + #[test] + fn is_hallucination_detects_blank_audio() { + assert!(is_hallucination("[blank_audio]")); + assert!(is_hallucination(" [music] ")); + } + + #[test] + fn is_hallucination_detects_auto_thanks() { + assert!(is_hallucination("Thank you.")); + assert!(is_hallucination("thanks.")); + } + + #[test] + fn is_hallucination_allows_real_text() { + assert!(!is_hallucination("The meeting is at three o'clock.")); + } +} diff --git a/crates/audio/Cargo.toml b/crates/audio/Cargo.toml new file mode 100644 index 0000000..63288e8 --- /dev/null +++ b/crates/audio/Cargo.toml @@ -0,0 +1,27 @@ +[package] +name = "kon-audio" +version = "0.1.0" +edition = "2021" +description = "Audio capture (cpal), VAD, resampling (rubato), file decoding (symphonia), WAV I/O (hound) for Kon" + +[dependencies] +kon-core = { path = "../core" } + +# Microphone capture +cpal = "0.17" + +# Voice activity detection — deferred until ort version conflict between +# VAD crates (ort rc.10) and transcribe-rs (ort rc.12) is resolved upstream. +# silero-vad-rust = { version = "6", default-features = false } + +# High-quality resampling (sinc interpolation) +rubato = "0.15" + +# WAV file I/O +hound = "3.5" + +# Audio file decoding (mp3, aac, flac, wav, ogg, etc.) +symphonia = { version = "0.5", features = ["mp3", "aac", "flac", "pcm", "vorbis", "wav", "ogg", "isomp4"] } + +# Async runtime for threading +tokio = { version = "1", features = ["rt", "sync"] } diff --git a/crates/audio/src/capture.rs b/crates/audio/src/capture.rs new file mode 100644 index 0000000..94abcc8 --- /dev/null +++ b/crates/audio/src/capture.rs @@ -0,0 +1,75 @@ +use std::sync::mpsc; + +use cpal::traits::{DeviceTrait, HostTrait, StreamTrait}; + +use kon_core::error::{KonError, Result}; + +/// A chunk of captured audio from the microphone. +pub struct AudioChunk { + pub samples: Vec, + pub sample_rate: u32, + pub channels: u16, +} + +/// Manages microphone capture via cpal. +/// Call `start()` to begin capturing, which returns a receiver for audio chunks. +/// Call `stop()` to end the stream. +pub struct MicrophoneCapture { + stream: Option, +} + +impl MicrophoneCapture { + /// Start capturing audio from the default input device. + /// Returns a receiver that yields AudioChunks as they arrive. + pub fn start() -> Result<(Self, mpsc::Receiver)> { + let host = cpal::default_host(); + let device = host.default_input_device().ok_or_else(|| { + KonError::AudioCaptureFailed("No input device found".into()) + })?; + + let config = device.default_input_config().map_err(|e| { + KonError::AudioCaptureFailed(format!("No input config: {e}")) + })?; + + let sample_rate = config.sample_rate(); + let channels = config.channels() as u16; + + let (tx, rx) = mpsc::channel::(); + + let stream = device + .build_input_stream( + &config.into(), + move |data: &[f32], _info: &cpal::InputCallbackInfo| { + let _ = tx.send(AudioChunk { + samples: data.to_vec(), + sample_rate, + channels, + }); + }, + |err| eprintln!("audio capture error: {err}"), + None, + ) + .map_err(|e| { + KonError::AudioCaptureFailed(format!("Build stream failed: {e}")) + })?; + + stream.play().map_err(|e| { + KonError::AudioCaptureFailed(format!("Stream play failed: {e}")) + })?; + + Ok((Self { stream: Some(stream) }, rx)) + } + + /// Stop capturing audio. + pub fn stop(&mut self) { + if let Some(stream) = self.stream.take() { + let _ = stream.pause(); + } + } +} + +impl Drop for MicrophoneCapture { + fn drop(&mut self) { + self.stop(); + } +} diff --git a/crates/audio/src/concurrency.rs b/crates/audio/src/concurrency.rs new file mode 100644 index 0000000..ce3d4e2 --- /dev/null +++ b/crates/audio/src/concurrency.rs @@ -0,0 +1,19 @@ +use std::path::Path; + +use kon_core::error::Result; +use kon_core::types::AudioSamples; + +use crate::decode::decode_audio_file; +use crate::resample::resample_to_16khz; + +/// Decode and resample an audio file on a blocking thread. +/// Returns 16kHz mono AudioSamples ready for transcription. +pub async fn decode_and_resample(path: &Path) -> Result { + let path = path.to_path_buf(); + tokio::task::spawn_blocking(move || { + let audio = decode_audio_file(&path)?; + resample_to_16khz(&audio) + }) + .await + .map_err(|e| kon_core::error::KonError::AudioDecodeFailed(format!("Task join error: {e}")))? +} diff --git a/crates/audio/src/decode.rs b/crates/audio/src/decode.rs new file mode 100644 index 0000000..5d08285 --- /dev/null +++ b/crates/audio/src/decode.rs @@ -0,0 +1,104 @@ +use std::fs::File; +use std::path::Path; + +use symphonia::core::audio::SampleBuffer; +use symphonia::core::codecs::DecoderOptions; +use symphonia::core::formats::FormatOptions; +use symphonia::core::io::MediaSourceStream; +use symphonia::core::meta::MetadataOptions; +use symphonia::core::probe::Hint; + +use kon_core::error::{KonError, Result}; +use kon_core::types::AudioSamples; + +/// Decode an audio file to mono f32 PCM samples. +/// Supports all formats symphonia handles: mp3, aac, flac, wav, ogg, etc. +pub fn decode_audio_file(path: &Path) -> Result { + let file = File::open(path) + .map_err(|e| KonError::AudioDecodeFailed(format!("Cannot open file: {e}")))?; + let mss = MediaSourceStream::new(Box::new(file), Default::default()); + + let mut hint = Hint::new(); + if let Some(ext) = path.extension().and_then(|e| e.to_str()) { + hint.with_extension(ext); + } + + let probed = symphonia::default::get_probe() + .format(&hint, mss, &FormatOptions::default(), &MetadataOptions::default()) + .map_err(|e| KonError::AudioDecodeFailed(format!("Unsupported format: {e}")))?; + + let mut format = probed.format; + + let track = format + .default_track() + .ok_or_else(|| KonError::AudioDecodeFailed("No audio track found".into()))?; + let sample_rate = track + .codec_params + .sample_rate + .ok_or_else(|| KonError::AudioDecodeFailed("Unknown sample rate".into()))?; + + if sample_rate == 0 { + return Err(KonError::AudioDecodeFailed("Invalid sample rate: 0".into())); + } + + let track_id = track.id; + + let mut decoder = symphonia::default::get_codecs() + .make(&track.codec_params, &DecoderOptions::default()) + .map_err(|e| KonError::AudioDecodeFailed(format!("Codec error: {e}")))?; + + let mut samples: Vec = Vec::new(); + let mut decode_errors = 0u32; + + loop { + let packet = match format.next_packet() { + Ok(p) => p, + Err(symphonia::core::errors::Error::IoError(ref e)) + if e.kind() == std::io::ErrorKind::UnexpectedEof => + { + break; + } + Err(symphonia::core::errors::Error::ResetRequired) => break, + Err(_) => break, + }; + + if packet.track_id() != track_id { + continue; + } + + let decoded = match decoder.decode(&packet) { + Ok(d) => d, + Err(_) => { + decode_errors += 1; + continue; + } + }; + + let spec = *decoded.spec(); + let channels = spec.channels.count(); + let mut sample_buf = + SampleBuffer::::new(decoded.capacity() as u64, spec); + sample_buf.copy_interleaved_ref(decoded); + + let buf = sample_buf.samples(); + if channels == 1 { + samples.extend_from_slice(buf); + } else { + for chunk in buf.chunks(channels) { + let sum: f32 = chunk.iter().sum(); + samples.push(sum / channels as f32); + } + } + } + + if samples.is_empty() { + if decode_errors > 0 { + return Err(KonError::AudioDecodeFailed(format!( + "No audio decoded ({decode_errors} packets failed — file may be corrupt)" + ))); + } + return Err(KonError::AudioDecodeFailed("No audio data decoded".into())); + } + + Ok(AudioSamples::new(samples, sample_rate, 1)) +} diff --git a/crates/audio/src/lib.rs b/crates/audio/src/lib.rs new file mode 100644 index 0000000..385d7b4 --- /dev/null +++ b/crates/audio/src/lib.rs @@ -0,0 +1,13 @@ +pub mod capture; +pub mod concurrency; +pub mod decode; +pub mod resample; +pub mod vad; +pub mod wav; + +pub use capture::{AudioChunk, MicrophoneCapture}; +pub use concurrency::decode_and_resample; +pub use decode::decode_audio_file; +pub use resample::resample_to_16khz; +pub use vad::SpeechDetector; +pub use wav::{read_wav, write_wav}; diff --git a/crates/audio/src/resample.rs b/crates/audio/src/resample.rs new file mode 100644 index 0000000..97a0d22 --- /dev/null +++ b/crates/audio/src/resample.rs @@ -0,0 +1,105 @@ +use rubato::{SincFixedIn, SincInterpolationParameters, SincInterpolationType, Resampler, WindowFunction}; + +use kon_core::constants::WHISPER_SAMPLE_RATE; +use kon_core::error::{KonError, Result}; +use kon_core::types::AudioSamples; + +/// Resample audio to 16kHz mono using sinc interpolation (rubato). +/// Returns a new AudioSamples at the target sample rate. +pub fn resample_to_16khz(audio: &AudioSamples) -> Result { + let from_rate = audio.sample_rate(); + let target_rate = WHISPER_SAMPLE_RATE; + + if from_rate == target_rate { + return Ok(AudioSamples::mono_16khz(audio.samples().to_vec())); + } + + if from_rate == 0 { + return Err(KonError::AudioDecodeFailed( + "Cannot resample: source rate is 0".into(), + )); + } + + let ratio = target_rate as f64 / from_rate as f64; + let chunk_size = 1024; + + let params = SincInterpolationParameters { + sinc_len: 256, + f_cutoff: 0.95, + oversampling_factor: 128, + interpolation: SincInterpolationType::Cubic, + window: WindowFunction::Blackman, + }; + + let mut resampler = SincFixedIn::::new( + ratio, + 1.1, + params, + chunk_size, + 1, // mono + ) + .map_err(|e| { + KonError::AudioDecodeFailed(format!("Resampler init failed: {e}")) + })?; + + let samples = audio.samples(); + let mut output_samples: Vec = Vec::new(); + + let mut offset = 0; + while offset < samples.len() { + let end = (offset + chunk_size).min(samples.len()); + let mut chunk = samples[offset..end].to_vec(); + + if chunk.len() < chunk_size { + chunk.resize(chunk_size, 0.0); + } + + let input = vec![chunk]; + let result = resampler.process(&input, None).map_err(|e| { + KonError::AudioDecodeFailed(format!("Resample failed: {e}")) + })?; + + if !result.is_empty() && !result[0].is_empty() { + output_samples.extend_from_slice(&result[0]); + } + + offset += chunk_size; + } + + // Trim to expected length (padding may have added extra samples) + let expected_len = (samples.len() as f64 * ratio) as usize; + output_samples.truncate(expected_len); + + Ok(AudioSamples::mono_16khz(output_samples)) +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn resample_passthrough_at_16khz() { + let input = AudioSamples::mono_16khz(vec![0.1, 0.2, 0.3]); + let output = resample_to_16khz(&input).unwrap(); + assert_eq!(output.sample_rate(), 16000); + assert_eq!(output.samples().len(), 3); + } + + #[test] + fn resample_preserves_approximate_duration() { + let rate = 48000; + let duration_secs = 1.0; + let num_samples = (rate as f64 * duration_secs) as usize; + let samples: Vec = + (0..num_samples).map(|i| (i as f32 * 0.001).sin()).collect(); + + let input = AudioSamples::new(samples, rate, 1); + let output = resample_to_16khz(&input).unwrap(); + + let output_duration = output.samples().len() as f64 / 16000.0; + assert!( + (output_duration - duration_secs).abs() < 0.1, + "Duration mismatch: expected ~{duration_secs}s, got {output_duration}s" + ); + } +} diff --git a/crates/audio/src/vad.rs b/crates/audio/src/vad.rs new file mode 100644 index 0000000..6001a8a --- /dev/null +++ b/crates/audio/src/vad.rs @@ -0,0 +1,35 @@ +// Voice Activity Detection — stubbed. +// +// Both `voice_activity_detector` and `silero-vad-rust` pin ort 2.0.0-rc.10 +// which conflicts with transcribe-rs requiring ort 2.0.0-rc.12. +// When the ort ecosystem aligns (likely at 2.0.0 stable), add Silero VAD here. +// +// For now, all audio is treated as speech. This matches v0.2 behaviour +// (no VAD) and doesn't affect core functionality. + +use kon_core::constants::VAD_SPEECH_THRESHOLD; + +/// Stub speech detector. Treats all audio as speech. +#[derive(Default)] +pub struct SpeechDetector { + threshold: f64, +} + +impl SpeechDetector { + pub fn new() -> Self { + Self { + threshold: VAD_SPEECH_THRESHOLD, + } + } + + /// Always returns true (no VAD filtering until ort conflict resolved). + pub fn is_speech(&self, _samples: &[f32]) -> bool { + true + } + + pub fn threshold(&self) -> f64 { + self.threshold + } + + pub fn reset(&mut self) {} +} diff --git a/crates/audio/src/wav.rs b/crates/audio/src/wav.rs new file mode 100644 index 0000000..eed82a7 --- /dev/null +++ b/crates/audio/src/wav.rs @@ -0,0 +1,83 @@ +use std::path::Path; + +use kon_core::error::{KonError, Result}; +use kon_core::types::AudioSamples; + +/// Write f32 PCM samples to a 16-bit WAV file. +pub fn write_wav(path: &Path, audio: &AudioSamples) -> Result<()> { + let spec = hound::WavSpec { + channels: audio.channels(), + sample_rate: audio.sample_rate(), + bits_per_sample: 16, + sample_format: hound::SampleFormat::Int, + }; + + let mut writer = hound::WavWriter::create(path, spec) + .map_err(|e| KonError::Io(std::io::Error::other(format!("WAV create failed: {e}"))))?; + + for &sample in audio.samples() { + let clamped = sample.clamp(-1.0, 1.0); + let int_sample = (clamped * i16::MAX as f32) as i16; + writer + .write_sample(int_sample) + .map_err(|e| KonError::Io(std::io::Error::other(format!("WAV write failed: {e}"))))?; + } + + writer + .finalize() + .map_err(|e| KonError::Io(std::io::Error::other(format!("WAV finalize failed: {e}"))))?; + + Ok(()) +} + +/// Read a WAV file to f32 PCM AudioSamples. +pub fn read_wav(path: &Path) -> Result { + let reader = hound::WavReader::open(path) + .map_err(|e| KonError::AudioDecodeFailed(format!("WAV open failed: {e}")))?; + + let spec = reader.spec(); + let sample_rate = spec.sample_rate; + let channels = spec.channels; + + let samples: Vec = match spec.sample_format { + hound::SampleFormat::Int => reader + .into_samples::() + .filter_map(|s| s.ok()) + .map(|s| s as f32 / (1 << (spec.bits_per_sample - 1)) as f32) + .collect(), + hound::SampleFormat::Float => reader + .into_samples::() + .filter_map(|s| s.ok()) + .collect(), + }; + + Ok(AudioSamples::new(samples, sample_rate, channels)) +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn wav_roundtrip() { + let temp_dir = std::env::temp_dir(); + let path = temp_dir.join("kon_test_roundtrip.wav"); + + let original = AudioSamples::mono_16khz(vec![0.0, 0.5, -0.5, 0.25, -0.25]); + write_wav(&path, &original).unwrap(); + + let loaded = read_wav(&path).unwrap(); + assert_eq!(loaded.sample_rate(), 16000); + assert_eq!(loaded.samples().len(), 5); + + // 16-bit quantisation introduces small error + for (a, b) in original.samples().iter().zip(loaded.samples().iter()) { + assert!( + (a - b).abs() < 0.001, + "Sample mismatch: original={a}, loaded={b}" + ); + } + + std::fs::remove_file(&path).ok(); + } +} diff --git a/crates/cloud-providers/Cargo.toml b/crates/cloud-providers/Cargo.toml new file mode 100644 index 0000000..b14cc42 --- /dev/null +++ b/crates/cloud-providers/Cargo.toml @@ -0,0 +1,8 @@ +[package] +name = "kon-cloud-providers" +version = "0.1.0" +edition = "2021" +description = "BYOK cloud STT provider stubs and API key storage for Kon" + +[dependencies] +kon-core = { path = "../core" } diff --git a/crates/cloud-providers/src/keystore.rs b/crates/cloud-providers/src/keystore.rs new file mode 100644 index 0000000..871565c --- /dev/null +++ b/crates/cloud-providers/src/keystore.rs @@ -0,0 +1,29 @@ +/// Store an API key in the OS keychain. +/// +/// Stub implementation using environment variables until the `keyring` crate is +/// added. Keys are only held in-process and lost on exit. +/// +/// # Safety note +/// `std::env::set_var` is deprecated in Rust 2024 edition and is **not** +/// thread-safe — mutating the environment while other threads read it is +/// undefined behaviour. This is acceptable during single-threaded app init +/// but must not be called from async/multi-threaded contexts. +/// +/// TODO: Replace with the `keyring` crate (or platform-native credential +/// storage) so keys persist across sessions and are accessed safely. +#[allow(deprecated)] // set_var deprecated in Rust 2024 edition +pub fn store_api_key(provider: &str, key: &str) { + // SAFETY: Only safe when called from a single-threaded context (e.g. app + // initialisation). See doc comment above. + std::env::set_var(format!("KON_API_KEY_{}", provider.to_uppercase()), key); +} + +/// Retrieve an API key from the OS keychain. +/// +/// Stub implementation using environment variables until the `keyring` crate is +/// added. Returns `None` if no key has been stored this session. +/// +/// TODO: Replace with the `keyring` crate alongside `store_api_key`. +pub fn retrieve_api_key(provider: &str) -> Option { + std::env::var(format!("KON_API_KEY_{}", provider.to_uppercase())).ok() +} diff --git a/crates/cloud-providers/src/lib.rs b/crates/cloud-providers/src/lib.rs new file mode 100644 index 0000000..a22aff2 --- /dev/null +++ b/crates/cloud-providers/src/lib.rs @@ -0,0 +1,3 @@ +pub mod keystore; + +pub use keystore::{retrieve_api_key, store_api_key}; diff --git a/crates/core/Cargo.toml b/crates/core/Cargo.toml new file mode 100644 index 0000000..b1d3d51 --- /dev/null +++ b/crates/core/Cargo.toml @@ -0,0 +1,12 @@ +[package] +name = "kon-core" +version = "0.1.0" +edition = "2021" +description = "Core types, constants, traits, hardware detection, and model registry for Kon" + +[dependencies] +serde = { version = "1", features = ["derive"] } +serde_json = "1" +thiserror = "2" +sysinfo = "0.35" +async-trait = "0.1" diff --git a/crates/core/src/constants.rs b/crates/core/src/constants.rs new file mode 100644 index 0000000..ada8903 --- /dev/null +++ b/crates/core/src/constants.rs @@ -0,0 +1,49 @@ +/// Audio pipeline constants. +pub const WHISPER_SAMPLE_RATE: u32 = 16_000; +pub const WHISPER_CHANNELS: u16 = 1; + +/// Parakeet mel spectrogram constants. +pub const PARAKEET_N_FFT: usize = 512; +pub const PARAKEET_HOP_LENGTH: usize = 160; +pub const PARAKEET_WIN_LENGTH: usize = 400; +pub const PARAKEET_N_MELS: usize = 80; +pub const PARAKEET_PRE_EMPHASIS: f32 = 0.97; +pub const PARAKEET_BLANK_TOKEN: usize = 1024; +pub const PARAKEET_LOG_GUARD: f32 = 5.960_464_5e-8; // 2^-24 + +/// Chunk timing for live transcription. +pub const CHUNK_INTERVAL_MS: u64 = 3000; +pub const MIN_CHUNK_SAMPLES: usize = 8000; + +/// Post-processing thresholds. +pub const SMART_PARAGRAPH_GAP_SECS: f64 = 2.0; + +/// Thread count for inference. Leaves headroom for the UI thread. +pub const MIN_INFERENCE_THREADS: usize = 4; + +/// History limits. +pub const HISTORY_MAX_ENTRIES: usize = 100; + +/// RAM thresholds for model recommendations (in GB). +pub const RAM_MINIMUM_FOR_LOCAL_STT: f64 = 2.0; +pub const RAM_THRESHOLD_LIGHTWEIGHT: f64 = 4.0; +pub const RAM_THRESHOLD_STANDARD: f64 = 8.0; +pub const RAM_THRESHOLD_COMFORTABLE: f64 = 16.0; + +/// VAD configuration defaults. +pub const VAD_SPEECH_THRESHOLD: f64 = 0.5; +pub const VAD_MIN_SPEECH_DURATION_MS: u32 = 250; +pub const VAD_MAX_SPEECH_DURATION_S: u32 = 30; +pub const VAD_MIN_SILENCE_DURATION_MS: u32 = 300; +pub const VAD_SPEECH_PAD_MS: u32 = 100; + +/// Model download chunk size for progress reporting. +pub const DOWNLOAD_CHUNK_BYTES: usize = 65_536; + +/// Inference thread count based on available parallelism. +pub fn inference_thread_count() -> usize { + std::thread::available_parallelism() + .map(|p| p.get().saturating_sub(1)) + .unwrap_or(MIN_INFERENCE_THREADS) + .max(MIN_INFERENCE_THREADS) +} diff --git a/crates/core/src/error.rs b/crates/core/src/error.rs new file mode 100644 index 0000000..d0e4db3 --- /dev/null +++ b/crates/core/src/error.rs @@ -0,0 +1,60 @@ +use std::path::PathBuf; + +use serde::Serialize; + +use crate::types::ModelId; + +/// Structured error type for Kon. +/// +/// Implements `Serialize` so errors can be sent to the frontend as +/// structured JSON rather than opaque strings. +#[derive(Debug, thiserror::Error, Serialize)] +pub enum KonError { + #[error("model not found: {0}")] + ModelNotFound(ModelId), + + #[error("model not downloaded: {0}")] + ModelNotDownloaded(ModelId), + + #[error("engine not loaded: call load_model first")] + EngineNotLoaded, + + #[error("transcription failed: {0}")] + TranscriptionFailed(String), + + #[error("audio decode failed: {0}")] + AudioDecodeFailed(String), + + #[error("audio capture failed: {0}")] + AudioCaptureFailed(String), + + #[error("model download failed: {0}")] + DownloadFailed(String), + + #[error("file not found: {}", .0.display())] + FileNotFound(PathBuf), + + #[error("storage error: {0}")] + StorageError(String), + + #[error("io error: {0}")] + Io( + #[from] + #[serde(serialize_with = "serialize_io_error")] + std::io::Error, + ), + + #[error("{0}")] + Other(String), +} + +/// Serialises `std::io::Error` as its display string, since it does +/// not implement `Serialize` natively. +fn serialize_io_error( + err: &std::io::Error, + s: S, +) -> std::result::Result { + s.serialize_str(&err.to_string()) +} + +pub type Result = std::result::Result; diff --git a/crates/core/src/hardware.rs b/crates/core/src/hardware.rs new file mode 100644 index 0000000..23df6a2 --- /dev/null +++ b/crates/core/src/hardware.rs @@ -0,0 +1,105 @@ +use sysinfo::System; + +use crate::types::Megabytes; + +/// Detected system capabilities. +#[derive(Debug, Clone)] +pub struct SystemProfile { + pub ram: Megabytes, + pub cpu: CpuInfo, + pub gpu: Option, + pub os: Os, +} + +#[derive(Debug, Clone)] +pub struct CpuInfo { + pub logical_processors: usize, + pub brand: String, +} + +#[derive(Debug, Clone)] +pub struct GpuInfo { + pub vendor: GpuVendor, + pub vram: Megabytes, + pub acceleration: GpuAcceleration, +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub enum GpuVendor { + Nvidia, + Amd, + Intel, + Apple, + Unknown, +} + +#[derive(Debug, Clone)] +pub struct GpuAcceleration { + pub cuda: bool, + pub metal: bool, + pub vulkan: bool, +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub enum Os { + Windows, + Linux, + MacOs, + Ios, + Android, +} + +/// Probes RAM from a shared `System` instance. +fn probe_ram_from(sys: &System) -> Megabytes { + let total_bytes = sys.total_memory(); + Megabytes(total_bytes / (1024 * 1024)) +} + +/// Probes CPU info from a shared `System` instance. +fn probe_cpu_from(sys: &System) -> CpuInfo { + CpuInfo { + logical_processors: sys.cpus().len(), + brand: sys + .cpus() + .first() + .map(|c| c.brand().to_string()) + .unwrap_or_default(), + } +} + +pub fn probe_gpu() -> Option { + // GPU detection via wgpu or platform-specific APIs. + // Placeholder: returns None until wgpu or nvml integration is added. + None +} + +pub fn probe_os() -> Os { + #[cfg(target_os = "windows")] + return Os::Windows; + #[cfg(target_os = "linux")] + return Os::Linux; + #[cfg(target_os = "macos")] + return Os::MacOs; + #[cfg(target_os = "ios")] + return Os::Ios; + #[cfg(target_os = "android")] + return Os::Android; + + // Fallback for unsupported targets — treat as Linux since + // most exotic/embedded targets are Unix-like. + #[allow(unreachable_code)] + Os::Linux +} + +/// Composes the individual probes using a single `System` snapshot. +/// `System::new_all()` is expensive — calling it once rather than +/// per-probe avoids redundant OS queries. +pub fn probe_system() -> SystemProfile { + let sys = System::new_all(); + SystemProfile { + ram: probe_ram_from(&sys), + cpu: probe_cpu_from(&sys), + gpu: probe_gpu(), + os: probe_os(), + } +} diff --git a/crates/core/src/lib.rs b/crates/core/src/lib.rs new file mode 100644 index 0000000..9084835 --- /dev/null +++ b/crates/core/src/lib.rs @@ -0,0 +1,13 @@ +pub mod constants; +pub mod error; +pub mod hardware; +pub mod model_registry; +pub mod providers; +pub mod recommendation; +pub mod types; + +pub use error::{KonError, Result}; +pub use types::{ + AudioSamples, DownloadProgress, EngineName, Megabytes, ModelId, Segment, + Transcript, TranscriptMetadata, TranscriptionOptions, +}; diff --git a/crates/core/src/model_registry.rs b/crates/core/src/model_registry.rs new file mode 100644 index 0000000..e8ace94 --- /dev/null +++ b/crates/core/src/model_registry.rs @@ -0,0 +1,166 @@ +use std::sync::LazyLock; + +use crate::types::{Megabytes, ModelId}; + +/// Which inference backend a model uses. +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub enum Engine { + Whisper, + Parakeet, + Moonshine, +} + +/// Qualitative speed classification. +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub enum SpeedTier { + Instant, + Fast, + Moderate, + Slow, +} + +/// Qualitative accuracy classification. +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub enum AccuracyTier { + Excellent, + Great, + Good, +} + +/// Language support scope. +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub enum LanguageSupport { + EnglishOnly, + Multilingual(u16), +} + +/// File required for a model download. +#[derive(Debug, Clone)] +pub struct ModelFile { + pub filename: &'static str, + pub url: &'static str, + pub size: Megabytes, +} + +/// All metadata for a single downloadable model. +/// This is pure data — no scoring logic lives here. +#[derive(Debug, Clone)] +pub struct ModelEntry { + pub id: ModelId, + pub engine: Engine, + pub display_name: &'static str, + pub disk_size: Megabytes, + pub ram_required: Megabytes, + pub speed_tier: SpeedTier, + pub accuracy_tier: AccuracyTier, + pub languages: LanguageSupport, + pub files: Vec, + pub description: &'static str, +} + +static ALL_MODELS: LazyLock> = LazyLock::new(|| { + vec![ + ModelEntry { + id: ModelId::new("parakeet-ctc-0.6b-int8"), + engine: Engine::Parakeet, + display_name: "Parakeet CTC 0.6B (int8)", + disk_size: Megabytes(613), + ram_required: Megabytes(600), + speed_tier: SpeedTier::Instant, + accuracy_tier: AccuracyTier::Great, + languages: LanguageSupport::EnglishOnly, + files: vec![ + ModelFile { + filename: "encoder-model.onnx", + url: "https://huggingface.co/onnx-community/parakeet-ctc-0.6b-ONNX/resolve/main/onnx/model_int8.onnx", + size: Megabytes(1), + }, + ModelFile { + filename: "model_int8.onnx_data", + url: "https://huggingface.co/onnx-community/parakeet-ctc-0.6b-ONNX/resolve/main/onnx/model_int8.onnx_data", + size: Megabytes(611), + }, + ModelFile { + filename: "tokenizer.json", + url: "https://huggingface.co/onnx-community/parakeet-ctc-0.6b-ONNX/resolve/main/tokenizer.json", + size: Megabytes(1), + }, + ], + description: "Fastest local model — near-instant transcription", + }, + ModelEntry { + id: ModelId::new("whisper-tiny-en"), + engine: Engine::Whisper, + display_name: "Whisper Tiny (English)", + disk_size: Megabytes(75), + ram_required: Megabytes(390), + speed_tier: SpeedTier::Fast, + accuracy_tier: AccuracyTier::Good, + languages: LanguageSupport::EnglishOnly, + files: vec![ModelFile { + filename: "ggml-tiny.en.bin", + url: "https://huggingface.co/ggerganov/whisper.cpp/resolve/main/ggml-tiny.en.bin", + size: Megabytes(75), + }], + description: "Bundled with app — works instantly", + }, + ModelEntry { + id: ModelId::new("whisper-base-en"), + engine: Engine::Whisper, + display_name: "Whisper Base (English)", + disk_size: Megabytes(142), + ram_required: Megabytes(500), + speed_tier: SpeedTier::Fast, + accuracy_tier: AccuracyTier::Good, + languages: LanguageSupport::EnglishOnly, + files: vec![ModelFile { + filename: "ggml-base.en.bin", + url: "https://huggingface.co/ggerganov/whisper.cpp/resolve/main/ggml-base.en.bin", + size: Megabytes(142), + }], + description: "Good balance of speed and accuracy", + }, + ModelEntry { + id: ModelId::new("whisper-small-en"), + engine: Engine::Whisper, + display_name: "Whisper Small (English)", + disk_size: Megabytes(466), + ram_required: Megabytes(1024), + speed_tier: SpeedTier::Moderate, + accuracy_tier: AccuracyTier::Great, + languages: LanguageSupport::EnglishOnly, + files: vec![ModelFile { + filename: "ggml-small.en.bin", + url: "https://huggingface.co/ggerganov/whisper.cpp/resolve/main/ggml-small.en.bin", + size: Megabytes(466), + }], + description: "Accuracy-first English transcription", + }, + ModelEntry { + id: ModelId::new("whisper-medium-en"), + engine: Engine::Whisper, + display_name: "Whisper Medium (English)", + disk_size: Megabytes(1500), + ram_required: Megabytes(2600), + speed_tier: SpeedTier::Slow, + accuracy_tier: AccuracyTier::Excellent, + languages: LanguageSupport::EnglishOnly, + files: vec![ModelFile { + filename: "ggml-medium.en.bin", + url: "https://huggingface.co/ggerganov/whisper.cpp/resolve/main/ggml-medium.en.bin", + size: Megabytes(1500), + }], + description: "Best Whisper accuracy — needs 4+ GB RAM", + }, + ] +}); + +/// Returns all known models. Pure data, no scoring. +pub fn all_models() -> &'static [ModelEntry] { + &ALL_MODELS +} + +/// Find a model by its ID. +pub fn find_model(id: &ModelId) -> Option<&'static ModelEntry> { + ALL_MODELS.iter().find(|m| &m.id == id) +} diff --git a/crates/core/src/providers.rs b/crates/core/src/providers.rs new file mode 100644 index 0000000..0307c58 --- /dev/null +++ b/crates/core/src/providers.rs @@ -0,0 +1,40 @@ +use std::sync::Arc; + +use async_trait::async_trait; + +use crate::error::Result; +use crate::types::{AudioSamples, EngineName, Transcript, TranscriptionOptions}; + +/// Any speech-to-text engine implements this trait. +/// Base types know nothing about their derivatives. +#[async_trait] +pub trait SpeechToText: Send + Sync { + async fn transcribe( + &self, + audio: AudioSamples, + options: &TranscriptionOptions, + ) -> Result; + + fn name(&self) -> &EngineName; + + fn is_available(&self) -> bool; +} + +/// Any text post-processor implements this trait. +#[async_trait] +pub trait TextProcessor: Send + Sync { + async fn process(&self, text: &str, instruction: &str) -> Result; + + fn name(&self) -> &EngineName; + + fn is_available(&self) -> bool; +} + +/// Holds the active provider instances. Constructed at startup, +/// rebuilt when user changes provider in settings. +// TODO: Wire into Tauri app state once multi-engine switching is implemented. +#[allow(dead_code)] +pub struct ProviderRegistry { + pub stt: Arc, + pub text: Option>, +} diff --git a/crates/core/src/recommendation.rs b/crates/core/src/recommendation.rs new file mode 100644 index 0000000..cce6dff --- /dev/null +++ b/crates/core/src/recommendation.rs @@ -0,0 +1,180 @@ +use crate::hardware::SystemProfile; +use crate::model_registry::{all_models, AccuracyTier, Engine, ModelEntry, SpeedTier}; +use crate::types::Megabytes; + +/// A model's suitability score for a given system. Higher is better. +/// No boolean flags — position in the ranked list conveys recommendation. +pub struct ScoredModel { + pub entry: &'static ModelEntry, + pub score: f64, + pub reason: String, +} + +/// Scores a single model against a system profile. +/// Pure function, no side effects. +pub fn score_model(model: &'static ModelEntry, profile: &SystemProfile) -> Option { + if model.ram_required > profile.ram { + return None; + } + + let mut score = 0.0; + let mut reasons: Vec = Vec::new(); + + score += match model.speed_tier { + SpeedTier::Instant => 40.0, + SpeedTier::Fast => 30.0, + SpeedTier::Moderate => 20.0, + SpeedTier::Slow => 10.0, + }; + + score += match model.accuracy_tier { + AccuracyTier::Excellent => 30.0, + AccuracyTier::Great => 20.0, + AccuracyTier::Good => 10.0, + }; + + if let Some(gpu) = &profile.gpu { + let has_accel = match model.engine { + Engine::Whisper => { + gpu.acceleration.metal || gpu.acceleration.vulkan || gpu.acceleration.cuda + } + Engine::Parakeet | Engine::Moonshine => { + gpu.acceleration.cuda || gpu.acceleration.vulkan + } + }; + if has_accel { + score += 15.0; + reasons.push("GPU accelerated on your system".into()); + } + } + + let headroom = Megabytes(profile.ram.0.saturating_sub(model.ram_required.0)); + if headroom > Megabytes::from_gb(4.0) { + score += 10.0; + } + + let reason = if reasons.is_empty() { + model.description.to_string() + } else { + reasons.join(". ") + }; + + Some(ScoredModel { + entry: model, + score, + reason, + }) +} + +/// Scores all models and returns them ranked. +/// Index 0 is the recommendation. No flag arguments. +pub fn rank_recommendations(profile: &SystemProfile) -> Vec { + let mut scored: Vec = all_models() + .iter() + .filter_map(|model| score_model(model, profile)) + .collect(); + + scored.sort_by(|a, b| { + b.score + .partial_cmp(&a.score) + .unwrap_or(std::cmp::Ordering::Equal) + }); + scored +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::hardware::{CpuInfo, GpuAcceleration, GpuInfo, GpuVendor, Os}; + + fn profile_with_ram(ram: Megabytes) -> SystemProfile { + SystemProfile { + ram, + cpu: CpuInfo { + logical_processors: 8, + brand: "Test CPU".into(), + }, + gpu: None, + os: Os::Windows, + } + } + + fn profile_with_gpu(ram: Megabytes) -> SystemProfile { + SystemProfile { + ram, + cpu: CpuInfo { + logical_processors: 8, + brand: "Test CPU".into(), + }, + gpu: Some(GpuInfo { + vendor: GpuVendor::Nvidia, + vram: Megabytes(8192), + acceleration: GpuAcceleration { + cuda: true, + metal: false, + vulkan: true, + }, + }), + os: Os::Windows, + } + } + + #[test] + fn score_model_excludes_models_exceeding_available_ram() { + let profile = profile_with_ram(Megabytes(256)); + let model = all_models() + .iter() + .find(|m| m.ram_required > Megabytes(256)) + .expect("need a model larger than 256 MB"); + + let result = score_model(model, &profile); + + assert!(result.is_none()); + } + + #[test] + fn score_model_includes_models_fitting_in_ram() { + let profile = profile_with_ram(Megabytes(16384)); + let model = &all_models()[0]; + + let result = score_model(model, &profile); + + assert!(result.is_some()); + } + + #[test] + fn score_model_boosts_gpu_accelerated_models() { + let model = all_models() + .iter() + .find(|m| m.engine == Engine::Parakeet) + .expect("need a Parakeet model"); + + let gpu_score = score_model(model, &profile_with_gpu(Megabytes(16384))) + .unwrap() + .score; + let cpu_score = score_model(model, &profile_with_ram(Megabytes(16384))) + .unwrap() + .score; + + assert!(gpu_score > cpu_score); + } + + #[test] + fn rank_recommendations_places_highest_score_first() { + let profile = profile_with_ram(Megabytes(16384)); + + let ranked = rank_recommendations(&profile); + + assert!(ranked.len() >= 2); + assert!(ranked[0].score >= ranked[1].score); + } + + #[test] + fn rank_recommendations_returns_empty_for_very_low_ram() { + let profile = profile_with_ram(Megabytes(128)); + + let ranked = rank_recommendations(&profile); + + assert!(ranked.is_empty()); + } +} diff --git a/crates/core/src/types.rs b/crates/core/src/types.rs new file mode 100644 index 0000000..c72f981 --- /dev/null +++ b/crates/core/src/types.rs @@ -0,0 +1,194 @@ +use serde::{Deserialize, Serialize}; + +/// Prevents passing raw strings where model IDs are expected. +#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)] +pub struct ModelId(String); + +impl ModelId { + pub fn new(id: impl Into) -> Self { + Self(id.into()) + } + + pub fn as_str(&self) -> &str { + &self.0 + } +} + +impl std::fmt::Display for ModelId { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + f.write_str(&self.0) + } +} + +/// Prevents passing raw strings where engine names are expected. +#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] +pub struct EngineName(String); + +impl EngineName { + pub fn new(name: impl Into) -> Self { + Self(name.into()) + } + + pub fn as_str(&self) -> &str { + &self.0 + } +} + +impl std::fmt::Display for EngineName { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + f.write_str(&self.0) + } +} + +/// Prevents mixing up bytes, megabytes, and gigabytes. +#[derive(Debug, Clone, Copy, PartialEq, PartialOrd, Serialize, Deserialize)] +pub struct Megabytes(pub u64); + +impl Megabytes { + pub fn from_gb(gb: f64) -> Self { + Self((gb * 1024.0) as u64) + } + + pub fn as_gb(&self) -> f64 { + self.0 as f64 / 1024.0 + } +} + +impl std::fmt::Display for Megabytes { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + if self.0 >= 1024 { + write!(f, "{:.1} GB", self.as_gb()) + } else { + write!(f, "{} MB", self.0) + } + } +} + +/// Wraps raw audio samples with metadata. +#[derive(Debug, Clone)] +pub struct AudioSamples { + samples: Vec, + sample_rate: u32, + channels: u16, +} + +impl AudioSamples { + pub fn new(samples: Vec, sample_rate: u32, channels: u16) -> Self { + Self { + samples, + sample_rate, + channels, + } + } + + pub fn mono_16khz(samples: Vec) -> Self { + Self { + samples, + sample_rate: crate::constants::WHISPER_SAMPLE_RATE, + channels: crate::constants::WHISPER_CHANNELS, + } + } + + pub fn samples(&self) -> &[f32] { + &self.samples + } + + pub fn into_samples(self) -> Vec { + self.samples + } + + pub fn sample_rate(&self) -> u32 { + self.sample_rate + } + + pub fn channels(&self) -> u16 { + self.channels + } + + pub fn duration_secs(&self) -> f64 { + if self.sample_rate == 0 { + return 0.0; + } + self.samples.len() as f64 / self.sample_rate as f64 + } +} + +/// A single timed segment of a transcription. +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct Segment { + pub start: f64, + pub end: f64, + pub text: String, +} + +/// The result of a transcription. +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct Transcript { + segments: Vec, + language: String, + duration: f64, +} + +impl Transcript { + pub fn new(segments: Vec, language: String, duration: f64) -> Self { + Self { + segments, + language, + duration, + } + } + + pub fn text(&self) -> String { + self.segments + .iter() + .map(|s| s.text.as_str()) + .collect::>() + .join(" ") + } + + pub fn segments(&self) -> &[Segment] { + &self.segments + } + + pub fn language(&self) -> &str { + &self.language + } + + pub fn duration(&self) -> f64 { + self.duration + } +} + +/// Options passed to a transcription engine. +#[derive(Debug, Clone, Default, Serialize, Deserialize)] +pub struct TranscriptionOptions { + pub language: Option, + pub initial_prompt: Option, +} + +/// Full provenance metadata for a transcript. +/// Captures everything needed to reproduce the transcription. +// TODO: Attach to Transcript once the store layer persists transcription provenance. +#[allow(dead_code)] +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct TranscriptMetadata { + pub engine: String, + pub model_id: ModelId, + pub inference_ms: u64, + pub sample_rate: u32, + pub audio_channels: u16, + pub format_mode: String, + pub remove_fillers: bool, + pub british_english: bool, + pub anti_hallucination: bool, +} + +/// Progress update during model download. +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct DownloadProgress { + pub model_id: ModelId, + pub file_name: String, + pub bytes_downloaded: u64, + pub total_bytes: u64, + pub percent: u8, +} diff --git a/crates/storage/Cargo.toml b/crates/storage/Cargo.toml new file mode 100644 index 0000000..143ed57 --- /dev/null +++ b/crates/storage/Cargo.toml @@ -0,0 +1,17 @@ +[package] +name = "kon-storage" +version = "0.1.0" +edition = "2021" +description = "SQLite persistence, BM25 search, and file storage for Kon" + +[dependencies] +kon-core = { path = "../core" } + +# SQLite with compile-time checked queries +sqlx = { version = "0.8", features = ["sqlite", "runtime-tokio"] } + +# Async runtime +tokio = { version = "1", features = ["rt", "sync", "macros"] } + +# Logging +log = "0.4" diff --git a/crates/storage/src/database.rs b/crates/storage/src/database.rs new file mode 100644 index 0000000..2bb5f87 --- /dev/null +++ b/crates/storage/src/database.rs @@ -0,0 +1,385 @@ +use std::path::Path; + +use sqlx::sqlite::{SqliteConnectOptions, SqlitePoolOptions}; +use sqlx::{Row, SqlitePool}; + +use kon_core::error::{KonError, Result}; + +/// Initialise the SQLite database with connection pool and run migrations. +pub async fn init(db_path: &Path) -> Result { + if let Some(parent) = db_path.parent() { + std::fs::create_dir_all(parent)?; + } + + let options = SqliteConnectOptions::new() + .filename(db_path) + .create_if_missing(true); + + let pool = SqlitePoolOptions::new() + .max_connections(5) + .connect_with(options) + .await + .map_err(|e| KonError::StorageError(format!("Database connect failed: {e}")))?; + + run_migrations(&pool).await?; + + Ok(pool) +} + +/// Run schema migrations via the versioned migration system. +async fn run_migrations(pool: &SqlitePool) -> Result<()> { + crate::migrations::run_migrations(pool).await +} + +// --- Transcript CRUD --- + +/// Parameters for inserting a transcript with full provenance. +pub struct InsertTranscriptParams<'a> { + pub id: &'a str, + pub text: &'a str, + pub source: &'a str, + pub title: Option<&'a str>, + pub audio_path: Option<&'a str>, + pub duration: f64, + pub engine: Option<&'a str>, + pub model_id: Option<&'a str>, + pub inference_ms: Option, + pub sample_rate: Option, + pub audio_channels: Option, + pub format_mode: Option<&'a str>, + pub remove_fillers: bool, + pub british_english: bool, + pub anti_hallucination: bool, +} + +pub async fn insert_transcript( + pool: &SqlitePool, + params: &InsertTranscriptParams<'_>, +) -> Result<()> { + sqlx::query( + "INSERT INTO transcripts (id, text, source, title, audio_path, duration, engine, model_id, inference_ms, sample_rate, audio_channels, format_mode, remove_fillers, british_english, anti_hallucination) + VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", + ) + .bind(params.id) + .bind(params.text) + .bind(params.source) + .bind(params.title) + .bind(params.audio_path) + .bind(params.duration) + .bind(params.engine) + .bind(params.model_id) + .bind(params.inference_ms) + .bind(params.sample_rate) + .bind(params.audio_channels) + .bind(params.format_mode) + .bind(params.remove_fillers) + .bind(params.british_english) + .bind(params.anti_hallucination) + .execute(pool) + .await + .map_err(|e| KonError::StorageError(format!("Insert transcript failed: {e}")))?; + Ok(()) +} + +pub async fn get_transcript(pool: &SqlitePool, id: &str) -> Result> { + let row = sqlx::query( + "SELECT id, text, source, title, audio_path, duration, engine, model_id, inference_ms, sample_rate, audio_channels, format_mode, remove_fillers, british_english, anti_hallucination, created_at FROM transcripts WHERE id = ?", + ) + .bind(id) + .fetch_optional(pool) + .await + .map_err(|e| KonError::StorageError(format!("Get transcript failed: {e}")))?; + + Ok(row.map(|r| transcript_row_from(&r))) +} + +pub async fn list_transcripts(pool: &SqlitePool, limit: i64) -> Result> { + let rows = sqlx::query( + "SELECT id, text, source, title, audio_path, duration, engine, model_id, inference_ms, sample_rate, audio_channels, format_mode, remove_fillers, british_english, anti_hallucination, created_at FROM transcripts ORDER BY created_at DESC LIMIT ?", + ) + .bind(limit) + .fetch_all(pool) + .await + .map_err(|e| KonError::StorageError(format!("List transcripts failed: {e}")))?; + + Ok(rows.iter().map(transcript_row_from).collect()) +} + +pub async fn delete_transcript(pool: &SqlitePool, id: &str) -> Result<()> { + sqlx::query("DELETE FROM transcripts WHERE id = ?") + .bind(id) + .execute(pool) + .await + .map_err(|e| KonError::StorageError(format!("Delete transcript failed: {e}")))?; + Ok(()) +} + +// --- Task CRUD --- + +pub async fn insert_task( + pool: &SqlitePool, + id: &str, + text: &str, + bucket: &str, + source_transcript_id: Option<&str>, +) -> Result<()> { + sqlx::query("INSERT INTO tasks (id, text, bucket, source_transcript_id) VALUES (?, ?, ?, ?)") + .bind(id) + .bind(text) + .bind(bucket) + .bind(source_transcript_id) + .execute(pool) + .await + .map_err(|e| KonError::StorageError(format!("Insert task failed: {e}")))?; + Ok(()) +} + +pub async fn list_tasks(pool: &SqlitePool) -> Result> { + let rows = + sqlx::query("SELECT id, text, bucket, list_id, effort, done, done_at, created_at, source_transcript_id FROM tasks ORDER BY created_at DESC") + .fetch_all(pool) + .await + .map_err(|e| KonError::StorageError(format!("List tasks failed: {e}")))?; + + Ok(rows + .into_iter() + .map(|r| TaskRow { + id: r.get("id"), + text: r.get("text"), + bucket: r.get("bucket"), + list_id: r.get("list_id"), + effort: r.get("effort"), + done: r.get("done"), + done_at: r.get("done_at"), + created_at: r.get("created_at"), + source_transcript_id: r.get("source_transcript_id"), + }) + .collect()) +} + +pub async fn complete_task(pool: &SqlitePool, id: &str) -> Result<()> { + sqlx::query("UPDATE tasks SET done = 1, done_at = datetime('now') WHERE id = ?") + .bind(id) + .execute(pool) + .await + .map_err(|e| KonError::StorageError(format!("Complete task failed: {e}")))?; + Ok(()) +} + +pub async fn delete_task(pool: &SqlitePool, id: &str) -> Result<()> { + sqlx::query("DELETE FROM tasks WHERE id = ?") + .bind(id) + .execute(pool) + .await + .map_err(|e| KonError::StorageError(format!("Delete task failed: {e}")))?; + Ok(()) +} + +// --- Settings CRUD --- + +pub async fn set_setting(pool: &SqlitePool, key: &str, value: &str) -> Result<()> { + sqlx::query("INSERT OR REPLACE INTO settings (key, value) VALUES (?, ?)") + .bind(key) + .bind(value) + .execute(pool) + .await + .map_err(|e| KonError::StorageError(format!("Set setting failed: {e}")))?; + Ok(()) +} + +pub async fn get_setting(pool: &SqlitePool, key: &str) -> Result> { + let row = sqlx::query("SELECT value FROM settings WHERE key = ?") + .bind(key) + .fetch_optional(pool) + .await + .map_err(|e| KonError::StorageError(format!("Get setting failed: {e}")))?; + Ok(row.map(|r| r.get("value"))) +} + +// --- Row types --- + +#[derive(Debug, Clone)] +pub struct TranscriptRow { + pub id: String, + pub text: String, + pub source: String, + pub title: Option, + pub audio_path: Option, + pub duration: f64, + pub engine: Option, + pub model_id: Option, + pub inference_ms: Option, + pub sample_rate: Option, + pub audio_channels: Option, + pub format_mode: Option, + pub remove_fillers: bool, + pub british_english: bool, + pub anti_hallucination: bool, + pub created_at: String, +} + +#[derive(Debug, Clone)] +pub struct TaskRow { + pub id: String, + pub text: String, + pub bucket: String, + pub list_id: Option, + pub effort: Option, + pub done: bool, + pub done_at: Option, + pub created_at: String, + pub source_transcript_id: Option, +} + +fn transcript_row_from(r: &sqlx::sqlite::SqliteRow) -> TranscriptRow { + TranscriptRow { + id: r.get("id"), + text: r.get("text"), + source: r.get("source"), + title: r.get("title"), + audio_path: r.get("audio_path"), + duration: r.get("duration"), + engine: r.get("engine"), + model_id: r.get("model_id"), + inference_ms: r.get("inference_ms"), + sample_rate: r.get("sample_rate"), + audio_channels: r.get("audio_channels"), + format_mode: r.get("format_mode"), + remove_fillers: r.get("remove_fillers"), + british_english: r.get("british_english"), + anti_hallucination: r.get("anti_hallucination"), + created_at: r.get("created_at"), + } +} + +// --- Error Logging --- + +/// Log a structured error to the `error_log` table. +/// +/// Available for Tauri command handlers to persist errors for diagnostics. +/// Each entry records context (which subsystem), an optional error code, +/// the human-readable message, and optional JSON metadata. +/// +/// # Example +/// ```ignore +/// log_error(&pool, "transcription", Some("WHISPER_INIT"), "Model load failed", None).await?; +/// ``` +/// +/// TODO: Wire this into Tauri command error paths so runtime failures are +/// persisted for user-facing error history and crash diagnostics. +pub async fn log_error( + pool: &SqlitePool, + context: &str, + error_code: Option<&str>, + message: &str, + metadata: Option<&str>, +) -> Result<()> { + sqlx::query( + "INSERT INTO error_log (context, error_code, message, metadata) VALUES (?, ?, ?, ?)", + ) + .bind(context) + .bind(error_code) + .bind(message) + .bind(metadata) + .execute(pool) + .await + .map_err(|e| KonError::StorageError(format!("Error log failed: {e}")))?; + Ok(()) +} + +#[cfg(test)] +mod tests { + use super::*; + + async fn test_pool() -> SqlitePool { + let pool = SqlitePoolOptions::new() + .connect("sqlite::memory:") + .await + .unwrap(); + run_migrations(&pool).await.unwrap(); + pool + } + + #[tokio::test] + async fn transcript_crud_roundtrip() { + let pool = test_pool().await; + + insert_transcript( + &pool, + &InsertTranscriptParams { + id: "t1", + text: "Hello world", + source: "microphone", + title: Some("Test"), + audio_path: None, + duration: 1.5, + engine: Some("whisper"), + model_id: Some("whisper-tiny-en"), + inference_ms: Some(250), + sample_rate: Some(48000), + audio_channels: Some(1), + format_mode: Some("Clean"), + remove_fillers: true, + british_english: true, + anti_hallucination: false, + }, + ) + .await + .unwrap(); + + let t = get_transcript(&pool, "t1").await.unwrap().unwrap(); + assert_eq!(t.text, "Hello world"); + assert_eq!(t.source, "microphone"); + assert_eq!(t.duration, 1.5); + assert_eq!(t.engine.as_deref(), Some("whisper")); + assert_eq!(t.model_id.as_deref(), Some("whisper-tiny-en")); + assert_eq!(t.inference_ms, Some(250)); + assert!(t.remove_fillers); + assert!(t.british_english); + + let list = list_transcripts(&pool, 10).await.unwrap(); + assert_eq!(list.len(), 1); + + delete_transcript(&pool, "t1").await.unwrap(); + let deleted = get_transcript(&pool, "t1").await.unwrap(); + assert!(deleted.is_none()); + } + + #[tokio::test] + async fn task_crud_roundtrip() { + let pool = test_pool().await; + + insert_task(&pool, "task1", "Buy groceries", "today", None) + .await + .unwrap(); + + let tasks = list_tasks(&pool).await.unwrap(); + assert_eq!(tasks.len(), 1); + assert_eq!(tasks[0].text, "Buy groceries"); + assert!(!tasks[0].done); + + complete_task(&pool, "task1").await.unwrap(); + let tasks = list_tasks(&pool).await.unwrap(); + assert!(tasks[0].done); + + delete_task(&pool, "task1").await.unwrap(); + let tasks = list_tasks(&pool).await.unwrap(); + assert!(tasks.is_empty()); + } + + #[tokio::test] + async fn settings_crud_roundtrip() { + let pool = test_pool().await; + + set_setting(&pool, "theme", "dark").await.unwrap(); + let val = get_setting(&pool, "theme").await.unwrap(); + assert_eq!(val.as_deref(), Some("dark")); + + set_setting(&pool, "theme", "light").await.unwrap(); + let val = get_setting(&pool, "theme").await.unwrap(); + assert_eq!(val.as_deref(), Some("light")); + + let missing = get_setting(&pool, "nonexistent").await.unwrap(); + assert!(missing.is_none()); + } +} diff --git a/crates/storage/src/file_storage.rs b/crates/storage/src/file_storage.rs new file mode 100644 index 0000000..1b1000e --- /dev/null +++ b/crates/storage/src/file_storage.rs @@ -0,0 +1,28 @@ +use std::path::PathBuf; + +/// Resolve the app data directory. +/// Windows: %LOCALAPPDATA%/kon +/// Unix: ~/.kon +/// +/// TODO: Consolidate with `crates/transcription/src/model_manager.rs::dirs_path()` +/// into a shared helper in `crates/core/` to avoid duplicating platform-specific +/// path logic across crates. +pub fn app_data_dir() -> PathBuf { + if cfg!(target_os = "windows") { + let local_app_data = std::env::var("LOCALAPPDATA").unwrap_or_else(|_| ".".to_string()); + PathBuf::from(local_app_data).join("kon") + } else { + let home = std::env::var("HOME").unwrap_or_else(|_| "/tmp".to_string()); + PathBuf::from(home).join(".kon") + } +} + +/// Path to the SQLite database file. +pub fn database_path() -> PathBuf { + app_data_dir().join("kon.db") +} + +/// Directory for saved audio recordings. +pub fn recordings_dir() -> PathBuf { + app_data_dir().join("recordings") +} diff --git a/crates/storage/src/lib.rs b/crates/storage/src/lib.rs new file mode 100644 index 0000000..b445049 --- /dev/null +++ b/crates/storage/src/lib.rs @@ -0,0 +1,10 @@ +pub mod database; +pub mod file_storage; +pub mod migrations; + +pub use database::{ + complete_task, delete_task, delete_transcript, get_setting, get_transcript, init, insert_task, + insert_transcript, list_tasks, list_transcripts, log_error, set_setting, + InsertTranscriptParams, TaskRow, TranscriptRow, +}; +pub use file_storage::{app_data_dir, database_path, recordings_dir}; diff --git a/crates/storage/src/migrations.rs b/crates/storage/src/migrations.rs new file mode 100644 index 0000000..2af4269 --- /dev/null +++ b/crates/storage/src/migrations.rs @@ -0,0 +1,168 @@ +use sqlx::SqlitePool; +use kon_core::error::{KonError, Result}; + +/// Each migration is a (version, description, sql) tuple. +/// Migrations MUST be append-only — never modify an existing migration. +/// Column defaults and NOT NULL constraints must exactly match the existing schema. +const MIGRATIONS: &[(i64, &str, &str)] = &[ + (1, "initial schema", r#" + CREATE TABLE IF NOT EXISTS transcripts ( + id TEXT PRIMARY KEY, + text TEXT NOT NULL DEFAULT '', + source TEXT NOT NULL DEFAULT 'microphone', + title TEXT, + audio_path TEXT, + duration REAL NOT NULL DEFAULT 0.0, + engine TEXT, + model_id TEXT, + inference_ms INTEGER, + sample_rate INTEGER, + audio_channels INTEGER, + format_mode TEXT, + remove_fillers INTEGER NOT NULL DEFAULT 0, + british_english INTEGER NOT NULL DEFAULT 0, + anti_hallucination INTEGER NOT NULL DEFAULT 0, + created_at TEXT NOT NULL DEFAULT (datetime('now')) + ); + + CREATE TABLE IF NOT EXISTS segments ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + transcript_id TEXT NOT NULL REFERENCES transcripts(id) ON DELETE CASCADE, + start_time REAL NOT NULL, + end_time REAL NOT NULL, + text TEXT NOT NULL DEFAULT '' + ); + + CREATE TABLE IF NOT EXISTS tasks ( + id TEXT PRIMARY KEY, + text TEXT NOT NULL, + bucket TEXT NOT NULL DEFAULT 'inbox', + list_id TEXT, + effort TEXT, + done INTEGER NOT NULL DEFAULT 0, + done_at TEXT, + created_at TEXT NOT NULL DEFAULT (datetime('now')), + source_transcript_id TEXT + ); + + CREATE TABLE IF NOT EXISTS task_lists ( + id TEXT PRIMARY KEY, + name TEXT NOT NULL, + built_in INTEGER NOT NULL DEFAULT 0, + profile_id TEXT, + created_at TEXT NOT NULL DEFAULT (datetime('now')) + ); + + CREATE TABLE IF NOT EXISTS settings ( + key TEXT PRIMARY KEY, + value TEXT NOT NULL + ); + + CREATE TABLE IF NOT EXISTS error_log ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + timestamp TEXT NOT NULL DEFAULT (datetime('now')), + context TEXT NOT NULL, + error_code TEXT, + message TEXT NOT NULL, + metadata TEXT + ); + + CREATE INDEX IF NOT EXISTS idx_transcripts_created ON transcripts(created_at); + CREATE INDEX IF NOT EXISTS idx_segments_transcript ON segments(transcript_id); + CREATE INDEX IF NOT EXISTS idx_tasks_bucket ON tasks(bucket); + CREATE INDEX IF NOT EXISTS idx_tasks_transcript ON tasks(source_transcript_id); + CREATE INDEX IF NOT EXISTS idx_error_log_context ON error_log(context) + "#), +]; + +/// Ensure the schema_version table exists and run any pending migrations. +pub async fn run_migrations(pool: &SqlitePool) -> Result<()> { + sqlx::query( + "CREATE TABLE IF NOT EXISTS schema_version ( + version INTEGER PRIMARY KEY, + description TEXT NOT NULL, + applied_at TEXT NOT NULL DEFAULT (datetime('now')) + )" + ) + .execute(pool) + .await + .map_err(|e| KonError::StorageError(format!("Schema version table creation failed: {e}")))?; + + let current: i64 = sqlx::query_scalar("SELECT COALESCE(MAX(version), 0) FROM schema_version") + .fetch_one(pool) + .await + .map_err(|e| KonError::StorageError(format!("Schema version query failed: {e}")))?; + + for (version, description, sql) in MIGRATIONS { + if *version > current { + log::info!("Running migration {}: {}", version, description); + + let statements: Vec<&str> = sql.split(';') + .map(|s| s.trim()) + .filter(|s| !s.is_empty()) + .collect(); + + for statement in statements { + sqlx::query(statement) + .execute(pool) + .await + .map_err(|e| KonError::StorageError(format!("Migration {} failed: {e}", version)))?; + } + + sqlx::query("INSERT INTO schema_version (version, description) VALUES (?, ?)") + .bind(version) + .bind(description) + .execute(pool) + .await + .map_err(|e| KonError::StorageError(format!("Migration version record failed: {e}")))?; + + log::info!("Migration {} complete", version); + } + } + + Ok(()) +} + +#[cfg(test)] +mod tests { + use super::*; + use sqlx::sqlite::SqlitePoolOptions; + + #[tokio::test] + async fn test_migrations_run_on_empty_db() { + let pool = SqlitePoolOptions::new() + .connect("sqlite::memory:") + .await + .unwrap(); + + run_migrations(&pool).await.unwrap(); + + let count: i64 = sqlx::query_scalar("SELECT COUNT(*) FROM schema_version") + .fetch_one(&pool) + .await + .unwrap(); + assert_eq!(count, 1); + + sqlx::query("INSERT INTO settings (key, value) VALUES ('test', 'value')") + .execute(&pool) + .await + .unwrap(); + } + + #[tokio::test] + async fn test_migrations_idempotent() { + let pool = SqlitePoolOptions::new() + .connect("sqlite::memory:") + .await + .unwrap(); + + run_migrations(&pool).await.unwrap(); + run_migrations(&pool).await.unwrap(); + + let count: i64 = sqlx::query_scalar("SELECT COUNT(*) FROM schema_version") + .fetch_one(&pool) + .await + .unwrap(); + assert_eq!(count, 1); + } +} diff --git a/crates/transcription/Cargo.toml b/crates/transcription/Cargo.toml new file mode 100644 index 0000000..d42e695 --- /dev/null +++ b/crates/transcription/Cargo.toml @@ -0,0 +1,18 @@ +[package] +name = "kon-transcription" +version = "0.1.0" +edition = "2021" +description = "Speech-to-text engine wrappers, model management, and inference concurrency for Kon" + +[dependencies] +kon-core = { path = "../core" } + +# Unified STT engine (Parakeet via ONNX, Whisper via whisper.cpp) +transcribe-rs = { version = "0.3", features = ["onnx", "whisper-cpp"] } + +# Async runtime for spawn_blocking +tokio = { version = "1", features = ["rt", "sync"] } + +# Model downloads +reqwest = { version = "0.12", features = ["stream"] } +futures-util = "0.3" diff --git a/crates/transcription/src/concurrency.rs b/crates/transcription/src/concurrency.rs new file mode 100644 index 0000000..52c1d8e --- /dev/null +++ b/crates/transcription/src/concurrency.rs @@ -0,0 +1,22 @@ +use std::sync::Arc; + +use kon_core::error::{KonError, Result}; +use kon_core::types::{AudioSamples, TranscriptionOptions}; + +use crate::local_engine::{LocalEngine, TimedTranscript}; + +/// Runs inference on a blocking thread. Encapsulates all threading concerns. +/// Callers never see spawn_blocking — they call this async function. +pub async fn run_inference( + engine: Arc, + audio: AudioSamples, + options: TranscriptionOptions, +) -> Result { + tokio::task::spawn_blocking(move || { + engine.transcribe_sync(&audio, &options) + }) + .await + .map_err(|e| { + KonError::TranscriptionFailed(format!("Task join error: {e}")) + })? +} diff --git a/crates/transcription/src/lib.rs b/crates/transcription/src/lib.rs new file mode 100644 index 0000000..b43b365 --- /dev/null +++ b/crates/transcription/src/lib.rs @@ -0,0 +1,11 @@ +pub mod concurrency; +pub mod local_engine; +pub mod model_manager; + +pub use concurrency::run_inference; +pub use local_engine::{ + load_parakeet, load_whisper, LocalEngine, TimedTranscript, +}; +pub use model_manager::{ + download, is_downloaded, list_downloaded, model_dir, models_dir, +}; diff --git a/crates/transcription/src/local_engine.rs b/crates/transcription/src/local_engine.rs new file mode 100644 index 0000000..026b026 --- /dev/null +++ b/crates/transcription/src/local_engine.rs @@ -0,0 +1,155 @@ +use std::path::Path; +use std::sync::Mutex; +use std::time::Instant; + +use transcribe_rs::{SpeechModel, TranscribeOptions, TranscriptionResult}; + +use kon_core::error::{KonError, Result}; +use kon_core::types::{ + AudioSamples, EngineName, ModelId, Segment, Transcript, + TranscriptionOptions, +}; + +/// Result of a timed transcription: transcript + inference duration. +pub struct TimedTranscript { + pub transcript: Transcript, + pub inference_ms: u64, +} + +/// Wraps any transcribe-rs engine in Kon's SpeechToText trait. +/// Encapsulates threading: inference always runs on a blocking thread. +/// The rest of the app never imports transcribe-rs directly. +pub struct LocalEngine { + engine: Mutex>>, + engine_name: EngineName, + loaded_model_id: Mutex>, +} + +impl LocalEngine { + pub fn new(engine_name: EngineName) -> Self { + Self { + engine: Mutex::new(None), + engine_name, + loaded_model_id: Mutex::new(None), + } + } + + pub fn load(&self, model: Box, model_id: ModelId) { + let mut guard = + self.engine.lock().unwrap_or_else(|e| e.into_inner()); + *guard = Some(model); + let mut id_guard = self + .loaded_model_id + .lock() + .unwrap_or_else(|e| e.into_inner()); + *id_guard = Some(model_id); + } + + pub fn name(&self) -> &EngineName { + &self.engine_name + } + + pub fn loaded_model_id(&self) -> Option { + let guard = self + .loaded_model_id + .lock() + .unwrap_or_else(|e| e.into_inner()); + guard.clone() + } + + pub fn is_loaded(&self) -> bool { + let guard = + self.engine.lock().unwrap_or_else(|e| e.into_inner()); + guard.is_some() + } + + /// Run transcription synchronously with timing. + /// Called from within spawn_blocking. + pub fn transcribe_sync( + &self, + audio: &AudioSamples, + options: &TranscriptionOptions, + ) -> Result { + let mut guard = + self.engine.lock().unwrap_or_else(|e| e.into_inner()); + let engine = + guard.as_mut().ok_or(KonError::EngineNotLoaded)?; + + let opts = TranscribeOptions { + language: options.language.clone(), + translate: false, + }; + + let start = Instant::now(); + let result: TranscriptionResult = engine + .transcribe(audio.samples(), &opts) + .map_err(|e| KonError::TranscriptionFailed(e.to_string()))?; + let inference_ms = start.elapsed().as_millis() as u64; + + let segments = result + .segments + .unwrap_or_default() + .into_iter() + .map(|s| Segment { + start: s.start as f64, + end: s.end as f64, + text: s.text, + }) + .collect(); + + Ok(TimedTranscript { + transcript: Transcript::new( + segments, + options + .language + .clone() + .unwrap_or_else(|| "en".to_string()), + audio.duration_secs(), + ), + inference_ms, + }) + } +} + +/// Load a Parakeet model from a directory path. +pub fn load_parakeet( + model_dir: &Path, +) -> Result> { + use transcribe_rs::onnx::Quantization; + let model = transcribe_rs::onnx::parakeet::ParakeetModel::load( + model_dir, + &Quantization::Int8, + ) + .map_err(|e| { + KonError::TranscriptionFailed(format!( + "Failed to load Parakeet: {e}" + )) + })?; + Ok(Box::new(model)) +} + +/// Load a Whisper model from a GGML file path. +pub fn load_whisper( + model_path: &Path, +) -> Result> { + let engine = + transcribe_rs::whisper_cpp::WhisperEngine::load(model_path) + .map_err(|e| { + KonError::TranscriptionFailed(format!( + "Failed to load Whisper: {e}" + )) + })?; + Ok(Box::new(engine)) +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn engine_reports_not_available_before_loading() { + let engine = LocalEngine::new(EngineName::new("test")); + assert!(!engine.is_loaded()); + assert!(engine.loaded_model_id().is_none()); + } +} diff --git a/crates/transcription/src/model_manager.rs b/crates/transcription/src/model_manager.rs new file mode 100644 index 0000000..3e15c19 --- /dev/null +++ b/crates/transcription/src/model_manager.rs @@ -0,0 +1,165 @@ +use std::path::{Path, PathBuf}; + +use kon_core::error::{KonError, Result}; +use kon_core::model_registry::{find_model, ModelFile}; +use kon_core::types::{DownloadProgress, ModelId}; + +/// Resolve the models storage directory. +/// Windows: %LOCALAPPDATA%/kon/models +/// Unix: ~/.kon/models +pub fn models_dir() -> PathBuf { + if cfg!(target_os = "windows") { + let local_app_data = std::env::var("LOCALAPPDATA") + .unwrap_or_else(|_| ".".to_string()); + PathBuf::from(local_app_data).join("kon").join("models") + } else { + dirs_path().join("models") + } +} + +fn dirs_path() -> PathBuf { + if cfg!(target_os = "windows") { + let local_app_data = std::env::var("LOCALAPPDATA") + .unwrap_or_else(|_| ".".to_string()); + PathBuf::from(local_app_data).join("kon") + } else { + let home = + std::env::var("HOME").unwrap_or_else(|_| "/tmp".to_string()); + PathBuf::from(home).join(".kon") + } +} + +/// Get the directory path where a specific model's files are stored. +pub fn model_dir(id: &ModelId) -> PathBuf { + models_dir().join(id.as_str()) +} + +/// Check whether all files for a model have been downloaded. +pub fn is_downloaded(id: &ModelId) -> bool { + let entry = match find_model(id) { + Some(e) => e, + None => return false, + }; + let dir = model_dir(id); + entry.files.iter().all(|f| dir.join(f.filename).exists()) +} + +/// List all downloaded model IDs. +pub fn list_downloaded() -> Vec { + kon_core::model_registry::all_models() + .iter() + .filter(|m| is_downloaded(&m.id)) + .map(|m| m.id.clone()) + .collect() +} + +/// Download all files for a model, calling the progress callback per chunk. +/// Files are downloaded to a .part suffix and atomically renamed on completion. +pub async fn download( + id: &ModelId, + progress: impl Fn(DownloadProgress) + Send + 'static, +) -> Result<()> { + let entry = find_model(id) + .ok_or_else(|| KonError::ModelNotFound(id.clone()))?; + + let dir = model_dir(id); + std::fs::create_dir_all(&dir)?; + + for file in &entry.files { + let dest = dir.join(file.filename); + if dest.exists() { + continue; + } + download_file(file, &dest, id, &progress).await?; + } + + Ok(()) +} + +async fn download_file( + file: &ModelFile, + dest: &Path, + model_id: &ModelId, + progress: &(impl Fn(DownloadProgress) + Send), +) -> Result<()> { + use futures_util::StreamExt; + + let part_path = dest.with_extension( + dest.extension() + .map(|e| format!("{}.part", e.to_string_lossy())) + .unwrap_or_else(|| "part".to_string()), + ); + + let client = reqwest::Client::builder() + .connect_timeout(std::time::Duration::from_secs(30)) + .build() + .map_err(|e| KonError::DownloadFailed(e.to_string()))?; + + let response = client + .get(file.url) + .send() + .await + .map_err(|e| KonError::DownloadFailed(e.to_string()))?; + + let total_bytes = response.content_length().unwrap_or(0); + let mut stream = response.bytes_stream(); + let mut downloaded: u64 = 0; + let mut last_percent: u8 = 0; + + let mut out = std::fs::File::create(&part_path)?; + + while let Some(chunk) = stream.next().await { + let chunk = chunk + .map_err(|e| KonError::DownloadFailed(e.to_string()))?; + std::io::Write::write_all(&mut out, &chunk)?; + downloaded += chunk.len() as u64; + + let percent = if total_bytes > 0 { + ((downloaded as f64 / total_bytes as f64) * 100.0) as u8 + } else { + 0 + }; + + if percent != last_percent { + last_percent = percent; + progress(DownloadProgress { + model_id: model_id.clone(), + file_name: file.filename.to_string(), + bytes_downloaded: downloaded, + total_bytes, + percent, + }); + } + } + + drop(out); + std::fs::rename(&part_path, dest)?; + + Ok(()) +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn model_dir_returns_correct_path() { + let id = ModelId::new("whisper-tiny-en"); + let path = model_dir(&id); + assert!(path.to_string_lossy().contains("whisper-tiny-en")); + } + + #[test] + fn is_downloaded_returns_false_for_missing_model() { + let id = ModelId::new("nonexistent-model"); + assert!(!is_downloaded(&id)); + } + + #[test] + fn list_downloaded_returns_empty_when_no_models() { + let list = list_downloaded(); + // In test environment, no models are downloaded + // This just verifies the function doesn't panic + assert!(list.len() <= kon_core::model_registry::all_models().len()); + } +} diff --git a/docs/design/phase2/fox/nanobanana-fox-mark.svg b/docs/design/phase2/fox/nanobanana-fox-mark.svg new file mode 100644 index 0000000..ad4a8a5 --- /dev/null +++ b/docs/design/phase2/fox/nanobanana-fox-mark.svg @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/jsconfig.json b/jsconfig.json new file mode 100644 index 0000000..4344710 --- /dev/null +++ b/jsconfig.json @@ -0,0 +1,14 @@ +{ + "extends": "./.svelte-kit/tsconfig.json", + "compilerOptions": { + "allowJs": true, + "checkJs": true, + "esModuleInterop": true, + "forceConsistentCasingInFileNames": true, + "resolveJsonModule": true, + "skipLibCheck": true, + "sourceMap": true, + "strict": true, + "moduleResolution": "bundler" + } +} diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 0000000..876148b --- /dev/null +++ b/package-lock.json @@ -0,0 +1,2579 @@ +{ + "name": "kon", + "version": "0.1.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "kon", + "version": "0.1.0", + "license": "MIT", + "dependencies": { + "@tauri-apps/api": "^2", + "@tauri-apps/plugin-dialog": "^2.6.0", + "@tauri-apps/plugin-global-shortcut": "^2.3.1", + "@tauri-apps/plugin-opener": "^2" + }, + "devDependencies": { + "@sveltejs/adapter-static": "^3.0.6", + "@sveltejs/kit": "^2.9.0", + "@sveltejs/vite-plugin-svelte": "^5.0.0", + "@tailwindcss/vite": "^4.2.1", + "@tauri-apps/cli": "^2", + "svelte": "^5.0.0", + "svelte-check": "^4.0.0", + "tailwindcss": "^4.2.1", + "typescript": "~5.6.2", + "vite": "^6.0.3" + } + }, + "node_modules/@esbuild/aix-ppc64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.12.tgz", + "integrity": "sha512-Hhmwd6CInZ3dwpuGTF8fJG6yoWmsToE+vYgD4nytZVxcu1ulHpUQRAB1UJ8+N1Am3Mz4+xOByoQoSZf4D+CpkA==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "aix" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.25.12.tgz", + "integrity": "sha512-VJ+sKvNA/GE7Ccacc9Cha7bpS8nyzVv0jdVgwNDaR4gDMC/2TTRc33Ip8qrNYUcpkOHUT5OZ0bUcNNVZQ9RLlg==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.25.12.tgz", + "integrity": "sha512-6AAmLG7zwD1Z159jCKPvAxZd4y/VTO0VkprYy+3N2FtJ8+BQWFXU+OxARIwA46c5tdD9SsKGZ/1ocqBS/gAKHg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-x64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.25.12.tgz", + "integrity": "sha512-5jbb+2hhDHx5phYR2By8GTWEzn6I9UqR11Kwf22iKbNpYrsmRB18aX/9ivc5cabcUiAT/wM+YIZ6SG9QO6a8kg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-arm64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.25.12.tgz", + "integrity": "sha512-N3zl+lxHCifgIlcMUP5016ESkeQjLj/959RxxNYIthIg+CQHInujFuXeWbWMgnTo4cp5XVHqFPmpyu9J65C1Yg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-x64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.25.12.tgz", + "integrity": "sha512-HQ9ka4Kx21qHXwtlTUVbKJOAnmG1ipXhdWTmNXiPzPfWKpXqASVcWdnf2bnL73wgjNrFXAa3yYvBSd9pzfEIpA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-arm64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.25.12.tgz", + "integrity": "sha512-gA0Bx759+7Jve03K1S0vkOu5Lg/85dou3EseOGUes8flVOGxbhDDh/iZaoek11Y8mtyKPGF3vP8XhnkDEAmzeg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-x64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.25.12.tgz", + "integrity": "sha512-TGbO26Yw2xsHzxtbVFGEXBFH0FRAP7gtcPE7P5yP7wGy7cXK2oO7RyOhL5NLiqTlBh47XhmIUXuGciXEqYFfBQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.25.12.tgz", + "integrity": "sha512-lPDGyC1JPDou8kGcywY0YILzWlhhnRjdof3UlcoqYmS9El818LLfJJc3PXXgZHrHCAKs/Z2SeZtDJr5MrkxtOw==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.25.12.tgz", + "integrity": "sha512-8bwX7a8FghIgrupcxb4aUmYDLp8pX06rGh5HqDT7bB+8Rdells6mHvrFHHW2JAOPZUbnjUpKTLg6ECyzvas2AQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ia32": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.25.12.tgz", + "integrity": "sha512-0y9KrdVnbMM2/vG8KfU0byhUN+EFCny9+8g202gYqSSVMonbsCfLjUO+rCci7pM0WBEtz+oK/PIwHkzxkyharA==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-loong64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.25.12.tgz", + "integrity": "sha512-h///Lr5a9rib/v1GGqXVGzjL4TMvVTv+s1DPoxQdz7l/AYv6LDSxdIwzxkrPW438oUXiDtwM10o9PmwS/6Z0Ng==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-mips64el": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.25.12.tgz", + "integrity": "sha512-iyRrM1Pzy9GFMDLsXn1iHUm18nhKnNMWscjmp4+hpafcZjrr2WbT//d20xaGljXDBYHqRcl8HnxbX6uaA/eGVw==", + "cpu": [ + "mips64el" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ppc64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.25.12.tgz", + "integrity": "sha512-9meM/lRXxMi5PSUqEXRCtVjEZBGwB7P/D4yT8UG/mwIdze2aV4Vo6U5gD3+RsoHXKkHCfSxZKzmDssVlRj1QQA==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-riscv64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.25.12.tgz", + "integrity": "sha512-Zr7KR4hgKUpWAwb1f3o5ygT04MzqVrGEGXGLnj15YQDJErYu/BGg+wmFlIDOdJp0PmB0lLvxFIOXZgFRrdjR0w==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-s390x": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.25.12.tgz", + "integrity": "sha512-MsKncOcgTNvdtiISc/jZs/Zf8d0cl/t3gYWX8J9ubBnVOwlk65UIEEvgBORTiljloIWnBzLs4qhzPkJcitIzIg==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-x64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.25.12.tgz", + "integrity": "sha512-uqZMTLr/zR/ed4jIGnwSLkaHmPjOjJvnm6TVVitAa08SLS9Z0VM8wIRx7gWbJB5/J54YuIMInDquWyYvQLZkgw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-arm64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.25.12.tgz", + "integrity": "sha512-xXwcTq4GhRM7J9A8Gv5boanHhRa/Q9KLVmcyXHCTaM4wKfIpWkdXiMog/KsnxzJ0A1+nD+zoecuzqPmCRyBGjg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-x64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.25.12.tgz", + "integrity": "sha512-Ld5pTlzPy3YwGec4OuHh1aCVCRvOXdH8DgRjfDy/oumVovmuSzWfnSJg+VtakB9Cm0gxNO9BzWkj6mtO1FMXkQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-arm64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.25.12.tgz", + "integrity": "sha512-fF96T6KsBo/pkQI950FARU9apGNTSlZGsv1jZBAlcLL1MLjLNIWPBkj5NlSz8aAzYKg+eNqknrUJ24QBybeR5A==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-x64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.25.12.tgz", + "integrity": "sha512-MZyXUkZHjQxUvzK7rN8DJ3SRmrVrke8ZyRusHlP+kuwqTcfWLyqMOE3sScPPyeIXN/mDJIfGXvcMqCgYKekoQw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openharmony-arm64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.25.12.tgz", + "integrity": "sha512-rm0YWsqUSRrjncSXGA7Zv78Nbnw4XL6/dzr20cyrQf7ZmRcsovpcRBdhD43Nuk3y7XIoW2OxMVvwuRvk9XdASg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/sunos-x64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.25.12.tgz", + "integrity": "sha512-3wGSCDyuTHQUzt0nV7bocDy72r2lI33QL3gkDNGkod22EsYl04sMf0qLb8luNKTOmgF/eDEDP5BFNwoBKH441w==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-arm64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.25.12.tgz", + "integrity": "sha512-rMmLrur64A7+DKlnSuwqUdRKyd3UE7oPJZmnljqEptesKM8wx9J8gx5u0+9Pq0fQQW8vqeKebwNXdfOyP+8Bsg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-ia32": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.25.12.tgz", + "integrity": "sha512-HkqnmmBoCbCwxUKKNPBixiWDGCpQGVsrQfJoVGYLPT41XWF8lHuE5N6WhVia2n4o5QK5M4tYr21827fNhi4byQ==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-x64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.25.12.tgz", + "integrity": "sha512-alJC0uCZpTFrSL0CCDjcgleBXPnCrEAhTBILpeAp7M/OFgoqtAetfBzX0xM00MUsVVPpVjlPuMbREqnZCXaTnA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@jridgewell/gen-mapping": { + "version": "0.3.13", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz", + "integrity": "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.5.0", + "@jridgewell/trace-mapping": "^0.3.24" + } + }, + "node_modules/@jridgewell/remapping": { + "version": "2.3.5", + "resolved": "https://registry.npmjs.org/@jridgewell/remapping/-/remapping-2.3.5.tgz", + "integrity": "sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.24" + } + }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", + "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.5.5", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz", + "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==", + "dev": true, + "license": "MIT" + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.31", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz", + "integrity": "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + }, + "node_modules/@polka/url": { + "version": "1.0.0-next.29", + "resolved": "https://registry.npmjs.org/@polka/url/-/url-1.0.0-next.29.tgz", + "integrity": "sha512-wwQAWhWSuHaag8c4q/KN/vCoeOJYshAIvMQwD4GpSb3OiZklFfvAgmj0VCBBImRpuF/aFgIRzllXlVX93Jevww==", + "dev": true, + "license": "MIT" + }, + "node_modules/@rollup/rollup-android-arm-eabi": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.59.0.tgz", + "integrity": "sha512-upnNBkA6ZH2VKGcBj9Fyl9IGNPULcjXRlg0LLeaioQWueH30p6IXtJEbKAgvyv+mJaMxSm1l6xwDXYjpEMiLMg==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-android-arm64": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.59.0.tgz", + "integrity": "sha512-hZ+Zxj3SySm4A/DylsDKZAeVg0mvi++0PYVceVyX7hemkw7OreKdCvW2oQ3T1FMZvCaQXqOTHb8qmBShoqk69Q==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-darwin-arm64": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.59.0.tgz", + "integrity": "sha512-W2Psnbh1J8ZJw0xKAd8zdNgF9HRLkdWwwdWqubSVk0pUuQkoHnv7rx4GiF9rT4t5DIZGAsConRE3AxCdJ4m8rg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-darwin-x64": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.59.0.tgz", + "integrity": "sha512-ZW2KkwlS4lwTv7ZVsYDiARfFCnSGhzYPdiOU4IM2fDbL+QGlyAbjgSFuqNRbSthybLbIJ915UtZBtmuLrQAT/w==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-freebsd-arm64": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.59.0.tgz", + "integrity": "sha512-EsKaJ5ytAu9jI3lonzn3BgG8iRBjV4LxZexygcQbpiU0wU0ATxhNVEpXKfUa0pS05gTcSDMKpn3Sx+QB9RlTTA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@rollup/rollup-freebsd-x64": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.59.0.tgz", + "integrity": "sha512-d3DuZi2KzTMjImrxoHIAODUZYoUUMsuUiY4SRRcJy6NJoZ6iIqWnJu9IScV9jXysyGMVuW+KNzZvBLOcpdl3Vg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@rollup/rollup-linux-arm-gnueabihf": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.59.0.tgz", + "integrity": "sha512-t4ONHboXi/3E0rT6OZl1pKbl2Vgxf9vJfWgmUoCEVQVxhW6Cw/c8I6hbbu7DAvgp82RKiH7TpLwxnJeKv2pbsw==", + "cpu": [ + "arm" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm-musleabihf": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.59.0.tgz", + "integrity": "sha512-CikFT7aYPA2ufMD086cVORBYGHffBo4K8MQ4uPS/ZnY54GKj36i196u8U+aDVT2LX4eSMbyHtyOh7D7Zvk2VvA==", + "cpu": [ + "arm" + ], + "dev": true, + "libc": [ + "musl" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-gnu": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.59.0.tgz", + "integrity": "sha512-jYgUGk5aLd1nUb1CtQ8E+t5JhLc9x5WdBKew9ZgAXg7DBk0ZHErLHdXM24rfX+bKrFe+Xp5YuJo54I5HFjGDAA==", + "cpu": [ + "arm64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-musl": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.59.0.tgz", + "integrity": "sha512-peZRVEdnFWZ5Bh2KeumKG9ty7aCXzzEsHShOZEFiCQlDEepP1dpUl/SrUNXNg13UmZl+gzVDPsiCwnV1uI0RUA==", + "cpu": [ + "arm64" + ], + "dev": true, + "libc": [ + "musl" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-loong64-gnu": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-gnu/-/rollup-linux-loong64-gnu-4.59.0.tgz", + "integrity": "sha512-gbUSW/97f7+r4gHy3Jlup8zDG190AuodsWnNiXErp9mT90iCy9NKKU0Xwx5k8VlRAIV2uU9CsMnEFg/xXaOfXg==", + "cpu": [ + "loong64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-loong64-musl": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-musl/-/rollup-linux-loong64-musl-4.59.0.tgz", + "integrity": "sha512-yTRONe79E+o0FWFijasoTjtzG9EBedFXJMl888NBEDCDV9I2wGbFFfJQQe63OijbFCUZqxpHz1GzpbtSFikJ4Q==", + "cpu": [ + "loong64" + ], + "dev": true, + "libc": [ + "musl" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-ppc64-gnu": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.59.0.tgz", + "integrity": "sha512-sw1o3tfyk12k3OEpRddF68a1unZ5VCN7zoTNtSn2KndUE+ea3m3ROOKRCZxEpmT9nsGnogpFP9x6mnLTCaoLkA==", + "cpu": [ + "ppc64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-ppc64-musl": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-musl/-/rollup-linux-ppc64-musl-4.59.0.tgz", + "integrity": "sha512-+2kLtQ4xT3AiIxkzFVFXfsmlZiG5FXYW7ZyIIvGA7Bdeuh9Z0aN4hVyXS/G1E9bTP/vqszNIN/pUKCk/BTHsKA==", + "cpu": [ + "ppc64" + ], + "dev": true, + "libc": [ + "musl" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-riscv64-gnu": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.59.0.tgz", + "integrity": "sha512-NDYMpsXYJJaj+I7UdwIuHHNxXZ/b/N2hR15NyH3m2qAtb/hHPA4g4SuuvrdxetTdndfj9b1WOmy73kcPRoERUg==", + "cpu": [ + "riscv64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-riscv64-musl": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.59.0.tgz", + "integrity": "sha512-nLckB8WOqHIf1bhymk+oHxvM9D3tyPndZH8i8+35p/1YiVoVswPid2yLzgX7ZJP0KQvnkhM4H6QZ5m0LzbyIAg==", + "cpu": [ + "riscv64" + ], + "dev": true, + "libc": [ + "musl" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-s390x-gnu": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.59.0.tgz", + "integrity": "sha512-oF87Ie3uAIvORFBpwnCvUzdeYUqi2wY6jRFWJAy1qus/udHFYIkplYRW+wo+GRUP4sKzYdmE1Y3+rY5Gc4ZO+w==", + "cpu": [ + "s390x" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-gnu": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.59.0.tgz", + "integrity": "sha512-3AHmtQq/ppNuUspKAlvA8HtLybkDflkMuLK4DPo77DfthRb71V84/c4MlWJXixZz4uruIH4uaa07IqoAkG64fg==", + "cpu": [ + "x64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-musl": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.59.0.tgz", + "integrity": "sha512-2UdiwS/9cTAx7qIUZB/fWtToJwvt0Vbo0zmnYt7ED35KPg13Q0ym1g442THLC7VyI6JfYTP4PiSOWyoMdV2/xg==", + "cpu": [ + "x64" + ], + "dev": true, + "libc": [ + "musl" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-openbsd-x64": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-openbsd-x64/-/rollup-openbsd-x64-4.59.0.tgz", + "integrity": "sha512-M3bLRAVk6GOwFlPTIxVBSYKUaqfLrn8l0psKinkCFxl4lQvOSz8ZrKDz2gxcBwHFpci0B6rttydI4IpS4IS/jQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ] + }, + "node_modules/@rollup/rollup-openharmony-arm64": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-openharmony-arm64/-/rollup-openharmony-arm64-4.59.0.tgz", + "integrity": "sha512-tt9KBJqaqp5i5HUZzoafHZX8b5Q2Fe7UjYERADll83O4fGqJ49O1FsL6LpdzVFQcpwvnyd0i+K/VSwu/o/nWlA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ] + }, + "node_modules/@rollup/rollup-win32-arm64-msvc": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.59.0.tgz", + "integrity": "sha512-V5B6mG7OrGTwnxaNUzZTDTjDS7F75PO1ae6MJYdiMu60sq0CqN5CVeVsbhPxalupvTX8gXVSU9gq+Rx1/hvu6A==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-ia32-msvc": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.59.0.tgz", + "integrity": "sha512-UKFMHPuM9R0iBegwzKF4y0C4J9u8C6MEJgFuXTBerMk7EJ92GFVFYBfOZaSGLu6COf7FxpQNqhNS4c4icUPqxA==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-x64-gnu": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-gnu/-/rollup-win32-x64-gnu-4.59.0.tgz", + "integrity": "sha512-laBkYlSS1n2L8fSo1thDNGrCTQMmxjYY5G0WFWjFFYZkKPjsMBsgJfGf4TLxXrF6RyhI60L8TMOjBMvXiTcxeA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-x64-msvc": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.59.0.tgz", + "integrity": "sha512-2HRCml6OztYXyJXAvdDXPKcawukWY2GpR5/nxKp4iBgiO3wcoEGkAaqctIbZcNB6KlUQBIqt8VYkNSj2397EfA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@standard-schema/spec": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@standard-schema/spec/-/spec-1.1.0.tgz", + "integrity": "sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w==", + "dev": true, + "license": "MIT" + }, + "node_modules/@sveltejs/acorn-typescript": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/@sveltejs/acorn-typescript/-/acorn-typescript-1.0.9.tgz", + "integrity": "sha512-lVJX6qEgs/4DOcRTpo56tmKzVPtoWAaVbL4hfO7t7NVwl9AAXzQR6cihesW1BmNMPl+bK6dreu2sOKBP2Q9CIA==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "acorn": "^8.9.0" + } + }, + "node_modules/@sveltejs/adapter-static": { + "version": "3.0.10", + "resolved": "https://registry.npmjs.org/@sveltejs/adapter-static/-/adapter-static-3.0.10.tgz", + "integrity": "sha512-7D9lYFWJmB7zxZyTE/qxjksvMqzMuYrrsyh1f4AlZqeZeACPRySjbC3aFiY55wb1tWUaKOQG9PVbm74JcN2Iew==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "@sveltejs/kit": "^2.0.0" + } + }, + "node_modules/@sveltejs/kit": { + "version": "2.55.0", + "resolved": "https://registry.npmjs.org/@sveltejs/kit/-/kit-2.55.0.tgz", + "integrity": "sha512-MdFRjevVxmAknf2NbaUkDF16jSIzXMWd4Nfah0Qp8TtQVoSp3bV4jKt8mX7z7qTUTWvgSaxtR0EG5WJf53gcuA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@standard-schema/spec": "^1.0.0", + "@sveltejs/acorn-typescript": "^1.0.5", + "@types/cookie": "^0.6.0", + "acorn": "^8.14.1", + "cookie": "^0.6.0", + "devalue": "^5.6.4", + "esm-env": "^1.2.2", + "kleur": "^4.1.5", + "magic-string": "^0.30.5", + "mrmime": "^2.0.0", + "set-cookie-parser": "^3.0.0", + "sirv": "^3.0.0" + }, + "bin": { + "svelte-kit": "svelte-kit.js" + }, + "engines": { + "node": ">=18.13" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.0.0", + "@sveltejs/vite-plugin-svelte": "^3.0.0 || ^4.0.0-next.1 || ^5.0.0 || ^6.0.0-next.0 || ^7.0.0", + "svelte": "^4.0.0 || ^5.0.0-next.0", + "typescript": "^5.3.3", + "vite": "^5.0.3 || ^6.0.0 || ^7.0.0-beta.0 || ^8.0.0" + }, + "peerDependenciesMeta": { + "@opentelemetry/api": { + "optional": true + }, + "typescript": { + "optional": true + } + } + }, + "node_modules/@sveltejs/vite-plugin-svelte": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/@sveltejs/vite-plugin-svelte/-/vite-plugin-svelte-5.1.1.tgz", + "integrity": "sha512-Y1Cs7hhTc+a5E9Va/xwKlAJoariQyHY+5zBgCZg4PFWNYQ1nMN9sjK1zhw1gK69DuqVP++sht/1GZg1aRwmAXQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@sveltejs/vite-plugin-svelte-inspector": "^4.0.1", + "debug": "^4.4.1", + "deepmerge": "^4.3.1", + "kleur": "^4.1.5", + "magic-string": "^0.30.17", + "vitefu": "^1.0.6" + }, + "engines": { + "node": "^18.0.0 || ^20.0.0 || >=22" + }, + "peerDependencies": { + "svelte": "^5.0.0", + "vite": "^6.0.0" + } + }, + "node_modules/@sveltejs/vite-plugin-svelte-inspector": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@sveltejs/vite-plugin-svelte-inspector/-/vite-plugin-svelte-inspector-4.0.1.tgz", + "integrity": "sha512-J/Nmb2Q2y7mck2hyCX4ckVHcR5tu2J+MtBEQqpDrrgELZ2uvraQcK/ioCV61AqkdXFgriksOKIceDcQmqnGhVw==", + "dev": true, + "license": "MIT", + "dependencies": { + "debug": "^4.3.7" + }, + "engines": { + "node": "^18.0.0 || ^20.0.0 || >=22" + }, + "peerDependencies": { + "@sveltejs/vite-plugin-svelte": "^5.0.0", + "svelte": "^5.0.0", + "vite": "^6.0.0" + } + }, + "node_modules/@tailwindcss/node": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/@tailwindcss/node/-/node-4.2.1.tgz", + "integrity": "sha512-jlx6sLk4EOwO6hHe1oCGm1Q4AN/s0rSrTTPBGPM0/RQ6Uylwq17FuU8IeJJKEjtc6K6O07zsvP+gDO6MMWo7pg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/remapping": "^2.3.5", + "enhanced-resolve": "^5.19.0", + "jiti": "^2.6.1", + "lightningcss": "1.31.1", + "magic-string": "^0.30.21", + "source-map-js": "^1.2.1", + "tailwindcss": "4.2.1" + } + }, + "node_modules/@tailwindcss/oxide": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide/-/oxide-4.2.1.tgz", + "integrity": "sha512-yv9jeEFWnjKCI6/T3Oq50yQEOqmpmpfzG1hcZsAOaXFQPfzWprWrlHSdGPEF3WQTi8zu8ohC9Mh9J470nT5pUw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 20" + }, + "optionalDependencies": { + "@tailwindcss/oxide-android-arm64": "4.2.1", + "@tailwindcss/oxide-darwin-arm64": "4.2.1", + "@tailwindcss/oxide-darwin-x64": "4.2.1", + "@tailwindcss/oxide-freebsd-x64": "4.2.1", + "@tailwindcss/oxide-linux-arm-gnueabihf": "4.2.1", + "@tailwindcss/oxide-linux-arm64-gnu": "4.2.1", + "@tailwindcss/oxide-linux-arm64-musl": "4.2.1", + "@tailwindcss/oxide-linux-x64-gnu": "4.2.1", + "@tailwindcss/oxide-linux-x64-musl": "4.2.1", + "@tailwindcss/oxide-wasm32-wasi": "4.2.1", + "@tailwindcss/oxide-win32-arm64-msvc": "4.2.1", + "@tailwindcss/oxide-win32-x64-msvc": "4.2.1" + } + }, + "node_modules/@tailwindcss/oxide-android-arm64": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-android-arm64/-/oxide-android-arm64-4.2.1.tgz", + "integrity": "sha512-eZ7G1Zm5EC8OOKaesIKuw77jw++QJ2lL9N+dDpdQiAB/c/B2wDh0QPFHbkBVrXnwNugvrbJFk1gK2SsVjwWReg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">= 20" + } + }, + "node_modules/@tailwindcss/oxide-darwin-arm64": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-darwin-arm64/-/oxide-darwin-arm64-4.2.1.tgz", + "integrity": "sha512-q/LHkOstoJ7pI1J0q6djesLzRvQSIfEto148ppAd+BVQK0JYjQIFSK3JgYZJa+Yzi0DDa52ZsQx2rqytBnf8Hw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 20" + } + }, + "node_modules/@tailwindcss/oxide-darwin-x64": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-darwin-x64/-/oxide-darwin-x64-4.2.1.tgz", + "integrity": "sha512-/f/ozlaXGY6QLbpvd/kFTro2l18f7dHKpB+ieXz+Cijl4Mt9AI2rTrpq7V+t04nK+j9XBQHnSMdeQRhbGyt6fw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 20" + } + }, + "node_modules/@tailwindcss/oxide-freebsd-x64": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-freebsd-x64/-/oxide-freebsd-x64-4.2.1.tgz", + "integrity": "sha512-5e/AkgYJT/cpbkys/OU2Ei2jdETCLlifwm7ogMC7/hksI2fC3iiq6OcXwjibcIjPung0kRtR3TxEITkqgn0TcA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">= 20" + } + }, + "node_modules/@tailwindcss/oxide-linux-arm-gnueabihf": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm-gnueabihf/-/oxide-linux-arm-gnueabihf-4.2.1.tgz", + "integrity": "sha512-Uny1EcVTTmerCKt/1ZuKTkb0x8ZaiuYucg2/kImO5A5Y/kBz41/+j0gxUZl+hTF3xkWpDmHX+TaWhOtba2Fyuw==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 20" + } + }, + "node_modules/@tailwindcss/oxide-linux-arm64-gnu": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm64-gnu/-/oxide-linux-arm64-gnu-4.2.1.tgz", + "integrity": "sha512-CTrwomI+c7n6aSSQlsPL0roRiNMDQ/YzMD9EjcR+H4f0I1SQ8QqIuPnsVp7QgMkC1Qi8rtkekLkOFjo7OlEFRQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 20" + } + }, + "node_modules/@tailwindcss/oxide-linux-arm64-musl": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm64-musl/-/oxide-linux-arm64-musl-4.2.1.tgz", + "integrity": "sha512-WZA0CHRL/SP1TRbA5mp9htsppSEkWuQ4KsSUumYQnyl8ZdT39ntwqmz4IUHGN6p4XdSlYfJwM4rRzZLShHsGAQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "libc": [ + "musl" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 20" + } + }, + "node_modules/@tailwindcss/oxide-linux-x64-gnu": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-x64-gnu/-/oxide-linux-x64-gnu-4.2.1.tgz", + "integrity": "sha512-qMFzxI2YlBOLW5PhblzuSWlWfwLHaneBE0xHzLrBgNtqN6mWfs+qYbhryGSXQjFYB1Dzf5w+LN5qbUTPhW7Y5g==", + "cpu": [ + "x64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 20" + } + }, + "node_modules/@tailwindcss/oxide-linux-x64-musl": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-x64-musl/-/oxide-linux-x64-musl-4.2.1.tgz", + "integrity": "sha512-5r1X2FKnCMUPlXTWRYpHdPYUY6a1Ar/t7P24OuiEdEOmms5lyqjDRvVY1yy9Rmioh+AunQ0rWiOTPE8F9A3v5g==", + "cpu": [ + "x64" + ], + "dev": true, + "libc": [ + "musl" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 20" + } + }, + "node_modules/@tailwindcss/oxide-wasm32-wasi": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-wasm32-wasi/-/oxide-wasm32-wasi-4.2.1.tgz", + "integrity": "sha512-MGFB5cVPvshR85MTJkEvqDUnuNoysrsRxd6vnk1Lf2tbiqNlXpHYZqkqOQalydienEWOHHFyyuTSYRsLfxFJ2Q==", + "bundleDependencies": [ + "@napi-rs/wasm-runtime", + "@emnapi/core", + "@emnapi/runtime", + "@tybys/wasm-util", + "@emnapi/wasi-threads", + "tslib" + ], + "cpu": [ + "wasm32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "@emnapi/core": "^1.8.1", + "@emnapi/runtime": "^1.8.1", + "@emnapi/wasi-threads": "^1.1.0", + "@napi-rs/wasm-runtime": "^1.1.1", + "@tybys/wasm-util": "^0.10.1", + "tslib": "^2.8.1" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@tailwindcss/oxide-win32-arm64-msvc": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-win32-arm64-msvc/-/oxide-win32-arm64-msvc-4.2.1.tgz", + "integrity": "sha512-YlUEHRHBGnCMh4Nj4GnqQyBtsshUPdiNroZj8VPkvTZSoHsilRCwXcVKnG9kyi0ZFAS/3u+qKHBdDc81SADTRA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 20" + } + }, + "node_modules/@tailwindcss/oxide-win32-x64-msvc": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-win32-x64-msvc/-/oxide-win32-x64-msvc-4.2.1.tgz", + "integrity": "sha512-rbO34G5sMWWyrN/idLeVxAZgAKWrn5LiR3/I90Q9MkA67s6T1oB0xtTe+0heoBvHSpbU9Mk7i6uwJnpo4u21XQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 20" + } + }, + "node_modules/@tailwindcss/vite": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/@tailwindcss/vite/-/vite-4.2.1.tgz", + "integrity": "sha512-TBf2sJjYeb28jD2U/OhwdW0bbOsxkWPwQ7SrqGf9sVcoYwZj7rkXljroBO9wKBut9XnmQLXanuDUeqQK0lGg/w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@tailwindcss/node": "4.2.1", + "@tailwindcss/oxide": "4.2.1", + "tailwindcss": "4.2.1" + }, + "peerDependencies": { + "vite": "^5.2.0 || ^6 || ^7" + } + }, + "node_modules/@tauri-apps/api": { + "version": "2.10.1", + "resolved": "https://registry.npmjs.org/@tauri-apps/api/-/api-2.10.1.tgz", + "integrity": "sha512-hKL/jWf293UDSUN09rR69hrToyIXBb8CjGaWC7gfinvnQrBVvnLr08FeFi38gxtugAVyVcTa5/FD/Xnkb1siBw==", + "license": "Apache-2.0 OR MIT", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/tauri" + } + }, + "node_modules/@tauri-apps/cli": { + "version": "2.10.1", + "resolved": "https://registry.npmjs.org/@tauri-apps/cli/-/cli-2.10.1.tgz", + "integrity": "sha512-jQNGF/5quwORdZSSLtTluyKQ+o6SMa/AUICfhf4egCGFdMHqWssApVgYSbg+jmrZoc8e1DscNvjTnXtlHLS11g==", + "dev": true, + "license": "Apache-2.0 OR MIT", + "bin": { + "tauri": "tauri.js" + }, + "engines": { + "node": ">= 10" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/tauri" + }, + "optionalDependencies": { + "@tauri-apps/cli-darwin-arm64": "2.10.1", + "@tauri-apps/cli-darwin-x64": "2.10.1", + "@tauri-apps/cli-linux-arm-gnueabihf": "2.10.1", + "@tauri-apps/cli-linux-arm64-gnu": "2.10.1", + "@tauri-apps/cli-linux-arm64-musl": "2.10.1", + "@tauri-apps/cli-linux-riscv64-gnu": "2.10.1", + "@tauri-apps/cli-linux-x64-gnu": "2.10.1", + "@tauri-apps/cli-linux-x64-musl": "2.10.1", + "@tauri-apps/cli-win32-arm64-msvc": "2.10.1", + "@tauri-apps/cli-win32-ia32-msvc": "2.10.1", + "@tauri-apps/cli-win32-x64-msvc": "2.10.1" + } + }, + "node_modules/@tauri-apps/cli-darwin-arm64": { + "version": "2.10.1", + "resolved": "https://registry.npmjs.org/@tauri-apps/cli-darwin-arm64/-/cli-darwin-arm64-2.10.1.tgz", + "integrity": "sha512-Z2OjCXiZ+fbYZy7PmP3WRnOpM9+Fy+oonKDEmUE6MwN4IGaYqgceTjwHucc/kEEYZos5GICve35f7ZiizgqEnQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "Apache-2.0 OR MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tauri-apps/cli-darwin-x64": { + "version": "2.10.1", + "resolved": "https://registry.npmjs.org/@tauri-apps/cli-darwin-x64/-/cli-darwin-x64-2.10.1.tgz", + "integrity": "sha512-V/irQVvjPMGOTQqNj55PnQPVuH4VJP8vZCN7ajnj+ZS8Kom1tEM2hR3qbbIRoS3dBKs5mbG8yg1WC+97dq17Pw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "Apache-2.0 OR MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tauri-apps/cli-linux-arm-gnueabihf": { + "version": "2.10.1", + "resolved": "https://registry.npmjs.org/@tauri-apps/cli-linux-arm-gnueabihf/-/cli-linux-arm-gnueabihf-2.10.1.tgz", + "integrity": "sha512-Hyzwsb4VnCWKGfTw+wSt15Z2pLw2f0JdFBfq2vHBOBhvg7oi6uhKiF87hmbXOBXUZaGkyRDkCHsdzJcIfoJC2w==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "Apache-2.0 OR MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tauri-apps/cli-linux-arm64-gnu": { + "version": "2.10.1", + "resolved": "https://registry.npmjs.org/@tauri-apps/cli-linux-arm64-gnu/-/cli-linux-arm64-gnu-2.10.1.tgz", + "integrity": "sha512-OyOYs2t5GkBIvyWjA1+h4CZxTcdz1OZPCWAPz5DYEfB0cnWHERTnQ/SLayQzncrT0kwRoSfSz9KxenkyJoTelA==", + "cpu": [ + "arm64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "Apache-2.0 OR MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tauri-apps/cli-linux-arm64-musl": { + "version": "2.10.1", + "resolved": "https://registry.npmjs.org/@tauri-apps/cli-linux-arm64-musl/-/cli-linux-arm64-musl-2.10.1.tgz", + "integrity": "sha512-MIj78PDDGjkg3NqGptDOGgfXks7SYJwhiMh8SBoZS+vfdz7yP5jN18bNaLnDhsVIPARcAhE1TlsZe/8Yxo2zqg==", + "cpu": [ + "arm64" + ], + "dev": true, + "libc": [ + "musl" + ], + "license": "Apache-2.0 OR MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tauri-apps/cli-linux-riscv64-gnu": { + "version": "2.10.1", + "resolved": "https://registry.npmjs.org/@tauri-apps/cli-linux-riscv64-gnu/-/cli-linux-riscv64-gnu-2.10.1.tgz", + "integrity": "sha512-X0lvOVUg8PCVaoEtEAnpxmnkwlE1gcMDTqfhbefICKDnOTJ5Est3qL0SrWxizDackIOKBcvtpejrSiVpuJI1kw==", + "cpu": [ + "riscv64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "Apache-2.0 OR MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tauri-apps/cli-linux-x64-gnu": { + "version": "2.10.1", + "resolved": "https://registry.npmjs.org/@tauri-apps/cli-linux-x64-gnu/-/cli-linux-x64-gnu-2.10.1.tgz", + "integrity": "sha512-2/12bEzsJS9fAKybxgicCDFxYD1WEI9kO+tlDwX5znWG2GwMBaiWcmhGlZ8fi+DMe9CXlcVarMTYc0L3REIRxw==", + "cpu": [ + "x64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "Apache-2.0 OR MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tauri-apps/cli-linux-x64-musl": { + "version": "2.10.1", + "resolved": "https://registry.npmjs.org/@tauri-apps/cli-linux-x64-musl/-/cli-linux-x64-musl-2.10.1.tgz", + "integrity": "sha512-Y8J0ZzswPz50UcGOFuXGEMrxbjwKSPgXftx5qnkuMs2rmwQB5ssvLb6tn54wDSYxe7S6vlLob9vt0VKuNOaCIQ==", + "cpu": [ + "x64" + ], + "dev": true, + "libc": [ + "musl" + ], + "license": "Apache-2.0 OR MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tauri-apps/cli-win32-arm64-msvc": { + "version": "2.10.1", + "resolved": "https://registry.npmjs.org/@tauri-apps/cli-win32-arm64-msvc/-/cli-win32-arm64-msvc-2.10.1.tgz", + "integrity": "sha512-iSt5B86jHYAPJa/IlYw++SXtFPGnWtFJriHn7X0NFBVunF6zu9+/zOn8OgqIWSl8RgzhLGXQEEtGBdR4wzpVgg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "Apache-2.0 OR MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tauri-apps/cli-win32-ia32-msvc": { + "version": "2.10.1", + "resolved": "https://registry.npmjs.org/@tauri-apps/cli-win32-ia32-msvc/-/cli-win32-ia32-msvc-2.10.1.tgz", + "integrity": "sha512-gXyxgEzsFegmnWywYU5pEBURkcFN/Oo45EAwvZrHMh+zUSEAvO5E8TXsgPADYm31d1u7OQU3O3HsYfVBf2moHw==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "Apache-2.0 OR MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tauri-apps/cli-win32-x64-msvc": { + "version": "2.10.1", + "resolved": "https://registry.npmjs.org/@tauri-apps/cli-win32-x64-msvc/-/cli-win32-x64-msvc-2.10.1.tgz", + "integrity": "sha512-6Cn7YpPFwzChy0ERz6djKEmUehWrYlM+xTaNzGPgZocw3BD7OfwfWHKVWxXzdjEW2KfKkHddfdxK1XXTYqBRLg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "Apache-2.0 OR MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tauri-apps/plugin-dialog": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/@tauri-apps/plugin-dialog/-/plugin-dialog-2.6.0.tgz", + "integrity": "sha512-q4Uq3eY87TdcYzXACiYSPhmpBA76shgmQswGkSVio4C82Sz2W4iehe9TnKYwbq7weHiL88Yw19XZm7v28+Micg==", + "license": "MIT OR Apache-2.0", + "dependencies": { + "@tauri-apps/api": "^2.8.0" + } + }, + "node_modules/@tauri-apps/plugin-global-shortcut": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/@tauri-apps/plugin-global-shortcut/-/plugin-global-shortcut-2.3.1.tgz", + "integrity": "sha512-vr40W2N6G63dmBPaha1TsBQLLURXG538RQbH5vAm0G/ovVZyXJrmZR1HF1W+WneNloQvwn4dm8xzwpEXRW560g==", + "license": "MIT OR Apache-2.0", + "dependencies": { + "@tauri-apps/api": "^2.8.0" + } + }, + "node_modules/@tauri-apps/plugin-opener": { + "version": "2.5.3", + "resolved": "https://registry.npmjs.org/@tauri-apps/plugin-opener/-/plugin-opener-2.5.3.tgz", + "integrity": "sha512-CCcUltXMOfUEArbf3db3kCE7Ggy1ExBEBl51Ko2ODJ6GDYHRp1nSNlQm5uNCFY5k7/ufaK5Ib3Du/Zir19IYQQ==", + "license": "MIT OR Apache-2.0", + "dependencies": { + "@tauri-apps/api": "^2.8.0" + } + }, + "node_modules/@types/cookie": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/@types/cookie/-/cookie-0.6.0.tgz", + "integrity": "sha512-4Kh9a6B2bQciAhf7FSuMRRkUWecJgJu9nPnx3yzpsfXX/c50REIqpHY4C82bXP90qrLtXtkDxTZosYO3UpOwlA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/estree": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz", + "integrity": "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/trusted-types": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/@types/trusted-types/-/trusted-types-2.0.7.tgz", + "integrity": "sha512-ScaPdn1dQczgbl0QFTeTOmVHFULt394XJgOQNoyVhZ6r2vLnMLJfBPd53SB52T/3G36VI1/g2MZaX0cwDuXsfw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@typescript-eslint/types": { + "version": "8.57.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.57.1.tgz", + "integrity": "sha512-S29BOBPJSFUiblEl6RzPPjJt6w25A6XsBqRVDt53tA/tlL8q7ceQNZHTjPeONt/3S7KRI4quk+yP9jK2WjBiPQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/acorn": { + "version": "8.16.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.16.0.tgz", + "integrity": "sha512-UVJyE9MttOsBQIDKw1skb9nAwQuR5wuGD3+82K6JgJlm/Y+KI92oNsMNGZCYdDsVtRHSak0pcV5Dno5+4jh9sw==", + "dev": true, + "license": "MIT", + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/aria-query": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-5.3.1.tgz", + "integrity": "sha512-Z/ZeOgVl7bcSYZ/u/rh0fOpvEpq//LZmdbkXyc7syVzjPAhfOa9ebsdTSjEBDU4vs5nC98Kfduj1uFo0qyET3g==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/axobject-query": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/axobject-query/-/axobject-query-4.1.0.tgz", + "integrity": "sha512-qIj0G9wZbMGNLjLmg1PT6v2mE9AH2zlnADJD/2tC6E00hgmhUOfEB6greHPAfLRSufHqROIUTkw6E+M3lH0PTQ==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/chokidar": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-4.0.3.tgz", + "integrity": "sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==", + "dev": true, + "license": "MIT", + "dependencies": { + "readdirp": "^4.0.1" + }, + "engines": { + "node": ">= 14.16.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/clsx": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/clsx/-/clsx-2.1.1.tgz", + "integrity": "sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/cookie": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.6.0.tgz", + "integrity": "sha512-U71cyTamuh1CRNCfpGY6to28lxvNwPG4Guz/EVjgf3Jmzv0vlDp1atT9eS5dDjMYHucpHbWns6Lwf3BKz6svdw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/debug": { + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", + "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/deepmerge": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.3.1.tgz", + "integrity": "sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/detect-libc": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.1.2.tgz", + "integrity": "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=8" + } + }, + "node_modules/devalue": { + "version": "5.6.4", + "resolved": "https://registry.npmjs.org/devalue/-/devalue-5.6.4.tgz", + "integrity": "sha512-Gp6rDldRsFh/7XuouDbxMH3Mx8GMCcgzIb1pDTvNyn8pZGQ22u+Wa+lGV9dQCltFQ7uVw0MhRyb8XDskNFOReA==", + "dev": true, + "license": "MIT" + }, + "node_modules/enhanced-resolve": { + "version": "5.20.0", + "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.20.0.tgz", + "integrity": "sha512-/ce7+jQ1PQ6rVXwe+jKEg5hW5ciicHwIQUagZkp6IufBoY3YDgdTTY1azVs0qoRgVmvsNB+rbjLJxDAeHHtwsQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "graceful-fs": "^4.2.4", + "tapable": "^2.3.0" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/esbuild": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.12.tgz", + "integrity": "sha512-bbPBYYrtZbkt6Os6FiTLCTFxvq4tt3JKall1vRwshA3fdVztsLAatFaZobhkBC8/BrPetoa0oksYoKXoG4ryJg==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=18" + }, + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.25.12", + "@esbuild/android-arm": "0.25.12", + "@esbuild/android-arm64": "0.25.12", + "@esbuild/android-x64": "0.25.12", + "@esbuild/darwin-arm64": "0.25.12", + "@esbuild/darwin-x64": "0.25.12", + "@esbuild/freebsd-arm64": "0.25.12", + "@esbuild/freebsd-x64": "0.25.12", + "@esbuild/linux-arm": "0.25.12", + "@esbuild/linux-arm64": "0.25.12", + "@esbuild/linux-ia32": "0.25.12", + "@esbuild/linux-loong64": "0.25.12", + "@esbuild/linux-mips64el": "0.25.12", + "@esbuild/linux-ppc64": "0.25.12", + "@esbuild/linux-riscv64": "0.25.12", + "@esbuild/linux-s390x": "0.25.12", + "@esbuild/linux-x64": "0.25.12", + "@esbuild/netbsd-arm64": "0.25.12", + "@esbuild/netbsd-x64": "0.25.12", + "@esbuild/openbsd-arm64": "0.25.12", + "@esbuild/openbsd-x64": "0.25.12", + "@esbuild/openharmony-arm64": "0.25.12", + "@esbuild/sunos-x64": "0.25.12", + "@esbuild/win32-arm64": "0.25.12", + "@esbuild/win32-ia32": "0.25.12", + "@esbuild/win32-x64": "0.25.12" + } + }, + "node_modules/esm-env": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/esm-env/-/esm-env-1.2.2.tgz", + "integrity": "sha512-Epxrv+Nr/CaL4ZcFGPJIYLWFom+YeV1DqMLHJoEd9SYRxNbaFruBwfEX/kkHUJf55j2+TUbmDcmuilbP1TmXHA==", + "dev": true, + "license": "MIT" + }, + "node_modules/esrap": { + "version": "2.2.4", + "resolved": "https://registry.npmjs.org/esrap/-/esrap-2.2.4.tgz", + "integrity": "sha512-suICpxAmZ9A8bzJjEl/+rLJiDKC0X4gYWUxT6URAWBLvlXmtbZd5ySMu/N2ZGEtMCAmflUDPSehrP9BQcsGcSg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.4.15", + "@typescript-eslint/types": "^8.2.0" + } + }, + "node_modules/fdir": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz", + "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12.0.0" + }, + "peerDependencies": { + "picomatch": "^3 || ^4" + }, + "peerDependenciesMeta": { + "picomatch": { + "optional": true + } + } + }, + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/graceful-fs": { + "version": "4.2.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/is-reference": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/is-reference/-/is-reference-3.0.3.tgz", + "integrity": "sha512-ixkJoqQvAP88E6wLydLGGqCJsrFUnqoH6HnaczB8XmDH1oaWU+xxdptvikTgaEhtZ53Ky6YXiBuUI2WXLMCwjw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/estree": "^1.0.6" + } + }, + "node_modules/jiti": { + "version": "2.6.1", + "resolved": "https://registry.npmjs.org/jiti/-/jiti-2.6.1.tgz", + "integrity": "sha512-ekilCSN1jwRvIbgeg/57YFh8qQDNbwDb9xT/qu2DAHbFFZUicIl4ygVaAvzveMhMVr3LnpSKTNnwt8PoOfmKhQ==", + "dev": true, + "license": "MIT", + "bin": { + "jiti": "lib/jiti-cli.mjs" + } + }, + "node_modules/kleur": { + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/kleur/-/kleur-4.1.5.tgz", + "integrity": "sha512-o+NO+8WrRiQEE4/7nwRJhN1HWpVmJm511pBHUxPLtp0BUISzlBplORYSmTclCnJvQq2tKu/sgl3xVpkc7ZWuQQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/lightningcss": { + "version": "1.31.1", + "resolved": "https://registry.npmjs.org/lightningcss/-/lightningcss-1.31.1.tgz", + "integrity": "sha512-l51N2r93WmGUye3WuFoN5k10zyvrVs0qfKBhyC5ogUQ6Ew6JUSswh78mbSO+IU3nTWsyOArqPCcShdQSadghBQ==", + "dev": true, + "license": "MPL-2.0", + "dependencies": { + "detect-libc": "^2.0.3" + }, + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + }, + "optionalDependencies": { + "lightningcss-android-arm64": "1.31.1", + "lightningcss-darwin-arm64": "1.31.1", + "lightningcss-darwin-x64": "1.31.1", + "lightningcss-freebsd-x64": "1.31.1", + "lightningcss-linux-arm-gnueabihf": "1.31.1", + "lightningcss-linux-arm64-gnu": "1.31.1", + "lightningcss-linux-arm64-musl": "1.31.1", + "lightningcss-linux-x64-gnu": "1.31.1", + "lightningcss-linux-x64-musl": "1.31.1", + "lightningcss-win32-arm64-msvc": "1.31.1", + "lightningcss-win32-x64-msvc": "1.31.1" + } + }, + "node_modules/lightningcss-android-arm64": { + "version": "1.31.1", + "resolved": "https://registry.npmjs.org/lightningcss-android-arm64/-/lightningcss-android-arm64-1.31.1.tgz", + "integrity": "sha512-HXJF3x8w9nQ4jbXRiNppBCqeZPIAfUo8zE/kOEGbW5NZvGc/K7nMxbhIr+YlFlHW5mpbg/YFPdbnCh1wAXCKFg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-darwin-arm64": { + "version": "1.31.1", + "resolved": "https://registry.npmjs.org/lightningcss-darwin-arm64/-/lightningcss-darwin-arm64-1.31.1.tgz", + "integrity": "sha512-02uTEqf3vIfNMq3h/z2cJfcOXnQ0GRwQrkmPafhueLb2h7mqEidiCzkE4gBMEH65abHRiQvhdcQ+aP0D0g67sg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-darwin-x64": { + "version": "1.31.1", + "resolved": "https://registry.npmjs.org/lightningcss-darwin-x64/-/lightningcss-darwin-x64-1.31.1.tgz", + "integrity": "sha512-1ObhyoCY+tGxtsz1lSx5NXCj3nirk0Y0kB/g8B8DT+sSx4G9djitg9ejFnjb3gJNWo7qXH4DIy2SUHvpoFwfTA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-freebsd-x64": { + "version": "1.31.1", + "resolved": "https://registry.npmjs.org/lightningcss-freebsd-x64/-/lightningcss-freebsd-x64-1.31.1.tgz", + "integrity": "sha512-1RINmQKAItO6ISxYgPwszQE1BrsVU5aB45ho6O42mu96UiZBxEXsuQ7cJW4zs4CEodPUioj/QrXW1r9pLUM74A==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-arm-gnueabihf": { + "version": "1.31.1", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm-gnueabihf/-/lightningcss-linux-arm-gnueabihf-1.31.1.tgz", + "integrity": "sha512-OOCm2//MZJ87CdDK62rZIu+aw9gBv4azMJuA8/KB74wmfS3lnC4yoPHm0uXZ/dvNNHmnZnB8XLAZzObeG0nS1g==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-arm64-gnu": { + "version": "1.31.1", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-gnu/-/lightningcss-linux-arm64-gnu-1.31.1.tgz", + "integrity": "sha512-WKyLWztD71rTnou4xAD5kQT+982wvca7E6QoLpoawZ1gP9JM0GJj4Tp5jMUh9B3AitHbRZ2/H3W5xQmdEOUlLg==", + "cpu": [ + "arm64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-arm64-musl": { + "version": "1.31.1", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-musl/-/lightningcss-linux-arm64-musl-1.31.1.tgz", + "integrity": "sha512-mVZ7Pg2zIbe3XlNbZJdjs86YViQFoJSpc41CbVmKBPiGmC4YrfeOyz65ms2qpAobVd7WQsbW4PdsSJEMymyIMg==", + "cpu": [ + "arm64" + ], + "dev": true, + "libc": [ + "musl" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-x64-gnu": { + "version": "1.31.1", + "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-gnu/-/lightningcss-linux-x64-gnu-1.31.1.tgz", + "integrity": "sha512-xGlFWRMl+0KvUhgySdIaReQdB4FNudfUTARn7q0hh/V67PVGCs3ADFjw+6++kG1RNd0zdGRlEKa+T13/tQjPMA==", + "cpu": [ + "x64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-x64-musl": { + "version": "1.31.1", + "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-musl/-/lightningcss-linux-x64-musl-1.31.1.tgz", + "integrity": "sha512-eowF8PrKHw9LpoZii5tdZwnBcYDxRw2rRCyvAXLi34iyeYfqCQNA9rmUM0ce62NlPhCvof1+9ivRaTY6pSKDaA==", + "cpu": [ + "x64" + ], + "dev": true, + "libc": [ + "musl" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-win32-arm64-msvc": { + "version": "1.31.1", + "resolved": "https://registry.npmjs.org/lightningcss-win32-arm64-msvc/-/lightningcss-win32-arm64-msvc-1.31.1.tgz", + "integrity": "sha512-aJReEbSEQzx1uBlQizAOBSjcmr9dCdL3XuC/6HLXAxmtErsj2ICo5yYggg1qOODQMtnjNQv2UHb9NpOuFtYe4w==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-win32-x64-msvc": { + "version": "1.31.1", + "resolved": "https://registry.npmjs.org/lightningcss-win32-x64-msvc/-/lightningcss-win32-x64-msvc-1.31.1.tgz", + "integrity": "sha512-I9aiFrbd7oYHwlnQDqr1Roz+fTz61oDDJX7n9tYF9FJymH1cIN1DtKw3iYt6b8WZgEjoNwVSncwF4wx/ZedMhw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/locate-character": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/locate-character/-/locate-character-3.0.0.tgz", + "integrity": "sha512-SW13ws7BjaeJ6p7Q6CO2nchbYEc3X3J6WrmTTDto7yMPqVSZTUyY5Tjbid+Ab8gLnATtygYtiDIJGQRRn2ZOiA==", + "dev": true, + "license": "MIT" + }, + "node_modules/magic-string": { + "version": "0.30.21", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.21.tgz", + "integrity": "sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.5.5" + } + }, + "node_modules/mri": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/mri/-/mri-1.2.0.tgz", + "integrity": "sha512-tzzskb3bG8LvYGFF/mDTpq3jpI6Q9wc3LEmBaghu+DdCssd1FakN7Bc0hVNmEyGq1bq3RgfkCb3cmQLpNPOroA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/mrmime": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/mrmime/-/mrmime-2.0.1.tgz", + "integrity": "sha512-Y3wQdFg2Va6etvQ5I82yUhGdsKrcYox6p7FfL1LbK2J4V01F9TGlepTIhnK24t7koZibmg82KGglhA1XK5IsLQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + } + }, + "node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true, + "license": "MIT" + }, + "node_modules/nanoid": { + "version": "3.3.11", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz", + "integrity": "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, + "node_modules/picocolors": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", + "dev": true, + "license": "ISC" + }, + "node_modules/picomatch": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", + "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/postcss": { + "version": "8.5.8", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.8.tgz", + "integrity": "sha512-OW/rX8O/jXnm82Ey1k44pObPtdblfiuWnrd8X7GJ7emImCOstunGbXUpp7HdBrFQX6rJzn3sPT397Wp5aCwCHg==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "nanoid": "^3.3.11", + "picocolors": "^1.1.1", + "source-map-js": "^1.2.1" + }, + "engines": { + "node": "^10 || ^12 || >=14" + } + }, + "node_modules/readdirp": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-4.1.2.tgz", + "integrity": "sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 14.18.0" + }, + "funding": { + "type": "individual", + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/rollup": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.59.0.tgz", + "integrity": "sha512-2oMpl67a3zCH9H79LeMcbDhXW/UmWG/y2zuqnF2jQq5uq9TbM9TVyXvA4+t+ne2IIkBdrLpAaRQAvo7YI/Yyeg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/estree": "1.0.8" + }, + "bin": { + "rollup": "dist/bin/rollup" + }, + "engines": { + "node": ">=18.0.0", + "npm": ">=8.0.0" + }, + "optionalDependencies": { + "@rollup/rollup-android-arm-eabi": "4.59.0", + "@rollup/rollup-android-arm64": "4.59.0", + "@rollup/rollup-darwin-arm64": "4.59.0", + "@rollup/rollup-darwin-x64": "4.59.0", + "@rollup/rollup-freebsd-arm64": "4.59.0", + "@rollup/rollup-freebsd-x64": "4.59.0", + "@rollup/rollup-linux-arm-gnueabihf": "4.59.0", + "@rollup/rollup-linux-arm-musleabihf": "4.59.0", + "@rollup/rollup-linux-arm64-gnu": "4.59.0", + "@rollup/rollup-linux-arm64-musl": "4.59.0", + "@rollup/rollup-linux-loong64-gnu": "4.59.0", + "@rollup/rollup-linux-loong64-musl": "4.59.0", + "@rollup/rollup-linux-ppc64-gnu": "4.59.0", + "@rollup/rollup-linux-ppc64-musl": "4.59.0", + "@rollup/rollup-linux-riscv64-gnu": "4.59.0", + "@rollup/rollup-linux-riscv64-musl": "4.59.0", + "@rollup/rollup-linux-s390x-gnu": "4.59.0", + "@rollup/rollup-linux-x64-gnu": "4.59.0", + "@rollup/rollup-linux-x64-musl": "4.59.0", + "@rollup/rollup-openbsd-x64": "4.59.0", + "@rollup/rollup-openharmony-arm64": "4.59.0", + "@rollup/rollup-win32-arm64-msvc": "4.59.0", + "@rollup/rollup-win32-ia32-msvc": "4.59.0", + "@rollup/rollup-win32-x64-gnu": "4.59.0", + "@rollup/rollup-win32-x64-msvc": "4.59.0", + "fsevents": "~2.3.2" + } + }, + "node_modules/sade": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/sade/-/sade-1.8.1.tgz", + "integrity": "sha512-xal3CZX1Xlo/k4ApwCFrHVACi9fBqJ7V+mwhBsuf/1IOKbBy098Fex+Wa/5QMubw09pSZ/u8EY8PWgevJsXp1A==", + "dev": true, + "license": "MIT", + "dependencies": { + "mri": "^1.1.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/set-cookie-parser": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/set-cookie-parser/-/set-cookie-parser-3.0.1.tgz", + "integrity": "sha512-n7Z7dXZhJbwuAHhNzkTti6Aw9QDDjZtm3JTpTGATIdNzdQz5GuFs22w90BcvF4INfnrL5xrX3oGsuqO5Dx3A1Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/sirv": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/sirv/-/sirv-3.0.2.tgz", + "integrity": "sha512-2wcC/oGxHis/BoHkkPwldgiPSYcpZK3JU28WoMVv55yHJgcZ8rlXvuG9iZggz+sU1d4bRgIGASwyWqjxu3FM0g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@polka/url": "^1.0.0-next.24", + "mrmime": "^2.0.0", + "totalist": "^3.0.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/source-map-js": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", + "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/svelte": { + "version": "5.53.12", + "resolved": "https://registry.npmjs.org/svelte/-/svelte-5.53.12.tgz", + "integrity": "sha512-4x/uk4rQe/d7RhfvS8wemTfNjQ0bJbKvamIzRBfTe2eHHjzBZ7PZicUQrC2ryj83xxEacfA1zHKd1ephD1tAxA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/remapping": "^2.3.4", + "@jridgewell/sourcemap-codec": "^1.5.0", + "@sveltejs/acorn-typescript": "^1.0.5", + "@types/estree": "^1.0.5", + "@types/trusted-types": "^2.0.7", + "acorn": "^8.12.1", + "aria-query": "5.3.1", + "axobject-query": "^4.1.0", + "clsx": "^2.1.1", + "devalue": "^5.6.4", + "esm-env": "^1.2.1", + "esrap": "^2.2.2", + "is-reference": "^3.0.3", + "locate-character": "^3.0.0", + "magic-string": "^0.30.11", + "zimmerframe": "^1.1.2" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/svelte-check": { + "version": "4.4.5", + "resolved": "https://registry.npmjs.org/svelte-check/-/svelte-check-4.4.5.tgz", + "integrity": "sha512-1bSwIRCvvmSHrlK52fOlZmVtUZgil43jNL/2H18pRpa+eQjzGt6e3zayxhp1S7GajPFKNM/2PMCG+DZFHlG9fw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/trace-mapping": "^0.3.25", + "chokidar": "^4.0.1", + "fdir": "^6.2.0", + "picocolors": "^1.0.0", + "sade": "^1.7.4" + }, + "bin": { + "svelte-check": "bin/svelte-check" + }, + "engines": { + "node": ">= 18.0.0" + }, + "peerDependencies": { + "svelte": "^4.0.0 || ^5.0.0-next.0", + "typescript": ">=5.0.0" + } + }, + "node_modules/tailwindcss": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-4.2.1.tgz", + "integrity": "sha512-/tBrSQ36vCleJkAOsy9kbNTgaxvGbyOamC30PRePTQe/o1MFwEKHQk4Cn7BNGaPtjp+PuUrByJehM1hgxfq4sw==", + "dev": true, + "license": "MIT" + }, + "node_modules/tapable": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.3.0.tgz", + "integrity": "sha512-g9ljZiwki/LfxmQADO3dEY1CbpmXT5Hm2fJ+QaGKwSXUylMybePR7/67YW7jOrrvjEgL1Fmz5kzyAjWVWLlucg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, + "node_modules/tinyglobby": { + "version": "0.2.15", + "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.15.tgz", + "integrity": "sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "fdir": "^6.5.0", + "picomatch": "^4.0.3" + }, + "engines": { + "node": ">=12.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/SuperchupuDev" + } + }, + "node_modules/totalist": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/totalist/-/totalist-3.0.1.tgz", + "integrity": "sha512-sf4i37nQ2LBx4m3wB74y+ubopq6W/dIzXg0FDGjsYnZHVa1Da8FH853wlL2gtUhg+xJXjfk3kUZS3BRoQeoQBQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/typescript": { + "version": "5.6.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.6.3.tgz", + "integrity": "sha512-hjcS1mhfuyi4WW8IWtjP7brDrG2cuDZukyrYrSauoXGNgx0S7zceP07adYkJycEr56BOUTNPzbInooiN3fn1qw==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/vite": { + "version": "6.4.1", + "resolved": "https://registry.npmjs.org/vite/-/vite-6.4.1.tgz", + "integrity": "sha512-+Oxm7q9hDoLMyJOYfUYBuHQo+dkAloi33apOPP56pzj+vsdJDzr+j1NISE5pyaAuKL4A3UD34qd0lx5+kfKp2g==", + "dev": true, + "license": "MIT", + "dependencies": { + "esbuild": "^0.25.0", + "fdir": "^6.4.4", + "picomatch": "^4.0.2", + "postcss": "^8.5.3", + "rollup": "^4.34.9", + "tinyglobby": "^0.2.13" + }, + "bin": { + "vite": "bin/vite.js" + }, + "engines": { + "node": "^18.0.0 || ^20.0.0 || >=22.0.0" + }, + "funding": { + "url": "https://github.com/vitejs/vite?sponsor=1" + }, + "optionalDependencies": { + "fsevents": "~2.3.3" + }, + "peerDependencies": { + "@types/node": "^18.0.0 || ^20.0.0 || >=22.0.0", + "jiti": ">=1.21.0", + "less": "*", + "lightningcss": "^1.21.0", + "sass": "*", + "sass-embedded": "*", + "stylus": "*", + "sugarss": "*", + "terser": "^5.16.0", + "tsx": "^4.8.1", + "yaml": "^2.4.2" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + }, + "jiti": { + "optional": true + }, + "less": { + "optional": true + }, + "lightningcss": { + "optional": true + }, + "sass": { + "optional": true + }, + "sass-embedded": { + "optional": true + }, + "stylus": { + "optional": true + }, + "sugarss": { + "optional": true + }, + "terser": { + "optional": true + }, + "tsx": { + "optional": true + }, + "yaml": { + "optional": true + } + } + }, + "node_modules/vitefu": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/vitefu/-/vitefu-1.1.2.tgz", + "integrity": "sha512-zpKATdUbzbsycPFBN71nS2uzBUQiVnFoOrr2rvqv34S1lcAgMKKkjWleLGeiJlZ8lwCXvtWaRn7R3ZC16SYRuw==", + "dev": true, + "license": "MIT", + "workspaces": [ + "tests/deps/*", + "tests/projects/*", + "tests/projects/workspace/packages/*" + ], + "peerDependencies": { + "vite": "^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-beta.0" + }, + "peerDependenciesMeta": { + "vite": { + "optional": true + } + } + }, + "node_modules/zimmerframe": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/zimmerframe/-/zimmerframe-1.1.4.tgz", + "integrity": "sha512-B58NGBEoc8Y9MWWCQGl/gq9xBCe4IiKM0a2x7GZdQKOW5Exr8S1W24J6OgM1njK8xCRGvAJIL/MxXHf6SkmQKQ==", + "dev": true, + "license": "MIT" + } + } +} diff --git a/package.json b/package.json new file mode 100644 index 0000000..b8c845c --- /dev/null +++ b/package.json @@ -0,0 +1,33 @@ +{ + "name": "kon", + "version": "0.1.0", + "description": "Kon — Think out loud", + "type": "module", + "scripts": { + "dev": "vite dev", + "build": "vite build", + "preview": "vite preview", + "check": "svelte-kit sync && svelte-check --tsconfig ./jsconfig.json", + "check:watch": "svelte-kit sync && svelte-check --tsconfig ./jsconfig.json --watch", + "tauri": "tauri" + }, + "license": "MIT", + "dependencies": { + "@tauri-apps/api": "^2", + "@tauri-apps/plugin-dialog": "^2.6.0", + "@tauri-apps/plugin-global-shortcut": "^2.3.1", + "@tauri-apps/plugin-opener": "^2" + }, + "devDependencies": { + "@sveltejs/adapter-static": "^3.0.6", + "@sveltejs/kit": "^2.9.0", + "@sveltejs/vite-plugin-svelte": "^5.0.0", + "@tailwindcss/vite": "^4.2.1", + "@tauri-apps/cli": "^2", + "svelte": "^5.0.0", + "svelte-check": "^4.0.0", + "tailwindcss": "^4.2.1", + "typescript": "~5.6.2", + "vite": "^6.0.3" + } +} diff --git a/src-tauri/.cargo/config.toml b/src-tauri/.cargo/config.toml new file mode 100644 index 0000000..417b7a5 --- /dev/null +++ b/src-tauri/.cargo/config.toml @@ -0,0 +1,2 @@ +[env] +LIBCLANG_PATH = "C:\\Program Files\\LLVM\\bin" diff --git a/src-tauri/Cargo.toml b/src-tauri/Cargo.toml new file mode 100644 index 0000000..2d93ee5 --- /dev/null +++ b/src-tauri/Cargo.toml @@ -0,0 +1,37 @@ +[package] +name = "kon" +version = "0.1.0" +description = "Kon — Think out loud" +authors = ["CORBEL Ltd"] +edition = "2021" + +[lib] +name = "kon_lib" +crate-type = ["staticlib", "cdylib", "rlib"] + +[build-dependencies] +tauri-build = { version = "2", features = [] } + +[dependencies] +# Workspace crates +kon-core = { path = "../crates/core" } +kon-audio = { path = "../crates/audio" } +kon-transcription = { path = "../crates/transcription" } +kon-ai-formatting = { path = "../crates/ai-formatting" } +kon-storage = { path = "../crates/storage" } +kon-cloud-providers = { path = "../crates/cloud-providers" } + +# Tauri +tauri = { version = "2", features = ["tray-icon"] } +tauri-plugin-opener = "2" +tauri-plugin-dialog = "2" +tauri-plugin-global-shortcut = "2" + +# Serialisation +serde = { version = "1", features = ["derive"] } +serde_json = "1" + +# Async runtime (spawn_blocking for inference) +tokio = { version = "1", features = ["rt", "sync"] } +arboard = "3.6.1" +tauri-plugin-mcp = "0.7.1" diff --git a/src-tauri/build.rs b/src-tauri/build.rs new file mode 100644 index 0000000..d860e1e --- /dev/null +++ b/src-tauri/build.rs @@ -0,0 +1,3 @@ +fn main() { + tauri_build::build() +} diff --git a/src-tauri/capabilities/default.json b/src-tauri/capabilities/default.json new file mode 100644 index 0000000..f94b23d --- /dev/null +++ b/src-tauri/capabilities/default.json @@ -0,0 +1,22 @@ +{ + "$schema": "../gen/schemas/desktop-schema.json", + "identifier": "default", + "description": "Capability for the main window", + "windows": ["main", "tasks-float"], + "permissions": [ + "core:default", + "core:window:allow-start-dragging", + "core:window:allow-set-always-on-top", + "core:window:allow-minimize", + "core:window:allow-toggle-maximize", + "core:window:allow-is-maximized", + "core:window:allow-close", + "core:window:allow-hide", + "core:window:allow-show", + "core:window:allow-set-focus", + "opener:default", + "dialog:default", + "global-shortcut:allow-register", + "global-shortcut:allow-unregister" + ] +} diff --git a/src-tauri/gen/schemas/acl-manifests.json b/src-tauri/gen/schemas/acl-manifests.json new file mode 100644 index 0000000..e63209c --- /dev/null +++ b/src-tauri/gen/schemas/acl-manifests.json @@ -0,0 +1 @@ +{"core":{"default_permission":{"identifier":"default","description":"Default core plugins set.","permissions":["core:path:default","core:event:default","core:window:default","core:webview:default","core:app:default","core:image:default","core:resources:default","core:menu:default","core:tray:default"]},"permissions":{},"permission_sets":{},"global_scope_schema":null},"core:app":{"default_permission":{"identifier":"default","description":"Default permissions for the plugin.","permissions":["allow-version","allow-name","allow-tauri-version","allow-identifier","allow-bundle-type","allow-register-listener","allow-remove-listener"]},"permissions":{"allow-app-hide":{"identifier":"allow-app-hide","description":"Enables the app_hide command without any pre-configured scope.","commands":{"allow":["app_hide"],"deny":[]}},"allow-app-show":{"identifier":"allow-app-show","description":"Enables the app_show command without any pre-configured scope.","commands":{"allow":["app_show"],"deny":[]}},"allow-bundle-type":{"identifier":"allow-bundle-type","description":"Enables the bundle_type command without any pre-configured scope.","commands":{"allow":["bundle_type"],"deny":[]}},"allow-default-window-icon":{"identifier":"allow-default-window-icon","description":"Enables the default_window_icon command without any pre-configured scope.","commands":{"allow":["default_window_icon"],"deny":[]}},"allow-fetch-data-store-identifiers":{"identifier":"allow-fetch-data-store-identifiers","description":"Enables the fetch_data_store_identifiers command without any pre-configured scope.","commands":{"allow":["fetch_data_store_identifiers"],"deny":[]}},"allow-identifier":{"identifier":"allow-identifier","description":"Enables the identifier command without any pre-configured scope.","commands":{"allow":["identifier"],"deny":[]}},"allow-name":{"identifier":"allow-name","description":"Enables the name command without any pre-configured scope.","commands":{"allow":["name"],"deny":[]}},"allow-register-listener":{"identifier":"allow-register-listener","description":"Enables the register_listener command without any pre-configured scope.","commands":{"allow":["register_listener"],"deny":[]}},"allow-remove-data-store":{"identifier":"allow-remove-data-store","description":"Enables the remove_data_store command without any pre-configured scope.","commands":{"allow":["remove_data_store"],"deny":[]}},"allow-remove-listener":{"identifier":"allow-remove-listener","description":"Enables the remove_listener command without any pre-configured scope.","commands":{"allow":["remove_listener"],"deny":[]}},"allow-set-app-theme":{"identifier":"allow-set-app-theme","description":"Enables the set_app_theme command without any pre-configured scope.","commands":{"allow":["set_app_theme"],"deny":[]}},"allow-set-dock-visibility":{"identifier":"allow-set-dock-visibility","description":"Enables the set_dock_visibility command without any pre-configured scope.","commands":{"allow":["set_dock_visibility"],"deny":[]}},"allow-tauri-version":{"identifier":"allow-tauri-version","description":"Enables the tauri_version command without any pre-configured scope.","commands":{"allow":["tauri_version"],"deny":[]}},"allow-version":{"identifier":"allow-version","description":"Enables the version command without any pre-configured scope.","commands":{"allow":["version"],"deny":[]}},"deny-app-hide":{"identifier":"deny-app-hide","description":"Denies the app_hide command without any pre-configured scope.","commands":{"allow":[],"deny":["app_hide"]}},"deny-app-show":{"identifier":"deny-app-show","description":"Denies the app_show command without any pre-configured scope.","commands":{"allow":[],"deny":["app_show"]}},"deny-bundle-type":{"identifier":"deny-bundle-type","description":"Denies the bundle_type command without any pre-configured scope.","commands":{"allow":[],"deny":["bundle_type"]}},"deny-default-window-icon":{"identifier":"deny-default-window-icon","description":"Denies the default_window_icon command without any pre-configured scope.","commands":{"allow":[],"deny":["default_window_icon"]}},"deny-fetch-data-store-identifiers":{"identifier":"deny-fetch-data-store-identifiers","description":"Denies the fetch_data_store_identifiers command without any pre-configured scope.","commands":{"allow":[],"deny":["fetch_data_store_identifiers"]}},"deny-identifier":{"identifier":"deny-identifier","description":"Denies the identifier command without any pre-configured scope.","commands":{"allow":[],"deny":["identifier"]}},"deny-name":{"identifier":"deny-name","description":"Denies the name command without any pre-configured scope.","commands":{"allow":[],"deny":["name"]}},"deny-register-listener":{"identifier":"deny-register-listener","description":"Denies the register_listener command without any pre-configured scope.","commands":{"allow":[],"deny":["register_listener"]}},"deny-remove-data-store":{"identifier":"deny-remove-data-store","description":"Denies the remove_data_store command without any pre-configured scope.","commands":{"allow":[],"deny":["remove_data_store"]}},"deny-remove-listener":{"identifier":"deny-remove-listener","description":"Denies the remove_listener command without any pre-configured scope.","commands":{"allow":[],"deny":["remove_listener"]}},"deny-set-app-theme":{"identifier":"deny-set-app-theme","description":"Denies the set_app_theme command without any pre-configured scope.","commands":{"allow":[],"deny":["set_app_theme"]}},"deny-set-dock-visibility":{"identifier":"deny-set-dock-visibility","description":"Denies the set_dock_visibility command without any pre-configured scope.","commands":{"allow":[],"deny":["set_dock_visibility"]}},"deny-tauri-version":{"identifier":"deny-tauri-version","description":"Denies the tauri_version command without any pre-configured scope.","commands":{"allow":[],"deny":["tauri_version"]}},"deny-version":{"identifier":"deny-version","description":"Denies the version command without any pre-configured scope.","commands":{"allow":[],"deny":["version"]}}},"permission_sets":{},"global_scope_schema":null},"core:event":{"default_permission":{"identifier":"default","description":"Default permissions for the plugin, which enables all commands.","permissions":["allow-listen","allow-unlisten","allow-emit","allow-emit-to"]},"permissions":{"allow-emit":{"identifier":"allow-emit","description":"Enables the emit command without any pre-configured scope.","commands":{"allow":["emit"],"deny":[]}},"allow-emit-to":{"identifier":"allow-emit-to","description":"Enables the emit_to command without any pre-configured scope.","commands":{"allow":["emit_to"],"deny":[]}},"allow-listen":{"identifier":"allow-listen","description":"Enables the listen command without any pre-configured scope.","commands":{"allow":["listen"],"deny":[]}},"allow-unlisten":{"identifier":"allow-unlisten","description":"Enables the unlisten command without any pre-configured scope.","commands":{"allow":["unlisten"],"deny":[]}},"deny-emit":{"identifier":"deny-emit","description":"Denies the emit command without any pre-configured scope.","commands":{"allow":[],"deny":["emit"]}},"deny-emit-to":{"identifier":"deny-emit-to","description":"Denies the emit_to command without any pre-configured scope.","commands":{"allow":[],"deny":["emit_to"]}},"deny-listen":{"identifier":"deny-listen","description":"Denies the listen command without any pre-configured scope.","commands":{"allow":[],"deny":["listen"]}},"deny-unlisten":{"identifier":"deny-unlisten","description":"Denies the unlisten command without any pre-configured scope.","commands":{"allow":[],"deny":["unlisten"]}}},"permission_sets":{},"global_scope_schema":null},"core:image":{"default_permission":{"identifier":"default","description":"Default permissions for the plugin, which enables all commands.","permissions":["allow-new","allow-from-bytes","allow-from-path","allow-rgba","allow-size"]},"permissions":{"allow-from-bytes":{"identifier":"allow-from-bytes","description":"Enables the from_bytes command without any pre-configured scope.","commands":{"allow":["from_bytes"],"deny":[]}},"allow-from-path":{"identifier":"allow-from-path","description":"Enables the from_path command without any pre-configured scope.","commands":{"allow":["from_path"],"deny":[]}},"allow-new":{"identifier":"allow-new","description":"Enables the new command without any pre-configured scope.","commands":{"allow":["new"],"deny":[]}},"allow-rgba":{"identifier":"allow-rgba","description":"Enables the rgba command without any pre-configured scope.","commands":{"allow":["rgba"],"deny":[]}},"allow-size":{"identifier":"allow-size","description":"Enables the size command without any pre-configured scope.","commands":{"allow":["size"],"deny":[]}},"deny-from-bytes":{"identifier":"deny-from-bytes","description":"Denies the from_bytes command without any pre-configured scope.","commands":{"allow":[],"deny":["from_bytes"]}},"deny-from-path":{"identifier":"deny-from-path","description":"Denies the from_path command without any pre-configured scope.","commands":{"allow":[],"deny":["from_path"]}},"deny-new":{"identifier":"deny-new","description":"Denies the new command without any pre-configured scope.","commands":{"allow":[],"deny":["new"]}},"deny-rgba":{"identifier":"deny-rgba","description":"Denies the rgba command without any pre-configured scope.","commands":{"allow":[],"deny":["rgba"]}},"deny-size":{"identifier":"deny-size","description":"Denies the size command without any pre-configured scope.","commands":{"allow":[],"deny":["size"]}}},"permission_sets":{},"global_scope_schema":null},"core:menu":{"default_permission":{"identifier":"default","description":"Default permissions for the plugin, which enables all commands.","permissions":["allow-new","allow-append","allow-prepend","allow-insert","allow-remove","allow-remove-at","allow-items","allow-get","allow-popup","allow-create-default","allow-set-as-app-menu","allow-set-as-window-menu","allow-text","allow-set-text","allow-is-enabled","allow-set-enabled","allow-set-accelerator","allow-set-as-windows-menu-for-nsapp","allow-set-as-help-menu-for-nsapp","allow-is-checked","allow-set-checked","allow-set-icon"]},"permissions":{"allow-append":{"identifier":"allow-append","description":"Enables the append command without any pre-configured scope.","commands":{"allow":["append"],"deny":[]}},"allow-create-default":{"identifier":"allow-create-default","description":"Enables the create_default command without any pre-configured scope.","commands":{"allow":["create_default"],"deny":[]}},"allow-get":{"identifier":"allow-get","description":"Enables the get command without any pre-configured scope.","commands":{"allow":["get"],"deny":[]}},"allow-insert":{"identifier":"allow-insert","description":"Enables the insert command without any pre-configured scope.","commands":{"allow":["insert"],"deny":[]}},"allow-is-checked":{"identifier":"allow-is-checked","description":"Enables the is_checked command without any pre-configured scope.","commands":{"allow":["is_checked"],"deny":[]}},"allow-is-enabled":{"identifier":"allow-is-enabled","description":"Enables the is_enabled command without any pre-configured scope.","commands":{"allow":["is_enabled"],"deny":[]}},"allow-items":{"identifier":"allow-items","description":"Enables the items command without any pre-configured scope.","commands":{"allow":["items"],"deny":[]}},"allow-new":{"identifier":"allow-new","description":"Enables the new command without any pre-configured scope.","commands":{"allow":["new"],"deny":[]}},"allow-popup":{"identifier":"allow-popup","description":"Enables the popup command without any pre-configured scope.","commands":{"allow":["popup"],"deny":[]}},"allow-prepend":{"identifier":"allow-prepend","description":"Enables the prepend command without any pre-configured scope.","commands":{"allow":["prepend"],"deny":[]}},"allow-remove":{"identifier":"allow-remove","description":"Enables the remove command without any pre-configured scope.","commands":{"allow":["remove"],"deny":[]}},"allow-remove-at":{"identifier":"allow-remove-at","description":"Enables the remove_at command without any pre-configured scope.","commands":{"allow":["remove_at"],"deny":[]}},"allow-set-accelerator":{"identifier":"allow-set-accelerator","description":"Enables the set_accelerator command without any pre-configured scope.","commands":{"allow":["set_accelerator"],"deny":[]}},"allow-set-as-app-menu":{"identifier":"allow-set-as-app-menu","description":"Enables the set_as_app_menu command without any pre-configured scope.","commands":{"allow":["set_as_app_menu"],"deny":[]}},"allow-set-as-help-menu-for-nsapp":{"identifier":"allow-set-as-help-menu-for-nsapp","description":"Enables the set_as_help_menu_for_nsapp command without any pre-configured scope.","commands":{"allow":["set_as_help_menu_for_nsapp"],"deny":[]}},"allow-set-as-window-menu":{"identifier":"allow-set-as-window-menu","description":"Enables the set_as_window_menu command without any pre-configured scope.","commands":{"allow":["set_as_window_menu"],"deny":[]}},"allow-set-as-windows-menu-for-nsapp":{"identifier":"allow-set-as-windows-menu-for-nsapp","description":"Enables the set_as_windows_menu_for_nsapp command without any pre-configured scope.","commands":{"allow":["set_as_windows_menu_for_nsapp"],"deny":[]}},"allow-set-checked":{"identifier":"allow-set-checked","description":"Enables the set_checked command without any pre-configured scope.","commands":{"allow":["set_checked"],"deny":[]}},"allow-set-enabled":{"identifier":"allow-set-enabled","description":"Enables the set_enabled command without any pre-configured scope.","commands":{"allow":["set_enabled"],"deny":[]}},"allow-set-icon":{"identifier":"allow-set-icon","description":"Enables the set_icon command without any pre-configured scope.","commands":{"allow":["set_icon"],"deny":[]}},"allow-set-text":{"identifier":"allow-set-text","description":"Enables the set_text command without any pre-configured scope.","commands":{"allow":["set_text"],"deny":[]}},"allow-text":{"identifier":"allow-text","description":"Enables the text command without any pre-configured scope.","commands":{"allow":["text"],"deny":[]}},"deny-append":{"identifier":"deny-append","description":"Denies the append command without any pre-configured scope.","commands":{"allow":[],"deny":["append"]}},"deny-create-default":{"identifier":"deny-create-default","description":"Denies the create_default command without any pre-configured scope.","commands":{"allow":[],"deny":["create_default"]}},"deny-get":{"identifier":"deny-get","description":"Denies the get command without any pre-configured scope.","commands":{"allow":[],"deny":["get"]}},"deny-insert":{"identifier":"deny-insert","description":"Denies the insert command without any pre-configured scope.","commands":{"allow":[],"deny":["insert"]}},"deny-is-checked":{"identifier":"deny-is-checked","description":"Denies the is_checked command without any pre-configured scope.","commands":{"allow":[],"deny":["is_checked"]}},"deny-is-enabled":{"identifier":"deny-is-enabled","description":"Denies the is_enabled command without any pre-configured scope.","commands":{"allow":[],"deny":["is_enabled"]}},"deny-items":{"identifier":"deny-items","description":"Denies the items command without any pre-configured scope.","commands":{"allow":[],"deny":["items"]}},"deny-new":{"identifier":"deny-new","description":"Denies the new command without any pre-configured scope.","commands":{"allow":[],"deny":["new"]}},"deny-popup":{"identifier":"deny-popup","description":"Denies the popup command without any pre-configured scope.","commands":{"allow":[],"deny":["popup"]}},"deny-prepend":{"identifier":"deny-prepend","description":"Denies the prepend command without any pre-configured scope.","commands":{"allow":[],"deny":["prepend"]}},"deny-remove":{"identifier":"deny-remove","description":"Denies the remove command without any pre-configured scope.","commands":{"allow":[],"deny":["remove"]}},"deny-remove-at":{"identifier":"deny-remove-at","description":"Denies the remove_at command without any pre-configured scope.","commands":{"allow":[],"deny":["remove_at"]}},"deny-set-accelerator":{"identifier":"deny-set-accelerator","description":"Denies the set_accelerator command without any pre-configured scope.","commands":{"allow":[],"deny":["set_accelerator"]}},"deny-set-as-app-menu":{"identifier":"deny-set-as-app-menu","description":"Denies the set_as_app_menu command without any pre-configured scope.","commands":{"allow":[],"deny":["set_as_app_menu"]}},"deny-set-as-help-menu-for-nsapp":{"identifier":"deny-set-as-help-menu-for-nsapp","description":"Denies the set_as_help_menu_for_nsapp command without any pre-configured scope.","commands":{"allow":[],"deny":["set_as_help_menu_for_nsapp"]}},"deny-set-as-window-menu":{"identifier":"deny-set-as-window-menu","description":"Denies the set_as_window_menu command without any pre-configured scope.","commands":{"allow":[],"deny":["set_as_window_menu"]}},"deny-set-as-windows-menu-for-nsapp":{"identifier":"deny-set-as-windows-menu-for-nsapp","description":"Denies the set_as_windows_menu_for_nsapp command without any pre-configured scope.","commands":{"allow":[],"deny":["set_as_windows_menu_for_nsapp"]}},"deny-set-checked":{"identifier":"deny-set-checked","description":"Denies the set_checked command without any pre-configured scope.","commands":{"allow":[],"deny":["set_checked"]}},"deny-set-enabled":{"identifier":"deny-set-enabled","description":"Denies the set_enabled command without any pre-configured scope.","commands":{"allow":[],"deny":["set_enabled"]}},"deny-set-icon":{"identifier":"deny-set-icon","description":"Denies the set_icon command without any pre-configured scope.","commands":{"allow":[],"deny":["set_icon"]}},"deny-set-text":{"identifier":"deny-set-text","description":"Denies the set_text command without any pre-configured scope.","commands":{"allow":[],"deny":["set_text"]}},"deny-text":{"identifier":"deny-text","description":"Denies the text command without any pre-configured scope.","commands":{"allow":[],"deny":["text"]}}},"permission_sets":{},"global_scope_schema":null},"core:path":{"default_permission":{"identifier":"default","description":"Default permissions for the plugin, which enables all commands.","permissions":["allow-resolve-directory","allow-resolve","allow-normalize","allow-join","allow-dirname","allow-extname","allow-basename","allow-is-absolute"]},"permissions":{"allow-basename":{"identifier":"allow-basename","description":"Enables the basename command without any pre-configured scope.","commands":{"allow":["basename"],"deny":[]}},"allow-dirname":{"identifier":"allow-dirname","description":"Enables the dirname command without any pre-configured scope.","commands":{"allow":["dirname"],"deny":[]}},"allow-extname":{"identifier":"allow-extname","description":"Enables the extname command without any pre-configured scope.","commands":{"allow":["extname"],"deny":[]}},"allow-is-absolute":{"identifier":"allow-is-absolute","description":"Enables the is_absolute command without any pre-configured scope.","commands":{"allow":["is_absolute"],"deny":[]}},"allow-join":{"identifier":"allow-join","description":"Enables the join command without any pre-configured scope.","commands":{"allow":["join"],"deny":[]}},"allow-normalize":{"identifier":"allow-normalize","description":"Enables the normalize command without any pre-configured scope.","commands":{"allow":["normalize"],"deny":[]}},"allow-resolve":{"identifier":"allow-resolve","description":"Enables the resolve command without any pre-configured scope.","commands":{"allow":["resolve"],"deny":[]}},"allow-resolve-directory":{"identifier":"allow-resolve-directory","description":"Enables the resolve_directory command without any pre-configured scope.","commands":{"allow":["resolve_directory"],"deny":[]}},"deny-basename":{"identifier":"deny-basename","description":"Denies the basename command without any pre-configured scope.","commands":{"allow":[],"deny":["basename"]}},"deny-dirname":{"identifier":"deny-dirname","description":"Denies the dirname command without any pre-configured scope.","commands":{"allow":[],"deny":["dirname"]}},"deny-extname":{"identifier":"deny-extname","description":"Denies the extname command without any pre-configured scope.","commands":{"allow":[],"deny":["extname"]}},"deny-is-absolute":{"identifier":"deny-is-absolute","description":"Denies the is_absolute command without any pre-configured scope.","commands":{"allow":[],"deny":["is_absolute"]}},"deny-join":{"identifier":"deny-join","description":"Denies the join command without any pre-configured scope.","commands":{"allow":[],"deny":["join"]}},"deny-normalize":{"identifier":"deny-normalize","description":"Denies the normalize command without any pre-configured scope.","commands":{"allow":[],"deny":["normalize"]}},"deny-resolve":{"identifier":"deny-resolve","description":"Denies the resolve command without any pre-configured scope.","commands":{"allow":[],"deny":["resolve"]}},"deny-resolve-directory":{"identifier":"deny-resolve-directory","description":"Denies the resolve_directory command without any pre-configured scope.","commands":{"allow":[],"deny":["resolve_directory"]}}},"permission_sets":{},"global_scope_schema":null},"core:resources":{"default_permission":{"identifier":"default","description":"Default permissions for the plugin, which enables all commands.","permissions":["allow-close"]},"permissions":{"allow-close":{"identifier":"allow-close","description":"Enables the close command without any pre-configured scope.","commands":{"allow":["close"],"deny":[]}},"deny-close":{"identifier":"deny-close","description":"Denies the close command without any pre-configured scope.","commands":{"allow":[],"deny":["close"]}}},"permission_sets":{},"global_scope_schema":null},"core:tray":{"default_permission":{"identifier":"default","description":"Default permissions for the plugin, which enables all commands.","permissions":["allow-new","allow-get-by-id","allow-remove-by-id","allow-set-icon","allow-set-menu","allow-set-tooltip","allow-set-title","allow-set-visible","allow-set-temp-dir-path","allow-set-icon-as-template","allow-set-show-menu-on-left-click"]},"permissions":{"allow-get-by-id":{"identifier":"allow-get-by-id","description":"Enables the get_by_id command without any pre-configured scope.","commands":{"allow":["get_by_id"],"deny":[]}},"allow-new":{"identifier":"allow-new","description":"Enables the new command without any pre-configured scope.","commands":{"allow":["new"],"deny":[]}},"allow-remove-by-id":{"identifier":"allow-remove-by-id","description":"Enables the remove_by_id command without any pre-configured scope.","commands":{"allow":["remove_by_id"],"deny":[]}},"allow-set-icon":{"identifier":"allow-set-icon","description":"Enables the set_icon command without any pre-configured scope.","commands":{"allow":["set_icon"],"deny":[]}},"allow-set-icon-as-template":{"identifier":"allow-set-icon-as-template","description":"Enables the set_icon_as_template command without any pre-configured scope.","commands":{"allow":["set_icon_as_template"],"deny":[]}},"allow-set-menu":{"identifier":"allow-set-menu","description":"Enables the set_menu command without any pre-configured scope.","commands":{"allow":["set_menu"],"deny":[]}},"allow-set-show-menu-on-left-click":{"identifier":"allow-set-show-menu-on-left-click","description":"Enables the set_show_menu_on_left_click command without any pre-configured scope.","commands":{"allow":["set_show_menu_on_left_click"],"deny":[]}},"allow-set-temp-dir-path":{"identifier":"allow-set-temp-dir-path","description":"Enables the set_temp_dir_path command without any pre-configured scope.","commands":{"allow":["set_temp_dir_path"],"deny":[]}},"allow-set-title":{"identifier":"allow-set-title","description":"Enables the set_title command without any pre-configured scope.","commands":{"allow":["set_title"],"deny":[]}},"allow-set-tooltip":{"identifier":"allow-set-tooltip","description":"Enables the set_tooltip command without any pre-configured scope.","commands":{"allow":["set_tooltip"],"deny":[]}},"allow-set-visible":{"identifier":"allow-set-visible","description":"Enables the set_visible command without any pre-configured scope.","commands":{"allow":["set_visible"],"deny":[]}},"deny-get-by-id":{"identifier":"deny-get-by-id","description":"Denies the get_by_id command without any pre-configured scope.","commands":{"allow":[],"deny":["get_by_id"]}},"deny-new":{"identifier":"deny-new","description":"Denies the new command without any pre-configured scope.","commands":{"allow":[],"deny":["new"]}},"deny-remove-by-id":{"identifier":"deny-remove-by-id","description":"Denies the remove_by_id command without any pre-configured scope.","commands":{"allow":[],"deny":["remove_by_id"]}},"deny-set-icon":{"identifier":"deny-set-icon","description":"Denies the set_icon command without any pre-configured scope.","commands":{"allow":[],"deny":["set_icon"]}},"deny-set-icon-as-template":{"identifier":"deny-set-icon-as-template","description":"Denies the set_icon_as_template command without any pre-configured scope.","commands":{"allow":[],"deny":["set_icon_as_template"]}},"deny-set-menu":{"identifier":"deny-set-menu","description":"Denies the set_menu command without any pre-configured scope.","commands":{"allow":[],"deny":["set_menu"]}},"deny-set-show-menu-on-left-click":{"identifier":"deny-set-show-menu-on-left-click","description":"Denies the set_show_menu_on_left_click command without any pre-configured scope.","commands":{"allow":[],"deny":["set_show_menu_on_left_click"]}},"deny-set-temp-dir-path":{"identifier":"deny-set-temp-dir-path","description":"Denies the set_temp_dir_path command without any pre-configured scope.","commands":{"allow":[],"deny":["set_temp_dir_path"]}},"deny-set-title":{"identifier":"deny-set-title","description":"Denies the set_title command without any pre-configured scope.","commands":{"allow":[],"deny":["set_title"]}},"deny-set-tooltip":{"identifier":"deny-set-tooltip","description":"Denies the set_tooltip command without any pre-configured scope.","commands":{"allow":[],"deny":["set_tooltip"]}},"deny-set-visible":{"identifier":"deny-set-visible","description":"Denies the set_visible command without any pre-configured scope.","commands":{"allow":[],"deny":["set_visible"]}}},"permission_sets":{},"global_scope_schema":null},"core:webview":{"default_permission":{"identifier":"default","description":"Default permissions for the plugin.","permissions":["allow-get-all-webviews","allow-webview-position","allow-webview-size","allow-internal-toggle-devtools"]},"permissions":{"allow-clear-all-browsing-data":{"identifier":"allow-clear-all-browsing-data","description":"Enables the clear_all_browsing_data command without any pre-configured scope.","commands":{"allow":["clear_all_browsing_data"],"deny":[]}},"allow-create-webview":{"identifier":"allow-create-webview","description":"Enables the create_webview command without any pre-configured scope.","commands":{"allow":["create_webview"],"deny":[]}},"allow-create-webview-window":{"identifier":"allow-create-webview-window","description":"Enables the create_webview_window command without any pre-configured scope.","commands":{"allow":["create_webview_window"],"deny":[]}},"allow-get-all-webviews":{"identifier":"allow-get-all-webviews","description":"Enables the get_all_webviews command without any pre-configured scope.","commands":{"allow":["get_all_webviews"],"deny":[]}},"allow-internal-toggle-devtools":{"identifier":"allow-internal-toggle-devtools","description":"Enables the internal_toggle_devtools command without any pre-configured scope.","commands":{"allow":["internal_toggle_devtools"],"deny":[]}},"allow-print":{"identifier":"allow-print","description":"Enables the print command without any pre-configured scope.","commands":{"allow":["print"],"deny":[]}},"allow-reparent":{"identifier":"allow-reparent","description":"Enables the reparent command without any pre-configured scope.","commands":{"allow":["reparent"],"deny":[]}},"allow-set-webview-auto-resize":{"identifier":"allow-set-webview-auto-resize","description":"Enables the set_webview_auto_resize command without any pre-configured scope.","commands":{"allow":["set_webview_auto_resize"],"deny":[]}},"allow-set-webview-background-color":{"identifier":"allow-set-webview-background-color","description":"Enables the set_webview_background_color command without any pre-configured scope.","commands":{"allow":["set_webview_background_color"],"deny":[]}},"allow-set-webview-focus":{"identifier":"allow-set-webview-focus","description":"Enables the set_webview_focus command without any pre-configured scope.","commands":{"allow":["set_webview_focus"],"deny":[]}},"allow-set-webview-position":{"identifier":"allow-set-webview-position","description":"Enables the set_webview_position command without any pre-configured scope.","commands":{"allow":["set_webview_position"],"deny":[]}},"allow-set-webview-size":{"identifier":"allow-set-webview-size","description":"Enables the set_webview_size command without any pre-configured scope.","commands":{"allow":["set_webview_size"],"deny":[]}},"allow-set-webview-zoom":{"identifier":"allow-set-webview-zoom","description":"Enables the set_webview_zoom command without any pre-configured scope.","commands":{"allow":["set_webview_zoom"],"deny":[]}},"allow-webview-close":{"identifier":"allow-webview-close","description":"Enables the webview_close command without any pre-configured scope.","commands":{"allow":["webview_close"],"deny":[]}},"allow-webview-hide":{"identifier":"allow-webview-hide","description":"Enables the webview_hide command without any pre-configured scope.","commands":{"allow":["webview_hide"],"deny":[]}},"allow-webview-position":{"identifier":"allow-webview-position","description":"Enables the webview_position command without any pre-configured scope.","commands":{"allow":["webview_position"],"deny":[]}},"allow-webview-show":{"identifier":"allow-webview-show","description":"Enables the webview_show command without any pre-configured scope.","commands":{"allow":["webview_show"],"deny":[]}},"allow-webview-size":{"identifier":"allow-webview-size","description":"Enables the webview_size command without any pre-configured scope.","commands":{"allow":["webview_size"],"deny":[]}},"deny-clear-all-browsing-data":{"identifier":"deny-clear-all-browsing-data","description":"Denies the clear_all_browsing_data command without any pre-configured scope.","commands":{"allow":[],"deny":["clear_all_browsing_data"]}},"deny-create-webview":{"identifier":"deny-create-webview","description":"Denies the create_webview command without any pre-configured scope.","commands":{"allow":[],"deny":["create_webview"]}},"deny-create-webview-window":{"identifier":"deny-create-webview-window","description":"Denies the create_webview_window command without any pre-configured scope.","commands":{"allow":[],"deny":["create_webview_window"]}},"deny-get-all-webviews":{"identifier":"deny-get-all-webviews","description":"Denies the get_all_webviews command without any pre-configured scope.","commands":{"allow":[],"deny":["get_all_webviews"]}},"deny-internal-toggle-devtools":{"identifier":"deny-internal-toggle-devtools","description":"Denies the internal_toggle_devtools command without any pre-configured scope.","commands":{"allow":[],"deny":["internal_toggle_devtools"]}},"deny-print":{"identifier":"deny-print","description":"Denies the print command without any pre-configured scope.","commands":{"allow":[],"deny":["print"]}},"deny-reparent":{"identifier":"deny-reparent","description":"Denies the reparent command without any pre-configured scope.","commands":{"allow":[],"deny":["reparent"]}},"deny-set-webview-auto-resize":{"identifier":"deny-set-webview-auto-resize","description":"Denies the set_webview_auto_resize command without any pre-configured scope.","commands":{"allow":[],"deny":["set_webview_auto_resize"]}},"deny-set-webview-background-color":{"identifier":"deny-set-webview-background-color","description":"Denies the set_webview_background_color command without any pre-configured scope.","commands":{"allow":[],"deny":["set_webview_background_color"]}},"deny-set-webview-focus":{"identifier":"deny-set-webview-focus","description":"Denies the set_webview_focus command without any pre-configured scope.","commands":{"allow":[],"deny":["set_webview_focus"]}},"deny-set-webview-position":{"identifier":"deny-set-webview-position","description":"Denies the set_webview_position command without any pre-configured scope.","commands":{"allow":[],"deny":["set_webview_position"]}},"deny-set-webview-size":{"identifier":"deny-set-webview-size","description":"Denies the set_webview_size command without any pre-configured scope.","commands":{"allow":[],"deny":["set_webview_size"]}},"deny-set-webview-zoom":{"identifier":"deny-set-webview-zoom","description":"Denies the set_webview_zoom command without any pre-configured scope.","commands":{"allow":[],"deny":["set_webview_zoom"]}},"deny-webview-close":{"identifier":"deny-webview-close","description":"Denies the webview_close command without any pre-configured scope.","commands":{"allow":[],"deny":["webview_close"]}},"deny-webview-hide":{"identifier":"deny-webview-hide","description":"Denies the webview_hide command without any pre-configured scope.","commands":{"allow":[],"deny":["webview_hide"]}},"deny-webview-position":{"identifier":"deny-webview-position","description":"Denies the webview_position command without any pre-configured scope.","commands":{"allow":[],"deny":["webview_position"]}},"deny-webview-show":{"identifier":"deny-webview-show","description":"Denies the webview_show command without any pre-configured scope.","commands":{"allow":[],"deny":["webview_show"]}},"deny-webview-size":{"identifier":"deny-webview-size","description":"Denies the webview_size command without any pre-configured scope.","commands":{"allow":[],"deny":["webview_size"]}}},"permission_sets":{},"global_scope_schema":null},"core:window":{"default_permission":{"identifier":"default","description":"Default permissions for the plugin.","permissions":["allow-get-all-windows","allow-scale-factor","allow-inner-position","allow-outer-position","allow-inner-size","allow-outer-size","allow-is-fullscreen","allow-is-minimized","allow-is-maximized","allow-is-focused","allow-is-decorated","allow-is-resizable","allow-is-maximizable","allow-is-minimizable","allow-is-closable","allow-is-visible","allow-is-enabled","allow-title","allow-current-monitor","allow-primary-monitor","allow-monitor-from-point","allow-available-monitors","allow-cursor-position","allow-theme","allow-is-always-on-top","allow-internal-toggle-maximize"]},"permissions":{"allow-available-monitors":{"identifier":"allow-available-monitors","description":"Enables the available_monitors command without any pre-configured scope.","commands":{"allow":["available_monitors"],"deny":[]}},"allow-center":{"identifier":"allow-center","description":"Enables the center command without any pre-configured scope.","commands":{"allow":["center"],"deny":[]}},"allow-close":{"identifier":"allow-close","description":"Enables the close command without any pre-configured scope.","commands":{"allow":["close"],"deny":[]}},"allow-create":{"identifier":"allow-create","description":"Enables the create command without any pre-configured scope.","commands":{"allow":["create"],"deny":[]}},"allow-current-monitor":{"identifier":"allow-current-monitor","description":"Enables the current_monitor command without any pre-configured scope.","commands":{"allow":["current_monitor"],"deny":[]}},"allow-cursor-position":{"identifier":"allow-cursor-position","description":"Enables the cursor_position command without any pre-configured scope.","commands":{"allow":["cursor_position"],"deny":[]}},"allow-destroy":{"identifier":"allow-destroy","description":"Enables the destroy command without any pre-configured scope.","commands":{"allow":["destroy"],"deny":[]}},"allow-get-all-windows":{"identifier":"allow-get-all-windows","description":"Enables the get_all_windows command without any pre-configured scope.","commands":{"allow":["get_all_windows"],"deny":[]}},"allow-hide":{"identifier":"allow-hide","description":"Enables the hide command without any pre-configured scope.","commands":{"allow":["hide"],"deny":[]}},"allow-inner-position":{"identifier":"allow-inner-position","description":"Enables the inner_position command without any pre-configured scope.","commands":{"allow":["inner_position"],"deny":[]}},"allow-inner-size":{"identifier":"allow-inner-size","description":"Enables the inner_size command without any pre-configured scope.","commands":{"allow":["inner_size"],"deny":[]}},"allow-internal-toggle-maximize":{"identifier":"allow-internal-toggle-maximize","description":"Enables the internal_toggle_maximize command without any pre-configured scope.","commands":{"allow":["internal_toggle_maximize"],"deny":[]}},"allow-is-always-on-top":{"identifier":"allow-is-always-on-top","description":"Enables the is_always_on_top command without any pre-configured scope.","commands":{"allow":["is_always_on_top"],"deny":[]}},"allow-is-closable":{"identifier":"allow-is-closable","description":"Enables the is_closable command without any pre-configured scope.","commands":{"allow":["is_closable"],"deny":[]}},"allow-is-decorated":{"identifier":"allow-is-decorated","description":"Enables the is_decorated command without any pre-configured scope.","commands":{"allow":["is_decorated"],"deny":[]}},"allow-is-enabled":{"identifier":"allow-is-enabled","description":"Enables the is_enabled command without any pre-configured scope.","commands":{"allow":["is_enabled"],"deny":[]}},"allow-is-focused":{"identifier":"allow-is-focused","description":"Enables the is_focused command without any pre-configured scope.","commands":{"allow":["is_focused"],"deny":[]}},"allow-is-fullscreen":{"identifier":"allow-is-fullscreen","description":"Enables the is_fullscreen command without any pre-configured scope.","commands":{"allow":["is_fullscreen"],"deny":[]}},"allow-is-maximizable":{"identifier":"allow-is-maximizable","description":"Enables the is_maximizable command without any pre-configured scope.","commands":{"allow":["is_maximizable"],"deny":[]}},"allow-is-maximized":{"identifier":"allow-is-maximized","description":"Enables the is_maximized command without any pre-configured scope.","commands":{"allow":["is_maximized"],"deny":[]}},"allow-is-minimizable":{"identifier":"allow-is-minimizable","description":"Enables the is_minimizable command without any pre-configured scope.","commands":{"allow":["is_minimizable"],"deny":[]}},"allow-is-minimized":{"identifier":"allow-is-minimized","description":"Enables the is_minimized command without any pre-configured scope.","commands":{"allow":["is_minimized"],"deny":[]}},"allow-is-resizable":{"identifier":"allow-is-resizable","description":"Enables the is_resizable command without any pre-configured scope.","commands":{"allow":["is_resizable"],"deny":[]}},"allow-is-visible":{"identifier":"allow-is-visible","description":"Enables the is_visible command without any pre-configured scope.","commands":{"allow":["is_visible"],"deny":[]}},"allow-maximize":{"identifier":"allow-maximize","description":"Enables the maximize command without any pre-configured scope.","commands":{"allow":["maximize"],"deny":[]}},"allow-minimize":{"identifier":"allow-minimize","description":"Enables the minimize command without any pre-configured scope.","commands":{"allow":["minimize"],"deny":[]}},"allow-monitor-from-point":{"identifier":"allow-monitor-from-point","description":"Enables the monitor_from_point command without any pre-configured scope.","commands":{"allow":["monitor_from_point"],"deny":[]}},"allow-outer-position":{"identifier":"allow-outer-position","description":"Enables the outer_position command without any pre-configured scope.","commands":{"allow":["outer_position"],"deny":[]}},"allow-outer-size":{"identifier":"allow-outer-size","description":"Enables the outer_size command without any pre-configured scope.","commands":{"allow":["outer_size"],"deny":[]}},"allow-primary-monitor":{"identifier":"allow-primary-monitor","description":"Enables the primary_monitor command without any pre-configured scope.","commands":{"allow":["primary_monitor"],"deny":[]}},"allow-request-user-attention":{"identifier":"allow-request-user-attention","description":"Enables the request_user_attention command without any pre-configured scope.","commands":{"allow":["request_user_attention"],"deny":[]}},"allow-scale-factor":{"identifier":"allow-scale-factor","description":"Enables the scale_factor command without any pre-configured scope.","commands":{"allow":["scale_factor"],"deny":[]}},"allow-set-always-on-bottom":{"identifier":"allow-set-always-on-bottom","description":"Enables the set_always_on_bottom command without any pre-configured scope.","commands":{"allow":["set_always_on_bottom"],"deny":[]}},"allow-set-always-on-top":{"identifier":"allow-set-always-on-top","description":"Enables the set_always_on_top command without any pre-configured scope.","commands":{"allow":["set_always_on_top"],"deny":[]}},"allow-set-background-color":{"identifier":"allow-set-background-color","description":"Enables the set_background_color command without any pre-configured scope.","commands":{"allow":["set_background_color"],"deny":[]}},"allow-set-badge-count":{"identifier":"allow-set-badge-count","description":"Enables the set_badge_count command without any pre-configured scope.","commands":{"allow":["set_badge_count"],"deny":[]}},"allow-set-badge-label":{"identifier":"allow-set-badge-label","description":"Enables the set_badge_label command without any pre-configured scope.","commands":{"allow":["set_badge_label"],"deny":[]}},"allow-set-closable":{"identifier":"allow-set-closable","description":"Enables the set_closable command without any pre-configured scope.","commands":{"allow":["set_closable"],"deny":[]}},"allow-set-content-protected":{"identifier":"allow-set-content-protected","description":"Enables the set_content_protected command without any pre-configured scope.","commands":{"allow":["set_content_protected"],"deny":[]}},"allow-set-cursor-grab":{"identifier":"allow-set-cursor-grab","description":"Enables the set_cursor_grab command without any pre-configured scope.","commands":{"allow":["set_cursor_grab"],"deny":[]}},"allow-set-cursor-icon":{"identifier":"allow-set-cursor-icon","description":"Enables the set_cursor_icon command without any pre-configured scope.","commands":{"allow":["set_cursor_icon"],"deny":[]}},"allow-set-cursor-position":{"identifier":"allow-set-cursor-position","description":"Enables the set_cursor_position command without any pre-configured scope.","commands":{"allow":["set_cursor_position"],"deny":[]}},"allow-set-cursor-visible":{"identifier":"allow-set-cursor-visible","description":"Enables the set_cursor_visible command without any pre-configured scope.","commands":{"allow":["set_cursor_visible"],"deny":[]}},"allow-set-decorations":{"identifier":"allow-set-decorations","description":"Enables the set_decorations command without any pre-configured scope.","commands":{"allow":["set_decorations"],"deny":[]}},"allow-set-effects":{"identifier":"allow-set-effects","description":"Enables the set_effects command without any pre-configured scope.","commands":{"allow":["set_effects"],"deny":[]}},"allow-set-enabled":{"identifier":"allow-set-enabled","description":"Enables the set_enabled command without any pre-configured scope.","commands":{"allow":["set_enabled"],"deny":[]}},"allow-set-focus":{"identifier":"allow-set-focus","description":"Enables the set_focus command without any pre-configured scope.","commands":{"allow":["set_focus"],"deny":[]}},"allow-set-focusable":{"identifier":"allow-set-focusable","description":"Enables the set_focusable command without any pre-configured scope.","commands":{"allow":["set_focusable"],"deny":[]}},"allow-set-fullscreen":{"identifier":"allow-set-fullscreen","description":"Enables the set_fullscreen command without any pre-configured scope.","commands":{"allow":["set_fullscreen"],"deny":[]}},"allow-set-icon":{"identifier":"allow-set-icon","description":"Enables the set_icon command without any pre-configured scope.","commands":{"allow":["set_icon"],"deny":[]}},"allow-set-ignore-cursor-events":{"identifier":"allow-set-ignore-cursor-events","description":"Enables the set_ignore_cursor_events command without any pre-configured scope.","commands":{"allow":["set_ignore_cursor_events"],"deny":[]}},"allow-set-max-size":{"identifier":"allow-set-max-size","description":"Enables the set_max_size command without any pre-configured scope.","commands":{"allow":["set_max_size"],"deny":[]}},"allow-set-maximizable":{"identifier":"allow-set-maximizable","description":"Enables the set_maximizable command without any pre-configured scope.","commands":{"allow":["set_maximizable"],"deny":[]}},"allow-set-min-size":{"identifier":"allow-set-min-size","description":"Enables the set_min_size command without any pre-configured scope.","commands":{"allow":["set_min_size"],"deny":[]}},"allow-set-minimizable":{"identifier":"allow-set-minimizable","description":"Enables the set_minimizable command without any pre-configured scope.","commands":{"allow":["set_minimizable"],"deny":[]}},"allow-set-overlay-icon":{"identifier":"allow-set-overlay-icon","description":"Enables the set_overlay_icon command without any pre-configured scope.","commands":{"allow":["set_overlay_icon"],"deny":[]}},"allow-set-position":{"identifier":"allow-set-position","description":"Enables the set_position command without any pre-configured scope.","commands":{"allow":["set_position"],"deny":[]}},"allow-set-progress-bar":{"identifier":"allow-set-progress-bar","description":"Enables the set_progress_bar command without any pre-configured scope.","commands":{"allow":["set_progress_bar"],"deny":[]}},"allow-set-resizable":{"identifier":"allow-set-resizable","description":"Enables the set_resizable command without any pre-configured scope.","commands":{"allow":["set_resizable"],"deny":[]}},"allow-set-shadow":{"identifier":"allow-set-shadow","description":"Enables the set_shadow command without any pre-configured scope.","commands":{"allow":["set_shadow"],"deny":[]}},"allow-set-simple-fullscreen":{"identifier":"allow-set-simple-fullscreen","description":"Enables the set_simple_fullscreen command without any pre-configured scope.","commands":{"allow":["set_simple_fullscreen"],"deny":[]}},"allow-set-size":{"identifier":"allow-set-size","description":"Enables the set_size command without any pre-configured scope.","commands":{"allow":["set_size"],"deny":[]}},"allow-set-size-constraints":{"identifier":"allow-set-size-constraints","description":"Enables the set_size_constraints command without any pre-configured scope.","commands":{"allow":["set_size_constraints"],"deny":[]}},"allow-set-skip-taskbar":{"identifier":"allow-set-skip-taskbar","description":"Enables the set_skip_taskbar command without any pre-configured scope.","commands":{"allow":["set_skip_taskbar"],"deny":[]}},"allow-set-theme":{"identifier":"allow-set-theme","description":"Enables the set_theme command without any pre-configured scope.","commands":{"allow":["set_theme"],"deny":[]}},"allow-set-title":{"identifier":"allow-set-title","description":"Enables the set_title command without any pre-configured scope.","commands":{"allow":["set_title"],"deny":[]}},"allow-set-title-bar-style":{"identifier":"allow-set-title-bar-style","description":"Enables the set_title_bar_style command without any pre-configured scope.","commands":{"allow":["set_title_bar_style"],"deny":[]}},"allow-set-visible-on-all-workspaces":{"identifier":"allow-set-visible-on-all-workspaces","description":"Enables the set_visible_on_all_workspaces command without any pre-configured scope.","commands":{"allow":["set_visible_on_all_workspaces"],"deny":[]}},"allow-show":{"identifier":"allow-show","description":"Enables the show command without any pre-configured scope.","commands":{"allow":["show"],"deny":[]}},"allow-start-dragging":{"identifier":"allow-start-dragging","description":"Enables the start_dragging command without any pre-configured scope.","commands":{"allow":["start_dragging"],"deny":[]}},"allow-start-resize-dragging":{"identifier":"allow-start-resize-dragging","description":"Enables the start_resize_dragging command without any pre-configured scope.","commands":{"allow":["start_resize_dragging"],"deny":[]}},"allow-theme":{"identifier":"allow-theme","description":"Enables the theme command without any pre-configured scope.","commands":{"allow":["theme"],"deny":[]}},"allow-title":{"identifier":"allow-title","description":"Enables the title command without any pre-configured scope.","commands":{"allow":["title"],"deny":[]}},"allow-toggle-maximize":{"identifier":"allow-toggle-maximize","description":"Enables the toggle_maximize command without any pre-configured scope.","commands":{"allow":["toggle_maximize"],"deny":[]}},"allow-unmaximize":{"identifier":"allow-unmaximize","description":"Enables the unmaximize command without any pre-configured scope.","commands":{"allow":["unmaximize"],"deny":[]}},"allow-unminimize":{"identifier":"allow-unminimize","description":"Enables the unminimize command without any pre-configured scope.","commands":{"allow":["unminimize"],"deny":[]}},"deny-available-monitors":{"identifier":"deny-available-monitors","description":"Denies the available_monitors command without any pre-configured scope.","commands":{"allow":[],"deny":["available_monitors"]}},"deny-center":{"identifier":"deny-center","description":"Denies the center command without any pre-configured scope.","commands":{"allow":[],"deny":["center"]}},"deny-close":{"identifier":"deny-close","description":"Denies the close command without any pre-configured scope.","commands":{"allow":[],"deny":["close"]}},"deny-create":{"identifier":"deny-create","description":"Denies the create command without any pre-configured scope.","commands":{"allow":[],"deny":["create"]}},"deny-current-monitor":{"identifier":"deny-current-monitor","description":"Denies the current_monitor command without any pre-configured scope.","commands":{"allow":[],"deny":["current_monitor"]}},"deny-cursor-position":{"identifier":"deny-cursor-position","description":"Denies the cursor_position command without any pre-configured scope.","commands":{"allow":[],"deny":["cursor_position"]}},"deny-destroy":{"identifier":"deny-destroy","description":"Denies the destroy command without any pre-configured scope.","commands":{"allow":[],"deny":["destroy"]}},"deny-get-all-windows":{"identifier":"deny-get-all-windows","description":"Denies the get_all_windows command without any pre-configured scope.","commands":{"allow":[],"deny":["get_all_windows"]}},"deny-hide":{"identifier":"deny-hide","description":"Denies the hide command without any pre-configured scope.","commands":{"allow":[],"deny":["hide"]}},"deny-inner-position":{"identifier":"deny-inner-position","description":"Denies the inner_position command without any pre-configured scope.","commands":{"allow":[],"deny":["inner_position"]}},"deny-inner-size":{"identifier":"deny-inner-size","description":"Denies the inner_size command without any pre-configured scope.","commands":{"allow":[],"deny":["inner_size"]}},"deny-internal-toggle-maximize":{"identifier":"deny-internal-toggle-maximize","description":"Denies the internal_toggle_maximize command without any pre-configured scope.","commands":{"allow":[],"deny":["internal_toggle_maximize"]}},"deny-is-always-on-top":{"identifier":"deny-is-always-on-top","description":"Denies the is_always_on_top command without any pre-configured scope.","commands":{"allow":[],"deny":["is_always_on_top"]}},"deny-is-closable":{"identifier":"deny-is-closable","description":"Denies the is_closable command without any pre-configured scope.","commands":{"allow":[],"deny":["is_closable"]}},"deny-is-decorated":{"identifier":"deny-is-decorated","description":"Denies the is_decorated command without any pre-configured scope.","commands":{"allow":[],"deny":["is_decorated"]}},"deny-is-enabled":{"identifier":"deny-is-enabled","description":"Denies the is_enabled command without any pre-configured scope.","commands":{"allow":[],"deny":["is_enabled"]}},"deny-is-focused":{"identifier":"deny-is-focused","description":"Denies the is_focused command without any pre-configured scope.","commands":{"allow":[],"deny":["is_focused"]}},"deny-is-fullscreen":{"identifier":"deny-is-fullscreen","description":"Denies the is_fullscreen command without any pre-configured scope.","commands":{"allow":[],"deny":["is_fullscreen"]}},"deny-is-maximizable":{"identifier":"deny-is-maximizable","description":"Denies the is_maximizable command without any pre-configured scope.","commands":{"allow":[],"deny":["is_maximizable"]}},"deny-is-maximized":{"identifier":"deny-is-maximized","description":"Denies the is_maximized command without any pre-configured scope.","commands":{"allow":[],"deny":["is_maximized"]}},"deny-is-minimizable":{"identifier":"deny-is-minimizable","description":"Denies the is_minimizable command without any pre-configured scope.","commands":{"allow":[],"deny":["is_minimizable"]}},"deny-is-minimized":{"identifier":"deny-is-minimized","description":"Denies the is_minimized command without any pre-configured scope.","commands":{"allow":[],"deny":["is_minimized"]}},"deny-is-resizable":{"identifier":"deny-is-resizable","description":"Denies the is_resizable command without any pre-configured scope.","commands":{"allow":[],"deny":["is_resizable"]}},"deny-is-visible":{"identifier":"deny-is-visible","description":"Denies the is_visible command without any pre-configured scope.","commands":{"allow":[],"deny":["is_visible"]}},"deny-maximize":{"identifier":"deny-maximize","description":"Denies the maximize command without any pre-configured scope.","commands":{"allow":[],"deny":["maximize"]}},"deny-minimize":{"identifier":"deny-minimize","description":"Denies the minimize command without any pre-configured scope.","commands":{"allow":[],"deny":["minimize"]}},"deny-monitor-from-point":{"identifier":"deny-monitor-from-point","description":"Denies the monitor_from_point command without any pre-configured scope.","commands":{"allow":[],"deny":["monitor_from_point"]}},"deny-outer-position":{"identifier":"deny-outer-position","description":"Denies the outer_position command without any pre-configured scope.","commands":{"allow":[],"deny":["outer_position"]}},"deny-outer-size":{"identifier":"deny-outer-size","description":"Denies the outer_size command without any pre-configured scope.","commands":{"allow":[],"deny":["outer_size"]}},"deny-primary-monitor":{"identifier":"deny-primary-monitor","description":"Denies the primary_monitor command without any pre-configured scope.","commands":{"allow":[],"deny":["primary_monitor"]}},"deny-request-user-attention":{"identifier":"deny-request-user-attention","description":"Denies the request_user_attention command without any pre-configured scope.","commands":{"allow":[],"deny":["request_user_attention"]}},"deny-scale-factor":{"identifier":"deny-scale-factor","description":"Denies the scale_factor command without any pre-configured scope.","commands":{"allow":[],"deny":["scale_factor"]}},"deny-set-always-on-bottom":{"identifier":"deny-set-always-on-bottom","description":"Denies the set_always_on_bottom command without any pre-configured scope.","commands":{"allow":[],"deny":["set_always_on_bottom"]}},"deny-set-always-on-top":{"identifier":"deny-set-always-on-top","description":"Denies the set_always_on_top command without any pre-configured scope.","commands":{"allow":[],"deny":["set_always_on_top"]}},"deny-set-background-color":{"identifier":"deny-set-background-color","description":"Denies the set_background_color command without any pre-configured scope.","commands":{"allow":[],"deny":["set_background_color"]}},"deny-set-badge-count":{"identifier":"deny-set-badge-count","description":"Denies the set_badge_count command without any pre-configured scope.","commands":{"allow":[],"deny":["set_badge_count"]}},"deny-set-badge-label":{"identifier":"deny-set-badge-label","description":"Denies the set_badge_label command without any pre-configured scope.","commands":{"allow":[],"deny":["set_badge_label"]}},"deny-set-closable":{"identifier":"deny-set-closable","description":"Denies the set_closable command without any pre-configured scope.","commands":{"allow":[],"deny":["set_closable"]}},"deny-set-content-protected":{"identifier":"deny-set-content-protected","description":"Denies the set_content_protected command without any pre-configured scope.","commands":{"allow":[],"deny":["set_content_protected"]}},"deny-set-cursor-grab":{"identifier":"deny-set-cursor-grab","description":"Denies the set_cursor_grab command without any pre-configured scope.","commands":{"allow":[],"deny":["set_cursor_grab"]}},"deny-set-cursor-icon":{"identifier":"deny-set-cursor-icon","description":"Denies the set_cursor_icon command without any pre-configured scope.","commands":{"allow":[],"deny":["set_cursor_icon"]}},"deny-set-cursor-position":{"identifier":"deny-set-cursor-position","description":"Denies the set_cursor_position command without any pre-configured scope.","commands":{"allow":[],"deny":["set_cursor_position"]}},"deny-set-cursor-visible":{"identifier":"deny-set-cursor-visible","description":"Denies the set_cursor_visible command without any pre-configured scope.","commands":{"allow":[],"deny":["set_cursor_visible"]}},"deny-set-decorations":{"identifier":"deny-set-decorations","description":"Denies the set_decorations command without any pre-configured scope.","commands":{"allow":[],"deny":["set_decorations"]}},"deny-set-effects":{"identifier":"deny-set-effects","description":"Denies the set_effects command without any pre-configured scope.","commands":{"allow":[],"deny":["set_effects"]}},"deny-set-enabled":{"identifier":"deny-set-enabled","description":"Denies the set_enabled command without any pre-configured scope.","commands":{"allow":[],"deny":["set_enabled"]}},"deny-set-focus":{"identifier":"deny-set-focus","description":"Denies the set_focus command without any pre-configured scope.","commands":{"allow":[],"deny":["set_focus"]}},"deny-set-focusable":{"identifier":"deny-set-focusable","description":"Denies the set_focusable command without any pre-configured scope.","commands":{"allow":[],"deny":["set_focusable"]}},"deny-set-fullscreen":{"identifier":"deny-set-fullscreen","description":"Denies the set_fullscreen command without any pre-configured scope.","commands":{"allow":[],"deny":["set_fullscreen"]}},"deny-set-icon":{"identifier":"deny-set-icon","description":"Denies the set_icon command without any pre-configured scope.","commands":{"allow":[],"deny":["set_icon"]}},"deny-set-ignore-cursor-events":{"identifier":"deny-set-ignore-cursor-events","description":"Denies the set_ignore_cursor_events command without any pre-configured scope.","commands":{"allow":[],"deny":["set_ignore_cursor_events"]}},"deny-set-max-size":{"identifier":"deny-set-max-size","description":"Denies the set_max_size command without any pre-configured scope.","commands":{"allow":[],"deny":["set_max_size"]}},"deny-set-maximizable":{"identifier":"deny-set-maximizable","description":"Denies the set_maximizable command without any pre-configured scope.","commands":{"allow":[],"deny":["set_maximizable"]}},"deny-set-min-size":{"identifier":"deny-set-min-size","description":"Denies the set_min_size command without any pre-configured scope.","commands":{"allow":[],"deny":["set_min_size"]}},"deny-set-minimizable":{"identifier":"deny-set-minimizable","description":"Denies the set_minimizable command without any pre-configured scope.","commands":{"allow":[],"deny":["set_minimizable"]}},"deny-set-overlay-icon":{"identifier":"deny-set-overlay-icon","description":"Denies the set_overlay_icon command without any pre-configured scope.","commands":{"allow":[],"deny":["set_overlay_icon"]}},"deny-set-position":{"identifier":"deny-set-position","description":"Denies the set_position command without any pre-configured scope.","commands":{"allow":[],"deny":["set_position"]}},"deny-set-progress-bar":{"identifier":"deny-set-progress-bar","description":"Denies the set_progress_bar command without any pre-configured scope.","commands":{"allow":[],"deny":["set_progress_bar"]}},"deny-set-resizable":{"identifier":"deny-set-resizable","description":"Denies the set_resizable command without any pre-configured scope.","commands":{"allow":[],"deny":["set_resizable"]}},"deny-set-shadow":{"identifier":"deny-set-shadow","description":"Denies the set_shadow command without any pre-configured scope.","commands":{"allow":[],"deny":["set_shadow"]}},"deny-set-simple-fullscreen":{"identifier":"deny-set-simple-fullscreen","description":"Denies the set_simple_fullscreen command without any pre-configured scope.","commands":{"allow":[],"deny":["set_simple_fullscreen"]}},"deny-set-size":{"identifier":"deny-set-size","description":"Denies the set_size command without any pre-configured scope.","commands":{"allow":[],"deny":["set_size"]}},"deny-set-size-constraints":{"identifier":"deny-set-size-constraints","description":"Denies the set_size_constraints command without any pre-configured scope.","commands":{"allow":[],"deny":["set_size_constraints"]}},"deny-set-skip-taskbar":{"identifier":"deny-set-skip-taskbar","description":"Denies the set_skip_taskbar command without any pre-configured scope.","commands":{"allow":[],"deny":["set_skip_taskbar"]}},"deny-set-theme":{"identifier":"deny-set-theme","description":"Denies the set_theme command without any pre-configured scope.","commands":{"allow":[],"deny":["set_theme"]}},"deny-set-title":{"identifier":"deny-set-title","description":"Denies the set_title command without any pre-configured scope.","commands":{"allow":[],"deny":["set_title"]}},"deny-set-title-bar-style":{"identifier":"deny-set-title-bar-style","description":"Denies the set_title_bar_style command without any pre-configured scope.","commands":{"allow":[],"deny":["set_title_bar_style"]}},"deny-set-visible-on-all-workspaces":{"identifier":"deny-set-visible-on-all-workspaces","description":"Denies the set_visible_on_all_workspaces command without any pre-configured scope.","commands":{"allow":[],"deny":["set_visible_on_all_workspaces"]}},"deny-show":{"identifier":"deny-show","description":"Denies the show command without any pre-configured scope.","commands":{"allow":[],"deny":["show"]}},"deny-start-dragging":{"identifier":"deny-start-dragging","description":"Denies the start_dragging command without any pre-configured scope.","commands":{"allow":[],"deny":["start_dragging"]}},"deny-start-resize-dragging":{"identifier":"deny-start-resize-dragging","description":"Denies the start_resize_dragging command without any pre-configured scope.","commands":{"allow":[],"deny":["start_resize_dragging"]}},"deny-theme":{"identifier":"deny-theme","description":"Denies the theme command without any pre-configured scope.","commands":{"allow":[],"deny":["theme"]}},"deny-title":{"identifier":"deny-title","description":"Denies the title command without any pre-configured scope.","commands":{"allow":[],"deny":["title"]}},"deny-toggle-maximize":{"identifier":"deny-toggle-maximize","description":"Denies the toggle_maximize command without any pre-configured scope.","commands":{"allow":[],"deny":["toggle_maximize"]}},"deny-unmaximize":{"identifier":"deny-unmaximize","description":"Denies the unmaximize command without any pre-configured scope.","commands":{"allow":[],"deny":["unmaximize"]}},"deny-unminimize":{"identifier":"deny-unminimize","description":"Denies the unminimize command without any pre-configured scope.","commands":{"allow":[],"deny":["unminimize"]}}},"permission_sets":{},"global_scope_schema":null},"dialog":{"default_permission":{"identifier":"default","description":"This permission set configures the types of dialogs\navailable from the dialog plugin.\n\n#### Granted Permissions\n\nAll dialog types are enabled.\n\n\n","permissions":["allow-ask","allow-confirm","allow-message","allow-save","allow-open"]},"permissions":{"allow-ask":{"identifier":"allow-ask","description":"Enables the ask command without any pre-configured scope.","commands":{"allow":["ask"],"deny":[]}},"allow-confirm":{"identifier":"allow-confirm","description":"Enables the confirm command without any pre-configured scope.","commands":{"allow":["confirm"],"deny":[]}},"allow-message":{"identifier":"allow-message","description":"Enables the message command without any pre-configured scope.","commands":{"allow":["message"],"deny":[]}},"allow-open":{"identifier":"allow-open","description":"Enables the open command without any pre-configured scope.","commands":{"allow":["open"],"deny":[]}},"allow-save":{"identifier":"allow-save","description":"Enables the save command without any pre-configured scope.","commands":{"allow":["save"],"deny":[]}},"deny-ask":{"identifier":"deny-ask","description":"Denies the ask command without any pre-configured scope.","commands":{"allow":[],"deny":["ask"]}},"deny-confirm":{"identifier":"deny-confirm","description":"Denies the confirm command without any pre-configured scope.","commands":{"allow":[],"deny":["confirm"]}},"deny-message":{"identifier":"deny-message","description":"Denies the message command without any pre-configured scope.","commands":{"allow":[],"deny":["message"]}},"deny-open":{"identifier":"deny-open","description":"Denies the open command without any pre-configured scope.","commands":{"allow":[],"deny":["open"]}},"deny-save":{"identifier":"deny-save","description":"Denies the save command without any pre-configured scope.","commands":{"allow":[],"deny":["save"]}}},"permission_sets":{},"global_scope_schema":null},"global-shortcut":{"default_permission":{"identifier":"default","description":"No features are enabled by default, as we believe\nthe shortcuts can be inherently dangerous and it is\napplication specific if specific shortcuts should be\nregistered or unregistered.\n","permissions":[]},"permissions":{"allow-is-registered":{"identifier":"allow-is-registered","description":"Enables the is_registered command without any pre-configured scope.","commands":{"allow":["is_registered"],"deny":[]}},"allow-register":{"identifier":"allow-register","description":"Enables the register command without any pre-configured scope.","commands":{"allow":["register"],"deny":[]}},"allow-register-all":{"identifier":"allow-register-all","description":"Enables the register_all command without any pre-configured scope.","commands":{"allow":["register_all"],"deny":[]}},"allow-unregister":{"identifier":"allow-unregister","description":"Enables the unregister command without any pre-configured scope.","commands":{"allow":["unregister"],"deny":[]}},"allow-unregister-all":{"identifier":"allow-unregister-all","description":"Enables the unregister_all command without any pre-configured scope.","commands":{"allow":["unregister_all"],"deny":[]}},"deny-is-registered":{"identifier":"deny-is-registered","description":"Denies the is_registered command without any pre-configured scope.","commands":{"allow":[],"deny":["is_registered"]}},"deny-register":{"identifier":"deny-register","description":"Denies the register command without any pre-configured scope.","commands":{"allow":[],"deny":["register"]}},"deny-register-all":{"identifier":"deny-register-all","description":"Denies the register_all command without any pre-configured scope.","commands":{"allow":[],"deny":["register_all"]}},"deny-unregister":{"identifier":"deny-unregister","description":"Denies the unregister command without any pre-configured scope.","commands":{"allow":[],"deny":["unregister"]}},"deny-unregister-all":{"identifier":"deny-unregister-all","description":"Denies the unregister_all command without any pre-configured scope.","commands":{"allow":[],"deny":["unregister_all"]}}},"permission_sets":{},"global_scope_schema":null},"mcp":{"default_permission":{"identifier":"default","description":"This permission set configures what kind of\noperations are available from the mcp plugin.\n\n#### Granted Permissions\n\nAll operations are enabled by default.\n","permissions":["allow-connect-server","allow-disconnect-server","allow-list-tools","allow-call-tool"]},"permissions":{"allow-call-tool":{"identifier":"allow-call-tool","description":"Enables the call_tool command without any pre-configured scope.","commands":{"allow":["call_tool"],"deny":[]}},"allow-connect-server":{"identifier":"allow-connect-server","description":"Enables the connect_server command without any pre-configured scope.","commands":{"allow":["connect_server"],"deny":[]}},"allow-disconnect-server":{"identifier":"allow-disconnect-server","description":"Enables the disconnect_server command without any pre-configured scope.","commands":{"allow":["disconnect_server"],"deny":[]}},"allow-list-tools":{"identifier":"allow-list-tools","description":"Enables the list_tools command without any pre-configured scope.","commands":{"allow":["list_tools"],"deny":[]}},"deny-call-tool":{"identifier":"deny-call-tool","description":"Denies the call_tool command without any pre-configured scope.","commands":{"allow":[],"deny":["call_tool"]}},"deny-connect-server":{"identifier":"deny-connect-server","description":"Denies the connect_server command without any pre-configured scope.","commands":{"allow":[],"deny":["connect_server"]}},"deny-disconnect-server":{"identifier":"deny-disconnect-server","description":"Denies the disconnect_server command without any pre-configured scope.","commands":{"allow":[],"deny":["disconnect_server"]}},"deny-list-tools":{"identifier":"deny-list-tools","description":"Denies the list_tools command without any pre-configured scope.","commands":{"allow":[],"deny":["list_tools"]}}},"permission_sets":{},"global_scope_schema":null},"opener":{"default_permission":{"identifier":"default","description":"This permission set allows opening `mailto:`, `tel:`, `https://` and `http://` urls using their default application\nas well as reveal file in directories using default file explorer","permissions":["allow-open-url","allow-reveal-item-in-dir","allow-default-urls"]},"permissions":{"allow-default-urls":{"identifier":"allow-default-urls","description":"This enables opening `mailto:`, `tel:`, `https://` and `http://` urls using their default application.","commands":{"allow":[],"deny":[]},"scope":{"allow":[{"url":"mailto:*"},{"url":"tel:*"},{"url":"http://*"},{"url":"https://*"}]}},"allow-open-path":{"identifier":"allow-open-path","description":"Enables the open_path command without any pre-configured scope.","commands":{"allow":["open_path"],"deny":[]}},"allow-open-url":{"identifier":"allow-open-url","description":"Enables the open_url command without any pre-configured scope.","commands":{"allow":["open_url"],"deny":[]}},"allow-reveal-item-in-dir":{"identifier":"allow-reveal-item-in-dir","description":"Enables the reveal_item_in_dir command without any pre-configured scope.","commands":{"allow":["reveal_item_in_dir"],"deny":[]}},"deny-open-path":{"identifier":"deny-open-path","description":"Denies the open_path command without any pre-configured scope.","commands":{"allow":[],"deny":["open_path"]}},"deny-open-url":{"identifier":"deny-open-url","description":"Denies the open_url command without any pre-configured scope.","commands":{"allow":[],"deny":["open_url"]}},"deny-reveal-item-in-dir":{"identifier":"deny-reveal-item-in-dir","description":"Denies the reveal_item_in_dir command without any pre-configured scope.","commands":{"allow":[],"deny":["reveal_item_in_dir"]}}},"permission_sets":{},"global_scope_schema":{"$schema":"http://json-schema.org/draft-07/schema#","anyOf":[{"properties":{"app":{"allOf":[{"$ref":"#/definitions/Application"}],"description":"An application to open this url with, for example: firefox."},"url":{"description":"A URL that can be opened by the webview when using the Opener APIs.\n\nWildcards can be used following the UNIX glob pattern.\n\nExamples:\n\n- \"https://*\" : allows all HTTPS origin\n\n- \"https://*.github.com/tauri-apps/tauri\": allows any subdomain of \"github.com\" with the \"tauri-apps/api\" path\n\n- \"https://myapi.service.com/users/*\": allows access to any URLs that begins with \"https://myapi.service.com/users/\"","type":"string"}},"required":["url"],"type":"object"},{"properties":{"app":{"allOf":[{"$ref":"#/definitions/Application"}],"description":"An application to open this path with, for example: xdg-open."},"path":{"description":"A path that can be opened by the webview when using the Opener APIs.\n\nThe pattern can start with a variable that resolves to a system base directory. The variables are: `$AUDIO`, `$CACHE`, `$CONFIG`, `$DATA`, `$LOCALDATA`, `$DESKTOP`, `$DOCUMENT`, `$DOWNLOAD`, `$EXE`, `$FONT`, `$HOME`, `$PICTURE`, `$PUBLIC`, `$RUNTIME`, `$TEMPLATE`, `$VIDEO`, `$RESOURCE`, `$APP`, `$LOG`, `$TEMP`, `$APPCONFIG`, `$APPDATA`, `$APPLOCALDATA`, `$APPCACHE`, `$APPLOG`.","type":"string"}},"required":["path"],"type":"object"}],"definitions":{"Application":{"anyOf":[{"description":"Open in default application.","type":"null"},{"description":"If true, allow open with any application.","type":"boolean"},{"description":"Allow specific application to open with.","type":"string"}],"description":"Opener scope application."}},"description":"Opener scope entry.","title":"OpenerScopeEntry"}}} \ No newline at end of file diff --git a/src-tauri/gen/schemas/capabilities.json b/src-tauri/gen/schemas/capabilities.json new file mode 100644 index 0000000..b965498 --- /dev/null +++ b/src-tauri/gen/schemas/capabilities.json @@ -0,0 +1 @@ +{"default":{"identifier":"default","description":"Capability for the main window","local":true,"windows":["main","tasks-float"],"permissions":["core:default","core:window:allow-start-dragging","core:window:allow-set-always-on-top","core:window:allow-minimize","core:window:allow-toggle-maximize","core:window:allow-is-maximized","core:window:allow-close","core:window:allow-hide","core:window:allow-show","core:window:allow-set-focus","opener:default","dialog:default","global-shortcut:allow-register","global-shortcut:allow-unregister"]}} \ No newline at end of file diff --git a/src-tauri/gen/schemas/desktop-schema.json b/src-tauri/gen/schemas/desktop-schema.json new file mode 100644 index 0000000..608d2ed --- /dev/null +++ b/src-tauri/gen/schemas/desktop-schema.json @@ -0,0 +1,2663 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "CapabilityFile", + "description": "Capability formats accepted in a capability file.", + "anyOf": [ + { + "description": "A single capability.", + "allOf": [ + { + "$ref": "#/definitions/Capability" + } + ] + }, + { + "description": "A list of capabilities.", + "type": "array", + "items": { + "$ref": "#/definitions/Capability" + } + }, + { + "description": "A list of capabilities.", + "type": "object", + "required": [ + "capabilities" + ], + "properties": { + "capabilities": { + "description": "The list of capabilities.", + "type": "array", + "items": { + "$ref": "#/definitions/Capability" + } + } + } + } + ], + "definitions": { + "Capability": { + "description": "A grouping and boundary mechanism developers can use to isolate access to the IPC layer.\n\nIt controls application windows' and webviews' fine grained access to the Tauri core, application, or plugin commands. If a webview or its window is not matching any capability then it has no access to the IPC layer at all.\n\nThis can be done to create groups of windows, based on their required system access, which can reduce impact of frontend vulnerabilities in less privileged windows. Windows can be added to a capability by exact name (e.g. `main-window`) or glob patterns like `*` or `admin-*`. A Window can have none, one, or multiple associated capabilities.\n\n## Example\n\n```json { \"identifier\": \"main-user-files-write\", \"description\": \"This capability allows the `main` window on macOS and Windows access to `filesystem` write related commands and `dialog` commands to enable programmatic access to files selected by the user.\", \"windows\": [ \"main\" ], \"permissions\": [ \"core:default\", \"dialog:open\", { \"identifier\": \"fs:allow-write-text-file\", \"allow\": [{ \"path\": \"$HOME/test.txt\" }] }, ], \"platforms\": [\"macOS\",\"windows\"] } ```", + "type": "object", + "required": [ + "identifier", + "permissions" + ], + "properties": { + "identifier": { + "description": "Identifier of the capability.\n\n## Example\n\n`main-user-files-write`", + "type": "string" + }, + "description": { + "description": "Description of what the capability is intended to allow on associated windows.\n\nIt should contain a description of what the grouped permissions should allow.\n\n## Example\n\nThis capability allows the `main` window access to `filesystem` write related commands and `dialog` commands to enable programmatic access to files selected by the user.", + "default": "", + "type": "string" + }, + "remote": { + "description": "Configure remote URLs that can use the capability permissions.\n\nThis setting is optional and defaults to not being set, as our default use case is that the content is served from our local application.\n\n:::caution Make sure you understand the security implications of providing remote sources with local system access. :::\n\n## Example\n\n```json { \"urls\": [\"https://*.mydomain.dev\"] } ```", + "anyOf": [ + { + "$ref": "#/definitions/CapabilityRemote" + }, + { + "type": "null" + } + ] + }, + "local": { + "description": "Whether this capability is enabled for local app URLs or not. Defaults to `true`.", + "default": true, + "type": "boolean" + }, + "windows": { + "description": "List of windows that are affected by this capability. Can be a glob pattern.\n\nIf a window label matches any of the patterns in this list, the capability will be enabled on all the webviews of that window, regardless of the value of [`Self::webviews`].\n\nOn multiwebview windows, prefer specifying [`Self::webviews`] and omitting [`Self::windows`] for a fine grained access control.\n\n## Example\n\n`[\"main\"]`", + "type": "array", + "items": { + "type": "string" + } + }, + "webviews": { + "description": "List of webviews that are affected by this capability. Can be a glob pattern.\n\nThe capability will be enabled on all the webviews whose label matches any of the patterns in this list, regardless of whether the webview's window label matches a pattern in [`Self::windows`].\n\n## Example\n\n`[\"sub-webview-one\", \"sub-webview-two\"]`", + "type": "array", + "items": { + "type": "string" + } + }, + "permissions": { + "description": "List of permissions attached to this capability.\n\nMust include the plugin name as prefix in the form of `${plugin-name}:${permission-name}`. For commands directly implemented in the application itself only `${permission-name}` is required.\n\n## Example\n\n```json [ \"core:default\", \"shell:allow-open\", \"dialog:open\", { \"identifier\": \"fs:allow-write-text-file\", \"allow\": [{ \"path\": \"$HOME/test.txt\" }] } ] ```", + "type": "array", + "items": { + "$ref": "#/definitions/PermissionEntry" + }, + "uniqueItems": true + }, + "platforms": { + "description": "Limit which target platforms this capability applies to.\n\nBy default all platforms are targeted.\n\n## Example\n\n`[\"macOS\",\"windows\"]`", + "type": [ + "array", + "null" + ], + "items": { + "$ref": "#/definitions/Target" + } + } + } + }, + "CapabilityRemote": { + "description": "Configuration for remote URLs that are associated with the capability.", + "type": "object", + "required": [ + "urls" + ], + "properties": { + "urls": { + "description": "Remote domains this capability refers to using the [URLPattern standard](https://urlpattern.spec.whatwg.org/).\n\n## Examples\n\n- \"https://*.mydomain.dev\": allows subdomains of mydomain.dev - \"https://mydomain.dev/api/*\": allows any subpath of mydomain.dev/api", + "type": "array", + "items": { + "type": "string" + } + } + } + }, + "PermissionEntry": { + "description": "An entry for a permission value in a [`Capability`] can be either a raw permission [`Identifier`] or an object that references a permission and extends its scope.", + "anyOf": [ + { + "description": "Reference a permission or permission set by identifier.", + "allOf": [ + { + "$ref": "#/definitions/Identifier" + } + ] + }, + { + "description": "Reference a permission or permission set by identifier and extends its scope.", + "type": "object", + "allOf": [ + { + "if": { + "properties": { + "identifier": { + "anyOf": [ + { + "description": "This permission set allows opening `mailto:`, `tel:`, `https://` and `http://` urls using their default application\nas well as reveal file in directories using default file explorer\n#### This default permission set includes:\n\n- `allow-open-url`\n- `allow-reveal-item-in-dir`\n- `allow-default-urls`", + "type": "string", + "const": "opener:default", + "markdownDescription": "This permission set allows opening `mailto:`, `tel:`, `https://` and `http://` urls using their default application\nas well as reveal file in directories using default file explorer\n#### This default permission set includes:\n\n- `allow-open-url`\n- `allow-reveal-item-in-dir`\n- `allow-default-urls`" + }, + { + "description": "This enables opening `mailto:`, `tel:`, `https://` and `http://` urls using their default application.", + "type": "string", + "const": "opener:allow-default-urls", + "markdownDescription": "This enables opening `mailto:`, `tel:`, `https://` and `http://` urls using their default application." + }, + { + "description": "Enables the open_path command without any pre-configured scope.", + "type": "string", + "const": "opener:allow-open-path", + "markdownDescription": "Enables the open_path command without any pre-configured scope." + }, + { + "description": "Enables the open_url command without any pre-configured scope.", + "type": "string", + "const": "opener:allow-open-url", + "markdownDescription": "Enables the open_url command without any pre-configured scope." + }, + { + "description": "Enables the reveal_item_in_dir command without any pre-configured scope.", + "type": "string", + "const": "opener:allow-reveal-item-in-dir", + "markdownDescription": "Enables the reveal_item_in_dir command without any pre-configured scope." + }, + { + "description": "Denies the open_path command without any pre-configured scope.", + "type": "string", + "const": "opener:deny-open-path", + "markdownDescription": "Denies the open_path command without any pre-configured scope." + }, + { + "description": "Denies the open_url command without any pre-configured scope.", + "type": "string", + "const": "opener:deny-open-url", + "markdownDescription": "Denies the open_url command without any pre-configured scope." + }, + { + "description": "Denies the reveal_item_in_dir command without any pre-configured scope.", + "type": "string", + "const": "opener:deny-reveal-item-in-dir", + "markdownDescription": "Denies the reveal_item_in_dir command without any pre-configured scope." + } + ] + } + } + }, + "then": { + "properties": { + "allow": { + "items": { + "title": "OpenerScopeEntry", + "description": "Opener scope entry.", + "anyOf": [ + { + "type": "object", + "required": [ + "url" + ], + "properties": { + "app": { + "description": "An application to open this url with, for example: firefox.", + "allOf": [ + { + "$ref": "#/definitions/Application" + } + ] + }, + "url": { + "description": "A URL that can be opened by the webview when using the Opener APIs.\n\nWildcards can be used following the UNIX glob pattern.\n\nExamples:\n\n- \"https://*\" : allows all HTTPS origin\n\n- \"https://*.github.com/tauri-apps/tauri\": allows any subdomain of \"github.com\" with the \"tauri-apps/api\" path\n\n- \"https://myapi.service.com/users/*\": allows access to any URLs that begins with \"https://myapi.service.com/users/\"", + "type": "string" + } + } + }, + { + "type": "object", + "required": [ + "path" + ], + "properties": { + "app": { + "description": "An application to open this path with, for example: xdg-open.", + "allOf": [ + { + "$ref": "#/definitions/Application" + } + ] + }, + "path": { + "description": "A path that can be opened by the webview when using the Opener APIs.\n\nThe pattern can start with a variable that resolves to a system base directory. The variables are: `$AUDIO`, `$CACHE`, `$CONFIG`, `$DATA`, `$LOCALDATA`, `$DESKTOP`, `$DOCUMENT`, `$DOWNLOAD`, `$EXE`, `$FONT`, `$HOME`, `$PICTURE`, `$PUBLIC`, `$RUNTIME`, `$TEMPLATE`, `$VIDEO`, `$RESOURCE`, `$APP`, `$LOG`, `$TEMP`, `$APPCONFIG`, `$APPDATA`, `$APPLOCALDATA`, `$APPCACHE`, `$APPLOG`.", + "type": "string" + } + } + } + ] + } + }, + "deny": { + "items": { + "title": "OpenerScopeEntry", + "description": "Opener scope entry.", + "anyOf": [ + { + "type": "object", + "required": [ + "url" + ], + "properties": { + "app": { + "description": "An application to open this url with, for example: firefox.", + "allOf": [ + { + "$ref": "#/definitions/Application" + } + ] + }, + "url": { + "description": "A URL that can be opened by the webview when using the Opener APIs.\n\nWildcards can be used following the UNIX glob pattern.\n\nExamples:\n\n- \"https://*\" : allows all HTTPS origin\n\n- \"https://*.github.com/tauri-apps/tauri\": allows any subdomain of \"github.com\" with the \"tauri-apps/api\" path\n\n- \"https://myapi.service.com/users/*\": allows access to any URLs that begins with \"https://myapi.service.com/users/\"", + "type": "string" + } + } + }, + { + "type": "object", + "required": [ + "path" + ], + "properties": { + "app": { + "description": "An application to open this path with, for example: xdg-open.", + "allOf": [ + { + "$ref": "#/definitions/Application" + } + ] + }, + "path": { + "description": "A path that can be opened by the webview when using the Opener APIs.\n\nThe pattern can start with a variable that resolves to a system base directory. The variables are: `$AUDIO`, `$CACHE`, `$CONFIG`, `$DATA`, `$LOCALDATA`, `$DESKTOP`, `$DOCUMENT`, `$DOWNLOAD`, `$EXE`, `$FONT`, `$HOME`, `$PICTURE`, `$PUBLIC`, `$RUNTIME`, `$TEMPLATE`, `$VIDEO`, `$RESOURCE`, `$APP`, `$LOG`, `$TEMP`, `$APPCONFIG`, `$APPDATA`, `$APPLOCALDATA`, `$APPCACHE`, `$APPLOG`.", + "type": "string" + } + } + } + ] + } + } + } + }, + "properties": { + "identifier": { + "description": "Identifier of the permission or permission set.", + "allOf": [ + { + "$ref": "#/definitions/Identifier" + } + ] + } + } + }, + { + "properties": { + "identifier": { + "description": "Identifier of the permission or permission set.", + "allOf": [ + { + "$ref": "#/definitions/Identifier" + } + ] + }, + "allow": { + "description": "Data that defines what is allowed by the scope.", + "type": [ + "array", + "null" + ], + "items": { + "$ref": "#/definitions/Value" + } + }, + "deny": { + "description": "Data that defines what is denied by the scope. This should be prioritized by validation logic.", + "type": [ + "array", + "null" + ], + "items": { + "$ref": "#/definitions/Value" + } + } + } + } + ], + "required": [ + "identifier" + ] + } + ] + }, + "Identifier": { + "description": "Permission identifier", + "oneOf": [ + { + "description": "Default core plugins set.\n#### This default permission set includes:\n\n- `core:path:default`\n- `core:event:default`\n- `core:window:default`\n- `core:webview:default`\n- `core:app:default`\n- `core:image:default`\n- `core:resources:default`\n- `core:menu:default`\n- `core:tray:default`", + "type": "string", + "const": "core:default", + "markdownDescription": "Default core plugins set.\n#### This default permission set includes:\n\n- `core:path:default`\n- `core:event:default`\n- `core:window:default`\n- `core:webview:default`\n- `core:app:default`\n- `core:image:default`\n- `core:resources:default`\n- `core:menu:default`\n- `core:tray:default`" + }, + { + "description": "Default permissions for the plugin.\n#### This default permission set includes:\n\n- `allow-version`\n- `allow-name`\n- `allow-tauri-version`\n- `allow-identifier`\n- `allow-bundle-type`\n- `allow-register-listener`\n- `allow-remove-listener`", + "type": "string", + "const": "core:app:default", + "markdownDescription": "Default permissions for the plugin.\n#### This default permission set includes:\n\n- `allow-version`\n- `allow-name`\n- `allow-tauri-version`\n- `allow-identifier`\n- `allow-bundle-type`\n- `allow-register-listener`\n- `allow-remove-listener`" + }, + { + "description": "Enables the app_hide command without any pre-configured scope.", + "type": "string", + "const": "core:app:allow-app-hide", + "markdownDescription": "Enables the app_hide command without any pre-configured scope." + }, + { + "description": "Enables the app_show command without any pre-configured scope.", + "type": "string", + "const": "core:app:allow-app-show", + "markdownDescription": "Enables the app_show command without any pre-configured scope." + }, + { + "description": "Enables the bundle_type command without any pre-configured scope.", + "type": "string", + "const": "core:app:allow-bundle-type", + "markdownDescription": "Enables the bundle_type command without any pre-configured scope." + }, + { + "description": "Enables the default_window_icon command without any pre-configured scope.", + "type": "string", + "const": "core:app:allow-default-window-icon", + "markdownDescription": "Enables the default_window_icon command without any pre-configured scope." + }, + { + "description": "Enables the fetch_data_store_identifiers command without any pre-configured scope.", + "type": "string", + "const": "core:app:allow-fetch-data-store-identifiers", + "markdownDescription": "Enables the fetch_data_store_identifiers command without any pre-configured scope." + }, + { + "description": "Enables the identifier command without any pre-configured scope.", + "type": "string", + "const": "core:app:allow-identifier", + "markdownDescription": "Enables the identifier command without any pre-configured scope." + }, + { + "description": "Enables the name command without any pre-configured scope.", + "type": "string", + "const": "core:app:allow-name", + "markdownDescription": "Enables the name command without any pre-configured scope." + }, + { + "description": "Enables the register_listener command without any pre-configured scope.", + "type": "string", + "const": "core:app:allow-register-listener", + "markdownDescription": "Enables the register_listener command without any pre-configured scope." + }, + { + "description": "Enables the remove_data_store command without any pre-configured scope.", + "type": "string", + "const": "core:app:allow-remove-data-store", + "markdownDescription": "Enables the remove_data_store command without any pre-configured scope." + }, + { + "description": "Enables the remove_listener command without any pre-configured scope.", + "type": "string", + "const": "core:app:allow-remove-listener", + "markdownDescription": "Enables the remove_listener command without any pre-configured scope." + }, + { + "description": "Enables the set_app_theme command without any pre-configured scope.", + "type": "string", + "const": "core:app:allow-set-app-theme", + "markdownDescription": "Enables the set_app_theme command without any pre-configured scope." + }, + { + "description": "Enables the set_dock_visibility command without any pre-configured scope.", + "type": "string", + "const": "core:app:allow-set-dock-visibility", + "markdownDescription": "Enables the set_dock_visibility command without any pre-configured scope." + }, + { + "description": "Enables the tauri_version command without any pre-configured scope.", + "type": "string", + "const": "core:app:allow-tauri-version", + "markdownDescription": "Enables the tauri_version command without any pre-configured scope." + }, + { + "description": "Enables the version command without any pre-configured scope.", + "type": "string", + "const": "core:app:allow-version", + "markdownDescription": "Enables the version command without any pre-configured scope." + }, + { + "description": "Denies the app_hide command without any pre-configured scope.", + "type": "string", + "const": "core:app:deny-app-hide", + "markdownDescription": "Denies the app_hide command without any pre-configured scope." + }, + { + "description": "Denies the app_show command without any pre-configured scope.", + "type": "string", + "const": "core:app:deny-app-show", + "markdownDescription": "Denies the app_show command without any pre-configured scope." + }, + { + "description": "Denies the bundle_type command without any pre-configured scope.", + "type": "string", + "const": "core:app:deny-bundle-type", + "markdownDescription": "Denies the bundle_type command without any pre-configured scope." + }, + { + "description": "Denies the default_window_icon command without any pre-configured scope.", + "type": "string", + "const": "core:app:deny-default-window-icon", + "markdownDescription": "Denies the default_window_icon command without any pre-configured scope." + }, + { + "description": "Denies the fetch_data_store_identifiers command without any pre-configured scope.", + "type": "string", + "const": "core:app:deny-fetch-data-store-identifiers", + "markdownDescription": "Denies the fetch_data_store_identifiers command without any pre-configured scope." + }, + { + "description": "Denies the identifier command without any pre-configured scope.", + "type": "string", + "const": "core:app:deny-identifier", + "markdownDescription": "Denies the identifier command without any pre-configured scope." + }, + { + "description": "Denies the name command without any pre-configured scope.", + "type": "string", + "const": "core:app:deny-name", + "markdownDescription": "Denies the name command without any pre-configured scope." + }, + { + "description": "Denies the register_listener command without any pre-configured scope.", + "type": "string", + "const": "core:app:deny-register-listener", + "markdownDescription": "Denies the register_listener command without any pre-configured scope." + }, + { + "description": "Denies the remove_data_store command without any pre-configured scope.", + "type": "string", + "const": "core:app:deny-remove-data-store", + "markdownDescription": "Denies the remove_data_store command without any pre-configured scope." + }, + { + "description": "Denies the remove_listener command without any pre-configured scope.", + "type": "string", + "const": "core:app:deny-remove-listener", + "markdownDescription": "Denies the remove_listener command without any pre-configured scope." + }, + { + "description": "Denies the set_app_theme command without any pre-configured scope.", + "type": "string", + "const": "core:app:deny-set-app-theme", + "markdownDescription": "Denies the set_app_theme command without any pre-configured scope." + }, + { + "description": "Denies the set_dock_visibility command without any pre-configured scope.", + "type": "string", + "const": "core:app:deny-set-dock-visibility", + "markdownDescription": "Denies the set_dock_visibility command without any pre-configured scope." + }, + { + "description": "Denies the tauri_version command without any pre-configured scope.", + "type": "string", + "const": "core:app:deny-tauri-version", + "markdownDescription": "Denies the tauri_version command without any pre-configured scope." + }, + { + "description": "Denies the version command without any pre-configured scope.", + "type": "string", + "const": "core:app:deny-version", + "markdownDescription": "Denies the version command without any pre-configured scope." + }, + { + "description": "Default permissions for the plugin, which enables all commands.\n#### This default permission set includes:\n\n- `allow-listen`\n- `allow-unlisten`\n- `allow-emit`\n- `allow-emit-to`", + "type": "string", + "const": "core:event:default", + "markdownDescription": "Default permissions for the plugin, which enables all commands.\n#### This default permission set includes:\n\n- `allow-listen`\n- `allow-unlisten`\n- `allow-emit`\n- `allow-emit-to`" + }, + { + "description": "Enables the emit command without any pre-configured scope.", + "type": "string", + "const": "core:event:allow-emit", + "markdownDescription": "Enables the emit command without any pre-configured scope." + }, + { + "description": "Enables the emit_to command without any pre-configured scope.", + "type": "string", + "const": "core:event:allow-emit-to", + "markdownDescription": "Enables the emit_to command without any pre-configured scope." + }, + { + "description": "Enables the listen command without any pre-configured scope.", + "type": "string", + "const": "core:event:allow-listen", + "markdownDescription": "Enables the listen command without any pre-configured scope." + }, + { + "description": "Enables the unlisten command without any pre-configured scope.", + "type": "string", + "const": "core:event:allow-unlisten", + "markdownDescription": "Enables the unlisten command without any pre-configured scope." + }, + { + "description": "Denies the emit command without any pre-configured scope.", + "type": "string", + "const": "core:event:deny-emit", + "markdownDescription": "Denies the emit command without any pre-configured scope." + }, + { + "description": "Denies the emit_to command without any pre-configured scope.", + "type": "string", + "const": "core:event:deny-emit-to", + "markdownDescription": "Denies the emit_to command without any pre-configured scope." + }, + { + "description": "Denies the listen command without any pre-configured scope.", + "type": "string", + "const": "core:event:deny-listen", + "markdownDescription": "Denies the listen command without any pre-configured scope." + }, + { + "description": "Denies the unlisten command without any pre-configured scope.", + "type": "string", + "const": "core:event:deny-unlisten", + "markdownDescription": "Denies the unlisten command without any pre-configured scope." + }, + { + "description": "Default permissions for the plugin, which enables all commands.\n#### This default permission set includes:\n\n- `allow-new`\n- `allow-from-bytes`\n- `allow-from-path`\n- `allow-rgba`\n- `allow-size`", + "type": "string", + "const": "core:image:default", + "markdownDescription": "Default permissions for the plugin, which enables all commands.\n#### This default permission set includes:\n\n- `allow-new`\n- `allow-from-bytes`\n- `allow-from-path`\n- `allow-rgba`\n- `allow-size`" + }, + { + "description": "Enables the from_bytes command without any pre-configured scope.", + "type": "string", + "const": "core:image:allow-from-bytes", + "markdownDescription": "Enables the from_bytes command without any pre-configured scope." + }, + { + "description": "Enables the from_path command without any pre-configured scope.", + "type": "string", + "const": "core:image:allow-from-path", + "markdownDescription": "Enables the from_path command without any pre-configured scope." + }, + { + "description": "Enables the new command without any pre-configured scope.", + "type": "string", + "const": "core:image:allow-new", + "markdownDescription": "Enables the new command without any pre-configured scope." + }, + { + "description": "Enables the rgba command without any pre-configured scope.", + "type": "string", + "const": "core:image:allow-rgba", + "markdownDescription": "Enables the rgba command without any pre-configured scope." + }, + { + "description": "Enables the size command without any pre-configured scope.", + "type": "string", + "const": "core:image:allow-size", + "markdownDescription": "Enables the size command without any pre-configured scope." + }, + { + "description": "Denies the from_bytes command without any pre-configured scope.", + "type": "string", + "const": "core:image:deny-from-bytes", + "markdownDescription": "Denies the from_bytes command without any pre-configured scope." + }, + { + "description": "Denies the from_path command without any pre-configured scope.", + "type": "string", + "const": "core:image:deny-from-path", + "markdownDescription": "Denies the from_path command without any pre-configured scope." + }, + { + "description": "Denies the new command without any pre-configured scope.", + "type": "string", + "const": "core:image:deny-new", + "markdownDescription": "Denies the new command without any pre-configured scope." + }, + { + "description": "Denies the rgba command without any pre-configured scope.", + "type": "string", + "const": "core:image:deny-rgba", + "markdownDescription": "Denies the rgba command without any pre-configured scope." + }, + { + "description": "Denies the size command without any pre-configured scope.", + "type": "string", + "const": "core:image:deny-size", + "markdownDescription": "Denies the size command without any pre-configured scope." + }, + { + "description": "Default permissions for the plugin, which enables all commands.\n#### This default permission set includes:\n\n- `allow-new`\n- `allow-append`\n- `allow-prepend`\n- `allow-insert`\n- `allow-remove`\n- `allow-remove-at`\n- `allow-items`\n- `allow-get`\n- `allow-popup`\n- `allow-create-default`\n- `allow-set-as-app-menu`\n- `allow-set-as-window-menu`\n- `allow-text`\n- `allow-set-text`\n- `allow-is-enabled`\n- `allow-set-enabled`\n- `allow-set-accelerator`\n- `allow-set-as-windows-menu-for-nsapp`\n- `allow-set-as-help-menu-for-nsapp`\n- `allow-is-checked`\n- `allow-set-checked`\n- `allow-set-icon`", + "type": "string", + "const": "core:menu:default", + "markdownDescription": "Default permissions for the plugin, which enables all commands.\n#### This default permission set includes:\n\n- `allow-new`\n- `allow-append`\n- `allow-prepend`\n- `allow-insert`\n- `allow-remove`\n- `allow-remove-at`\n- `allow-items`\n- `allow-get`\n- `allow-popup`\n- `allow-create-default`\n- `allow-set-as-app-menu`\n- `allow-set-as-window-menu`\n- `allow-text`\n- `allow-set-text`\n- `allow-is-enabled`\n- `allow-set-enabled`\n- `allow-set-accelerator`\n- `allow-set-as-windows-menu-for-nsapp`\n- `allow-set-as-help-menu-for-nsapp`\n- `allow-is-checked`\n- `allow-set-checked`\n- `allow-set-icon`" + }, + { + "description": "Enables the append command without any pre-configured scope.", + "type": "string", + "const": "core:menu:allow-append", + "markdownDescription": "Enables the append command without any pre-configured scope." + }, + { + "description": "Enables the create_default command without any pre-configured scope.", + "type": "string", + "const": "core:menu:allow-create-default", + "markdownDescription": "Enables the create_default command without any pre-configured scope." + }, + { + "description": "Enables the get command without any pre-configured scope.", + "type": "string", + "const": "core:menu:allow-get", + "markdownDescription": "Enables the get command without any pre-configured scope." + }, + { + "description": "Enables the insert command without any pre-configured scope.", + "type": "string", + "const": "core:menu:allow-insert", + "markdownDescription": "Enables the insert command without any pre-configured scope." + }, + { + "description": "Enables the is_checked command without any pre-configured scope.", + "type": "string", + "const": "core:menu:allow-is-checked", + "markdownDescription": "Enables the is_checked command without any pre-configured scope." + }, + { + "description": "Enables the is_enabled command without any pre-configured scope.", + "type": "string", + "const": "core:menu:allow-is-enabled", + "markdownDescription": "Enables the is_enabled command without any pre-configured scope." + }, + { + "description": "Enables the items command without any pre-configured scope.", + "type": "string", + "const": "core:menu:allow-items", + "markdownDescription": "Enables the items command without any pre-configured scope." + }, + { + "description": "Enables the new command without any pre-configured scope.", + "type": "string", + "const": "core:menu:allow-new", + "markdownDescription": "Enables the new command without any pre-configured scope." + }, + { + "description": "Enables the popup command without any pre-configured scope.", + "type": "string", + "const": "core:menu:allow-popup", + "markdownDescription": "Enables the popup command without any pre-configured scope." + }, + { + "description": "Enables the prepend command without any pre-configured scope.", + "type": "string", + "const": "core:menu:allow-prepend", + "markdownDescription": "Enables the prepend command without any pre-configured scope." + }, + { + "description": "Enables the remove command without any pre-configured scope.", + "type": "string", + "const": "core:menu:allow-remove", + "markdownDescription": "Enables the remove command without any pre-configured scope." + }, + { + "description": "Enables the remove_at command without any pre-configured scope.", + "type": "string", + "const": "core:menu:allow-remove-at", + "markdownDescription": "Enables the remove_at command without any pre-configured scope." + }, + { + "description": "Enables the set_accelerator command without any pre-configured scope.", + "type": "string", + "const": "core:menu:allow-set-accelerator", + "markdownDescription": "Enables the set_accelerator command without any pre-configured scope." + }, + { + "description": "Enables the set_as_app_menu command without any pre-configured scope.", + "type": "string", + "const": "core:menu:allow-set-as-app-menu", + "markdownDescription": "Enables the set_as_app_menu command without any pre-configured scope." + }, + { + "description": "Enables the set_as_help_menu_for_nsapp command without any pre-configured scope.", + "type": "string", + "const": "core:menu:allow-set-as-help-menu-for-nsapp", + "markdownDescription": "Enables the set_as_help_menu_for_nsapp command without any pre-configured scope." + }, + { + "description": "Enables the set_as_window_menu command without any pre-configured scope.", + "type": "string", + "const": "core:menu:allow-set-as-window-menu", + "markdownDescription": "Enables the set_as_window_menu command without any pre-configured scope." + }, + { + "description": "Enables the set_as_windows_menu_for_nsapp command without any pre-configured scope.", + "type": "string", + "const": "core:menu:allow-set-as-windows-menu-for-nsapp", + "markdownDescription": "Enables the set_as_windows_menu_for_nsapp command without any pre-configured scope." + }, + { + "description": "Enables the set_checked command without any pre-configured scope.", + "type": "string", + "const": "core:menu:allow-set-checked", + "markdownDescription": "Enables the set_checked command without any pre-configured scope." + }, + { + "description": "Enables the set_enabled command without any pre-configured scope.", + "type": "string", + "const": "core:menu:allow-set-enabled", + "markdownDescription": "Enables the set_enabled command without any pre-configured scope." + }, + { + "description": "Enables the set_icon command without any pre-configured scope.", + "type": "string", + "const": "core:menu:allow-set-icon", + "markdownDescription": "Enables the set_icon command without any pre-configured scope." + }, + { + "description": "Enables the set_text command without any pre-configured scope.", + "type": "string", + "const": "core:menu:allow-set-text", + "markdownDescription": "Enables the set_text command without any pre-configured scope." + }, + { + "description": "Enables the text command without any pre-configured scope.", + "type": "string", + "const": "core:menu:allow-text", + "markdownDescription": "Enables the text command without any pre-configured scope." + }, + { + "description": "Denies the append command without any pre-configured scope.", + "type": "string", + "const": "core:menu:deny-append", + "markdownDescription": "Denies the append command without any pre-configured scope." + }, + { + "description": "Denies the create_default command without any pre-configured scope.", + "type": "string", + "const": "core:menu:deny-create-default", + "markdownDescription": "Denies the create_default command without any pre-configured scope." + }, + { + "description": "Denies the get command without any pre-configured scope.", + "type": "string", + "const": "core:menu:deny-get", + "markdownDescription": "Denies the get command without any pre-configured scope." + }, + { + "description": "Denies the insert command without any pre-configured scope.", + "type": "string", + "const": "core:menu:deny-insert", + "markdownDescription": "Denies the insert command without any pre-configured scope." + }, + { + "description": "Denies the is_checked command without any pre-configured scope.", + "type": "string", + "const": "core:menu:deny-is-checked", + "markdownDescription": "Denies the is_checked command without any pre-configured scope." + }, + { + "description": "Denies the is_enabled command without any pre-configured scope.", + "type": "string", + "const": "core:menu:deny-is-enabled", + "markdownDescription": "Denies the is_enabled command without any pre-configured scope." + }, + { + "description": "Denies the items command without any pre-configured scope.", + "type": "string", + "const": "core:menu:deny-items", + "markdownDescription": "Denies the items command without any pre-configured scope." + }, + { + "description": "Denies the new command without any pre-configured scope.", + "type": "string", + "const": "core:menu:deny-new", + "markdownDescription": "Denies the new command without any pre-configured scope." + }, + { + "description": "Denies the popup command without any pre-configured scope.", + "type": "string", + "const": "core:menu:deny-popup", + "markdownDescription": "Denies the popup command without any pre-configured scope." + }, + { + "description": "Denies the prepend command without any pre-configured scope.", + "type": "string", + "const": "core:menu:deny-prepend", + "markdownDescription": "Denies the prepend command without any pre-configured scope." + }, + { + "description": "Denies the remove command without any pre-configured scope.", + "type": "string", + "const": "core:menu:deny-remove", + "markdownDescription": "Denies the remove command without any pre-configured scope." + }, + { + "description": "Denies the remove_at command without any pre-configured scope.", + "type": "string", + "const": "core:menu:deny-remove-at", + "markdownDescription": "Denies the remove_at command without any pre-configured scope." + }, + { + "description": "Denies the set_accelerator command without any pre-configured scope.", + "type": "string", + "const": "core:menu:deny-set-accelerator", + "markdownDescription": "Denies the set_accelerator command without any pre-configured scope." + }, + { + "description": "Denies the set_as_app_menu command without any pre-configured scope.", + "type": "string", + "const": "core:menu:deny-set-as-app-menu", + "markdownDescription": "Denies the set_as_app_menu command without any pre-configured scope." + }, + { + "description": "Denies the set_as_help_menu_for_nsapp command without any pre-configured scope.", + "type": "string", + "const": "core:menu:deny-set-as-help-menu-for-nsapp", + "markdownDescription": "Denies the set_as_help_menu_for_nsapp command without any pre-configured scope." + }, + { + "description": "Denies the set_as_window_menu command without any pre-configured scope.", + "type": "string", + "const": "core:menu:deny-set-as-window-menu", + "markdownDescription": "Denies the set_as_window_menu command without any pre-configured scope." + }, + { + "description": "Denies the set_as_windows_menu_for_nsapp command without any pre-configured scope.", + "type": "string", + "const": "core:menu:deny-set-as-windows-menu-for-nsapp", + "markdownDescription": "Denies the set_as_windows_menu_for_nsapp command without any pre-configured scope." + }, + { + "description": "Denies the set_checked command without any pre-configured scope.", + "type": "string", + "const": "core:menu:deny-set-checked", + "markdownDescription": "Denies the set_checked command without any pre-configured scope." + }, + { + "description": "Denies the set_enabled command without any pre-configured scope.", + "type": "string", + "const": "core:menu:deny-set-enabled", + "markdownDescription": "Denies the set_enabled command without any pre-configured scope." + }, + { + "description": "Denies the set_icon command without any pre-configured scope.", + "type": "string", + "const": "core:menu:deny-set-icon", + "markdownDescription": "Denies the set_icon command without any pre-configured scope." + }, + { + "description": "Denies the set_text command without any pre-configured scope.", + "type": "string", + "const": "core:menu:deny-set-text", + "markdownDescription": "Denies the set_text command without any pre-configured scope." + }, + { + "description": "Denies the text command without any pre-configured scope.", + "type": "string", + "const": "core:menu:deny-text", + "markdownDescription": "Denies the text command without any pre-configured scope." + }, + { + "description": "Default permissions for the plugin, which enables all commands.\n#### This default permission set includes:\n\n- `allow-resolve-directory`\n- `allow-resolve`\n- `allow-normalize`\n- `allow-join`\n- `allow-dirname`\n- `allow-extname`\n- `allow-basename`\n- `allow-is-absolute`", + "type": "string", + "const": "core:path:default", + "markdownDescription": "Default permissions for the plugin, which enables all commands.\n#### This default permission set includes:\n\n- `allow-resolve-directory`\n- `allow-resolve`\n- `allow-normalize`\n- `allow-join`\n- `allow-dirname`\n- `allow-extname`\n- `allow-basename`\n- `allow-is-absolute`" + }, + { + "description": "Enables the basename command without any pre-configured scope.", + "type": "string", + "const": "core:path:allow-basename", + "markdownDescription": "Enables the basename command without any pre-configured scope." + }, + { + "description": "Enables the dirname command without any pre-configured scope.", + "type": "string", + "const": "core:path:allow-dirname", + "markdownDescription": "Enables the dirname command without any pre-configured scope." + }, + { + "description": "Enables the extname command without any pre-configured scope.", + "type": "string", + "const": "core:path:allow-extname", + "markdownDescription": "Enables the extname command without any pre-configured scope." + }, + { + "description": "Enables the is_absolute command without any pre-configured scope.", + "type": "string", + "const": "core:path:allow-is-absolute", + "markdownDescription": "Enables the is_absolute command without any pre-configured scope." + }, + { + "description": "Enables the join command without any pre-configured scope.", + "type": "string", + "const": "core:path:allow-join", + "markdownDescription": "Enables the join command without any pre-configured scope." + }, + { + "description": "Enables the normalize command without any pre-configured scope.", + "type": "string", + "const": "core:path:allow-normalize", + "markdownDescription": "Enables the normalize command without any pre-configured scope." + }, + { + "description": "Enables the resolve command without any pre-configured scope.", + "type": "string", + "const": "core:path:allow-resolve", + "markdownDescription": "Enables the resolve command without any pre-configured scope." + }, + { + "description": "Enables the resolve_directory command without any pre-configured scope.", + "type": "string", + "const": "core:path:allow-resolve-directory", + "markdownDescription": "Enables the resolve_directory command without any pre-configured scope." + }, + { + "description": "Denies the basename command without any pre-configured scope.", + "type": "string", + "const": "core:path:deny-basename", + "markdownDescription": "Denies the basename command without any pre-configured scope." + }, + { + "description": "Denies the dirname command without any pre-configured scope.", + "type": "string", + "const": "core:path:deny-dirname", + "markdownDescription": "Denies the dirname command without any pre-configured scope." + }, + { + "description": "Denies the extname command without any pre-configured scope.", + "type": "string", + "const": "core:path:deny-extname", + "markdownDescription": "Denies the extname command without any pre-configured scope." + }, + { + "description": "Denies the is_absolute command without any pre-configured scope.", + "type": "string", + "const": "core:path:deny-is-absolute", + "markdownDescription": "Denies the is_absolute command without any pre-configured scope." + }, + { + "description": "Denies the join command without any pre-configured scope.", + "type": "string", + "const": "core:path:deny-join", + "markdownDescription": "Denies the join command without any pre-configured scope." + }, + { + "description": "Denies the normalize command without any pre-configured scope.", + "type": "string", + "const": "core:path:deny-normalize", + "markdownDescription": "Denies the normalize command without any pre-configured scope." + }, + { + "description": "Denies the resolve command without any pre-configured scope.", + "type": "string", + "const": "core:path:deny-resolve", + "markdownDescription": "Denies the resolve command without any pre-configured scope." + }, + { + "description": "Denies the resolve_directory command without any pre-configured scope.", + "type": "string", + "const": "core:path:deny-resolve-directory", + "markdownDescription": "Denies the resolve_directory command without any pre-configured scope." + }, + { + "description": "Default permissions for the plugin, which enables all commands.\n#### This default permission set includes:\n\n- `allow-close`", + "type": "string", + "const": "core:resources:default", + "markdownDescription": "Default permissions for the plugin, which enables all commands.\n#### This default permission set includes:\n\n- `allow-close`" + }, + { + "description": "Enables the close command without any pre-configured scope.", + "type": "string", + "const": "core:resources:allow-close", + "markdownDescription": "Enables the close command without any pre-configured scope." + }, + { + "description": "Denies the close command without any pre-configured scope.", + "type": "string", + "const": "core:resources:deny-close", + "markdownDescription": "Denies the close command without any pre-configured scope." + }, + { + "description": "Default permissions for the plugin, which enables all commands.\n#### This default permission set includes:\n\n- `allow-new`\n- `allow-get-by-id`\n- `allow-remove-by-id`\n- `allow-set-icon`\n- `allow-set-menu`\n- `allow-set-tooltip`\n- `allow-set-title`\n- `allow-set-visible`\n- `allow-set-temp-dir-path`\n- `allow-set-icon-as-template`\n- `allow-set-show-menu-on-left-click`", + "type": "string", + "const": "core:tray:default", + "markdownDescription": "Default permissions for the plugin, which enables all commands.\n#### This default permission set includes:\n\n- `allow-new`\n- `allow-get-by-id`\n- `allow-remove-by-id`\n- `allow-set-icon`\n- `allow-set-menu`\n- `allow-set-tooltip`\n- `allow-set-title`\n- `allow-set-visible`\n- `allow-set-temp-dir-path`\n- `allow-set-icon-as-template`\n- `allow-set-show-menu-on-left-click`" + }, + { + "description": "Enables the get_by_id command without any pre-configured scope.", + "type": "string", + "const": "core:tray:allow-get-by-id", + "markdownDescription": "Enables the get_by_id command without any pre-configured scope." + }, + { + "description": "Enables the new command without any pre-configured scope.", + "type": "string", + "const": "core:tray:allow-new", + "markdownDescription": "Enables the new command without any pre-configured scope." + }, + { + "description": "Enables the remove_by_id command without any pre-configured scope.", + "type": "string", + "const": "core:tray:allow-remove-by-id", + "markdownDescription": "Enables the remove_by_id command without any pre-configured scope." + }, + { + "description": "Enables the set_icon command without any pre-configured scope.", + "type": "string", + "const": "core:tray:allow-set-icon", + "markdownDescription": "Enables the set_icon command without any pre-configured scope." + }, + { + "description": "Enables the set_icon_as_template command without any pre-configured scope.", + "type": "string", + "const": "core:tray:allow-set-icon-as-template", + "markdownDescription": "Enables the set_icon_as_template command without any pre-configured scope." + }, + { + "description": "Enables the set_menu command without any pre-configured scope.", + "type": "string", + "const": "core:tray:allow-set-menu", + "markdownDescription": "Enables the set_menu command without any pre-configured scope." + }, + { + "description": "Enables the set_show_menu_on_left_click command without any pre-configured scope.", + "type": "string", + "const": "core:tray:allow-set-show-menu-on-left-click", + "markdownDescription": "Enables the set_show_menu_on_left_click command without any pre-configured scope." + }, + { + "description": "Enables the set_temp_dir_path command without any pre-configured scope.", + "type": "string", + "const": "core:tray:allow-set-temp-dir-path", + "markdownDescription": "Enables the set_temp_dir_path command without any pre-configured scope." + }, + { + "description": "Enables the set_title command without any pre-configured scope.", + "type": "string", + "const": "core:tray:allow-set-title", + "markdownDescription": "Enables the set_title command without any pre-configured scope." + }, + { + "description": "Enables the set_tooltip command without any pre-configured scope.", + "type": "string", + "const": "core:tray:allow-set-tooltip", + "markdownDescription": "Enables the set_tooltip command without any pre-configured scope." + }, + { + "description": "Enables the set_visible command without any pre-configured scope.", + "type": "string", + "const": "core:tray:allow-set-visible", + "markdownDescription": "Enables the set_visible command without any pre-configured scope." + }, + { + "description": "Denies the get_by_id command without any pre-configured scope.", + "type": "string", + "const": "core:tray:deny-get-by-id", + "markdownDescription": "Denies the get_by_id command without any pre-configured scope." + }, + { + "description": "Denies the new command without any pre-configured scope.", + "type": "string", + "const": "core:tray:deny-new", + "markdownDescription": "Denies the new command without any pre-configured scope." + }, + { + "description": "Denies the remove_by_id command without any pre-configured scope.", + "type": "string", + "const": "core:tray:deny-remove-by-id", + "markdownDescription": "Denies the remove_by_id command without any pre-configured scope." + }, + { + "description": "Denies the set_icon command without any pre-configured scope.", + "type": "string", + "const": "core:tray:deny-set-icon", + "markdownDescription": "Denies the set_icon command without any pre-configured scope." + }, + { + "description": "Denies the set_icon_as_template command without any pre-configured scope.", + "type": "string", + "const": "core:tray:deny-set-icon-as-template", + "markdownDescription": "Denies the set_icon_as_template command without any pre-configured scope." + }, + { + "description": "Denies the set_menu command without any pre-configured scope.", + "type": "string", + "const": "core:tray:deny-set-menu", + "markdownDescription": "Denies the set_menu command without any pre-configured scope." + }, + { + "description": "Denies the set_show_menu_on_left_click command without any pre-configured scope.", + "type": "string", + "const": "core:tray:deny-set-show-menu-on-left-click", + "markdownDescription": "Denies the set_show_menu_on_left_click command without any pre-configured scope." + }, + { + "description": "Denies the set_temp_dir_path command without any pre-configured scope.", + "type": "string", + "const": "core:tray:deny-set-temp-dir-path", + "markdownDescription": "Denies the set_temp_dir_path command without any pre-configured scope." + }, + { + "description": "Denies the set_title command without any pre-configured scope.", + "type": "string", + "const": "core:tray:deny-set-title", + "markdownDescription": "Denies the set_title command without any pre-configured scope." + }, + { + "description": "Denies the set_tooltip command without any pre-configured scope.", + "type": "string", + "const": "core:tray:deny-set-tooltip", + "markdownDescription": "Denies the set_tooltip command without any pre-configured scope." + }, + { + "description": "Denies the set_visible command without any pre-configured scope.", + "type": "string", + "const": "core:tray:deny-set-visible", + "markdownDescription": "Denies the set_visible command without any pre-configured scope." + }, + { + "description": "Default permissions for the plugin.\n#### This default permission set includes:\n\n- `allow-get-all-webviews`\n- `allow-webview-position`\n- `allow-webview-size`\n- `allow-internal-toggle-devtools`", + "type": "string", + "const": "core:webview:default", + "markdownDescription": "Default permissions for the plugin.\n#### This default permission set includes:\n\n- `allow-get-all-webviews`\n- `allow-webview-position`\n- `allow-webview-size`\n- `allow-internal-toggle-devtools`" + }, + { + "description": "Enables the clear_all_browsing_data command without any pre-configured scope.", + "type": "string", + "const": "core:webview:allow-clear-all-browsing-data", + "markdownDescription": "Enables the clear_all_browsing_data command without any pre-configured scope." + }, + { + "description": "Enables the create_webview command without any pre-configured scope.", + "type": "string", + "const": "core:webview:allow-create-webview", + "markdownDescription": "Enables the create_webview command without any pre-configured scope." + }, + { + "description": "Enables the create_webview_window command without any pre-configured scope.", + "type": "string", + "const": "core:webview:allow-create-webview-window", + "markdownDescription": "Enables the create_webview_window command without any pre-configured scope." + }, + { + "description": "Enables the get_all_webviews command without any pre-configured scope.", + "type": "string", + "const": "core:webview:allow-get-all-webviews", + "markdownDescription": "Enables the get_all_webviews command without any pre-configured scope." + }, + { + "description": "Enables the internal_toggle_devtools command without any pre-configured scope.", + "type": "string", + "const": "core:webview:allow-internal-toggle-devtools", + "markdownDescription": "Enables the internal_toggle_devtools command without any pre-configured scope." + }, + { + "description": "Enables the print command without any pre-configured scope.", + "type": "string", + "const": "core:webview:allow-print", + "markdownDescription": "Enables the print command without any pre-configured scope." + }, + { + "description": "Enables the reparent command without any pre-configured scope.", + "type": "string", + "const": "core:webview:allow-reparent", + "markdownDescription": "Enables the reparent command without any pre-configured scope." + }, + { + "description": "Enables the set_webview_auto_resize command without any pre-configured scope.", + "type": "string", + "const": "core:webview:allow-set-webview-auto-resize", + "markdownDescription": "Enables the set_webview_auto_resize command without any pre-configured scope." + }, + { + "description": "Enables the set_webview_background_color command without any pre-configured scope.", + "type": "string", + "const": "core:webview:allow-set-webview-background-color", + "markdownDescription": "Enables the set_webview_background_color command without any pre-configured scope." + }, + { + "description": "Enables the set_webview_focus command without any pre-configured scope.", + "type": "string", + "const": "core:webview:allow-set-webview-focus", + "markdownDescription": "Enables the set_webview_focus command without any pre-configured scope." + }, + { + "description": "Enables the set_webview_position command without any pre-configured scope.", + "type": "string", + "const": "core:webview:allow-set-webview-position", + "markdownDescription": "Enables the set_webview_position command without any pre-configured scope." + }, + { + "description": "Enables the set_webview_size command without any pre-configured scope.", + "type": "string", + "const": "core:webview:allow-set-webview-size", + "markdownDescription": "Enables the set_webview_size command without any pre-configured scope." + }, + { + "description": "Enables the set_webview_zoom command without any pre-configured scope.", + "type": "string", + "const": "core:webview:allow-set-webview-zoom", + "markdownDescription": "Enables the set_webview_zoom command without any pre-configured scope." + }, + { + "description": "Enables the webview_close command without any pre-configured scope.", + "type": "string", + "const": "core:webview:allow-webview-close", + "markdownDescription": "Enables the webview_close command without any pre-configured scope." + }, + { + "description": "Enables the webview_hide command without any pre-configured scope.", + "type": "string", + "const": "core:webview:allow-webview-hide", + "markdownDescription": "Enables the webview_hide command without any pre-configured scope." + }, + { + "description": "Enables the webview_position command without any pre-configured scope.", + "type": "string", + "const": "core:webview:allow-webview-position", + "markdownDescription": "Enables the webview_position command without any pre-configured scope." + }, + { + "description": "Enables the webview_show command without any pre-configured scope.", + "type": "string", + "const": "core:webview:allow-webview-show", + "markdownDescription": "Enables the webview_show command without any pre-configured scope." + }, + { + "description": "Enables the webview_size command without any pre-configured scope.", + "type": "string", + "const": "core:webview:allow-webview-size", + "markdownDescription": "Enables the webview_size command without any pre-configured scope." + }, + { + "description": "Denies the clear_all_browsing_data command without any pre-configured scope.", + "type": "string", + "const": "core:webview:deny-clear-all-browsing-data", + "markdownDescription": "Denies the clear_all_browsing_data command without any pre-configured scope." + }, + { + "description": "Denies the create_webview command without any pre-configured scope.", + "type": "string", + "const": "core:webview:deny-create-webview", + "markdownDescription": "Denies the create_webview command without any pre-configured scope." + }, + { + "description": "Denies the create_webview_window command without any pre-configured scope.", + "type": "string", + "const": "core:webview:deny-create-webview-window", + "markdownDescription": "Denies the create_webview_window command without any pre-configured scope." + }, + { + "description": "Denies the get_all_webviews command without any pre-configured scope.", + "type": "string", + "const": "core:webview:deny-get-all-webviews", + "markdownDescription": "Denies the get_all_webviews command without any pre-configured scope." + }, + { + "description": "Denies the internal_toggle_devtools command without any pre-configured scope.", + "type": "string", + "const": "core:webview:deny-internal-toggle-devtools", + "markdownDescription": "Denies the internal_toggle_devtools command without any pre-configured scope." + }, + { + "description": "Denies the print command without any pre-configured scope.", + "type": "string", + "const": "core:webview:deny-print", + "markdownDescription": "Denies the print command without any pre-configured scope." + }, + { + "description": "Denies the reparent command without any pre-configured scope.", + "type": "string", + "const": "core:webview:deny-reparent", + "markdownDescription": "Denies the reparent command without any pre-configured scope." + }, + { + "description": "Denies the set_webview_auto_resize command without any pre-configured scope.", + "type": "string", + "const": "core:webview:deny-set-webview-auto-resize", + "markdownDescription": "Denies the set_webview_auto_resize command without any pre-configured scope." + }, + { + "description": "Denies the set_webview_background_color command without any pre-configured scope.", + "type": "string", + "const": "core:webview:deny-set-webview-background-color", + "markdownDescription": "Denies the set_webview_background_color command without any pre-configured scope." + }, + { + "description": "Denies the set_webview_focus command without any pre-configured scope.", + "type": "string", + "const": "core:webview:deny-set-webview-focus", + "markdownDescription": "Denies the set_webview_focus command without any pre-configured scope." + }, + { + "description": "Denies the set_webview_position command without any pre-configured scope.", + "type": "string", + "const": "core:webview:deny-set-webview-position", + "markdownDescription": "Denies the set_webview_position command without any pre-configured scope." + }, + { + "description": "Denies the set_webview_size command without any pre-configured scope.", + "type": "string", + "const": "core:webview:deny-set-webview-size", + "markdownDescription": "Denies the set_webview_size command without any pre-configured scope." + }, + { + "description": "Denies the set_webview_zoom command without any pre-configured scope.", + "type": "string", + "const": "core:webview:deny-set-webview-zoom", + "markdownDescription": "Denies the set_webview_zoom command without any pre-configured scope." + }, + { + "description": "Denies the webview_close command without any pre-configured scope.", + "type": "string", + "const": "core:webview:deny-webview-close", + "markdownDescription": "Denies the webview_close command without any pre-configured scope." + }, + { + "description": "Denies the webview_hide command without any pre-configured scope.", + "type": "string", + "const": "core:webview:deny-webview-hide", + "markdownDescription": "Denies the webview_hide command without any pre-configured scope." + }, + { + "description": "Denies the webview_position command without any pre-configured scope.", + "type": "string", + "const": "core:webview:deny-webview-position", + "markdownDescription": "Denies the webview_position command without any pre-configured scope." + }, + { + "description": "Denies the webview_show command without any pre-configured scope.", + "type": "string", + "const": "core:webview:deny-webview-show", + "markdownDescription": "Denies the webview_show command without any pre-configured scope." + }, + { + "description": "Denies the webview_size command without any pre-configured scope.", + "type": "string", + "const": "core:webview:deny-webview-size", + "markdownDescription": "Denies the webview_size command without any pre-configured scope." + }, + { + "description": "Default permissions for the plugin.\n#### This default permission set includes:\n\n- `allow-get-all-windows`\n- `allow-scale-factor`\n- `allow-inner-position`\n- `allow-outer-position`\n- `allow-inner-size`\n- `allow-outer-size`\n- `allow-is-fullscreen`\n- `allow-is-minimized`\n- `allow-is-maximized`\n- `allow-is-focused`\n- `allow-is-decorated`\n- `allow-is-resizable`\n- `allow-is-maximizable`\n- `allow-is-minimizable`\n- `allow-is-closable`\n- `allow-is-visible`\n- `allow-is-enabled`\n- `allow-title`\n- `allow-current-monitor`\n- `allow-primary-monitor`\n- `allow-monitor-from-point`\n- `allow-available-monitors`\n- `allow-cursor-position`\n- `allow-theme`\n- `allow-is-always-on-top`\n- `allow-internal-toggle-maximize`", + "type": "string", + "const": "core:window:default", + "markdownDescription": "Default permissions for the plugin.\n#### This default permission set includes:\n\n- `allow-get-all-windows`\n- `allow-scale-factor`\n- `allow-inner-position`\n- `allow-outer-position`\n- `allow-inner-size`\n- `allow-outer-size`\n- `allow-is-fullscreen`\n- `allow-is-minimized`\n- `allow-is-maximized`\n- `allow-is-focused`\n- `allow-is-decorated`\n- `allow-is-resizable`\n- `allow-is-maximizable`\n- `allow-is-minimizable`\n- `allow-is-closable`\n- `allow-is-visible`\n- `allow-is-enabled`\n- `allow-title`\n- `allow-current-monitor`\n- `allow-primary-monitor`\n- `allow-monitor-from-point`\n- `allow-available-monitors`\n- `allow-cursor-position`\n- `allow-theme`\n- `allow-is-always-on-top`\n- `allow-internal-toggle-maximize`" + }, + { + "description": "Enables the available_monitors command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-available-monitors", + "markdownDescription": "Enables the available_monitors command without any pre-configured scope." + }, + { + "description": "Enables the center command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-center", + "markdownDescription": "Enables the center command without any pre-configured scope." + }, + { + "description": "Enables the close command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-close", + "markdownDescription": "Enables the close command without any pre-configured scope." + }, + { + "description": "Enables the create command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-create", + "markdownDescription": "Enables the create command without any pre-configured scope." + }, + { + "description": "Enables the current_monitor command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-current-monitor", + "markdownDescription": "Enables the current_monitor command without any pre-configured scope." + }, + { + "description": "Enables the cursor_position command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-cursor-position", + "markdownDescription": "Enables the cursor_position command without any pre-configured scope." + }, + { + "description": "Enables the destroy command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-destroy", + "markdownDescription": "Enables the destroy command without any pre-configured scope." + }, + { + "description": "Enables the get_all_windows command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-get-all-windows", + "markdownDescription": "Enables the get_all_windows command without any pre-configured scope." + }, + { + "description": "Enables the hide command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-hide", + "markdownDescription": "Enables the hide command without any pre-configured scope." + }, + { + "description": "Enables the inner_position command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-inner-position", + "markdownDescription": "Enables the inner_position command without any pre-configured scope." + }, + { + "description": "Enables the inner_size command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-inner-size", + "markdownDescription": "Enables the inner_size command without any pre-configured scope." + }, + { + "description": "Enables the internal_toggle_maximize command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-internal-toggle-maximize", + "markdownDescription": "Enables the internal_toggle_maximize command without any pre-configured scope." + }, + { + "description": "Enables the is_always_on_top command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-is-always-on-top", + "markdownDescription": "Enables the is_always_on_top command without any pre-configured scope." + }, + { + "description": "Enables the is_closable command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-is-closable", + "markdownDescription": "Enables the is_closable command without any pre-configured scope." + }, + { + "description": "Enables the is_decorated command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-is-decorated", + "markdownDescription": "Enables the is_decorated command without any pre-configured scope." + }, + { + "description": "Enables the is_enabled command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-is-enabled", + "markdownDescription": "Enables the is_enabled command without any pre-configured scope." + }, + { + "description": "Enables the is_focused command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-is-focused", + "markdownDescription": "Enables the is_focused command without any pre-configured scope." + }, + { + "description": "Enables the is_fullscreen command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-is-fullscreen", + "markdownDescription": "Enables the is_fullscreen command without any pre-configured scope." + }, + { + "description": "Enables the is_maximizable command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-is-maximizable", + "markdownDescription": "Enables the is_maximizable command without any pre-configured scope." + }, + { + "description": "Enables the is_maximized command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-is-maximized", + "markdownDescription": "Enables the is_maximized command without any pre-configured scope." + }, + { + "description": "Enables the is_minimizable command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-is-minimizable", + "markdownDescription": "Enables the is_minimizable command without any pre-configured scope." + }, + { + "description": "Enables the is_minimized command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-is-minimized", + "markdownDescription": "Enables the is_minimized command without any pre-configured scope." + }, + { + "description": "Enables the is_resizable command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-is-resizable", + "markdownDescription": "Enables the is_resizable command without any pre-configured scope." + }, + { + "description": "Enables the is_visible command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-is-visible", + "markdownDescription": "Enables the is_visible command without any pre-configured scope." + }, + { + "description": "Enables the maximize command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-maximize", + "markdownDescription": "Enables the maximize command without any pre-configured scope." + }, + { + "description": "Enables the minimize command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-minimize", + "markdownDescription": "Enables the minimize command without any pre-configured scope." + }, + { + "description": "Enables the monitor_from_point command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-monitor-from-point", + "markdownDescription": "Enables the monitor_from_point command without any pre-configured scope." + }, + { + "description": "Enables the outer_position command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-outer-position", + "markdownDescription": "Enables the outer_position command without any pre-configured scope." + }, + { + "description": "Enables the outer_size command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-outer-size", + "markdownDescription": "Enables the outer_size command without any pre-configured scope." + }, + { + "description": "Enables the primary_monitor command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-primary-monitor", + "markdownDescription": "Enables the primary_monitor command without any pre-configured scope." + }, + { + "description": "Enables the request_user_attention command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-request-user-attention", + "markdownDescription": "Enables the request_user_attention command without any pre-configured scope." + }, + { + "description": "Enables the scale_factor command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-scale-factor", + "markdownDescription": "Enables the scale_factor command without any pre-configured scope." + }, + { + "description": "Enables the set_always_on_bottom command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-set-always-on-bottom", + "markdownDescription": "Enables the set_always_on_bottom command without any pre-configured scope." + }, + { + "description": "Enables the set_always_on_top command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-set-always-on-top", + "markdownDescription": "Enables the set_always_on_top command without any pre-configured scope." + }, + { + "description": "Enables the set_background_color command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-set-background-color", + "markdownDescription": "Enables the set_background_color command without any pre-configured scope." + }, + { + "description": "Enables the set_badge_count command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-set-badge-count", + "markdownDescription": "Enables the set_badge_count command without any pre-configured scope." + }, + { + "description": "Enables the set_badge_label command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-set-badge-label", + "markdownDescription": "Enables the set_badge_label command without any pre-configured scope." + }, + { + "description": "Enables the set_closable command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-set-closable", + "markdownDescription": "Enables the set_closable command without any pre-configured scope." + }, + { + "description": "Enables the set_content_protected command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-set-content-protected", + "markdownDescription": "Enables the set_content_protected command without any pre-configured scope." + }, + { + "description": "Enables the set_cursor_grab command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-set-cursor-grab", + "markdownDescription": "Enables the set_cursor_grab command without any pre-configured scope." + }, + { + "description": "Enables the set_cursor_icon command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-set-cursor-icon", + "markdownDescription": "Enables the set_cursor_icon command without any pre-configured scope." + }, + { + "description": "Enables the set_cursor_position command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-set-cursor-position", + "markdownDescription": "Enables the set_cursor_position command without any pre-configured scope." + }, + { + "description": "Enables the set_cursor_visible command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-set-cursor-visible", + "markdownDescription": "Enables the set_cursor_visible command without any pre-configured scope." + }, + { + "description": "Enables the set_decorations command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-set-decorations", + "markdownDescription": "Enables the set_decorations command without any pre-configured scope." + }, + { + "description": "Enables the set_effects command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-set-effects", + "markdownDescription": "Enables the set_effects command without any pre-configured scope." + }, + { + "description": "Enables the set_enabled command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-set-enabled", + "markdownDescription": "Enables the set_enabled command without any pre-configured scope." + }, + { + "description": "Enables the set_focus command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-set-focus", + "markdownDescription": "Enables the set_focus command without any pre-configured scope." + }, + { + "description": "Enables the set_focusable command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-set-focusable", + "markdownDescription": "Enables the set_focusable command without any pre-configured scope." + }, + { + "description": "Enables the set_fullscreen command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-set-fullscreen", + "markdownDescription": "Enables the set_fullscreen command without any pre-configured scope." + }, + { + "description": "Enables the set_icon command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-set-icon", + "markdownDescription": "Enables the set_icon command without any pre-configured scope." + }, + { + "description": "Enables the set_ignore_cursor_events command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-set-ignore-cursor-events", + "markdownDescription": "Enables the set_ignore_cursor_events command without any pre-configured scope." + }, + { + "description": "Enables the set_max_size command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-set-max-size", + "markdownDescription": "Enables the set_max_size command without any pre-configured scope." + }, + { + "description": "Enables the set_maximizable command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-set-maximizable", + "markdownDescription": "Enables the set_maximizable command without any pre-configured scope." + }, + { + "description": "Enables the set_min_size command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-set-min-size", + "markdownDescription": "Enables the set_min_size command without any pre-configured scope." + }, + { + "description": "Enables the set_minimizable command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-set-minimizable", + "markdownDescription": "Enables the set_minimizable command without any pre-configured scope." + }, + { + "description": "Enables the set_overlay_icon command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-set-overlay-icon", + "markdownDescription": "Enables the set_overlay_icon command without any pre-configured scope." + }, + { + "description": "Enables the set_position command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-set-position", + "markdownDescription": "Enables the set_position command without any pre-configured scope." + }, + { + "description": "Enables the set_progress_bar command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-set-progress-bar", + "markdownDescription": "Enables the set_progress_bar command without any pre-configured scope." + }, + { + "description": "Enables the set_resizable command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-set-resizable", + "markdownDescription": "Enables the set_resizable command without any pre-configured scope." + }, + { + "description": "Enables the set_shadow command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-set-shadow", + "markdownDescription": "Enables the set_shadow command without any pre-configured scope." + }, + { + "description": "Enables the set_simple_fullscreen command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-set-simple-fullscreen", + "markdownDescription": "Enables the set_simple_fullscreen command without any pre-configured scope." + }, + { + "description": "Enables the set_size command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-set-size", + "markdownDescription": "Enables the set_size command without any pre-configured scope." + }, + { + "description": "Enables the set_size_constraints command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-set-size-constraints", + "markdownDescription": "Enables the set_size_constraints command without any pre-configured scope." + }, + { + "description": "Enables the set_skip_taskbar command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-set-skip-taskbar", + "markdownDescription": "Enables the set_skip_taskbar command without any pre-configured scope." + }, + { + "description": "Enables the set_theme command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-set-theme", + "markdownDescription": "Enables the set_theme command without any pre-configured scope." + }, + { + "description": "Enables the set_title command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-set-title", + "markdownDescription": "Enables the set_title command without any pre-configured scope." + }, + { + "description": "Enables the set_title_bar_style command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-set-title-bar-style", + "markdownDescription": "Enables the set_title_bar_style command without any pre-configured scope." + }, + { + "description": "Enables the set_visible_on_all_workspaces command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-set-visible-on-all-workspaces", + "markdownDescription": "Enables the set_visible_on_all_workspaces command without any pre-configured scope." + }, + { + "description": "Enables the show command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-show", + "markdownDescription": "Enables the show command without any pre-configured scope." + }, + { + "description": "Enables the start_dragging command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-start-dragging", + "markdownDescription": "Enables the start_dragging command without any pre-configured scope." + }, + { + "description": "Enables the start_resize_dragging command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-start-resize-dragging", + "markdownDescription": "Enables the start_resize_dragging command without any pre-configured scope." + }, + { + "description": "Enables the theme command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-theme", + "markdownDescription": "Enables the theme command without any pre-configured scope." + }, + { + "description": "Enables the title command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-title", + "markdownDescription": "Enables the title command without any pre-configured scope." + }, + { + "description": "Enables the toggle_maximize command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-toggle-maximize", + "markdownDescription": "Enables the toggle_maximize command without any pre-configured scope." + }, + { + "description": "Enables the unmaximize command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-unmaximize", + "markdownDescription": "Enables the unmaximize command without any pre-configured scope." + }, + { + "description": "Enables the unminimize command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-unminimize", + "markdownDescription": "Enables the unminimize command without any pre-configured scope." + }, + { + "description": "Denies the available_monitors command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-available-monitors", + "markdownDescription": "Denies the available_monitors command without any pre-configured scope." + }, + { + "description": "Denies the center command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-center", + "markdownDescription": "Denies the center command without any pre-configured scope." + }, + { + "description": "Denies the close command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-close", + "markdownDescription": "Denies the close command without any pre-configured scope." + }, + { + "description": "Denies the create command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-create", + "markdownDescription": "Denies the create command without any pre-configured scope." + }, + { + "description": "Denies the current_monitor command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-current-monitor", + "markdownDescription": "Denies the current_monitor command without any pre-configured scope." + }, + { + "description": "Denies the cursor_position command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-cursor-position", + "markdownDescription": "Denies the cursor_position command without any pre-configured scope." + }, + { + "description": "Denies the destroy command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-destroy", + "markdownDescription": "Denies the destroy command without any pre-configured scope." + }, + { + "description": "Denies the get_all_windows command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-get-all-windows", + "markdownDescription": "Denies the get_all_windows command without any pre-configured scope." + }, + { + "description": "Denies the hide command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-hide", + "markdownDescription": "Denies the hide command without any pre-configured scope." + }, + { + "description": "Denies the inner_position command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-inner-position", + "markdownDescription": "Denies the inner_position command without any pre-configured scope." + }, + { + "description": "Denies the inner_size command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-inner-size", + "markdownDescription": "Denies the inner_size command without any pre-configured scope." + }, + { + "description": "Denies the internal_toggle_maximize command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-internal-toggle-maximize", + "markdownDescription": "Denies the internal_toggle_maximize command without any pre-configured scope." + }, + { + "description": "Denies the is_always_on_top command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-is-always-on-top", + "markdownDescription": "Denies the is_always_on_top command without any pre-configured scope." + }, + { + "description": "Denies the is_closable command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-is-closable", + "markdownDescription": "Denies the is_closable command without any pre-configured scope." + }, + { + "description": "Denies the is_decorated command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-is-decorated", + "markdownDescription": "Denies the is_decorated command without any pre-configured scope." + }, + { + "description": "Denies the is_enabled command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-is-enabled", + "markdownDescription": "Denies the is_enabled command without any pre-configured scope." + }, + { + "description": "Denies the is_focused command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-is-focused", + "markdownDescription": "Denies the is_focused command without any pre-configured scope." + }, + { + "description": "Denies the is_fullscreen command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-is-fullscreen", + "markdownDescription": "Denies the is_fullscreen command without any pre-configured scope." + }, + { + "description": "Denies the is_maximizable command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-is-maximizable", + "markdownDescription": "Denies the is_maximizable command without any pre-configured scope." + }, + { + "description": "Denies the is_maximized command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-is-maximized", + "markdownDescription": "Denies the is_maximized command without any pre-configured scope." + }, + { + "description": "Denies the is_minimizable command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-is-minimizable", + "markdownDescription": "Denies the is_minimizable command without any pre-configured scope." + }, + { + "description": "Denies the is_minimized command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-is-minimized", + "markdownDescription": "Denies the is_minimized command without any pre-configured scope." + }, + { + "description": "Denies the is_resizable command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-is-resizable", + "markdownDescription": "Denies the is_resizable command without any pre-configured scope." + }, + { + "description": "Denies the is_visible command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-is-visible", + "markdownDescription": "Denies the is_visible command without any pre-configured scope." + }, + { + "description": "Denies the maximize command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-maximize", + "markdownDescription": "Denies the maximize command without any pre-configured scope." + }, + { + "description": "Denies the minimize command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-minimize", + "markdownDescription": "Denies the minimize command without any pre-configured scope." + }, + { + "description": "Denies the monitor_from_point command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-monitor-from-point", + "markdownDescription": "Denies the monitor_from_point command without any pre-configured scope." + }, + { + "description": "Denies the outer_position command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-outer-position", + "markdownDescription": "Denies the outer_position command without any pre-configured scope." + }, + { + "description": "Denies the outer_size command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-outer-size", + "markdownDescription": "Denies the outer_size command without any pre-configured scope." + }, + { + "description": "Denies the primary_monitor command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-primary-monitor", + "markdownDescription": "Denies the primary_monitor command without any pre-configured scope." + }, + { + "description": "Denies the request_user_attention command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-request-user-attention", + "markdownDescription": "Denies the request_user_attention command without any pre-configured scope." + }, + { + "description": "Denies the scale_factor command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-scale-factor", + "markdownDescription": "Denies the scale_factor command without any pre-configured scope." + }, + { + "description": "Denies the set_always_on_bottom command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-set-always-on-bottom", + "markdownDescription": "Denies the set_always_on_bottom command without any pre-configured scope." + }, + { + "description": "Denies the set_always_on_top command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-set-always-on-top", + "markdownDescription": "Denies the set_always_on_top command without any pre-configured scope." + }, + { + "description": "Denies the set_background_color command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-set-background-color", + "markdownDescription": "Denies the set_background_color command without any pre-configured scope." + }, + { + "description": "Denies the set_badge_count command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-set-badge-count", + "markdownDescription": "Denies the set_badge_count command without any pre-configured scope." + }, + { + "description": "Denies the set_badge_label command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-set-badge-label", + "markdownDescription": "Denies the set_badge_label command without any pre-configured scope." + }, + { + "description": "Denies the set_closable command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-set-closable", + "markdownDescription": "Denies the set_closable command without any pre-configured scope." + }, + { + "description": "Denies the set_content_protected command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-set-content-protected", + "markdownDescription": "Denies the set_content_protected command without any pre-configured scope." + }, + { + "description": "Denies the set_cursor_grab command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-set-cursor-grab", + "markdownDescription": "Denies the set_cursor_grab command without any pre-configured scope." + }, + { + "description": "Denies the set_cursor_icon command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-set-cursor-icon", + "markdownDescription": "Denies the set_cursor_icon command without any pre-configured scope." + }, + { + "description": "Denies the set_cursor_position command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-set-cursor-position", + "markdownDescription": "Denies the set_cursor_position command without any pre-configured scope." + }, + { + "description": "Denies the set_cursor_visible command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-set-cursor-visible", + "markdownDescription": "Denies the set_cursor_visible command without any pre-configured scope." + }, + { + "description": "Denies the set_decorations command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-set-decorations", + "markdownDescription": "Denies the set_decorations command without any pre-configured scope." + }, + { + "description": "Denies the set_effects command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-set-effects", + "markdownDescription": "Denies the set_effects command without any pre-configured scope." + }, + { + "description": "Denies the set_enabled command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-set-enabled", + "markdownDescription": "Denies the set_enabled command without any pre-configured scope." + }, + { + "description": "Denies the set_focus command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-set-focus", + "markdownDescription": "Denies the set_focus command without any pre-configured scope." + }, + { + "description": "Denies the set_focusable command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-set-focusable", + "markdownDescription": "Denies the set_focusable command without any pre-configured scope." + }, + { + "description": "Denies the set_fullscreen command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-set-fullscreen", + "markdownDescription": "Denies the set_fullscreen command without any pre-configured scope." + }, + { + "description": "Denies the set_icon command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-set-icon", + "markdownDescription": "Denies the set_icon command without any pre-configured scope." + }, + { + "description": "Denies the set_ignore_cursor_events command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-set-ignore-cursor-events", + "markdownDescription": "Denies the set_ignore_cursor_events command without any pre-configured scope." + }, + { + "description": "Denies the set_max_size command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-set-max-size", + "markdownDescription": "Denies the set_max_size command without any pre-configured scope." + }, + { + "description": "Denies the set_maximizable command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-set-maximizable", + "markdownDescription": "Denies the set_maximizable command without any pre-configured scope." + }, + { + "description": "Denies the set_min_size command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-set-min-size", + "markdownDescription": "Denies the set_min_size command without any pre-configured scope." + }, + { + "description": "Denies the set_minimizable command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-set-minimizable", + "markdownDescription": "Denies the set_minimizable command without any pre-configured scope." + }, + { + "description": "Denies the set_overlay_icon command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-set-overlay-icon", + "markdownDescription": "Denies the set_overlay_icon command without any pre-configured scope." + }, + { + "description": "Denies the set_position command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-set-position", + "markdownDescription": "Denies the set_position command without any pre-configured scope." + }, + { + "description": "Denies the set_progress_bar command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-set-progress-bar", + "markdownDescription": "Denies the set_progress_bar command without any pre-configured scope." + }, + { + "description": "Denies the set_resizable command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-set-resizable", + "markdownDescription": "Denies the set_resizable command without any pre-configured scope." + }, + { + "description": "Denies the set_shadow command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-set-shadow", + "markdownDescription": "Denies the set_shadow command without any pre-configured scope." + }, + { + "description": "Denies the set_simple_fullscreen command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-set-simple-fullscreen", + "markdownDescription": "Denies the set_simple_fullscreen command without any pre-configured scope." + }, + { + "description": "Denies the set_size command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-set-size", + "markdownDescription": "Denies the set_size command without any pre-configured scope." + }, + { + "description": "Denies the set_size_constraints command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-set-size-constraints", + "markdownDescription": "Denies the set_size_constraints command without any pre-configured scope." + }, + { + "description": "Denies the set_skip_taskbar command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-set-skip-taskbar", + "markdownDescription": "Denies the set_skip_taskbar command without any pre-configured scope." + }, + { + "description": "Denies the set_theme command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-set-theme", + "markdownDescription": "Denies the set_theme command without any pre-configured scope." + }, + { + "description": "Denies the set_title command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-set-title", + "markdownDescription": "Denies the set_title command without any pre-configured scope." + }, + { + "description": "Denies the set_title_bar_style command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-set-title-bar-style", + "markdownDescription": "Denies the set_title_bar_style command without any pre-configured scope." + }, + { + "description": "Denies the set_visible_on_all_workspaces command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-set-visible-on-all-workspaces", + "markdownDescription": "Denies the set_visible_on_all_workspaces command without any pre-configured scope." + }, + { + "description": "Denies the show command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-show", + "markdownDescription": "Denies the show command without any pre-configured scope." + }, + { + "description": "Denies the start_dragging command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-start-dragging", + "markdownDescription": "Denies the start_dragging command without any pre-configured scope." + }, + { + "description": "Denies the start_resize_dragging command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-start-resize-dragging", + "markdownDescription": "Denies the start_resize_dragging command without any pre-configured scope." + }, + { + "description": "Denies the theme command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-theme", + "markdownDescription": "Denies the theme command without any pre-configured scope." + }, + { + "description": "Denies the title command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-title", + "markdownDescription": "Denies the title command without any pre-configured scope." + }, + { + "description": "Denies the toggle_maximize command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-toggle-maximize", + "markdownDescription": "Denies the toggle_maximize command without any pre-configured scope." + }, + { + "description": "Denies the unmaximize command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-unmaximize", + "markdownDescription": "Denies the unmaximize command without any pre-configured scope." + }, + { + "description": "Denies the unminimize command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-unminimize", + "markdownDescription": "Denies the unminimize command without any pre-configured scope." + }, + { + "description": "This permission set configures the types of dialogs\navailable from the dialog plugin.\n\n#### Granted Permissions\n\nAll dialog types are enabled.\n\n\n\n#### This default permission set includes:\n\n- `allow-ask`\n- `allow-confirm`\n- `allow-message`\n- `allow-save`\n- `allow-open`", + "type": "string", + "const": "dialog:default", + "markdownDescription": "This permission set configures the types of dialogs\navailable from the dialog plugin.\n\n#### Granted Permissions\n\nAll dialog types are enabled.\n\n\n\n#### This default permission set includes:\n\n- `allow-ask`\n- `allow-confirm`\n- `allow-message`\n- `allow-save`\n- `allow-open`" + }, + { + "description": "Enables the ask command without any pre-configured scope.", + "type": "string", + "const": "dialog:allow-ask", + "markdownDescription": "Enables the ask command without any pre-configured scope." + }, + { + "description": "Enables the confirm command without any pre-configured scope.", + "type": "string", + "const": "dialog:allow-confirm", + "markdownDescription": "Enables the confirm command without any pre-configured scope." + }, + { + "description": "Enables the message command without any pre-configured scope.", + "type": "string", + "const": "dialog:allow-message", + "markdownDescription": "Enables the message command without any pre-configured scope." + }, + { + "description": "Enables the open command without any pre-configured scope.", + "type": "string", + "const": "dialog:allow-open", + "markdownDescription": "Enables the open command without any pre-configured scope." + }, + { + "description": "Enables the save command without any pre-configured scope.", + "type": "string", + "const": "dialog:allow-save", + "markdownDescription": "Enables the save command without any pre-configured scope." + }, + { + "description": "Denies the ask command without any pre-configured scope.", + "type": "string", + "const": "dialog:deny-ask", + "markdownDescription": "Denies the ask command without any pre-configured scope." + }, + { + "description": "Denies the confirm command without any pre-configured scope.", + "type": "string", + "const": "dialog:deny-confirm", + "markdownDescription": "Denies the confirm command without any pre-configured scope." + }, + { + "description": "Denies the message command without any pre-configured scope.", + "type": "string", + "const": "dialog:deny-message", + "markdownDescription": "Denies the message command without any pre-configured scope." + }, + { + "description": "Denies the open command without any pre-configured scope.", + "type": "string", + "const": "dialog:deny-open", + "markdownDescription": "Denies the open command without any pre-configured scope." + }, + { + "description": "Denies the save command without any pre-configured scope.", + "type": "string", + "const": "dialog:deny-save", + "markdownDescription": "Denies the save command without any pre-configured scope." + }, + { + "description": "No features are enabled by default, as we believe\nthe shortcuts can be inherently dangerous and it is\napplication specific if specific shortcuts should be\nregistered or unregistered.\n", + "type": "string", + "const": "global-shortcut:default", + "markdownDescription": "No features are enabled by default, as we believe\nthe shortcuts can be inherently dangerous and it is\napplication specific if specific shortcuts should be\nregistered or unregistered.\n" + }, + { + "description": "Enables the is_registered command without any pre-configured scope.", + "type": "string", + "const": "global-shortcut:allow-is-registered", + "markdownDescription": "Enables the is_registered command without any pre-configured scope." + }, + { + "description": "Enables the register command without any pre-configured scope.", + "type": "string", + "const": "global-shortcut:allow-register", + "markdownDescription": "Enables the register command without any pre-configured scope." + }, + { + "description": "Enables the register_all command without any pre-configured scope.", + "type": "string", + "const": "global-shortcut:allow-register-all", + "markdownDescription": "Enables the register_all command without any pre-configured scope." + }, + { + "description": "Enables the unregister command without any pre-configured scope.", + "type": "string", + "const": "global-shortcut:allow-unregister", + "markdownDescription": "Enables the unregister command without any pre-configured scope." + }, + { + "description": "Enables the unregister_all command without any pre-configured scope.", + "type": "string", + "const": "global-shortcut:allow-unregister-all", + "markdownDescription": "Enables the unregister_all command without any pre-configured scope." + }, + { + "description": "Denies the is_registered command without any pre-configured scope.", + "type": "string", + "const": "global-shortcut:deny-is-registered", + "markdownDescription": "Denies the is_registered command without any pre-configured scope." + }, + { + "description": "Denies the register command without any pre-configured scope.", + "type": "string", + "const": "global-shortcut:deny-register", + "markdownDescription": "Denies the register command without any pre-configured scope." + }, + { + "description": "Denies the register_all command without any pre-configured scope.", + "type": "string", + "const": "global-shortcut:deny-register-all", + "markdownDescription": "Denies the register_all command without any pre-configured scope." + }, + { + "description": "Denies the unregister command without any pre-configured scope.", + "type": "string", + "const": "global-shortcut:deny-unregister", + "markdownDescription": "Denies the unregister command without any pre-configured scope." + }, + { + "description": "Denies the unregister_all command without any pre-configured scope.", + "type": "string", + "const": "global-shortcut:deny-unregister-all", + "markdownDescription": "Denies the unregister_all command without any pre-configured scope." + }, + { + "description": "This permission set configures what kind of\noperations are available from the mcp plugin.\n\n#### Granted Permissions\n\nAll operations are enabled by default.\n\n#### This default permission set includes:\n\n- `allow-connect-server`\n- `allow-disconnect-server`\n- `allow-list-tools`\n- `allow-call-tool`", + "type": "string", + "const": "mcp:default", + "markdownDescription": "This permission set configures what kind of\noperations are available from the mcp plugin.\n\n#### Granted Permissions\n\nAll operations are enabled by default.\n\n#### This default permission set includes:\n\n- `allow-connect-server`\n- `allow-disconnect-server`\n- `allow-list-tools`\n- `allow-call-tool`" + }, + { + "description": "Enables the call_tool command without any pre-configured scope.", + "type": "string", + "const": "mcp:allow-call-tool", + "markdownDescription": "Enables the call_tool command without any pre-configured scope." + }, + { + "description": "Enables the connect_server command without any pre-configured scope.", + "type": "string", + "const": "mcp:allow-connect-server", + "markdownDescription": "Enables the connect_server command without any pre-configured scope." + }, + { + "description": "Enables the disconnect_server command without any pre-configured scope.", + "type": "string", + "const": "mcp:allow-disconnect-server", + "markdownDescription": "Enables the disconnect_server command without any pre-configured scope." + }, + { + "description": "Enables the list_tools command without any pre-configured scope.", + "type": "string", + "const": "mcp:allow-list-tools", + "markdownDescription": "Enables the list_tools command without any pre-configured scope." + }, + { + "description": "Denies the call_tool command without any pre-configured scope.", + "type": "string", + "const": "mcp:deny-call-tool", + "markdownDescription": "Denies the call_tool command without any pre-configured scope." + }, + { + "description": "Denies the connect_server command without any pre-configured scope.", + "type": "string", + "const": "mcp:deny-connect-server", + "markdownDescription": "Denies the connect_server command without any pre-configured scope." + }, + { + "description": "Denies the disconnect_server command without any pre-configured scope.", + "type": "string", + "const": "mcp:deny-disconnect-server", + "markdownDescription": "Denies the disconnect_server command without any pre-configured scope." + }, + { + "description": "Denies the list_tools command without any pre-configured scope.", + "type": "string", + "const": "mcp:deny-list-tools", + "markdownDescription": "Denies the list_tools command without any pre-configured scope." + }, + { + "description": "This permission set allows opening `mailto:`, `tel:`, `https://` and `http://` urls using their default application\nas well as reveal file in directories using default file explorer\n#### This default permission set includes:\n\n- `allow-open-url`\n- `allow-reveal-item-in-dir`\n- `allow-default-urls`", + "type": "string", + "const": "opener:default", + "markdownDescription": "This permission set allows opening `mailto:`, `tel:`, `https://` and `http://` urls using their default application\nas well as reveal file in directories using default file explorer\n#### This default permission set includes:\n\n- `allow-open-url`\n- `allow-reveal-item-in-dir`\n- `allow-default-urls`" + }, + { + "description": "This enables opening `mailto:`, `tel:`, `https://` and `http://` urls using their default application.", + "type": "string", + "const": "opener:allow-default-urls", + "markdownDescription": "This enables opening `mailto:`, `tel:`, `https://` and `http://` urls using their default application." + }, + { + "description": "Enables the open_path command without any pre-configured scope.", + "type": "string", + "const": "opener:allow-open-path", + "markdownDescription": "Enables the open_path command without any pre-configured scope." + }, + { + "description": "Enables the open_url command without any pre-configured scope.", + "type": "string", + "const": "opener:allow-open-url", + "markdownDescription": "Enables the open_url command without any pre-configured scope." + }, + { + "description": "Enables the reveal_item_in_dir command without any pre-configured scope.", + "type": "string", + "const": "opener:allow-reveal-item-in-dir", + "markdownDescription": "Enables the reveal_item_in_dir command without any pre-configured scope." + }, + { + "description": "Denies the open_path command without any pre-configured scope.", + "type": "string", + "const": "opener:deny-open-path", + "markdownDescription": "Denies the open_path command without any pre-configured scope." + }, + { + "description": "Denies the open_url command without any pre-configured scope.", + "type": "string", + "const": "opener:deny-open-url", + "markdownDescription": "Denies the open_url command without any pre-configured scope." + }, + { + "description": "Denies the reveal_item_in_dir command without any pre-configured scope.", + "type": "string", + "const": "opener:deny-reveal-item-in-dir", + "markdownDescription": "Denies the reveal_item_in_dir command without any pre-configured scope." + } + ] + }, + "Value": { + "description": "All supported ACL values.", + "anyOf": [ + { + "description": "Represents a null JSON value.", + "type": "null" + }, + { + "description": "Represents a [`bool`].", + "type": "boolean" + }, + { + "description": "Represents a valid ACL [`Number`].", + "allOf": [ + { + "$ref": "#/definitions/Number" + } + ] + }, + { + "description": "Represents a [`String`].", + "type": "string" + }, + { + "description": "Represents a list of other [`Value`]s.", + "type": "array", + "items": { + "$ref": "#/definitions/Value" + } + }, + { + "description": "Represents a map of [`String`] keys to [`Value`]s.", + "type": "object", + "additionalProperties": { + "$ref": "#/definitions/Value" + } + } + ] + }, + "Number": { + "description": "A valid ACL number.", + "anyOf": [ + { + "description": "Represents an [`i64`].", + "type": "integer", + "format": "int64" + }, + { + "description": "Represents a [`f64`].", + "type": "number", + "format": "double" + } + ] + }, + "Target": { + "description": "Platform target.", + "oneOf": [ + { + "description": "MacOS.", + "type": "string", + "enum": [ + "macOS" + ] + }, + { + "description": "Windows.", + "type": "string", + "enum": [ + "windows" + ] + }, + { + "description": "Linux.", + "type": "string", + "enum": [ + "linux" + ] + }, + { + "description": "Android.", + "type": "string", + "enum": [ + "android" + ] + }, + { + "description": "iOS.", + "type": "string", + "enum": [ + "iOS" + ] + } + ] + }, + "Application": { + "description": "Opener scope application.", + "anyOf": [ + { + "description": "Open in default application.", + "type": "null" + }, + { + "description": "If true, allow open with any application.", + "type": "boolean" + }, + { + "description": "Allow specific application to open with.", + "type": "string" + } + ] + } + } +} \ No newline at end of file diff --git a/src-tauri/gen/schemas/windows-schema.json b/src-tauri/gen/schemas/windows-schema.json new file mode 100644 index 0000000..608d2ed --- /dev/null +++ b/src-tauri/gen/schemas/windows-schema.json @@ -0,0 +1,2663 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "CapabilityFile", + "description": "Capability formats accepted in a capability file.", + "anyOf": [ + { + "description": "A single capability.", + "allOf": [ + { + "$ref": "#/definitions/Capability" + } + ] + }, + { + "description": "A list of capabilities.", + "type": "array", + "items": { + "$ref": "#/definitions/Capability" + } + }, + { + "description": "A list of capabilities.", + "type": "object", + "required": [ + "capabilities" + ], + "properties": { + "capabilities": { + "description": "The list of capabilities.", + "type": "array", + "items": { + "$ref": "#/definitions/Capability" + } + } + } + } + ], + "definitions": { + "Capability": { + "description": "A grouping and boundary mechanism developers can use to isolate access to the IPC layer.\n\nIt controls application windows' and webviews' fine grained access to the Tauri core, application, or plugin commands. If a webview or its window is not matching any capability then it has no access to the IPC layer at all.\n\nThis can be done to create groups of windows, based on their required system access, which can reduce impact of frontend vulnerabilities in less privileged windows. Windows can be added to a capability by exact name (e.g. `main-window`) or glob patterns like `*` or `admin-*`. A Window can have none, one, or multiple associated capabilities.\n\n## Example\n\n```json { \"identifier\": \"main-user-files-write\", \"description\": \"This capability allows the `main` window on macOS and Windows access to `filesystem` write related commands and `dialog` commands to enable programmatic access to files selected by the user.\", \"windows\": [ \"main\" ], \"permissions\": [ \"core:default\", \"dialog:open\", { \"identifier\": \"fs:allow-write-text-file\", \"allow\": [{ \"path\": \"$HOME/test.txt\" }] }, ], \"platforms\": [\"macOS\",\"windows\"] } ```", + "type": "object", + "required": [ + "identifier", + "permissions" + ], + "properties": { + "identifier": { + "description": "Identifier of the capability.\n\n## Example\n\n`main-user-files-write`", + "type": "string" + }, + "description": { + "description": "Description of what the capability is intended to allow on associated windows.\n\nIt should contain a description of what the grouped permissions should allow.\n\n## Example\n\nThis capability allows the `main` window access to `filesystem` write related commands and `dialog` commands to enable programmatic access to files selected by the user.", + "default": "", + "type": "string" + }, + "remote": { + "description": "Configure remote URLs that can use the capability permissions.\n\nThis setting is optional and defaults to not being set, as our default use case is that the content is served from our local application.\n\n:::caution Make sure you understand the security implications of providing remote sources with local system access. :::\n\n## Example\n\n```json { \"urls\": [\"https://*.mydomain.dev\"] } ```", + "anyOf": [ + { + "$ref": "#/definitions/CapabilityRemote" + }, + { + "type": "null" + } + ] + }, + "local": { + "description": "Whether this capability is enabled for local app URLs or not. Defaults to `true`.", + "default": true, + "type": "boolean" + }, + "windows": { + "description": "List of windows that are affected by this capability. Can be a glob pattern.\n\nIf a window label matches any of the patterns in this list, the capability will be enabled on all the webviews of that window, regardless of the value of [`Self::webviews`].\n\nOn multiwebview windows, prefer specifying [`Self::webviews`] and omitting [`Self::windows`] for a fine grained access control.\n\n## Example\n\n`[\"main\"]`", + "type": "array", + "items": { + "type": "string" + } + }, + "webviews": { + "description": "List of webviews that are affected by this capability. Can be a glob pattern.\n\nThe capability will be enabled on all the webviews whose label matches any of the patterns in this list, regardless of whether the webview's window label matches a pattern in [`Self::windows`].\n\n## Example\n\n`[\"sub-webview-one\", \"sub-webview-two\"]`", + "type": "array", + "items": { + "type": "string" + } + }, + "permissions": { + "description": "List of permissions attached to this capability.\n\nMust include the plugin name as prefix in the form of `${plugin-name}:${permission-name}`. For commands directly implemented in the application itself only `${permission-name}` is required.\n\n## Example\n\n```json [ \"core:default\", \"shell:allow-open\", \"dialog:open\", { \"identifier\": \"fs:allow-write-text-file\", \"allow\": [{ \"path\": \"$HOME/test.txt\" }] } ] ```", + "type": "array", + "items": { + "$ref": "#/definitions/PermissionEntry" + }, + "uniqueItems": true + }, + "platforms": { + "description": "Limit which target platforms this capability applies to.\n\nBy default all platforms are targeted.\n\n## Example\n\n`[\"macOS\",\"windows\"]`", + "type": [ + "array", + "null" + ], + "items": { + "$ref": "#/definitions/Target" + } + } + } + }, + "CapabilityRemote": { + "description": "Configuration for remote URLs that are associated with the capability.", + "type": "object", + "required": [ + "urls" + ], + "properties": { + "urls": { + "description": "Remote domains this capability refers to using the [URLPattern standard](https://urlpattern.spec.whatwg.org/).\n\n## Examples\n\n- \"https://*.mydomain.dev\": allows subdomains of mydomain.dev - \"https://mydomain.dev/api/*\": allows any subpath of mydomain.dev/api", + "type": "array", + "items": { + "type": "string" + } + } + } + }, + "PermissionEntry": { + "description": "An entry for a permission value in a [`Capability`] can be either a raw permission [`Identifier`] or an object that references a permission and extends its scope.", + "anyOf": [ + { + "description": "Reference a permission or permission set by identifier.", + "allOf": [ + { + "$ref": "#/definitions/Identifier" + } + ] + }, + { + "description": "Reference a permission or permission set by identifier and extends its scope.", + "type": "object", + "allOf": [ + { + "if": { + "properties": { + "identifier": { + "anyOf": [ + { + "description": "This permission set allows opening `mailto:`, `tel:`, `https://` and `http://` urls using their default application\nas well as reveal file in directories using default file explorer\n#### This default permission set includes:\n\n- `allow-open-url`\n- `allow-reveal-item-in-dir`\n- `allow-default-urls`", + "type": "string", + "const": "opener:default", + "markdownDescription": "This permission set allows opening `mailto:`, `tel:`, `https://` and `http://` urls using their default application\nas well as reveal file in directories using default file explorer\n#### This default permission set includes:\n\n- `allow-open-url`\n- `allow-reveal-item-in-dir`\n- `allow-default-urls`" + }, + { + "description": "This enables opening `mailto:`, `tel:`, `https://` and `http://` urls using their default application.", + "type": "string", + "const": "opener:allow-default-urls", + "markdownDescription": "This enables opening `mailto:`, `tel:`, `https://` and `http://` urls using their default application." + }, + { + "description": "Enables the open_path command without any pre-configured scope.", + "type": "string", + "const": "opener:allow-open-path", + "markdownDescription": "Enables the open_path command without any pre-configured scope." + }, + { + "description": "Enables the open_url command without any pre-configured scope.", + "type": "string", + "const": "opener:allow-open-url", + "markdownDescription": "Enables the open_url command without any pre-configured scope." + }, + { + "description": "Enables the reveal_item_in_dir command without any pre-configured scope.", + "type": "string", + "const": "opener:allow-reveal-item-in-dir", + "markdownDescription": "Enables the reveal_item_in_dir command without any pre-configured scope." + }, + { + "description": "Denies the open_path command without any pre-configured scope.", + "type": "string", + "const": "opener:deny-open-path", + "markdownDescription": "Denies the open_path command without any pre-configured scope." + }, + { + "description": "Denies the open_url command without any pre-configured scope.", + "type": "string", + "const": "opener:deny-open-url", + "markdownDescription": "Denies the open_url command without any pre-configured scope." + }, + { + "description": "Denies the reveal_item_in_dir command without any pre-configured scope.", + "type": "string", + "const": "opener:deny-reveal-item-in-dir", + "markdownDescription": "Denies the reveal_item_in_dir command without any pre-configured scope." + } + ] + } + } + }, + "then": { + "properties": { + "allow": { + "items": { + "title": "OpenerScopeEntry", + "description": "Opener scope entry.", + "anyOf": [ + { + "type": "object", + "required": [ + "url" + ], + "properties": { + "app": { + "description": "An application to open this url with, for example: firefox.", + "allOf": [ + { + "$ref": "#/definitions/Application" + } + ] + }, + "url": { + "description": "A URL that can be opened by the webview when using the Opener APIs.\n\nWildcards can be used following the UNIX glob pattern.\n\nExamples:\n\n- \"https://*\" : allows all HTTPS origin\n\n- \"https://*.github.com/tauri-apps/tauri\": allows any subdomain of \"github.com\" with the \"tauri-apps/api\" path\n\n- \"https://myapi.service.com/users/*\": allows access to any URLs that begins with \"https://myapi.service.com/users/\"", + "type": "string" + } + } + }, + { + "type": "object", + "required": [ + "path" + ], + "properties": { + "app": { + "description": "An application to open this path with, for example: xdg-open.", + "allOf": [ + { + "$ref": "#/definitions/Application" + } + ] + }, + "path": { + "description": "A path that can be opened by the webview when using the Opener APIs.\n\nThe pattern can start with a variable that resolves to a system base directory. The variables are: `$AUDIO`, `$CACHE`, `$CONFIG`, `$DATA`, `$LOCALDATA`, `$DESKTOP`, `$DOCUMENT`, `$DOWNLOAD`, `$EXE`, `$FONT`, `$HOME`, `$PICTURE`, `$PUBLIC`, `$RUNTIME`, `$TEMPLATE`, `$VIDEO`, `$RESOURCE`, `$APP`, `$LOG`, `$TEMP`, `$APPCONFIG`, `$APPDATA`, `$APPLOCALDATA`, `$APPCACHE`, `$APPLOG`.", + "type": "string" + } + } + } + ] + } + }, + "deny": { + "items": { + "title": "OpenerScopeEntry", + "description": "Opener scope entry.", + "anyOf": [ + { + "type": "object", + "required": [ + "url" + ], + "properties": { + "app": { + "description": "An application to open this url with, for example: firefox.", + "allOf": [ + { + "$ref": "#/definitions/Application" + } + ] + }, + "url": { + "description": "A URL that can be opened by the webview when using the Opener APIs.\n\nWildcards can be used following the UNIX glob pattern.\n\nExamples:\n\n- \"https://*\" : allows all HTTPS origin\n\n- \"https://*.github.com/tauri-apps/tauri\": allows any subdomain of \"github.com\" with the \"tauri-apps/api\" path\n\n- \"https://myapi.service.com/users/*\": allows access to any URLs that begins with \"https://myapi.service.com/users/\"", + "type": "string" + } + } + }, + { + "type": "object", + "required": [ + "path" + ], + "properties": { + "app": { + "description": "An application to open this path with, for example: xdg-open.", + "allOf": [ + { + "$ref": "#/definitions/Application" + } + ] + }, + "path": { + "description": "A path that can be opened by the webview when using the Opener APIs.\n\nThe pattern can start with a variable that resolves to a system base directory. The variables are: `$AUDIO`, `$CACHE`, `$CONFIG`, `$DATA`, `$LOCALDATA`, `$DESKTOP`, `$DOCUMENT`, `$DOWNLOAD`, `$EXE`, `$FONT`, `$HOME`, `$PICTURE`, `$PUBLIC`, `$RUNTIME`, `$TEMPLATE`, `$VIDEO`, `$RESOURCE`, `$APP`, `$LOG`, `$TEMP`, `$APPCONFIG`, `$APPDATA`, `$APPLOCALDATA`, `$APPCACHE`, `$APPLOG`.", + "type": "string" + } + } + } + ] + } + } + } + }, + "properties": { + "identifier": { + "description": "Identifier of the permission or permission set.", + "allOf": [ + { + "$ref": "#/definitions/Identifier" + } + ] + } + } + }, + { + "properties": { + "identifier": { + "description": "Identifier of the permission or permission set.", + "allOf": [ + { + "$ref": "#/definitions/Identifier" + } + ] + }, + "allow": { + "description": "Data that defines what is allowed by the scope.", + "type": [ + "array", + "null" + ], + "items": { + "$ref": "#/definitions/Value" + } + }, + "deny": { + "description": "Data that defines what is denied by the scope. This should be prioritized by validation logic.", + "type": [ + "array", + "null" + ], + "items": { + "$ref": "#/definitions/Value" + } + } + } + } + ], + "required": [ + "identifier" + ] + } + ] + }, + "Identifier": { + "description": "Permission identifier", + "oneOf": [ + { + "description": "Default core plugins set.\n#### This default permission set includes:\n\n- `core:path:default`\n- `core:event:default`\n- `core:window:default`\n- `core:webview:default`\n- `core:app:default`\n- `core:image:default`\n- `core:resources:default`\n- `core:menu:default`\n- `core:tray:default`", + "type": "string", + "const": "core:default", + "markdownDescription": "Default core plugins set.\n#### This default permission set includes:\n\n- `core:path:default`\n- `core:event:default`\n- `core:window:default`\n- `core:webview:default`\n- `core:app:default`\n- `core:image:default`\n- `core:resources:default`\n- `core:menu:default`\n- `core:tray:default`" + }, + { + "description": "Default permissions for the plugin.\n#### This default permission set includes:\n\n- `allow-version`\n- `allow-name`\n- `allow-tauri-version`\n- `allow-identifier`\n- `allow-bundle-type`\n- `allow-register-listener`\n- `allow-remove-listener`", + "type": "string", + "const": "core:app:default", + "markdownDescription": "Default permissions for the plugin.\n#### This default permission set includes:\n\n- `allow-version`\n- `allow-name`\n- `allow-tauri-version`\n- `allow-identifier`\n- `allow-bundle-type`\n- `allow-register-listener`\n- `allow-remove-listener`" + }, + { + "description": "Enables the app_hide command without any pre-configured scope.", + "type": "string", + "const": "core:app:allow-app-hide", + "markdownDescription": "Enables the app_hide command without any pre-configured scope." + }, + { + "description": "Enables the app_show command without any pre-configured scope.", + "type": "string", + "const": "core:app:allow-app-show", + "markdownDescription": "Enables the app_show command without any pre-configured scope." + }, + { + "description": "Enables the bundle_type command without any pre-configured scope.", + "type": "string", + "const": "core:app:allow-bundle-type", + "markdownDescription": "Enables the bundle_type command without any pre-configured scope." + }, + { + "description": "Enables the default_window_icon command without any pre-configured scope.", + "type": "string", + "const": "core:app:allow-default-window-icon", + "markdownDescription": "Enables the default_window_icon command without any pre-configured scope." + }, + { + "description": "Enables the fetch_data_store_identifiers command without any pre-configured scope.", + "type": "string", + "const": "core:app:allow-fetch-data-store-identifiers", + "markdownDescription": "Enables the fetch_data_store_identifiers command without any pre-configured scope." + }, + { + "description": "Enables the identifier command without any pre-configured scope.", + "type": "string", + "const": "core:app:allow-identifier", + "markdownDescription": "Enables the identifier command without any pre-configured scope." + }, + { + "description": "Enables the name command without any pre-configured scope.", + "type": "string", + "const": "core:app:allow-name", + "markdownDescription": "Enables the name command without any pre-configured scope." + }, + { + "description": "Enables the register_listener command without any pre-configured scope.", + "type": "string", + "const": "core:app:allow-register-listener", + "markdownDescription": "Enables the register_listener command without any pre-configured scope." + }, + { + "description": "Enables the remove_data_store command without any pre-configured scope.", + "type": "string", + "const": "core:app:allow-remove-data-store", + "markdownDescription": "Enables the remove_data_store command without any pre-configured scope." + }, + { + "description": "Enables the remove_listener command without any pre-configured scope.", + "type": "string", + "const": "core:app:allow-remove-listener", + "markdownDescription": "Enables the remove_listener command without any pre-configured scope." + }, + { + "description": "Enables the set_app_theme command without any pre-configured scope.", + "type": "string", + "const": "core:app:allow-set-app-theme", + "markdownDescription": "Enables the set_app_theme command without any pre-configured scope." + }, + { + "description": "Enables the set_dock_visibility command without any pre-configured scope.", + "type": "string", + "const": "core:app:allow-set-dock-visibility", + "markdownDescription": "Enables the set_dock_visibility command without any pre-configured scope." + }, + { + "description": "Enables the tauri_version command without any pre-configured scope.", + "type": "string", + "const": "core:app:allow-tauri-version", + "markdownDescription": "Enables the tauri_version command without any pre-configured scope." + }, + { + "description": "Enables the version command without any pre-configured scope.", + "type": "string", + "const": "core:app:allow-version", + "markdownDescription": "Enables the version command without any pre-configured scope." + }, + { + "description": "Denies the app_hide command without any pre-configured scope.", + "type": "string", + "const": "core:app:deny-app-hide", + "markdownDescription": "Denies the app_hide command without any pre-configured scope." + }, + { + "description": "Denies the app_show command without any pre-configured scope.", + "type": "string", + "const": "core:app:deny-app-show", + "markdownDescription": "Denies the app_show command without any pre-configured scope." + }, + { + "description": "Denies the bundle_type command without any pre-configured scope.", + "type": "string", + "const": "core:app:deny-bundle-type", + "markdownDescription": "Denies the bundle_type command without any pre-configured scope." + }, + { + "description": "Denies the default_window_icon command without any pre-configured scope.", + "type": "string", + "const": "core:app:deny-default-window-icon", + "markdownDescription": "Denies the default_window_icon command without any pre-configured scope." + }, + { + "description": "Denies the fetch_data_store_identifiers command without any pre-configured scope.", + "type": "string", + "const": "core:app:deny-fetch-data-store-identifiers", + "markdownDescription": "Denies the fetch_data_store_identifiers command without any pre-configured scope." + }, + { + "description": "Denies the identifier command without any pre-configured scope.", + "type": "string", + "const": "core:app:deny-identifier", + "markdownDescription": "Denies the identifier command without any pre-configured scope." + }, + { + "description": "Denies the name command without any pre-configured scope.", + "type": "string", + "const": "core:app:deny-name", + "markdownDescription": "Denies the name command without any pre-configured scope." + }, + { + "description": "Denies the register_listener command without any pre-configured scope.", + "type": "string", + "const": "core:app:deny-register-listener", + "markdownDescription": "Denies the register_listener command without any pre-configured scope." + }, + { + "description": "Denies the remove_data_store command without any pre-configured scope.", + "type": "string", + "const": "core:app:deny-remove-data-store", + "markdownDescription": "Denies the remove_data_store command without any pre-configured scope." + }, + { + "description": "Denies the remove_listener command without any pre-configured scope.", + "type": "string", + "const": "core:app:deny-remove-listener", + "markdownDescription": "Denies the remove_listener command without any pre-configured scope." + }, + { + "description": "Denies the set_app_theme command without any pre-configured scope.", + "type": "string", + "const": "core:app:deny-set-app-theme", + "markdownDescription": "Denies the set_app_theme command without any pre-configured scope." + }, + { + "description": "Denies the set_dock_visibility command without any pre-configured scope.", + "type": "string", + "const": "core:app:deny-set-dock-visibility", + "markdownDescription": "Denies the set_dock_visibility command without any pre-configured scope." + }, + { + "description": "Denies the tauri_version command without any pre-configured scope.", + "type": "string", + "const": "core:app:deny-tauri-version", + "markdownDescription": "Denies the tauri_version command without any pre-configured scope." + }, + { + "description": "Denies the version command without any pre-configured scope.", + "type": "string", + "const": "core:app:deny-version", + "markdownDescription": "Denies the version command without any pre-configured scope." + }, + { + "description": "Default permissions for the plugin, which enables all commands.\n#### This default permission set includes:\n\n- `allow-listen`\n- `allow-unlisten`\n- `allow-emit`\n- `allow-emit-to`", + "type": "string", + "const": "core:event:default", + "markdownDescription": "Default permissions for the plugin, which enables all commands.\n#### This default permission set includes:\n\n- `allow-listen`\n- `allow-unlisten`\n- `allow-emit`\n- `allow-emit-to`" + }, + { + "description": "Enables the emit command without any pre-configured scope.", + "type": "string", + "const": "core:event:allow-emit", + "markdownDescription": "Enables the emit command without any pre-configured scope." + }, + { + "description": "Enables the emit_to command without any pre-configured scope.", + "type": "string", + "const": "core:event:allow-emit-to", + "markdownDescription": "Enables the emit_to command without any pre-configured scope." + }, + { + "description": "Enables the listen command without any pre-configured scope.", + "type": "string", + "const": "core:event:allow-listen", + "markdownDescription": "Enables the listen command without any pre-configured scope." + }, + { + "description": "Enables the unlisten command without any pre-configured scope.", + "type": "string", + "const": "core:event:allow-unlisten", + "markdownDescription": "Enables the unlisten command without any pre-configured scope." + }, + { + "description": "Denies the emit command without any pre-configured scope.", + "type": "string", + "const": "core:event:deny-emit", + "markdownDescription": "Denies the emit command without any pre-configured scope." + }, + { + "description": "Denies the emit_to command without any pre-configured scope.", + "type": "string", + "const": "core:event:deny-emit-to", + "markdownDescription": "Denies the emit_to command without any pre-configured scope." + }, + { + "description": "Denies the listen command without any pre-configured scope.", + "type": "string", + "const": "core:event:deny-listen", + "markdownDescription": "Denies the listen command without any pre-configured scope." + }, + { + "description": "Denies the unlisten command without any pre-configured scope.", + "type": "string", + "const": "core:event:deny-unlisten", + "markdownDescription": "Denies the unlisten command without any pre-configured scope." + }, + { + "description": "Default permissions for the plugin, which enables all commands.\n#### This default permission set includes:\n\n- `allow-new`\n- `allow-from-bytes`\n- `allow-from-path`\n- `allow-rgba`\n- `allow-size`", + "type": "string", + "const": "core:image:default", + "markdownDescription": "Default permissions for the plugin, which enables all commands.\n#### This default permission set includes:\n\n- `allow-new`\n- `allow-from-bytes`\n- `allow-from-path`\n- `allow-rgba`\n- `allow-size`" + }, + { + "description": "Enables the from_bytes command without any pre-configured scope.", + "type": "string", + "const": "core:image:allow-from-bytes", + "markdownDescription": "Enables the from_bytes command without any pre-configured scope." + }, + { + "description": "Enables the from_path command without any pre-configured scope.", + "type": "string", + "const": "core:image:allow-from-path", + "markdownDescription": "Enables the from_path command without any pre-configured scope." + }, + { + "description": "Enables the new command without any pre-configured scope.", + "type": "string", + "const": "core:image:allow-new", + "markdownDescription": "Enables the new command without any pre-configured scope." + }, + { + "description": "Enables the rgba command without any pre-configured scope.", + "type": "string", + "const": "core:image:allow-rgba", + "markdownDescription": "Enables the rgba command without any pre-configured scope." + }, + { + "description": "Enables the size command without any pre-configured scope.", + "type": "string", + "const": "core:image:allow-size", + "markdownDescription": "Enables the size command without any pre-configured scope." + }, + { + "description": "Denies the from_bytes command without any pre-configured scope.", + "type": "string", + "const": "core:image:deny-from-bytes", + "markdownDescription": "Denies the from_bytes command without any pre-configured scope." + }, + { + "description": "Denies the from_path command without any pre-configured scope.", + "type": "string", + "const": "core:image:deny-from-path", + "markdownDescription": "Denies the from_path command without any pre-configured scope." + }, + { + "description": "Denies the new command without any pre-configured scope.", + "type": "string", + "const": "core:image:deny-new", + "markdownDescription": "Denies the new command without any pre-configured scope." + }, + { + "description": "Denies the rgba command without any pre-configured scope.", + "type": "string", + "const": "core:image:deny-rgba", + "markdownDescription": "Denies the rgba command without any pre-configured scope." + }, + { + "description": "Denies the size command without any pre-configured scope.", + "type": "string", + "const": "core:image:deny-size", + "markdownDescription": "Denies the size command without any pre-configured scope." + }, + { + "description": "Default permissions for the plugin, which enables all commands.\n#### This default permission set includes:\n\n- `allow-new`\n- `allow-append`\n- `allow-prepend`\n- `allow-insert`\n- `allow-remove`\n- `allow-remove-at`\n- `allow-items`\n- `allow-get`\n- `allow-popup`\n- `allow-create-default`\n- `allow-set-as-app-menu`\n- `allow-set-as-window-menu`\n- `allow-text`\n- `allow-set-text`\n- `allow-is-enabled`\n- `allow-set-enabled`\n- `allow-set-accelerator`\n- `allow-set-as-windows-menu-for-nsapp`\n- `allow-set-as-help-menu-for-nsapp`\n- `allow-is-checked`\n- `allow-set-checked`\n- `allow-set-icon`", + "type": "string", + "const": "core:menu:default", + "markdownDescription": "Default permissions for the plugin, which enables all commands.\n#### This default permission set includes:\n\n- `allow-new`\n- `allow-append`\n- `allow-prepend`\n- `allow-insert`\n- `allow-remove`\n- `allow-remove-at`\n- `allow-items`\n- `allow-get`\n- `allow-popup`\n- `allow-create-default`\n- `allow-set-as-app-menu`\n- `allow-set-as-window-menu`\n- `allow-text`\n- `allow-set-text`\n- `allow-is-enabled`\n- `allow-set-enabled`\n- `allow-set-accelerator`\n- `allow-set-as-windows-menu-for-nsapp`\n- `allow-set-as-help-menu-for-nsapp`\n- `allow-is-checked`\n- `allow-set-checked`\n- `allow-set-icon`" + }, + { + "description": "Enables the append command without any pre-configured scope.", + "type": "string", + "const": "core:menu:allow-append", + "markdownDescription": "Enables the append command without any pre-configured scope." + }, + { + "description": "Enables the create_default command without any pre-configured scope.", + "type": "string", + "const": "core:menu:allow-create-default", + "markdownDescription": "Enables the create_default command without any pre-configured scope." + }, + { + "description": "Enables the get command without any pre-configured scope.", + "type": "string", + "const": "core:menu:allow-get", + "markdownDescription": "Enables the get command without any pre-configured scope." + }, + { + "description": "Enables the insert command without any pre-configured scope.", + "type": "string", + "const": "core:menu:allow-insert", + "markdownDescription": "Enables the insert command without any pre-configured scope." + }, + { + "description": "Enables the is_checked command without any pre-configured scope.", + "type": "string", + "const": "core:menu:allow-is-checked", + "markdownDescription": "Enables the is_checked command without any pre-configured scope." + }, + { + "description": "Enables the is_enabled command without any pre-configured scope.", + "type": "string", + "const": "core:menu:allow-is-enabled", + "markdownDescription": "Enables the is_enabled command without any pre-configured scope." + }, + { + "description": "Enables the items command without any pre-configured scope.", + "type": "string", + "const": "core:menu:allow-items", + "markdownDescription": "Enables the items command without any pre-configured scope." + }, + { + "description": "Enables the new command without any pre-configured scope.", + "type": "string", + "const": "core:menu:allow-new", + "markdownDescription": "Enables the new command without any pre-configured scope." + }, + { + "description": "Enables the popup command without any pre-configured scope.", + "type": "string", + "const": "core:menu:allow-popup", + "markdownDescription": "Enables the popup command without any pre-configured scope." + }, + { + "description": "Enables the prepend command without any pre-configured scope.", + "type": "string", + "const": "core:menu:allow-prepend", + "markdownDescription": "Enables the prepend command without any pre-configured scope." + }, + { + "description": "Enables the remove command without any pre-configured scope.", + "type": "string", + "const": "core:menu:allow-remove", + "markdownDescription": "Enables the remove command without any pre-configured scope." + }, + { + "description": "Enables the remove_at command without any pre-configured scope.", + "type": "string", + "const": "core:menu:allow-remove-at", + "markdownDescription": "Enables the remove_at command without any pre-configured scope." + }, + { + "description": "Enables the set_accelerator command without any pre-configured scope.", + "type": "string", + "const": "core:menu:allow-set-accelerator", + "markdownDescription": "Enables the set_accelerator command without any pre-configured scope." + }, + { + "description": "Enables the set_as_app_menu command without any pre-configured scope.", + "type": "string", + "const": "core:menu:allow-set-as-app-menu", + "markdownDescription": "Enables the set_as_app_menu command without any pre-configured scope." + }, + { + "description": "Enables the set_as_help_menu_for_nsapp command without any pre-configured scope.", + "type": "string", + "const": "core:menu:allow-set-as-help-menu-for-nsapp", + "markdownDescription": "Enables the set_as_help_menu_for_nsapp command without any pre-configured scope." + }, + { + "description": "Enables the set_as_window_menu command without any pre-configured scope.", + "type": "string", + "const": "core:menu:allow-set-as-window-menu", + "markdownDescription": "Enables the set_as_window_menu command without any pre-configured scope." + }, + { + "description": "Enables the set_as_windows_menu_for_nsapp command without any pre-configured scope.", + "type": "string", + "const": "core:menu:allow-set-as-windows-menu-for-nsapp", + "markdownDescription": "Enables the set_as_windows_menu_for_nsapp command without any pre-configured scope." + }, + { + "description": "Enables the set_checked command without any pre-configured scope.", + "type": "string", + "const": "core:menu:allow-set-checked", + "markdownDescription": "Enables the set_checked command without any pre-configured scope." + }, + { + "description": "Enables the set_enabled command without any pre-configured scope.", + "type": "string", + "const": "core:menu:allow-set-enabled", + "markdownDescription": "Enables the set_enabled command without any pre-configured scope." + }, + { + "description": "Enables the set_icon command without any pre-configured scope.", + "type": "string", + "const": "core:menu:allow-set-icon", + "markdownDescription": "Enables the set_icon command without any pre-configured scope." + }, + { + "description": "Enables the set_text command without any pre-configured scope.", + "type": "string", + "const": "core:menu:allow-set-text", + "markdownDescription": "Enables the set_text command without any pre-configured scope." + }, + { + "description": "Enables the text command without any pre-configured scope.", + "type": "string", + "const": "core:menu:allow-text", + "markdownDescription": "Enables the text command without any pre-configured scope." + }, + { + "description": "Denies the append command without any pre-configured scope.", + "type": "string", + "const": "core:menu:deny-append", + "markdownDescription": "Denies the append command without any pre-configured scope." + }, + { + "description": "Denies the create_default command without any pre-configured scope.", + "type": "string", + "const": "core:menu:deny-create-default", + "markdownDescription": "Denies the create_default command without any pre-configured scope." + }, + { + "description": "Denies the get command without any pre-configured scope.", + "type": "string", + "const": "core:menu:deny-get", + "markdownDescription": "Denies the get command without any pre-configured scope." + }, + { + "description": "Denies the insert command without any pre-configured scope.", + "type": "string", + "const": "core:menu:deny-insert", + "markdownDescription": "Denies the insert command without any pre-configured scope." + }, + { + "description": "Denies the is_checked command without any pre-configured scope.", + "type": "string", + "const": "core:menu:deny-is-checked", + "markdownDescription": "Denies the is_checked command without any pre-configured scope." + }, + { + "description": "Denies the is_enabled command without any pre-configured scope.", + "type": "string", + "const": "core:menu:deny-is-enabled", + "markdownDescription": "Denies the is_enabled command without any pre-configured scope." + }, + { + "description": "Denies the items command without any pre-configured scope.", + "type": "string", + "const": "core:menu:deny-items", + "markdownDescription": "Denies the items command without any pre-configured scope." + }, + { + "description": "Denies the new command without any pre-configured scope.", + "type": "string", + "const": "core:menu:deny-new", + "markdownDescription": "Denies the new command without any pre-configured scope." + }, + { + "description": "Denies the popup command without any pre-configured scope.", + "type": "string", + "const": "core:menu:deny-popup", + "markdownDescription": "Denies the popup command without any pre-configured scope." + }, + { + "description": "Denies the prepend command without any pre-configured scope.", + "type": "string", + "const": "core:menu:deny-prepend", + "markdownDescription": "Denies the prepend command without any pre-configured scope." + }, + { + "description": "Denies the remove command without any pre-configured scope.", + "type": "string", + "const": "core:menu:deny-remove", + "markdownDescription": "Denies the remove command without any pre-configured scope." + }, + { + "description": "Denies the remove_at command without any pre-configured scope.", + "type": "string", + "const": "core:menu:deny-remove-at", + "markdownDescription": "Denies the remove_at command without any pre-configured scope." + }, + { + "description": "Denies the set_accelerator command without any pre-configured scope.", + "type": "string", + "const": "core:menu:deny-set-accelerator", + "markdownDescription": "Denies the set_accelerator command without any pre-configured scope." + }, + { + "description": "Denies the set_as_app_menu command without any pre-configured scope.", + "type": "string", + "const": "core:menu:deny-set-as-app-menu", + "markdownDescription": "Denies the set_as_app_menu command without any pre-configured scope." + }, + { + "description": "Denies the set_as_help_menu_for_nsapp command without any pre-configured scope.", + "type": "string", + "const": "core:menu:deny-set-as-help-menu-for-nsapp", + "markdownDescription": "Denies the set_as_help_menu_for_nsapp command without any pre-configured scope." + }, + { + "description": "Denies the set_as_window_menu command without any pre-configured scope.", + "type": "string", + "const": "core:menu:deny-set-as-window-menu", + "markdownDescription": "Denies the set_as_window_menu command without any pre-configured scope." + }, + { + "description": "Denies the set_as_windows_menu_for_nsapp command without any pre-configured scope.", + "type": "string", + "const": "core:menu:deny-set-as-windows-menu-for-nsapp", + "markdownDescription": "Denies the set_as_windows_menu_for_nsapp command without any pre-configured scope." + }, + { + "description": "Denies the set_checked command without any pre-configured scope.", + "type": "string", + "const": "core:menu:deny-set-checked", + "markdownDescription": "Denies the set_checked command without any pre-configured scope." + }, + { + "description": "Denies the set_enabled command without any pre-configured scope.", + "type": "string", + "const": "core:menu:deny-set-enabled", + "markdownDescription": "Denies the set_enabled command without any pre-configured scope." + }, + { + "description": "Denies the set_icon command without any pre-configured scope.", + "type": "string", + "const": "core:menu:deny-set-icon", + "markdownDescription": "Denies the set_icon command without any pre-configured scope." + }, + { + "description": "Denies the set_text command without any pre-configured scope.", + "type": "string", + "const": "core:menu:deny-set-text", + "markdownDescription": "Denies the set_text command without any pre-configured scope." + }, + { + "description": "Denies the text command without any pre-configured scope.", + "type": "string", + "const": "core:menu:deny-text", + "markdownDescription": "Denies the text command without any pre-configured scope." + }, + { + "description": "Default permissions for the plugin, which enables all commands.\n#### This default permission set includes:\n\n- `allow-resolve-directory`\n- `allow-resolve`\n- `allow-normalize`\n- `allow-join`\n- `allow-dirname`\n- `allow-extname`\n- `allow-basename`\n- `allow-is-absolute`", + "type": "string", + "const": "core:path:default", + "markdownDescription": "Default permissions for the plugin, which enables all commands.\n#### This default permission set includes:\n\n- `allow-resolve-directory`\n- `allow-resolve`\n- `allow-normalize`\n- `allow-join`\n- `allow-dirname`\n- `allow-extname`\n- `allow-basename`\n- `allow-is-absolute`" + }, + { + "description": "Enables the basename command without any pre-configured scope.", + "type": "string", + "const": "core:path:allow-basename", + "markdownDescription": "Enables the basename command without any pre-configured scope." + }, + { + "description": "Enables the dirname command without any pre-configured scope.", + "type": "string", + "const": "core:path:allow-dirname", + "markdownDescription": "Enables the dirname command without any pre-configured scope." + }, + { + "description": "Enables the extname command without any pre-configured scope.", + "type": "string", + "const": "core:path:allow-extname", + "markdownDescription": "Enables the extname command without any pre-configured scope." + }, + { + "description": "Enables the is_absolute command without any pre-configured scope.", + "type": "string", + "const": "core:path:allow-is-absolute", + "markdownDescription": "Enables the is_absolute command without any pre-configured scope." + }, + { + "description": "Enables the join command without any pre-configured scope.", + "type": "string", + "const": "core:path:allow-join", + "markdownDescription": "Enables the join command without any pre-configured scope." + }, + { + "description": "Enables the normalize command without any pre-configured scope.", + "type": "string", + "const": "core:path:allow-normalize", + "markdownDescription": "Enables the normalize command without any pre-configured scope." + }, + { + "description": "Enables the resolve command without any pre-configured scope.", + "type": "string", + "const": "core:path:allow-resolve", + "markdownDescription": "Enables the resolve command without any pre-configured scope." + }, + { + "description": "Enables the resolve_directory command without any pre-configured scope.", + "type": "string", + "const": "core:path:allow-resolve-directory", + "markdownDescription": "Enables the resolve_directory command without any pre-configured scope." + }, + { + "description": "Denies the basename command without any pre-configured scope.", + "type": "string", + "const": "core:path:deny-basename", + "markdownDescription": "Denies the basename command without any pre-configured scope." + }, + { + "description": "Denies the dirname command without any pre-configured scope.", + "type": "string", + "const": "core:path:deny-dirname", + "markdownDescription": "Denies the dirname command without any pre-configured scope." + }, + { + "description": "Denies the extname command without any pre-configured scope.", + "type": "string", + "const": "core:path:deny-extname", + "markdownDescription": "Denies the extname command without any pre-configured scope." + }, + { + "description": "Denies the is_absolute command without any pre-configured scope.", + "type": "string", + "const": "core:path:deny-is-absolute", + "markdownDescription": "Denies the is_absolute command without any pre-configured scope." + }, + { + "description": "Denies the join command without any pre-configured scope.", + "type": "string", + "const": "core:path:deny-join", + "markdownDescription": "Denies the join command without any pre-configured scope." + }, + { + "description": "Denies the normalize command without any pre-configured scope.", + "type": "string", + "const": "core:path:deny-normalize", + "markdownDescription": "Denies the normalize command without any pre-configured scope." + }, + { + "description": "Denies the resolve command without any pre-configured scope.", + "type": "string", + "const": "core:path:deny-resolve", + "markdownDescription": "Denies the resolve command without any pre-configured scope." + }, + { + "description": "Denies the resolve_directory command without any pre-configured scope.", + "type": "string", + "const": "core:path:deny-resolve-directory", + "markdownDescription": "Denies the resolve_directory command without any pre-configured scope." + }, + { + "description": "Default permissions for the plugin, which enables all commands.\n#### This default permission set includes:\n\n- `allow-close`", + "type": "string", + "const": "core:resources:default", + "markdownDescription": "Default permissions for the plugin, which enables all commands.\n#### This default permission set includes:\n\n- `allow-close`" + }, + { + "description": "Enables the close command without any pre-configured scope.", + "type": "string", + "const": "core:resources:allow-close", + "markdownDescription": "Enables the close command without any pre-configured scope." + }, + { + "description": "Denies the close command without any pre-configured scope.", + "type": "string", + "const": "core:resources:deny-close", + "markdownDescription": "Denies the close command without any pre-configured scope." + }, + { + "description": "Default permissions for the plugin, which enables all commands.\n#### This default permission set includes:\n\n- `allow-new`\n- `allow-get-by-id`\n- `allow-remove-by-id`\n- `allow-set-icon`\n- `allow-set-menu`\n- `allow-set-tooltip`\n- `allow-set-title`\n- `allow-set-visible`\n- `allow-set-temp-dir-path`\n- `allow-set-icon-as-template`\n- `allow-set-show-menu-on-left-click`", + "type": "string", + "const": "core:tray:default", + "markdownDescription": "Default permissions for the plugin, which enables all commands.\n#### This default permission set includes:\n\n- `allow-new`\n- `allow-get-by-id`\n- `allow-remove-by-id`\n- `allow-set-icon`\n- `allow-set-menu`\n- `allow-set-tooltip`\n- `allow-set-title`\n- `allow-set-visible`\n- `allow-set-temp-dir-path`\n- `allow-set-icon-as-template`\n- `allow-set-show-menu-on-left-click`" + }, + { + "description": "Enables the get_by_id command without any pre-configured scope.", + "type": "string", + "const": "core:tray:allow-get-by-id", + "markdownDescription": "Enables the get_by_id command without any pre-configured scope." + }, + { + "description": "Enables the new command without any pre-configured scope.", + "type": "string", + "const": "core:tray:allow-new", + "markdownDescription": "Enables the new command without any pre-configured scope." + }, + { + "description": "Enables the remove_by_id command without any pre-configured scope.", + "type": "string", + "const": "core:tray:allow-remove-by-id", + "markdownDescription": "Enables the remove_by_id command without any pre-configured scope." + }, + { + "description": "Enables the set_icon command without any pre-configured scope.", + "type": "string", + "const": "core:tray:allow-set-icon", + "markdownDescription": "Enables the set_icon command without any pre-configured scope." + }, + { + "description": "Enables the set_icon_as_template command without any pre-configured scope.", + "type": "string", + "const": "core:tray:allow-set-icon-as-template", + "markdownDescription": "Enables the set_icon_as_template command without any pre-configured scope." + }, + { + "description": "Enables the set_menu command without any pre-configured scope.", + "type": "string", + "const": "core:tray:allow-set-menu", + "markdownDescription": "Enables the set_menu command without any pre-configured scope." + }, + { + "description": "Enables the set_show_menu_on_left_click command without any pre-configured scope.", + "type": "string", + "const": "core:tray:allow-set-show-menu-on-left-click", + "markdownDescription": "Enables the set_show_menu_on_left_click command without any pre-configured scope." + }, + { + "description": "Enables the set_temp_dir_path command without any pre-configured scope.", + "type": "string", + "const": "core:tray:allow-set-temp-dir-path", + "markdownDescription": "Enables the set_temp_dir_path command without any pre-configured scope." + }, + { + "description": "Enables the set_title command without any pre-configured scope.", + "type": "string", + "const": "core:tray:allow-set-title", + "markdownDescription": "Enables the set_title command without any pre-configured scope." + }, + { + "description": "Enables the set_tooltip command without any pre-configured scope.", + "type": "string", + "const": "core:tray:allow-set-tooltip", + "markdownDescription": "Enables the set_tooltip command without any pre-configured scope." + }, + { + "description": "Enables the set_visible command without any pre-configured scope.", + "type": "string", + "const": "core:tray:allow-set-visible", + "markdownDescription": "Enables the set_visible command without any pre-configured scope." + }, + { + "description": "Denies the get_by_id command without any pre-configured scope.", + "type": "string", + "const": "core:tray:deny-get-by-id", + "markdownDescription": "Denies the get_by_id command without any pre-configured scope." + }, + { + "description": "Denies the new command without any pre-configured scope.", + "type": "string", + "const": "core:tray:deny-new", + "markdownDescription": "Denies the new command without any pre-configured scope." + }, + { + "description": "Denies the remove_by_id command without any pre-configured scope.", + "type": "string", + "const": "core:tray:deny-remove-by-id", + "markdownDescription": "Denies the remove_by_id command without any pre-configured scope." + }, + { + "description": "Denies the set_icon command without any pre-configured scope.", + "type": "string", + "const": "core:tray:deny-set-icon", + "markdownDescription": "Denies the set_icon command without any pre-configured scope." + }, + { + "description": "Denies the set_icon_as_template command without any pre-configured scope.", + "type": "string", + "const": "core:tray:deny-set-icon-as-template", + "markdownDescription": "Denies the set_icon_as_template command without any pre-configured scope." + }, + { + "description": "Denies the set_menu command without any pre-configured scope.", + "type": "string", + "const": "core:tray:deny-set-menu", + "markdownDescription": "Denies the set_menu command without any pre-configured scope." + }, + { + "description": "Denies the set_show_menu_on_left_click command without any pre-configured scope.", + "type": "string", + "const": "core:tray:deny-set-show-menu-on-left-click", + "markdownDescription": "Denies the set_show_menu_on_left_click command without any pre-configured scope." + }, + { + "description": "Denies the set_temp_dir_path command without any pre-configured scope.", + "type": "string", + "const": "core:tray:deny-set-temp-dir-path", + "markdownDescription": "Denies the set_temp_dir_path command without any pre-configured scope." + }, + { + "description": "Denies the set_title command without any pre-configured scope.", + "type": "string", + "const": "core:tray:deny-set-title", + "markdownDescription": "Denies the set_title command without any pre-configured scope." + }, + { + "description": "Denies the set_tooltip command without any pre-configured scope.", + "type": "string", + "const": "core:tray:deny-set-tooltip", + "markdownDescription": "Denies the set_tooltip command without any pre-configured scope." + }, + { + "description": "Denies the set_visible command without any pre-configured scope.", + "type": "string", + "const": "core:tray:deny-set-visible", + "markdownDescription": "Denies the set_visible command without any pre-configured scope." + }, + { + "description": "Default permissions for the plugin.\n#### This default permission set includes:\n\n- `allow-get-all-webviews`\n- `allow-webview-position`\n- `allow-webview-size`\n- `allow-internal-toggle-devtools`", + "type": "string", + "const": "core:webview:default", + "markdownDescription": "Default permissions for the plugin.\n#### This default permission set includes:\n\n- `allow-get-all-webviews`\n- `allow-webview-position`\n- `allow-webview-size`\n- `allow-internal-toggle-devtools`" + }, + { + "description": "Enables the clear_all_browsing_data command without any pre-configured scope.", + "type": "string", + "const": "core:webview:allow-clear-all-browsing-data", + "markdownDescription": "Enables the clear_all_browsing_data command without any pre-configured scope." + }, + { + "description": "Enables the create_webview command without any pre-configured scope.", + "type": "string", + "const": "core:webview:allow-create-webview", + "markdownDescription": "Enables the create_webview command without any pre-configured scope." + }, + { + "description": "Enables the create_webview_window command without any pre-configured scope.", + "type": "string", + "const": "core:webview:allow-create-webview-window", + "markdownDescription": "Enables the create_webview_window command without any pre-configured scope." + }, + { + "description": "Enables the get_all_webviews command without any pre-configured scope.", + "type": "string", + "const": "core:webview:allow-get-all-webviews", + "markdownDescription": "Enables the get_all_webviews command without any pre-configured scope." + }, + { + "description": "Enables the internal_toggle_devtools command without any pre-configured scope.", + "type": "string", + "const": "core:webview:allow-internal-toggle-devtools", + "markdownDescription": "Enables the internal_toggle_devtools command without any pre-configured scope." + }, + { + "description": "Enables the print command without any pre-configured scope.", + "type": "string", + "const": "core:webview:allow-print", + "markdownDescription": "Enables the print command without any pre-configured scope." + }, + { + "description": "Enables the reparent command without any pre-configured scope.", + "type": "string", + "const": "core:webview:allow-reparent", + "markdownDescription": "Enables the reparent command without any pre-configured scope." + }, + { + "description": "Enables the set_webview_auto_resize command without any pre-configured scope.", + "type": "string", + "const": "core:webview:allow-set-webview-auto-resize", + "markdownDescription": "Enables the set_webview_auto_resize command without any pre-configured scope." + }, + { + "description": "Enables the set_webview_background_color command without any pre-configured scope.", + "type": "string", + "const": "core:webview:allow-set-webview-background-color", + "markdownDescription": "Enables the set_webview_background_color command without any pre-configured scope." + }, + { + "description": "Enables the set_webview_focus command without any pre-configured scope.", + "type": "string", + "const": "core:webview:allow-set-webview-focus", + "markdownDescription": "Enables the set_webview_focus command without any pre-configured scope." + }, + { + "description": "Enables the set_webview_position command without any pre-configured scope.", + "type": "string", + "const": "core:webview:allow-set-webview-position", + "markdownDescription": "Enables the set_webview_position command without any pre-configured scope." + }, + { + "description": "Enables the set_webview_size command without any pre-configured scope.", + "type": "string", + "const": "core:webview:allow-set-webview-size", + "markdownDescription": "Enables the set_webview_size command without any pre-configured scope." + }, + { + "description": "Enables the set_webview_zoom command without any pre-configured scope.", + "type": "string", + "const": "core:webview:allow-set-webview-zoom", + "markdownDescription": "Enables the set_webview_zoom command without any pre-configured scope." + }, + { + "description": "Enables the webview_close command without any pre-configured scope.", + "type": "string", + "const": "core:webview:allow-webview-close", + "markdownDescription": "Enables the webview_close command without any pre-configured scope." + }, + { + "description": "Enables the webview_hide command without any pre-configured scope.", + "type": "string", + "const": "core:webview:allow-webview-hide", + "markdownDescription": "Enables the webview_hide command without any pre-configured scope." + }, + { + "description": "Enables the webview_position command without any pre-configured scope.", + "type": "string", + "const": "core:webview:allow-webview-position", + "markdownDescription": "Enables the webview_position command without any pre-configured scope." + }, + { + "description": "Enables the webview_show command without any pre-configured scope.", + "type": "string", + "const": "core:webview:allow-webview-show", + "markdownDescription": "Enables the webview_show command without any pre-configured scope." + }, + { + "description": "Enables the webview_size command without any pre-configured scope.", + "type": "string", + "const": "core:webview:allow-webview-size", + "markdownDescription": "Enables the webview_size command without any pre-configured scope." + }, + { + "description": "Denies the clear_all_browsing_data command without any pre-configured scope.", + "type": "string", + "const": "core:webview:deny-clear-all-browsing-data", + "markdownDescription": "Denies the clear_all_browsing_data command without any pre-configured scope." + }, + { + "description": "Denies the create_webview command without any pre-configured scope.", + "type": "string", + "const": "core:webview:deny-create-webview", + "markdownDescription": "Denies the create_webview command without any pre-configured scope." + }, + { + "description": "Denies the create_webview_window command without any pre-configured scope.", + "type": "string", + "const": "core:webview:deny-create-webview-window", + "markdownDescription": "Denies the create_webview_window command without any pre-configured scope." + }, + { + "description": "Denies the get_all_webviews command without any pre-configured scope.", + "type": "string", + "const": "core:webview:deny-get-all-webviews", + "markdownDescription": "Denies the get_all_webviews command without any pre-configured scope." + }, + { + "description": "Denies the internal_toggle_devtools command without any pre-configured scope.", + "type": "string", + "const": "core:webview:deny-internal-toggle-devtools", + "markdownDescription": "Denies the internal_toggle_devtools command without any pre-configured scope." + }, + { + "description": "Denies the print command without any pre-configured scope.", + "type": "string", + "const": "core:webview:deny-print", + "markdownDescription": "Denies the print command without any pre-configured scope." + }, + { + "description": "Denies the reparent command without any pre-configured scope.", + "type": "string", + "const": "core:webview:deny-reparent", + "markdownDescription": "Denies the reparent command without any pre-configured scope." + }, + { + "description": "Denies the set_webview_auto_resize command without any pre-configured scope.", + "type": "string", + "const": "core:webview:deny-set-webview-auto-resize", + "markdownDescription": "Denies the set_webview_auto_resize command without any pre-configured scope." + }, + { + "description": "Denies the set_webview_background_color command without any pre-configured scope.", + "type": "string", + "const": "core:webview:deny-set-webview-background-color", + "markdownDescription": "Denies the set_webview_background_color command without any pre-configured scope." + }, + { + "description": "Denies the set_webview_focus command without any pre-configured scope.", + "type": "string", + "const": "core:webview:deny-set-webview-focus", + "markdownDescription": "Denies the set_webview_focus command without any pre-configured scope." + }, + { + "description": "Denies the set_webview_position command without any pre-configured scope.", + "type": "string", + "const": "core:webview:deny-set-webview-position", + "markdownDescription": "Denies the set_webview_position command without any pre-configured scope." + }, + { + "description": "Denies the set_webview_size command without any pre-configured scope.", + "type": "string", + "const": "core:webview:deny-set-webview-size", + "markdownDescription": "Denies the set_webview_size command without any pre-configured scope." + }, + { + "description": "Denies the set_webview_zoom command without any pre-configured scope.", + "type": "string", + "const": "core:webview:deny-set-webview-zoom", + "markdownDescription": "Denies the set_webview_zoom command without any pre-configured scope." + }, + { + "description": "Denies the webview_close command without any pre-configured scope.", + "type": "string", + "const": "core:webview:deny-webview-close", + "markdownDescription": "Denies the webview_close command without any pre-configured scope." + }, + { + "description": "Denies the webview_hide command without any pre-configured scope.", + "type": "string", + "const": "core:webview:deny-webview-hide", + "markdownDescription": "Denies the webview_hide command without any pre-configured scope." + }, + { + "description": "Denies the webview_position command without any pre-configured scope.", + "type": "string", + "const": "core:webview:deny-webview-position", + "markdownDescription": "Denies the webview_position command without any pre-configured scope." + }, + { + "description": "Denies the webview_show command without any pre-configured scope.", + "type": "string", + "const": "core:webview:deny-webview-show", + "markdownDescription": "Denies the webview_show command without any pre-configured scope." + }, + { + "description": "Denies the webview_size command without any pre-configured scope.", + "type": "string", + "const": "core:webview:deny-webview-size", + "markdownDescription": "Denies the webview_size command without any pre-configured scope." + }, + { + "description": "Default permissions for the plugin.\n#### This default permission set includes:\n\n- `allow-get-all-windows`\n- `allow-scale-factor`\n- `allow-inner-position`\n- `allow-outer-position`\n- `allow-inner-size`\n- `allow-outer-size`\n- `allow-is-fullscreen`\n- `allow-is-minimized`\n- `allow-is-maximized`\n- `allow-is-focused`\n- `allow-is-decorated`\n- `allow-is-resizable`\n- `allow-is-maximizable`\n- `allow-is-minimizable`\n- `allow-is-closable`\n- `allow-is-visible`\n- `allow-is-enabled`\n- `allow-title`\n- `allow-current-monitor`\n- `allow-primary-monitor`\n- `allow-monitor-from-point`\n- `allow-available-monitors`\n- `allow-cursor-position`\n- `allow-theme`\n- `allow-is-always-on-top`\n- `allow-internal-toggle-maximize`", + "type": "string", + "const": "core:window:default", + "markdownDescription": "Default permissions for the plugin.\n#### This default permission set includes:\n\n- `allow-get-all-windows`\n- `allow-scale-factor`\n- `allow-inner-position`\n- `allow-outer-position`\n- `allow-inner-size`\n- `allow-outer-size`\n- `allow-is-fullscreen`\n- `allow-is-minimized`\n- `allow-is-maximized`\n- `allow-is-focused`\n- `allow-is-decorated`\n- `allow-is-resizable`\n- `allow-is-maximizable`\n- `allow-is-minimizable`\n- `allow-is-closable`\n- `allow-is-visible`\n- `allow-is-enabled`\n- `allow-title`\n- `allow-current-monitor`\n- `allow-primary-monitor`\n- `allow-monitor-from-point`\n- `allow-available-monitors`\n- `allow-cursor-position`\n- `allow-theme`\n- `allow-is-always-on-top`\n- `allow-internal-toggle-maximize`" + }, + { + "description": "Enables the available_monitors command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-available-monitors", + "markdownDescription": "Enables the available_monitors command without any pre-configured scope." + }, + { + "description": "Enables the center command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-center", + "markdownDescription": "Enables the center command without any pre-configured scope." + }, + { + "description": "Enables the close command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-close", + "markdownDescription": "Enables the close command without any pre-configured scope." + }, + { + "description": "Enables the create command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-create", + "markdownDescription": "Enables the create command without any pre-configured scope." + }, + { + "description": "Enables the current_monitor command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-current-monitor", + "markdownDescription": "Enables the current_monitor command without any pre-configured scope." + }, + { + "description": "Enables the cursor_position command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-cursor-position", + "markdownDescription": "Enables the cursor_position command without any pre-configured scope." + }, + { + "description": "Enables the destroy command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-destroy", + "markdownDescription": "Enables the destroy command without any pre-configured scope." + }, + { + "description": "Enables the get_all_windows command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-get-all-windows", + "markdownDescription": "Enables the get_all_windows command without any pre-configured scope." + }, + { + "description": "Enables the hide command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-hide", + "markdownDescription": "Enables the hide command without any pre-configured scope." + }, + { + "description": "Enables the inner_position command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-inner-position", + "markdownDescription": "Enables the inner_position command without any pre-configured scope." + }, + { + "description": "Enables the inner_size command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-inner-size", + "markdownDescription": "Enables the inner_size command without any pre-configured scope." + }, + { + "description": "Enables the internal_toggle_maximize command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-internal-toggle-maximize", + "markdownDescription": "Enables the internal_toggle_maximize command without any pre-configured scope." + }, + { + "description": "Enables the is_always_on_top command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-is-always-on-top", + "markdownDescription": "Enables the is_always_on_top command without any pre-configured scope." + }, + { + "description": "Enables the is_closable command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-is-closable", + "markdownDescription": "Enables the is_closable command without any pre-configured scope." + }, + { + "description": "Enables the is_decorated command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-is-decorated", + "markdownDescription": "Enables the is_decorated command without any pre-configured scope." + }, + { + "description": "Enables the is_enabled command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-is-enabled", + "markdownDescription": "Enables the is_enabled command without any pre-configured scope." + }, + { + "description": "Enables the is_focused command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-is-focused", + "markdownDescription": "Enables the is_focused command without any pre-configured scope." + }, + { + "description": "Enables the is_fullscreen command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-is-fullscreen", + "markdownDescription": "Enables the is_fullscreen command without any pre-configured scope." + }, + { + "description": "Enables the is_maximizable command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-is-maximizable", + "markdownDescription": "Enables the is_maximizable command without any pre-configured scope." + }, + { + "description": "Enables the is_maximized command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-is-maximized", + "markdownDescription": "Enables the is_maximized command without any pre-configured scope." + }, + { + "description": "Enables the is_minimizable command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-is-minimizable", + "markdownDescription": "Enables the is_minimizable command without any pre-configured scope." + }, + { + "description": "Enables the is_minimized command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-is-minimized", + "markdownDescription": "Enables the is_minimized command without any pre-configured scope." + }, + { + "description": "Enables the is_resizable command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-is-resizable", + "markdownDescription": "Enables the is_resizable command without any pre-configured scope." + }, + { + "description": "Enables the is_visible command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-is-visible", + "markdownDescription": "Enables the is_visible command without any pre-configured scope." + }, + { + "description": "Enables the maximize command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-maximize", + "markdownDescription": "Enables the maximize command without any pre-configured scope." + }, + { + "description": "Enables the minimize command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-minimize", + "markdownDescription": "Enables the minimize command without any pre-configured scope." + }, + { + "description": "Enables the monitor_from_point command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-monitor-from-point", + "markdownDescription": "Enables the monitor_from_point command without any pre-configured scope." + }, + { + "description": "Enables the outer_position command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-outer-position", + "markdownDescription": "Enables the outer_position command without any pre-configured scope." + }, + { + "description": "Enables the outer_size command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-outer-size", + "markdownDescription": "Enables the outer_size command without any pre-configured scope." + }, + { + "description": "Enables the primary_monitor command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-primary-monitor", + "markdownDescription": "Enables the primary_monitor command without any pre-configured scope." + }, + { + "description": "Enables the request_user_attention command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-request-user-attention", + "markdownDescription": "Enables the request_user_attention command without any pre-configured scope." + }, + { + "description": "Enables the scale_factor command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-scale-factor", + "markdownDescription": "Enables the scale_factor command without any pre-configured scope." + }, + { + "description": "Enables the set_always_on_bottom command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-set-always-on-bottom", + "markdownDescription": "Enables the set_always_on_bottom command without any pre-configured scope." + }, + { + "description": "Enables the set_always_on_top command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-set-always-on-top", + "markdownDescription": "Enables the set_always_on_top command without any pre-configured scope." + }, + { + "description": "Enables the set_background_color command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-set-background-color", + "markdownDescription": "Enables the set_background_color command without any pre-configured scope." + }, + { + "description": "Enables the set_badge_count command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-set-badge-count", + "markdownDescription": "Enables the set_badge_count command without any pre-configured scope." + }, + { + "description": "Enables the set_badge_label command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-set-badge-label", + "markdownDescription": "Enables the set_badge_label command without any pre-configured scope." + }, + { + "description": "Enables the set_closable command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-set-closable", + "markdownDescription": "Enables the set_closable command without any pre-configured scope." + }, + { + "description": "Enables the set_content_protected command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-set-content-protected", + "markdownDescription": "Enables the set_content_protected command without any pre-configured scope." + }, + { + "description": "Enables the set_cursor_grab command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-set-cursor-grab", + "markdownDescription": "Enables the set_cursor_grab command without any pre-configured scope." + }, + { + "description": "Enables the set_cursor_icon command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-set-cursor-icon", + "markdownDescription": "Enables the set_cursor_icon command without any pre-configured scope." + }, + { + "description": "Enables the set_cursor_position command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-set-cursor-position", + "markdownDescription": "Enables the set_cursor_position command without any pre-configured scope." + }, + { + "description": "Enables the set_cursor_visible command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-set-cursor-visible", + "markdownDescription": "Enables the set_cursor_visible command without any pre-configured scope." + }, + { + "description": "Enables the set_decorations command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-set-decorations", + "markdownDescription": "Enables the set_decorations command without any pre-configured scope." + }, + { + "description": "Enables the set_effects command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-set-effects", + "markdownDescription": "Enables the set_effects command without any pre-configured scope." + }, + { + "description": "Enables the set_enabled command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-set-enabled", + "markdownDescription": "Enables the set_enabled command without any pre-configured scope." + }, + { + "description": "Enables the set_focus command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-set-focus", + "markdownDescription": "Enables the set_focus command without any pre-configured scope." + }, + { + "description": "Enables the set_focusable command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-set-focusable", + "markdownDescription": "Enables the set_focusable command without any pre-configured scope." + }, + { + "description": "Enables the set_fullscreen command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-set-fullscreen", + "markdownDescription": "Enables the set_fullscreen command without any pre-configured scope." + }, + { + "description": "Enables the set_icon command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-set-icon", + "markdownDescription": "Enables the set_icon command without any pre-configured scope." + }, + { + "description": "Enables the set_ignore_cursor_events command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-set-ignore-cursor-events", + "markdownDescription": "Enables the set_ignore_cursor_events command without any pre-configured scope." + }, + { + "description": "Enables the set_max_size command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-set-max-size", + "markdownDescription": "Enables the set_max_size command without any pre-configured scope." + }, + { + "description": "Enables the set_maximizable command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-set-maximizable", + "markdownDescription": "Enables the set_maximizable command without any pre-configured scope." + }, + { + "description": "Enables the set_min_size command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-set-min-size", + "markdownDescription": "Enables the set_min_size command without any pre-configured scope." + }, + { + "description": "Enables the set_minimizable command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-set-minimizable", + "markdownDescription": "Enables the set_minimizable command without any pre-configured scope." + }, + { + "description": "Enables the set_overlay_icon command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-set-overlay-icon", + "markdownDescription": "Enables the set_overlay_icon command without any pre-configured scope." + }, + { + "description": "Enables the set_position command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-set-position", + "markdownDescription": "Enables the set_position command without any pre-configured scope." + }, + { + "description": "Enables the set_progress_bar command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-set-progress-bar", + "markdownDescription": "Enables the set_progress_bar command without any pre-configured scope." + }, + { + "description": "Enables the set_resizable command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-set-resizable", + "markdownDescription": "Enables the set_resizable command without any pre-configured scope." + }, + { + "description": "Enables the set_shadow command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-set-shadow", + "markdownDescription": "Enables the set_shadow command without any pre-configured scope." + }, + { + "description": "Enables the set_simple_fullscreen command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-set-simple-fullscreen", + "markdownDescription": "Enables the set_simple_fullscreen command without any pre-configured scope." + }, + { + "description": "Enables the set_size command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-set-size", + "markdownDescription": "Enables the set_size command without any pre-configured scope." + }, + { + "description": "Enables the set_size_constraints command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-set-size-constraints", + "markdownDescription": "Enables the set_size_constraints command without any pre-configured scope." + }, + { + "description": "Enables the set_skip_taskbar command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-set-skip-taskbar", + "markdownDescription": "Enables the set_skip_taskbar command without any pre-configured scope." + }, + { + "description": "Enables the set_theme command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-set-theme", + "markdownDescription": "Enables the set_theme command without any pre-configured scope." + }, + { + "description": "Enables the set_title command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-set-title", + "markdownDescription": "Enables the set_title command without any pre-configured scope." + }, + { + "description": "Enables the set_title_bar_style command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-set-title-bar-style", + "markdownDescription": "Enables the set_title_bar_style command without any pre-configured scope." + }, + { + "description": "Enables the set_visible_on_all_workspaces command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-set-visible-on-all-workspaces", + "markdownDescription": "Enables the set_visible_on_all_workspaces command without any pre-configured scope." + }, + { + "description": "Enables the show command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-show", + "markdownDescription": "Enables the show command without any pre-configured scope." + }, + { + "description": "Enables the start_dragging command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-start-dragging", + "markdownDescription": "Enables the start_dragging command without any pre-configured scope." + }, + { + "description": "Enables the start_resize_dragging command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-start-resize-dragging", + "markdownDescription": "Enables the start_resize_dragging command without any pre-configured scope." + }, + { + "description": "Enables the theme command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-theme", + "markdownDescription": "Enables the theme command without any pre-configured scope." + }, + { + "description": "Enables the title command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-title", + "markdownDescription": "Enables the title command without any pre-configured scope." + }, + { + "description": "Enables the toggle_maximize command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-toggle-maximize", + "markdownDescription": "Enables the toggle_maximize command without any pre-configured scope." + }, + { + "description": "Enables the unmaximize command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-unmaximize", + "markdownDescription": "Enables the unmaximize command without any pre-configured scope." + }, + { + "description": "Enables the unminimize command without any pre-configured scope.", + "type": "string", + "const": "core:window:allow-unminimize", + "markdownDescription": "Enables the unminimize command without any pre-configured scope." + }, + { + "description": "Denies the available_monitors command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-available-monitors", + "markdownDescription": "Denies the available_monitors command without any pre-configured scope." + }, + { + "description": "Denies the center command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-center", + "markdownDescription": "Denies the center command without any pre-configured scope." + }, + { + "description": "Denies the close command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-close", + "markdownDescription": "Denies the close command without any pre-configured scope." + }, + { + "description": "Denies the create command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-create", + "markdownDescription": "Denies the create command without any pre-configured scope." + }, + { + "description": "Denies the current_monitor command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-current-monitor", + "markdownDescription": "Denies the current_monitor command without any pre-configured scope." + }, + { + "description": "Denies the cursor_position command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-cursor-position", + "markdownDescription": "Denies the cursor_position command without any pre-configured scope." + }, + { + "description": "Denies the destroy command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-destroy", + "markdownDescription": "Denies the destroy command without any pre-configured scope." + }, + { + "description": "Denies the get_all_windows command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-get-all-windows", + "markdownDescription": "Denies the get_all_windows command without any pre-configured scope." + }, + { + "description": "Denies the hide command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-hide", + "markdownDescription": "Denies the hide command without any pre-configured scope." + }, + { + "description": "Denies the inner_position command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-inner-position", + "markdownDescription": "Denies the inner_position command without any pre-configured scope." + }, + { + "description": "Denies the inner_size command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-inner-size", + "markdownDescription": "Denies the inner_size command without any pre-configured scope." + }, + { + "description": "Denies the internal_toggle_maximize command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-internal-toggle-maximize", + "markdownDescription": "Denies the internal_toggle_maximize command without any pre-configured scope." + }, + { + "description": "Denies the is_always_on_top command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-is-always-on-top", + "markdownDescription": "Denies the is_always_on_top command without any pre-configured scope." + }, + { + "description": "Denies the is_closable command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-is-closable", + "markdownDescription": "Denies the is_closable command without any pre-configured scope." + }, + { + "description": "Denies the is_decorated command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-is-decorated", + "markdownDescription": "Denies the is_decorated command without any pre-configured scope." + }, + { + "description": "Denies the is_enabled command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-is-enabled", + "markdownDescription": "Denies the is_enabled command without any pre-configured scope." + }, + { + "description": "Denies the is_focused command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-is-focused", + "markdownDescription": "Denies the is_focused command without any pre-configured scope." + }, + { + "description": "Denies the is_fullscreen command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-is-fullscreen", + "markdownDescription": "Denies the is_fullscreen command without any pre-configured scope." + }, + { + "description": "Denies the is_maximizable command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-is-maximizable", + "markdownDescription": "Denies the is_maximizable command without any pre-configured scope." + }, + { + "description": "Denies the is_maximized command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-is-maximized", + "markdownDescription": "Denies the is_maximized command without any pre-configured scope." + }, + { + "description": "Denies the is_minimizable command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-is-minimizable", + "markdownDescription": "Denies the is_minimizable command without any pre-configured scope." + }, + { + "description": "Denies the is_minimized command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-is-minimized", + "markdownDescription": "Denies the is_minimized command without any pre-configured scope." + }, + { + "description": "Denies the is_resizable command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-is-resizable", + "markdownDescription": "Denies the is_resizable command without any pre-configured scope." + }, + { + "description": "Denies the is_visible command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-is-visible", + "markdownDescription": "Denies the is_visible command without any pre-configured scope." + }, + { + "description": "Denies the maximize command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-maximize", + "markdownDescription": "Denies the maximize command without any pre-configured scope." + }, + { + "description": "Denies the minimize command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-minimize", + "markdownDescription": "Denies the minimize command without any pre-configured scope." + }, + { + "description": "Denies the monitor_from_point command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-monitor-from-point", + "markdownDescription": "Denies the monitor_from_point command without any pre-configured scope." + }, + { + "description": "Denies the outer_position command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-outer-position", + "markdownDescription": "Denies the outer_position command without any pre-configured scope." + }, + { + "description": "Denies the outer_size command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-outer-size", + "markdownDescription": "Denies the outer_size command without any pre-configured scope." + }, + { + "description": "Denies the primary_monitor command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-primary-monitor", + "markdownDescription": "Denies the primary_monitor command without any pre-configured scope." + }, + { + "description": "Denies the request_user_attention command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-request-user-attention", + "markdownDescription": "Denies the request_user_attention command without any pre-configured scope." + }, + { + "description": "Denies the scale_factor command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-scale-factor", + "markdownDescription": "Denies the scale_factor command without any pre-configured scope." + }, + { + "description": "Denies the set_always_on_bottom command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-set-always-on-bottom", + "markdownDescription": "Denies the set_always_on_bottom command without any pre-configured scope." + }, + { + "description": "Denies the set_always_on_top command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-set-always-on-top", + "markdownDescription": "Denies the set_always_on_top command without any pre-configured scope." + }, + { + "description": "Denies the set_background_color command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-set-background-color", + "markdownDescription": "Denies the set_background_color command without any pre-configured scope." + }, + { + "description": "Denies the set_badge_count command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-set-badge-count", + "markdownDescription": "Denies the set_badge_count command without any pre-configured scope." + }, + { + "description": "Denies the set_badge_label command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-set-badge-label", + "markdownDescription": "Denies the set_badge_label command without any pre-configured scope." + }, + { + "description": "Denies the set_closable command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-set-closable", + "markdownDescription": "Denies the set_closable command without any pre-configured scope." + }, + { + "description": "Denies the set_content_protected command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-set-content-protected", + "markdownDescription": "Denies the set_content_protected command without any pre-configured scope." + }, + { + "description": "Denies the set_cursor_grab command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-set-cursor-grab", + "markdownDescription": "Denies the set_cursor_grab command without any pre-configured scope." + }, + { + "description": "Denies the set_cursor_icon command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-set-cursor-icon", + "markdownDescription": "Denies the set_cursor_icon command without any pre-configured scope." + }, + { + "description": "Denies the set_cursor_position command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-set-cursor-position", + "markdownDescription": "Denies the set_cursor_position command without any pre-configured scope." + }, + { + "description": "Denies the set_cursor_visible command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-set-cursor-visible", + "markdownDescription": "Denies the set_cursor_visible command without any pre-configured scope." + }, + { + "description": "Denies the set_decorations command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-set-decorations", + "markdownDescription": "Denies the set_decorations command without any pre-configured scope." + }, + { + "description": "Denies the set_effects command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-set-effects", + "markdownDescription": "Denies the set_effects command without any pre-configured scope." + }, + { + "description": "Denies the set_enabled command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-set-enabled", + "markdownDescription": "Denies the set_enabled command without any pre-configured scope." + }, + { + "description": "Denies the set_focus command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-set-focus", + "markdownDescription": "Denies the set_focus command without any pre-configured scope." + }, + { + "description": "Denies the set_focusable command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-set-focusable", + "markdownDescription": "Denies the set_focusable command without any pre-configured scope." + }, + { + "description": "Denies the set_fullscreen command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-set-fullscreen", + "markdownDescription": "Denies the set_fullscreen command without any pre-configured scope." + }, + { + "description": "Denies the set_icon command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-set-icon", + "markdownDescription": "Denies the set_icon command without any pre-configured scope." + }, + { + "description": "Denies the set_ignore_cursor_events command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-set-ignore-cursor-events", + "markdownDescription": "Denies the set_ignore_cursor_events command without any pre-configured scope." + }, + { + "description": "Denies the set_max_size command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-set-max-size", + "markdownDescription": "Denies the set_max_size command without any pre-configured scope." + }, + { + "description": "Denies the set_maximizable command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-set-maximizable", + "markdownDescription": "Denies the set_maximizable command without any pre-configured scope." + }, + { + "description": "Denies the set_min_size command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-set-min-size", + "markdownDescription": "Denies the set_min_size command without any pre-configured scope." + }, + { + "description": "Denies the set_minimizable command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-set-minimizable", + "markdownDescription": "Denies the set_minimizable command without any pre-configured scope." + }, + { + "description": "Denies the set_overlay_icon command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-set-overlay-icon", + "markdownDescription": "Denies the set_overlay_icon command without any pre-configured scope." + }, + { + "description": "Denies the set_position command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-set-position", + "markdownDescription": "Denies the set_position command without any pre-configured scope." + }, + { + "description": "Denies the set_progress_bar command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-set-progress-bar", + "markdownDescription": "Denies the set_progress_bar command without any pre-configured scope." + }, + { + "description": "Denies the set_resizable command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-set-resizable", + "markdownDescription": "Denies the set_resizable command without any pre-configured scope." + }, + { + "description": "Denies the set_shadow command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-set-shadow", + "markdownDescription": "Denies the set_shadow command without any pre-configured scope." + }, + { + "description": "Denies the set_simple_fullscreen command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-set-simple-fullscreen", + "markdownDescription": "Denies the set_simple_fullscreen command without any pre-configured scope." + }, + { + "description": "Denies the set_size command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-set-size", + "markdownDescription": "Denies the set_size command without any pre-configured scope." + }, + { + "description": "Denies the set_size_constraints command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-set-size-constraints", + "markdownDescription": "Denies the set_size_constraints command without any pre-configured scope." + }, + { + "description": "Denies the set_skip_taskbar command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-set-skip-taskbar", + "markdownDescription": "Denies the set_skip_taskbar command without any pre-configured scope." + }, + { + "description": "Denies the set_theme command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-set-theme", + "markdownDescription": "Denies the set_theme command without any pre-configured scope." + }, + { + "description": "Denies the set_title command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-set-title", + "markdownDescription": "Denies the set_title command without any pre-configured scope." + }, + { + "description": "Denies the set_title_bar_style command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-set-title-bar-style", + "markdownDescription": "Denies the set_title_bar_style command without any pre-configured scope." + }, + { + "description": "Denies the set_visible_on_all_workspaces command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-set-visible-on-all-workspaces", + "markdownDescription": "Denies the set_visible_on_all_workspaces command without any pre-configured scope." + }, + { + "description": "Denies the show command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-show", + "markdownDescription": "Denies the show command without any pre-configured scope." + }, + { + "description": "Denies the start_dragging command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-start-dragging", + "markdownDescription": "Denies the start_dragging command without any pre-configured scope." + }, + { + "description": "Denies the start_resize_dragging command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-start-resize-dragging", + "markdownDescription": "Denies the start_resize_dragging command without any pre-configured scope." + }, + { + "description": "Denies the theme command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-theme", + "markdownDescription": "Denies the theme command without any pre-configured scope." + }, + { + "description": "Denies the title command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-title", + "markdownDescription": "Denies the title command without any pre-configured scope." + }, + { + "description": "Denies the toggle_maximize command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-toggle-maximize", + "markdownDescription": "Denies the toggle_maximize command without any pre-configured scope." + }, + { + "description": "Denies the unmaximize command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-unmaximize", + "markdownDescription": "Denies the unmaximize command without any pre-configured scope." + }, + { + "description": "Denies the unminimize command without any pre-configured scope.", + "type": "string", + "const": "core:window:deny-unminimize", + "markdownDescription": "Denies the unminimize command without any pre-configured scope." + }, + { + "description": "This permission set configures the types of dialogs\navailable from the dialog plugin.\n\n#### Granted Permissions\n\nAll dialog types are enabled.\n\n\n\n#### This default permission set includes:\n\n- `allow-ask`\n- `allow-confirm`\n- `allow-message`\n- `allow-save`\n- `allow-open`", + "type": "string", + "const": "dialog:default", + "markdownDescription": "This permission set configures the types of dialogs\navailable from the dialog plugin.\n\n#### Granted Permissions\n\nAll dialog types are enabled.\n\n\n\n#### This default permission set includes:\n\n- `allow-ask`\n- `allow-confirm`\n- `allow-message`\n- `allow-save`\n- `allow-open`" + }, + { + "description": "Enables the ask command without any pre-configured scope.", + "type": "string", + "const": "dialog:allow-ask", + "markdownDescription": "Enables the ask command without any pre-configured scope." + }, + { + "description": "Enables the confirm command without any pre-configured scope.", + "type": "string", + "const": "dialog:allow-confirm", + "markdownDescription": "Enables the confirm command without any pre-configured scope." + }, + { + "description": "Enables the message command without any pre-configured scope.", + "type": "string", + "const": "dialog:allow-message", + "markdownDescription": "Enables the message command without any pre-configured scope." + }, + { + "description": "Enables the open command without any pre-configured scope.", + "type": "string", + "const": "dialog:allow-open", + "markdownDescription": "Enables the open command without any pre-configured scope." + }, + { + "description": "Enables the save command without any pre-configured scope.", + "type": "string", + "const": "dialog:allow-save", + "markdownDescription": "Enables the save command without any pre-configured scope." + }, + { + "description": "Denies the ask command without any pre-configured scope.", + "type": "string", + "const": "dialog:deny-ask", + "markdownDescription": "Denies the ask command without any pre-configured scope." + }, + { + "description": "Denies the confirm command without any pre-configured scope.", + "type": "string", + "const": "dialog:deny-confirm", + "markdownDescription": "Denies the confirm command without any pre-configured scope." + }, + { + "description": "Denies the message command without any pre-configured scope.", + "type": "string", + "const": "dialog:deny-message", + "markdownDescription": "Denies the message command without any pre-configured scope." + }, + { + "description": "Denies the open command without any pre-configured scope.", + "type": "string", + "const": "dialog:deny-open", + "markdownDescription": "Denies the open command without any pre-configured scope." + }, + { + "description": "Denies the save command without any pre-configured scope.", + "type": "string", + "const": "dialog:deny-save", + "markdownDescription": "Denies the save command without any pre-configured scope." + }, + { + "description": "No features are enabled by default, as we believe\nthe shortcuts can be inherently dangerous and it is\napplication specific if specific shortcuts should be\nregistered or unregistered.\n", + "type": "string", + "const": "global-shortcut:default", + "markdownDescription": "No features are enabled by default, as we believe\nthe shortcuts can be inherently dangerous and it is\napplication specific if specific shortcuts should be\nregistered or unregistered.\n" + }, + { + "description": "Enables the is_registered command without any pre-configured scope.", + "type": "string", + "const": "global-shortcut:allow-is-registered", + "markdownDescription": "Enables the is_registered command without any pre-configured scope." + }, + { + "description": "Enables the register command without any pre-configured scope.", + "type": "string", + "const": "global-shortcut:allow-register", + "markdownDescription": "Enables the register command without any pre-configured scope." + }, + { + "description": "Enables the register_all command without any pre-configured scope.", + "type": "string", + "const": "global-shortcut:allow-register-all", + "markdownDescription": "Enables the register_all command without any pre-configured scope." + }, + { + "description": "Enables the unregister command without any pre-configured scope.", + "type": "string", + "const": "global-shortcut:allow-unregister", + "markdownDescription": "Enables the unregister command without any pre-configured scope." + }, + { + "description": "Enables the unregister_all command without any pre-configured scope.", + "type": "string", + "const": "global-shortcut:allow-unregister-all", + "markdownDescription": "Enables the unregister_all command without any pre-configured scope." + }, + { + "description": "Denies the is_registered command without any pre-configured scope.", + "type": "string", + "const": "global-shortcut:deny-is-registered", + "markdownDescription": "Denies the is_registered command without any pre-configured scope." + }, + { + "description": "Denies the register command without any pre-configured scope.", + "type": "string", + "const": "global-shortcut:deny-register", + "markdownDescription": "Denies the register command without any pre-configured scope." + }, + { + "description": "Denies the register_all command without any pre-configured scope.", + "type": "string", + "const": "global-shortcut:deny-register-all", + "markdownDescription": "Denies the register_all command without any pre-configured scope." + }, + { + "description": "Denies the unregister command without any pre-configured scope.", + "type": "string", + "const": "global-shortcut:deny-unregister", + "markdownDescription": "Denies the unregister command without any pre-configured scope." + }, + { + "description": "Denies the unregister_all command without any pre-configured scope.", + "type": "string", + "const": "global-shortcut:deny-unregister-all", + "markdownDescription": "Denies the unregister_all command without any pre-configured scope." + }, + { + "description": "This permission set configures what kind of\noperations are available from the mcp plugin.\n\n#### Granted Permissions\n\nAll operations are enabled by default.\n\n#### This default permission set includes:\n\n- `allow-connect-server`\n- `allow-disconnect-server`\n- `allow-list-tools`\n- `allow-call-tool`", + "type": "string", + "const": "mcp:default", + "markdownDescription": "This permission set configures what kind of\noperations are available from the mcp plugin.\n\n#### Granted Permissions\n\nAll operations are enabled by default.\n\n#### This default permission set includes:\n\n- `allow-connect-server`\n- `allow-disconnect-server`\n- `allow-list-tools`\n- `allow-call-tool`" + }, + { + "description": "Enables the call_tool command without any pre-configured scope.", + "type": "string", + "const": "mcp:allow-call-tool", + "markdownDescription": "Enables the call_tool command without any pre-configured scope." + }, + { + "description": "Enables the connect_server command without any pre-configured scope.", + "type": "string", + "const": "mcp:allow-connect-server", + "markdownDescription": "Enables the connect_server command without any pre-configured scope." + }, + { + "description": "Enables the disconnect_server command without any pre-configured scope.", + "type": "string", + "const": "mcp:allow-disconnect-server", + "markdownDescription": "Enables the disconnect_server command without any pre-configured scope." + }, + { + "description": "Enables the list_tools command without any pre-configured scope.", + "type": "string", + "const": "mcp:allow-list-tools", + "markdownDescription": "Enables the list_tools command without any pre-configured scope." + }, + { + "description": "Denies the call_tool command without any pre-configured scope.", + "type": "string", + "const": "mcp:deny-call-tool", + "markdownDescription": "Denies the call_tool command without any pre-configured scope." + }, + { + "description": "Denies the connect_server command without any pre-configured scope.", + "type": "string", + "const": "mcp:deny-connect-server", + "markdownDescription": "Denies the connect_server command without any pre-configured scope." + }, + { + "description": "Denies the disconnect_server command without any pre-configured scope.", + "type": "string", + "const": "mcp:deny-disconnect-server", + "markdownDescription": "Denies the disconnect_server command without any pre-configured scope." + }, + { + "description": "Denies the list_tools command without any pre-configured scope.", + "type": "string", + "const": "mcp:deny-list-tools", + "markdownDescription": "Denies the list_tools command without any pre-configured scope." + }, + { + "description": "This permission set allows opening `mailto:`, `tel:`, `https://` and `http://` urls using their default application\nas well as reveal file in directories using default file explorer\n#### This default permission set includes:\n\n- `allow-open-url`\n- `allow-reveal-item-in-dir`\n- `allow-default-urls`", + "type": "string", + "const": "opener:default", + "markdownDescription": "This permission set allows opening `mailto:`, `tel:`, `https://` and `http://` urls using their default application\nas well as reveal file in directories using default file explorer\n#### This default permission set includes:\n\n- `allow-open-url`\n- `allow-reveal-item-in-dir`\n- `allow-default-urls`" + }, + { + "description": "This enables opening `mailto:`, `tel:`, `https://` and `http://` urls using their default application.", + "type": "string", + "const": "opener:allow-default-urls", + "markdownDescription": "This enables opening `mailto:`, `tel:`, `https://` and `http://` urls using their default application." + }, + { + "description": "Enables the open_path command without any pre-configured scope.", + "type": "string", + "const": "opener:allow-open-path", + "markdownDescription": "Enables the open_path command without any pre-configured scope." + }, + { + "description": "Enables the open_url command without any pre-configured scope.", + "type": "string", + "const": "opener:allow-open-url", + "markdownDescription": "Enables the open_url command without any pre-configured scope." + }, + { + "description": "Enables the reveal_item_in_dir command without any pre-configured scope.", + "type": "string", + "const": "opener:allow-reveal-item-in-dir", + "markdownDescription": "Enables the reveal_item_in_dir command without any pre-configured scope." + }, + { + "description": "Denies the open_path command without any pre-configured scope.", + "type": "string", + "const": "opener:deny-open-path", + "markdownDescription": "Denies the open_path command without any pre-configured scope." + }, + { + "description": "Denies the open_url command without any pre-configured scope.", + "type": "string", + "const": "opener:deny-open-url", + "markdownDescription": "Denies the open_url command without any pre-configured scope." + }, + { + "description": "Denies the reveal_item_in_dir command without any pre-configured scope.", + "type": "string", + "const": "opener:deny-reveal-item-in-dir", + "markdownDescription": "Denies the reveal_item_in_dir command without any pre-configured scope." + } + ] + }, + "Value": { + "description": "All supported ACL values.", + "anyOf": [ + { + "description": "Represents a null JSON value.", + "type": "null" + }, + { + "description": "Represents a [`bool`].", + "type": "boolean" + }, + { + "description": "Represents a valid ACL [`Number`].", + "allOf": [ + { + "$ref": "#/definitions/Number" + } + ] + }, + { + "description": "Represents a [`String`].", + "type": "string" + }, + { + "description": "Represents a list of other [`Value`]s.", + "type": "array", + "items": { + "$ref": "#/definitions/Value" + } + }, + { + "description": "Represents a map of [`String`] keys to [`Value`]s.", + "type": "object", + "additionalProperties": { + "$ref": "#/definitions/Value" + } + } + ] + }, + "Number": { + "description": "A valid ACL number.", + "anyOf": [ + { + "description": "Represents an [`i64`].", + "type": "integer", + "format": "int64" + }, + { + "description": "Represents a [`f64`].", + "type": "number", + "format": "double" + } + ] + }, + "Target": { + "description": "Platform target.", + "oneOf": [ + { + "description": "MacOS.", + "type": "string", + "enum": [ + "macOS" + ] + }, + { + "description": "Windows.", + "type": "string", + "enum": [ + "windows" + ] + }, + { + "description": "Linux.", + "type": "string", + "enum": [ + "linux" + ] + }, + { + "description": "Android.", + "type": "string", + "enum": [ + "android" + ] + }, + { + "description": "iOS.", + "type": "string", + "enum": [ + "iOS" + ] + } + ] + }, + "Application": { + "description": "Opener scope application.", + "anyOf": [ + { + "description": "Open in default application.", + "type": "null" + }, + { + "description": "If true, allow open with any application.", + "type": "boolean" + }, + { + "description": "Allow specific application to open with.", + "type": "string" + } + ] + } + } +} \ No newline at end of file diff --git a/src-tauri/icons/128x128.png b/src-tauri/icons/128x128.png new file mode 100644 index 0000000..6be5e50 Binary files /dev/null and b/src-tauri/icons/128x128.png differ diff --git a/src-tauri/icons/128x128@2x.png b/src-tauri/icons/128x128@2x.png new file mode 100644 index 0000000..e81bece Binary files /dev/null and b/src-tauri/icons/128x128@2x.png differ diff --git a/src-tauri/icons/32x32.png b/src-tauri/icons/32x32.png new file mode 100644 index 0000000..a437dd5 Binary files /dev/null and b/src-tauri/icons/32x32.png differ diff --git a/src-tauri/icons/Square107x107Logo.png b/src-tauri/icons/Square107x107Logo.png new file mode 100644 index 0000000..0ca4f27 Binary files /dev/null and b/src-tauri/icons/Square107x107Logo.png differ diff --git a/src-tauri/icons/Square142x142Logo.png b/src-tauri/icons/Square142x142Logo.png new file mode 100644 index 0000000..b81f820 Binary files /dev/null and b/src-tauri/icons/Square142x142Logo.png differ diff --git a/src-tauri/icons/Square150x150Logo.png b/src-tauri/icons/Square150x150Logo.png new file mode 100644 index 0000000..624c7bf Binary files /dev/null and b/src-tauri/icons/Square150x150Logo.png differ diff --git a/src-tauri/icons/Square284x284Logo.png b/src-tauri/icons/Square284x284Logo.png new file mode 100644 index 0000000..c021d2b Binary files /dev/null and b/src-tauri/icons/Square284x284Logo.png differ diff --git a/src-tauri/icons/Square30x30Logo.png b/src-tauri/icons/Square30x30Logo.png new file mode 100644 index 0000000..6219700 Binary files /dev/null and b/src-tauri/icons/Square30x30Logo.png differ diff --git a/src-tauri/icons/Square310x310Logo.png b/src-tauri/icons/Square310x310Logo.png new file mode 100644 index 0000000..f9bc048 Binary files /dev/null and b/src-tauri/icons/Square310x310Logo.png differ diff --git a/src-tauri/icons/Square44x44Logo.png b/src-tauri/icons/Square44x44Logo.png new file mode 100644 index 0000000..d5fbfb2 Binary files /dev/null and b/src-tauri/icons/Square44x44Logo.png differ diff --git a/src-tauri/icons/Square71x71Logo.png b/src-tauri/icons/Square71x71Logo.png new file mode 100644 index 0000000..63440d7 Binary files /dev/null and b/src-tauri/icons/Square71x71Logo.png differ diff --git a/src-tauri/icons/Square89x89Logo.png b/src-tauri/icons/Square89x89Logo.png new file mode 100644 index 0000000..f3f705a Binary files /dev/null and b/src-tauri/icons/Square89x89Logo.png differ diff --git a/src-tauri/icons/StoreLogo.png b/src-tauri/icons/StoreLogo.png new file mode 100644 index 0000000..4556388 Binary files /dev/null and b/src-tauri/icons/StoreLogo.png differ diff --git a/src-tauri/icons/icon.icns b/src-tauri/icons/icon.icns new file mode 100644 index 0000000..12a5bce Binary files /dev/null and b/src-tauri/icons/icon.icns differ diff --git a/src-tauri/icons/icon.ico b/src-tauri/icons/icon.ico new file mode 100644 index 0000000..b3636e4 Binary files /dev/null and b/src-tauri/icons/icon.ico differ diff --git a/src-tauri/icons/icon.png b/src-tauri/icons/icon.png new file mode 100644 index 0000000..e1cd261 Binary files /dev/null and b/src-tauri/icons/icon.png differ diff --git a/src-tauri/src/commands/audio.rs b/src-tauri/src/commands/audio.rs new file mode 100644 index 0000000..51d72d6 --- /dev/null +++ b/src-tauri/src/commands/audio.rs @@ -0,0 +1,49 @@ +use std::path::PathBuf; + +use tauri::Manager; + +use kon_core::types::AudioSamples; + +/// Save PCM f32 samples as a WAV file. Returns the file path. +#[tauri::command] +pub async fn save_audio( + app: tauri::AppHandle, + samples: Vec, + output_folder: Option, +) -> Result { + let recordings_dir = if let Some(ref folder) = output_folder { + if !folder.is_empty() { + PathBuf::from(folder) + } else { + app.path() + .app_local_data_dir() + .map_err(|e: tauri::Error| e.to_string())? + .join("recordings") + } + } else { + app.path() + .app_local_data_dir() + .map_err(|e: tauri::Error| e.to_string())? + .join("recordings") + }; + + std::fs::create_dir_all(&recordings_dir) + .map_err(|e| format!("Failed to create recordings dir: {e}"))?; + + let timestamp = std::time::SystemTime::now() + .duration_since(std::time::UNIX_EPOCH) + .unwrap_or_default() + .as_secs(); + let filename = format!("kon-{timestamp}.wav"); + let path = recordings_dir.join(&filename); + let path_clone = path.clone(); + + tokio::task::spawn_blocking(move || { + let audio = AudioSamples::mono_16khz(samples); + kon_audio::write_wav(&path_clone, &audio).map_err(|e| e.to_string()) + }) + .await + .map_err(|e| e.to_string())??; + + Ok(path.to_string_lossy().to_string()) +} diff --git a/src-tauri/src/commands/clipboard.rs b/src-tauri/src/commands/clipboard.rs new file mode 100644 index 0000000..fe9e39d --- /dev/null +++ b/src-tauri/src/commands/clipboard.rs @@ -0,0 +1,12 @@ +use arboard::Clipboard; + +/// Copy text to the system clipboard via arboard. +#[tauri::command] +pub fn copy_to_clipboard(text: String) -> Result<(), String> { + let mut clipboard = + Clipboard::new().map_err(|e| format!("Clipboard init failed: {e}"))?; + clipboard + .set_text(&text) + .map_err(|e| format!("Clipboard write failed: {e}"))?; + Ok(()) +} diff --git a/src-tauri/src/commands/hardware.rs b/src-tauri/src/commands/hardware.rs new file mode 100644 index 0000000..7c0d7a7 --- /dev/null +++ b/src-tauri/src/commands/hardware.rs @@ -0,0 +1,69 @@ +use serde::Serialize; + +use kon_core::hardware::{self, Os}; +use kon_core::recommendation; + +#[derive(Serialize)] +pub struct SystemInfo { + pub ram_mb: u64, + pub cpu_brand: String, + pub cpu_cores: usize, + pub os: String, + pub gpu: Option, +} + +#[derive(Serialize)] +pub struct ModelRecommendation { + pub id: String, + pub display_name: &'static str, + pub disk_size_mb: u64, + pub ram_required_mb: u64, + pub description: &'static str, + pub score: f64, + pub reason: String, + pub is_downloaded: bool, +} + +/// Probe system hardware and return a summary. +#[tauri::command] +pub fn probe_system() -> Result { + let profile = hardware::probe_system(); + Ok(SystemInfo { + ram_mb: profile.ram.0, + cpu_brand: profile.cpu.brand, + cpu_cores: profile.cpu.logical_processors, + os: match profile.os { + Os::Windows => "Windows", + Os::Linux => "Linux", + Os::MacOs => "macOS", + Os::Ios => "iOS", + Os::Android => "Android", + } + .to_string(), + gpu: profile.gpu.map(|g| format!("{:?}", g.vendor)), + }) +} + +/// Rank models for the current system and return recommendations. +#[tauri::command] +pub fn rank_models() -> Result, String> { + let profile = hardware::probe_system(); + let ranked = recommendation::rank_recommendations(&profile); + + Ok(ranked + .into_iter() + .map(|scored| { + let downloaded = kon_transcription::is_downloaded(&scored.entry.id); + ModelRecommendation { + id: scored.entry.id.as_str().to_string(), + display_name: scored.entry.display_name, + disk_size_mb: scored.entry.disk_size.0, + ram_required_mb: scored.entry.ram_required.0, + description: scored.entry.description, + score: scored.score, + reason: scored.reason, + is_downloaded: downloaded, + } + }) + .collect()) +} diff --git a/src-tauri/src/commands/mod.rs b/src-tauri/src/commands/mod.rs new file mode 100644 index 0000000..d8b9d73 --- /dev/null +++ b/src-tauri/src/commands/mod.rs @@ -0,0 +1,6 @@ +pub mod audio; +pub mod clipboard; +pub mod hardware; +pub mod models; +pub mod transcription; +pub mod windows; diff --git a/src-tauri/src/commands/models.rs b/src-tauri/src/commands/models.rs new file mode 100644 index 0000000..bcde847 --- /dev/null +++ b/src-tauri/src/commands/models.rs @@ -0,0 +1,174 @@ +use tauri::Emitter; + +use crate::AppState; +use kon_core::types::ModelId; +use kon_transcription::model_manager; + +/// Map legacy size strings to ModelId. +fn whisper_model_id(size: &str) -> ModelId { + match size.to_lowercase().as_str() { + "tiny" => ModelId::new("whisper-tiny-en"), + "base" => ModelId::new("whisper-base-en"), + "small" => ModelId::new("whisper-small-en"), + "medium" => ModelId::new("whisper-medium-en"), + other => ModelId::new(other), + } +} + +fn parakeet_model_id(name: &str) -> ModelId { + match name { + "ctc-int8" => ModelId::new("parakeet-ctc-0.6b-int8"), + other => ModelId::new(other), + } +} + +// --- Whisper model commands --- + +#[tauri::command] +pub async fn download_model( + app: tauri::AppHandle, + size: String, +) -> Result { + let id = whisper_model_id(&size); + let app_clone = app.clone(); + model_manager::download(&id, move |progress| { + let _ = app_clone.emit("model-download-progress", &progress); + }) + .await + .map_err(|e| e.to_string())?; + Ok(format!("Model {} downloaded", size)) +} + +#[tauri::command] +pub fn check_model(size: String) -> Result { + let id = whisper_model_id(&size); + Ok(model_manager::is_downloaded(&id)) +} + +#[tauri::command] +pub fn list_models() -> Result, String> { + let ids = model_manager::list_downloaded(); + Ok(ids + .into_iter() + .filter(|id| id.as_str().starts_with("whisper-")) + .map(|id| { + match id.as_str() { + "whisper-tiny-en" => "Tiny".to_string(), + "whisper-base-en" => "Base".to_string(), + "whisper-small-en" => "Small".to_string(), + "whisper-medium-en" => "Medium".to_string(), + other => other.to_string(), + } + }) + .collect()) +} + +#[tauri::command] +pub async fn load_model( + state: tauri::State<'_, AppState>, + size: String, +) -> Result { + let id = whisper_model_id(&size); + let dir = model_manager::model_dir(&id); + let model_file = dir.join( + kon_core::model_registry::find_model(&id) + .ok_or_else(|| format!("Unknown model: {size}"))? + .files + .first() + .ok_or_else(|| format!("No files for model: {size}"))? + .filename, + ); + + if !model_file.exists() { + return Err(format!("Model not downloaded: {size}")); + } + + let engine = state.whisper_engine.clone(); + let mid = id.clone(); + tokio::task::spawn_blocking(move || { + let model = kon_transcription::load_whisper(&model_file) + .map_err(|e| e.to_string())?; + engine.load(model, mid); + Ok::<_, String>(()) + }) + .await + .map_err(|e| e.to_string())??; + + Ok(format!("Model {} loaded", size)) +} + +#[tauri::command] +pub fn check_engine(state: tauri::State) -> Result { + Ok(state.whisper_engine.is_loaded()) +} + +// --- Parakeet model commands --- + +#[tauri::command] +pub async fn download_parakeet_model( + app: tauri::AppHandle, + name: String, +) -> Result { + let id = parakeet_model_id(&name); + let app_clone = app.clone(); + model_manager::download(&id, move |progress| { + let _ = app_clone.emit("parakeet-download-progress", &progress); + }) + .await + .map_err(|e| e.to_string())?; + Ok(format!("Parakeet model {} downloaded", name)) +} + +#[tauri::command] +pub fn check_parakeet_model(name: String) -> Result { + let id = parakeet_model_id(&name); + Ok(model_manager::is_downloaded(&id)) +} + +#[tauri::command] +pub fn list_parakeet_models() -> Result, String> { + let ids = model_manager::list_downloaded(); + Ok(ids + .into_iter() + .filter(|id| id.as_str().starts_with("parakeet-")) + .map(|id| { + match id.as_str() { + "parakeet-ctc-0.6b-int8" => "ctc-int8".to_string(), + other => other.to_string(), + } + }) + .collect()) +} + +#[tauri::command] +pub async fn load_parakeet_model( + state: tauri::State<'_, AppState>, + name: String, +) -> Result { + let id = parakeet_model_id(&name); + let dir = model_manager::model_dir(&id); + + if !dir.exists() { + return Err(format!("Parakeet model not downloaded: {name}")); + } + + let engine = state.parakeet_engine.clone(); + let mid = id.clone(); + tokio::task::spawn_blocking(move || { + let model = kon_transcription::load_parakeet(&dir) + .map_err(|e| e.to_string())?; + engine.load(model, mid); + Ok::<_, String>(()) + }) + .await + .map_err(|e| e.to_string())??; + + Ok(format!("Parakeet model {} loaded", name)) +} + +#[tauri::command] +pub fn check_parakeet_engine( + state: tauri::State, +) -> Result { + Ok(state.parakeet_engine.is_loaded()) +} diff --git a/src-tauri/src/commands/transcription.rs b/src-tauri/src/commands/transcription.rs new file mode 100644 index 0000000..fabd1c7 --- /dev/null +++ b/src-tauri/src/commands/transcription.rs @@ -0,0 +1,163 @@ +// Tauri command handlers must match the frontend's invoke() parameter lists, +// so the argument counts are dictated by the Svelte code. +#![allow(clippy::too_many_arguments)] + +use std::path::Path; + +use tauri::Emitter; + +use crate::AppState; +use kon_ai_formatting::{post_process_segments, FormatMode, PostProcessOptions}; +use kon_core::types::{Segment, TranscriptionOptions}; + +/// Transcribe raw PCM f32 samples (Whisper). Emits "transcription-result" event. +#[tauri::command] +pub async fn transcribe_pcm( + state: tauri::State<'_, AppState>, + app: tauri::AppHandle, + samples: Vec, + chunk_id: u32, + language: String, + initial_prompt: String, + remove_fillers: bool, + british_english: bool, + anti_hallucination: bool, + format_mode: String, +) -> Result<(), String> { + let engine = state.whisper_engine.clone(); + let audio = kon_core::AudioSamples::mono_16khz(samples); + let options = TranscriptionOptions { + language: Some(language), + initial_prompt: Some(initial_prompt), + }; + + let timed = tokio::task::spawn_blocking(move || { + engine.transcribe_sync(&audio, &options).map_err(|e| e.to_string()) + }) + .await + .map_err(|e| e.to_string())??; + + let mut segments: Vec = timed.transcript.segments().to_vec(); + post_process_segments( + &mut segments, + &PostProcessOptions { + remove_fillers, + british_english, + anti_hallucination, + format_mode: FormatMode::parse(&format_mode), + }, + ); + + app.emit( + "transcription-result", + serde_json::json!({ + "status": "transcription", + "segments": segments, + "language": timed.transcript.language(), + "duration": timed.transcript.duration(), + "chunk_id": chunk_id, + "inference_ms": timed.inference_ms, + }), + ) + .map_err(|e| format!("Failed to emit result: {e}"))?; + + Ok(()) +} + +/// Transcribe an audio file by path. Decodes, resamples to 16kHz, runs Whisper. +#[tauri::command] +pub async fn transcribe_file( + state: tauri::State<'_, AppState>, + path: String, + language: String, + initial_prompt: String, + remove_fillers: bool, + british_english: bool, + anti_hallucination: bool, + format_mode: String, +) -> Result { + let engine = state.whisper_engine.clone(); + let options = TranscriptionOptions { + language: Some(language), + initial_prompt: Some(initial_prompt), + }; + + let timed = tokio::task::spawn_blocking(move || { + let audio = kon_audio::decode_audio_file(Path::new(&path)) + .map_err(|e| e.to_string())?; + let resampled = + kon_audio::resample_to_16khz(&audio).map_err(|e| e.to_string())?; + engine + .transcribe_sync(&resampled, &options) + .map_err(|e| e.to_string()) + }) + .await + .map_err(|e| e.to_string())??; + + let mut segments: Vec = timed.transcript.segments().to_vec(); + post_process_segments( + &mut segments, + &PostProcessOptions { + remove_fillers, + british_english, + anti_hallucination, + format_mode: FormatMode::parse(&format_mode), + }, + ); + + Ok(serde_json::json!({ + "segments": segments, + "language": timed.transcript.language(), + "duration": timed.transcript.duration(), + "inference_ms": timed.inference_ms, + })) +} + +/// Transcribe raw PCM f32 samples (Parakeet). Emits "transcription-result" event. +#[tauri::command] +pub async fn transcribe_pcm_parakeet( + state: tauri::State<'_, AppState>, + app: tauri::AppHandle, + samples: Vec, + chunk_id: u32, + remove_fillers: bool, + british_english: bool, + anti_hallucination: bool, + format_mode: String, +) -> Result<(), String> { + let engine = state.parakeet_engine.clone(); + let audio = kon_core::AudioSamples::mono_16khz(samples); + let options = TranscriptionOptions::default(); + + let timed = tokio::task::spawn_blocking(move || { + engine.transcribe_sync(&audio, &options).map_err(|e| e.to_string()) + }) + .await + .map_err(|e| e.to_string())??; + + let mut segments: Vec = timed.transcript.segments().to_vec(); + post_process_segments( + &mut segments, + &PostProcessOptions { + remove_fillers, + british_english, + anti_hallucination, + format_mode: FormatMode::parse(&format_mode), + }, + ); + + app.emit( + "transcription-result", + serde_json::json!({ + "status": "transcription", + "segments": segments, + "language": timed.transcript.language(), + "duration": timed.transcript.duration(), + "chunk_id": chunk_id, + "inference_ms": timed.inference_ms, + }), + ) + .map_err(|e| format!("Failed to emit result: {e}"))?; + + Ok(()) +} diff --git a/src-tauri/src/commands/windows.rs b/src-tauri/src/commands/windows.rs new file mode 100644 index 0000000..234d380 --- /dev/null +++ b/src-tauri/src/commands/windows.rs @@ -0,0 +1,58 @@ +use tauri::{Emitter, Manager, WebviewUrl, WebviewWindowBuilder}; + +/// Open a floating always-on-top task window. +#[tauri::command] +pub async fn open_task_window( + app: tauri::AppHandle, +) -> Result<(), String> { + if let Some(window) = app.get_webview_window("tasks-float") { + window.show().map_err(|e| e.to_string())?; + window.set_focus().map_err(|e| e.to_string())?; + app.emit("task-window-focus", ()) + .map_err(|e| e.to_string())?; + return Ok(()); + } + + WebviewWindowBuilder::new( + &app, + "tasks-float", + WebviewUrl::App("/float".into()), + ) + .title("Kon Tasks") + .inner_size(480.0, 520.0) + .min_inner_size(400.0, 400.0) + .always_on_top(true) + .decorations(false) + .resizable(true) + .build() + .map_err(|e| e.to_string())?; + + Ok(()) +} + +/// Open the transcript viewer window. +#[tauri::command] +pub async fn open_viewer_window( + app: tauri::AppHandle, +) -> Result<(), String> { + if let Some(window) = app.get_webview_window("transcript-viewer") { + window.show().map_err(|e| e.to_string())?; + window.set_focus().map_err(|e| e.to_string())?; + return Ok(()); + } + + WebviewWindowBuilder::new( + &app, + "transcript-viewer", + WebviewUrl::App("/viewer".into()), + ) + .title("Kon - Viewer") + .inner_size(600.0, 700.0) + .min_inner_size(450.0, 500.0) + .decorations(false) + .resizable(true) + .build() + .map_err(|e| e.to_string())?; + + Ok(()) +} diff --git a/src-tauri/src/lib.rs b/src-tauri/src/lib.rs new file mode 100644 index 0000000..c1c486c --- /dev/null +++ b/src-tauri/src/lib.rs @@ -0,0 +1,81 @@ +mod commands; +mod tray; + +use std::sync::Arc; + +use tauri::Manager; + +use kon_core::types::EngineName; +use kon_transcription::LocalEngine; + +/// Shared app state holding the transcription engines. +pub struct AppState { + pub whisper_engine: Arc, + pub parakeet_engine: Arc, +} + +#[cfg_attr(mobile, tauri::mobile_entry_point)] +pub fn run() { + tauri::Builder::default() + .plugin(tauri_plugin_opener::init()) + .plugin(tauri_plugin_dialog::init()) + .plugin(tauri_plugin_global_shortcut::Builder::new().build()) + .manage(AppState { + whisper_engine: Arc::new(LocalEngine::new( + EngineName::new("whisper"), + )), + parakeet_engine: Arc::new(LocalEngine::new( + EngineName::new("parakeet"), + )), + }) + .setup(|app| { + if let Err(e) = tray::setup(app) { + eprintln!("Failed to setup tray: {e}"); + } + + // Close-to-tray: hide window instead of exiting + if let Some(main_window) = app.get_webview_window("main") { + let win = main_window.clone(); + main_window.on_window_event(move |event| { + if let tauri::WindowEvent::CloseRequested { api, .. } = + event + { + api.prevent_close(); + let _ = win.hide(); + } + }); + } + + Ok(()) + }) + .invoke_handler(tauri::generate_handler![ + // Whisper model management + commands::models::download_model, + commands::models::check_model, + commands::models::list_models, + commands::models::load_model, + commands::models::check_engine, + // Parakeet model management + commands::models::download_parakeet_model, + commands::models::check_parakeet_model, + commands::models::list_parakeet_models, + commands::models::load_parakeet_model, + commands::models::check_parakeet_engine, + // Transcription + commands::transcription::transcribe_pcm, + commands::transcription::transcribe_file, + commands::transcription::transcribe_pcm_parakeet, + // Audio + commands::audio::save_audio, + // Windows + commands::windows::open_task_window, + commands::windows::open_viewer_window, + // Clipboard + commands::clipboard::copy_to_clipboard, + // Hardware + commands::hardware::probe_system, + commands::hardware::rank_models, + ]) + .run(tauri::generate_context!()) + .expect("error while running Kon"); +} diff --git a/src-tauri/src/main.rs b/src-tauri/src/main.rs new file mode 100644 index 0000000..f61cf83 --- /dev/null +++ b/src-tauri/src/main.rs @@ -0,0 +1,5 @@ +#![cfg_attr(not(debug_assertions), windows_subsystem = "windows")] + +fn main() { + kon_lib::run() +} diff --git a/src-tauri/src/tray.rs b/src-tauri/src/tray.rs new file mode 100644 index 0000000..f635ea4 --- /dev/null +++ b/src-tauri/src/tray.rs @@ -0,0 +1,59 @@ +use tauri::image::Image; +use tauri::menu::{MenuBuilder, MenuItemBuilder}; +use tauri::tray::TrayIconBuilder; +use tauri::Manager; + +pub fn setup(app: &tauri::App) -> Result<(), Box> { + let show = MenuItemBuilder::with_id("show", "Show Kon").build(app)?; + let status = MenuItemBuilder::with_id("status", "Ready") + .enabled(false) + .build(app)?; + let quit = MenuItemBuilder::with_id("quit", "Quit").build(app)?; + + let menu = MenuBuilder::new(app) + .item(&show) + .separator() + .item(&status) + .separator() + .item(&quit) + .build()?; + + let icon = app + .default_window_icon() + .cloned() + .unwrap_or_else(|| Image::new(&[0u8; 4], 1, 1)); + + let _tray = TrayIconBuilder::new() + .icon(icon) + .tooltip("Kon — Ready") + .menu(&menu) + .on_menu_event(move |app, event| match event.id().as_ref() { + "show" => { + if let Some(window) = app.get_webview_window("main") { + let _ = window.show(); + let _ = window.set_focus(); + } + } + "quit" => { + app.exit(0); + } + _ => {} + }) + .on_tray_icon_event(|tray, event| { + if let tauri::tray::TrayIconEvent::Click { + button: tauri::tray::MouseButton::Left, + .. + } = event + { + if let Some(window) = + tray.app_handle().get_webview_window("main") + { + let _ = window.show(); + let _ = window.set_focus(); + } + } + }) + .build(app)?; + + Ok(()) +} diff --git a/src-tauri/tauri.conf.json b/src-tauri/tauri.conf.json new file mode 100644 index 0000000..fff89c3 --- /dev/null +++ b/src-tauri/tauri.conf.json @@ -0,0 +1,40 @@ +{ + "$schema": "https://schema.tauri.app/config/2", + "productName": "Kon", + "version": "0.1.0", + "identifier": "uk.co.corbel.kon", + "build": { + "beforeDevCommand": "npm run dev", + "devUrl": "http://localhost:1420", + "beforeBuildCommand": "npm run build", + "frontendDist": "../build" + }, + "app": { + "windows": [ + { + "title": "Kon", + "width": 1020, + "height": 720, + "minWidth": 1020, + "minHeight": 540, + "decorations": false, + "resizable": true, + "center": true + } + ], + "security": { + "csp": "default-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline'; img-src 'self' asset: https://asset.localhost; connect-src ipc: http://ipc.localhost asset: https://asset.localhost http://localhost:* ws://localhost:*; media-src 'self' asset: https://asset.localhost" + } + }, + "bundle": { + "active": true, + "targets": "all", + "icon": [ + "icons/32x32.png", + "icons/128x128.png", + "icons/128x128@2x.png", + "icons/icon.icns", + "icons/icon.ico" + ] + } +} diff --git a/src/app.css b/src/app.css new file mode 100644 index 0000000..e5c0d2c --- /dev/null +++ b/src/app.css @@ -0,0 +1,307 @@ +@import url('https://fonts.googleapis.com/css2?family=DM+Sans:ital,opsz,wght@0,9..40,300..700;1,9..40,300..700&family=Instrument+Serif:ital@0;1&display=swap'); +@import "tailwindcss"; + +/* === Kon Design Tokens === */ +@theme { + /* Surfaces — warm layered depth */ + --color-bg: #0f0e0c; + --color-bg-elevated: #171614; + --color-bg-card: #1b1a17; + --color-bg-input: #151412; + --color-border: #2c2923; + --color-border-subtle: #221f1b; + + /* Text — warm hierarchy */ + --color-text: #f0ece4; + --color-text-secondary: #9a9486; + --color-text-tertiary: #716b60; + + /* Accent — warm amber/copper */ + --color-accent: #e8a87c; + --color-accent-hover: #d4976a; + --color-accent-subtle: #e8a87c10; + --color-accent-glow: #e8a87c25; + + /* Semantic */ + --color-success: #7ec89a; + --color-danger: #e87171; + --color-warning: #e8c86e; + + /* Layout */ + --color-sidebar: #13120f; + --color-nav-active: #201e1a; + --color-hover: #1e1c18; + + /* === Layout Tokens === */ + --radius-sm: 6px; + --radius-md: 8px; + --radius-lg: 12px; + --radius-xl: 16px; + --title-size: 26px; +} + +/* === Button Component Classes === */ +.btn-sm { @apply px-2.5 py-1 text-[11px]; } +.btn-md { @apply px-3 py-1.5 text-[12px]; } +.btn-lg { @apply px-4 py-2 text-[13px]; } + +/* === Light theme overrides === */ +html.light { + --color-bg: #faf8f5; + --color-bg-elevated: #f3f0eb; + --color-bg-card: #ffffff; + --color-bg-input: #f0ede8; + --color-border: #ddd8d0; + --color-border-subtle: #e6e2da; + + --color-text: #1a1816; + --color-text-secondary: #5c574d; + --color-text-tertiary: #8a8578; + + --color-accent: #d4956a; + --color-accent-hover: #c48a60; + --color-accent-subtle: #d4956a10; + --color-accent-glow: #d4956a25; + + --color-success: #4a9e6a; + --color-danger: #d45454; + --color-warning: #c9a84e; + + --color-sidebar: #f5f2ed; + --color-nav-active: #eae6e0; + --color-hover: #ede9e3; +} + +html.light ::-webkit-scrollbar-thumb { + background: #d0ccc4; +} +html.light ::-webkit-scrollbar-thumb:hover { + background: #b8b3aa; +} +html.light .grain::after { + opacity: 0.015; +} + +/* === Base === */ +html, body { + margin: 0; + padding: 0; + height: 100%; + overflow: hidden; + background: var(--color-bg); + color: var(--color-text); + font-family: "DM Sans", -apple-system, BlinkMacSystemFont, system-ui, sans-serif; + font-size: 14px; + line-height: 1.5; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; + user-select: none; +} + +/* === Display font === */ +.font-display { + font-family: "Instrument Serif", Georgia, "Times New Roman", serif; +} + +/* === Transcript font — optimised for reading === */ +.font-transcript { + font-family: "DM Sans", system-ui, sans-serif; + font-size: var(--font-size-transcript, 15px); + line-height: 1.85; + letter-spacing: 0.01em; + font-feature-settings: "liga" 1, "kern" 1; +} + +/* === Grain texture overlay === */ +.grain::after { + content: ""; + position: fixed; + inset: 0; + pointer-events: none; + opacity: 0.025; + background-image: url("data:image/svg+xml,%3Csvg viewBox='0 0 256 256' xmlns='http://www.w3.org/2000/svg'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='4' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)'/%3E%3C/svg%3E"); + z-index: 50; + pointer-events: none !important; +} + +/* === Scrollbar — thin, appears on hover === */ +::-webkit-scrollbar { + width: 5px; +} +::-webkit-scrollbar-track { + background: transparent; +} +::-webkit-scrollbar-thumb { + background: #2c2923; + border-radius: 999px; +} +::-webkit-scrollbar-thumb:hover { + background: #3d3830; +} + +/* === Smooth transitions (global) === */ +* { + transition-property: background-color, border-color, color, opacity, box-shadow; + transition-duration: 150ms; + transition-timing-function: cubic-bezier(0.2, 0.8, 0.2, 1); +} + +/* Opt out for inputs */ +textarea, input, [data-no-transition] { + transition: none; +} + +/* === Focus ring — consistent, accessible === */ +:focus-visible { + outline: 2px solid var(--color-accent); + outline-offset: 3px; + border-radius: var(--radius-md); +} + +/* === Selection colour === */ +::selection { + background: var(--color-accent-glow); + color: var(--color-text); +} + +/* === Animations === */ +@keyframes fade-in { + from { opacity: 0; transform: translateY(4px); } + to { opacity: 1; transform: translateY(0); } +} + +@keyframes pulse-soft { + 0%, 100% { opacity: 1; } + 50% { opacity: 0.4; } +} + +@keyframes pulse-warm { + 0%, 100% { box-shadow: 0 0 24px rgba(232, 168, 124, 0.25), 0 0 48px rgba(232, 168, 124, 0.08); } + 50% { box-shadow: 0 0 32px rgba(232, 168, 124, 0.4), 0 0 64px rgba(232, 168, 124, 0.15); } +} + +@keyframes slide-up { + from { opacity: 0; transform: translateY(8px); } + to { opacity: 1; transform: translateY(0); } +} + +@keyframes breathe { + 0%, 100% { transform: scale(1); } + 50% { transform: scale(1.04); } +} + +.animate-fade-in { + animation: fade-in 200ms ease-out; +} + +.animate-pulse-soft { + animation: pulse-soft 1.5s ease-in-out infinite; +} + +.animate-pulse-warm { + animation: pulse-warm 2s ease-in-out infinite; +} + +.animate-slide-up { + animation: slide-up 250ms ease-out; +} + +.animate-breathe { + animation: breathe 3s ease-in-out infinite; +} + +/* === Task sidebar slide === */ +@keyframes slide-in-right { + from { transform: translateX(100%); opacity: 0; } + to { transform: translateX(0); opacity: 1; } +} +@keyframes slide-out-right { + from { transform: translateX(0); opacity: 1; } + to { transform: translateX(100%); opacity: 0; } +} + +/* Task extraction highlight */ +@keyframes highlight-warm { + 0% { border-left-color: var(--color-accent); } + 100% { border-left-color: transparent; } +} + +/* Checkbox pop */ +@keyframes scale-pop { + 0% { transform: scale(0.95); } + 100% { transform: scale(1); } +} + +.animate-slide-in-right { + animation: slide-in-right 200ms ease-out; +} +.animate-highlight-warm { + border-left: 3px solid transparent; + animation: highlight-warm 2s ease-out; +} +.animate-scale-pop { + animation: scale-pop 50ms ease-out; +} + +/* Window focus glow */ +@keyframes glow-pulse { + 0% { box-shadow: 0 0 0 0 rgba(232, 168, 124, 0); } + 30% { box-shadow: 0 0 20px 4px rgba(232, 168, 124, 0.35), inset 0 0 12px rgba(232, 168, 124, 0.08); } + 100% { box-shadow: 0 0 0 0 rgba(232, 168, 124, 0); } +} + +.animate-glow-pulse { + animation: glow-pulse 700ms ease-out; +} + +html.light .animate-glow-pulse { + animation: glow-pulse-light 700ms ease-out; +} + +@keyframes glow-pulse-light { + 0% { box-shadow: 0 0 0 0 rgba(212, 149, 106, 0); } + 30% { box-shadow: 0 0 20px 4px rgba(212, 149, 106, 0.3), inset 0 0 12px rgba(212, 149, 106, 0.06); } + 100% { box-shadow: 0 0 0 0 rgba(212, 149, 106, 0); } +} + +/* Float window entrance */ +@keyframes float-enter { + from { opacity: 0; transform: scale(0.97); } + to { opacity: 1; transform: scale(1); } +} + +.animate-float-enter { + animation: float-enter 200ms ease-out; +} + +/* === Custom titlebar buttons === */ +.titlebar-btn { + display: flex; + align-items: center; + justify-content: center; + width: 46px; + height: 32px; + color: var(--color-text-secondary); +} + +/* Sinhala character spin (decorative, during recording) */ +@keyframes sinhala-spin { + from { transform: rotate(0deg); } + to { transform: rotate(360deg); } +} +.animate-sinhala-spin { + animation: sinhala-spin 2s linear infinite; +} + +/* Recording indicator dot (follows mouse via JS, see +layout.svelte) */ + +/* === Reduced Motion === */ +@media (prefers-reduced-motion: reduce) { + *, + *::before, + *::after { + animation-duration: 0.01ms !important; + animation-iteration-count: 1 !important; + transition-duration: 0.01ms !important; + } +} diff --git a/src/app.html b/src/app.html new file mode 100644 index 0000000..5dbf136 --- /dev/null +++ b/src/app.html @@ -0,0 +1,13 @@ + + + + + + + Kon + %sveltekit.head% + + +
%sveltekit.body%
+ + diff --git a/src/lib/Sidebar.svelte b/src/lib/Sidebar.svelte new file mode 100644 index 0000000..794e56d --- /dev/null +++ b/src/lib/Sidebar.svelte @@ -0,0 +1,173 @@ + + + diff --git a/src/lib/components/Card.svelte b/src/lib/components/Card.svelte new file mode 100644 index 0000000..7532acc --- /dev/null +++ b/src/lib/components/Card.svelte @@ -0,0 +1,7 @@ + + +
+ {@render children()} +
diff --git a/src/lib/components/HotkeyRecorder.svelte b/src/lib/components/HotkeyRecorder.svelte new file mode 100644 index 0000000..5ff247b --- /dev/null +++ b/src/lib/components/HotkeyRecorder.svelte @@ -0,0 +1,73 @@ + + + diff --git a/src/lib/components/ModelDownloader.svelte b/src/lib/components/ModelDownloader.svelte new file mode 100644 index 0000000..dafd77f --- /dev/null +++ b/src/lib/components/ModelDownloader.svelte @@ -0,0 +1,105 @@ + + +
+ +
+
+ + + +
+ +

Download Whisper Model

+

+ Kon needs the {modelSize} model to transcribe speech. +

+

+ {modelInfo[modelSize]?.size ?? "?"} · {modelInfo[modelSize]?.accuracy ?? "?"} accuracy · 100% offline +

+ + {#if downloading} +
+
+
+
+

+ {progress}% · {formatBytes(downloaded)} / {formatBytes(total)} +

+
+ {:else} + + {/if} + + {#if error} +

{error}

+ {/if} + +

+ Models are cached locally. No data leaves your machine. +

+
+
+
diff --git a/src/lib/components/SegmentedButton.svelte b/src/lib/components/SegmentedButton.svelte new file mode 100644 index 0000000..648296d --- /dev/null +++ b/src/lib/components/SegmentedButton.svelte @@ -0,0 +1,18 @@ + + +
+ {#each options as option} + + {/each} +
diff --git a/src/lib/components/TaskSidebar.svelte b/src/lib/components/TaskSidebar.svelte new file mode 100644 index 0000000..a1484cc --- /dev/null +++ b/src/lib/components/TaskSidebar.svelte @@ -0,0 +1,95 @@ + + + diff --git a/src/lib/components/Titlebar.svelte b/src/lib/components/Titlebar.svelte new file mode 100644 index 0000000..420e04e --- /dev/null +++ b/src/lib/components/Titlebar.svelte @@ -0,0 +1,74 @@ + + +
+ +
+ + +
+ + +
+ + + +
+
diff --git a/src/lib/components/Toggle.svelte b/src/lib/components/Toggle.svelte new file mode 100644 index 0000000..78e548c --- /dev/null +++ b/src/lib/components/Toggle.svelte @@ -0,0 +1,27 @@ + + +
+ +
+

{label}

+ {#if description} +

{description}

+ {/if} +
+
diff --git a/src/lib/components/UnicodeSpinner.svelte b/src/lib/components/UnicodeSpinner.svelte new file mode 100644 index 0000000..19d3fb8 --- /dev/null +++ b/src/lib/components/UnicodeSpinner.svelte @@ -0,0 +1,29 @@ + + + diff --git a/src/lib/pages/DictationPage.svelte b/src/lib/pages/DictationPage.svelte new file mode 100644 index 0000000..f189157 --- /dev/null +++ b/src/lib/pages/DictationPage.svelte @@ -0,0 +1,721 @@ + + +
+
+ {#if page.recording}Recording started{/if} +
+ {#if needsDownload} + + {:else} + +
+ + + + +
+ {#if page.recording} + + {#each [0.4, 0.8, 0.5, 1, 0.6, 0.9, 0.4, 0.7, 0.5, 0.8, 0.3, 0.6] as h, i} + + {/each} + + {:else} + + {#if modelLoading} + Loading model... + {:else if saved} + + Saved{#if extractedCount > 0} · {extractedCount} task{extractedCount === 1 ? '' : 's'} extracted{/if} + + {:else} + Press record or Ctrl+Shift+R + {/if} + + {/if} +
+ + + + {page.timerText} + + + + + {#if page.recording} + + + REC + + {:else if modelLoading} + Loading + {:else} + Ready + {/if} + + + + + + + +
+ + +
+ + {#if templates.length > 0} +
+ + {#if showTemplateMenu} +
+ {#each templates as template} + + {/each} +
+ {/if} +
+ {/if} + + + + + +
+ + {#if showExportMenu} +
+ {#each [["txt", "Plain Text"], ["md", "Markdown"], ["csv", "CSV"], ["html", "HTML"], ["srt", "SRT Subtitles"], ["vtt", "WebVTT"]] as [fmt, label]} + + {/each} +
+ {/if} +
+
+ + + {#if activeTemplate} +
+
+ Template: {activeTemplate} + Click a section, then record to fill it +
+ +
+
+ {/if} + + + {#if error} +
+
+ {error} +
+
+ {/if} + + +
+ + + + +
+ + {#if wordCount > 0} + {wordCount} {wordCount === 1 ? 'word' : 'words'} + {:else} + 0 words + {/if} + {#if insertPos >= 0 && page.recording} + · inserting at cursor + {/if} + +
+ {#if aiStatus} + {aiStatus} + · + {/if} + + {settings.formatMode} · {page.activeProfile === "None" ? "No profile" : page.activeProfile} + +
+
+
+
+ {/if} +
diff --git a/src/lib/pages/FilesPage.svelte b/src/lib/pages/FilesPage.svelte new file mode 100644 index 0000000..0ac9cf0 --- /dev/null +++ b/src/lib/pages/FilesPage.svelte @@ -0,0 +1,244 @@ + + +
+ +

File Transcription

+ + +
+ +
+
+ + + +
+

+ Drop audio or video files here +

+

+ MP3, WAV, M4A, MP4, FLAC, OGG +

+
+
+
+ + +
+ +
+ {#if progressText} + {progressText} + {/if} +
+ + + {#if error} +
+
+ {error} +
+
+ {/if} + + + {#if progress > 0} +
+
+
+
+ {#if fileName} +

{fileName}

+ {/if} +
+ {/if} + + +
+ + + +
+ + +
+ +
+ + {#if showExportMenu} +
+ {#each [["txt", "Plain Text"], ["md", "Markdown"], ["csv", "CSV"], ["html", "HTML"], ["srt", "SRT Subtitles"], ["vtt", "WebVTT"]] as [fmt, label]} + + {/each} +
+ {/if} +
+
+
diff --git a/src/lib/pages/FirstRunPage.svelte b/src/lib/pages/FirstRunPage.svelte new file mode 100644 index 0000000..55aab82 --- /dev/null +++ b/src/lib/pages/FirstRunPage.svelte @@ -0,0 +1,170 @@ + + +
+ {#if probing} +
+ +

Setting up Kon

+

Detecting your hardware...

+
+ + {:else if ready} +
+ +

Ready to go

+

Starting Kon...

+
+ + {:else if downloading} +
+

Downloading model

+

{downloadingModel}

+
+
+
+

{downloadProgress}%

+
+ + {:else} +
+

Welcome to Kon

+

Think out loud

+ + {#if error} +
{error}
+ {/if} + + {#if systemInfo} +
+

Your system

+
+ RAM + {Math.round(systemInfo.ram_mb / 1024)} GB + CPU + {systemInfo.cpu_brand} + Cores + {systemInfo.cpu_cores} + OS + {systemInfo.os} +
+
+ {/if} + + {#if models.length > 0} +
+

Recommended models

+
+ {#each models as model, i} + + {/each} +
+
+ {/if} + + +
+ {/if} +
diff --git a/src/lib/pages/HistoryPage.svelte b/src/lib/pages/HistoryPage.svelte new file mode 100644 index 0000000..556fc47 --- /dev/null +++ b/src/lib/pages/HistoryPage.svelte @@ -0,0 +1,344 @@ + + +
+ +
+

History

+ {history.length} saved +
+ {#if history.length > 0} + + {/if} +
+ + +
+ +
+ + + + + {#if searchQuery} + {filtered.length} results + + {/if} +
+
+
+ + +
+ + {#if filtered.length === 0} +
+
+ + + +
+

+ {searchQuery ? "No matching transcripts" : "No history yet"} +

+

+ {searchQuery ? "Try a different search" : "Transcripts auto-save after recording"} +

+
+ {:else} +
+ {#each filtered as item} + +
toggleExpand(item.id)} + onkeydown={(e) => { if (e.key === "Enter" || e.key === " ") { e.preventDefault(); toggleExpand(item.id); } }} + role="button" + tabindex="0" + aria-expanded={expandedId === item.id} + > + + {#if item.audioPath} + + {:else} + +
+ {/if} + + + + {item.title || item.preview || item.text.slice(0, 80)} + + + + {#if item.duration} + + {formatDuration(item.duration)} + + {/if} + + + + {#if item.source && item.source.toLowerCase().includes("file")} + + + + + + {:else} + + + + + + + + {/if} + + + + + {item.date} + + + + + + +
+ + + {#if expandedId === item.id} +
+ + {#if item.audioPath && playingId === item.id} +
+ + {formatTime(currentTime)} / {formatTime(duration)} + + e.stopPropagation()} + /> +
+ {#each PLAYBACK_SPEEDS as speed} + + {/each} +
+
+ {/if} + + +

{item.text}

+ + +
+ + + {#if item.audioPath && item.segments && item.segments.length > 0} + + {/if} +
+ +
+
+ {/if} + {/each} +
+ {/if} +
+
+
diff --git a/src/lib/pages/ProfilesPage.svelte b/src/lib/pages/ProfilesPage.svelte new file mode 100644 index 0000000..fd7872f --- /dev/null +++ b/src/lib/pages/ProfilesPage.svelte @@ -0,0 +1,264 @@ + + +
+ +
+

+ {tab === "Profiles" ? "Profiles" : "Templates"} +

+
+ +
+ + +
+ +
+ + +

+ {#if tab === "Profiles"} + Add custom vocabulary to improve transcription accuracy. + Names, places, and specialist terms that Whisper might misspell. + {:else} + Create structured templates for dictation. Sections become headings + you can click and record into — fill reports, meeting notes, or any repeating format. + {/if} +

+ + + {#if showNewDialog} +
+ +
+

+ New {tab === "Profiles" ? "Profile" : "Template"} +

+ e.key === "Enter" && handleCreate()} + data-no-transition + /> +

+ {tab === "Profiles" + ? "You can add vocabulary after creating the profile." + : "You can edit sections after creating the template."} +

+
+ + +
+
+
+
+ {/if} + + +
+ {#if tab === "Profiles"} + + {#if profiles.length === 0 && !showNewDialog} +
+
+ + + +
+

No profiles yet

+

Create one to improve transcription accuracy

+
+ {/if} + + {#each profiles as profile, i} +
+ +
+
+

{profile.name}

+ + {wordCount(profile.words)} {wordCount(profile.words) === 1 ? 'word' : 'words'} + +
+ +
+ +

+ One word or phrase per line. These will be prioritised during transcription. +

+ + + +
+ + {#if profile.saved} + Saved + {/if} +
+
+
+
+ {/each} + + {:else} + + {#if templates.length === 0 && !showNewDialog} +
+
+ + + +
+

No templates yet

+

Create one for structured dictation

+
+ {/if} + + {#each templates as template, i} +
+ +
+
+

{template.name}

+ + {template.sections.length} sections + +
+ +
+ +

+ One section per line. These become headings in your transcript. +

+ + + +
+ + {#if template._saved} + Saved + {/if} +
+ + +
+

Preview

+
+ {#each template.sections as section} +

# {section}

+ {/each} +
+
+
+
+
+ {/each} + {/if} +
+
diff --git a/src/lib/pages/SettingsPage.svelte b/src/lib/pages/SettingsPage.svelte new file mode 100644 index 0000000..7e3b91b --- /dev/null +++ b/src/lib/pages/SettingsPage.svelte @@ -0,0 +1,703 @@ + + +
+ +

Settings

+ +
+ + +
+ + {#if openSection === 'transcription'} +
+ + +
+

Engine

+ +

+ {settings.engine === "whisper" ? "OpenAI Whisper — 99+ languages, reliable" : + "Nvidia Parakeet — faster on CPU, English-focused, auto-punctuated"} +

+
+ + +
+

Format Mode

+ +

+ {settings.formatMode === "Raw" ? "Exact Whisper output, no formatting" : + settings.formatMode === "Clean" ? "Grouped into paragraphs, punctuation tidied" : + "Structured with lists, headings, and sections"} +

+
+ + + {#if settings.engine === "whisper"} +
+

Whisper Model

+ +

{modelDescriptions[settings.modelSize]}

+ +
+ {#if isModelDownloaded(settings.modelSize)} + + + Downloaded + + + {:else if downloadingModel === settings.modelSize.toLowerCase()} + {downloadProgress}% downloading... + {:else} + + {/if} +
+
+ {:else} +
+

Parakeet Model

+

Parakeet CTC 0.6B (int8) — ~613MB, near-instant transcription

+ +
+ {#if parakeetOk} + + + Model loaded + + {:else if parakeetDownloaded} + + + Downloaded + + + {:else if parakeetDownloading} + {parakeetProgress}% downloading... + {:else} + + {/if} +
+
+ {/if} + + +
+

Compute Device

+ +

GPU acceleration requires building with CUDA feature

+
+ + +
+

Language

+
+ + {#if settings.language === "en"} + + {/if} +
+
+
+ {/if} +
+ + +
+ + {#if openSection === 'processing'} +
+
+ + +
+
+ {/if} +
+ + +
+ + {#if openSection === 'ai'} +
+

Local LLM for smart task extraction, transcript cleanup, and formatting. Runs 100% offline.

+
+

Coming soon

+

AI-powered cleanup and smart extraction are being rebuilt with a faster engine. Task extraction currently uses rule-based matching, which runs automatically after each recording.

+
+
+ {/if} +
+ + +
+ + {#if openSection === 'profiles'} +
+ + +

Custom vocabulary to improve transcription accuracy

+ + {#if showProfiles} +
+ {#each profiles as profile, i} +
+
+ {profile.name} + + {profileWordCount(profile.words)} words + + + +
+ {#if editingProfile === i} +
+ +
+ {/if} +
+ {/each} + + {#if showNewProfile} +
+ e.key === "Enter" && createProfile()} + data-no-transition + /> + + +
+ {:else} + + {/if} +
+ {/if} + +
+ + + +

Structured formats for dictation sessions

+ + {#if showTemplates} +
+ {#each templates as template, i} +
+
+ {template.name} + + {template.sections.length} sections + + + +
+ {#if editingTemplate === i} +
+ +
+ {/if} +
+ {/each} + + {#if showNewTemplate} +
+ e.key === "Enter" && createTemplate()} + data-no-transition + /> + + +
+ {:else} + + {/if} +
+ {/if} +
+ {/if} +
+ + +
+ + {#if openSection === 'output'} +
+
+ + + + {#if settings.saveAudio} +
+

Output Folder

+
+
+

+ {settings.outputFolder || "Default (app data)"} +

+
+ + {#if settings.outputFolder} + + {/if} +
+
+ {/if} +
+
+ {/if} +
+ + +
+ + {#if openSection === 'hotkey'} +
+

Toggle recording from anywhere. Click to change.

+ +
+ {/if} +
+ + +
+ + {#if openSection === 'appearance'} +
+
+

Theme

+ +
+ +
+

+ Font Size {settings.fontSize}px +

+ +
+
+ {/if} +
+ + +
+ + {#if openSection === 'about'} +
+ +
+ + {engineStatus} +
+ +
+ {#each [ + "100% offline — all processing on your machine", + "No Python required — compiled Whisper engine", + "No cloud — audio never leaves your computer", + "No accounts — no sign-up, no tracking", + "No telemetry — zero data collection", + ] as item} +
+ + + +

{item}

+
+ {/each} +
+ +

Kon v1.0 · Powered by whisper.cpp · Built by CORBEL Ltd

+
+ {/if} +
+
+
+
diff --git a/src/lib/pages/TasksPage.svelte b/src/lib/pages/TasksPage.svelte new file mode 100644 index 0000000..211adca --- /dev/null +++ b/src/lib/pages/TasksPage.svelte @@ -0,0 +1,517 @@ + + +
+ +
+
+

Tasks

+

Extracted from transcripts or added manually

+
+
+ +
+ + +
+
+ + + + + + {#if searchQuery} + + {/if} +
+
+ + +
+
+ + + + + {#if quickInput.trim()} + + → {activeBucket === "all" ? "inbox" : activeBucket} + + {/if} +
+
+ + +
+ + +
+ + +
+ + {#if showSortMenu} +
+ {#each [["date", "By date"], ["quick-first", "Quick first"], ["deep-first", "Deep first"]] as [mode, label]} + + {/each} +
+ {/if} +
+
+ + +
+ +
+ + + + +
+ {#each taskLists as list (list.id)} + {#if editingListId === list.id && !sidebarCollapsed} +
+ { if (e.key === "Enter") finishRenaming(); if (e.key === "Escape") { editingListId = null; } }} + onblur={finishRenaming} + data-no-transition + autofocus + /> +
+ {:else} +
+ + + + {#if contextMenuListId === list.id && !sidebarCollapsed} +
+ +
+ +
+ {/if} +
+ {/if} + {/each} +
+ + + {#if !sidebarCollapsed} +
+ {#if showNewList} + { showNewList = false; newListName = ""; }} + data-no-transition + autofocus + /> + {:else} + + {/if} +
+ {/if} +
+ + +
+ {#if filteredTasks.length === 0} +
+ + + +

+ {searchQuery ? "No matching tasks" + : activeListId !== "all" && activeBucket !== "all" + ? `No ${activeBucket} tasks in ${activeListName}` + : activeListId !== "all" + ? `No tasks in ${activeListName}` + : activeBucket === "all" ? "No tasks yet" : `Nothing in ${activeBucket}`} +

+

+ {searchQuery ? "Try a different search" : "Tasks are extracted from transcripts or added above"} +

+
+ {:else} +
+ {#each filteredTasks as task (task.id)} +
+ + + + +
+

{task.text}

+
+ + {#each ["today", "soon", "later"] as b} + + {/each} + · + + {#each ["quick", "medium", "deep"] as e} + + {/each} + + {#if task.createdAt} + {formatTimestamp(task.createdAt)} + {/if} +
+ + {#if activeListId === "all" && getListName(task.listId)} +

{getListName(task.listId)}

+ {/if} +
+ + + +
+ {/each} +
+ {/if} + + + {#if completedTasks.length > 0} +
+ + {#if showCompleted} +
+ {#each completedTasks as task (task.id)} +
+ +
+

{task.text}

+ {#if task.doneAt} +

Completed {formatTimestamp(task.doneAt)}

+ {/if} +
+ +
+ {/each} +
+ {/if} +
+ {/if} +
+
+
diff --git a/src/lib/stores/page.svelte.js b/src/lib/stores/page.svelte.js new file mode 100644 index 0000000..1eb3bee --- /dev/null +++ b/src/lib/stores/page.svelte.js @@ -0,0 +1,353 @@ +/** @type {{ current: string, status: string, statusColor: string, activeProfile: string, recording: boolean, timerText: string, handedness: string, taskSidebarOpen: boolean }} */ +export const page = $state({ + current: "dictation", + status: "Ready", + statusColor: "#7ec89a", + activeProfile: "None", + recording: false, + timerText: "00:00", + handedness: "Right", + taskSidebarOpen: false, +}); + +// ---- Settings (persisted to localStorage) ---- + +const SETTINGS_KEY = "kon_settings"; + +const defaults = { + engine: "whisper", + modelSize: "Base", + language: "en", + device: "auto", + formatMode: "Smart", + removeFillers: true, + antiHallucination: true, + britishEnglish: true, + autoCopy: true, + includeTimestamps: true, + theme: "Dark", + fontSize: 14, + llmModelSize: "small", + llmEnabled: false, + saveAudio: false, + outputFolder: "", + globalHotkey: "Ctrl+Shift+R", + sidebarCollapsed: false, +}; + +function loadSettings() { + try { + const raw = localStorage.getItem(SETTINGS_KEY); + if (raw) return { ...defaults, ...JSON.parse(raw) }; + } catch {} + return { ...defaults }; +} + +export const settings = $state(loadSettings()); + +/** Save current settings to localStorage */ +export function saveSettings() { + try { + localStorage.setItem(SETTINGS_KEY, JSON.stringify(settings)); + } catch {} +} + +// ---- Profiles (persisted to localStorage) ---- + +const PROFILES_KEY = "kon_profiles"; + +function loadProfiles() { + try { + const raw = localStorage.getItem(PROFILES_KEY); + if (raw) return JSON.parse(raw); + } catch {} + return []; +} + +export const profiles = $state(loadProfiles()); + +export function saveProfiles() { + try { + localStorage.setItem(PROFILES_KEY, JSON.stringify(profiles)); + } catch {} +} + +// ---- History (persisted to localStorage) ---- + +const HISTORY_KEY = "kon_history"; + +function loadHistory() { + try { + const raw = localStorage.getItem(HISTORY_KEY); + if (raw) return JSON.parse(raw); + } catch {} + return []; +} + +export const history = $state(loadHistory()); + +export function saveHistory() { + try { + localStorage.setItem(HISTORY_KEY, JSON.stringify(history)); + } catch {} +} + +export function addToHistory(entry) { + history.unshift(entry); + if (history.length > 100) history.length = 100; + saveHistory(); +} + +export function deleteFromHistory(index) { + history.splice(index, 1); + saveHistory(); +} + +// ---- Tasks (persisted to localStorage) ---- + +const TASKS_KEY = "kon_tasks"; + +function loadTasks() { + try { + const raw = localStorage.getItem(TASKS_KEY); + if (raw) return JSON.parse(raw); + } catch {} + return []; +} + +export const tasks = $state(loadTasks()); + +export function saveTasks() { + try { + localStorage.setItem(TASKS_KEY, JSON.stringify(tasks)); + } catch {} +} + +export function addTask(task) { + tasks.unshift({ + id: crypto.randomUUID(), + text: task.text, + bucket: task.bucket || "inbox", + listId: task.listId || null, + context: task.context || "", + effort: task.effort || "", + done: false, + doneAt: null, + createdAt: new Date().toISOString(), + sourceTranscriptId: task.sourceTranscriptId || null, + notes: "", + }); + saveTasks(); + broadcastTasks(); +} + +export function updateTask(id, updates) { + const idx = tasks.findIndex((t) => t.id === id); + if (idx >= 0) { + Object.assign(tasks[idx], updates); + saveTasks(); + broadcastTasks(); + } +} + +export function deleteTask(id) { + const idx = tasks.findIndex((t) => t.id === id); + if (idx >= 0) { + tasks.splice(idx, 1); + saveTasks(); + broadcastTasks(); + } +} + +export function completeTask(id) { + updateTask(id, { done: true, doneAt: new Date().toISOString() }); +} + +export function uncompleteTask(id) { + updateTask(id, { done: false, doneAt: null }); +} + +// ---- BroadcastChannel for multi-window task sync ---- + +const taskChannel = typeof BroadcastChannel !== "undefined" + ? new BroadcastChannel("kon_tasks") + : null; + +if (taskChannel) { + taskChannel.onmessage = (event) => { + if (event.data.type === "tasks_updated") { + tasks.length = 0; + tasks.push(...event.data.tasks); + } + }; +} + +function broadcastTasks() { + if (taskChannel) { + taskChannel.postMessage({ type: "tasks_updated", tasks: $state.snapshot(tasks) }); + } +} + +// ---- Task Lists (persisted to localStorage) ---- + +const TASK_LISTS_KEY = "kon_task_lists"; + +function loadTaskLists() { + try { + const raw = localStorage.getItem(TASK_LISTS_KEY); + if (raw) return JSON.parse(raw); + } catch {} + return [ + { id: "all", name: "All Tasks", builtIn: true, createdAt: null }, + { id: "inbox", name: "Inbox", builtIn: true, createdAt: null }, + ]; +} + +export const taskLists = $state(loadTaskLists()); + +export function saveTaskLists() { + try { + localStorage.setItem(TASK_LISTS_KEY, JSON.stringify(taskLists)); + } catch {} + broadcastTaskLists(); +} + +export function addTaskList(name, profileId = null) { + taskLists.push({ + id: crypto.randomUUID(), + name, + builtIn: false, + profileId, + createdAt: new Date().toISOString(), + }); + saveTaskLists(); +} + +export function addProfileTaskList(profileName) { + const exists = taskLists.find((l) => l.profileId === profileName); + if (exists) return exists.id; + const id = crypto.randomUUID(); + taskLists.push({ + id, + name: profileName, + builtIn: false, + profileId: profileName, + createdAt: new Date().toISOString(), + }); + saveTaskLists(); + return id; +} + +export function removeProfileTaskList(profileName) { + const idx = taskLists.findIndex((l) => l.profileId === profileName); + if (idx >= 0) { + const listId = taskLists[idx].id; + for (const t of tasks) { + if (t.listId === listId) t.listId = null; + } + saveTasks(); + broadcastTasks(); + taskLists.splice(idx, 1); + saveTaskLists(); + } +} + +export function moveTaskToList(taskId, listId) { + updateTask(taskId, { listId: listId === "inbox" || listId === "all" ? null : listId }); +} + +export function moveTaskListToProfile(listId, profileId) { + const list = taskLists.find((l) => l.id === listId); + if (list && !list.builtIn) { + list.profileId = profileId || null; + if (profileId && !list.name) list.name = profileId; + saveTaskLists(); + } +} + +export function renameTaskList(id, name) { + const list = taskLists.find((l) => l.id === id); + if (list && !list.builtIn) { + list.name = name; + saveTaskLists(); + } +} + +export function deleteTaskList(id) { + const idx = taskLists.findIndex((l) => l.id === id); + if (idx >= 0 && !taskLists[idx].builtIn) { + for (const t of tasks) { + if (t.listId === id) t.listId = null; + } + saveTasks(); + broadcastTasks(); + taskLists.splice(idx, 1); + saveTaskLists(); + } +} + +export function moveTaskList(id, direction) { + const idx = taskLists.findIndex((l) => l.id === id); + const targetIdx = idx + direction; + if (targetIdx < 0 || targetIdx >= taskLists.length) return; + if (taskLists[targetIdx].builtIn) return; + [taskLists[idx], taskLists[targetIdx]] = [taskLists[targetIdx], taskLists[idx]]; + saveTaskLists(); +} + +export function sortTaskLists(mode) { + const builtIn = taskLists.filter((l) => l.builtIn); + const custom = taskLists.filter((l) => !l.builtIn); + if (mode === "alpha") { + custom.sort((a, b) => a.name.localeCompare(b.name)); + } else if (mode === "date") { + custom.sort((a, b) => new Date(a.createdAt) - new Date(b.createdAt)); + } + taskLists.length = 0; + taskLists.push(...builtIn, ...custom); + saveTaskLists(); +} + +// BroadcastChannel for task lists +const taskListChannel = typeof BroadcastChannel !== "undefined" + ? new BroadcastChannel("kon_task_lists") + : null; + +if (taskListChannel) { + taskListChannel.onmessage = (event) => { + if (event.data.type === "task_lists_updated") { + taskLists.length = 0; + taskLists.push(...event.data.lists); + } + }; +} + +function broadcastTaskLists() { + if (taskListChannel) { + taskListChannel.postMessage({ type: "task_lists_updated", lists: $state.snapshot(taskLists) }); + } +} + +// ---- Templates (persisted to localStorage) ---- + +const TEMPLATES_KEY = "kon_templates"; + +function loadTemplates() { + try { + const raw = localStorage.getItem(TEMPLATES_KEY); + if (raw) return JSON.parse(raw); + } catch {} + return [ + { name: "Meeting Notes", sections: ["Attendees", "Agenda", "Discussion", "Action Items", "Next Steps"] }, + { name: "Report", sections: ["Summary", "Background", "Findings", "Recommendations"] }, + { name: "Interview", sections: ["Candidate", "Role", "Questions & Answers", "Assessment", "Next Steps"] }, + ]; +} + +export const templates = $state(loadTemplates()); + +export function saveTemplates() { + try { + localStorage.setItem(TEMPLATES_KEY, JSON.stringify(templates)); + } catch {} +} diff --git a/src/lib/utils/constants.js b/src/lib/utils/constants.js new file mode 100644 index 0000000..9a55897 --- /dev/null +++ b/src/lib/utils/constants.js @@ -0,0 +1,30 @@ +// Timing +export const FEEDBACK_TIMEOUT_MS = 3000; +export const HOTKEY_FEEDBACK_MS = 1500; +export const HISTORY_MAX_ENTRIES = 100; +export const MAX_PCM_SAMPLES = 4_800_000; // 5 min at 16kHz +export const SIDEBAR_MAX_TASKS = 30; +export const CHUNK_INTERVAL_MS = 3000; +export const MIN_CHUNK_SAMPLES = 8000; + +// Buckets +export const BUCKET_COLORS = { + inbox: "text-text-tertiary", + today: "text-accent", + soon: "text-warning", + later: "text-text-secondary", +}; + +export const BUCKET_DOT_COLORS = { + inbox: "bg-text-tertiary", + today: "bg-accent", + soon: "bg-warning", + later: "bg-text-secondary", +}; + +// Effort +export const EFFORT_LABELS = { quick: "Quick", medium: "Medium", deep: "Deep" }; +export const EFFORT_ORDER = { quick: 1, medium: 2, deep: 3, "": 4 }; + +// Playback +export const PLAYBACK_SPEEDS = [0.5, 1, 1.5, 2, 3, 5]; diff --git a/src/lib/utils/export.js b/src/lib/utils/export.js new file mode 100644 index 0000000..33a5367 --- /dev/null +++ b/src/lib/utils/export.js @@ -0,0 +1,118 @@ +import { pad, formatTimeSRT, formatTimeVTT } from "./time.js"; + +/** + * Export transcript in various formats. + * @param {string} text - Plain text transcript + * @param {Array<{start: number, end: number, text: string}>} segments - Timed segments + * @param {string} format - "txt" | "md" | "csv" | "html" | "srt" | "vtt" + * @returns {string} + */ +export function exportTranscript(text, segments, format) { + switch (format) { + case "srt": + return toSRT(segments); + case "vtt": + return toVTT(segments); + case "md": + return toMarkdown(text, segments); + case "csv": + return toCSV(segments); + case "html": + return toHTML(text, segments); + default: + return text; + } +} + +function toSRT(segments) { + if (!segments || segments.length === 0) return ""; + return segments + .map((seg, i) => { + return `${i + 1}\n${formatTimeSRT(seg.start)} --> ${formatTimeSRT(seg.end)}\n${seg.text.trim()}\n`; + }) + .join("\n"); +} + +function toVTT(segments) { + if (!segments || segments.length === 0) return ""; + let out = "WEBVTT\n\n"; + out += segments + .map((seg, i) => { + return `${i + 1}\n${formatTimeVTT(seg.start)} --> ${formatTimeVTT(seg.end)}\n${seg.text.trim()}\n`; + }) + .join("\n"); + return out; +} + +function toCSV(segments) { + if (!segments || segments.length === 0) return "Start,End,Text\n"; + let csv = "Start,End,Text\n"; + for (const seg of segments) { + const text = seg.text.trim().replace(/"/g, '""'); + csv += `${seg.start.toFixed(2)},${seg.end.toFixed(2)},"${text}"\n`; + } + return csv; +} + +function escapeHtml(str) { + return str.replace(/&/g, '&').replace(//g, '>').replace(/"/g, '"'); +} + +function toHTML(text, segments) { + let html = ` + + + +Kon Transcript + + + +

Transcript

+

${new Date().toLocaleDateString("en-GB")}`; + if (segments?.length > 0) { + const dur = segments[segments.length - 1].end; + html += ` · ${Math.round(dur)}s`; + } + html += `

\n`; + + if (segments?.length > 0) { + for (const seg of segments) { + const mins = Math.floor(seg.start / 60); + const secs = Math.floor(seg.start % 60); + html += `
${pad(mins)}:${pad(secs)}${escapeHtml(seg.text.trim())}
\n`; + } + } else { + html += `

${escapeHtml(text).replace(/\n/g, "
")}

`; + } + html += ``; + return html; +} + +function toMarkdown(text, segments) { + let md = `# Transcription\n\n`; + md += `**Date:** ${new Date().toLocaleDateString("en-GB")}\n`; + if (segments && segments.length > 0) { + const duration = segments[segments.length - 1].end; + md += `**Duration:** ${Math.round(duration)}s\n`; + } + md += `\n---\n\n`; + + if (segments && segments.length > 0) { + segments.forEach((seg) => { + const mins = Math.floor(seg.start / 60); + const secs = Math.floor(seg.start % 60); + md += `[${pad(mins)}:${pad(secs)}] ${seg.text.trim()}\n\n`; + }); + } else { + md += text; + } + + return md; +} diff --git a/src/lib/utils/taskExtractor.js b/src/lib/utils/taskExtractor.js new file mode 100644 index 0000000..8d1e44d --- /dev/null +++ b/src/lib/utils/taskExtractor.js @@ -0,0 +1,127 @@ +/** + * Rule-based task extraction from transcripts. + * Identifies action items from natural speech patterns. + */ + +// Action verbs that typically start task sentences +const ACTION_VERBS = [ + "call", "email", "send", "write", "build", "fix", "update", "check", + "review", "schedule", "book", "create", "set up", "follow up", "organise", + "prepare", "draft", "submit", "cancel", "confirm", "arrange", "order", + "buy", "get", "find", "look into", "research", "test", "deploy", "push", + "move", "add", "remove", "delete", "install", "configure", "contact", + "message", "tell", "ask", "invite", "remind", "finish", "complete", + "start", "begin", "plan", "design", "implement", "refactor", +]; + +// Phrases that signal a task +const TASK_PHRASES = [ + "need to", "needs to", "should", "must", "have to", "has to", + "want to", "going to", "gonna", "got to", "gotta", + "don't forget to", "remember to", "make sure to", "make sure we", + "let's", "we should", "i should", "we need to", "i need to", + "we have to", "i have to", "we must", "i must", +]; + +// Explicit markers (user intentionally marks a task) +const EXPLICIT_MARKERS = [ + "action:", "action item:", "todo:", "task:", "to do:", + "action item", "follow up:", "follow-up:", +]; + +/** + * Extract tasks from a transcript string. + * Returns an array of { text, confidence } objects. + */ +export function extractTasks(transcript) { + if (!transcript || !transcript.trim()) return []; + + const tasks = []; + const seen = new Set(); + + // Split into sentences (rough but effective for speech) + const sentences = splitSentences(transcript); + + for (const sentence of sentences) { + const trimmed = sentence.trim(); + if (trimmed.length < 5) continue; + + const lower = trimmed.toLowerCase(); + let matched = false; + let confidence = 0; + + // Check explicit markers (highest confidence) + for (const marker of EXPLICIT_MARKERS) { + if (lower.startsWith(marker) || lower.includes(marker)) { + const taskText = extractAfterMarker(trimmed, marker); + if (taskText && taskText.length > 3) { + addTask(tasks, seen, capitalise(taskText), 0.95); + matched = true; + break; + } + } + } + if (matched) continue; + + // Check task phrases (high confidence) + for (const phrase of TASK_PHRASES) { + const idx = lower.indexOf(phrase); + if (idx >= 0) { + const taskText = extractTaskFromPhrase(trimmed, phrase, idx); + if (taskText && taskText.length > 3) { + addTask(tasks, seen, capitalise(taskText), 0.8); + matched = true; + break; + } + } + } + if (matched) continue; + + // Check if sentence starts with an action verb (medium confidence) + const firstWord = lower.split(/\s+/)[0]; + const firstTwo = lower.split(/\s+/).slice(0, 2).join(" "); + if (ACTION_VERBS.includes(firstWord) || ACTION_VERBS.includes(firstTwo)) { + addTask(tasks, seen, capitalise(trimmed), 0.6); + } + } + + return tasks; +} + +function splitSentences(text) { + // Split on sentence-ending punctuation, newlines, or common speech breaks + return text + .split(/(?<=[.!?])\s+|\n+/) + .flatMap((s) => s.split(/(?:,\s*(?:and\s+)?)?(?=(?:then|also|plus)\s)/i)) + .filter((s) => s.trim().length > 0); +} + +function extractAfterMarker(sentence, marker) { + const lower = sentence.toLowerCase(); + const idx = lower.indexOf(marker); + if (idx < 0) return null; + return sentence.slice(idx + marker.length).trim().replace(/^[:\-–—]\s*/, ""); +} + +function extractTaskFromPhrase(sentence, phrase, idx) { + // Extract "need to X" → "X" + const afterPhrase = sentence.slice(idx + phrase.length).trim(); + if (afterPhrase) return afterPhrase; + return null; +} + +function capitalise(text) { + if (!text) return text; + // Clean up leading punctuation/whitespace + const cleaned = text.replace(/^[,;:\-–—\s]+/, "").trim(); + if (!cleaned) return text; + return cleaned.charAt(0).toUpperCase() + cleaned.slice(1); +} + +function addTask(tasks, seen, text, confidence) { + // Remove trailing punctuation for dedup + const key = text.toLowerCase().replace(/[.!?,;:]+$/, "").trim(); + if (seen.has(key)) return; + seen.add(key); + tasks.push({ text: text.replace(/[.!?]+$/, "").trim(), confidence }); +} diff --git a/src/lib/utils/time.js b/src/lib/utils/time.js new file mode 100644 index 0000000..93e14f6 --- /dev/null +++ b/src/lib/utils/time.js @@ -0,0 +1,46 @@ +/** Pad number to 2 digits */ +export function pad(n) { + return n.toString().padStart(2, "0"); +} + +/** Format seconds as M:SS (e.g. 1:05) */ +export function formatTime(seconds) { + if (!seconds || isNaN(seconds)) return "0:00"; + const m = Math.floor(seconds / 60); + const s = Math.floor(seconds % 60).toString().padStart(2, "0"); + return `${m}:${s}`; +} + +/** Format seconds as human duration (e.g. 2m 30s) */ +export function formatDuration(seconds) { + if (!seconds) return ""; + const m = Math.floor(seconds / 60); + const s = Math.round(seconds % 60); + return m > 0 ? `${m}m ${s}s` : `${s}s`; +} + +/** Format ISO timestamp as D Mon HH:MM (e.g. 15 Mar 18:11) */ +export function formatTimestamp(iso) { + if (!iso) return ""; + const d = new Date(iso); + return d.toLocaleDateString("en-GB", { day: "numeric", month: "short" }) + + " " + d.toLocaleTimeString("en-GB", { hour: "2-digit", minute: "2-digit" }); +} + +/** Format seconds as SRT timestamp (HH:MM:SS,mmm) */ +export function formatTimeSRT(seconds) { + const h = Math.floor(seconds / 3600); + const m = Math.floor((seconds % 3600) / 60); + const s = Math.floor(seconds % 60); + const ms = Math.floor((seconds % 1) * 1000); + return `${pad(h)}:${pad(m)}:${pad(s)},${ms.toString().padStart(3, "0")}`; +} + +/** Format seconds as VTT timestamp (HH:MM:SS.mmm) */ +export function formatTimeVTT(seconds) { + const h = Math.floor(seconds / 3600); + const m = Math.floor((seconds % 3600) / 60); + const s = Math.floor(seconds % 60); + const ms = Math.floor((seconds % 1) * 1000); + return `${pad(h)}:${pad(m)}:${pad(s)}.${ms.toString().padStart(3, "0")}`; +} diff --git a/src/routes/+layout.js b/src/routes/+layout.js new file mode 100644 index 0000000..9d24899 --- /dev/null +++ b/src/routes/+layout.js @@ -0,0 +1,5 @@ +// Tauri doesn't have a Node.js server to do proper SSR +// so we use adapter-static with a fallback to index.html to put the site in SPA mode +// See: https://svelte.dev/docs/kit/single-page-apps +// See: https://v2.tauri.app/start/frontend/sveltekit/ for more info +export const ssr = false; diff --git a/src/routes/+layout.svelte b/src/routes/+layout.svelte new file mode 100644 index 0000000..a72ef41 --- /dev/null +++ b/src/routes/+layout.svelte @@ -0,0 +1,177 @@ + + + + +{#if page.recording} +
+{/if} + +{#if isSecondaryWindow} + + {@render children()} +{:else} +
+ +
+ {#if page.current !== "first-run"} + + {/if} +
+ {@render children()} +
+
+
+ + + {#if page.taskSidebarOpen && page.current !== "first-run" && !isSecondaryWindow} + + +
{ if (e.target === e.currentTarget) page.taskSidebarOpen = false; }} + > + + +
{ page.taskSidebarOpen = false; }} + >
+ +
e.stopPropagation()} + > + +
+
+ {/if} +{/if} diff --git a/src/routes/+page.svelte b/src/routes/+page.svelte new file mode 100644 index 0000000..b1a19cf --- /dev/null +++ b/src/routes/+page.svelte @@ -0,0 +1,30 @@ + + +
+ {#if page.current === "first-run"} + + {:else if page.current === "dictation"} + + {:else if page.current === "files"} + + {:else if page.current === "tasks"} + + {:else if page.current === "history"} + + {:else if page.current === "settings"} + + {/if} +
diff --git a/src/routes/float/+layout@.svelte b/src/routes/float/+layout@.svelte new file mode 100644 index 0000000..e30a3e6 --- /dev/null +++ b/src/routes/float/+layout@.svelte @@ -0,0 +1,71 @@ + + + + +
+ {@render children()} +
diff --git a/src/routes/float/+page.svelte b/src/routes/float/+page.svelte new file mode 100644 index 0000000..1779d84 --- /dev/null +++ b/src/routes/float/+page.svelte @@ -0,0 +1,460 @@ + + + + +
+ +
+ + Kon - To-do + + +
+ + + + + + +
+ + +
+ +
+ {#each builtInLists as list (list.id)} + + {/each} + + + {#if customLists.length > 0} + + {/if} + + {#each customLists as list (list.id)} + {#if editingListId === list.id} + + {:else} +
+ + + + {#if contextMenuListId === list.id} +
e.stopPropagation()}> + + + + {#if profiles.length > 0} +
+

Move to profile

+ {#each profiles as profile} + + {/each} + + {/if} +
+ +
+ {/if} +
+ {/if} + {/each} + + + {#if showNewList} + { showNewList = false; newListName = ""; }} + data-no-transition + autofocus + /> + {:else} + + {/if} + + +
+ + {#if showSortMenu} +
e.stopPropagation()}> + + +
+ {/if} +
+
+ + +
+ +
+ + +
+ {#if tasksForActiveList.length === 0} +
+

No active tasks

+

Type above or drag tasks here

+
+ {:else} +
+ {#each tasksForActiveList as task (task.id)} +
handleTaskDragStart(e, task.id)} + ondragend={handleTaskDragEnd} + > + +
+

{task.text}

+ {#if task.createdAt} +

+ {new Date(task.createdAt).toLocaleDateString("en-GB", { day: "numeric", month: "short" })} +

+ {/if} +
+ +
+ {/each} +
+ {/if} + + + {#if completedForActiveList.length > 0} +
+ + {#if showCompleted} +
+ {#each completedForActiveList as task (task.id)} +
+ +

{task.text}

+
+ {/each} +
+ {/if} +
+ {/if} +
+
+
diff --git a/src/routes/viewer/+layout@.svelte b/src/routes/viewer/+layout@.svelte new file mode 100644 index 0000000..460d9d8 --- /dev/null +++ b/src/routes/viewer/+layout@.svelte @@ -0,0 +1,48 @@ + + + + +
+ {@render children()} +
diff --git a/src/routes/viewer/+page.svelte b/src/routes/viewer/+page.svelte new file mode 100644 index 0000000..96b9dc5 --- /dev/null +++ b/src/routes/viewer/+page.svelte @@ -0,0 +1,453 @@ + + +
+ +
+ + Kon - Viewer + +
+ +
+ + {#if item} + +
+

+ {item.title || "Transcript"} +

+

+ {item.date}{#if item.duration} · {formatDuration(item.duration)}{/if} · {item.source} +

+
+ + + {#if audioEl} +
+ + + + + + {formatTime(currentTime)} / {formatTime(duration)} + + + + + + +
+ {#each PLAYBACK_SPEEDS as speed} + + {/each} +
+
+ {/if} + + +
+
+ + + + + + {#if searchQuery} + {matchCount} matches + + {/if} +
+ + + + +
+ + +
+ {#if item.segments && item.segments.length > 0} +
+ {#each visibleSegments as seg (seg._idx)} +
seekToTime(seg.start)} + ondblclick={() => startEditing(seg._idx)} + role="button" + tabindex="0" + onkeydown={(e) => { if (e.key === "Enter" && editingIdx !== seg._idx) seekToTime(seg.start); }} + > + + + + {#if showTimestamps} + + {formatTime(seg.start)} + + {/if} + + {#if editingIdx === seg._idx} + + {:else} +

+ {#if searchQuery.trim()} + {@html highlightText(seg.text.trim())} + {:else} + {seg.text.trim()} + {/if} +

+ {/if} + +
+ + +
+
+ {/each} +
+ {:else} + +

{item.text}

+ {/if} +
+ {:else} +
+

No transcript loaded

+
+ {/if} +
diff --git a/static/favicon.png b/static/favicon.png new file mode 100644 index 0000000..825b9e6 Binary files /dev/null and b/static/favicon.png differ diff --git a/static/pcm-processor.js b/static/pcm-processor.js new file mode 100644 index 0000000..5bf3025 --- /dev/null +++ b/static/pcm-processor.js @@ -0,0 +1,43 @@ +class PcmProcessor extends AudioWorkletProcessor { + constructor() { + super(); + this.buffer = []; + // sampleRate is a global in AudioWorkletProcessor scope + this.ratio = sampleRate / 16000; + this.needsResample = Math.abs(this.ratio - 1.0) > 0.01; + this.resamplePos = 0; + } + + process(inputs) { + const input = inputs[0]; + if (!input || input.length === 0) return true; + + const samples = input[0]; // First channel (mono) + if (!samples) return true; + + if (this.needsResample) { + // Simple downsampling to 16kHz + for (let i = 0; i < samples.length; i++) { + this.resamplePos += 1; + if (this.resamplePos >= this.ratio) { + this.buffer.push(samples[i]); + this.resamplePos -= this.ratio; + } + } + } else { + for (let i = 0; i < samples.length; i++) { + this.buffer.push(samples[i]); + } + } + + // Send every ~0.5 seconds at 16kHz = 8000 samples + if (this.buffer.length >= 8000) { + this.port.postMessage({ type: "pcm", samples: this.buffer }); + this.buffer = []; + } + + return true; + } +} + +registerProcessor("pcm-processor", PcmProcessor); diff --git a/static/svelte.svg b/static/svelte.svg new file mode 100644 index 0000000..c5e0848 --- /dev/null +++ b/static/svelte.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/static/tauri.svg b/static/tauri.svg new file mode 100644 index 0000000..31b62c9 --- /dev/null +++ b/static/tauri.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/static/vite.svg b/static/vite.svg new file mode 100644 index 0000000..e7b8dfb --- /dev/null +++ b/static/vite.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/svelte.config.js b/svelte.config.js new file mode 100644 index 0000000..7707cbc --- /dev/null +++ b/svelte.config.js @@ -0,0 +1,12 @@ +import adapter from "@sveltejs/adapter-static"; + +/** @type {import('@sveltejs/kit').Config} */ +const config = { + kit: { + adapter: adapter({ + fallback: "index.html", + }), + }, +}; + +export default config; diff --git a/vite.config.js b/vite.config.js new file mode 100644 index 0000000..5ff644f --- /dev/null +++ b/vite.config.js @@ -0,0 +1,27 @@ +import { defineConfig } from "vite"; +import { sveltekit } from "@sveltejs/kit/vite"; +import tailwindcss from "@tailwindcss/vite"; + +// @ts-expect-error process is a nodejs global +const host = process.env.TAURI_DEV_HOST; + +// https://vite.dev/config/ +export default defineConfig(async () => ({ + plugins: [sveltekit(), tailwindcss()], + clearScreen: false, + server: { + port: 1420, + strictPort: true, + host: host || false, + hmr: host + ? { + protocol: "ws", + host, + port: 1421, + } + : undefined, + watch: { + ignored: ["**/src-tauri/**"], + }, + }, +}));