mecha10-cli-core 0.6.3

Mecha10 CLI core foundation — shared types, services, and utilities
Documentation
//! Node identity helpers shared across the CLI and its sibling binaries.
//!
//! A node has two name forms: scoped (`@mecha10/teleop`) and short (`teleop`). Various
//! callers (process tracking, log file naming, the remote-runtime supervisor) need to
//! normalize between the two, and previously reimplemented the same stripping logic
//! independently in several places. That drift caused a bug where node-runner's scoped
//! keys were compared against a bare `"teleop"` string because nothing routed through a
//! single shared normalization function. This is that function.

/// Strip a `@scope/name` node identifier down to its bare short name.
///
/// Plain (already-short) identifiers pass through unchanged, since there's no `/` to
/// split on.
///
/// # Examples
///
/// ```
/// use mecha10_cli_core::utils::strip_node_scope;
///
/// assert_eq!(strip_node_scope("@mecha10/teleop"), "teleop");
/// assert_eq!(strip_node_scope("teleop"), "teleop");
/// ```
pub fn strip_node_scope(identifier: &str) -> &str {
    identifier.rsplit('/').next().unwrap_or(identifier)
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn strips_scope_prefix() {
        assert_eq!(strip_node_scope("@mecha10/simulator"), "simulator");
        assert_eq!(strip_node_scope("@mecha10/video-streamer"), "video-streamer");
        assert_eq!(strip_node_scope("@mecha10/teleop"), "teleop");
    }

    #[test]
    fn leaves_plain_name_untouched() {
        assert_eq!(strip_node_scope("simulator"), "simulator");
        assert_eq!(strip_node_scope("teleop"), "teleop");
    }

    #[test]
    fn is_consistent_across_scoped_and_short_pairs() {
        let pairs = [
            ("@mecha10/object-detector", "object-detector"),
            ("@mecha10/image-classifier", "image-classifier"),
            ("@mecha10/llm-command", "llm-command"),
            ("@mecha10/behavior-executor", "behavior-executor"),
            ("@mecha10/diagnostics", "diagnostics"),
            ("@mecha10/imu", "imu"),
            ("@mecha10/listener", "listener"),
            ("@mecha10/motor", "motor"),
            ("@mecha10/speaker", "speaker"),
            ("@mecha10/teleop", "teleop"),
            ("@mecha10/websocket-bridge", "websocket-bridge"),
            ("teleop", "teleop"),
            ("simulator", "simulator"),
        ];

        for (scoped, short) in pairs {
            assert_eq!(
                strip_node_scope(scoped),
                short,
                "scoped form should strip to short form"
            );
            assert_eq!(
                strip_node_scope(short),
                short,
                "short form should pass through unchanged"
            );
        }
    }
}