1use std::ffi::OsString;
2use std::process;
3
4use crate::cli::{FlowAddStepArgs, FlowAddStepMode, FlowValidateArgs};
5use crate::passthrough::{resolve_binary, run_passthrough};
6use crate::path_safety::normalize_under_root;
7use anyhow::{Context, Result};
8
9pub fn validate(args: FlowValidateArgs) -> Result<()> {
10 let root = std::env::current_dir()
11 .context("failed to resolve workspace root")?
12 .canonicalize()
13 .context("failed to canonicalize workspace root")?;
14 let safe = normalize_under_root(&root, &args.file)?;
15 let bin = resolve_binary("greentic-flow")?;
16 let mut passthrough_args: Vec<OsString> =
17 vec!["doctor".into(), "--flow".into(), safe.into_os_string()];
18 if args.json {
19 passthrough_args.push("--json".into());
20 }
21
22 let status = run_passthrough(&bin, &passthrough_args, false)?;
23 process::exit(status.code().unwrap_or(1));
24}
25
26pub fn doctor(args: FlowValidateArgs) -> Result<()> {
27 validate(args)
28}
29
30pub fn run_add_step(args: FlowAddStepArgs) -> Result<()> {
31 let root = std::env::current_dir()
32 .context("failed to resolve workspace root")?
33 .canonicalize()
34 .context("failed to canonicalize workspace root")?;
35 let flow = normalize_under_root(&root, &args.flow_path)?;
36
37 let bin = resolve_binary("greentic-flow")?;
38 let mut passthrough_args: Vec<OsString> =
39 vec!["add-step".into(), "--flow".into(), flow.into_os_string()];
40
41 if let Some(after) = args.after {
42 passthrough_args.push("--after".into());
43 passthrough_args.push(after.into());
44 }
45
46 match args.mode {
47 FlowAddStepMode::Default => {
48 if let Some(component) = args.component_id {
49 passthrough_args.push("--component".into());
50 passthrough_args.push(component.into());
51 }
52 if let Some(alias) = args.pack_alias {
53 passthrough_args.push("--pack-alias".into());
54 passthrough_args.push(alias.into());
55 }
56 if let Some(op) = args.operation {
57 passthrough_args.push("--operation".into());
58 passthrough_args.push(op.into());
59 }
60 passthrough_args.push("--payload".into());
61 passthrough_args.push(args.payload.into());
62 if let Some(routing) = args.routing {
63 passthrough_args.push("--routing".into());
64 passthrough_args.push(routing.into());
65 }
66 }
67 FlowAddStepMode::Config => {
68 passthrough_args.push("--mode".into());
69 passthrough_args.push("config".into());
70 if let Some(config) = args.config_flow {
71 passthrough_args.push("--config-flow".into());
72 passthrough_args.push(config.into_os_string());
73 }
74 if let Some(answers) = args.answers {
75 passthrough_args.push("--answers".into());
76 passthrough_args.push(answers.into());
77 }
78 if let Some(file) = args.answers_file {
79 passthrough_args.push("--answers-file".into());
80 passthrough_args.push(file.into_os_string());
81 }
82 }
83 }
84
85 if args.allow_cycles {
86 passthrough_args.push("--allow-cycles".into());
87 }
88 if args.write {
89 passthrough_args.push("--write".into());
90 }
91 if args.validate_only {
92 passthrough_args.push("--validate-only".into());
93 }
94 if let Some(node_id) = args.node_id {
95 passthrough_args.push("--node-id".into());
96 passthrough_args.push(node_id.into());
97 }
98 for manifest in args.manifests {
99 passthrough_args.push("--manifest".into());
100 passthrough_args.push(manifest.into_os_string());
101 }
102
103 let status = run_passthrough(&bin, &passthrough_args, args.verbose)?;
104 process::exit(status.code().unwrap_or(1));
105}