greentic_dev/
cli.rs

1use std::path::PathBuf;
2
3use clap::{Args, Parser, Subcommand, ValueEnum};
4use greentic_component::cmd::{
5    build::BuildArgs as ComponentBuildArgs, doctor::DoctorArgs as ComponentDoctorArgs,
6    flow::FlowCommand as ComponentFlowCommand, hash::HashArgs as ComponentHashArgs,
7    inspect::InspectArgs as ComponentInspectArgs, new::NewArgs as ComponentNewArgs,
8    store::StoreCommand as ComponentStoreCommand,
9    templates::TemplatesArgs as ComponentTemplatesArgs,
10};
11
12#[derive(Parser, Debug)]
13#[command(name = "greentic-dev")]
14#[command(version)]
15#[command(about = "Greentic developer tooling CLI")]
16pub struct Cli {
17    #[command(subcommand)]
18    pub command: Command,
19}
20
21#[derive(Subcommand, Debug)]
22pub enum Command {
23    /// Flow tooling (validate, lint, bundle inspection)
24    #[command(subcommand)]
25    Flow(FlowCommand),
26    /// Pack tooling (delegates to packc for build/lint/sign/verify/new; uses greentic-pack for inspect/plan/events)
27    #[command(subcommand)]
28    Pack(PackCommand),
29    /// Component tooling (delegates to greentic-component built-ins + distributor add)
30    #[command(subcommand)]
31    Component(ComponentCommand),
32    /// Manage greentic-dev configuration
33    #[command(subcommand)]
34    Config(ConfigCommand),
35    /// MCP tooling
36    #[command(subcommand)]
37    Mcp(McpCommand),
38}
39
40#[derive(Subcommand, Debug)]
41pub enum FlowCommand {
42    /// Validate a flow YAML file and emit the canonical bundle JSON
43    Validate(FlowValidateArgs),
44    /// Add a configured component step to a flow via config-flow
45    AddStep(FlowAddStepArgs),
46}
47
48#[derive(Args, Debug)]
49pub struct FlowValidateArgs {
50    /// Path to the flow definition (YAML)
51    #[arg(short = 'f', long = "file")]
52    pub file: PathBuf,
53    /// Emit compact JSON instead of pretty-printing
54    #[arg(long = "json")]
55    pub json: bool,
56}
57
58#[derive(Args, Debug)]
59pub struct FlowAddStepArgs {
60    /// Path to component.manifest.json (defaults to ./component.manifest.json)
61    #[arg(long = "manifest")]
62    pub manifest: Option<PathBuf>,
63    /// Flow identifier inside manifest.dev_flows (default: default)
64    #[arg(long = "flow", default_value = "default")]
65    pub flow: String,
66    /// Flow identifier (maps to flows/<id>.ygtc)
67    pub flow_id: String,
68    /// Component coordinate (store://... or repo://...). If omitted, greentic-dev will prompt.
69    #[arg(long = "coordinate")]
70    pub coordinate: Option<String>,
71    /// Distributor profile to use (overrides GREENTIC_DISTRIBUTOR_PROFILE/env config)
72    #[arg(long = "profile")]
73    pub profile: Option<String>,
74    /// Config flow selection
75    #[arg(long = "mode", value_enum)]
76    pub mode: Option<ConfigFlowModeArg>,
77    /// Automatically append routing from an existing node (if provided)
78    #[arg(long = "after")]
79    pub after: Option<String>,
80}
81
82#[derive(Subcommand, Debug)]
83pub enum PackCommand {
84    /// Delegate to packc build
85    Build(PackcArgs),
86    /// Delegate to packc lint
87    Lint(PackcArgs),
88    /// Delegate to packc new
89    New(PackcArgs),
90    /// Delegate to packc sign
91    Sign(PackcArgs),
92    /// Delegate to packc verify
93    Verify(PackcArgs),
94    /// Inspect a .gtpack (or directory via temporary build)
95    Inspect(PackInspectArgs),
96    /// Generate a deployment plan
97    Plan(PackPlanArgs),
98    /// Events helpers
99    #[command(subcommand)]
100    Events(PackEventsCommand),
101    /// Execute a pack locally with mocks/telemetry support
102    Run(PackRunArgs),
103    /// Initialize a pack workspace from a remote coordinate
104    Init(PackInitArgs),
105}
106
107#[derive(Args, Debug)]
108pub struct PackRunArgs {
109    /// Path to the pack (.gtpack) to execute
110    #[arg(short = 'p', long = "pack")]
111    pub pack: PathBuf,
112    /// Flow entry identifier override
113    #[arg(long = "entry")]
114    pub entry: Option<String>,
115    /// JSON payload to use as run input
116    #[arg(long = "input")]
117    pub input: Option<String>,
118    /// Emit JSON output
119    #[arg(long = "json")]
120    pub json: bool,
121    /// Offline mode (disable network/proxy)
122    #[arg(long = "offline")]
123    pub offline: bool,
124    /// Use mock executor (internal/testing)
125    #[arg(long = "mock-exec", hide = true)]
126    pub mock_exec: bool,
127    /// Allow external calls in mock executor (default: false)
128    #[arg(long = "allow-external", hide = true)]
129    pub allow_external: bool,
130    /// Return mocked external responses when external calls are allowed (mock exec only)
131    #[arg(long = "mock-external", hide = true)]
132    pub mock_external: bool,
133    /// Path to JSON payload used for mocked external responses (mock exec only)
134    #[arg(long = "mock-external-payload", hide = true)]
135    pub mock_external_payload: Option<PathBuf>,
136    /// Prefix for env vars to load into the mock secrets store (mock exec only)
137    #[arg(long = "secrets-env-prefix", hide = true)]
138    pub secrets_env_prefix: Option<String>,
139    /// Enforcement policy for pack signatures
140    #[arg(long = "policy", default_value = "devok", value_enum)]
141    pub policy: RunPolicyArg,
142    /// OTLP collector endpoint (optional)
143    #[arg(long = "otlp")]
144    pub otlp: Option<String>,
145    /// Comma-separated list of allowed outbound hosts
146    #[arg(long = "allow")]
147    pub allow: Option<String>,
148    /// Mocks toggle
149    #[arg(long = "mocks", default_value = "on", value_enum)]
150    pub mocks: MockSettingArg,
151    /// Directory to persist run artifacts (transcripts, logs)
152    #[arg(long = "artifacts")]
153    pub artifacts: Option<PathBuf>,
154}
155
156#[derive(Args, Debug)]
157pub struct PackInitArgs {
158    /// Remote pack coordinate (e.g. pack://org/name@1.0.0)
159    pub from: String,
160    /// Distributor profile to use (overrides GREENTIC_DISTRIBUTOR_PROFILE/env config)
161    #[arg(long = "profile")]
162    pub profile: Option<String>,
163}
164
165#[derive(Args, Debug, Clone, Default)]
166#[command(disable_help_flag = true)]
167pub struct PackcArgs {
168    /// Arguments passed directly to the `packc` command
169    #[arg(
170        value_name = "ARGS",
171        trailing_var_arg = true,
172        allow_hyphen_values = true
173    )]
174    pub passthrough: Vec<String>,
175}
176
177#[derive(Args, Debug)]
178pub struct PackInspectArgs {
179    /// Path to the .gtpack file or pack directory
180    #[arg(value_name = "PATH")]
181    pub path: PathBuf,
182    /// Signature policy to enforce
183    #[arg(long, value_enum, default_value = "devok")]
184    pub policy: PackPolicyArg,
185    /// Emit JSON output
186    #[arg(long)]
187    pub json: bool,
188}
189
190#[derive(Subcommand, Debug)]
191pub enum PackEventsCommand {
192    /// List event providers declared in a pack
193    List(PackEventsListArgs),
194}
195
196#[derive(Args, Debug)]
197pub struct PackEventsListArgs {
198    /// Path to a .gtpack archive or pack source directory.
199    #[arg(value_name = "PATH")]
200    pub path: PathBuf,
201    /// Output format: table (default), json, yaml.
202    #[arg(long, value_enum, default_value = "table")]
203    pub format: PackEventsFormatArg,
204    /// When set, print additional diagnostics (for directory builds).
205    #[arg(long)]
206    pub verbose: bool,
207}
208
209#[derive(Args, Debug)]
210pub struct PackPlanArgs {
211    /// Path to a .gtpack archive or pack source directory.
212    #[arg(value_name = "PATH")]
213    pub input: PathBuf,
214    /// Tenant identifier to embed in the plan.
215    #[arg(long, default_value = "tenant-local")]
216    pub tenant: String,
217    /// Environment identifier to embed in the plan.
218    #[arg(long, default_value = "local")]
219    pub environment: String,
220    /// Emit compact JSON output instead of pretty-printing.
221    #[arg(long)]
222    pub json: bool,
223    /// When set, print additional diagnostics (for directory builds).
224    #[arg(long)]
225    pub verbose: bool,
226}
227
228#[derive(Subcommand, Debug, Clone)]
229pub enum ComponentCommand {
230    /// Add a remote component to the current workspace via the distributor
231    Add(ComponentAddArgs),
232    /// Scaffold a new Greentic component project
233    New(ComponentNewArgs),
234    /// List available component templates
235    Templates(ComponentTemplatesArgs),
236    /// Run component doctor checks
237    Doctor(ComponentDoctorArgs),
238    /// Inspect manifests and describe payloads
239    Inspect(ComponentInspectArgs),
240    /// Recompute manifest hashes
241    Hash(ComponentHashArgs),
242    /// Build component wasm + scaffold config flows
243    Build(ComponentBuildArgs),
244    /// Flow utilities (config flow scaffolding)
245    #[command(subcommand)]
246    Flow(ComponentFlowCommand),
247    /// Interact with the component store
248    #[command(subcommand)]
249    Store(ComponentStoreCommand),
250}
251
252#[derive(Args, Debug, Clone)]
253pub struct ComponentAddArgs {
254    /// Remote component coordinate (e.g. component://org/name@^1.0)
255    pub coordinate: String,
256    /// Distributor profile to use (overrides GREENTIC_DISTRIBUTOR_PROFILE/env config)
257    #[arg(long = "profile")]
258    pub profile: Option<String>,
259    /// Resolution intent (dev or runtime)
260    #[arg(long = "intent", default_value = "dev", value_enum)]
261    pub intent: DevIntentArg,
262}
263
264#[derive(Subcommand, Debug)]
265pub enum McpCommand {
266    /// Inspect MCP provider metadata
267    Doctor(McpDoctorArgs),
268}
269
270#[derive(Args, Debug)]
271pub struct McpDoctorArgs {
272    /// MCP provider identifier or config path
273    pub provider: String,
274    /// Emit compact JSON instead of pretty output
275    #[arg(long = "json")]
276    pub json: bool,
277}
278
279#[derive(Subcommand, Debug)]
280pub enum ConfigCommand {
281    /// Set a key in ~/.greentic/config.toml (e.g. defaults.component.org)
282    Set(ConfigSetArgs),
283}
284
285#[derive(Args, Debug)]
286pub struct ConfigSetArgs {
287    /// Config key path (e.g. defaults.component.org)
288    pub key: String,
289    /// Value to assign to the key (stored as a string)
290    pub value: String,
291    /// Override config file path (default: ~/.greentic/config.toml)
292    #[arg(long = "file")]
293    pub file: Option<PathBuf>,
294}
295
296#[derive(Copy, Clone, Debug, ValueEnum)]
297pub enum PackSignArg {
298    Dev,
299    None,
300}
301
302#[derive(Copy, Clone, Debug, ValueEnum)]
303pub enum PackPolicyArg {
304    Devok,
305    Strict,
306}
307
308#[derive(Copy, Clone, Debug, ValueEnum)]
309pub enum RunPolicyArg {
310    Strict,
311    Devok,
312}
313
314#[derive(Copy, Clone, Debug, ValueEnum)]
315pub enum VerifyPolicyArg {
316    Strict,
317    Devok,
318}
319
320#[derive(Copy, Clone, Debug, ValueEnum)]
321pub enum MockSettingArg {
322    On,
323    Off,
324}
325
326#[derive(Copy, Clone, Debug, ValueEnum)]
327pub enum PackEventsFormatArg {
328    Table,
329    Json,
330    Yaml,
331}
332
333#[derive(Copy, Clone, Debug, ValueEnum)]
334pub enum ConfigFlowModeArg {
335    Default,
336    Custom,
337}
338#[derive(Copy, Clone, Debug, ValueEnum)]
339pub enum DevIntentArg {
340    Dev,
341    Runtime,
342}
343
344#[cfg(test)]
345mod tests {}