emdash-cli 0.1.46__py3-none-any.whl → 0.1.70__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 (39) hide show
  1. emdash_cli/client.py +12 -28
  2. emdash_cli/commands/__init__.py +2 -2
  3. emdash_cli/commands/agent/constants.py +78 -0
  4. emdash_cli/commands/agent/handlers/__init__.py +10 -0
  5. emdash_cli/commands/agent/handlers/agents.py +67 -39
  6. emdash_cli/commands/agent/handlers/index.py +183 -0
  7. emdash_cli/commands/agent/handlers/misc.py +119 -0
  8. emdash_cli/commands/agent/handlers/registry.py +72 -0
  9. emdash_cli/commands/agent/handlers/rules.py +48 -31
  10. emdash_cli/commands/agent/handlers/sessions.py +1 -1
  11. emdash_cli/commands/agent/handlers/setup.py +187 -54
  12. emdash_cli/commands/agent/handlers/skills.py +42 -4
  13. emdash_cli/commands/agent/handlers/telegram.py +523 -0
  14. emdash_cli/commands/agent/handlers/todos.py +55 -34
  15. emdash_cli/commands/agent/handlers/verify.py +10 -5
  16. emdash_cli/commands/agent/help.py +236 -0
  17. emdash_cli/commands/agent/interactive.py +278 -47
  18. emdash_cli/commands/agent/menus.py +116 -84
  19. emdash_cli/commands/agent/onboarding.py +619 -0
  20. emdash_cli/commands/agent/session_restore.py +210 -0
  21. emdash_cli/commands/index.py +111 -13
  22. emdash_cli/commands/registry.py +635 -0
  23. emdash_cli/commands/skills.py +72 -6
  24. emdash_cli/design.py +328 -0
  25. emdash_cli/diff_renderer.py +438 -0
  26. emdash_cli/integrations/__init__.py +1 -0
  27. emdash_cli/integrations/telegram/__init__.py +15 -0
  28. emdash_cli/integrations/telegram/bot.py +402 -0
  29. emdash_cli/integrations/telegram/bridge.py +980 -0
  30. emdash_cli/integrations/telegram/config.py +155 -0
  31. emdash_cli/integrations/telegram/formatter.py +392 -0
  32. emdash_cli/main.py +52 -2
  33. emdash_cli/sse_renderer.py +632 -171
  34. {emdash_cli-0.1.46.dist-info → emdash_cli-0.1.70.dist-info}/METADATA +2 -2
  35. emdash_cli-0.1.70.dist-info/RECORD +63 -0
  36. emdash_cli/commands/swarm.py +0 -86
  37. emdash_cli-0.1.46.dist-info/RECORD +0 -49
  38. {emdash_cli-0.1.46.dist-info → emdash_cli-0.1.70.dist-info}/WHEEL +0 -0
  39. {emdash_cli-0.1.46.dist-info → emdash_cli-0.1.70.dist-info}/entry_points.txt +0 -0
@@ -2,6 +2,16 @@
2
2
 
3
3
  from rich.console import Console
4
4
 
5
+ from ....design import (
6
+ Colors,
7
+ header,
8
+ footer,
9
+ SEPARATOR_WIDTH,
10
+ STATUS_ACTIVE,
11
+ STATUS_INACTIVE,
12
+ DOT_BULLET,
13
+ )
14
+
5
15
  console = Console()
6
16
 
7
17
 
@@ -16,12 +26,19 @@ def handle_todos(args: str, client, session_id: str | None, pending_todos: list[
16
26
  """
17
27
  if not session_id:
18
28
  if pending_todos:
19
- console.print("\n[bold cyan]Pending Todos[/bold cyan] [dim](will be added when session starts)[/dim]\n")
20
- for i, todo in enumerate(pending_todos, 1):
21
- console.print(f" [dim][/dim] {todo}")
29
+ console.print()
30
+ console.print(f"[{Colors.MUTED}]{header('Pending Todos', SEPARATOR_WIDTH)}[/{Colors.MUTED}]")
31
+ console.print(f" [{Colors.DIM}]will be added when session starts[/{Colors.DIM}]")
32
+ console.print()
33
+ for todo in pending_todos:
34
+ console.print(f" [{Colors.MUTED}]○[/{Colors.MUTED}] {todo}")
35
+ console.print()
36
+ console.print(f"[{Colors.MUTED}]{footer(SEPARATOR_WIDTH)}[/{Colors.MUTED}]")
22
37
  console.print()
23
38
  else:
24
- console.print("\n[dim]No todos yet. Start a conversation and the agent will track its tasks here.[/dim]\n")
39
+ console.print()
40
+ console.print(f" [{Colors.DIM}]No todos yet. Start a conversation to track tasks.[/{Colors.DIM}]")
41
+ console.print()
25
42
  else:
26
43
  try:
27
44
  result = client.get_todos(session_id)
@@ -29,43 +46,41 @@ def handle_todos(args: str, client, session_id: str | None, pending_todos: list[
29
46
  summary = result.get("summary", {})
30
47
 
31
48
  if not todos:
32
- console.print("\n[dim]No todos in current session.[/dim]\n")
49
+ console.print()
50
+ console.print(f" [{Colors.DIM}]No todos in current session.[/{Colors.DIM}]")
51
+ console.print()
33
52
  else:
34
- console.print("\n[bold cyan]Agent Todo List[/bold cyan]\n")
35
-
36
- # Status icons
37
- icons = {
38
- "pending": "[dim]⬚[/dim]",
39
- "in_progress": "[yellow]🔄[/yellow]",
40
- "completed": "[green]✓[/green]",
41
- }
53
+ console.print()
54
+ console.print(f"[{Colors.MUTED}]{header('Todo List', SEPARATOR_WIDTH)}[/{Colors.MUTED}]")
55
+ console.print()
42
56
 
43
57
  for todo in todos:
44
- icon = icons.get(todo["status"], "?")
45
58
  title = todo["title"]
46
59
  status = todo["status"]
47
60
 
48
61
  if status == "completed":
49
- console.print(f" {icon} [dim strikethrough]{title}[/dim strikethrough]")
62
+ console.print(f" [{Colors.SUCCESS}]●[/{Colors.SUCCESS}] [{Colors.DIM} strike]{title}[/{Colors.DIM} strike]")
50
63
  elif status == "in_progress":
51
- console.print(f" {icon} [bold]{title}[/bold]")
64
+ console.print(f" [{Colors.WARNING}]◐[/{Colors.WARNING}] [{Colors.TEXT} bold]{title}[/{Colors.TEXT} bold]")
52
65
  else:
53
- console.print(f" {icon} {title}")
66
+ console.print(f" [{Colors.MUTED}]○[/{Colors.MUTED}] {title}")
54
67
 
55
68
  if todo.get("description"):
56
69
  desc = todo["description"]
57
- if len(desc) > 60:
58
- console.print(f" [dim]{desc[:60]}...[/dim]")
59
- else:
60
- console.print(f" [dim]{desc}[/dim]")
70
+ if len(desc) > 55:
71
+ desc = desc[:55] + "..."
72
+ console.print(f" [{Colors.DIM}]{desc}[/{Colors.DIM}]")
61
73
 
62
74
  console.print()
63
- console.print(
64
- f"[dim]Total: {summary.get('total', 0)} | "
65
- f"Pending: {summary.get('pending', 0)} | "
66
- f"In Progress: {summary.get('in_progress', 0)} | "
67
- f"Completed: {summary.get('completed', 0)}[/dim]"
68
- )
75
+ console.print(f"[{Colors.MUTED}]{footer(SEPARATOR_WIDTH)}[/{Colors.MUTED}]")
76
+
77
+ # Summary bar
78
+ total = summary.get('total', 0)
79
+ completed = summary.get('completed', 0)
80
+ in_progress = summary.get('in_progress', 0)
81
+ pending = summary.get('pending', 0)
82
+
83
+ console.print(f" [{Colors.DIM}]○ {pending}[/{Colors.DIM}] [{Colors.WARNING}]◐ {in_progress}[/{Colors.WARNING}] [{Colors.SUCCESS}]● {completed}[/{Colors.SUCCESS}] [{Colors.MUTED}]total {total}[/{Colors.MUTED}]")
69
84
  console.print()
70
85
 
71
86
  except Exception as e:
@@ -82,17 +97,23 @@ def handle_todo_add(args: str, client, session_id: str | None, pending_todos: li
82
97
  pending_todos: List of pending todos (before session starts)
83
98
  """
84
99
  if not args:
85
- console.print("[yellow]Usage: /todo-add <title>[/yellow]")
86
- console.print("[dim]Example: /todo-add Fix the failing tests[/dim]")
100
+ console.print()
101
+ console.print(f" [{Colors.WARNING}]Usage:[/{Colors.WARNING}] /todo-add <title>")
102
+ console.print(f" [{Colors.DIM}]Example: /todo-add Fix the failing tests[/{Colors.DIM}]")
103
+ console.print()
87
104
  elif not session_id:
88
105
  pending_todos.append(args)
89
- console.print(f"[green]Todo noted:[/green] {args}")
90
- console.print("[dim]This will be added to the agent's context when you start a conversation.[/dim]")
106
+ console.print()
107
+ console.print(f" [{Colors.SUCCESS}]{STATUS_ACTIVE}[/{Colors.SUCCESS}] [{Colors.MUTED}]noted:[/{Colors.MUTED}] {args}")
108
+ console.print(f" [{Colors.DIM}]will be added when session starts[/{Colors.DIM}]")
109
+ console.print()
91
110
  else:
92
111
  try:
93
112
  result = client.add_todo(session_id, args)
94
113
  task = result.get("task", {})
95
- console.print(f"[green]Added todo #{task.get('id')}: {task.get('title')}[/green]")
96
- console.print(f"[dim]Total tasks: {result.get('total_tasks', 0)}[/dim]")
114
+ console.print()
115
+ console.print(f" [{Colors.SUCCESS}]{STATUS_ACTIVE}[/{Colors.SUCCESS}] [{Colors.MUTED}]added:[/{Colors.MUTED}] {task.get('title')}")
116
+ console.print(f" [{Colors.DIM}]total: {result.get('total_tasks', 0)}[/{Colors.DIM}]")
117
+ console.print()
97
118
  except Exception as e:
98
- console.print(f"[red]Error adding todo: {e}[/red]")
119
+ console.print(f" [{Colors.ERROR}]error:[/{Colors.ERROR}] {e}")
@@ -480,14 +480,17 @@ def _run_verifiers(manager: VerifierManager) -> None:
480
480
  return
481
481
 
482
482
  console.print(f"[bold]Running {len(manager.verifiers)} verifier(s)...[/bold]")
483
- console.print()
484
483
 
485
484
  context = {
486
485
  "git_diff": get_git_diff(),
487
486
  "files_changed": get_changed_files(),
488
487
  }
489
488
 
490
- report = manager.run_all(context)
489
+ # Run with spinner for better UX
490
+ with console.status("[cyan]Running verifiers...", spinner="dots"):
491
+ report = manager.run_all(context)
492
+
493
+ console.print()
491
494
  display_report(report)
492
495
  console.print()
493
496
 
@@ -548,7 +551,6 @@ def run_verification(goal: str | None = None) -> tuple[VerificationReport, bool]
548
551
 
549
552
  console.print()
550
553
  console.print(f"[bold cyan]Running {len(manager.verifiers)} verifier(s)...[/bold cyan]")
551
- console.print()
552
554
 
553
555
  # Build context
554
556
  context = {
@@ -557,8 +559,11 @@ def run_verification(goal: str | None = None) -> tuple[VerificationReport, bool]
557
559
  "files_changed": get_changed_files(),
558
560
  }
559
561
 
560
- # Run verifiers
561
- report = manager.run_all(context)
562
+ # Run verifiers with spinner
563
+ with console.status("[cyan]Running verifiers...", spinner="dots"):
564
+ report = manager.run_all(context)
565
+
566
+ console.print()
562
567
 
563
568
  # Display results
564
569
  display_report(report)
@@ -0,0 +1,236 @@
1
+ """Contextual help system for emdash CLI.
2
+
3
+ Provides detailed help for commands with zen styling.
4
+ """
5
+
6
+ from rich.console import Console
7
+
8
+ from ...design import (
9
+ Colors,
10
+ STATUS_ACTIVE,
11
+ DOT_BULLET,
12
+ ARROW_PROMPT,
13
+ header,
14
+ footer,
15
+ SEPARATOR_WIDTH,
16
+ )
17
+
18
+ console = Console()
19
+
20
+ # Detailed help for each command
21
+ COMMAND_HELP = {
22
+ "/help": {
23
+ "description": "Show available commands and help",
24
+ "usage": ["/help", "/help <command>"],
25
+ "examples": ["/help", "/help agents"],
26
+ },
27
+ "/plan": {
28
+ "description": "Switch to plan mode for exploration and architecture",
29
+ "usage": ["/plan"],
30
+ "details": """Plan mode is read-only. The agent will explore your codebase,
31
+ analyze architecture, and create implementation plans without
32
+ making any changes.""",
33
+ "examples": ["/plan"],
34
+ },
35
+ "/code": {
36
+ "description": "Switch to code mode for implementation",
37
+ "usage": ["/code"],
38
+ "details": """Code mode allows the agent to make changes to your codebase.
39
+ Use this after approving a plan or for direct implementation tasks.""",
40
+ "examples": ["/code"],
41
+ },
42
+ "/agents": {
43
+ "description": "Manage custom agents for specialized tasks",
44
+ "usage": [
45
+ "/agents",
46
+ "/agents create <name>",
47
+ "/agents show <name>",
48
+ "/agents edit <name>",
49
+ "/agents delete <name>",
50
+ ],
51
+ "details": """Custom agents extend emdash with specialized capabilities.
52
+ Each agent has its own prompt, tools, and behavior configuration.""",
53
+ "examples": [
54
+ "/agents",
55
+ "/agents create code-reviewer",
56
+ "/agents edit planner",
57
+ ],
58
+ },
59
+ "/rules": {
60
+ "description": "Configure rules that guide agent behavior",
61
+ "usage": ["/rules", "/rules create", "/rules list"],
62
+ "details": """Rules define coding standards, preferences, and project
63
+ conventions. The agent follows these guidelines when working
64
+ on your codebase.""",
65
+ "examples": ["/rules", "/rules create"],
66
+ },
67
+ "/skills": {
68
+ "description": "Manage reusable skill templates",
69
+ "usage": ["/skills", "/skills create", "/skills list"],
70
+ "details": """Skills are reusable prompt templates that can be invoked
71
+ for common tasks like code review, testing, or documentation.""",
72
+ "examples": ["/skills", "/skills create"],
73
+ },
74
+ "/session": {
75
+ "description": "Manage conversation sessions",
76
+ "usage": ["/session", "/session save <name>", "/session load <name>"],
77
+ "details": """Sessions preserve conversation context. Save sessions to
78
+ continue work later or switch between different tasks.""",
79
+ "examples": [
80
+ "/session",
81
+ "/session save my-feature",
82
+ "/session load my-feature",
83
+ ],
84
+ },
85
+ "/verify": {
86
+ "description": "Run verification checks on the codebase",
87
+ "usage": ["/verify", "/verify <check>"],
88
+ "details": """Runs configured verifiers (tests, linting, type checking)
89
+ to ensure code quality. Use /verify-loop for automatic fixing.""",
90
+ "examples": ["/verify", "/verify tests"],
91
+ },
92
+ "/verify-loop": {
93
+ "description": "Run verification loop with automatic fixing",
94
+ "usage": ["/verify-loop <task>"],
95
+ "details": """Runs verifiers repeatedly, letting the agent fix issues
96
+ until all checks pass or you stop the loop.""",
97
+ "examples": ["/verify-loop fix the failing tests"],
98
+ },
99
+ "/pr": {
100
+ "description": "Review or create pull requests",
101
+ "usage": ["/pr <url>", "/pr create"],
102
+ "details": """Review GitHub pull requests or create new ones.
103
+ Provides detailed analysis of changes and suggestions.""",
104
+ "examples": [
105
+ "/pr https://github.com/org/repo/pull/123",
106
+ "/pr create",
107
+ ],
108
+ },
109
+ "/research": {
110
+ "description": "Research a topic using web search",
111
+ "usage": ["/research <query>"],
112
+ "details": """Searches the web for information and provides a summary.
113
+ Useful for finding documentation, examples, or solutions.""",
114
+ "examples": ["/research react hooks best practices"],
115
+ },
116
+ "/todos": {
117
+ "description": "View and manage task list",
118
+ "usage": ["/todos", "/todo-add <task>"],
119
+ "details": """Track tasks and progress. The agent can also add todos
120
+ during planning and implementation.""",
121
+ "examples": ["/todos", "/todo-add implement auth"],
122
+ },
123
+ "/context": {
124
+ "description": "View current context information",
125
+ "usage": ["/context"],
126
+ "details": """Shows token usage, context breakdown, and reranked items
127
+ in the current session.""",
128
+ "examples": ["/context"],
129
+ },
130
+ "/compact": {
131
+ "description": "Compact conversation context",
132
+ "usage": ["/compact"],
133
+ "details": """Summarizes the conversation to reduce context size while
134
+ preserving important information. Use when hitting limits.""",
135
+ "examples": ["/compact"],
136
+ },
137
+ "/status": {
138
+ "description": "Show current status and configuration",
139
+ "usage": ["/status"],
140
+ "details": """Displays current mode, model, session info, and
141
+ active configuration.""",
142
+ "examples": ["/status"],
143
+ },
144
+ "/doctor": {
145
+ "description": "Run diagnostic checks",
146
+ "usage": ["/doctor"],
147
+ "details": """Checks environment, dependencies, and configuration
148
+ for potential issues.""",
149
+ "examples": ["/doctor"],
150
+ },
151
+ "/auth": {
152
+ "description": "Manage authentication",
153
+ "usage": ["/auth login", "/auth logout", "/auth status"],
154
+ "details": """Connect or disconnect from GitHub. Authentication enables
155
+ PR reviews, issue management, and repository access.""",
156
+ "examples": ["/auth login", "/auth status"],
157
+ },
158
+ "/setup": {
159
+ "description": "Run interactive setup wizard",
160
+ "usage": ["/setup", "/setup rules", "/setup agents"],
161
+ "details": """AI-assisted setup for configuring rules, agents, skills,
162
+ and verifiers with templates and guidance.""",
163
+ "examples": ["/setup", "/setup rules"],
164
+ },
165
+ "/reset": {
166
+ "description": "Reset current session",
167
+ "usage": ["/reset"],
168
+ "details": """Clears the current session context. Use to start fresh
169
+ without closing the CLI.""",
170
+ "examples": ["/reset"],
171
+ },
172
+ "/quit": {
173
+ "description": "Exit emdash",
174
+ "usage": ["/quit", "/exit", "/q"],
175
+ "examples": ["/quit"],
176
+ },
177
+ }
178
+
179
+
180
+ def show_command_help(command: str) -> None:
181
+ """Show detailed help for a specific command."""
182
+ # Normalize command
183
+ if not command.startswith("/"):
184
+ command = "/" + command
185
+
186
+ help_info = COMMAND_HELP.get(command)
187
+
188
+ if not help_info:
189
+ console.print(f" [{Colors.ERROR}]Unknown command: {command}[/{Colors.ERROR}]")
190
+ console.print(f" [{Colors.DIM}]Type /help to see all commands[/{Colors.DIM}]")
191
+ return
192
+
193
+ console.print()
194
+ console.print(f"[{Colors.MUTED}]{header(command, SEPARATOR_WIDTH)}[/{Colors.MUTED}]")
195
+ console.print()
196
+ console.print(f" {help_info['description']}")
197
+ console.print()
198
+
199
+ # Usage
200
+ console.print(f" [{Colors.PRIMARY}]Usage:[/{Colors.PRIMARY}]")
201
+ for usage in help_info.get("usage", []):
202
+ console.print(f" {usage}")
203
+ console.print()
204
+
205
+ # Details
206
+ if "details" in help_info:
207
+ console.print(f" [{Colors.DIM}]{help_info['details']}[/{Colors.DIM}]")
208
+ console.print()
209
+
210
+ # Examples
211
+ if "examples" in help_info:
212
+ console.print(f" [{Colors.PRIMARY}]Examples:[/{Colors.PRIMARY}]")
213
+ for example in help_info["examples"]:
214
+ console.print(f" [{Colors.SUCCESS}]{example}[/{Colors.SUCCESS}]")
215
+ console.print()
216
+
217
+ console.print(f"[{Colors.MUTED}]{footer(SEPARATOR_WIDTH)}[/{Colors.MUTED}]")
218
+ console.print()
219
+
220
+
221
+ def show_quick_tips() -> None:
222
+ """Show quick tips for new users."""
223
+ console.print()
224
+ console.print(f"[{Colors.MUTED}]{header('Quick Tips', 35)}[/{Colors.MUTED}]")
225
+ console.print()
226
+ console.print(f" [{Colors.DIM}]Keyboard shortcuts:[/{Colors.DIM}]")
227
+ console.print(f" {DOT_BULLET} Ctrl+C to cancel")
228
+ console.print(f" {DOT_BULLET} Esc during execution to interrupt")
229
+ console.print(f" {DOT_BULLET} Alt+Enter for multiline input")
230
+ console.print()
231
+ console.print(f" [{Colors.DIM}]File references:[/{Colors.DIM}]")
232
+ console.print(f" {DOT_BULLET} Use @filename to include files")
233
+ console.print(f" {DOT_BULLET} Tab completion for @file paths")
234
+ console.print()
235
+ console.print(f"[{Colors.MUTED}]{footer(35)}[/{Colors.MUTED}]")
236
+ console.print()