tasktree-manager 2.4.0__tar.gz → 2.5.0__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.
- {tasktree_manager-2.4.0 → tasktree_manager-2.5.0}/CHANGELOG.md +6 -0
- {tasktree_manager-2.4.0 → tasktree_manager-2.5.0}/PKG-INFO +1 -1
- {tasktree_manager-2.4.0 → tasktree_manager-2.5.0}/docs/user-guide.md +1 -1
- {tasktree_manager-2.4.0 → tasktree_manager-2.5.0}/pyproject.toml +1 -1
- {tasktree_manager-2.4.0 → tasktree_manager-2.5.0}/tasktree_manager/_version.py +2 -2
- {tasktree_manager-2.4.0 → tasktree_manager-2.5.0}/tasktree_manager/app.py +7 -2
- tasktree_manager-2.5.0/tasktree_manager/commands.py +69 -0
- {tasktree_manager-2.4.0 → tasktree_manager-2.5.0}/tests/test_app.py +1 -0
- tasktree_manager-2.5.0/tests/test_commands.py +55 -0
- {tasktree_manager-2.4.0 → tasktree_manager-2.5.0}/.claude/skills/textual-tui/SKILL.md +0 -0
- {tasktree_manager-2.4.0 → tasktree_manager-2.5.0}/.claude/skills/textual-tui/assets/README.md +0 -0
- {tasktree_manager-2.4.0 → tasktree_manager-2.5.0}/.claude/skills/textual-tui/assets/dashboard_app.py +0 -0
- {tasktree_manager-2.4.0 → tasktree_manager-2.5.0}/.claude/skills/textual-tui/assets/data_viewer.py +0 -0
- {tasktree_manager-2.4.0 → tasktree_manager-2.5.0}/.claude/skills/textual-tui/assets/todo_app.py +0 -0
- {tasktree_manager-2.4.0 → tasktree_manager-2.5.0}/.claude/skills/textual-tui/assets/worker_demo.py +0 -0
- {tasktree_manager-2.4.0 → tasktree_manager-2.5.0}/.claude/skills/textual-tui/references/layouts.md +0 -0
- {tasktree_manager-2.4.0 → tasktree_manager-2.5.0}/.claude/skills/textual-tui/references/official-guides-index.md +0 -0
- {tasktree_manager-2.4.0 → tasktree_manager-2.5.0}/.claude/skills/textual-tui/references/styling.md +0 -0
- {tasktree_manager-2.4.0 → tasktree_manager-2.5.0}/.claude/skills/textual-tui/references/widgets.md +0 -0
- {tasktree_manager-2.4.0 → tasktree_manager-2.5.0}/.github/templates/CHANGELOG.md.j2 +0 -0
- {tasktree_manager-2.4.0 → tasktree_manager-2.5.0}/.github/workflows/ci.yml +0 -0
- {tasktree_manager-2.4.0 → tasktree_manager-2.5.0}/.github/workflows/release.yml +0 -0
- {tasktree_manager-2.4.0 → tasktree_manager-2.5.0}/.gitignore +0 -0
- {tasktree_manager-2.4.0 → tasktree_manager-2.5.0}/CONTRIBUTING.md +0 -0
- {tasktree_manager-2.4.0 → tasktree_manager-2.5.0}/LICENSE +0 -0
- {tasktree_manager-2.4.0 → tasktree_manager-2.5.0}/OPENSPEC.md +0 -0
- {tasktree_manager-2.4.0 → tasktree_manager-2.5.0}/README.md +0 -0
- {tasktree_manager-2.4.0 → tasktree_manager-2.5.0}/ROADMAP.md +0 -0
- {tasktree_manager-2.4.0 → tasktree_manager-2.5.0}/docs/claude-code-integration-spec.md +0 -0
- {tasktree_manager-2.4.0 → tasktree_manager-2.5.0}/docs/configuration.md +0 -0
- {tasktree_manager-2.4.0 → tasktree_manager-2.5.0}/docs/installation.md +0 -0
- {tasktree_manager-2.4.0 → tasktree_manager-2.5.0}/docs/troubleshooting.md +0 -0
- {tasktree_manager-2.4.0 → tasktree_manager-2.5.0}/mise.toml +0 -0
- {tasktree_manager-2.4.0 → tasktree_manager-2.5.0}/scripts/bump_version.py +0 -0
- {tasktree_manager-2.4.0 → tasktree_manager-2.5.0}/tasktree_manager/__init__.py +0 -0
- {tasktree_manager-2.4.0 → tasktree_manager-2.5.0}/tasktree_manager/services/__init__.py +0 -0
- {tasktree_manager-2.4.0 → tasktree_manager-2.5.0}/tasktree_manager/services/claude_hooks.py +0 -0
- {tasktree_manager-2.4.0 → tasktree_manager-2.5.0}/tasktree_manager/services/config.py +0 -0
- {tasktree_manager-2.4.0 → tasktree_manager-2.5.0}/tasktree_manager/services/git_ops.py +0 -0
- {tasktree_manager-2.4.0 → tasktree_manager-2.5.0}/tasktree_manager/services/models.py +0 -0
- {tasktree_manager-2.4.0 → tasktree_manager-2.5.0}/tasktree_manager/services/task_manager.py +0 -0
- {tasktree_manager-2.4.0 → tasktree_manager-2.5.0}/tasktree_manager/widgets/__init__.py +0 -0
- {tasktree_manager-2.4.0 → tasktree_manager-2.5.0}/tasktree_manager/widgets/create_modal.py +0 -0
- {tasktree_manager-2.4.0 → tasktree_manager-2.5.0}/tasktree_manager/widgets/messages_panel.py +0 -0
- {tasktree_manager-2.4.0 → tasktree_manager-2.5.0}/tasktree_manager/widgets/setup_modal.py +0 -0
- {tasktree_manager-2.4.0 → tasktree_manager-2.5.0}/tasktree_manager/widgets/status_panel.py +0 -0
- {tasktree_manager-2.4.0 → tasktree_manager-2.5.0}/tasktree_manager/widgets/task_list.py +0 -0
- {tasktree_manager-2.4.0 → tasktree_manager-2.5.0}/tasktree_manager/widgets/worktree_list.py +0 -0
- {tasktree_manager-2.4.0 → tasktree_manager-2.5.0}/tests/__init__.py +0 -0
- {tasktree_manager-2.4.0 → tasktree_manager-2.5.0}/tests/conftest.py +0 -0
- {tasktree_manager-2.4.0 → tasktree_manager-2.5.0}/tests/test_config.py +0 -0
- {tasktree_manager-2.4.0 → tasktree_manager-2.5.0}/tests/test_git_ops.py +0 -0
- {tasktree_manager-2.4.0 → tasktree_manager-2.5.0}/tests/test_integration_git.py +0 -0
- {tasktree_manager-2.4.0 → tasktree_manager-2.5.0}/tests/test_memory.py +0 -0
- {tasktree_manager-2.4.0 → tasktree_manager-2.5.0}/tests/test_messages_panel.py +0 -0
- {tasktree_manager-2.4.0 → tasktree_manager-2.5.0}/tests/test_modals.py +0 -0
- {tasktree_manager-2.4.0 → tasktree_manager-2.5.0}/tests/test_setup_modal.py +0 -0
- {tasktree_manager-2.4.0 → tasktree_manager-2.5.0}/tests/test_status_panel.py +0 -0
- {tasktree_manager-2.4.0 → tasktree_manager-2.5.0}/tests/test_task_manager.py +0 -0
|
@@ -15,6 +15,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
15
15
|
- Git hooks support
|
|
16
16
|
- Custom task metadata
|
|
17
17
|
|
|
18
|
+
## [2.5.0] - 2026-06-10
|
|
19
|
+
|
|
20
|
+
### Added
|
|
21
|
+
- Searchable app actions in the command palette (#7)
|
|
22
|
+
|
|
23
|
+
|
|
18
24
|
## [2.4.0] - 2026-06-10
|
|
19
25
|
|
|
20
26
|
### Added
|
|
@@ -364,7 +364,7 @@ Useful when you're spinning up several similar tasks that share the same set of
|
|
|
364
364
|
|
|
365
365
|
| Key | Action | Description |
|
|
366
366
|
|---------|-------------------------|----------------------------------------------|
|
|
367
|
-
| `Ctrl+P`| Open Command Palette |
|
|
367
|
+
| `Ctrl+P`| Open Command Palette | Search and run any action (hotkeys shown), switch themes |
|
|
368
368
|
| `o` | Open folder | Open current folder in new terminal tab |
|
|
369
369
|
| `m` | Toggle messages | Show/hide the activity messages panel |
|
|
370
370
|
| `?` | Show help | Display help modal with keybindings |
|
|
@@ -70,7 +70,7 @@ version-file = "tasktree_manager/_version.py"
|
|
|
70
70
|
# Semantic Release Configuration
|
|
71
71
|
[tool.semantic_release]
|
|
72
72
|
version_toml = ["pyproject.toml:tool.semantic_release.version"]
|
|
73
|
-
version = "2.
|
|
73
|
+
version = "2.5.0"
|
|
74
74
|
tag_format = "v{version}"
|
|
75
75
|
branch = "main"
|
|
76
76
|
commit_message = "chore(release): {version} [skip ci]"
|
|
@@ -18,7 +18,7 @@ version_tuple: tuple[int | str, ...]
|
|
|
18
18
|
commit_id: str | None
|
|
19
19
|
__commit_id__: str | None
|
|
20
20
|
|
|
21
|
-
__version__ = version = '2.
|
|
22
|
-
__version_tuple__ = version_tuple = (2,
|
|
21
|
+
__version__ = version = '2.5.0'
|
|
22
|
+
__version_tuple__ = version_tuple = (2, 5, 0)
|
|
23
23
|
|
|
24
24
|
__commit_id__ = commit_id = None
|
|
@@ -10,6 +10,7 @@ from textual.binding import Binding
|
|
|
10
10
|
from textual.containers import Horizontal, Vertical
|
|
11
11
|
from textual.widgets import Footer, Header, Static
|
|
12
12
|
|
|
13
|
+
from .commands import TaskTreeCommands
|
|
13
14
|
from .services.claude_hooks import ensure_claude_hooks, has_claude_session
|
|
14
15
|
from .services.config import Config
|
|
15
16
|
from .services.git_ops import GitOps
|
|
@@ -35,6 +36,10 @@ class TaskTreeApp(App):
|
|
|
35
36
|
|
|
36
37
|
TITLE = "tasktree-manager"
|
|
37
38
|
|
|
39
|
+
# System commands plus all keybound tasktree actions (searchable by
|
|
40
|
+
# name, displayed with their configured hotkey)
|
|
41
|
+
COMMANDS = App.COMMANDS | {TaskTreeCommands}
|
|
42
|
+
|
|
38
43
|
CSS = """
|
|
39
44
|
/* Main layout */
|
|
40
45
|
Screen {
|
|
@@ -226,7 +231,7 @@ class TaskTreeApp(App):
|
|
|
226
231
|
Binding("c", "open_claude_resume", "Claude", show=False),
|
|
227
232
|
Binding("p", "push_all", "Push", show=False),
|
|
228
233
|
Binding("r", "refresh", "Refresh"),
|
|
229
|
-
Binding("m", "toggle_messages", "Messages"
|
|
234
|
+
Binding("m", "toggle_messages", "Messages"),
|
|
230
235
|
Binding("q", "quit", "Quit"),
|
|
231
236
|
Binding("?", "help", "Help"),
|
|
232
237
|
Binding("enter", "open_shell", "Shell", show=False),
|
|
@@ -287,7 +292,7 @@ class TaskTreeApp(App):
|
|
|
287
292
|
Binding(kb.get("open_claude_resume", "c"), "open_claude_resume", "Claude", show=False),
|
|
288
293
|
Binding(kb.get("push_all", "p"), "push_all", "Push", show=False),
|
|
289
294
|
Binding(kb.get("refresh", "r"), "refresh", "Refresh"),
|
|
290
|
-
Binding(kb.get("toggle_messages", "m"), "toggle_messages", "Messages"
|
|
295
|
+
Binding(kb.get("toggle_messages", "m"), "toggle_messages", "Messages"),
|
|
291
296
|
Binding(kb.get("quit", "q"), "quit", "Quit"),
|
|
292
297
|
Binding(kb.get("help", "?"), "help", "Help"),
|
|
293
298
|
Binding(kb.get("open_shell", "enter"), "open_shell", "Shell", show=False),
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
"""Command palette provider for tasktree-manager actions."""
|
|
2
|
+
|
|
3
|
+
from functools import partial
|
|
4
|
+
|
|
5
|
+
from textual.command import DiscoveryHit, Hit, Hits, Provider
|
|
6
|
+
|
|
7
|
+
# (action, title, help) for every keybound app action. The key for each
|
|
8
|
+
# action is looked up from the app's config at search time so customized
|
|
9
|
+
# keybindings display correctly.
|
|
10
|
+
APP_COMMANDS: list[tuple[str, str, str]] = [
|
|
11
|
+
("new_task", "New Task", "Create a new task with worktrees"),
|
|
12
|
+
("clone_task", "Clone Task", "Create a new task with the same repos as the current one"),
|
|
13
|
+
("add_repo", "Add Repo", "Add repositories to the current task"),
|
|
14
|
+
("delete_task", "Delete Task", "Delete the current task (with safety checks)"),
|
|
15
|
+
("delete_worktree", "Delete Worktree", "Delete the selected worktree from the task"),
|
|
16
|
+
("open_lazygit", "Open Lazygit", "Open lazygit in the selected worktree"),
|
|
17
|
+
("open_editor", "Open Editor", "Open your editor in the focused task/worktree folder"),
|
|
18
|
+
("open_folder", "Open Folder", "Open the focused folder in a new terminal tab"),
|
|
19
|
+
("open_shell", "Open Shell", "Open a shell in the selected worktree"),
|
|
20
|
+
("open_claude_resume", "Open Claude", "Open Claude Code for the task (resume if possible)"),
|
|
21
|
+
(
|
|
22
|
+
"open_claude_gui_code",
|
|
23
|
+
"Open Claude Desktop",
|
|
24
|
+
"Open the Claude desktop app on the Code page",
|
|
25
|
+
),
|
|
26
|
+
("push_all", "Push All", "Push all worktrees in the current task"),
|
|
27
|
+
("pull_all", "Pull All", "Pull all worktrees in the current task"),
|
|
28
|
+
("refresh", "Refresh", "Refresh git status for all tasks"),
|
|
29
|
+
("toggle_messages", "Toggle Messages", "Show or hide the activity messages panel"),
|
|
30
|
+
("toggle_grouping", "Toggle Grouping", "Group worktrees by dirty/clean status"),
|
|
31
|
+
("cycle_sort", "Cycle Sort", "Cycle through task sort modes"),
|
|
32
|
+
("help", "Help", "Show the keybinding reference"),
|
|
33
|
+
("quit", "Quit", "Exit tasktree-manager"),
|
|
34
|
+
]
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
class TaskTreeCommands(Provider):
|
|
38
|
+
"""Expose all keybound tasktree actions in the command palette."""
|
|
39
|
+
|
|
40
|
+
def _entries(self):
|
|
41
|
+
"""Yield (display title with hotkey, action, help) tuples."""
|
|
42
|
+
config = getattr(self.app, "config", None)
|
|
43
|
+
keybindings = config.keybindings if config else {}
|
|
44
|
+
for action, title, help_text in APP_COMMANDS:
|
|
45
|
+
key = keybindings.get(action, "")
|
|
46
|
+
display = f"{title} ({key})" if key else title
|
|
47
|
+
yield display, action, help_text
|
|
48
|
+
|
|
49
|
+
async def discover(self) -> Hits:
|
|
50
|
+
"""List all commands when the palette opens with an empty query."""
|
|
51
|
+
for display, action, help_text in self._entries():
|
|
52
|
+
yield DiscoveryHit(
|
|
53
|
+
display,
|
|
54
|
+
partial(self.app.run_action, action),
|
|
55
|
+
help=help_text,
|
|
56
|
+
)
|
|
57
|
+
|
|
58
|
+
async def search(self, query: str) -> Hits:
|
|
59
|
+
"""Fuzzy-match commands against the query."""
|
|
60
|
+
matcher = self.matcher(query)
|
|
61
|
+
for display, action, help_text in self._entries():
|
|
62
|
+
score = matcher.match(display)
|
|
63
|
+
if score > 0:
|
|
64
|
+
yield Hit(
|
|
65
|
+
score,
|
|
66
|
+
matcher.highlight(display),
|
|
67
|
+
partial(self.app.run_action, action),
|
|
68
|
+
help=help_text,
|
|
69
|
+
)
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
"""Tests for the command palette provider."""
|
|
2
|
+
|
|
3
|
+
from tasktree_manager.app import TaskTreeApp
|
|
4
|
+
from tasktree_manager.commands import APP_COMMANDS, TaskTreeCommands
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class TestTaskTreeCommands:
|
|
8
|
+
"""Tests for the TaskTreeCommands palette provider."""
|
|
9
|
+
|
|
10
|
+
async def test_app_registers_provider(self, app):
|
|
11
|
+
"""The app exposes the provider alongside the system commands."""
|
|
12
|
+
assert TaskTreeCommands in TaskTreeApp.COMMANDS
|
|
13
|
+
|
|
14
|
+
async def test_discover_lists_all_commands(self, app):
|
|
15
|
+
"""Opening the palette with an empty query lists every action."""
|
|
16
|
+
async with app.run_test() as pilot:
|
|
17
|
+
await pilot.pause()
|
|
18
|
+
|
|
19
|
+
provider = TaskTreeCommands(app.screen)
|
|
20
|
+
hits = [hit async for hit in provider.discover()]
|
|
21
|
+
|
|
22
|
+
assert len(hits) == len(APP_COMMANDS)
|
|
23
|
+
|
|
24
|
+
async def test_search_finds_action_with_hotkey(self, app):
|
|
25
|
+
"""Searching shows the matching command with its hotkey."""
|
|
26
|
+
async with app.run_test() as pilot:
|
|
27
|
+
await pilot.pause()
|
|
28
|
+
|
|
29
|
+
provider = TaskTreeCommands(app.screen)
|
|
30
|
+
hits = [hit async for hit in provider.search("lazygit")]
|
|
31
|
+
|
|
32
|
+
assert hits
|
|
33
|
+
assert any("(g)" in str(hit.match_display) for hit in hits)
|
|
34
|
+
|
|
35
|
+
async def test_search_shows_customized_key(self, app):
|
|
36
|
+
"""A remapped keybinding shows the configured key, not the default."""
|
|
37
|
+
app.config.keybindings["push_all"] = "x"
|
|
38
|
+
|
|
39
|
+
async with app.run_test() as pilot:
|
|
40
|
+
await pilot.pause()
|
|
41
|
+
|
|
42
|
+
provider = TaskTreeCommands(app.screen)
|
|
43
|
+
hits = [hit async for hit in provider.search("push all")]
|
|
44
|
+
|
|
45
|
+
assert any("(x)" in str(hit.match_display) for hit in hits)
|
|
46
|
+
|
|
47
|
+
async def test_search_no_match_returns_nothing(self, app):
|
|
48
|
+
"""A nonsense query yields no hits."""
|
|
49
|
+
async with app.run_test() as pilot:
|
|
50
|
+
await pilot.pause()
|
|
51
|
+
|
|
52
|
+
provider = TaskTreeCommands(app.screen)
|
|
53
|
+
hits = [hit async for hit in provider.search("zzz-no-such-command")]
|
|
54
|
+
|
|
55
|
+
assert hits == []
|
|
File without changes
|
{tasktree_manager-2.4.0 → tasktree_manager-2.5.0}/.claude/skills/textual-tui/assets/README.md
RENAMED
|
File without changes
|
{tasktree_manager-2.4.0 → tasktree_manager-2.5.0}/.claude/skills/textual-tui/assets/dashboard_app.py
RENAMED
|
File without changes
|
{tasktree_manager-2.4.0 → tasktree_manager-2.5.0}/.claude/skills/textual-tui/assets/data_viewer.py
RENAMED
|
File without changes
|
{tasktree_manager-2.4.0 → tasktree_manager-2.5.0}/.claude/skills/textual-tui/assets/todo_app.py
RENAMED
|
File without changes
|
{tasktree_manager-2.4.0 → tasktree_manager-2.5.0}/.claude/skills/textual-tui/assets/worker_demo.py
RENAMED
|
File without changes
|
{tasktree_manager-2.4.0 → tasktree_manager-2.5.0}/.claude/skills/textual-tui/references/layouts.md
RENAMED
|
File without changes
|
|
File without changes
|
{tasktree_manager-2.4.0 → tasktree_manager-2.5.0}/.claude/skills/textual-tui/references/styling.md
RENAMED
|
File without changes
|
{tasktree_manager-2.4.0 → tasktree_manager-2.5.0}/.claude/skills/textual-tui/references/widgets.md
RENAMED
|
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
|
{tasktree_manager-2.4.0 → tasktree_manager-2.5.0}/tasktree_manager/widgets/messages_panel.py
RENAMED
|
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
|