soothe-cli 0.1.0__py3-none-any.whl

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.
Files changed (107) hide show
  1. soothe_cli/__init__.py +5 -0
  2. soothe_cli/cli/__init__.py +1 -0
  3. soothe_cli/cli/commands/__init__.py +1 -0
  4. soothe_cli/cli/commands/autopilot_cmd.py +410 -0
  5. soothe_cli/cli/commands/config_cmd.py +277 -0
  6. soothe_cli/cli/commands/run_cmd.py +87 -0
  7. soothe_cli/cli/commands/status_cmd.py +121 -0
  8. soothe_cli/cli/commands/subagent_names.py +17 -0
  9. soothe_cli/cli/commands/thread_cmd.py +657 -0
  10. soothe_cli/cli/execution/__init__.py +6 -0
  11. soothe_cli/cli/execution/daemon.py +194 -0
  12. soothe_cli/cli/execution/headless.py +99 -0
  13. soothe_cli/cli/execution/launcher.py +31 -0
  14. soothe_cli/cli/main.py +509 -0
  15. soothe_cli/cli/renderer.py +444 -0
  16. soothe_cli/cli/stream/__init__.py +17 -0
  17. soothe_cli/cli/stream/context.py +138 -0
  18. soothe_cli/cli/stream/display_line.py +83 -0
  19. soothe_cli/cli/stream/formatter.py +412 -0
  20. soothe_cli/cli/stream/pipeline.py +521 -0
  21. soothe_cli/cli/utils.py +46 -0
  22. soothe_cli/config/__init__.py +5 -0
  23. soothe_cli/config/cli_config.py +155 -0
  24. soothe_cli/plan/__init__.py +5 -0
  25. soothe_cli/plan/rich_tree.py +54 -0
  26. soothe_cli/shared/__init__.py +107 -0
  27. soothe_cli/shared/command_router.py +246 -0
  28. soothe_cli/shared/config_loader.py +68 -0
  29. soothe_cli/shared/display_policy.py +413 -0
  30. soothe_cli/shared/essential_events.py +68 -0
  31. soothe_cli/shared/event_processor.py +823 -0
  32. soothe_cli/shared/message_processing.py +393 -0
  33. soothe_cli/shared/presentation_engine.py +173 -0
  34. soothe_cli/shared/processor_state.py +80 -0
  35. soothe_cli/shared/renderer_protocol.py +158 -0
  36. soothe_cli/shared/rendering.py +43 -0
  37. soothe_cli/shared/slash_commands.py +354 -0
  38. soothe_cli/shared/subagent_routing.py +63 -0
  39. soothe_cli/shared/suppression_state.py +188 -0
  40. soothe_cli/shared/tool_formatters/__init__.py +27 -0
  41. soothe_cli/shared/tool_formatters/base.py +109 -0
  42. soothe_cli/shared/tool_formatters/execution.py +297 -0
  43. soothe_cli/shared/tool_formatters/fallback.py +128 -0
  44. soothe_cli/shared/tool_formatters/file_ops.py +299 -0
  45. soothe_cli/shared/tool_formatters/goal_formatter.py +331 -0
  46. soothe_cli/shared/tool_formatters/media.py +291 -0
  47. soothe_cli/shared/tool_formatters/structured.py +202 -0
  48. soothe_cli/shared/tool_formatters/web.py +143 -0
  49. soothe_cli/shared/tool_output_formatter.py +227 -0
  50. soothe_cli/shared/tui_trace_log.py +40 -0
  51. soothe_cli/tui/__init__.py +5 -0
  52. soothe_cli/tui/_ask_user_types.py +50 -0
  53. soothe_cli/tui/_cli_context.py +27 -0
  54. soothe_cli/tui/_env_vars.py +56 -0
  55. soothe_cli/tui/_session_stats.py +114 -0
  56. soothe_cli/tui/_version.py +21 -0
  57. soothe_cli/tui/app.py +4992 -0
  58. soothe_cli/tui/app.tcss +302 -0
  59. soothe_cli/tui/command_registry.py +310 -0
  60. soothe_cli/tui/config.py +2381 -0
  61. soothe_cli/tui/daemon_session.py +233 -0
  62. soothe_cli/tui/file_ops.py +409 -0
  63. soothe_cli/tui/formatting.py +28 -0
  64. soothe_cli/tui/hooks.py +23 -0
  65. soothe_cli/tui/input.py +782 -0
  66. soothe_cli/tui/media_utils.py +471 -0
  67. soothe_cli/tui/model_config.py +518 -0
  68. soothe_cli/tui/output.py +69 -0
  69. soothe_cli/tui/project_utils.py +188 -0
  70. soothe_cli/tui/sessions.py +1248 -0
  71. soothe_cli/tui/skills/__init__.py +5 -0
  72. soothe_cli/tui/skills/invocation.py +74 -0
  73. soothe_cli/tui/skills/load.py +93 -0
  74. soothe_cli/tui/textual_adapter.py +1430 -0
  75. soothe_cli/tui/theme.py +838 -0
  76. soothe_cli/tui/tool_display.py +297 -0
  77. soothe_cli/tui/unicode_security.py +502 -0
  78. soothe_cli/tui/update_check.py +447 -0
  79. soothe_cli/tui/widgets/__init__.py +9 -0
  80. soothe_cli/tui/widgets/_links.py +63 -0
  81. soothe_cli/tui/widgets/approval.py +430 -0
  82. soothe_cli/tui/widgets/ask_user.py +392 -0
  83. soothe_cli/tui/widgets/autocomplete.py +666 -0
  84. soothe_cli/tui/widgets/autopilot_dashboard.py +308 -0
  85. soothe_cli/tui/widgets/autopilot_screen.py +64 -0
  86. soothe_cli/tui/widgets/chat_input.py +1834 -0
  87. soothe_cli/tui/widgets/clipboard.py +128 -0
  88. soothe_cli/tui/widgets/diff.py +240 -0
  89. soothe_cli/tui/widgets/editor.py +140 -0
  90. soothe_cli/tui/widgets/history.py +221 -0
  91. soothe_cli/tui/widgets/loading.py +194 -0
  92. soothe_cli/tui/widgets/mcp_viewer.py +352 -0
  93. soothe_cli/tui/widgets/message_store.py +693 -0
  94. soothe_cli/tui/widgets/messages.py +1720 -0
  95. soothe_cli/tui/widgets/model_selector.py +988 -0
  96. soothe_cli/tui/widgets/notification_settings.py +155 -0
  97. soothe_cli/tui/widgets/status.py +403 -0
  98. soothe_cli/tui/widgets/theme_selector.py +158 -0
  99. soothe_cli/tui/widgets/thread_selector.py +1865 -0
  100. soothe_cli/tui/widgets/tool_renderers.py +148 -0
  101. soothe_cli/tui/widgets/tool_widgets.py +254 -0
  102. soothe_cli/tui/widgets/tools.py +165 -0
  103. soothe_cli/tui/widgets/welcome.py +330 -0
  104. soothe_cli-0.1.0.dist-info/METADATA +100 -0
  105. soothe_cli-0.1.0.dist-info/RECORD +107 -0
  106. soothe_cli-0.1.0.dist-info/WHEEL +4 -0
  107. soothe_cli-0.1.0.dist-info/entry_points.txt +2 -0
@@ -0,0 +1,87 @@
1
+ """Run command for Soothe CLI."""
2
+
3
+ import logging
4
+ import sys
5
+ import time
6
+ from pathlib import Path
7
+ from typing import Literal
8
+
9
+ import typer
10
+ from soothe_sdk import SOOTHE_HOME, VERBOSITY_TO_LOG_LEVEL
11
+
12
+ from soothe_cli.cli.execution import run_headless, run_tui
13
+ from soothe_cli.shared import load_config, setup_logging
14
+
15
+ logger = logging.getLogger(__name__)
16
+
17
+
18
+ def run_impl(
19
+ prompt: str | None,
20
+ config: str | None,
21
+ thread_id: str | None,
22
+ no_tui: bool, # noqa: FBT001
23
+ autonomous: bool, # noqa: FBT001
24
+ max_iterations: int | None,
25
+ output_format: str,
26
+ verbosity: Literal["quiet", "minimal", "normal", "detailed", "debug"] | None,
27
+ ) -> None:
28
+ """Core implementation for running Soothe agent.
29
+
30
+ Args:
31
+ prompt: Optional prompt for headless mode
32
+ config: Path to config file
33
+ thread_id: Thread ID to resume
34
+ no_tui: Force headless mode
35
+ autonomous: Enable autonomous iteration mode
36
+ max_iterations: Max iterations for autonomous mode
37
+ output_format: Output format (text or jsonl)
38
+ verbosity: Verbosity level
39
+ """
40
+ startup_start = time.perf_counter()
41
+
42
+ try:
43
+ cfg = load_config(config)
44
+ if verbosity is not None:
45
+ logging_config = cfg.logging.model_copy(update={"verbosity": verbosity})
46
+ cfg = cfg.model_copy(update={"logging": logging_config})
47
+ log_level = VERBOSITY_TO_LOG_LEVEL.get(cfg.logging.verbosity, "INFO")
48
+ log_file = Path(SOOTHE_HOME) / "logs" / "soothe-cli.log"
49
+ setup_logging(log_level, log_file=log_file)
50
+
51
+ # PostgreSQL availability check (requires daemon-side config)
52
+ if hasattr(cfg, "protocols") and hasattr(cfg.protocols, "durability"):
53
+ checkpointer = getattr(cfg.protocols.durability, "checkpointer", None)
54
+ if checkpointer == "postgresql":
55
+ logger.info("PostgreSQL checkpointer configured; ensure server is running.")
56
+
57
+ startup_elapsed_ms = (time.perf_counter() - startup_start) * 1000
58
+ logger.info("[Startup] ✓ Ready (%.1fms)", startup_elapsed_ms)
59
+
60
+ run_start = time.perf_counter()
61
+
62
+ if no_tui:
63
+ # Headless mode (force no TUI)
64
+ run_headless(
65
+ cfg,
66
+ prompt or "",
67
+ thread_id=thread_id,
68
+ output_format=output_format,
69
+ autonomous=autonomous,
70
+ max_iterations=max_iterations,
71
+ )
72
+ else:
73
+ # TUI mode (with optional initial prompt)
74
+ run_tui(cfg, thread_id=thread_id, config_path=config, initial_prompt=prompt)
75
+
76
+ run_elapsed_s = time.perf_counter() - run_start
77
+ typer.echo(f"Total running time: {run_elapsed_s:.2f}s", err=True)
78
+
79
+ except KeyboardInterrupt:
80
+ typer.echo("\nInterrupted.")
81
+ sys.exit(0)
82
+ except Exception as e:
83
+ logger.exception("CLI run error")
84
+ from soothe_sdk import format_cli_error
85
+
86
+ typer.echo(f"Error: {format_cli_error(e)}", err=True)
87
+ sys.exit(1)
@@ -0,0 +1,121 @@
1
+ """Status commands for Soothe CLI."""
2
+
3
+ import logging
4
+ import sys
5
+ from typing import Annotated
6
+
7
+ import typer
8
+
9
+ logger = logging.getLogger(__name__)
10
+
11
+
12
+ def agent_list(
13
+ config: Annotated[
14
+ str | None,
15
+ typer.Option("--config", "-c", help="Path to configuration file."),
16
+ ] = None,
17
+ enabled: Annotated[ # noqa: FBT002
18
+ bool,
19
+ typer.Option("--enabled", help="Show only enabled agents."),
20
+ ] = False,
21
+ disabled: Annotated[ # noqa: FBT002
22
+ bool,
23
+ typer.Option("--disabled", help="Show only disabled agents."),
24
+ ] = False,
25
+ ) -> None:
26
+ """List available agents and their status.
27
+
28
+ Examples:
29
+ soothe agent list
30
+ soothe agent list --enabled
31
+ soothe agent list --disabled
32
+ """
33
+ from soothe_cli.shared import load_config
34
+
35
+ try:
36
+ cfg = load_config(config)
37
+
38
+ from rich.console import Console
39
+ from rich.table import Table
40
+
41
+ from soothe_cli.cli.commands.subagent_names import (
42
+ BUILTIN_SUBAGENT_NAMES,
43
+ SUBAGENT_DISPLAY_NAMES,
44
+ )
45
+
46
+ table = Table(title="Available Agents")
47
+ table.add_column("Name", style="cyan")
48
+ table.add_column("Technical ID", style="yellow")
49
+ table.add_column("Status", justify="center")
50
+
51
+ for subagent_id in BUILTIN_SUBAGENT_NAMES:
52
+ is_enabled = True
53
+ if subagent_id in cfg.subagents:
54
+ is_enabled = cfg.subagents[subagent_id].enabled
55
+
56
+ # Filter by status
57
+ if enabled and not is_enabled:
58
+ continue
59
+ if disabled and is_enabled:
60
+ continue
61
+
62
+ display_name = SUBAGENT_DISPLAY_NAMES[subagent_id]
63
+ status = "[green]✓ enabled[/green]" if is_enabled else "[red]✗ disabled[/red]"
64
+ table.add_row(display_name, subagent_id, status)
65
+
66
+ console = Console()
67
+ console.print(table)
68
+
69
+ # Also show custom subagents if any
70
+ custom_subagents = set(cfg.subagents.keys()) - set(BUILTIN_SUBAGENT_NAMES)
71
+ if custom_subagents:
72
+ typer.echo("\nCustom agents:")
73
+ for subagent_id in sorted(custom_subagents):
74
+ is_enabled = cfg.subagents[subagent_id].enabled
75
+ status = "enabled" if is_enabled else "disabled"
76
+ typer.echo(f" - {subagent_id}: {status}")
77
+
78
+ except KeyboardInterrupt:
79
+ typer.echo("\nInterrupted.")
80
+ sys.exit(0)
81
+ except Exception as e:
82
+ logger.exception("Agent list error")
83
+ from soothe_sdk import format_cli_error
84
+
85
+ typer.echo(f"Error: {format_cli_error(e)}", err=True)
86
+ sys.exit(1)
87
+
88
+
89
+ def agent_status(
90
+ config: Annotated[
91
+ str | None,
92
+ typer.Option("--config", "-c", help="Path to configuration file."),
93
+ ] = None,
94
+ ) -> None:
95
+ """Show detailed agent status.
96
+
97
+ Examples:
98
+ soothe agent status
99
+ """
100
+ from soothe_cli.shared import load_config
101
+
102
+ try:
103
+ cfg = load_config(config)
104
+
105
+ typer.echo("\nAgent Status:")
106
+ typer.echo("-" * 50)
107
+ for name, sub_cfg in cfg.subagents.items():
108
+ status = "enabled" if sub_cfg.enabled else "disabled"
109
+ model = sub_cfg.model or cfg.resolve_model("default")
110
+ typer.echo(f" {name}: {status}")
111
+ typer.echo(f" Model: {model}")
112
+ typer.echo("-" * 50)
113
+ enabled_count = len([s for s in cfg.subagents.values() if s.enabled])
114
+ total_count = len(cfg.subagents)
115
+ typer.echo(f"\nTotal: {enabled_count}/{total_count} agents enabled")
116
+ except Exception as e:
117
+ logger.exception("Agent status error")
118
+ from soothe_sdk import format_cli_error
119
+
120
+ typer.echo(f"Error: {format_cli_error(e)}", err=True)
121
+ sys.exit(1)
@@ -0,0 +1,17 @@
1
+ """Subagent display names and routing helpers (CLI module path; implementation in shared)."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from soothe_cli.shared.subagent_routing import (
6
+ BUILTIN_SUBAGENT_NAMES,
7
+ SUBAGENT_DISPLAY_NAMES,
8
+ get_subagent_display_name,
9
+ parse_subagent_from_input,
10
+ )
11
+
12
+ __all__ = [
13
+ "BUILTIN_SUBAGENT_NAMES",
14
+ "SUBAGENT_DISPLAY_NAMES",
15
+ "get_subagent_display_name",
16
+ "parse_subagent_from_input",
17
+ ]