Files
Skald-Circle/Cargo.toml
T
dguiducci 8013022321
Nightly Build / build (push) Successful in 8m52s
feat(files): streaming ZIP download in the project explorer
Each row of the project Files tab gains a download action, and the toolbar
gains a Download ZIP button scoped to the folder being browsed (at the root,
the whole project). Visible to read-only members too: download is a read.

Single files need no new backend: they reuse GET /api/file?force_download.
Directories go through the new GET /api/file/download, which builds the ZIP
on the fly: an async task walks the tree and async_zip (Astral's maintained
rs-async-zip fork) streams entries into a bounded duplex stream backing the
response body — no temp file, no whole-archive buffer, backpressure for free,
and the task dies with the client. Compression is per entry: Deflate at
maximum level, except files whose magic bytes name an already-compressed
format (media/PDF via the shared sniffer, the ZIP family, gzip/zstd/7z/rar,
compressed audio), which are Stored. Entries are prefixed with the folder
name, empty folders and unix permission bits survive, symlinks are never
followed into the archive, and containment stays fail-closed under the
resolved root. Covered by a round-trip test read back with the crate's own
reader (and verified against unzip/python's zipfile).
2026-08-07 19:49:30 +01:00

93 lines
4.2 KiB
TOML

[workspace]
members = [
".",
"crates/agent-loop",
"crates/skald-core",
"crates/skald-setup",
"crates/honcho-client",
"crates/core-api",
"crates/mcp-client",
"crates/plugin-tailscale-remote",
"crates/plugin-telegram-bot",
"crates/plugin-mobile-connector",
"crates/plugin-transcribe-whisper-local",
"crates/plugin-comfyui",
"crates/plugin-tts-orpheus-3b",
"crates/plugin-tts-kokoro",
"crates/plugin-elevenlabs",
"crates/plugin-honcho",
"crates/skald-relay-common",
"crates/skald-relay-server",
"crates/skald-relay-client",
]
resolver = "2"
[package]
name = "skald"
version = "0.2.0"
edition = "2024"
[features]
default = ["whisper-local"]
whisper-local = ["dep:plugin-transcribe-whisper-local"]
# Embedded (pure-Rust) Tailscale provider. Off by default: the `tailscale` crate
# forces the `aws-lc-rs` crypto backend (a cmake/NASM C build) back into the
# tree, defeating the ring-only crypto path. The recommended `tailscale_sys`
# provider (system tailscaled) stays available without it. Enable only for a
# self-contained embedded mesh (re-introduces the aws-lc-rs C build).
embedded-tailscale = ["plugin-tailscale-remote/remote-tailscale"]
[dependencies]
skald-core = { path = "crates/skald-core" }
axum = { version = "0.8", features = ["ws", "multipart"] }
tokio = { version = "1.52.3", features = ["full"] }
tokio-util = { version = "0.7", features = ["rt", "io"] }
futures = "0.3"
# Streaming ZIP for directory downloads (src/frontend/api/files.rs): an async
# ZIP writer over a duplex stream, so archives are built on the fly straight
# into the HTTP body — no temp file, no whole-archive buffer. Astral's
# maintained fork of rs-async-zip (used by uv); the `zip` crate has no
# non-seekable writer in any non-yanked release.
astral_async_zip = { version = "0.0.20", default-features = false, features = ["tokio", "deflate"] }
tower-http = { version = "0.7.0", features = ["fs", "compression-gzip", "compression-br", "set-header"] }
tower = "0.5"
serde = { version = "1", features = ["derive"] }
serde_yaml = "0.9"
anyhow = "1"
# Verifies the SHA-256 digests the connector marketplace declares for each file
# it serves (src/frontend/api/marketplace.rs).
sha2 = "0.10"
sqlx = { version = "0.9.0", features = ["runtime-tokio", "sqlite"] }
reqwest = { version = "0.13.4", default-features = false, features = ["rustls-no-provider", "charset", "http2", "system-proxy", "json", "multipart"] }
# rustls is pinned as a direct dependency solely to select the crypto provider:
# `ring` instead of the default `aws-lc-rs`, avoiding aws-lc's cmake/NASM build.
# Every reqwest client uses `rustls-no-provider`, so exactly one process-wide
# provider is installed in main() before any TLS handshake.
#
# TLS therefore never touches OpenSSL. libcrypto is nonetheless in the tree now,
# vendored and statically linked for SQLCipher (see `libsqlite3-sys` in
# crates/skald-core) — so the binary stays self-contained, but "no OpenSSL
# anywhere" is no longer true.
rustls = { version = "0.23", default-features = false, features = ["ring", "std", "tls12", "logging"] }
async-trait = "0.1"
serde_json = "1"
indexmap = { version = "2", features = ["serde"] }
tracing = "0.1"
tracing-subscriber = { version = "0.3", features = ["env-filter"] }
tracing-appender = "0.2"
chrono = { version = "0.4", default-features = false, features = ["clock", "std"] }
notify = "8"
honcho-client = { path = "crates/honcho-client" }
core-api = { path = "crates/core-api" }
mcp-client = { path = "crates/mcp-client" }
plugin-tailscale-remote = { path = "crates/plugin-tailscale-remote" }
plugin-telegram-bot = { path = "crates/plugin-telegram-bot" }
plugin-mobile-connector = { path = "crates/plugin-mobile-connector" }
plugin-transcribe-whisper-local = { path = "crates/plugin-transcribe-whisper-local", optional = true }
plugin-comfyui = { path = "crates/plugin-comfyui" }
plugin-tts-orpheus-3b = { path = "crates/plugin-tts-orpheus-3b" }
plugin-tts-kokoro = { path = "crates/plugin-tts-kokoro" }
plugin-elevenlabs = { path = "crates/plugin-elevenlabs" }
plugin-honcho = { path = "crates/plugin-honcho" }