chore: monorepo inicial con arje + minga + yahweh absorbidos
Workspace en 4 ejes (core/modules/apps/shared):
- core/: 24 crates de arje (Init systemd-compatible: ente-card, ente-zero,
ente-kernel, ente-bus, ente-cas, ente-soma, ente-wasm, ente-snapshot,
ente-brain, ente-echo, ente-policy-provider, + 12 crates *-compat)
- modules/semantic_dht/: 5 crates de minga (minga-core con AST/CAS/MST,
minga-p2p con libp2p Kad, minga-store, minga-vfs, minga-cli)
- modules/ui_engine/: 11 crates de yahweh (libs/{core,theme,bus,providers},
widgets/{tree,splitter,tabs,tiled,container_core,text_input})
- apps/: 5 crates de yahweh (file_explorer, database_explorer, text_viewer,
image_viewer, yahweh-shell)
- shared_wit/protocol.wit: handshake/lifecycle inicial
Cargo.toml unificado: thiserror bumped a 2 (transparente para arje), tokio
"full", paths intra-workspace de yahweh redirigidos a su nueva ubicación.
cargo check --workspace: 0 errores, 17 warnings (dead code preexistente).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Delta semántico · 1474
crates/apps/database_explorer/src/lib.rs
- nueva struct DatabaseExplorer pub
- nueva enum DatabaseExplorerEvent pub
- nueva def ROOT_KEY
- nueva fn append_children
- nueva fn db_path pub
- nueva fn find_entry
- nueva fn load_children
- nueva fn new pub
- nueva fn on_children_loaded
- nueva fn on_tree_event
- nueva fn push_rows
- nueva fn render
- nueva fn sort_entries
crates/apps/file_explorer/src/lib.rs
- nueva struct FileExplorer pub
- nueva enum FileExplorerEvent pub
- nueva def MENU_WIDTH
- nueva struct MenuState
- nueva struct MenuTarget
- nueva struct RenameState
- nueva fn action_copy_path
- nueva fn action_delete
- nueva fn action_new_file
- nueva fn action_new_folder
- nueva fn action_open
- nueva fn action_rename
- nueva fn append_children
- nueva fn close_menu
- nueva fn close_rename
- nueva fn commit_rename
- nueva fn find_entry
- nueva fn is_folder_path
- nueva fn load_children
- nueva fn menu_item
- nueva fn new pub
- nueva fn next_available_name
- nueva fn on_children_loaded
- nueva fn on_tree_event
- nueva fn open_menu
- nueva fn parent_for_new
- nueva fn push_rows
- nueva fn refresh_dir
- nueva fn render
- nueva fn render_menu
- nueva fn render_rename
- nueva fn root pub
- nueva fn separator
- nueva fn set_root pub
- nueva fn sort_entries
crates/apps/image_viewer/src/lib.rs
- nueva def FS_PROVIDER
- nueva struct ImageViewer pub
- nueva fn is_image_path
- nueva fn new pub
- nueva fn on_app_event
- nueva fn render
crates/apps/text_viewer/src/lib.rs
- nueva enum Content
- nueva struct CurrentEntity
- nueva def MAX_TEXT_BYTES
- nueva def PREVIEW_HEX_BYTES
- nueva struct TextViewer pub
- nueva fn bytes_to_content
- nueva fn new pub
- nueva fn on_app_event
- nueva fn on_loaded
- nueva fn render
- nueva fn spawn_load_fs
- nueva fn spawn_load_sqlite
crates/apps/yahweh-shell/src/hot_reload.rs
- nueva def POLL_INTERVAL
- nueva fn poll_loop
- nueva fn spawn_watch pub
crates/apps/yahweh-shell/src/layout_host.rs
- nueva struct LayoutHost pub
- nueva enum NodeSlot
- nueva struct PlaceholderView pub
- nueva fn build_child_slots
- nueva fn build_database_explorer
- nueva fn build_file_explorer
- nueva fn build_image_viewer
- nueva fn build_node
- nueva fn build_placeholder
- nueva fn build_split
- nueva fn build_status
- nueva fn build_tabs
- nueva fn build_text_viewer
- nueva fn build_tiled
- nueva fn build_tree
- nueva fn new pub
- nueva fn new pub
- nueva fn rebuild pub
- nueva fn render
- nueva fn render
crates/apps/yahweh-shell/src/layout_model.rs
- nueva struct LayoutModel pub
- nueva enum LayoutModelEvent pub
- nueva fn mutate_node
- nueva fn new pub
- nueva fn replace_tree pub
- nueva fn set_flex pub
- nueva fn set_kind pub
- nueva fn swap_children pub
- nueva fn tree pub
crates/apps/yahweh-shell/src/main.rs
- nueva def LAYOUT_PATH
- nueva mod hot_reload
- nueva mod layout_host
- nueva mod layout_model
- nueva fn main
- nueva mod managed_tree
- nueva mod persister
- nueva mod status_panel
crates/apps/yahweh-shell/src/managed_tree.rs
- nueva struct DemoNode pub
- nueva struct ManagedTree pub
- nueva enum ManagedTreeEvent pub
- nueva fn branch
- nueva fn branch
- nueva fn dataset_for pub
- nueva fn dataset_key pub
- nueva fn flatten
- nueva fn leaf
- nueva fn new pub
- nueva fn on_tree_event
- nueva fn push_rows
- nueva fn render
- nueva fn yahweh_deps_tree
- nueva fn yahweh_sources_tree
crates/apps/yahweh-shell/src/status_panel.rs
- nueva def LAYOUT_PATH
- nueva def SWAPPABLE_KINDS
- nueva def SWAP_TARGET_ID
- nueva struct StatusPanel pub
- nueva fn current_target_kind
- nueva fn cycle_theme
- nueva fn find_kind
- nueva fn new pub
- nueva fn pick_theme
- nueva fn reload_from_disk
- nueva fn render
- nueva fn set_status pub
- nueva fn swap_container
crates/core/ente-binfmt-compat/src/main.rs
- nueva def REGISTER_PATH
- nueva struct RegError
- nueva def SEARCH_DIRS
- nueva fn fmt
- nueva fn init_tracing
- nueva fn is_already_exists
- nueva fn main
- nueva fn register
crates/core/ente-brain/examples/brainctl.rs
- nueva fn _suppress
- nueva fn hex_long
- nueva fn hex_short
- nueva fn main
- nueva fn print_response
- nueva fn run_stream_audit
- nueva fn socket_path
crates/core/ente-brain/src/audit.rs
- nueva enum AuditAction pub
- nueva struct AuditEntry pub
- nueva struct AuditHeadPointer pub
- nueva struct AuditLog pub
- nueva def CAS_TEST_LOCK
- nueva struct G
- nueva struct ReplayReport pub
- nueva struct VerificationReport pub
- nueva fn append pub
- nueva fn canonical_bytes
- nueva fn cap_evicts_oldest
- nueva fn chain_links_consecutive_entries
- nueva fn collect_chain_from_cas pub
- nueva fn compute_sha
- nueva fn default
- nueva fn drop
- nueva fn dummy_crystal
- nueva fn flush_round_trip_preserves_chain
- nueva fn flush_to_cas pub
- nueva fn flushed_count pub
- nueva fn head_sha pub
- nueva fn is_empty pub
- nueva fn last_flush_age_secs pub
- nueva fn last_flush_at_ms pub
- nueva fn last_flushed_sha pub
- nueva fn len pub
- nueva fn new pub
- nueva fn now_ms
- nueva fn persist_to_cas pub
- nueva fn reachable_from_head pub
- nueva fn recent pub
- nueva fn replay_after_eviction_still_works
- nueva fn replay_chain pub
- nueva fn replay_reconstructs_engine_state
- nueva fn scopeguard
- nueva fn seq_monotonic
- nueva fn subscribe pub
- nueva fn subscriber_count pub
- nueva mod tests
- nueva fn verify_chain_from_cas pub
- nueva fn with_cap pub
- nueva fn with_head_pointer pub
- nueva fn with_temp_cas
crates/core/ente-brain/src/autopromote.rs
- nueva struct AutopromoteParams pub
- nueva fn default
- nueva fn promote_one
- nueva fn run_one_pass
- nueva fn spawn_autopromote_loop pub
crates/core/ente-brain/src/crystallize.rs
- nueva struct Crystal pub
- nueva struct CrystallizationParams pub
- nueva enum PatternCrystal pub
- nueva struct PatternParams pub
- nueva fn crystal_to_json_pretty pub
- nueva fn crystal_to_rule pub
- nueva fn default
- nueva fn default
- nueva fn detect_crystals pub
- nueva fn detect_pattern_crystals pub
- nueva fn detects_perfect_correlation
- nueva fn rejects_below_threshold
- nueva mod tests
crates/core/ente-brain/src/dispatch.rs
- nueva trait ActionSink pub
- nueva struct NullSink pub
- nueva fn dispatch_actions pub
- nueva fn emit_log
- nueva fn execute_action
- nueva fn inhibit
- nueva fn invoke
- nueva fn notify
- nueva fn spawn
crates/core/ente-brain/src/engine.rs
- nueva enum EventKindDiscriminant pub
- nueva struct RuleEngine pub
- nueva struct SubjectInfo pub
- nueva fn all_requires_every_branch
- nueva fn bus_invoke_generic_matches_specific
- nueva fn default
- nueva fn dispatch pub
- nueva fn dispatch_picks_only_matching_kind
- nueva fn either_matches_any_branch
- nueva fn empty pub
- nueva fn empty_history
- nueva fn from
- nueva fn insert pub
- nueva fn is_empty pub
- nueva fn len pub
- nueva fn load_json pub
- nueva fn matches_event_payload
- nueva fn matches_pattern
- nueva fn matches_scope
- nueva fn priority_orders_descending
- nueva fn remove pub
- nueva fn rule_single
- nueva fn rules pub
- nueva fn scope_filters_by_label
- nueva fn sequence_pattern_matches_with_history
- nueva fn sequence_rejects_outside_time_window
- nueva fn sequence_requires_correct_order
- nueva mod tests
crates/core/ente-brain/src/introspect.rs
- nueva struct BrainState pub
- nueva struct CorrelationEntry pub
- nueva enum IntrospectRequest pub
- nueva enum IntrospectResponse pub
- nueva struct IntrospectServer pub
- nueva def MAX_FRAME
- nueva struct RuleSummary pub
- nueva fn append_rule_jsonl pub
- nueva fn call pub
- nueva fn dispatch
- nueva fn handle
- nueva fn marginal_summary pub
- nueva fn new pub
- nueva fn new pub
- nueva fn serve pub
- nueva fn stream_audit
- nueva fn with_params pub
- nueva fn with_rules_out pub
crates/core/ente-brain/src/lib.rs
- nueva mod audit pub
- nueva mod autopromote pub
- nueva mod crystallize pub
- nueva mod dispatch pub
- nueva mod engine pub
- nueva mod introspect pub
- nueva mod loader pub
- nueva mod metrics pub
- nueva mod observer pub
- nueva mod rules pub
crates/core/ente-brain/src/loader.rs
- nueva fn append_rule_jsonl_roundtrip
- nueva fn extract_card_from_json pub
- nueva fn extract_rules_from_json pub
- nueva fn load_card_file pub
- nueva fn load_rules_file pub
- nueva fn rules_from_array
- nueva fn rules_from_jsonl_with_comments_and_blanks
- nueva fn rules_from_object_with_array
- nueva fn sample_rule
- nueva fn tempdir_unique
- nueva mod tests
crates/core/ente-brain/src/metrics.rs
- nueva fn format_metrics
- nueva fn handle_scrape
- nueva fn kind_label
- nueva fn serve_metrics pub
crates/core/ente-brain/src/observer.rs
- nueva def GAP_BUCKET_LIMITS_SECS
- nueva struct GapHistogram pub
- nueva struct GapStats pub
- nueva def OBSERVER_SCHEMA_VERSION
- nueva struct Observer pub
- nueva struct ObserverSnapshot pub
- nueva struct TimedEvent pub
- nueva fn apply_delta pub
- nueva fn bucket_limits pub
- nueva fn conditional_prob pub
- nueva fn conditional_prob_perfect_dependency
- nueva fn cooccur_decayed pub
- nueva fn cooccurrences pub
- nueva fn current_window pub
- nueva fn decay
- nueva fn entropy_one_for_balanced_binary
- nueva fn entropy_zero_for_single_event
- nueva fn from_snapshot pub
- nueva fn gap_histograms pub
- nueva fn half_life pub
- nueva fn last_seen_marginal pub
- nueva fn marginal_decayed pub
- nueva fn marginals pub
- nueva fn mean_secs pub
- nueva fn new pub
- nueva fn observe pub
- nueva fn pmi pub
- nueva fn recent pub
- nueva fn record pub
- nueva fn shannon_entropy pub
- nueva fn snapshot pub
- nueva fn snapshot_delta pub
- nueva fn stats pub
- nueva fn stddev_secs pub
- nueva mod tests
- nueva fn top_gap_pairs pub
- nueva fn total pub
- nueva fn weighted_pmi pub
- nueva fn window_size pub
- nueva fn with_half_life pub
crates/core/ente-brain/src/rules.rs
- nueva enum Action pub
- nueva enum EventKind pub
- nueva enum EventPattern pub
- nueva enum LogLevel pub
- nueva struct Rule pub
- nueva enum RuleError pub
- nueva struct Scope pub
- nueva fn as_str pub
- nueva mod blob_b64
- nueva fn default_log_level
- nueva fn default_priority
- nueva fn deserialize pub
- nueva fn fmt
- nueva fn is_simple pub
- nueva fn is_wildcard pub
- nueva fn serialize pub
- nueva fn trigger_kind pub
- nueva fn validate pub
- nueva fn validate_recursive pub
crates/core/ente-bus/examples/busctl.rs
- nueva fn main
crates/core/ente-bus/src/lib.rs
- nueva struct BusClient pub
- nueva struct BusMessage pub
- nueva enum BusPayload pub
- nueva enum BusRequest pub
- nueva enum BusResponse pub
- nueva struct BusServer pub
- nueva def ENV_BUS_SOCK pub
- nueva def ENV_ENTE_ID pub
- nueva struct EnteInfo pub
- nueva trait InvokeHandler pub
- nueva def MAX_FRAME pub
- nueva def POLKIT_DECISION_IFACE pub
- nueva def POLKIT_SERVICE_IFACE pub
- nueva struct PeerCreds pub
- nueva fn announce pub
- nueva fn call pub
- nueva fn connect pub
- nueva fn from_env pub
- nueva fn from_env pub
- nueva fn read_frame pub
- nueva fn serve pub
- nueva fn write_frame pub
crates/core/ente-card/src/lib.rs
- nueva def CARD_SCHEMA_VERSION pub
- nueva enum Capability pub
- nueva enum CardError pub
- nueva struct CgroupSpec pub
- nueva enum DeviceClass pub
- nueva struct EntityCard pub
- nueva struct InterfaceId pub
- nueva enum LegacyFacade pub
- nueva struct NamespaceSet pub
- nueva enum NetlinkFamily pub
- nueva enum Payload pub
- nueva struct ResourceLimits pub
- nueva struct SomaSpec pub
- nueva enum Supervision pub
- nueva fn deserialize pub
- nueva mod duration_millis
- nueva fn fmt
- nueva fn invalid_genesis_propagates
- nueva fn seed_card_validates
- nueva fn self_dependency_rejected
- nueva fn serialize pub
- nueva mod tests
- nueva fn validate pub
- nueva fn validate_cgroup
- nueva fn validate_payload
- nueva fn validate_rlimits
crates/core/ente-cas/src/lib.rs
crates/core/ente-echo/src/lib.rs
- nueva def ECHO_IFACE pub
- nueva def ECHO_VERSION pub
- nueva fn echo_capability pub
crates/core/ente-echo/src/main.rs
- nueva struct EchoHandler
- nueva fn handle
- nueva fn main
crates/core/ente-hostnamed-compat/src/main.rs
- nueva def BUS_NAME
- nueva struct HostnameManager
- nueva def OBJ_PATH
- nueva fn announce_to_fractal
- nueva fn atomic_write
- nueva fn chassis
- nueva fn deployment
- nueva fn firmware_version
- nueva fn gethostname_libc
- nueva fn hardware_model
- nueva fn hardware_vendor
- nueva fn home_url
- nueva fn hostname
- nueva fn icon_name
- nueva fn init_tracing
- nueva fn is_valid_hostname
- nueva fn kernel_name
- nueva fn kernel_release
- nueva fn kernel_version
- nueva fn location
- nueva fn main
- nueva fn operating_system_cpename
- nueva fn operating_system_pretty_name
- nueva fn parse_kv_file
- nueva fn pretty_hostname
- nueva fn read_dmi
- nueva fn read_machine_info_field
- nueva fn read_os_release_field
- nueva fn set_chassis
- nueva fn set_deployment
- nueva fn set_hostname
- nueva fn set_icon_name
- nueva fn set_location
- nueva fn set_pretty_hostname
- nueva fn set_static_hostname
- nueva fn static_hostname
- nueva fn update_machine_info
- nueva fn wait_for_term
crates/core/ente-journald-compat/src/journalctl.rs
- nueva struct Args
- nueva struct IndexEntry
- nueva enum OutputFormat
- nueva fn gethostname_safe
- nueva fn index_path
- nueva fn main
- nueva fn now_ms
- nueva fn parse_args
- nueva fn parse_line
- nueva fn parse_sha
- nueva fn print_export
- nueva fn print_help
- nueva fn print_json
- nueva fn print_pretty
- nueva fn safe_export_byte
crates/core/ente-journald-compat/src/main.rs
- nueva def DEV_LOG
- nueva def INDEX_FILE
- nueva def JOURNAL_SOCKET
- nueva struct OwnedFdWrap
- nueva fn announce_to_fractal
- nueva fn as_raw_fd
- nueva fn bind_dgram
- nueva fn handle_message
- nueva fn index_path
- nueva fn init_tracing
- nueva fn main
- nueva fn now_ms
- nueva fn persist_to_cas
- nueva fn spawn_listener
- nueva fn wait_for_term
crates/core/ente-kernel/src/sigchld.rs
- nueva struct SignalFdHandle
- nueva fn as_raw_fd
- nueva fn drain
- nueva fn spawn_sigchld_stream pub
crates/core/ente-kernel/src/surface.rs
- nueva enum ReapStatus pub
- nueva struct ReapedChild pub
- nueva fn become_child_subreaper pub
- nueva fn bootstrap_kernel_surface pub
- nueva fn reap_all pub
crates/core/ente-kernel/src/uevent.rs
- nueva struct NetlinkHandle
- nueva enum UAction pub
- nueva struct UEvent pub
- nueva fn as_raw_fd
- nueva fn libudev_messages_filtered
- nueva fn map_device_class
- nueva fn parse_action
- nueva fn parse_minimal_uevent
- nueva fn parse_uevent
- nueva fn spawn_uevent_stream pub
- nueva mod tests
crates/core/ente-localed-compat/src/main.rs
- nueva def BUS_NAME
- nueva struct LocaleManager
- nueva def OBJ_PATH
- nueva fn announce_to_fractal
- nueva fn atomic_write
- nueva fn init_tracing
- nueva fn locale
- nueva fn main
- nueva fn read_kv
- nueva fn read_vconsole
- nueva fn set_locale
- nueva fn set_vconsole_keymap
- nueva fn set_x11_keyboard
- nueva fn vconsole_keymap
- nueva fn vconsole_keymap_toggle
- nueva fn wait_for_term
- nueva fn x11layout
- nueva fn x11model
- nueva fn x11options
- nueva fn x11variant
crates/core/ente-logind-compat/src/main.rs
- nueva def BUS_NAME
- nueva struct LogindManager
- nueva def MANAGER_PATH
- nueva type SessionTuple
- nueva type UserTuple
- nueva fn announce_to_fractal
- nueva fn block_inhibited
- nueva fn build_connection
- nueva fn can_hibernate
- nueva fn can_power_off
- nueva fn can_reboot
- nueva fn can_suspend
- nueva fn delay_inhibited
- nueva fn docked
- nueva fn forward_to_fractal
- nueva fn get_session
- nueva fn get_session_by_pid
- nueva fn get_user
- nueva fn get_user_by_pid
- nueva fn hibernate
- nueva fn idle_hint
- nueva fn idle_since_hint
- nueva fn idle_since_hint_monotonic
- nueva fn inhibit
- nueva fn init_tracing
- nueva fn lid_closed
- nueva fn list_sessions
- nueva fn list_users
- nueva fn main
- nueva fn on_external_power
- nueva fn power_off
- nueva fn reboot
- nueva fn suspend
- nueva fn wait_for_term
crates/core/ente-machined-compat/src/main.rs
- nueva def BUS_NAME
- nueva type Machine
- nueva struct MachineManager
- nueva def OBJ_PATH
- nueva fn announce_to_fractal
- nueva fn create_machine
- nueva fn get_machine
- nueva fn get_machine_address
- nueva fn get_machine_by_pid
- nueva fn get_machine_osrelease
- nueva fn init_tracing
- nueva fn kill_machine
- nueva fn list_machines
- nueva fn main
- nueva fn open_machine_login
- nueva fn open_machine_shell
- nueva fn register_machine
- nueva fn register_machine_with_network
- nueva fn terminate_machine
- nueva fn wait_for_term
crates/core/ente-notify-compat/src/main.rs
- nueva def NOTIFY_SOCKET_PATH
- nueva struct OwnedFdWrap
- nueva fn announce_to_fractal
- nueva fn as_raw_fd
- nueva fn bind_dgram
- nueva fn handle_notification
- nueva fn init_tracing
- nueva fn main
- nueva fn spawn_listener
- nueva fn wait_for_term
crates/core/ente-policy-provider/src/main.rs
- nueva enum Decision
- nueva struct PolicyConfig
- nueva struct PolicyHandler
- nueva struct Rule
- nueva fn decide
- nueva fn default
- nueva fn default_decision
- nueva fn glob_match
- nueva fn handle
- nueva fn init_tracing
- nueva fn load_policy
- nueva fn main
crates/core/ente-polkit-compat/src/main.rs
- nueva type AuthResult
- nueva def BUS_NAME
- nueva type EnumeratedAction
- nueva def OBJ_PATH
- nueva struct PolicyDecision
- nueva struct PolkitAuthority
- nueva type Subject
- nueva type TemporaryAuth
- nueva fn announce_to_fractal
- nueva fn authentication_agent_response
- nueva fn backend_features
- nueva fn backend_name
- nueva fn backend_version
- nueva fn cancel_check_authorization
- nueva fn check_authorization
- nueva fn check_authorization_by_async
- nueva fn enumerate_actions
- nueva fn enumerate_temporary_authorizations
- nueva fn init_tracing
- nueva fn main
- nueva fn query_policy
- nueva fn register_authentication_agent
- nueva fn register_authentication_agent_with_options
- nueva fn revoke_temporary_authorization_by_id
- nueva fn revoke_temporary_authorizations
- nueva fn unregister_authentication_agent
- nueva fn wait_for_term
crates/core/ente-resolved-compat/src/main.rs
- nueva def AF_INET
- nueva def AF_INET6
- nueva def BUS_NAME
- nueva type HostnameAddress
- nueva def OBJ_PATH
- nueva struct ResolveManager
- nueva fn announce_to_fractal
- nueva fn init_tracing
- nueva fn main
- nueva fn parse_address
- nueva fn resolve_address
- nueva fn resolve_hostname
- nueva fn resolve_record
- nueva fn reverse_lookup
- nueva fn wait_for_term
crates/core/ente-snapshot/src/lib.rs
- nueva struct FractalSnapshot pub
- nueva def SNAPSHOT_VERSION pub
- nueva fn now_ms pub
- nueva fn read pub
- nueva fn write pub
crates/core/ente-soma/src/lib.rs
- nueva def BUS_SOCK_PATH
- nueva fn _keep_imports
- nueva fn apply_rlimits_unchecked
- nueva fn build_clone_flags
- nueva fn build_env
- nueva fn configure_child
- nueva fn current_cgroup
- nueva fn ensure_cgroup
- nueva fn incarnate pub
- nueva fn incarnate_namespaced
- nueva fn incarnate_plain
- nueva fn needs_namespacing
- nueva fn resolve_cgroup_path
- nueva fn set_bus_sock pub
- nueva fn set_cpu_affinity
crates/core/ente-systemd1-compat/src/main.rs
- nueva def BUS_NAME
- nueva def OBJ_PATH
- nueva struct SystemdManager
- nueva type UnitInfo
- nueva fn _suppress
- nueva fn announce_to_fractal
- nueva fn architecture
- nueva fn confined
- nueva fn environment
- nueva fn escape_unit_name
- nueva fn features
- nueva fn get_default_target
- nueva fn get_unit
- nueva fn get_unit_by_pid
- nueva fn init_tracing
- nueva fn kill_unit
- nueva fn list_jobs
- nueva fn list_unit_files
- nueva fn list_units
- nueva fn list_units_by_names
- nueva fn list_units_filtered
- nueva fn main
- nueva fn n_jobs
- nueva fn n_names
- nueva fn progress
- nueva fn query_list_entes
- nueva fn reload
- nueva fn reload_unit
- nueva fn restart_unit
- nueva fn set_default_target
- nueva fn start_unit
- nueva fn stop_unit
- nueva fn subscribe
- nueva fn unsubscribe
- nueva fn version
- nueva fn virtualization
- nueva fn wait_for_term
crates/core/ente-timedated-compat/src/main.rs
- nueva def BUS_NAME
- nueva def OBJ_PATH
- nueva struct TimedateManager
- nueva fn announce_to_fractal
- nueva fn can_ntp
- nueva fn init_tracing
- nueva fn list_timezones
- nueva fn local_rtc
- nueva fn main
- nueva fn ntp
- nueva fn ntpsynchronized
- nueva fn rtctime_usec
- nueva fn set_local_rtc
- nueva fn set_ntp
- nueva fn set_time
- nueva fn set_timezone
- nueva fn time_usec
- nueva fn timezone
- nueva fn wait_for_term
crates/core/ente-timer-compat/src/main.rs
- nueva struct Cron
- nueva enum CronField
- nueva struct TimeBits
- nueva struct TimerConfig
- nueva fn announce_to_fractal
- nueva fn fire
- nueva fn init_tracing
- nueva fn load_timers
- nueva fn main
- nueva fn matches
- nueva fn matches
- nueva fn parse
- nueva fn parse
- nueva fn time_bits_utc
crates/core/ente-tmpfiles-compat/src/main.rs
- nueva struct Directive
- nueva def SEARCH_DIRS
- nueva fn apply
- nueva fn apply_d
- nueva fn apply_e
- nueva fn apply_f
- nueva fn apply_l
- nueva fn apply_r
- nueva fn chown
- nueva fn collect_directives
- nueva fn init_tracing
- nueva fn lookup_gid
- nueva fn lookup_uid
- nueva fn main
- nueva fn parse_default
- nueva fn parse_line
- nueva fn parse_mode
crates/core/ente-wasm/src/lib.rs
- nueva struct WasmEnte pub
- nueva fn demo_module_bytes pub
- nueva fn host_log
- nueva fn incarnate_wasm pub
- nueva fn read_memory
- nueva fn run_wasm
crates/core/ente-zero/src/brain_glue.rs
- nueva trait GraphCardLookup pub
- nueva struct GraphSink pub
- nueva struct _Touch
- nueva fn card_for
- nueva fn graph_event_to_brain pub
- nueva fn inhibit
- nueva fn invoke
- nueva fn notify
- nueva fn spawn
- nueva fn subject_info_for
crates/core/ente-zero/src/bus.rs
- nueva fn default_socket_path pub
- nueva fn handle_conn
- nueva fn spawn_bus pub
crates/core/ente-zero/src/events.rs
- nueva enum CapabilityGrant pub
- nueva enum ExitStatus pub
- nueva enum GraphEvent pub
- nueva enum ShutdownReason pub
crates/core/ente-zero/src/graph/bus_mediator.rs
- nueva def alloc_invoke_seq
- nueva fn apply_capability_update
- nueva fn forward_invoke
- nueva fn on_bus_conn_closed pub
- nueva fn on_bus_request pub
- nueva fn on_bus_response pub
- nueva fn pick_invokable_provider
- nueva fn requires_auth
crates/core/ente-zero/src/graph/capabilities.rs
- nueva fn active_grants_count pub
- nueva fn active_tokens_for pub
- nueva fn mediate_capability pub
- nueva fn purge_expired_grants pub
- nueva fn renew_grant pub
crates/core/ente-zero/src/graph/devices.rs
- nueva fn devices_of_class
- nueva fn on_uevent pub
crates/core/ente-zero/src/graph/lifecycle.rs
- nueva fn authorize_and_spawn pub
- nueva fn instantiate_seed_dependencies pub
- nueva fn notify_lineage_of_death
- nueva fn on_death pub
crates/core/ente-zero/src/graph/mod.rs
- nueva def DEFAULT_GRANT_TTL pub
- nueva struct EnteGraph pub
- nueva def GrantedCapability
- nueva def Incarnated
- nueva def SERVER_SEQ_FLAG
- nueva mod bus_mediator
- nueva mod capabilities
- nueva mod devices
- nueva def holder_has
- nueva mod lifecycle
- nueva fn lookup_pid pub
- nueva fn new pub
- nueva fn peek_card pub
- nueva fn quota_for_capability pub
- nueva def register_dynamic_cap
- nueva def register_provider
- nueva fn seed_id pub
- nueva mod shutdown
- nueva fn snapshot pub
- nueva mod topology
- nueva fn ttl_for_capability pub
- nueva def unregister_dynamic_cap
- nueva def unregister_provider
crates/core/ente-zero/src/graph/shutdown.rs
- nueva def SHUTDOWN_GRACE pub
- nueva fn cascade_shutdown pub
- nueva fn reap_during_shutdown
crates/core/ente-zero/src/graph/topology.rs
- nueva fn dfs_post
- nueva def topo_order
crates/core/ente-zero/src/main.rs
- nueva struct CliArgs
- nueva mod brain_glue
- nueva fn brain_introspect_path
- nueva mod bus
- nueva fn dispatch_graph_event
- nueva fn emit_death
- nueva mod events
- nueva fn feed_brain
- nueva mod graph
- nueva fn init_tracing
- nueva fn main
- nueva fn parse_args
- nueva fn primordial_loop
- nueva fn read_brain_snapshot
- nueva fn reap_until_empty
- nueva mod seed
- nueva fn spawn_audit_auto_flush
- nueva fn spawn_brain_introspect
- nueva fn spawn_echo_smoke_test
- nueva fn write_brain_snapshot
crates/core/ente-zero/src/seed.rs
- nueva def SEED_PATH_DEV
- nueva def SEED_PATH_PROD
- nueva fn load pub
- nueva fn load_from_snapshot
- nueva fn load_or_synthesize
- nueva fn make_card
- nueva fn optional_native_card
- nueva fn restart_supervision
- nueva fn synthesize_dev_seed
crates/modules/semantic_dht/minga-cli/src/commands.rs
- nueva struct IngestResult pub
- nueva def KEYPAIR_FILENAME pub
- nueva def REPO_DIRNAME pub
- nueva struct RepoStatus pub
- nueva fn cmd_ingest pub
- nueva fn cmd_init pub
- nueva fn cmd_listen pub
- nueva fn cmd_status pub
- nueva fn cmd_sync pub
- nueva fn cmd_watch pub
- nueva fn extract_peer_id
- nueva fn ingest_into_repo
- nueva fn initial_scan
- nueva fn is_relevant_event
- nueva fn is_rs_file
crates/modules/semantic_dht/minga-cli/src/error.rs
- nueva enum CliError pub
crates/modules/semantic_dht/minga-cli/src/main.rs
- nueva struct Cli
- nueva enum Command
- nueva fn main
- nueva fn prompt_passphrase
- nueva fn prompt_passphrase_with_confirm
- nueva fn run
crates/modules/semantic_dht/minga-cli/tests/cli_smoke.rs
- nueva fn ingest_persists_across_runs
- nueva fn ingest_persists_function_with_self_attestation
- nueva fn ingest_same_file_twice_is_idempotent
- nueva fn init_creates_keypair_and_repo
- nueva fn init_refuses_existing_non_empty_directory
- nueva fn status_shows_empty_state_after_init
- nueva fn status_with_wrong_passphrase_errors
crates/modules/semantic_dht/minga-cli/tests/watcher.rs
- nueva fn wait_until_mst_size
- nueva fn watcher_ignores_non_rs_files
- nueva fn watcher_ingests_new_file_after_creation
- nueva fn watcher_initial_scan_picks_up_existing_files
crates/modules/semantic_dht/minga-core/src/alpha.rs
- nueva def TAG_BINDER
- nueva def TAG_LEAF
- nueva def TAG_NO_LEAF
- nueva def TAG_REF_BOUND
- nueva def TAG_REF_FREE
- nueva fn collect_callable_binders
- nueva fn collect_field_pattern_binders
- nueva fn collect_match_pattern_binders
- nueva fn collect_pattern_binders
- nueva fn emit_binder_body
- nueva fn emit_binder_node
- nueva fn emit_identifier_ref
- nueva fn emit_leaf_marker
- nueva fn feed
- nueva fn feed_as_literal
- nueva fn feed_block
- nueva fn feed_callable
- nueva fn feed_callable_params
- nueva fn feed_default
- nueva fn feed_field_pattern
- nueva fn feed_for
- nueva fn feed_let
- nueva fn feed_match_arm
- nueva fn feed_match_pattern_split
- nueva fn feed_parameter
- nueva fn feed_pattern
- nueva fn hash_node_alpha pub
- nueva fn is_binder_identifier
- nueva fn is_binder_name
- nueva fn push_identifier_name
- nueva fn write_kind_and_field
- nueva fn write_str
crates/modules/semantic_dht/minga-core/src/ast.rs
- nueva struct SemanticNode pub
- nueva fn build
- nueva fn from_tree_sitter pub
crates/modules/semantic_dht/minga-core/src/attestation.rs
- nueva struct Attestation pub
- nueva enum AttestationError pub
- nueva struct AttestationStore pub
- nueva fn add pub
- nueva fn all pub
- nueva fn authors_of pub
- nueva fn create pub
- nueva fn fmt
- nueva fn get pub
- nueva fn is_empty pub
- nueva fn len pub
- nueva fn new pub
- nueva fn verify pub
crates/modules/semantic_dht/minga-core/src/cas.rs
- nueva struct ContentHash pub
- nueva fn as_bytes pub
- nueva fn fmt
- nueva fn hash_components pub
- nueva fn hash_node pub
- nueva fn write_str
crates/modules/semantic_dht/minga-core/src/identity.rs
- nueva def AES_NONCE_LEN
- nueva def ARGON2_SALT_LEN
- nueva struct Did pub
- nueva def KEYPAIR_HEADER_LEN
- nueva def KEYPAIR_MAGIC
- nueva def KEYPAIR_VERSION
- nueva struct Keypair pub
- nueva enum KeypairCryptoError pub
- nueva struct Signature pub
- nueva fn as_bytes pub
- nueva fn as_bytes pub
- nueva fn decrypt pub
- nueva fn derive_aes_key
- nueva fn did pub
- nueva fn encrypt pub
- nueva fn fmt
- nueva fn fmt
- nueva fn from_seed pub
- nueva fn generate pub
- nueva fn sign pub
- nueva fn verify pub
crates/modules/semantic_dht/minga-core/src/lib.rs
crates/modules/semantic_dht/minga-core/src/mst.rs
- nueva def H
- nueva type Item
- nueva struct Iter pub
- nueva struct Mst pub
- nueva struct MstDiff pub
- nueva struct NodeData
- nueva struct NodeProbe pub
- nueva enum Subtree
- nueva fn build_probe_index pub
- nueva fn collect_all
- nueva fn contains pub
- nueva fn contains_in
- nueva fn descend_left
- nueva fn diff pub
- nueva fn diff_subtrees
- nueva fn empty_subtree_hash pub
- nueva fn index_subtree
- nueva fn insert pub
- nueva fn insert_in
- nueva fn is_empty pub
- nueva fn is_empty pub
- nueva fn iter pub
- nueva fn len pub
- nueva fn len_of
- nueva fn level_of
- nueva fn merge_diff_sorted
- nueva fn new pub
- nueva fn next
- nueva fn root_hash pub
- nueva fn split_at
- nueva fn subtree_hash
- nueva fn total pub
crates/modules/semantic_dht/minga-core/src/parse.rs
- nueva enum ParseError pub
- nueva fn rust pub
crates/modules/semantic_dht/minga-core/src/store.rs
- nueva struct MemStore pub
- nueva trait NodeStore pub
- nueva struct StoredNode pub
- nueva fn contains
- nueva fn get
- nueva fn hash_stored pub
- nueva fn is_empty
- nueva fn iter
- nueva fn len
- nueva fn new pub
- nueva fn put
- nueva fn put_chunked
- nueva fn reconstruct
crates/modules/semantic_dht/minga-core/tests/alpha_invariants.rs
- nueva fn alpha_body_change_matters
- nueva fn alpha_closure_captures_outer_binding
- nueva fn alpha_closure_distinguishes_captured_vs_free
- nueva fn alpha_closure_param_rename_invariant
- nueva fn alpha_distinguishes_bound_vs_free
- nueva fn alpha_diverges_from_structural_under_rename
- nueva fn alpha_for_loop_var_rename_invariant
- nueva fn alpha_free_variable_identity_matters
- nueva fn alpha_function_name_matters
- nueva fn alpha_let_rename_invariant
- nueva fn alpha_match_arms_have_independent_scope
- nueva fn alpha_match_captured_pattern_rename_invariant
- nueva fn alpha_match_captured_range_changes_hash
- nueva fn alpha_match_constructor_distinguishes_arms
- nueva fn alpha_match_constructor_vs_binder
- nueva fn alpha_match_guard_binder_rename_invariant
- nueva fn alpha_match_guard_op_distinguishes
- nueva fn alpha_match_simple_arm_rename_invariant
- nueva fn alpha_match_struct_pattern_field_name_matters
- nueva fn alpha_match_struct_pattern_rename_invariant
- nueva fn alpha_match_tuple_struct_binder_rename_invariant
- nueva fn alpha_mut_pattern_rename_invariant
- nueva fn alpha_param_order_matters
- nueva fn alpha_param_rename_invariant
- nueva fn alpha_param_swap_with_rename_invariant
- nueva fn alpha_shadowing_let_invariant
- nueva fn alpha_signature_type_matters
- nueva fn alpha_tuple_destructure_position_matters
- nueva fn alpha_tuple_destructure_rename_invariant
crates/modules/semantic_dht/minga-core/tests/attestation_invariants.rs
- nueva fn authors_of_for_unknown_content_is_empty
- nueva fn ch
- nueva fn create_then_verify_succeeds
- nueva fn distinct_authors_distinct_signatures_same_content
- nueva fn kp
- nueva fn modifying_author_invalidates
- nueva fn modifying_content_invalidates
- nueva fn modifying_signature_invalidates
- nueva fn store_accepts_valid_attestation
- nueva fn store_is_idempotent_for_same_author_content
- nueva fn store_keeps_multiple_authors_per_content
- nueva fn store_rejects_invalid_signature
- nueva fn store_rejects_swapped_content
crates/modules/semantic_dht/minga-core/tests/cas_invariants.rs
- nueva fn body_change_breaks_hash
- nueva fn comment_invariant
- nueva fn order_matters
- nueva fn rename_breaks_hash_for_now
- nueva fn signature_change_breaks_hash
- nueva fn whitespace_invariant
crates/modules/semantic_dht/minga-core/tests/identity_invariants.rs
- nueva fn decrypt_rejects_invalid_format
- nueva fn decrypt_rejects_tampered_ciphertext
- nueva fn decrypt_with_wrong_passphrase_fails
- nueva fn did_display_uses_did_key_prefix
- nueva fn distinct_passphrases_produce_distinct_blobs
- nueva fn distinct_seeds_produce_distinct_dids
- nueva fn encrypt_decrypt_roundtrip_preserves_identity
- nueva fn generate_produces_unique_dids
- nueva fn keypair_debug_does_not_leak_private_key
- nueva fn keypair_from_seed_is_deterministic
- nueva fn kp
- nueva fn re_encrypting_same_keypair_produces_distinct_blobs
- nueva fn sign_verify_roundtrip
- nueva fn verify_fails_with_tampered_message
- nueva fn verify_fails_with_tampered_signature
- nueva fn verify_fails_with_wrong_did
- nueva fn verify_handles_invalid_did_bytes
crates/modules/semantic_dht/minga-core/tests/mst_invariants.rs
- nueva fn ch
- nueva fn mst_contains_after_many_inserts
- nueva fn mst_diff_apply_converges
- nueva fn mst_diff_disjoint_sets
- nueva fn mst_diff_history_independent
- nueva fn mst_diff_identical_is_empty
- nueva fn mst_diff_is_symmetric
- nueva fn mst_diff_one_empty_yields_other
- nueva fn mst_diff_output_is_sorted
- nueva fn mst_diff_partial_overlap
- nueva fn mst_diff_single_key_change
- nueva fn mst_empty
- nueva fn mst_history_independence
- nueva fn mst_insert_single
- nueva fn mst_iter_yields_sorted_keys
- nueva fn mst_levels_distribute_naturally
- nueva fn mst_no_duplicates_inflate_size
- nueva fn mst_root_hash_changes_with_size
- nueva fn mst_set_difference_changes_root
crates/modules/semantic_dht/minga-core/tests/serde_roundtrips.rs
- nueva fn attestation_roundtrip
- nueva fn attestation_roundtrip_preserves_verify
- nueva fn content_hash_roundtrip
- nueva fn did_roundtrip
- nueva fn empty_collections_serialize_compactly
- nueva fn malformed_bytes_fail_decode
- nueva fn node_probe_roundtrip
- nueva fn roundtrip
- nueva fn signature_roundtrip
- nueva fn signature_roundtrip_preserves_verify
- nueva fn stored_node_roundtrip
- nueva fn stored_node_with_leaf_roundtrip
crates/modules/semantic_dht/minga-core/tests/store_invariants.rs
- nueva fn find_first_kind
- nueva fn store_dedup_shared_subtree
- nueva fn store_hash_matches_cas
- nueva fn store_idempotent_put
- nueva fn store_multiple_files_share_common_constants
- nueva fn store_round_trip_preserves_tree
- nueva fn store_subtree_resolvable_independently
- nueva fn store_unknown_hash_is_none
crates/modules/semantic_dht/minga-p2p/src/async_driver.rs
- nueva enum AsyncSyncError pub
- nueva def MAX_FRAME_SIZE
- nueva fn recv_frame
- nueva fn run_sync_async pub
- nueva fn send_frame
crates/modules/semantic_dht/minga-p2p/src/harness.rs
crates/modules/semantic_dht/minga-p2p/src/lib.rs
crates/modules/semantic_dht/minga-p2p/src/message.rs
crates/modules/semantic_dht/minga-p2p/src/network.rs
- nueva enum Command
- nueva struct DiscoveredPeer pub
- nueva def IDENTIFY_PROTOCOL
- nueva struct LibP2pNode pub
- nueva struct MingaBehaviour
- nueva enum NodeError pub
- nueva def SYNC_PROTOCOL pub
- nueva fn add_dht_peer pub
- nueva fn dial pub
- nueva fn find_closest_peers pub
- nueva fn find_providers pub
- nueva fn listen pub
- nueva fn new pub
- nueva fn start_providing pub
crates/modules/semantic_dht/minga-p2p/src/peer.rs
- nueva struct MingaPeer pub
- nueva enum PeerOpenError pub
- nueva struct PeerState
- nueva enum PeerSyncError pub
- nueva fn add_dht_peer pub
- nueva fn announce_provider pub
- nueva fn dial pub
- nueva fn find_closest_peers pub
- nueva fn find_providers pub
- nueva fn flush pub
- nueva fn handle_incoming
- nueva fn ingest pub
- nueva fn ingest_attestation pub
- nueva fn listen pub
- nueva fn merge_back
- nueva fn merge_into_state
- nueva fn new pub
- nueva fn open pub
- nueva fn peer_id pub
- nueva fn run_passive_accept pub
- nueva fn snapshot pub
- nueva fn snapshot_session
- nueva fn sync_with pub
crates/modules/semantic_dht/minga-p2p/src/session.rs
- nueva struct SyncSession pub
- nueva fn attestations pub
- nueva fn handle pub
- nueva def hello_payload
- nueva fn into_parts pub
- nueva fn is_done pub
- nueva fn local_did pub
- nueva fn maybe_done
- nueva fn mst pub
- nueva fn new pub
- nueva fn peer_did pub
- nueva fn process_probe
- nueva fn rejected_attests pub
- nueva fn rejected_delivers pub
- nueva fn rejected_hellos pub
- nueva fn self_nonce pub
- nueva fn should_probe
- nueva fn start pub
- nueva fn store pub
- nueva fn without_attestations pub
crates/modules/semantic_dht/minga-p2p/tests/async_driver_invariants.rs
- nueva fn async_sync_disjoint_sets_merge
- nueva fn async_sync_identical_repos
- nueva fn async_sync_one_empty_pulls_everything
- nueva fn async_sync_propagates_attestations
- nueva fn async_sync_propagates_authenticated_identity
- nueva fn build_repo
- nueva fn kp
crates/modules/semantic_dht/minga-p2p/tests/kad_discovery.rs
- nueva fn identify_auto_populates_kad_routing_table
- nueva fn kad_discovery_then_sync
- nueva fn kad_three_node_discovery_via_rendezvous
- nueva fn kad_two_node_basic_discovery
- nueva fn singleton
crates/modules/semantic_dht/minga-p2p/tests/kad_providers.rs
- nueva fn kp
- nueva fn minga_peer_ingest_auto_announces_provider
- nueva fn provider_announce_and_lookup_two_nodes
- nueva fn provider_lookup_returns_empty_for_unknown_content
crates/modules/semantic_dht/minga-p2p/tests/libp2p_integration.rs
- nueva fn build_repo
- nueva fn kp
- nueva fn libp2p_sync_two_peers_over_tcp
- nueva fn libp2p_sync_with_attestations
crates/modules/semantic_dht/minga-p2p/tests/passive_listener.rs
- nueva fn kp
- nueva fn passive_listener_propagates_attestations
- nueva fn passive_listener_serves_two_consecutive_peers
- nueva fn singleton_repo
- nueva fn sync_with_retry
crates/modules/semantic_dht/minga-p2p/tests/persistent_peer.rs
- nueva fn _session_marker
- nueva fn ingest_attestation_persists_across_restart
- nueva fn ingest_multiple_authors_for_same_content_persist
- nueva fn ingest_persists_across_restart
- nueva fn kp
- nueva fn open_creates_empty_repo_at_new_path
- nueva fn root_hash_stable_across_restart
- nueva fn sync_into_persistent_peer_survives_restart
crates/modules/semantic_dht/minga-p2p/tests/sync_invariants.rs
- nueva fn _signature_marker
- nueva fn build_repo
- nueva fn build_repo_with_attests
- nueva fn cas_hash_node_equals_hash_stored
- nueva fn hello_payload
- nueva fn kp
- nueva fn sync_accepts_well_formed_deliver
- nueva fn sync_attest_push_before_hello_is_rejected
- nueva fn sync_attest_push_count_in_stats
- nueva fn sync_attestations_about_remote_content
- nueva fn sync_attestations_are_idempotent_across_runs
- nueva fn sync_attestations_are_verified_at_receiver
- nueva fn sync_both_empty_terminates
- nueva fn sync_captures_peer_did_after_valid_hello
- nueva fn sync_disjoint_sets_merge
- nueva fn sync_idempotent_after_convergence
- nueva fn sync_identical_is_noop
- nueva fn sync_merges_multiple_authors_for_shared_content
- nueva fn sync_one_empty_pulls_everything
- nueva fn sync_partial_overlap_converges
- nueva fn sync_proceeds_after_valid_hello_following_rejection
- nueva fn sync_propagates_attestations_for_owned_content
- nueva fn sync_rejects_hello_signed_over_different_root
- nueva fn sync_rejects_hello_with_swapped_did
- nueva fn sync_rejects_hello_with_tampered_signature
- nueva fn sync_rejects_replay_of_hello_from_different_session
- nueva fn sync_rejects_tampered_deliver
- nueva fn sync_subtree_short_circuit_skips_shared_branches
- nueva fn sync_three_way_via_pairwise_runs
- nueva fn sync_transitive_children_pulled
crates/modules/semantic_dht/minga-p2p/tests/wire_roundtrips.rs
- nueva fn attest_push_roundtrip
- nueva fn deliver_roundtrip
- nueva fn done_roundtrip
- nueva fn empty_bytes_decode_to_error
- nueva fn fetch_roundtrip
- nueva fn hello_roundtrip
- nueva fn kp
- nueva fn malformed_bytes_decode_to_error
- nueva fn message_decode_after_encode_preserves_signatures
- nueva fn probe_req_roundtrip
- nueva fn probe_res_empty_roundtrip
- nueva fn probe_res_with_probe_roundtrip
- nueva fn roundtrip
crates/modules/semantic_dht/minga-store/src/attestation_store.rs
- nueva struct SledAttestationStore pub
- nueva fn add pub
- nueva fn authors_of pub
- nueva fn compose_key
- nueva fn flush pub
- nueva fn get pub
- nueva fn is_empty pub
- nueva fn iter pub
- nueva fn len pub
- nueva fn open_tree pub
crates/modules/semantic_dht/minga-store/src/error.rs
- nueva enum StoreError pub
crates/modules/semantic_dht/minga-store/src/keypair_file.rs
- nueva enum KeypairFileError pub
- nueva fn load pub
- nueva fn save pub
crates/modules/semantic_dht/minga-store/src/lib.rs
- nueva mod attestation_store pub
- nueva mod error pub
- nueva mod keypair_file pub
- nueva mod mst_store pub
- nueva mod node_store pub
- nueva mod repo pub
crates/modules/semantic_dht/minga-store/src/mst_store.rs
- nueva struct SledMstStore pub
- nueva fn contains pub
- nueva fn flush pub
- nueva fn insert pub
- nueva fn is_empty pub
- nueva fn iter pub
- nueva fn len pub
- nueva fn open_tree pub
- nueva fn to_in_memory pub
crates/modules/semantic_dht/minga-store/src/node_store.rs
- nueva struct SledNodeStore pub
- nueva fn contains pub
- nueva fn flush pub
- nueva fn get pub
- nueva fn is_empty pub
- nueva fn iter pub
- nueva fn len pub
- nueva fn open_tree pub
- nueva fn put pub
- nueva fn put_chunked pub
- nueva fn reconstruct pub
crates/modules/semantic_dht/minga-store/src/repo.rs
- nueva struct PersistentRepo pub
- nueva fn flush pub
- nueva fn open pub
crates/modules/semantic_dht/minga-store/tests/attestation_store_persistence.rs
- nueva fn add_then_get_roundtrips
- nueva fn ch
- nueva fn data_persists_across_reopen
- nueva fn idempotent_per_author_and_content
- nueva fn invalid_signature_rejected
- nueva fn kp
- nueva fn multiple_authors_per_content
- nueva fn open_store
- nueva fn unknown_content_returns_empty
crates/modules/semantic_dht/minga-store/tests/keypair_file_persistence.rs
- nueva fn file_size_is_compact
- nueva fn load_missing_file_errors
- nueva fn load_with_wrong_passphrase_errors
- nueva fn save_overwrites_existing
- nueva fn save_then_load_preserves_identity
crates/modules/semantic_dht/minga-store/tests/mst_store_persistence.rs
- nueva fn ch
- nueva fn data_persists_across_reopen
- nueva fn insert_and_contains
- nueva fn iter_returns_sorted_keys
- nueva fn open_store
- nueva fn order_independent_persistence
- nueva fn root_hash_matches_in_memory_mst
crates/modules/semantic_dht/minga-store/tests/node_store_persistence.rs
- nueva fn data_persists_across_reopen
- nueva fn open_store
- nueva fn put_chunked_accepts_correct_hash
- nueva fn put_chunked_rejects_hash_mismatch
- nueva fn put_hash_matches_cas
- nueva fn put_is_idempotent
- nueva fn round_trip_preserves_tree
- nueva fn shared_subtrees_dedup
- nueva fn unknown_hash_returns_none
crates/modules/semantic_dht/minga-store/tests/repo_integration.rs
crates/modules/ui_engine/libs/core/src/lib.rs
- nueva trait DataProvider pub
- nueva enum DisplayType pub
- nueva struct EntityNode pub
- nueva struct LayerConfig pub
- nueva struct LayerParam pub
- nueva enum LayoutDirection pub
- nueva enum LayoutMode pub
- nueva enum ModuloTipo pub
- nueva struct NodeId pub
- nueva fn as_str pub
- nueva fn default
- nueva fn default
- nueva fn default
- nueva fn flex_weight pub
- nueva fn fmt
- nueva fn from_kind pub
- nueva fn from_layer pub
- nueva fn from_str pub
- nueva fn from_str pub
- nueva fn get_data
- nueva fn get_param pub
- nueva fn layout_direction pub
- nueva fn load_or_default pub
- nueva fn modulo_tipo pub
- nueva fn new pub
- nueva fn serialize_json pub
crates/modules/ui_engine/libs/providers/fs/src/lib.rs
- nueva struct FileDataProvider pub
- nueva def PROVIDER_ID pub
- nueva fn get_read_stream
- nueva fn get_write_stream
- nueva fn list_children
- nueva fn provider_id
crates/modules/ui_engine/libs/providers/sqlite/src/lib.rs
- nueva def PROVIDER_ID pub
- nueva struct SqliteDataProvider pub
- nueva fn get_read_stream
- nueva fn get_write_stream
- nueva fn list_children
- nueva fn new pub
- nueva fn provider_id
crates/modules/ui_engine/libs/theme/src/lib.rs
- nueva struct Theme pub
- nueva fn all pub
- nueva fn aurora pub
- nueva fn by_name pub
- nueva fn flat_dark pub
- nueva fn global pub
- nueva fn high_contrast pub
- nueva fn install_default pub
- nueva fn nebula pub
- nueva fn next_after pub
- nueva fn set pub
- nueva fn solarized_light pub
- nueva fn sunset pub
crates/modules/ui_engine/widgets/container_core/src/lib.rs
- nueva struct ChildSlot pub
crates/modules/ui_engine/widgets/splitter/src/lib.rs
- nueva def DIVIDER_THICKNESS
- nueva struct DragState
- nueva def MIN_FLEX
- nueva struct SplitContainer pub
- nueva enum SplitEvent pub
- nueva fn children pub
- nueva fn continue_drag
- nueva fn direction pub
- nueva fn end_drag
- nueva fn main_axis
- nueva fn main_axis_pt
- nueva fn new pub
- nueva fn render
- nueva fn set_children pub
- nueva fn set_direction pub
- nueva fn start_drag
crates/modules/ui_engine/widgets/tabs/src/lib.rs
- nueva def TAB_HEADER_HEIGHT
- nueva struct TabContainer pub
- nueva enum TabsEvent pub
- nueva fn active_id pub
- nueva fn active_index
- nueva fn new pub
- nueva fn on_tab_click
- nueva fn render
- nueva fn set_active pub
- nueva fn set_children pub
crates/modules/ui_engine/widgets/text_input/src/lib.rs
- nueva struct TextInput pub
- nueva enum TextInputEvent pub
- nueva fn focus_handle
- nueva fn handle_key_down
- nueva fn new pub
- nueva fn render
- nueva fn request_focus pub
- nueva fn set_text pub
- nueva fn text pub
- nueva fn with_placeholder pub
crates/modules/ui_engine/widgets/tiled/src/lib.rs
- nueva struct DragState
- nueva def TILE_GAP
- nueva def TITLE_BAR_HEIGHT
- nueva struct TiledContainer pub
- nueva enum TiledEvent pub
- nueva fn children pub
- nueva fn end_drag
- nueva fn new pub
- nueva fn render
- nueva fn set_children pub
- nueva fn start_drag
- nueva fn update_hover
crates/modules/ui_engine/widgets/tree/src/lib.rs
- nueva def CHEVRON_PX
- nueva def INDENT_PX
- nueva def ROW_HEIGHT
- nueva struct RowId pub
- nueva enum RowKind pub
- nueva enum TreeEvent pub
- nueva struct TreeRow pub
- nueva struct TreeView pub
- nueva fn active_id pub
- nueva fn add_selected pub
- nueva fn as_str pub
- nueva fn default
- nueva fn fmt
- nueva fn from
- nueva fn from
- nueva fn handle_chevron_click
- nueva fn handle_right_click
- nueva fn handle_row_click
- nueva fn new pub
- nueva fn new pub
- nueva fn remove_selected pub
- nueva fn render
- nueva fn render_row
- nueva fn rows pub
- nueva fn set_active pub
- nueva fn set_rows pub
- nueva fn set_selected pub
176 archivos · +34845 −0
- .gitignore +4 −0
- Cargo.lock +10057 −0
- Cargo.toml +175 −0
- crates/apps/database_explorer/Cargo.toml +13 −0
- crates/apps/database_explorer/src/lib.rs +284 −0
- crates/apps/file_explorer/Cargo.toml +14 −0
- crates/apps/file_explorer/src/lib.rs +786 −0
- crates/apps/image_viewer/Cargo.toml +11 −0
- crates/apps/image_viewer/src/lib.rs +148 −0
- crates/apps/text_viewer/Cargo.toml +14 −0
- crates/apps/text_viewer/src/lib.rs +285 −0
- crates/apps/yahweh-shell/Cargo.toml +31 −0
- crates/apps/yahweh-shell/src/hot_reload.rs +108 −0
- crates/apps/yahweh-shell/src/layout_host.rs +576 −0
- crates/apps/yahweh-shell/src/layout_model.rs +140 −0
- crates/apps/yahweh-shell/src/main.rs +63 −0
- crates/apps/yahweh-shell/src/managed_tree.rs +287 −0
- crates/apps/yahweh-shell/src/persister.rs +52 −0
- crates/apps/yahweh-shell/src/status_panel.rs +343 −0
- crates/core/ente-binfmt-compat/Cargo.toml +15 −0
- crates/core/ente-binfmt-compat/src/main.rs +109 −0
- crates/core/ente-brain/Cargo.toml +23 −0
- crates/core/ente-brain/examples/brainctl.rs +234 −0
- crates/core/ente-brain/schema/rule.k +167 −0
- crates/core/ente-brain/src/audit.rs +550 −0
- crates/core/ente-brain/src/autopromote.rs +102 −0
- crates/core/ente-brain/src/crystallize.rs +244 −0
- crates/core/ente-brain/src/dispatch.rs +73 −0
- crates/core/ente-brain/src/engine.rs +399 −0
- crates/core/ente-brain/src/introspect.rs +476 −0
- crates/core/ente-brain/src/lib.rs +38 −0
- crates/core/ente-brain/src/loader.rs +172 −0
- crates/core/ente-brain/src/metrics.rs +175 −0
- crates/core/ente-brain/src/observer.rs +453 −0
- crates/core/ente-brain/src/rules.rs +206 −0
- crates/core/ente-bus/Cargo.toml +22 −0
- crates/core/ente-bus/examples/busctl.rs +52 −0
- crates/core/ente-bus/src/lib.rs +228 −0
- crates/core/ente-card/Cargo.toml +11 −0
- crates/core/ente-card/schema/card.k +178 −0
- crates/core/ente-card/src/lib.rs +326 −0
- crates/core/ente-cas/Cargo.toml +11 −0
- crates/core/ente-cas/src/lib.rs +120 −0
- crates/core/ente-echo/Cargo.toml +22 −0
- crates/core/ente-echo/src/lib.rs +18 −0
- crates/core/ente-echo/src/main.rs +46 −0
- crates/core/ente-hostnamed-compat/Cargo.toml +21 −0
- crates/core/ente-hostnamed-compat/src/main.rs +340 −0
- crates/core/ente-journald-compat/Cargo.toml +25 −0
- crates/core/ente-journald-compat/src/journalctl.rs +289 −0
- crates/core/ente-journald-compat/src/main.rs +218 −0
- crates/core/ente-kernel/Cargo.toml +14 −0
- crates/core/ente-kernel/src/lib.rs +11 −0
- crates/core/ente-kernel/src/sigchld.rs +66 −0
- crates/core/ente-kernel/src/surface.rs +86 −0
- crates/core/ente-kernel/src/uevent.rs +146 −0
- crates/core/ente-localed-compat/Cargo.toml +19 −0
- crates/core/ente-localed-compat/src/main.rs +219 −0
- crates/core/ente-logind-compat/Cargo.toml +19 −0
- crates/core/ente-logind-compat/src/main.rs +249 −0
- crates/core/ente-machined-compat/Cargo.toml +19 −0
- crates/core/ente-machined-compat/src/main.rs +186 −0
- crates/core/ente-notify-compat/Cargo.toml +20 −0
- crates/core/ente-notify-compat/src/main.rs +160 −0
- crates/core/ente-policy-provider/Cargo.toml +20 −0
- crates/core/ente-policy-provider/src/main.rs +221 −0
- crates/core/ente-polkit-compat/Cargo.toml +19 −0
- crates/core/ente-polkit-compat/src/main.rs +262 −0
- crates/core/ente-resolved-compat/Cargo.toml +20 −0
- crates/core/ente-resolved-compat/src/main.rs +210 −0
- crates/core/ente-snapshot/Cargo.toml +13 −0
- crates/core/ente-snapshot/src/lib.rs +61 −0
- crates/core/ente-soma/Cargo.toml +14 −0
- crates/core/ente-soma/src/lib.rs +362 −0
- crates/core/ente-systemd1-compat/Cargo.toml +19 −0
- crates/core/ente-systemd1-compat/src/main.rs +280 −0
- crates/core/ente-timedated-compat/Cargo.toml +19 −0
- crates/core/ente-timedated-compat/src/main.rs +182 −0
- crates/core/ente-timer-compat/Cargo.toml +21 −0
- crates/core/ente-timer-compat/src/main.rs +228 −0
- crates/core/ente-tmpfiles-compat/Cargo.toml +17 −0
- crates/core/ente-tmpfiles-compat/src/main.rs +281 −0
- crates/core/ente-wasm/Cargo.toml +14 −0
- crates/core/ente-wasm/src/lib.rs +118 −0
- crates/core/ente-zero/Cargo.toml +33 −0
- crates/core/ente-zero/src/brain_glue.rs +129 −0
- crates/core/ente-zero/src/bus.rs +143 −0
- crates/core/ente-zero/src/events.rs +58 −0
- crates/core/ente-zero/src/graph/bus_mediator.rs +240 −0
- crates/core/ente-zero/src/graph/capabilities.rs +95 −0
- crates/core/ente-zero/src/graph/devices.rs +60 −0
- crates/core/ente-zero/src/graph/lifecycle.rs +154 −0
- crates/core/ente-zero/src/graph/mod.rs +225 −0
- crates/core/ente-zero/src/graph/shutdown.rs +100 −0
- crates/core/ente-zero/src/graph/topology.rs +35 −0
- crates/core/ente-zero/src/main.rs +506 −0
- crates/core/ente-zero/src/seed.rs +245 −0
- crates/modules/semantic_dht/minga-cli/Cargo.toml +26 −0
- crates/modules/semantic_dht/minga-cli/src/commands.rs +246 −0
- crates/modules/semantic_dht/minga-cli/src/error.rs +43 −0
- crates/modules/semantic_dht/minga-cli/src/lib.rs +15 −0
- crates/modules/semantic_dht/minga-cli/src/main.rs +141 −0
- crates/modules/semantic_dht/minga-cli/tests/cli_smoke.rs +110 −0
- crates/modules/semantic_dht/minga-cli/tests/watcher.rs +129 −0
- crates/modules/semantic_dht/minga-core/Cargo.toml +23 −0
- crates/modules/semantic_dht/minga-core/src/alpha.rs +515 −0
- crates/modules/semantic_dht/minga-core/src/ast.rs +52 −0
- crates/modules/semantic_dht/minga-core/src/attestation.rs +127 −0
- crates/modules/semantic_dht/minga-core/src/cas.rs +95 −0
- crates/modules/semantic_dht/minga-core/src/identity.rs +223 −0
- crates/modules/semantic_dht/minga-core/src/lib.rs +23 −0
- crates/modules/semantic_dht/minga-core/src/mst.rs +457 −0
- crates/modules/semantic_dht/minga-core/src/parse.rs +25 −0
- crates/modules/semantic_dht/minga-core/src/store.rs +144 −0
- crates/modules/semantic_dht/minga-core/tests/alpha_invariants.rs +252 −0
- crates/modules/semantic_dht/minga-core/tests/attestation_invariants.rs +136 −0
- crates/modules/semantic_dht/minga-core/tests/cas_invariants.rs +64 −0
- crates/modules/semantic_dht/minga-core/tests/identity_invariants.rs +172 −0
- crates/modules/semantic_dht/minga-core/tests/mst_invariants.rs +347 −0
- crates/modules/semantic_dht/minga-core/tests/serde_roundtrips.rs +134 −0
- crates/modules/semantic_dht/minga-core/tests/store_invariants.rs +129 −0
- crates/modules/semantic_dht/minga-p2p/Cargo.toml +24 −0
- crates/modules/semantic_dht/minga-p2p/src/async_driver.rs +100 −0
- crates/modules/semantic_dht/minga-p2p/src/harness.rs +89 −0
- crates/modules/semantic_dht/minga-p2p/src/lib.rs +26 −0
- crates/modules/semantic_dht/minga-p2p/src/message.rs +94 −0
- crates/modules/semantic_dht/minga-p2p/src/network.rs +282 −0
- crates/modules/semantic_dht/minga-p2p/src/peer.rs +313 −0
- crates/modules/semantic_dht/minga-p2p/src/session.rs +461 −0
- crates/modules/semantic_dht/minga-p2p/tests/async_driver_invariants.rs +161 −0
- crates/modules/semantic_dht/minga-p2p/tests/kad_discovery.rs +189 −0
- crates/modules/semantic_dht/minga-p2p/tests/kad_providers.rs +98 −0
- crates/modules/semantic_dht/minga-p2p/tests/libp2p_integration.rs +161 −0
- crates/modules/semantic_dht/minga-p2p/tests/passive_listener.rs +128 −0
- crates/modules/semantic_dht/minga-p2p/tests/persistent_peer.rs +239 −0
- crates/modules/semantic_dht/minga-p2p/tests/sync_invariants.rs +798 −0
- crates/modules/semantic_dht/minga-p2p/tests/wire_roundtrips.rs +128 −0
- crates/modules/semantic_dht/minga-store/Cargo.toml +18 −0
- crates/modules/semantic_dht/minga-store/src/attestation_store.rs +83 −0
- crates/modules/semantic_dht/minga-store/src/error.rs +16 −0
- crates/modules/semantic_dht/minga-store/src/keypair_file.rs +41 −0
- crates/modules/semantic_dht/minga-store/src/lib.rs +36 −0
- crates/modules/semantic_dht/minga-store/src/mst_store.rs +74 −0
- crates/modules/semantic_dht/minga-store/src/node_store.rs +134 −0
- crates/modules/semantic_dht/minga-store/src/repo.rs +41 −0
- crates/modules/semantic_dht/minga-store/tests/attestation_store_persistence.rs +113 −0
- crates/modules/semantic_dht/minga-store/tests/keypair_file_persistence.rs +67 −0
- crates/modules/semantic_dht/minga-store/tests/mst_store_persistence.rs +119 −0
- crates/modules/semantic_dht/minga-store/tests/node_store_persistence.rs +145 −0
- crates/modules/semantic_dht/minga-store/tests/repo_integration.rs +104 −0
- crates/modules/semantic_dht/minga-vfs/Cargo.toml +10 −0
- crates/modules/semantic_dht/minga-vfs/src/lib.rs +2 −0
- crates/modules/ui_engine/libs/bus/Cargo.toml +9 −0
- crates/modules/ui_engine/libs/bus/src/lib.rs +44 −0
- crates/modules/ui_engine/libs/core/Cargo.toml +12 −0
- crates/modules/ui_engine/libs/core/src/lib.rs +266 −0
- crates/modules/ui_engine/libs/providers/fs/Cargo.toml +12 −0
- crates/modules/ui_engine/libs/providers/fs/src/lib.rs +67 −0
- crates/modules/ui_engine/libs/providers/sqlite/Cargo.toml +12 −0
- crates/modules/ui_engine/libs/providers/sqlite/src/lib.rs +118 −0
- crates/modules/ui_engine/libs/theme/Cargo.toml +9 −0
- crates/modules/ui_engine/libs/theme/src/lib.rs +334 −0
- crates/modules/ui_engine/widgets/container_core/Cargo.toml +10 −0
- crates/modules/ui_engine/widgets/container_core/src/lib.rs +38 −0
- crates/modules/ui_engine/widgets/splitter/Cargo.toml +12 −0
- crates/modules/ui_engine/widgets/splitter/src/lib.rs +362 −0
- crates/modules/ui_engine/widgets/tabs/Cargo.toml +12 −0
- crates/modules/ui_engine/widgets/tabs/src/lib.rs +192 −0
- crates/modules/ui_engine/widgets/text_input/Cargo.toml +10 −0
- crates/modules/ui_engine/widgets/text_input/src/lib.rs +156 −0
- crates/modules/ui_engine/widgets/tiled/Cargo.toml +12 −0
- crates/modules/ui_engine/widgets/tiled/src/lib.rs +327 −0
- crates/modules/ui_engine/widgets/tree/Cargo.toml +10 −0
- crates/modules/ui_engine/widgets/tree/src/lib.rs +415 −0
- rust-toolchain.toml +3 −0
- shared_wit/protocol.wit +109 −0
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..113ac98
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,4 @@
+/target
+**/*.rs.bk
+Cargo.lock.bak
+.DS_Store
diff --git a/Cargo.lock b/Cargo.lock
new file mode 100644
index 0000000..2bc8f33
--- /dev/null
+++ b/Cargo.lock
@@ -0,0 +1,10057 @@
+# This file is automatically @generated by Cargo.
+# It is not intended for manual editing.
+version = 4
+
+[[package]]
+name = "adler2"
+version = "2.0.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "320119579fcad9c21884f5c4861d16174d0e06250625266f50fe6898340abefa"
+
+[[package]]
+name = "aead"
+version = "0.5.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d122413f284cf2d62fb1b7db97e02edb8cda96d769b16e443a4f6195e35662b0"
+dependencies = [
+ "crypto-common",
+ "generic-array",
+]
+
+[[package]]
+name = "aes"
+version = "0.8.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b169f7a6d4742236a0a00c541b845991d0ac43e546831af1249753ab4c3aa3a0"
+dependencies = [
+ "cfg-if",
+ "cipher",
+ "cpufeatures 0.2.17",
+ "zeroize",
+]
+
+[[package]]
+name = "aes-gcm"
+version = "0.10.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "831010a0f742e1209b3bcea8fab6a8e149051ba6099432c8cb2cc117dec3ead1"
+dependencies = [
+ "aead",
+ "aes",
+ "cipher",
+ "ctr",
+ "ghash",
+ "subtle",
+]
+
+[[package]]
+name = "ahash"
+version = "0.8.12"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5a15f179cd60c4584b8a8c596927aadc462e27f2ca70c04e0071964a73ba7a75"
+dependencies = [
+ "cfg-if",
+ "const-random",
+ "once_cell",
+ "version_check",
+ "zerocopy",
+]
+
+[[package]]
+name = "aho-corasick"
+version = "1.1.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ddd31a130427c27518df266943a5308ed92d4b226cc639f5a8f1002816174301"
+dependencies = [
+ "memchr",
+]
+
+[[package]]
+name = "aligned"
+version = "0.4.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ee4508988c62edf04abd8d92897fca0c2995d907ce1dfeaf369dac3716a40685"
+dependencies = [
+ "as-slice",
+]
+
+[[package]]
+name = "aligned-vec"
+version = "0.6.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "dc890384c8602f339876ded803c97ad529f3842aba97f6392b3dba0dd171769b"
+dependencies = [
+ "equator",
+]
+
+[[package]]
+name = "anstream"
+version = "1.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "824a212faf96e9acacdbd09febd34438f8f711fb84e09a8916013cd7815ca28d"
+dependencies = [
+ "anstyle",
+ "anstyle-parse",
+ "anstyle-query",
+ "anstyle-wincon",
+ "colorchoice",
+ "is_terminal_polyfill",
+ "utf8parse",
+]
+
+[[package]]
+name = "anstyle"
+version = "1.0.14"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "940b3a0ca603d1eade50a4846a2afffd5ef57a9feac2c0e2ec2e14f9ead76000"
+
+[[package]]
+name = "anstyle-parse"
+version = "1.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "52ce7f38b242319f7cabaa6813055467063ecdc9d355bbb4ce0c68908cd8130e"
+dependencies = [
+ "utf8parse",
+]
+
+[[package]]
+name = "anstyle-query"
+version = "1.1.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "40c48f72fd53cd289104fc64099abca73db4166ad86ea0b4341abe65af83dadc"
+dependencies = [
+ "windows-sys 0.61.2",
+]
+
+[[package]]
+name = "anstyle-wincon"
+version = "3.0.11"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "291e6a250ff86cd4a820112fb8898808a366d8f9f58ce16d1f538353ad55747d"
+dependencies = [
+ "anstyle",
+ "once_cell_polyfill",
+ "windows-sys 0.61.2",
+]
+
+[[package]]
+name = "anyhow"
+version = "1.0.102"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7f202df86484c868dbad7eaa557ef785d5c66295e41b460ef922eca0723b842c"
+
+[[package]]
+name = "ar_archive_writer"
+version = "0.5.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7eb93bbb63b9c227414f6eb3a0adfddca591a8ce1e9b60661bb08969b87e340b"
+dependencies = [
+ "object",
+]
+
+[[package]]
+name = "arbitrary"
+version = "1.4.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c3d036a3c4ab069c7b410a2ce876bd74808d2d0888a82667669f8e783a898bf1"
+
+[[package]]
+name = "arg_enum_proc_macro"
+version = "0.3.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0ae92a5119aa49cdbcf6b9f893fe4e1d98b04ccbf82ee0584ad948a44a734dea"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.117",
+]
+
+[[package]]
+name = "argon2"
+version = "0.5.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3c3610892ee6e0cbce8ae2700349fcf8f98adb0dbfbee85aec3c9179d29cc072"
+dependencies = [
+ "base64ct",
+ "blake2",
+ "cpufeatures 0.2.17",
+ "password-hash",
+]
+
+[[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 = "as-raw-xcb-connection"
+version = "1.0.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "175571dd1d178ced59193a6fc02dde1b972eb0bc56c892cde9beeceac5bf0f6b"
+
+[[package]]
+name = "as-slice"
+version = "0.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "516b6b4f0e40d50dcda9365d53964ec74560ad4284da2e7fc97122cd83174516"
+dependencies = [
+ "stable_deref_trait",
+]
+
+[[package]]
+name = "ash"
+version = "0.38.0+1.3.281"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0bb44936d800fea8f016d7f2311c6a4f97aebd5dc86f09906139ec848cf3a46f"
+dependencies = [
+ "libloading",
+]
+
+[[package]]
+name = "ash-window"
+version = "0.13.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "52bca67b61cb81e5553babde81b8211f713cb6db79766f80168f3e5f40ea6c82"
+dependencies = [
+ "ash",
+ "raw-window-handle",
+ "raw-window-metal",
+]
+
+[[package]]
+name = "ashpd"
+version = "0.11.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d2f3f79755c74fd155000314eb349864caa787c6592eace6c6882dad873d9c39"
+dependencies = [
+ "async-fs",
+ "async-net",
+ "enumflags2",
+ "futures-channel",
+ "futures-util",
+ "rand 0.9.4",
+ "serde",
+ "serde_repr",
+ "url",
+ "wayland-backend",
+ "wayland-client",
+ "wayland-protocols 0.32.12",
+ "zbus 5.15.0",
+]
+
+[[package]]
+name = "ashpd"
+version = "0.12.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "33a3c86f3fd70c0ffa500ed189abfa90b5a52398a45d5dc372fcc38ebeb7a645"
+dependencies = [
+ "async-fs",
+ "async-net",
+ "enumflags2",
+ "futures-channel",
+ "futures-util",
+ "rand 0.9.4",
+ "serde",
+ "serde_repr",
+ "url",
+ "zbus 5.15.0",
+]
+
+[[package]]
+name = "asn1-rs"
+version = "0.7.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "56624a96882bb8c26d61312ae18cb45868e5a9992ea73c58e45c3101e56a1e60"
+dependencies = [
+ "asn1-rs-derive",
+ "asn1-rs-impl",
+ "displaydoc",
+ "nom 7.1.3",
+ "num-traits",
+ "rusticata-macros",
+ "thiserror 2.0.18",
+ "time",
+]
+
+[[package]]
+name = "asn1-rs-derive"
+version = "0.6.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3109e49b1e4909e9db6515a30c633684d68cdeaa252f215214cb4fa1a5bfee2c"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.117",
+ "synstructure",
+]
+
+[[package]]
+name = "asn1-rs-impl"
+version = "0.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7b18050c2cd6fe86c3a76584ef5e0baf286d038cda203eb6223df2cc413565f7"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.117",
+]
+
+[[package]]
+name = "async-broadcast"
+version = "0.7.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "435a87a52755b8f27fcf321ac4f04b2802e337c8c4872923137471ec39c37532"
+dependencies = [
+ "event-listener 5.4.1",
+ "event-listener-strategy",
+ "futures-core",
+ "pin-project-lite",
+]
+
+[[package]]
+name = "async-channel"
+version = "1.9.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "81953c529336010edd6d8e358f886d9581267795c61b19475b71314bffa46d35"
+dependencies = [
+ "concurrent-queue",
+ "event-listener 2.5.3",
+ "futures-core",
+]
+
+[[package]]
+name = "async-channel"
+version = "2.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "924ed96dd52d1b75e9c1a3e6275715fd320f5f9439fb5a4a11fa51f4221158d2"
+dependencies = [
+ "concurrent-queue",
+ "event-listener-strategy",
+ "futures-core",
+ "pin-project-lite",
+]
+
+[[package]]
+name = "async-compression"
+version = "0.4.42"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e79b3f8a79cccc2898f31920fc69f304859b3bd567490f75ebf51ae1c792a9ac"
+dependencies = [
+ "compression-codecs",
+ "compression-core",
+ "futures-io",
+ "pin-project-lite",
+]
+
+[[package]]
+name = "async-executor"
+version = "1.14.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c96bf972d85afc50bf5ab8fe2d54d1586b4e0b46c97c50a0c9e71e2f7bcd812a"
+dependencies = [
+ "async-task",
+ "concurrent-queue",
+ "fastrand 2.4.1",
+ "futures-lite 2.6.1",
+ "pin-project-lite",
+ "slab",
+]
+
+[[package]]
+name = "async-fs"
+version = "2.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8034a681df4aed8b8edbd7fbe472401ecf009251c8b40556b304567052e294c5"
+dependencies = [
+ "async-lock",
+ "blocking",
+ "futures-lite 2.6.1",
+]
+
+[[package]]
+name = "async-global-executor"
+version = "2.4.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "05b1b633a2115cd122d73b955eadd9916c18c8f510ec9cd1686404c60ad1c29c"
+dependencies = [
+ "async-channel 2.5.0",
+ "async-executor",
+ "async-io",
+ "async-lock",
+ "blocking",
+ "futures-lite 2.6.1",
+ "once_cell",
+]
+
+[[package]]
+name = "async-io"
+version = "2.6.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "456b8a8feb6f42d237746d4b3e9a178494627745c3c56c6ea55d92ba50d026fc"
+dependencies = [
+ "autocfg",
+ "cfg-if",
+ "concurrent-queue",
+ "futures-io",
+ "futures-lite 2.6.1",
+ "parking",
+ "polling",
+ "rustix 1.1.4",
+ "slab",
+ "windows-sys 0.61.2",
+]
+
+[[package]]
+name = "async-lock"
+version = "3.4.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "290f7f2596bd5b78a9fec8088ccd89180d7f9f55b94b0576823bbbdc72ee8311"
+dependencies = [
+ "event-listener 5.4.1",
+ "event-listener-strategy",
+ "pin-project-lite",
+]
+
+[[package]]
+name = "async-net"
+version = "2.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b948000fad4873c1c9339d60f2623323a0cfd3816e5181033c6a5cb68b2accf7"
+dependencies = [
+ "async-io",
+ "blocking",
+ "futures-lite 2.6.1",
+]
+
+[[package]]
+name = "async-process"
+version = "2.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "fc50921ec0055cdd8a16de48773bfeec5c972598674347252c0399676be7da75"
+dependencies = [
+ "async-channel 2.5.0",
+ "async-io",
+ "async-lock",
+ "async-signal",
+ "async-task",
+ "blocking",
+ "cfg-if",
+ "event-listener 5.4.1",
+ "futures-lite 2.6.1",
+ "rustix 1.1.4",
+]
+
+[[package]]
+name = "async-recursion"
+version = "1.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3b43422f69d8ff38f95f1b2bb76517c91589a924d1559a0e935d7c8ce0274c11"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.117",
+]
+
+[[package]]
+name = "async-signal"
+version = "0.2.14"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "52b5aaafa020cf5053a01f2a60e8ff5dccf550f0f77ec54a4e47285ac2bab485"
+dependencies = [
+ "async-io",
+ "async-lock",
+ "atomic-waker",
+ "cfg-if",
+ "futures-core",
+ "futures-io",
+ "rustix 1.1.4",
+ "signal-hook-registry",
+ "slab",
+ "windows-sys 0.61.2",
+]
+
+[[package]]
+name = "async-std"
+version = "1.13.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2c8e079a4ab67ae52b7403632e4618815d6db36d2a010cfe41b02c1b1578f93b"
+dependencies = [
+ "async-channel 1.9.0",
+ "async-global-executor",
+ "async-io",
+ "async-lock",
+ "async-process",
+ "crossbeam-utils",
+ "futures-channel",
+ "futures-core",
+ "futures-io",
+ "futures-lite 2.6.1",
+ "gloo-timers",
+ "kv-log-macro",
+ "log",
+ "memchr",
+ "once_cell",
+ "pin-project-lite",
+ "pin-utils",
+ "slab",
+ "wasm-bindgen-futures",
+]
+
+[[package]]
+name = "async-task"
+version = "4.7.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8b75356056920673b02621b35afd0f7dda9306d03c79a30f5c56c44cf256e3de"
+
+[[package]]
+name = "async-trait"
+version = "0.1.89"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9035ad2d096bed7955a320ee7e2230574d28fd3c3a0f186cbea1ff3c7eed5dbb"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.117",
+]
+
+[[package]]
+name = "async_zip"
+version = "0.0.17"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "00b9f7252833d5ed4b00aa9604b563529dd5e11de9c23615de2dcdf91eb87b52"
+dependencies = [
+ "async-compression",
+ "crc32fast",
+ "futures-lite 2.6.1",
+ "pin-project",
+ "thiserror 1.0.69",
+]
+
+[[package]]
+name = "asynchronous-codec"
+version = "0.7.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a860072022177f903e59730004fb5dc13db9275b79bb2aef7ba8ce831956c233"
+dependencies = [
+ "bytes",
+ "futures-sink",
+ "futures-util",
+ "memchr",
+ "pin-project-lite",
+]
+
+[[package]]
+name = "atomic"
+version = "0.5.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c59bdb34bc650a32731b31bd8f0829cc15d24a708ee31559e0bb34f2bc320cba"
+
+[[package]]
+name = "atomic-polyfill"
+version = "1.0.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8cf2bce30dfe09ef0bfaef228b9d414faaf7e563035494d7fe092dba54b300f4"
+dependencies = [
+ "critical-section",
+]
+
+[[package]]
+name = "atomic-waker"
+version = "1.1.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0"
+
+[[package]]
+name = "attohttpc"
+version = "0.30.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "16e2cdb6d5ed835199484bb92bb8b3edd526effe995c61732580439c1a67e2e9"
+dependencies = [
+ "base64",
+ "http",
+ "log",
+ "url",
+]
+
+[[package]]
+name = "autocfg"
+version = "1.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8"
+
+[[package]]
+name = "av-scenechange"
+version = "0.14.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0f321d77c20e19b92c39e7471cf986812cbb46659d2af674adc4331ef3f18394"
+dependencies = [
+ "aligned",
+ "anyhow",
+ "arg_enum_proc_macro",
+ "arrayvec",
+ "log",
+ "num-rational",
+ "num-traits",
+ "pastey",
+ "rayon",
+ "thiserror 2.0.18",
+ "v_frame",
+ "y4m",
+]
+
+[[package]]
+name = "av1-grain"
+version = "0.2.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8cfddb07216410377231960af4fcab838eaa12e013417781b78bd95ee22077f8"
+dependencies = [
+ "anyhow",
+ "arrayvec",
+ "log",
+ "nom 8.0.0",
+ "num-rational",
+ "v_frame",
+]
+
+[[package]]
+name = "avif-serialize"
+version = "0.8.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e7178fe5f7d460b13895ebb9dcb28a3a6216d2df2574a0806cb51b555d297f38"
+dependencies = [
+ "arrayvec",
+]
+
+[[package]]
+name = "base-x"
+version = "0.2.11"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4cbbc9d0964165b47557570cce6c952866c2678457aca742aafc9fb771d30270"
+
+[[package]]
+name = "base256emoji"
+version = "1.0.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b5e9430d9a245a77c92176e649af6e275f20839a48389859d1661e9a128d077c"
+dependencies = [
+ "const-str",
+ "match-lookup",
+]
+
+[[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.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2af50177e190e07a26ab74f8b1efbfe2ef87da2116221318cb1c2e82baf7de06"
+
+[[package]]
+name = "bincode"
+version = "1.3.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b1f45e9417d87227c7a56d22e471c6206462cba514c7590c09aff4cf6d1ddcad"
+dependencies = [
+ "serde",
+]
+
+[[package]]
+name = "bindgen"
+version = "0.71.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5f58bf3d7db68cfbac37cfc485a8d711e87e064c3d0fe0435b92f7a407f9d6b3"
+dependencies = [
+ "bitflags 2.11.1",
+ "cexpr",
+ "clang-sys",
+ "itertools 0.13.0",
+ "log",
+ "prettyplease",
+ "proc-macro2",
+ "quote",
+ "regex",
+ "rustc-hash 2.1.2",
+ "shlex",
+ "syn 2.0.117",
+]
+
+[[package]]
+name = "bit-set"
+version = "0.8.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "08807e080ed7f9d5433fa9b275196cfc35414f66a0c79d864dc51a0d825231a3"
+dependencies = [
+ "bit-vec",
+]
+
+[[package]]
+name = "bit-vec"
+version = "0.8.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5e764a1d40d510daf35e07be9eb06e75770908c27d411ee6c92109c9840eaaf7"
+
+[[package]]
+name = "bit_field"
+version = "0.10.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1e4b40c7323adcfc0a41c4b88143ed58346ff65a288fc144329c5c45e05d70c6"
+
+[[package]]
+name = "bitflags"
+version = "1.3.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
+
+[[package]]
+name = "bitflags"
+version = "2.11.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c4512299f36f043ab09a583e57bceb5a5aab7a73db1805848e8fef3c9e8c78b3"
+
+[[package]]
+name = "bitstream-io"
+version = "4.10.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7eff00be299a18769011411c9def0d827e8f2d7bf0c3dbf53633147a8867fd1f"
+dependencies = [
+ "no_std_io2",
+]
+
+[[package]]
+name = "blade-graphics"
+version = "0.7.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e71cfb73b98eb9f58ee84048aa1bdf4e7497fd20c141b57523499fa066b48fed"
+dependencies = [
+ "ash",
+ "ash-window",
+ "bitflags 2.11.1",
+ "bytemuck",
+ "codespan-reporting",
+ "glow",
+ "gpu-alloc",
+ "gpu-alloc-ash",
+ "hidden-trait",
+ "js-sys",
+ "khronos-egl",
+ "libloading",
+ "log",
+ "mint",
+ "naga",
+ "objc2",
+ "objc2-app-kit",
+ "objc2-core-foundation",
+ "objc2-foundation",
+ "objc2-metal",
+ "objc2-quartz-core",
+ "objc2-ui-kit",
+ "once_cell",
+ "raw-window-handle",
+ "slab",
+ "wasm-bindgen",
+ "web-sys",
+]
+
+[[package]]
+name = "blade-macros"
+version = "0.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "27142319e2f4c264581067eaccb9f80acccdde60d8b4bf57cc50cd3152f109ca"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.117",
+]
+
+[[package]]
+name = "blade-util"
+version = "0.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3a6be3a82c001ba7a17b6f8e413ede5d1004e6047213f8efaf0ffc15b5c4904c"
+dependencies = [
+ "blade-graphics",
+ "bytemuck",
+ "log",
+ "profiling",
+]
+
+[[package]]
+name = "blake2"
+version = "0.10.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "46502ad458c9a52b69d4d4d32775c788b7a1b85e8bc9d482d92250fc0e3f8efe"
+dependencies = [
+ "digest",
+]
+
+[[package]]
+name = "blake3"
+version = "1.8.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0aa83c34e62843d924f905e0f5c866eb1dd6545fc4d719e803d9ba6030371fce"
+dependencies = [
+ "arrayref",
+ "arrayvec",
+ "cc",
+ "cfg-if",
+ "constant_time_eq",
+ "cpufeatures 0.3.0",
+]
+
+[[package]]
+name = "block"
+version = "0.1.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0d8c1fef690941d3e7788d328517591fecc684c084084702d6ff1641e993699a"
+
+[[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-padding"
+version = "0.3.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a8894febbff9f758034a5b8e12d87918f56dfc64a8e1fe757d65e29041538d93"
+dependencies = [
+ "generic-array",
+]
+
+[[package]]
+name = "block2"
+version = "0.6.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "cdeb9d870516001442e364c5220d3574d2da8dc765554b4a617230d33fa58ef5"
+dependencies = [
+ "objc2",
+]
+
+[[package]]
+name = "blocking"
+version = "1.6.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e83f8d02be6967315521be875afa792a316e28d57b5a2d401897e2a7921b7f21"
+dependencies = [
+ "async-channel 2.5.0",
+ "async-task",
+ "futures-io",
+ "futures-lite 2.6.1",
+ "piper",
+]
+
+[[package]]
+name = "bs58"
+version = "0.5.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bf88ba1141d185c399bee5288d850d63b8369520c1eafc32a0430b5b6c287bf4"
+dependencies = [
+ "tinyvec",
+]
+
+[[package]]
+name = "bstr"
+version = "1.12.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "63044e1ae8e69f3b5a92c736ca6269b8d12fa7efe39bf34ddb06d102cf0e2cab"
+dependencies = [
+ "memchr",
+ "serde",
+]
+
+[[package]]
+name = "built"
+version = "0.8.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f4ad8f11f288f48ca24471bbd51ac257aaeaaa07adae295591266b792902ae64"
+
+[[package]]
+name = "bumpalo"
+version = "3.20.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5d20789868f4b01b2f2caec9f5c4e0213b41e3e5702a50157d699ae31ced2fcb"
+
+[[package]]
+name = "bytemuck"
+version = "1.25.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c8efb64bd706a16a1bdde310ae86b351e4d21550d98d056f22f8a7f7a2183fec"
+dependencies = [
+ "bytemuck_derive",
+]
+
+[[package]]
+name = "bytemuck_derive"
+version = "1.10.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f9abbd1bc6865053c427f7198e6af43bfdedc55ab791faed4fbd361d789575ff"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.117",
+]
+
+[[package]]
+name = "byteorder"
+version = "1.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b"
+
+[[package]]
+name = "byteorder-lite"
+version = "0.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8f1fe948ff07f4bd06c30984e69f5b4899c516a3ef74f34df92a2df2ab535495"
+
+[[package]]
+name = "bytes"
+version = "1.11.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1e748733b7cbc798e1434b6ac524f0c1ff2ab456fe201501e6497c8417a4fc33"
+
+[[package]]
+name = "calloop"
+version = "0.13.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b99da2f8558ca23c71f4fd15dc57c906239752dd27ff3c00a1d56b685b7cbfec"
+dependencies = [
+ "bitflags 2.11.1",
+ "log",
+ "polling",
+ "rustix 0.38.44",
+ "slab",
+ "thiserror 1.0.69",
+]
+
+[[package]]
+name = "calloop-wayland-source"
+version = "0.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "95a66a987056935f7efce4ab5668920b5d0dac4a7c99991a67395f13702ddd20"
+dependencies = [
+ "calloop",
+ "rustix 0.38.44",
+ "wayland-backend",
+ "wayland-client",
+]
+
+[[package]]
+name = "cbc"
+version = "0.1.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "26b52a9543ae338f279b96b0b9fed9c8093744685043739079ce85cd58f289a6"
+dependencies = [
+ "cipher",
+]
+
+[[package]]
+name = "cbindgen"
+version = "0.28.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "eadd868a2ce9ca38de7eeafdcec9c7065ef89b42b32f0839278d55f35c54d1ff"
+dependencies = [
+ "heck 0.4.1",
+ "indexmap",
+ "log",
+ "proc-macro2",
+ "quote",
+ "serde",
+ "serde_json",
+ "syn 2.0.117",
+ "tempfile",
+ "toml 0.8.23",
+]
+
+[[package]]
+name = "cc"
+version = "1.2.61"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d16d90359e986641506914ba71350897565610e87ce0ad9e6f28569db3dd5c6d"
+dependencies = [
+ "find-msvc-tools",
+ "jobserver",
+ "libc",
+ "shlex",
+]
+
+[[package]]
+name = "cexpr"
+version = "0.6.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6fac387a98bb7c37292057cffc56d62ecb629900026402633ae9160df93a8766"
+dependencies = [
+ "nom 7.1.3",
+]
+
+[[package]]
+name = "cfg-if"
+version = "1.0.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801"
+
+[[package]]
+name = "cfg_aliases"
+version = "0.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724"
+
+[[package]]
+name = "cgl"
+version = "0.3.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0ced0551234e87afee12411d535648dd89d2e7f34c78b753395567aff3d447ff"
+dependencies = [
+ "libc",
+]
+
+[[package]]
+name = "chacha20"
+version = "0.9.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c3613f74bd2eac03dad61bd53dbe620703d4371614fe0bc3b9f04dd36fe4e818"
+dependencies = [
+ "cfg-if",
+ "cipher",
+ "cpufeatures 0.2.17",
+]
+
+[[package]]
+name = "chacha20poly1305"
+version = "0.10.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "10cd79432192d1c0f4e1a0fef9527696cc039165d729fb41b3f4f4f354c2dc35"
+dependencies = [
+ "aead",
+ "chacha20",
+ "cipher",
+ "poly1305",
+ "zeroize",
+]
+
+[[package]]
+name = "cipher"
+version = "0.4.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "773f3b9af64447d2ce9850330c473515014aa235e6a783b02db81ff39e4a3dad"
+dependencies = [
+ "crypto-common",
+ "inout",
+ "zeroize",
+]
+
+[[package]]
+name = "clang-sys"
+version = "1.8.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0b023947811758c97c59bf9d1c188fd619ad4718dcaa767947df1cadb14f39f4"
+dependencies = [
+ "glob",
+ "libc",
+ "libloading",
+]
+
+[[package]]
+name = "clap"
+version = "4.6.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1ddb117e43bbf7dacf0a4190fef4d345b9bad68dfc649cb349e7d17d28428e51"
+dependencies = [
+ "clap_builder",
+ "clap_derive",
+]
+
+[[package]]
+name = "clap_builder"
+version = "4.6.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "714a53001bf66416adb0e2ef5ac857140e7dc3a0c48fb28b2f10762fc4b5069f"
+dependencies = [
+ "anstream",
+ "anstyle",
+ "clap_lex",
+ "strsim",
+]
+
+[[package]]
+name = "clap_derive"
+version = "4.6.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f2ce8604710f6733aa641a2b3731eaa1e8b3d9973d5e3565da11800813f997a9"
+dependencies = [
+ "heck 0.5.0",
+ "proc-macro2",
+ "quote",
+ "syn 2.0.117",
+]
+
+[[package]]
+name = "clap_lex"
+version = "1.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c8d4a3bb8b1e0c1050499d1815f5ab16d04f0959b233085fb31653fbfc9d98f9"
+
+[[package]]
+name = "cobs"
+version = "0.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0fa961b519f0b462e3a3b4a34b64d119eeaca1d59af726fe450bbba07a9fc0a1"
+dependencies = [
+ "thiserror 2.0.18",
+]
+
+[[package]]
+name = "cocoa"
+version = "0.25.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f6140449f97a6e97f9511815c5632d84c8aacf8ac271ad77c559218161a1373c"
+dependencies = [
+ "bitflags 1.3.2",
+ "block",
+ "cocoa-foundation 0.1.2",
+ "core-foundation 0.9.4",
+ "core-graphics 0.23.2",
+ "foreign-types",
+ "libc",
+ "objc",
+]
+
+[[package]]
+name = "cocoa"
+version = "0.26.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f79398230a6e2c08f5c9760610eb6924b52aa9e7950a619602baba59dcbbdbb2"
+dependencies = [
+ "bitflags 2.11.1",
+ "block",
+ "cocoa-foundation 0.2.0",
+ "core-foundation 0.10.0",
+ "core-graphics 0.24.0",
+ "foreign-types",
+ "libc",
+ "objc",
+]
+
+[[package]]
+name = "cocoa-foundation"
+version = "0.1.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8c6234cbb2e4c785b456c0644748b1ac416dd045799740356f8363dfe00c93f7"
+dependencies = [
+ "bitflags 1.3.2",
+ "block",
+ "core-foundation 0.9.4",
+ "core-graphics-types 0.1.3",
+ "libc",
+ "objc",
+]
+
+[[package]]
+name = "cocoa-foundation"
+version = "0.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e14045fb83be07b5acf1c0884b2180461635b433455fa35d1cd6f17f1450679d"
+dependencies = [
+ "bitflags 2.11.1",
+ "block",
+ "core-foundation 0.10.0",
+ "core-graphics-types 0.2.0",
+ "libc",
+ "objc",
+]
+
+[[package]]
+name = "codespan-reporting"
+version = "0.12.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "fe6d2e5af09e8c8ad56c969f2157a3d4238cebc7c55f0a517728c38f7b200f81"
+dependencies = [
+ "serde",
+ "termcolor",
+ "unicode-width",
+]
+
+[[package]]
+name = "color_quant"
+version = "1.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3d7b894f5411737b7867f4827955924d7c254fc9f4d91a6aad6b097804b1018b"
+
+[[package]]
+name = "colorchoice"
+version = "1.0.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1d07550c9036bf2ae0c684c4297d503f838287c83c53686d05370d0e139ae570"
+
+[[package]]
+name = "command-fds"
+version = "0.3.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1b60b5124979fccd9addd89d8b97a1d6eebb4950694520c75ddd722535ea443f"
+dependencies = [
+ "nix 0.31.2",
+ "thiserror 2.0.18",
+]
+
+[[package]]
+name = "compression-codecs"
+version = "0.4.38"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ce2548391e9c1929c21bf6aa2680af86fe4c1b33e6cea9ac1cfeec0bd11218cf"
+dependencies = [
+ "compression-core",
+ "deflate64",
+ "flate2",
+ "memchr",
+]
+
+[[package]]
+name = "compression-core"
+version = "0.4.32"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "cc14f565cf027a105f7a44ccf9e5b424348421a1d8952a8fc9d499d313107789"
+
+[[package]]
+name = "concurrent-queue"
+version = "2.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4ca0197aee26d1ae37445ee532fefce43251d24cc7c166799f4d46817f1d3973"
+dependencies = [
+ "crossbeam-utils",
+]
+
+[[package]]
+name = "const-oid"
+version = "0.9.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c2459377285ad874054d797f3ccebf984978aa39129f6eafde5cdc8315b612f8"
+
+[[package]]
+name = "const-random"
+version = "0.1.18"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "87e00182fe74b066627d63b85fd550ac2998d4b0bd86bfed477a0ae4c7c71359"
+dependencies = [
+ "const-random-macro",
+]
+
+[[package]]
+name = "const-random-macro"
+version = "0.1.16"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f9d839f2a20b0aee515dc581a6172f2321f96cab76c1a38a4c584a194955390e"
+dependencies = [
+ "getrandom 0.2.17",
+ "once_cell",
+ "tiny-keccak",
+]
+
+[[package]]
+name = "const-str"
+version = "0.4.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2f421161cb492475f1661ddc9815a745a1c894592070661180fdec3d4872e9c3"
+
+[[package]]
+name = "constant_time_eq"
+version = "0.4.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3d52eff69cd5e647efe296129160853a42795992097e8af39800e1060caeea9b"
+
+[[package]]
+name = "convert_case"
+version = "0.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6245d59a3e82a7fc217c5828a6692dbc6dfb63a0c8c90495621f7b9d79704a0e"
+
+[[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.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b55271e5c8c478ad3f38ad24ef34923091e0548492a266d19b3c0b4d82574c63"
+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 = "core-graphics"
+version = "0.23.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c07782be35f9e1140080c6b96f0d44b739e2278479f64e02fdab4e32dfd8b081"
+dependencies = [
+ "bitflags 1.3.2",
+ "core-foundation 0.9.4",
+ "core-graphics-types 0.1.3",
+ "foreign-types",
+ "libc",
+]
+
+[[package]]
+name = "core-graphics"
+version = "0.24.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "fa95a34622365fa5bbf40b20b75dba8dfa8c94c734aea8ac9a5ca38af14316f1"
+dependencies = [
+ "bitflags 2.11.1",
+ "core-foundation 0.10.0",
+ "core-graphics-types 0.2.0",
+ "foreign-types",
+ "libc",
+]
+
+[[package]]
+name = "core-graphics-helmer-fork"
+version = "0.24.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "32eb7c354ae9f6d437a6039099ce7ecd049337a8109b23d73e48e8ffba8e9cd5"
+dependencies = [
+ "bitflags 2.11.1",
+ "core-foundation 0.9.4",
+ "core-graphics-types 0.1.3",
+ "foreign-types",
+ "libc",
+]
+
+[[package]]
+name = "core-graphics-types"
+version = "0.1.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "45390e6114f68f718cc7a830514a96f903cccd70d02a8f6d9f643ac4ba45afaf"
+dependencies = [
+ "bitflags 1.3.2",
+ "core-foundation 0.9.4",
+ "libc",
+]
+
+[[package]]
+name = "core-graphics-types"
+version = "0.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3d44a101f213f6c4cdc1853d4b78aef6db6bdfa3468798cc1d9912f4735013eb"
+dependencies = [
+ "bitflags 2.11.1",
+ "core-foundation 0.10.0",
+ "libc",
+]
+
+[[package]]
+name = "core-graphics2"
+version = "0.4.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7e4583956b9806b69f73fcb23aee05eb3620efc282972f08f6a6db7504f8334d"
+dependencies = [
+ "bitflags 2.11.1",
+ "block",
+ "cfg-if",
+ "core-foundation 0.10.0",
+ "libc",
+]
+
+[[package]]
+name = "core-text"
+version = "21.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a593227b66cbd4007b2a050dfdd9e1d1318311409c8d600dc82ba1b15ca9c130"
+dependencies = [
+ "core-foundation 0.10.0",
+ "core-graphics 0.24.0",
+ "foreign-types",
+ "libc",
+]
+
+[[package]]
+name = "core-video"
+version = "0.4.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d45e71d5be22206bed53c3c3cb99315fc4c3d31b8963808c6bc4538168c4f8ef"
+dependencies = [
+ "block",
+ "core-foundation 0.10.0",
+ "core-graphics2",
+ "io-surface",
+ "libc",
+ "metal",
+]
+
+[[package]]
+name = "core_maths"
+version = "0.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "77745e017f5edba1a9c1d854f6f3a52dac8a12dd5af5d2f54aecf61e43d80d30"
+dependencies = [
+ "libm",
+]
+
+[[package]]
+name = "cosmic-text"
+version = "0.14.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "da46a9d5a8905cc538a4a5bceb6a4510de7a51049c5588c0114efce102bcbbe8"
+dependencies = [
+ "bitflags 2.11.1",
+ "fontdb 0.16.2",
+ "log",
+ "rangemap",
+ "rustc-hash 1.1.0",
+ "rustybuzz 0.14.1",
+ "self_cell",
+ "smol_str",
+ "swash",
+ "sys-locale",
+ "ttf-parser 0.21.1",
+ "unicode-bidi",
+ "unicode-linebreak",
+ "unicode-script",
+ "unicode-segmentation",
+]
+
+[[package]]
+name = "cpufeatures"
+version = "0.2.17"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "59ed5838eebb26a2bb2e58f6d5b5316989ae9d08bab10e0e6d103e656d1b0280"
+dependencies = [
+ "libc",
+]
+
+[[package]]
+name = "cpufeatures"
+version = "0.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8b2a41393f66f16b0823bb79094d54ac5fbd34ab292ddafb9a0456ac9f87d201"
+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 = "critical-section"
+version = "1.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "790eea4361631c5e7d22598ecd5723ff611904e3344ce8720784c93e3d83d40b"
+
+[[package]]
+name = "crossbeam-channel"
+version = "0.5.15"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "82b8f8f868b36967f9606790d1903570de9ceaf870a7bf9fbbd3016d636a2cb2"
+dependencies = [
+ "crossbeam-utils",
+]
+
+[[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-queue"
+version = "0.3.12"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0f58bbc28f91df819d0aa2a2c00cd19754769c2fad90579b3592b1c9ba7a3115"
+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 = "crunchy"
+version = "0.2.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "460fbee9c2c2f33933d720630a6a0bac33ba7053db5344fac858d4b8952d77d5"
+
+[[package]]
+name = "crypto-common"
+version = "0.1.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "78c8292055d1c1df0cce5d180393dc8cce0abec0a7102adb6c7b1eef6016d60a"
+dependencies = [
+ "generic-array",
+ "rand_core 0.6.4",
+ "typenum",
+]
+
+[[package]]
+name = "ctor"
+version = "0.4.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ec09e802f5081de6157da9a75701d6c713d8dc3ba52571fd4bd25f412644e8a6"
+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.9.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0369ee1ad671834580515889b80f2ea915f23b8be8d0daa4bbaf2ac5c7590835"
+dependencies = [
+ "cipher",
+]
+
+[[package]]
+name = "curve25519-dalek"
+version = "4.1.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "97fb8b7c4503de7d6ae7b42ab72a5a59857b4c937ec27a3d4539dba95b5ab2be"
+dependencies = [
+ "cfg-if",
+ "cpufeatures 0.2.17",
+ "curve25519-dalek-derive",
+ "digest",
+ "fiat-crypto",
+ "rustc_version",
+ "subtle",
+ "zeroize",
+]
+
+[[package]]
+name = "curve25519-dalek-derive"
+version = "0.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f46882e17999c6cc590af592290432be3bce0428cb0d5f8b6715e4dc7b383eb3"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.117",
+]
+
+[[package]]
+name = "data-encoding"
+version = "2.11.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a4ae5f15dda3c708c0ade84bfee31ccab44a3da4f88015ed22f63732abe300c8"
+
+[[package]]
+name = "data-encoding-macro"
+version = "0.1.20"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3259c913752a86488b501ed8680446a5ed2d5aeac6e596cb23ba3800768ea32c"
+dependencies = [
+ "data-encoding",
+ "data-encoding-macro-internal",
+]
+
+[[package]]
+name = "data-encoding-macro-internal"
+version = "0.1.18"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ccc2776f0c61eca1ca32528f85548abd1a4be8fb53d1b21c013e4f18da1e7090"
+dependencies = [
+ "data-encoding",
+ "syn 2.0.117",
+]
+
+[[package]]
+name = "data-url"
+version = "0.3.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "be1e0bca6c3637f992fc1cc7cbc52a78c1ef6db076dbf1059c4323d6a2048376"
+
+[[package]]
+name = "deflate64"
+version = "0.1.12"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ac6b926516df9c60bfa16e107b21086399f8285a44ca9711344b9e553c5146e2"
+
+[[package]]
+name = "der"
+version = "0.7.10"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e7c1832837b905bbfb5101e07cc24c8deddf52f93225eee6ead5f4d63d53ddcb"
+dependencies = [
+ "const-oid",
+ "zeroize",
+]
+
+[[package]]
+name = "der-parser"
+version = "10.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "07da5016415d5a3c4dd39b11ed26f915f52fc4e0dc197d87908bc916e51bc1a6"
+dependencies = [
+ "asn1-rs",
+ "displaydoc",
+ "nom 7.1.3",
+ "num-bigint",
+ "num-traits",
+ "rusticata-macros",
+]
+
+[[package]]
+name = "deranged"
+version = "0.5.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7cd812cc2bc1d69d4764bd80df88b4317eaef9e773c75226407d9bc0876b211c"
+dependencies = [
+ "powerfmt",
+]
+
+[[package]]
+name = "derive_more"
+version = "0.99.20"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6edb4b64a43d977b8e99788fe3a04d483834fba1215a7e02caa415b626497f7f"
+dependencies = [
+ "convert_case",
+ "proc-macro2",
+ "quote",
+ "rustc_version",
+ "syn 2.0.117",
+]
+
+[[package]]
+name = "digest"
+version = "0.10.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292"
+dependencies = [
+ "block-buffer",
+ "crypto-common",
+ "subtle",
+]
+
+[[package]]
+name = "dirs"
+version = "4.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ca3aa72a6f96ea37bbc5aa912f6788242832f75369bdfdadcb0e38423f100059"
+dependencies = [
+ "dirs-sys 0.3.7",
+]
+
+[[package]]
+name = "dirs"
+version = "5.0.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "44c45a9d03d6676652bcb5e724c7e988de1acad23a711b5217ab9cbecbec2225"
+dependencies = [
+ "dirs-sys 0.4.1",
+]
+
+[[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"
+version = "0.4.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "520f05a5cbd335fae5a99ff7a6ab8627577660ee5cfd6a94a6a929b52ff0321c"
+dependencies = [
+ "libc",
+ "option-ext",
+ "redox_users",
+ "windows-sys 0.48.0",
+]
+
+[[package]]
+name = "dispatch"
+version = "0.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bd0c93bb4b0c6d9b77f4435b0ae98c24d17f1c45b2ff844c6151a07256ca923b"
+
+[[package]]
+name = "dispatch2"
+version = "0.3.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1e0e367e4e7da84520dedcac1901e4da967309406d1e51017ae1abfb97adbd38"
+dependencies = [
+ "bitflags 2.11.1",
+ "objc2",
+]
+
+[[package]]
+name = "displaydoc"
+version = "0.2.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.117",
+]
+
+[[package]]
+name = "dlib"
+version = "0.5.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ab8ecd87370524b461f8557c119c405552c396ed91fc0a8eec68679eab26f94a"
+dependencies = [
+ "libloading",
+]
+
+[[package]]
+name = "downcast-rs"
+version = "1.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "75b325c5dbd37f80359721ad39aca5a29fb04c89279657cffdda8736d0c0b9d2"
+
+[[package]]
+name = "dtoa"
+version = "1.0.11"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4c3cf4824e2d5f025c7b531afcb2325364084a16806f6d47fbc1f5fbd9960590"
+
+[[package]]
+name = "dtor"
+version = "0.0.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "97cbdf2ad6846025e8e25df05171abfb30e3ababa12ee0a0e44b9bbe570633a8"
+dependencies = [
+ "dtor-proc-macro",
+]
+
+[[package]]
+name = "dtor-proc-macro"
+version = "0.0.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7454e41ff9012c00d53cf7f475c5e3afa3b91b7c90568495495e8d9bf47a1055"
+
+[[package]]
+name = "dunce"
+version = "1.0.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "92773504d58c093f6de2459af4af33faa518c13451eb8f2b5698ed3d36e7c813"
+
+[[package]]
+name = "dwrote"
+version = "0.11.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9e1b35532432acc8b19ceed096e35dfa088d3ea037fe4f3c085f1f97f33b4d02"
+dependencies = [
+ "lazy_static",
+ "libc",
+ "winapi",
+ "wio",
+]
+
+[[package]]
+name = "dyn-clone"
+version = "1.0.20"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d0881ea181b1df73ff77ffaaf9c7544ecc11e82fba9b5f27b262a3c73a332555"
+
+[[package]]
+name = "ed25519"
+version = "2.2.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "115531babc129696a58c64a4fef0a8bf9e9698629fb97e9e40767d235cfbcd53"
+dependencies = [
+ "pkcs8",
+ "signature",
+]
+
+[[package]]
+name = "ed25519-dalek"
+version = "2.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "70e796c081cee67dc755e1a36a0a172b897fab85fc3f6bc48307991f64e4eca9"
+dependencies = [
+ "curve25519-dalek",
+ "ed25519",
+ "serde",
+ "sha2",
+ "subtle",
+ "zeroize",
+]
+
+[[package]]
+name = "either"
+version = "1.15.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719"
+
+[[package]]
+name = "embed-resource"
+version = "3.0.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c31a88c8d26de40ed18fe748c547845aa39de1db3afd958f8cb91579f3644bcb"
+dependencies = [
+ "cc",
+ "memchr",
+ "rustc_version",
+ "toml 1.1.2+spec-1.1.0",
+ "vswhom",
+ "winreg",
+]
+
+[[package]]
+name = "embedded-io"
+version = "0.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ef1a6892d9eef45c8fa6b9e0086428a2cca8491aca8f787c534a3d6d0bcb3ced"
+
+[[package]]
+name = "embedded-io"
+version = "0.6.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "edd0f118536f44f5ccd48bcb8b111bdc3de888b58c74639dfb034a357d0f206d"
+
+[[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 = "endi"
+version = "1.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "66b7e2430c6dff6a955451e2cfc438f09cea1965a9d6f87f7e3b90decc014099"
+
+[[package]]
+name = "ente-binfmt-compat"
+version = "0.0.1"
+dependencies = [
+ "anyhow",
+ "tracing",
+ "tracing-subscriber",
+]
+
+[[package]]
+name = "ente-brain"
+version = "0.0.1"
+dependencies = [
+ "anyhow",
+ "base64",
+ "bincode",
+ "ente-card",
+ "ente-cas",
+ "postcard",
+ "serde",
+ "serde_json",
+ "tokio",
+ "tracing",
+ "ulid",
+]
+
+[[package]]
+name = "ente-bus"
+version = "0.0.1"
+dependencies = [
+ "anyhow",
+ "ente-card",
+ "ente-echo",
+ "postcard",
+ "serde",
+ "tokio",
+ "tracing",
+ "ulid",
+]
+
+[[package]]
+name = "ente-card"
+version = "0.0.1"
+dependencies = [
+ "serde",
+ "serde_json",
+ "ulid",
+]
+
+[[package]]
+name = "ente-cas"
+version = "0.0.1"
+dependencies = [
+ "anyhow",
+ "sha2",
+ "tracing",
+]
+
+[[package]]
+name = "ente-echo"
+version = "0.0.1"
+dependencies = [
+ "anyhow",
+ "ente-bus",
+ "ente-card",
+ "tokio",
+ "tracing",
+ "tracing-subscriber",
+]
+
+[[package]]
+name = "ente-hostnamed-compat"
+version = "0.0.1"
+dependencies = [
+ "anyhow",
+ "ente-bus",
+ "ente-card",
+ "libc",
+ "nix 0.29.0",
+ "tokio",
+ "tracing",
+ "tracing-subscriber",
+ "zbus 4.4.0",
+]
+
+[[package]]
+name = "ente-journald-compat"
+version = "0.0.1"
+dependencies = [
+ "anyhow",
+ "ente-bus",
+ "ente-card",
+ "ente-cas",
+ "libc",
+ "nix 0.29.0",
+ "tokio",
+ "tracing",
+ "tracing-subscriber",
+]
+
+[[package]]
+name = "ente-kernel"
+version = "0.0.1"
+dependencies = [
+ "anyhow",
+ "ente-card",
+ "libc",
+ "nix 0.29.0",
+ "tokio",
+ "tracing",
+]
+
+[[package]]
+name = "ente-localed-compat"
+version = "0.0.1"
+dependencies = [
+ "anyhow",
+ "ente-bus",
+ "ente-card",
+ "tokio",
+ "tracing",
+ "tracing-subscriber",
+ "zbus 4.4.0",
+]
+
+[[package]]
+name = "ente-logind-compat"
+version = "0.0.1"
+dependencies = [
+ "anyhow",
+ "ente-bus",
+ "ente-card",
+ "tokio",
+ "tracing",
+ "tracing-subscriber",
+ "zbus 4.4.0",
+]
+
+[[package]]
+name = "ente-machined-compat"
+version = "0.0.1"
+dependencies = [
+ "anyhow",
+ "ente-bus",
+ "ente-card",
+ "tokio",
+ "tracing",
+ "tracing-subscriber",
+ "zbus 4.4.0",
+]
+
+[[package]]
+name = "ente-notify-compat"
+version = "0.0.1"
+dependencies = [
+ "anyhow",
+ "ente-bus",
+ "ente-card",
+ "libc",
+ "nix 0.29.0",
+ "tokio",
+ "tracing",
+ "tracing-subscriber",
+]
+
+[[package]]
+name = "ente-policy-provider"
+version = "0.0.1"
+dependencies = [
+ "anyhow",
+ "ente-bus",
+ "ente-card",
+ "serde",
+ "serde_json",
+ "tokio",
+ "tracing",
+ "tracing-subscriber",
+]
+
+[[package]]
+name = "ente-polkit-compat"
+version = "0.0.1"
+dependencies = [
+ "anyhow",
+ "ente-bus",
+ "ente-card",
+ "tokio",
+ "tracing",
+ "tracing-subscriber",
+ "zbus 4.4.0",
+]
+
+[[package]]
+name = "ente-resolved-compat"
+version = "0.0.1"
+dependencies = [
+ "anyhow",
+ "ente-bus",
+ "ente-card",
+ "libc",
+ "tokio",
+ "tracing",
+ "tracing-subscriber",
+ "zbus 4.4.0",
+]
+
+[[package]]
+name = "ente-snapshot"
+version = "0.0.1"
+dependencies = [
+ "anyhow",
+ "ente-card",
+ "serde",
+ "serde_json",
+ "ulid",
+]
+
+[[package]]
+name = "ente-soma"
+version = "0.0.1"
+dependencies = [
+ "anyhow",
+ "ente-bus",
+ "ente-card",
+ "libc",
+ "nix 0.29.0",
+ "tracing",
+]
+
+[[package]]
+name = "ente-systemd1-compat"
+version = "0.0.1"
+dependencies = [
+ "anyhow",
+ "ente-bus",
+ "ente-card",
+ "tokio",
+ "tracing",
+ "tracing-subscriber",
+ "zbus 4.4.0",
+]
+
+[[package]]
+name = "ente-timedated-compat"
+version = "0.0.1"
+dependencies = [
+ "anyhow",
+ "ente-bus",
+ "ente-card",
+ "tokio",
+ "tracing",
+ "tracing-subscriber",
+ "zbus 4.4.0",
+]
+
+[[package]]
+name = "ente-timer-compat"
+version = "0.0.1"
+dependencies = [
+ "anyhow",
+ "ente-bus",
+ "ente-card",
+ "serde",
+ "serde_json",
+ "tokio",
+ "tracing",
+ "tracing-subscriber",
+ "ulid",
+]
+
+[[package]]
+name = "ente-tmpfiles-compat"
+version = "0.0.1"
+dependencies = [
+ "anyhow",
+ "libc",
+ "nix 0.29.0",
+ "tracing",
+ "tracing-subscriber",
+]
+
+[[package]]
+name = "ente-wasm"
+version = "0.0.1"
+dependencies = [
+ "anyhow",
+ "ente-card",
+ "tracing",
+ "ulid",
+ "wasmi",
+ "wat",
+]
+
+[[package]]
+name = "ente-zero"
+version = "0.0.1"
+dependencies = [
+ "anyhow",
+ "ente-brain",
+ "ente-bus",
+ "ente-card",
+ "ente-cas",
+ "ente-echo",
+ "ente-kernel",
+ "ente-snapshot",
+ "ente-soma",
+ "ente-wasm",
+ "libc",
+ "nix 0.29.0",
+ "serde",
+ "serde_json",
+ "tokio",
+ "tracing",
+ "tracing-subscriber",
+ "ulid",
+]
+
+[[package]]
+name = "enum-as-inner"
+version = "0.6.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a1e6a265c649f3f5979b601d26f1d05ada116434c87741c9493cb56218f76cbc"
+dependencies = [
+ "heck 0.5.0",
+ "proc-macro2",
+ "quote",
+ "syn 2.0.117",
+]
+
+[[package]]
+name = "enumflags2"
+version = "0.7.12"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1027f7680c853e056ebcec683615fb6fbbc07dbaa13b4d5d9442b146ded4ecef"
+dependencies = [
+ "enumflags2_derive",
+ "serde",
+]
+
+[[package]]
+name = "enumflags2_derive"
+version = "0.7.12"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "67c78a4d8fdf9953a5c9d458f9efe940fd97a0cab0941c075a813ac594733827"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.117",
+]
+
+[[package]]
+name = "equator"
+version = "0.4.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4711b213838dfee0117e3be6ac926007d7f433d7bbe33595975d4190cb07e6fc"
+dependencies = [
+ "equator-macro",
+]
+
+[[package]]
+name = "equator-macro"
+version = "0.4.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "44f23cf4b44bfce11a86ace86f8a73ffdec849c9fd00a386a53d278bd9e81fb3"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.117",
+]
+
+[[package]]
+name = "equivalent"
+version = "1.0.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f"
+
+[[package]]
+name = "erased-serde"
+version = "0.4.10"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d2add8a07dd6a8d93ff627029c51de145e12686fbc36ecb298ac22e74cf02dec"
+dependencies = [
+ "serde",
+ "serde_core",
+ "typeid",
+]
+
+[[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 = "etagere"
+version = "0.2.15"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "fc89bf99e5dc15954a60f707c1e09d7540e5cd9af85fa75caa0b510bc08c5342"
+dependencies = [
+ "euclid",
+ "svg_fmt",
+]
+
+[[package]]
+name = "euclid"
+version = "0.22.14"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f1a05365e3b1c6d1650318537c7460c6923f1abdd272ad6842baa2b509957a06"
+dependencies = [
+ "num-traits",
+]
+
+[[package]]
+name = "event-listener"
+version = "2.5.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0206175f82b8d6bf6652ff7d71a1e27fd2e4efde587fd368662814d6ec1d9ce0"
+
+[[package]]
+name = "event-listener"
+version = "5.4.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e13b66accf52311f30a0db42147dadea9850cb48cd070028831ae5f5d4b856ab"
+dependencies = [
+ "concurrent-queue",
+ "parking",
+ "pin-project-lite",
+]
+
+[[package]]
+name = "event-listener-strategy"
+version = "0.5.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8be9f3dfaaffdae2972880079a491a1a8bb7cbed0b8dd7a347f668b4150a3b93"
+dependencies = [
+ "event-listener 5.4.1",
+ "pin-project-lite",
+]
+
+[[package]]
+name = "exr"
+version = "1.74.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4300e043a56aa2cb633c01af81ca8f699a321879a7854d3896a0ba89056363be"
+dependencies = [
+ "bit_field",
+ "half",
+ "lebe",
+ "miniz_oxide",
+ "rayon-core",
+ "smallvec",
+ "zune-inflate",
+]
+
+[[package]]
+name = "fallible-iterator"
+version = "0.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2acce4a10f12dc2fb14a218589d4f1f62ef011b2d0cc4b3cb1bba8e94da14649"
+
+[[package]]
+name = "fallible-streaming-iterator"
+version = "0.1.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7360491ce676a36bf9bb3c56c1aa791658183a54d2744120f27285738d90465a"
+
+[[package]]
+name = "fastrand"
+version = "1.9.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e51093e27b0797c359783294ca4f0a911c270184cb10f85783b118614a1501be"
+dependencies = [
+ "instant",
+]
+
+[[package]]
+name = "fastrand"
+version = "2.4.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9f1f227452a390804cdb637b74a86990f2a7d7ba4b7d5693aac9b4dd6defd8d6"
+
+[[package]]
+name = "fax"
+version = "0.2.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "caf1079563223d5d59d83c85886a56e586cfd5c1a26292e971a0fa266531ac5a"
+
+[[package]]
+name = "fdeflate"
+version = "0.3.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1e6853b52649d4ac5c0bd02320cddc5ba956bdb407c4b75a2c6b75bf51500f8c"
+dependencies = [
+ "simd-adler32",
+]
+
+[[package]]
+name = "fiat-crypto"
+version = "0.2.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "28dea519a9695b9977216879a3ebfddf92f1c08c05d984f8996aecd6ecdc811d"
+
+[[package]]
+name = "filedescriptor"
+version = "0.8.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e40758ed24c9b2eeb76c35fb0aebc66c626084edd827e07e1552279814c6682d"
+dependencies = [
+ "libc",
+ "thiserror 1.0.69",
+ "winapi",
+]
+
+[[package]]
+name = "filetime"
+version = "0.2.27"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f98844151eee8917efc50bd9e8318cb963ae8b297431495d3f758616ea5c57db"
+dependencies = [
+ "cfg-if",
+ "libc",
+ "libredox",
+]
+
+[[package]]
+name = "find-msvc-tools"
+version = "0.1.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5baebc0774151f905a1a2cc41989300b1e6fbb29aff0ceffa1064fdd3088d582"
+
+[[package]]
+name = "flate2"
+version = "1.1.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "843fba2746e448b37e26a819579957415c8cef339bf08564fe8b7ddbd959573c"
+dependencies = [
+ "crc32fast",
+ "miniz_oxide",
+]
+
+[[package]]
+name = "float-cmp"
+version = "0.9.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "98de4bbd547a563b716d8dfa9aad1cb19bfab00f4fa09a6a4ed21dbcf44ce9c4"
+
+[[package]]
+name = "float-ord"
+version = "0.3.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8ce81f49ae8a0482e4c55ea62ebbd7e5a686af544c00b9d090bba3ff9be97b3d"
+
+[[package]]
+name = "float_next_after"
+version = "1.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8bf7cc16383c4b8d58b9905a8509f02926ce3058053c056376248d958c9df1e8"
+
+[[package]]
+name = "flume"
+version = "0.11.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "da0e4dd2a88388a1f4ccc7c9ce104604dab68d9f408dc34cd45823d5a9069095"
+dependencies = [
+ "futures-core",
+ "futures-sink",
+ "nanorand",
+ "spin",
+]
+
+[[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 = "font-types"
+version = "0.11.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5b38ad915f6dadd993ced50848a8291a543bd41ca62bc10740d5e64e2ab4cfd7"
+dependencies = [
+ "bytemuck",
+]
+
+[[package]]
+name = "fontconfig-parser"
+version = "0.5.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bbc773e24e02d4ddd8395fd30dc147524273a83e54e0f312d986ea30de5f5646"
+dependencies = [
+ "roxmltree",
+]
+
+[[package]]
+name = "fontdb"
+version = "0.16.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b0299020c3ef3f60f526a4f64ab4a3d4ce116b1acbf24cdd22da0068e5d81dc3"
+dependencies = [
+ "fontconfig-parser",
+ "log",
+ "memmap2",
+ "slotmap",
+ "tinyvec",
+ "ttf-parser 0.20.0",
+]
+
+[[package]]
+name = "fontdb"
+version = "0.23.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "457e789b3d1202543297a350643cf459f836cade38934e7a4cf6a39e7cde2905"
+dependencies = [
+ "fontconfig-parser",
+ "log",
+ "memmap2",
+ "slotmap",
+ "tinyvec",
+ "ttf-parser 0.25.1",
+]
+
+[[package]]
+name = "foreign-types"
+version = "0.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d737d9aa519fb7b749cbc3b962edcf310a8dd1f4b67c91c4f83975dbdd17d965"
+dependencies = [
+ "foreign-types-macros",
+ "foreign-types-shared",
+]
+
+[[package]]
+name = "foreign-types-macros"
+version = "0.2.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1a5c6c585bc94aaf2c7b51dd4c2ba22680844aba4c687be581871a6f518c5742"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.117",
+]
+
+[[package]]
+name = "foreign-types-shared"
+version = "0.3.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "aa9a19cbb55df58761df49b23516a86d432839add4af60fc256da840f66ed35b"
+
+[[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 = "freetype-sys"
+version = "0.20.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0e7edc5b9669349acfda99533e9e0bcf26a51862ab43b08ee7745c55d28eb134"
+dependencies = [
+ "cc",
+ "libc",
+ "pkg-config",
+]
+
+[[package]]
+name = "fs2"
+version = "0.4.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9564fc758e15025b46aa6643b1b77d047d1a56a1aea6e01002ac0c7026876213"
+dependencies = [
+ "libc",
+ "winapi",
+]
+
+[[package]]
+name = "fsevent-sys"
+version = "4.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "76ee7a02da4d231650c7cea31349b889be2f45ddb3ef3032d2ec8185f6313fd2"
+dependencies = [
+ "libc",
+]
+
+[[package]]
+name = "futf"
+version = "0.1.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "df420e2e84819663797d1ec6544b13c5be84629e7bb00dc960d6917db2987843"
+dependencies = [
+ "mac",
+ "new_debug_unreachable",
+]
+
+[[package]]
+name = "futures"
+version = "0.3.32"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8b147ee9d1f6d097cef9ce628cd2ee62288d963e16fb287bd9286455b241382d"
+dependencies = [
+ "futures-channel",
+ "futures-core",
+ "futures-executor",
+ "futures-io",
+ "futures-sink",
+ "futures-task",
+ "futures-util",
+]
+
+[[package]]
+name = "futures-bounded"
+version = "0.2.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "91f328e7fb845fc832912fb6a34f40cf6d1888c92f974d1893a54e97b5ff542e"
+dependencies = [
+ "futures-timer",
+ "futures-util",
+]
+
+[[package]]
+name = "futures-channel"
+version = "0.3.32"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "07bbe89c50d7a535e539b8c17bc0b49bdb77747034daa8087407d655f3f7cc1d"
+dependencies = [
+ "futures-core",
+ "futures-sink",
+]
+
+[[package]]
+name = "futures-core"
+version = "0.3.32"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7e3450815272ef58cec6d564423f6e755e25379b217b0bc688e295ba24df6b1d"
+
+[[package]]
+name = "futures-executor"
+version = "0.3.32"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "baf29c38818342a3b26b5b923639e7b1f4a61fc5e76102d4b1981c6dc7a7579d"
+dependencies = [
+ "futures-core",
+ "futures-task",
+ "futures-util",
+]
+
+[[package]]
+name = "futures-io"
+version = "0.3.32"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "cecba35d7ad927e23624b22ad55235f2239cfa44fd10428eecbeba6d6a717718"
+
+[[package]]
+name = "futures-lite"
+version = "1.13.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "49a9d51ce47660b1e808d3c990b4709f2f415d928835a17dfd16991515c46bce"
+dependencies = [
+ "fastrand 1.9.0",
+ "futures-core",
+ "futures-io",
+ "memchr",
+ "parking",
+ "pin-project-lite",
+ "waker-fn",
+]
+
+[[package]]
+name = "futures-lite"
+version = "2.6.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f78e10609fe0e0b3f4157ffab1876319b5b0db102a2c60dc4626306dc46b44ad"
+dependencies = [
+ "fastrand 2.4.1",
+ "futures-core",
+ "futures-io",
+ "parking",
+ "pin-project-lite",
+]
+
+[[package]]
+name = "futures-macro"
+version = "0.3.32"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e835b70203e41293343137df5c0664546da5745f82ec9b84d40be8336958447b"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.117",
+]
+
+[[package]]
+name = "futures-rustls"
+version = "0.26.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a8f2f12607f92c69b12ed746fabf9ca4f5c482cba46679c1a75b874ed7c26adb"
+dependencies = [
+ "futures-io",
+ "rustls",
+ "rustls-pki-types",
+]
+
+[[package]]
+name = "futures-sink"
+version = "0.3.32"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c39754e157331b013978ec91992bde1ac089843443c49cbc7f46150b0fad0893"
+
+[[package]]
+name = "futures-task"
+version = "0.3.32"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "037711b3d59c33004d3856fbdc83b99d4ff37a24768fa1be9ce3538a1cde4393"
+
+[[package]]
+name = "futures-timer"
+version = "3.0.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f288b0a4f20f9a56b5d1da57e2227c661b7b16168e2f72365f57b63326e29b24"
+
+[[package]]
+name = "futures-util"
+version = "0.3.32"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "389ca41296e6190b48053de0321d02a77f32f8a5d2461dd38762c0593805c6d6"
+dependencies = [
+ "futures-channel",
+ "futures-core",
+ "futures-io",
+ "futures-macro",
+ "futures-sink",
+ "futures-task",
+ "memchr",
+ "pin-project-lite",
+ "slab",
+]
+
+[[package]]
+name = "fxhash"
+version = "0.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c31b6d751ae2c7f11320402d34e41349dd1016f8d5d45e48c4312bc8625af50c"
+dependencies = [
+ "byteorder",
+]
+
+[[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 = "gethostname"
+version = "1.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1bd49230192a3797a9a4d6abe9b3eed6f7fa4c8a8a4947977c6f80025f92cbd8"
+dependencies = [
+ "rustix 1.1.4",
+ "windows-link 0.2.1",
+]
+
+[[package]]
+name = "getrandom"
+version = "0.2.17"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ff2abc00be7fca6ebc474524697ae276ad847ad0a6b3faa4bcb027e9a4614ad0"
+dependencies = [
+ "cfg-if",
+ "js-sys",
+ "libc",
+ "wasi",
+ "wasm-bindgen",
+]
+
+[[package]]
+name = "getrandom"
+version = "0.3.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "899def5c37c4fd7b2664648c28120ecec138e4d395b459e5ca34f9cce2dd77fd"
+dependencies = [
+ "cfg-if",
+ "js-sys",
+ "libc",
+ "r-efi 5.3.0",
+ "wasip2",
+ "wasm-bindgen",
+]
+
+[[package]]
+name = "getrandom"
+version = "0.4.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0de51e6874e94e7bf76d726fc5d13ba782deca734ff60d5bb2fb2607c7406555"
+dependencies = [
+ "cfg-if",
+ "libc",
+ "r-efi 6.0.0",
+ "wasip2",
+ "wasip3",
+]
+
+[[package]]
+name = "ghash"
+version = "0.5.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f0d8a4362ccb29cb0b265253fb0a2728f592895ee6854fd9bc13f2ffda266ff1"
+dependencies = [
+ "opaque-debug",
+ "polyval",
+]
+
+[[package]]
+name = "gif"
+version = "0.14.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ee8cfcc411d9adbbaba82fb72661cc1bcca13e8bba98b364e62b2dba8f960159"
+dependencies = [
+ "color_quant",
+ "weezl",
+]
+
+[[package]]
+name = "glob"
+version = "0.3.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0cc23270f6e1808e30a928bdc84dea0b9b4136a8bc82338574f23baf47bbd280"
+
+[[package]]
+name = "globset"
+version = "0.4.18"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "52dfc19153a48bde0cbd630453615c8151bce3a5adfac7a0aebfbf0a1e1f57e3"
+dependencies = [
+ "aho-corasick",
+ "bstr",
+ "log",
+ "regex-automata",
+ "regex-syntax",
+]
+
+[[package]]
+name = "gloo-timers"
+version = "0.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bbb143cf96099802033e0d4f4963b19fd2e0b728bcf076cd9cf7f6634f092994"
+dependencies = [
+ "futures-channel",
+ "futures-core",
+ "js-sys",
+ "wasm-bindgen",
+]
+
+[[package]]
+name = "glow"
+version = "0.16.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c5e5ea60d70410161c8bf5da3fdfeaa1c72ed2c15f8bbb9d19fe3a4fad085f08"
+dependencies = [
+ "js-sys",
+ "slotmap",
+ "wasm-bindgen",
+ "web-sys",
+]
+
+[[package]]
+name = "gpu-alloc"
+version = "0.6.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "fbcd2dba93594b227a1f57ee09b8b9da8892c34d55aa332e034a228d0fe6a171"
+dependencies = [
+ "bitflags 2.11.1",
+ "gpu-alloc-types",
+]
+
+[[package]]
+name = "gpu-alloc-ash"
+version = "0.7.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "cbda7a18a29bc98c2e0de0435c347df935bf59489935d0cbd0b73f1679b6f79a"
+dependencies = [
+ "ash",
+ "gpu-alloc-types",
+ "tinyvec",
+]
+
+[[package]]
+name = "gpu-alloc-types"
+version = "0.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "98ff03b468aa837d70984d55f5d3f846f6ec31fe34bbb97c4f85219caeee1ca4"
+dependencies = [
+ "bitflags 2.11.1",
+]
+
+[[package]]
+name = "gpui"
+version = "0.2.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "979b45cfa6ec723b6f42330915a1b3769b930d02b2d505f9697f8ca602bee707"
+dependencies = [
+ "anyhow",
+ "as-raw-xcb-connection",
+ "ashpd 0.11.1",
+ "async-task",
+ "bindgen",
+ "blade-graphics",
+ "blade-macros",
+ "blade-util",
+ "block",
+ "bytemuck",
+ "calloop",
+ "calloop-wayland-source",
+ "cbindgen",
+ "cocoa 0.26.0",
+ "cocoa-foundation 0.2.0",
+ "core-foundation 0.10.0",
+ "core-foundation-sys",
+ "core-graphics 0.24.0",
+ "core-text",
+ "core-video",
+ "cosmic-text",
+ "ctor",
+ "derive_more",
+ "embed-resource",
+ "etagere",
+ "filedescriptor",
+ "flume",
+ "foreign-types",
+ "futures",
+ "gpui-macros",
+ "gpui_collections",
+ "gpui_http_client",
+ "gpui_media",
+ "gpui_refineable",
+ "gpui_semantic_version",
+ "gpui_sum_tree",
+ "gpui_util",
+ "gpui_util_macros",
+ "image",
+ "inventory",
+ "itertools 0.14.0",
+ "libc",
+ "log",
+ "lyon",
+ "metal",
+ "naga",
+ "num_cpus",
+ "objc",
+ "oo7",
+ "open",
+ "parking",
+ "parking_lot 0.12.5",
+ "pathfinder_geometry",
+ "pin-project",
+ "postage",
+ "profiling",
+ "rand 0.9.4",
+ "raw-window-handle",
+ "resvg",
+ "schemars",
+ "seahash",
+ "serde",
+ "serde_json",
+ "slotmap",
+ "smallvec",
+ "smol",
+ "stacksafe",
+ "strum 0.27.2",
+ "taffy",
+ "thiserror 2.0.18",
+ "usvg",
+ "uuid",
+ "waker-fn",
+ "wayland-backend",
+ "wayland-client",
+ "wayland-cursor",
+ "wayland-protocols 0.31.2",
+ "wayland-protocols-plasma",
+ "windows 0.61.3",
+ "windows-core 0.61.2",
+ "windows-numerics 0.2.0",
+ "windows-registry 0.5.3",
+ "x11-clipboard",
+ "x11rb",
+ "xkbcommon",
+ "zed-font-kit",
+ "zed-scap",
+ "zed-xim",
+]
+
+[[package]]
+name = "gpui-macros"
+version = "0.2.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bcb02dd63a2859714ac7b6b476937617c3c744157af1b49f7c904023a79039be"
+dependencies = [
+ "heck 0.5.0",
+ "proc-macro2",
+ "quote",
+ "syn 2.0.117",
+]
+
+[[package]]
+name = "gpui_collections"
+version = "0.2.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ae39dc6d3d201be97e4bc08d96dbef2bc5b5c3d5734e05786e8cc3043342351c"
+dependencies = [
+ "indexmap",
+ "rustc-hash 2.1.2",
+]
+
+[[package]]
+name = "gpui_derive_refineable"
+version = "0.2.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "644de174341a87b3478bd65b66bca38af868bcf2b2e865700523734f83cfc664"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.117",
+]
+
+[[package]]
+name = "gpui_http_client"
+version = "0.2.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "23822b0a6d2c5e6a42507980a0ab3848610ea908942c8ef98187f646f690335e"
+dependencies = [
+ "anyhow",
+ "async-compression",
+ "async-fs",
+ "bytes",
+ "derive_more",
+ "futures",
+ "gpui_util",
+ "http",
+ "http-body",
+ "log",
+ "parking_lot 0.12.5",
+ "serde",
+ "serde_json",
+ "sha2",
+ "tempfile",
+ "url",
+ "zed-async-tar",
+ "zed-reqwest",
+]
+
+[[package]]
+name = "gpui_media"
+version = "0.2.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "05cb8912ae17371725132d2b7eec6797a255accc95d58ee5c1134b529810f14b"
+dependencies = [
+ "anyhow",
+ "bindgen",
+ "core-foundation 0.10.0",
+ "core-video",
+ "ctor",
+ "foreign-types",
+ "metal",
+ "objc",
+]
+
+[[package]]
+name = "gpui_perf"
+version = "0.2.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f40a0961dcf598955130e867f4b731150a20546427b41b1a63767c1037a86d77"
+dependencies = [
+ "gpui_collections",
+ "serde",
+ "serde_json",
+]
+
+[[package]]
+name = "gpui_refineable"
+version = "0.2.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "258cb099254e9468181aee5614410fba61db4ae115fc1d51b4a0b985f60d6641"
+dependencies = [
+ "gpui_derive_refineable",
+]
+
+[[package]]
+name = "gpui_semantic_version"
+version = "0.2.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "201e45eff7b695528fb3af6560a534943fbc2db5323d755b9d198bd743948e35"
+dependencies = [
+ "anyhow",
+ "serde",
+]
+
+[[package]]
+name = "gpui_sum_tree"
+version = "0.2.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e4f3bedd573fafafa13d1200b356c588cf094fb2786e3684bb3f5ea59b549fa9"
+dependencies = [
+ "arrayvec",
+ "log",
+ "rayon",
+]
+
+[[package]]
+name = "gpui_util"
+version = "0.2.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "68faea25903ae524de9af83990b9aa51bcbc8dd085929ac0aea7fd41905e05c3"
+dependencies = [
+ "anyhow",
+ "async-fs",
+ "async_zip",
+ "command-fds",
+ "dirs 4.0.0",
+ "dunce",
+ "futures",
+ "futures-lite 1.13.0",
+ "globset",
+ "gpui_collections",
+ "itertools 0.14.0",
+ "libc",
+ "log",
+ "nix 0.29.0",
+ "regex",
+ "rust-embed",
+ "schemars",
+ "serde",
+ "serde_json",
+ "serde_json_lenient",
+ "shlex",
+ "smol",
+ "take-until",
+ "tempfile",
+ "tendril",
+ "unicase",
+ "walkdir",
+ "which",
+]
+
+[[package]]
+name = "gpui_util_macros"
+version = "0.2.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2c28f65ef47fb97e21e82fd4dd75ccc2506eda010c846dc8054015ea234f1a22"
+dependencies = [
+ "gpui_perf",
+ "quote",
+ "syn 2.0.117",
+]
+
+[[package]]
+name = "grid"
+version = "0.18.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "12101ecc8225ea6d675bc70263074eab6169079621c2186fe0c66590b2df9681"
+
+[[package]]
+name = "h2"
+version = "0.4.14"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "171fefbc92fe4a4de27e0698d6a5b392d6a0e333506bc49133760b3bcf948733"
+dependencies = [
+ "atomic-waker",
+ "bytes",
+ "fnv",
+ "futures-core",
+ "futures-sink",
+ "http",
+ "indexmap",
+ "slab",
+ "tokio",
+ "tokio-util",
+ "tracing",
+]
+
+[[package]]
+name = "half"
+version = "2.7.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6ea2d84b969582b4b1864a92dc5d27cd2b77b622a8d79306834f1be5ba20d84b"
+dependencies = [
+ "cfg-if",
+ "crunchy",
+ "num-traits",
+ "zerocopy",
+]
+
+[[package]]
+name = "hash32"
+version = "0.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b0c35f58762feb77d74ebe43bdbc3210f09be9fe6742234d573bacc26ed92b67"
+dependencies = [
+ "byteorder",
+]
+
+[[package]]
+name = "hashbrown"
+version = "0.14.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1"
+dependencies = [
+ "ahash",
+]
+
+[[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.17.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4f467dd6dccf739c208452f8014c75c18bb8301b050ad1cfb27153803edb0f51"
+
+[[package]]
+name = "hashlink"
+version = "0.9.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6ba4ff7128dee98c7dc9794b6a411377e1404dba1c97deb8d1a55297bd25d8af"
+dependencies = [
+ "hashbrown 0.14.5",
+]
+
+[[package]]
+name = "hashlink"
+version = "0.10.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7382cf6263419f2d8df38c55d7da83da5c18aef87fc7a7fc1fb1e344edfe14c1"
+dependencies = [
+ "hashbrown 0.15.5",
+]
+
+[[package]]
+name = "heapless"
+version = "0.7.17"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "cdc6457c0eb62c71aac4bc17216026d8410337c4126773b9c5daba343f17964f"
+dependencies = [
+ "atomic-polyfill",
+ "hash32",
+ "rustc_version",
+ "serde",
+ "spin",
+ "stable_deref_trait",
+]
+
+[[package]]
+name = "heck"
+version = "0.4.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8"
+
+[[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 = "hexf-parse"
+version = "0.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "dfa686283ad6dd069f105e5ab091b04c62850d3e4cf5d67debad1933f55023df"
+
+[[package]]
+name = "hickory-proto"
+version = "0.25.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f8a6fe56c0038198998a6f217ca4e7ef3a5e51f46163bd6dd60b5c71ca6c6502"
+dependencies = [
+ "async-trait",
+ "cfg-if",
+ "data-encoding",
+ "enum-as-inner",
+ "futures-channel",
+ "futures-io",
+ "futures-util",
+ "idna",
+ "ipnet",
+ "once_cell",
+ "rand 0.9.4",
+ "ring",
+ "socket2 0.5.10",
+ "thiserror 2.0.18",
+ "tinyvec",
+ "tokio",
+ "tracing",
+ "url",
+]
+
+[[package]]
+name = "hickory-resolver"
+version = "0.25.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "dc62a9a99b0bfb44d2ab95a7208ac952d31060efc16241c87eaf36406fecf87a"
+dependencies = [
+ "cfg-if",
+ "futures-util",
+ "hickory-proto",
+ "ipconfig",
+ "moka",
+ "once_cell",
+ "parking_lot 0.12.5",
+ "rand 0.9.4",
+ "resolv-conf",
+ "smallvec",
+ "thiserror 2.0.18",
+ "tokio",
+ "tracing",
+]
+
+[[package]]
+name = "hidden-trait"
+version = "0.1.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "68ed9e850438ac849bec07e7d09fbe9309cbd396a5988c30b010580ce08860df"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 1.0.109",
+]
+
+[[package]]
+name = "hkdf"
+version = "0.12.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7b5f8eb2ad728638ea2c7d47a21db23b7b58a72ed6a38256b8a1849f15fbbdf7"
+dependencies = [
+ "hmac",
+]
+
+[[package]]
+name = "hmac"
+version = "0.12.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e"
+dependencies = [
+ "digest",
+]
+
+[[package]]
+name = "home"
+version = "0.5.12"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "cc627f471c528ff0c4a49e1d5e60450c8f6461dd6d10ba9dcd3a61d3dff7728d"
+dependencies = [
+ "windows-sys 0.61.2",
+]
+
+[[package]]
+name = "http"
+version = "1.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e3ba2a386d7f85a81f119ad7498ebe444d2e22c2af0b86b069416ace48b3311a"
+dependencies = [
+ "bytes",
+ "itoa",
+]
+
+[[package]]
+name = "http-body"
+version = "1.0.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1efedce1fb8e6913f23e0c92de8e62cd5b772a67e7b3946df930a62566c93184"
+dependencies = [
+ "bytes",
+ "http",
+]
+
+[[package]]
+name = "http-body-util"
+version = "0.1.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b021d93e26becf5dc7e1b75b1bed1fd93124b374ceb73f43d4d4eafec896a64a"
+dependencies = [
+ "bytes",
+ "futures-core",
+ "http",
+ "http-body",
+ "pin-project-lite",
+]
+
+[[package]]
+name = "httparse"
+version = "1.10.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6dbf3de79e51f3d586ab4cb9d5c3e2c14aa28ed23d180cf89b4df0454a69cc87"
+
+[[package]]
+name = "hyper"
+version = "1.9.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6299f016b246a94207e63da54dbe807655bf9e00044f73ded42c3ac5305fbcca"
+dependencies = [
+ "atomic-waker",
+ "bytes",
+ "futures-channel",
+ "futures-core",
+ "h2",
+ "http",
+ "http-body",
+ "httparse",
+ "itoa",
+ "pin-project-lite",
+ "smallvec",
+ "tokio",
+ "want",
+]
+
+[[package]]
+name = "hyper-rustls"
+version = "0.27.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "33ca68d021ef39cf6463ab54c1d0f5daf03377b70561305bb89a8f83aab66e0f"
+dependencies = [
+ "http",
+ "hyper",
+ "hyper-util",
+ "rustls",
+ "rustls-native-certs",
+ "tokio",
+ "tokio-rustls",
+ "tower-service",
+]
+
+[[package]]
+name = "hyper-util"
+version = "0.1.20"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "96547c2556ec9d12fb1578c4eaf448b04993e7fb79cbaad930a656880a6bdfa0"
+dependencies = [
+ "bytes",
+ "futures-channel",
+ "futures-util",
+ "http",
+ "http-body",
+ "hyper",
+ "libc",
+ "pin-project-lite",
+ "socket2 0.6.3",
+ "tokio",
+ "tower-service",
+ "tracing",
+]
+
+[[package]]
+name = "icu_collections"
+version = "2.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2984d1cd16c883d7935b9e07e44071dca8d917fd52ecc02c04d5fa0b5a3f191c"
+dependencies = [
+ "displaydoc",
+ "potential_utf",
+ "utf8_iter",
+ "yoke",
+ "zerofrom",
+ "zerovec",
+]
+
+[[package]]
+name = "icu_locale_core"
+version = "2.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "92219b62b3e2b4d88ac5119f8904c10f8f61bf7e95b640d25ba3075e6cac2c29"
+dependencies = [
+ "displaydoc",
+ "litemap",
+ "tinystr",
+ "writeable",
+ "zerovec",
+]
+
+[[package]]
+name = "icu_normalizer"
+version = "2.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c56e5ee99d6e3d33bd91c5d85458b6005a22140021cc324cea84dd0e72cff3b4"
+dependencies = [
+ "icu_collections",
+ "icu_normalizer_data",
+ "icu_properties",
+ "icu_provider",
+ "smallvec",
+ "zerovec",
+]
+
+[[package]]
+name = "icu_normalizer_data"
+version = "2.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "da3be0ae77ea334f4da67c12f149704f19f81d1adf7c51cf482943e84a2bad38"
+
+[[package]]
+name = "icu_properties"
+version = "2.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bee3b67d0ea5c2cca5003417989af8996f8604e34fb9ddf96208a033901e70de"
+dependencies = [
+ "icu_collections",
+ "icu_locale_core",
+ "icu_properties_data",
+ "icu_provider",
+ "zerotrie",
+ "zerovec",
+]
+
+[[package]]
+name = "icu_properties_data"
+version = "2.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8e2bbb201e0c04f7b4b3e14382af113e17ba4f63e2c9d2ee626b720cbce54a14"
+
+[[package]]
+name = "icu_provider"
+version = "2.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "139c4cf31c8b5f33d7e199446eff9c1e02decfc2f0eec2c8d71f65befa45b421"
+dependencies = [
+ "displaydoc",
+ "icu_locale_core",
+ "writeable",
+ "yoke",
+ "zerofrom",
+ "zerotrie",
+ "zerovec",
+]
+
+[[package]]
+name = "id-arena"
+version = "2.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3d3067d79b975e8844ca9eb072e16b31c3c1c36928edf9c6789548c524d0d954"
+
+[[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.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "cb68373c0d6620ef8105e855e7745e18b0d00d3bdb07fb532e434244cdb9a714"
+dependencies = [
+ "icu_normalizer",
+ "icu_properties",
+]
+
+[[package]]
+name = "if-addrs"
+version = "0.15.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c0a05c691e1fae256cf7013d99dad472dc52d5543322761f83ec8d47eab40d2b"
+dependencies = [
+ "libc",
+ "windows-sys 0.61.2",
+]
+
+[[package]]
+name = "if-watch"
+version = "3.2.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "71c02a5161c313f0cbdbadc511611893584a10a7b6153cb554bdf83ddce99ec2"
+dependencies = [
+ "async-io",
+ "core-foundation 0.9.4",
+ "fnv",
+ "futures",
+ "if-addrs",
+ "ipnet",
+ "log",
+ "netlink-packet-core",
+ "netlink-packet-route",
+ "netlink-proto",
+ "netlink-sys",
+ "rtnetlink",
+ "system-configuration 0.7.0",
+ "tokio",
+ "windows 0.62.2",
+]
+
+[[package]]
+name = "igd-next"
+version = "0.16.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "516893339c97f6011282d5825ac94fc1c7aad5cad26bdc2d0cee068c0bf97f97"
+dependencies = [
+ "async-trait",
+ "attohttpc",
+ "bytes",
+ "futures",
+ "http",
+ "http-body-util",
+ "hyper",
+ "hyper-util",
+ "log",
+ "rand 0.9.4",
+ "tokio",
+ "url",
+ "xmltree",
+]
+
+[[package]]
+name = "image"
+version = "0.25.10"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "85ab80394333c02fe689eaf900ab500fbd0c2213da414687ebf995a65d5a6104"
+dependencies = [
+ "bytemuck",
+ "byteorder-lite",
+ "color_quant",
+ "exr",
+ "gif",
+ "image-webp",
+ "moxcms",
+ "num-traits",
+ "png 0.18.1",
+ "qoi",
+ "ravif",
+ "rayon",
+ "rgb",
+ "tiff",
+ "zune-core",
+ "zune-jpeg",
+]
+
+[[package]]
+name = "image-webp"
+version = "0.2.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "525e9ff3e1a4be2fbea1fdf0e98686a6d98b4d8f937e1bf7402245af1909e8c3"
+dependencies = [
+ "byteorder-lite",
+ "quick-error",
+]
+
+[[package]]
+name = "imagesize"
+version = "0.13.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "edcd27d72f2f071c64249075f42e205ff93c9a4c5f6c6da53e79ed9f9832c285"
+
+[[package]]
+name = "imgref"
+version = "1.12.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "40fac9d56ed6437b198fddba683305e8e2d651aa42647f00f5ae542e7f5c94a2"
+
+[[package]]
+name = "indexmap"
+version = "2.14.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d466e9454f08e4a911e14806c24e16fba1b4c121d1ea474396f396069cf949d9"
+dependencies = [
+ "equivalent",
+ "hashbrown 0.17.0",
+ "serde",
+ "serde_core",
+]
+
+[[package]]
+name = "inotify"
+version = "0.9.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f8069d3ec154eb856955c1c0fbffefbf5f3c40a104ec912d4797314c1801abff"
+dependencies = [
+ "bitflags 1.3.2",
+ "inotify-sys",
+ "libc",
+]
+
+[[package]]
+name = "inotify-sys"
+version = "0.1.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e05c02b5e89bff3b946cedeca278abc628fe811e604f027c45a8aa3cf793d0eb"
+dependencies = [
+ "libc",
+]
+
+[[package]]
+name = "inout"
+version = "0.1.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "879f10e63c20629ecabbb64a8010319738c66a5cd0c29b02d63d272b03751d01"
+dependencies = [
+ "block-padding",
+ "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 = "interpolate_name"
+version = "0.2.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c34819042dc3d3971c46c2190835914dfbe0c3c13f61449b2997f4e9722dfa60"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.117",
+]
+
+[[package]]
+name = "inventory"
+version = "0.3.24"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a4f0c30c76f2f4ccee3fe55a2435f691ca00c0e4bd87abe4f4a851b1d4dac39b"
+dependencies = [
+ "rustversion",
+]
+
+[[package]]
+name = "io-surface"
+version = "0.16.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "554b8c5d64ec09a3a520fe58e4d48a73e00ff32899cdcbe32a4877afd4968b8e"
+dependencies = [
+ "cgl",
+ "core-foundation 0.10.0",
+ "core-foundation-sys",
+ "leaky-cow",
+]
+
+[[package]]
+name = "ipconfig"
+version = "0.3.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4d40460c0ce33d6ce4b0630ad68ff63d6661961c48b6dba35e5a4d81cfb48222"
+dependencies = [
+ "socket2 0.6.3",
+ "widestring",
+ "windows-registry 0.6.1",
+ "windows-result 0.4.1",
+ "windows-sys 0.61.2",
+]
+
+[[package]]
+name = "ipnet"
+version = "2.12.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d98f6fed1fde3f8c21bc40a1abb88dd75e67924f9cffc3ef95607bad8017f8e2"
+
+[[package]]
+name = "is-docker"
+version = "0.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "928bae27f42bc99b60d9ac7334e3a21d10ad8f1835a4e12ec3ec0464765ed1b3"
+dependencies = [
+ "once_cell",
+]
+
+[[package]]
+name = "is-wsl"
+version = "0.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "173609498df190136aa7dea1a91db051746d339e18476eed5ca40521f02d7aa5"
+dependencies = [
+ "is-docker",
+ "once_cell",
+]
+
+[[package]]
+name = "is_terminal_polyfill"
+version = "1.70.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a6cb138bb79a146c1bd460005623e142ef0181e3d0219cb493e02f7d08a35695"
+
+[[package]]
+name = "itertools"
+version = "0.13.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "413ee7dfc52ee1a4949ceeb7dbc8a33f2d6c088194d9f922fb8318faf1f01186"
+dependencies = [
+ "either",
+]
+
+[[package]]
+name = "itertools"
+version = "0.14.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2b192c782037fadd9cfa75548310488aabdbf3d2da73885b31bd0abd03351285"
+dependencies = [
+ "either",
+]
+
+[[package]]
+name = "itoa"
+version = "1.0.18"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682"
+
+[[package]]
+name = "jobserver"
+version = "0.1.34"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9afb3de4395d6b3e67a780b6de64b51c978ecf11cb9a462c66be7d4ca9039d33"
+dependencies = [
+ "getrandom 0.3.4",
+ "libc",
+]
+
+[[package]]
+name = "js-sys"
+version = "0.3.98"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "67df7112613f8bfd9150013a0314e196f4800d3201ae742489d999db2f979f08"
+dependencies = [
+ "cfg-if",
+ "futures-util",
+ "once_cell",
+ "wasm-bindgen",
+]
+
+[[package]]
+name = "khronos-egl"
+version = "6.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6aae1df220ece3c0ada96b8153459b67eebe9ae9212258bb0134ae60416fdf76"
+dependencies = [
+ "libc",
+ "libloading",
+]
+
+[[package]]
+name = "kqueue"
+version = "1.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "eac30106d7dce88daf4a3fcb4879ea939476d5074a9b7ddd0fb97fa4bed5596a"
+dependencies = [
+ "kqueue-sys",
+ "libc",
+]
+
+[[package]]
+name = "kqueue-sys"
+version = "1.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a7b65860415f949f23fa882e669f2dbd4a0f0eeb1acdd56790b30494afd7da2f"
+dependencies = [
+ "bitflags 2.11.1",
+ "libc",
+]
+
+[[package]]
+name = "kurbo"
+version = "0.11.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c62026ae44756f8a599ba21140f350303d4f08dcdcc71b5ad9c9bb8128c13c62"
+dependencies = [
+ "arrayvec",
+ "euclid",
+ "smallvec",
+]
+
+[[package]]
+name = "kv-log-macro"
+version = "1.0.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0de8b303297635ad57c9f5059fd9cee7a47f8e8daa09df0fcd07dd39fb22977f"
+dependencies = [
+ "log",
+]
+
+[[package]]
+name = "lazy_static"
+version = "1.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe"
+dependencies = [
+ "spin",
+]
+
+[[package]]
+name = "leak"
+version = "0.1.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bd100e01f1154f2908dfa7d02219aeab25d0b9c7fa955164192e3245255a0c73"
+
+[[package]]
+name = "leaky-cow"
+version = "0.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "40a8225d44241fd324a8af2806ba635fc7c8a7e9a7de4d5cf3ef54e71f5926fc"
+dependencies = [
+ "leak",
+]
+
+[[package]]
+name = "leb128fmt"
+version = "0.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "09edd9e8b54e49e587e4f6295a7d29c3ea94d469cb40ab8ca70b288248a81db2"
+
+[[package]]
+name = "lebe"
+version = "0.5.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7a79a3332a6609480d7d0c9eab957bca6b455b91bb84e66d19f5ff66294b85b8"
+
+[[package]]
+name = "libc"
+version = "0.2.186"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "68ab91017fe16c622486840e4c83c9a37afeff978bd239b5293d61ece587de66"
+
+[[package]]
+name = "libfuzzer-sys"
+version = "0.4.12"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f12a681b7dd8ce12bff52488013ba614b869148d54dd79836ab85aafdd53f08d"
+dependencies = [
+ "arbitrary",
+ "cc",
+]
+
+[[package]]
+name = "libloading"
+version = "0.8.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d7c4b02199fee7c5d21a5ae7d8cfa79a6ef5bb2fc834d6e9058e89c825efdc55"
+dependencies = [
+ "cfg-if",
+ "windows-link 0.2.1",
+]
+
+[[package]]
+name = "libm"
+version = "0.2.16"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b6d2cec3eae94f9f509c767b45932f1ada8350c4bdb85af2fcab4a3c14807981"
+
+[[package]]
+name = "libp2p"
+version = "0.56.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ce71348bf5838e46449ae240631117b487073d5f347c06d434caddcb91dceb5a"
+dependencies = [
+ "bytes",
+ "either",
+ "futures",
+ "futures-timer",
+ "getrandom 0.2.17",
+ "libp2p-allow-block-list",
+ "libp2p-connection-limits",
+ "libp2p-core",
+ "libp2p-dns",
+ "libp2p-identify",
+ "libp2p-identity",
+ "libp2p-kad",
+ "libp2p-mdns",
+ "libp2p-metrics",
+ "libp2p-noise",
+ "libp2p-quic",
+ "libp2p-swarm",
+ "libp2p-tcp",
+ "libp2p-upnp",
+ "libp2p-yamux",
+ "multiaddr",
+ "pin-project",
+ "rw-stream-sink",
+ "thiserror 2.0.18",
+]
+
+[[package]]
+name = "libp2p-allow-block-list"
+version = "0.6.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d16ccf824ee859ca83df301e1c0205270206223fd4b1f2e512a693e1912a8f4a"
+dependencies = [
+ "libp2p-core",
+ "libp2p-identity",
+ "libp2p-swarm",
+]
+
+[[package]]
+name = "libp2p-connection-limits"
+version = "0.6.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a18b8b607cf3bfa2f8c57db9c7d8569a315d5cc0a282e6bfd5ebfc0a9840b2a0"
+dependencies = [
+ "libp2p-core",
+ "libp2p-identity",
+ "libp2p-swarm",
+]
+
+[[package]]
+name = "libp2p-core"
+version = "0.43.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "249128cd37a2199aff30a7675dffa51caf073b51aa612d2f544b19932b9aebca"
+dependencies = [
+ "either",
+ "fnv",
+ "futures",
+ "futures-timer",
+ "libp2p-identity",
+ "multiaddr",
+ "multihash",
+ "multistream-select",
+ "parking_lot 0.12.5",
+ "pin-project",
+ "quick-protobuf",
+ "rand 0.8.6",
+ "rw-stream-sink",
+ "thiserror 2.0.18",
+ "tracing",
+ "unsigned-varint 0.8.0",
+ "web-time",
+]
+
+[[package]]
+name = "libp2p-dns"
+version = "0.44.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0b770c1c8476736ca98c578cba4b505104ff8e842c2876b528925f9766379f9a"
+dependencies = [
+ "async-trait",
+ "futures",
+ "hickory-resolver",
+ "libp2p-core",
+ "libp2p-identity",
+ "parking_lot 0.12.5",
+ "smallvec",
+ "tracing",
+]
+
+[[package]]
+name = "libp2p-identify"
+version = "0.47.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8ab792a8b68fdef443a62155b01970c81c3aadab5e659621b063ef252a8e65e8"
+dependencies = [
+ "asynchronous-codec",
+ "either",
+ "futures",
+ "futures-bounded",
+ "futures-timer",
+ "libp2p-core",
+ "libp2p-identity",
+ "libp2p-swarm",
+ "quick-protobuf",
+ "quick-protobuf-codec",
+ "smallvec",
+ "thiserror 2.0.18",
+ "tracing",
+]
+
+[[package]]
+name = "libp2p-identity"
+version = "0.2.13"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f0c7892c221730ba55f7196e98b0b8ba5e04b4155651736036628e9f73ed6fc3"
+dependencies = [
+ "bs58",
+ "ed25519-dalek",
+ "hkdf",
+ "multihash",
+ "quick-protobuf",
+ "rand 0.8.6",
+ "sha2",
+ "thiserror 2.0.18",
+ "tracing",
+ "zeroize",
+]
+
+[[package]]
+name = "libp2p-kad"
+version = "0.48.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "13d3fd632a5872ec804d37e7413ceea20588f69d027a0fa3c46f82574f4dee60"
+dependencies = [
+ "asynchronous-codec",
+ "bytes",
+ "either",
+ "fnv",
+ "futures",
+ "futures-bounded",
+ "futures-timer",
+ "libp2p-core",
+ "libp2p-identity",
+ "libp2p-swarm",
+ "quick-protobuf",
+ "quick-protobuf-codec",
+ "rand 0.8.6",
+ "sha2",
+ "smallvec",
+ "thiserror 2.0.18",
+ "tracing",
+ "uint",
+ "web-time",
+]
+
+[[package]]
+name = "libp2p-mdns"
+version = "0.48.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c66872d0f1ffcded2788683f76931be1c52e27f343edb93bc6d0bcd8887be443"
+dependencies = [
+ "futures",
+ "hickory-proto",
+ "if-watch",
+ "libp2p-core",
+ "libp2p-identity",
+ "libp2p-swarm",
+ "rand 0.8.6",
+ "smallvec",
+ "socket2 0.5.10",
+ "tokio",
+ "tracing",
+]
+
+[[package]]
+name = "libp2p-metrics"
+version = "0.17.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "805a555148522cb3414493a5153451910cb1a146c53ffbf4385708349baf62b7"
+dependencies = [
+ "futures",
+ "libp2p-core",
+ "libp2p-identify",
+ "libp2p-identity",
+ "libp2p-kad",
+ "libp2p-swarm",
+ "pin-project",
+ "prometheus-client",
+ "web-time",
+]
+
+[[package]]
+name = "libp2p-noise"
+version = "0.46.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bc73eacbe6462a0eb92a6527cac6e63f02026e5407f8831bde8293f19217bfbf"
+dependencies = [
+ "asynchronous-codec",
+ "bytes",
+ "futures",
+ "libp2p-core",
+ "libp2p-identity",
+ "multiaddr",
+ "multihash",
+ "quick-protobuf",
+ "rand 0.8.6",
+ "snow",
+ "static_assertions",
+ "thiserror 2.0.18",
+ "tracing",
+ "x25519-dalek",
+ "zeroize",
+]
+
+[[package]]
+name = "libp2p-quic"
+version = "0.13.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8dc448b2de9f4745784e3751fe8bc6c473d01b8317edd5ababcb0dec803d843f"
+dependencies = [
+ "futures",
+ "futures-timer",
+ "if-watch",
+ "libp2p-core",
+ "libp2p-identity",
+ "libp2p-tls",
+ "quinn",
+ "rand 0.8.6",
+ "ring",
+ "rustls",
+ "socket2 0.5.10",
+ "thiserror 2.0.18",
+ "tokio",
+ "tracing",
+]
+
+[[package]]
+name = "libp2p-stream"
+version = "0.4.0-alpha"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1d6bd8025c80205ec2810cfb28b02f362ab48a01bee32c50ab5f12761e033464"
+dependencies = [
+ "futures",
+ "libp2p-core",
+ "libp2p-identity",
+ "libp2p-swarm",
+ "rand 0.8.6",
+ "tracing",
+]
+
+[[package]]
+name = "libp2p-swarm"
+version = "0.47.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ce88c6c4bf746c8482480345ea3edfd08301f49e026889d1cbccfa1808a9ed9e"
+dependencies = [
+ "either",
+ "fnv",
+ "futures",
+ "futures-timer",
+ "hashlink 0.10.0",
+ "libp2p-core",
+ "libp2p-identity",
+ "libp2p-swarm-derive",
+ "multistream-select",
+ "rand 0.8.6",
+ "smallvec",
+ "tokio",
+ "tracing",
+ "web-time",
+]
+
+[[package]]
+name = "libp2p-swarm-derive"
+version = "0.35.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "dd297cf53f0cb3dee4d2620bb319ae47ef27c702684309f682bdb7e55a18ae9c"
+dependencies = [
+ "heck 0.5.0",
+ "quote",
+ "syn 2.0.117",
+]
+
+[[package]]
+name = "libp2p-tcp"
+version = "0.44.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "fb6585b9309699f58704ec9ab0bb102eca7a3777170fa91a8678d73ca9cafa93"
+dependencies = [
+ "futures",
+ "futures-timer",
+ "if-watch",
+ "libc",
+ "libp2p-core",
+ "socket2 0.6.3",
+ "tokio",
+ "tracing",
+]
+
+[[package]]
+name = "libp2p-tls"
+version = "0.6.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "96ff65a82e35375cbc31ebb99cacbbf28cb6c4fefe26bf13756ddcf708d40080"
+dependencies = [
+ "futures",
+ "futures-rustls",
+ "libp2p-core",
+ "libp2p-identity",
+ "rcgen",
+ "ring",
+ "rustls",
+ "rustls-webpki",
+ "thiserror 2.0.18",
+ "x509-parser",
+ "yasna",
+]
+
+[[package]]
+name = "libp2p-upnp"
+version = "0.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4757e65fe69399c1a243bbb90ec1ae5a2114b907467bf09f3575e899815bb8d3"
+dependencies = [
+ "futures",
+ "futures-timer",
+ "igd-next",
+ "libp2p-core",
+ "libp2p-swarm",
+ "tokio",
+ "tracing",
+]
+
+[[package]]
+name = "libp2p-yamux"
+version = "0.47.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f15df094914eb4af272acf9adaa9e287baa269943f32ea348ba29cfb9bfc60d8"
+dependencies = [
+ "either",
+ "futures",
+ "libp2p-core",
+ "thiserror 2.0.18",
+ "tracing",
+ "yamux 0.12.1",
+ "yamux 0.13.10",
+]
+
+[[package]]
+name = "libredox"
+version = "0.1.16"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e02f3bb43d335493c96bf3fd3a321600bf6bd07ed34bc64118e9293bdffea46c"
+dependencies = [
+ "bitflags 2.11.1",
+ "libc",
+ "plain",
+ "redox_syscall 0.7.5",
+]
+
+[[package]]
+name = "libsqlite3-sys"
+version = "0.28.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0c10584274047cb335c23d3e61bcef8e323adae7c5c8c760540f73610177fc3f"
+dependencies = [
+ "cc",
+ "pkg-config",
+ "vcpkg",
+]
+
+[[package]]
+name = "linux-raw-sys"
+version = "0.4.15"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d26c52dbd32dccf2d10cac7725f8eae5296885fb5703b261f7d0a0739ec807ab"
+
+[[package]]
+name = "linux-raw-sys"
+version = "0.12.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "32a66949e030da00e8c7d4434b251670a91556f4144941d37452769c25d58a53"
+
+[[package]]
+name = "litemap"
+version = "0.8.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "92daf443525c4cce67b150400bc2316076100ce0b3686209eb8cf3c31612e6f0"
+
+[[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.29"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5e5032e24019045c762d3c0f28f5b6b8bbf38563a65908389bf7978758920897"
+dependencies = [
+ "serde_core",
+ "value-bag",
+]
+
+[[package]]
+name = "loop9"
+version = "0.1.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0fae87c125b03c1d2c0150c90365d7d6bcc53fb73a9acaef207d2d065860f062"
+dependencies = [
+ "imgref",
+]
+
+[[package]]
+name = "lru-slab"
+version = "0.1.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "112b39cec0b298b6c1999fee3e31427f74f676e4cb9879ed1a121b43661a4154"
+
+[[package]]
+name = "lyon"
+version = "1.0.19"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bd0578bdecb7d6d88987b8b2b1e3a4e2f81df9d0ece1078623324a567904e7b7"
+dependencies = [
+ "lyon_algorithms",
+ "lyon_tessellation",
+]
+
+[[package]]
+name = "lyon_algorithms"
+version = "1.0.20"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8575c0d003ae459399623c4def180c63b77f343b1a7fee64f249b349e7699a31"
+dependencies = [
+ "lyon_path",
+ "num-traits",
+]
+
+[[package]]
+name = "lyon_geom"
+version = "1.0.19"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4336502e29e32af93cf2dad2214ed6003c17ceb5bd499df77b1de663b9042b92"
+dependencies = [
+ "arrayvec",
+ "euclid",
+ "num-traits",
+]
+
+[[package]]
+name = "lyon_path"
+version = "1.0.19"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5c463f9c428b7fc5ec885dcd39ce4aa61e29111d0e33483f6f98c74e89d8621e"
+dependencies = [
+ "lyon_geom",
+ "num-traits",
+]
+
+[[package]]
+name = "lyon_tessellation"
+version = "1.0.20"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8e43b7e44161571868f5c931d12583592c223c5583eef86b08aa02b7048a3552"
+dependencies = [
+ "float_next_after",
+ "lyon_path",
+ "num-traits",
+]
+
+[[package]]
+name = "mac"
+version = "0.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c41e0c4fef86961ac6d6f8a82609f55f31b05e4fce149ac5710e439df7619ba4"
+
+[[package]]
+name = "malloc_buf"
+version = "0.0.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "62bb907fe88d54d8d9ce32a3cceab4218ed2f6b7d35617cafe9adf84e43919cb"
+dependencies = [
+ "libc",
+]
+
+[[package]]
+name = "match-lookup"
+version = "0.1.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "757aee279b8bdbb9f9e676796fd459e4207a1f986e87886700abf589f5abf771"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.117",
+]
+
+[[package]]
+name = "matchers"
+version = "0.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d1525a2a28c7f4fa0fc98bb91ae755d1e2d1505079e05539e35bc876b5d65ae9"
+dependencies = [
+ "regex-automata",
+]
+
+[[package]]
+name = "maybe-rayon"
+version = "0.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8ea1f30cedd69f0a2954655f7188c6a834246d2bcf1e315e2ac40c4b24dc9519"
+dependencies = [
+ "cfg-if",
+ "rayon",
+]
+
+[[package]]
+name = "md-5"
+version = "0.10.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d89e7ee0cfbedfc4da3340218492196241d89eefb6dab27de5df917a6d2e78cf"
+dependencies = [
+ "cfg-if",
+ "digest",
+]
+
+[[package]]
+name = "memchr"
+version = "2.8.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f8ca58f447f06ed17d5fc4043ce1b10dd205e060fb3ce5b979b8ed8e59ff3f79"
+
+[[package]]
+name = "memmap2"
+version = "0.9.10"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "714098028fe011992e1c3962653c96b2d578c4b4bce9036e15ff220319b1e0e3"
+dependencies = [
+ "libc",
+]
+
+[[package]]
+name = "memoffset"
+version = "0.9.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "488016bfae457b036d996092f6cb448677611ce4449e970ceaf42695203f218a"
+dependencies = [
+ "autocfg",
+]
+
+[[package]]
+name = "metal"
+version = "0.29.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7ecfd3296f8c56b7c1f6fbac3c71cefa9d78ce009850c45000015f206dc7fa21"
+dependencies = [
+ "bitflags 2.11.1",
+ "block",
+ "core-graphics-types 0.1.3",
+ "foreign-types",
+ "log",
+ "objc",
+ "paste",
+]
+
+[[package]]
+name = "mime"
+version = "0.3.17"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a"
+
+[[package]]
+name = "mime_guess"
+version = "2.0.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f7c44f8e672c00fe5308fa235f821cb4198414e1c77935c1ab6948d3fd78550e"
+dependencies = [
+ "mime",
+ "unicase",
+]
+
+[[package]]
+name = "minga-cli"
+version = "0.1.0"
+dependencies = [
+ "clap",
+ "futures",
+ "libp2p",
+ "minga-core",
+ "minga-p2p",
+ "minga-store",
+ "notify",
+ "rpassword",
+ "tempfile",
+ "thiserror 2.0.18",
+ "tokio",
+]
+
+[[package]]
+name = "minga-core"
+version = "0.1.0"
+dependencies = [
+ "aes-gcm",
+ "argon2",
+ "blake3",
+ "ed25519-dalek",
+ "postcard",
+ "rand 0.8.6",
+ "serde",
+ "serde-big-array",
+ "thiserror 2.0.18",
+ "tree-sitter",
+ "tree-sitter-rust",
+]
+
+[[package]]
+name = "minga-p2p"
+version = "0.1.0"
+dependencies = [
+ "futures",
+ "libp2p",
+ "libp2p-stream",
+ "minga-core",
+ "minga-store",
+ "postcard",
+ "rand 0.8.6",
+ "serde",
+ "tempfile",
+ "thiserror 2.0.18",
+ "tokio",
+ "tokio-util",
+]
+
+[[package]]
+name = "minga-store"
+version = "0.1.0"
+dependencies = [
+ "blake3",
+ "minga-core",
+ "postcard",
+ "serde",
+ "sled",
+ "tempfile",
+ "thiserror 2.0.18",
+]
+
+[[package]]
+name = "minga-vfs"
+version = "0.1.0"
+dependencies = [
+ "minga-core",
+]
+
+[[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",
+ "simd-adler32",
+]
+
+[[package]]
+name = "mint"
+version = "0.5.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e53debba6bda7a793e5f99b8dacf19e626084f525f7829104ba9898f367d85ff"
+
+[[package]]
+name = "mio"
+version = "0.8.11"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a4a650543ca06a924e8b371db273b2756685faae30f8487da1b56505a8f78b0c"
+dependencies = [
+ "libc",
+ "log",
+ "wasi",
+ "windows-sys 0.48.0",
+]
+
+[[package]]
+name = "mio"
+version = "1.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "50b7e5b27aa02a74bac8c3f23f448f8d87ff11f92d3aac1a6ed369ee08cc56c1"
+dependencies = [
+ "libc",
+ "wasi",
+ "windows-sys 0.61.2",
+]
+
+[[package]]
+name = "moka"
+version = "0.12.15"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "957228ad12042ee839f93c8f257b62b4c0ab5eaae1d4fa60de53b27c9d7c5046"
+dependencies = [
+ "crossbeam-channel",
+ "crossbeam-epoch",
+ "crossbeam-utils",
+ "equivalent",
+ "parking_lot 0.12.5",
+ "portable-atomic",
+ "smallvec",
+ "tagptr",
+ "uuid",
+]
+
+[[package]]
+name = "moxcms"
+version = "0.8.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bb85c154ba489f01b25c0d36ae69a87e4a1c73a72631fc6c0eb6dde34a73e44b"
+dependencies = [
+ "num-traits",
+ "pxfm",
+]
+
+[[package]]
+name = "multi-stash"
+version = "0.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "685a9ac4b61f4e728e1d2c6a7844609c16527aeb5e6c865915c08e619c16410f"
+
+[[package]]
+name = "multiaddr"
+version = "0.18.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "fe6351f60b488e04c1d21bc69e56b89cb3f5e8f5d22557d6e8031bdfd79b6961"
+dependencies = [
+ "arrayref",
+ "byteorder",
+ "data-encoding",
+ "libp2p-identity",
+ "multibase",
+ "multihash",
+ "percent-encoding",
+ "serde",
+ "static_assertions",
+ "unsigned-varint 0.8.0",
+ "url",
+]
+
+[[package]]
+name = "multibase"
+version = "0.9.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8694bb4835f452b0e3bb06dbebb1d6fc5385b6ca1caf2e55fd165c042390ec77"
+dependencies = [
+ "base-x",
+ "base256emoji",
+ "data-encoding",
+ "data-encoding-macro",
+]
+
+[[package]]
+name = "multihash"
+version = "0.19.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "577c63b00ad74d57e8c9aa870b5fccebf2fd64a308a5aee9f1bb88e4aea19447"
+dependencies = [
+ "unsigned-varint 0.8.0",
+]
+
+[[package]]
+name = "multistream-select"
+version = "0.13.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ea0df8e5eec2298a62b326ee4f0d7fe1a6b90a09dfcf9df37b38f947a8c42f19"
+dependencies = [
+ "bytes",
+ "futures",
+ "log",
+ "pin-project",
+ "smallvec",
+ "unsigned-varint 0.7.2",
+]
+
+[[package]]
+name = "naga"
+version = "25.0.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2b977c445f26e49757f9aca3631c3b8b836942cb278d69a92e7b80d3b24da632"
+dependencies = [
+ "arrayvec",
+ "bit-set",
+ "bitflags 2.11.1",
+ "cfg_aliases",
+ "codespan-reporting",
+ "half",
+ "hashbrown 0.15.5",
+ "hexf-parse",
+ "indexmap",
+ "log",
+ "num-traits",
+ "once_cell",
+ "rustc-hash 1.1.0",
+ "spirv",
+ "strum 0.26.3",
+ "thiserror 2.0.18",
+ "unicode-ident",
+]
+
+[[package]]
+name = "nanorand"
+version = "0.7.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6a51313c5820b0b02bd422f4b44776fbf47961755c74ce64afc73bfad10226c3"
+dependencies = [
+ "getrandom 0.2.17",
+]
+
+[[package]]
+name = "netlink-packet-core"
+version = "0.8.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3463cbb78394cb0141e2c926b93fc2197e473394b761986eca3b9da2c63ae0f4"
+dependencies = [
+ "paste",
+]
+
+[[package]]
+name = "netlink-packet-route"
+version = "0.28.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4ce3636fa715e988114552619582b530481fd5ef176a1e5c1bf024077c2c9445"
+dependencies = [
+ "bitflags 2.11.1",
+ "libc",
+ "log",
+ "netlink-packet-core",
+]
+
+[[package]]
+name = "netlink-proto"
+version = "0.12.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b65d130ee111430e47eed7896ea43ca693c387f097dd97376bffafbf25812128"
+dependencies = [
+ "bytes",
+ "futures",
+ "log",
+ "netlink-packet-core",
+ "netlink-sys",
+ "thiserror 2.0.18",
+]
+
+[[package]]
+name = "netlink-sys"
+version = "0.8.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "cd6c30ed10fa69cc491d491b85cc971f6bdeb8e7367b7cde2ee6cc878d583fae"
+dependencies = [
+ "bytes",
+ "futures-util",
+ "libc",
+ "log",
+ "tokio",
+]
+
+[[package]]
+name = "new_debug_unreachable"
+version = "1.0.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "650eef8c711430f1a879fdd01d4745a7deea475becfb90269c06775983bbf086"
+
+[[package]]
+name = "nix"
+version = "0.29.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "71e2746dc3a24dd78b3cfcb7be93368c6de9963d30f43a6a73998a9cf4b17b46"
+dependencies = [
+ "bitflags 2.11.1",
+ "cfg-if",
+ "cfg_aliases",
+ "libc",
+ "memoffset",
+]
+
+[[package]]
+name = "nix"
+version = "0.30.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "74523f3a35e05aba87a1d978330aef40f67b0304ac79c1c00b294c9830543db6"
+dependencies = [
+ "bitflags 2.11.1",
+ "cfg-if",
+ "cfg_aliases",
+ "libc",
+]
+
+[[package]]
+name = "nix"
+version = "0.31.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5d6d0705320c1e6ba1d912b5e37cf18071b6c2e9b7fa8215a1e8a7651966f5d3"
+dependencies = [
+ "bitflags 2.11.1",
+ "cfg-if",
+ "cfg_aliases",
+ "libc",
+]
+
+[[package]]
+name = "no_std_io2"
+version = "0.9.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "418abd1b6d34fbf6cae440dc874771b0525a604428704c76e48b29a5e67b8003"
+dependencies = [
+ "memchr",
+]
+
+[[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 = "nom"
+version = "8.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "df9761775871bdef83bee530e60050f7e54b1105350d6884eb0fb4f46c2f9405"
+dependencies = [
+ "memchr",
+]
+
+[[package]]
+name = "noop_proc_macro"
+version = "0.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0676bb32a98c1a483ce53e500a81ad9c3d5b3f7c920c28c24e9cb0980d0b5bc8"
+
+[[package]]
+name = "notify"
+version = "6.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6205bd8bb1e454ad2e27422015fb5e4f2bcc7e08fa8f27058670d208324a4d2d"
+dependencies = [
+ "bitflags 2.11.1",
+ "crossbeam-channel",
+ "filetime",
+ "fsevent-sys",
+ "inotify",
+ "kqueue",
+ "libc",
+ "log",
+ "mio 0.8.11",
+ "walkdir",
+ "windows-sys 0.48.0",
+]
+
+[[package]]
+name = "ntapi"
+version = "0.4.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c3b335231dfd352ffb0f8017f3b6027a4917f7df785ea2143d8af2adc66980ae"
+dependencies = [
+ "winapi",
+]
+
+[[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-bigint-dig"
+version = "0.8.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e661dda6640fad38e827a6d4a310ff4763082116fe217f279885c97f511bb0b7"
+dependencies = [
+ "lazy_static",
+ "libm",
+ "num-integer",
+ "num-iter",
+ "num-traits",
+ "rand 0.8.6",
+ "serde",
+ "smallvec",
+ "zeroize",
+]
+
+[[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.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c6673768db2d862beb9b39a78fdcb1a69439615d5794a1be50caa9bc92c81967"
+
+[[package]]
+name = "num-derive"
+version = "0.4.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ed3955f1a9c7c0c15e092f9c887db08b1fc683305fdf6eb6684f22555355e202"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.117",
+]
+
+[[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",
+ "libm",
+]
+
+[[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 = "objc"
+version = "0.2.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "915b1b472bc21c53464d6c8461c9d3af805ba1ef837e1cac254428f4a77177b1"
+dependencies = [
+ "malloc_buf",
+ "objc_exception",
+]
+
+[[package]]
+name = "objc-foundation"
+version = "0.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1add1b659e36c9607c7aab864a76c7a4c2760cd0cd2e120f3fb8b952c7e22bf9"
+dependencies = [
+ "block",
+ "objc",
+ "objc_id",
+]
+
+[[package]]
+name = "objc2"
+version = "0.6.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3a12a8ed07aefc768292f076dc3ac8c48f3781c8f2d5851dd3d98950e8c5a89f"
+dependencies = [
+ "objc2-encode",
+]
+
+[[package]]
+name = "objc2-app-kit"
+version = "0.3.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d49e936b501e5c5bf01fda3a9452ff86dc3ea98ad5f283e1455153142d97518c"
+dependencies = [
+ "bitflags 2.11.1",
+ "objc2",
+ "objc2-core-foundation",
+ "objc2-foundation",
+ "objc2-quartz-core",
+]
+
+[[package]]
+name = "objc2-core-foundation"
+version = "0.3.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2a180dd8642fa45cdb7dd721cd4c11b1cadd4929ce112ebd8b9f5803cc79d536"
+dependencies = [
+ "bitflags 2.11.1",
+ "dispatch2",
+ "objc2",
+]
+
+[[package]]
+name = "objc2-encode"
+version = "4.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ef25abbcd74fb2609453eb695bd2f860d389e457f67dc17cafc8b8cbc89d0c33"
+
+[[package]]
+name = "objc2-foundation"
+version = "0.3.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e3e0adef53c21f888deb4fa59fc59f7eb17404926ee8a6f59f5df0fd7f9f3272"
+dependencies = [
+ "bitflags 2.11.1",
+ "objc2",
+ "objc2-core-foundation",
+]
+
+[[package]]
+name = "objc2-metal"
+version = "0.3.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a0125f776a10d00af4152d74616409f0d4a2053a6f57fa5b7d6aa2854ac04794"
+dependencies = [
+ "bitflags 2.11.1",
+ "block2",
+ "objc2",
+ "objc2-foundation",
+]
+
+[[package]]
+name = "objc2-quartz-core"
+version = "0.3.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "96c1358452b371bf9f104e21ec536d37a650eb10f7ee379fff67d2e08d537f1f"
+dependencies = [
+ "bitflags 2.11.1",
+ "objc2",
+ "objc2-core-foundation",
+ "objc2-foundation",
+ "objc2-metal",
+]
+
+[[package]]
+name = "objc2-ui-kit"
+version = "0.3.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d87d638e33c06f577498cbcc50491496a3ed4246998a7fbba7ccb98b1e7eab22"
+dependencies = [
+ "bitflags 2.11.1",
+ "objc2",
+ "objc2-core-foundation",
+ "objc2-foundation",
+ "objc2-quartz-core",
+]
+
+[[package]]
+name = "objc_exception"
+version = "0.1.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ad970fb455818ad6cba4c122ad012fae53ae8b4795f86378bce65e4f6bab2ca4"
+dependencies = [
+ "cc",
+]
+
+[[package]]
+name = "objc_id"
+version = "0.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c92d4ddb4bd7b50d730c215ff871754d0da6b2178849f8a2a2ab69712d0c073b"
+dependencies = [
+ "objc",
+]
+
+[[package]]
+name = "object"
+version = "0.37.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ff76201f031d8863c38aa7f905eca4f53abbfa15f609db4277d44cd8938f33fe"
+dependencies = [
+ "memchr",
+]
+
+[[package]]
+name = "oid-registry"
+version = "0.8.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "12f40cff3dde1b6087cc5d5f5d4d65712f34016a03ed60e9c08dcc392736b5b7"
+dependencies = [
+ "asn1-rs",
+]
+
+[[package]]
+name = "once_cell"
+version = "1.21.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9f7c3e4beb33f85d45ae3e3a1792185706c8e16d043238c593331cc7cd313b50"
+dependencies = [
+ "critical-section",
+ "portable-atomic",
+]
+
+[[package]]
+name = "once_cell_polyfill"
+version = "1.70.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "384b8ab6d37215f3c5301a95a4accb5d64aa607f1fcb26a11b5303878451b4fe"
+
+[[package]]
+name = "oo7"
+version = "0.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e3299dd401feaf1d45afd8fd1c0586f10fcfb22f244bb9afa942cec73503b89d"
+dependencies = [
+ "aes",
+ "ashpd 0.12.3",
+ "async-fs",
+ "async-io",
+ "async-lock",
+ "blocking",
+ "cbc",
+ "cipher",
+ "digest",
+ "endi",
+ "futures-lite 2.6.1",
+ "futures-util",
+ "getrandom 0.3.4",
+ "hkdf",
+ "hmac",
+ "md-5",
+ "num",
+ "num-bigint-dig",
+ "pbkdf2",
+ "rand 0.9.4",
+ "serde",
+ "sha2",
+ "subtle",
+ "zbus 5.15.0",
+ "zbus_macros 5.15.0",
+ "zeroize",
+ "zvariant 5.11.0",
+]
+
+[[package]]
+name = "opaque-debug"
+version = "0.3.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c08d65885ee38876c4f86fa503fb49d7b507c2b62552df7c70b2fce627e06381"
+
+[[package]]
+name = "open"
+version = "5.3.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9f3bab717c29a857abf75fcef718d441ec7cb2725f937343c734740a985d37fd"
+dependencies = [
+ "is-wsl",
+ "libc",
+ "pathdiff",
+]
+
+[[package]]
+name = "openssl-probe"
+version = "0.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7c87def4c32ab89d880effc9e097653c8da5d6ef28e6b539d313baaacfbafcbe"
+
+[[package]]
+name = "option-ext"
+version = "0.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "04744f49eae99ab78e0d5c0b603ab218f515ea8cfe5a456d7629ad883a3b6e7d"
+
+[[package]]
+name = "ordered-stream"
+version = "0.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9aa2b01e1d916879f73a53d01d1d6cee68adbb31d6d9177a8cfce093cced1d50"
+dependencies = [
+ "futures-core",
+ "pin-project-lite",
+]
+
+[[package]]
+name = "parking"
+version = "2.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f38d5652c16fde515bb1ecef450ab0f6a219d619a7274976324d5e377f7dceba"
+
+[[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 0.2.1",
+]
+
+[[package]]
+name = "password-hash"
+version = "0.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "346f04948ba92c43e8469c1ee6736c7563d71012b17d40745260fe106aac2166"
+dependencies = [
+ "base64ct",
+ "rand_core 0.6.4",
+ "subtle",
+]
+
+[[package]]
+name = "paste"
+version = "1.0.15"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a"
+
+[[package]]
+name = "pastey"
+version = "0.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "35fb2e5f958ec131621fdd531e9fc186ed768cbe395337403ae56c17a74c68ec"
+
+[[package]]
+name = "pathdiff"
+version = "0.2.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "df94ce210e5bc13cb6651479fa48d14f601d9858cfe0467f43ae157023b938d3"
+
+[[package]]
+name = "pathfinder_geometry"
+version = "0.5.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0b7b7e7b4ea703700ce73ebf128e1450eb69c3a8329199ffbfb9b2a0418e5ad3"
+dependencies = [
+ "log",
+ "pathfinder_simd",
+]
+
+[[package]]
+name = "pathfinder_simd"
+version = "0.5.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4500030c302e4af1d423f36f3b958d1aecb6c04184356ed5a833bf6b60435777"
+dependencies = [
+ "rustc_version",
+]
+
+[[package]]
+name = "pbkdf2"
+version = "0.12.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f8ed6a7761f76e3b9f92dfb0a60a6a6477c61024b775147ff0973a02653abaf2"
+dependencies = [
+ "digest",
+ "hmac",
+]
+
+[[package]]
+name = "pem"
+version = "3.0.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1d30c53c26bc5b31a98cd02d20f25a7c8567146caf63ed593a9d87b2775291be"
+dependencies = [
+ "base64",
+ "serde_core",
+]
+
+[[package]]
+name = "percent-encoding"
+version = "2.3.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9b4f627cb1b25917193a259e49bdad08f671f8d9708acfd5fe0a8c1455d87220"
+
+[[package]]
+name = "pico-args"
+version = "0.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5be167a7af36ee22fe3115051bc51f6e6c7054c9348e28deb4f49bd6f705a315"
+
+[[package]]
+name = "pin-project"
+version = "1.1.12"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "cbf0d9e68100b3a7989b4901972f265cd542e560a3a8a724e1e20322f4d06ce9"
+dependencies = [
+ "pin-project-internal",
+]
+
+[[package]]
+name = "pin-project-internal"
+version = "1.1.12"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a990e22f43e84855daf260dded30524ef4a9021cc7541c26540500a50b624389"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.117",
+]
+
+[[package]]
+name = "pin-project-lite"
+version = "0.2.17"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a89322df9ebe1c1578d689c92318e070967d1042b512afbe49518723f4e6d5cd"
+
+[[package]]
+name = "pin-utils"
+version = "0.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184"
+
+[[package]]
+name = "piper"
+version = "0.2.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c835479a4443ded371d6c535cbfd8d31ad92c5d23ae9770a61bc155e4992a3c1"
+dependencies = [
+ "atomic-waker",
+ "fastrand 2.4.1",
+ "futures-io",
+]
+
+[[package]]
+name = "pkcs8"
+version = "0.10.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f950b2377845cebe5cf8b5165cb3cc1a5e0fa5cfa3e1f7f55707d8fd82e0a7b7"
+dependencies = [
+ "der",
+ "spki",
+]
+
+[[package]]
+name = "pkg-config"
+version = "0.3.33"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "19f132c84eca552bf34cab8ec81f1c1dcc229b811638f9d283dceabe58c5569e"
+
+[[package]]
+name = "plain"
+version = "0.2.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b4596b6d070b27117e987119b4dac604f3c58cfb0b191112e24771b2faeac1a6"
+
+[[package]]
+name = "png"
+version = "0.17.16"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "82151a2fc869e011c153adc57cf2789ccb8d9906ce52c0b39a6b5697749d7526"
+dependencies = [
+ "bitflags 1.3.2",
+ "crc32fast",
+ "fdeflate",
+ "flate2",
+ "miniz_oxide",
+]
+
+[[package]]
+name = "png"
+version = "0.18.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "60769b8b31b2a9f263dae2776c37b1b28ae246943cf719eb6946a1db05128a61"
+dependencies = [
+ "bitflags 2.11.1",
+ "crc32fast",
+ "fdeflate",
+ "flate2",
+ "miniz_oxide",
+]
+
+[[package]]
+name = "polling"
+version = "3.11.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5d0e4f59085d47d8241c88ead0f274e8a0cb551f3625263c05eb8dd897c34218"
+dependencies = [
+ "cfg-if",
+ "concurrent-queue",
+ "hermit-abi",
+ "pin-project-lite",
+ "rustix 1.1.4",
+ "windows-sys 0.61.2",
+]
+
+[[package]]
+name = "pollster"
+version = "0.2.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5da3b0203fd7ee5720aa0b5e790b591aa5d3f41c3ed2c34a3a393382198af2f7"
+
+[[package]]
+name = "poly1305"
+version = "0.8.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8159bd90725d2df49889a078b54f4f79e87f1f8a8444194cdca81d38f5393abf"
+dependencies = [
+ "cpufeatures 0.2.17",
+ "opaque-debug",
+ "universal-hash",
+]
+
+[[package]]
+name = "polyval"
+version = "0.6.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9d1fe60d06143b2430aa532c94cfe9e29783047f06c0d7fd359a9a51b729fa25"
+dependencies = [
+ "cfg-if",
+ "cpufeatures 0.2.17",
+ "opaque-debug",
+ "universal-hash",
+]
+
+[[package]]
+name = "portable-atomic"
+version = "1.13.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c33a9471896f1c69cecef8d20cbe2f7accd12527ce60845ff44c153bb2a21b49"
+
+[[package]]
+name = "postage"
+version = "0.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "af3fb618632874fb76937c2361a7f22afd393c982a2165595407edc75b06d3c1"
+dependencies = [
+ "atomic",
+ "crossbeam-queue",
+ "futures",
+ "log",
+ "parking_lot 0.12.5",
+ "pin-project",
+ "pollster",
+ "static_assertions",
+ "thiserror 1.0.69",
+]
+
+[[package]]
+name = "postcard"
+version = "1.1.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6764c3b5dd454e283a30e6dfe78e9b31096d9e32036b5d1eaac7a6119ccb9a24"
+dependencies = [
+ "cobs",
+ "embedded-io 0.4.0",
+ "embedded-io 0.6.1",
+ "heapless",
+ "serde",
+]
+
+[[package]]
+name = "potential_utf"
+version = "0.1.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0103b1cef7ec0cf76490e969665504990193874ea05c85ff9bab8b911d0a0564"
+dependencies = [
+ "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 = "prettyplease"
+version = "0.2.37"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "479ca8adacdd7ce8f1fb39ce9ecccbfe93a3f1344b3d0d97f20bc0196208f62b"
+dependencies = [
+ "proc-macro2",
+ "syn 2.0.117",
+]
+
+[[package]]
+name = "proc-macro-crate"
+version = "3.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e67ba7e9b2b56446f1d419b1d807906278ffa1a658a8a5d8a39dcb1f5a78614f"
+dependencies = [
+ "toml_edit 0.25.11+spec-1.1.0",
+]
+
+[[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 2.0.117",
+]
+
+[[package]]
+name = "proc-macro2"
+version = "1.0.106"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8fd00f0bb2e90d81d1044c2b32617f68fcb9fa3bb7640c23e9c748e53fb30934"
+dependencies = [
+ "unicode-ident",
+]
+
+[[package]]
+name = "profiling"
+version = "1.0.18"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3d595e54a326bc53c1c197b32d295e14b169e3cfeaa8dc82b529f947fba6bcf5"
+dependencies = [
+ "profiling-procmacros",
+]
+
+[[package]]
+name = "profiling-procmacros"
+version = "1.0.18"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4488a4a36b9a4ba6b9334a32a39971f77c1436ec82c38707bce707699cc3bbcb"
+dependencies = [
+ "quote",
+ "syn 2.0.117",
+]
+
+[[package]]
+name = "prometheus-client"
+version = "0.23.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "cf41c1a7c32ed72abe5082fb19505b969095c12da9f5732a4bc9878757fd087c"
+dependencies = [
+ "dtoa",
+ "itoa",
+ "parking_lot 0.12.5",
+ "prometheus-client-derive-encode",
+]
+
+[[package]]
+name = "prometheus-client-derive-encode"
+version = "0.4.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "440f724eba9f6996b75d63681b0a92b06947f1457076d503a4d2e2c8f56442b8"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.117",
+]
+
+[[package]]
+name = "psm"
+version = "0.1.31"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "645dbe486e346d9b5de3ef16ede18c26e6c70ad97418f4874b8b1889d6e761ea"
+dependencies = [
+ "ar_archive_writer",
+ "cc",
+]
+
+[[package]]
+name = "pxfm"
+version = "0.1.29"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e0c5ccf5294c6ccd63a74f1565028353830a9c2f5eb0c682c355c471726a6e3f"
+
+[[package]]
+name = "qoi"
+version = "0.4.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7f6d64c71eb498fe9eae14ce4ec935c555749aef511cca85b5568910d6e48001"
+dependencies = [
+ "bytemuck",
+]
+
+[[package]]
+name = "quick-error"
+version = "2.0.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a993555f31e5a609f617c12db6250dedcac1b0a85076912c436e6fc9b2c8e6a3"
+
+[[package]]
+name = "quick-protobuf"
+version = "0.8.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9d6da84cc204722a989e01ba2f6e1e276e190f22263d0cb6ce8526fcdb0d2e1f"
+dependencies = [
+ "byteorder",
+]
+
+[[package]]
+name = "quick-protobuf-codec"
+version = "0.3.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "15a0580ab32b169745d7a39db2ba969226ca16738931be152a3209b409de2474"
+dependencies = [
+ "asynchronous-codec",
+ "bytes",
+ "quick-protobuf",
+ "thiserror 1.0.69",
+ "unsigned-varint 0.8.0",
+]
+
+[[package]]
+name = "quick-xml"
+version = "0.30.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "eff6510e86862b57b210fd8cbe8ed3f0d7d600b9c2863cd4549a2e033c66e956"
+dependencies = [
+ "memchr",
+]
+
+[[package]]
+name = "quick-xml"
+version = "0.39.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "721da970c312655cde9b4ffe0547f20a8494866a4af5ff51f18b7c633d0c870b"
+dependencies = [
+ "memchr",
+]
+
+[[package]]
+name = "quinn"
+version = "0.11.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b9e20a958963c291dc322d98411f541009df2ced7b5a4f2bd52337638cfccf20"
+dependencies = [
+ "bytes",
+ "cfg_aliases",
+ "futures-io",
+ "pin-project-lite",
+ "quinn-proto",
+ "quinn-udp",
+ "rustc-hash 2.1.2",
+ "rustls",
+ "socket2 0.6.3",
+ "thiserror 2.0.18",
+ "tokio",
+ "tracing",
+ "web-time",
+]
+
+[[package]]
+name = "quinn-proto"
+version = "0.11.14"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "434b42fec591c96ef50e21e886936e66d3cc3f737104fdb9b737c40ffb94c098"
+dependencies = [
+ "bytes",
+ "getrandom 0.3.4",
+ "lru-slab",
+ "rand 0.9.4",
+ "ring",
+ "rustc-hash 2.1.2",
+ "rustls",
+ "rustls-pki-types",
+ "slab",
+ "thiserror 2.0.18",
+ "tinyvec",
+ "tracing",
+ "web-time",
+]
+
+[[package]]
+name = "quinn-udp"
+version = "0.5.14"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "addec6a0dcad8a8d96a771f815f0eaf55f9d1805756410b39f5fa81332574cbd"
+dependencies = [
+ "cfg_aliases",
+ "libc",
+ "once_cell",
+ "socket2 0.6.3",
+ "tracing",
+ "windows-sys 0.60.2",
+]
+
+[[package]]
+name = "quote"
+version = "1.0.45"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "41f2619966050689382d2b44f664f4bc593e129785a36d6ee376ddf37259b924"
+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 = "r-efi"
+version = "6.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f8dcc9c7d52a811697d2151c701e0d08956f92b0e24136cf4cf27b57a6a0d9bf"
+
+[[package]]
+name = "rand"
+version = "0.8.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5ca0ecfa931c29007047d1bc58e623ab12e5590e8c7cc53200d5202b69266d8a"
+dependencies = [
+ "libc",
+ "rand_chacha 0.3.1",
+ "rand_core 0.6.4",
+]
+
+[[package]]
+name = "rand"
+version = "0.9.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "44c5af06bb1b7d3216d91932aed5265164bf384dc89cd6ba05cf59a35f5f76ea"
+dependencies = [
+ "rand_chacha 0.9.0",
+ "rand_core 0.9.5",
+]
+
+[[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_chacha"
+version = "0.9.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d3022b5f1df60f26e1ffddd6c66e8aa15de382ae63b3a0c1bfc0e4d3e3f325cb"
+dependencies = [
+ "ppv-lite86",
+ "rand_core 0.9.5",
+]
+
+[[package]]
+name = "rand_core"
+version = "0.6.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c"
+dependencies = [
+ "getrandom 0.2.17",
+]
+
+[[package]]
+name = "rand_core"
+version = "0.9.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "76afc826de14238e6e8c374ddcc1fa19e374fd8dd986b0d2af0d02377261d83c"
+dependencies = [
+ "getrandom 0.3.4",
+]
+
+[[package]]
+name = "rangemap"
+version = "1.7.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "973443cf09a9c8656b574a866ab68dfa19f0867d0340648c7d2f6a71b8a8ea68"
+
+[[package]]
+name = "rav1e"
+version = "0.8.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "43b6dd56e85d9483277cde964fd1bdb0428de4fec5ebba7540995639a21cb32b"
+dependencies = [
+ "aligned-vec",
+ "arbitrary",
+ "arg_enum_proc_macro",
+ "arrayvec",
+ "av-scenechange",
+ "av1-grain",
+ "bitstream-io",
+ "built",
+ "cfg-if",
+ "interpolate_name",
+ "itertools 0.14.0",
+ "libc",
+ "libfuzzer-sys",
+ "log",
+ "maybe-rayon",
+ "new_debug_unreachable",
+ "noop_proc_macro",
+ "num-derive",
+ "num-traits",
+ "paste",
+ "profiling",
+ "rand 0.9.4",
+ "rand_chacha 0.9.0",
+ "simd_helpers",
+ "thiserror 2.0.18",
+ "v_frame",
+ "wasm-bindgen",
+]
+
+[[package]]
+name = "ravif"
+version = "0.13.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e52310197d971b0f5be7fe6b57530dcd27beb35c1b013f29d66c1ad73fbbcc45"
+dependencies = [
+ "avif-serialize",
+ "imgref",
+ "loop9",
+ "quick-error",
+ "rav1e",
+ "rayon",
+ "rgb",
+]
+
+[[package]]
+name = "raw-window-handle"
+version = "0.6.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "20675572f6f24e9e76ef639bc5552774ed45f1c30e2951e1e99c59888861c539"
+
+[[package]]
+name = "raw-window-metal"
+version = "0.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "76e8caa82e31bb98fee12fa8f051c94a6aa36b07cddb03f0d4fc558988360ff1"
+dependencies = [
+ "cocoa 0.25.0",
+ "core-graphics 0.23.2",
+ "objc",
+ "raw-window-handle",
+]
+
+[[package]]
+name = "rayon"
+version = "1.12.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "fb39b166781f92d482534ef4b4b1b2568f42613b53e5b6c160e24cfbfa30926d"
+dependencies = [
+ "either",
+ "rayon-core",
+]
+
+[[package]]
+name = "rayon-core"
+version = "1.13.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "22e18b0f0062d30d4230b2e85ff77fdfe4326feb054b9783a3460d8435c8ab91"
+dependencies = [
+ "crossbeam-deque",
+ "crossbeam-utils",
+]
+
+[[package]]
+name = "rcgen"
+version = "0.13.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "75e669e5202259b5314d1ea5397316ad400819437857b90861765f24c4cf80a2"
+dependencies = [
+ "pem",
+ "ring",
+ "rustls-pki-types",
+ "time",
+ "yasna",
+]
+
+[[package]]
+name = "read-fonts"
+version = "0.37.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7b634fabf032fab15307ffd272149b622260f55974d9fad689292a5d33df02e5"
+dependencies = [
+ "bytemuck",
+ "font-types",
+]
+
+[[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.11.1",
+]
+
+[[package]]
+name = "redox_syscall"
+version = "0.7.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4666a1a60d8412eab19d94f6d13dcc9cea0a5ef4fdf6a5db306537413c661b1b"
+dependencies = [
+ "bitflags 2.11.1",
+]
+
+[[package]]
+name = "redox_users"
+version = "0.4.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ba009ff324d1fc1b900bd1fdb31564febe58a8ccc8a6fdbb93b543d33b13ca43"
+dependencies = [
+ "getrandom 0.2.17",
+ "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 2.0.117",
+]
+
+[[package]]
+name = "regex"
+version = "1.12.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e10754a14b9137dd7b1e3e5b0493cc9171fdd105e0ab477f51b72e7f3ac0e276"
+dependencies = [
+ "aho-corasick",
+ "memchr",
+ "regex-automata",
+ "regex-syntax",
+]
+
+[[package]]
+name = "regex-automata"
+version = "0.4.14"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6e1dd4122fc1595e8162618945476892eefca7b88c52820e74af6262213cae8f"
+dependencies = [
+ "aho-corasick",
+ "memchr",
+ "regex-syntax",
+]
+
+[[package]]
+name = "regex-syntax"
+version = "0.8.10"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "dc897dd8d9e8bd1ed8cdad82b5966c3e0ecae09fb1907d58efaa013543185d0a"
+
+[[package]]
+name = "resolv-conf"
+version = "0.7.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1e061d1b48cb8d38042de4ae0a7a6401009d6143dc80d2e2d6f31f0bdd6470c7"
+
+[[package]]
+name = "resvg"
+version = "0.45.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a8928798c0a55e03c9ca6c4c6846f76377427d2c1e1f7e6de3c06ae57942df43"
+dependencies = [
+ "log",
+ "pico-args",
+ "rgb",
+ "svgtypes",
+ "tiny-skia",
+ "usvg",
+]
+
+[[package]]
+name = "rgb"
+version = "0.8.53"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "47b34b781b31e5d73e9fbc8689c70551fd1ade9a19e3e28cfec8580a79290cc4"
+dependencies = [
+ "bytemuck",
+]
+
+[[package]]
+name = "ring"
+version = "0.17.14"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a4689e6c2294d81e88dc6261c768b63bc4fcdb852be6d1352498b114f61383b7"
+dependencies = [
+ "cc",
+ "cfg-if",
+ "getrandom 0.2.17",
+ "libc",
+ "untrusted",
+ "windows-sys 0.52.0",
+]
+
+[[package]]
+name = "roxmltree"
+version = "0.20.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6c20b6793b5c2fa6553b250154b78d6d0db37e72700ae35fad9387a46f487c97"
+
+[[package]]
+name = "rpassword"
+version = "7.5.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5ac5b223d9738ef56e0b98305410be40fa0941bf6036c56f1506751e43552d64"
+dependencies = [
+ "libc",
+ "rtoolbox",
+ "windows-sys 0.61.2",
+]
+
+[[package]]
+name = "rtnetlink"
+version = "0.20.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4b960d5d873a75b5be9761b1e73b146f52dddcd27bac75263f40fba686d4d7b5"
+dependencies = [
+ "futures-channel",
+ "futures-util",
+ "log",
+ "netlink-packet-core",
+ "netlink-packet-route",
+ "netlink-proto",
+ "netlink-sys",
+ "nix 0.30.1",
+ "thiserror 1.0.69",
+ "tokio",
+]
+
+[[package]]
+name = "rtoolbox"
+version = "0.0.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "50a0e551c1e27e1731aba276dbeaeac73f53c7cd34d1bda485d02bd1e0f36844"
+dependencies = [
+ "libc",
+ "windows-sys 0.59.0",
+]
+
+[[package]]
+name = "rusqlite"
+version = "0.31.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b838eba278d213a8beaf485bd313fd580ca4505a00d5871caeb1457c55322cae"
+dependencies = [
+ "bitflags 2.11.1",
+ "fallible-iterator",
+ "fallible-streaming-iterator",
+ "hashlink 0.9.1",
+ "libsqlite3-sys",
+ "smallvec",
+]
+
+[[package]]
+name = "rust-embed"
+version = "8.11.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "04113cb9355a377d83f06ef1f0a45b8ab8cd7d8b1288160717d66df5c7988d27"
+dependencies = [
+ "rust-embed-impl",
+ "rust-embed-utils",
+ "walkdir",
+]
+
+[[package]]
+name = "rust-embed-impl"
+version = "8.11.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "da0902e4c7c8e997159ab384e6d0fc91c221375f6894346ae107f47dd0f3ccaa"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "rust-embed-utils",
+ "syn 2.0.117",
+ "walkdir",
+]
+
+[[package]]
+name = "rust-embed-utils"
+version = "8.11.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5bcdef0be6fe7f6fa333b1073c949729274b05f123a0ad7efcb8efd878e5c3b1"
+dependencies = [
+ "globset",
+ "sha2",
+ "walkdir",
+]
+
+[[package]]
+name = "rustc-hash"
+version = "1.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2"
+
+[[package]]
+name = "rustc-hash"
+version = "2.1.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "94300abf3f1ae2e2b8ffb7b58043de3d399c73fa6f4b73826402a5c457614dbe"
+
+[[package]]
+name = "rustc_version"
+version = "0.4.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "cfcb3a22ef46e85b45de6ee7e79d063319ebb6594faafcf1c225ea92ab6e9b92"
+dependencies = [
+ "semver",
+]
+
+[[package]]
+name = "rusticata-macros"
+version = "4.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "faf0c4a6ece9950b9abdb62b1cfcf2a68b3b67a10ba445b3bb85be2a293d0632"
+dependencies = [
+ "nom 7.1.3",
+]
+
+[[package]]
+name = "rustix"
+version = "0.38.44"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "fdb5bc1ae2baa591800df16c9ca78619bf65c0488b41b96ccec5d11220d8c154"
+dependencies = [
+ "bitflags 2.11.1",
+ "errno",
+ "libc",
+ "linux-raw-sys 0.4.15",
+ "windows-sys 0.59.0",
+]
+
+[[package]]
+name = "rustix"
+version = "1.1.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b6fe4565b9518b83ef4f91bb47ce29620ca828bd32cb7e408f0062e9930ba190"
+dependencies = [
+ "bitflags 2.11.1",
+ "errno",
+ "libc",
+ "linux-raw-sys 0.12.1",
+ "windows-sys 0.61.2",
+]
+
+[[package]]
+name = "rustls"
+version = "0.23.40"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ef86cd5876211988985292b91c96a8f2d298df24e75989a43a3c73f2d4d8168b"
+dependencies = [
+ "once_cell",
+ "ring",
+ "rustls-pki-types",
+ "rustls-webpki",
+ "subtle",
+ "zeroize",
+]
+
+[[package]]
+name = "rustls-native-certs"
+version = "0.8.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "612460d5f7bea540c490b2b6395d8e34a953e52b491accd6c86c8164c5932a63"
+dependencies = [
+ "openssl-probe",
+ "rustls-pki-types",
+ "schannel",
+ "security-framework",
+]
+
+[[package]]
+name = "rustls-pemfile"
+version = "2.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "dce314e5fee3f39953d46bb63bb8a46d40c2f8fb7cc5a3b6cab2bde9721d6e50"
+dependencies = [
+ "rustls-pki-types",
+]
+
+[[package]]
+name = "rustls-pki-types"
+version = "1.14.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "30a7197ae7eb376e574fe940d068c30fe0462554a3ddbe4eca7838e049c937a9"
+dependencies = [
+ "web-time",
+ "zeroize",
+]
+
+[[package]]
+name = "rustls-webpki"
+version = "0.103.13"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "61c429a8649f110dddef65e2a5ad240f747e85f7758a6bccc7e5777bd33f756e"
+dependencies = [
+ "ring",
+ "rustls-pki-types",
+ "untrusted",
+]
+
+[[package]]
+name = "rustversion"
+version = "1.0.22"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d"
+
+[[package]]
+name = "rustybuzz"
+version = "0.14.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "cfb9cf8877777222e4a3bc7eb247e398b56baba500c38c1c46842431adc8b55c"
+dependencies = [
+ "bitflags 2.11.1",
+ "bytemuck",
+ "libm",
+ "smallvec",
+ "ttf-parser 0.21.1",
+ "unicode-bidi-mirroring 0.2.0",
+ "unicode-ccc 0.2.0",
+ "unicode-properties",
+ "unicode-script",
+]
+
+[[package]]
+name = "rustybuzz"
+version = "0.20.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "fd3c7c96f8a08ee34eff8857b11b49b07d71d1c3f4e88f8a88d4c9e9f90b1702"
+dependencies = [
+ "bitflags 2.11.1",
+ "bytemuck",
+ "core_maths",
+ "log",
+ "smallvec",
+ "ttf-parser 0.25.1",
+ "unicode-bidi-mirroring 0.4.0",
+ "unicode-ccc 0.4.0",
+ "unicode-properties",
+ "unicode-script",
+]
+
+[[package]]
+name = "rw-stream-sink"
+version = "0.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d8c9026ff5d2f23da5e45bbc283f156383001bfb09c4e44256d02c1a685fe9a1"
+dependencies = [
+ "futures",
+ "pin-project",
+ "static_assertions",
+]
+
+[[package]]
+name = "ryu"
+version = "1.0.23"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9774ba4a74de5f7b1c1451ed6cd5285a32eddb5cccb8cc655a4e50009e06477f"
+
+[[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 = "schannel"
+version = "0.1.29"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "91c1b7e4904c873ef0710c1f407dde2e6287de2bebc1bbbf7d430bb7cbffd939"
+dependencies = [
+ "windows-sys 0.61.2",
+]
+
+[[package]]
+name = "schemars"
+version = "1.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a2b42f36aa1cd011945615b92222f6bf73c599a102a300334cd7f8dbeec726cc"
+dependencies = [
+ "dyn-clone",
+ "indexmap",
+ "ref-cast",
+ "schemars_derive",
+ "serde",
+ "serde_json",
+]
+
+[[package]]
+name = "schemars_derive"
+version = "1.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7d115b50f4aaeea07e79c1912f645c7513d81715d0420f8bc77a18c6260b307f"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "serde_derive_internals",
+ "syn 2.0.117",
+]
+
+[[package]]
+name = "scoped-tls"
+version = "1.0.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e1cf6437eb19a8f4a6cc0f7dca544973b0b78843adbfeb3683d1a94a0024a294"
+
+[[package]]
+name = "scopeguard"
+version = "1.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49"
+
+[[package]]
+name = "screencapturekit"
+version = "0.2.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1a5eeeb57ac94960cfe5ff4c402be6585ae4c8d29a2cf41b276048c2e849d64e"
+dependencies = [
+ "screencapturekit-sys",
+]
+
+[[package]]
+name = "screencapturekit-sys"
+version = "0.2.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "22411b57f7d49e7fe08025198813ee6fd65e1ee5eff4ebc7880c12c82bde4c60"
+dependencies = [
+ "block",
+ "dispatch",
+ "objc",
+ "objc-foundation",
+ "objc_id",
+ "once_cell",
+]
+
+[[package]]
+name = "seahash"
+version = "4.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1c107b6f4780854c8b126e228ea8869f4d7b71260f962fefb57b996b8959ba6b"
+
+[[package]]
+name = "security-framework"
+version = "3.7.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b7f4bc775c73d9a02cde8bf7b2ec4c9d12743edf609006c7facc23998404cd1d"
+dependencies = [
+ "bitflags 2.11.1",
+ "core-foundation 0.10.0",
+ "core-foundation-sys",
+ "libc",
+ "security-framework-sys",
+]
+
+[[package]]
+name = "security-framework-sys"
+version = "2.17.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6ce2691df843ecc5d231c0b14ece2acc3efb62c0a398c7e1d875f3983ce020e3"
+dependencies = [
+ "core-foundation-sys",
+ "libc",
+]
+
+[[package]]
+name = "self_cell"
+version = "1.2.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b12e76d157a900eb52e81bc6e9f3069344290341720e9178cde2407113ac8d89"
+
+[[package]]
+name = "semver"
+version = "1.0.28"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8a7852d02fc848982e0c167ef163aaff9cd91dc640ba85e263cb1ce46fae51cd"
+
+[[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-big-array"
+version = "0.5.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "11fc7cc2c76d73e0f27ee52abbd64eec84d46f370c88371120433196934e4b7f"
+dependencies = [
+ "serde",
+]
+
+[[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 2.0.117",
+]
+
+[[package]]
+name = "serde_derive_internals"
+version = "0.29.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "18d26a20a969b9e3fdf2fc2d9f21eda6c40e2de84c9408bb5d3b05d499aae711"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.117",
+]
+
+[[package]]
+name = "serde_fmt"
+version = "1.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6e497af288b3b95d067a23a4f749f2861121ffcb2f6d8379310dcda040c345ed"
+dependencies = [
+ "serde_core",
+]
+
+[[package]]
+name = "serde_json"
+version = "1.0.149"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "83fc039473c5595ace860d8c4fafa220ff474b3fc6bfdb4293327f1a37e94d86"
+dependencies = [
+ "indexmap",
+ "itoa",
+ "memchr",
+ "serde",
+ "serde_core",
+ "zmij",
+]
+
+[[package]]
+name = "serde_json_lenient"
+version = "0.2.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0e033097bf0d2b59a62b42c18ebbb797503839b26afdda2c4e1415cb6c813540"
+dependencies = [
+ "indexmap",
+ "itoa",
+ "memchr",
+ "ryu",
+ "serde",
+]
+
+[[package]]
+name = "serde_repr"
+version = "0.1.20"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "175ee3e80ae9982737ca543e96133087cbd9a485eecc3bc4de9c1a37b47ea59c"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.117",
+]
+
+[[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_spanned"
+version = "1.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6662b5879511e06e8999a8a235d848113e942c9124f211511b16466ee2995f26"
+dependencies = [
+ "serde_core",
+]
+
+[[package]]
+name = "serde_urlencoded"
+version = "0.7.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d3491c14715ca2294c4d6a88f15e84739788c1d030eed8c110436aafdaa2f3fd"
+dependencies = [
+ "form_urlencoded",
+ "itoa",
+ "ryu",
+ "serde",
+]
+
+[[package]]
+name = "sha1"
+version = "0.10.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e3bf829a2d51ab4a5ddf1352d8470c140cadc8301b2ae1789db023f01cedd6ba"
+dependencies = [
+ "cfg-if",
+ "cpufeatures 0.2.17",
+ "digest",
+]
+
+[[package]]
+name = "sha1_smol"
+version = "1.0.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bbfa15b3dddfee50a0fff136974b3e1bde555604ba463834a7eb7deb6417705d"
+
+[[package]]
+name = "sha2"
+version = "0.10.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a7507d819769d01a365ab707794a4084392c824f54a7a6a7862f8c3d0892b283"
+dependencies = [
+ "cfg-if",
+ "cpufeatures 0.2.17",
+ "digest",
+]
+
+[[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 = "shlex"
+version = "1.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64"
+
+[[package]]
+name = "signal-hook-registry"
+version = "1.4.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c4db69cba1110affc0e9f7bcd48bbf87b3f4fc7c61fc9155afd4c469eb3d6c1b"
+dependencies = [
+ "errno",
+ "libc",
+]
+
+[[package]]
+name = "signature"
+version = "2.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "77549399552de45a898a580c1b41d445bf730df867cc44e6c0233bbc4b8329de"
+dependencies = [
+ "rand_core 0.6.4",
+]
+
+[[package]]
+name = "simd-adler32"
+version = "0.3.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "703d5c7ef118737c72f1af64ad2f6f8c5e1921f818cdcb97b8fe6fc69bf66214"
+
+[[package]]
+name = "simd_helpers"
+version = "0.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "95890f873bec569a0362c235787f3aca6e1e887302ba4840839bcc6459c42da6"
+dependencies = [
+ "quote",
+]
+
+[[package]]
+name = "simplecss"
+version = "0.2.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7a9c6883ca9c3c7c90e888de77b7a5c849c779d25d74a1269b0218b14e8b136c"
+dependencies = [
+ "log",
+]
+
+[[package]]
+name = "siphasher"
+version = "1.0.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8ee5873ec9cce0195efcb7a4e9507a04cd49aec9c83d0389df45b1ef7ba2e649"
+
+[[package]]
+name = "skrifa"
+version = "0.40.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7fbdfe3d2475fbd7ddd1f3e5cf8288a30eb3e5f95832829570cd88115a7434ac"
+dependencies = [
+ "bytemuck",
+ "read-fonts",
+]
+
+[[package]]
+name = "slab"
+version = "0.4.12"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0c790de23124f9ab44544d7ac05d60440adc586479ce501c1d6d7da3cd8c9cf5"
+
+[[package]]
+name = "sled"
+version = "0.34.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7f96b4737c2ce5987354855aed3797279def4ebf734436c6aa4552cf8e169935"
+dependencies = [
+ "crc32fast",
+ "crossbeam-epoch",
+ "crossbeam-utils",
+ "fs2",
+ "fxhash",
+ "libc",
+ "log",
+ "parking_lot 0.11.2",
+]
+
+[[package]]
+name = "slotmap"
+version = "1.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bdd58c3c93c3d278ca835519292445cb4b0d4dc59ccfdf7ceadaab3f8aeb4038"
+dependencies = [
+ "version_check",
+]
+
+[[package]]
+name = "smallvec"
+version = "1.15.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03"
+
+[[package]]
+name = "smol"
+version = "2.0.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a33bd3e260892199c3ccfc487c88b2da2265080acb316cd920da72fdfd7c599f"
+dependencies = [
+ "async-channel 2.5.0",
+ "async-executor",
+ "async-fs",
+ "async-io",
+ "async-lock",
+ "async-net",
+ "async-process",
+ "blocking",
+ "futures-lite 2.6.1",
+]
+
+[[package]]
+name = "smol_str"
+version = "0.2.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "dd538fb6910ac1099850255cf94a94df6551fbdd602454387d0adb2d1ca6dead"
+
+[[package]]
+name = "snow"
+version = "0.9.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "850948bee068e713b8ab860fe1adc4d109676ab4c3b621fd8147f06b261f2f85"
+dependencies = [
+ "aes-gcm",
+ "blake2",
+ "chacha20poly1305",
+ "curve25519-dalek",
+ "rand_core 0.6.4",
+ "ring",
+ "rustc_version",
+ "sha2",
+ "subtle",
+]
+
+[[package]]
+name = "socket2"
+version = "0.5.10"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e22376abed350d73dd1cd119b57ffccad95b4e585a7cda43e286245ce23c0678"
+dependencies = [
+ "libc",
+ "windows-sys 0.52.0",
+]
+
+[[package]]
+name = "socket2"
+version = "0.6.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3a766e1110788c36f4fa1c2b71b387a7815aa65f88ce0229841826633d93723e"
+dependencies = [
+ "libc",
+ "windows-sys 0.61.2",
+]
+
+[[package]]
+name = "spin"
+version = "0.9.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67"
+dependencies = [
+ "lock_api",
+]
+
+[[package]]
+name = "spirv"
+version = "0.3.0+sdk-1.3.268.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "eda41003dc44290527a59b13432d4a0379379fa074b70174882adfbdfd917844"
+dependencies = [
+ "bitflags 2.11.1",
+]
+
+[[package]]
+name = "spki"
+version = "0.7.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d91ed6c858b01f942cd56b37a94b3e0a1798290327d1236e4d9cf4eaca44d29d"
+dependencies = [
+ "base64ct",
+ "der",
+]
+
+[[package]]
+name = "stable_deref_trait"
+version = "1.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6ce2be8dc25455e1f91df71bfa12ad37d7af1092ae736f3a6cd0e37bc7810596"
+
+[[package]]
+name = "stacker"
+version = "0.1.24"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "640c8cdd92b6b12f5bcb1803ca3bbf5ab96e5e6b6b96b9ab77dabe9e880b3190"
+dependencies = [
+ "cc",
+ "cfg-if",
+ "libc",
+ "psm",
+ "windows-sys 0.61.2",
+]
+
+[[package]]
+name = "stacksafe"
+version = "0.1.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1d9c1172965d317e87ddb6d364a040d958b40a1db82b6ef97da26253a8b3d090"
+dependencies = [
+ "stacker",
+ "stacksafe-macro",
+]
+
+[[package]]
+name = "stacksafe-macro"
+version = "0.1.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "172175341049678163e979d9107ca3508046d4d2a7c6682bee46ac541b17db69"
+dependencies = [
+ "proc-macro-error2",
+ "quote",
+ "syn 2.0.117",
+]
+
+[[package]]
+name = "static_assertions"
+version = "1.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f"
+
+[[package]]
+name = "streaming-iterator"
+version = "0.1.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2b2231b7c3057d5e4ad0156fb3dc807d900806020c5ffa3ee6ff2c8c76fb8520"
+
+[[package]]
+name = "strict-num"
+version = "0.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6637bab7722d379c8b41ba849228d680cc12d0a45ba1fa2b48f2a30577a06731"
+dependencies = [
+ "float-cmp",
+]
+
+[[package]]
+name = "string-interner"
+version = "0.18.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1a3275464d7a9f2d4cac57c89c2ef96a8524dba2864c8d6f82e3980baf136f9b"
+dependencies = [
+ "hashbrown 0.15.5",
+ "serde",
+]
+
+[[package]]
+name = "strsim"
+version = "0.11.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f"
+
+[[package]]
+name = "strum"
+version = "0.26.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8fec0f0aef304996cf250b31b5a10dee7980c85da9d759361292b8bca5a18f06"
+dependencies = [
+ "strum_macros 0.26.4",
+]
+
+[[package]]
+name = "strum"
+version = "0.27.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "af23d6f6c1a224baef9d3f61e287d2761385a5b88fdab4eb4c6f11aeb54c4bcf"
+dependencies = [
+ "strum_macros 0.27.2",
+]
+
+[[package]]
+name = "strum_macros"
+version = "0.26.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4c6bee85a5a24955dc440386795aa378cd9cf82acd5f764469152d2270e581be"
+dependencies = [
+ "heck 0.5.0",
+ "proc-macro2",
+ "quote",
+ "rustversion",
+ "syn 2.0.117",
+]
+
+[[package]]
+name = "strum_macros"
+version = "0.27.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7695ce3845ea4b33927c055a39dc438a45b059f7c1b3d91d38d10355fb8cbca7"
+dependencies = [
+ "heck 0.5.0",
+ "proc-macro2",
+ "quote",
+ "syn 2.0.117",
+]
+
+[[package]]
+name = "subtle"
+version = "2.6.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292"
+
+[[package]]
+name = "sval"
+version = "2.19.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4a05195a68cb8336336413c3f52ea0467c7666f5f652e01ba807319ffcc090f2"
+
+[[package]]
+name = "sval_buffer"
+version = "2.19.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2887fd5e2454319f2f170860427f615451bb057fc9b3fd7f28b7a99ac2ccf0e4"
+dependencies = [
+ "sval",
+ "sval_ref",
+]
+
+[[package]]
+name = "sval_dynamic"
+version = "2.19.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "12ddf3833aa407554ad40be081aea9cc3ea6d6798832ec83dd35022b45373896"
+dependencies = [
+ "sval",
+]
+
+[[package]]
+name = "sval_fmt"
+version = "2.19.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "94398bdd2ee99eee108e0b7b0df9081700a96cdefac3add5c09ad3e6f2376bcb"
+dependencies = [
+ "itoa",
+ "ryu",
+ "sval",
+]
+
+[[package]]
+name = "sval_json"
+version = "2.19.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3f51ae40f37b541fdf81531e51d5071e8edc7c5a191cc23d288b654995b9eaba"
+dependencies = [
+ "itoa",
+ "ryu",
+ "sval",
+]
+
+[[package]]
+name = "sval_nested"
+version = "2.19.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3abe05be8455348e3f6edc14a85fd2fcf32f801a14f0126ce025e63851b4f13b"
+dependencies = [
+ "sval",
+ "sval_buffer",
+ "sval_ref",
+]
+
+[[package]]
+name = "sval_ref"
+version = "2.19.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a36361fa3c42c9fd129f4c5023a812d5b275742b28a672c758ec70049c61df00"
+dependencies = [
+ "sval",
+]
+
+[[package]]
+name = "sval_serde"
+version = "2.19.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "fb76707179eccecab345902a803aacacab6889f3af675dbe89766bc790b1a6cb"
+dependencies = [
+ "serde_core",
+ "sval",
+ "sval_nested",
+]
+
+[[package]]
+name = "svg_fmt"
+version = "0.4.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0193cc4331cfd2f3d2011ef287590868599a2f33c3e69bc22c1a3d3acf9e02fb"
+
+[[package]]
+name = "svgtypes"
+version = "0.15.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "68c7541fff44b35860c1a7a47a7cadf3e4a304c457b58f9870d9706ece028afc"
+dependencies = [
+ "kurbo",
+ "siphasher",
+]
+
+[[package]]
+name = "swash"
+version = "0.2.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "842f3cd369c2ba38966204f983eaa5e54a8e84a7d7159ed36ade2b6c335aae64"
+dependencies = [
+ "skrifa",
+ "yazi",
+ "zeno",
+]
+
+[[package]]
+name = "syn"
+version = "1.0.109"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "unicode-ident",
+]
+
+[[package]]
+name = "syn"
+version = "2.0.117"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e665b8803e7b1d2a727f4023456bbbbe74da67099c585258af0ad9c5013b9b99"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "unicode-ident",
+]
+
+[[package]]
+name = "sync_wrapper"
+version = "1.0.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0bf256ce5efdfa370213c1dabab5935a12e49f2c58d15e9eac2870d3b4f27263"
+dependencies = [
+ "futures-core",
+]
+
+[[package]]
+name = "synstructure"
+version = "0.13.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "728a70f3dbaf5bab7f0c4b1ac8d7ae5ea60a4b5549c8a5914361c99147a709d2"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.117",
+]
+
+[[package]]
+name = "sys-locale"
+version = "0.3.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8eab9a99a024a169fe8a903cf9d4a3b3601109bcc13bd9e3c6fff259138626c4"
+dependencies = [
+ "libc",
+]
+
+[[package]]
+name = "sysinfo"
+version = "0.31.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "355dbe4f8799b304b05e1b0f05fc59b2a18d36645cf169607da45bde2f69a1be"
+dependencies = [
+ "core-foundation-sys",
+ "libc",
+ "memchr",
+ "ntapi",
+ "rayon",
+ "windows 0.57.0",
+]
+
+[[package]]
+name = "system-configuration"
+version = "0.6.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3c879d448e9d986b661742763247d3693ed13609438cf3d006f51f5368a5ba6b"
+dependencies = [
+ "bitflags 2.11.1",
+ "core-foundation 0.9.4",
+ "system-configuration-sys",
+]
+
+[[package]]
+name = "system-configuration"
+version = "0.7.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a13f3d0daba03132c0aa9767f98351b3488edc2c100cda2d2ec2b04f3d8d3c8b"
+dependencies = [
+ "bitflags 2.11.1",
+ "core-foundation 0.9.4",
+ "system-configuration-sys",
+]
+
+[[package]]
+name = "system-configuration-sys"
+version = "0.6.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8e1d1b10ced5ca923a1fcb8d03e96b8d3268065d724548c0211415ff6ac6bac4"
+dependencies = [
+ "core-foundation-sys",
+ "libc",
+]
+
+[[package]]
+name = "taffy"
+version = "0.9.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a13e5d13f79d558b5d353a98072ca8ca0e99da429467804de959aa8c83c9a004"
+dependencies = [
+ "arrayvec",
+ "grid",
+ "serde",
+ "slotmap",
+]
+
+[[package]]
+name = "tagptr"
+version = "0.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7b2093cf4c8eb1e67749a6762251bc9cd836b6fc171623bd0a9d324d37af2417"
+
+[[package]]
+name = "take-until"
+version = "0.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8bdb6fa0dfa67b38c1e66b7041ba9dcf23b99d8121907cd31c807a332f7a0bbb"
+
+[[package]]
+name = "tao-core-video-sys"
+version = "0.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "271450eb289cb4d8d0720c6ce70c72c8c858c93dd61fc625881616752e6b98f6"
+dependencies = [
+ "cfg-if",
+ "core-foundation-sys",
+ "libc",
+ "objc",
+]
+
+[[package]]
+name = "tempfile"
+version = "3.27.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "32497e9a4c7b38532efcdebeef879707aa9f794296a4f0244f6f69e9bc8574bd"
+dependencies = [
+ "fastrand 2.4.1",
+ "getrandom 0.4.2",
+ "once_cell",
+ "rustix 1.1.4",
+ "windows-sys 0.61.2",
+]
+
+[[package]]
+name = "tendril"
+version = "0.4.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d24a120c5fc464a3458240ee02c299ebcb9d67b5249c8848b09d639dca8d7bb0"
+dependencies = [
+ "futf",
+ "mac",
+ "utf-8",
+]
+
+[[package]]
+name = "termcolor"
+version = "1.4.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "06794f8f6c5c898b3275aebefa6b8a1cb24cd2c6c79397ab15774837a0bc5755"
+dependencies = [
+ "winapi-util",
+]
+
+[[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.18"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4288b5bcbc7920c07a1149a35cf9590a2aa808e0bc1eafaade0b80947865fbc4"
+dependencies = [
+ "thiserror-impl 2.0.18",
+]
+
+[[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 2.0.117",
+]
+
+[[package]]
+name = "thiserror-impl"
+version = "2.0.18"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ebc4ee7f67670e9b64d05fa4253e753e016c6c95ff35b89b7941d6b856dec1d5"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.117",
+]
+
+[[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 = "tiff"
+version = "0.11.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b63feaf3343d35b6ca4d50483f94843803b0f51634937cc2ec519fc32232bc52"
+dependencies = [
+ "fax",
+ "flate2",
+ "half",
+ "quick-error",
+ "weezl",
+ "zune-jpeg",
+]
+
+[[package]]
+name = "time"
+version = "0.3.47"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "743bd48c283afc0388f9b8827b976905fb217ad9e647fae3a379a9283c4def2c"
+dependencies = [
+ "deranged",
+ "itoa",
+ "num-conv",
+ "powerfmt",
+ "serde_core",
+ "time-core",
+ "time-macros",
+]
+
+[[package]]
+name = "time-core"
+version = "0.1.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7694e1cfe791f8d31026952abf09c69ca6f6fa4e1a1229e18988f06a04a12dca"
+
+[[package]]
+name = "time-macros"
+version = "0.2.27"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2e70e4c5a0e0a8a4823ad65dfe1a6930e4f4d756dcd9dd7939022b5e8c501215"
+dependencies = [
+ "num-conv",
+ "time-core",
+]
+
+[[package]]
+name = "tiny-keccak"
+version = "2.0.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2c9d3793400a45f954c52e73d068316d76b6f4e36977e3fcebb13a2721e80237"
+dependencies = [
+ "crunchy",
+]
+
+[[package]]
+name = "tiny-skia"
+version = "0.11.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "83d13394d44dae3207b52a326c0c85a8bf87f1541f23b0d143811088497b09ab"
+dependencies = [
+ "arrayref",
+ "arrayvec",
+ "bytemuck",
+ "cfg-if",
+ "log",
+ "png 0.17.16",
+ "tiny-skia-path",
+]
+
+[[package]]
+name = "tiny-skia-path"
+version = "0.11.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9c9e7fc0c2e86a30b117d0462aa261b72b7a99b7ebd7deb3a14ceda95c5bdc93"
+dependencies = [
+ "arrayref",
+ "bytemuck",
+ "strict-num",
+]
+
+[[package]]
+name = "tinystr"
+version = "0.8.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c8323304221c2a851516f22236c5722a72eaa19749016521d6dff0824447d96d"
+dependencies = [
+ "displaydoc",
+ "zerovec",
+]
+
+[[package]]
+name = "tinyvec"
+version = "1.11.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3e61e67053d25a4e82c844e8424039d9745781b3fc4f32b8d55ed50f5f667ef3"
+dependencies = [
+ "tinyvec_macros",
+]
+
+[[package]]
+name = "tinyvec_macros"
+version = "0.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20"
+
+[[package]]
+name = "tokio"
+version = "1.52.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "110a78583f19d5cdb2c5ccf321d1290344e71313c6c37d43520d386027d18386"
+dependencies = [
+ "bytes",
+ "libc",
+ "mio 1.2.0",
+ "parking_lot 0.12.5",
+ "pin-project-lite",
+ "signal-hook-registry",
+ "socket2 0.6.3",
+ "tokio-macros",
+ "tracing",
+ "windows-sys 0.61.2",
+]
+
+[[package]]
+name = "tokio-macros"
+version = "2.7.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "385a6cb71ab9ab790c5fe8d67f1645e6c450a7ce006a33de03daa956cf70a496"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.117",
+]
+
+[[package]]
+name = "tokio-rustls"
+version = "0.26.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1729aa945f29d91ba541258c8df89027d5792d85a8841fb65e8bf0f4ede4ef61"
+dependencies = [
+ "rustls",
+ "tokio",
+]
+
+[[package]]
+name = "tokio-socks"
+version = "0.5.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0d4770b8024672c1101b3f6733eab95b18007dbe0847a8afe341fcf79e06043f"
+dependencies = [
+ "either",
+ "futures-util",
+ "thiserror 1.0.69",
+ "tokio",
+]
+
+[[package]]
+name = "tokio-util"
+version = "0.7.18"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9ae9cec805b01e8fc3fd2fe289f89149a9b66dd16786abd8b19cfa7b48cb0098"
+dependencies = [
+ "bytes",
+ "futures-core",
+ "futures-io",
+ "futures-sink",
+ "pin-project-lite",
+ "tokio",
+]
+
+[[package]]
+name = "toml"
+version = "0.8.23"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "dc1beb996b9d83529a9e75c17a1686767d148d70663143c7854d8b4a09ced362"
+dependencies = [
+ "serde",
+ "serde_spanned 0.6.9",
+ "toml_datetime 0.6.11",
+ "toml_edit 0.22.27",
+]
+
+[[package]]
+name = "toml"
+version = "1.1.2+spec-1.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "81f3d15e84cbcd896376e6730314d59fb5a87f31e4b038454184435cd57defee"
+dependencies = [
+ "indexmap",
+ "serde_core",
+ "serde_spanned 1.1.1",
+ "toml_datetime 1.1.1+spec-1.1.0",
+ "toml_parser",
+ "toml_writer",
+ "winnow 1.0.2",
+]
+
+[[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_datetime"
+version = "1.1.1+spec-1.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3165f65f62e28e0115a00b2ebdd37eb6f3b641855f9d636d3cd4103767159ad7"
+dependencies = [
+ "serde_core",
+]
+
+[[package]]
+name = "toml_edit"
+version = "0.22.27"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "41fe8c660ae4257887cf66394862d21dbca4a6ddd26f04a3560410406a2f819a"
+dependencies = [
+ "indexmap",
+ "serde",
+ "serde_spanned 0.6.9",
+ "toml_datetime 0.6.11",
+ "toml_write",
+ "winnow 0.7.15",
+]
+
+[[package]]
+name = "toml_edit"
+version = "0.25.11+spec-1.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0b59c4d22ed448339746c59b905d24568fcbb3ab65a500494f7b8c3e97739f2b"
+dependencies = [
+ "indexmap",
+ "toml_datetime 1.1.1+spec-1.1.0",
+ "toml_parser",
+ "winnow 1.0.2",
+]
+
+[[package]]
+name = "toml_parser"
+version = "1.1.2+spec-1.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a2abe9b86193656635d2411dc43050282ca48aa31c2451210f4202550afb7526"
+dependencies = [
+ "winnow 1.0.2",
+]
+
+[[package]]
+name = "toml_write"
+version = "0.1.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5d99f8c9a7727884afe522e9bd5edbfc91a3312b36a77b5fb8926e4c31a41801"
+
+[[package]]
+name = "toml_writer"
+version = "1.1.1+spec-1.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "756daf9b1013ebe47a8776667b466417e2d4c5679d441c26230efd9ef78692db"
+
+[[package]]
+name = "tower"
+version = "0.5.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ebe5ef63511595f1344e2d5cfa636d973292adc0eec1f0ad45fae9f0851ab1d4"
+dependencies = [
+ "futures-core",
+ "futures-util",
+ "pin-project-lite",
+ "sync_wrapper",
+ "tokio",
+ "tower-layer",
+ "tower-service",
+]
+
+[[package]]
+name = "tower-layer"
+version = "0.3.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "121c2a6cda46980bb0fcd1647ffaf6cd3fc79a013de288782836f6df9c48780e"
+
+[[package]]
+name = "tower-service"
+version = "0.3.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8df9b6e13f2d32c91b9bd719c00d1958837bc7dec474d94952798cc8e69eeec3"
+
+[[package]]
+name = "tracing"
+version = "0.1.44"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "63e71662fa4b2a2c3a26f570f037eb95bb1f85397f3cd8076caed2f026a6d100"
+dependencies = [
+ "pin-project-lite",
+ "tracing-attributes",
+ "tracing-core",
+]
+
+[[package]]
+name = "tracing-attributes"
+version = "0.1.31"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7490cfa5ec963746568740651ac6781f701c9c5ea257c58e057f3ba8cf69e8da"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.117",
+]
+
+[[package]]
+name = "tracing-core"
+version = "0.1.36"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "db97caf9d906fbde555dd62fa95ddba9eecfd14cb388e4f491a66d74cd5fb79a"
+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.23"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "cb7f578e5945fb242538965c2d0b04418d38ec25c79d160cd279bf0731c8d319"
+dependencies = [
+ "matchers",
+ "nu-ansi-term",
+ "once_cell",
+ "regex-automata",
+ "sharded-slab",
+ "smallvec",
+ "thread_local",
+ "tracing",
+ "tracing-core",
+ "tracing-log",
+]
+
+[[package]]
+name = "tree-sitter"
+version = "0.24.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a5387dffa7ffc7d2dae12b50c6f7aab8ff79d6210147c6613561fc3d474c6f75"
+dependencies = [
+ "cc",
+ "regex",
+ "regex-syntax",
+ "streaming-iterator",
+ "tree-sitter-language",
+]
+
+[[package]]
+name = "tree-sitter-language"
+version = "0.1.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "009994f150cc0cd50ff54917d5bc8bffe8cad10ca10d81c34da2ec421ae61782"
+
+[[package]]
+name = "tree-sitter-rust"
+version = "0.23.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ca8ccb3e3a3495c8a943f6c3fd24c3804c471fd7f4f16087623c7fa4c0068e8a"
+dependencies = [
+ "cc",
+ "tree-sitter-language",
+]
+
+[[package]]
+name = "try-lock"
+version = "0.2.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b"
+
+[[package]]
+name = "ttf-parser"
+version = "0.20.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "17f77d76d837a7830fe1d4f12b7b4ba4192c1888001c7164257e4bc6d21d96b4"
+
+[[package]]
+name = "ttf-parser"
+version = "0.21.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2c591d83f69777866b9126b24c6dd9a18351f177e49d625920d19f989fd31cf8"
+
+[[package]]
+name = "ttf-parser"
+version = "0.25.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d2df906b07856748fa3f6e0ad0cbaa047052d4a7dd609e231c4f72cee8c36f31"
+dependencies = [
+ "core_maths",
+]
+
+[[package]]
+name = "typeid"
+version = "1.0.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bc7d623258602320d5c55d1bc22793b57daff0ec7efc270ea7d55ce1d5f5471c"
+
+[[package]]
+name = "typenum"
+version = "1.20.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "40ce102ab67701b8526c123c1bab5cbe42d7040ccfd0f64af1a385808d2f43de"
+
+[[package]]
+name = "uds_windows"
+version = "1.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f2f6fb2847f6742cd76af783a2a2c49e9375d0a111c7bef6f71cd9e738c72d6e"
+dependencies = [
+ "memoffset",
+ "tempfile",
+ "windows-sys 0.61.2",
+]
+
+[[package]]
+name = "uint"
+version = "0.10.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "909988d098b2f738727b161a106cfc7cab00c539c2687a8836f8e565976fb53e"
+dependencies = [
+ "byteorder",
+ "crunchy",
+ "hex",
+ "static_assertions",
+]
+
+[[package]]
+name = "ulid"
+version = "1.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "470dbf6591da1b39d43c14523b2b469c86879a53e8b758c8e090a470fe7b1fbe"
+dependencies = [
+ "rand 0.9.4",
+ "serde",
+ "web-time",
+]
+
+[[package]]
+name = "unicase"
+version = "2.9.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "dbc4bc3a9f746d862c45cb89d705aa10f187bb96c76001afab07a0d35ce60142"
+
+[[package]]
+name = "unicode-bidi"
+version = "0.3.18"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5c1cb5db39152898a79168971543b1cb5020dff7fe43c8dc468b0885f5e29df5"
+
+[[package]]
+name = "unicode-bidi-mirroring"
+version = "0.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "23cb788ffebc92c5948d0e997106233eeb1d8b9512f93f41651f52b6c5f5af86"
+
+[[package]]
+name = "unicode-bidi-mirroring"
+version = "0.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5dfa6e8c60bb66d49db113e0125ee8711b7647b5579dc7f5f19c42357ed039fe"
+
+[[package]]
+name = "unicode-ccc"
+version = "0.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1df77b101bcc4ea3d78dafc5ad7e4f58ceffe0b2b16bf446aeb50b6cb4157656"
+
+[[package]]
+name = "unicode-ccc"
+version = "0.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ce61d488bcdc9bc8b5d1772c404828b17fc481c0a582b5581e95fb233aef503e"
+
+[[package]]
+name = "unicode-ident"
+version = "1.0.24"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75"
+
+[[package]]
+name = "unicode-linebreak"
+version = "0.1.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3b09c83c3c29d37506a3e260c08c03743a6bb66a9cd432c6934ab501a190571f"
+
+[[package]]
+name = "unicode-properties"
+version = "0.1.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7df058c713841ad818f1dc5d3fd88063241cc61f49f5fbea4b951e8cf5a8d71d"
+
+[[package]]
+name = "unicode-script"
+version = "0.5.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "383ad40bb927465ec0ce7720e033cb4ca06912855fc35db31b5755d0de75b1ee"
+
+[[package]]
+name = "unicode-segmentation"
+version = "1.13.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9629274872b2bfaf8d66f5f15725007f635594914870f65218920345aa11aa8c"
+
+[[package]]
+name = "unicode-vo"
+version = "0.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b1d386ff53b415b7fe27b50bb44679e2cc4660272694b7b6f3326d8480823a94"
+
+[[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 = "universal-hash"
+version = "0.5.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "fc1de2c688dc15305988b563c3854064043356019f97a4b46276fe734c4f07ea"
+dependencies = [
+ "crypto-common",
+ "subtle",
+]
+
+[[package]]
+name = "unsigned-varint"
+version = "0.7.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6889a77d49f1f013504cec6bf97a2c730394adedaeb1deb5ea08949a50541105"
+
+[[package]]
+name = "unsigned-varint"
+version = "0.8.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "eb066959b24b5196ae73cb057f45598450d2c5f71460e98c49b738086eff9c06"
+
+[[package]]
+name = "untrusted"
+version = "0.9.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1"
+
+[[package]]
+name = "url"
+version = "2.5.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ff67a8a4397373c3ef660812acab3268222035010ab8680ec4215f38ba3d0eed"
+dependencies = [
+ "form_urlencoded",
+ "idna",
+ "percent-encoding",
+ "serde",
+ "serde_derive",
+]
+
+[[package]]
+name = "usvg"
+version = "0.45.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "80be9b06fbae3b8b303400ab20778c80bbaf338f563afe567cf3c9eea17b47ef"
+dependencies = [
+ "base64",
+ "data-url",
+ "flate2",
+ "fontdb 0.23.0",
+ "imagesize",
+ "kurbo",
+ "log",
+ "pico-args",
+ "roxmltree",
+ "rustybuzz 0.20.1",
+ "simplecss",
+ "siphasher",
+ "strict-num",
+ "svgtypes",
+ "tiny-skia-path",
+ "unicode-bidi",
+ "unicode-script",
+ "unicode-vo",
+ "xmlwriter",
+]
+
+[[package]]
+name = "utf-8"
+version = "0.7.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "09cc8ee72d2a9becf2f2febe0205bbed8fc6615b7cb429ad062dc7b7ddd036a9"
+
+[[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 = "uuid"
+version = "1.23.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ddd74a9687298c6858e9b88ec8935ec45d22e8fd5e6394fa1bd4e99a87789c76"
+dependencies = [
+ "getrandom 0.4.2",
+ "js-sys",
+ "serde_core",
+ "sha1_smol",
+ "wasm-bindgen",
+]
+
+[[package]]
+name = "v_frame"
+version = "0.3.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "666b7727c8875d6ab5db9533418d7c764233ac9c0cff1d469aec8fa127597be2"
+dependencies = [
+ "aligned-vec",
+ "num-traits",
+ "wasm-bindgen",
+]
+
+[[package]]
+name = "valuable"
+version = "0.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ba73ea9cf16a25df0c8caa16c51acb937d5712a8429db78a3ee29d5dcacd3a65"
+
+[[package]]
+name = "value-bag"
+version = "1.12.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7ba6f5989077681266825251a52748b8c1d8a4ad098cc37e440103d0ea717fc0"
+dependencies = [
+ "value-bag-serde1",
+ "value-bag-sval2",
+]
+
+[[package]]
+name = "value-bag-serde1"
+version = "1.12.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "16530907bfe2999a1773ca5900a65101e092c70f642f25cc23ca0c43573262c5"
+dependencies = [
+ "erased-serde",
+ "serde_core",
+ "serde_fmt",
+]
+
+[[package]]
+name = "value-bag-sval2"
+version = "1.12.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d00ae130edd690eaa877e4f40605d534790d1cf1d651e7685bd6a144521b251f"
+dependencies = [
+ "sval",
+ "sval_buffer",
+ "sval_dynamic",
+ "sval_fmt",
+ "sval_json",
+ "sval_ref",
+ "sval_serde",
+]
+
+[[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 = "vswhom"
+version = "0.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "be979b7f07507105799e854203b470ff7c78a1639e330a58f183b5fea574608b"
+dependencies = [
+ "libc",
+ "vswhom-sys",
+]
+
+[[package]]
+name = "vswhom-sys"
+version = "0.1.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "fb067e4cbd1ff067d1df46c9194b5de0e98efd2810bbc95c5d5e5f25a3231150"
+dependencies = [
+ "cc",
+ "libc",
+]
+
+[[package]]
+name = "waker-fn"
+version = "1.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "317211a0dc0ceedd78fb2ca9a44aed3d7b9b26f81870d485c07122b4350673b7"
+
+[[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 = "want"
+version = "0.3.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bfa7760aed19e106de2c7c0b581b509f2f25d3dacaf737cb82ac61bc6d760b0e"
+dependencies = [
+ "try-lock",
+]
+
+[[package]]
+name = "wasi"
+version = "0.11.1+wasi-snapshot-preview1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b"
+
+[[package]]
+name = "wasip2"
+version = "1.0.3+wasi-0.2.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "20064672db26d7cdc89c7798c48a0fdfac8213434a1186e5ef29fd560ae223d6"
+dependencies = [
+ "wit-bindgen 0.57.1",
+]
+
+[[package]]
+name = "wasip3"
+version = "0.4.0+wasi-0.3.0-rc-2026-01-06"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5428f8bf88ea5ddc08faddef2ac4a67e390b88186c703ce6dbd955e1c145aca5"
+dependencies = [
+ "wit-bindgen 0.51.0",
+]
+
+[[package]]
+name = "wasm-bindgen"
+version = "0.2.121"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "49ace1d07c165b0864824eee619580c4689389afa9dc9ed3a4c75040d82e6790"
+dependencies = [
+ "cfg-if",
+ "once_cell",
+ "rustversion",
+ "wasm-bindgen-macro",
+ "wasm-bindgen-shared",
+]
+
+[[package]]
+name = "wasm-bindgen-futures"
+version = "0.4.71"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "96492d0d3ffba25305a7dc88720d250b1401d7edca02cc3bcd50633b424673b8"
+dependencies = [
+ "js-sys",
+ "wasm-bindgen",
+]
+
+[[package]]
+name = "wasm-bindgen-macro"
+version = "0.2.121"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8e68e6f4afd367a562002c05637acb8578ff2dea1943df76afb9e83d177c8578"
+dependencies = [
+ "quote",
+ "wasm-bindgen-macro-support",
+]
+
+[[package]]
+name = "wasm-bindgen-macro-support"
+version = "0.2.121"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d95a9ec35c64b2a7cb35d3fead40c4238d0940c86d107136999567a4703259f2"
+dependencies = [
+ "bumpalo",
+ "proc-macro2",
+ "quote",
+ "syn 2.0.117",
+ "wasm-bindgen-shared",
+]
+
+[[package]]
+name = "wasm-bindgen-shared"
+version = "0.2.121"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c4e0100b01e9f0d03189a92b96772a1fb998639d981193d7dbab487302513441"
+dependencies = [
+ "unicode-ident",
+]
+
+[[package]]
+name = "wasm-encoder"
+version = "0.244.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "990065f2fe63003fe337b932cfb5e3b80e0b4d0f5ff650e6985b1048f62c8319"
+dependencies = [
+ "leb128fmt",
+ "wasmparser 0.244.0",
+]
+
+[[package]]
+name = "wasm-encoder"
+version = "0.248.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ac92cf547bc18d27ecc521015c08c353b4f18b84ab388bb6d1b6b682c620d9b6"
+dependencies = [
+ "leb128fmt",
+ "wasmparser 0.248.0",
+]
+
+[[package]]
+name = "wasm-metadata"
+version = "0.244.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bb0e353e6a2fbdc176932bbaab493762eb1255a7900fe0fea1a2f96c296cc909"
+dependencies = [
+ "anyhow",
+ "indexmap",
+ "wasm-encoder 0.244.0",
+ "wasmparser 0.244.0",
+]
+
+[[package]]
+name = "wasm-streams"
+version = "0.4.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "15053d8d85c7eccdbefef60f06769760a563c7f0a9d6902a13d35c7800b0ad65"
+dependencies = [
+ "futures-util",
+ "js-sys",
+ "wasm-bindgen",
+ "wasm-bindgen-futures",
+ "web-sys",
+]
+
+[[package]]
+name = "wasmi"
+version = "0.40.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a19af97fcb96045dd1d6b4d23e2b4abdbbe81723dbc5c9f016eb52145b320063"
+dependencies = [
+ "arrayvec",
+ "multi-stash",
+ "smallvec",
+ "spin",
+ "wasmi_collections",
+ "wasmi_core",
+ "wasmi_ir",
+ "wasmparser 0.221.3",
+]
+
+[[package]]
+name = "wasmi_collections"
+version = "0.40.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e80d6b275b1c922021939d561574bf376613493ae2b61c6963b15db0e8813562"
+dependencies = [
+ "string-interner",
+]
+
+[[package]]
+name = "wasmi_core"
+version = "0.40.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3a8c51482cc32d31c2c7ff211cd2bedd73c5bd057ba16a2ed0110e7a96097c33"
+dependencies = [
+ "downcast-rs",
+ "libm",
+]
+
+[[package]]
+name = "wasmi_ir"
+version = "0.40.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6e431a14c186db59212a88516788bd68ed51f87aa1e08d1df742522867b5289a"
+dependencies = [
+ "wasmi_core",
+]
+
+[[package]]
+name = "wasmparser"
+version = "0.221.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d06bfa36ab3ac2be0dee563380147a5b81ba10dd8885d7fbbc9eb574be67d185"
+dependencies = [
+ "bitflags 2.11.1",
+ "indexmap",
+]
+
+[[package]]
+name = "wasmparser"
+version = "0.244.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "47b807c72e1bac69382b3a6fb3dbe8ea4c0ed87ff5629b8685ae6b9a611028fe"
+dependencies = [
+ "bitflags 2.11.1",
+ "hashbrown 0.15.5",
+ "indexmap",
+ "semver",
+]
+
+[[package]]
+name = "wasmparser"
+version = "0.248.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "aa4439c5eee9df71ee0c6efb37f63b1fcb1fec38f85f5142c54e7ed05d33091a"
+dependencies = [
+ "bitflags 2.11.1",
+ "indexmap",
+ "semver",
+]
+
+[[package]]
+name = "wast"
+version = "248.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "acc54622ed5a5cddafcdf152043f9d4aed54d4a653d686b7dfe874809fca99d7"
+dependencies = [
+ "bumpalo",
+ "leb128fmt",
+ "memchr",
+ "unicode-width",
+ "wasm-encoder 0.248.0",
+]
+
+[[package]]
+name = "wat"
+version = "1.248.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d75cd9e510603909748e6ebab89f27cd04472c1d9d85a3c88a7a6fc51a1a7934"
+dependencies = [
+ "wast",
+]
+
+[[package]]
+name = "wayland-backend"
+version = "0.3.15"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2857dd20b54e916ec7253b3d6b4d5c4d7d4ca2c33c2e11c6c76a99bd8744755d"
+dependencies = [
+ "cc",
+ "downcast-rs",
+ "rustix 1.1.4",
+ "scoped-tls",
+ "smallvec",
+ "wayland-sys",
+]
+
+[[package]]
+name = "wayland-client"
+version = "0.31.14"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "645c7c96bb74690c3189b5c9cb4ca1627062bb23693a4fad9d8c3de958260144"
+dependencies = [
+ "bitflags 2.11.1",
+ "rustix 1.1.4",
+ "wayland-backend",
+ "wayland-scanner",
+]
+
+[[package]]
+name = "wayland-cursor"
+version = "0.31.14"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4a52d18780be9b1314328a3de5f930b73d2200112e3849ca6cb11822793fb34d"
+dependencies = [
+ "rustix 1.1.4",
+ "wayland-client",
+ "xcursor",
+]
+
+[[package]]
+name = "wayland-protocols"
+version = "0.31.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8f81f365b8b4a97f422ac0e8737c438024b5951734506b0e1d775c73030561f4"
+dependencies = [
+ "bitflags 2.11.1",
+ "wayland-backend",
+ "wayland-client",
+ "wayland-scanner",
+]
+
+[[package]]
+name = "wayland-protocols"
+version = "0.32.12"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "563a85523cade2429938e790815fd7319062103b9f4a2dc806e9b53b95982d8f"
+dependencies = [
+ "bitflags 2.11.1",
+ "wayland-backend",
+ "wayland-client",
+ "wayland-scanner",
+]
+
+[[package]]
+name = "wayland-protocols-plasma"
+version = "0.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "23803551115ff9ea9bce586860c5c5a971e360825a0309264102a9495a5ff479"
+dependencies = [
+ "bitflags 2.11.1",
+ "wayland-backend",
+ "wayland-client",
+ "wayland-protocols 0.31.2",
+ "wayland-scanner",
+]
+
+[[package]]
+name = "wayland-scanner"
+version = "0.31.10"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9c324a910fd86ebdc364a3e61ec1f11737d3b1d6c273c0239ee8ff4bc0d24b4a"
+dependencies = [
+ "proc-macro2",
+ "quick-xml 0.39.3",
+ "quote",
+]
+
+[[package]]
+name = "wayland-sys"
+version = "0.31.11"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d8eab23fefc9e41f8e841df4a9c707e8a8c4ed26e944ef69297184de2785e3be"
+dependencies = [
+ "dlib",
+ "log",
+ "once_cell",
+ "pkg-config",
+]
+
+[[package]]
+name = "web-sys"
+version = "0.3.98"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4b572dff8bcf38bad0fa19729c89bb5748b2b9b1d8be70cf90df697e3a8f32aa"
+dependencies = [
+ "js-sys",
+ "wasm-bindgen",
+]
+
+[[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 = "weezl"
+version = "0.1.12"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a28ac98ddc8b9274cb41bb4d9d4d5c425b6020c50c46f25559911905610b4a88"
+
+[[package]]
+name = "which"
+version = "6.0.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b4ee928febd44d98f2f459a4a79bd4d928591333a494a10a868418ac1b39cf1f"
+dependencies = [
+ "either",
+ "home",
+ "rustix 0.38.44",
+ "winsafe",
+]
+
+[[package]]
+name = "widestring"
+version = "1.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "72069c3113ab32ab29e5584db3c6ec55d416895e60715417b5b883a357c3e471"
+
+[[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"
+version = "0.57.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "12342cb4d8e3b046f3d80effd474a7a02447231330ef77d71daa6fbc40681143"
+dependencies = [
+ "windows-core 0.57.0",
+ "windows-targets 0.52.6",
+]
+
+[[package]]
+name = "windows"
+version = "0.61.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9babd3a767a4c1aef6900409f85f5d53ce2544ccdfaa86dad48c91782c6d6893"
+dependencies = [
+ "windows-collections 0.2.0",
+ "windows-core 0.61.2",
+ "windows-future 0.2.1",
+ "windows-link 0.1.3",
+ "windows-numerics 0.2.0",
+]
+
+[[package]]
+name = "windows"
+version = "0.62.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "527fadee13e0c05939a6a05d5bd6eec6cd2e3dbd648b9f8e447c6518133d8580"
+dependencies = [
+ "windows-collections 0.3.2",
+ "windows-core 0.62.2",
+ "windows-future 0.3.2",
+ "windows-numerics 0.3.1",
+]
+
+[[package]]
+name = "windows-capture"
+version = "1.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3a4df73e95feddb9ec1a7e9c2ca6323b8c97d5eeeff78d28f1eccdf19c882b24"
+dependencies = [
+ "parking_lot 0.12.5",
+ "rayon",
+ "thiserror 2.0.18",
+ "windows 0.61.3",
+ "windows-future 0.2.1",
+]
+
+[[package]]
+name = "windows-collections"
+version = "0.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3beeceb5e5cfd9eb1d76b381630e82c4241ccd0d27f1a39ed41b2760b255c5e8"
+dependencies = [
+ "windows-core 0.61.2",
+]
+
+[[package]]
+name = "windows-collections"
+version = "0.3.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "23b2d95af1a8a14a3c7367e1ed4fc9c20e0a26e79551b1454d72583c97cc6610"
+dependencies = [
+ "windows-core 0.62.2",
+]
+
+[[package]]
+name = "windows-core"
+version = "0.57.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d2ed2439a290666cd67ecce2b0ffaad89c2a56b976b736e6ece670297897832d"
+dependencies = [
+ "windows-implement 0.57.0",
+ "windows-interface 0.57.0",
+ "windows-result 0.1.2",
+ "windows-targets 0.52.6",
+]
+
+[[package]]
+name = "windows-core"
+version = "0.61.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c0fdd3ddb90610c7638aa2b3a3ab2904fb9e5cdbecc643ddb3647212781c4ae3"
+dependencies = [
+ "windows-implement 0.60.2",
+ "windows-interface 0.59.3",
+ "windows-link 0.1.3",
+ "windows-result 0.3.4",
+ "windows-strings 0.4.2",
+]
+
+[[package]]
+name = "windows-core"
+version = "0.62.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b8e83a14d34d0623b51dce9581199302a221863196a1dde71a7663a4c2be9deb"
+dependencies = [
+ "windows-implement 0.60.2",
+ "windows-interface 0.59.3",
+ "windows-link 0.2.1",
+ "windows-result 0.4.1",
+ "windows-strings 0.5.1",
+]
+
+[[package]]
+name = "windows-future"
+version = "0.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "fc6a41e98427b19fe4b73c550f060b59fa592d7d686537eebf9385621bfbad8e"
+dependencies = [
+ "windows-core 0.61.2",
+ "windows-link 0.1.3",
+ "windows-threading 0.1.0",
+]
+
+[[package]]
+name = "windows-future"
+version = "0.3.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e1d6f90251fe18a279739e78025bd6ddc52a7e22f921070ccdc67dde84c605cb"
+dependencies = [
+ "windows-core 0.62.2",
+ "windows-link 0.2.1",
+ "windows-threading 0.2.1",
+]
+
+[[package]]
+name = "windows-implement"
+version = "0.57.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9107ddc059d5b6fbfbffdfa7a7fe3e22a226def0b2608f72e9d552763d3e1ad7"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.117",
+]
+
+[[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 2.0.117",
+]
+
+[[package]]
+name = "windows-interface"
+version = "0.57.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "29bee4b38ea3cde66011baa44dba677c432a78593e202392d1e9070cf2a7fca7"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.117",
+]
+
+[[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 2.0.117",
+]
+
+[[package]]
+name = "windows-link"
+version = "0.1.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5e6ad25900d524eaabdbbb96d20b4311e1e7ae1699af4fb28c17ae66c80d798a"
+
+[[package]]
+name = "windows-link"
+version = "0.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5"
+
+[[package]]
+name = "windows-numerics"
+version = "0.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9150af68066c4c5c07ddc0ce30421554771e528bde427614c61038bc2c92c2b1"
+dependencies = [
+ "windows-core 0.61.2",
+ "windows-link 0.1.3",
+]
+
+[[package]]
+name = "windows-numerics"
+version = "0.3.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6e2e40844ac143cdb44aead537bbf727de9b044e107a0f1220392177d15b0f26"
+dependencies = [
+ "windows-core 0.62.2",
+ "windows-link 0.2.1",
+]
+
+[[package]]
+name = "windows-registry"
+version = "0.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4286ad90ddb45071efd1a66dfa43eb02dd0dfbae1545ad6cc3c51cf34d7e8ba3"
+dependencies = [
+ "windows-result 0.3.4",
+ "windows-strings 0.3.1",
+ "windows-targets 0.53.5",
+]
+
+[[package]]
+name = "windows-registry"
+version = "0.5.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5b8a9ed28765efc97bbc954883f4e6796c33a06546ebafacbabee9696967499e"
+dependencies = [
+ "windows-link 0.1.3",
+ "windows-result 0.3.4",
+ "windows-strings 0.4.2",
+]
+
+[[package]]
+name = "windows-registry"
+version = "0.6.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "02752bf7fbdcce7f2a27a742f798510f3e5ad88dbe84871e5168e2120c3d5720"
+dependencies = [
+ "windows-link 0.2.1",
+ "windows-result 0.4.1",
+ "windows-strings 0.5.1",
+]
+
+[[package]]
+name = "windows-result"
+version = "0.1.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5e383302e8ec8515204254685643de10811af0ed97ea37210dc26fb0032647f8"
+dependencies = [
+ "windows-targets 0.52.6",
+]
+
+[[package]]
+name = "windows-result"
+version = "0.3.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "56f42bd332cc6c8eac5af113fc0c1fd6a8fd2aa08a0119358686e5160d0586c6"
+dependencies = [
+ "windows-link 0.1.3",
+]
+
+[[package]]
+name = "windows-result"
+version = "0.4.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7781fa89eaf60850ac3d2da7af8e5242a5ea78d1a11c49bf2910bb5a73853eb5"
+dependencies = [
+ "windows-link 0.2.1",
+]
+
+[[package]]
+name = "windows-strings"
+version = "0.3.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "87fa48cc5d406560701792be122a10132491cff9d0aeb23583cc2dcafc847319"
+dependencies = [
+ "windows-link 0.1.3",
+]
+
+[[package]]
+name = "windows-strings"
+version = "0.4.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "56e6c93f3a0c3b36176cb1327a4958a0353d5d166c2a35cb268ace15e91d3b57"
+dependencies = [
+ "windows-link 0.1.3",
+]
+
+[[package]]
+name = "windows-strings"
+version = "0.5.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7837d08f69c77cf6b07689544538e017c1bfcf57e34b4c0ff58e6c2cd3b37091"
+dependencies = [
+ "windows-link 0.2.1",
+]
+
+[[package]]
+name = "windows-sys"
+version = "0.48.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9"
+dependencies = [
+ "windows-targets 0.48.5",
+]
+
+[[package]]
+name = "windows-sys"
+version = "0.52.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d"
+dependencies = [
+ "windows-targets 0.52.6",
+]
+
+[[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 0.2.1",
+]
+
+[[package]]
+name = "windows-targets"
+version = "0.48.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c"
+dependencies = [
+ "windows_aarch64_gnullvm 0.48.5",
+ "windows_aarch64_msvc 0.48.5",
+ "windows_i686_gnu 0.48.5",
+ "windows_i686_msvc 0.48.5",
+ "windows_x86_64_gnu 0.48.5",
+ "windows_x86_64_gnullvm 0.48.5",
+ "windows_x86_64_msvc 0.48.5",
+]
+
+[[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 0.2.1",
+ "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-threading"
+version = "0.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b66463ad2e0ea3bbf808b7f1d371311c80e115c0b71d60efc142cafbcfb057a6"
+dependencies = [
+ "windows-link 0.1.3",
+]
+
+[[package]]
+name = "windows-threading"
+version = "0.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3949bd5b99cafdf1c7ca86b43ca564028dfe27d66958f2470940f73d86d75b37"
+dependencies = [
+ "windows-link 0.2.1",
+]
+
+[[package]]
+name = "windows_aarch64_gnullvm"
+version = "0.48.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8"
+
+[[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.48.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc"
+
+[[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.48.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e"
+
+[[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.48.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406"
+
+[[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.48.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e"
+
+[[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.48.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc"
+
+[[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.48.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538"
+
+[[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.15"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "df79d97927682d2fd8adb29682d1140b343be4ac0f08fd68b7765d9c059d3945"
+dependencies = [
+ "memchr",
+]
+
+[[package]]
+name = "winnow"
+version = "1.0.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2ee1708bef14716a11bae175f579062d4554d95be2c6829f518df847b7b3fdd0"
+dependencies = [
+ "memchr",
+]
+
+[[package]]
+name = "winreg"
+version = "0.55.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "cb5a765337c50e9ec252c2069be9bf91c7df47afb103b642ba3a53bf8101be97"
+dependencies = [
+ "cfg-if",
+ "windows-sys 0.59.0",
+]
+
+[[package]]
+name = "winsafe"
+version = "0.0.19"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d135d17ab770252ad95e9a872d365cf3090e3be864a34ab46f48555993efc904"
+
+[[package]]
+name = "wio"
+version = "0.2.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5d129932f4644ac2396cb456385cbf9e63b5b30c6e8dc4820bdca4eb082037a5"
+dependencies = [
+ "winapi",
+]
+
+[[package]]
+name = "wit-bindgen"
+version = "0.51.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d7249219f66ced02969388cf2bb044a09756a083d0fab1e566056b04d9fbcaa5"
+dependencies = [
+ "wit-bindgen-rust-macro",
+]
+
+[[package]]
+name = "wit-bindgen"
+version = "0.57.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1ebf944e87a7c253233ad6766e082e3cd714b5d03812acc24c318f549614536e"
+
+[[package]]
+name = "wit-bindgen-core"
+version = "0.51.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ea61de684c3ea68cb082b7a88508a8b27fcc8b797d738bfc99a82facf1d752dc"
+dependencies = [
+ "anyhow",
+ "heck 0.5.0",
+ "wit-parser",
+]
+
+[[package]]
+name = "wit-bindgen-rust"
+version = "0.51.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b7c566e0f4b284dd6561c786d9cb0142da491f46a9fbed79ea69cdad5db17f21"
+dependencies = [
+ "anyhow",
+ "heck 0.5.0",
+ "indexmap",
+ "prettyplease",
+ "syn 2.0.117",
+ "wasm-metadata",
+ "wit-bindgen-core",
+ "wit-component",
+]
+
+[[package]]
+name = "wit-bindgen-rust-macro"
+version = "0.51.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0c0f9bfd77e6a48eccf51359e3ae77140a7f50b1e2ebfe62422d8afdaffab17a"
+dependencies = [
+ "anyhow",
+ "prettyplease",
+ "proc-macro2",
+ "quote",
+ "syn 2.0.117",
+ "wit-bindgen-core",
+ "wit-bindgen-rust",
+]
+
+[[package]]
+name = "wit-component"
+version = "0.244.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9d66ea20e9553b30172b5e831994e35fbde2d165325bec84fc43dbf6f4eb9cb2"
+dependencies = [
+ "anyhow",
+ "bitflags 2.11.1",
+ "indexmap",
+ "log",
+ "serde",
+ "serde_derive",
+ "serde_json",
+ "wasm-encoder 0.244.0",
+ "wasm-metadata",
+ "wasmparser 0.244.0",
+ "wit-parser",
+]
+
+[[package]]
+name = "wit-parser"
+version = "0.244.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ecc8ac4bc1dc3381b7f59c34f00b67e18f910c2c0f50015669dde7def656a736"
+dependencies = [
+ "anyhow",
+ "id-arena",
+ "indexmap",
+ "log",
+ "semver",
+ "serde",
+ "serde_derive",
+ "serde_json",
+ "unicode-xid",
+ "wasmparser 0.244.0",
+]
+
+[[package]]
+name = "writeable"
+version = "0.6.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1ffae5123b2d3fc086436f8834ae3ab053a283cfac8fe0a0b8eaae044768a4c4"
+
+[[package]]
+name = "x11"
+version = "2.21.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "502da5464ccd04011667b11c435cb992822c2c0dbde1770c988480d312a0db2e"
+dependencies = [
+ "libc",
+ "pkg-config",
+]
+
+[[package]]
+name = "x11-clipboard"
+version = "0.9.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "662d74b3d77e396b8e5beb00b9cad6a9eccf40b2ef68cc858784b14c41d535a3"
+dependencies = [
+ "libc",
+ "x11rb",
+]
+
+[[package]]
+name = "x11rb"
+version = "0.13.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9993aa5be5a26815fe2c3eacfc1fde061fc1a1f094bf1ad2a18bf9c495dd7414"
+dependencies = [
+ "as-raw-xcb-connection",
+ "gethostname",
+ "libc",
+ "rustix 1.1.4",
+ "x11rb-protocol",
+ "xcursor",
+]
+
+[[package]]
+name = "x11rb-protocol"
+version = "0.13.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ea6fc2961e4ef194dcbfe56bb845534d0dc8098940c7e5c012a258bfec6701bd"
+
+[[package]]
+name = "x25519-dalek"
+version = "2.0.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c7e468321c81fb07fa7f4c636c3972b9100f0346e5b6a9f2bd0603a52f7ed277"
+dependencies = [
+ "curve25519-dalek",
+ "rand_core 0.6.4",
+ "serde",
+ "zeroize",
+]
+
+[[package]]
+name = "x509-parser"
+version = "0.17.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4569f339c0c402346d4a75a9e39cf8dad310e287eef1ff56d4c68e5067f53460"
+dependencies = [
+ "asn1-rs",
+ "data-encoding",
+ "der-parser",
+ "lazy_static",
+ "nom 7.1.3",
+ "oid-registry",
+ "rusticata-macros",
+ "thiserror 2.0.18",
+ "time",
+]
+
+[[package]]
+name = "xattr"
+version = "0.2.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6d1526bbe5aaeb5eb06885f4d987bcdfa5e23187055de9b83fe00156a821fabc"
+dependencies = [
+ "libc",
+]
+
+[[package]]
+name = "xcb"
+version = "1.7.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ee4c580d8205abb0a5cf4eb7e927bd664e425b6c3263f9c5310583da96970cf6"
+dependencies = [
+ "bitflags 1.3.2",
+ "libc",
+ "quick-xml 0.30.0",
+ "x11",
+]
+
+[[package]]
+name = "xcursor"
+version = "0.3.10"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bec9e4a500ca8864c5b47b8b482a73d62e4237670e5b5f1d6b9e3cae50f28f2b"
+
+[[package]]
+name = "xdg-home"
+version = "1.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ec1cdab258fb55c0da61328dc52c8764709b249011b2cad0454c72f0bf10a1f6"
+dependencies = [
+ "libc",
+ "windows-sys 0.59.0",
+]
+
+[[package]]
+name = "xim-ctext"
+version = "0.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2ac61a7062c40f3c37b6e82eeeef835d5cc7824b632a72784a89b3963c33284c"
+dependencies = [
+ "encoding_rs",
+]
+
+[[package]]
+name = "xim-parser"
+version = "0.2.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5dcee45f89572d5a65180af3a84e7ddb24f5ea690a6d3aa9de231281544dd7b7"
+dependencies = [
+ "bitflags 2.11.1",
+]
+
+[[package]]
+name = "xkbcommon"
+version = "0.8.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8d66ca9352cbd4eecbbc40871d8a11b4ac8107cfc528a6e14d7c19c69d0e1ac9"
+dependencies = [
+ "as-raw-xcb-connection",
+ "libc",
+ "memmap2",
+ "xkeysym",
+]
+
+[[package]]
+name = "xkeysym"
+version = "0.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b9cc00251562a284751c9973bace760d86c0276c471b4be569fe6b068ee97a56"
+
+[[package]]
+name = "xml-rs"
+version = "0.8.28"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3ae8337f8a065cfc972643663ea4279e04e7256de865aa66fe25cec5fb912d3f"
+
+[[package]]
+name = "xmltree"
+version = "0.10.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d7d8a75eaf6557bb84a65ace8609883db44a29951042ada9b393151532e41fcb"
+dependencies = [
+ "xml-rs",
+]
+
+[[package]]
+name = "xmlwriter"
+version = "0.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ec7a2a501ed189703dba8b08142f057e887dfc4b2cc4db2d343ac6376ba3e0b9"
+
+[[package]]
+name = "y4m"
+version = "0.8.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7a5a4b21e1a62b67a2970e6831bc091d7b87e119e7f9791aef9702e3bef04448"
+
+[[package]]
+name = "yahweh-bus"
+version = "0.1.0"
+dependencies = [
+ "gpui",
+]
+
+[[package]]
+name = "yahweh-core"
+version = "0.1.0"
+dependencies = [
+ "async-trait",
+ "serde",
+ "serde_json",
+ "tokio",
+]
+
+[[package]]
+name = "yahweh-database-explorer"
+version = "0.1.0"
+dependencies = [
+ "gpui",
+ "yahweh-core",
+ "yahweh-provider-sqlite",
+ "yahweh-theme",
+ "yahweh-widget-tree",
+]
+
+[[package]]
+name = "yahweh-file-explorer"
+version = "0.1.0"
+dependencies = [
+ "gpui",
+ "yahweh-core",
+ "yahweh-provider-fs",
+ "yahweh-theme",
+ "yahweh-widget-text-input",
+ "yahweh-widget-tree",
+]
+
+[[package]]
+name = "yahweh-image-viewer"
+version = "0.1.0"
+dependencies = [
+ "gpui",
+ "yahweh-bus",
+ "yahweh-theme",
+]
+
+[[package]]
+name = "yahweh-provider-fs"
+version = "0.1.0"
+dependencies = [
+ "async-trait",
+ "notify",
+ "tokio",
+ "yahweh-core",
+]
+
+[[package]]
+name = "yahweh-provider-sqlite"
+version = "0.1.0"
+dependencies = [
+ "async-trait",
+ "rusqlite",
+ "tokio",
+ "yahweh-core",
+]
+
+[[package]]
+name = "yahweh-shell"
+version = "0.1.0"
+dependencies = [
+ "gpui",
+ "notify",
+ "serde",
+ "serde_json",
+ "tokio",
+ "yahweh-bus",
+ "yahweh-core",
+ "yahweh-database-explorer",
+ "yahweh-file-explorer",
+ "yahweh-image-viewer",
+ "yahweh-provider-fs",
+ "yahweh-provider-sqlite",
+ "yahweh-text-viewer",
+ "yahweh-theme",
+ "yahweh-widget-container-core",
+ "yahweh-widget-splitter",
+ "yahweh-widget-tabs",
+ "yahweh-widget-tiled",
+ "yahweh-widget-tree",
+]
+
+[[package]]
+name = "yahweh-text-viewer"
+version = "0.1.0"
+dependencies = [
+ "gpui",
+ "yahweh-bus",
+ "yahweh-core",
+ "yahweh-provider-fs",
+ "yahweh-provider-sqlite",
+ "yahweh-theme",
+]
+
+[[package]]
+name = "yahweh-theme"
+version = "0.1.0"
+dependencies = [
+ "gpui",
+]
+
+[[package]]
+name = "yahweh-widget-container-core"
+version = "0.1.0"
+dependencies = [
+ "gpui",
+ "yahweh-core",
+]
+
+[[package]]
+name = "yahweh-widget-splitter"
+version = "0.1.0"
+dependencies = [
+ "gpui",
+ "yahweh-core",
+ "yahweh-theme",
+ "yahweh-widget-container-core",
+]
+
+[[package]]
+name = "yahweh-widget-tabs"
+version = "0.1.0"
+dependencies = [
+ "gpui",
+ "yahweh-core",
+ "yahweh-theme",
+ "yahweh-widget-container-core",
+]
+
+[[package]]
+name = "yahweh-widget-text-input"
+version = "0.1.0"
+dependencies = [
+ "gpui",
+ "yahweh-theme",
+]
+
+[[package]]
+name = "yahweh-widget-tiled"
+version = "0.1.0"
+dependencies = [
+ "gpui",
+ "yahweh-core",
+ "yahweh-theme",
+ "yahweh-widget-container-core",
+]
+
+[[package]]
+name = "yahweh-widget-tree"
+version = "0.1.0"
+dependencies = [
+ "gpui",
+ "yahweh-theme",
+]
+
+[[package]]
+name = "yamux"
+version = "0.12.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9ed0164ae619f2dc144909a9f082187ebb5893693d8c0196e8085283ccd4b776"
+dependencies = [
+ "futures",
+ "log",
+ "nohash-hasher",
+ "parking_lot 0.12.5",
+ "pin-project",
+ "rand 0.8.6",
+ "static_assertions",
+]
+
+[[package]]
+name = "yamux"
+version = "0.13.10"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1991f6690292030e31b0144d73f5e8368936c58e45e7068254f7138b23b00672"
+dependencies = [
+ "futures",
+ "log",
+ "nohash-hasher",
+ "parking_lot 0.12.5",
+ "pin-project",
+ "rand 0.9.4",
+ "static_assertions",
+ "web-time",
+]
+
+[[package]]
+name = "yasna"
+version = "0.5.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e17bb3549cc1321ae1296b9cdc2698e2b6cb1992adfa19a8c72e5b7a738f44cd"
+dependencies = [
+ "time",
+]
+
+[[package]]
+name = "yazi"
+version = "0.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e01738255b5a16e78bbb83e7fbba0a1e7dd506905cfc53f4622d89015a03fbb5"
+
+[[package]]
+name = "yeslogic-fontconfig-sys"
+version = "6.0.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1d8b8abf912b9a29ff112e1671c97c33636903d13a69712037190e6805af4f76"
+dependencies = [
+ "dlib",
+ "once_cell",
+ "pkg-config",
+]
+
+[[package]]
+name = "yoke"
+version = "0.8.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "abe8c5fda708d9ca3df187cae8bfb9ceda00dd96231bed36e445a1a48e66f9ca"
+dependencies = [
+ "stable_deref_trait",
+ "yoke-derive",
+ "zerofrom",
+]
+
+[[package]]
+name = "yoke-derive"
+version = "0.8.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "de844c262c8848816172cef550288e7dc6c7b7814b4ee56b3e1553f275f1858e"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.117",
+ "synstructure",
+]
+
+[[package]]
+name = "zbus"
+version = "4.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bb97012beadd29e654708a0fdb4c84bc046f537aecfde2c3ee0a9e4b4d48c725"
+dependencies = [
+ "async-broadcast",
+ "async-process",
+ "async-recursion",
+ "async-trait",
+ "enumflags2",
+ "event-listener 5.4.1",
+ "futures-core",
+ "futures-sink",
+ "futures-util",
+ "hex",
+ "nix 0.29.0",
+ "ordered-stream",
+ "rand 0.8.6",
+ "serde",
+ "serde_repr",
+ "sha1",
+ "static_assertions",
+ "tokio",
+ "tracing",
+ "uds_windows",
+ "windows-sys 0.52.0",
+ "xdg-home",
+ "zbus_macros 4.4.0",
+ "zbus_names 3.0.0",
+ "zvariant 4.2.0",
+]
+
+[[package]]
+name = "zbus"
+version = "5.15.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c3bcbf15c8708d7fc1be0c993622e0a5cbd5e8b52bfa40afa4c3e0cd8d724ac1"
+dependencies = [
+ "async-broadcast",
+ "async-executor",
+ "async-io",
+ "async-lock",
+ "async-process",
+ "async-recursion",
+ "async-task",
+ "async-trait",
+ "blocking",
+ "enumflags2",
+ "event-listener 5.4.1",
+ "futures-core",
+ "futures-lite 2.6.1",
+ "hex",
+ "libc",
+ "ordered-stream",
+ "rustix 1.1.4",
+ "serde",
+ "serde_repr",
+ "tracing",
+ "uds_windows",
+ "uuid",
+ "windows-sys 0.61.2",
+ "winnow 1.0.2",
+ "zbus_macros 5.15.0",
+ "zbus_names 4.3.2",
+ "zvariant 5.11.0",
+]
+
+[[package]]
+name = "zbus_macros"
+version = "4.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "267db9407081e90bbfa46d841d3cbc60f59c0351838c4bc65199ecd79ab1983e"
+dependencies = [
+ "proc-macro-crate",
+ "proc-macro2",
+ "quote",
+ "syn 2.0.117",
+ "zvariant_utils 2.1.0",
+]
+
+[[package]]
+name = "zbus_macros"
+version = "5.15.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "51fa5406ad9175a8c825a931f8cf347116b531b3634fcb0b627c290f1f2516ff"
+dependencies = [
+ "proc-macro-crate",
+ "proc-macro2",
+ "quote",
+ "syn 2.0.117",
+ "zbus_names 4.3.2",
+ "zvariant 5.11.0",
+ "zvariant_utils 3.3.1",
+]
+
+[[package]]
+name = "zbus_names"
+version = "3.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4b9b1fef7d021261cc16cba64c351d291b715febe0fa10dc3a443ac5a5022e6c"
+dependencies = [
+ "serde",
+ "static_assertions",
+ "zvariant 4.2.0",
+]
+
+[[package]]
+name = "zbus_names"
+version = "4.3.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7074f3e50b894eac91750142016d30d0a89be8e67dbfd9704fb875825760e52d"
+dependencies = [
+ "serde",
+ "winnow 1.0.2",
+ "zvariant 5.11.0",
+]
+
+[[package]]
+name = "zed-async-tar"
+version = "0.5.0-zed"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6cf4b5f655e29700e473cb1acd914ab112b37b62f96f7e642d5fc6a0c02eb881"
+dependencies = [
+ "async-std",
+ "filetime",
+ "libc",
+ "pin-project",
+ "redox_syscall 0.2.16",
+ "xattr",
+]
+
+[[package]]
+name = "zed-font-kit"
+version = "0.14.1-zed"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a3898e450f36f852edda72e3f985c34426042c4951790b23b107f93394f9bff5"
+dependencies = [
+ "bitflags 2.11.1",
+ "byteorder",
+ "core-foundation 0.10.0",
+ "core-graphics 0.24.0",
+ "core-text",
+ "dirs 5.0.1",
+ "dwrote",
+ "float-ord",
+ "freetype-sys",
+ "lazy_static",
+ "libc",
+ "log",
+ "pathfinder_geometry",
+ "pathfinder_simd",
+ "walkdir",
+ "winapi",
+ "yeslogic-fontconfig-sys",
+]
+
+[[package]]
+name = "zed-reqwest"
+version = "0.12.15-zed"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ac2d05756ff48539950c3282ad7acf3817ad3f08797c205ad1c34a2ce03b9970"
+dependencies = [
+ "base64",
+ "bytes",
+ "encoding_rs",
+ "futures-core",
+ "futures-util",
+ "h2",
+ "http",
+ "http-body",
+ "http-body-util",
+ "hyper",
+ "hyper-rustls",
+ "hyper-util",
+ "ipnet",
+ "js-sys",
+ "log",
+ "mime",
+ "mime_guess",
+ "once_cell",
+ "percent-encoding",
+ "pin-project-lite",
+ "quinn",
+ "rustls",
+ "rustls-native-certs",
+ "rustls-pemfile",
+ "rustls-pki-types",
+ "serde",
+ "serde_json",
+ "serde_urlencoded",
+ "sync_wrapper",
+ "system-configuration 0.6.1",
+ "tokio",
+ "tokio-rustls",
+ "tokio-socks",
+ "tokio-util",
+ "tower",
+ "tower-service",
+ "url",
+ "wasm-bindgen",
+ "wasm-bindgen-futures",
+ "wasm-streams",
+ "web-sys",
+ "windows-registry 0.4.0",
+]
+
+[[package]]
+name = "zed-scap"
+version = "0.0.8-zed"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b6b338d705ae33a43ca00287c11129303a7a0aa57b101b72a1c08c863f698ac8"
+dependencies = [
+ "anyhow",
+ "cocoa 0.25.0",
+ "core-graphics-helmer-fork",
+ "log",
+ "objc",
+ "rand 0.8.6",
+ "screencapturekit",
+ "screencapturekit-sys",
+ "sysinfo",
+ "tao-core-video-sys",
+ "windows 0.61.3",
+ "windows-capture",
+ "x11",
+ "xcb",
+]
+
+[[package]]
+name = "zed-xim"
+version = "0.4.0-zed"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0c0b46ed118eba34d9ba53d94ddc0b665e0e06a2cf874cfa2dd5dec278148642"
+dependencies = [
+ "ahash",
+ "hashbrown 0.14.5",
+ "log",
+ "x11rb",
+ "xim-ctext",
+ "xim-parser",
+]
+
+[[package]]
+name = "zeno"
+version = "0.3.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6df3dc4292935e51816d896edcd52aa30bc297907c26167fec31e2b0c6a32524"
+
+[[package]]
+name = "zerocopy"
+version = "0.8.48"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "eed437bf9d6692032087e337407a86f04cd8d6a16a37199ed57949d415bd68e9"
+dependencies = [
+ "zerocopy-derive",
+]
+
+[[package]]
+name = "zerocopy-derive"
+version = "0.8.48"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "70e3cd084b1788766f53af483dd21f93881ff30d7320490ec3ef7526d203bad4"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.117",
+]
+
+[[package]]
+name = "zerofrom"
+version = "0.1.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "69faa1f2a1ea75661980b013019ed6687ed0e83d069bc1114e2cc74c6c04c4df"
+dependencies = [
+ "zerofrom-derive",
+]
+
+[[package]]
+name = "zerofrom-derive"
+version = "0.1.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "11532158c46691caf0f2593ea8358fed6bbf68a0315e80aae9bd41fbade684a1"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.117",
+ "synstructure",
+]
+
+[[package]]
+name = "zeroize"
+version = "1.8.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b97154e67e32c85465826e8bcc1c59429aaaf107c1e4a9e53c8d8ccd5eff88d0"
+dependencies = [
+ "zeroize_derive",
+]
+
+[[package]]
+name = "zeroize_derive"
+version = "1.4.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "85a5b4158499876c763cb03bc4e49185d3cccbabb15b33c627f7884f43db852e"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.117",
+]
+
+[[package]]
+name = "zerotrie"
+version = "0.2.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0f9152d31db0792fa83f70fb2f83148effb5c1f5b8c7686c3459e361d9bc20bf"
+dependencies = [
+ "displaydoc",
+ "yoke",
+ "zerofrom",
+]
+
+[[package]]
+name = "zerovec"
+version = "0.11.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "90f911cbc359ab6af17377d242225f4d75119aec87ea711a880987b18cd7b239"
+dependencies = [
+ "yoke",
+ "zerofrom",
+ "zerovec-derive",
+]
+
+[[package]]
+name = "zerovec-derive"
+version = "0.11.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "625dc425cab0dca6dc3c3319506e6593dcb08a9f387ea3b284dbd52a92c40555"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.117",
+]
+
+[[package]]
+name = "zmij"
+version = "1.0.21"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b8848ee67ecc8aedbaf3e4122217aff892639231befc6a1b58d29fff4c2cabaa"
+
+[[package]]
+name = "zune-core"
+version = "0.5.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "cb8a0807f7c01457d0379ba880ba6322660448ddebc890ce29bb64da71fb40f9"
+
+[[package]]
+name = "zune-inflate"
+version = "0.2.54"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "73ab332fe2f6680068f3582b16a24f90ad7096d5d39b974d1c0aff0125116f02"
+dependencies = [
+ "simd-adler32",
+]
+
+[[package]]
+name = "zune-jpeg"
+version = "0.5.15"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "27bc9d5b815bc103f142aa054f561d9187d191692ec7c2d1e2b4737f8dbd7296"
+dependencies = [
+ "zune-core",
+]
+
+[[package]]
+name = "zvariant"
+version = "4.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2084290ab9a1c471c38fc524945837734fbf124487e105daec2bb57fd48c81fe"
+dependencies = [
+ "endi",
+ "enumflags2",
+ "serde",
+ "static_assertions",
+ "zvariant_derive 4.2.0",
+]
+
+[[package]]
+name = "zvariant"
+version = "5.11.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1c1567a6ec68df868cbbfde844cfc6d81649fe5109a62b116b19fabd53e618ee"
+dependencies = [
+ "endi",
+ "enumflags2",
+ "serde",
+ "url",
+ "winnow 1.0.2",
+ "zvariant_derive 5.11.0",
+ "zvariant_utils 3.3.1",
+]
+
+[[package]]
+name = "zvariant_derive"
+version = "4.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "73e2ba546bda683a90652bac4a279bc146adad1386f25379cf73200d2002c449"
+dependencies = [
+ "proc-macro-crate",
+ "proc-macro2",
+ "quote",
+ "syn 2.0.117",
+ "zvariant_utils 2.1.0",
+]
+
+[[package]]
+name = "zvariant_derive"
+version = "5.11.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c7d5b780599bbde114e39d9a0799577fad1ced5105d38515745f7b3099d8ceda"
+dependencies = [
+ "proc-macro-crate",
+ "proc-macro2",
+ "quote",
+ "syn 2.0.117",
+ "zvariant_utils 3.3.1",
+]
+
+[[package]]
+name = "zvariant_utils"
+version = "2.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c51bcff7cc3dbb5055396bcf774748c3dab426b4b8659046963523cee4808340"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.117",
+]
+
+[[package]]
+name = "zvariant_utils"
+version = "3.3.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6d464f5733ffa07a3164d656f18533caace9d0638596721355d73256a410d691"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "serde",
+ "syn 2.0.117",
+ "winnow 1.0.2",
+]
diff --git a/Cargo.toml b/Cargo.toml
new file mode 100644
index 0000000..a8ca317
--- /dev/null
+++ b/Cargo.toml
@@ -0,0 +1,175 @@
+[workspace]
+resolver = "2"
+members = [
+ # ============================================================
+ # core/ — Init y compat (arje absorbido)
+ # ============================================================
+ "crates/core/ente-card",
+ "crates/core/ente-bus",
+ "crates/core/ente-cas",
+ "crates/core/ente-kernel",
+ "crates/core/ente-soma",
+ "crates/core/ente-wasm",
+ "crates/core/ente-snapshot",
+ "crates/core/ente-brain",
+ "crates/core/ente-zero",
+ "crates/core/ente-echo",
+ "crates/core/ente-policy-provider",
+ "crates/core/ente-logind-compat",
+ "crates/core/ente-hostnamed-compat",
+ "crates/core/ente-timedated-compat",
+ "crates/core/ente-localed-compat",
+ "crates/core/ente-journald-compat",
+ "crates/core/ente-resolved-compat",
+ "crates/core/ente-polkit-compat",
+ "crates/core/ente-machined-compat",
+ "crates/core/ente-tmpfiles-compat",
+ "crates/core/ente-systemd1-compat",
+ "crates/core/ente-notify-compat",
+ "crates/core/ente-binfmt-compat",
+ "crates/core/ente-timer-compat",
+
+ # ============================================================
+ # modules/semantic_dht/ — DHT semántico (minga absorbido)
+ # ============================================================
+ "crates/modules/semantic_dht/minga-core",
+ "crates/modules/semantic_dht/minga-store",
+ "crates/modules/semantic_dht/minga-p2p",
+ "crates/modules/semantic_dht/minga-vfs",
+ "crates/modules/semantic_dht/minga-cli",
+
+ # ============================================================
+ # modules/ui_engine/ — Motor de widgets (yahweh libs+widgets)
+ # ============================================================
+ "crates/modules/ui_engine/libs/core",
+ "crates/modules/ui_engine/libs/theme",
+ "crates/modules/ui_engine/libs/bus",
+ "crates/modules/ui_engine/libs/providers/fs",
+ "crates/modules/ui_engine/libs/providers/sqlite",
+ "crates/modules/ui_engine/widgets/tree",
+ "crates/modules/ui_engine/widgets/container_core",
+ "crates/modules/ui_engine/widgets/splitter",
+ "crates/modules/ui_engine/widgets/tabs",
+ "crates/modules/ui_engine/widgets/tiled",
+ "crates/modules/ui_engine/widgets/text_input",
+
+ # ============================================================
+ # apps/ — apps que consumen el protocolo (yahweh modules+shell)
+ # ============================================================
+ "crates/apps/file_explorer",
+ "crates/apps/database_explorer",
+ "crates/apps/text_viewer",
+ "crates/apps/image_viewer",
+ "crates/apps/yahweh-shell",
+]
+
+[workspace.package]
+version = "0.1.0"
+edition = "2021"
+rust-version = "1.80"
+license = "MIT OR Apache-2.0"
+authors = ["Brahman Contributors"]
+publish = false
+repository = "https://example.invalid/brahman"
+
+[workspace.dependencies]
+# === Serialización ===
+serde = { version = "1", features = ["derive"] }
+serde_json = "1"
+serde-big-array = "0.5"
+postcard = { version = "1", features = ["use-std"] }
+toml = "0.8"
+bincode = "1"
+base64 = "0.22"
+
+# === Errores ===
+thiserror = "2" # bump uniforme; arje (era 1) puede requerir ajustes menores
+anyhow = "1"
+
+# === Async ===
+tokio = { version = "1", features = ["full"] }
+tokio-util = { version = "0.7", features = ["compat"] }
+async-trait = "0.1"
+futures = "0.3"
+
+# === Observabilidad ===
+tracing = "0.1"
+tracing-subscriber = { version = "0.3", features = ["env-filter", "fmt"] }
+
+# === Linux primitives (arje) ===
+nix = { version = "0.29", features = ["signal", "process", "sched", "mount", "fs", "socket", "net", "user"] }
+libc = "0.2"
+
+# === IDs / Hash / Crypto ===
+ulid = { version = "1", features = ["serde"] }
+uuid = { version = "1", features = ["v4"] }
+sha2 = "0.10"
+blake3 = "1.5"
+ed25519-dalek = "2"
+aes-gcm = "0.10"
+argon2 = "0.5"
+rand = "0.8"
+
+# === WASM (arje) ===
+wasmi = "0.40"
+wat = "1"
+
+# === Storage / DB ===
+sled = "0.34"
+rusqlite = { version = "0.31", features = ["bundled", "blob"] }
+
+# === P2P (minga) ===
+libp2p = { version = "0.56", features = ["tokio", "tcp", "noise", "yamux", "macros", "kad", "identify"] }
+libp2p-stream = "=0.4.0-alpha"
+
+# === Code parsing (minga) ===
+tree-sitter = "0.24"
+tree-sitter-rust = "0.23"
+
+# === FS notify ===
+notify = "6.1"
+
+# === CLI / auth (minga) ===
+clap = { version = "4", features = ["derive"] }
+rpassword = "7"
+
+# === D-Bus (arje compat) ===
+zbus = { version = "4", default-features = false, features = ["tokio"] }
+
+# === Tests ===
+tempfile = "3"
+
+# === GPUI (yahweh) ===
+gpui = "0.2"
+
+# === Filesystem helpers ===
+directories = "5"
+
+# ============================================================
+# Intra-workspace deps de yahweh (referenciadas por workspace = true)
+# ============================================================
+yahweh-core = { path = "crates/modules/ui_engine/libs/core" }
+yahweh-theme = { path = "crates/modules/ui_engine/libs/theme" }
+yahweh-bus = { path = "crates/modules/ui_engine/libs/bus" }
+yahweh-provider-fs = { path = "crates/modules/ui_engine/libs/providers/fs" }
+yahweh-provider-sqlite = { path = "crates/modules/ui_engine/libs/providers/sqlite" }
+yahweh-widget-tree = { path = "crates/modules/ui_engine/widgets/tree" }
+yahweh-widget-container-core = { path = "crates/modules/ui_engine/widgets/container_core" }
+yahweh-widget-splitter = { path = "crates/modules/ui_engine/widgets/splitter" }
+yahweh-widget-tabs = { path = "crates/modules/ui_engine/widgets/tabs" }
+yahweh-widget-tiled = { path = "crates/modules/ui_engine/widgets/tiled" }
+yahweh-widget-text-input = { path = "crates/modules/ui_engine/widgets/text_input" }
+yahweh-file-explorer = { path = "crates/apps/file_explorer" }
+yahweh-database-explorer = { path = "crates/apps/database_explorer" }
+yahweh-text-viewer = { path = "crates/apps/text_viewer" }
+yahweh-image-viewer = { path = "crates/apps/image_viewer" }
+
+[profile.release]
+lto = "thin"
+codegen-units = 1
+strip = "symbols"
+panic = "abort"
+
+[profile.dev]
+opt-level = 0
+debug = true
diff --git a/crates/apps/database_explorer/Cargo.toml b/crates/apps/database_explorer/Cargo.toml
new file mode 100644
index 0000000..08bd932
--- /dev/null
+++ b/crates/apps/database_explorer/Cargo.toml
@@ -0,0 +1,13 @@
+[package]
+name = "yahweh-database-explorer"
+version = { workspace = true }
+edition = { workspace = true }
+license = { workspace = true }
+description = "Explorer de SQLite — composición TreeView + SqliteProvider con lazy load."
+
+[dependencies]
+gpui = { workspace = true }
+yahweh-core = { workspace = true }
+yahweh-theme = { workspace = true }
+yahweh-widget-tree = { workspace = true }
+yahweh-provider-sqlite = { workspace = true }
diff --git a/crates/apps/database_explorer/src/lib.rs b/crates/apps/database_explorer/src/lib.rs
new file mode 100644
index 0000000..49782da
--- /dev/null
+++ b/crates/apps/database_explorer/src/lib.rs
@@ -0,0 +1,284 @@
+//! `yahweh_database_explorer` — explorer de SQLite.
+//!
+//! Mismo patrón que `yahweh_file_explorer` pero con `SqliteProvider`. La
+//! UX es idéntica (TreeView con lazy load por chevron); cambia solo el
+//! origen de los datos: filas de una tabla `items(id, parent_id, name,
+//! display_type, content)` en lugar del filesystem.
+
+use std::collections::{HashMap, HashSet};
+use std::sync::Arc;
+
+use gpui::{
+ Context, Entity, EventEmitter, IntoElement, Render, SharedString, Window, div, prelude::*,
+ px,
+};
+
+use yahweh_core::{DataProvider, DisplayType, EntityNode};
+use yahweh_provider_sqlite::SqliteDataProvider;
+use yahweh_theme::Theme;
+use yahweh_widget_tree::{RowId, RowKind, TreeEvent, TreeRow, TreeView};
+
+#[derive(Clone, Debug)]
+#[allow(dead_code)] // Consumido por el AppBus en Fase 4+.
+pub enum DatabaseExplorerEvent {
+ EntitySelected { id: String },
+ EntityOpened { id: String },
+}
+
+pub struct DatabaseExplorer {
+ tree_view: Entity<TreeView>,
+ provider: Arc<SqliteDataProvider>,
+ db_path: String,
+
+ expanded: HashSet<String>,
+ children: HashMap<String, Vec<EntityNode>>,
+ pending: HashSet<String>,
+ /// Mensaje de error si la DB no abrió. Se muestra en el header.
+ open_error: Option<String>,
+}
+
+const ROOT_KEY: &str = "__db_root__";
+
+impl EventEmitter<DatabaseExplorerEvent> for DatabaseExplorer {}
+
+impl DatabaseExplorer {
+ /// `db_path` es la ruta al .sqlite. Si no existe se crea con la tabla
+ /// `items` y un seed mínimo (ver `SqliteDataProvider::new`).
+ pub fn new(db_path: String, cx: &mut Context<Self>) -> Self {
+ cx.observe_global::<Theme>(|_, cx| cx.notify()).detach();
+
+ let tree_view = cx.new(|cx| TreeView::new("db-explorer-tree", cx));
+ cx.subscribe(&tree_view, |this: &mut DatabaseExplorer, _, ev, cx| {
+ this.on_tree_event(ev, cx);
+ })
+ .detach();
+
+ let (provider, open_error) = match SqliteDataProvider::new(&db_path) {
+ Ok(p) => (Some(Arc::new(p)), None),
+ Err(e) => (None, Some(e)),
+ };
+
+ let mut expanded = HashSet::new();
+ expanded.insert(ROOT_KEY.to_string());
+
+ let mut me = Self {
+ tree_view,
+ // Usamos un dummy provider si la DB no abrió. La UI mostrará el
+ // error en el header; cualquier load_children retornará vacío.
+ provider: provider.unwrap_or_else(|| {
+ Arc::new(SqliteDataProvider::new(":memory:").expect("memory db"))
+ }),
+ db_path,
+ expanded,
+ children: HashMap::new(),
+ pending: HashSet::new(),
+ open_error,
+ };
+ // Cargar el root (parent_id NULL en SQLite, mapped to None acá).
+ me.load_children(ROOT_KEY.to_string(), cx);
+ me
+ }
+
+ pub fn db_path(&self) -> &str {
+ &self.db_path
+ }
+
+ fn load_children(&mut self, parent_key: String, cx: &mut Context<Self>) {
+ if self.pending.contains(&parent_key) || self.children.contains_key(&parent_key) {
+ return;
+ }
+ self.pending.insert(parent_key.clone());
+
+ let provider = self.provider.clone();
+ let parent_for_task = parent_key.clone();
+ cx.spawn(async move |this, cx| {
+ // ROOT_KEY → None; cualquier otro → Some(actual id).
+ let arg: Option<String> = if parent_for_task == ROOT_KEY {
+ None
+ } else {
+ Some(parent_for_task.clone())
+ };
+ let result = provider.list_children(arg.as_deref()).await;
+ let _ = this.update(cx, |this, cx| {
+ this.on_children_loaded(parent_for_task, result, cx);
+ });
+ })
+ .detach();
+ }
+
+ fn on_children_loaded(
+ &mut self,
+ parent_key: String,
+ result: Result<Vec<EntityNode>, String>,
+ cx: &mut Context<Self>,
+ ) {
+ self.pending.remove(&parent_key);
+ let mut entries = result.unwrap_or_default();
+ sort_entries(&mut entries);
+ self.children.insert(parent_key, entries);
+ self.push_rows(cx);
+ }
+
+ fn push_rows(&self, cx: &mut Context<Self>) {
+ let mut rows = Vec::new();
+ // Una row "raíz virtual" para que el árbol tenga un anchor visible.
+ rows.push(TreeRow {
+ id: RowId::new(ROOT_KEY),
+ label: format!("(db) {}", self.db_path),
+ depth: 0,
+ kind: RowKind::Branch,
+ expanded: self.expanded.contains(ROOT_KEY),
+ icon: Some("🗄️".to_string()),
+ });
+ if self.expanded.contains(ROOT_KEY) {
+ self.append_children(ROOT_KEY, 1, &mut rows);
+ }
+
+ self.tree_view
+ .update(&mut *cx, |tree, cx| tree.set_rows(rows, cx));
+ }
+
+ fn append_children(&self, parent: &str, depth: u32, out: &mut Vec<TreeRow>) {
+ let Some(children) = self.children.get(parent) else { return };
+ for entry in children {
+ let kind = match entry.display_type {
+ DisplayType::Folder => RowKind::Branch,
+ _ => RowKind::Leaf,
+ };
+ let icon = match entry.display_type {
+ DisplayType::Folder => "📂",
+ DisplayType::File => "📄",
+ DisplayType::Stream => "📡",
+ };
+ let is_expanded = self.expanded.contains(&entry.id);
+ out.push(TreeRow {
+ id: RowId::new(entry.id.clone()),
+ label: entry.name.clone(),
+ depth,
+ kind,
+ expanded: is_expanded,
+ icon: Some(icon.to_string()),
+ });
+ if is_expanded {
+ self.append_children(&entry.id, depth + 1, out);
+ }
+ }
+ }
+
+ fn on_tree_event(&mut self, event: &TreeEvent, cx: &mut Context<Self>) {
+ match event {
+ TreeEvent::ChevronToggled(id) => {
+ let key = id.as_str().to_string();
+ if !self.expanded.remove(&key) {
+ self.expanded.insert(key.clone());
+ self.load_children(key, cx);
+ }
+ self.push_rows(cx);
+ }
+ TreeEvent::RowClicked(id) => {
+ let key = id.as_str();
+ if key == ROOT_KEY {
+ return;
+ }
+ if let Some(entry) = self.find_entry(key) {
+ if !matches!(entry.display_type, DisplayType::Folder) {
+ cx.emit(DatabaseExplorerEvent::EntitySelected {
+ id: key.to_string(),
+ });
+ }
+ }
+ }
+ TreeEvent::RowDoubleClicked(id) => {
+ let key = id.as_str();
+ if key == ROOT_KEY {
+ return;
+ }
+ if let Some(entry) = self.find_entry(key) {
+ if !matches!(entry.display_type, DisplayType::Folder) {
+ cx.emit(DatabaseExplorerEvent::EntityOpened {
+ id: key.to_string(),
+ });
+ }
+ }
+ }
+ TreeEvent::ContextMenuRequested { .. } | TreeEvent::ActiveChanged(_) => {}
+ }
+ }
+
+ fn find_entry(&self, id: &str) -> Option<&EntityNode> {
+ for entries in self.children.values() {
+ if let Some(e) = entries.iter().find(|e| e.id == id) {
+ return Some(e);
+ }
+ }
+ None
+ }
+}
+
+impl Render for DatabaseExplorer {
+ fn render(&mut self, _w: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
+ let theme = Theme::global(cx).clone();
+ let pending_count = self.pending.len();
+
+ div()
+ .size_full()
+ .bg(theme.bg_panel.clone())
+ .flex()
+ .flex_col()
+ .child(
+ div()
+ .h(px(28.0))
+ .px(px(8.0))
+ .border_b_1()
+ .border_color(theme.border)
+ .flex()
+ .flex_row()
+ .items_center()
+ .gap(px(6.0))
+ .child(
+ div()
+ .text_size(px(11.0))
+ .text_color(theme.fg_muted)
+ .child("🗄️"),
+ )
+ .child(
+ div()
+ .text_size(px(11.0))
+ .text_color(theme.fg_text)
+ .child(SharedString::from(self.db_path.clone())),
+ )
+ .child(
+ div()
+ .ml_auto()
+ .text_size(px(10.0))
+ .text_color(theme.fg_muted)
+ .child(SharedString::from(if pending_count > 0 {
+ format!("⏳ {}", pending_count)
+ } else {
+ String::new()
+ })),
+ ),
+ )
+ .child(if let Some(err) = self.open_error.clone() {
+ // Si la DB no abrió, mostramos el error y no pintamos el
+ // árbol vacío — sería confuso.
+ div()
+ .p(px(12.0))
+ .text_size(px(11.0))
+ .text_color(theme.accent_strong)
+ .child(SharedString::from(format!("error abriendo DB: {}", err)))
+ } else {
+ div().flex_grow().min_h(px(0.0)).child(self.tree_view.clone())
+ })
+ }
+}
+
+fn sort_entries(entries: &mut Vec<EntityNode>) {
+ entries.sort_by(|a, b| {
+ let a_dir = matches!(a.display_type, DisplayType::Folder);
+ let b_dir = matches!(b.display_type, DisplayType::Folder);
+ b_dir
+ .cmp(&a_dir)
+ .then_with(|| a.name.to_lowercase().cmp(&b.name.to_lowercase()))
+ });
+}
diff --git a/crates/apps/file_explorer/Cargo.toml b/crates/apps/file_explorer/Cargo.toml
new file mode 100644
index 0000000..0835f69
--- /dev/null
+++ b/crates/apps/file_explorer/Cargo.toml
@@ -0,0 +1,14 @@
+[package]
+name = "yahweh-file-explorer"
+version = { workspace = true }
+edition = { workspace = true }
+license = { workspace = true }
+description = "Explorer de filesystem — composición TreeView + FsProvider con lazy load."
+
+[dependencies]
+gpui = { workspace = true }
+yahweh-core = { workspace = true }
+yahweh-theme = { workspace = true }
+yahweh-widget-tree = { workspace = true }
+yahweh-widget-text-input = { workspace = true }
+yahweh-provider-fs = { workspace = true }
diff --git a/crates/apps/file_explorer/src/lib.rs b/crates/apps/file_explorer/src/lib.rs
new file mode 100644
index 0000000..4b96cc3
--- /dev/null
+++ b/crates/apps/file_explorer/src/lib.rs
@@ -0,0 +1,786 @@
+//! `yahweh_file_explorer` — explorer de filesystem con menú contextual.
+//!
+//! Composición canónica del patrón "explorer = TreeView + provider":
+//!
+//! ```text
+//! FileExplorer
+//! ├── TreeView (widgets/tree, agnóstico)
+//! └── FsProvider (libs/providers/fs, async + tokio::io)
+//! ```
+//!
+//! Estado:
+//! - `expanded`: set de paths cuyo chevron está abierto.
+//! - `children`: cache de hijos por path parent (cargado lazy via
+//! `cx.spawn` + provider).
+//! - `pending`: set de loads en vuelo (anti re-trigger).
+//! - `menu`: estado del menú contextual flotante (Fase 4.5).
+//!
+//! Menú contextual (Fase 4.5):
+//! Right-click sobre una fila o el área vacía del árbol abre un menú con
+//! las acciones FS habituales. Las mutaciones se ejecutan sincrónicamente
+//! contra `std::fs` y luego se invalida el cache del directorio afectado
+//! para forzar reload del provider.
+//!
+//! Acciones soportadas:
+//! - **Open** (solo file): emite `FileExplorerEvent::FileOpened` (que el
+//! forwarder de la Shell traduce a `AppEvent::EntityOpened` al bus).
+//! - **Copy path**: copia el path absoluto al clipboard.
+//! - **New file**: crea un archivo vacío con nombre auto-generado
+//! (`new_file_NN.txt`) en el directorio elegido — sin necesitar text
+//! input por ahora; renombrar viene cuando sumemos un TextInput
+//! widget.
+//! - **New folder**: crea un directorio con nombre auto (`new_folder_NN`).
+//! - **Delete**: confirmación vía `window.prompt` (dialog del platform);
+//! si el usuario confirma, `remove_file` o `remove_dir_all` según
+//! corresponda.
+
+use std::collections::{HashMap, HashSet};
+use std::sync::Arc;
+
+use gpui::{
+ ClickEvent, ClipboardItem, Context, Entity, EventEmitter, IntoElement, Pixels, Point,
+ PromptLevel, Render, SharedString, Window, div, prelude::*, px,
+};
+
+use yahweh_core::{DataProvider, DisplayType, EntityNode};
+use yahweh_provider_fs::FileDataProvider;
+use yahweh_theme::Theme;
+use yahweh_widget_text_input::{TextInput, TextInputEvent};
+use yahweh_widget_tree::{RowId, RowKind, TreeEvent, TreeRow, TreeView};
+
+#[derive(Clone, Debug)]
+#[allow(dead_code)]
+pub enum FileExplorerEvent {
+ FileSelected { path: String },
+ FileOpened { path: String },
+ RootChanged { path: String },
+}
+
+#[derive(Clone, Debug)]
+struct MenuState {
+ /// `None` ⇒ menú "fondo" (área vacía del tree). `Some` ⇒ sobre una
+ /// fila concreta.
+ target: Option<MenuTarget>,
+ /// Posición absoluta donde se hizo el right-click. Para el overlay
+ /// usamos coords window-relative (gpui las maneja como px).
+ position: Point<Pixels>,
+}
+
+#[derive(Clone, Debug)]
+struct MenuTarget {
+ id: String,
+ is_folder: bool,
+}
+
+pub struct FileExplorer {
+ tree_view: Entity<TreeView>,
+ provider: Arc<FileDataProvider>,
+
+ root: String,
+ expanded: HashSet<String>,
+ children: HashMap<String, Vec<EntityNode>>,
+ pending: HashSet<String>,
+ menu: Option<MenuState>,
+ /// Modal de rename activo. `None` ⇒ no hay modal.
+ rename: Option<RenameState>,
+}
+
+/// Estado del modal de rename. El TextInput vive como sub-entity para
+/// que pueda recibir focus + key events. El target_path lo lleva la
+/// closure de subscripción (no lo necesitamos en `self` aparte).
+#[derive(Clone)]
+struct RenameState {
+ original_name: String,
+ input: Entity<TextInput>,
+}
+
+impl EventEmitter<FileExplorerEvent> for FileExplorer {}
+
+impl FileExplorer {
+ pub fn new(root: String, cx: &mut Context<Self>) -> Self {
+ cx.observe_global::<Theme>(|_, cx| cx.notify()).detach();
+
+ let tree_view = cx.new(|cx| TreeView::new("file-explorer-tree", cx));
+ cx.subscribe(&tree_view, |this: &mut FileExplorer, _, ev, cx| {
+ this.on_tree_event(ev, cx);
+ })
+ .detach();
+
+ let mut expanded = HashSet::new();
+ expanded.insert(root.clone());
+
+ let mut me = Self {
+ tree_view,
+ provider: Arc::new(FileDataProvider),
+ root: root.clone(),
+ expanded,
+ children: HashMap::new(),
+ pending: HashSet::new(),
+ menu: None,
+ rename: None,
+ };
+ me.load_children(root, cx);
+ me
+ }
+
+ pub fn root(&self) -> &str {
+ &self.root
+ }
+
+ #[allow(dead_code)]
+ pub fn set_root(&mut self, path: String, cx: &mut Context<Self>) {
+ if path != self.root {
+ self.root = path.clone();
+ self.expanded.insert(path.clone());
+ self.load_children(path.clone(), cx);
+ self.push_rows(cx);
+ cx.emit(FileExplorerEvent::RootChanged { path });
+ }
+ }
+
+ // ----- load + cache -----
+
+ fn load_children(&mut self, parent: String, cx: &mut Context<Self>) {
+ if self.pending.contains(&parent) || self.children.contains_key(&parent) {
+ return;
+ }
+ self.pending.insert(parent.clone());
+
+ let provider = self.provider.clone();
+ let parent_for_task = parent.clone();
+ cx.spawn(async move |this, cx| {
+ let result = provider.list_children(Some(&parent_for_task)).await;
+ let _ = this.update(cx, |this, cx| {
+ this.on_children_loaded(parent_for_task, result, cx);
+ });
+ })
+ .detach();
+ }
+
+ /// Versión "force": invalida el cache antes de re-pedir. Se usa tras
+ /// una mutación FS (new/delete) para que la UI refleje el cambio.
+ fn refresh_dir(&mut self, parent: String, cx: &mut Context<Self>) {
+ self.children.remove(&parent);
+ self.pending.remove(&parent);
+ self.load_children(parent, cx);
+ }
+
+ fn on_children_loaded(
+ &mut self,
+ parent: String,
+ result: Result<Vec<EntityNode>, String>,
+ cx: &mut Context<Self>,
+ ) {
+ self.pending.remove(&parent);
+ match result {
+ Ok(mut children) => {
+ sort_entries(&mut children);
+ self.children.insert(parent, children);
+ self.push_rows(cx);
+ }
+ Err(_) => {
+ self.children.insert(parent, Vec::new());
+ self.push_rows(cx);
+ }
+ }
+ }
+
+ fn push_rows(&self, cx: &mut Context<Self>) {
+ let mut rows = Vec::new();
+ rows.push(TreeRow {
+ id: RowId::new(self.root.clone()),
+ label: self.root.clone(),
+ depth: 0,
+ kind: RowKind::Branch,
+ expanded: self.expanded.contains(&self.root),
+ icon: Some("📂".to_string()),
+ });
+ if self.expanded.contains(&self.root) {
+ self.append_children(&self.root, 1, &mut rows);
+ }
+
+ self.tree_view
+ .update(cx, |tree, cx| tree.set_rows(rows, cx));
+ }
+
+ fn append_children(&self, parent: &str, depth: u32, out: &mut Vec<TreeRow>) {
+ let Some(children) = self.children.get(parent) else { return };
+ for entry in children {
+ let kind = match entry.display_type {
+ DisplayType::Folder => RowKind::Branch,
+ _ => RowKind::Leaf,
+ };
+ let icon = match entry.display_type {
+ DisplayType::Folder => "📁",
+ DisplayType::File => "📄",
+ DisplayType::Stream => "📡",
+ };
+ let is_expanded = self.expanded.contains(&entry.id);
+ out.push(TreeRow {
+ id: RowId::new(entry.id.clone()),
+ label: entry.name.clone(),
+ depth,
+ kind,
+ expanded: is_expanded,
+ icon: Some(icon.to_string()),
+ });
+ if is_expanded {
+ self.append_children(&entry.id, depth + 1, out);
+ }
+ }
+ }
+
+ // ----- TreeView events -----
+
+ fn on_tree_event(&mut self, event: &TreeEvent, cx: &mut Context<Self>) {
+ match event {
+ TreeEvent::ChevronToggled(id) => {
+ let path = id.as_str().to_string();
+ if !self.expanded.remove(&path) {
+ self.expanded.insert(path.clone());
+ self.load_children(path, cx);
+ }
+ self.push_rows(cx);
+ }
+ TreeEvent::RowClicked(id) => {
+ let path = id.as_str();
+ if let Some(entry) = self.find_entry(path) {
+ if !matches!(entry.display_type, DisplayType::Folder) {
+ cx.emit(FileExplorerEvent::FileSelected {
+ path: path.to_string(),
+ });
+ }
+ }
+ // Click primario en cualquier lado también cierra el
+ // menú contextual si estaba abierto.
+ if self.menu.is_some() {
+ self.menu = None;
+ cx.notify();
+ }
+ }
+ TreeEvent::RowDoubleClicked(id) => {
+ let path = id.as_str();
+ if let Some(entry) = self.find_entry(path) {
+ if !matches!(entry.display_type, DisplayType::Folder) {
+ cx.emit(FileExplorerEvent::FileOpened {
+ path: path.to_string(),
+ });
+ }
+ }
+ }
+ TreeEvent::ContextMenuRequested { id, position } => {
+ self.open_menu(id.as_ref().map(|i| i.as_str().to_string()), *position, cx);
+ }
+ TreeEvent::ActiveChanged(_) => {}
+ }
+ }
+
+ fn find_entry(&self, id: &str) -> Option<&EntityNode> {
+ for entries in self.children.values() {
+ if let Some(e) = entries.iter().find(|e| e.id == id) {
+ return Some(e);
+ }
+ }
+ None
+ }
+
+ fn is_folder_path(&self, id: &str) -> bool {
+ self.find_entry(id)
+ .map(|e| matches!(e.display_type, DisplayType::Folder))
+ .unwrap_or_else(|| std::path::Path::new(id).is_dir())
+ }
+
+ /// Resuelve el directorio donde crear un nuevo archivo/carpeta según
+ /// el target del menú: si target es folder → adentro; si target es
+ /// file → su parent; si target es None (fondo) → root.
+ fn parent_for_new(&self, target: &Option<MenuTarget>) -> String {
+ match target {
+ None => self.root.clone(),
+ Some(t) if t.is_folder => t.id.clone(),
+ Some(t) => std::path::Path::new(&t.id)
+ .parent()
+ .map(|p| p.to_string_lossy().into_owned())
+ .unwrap_or_else(|| self.root.clone()),
+ }
+ }
+
+ // ----- menú: open/close -----
+
+ fn open_menu(
+ &mut self,
+ id: Option<String>,
+ position: Point<Pixels>,
+ cx: &mut Context<Self>,
+ ) {
+ let target = id.map(|id| {
+ let is_folder = self.is_folder_path(&id);
+ MenuTarget { id, is_folder }
+ });
+ self.menu = Some(MenuState { target, position });
+ cx.notify();
+ }
+
+ fn close_menu(&mut self, cx: &mut Context<Self>) {
+ if self.menu.take().is_some() {
+ cx.notify();
+ }
+ }
+
+ // ----- acciones del menú -----
+
+ fn action_open(&mut self, target: MenuTarget, cx: &mut Context<Self>) {
+ if !target.is_folder {
+ cx.emit(FileExplorerEvent::FileOpened { path: target.id });
+ }
+ self.close_menu(cx);
+ }
+
+ fn action_copy_path(
+ &mut self,
+ target: MenuTarget,
+ _w: &mut Window,
+ cx: &mut Context<Self>,
+ ) {
+ cx.write_to_clipboard(ClipboardItem::new_string(target.id));
+ self.close_menu(cx);
+ }
+
+ fn action_new_file(
+ &mut self,
+ target: Option<MenuTarget>,
+ cx: &mut Context<Self>,
+ ) {
+ let parent = self.parent_for_new(&target);
+ if let Some(name) = next_available_name(&parent, "new_file_", ".txt", false) {
+ let full = std::path::Path::new(&parent).join(&name);
+ if let Err(e) = std::fs::OpenOptions::new()
+ .write(true)
+ .create_new(true)
+ .open(&full)
+ {
+ eprintln!("[FileExplorer] new file {:?}: {}", full, e);
+ }
+ }
+ self.refresh_dir(parent, cx);
+ self.close_menu(cx);
+ }
+
+ fn action_new_folder(
+ &mut self,
+ target: Option<MenuTarget>,
+ cx: &mut Context<Self>,
+ ) {
+ let parent = self.parent_for_new(&target);
+ if let Some(name) = next_available_name(&parent, "new_folder_", "", true) {
+ let full = std::path::Path::new(&parent).join(&name);
+ if let Err(e) = std::fs::create_dir(&full) {
+ eprintln!("[FileExplorer] new folder {:?}: {}", full, e);
+ }
+ }
+ self.refresh_dir(parent, cx);
+ self.close_menu(cx);
+ }
+
+ fn action_rename(
+ &mut self,
+ target: MenuTarget,
+ window: &mut Window,
+ cx: &mut Context<Self>,
+ ) {
+ // Nombre actual = file_name del path. Si por alguna razón no
+ // tiene file_name (path raíz), usamos el path completo.
+ let original_name = std::path::Path::new(&target.id)
+ .file_name()
+ .map(|s| s.to_string_lossy().into_owned())
+ .unwrap_or_else(|| target.id.clone());
+
+ let initial = original_name.clone();
+ let input = cx.new(|cx| TextInput::new(initial, cx));
+
+ // Subscribirse a los eventos del input para confirmar/cancelar.
+ cx.subscribe(&input, {
+ let target_path = target.id.clone();
+ let original_name = original_name.clone();
+ move |this: &mut FileExplorer, _, ev: &TextInputEvent, cx| match ev {
+ TextInputEvent::Confirmed(new_name) => {
+ this.commit_rename(&target_path, &original_name, new_name.clone(), cx);
+ }
+ TextInputEvent::Cancelled => {
+ this.close_rename(cx);
+ }
+ }
+ })
+ .detach();
+
+ // Pedir focus para que las próximas teclas vayan al input. Hay
+ // que hacerlo después de que el render lo monte; lo más seguro
+ // es delay un frame con cx.spawn + immediate await.
+ input.update(cx, |i, _| i.request_focus(window));
+
+ self.rename = Some(RenameState {
+ original_name,
+ input,
+ });
+ self.close_menu(cx);
+ }
+
+ fn close_rename(&mut self, cx: &mut Context<Self>) {
+ if self.rename.take().is_some() {
+ cx.notify();
+ }
+ }
+
+ fn commit_rename(
+ &mut self,
+ target_path: &str,
+ original_name: &str,
+ new_name: String,
+ cx: &mut Context<Self>,
+ ) {
+ let trimmed = new_name.trim();
+ let parent_dir = std::path::Path::new(target_path)
+ .parent()
+ .map(|p| p.to_path_buf())
+ .unwrap_or_else(|| std::path::PathBuf::from(self.root.clone()));
+
+ if !trimmed.is_empty() && trimmed != original_name {
+ let from = std::path::PathBuf::from(target_path);
+ let to = parent_dir.join(trimmed);
+ if let Err(e) = std::fs::rename(&from, &to) {
+ eprintln!("[FileExplorer] rename {:?} → {:?}: {}", from, to, e);
+ }
+ }
+
+ let parent_str = parent_dir.to_string_lossy().into_owned();
+ self.refresh_dir(parent_str, cx);
+ self.close_rename(cx);
+ }
+
+ fn action_delete(
+ &mut self,
+ target: MenuTarget,
+ window: &mut Window,
+ cx: &mut Context<Self>,
+ ) {
+ // Prompt nativo del platform — devuelve un Receiver con el índice
+ // del botón clickeado. Esperamos el resultado en un task spawn.
+ let path = target.id.clone();
+ let is_folder = target.is_folder;
+ let name = std::path::Path::new(&path)
+ .file_name()
+ .map(|s| s.to_string_lossy().into_owned())
+ .unwrap_or_else(|| path.clone());
+ let parent_dir = std::path::Path::new(&path)
+ .parent()
+ .map(|p| p.to_string_lossy().into_owned())
+ .unwrap_or_else(|| self.root.clone());
+
+ let answer = window.prompt(
+ PromptLevel::Warning,
+ &format!("¿Borrar \"{}\"?", name),
+ None,
+ &["Borrar", "Cancelar"],
+ cx,
+ );
+
+ cx.spawn(async move |this, cx| {
+ let Ok(idx) = answer.await else { return };
+ // 0 = Borrar, 1 = Cancelar.
+ if idx != 0 {
+ return;
+ }
+ let res = if is_folder {
+ std::fs::remove_dir_all(&path)
+ } else {
+ std::fs::remove_file(&path)
+ };
+ if let Err(e) = res {
+ eprintln!("[FileExplorer] delete {}: {}", path, e);
+ }
+ let _ = this.update(cx, |this, cx| {
+ this.refresh_dir(parent_dir, cx);
+ });
+ })
+ .detach();
+
+ self.close_menu(cx);
+ }
+}
+
+// ---- helpers FS ----
+
+fn sort_entries(entries: &mut Vec<EntityNode>) {
+ entries.sort_by(|a, b| {
+ let a_dir = matches!(a.display_type, DisplayType::Folder);
+ let b_dir = matches!(b.display_type, DisplayType::Folder);
+ b_dir
+ .cmp(&a_dir)
+ .then_with(|| a.name.to_lowercase().cmp(&b.name.to_lowercase()))
+ });
+}
+
+/// Primer nombre `prefix{n}{suffix}` (n = 1..=999) que no exista en `dir`.
+/// Para folder no agregamos sufijo. Devuelve None si los 999 nombres ya
+/// estaban en uso (improbable).
+fn next_available_name(
+ dir: &str,
+ prefix: &str,
+ suffix: &str,
+ is_folder: bool,
+) -> Option<String> {
+ for n in 1..=999u32 {
+ let candidate = format!("{}{}{}", prefix, n, suffix);
+ let full = std::path::Path::new(dir).join(&candidate);
+ let exists = if is_folder {
+ full.is_dir()
+ } else {
+ full.exists()
+ };
+ if !exists {
+ return Some(candidate);
+ }
+ }
+ None
+}
+
+// =====================================================================
+// Render
+// =====================================================================
+
+const MENU_WIDTH: f32 = 200.0;
+
+impl Render for FileExplorer {
+ fn render(&mut self, _w: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
+ let theme = Theme::global(cx).clone();
+ let pending_count = self.pending.len();
+
+ // Capa 1: header + tree.
+ let header = div()
+ .h(px(28.0))
+ .px(px(8.0))
+ .border_b_1()
+ .border_color(theme.border)
+ .flex()
+ .flex_row()
+ .items_center()
+ .gap(px(6.0))
+ .child(
+ div()
+ .text_size(px(11.0))
+ .text_color(theme.fg_muted)
+ .child("📂"),
+ )
+ .child(
+ div()
+ .text_size(px(11.0))
+ .text_color(theme.fg_text)
+ .child(SharedString::from(self.root.clone())),
+ )
+ .child(
+ div()
+ .ml_auto()
+ .text_size(px(10.0))
+ .text_color(theme.fg_muted)
+ .child(SharedString::from(if pending_count > 0 {
+ format!("⏳ {}", pending_count)
+ } else {
+ String::new()
+ })),
+ );
+
+ let body = div().flex_grow().min_h(px(0.0)).child(self.tree_view.clone());
+
+ // Capa 2 (overlay condicional): menú contextual.
+ let menu_overlay = self.menu.clone().map(|menu| self.render_menu(&theme, menu, cx));
+ // Capa 3 (overlay condicional): modal de rename.
+ let rename_overlay = self.rename.clone().map(|st| self.render_rename(&theme, st));
+
+ let mut root = div()
+ .id("file-explorer-root")
+ .size_full()
+ .relative()
+ .bg(theme.bg_panel.clone())
+ .flex()
+ .flex_col()
+ .child(header)
+ .child(body);
+
+ if let Some(overlay) = menu_overlay {
+ root = root.child(overlay);
+ }
+ if let Some(overlay) = rename_overlay {
+ root = root.child(overlay);
+ }
+
+ root
+ }
+}
+
+impl FileExplorer {
+ fn render_menu(
+ &self,
+ theme: &Theme,
+ menu: MenuState,
+ cx: &mut Context<Self>,
+ ) -> impl IntoElement {
+ let on_entry = menu.target.is_some();
+ let target = menu.target.clone();
+ let is_folder = target.as_ref().map(|t| t.is_folder).unwrap_or(false);
+
+ let mut items = div()
+ .flex()
+ .flex_col()
+ .py(px(4.0))
+ .min_w(px(MENU_WIDTH))
+ .bg(theme.bg_panel_alt.clone())
+ .border_1()
+ .border_color(theme.border_strong)
+ .rounded(px(6.0));
+
+ // Open: solo file targets.
+ if on_entry && !is_folder {
+ let t = target.clone().unwrap();
+ items = items.child(
+ menu_item("fe-menu-open", "Abrir", theme).on_click(cx.listener(
+ move |this, _: &ClickEvent, _, cx| {
+ this.action_open(t.clone(), cx);
+ },
+ )),
+ );
+ }
+
+ // Copy path.
+ if let Some(t) = target.clone() {
+ let t_clone = t.clone();
+ items = items.child(
+ menu_item("fe-menu-copy", "Copiar ruta", theme).on_click(cx.listener(
+ move |this, _: &ClickEvent, w, cx| {
+ this.action_copy_path(t_clone.clone(), w, cx);
+ },
+ )),
+ );
+ }
+
+ // Rename — solo cuando hay target.
+ if let Some(t) = target.clone() {
+ items = items.child(
+ menu_item("fe-menu-rename", "Renombrar…", theme).on_click(cx.listener(
+ move |this, _: &ClickEvent, w, cx| {
+ this.action_rename(t.clone(), w, cx);
+ },
+ )),
+ );
+ items = items.child(separator(theme));
+ }
+
+ // New file.
+ let new_target = target.clone();
+ items = items.child(
+ menu_item("fe-menu-newfile", "Nuevo archivo", theme).on_click(cx.listener(
+ move |this, _: &ClickEvent, _, cx| {
+ this.action_new_file(new_target.clone(), cx);
+ },
+ )),
+ );
+
+ // New folder.
+ let new_target_folder = target.clone();
+ items = items.child(
+ menu_item("fe-menu-newfolder", "Nueva carpeta", theme).on_click(cx.listener(
+ move |this, _: &ClickEvent, _, cx| {
+ this.action_new_folder(new_target_folder.clone(), cx);
+ },
+ )),
+ );
+
+ // Delete: solo entries existentes.
+ if let Some(t) = target.clone() {
+ items = items.child(separator(theme));
+ items = items.child(
+ menu_item("fe-menu-delete", "Borrar", theme).on_click(cx.listener(
+ move |this, _: &ClickEvent, w, cx| {
+ this.action_delete(t.clone(), w, cx);
+ },
+ )),
+ );
+ }
+
+ // Wrapper absolute en la posición del click. Las coords del
+ // ContextMenuRequested son window-coords absolutas; las pasamos
+ // directo con .left/.top.
+ div()
+ .absolute()
+ .left(menu.position.x)
+ .top(menu.position.y)
+ .child(items)
+ }
+}
+
+impl FileExplorer {
+ fn render_rename(&self, theme: &Theme, state: RenameState) -> impl IntoElement {
+ // Backdrop oscuro semi-transparente que cubre todo el explorer +
+ // caja centrada con el TextInput. Click sobre el backdrop NO
+ // cierra (queremos forzar Enter/Escape para evitar pérdida
+ // accidental de input).
+ div()
+ .absolute()
+ .top(px(0.0))
+ .left(px(0.0))
+ .size_full()
+ .flex()
+ .items_center()
+ .justify_center()
+ .bg(gpui::hsla(0.0, 0.0, 0.0, 0.55))
+ .child(
+ div()
+ .min_w(px(360.0))
+ .p(px(16.0))
+ .flex()
+ .flex_col()
+ .gap(px(10.0))
+ .bg(theme.bg_panel_alt.clone())
+ .border_1()
+ .border_color(theme.border_strong)
+ .rounded(px(8.0))
+ .child(
+ div()
+ .text_size(px(13.0))
+ .text_color(theme.fg_text)
+ .child(SharedString::from(format!(
+ "Renombrar \"{}\"",
+ state.original_name
+ ))),
+ )
+ .child(state.input.clone())
+ .child(
+ div()
+ .text_size(px(10.0))
+ .text_color(theme.fg_muted)
+ .child("Enter = confirmar — Escape = cancelar"),
+ ),
+ )
+ }
+}
+
+fn menu_item(
+ id: &'static str,
+ label: &'static str,
+ theme: &Theme,
+) -> gpui::Stateful<gpui::Div> {
+ div()
+ .id(id)
+ .px(px(12.0))
+ .py(px(6.0))
+ .text_size(px(12.0))
+ .text_color(theme.fg_text)
+ .hover(|s| s.bg(theme.bg_row_hover))
+ .child(label)
+}
+
+fn separator(theme: &Theme) -> gpui::Div {
+ div()
+ .my(px(3.0))
+ .h(px(1.0))
+ .w_full()
+ .bg(theme.border)
+}
diff --git a/crates/apps/image_viewer/Cargo.toml b/crates/apps/image_viewer/Cargo.toml
new file mode 100644
index 0000000..4d36de2
--- /dev/null
+++ b/crates/apps/image_viewer/Cargo.toml
@@ -0,0 +1,11 @@
+[package]
+name = "yahweh-image-viewer"
+version = { workspace = true }
+edition = { workspace = true }
+license = { workspace = true }
+description = "Visor de imágenes. Suscribe al AppBus y renderea con gpui::img(path)."
+
+[dependencies]
+gpui = { workspace = true }
+yahweh-bus = { workspace = true }
+yahweh-theme = { workspace = true }
diff --git a/crates/apps/image_viewer/src/lib.rs b/crates/apps/image_viewer/src/lib.rs
new file mode 100644
index 0000000..c4eb516
--- /dev/null
+++ b/crates/apps/image_viewer/src/lib.rs
@@ -0,0 +1,148 @@
+//! `yahweh_image_viewer` — visor de imágenes.
+//!
+//! Suscribe al `AppBus` y, en cada `EntitySelected` cuyo provider sea
+//! `local_fs` y la extensión sugiera imagen (jpg, png, webp, gif), pasa el
+//! path a `gpui::img(...)` que se encarga del decode + cache. Para otros
+//! providers o extensiones desconocidas, muestra un mensaje neutro sin
+//! intentar render (evita binarios random pasando por el decoder).
+//!
+//! Detección por extensión: lista de extensiones soportadas en
+//! [`is_image_path`]. Para discriminar por mime real (sin importar la
+//! extensión) habría que invocar `image::guess_format` en un task —
+//! valdrá la pena cuando carguemos imágenes desde SQLite blobs.
+
+use std::path::Path;
+
+use gpui::{
+ Context, Entity, IntoElement, Render, SharedString, Window, div, img, prelude::*, px,
+};
+
+use yahweh_bus::{AppBus, AppEvent};
+use yahweh_theme::Theme;
+
+const FS_PROVIDER: &str = "local_fs";
+
+pub struct ImageViewer {
+ /// Path actualmente mostrado (si lo hay).
+ current_path: Option<String>,
+ /// Mensaje a mostrar cuando no se puede renderear (extensión no
+ /// reconocida, provider sin soporte, etc.).
+ notice: Option<SharedString>,
+}
+
+impl ImageViewer {
+ pub fn new(bus: Entity<AppBus>, cx: &mut Context<Self>) -> Self {
+ cx.observe_global::<Theme>(|_, cx| cx.notify()).detach();
+ cx.subscribe(&bus, |this: &mut ImageViewer, _, ev, cx| {
+ this.on_app_event(ev, cx);
+ })
+ .detach();
+ Self {
+ current_path: None,
+ notice: None,
+ }
+ }
+
+ fn on_app_event(&mut self, event: &AppEvent, cx: &mut Context<Self>) {
+ let (provider, id) = match event {
+ AppEvent::EntitySelected { provider, id, .. }
+ | AppEvent::EntityOpened { provider, id, .. } => (provider, id),
+ };
+
+ if provider != FS_PROVIDER {
+ self.current_path = None;
+ self.notice = Some(
+ format!("provider '{}' no soportado por ImageViewer", provider).into(),
+ );
+ cx.notify();
+ return;
+ }
+
+ if !is_image_path(id) {
+ self.current_path = None;
+ self.notice = Some("(no es una imagen reconocible)".into());
+ cx.notify();
+ return;
+ }
+
+ self.current_path = Some(id.clone());
+ self.notice = None;
+ cx.notify();
+ }
+}
+
+fn is_image_path(path: &str) -> bool {
+ let ext = Path::new(path)
+ .extension()
+ .and_then(|e| e.to_str())
+ .unwrap_or("")
+ .to_ascii_lowercase();
+ matches!(
+ ext.as_str(),
+ "png" | "jpg" | "jpeg" | "webp" | "gif" | "bmp" | "ico" | "tiff" | "tif"
+ )
+}
+
+impl Render for ImageViewer {
+ fn render(&mut self, _w: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
+ let theme = Theme::global(cx).clone();
+
+ let header_text = match (&self.current_path, &self.notice) {
+ (Some(p), _) => format!("[image] {}", p),
+ (None, Some(n)) => n.to_string(),
+ (None, None) => "(ninguna imagen seleccionada)".to_string(),
+ };
+
+ let body: gpui::AnyElement = match (&self.current_path, &self.notice) {
+ (Some(path), _) => {
+ let path_buf = std::path::PathBuf::from(path);
+ div()
+ .flex_grow()
+ .min_h(px(0.0))
+ .flex()
+ .items_center()
+ .justify_center()
+ .p(px(12.0))
+ .child(img(path_buf).max_w_full().max_h_full())
+ .into_any_element()
+ }
+ (None, Some(n)) => div()
+ .flex_grow()
+ .flex()
+ .items_center()
+ .justify_center()
+ .text_color(theme.fg_muted)
+ .text_size(px(11.0))
+ .child(n.clone())
+ .into_any_element(),
+ (None, None) => div()
+ .flex_grow()
+ .flex()
+ .items_center()
+ .justify_center()
+ .text_color(theme.fg_muted)
+ .text_size(px(11.0))
+ .child("doble click sobre una imagen en el FileExplorer.")
+ .into_any_element(),
+ };
+
+ div()
+ .size_full()
+ .bg(theme.bg_panel.clone())
+ .flex()
+ .flex_col()
+ .child(
+ div()
+ .h(px(28.0))
+ .px(px(10.0))
+ .border_b_1()
+ .border_color(theme.border)
+ .flex()
+ .items_center()
+ .text_size(px(11.0))
+ .text_color(theme.fg_muted)
+ .child(SharedString::from(header_text)),
+ )
+ .child(body)
+ }
+}
diff --git a/crates/apps/text_viewer/Cargo.toml b/crates/apps/text_viewer/Cargo.toml
new file mode 100644
index 0000000..fd462a7
--- /dev/null
+++ b/crates/apps/text_viewer/Cargo.toml
@@ -0,0 +1,14 @@
+[package]
+name = "yahweh-text-viewer"
+version = { workspace = true }
+edition = { workspace = true }
+license = { workspace = true }
+description = "Visor de texto plano. Suscribe al AppBus y carga contenido async."
+
+[dependencies]
+gpui = { workspace = true }
+yahweh-core = { workspace = true }
+yahweh-theme = { workspace = true }
+yahweh-bus = { workspace = true }
+yahweh-provider-fs = { workspace = true }
+yahweh-provider-sqlite = { workspace = true }
diff --git a/crates/apps/text_viewer/src/lib.rs b/crates/apps/text_viewer/src/lib.rs
new file mode 100644
index 0000000..135b40f
--- /dev/null
+++ b/crates/apps/text_viewer/src/lib.rs
@@ -0,0 +1,285 @@
+//! `yahweh_text_viewer` — visor de texto plano.
+//!
+//! Suscribe al `AppBus` y, en cada `EntitySelected` / `EntityOpened`,
+//! decide si el `provider` corresponde a uno que sabe leer (por ahora
+//! `local_fs` y `sqlite_db`); si sí, dispara `cx.spawn` con el provider
+//! correspondiente para traer el contenido. Mientras carga muestra
+//! "(cargando…)"; al terminar lo pinta como texto con saltos de línea
+//! preservados.
+//!
+//! Si el contenido no es válido UTF-8 (binario), muestra los primeros
+//! N bytes en hex — útil para preview no ciego sin pretender ser un
+//! editor de binarios.
+
+use std::sync::Arc;
+
+use gpui::{
+ Context, Entity, IntoElement, Render, SharedString, Window, div, prelude::*, px,
+};
+
+use yahweh_bus::{AppBus, AppEvent};
+use yahweh_core::DataProvider;
+use yahweh_provider_fs::{FileDataProvider, PROVIDER_ID as FS_PROVIDER_ID};
+use yahweh_provider_sqlite::{PROVIDER_ID as SQL_PROVIDER_ID, SqliteDataProvider};
+use yahweh_theme::Theme;
+
+const PREVIEW_HEX_BYTES: usize = 256;
+const MAX_TEXT_BYTES: usize = 256 * 1024;
+
+pub struct TextViewer {
+ /// Última entidad mostrada. `None` ⇒ pantalla en estado "vacío".
+ current: Option<CurrentEntity>,
+ /// Contenido renderizado. Si está cargando se muestra el estado en
+ /// `current`.
+ content: Content,
+ /// Generación monotónica — al cambiar `current` la incrementamos para
+ /// descartar resultados de loads previos que vuelvan tarde.
+ generation: u64,
+}
+
+#[derive(Clone, Debug)]
+struct CurrentEntity {
+ provider: String,
+ provider_path: Option<String>,
+ id: String,
+ loading: bool,
+}
+
+#[derive(Clone)]
+enum Content {
+ Empty,
+ Loading,
+ Text(SharedString),
+ HexPreview(SharedString),
+ Error(SharedString),
+ Unsupported(SharedString),
+}
+
+impl TextViewer {
+ pub fn new(bus: Entity<AppBus>, cx: &mut Context<Self>) -> Self {
+ cx.observe_global::<Theme>(|_, cx| cx.notify()).detach();
+
+ cx.subscribe(&bus, |this: &mut TextViewer, _, ev, cx| {
+ this.on_app_event(ev, cx);
+ })
+ .detach();
+
+ Self {
+ current: None,
+ content: Content::Empty,
+ generation: 0,
+ }
+ }
+
+ fn on_app_event(&mut self, event: &AppEvent, cx: &mut Context<Self>) {
+ let (provider, provider_path, id) = match event {
+ AppEvent::EntitySelected { provider, provider_path, id }
+ | AppEvent::EntityOpened { provider, provider_path, id } => {
+ (provider.clone(), provider_path.clone(), id.clone())
+ }
+ };
+
+ // Comparar con el actual para evitar reload de lo mismo.
+ if let Some(cur) = &self.current {
+ if cur.provider == provider && cur.id == id && cur.provider_path == provider_path {
+ return;
+ }
+ }
+
+ self.generation = self.generation.wrapping_add(1);
+ let gen = self.generation;
+ self.current = Some(CurrentEntity {
+ provider: provider.clone(),
+ provider_path: provider_path.clone(),
+ id: id.clone(),
+ loading: true,
+ });
+ self.content = Content::Loading;
+ cx.notify();
+
+ // Dispatch por provider.
+ if provider == FS_PROVIDER_ID {
+ self.spawn_load_fs(id, gen, cx);
+ } else if provider == SQL_PROVIDER_ID {
+ self.spawn_load_sqlite(provider_path, id, gen, cx);
+ } else {
+ self.content = Content::Unsupported(
+ format!("provider '{}' no soportado por TextViewer", provider).into(),
+ );
+ if let Some(cur) = &mut self.current {
+ cur.loading = false;
+ }
+ cx.notify();
+ }
+ }
+
+ fn spawn_load_fs(&self, path: String, gen: u64, cx: &mut Context<Self>) {
+ let provider = Arc::new(FileDataProvider);
+ cx.spawn(async move |this, cx| {
+ let result = provider.get_data(&path).await;
+ let _ = this.update(cx, |this, cx| this.on_loaded(gen, result, cx));
+ })
+ .detach();
+ }
+
+ fn spawn_load_sqlite(
+ &self,
+ provider_path: Option<String>,
+ id: String,
+ gen: u64,
+ cx: &mut Context<Self>,
+ ) {
+ let db_path = provider_path.unwrap_or_else(|| "yahweh.db".to_string());
+ cx.spawn(async move |this, cx| {
+ // El SqliteDataProvider abre la DB en su constructor — si
+ // falla, reportamos error y salimos.
+ let provider = match SqliteDataProvider::new(&db_path) {
+ Ok(p) => p,
+ Err(e) => {
+ let _ = this.update(cx, |this, cx| {
+ this.on_loaded(
+ gen,
+ Err(format!("abriendo {}: {}", db_path, e)),
+ cx,
+ )
+ });
+ return;
+ }
+ };
+ let result = provider.get_data(&id).await;
+ let _ = this.update(cx, |this, cx| this.on_loaded(gen, result, cx));
+ })
+ .detach();
+ }
+
+ fn on_loaded(
+ &mut self,
+ gen: u64,
+ result: Result<Vec<u8>, String>,
+ cx: &mut Context<Self>,
+ ) {
+ // Si el usuario cambió de selección antes de que volviera el load,
+ // descartamos este resultado.
+ if gen != self.generation {
+ return;
+ }
+
+ if let Some(cur) = &mut self.current {
+ cur.loading = false;
+ }
+
+ self.content = match result {
+ Ok(bytes) => bytes_to_content(&bytes),
+ Err(e) => Content::Error(format!("error: {}", e).into()),
+ };
+ cx.notify();
+ }
+}
+
+fn bytes_to_content(bytes: &[u8]) -> Content {
+ if bytes.is_empty() {
+ return Content::Text("(vacío)".into());
+ }
+ let truncated = bytes.len() > MAX_TEXT_BYTES;
+ let slice = if truncated { &bytes[..MAX_TEXT_BYTES] } else { bytes };
+ match std::str::from_utf8(slice) {
+ Ok(s) => {
+ let mut out = s.to_string();
+ if truncated {
+ out.push_str("\n…(truncado)…");
+ }
+ Content::Text(out.into())
+ }
+ Err(_) => {
+ // No es UTF-8: mostramos hex preview de los primeros bytes.
+ let n = bytes.len().min(PREVIEW_HEX_BYTES);
+ let mut hex = String::with_capacity(n * 3);
+ for (i, b) in bytes[..n].iter().enumerate() {
+ if i > 0 && i % 16 == 0 {
+ hex.push('\n');
+ }
+ hex.push_str(&format!("{:02x} ", b));
+ }
+ if bytes.len() > n {
+ hex.push_str(&format!("\n…({} bytes más)", bytes.len() - n));
+ }
+ Content::HexPreview(hex.into())
+ }
+ }
+}
+
+impl Render for TextViewer {
+ fn render(&mut self, _w: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
+ let theme = Theme::global(cx).clone();
+
+ let header_text = match &self.current {
+ None => "(ningún archivo seleccionado)".to_string(),
+ Some(cur) => {
+ let suffix = if cur.loading { " ⏳" } else { "" };
+ format!("[{}] {}{}", cur.provider, cur.id, suffix)
+ }
+ };
+
+ let body: gpui::AnyElement = match &self.content {
+ Content::Empty => div()
+ .text_color(theme.fg_muted)
+ .text_size(px(11.0))
+ .child("seleccioná un archivo en el FileExplorer o una entry en el DatabaseExplorer.")
+ .into_any_element(),
+ Content::Loading => div()
+ .text_color(theme.fg_muted)
+ .text_size(px(11.0))
+ .child("(cargando…)")
+ .into_any_element(),
+ Content::Text(s) => div()
+ .text_color(theme.fg_text)
+ .text_size(px(12.0))
+ .font_family("monospace")
+ .child(s.clone())
+ .into_any_element(),
+ Content::HexPreview(s) => div()
+ .text_color(theme.fg_muted)
+ .text_size(px(11.0))
+ .font_family("monospace")
+ .child(s.clone())
+ .into_any_element(),
+ Content::Error(s) => div()
+ .text_color(theme.accent_strong)
+ .text_size(px(11.0))
+ .child(s.clone())
+ .into_any_element(),
+ Content::Unsupported(s) => div()
+ .text_color(theme.fg_muted)
+ .text_size(px(11.0))
+ .child(s.clone())
+ .into_any_element(),
+ };
+
+ div()
+ .size_full()
+ .bg(theme.bg_panel.clone())
+ .flex()
+ .flex_col()
+ .child(
+ div()
+ .h(px(28.0))
+ .px(px(10.0))
+ .border_b_1()
+ .border_color(theme.border)
+ .flex()
+ .items_center()
+ .text_size(px(11.0))
+ .text_color(theme.fg_muted)
+ .child(SharedString::from(header_text)),
+ )
+ .child(
+ div()
+ .id("text-viewer-body")
+ .flex_grow()
+ .min_h(px(0.0))
+ .overflow_scroll()
+ .p(px(12.0))
+ .child(body),
+ )
+ }
+}
diff --git a/crates/apps/yahweh-shell/Cargo.toml b/crates/apps/yahweh-shell/Cargo.toml
new file mode 100644
index 0000000..3d66cae
--- /dev/null
+++ b/crates/apps/yahweh-shell/Cargo.toml
@@ -0,0 +1,31 @@
+[package]
+name = "yahweh-shell"
+version = { workspace = true }
+edition = { workspace = true }
+license = { workspace = true }
+description = "Bootstrap GPUI + LayoutHost de Yahweh."
+
+[dependencies]
+yahweh-core = { workspace = true }
+yahweh-theme = { workspace = true }
+yahweh-provider-fs = { workspace = true }
+yahweh-provider-sqlite = { workspace = true }
+yahweh-widget-tree = { workspace = true }
+yahweh-widget-container-core = { workspace = true }
+yahweh-widget-splitter = { workspace = true }
+yahweh-widget-tabs = { workspace = true }
+yahweh-widget-tiled = { workspace = true }
+yahweh-bus = { workspace = true }
+yahweh-file-explorer = { workspace = true }
+yahweh-database-explorer = { workspace = true }
+yahweh-text-viewer = { workspace = true }
+yahweh-image-viewer = { workspace = true }
+gpui = { workspace = true }
+tokio = { workspace = true }
+serde = { workspace = true }
+serde_json = { workspace = true }
+notify = { workspace = true }
+
+[[bin]]
+name = "yahweh"
+path = "src/main.rs"
diff --git a/crates/apps/yahweh-shell/src/hot_reload.rs b/crates/apps/yahweh-shell/src/hot_reload.rs
new file mode 100644
index 0000000..960b086
--- /dev/null
+++ b/crates/apps/yahweh-shell/src/hot_reload.rs
@@ -0,0 +1,108 @@
+//! Hot-reload del `layout.json` vía `notify` watcher.
+//!
+//! Anatomía:
+//! 1. Un thread del SO corre el watcher (`notify::recommended_watcher`) que
+//! spawnea su propio thread de polling. Cuando detecta cambios en el
+//! archivo objetivo, manda `()` por un `std::sync::mpsc::channel`.
+//! 2. Una task de gpui (`cx.spawn`) hace `try_recv` cada N ms (timer en el
+//! `background_executor`). Si llega algo, relee el JSON y actualiza el
+//! `LayoutModel` con `replace_tree`.
+//!
+//! Esquema separado intencional: notify trabaja en hilos del SO (no
+//! integra con el executor de gpui), así que rebotamos vía mpsc para no
+//! tocar entities desde threads ajenos. El tradeoff es una latencia de
+//! poll N (250ms por default) — imperceptible para edición manual de un
+//! JSON.
+//!
+//! Ignoramos cambios cuando el JSON quedó inválido (parse error) — el
+//! `LayerConfig::load_or_default` cae al árbol default. Si querés que la
+//! UI muestre el error, agregar un AppEvent::ConfigError y un toast en
+//! Fase 8.
+
+use std::path::PathBuf;
+use std::sync::mpsc::{Receiver, channel};
+use std::time::Duration;
+
+use gpui::{App, AsyncApp, Entity};
+use notify::{RecommendedWatcher, RecursiveMode, Watcher};
+
+use yahweh_core::LayerConfig;
+
+use crate::layout_model::LayoutModel;
+
+/// Frecuencia de polling del receiver. 250ms es el sweet spot:
+/// suficientemente rápido para sentirse "instantáneo" pero sin gastar CPU.
+const POLL_INTERVAL: Duration = Duration::from_millis(250);
+
+/// Spawnea el watcher + el polling task. Devuelve el `RecommendedWatcher`
+/// — el caller debe mantenerlo vivo (drop ⇒ stop watching). Por
+/// conveniencia retorna también nada más; el caller suele guardar el
+/// watcher en una global o filed-leakeada.
+pub fn spawn_watch(
+ path: PathBuf,
+ model: Entity<LayoutModel>,
+ cx: &mut App,
+) -> notify::Result<RecommendedWatcher> {
+ let (tx, rx) = channel::<()>();
+
+ // Watcher: el cierre se ejecuta en el thread que `notify` provee. Solo
+ // empujamos `()` al canal — el side mpsc maneja toda la lógica.
+ let mut watcher = notify::recommended_watcher(move |res: notify::Result<notify::Event>| {
+ if let Ok(ev) = res {
+ // Solo nos interesan modify/create — los Access se ignoran
+ // para no triggerear en lecturas (ej. cat).
+ if matches!(
+ ev.kind,
+ notify::EventKind::Modify(_)
+ | notify::EventKind::Create(_)
+ | notify::EventKind::Remove(_)
+ ) {
+ let _ = tx.send(());
+ }
+ }
+ })?;
+
+ // Watcheamos el directorio padre, no el archivo en sí. Muchos editores
+ // hacen "rename + create" al guardar (atomic write), lo que rompe
+ // watching del file directo. Ver el dir y filtrar por path es robusto.
+ let parent = path
+ .parent()
+ .map(|p| p.to_path_buf())
+ .unwrap_or_else(|| PathBuf::from("."));
+ watcher.watch(&parent, RecursiveMode::NonRecursive)?;
+
+ // Spawnea el polling task en el ForegroundExecutor para poder llamar
+ // model.update sin cross-thread issues.
+ let path_for_task = path.clone();
+ cx.foreground_executor()
+ .spawn(poll_loop(rx, path_for_task, model, cx.to_async()))
+ .detach();
+
+ Ok(watcher)
+}
+
+async fn poll_loop(
+ rx: Receiver<()>,
+ path: PathBuf,
+ model: Entity<LayoutModel>,
+ mut cx: AsyncApp,
+) {
+ let timer = cx.background_executor().clone();
+ loop {
+ timer.timer(POLL_INTERVAL).await;
+ // Drenamos todos los eventos acumulados en este ciclo —
+ // múltiples writes seguidos colapsan a UN solo reload.
+ let mut had_event = false;
+ while rx.try_recv().is_ok() {
+ had_event = true;
+ }
+ if !had_event {
+ continue;
+ }
+
+ // Releemos el JSON desde disco. Si parsea bien, replace_tree;
+ // si no, el `load_or_default` cae al default (no rompe la UI).
+ let tree = LayerConfig::load_or_default(path.to_string_lossy().as_ref());
+ let _ = model.update(&mut cx, |m, cx| m.replace_tree(tree, cx));
+ }
+}
diff --git a/crates/apps/yahweh-shell/src/layout_host.rs b/crates/apps/yahweh-shell/src/layout_host.rs
new file mode 100644
index 0000000..a9fe8f1
--- /dev/null
+++ b/crates/apps/yahweh-shell/src/layout_host.rs
@@ -0,0 +1,576 @@
+//! `LayoutHost` — orquestador del layout dinámico.
+//!
+//! Lee un `LayerConfig` (raíz del JSON) y construye un árbol de entidades
+//! GPUI dispatch-eando por `kind`:
+//!
+//! | kind | factory |
+//! |-------------|----------------------------------------------|
+//! | "Split" | `SplitContainer` con dirección + flex |
+//! | "Tree" | `ManagedTree` con dataset stub |
+//! | "Status" | `StatusPanel` |
+//! | (otro) | placeholder textual con el kind y params |
+//!
+//! Cada entidad se memoiza por `NodeId` (string opcional del JSON o el path
+//! sintético `root/child/0`). Mientras el `id` no cambie entre rebuilds, la
+//! misma instancia se reusa — esto es lo que permite swappear el `kind` de
+//! un container (Split → Tabs → Tiled) preservando los hijos sin reset.
+//!
+//! En Fase 3 el `LayoutHost` solo reconstruye al inicio. La observación del
+//! `LayoutModel` (hot-reload del JSON, mutaciones desde la UI) entra en
+//! Fase 7. Pero el diseño ya soporta `rebuild()` idempotente — se invoca
+//! cuando el modelo cambia y la memoización mantiene los hijos vivos.
+
+use std::collections::HashMap;
+
+use gpui::{
+ AnyView, Context, Entity, IntoElement, Render, SharedString, Window, div, prelude::*,
+};
+
+use yahweh_bus::{AppBus, AppEvent};
+use yahweh_core::{LayerConfig, LayoutDirection, NodeId};
+use yahweh_database_explorer::{DatabaseExplorer, DatabaseExplorerEvent};
+use yahweh_file_explorer::{FileExplorer, FileExplorerEvent};
+use yahweh_image_viewer::ImageViewer;
+use yahweh_text_viewer::TextViewer;
+use yahweh_widget_container_core::ChildSlot;
+use yahweh_widget_splitter::{SplitContainer, SplitEvent};
+use yahweh_widget_tabs::TabContainer;
+use yahweh_widget_tiled::{TiledContainer, TiledEvent};
+
+use crate::layout_model::{LayoutModel, LayoutModelEvent};
+use crate::managed_tree::ManagedTree;
+use crate::persister::Persister;
+use crate::status_panel::StatusPanel;
+
+// =====================================================================
+// LayoutHost
+// =====================================================================
+
+pub struct LayoutHost {
+ /// Modelo observable. Cualquier mutación (set_kind, replace_tree)
+ /// dispara un rebuild idempotente que preserva memoización.
+ model: Entity<LayoutModel>,
+
+ /// Bus app-level. Lo distribuimos a viewers (que se subscriben para
+ /// reaccionar a EntitySelected/Opened) y forwardeamos los eventos
+ /// tipados de explorers hacia él.
+ bus: Entity<AppBus>,
+
+ /// Persister adoptado — el LayoutHost mantiene su Entity vivo. Sin
+ /// strong handle el entity se dropea y la subscripción al model
+ /// queda inactiva.
+ #[allow(dead_code)]
+ persister: Entity<Persister>,
+
+ /// Memoización de instancias por NodeId. Cada slot guarda la entidad
+ /// tipada para poder llamarle métodos específicos (set_children en
+ /// containers, etc.). Se preserva entre rebuilds — eso es lo que
+ /// permite swappear kind del padre sin perder los hijos.
+ nodes: HashMap<NodeId, NodeSlot>,
+
+ /// La AnyView raíz, computada por el último `rebuild`. El render solo
+ /// pinta este handle.
+ root_view: Option<AnyView>,
+}
+
+/// Una entidad concreta instanciada en el árbol. Distinguimos por variante
+/// porque cada tipo tiene una API distinta para reaccionar a actualizaciones
+/// (set_children para Split, etc.). Las factories devuelven `AnyView`
+/// directamente (`AnyView::from(entity.clone())`); esta enum solo guarda
+/// la handle tipada para llamadas futuras.
+enum NodeSlot {
+ Split(Entity<SplitContainer>),
+ Tabs(Entity<TabContainer>),
+ Tiled(Entity<TiledContainer>),
+ Tree(Entity<ManagedTree>),
+ FileExplorer(Entity<FileExplorer>),
+ DatabaseExplorer(Entity<DatabaseExplorer>),
+ TextViewer(Entity<TextViewer>),
+ ImageViewer(Entity<ImageViewer>),
+ Status(Entity<StatusPanel>),
+ Placeholder(Entity<PlaceholderView>),
+}
+
+impl LayoutHost {
+ pub fn new(
+ model: Entity<LayoutModel>,
+ bus: Entity<AppBus>,
+ persister: Entity<Persister>,
+ cx: &mut Context<Self>,
+ ) -> Self {
+ // Subscripción event-filtered: solo rebuildeamos en cambios
+ // estructurales (set_kind, replace_tree). FlexChanged proviene de
+ // drags de divisor — el splitter ya tiene el flex aplicado en su
+ // Vec, rebuildear lo resetearía y rompería el drag.
+ cx.subscribe(&model, |this, _, ev: &LayoutModelEvent, cx| match ev {
+ LayoutModelEvent::StructureChanged => this.rebuild(cx),
+ LayoutModelEvent::FlexChanged => {}
+ })
+ .detach();
+
+ let mut me = Self {
+ model,
+ bus,
+ persister,
+ nodes: HashMap::new(),
+ root_view: None,
+ };
+ me.rebuild(cx);
+ me
+ }
+
+ /// Rebuild idempotente: walk del árbol del model, instancia (o reusa)
+ /// cada nodo, propaga children a los containers.
+ pub fn rebuild(&mut self, cx: &mut Context<Self>) {
+ // Snapshot del config para no chocar con el borrow al iterar +
+ // mutar self.nodes.
+ let cfg = self.model.read(cx).tree().clone();
+ let used_ids = std::cell::RefCell::new(Vec::new());
+ let view = self.build_node(&cfg, "root", &used_ids, cx);
+
+ // GC: tirar nodos cuyo id ya no aparece en el árbol nuevo.
+ let used: std::collections::HashSet<NodeId> =
+ used_ids.into_inner().into_iter().collect();
+ self.nodes.retain(|id, _| used.contains(id));
+
+ self.root_view = Some(view);
+ cx.notify();
+ }
+
+ /// DFS recursivo. `path` se acumula para los nodos que no traen `id`
+ /// propio en el JSON (`root/0/1` etc) — la sintetización vive en
+ /// `NodeId::from_layer`.
+ fn build_node(
+ &mut self,
+ cfg: &LayerConfig,
+ path: &str,
+ used_ids: &std::cell::RefCell<Vec<NodeId>>,
+ cx: &mut Context<Self>,
+ ) -> AnyView {
+ let id = NodeId::from_layer(cfg, path);
+ used_ids.borrow_mut().push(id.clone());
+
+ match cfg.kind.as_str() {
+ "Split" => self.build_split(id, cfg, path, used_ids, cx),
+ "Tabs" => self.build_tabs(id, cfg, path, used_ids, cx),
+ "Tiled" => self.build_tiled(id, cfg, path, used_ids, cx),
+ "Tree" => self.build_tree(id, cfg, cx),
+ "FileExplorer" => self.build_file_explorer(id, cfg, cx),
+ "DatabaseExplorer" => self.build_database_explorer(id, cfg, cx),
+ "TextViewer" => self.build_text_viewer(id, cx),
+ "ImageViewer" => self.build_image_viewer(id, cx),
+ "Status" => self.build_status(id, cx),
+ _ => self.build_placeholder(id, cfg, cx),
+ }
+ }
+
+ /// Helper común — construye los `ChildSlot`s de un contenedor haciendo
+ /// recursión sobre los hijos del JSON. Usado por Split / Tabs / Tiled.
+ fn build_child_slots(
+ &mut self,
+ cfg: &LayerConfig,
+ path: &str,
+ used_ids: &std::cell::RefCell<Vec<NodeId>>,
+ cx: &mut Context<Self>,
+ ) -> Vec<ChildSlot> {
+ let mut slots = Vec::with_capacity(cfg.children.len());
+ for (i, child) in cfg.children.iter().enumerate() {
+ let child_path = format!("{}/{}", path, i);
+ let child_view = self.build_node(child, &child_path, used_ids, cx);
+ slots.push(ChildSlot {
+ id: NodeId::from_layer(child, &child_path),
+ flex: child.flex_weight() as f32,
+ label: child.get_param("label").cloned(),
+ view: child_view,
+ });
+ }
+ slots
+ }
+
+ // ------- factories por kind -------
+
+ fn build_split(
+ &mut self,
+ id: NodeId,
+ cfg: &LayerConfig,
+ path: &str,
+ used_ids: &std::cell::RefCell<Vec<NodeId>>,
+ cx: &mut Context<Self>,
+ ) -> AnyView {
+ let direction = match cfg.layout_direction() {
+ LayoutDirection::Vertical => LayoutDirection::Vertical,
+ LayoutDirection::Horizontal => LayoutDirection::Horizontal,
+ LayoutDirection::Overlay => LayoutDirection::Vertical, // fallback
+ };
+
+ // Get-or-create — si ya existe del rebuild anterior y es Split, lo
+ // reusamos. Si era de otro tipo, lo descartamos.
+ let entity = match self.nodes.get(&id) {
+ Some(NodeSlot::Split(e)) => e.clone(),
+ _ => {
+ let e = cx.new(|cx| SplitContainer::new(direction, cx));
+ // Suscripción a DragEnd para persistir flex al model.
+ // Usamos el id del Split como ancla para resolver children
+ // por id en el LayerConfig.
+ let model = self.model.clone();
+ let split_node_id = id.clone();
+ cx.subscribe(&e, move |_, split_entity, ev: &SplitEvent, cx| {
+ if !matches!(ev, SplitEvent::DragEnd) {
+ return;
+ }
+ // Snapshot de los flex actuales del splitter.
+ let snapshots: Vec<(NodeId, f32)> = split_entity
+ .read(cx)
+ .children()
+ .iter()
+ .map(|c| (c.id.clone(), c.flex))
+ .collect();
+ let _ = split_node_id; // (queda disponible si en
+ // futuro queremos targetear
+ // el padre directamente).
+ model.update(cx, |m, cx| {
+ for (child_id, flex) in snapshots {
+ m.set_flex(&child_id, flex, cx);
+ }
+ });
+ })
+ .detach();
+ self.nodes.insert(id.clone(), NodeSlot::Split(e.clone()));
+ e
+ }
+ };
+
+ // Sincronizamos la dirección por si el JSON cambió.
+ entity.update(cx, |s, cx| s.set_direction(direction, cx));
+
+ let slots = self.build_child_slots(cfg, path, used_ids, cx);
+ entity.update(cx, |s, cx| s.set_children(slots, cx));
+
+ AnyView::from(entity)
+ }
+
+ fn build_tabs(
+ &mut self,
+ id: NodeId,
+ cfg: &LayerConfig,
+ path: &str,
+ used_ids: &std::cell::RefCell<Vec<NodeId>>,
+ cx: &mut Context<Self>,
+ ) -> AnyView {
+ let entity = match self.nodes.get(&id) {
+ Some(NodeSlot::Tabs(e)) => e.clone(),
+ _ => {
+ let e = cx.new(|cx| TabContainer::new(cx));
+ self.nodes.insert(id.clone(), NodeSlot::Tabs(e.clone()));
+ e
+ }
+ };
+
+ let slots = self.build_child_slots(cfg, path, used_ids, cx);
+ entity.update(cx, |s, cx| s.set_children(slots, cx));
+
+ AnyView::from(entity)
+ }
+
+ fn build_tiled(
+ &mut self,
+ id: NodeId,
+ cfg: &LayerConfig,
+ path: &str,
+ used_ids: &std::cell::RefCell<Vec<NodeId>>,
+ cx: &mut Context<Self>,
+ ) -> AnyView {
+ let entity = match self.nodes.get(&id) {
+ Some(NodeSlot::Tiled(e)) => e.clone(),
+ _ => {
+ let e = cx.new(|cx| TiledContainer::new(cx));
+ // Drag-to-swap: el TiledContainer emite Reordered cuando
+ // un drag termina sobre otro tile. Lo commiteamos al
+ // model swappeando children del padre — el rebuild
+ // posterior aplicará el nuevo orden preservando los
+ // entities por NodeId.
+ let model = self.model.clone();
+ let parent_id = id.clone();
+ cx.subscribe(&e, move |_, _, ev: &TiledEvent, cx| match ev {
+ TiledEvent::Reordered {
+ from_index,
+ to_index,
+ ..
+ } => {
+ let from = *from_index;
+ let to = *to_index;
+ let parent = parent_id.clone();
+ model.update(cx, |m, cx| m.swap_children(&parent, from, to, cx));
+ }
+ })
+ .detach();
+ self.nodes.insert(id.clone(), NodeSlot::Tiled(e.clone()));
+ e
+ }
+ };
+
+ let slots = self.build_child_slots(cfg, path, used_ids, cx);
+ entity.update(cx, |s, cx| s.set_children(slots, cx));
+
+ AnyView::from(entity)
+ }
+
+ fn build_tree(&mut self, id: NodeId, cfg: &LayerConfig, cx: &mut Context<Self>) -> AnyView {
+ // Param `dataset` selecciona el stub. Default: "sources".
+ let dataset = cfg
+ .get_param("dataset")
+ .cloned()
+ .unwrap_or_else(|| "sources".to_string());
+
+ let entity = match self.nodes.get(&id) {
+ Some(NodeSlot::Tree(e)) => e.clone(),
+ _ => {
+ let list_id = SharedString::from(format!("tree-{}", id));
+ let dataset_key = SharedString::from(dataset);
+ let e = cx.new(|cx| ManagedTree::new(list_id, dataset_key, cx));
+ self.nodes.insert(id.clone(), NodeSlot::Tree(e.clone()));
+ e
+ }
+ };
+
+ AnyView::from(entity)
+ }
+
+ fn build_file_explorer(
+ &mut self,
+ id: NodeId,
+ cfg: &LayerConfig,
+ cx: &mut Context<Self>,
+ ) -> AnyView {
+ // Param `root` define el path inicial. Default: "." (cwd).
+ let root = cfg
+ .get_param("root")
+ .cloned()
+ .unwrap_or_else(|| ".".to_string());
+
+ let entity = match self.nodes.get(&id) {
+ Some(NodeSlot::FileExplorer(e)) => e.clone(),
+ _ => {
+ let e = cx.new(|cx| FileExplorer::new(root, cx));
+ // Forwarder: cuando el explorer emite eventos tipados, los
+ // traducimos al formato agnóstico del AppBus.
+ let bus = self.bus.clone();
+ cx.subscribe(&e, move |_, _, ev: &FileExplorerEvent, cx| {
+ let app_ev = match ev {
+ FileExplorerEvent::FileSelected { path } => {
+ Some(AppEvent::EntitySelected {
+ provider: "local_fs".to_string(),
+ provider_path: None,
+ id: path.clone(),
+ })
+ }
+ FileExplorerEvent::FileOpened { path } => {
+ Some(AppEvent::EntityOpened {
+ provider: "local_fs".to_string(),
+ provider_path: None,
+ id: path.clone(),
+ })
+ }
+ FileExplorerEvent::RootChanged { .. } => None,
+ };
+ if let Some(ev) = app_ev {
+ bus.update(cx, |_, cx| cx.emit(ev));
+ }
+ })
+ .detach();
+ self.nodes
+ .insert(id.clone(), NodeSlot::FileExplorer(e.clone()));
+ e
+ }
+ };
+ AnyView::from(entity)
+ }
+
+ fn build_database_explorer(
+ &mut self,
+ id: NodeId,
+ cfg: &LayerConfig,
+ cx: &mut Context<Self>,
+ ) -> AnyView {
+ // Param `path` define el .sqlite. Default: "yahweh.db" en cwd.
+ let path = cfg
+ .get_param("path")
+ .cloned()
+ .unwrap_or_else(|| "yahweh.db".to_string());
+
+ let entity = match self.nodes.get(&id) {
+ Some(NodeSlot::DatabaseExplorer(e)) => e.clone(),
+ _ => {
+ let e = cx.new(|cx| DatabaseExplorer::new(path.clone(), cx));
+ // Forwarder al bus; el `provider_path` lleva el path del
+ // .sqlite para que el TextViewer pueda construir su propio
+ // SqliteDataProvider de la misma DB.
+ let bus = self.bus.clone();
+ let db_path = path.clone();
+ cx.subscribe(&e, move |_, _, ev: &DatabaseExplorerEvent, cx| {
+ let app_ev = match ev {
+ DatabaseExplorerEvent::EntitySelected { id } => {
+ Some(AppEvent::EntitySelected {
+ provider: "sqlite_db".to_string(),
+ provider_path: Some(db_path.clone()),
+ id: id.clone(),
+ })
+ }
+ DatabaseExplorerEvent::EntityOpened { id } => {
+ Some(AppEvent::EntityOpened {
+ provider: "sqlite_db".to_string(),
+ provider_path: Some(db_path.clone()),
+ id: id.clone(),
+ })
+ }
+ };
+ if let Some(ev) = app_ev {
+ bus.update(cx, |_, cx| cx.emit(ev));
+ }
+ })
+ .detach();
+ self.nodes
+ .insert(id.clone(), NodeSlot::DatabaseExplorer(e.clone()));
+ e
+ }
+ };
+ AnyView::from(entity)
+ }
+
+ fn build_text_viewer(&mut self, id: NodeId, cx: &mut Context<Self>) -> AnyView {
+ let entity = match self.nodes.get(&id) {
+ Some(NodeSlot::TextViewer(e)) => e.clone(),
+ _ => {
+ let bus = self.bus.clone();
+ let e = cx.new(|cx| TextViewer::new(bus, cx));
+ self.nodes
+ .insert(id.clone(), NodeSlot::TextViewer(e.clone()));
+ e
+ }
+ };
+ AnyView::from(entity)
+ }
+
+ fn build_image_viewer(&mut self, id: NodeId, cx: &mut Context<Self>) -> AnyView {
+ let entity = match self.nodes.get(&id) {
+ Some(NodeSlot::ImageViewer(e)) => e.clone(),
+ _ => {
+ let bus = self.bus.clone();
+ let e = cx.new(|cx| ImageViewer::new(bus, cx));
+ self.nodes
+ .insert(id.clone(), NodeSlot::ImageViewer(e.clone()));
+ e
+ }
+ };
+ AnyView::from(entity)
+ }
+
+ fn build_status(&mut self, id: NodeId, cx: &mut Context<Self>) -> AnyView {
+ let entity = match self.nodes.get(&id) {
+ Some(NodeSlot::Status(e)) => e.clone(),
+ _ => {
+ let model = self.model.clone();
+ let e = cx.new(|cx| StatusPanel::new(model, cx));
+ self.nodes.insert(id.clone(), NodeSlot::Status(e.clone()));
+ e
+ }
+ };
+ AnyView::from(entity)
+ }
+
+ fn build_placeholder(
+ &mut self,
+ id: NodeId,
+ cfg: &LayerConfig,
+ cx: &mut Context<Self>,
+ ) -> AnyView {
+ // Si ya hay placeholder con esta id pero el kind cambió, lo
+ // recreamos para reflejar el nuevo `kind` en su mensaje.
+ let want_kind = cfg.kind.clone();
+ let create_new = match self.nodes.get(&id) {
+ Some(NodeSlot::Placeholder(e)) => {
+ let same_kind = e.read(cx).kind == want_kind;
+ !same_kind
+ }
+ _ => true,
+ };
+
+ if create_new {
+ let kind_clone = cfg.kind.clone();
+ let e = cx.new(|cx| PlaceholderView::new(kind_clone, cx));
+ self.nodes
+ .insert(id.clone(), NodeSlot::Placeholder(e.clone()));
+ return AnyView::from(e);
+ }
+
+ // Reuso.
+ if let Some(NodeSlot::Placeholder(e)) = self.nodes.get(&id) {
+ return AnyView::from(e.clone());
+ }
+ // Imposible llegar acá si la lógica de arriba está bien, pero
+ // mantenemos el fallback para no panicar en debug builds.
+ let kind_clone = cfg.kind.clone();
+ let e = cx.new(|cx| PlaceholderView::new(kind_clone, cx));
+ self.nodes.insert(id, NodeSlot::Placeholder(e.clone()));
+ AnyView::from(e)
+ }
+}
+
+impl Render for LayoutHost {
+ fn render(&mut self, _w: &mut Window, _cx: &mut Context<Self>) -> impl IntoElement {
+ // En Fase 3 el árbol se construyó en `new` y queda fijo. Si
+ // root_view es None (ej. config vacío + GC barrió todo), pintamos
+ // un placeholder neutro.
+ match self.root_view.clone() {
+ Some(v) => div().size_full().child(v),
+ None => div()
+ .size_full()
+ .child("(layout vacío — revisar layout.json)"),
+ }
+ }
+}
+
+// =====================================================================
+// PlaceholderView — kind no reconocido
+// =====================================================================
+
+/// View neutra que se instancia para cualquier `kind` que el LayoutHost no
+/// sepa construir. Renderea el `kind` y los params para que sea evidente
+/// qué falta implementar — útil mientras se desarrollan kinds nuevos
+/// (FileExplorer, Tabs, Tiled, etc.).
+pub struct PlaceholderView {
+ kind: String,
+}
+
+impl PlaceholderView {
+ pub fn new(kind: String, cx: &mut Context<Self>) -> Self {
+ cx.observe_global::<yahweh_theme::Theme>(|_, cx| cx.notify())
+ .detach();
+ Self { kind }
+ }
+}
+
+impl Render for PlaceholderView {
+ fn render(&mut self, _w: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
+ let theme = yahweh_theme::Theme::global(cx).clone();
+ div()
+ .size_full()
+ .bg(theme.bg_panel.clone())
+ .p(gpui::px(16.0))
+ .flex()
+ .flex_col()
+ .gap(gpui::px(6.0))
+ .child(
+ div()
+ .text_color(theme.accent)
+ .text_size(gpui::px(14.0))
+ .child(SharedString::from(format!("⟨ kind: {} ⟩", self.kind))),
+ )
+ .child(
+ div()
+ .text_color(theme.fg_muted)
+ .text_size(gpui::px(11.0))
+ .child("(placeholder — kind no implementado todavía)"),
+ )
+ }
+}
diff --git a/crates/apps/yahweh-shell/src/layout_model.rs b/crates/apps/yahweh-shell/src/layout_model.rs
new file mode 100644
index 0000000..3202b96
--- /dev/null
+++ b/crates/apps/yahweh-shell/src/layout_model.rs
@@ -0,0 +1,140 @@
+//! `LayoutModel` — fuente de verdad mutable del árbol de layout.
+//!
+//! Distinguimos dos clases de cambio:
+//!
+//! - [`LayoutModelEvent::StructureChanged`]: cambios que requieren rebuild
+//! del árbol de entidades (kind, children, params relevantes). Estos
+//! también invocan `cx.notify()` para que los `cx.observe` (StatusPanel,
+//! etc.) refresquen.
+//! - [`LayoutModelEvent::FlexChanged`]: actualización de `flex` de un
+//! nodo (típicamente proviene de un drag de divisor). NO requiere
+//! rebuild — el SplitContainer ya tiene el flex aplicado en su Vec; solo
+//! nos importa para persistir. Por eso no llamamos `cx.notify()`: solo
+//! emitimos el evento, así los `cx.observe` (que rebuilden) se mantienen
+//! silenciosos durante el drag.
+//!
+//! El `Persister` (ver `shell/persister.rs`) se subscribe vía
+//! `cx.subscribe` y reacciona a los dos.
+
+use gpui::{Context, EventEmitter};
+
+use yahweh_core::{LayerConfig, NodeId};
+
+#[derive(Clone, Debug)]
+pub enum LayoutModelEvent {
+ /// Estructural — kind / children / params. Triggerea rebuild en
+ /// `LayoutHost` y persist.
+ StructureChanged,
+ /// Solo flex de un nodo. Triggerea persist; NO rebuild.
+ FlexChanged,
+}
+
+pub struct LayoutModel {
+ tree: LayerConfig,
+}
+
+impl EventEmitter<LayoutModelEvent> for LayoutModel {}
+
+impl LayoutModel {
+ pub fn new(tree: LayerConfig) -> Self {
+ Self { tree }
+ }
+
+ pub fn tree(&self) -> &LayerConfig {
+ &self.tree
+ }
+
+ /// Reemplazo completo del árbol — para hot-reload del JSON.
+ pub fn replace_tree(&mut self, tree: LayerConfig, cx: &mut Context<Self>) {
+ self.tree = tree;
+ cx.emit(LayoutModelEvent::StructureChanged);
+ cx.notify();
+ }
+
+ /// Cambia el `kind` del nodo cuyo id JSON coincide con `target_id`.
+ pub fn set_kind(
+ &mut self,
+ target_id: &NodeId,
+ new_kind: &str,
+ cx: &mut Context<Self>,
+ ) {
+ let changed = mutate_node(&mut self.tree, target_id, &mut |node| {
+ if node.kind != new_kind {
+ node.kind = new_kind.to_string();
+ true
+ } else {
+ false
+ }
+ });
+ if changed {
+ cx.emit(LayoutModelEvent::StructureChanged);
+ cx.notify();
+ }
+ }
+
+ /// Setea el flex de un nodo. Solo emite `FlexChanged` (no notify) —
+ /// usado al final de un drag de divisor para persistir sin
+ /// triggerear rebuild.
+ pub fn set_flex(&mut self, target_id: &NodeId, flex: f32, cx: &mut Context<Self>) {
+ let new_val = Some(flex as f64);
+ let changed = mutate_node(&mut self.tree, target_id, &mut |node| {
+ if node.flex != new_val {
+ node.flex = new_val;
+ true
+ } else {
+ false
+ }
+ });
+ if changed {
+ cx.emit(LayoutModelEvent::FlexChanged);
+ }
+ }
+
+ /// Intercambia dos children del nodo `parent_id`. Triggerea
+ /// `StructureChanged` (rebuild + persist), porque cambia el orden de
+ /// instanciación. Si los índices son iguales o están out-of-bounds,
+ /// es no-op.
+ pub fn swap_children(
+ &mut self,
+ parent_id: &NodeId,
+ idx_a: usize,
+ idx_b: usize,
+ cx: &mut Context<Self>,
+ ) {
+ if idx_a == idx_b {
+ return;
+ }
+ let mut did_swap = false;
+ mutate_node(&mut self.tree, parent_id, &mut |node| {
+ if idx_a < node.children.len() && idx_b < node.children.len() {
+ node.children.swap(idx_a, idx_b);
+ did_swap = true;
+ true
+ } else {
+ false
+ }
+ });
+ if did_swap {
+ cx.emit(LayoutModelEvent::StructureChanged);
+ cx.notify();
+ }
+ }
+}
+
+fn mutate_node(
+ node: &mut LayerConfig,
+ target: &NodeId,
+ f: &mut impl FnMut(&mut LayerConfig) -> bool,
+) -> bool {
+ if let Some(id) = &node.id {
+ if id == target.as_str() {
+ return f(node);
+ }
+ }
+ for child in node.children.iter_mut() {
+ if mutate_node(child, target, f) {
+ return true;
+ }
+ }
+ false
+}
diff --git a/crates/apps/yahweh-shell/src/main.rs b/crates/apps/yahweh-shell/src/main.rs
new file mode 100644
index 0000000..9a31784
--- /dev/null
+++ b/crates/apps/yahweh-shell/src/main.rs
@@ -0,0 +1,63 @@
+//! Yahweh — bootstrap GPUI.
+//!
+//! Fase 6: además del LayoutModel, la Shell crea un `AppBus` (Entity) y se
+//! lo pasa al LayoutHost. El bus circula a viewers (TextViewer,
+//! ImageViewer) que se subscriben directo, y el LayoutHost forwardea los
+//! eventos tipados de los explorers (FileExplorer, DatabaseExplorer)
+//! traducidos a AppEvent.
+
+mod hot_reload;
+mod layout_host;
+mod layout_model;
+mod managed_tree;
+mod persister;
+mod status_panel;
+
+use gpui::{App, Application, Bounds, WindowBounds, WindowOptions, prelude::*, px, size};
+
+use yahweh_bus::AppBus;
+use yahweh_core::LayerConfig;
+use yahweh_theme::Theme;
+
+use crate::layout_host::LayoutHost;
+use crate::layout_model::LayoutModel;
+use crate::persister::Persister;
+
+const LAYOUT_PATH: &str = "layout.json";
+
+fn main() {
+ Application::new().run(|cx: &mut App| {
+ Theme::install_default(cx);
+
+ let config = LayerConfig::load_or_default(LAYOUT_PATH);
+ let bounds = Bounds::centered(None, size(px(1300.), px(800.)), cx);
+
+ cx.open_window(
+ WindowOptions {
+ window_bounds: Some(WindowBounds::Windowed(bounds)),
+ ..Default::default()
+ },
+ |_w, cx| {
+ let model = cx.new(|_| LayoutModel::new(config.clone()));
+ let bus = cx.new(|_| AppBus);
+ let persister = cx.new(|cx| {
+ Persister::new(LAYOUT_PATH.into(), model.clone(), cx)
+ });
+ // Hot-reload: notify watcher en el dir del JSON. El
+ // watcher debe mantenerse vivo (drop ⇒ stop), así que lo
+ // movemos a una static atómica vía Box::leak.
+ match hot_reload::spawn_watch(LAYOUT_PATH.into(), model.clone(), cx) {
+ Ok(watcher) => {
+ Box::leak(Box::new(watcher));
+ }
+ Err(e) => {
+ eprintln!("[hot_reload] no se pudo iniciar watcher: {}", e);
+ }
+ }
+ cx.new(|cx| LayoutHost::new(model, bus, persister, cx))
+ },
+ )
+ .unwrap();
+ cx.activate(true);
+ });
+}
diff --git a/crates/apps/yahweh-shell/src/managed_tree.rs b/crates/apps/yahweh-shell/src/managed_tree.rs
new file mode 100644
index 0000000..1d8e03d
--- /dev/null
+++ b/crates/apps/yahweh-shell/src/managed_tree.rs
@@ -0,0 +1,287 @@
+//! `ManagedTree` — wrapper de `TreeView` que aporta su propio modelo de
+//! datos + estado de expansión. En Fase 3 sirve como stub data-driven (los
+//! datasets se eligen vía param `dataset` del JSON). En Fase 4 este patrón
+//! se concretiza en `FileExplorer` (TreeView + FsProvider) y
+//! `DatabaseExplorer` (TreeView + SqliteProvider).
+//!
+//! La entidad es completamente Render-able y se entrega al LayoutHost como
+//! un AnyView. Los TreeView events (RowClicked, ChevronToggled, …) se
+//! traducen acá en cambios al estado de expansión y luego se re-emiten
+//! como `ManagedTreeEvent` para que el host (LayoutHost o un App-bus
+//! futuro) los consuma.
+
+use std::collections::HashSet;
+
+use gpui::{
+ Context, Entity, EventEmitter, IntoElement, Render, SharedString, Window, div, prelude::*,
+};
+
+use yahweh_widget_tree::{RowId, RowKind, TreeEvent, TreeRow, TreeView};
+
+// =====================================================================
+// Datasets stub (Fase 3). En Fase 4 los reemplazan los providers reales.
+// =====================================================================
+
+#[derive(Clone)]
+pub struct DemoNode {
+ pub id: &'static str,
+ pub label: &'static str,
+ pub icon: &'static str,
+ pub children: Vec<DemoNode>,
+}
+
+impl DemoNode {
+ fn leaf(id: &'static str, label: &'static str, icon: &'static str) -> Self {
+ Self { id, label, icon, children: vec![] }
+ }
+ fn branch(id: &'static str, label: &'static str, children: Vec<Self>) -> Self {
+ Self { id, label, icon: "📁", children }
+ }
+}
+
+/// Resuelve el dataset por `key` (proveniente del param `dataset` del JSON).
+/// Cualquier key desconocida cae al stub vacío para no romper el render.
+pub fn dataset_for(key: &str) -> DemoNode {
+ match key {
+ "sources" => yahweh_sources_tree(),
+ "deps" => yahweh_deps_tree(),
+ _ => DemoNode {
+ id: "unknown",
+ label: "(dataset desconocido)",
+ icon: "❓",
+ children: vec![],
+ },
+ }
+}
+
+fn yahweh_sources_tree() -> DemoNode {
+ DemoNode::branch(
+ "src-root",
+ "yahweh (src)",
+ vec![
+ DemoNode::branch(
+ "shell",
+ "shell",
+ vec![DemoNode::leaf("shell/main.rs", "main.rs", "📄")],
+ ),
+ DemoNode::branch(
+ "widgets",
+ "widgets",
+ vec![
+ DemoNode::branch(
+ "widgets/tree",
+ "tree",
+ vec![DemoNode::leaf("widgets/tree/lib.rs", "lib.rs", "📄")],
+ ),
+ DemoNode::branch(
+ "widgets/splitter",
+ "splitter",
+ vec![DemoNode::leaf("widgets/splitter/lib.rs", "lib.rs", "📄")],
+ ),
+ ],
+ ),
+ DemoNode::branch(
+ "libs",
+ "libs",
+ vec![
+ DemoNode::branch(
+ "libs/core",
+ "core",
+ vec![DemoNode::leaf("libs/core/lib.rs", "lib.rs", "📄")],
+ ),
+ DemoNode::branch(
+ "libs/theme",
+ "theme",
+ vec![DemoNode::leaf("libs/theme/lib.rs", "lib.rs", "📄")],
+ ),
+ DemoNode::branch(
+ "libs/providers",
+ "providers",
+ vec![
+ DemoNode::leaf("libs/providers/fs.rs", "fs.rs", "📄"),
+ DemoNode::leaf("libs/providers/sqlite.rs", "sqlite.rs", "📄"),
+ ],
+ ),
+ ],
+ ),
+ ],
+ )
+}
+
+fn yahweh_deps_tree() -> DemoNode {
+ fn branch(id: &'static str, label: &'static str, children: Vec<DemoNode>) -> DemoNode {
+ DemoNode { id, label, icon: "📦", children }
+ }
+ let leaf = DemoNode::leaf;
+ branch(
+ "deps-root",
+ "deps",
+ vec![
+ branch(
+ "ui",
+ "ui",
+ vec![
+ leaf("dep:gpui", "gpui 0.2.2", "🧊"),
+ leaf("dep:gpui-macros", "gpui-macros 0.2.2", "🧊"),
+ ],
+ ),
+ branch(
+ "async",
+ "async",
+ vec![
+ leaf("dep:tokio", "tokio 1.x", "🌀"),
+ leaf("dep:async-trait", "async-trait 0.1", "🌀"),
+ ],
+ ),
+ branch(
+ "data",
+ "data",
+ vec![
+ leaf("dep:serde", "serde 1", "🧬"),
+ leaf("dep:serde_json", "serde_json 1", "🧬"),
+ leaf("dep:rusqlite", "rusqlite 0.31", "🗃️"),
+ ],
+ ),
+ leaf("dep:notify", "notify 6.1", "👂"),
+ leaf("dep:uuid", "uuid 1", "🔗"),
+ ],
+ )
+}
+
+// =====================================================================
+// Eventos re-emitidos
+// =====================================================================
+
+/// Re-emitidos por ManagedTree después de procesar el evento bruto del
+/// TreeView interno. Contienen el `dataset_key` para que el host distinga
+/// entre múltiples ManagedTrees.
+///
+/// Los campos están marcados `dead_code`-ok porque en Fase 3 nadie se
+/// suscribe — el LayoutHost los va a consumir en Fase 4 vía un AppBus que
+/// reenvíe estos eventos a los viewers (TextViewer / ImageViewer / etc).
+#[derive(Clone, Debug)]
+#[allow(dead_code)]
+pub enum ManagedTreeEvent {
+ RowClicked { dataset: SharedString, id: String },
+ RowDoubleClicked { dataset: SharedString, id: String },
+ ContextMenu { dataset: SharedString, id: Option<String> },
+}
+
+// =====================================================================
+// Widget
+// =====================================================================
+
+pub struct ManagedTree {
+ view: Entity<TreeView>,
+ data: DemoNode,
+ expanded: HashSet<String>,
+ dataset_key: SharedString,
+}
+
+impl EventEmitter<ManagedTreeEvent> for ManagedTree {}
+
+impl ManagedTree {
+ pub fn new(
+ list_id: SharedString,
+ dataset_key: SharedString,
+ cx: &mut Context<Self>,
+ ) -> Self {
+ let view = cx.new(|cx| TreeView::new(list_id, cx));
+ cx.subscribe(&view, |this: &mut ManagedTree, _, ev, cx| {
+ this.on_tree_event(ev, cx);
+ })
+ .detach();
+
+ let data = dataset_for(&dataset_key);
+ let mut expanded = HashSet::new();
+ expanded.insert(data.id.to_string());
+
+ let me = Self {
+ view,
+ data,
+ expanded,
+ dataset_key,
+ };
+ me.push_rows(cx);
+ me
+ }
+
+ fn push_rows(&self, cx: &mut Context<Self>) {
+ let mut rows = Vec::new();
+ flatten(&self.data, 0, &self.expanded, &mut rows);
+ self.view.update(cx, |tree, cx| tree.set_rows(rows, cx));
+ }
+
+ fn on_tree_event(&mut self, event: &TreeEvent, cx: &mut Context<Self>) {
+ match event {
+ TreeEvent::ChevronToggled(id) => {
+ let key = id.as_str().to_string();
+ if !self.expanded.remove(&key) {
+ self.expanded.insert(key);
+ }
+ self.push_rows(cx);
+ }
+ TreeEvent::RowClicked(id) => {
+ cx.emit(ManagedTreeEvent::RowClicked {
+ dataset: self.dataset_key.clone(),
+ id: id.to_string(),
+ });
+ }
+ TreeEvent::RowDoubleClicked(id) => {
+ cx.emit(ManagedTreeEvent::RowDoubleClicked {
+ dataset: self.dataset_key.clone(),
+ id: id.to_string(),
+ });
+ }
+ TreeEvent::ContextMenuRequested { id, .. } => {
+ cx.emit(ManagedTreeEvent::ContextMenu {
+ dataset: self.dataset_key.clone(),
+ id: id.as_ref().map(|i| i.to_string()),
+ });
+ }
+ TreeEvent::ActiveChanged(_) => {}
+ }
+ }
+
+ /// Reservado para Fase 4: el LayoutHost lo va a consultar al
+ /// re-emitir eventos al bus.
+ #[allow(dead_code)]
+ pub fn dataset_key(&self) -> &str {
+ &self.dataset_key
+ }
+}
+
+impl Render for ManagedTree {
+ fn render(&mut self, _w: &mut Window, _cx: &mut Context<Self>) -> impl IntoElement {
+ div().size_full().child(self.view.clone())
+ }
+}
+
+// -------- helpers --------
+
+fn flatten(
+ node: &DemoNode,
+ depth: u32,
+ expanded: &HashSet<String>,
+ out: &mut Vec<TreeRow>,
+) {
+ let kind = if node.children.is_empty() {
+ RowKind::Leaf
+ } else {
+ RowKind::Branch
+ };
+ let is_expanded = expanded.contains(node.id);
+ out.push(TreeRow {
+ id: RowId::new(node.id),
+ label: node.label.to_string(),
+ depth,
+ kind,
+ expanded: is_expanded,
+ icon: Some(node.icon.to_string()),
+ });
+ if is_expanded {
+ for child in &node.children {
+ flatten(child, depth + 1, expanded, out);
+ }
+ }
+}
diff --git a/crates/apps/yahweh-shell/src/persister.rs b/crates/apps/yahweh-shell/src/persister.rs
new file mode 100644
index 0000000..0b9caa0
--- /dev/null
+++ b/crates/apps/yahweh-shell/src/persister.rs
@@ -0,0 +1,52 @@
+//! `Persister` — escribe el `LayoutModel` a disco en cada cambio.
+//!
+//! Es una entity sin estado visible (no se renderea). Solo existe para
+//! mantener viva la subscripción al `LayoutModel`. Cualquier evento
+//! (`StructureChanged` o `FlexChanged`) dispara una escritura sincrónica
+//! al `path` configurado.
+//!
+//! Hoy NO hay debounce — cada drag de divisor emite UN solo `FlexChanged`
+//! al final (en DragEnd, no por frame), y los swaps de kind son acción
+//! manual del usuario. Si en el futuro las escrituras se vuelven
+//! frecuentes, el lugar para sumar debounce es acá: spawn un task que
+//! coalesce events dentro de N ms.
+
+use std::path::PathBuf;
+
+use gpui::{Context, Entity};
+
+use crate::layout_model::{LayoutModel, LayoutModelEvent};
+
+pub struct Persister {
+ path: PathBuf,
+}
+
+impl Persister {
+ pub fn new(path: PathBuf, model: Entity<LayoutModel>, cx: &mut Context<Self>) -> Self {
+ cx.subscribe(&model, |this: &mut Persister, model, _ev: &LayoutModelEvent, cx| {
+ this.write(model.read(cx).tree());
+ })
+ .detach();
+ Self { path }
+ }
+
+ fn write(&self, tree: &yahweh_core::LayerConfig) {
+ let json = tree.serialize_json();
+ // Anti-loop: si el contenido en disco ya coincide, skip. Esto
+ // matters cuando el watcher está corriendo: persister write →
+ // notify modify → replace_tree → persister write → ... sin esto
+ // sería un loop infinito de syscalls.
+ if let Ok(existing) = std::fs::read_to_string(&self.path) {
+ if existing == json {
+ return;
+ }
+ }
+ if let Err(e) = std::fs::write(&self.path, json) {
+ eprintln!(
+ "[Persister] error escribiendo {}: {}",
+ self.path.display(),
+ e
+ );
+ }
+ }
+}
diff --git a/crates/apps/yahweh-shell/src/status_panel.rs b/crates/apps/yahweh-shell/src/status_panel.rs
new file mode 100644
index 0000000..73abbbe
--- /dev/null
+++ b/crates/apps/yahweh-shell/src/status_panel.rs
@@ -0,0 +1,343 @@
+//! `StatusPanel` — panel lateral con info de la app, switcher de tema y
+//! controles de swap del kind del contenedor objetivo (Fase 5).
+//!
+//! Recibe el `Entity<LayoutModel>` para mutarlo: cuando el usuario clickea
+//! "Tabs", el StatusPanel hace
+//! `model.update(cx, |m, cx| m.set_kind(target_id, "Tabs", cx))`. El
+//! LayoutHost está suscripto al model y rebuildea preservando los hijos
+//! del contenedor por NodeId — eso es lo que demuestra que swappear el
+//! contenedor no resetea el contenido (las pestañas activas, expansiones
+//! del FileExplorer, scroll position, todo se mantiene).
+
+use gpui::{
+ ClickEvent, Context, Entity, IntoElement, Render, SharedString, Window, div, prelude::*, px,
+};
+
+use yahweh_core::{LayerConfig, NodeId};
+use yahweh_theme::Theme;
+
+use crate::layout_model::LayoutModel;
+
+/// Id del contenedor que el StatusPanel controla con sus botones de swap.
+/// Hardcoded por ahora; en el futuro lo podríamos leer de un param del
+/// JSON (e.g. `target_id`) para que cualquier StatusPanel apunte al
+/// container que querramos.
+const SWAP_TARGET_ID: &str = "explorers";
+
+const SWAPPABLE_KINDS: &[&str] = &["Split", "Tabs", "Tiled"];
+
+/// Path del JSON que el botón "Reload" relee. Mantenemos consistencia con
+/// `main.rs` — si llegamos a parametrizarlo, hacerlo en un solo lugar.
+const LAYOUT_PATH: &str = "layout.json";
+
+pub struct StatusPanel {
+ model: Entity<LayoutModel>,
+ last_event: SharedString,
+}
+
+impl StatusPanel {
+ pub fn new(model: Entity<LayoutModel>, cx: &mut Context<Self>) -> Self {
+ cx.observe_global::<Theme>(|_, cx| cx.notify()).detach();
+ // Subscripción al model para refrescar el "kind activo" del swap.
+ cx.observe(&model, |_, _, cx| cx.notify()).detach();
+ Self {
+ model,
+ last_event: "(esperando bus app-level — Fase 6)".into(),
+ }
+ }
+
+ /// Reservado para Fase 6: el AppBus va a actualizar este texto.
+ #[allow(dead_code)]
+ pub fn set_status(&mut self, text: SharedString, cx: &mut Context<Self>) {
+ self.last_event = text;
+ cx.notify();
+ }
+
+ fn cycle_theme(&mut self, _: &ClickEvent, _: &mut Window, cx: &mut Context<Self>) {
+ let current = Theme::global(cx).name.to_string();
+ Theme::set(cx, Theme::next_after(¤t));
+ cx.notify();
+ }
+
+ fn pick_theme(
+ &mut self,
+ name: SharedString,
+ _: &ClickEvent,
+ _: &mut Window,
+ cx: &mut Context<Self>,
+ ) {
+ if let Some(theme) = Theme::by_name(&name) {
+ Theme::set(cx, theme);
+ cx.notify();
+ }
+ }
+
+ fn swap_container(
+ &mut self,
+ kind: SharedString,
+ _: &ClickEvent,
+ _: &mut Window,
+ cx: &mut Context<Self>,
+ ) {
+ let target = NodeId::new(SWAP_TARGET_ID);
+ self.model.update(cx, |m, cx| {
+ m.set_kind(&target, &kind, cx);
+ });
+ }
+
+ fn reload_from_disk(
+ &mut self,
+ _: &ClickEvent,
+ _: &mut Window,
+ cx: &mut Context<Self>,
+ ) {
+ // Releemos el JSON. Si el parsing falla, `load_or_default` cae al
+ // árbol default — no panicamos. La preservación de hijos
+ // funciona vía el id JSON: lo que matchee, persiste; lo nuevo se
+ // instancia.
+ let tree = LayerConfig::load_or_default(LAYOUT_PATH);
+ self.model.update(cx, |m, cx| m.replace_tree(tree, cx));
+ }
+
+ /// Lee el `kind` actual del contenedor objetivo desde el model. Si el
+ /// id no existe (alguien cambió el JSON), devuelve `None` y no
+ /// resaltamos ningún chip.
+ fn current_target_kind(&self, cx: &Context<Self>) -> Option<String> {
+ find_kind(self.model.read(cx).tree(), SWAP_TARGET_ID)
+ }
+}
+
+fn find_kind(node: &yahweh_core::LayerConfig, target: &str) -> Option<String> {
+ if let Some(id) = &node.id {
+ if id == target {
+ return Some(node.kind.clone());
+ }
+ }
+ for child in &node.children {
+ if let Some(k) = find_kind(child, target) {
+ return Some(k);
+ }
+ }
+ None
+}
+
+impl Render for StatusPanel {
+ fn render(&mut self, _w: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
+ let theme = Theme::global(cx).clone();
+ let active_theme = theme.name;
+ let theme_chips: Vec<_> = Theme::all()
+ .into_iter()
+ .map(|t| (t.name, t.name == active_theme))
+ .collect();
+
+ let current_kind = self.current_target_kind(cx);
+
+ // Theme chips.
+ let mut theme_row = div().flex().flex_row().flex_wrap().gap(px(6.0));
+ for (name, is_active) in theme_chips {
+ let bg = if is_active {
+ theme.bg_row_active
+ } else {
+ theme.bg_row_hover
+ };
+ let border = if is_active {
+ theme.accent_strong
+ } else {
+ theme.border
+ };
+ let chip_id = SharedString::from(format!("theme-chip-{}", name));
+ let chip_name = SharedString::from(name.to_string());
+ theme_row = theme_row.child(
+ div()
+ .id(chip_id)
+ .px(px(10.0))
+ .py(px(5.0))
+ .rounded(px(4.0))
+ .border_1()
+ .border_color(border)
+ .bg(bg)
+ .text_size(px(11.0))
+ .text_color(theme.fg_text)
+ .hover(|s| s.opacity(0.85))
+ .child(SharedString::from(name.to_string()))
+ .on_click(cx.listener(move |this, click, w, cx| {
+ this.pick_theme(chip_name.clone(), click, w, cx);
+ })),
+ );
+ }
+
+ // Swap chips — uno por kind (Split / Tabs / Tiled). El activo
+ // refleja el `kind` actual del nodo objetivo.
+ let mut swap_row = div().flex().flex_row().gap(px(6.0));
+ for &kind in SWAPPABLE_KINDS {
+ let is_active = current_kind.as_deref() == Some(kind);
+ let bg = if is_active {
+ theme.bg_row_active
+ } else {
+ theme.bg_row_hover
+ };
+ let border = if is_active {
+ theme.accent_strong
+ } else {
+ theme.border
+ };
+ let chip_id = SharedString::from(format!("swap-chip-{}", kind));
+ let kind_str = SharedString::from(kind.to_string());
+ swap_row = swap_row.child(
+ div()
+ .id(chip_id)
+ .px(px(12.0))
+ .py(px(6.0))
+ .rounded(px(4.0))
+ .border_1()
+ .border_color(border)
+ .bg(bg)
+ .text_size(px(12.0))
+ .text_color(theme.fg_text)
+ .hover(|s| s.opacity(0.85))
+ .child(SharedString::from(kind.to_string()))
+ .on_click(cx.listener(move |this, click, w, cx| {
+ this.swap_container(kind_str.clone(), click, w, cx);
+ })),
+ );
+ }
+
+ div()
+ .size_full()
+ .bg(theme.bg_panel_alt.clone())
+ .p(px(20.0))
+ .flex()
+ .flex_col()
+ .gap(px(14.0))
+ .child(
+ div()
+ .text_size(px(22.0))
+ .text_color(theme.accent_strong)
+ .child("Yahweh — Fase 5"),
+ )
+ .child(
+ div()
+ .text_color(theme.fg_muted)
+ .text_size(px(12.0))
+ .child("Contenedores intercambiables sin perder hijos."),
+ )
+ // ----- persistencia + reload -----
+ .child(
+ div()
+ .mt(px(14.0))
+ .text_color(theme.fg_muted)
+ .text_size(px(11.0))
+ .child("layout.json:"),
+ )
+ .child(
+ div()
+ .flex()
+ .flex_row()
+ .items_center()
+ .gap(px(8.0))
+ .child(
+ div()
+ .text_size(px(10.0))
+ .text_color(theme.fg_muted)
+ .child(
+ "auto-save al swap o al soltar un divisor.",
+ ),
+ )
+ .child(
+ div()
+ .id("reload-from-disk")
+ .px(px(10.0))
+ .py(px(4.0))
+ .rounded(px(4.0))
+ .border_1()
+ .border_color(theme.border_strong)
+ .bg(theme.bg_panel.clone())
+ .text_color(theme.fg_text)
+ .text_size(px(11.0))
+ .hover(|s| s.opacity(0.85))
+ .on_click(cx.listener(Self::reload_from_disk))
+ .child("⤓ reload"),
+ ),
+ )
+ // ----- swap del contenedor 'explorers' -----
+ .child(
+ div()
+ .mt(px(14.0))
+ .text_color(theme.fg_muted)
+ .text_size(px(11.0))
+ .child(SharedString::from(format!(
+ "contenedor '{}' — kind:",
+ SWAP_TARGET_ID
+ ))),
+ )
+ .child(swap_row)
+ .child(
+ div()
+ .mt(px(2.0))
+ .text_color(theme.fg_muted)
+ .text_size(px(10.0))
+ .child(
+ "click ⇒ swappea el kind del contenedor padre. Los hijos \
+ (FileExplorer, DatabaseExplorer) se preservan: cualquier \
+ folder expandido o entry seleccionado sigue así tras el swap.",
+ ),
+ )
+ // ----- log de evento (placeholder Fase 6) -----
+ .child(
+ div()
+ .mt(px(16.0))
+ .text_color(theme.fg_muted)
+ .text_size(px(11.0))
+ .child("último evento (bus Fase 6):"),
+ )
+ .child(
+ div()
+ .px(px(10.0))
+ .py(px(8.0))
+ .bg(theme.bg_panel.clone())
+ .border_1()
+ .border_color(theme.border)
+ .rounded(px(4.0))
+ .text_size(px(11.0))
+ .text_color(theme.fg_text)
+ .child(self.last_event.clone()),
+ )
+ // ----- theme switcher -----
+ .child(
+ div()
+ .mt(px(20.0))
+ .text_color(theme.fg_muted)
+ .text_size(px(11.0))
+ .child("tema activo:"),
+ )
+ .child(
+ div()
+ .flex()
+ .flex_row()
+ .items_center()
+ .gap(px(10.0))
+ .child(
+ div()
+ .text_color(theme.accent)
+ .text_size(px(15.0))
+ .child(SharedString::from(theme.name.to_string())),
+ )
+ .child(
+ div()
+ .id("cycle-theme")
+ .px(px(10.0))
+ .py(px(4.0))
+ .rounded(px(4.0))
+ .border_1()
+ .border_color(theme.border_strong)
+ .bg(theme.bg_panel.clone())
+ .text_color(theme.fg_text)
+ .text_size(px(11.0))
+ .hover(|s| s.opacity(0.85))
+ .on_click(cx.listener(Self::cycle_theme))
+ .child("⇄ siguiente"),
+ ),
+ )
+ .child(theme_row)
+ }
+}
diff --git a/crates/core/ente-binfmt-compat/Cargo.toml b/crates/core/ente-binfmt-compat/Cargo.toml
new file mode 100644
index 0000000..f972677
--- /dev/null
+++ b/crates/core/ente-binfmt-compat/Cargo.toml
@@ -0,0 +1,15 @@
+[package]
+name = "ente-binfmt-compat"
+version = "0.0.1"
+edition.workspace = true
+license.workspace = true
+publish.workspace = true
+
+[[bin]]
+name = "ente-binfmt-compat"
+path = "src/main.rs"
+
+[dependencies]
+anyhow = { workspace = true }
+tracing = { workspace = true }
+tracing-subscriber = { workspace = true }
diff --git a/crates/core/ente-binfmt-compat/src/main.rs b/crates/core/ente-binfmt-compat/src/main.rs
new file mode 100644
index 0000000..9789d5c
--- /dev/null
+++ b/crates/core/ente-binfmt-compat/src/main.rs
@@ -0,0 +1,109 @@
+//! ente-binfmt-compat: registra handlers de binfmt_misc al boot.
+//!
+//! systemd-binfmt lee `/usr/lib/binfmt.d/*.conf` y `/etc/binfmt.d/*.conf` y
+//! escribe cada línea al kernel via `/proc/sys/fs/binfmt_misc/register`.
+//! Esto habilita ejecución transparente de binarios no-ELF (qemu-user,
+//! wine, etc).
+//!
+//! Formato de cada línea:
+//! :<name>:<type>:<offset>:<magic>:<mask>:<interpreter>:<flags>
+//!
+//! Líneas que empiezan con `#` o vacías se ignoran.
+
+use std::fs;
+use std::io::Write;
+use std::path::Path;
+use tracing::{info, warn};
+use tracing_subscriber::EnvFilter;
+
+const REGISTER_PATH: &str = "/proc/sys/fs/binfmt_misc/register";
+const SEARCH_DIRS: &[&str] = &[
+ "/usr/lib/binfmt.d",
+ "/etc/binfmt.d",
+ "/run/binfmt.d",
+];
+
+fn main() {
+ init_tracing();
+ info!("ente-binfmt-compat: registrando handlers binfmt_misc");
+
+ if !Path::new(REGISTER_PATH).exists() {
+ warn!(path = REGISTER_PATH, "binfmt_misc no montado — skip");
+ std::process::exit(0);
+ }
+
+ let mut registered = 0;
+ let mut errors = 0;
+ let mut skipped = 0;
+
+ for dir in SEARCH_DIRS {
+ if !Path::new(dir).exists() { continue; }
+ let mut entries: Vec<_> = match fs::read_dir(dir) {
+ Ok(rd) => rd.filter_map(|e| e.ok()).collect(),
+ Err(_) => continue,
+ };
+ entries.sort_by_key(|e| e.file_name());
+ for entry in entries {
+ let path = entry.path();
+ if path.extension().map(|e| e != "conf").unwrap_or(true) { continue; }
+ let content = match fs::read_to_string(&path) {
+ Ok(c) => c,
+ Err(e) => { warn!(?e, path = %path.display(), "read"); continue; }
+ };
+ for line in content.lines() {
+ let line = line.trim();
+ if line.is_empty() || line.starts_with('#') { continue; }
+ match register(line) {
+ Ok(name) => {
+ info!(file = %path.display(), %name, "binfmt registrado");
+ registered += 1;
+ }
+ Err(e) => {
+ if e.is_already_exists() {
+ skipped += 1;
+ } else {
+ warn!(?e, file = %path.display(), "registro falló");
+ errors += 1;
+ }
+ }
+ }
+ }
+ }
+ }
+ info!(registered, skipped, errors, "binfmt aplicado");
+ if errors > 0 { std::process::exit(1); }
+}
+
+#[derive(Debug)]
+struct RegError(std::io::Error);
+impl std::fmt::Display for RegError {
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { write!(f, "{}", self.0) }
+}
+impl RegError {
+ fn is_already_exists(&self) -> bool {
+ // EEXIST = 17 en Linux.
+ self.0.raw_os_error() == Some(17)
+ }
+}
+
+/// Escribe la línea al register file. Devuelve el `name` extraído del
+/// primer campo (entre `:` separators) si tuvo éxito.
+fn register(line: &str) -> Result<String, RegError> {
+ // Sintaxis: :<name>:<type>:<offset>:<magic>:<mask>:<interpreter>:<flags>
+ // Field 0 (después del ':' inicial) es el name.
+ let name = line.split(':').nth(1)
+ .map(|s| s.to_string())
+ .unwrap_or_else(|| "?".into());
+ let mut f = fs::OpenOptions::new()
+ .write(true)
+ .open(REGISTER_PATH)
+ .map_err(RegError)?;
+ f.write_all(line.as_bytes()).map_err(RegError)?;
+ Ok(name)
+}
+
+fn init_tracing() {
+ let filter = EnvFilter::try_from_default_env()
+ .unwrap_or_else(|_| EnvFilter::new("ente_binfmt_compat=info"));
+ tracing_subscriber::fmt().with_env_filter(filter).with_target(true).init();
+}
diff --git a/crates/core/ente-brain/Cargo.toml b/crates/core/ente-brain/Cargo.toml
new file mode 100644
index 0000000..0a6958c
--- /dev/null
+++ b/crates/core/ente-brain/Cargo.toml
@@ -0,0 +1,23 @@
+[package]
+name = "ente-brain"
+version = "0.0.1"
+edition.workspace = true
+license.workspace = true
+publish.workspace = true
+
+[dependencies]
+ente-card = { path = "../ente-card" }
+ente-cas = { path = "../ente-cas" }
+serde = { workspace = true }
+serde_json = { workspace = true }
+ulid = { workspace = true }
+tokio = { workspace = true }
+bincode = { workspace = true }
+base64 = { workspace = true }
+postcard = { workspace = true }
+anyhow = { workspace = true }
+tracing = { workspace = true }
+
+[[example]]
+name = "brainctl"
+path = "examples/brainctl.rs"
diff --git a/crates/core/ente-brain/examples/brainctl.rs b/crates/core/ente-brain/examples/brainctl.rs
new file mode 100644
index 0000000..5b051b1
--- /dev/null
+++ b/crates/core/ente-brain/examples/brainctl.rs
@@ -0,0 +1,234 @@
+//! brainctl: cliente CLI del introspect API.
+//!
+//! Uso:
+//! cargo run --example brainctl -p ente-brain -- list-rules
+//! cargo run --example brainctl -p ente-brain -- entropy
+//! cargo run --example brainctl -p ente-brain -- top 10
+//! cargo run --example brainctl -p ente-brain -- crystals
+//! cargo run --example brainctl -p ente-brain -- crystal-json 0
+//!
+//! Path del socket: $ENTE_BRAIN_SOCK o $XDG_RUNTIME_DIR/ente-brain.sock
+
+use ente_brain::introspect::{call, IntrospectRequest, IntrospectResponse};
+use std::path::{Path, PathBuf};
+use tokio::io::{AsyncReadExt, AsyncWriteExt};
+use tokio::net::UnixStream;
+
+fn socket_path() -> PathBuf {
+ if let Ok(p) = std::env::var("ENTE_BRAIN_SOCK") {
+ return p.into();
+ }
+ let runtime = std::env::var("XDG_RUNTIME_DIR")
+ .unwrap_or_else(|_| std::env::var("TMPDIR").unwrap_or_else(|_| "/tmp".into()));
+ format!("{runtime}/ente-brain.sock").into()
+}
+
+#[tokio::main(flavor = "current_thread")]
+async fn main() -> anyhow::Result<()> {
+ let args: Vec<String> = std::env::args().collect();
+ let cmd = args.get(1).map(|s| s.as_str()).unwrap_or("entropy");
+
+ // Comando especial: streaming. Mantiene la conn abierta y lee frames
+ // hasta Ctrl-C o EOF del servidor.
+ if cmd == "stream-audit" || cmd == "stream" {
+ return run_stream_audit(socket_path()).await;
+ }
+
+ let req = match cmd {
+ "list-rules" | "rules" => IntrospectRequest::ListRules,
+ "entropy" => IntrospectRequest::EntropySnapshot,
+ "top" => {
+ let n: usize = args.get(2).and_then(|s| s.parse().ok()).unwrap_or(10);
+ IntrospectRequest::TopCorrelations { n }
+ }
+ "crystals" => IntrospectRequest::Crystals,
+ "crystal-json" => {
+ let i: usize = args.get(2).and_then(|s| s.parse().ok()).unwrap_or(0);
+ IntrospectRequest::CrystalJson { index: i }
+ }
+ "promote" => {
+ let i: usize = args.get(2).and_then(|s| s.parse().ok()).unwrap_or(0);
+ IntrospectRequest::PromoteCrystal { index: i }
+ }
+ "remove" => {
+ let id_s = args.get(2).ok_or_else(|| anyhow::anyhow!("se requiere <ulid>"))?;
+ let id: ulid::Ulid = id_s.parse()?;
+ IntrospectRequest::RemoveRule { id }
+ }
+ "audit" => {
+ let limit: usize = args.get(2).and_then(|s| s.parse().ok()).unwrap_or(20);
+ IntrospectRequest::ListAudit { limit }
+ }
+ "flush-audit" => IntrospectRequest::FlushAudit,
+ "audit-verify" | "verify" => IntrospectRequest::VerifyAudit,
+ "replay" => IntrospectRequest::ReplayAudit,
+ "gc-cas" => IntrospectRequest::GcCas { extra_roots: Vec::new() },
+ "patterns" => IntrospectRequest::PatternCrystals,
+ "reload" => {
+ let path = args.get(2).cloned();
+ IntrospectRequest::ReloadRules { path }
+ }
+ other => {
+ eprintln!("subcomando desconocido: {other}");
+ eprintln!("válidos: list-rules | entropy | top <n> | crystals | crystal-json <i> | promote <i> | remove <ulid> | audit <limit> | flush-audit | reload [path]");
+ std::process::exit(2);
+ }
+ };
+
+ let path = socket_path();
+ let resp = call(&path, req).await?;
+ print_response(&resp);
+ Ok(())
+}
+
+fn print_response(r: &IntrospectResponse) {
+ match r {
+ IntrospectResponse::Rules(rs) => {
+ println!("{} reglas vivas:", rs.len());
+ for r in rs {
+ println!(" {} prio={} kind={} actions={} wildcard={}",
+ r.id, r.priority, r.event_kind_tag, r.action_count, r.scope_wildcard);
+ }
+ }
+ IntrospectResponse::Rule(rule) => match rule {
+ Some(r) => println!("{r:#?}"),
+ None => println!("regla no encontrada"),
+ },
+ IntrospectResponse::Entropy { value_bits, sample_size, distinct_kinds, window_full } => {
+ println!("Shannon entropy : {value_bits:.4} bits");
+ println!("Sample size : {sample_size}");
+ println!("Distinct kinds : {distinct_kinds}");
+ println!("Window full : {window_full}");
+ }
+ IntrospectResponse::Correlations(entries) => {
+ println!("{} pares (top, ordenado por co-ocurrencia):", entries.len());
+ for e in entries {
+ println!(" n={:>4} P(b|a)={:.3} PMI={:>6.3}b {} → {}",
+ e.joint_count, e.conditional_prob, e.pmi_bits, e.a, e.b);
+ }
+ }
+ IntrospectResponse::Crystals(cs) => {
+ println!("{} cristales detectados:", cs.len());
+ for (i, c) in cs.iter().enumerate() {
+ println!(" [{i}] {:?} → {:?} P={:.3} PMI={:.3}b n={}",
+ c.antecedent, c.consequent, c.conditional_prob, c.pmi, c.support);
+ }
+ }
+ IntrospectResponse::Json(s) => println!("{s}"),
+ IntrospectResponse::Promoted { rule_id, rule_json } => {
+ println!("regla creada: {rule_id}");
+ println!("--- JSON para auditoría / persistencia ---");
+ println!("{rule_json}");
+ }
+ IntrospectResponse::Removed(was_present) => {
+ if *was_present { println!("regla eliminada"); }
+ else { println!("regla no encontrada"); }
+ }
+ IntrospectResponse::AuditEntries(entries) => {
+ println!("{} entries de audit log:", entries.len());
+ for e in entries {
+ let prev = e.prev_sha.map(hex_short).unwrap_or_else(|| "—".into());
+ let sha = hex_short(e.sha);
+ println!(" seq={:>4} t={} prev={} sha={} {:?}",
+ e.seq, e.timestamp_ms, prev, sha, e.action);
+ }
+ }
+ IntrospectResponse::Flushed { written, head_sha, total_flushed } => {
+ println!("flushed: {written} entries esta pasada, total acumulado: {total_flushed}");
+ if let Some(sha) = head_sha {
+ println!("head sha: {}", hex_long(*sha));
+ }
+ }
+ IntrospectResponse::Reloaded { count } => {
+ println!("reload OK: {count} reglas activas tras reload");
+ }
+ IntrospectResponse::Replayed(rep) => {
+ if let Some(e) = &rep.error {
+ println!("✗ replay falló: {e}");
+ } else {
+ println!("✓ replay completo — {} actions aplicadas, {} reglas finales",
+ rep.applied, rep.final_rule_count);
+ }
+ }
+ IntrospectResponse::AuditVerified(rep) => {
+ if let Some(seq) = rep.broken_at_seq {
+ println!("✗ verificación FALLÓ tras seq={seq}");
+ if let Some(e) = &rep.error { println!(" motivo: {e}"); }
+ println!(" entries verificadas: {}", rep.verified);
+ } else {
+ println!("✓ chain verificada — {} entries íntegras", rep.verified);
+ if let Some(g) = rep.genesis_sha { println!(" genesis: {}", hex_long(g)); }
+ }
+ }
+ IntrospectResponse::Patterns(ps) => {
+ println!("{} cristales pattern detectados:", ps.len());
+ for p in ps {
+ match p {
+ ente_brain::crystallize::PatternCrystal::Burst { kind, count, frequency_per_sec } => {
+ println!(" burst: {kind:?} count={count} freq={frequency_per_sec:.2} Hz");
+ }
+ ente_brain::crystallize::PatternCrystal::Silence { kind, last_count, since_secs } => {
+ println!(" silence: {kind:?} last_count={last_count} ausente={since_secs:.1}s");
+ }
+ }
+ }
+ }
+ IntrospectResponse::GcResult { deleted, freed_bytes } => {
+ println!("CAS gc: {deleted} blobs eliminados, {freed_bytes} bytes liberados");
+ }
+ IntrospectResponse::AuditStreamFrame(_) => {
+ // En modo request/response no debería llegar; solo aparece en
+ // run_stream_audit. Si llega aquí es un bug del servidor.
+ eprintln!("frame de stream recibido fuera de stream-audit (bug)");
+ }
+ IntrospectResponse::Error(e) => eprintln!("error: {e}"),
+ }
+}
+
+fn hex_short(sha: [u8; 32]) -> String {
+ sha[..4].iter().map(|b| format!("{:02x}", b)).collect::<String>() + ".."
+}
+
+fn hex_long(sha: [u8; 32]) -> String {
+ sha.iter().map(|b| format!("{:02x}", b)).collect()
+}
+
+async fn run_stream_audit(path: PathBuf) -> anyhow::Result<()> {
+ let mut stream = UnixStream::connect(&path).await?;
+ let req = IntrospectRequest::StreamAudit;
+ let buf = bincode::serialize(&req)?;
+ stream.write_u32(buf.len() as u32).await?;
+ stream.write_all(&buf).await?;
+ eprintln!("audit stream conectado a {} — Ctrl-C para salir", path.display());
+
+ loop {
+ let mut len_buf = [0u8; 4];
+ if stream.read_exact(&mut len_buf).await.is_err() {
+ eprintln!("\nstream cerrado por el servidor");
+ return Ok(());
+ }
+ let len = u32::from_be_bytes(len_buf) as usize;
+ if len > 4 * 1024 * 1024 { anyhow::bail!("frame oversize"); }
+ let mut buf = vec![0u8; len];
+ stream.read_exact(&mut buf).await?;
+ let resp: IntrospectResponse = bincode::deserialize(&buf)?;
+ match resp {
+ IntrospectResponse::AuditStreamFrame(entry) => {
+ let prev = entry.prev_sha
+ .map(|s| s[..4].iter().map(|b| format!("{:02x}", b)).collect::<String>() + "..")
+ .unwrap_or_else(|| "—".into());
+ let sha = entry.sha[..4].iter().map(|b| format!("{:02x}", b))
+ .collect::<String>() + "..";
+ println!("[stream] seq={} prev={} sha={} {:?}",
+ entry.seq, prev, sha, entry.action);
+ }
+ other => {
+ eprintln!("frame no esperado en stream: {other:?}");
+ return Ok(());
+ }
+ }
+ }
+}
+
+#[allow(dead_code)]
+fn _suppress(_: &Path) {} // mantener Path import si compilador se queja
diff --git a/crates/core/ente-brain/schema/rule.k b/crates/core/ente-brain/schema/rule.k
new file mode 100644
index 0000000..432cde5
--- /dev/null
+++ b/crates/core/ente-brain/schema/rule.k
@@ -0,0 +1,167 @@
+# ============================================================================
+# rule.k — REFERENCE ONLY. NOT LOADED.
+#
+# La gramática autoritativa de Rule vive en Rust:
+# crates/ente-brain/src/rules.rs
+# El loader (crates/ente-brain/src/loader.rs) sólo acepta JSON / JSONL.
+#
+# Conservado como notas de diseño humano-legibles del shape Rule:
+# Triplet [Sujeto + Evento + Acción(Objeto)]. Cada regla es una sinapsis:
+# cuando ocurre `when`, el motor ejecuta `then` para los Entes que cumplen
+# `scope`. El motor las indexa por discriminante de EventKind para lookup
+# en O(1). Las reglas son inmutables tras carga (Arc<Rule>).
+#
+# Si cambias el shape en Rust, sincroniza este archivo a mano (o
+# reemplázalo por JSON Schema generado vía `schemars`).
+# ============================================================================
+
+schema Rule:
+ """Una sinapsis del fractal. Determinista, sin estado entre disparos."""
+ id: str # Ulid 26 chars
+ priority: int = 5 # 0..255, mayor = se ejecuta primero
+ when: EventPattern
+ then: [Action]
+ scope: Scope = Scope {} # qué Entes son sujetos válidos
+
+ check:
+ len(id) == 26, "id debe ser Ulid"
+ priority >= 0 and priority <= 255, "priority fuera de rango"
+ len(then) > 0, "regla sin acciones"
+
+
+# ---------- Subject: alcance del sujeto ----------
+
+schema Scope:
+ """Match del sujeto. None en todos los campos = match cualquier Ente."""
+ subject_id?: str # Ulid exacto
+ subject_label?: str # label exacto
+ subject_has_cap?: Capability # Ente que declara esta capacidad
+
+ check:
+ subject_id is None or len(subject_id) == 26, "subject_id no es Ulid"
+
+
+# ---------- Event: qué dispara la regla ----------
+
+# EventPattern es tagged union recursivo.
+#
+# Atómicos:
+# Single — match un evento por kind
+# Sequence — N eventos consecutivos dentro de within_ms
+#
+# Compuestos (recursivos):
+# Either — OR sobre sub-patterns
+# All — AND sobre sub-patterns (mismo event/history)
+schema EventPattern:
+ type: "Single" | "Sequence" | "Either" | "All"
+ kind?: EventKind # Single
+ kinds?: [EventKind] # Sequence
+ within_ms?: int = 0
+ patterns?: [EventPattern] # Either / All (recursivo)
+
+ check:
+ type != "Single" or kind is not None, "Single requiere kind"
+ type != "Sequence" or (kinds is not None and len(kinds) > 0), \
+ "Sequence requiere kinds no vacío"
+ type != "Either" or (patterns is not None and len(patterns) > 0), \
+ "Either requiere patterns no vacío"
+ type != "All" or (patterns is not None and len(patterns) > 0), \
+ "All requiere patterns no vacío"
+ within_ms is None or within_ms >= 0, "within_ms negativo"
+
+
+# EventKind con tag interno + payload opcional según tag.
+schema EventKind:
+ tag: "EnteSpawned" | "EnteDied" | "BusAnnounce" | "BusInvoke" | "BusInvokeOf" | "DeviceAdded" | "DeviceRemoved" | "Custom"
+ cap?: Capability # para BusInvokeOf
+ custom?: str # para Custom
+
+ check:
+ tag != "BusInvokeOf" or cap is not None, "BusInvokeOf requiere cap"
+ tag != "Custom" or custom is not None, "Custom requiere custom string"
+
+
+# ---------- Action: qué hacer ----------
+
+schema Action:
+ """Una acción ejecutable por el motor. Tagged union con kind."""
+ kind: "Log" | "Notify" | "Spawn" | "Invoke" | "Inhibit"
+ # Log
+ level?: "trace" | "debug" | "info" | "warn" | "error"
+ message?: str
+ # Notify
+ target_id?: str # Ulid
+ # Spawn
+ card_blob?: str # base64-encoded EntityCard JSON
+ # Invoke
+ target_cap?: Capability
+ blob_b64?: str
+ # Inhibit
+ reason?: str
+
+ check:
+ kind != "Log" or message is not None, "Log requiere message"
+ kind != "Notify" or (target_id is not None and message is not None), \
+ "Notify requiere target_id + message"
+ kind != "Spawn" or card_blob is not None, "Spawn requiere card_blob"
+ kind != "Invoke" or target_cap is not None, "Invoke requiere target_cap"
+ kind != "Inhibit" or reason is not None, "Inhibit requiere reason"
+
+
+# ---------- Capability: re-export desde card.k para evitar inclusión circular ----------
+
+# En uso real: `import ..ente_card.schema.card` y referencia Capability.
+# Aquí declaramos una versión alineada para auto-contención del esquema.
+schema Capability:
+ kind: "FilesystemRoot" | "KernelNetlink" | "Endpoint" | "LegacyLogind" | "Device" | "Spawn" | "Journal"
+ netlink_family?: "Uevent" | "Route" | "Generic" | "Audit"
+ endpoint_interface?: str
+ endpoint_version?: int
+ device_class?: "Block" | "Tty" | "Input" | "Drm" | "Net" | "Hidraw"
+
+
+# ============================================================================
+# Ejemplo de regla cristalizada (auto-generada por el observador)
+# ============================================================================
+
+example_rule = Rule {
+ id = "01KQQ100000000000000000000"
+ priority = 5
+ when = EventPattern {
+ type = "Single"
+ kind = EventKind {tag = "EnteSpawned"}
+ }
+ scope = Scope {
+ subject_label = "demo-echo"
+ }
+ then = [
+ Action {
+ kind = "Log"
+ level = "info"
+ message = "demo-echo encarnado, observando para crystallization"
+ }
+ ]
+}
+
+# Ejemplo de regla compuesta: cuando un Ente se anuncia y luego es invocado
+# en menos de 500ms, log estructurado para auditoría.
+example_sequence = Rule {
+ id = "01KQQ200000000000000000000"
+ priority = 7
+ when = EventPattern {
+ type = "Sequence"
+ kinds = [
+ EventKind {tag = "BusAnnounce"}
+ EventKind {tag = "BusInvoke"}
+ ]
+ within_ms = 500
+ }
+ scope = Scope {}
+ then = [
+ Action {
+ kind = "Log"
+ level = "info"
+ message = "patrón Announce→Invoke detectado <500ms"
+ }
+ ]
+}
diff --git a/crates/core/ente-brain/src/audit.rs b/crates/core/ente-brain/src/audit.rs
new file mode 100644
index 0000000..a95e80f
--- /dev/null
+++ b/crates/core/ente-brain/src/audit.rs
@@ -0,0 +1,550 @@
+//! Audit log: cada acción mutadora del cerebro deja una entry inmutable
+//! con su predecesor encadenado por SHA256 (estilo Merkle). Verificable a
+//! posteriori sin confianza en quien escribe.
+//!
+//! Los entries viven en memoria. Para persistencia, `flush_to_cas()` los
+//! escribe al content-addressable store y devuelve el SHA del head, que
+//! puede guardarse en un archivo de "head pointer" (fuera de scope aquí).
+
+use crate::crystallize::Crystal;
+use serde::{Deserialize, Serialize};
+use std::collections::VecDeque;
+use ulid::Ulid;
+
+#[derive(Debug, Clone, Serialize, Deserialize)]
+pub struct AuditEntry {
+ /// Sequence number monotónico desde el inicio del log.
+ pub seq: u64,
+ /// Wall-clock al insertar.
+ pub timestamp_ms: u64,
+ /// SHA256 del entry anterior. None para el primer entry.
+ pub prev_sha: Option<[u8; 32]>,
+ /// SHA256 de este entry (auto-calculado al construir).
+ pub sha: [u8; 32],
+ /// Acción registrada.
+ pub action: AuditAction,
+}
+
+/// Sin `#[serde(tag)]`: bincode requiere external tagging (default serde
+/// para enums) para no usar `deserialize_any`. JSON sigue legible.
+#[derive(Debug, Clone, Serialize, Deserialize)]
+pub enum AuditAction {
+ PromoteCrystal { rule_id: Ulid, crystal: Crystal },
+ RemoveRule { rule_id: Ulid },
+ LoadRulesFile { path: String, count: usize },
+}
+
+pub struct AuditLog {
+ entries: VecDeque<AuditEntry>,
+ next_seq: u64,
+ /// Cap del log en memoria. Entries más viejos se descartan tras flush.
+ cap: usize,
+ /// Total acumulado de entries flusheadas a CAS.
+ flushed_count: u64,
+ /// SHA del último entry persistido a CAS — el "head pointer" del log.
+ last_flushed_sha: Option<[u8; 32]>,
+ /// Path opcional donde escribir el head pointer tras cada flush.
+ head_pointer_path: Option<std::path::PathBuf>,
+ /// Subscribers a entries en tiempo real. Cada `append` empuja a todos.
+ /// Subscribers cuyo receiver se dropeó se purgan en el siguiente push.
+ subscribers: Vec<tokio::sync::mpsc::UnboundedSender<AuditEntry>>,
+ /// Wall-clock del último flush exitoso a CAS. None si aún no se flush.
+ last_flush_at_ms: Option<u64>,
+}
+
+impl AuditLog {
+ pub fn new() -> Self {
+ Self::with_cap(512)
+ }
+
+ pub fn with_cap(cap: usize) -> Self {
+ Self {
+ entries: VecDeque::new(),
+ next_seq: 0,
+ cap,
+ flushed_count: 0,
+ last_flushed_sha: None,
+ head_pointer_path: None,
+ subscribers: Vec::new(),
+ last_flush_at_ms: None,
+ }
+ }
+
+ /// Registra un nuevo subscriber. El receiver recibe cada `AuditEntry`
+ /// futuro hasta que el receiver se dropee (subscriber se purga al
+ /// siguiente `append`).
+ pub fn subscribe(&mut self) -> tokio::sync::mpsc::UnboundedReceiver<AuditEntry> {
+ let (tx, rx) = tokio::sync::mpsc::unbounded_channel();
+ self.subscribers.push(tx);
+ rx
+ }
+
+ pub fn subscriber_count(&self) -> usize { self.subscribers.len() }
+
+ pub fn with_head_pointer(mut self, path: std::path::PathBuf) -> Self {
+ self.head_pointer_path = Some(path);
+ self
+ }
+
+ /// Apendea una acción. Calcula el SHA encadenado contra el último entry.
+ pub fn append(&mut self, action: AuditAction) -> AuditEntry {
+ let prev_sha = self.entries.back().map(|e| e.sha);
+ let timestamp_ms = now_ms();
+ let seq = self.next_seq;
+ self.next_seq += 1;
+
+ // Pre-construct con sha en cero, luego calcular sha sobre el
+ // serializado canónico, luego sobreescribir el campo.
+ let mut entry = AuditEntry {
+ seq, timestamp_ms, prev_sha, sha: [0u8; 32], action,
+ };
+ entry.sha = compute_sha(&entry);
+
+ if self.entries.len() >= self.cap {
+ self.entries.pop_front();
+ }
+ self.entries.push_back(entry.clone());
+ // Empujar a subscribers, purgando los muertos in-place.
+ self.subscribers.retain(|tx| tx.send(entry.clone()).is_ok());
+ entry
+ }
+
+ pub fn recent(&self, limit: usize) -> impl Iterator<Item = &AuditEntry> {
+ let n = if limit == 0 { self.entries.len() } else { limit.min(self.entries.len()) };
+ self.entries.iter().skip(self.entries.len() - n)
+ }
+
+ pub fn len(&self) -> usize { self.entries.len() }
+ pub fn is_empty(&self) -> bool { self.entries.is_empty() }
+
+ pub fn head_sha(&self) -> Option<[u8; 32]> {
+ self.entries.back().map(|e| e.sha)
+ }
+
+ /// Persiste el entry pasado al CAS y devuelve su SHA. Pensado para
+ /// snapshots externos — el log en memoria sigue intacto.
+ pub fn persist_to_cas(entry: &AuditEntry) -> anyhow::Result<[u8; 32]> {
+ let bytes = serde_json::to_vec(entry)?;
+ let sha = ente_cas::store(&bytes)?;
+ Ok(sha)
+ }
+
+ /// Persiste TODOS los entries actuales al CAS y actualiza el head pointer.
+ /// Idempotente: re-flushar dos veces da los mismos SHAs (CAS dedup).
+ /// Devuelve cuántas entries se flushearon en esta pasada.
+ ///
+ /// Forma canónica: serializamos `entry` con `sha = [0; 32]` (formato
+ /// pre-hash). El CAS computa sha256 sobre esos bytes y devuelve un SHA
+ /// que por construcción coincide con `entry.sha` calculado al append.
+ pub fn flush_to_cas(&mut self) -> anyhow::Result<usize> {
+ let mut written = 0;
+ let mut last_sha = self.last_flushed_sha;
+ for entry in &self.entries {
+ if entry.seq < self.flushed_count { continue; }
+ let bytes = canonical_bytes(entry);
+ let sha = ente_cas::store(&bytes)?;
+ debug_assert_eq!(sha, entry.sha,
+ "CAS sha != entry.sha — fórmula canónica rota");
+ last_sha = Some(sha);
+ written += 1;
+ }
+ self.flushed_count += written as u64;
+ self.last_flushed_sha = last_sha;
+ if written > 0 {
+ self.last_flush_at_ms = Some(now_ms());
+ }
+ // Persistir head pointer si está configurado.
+ if let (Some(path), Some(sha)) = (&self.head_pointer_path, last_sha) {
+ let pointer = AuditHeadPointer {
+ last_seq: self.next_seq.saturating_sub(1),
+ last_sha: sha,
+ flushed_count: self.flushed_count,
+ timestamp_ms: now_ms(),
+ };
+ let json = serde_json::to_vec_pretty(&pointer)?;
+ // Escritura atómica: tmp + rename
+ let tmp = path.with_extension("tmp");
+ if let Some(parent) = path.parent() { let _ = std::fs::create_dir_all(parent); }
+ std::fs::write(&tmp, json)?;
+ std::fs::rename(&tmp, path)?;
+ }
+ Ok(written)
+ }
+
+ pub fn flushed_count(&self) -> u64 { self.flushed_count }
+ pub fn last_flushed_sha(&self) -> Option<[u8; 32]> { self.last_flushed_sha }
+ pub fn last_flush_at_ms(&self) -> Option<u64> { self.last_flush_at_ms }
+
+ /// Segundos transcurridos desde el último flush. None si nunca se flush.
+ pub fn last_flush_age_secs(&self) -> Option<f64> {
+ let then = self.last_flush_at_ms?;
+ let now = now_ms();
+ Some((now.saturating_sub(then)) as f64 / 1000.0)
+ }
+}
+
+/// Pointer al head del audit log — escrito atómicamente en disco tras cada
+/// flush. Permite verificar la integridad del log sin escanearlo entero:
+/// el cliente lee el head, recupera el blob desde CAS, valida `prev_sha`
+/// recursivamente hasta el genesis.
+#[derive(Debug, Clone, Serialize, Deserialize)]
+pub struct AuditHeadPointer {
+ pub last_seq: u64,
+ pub last_sha: [u8; 32],
+ pub flushed_count: u64,
+ pub timestamp_ms: u64,
+}
+
+/// Reporte de un replay: número de actions aplicadas + reglas finales.
+#[derive(Debug, Clone, Serialize, Deserialize)]
+pub struct ReplayReport {
+ pub applied: u64,
+ pub final_rule_count: usize,
+ pub error: Option<String>,
+}
+
+/// Reporte de verificación de la cadena audit.
+#[derive(Debug, Clone, Serialize, Deserialize)]
+pub struct VerificationReport {
+ /// Cuántas entries se recorrieron y verificaron exitosamente.
+ pub verified: u64,
+ /// Si hubo error, el seq donde se detectó.
+ pub broken_at_seq: Option<u64>,
+ /// Detalles del error si hubo.
+ pub error: Option<String>,
+ /// SHA del genesis (primer entry; prev_sha = None).
+ pub genesis_sha: Option<[u8; 32]>,
+}
+
+/// Recorre la cadena del audit log desde `start_sha` hacia atrás vía `prev_sha`
+/// hasta el genesis. Para cada entry valida:
+/// 1. CAS contiene un blob bajo ese SHA
+/// 2. sha256(blob) == SHA esperado (defensa contra tampering del CAS)
+/// 3. El blob deserializa a AuditEntry con sha=[0;32] (forma canónica)
+///
+/// Devuelve un VerificationReport con el conteo, posibles errores y
+/// el SHA del genesis (útil para clientes que quieren cachearlo).
+pub fn verify_chain_from_cas(start_sha: [u8; 32]) -> VerificationReport {
+ let mut current = Some(start_sha);
+ let mut verified = 0u64;
+ let mut last_seen: Option<AuditEntry> = None;
+
+ while let Some(sha) = current {
+ let path = ente_cas::cas_root().join(ente_cas::hex(&sha));
+ let bytes = match std::fs::read(&path) {
+ Ok(b) => b,
+ Err(e) => return VerificationReport {
+ verified,
+ broken_at_seq: last_seen.as_ref().map(|e| e.seq),
+ error: Some(format!("CAS read {}: {e}", path.display())),
+ genesis_sha: None,
+ },
+ };
+ // Verificación 1: el blob hashea a la SHA esperada (CAS contract).
+ let actual = ente_cas::sha256_of(&bytes);
+ if actual != sha {
+ return VerificationReport {
+ verified,
+ broken_at_seq: last_seen.as_ref().map(|e| e.seq),
+ error: Some(format!(
+ "CAS tamper en {}: expected {} got {}",
+ path.display(), ente_cas::hex(&sha), ente_cas::hex(&actual)
+ )),
+ genesis_sha: None,
+ };
+ }
+ // Verificación 2: deserialize. El blob canónico tiene sha=[0;32].
+ let mut entry: AuditEntry = match serde_json::from_slice(&bytes) {
+ Ok(e) => e,
+ Err(e) => return VerificationReport {
+ verified,
+ broken_at_seq: last_seen.as_ref().map(|e| e.seq),
+ error: Some(format!("deserialize: {e}")),
+ genesis_sha: None,
+ },
+ };
+ // Re-poblar el sha en el entry para reportar coherentemente.
+ entry.sha = sha;
+ verified += 1;
+
+ let prev = entry.prev_sha;
+ last_seen = Some(entry);
+ current = prev;
+ }
+
+ VerificationReport {
+ verified,
+ broken_at_seq: None,
+ error: None,
+ genesis_sha: last_seen.as_ref().map(|e| e.sha),
+ }
+}
+
+/// Devuelve el set de SHAs alcanzables desde `start_sha` siguiendo
+/// `prev_sha` hasta el genesis. Usado por el GC del CAS para construir
+/// las "raíces vivas" del audit log.
+pub fn reachable_from_head(start_sha: [u8; 32]) -> std::collections::HashSet<[u8; 32]> {
+ let mut set = std::collections::HashSet::new();
+ let mut current = Some(start_sha);
+ while let Some(sha) = current {
+ if !set.insert(sha) { break; } // ciclo (no debería pasar) — corta
+ let path = ente_cas::cas_root().join(ente_cas::hex(&sha));
+ let bytes = match std::fs::read(&path) { Ok(b) => b, Err(_) => break };
+ let entry: AuditEntry = match serde_json::from_slice(&bytes) {
+ Ok(e) => e, Err(_) => break,
+ };
+ current = entry.prev_sha;
+ }
+ set
+}
+
+/// Recorre la cadena entera (head→genesis) y reconstruye la lista de
+/// actions en orden cronológico (oldest first). Útil tanto para replay
+/// como para auditoría retrospectiva.
+pub fn collect_chain_from_cas(start_sha: [u8; 32]) -> anyhow::Result<Vec<AuditEntry>> {
+ let mut entries = Vec::new();
+ let mut current = Some(start_sha);
+ while let Some(sha) = current {
+ let path = ente_cas::cas_root().join(ente_cas::hex(&sha));
+ let bytes = std::fs::read(&path)?;
+ let mut entry: AuditEntry = serde_json::from_slice(&bytes)?;
+ entry.sha = sha;
+ let prev = entry.prev_sha;
+ entries.push(entry);
+ current = prev;
+ }
+ // entries está en orden head→genesis. Reverse para chronological.
+ entries.reverse();
+ Ok(entries)
+}
+
+/// Aplica las actions de la cadena en orden cronológico contra un engine
+/// fresco. PromoteCrystal → insert. RemoveRule → remove. LoadRulesFile →
+/// log informativo (los archivos pueden no existir en el ambiente actual).
+pub fn replay_chain(
+ start_sha: [u8; 32],
+ engine: &mut crate::engine::RuleEngine,
+) -> ReplayReport {
+ let entries = match collect_chain_from_cas(start_sha) {
+ Ok(es) => es,
+ Err(e) => return ReplayReport {
+ applied: 0, final_rule_count: engine.len(),
+ error: Some(format!("collect chain: {e}")),
+ },
+ };
+ let mut applied = 0u64;
+ for entry in &entries {
+ match &entry.action {
+ AuditAction::PromoteCrystal { rule_id, crystal } => {
+ let mut rule = crate::crystallize::crystal_to_rule(crystal);
+ rule.id = *rule_id; // preservar identidad histórica
+ engine.insert(rule);
+ }
+ AuditAction::RemoveRule { rule_id } => {
+ engine.remove(*rule_id);
+ }
+ AuditAction::LoadRulesFile { path: _, count: _ } => {
+ // Los archivos referenciados por path pueden haber cambiado
+ // o no existi
El parche sigue, pero se cortó acá: pedí el commit por git para verlo entero.