Skip to main content

claude_wrapper/command/
plugin.rs

1//! Plugin subcommand builders.
2//!
3//! Builders for the `claude plugin` surface: list, install, uninstall,
4//! enable, disable, update, validate, details, prune, and tag. See
5//! [`crate::command::marketplace`] for managing the marketplaces
6//! plugins are installed from.
7
8#[cfg(feature = "async")]
9use crate::Claude;
10use crate::command::ClaudeCommand;
11#[cfg(feature = "async")]
12use crate::error::Result;
13#[cfg(feature = "async")]
14use crate::exec;
15use crate::exec::CommandOutput;
16use crate::types::Scope;
17
18/// List installed plugins.
19///
20/// # Example
21///
22/// ```no_run
23/// use claude_wrapper::{Claude, ClaudeCommand, PluginListCommand};
24///
25/// # async fn example() -> claude_wrapper::Result<()> {
26/// let claude = Claude::builder().build()?;
27/// let output = PluginListCommand::new().json().execute(&claude).await?;
28/// println!("{}", output.stdout);
29/// # Ok(())
30/// # }
31/// ```
32#[derive(Debug, Clone, Default)]
33pub struct PluginListCommand {
34    json: bool,
35    available: bool,
36}
37
38impl PluginListCommand {
39    /// Creates a new plugin list command.
40    #[must_use]
41    pub fn new() -> Self {
42        Self::default()
43    }
44
45    /// Output as JSON.
46    #[must_use]
47    pub fn json(mut self) -> Self {
48        self.json = true;
49        self
50    }
51
52    /// Include available plugins from marketplaces (requires `json()`).
53    #[must_use]
54    pub fn available(mut self) -> Self {
55        self.available = true;
56        self
57    }
58}
59
60impl ClaudeCommand for PluginListCommand {
61    type Output = CommandOutput;
62
63    fn args(&self) -> Vec<String> {
64        let mut args = vec!["plugin".to_string(), "list".to_string()];
65        if self.json {
66            args.push("--json".to_string());
67        }
68        if self.available {
69            args.push("--available".to_string());
70        }
71        args
72    }
73
74    #[cfg(feature = "async")]
75    async fn execute(&self, claude: &Claude) -> Result<CommandOutput> {
76        exec::run_claude(claude, self.args()).await
77    }
78}
79
80/// Install a plugin.
81///
82/// # Example
83///
84/// ```no_run
85/// use claude_wrapper::{Claude, ClaudeCommand, PluginInstallCommand, Scope};
86///
87/// # async fn example() -> claude_wrapper::Result<()> {
88/// let claude = Claude::builder().build()?;
89/// PluginInstallCommand::new("my-plugin")
90///     .scope(Scope::User)
91///     .execute(&claude)
92///     .await?;
93/// # Ok(())
94/// # }
95/// ```
96#[derive(Debug, Clone)]
97pub struct PluginInstallCommand {
98    plugin: String,
99    scope: Option<Scope>,
100    config: Vec<(String, String)>,
101}
102
103impl PluginInstallCommand {
104    /// Creates a command to install a plugin by name.
105    #[must_use]
106    pub fn new(plugin: impl Into<String>) -> Self {
107        Self {
108            plugin: plugin.into(),
109            scope: None,
110            config: Vec::new(),
111        }
112    }
113
114    /// Set the installation scope.
115    #[must_use]
116    pub fn scope(mut self, scope: Scope) -> Self {
117        self.scope = Some(scope);
118        self
119    }
120
121    /// Set a `userConfig` option declared in the plugin's manifest
122    /// (`--config key=value`). Repeatable; each call adds one option.
123    /// Values are validated against the manifest schema.
124    #[must_use]
125    pub fn config(mut self, key: impl Into<String>, value: impl Into<String>) -> Self {
126        self.config.push((key.into(), value.into()));
127        self
128    }
129}
130
131impl ClaudeCommand for PluginInstallCommand {
132    type Output = CommandOutput;
133
134    fn args(&self) -> Vec<String> {
135        let mut args = vec!["plugin".to_string(), "install".to_string()];
136        if let Some(ref scope) = self.scope {
137            args.push("--scope".to_string());
138            args.push(scope.as_arg().to_string());
139        }
140        for (key, value) in &self.config {
141            args.push("--config".to_string());
142            args.push(format!("{key}={value}"));
143        }
144        args.push(self.plugin.clone());
145        args
146    }
147
148    #[cfg(feature = "async")]
149    async fn execute(&self, claude: &Claude) -> Result<CommandOutput> {
150        exec::run_claude(claude, self.args()).await
151    }
152}
153
154/// Uninstall a plugin.
155///
156/// **Headless callers should pass [`Self::yes`]** -- the underlying
157/// CLI requires `-y` whenever stdin/stdout isn't a TTY and will
158/// otherwise wait on a prompt that no one is around to answer.
159#[derive(Debug, Clone)]
160pub struct PluginUninstallCommand {
161    plugin: String,
162    scope: Option<Scope>,
163    keep_data: bool,
164    prune: bool,
165    yes: bool,
166}
167
168impl PluginUninstallCommand {
169    /// Creates a command to uninstall a plugin by name.
170    #[must_use]
171    pub fn new(plugin: impl Into<String>) -> Self {
172        Self {
173            plugin: plugin.into(),
174            scope: None,
175            keep_data: false,
176            prune: false,
177            yes: false,
178        }
179    }
180
181    /// Set the scope.
182    #[must_use]
183    pub fn scope(mut self, scope: Scope) -> Self {
184        self.scope = Some(scope);
185        self
186    }
187
188    /// Preserve the plugin's persistent data directory
189    /// (`~/.claude/plugins/data/{id}/`) on uninstall (`--keep-data`).
190    /// Default: data is removed alongside the plugin.
191    #[must_use]
192    pub fn keep_data(mut self) -> Self {
193        self.keep_data = true;
194        self
195    }
196
197    /// Also remove auto-installed dependencies that are no longer
198    /// needed (`--prune`). Requires [`Self::yes`] in non-interactive
199    /// contexts (which the wrapper always is).
200    #[must_use]
201    pub fn prune(mut self) -> Self {
202        self.prune = true;
203        self
204    }
205
206    /// Skip the `--prune` confirmation prompt (`-y`). **Required for
207    /// non-TTY callers** -- without it, the CLI will hang waiting on
208    /// stdin. Every wrapper consumer running under `execute()` is
209    /// non-TTY by definition, so you almost always want this on.
210    #[must_use]
211    pub fn yes(mut self) -> Self {
212        self.yes = true;
213        self
214    }
215}
216
217impl ClaudeCommand for PluginUninstallCommand {
218    type Output = CommandOutput;
219
220    fn args(&self) -> Vec<String> {
221        let mut args = vec!["plugin".to_string(), "uninstall".to_string()];
222        if let Some(ref scope) = self.scope {
223            args.push("--scope".to_string());
224            args.push(scope.as_arg().to_string());
225        }
226        if self.keep_data {
227            args.push("--keep-data".to_string());
228        }
229        if self.prune {
230            args.push("--prune".to_string());
231        }
232        if self.yes {
233            args.push("--yes".to_string());
234        }
235        args.push(self.plugin.clone());
236        args
237    }
238
239    #[cfg(feature = "async")]
240    async fn execute(&self, claude: &Claude) -> Result<CommandOutput> {
241        exec::run_claude(claude, self.args()).await
242    }
243}
244
245/// Enable a disabled plugin.
246#[derive(Debug, Clone)]
247pub struct PluginEnableCommand {
248    plugin: String,
249    scope: Option<Scope>,
250}
251
252impl PluginEnableCommand {
253    /// Creates a command to enable a plugin by name.
254    #[must_use]
255    pub fn new(plugin: impl Into<String>) -> Self {
256        Self {
257            plugin: plugin.into(),
258            scope: None,
259        }
260    }
261
262    /// Set the scope.
263    #[must_use]
264    pub fn scope(mut self, scope: Scope) -> Self {
265        self.scope = Some(scope);
266        self
267    }
268}
269
270impl ClaudeCommand for PluginEnableCommand {
271    type Output = CommandOutput;
272
273    fn args(&self) -> Vec<String> {
274        let mut args = vec!["plugin".to_string(), "enable".to_string()];
275        if let Some(ref scope) = self.scope {
276            args.push("--scope".to_string());
277            args.push(scope.as_arg().to_string());
278        }
279        args.push(self.plugin.clone());
280        args
281    }
282
283    #[cfg(feature = "async")]
284    async fn execute(&self, claude: &Claude) -> Result<CommandOutput> {
285        exec::run_claude(claude, self.args()).await
286    }
287}
288
289/// Disable an enabled plugin.
290#[derive(Debug, Clone)]
291pub struct PluginDisableCommand {
292    plugin: Option<String>,
293    scope: Option<Scope>,
294    all: bool,
295}
296
297impl PluginDisableCommand {
298    /// Creates a command to disable a plugin by name. To disable all plugins, use [`PluginDisableCommand::all`].
299    #[must_use]
300    pub fn new(plugin: impl Into<String>) -> Self {
301        Self {
302            plugin: Some(plugin.into()),
303            scope: None,
304            all: false,
305        }
306    }
307
308    /// Disable all enabled plugins.
309    #[must_use]
310    pub fn all() -> Self {
311        Self {
312            plugin: None,
313            scope: None,
314            all: true,
315        }
316    }
317
318    /// Set the scope.
319    #[must_use]
320    pub fn scope(mut self, scope: Scope) -> Self {
321        self.scope = Some(scope);
322        self
323    }
324}
325
326impl ClaudeCommand for PluginDisableCommand {
327    type Output = CommandOutput;
328
329    fn args(&self) -> Vec<String> {
330        let mut args = vec!["plugin".to_string(), "disable".to_string()];
331        if self.all {
332            args.push("--all".to_string());
333        }
334        if let Some(ref scope) = self.scope {
335            args.push("--scope".to_string());
336            args.push(scope.as_arg().to_string());
337        }
338        if let Some(ref plugin) = self.plugin {
339            args.push(plugin.clone());
340        }
341        args
342    }
343
344    #[cfg(feature = "async")]
345    async fn execute(&self, claude: &Claude) -> Result<CommandOutput> {
346        exec::run_claude(claude, self.args()).await
347    }
348}
349
350/// Update a plugin to the latest version.
351#[derive(Debug, Clone)]
352pub struct PluginUpdateCommand {
353    plugin: String,
354    scope: Option<Scope>,
355}
356
357impl PluginUpdateCommand {
358    /// Creates a command to update a plugin to the latest version.
359    #[must_use]
360    pub fn new(plugin: impl Into<String>) -> Self {
361        Self {
362            plugin: plugin.into(),
363            scope: None,
364        }
365    }
366
367    /// Set the scope.
368    #[must_use]
369    pub fn scope(mut self, scope: Scope) -> Self {
370        self.scope = Some(scope);
371        self
372    }
373}
374
375impl ClaudeCommand for PluginUpdateCommand {
376    type Output = CommandOutput;
377
378    fn args(&self) -> Vec<String> {
379        let mut args = vec!["plugin".to_string(), "update".to_string()];
380        if let Some(ref scope) = self.scope {
381            args.push("--scope".to_string());
382            args.push(scope.as_arg().to_string());
383        }
384        args.push(self.plugin.clone());
385        args
386    }
387
388    #[cfg(feature = "async")]
389    async fn execute(&self, claude: &Claude) -> Result<CommandOutput> {
390        exec::run_claude(claude, self.args()).await
391    }
392}
393
394/// Validate a plugin or marketplace manifest.
395#[derive(Debug, Clone)]
396pub struct PluginValidateCommand {
397    path: String,
398}
399
400impl PluginValidateCommand {
401    /// Creates a command to validate a plugin manifest at the given path.
402    #[must_use]
403    pub fn new(path: impl Into<String>) -> Self {
404        Self { path: path.into() }
405    }
406}
407
408impl ClaudeCommand for PluginValidateCommand {
409    type Output = CommandOutput;
410
411    fn args(&self) -> Vec<String> {
412        vec![
413            "plugin".to_string(),
414            "validate".to_string(),
415            self.path.clone(),
416        ]
417    }
418
419    #[cfg(feature = "async")]
420    async fn execute(&self, claude: &Claude) -> Result<CommandOutput> {
421        exec::run_claude(claude, self.args()).await
422    }
423}
424
425/// Create a `{name}--v{version}` git tag for a plugin release.
426///
427/// Runs `claude plugin tag [path]`, validating that the plugin's
428/// `plugin.json` and any enclosing marketplace entry agree on the
429/// version before tagging.
430///
431/// # Example
432///
433/// ```no_run
434/// # #[cfg(feature = "async")] {
435/// use claude_wrapper::{Claude, ClaudeCommand, PluginTagCommand};
436///
437/// # async fn example() -> claude_wrapper::Result<()> {
438/// let claude = Claude::builder().build()?;
439/// let out = PluginTagCommand::new()
440///     .path("./my-plugin")
441///     .message("release %s")
442///     .push()
443///     .execute(&claude)
444///     .await?;
445/// println!("{}", out.stdout);
446/// # Ok(()) }
447/// # }
448/// ```
449#[derive(Debug, Clone, Default)]
450pub struct PluginTagCommand {
451    path: Option<String>,
452    dry_run: bool,
453    force: bool,
454    message: Option<String>,
455    push: bool,
456    remote: Option<String>,
457}
458
459impl PluginTagCommand {
460    /// Create a new tag command. Without [`path`](Self::path), the CLI
461    /// uses the current directory.
462    #[must_use]
463    pub fn new() -> Self {
464        Self::default()
465    }
466
467    /// Path to the plugin directory.
468    #[must_use]
469    pub fn path(mut self, path: impl Into<String>) -> Self {
470        self.path = Some(path.into());
471        self
472    }
473
474    /// Print what would be tagged without creating anything.
475    #[must_use]
476    pub fn dry_run(mut self) -> Self {
477        self.dry_run = true;
478        self
479    }
480
481    /// Skip dirty-working-tree and tag-already-exists checks.
482    #[must_use]
483    pub fn force(mut self) -> Self {
484        self.force = true;
485        self
486    }
487
488    /// Tag annotation message; `%s` is substituted with the version.
489    #[must_use]
490    pub fn message(mut self, msg: impl Into<String>) -> Self {
491        self.message = Some(msg.into());
492        self
493    }
494
495    /// Push the tag after creating it.
496    #[must_use]
497    pub fn push(mut self) -> Self {
498        self.push = true;
499        self
500    }
501
502    /// Override the remote pushed to with [`push`](Self::push) (default `origin`).
503    #[must_use]
504    pub fn remote(mut self, remote: impl Into<String>) -> Self {
505        self.remote = Some(remote.into());
506        self
507    }
508}
509
510impl ClaudeCommand for PluginTagCommand {
511    type Output = CommandOutput;
512
513    fn args(&self) -> Vec<String> {
514        let mut args = vec!["plugin".to_string(), "tag".to_string()];
515        if self.dry_run {
516            args.push("--dry-run".to_string());
517        }
518        if self.force {
519            args.push("--force".to_string());
520        }
521        if let Some(ref msg) = self.message {
522            args.push("--message".to_string());
523            args.push(msg.clone());
524        }
525        if self.push {
526            args.push("--push".to_string());
527        }
528        if let Some(ref remote) = self.remote {
529            args.push("--remote".to_string());
530            args.push(remote.clone());
531        }
532        if let Some(ref path) = self.path {
533            args.push(path.clone());
534        }
535        args
536    }
537
538    #[cfg(feature = "async")]
539    async fn execute(&self, claude: &Claude) -> Result<CommandOutput> {
540        exec::run_claude(claude, self.args()).await
541    }
542}
543
544/// Show a plugin's component inventory and projected token cost
545/// (`claude plugin details <name>`).
546#[derive(Debug, Clone)]
547pub struct PluginDetailsCommand {
548    plugin: String,
549}
550
551impl PluginDetailsCommand {
552    /// Create a details command for the given plugin name.
553    #[must_use]
554    pub fn new(plugin: impl Into<String>) -> Self {
555        Self {
556            plugin: plugin.into(),
557        }
558    }
559}
560
561impl ClaudeCommand for PluginDetailsCommand {
562    type Output = CommandOutput;
563
564    fn args(&self) -> Vec<String> {
565        vec![
566            "plugin".to_string(),
567            "details".to_string(),
568            self.plugin.clone(),
569        ]
570    }
571
572    #[cfg(feature = "async")]
573    async fn execute(&self, claude: &Claude) -> Result<CommandOutput> {
574        exec::run_claude(claude, self.args()).await
575    }
576}
577
578/// Remove auto-installed dependencies that are no longer needed
579/// (`claude plugin prune` -- alias `autoremove`).
580///
581/// Non-TTY callers should pass [`Self::yes`] -- the underlying CLI
582/// requires `-y` whenever stdin/stdout isn't a TTY and will
583/// otherwise wait on a confirmation prompt.
584#[derive(Debug, Clone, Default)]
585pub struct PluginPruneCommand {
586    dry_run: bool,
587    scope: Option<Scope>,
588    yes: bool,
589}
590
591impl PluginPruneCommand {
592    /// Create a new prune command.
593    #[must_use]
594    pub fn new() -> Self {
595        Self::default()
596    }
597
598    /// Print what would be removed without removing anything
599    /// (`--dry-run`).
600    #[must_use]
601    pub fn dry_run(mut self) -> Self {
602        self.dry_run = true;
603        self
604    }
605
606    /// Set the scope (`-s/--scope`). Default: `user`.
607    #[must_use]
608    pub fn scope(mut self, scope: Scope) -> Self {
609        self.scope = Some(scope);
610        self
611    }
612
613    /// Skip the confirmation prompt (`-y`). **Required for non-TTY
614    /// callers** -- without it the CLI will hang waiting on stdin.
615    #[must_use]
616    pub fn yes(mut self) -> Self {
617        self.yes = true;
618        self
619    }
620}
621
622impl ClaudeCommand for PluginPruneCommand {
623    type Output = CommandOutput;
624
625    fn args(&self) -> Vec<String> {
626        let mut args = vec!["plugin".to_string(), "prune".to_string()];
627        if self.dry_run {
628            args.push("--dry-run".to_string());
629        }
630        if let Some(ref scope) = self.scope {
631            args.push("--scope".to_string());
632            args.push(scope.as_arg().to_string());
633        }
634        if self.yes {
635            args.push("--yes".to_string());
636        }
637        args
638    }
639
640    #[cfg(feature = "async")]
641    async fn execute(&self, claude: &Claude) -> Result<CommandOutput> {
642        exec::run_claude(claude, self.args()).await
643    }
644}
645
646#[cfg(test)]
647mod tests {
648    use super::*;
649    use crate::command::ClaudeCommand;
650
651    #[test]
652    fn test_plugin_list() {
653        let cmd = PluginListCommand::new().json().available();
654        assert_eq!(
655            ClaudeCommand::args(&cmd),
656            vec!["plugin", "list", "--json", "--available"]
657        );
658    }
659
660    #[test]
661    fn test_plugin_install() {
662        let cmd = PluginInstallCommand::new("my-plugin").scope(Scope::User);
663        assert_eq!(
664            ClaudeCommand::args(&cmd),
665            vec!["plugin", "install", "--scope", "user", "my-plugin"]
666        );
667    }
668
669    #[test]
670    fn test_plugin_install_with_config() {
671        let cmd = PluginInstallCommand::new("my-plugin").config("k", "v");
672        assert_eq!(
673            ClaudeCommand::args(&cmd),
674            vec!["plugin", "install", "--config", "k=v", "my-plugin"]
675        );
676    }
677
678    #[test]
679    fn test_plugin_install_with_multiple_config() {
680        let cmd = PluginInstallCommand::new("my-plugin")
681            .config("a", "1")
682            .config("b", "2");
683        assert_eq!(
684            ClaudeCommand::args(&cmd),
685            vec![
686                "plugin",
687                "install",
688                "--config",
689                "a=1",
690                "--config",
691                "b=2",
692                "my-plugin"
693            ]
694        );
695    }
696
697    #[test]
698    fn test_plugin_install_with_scope_and_config() {
699        let cmd = PluginInstallCommand::new("my-plugin")
700            .scope(Scope::User)
701            .config("k", "v");
702        assert_eq!(
703            ClaudeCommand::args(&cmd),
704            vec![
705                "plugin",
706                "install",
707                "--scope",
708                "user",
709                "--config",
710                "k=v",
711                "my-plugin"
712            ]
713        );
714    }
715
716    #[test]
717    fn test_plugin_uninstall() {
718        let cmd = PluginUninstallCommand::new("old-plugin");
719        assert_eq!(
720            ClaudeCommand::args(&cmd),
721            vec!["plugin", "uninstall", "old-plugin"]
722        );
723    }
724
725    #[test]
726    fn test_plugin_uninstall_with_all_flags() {
727        let cmd = PluginUninstallCommand::new("old-plugin")
728            .scope(Scope::User)
729            .keep_data()
730            .prune()
731            .yes();
732        assert_eq!(
733            ClaudeCommand::args(&cmd),
734            vec![
735                "plugin",
736                "uninstall",
737                "--scope",
738                "user",
739                "--keep-data",
740                "--prune",
741                "--yes",
742                "old-plugin"
743            ]
744        );
745    }
746
747    #[test]
748    fn test_plugin_uninstall_yes_alone() {
749        // Most common headless case: just need to skip the prompt.
750        let cmd = PluginUninstallCommand::new("p").yes();
751        assert_eq!(
752            ClaudeCommand::args(&cmd),
753            vec!["plugin", "uninstall", "--yes", "p"]
754        );
755    }
756
757    #[test]
758    fn test_plugin_enable() {
759        let cmd = PluginEnableCommand::new("my-plugin").scope(Scope::Project);
760        assert_eq!(
761            ClaudeCommand::args(&cmd),
762            vec!["plugin", "enable", "--scope", "project", "my-plugin"]
763        );
764    }
765
766    #[test]
767    fn test_plugin_disable_specific() {
768        let cmd = PluginDisableCommand::new("my-plugin");
769        assert_eq!(
770            ClaudeCommand::args(&cmd),
771            vec!["plugin", "disable", "my-plugin"]
772        );
773    }
774
775    #[test]
776    fn test_plugin_disable_all() {
777        let cmd = PluginDisableCommand::all();
778        assert_eq!(
779            ClaudeCommand::args(&cmd),
780            vec!["plugin", "disable", "--all"]
781        );
782    }
783
784    #[test]
785    fn test_plugin_update() {
786        let cmd = PluginUpdateCommand::new("my-plugin").scope(Scope::Local);
787        assert_eq!(
788            ClaudeCommand::args(&cmd),
789            vec!["plugin", "update", "--scope", "local", "my-plugin"]
790        );
791    }
792
793    #[test]
794    fn test_plugin_validate() {
795        let cmd = PluginValidateCommand::new("/path/to/manifest");
796        assert_eq!(
797            ClaudeCommand::args(&cmd),
798            vec!["plugin", "validate", "/path/to/manifest"]
799        );
800    }
801
802    #[test]
803    fn plugin_tag_defaults_to_just_subcommand() {
804        let cmd = PluginTagCommand::new();
805        assert_eq!(ClaudeCommand::args(&cmd), vec!["plugin", "tag"]);
806    }
807
808    #[test]
809    fn plugin_tag_with_all_options() {
810        let cmd = PluginTagCommand::new()
811            .path("./plugin")
812            .dry_run()
813            .force()
814            .message("release %s")
815            .push()
816            .remote("upstream");
817        assert_eq!(
818            ClaudeCommand::args(&cmd),
819            vec![
820                "plugin",
821                "tag",
822                "--dry-run",
823                "--force",
824                "--message",
825                "release %s",
826                "--push",
827                "--remote",
828                "upstream",
829                "./plugin",
830            ]
831        );
832    }
833
834    #[test]
835    fn test_plugin_details() {
836        let cmd = PluginDetailsCommand::new("some-plugin");
837        assert_eq!(
838            ClaudeCommand::args(&cmd),
839            vec!["plugin", "details", "some-plugin"]
840        );
841    }
842
843    #[test]
844    fn test_plugin_prune_default() {
845        let cmd = PluginPruneCommand::new();
846        assert_eq!(ClaudeCommand::args(&cmd), vec!["plugin", "prune"]);
847    }
848
849    #[test]
850    fn test_plugin_prune_all_flags() {
851        let cmd = PluginPruneCommand::new().dry_run().scope(Scope::User).yes();
852        assert_eq!(
853            ClaudeCommand::args(&cmd),
854            vec!["plugin", "prune", "--dry-run", "--scope", "user", "--yes"]
855        );
856    }
857
858    #[test]
859    fn test_scope_managed_renders_as_arg() {
860        // `claude plugin update --scope managed` added in 2.1.143.
861        let cmd = PluginUpdateCommand::new("p").scope(Scope::Managed);
862        assert_eq!(
863            ClaudeCommand::args(&cmd),
864            vec!["plugin", "update", "--scope", "managed", "p"]
865        );
866    }
867}