@anastops/cli 1.0.0 → 1.2.0
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.
- package/dist/commands/doctor.d.ts.map +1 -1
- package/dist/commands/doctor.js +8 -6
- package/dist/commands/doctor.js.map +1 -1
- package/dist/commands/init.d.ts +17 -0
- package/dist/commands/init.d.ts.map +1 -1
- package/dist/commands/init.js +315 -17
- package/dist/commands/init.js.map +1 -1
- package/dist/commands/ranger.d.ts +7 -2
- package/dist/commands/ranger.d.ts.map +1 -1
- package/dist/commands/ranger.js +99 -21
- package/dist/commands/ranger.js.map +1 -1
- package/dist/commands/uninstall.d.ts +16 -0
- package/dist/commands/uninstall.d.ts.map +1 -0
- package/dist/commands/uninstall.js +206 -0
- package/dist/commands/uninstall.js.map +1 -0
- package/dist/index.js +11 -0
- package/dist/index.js.map +1 -1
- package/package.json +8 -6
- package/ranger-tui/pyproject.toml +51 -0
- package/ranger-tui/ranger_tui/__init__.py +5 -0
- package/ranger-tui/ranger_tui/__main__.py +16 -0
- package/ranger-tui/ranger_tui/__pycache__/__init__.cpython-314.pyc +0 -0
- package/ranger-tui/ranger_tui/__pycache__/__main__.cpython-314.pyc +0 -0
- package/ranger-tui/ranger_tui/__pycache__/accessibility.cpython-314.pyc +0 -0
- package/ranger-tui/ranger_tui/__pycache__/app.cpython-314.pyc +0 -0
- package/ranger-tui/ranger_tui/__pycache__/config.cpython-314.pyc +0 -0
- package/ranger-tui/ranger_tui/__pycache__/theme.cpython-314.pyc +0 -0
- package/ranger-tui/ranger_tui/accessibility.py +499 -0
- package/ranger-tui/ranger_tui/actions/__init__.py +13 -0
- package/ranger-tui/ranger_tui/actions/agent_actions.py +74 -0
- package/ranger-tui/ranger_tui/actions/session_actions.py +110 -0
- package/ranger-tui/ranger_tui/actions/task_actions.py +107 -0
- package/ranger-tui/ranger_tui/app.py +93 -0
- package/ranger-tui/ranger_tui/assets/ranger_head.png +0 -0
- package/ranger-tui/ranger_tui/config.py +100 -0
- package/ranger-tui/ranger_tui/data/__init__.py +16 -0
- package/ranger-tui/ranger_tui/data/__pycache__/__init__.cpython-314.pyc +0 -0
- package/ranger-tui/ranger_tui/data/__pycache__/client.cpython-314.pyc +0 -0
- package/ranger-tui/ranger_tui/data/__pycache__/models.cpython-314.pyc +0 -0
- package/ranger-tui/ranger_tui/data/client.py +858 -0
- package/ranger-tui/ranger_tui/data/models.py +151 -0
- package/ranger-tui/ranger_tui/screens/__init__.py +16 -0
- package/ranger-tui/ranger_tui/screens/__pycache__/__init__.cpython-314.pyc +0 -0
- package/ranger-tui/ranger_tui/screens/__pycache__/dashboard.cpython-314.pyc +0 -0
- package/ranger-tui/ranger_tui/screens/__pycache__/modals.cpython-314.pyc +0 -0
- package/ranger-tui/ranger_tui/screens/__pycache__/session.cpython-314.pyc +0 -0
- package/ranger-tui/ranger_tui/screens/__pycache__/task.cpython-314.pyc +0 -0
- package/ranger-tui/ranger_tui/screens/command_palette.py +357 -0
- package/ranger-tui/ranger_tui/screens/dashboard.py +232 -0
- package/ranger-tui/ranger_tui/screens/help.py +103 -0
- package/ranger-tui/ranger_tui/screens/modals.py +95 -0
- package/ranger-tui/ranger_tui/screens/session.py +289 -0
- package/ranger-tui/ranger_tui/screens/task.py +187 -0
- package/ranger-tui/ranger_tui/styles/ranger.tcss +254 -0
- package/ranger-tui/ranger_tui/theme.py +93 -0
- package/ranger-tui/ranger_tui/widgets/__init__.py +23 -0
- package/ranger-tui/ranger_tui/widgets/__pycache__/__init__.cpython-314.pyc +0 -0
- package/ranger-tui/ranger_tui/widgets/__pycache__/accessible.cpython-314.pyc +0 -0
- package/ranger-tui/ranger_tui/widgets/__pycache__/logo.cpython-314.pyc +0 -0
- package/ranger-tui/ranger_tui/widgets/__pycache__/logo_assets.cpython-314.pyc +0 -0
- package/ranger-tui/ranger_tui/widgets/__pycache__/ranger_image.cpython-314.pyc +0 -0
- package/ranger-tui/ranger_tui/widgets/__pycache__/sidebar.cpython-314.pyc +0 -0
- package/ranger-tui/ranger_tui/widgets/__pycache__/topbar.cpython-314.pyc +0 -0
- package/ranger-tui/ranger_tui/widgets/accessible.py +176 -0
- package/ranger-tui/ranger_tui/widgets/agents_table.py +151 -0
- package/ranger-tui/ranger_tui/widgets/header.py +141 -0
- package/ranger-tui/ranger_tui/widgets/logo.py +258 -0
- package/ranger-tui/ranger_tui/widgets/logo_assets.py +62 -0
- package/ranger-tui/ranger_tui/widgets/metrics_panel.py +121 -0
- package/ranger-tui/ranger_tui/widgets/ranger_image.py +91 -0
- package/ranger-tui/ranger_tui/widgets/sessions_table.py +191 -0
- package/ranger-tui/ranger_tui/widgets/sidebar.py +91 -0
- package/ranger-tui/ranger_tui/widgets/tasks_table.py +189 -0
- package/ranger-tui/ranger_tui/widgets/topbar.py +168 -0
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Pydantic models for Anastops data types.
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
from datetime import datetime
|
|
6
|
+
from typing import Optional, Any
|
|
7
|
+
from pydantic import BaseModel, Field
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class TokenUsage(BaseModel):
|
|
11
|
+
"""Token usage metrics."""
|
|
12
|
+
prompt_tokens: int = 0
|
|
13
|
+
completion_tokens: int = 0
|
|
14
|
+
total_tokens: int = 0
|
|
15
|
+
cost: float = 0.0
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
class SessionMetadata(BaseModel):
|
|
19
|
+
"""Session metadata."""
|
|
20
|
+
total_tokens: int = 0
|
|
21
|
+
total_cost: float = 0.0
|
|
22
|
+
agents_used: list[str] = Field(default_factory=list)
|
|
23
|
+
files_affected: list[str] = Field(default_factory=list)
|
|
24
|
+
tasks_total: int = 0
|
|
25
|
+
tasks_completed: int = 0
|
|
26
|
+
tasks_failed: int = 0
|
|
27
|
+
tasks_running: int = 0
|
|
28
|
+
tasks_pending: int = 0
|
|
29
|
+
tasks_queued: int = 0
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
class Session(BaseModel):
|
|
33
|
+
"""Orchestration session."""
|
|
34
|
+
id: str
|
|
35
|
+
user_id: str = "local"
|
|
36
|
+
parent_session_id: Optional[str] = None
|
|
37
|
+
fork_point: Optional[int] = None
|
|
38
|
+
fork_reason: Optional[str] = None
|
|
39
|
+
status: str = "active"
|
|
40
|
+
objective: str
|
|
41
|
+
created_at: datetime
|
|
42
|
+
updated_at: datetime
|
|
43
|
+
metadata: SessionMetadata = Field(default_factory=SessionMetadata)
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
class TaskInput(BaseModel):
|
|
47
|
+
"""Task input data."""
|
|
48
|
+
prompt: str = ""
|
|
49
|
+
context_files: list[str] = Field(default_factory=list)
|
|
50
|
+
agent: Optional[str] = None
|
|
51
|
+
skills: list[str] = Field(default_factory=list)
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
class TaskOutput(BaseModel):
|
|
55
|
+
"""Task output data."""
|
|
56
|
+
content: str = ""
|
|
57
|
+
artifacts: list[str] = Field(default_factory=list)
|
|
58
|
+
files_modified: list[str] = Field(default_factory=list)
|
|
59
|
+
metadata: dict[str, Any] = Field(default_factory=dict)
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
class Task(BaseModel):
|
|
63
|
+
"""Orchestration task."""
|
|
64
|
+
id: str
|
|
65
|
+
session_id: str
|
|
66
|
+
agent_id: Optional[str] = None
|
|
67
|
+
type: str = "other"
|
|
68
|
+
status: str = "pending"
|
|
69
|
+
description: str
|
|
70
|
+
input: TaskInput = Field(default_factory=TaskInput)
|
|
71
|
+
output: Optional[TaskOutput] = None
|
|
72
|
+
error: Optional[str] = None
|
|
73
|
+
complexity_score: int = 0
|
|
74
|
+
routing_tier: int = 3
|
|
75
|
+
provider: str = "claude"
|
|
76
|
+
model: str = "claude-sonnet"
|
|
77
|
+
token_usage: TokenUsage = Field(default_factory=TokenUsage)
|
|
78
|
+
created_at: datetime
|
|
79
|
+
started_at: Optional[datetime] = None
|
|
80
|
+
completed_at: Optional[datetime] = None
|
|
81
|
+
dependencies: list[str] = Field(default_factory=list)
|
|
82
|
+
priority: int = 5
|
|
83
|
+
retry_count: int = 0
|
|
84
|
+
max_retries: int = 3
|
|
85
|
+
logs: Optional[str] = None # Streaming logs captured during execution
|
|
86
|
+
|
|
87
|
+
|
|
88
|
+
class Agent(BaseModel):
|
|
89
|
+
"""AI agent."""
|
|
90
|
+
id: str
|
|
91
|
+
session_id: str
|
|
92
|
+
role: str = "implementer"
|
|
93
|
+
name: str
|
|
94
|
+
status: str = "idle"
|
|
95
|
+
provider: str = "claude"
|
|
96
|
+
model: str = "claude-sonnet"
|
|
97
|
+
current_task_id: Optional[str] = None
|
|
98
|
+
tasks_completed: int = 0
|
|
99
|
+
tasks_failed: int = 0
|
|
100
|
+
tokens_used: int = 0
|
|
101
|
+
created_at: datetime
|
|
102
|
+
last_activity_at: datetime
|
|
103
|
+
config: dict[str, Any] = Field(default_factory=dict)
|
|
104
|
+
|
|
105
|
+
|
|
106
|
+
class Artifact(BaseModel):
|
|
107
|
+
"""Generated artifact."""
|
|
108
|
+
id: str
|
|
109
|
+
session_id: str
|
|
110
|
+
task_id: Optional[str] = None
|
|
111
|
+
type: str = "other"
|
|
112
|
+
name: str
|
|
113
|
+
extension: str = ""
|
|
114
|
+
content: str = ""
|
|
115
|
+
content_hash: str = ""
|
|
116
|
+
size_bytes: int = 0
|
|
117
|
+
summary: str = ""
|
|
118
|
+
token_count: int = 0
|
|
119
|
+
relevance_score: int = 50
|
|
120
|
+
metadata: dict[str, Any] = Field(default_factory=dict)
|
|
121
|
+
created_at: datetime
|
|
122
|
+
updated_at: datetime
|
|
123
|
+
|
|
124
|
+
|
|
125
|
+
class TaskStats(BaseModel):
|
|
126
|
+
"""Task statistics."""
|
|
127
|
+
total: int = 0
|
|
128
|
+
pending: int = 0
|
|
129
|
+
queued: int = 0
|
|
130
|
+
running: int = 0
|
|
131
|
+
completed: int = 0
|
|
132
|
+
failed: int = 0
|
|
133
|
+
cancelled: int = 0
|
|
134
|
+
|
|
135
|
+
|
|
136
|
+
class SessionStatistics(BaseModel):
|
|
137
|
+
"""Session statistics."""
|
|
138
|
+
tasks: TaskStats = Field(default_factory=TaskStats)
|
|
139
|
+
total_tokens: int = 0
|
|
140
|
+
total_cost_usd: float = 0.0
|
|
141
|
+
agents_count: int = 0
|
|
142
|
+
artifacts_count: int = 0
|
|
143
|
+
|
|
144
|
+
|
|
145
|
+
class SessionReport(BaseModel):
|
|
146
|
+
"""Comprehensive session report."""
|
|
147
|
+
session: Session
|
|
148
|
+
statistics: SessionStatistics
|
|
149
|
+
tasks: list[Task] = Field(default_factory=list)
|
|
150
|
+
agents: list[Agent] = Field(default_factory=list)
|
|
151
|
+
artifacts: list[Artifact] = Field(default_factory=list)
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Screens for Ranger TUI.
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
from .dashboard import DashboardScreen
|
|
6
|
+
from .session import SessionScreen
|
|
7
|
+
from .task import TaskScreen
|
|
8
|
+
from .modals import NewSessionModal, NewTaskModal
|
|
9
|
+
|
|
10
|
+
__all__ = [
|
|
11
|
+
"DashboardScreen",
|
|
12
|
+
"SessionScreen",
|
|
13
|
+
"TaskScreen",
|
|
14
|
+
"NewSessionModal",
|
|
15
|
+
"NewTaskModal",
|
|
16
|
+
]
|
|
Binary file
|
|
Binary file
|
|
@@ -0,0 +1,357 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Command palette screen - Quick access to all operations.
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
from typing import Callable, Awaitable
|
|
6
|
+
from textual.app import ComposeResult
|
|
7
|
+
from textual.screen import ModalScreen
|
|
8
|
+
from textual.binding import Binding
|
|
9
|
+
from textual.containers import Container, VerticalScroll
|
|
10
|
+
from textual.widgets import Static, Input, OptionList
|
|
11
|
+
from textual.widgets.option_list import Option
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
class Command:
|
|
15
|
+
"""A command that can be executed from the palette."""
|
|
16
|
+
|
|
17
|
+
def __init__(
|
|
18
|
+
self,
|
|
19
|
+
name: str,
|
|
20
|
+
description: str,
|
|
21
|
+
category: str,
|
|
22
|
+
action: Callable[[], Awaitable[None]],
|
|
23
|
+
):
|
|
24
|
+
self.name = name
|
|
25
|
+
self.description = description
|
|
26
|
+
self.category = category
|
|
27
|
+
self.action = action
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
class CommandPaletteScreen(ModalScreen):
|
|
31
|
+
"""Command palette for quick access to all operations."""
|
|
32
|
+
|
|
33
|
+
BINDINGS = [
|
|
34
|
+
Binding("escape", "close", "Close", show=True),
|
|
35
|
+
Binding("enter", "execute", "Execute", show=False),
|
|
36
|
+
Binding("up", "move_up", "Up", show=False),
|
|
37
|
+
Binding("down", "move_down", "Down", show=False),
|
|
38
|
+
]
|
|
39
|
+
|
|
40
|
+
def __init__(self):
|
|
41
|
+
super().__init__()
|
|
42
|
+
self.commands: list[Command] = []
|
|
43
|
+
self.filtered_commands: list[Command] = []
|
|
44
|
+
|
|
45
|
+
def compose(self) -> ComposeResult:
|
|
46
|
+
"""Compose the command palette."""
|
|
47
|
+
with Container(id="palette-container"):
|
|
48
|
+
yield Static("Command Palette", id="palette-title")
|
|
49
|
+
yield Input(placeholder="Type to search commands...", id="palette-search")
|
|
50
|
+
yield OptionList(id="palette-list")
|
|
51
|
+
|
|
52
|
+
def on_mount(self) -> None:
|
|
53
|
+
"""Initialize commands on mount."""
|
|
54
|
+
self._build_commands()
|
|
55
|
+
self._update_list("")
|
|
56
|
+
self.query_one("#palette-search", Input).focus()
|
|
57
|
+
|
|
58
|
+
def _build_commands(self) -> None:
|
|
59
|
+
"""Build the list of available commands."""
|
|
60
|
+
self.commands = [
|
|
61
|
+
# Session commands
|
|
62
|
+
Command(
|
|
63
|
+
"New Session",
|
|
64
|
+
"Create a new orchestration session",
|
|
65
|
+
"Session",
|
|
66
|
+
self._new_session,
|
|
67
|
+
),
|
|
68
|
+
Command(
|
|
69
|
+
"Archive Session",
|
|
70
|
+
"Archive the current/selected session",
|
|
71
|
+
"Session",
|
|
72
|
+
self._archive_session,
|
|
73
|
+
),
|
|
74
|
+
Command(
|
|
75
|
+
"Purge Session",
|
|
76
|
+
"Permanently delete a session",
|
|
77
|
+
"Session",
|
|
78
|
+
self._purge_session,
|
|
79
|
+
),
|
|
80
|
+
Command(
|
|
81
|
+
"Purge All Archived",
|
|
82
|
+
"Delete all archived sessions",
|
|
83
|
+
"Session",
|
|
84
|
+
self._purge_all_archived,
|
|
85
|
+
),
|
|
86
|
+
Command(
|
|
87
|
+
"Fork Session",
|
|
88
|
+
"Create a fork of the current session",
|
|
89
|
+
"Session",
|
|
90
|
+
self._fork_session,
|
|
91
|
+
),
|
|
92
|
+
Command(
|
|
93
|
+
"Session Report",
|
|
94
|
+
"View comprehensive session report",
|
|
95
|
+
"Session",
|
|
96
|
+
self._session_report,
|
|
97
|
+
),
|
|
98
|
+
Command(
|
|
99
|
+
"Session Cost",
|
|
100
|
+
"View session cost breakdown",
|
|
101
|
+
"Session",
|
|
102
|
+
self._session_cost,
|
|
103
|
+
),
|
|
104
|
+
|
|
105
|
+
# Task commands
|
|
106
|
+
Command(
|
|
107
|
+
"New Task",
|
|
108
|
+
"Create a new task in current session",
|
|
109
|
+
"Task",
|
|
110
|
+
self._new_task,
|
|
111
|
+
),
|
|
112
|
+
Command(
|
|
113
|
+
"Execute Task",
|
|
114
|
+
"Queue selected task for execution",
|
|
115
|
+
"Task",
|
|
116
|
+
self._execute_task,
|
|
117
|
+
),
|
|
118
|
+
Command(
|
|
119
|
+
"Cancel Task",
|
|
120
|
+
"Cancel the selected task",
|
|
121
|
+
"Task",
|
|
122
|
+
self._cancel_task,
|
|
123
|
+
),
|
|
124
|
+
Command(
|
|
125
|
+
"Retry Task",
|
|
126
|
+
"Retry a failed task",
|
|
127
|
+
"Task",
|
|
128
|
+
self._retry_task,
|
|
129
|
+
),
|
|
130
|
+
|
|
131
|
+
# Agent commands
|
|
132
|
+
Command(
|
|
133
|
+
"New Agent",
|
|
134
|
+
"Create a new agent",
|
|
135
|
+
"Agent",
|
|
136
|
+
self._new_agent,
|
|
137
|
+
),
|
|
138
|
+
Command(
|
|
139
|
+
"Deploy Agent",
|
|
140
|
+
"Deploy an agent to a task",
|
|
141
|
+
"Agent",
|
|
142
|
+
self._deploy_agent,
|
|
143
|
+
),
|
|
144
|
+
Command(
|
|
145
|
+
"Retire Agent",
|
|
146
|
+
"Retire an agent",
|
|
147
|
+
"Agent",
|
|
148
|
+
self._retire_agent,
|
|
149
|
+
),
|
|
150
|
+
|
|
151
|
+
# System commands
|
|
152
|
+
Command(
|
|
153
|
+
"Refresh",
|
|
154
|
+
"Refresh all data",
|
|
155
|
+
"System",
|
|
156
|
+
self._refresh,
|
|
157
|
+
),
|
|
158
|
+
Command(
|
|
159
|
+
"Health Check",
|
|
160
|
+
"Check system health",
|
|
161
|
+
"System",
|
|
162
|
+
self._health_check,
|
|
163
|
+
),
|
|
164
|
+
Command(
|
|
165
|
+
"Toggle Dark Mode",
|
|
166
|
+
"Switch between dark and light theme",
|
|
167
|
+
"System",
|
|
168
|
+
self._toggle_dark,
|
|
169
|
+
),
|
|
170
|
+
Command(
|
|
171
|
+
"Show Help",
|
|
172
|
+
"Display help information",
|
|
173
|
+
"System",
|
|
174
|
+
self._show_help,
|
|
175
|
+
),
|
|
176
|
+
Command(
|
|
177
|
+
"Quit",
|
|
178
|
+
"Exit the application",
|
|
179
|
+
"System",
|
|
180
|
+
self._quit,
|
|
181
|
+
),
|
|
182
|
+
]
|
|
183
|
+
|
|
184
|
+
self.filtered_commands = self.commands.copy()
|
|
185
|
+
|
|
186
|
+
def _update_list(self, filter_text: str) -> None:
|
|
187
|
+
"""Update the command list based on filter."""
|
|
188
|
+
filter_lower = filter_text.lower()
|
|
189
|
+
|
|
190
|
+
if filter_text:
|
|
191
|
+
self.filtered_commands = [
|
|
192
|
+
cmd for cmd in self.commands
|
|
193
|
+
if filter_lower in cmd.name.lower()
|
|
194
|
+
or filter_lower in cmd.description.lower()
|
|
195
|
+
or filter_lower in cmd.category.lower()
|
|
196
|
+
]
|
|
197
|
+
else:
|
|
198
|
+
self.filtered_commands = self.commands.copy()
|
|
199
|
+
|
|
200
|
+
option_list = self.query_one("#palette-list", OptionList)
|
|
201
|
+
option_list.clear_options()
|
|
202
|
+
|
|
203
|
+
current_category = ""
|
|
204
|
+
for cmd in self.filtered_commands:
|
|
205
|
+
if cmd.category != current_category:
|
|
206
|
+
current_category = cmd.category
|
|
207
|
+
option_list.add_option(Option(f"── {current_category} ──", disabled=True))
|
|
208
|
+
|
|
209
|
+
option_list.add_option(Option(f"{cmd.name} - {cmd.description}", id=cmd.name))
|
|
210
|
+
|
|
211
|
+
def on_input_changed(self, event: Input.Changed) -> None:
|
|
212
|
+
"""Handle search input changes."""
|
|
213
|
+
if event.input.id == "palette-search":
|
|
214
|
+
self._update_list(event.value)
|
|
215
|
+
|
|
216
|
+
def on_option_list_option_selected(self, event: OptionList.OptionSelected) -> None:
|
|
217
|
+
"""Handle option selection."""
|
|
218
|
+
selected_name = event.option.id
|
|
219
|
+
for cmd in self.filtered_commands:
|
|
220
|
+
if cmd.name == selected_name:
|
|
221
|
+
self.dismiss()
|
|
222
|
+
self.app.call_later(cmd.action)
|
|
223
|
+
break
|
|
224
|
+
|
|
225
|
+
def action_close(self) -> None:
|
|
226
|
+
"""Close the palette."""
|
|
227
|
+
self.dismiss()
|
|
228
|
+
|
|
229
|
+
async def action_execute(self) -> None:
|
|
230
|
+
"""Execute highlighted command."""
|
|
231
|
+
option_list = self.query_one("#palette-list", OptionList)
|
|
232
|
+
if option_list.highlighted is not None:
|
|
233
|
+
highlighted_option = option_list.get_option_at_index(option_list.highlighted)
|
|
234
|
+
if highlighted_option and not highlighted_option.disabled:
|
|
235
|
+
selected_name = highlighted_option.id
|
|
236
|
+
for cmd in self.filtered_commands:
|
|
237
|
+
if cmd.name == selected_name:
|
|
238
|
+
self.dismiss()
|
|
239
|
+
await cmd.action()
|
|
240
|
+
break
|
|
241
|
+
|
|
242
|
+
def action_move_up(self) -> None:
|
|
243
|
+
"""Move selection up."""
|
|
244
|
+
option_list = self.query_one("#palette-list", OptionList)
|
|
245
|
+
option_list.action_cursor_up()
|
|
246
|
+
|
|
247
|
+
def action_move_down(self) -> None:
|
|
248
|
+
"""Move selection down."""
|
|
249
|
+
option_list = self.query_one("#palette-list", OptionList)
|
|
250
|
+
option_list.action_cursor_down()
|
|
251
|
+
|
|
252
|
+
# Command implementations
|
|
253
|
+
|
|
254
|
+
async def _new_session(self) -> None:
|
|
255
|
+
"""Create new session."""
|
|
256
|
+
from ranger_tui.screens.modals import NewSessionModal
|
|
257
|
+
|
|
258
|
+
async def on_submit(objective: str) -> None:
|
|
259
|
+
if objective:
|
|
260
|
+
session = await self.app.client.create_session(objective)
|
|
261
|
+
self.app.notify(f"Created session: {session.id}")
|
|
262
|
+
await self.app._refresh_data()
|
|
263
|
+
|
|
264
|
+
await self.app.push_screen(NewSessionModal(), on_submit)
|
|
265
|
+
|
|
266
|
+
async def _archive_session(self) -> None:
|
|
267
|
+
"""Archive session - requires dashboard context."""
|
|
268
|
+
self.app.notify("Use 'a' key on dashboard to archive selected session", severity="information")
|
|
269
|
+
|
|
270
|
+
async def _purge_session(self) -> None:
|
|
271
|
+
"""Purge session - requires dashboard context."""
|
|
272
|
+
self.app.notify("Use 'p' key on dashboard to purge selected session", severity="information")
|
|
273
|
+
|
|
274
|
+
async def _purge_all_archived(self) -> None:
|
|
275
|
+
"""Purge all archived sessions."""
|
|
276
|
+
from ranger_tui.screens.modals import ConfirmModal
|
|
277
|
+
|
|
278
|
+
async def on_confirm(confirmed: bool) -> None:
|
|
279
|
+
if confirmed:
|
|
280
|
+
result = await self.app.client.purge_sessions_by_status("archived")
|
|
281
|
+
count = result.get("deleted_count", 0)
|
|
282
|
+
self.app.notify(f"Purged {count} archived sessions", severity="warning")
|
|
283
|
+
await self.app._refresh_data()
|
|
284
|
+
|
|
285
|
+
await self.app.push_screen(
|
|
286
|
+
ConfirmModal(
|
|
287
|
+
title="Purge All Archived",
|
|
288
|
+
message="Permanently delete ALL archived sessions?",
|
|
289
|
+
),
|
|
290
|
+
on_confirm,
|
|
291
|
+
)
|
|
292
|
+
|
|
293
|
+
async def _fork_session(self) -> None:
|
|
294
|
+
"""Fork session - requires dashboard context."""
|
|
295
|
+
self.app.notify("Use 'f' key on dashboard to fork selected session", severity="information")
|
|
296
|
+
|
|
297
|
+
async def _session_report(self) -> None:
|
|
298
|
+
"""View session report - requires session context."""
|
|
299
|
+
self.app.notify("Open a session to view its report", severity="information")
|
|
300
|
+
|
|
301
|
+
async def _session_cost(self) -> None:
|
|
302
|
+
"""View session cost - requires session context."""
|
|
303
|
+
self.app.notify("Open a session to view its cost", severity="information")
|
|
304
|
+
|
|
305
|
+
async def _new_task(self) -> None:
|
|
306
|
+
"""Create new task - requires session context."""
|
|
307
|
+
self.app.notify("Open a session and use 't' key to create a task", severity="information")
|
|
308
|
+
|
|
309
|
+
async def _execute_task(self) -> None:
|
|
310
|
+
"""Execute task - requires task context."""
|
|
311
|
+
self.app.notify("Select a task and use 'e' key to execute", severity="information")
|
|
312
|
+
|
|
313
|
+
async def _cancel_task(self) -> None:
|
|
314
|
+
"""Cancel task - requires task context."""
|
|
315
|
+
self.app.notify("Select a task and use 'c' key to cancel", severity="information")
|
|
316
|
+
|
|
317
|
+
async def _retry_task(self) -> None:
|
|
318
|
+
"""Retry task - requires task context."""
|
|
319
|
+
self.app.notify("Select a failed task and use 'y' key to retry", severity="information")
|
|
320
|
+
|
|
321
|
+
async def _new_agent(self) -> None:
|
|
322
|
+
"""Create new agent."""
|
|
323
|
+
from ranger_tui.screens.modals import NewAgentModal
|
|
324
|
+
self.app.notify("Agent creation requires session context", severity="information")
|
|
325
|
+
|
|
326
|
+
async def _deploy_agent(self) -> None:
|
|
327
|
+
"""Deploy agent."""
|
|
328
|
+
self.app.notify("Agent deployment requires agent and task context", severity="information")
|
|
329
|
+
|
|
330
|
+
async def _retire_agent(self) -> None:
|
|
331
|
+
"""Retire agent."""
|
|
332
|
+
self.app.notify("Agent retirement requires agent context", severity="information")
|
|
333
|
+
|
|
334
|
+
async def _refresh(self) -> None:
|
|
335
|
+
"""Refresh data."""
|
|
336
|
+
await self.app._refresh_data()
|
|
337
|
+
self.app.notify("Data refreshed")
|
|
338
|
+
|
|
339
|
+
async def _health_check(self) -> None:
|
|
340
|
+
"""Check system health."""
|
|
341
|
+
health = await self.app.client.health_check()
|
|
342
|
+
mongo_status = "OK" if health.get("mongodb") else "FAIL"
|
|
343
|
+
redis_status = "OK" if health.get("redis") else "FAIL"
|
|
344
|
+
self.app.notify(f"MongoDB: {mongo_status}, Redis: {redis_status}")
|
|
345
|
+
|
|
346
|
+
async def _toggle_dark(self) -> None:
|
|
347
|
+
"""Toggle dark mode."""
|
|
348
|
+
self.app.dark = not self.app.dark
|
|
349
|
+
|
|
350
|
+
async def _show_help(self) -> None:
|
|
351
|
+
"""Show help."""
|
|
352
|
+
from ranger_tui.screens.help import HelpScreen
|
|
353
|
+
await self.app.push_screen(HelpScreen())
|
|
354
|
+
|
|
355
|
+
async def _quit(self) -> None:
|
|
356
|
+
"""Quit application."""
|
|
357
|
+
self.app.exit()
|