emdash-cli 0.1.30__py3-none-any.whl → 0.1.46__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 (32) hide show
  1. emdash_cli/__init__.py +15 -0
  2. emdash_cli/client.py +156 -0
  3. emdash_cli/clipboard.py +30 -61
  4. emdash_cli/commands/agent/__init__.py +14 -0
  5. emdash_cli/commands/agent/cli.py +100 -0
  6. emdash_cli/commands/agent/constants.py +53 -0
  7. emdash_cli/commands/agent/file_utils.py +178 -0
  8. emdash_cli/commands/agent/handlers/__init__.py +41 -0
  9. emdash_cli/commands/agent/handlers/agents.py +421 -0
  10. emdash_cli/commands/agent/handlers/auth.py +69 -0
  11. emdash_cli/commands/agent/handlers/doctor.py +319 -0
  12. emdash_cli/commands/agent/handlers/hooks.py +121 -0
  13. emdash_cli/commands/agent/handlers/mcp.py +183 -0
  14. emdash_cli/commands/agent/handlers/misc.py +200 -0
  15. emdash_cli/commands/agent/handlers/rules.py +394 -0
  16. emdash_cli/commands/agent/handlers/sessions.py +168 -0
  17. emdash_cli/commands/agent/handlers/setup.py +582 -0
  18. emdash_cli/commands/agent/handlers/skills.py +440 -0
  19. emdash_cli/commands/agent/handlers/todos.py +98 -0
  20. emdash_cli/commands/agent/handlers/verify.py +648 -0
  21. emdash_cli/commands/agent/interactive.py +657 -0
  22. emdash_cli/commands/agent/menus.py +728 -0
  23. emdash_cli/commands/agent.py +7 -856
  24. emdash_cli/commands/server.py +99 -40
  25. emdash_cli/server_manager.py +70 -10
  26. emdash_cli/session_store.py +321 -0
  27. emdash_cli/sse_renderer.py +256 -110
  28. {emdash_cli-0.1.30.dist-info → emdash_cli-0.1.46.dist-info}/METADATA +2 -4
  29. emdash_cli-0.1.46.dist-info/RECORD +49 -0
  30. emdash_cli-0.1.30.dist-info/RECORD +0 -29
  31. {emdash_cli-0.1.30.dist-info → emdash_cli-0.1.46.dist-info}/WHEEL +0 -0
  32. {emdash_cli-0.1.30.dist-info → emdash_cli-0.1.46.dist-info}/entry_points.txt +0 -0
@@ -0,0 +1,168 @@
1
+ """Handler for /session command."""
2
+
3
+ from pathlib import Path
4
+
5
+ from rich.console import Console
6
+
7
+ from ..menus import show_sessions_interactive_menu, confirm_session_delete
8
+ from ..constants import AgentMode
9
+
10
+ console = Console()
11
+
12
+
13
+ def handle_session(
14
+ args: str,
15
+ client,
16
+ model: str | None,
17
+ session_id_ref: list,
18
+ current_spec_ref: list,
19
+ current_mode_ref: list,
20
+ loaded_messages_ref: list,
21
+ ) -> None:
22
+ """Handle /session command.
23
+
24
+ Args:
25
+ args: Command arguments
26
+ client: EmdashClient instance
27
+ model: Current model
28
+ session_id_ref: Reference to session_id (list wrapper for mutation)
29
+ current_spec_ref: Reference to current_spec (list wrapper for mutation)
30
+ current_mode_ref: Reference to current_mode (list wrapper for mutation)
31
+ loaded_messages_ref: Reference to loaded_messages (list wrapper for mutation)
32
+ """
33
+ from ...session_store import SessionStore
34
+
35
+ store = SessionStore(Path.cwd())
36
+
37
+ # Parse subcommand
38
+ subparts = args.split(maxsplit=1) if args else []
39
+ subcommand = subparts[0].lower() if subparts else ""
40
+ subargs = subparts[1].strip() if len(subparts) > 1 else ""
41
+
42
+ def _load_session(name: str) -> bool:
43
+ """Load a session by name. Returns True if successful."""
44
+ session_data = store.load_session(name)
45
+ if session_data:
46
+ session_id_ref[0] = None
47
+ current_spec_ref[0] = session_data.spec
48
+ if session_data.mode == "plan":
49
+ current_mode_ref[0] = AgentMode.PLAN
50
+ else:
51
+ current_mode_ref[0] = AgentMode.CODE
52
+ loaded_messages_ref[0] = session_data.messages
53
+ store.set_active_session(name)
54
+ console.print(f"[green]Loaded session '{name}'[/green]")
55
+ console.print(f"[dim]{len(session_data.messages)} messages restored, mode: {current_mode_ref[0].value}[/dim]")
56
+ if current_spec_ref[0]:
57
+ console.print("[dim]Spec restored[/dim]")
58
+ return True
59
+ else:
60
+ console.print(f"[yellow]Session '{name}' not found[/yellow]")
61
+ return False
62
+
63
+ def _delete_session(name: str) -> bool:
64
+ """Delete a session by name with confirmation."""
65
+ if confirm_session_delete(name):
66
+ success, msg = store.delete_session(name)
67
+ if success:
68
+ console.print(f"[green]{msg}[/green]")
69
+ return True
70
+ else:
71
+ console.print(f"[yellow]{msg}[/yellow]")
72
+ else:
73
+ console.print("[dim]Cancelled[/dim]")
74
+ return False
75
+
76
+ if subcommand == "" or subcommand == "list":
77
+ # Interactive menu (or list if no sessions)
78
+ sessions = store.list_sessions()
79
+ if sessions:
80
+ if subcommand == "list":
81
+ # Just list, don't show interactive menu
82
+ console.print("\n[bold cyan]Saved Sessions[/bold cyan]\n")
83
+ for s in sessions:
84
+ mode_color = "green" if s.mode == "code" else "yellow"
85
+ active_marker = " [bold green]*[/bold green]" if store.get_active_session() == s.name else ""
86
+ console.print(f" [cyan]{s.name}[/cyan]{active_marker} [{mode_color}]{s.mode}[/{mode_color}]")
87
+ console.print(f" [dim]{s.message_count} messages | {s.updated_at[:10]}[/dim]")
88
+ if s.summary:
89
+ summary = s.summary[:60] + "..." if len(s.summary) > 60 else s.summary
90
+ console.print(f" [dim]{summary}[/dim]")
91
+ console.print()
92
+ else:
93
+ # Interactive menu
94
+ while True:
95
+ action, session_name = show_sessions_interactive_menu(
96
+ sessions, store.get_active_session()
97
+ )
98
+ if action == "cancel":
99
+ break
100
+ elif action == "load":
101
+ _load_session(session_name)
102
+ break
103
+ elif action == "delete":
104
+ if _delete_session(session_name):
105
+ # Refresh sessions list
106
+ sessions = store.list_sessions()
107
+ if not sessions:
108
+ console.print("\n[dim]No more sessions.[/dim]\n")
109
+ break
110
+ # Continue showing menu
111
+ else:
112
+ console.print("\n[dim]No saved sessions.[/dim]")
113
+ console.print("[dim]Save with: /session save <name>[/dim]\n")
114
+
115
+ elif subcommand == "save":
116
+ if not subargs:
117
+ console.print("[yellow]Usage: /session save <name>[/yellow]")
118
+ console.print("[dim]Example: /session save auth-feature[/dim]")
119
+ else:
120
+ # Get current messages from the API session
121
+ if session_id_ref[0]:
122
+ try:
123
+ export_resp = client.get(f"/api/agent/chat/{session_id_ref[0]}/export")
124
+ if export_resp.status_code == 200:
125
+ data = export_resp.json()
126
+ messages = data.get("messages", [])
127
+ else:
128
+ messages = []
129
+ except Exception:
130
+ messages = []
131
+ else:
132
+ messages = []
133
+
134
+ success, msg = store.save_session(
135
+ name=subargs,
136
+ messages=messages,
137
+ mode=current_mode_ref[0].value,
138
+ spec=current_spec_ref[0],
139
+ model=model,
140
+ )
141
+ if success:
142
+ store.set_active_session(subargs)
143
+ console.print(f"[green]{msg}[/green]")
144
+ else:
145
+ console.print(f"[yellow]{msg}[/yellow]")
146
+
147
+ elif subcommand == "load":
148
+ if not subargs:
149
+ console.print("[yellow]Usage: /session load <name>[/yellow]")
150
+ else:
151
+ _load_session(subargs)
152
+
153
+ elif subcommand == "delete":
154
+ if not subargs:
155
+ console.print("[yellow]Usage: /session delete <name>[/yellow]")
156
+ else:
157
+ _delete_session(subargs)
158
+
159
+ elif subcommand == "clear":
160
+ session_id_ref[0] = None
161
+ current_spec_ref[0] = None
162
+ loaded_messages_ref[0] = []
163
+ store.set_active_session(None)
164
+ console.print("[green]Session cleared[/green]")
165
+
166
+ else:
167
+ console.print(f"[yellow]Unknown subcommand: {subcommand}[/yellow]")
168
+ console.print("[dim]Usage: /session [list|save|load|delete|clear] [name][/dim]")