openpencil/crates/op-cli/src/cli_conversion.rs
Kayshen-X 0fc6753dd9 refactor(cli,mcp,web): typed error enums for the densest stringly paths
CliError/SkillInstallError carry every op-cli failure (94 sites),
ProgramError types batch_program (14), WebCanvasError maps route
failures onto their existing HTTP statuses (23 -> 6 deliberate
boundary adapters). Display output is byte-identical to the old
strings so caller-visible text and tests are unchanged.
2026-07-26 13:20:59 +08:00

116 lines
3.7 KiB
Rust

//! Code-to-design conversion command aliases.
use std::fs;
use super::{flag_value, pair, tool_call, Command, Flags};
use crate::cli_error::CliError;
pub(crate) fn map_design_conversion(
positionals: &[String],
flags: &Flags,
) -> Result<Command, CliError> {
match positionals[0].as_str() {
"design:upsert-vars" => map_upsert_variables(flags),
"design:upsert-component" => map_upsert_component(flags),
"design:upsert-screen" => map_upsert_screen(flags),
"design:status" => map_status(flags),
"design:lint" => map_lint(flags),
_ => unreachable!("caller guards design conversion command set"),
}
}
fn map_upsert_variables(flags: &Flags) -> Result<Command, CliError> {
let key = required_flag(
flags,
"key",
"Usage: op design:upsert-vars --key <key> --file vars.json",
)?;
let variables = read_payload_file(
flags,
"Usage: op design:upsert-vars --key <key> --file vars.json",
)?;
let mut args = vec![pair("key", key), pair("variables", variables)];
push_source_fields(&mut args, flags);
tool_call("upsert_variables", args)
}
fn map_upsert_component(flags: &Flags) -> Result<Command, CliError> {
let key = required_flag(
flags,
"key",
"Usage: op design:upsert-component --key <key> --name <name> --file node.json",
)?;
let name = required_flag(
flags,
"name",
"Usage: op design:upsert-component --key <key> --name <name> --file node.json",
)?;
let node_json = read_payload_file(
flags,
"Usage: op design:upsert-component --key <key> --name <name> --file node.json",
)?;
let mut args = vec![
pair("key", key),
pair("name", name),
pair("node_json", node_json),
];
push_source_fields(&mut args, flags);
tool_call("upsert_component", args)
}
fn map_upsert_screen(flags: &Flags) -> Result<Command, CliError> {
let key = required_flag(
flags,
"key",
"Usage: op design:upsert-screen --key <key> --file node.json",
)?;
let node_json = read_payload_file(
flags,
"Usage: op design:upsert-screen --key <key> --file node.json",
)?;
let mut args = vec![pair("key", key), pair("node_json", node_json)];
push_source_fields(&mut args, flags);
tool_call("upsert_screen", args)
}
fn map_status(flags: &Flags) -> Result<Command, CliError> {
let mut args = Vec::new();
if let Some(kind) = flag_value(flags, "kind") {
if !matches!(kind.as_str(), "token" | "component" | "screen") {
return Err(CliError::usage(
"--kind must be token, component, or screen",
));
}
args.push(pair("kind", kind));
}
tool_call("conversion_status", args)
}
fn map_lint(flags: &Flags) -> Result<Command, CliError> {
let mut args = Vec::new();
if let Some(node_id) = flag_value(flags, "node") {
args.push(pair("nodeId", node_id));
}
tool_call("lint_document", args)
}
fn required_flag(flags: &Flags, name: &str, usage: &str) -> Result<String, CliError> {
flag_value(flags, name).ok_or_else(|| CliError::usage(usage))
}
fn read_payload_file(flags: &Flags, usage: &str) -> Result<String, CliError> {
let path = required_flag(flags, "file", usage)?;
fs::read_to_string(&path)
.map(|contents| contents.trim().to_string())
.map_err(|e| CliError::Io(format!("cannot read --file {path:?}: {e}")))
}
fn push_source_fields(args: &mut Vec<(String, String)>, flags: &Flags) {
if let Some(source) = flag_value(flags, "source") {
args.push(pair("sourcePath", source));
}
if let Some(hash) = flag_value(flags, "hash") {
args.push(pair("sourceHash", hash));
}
}