ccmd 2.0.2__tar.gz → 2.0.3__tar.gz
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.
- {ccmd-2.0.2/ccmd.egg-info → ccmd-2.0.3}/PKG-INFO +1 -1
- {ccmd-2.0.2 → ccmd-2.0.3}/ccmd/__init__.py +1 -1
- {ccmd-2.0.2 → ccmd-2.0.3}/ccmd/tui/screens/hub.py +30 -9
- {ccmd-2.0.2 → ccmd-2.0.3/ccmd.egg-info}/PKG-INFO +1 -1
- {ccmd-2.0.2 → ccmd-2.0.3}/pyproject.toml +1 -1
- {ccmd-2.0.2 → ccmd-2.0.3}/LICENSE +0 -0
- {ccmd-2.0.2 → ccmd-2.0.3}/MANIFEST.in +0 -0
- {ccmd-2.0.2 → ccmd-2.0.3}/README.md +0 -0
- {ccmd-2.0.2 → ccmd-2.0.3}/ccmd/__main__.py +0 -0
- {ccmd-2.0.2 → ccmd-2.0.3}/ccmd/cli.py +0 -0
- {ccmd-2.0.2 → ccmd-2.0.3}/ccmd/config/__init__.py +0 -0
- {ccmd-2.0.2 → ccmd-2.0.3}/ccmd/config/paths.py +0 -0
- {ccmd-2.0.2 → ccmd-2.0.3}/ccmd/config/schema.py +0 -0
- {ccmd-2.0.2 → ccmd-2.0.3}/ccmd/core/__init__.py +0 -0
- {ccmd-2.0.2 → ccmd-2.0.3}/ccmd/core/agents/__init__.py +0 -0
- {ccmd-2.0.2 → ccmd-2.0.3}/ccmd/core/agents/aider.py +0 -0
- {ccmd-2.0.2 → ccmd-2.0.3}/ccmd/core/agents/base.py +0 -0
- {ccmd-2.0.2 → ccmd-2.0.3}/ccmd/core/agents/chatgpt.py +0 -0
- {ccmd-2.0.2 → ccmd-2.0.3}/ccmd/core/agents/claude.py +0 -0
- {ccmd-2.0.2 → ccmd-2.0.3}/ccmd/core/agents/codex.py +0 -0
- {ccmd-2.0.2 → ccmd-2.0.3}/ccmd/core/agents/cursor.py +0 -0
- {ccmd-2.0.2 → ccmd-2.0.3}/ccmd/core/agents/goose.py +0 -0
- {ccmd-2.0.2 → ccmd-2.0.3}/ccmd/core/agents/grok.py +0 -0
- {ccmd-2.0.2 → ccmd-2.0.3}/ccmd/core/fs.py +0 -0
- {ccmd-2.0.2 → ccmd-2.0.3}/ccmd/core/launcher.py +0 -0
- {ccmd-2.0.2 → ccmd-2.0.3}/ccmd/core/migrate.py +0 -0
- {ccmd-2.0.2 → ccmd-2.0.3}/ccmd/core/profiles.py +0 -0
- {ccmd-2.0.2 → ccmd-2.0.3}/ccmd/core/projects.py +0 -0
- {ccmd-2.0.2 → ccmd-2.0.3}/ccmd/core/scan.py +0 -0
- {ccmd-2.0.2 → ccmd-2.0.3}/ccmd/core/sessions.py +0 -0
- {ccmd-2.0.2 → ccmd-2.0.3}/ccmd/core/ssh.py +0 -0
- {ccmd-2.0.2 → ccmd-2.0.3}/ccmd/mcp/__init__.py +0 -0
- {ccmd-2.0.2 → ccmd-2.0.3}/ccmd/mcp/server.py +0 -0
- {ccmd-2.0.2 → ccmd-2.0.3}/ccmd/tui/__init__.py +0 -0
- {ccmd-2.0.2 → ccmd-2.0.3}/ccmd/tui/app.py +0 -0
- {ccmd-2.0.2 → ccmd-2.0.3}/ccmd/tui/ascii.py +0 -0
- {ccmd-2.0.2 → ccmd-2.0.3}/ccmd/tui/screens/__init__.py +0 -0
- {ccmd-2.0.2 → ccmd-2.0.3}/ccmd/tui/screens/agents.py +0 -0
- {ccmd-2.0.2 → ccmd-2.0.3}/ccmd/tui/screens/aliases.py +0 -0
- {ccmd-2.0.2 → ccmd-2.0.3}/ccmd/tui/screens/browser.py +0 -0
- {ccmd-2.0.2 → ccmd-2.0.3}/ccmd/tui/screens/project_edit.py +0 -0
- {ccmd-2.0.2 → ccmd-2.0.3}/ccmd/tui/screens/sessions.py +0 -0
- {ccmd-2.0.2 → ccmd-2.0.3}/ccmd/tui/screens/ssh.py +0 -0
- {ccmd-2.0.2 → ccmd-2.0.3}/ccmd/tui/theme.py +0 -0
- {ccmd-2.0.2 → ccmd-2.0.3}/ccmd/tui/widgets/__init__.py +0 -0
- {ccmd-2.0.2 → ccmd-2.0.3}/ccmd/tui/widgets/spinner.py +0 -0
- {ccmd-2.0.2 → ccmd-2.0.3}/ccmd.egg-info/SOURCES.txt +0 -0
- {ccmd-2.0.2 → ccmd-2.0.3}/ccmd.egg-info/dependency_links.txt +0 -0
- {ccmd-2.0.2 → ccmd-2.0.3}/ccmd.egg-info/entry_points.txt +0 -0
- {ccmd-2.0.2 → ccmd-2.0.3}/ccmd.egg-info/requires.txt +0 -0
- {ccmd-2.0.2 → ccmd-2.0.3}/ccmd.egg-info/top_level.txt +0 -0
- {ccmd-2.0.2 → ccmd-2.0.3}/commands.yaml +0 -0
- {ccmd-2.0.2 → ccmd-2.0.3}/requirements.txt +0 -0
- {ccmd-2.0.2 → ccmd-2.0.3}/setup.cfg +0 -0
|
@@ -33,6 +33,7 @@ def _agent_bar() -> str:
|
|
|
33
33
|
|
|
34
34
|
|
|
35
35
|
class HubScreen(Screen):
|
|
36
|
+
# Filter Input is can_focus=False until / is pressed, so f/b/a never type into it.
|
|
36
37
|
BINDINGS = [
|
|
37
38
|
Binding("enter", "open_project", "Open", show=True),
|
|
38
39
|
Binding("a", "pick_agent", "Agents", show=True),
|
|
@@ -44,13 +45,13 @@ class HubScreen(Screen):
|
|
|
44
45
|
Binding("h", "ssh", "SSH", show=True),
|
|
45
46
|
Binding("l", "aliases", "Aliases", show=True),
|
|
46
47
|
Binding("d", "detach", "Detach", show=True),
|
|
48
|
+
Binding("r", "refresh", "Refresh", show=True),
|
|
49
|
+
Binding("q", "quit", "Quit", show=True),
|
|
47
50
|
Binding("left_square_bracket", "agent_prev", "Agent−", show=True),
|
|
48
51
|
Binding("right_square_bracket", "agent_next", "Agent+", show=True),
|
|
49
52
|
Binding("slash", "focus_filter", "Filter", show=False),
|
|
50
53
|
Binding("/", "focus_filter", "Filter", show=True),
|
|
51
|
-
Binding("
|
|
52
|
-
Binding("q", "quit", "Quit", show=True),
|
|
53
|
-
# 1–7 set default agent
|
|
54
|
+
Binding("escape", "blur_filter", "Esc", show=False),
|
|
54
55
|
Binding("1", "agent_n_1", show=False),
|
|
55
56
|
Binding("2", "agent_n_2", show=False),
|
|
56
57
|
Binding("3", "agent_n_3", show=False),
|
|
@@ -74,7 +75,11 @@ class HubScreen(Screen):
|
|
|
74
75
|
id="subtitle",
|
|
75
76
|
)
|
|
76
77
|
yield Static(_agent_bar(), id="agent-bar")
|
|
77
|
-
|
|
78
|
+
# can_focus stays False until / — prevents f/b/a landing in the box
|
|
79
|
+
yield Input(
|
|
80
|
+
placeholder="press / to filter projects…",
|
|
81
|
+
id="filter",
|
|
82
|
+
)
|
|
78
83
|
with Horizontal(id="main"):
|
|
79
84
|
with Vertical(id="projects-panel"):
|
|
80
85
|
yield Static("projects (registry — not whole disk)", classes="panel-title")
|
|
@@ -84,13 +89,14 @@ class HubScreen(Screen):
|
|
|
84
89
|
yield Static("Select a project", id="detail")
|
|
85
90
|
yield Static("", id="status")
|
|
86
91
|
yield Static(
|
|
87
|
-
"↵ open ·
|
|
88
|
-
"b browse · f /mnt · d detach · q quit",
|
|
92
|
+
"↵ open · f /mnt · b browse · / filter · esc list · a agent · ] cycle · q quit",
|
|
89
93
|
id="footer-bar",
|
|
90
94
|
)
|
|
91
95
|
yield Footer()
|
|
92
96
|
|
|
93
97
|
def on_mount(self) -> None:
|
|
98
|
+
filt = self.query_one("#filter", Input)
|
|
99
|
+
filt.can_focus = False
|
|
94
100
|
self._load_projects()
|
|
95
101
|
self.query_one("#project-list", OptionList).focus()
|
|
96
102
|
if not self._projects:
|
|
@@ -101,10 +107,9 @@ class HubScreen(Screen):
|
|
|
101
107
|
)
|
|
102
108
|
self.set_timer(0.3, self.action_browse)
|
|
103
109
|
else:
|
|
104
|
-
# hint once if everything is claude
|
|
105
110
|
if all(p.default_agent == "claude" for p in self._projects[:20]):
|
|
106
111
|
self.notify(
|
|
107
|
-
"tip:
|
|
112
|
+
"tip: f = browse /mnt · / = filter · ] = cycle agent",
|
|
108
113
|
severity="information",
|
|
109
114
|
timeout=5,
|
|
110
115
|
)
|
|
@@ -255,7 +260,23 @@ class HubScreen(Screen):
|
|
|
255
260
|
# ── actions ──────────────────────────────────────────────
|
|
256
261
|
|
|
257
262
|
def action_focus_filter(self) -> None:
|
|
258
|
-
|
|
263
|
+
"""Only way into the filter — so f never types into the box by accident."""
|
|
264
|
+
filt = self.query_one("#filter", Input)
|
|
265
|
+
filt.can_focus = True
|
|
266
|
+
filt.focus()
|
|
267
|
+
|
|
268
|
+
def action_blur_filter(self) -> None:
|
|
269
|
+
"""Esc: leave filter, give keys back to hub (f/b/a work again)."""
|
|
270
|
+
filt = self.query_one("#filter", Input)
|
|
271
|
+
if self.focused is filt or filt.has_focus:
|
|
272
|
+
filt.can_focus = False
|
|
273
|
+
self.query_one("#project-list", OptionList).focus()
|
|
274
|
+
return
|
|
275
|
+
# if not in filter, esc clears filter text
|
|
276
|
+
if filt.value:
|
|
277
|
+
filt.value = ""
|
|
278
|
+
self._load_projects("")
|
|
279
|
+
self.query_one("#project-list", OptionList).focus()
|
|
259
280
|
|
|
260
281
|
def action_refresh(self) -> None:
|
|
261
282
|
self._agent_info = detect_agents()
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|