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.
- soothe_cli/__init__.py +5 -0
- soothe_cli/cli/__init__.py +1 -0
- soothe_cli/cli/commands/__init__.py +1 -0
- soothe_cli/cli/commands/autopilot_cmd.py +410 -0
- soothe_cli/cli/commands/config_cmd.py +277 -0
- soothe_cli/cli/commands/run_cmd.py +87 -0
- soothe_cli/cli/commands/status_cmd.py +121 -0
- soothe_cli/cli/commands/subagent_names.py +17 -0
- soothe_cli/cli/commands/thread_cmd.py +657 -0
- soothe_cli/cli/execution/__init__.py +6 -0
- soothe_cli/cli/execution/daemon.py +194 -0
- soothe_cli/cli/execution/headless.py +99 -0
- soothe_cli/cli/execution/launcher.py +31 -0
- soothe_cli/cli/main.py +509 -0
- soothe_cli/cli/renderer.py +444 -0
- soothe_cli/cli/stream/__init__.py +17 -0
- soothe_cli/cli/stream/context.py +138 -0
- soothe_cli/cli/stream/display_line.py +83 -0
- soothe_cli/cli/stream/formatter.py +412 -0
- soothe_cli/cli/stream/pipeline.py +521 -0
- soothe_cli/cli/utils.py +46 -0
- soothe_cli/config/__init__.py +5 -0
- soothe_cli/config/cli_config.py +155 -0
- soothe_cli/plan/__init__.py +5 -0
- soothe_cli/plan/rich_tree.py +54 -0
- soothe_cli/shared/__init__.py +107 -0
- soothe_cli/shared/command_router.py +246 -0
- soothe_cli/shared/config_loader.py +68 -0
- soothe_cli/shared/display_policy.py +413 -0
- soothe_cli/shared/essential_events.py +68 -0
- soothe_cli/shared/event_processor.py +823 -0
- soothe_cli/shared/message_processing.py +393 -0
- soothe_cli/shared/presentation_engine.py +173 -0
- soothe_cli/shared/processor_state.py +80 -0
- soothe_cli/shared/renderer_protocol.py +158 -0
- soothe_cli/shared/rendering.py +43 -0
- soothe_cli/shared/slash_commands.py +354 -0
- soothe_cli/shared/subagent_routing.py +63 -0
- soothe_cli/shared/suppression_state.py +188 -0
- soothe_cli/shared/tool_formatters/__init__.py +27 -0
- soothe_cli/shared/tool_formatters/base.py +109 -0
- soothe_cli/shared/tool_formatters/execution.py +297 -0
- soothe_cli/shared/tool_formatters/fallback.py +128 -0
- soothe_cli/shared/tool_formatters/file_ops.py +299 -0
- soothe_cli/shared/tool_formatters/goal_formatter.py +331 -0
- soothe_cli/shared/tool_formatters/media.py +291 -0
- soothe_cli/shared/tool_formatters/structured.py +202 -0
- soothe_cli/shared/tool_formatters/web.py +143 -0
- soothe_cli/shared/tool_output_formatter.py +227 -0
- soothe_cli/shared/tui_trace_log.py +40 -0
- soothe_cli/tui/__init__.py +5 -0
- soothe_cli/tui/_ask_user_types.py +50 -0
- soothe_cli/tui/_cli_context.py +27 -0
- soothe_cli/tui/_env_vars.py +56 -0
- soothe_cli/tui/_session_stats.py +114 -0
- soothe_cli/tui/_version.py +21 -0
- soothe_cli/tui/app.py +4992 -0
- soothe_cli/tui/app.tcss +302 -0
- soothe_cli/tui/command_registry.py +310 -0
- soothe_cli/tui/config.py +2381 -0
- soothe_cli/tui/daemon_session.py +233 -0
- soothe_cli/tui/file_ops.py +409 -0
- soothe_cli/tui/formatting.py +28 -0
- soothe_cli/tui/hooks.py +23 -0
- soothe_cli/tui/input.py +782 -0
- soothe_cli/tui/media_utils.py +471 -0
- soothe_cli/tui/model_config.py +518 -0
- soothe_cli/tui/output.py +69 -0
- soothe_cli/tui/project_utils.py +188 -0
- soothe_cli/tui/sessions.py +1248 -0
- soothe_cli/tui/skills/__init__.py +5 -0
- soothe_cli/tui/skills/invocation.py +74 -0
- soothe_cli/tui/skills/load.py +93 -0
- soothe_cli/tui/textual_adapter.py +1430 -0
- soothe_cli/tui/theme.py +838 -0
- soothe_cli/tui/tool_display.py +297 -0
- soothe_cli/tui/unicode_security.py +502 -0
- soothe_cli/tui/update_check.py +447 -0
- soothe_cli/tui/widgets/__init__.py +9 -0
- soothe_cli/tui/widgets/_links.py +63 -0
- soothe_cli/tui/widgets/approval.py +430 -0
- soothe_cli/tui/widgets/ask_user.py +392 -0
- soothe_cli/tui/widgets/autocomplete.py +666 -0
- soothe_cli/tui/widgets/autopilot_dashboard.py +308 -0
- soothe_cli/tui/widgets/autopilot_screen.py +64 -0
- soothe_cli/tui/widgets/chat_input.py +1834 -0
- soothe_cli/tui/widgets/clipboard.py +128 -0
- soothe_cli/tui/widgets/diff.py +240 -0
- soothe_cli/tui/widgets/editor.py +140 -0
- soothe_cli/tui/widgets/history.py +221 -0
- soothe_cli/tui/widgets/loading.py +194 -0
- soothe_cli/tui/widgets/mcp_viewer.py +352 -0
- soothe_cli/tui/widgets/message_store.py +693 -0
- soothe_cli/tui/widgets/messages.py +1720 -0
- soothe_cli/tui/widgets/model_selector.py +988 -0
- soothe_cli/tui/widgets/notification_settings.py +155 -0
- soothe_cli/tui/widgets/status.py +403 -0
- soothe_cli/tui/widgets/theme_selector.py +158 -0
- soothe_cli/tui/widgets/thread_selector.py +1865 -0
- soothe_cli/tui/widgets/tool_renderers.py +148 -0
- soothe_cli/tui/widgets/tool_widgets.py +254 -0
- soothe_cli/tui/widgets/tools.py +165 -0
- soothe_cli/tui/widgets/welcome.py +330 -0
- soothe_cli-0.1.0.dist-info/METADATA +100 -0
- soothe_cli-0.1.0.dist-info/RECORD +107 -0
- soothe_cli-0.1.0.dist-info/WHEEL +4 -0
- 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
|
+
]
|