emdash-cli 0.1.35__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.
- emdash_cli/client.py +35 -0
- emdash_cli/clipboard.py +30 -61
- emdash_cli/commands/agent/__init__.py +14 -0
- emdash_cli/commands/agent/cli.py +100 -0
- emdash_cli/commands/agent/constants.py +53 -0
- emdash_cli/commands/agent/file_utils.py +178 -0
- emdash_cli/commands/agent/handlers/__init__.py +41 -0
- emdash_cli/commands/agent/handlers/agents.py +421 -0
- emdash_cli/commands/agent/handlers/auth.py +69 -0
- emdash_cli/commands/agent/handlers/doctor.py +319 -0
- emdash_cli/commands/agent/handlers/hooks.py +121 -0
- emdash_cli/commands/agent/handlers/mcp.py +183 -0
- emdash_cli/commands/agent/handlers/misc.py +200 -0
- emdash_cli/commands/agent/handlers/rules.py +394 -0
- emdash_cli/commands/agent/handlers/sessions.py +168 -0
- emdash_cli/commands/agent/handlers/setup.py +582 -0
- emdash_cli/commands/agent/handlers/skills.py +440 -0
- emdash_cli/commands/agent/handlers/todos.py +98 -0
- emdash_cli/commands/agent/handlers/verify.py +648 -0
- emdash_cli/commands/agent/interactive.py +657 -0
- emdash_cli/commands/agent/menus.py +728 -0
- emdash_cli/commands/agent.py +7 -1321
- emdash_cli/commands/server.py +99 -40
- emdash_cli/server_manager.py +70 -10
- emdash_cli/sse_renderer.py +36 -5
- {emdash_cli-0.1.35.dist-info → emdash_cli-0.1.46.dist-info}/METADATA +2 -4
- emdash_cli-0.1.46.dist-info/RECORD +49 -0
- emdash_cli-0.1.35.dist-info/RECORD +0 -30
- {emdash_cli-0.1.35.dist-info → emdash_cli-0.1.46.dist-info}/WHEEL +0 -0
- {emdash_cli-0.1.35.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]")
|