Create initial Visual Studio Code extension

finchie
Nov 26, 2025, 8:45 AM
WFWTKCJNC4VSURSQWE5FXJGTEJJOCDMQ6LN2O6EW2DNOVT2ZUMRQC

Dependencies

Change contents

  • file addition: xtask (d--r------)
    [2.1]
  • file addition: src (d--r------)
    [0.17]
  • file addition: main.rs (----------)
    [0.34]
    use camino::Utf8PathBuf;
    use clap::Parser;
    mod build;
    #[derive(Debug, clap::Parser)]
    pub enum SubCommand {
    Build(build::Args),
    }
    #[derive(Clone, Copy, Debug, clap::ValueEnum)]
    pub enum ExtensionTarget {
    #[value(name = "vscode")]
    VisualStudioCode,
    }
    impl ExtensionTarget {
    pub fn name(&self) -> &str {
    match self {
    ExtensionTarget::VisualStudioCode => "vscode",
    }
    }
    pub fn base_path(&self, metadata: &cargo_metadata::Metadata) -> Utf8PathBuf {
    // TODO: get the workspace root
    let workspace_root = &metadata.workspace_root;
    assert!(workspace_root.exists());
    assert!(workspace_root.is_dir());
    let path = workspace_root.join("extensions").join(self.name());
    assert!(path.exists());
    assert!(path.is_dir());
    path
    }
    }
    fn main() -> Result<(), anyhow::Error> {
    let sub_command = SubCommand::parse();
    let metadata = cargo_metadata::MetadataCommand::new().exec()?;
    match sub_command {
    SubCommand::Build(args) => args.run(&metadata),
    }
    }
  • file addition: build.rs (----------)
    [0.34]
    use std::process::Command;
    use crate::ExtensionTarget;
    #[derive(Debug, clap::Parser)]
    pub struct Args {
    #[arg(value_enum)]
    extension_target: ExtensionTarget,
    }
    impl Args {
    pub fn run(&self, metadata: &cargo_metadata::Metadata) -> Result<(), anyhow::Error> {
    let base_path = self.extension_target.base_path(metadata);
    // TODO: walk the tree before/after build to make sure no artifacts were missed
    match self.extension_target {
    ExtensionTarget::VisualStudioCode => {
    // Steps:
    // 1. Install all dependencies
    // 2. Build native Rust module
    // 3. Build TypeScript code
    let out_dir = base_path.join("out");
    let native_module = out_dir.join("native-module");
    std::fs::create_dir_all(&out_dir)?;
    std::fs::create_dir_all(&native_module)?;
    // TODO: pnpm install?
    // TODO: release builds
    // TODO: multiple targets
    let mut rust_build = Command::new("pnpm");
    rust_build.current_dir(&base_path);
    rust_build.args([
    "exec",
    "napi",
    "build",
    "--platform",
    "--output-dir",
    native_module.as_str(),
    "--target",
    "x86_64-unknown-linux-gnu",
    ]);
    let rust_exit_status = rust_build.status()?;
    assert!(rust_exit_status.success());
    let mut typescript_build = Command::new("pnpm");
    typescript_build.current_dir(base_path);
    typescript_build.args(["exec", "tsc", "--outDir", out_dir.as_str()]);
    let typescript_exit_status = typescript_build.status()?;
    assert!(typescript_exit_status.success());
    }
    }
    Ok(())
    }
    }
  • file addition: Cargo.toml (----------)
    [0.17]
    [package]
    name = "xtask"
    publish = false
    description = "Build scripts using the cargo-xtask pattern"
    # Keys inherited from workspace
    authors.workspace = true
    categories.workspace = true
    edition.workspace = true
    keywords.workspace = true
    license.workspace = true
    repository.workspace = true
    version.workspace = true
    [dependencies]
    anyhow.workspace = true
    camino.workspace = true
    cargo_metadata.workspace = true
    clap.workspace = true
  • file addition: pijul-extension (d--r------)
    [2.1]
  • file addition: src (d--r------)
    [0.3664]
  • file addition: untracked.rs (----------)
    [0.3681]
    // TODO: rewrite to be generic over filesystem implementations
    use std::collections::HashSet;
    use camino::{Utf8Path, Utf8PathBuf};
    use canonical_path::CanonicalPathBuf;
    use libpijul::pristine::sanakirja::{MutTxn, SanakirjaError};
    use libpijul::{ArcTxn, TxnTExt};
    #[derive(Debug, thiserror::Error)]
    pub enum UntrackedItemError {
    #[error("unable to get untracked path from filesystem: {0:#?}")]
    IO(std::io::Error),
    #[error("unable to check if path is tracked: {0:#?}")]
    IsTracked(SanakirjaError),
    #[error("unable to convert `{invalid_path:#?}` to UTF-8: {conversion_error:#?}")]
    Utf8Path {
    invalid_path: std::path::PathBuf,
    conversion_error: camino::FromPathBufError,
    },
    }
    #[derive(Debug, thiserror::Error)]
    #[error(transparent)]
    pub enum UntrackedError {
    #[error("unable to get available parallelism: {0:#?}")]
    AvailableParallelism(std::io::Error),
    #[error("unable to canonicalize root path `{root_path}`: {io_error:#?}")]
    CanonicalRoot {
    root_path: Utf8PathBuf,
    io_error: std::io::Error,
    },
    #[error("unable to iterate untracked files: {0:#?}")]
    Iteration(std::io::Error),
    #[error(transparent)]
    IterationItem(#[from] UntrackedItemError),
    }
    pub fn file_system(
    root: &Utf8Path,
    file_system: &libpijul::working_copy::FileSystem,
    transaction: ArcTxn<MutTxn<()>>,
    ) -> Result<HashSet<Utf8PathBuf>, UntrackedError> {
    let untracked_items_transaction = transaction.clone();
    let canonical_path =
    CanonicalPathBuf::canonicalize(root).map_err(|io_error| UntrackedError::CanonicalRoot {
    root_path: root.to_path_buf(),
    io_error,
    })?;
    let untracked_files: HashSet<Utf8PathBuf> = file_system
    .iterate_prefix_rec(
    canonical_path.clone(),
    canonical_path,
    false,
    std::thread::available_parallelism()
    .map_err(UntrackedError::AvailableParallelism)?
    .get(),
    // Follow all paths
    |_path, _is_directory| true,
    )
    .map_err(UntrackedError::Iteration)?
    // Handle any errors in iteration
    .map(|filesystem_result| match filesystem_result {
    Ok((path, _is_directory)) => {
    Utf8PathBuf::try_from(path.clone()).map_err(|conversion_error| {
    UntrackedItemError::Utf8Path {
    invalid_path: path,
    conversion_error,
    }
    })
    }
    Err(io_error) => Err(UntrackedItemError::IO(io_error)),
    })
    // Filter out tracked paths
    .filter_map(|path_result| match path_result {
    Ok(path) => match untracked_items_transaction.read().is_tracked(path.as_str()) {
    Ok(true) => None,
    Ok(false) => Some(Ok(path)),
    Err(error) => Some(Err(UntrackedItemError::IsTracked(error))),
    },
    Err(error) => Some(Err(error)),
    })
    .collect::<Result<_, UntrackedItemError>>()?;
    Ok(untracked_files)
    }
  • file addition: modified_paths.rs (----------)
    [0.3681]
    use std::collections::HashMap;
    use camino::Utf8PathBuf;
    use libpijul::change::BaseHunk;
    use libpijul::changestore::ChangeStore;
    use libpijul::pristine::sanakirja::{MutTxn, SanakirjaError};
    use libpijul::working_copy::WorkingCopy;
    use libpijul::{ArcTxn, ChannelRef, RecordBuilder};
    use crate::TrackedState;
    #[derive(Debug, thiserror::Error)]
    pub enum ModifiedPathsError<C: std::error::Error + 'static, W: std::error::Error> {
    Globalize(#[from] SanakirjaError),
    Record(#[from] libpijul::record::RecordError<C, W, MutTxn<()>>),
    }
    pub fn modified_paths<C, W>(
    transaction: &ArcTxn<MutTxn<()>>,
    channel: &ChannelRef<MutTxn<()>>,
    working_copy: &W,
    change_store: &C,
    ) -> Result<HashMap<Utf8PathBuf, TrackedState>, ModifiedPathsError<C::Error, W::Error>>
    where
    C: ChangeStore + Clone + Send + 'static,
    W: WorkingCopy + Clone + Send + Sync + 'static,
    {
    let mut unrecorded_changes = RecordBuilder::new();
    unrecorded_changes.record(
    transaction.clone(),
    libpijul::Algorithm::default(),
    false, // TODO: check and document
    &libpijul::DEFAULT_SEPARATOR,
    channel.clone(),
    working_copy,
    change_store,
    "",
    1, // TODO: figure out concurrency model
    )?;
    let unrecorded_state = unrecorded_changes.finish();
    let mut modified_paths = HashMap::new();
    for hunk in unrecorded_state.actions {
    match hunk {
    BaseHunk::FileMove { path, .. } => {
    modified_paths
    .entry(Utf8PathBuf::from(path))
    .and_modify(|path_state| match path_state {
    TrackedState::Modified => *path_state = TrackedState::ModifiedAndMoved,
    _ => unreachable!("{path_state:#?}"),
    })
    .or_insert(TrackedState::Moved);
    }
    BaseHunk::FileDel { path, .. } => {
    modified_paths
    .try_insert(Utf8PathBuf::from(path), TrackedState::Removed)
    .unwrap();
    }
    BaseHunk::FileAdd { path, .. } => {
    modified_paths
    .try_insert(Utf8PathBuf::from(path), TrackedState::Added)
    .unwrap();
    }
    BaseHunk::Edit { local, .. } | BaseHunk::Replacement { local, .. } => {
    modified_paths
    .entry(Utf8PathBuf::from(local.path))
    .and_modify(|path_state| match path_state {
    TrackedState::Modified => (),
    TrackedState::Moved => *path_state = TrackedState::ModifiedAndMoved,
    _ => unreachable!("{path_state:#?}"),
    })
    .or_insert(TrackedState::Modified);
    }
    // TODO: FileUndel
    // TODO: conflicts
    _ => continue,
    }
    }
    Ok(modified_paths)
    }
  • file addition: lib.rs (----------)
    [0.3681]
    #![feature(map_try_insert)]
    // TODO: cache wherever possible
    // TODO: audit pub fields
    // TODO: changestore/pristine FileSystem integration should integrate with WorkingCopy(Read) traits
    // TODO: test against memfs to make sure alternative filesystems are supported https://github.com/microsoft/vscode-extension-samples/blob/main/fsprovider-sample/README.md
    // TODO: zero-copy data if possible?
    // TODO: try do one transaction per function call (no inline .read() etc) - unless maybe if only one read/write call?
    // TODO: atomic updates to everything? e.g. write working copy and pristine in one go so everything stays in sync
    // TODO: inject like 10secs of latency everywhere to make sure cancellation works properly (same for any await point - could introduce TOCTOU bugs)
    // TODO: update tracked state when externally modified on disk (e.g. pijul command directly) - and figure out how to test this?
    // TODO: make sure paths are based in the root of the repo
    use std::collections::{HashMap, HashSet};
    use camino::{Utf8Path, Utf8PathBuf};
    use libpijul::change::ChangeHeader;
    use libpijul::changestore;
    use libpijul::changestore::ChangeStore;
    use libpijul::pristine::TxnErr;
    use libpijul::pristine::sanakirja::{MutTxn, Pristine, SanakirjaError};
    use libpijul::working_copy::WorkingCopy;
    use libpijul::working_copy::{self, WorkingCopyRead};
    use libpijul::{ArcTxn, ChangeId, ChannelRef, TxnT};
    use crate::author::{AuthorSource, Authors};
    use crate::channel_state::{ChannelState, ChannelStateError};
    use crate::file_system::changes::unrecorded::UnrecordedChangesError;
    use crate::file_system::open_file::{OpenFile, OpenFileError};
    use crate::file_system::working_copy::EditorWorkingCopy;
    use crate::modified_paths::ModifiedPathsError;
    pub mod author;
    pub mod channel_state;
    pub mod file_system;
    pub mod modified_paths;
    pub mod untracked;
    #[derive(Debug, thiserror::Error)]
    pub enum RepositoryError<C: std::error::Error + 'static, W: std::error::Error + 'static> {
    #[error("unable to open pristine: {0:#?}")]
    Pristine(#[from] SanakirjaError),
    #[error("unable to begin transaction: {0:#?}")]
    BeginTransaction(#[from] BeginTransactionError),
    #[error("unable to get untracked paths: {0:#?}")]
    Untracked(#[from] untracked::UntrackedError),
    #[error("failed to log changes: {0:#?}")]
    Changes(#[from] ChannelStateError<C>),
    #[error("unable to get modified paths: {0:#?}")]
    Modified(#[from] ModifiedPathsError<C, W>),
    }
    #[derive(Debug, thiserror::Error)]
    pub enum BeginTransactionError {
    #[error("unable to begin transaction: {0:#?}")]
    Transaction(#[from] SanakirjaError),
    #[error("unable to open channel: {0:#?}")]
    Channel(#[from] TxnErr<SanakirjaError>),
    }
    #[derive(Debug, thiserror::Error)]
    pub enum CreditError {
    #[error("error while checking if `{path}` is tracked: {error:#?}")]
    GetIsTracked {
    path: Utf8PathBuf,
    error: SanakirjaError,
    },
    #[error("missing open file for {0}")]
    MissingOpenFile(Utf8PathBuf),
    }
    #[derive(Debug, thiserror::Error)]
    pub enum CreateOpenFileError<C: std::error::Error + 'static, W: std::error::Error + 'static> {
    #[error("unable to get metadata for file: {0:?}")]
    FileMetadata(W),
    #[error(transparent)]
    OpenFile(#[from] OpenFileError<C>),
    #[error("File already open at {0}")]
    AlreadyOpen(Utf8PathBuf),
    }
    #[derive(Debug, thiserror::Error)]
    pub enum UpdateOpenFileError<C: std::error::Error + 'static> {
    #[error(transparent)]
    UnrecordedChanges(#[from] UnrecordedChangesError<C>),
    #[error("No file open at {0}")]
    NoMatchingFile(Utf8PathBuf),
    #[error("Unable to begin transaction: {0:#?}")]
    BeginTransaction(#[from] BeginTransactionError),
    }
    #[derive(Clone, Copy, Debug)]
    pub enum TrackedState {
    Added,
    Removed,
    Modified,
    Moved,
    ModifiedAndMoved,
    }
    #[derive(Debug)]
    pub enum PathState {
    Untracked,
    Tracked(TrackedState),
    }
    pub type FileSystemRepository =
    Repository<changestore::filesystem::FileSystem, working_copy::FileSystem>;
    pub struct Repository<C, W>
    where
    C: ChangeStore + Clone + Send + 'static,
    W: WorkingCopy + Clone + Send + Sync + 'static,
    {
    pub authors: Authors,
    pub channel_state: ChannelState,
    pub working_copy: EditorWorkingCopy<W>,
    // TODO: use a trie
    pub untracked: HashSet<Utf8PathBuf>,
    pub modified_paths: HashMap<Utf8PathBuf, TrackedState>,
    pub change_store: C,
    pub pristine: Pristine,
    }
    impl FileSystemRepository {
    pub fn new(
    root: &Utf8Path,
    // TODO: take open files here
    ) -> Result<Self, RepositoryError<changestore::filesystem::Error, std::io::Error>> {
    let dot_directory = root.join(libpijul::DOT_DIR);
    let change_store = changestore::filesystem::FileSystem::from_root(root.as_str(), 256);
    let pristine = Pristine::new(dot_directory.join("pristine").join("db").as_str())?;
    let file_system = working_copy::FileSystem::from_root(root.as_str());
    let (transaction, channel) = begin_transaction(&pristine)?;
    let working_copy = EditorWorkingCopy::new(file_system);
    let channel_state = ChannelState::new(&transaction, &channel, &change_store)?;
    let authors = Authors::new(&channel_state, &dot_directory);
    let untracked =
    untracked::file_system(root, &working_copy.working_copy, transaction.clone())?;
    let modified_paths = modified_paths::modified_paths(
    &transaction,
    &channel,
    &working_copy.working_copy,
    &change_store,
    )?;
    Ok(Self {
    authors,
    channel_state,
    working_copy,
    untracked,
    modified_paths,
    change_store,
    pristine,
    })
    }
    }
    impl<C, W> Repository<C, W>
    where
    C: ChangeStore + Clone + Send + 'static,
    W: WorkingCopy + Clone + Send + Sync + 'static,
    {
    pub fn get_change_header(&self, change_id: &ChangeId) -> Option<&ChangeHeader> {
    self.channel_state.get_change_header(change_id)
    }
    pub fn get_path_state(&self, path: &Utf8Path) -> Option<PathState> {
    if self.untracked.contains(path) {
    Some(PathState::Untracked)
    } else {
    self.modified_paths
    .get(path)
    .map(|path_state| PathState::Tracked(*path_state))
    }
    }
    pub fn is_untracked(&self, path: &Utf8Path) -> bool {
    self.untracked.contains(path)
    }
    pub fn iter_modified(&self) -> impl Iterator<Item = &Utf8PathBuf> {
    self.modified_paths.keys()
    }
    pub fn iter_untracked(&self) -> impl Iterator<Item = &Utf8PathBuf> {
    self.untracked.iter()
    }
    pub fn authors_for_change(&self, change_header: &ChangeHeader) -> Vec<&AuthorSource> {
    self.authors.authors_for_change(change_header)
    }
    pub fn create_open_file(
    &mut self,
    path: Utf8PathBuf,
    file_contents: String,
    ) -> Result<(), CreateOpenFileError<C::Error, W::Error>> {
    let metadata = self
    .working_copy
    .file_metadata(path.as_str())
    .map_err(CreateOpenFileError::FileMetadata)?;
    let (transaction, channel) = begin_transaction(&self.pristine).unwrap();
    let open_file = OpenFile::open(
    path.clone(),
    file_contents,
    metadata,
    &transaction,
    &channel,
    &self.change_store,
    &self.working_copy,
    )?;
    self.working_copy
    .open_files
    .try_insert(path.clone(), open_file)
    .map_err(|_error| CreateOpenFileError::AlreadyOpen(path))?;
    Ok(())
    }
    pub fn update_open_file(
    &mut self,
    path: &Utf8Path,
    character_offset: usize,
    characters_replaced: usize,
    replacement_text: &str,
    ) -> Result<(), UpdateOpenFileError<C::Error>> {
    let open_file = self
    .working_copy
    .open_files
    .get_mut(path)
    .ok_or_else(|| UpdateOpenFileError::NoMatchingFile(path.to_path_buf()))?;
    let (transaction, channel) = begin_transaction(&self.pristine)?;
    open_file.update(
    character_offset,
    characters_replaced,
    replacement_text,
    &transaction,
    &channel,
    &self.change_store,
    )?;
    Ok(())
    }
    pub fn get_open_file(&self, path: &Utf8Path) -> Option<&OpenFile> {
    self.working_copy.open_files.get(path)
    }
    }
    fn begin_transaction(
    pristine: &Pristine,
    ) -> Result<(ArcTxn<MutTxn<()>>, ChannelRef<MutTxn<()>>), BeginTransactionError> {
    let transaction = pristine.arc_txn_begin()?;
    let channel = transaction
    .read()
    .load_channel(
    transaction
    .read()
    .current_channel()
    .unwrap_or(libpijul::DEFAULT_CHANNEL),
    )?
    .unwrap();
    Ok((transaction, channel))
    }
  • file addition: file_system (d--r------)
    [0.3681]
  • file addition: working_copy.rs (----------)
    [0.18874]
    use std::collections::HashMap;
    use camino::{Utf8Path, Utf8PathBuf};
    use libpijul::working_copy::WorkingCopy;
    use libpijul::working_copy::WorkingCopyRead;
    use crate::file_system::open_file::OpenFile;
    #[derive(Clone)]
    pub struct EditorWorkingCopy<W: WorkingCopy + Clone + Send + Sync + 'static> {
    pub working_copy: W,
    pub open_files: HashMap<Utf8PathBuf, OpenFile>,
    }
    impl<W: WorkingCopy + Clone + Send + Sync + 'static> EditorWorkingCopy<W> {
    pub fn new(working_copy: W) -> Self {
    Self {
    working_copy,
    open_files: HashMap::new(),
    }
    }
    }
    impl<W: WorkingCopy + Clone + Send + Sync + 'static> WorkingCopyRead for EditorWorkingCopy<W> {
    type Error = W::Error;
    fn file_metadata(&self, file: &str) -> Result<libpijul::pristine::InodeMetadata, Self::Error> {
    self.working_copy.file_metadata(file)
    }
    fn read_file(&self, file: &str, buffer: &mut Vec<u8>) -> Result<(), Self::Error> {
    match self.open_files.get(Utf8Path::new(file)) {
    Some(open_file) => buffer.extend(open_file.contents.text.bytes()),
    None => self.working_copy.read_file(file, buffer)?,
    }
    Ok(())
    }
    fn modified_time(&self, file: &str) -> Result<std::time::SystemTime, Self::Error> {
    match self.open_files.get(Utf8Path::new(file)) {
    Some(open_file) => Ok(open_file.contents.modified_time),
    None => self.working_copy.modified_time(file),
    }
    }
    }
  • file addition: open_file (d--r------)
    [0.18874]
  • file addition: mod.rs (----------)
    [0.20423]
    use std::ops::RangeInclusive;
    use camino::Utf8PathBuf;
    use libpijul::ArcTxn;
    use libpijul::ChannelRef;
    use libpijul::TxnTExt;
    use libpijul::changestore::ChangeStore;
    use libpijul::pristine::InodeMetadata;
    use libpijul::pristine::sanakirja::MutTxn;
    use libpijul::pristine::sanakirja::SanakirjaError;
    use libpijul::working_copy::WorkingCopyRead;
    use crate::file_system::changes::CreditSource;
    use crate::file_system::changes::FileCredits;
    use crate::file_system::changes::FileCreditsError;
    use crate::file_system::changes::Span;
    use crate::file_system::changes::unrecorded::UnrecordedChangesError;
    use crate::file_system::open_file::contents::FileContents;
    pub mod contents;
    #[derive(Debug, thiserror::Error)]
    pub enum OpenFileError<C: std::error::Error + 'static> {
    #[error("failed to check if {path} is tracked: {error:#?}")]
    CheckIfTracked {
    path: Utf8PathBuf,
    error: SanakirjaError,
    },
    #[error(transparent)]
    FileChanges(#[from] UnrecordedChangesError<C>),
    #[error(transparent)]
    TrackedFile(#[from] FileCreditsError<C>),
    }
    #[derive(Clone, Debug)]
    pub struct OpenFile {
    pub contents: FileContents,
    pub credits: Option<FileCredits>,
    }
    impl OpenFile {
    pub fn open<C, W>(
    path: Utf8PathBuf,
    file_contents: String,
    metadata: InodeMetadata,
    transaction: &ArcTxn<MutTxn<()>>,
    channel: &ChannelRef<MutTxn<()>>,
    change_store: &C,
    working_copy: &W,
    ) -> Result<Self, OpenFileError<C::Error>>
    where
    C: ChangeStore + Clone + Send + 'static,
    W: WorkingCopyRead,
    {
    let contents = FileContents::new(path.clone(), metadata, file_contents, working_copy);
    let credits = if transaction
    .read()
    .is_tracked(path.as_str())
    .map_err(|error| OpenFileError::CheckIfTracked { path, error })?
    {
    Some(FileCredits::new(
    &contents,
    transaction,
    channel,
    change_store,
    )?)
    } else {
    None
    };
    Ok(Self { contents, credits })
    }
    pub fn update<C>(
    &mut self,
    character_offset: usize,
    characters_replaced: usize,
    replacement_text: &str,
    transaction: &ArcTxn<MutTxn<()>>,
    channel: &ChannelRef<MutTxn<()>>,
    change_store: &C,
    ) -> Result<(), UnrecordedChangesError<C::Error>>
    where
    C: ChangeStore + Clone + Send + 'static,
    {
    if characters_replaced > 0 {
    self.contents
    .text
    .remove(character_offset..(character_offset + characters_replaced));
    }
    if !replacement_text.is_empty() {
    self.contents
    .text
    .insert(character_offset, replacement_text);
    }
    if let Some(credits) = &mut self.credits {
    // TODO: only re-compute spans that were affected
    credits.recompute_spans(&self.contents, transaction, channel, change_store)?;
    }
    Ok(())
    }
    pub fn credit(&self, lines: RangeInclusive<usize>) -> Vec<Span<CreditSource>> {
    match &self.credits {
    Some(credits) => credits.spans_within_lines(lines).collect(),
    None => Vec::from([Span {
    value: CreditSource::Untracked,
    lines,
    }]),
    }
    }
    pub fn tracked_contents(&self) -> String {
    self.contents.text.to_string()
    }
    }
  • file addition: contents.rs (----------)
    [0.20423]
    use std::time::SystemTime;
    use camino::Utf8PathBuf;
    use libpijul::pristine::InodeMetadata;
    use libpijul::working_copy::WorkingCopyRead;
    use ropey::Rope;
    #[derive(Debug, thiserror::Error)]
    pub enum FileContentsError {
    #[error("Invalid path: expected {expected_path:?}, got {incorrect_path:?}")]
    InvalidPath {
    expected_path: Utf8PathBuf,
    incorrect_path: Utf8PathBuf,
    },
    }
    #[derive(Clone, Debug)]
    pub struct FileContents {
    // TODO: path shouldn't be stored here
    pub path: Utf8PathBuf,
    pub metadata: InodeMetadata,
    pub modified_time: SystemTime,
    pub text: Rope,
    }
    impl FileContents {
    pub fn new<W: WorkingCopyRead>(
    path: Utf8PathBuf,
    metadata: InodeMetadata,
    contents: String,
    working_copy: &W,
    ) -> Self {
    let last_modified_time = working_copy
    .modified_time(path.as_str())
    .unwrap_or(SystemTime::now());
    Self {
    path,
    metadata,
    modified_time: last_modified_time,
    text: Rope::from(contents),
    }
    }
    }
    // TODO: implement `WorkingCopyRead` for `EditorWorkingCopy` instead?
    impl WorkingCopyRead for FileContents {
    type Error = FileContentsError;
    fn file_metadata(&self, file: &str) -> Result<InodeMetadata, Self::Error> {
    if file != self.path.as_str() {
    return Err(FileContentsError::InvalidPath {
    expected_path: self.path.clone(),
    incorrect_path: Utf8PathBuf::from(file),
    });
    }
    Ok(self.metadata)
    }
    fn read_file(&self, file: &str, buffer: &mut Vec<u8>) -> Result<(), Self::Error> {
    if file != self.path.as_str() {
    return Err(FileContentsError::InvalidPath {
    expected_path: self.path.clone(),
    incorrect_path: Utf8PathBuf::from(file),
    });
    }
    buffer.extend(self.text.bytes());
    Ok(())
    }
    fn modified_time(&self, file: &str) -> Result<SystemTime, Self::Error> {
    if file != self.path.as_str() {
    return Err(FileContentsError::InvalidPath {
    expected_path: self.path.clone(),
    incorrect_path: Utf8PathBuf::from(file),
    });
    }
    Ok(self.modified_time)
    }
    }
  • file addition: mod.rs (----------)
    [0.18874]
    pub mod changes;
    pub mod open_file;
    pub mod working_copy;
  • file addition: changes (d--r------)
    [0.18874]
  • file addition: unrecorded.rs (----------)
    [0.26417]
    use libpijul::change::{Atom, BaseHunk, TextSerError};
    use libpijul::changestore::ChangeStore;
    use libpijul::pristine::sanakirja::{MutTxn, SanakirjaError};
    use libpijul::{ArcTxn, ChannelRef, RecordBuilder};
    use crate::file_system::changes::Span;
    use crate::file_system::open_file::contents::{FileContents, FileContentsError};
    #[derive(Debug, thiserror::Error)]
    #[error(transparent)]
    pub enum UnrecordedChangesError<C: std::error::Error + 'static> {
    ChangeContents(#[from] TextSerError<C>),
    Globalize(#[from] SanakirjaError),
    Record(#[from] libpijul::record::RecordError<C, FileContentsError, MutTxn<()>>),
    }
    #[derive(Clone, Copy, Debug)]
    pub enum SpanKind {
    Replacement {
    old_line_count: usize,
    new_line_count: usize,
    },
    Addition {
    lines_added: usize,
    },
    Deletion {
    lines_removed: usize,
    },
    }
    #[derive(Clone, Debug)]
    pub struct UnrecordedChanges {
    pub spans: Vec<Span<SpanKind>>,
    }
    impl UnrecordedChanges {
    pub fn new<C>(
    file: &FileContents,
    transaction: &ArcTxn<MutTxn<()>>,
    channel: &ChannelRef<MutTxn<()>>,
    change_store: &C,
    ) -> Result<Self, UnrecordedChangesError<C::Error>>
    where
    C: ChangeStore + Clone + Send + 'static,
    {
    let mut unrecorded_changes = RecordBuilder::new();
    unrecorded_changes.record(
    transaction.clone(),
    libpijul::Algorithm::default(),
    false, // TODO: check and document
    &libpijul::DEFAULT_SEPARATOR,
    channel.clone(),
    file,
    change_store,
    file.path.as_str(),
    1, // TODO: figure out concurrency model
    )?;
    let unrecorded_state = unrecorded_changes.finish();
    let change_contents = unrecorded_state.contents.lock();
    let mut unrecorded_spans = Vec::new();
    // TODO: handle encoding
    for hunk in unrecorded_state.actions {
    let globalized_hunk = hunk.globalize(&*transaction.read())?;
    match globalized_hunk {
    BaseHunk::Replacement {
    change,
    replacement,
    local,
    encoding,
    } => {
    let old_contents = libpijul::change::get_change_contents(
    change_store,
    &change,
    &change_contents,
    )?;
    let new_contents = libpijul::change::get_change_contents(
    change_store,
    &replacement,
    &change_contents,
    )?;
    let old_text = String::from_utf8(old_contents).unwrap();
    let new_text = String::from_utf8(new_contents).unwrap();
    let old_line_count = old_text.lines().count().strict_sub(1);
    let new_line_count = new_text.lines().count().strict_sub(1);
    let span_start = local.line - 1;
    unrecorded_spans.push(Span {
    value: SpanKind::Replacement {
    old_line_count,
    new_line_count,
    },
    lines: span_start..=span_start.strict_add(new_line_count),
    });
    }
    BaseHunk::Edit {
    change,
    local,
    encoding,
    } => {
    let new_contents = libpijul::change::get_change_contents(
    change_store,
    &change,
    &change_contents,
    )?;
    let text = String::from_utf8(new_contents).unwrap();
    let line_count = text.lines().count();
    let span_start = local.line - 1;
    // Skip deletions as they don't contribute any spans
    let span = if let Atom::EdgeMap(edge) = change
    && (edge.edges.is_empty() || edge.edges[0].flag.is_deleted())
    {
    Span {
    value: SpanKind::Deletion {
    lines_removed: line_count,
    },
    lines: span_start..=span_start,
    }
    } else {
    Span {
    value: SpanKind::Addition {
    lines_added: line_count,
    },
    lines: span_start..=(span_start + line_count - 1),
    }
    };
    unrecorded_spans.push(span);
    }
    // TODO: handle conflict resolution
    // TODO: handle moves
    _ => {
    tracing::warn!(message = "Skipping unrecorded hunk", ?globalized_hunk);
    }
    }
    }
    unrecorded_spans.sort_by_key(|span| *span.lines.start());
    Ok(Self {
    spans: unrecorded_spans,
    })
    }
    }
  • file addition: recorded.rs (----------)
    [0.26417]
    use std::ops::RangeInclusive;
    use std::sync::OnceLock;
    use camino::Utf8Path;
    use libpijul::changestore::ChangeStore;
    use libpijul::pristine::sanakirja::{MutTxn, SanakirjaError};
    use libpijul::vertex_buffer::VertexBuffer;
    use libpijul::{ArcTxn, ChangeId, ChannelRef, TxnTExt, Vertex};
    use crate::file_system::changes::{CreditSource, Span};
    #[derive(Debug, thiserror::Error)]
    pub enum RecordedStateError<C: std::error::Error + 'static> {
    #[error("unable to find oldest vertex: {0:#?}")]
    OldestVertex(#[from] libpijul::fs::FsErrorC<C, MutTxn<()>>),
    #[error("unable to output file: {0:#?}")]
    OutputFile(#[from] libpijul::output::FileError<C, MutTxn<()>>),
    #[error("unable to get external hash for {change_id:#?}")]
    ExternalHash {
    change_id: libpijul::pristine::ChangeId,
    error: libpijul::pristine::TxnErr<SanakirjaError>,
    },
    #[error("no matching external hash for change ID: {0:#?}")]
    MissingExternalHash(libpijul::pristine::ChangeId),
    #[error("unable to get hash from changestore: {0:#?}")]
    ChangeStore(C),
    }
    // TODO: reference diff::vertex_buffer::Diff file:///home/finchie/Projects/Pijul/pijul/target/doc/libpijul/diff/vertex_buffer/struct.Diff.html
    struct ChangesBuffer {
    introduced_by: OnceLock<ChangeId>,
    original_contents: String,
    spans: Vec<Span<ChangeId>>,
    }
    // TODO: don't assume encoding
    #[derive(Clone, Debug)]
    pub struct RecordedState {
    pub introduced_by: ChangeId,
    pub original_contents: String,
    pub spans: Vec<Span<ChangeId>>,
    }
    impl RecordedState {
    pub fn new<C>(
    path: &Utf8Path,
    transaction: &ArcTxn<MutTxn<()>>,
    channel: &ChannelRef<MutTxn<()>>,
    change_store: &C,
    ) -> Result<Self, RecordedStateError<C::Error>>
    where
    C: ChangeStore,
    {
    // TODO: handle ambiguity (possibly when there is a path conflict?)
    let (oldest_vertex, _ambiguous) =
    transaction
    .read()
    .follow_oldest_path(change_store, channel, path.as_str())?;
    let mut changes_buffer = ChangesBuffer {
    introduced_by: OnceLock::new(),
    original_contents: String::new(),
    spans: Vec::new(),
    };
    libpijul::output::output_file(
    change_store,
    transaction,
    channel,
    oldest_vertex,
    &mut changes_buffer,
    )?;
    Ok(Self {
    introduced_by: changes_buffer.introduced_by.take().unwrap(),
    original_contents: changes_buffer.original_contents,
    spans: changes_buffer.spans,
    })
    }
    pub fn spans_within_lines(
    &self,
    untracked_line_range: RangeInclusive<usize>,
    offset: isize,
    ) -> impl Iterator<Item = Span<CreditSource>> {
    let tracked_line_range = untracked_line_range.start().strict_add_signed(offset)
    ..=untracked_line_range.end().strict_add_signed(offset);
    Span::spans_within_lines(&self.spans, tracked_line_range).map(move |span| Span {
    value: CreditSource::Tracked(span.value),
    lines: (span.lines.start().strict_sub_signed(offset))
    ..=(span.lines.end().strict_sub_signed(offset)),
    })
    }
    }
    impl VertexBuffer for ChangesBuffer {
    fn output_line<E, F>(&mut self, vertex: Vertex<ChangeId>, contents: F) -> Result<(), E>
    where
    E: From<std::io::Error>,
    F: FnOnce(&mut [u8]) -> Result<(), E>,
    {
    // The first "line" output is an empty line representing the change that introduced the file
    if self.introduced_by.get().is_none() {
    self.introduced_by.set(vertex.change).unwrap();
    assert!(vertex.is_empty());
    return Ok(());
    }
    // The final "line" output is an empty line with an empty change ID
    if vertex.change.0.as_u64() == 0 {
    return Ok(());
    }
    assert!(!vertex.is_empty());
    assert!(!vertex.is_root());
    let mut buffer = vec![0; vertex.end - vertex.start];
    contents(&mut buffer)?;
    let contents = String::from_utf8(buffer).unwrap();
    // Keep track of the original contents
    self.original_contents.push_str(&contents);
    // Add the starting line and line count of the contents affected by this change ID
    let start_line = match self.spans.last() {
    Some(previous_span) => previous_span.next_span_start(),
    None => 0,
    };
    let length = contents.lines().count();
    self.spans.push(Span {
    value: vertex.change,
    lines: start_line..=(start_line + length - 1),
    });
    Ok(())
    }
    // TODO: handle all the conflict markers independently
    fn output_conflict_marker<C: libpijul::changestore::ChangeStore>(
    &mut self,
    s: &str,
    id: usize,
    sides: Option<(&C, &[&libpijul::Hash])>,
    ) -> Result<(), std::io::Error> {
    todo!("Conflict markers")
    }
    }
  • file addition: mod.rs (----------)
    [0.26417]
    use std::ops::RangeInclusive;
    use libpijul::changestore::ChangeStore;
    use libpijul::pristine::sanakirja::MutTxn;
    use libpijul::{ArcTxn, ChangeId, ChannelRef};
    use crate::file_system::changes::recorded::RecordedStateError;
    use crate::file_system::changes::unrecorded::UnrecordedChangesError;
    use crate::file_system::open_file::contents::FileContents;
    pub mod recorded;
    pub mod unrecorded;
    #[derive(Clone, Debug)]
    pub struct Span<T: std::fmt::Debug> {
    pub value: T,
    pub lines: RangeInclusive<usize>,
    }
    impl<T: Clone + std::fmt::Debug> Span<T> {
    pub fn next_span_start(&self) -> usize {
    self.lines.end() + 1
    }
    pub fn spans_within_lines(
    spans: &[Self],
    line_range: RangeInclusive<usize>,
    ) -> impl Iterator<Item = Self> {
    debug_assert!(
    line_range.start() <= line_range.end(),
    "Invalid range: {line_range:#?}"
    );
    debug_assert!(spans.is_sorted_by_key(|span| span.lines.start()));
    let lines_start = *line_range.start();
    let lines_end = *line_range.end();
    spans
    .iter()
    .skip_while(move |span| *span.lines.end() < lines_start)
    .take_while(move |span| *span.lines.start() <= lines_end)
    .filter_map(move |span| {
    let span_start = *span.lines.start().max(&lines_start);
    let span_end = *span.lines.end().min(&lines_end);
    if span_end >= span_start {
    Some(Span {
    value: span.value.clone(),
    lines: span_start..=span_end,
    })
    } else {
    None
    }
    })
    }
    }
    #[derive(Clone, Debug, PartialEq, Eq)]
    pub enum CreditSource {
    Tracked(ChangeId),
    Untracked,
    }
    #[derive(Debug, thiserror::Error)]
    pub enum FileCreditsError<C: std::error::Error + 'static> {
    #[error("unable to get tracked file state: {0:?}")]
    TrackedState(#[from] RecordedStateError<C>),
    #[error("unable to get untracked changes: {0:?}")]
    UntrackedChanges(#[from] UnrecordedChangesError<C>),
    }
    #[derive(Clone, Debug)]
    pub struct FileCredits {
    pub recorded_state: recorded::RecordedState,
    pub spans: Vec<Span<CreditSource>>,
    }
    impl FileCredits {
    pub fn new<C>(
    file: &FileContents,
    transaction: &ArcTxn<MutTxn<()>>,
    channel: &ChannelRef<MutTxn<()>>,
    change_store: &C,
    ) -> Result<Self, FileCreditsError<C::Error>>
    where
    C: ChangeStore + Clone + Send + 'static,
    {
    let state = recorded::RecordedState::new(&file.path, transaction, channel, change_store)?;
    let mut tracked_file = Self {
    recorded_state: state,
    spans: Vec::new(),
    };
    tracked_file.recompute_spans(file, transaction, channel, change_store)?;
    Ok(tracked_file)
    }
    pub fn recompute_spans<C>(
    &mut self,
    file: &FileContents,
    transaction: &ArcTxn<MutTxn<()>>,
    channel: &ChannelRef<MutTxn<()>>,
    change_store: &C,
    ) -> Result<(), UnrecordedChangesError<C::Error>>
    where
    C: ChangeStore + Clone + Send + 'static,
    {
    let untracked_changes =
    unrecorded::UnrecordedChanges::new(file, transaction, channel, change_store)?;
    let mut merged_spans = Vec::new();
    let mut untracked_spans = untracked_changes.spans.iter().peekable();
    let mut current_offset: isize = 0;
    let mut incomplete_span_start: Option<usize> = Some(0);
    while let Some(untracked_span) = untracked_spans.next() {
    if let Some(incomplete_span_start) = incomplete_span_start.take()
    && *untracked_span.lines.start() > incomplete_span_start
    {
    merged_spans.extend(self.recorded_state.spans_within_lines(
    incomplete_span_start..=(untracked_span.lines.start().strict_sub(1)),
    current_offset,
    ));
    }
    match untracked_span.value {
    unrecorded::SpanKind::Replacement {
    old_line_count,
    new_line_count,
    } => {
    merged_spans.push(Span {
    value: CreditSource::Untracked,
    lines: untracked_span.lines.clone(),
    });
    let replacement_line_offset =
    (new_line_count as isize).strict_add_unsigned(old_line_count);
    current_offset = current_offset.strict_add(replacement_line_offset);
    }
    unrecorded::SpanKind::Addition { lines_added } => {
    merged_spans.push(Span {
    value: CreditSource::Untracked,
    lines: untracked_span.lines.clone(),
    });
    current_offset = current_offset.strict_sub_unsigned(lines_added);
    }
    unrecorded::SpanKind::Deletion { lines_removed } => {
    // Deletions don't contribute any spans, only change the offset
    // to skip the deleted lines.
    current_offset = current_offset.strict_add_unsigned(lines_removed);
    incomplete_span_start = Some(*untracked_span.lines.start());
    }
    }
    if let Some(next_untracked_span) = untracked_spans.peek()
    && *next_untracked_span.lines.start() > untracked_span.next_span_start()
    {
    merged_spans.extend(self.recorded_state.spans_within_lines(
    untracked_span.next_span_start()..=(next_untracked_span.lines.start() - 1),
    current_offset,
    ));
    }
    }
    let file_length = file.text.len_lines(ropey::LineType::LF_CR).strict_sub(1);
    if let Some(final_span) = merged_spans.last()
    && *final_span.lines.end() < file_length.strict_sub(1)
    {
    merged_spans.extend(self.recorded_state.spans_within_lines(
    (final_span.lines.end() + 1)..=file_length.strict_sub(1),
    current_offset,
    ));
    }
    if merged_spans.is_empty() {
    merged_spans.extend(
    self.recorded_state
    .spans_within_lines(0..=file_length.strict_sub(1), 0),
    );
    }
    // If the final line ends in a newline, text editors will allow selecting the "next line"
    // For example: `Line 1\nLine 2\n` will be rendered as:
    // ```
    // Line 1
    // Line 2
    //
    // ```
    // So extend the span of line 2 (index 1) to include this empty line
    if let Some(final_span) = merged_spans.last_mut()
    && let Some(final_character) = file.text.chars().last()
    && final_character == '\n'
    {
    let start_line = *final_span.lines.start();
    let end_line = *final_span.lines.end();
    final_span.lines = start_line..=(end_line + 1);
    }
    // Check the spans were generated correctly
    if cfg!(debug_assertions) {
    let mut span_windows = merged_spans.windows(2);
    // Span ranges must be in order
    while let Some([first, second]) = span_windows.next() {
    assert_eq!(
    first.lines.end() + 1,
    *second.lines.start(),
    "Invalid span ranges: {merged_spans:#?}"
    )
    }
    // Entire file is covered
    let last_span_line = merged_spans
    .last()
    .map(|span| *span.lines.end())
    .unwrap_or(0);
    let last_text_lines = file.text.len_lines(ropey::LineType::LF_CR) - 1;
    assert_eq!(
    last_span_line, last_text_lines,
    "Incorrect span end (got {last_span_line}, expected {last_text_lines}): {merged_spans:#?}"
    );
    }
    // Combine consecutive spans of the same type into a single span
    merged_spans =
    merged_spans
    .into_iter()
    .fold(Vec::new(), |mut previous_spans, current_span| {
    if let Some(previous_span) = previous_spans.last_mut()
    && previous_span.value == current_span.value
    {
    let previous_start = *previous_span.lines.start();
    previous_span.lines = previous_start..=*current_span.lines.end();
    } else {
    previous_spans.push(current_span);
    }
    previous_spans
    });
    self.spans = merged_spans;
    Ok(())
    }
    // TODO: check that range is within limits?
    pub fn spans_within_lines(
    &self,
    line_range: RangeInclusive<usize>,
    ) -> impl Iterator<Item = Span<CreditSource>> {
    Span::spans_within_lines(&self.spans, line_range)
    }
    }
  • file addition: channel_state.rs (----------)
    [0.3681]
    use std::cell::OnceCell;
    use std::collections::HashMap;
    use libpijul::change::ChangeHeader;
    use libpijul::changestore::ChangeStore;
    use libpijul::pristine::TxnErr;
    use libpijul::pristine::sanakirja::{MutTxn, SanakirjaError};
    use libpijul::{ArcTxn, ChangeId, ChannelRef, GraphTxnT, TxnTExt};
    #[derive(Debug, thiserror::Error)]
    pub enum ChannelStateError<C: std::error::Error + 'static> {
    #[error("unable to iterate changes: {0:#?}")]
    ReverseLog(SanakirjaError),
    #[error("encountered error while iterating log: {0:#?}")]
    Item(SanakirjaError),
    #[error("unable to get external hash: {0:#?}")]
    InternalHash(TxnErr<SanakirjaError>),
    #[error("unable to read changes: {0:#?}")]
    ChangeStore(C),
    }
    pub struct ChannelState {
    root_change: ChangeId,
    changes: HashMap<ChangeId, ChangeHeader>,
    }
    impl ChannelState {
    pub fn new<C>(
    transaction: &ArcTxn<MutTxn<()>>,
    channel: &ChannelRef<MutTxn<()>>,
    change_store: &C,
    ) -> Result<Self, ChannelStateError<C::Error>>
    where
    C: ChangeStore + Clone + Send + 'static,
    {
    let mut changes = HashMap::new();
    let mut root_change = OnceCell::new();
    // TODO: authors
    // let mut authors = HashSet::new();
    let read_transaction = transaction.read();
    let mut reverse_log = read_transaction
    .reverse_log(&*channel.read(), None)
    .map_err(ChannelStateError::ReverseLog)?
    .peekable();
    while let Some(log_result) = reverse_log.next() {
    // TODO: merkle
    let (_, (hash, merkle)) = log_result.map_err(ChannelStateError::Item)?;
    let change_id = *read_transaction
    .get_internal(hash)
    .map_err(ChannelStateError::InternalHash)?
    .unwrap();
    // TODO: `change_id.is_root()` is broken?
    if reverse_log.peek().is_none() {
    root_change.set(change_id).unwrap();
    } else {
    let change_header = change_store
    .get_header(&hash.into())
    .map_err(ChannelStateError::ChangeStore)?;
    dbg!(&change_header.authors);
    changes.try_insert(change_id, change_header).unwrap();
    }
    }
    Ok(ChannelState {
    root_change: root_change.take().unwrap(),
    changes,
    })
    }
    pub fn get_change_header(&self, change_id: &ChangeId) -> Option<&ChangeHeader> {
    self.changes.get(change_id)
    }
    pub fn iter_change_headers(&self) -> impl Iterator<Item = &ChangeHeader> {
    self.changes.values()
    }
    }
  • file addition: author.rs (----------)
    [0.3681]
    use std::collections::HashMap;
    use std::collections::hash_map::Entry;
    use std::fs::File;
    use camino::Utf8Path;
    use libpijul::change::ChangeHeader;
    use crate::channel_state::ChannelState;
    #[derive(Clone, Debug)]
    pub enum AuthorSource {
    Local(pijul_identity::Complete),
    Remote(pijul_identity::Complete),
    Unknown(String),
    }
    pub struct Authors {
    authors: HashMap<String, AuthorSource>,
    }
    impl Authors {
    pub fn new(channel_state: &ChannelState, dot_directory: &Utf8Path) -> Self {
    let mut authors = HashMap::new();
    let repository_identities_path = dot_directory.join("identities");
    match pijul_identity::Complete::load_all() {
    Ok(local_identities) => {
    for local_identity in local_identities {
    let public_key_signature = local_identity.public_key.key.clone();
    match authors.entry(public_key_signature.clone()) {
    Entry::Occupied(occupied_entry) => {
    tracing::error!(
    message = "Duplicate local identities found",
    public_key_signature,
    previous_author = ?occupied_entry.get(),
    );
    }
    Entry::Vacant(vacant_entry) => {
    vacant_entry.insert(AuthorSource::Local(local_identity));
    }
    }
    }
    }
    Err(error) => tracing::error!(message = "Unable to load local identities", ?error),
    }
    for change_header in channel_state.iter_change_headers() {
    for serialized_author in &change_header.authors {
    match serialized_author.0.get("key") {
    Some(public_key_signature) => {
    if let Entry::Vacant(vacant_entry) =
    authors.entry(public_key_signature.to_owned())
    {
    // Try to read from `.pijul/identities/{public_key_signature}`
    let identity_path =
    repository_identities_path.join(public_key_signature);
    let author_source = match File::open(&identity_path) {
    Ok(identity_file) => match serde_json::from_reader(identity_file) {
    Ok(remote_identity) => AuthorSource::Remote(remote_identity),
    Err(error) => {
    tracing::error!(
    message = "Failed to deserialize identity file",
    ?identity_path,
    ?error
    );
    AuthorSource::Unknown(public_key_signature.to_owned())
    }
    },
    Err(error) => {
    tracing::error!(
    message = "Failed to open identity file",
    ?identity_path,
    ?error
    );
    AuthorSource::Unknown(public_key_signature.to_owned())
    }
    };
    vacant_entry.insert(author_source);
    }
    }
    None => {
    tracing::warn!(message = "Author missing `key` field", ?serialized_author);
    }
    }
    }
    }
    Self { authors }
    }
    pub fn authors_for_change(&self, change_header: &ChangeHeader) -> Vec<&AuthorSource> {
    let mut authors = Vec::new();
    for serialized_author in &change_header.authors {
    match serialized_author.0.get("key") {
    Some(public_key_signature) => match self.authors.get(public_key_signature) {
    Some(author) => {
    authors.push(author);
    }
    None => tracing::error!(
    message = "No matching author for key",
    public_key_signature,
    ?change_header
    ),
    },
    None => {
    tracing::warn!(message = "Author missing `key` field", ?serialized_author);
    }
    }
    }
    authors
    }
    }
  • file addition: Cargo.toml (----------)
    [0.3664]
    [package]
    name = "pijul-extension"
    version = "0.1.0"
    edition = "2024"
    [dependencies]
    camino.workspace = true
    canonical-path.workspace = true
    libpijul.workspace = true
    path-slash.workspace = true
    pijul-identity.workspace = true
    ropey.workspace = true
    serde_json.workspace = true
    thiserror.workspace = true
    tracing.workspace = true
  • file addition: extensions (d--r------)
    [2.1]
  • file addition: vscode (d--r------)
    [0.53748]
  • file addition: tsconfig.json (----------)
    [0.53768]
    {
    "compilerOptions": {
    "module": "Node16",
    "target": "ES2022",
    "outDir": "out",
    "lib": ["ES2022"],
    "sourceMap": true,
    "rootDir": "src",
    "strict": true /* enable all strict type-checking options */
    /* Additional Checks */
    // "noImplicitReturns": true, /* Report error when not all code paths in function return a value. */
    // "noFallthroughCasesInSwitch": true, /* Report errors for fallthrough cases in switch statement. */
    // "noUnusedParameters": true, /* Report errors on unused parameters. */
    }
    }
  • file addition: src (d--r------)
    [0.53768]
  • file addition: vscode_sys (d--r------)
    [0.54351]
  • file addition: workspace.rs (----------)
    [0.54375]
    use napi::bindgen_prelude;
    use napi::bindgen_prelude::JsObjectValue;
    use super::macros::{event_handler, namespace_field_getter, namespace_function, register_provider};
    use super::{
    TextDocument, TextDocumentChangeEvent, TextDocumentContentProvider, Uri, WorkspaceFolder,
    WorkspaceFoldersChangeEvent,
    };
    event_handler!(
    "workspace",
    "onDidChangeTextDocument",
    on_did_change_text_document(TextDocumentChangeEvent)
    );
    event_handler!(
    "workspace",
    "onDidChangeWorkspaceFolders",
    on_did_change_workspace_folders(WorkspaceFoldersChangeEvent)
    );
    namespace_field_getter! {
    "workspace" {
    "textDocuments": get_text_documents -> Vec<TextDocument<'env>>;
    "workspaceFolders": get_workspace_folders -> Vec<WorkspaceFolder<'env>>;
    }
    }
    namespace_function! {
    "workspace" {
    "getWorkspaceFolder":
    get_workspace_folder(
    uri: &Uri,
    ) -> Option<WorkspaceFolder<'env>>;
    }
    }
    register_provider!(
    "workspace",
    "registerTextDocumentContentProvider",
    register_text_document_content_provider(scheme: &str, provider: TextDocumentContentProvider<'env>)
    );
  • file addition: window.rs (----------)
    [0.54375]
    use napi::bindgen_prelude;
    use napi::bindgen_prelude::JsObjectValue;
    use super::macros::{event_handler, namespace_field_getter, namespace_function, register_provider};
    use super::{
    DecorationRenderOptions, FileDecorationProvider, TextEditor, TextEditorDecorationType,
    TextEditorSelectionChangeEvent,
    };
    event_handler!(
    "window",
    "onDidChangeTextEditorSelection",
    on_did_change_text_editor_selections(TextEditorSelectionChangeEvent)
    );
    event_handler!(
    "window",
    "onDidChangeVisibleTextEditors",
    on_did_change_visible_text_editors(Vec<TextEditor>)
    );
    namespace_field_getter! {
    "window" {
    "activeTextEditor": get_active_text_editor -> Option<TextEditor<'env>>;
    "visibleTextEditors": get_visible_text_editors -> Vec<TextEditor<'env>>;
    }
    }
    namespace_function! {
    "window" {
    "createTextEditorDecorationType":
    create_text_editor_decoration_type(
    render_options: DecorationRenderOptions,
    ) -> TextEditorDecorationType<'env>;
    }
    }
    register_provider!("window", "registerFileDecorationProvider", register_file_decoration_provider(provider: FileDecorationProvider));
    pub fn create_log_output_channel<'env>(
    env: &napi::Env,
    name: &str,
    ) -> Result<bindgen_prelude::Object<'env>, napi::Error> {
    let vscode_object = super::VscodeContext::vscode(env)?;
    let window: bindgen_prelude::Object = vscode_object.get_named_property("window")?;
    let function_prototype: bindgen_prelude::Function<
    bindgen_prelude::FnArgs<(&str, bindgen_prelude::Object)>,
    bindgen_prelude::Object,
    > = window.get_named_property("createOutputChannel")?;
    let mut options = bindgen_prelude::Object::new(env)?;
    options.set_named_property("log", true)?;
    let output_channel =
    function_prototype.apply(window, bindgen_prelude::FnArgs::from((name, options)))?;
    Ok(output_channel)
    }
  • file addition: scm.rs (----------)
    [0.54375]
    use napi::bindgen_prelude;
    use napi::bindgen_prelude::JsObjectValue;
    use super::macros::namespace_function;
    use super::{SourceControl, Uri};
    namespace_function! {
    "scm" {
    "createSourceControl":
    create_source_control(
    id: &str,
    label: &str,
    root_uri: &Uri,
    ) -> SourceControl<'env>;
    }
    }
  • file addition: reference.rs (----------)
    [0.54375]
    use napi::bindgen_prelude;
    use super::macros::object_reference;
    use super::{SourceControl, SourceControlResourceGroup, TextEditor, TextEditorDecorationType};
    object_reference!(SourceControlRef: SourceControl);
    object_reference!(SourceControlResourceGroupRef: SourceControlResourceGroup);
    object_reference!(TextEditorRef: TextEditor);
    object_reference!(TextEditorDecorationTypeRef: TextEditorDecorationType);
  • file addition: mod.rs (----------)
    [0.54375]
    // TODO: `FromNapiValue` should also validate
    // TODO: either completely remove/embrace `FnArgs`
    use std::sync::MappedMutexGuard;
    use std::sync::{Mutex, MutexGuard, OnceLock};
    use napi::JsValue;
    use napi::bindgen_prelude;
    use napi::bindgen_prelude::{
    FromNapiValue, JsObjectValue, ToNapiValue, TypeName, ValidateNapiValue,
    };
    use napi_sys::{napi_env, napi_value};
    use macros::{
    class_wrapper, empty_function_caller, field_getter, field_setter, function_caller,
    function_setter, interface_builder, static_class_method,
    };
    // Internal/helper modules
    pub mod log;
    mod macros;
    pub mod reference;
    // VSCode API namespaces
    pub mod scm;
    pub mod window;
    pub mod workspace;
    static CONTEXT: Mutex<OnceLock<VscodeContext>> = Mutex::new(OnceLock::new());
    struct VscodeContext {
    vscode: bindgen_prelude::ObjectRef,
    extension_context: bindgen_prelude::ObjectRef,
    }
    impl VscodeContext {
    fn inner() -> Result<MappedMutexGuard<'static, Self>, napi::Error> {
    let mutex_guard = CONTEXT.lock().map_err(|_error| {
    napi::Error::from_reason("vscode_sys::Context mutex has been poisoned")
    })?;
    MutexGuard::filter_map(mutex_guard, |guarded_value| match guarded_value.get_mut() {
    Some(vscode_context) => Some(vscode_context),
    None => None,
    })
    .map_err(|_empty_guard| {
    napi::Error::new(napi::Status::GenericFailure, "`vscode` object is not set")
    })
    }
    fn extension_context<'env>(
    env: &'env napi::Env,
    ) -> Result<bindgen_prelude::Object<'env>, napi::Error> {
    let context = Self::inner()?;
    context.extension_context.get_value(env)
    }
    fn vscode<'env>(env: &'env napi::Env) -> Result<bindgen_prelude::Object<'env>, napi::Error> {
    let context = Self::inner()?;
    context.vscode.get_value(env)
    }
    }
    pub fn activate(
    vscode_object: &bindgen_prelude::Object,
    extension_context: &bindgen_prelude::Object,
    ) -> Result<(), napi::Error> {
    let mutex_guard = CONTEXT.lock().map_err(|_error| {
    napi::Error::from_reason(
    "vscode_sys::Context mutex was poisoned before it could be initialized",
    )
    })?;
    let context = VscodeContext {
    vscode: vscode_object.create_ref()?,
    extension_context: extension_context.create_ref()?,
    };
    mutex_guard.set(context).map_err(|_error| {
    napi::Error::from_reason(
    "`activate()` has already been called, but must be called exactly once",
    )
    })?;
    Ok(())
    }
    class_wrapper!(FileDecoration(badge: &str, tooltip: &str, color: &ThemeColor));
    class_wrapper!(MarkdownString(value: &str, support_theme_icons: bool));
    class_wrapper!(Position(line: u32, character: u32));
    field_getter! {
    Position {
    "line": get_line -> u32;
    }
    }
    class_wrapper!(Range(start: &Position<'env>, end: &Position<'env>));
    class_wrapper!(Selection(anchor: &Position<'env>, active: &Position<'env>));
    field_getter! {
    Selection {
    "start": get_start -> Position<'env>;
    "end": get_end -> Position<'env>;
    }
    }
    class_wrapper!(ThemeColor(id: &str));
    // TODO: private constructor
    class_wrapper!(Uri(scheme: &str, authority: &str, path: &str, query: &str, fragment: &str));
    field_getter! {
    Uri {
    "fsPath": get_fs_path -> String;
    "scheme": get_scheme -> String;
    }
    }
    empty_function_caller! {
    Uri {
    "toString":
    to_string() -> String;
    }
    }
    function_caller! {
    Uri {
    "with":
    with(
    change: UriWithChange,
    ) -> Uri<'env>;
    }
    }
    static_class_method! {
    Uri {
    "file":
    file(
    path: &str,
    ) -> Uri<'env>;
    }
    }
    interface_builder! {
    DecorationOptions {
    ("range": Range, range: &Range),
    }
    ("hoverMessage", hover_message: &MarkdownString),
    ("renderOptions", render_options: DecorationInstanceRenderOptions),
    }
    interface_builder! {
    DecorationInstanceRenderOptions {}
    ("after", after: ThemableDecorationAttachmentRenderOptions),
    }
    interface_builder! {
    DecorationRenderOptions {}
    ("after", after: ThemableDecorationAttachmentRenderOptions),
    }
    interface_builder! {
    FileDecorationProvider {
    F: set_provide_file_decoration =
    provide_file_decoration(
    uri: Uri,
    cancellation_token: bindgen_prelude::Object
    ) -> FileDecoration<'function_context>;
    }
    }
    function_setter! {
    FileDecorationProvider {
    "provideFileDecoration" {
    set_provide_file_decoration(
    uri: Uri,
    cancellation_token: bindgen_prelude::Object
    ) -> FileDecoration<'function_context>;
    bindgen_prelude::ObjectRef = |returned_result: Option<FileDecoration>| returned_result.map(|object| object.inner.create_ref()).transpose();
    }
    }
    }
    interface_builder! {
    QuickDiffProvider {}
    }
    function_setter! {
    QuickDiffProvider {
    "provideOriginalResource" {
    set_provide_original_resource(
    uri: Uri<'function_context>,
    cancellation_token: bindgen_prelude::Object<'function_context>
    ) -> Uri<'function_context>;
    bindgen_prelude::ObjectRef = |returned_result: Option<Uri>| returned_result.map(|object| object.inner.create_ref()).transpose();
    }
    }
    }
    interface_builder! {
    SourceControl {}
    }
    field_setter! {
    SourceControl {
    "quickDiffProvider": set_quick_diff_provider(QuickDiffProvider);
    }
    }
    function_caller! {
    SourceControl {
    "createResourceGroup":
    create_resource_group(
    id: &str,
    label: &str,
    ) -> SourceControlResourceGroup<'env>;
    }
    }
    interface_builder! {
    SourceControlResourceGroup {}
    }
    field_setter! {
    SourceControlResourceGroup {
    "resourceStates": set_resource_states(Vec<SourceControlResourceState>);
    }
    }
    interface_builder! {
    SourceControlResourceState {
    ("resourceUri": Uri, resource_uri: &Uri),
    }
    }
    interface_builder! {
    TextDocument {}
    }
    field_getter! {
    TextDocument {
    "uri": get_uri -> Uri<'env>;
    }
    }
    function_caller! {
    TextDocument {
    "getText":
    get_text(
    range: Option<Range>,
    ) -> String;
    }
    }
    interface_builder! {
    TextDocumentChangeEvent {}
    }
    field_getter! {
    TextDocumentChangeEvent {
    "document": get_document -> TextDocument<'env>;
    "contentChanges": get_content_changes -> Vec<TextDocumentContentChangeEvent<'env>>;
    }
    }
    interface_builder! {
    TextDocumentContentChangeEvent {}
    }
    field_getter! {
    TextDocumentContentChangeEvent {
    "rangeOffset": get_range_offset -> u32;
    "rangeLength": get_range_length -> u32;
    "text": get_text -> String;
    }
    }
    interface_builder! {
    TextDocumentContentProvider {
    F: set_provide_text_document_content =
    provide_text_document_content(
    uri: Uri<'function_context>,
    cancellation_token: bindgen_prelude::Object<'function_context>
    ) -> String;
    }
    }
    function_setter! {
    TextDocumentContentProvider {
    "provideTextDocumentContent" {
    set_provide_text_document_content(
    uri: Uri<'function_context>,
    cancellation_token: bindgen_prelude::Object<'function_context>
    ) -> String;
    String = |returned_result: Option<String>| Ok(returned_result);
    }
    }
    }
    interface_builder! {
    TextEditor {}
    }
    field_getter! {
    TextEditor {
    "document": get_document -> TextDocument<'env>;
    "selections": get_selections -> Vec<Selection<'env>>;
    }
    }
    function_caller! {
    TextEditor {
    "setDecorations":
    set_decorations(
    decoration_type: TextEditorDecorationType,
    options: Vec<DecorationOptions>,
    ) -> ();
    }
    }
    interface_builder! {
    TextEditorDecorationType {}
    }
    interface_builder! {
    TextEditorSelectionChangeEvent {}
    }
    field_getter! {
    TextEditorSelectionChangeEvent {
    "textEditor": get_text_editor -> TextEditor<'env>;
    "selections": get_selections -> Vec<Selection<'env>>;
    }
    }
    interface_builder! {
    ThemableDecorationAttachmentRenderOptions {}
    ("color", color: &ThemeColor),
    ("contentText", content_text: &str),
    ("margin", margin: &str),
    }
    interface_builder! {
    UriWithChange {}
    ("scheme", scheme: &str),
    ("authority", authority: &str),
    ("path", path: &str),
    ("query", query: &str),
    ("fragment", fragment: &str),
    }
    interface_builder! {
    WorkspaceFolder {}
    }
    field_getter! {
    WorkspaceFolder {
    "uri": get_uri -> Uri<'env>;
    }
    }
    interface_builder! {
    WorkspaceFoldersChangeEvent {}
    }
    field_getter! {
    WorkspaceFoldersChangeEvent {
    "added": get_added -> Vec<WorkspaceFolder<'env>>;
    "removed": get_removed -> Vec<WorkspaceFolder<'env>>;
    }
    }
  • file addition: macros (d--r------)
    [0.54375]
  • file addition: register_provider.rs (----------)
    [0.67463]
    macro_rules! register_provider {
    (
    $namespace:literal, $function_js_name:literal,
    $function_rust_name:ident(
    $($argument_name:ident: $argument_type:ty),+
    )
    ) => {
    // TODO: error handling
    pub fn $function_rust_name<'env>(
    env: &'env napi::Env,
    extension_context: &bindgen_prelude::Object,
    $($argument_name: $argument_type),+
    ) -> Result<(), napi::Error> {
    let vscode_object = super::VscodeContext::vscode(env)?;
    let namespace: bindgen_prelude::Object = vscode_object.get_named_property($namespace)?;
    let js_register_provider: bindgen_prelude::Function<
    bindgen_prelude::FnArgs<($($argument_type,)+)>,
    bindgen_prelude::Object,
    > = namespace.get_named_property($function_js_name)?;
    let subscription = js_register_provider
    .apply(namespace, bindgen_prelude::FnArgs::from(($($argument_name,)+)))?;
    let mut subscriptions: bindgen_prelude::Array =
    extension_context.get_named_property("subscriptions")?;
    subscriptions.insert(subscription)?;
    Ok(())
    }
    };
    }
    pub(crate) use register_provider;
  • file addition: object_reference.rs (----------)
    [0.67463]
    macro_rules! object_reference {
    ($reference_name:ident: $owned_name:ident) => {
    pub struct $reference_name {
    inner: bindgen_prelude::ObjectRef,
    }
    impl $reference_name {
    pub fn get_inner<'env>(
    &self,
    env: &'env napi::Env,
    ) -> Result<$owned_name<'env>, napi::Error> {
    let inner = self.inner.get_value(env)?;
    Ok($owned_name { inner })
    }
    }
    impl<'env> $owned_name<'env> {
    pub fn create_ref(&self) -> Result<$reference_name, napi::Error> {
    let inner = self.inner.create_ref()?;
    Ok($reference_name { inner })
    }
    }
    };
    }
    pub(crate) use object_reference;
  • file addition: object (d--r------)
    [0.67463]
  • file addition: mod.rs (----------)
    [0.69613]
    pub mod field;
    pub mod function;
  • file addition: function (d--r------)
    [0.69613]
  • file addition: setter.rs (----------)
    [0.69701]
    macro_rules! function_setter {
    ($interface_name:ident {
    $(
    $function_js_name:literal {
    $setter_name:ident(
    $(
    $function_argument_name:ident: $function_argument_type:ty
    ),*
    ) -> $function_borrowed_return_type:ty;
    // TODO: remove this hack and properly handle types
    $function_owned_return_type:ty = $function_create_owned_return_type:expr;
    }
    )*
    }) => {
    impl<'env> $interface_name<'env> {
    $(
    pub fn $setter_name<F>(
    &mut self,
    env: &napi::Env,
    function_callback: F,
    ) -> Result<(), napi::Error>
    where
    F: for<'function_context> Fn(
    &'function_context napi::Env,
    $($function_argument_type,)*
    ) -> Result<
    Option<$function_borrowed_return_type>,
    napi::Error,
    > + 'static,
    {
    let function_callback: bindgen_prelude::Function<
    // Treat arguments as `Unknown` to make sure type errors are handled inside the closure
    bindgen_prelude::Unknown,
    // Extend the return type's lifetime beyond the lifetime of the closure
    Option<$function_owned_return_type>,
    > =
    env.create_function_from_closure($function_js_name, move |function_context| {
    // TODO: error handling
    let ($($function_argument_name),*) = function_context.args()?;
    let returned_result =
    function_callback(function_context.env, $($function_argument_name),*)?;
    $function_create_owned_return_type(returned_result)
    })?;
    self.inner.set_named_property($function_js_name, function_callback)?;
    Ok(())
    }
    )*
    }
    };
    }
    pub(crate) use function_setter;
  • file addition: mod.rs (----------)
    [0.69701]
    pub mod caller;
    pub mod setter;
  • file addition: caller.rs (----------)
    [0.69701]
    macro_rules! empty_function_caller {
    (
    $interface_name:ident {
    $(
    $empty_function_js_name:literal:
    $empty_function_rust_name:ident() -> $empty_function_return_type:ty;
    )*
    }
    ) => {
    impl<'env> $interface_name<'env> {
    $(
    pub fn $empty_function_rust_name(
    &self,
    ) -> Result<$empty_function_return_type, napi::Error> {
    let js_function: bindgen_prelude::Function<
    (),
    $empty_function_return_type,
    > = self.inner.get_named_property($empty_function_js_name)?;
    js_function.apply(self.inner, ())
    }
    )*
    }
    };
    }
    macro_rules! function_caller {
    (
    $interface_name:ident {
    $(
    $function_js_name:literal:
    $function_rust_name:ident(
    $(
    $function_argument_name:ident: $function_argument_type:ty,
    )+
    ) -> $function_return_type:ty;
    )*
    }
    ) => {
    impl<'env> $interface_name<'env> {
    $(
    pub fn $function_rust_name(
    &self,
    $($function_argument_name: $function_argument_type),+
    ) -> Result<$function_return_type, napi::Error> {
    let js_function: bindgen_prelude::Function<
    bindgen_prelude::FnArgs<($($function_argument_type,)+)>,
    $function_return_type,
    > = self.inner.get_named_property($function_js_name)?;
    js_function.apply(self.inner, bindgen_prelude::FnArgs::from(($($function_argument_name,)+)))
    }
    )*
    }
    };
    }
    pub(crate) use empty_function_caller;
    pub(crate) use function_caller;
  • file addition: field (d--r------)
    [0.69613]
  • file addition: setter.rs (----------)
    [0.74128]
    macro_rules! field_setter {
    (
    $object_name:ident {
    $(
    $field_js_name:literal: $setter_name:ident($field_type:ty);
    )*
    }
    ) => {
    impl<'env> $object_name<'env> {
    $(
    pub fn $setter_name(&mut self, value: $field_type) -> Result<(), napi::Error> {
    self.inner.set_named_property($field_js_name, value)
    }
    )*
    }
    };
    }
    pub(crate) use field_setter;
  • file addition: mod.rs (----------)
    [0.74128]
    mod getter;
    mod setter;
    pub(crate) use getter::field_getter;
    pub(crate) use setter::field_setter;
  • file addition: getter.rs (----------)
    [0.74128]
    macro_rules! field_getter {
    (
    $object_name:ident {
    $(
    $field_js_name:literal: $getter_name:ident -> $field_type:ty;
    )*
    }
    ) => {
    impl<'env> $object_name<'env> {
    $(
    pub fn $getter_name(&self) -> Result<$field_type, napi::Error> {
    self.inner.get_named_property($field_js_name)
    }
    )*
    }
    };
    }
    pub(crate) use field_getter;
  • file addition: namespace (d--r------)
    [0.67463]
  • file addition: mod.rs (----------)
    [0.75327]
    pub mod field_getter;
    pub mod function;
  • file addition: function.rs (----------)
    [0.75327]
    macro_rules! namespace_function {
    (
    $namespace:literal {
    $(
    $function_js_name:literal: $function_rust_name:ident(
    $(
    $argument_name:ident: $argument_type:ty,
    )*
    ) -> $return_type:ty;
    )*
    }
    ) => {
    $(
    pub fn $function_rust_name<'env>(
    env: &napi::Env,
    $($argument_name: $argument_type),*
    ) -> Result<$return_type, napi::Error> {
    let vscode_object = super::VscodeContext::vscode(env)?;
    let namespace: bindgen_prelude::Object = vscode_object.get_named_property($namespace)?;
    let function_prototype: bindgen_prelude::Function<
    bindgen_prelude::FnArgs<($($argument_type,)*)>,
    $return_type,
    > = namespace.get_named_property($function_js_name)?;
    function_prototype.apply(
    namespace,
    bindgen_prelude::FnArgs::from(($($argument_name,)*)),
    )
    }
    )*
    };
    }
    pub(crate) use namespace_function;
  • file addition: field_getter.rs (----------)
    [0.75327]
    macro_rules! namespace_field_getter {
    (
    $namespace:literal {
    $(
    $field_js_name:literal: $function_name:ident -> $field_type:ty;
    )*
    }
    ) => {
    $(
    pub fn $function_name<'env>(env: &'env napi::Env) -> Result<$field_type, napi::Error> {
    let vscode_object = super::VscodeContext::vscode(env)?;
    let window: bindgen_prelude::Object = vscode_object.get_named_property($namespace)?;
    window.get_named_property($field_js_name)
    }
    )*
    };
    }
    pub(crate) use namespace_field_getter;
  • file addition: mod.rs (----------)
    [0.67463]
    mod class;
    mod event_handler;
    mod interface_builder;
    mod namespace;
    mod object;
    mod object_reference;
    mod register_provider;
    pub(super) use class::static_method::static_class_method;
    pub(super) use class::wrapper::class_wrapper;
    pub(super) use event_handler::event_handler;
    pub(super) use interface_builder::interface_builder;
    pub(super) use namespace::field_getter::namespace_field_getter;
    pub(super) use namespace::function::namespace_function;
    pub(super) use object::field::field_getter;
    pub(super) use object::field::field_setter;
    pub(super) use object::function::caller::empty_function_caller;
    pub(super) use object::function::caller::function_caller;
    pub(super) use object::function::setter::function_setter;
    pub(super) use object_reference::object_reference;
    pub(super) use register_provider::register_provider;
  • file addition: interface_builder.rs (----------)
    [0.67463]
    macro_rules! interface_builder {
    (
    $interface_name:ident {
    $(
    (
    $required_field_js_name:literal: $required_field_js_type:ty,
    $required_field_rust_name:ident: $required_field_rust_type:ty
    ),
    )*
    $(
    $required_function_generic:ident: $required_function_setter:ident =
    $required_function_rust_name:ident(
    $(
    $required_function_argument_name:ident: $required_function_argument_type:ty
    ),*
    ) -> $required_function_return_type:ty;
    )*
    }
    $(
    ($optional_field_js_name:literal, $optional_field_rust_name:ident: $optional_field_type:ty),
    )*
    ) => {
    #[derive(Clone, Copy)]
    pub struct $interface_name<'env> {
    inner: ::napi::bindgen_prelude::Object<'env>
    }
    impl<'env> $interface_name<'env> {
    pub fn new<$($required_function_generic),*>(
    env: &napi::Env,
    $($required_field_rust_name: $required_field_rust_type),*
    $($required_function_rust_name: $required_function_generic),*
    ) -> Result<Self, napi::Error>
    where
    $(
    $required_function_generic: for<'function_context> Fn(
    &'function_context napi::Env,
    $($required_function_argument_type,)*
    ) -> Result<
    Option<$required_function_return_type>,
    napi::Error,
    > + 'static,
    )*
    {
    // TODO: generate more idiomatic code depending on if the object actually gets mutated
    #[allow(unused_mut)]
    let mut builder = Self {
    inner: bindgen_prelude::Object::new(env)?,
    };
    // TODO: use Rust setters here
    $(builder.inner.set_named_property($required_field_js_name, $required_field_rust_name)?;)*
    $(builder.$required_function_setter(env, $required_function_rust_name)?;)*
    Ok(builder)
    }
    $(
    pub fn $optional_field_rust_name(mut self, $optional_field_rust_name: $optional_field_type) -> Result<Self, ::napi::Error> {
    self.inner.set_named_property($optional_field_js_name, $optional_field_rust_name)?;
    Ok(self)
    }
    )*
    }
    impl<'env> bindgen_prelude::ToNapiValue for &$interface_name<'env> {
    unsafe fn to_napi_value(env: napi_sys::napi_env, val: Self) -> Result<napi_sys::napi_value, napi::Error> {
    unsafe { bindgen_prelude::Object::to_napi_value(env, val.inner) }
    }
    }
    impl<'env> bindgen_prelude::ToNapiValue for $interface_name<'env> {
    unsafe fn to_napi_value(env: napi_sys::napi_env, val: Self) -> Result<napi_sys::napi_value, napi::Error> {
    unsafe { bindgen_prelude::Object::to_napi_value(env, val.inner) }
    }
    }
    impl<'env> bindgen_prelude::TypeName for $interface_name<'env> {
    fn type_name() -> &'static str {
    bindgen_prelude::Object::type_name()
    }
    fn value_type() -> napi::ValueType {
    bindgen_prelude::Object::value_type()
    }
    }
    // TODO: validate non-optional fields
    impl<'env> bindgen_prelude::FromNapiValue for $interface_name<'env> {
    unsafe fn from_napi_value(
    raw_env: napi_sys::napi_env,
    napi_val: napi_sys::napi_value,
    ) -> Result<Self, napi::Error> {
    let inner = unsafe { bindgen_prelude::Object::from_napi_value(raw_env, napi_val) }?;
    Ok(Self { inner })
    }
    }
    // TODO: validate functions
    impl<'env> bindgen_prelude::ValidateNapiValue for $interface_name<'env> {
    unsafe fn validate(
    raw_env: napi_sys::napi_env,
    raw_interface_value: napi_sys::napi_value,
    ) -> Result<napi_sys::napi_value, napi::Error> {
    // TODO: only generate when needed
    #[allow(unused)]
    let interface = match unsafe {
    <bindgen_prelude::Object as bindgen_prelude::ValidateNapiValue>::validate(raw_env, raw_interface_value)
    } {
    Ok(_validated_object) => bindgen_prelude::Object::from_raw(raw_env, raw_interface_value),
    Err(error) => {
    return Err(napi::Error::from_reason(format!(
    "{} should be an Object: {}",
    stringify!($interface_name),
    error
    )));
    }
    };
    $(
    let _property_value: $required_field_js_type = interface.get_named_property($required_field_js_name).map_err(|mut error| {
    error.reason = format!(
    "Error validating property {} of {}: {}",
    $required_field_js_name,
    stringify!($interface_name),
    error.reason
    );
    error
    })?;
    )*
    Ok(raw_interface_value)
    }
    }
    };
    }
    pub(crate) use interface_builder;
  • file addition: event_handler.rs (----------)
    [0.67463]
    macro_rules! event_handler {
    (
    $namespace:literal, $function_js_name:literal, $function_rust_name:ident($event_type:ty)
    ) => {
    pub fn $function_rust_name<F>(
    env: &napi::Env,
    handler: F,
    // TODO: generic errors
    ) -> Result<(), napi::Error>
    where
    F: for<'function_context> Fn(
    &'function_context napi::Env,
    $event_type,
    ) -> Result<(), napi::Error>
    + 'static,
    {
    let extension_context = super::VscodeContext::extension_context(env)?;
    let mut subscriptions: bindgen_prelude::Array =
    extension_context.get_named_property("subscriptions")?;
    let vscode_object = super::VscodeContext::vscode(env)?;
    let namespace: bindgen_prelude::Object =
    vscode_object.get_named_property($namespace)?;
    let event_creator: bindgen_prelude::Function<
    bindgen_prelude::Function<$event_type, ()>,
    // TODO: disposable
    bindgen_prelude::Object,
    > = namespace.get_named_property($function_js_name)?;
    let event_handler_fn: bindgen_prelude::Function<$event_type, ()> = env
    .create_function_from_closure($function_js_name, move |function_context| {
    let parent_span = tracing::span!(tracing::Level::TRACE, "event_handler");
    let _entered_span = parent_span.enter();
    let event = match function_context.args::<($event_type,)>() {
    Ok((event,)) => event,
    Err(error) => {
    tracing::error!(
    message = "Invalid arguments",
    event_handler = $function_js_name,
    ?error
    );
    return Ok(());
    }
    };
    if let Err(error) = handler(function_context.env, event) {
    tracing::error!(
    message = "Handler exited unsuccessfully",
    event_handler = $function_js_name,
    ?error
    );
    }
    Ok(())
    })?;
    let handler_subscription: bindgen_prelude::Object =
    event_creator.call(event_handler_fn)?;
    subscriptions.insert(handler_subscription)?;
    Ok(())
    }
    };
    }
    pub(crate) use event_handler;
  • file addition: class (d--r------)
    [0.67463]
  • file addition: wrapper.rs (----------)
    [0.86585]
    // TODO: lifetimes when storing in e.g. statics
    // TODO: either qualify everything or nothing
    macro_rules! class_wrapper {
    ($class_name:ident($($argument_name:ident: $argument_type:ty),*)) => {
    pub struct $class_name<'env> {
    pub inner: ::napi::bindgen_prelude::Object<'env>,
    }
    impl<'env> $class_name<'env> {
    pub fn new(
    env: &napi::Env,
    $($argument_name: $argument_type),*
    ) -> Result<Self, ::napi::Error> {
    let vscode_object = VscodeContext::vscode(env)?;
    let constructor_prototype: ::napi::bindgen_prelude::Function<
    'env,
    ::napi::bindgen_prelude::FnArgs<($($argument_type,)*)>,
    ::napi::bindgen_prelude::Object<'env>,
    > = vscode_object.get_named_property(stringify!($class_name))?;
    let class_result: ::napi::bindgen_prelude::Unknown =
    constructor_prototype.new_instance(::napi::bindgen_prelude::FnArgs::from(($($argument_name,)*)))?;
    let class_object = ::napi::bindgen_prelude::Object::from_unknown(class_result)?;
    Ok(Self {
    inner: class_object,
    })
    }
    }
    impl<'env> ToNapiValue for &$class_name<'env> {
    unsafe fn to_napi_value(env: napi_env, val: Self) -> Result<napi_value, napi::Error> {
    unsafe { bindgen_prelude::Object::to_napi_value(env, val.inner) }
    }
    }
    impl<'env> ToNapiValue for $class_name<'env> {
    unsafe fn to_napi_value(env: napi_env, val: Self) -> Result<napi_value, napi::Error> {
    unsafe { bindgen_prelude::Object::to_napi_value(env, val.inner) }
    }
    }
    // TODO: validate non-optional fields
    // TODO: move validation logic into validatenapivalue???
    impl<'env> FromNapiValue for $class_name<'env> {
    unsafe fn from_napi_value(
    raw_env: napi_sys::napi_env,
    napi_val: napi_sys::napi_value,
    ) -> Result<Self, napi::Error> {
    let inner = unsafe { bindgen_prelude::Object::from_napi_value(raw_env, napi_val) }?;
    Ok(Self { inner })
    }
    }
    impl<'env> TypeName for $class_name<'env> {
    fn type_name() -> &'static str {
    bindgen_prelude::Object::type_name()
    }
    fn value_type() -> napi::ValueType {
    bindgen_prelude::Object::value_type()
    }
    }
    impl<'env> ValidateNapiValue for $class_name<'env> {
    unsafe fn validate(
    raw_env: napi_sys::napi_env,
    raw_class: napi_sys::napi_value,
    ) -> Result<napi_sys::napi_value, napi::Error> {
    let class = match unsafe { <bindgen_prelude::Object as ValidateNapiValue>::validate(raw_env, raw_class) } {
    Ok(_validated_class) => bindgen_prelude::Object::from_raw(raw_env, raw_class),
    Err(mut error) => {
    error.reason = format!("Invalid type for {}: {}", stringify!($class_name), error.reason);
    return Err(error);
    }
    };
    let env = napi::Env::from_raw(raw_env);
    let vscode_object = VscodeContext::vscode(&env)?;
    let constructor: bindgen_prelude::Function<bindgen_prelude::FnArgs<($($argument_type,)*)>, bindgen_prelude::Object> = vscode_object.get_named_property(stringify!($class_name))?;
    if !class.instanceof(constructor)? {
    return Err(napi::Error::from_reason(
    concat!("Object is not an instance of ", stringify!($class_name)),
    ));
    }
    // TODO: validate fields
    Ok(raw_class)
    }
    }
    };
    }
    pub(crate) use class_wrapper;
  • file addition: static_method.rs (----------)
    [0.86585]
    macro_rules! static_class_method {
    (
    $class_name:ident {
    $(
    $function_js_name:literal:
    $function_rust_name:ident(
    $(
    $function_argument_name:ident: $function_argument_type:ty,
    )*
    ) -> $function_return_type:ty;
    )*
    }
    ) => {
    impl<'env> $class_name<'env> {
    $(
    pub fn $function_rust_name(
    env: &'env napi::Env,
    $($function_argument_name: $function_argument_type),*
    ) -> Result<$function_return_type, napi::Error> {
    let vscode_object = VscodeContext::vscode(env)?;
    let constructor: ::napi::bindgen_prelude::Function<
    bindgen_prelude::Unknown,
    bindgen_prelude::Unknown,
    > = vscode_object.get_named_property(stringify!($class_name))?;
    let js_function: bindgen_prelude::Function<
    bindgen_prelude::FnArgs<($($function_argument_type,)*)>,
    $function_return_type,
    > = constructor.get_named_property($function_js_name)?;
    js_function.apply(constructor, bindgen_prelude::FnArgs::from(($($function_argument_name,)*)))
    }
    )*
    }
    };
    }
    pub(crate) use static_class_method;
  • file addition: mod.rs (----------)
    [0.86585]
    pub mod static_method;
    pub mod wrapper;
  • file addition: log.rs (----------)
    [0.54375]
    // TODO: https://github.com/tokio-rs/tracing/blob/main/examples/examples/panic_hook.rs
    // TODO: Use a custom language ID in `window.createOutputChannel` to better format log messages
    use napi::bindgen_prelude::{self, JsObjectValue};
    use napi::threadsafe_function::ThreadsafeFunctionCallMode;
    use tracing::{Level, Subscriber};
    use tracing_subscriber::Layer;
    use tracing_subscriber::fmt::{FormatFields, FormattedFields};
    use tracing_subscriber::layer::SubscriberExt;
    use tracing_subscriber::registry::LookupSpan;
    struct VscodeLayer<F>
    where
    F: for<'writer> FormatFields<'writer> + 'static,
    {
    threadsafe_function: napi::threadsafe_function::ThreadsafeFunction<
    (&'static str, String),
    (),
    (&'static str, String),
    napi::Status,
    false,
    false,
    0,
    >,
    field_formatter: F,
    }
    impl<F> VscodeLayer<F>
    where
    F: for<'writer> FormatFields<'writer> + 'static,
    {
    fn new(env: &napi::Env, name: &str, field_formatter: F) -> Result<Self, napi::Error> {
    let output_channel = super::window::create_log_output_channel(env, name)?;
    let threadsafe_function: bindgen_prelude::Function<(&str, String), ()> = env
    .create_function_from_closure("tracing_event_handler", |function_context| {
    let ((method, message),): ((String, String),) = function_context.args()?;
    let output_channel: bindgen_prelude::Object = function_context.this()?;
    let log_function: bindgen_prelude::Function<String, ()> =
    output_channel.get_named_property(&method)?;
    log_function.apply(output_channel, message)
    })?;
    // TODO: build_callback so can pass rust values
    let threadsafe_function = threadsafe_function
    .bind(output_channel)?
    .build_threadsafe_function()
    .callee_handled::<false>()
    .max_queue_size::<0>()
    .weak::<false>()
    .build()?;
    Ok(Self {
    threadsafe_function,
    field_formatter,
    })
    }
    fn call_output_channel<S: Into<String>>(&self, level: Level, message: S) {
    let level = match level {
    Level::TRACE => "trace",
    Level::DEBUG => "debug",
    Level::INFO => "info",
    Level::WARN => "warn",
    Level::ERROR => "error",
    };
    let status = self.threadsafe_function.call(
    // Ok((level, message.into())),
    (level, message.into()),
    ThreadsafeFunctionCallMode::Blocking,
    );
    }
    fn internal_message<S: core::fmt::Display>(&self, level: Level, message: S) {
    self.call_output_channel(level, format!("Internal tracing message: {message}"));
    }
    }
    impl<F, S> Layer<S> for VscodeLayer<F>
    where
    F: for<'writer> FormatFields<'writer> + 'static,
    S: Subscriber + for<'registry> LookupSpan<'registry>,
    {
    fn on_new_span(
    &self,
    attributes: &tracing::span::Attributes<'_>,
    id: &tracing::span::Id,
    context: tracing_subscriber::layer::Context<'_, S>,
    ) {
    let Some(span) = context.span(id) else {
    self.internal_message(Level::ERROR, format!("no matching span for ID: {id:#?}"));
    return;
    };
    let mut extensions = span.extensions_mut();
    if extensions.get_mut::<FormattedFields<F>>().is_none() {
    let mut formatted_fields: FormattedFields<F> = FormattedFields::new(String::new());
    let format_result = self
    .field_formatter
    .format_fields(formatted_fields.as_writer(), attributes);
    match format_result {
    Ok(()) => extensions.insert(formatted_fields),
    Err(error) => {
    self.internal_message(Level::ERROR, format!("failed to format fields: {error}"))
    }
    }
    }
    }
    fn on_event(
    &self,
    event: &tracing::Event<'_>,
    context: tracing_subscriber::layer::Context<'_, S>,
    ) {
    let mut message = String::new();
    if let Some(event_scope) = context.event_scope(event) {
    for span in event_scope.from_root() {
    message.push_str(span.name());
    match span.extensions().get::<FormattedFields<F>>() {
    Some(formatted_fields) => {
    if !formatted_fields.is_empty() {
    message.push('{');
    message.push_str(formatted_fields);
    message.push('}');
    }
    }
    None => {
    self.internal_message(
    Level::WARN,
    format!("no formatted fields stored for {:#?}", span.id()),
    );
    message.push_str("{missing fields}");
    }
    }
    message.push(':');
    }
    }
    match event.metadata().module_path() {
    Some(module_path) => {
    if !message.is_empty() {
    message.push(' ');
    }
    message.push_str(module_path);
    message.push_str(": ");
    }
    None => {
    self.internal_message(
    Level::WARN,
    format!(
    "missing module path for event at callsite {:#?}",
    event.metadata().callsite()
    ),
    );
    }
    }
    // TODO: https://github.com/tokio-rs/tracing/issues/3335
    let writer = tracing_subscriber::fmt::format::Writer::new(&mut message);
    if let Err(error) = self.field_formatter.format_fields(writer, event) {
    self.internal_message(
    Level::ERROR,
    format!("failed to write event fields: {error}"),
    );
    }
    self.call_output_channel(*event.metadata().level(), message);
    }
    }
    pub fn init<F>(env: &napi::Env, name: &str, field_formatter: F) -> Result<(), napi::Error>
    where
    F: for<'writer> FormatFields<'writer> + Send + Sync + 'static,
    {
    let vscode_layer = VscodeLayer::new(env, name, field_formatter)?;
    // TODO: https://docs.rs/tracing-appender/latest/tracing_appender/
    let subscriber = tracing_subscriber::registry().with(vscode_layer);
    tracing::subscriber::set_global_default(subscriber).map_err(|error| {
    napi::Error::from_reason(format!("Failed to set global default subscriber: {error}"))
    })?;
    Ok(())
    }
  • file addition: repository (d--r------)
    [0.54351]
  • file addition: open_repository.rs (----------)
    [0.98972]
    use std::collections::HashMap;
    use camino::{Utf8Path, Utf8PathBuf};
    use pijul_extension::FileSystemRepository;
    use crate::vscode_sys::reference::{
    SourceControlRef, SourceControlResourceGroupRef, TextEditorRef,
    };
    use crate::vscode_sys::{self, SourceControlResourceState};
    use crate::vscode_sys::{TextEditor, Uri};
    // TODO: remove public fields
    pub struct OpenRepository {
    pub repository: FileSystemRepository,
    pub source_control: SourceControlRef,
    open_editors: HashMap<Utf8PathBuf, TextEditorRef>,
    unrecorded_changes: SourceControlResourceGroupRef,
    untracked_paths: SourceControlResourceGroupRef,
    }
    impl OpenRepository {
    #[tracing::instrument(skip_all)]
    pub fn new(
    env: &napi::Env,
    // TODO: pass SourceControl directly instead of URI?
    repository_uri: &Uri,
    // open_editors: HashMap<Utf8PathBuf, TextEditor>,
    // TODO: thiserror
    ) -> Result<Self, napi::Error> {
    tracing::debug!(message = "Opening repository", uri = ?repository_uri.to_string()?);
    let repository_path = Utf8PathBuf::from(repository_uri.get_fs_path()?);
    let source_control =
    vscode_sys::scm::create_source_control(env, "pijul", "Pijul", repository_uri)?;
    let repository = FileSystemRepository::new(&repository_path).map_err(|error| {
    napi::Error::from_reason(format!(
    "cannot open workspace at {repository_path}: {error}"
    ))
    })?;
    tracing::debug!("repository");
    let mut unrecorded_changes = source_control.create_resource_group("changes", "Changes")?;
    let mut untracked_paths = source_control.create_resource_group("untracked", "Untracked")?;
    tracing::debug!("resource groups");
    let mut modified_resource_states = Vec::new();
    tracing::debug!("starting loop");
    for relative_modified_path in repository.iter_modified() {
    let absolute_modified_path = repository_path.join(relative_modified_path);
    let resource_uri = Uri::file(env, absolute_modified_path.as_str())?;
    let resource_state = SourceControlResourceState::new(env, &resource_uri)?;
    modified_resource_states.push(resource_state)
    }
    unrecorded_changes.set_resource_states(modified_resource_states)?;
    let mut untracked_resource_states = Vec::new();
    for relative_untracked_path in repository.iter_untracked() {
    let absolute_untracked_path = repository_path.join(relative_untracked_path);
    tracing::debug!(path = absolute_untracked_path.as_str());
    let resource_uri = Uri::file(env, absolute_untracked_path.as_str())?;
    let resource_state = SourceControlResourceState::new(env, &resource_uri)?;
    untracked_resource_states.push(resource_state)
    }
    untracked_paths.set_resource_states(untracked_resource_states)?;
    tracing::debug!("resource states");
    Ok(Self {
    source_control: source_control.create_ref()?,
    repository,
    unrecorded_changes: unrecorded_changes.create_ref()?,
    untracked_paths: untracked_paths.create_ref()?,
    open_editors: HashMap::new(),
    })
    }
    #[tracing::instrument(skip_all)]
    pub fn register_text_editor(
    &mut self,
    path: Utf8PathBuf,
    text_editor: TextEditor,
    ) -> Result<(), napi::Error> {
    if self.repository.get_open_file(&path).is_none() {
    let document = text_editor.get_document()?;
    let file_contents = document.get_text(None)?;
    // TODO: proper error handling
    self.repository
    .create_open_file(path.clone(), file_contents)
    .map_err(|error| {
    napi::Error::from_reason(format!("Unable to create open file: {error}"))
    })?;
    let text_editor_reference = text_editor.create_ref()?;
    self.open_editors
    .try_insert(path, text_editor_reference)
    .map_err(|_error| napi::Error::from_reason("Text editor already exists"))?;
    }
    Ok(())
    }
    #[tracing::instrument(skip_all)]
    pub fn get_text_editor<'env>(
    &self,
    env: &'env napi::Env,
    path: &Utf8Path,
    ) -> Result<Option<TextEditor<'env>>, napi::Error> {
    self.open_editors
    .get(path)
    .map(|reference| reference.get_inner(env))
    .transpose()
    }
    }
  • file addition: mod.rs (----------)
    [0.98972]
    use std::collections::HashMap;
    use camino::Utf8PathBuf;
    use crate::repository::open_repository::OpenRepository;
    use crate::vscode_sys;
    mod open_repository;
    #[derive(Default)]
    pub struct OpenRepositories {
    // TODO: proper URIs
    // TODO: multiple repositories per workspace folder
    repositories: HashMap<Utf8PathBuf, OpenRepository>,
    }
    impl OpenRepositories {
    #[tracing::instrument(skip_all)]
    pub fn new() -> Self {
    Self::default()
    }
    #[tracing::instrument(skip_all)]
    pub fn get_open_repository(
    &self,
    env: &napi::Env,
    uri: &vscode_sys::Uri,
    ) -> Result<Option<(Utf8PathBuf, &OpenRepository)>, napi::Error> {
    let Some(workspace_folder) = vscode_sys::workspace::get_workspace_folder(env, uri)? else {
    tracing::debug!(
    message = "URI does not correspond to a workspace folder",
    uri = ?uri.to_string()
    );
    return Ok(None);
    };
    let workspace_uri = workspace_folder.get_uri()?;
    let workspace_path = Utf8PathBuf::from(workspace_uri.get_fs_path()?);
    Ok(self
    .repositories
    .get(&workspace_path)
    .map(|open_repository| (workspace_path, open_repository)))
    }
    #[tracing::instrument(skip_all)]
    pub fn get_open_repository_mut(
    &mut self,
    env: &napi::Env,
    uri: &vscode_sys::Uri,
    ) -> Result<Option<(Utf8PathBuf, &mut OpenRepository)>, napi::Error> {
    let Some(workspace_folder) = vscode_sys::workspace::get_workspace_folder(env, uri)? else {
    tracing::debug!(
    message = "URI does not correspond to a workspace folder",
    uri = ?uri.to_string()
    );
    return Ok(None);
    };
    let workspace_uri = workspace_folder.get_uri()?;
    let workspace_path = Utf8PathBuf::from(workspace_uri.get_fs_path()?);
    Ok(self
    .repositories
    .get_mut(&workspace_path)
    .map(|open_repository| (workspace_path, open_repository)))
    }
    pub fn register_text_editors(
    &mut self,
    env: &napi::Env,
    text_editors: Vec<vscode_sys::TextEditor>,
    ) -> Result<(), napi::Error> {
    for text_editor in text_editors {
    let document = text_editor.get_document()?;
    let uri = document.get_uri()?;
    if let Some((repository_path, open_repository)) =
    self.get_open_repository_mut(env, &uri)?
    {
    let absolute_editor_path = Utf8PathBuf::from(uri.get_fs_path()?);
    let relative_editor_path = absolute_editor_path
    .strip_prefix(&repository_path)
    // TODO: error handling
    .unwrap()
    .to_path_buf();
    open_repository.register_text_editor(relative_editor_path, text_editor)?;
    tracing::debug!(
    message = "Registered text editor",
    ?repository_path,
    uri = uri.to_string()?
    );
    } else {
    // Ignore documents not part of any workspace folder
    tracing::debug!(
    message = "Ignoring text editor without valid workspace",
    uri = uri.to_string()?
    );
    }
    }
    Ok(())
    }
    #[tracing::instrument(skip_all)]
    pub fn open_workspace_folder(
    &mut self,
    env: &napi::Env,
    workspace_folder: vscode_sys::WorkspaceFolder,
    ) -> Result<(), napi::Error> {
    let repository_uri = workspace_folder.get_uri()?;
    let repository_path = Utf8PathBuf::from(repository_uri.get_fs_path()?);
    let open_repository = OpenRepository::new(env, &repository_uri)?;
    if self
    .repositories
    .try_insert(repository_path.clone(), open_repository)
    .is_err()
    {
    tracing::error!(
    message = "Failed to insert duplicate repository",
    ?repository_path
    );
    }
    Ok(())
    }
    #[tracing::instrument(skip_all)]
    pub fn close_workspace_folder(
    &mut self,
    workspace_folder: vscode_sys::WorkspaceFolder,
    ) -> Result<(), napi::Error> {
    let repository_uri = workspace_folder.get_uri()?;
    let repository_path = Utf8PathBuf::from(repository_uri.get_fs_path()?);
    if self.repositories.remove(&repository_path).is_none() {
    tracing::error!(
    message = "Failed to remove repository that does not exist",
    ?repository_path
    );
    }
    Ok(())
    }
    // TODO: remove this
    #[tracing::instrument(skip_all)]
    pub fn iter_repositories(&self) -> impl Iterator<Item = (&Utf8PathBuf, &OpenRepository)> {
    self.repositories.iter()
    }
    }
  • file addition: lib.rs (----------)
    [0.54351]
    #![feature(map_try_insert)]
    #![feature(mapped_lock_guards)]
    // TODO: panic handler
    // TODO: fix credits in quick diff panel
    // TODO: quick diff untracked files
    // TODO: find a way to validate all subscriptions are disposed? or just standardize how they are registered
    // TODO: replace `get_repository_folder` with something that can handle nested repositories
    // TODO: consistent naming
    // TODO: handle adding/removing workspace folders (and adding/removing .pijul folders)
    // TODO: handle changing active text editors
    // TODO: color workspace root with `gitDecoration.submoduleResourceForeground`?
    // TODO: something breaks when opening quick diff
    // TODO: static handling of package.json contributions
    // TODO: move l10n into pijul-extension
    use std::sync::{Mutex, MutexGuard, OnceLock};
    use camino::Utf8PathBuf;
    use napi::bindgen_prelude;
    use napi_derive::napi;
    use pijul_extension::{PathState, TrackedState};
    use repository::OpenRepositories;
    mod decorations;
    mod repository;
    mod vscode_sys;
    static EXTENSION_STATE: OnceLock<Mutex<ExtensionState>> = OnceLock::new();
    pub const PIJUL_SCHEME: &str = "pijul";
    struct ExtensionState {
    decoration_type: vscode_sys::reference::TextEditorDecorationTypeRef,
    repositories: OpenRepositories,
    }
    impl ExtensionState {
    fn get() -> Result<MutexGuard<'static, Self>, napi::Error> {
    EXTENSION_STATE
    .get()
    .ok_or_else(|| napi::Error::from_reason("Extension state is not set"))?
    .lock()
    .map_err(|_error| napi::Error::from_reason("Extension state mutex has been poisoned"))
    }
    }
    fn provide_file_decoration<'env>(
    env: &'env napi::Env,
    uri: vscode_sys::Uri,
    _cancellation_token: bindgen_prelude::Object,
    ) -> Result<Option<vscode_sys::FileDecoration<'env>>, napi::Error> {
    let program_state = ExtensionState::get()?;
    let Some((repository_path, open_repository)) =
    program_state.repositories.get_open_repository(env, &uri)?
    else {
    return Ok(None);
    };
    let absolute_file_path = Utf8PathBuf::from(uri.get_fs_path()?);
    let relative_file_path =
    absolute_file_path
    .strip_prefix(&repository_path)
    .map_err(|error| {
    napi::Error::from_reason(format!(
    "Failed to strip prefix {repository_path} from {absolute_file_path}: {error}"
    ))
    })?;
    let Some(path_state) = open_repository
    .repository
    .get_path_state(relative_file_path)
    else {
    return Ok(None);
    };
    // TODO: l10n_embed
    let (badge, tooltip, color_id) = match path_state {
    PathState::Untracked => ("U", "Untracked", "pijul.decorations.path.untracked"),
    PathState::Tracked(modified_state) => match modified_state {
    TrackedState::Added => ("A", "Added", "pijul.decorations.path.added"),
    TrackedState::Removed => ("RM", "Removed", "pijul.decorations.path.removed"),
    TrackedState::Modified => ("M", "Modified", "pijul.decorations.path.modified"),
    TrackedState::Moved => ("MV", "Moved", "pijul.decorations.path.moved"),
    TrackedState::ModifiedAndMoved => (
    "M,MV",
    "Modified, Moved",
    "pijul.decorations.path.modifiedAndMoved",
    ),
    },
    };
    let color = vscode_sys::ThemeColor::new(env, color_id)?;
    let path_decoration = vscode_sys::FileDecoration::new(env, badge, tooltip, &color)?;
    Ok(Some(path_decoration))
    }
    fn provide_text_document_content(
    env: &napi::Env,
    pijul_uri: vscode_sys::Uri,
    _cancellation_token: bindgen_prelude::Object,
    ) -> Result<Option<String>, napi::Error> {
    let program_state = ExtensionState::get()?;
    let uri_change = vscode_sys::UriWithChange::new(env)?.scheme("file")?;
    let uri = pijul_uri.with(uri_change)?;
    if let Some((workspace_path, workspace)) =
    program_state.repositories.get_open_repository(env, &uri)?
    {
    let absolute_path = Utf8PathBuf::from(uri.get_fs_path()?);
    let relative_path = absolute_path
    .strip_prefix(&workspace_path)
    .map_err(|error| {
    napi::Error::from_reason(format!(
    "Failed to strip prefix {workspace_path} from {absolute_path}: {error}"
    ))
    })?;
    match workspace.repository.get_open_file(relative_path) {
    Some(open_file) => Ok(Some(open_file.tracked_contents())),
    None => {
    tracing::error!(
    message = "No tracked file state for {relative_path}",
    ?workspace_path
    );
    Ok(None)
    }
    }
    } else {
    tracing::debug!(message = "Ignoring URI", uri = uri.to_string()?);
    Ok(None)
    }
    }
    fn provide_original_resource<'env>(
    env: &'env napi::Env,
    uri: vscode_sys::Uri<'env>,
    _cancellation_token: bindgen_prelude::Object,
    ) -> Result<Option<vscode_sys::Uri<'env>>, napi::Error> {
    // TODO: create a proper uri that preserves everything, including the original scheme
    let uri_change = vscode_sys::UriWithChange::new(env)?.scheme(PIJUL_SCHEME)?;
    let pijul_uri = uri.with(uri_change)?;
    Ok(Some(pijul_uri))
    }
    #[tracing::instrument(skip_all)]
    fn on_did_change_text_document(
    env: &napi::Env,
    event: vscode_sys::TextDocumentChangeEvent,
    ) -> Result<(), napi::Error> {
    let mut program_state = ExtensionState::get()?;
    let text_document = event.get_document()?;
    let document_uri = text_document.get_uri()?;
    // Ignore any messages printed to the `Output` channel (used by `tracing`)
    if document_uri.get_scheme()? == "output" {
    return Ok(());
    }
    if let Some((repository_path, open_repository)) = program_state
    .repositories
    .get_open_repository_mut(env, &document_uri)?
    {
    let absolute_document_path = Utf8PathBuf::from(document_uri.get_fs_path()?);
    tracing::debug!(?absolute_document_path);
    let relative_document_path = absolute_document_path
    .strip_prefix(&repository_path)
    .map_err(|error| napi::Error::from_reason(format!("Failed to strip prefix {repository_path} from {absolute_document_path}: {error}")))?;
    let change_events = event.get_content_changes()?;
    for change_event in change_events {
    let character_offset = change_event.get_range_offset()?;
    let characters_replaced = change_event.get_range_length()?;
    let replacement_text = change_event.get_text()?;
    open_repository
    .repository
    .update_open_file(
    relative_document_path,
    character_offset as usize,
    characters_replaced as usize,
    &replacement_text,
    )
    .map_err(|error| {
    napi::Error::from_reason(format!(
    "Unable to update open file {relative_document_path} ({absolute_document_path}): {error}"
    ))
    })?;
    }
    // TODO: avoid the flashing this causes
    // Re-render the inline credit annotation
    let text_editor = open_repository
    .get_text_editor(env, relative_document_path)?
    .ok_or_else(|| {
    napi::Error::from_reason(format!(
    "no open text editor for {absolute_document_path}"
    ))
    })?;
    let selections = text_editor.get_selections()?;
    decorations::inline_credit::render(env, &program_state, &text_editor, selections)?;
    }
    Ok(())
    }
    #[tracing::instrument(skip_all)]
    fn on_did_change_text_editor_selections(
    env: &napi::Env,
    event: vscode_sys::TextEditorSelectionChangeEvent,
    ) -> Result<(), napi::Error> {
    let program_state = ExtensionState::get()?;
    let editor = event.get_text_editor()?;
    let document = editor.get_document()?;
    let uri = document.get_uri()?;
    // Ignore any messages printed to the `Output` channel (used by `tracing`)
    if uri.get_scheme()? == "output" {
    return Ok(());
    }
    let selections = event.get_selections()?;
    decorations::inline_credit::render(env, &program_state, &editor, selections)
    }
    #[tracing::instrument(skip_all)]
    fn on_did_change_workspace_folders(
    env: &napi::Env,
    event: vscode_sys::WorkspaceFoldersChangeEvent,
    ) -> Result<(), napi::Error> {
    let mut program_state = ExtensionState::get()?;
    let added_workspaces = event.get_added()?;
    let removed_workspaces = event.get_removed()?;
    for added_workspace in added_workspaces {
    program_state
    .repositories
    .open_workspace_folder(env, added_workspace)?;
    }
    for removed_workspace in removed_workspaces {
    program_state
    .repositories
    .close_workspace_folder(removed_workspace)?;
    }
    Ok(())
    }
    // TODO: handle closing text editors
    #[tracing::instrument(skip_all)]
    fn on_did_change_visible_text_editors(
    env: &napi::Env,
    visible_text_editors: Vec<vscode_sys::TextEditor>,
    ) -> Result<(), napi::Error> {
    let mut extension_state = ExtensionState::get()?;
    extension_state
    .repositories
    .register_text_editors(env, visible_text_editors)
    }
    // TODO: make sure things are registered in order:
    // 1. Create extension state
    // 2. First-time init e.g. initial inline credit and open files
    // 3. Register extension state
    // 4. Providers
    // 5. Event handlers
    // TODO: remove catch_unwind (make activate_internal)
    #[napi(catch_unwind)]
    pub fn activate(
    env: &napi::Env,
    vscode_object: bindgen_prelude::Object,
    extension_context: bindgen_prelude::Object,
    ) -> Result<(), napi::Error> {
    vscode_sys::activate(&vscode_object, &extension_context)?;
    vscode_sys::log::init(
    env,
    "Pijul",
    tracing_subscriber::fmt::format::DefaultFields::new(),
    )?;
    let mut repositories = OpenRepositories::new();
    for workspace_folder in vscode_sys::workspace::get_workspace_folders(env)? {
    repositories.open_workspace_folder(env, workspace_folder)?;
    }
    let visible_text_editors = vscode_sys::window::get_visible_text_editors(env)?;
    repositories.register_text_editors(env, visible_text_editors)?;
    let decoration_type = decorations::create_decoration_type(env)?;
    let extension_state = ExtensionState {
    decoration_type: decoration_type.create_ref()?,
    repositories,
    };
    if let Some(active_text_editor) = vscode_sys::window::get_active_text_editor(env)? {
    let selections = active_text_editor.get_selections()?;
    decorations::inline_credit::render(env, &extension_state, &active_text_editor, selections)?;
    }
    EXTENSION_STATE
    .set(Mutex::new(extension_state))
    .map_err(|_existing_object| {
    napi::Error::from_reason("Extension state has already been set")
    })?;
    let file_decoration_provider =
    vscode_sys::FileDecorationProvider::new(env, provide_file_decoration)?;
    vscode_sys::window::register_file_decoration_provider(
    env,
    &extension_context,
    file_decoration_provider,
    )?;
    let text_document_provider =
    vscode_sys::TextDocumentContentProvider::new(env, provide_text_document_content)?;
    vscode_sys::workspace::register_text_document_content_provider(
    env,
    &extension_context,
    PIJUL_SCHEME,
    text_document_provider,
    )?;
    let mut quick_diff_provider = vscode_sys::QuickDiffProvider::new(env)?;
    quick_diff_provider.set_provide_original_resource(env, provide_original_resource)?;
    let program_state = ExtensionState::get()?;
    for (_repository_path, open_repository) in program_state.repositories.iter_repositories() {
    let mut source_control = open_repository.source_control.get_inner(env)?;
    source_control.set_quick_diff_provider(quick_diff_provider)?;
    }
    vscode_sys::window::on_did_change_text_editor_selections(
    env,
    on_did_change_text_editor_selections,
    )?;
    vscode_sys::window::on_did_change_visible_text_editors(
    env,
    on_did_change_visible_text_editors,
    )?;
    vscode_sys::workspace::on_did_change_text_document(env, on_did_change_text_document)?;
    vscode_sys::workspace::on_did_change_workspace_folders(env, on_did_change_workspace_folders)?;
    tracing::info!("Extension activated");
    Ok(())
    }
  • file addition: extension.ts (----------)
    [0.54351]
    // The module 'vscode' contains the VS Code extensibility API
    // Import the module and reference it with the alias vscode in your code below
    import * as vscode from "vscode";
    import nativeModule from "../out/native-module";
    // This method is called when your extension is activated
    // Your extension is activated the very first time the command is executed
    export function activate(context: vscode.ExtensionContext) {
    // Use the console to output diagnostic information (console.log) and errors (console.error)
    // This line of code will only be executed once when your extension is activated
    console.log('Congratulations, your extension "pijul-vscode" is now active!');
    nativeModule.activate(vscode, context);
    // The command has been defined in the package.json file
    // Now provide the implementation of the command with registerCommand
    // The commandId parameter must match the command field in package.json
    const disposable = vscode.commands.registerCommand(
    "pijul-vscode.helloWorld",
    () => {
    // The code you place here will be executed every time your command is executed
    // Display a message box to the user
    vscode.window.showInformationMessage("Hello World from pijul-vscode!");
    },
    );
    context.subscriptions.push(disposable);
    }
    // This method is called when your extension is deactivated
    export function deactivate() {}
  • file addition: decorations (d--r------)
    [0.54351]
  • file addition: mod.rs (----------)
    [0.122472]
    use crate::vscode_sys;
    pub mod inline_credit;
    pub fn create_decoration_type<'env>(
    env: &'env napi::Env,
    ) -> Result<vscode_sys::TextEditorDecorationType<'env>, napi::Error> {
    let theme_color =
    vscode_sys::ThemeColor::new(env, "pijul.decorations.inlineCredit.foreground")?;
    let after = vscode_sys::ThemableDecorationAttachmentRenderOptions::new(env)?
    // Margin of roughly 10 characters to the right
    // https://developer.mozilla.org/en-US/docs/Web/CSS/length#ch
    .margin("0 0 0 10ch")?
    .color(&theme_color)?;
    let render_options = vscode_sys::DecorationRenderOptions::new(env)?.after(after)?;
    let decoration_type =
    vscode_sys::window::create_text_editor_decoration_type(env, render_options)?;
    Ok(decoration_type)
    }
  • file addition: inline_credit.rs (----------)
    [0.122472]
    // TODO: better, localized hover messages
    // TODO: generate the enums in their own impl blocks
    use std::ops::RangeInclusive;
    use camino::Utf8PathBuf;
    use icu_locale::locale;
    use jiff::Timestamp;
    use l10n_embed::Localize;
    use l10n_embed_derive::localize;
    use napi::bindgen_prelude::JsObjectValue;
    use pijul_extension::FileSystemRepository;
    use pijul_extension::file_system::changes::CreditSource;
    use pijul_extension::file_system::changes::Span;
    use pijul_extension::file_system::open_file::OpenFile;
    use crate::ExtensionState;
    use crate::vscode_sys;
    #[localize("l10n/**/inline_credit.ftl")]
    enum AuthorKind<'change_header> {
    Local,
    Remote {
    username: &'change_header str,
    },
    Unknown {
    public_key_signature: &'change_header str,
    },
    }
    #[localize("l10n/**/inline_credit.ftl")]
    enum InlineCreditAnnotation<'change_header> {
    Tracked {
    authors: l10n_embed::list::AndList<AuthorKind<'change_header>>,
    timestamp: Timestamp,
    message: &'change_header str,
    },
    Untracked {
    timestamp: Timestamp,
    },
    }
    fn get_lines_selected(
    editor_selections: Vec<vscode_sys::Selection>,
    ) -> Result<Vec<RangeInclusive<usize>>, napi::Error> {
    let mut credits = Vec::with_capacity(editor_selections.len());
    for editor_selection in &editor_selections {
    let start_line = editor_selection.get_start()?.get_line()?;
    let end_line: u32 = editor_selection.get_end()?.get_line()?;
    credits.push((start_line as usize)..=(end_line as usize));
    }
    Ok(credits)
    }
    fn decoration_options<'env>(
    env: &napi::Env,
    localization_context: &l10n_embed::Context,
    repository: &FileSystemRepository,
    open_file: &OpenFile,
    credits: impl Iterator<Item = Span<CreditSource>>,
    ) -> Result<Vec<vscode_sys::DecorationOptions<'env>>, napi::Error> {
    let mut decoration_options_list = Vec::new();
    for credit in credits {
    tracing::debug!(?credit);
    let annotation = match credit.value {
    CreditSource::Tracked(change_id) => {
    let change_header = repository.get_change_header(&change_id).ok_or_else(|| {
    napi::Error::from_reason(format!("unable to get change {change_id:#?}"))
    })?;
    let authors = repository
    .authors_for_change(change_header)
    .into_iter()
    .map(|author_source| match author_source {
    pijul_extension::author::AuthorSource::Local(_identity) => {
    AuthorKind::Local
    }
    pijul_extension::author::AuthorSource::Remote(identity) => {
    AuthorKind::Remote {
    username: &identity.config.author.username,
    }
    }
    pijul_extension::author::AuthorSource::Unknown(public_key_signature) => {
    AuthorKind::Unknown {
    public_key_signature,
    }
    }
    })
    .collect();
    InlineCreditAnnotation::Tracked {
    authors: l10n_embed::list::AndList::new(authors),
    timestamp: change_header.timestamp,
    message: &change_header.message,
    }
    }
    CreditSource::Untracked => InlineCreditAnnotation::Untracked {
    timestamp: Timestamp::try_from(open_file.contents.modified_time).map_err(
    |error| {
    napi::Error::from_reason(format!(
    "Failed to parse timestamp {:#?}: {error}",
    open_file.contents.modified_time
    ))
    },
    )?,
    },
    };
    let mut localized_annotation = String::new();
    annotation.localize(localization_context, &mut localized_annotation);
    let hover_message_text = match credit.value {
    CreditSource::Tracked(change_id) => {
    let change_header = repository.get_change_header(&change_id).ok_or_else(|| {
    napi::Error::from_reason(format!("unable to get change {change_id:#?}"))
    })?;
    match &change_header.description {
    Some(description) => {
    format!("<h2>{}</h2><p>{}</p>", change_header.message, description)
    }
    None => change_header.message.clone(),
    }
    }
    CreditSource::Untracked => String::new(),
    };
    for line in credit.lines {
    let current_line_contents = open_file
    .contents
    .text
    .get_line(line, ropey::LineType::LF_CR)
    .ok_or_else(|| napi::Error::from_reason(format!("no contents for line {line}")))?;
    let final_character_offset = current_line_contents.len() as u32;
    let start = vscode_sys::Position::new(env, line as u32, final_character_offset)?;
    let end = vscode_sys::Position::new(env, line as u32, final_character_offset)?;
    let range = vscode_sys::Range::new(env, &start, &end)?;
    let mut hover_message =
    vscode_sys::MarkdownString::new(env, &hover_message_text, false)?;
    hover_message
    .inner
    .set_named_property("supportHtml", true)?;
    let after = vscode_sys::ThemableDecorationAttachmentRenderOptions::new(env)?
    .content_text(&localized_annotation)?;
    let render_options =
    vscode_sys::DecorationInstanceRenderOptions::new(env)?.after(after)?;
    let decoration_options = vscode_sys::DecorationOptions::new(env, &range)?
    .hover_message(&hover_message)?
    .render_options(render_options)?;
    decoration_options_list.push(decoration_options);
    }
    }
    Ok(decoration_options_list)
    }
    // TODO: different rendering modes? e.g. render only at boundaries between lines, render only on cursors, etc
    pub fn render(
    env: &napi::Env,
    program_state: &ExtensionState,
    editor: &vscode_sys::TextEditor,
    selections: Vec<vscode_sys::Selection>,
    ) -> Result<(), napi::Error> {
    let editor_document = editor.get_document()?;
    let document_uri = editor_document.get_uri()?;
    let Some((repository_path, open_repository)) = program_state
    .repositories
    .get_open_repository(env, &document_uri)?
    else {
    return Ok(());
    };
    let absolute_file_path = Utf8PathBuf::from(document_uri.get_fs_path()?);
    let relative_file_path =
    absolute_file_path
    .strip_prefix(&repository_path)
    .map_err(|error| {
    napi::Error::from_reason(format!(
    "Failed to strip prefix {repository_path} from {absolute_file_path}: {error}"
    ))
    })?;
    let localization_context = l10n_embed::Context::new(locale!("en-US"), false);
    let lines_selected = get_lines_selected(selections)?;
    let open_file = open_repository
    .repository
    .get_open_file(relative_file_path)
    .ok_or_else(|| {
    napi::Error::from_reason(format!("unable to get open file for {relative_file_path}"))
    })?;
    let credits = lines_selected
    .into_iter()
    .flat_map(|line_range| open_file.credit(line_range));
    let decoration_options = decoration_options(
    env,
    &localization_context,
    &open_repository.repository,
    open_file,
    credits,
    )?;
    let decoration_type = program_state.decoration_type.get_inner(env)?;
    editor.set_decorations(decoration_type, decoration_options)?;
    Ok(())
    }
  • file addition: pnpm-lock.yaml (----------)
    [0.53768]
    lockfileVersion: '9.0'
    settings:
    autoInstallPeers: true
    excludeLinksFromLockfile: false
    importers:
    .:
    devDependencies:
    '@napi-rs/cli':
    specifier: ^3.3.1
    version: 3.4.1(@emnapi/runtime@1.7.1)(@types/node@22.19.1)
    '@types/node':
    specifier: 22.x
    version: 22.19.1
    '@types/vscode':
    specifier: ^1.105.0
    version: 1.106.1
    typescript:
    specifier: ^5.9.3
    version: 5.9.3
    packages:
    '@emnapi/core@1.7.1':
    resolution: {integrity: sha512-o1uhUASyo921r2XtHYOHy7gdkGLge8ghBEQHMWmyJFoXlpU58kIrhhN3w26lpQb6dspetweapMn2CSNwQ8I4wg==}
    '@emnapi/runtime@1.7.1':
    resolution: {integrity: sha512-PVtJr5CmLwYAU9PZDMITZoR5iAOShYREoR45EyyLrbntV50mdePTgUn4AmOw90Ifcj+x2kRjdzr1HP3RrNiHGA==}
    '@emnapi/wasi-threads@1.1.0':
    resolution: {integrity: sha512-WI0DdZ8xFSbgMjR1sFsKABJ/C5OnRrjT06JXbZKexJGrDuPTzZdDYfFlsgcCXCyf+suG5QU2e/y1Wo2V/OapLQ==}
    '@inquirer/ansi@1.0.2':
    resolution: {integrity: sha512-S8qNSZiYzFd0wAcyG5AXCvUHC5Sr7xpZ9wZ2py9XR88jUz8wooStVx5M6dRzczbBWjic9NP7+rY0Xi7qqK/aMQ==}
    engines: {node: '>=18'}
    '@inquirer/checkbox@4.3.2':
    resolution: {integrity: sha512-VXukHf0RR1doGe6Sm4F0Em7SWYLTHSsbGfJdS9Ja2bX5/D5uwVOEjr07cncLROdBvmnvCATYEWlHqYmXv2IlQA==}
    engines: {node: '>=18'}
    peerDependencies:
    '@types/node': '>=18'
    peerDependenciesMeta:
    '@types/node':
    optional: true
    '@inquirer/confirm@5.1.21':
    resolution: {integrity: sha512-KR8edRkIsUayMXV+o3Gv+q4jlhENF9nMYUZs9PA2HzrXeHI8M5uDag70U7RJn9yyiMZSbtF5/UexBtAVtZGSbQ==}
    engines: {node: '>=18'}
    peerDependencies:
    '@types/node': '>=18'
    peerDependenciesMeta:
    '@types/node':
    optional: true
    '@inquirer/core@10.3.2':
    resolution: {integrity: sha512-43RTuEbfP8MbKzedNqBrlhhNKVwoK//vUFNW3Q3vZ88BLcrs4kYpGg+B2mm5p2K/HfygoCxuKwJJiv8PbGmE0A==}
    engines: {node: '>=18'}
    peerDependencies:
    '@types/node': '>=18'
    peerDependenciesMeta:
    '@types/node':
    optional: true
    '@inquirer/editor@4.2.23':
    resolution: {integrity: sha512-aLSROkEwirotxZ1pBaP8tugXRFCxW94gwrQLxXfrZsKkfjOYC1aRvAZuhpJOb5cu4IBTJdsCigUlf2iCOu4ZDQ==}
    engines: {node: '>=18'}
    peerDependencies:
    '@types/node': '>=18'
    peerDependenciesMeta:
    '@types/node':
    optional: true
    '@inquirer/expand@4.0.23':
    resolution: {integrity: sha512-nRzdOyFYnpeYTTR2qFwEVmIWypzdAx/sIkCMeTNTcflFOovfqUk+HcFhQQVBftAh9gmGrpFj6QcGEqrDMDOiew==}
    engines: {node: '>=18'}
    peerDependencies:
    '@types/node': '>=18'
    peerDependenciesMeta:
    '@types/node':
    optional: true
    '@inquirer/external-editor@1.0.3':
    resolution: {integrity: sha512-RWbSrDiYmO4LbejWY7ttpxczuwQyZLBUyygsA9Nsv95hpzUWwnNTVQmAq3xuh7vNwCp07UTmE5i11XAEExx4RA==}
    engines: {node: '>=18'}
    peerDependencies:
    '@types/node': '>=18'
    peerDependenciesMeta:
    '@types/node':
    optional: true
    '@inquirer/figures@1.0.15':
    resolution: {integrity: sha512-t2IEY+unGHOzAaVM5Xx6DEWKeXlDDcNPeDyUpsRc6CUhBfU3VQOEl+Vssh7VNp1dR8MdUJBWhuObjXCsVpjN5g==}
    engines: {node: '>=18'}
    '@inquirer/input@4.3.1':
    resolution: {integrity: sha512-kN0pAM4yPrLjJ1XJBjDxyfDduXOuQHrBB8aLDMueuwUGn+vNpF7Gq7TvyVxx8u4SHlFFj4trmj+a2cbpG4Jn1g==}
    engines: {node: '>=18'}
    peerDependencies:
    '@types/node': '>=18'
    peerDependenciesMeta:
    '@types/node':
    optional: true
    '@inquirer/number@3.0.23':
    resolution: {integrity: sha512-5Smv0OK7K0KUzUfYUXDXQc9jrf8OHo4ktlEayFlelCjwMXz0299Y8OrI+lj7i4gCBY15UObk76q0QtxjzFcFcg==}
    engines: {node: '>=18'}
    peerDependencies:
    '@types/node': '>=18'
    peerDependenciesMeta:
    '@types/node':
    optional: true
    '@inquirer/password@4.0.23':
    resolution: {integrity: sha512-zREJHjhT5vJBMZX/IUbyI9zVtVfOLiTO66MrF/3GFZYZ7T4YILW5MSkEYHceSii/KtRk+4i3RE7E1CUXA2jHcA==}
    engines: {node: '>=18'}
    peerDependencies:
    '@types/node': '>=18'
    peerDependenciesMeta:
    '@types/node':
    optional: true
    '@inquirer/prompts@7.10.1':
    resolution: {integrity: sha512-Dx/y9bCQcXLI5ooQ5KyvA4FTgeo2jYj/7plWfV5Ak5wDPKQZgudKez2ixyfz7tKXzcJciTxqLeK7R9HItwiByg==}
    engines: {node: '>=18'}
    peerDependencies:
    '@types/node': '>=18'
    peerDependenciesMeta:
    '@types/node':
    optional: true
    '@inquirer/rawlist@4.1.11':
    resolution: {integrity: sha512-+LLQB8XGr3I5LZN/GuAHo+GpDJegQwuPARLChlMICNdwW7OwV2izlCSCxN6cqpL0sMXmbKbFcItJgdQq5EBXTw==}
    engines: {node: '>=18'}
    peerDependencies:
    '@types/node': '>=18'
    peerDependenciesMeta:
    '@types/node':
    optional: true
    '@inquirer/search@3.2.2':
    resolution: {integrity: sha512-p2bvRfENXCZdWF/U2BXvnSI9h+tuA8iNqtUKb9UWbmLYCRQxd8WkvwWvYn+3NgYaNwdUkHytJMGG4MMLucI1kA==}
    engines: {node: '>=18'}
    peerDependencies:
    '@types/node': '>=18'
    peerDependenciesMeta:
    '@types/node':
    optional: true
    '@inquirer/select@4.4.2':
    resolution: {integrity: sha512-l4xMuJo55MAe+N7Qr4rX90vypFwCajSakx59qe/tMaC1aEHWLyw68wF4o0A4SLAY4E0nd+Vt+EyskeDIqu1M6w==}
    engines: {node: '>=18'}
    peerDependencies:
    '@types/node': '>=18'
    peerDependenciesMeta:
    '@types/node':
    optional: true
    '@inquirer/type@3.0.10':
    resolution: {integrity: sha512-BvziSRxfz5Ov8ch0z/n3oijRSEcEsHnhggm4xFZe93DHcUCTlutlq9Ox4SVENAfcRD22UQq7T/atg9Wr3k09eA==}
    engines: {node: '>=18'}
    peerDependencies:
    '@types/node': '>=18'
    peerDependenciesMeta:
    '@types/node':
    optional: true
    '@napi-rs/cli@3.4.1':
    resolution: {integrity: sha512-ayhm+NfrP5Hmh7vy5pfyYm/ktYtLh2PrgdLuqHTAubO7RoO2JkUE4F991AtgYxNewwXI8+guZLxU8itV7QnDrQ==}
    engines: {node: '>= 16'}
    hasBin: true
    peerDependencies:
    '@emnapi/runtime': ^1.5.0
    peerDependenciesMeta:
    '@emnapi/runtime':
    optional: true
    '@napi-rs/cross-toolchain@1.0.3':
    resolution: {integrity: sha512-ENPfLe4937bsKVTDA6zdABx4pq9w0tHqRrJHyaGxgaPq03a2Bd1unD5XSKjXJjebsABJ+MjAv1A2OvCgK9yehg==}
    peerDependencies:
    '@napi-rs/cross-toolchain-arm64-target-aarch64': ^1.0.3
    '@napi-rs/cross-toolchain-arm64-target-armv7': ^1.0.3
    '@napi-rs/cross-toolchain-arm64-target-ppc64le': ^1.0.3
    '@napi-rs/cross-toolchain-arm64-target-s390x': ^1.0.3
    '@napi-rs/cross-toolchain-arm64-target-x86_64': ^1.0.3
    '@napi-rs/cross-toolchain-x64-target-aarch64': ^1.0.3
    '@napi-rs/cross-toolchain-x64-target-armv7': ^1.0.3
    '@napi-rs/cross-toolchain-x64-target-ppc64le': ^1.0.3
    '@napi-rs/cross-toolchain-x64-target-s390x': ^1.0.3
    '@napi-rs/cross-toolchain-x64-target-x86_64': ^1.0.3
    peerDependenciesMeta:
    '@napi-rs/cross-toolchain-arm64-target-aarch64':
    optional: true
    '@napi-rs/cross-toolchain-arm64-target-armv7':
    optional: true
    '@napi-rs/cross-toolchain-arm64-target-ppc64le':
    optional: true
    '@napi-rs/cross-toolchain-arm64-target-s390x':
    optional: true
    '@napi-rs/cross-toolchain-arm64-target-x86_64':
    optional: true
    '@napi-rs/cross-toolchain-x64-target-aarch64':
    optional: true
    '@napi-rs/cross-toolchain-x64-target-armv7':
    optional: true
    '@napi-rs/cross-toolchain-x64-target-ppc64le':
    optional: true
    '@napi-rs/cross-toolchain-x64-target-s390x':
    optional: true
    '@napi-rs/cross-toolchain-x64-target-x86_64':
    optional: true
    '@napi-rs/lzma-android-arm-eabi@1.4.5':
    resolution: {integrity: sha512-Up4gpyw2SacmyKWWEib06GhiDdF+H+CCU0LAV8pnM4aJIDqKKd5LHSlBht83Jut6frkB0vwEPmAkv4NjQ5u//Q==}
    engines: {node: '>= 10'}
    cpu: [arm]
    os: [android]
    '@napi-rs/lzma-android-arm64@1.4.5':
    resolution: {integrity: sha512-uwa8sLlWEzkAM0MWyoZJg0JTD3BkPknvejAFG2acUA1raXM8jLrqujWCdOStisXhqQjZ2nDMp3FV6cs//zjfuQ==}
    engines: {node: '>= 10'}
    cpu: [arm64]
    os: [android]
    '@napi-rs/lzma-darwin-arm64@1.4.5':
    resolution: {integrity: sha512-0Y0TQLQ2xAjVabrMDem1NhIssOZzF/y/dqetc6OT8mD3xMTDtF8u5BqZoX3MyPc9FzpsZw4ksol+w7DsxHrpMA==}
    engines: {node: '>= 10'}
    cpu: [arm64]
    os: [darwin]
    '@napi-rs/lzma-darwin-x64@1.4.5':
    resolution: {integrity: sha512-vR2IUyJY3En+V1wJkwmbGWcYiT8pHloTAWdW4pG24+51GIq+intst6Uf6D/r46citObGZrlX0QvMarOkQeHWpw==}
    engines: {node: '>= 10'}
    cpu: [x64]
    os: [darwin]
    '@napi-rs/lzma-freebsd-x64@1.4.5':
    resolution: {integrity: sha512-XpnYQC5SVovO35tF0xGkbHYjsS6kqyNCjuaLQ2dbEblFRr5cAZVvsJ/9h7zj/5FluJPJRDojVNxGyRhTp4z2lw==}
    engines: {node: '>= 10'}
    cpu: [x64]
    os: [freebsd]
    '@napi-rs/lzma-linux-arm-gnueabihf@1.4.5':
    resolution: {integrity: sha512-ic1ZZMoRfRMwtSwxkyw4zIlbDZGC6davC9r+2oX6x9QiF247BRqqT94qGeL5ZP4Vtz0Hyy7TEViWhx5j6Bpzvw==}
    engines: {node: '>= 10'}
    cpu: [arm]
    os: [linux]
    '@napi-rs/lzma-linux-arm64-gnu@1.4.5':
    resolution: {integrity: sha512-asEp7FPd7C1Yi6DQb45a3KPHKOFBSfGuJWXcAd4/bL2Fjetb2n/KK2z14yfW8YC/Fv6x3rBM0VAZKmJuz4tysg==}
    engines: {node: '>= 10'}
    cpu: [arm64]
    os: [linux]
    '@napi-rs/lzma-linux-arm64-musl@1.4.5':
    resolution: {integrity: sha512-yWjcPDgJ2nIL3KNvi4536dlT/CcCWO0DUyEOlBs/SacG7BeD6IjGh6yYzd3/X1Y3JItCbZoDoLUH8iB1lTXo3w==}
    engines: {node: '>= 10'}
    cpu: [arm64]
    os: [linux]
    '@napi-rs/lzma-linux-ppc64-gnu@1.4.5':
    resolution: {integrity: sha512-0XRhKuIU/9ZjT4WDIG/qnX7Xz7mSQHYZo9Gb3MP2gcvBgr6BA4zywQ9k3gmQaPn9ECE+CZg2V7DV7kT+x2pUMQ==}
    engines: {node: '>= 10'}
    cpu: [ppc64]
    os: [linux]
    '@napi-rs/lzma-linux-riscv64-gnu@1.4.5':
    resolution: {integrity: sha512-QrqDIPEUUB23GCpyQj/QFyMlr8SGxxyExeZz9OWFnHfb70kXdTLWrHS/hEI1Ru+lSbQ/6xRqeoGyQ4Aqdg+/RA==}
    engines: {node: '>= 10'}
    cpu: [riscv64]
    os: [linux]
    '@napi-rs/lzma-linux-s390x-gnu@1.4.5':
    resolution: {integrity: sha512-k8RVM5aMhW86E9H0QXdquwojew4H3SwPxbRVbl49/COJQWCUjGi79X6mYruMnMPEznZinUiT1jgKbFo2A00NdA==}
    engines: {node: '>= 10'}
    cpu: [s390x]
    os: [linux]
    '@napi-rs/lzma-linux-x64-gnu@1.4.5':
    resolution: {integrity: sha512-6rMtBgnIq2Wcl1rQdZsnM+rtCcVCbws1nF8S2NzaUsVaZv8bjrPiAa0lwg4Eqnn1d9lgwqT+cZgm5m+//K08Kw==}
    engines: {node: '>= 10'}
    cpu: [x64]
    os: [linux]
    '@napi-rs/lzma-linux-x64-musl@1.4.5':
    resolution: {integrity: sha512-eiadGBKi7Vd0bCArBUOO/qqRYPHt/VQVvGyYvDFt6C2ZSIjlD+HuOl+2oS1sjf4CFjK4eDIog6EdXnL0NE6iyQ==}
    engines: {node: '>= 10'}
    cpu: [x64]
    os: [linux]
    '@napi-rs/lzma-wasm32-wasi@1.4.5':
    resolution: {integrity: sha512-+VyHHlr68dvey6fXc2hehw9gHVFIW3TtGF1XkcbAu65qVXsA9D/T+uuoRVqhE+JCyFHFrO0ixRbZDRK1XJt1sA==}
    engines: {node: '>=14.0.0'}
    cpu: [wasm32]
    '@napi-rs/lzma-win32-arm64-msvc@1.4.5':
    resolution: {integrity: sha512-eewnqvIyyhHi3KaZtBOJXohLvwwN27gfS2G/YDWdfHlbz1jrmfeHAmzMsP5qv8vGB+T80TMHNkro4kYjeh6Deg==}
    engines: {node: '>= 10'}
    cpu: [arm64]
    os: [win32]
    '@napi-rs/lzma-win32-ia32-msvc@1.4.5':
    resolution: {integrity: sha512-OeacFVRCJOKNU/a0ephUfYZ2Yt+NvaHze/4TgOwJ0J0P4P7X1mHzN+ig9Iyd74aQDXYqc7kaCXA2dpAOcH87Cg==}
    engines: {node: '>= 10'}
    cpu: [ia32]
    os: [win32]
    '@napi-rs/lzma-win32-x64-msvc@1.4.5':
    resolution: {integrity: sha512-T4I1SamdSmtyZgDXGAGP+y5LEK5vxHUFwe8mz6D4R7Sa5/WCxTcCIgPJ9BD7RkpO17lzhlaM2vmVvMy96Lvk9Q==}
    engines: {node: '>= 10'}
    cpu: [x64]
    os: [win32]
    '@napi-rs/lzma@1.4.5':
    resolution: {integrity: sha512-zS5LuN1OBPAyZpda2ZZgYOEDC+xecUdAGnrvbYzjnLXkrq/OBC3B9qcRvlxbDR3k5H/gVfvef1/jyUqPknqjbg==}
    engines: {node: '>= 10'}
    '@napi-rs/tar-android-arm-eabi@1.1.0':
    resolution: {integrity: sha512-h2Ryndraj/YiKgMV/r5by1cDusluYIRT0CaE0/PekQ4u+Wpy2iUVqvzVU98ZPnhXaNeYxEvVJHNGafpOfaD0TA==}
    engines: {node: '>= 10'}
    cpu: [arm]
    os: [android]
    '@napi-rs/tar-android-arm64@1.1.0':
    resolution: {integrity: sha512-DJFyQHr1ZxNZorm/gzc1qBNLF/FcKzcH0V0Vwan5P+o0aE2keQIGEjJ09FudkF9v6uOuJjHCVDdK6S6uHtShAw==}
    engines: {node: '>= 10'}
    cpu: [arm64]
    os: [android]
    '@napi-rs/tar-darwin-arm64@1.1.0':
    resolution: {integrity: sha512-Zz2sXRzjIX4e532zD6xm2SjXEym6MkvfCvL2RMpG2+UwNVDVscHNcz3d47Pf3sysP2e2af7fBB3TIoK2f6trPw==}
    engines: {node: '>= 10'}
    cpu: [arm64]
    os: [darwin]
    '@napi-rs/tar-darwin-x64@1.1.0':
    resolution: {integrity: sha512-EI+CptIMNweT0ms9S3mkP/q+J6FNZ1Q6pvpJOEcWglRfyfQpLqjlC0O+dptruTPE8VamKYuqdjxfqD8hifZDOA==}
    engines: {node: '>= 10'}
    cpu: [x64]
    os: [darwin]
    '@napi-rs/tar-freebsd-x64@1.1.0':
    resolution: {integrity: sha512-J0PIqX+pl6lBIAckL/c87gpodLbjZB1OtIK+RDscKC9NLdpVv6VGOxzUV/fYev/hctcE8EfkLbgFOfpmVQPg2g==}
    engines: {node: '>= 10'}
    cpu: [x64]
    os: [freebsd]
    '@napi-rs/tar-linux-arm-gnueabihf@1.1.0':
    resolution: {integrity: sha512-SLgIQo3f3EjkZ82ZwvrEgFvMdDAhsxCYjyoSuWfHCz0U16qx3SuGCp8+FYOPYCECHN3ZlGjXnoAIt9ERd0dEUg==}
    engines: {node: '>= 10'}
    cpu: [arm]
    os: [linux]
    '@napi-rs/tar-linux-arm64-gnu@1.1.0':
    resolution: {integrity: sha512-d014cdle52EGaH6GpYTQOP9Py7glMO1zz/+ynJPjjzYFSxvdYx0byrjumZk2UQdIyGZiJO2MEFpCkEEKFSgPYA==}
    engines: {node: '>= 10'}
    cpu: [arm64]
    os: [linux]
    '@napi-rs/tar-linux-arm64-musl@1.1.0':
    resolution: {integrity: sha512-L/y1/26q9L/uBqiW/JdOb/Dc94egFvNALUZV2WCGKQXc6UByPBMgdiEyW2dtoYxYYYYc+AKD+jr+wQPcvX2vrQ==}
    engines: {node: '>= 10'}
    cpu: [arm64]
    os: [linux]
    '@napi-rs/tar-linux-ppc64-gnu@1.1.0':
    resolution: {integrity: sha512-EPE1K/80RQvPbLRJDJs1QmCIcH+7WRi0F73+oTe1582y9RtfGRuzAkzeBuAGRXAQEjRQw/RjtNqr6UTJ+8UuWQ==}
    engines: {node: '>= 10'}
    cpu: [ppc64]
    os: [linux]
    '@napi-rs/tar-linux-s390x-gnu@1.1.0':
    resolution: {integrity: sha512-B2jhWiB1ffw1nQBqLUP1h4+J1ovAxBOoe5N2IqDMOc63fsPZKNqF1PvO/dIem8z7LL4U4bsfmhy3gBfu547oNQ==}
    engines: {node: '>= 10'}
    cpu: [s390x]
    os: [linux]
    '@napi-rs/tar-linux-x64-gnu@1.1.0':
    resolution: {integrity: sha512-tbZDHnb9617lTnsDMGo/eAMZxnsQFnaRe+MszRqHguKfMwkisc9CCJnks/r1o84u5fECI+J/HOrKXgczq/3Oww==}
    engines: {node: '>= 10'}
    cpu: [x64]
    os: [linux]
    '@napi-rs/tar-linux-x64-musl@1.1.0':
    resolution: {integrity: sha512-dV6cODlzbO8u6Anmv2N/ilQHq/AWz0xyltuXoLU3yUyXbZcnWYZuB2rL8OBGPmqNcD+x9NdScBNXh7vWN0naSQ==}
    engines: {node: '>= 10'}
    cpu: [x64]
    os: [linux]
    '@napi-rs/tar-wasm32-wasi@1.1.0':
    resolution: {integrity: sha512-jIa9nb2HzOrfH0F8QQ9g3WE4aMH5vSI5/1NYVNm9ysCmNjCCtMXCAhlI3WKCdm/DwHf0zLqdrrtDFXODcNaqMw==}
    engines: {node: '>=14.0.0'}
    cpu: [wasm32]
    '@napi-rs/tar-win32-arm64-msvc@1.1.0':
    resolution: {integrity: sha512-vfpG71OB0ijtjemp3WTdmBKJm9R70KM8vsSExMsIQtV0lVzP07oM1CW6JbNRPXNLhRoue9ofYLiUDk8bE0Hckg==}
    engines: {node: '>= 10'}
    cpu: [arm64]
    os: [win32]
    '@napi-rs/tar-win32-ia32-msvc@1.1.0':
    resolution: {integrity: sha512-hGPyPW60YSpOSgzfy68DLBHgi6HxkAM+L59ZZZPMQ0TOXjQg+p2EW87+TjZfJOkSpbYiEkULwa/f4a2hcVjsqQ==}
    engines: {node: '>= 10'}
    cpu: [ia32]
    os: [win32]
    '@napi-rs/tar-win32-x64-msvc@1.1.0':
    resolution: {integrity: sha512-L6Ed1DxXK9YSCMyvpR8MiNAyKNkQLjsHsHK9E0qnHa8NzLFqzDKhvs5LfnWxM2kJ+F7m/e5n9zPm24kHb3LsVw==}
    engines: {node: '>= 10'}
    cpu: [x64]
    os: [win32]
    '@napi-rs/tar@1.1.0':
    resolution: {integrity: sha512-7cmzIu+Vbupriudo7UudoMRH2OA3cTw67vva8MxeoAe5S7vPFI7z0vp0pMXiA25S8IUJefImQ90FeJjl8fjEaQ==}
    engines: {node: '>= 10'}
    '@napi-rs/wasm-runtime@1.0.7':
    resolution: {integrity: sha512-SeDnOO0Tk7Okiq6DbXmmBODgOAb9dp9gjlphokTUxmt8U3liIP1ZsozBahH69j/RJv+Rfs6IwUKHTgQYJ/HBAw==}
    '@napi-rs/wasm-tools-android-arm-eabi@1.0.1':
    resolution: {integrity: sha512-lr07E/l571Gft5v4aA1dI8koJEmF1F0UigBbsqg9OWNzg80H3lDPO+auv85y3T/NHE3GirDk7x/D3sLO57vayw==}
    engines: {node: '>= 10'}
    cpu: [arm]
    os: [android]
    '@napi-rs/wasm-tools-android-arm64@1.0.1':
    resolution: {integrity: sha512-WDR7S+aRLV6LtBJAg5fmjKkTZIdrEnnQxgdsb7Cf8pYiMWBHLU+LC49OUVppQ2YSPY0+GeYm9yuZWW3kLjJ7Bg==}
    engines: {node: '>= 10'}
    cpu: [arm64]
    os: [android]
    '@napi-rs/wasm-tools-darwin-arm64@1.0.1':
    resolution: {integrity: sha512-qWTI+EEkiN0oIn/N2gQo7+TVYil+AJ20jjuzD2vATS6uIjVz+Updeqmszi7zq7rdFTLp6Ea3/z4kDKIfZwmR9g==}
    engines: {node: '>= 10'}
    cpu: [arm64]
    os: [darwin]
    '@napi-rs/wasm-tools-darwin-x64@1.0.1':
    resolution: {integrity: sha512-bA6hubqtHROR5UI3tToAF/c6TDmaAgF0SWgo4rADHtQ4wdn0JeogvOk50gs2TYVhKPE2ZD2+qqt7oBKB+sxW3A==}
    engines: {node: '>= 10'}
    cpu: [x64]
    os: [darwin]
    '@napi-rs/wasm-tools-freebsd-x64@1.0.1':
    resolution: {integrity: sha512-90+KLBkD9hZEjPQW1MDfwSt5J1L46EUKacpCZWyRuL6iIEO5CgWU0V/JnEgFsDOGyyYtiTvHc5bUdUTWd4I9Vg==}
    engines: {node: '>= 10'}
    cpu: [x64]
    os: [freebsd]
    '@napi-rs/wasm-tools-linux-arm64-gnu@1.0.1':
    resolution: {integrity: sha512-rG0QlS65x9K/u3HrKafDf8cFKj5wV2JHGfl8abWgKew0GVPyp6vfsDweOwHbWAjcHtp2LHi6JHoW80/MTHm52Q==}
    engines: {node: '>= 10'}
    cpu: [arm64]
    os: [linux]
    '@napi-rs/wasm-tools-linux-arm64-musl@1.0.1':
    resolution: {integrity: sha512-jAasbIvjZXCgX0TCuEFQr+4D6Lla/3AAVx2LmDuMjgG4xoIXzjKWl7c4chuaD+TI+prWT0X6LJcdzFT+ROKGHQ==}
    engines: {node: '>= 10'}
    cpu: [arm64]
    os: [linux]
    '@napi-rs/wasm-tools-linux-x64-gnu@1.0.1':
    resolution: {integrity: sha512-Plgk5rPqqK2nocBGajkMVbGm010Z7dnUgq0wtnYRZbzWWxwWcXfZMPa8EYxrK4eE8SzpI7VlZP1tdVsdjgGwMw==}
    engines: {node: '>= 10'}
    cpu: [x64]
    os: [linux]
    '@napi-rs/wasm-tools-linux-x64-musl@1.0.1':
    resolution: {integrity: sha512-GW7AzGuWxtQkyHknHWYFdR0CHmW6is8rG2Rf4V6GNmMpmwtXt/ItWYWtBe4zqJWycMNazpfZKSw/BpT7/MVCXQ==}
    engines: {node: '>= 10'}
    cpu: [x64]
    os: [linux]
    '@napi-rs/wasm-tools-wasm32-wasi@1.0.1':
    resolution: {integrity: sha512-/nQVSTrqSsn7YdAc2R7Ips/tnw5SPUcl3D7QrXCNGPqjbatIspnaexvaOYNyKMU6xPu+pc0BTnKVmqhlJJCPLA==}
    engines: {node: '>=14.0.0'}
    cpu: [wasm32]
    '@napi-rs/wasm-tools-win32-arm64-msvc@1.0.1':
    resolution: {integrity: sha512-PFi7oJIBu5w7Qzh3dwFea3sHRO3pojMsaEnUIy22QvsW+UJfNQwJCryVrpoUt8m4QyZXI+saEq/0r4GwdoHYFQ==}
    engines: {node: '>= 10'}
    cpu: [arm64]
    os: [win32]
    '@napi-rs/wasm-tools-win32-ia32-msvc@1.0.1':
    resolution: {integrity: sha512-gXkuYzxQsgkj05Zaq+KQTkHIN83dFAwMcTKa2aQcpYPRImFm2AQzEyLtpXmyCWzJ0F9ZYAOmbSyrNew8/us6bw==}
    engines: {node: '>= 10'}
    cpu: [ia32]
    os: [win32]
    '@napi-rs/wasm-tools-win32-x64-msvc@1.0.1':
    resolution: {integrity: sha512-rEAf05nol3e3eei2sRButmgXP+6ATgm0/38MKhz9Isne82T4rPIMYsCIFj0kOisaGeVwoi2fnm7O9oWp5YVnYQ==}
    engines: {node: '>= 10'}
    cpu: [x64]
    os: [win32]
    '@napi-rs/wasm-tools@1.0.1':
    resolution: {integrity: sha512-enkZYyuCdo+9jneCPE/0fjIta4wWnvVN9hBo2HuiMpRF0q3lzv1J6b/cl7i0mxZUKhBrV3aCKDBQnCOhwKbPmQ==}
    engines: {node: '>= 10'}
    '@octokit/auth-token@6.0.0':
    resolution: {integrity: sha512-P4YJBPdPSpWTQ1NU4XYdvHvXJJDxM6YwpS0FZHRgP7YFkdVxsWcpWGy/NVqlAA7PcPCnMacXlRm1y2PFZRWL/w==}
    engines: {node: '>= 20'}
    '@octokit/core@7.0.6':
    resolution: {integrity: sha512-DhGl4xMVFGVIyMwswXeyzdL4uXD5OGILGX5N8Y+f6W7LhC1Ze2poSNrkF/fedpVDHEEZ+PHFW0vL14I+mm8K3Q==}
    engines: {node: '>= 20'}
    '@octokit/endpoint@11.0.2':
    resolution: {integrity: sha512-4zCpzP1fWc7QlqunZ5bSEjxc6yLAlRTnDwKtgXfcI/FxxGoqedDG8V2+xJ60bV2kODqcGB+nATdtap/XYq2NZQ==}
    engines: {node: '>= 20'}
    '@octokit/graphql@9.0.3':
    resolution: {integrity: sha512-grAEuupr/C1rALFnXTv6ZQhFuL1D8G5y8CN04RgrO4FIPMrtm+mcZzFG7dcBm+nq+1ppNixu+Jd78aeJOYxlGA==}
    engines: {node: '>= 20'}
    '@octokit/openapi-types@27.0.0':
    resolution: {integrity: sha512-whrdktVs1h6gtR+09+QsNk2+FO+49j6ga1c55YZudfEG+oKJVvJLQi3zkOm5JjiUXAagWK2tI2kTGKJ2Ys7MGA==}
    '@octokit/plugin-paginate-rest@14.0.0':
    resolution: {integrity: sha512-fNVRE7ufJiAA3XUrha2omTA39M6IXIc6GIZLvlbsm8QOQCYvpq/LkMNGyFlB1d8hTDzsAXa3OKtybdMAYsV/fw==}
    engines: {node: '>= 20'}
    peerDependencies:
    '@octokit/core': '>=6'
    '@octokit/plugin-request-log@6.0.0':
    resolution: {integrity: sha512-UkOzeEN3W91/eBq9sPZNQ7sUBvYCqYbrrD8gTbBuGtHEuycE4/awMXcYvx6sVYo7LypPhmQwwpUe4Yyu4QZN5Q==}
    engines: {node: '>= 20'}
    peerDependencies:
    '@octokit/core': '>=6'
    '@octokit/plugin-rest-endpoint-methods@17.0.0':
    resolution: {integrity: sha512-B5yCyIlOJFPqUUeiD0cnBJwWJO8lkJs5d8+ze9QDP6SvfiXSz1BF+91+0MeI1d2yxgOhU/O+CvtiZ9jSkHhFAw==}
    engines: {node: '>= 20'}
    peerDependencies:
    '@octokit/core': '>=6'
    '@octokit/request-error@7.1.0':
    resolution: {integrity: sha512-KMQIfq5sOPpkQYajXHwnhjCC0slzCNScLHs9JafXc4RAJI+9f+jNDlBNaIMTvazOPLgb4BnlhGJOTbnN0wIjPw==}
    engines: {node: '>= 20'}
    '@octokit/request@10.0.7':
    resolution: {integrity: sha512-v93h0i1yu4idj8qFPZwjehoJx4j3Ntn+JhXsdJrG9pYaX6j/XRz2RmasMUHtNgQD39nrv/VwTWSqK0RNXR8upA==}
    engines: {node: '>= 20'}
    '@octokit/rest@22.0.1':
    resolution: {integrity: sha512-Jzbhzl3CEexhnivb1iQ0KJ7s5vvjMWcmRtq5aUsKmKDrRW6z3r84ngmiFKFvpZjpiU/9/S6ITPFRpn5s/3uQJw==}
    engines: {node: '>= 20'}
    '@octokit/types@16.0.0':
    resolution: {integrity: sha512-sKq+9r1Mm4efXW1FCk7hFSeJo4QKreL/tTbR0rz/qx/r1Oa2VV83LTA/H/MuCOX7uCIJmQVRKBcbmWoySjAnSg==}
    '@tybys/wasm-util@0.10.1':
    resolution: {integrity: sha512-9tTaPJLSiejZKx+Bmog4uSubteqTvFrVrURwkmHixBo0G4seD0zUxp98E1DzUBJxLQ3NPwXrGKDiVjwx/DpPsg==}
    '@types/node@22.19.1':
    resolution: {integrity: sha512-LCCV0HdSZZZb34qifBsyWlUmok6W7ouER+oQIGBScS8EsZsQbrtFTUrDX4hOl+CS6p7cnNC4td+qrSVGSCTUfQ==}
    '@types/vscode@1.106.1':
    resolution: {integrity: sha512-R/HV8u2h8CAddSbX8cjpdd7B8/GnE4UjgjpuGuHcbp1xV6yh4OeqU4L1pKjlwujCrSFS0MOpwJAIs/NexMB1fQ==}
    ansi-regex@5.0.1:
    resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==}
    engines: {node: '>=8'}
    ansi-styles@4.3.0:
    resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==}
    engines: {node: '>=8'}
    argparse@2.0.1:
    resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==}
    before-after-hook@4.0.0:
    resolution: {integrity: sha512-q6tR3RPqIB1pMiTRMFcZwuG5T8vwp+vUvEG0vuI6B+Rikh5BfPp2fQ82c925FOs+b0lcFQ8CFrL+KbilfZFhOQ==}
    chardet@2.1.1:
    resolution: {integrity: sha512-PsezH1rqdV9VvyNhxxOW32/d75r01NY7TQCmOqomRo15ZSOKbpTFVsfjghxo6JloQUCGnH4k1LGu0R4yCLlWQQ==}
    cli-width@4.1.0:
    resolution: {integrity: sha512-ouuZd4/dm2Sw5Gmqy6bGyNNNe1qt9RpmxveLSO7KcgsTnU7RXfsw+/bukWGo1abgBiMAic068rclZsO4IWmmxQ==}
    engines: {node: '>= 12'}
    clipanion@4.0.0-rc.4:
    resolution: {integrity: sha512-CXkMQxU6s9GklO/1f714dkKBMu1lopS1WFF0B8o4AxPykR1hpozxSiUZ5ZUeBjfPgCWqbcNOtZVFhB8Lkfp1+Q==}
    peerDependencies:
    typanion: '*'
    color-convert@2.0.1:
    resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==}
    engines: {node: '>=7.0.0'}
    color-name@1.1.4:
    resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==}
    colorette@2.0.20:
    resolution: {integrity: sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==}
    debug@4.4.3:
    resolution: {integrity: sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==}
    engines: {node: '>=6.0'}
    peerDependencies:
    supports-color: '*'
    peerDependenciesMeta:
    supports-color:
    optional: true
    emnapi@1.7.1:
    resolution: {integrity: sha512-wlLK2xFq+T+rCBlY6+lPlFVDEyE93b7hSn9dMrfWBIcPf4ArwUvymvvMnN9M5WWuiryYQe9M+UJrkqw4trdyRA==}
    peerDependencies:
    node-addon-api: '>= 6.1.0'
    peerDependenciesMeta:
    node-addon-api:
    optional: true
    emoji-regex@8.0.0:
    resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==}
    es-toolkit@1.42.0:
    resolution: {integrity: sha512-SLHIyY7VfDJBM8clz4+T2oquwTQxEzu263AyhVK4jREOAwJ+8eebaa4wM3nlvnAqhDrMm2EsA6hWHaQsMPQ1nA==}
    fast-content-type-parse@3.0.0:
    resolution: {integrity: sha512-ZvLdcY8P+N8mGQJahJV5G4U88CSvT1rP8ApL6uETe88MBXrBHAkZlSEySdUlyztF7ccb+Znos3TFqaepHxdhBg==}
    iconv-lite@0.7.0:
    resolution: {integrity: sha512-cf6L2Ds3h57VVmkZe+Pn+5APsT7FpqJtEhhieDCvrE2MK5Qk9MyffgQyuxQTm6BChfeZNtcOLHp9IcWRVcIcBQ==}
    engines: {node: '>=0.10.0'}
    is-fullwidth-code-point@3.0.0:
    resolution: {integrity: sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==}
    engines: {node: '>=8'}
    js-yaml@4.1.1:
    resolution: {integrity: sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==}
    hasBin: true
    ms@2.1.3:
    resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==}
    mute-stream@2.0.0:
    resolution: {integrity: sha512-WWdIxpyjEn+FhQJQQv9aQAYlHoNVdzIzUySNV1gHUPDSdZJ3yZn7pAAbQcV7B56Mvu881q9FZV+0Vx2xC44VWA==}
    engines: {node: ^18.17.0 || >=20.5.0}
    safer-buffer@2.1.2:
    resolution: {integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==}
    semver@7.7.3:
    resolution: {integrity: sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==}
    engines: {node: '>=10'}
    hasBin: true
    signal-exit@4.1.0:
    resolution: {integrity: sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==}
    engines: {node: '>=14'}
    string-width@4.2.3:
    resolution: {integrity: sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==}
    engines: {node: '>=8'}
    strip-ansi@6.0.1:
    resolution: {integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==}
    engines: {node: '>=8'}
    tslib@2.8.1:
    resolution: {integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==}
    typanion@3.14.0:
    resolution: {integrity: sha512-ZW/lVMRabETuYCd9O9ZvMhAh8GslSqaUjxmK/JLPCh6l73CvLBiuXswj/+7LdnWOgYsQ130FqLzFz5aGT4I3Ug==}
    typescript@5.9.3:
    resolution: {integrity: sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==}
    engines: {node: '>=14.17'}
    hasBin: true
    undici-types@6.21.0:
    resolution: {integrity: sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==}
    universal-user-agent@7.0.3:
    resolution: {integrity: sha512-TmnEAEAsBJVZM/AADELsK76llnwcf9vMKuPz8JflO1frO8Lchitr0fNaN9d+Ap0BjKtqWqd/J17qeDnXh8CL2A==}
    wrap-ansi@6.2.0:
    resolution: {integrity: sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==}
    engines: {node: '>=8'}
    yoctocolors-cjs@2.1.3:
    resolution: {integrity: sha512-U/PBtDf35ff0D8X8D0jfdzHYEPFxAI7jJlxZXwCSez5M3190m+QobIfh+sWDWSHMCWWJN2AWamkegn6vr6YBTw==}
    engines: {node: '>=18'}
    snapshots:
    '@emnapi/core@1.7.1':
    dependencies:
    '@emnapi/wasi-threads': 1.1.0
    tslib: 2.8.1
    optional: true
    '@emnapi/runtime@1.7.1':
    dependencies:
    tslib: 2.8.1
    optional: true
    '@emnapi/wasi-threads@1.1.0':
    dependencies:
    tslib: 2.8.1
    optional: true
    '@inquirer/ansi@1.0.2': {}
    '@inquirer/checkbox@4.3.2(@types/node@22.19.1)':
    dependencies:
    '@inquirer/ansi': 1.0.2
    '@inquirer/core': 10.3.2(@types/node@22.19.1)
    '@inquirer/figures': 1.0.15
    '@inquirer/type': 3.0.10(@types/node@22.19.1)
    yoctocolors-cjs: 2.1.3
    optionalDependencies:
    '@types/node': 22.19.1
    '@inquirer/confirm@5.1.21(@types/node@22.19.1)':
    dependencies:
    '@inquirer/core': 10.3.2(@types/node@22.19.1)
    '@inquirer/type': 3.0.10(@types/node@22.19.1)
    optionalDependencies:
    '@types/node': 22.19.1
    '@inquirer/core@10.3.2(@types/node@22.19.1)':
    dependencies:
    '@inquirer/ansi': 1.0.2
    '@inquirer/figures': 1.0.15
    '@inquirer/type': 3.0.10(@types/node@22.19.1)
    cli-width: 4.1.0
    mute-stream: 2.0.0
    signal-exit: 4.1.0
    wrap-ansi: 6.2.0
    yoctocolors-cjs: 2.1.3
    optionalDependencies:
    '@types/node': 22.19.1
    '@inquirer/editor@4.2.23(@types/node@22.19.1)':
    dependencies:
    '@inquirer/core': 10.3.2(@types/node@22.19.1)
    '@inquirer/external-editor': 1.0.3(@types/node@22.19.1)
    '@inquirer/type': 3.0.10(@types/node@22.19.1)
    optionalDependencies:
    '@types/node': 22.19.1
    '@inquirer/expand@4.0.23(@types/node@22.19.1)':
    dependencies:
    '@inquirer/core': 10.3.2(@types/node@22.19.1)
    '@inquirer/type': 3.0.10(@types/node@22.19.1)
    yoctocolors-cjs: 2.1.3
    optionalDependencies:
    '@types/node': 22.19.1
    '@inquirer/external-editor@1.0.3(@types/node@22.19.1)':
    dependencies:
    chardet: 2.1.1
    iconv-lite: 0.7.0
    optionalDependencies:
    '@types/node': 22.19.1
    '@inquirer/figures@1.0.15': {}
    '@inquirer/input@4.3.1(@types/node@22.19.1)':
    dependencies:
    '@inquirer/core': 10.3.2(@types/node@22.19.1)
    '@inquirer/type': 3.0.10(@types/node@22.19.1)
    optionalDependencies:
    '@types/node': 22.19.1
    '@inquirer/number@3.0.23(@types/node@22.19.1)':
    dependencies:
    '@inquirer/core': 10.3.2(@types/node@22.19.1)
    '@inquirer/type': 3.0.10(@types/node@22.19.1)
    optionalDependencies:
    '@types/node': 22.19.1
    '@inquirer/password@4.0.23(@types/node@22.19.1)':
    dependencies:
    '@inquirer/ansi': 1.0.2
    '@inquirer/core': 10.3.2(@types/node@22.19.1)
    '@inquirer/type': 3.0.10(@types/node@22.19.1)
    optionalDependencies:
    '@types/node': 22.19.1
    '@inquirer/prompts@7.10.1(@types/node@22.19.1)':
    dependencies:
    '@inquirer/checkbox': 4.3.2(@types/node@22.19.1)
    '@inquirer/confirm': 5.1.21(@types/node@22.19.1)
    '@inquirer/editor': 4.2.23(@types/node@22.19.1)
    '@inquirer/expand': 4.0.23(@types/node@22.19.1)
    '@inquirer/input': 4.3.1(@types/node@22.19.1)
    '@inquirer/number': 3.0.23(@types/node@22.19.1)
    '@inquirer/password': 4.0.23(@types/node@22.19.1)
    '@inquirer/rawlist': 4.1.11(@types/node@22.19.1)
    '@inquirer/search': 3.2.2(@types/node@22.19.1)
    '@inquirer/select': 4.4.2(@types/node@22.19.1)
    optionalDependencies:
    '@types/node': 22.19.1
    '@inquirer/rawlist@4.1.11(@types/node@22.19.1)':
    dependencies:
    '@inquirer/core': 10.3.2(@types/node@22.19.1)
    '@inquirer/type': 3.0.10(@types/node@22.19.1)
    yoctocolors-cjs: 2.1.3
    optionalDependencies:
    '@types/node': 22.19.1
    '@inquirer/search@3.2.2(@types/node@22.19.1)':
    dependencies:
    '@inquirer/core': 10.3.2(@types/node@22.19.1)
    '@inquirer/figures': 1.0.15
    '@inquirer/type': 3.0.10(@types/node@22.19.1)
    yoctocolors-cjs: 2.1.3
    optionalDependencies:
    '@types/node': 22.19.1
    '@inquirer/select@4.4.2(@types/node@22.19.1)':
    dependencies:
    '@inquirer/ansi': 1.0.2
    '@inquirer/core': 10.3.2(@types/node@22.19.1)
    '@inquirer/figures': 1.0.15
    '@inquirer/type': 3.0.10(@types/node@22.19.1)
    yoctocolors-cjs: 2.1.3
    optionalDependencies:
    '@types/node': 22.19.1
    '@inquirer/type@3.0.10(@types/node@22.19.1)':
    optionalDependencies:
    '@types/node': 22.19.1
    '@napi-rs/cli@3.4.1(@emnapi/runtime@1.7.1)(@types/node@22.19.1)':
    dependencies:
    '@inquirer/prompts': 7.10.1(@types/node@22.19.1)
    '@napi-rs/cross-toolchain': 1.0.3
    '@napi-rs/wasm-tools': 1.0.1
    '@octokit/rest': 22.0.1
    clipanion: 4.0.0-rc.4(typanion@3.14.0)
    colorette: 2.0.20
    debug: 4.4.3
    emnapi: 1.7.1
    es-toolkit: 1.42.0
    js-yaml: 4.1.1
    semver: 7.7.3
    typanion: 3.14.0
    optionalDependencies:
    '@emnapi/runtime': 1.7.1
    transitivePeerDependencies:
    - '@napi-rs/cross-toolchain-arm64-target-aarch64'
    - '@napi-rs/cross-toolchain-arm64-target-armv7'
    - '@napi-rs/cross-toolchain-arm64-target-ppc64le'
    - '@napi-rs/cross-toolchain-arm64-target-s390x'
    - '@napi-rs/cross-toolchain-arm64-target-x86_64'
    - '@napi-rs/cross-toolchain-x64-target-aarch64'
    - '@napi-rs/cross-toolchain-x64-target-armv7'
    - '@napi-rs/cross-toolchain-x64-target-ppc64le'
    - '@napi-rs/cross-toolchain-x64-target-s390x'
    - '@napi-rs/cross-toolchain-x64-target-x86_64'
    - '@types/node'
    - node-addon-api
    - supports-color
    '@napi-rs/cross-toolchain@1.0.3':
    dependencies:
    '@napi-rs/lzma': 1.4.5
    '@napi-rs/tar': 1.1.0
    debug: 4.4.3
    transitivePeerDependencies:
    - supports-color
    '@napi-rs/lzma-android-arm-eabi@1.4.5':
    optional: true
    '@napi-rs/lzma-android-arm64@1.4.5':
    optional: true
    '@napi-rs/lzma-darwin-arm64@1.4.5':
    optional: true
    '@napi-rs/lzma-darwin-x64@1.4.5':
    optional: true
    '@napi-rs/lzma-freebsd-x64@1.4.5':
    optional: true
    '@napi-rs/lzma-linux-arm-gnueabihf@1.4.5':
    optional: true
    '@napi-rs/lzma-linux-arm64-gnu@1.4.5':
    optional: true
    '@napi-rs/lzma-linux-arm64-musl@1.4.5':
    optional: true
    '@napi-rs/lzma-linux-ppc64-gnu@1.4.5':
    optional: true
    '@napi-rs/lzma-linux-riscv64-gnu@1.4.5':
    optional: true
    '@napi-rs/lzma-linux-s390x-gnu@1.4.5':
    optional: true
    '@napi-rs/lzma-linux-x64-gnu@1.4.5':
    optional: true
    '@napi-rs/lzma-linux-x64-musl@1.4.5':
    optional: true
    '@napi-rs/lzma-wasm32-wasi@1.4.5':
    dependencies:
    '@napi-rs/wasm-runtime': 1.0.7
    optional: true
    '@napi-rs/lzma-win32-arm64-msvc@1.4.5':
    optional: true
    '@napi-rs/lzma-win32-ia32-msvc@1.4.5':
    optional: true
    '@napi-rs/lzma-win32-x64-msvc@1.4.5':
    optional: true
    '@napi-rs/lzma@1.4.5':
    optionalDependencies:
    '@napi-rs/lzma-android-arm-eabi': 1.4.5
    '@napi-rs/lzma-android-arm64': 1.4.5
    '@napi-rs/lzma-darwin-arm64': 1.4.5
    '@napi-rs/lzma-darwin-x64': 1.4.5
    '@napi-rs/lzma-freebsd-x64': 1.4.5
    '@napi-rs/lzma-linux-arm-gnueabihf': 1.4.5
    '@napi-rs/lzma-linux-arm64-gnu': 1.4.5
    '@napi-rs/lzma-linux-arm64-musl': 1.4.5
    '@napi-rs/lzma-linux-ppc64-gnu': 1.4.5
    '@napi-rs/lzma-linux-riscv64-gnu': 1.4.5
    '@napi-rs/lzma-linux-s390x-gnu': 1.4.5
    '@napi-rs/lzma-linux-x64-gnu': 1.4.5
    '@napi-rs/lzma-linux-x64-musl': 1.4.5
    '@napi-rs/lzma-wasm32-wasi': 1.4.5
    '@napi-rs/lzma-win32-arm64-msvc': 1.4.5
    '@napi-rs/lzma-win32-ia32-msvc': 1.4.5
    '@napi-rs/lzma-win32-x64-msvc': 1.4.5
    '@napi-rs/tar-android-arm-eabi@1.1.0':
    optional: true
    '@napi-rs/tar-android-arm64@1.1.0':
    optional: true
    '@napi-rs/tar-darwin-arm64@1.1.0':
    optional: true
    '@napi-rs/tar-darwin-x64@1.1.0':
    optional: true
    '@napi-rs/tar-freebsd-x64@1.1.0':
    optional: true
    '@napi-rs/tar-linux-arm-gnueabihf@1.1.0':
    optional: true
    '@napi-rs/tar-linux-arm64-gnu@1.1.0':
    optional: true
    '@napi-rs/tar-linux-arm64-musl@1.1.0':
    optional: true
    '@napi-rs/tar-linux-ppc64-gnu@1.1.0':
    optional: true
    '@napi-rs/tar-linux-s390x-gnu@1.1.0':
    optional: true
    '@napi-rs/tar-linux-x64-gnu@1.1.0':
    optional: true
    '@napi-rs/tar-linux-x64-musl@1.1.0':
    optional: true
    '@napi-rs/tar-wasm32-wasi@1.1.0':
    dependencies:
    '@napi-rs/wasm-runtime': 1.0.7
    optional: true
    '@napi-rs/tar-win32-arm64-msvc@1.1.0':
    optional: true
    '@napi-rs/tar-win32-ia32-msvc@1.1.0':
    optional: true
    '@napi-rs/tar-win32-x64-msvc@1.1.0':
    optional: true
    '@napi-rs/tar@1.1.0':
    optionalDependencies:
    '@napi-rs/tar-android-arm-eabi': 1.1.0
    '@napi-rs/tar-android-arm64': 1.1.0
    '@napi-rs/tar-darwin-arm64': 1.1.0
    '@napi-rs/tar-darwin-x64': 1.1.0
    '@napi-rs/tar-freebsd-x64': 1.1.0
    '@napi-rs/tar-linux-arm-gnueabihf': 1.1.0
    '@napi-rs/tar-linux-arm64-gnu': 1.1.0
    '@napi-rs/tar-linux-arm64-musl': 1.1.0
    '@napi-rs/tar-linux-ppc64-gnu': 1.1.0
    '@napi-rs/tar-linux-s390x-gnu': 1.1.0
    '@napi-rs/tar-linux-x64-gnu': 1.1.0
    '@napi-rs/tar-linux-x64-musl': 1.1.0
    '@napi-rs/tar-wasm32-wasi': 1.1.0
    '@napi-rs/tar-win32-arm64-msvc': 1.1.0
    '@napi-rs/tar-win32-ia32-msvc': 1.1.0
    '@napi-rs/tar-win32-x64-msvc': 1.1.0
    '@napi-rs/wasm-runtime@1.0.7':
    dependencies:
    '@emnapi/core': 1.7.1
    '@emnapi/runtime': 1.7.1
    '@tybys/wasm-util': 0.10.1
    optional: true
    '@napi-rs/wasm-tools-android-arm-eabi@1.0.1':
    optional: true
    '@napi-rs/wasm-tools-android-arm64@1.0.1':
    optional: true
    '@napi-rs/wasm-tools-darwin-arm64@1.0.1':
    optional: true
    '@napi-rs/wasm-tools-darwin-x64@1.0.1':
    optional: true
    '@napi-rs/wasm-tools-freebsd-x64@1.0.1':
    optional: true
    '@napi-rs/wasm-tools-linux-arm64-gnu@1.0.1':
    optional: true
    '@napi-rs/wasm-tools-linux-arm64-musl@1.0.1':
    optional: true
    '@napi-rs/wasm-tools-linux-x64-gnu@1.0.1':
    optional: true
    '@napi-rs/wasm-tools-linux-x64-musl@1.0.1':
    optional: true
    '@napi-rs/wasm-tools-wasm32-wasi@1.0.1':
    dependencies:
    '@napi-rs/wasm-runtime': 1.0.7
    optional: true
    '@napi-rs/wasm-tools-win32-arm64-msvc@1.0.1':
    optional: true
    '@napi-rs/wasm-tools-win32-ia32-msvc@1.0.1':
    optional: true
    '@napi-rs/wasm-tools-win32-x64-msvc@1.0.1':
    optional: true
    '@napi-rs/wasm-tools@1.0.1':
    optionalDependencies:
    '@napi-rs/wasm-tools-android-arm-eabi': 1.0.1
    '@napi-rs/wasm-tools-android-arm64': 1.0.1
    '@napi-rs/wasm-tools-darwin-arm64': 1.0.1
    '@napi-rs/wasm-tools-darwin-x64': 1.0.1
    '@napi-rs/wasm-tools-freebsd-x64': 1.0.1
    '@napi-rs/wasm-tools-linux-arm64-gnu': 1.0.1
    '@napi-rs/wasm-tools-linux-arm64-musl': 1.0.1
    '@napi-rs/wasm-tools-linux-x64-gnu': 1.0.1
    '@napi-rs/wasm-tools-linux-x64-musl': 1.0.1
    '@napi-rs/wasm-tools-wasm32-wasi': 1.0.1
    '@napi-rs/wasm-tools-win32-arm64-msvc': 1.0.1
    '@napi-rs/wasm-tools-win32-ia32-msvc': 1.0.1
    '@napi-rs/wasm-tools-win32-x64-msvc': 1.0.1
    '@octokit/auth-token@6.0.0': {}
    '@octokit/core@7.0.6':
    dependencies:
    '@octokit/auth-token': 6.0.0
    '@octokit/graphql': 9.0.3
    '@octokit/request': 10.0.7
    '@octokit/request-error': 7.1.0
    '@octokit/types': 16.0.0
    before-after-hook: 4.0.0
    universal-user-agent: 7.0.3
    '@octokit/endpoint@11.0.2':
    dependencies:
    '@octokit/types': 16.0.0
    universal-user-agent: 7.0.3
    '@octokit/graphql@9.0.3':
    dependencies:
    '@octokit/request': 10.0.7
    '@octokit/types': 16.0.0
    universal-user-agent: 7.0.3
    '@octokit/openapi-types@27.0.0': {}
    '@octokit/plugin-paginate-rest@14.0.0(@octokit/core@7.0.6)':
    dependencies:
    '@octokit/core': 7.0.6
    '@octokit/types': 16.0.0
    '@octokit/plugin-request-log@6.0.0(@octokit/core@7.0.6)':
    dependencies:
    '@octokit/core': 7.0.6
    '@octokit/plugin-rest-endpoint-methods@17.0.0(@octokit/core@7.0.6)':
    dependencies:
    '@octokit/core': 7.0.6
    '@octokit/types': 16.0.0
    '@octokit/request-error@7.1.0':
    dependencies:
    '@octokit/types': 16.0.0
    '@octokit/request@10.0.7':
    dependencies:
    '@octokit/endpoint': 11.0.2
    '@octokit/request-error': 7.1.0
    '@octokit/types': 16.0.0
    fast-content-type-parse: 3.0.0
    universal-user-agent: 7.0.3
    '@octokit/rest@22.0.1':
    dependencies:
    '@octokit/core': 7.0.6
    '@octokit/plugin-paginate-rest': 14.0.0(@octokit/core@7.0.6)
    '@octokit/plugin-request-log': 6.0.0(@octokit/core@7.0.6)
    '@octokit/plugin-rest-endpoint-methods': 17.0.0(@octokit/core@7.0.6)
    '@octokit/types@16.0.0':
    dependencies:
    '@octokit/openapi-types': 27.0.0
    '@tybys/wasm-util@0.10.1':
    dependencies:
    tslib: 2.8.1
    optional: true
    '@types/node@22.19.1':
    dependencies:
    undici-types: 6.21.0
    '@types/vscode@1.106.1': {}
    ansi-regex@5.0.1: {}
    ansi-styles@4.3.0:
    dependencies:
    color-convert: 2.0.1
    argparse@2.0.1: {}
    before-after-hook@4.0.0: {}
    chardet@2.1.1: {}
    cli-width@4.1.0: {}
    clipanion@4.0.0-rc.4(typanion@3.14.0):
    dependencies:
    typanion: 3.14.0
    color-convert@2.0.1:
    dependencies:
    color-name: 1.1.4
    color-name@1.1.4: {}
    colorette@2.0.20: {}
    debug@4.4.3:
    dependencies:
    ms: 2.1.3
    emnapi@1.7.1: {}
    emoji-regex@8.0.0: {}
    es-toolkit@1.42.0: {}
    fast-content-type-parse@3.0.0: {}
    iconv-lite@0.7.0:
    dependencies:
    safer-buffer: 2.1.2
    is-fullwidth-code-point@3.0.0: {}
    js-yaml@4.1.1:
    dependencies:
    argparse: 2.0.1
    ms@2.1.3: {}
    mute-stream@2.0.0: {}
    safer-buffer@2.1.2: {}
    semver@7.7.3: {}
    signal-exit@4.1.0: {}
    string-width@4.2.3:
    dependencies:
    emoji-regex: 8.0.0
    is-fullwidth-code-point: 3.0.0
    strip-ansi: 6.0.1
    strip-ansi@6.0.1:
    dependencies:
    ansi-regex: 5.0.1
    tslib@2.8.1:
    optional: true
    typanion@3.14.0: {}
    typescript@5.9.3: {}
    undici-types@6.21.0: {}
    universal-user-agent@7.0.3: {}
    wrap-ansi@6.2.0:
    dependencies:
    ansi-styles: 4.3.0
    string-width: 4.2.3
    strip-ansi: 6.0.1
    yoctocolors-cjs@2.1.3: {}
  • file addition: package.json (----------)
    [0.53768]
    {
    "name": "pijul",
    "displayName": "Pijul",
    "description": "The Pijul version control system",
    "version": "0.0.1",
    "engines": {
    "node": ">= 12.22.0 < 13 || >= 14.17.0 < 15 || >= 15.12.0 < 16 || >= 16.0.0",
    "vscode": "^1.105.0"
    },
    "categories": [
    "SCM Providers"
    ],
    "activationEvents": [
    "*"
    ],
    "main": "./out/extension.js",
    "contributes": {
    "colors": [
    {
    "id": "pijul.decorations.path.untracked",
    "description": "Color of untracked paths in the file explorer",
    "defaults": {
    "light": "gitDecoration.untrackedResourceForeground",
    "dark": "gitDecoration.untrackedResourceForeground"
    }
    },
    {
    "id": "pijul.decorations.path.added",
    "description": "Color of added paths in the file explorer",
    "defaults": {
    "light": "gitDecoration.addedResourceForeground",
    "dark": "gitDecoration.addedResourceForeground"
    }
    },
    {
    "id": "pijul.decorations.path.removed",
    "description": "Color of removed paths in the file explorer",
    "defaults": {
    "light": "gitDecoration.deletedResourceForeground",
    "dark": "gitDecoration.deletedResourceForeground"
    }
    },
    {
    "id": "pijul.decorations.path.modified",
    "description": "Color of modified paths in the file explorer",
    "defaults": {
    "light": "gitDecoration.modifiedResourceForeground",
    "dark": "gitDecoration.modifiedResourceForeground"
    }
    },
    {
    "id": "pijul.decorations.path.moved",
    "description": "Color of moved paths in the file explorer",
    "defaults": {
    "light": "gitDecoration.renamedResourceForeground",
    "dark": "gitDecoration.renamedResourceForeground"
    }
    },
    {
    "id": "pijul.decorations.path.modifiedAndMoved",
    "description": "Color of paths that have been both modified and moved in the file explorer",
    "defaults": {
    "light": "gitDecoration.modifiedResourceForeground",
    "dark": "gitDecoration.modifiedResourceForeground"
    }
    },
    {
    "id": "pijul.decorations.inlineCredit.foreground",
    "description": "Color of inline credit annotations rendered beside text selections",
    "defaults": {
    "light": "git.blame.editorDecorationForeground",
    "dark": "git.blame.editorDecorationForeground"
    }
    }
    ],
    "commands": [
    {
    "command": "pijul-vscode.helloWorld",
    "title": "Hello World"
    }
    ]
    },
    "napi": {
    "binaryName": "pijul-vscode"
    },
    "devDependencies": {
    "@napi-rs/cli": "^3.3.1",
    "@types/node": "22.x",
    "@types/vscode": "^1.105.0",
    "typescript": "^5.9.3"
    }
    }
  • file addition: l10n (d--r------)
    [0.53768]
  • file addition: en-US (d--r------)
    [0.175075]
  • file addition: inline_credit.ftl (----------)
    [0.175094]
    local = You
    remote = { $username }
    unknown = { $public-key-signature }
    tracked = { $authors }, { $timestamp } • { $message }
    untracked = { $timestamp } • Untracked changes
  • file addition: build.rs (----------)
    [0.53768]
    fn main() {
    napi_build::setup();
    }
  • file addition: Cargo.toml (----------)
    [0.53768]
    [package]
    name = "pijul-vscode"
    description = "Pijul version control support for Visual Studio Code"
    # Keys inherited from workspace
    authors.workspace = true
    categories.workspace = true
    edition.workspace = true
    keywords.workspace = true
    license.workspace = true
    repository.workspace = true
    version.workspace = true
    [lib]
    crate-type = ["cdylib"]
    [dependencies]
    pijul-extension.workspace = true
    camino.workspace = true
    icu_locale.workspace = true
    jiff.workspace = true
    l10n_embed.workspace = true
    l10n_embed_derive.workspace = true
    napi.workspace = true
    napi-derive.workspace = true
    napi-sys.workspace = true
    ropey.workspace = true
    tracing.workspace = true
    tracing-subscriber.workspace = true
    [build-dependencies]
    napi-build.workspace = true
  • file addition: Cargo.toml (----------)
    [2.1]
    [workspace]
    resolver = "3"
    members = ["xtask", "pijul-extension", "extensions/vscode"]
    [workspace.package]
    authors = ["Finchie <rust@finchie.dev>"]
    categories = ["development-tools", "text-editors"]
    edition = "2024"
    keywords = ["version control", "vcs", "editor"]
    repository = "https://nest.pijul.com/finchie/extension"
    license = "MIT OR Apache-2.0"
    version = "0.1.0"
    [workspace.lints.clippy]
    all = "deny"
    pedantic = "warn"
    nursery = "warn"
    cargo = "warn"
    [workspace.dependencies]
    pijul-extension.path = "pijul-extension"
    anyhow = "1.0"
    camino = "1.1"
    canonical-path = "2.0"
    cargo_metadata = "0.23"
    clap = { version = "4.5", features = ["derive"] }
    icu_locale = "2.0"
    jiff = "0.2"
    l10n_embed = "0.2"
    l10n_embed_derive = "0.2"
    # TODO: remove unused features
    libpijul.path = "../pijul/libpijul"
    napi = { version = "3.0", features = ["napi5"] }
    napi-build = "2"
    napi-derive = "3.0"
    napi-sys = "3.0"
    path-slash = "0.2"
    pijul-identity.path = "../pijul/pijul-identity"
    ropey = "2.0.0-beta"
    serde_json = "1.0"
    thiserror = "2"
    tracing = "0.1"
    tracing-subscriber = "0.3"
  • file addition: Cargo.lock (----------)
    [2.1]
    # This file is automatically @generated by Cargo.
    # It is not intended for manual editing.
    version = 4
    [[package]]
    name = "addr2line"
    version = "0.25.1"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "1b5d307320b3181d6d7954e663bd7c774a838b8220fe0593c86d9fb09f498b4b"
    dependencies = [
    "gimli",
    ]
    [[package]]
    name = "adler2"
    version = "2.0.1"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "320119579fcad9c21884f5c4861d16174d0e06250625266f50fe6898340abefa"
    [[package]]
    name = "adler32"
    version = "1.2.0"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "aae1277d39aeec15cb388266ecc24b11c80469deae6067e17a1a7aa9e5c1f234"
    [[package]]
    name = "aes"
    version = "0.7.5"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "9e8b47f52ea9bae42228d07ec09eb676433d7c4ed1ebdf0f1d1c29ed446f1ab8"
    dependencies = [
    "cfg-if",
    "cipher 0.3.0",
    "cpufeatures",
    "ctr",
    "opaque-debug",
    ]
    [[package]]
    name = "aho-corasick"
    version = "1.1.3"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916"
    dependencies = [
    "memchr",
    ]
    [[package]]
    name = "android_system_properties"
    version = "0.1.5"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311"
    dependencies = [
    "libc",
    ]
    [[package]]
    name = "anstream"
    version = "0.6.21"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "43d5b281e737544384e969a5ccad3f1cdd24b48086a0fc1b2a5262a26b8f4f4a"
    dependencies = [
    "anstyle",
    "anstyle-parse",
    "anstyle-query",
    "anstyle-wincon",
    "colorchoice",
    "is_terminal_polyfill",
    "utf8parse",
    ]
    [[package]]
    name = "anstyle"
    version = "1.0.13"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "5192cca8006f1fd4f7237516f40fa183bb07f8fbdfedaa0036de5ea9b0b45e78"
    [[package]]
    name = "anstyle-parse"
    version = "0.2.7"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "4e7644824f0aa2c7b9384579234ef10eb7efb6a0deb83f9630a49594dd9c15c2"
    dependencies = [
    "utf8parse",
    ]
    [[package]]
    name = "anstyle-query"
    version = "1.1.4"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "9e231f6134f61b71076a3eab506c379d4f36122f2af15a9ff04415ea4c3339e2"
    dependencies = [
    "windows-sys 0.60.2",
    ]
    [[package]]
    name = "anstyle-wincon"
    version = "3.0.10"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "3e0633414522a32ffaac8ac6cc8f748e090c5717661fddeea04219e2344f5f2a"
    dependencies = [
    "anstyle",
    "once_cell_polyfill",
    "windows-sys 0.60.2",
    ]
    [[package]]
    name = "anyhow"
    version = "1.0.100"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "a23eb6b1614318a8071c9b2521f36b424b2c83db5eb3a0fead4a6c0809af6e61"
    [[package]]
    name = "arrayref"
    version = "0.3.9"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "76a2e8124351fda1ef8aaaa3bbd7ebbcb486bbcd4225aca0aa0d84bb2db8fecb"
    [[package]]
    name = "arrayvec"
    version = "0.7.6"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "7c02d123df017efcdfbd739ef81735b36c5ba83ec3c59c80a9d7ecc718f92e50"
    [[package]]
    name = "atomic"
    version = "0.6.1"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "a89cbf775b137e9b968e67227ef7f775587cde3fd31b0d8599dbd0f598a48340"
    dependencies = [
    "bytemuck",
    ]
    [[package]]
    name = "autocfg"
    version = "1.5.0"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8"
    [[package]]
    name = "backtrace"
    version = "0.3.76"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "bb531853791a215d7c62a30daf0dde835f381ab5de4589cfe7c649d2cbe92bd6"
    dependencies = [
    "addr2line",
    "cfg-if",
    "libc",
    "miniz_oxide",
    "object",
    "rustc-demangle",
    "windows-link",
    ]
    [[package]]
    name = "backtrace-ext"
    version = "0.2.1"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "537beee3be4a18fb023b570f80e3ae28003db9167a751266b259926e25539d50"
    dependencies = [
    "backtrace",
    ]
    [[package]]
    name = "base64"
    version = "0.22.1"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6"
    [[package]]
    name = "base64ct"
    version = "1.8.0"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "55248b47b0caf0546f7988906588779981c43bb1bc9d0c44087278f80cdb44ba"
    [[package]]
    name = "bcrypt-pbkdf"
    version = "0.10.0"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "6aeac2e1fe888769f34f05ac343bbef98b14d1ffb292ab69d4608b3abc86f2a2"
    dependencies = [
    "blowfish",
    "pbkdf2 0.12.2",
    "sha2 0.10.9",
    ]
    [[package]]
    name = "bincode"
    version = "1.3.3"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "b1f45e9417d87227c7a56d22e471c6206462cba514c7590c09aff4cf6d1ddcad"
    dependencies = [
    "serde",
    ]
    [[package]]
    name = "bit-vec"
    version = "0.6.3"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "349f9b6a179ed607305526ca489b34ad0a41aed5f7980fa90eb03160b69598fb"
    [[package]]
    name = "bitflags"
    version = "1.3.2"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
    [[package]]
    name = "bitflags"
    version = "2.9.4"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "2261d10cca569e4643e526d8dc2e62e433cc8aba21ab764233731f8d369bf394"
    dependencies = [
    "serde",
    ]
    [[package]]
    name = "blake3"
    version = "1.8.2"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "3888aaa89e4b2a40fca9848e400f6a658a5a3978de7be858e209cafa8be9a4a0"
    dependencies = [
    "arrayref",
    "arrayvec",
    "cc",
    "cfg-if",
    "constant_time_eq",
    ]
    [[package]]
    name = "block-buffer"
    version = "0.9.0"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "4152116fd6e9dadb291ae18fc1ec3575ed6d84c29642d97890f4b4a3417297e4"
    dependencies = [
    "generic-array",
    ]
    [[package]]
    name = "block-buffer"
    version = "0.10.4"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71"
    dependencies = [
    "generic-array",
    ]
    [[package]]
    name = "block-modes"
    version = "0.8.1"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "2cb03d1bed155d89dce0f845b7899b18a9a163e148fd004e1c28421a783e2d8e"
    dependencies = [
    "block-padding",
    "cipher 0.3.0",
    ]
    [[package]]
    name = "block-padding"
    version = "0.2.1"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "8d696c370c750c948ada61c69a0ee2cbbb9c50b1019ddb86d9317157a99c2cae"
    [[package]]
    name = "blowfish"
    version = "0.9.1"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "e412e2cd0f2b2d93e02543ceae7917b3c70331573df19ee046bcbc35e45e87d7"
    dependencies = [
    "byteorder",
    "cipher 0.4.4",
    ]
    [[package]]
    name = "bs58"
    version = "0.4.0"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "771fe0050b883fcc3ea2359b1a96bcfbc090b7116eae7c3c512c7a083fdf23d3"
    [[package]]
    name = "bstr"
    version = "1.12.0"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "234113d19d0d7d613b40e86fb654acf958910802bcceab913a4f9e7cda03b1a4"
    dependencies = [
    "memchr",
    "serde",
    ]
    [[package]]
    name = "bumpalo"
    version = "3.19.0"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "46c5e41b57b8bba42a04676d81cb89e9ee8e859a1a66f80a5a72e1cb76b34d43"
    [[package]]
    name = "bytemuck"
    version = "1.24.0"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "1fbdf580320f38b612e485521afda1ee26d10cc9884efaaa750d383e13e3c5f4"
    [[package]]
    name = "byteorder"
    version = "1.5.0"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b"
    [[package]]
    name = "bytes"
    version = "1.11.0"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "b35204fbdc0b3f4446b89fc1ac2cf84a8a68971995d0bf2e925ec7cd960f9cb3"
    [[package]]
    name = "camino"
    version = "1.2.1"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "276a59bf2b2c967788139340c9f0c5b12d7fd6630315c15c217e559de85d2609"
    dependencies = [
    "serde_core",
    ]
    [[package]]
    name = "canonical-path"
    version = "2.0.2"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "e6e9e01327e6c86e92ec72b1c798d4a94810f147209bbe3ffab6a86954937a6f"
    [[package]]
    name = "cargo-platform"
    version = "0.3.1"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "122ec45a44b270afd1402f351b782c676b173e3c3fb28d86ff7ebfb4d86a4ee4"
    dependencies = [
    "serde",
    ]
    [[package]]
    name = "cargo_metadata"
    version = "0.23.0"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "981a6f317983eec002839b90fae7411a85621410ae591a9cab2ecf5cb5744873"
    dependencies = [
    "camino",
    "cargo-platform",
    "semver",
    "serde",
    "serde_json",
    "thiserror 2.0.17",
    ]
    [[package]]
    name = "cc"
    version = "1.2.41"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "ac9fe6cdbb24b6ade63616c0a0688e45bb56732262c158df3c0c4bea4ca47cb7"
    dependencies = [
    "find-msvc-tools",
    "shlex",
    ]
    [[package]]
    name = "cfg-if"
    version = "1.0.3"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "2fd1289c04a9ea8cb22300a459a72a385d7c73d3259e2ed7dcb2af674838cfa9"
    [[package]]
    name = "chardetng"
    version = "0.1.17"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "14b8f0b65b7b08ae3c8187e8d77174de20cb6777864c6b832d8ad365999cf1ea"
    dependencies = [
    "cfg-if",
    "encoding_rs",
    "memchr",
    ]
    [[package]]
    name = "chrono"
    version = "0.4.42"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "145052bdd345b87320e369255277e3fb5152762ad123a901ef5c262dd38fe8d2"
    dependencies = [
    "iana-time-zone",
    "num-traits",
    "serde",
    "windows-link",
    ]
    [[package]]
    name = "cipher"
    version = "0.3.0"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "7ee52072ec15386f770805afd189a01c8841be8696bed250fa2f13c4c0d6dfb7"
    dependencies = [
    "generic-array",
    ]
    [[package]]
    name = "cipher"
    version = "0.4.4"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "773f3b9af64447d2ce9850330c473515014aa235e6a783b02db81ff39e4a3dad"
    dependencies = [
    "crypto-common",
    "inout",
    ]
    [[package]]
    name = "clap"
    version = "4.5.49"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "f4512b90fa68d3a9932cea5184017c5d200f5921df706d45e853537dea51508f"
    dependencies = [
    "clap_builder",
    "clap_derive",
    ]
    [[package]]
    name = "clap_builder"
    version = "4.5.49"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "0025e98baa12e766c67ba13ff4695a887a1eba19569aad00a472546795bd6730"
    dependencies = [
    "anstream",
    "anstyle",
    "clap_lex",
    "strsim",
    ]
    [[package]]
    name = "clap_derive"
    version = "4.5.49"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "2a0b5487afeab2deb2ff4e03a807ad1a03ac532ff5a2cee5d86884440c7f7671"
    dependencies = [
    "heck",
    "proc-macro2",
    "quote",
    "syn",
    ]
    [[package]]
    name = "clap_lex"
    version = "0.7.6"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "a1d728cc89cf3aee9ff92b05e62b19ee65a02b5702cff7d5a377e32c6ae29d8d"
    [[package]]
    name = "colorchoice"
    version = "1.0.4"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "b05b61dc5112cbb17e4b6cd61790d9845d13888356391624cbe7e41efeac1e75"
    [[package]]
    name = "console"
    version = "0.15.11"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "054ccb5b10f9f2cbf51eb355ca1d05c2d279ce1804688d0db74b4733a5aeafd8"
    dependencies = [
    "encode_unicode",
    "libc",
    "once_cell",
    "unicode-width 0.2.2",
    "windows-sys 0.59.0",
    ]
    [[package]]
    name = "const_format"
    version = "0.2.35"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "7faa7469a93a566e9ccc1c73fe783b4a65c274c5ace346038dca9c39fe0030ad"
    dependencies = [
    "const_format_proc_macros",
    ]
    [[package]]
    name = "const_format_proc_macros"
    version = "0.2.34"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "1d57c2eccfb16dbac1f4e61e206105db5820c9d26c3c472bc17c774259ef7744"
    dependencies = [
    "proc-macro2",
    "quote",
    "unicode-xid",
    ]
    [[package]]
    name = "constant_time_eq"
    version = "0.3.1"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "7c74b8349d32d297c9134b8c88677813a227df8f779daa29bfc29c183fe3dca6"
    [[package]]
    name = "convert_case"
    version = "0.8.0"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "baaaa0ecca5b51987b9423ccdc971514dd8b0bb7b4060b983d3664dad3f1f89f"
    dependencies = [
    "unicode-segmentation",
    ]
    [[package]]
    name = "core-foundation"
    version = "0.9.4"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "91e195e091a93c46f7102ec7818a2aa394e1e1771c3ab4825963fa03e45afb8f"
    dependencies = [
    "core-foundation-sys",
    "libc",
    ]
    [[package]]
    name = "core-foundation"
    version = "0.10.1"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "b2a6cd9ae233e7f62ba4e9353e81a88df7fc8a5987b8d445b4d90c879bd156f6"
    dependencies = [
    "core-foundation-sys",
    "libc",
    ]
    [[package]]
    name = "core-foundation-sys"
    version = "0.8.7"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b"
    [[package]]
    name = "cpufeatures"
    version = "0.2.17"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "59ed5838eebb26a2bb2e58f6d5b5316989ae9d08bab10e0e6d103e656d1b0280"
    dependencies = [
    "libc",
    ]
    [[package]]
    name = "crc32fast"
    version = "1.5.0"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "9481c1c90cbf2ac953f07c8d4a58aa3945c425b7185c9154d67a65e4230da511"
    dependencies = [
    "cfg-if",
    ]
    [[package]]
    name = "crossbeam-deque"
    version = "0.8.6"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "9dd111b7b7f7d55b72c0a6ae361660ee5853c9af73f70c3c2ef6858b950e2e51"
    dependencies = [
    "crossbeam-epoch",
    "crossbeam-utils",
    ]
    [[package]]
    name = "crossbeam-epoch"
    version = "0.9.18"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "5b82ac4a3c2ca9c3460964f020e1402edd5753411d7737aa39c3714ad1b5420e"
    dependencies = [
    "crossbeam-utils",
    ]
    [[package]]
    name = "crossbeam-utils"
    version = "0.8.21"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28"
    [[package]]
    name = "crypto-common"
    version = "0.1.7"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "78c8292055d1c1df0cce5d180393dc8cce0abec0a7102adb6c7b1eef6016d60a"
    dependencies = [
    "generic-array",
    "typenum",
    ]
    [[package]]
    name = "crypto-mac"
    version = "0.11.1"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "b1d1a86f49236c215f271d40892d5fc950490551400b02ef360692c29815c714"
    dependencies = [
    "generic-array",
    "subtle",
    ]
    [[package]]
    name = "cryptovec"
    version = "0.6.1"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "ccc7fa13a6bbb2322d325292c57f4c8e7291595506f8289968a0eb61c3130bdf"
    dependencies = [
    "libc",
    "winapi",
    ]
    [[package]]
    name = "ctor"
    version = "0.5.0"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "67773048316103656a637612c4a62477603b777d91d9c62ff2290f9cde178fdb"
    dependencies = [
    "ctor-proc-macro",
    "dtor",
    ]
    [[package]]
    name = "ctor-proc-macro"
    version = "0.0.6"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "e2931af7e13dc045d8e9d26afccc6fa115d64e115c9c84b1166288b46f6782c2"
    [[package]]
    name = "ctr"
    version = "0.8.0"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "049bb91fb4aaf0e3c7efa6cd5ef877dbbbd15b39dad06d9948de4ec8a75761ea"
    dependencies = [
    "cipher 0.3.0",
    ]
    [[package]]
    name = "curve25519-dalek"
    version = "3.2.1"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "90f9d052967f590a76e62eb387bd0bbb1b000182c3cefe5364db6b7211651bc0"
    dependencies = [
    "byteorder",
    "digest 0.9.0",
    "rand_core 0.5.1",
    "serde",
    "subtle",
    "zeroize",
    ]
    [[package]]
    name = "darling"
    version = "0.21.3"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "9cdf337090841a411e2a7f3deb9187445851f91b309c0c0a29e05f74a00a48c0"
    dependencies = [
    "darling_core",
    "darling_macro",
    ]
    [[package]]
    name = "darling_core"
    version = "0.21.3"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "1247195ecd7e3c85f83c8d2a366e4210d588e802133e1e355180a9870b517ea4"
    dependencies = [
    "fnv",
    "ident_case",
    "proc-macro2",
    "quote",
    "strsim",
    "syn",
    ]
    [[package]]
    name = "darling_macro"
    version = "0.21.3"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "d38308df82d1080de0afee5d069fa14b0326a88c14f15c5ccda35b4a6c414c81"
    dependencies = [
    "darling_core",
    "quote",
    "syn",
    ]
    [[package]]
    name = "data-encoding"
    version = "2.9.0"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "2a2330da5de22e8a3cb63252ce2abb30116bf5265e89c0e01bc17015ce30a476"
    [[package]]
    name = "dbus"
    version = "0.9.9"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "190b6255e8ab55a7b568df5a883e9497edc3e4821c06396612048b430e5ad1e9"
    dependencies = [
    "libc",
    "libdbus-sys",
    "windows-sys 0.59.0",
    ]
    [[package]]
    name = "dbus-secret-service"
    version = "4.0.3"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "b42a16374481d92aed73ae45b1f120207d8e71d24fb89f357fadbd8f946fd84b"
    dependencies = [
    "dbus",
    "futures-util",
    "num",
    "once_cell",
    "rand 0.8.5",
    ]
    [[package]]
    name = "deranged"
    version = "0.5.5"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "ececcb659e7ba858fb4f10388c250a7252eb0a27373f1a72b8748afdd248e587"
    dependencies = [
    "powerfmt",
    "serde_core",
    ]
    [[package]]
    name = "dialoguer"
    version = "0.10.4"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "59c6f2989294b9a498d3ad5491a79c6deb604617378e1cdc4bfc1c1361fe2f87"
    dependencies = [
    "console",
    "fuzzy-matcher",
    "shell-words",
    "tempfile",
    "zeroize",
    ]
    [[package]]
    name = "diffs"
    version = "0.5.1"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "ff116c9781d74b71b9b8958281309dd2faaeabad2f0a3df27e50bd79ce5dc805"
    [[package]]
    name = "digest"
    version = "0.9.0"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "d3dd60d1080a57a05ab032377049e0591415d2b31afd7028356dbf3cc6dcb066"
    dependencies = [
    "generic-array",
    ]
    [[package]]
    name = "digest"
    version = "0.10.7"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292"
    dependencies = [
    "block-buffer 0.10.4",
    "crypto-common",
    "subtle",
    ]
    [[package]]
    name = "dirs"
    version = "3.0.2"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "30baa043103c9d0c2a57cf537cc2f35623889dc0d405e6c3cccfadbc81c71309"
    dependencies = [
    "dirs-sys",
    ]
    [[package]]
    name = "dirs-next"
    version = "2.0.0"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "b98cf8ebf19c3d1b223e151f99a4f9f0690dca41414773390fc824184ac833e1"
    dependencies = [
    "cfg-if",
    "dirs-sys-next",
    ]
    [[package]]
    name = "dirs-sys"
    version = "0.3.7"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "1b1d1d91c932ef41c0f2663aa8b0ca0342d444d842c06914aa0a7e352d0bada6"
    dependencies = [
    "libc",
    "redox_users",
    "winapi",
    ]
    [[package]]
    name = "dirs-sys-next"
    version = "0.1.2"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "4ebda144c4fe02d1f7ea1a7d9641b6fc6b580adcfa024ae48797ecdeb6825b4d"
    dependencies = [
    "libc",
    "redox_users",
    "winapi",
    ]
    [[package]]
    name = "displaydoc"
    version = "0.2.5"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0"
    dependencies = [
    "proc-macro2",
    "quote",
    "syn",
    ]
    [[package]]
    name = "dtor"
    version = "0.1.0"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "e58a0764cddb55ab28955347b45be00ade43d4d6f3ba4bf3dc354e4ec9432934"
    dependencies = [
    "dtor-proc-macro",
    ]
    [[package]]
    name = "dtor-proc-macro"
    version = "0.0.6"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "f678cf4a922c215c63e0de95eb1ff08a958a81d47e485cf9da1e27bf6305cfa5"
    [[package]]
    name = "duplicate"
    version = "2.0.1"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "8e92f10a49176cbffacaedabfaa11d51db1ea0f80a83c26e1873b43cd1742c24"
    dependencies = [
    "heck",
    "proc-macro2",
    "proc-macro2-diagnostics",
    ]
    [[package]]
    name = "dyn-clone"
    version = "1.0.20"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "d0881ea181b1df73ff77ffaaf9c7544ecc11e82fba9b5f27b262a3c73a332555"
    [[package]]
    name = "ed25519"
    version = "1.5.3"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "91cff35c70bba8a626e3185d8cd48cc11b5437e1a5bcd15b9b5fa3c64b6dfee7"
    dependencies = [
    "serde",
    "signature",
    ]
    [[package]]
    name = "ed25519-dalek"
    version = "1.0.1"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "c762bae6dcaf24c4c84667b8579785430908723d5c889f469d76a41d59cc7a9d"
    dependencies = [
    "curve25519-dalek",
    "ed25519",
    "rand 0.7.3",
    "serde",
    "serde_bytes",
    "sha2 0.9.9",
    "zeroize",
    ]
    [[package]]
    name = "either"
    version = "1.15.0"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719"
    [[package]]
    name = "encode_unicode"
    version = "1.0.0"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "34aa73646ffb006b8f5147f3dc182bd4bcb190227ce861fc4a4844bf8e3cb2c0"
    [[package]]
    name = "encoding_rs"
    version = "0.8.35"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "75030f3c4f45dafd7586dd6780965a8c7e8e285a5ecb86713e63a79c5b2766f3"
    dependencies = [
    "cfg-if",
    ]
    [[package]]
    name = "equivalent"
    version = "1.0.2"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f"
    [[package]]
    name = "errno"
    version = "0.3.14"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb"
    dependencies = [
    "libc",
    "windows-sys 0.61.2",
    ]
    [[package]]
    name = "fastrand"
    version = "2.3.0"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be"
    [[package]]
    name = "figment"
    version = "0.10.19"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "8cb01cd46b0cf372153850f4c6c272d9cbea2da513e07538405148f95bd789f3"
    dependencies = [
    "atomic",
    "serde",
    "toml",
    "uncased",
    "version_check",
    ]
    [[package]]
    name = "find-msvc-tools"
    version = "0.1.4"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "52051878f80a721bb68ebfbc930e07b65ba72f2da88968ea5c06fd6ca3d3a127"
    [[package]]
    name = "fixed_decimal"
    version = "0.7.0"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "35943d22b2f19c0cb198ecf915910a8158e94541c89dcc63300d7799d46c2c5e"
    dependencies = [
    "displaydoc",
    "ryu",
    "smallvec",
    "writeable",
    ]
    [[package]]
    name = "fluent-syntax"
    version = "0.12.0"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "54f0d287c53ffd184d04d8677f590f4ac5379785529e5e08b1c8083acdd5c198"
    dependencies = [
    "memchr",
    "thiserror 2.0.17",
    ]
    [[package]]
    name = "fnv"
    version = "1.0.7"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1"
    [[package]]
    name = "foldhash"
    version = "0.1.5"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "d9c4f5dac5e15c24eb999c26181a6ca40b39fe946cbe4c263c7209467bc83af2"
    [[package]]
    name = "foreign-types"
    version = "0.3.2"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1"
    dependencies = [
    "foreign-types-shared",
    ]
    [[package]]
    name = "foreign-types-shared"
    version = "0.1.1"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b"
    [[package]]
    name = "form_urlencoded"
    version = "1.2.2"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "cb4cb245038516f5f85277875cdaa4f7d2c9a0fa0468de06ed190163b1581fcf"
    dependencies = [
    "percent-encoding",
    ]
    [[package]]
    name = "fs2"
    version = "0.4.3"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "9564fc758e15025b46aa6643b1b77d047d1a56a1aea6e01002ac0c7026876213"
    dependencies = [
    "libc",
    "winapi",
    ]
    [[package]]
    name = "futures"
    version = "0.3.31"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "65bc07b1a8bc7c85c5f2e110c476c7389b4554ba72af57d8445ea63a576b0876"
    dependencies = [
    "futures-channel",
    "futures-core",
    "futures-executor",
    "futures-io",
    "futures-sink",
    "futures-task",
    "futures-util",
    ]
    [[package]]
    name = "futures-channel"
    version = "0.3.31"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "2dff15bf788c671c1934e366d07e30c1814a8ef514e1af724a602e8a2fbe1b10"
    dependencies = [
    "futures-core",
    "futures-sink",
    ]
    [[package]]
    name = "futures-core"
    version = "0.3.31"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "05f29059c0c2090612e8d742178b0580d2dc940c837851ad723096f87af6663e"
    [[package]]
    name = "futures-executor"
    version = "0.3.31"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "1e28d1d997f585e54aebc3f97d39e72338912123a67330d723fdbb564d646c9f"
    dependencies = [
    "futures-core",
    "futures-task",
    "futures-util",
    ]
    [[package]]
    name = "futures-io"
    version = "0.3.31"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "9e5c1b78ca4aae1ac06c48a526a655760685149f0d465d21f37abfe57ce075c6"
    [[package]]
    name = "futures-macro"
    version = "0.3.31"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650"
    dependencies = [
    "proc-macro2",
    "quote",
    "syn",
    ]
    [[package]]
    name = "futures-sink"
    version = "0.3.31"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "e575fab7d1e0dcb8d0c7bcf9a63ee213816ab51902e6d244a95819acacf1d4f7"
    [[package]]
    name = "futures-task"
    version = "0.3.31"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "f90f7dce0722e95104fcb095585910c0977252f286e354b5e3bd38902cd99988"
    [[package]]
    name = "futures-util"
    version = "0.3.31"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "9fa08315bb612088cc391249efdc3bc77536f16c91f6cf495e6fbe85b20a4a81"
    dependencies = [
    "futures-channel",
    "futures-core",
    "futures-io",
    "futures-macro",
    "futures-sink",
    "futures-task",
    "memchr",
    "pin-project-lite",
    "pin-utils",
    "slab",
    ]
    [[package]]
    name = "fuzzy-matcher"
    version = "0.3.7"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "54614a3312934d066701a80f20f15fa3b56d67ac7722b39eea5b4c9dd1d66c94"
    dependencies = [
    "thread_local",
    ]
    [[package]]
    name = "generic-array"
    version = "0.14.7"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a"
    dependencies = [
    "typenum",
    "version_check",
    ]
    [[package]]
    name = "getrandom"
    version = "0.1.16"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "8fc3cb4d91f53b50155bdcfd23f6a4c39ae1969c2ae85982b135750cccaf5fce"
    dependencies = [
    "cfg-if",
    "libc",
    "wasi 0.9.0+wasi-snapshot-preview1",
    ]
    [[package]]
    name = "getrandom"
    version = "0.2.16"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "335ff9f135e4384c8150d6f27c6daed433577f86b4750418338c01a1a2528592"
    dependencies = [
    "cfg-if",
    "js-sys",
    "libc",
    "wasi 0.11.1+wasi-snapshot-preview1",
    "wasm-bindgen",
    ]
    [[package]]
    name = "getrandom"
    version = "0.3.3"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "26145e563e54f2cadc477553f1ec5ee650b00862f0a58bcd12cbdc5f0ea2d2f4"
    dependencies = [
    "cfg-if",
    "libc",
    "r-efi",
    "wasi 0.14.7+wasi-0.2.4",
    ]
    [[package]]
    name = "gimli"
    version = "0.32.3"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "e629b9b98ef3dd8afe6ca2bd0f89306cec16d43d907889945bc5d6687f2f13c7"
    [[package]]
    name = "globset"
    version = "0.4.16"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "54a1028dfc5f5df5da8a56a73e6c153c9a9708ec57232470703592a3f18e49f5"
    dependencies = [
    "aho-corasick",
    "bstr",
    "log",
    "regex-automata",
    "regex-syntax",
    ]
    [[package]]
    name = "hashbrown"
    version = "0.12.3"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888"
    [[package]]
    name = "hashbrown"
    version = "0.15.5"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "9229cfe53dfd69f0609a49f65461bd93001ea1ef889cd5529dd176593f5338a1"
    dependencies = [
    "foldhash",
    ]
    [[package]]
    name = "hashbrown"
    version = "0.16.0"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "5419bdc4f6a9207fbeba6d11b604d481addf78ecd10c11ad51e76c2f6482748d"
    [[package]]
    name = "heck"
    version = "0.5.0"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea"
    [[package]]
    name = "hermit-abi"
    version = "0.5.2"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "fc0fef456e4baa96da950455cd02c081ca953b141298e41db3fc7e36b1da849c"
    [[package]]
    name = "hex"
    version = "0.4.3"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70"
    [[package]]
    name = "hmac"
    version = "0.11.0"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "2a2a2320eb7ec0ebe8da8f744d7812d9fc4cb4d09344ac01898dbcb6a20ae69b"
    dependencies = [
    "crypto-mac",
    "digest 0.9.0",
    ]
    [[package]]
    name = "iana-time-zone"
    version = "0.1.64"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "33e57f83510bb73707521ebaffa789ec8caf86f9657cad665b092b581d40e9fb"
    dependencies = [
    "android_system_properties",
    "core-foundation-sys",
    "iana-time-zone-haiku",
    "js-sys",
    "log",
    "wasm-bindgen",
    "windows-core",
    ]
    [[package]]
    name = "iana-time-zone-haiku"
    version = "0.1.2"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f"
    dependencies = [
    "cc",
    ]
    [[package]]
    name = "icu_casemap"
    version = "2.0.0"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "6dc5e74b3c9d7b63e0d7c5fd54ee8c135705df2ea2aa558082dd555dc9747a97"
    dependencies = [
    "displaydoc",
    "icu_casemap_data",
    "icu_collections",
    "icu_locale_core",
    "icu_properties",
    "icu_provider",
    "potential_utf",
    "writeable",
    "zerovec",
    ]
    [[package]]
    name = "icu_casemap_data"
    version = "2.0.0"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "f7584067558ab4c60c95d1ac2abd1588689cb4bcd4e099507f62dae86ae8d2c0"
    [[package]]
    name = "icu_collections"
    version = "2.0.0"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "200072f5d0e3614556f94a9930d5dc3e0662a652823904c3a75dc3b0af7fee47"
    dependencies = [
    "displaydoc",
    "potential_utf",
    "serde",
    "yoke",
    "zerofrom",
    "zerovec",
    ]
    [[package]]
    name = "icu_decimal"
    version = "2.0.0"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "fec61c43fdc4e368a9f450272833123a8ef0d7083a44597660ce94d791b8a2e2"
    dependencies = [
    "displaydoc",
    "fixed_decimal",
    "icu_decimal_data",
    "icu_locale",
    "icu_locale_core",
    "icu_provider",
    "tinystr",
    "writeable",
    "zerovec",
    ]
    [[package]]
    name = "icu_decimal_data"
    version = "2.0.0"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "b70963bc35f9bdf1bc66a5c1f458f4991c1dc71760e00fa06016b2c76b2738d5"
    [[package]]
    name = "icu_experimental"
    version = "0.3.0"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "ebe3d7e64892a434b08d5a58b53127e47a095ff780305f563c8c01798a1051b0"
    dependencies = [
    "displaydoc",
    "either",
    "fixed_decimal",
    "icu_casemap",
    "icu_collections",
    "icu_decimal",
    "icu_experimental_data",
    "icu_list",
    "icu_locale",
    "icu_locale_core",
    "icu_normalizer",
    "icu_pattern",
    "icu_plurals",
    "icu_properties",
    "icu_provider",
    "litemap",
    "num-bigint",
    "num-rational",
    "num-traits",
    "potential_utf",
    "smallvec",
    "tinystr",
    "writeable",
    "zerofrom",
    "zerotrie",
    "zerovec",
    ]
    [[package]]
    name = "icu_experimental_data"
    version = "0.3.0"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "b60d32ba5610adfc2083f5a759f55d9a9082ebf72750f126cb1630844eea1acf"
    [[package]]
    name = "icu_list"
    version = "2.0.0"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "e26f94ec776bb8b28cedc7dcf91033b822c5cb4c1783cf7a3f796fc168aa0c8b"
    dependencies = [
    "displaydoc",
    "icu_list_data",
    "icu_locale",
    "icu_provider",
    "regex-automata",
    "writeable",
    "zerovec",
    ]
    [[package]]
    name = "icu_list_data"
    version = "2.0.0"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "5a456a2412458ca45e181d9d51c5090ef8cd90f5692e11d34bafab3b3be1c76b"
    [[package]]
    name = "icu_locale"
    version = "2.0.0"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "6ae5921528335e91da1b6c695dbf1ec37df5ac13faa3f91e5640be93aa2fbefd"
    dependencies = [
    "displaydoc",
    "icu_collections",
    "icu_locale_core",
    "icu_locale_data",
    "icu_provider",
    "potential_utf",
    "serde",
    "tinystr",
    "zerovec",
    ]
    [[package]]
    name = "icu_locale_core"
    version = "2.0.0"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "0cde2700ccaed3872079a65fb1a78f6c0a36c91570f28755dda67bc8f7d9f00a"
    dependencies = [
    "displaydoc",
    "litemap",
    "serde",
    "tinystr",
    "writeable",
    "zerovec",
    ]
    [[package]]
    name = "icu_locale_data"
    version = "2.0.0"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "4fdef0c124749d06a743c69e938350816554eb63ac979166590e2b4ee4252765"
    [[package]]
    name = "icu_normalizer"
    version = "2.0.0"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "436880e8e18df4d7bbc06d58432329d6458cc84531f7ac5f024e93deadb37979"
    dependencies = [
    "displaydoc",
    "icu_collections",
    "icu_normalizer_data",
    "icu_properties",
    "icu_provider",
    "smallvec",
    "zerovec",
    ]
    [[package]]
    name = "icu_normalizer_data"
    version = "2.0.0"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "00210d6893afc98edb752b664b8890f0ef174c8adbb8d0be9710fa66fbbf72d3"
    [[package]]
    name = "icu_pattern"
    version = "0.4.0"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "983825f401e6bc4a13c45d552ffd9ad6f3f6b6bc0ec03f31d6835a90a46deb1f"
    dependencies = [
    "displaydoc",
    "either",
    "writeable",
    "yoke",
    "zerovec",
    ]
    [[package]]
    name = "icu_plurals"
    version = "2.0.0"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "0fd83a65f58b6f28e1f3da8c6ada6b415ee3ad5cb480b75bdb669f34d72dd179"
    dependencies = [
    "displaydoc",
    "fixed_decimal",
    "icu_locale",
    "icu_plurals_data",
    "icu_provider",
    "zerovec",
    ]
    [[package]]
    name = "icu_plurals_data"
    version = "2.0.0"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "9ec552d761eaf4a1c39ad28936e0af77a41bf01ff756ea54be4f8bfc21c265d7"
    [[package]]
    name = "icu_properties"
    version = "2.0.1"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "016c619c1eeb94efb86809b015c58f479963de65bdb6253345c1a1276f22e32b"
    dependencies = [
    "displaydoc",
    "icu_collections",
    "icu_locale_core",
    "icu_properties_data",
    "icu_provider",
    "potential_utf",
    "zerotrie",
    "zerovec",
    ]
    [[package]]
    name = "icu_properties_data"
    version = "2.0.1"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "298459143998310acd25ffe6810ed544932242d3f07083eee1084d83a71bd632"
    [[package]]
    name = "icu_provider"
    version = "2.0.0"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "03c80da27b5f4187909049ee2d72f276f0d9f99a42c306bd0131ecfe04d8e5af"
    dependencies = [
    "displaydoc",
    "icu_locale_core",
    "serde",
    "stable_deref_trait",
    "tinystr",
    "writeable",
    "yoke",
    "zerofrom",
    "zerotrie",
    "zerovec",
    ]
    [[package]]
    name = "ident_case"
    version = "1.0.1"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39"
    [[package]]
    name = "idna"
    version = "1.1.0"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "3b0875f23caa03898994f6ddc501886a45c7d3d62d04d2d90788d47be1b1e4de"
    dependencies = [
    "idna_adapter",
    "smallvec",
    "utf8_iter",
    ]
    [[package]]
    name = "idna_adapter"
    version = "1.2.1"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "3acae9609540aa318d1bc588455225fb2085b9ed0c4f6bd0d9d5bcd86f1a0344"
    dependencies = [
    "icu_normalizer",
    "icu_properties",
    ]
    [[package]]
    name = "ignore"
    version = "0.4.23"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "6d89fd380afde86567dfba715db065673989d6253f42b88179abd3eae47bda4b"
    dependencies = [
    "crossbeam-deque",
    "globset",
    "log",
    "memchr",
    "regex-automata",
    "same-file",
    "walkdir",
    "winapi-util",
    ]
    [[package]]
    name = "imara-diff"
    version = "0.1.8"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "17d34b7d42178945f775e84bc4c36dde7c1c6cdfea656d3354d009056f2bb3d2"
    dependencies = [
    "hashbrown 0.15.5",
    ]
    [[package]]
    name = "indexmap"
    version = "1.9.3"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99"
    dependencies = [
    "autocfg",
    "hashbrown 0.12.3",
    "serde",
    ]
    [[package]]
    name = "indexmap"
    version = "2.11.4"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "4b0f83760fb341a774ed326568e19f5a863af4a952def8c39f9ab92fd95b88e5"
    dependencies = [
    "equivalent",
    "hashbrown 0.16.0",
    "serde",
    "serde_core",
    ]
    [[package]]
    name = "indicatif"
    version = "0.17.11"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "183b3088984b400f4cfac3620d5e076c84da5364016b4f49473de574b2586235"
    dependencies = [
    "console",
    "number_prefix",
    "portable-atomic",
    "unicode-segmentation",
    "unicode-width 0.2.2",
    "web-time",
    ]
    [[package]]
    name = "inout"
    version = "0.1.4"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "879f10e63c20629ecabbb64a8010319738c66a5cd0c29b02d63d272b03751d01"
    dependencies = [
    "generic-array",
    ]
    [[package]]
    name = "instant"
    version = "0.1.13"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "e0242819d153cba4b4b05a5a8f2a7e9bbf97b6055b2a002b395c96b5ff3c0222"
    dependencies = [
    "cfg-if",
    ]
    [[package]]
    name = "is_ci"
    version = "1.2.0"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "7655c9839580ee829dfacba1d1278c2b7883e50a277ff7541299489d6bdfdc45"
    [[package]]
    name = "is_terminal_polyfill"
    version = "1.70.1"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf"
    [[package]]
    name = "itertools"
    version = "0.11.0"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "b1c173a5686ce8bfa551b3563d0c2170bf24ca44da99c7ca4bfdab5418c3fe57"
    dependencies = [
    "either",
    ]
    [[package]]
    name = "itoa"
    version = "1.0.15"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c"
    [[package]]
    name = "jiff"
    version = "0.2.15"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "be1f93b8b1eb69c77f24bbb0afdf66f54b632ee39af40ca21c4365a1d7347e49"
    dependencies = [
    "jiff-static",
    "jiff-tzdb-platform",
    "log",
    "portable-atomic",
    "portable-atomic-util",
    "serde",
    "windows-sys 0.59.0",
    ]
    [[package]]
    name = "jiff-static"
    version = "0.2.15"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "03343451ff899767262ec32146f6d559dd759fdadf42ff0e227c7c48f72594b4"
    dependencies = [
    "proc-macro2",
    "quote",
    "syn",
    ]
    [[package]]
    name = "jiff-tzdb"
    version = "0.1.4"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "c1283705eb0a21404d2bfd6eef2a7593d240bc42a0bdb39db0ad6fa2ec026524"
    [[package]]
    name = "jiff-tzdb-platform"
    version = "0.1.3"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "875a5a69ac2bab1a891711cf5eccbec1ce0341ea805560dcd90b7a2e925132e8"
    dependencies = [
    "jiff-tzdb",
    ]
    [[package]]
    name = "js-sys"
    version = "0.3.81"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "ec48937a97411dcb524a265206ccd4c90bb711fca92b2792c407f268825b9305"
    dependencies = [
    "once_cell",
    "wasm-bindgen",
    ]
    [[package]]
    name = "keyring"
    version = "3.6.2"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "1961983669d57bdfe6c0f3ef8e4c229b5ef751afcc7d87e4271d2f71f6ccfa8b"
    dependencies = [
    "byteorder",
    "dbus-secret-service",
    "linux-keyutils",
    "log",
    "security-framework 2.11.1",
    "security-framework 3.5.1",
    "windows-sys 0.59.0",
    ]
    [[package]]
    name = "l10n_embed"
    version = "0.2.0"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "27e524acc0bf1aa0fd5608dfb4c5af944ef81bc5fd6241f68a6df3db004a4b57"
    dependencies = [
    "anstyle",
    "camino",
    "fixed_decimal",
    "icu_decimal",
    "icu_experimental",
    "icu_list",
    "icu_locale",
    "icu_plurals",
    "jiff",
    "serde",
    "writeable",
    ]
    [[package]]
    name = "l10n_embed_derive"
    version = "0.2.0"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "80a1f091c73d5861392a5bb327086370bca82a36f58f54781a8530707dad07ca"
    dependencies = [
    "camino",
    "fixed_decimal",
    "fluent-syntax",
    "heck",
    "icu_locale",
    "l10n_embed",
    "miette",
    "proc-macro-error2",
    "proc-macro2",
    "quote",
    "syn",
    "thiserror 2.0.17",
    "wax",
    ]
    [[package]]
    name = "lazy_static"
    version = "1.5.0"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe"
    [[package]]
    name = "libc"
    version = "0.2.177"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "2874a2af47a2325c2001a6e6fad9b16a53b802102b528163885171cf92b15976"
    [[package]]
    name = "libdbus-sys"
    version = "0.2.6"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "5cbe856efeb50e4681f010e9aaa2bf0a644e10139e54cde10fc83a307c23bd9f"
    dependencies = [
    "pkg-config",
    ]
    [[package]]
    name = "libloading"
    version = "0.8.9"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "d7c4b02199fee7c5d21a5ae7d8cfa79a6ef5bb2fc834d6e9058e89c825efdc55"
    dependencies = [
    "cfg-if",
    "windows-link",
    ]
    [[package]]
    name = "libpijul"
    version = "1.0.0-beta.10"
    dependencies = [
    "adler32",
    "aes",
    "bincode",
    "bitflags 2.9.4",
    "blake3",
    "bs58",
    "byteorder",
    "canonical-path",
    "chardetng",
    "crossbeam-deque",
    "curve25519-dalek",
    "data-encoding",
    "diffs",
    "ed25519-dalek",
    "encoding_rs",
    "generic-array",
    "getrandom 0.2.16",
    "hmac",
    "ignore",
    "imara-diff",
    "jiff",
    "log",
    "lru-cache",
    "nom",
    "parking_lot 0.12.5",
    "path-slash",
    "pbkdf2 0.9.0",
    "pijul-macros",
    "rand 0.8.5",
    "regex",
    "sanakirja",
    "serde",
    "serde_derive",
    "serde_json",
    "sha2 0.9.9",
    "tempfile",
    "thiserror 2.0.17",
    "toml",
    "twox-hash",
    "zstd-seekable",
    ]
    [[package]]
    name = "libredox"
    version = "0.1.10"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "416f7e718bdb06000964960ffa43b4335ad4012ae8b99060261aa4a8088d5ccb"
    dependencies = [
    "bitflags 2.9.4",
    "libc",
    "redox_syscall 0.5.18",
    ]
    [[package]]
    name = "libsodium-sys"
    version = "0.2.7"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "6b779387cd56adfbc02ea4a668e704f729be8d6a6abd2c27ca5ee537849a92fd"
    dependencies = [
    "cc",
    "libc",
    "pkg-config",
    "walkdir",
    ]
    [[package]]
    name = "linked-hash-map"
    version = "0.5.6"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "0717cef1bc8b636c6e1c1bbdefc09e6322da8a9321966e8928ef80d20f7f770f"
    [[package]]
    name = "linux-keyutils"
    version = "0.2.4"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "761e49ec5fd8a5a463f9b84e877c373d888935b71c6be78f3767fe2ae6bed18e"
    dependencies = [
    "bitflags 2.9.4",
    "libc",
    ]
    [[package]]
    name = "linux-raw-sys"
    version = "0.11.0"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "df1d3c3b53da64cf5760482273a98e575c651a67eec7f77df96b5b642de8f039"
    [[package]]
    name = "litemap"
    version = "0.8.0"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "241eaef5fd12c88705a01fc1066c48c4b36e0dd4377dcdc7ec3942cea7a69956"
    [[package]]
    name = "lock_api"
    version = "0.4.14"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "224399e74b87b5f3557511d98dff8b14089b3dadafcab6bb93eab67d3aace965"
    dependencies = [
    "scopeguard",
    ]
    [[package]]
    name = "log"
    version = "0.4.28"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "34080505efa8e45a4b816c349525ebe327ceaa8559756f0356cba97ef3bf7432"
    [[package]]
    name = "lru-cache"
    version = "0.1.2"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "31e24f1ad8321ca0e8a1e0ac13f23cb668e6f5466c2c57319f6a5cf1cc8e3b1c"
    dependencies = [
    "linked-hash-map",
    ]
    [[package]]
    name = "md5"
    version = "0.7.0"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "490cc448043f947bae3cbee9c203358d62dbee0db12107a74be5c30ccfd09771"
    [[package]]
    name = "memchr"
    version = "2.7.6"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "f52b00d39961fc5b2736ea853c9cc86238e165017a493d1d5c8eac6bdc4cc273"
    [[package]]
    name = "memmap2"
    version = "0.9.8"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "843a98750cd611cc2965a8213b53b43e715f13c37a9e096c6408e69990961db7"
    dependencies = [
    "libc",
    ]
    [[package]]
    name = "miette"
    version = "7.6.0"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "5f98efec8807c63c752b5bd61f862c165c115b0a35685bdcfd9238c7aeb592b7"
    dependencies = [
    "backtrace",
    "backtrace-ext",
    "cfg-if",
    "miette-derive",
    "owo-colors",
    "supports-color",
    "supports-hyperlinks",
    "supports-unicode",
    "terminal_size",
    "textwrap",
    "unicode-width 0.1.14",
    ]
    [[package]]
    name = "miette-derive"
    version = "7.6.0"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "db5b29714e950dbb20d5e6f74f9dcec4edbcc1067bb7f8ed198c097b8c1a818b"
    dependencies = [
    "proc-macro2",
    "quote",
    "syn",
    ]
    [[package]]
    name = "minimal-lexical"
    version = "0.2.1"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a"
    [[package]]
    name = "miniz_oxide"
    version = "0.8.9"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "1fa76a2c86f704bdb222d66965fb3d63269ce38518b83cb0575fca855ebb6316"
    dependencies = [
    "adler2",
    ]
    [[package]]
    name = "mio"
    version = "1.1.0"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "69d83b0086dc8ecf3ce9ae2874b2d1290252e2a30720bea58a5c6639b0092873"
    dependencies = [
    "libc",
    "wasi 0.11.1+wasi-snapshot-preview1",
    "windows-sys 0.61.2",
    ]
    [[package]]
    name = "napi"
    version = "3.3.0"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "f1b74e3dce5230795bb4d2821b941706dee733c7308752507254b0497f39cad7"
    dependencies = [
    "bitflags 2.9.4",
    "ctor",
    "napi-build",
    "napi-sys",
    "nohash-hasher",
    "rustc-hash",
    ]
    [[package]]
    name = "napi-build"
    version = "2.2.3"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "dcae8ad5609d14afb3a3b91dee88c757016261b151e9dcecabf1b2a31a6cab14"
    [[package]]
    name = "napi-derive"
    version = "3.2.5"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "7552d5a579b834614bbd496db5109f1b9f1c758f08224b0dee1e408333adf0d0"
    dependencies = [
    "convert_case",
    "ctor",
    "napi-derive-backend",
    "proc-macro2",
    "quote",
    "syn",
    ]
    [[package]]
    name = "napi-derive-backend"
    version = "2.2.0"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "5f6a81ac7486b70f2532a289603340862c06eea5a1e650c1ffeda2ce1238516a"
    dependencies = [
    "convert_case",
    "proc-macro2",
    "quote",
    "semver",
    "syn",
    ]
    [[package]]
    name = "napi-sys"
    version = "3.0.0"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "3e4e7135a8f97aa0f1509cce21a8a1f9dcec1b50d8dee006b48a5adb69a9d64d"
    dependencies = [
    "libloading",
    ]
    [[package]]
    name = "nohash-hasher"
    version = "0.2.0"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "2bf50223579dc7cdcfb3bfcacf7069ff68243f8c363f62ffa99cf000a6b9c451"
    [[package]]
    name = "nom"
    version = "7.1.3"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a"
    dependencies = [
    "memchr",
    "minimal-lexical",
    ]
    [[package]]
    name = "nu-ansi-term"
    version = "0.50.3"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "7957b9740744892f114936ab4a57b3f487491bbeafaf8083688b16841a4240e5"
    dependencies = [
    "windows-sys 0.61.2",
    ]
    [[package]]
    name = "num"
    version = "0.4.3"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "35bd024e8b2ff75562e5f34e7f4905839deb4b22955ef5e73d2fea1b9813cb23"
    dependencies = [
    "num-bigint",
    "num-complex",
    "num-integer",
    "num-iter",
    "num-rational",
    "num-traits",
    ]
    [[package]]
    name = "num-bigint"
    version = "0.4.6"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "a5e44f723f1133c9deac646763579fdb3ac745e418f2a7af9cd0c431da1f20b9"
    dependencies = [
    "num-integer",
    "num-traits",
    ]
    [[package]]
    name = "num-complex"
    version = "0.4.6"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "73f88a1307638156682bada9d7604135552957b7818057dcef22705b4d509495"
    dependencies = [
    "num-traits",
    ]
    [[package]]
    name = "num-conv"
    version = "0.1.0"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9"
    [[package]]
    name = "num-integer"
    version = "0.1.46"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858f"
    dependencies = [
    "num-traits",
    ]
    [[package]]
    name = "num-iter"
    version = "0.1.45"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "1429034a0490724d0075ebb2bc9e875d6503c3cf69e235a8941aa757d83ef5bf"
    dependencies = [
    "autocfg",
    "num-integer",
    "num-traits",
    ]
    [[package]]
    name = "num-rational"
    version = "0.4.2"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "f83d14da390562dca69fc84082e73e548e1ad308d24accdedd2720017cb37824"
    dependencies = [
    "num-bigint",
    "num-integer",
    "num-traits",
    ]
    [[package]]
    name = "num-traits"
    version = "0.2.19"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841"
    dependencies = [
    "autocfg",
    ]
    [[package]]
    name = "num_cpus"
    version = "1.17.0"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "91df4bbde75afed763b708b7eee1e8e7651e02d97f6d5dd763e89367e957b23b"
    dependencies = [
    "hermit-abi",
    "libc",
    ]
    [[package]]
    name = "number_prefix"
    version = "0.4.0"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "830b246a0e5f20af87141b25c173cd1b609bd7779a4617d6ec582abaf90870f3"
    [[package]]
    name = "object"
    version = "0.37.3"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "ff76201f031d8863c38aa7f905eca4f53abbfa15f609db4277d44cd8938f33fe"
    dependencies = [
    "memchr",
    ]
    [[package]]
    name = "once_cell"
    version = "1.21.3"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d"
    [[package]]
    name = "once_cell_polyfill"
    version = "1.70.1"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "a4895175b425cb1f87721b59f0f286c2092bd4af812243672510e1ac53e2e0ad"
    [[package]]
    name = "opaque-debug"
    version = "0.3.1"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "c08d65885ee38876c4f86fa503fb49d7b507c2b62552df7c70b2fce627e06381"
    [[package]]
    name = "openssl"
    version = "0.10.75"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "08838db121398ad17ab8531ce9de97b244589089e290a384c900cb9ff7434328"
    dependencies = [
    "bitflags 2.9.4",
    "cfg-if",
    "foreign-types",
    "libc",
    "once_cell",
    "openssl-macros",
    "openssl-sys",
    ]
    [[package]]
    name = "openssl-macros"
    version = "0.1.1"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c"
    dependencies = [
    "proc-macro2",
    "quote",
    "syn",
    ]
    [[package]]
    name = "openssl-sys"
    version = "0.9.111"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "82cab2d520aa75e3c58898289429321eb788c3106963d0dc886ec7a5f4adc321"
    dependencies = [
    "cc",
    "libc",
    "pkg-config",
    "vcpkg",
    ]
    [[package]]
    name = "owo-colors"
    version = "4.2.3"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "9c6901729fa79e91a0913333229e9ca5dc725089d1c363b2f4b4760709dc4a52"
    [[package]]
    name = "parking_lot"
    version = "0.11.2"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "7d17b78036a60663b797adeaee46f5c9dfebb86948d1255007a1d6be0271ff99"
    dependencies = [
    "instant",
    "lock_api",
    "parking_lot_core 0.8.6",
    ]
    [[package]]
    name = "parking_lot"
    version = "0.12.5"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "93857453250e3077bd71ff98b6a65ea6621a19bb0f559a85248955ac12c45a1a"
    dependencies = [
    "lock_api",
    "parking_lot_core 0.9.12",
    ]
    [[package]]
    name = "parking_lot_core"
    version = "0.8.6"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "60a2cfe6f0ad2bfc16aefa463b497d5c7a5ecd44a23efa72aa342d90177356dc"
    dependencies = [
    "cfg-if",
    "instant",
    "libc",
    "redox_syscall 0.2.16",
    "smallvec",
    "winapi",
    ]
    [[package]]
    name = "parking_lot_core"
    version = "0.9.12"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "2621685985a2ebf1c516881c026032ac7deafcda1a2c9b7850dc81e3dfcb64c1"
    dependencies = [
    "cfg-if",
    "libc",
    "redox_syscall 0.5.18",
    "smallvec",
    "windows-link",
    ]
    [[package]]
    name = "password-hash"
    version = "0.2.3"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "77e0b28ace46c5a396546bcf443bf422b57049617433d8854227352a4a9b24e7"
    dependencies = [
    "base64ct",
    "rand_core 0.6.4",
    "subtle",
    ]
    [[package]]
    name = "path-slash"
    version = "0.2.1"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "1e91099d4268b0e11973f036e885d652fb0b21fedcf69738c627f94db6a44f42"
    [[package]]
    name = "pbkdf2"
    version = "0.8.0"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "d95f5254224e617595d2cc3cc73ff0a5eaf2637519e25f03388154e9378b6ffa"
    dependencies = [
    "base64ct",
    "crypto-mac",
    "hmac",
    "password-hash",
    "sha2 0.9.9",
    ]
    [[package]]
    name = "pbkdf2"
    version = "0.9.0"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "f05894bce6a1ba4be299d0c5f29563e08af2bc18bb7d48313113bed71e904739"
    dependencies = [
    "crypto-mac",
    ]
    [[package]]
    name = "pbkdf2"
    version = "0.12.2"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "f8ed6a7761f76e3b9f92dfb0a60a6a6477c61024b775147ff0973a02653abaf2"
    dependencies = [
    "digest 0.10.7",
    ]
    [[package]]
    name = "percent-encoding"
    version = "2.3.2"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "9b4f627cb1b25917193a259e49bdad08f671f8d9708acfd5fe0a8c1455d87220"
    [[package]]
    name = "pijul-config"
    version = "1.0.0-beta.10"
    dependencies = [
    "anyhow",
    "dialoguer",
    "dirs-next",
    "figment",
    "icu_locale",
    "libpijul",
    "log",
    "serde",
    "serde_derive",
    "serde_with",
    "toml",
    "whoami",
    ]
    [[package]]
    name = "pijul-extension"
    version = "0.1.0"
    dependencies = [
    "camino",
    "canonical-path",
    "libpijul",
    "path-slash",
    "pijul-identity",
    "ropey",
    "serde_json",
    "thiserror 2.0.17",
    "tracing",
    ]
    [[package]]
    name = "pijul-identity"
    version = "1.0.0-beta.10"
    dependencies = [
    "anyhow",
    "dirs-next",
    "jiff",
    "keyring",
    "libpijul",
    "log",
    "pijul-config",
    "pijul-interaction",
    "serde",
    "serde_derive",
    "serde_json",
    "thiserror 2.0.17",
    "thrussh-keys",
    "toml",
    "validator",
    "whoami",
    ]
    [[package]]
    name = "pijul-interaction"
    version = "1.0.0-beta.10"
    dependencies = [
    "dialoguer",
    "duplicate",
    "indicatif",
    "log",
    "pijul-config",
    "thiserror 2.0.17",
    ]
    [[package]]
    name = "pijul-macros"
    version = "1.0.0-beta.10"
    dependencies = [
    "proc-macro2",
    "quote",
    "syn",
    ]
    [[package]]
    name = "pijul-vscode"
    version = "0.1.0"
    dependencies = [
    "camino",
    "icu_locale",
    "jiff",
    "l10n_embed",
    "l10n_embed_derive",
    "napi",
    "napi-build",
    "napi-derive",
    "napi-sys",
    "pijul-extension",
    "ropey",
    "tracing",
    "tracing-subscriber",
    ]
    [[package]]
    name = "pin-project-lite"
    version = "0.2.16"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "3b3cff922bd51709b605d9ead9aa71031d81447142d828eb4a6eba76fe619f9b"
    [[package]]
    name = "pin-utils"
    version = "0.1.0"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184"
    [[package]]
    name = "pkg-config"
    version = "0.3.32"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "7edddbd0b52d732b21ad9a5fab5c704c14cd949e5e9a1ec5929a24fded1b904c"
    [[package]]
    name = "pori"
    version = "0.0.0"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "a4a63d338dec139f56dacc692ca63ad35a6be6a797442479b55acd611d79e906"
    dependencies = [
    "nom",
    ]
    [[package]]
    name = "portable-atomic"
    version = "1.11.1"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "f84267b20a16ea918e43c6a88433c2d54fa145c92a811b5b047ccbe153674483"
    [[package]]
    name = "portable-atomic-util"
    version = "0.2.4"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "d8a2f0d8d040d7848a709caf78912debcc3f33ee4b3cac47d73d1e1069e83507"
    dependencies = [
    "portable-atomic",
    ]
    [[package]]
    name = "potential_utf"
    version = "0.1.3"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "84df19adbe5b5a0782edcab45899906947ab039ccf4573713735ee7de1e6b08a"
    dependencies = [
    "serde",
    "zerovec",
    ]
    [[package]]
    name = "powerfmt"
    version = "0.2.0"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391"
    [[package]]
    name = "ppv-lite86"
    version = "0.2.21"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "85eae3c4ed2f50dcfe72643da4befc30deadb458a9b590d720cde2f2b1e97da9"
    dependencies = [
    "zerocopy",
    ]
    [[package]]
    name = "proc-macro-error-attr2"
    version = "2.0.0"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "96de42df36bb9bba5542fe9f1a054b8cc87e172759a1868aa05c1f3acc89dfc5"
    dependencies = [
    "proc-macro2",
    "quote",
    ]
    [[package]]
    name = "proc-macro-error2"
    version = "2.0.1"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "11ec05c52be0a07b08061f7dd003e7d7092e0472bc731b4af7bb1ef876109802"
    dependencies = [
    "proc-macro-error-attr2",
    "proc-macro2",
    "quote",
    "syn",
    ]
    [[package]]
    name = "proc-macro2"
    version = "1.0.101"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "89ae43fd86e4158d6db51ad8e2b80f313af9cc74f5c0e03ccb87de09998732de"
    dependencies = [
    "unicode-ident",
    ]
    [[package]]
    name = "proc-macro2-diagnostics"
    version = "0.10.1"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "af066a9c399a26e020ada66a034357a868728e72cd426f3adcd35f80d88d88c8"
    dependencies = [
    "proc-macro2",
    "quote",
    "syn",
    "version_check",
    ]
    [[package]]
    name = "quote"
    version = "1.0.41"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "ce25767e7b499d1b604768e7cde645d14cc8584231ea6b295e9c9eb22c02e1d1"
    dependencies = [
    "proc-macro2",
    ]
    [[package]]
    name = "r-efi"
    version = "5.3.0"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f"
    [[package]]
    name = "rand"
    version = "0.7.3"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "6a6b1679d49b24bbfe0c803429aa1874472f50d9b363131f0e89fc356b544d03"
    dependencies = [
    "getrandom 0.1.16",
    "libc",
    "rand_chacha 0.2.2",
    "rand_core 0.5.1",
    "rand_hc",
    ]
    [[package]]
    name = "rand"
    version = "0.8.5"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404"
    dependencies = [
    "libc",
    "rand_chacha 0.3.1",
    "rand_core 0.6.4",
    ]
    [[package]]
    name = "rand_chacha"
    version = "0.2.2"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "f4c8ed856279c9737206bf725bf36935d8666ead7aa69b52be55af369d193402"
    dependencies = [
    "ppv-lite86",
    "rand_core 0.5.1",
    ]
    [[package]]
    name = "rand_chacha"
    version = "0.3.1"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88"
    dependencies = [
    "ppv-lite86",
    "rand_core 0.6.4",
    ]
    [[package]]
    name = "rand_core"
    version = "0.5.1"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19"
    dependencies = [
    "getrandom 0.1.16",
    ]
    [[package]]
    name = "rand_core"
    version = "0.6.4"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c"
    dependencies = [
    "getrandom 0.2.16",
    ]
    [[package]]
    name = "rand_hc"
    version = "0.2.0"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "ca3129af7b92a17112d59ad498c6f81eaf463253766b90396d39ea7a39d6613c"
    dependencies = [
    "rand_core 0.5.1",
    ]
    [[package]]
    name = "redox_syscall"
    version = "0.2.16"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "fb5a58c1855b4b6819d59012155603f0b22ad30cad752600aadfcb695265519a"
    dependencies = [
    "bitflags 1.3.2",
    ]
    [[package]]
    name = "redox_syscall"
    version = "0.5.18"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "ed2bf2547551a7053d6fdfafda3f938979645c44812fbfcda098faae3f1a362d"
    dependencies = [
    "bitflags 2.9.4",
    ]
    [[package]]
    name = "redox_users"
    version = "0.4.6"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "ba009ff324d1fc1b900bd1fdb31564febe58a8ccc8a6fdbb93b543d33b13ca43"
    dependencies = [
    "getrandom 0.2.16",
    "libredox",
    "thiserror 1.0.69",
    ]
    [[package]]
    name = "ref-cast"
    version = "1.0.25"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "f354300ae66f76f1c85c5f84693f0ce81d747e2c3f21a45fef496d89c960bf7d"
    dependencies = [
    "ref-cast-impl",
    ]
    [[package]]
    name = "ref-cast-impl"
    version = "1.0.25"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "b7186006dcb21920990093f30e3dea63b7d6e977bf1256be20c3563a5db070da"
    dependencies = [
    "proc-macro2",
    "quote",
    "syn",
    ]
    [[package]]
    name = "regex"
    version = "1.12.1"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "4a52d8d02cacdb176ef4678de6c052efb4b3da14b78e4db683a4252762be5433"
    dependencies = [
    "aho-corasick",
    "memchr",
    "regex-automata",
    "regex-syntax",
    ]
    [[package]]
    name = "regex-automata"
    version = "0.4.12"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "722166aa0d7438abbaa4d5cc2c649dac844e8c56d82fb3d33e9c34b5cd268fc6"
    dependencies = [
    "aho-corasick",
    "memchr",
    "regex-syntax",
    ]
    [[package]]
    name = "regex-syntax"
    version = "0.8.7"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "c3160422bbd54dd5ecfdca71e5fd59b7b8fe2b1697ab2baf64f6d05dcc66d298"
    [[package]]
    name = "ropey"
    version = "2.0.0-beta.1"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "4045a00dc327d084a2bbf126976e14125b54f23bd30511d45b842eba76c52d74"
    dependencies = [
    "str_indices",
    ]
    [[package]]
    name = "rustc-demangle"
    version = "0.1.26"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "56f7d92ca342cea22a06f2121d944b4fd82af56988c270852495420f961d4ace"
    [[package]]
    name = "rustc-hash"
    version = "2.1.1"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "357703d41365b4b27c590e3ed91eabb1b663f07c4c084095e60cbed4362dff0d"
    [[package]]
    name = "rustix"
    version = "1.1.2"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "cd15f8a2c5551a84d56efdc1cd049089e409ac19a3072d5037a17fd70719ff3e"
    dependencies = [
    "bitflags 2.9.4",
    "errno",
    "libc",
    "linux-raw-sys",
    "windows-sys 0.61.2",
    ]
    [[package]]
    name = "rustversion"
    version = "1.0.22"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d"
    [[package]]
    name = "ryu"
    version = "1.0.20"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "28d3b2b1366ec20994f1fd18c3c594f05c5dd4bc44d8bb0c1c632c8d6829481f"
    [[package]]
    name = "same-file"
    version = "1.0.6"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502"
    dependencies = [
    "winapi-util",
    ]
    [[package]]
    name = "sanakirja"
    version = "1.4.3"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "81aaf70d064e2122209f04d01fd91e8908e7a327b516236e1cbc0c3f34ac6d11"
    dependencies = [
    "crc32fast",
    "fs2",
    "lazy_static",
    "log",
    "memmap2",
    "parking_lot 0.11.2",
    "sanakirja-core",
    "serde",
    "thiserror 1.0.69",
    ]
    [[package]]
    name = "sanakirja-core"
    version = "1.4.1"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "8376db34ae3eac6e7bd91168bc638450073b708ce9fb46940de676f552238bf5"
    dependencies = [
    "crc32fast",
    ]
    [[package]]
    name = "schemars"
    version = "0.9.0"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "4cd191f9397d57d581cddd31014772520aa448f65ef991055d7f61582c65165f"
    dependencies = [
    "dyn-clone",
    "ref-cast",
    "serde",
    "serde_json",
    ]
    [[package]]
    name = "schemars"
    version = "1.1.0"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "9558e172d4e8533736ba97870c4b2cd63f84b382a3d6eb063da41b91cce17289"
    dependencies = [
    "dyn-clone",
    "ref-cast",
    "serde",
    "serde_json",
    ]
    [[package]]
    name = "scopeguard"
    version = "1.2.0"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49"
    [[package]]
    name = "security-framework"
    version = "2.11.1"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "897b2245f0b511c87893af39b033e5ca9cce68824c4d7e7630b5a1d339658d02"
    dependencies = [
    "bitflags 2.9.4",
    "core-foundation 0.9.4",
    "core-foundation-sys",
    "libc",
    "security-framework-sys",
    ]
    [[package]]
    name = "security-framework"
    version = "3.5.1"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "b3297343eaf830f66ede390ea39da1d462b6b0c1b000f420d0a83f898bbbe6ef"
    dependencies = [
    "bitflags 2.9.4",
    "core-foundation 0.10.1",
    "core-foundation-sys",
    "libc",
    "security-framework-sys",
    ]
    [[package]]
    name = "security-framework-sys"
    version = "2.15.0"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "cc1f0cbffaac4852523ce30d8bd3c5cdc873501d96ff467ca09b6767bb8cd5c0"
    dependencies = [
    "core-foundation-sys",
    "libc",
    ]
    [[package]]
    name = "semver"
    version = "1.0.27"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "d767eb0aabc880b29956c35734170f26ed551a859dbd361d140cdbeca61ab1e2"
    dependencies = [
    "serde",
    "serde_core",
    ]
    [[package]]
    name = "serde"
    version = "1.0.228"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e"
    dependencies = [
    "serde_core",
    "serde_derive",
    ]
    [[package]]
    name = "serde_bytes"
    version = "0.11.19"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "a5d440709e79d88e51ac01c4b72fc6cb7314017bb7da9eeff678aa94c10e3ea8"
    dependencies = [
    "serde",
    "serde_core",
    ]
    [[package]]
    name = "serde_core"
    version = "1.0.228"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad"
    dependencies = [
    "serde_derive",
    ]
    [[package]]
    name = "serde_derive"
    version = "1.0.228"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79"
    dependencies = [
    "proc-macro2",
    "quote",
    "syn",
    ]
    [[package]]
    name = "serde_json"
    version = "1.0.145"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "402a6f66d8c709116cf22f558eab210f5a50187f702eb4d7e5ef38d9a7f1c79c"
    dependencies = [
    "itoa",
    "memchr",
    "ryu",
    "serde",
    "serde_core",
    ]
    [[package]]
    name = "serde_spanned"
    version = "0.6.9"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "bf41e0cfaf7226dca15e8197172c295a782857fcb97fad1808a166870dee75a3"
    dependencies = [
    "serde",
    ]
    [[package]]
    name = "serde_with"
    version = "3.16.0"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "10574371d41b0d9b2cff89418eda27da52bcaff2cc8741db26382a77c29131f1"
    dependencies = [
    "base64",
    "chrono",
    "hex",
    "indexmap 1.9.3",
    "indexmap 2.11.4",
    "schemars 0.9.0",
    "schemars 1.1.0",
    "serde_core",
    "serde_json",
    "serde_with_macros",
    "time",
    ]
    [[package]]
    name = "serde_with_macros"
    version = "3.16.0"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "08a72d8216842fdd57820dc78d840bef99248e35fb2554ff923319e60f2d686b"
    dependencies = [
    "darling",
    "proc-macro2",
    "quote",
    "syn",
    ]
    [[package]]
    name = "sha2"
    version = "0.9.9"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "4d58a1e1bf39749807d89cf2d98ac2dfa0ff1cb3faa38fbb64dd88ac8013d800"
    dependencies = [
    "block-buffer 0.9.0",
    "cfg-if",
    "cpufeatures",
    "digest 0.9.0",
    "opaque-debug",
    ]
    [[package]]
    name = "sha2"
    version = "0.10.9"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "a7507d819769d01a365ab707794a4084392c824f54a7a6a7862f8c3d0892b283"
    dependencies = [
    "cfg-if",
    "cpufeatures",
    "digest 0.10.7",
    ]
    [[package]]
    name = "sharded-slab"
    version = "0.1.7"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "f40ca3c46823713e0d4209592e8d6e826aa57e928f09752619fc696c499637f6"
    dependencies = [
    "lazy_static",
    ]
    [[package]]
    name = "shell-words"
    version = "1.1.0"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "24188a676b6ae68c3b2cb3a01be17fbf7240ce009799bb56d5b1409051e78fde"
    [[package]]
    name = "shlex"
    version = "1.3.0"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64"
    [[package]]
    name = "signature"
    version = "1.6.4"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "74233d3b3b2f6d4b006dc19dee745e73e2a6bfb6f93607cd3b02bd5b00797d7c"
    [[package]]
    name = "slab"
    version = "0.4.11"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "7a2ae44ef20feb57a68b23d846850f861394c2e02dc425a50098ae8c90267589"
    [[package]]
    name = "smallvec"
    version = "1.15.1"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03"
    [[package]]
    name = "socket2"
    version = "0.6.1"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "17129e116933cf371d018bb80ae557e889637989d8638274fb25622827b03881"
    dependencies = [
    "libc",
    "windows-sys 0.60.2",
    ]
    [[package]]
    name = "stable_deref_trait"
    version = "1.2.1"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "6ce2be8dc25455e1f91df71bfa12ad37d7af1092ae736f3a6cd0e37bc7810596"
    [[package]]
    name = "static_assertions"
    version = "1.1.0"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f"
    [[package]]
    name = "str_indices"
    version = "0.4.4"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "d08889ec5408683408db66ad89e0e1f93dff55c73a4ccc71c427d5b277ee47e6"
    [[package]]
    name = "strsim"
    version = "0.11.1"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f"
    [[package]]
    name = "subtle"
    version = "2.4.1"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "6bdef32e8150c2a081110b42772ffe7d7c9032b606bc226c8260fd97e0976601"
    [[package]]
    name = "supports-color"
    version = "3.0.2"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "c64fc7232dd8d2e4ac5ce4ef302b1d81e0b80d055b9d77c7c4f51f6aa4c867d6"
    dependencies = [
    "is_ci",
    ]
    [[package]]
    name = "supports-hyperlinks"
    version = "3.1.0"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "804f44ed3c63152de6a9f90acbea1a110441de43006ea51bcce8f436196a288b"
    [[package]]
    name = "supports-unicode"
    version = "3.0.0"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "b7401a30af6cb5818bb64852270bb722533397edcfc7344954a38f420819ece2"
    [[package]]
    name = "syn"
    version = "2.0.106"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "ede7c438028d4436d71104916910f5bb611972c5cfd7f89b8300a8186e6fada6"
    dependencies = [
    "proc-macro2",
    "quote",
    "unicode-ident",
    ]
    [[package]]
    name = "synstructure"
    version = "0.13.2"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "728a70f3dbaf5bab7f0c4b1ac8d7ae5ea60a4b5549c8a5914361c99147a709d2"
    dependencies = [
    "proc-macro2",
    "quote",
    "syn",
    ]
    [[package]]
    name = "tempfile"
    version = "3.23.0"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "2d31c77bdf42a745371d260a26ca7163f1e0924b64afa0b688e61b5a9fa02f16"
    dependencies = [
    "fastrand",
    "getrandom 0.3.3",
    "once_cell",
    "rustix",
    "windows-sys 0.61.2",
    ]
    [[package]]
    name = "terminal_size"
    version = "0.4.3"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "60b8cb979cb11c32ce1603f8137b22262a9d131aaa5c37b5678025f22b8becd0"
    dependencies = [
    "rustix",
    "windows-sys 0.60.2",
    ]
    [[package]]
    name = "textwrap"
    version = "0.16.2"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "c13547615a44dc9c452a8a534638acdf07120d4b6847c8178705da06306a3057"
    dependencies = [
    "unicode-linebreak",
    "unicode-width 0.2.2",
    ]
    [[package]]
    name = "thiserror"
    version = "1.0.69"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52"
    dependencies = [
    "thiserror-impl 1.0.69",
    ]
    [[package]]
    name = "thiserror"
    version = "2.0.17"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "f63587ca0f12b72a0600bcba1d40081f830876000bb46dd2337a3051618f4fc8"
    dependencies = [
    "thiserror-impl 2.0.17",
    ]
    [[package]]
    name = "thiserror-impl"
    version = "1.0.69"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1"
    dependencies = [
    "proc-macro2",
    "quote",
    "syn",
    ]
    [[package]]
    name = "thiserror-impl"
    version = "2.0.17"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "3ff15c8ecd7de3849db632e14d18d2571fa09dfc5ed93479bc4485c7a517c913"
    dependencies = [
    "proc-macro2",
    "quote",
    "syn",
    ]
    [[package]]
    name = "thread_local"
    version = "1.1.9"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "f60246a4944f24f6e018aa17cdeffb7818b76356965d03b07d6a9886e8962185"
    dependencies = [
    "cfg-if",
    ]
    [[package]]
    name = "threadpool"
    version = "1.8.1"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "d050e60b33d41c19108b32cea32164033a9013fe3b46cbd4457559bfbf77afaa"
    dependencies = [
    "num_cpus",
    ]
    [[package]]
    name = "thrussh-keys"
    version = "0.22.1"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "c43d59b13e4c08db0e379bced99bda596ac5ed33651d919bf3916d34ad4259bb"
    dependencies = [
    "aes",
    "bcrypt-pbkdf",
    "bit-vec",
    "block-modes",
    "byteorder",
    "cryptovec",
    "data-encoding",
    "dirs",
    "futures",
    "hmac",
    "log",
    "md5",
    "num-bigint",
    "num-integer",
    "openssl",
    "pbkdf2 0.8.0",
    "rand 0.8.5",
    "serde",
    "serde_derive",
    "sha2 0.9.9",
    "thiserror 1.0.69",
    "thrussh-libsodium",
    "tokio",
    "tokio-stream",
    "yasna",
    ]
    [[package]]
    name = "thrussh-libsodium"
    version = "0.2.3"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "5f4f9c0eb4cff7225e782f7c4930c7b1f9caedf45c182e2d8602c0ec34679a1e"
    dependencies = [
    "lazy_static",
    "libc",
    "libsodium-sys",
    "pkg-config",
    "vcpkg",
    ]
    [[package]]
    name = "time"
    version = "0.3.44"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "91e7d9e3bb61134e77bde20dd4825b97c010155709965fedf0f49bb138e52a9d"
    dependencies = [
    "deranged",
    "itoa",
    "num-conv",
    "powerfmt",
    "serde",
    "time-core",
    "time-macros",
    ]
    [[package]]
    name = "time-core"
    version = "0.1.6"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "40868e7c1d2f0b8d73e4a8c7f0ff63af4f6d19be117e90bd73eb1d62cf831c6b"
    [[package]]
    name = "time-macros"
    version = "0.2.24"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "30cfb0125f12d9c277f35663a0a33f8c30190f4e4574868a330595412d34ebf3"
    dependencies = [
    "num-conv",
    "time-core",
    ]
    [[package]]
    name = "tinystr"
    version = "0.8.1"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "5d4f6d1145dcb577acf783d4e601bc1d76a13337bb54e6233add580b07344c8b"
    dependencies = [
    "displaydoc",
    "serde",
    "zerovec",
    ]
    [[package]]
    name = "tokio"
    version = "1.48.0"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "ff360e02eab121e0bc37a2d3b4d4dc622e6eda3a8e5253d5435ecf5bd4c68408"
    dependencies = [
    "bytes",
    "libc",
    "mio",
    "pin-project-lite",
    "socket2",
    "windows-sys 0.61.2",
    ]
    [[package]]
    name = "tokio-stream"
    version = "0.1.17"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "eca58d7bba4a75707817a2c44174253f9236b2d5fbd055602e9d5c07c139a047"
    dependencies = [
    "futures-core",
    "pin-project-lite",
    "tokio",
    ]
    [[package]]
    name = "toml"
    version = "0.8.23"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "dc1beb996b9d83529a9e75c17a1686767d148d70663143c7854d8b4a09ced362"
    dependencies = [
    "indexmap 2.11.4",
    "serde",
    "serde_spanned",
    "toml_datetime",
    "toml_edit",
    ]
    [[package]]
    name = "toml_datetime"
    version = "0.6.11"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "22cddaf88f4fbc13c51aebbf5f8eceb5c7c5a9da2ac40a13519eb5b0a0e8f11c"
    dependencies = [
    "serde",
    ]
    [[package]]
    name = "toml_edit"
    version = "0.22.27"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "41fe8c660ae4257887cf66394862d21dbca4a6ddd26f04a3560410406a2f819a"
    dependencies = [
    "indexmap 2.11.4",
    "serde",
    "serde_spanned",
    "toml_datetime",
    "toml_write",
    "winnow",
    ]
    [[package]]
    name = "toml_write"
    version = "0.1.2"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "5d99f8c9a7727884afe522e9bd5edbfc91a3312b36a77b5fb8926e4c31a41801"
    [[package]]
    name = "tracing"
    version = "0.1.41"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "784e0ac535deb450455cbfa28a6f0df145ea1bb7ae51b821cf5e7927fdcfbdd0"
    dependencies = [
    "pin-project-lite",
    "tracing-attributes",
    "tracing-core",
    ]
    [[package]]
    name = "tracing-attributes"
    version = "0.1.30"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "81383ab64e72a7a8b8e13130c49e3dab29def6d0c7d76a03087b3cf71c5c6903"
    dependencies = [
    "proc-macro2",
    "quote",
    "syn",
    ]
    [[package]]
    name = "tracing-core"
    version = "0.1.34"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "b9d12581f227e93f094d3af2ae690a574abb8a2b9b7a96e7cfe9647b2b617678"
    dependencies = [
    "once_cell",
    "valuable",
    ]
    [[package]]
    name = "tracing-log"
    version = "0.2.0"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "ee855f1f400bd0e5c02d150ae5de3840039a3f54b025156404e34c23c03f47c3"
    dependencies = [
    "log",
    "once_cell",
    "tracing-core",
    ]
    [[package]]
    name = "tracing-subscriber"
    version = "0.3.20"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "2054a14f5307d601f88daf0553e1cbf472acc4f2c51afab632431cdcd72124d5"
    dependencies = [
    "nu-ansi-term",
    "sharded-slab",
    "smallvec",
    "thread_local",
    "tracing-core",
    "tracing-log",
    ]
    [[package]]
    name = "twox-hash"
    version = "1.6.3"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "97fee6b57c6a41524a810daee9286c02d7752c4253064d0b05472833a438f675"
    dependencies = [
    "cfg-if",
    "rand 0.8.5",
    "static_assertions",
    ]
    [[package]]
    name = "typenum"
    version = "1.19.0"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "562d481066bde0658276a35467c4af00bdc6ee726305698a55b86e61d7ad82bb"
    [[package]]
    name = "uncased"
    version = "0.9.10"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "e1b88fcfe09e89d3866a5c11019378088af2d24c3fbd4f0543f96b479ec90697"
    dependencies = [
    "version_check",
    ]
    [[package]]
    name = "unicode-ident"
    version = "1.0.19"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "f63a545481291138910575129486daeaf8ac54aee4387fe7906919f7830c7d9d"
    [[package]]
    name = "unicode-linebreak"
    version = "0.1.5"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "3b09c83c3c29d37506a3e260c08c03743a6bb66a9cd432c6934ab501a190571f"
    [[package]]
    name = "unicode-segmentation"
    version = "1.12.0"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "f6ccf251212114b54433ec949fd6a7841275f9ada20dddd2f29e9ceea4501493"
    [[package]]
    name = "unicode-width"
    version = "0.1.14"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "7dd6e30e90baa6f72411720665d41d89b9a3d039dc45b8faea1ddd07f617f6af"
    [[package]]
    name = "unicode-width"
    version = "0.2.2"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "b4ac048d71ede7ee76d585517add45da530660ef4390e49b098733c6e897f254"
    [[package]]
    name = "unicode-xid"
    version = "0.2.6"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853"
    [[package]]
    name = "url"
    version = "2.5.7"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "08bc136a29a3d1758e07a9cca267be308aeebf5cfd5a10f3f67ab2097683ef5b"
    dependencies = [
    "form_urlencoded",
    "idna",
    "percent-encoding",
    "serde",
    ]
    [[package]]
    name = "utf8_iter"
    version = "1.0.4"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be"
    [[package]]
    name = "utf8parse"
    version = "0.2.2"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821"
    [[package]]
    name = "validator"
    version = "0.20.0"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "43fb22e1a008ece370ce08a3e9e4447a910e92621bb49b85d6e48a45397e7cfa"
    dependencies = [
    "idna",
    "once_cell",
    "regex",
    "serde",
    "serde_derive",
    "serde_json",
    "url",
    ]
    [[package]]
    name = "valuable"
    version = "0.1.1"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "ba73ea9cf16a25df0c8caa16c51acb937d5712a8429db78a3ee29d5dcacd3a65"
    [[package]]
    name = "vcpkg"
    version = "0.2.15"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426"
    [[package]]
    name = "version_check"
    version = "0.9.5"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a"
    [[package]]
    name = "walkdir"
    version = "2.5.0"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b"
    dependencies = [
    "same-file",
    "winapi-util",
    ]
    [[package]]
    name = "wasi"
    version = "0.9.0+wasi-snapshot-preview1"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519"
    [[package]]
    name = "wasi"
    version = "0.11.1+wasi-snapshot-preview1"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b"
    [[package]]
    name = "wasi"
    version = "0.14.7+wasi-0.2.4"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "883478de20367e224c0090af9cf5f9fa85bed63a95c1abf3afc5c083ebc06e8c"
    dependencies = [
    "wasip2",
    ]
    [[package]]
    name = "wasip2"
    version = "1.0.1+wasi-0.2.4"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "0562428422c63773dad2c345a1882263bbf4d65cf3f42e90921f787ef5ad58e7"
    dependencies = [
    "wit-bindgen",
    ]
    [[package]]
    name = "wasite"
    version = "0.1.0"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "b8dad83b4f25e74f184f64c43b150b91efe7647395b42289f38e50566d82855b"
    [[package]]
    name = "wasm-bindgen"
    version = "0.2.104"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "c1da10c01ae9f1ae40cbfac0bac3b1e724b320abfcf52229f80b547c0d250e2d"
    dependencies = [
    "cfg-if",
    "once_cell",
    "rustversion",
    "wasm-bindgen-macro",
    "wasm-bindgen-shared",
    ]
    [[package]]
    name = "wasm-bindgen-backend"
    version = "0.2.104"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "671c9a5a66f49d8a47345ab942e2cb93c7d1d0339065d4f8139c486121b43b19"
    dependencies = [
    "bumpalo",
    "log",
    "proc-macro2",
    "quote",
    "syn",
    "wasm-bindgen-shared",
    ]
    [[package]]
    name = "wasm-bindgen-macro"
    version = "0.2.104"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "7ca60477e4c59f5f2986c50191cd972e3a50d8a95603bc9434501cf156a9a119"
    dependencies = [
    "quote",
    "wasm-bindgen-macro-support",
    ]
    [[package]]
    name = "wasm-bindgen-macro-support"
    version = "0.2.104"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "9f07d2f20d4da7b26400c9f4a0511e6e0345b040694e8a75bd41d578fa4421d7"
    dependencies = [
    "proc-macro2",
    "quote",
    "syn",
    "wasm-bindgen-backend",
    "wasm-bindgen-shared",
    ]
    [[package]]
    name = "wasm-bindgen-shared"
    version = "0.2.104"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "bad67dc8b2a1a6e5448428adec4c3e84c43e561d8c9ee8a9e5aabeb193ec41d1"
    dependencies = [
    "unicode-ident",
    ]
    [[package]]
    name = "wax"
    version = "0.6.0"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "8d12a78aa0bab22d2f26ed1a96df7ab58e8a93506a3e20adb47c51a93b4e1357"
    dependencies = [
    "const_format",
    "itertools",
    "nom",
    "pori",
    "regex",
    "thiserror 1.0.69",
    "walkdir",
    ]
    [[package]]
    name = "web-time"
    version = "1.1.0"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "5a6580f308b1fad9207618087a65c04e7a10bc77e02c8e84e9b00dd4b12fa0bb"
    dependencies = [
    "js-sys",
    "wasm-bindgen",
    ]
    [[package]]
    name = "whoami"
    version = "1.6.1"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "5d4a4db5077702ca3015d3d02d74974948aba2ad9e12ab7df718ee64ccd7e97d"
    dependencies = [
    "libredox",
    "wasite",
    ]
    [[package]]
    name = "winapi"
    version = "0.3.9"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419"
    dependencies = [
    "winapi-i686-pc-windows-gnu",
    "winapi-x86_64-pc-windows-gnu",
    ]
    [[package]]
    name = "winapi-i686-pc-windows-gnu"
    version = "0.4.0"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
    [[package]]
    name = "winapi-util"
    version = "0.1.11"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "c2a7b1c03c876122aa43f3020e6c3c3ee5c05081c9a00739faf7503aeba10d22"
    dependencies = [
    "windows-sys 0.61.2",
    ]
    [[package]]
    name = "winapi-x86_64-pc-windows-gnu"
    version = "0.4.0"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
    [[package]]
    name = "windows-core"
    version = "0.62.2"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "b8e83a14d34d0623b51dce9581199302a221863196a1dde71a7663a4c2be9deb"
    dependencies = [
    "windows-implement",
    "windows-interface",
    "windows-link",
    "windows-result",
    "windows-strings",
    ]
    [[package]]
    name = "windows-implement"
    version = "0.60.2"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "053e2e040ab57b9dc951b72c264860db7eb3b0200ba345b4e4c3b14f67855ddf"
    dependencies = [
    "proc-macro2",
    "quote",
    "syn",
    ]
    [[package]]
    name = "windows-interface"
    version = "0.59.3"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "3f316c4a2570ba26bbec722032c4099d8c8bc095efccdc15688708623367e358"
    dependencies = [
    "proc-macro2",
    "quote",
    "syn",
    ]
    [[package]]
    name = "windows-link"
    version = "0.2.1"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5"
    [[package]]
    name = "windows-result"
    version = "0.4.1"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "7781fa89eaf60850ac3d2da7af8e5242a5ea78d1a11c49bf2910bb5a73853eb5"
    dependencies = [
    "windows-link",
    ]
    [[package]]
    name = "windows-strings"
    version = "0.5.1"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "7837d08f69c77cf6b07689544538e017c1bfcf57e34b4c0ff58e6c2cd3b37091"
    dependencies = [
    "windows-link",
    ]
    [[package]]
    name = "windows-sys"
    version = "0.59.0"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b"
    dependencies = [
    "windows-targets 0.52.6",
    ]
    [[package]]
    name = "windows-sys"
    version = "0.60.2"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "f2f500e4d28234f72040990ec9d39e3a6b950f9f22d3dba18416c35882612bcb"
    dependencies = [
    "windows-targets 0.53.5",
    ]
    [[package]]
    name = "windows-sys"
    version = "0.61.2"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc"
    dependencies = [
    "windows-link",
    ]
    [[package]]
    name = "windows-targets"
    version = "0.52.6"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973"
    dependencies = [
    "windows_aarch64_gnullvm 0.52.6",
    "windows_aarch64_msvc 0.52.6",
    "windows_i686_gnu 0.52.6",
    "windows_i686_gnullvm 0.52.6",
    "windows_i686_msvc 0.52.6",
    "windows_x86_64_gnu 0.52.6",
    "windows_x86_64_gnullvm 0.52.6",
    "windows_x86_64_msvc 0.52.6",
    ]
    [[package]]
    name = "windows-targets"
    version = "0.53.5"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "4945f9f551b88e0d65f3db0bc25c33b8acea4d9e41163edf90dcd0b19f9069f3"
    dependencies = [
    "windows-link",
    "windows_aarch64_gnullvm 0.53.1",
    "windows_aarch64_msvc 0.53.1",
    "windows_i686_gnu 0.53.1",
    "windows_i686_gnullvm 0.53.1",
    "windows_i686_msvc 0.53.1",
    "windows_x86_64_gnu 0.53.1",
    "windows_x86_64_gnullvm 0.53.1",
    "windows_x86_64_msvc 0.53.1",
    ]
    [[package]]
    name = "windows_aarch64_gnullvm"
    version = "0.52.6"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3"
    [[package]]
    name = "windows_aarch64_gnullvm"
    version = "0.53.1"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "a9d8416fa8b42f5c947f8482c43e7d89e73a173cead56d044f6a56104a6d1b53"
    [[package]]
    name = "windows_aarch64_msvc"
    version = "0.52.6"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469"
    [[package]]
    name = "windows_aarch64_msvc"
    version = "0.53.1"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "b9d782e804c2f632e395708e99a94275910eb9100b2114651e04744e9b125006"
    [[package]]
    name = "windows_i686_gnu"
    version = "0.52.6"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b"
    [[package]]
    name = "windows_i686_gnu"
    version = "0.53.1"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "960e6da069d81e09becb0ca57a65220ddff016ff2d6af6a223cf372a506593a3"
    [[package]]
    name = "windows_i686_gnullvm"
    version = "0.52.6"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66"
    [[package]]
    name = "windows_i686_gnullvm"
    version = "0.53.1"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "fa7359d10048f68ab8b09fa71c3daccfb0e9b559aed648a8f95469c27057180c"
    [[package]]
    name = "windows_i686_msvc"
    version = "0.52.6"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66"
    [[package]]
    name = "windows_i686_msvc"
    version = "0.53.1"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "1e7ac75179f18232fe9c285163565a57ef8d3c89254a30685b57d83a38d326c2"
    [[package]]
    name = "windows_x86_64_gnu"
    version = "0.52.6"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78"
    [[package]]
    name = "windows_x86_64_gnu"
    version = "0.53.1"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "9c3842cdd74a865a8066ab39c8a7a473c0778a3f29370b5fd6b4b9aa7df4a499"
    [[package]]
    name = "windows_x86_64_gnullvm"
    version = "0.52.6"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d"
    [[package]]
    name = "windows_x86_64_gnullvm"
    version = "0.53.1"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "0ffa179e2d07eee8ad8f57493436566c7cc30ac536a3379fdf008f47f6bb7ae1"
    [[package]]
    name = "windows_x86_64_msvc"
    version = "0.52.6"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec"
    [[package]]
    name = "windows_x86_64_msvc"
    version = "0.53.1"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "d6bbff5f0aada427a1e5a6da5f1f98158182f26556f345ac9e04d36d0ebed650"
    [[package]]
    name = "winnow"
    version = "0.7.13"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "21a0236b59786fed61e2a80582dd500fe61f18b5dca67a4a067d0bc9039339cf"
    dependencies = [
    "memchr",
    ]
    [[package]]
    name = "wit-bindgen"
    version = "0.46.0"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "f17a85883d4e6d00e8a97c586de764dabcc06133f7f1d55dce5cdc070ad7fe59"
    [[package]]
    name = "writeable"
    version = "0.6.1"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "ea2f10b9bb0928dfb1b42b65e1f9e36f7f54dbdf08457afefb38afcdec4fa2bb"
    dependencies = [
    "either",
    ]
    [[package]]
    name = "xtask"
    version = "0.1.0"
    dependencies = [
    "anyhow",
    "camino",
    "cargo_metadata",
    "clap",
    ]
    [[package]]
    name = "yasna"
    version = "0.4.0"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "e262a29d0e61ccf2b6190d7050d4b237535fc76ce4c1210d9caa316f71dffa75"
    dependencies = [
    "bit-vec",
    "num-bigint",
    ]
    [[package]]
    name = "yoke"
    version = "0.8.0"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "5f41bb01b8226ef4bfd589436a297c53d118f65921786300e427be8d487695cc"
    dependencies = [
    "serde",
    "stable_deref_trait",
    "yoke-derive",
    "zerofrom",
    ]
    [[package]]
    name = "yoke-derive"
    version = "0.8.0"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "38da3c9736e16c5d3c8c597a9aaa5d1fa565d0532ae05e27c24aa62fb32c0ab6"
    dependencies = [
    "proc-macro2",
    "quote",
    "syn",
    "synstructure",
    ]
    [[package]]
    name = "zerocopy"
    version = "0.8.27"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "0894878a5fa3edfd6da3f88c4805f4c8558e2b996227a3d864f47fe11e38282c"
    dependencies = [
    "zerocopy-derive",
    ]
    [[package]]
    name = "zerocopy-derive"
    version = "0.8.27"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "88d2b8d9c68ad2b9e4340d7832716a4d21a22a1154777ad56ea55c51a9cf3831"
    dependencies = [
    "proc-macro2",
    "quote",
    "syn",
    ]
    [[package]]
    name = "zerofrom"
    version = "0.1.6"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "50cc42e0333e05660c3587f3bf9d0478688e15d870fab3346451ce7f8c9fbea5"
    dependencies = [
    "zerofrom-derive",
    ]
    [[package]]
    name = "zerofrom-derive"
    version = "0.1.6"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "d71e5d6e06ab090c67b5e44993ec16b72dcbaabc526db883a360057678b48502"
    dependencies = [
    "proc-macro2",
    "quote",
    "syn",
    "synstructure",
    ]
    [[package]]
    name = "zeroize"
    version = "1.3.0"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "4756f7db3f7b5574938c3eb1c117038b8e07f95ee6718c0efad4ac21508f1efd"
    dependencies = [
    "zeroize_derive",
    ]
    [[package]]
    name = "zeroize_derive"
    version = "1.4.2"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69"
    dependencies = [
    "proc-macro2",
    "quote",
    "syn",
    ]
    [[package]]
    name = "zerotrie"
    version = "0.2.2"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "36f0bbd478583f79edad978b407914f61b2972f5af6fa089686016be8f9af595"
    dependencies = [
    "displaydoc",
    "yoke",
    "zerofrom",
    ]
    [[package]]
    name = "zerovec"
    version = "0.11.4"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "e7aa2bd55086f1ab526693ecbe444205da57e25f4489879da80635a46d90e73b"
    dependencies = [
    "serde",
    "yoke",
    "zerofrom",
    "zerovec-derive",
    ]
    [[package]]
    name = "zerovec-derive"
    version = "0.11.1"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "5b96237efa0c878c64bd89c436f661be4e46b2f3eff1ebb976f7ef2321d2f58f"
    dependencies = [
    "proc-macro2",
    "quote",
    "syn",
    ]
    [[package]]
    name = "zstd-seekable"
    version = "0.1.23"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "574a117c5cdb88d1f13381ee3a19a6a45fb6ca0c98436d3a95df852b7ca6c3c2"
    dependencies = [
    "bincode",
    "cc",
    "libc",
    "pkg-config",
    "serde",
    "serde_derive",
    "thiserror 1.0.69",
    "threadpool",
    ]
  • file addition: .vscode (d--r------)
    [2.1]
  • file addition: tasks.json (----------)
    [0.278500]
    // https://code.visualstudio.com/docs/debugtest/tasks
    {
    "version": "2.0.0",
    "tasks": [
    {
    "label": "Build VSCode Extension",
    "type": "process",
    "command": "cargo",
    "args": ["xtask", "build", "vscode"],
    "isBackground": false,
    "presentation": {
    "close": true,
    "reveal": "always",
    "focus": false
    },
    "group": {
    "kind": "build"
    }
    }
    ]
    }
  • file addition: launch.json (----------)
    [0.278500]
    // https://code.visualstudio.com/docs/debugtest/debugging-configuration
    {
    "version": "0.2.0",
    "configurations": [
    {
    "name": "Run VSCode Extension",
    "type": "extensionHost",
    "request": "launch",
    "args": [
    "--extensionDevelopmentPath=${workspaceFolder}/extensions/vscode"
    ],
    "preLaunchTask": "Build VSCode Extension"
    }
    ]
    }
  • file addition: .ignore (----------)
    [2.1]
    # JavaScript/TypeScript
    node_modules/
    out/
    # Rust
    target/
  • file addition: .cargo (d--r------)
    [2.1]
  • file addition: config.toml (----------)
    [0.279418]
    [alias]
    xtask = "run --package xtask --"