From 0e1b3807083fee3fb7c3bbb3f1aaf2cbda22d351 Mon Sep 17 00:00:00 2001 From: Samuel Williams Date: Tue, 6 Oct 2026 11:12:02 +1300 Subject: [PATCH 1/2] Align Rust crate interfaces and project guidance. --- Cargo.lock | 24 +++++--- bake/src/bake_generated_tasks/mod.rs | 4 +- context/development.md | 4 +- context/task-libraries.md | 10 ++-- readme.md | 37 ++++-------- releases.md | 4 ++ src/arguments.rs | 69 +-------------------- src/context.rs | 12 ++-- src/lib.rs | 9 ++- src/output.rs | 89 ++++++++++------------------ src/output_format.rs | 42 +++++++++++++ src/parameter.rs | 72 ++++++++++++++++++++++ src/registry.rs | 4 +- 13 files changed, 202 insertions(+), 178 deletions(-) create mode 100644 src/output_format.rs create mode 100644 src/parameter.rs diff --git a/Cargo.lock b/Cargo.lock index 0f7cc01..7efee3d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -30,15 +30,15 @@ dependencies = [ [[package]] name = "bake-agent-context" -version = "0.3.0" +version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "386910c08614146515e754bf6208aedba73abdb9a2767e8bd5c2d997845c84ef" +checksum = "9d0559ad6c6b640ec182f6378ca77825c4327f7b4fce65cfa84e47e25a1bfcb5" dependencies = [ "bake", "serde", "serde_json", "serde_yaml_ng", - "socketry-markdown 0.1.0", + "socketry-markdown 0.2.0", ] [[package]] @@ -90,9 +90,9 @@ dependencies = [ [[package]] name = "bake-readme" -version = "0.1.6" +version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "24fe3770977781484405d216b11a614a3e26404bb932bdddde718fad206f35c0" +checksum = "48b3733cc48991e6482c04b4997db89f75a7200e2c546c73047bd24e323c3f2a" dependencies = [ "bake", "serde_json", @@ -127,9 +127,9 @@ dependencies = [ [[package]] name = "bake-test-rust" -version = "0.3.0" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e9d5ceec9cc08a3bb421dd3755ad9e073831934793aa88d8f55095ad98c1dc45" +checksum = "3ced0bd0b0ae3f8df4b3cbb03b2a98080a5a9504c6b758c3eb96929dfd3dae93" dependencies = [ "bake", "serde_json", @@ -676,6 +676,16 @@ dependencies = [ "unicode-id", ] +[[package]] +name = "socketry-markdown" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "37d3a646262edeca60e86e4c4dd493167e74beb03ea75a60b2d5c40e6d6d8c5b" +dependencies = [ + "regex", + "unicode-id", +] + [[package]] name = "socketry-markdown" version = "0.3.0" diff --git a/bake/src/bake_generated_tasks/mod.rs b/bake/src/bake_generated_tasks/mod.rs index 2b1cd2f..941cb82 100644 --- a/bake/src/bake_generated_tasks/mod.rs +++ b/bake/src/bake_generated_tasks/mod.rs @@ -1,7 +1,5 @@ -// Released under the MIT License. -// Copyright, 2026, by Samuel Williams. - // Generated by `cargo bake --regenerate`; do not edit. + use bake_agent_context as _; use bake_cargo as _; use bake_license as _; diff --git a/context/development.md b/context/development.md index fb44870..18f25c2 100644 --- a/context/development.md +++ b/context/development.md @@ -8,10 +8,12 @@ Bake is a Cargo-compatible task runner inspired by Samuel Williams's Ruby Bake. ## Source map -- src/arguments.rs: parameter metadata, typed validation, command-line parsing. +- src/arguments.rs: typed validation and command-line parsing. +- src/parameter.rs: task parameter metadata and builders. - src/task.rs: task descriptor and handler interface. - src/task\_name.rs: constant-evaluated crate and module namespace inference. - src/registry.rs: registration, namespace imports, command planning, help and output. +- src/output\_format.rs: supported output formats and their names. - src/output.rs: replaceable default output, raw/JSON/NDJSON formatting, and null sink. - src/context.rs: shared state, project root, previous result, nested calls. - crates/macros/: task attribute and generated adapters; re-exported by bake. diff --git a/context/task-libraries.md b/context/task-libraries.md index 6608573..a43407c 100644 --- a/context/task-libraries.md +++ b/context/task-libraries.md @@ -157,11 +157,11 @@ Use ordinary Rust calls to compose implementation operations. Use `context.call( Add a reusable task library as a dependency of the local task binary, then run `cargo bake --regenerate` so its registration entries are linked: -```toml -[dependencies] -bake = "0.19" -socketry_executor = { package = "socketry-executor", version = "0.1" } -bake_agent_context = "0.3" +```sh +cargo bake --regenerate +cargo add --manifest-path bake/Cargo.toml socketry-executor --rename socketry_executor +cargo add --manifest-path bake/Cargo.toml bake-agent-context +cargo bake --regenerate ``` The first `cargo bake --regenerate` creates the private `bake/` workspace member and its minimal binary if they do not exist. Each run regenerates a small source file that links unconditional, non-optional, platform-independent direct dependencies in `bake/Cargo.toml` (apart from `bake` itself), and adds a module declaration to the selected binary if needed. It preserves the rest of the task source. Put reusable task libraries in `[dependencies]`; ordinary dependencies used by task code are also linked. diff --git a/readme.md b/readme.md index de484d4..44b3b58 100644 --- a/readme.md +++ b/readme.md @@ -31,35 +31,15 @@ The earlier `socketry-bake` package remains available for existing projects; use ## Add tasks to a project -Add an unpublished `bake` binary crate to your workspace: - -```text -Cargo.toml -src/ -bake/ - Cargo.toml - src/main.rs -``` - -In the project's `Cargo.toml`: +Create the private task package and let Cargo select the Bake dependency: -```toml -[workspace] -members = ["bake"] +```sh +cargo bake --regenerate +cargo add --manifest-path bake/Cargo.toml bake +cargo bake --regenerate ``` -In `bake/Cargo.toml`, depend on Bake by its published crate version: - -```toml -[package] -name = "project-tasks" -version = "0.0.0" -edition = "2024" -publish = false - -[dependencies] -bake = "0.19" -``` +The launcher creates an unpublished `bake/` binary and adds it to your workspace. The manifest records the dependency requirement; `Cargo.lock` records the selected version. In `bake/src/main.rs`: @@ -246,6 +226,11 @@ See [releases.md](releases.md) for the full release history. +## See Also + +- [`socketry-project`](https://github.com/socketry/socketry-project-rust). +- [`bake-agent-context`](https://github.com/socketry/bake-agent-context-rust). + ## Contributing Please open an issue or pull request on [GitHub](https://github.com/socketry/bake-rust). diff --git a/releases.md b/releases.md index ec18db9..21eeae3 100644 --- a/releases.md +++ b/releases.md @@ -1,5 +1,9 @@ # Releases +## Unreleased + +- Give `Parameter` and `OutputFormat` dedicated source files; preserve `Format` as a compatibility alias and refresh dependency setup examples. + ## v0.19.1 - Keep generated dependency skills out of the tracked repository. diff --git a/src/arguments.rs b/src/arguments.rs index 797cc94..cd1ab39 100644 --- a/src/arguments.rs +++ b/src/arguments.rs @@ -1,77 +1,12 @@ // Released under the MIT License. // Copyright, 2026, by Samuel Williams. -use crate::{Error, Result}; +use crate::{Error, Parameter, Result}; use std::collections::BTreeMap; use std::fmt::Display; use std::str::FromStr; -/// A task parameter. Names use underscores; command-line flags also accept hyphens. -pub struct Parameter { - pub(crate) name: String, - pub(crate) type_name: &'static str, - pub(crate) positional: bool, - pub(crate) required: bool, - pub(crate) repeated: bool, - pub(crate) default: Option, - pub(crate) description: String, - validate: fn(&str) -> Result<()>, -} - -impl Parameter { - /// Values use `FromStr`; custom types can implement it too. - pub fn new(name: &str) -> Self - where - Value::Err: Display, - { - Self { - name: name.into(), - type_name: std::any::type_name::(), - positional: true, - required: true, - repeated: false, - default: None, - description: String::new(), - validate: |value| parse::(value).map(|_| ()), - } - } - pub fn named(mut self) -> Self { - self.positional = false; - self - } - pub fn optional(mut self) -> Self { - self.required = false; - self - } - pub fn repeated(mut self) -> Self { - self.repeated = true; - self.positional = false; - self.required = false; - self - } - /// Consume repeated bare values until the task chain separator. - pub fn variadic(mut self) -> Self { - self.repeated = true; - self.positional = true; - self.required = false; - self - } - pub fn default(mut self, value: impl Into) -> Self { - self.default = Some(value.into()); - self.required = false; - self.positional = false; - self - } - pub fn help(mut self, description: impl Into) -> Self { - self.description = description.into(); - self - } - pub fn name(&self) -> &str { - &self.name - } -} - -fn parse(value: &str) -> Result +pub(crate) fn parse(value: &str) -> Result where Value::Err: Display, { diff --git a/src/context.rs b/src/context.rs index e700dc4..297c89d 100644 --- a/src/context.rs +++ b/src/context.rs @@ -1,7 +1,7 @@ // Released under the MIT License. // Copyright, 2026, by Samuel Williams. -use crate::output::Format; +use crate::OutputFormat; use crate::registry::Invocation; use crate::{Error, Registry, Result, Value}; use std::any::{Any, TypeId}; @@ -21,7 +21,7 @@ pub struct Context { state: HashMap>, depth: usize, terminal_output: String, - default_format: Option, + default_format: Option, } impl Context { @@ -49,10 +49,10 @@ impl Context { pub(crate) fn take_output(&mut self) -> String { std::mem::take(&mut self.terminal_output) } - pub(crate) fn set_default_format(&mut self, format: Option) { + pub(crate) fn set_default_format(&mut self, format: Option) { self.default_format = format; } - pub(crate) fn default_format(&self) -> Option { + pub(crate) fn default_format(&self) -> Option { self.default_format } pub fn insert(&mut self, state: State) { @@ -133,8 +133,8 @@ mod tests { let mut context = Registry::new().context("project"); assert_eq!(context.root(), Path::new("project")); assert_eq!(context.previous(), &Value::Null); - context.set_default_format(Some(Format::Json)); - assert_eq!(context.default_format(), Some(Format::Json)); + context.set_default_format(Some(OutputFormat::Json)); + assert_eq!(context.default_format(), Some(OutputFormat::Json)); assert!(context.get::().is_none()); assert!(context.get_mut::().is_none()); diff --git a/src/lib.rs b/src/lib.rs index 91f9e9f..9b77a87 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -13,6 +13,8 @@ mod arguments; mod context; mod error; mod output; +mod output_format; +mod parameter; mod registry; mod task; mod task_name; @@ -24,11 +26,14 @@ pub mod __private { pub use linkme; } -pub use arguments::{Arguments, Parameter}; +pub use arguments::Arguments; pub use bake_macros::task; pub use context::Context; pub use error::{Error, Result}; -pub use output::Format; +pub use output_format::OutputFormat; +/// Compatibility name for [`OutputFormat`]. +pub use output_format::OutputFormat as Format; +pub use parameter::Parameter; pub use registry::Registry; pub use serde_json::Value; pub use task::Task; diff --git a/src/output.rs b/src/output.rs index 05fcf53..19569ab 100644 --- a/src/output.rs +++ b/src/output.rs @@ -1,58 +1,20 @@ // Released under the MIT License. // Copyright, 2026, by Samuel Williams. -use crate::{Context, Error, Result, Value}; -use std::fmt; +use crate::{Context, Error, OutputFormat, Result, Value}; use std::fs; use std::path::Path; use std::path::PathBuf; -use std::str::FromStr; - -/// Built-in result encodings accepted by the default `output` task. -#[derive(Clone, Copy, Debug, Eq, PartialEq)] -pub enum Format { - /// Plain text for strings and pretty JSON for structured values. - Raw, - /// Indented JSON. - Json, - /// One compact JSON value per line; the input must be an array. - Ndjson, -} - -impl FromStr for Format { - type Err = Error; - - fn from_str(value: &str) -> Result { - match value { - "raw" => Ok(Self::Raw), - "json" => Ok(Self::Json), - "ndjson" => Ok(Self::Ndjson), - _ => Err(Error::new(format!( - "unknown output format {value:?}; use raw, json, or ndjson" - ))), - } - } -} - -impl fmt::Display for Format { - fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result { - formatter.write_str(match self { - Self::Raw => "raw", - Self::Json => "json", - Self::Ndjson => "ndjson", - }) - } -} -fn format_value(value: &Value, format: Format) -> Result { +fn format_value(value: &Value, format: OutputFormat) -> Result { let mut output = match format { - Format::Raw => match value { + OutputFormat::Raw => match value { Value::String(text) => text.clone(), Value::Null => String::new(), value => pretty_json(value), }, - Format::Json => pretty_json(value), - Format::Ndjson => { + OutputFormat::Json => pretty_json(value), + OutputFormat::Ndjson => { let Value::Array(values) = value else { return Err(Error::new("ndjson output requires an array result")); }; @@ -81,11 +43,11 @@ fn compact_json(value: &Value) -> String { .unwrap_or_else(|error| unreachable!("JSON values always serialize: {error}")) } -fn inferred_format(file: &Path) -> Option { +fn inferred_format(file: &Path) -> Option { match file.extension()?.to_str()?.to_ascii_lowercase().as_str() { - "json" => Some(Format::Json), - "ndjson" => Some(Format::Ndjson), - "txt" | "text" => Some(Format::Raw), + "json" => Some(OutputFormat::Json), + "ndjson" => Some(OutputFormat::Ndjson), + "txt" | "text" => Some(OutputFormat::Raw), _ => None, } } @@ -100,12 +62,12 @@ pub fn output( context: &mut Context, #[bake(input)] input: Value, file: Option, - format: Option, + format: Option, ) -> Result { let format = format .or_else(|| context.default_format()) .or_else(|| file.as_deref().and_then(inferred_format)) - .unwrap_or(Format::Raw); + .unwrap_or(OutputFormat::Raw); let contents = format_value(&input, format)?; if let Some(file) = file { @@ -135,24 +97,33 @@ mod tests { #[test] fn formats_have_stable_names() { - assert_eq!(Format::Raw.to_string(), "raw"); - assert_eq!(Format::Json.to_string(), "json"); - assert_eq!(Format::Ndjson.to_string(), "ndjson"); - assert_eq!("raw".parse::().unwrap(), Format::Raw); - assert_eq!("json".parse::().unwrap(), Format::Json); - assert_eq!("ndjson".parse::().unwrap(), Format::Ndjson); - assert!("yaml".parse::().is_err()); + assert_eq!(OutputFormat::Raw.to_string(), "raw"); + assert_eq!(OutputFormat::Json.to_string(), "json"); + assert_eq!(OutputFormat::Ndjson.to_string(), "ndjson"); + assert_eq!("raw".parse::().unwrap(), OutputFormat::Raw); + assert_eq!("json".parse::().unwrap(), OutputFormat::Json); + assert_eq!( + "ndjson".parse::().unwrap(), + OutputFormat::Ndjson + ); + assert!("yaml".parse::().is_err()); } #[test] fn unknown_file_extensions_do_not_select_a_format() { assert_eq!(inferred_format(Path::new("releases.md")), None); assert_eq!(inferred_format(Path::new("notes.csv")), None); - assert_eq!(inferred_format(Path::new("notes.txt")), Some(Format::Raw)); - assert_eq!(inferred_format(Path::new("notes.text")), Some(Format::Raw)); + assert_eq!( + inferred_format(Path::new("notes.txt")), + Some(OutputFormat::Raw) + ); + assert_eq!( + inferred_format(Path::new("notes.text")), + Some(OutputFormat::Raw) + ); assert_eq!( inferred_format(Path::new("notes.ndjson")), - Some(Format::Ndjson) + Some(OutputFormat::Ndjson) ); } diff --git a/src/output_format.rs b/src/output_format.rs new file mode 100644 index 0000000..e3ee7bd --- /dev/null +++ b/src/output_format.rs @@ -0,0 +1,42 @@ +// Released under the MIT License. +// Copyright, 2026, by Samuel Williams. + +use crate::{Error, Result}; +use std::fmt; +use std::str::FromStr; + +/// Built-in result encodings accepted by the default `output` task. +#[derive(Clone, Copy, Debug, Eq, PartialEq)] +pub enum OutputFormat { + /// Plain text for strings and pretty JSON for structured values. + Raw, + /// Indented JSON. + Json, + /// One compact JSON value per line; the input must be an array. + Ndjson, +} + +impl FromStr for OutputFormat { + type Err = Error; + + fn from_str(value: &str) -> Result { + match value { + "raw" => Ok(Self::Raw), + "json" => Ok(Self::Json), + "ndjson" => Ok(Self::Ndjson), + _ => Err(Error::new(format!( + "unknown output format {value:?}; use raw, json, or ndjson" + ))), + } + } +} + +impl fmt::Display for OutputFormat { + fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result { + formatter.write_str(match self { + Self::Raw => "raw", + Self::Json => "json", + Self::Ndjson => "ndjson", + }) + } +} diff --git a/src/parameter.rs b/src/parameter.rs new file mode 100644 index 0000000..396d3fc --- /dev/null +++ b/src/parameter.rs @@ -0,0 +1,72 @@ +// Released under the MIT License. +// Copyright, 2026, by Samuel Williams. + +use crate::Result; +use crate::arguments::parse; +use std::fmt::Display; +use std::str::FromStr; + +/// A task parameter. Names use underscores; command-line flags also accept hyphens. +pub struct Parameter { + pub(crate) name: String, + pub(crate) type_name: &'static str, + pub(crate) positional: bool, + pub(crate) required: bool, + pub(crate) repeated: bool, + pub(crate) default: Option, + pub(crate) description: String, + pub(crate) validate: fn(&str) -> Result<()>, +} + +impl Parameter { + /// Values use `FromStr`; custom types can implement it too. + pub fn new(name: &str) -> Self + where + Value::Err: Display, + { + Self { + name: name.into(), + type_name: std::any::type_name::(), + positional: true, + required: true, + repeated: false, + default: None, + description: String::new(), + validate: |value| parse::(value).map(|_| ()), + } + } + pub fn named(mut self) -> Self { + self.positional = false; + self + } + pub fn optional(mut self) -> Self { + self.required = false; + self + } + pub fn repeated(mut self) -> Self { + self.repeated = true; + self.positional = false; + self.required = false; + self + } + /// Consume repeated bare values until the task chain separator. + pub fn variadic(mut self) -> Self { + self.repeated = true; + self.positional = true; + self.required = false; + self + } + pub fn default(mut self, value: impl Into) -> Self { + self.default = Some(value.into()); + self.required = false; + self.positional = false; + self + } + pub fn help(mut self, description: impl Into) -> Self { + self.description = description.into(); + self + } + pub fn name(&self) -> &str { + &self.name + } +} diff --git a/src/registry.rs b/src/registry.rs index 4c5c9a8..d7ebf26 100644 --- a/src/registry.rs +++ b/src/registry.rs @@ -1,7 +1,7 @@ // Released under the MIT License. // Copyright, 2026, by Samuel Williams. -use crate::{Arguments, Context, Error, Format, Result, Task, output}; +use crate::{Arguments, Context, Error, OutputFormat, Result, Task, output}; use std::collections::{BTreeMap, BTreeSet}; use std::ffi::OsString; use std::io::{self, Write}; @@ -269,7 +269,7 @@ impl Registry { fn run_arguments_from(self, root: PathBuf, tokens: &[String]) -> Result { let (format, tokens) = if tokens.first().is_some_and(|token| token == "--json") { - (Some(Format::Json), &tokens[1..]) + (Some(OutputFormat::Json), &tokens[1..]) } else { (None, tokens) }; From edabd3dc2506756844c17d10f242b3dd4e5992f2 Mon Sep 17 00:00:00 2001 From: Samuel Williams Date: Tue, 6 Oct 2026 11:12:04 +1300 Subject: [PATCH 2/2] Prepare the consistency release. --- Cargo.lock | 6 +++--- Cargo.toml | 4 ++-- bake/Cargo.toml | 2 +- bake/src/bake_generated_tasks/mod.rs | 4 +++- readme.md | 11 ++++------- releases.md | 2 +- 6 files changed, 14 insertions(+), 15 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 7efee3d..1b53196 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -19,7 +19,7 @@ dependencies = [ [[package]] name = "bake" -version = "0.19.1" +version = "0.19.2" dependencies = [ "bake-macros", "linkme", @@ -71,7 +71,7 @@ dependencies = [ [[package]] name = "bake-macros" -version = "0.19.1" +version = "0.19.2" dependencies = [ "proc-macro2", "quote", @@ -658,7 +658,7 @@ checksum = "f9395f0f0eee849a9b707b2f06bb92a6a422090e2123bb2ef8e87a0e61892a8e" [[package]] name = "socketry-cargo-bake" -version = "0.19.1" +version = "0.19.2" dependencies = [ "serde", "serde_json", diff --git a/Cargo.toml b/Cargo.toml index c048dec..f7b6678 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -3,7 +3,7 @@ members = ["crates/macros", "crates/cargo-bake", "bake"] resolver = "3" [workspace.package] -version = "0.19.1" +version = "0.19.2" edition = "2024" license = "MIT" repository = "https://github.com/socketry/bake-rust" @@ -65,7 +65,7 @@ name = "bake" serde.workspace = true serde_json.workspace = true linkme.workspace = true -bake-macros = { version = "0.19.1", path = "crates/macros" } +bake-macros = { version = "0.19.2", path = "crates/macros" } [dev-dependencies] tempfile.workspace = true diff --git a/bake/Cargo.toml b/bake/Cargo.toml index 00806ed..ad35393 100644 --- a/bake/Cargo.toml +++ b/bake/Cargo.toml @@ -6,7 +6,7 @@ publish = false [dependencies] socketry-project = ">=0.3.7" -bake = { version = "0.19.1", path = ".." } +bake = { version = "0.19.2", path = ".." } bake-agent-context = { version = "0.3.0" } bake-test-rust = { version = "0.3.0" } bake-releases = { version = "0.3.0" } diff --git a/bake/src/bake_generated_tasks/mod.rs b/bake/src/bake_generated_tasks/mod.rs index 941cb82..2b1cd2f 100644 --- a/bake/src/bake_generated_tasks/mod.rs +++ b/bake/src/bake_generated_tasks/mod.rs @@ -1,5 +1,7 @@ -// Generated by `cargo bake --regenerate`; do not edit. +// Released under the MIT License. +// Copyright, 2026, by Samuel Williams. +// Generated by `cargo bake --regenerate`; do not edit. use bake_agent_context as _; use bake_cargo as _; use bake_license as _; diff --git a/readme.md b/readme.md index 44b3b58..696247c 100644 --- a/readme.md +++ b/readme.md @@ -203,6 +203,10 @@ Prepare a release with `cargo bake cargo:version:patch` (or `minor`, `major`, or See [releases.md](releases.md) for the full release history. +### v0.19.2 + +- Give `Parameter` and `OutputFormat` dedicated source files; preserve `Format` as a compatibility alias and refresh dependency setup examples. + ### v0.19.1 - Keep generated dependency skills out of the tracked repository. @@ -217,13 +221,6 @@ See [releases.md](releases.md) for the full release history. - Support unbounded positional `Vec` task arguments with `#[bake(positional)]`. Require `::` before chaining another task. -### v0.18.0 - -- Derive default task namespaces from `bake_*` library crate names, stripping `bake_` and translating remaining underscores to colons. Preserve explicit names, project binary names, and matching module prefixes. Existing unnamed library tasks outside those prefixes gain a namespace; use explicit names to retain their previous commands. -- Use `bake = "0"` for reusable task libraries so linked crates resolve one Bake 0.x version and share its task registry. -- Resolve task names at compile time. Generated descriptors now include their full namespaces, making manual registration and automatic discovery agree. Manual registries that added those namespaces with `Registry::include` should register the descriptors directly to avoid repeating the prefix. -- Document semantic task-library APIs, crate-derived namespaces, and testing conventions aligned with `socketry-project`. - ## See Also diff --git a/releases.md b/releases.md index 21eeae3..6c96634 100644 --- a/releases.md +++ b/releases.md @@ -1,6 +1,6 @@ # Releases -## Unreleased +## v0.19.2 - Give `Parameter` and `OutputFormat` dedicated source files; preserve `Format` as a compatibility alias and refresh dependency setup examples.