build(slice-2): workspace deps + rutster-tap-echo skeleton

- Add tokio-tungstenite 0.24, futures-util 0.3, url 2, base64 0.22 to
  [workspace.dependencies] (spec §8.1).
- Add crates/rutster-tap-echo as 7th workspace member (spec §2).
- Transition crates/rutster-tap/Cargo.toml from stub to real manifest
  with the deps Tasks 2-4 will need (rutster-media, tokio, tokio-tungstenite,
  serde, serde_json, base64, url, thiserror, tracing).
- Skeleton lib.rs (compile test) + main.rs (placeholder fn main) for
  rutster-tap-echo; Task 5 fills in the echo logic.
- Verify cargo deny check passes against the new transitive dep tree.

Spec ref: docs/superpowers/specs/2026-06-28-slice-2-agent-tap-design.md §2, §8.1.
This commit is contained in:
opencode controller
2026-06-28 14:01:12 -04:00
parent 22d3f03b8c
commit 0cccf77faf
7 changed files with 304 additions and 9 deletions

226
Cargo.lock generated
View File

@@ -207,6 +207,12 @@ version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4c7f02d4ea65f2c1853089ffd8d2787bdbc63de2f0d29dedbcf8ccdfa0ccd4cf"
[[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"
@@ -219,12 +225,27 @@ version = "2.13.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b4388bee8683e3d04af747c73422af53102d2bd24d9eadb6cbc100baef4b43f8"
[[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 = "bumpalo"
version = "3.20.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "72f5acc6cb2ba439de613abc23857ec3d78374d8ed5ac84e9d11336e87da8649"
[[package]]
name = "byteorder"
version = "1.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b"
[[package]]
name = "bytes"
version = "1.12.0"
@@ -412,6 +433,16 @@ dependencies = [
"powerfmt",
]
[[package]]
name = "digest"
version = "0.10.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292"
dependencies = [
"block-buffer",
"crypto-common",
]
[[package]]
name = "dimpl"
version = "0.7.0"
@@ -427,7 +458,7 @@ dependencies = [
"nom 8.0.0",
"once_cell",
"pkcs8",
"rand",
"rand 0.9.4",
"rcgen",
"sec1",
"signature",
@@ -512,6 +543,23 @@ version = "0.3.32"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7e3450815272ef58cec6d564423f6e755e25379b217b0bc688e295ba24df6b1d"
[[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",
]
[[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"
@@ -525,6 +573,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "389ca41296e6190b48053de0321d02a77f32f8a5d2461dd38762c0593805c6d6"
dependencies = [
"futures-core",
"futures-macro",
"futures-sink",
"futures-task",
"pin-project-lite",
"slab",
@@ -540,6 +590,17 @@ dependencies = [
"version_check",
]
[[package]]
name = "getrandom"
version = "0.2.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ff2abc00be7fca6ebc474524697ae276ad847ad0a6b3faa4bcb027e9a4614ad0"
dependencies = [
"cfg-if",
"libc",
"wasi",
]
[[package]]
name = "getrandom"
version = "0.3.4"
@@ -649,6 +710,16 @@ dependencies = [
"tower-service",
]
[[package]]
name = "idna"
version = "0.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "634d9b1461af396cad843f47fdba5597a4f9e6ddd4bfb6ff5d85028c25cb12f6"
dependencies = [
"unicode-bidi",
"unicode-normalization",
]
[[package]]
name = "inout"
version = "0.1.4"
@@ -960,14 +1031,35 @@ 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",
"rand_core",
"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]]
@@ -977,7 +1069,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d3022b5f1df60f26e1ffddd6c66e8aa15de382ae63b3a0c1bfc0e4d3e3f325cb"
dependencies = [
"ppv-lite86",
"rand_core",
"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]]
@@ -1104,7 +1205,32 @@ version = "0.0.0"
[[package]]
name = "rutster-tap"
version = "0.0.0"
version = "0.1.0"
dependencies = [
"base64",
"futures-util",
"rutster-media",
"serde",
"serde_json",
"thiserror 1.0.69",
"tokio",
"tokio-tungstenite",
"tracing",
"url",
]
[[package]]
name = "rutster-tap-echo"
version = "0.1.0"
dependencies = [
"futures-util",
"rutster-tap",
"serde_json",
"tokio",
"tokio-tungstenite",
"tracing",
"tracing-subscriber",
]
[[package]]
name = "ryu"
@@ -1127,7 +1253,7 @@ dependencies = [
"bytes",
"crc",
"log",
"rand",
"rand 0.9.4",
"rustc-hash",
"slab",
"thiserror 2.0.18",
@@ -1211,6 +1337,17 @@ dependencies = [
"serde",
]
[[package]]
name = "sha1"
version = "0.10.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e3bf829a2d51ab4a5ddf1352d8470c140cadc8301b2ae1789db023f01cedd6ba"
dependencies = [
"cfg-if",
"cpufeatures",
"digest",
]
[[package]]
name = "sharded-slab"
version = "0.1.7"
@@ -1435,6 +1572,21 @@ dependencies = [
"time-core",
]
[[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.3"
@@ -1463,6 +1615,18 @@ dependencies = [
"syn",
]
[[package]]
name = "tokio-tungstenite"
version = "0.24.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "edc5f74e248dc973e0dbb7b74c7e0d6fcc301c694ff50049504004ef4d0cdcd9"
dependencies = [
"futures-util",
"log",
"tokio",
"tungstenite",
]
[[package]]
name = "tower"
version = "0.5.3"
@@ -1553,24 +1717,74 @@ dependencies = [
"tracing-log",
]
[[package]]
name = "tungstenite"
version = "0.24.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "18e5b8366ee7a95b16d32197d0b2604b43a0be89dc5fac9f8e96ccafbaedda8a"
dependencies = [
"byteorder",
"bytes",
"data-encoding",
"http",
"httparse",
"log",
"rand 0.8.6",
"sha1",
"thiserror 1.0.69",
"utf-8",
]
[[package]]
name = "typenum"
version = "1.20.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b6f5e870be6c3b371b77fe0ee0bafb859fa4964b4404c27de1d380043c4dda20"
[[package]]
name = "unicode-bidi"
version = "0.3.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5c1cb5db39152898a79168971543b1cb5020dff7fe43c8dc468b0885f5e29df5"
[[package]]
name = "unicode-ident"
version = "1.0.24"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75"
[[package]]
name = "unicode-normalization"
version = "0.1.25"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5fd4f6878c9cb28d874b009da9e8d183b5abc80117c40bbd187a1fde336be6e8"
dependencies = [
"tinyvec",
]
[[package]]
name = "untrusted"
version = "0.7.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a156c684c91ea7d62626509bce3cb4e1d9ed5c4d978f7b4352658f96a4c26b4a"
[[package]]
name = "url"
version = "2.5.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "22784dbdf76fdde8af1aeda5622b546b422b6fc585325248a2bf9f5e41e94d6c"
dependencies = [
"form_urlencoded",
"idna",
"percent-encoding",
]
[[package]]
name = "utf-8"
version = "0.7.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "09cc8ee72d2a9becf2f2febe0205bbed8fc6615b7cb429ad062dc7b7ddd036a9"
[[package]]
name = "uuid"
version = "1.23.4"

View File

@@ -10,6 +10,7 @@ members = [
"crates/rutster-media",
"crates/rutster-signaling-sip",
"crates/rutster-tap",
"crates/rutster-tap-echo",
"crates/rutster-spend",
]
@@ -42,3 +43,11 @@ serde_json = "1"
# on the axum Router). Axum re-exports parts of tower but the integration test
# uses `tower::ServiceExt` directly, so it needs to be a workspace dep.
tower = { version = "0.5", features = ["util"] }
# tokio-tungstenite 0.24: WS client + server (slice-2 tap transport).
tokio-tungstenite = { version = "0.24", features = ["connect"] }
# futures-util 0.3: Sink/Stream traits for WebSocketStream.
futures-util = "0.3"
# url 2: tap URL parsing + host validation (spec §4.4).
url = "2"
# base64 0.22: PCM <-> base64 codec for the v1 wire format (spec §3).
base64 = "0.22"

View File

@@ -0,0 +1,15 @@
[package]
name = "rutster-tap-echo"
version = "0.1.0"
license.workspace = true
edition.workspace = true
repository.workspace = true
[dependencies]
rutster-tap = { path = "../rutster-tap" } # protocol types — the wire-types-reusable contract test
tokio = { workspace = true }
tokio-tungstenite = { workspace = true }
futures-util = { workspace = true }
serde_json = { workspace = true }
tracing = { workspace = true }
tracing-subscriber = { workspace = true }

View File

@@ -0,0 +1,23 @@
//! # rutster-tap-echo — the Rust reference echo brain + test server (spec §2.3, §8.4)
//!
//! Dual-purpose crate:
//! - **Standalone binary** (`cargo run -p rutster-tap-echo`): binds
//! `ws://127.0.0.1:8081/echo` and echoes `audio_in` → `audio_out` per the
//! slice-2 protocol (spec §3). The dev-loop brain the core dials out to.
//! - **In-process `EchoServer`** (Task 5 lands `EchoServer::start`): used by
//! `rutster`'s integration tests to drive the tap end-to-end without an
//! external process.
//!
//! ## Why a Rust brain at all (when the canonical brain is Python?)
//!
//! Reuses `rutster-tap`'s protocol types — **the contract test that the wire
//! types are reusable from outside the core**. Any future brain written in
//! Rust (or a step-3 OpenAI adapter in Rust) starts from this shape. The
//! Python brain (`examples/echo_brain/`) proves language-agnosticism; this
//! crate proves reusability + powers the in-process integration tests.
#[cfg(test)]
mod tests {
#[test]
fn crate_compiles() {}
}

View File

@@ -0,0 +1,6 @@
//! Standalone binary: bind `ws://127.0.0.1:8081/echo`, echo audio_in → audio_out.
//! Real implementation lands in Task 5; this is the skeleton that compiles.
fn main() {
eprintln!("rutster-tap-echo: skeleton — implementation lands in Task 5");
}

View File

@@ -1,8 +1,18 @@
# crates/rutster-tap/Cargo.toml
[package]
name = "rutster-tap"
version = "0.0.0"
version = "0.1.0"
license.workspace = true
edition.workspace = true
repository.workspace = true
description = "Agent audio tap — stub crate (filled in spearhead step 2)."
[dependencies]
rutster-media = { path = "../rutster-media" } # PcmFrame (re-exported — spec §3.1)
tokio = { workspace = true }
tokio-tungstenite = { workspace = true }
futures-util = { workspace = true }
serde = { workspace = true }
serde_json = { workspace = true }
base64 = { workspace = true }
url = { workspace = true }
thiserror = { workspace = true }
tracing = { workspace = true }

View File

@@ -111,6 +111,24 @@ skip = [
# together. Both pull distinct `r-efi` versions, so the two skips
# are coupled: skip one without the other and the dup remains.
"getrandom@0.3.4",
# `rand` / `rand_core` / `rand_chacha` / `getrandom` v0.2-era split
# (slice-2 §8.1 task 1): `tokio-tungstenite` = "0.24" → `tungstenite`
# 0.24 pulls the OLD `rand` 0.8 chain (rand_core 0.6, rand_chacha 0.3,
# getrandom 0.2), while `str0m` (via `dimpl`/`sctp-proto`) and the
# uuid branch use the NEW `rand` 0.9 chain (rand_core 0.9,
# rand_chacha 0.9, getrandom 0.4). Both branches are fully transitive
# (we don't depend on `rand` directly). Unified only by either
# bumping `tokio-tungstenite` to a release that adopts `rand` 0.9
# (none of the 0.24.x line does; newer 0.25+ requires features beyond
# slice-2's verbatim dep pin per spec §8.1), or forking tungstenite —
# both out of scope for Task 1. These four skips are coupled: skip
# rand@0.8.6 without its three peers and the duplicates remain.
# Revisit when `tokio-tungstenite` workspace dep moves to a release
# that unifies on `rand` 0.9.
"rand@0.8.6",
"rand_core@0.6.4",
"rand_chacha@0.3.1",
"getrandom@0.2.17",
]
skip-tree = []