deepctl-cmd-plugin 0.1.12__tar.gz → 0.1.13__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -129,7 +129,8 @@ dmypy.json
129
129
 
130
130
  # uv
131
131
  .uv_cache/
132
- uv.lock
132
+ # uv.lock IS committed: it pins the dev/CI environment so every run tests
133
+ # the same versions and dependency drift arrives as a reviewable PR.
133
134
 
134
135
  # IDEs
135
136
  .vscode/
@@ -1,5 +1,13 @@
1
1
  # Changelog
2
2
 
3
+ ## [0.1.13](https://github.com/deepgram/cli/compare/deepctl-cmd-plugin-v0.1.12...deepctl-cmd-plugin-v0.1.13) (2026-09-23)
4
+
5
+
6
+ ### Bug Fixes
7
+
8
+ * **plugin:** return exit code 2, rather than success, when plugin removal is cancelled ([0dcfd2c](https://github.com/deepgram/cli/commit/0dcfd2c0d68a6095f4f6651e51ba6995f2b430d3))
9
+ * **plugin:** write the plugin-removal confirmation prompt to stderr so JSON output stays parseable ([0497ac1](https://github.com/deepgram/cli/commit/0497ac1892333c09d2a482f0b10ccd59d1f1dba2))
10
+
3
11
  ## [0.1.12](https://github.com/deepgram/cli/compare/deepctl-cmd-plugin-v0.1.11...deepctl-cmd-plugin-v0.1.12) (2026-05-09)
4
12
 
5
13
 
@@ -1,6 +1,6 @@
1
- Metadata-Version: 2.4
1
+ Metadata-Version: 2.5
2
2
  Name: deepctl-cmd-plugin
3
- Version: 0.1.12
3
+ Version: 0.1.13
4
4
  Summary: Plugin management command for deepctl
5
5
  Author-email: Deepgram DevRel <devrel@deepgram.com>
6
6
  Requires-Python: >=3.10
@@ -2,7 +2,7 @@
2
2
  name = "deepctl-cmd-plugin"
3
3
  description = "Plugin management command for deepctl"
4
4
  readme = "README.md"
5
- version = "0.1.12" # x-release-please-version
5
+ version = "0.1.13" # x-release-please-version
6
6
  requires-python = ">=3.10"
7
7
  authors = [{ name = "Deepgram DevRel", email = "devrel@deepgram.com" }]
8
8
  dependencies = [
@@ -474,8 +474,17 @@ class PluginCommand(BaseGroupCommand):
474
474
  package = kwargs["package"]
475
475
  yes = kwargs.get("yes", False)
476
476
 
477
- if not yes and not click.confirm(f"Are you sure you want to remove {package}?"):
478
- return
477
+ # err=True: the prompt is interaction, not output. Keeping it off
478
+ # stdout is what lets `dg plugin remove ... -o json` stay parseable,
479
+ # and matches the sibling prompt in deepctl-cmd-keys.
480
+ if not yes and not click.confirm(
481
+ f"Are you sure you want to remove {package}?", err=True
482
+ ):
483
+ # Abort rather than return: this is a group subcommand, so there is
484
+ # no result for BaseCommand.EXIT_CODES to map, and a bare return
485
+ # exits 0 -- indistinguishable from a successful removal. main.py
486
+ # turns Abort into the documented exit 2 for user cancellation.
487
+ raise click.Abort()
479
488
 
480
489
  result = self.remove_plugin(config, auth_manager, client, package)
481
490
 
@@ -4,6 +4,7 @@ import json
4
4
  from pathlib import Path
5
5
  from unittest.mock import MagicMock, patch
6
6
 
7
+ import click
7
8
  import pytest
8
9
  from click.testing import CliRunner
9
10
  from deepctl_cmd_plugin.command import PluginCommand
@@ -234,6 +235,54 @@ class TestPluginCommand:
234
235
  assert result.success is False
235
236
  assert "not installed" in result.message
236
237
 
238
+ def test_remove_declined_aborts_instead_of_exiting_zero(self) -> None:
239
+ """Declining the prompt must exit 2, not 0.
240
+
241
+ `_handle_remove` is a group subcommand returning None, so there is no
242
+ result for BaseCommand.EXIT_CODES to map to an exit code. A bare
243
+ return made a declined removal indistinguishable from a successful
244
+ one for any script branching on the exit code, contradicting the
245
+ contract published in the README. Abort is what main.py turns into 2.
246
+ """
247
+ with (
248
+ patch("click.confirm", return_value=False),
249
+ patch.object(self.command, "remove_plugin") as mock_remove,
250
+ ):
251
+ with pytest.raises(click.Abort):
252
+ self.command._handle_remove(
253
+ self.config,
254
+ self.auth_manager,
255
+ self.client,
256
+ package="test-plugin",
257
+ )
258
+
259
+ mock_remove.assert_not_called()
260
+
261
+ def test_remove_with_yes_skips_the_prompt(self) -> None:
262
+ """Positive control: --yes must not prompt and must not abort."""
263
+ with (
264
+ patch("click.confirm") as mock_confirm,
265
+ patch.object(self.command, "remove_plugin") as mock_remove,
266
+ patch.object(self.command, "_maybe_update_skills"),
267
+ ):
268
+ mock_remove.return_value = PluginOperationResult(
269
+ success=True,
270
+ action="remove",
271
+ package="test-plugin",
272
+ message="Successfully removed test-plugin",
273
+ )
274
+
275
+ self.command._handle_remove(
276
+ self.config,
277
+ self.auth_manager,
278
+ self.client,
279
+ package="test-plugin",
280
+ yes=True,
281
+ )
282
+
283
+ mock_confirm.assert_not_called()
284
+ mock_remove.assert_called_once()
285
+
237
286
  @patch("deepctl_cmd_plugin.command.subprocess.run")
238
287
  def test_discover_from_environment(self, mock_run: MagicMock) -> None:
239
288
  """Test discovering plugins from a specific environment."""