diff --git a/crates/aura-cli/src/graph_construct.rs b/crates/aura-cli/src/graph_construct.rs index 7ef9fc3..ff21f89 100644 --- a/crates/aura-cli/src/graph_construct.rs +++ b/crates/aura-cli/src/graph_construct.rs @@ -589,10 +589,11 @@ fn introspect_registered(env: &aura_runner::project::Env) -> Result` / `--unwired` / `--params ` / the id -/// group must be set; zero or more than one is the usage error (exit 2). The id -/// group is `--content-id [FILE]` and/or `--identity-id` — the two id flags may -/// combine (one build, both ids, content id first). +/// `--vocabulary` / `--node ` / `--unwired` / `--params ` / +/// `--taps ` / the id group must be set; zero or more than one is the +/// usage error (exit 2). The id group is `--content-id [FILE]` and/or +/// `--identity-id` — the two id flags may combine (one build, both ids, +/// content id first). pub fn introspect_cmd(cmd: crate::GraphIntrospectCmd, env: &aura_runner::project::Env) { let count = cmd.vocabulary as usize + cmd.node.is_some() as usize @@ -600,10 +601,11 @@ pub fn introspect_cmd(cmd: crate::GraphIntrospectCmd, env: &aura_runner::project + cmd.folds as usize + cmd.registered as usize + cmd.params.is_some() as usize + + cmd.taps.is_some() as usize + (cmd.content_id.is_some() || cmd.identity_id) as usize; if count != 1 { eprintln!( - "aura: Usage: aura graph introspect --vocabulary | --node | --unwired | --folds | --registered | --params | --content-id [FILE] | --identity-id (the two id flags may be combined)" + "aura: Usage: aura graph introspect --vocabulary | --node | --unwired | --folds | --registered | --params | --taps | --content-id [FILE] | --identity-id (the two id flags may be combined)" ); std::process::exit(2); } @@ -675,6 +677,18 @@ pub fn introspect_cmd(cmd: crate::GraphIntrospectCmd, env: &aura_runner::project std::process::exit(1); } } + } else if let Some(target) = cmd.taps.as_deref() { + // --taps (#337): the positive declared-tap discovery view — + // #333 shipped only the refusal roster (`bind_tap_plan`'s + // `UnknownTap`), so provoking that refusal was the only way to learn + // a blueprint's declared tap names. + match taps_lines(target, env) { + Ok(s) => print!("{s}"), + Err(m) => { + eprintln!("aura: {m}"); + std::process::exit(1); + } + } } else { // --content-id [FILE] / --identity-id (combinable): one build, then each // requested id on its own line, content id first. With a FILE value the @@ -997,6 +1011,31 @@ fn params_lines(target: &str, env: &aura_runner::project::Env) -> Result` (#337): one row per declared tap +/// — ` . ` — the positive discovery view #333's +/// refusal roster (`bind_tap_plan`'s `UnknownTap`) deliberately deferred: +/// before this, the only way to learn a blueprint's declared tap names was +/// provoking that refusal. Loads exactly like `--params` (FILE gates the +/// authored root name, a store content id does not, C29). A tap-less +/// blueprint prints nothing to stdout — nothing was declared to list — plus a +/// stderr note (the `bind_tap_plan` unbound-this-run note's own "aura: note:" +/// convention), exit 0: a listing, not a fault. +fn taps_lines(target: &str, env: &aura_runner::project::Env) -> Result { + use std::fmt::Write as _; + let (text, is_file) = resolve_blueprint_text(target, env)?; + let composite = if is_file { composite_from_authored_text(&text, env)? } else { composite_from_any(&text, env)? }; + let taps = composite.declared_taps(); + if taps.is_empty() { + eprintln!("aura: note: {target} declares no taps"); + return Ok(String::new()); + } + let mut out = String::new(); + for (name, wire, kind) in taps { + let _ = writeln!(out, "{name} {wire} {kind:?}"); + } + Ok(out) +} + /// `aura graph register [--name