1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
//! Plugin CLI surface.
//!
//! Purpose:
//! - Plugin CLI surface.
//!
//! Responsibilities:
//! - Define Clap args for plugin management.
//!
//! Not handled here:
//! - Filesystem operations (see `crate::commands::plugin`).
//!
//!
//! Usage:
//! - Used through the crate module tree or integration test harness.
//!
//! Invariants/assumptions:
//! - `install` copies a plugin directory containing `plugin.json` into the chosen scope.
//! - Installing does NOT auto-enable the plugin (security).
use clap::{Args, Subcommand, ValueEnum};
use std::path::PathBuf;
#[derive(Args)]
pub struct PluginArgs {
#[command(subcommand)]
pub command: PluginCommand,
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, ValueEnum)]
pub enum PluginScopeArg {
Project,
Global,
}
#[derive(Args, Debug, Clone)]
#[command(
after_long_help = "Examples:\n cueloop plugin init acme.super_runner\n cueloop plugin init acme.super_runner --with-runner\n cueloop plugin init acme.super_runner --with-processor\n cueloop plugin init acme.super_runner --scope global\n cueloop plugin init acme.super_runner --dry-run\n"
)]
pub struct PluginInitArgs {
/// Plugin ID (used as directory name in default layout).
#[arg(value_name = "PLUGIN_ID")]
pub id: String,
/// Where to scaffold the plugin (ignored when --path is provided).
#[arg(long, value_enum, default_value = "project")]
pub scope: PluginScopeArg,
/// Target plugin directory (overrides --scope). Relative paths are resolved from repo root.
#[arg(long, value_name = "DIR")]
pub path: Option<PathBuf>,
/// Manifest name (default: derived from id).
#[arg(long)]
pub name: Option<String>,
/// Manifest version (SemVer string).
#[arg(long, default_value = "0.1.0")]
pub version: String,
/// Optional manifest description.
#[arg(long)]
pub description: Option<String>,
/// Include runner stub + runner manifest section.
#[arg(long)]
pub with_runner: bool,
/// Include processor stub + processors manifest section.
#[arg(long)]
pub with_processor: bool,
/// Preview what would be written without creating files.
#[arg(long)]
pub dry_run: bool,
/// Overwrite scaffolded files if the directory already exists.
#[arg(long)]
pub force: bool,
}
#[derive(Subcommand)]
pub enum PluginCommand {
/// List discovered plugins (global + project) and whether they are enabled.
#[command(after_long_help = "Examples:\n cueloop plugin list\n cueloop plugin list --json\n")]
List {
/// Output JSON instead of human-readable text.
#[arg(long)]
json: bool,
},
/// Validate discovered plugin manifests and referenced executables.
#[command(
after_long_help = "Examples:\n cueloop plugin validate\n cueloop plugin validate --id acme.super_runner\n"
)]
Validate {
/// Validate only a single plugin id.
#[arg(long)]
id: Option<String>,
},
/// Install a plugin from a local directory (must contain plugin.json).
#[command(
after_long_help = "Examples:\n cueloop plugin install ./my-plugin --scope project\n cueloop plugin install ./my-plugin --scope global\n\nNotes:\n - Install does not enable the plugin. Enable via config.plugins.plugins.<id>.enabled=true\n"
)]
Install {
/// Source directory containing plugin.json
source: String,
/// Install scope: project or global
#[arg(long, value_enum, default_value = "project")]
scope: PluginScopeArg,
},
/// Uninstall a plugin by id from the chosen scope.
#[command(
after_long_help = "Examples:\n cueloop plugin uninstall acme.super_runner --scope project\n"
)]
Uninstall {
id: String,
#[arg(long, value_enum, default_value = "project")]
scope: PluginScopeArg,
},
/// Scaffold a new plugin directory with plugin.json and optional scripts.
#[command(
after_long_help = "Examples:\n cueloop plugin init acme.super_runner\n cueloop plugin init acme.super_runner --with-runner\n cueloop plugin init acme.super_runner --with-processor\n cueloop plugin init acme.super_runner --scope global\n cueloop plugin init acme.super_runner --dry-run\n"
)]
Init(PluginInitArgs),
}