rook-cli 0.2.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.
- rook_cli-0.2.0/.claude/settings.local.json +66 -0
- rook_cli-0.2.0/.claude/worktrees/streamed-orbiting-llama/.claude/settings.local.json +66 -0
- rook_cli-0.2.0/.claude/worktrees/streamed-orbiting-llama/.gitignore +20 -0
- rook_cli-0.2.0/.claude/worktrees/streamed-orbiting-llama/LICENSE +10 -0
- rook_cli-0.2.0/.claude/worktrees/streamed-orbiting-llama/README.md +103 -0
- rook_cli-0.2.0/.claude/worktrees/streamed-orbiting-llama/pyproject.toml +51 -0
- rook_cli-0.2.0/.claude/worktrees/streamed-orbiting-llama/src/rook/__init__.py +1 -0
- rook_cli-0.2.0/.claude/worktrees/streamed-orbiting-llama/src/rook/__main__.py +48 -0
- rook_cli-0.2.0/.claude/worktrees/streamed-orbiting-llama/src/rook/app.py +222 -0
- rook_cli-0.2.0/.claude/worktrees/streamed-orbiting-llama/src/rook/branding.py +69 -0
- rook_cli-0.2.0/.claude/worktrees/streamed-orbiting-llama/src/rook/domain/__init__.py +0 -0
- rook_cli-0.2.0/.claude/worktrees/streamed-orbiting-llama/src/rook/domain/tasks.py +55 -0
- rook_cli-0.2.0/.claude/worktrees/streamed-orbiting-llama/src/rook/formatting.py +10 -0
- rook_cli-0.2.0/.claude/worktrees/streamed-orbiting-llama/src/rook/paths.py +31 -0
- rook_cli-0.2.0/.claude/worktrees/streamed-orbiting-llama/src/rook/persistence/__init__.py +0 -0
- rook_cli-0.2.0/.claude/worktrees/streamed-orbiting-llama/src/rook/persistence/archive.py +72 -0
- rook_cli-0.2.0/.claude/worktrees/streamed-orbiting-llama/src/rook/persistence/database.py +18 -0
- rook_cli-0.2.0/.claude/worktrees/streamed-orbiting-llama/src/rook/persistence/metadata.py +56 -0
- rook_cli-0.2.0/.claude/worktrees/streamed-orbiting-llama/src/rook/persistence/migrations.py +111 -0
- rook_cli-0.2.0/.claude/worktrees/streamed-orbiting-llama/src/rook/persistence/tasks.py +185 -0
- rook_cli-0.2.0/.claude/worktrees/streamed-orbiting-llama/src/rook/services/__init__.py +0 -0
- rook_cli-0.2.0/.claude/worktrees/streamed-orbiting-llama/src/rook/services/rollover.py +94 -0
- rook_cli-0.2.0/.claude/worktrees/streamed-orbiting-llama/src/rook/services/tasks.py +85 -0
- rook_cli-0.2.0/.claude/worktrees/streamed-orbiting-llama/src/rook/services/undo.py +72 -0
- rook_cli-0.2.0/.claude/worktrees/streamed-orbiting-llama/src/rook/symbols.py +40 -0
- rook_cli-0.2.0/.claude/worktrees/streamed-orbiting-llama/src/rook/widgets/__init__.py +0 -0
- rook_cli-0.2.0/.claude/worktrees/streamed-orbiting-llama/src/rook/widgets/archive_screen.py +162 -0
- rook_cli-0.2.0/.claude/worktrees/streamed-orbiting-llama/src/rook/widgets/shortcut_footer.py +79 -0
- rook_cli-0.2.0/.claude/worktrees/streamed-orbiting-llama/src/rook/widgets/task_line_input.py +44 -0
- rook_cli-0.2.0/.claude/worktrees/streamed-orbiting-llama/src/rook/widgets/task_list.py +415 -0
- rook_cli-0.2.0/.claude/worktrees/streamed-orbiting-llama/src/rook/widgets/task_row.py +155 -0
- rook_cli-0.2.0/.claude/worktrees/streamed-orbiting-llama/tests/support.py +75 -0
- rook_cli-0.2.0/.claude/worktrees/streamed-orbiting-llama/tests/test_app.py +369 -0
- rook_cli-0.2.0/.claude/worktrees/streamed-orbiting-llama/tests/test_archive_navigation.py +188 -0
- rook_cli-0.2.0/.claude/worktrees/streamed-orbiting-llama/tests/test_archive_queries.py +152 -0
- rook_cli-0.2.0/.claude/worktrees/streamed-orbiting-llama/tests/test_formatting.py +11 -0
- rook_cli-0.2.0/.claude/worktrees/streamed-orbiting-llama/tests/test_migrations.py +52 -0
- rook_cli-0.2.0/.claude/worktrees/streamed-orbiting-llama/tests/test_paths.py +20 -0
- rook_cli-0.2.0/.claude/worktrees/streamed-orbiting-llama/tests/test_persistence_failure.py +47 -0
- rook_cli-0.2.0/.claude/worktrees/streamed-orbiting-llama/tests/test_rollover.py +257 -0
- rook_cli-0.2.0/.claude/worktrees/streamed-orbiting-llama/tests/test_rollover_app.py +104 -0
- rook_cli-0.2.0/.claude/worktrees/streamed-orbiting-llama/tests/test_selection.py +40 -0
- rook_cli-0.2.0/.claude/worktrees/streamed-orbiting-llama/tests/test_shortcut_footer_selection.py +26 -0
- rook_cli-0.2.0/.claude/worktrees/streamed-orbiting-llama/tests/test_smoke.py +5 -0
- rook_cli-0.2.0/.claude/worktrees/streamed-orbiting-llama/tests/test_symbols.py +30 -0
- rook_cli-0.2.0/.claude/worktrees/streamed-orbiting-llama/tests/test_task_creation_and_editing.py +430 -0
- rook_cli-0.2.0/.claude/worktrees/streamed-orbiting-llama/tests/test_task_repository.py +153 -0
- rook_cli-0.2.0/.claude/worktrees/streamed-orbiting-llama/tests/test_task_row_rendering.py +57 -0
- rook_cli-0.2.0/.claude/worktrees/streamed-orbiting-llama/tests/test_task_service.py +37 -0
- rook_cli-0.2.0/.claude/worktrees/streamed-orbiting-llama/tests/test_task_states.py +261 -0
- rook_cli-0.2.0/.claude/worktrees/streamed-orbiting-llama/tests/test_undo.py +245 -0
- rook_cli-0.2.0/.claude/worktrees/streamed-orbiting-llama/tests/test_undo_manager.py +34 -0
- rook_cli-0.2.0/.claude/worktrees/streamed-orbiting-llama/tests/test_widget_markup_safety.py +47 -0
- rook_cli-0.2.0/.gitignore +20 -0
- rook_cli-0.2.0/DEVELOPMENT_GUIDE.md +15609 -0
- rook_cli-0.2.0/LICENSE +10 -0
- rook_cli-0.2.0/PKG-INFO +120 -0
- rook_cli-0.2.0/README.md +103 -0
- rook_cli-0.2.0/pyproject.toml +51 -0
- rook_cli-0.2.0/src/rook/__init__.py +1 -0
- rook_cli-0.2.0/src/rook/__main__.py +48 -0
- rook_cli-0.2.0/src/rook/app.py +222 -0
- rook_cli-0.2.0/src/rook/branding.py +69 -0
- rook_cli-0.2.0/src/rook/domain/__init__.py +0 -0
- rook_cli-0.2.0/src/rook/domain/tasks.py +55 -0
- rook_cli-0.2.0/src/rook/formatting.py +10 -0
- rook_cli-0.2.0/src/rook/paths.py +31 -0
- rook_cli-0.2.0/src/rook/persistence/__init__.py +0 -0
- rook_cli-0.2.0/src/rook/persistence/archive.py +72 -0
- rook_cli-0.2.0/src/rook/persistence/database.py +18 -0
- rook_cli-0.2.0/src/rook/persistence/metadata.py +56 -0
- rook_cli-0.2.0/src/rook/persistence/migrations.py +111 -0
- rook_cli-0.2.0/src/rook/persistence/tasks.py +185 -0
- rook_cli-0.2.0/src/rook/services/__init__.py +0 -0
- rook_cli-0.2.0/src/rook/services/rollover.py +94 -0
- rook_cli-0.2.0/src/rook/services/tasks.py +85 -0
- rook_cli-0.2.0/src/rook/services/undo.py +72 -0
- rook_cli-0.2.0/src/rook/symbols.py +40 -0
- rook_cli-0.2.0/src/rook/widgets/__init__.py +0 -0
- rook_cli-0.2.0/src/rook/widgets/archive_screen.py +162 -0
- rook_cli-0.2.0/src/rook/widgets/shortcut_footer.py +79 -0
- rook_cli-0.2.0/src/rook/widgets/task_line_input.py +44 -0
- rook_cli-0.2.0/src/rook/widgets/task_list.py +415 -0
- rook_cli-0.2.0/src/rook/widgets/task_row.py +155 -0
- rook_cli-0.2.0/tests/support.py +75 -0
- rook_cli-0.2.0/tests/test_app.py +369 -0
- rook_cli-0.2.0/tests/test_archive_navigation.py +188 -0
- rook_cli-0.2.0/tests/test_archive_queries.py +152 -0
- rook_cli-0.2.0/tests/test_formatting.py +11 -0
- rook_cli-0.2.0/tests/test_migrations.py +52 -0
- rook_cli-0.2.0/tests/test_paths.py +20 -0
- rook_cli-0.2.0/tests/test_persistence_failure.py +47 -0
- rook_cli-0.2.0/tests/test_rollover.py +257 -0
- rook_cli-0.2.0/tests/test_rollover_app.py +104 -0
- rook_cli-0.2.0/tests/test_selection.py +40 -0
- rook_cli-0.2.0/tests/test_shortcut_footer_selection.py +26 -0
- rook_cli-0.2.0/tests/test_smoke.py +5 -0
- rook_cli-0.2.0/tests/test_symbols.py +30 -0
- rook_cli-0.2.0/tests/test_task_creation_and_editing.py +430 -0
- rook_cli-0.2.0/tests/test_task_repository.py +153 -0
- rook_cli-0.2.0/tests/test_task_row_rendering.py +57 -0
- rook_cli-0.2.0/tests/test_task_service.py +37 -0
- rook_cli-0.2.0/tests/test_task_states.py +261 -0
- rook_cli-0.2.0/tests/test_undo.py +245 -0
- rook_cli-0.2.0/tests/test_undo_manager.py +34 -0
- rook_cli-0.2.0/tests/test_widget_markup_safety.py +47 -0
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
{
|
|
2
|
+
"permissions": {
|
|
3
|
+
"allow": [
|
|
4
|
+
"PowerShell(\\(Get-Content \"C:\\\\Users\\\\janchawla\\\\rook\\\\DEVELOPMENT_GUIDE.md\" | Measure-Object -Line\\).Lines)",
|
|
5
|
+
"PowerShell(\\(Get-Content \"C:\\\\Users\\\\janchawla\\\\rook\\\\DEVELOPMENT_GUIDE.md\"\\).Count)",
|
|
6
|
+
"PowerShell(py *)",
|
|
7
|
+
"PowerShell(Get-Command *)",
|
|
8
|
+
"PowerShell(python3 --version; python3 -c \"import sys; print\\(sys.executable\\)\")",
|
|
9
|
+
"PowerShell(git config *)",
|
|
10
|
+
"PowerShell(python3 -m venv .venv; Write-Host \"exit code: $LASTEXITCODE\")",
|
|
11
|
+
"PowerShell(.\\\\.venv\\\\Scripts\\\\python.exe -m pip install --upgrade pip 2>&1 | Select-Object -Last 5; .\\\\.venv\\\\Scripts\\\\python.exe -m pip install -e \".[dev]\" 2>&1 | Select-Object -Last 40)",
|
|
12
|
+
"PowerShell(.\\\\.venv\\\\Scripts\\\\python.exe -m pytest -q)",
|
|
13
|
+
"PowerShell(.\\\\.venv\\\\Scripts\\\\python.exe -m ruff check .; Write-Host \"ruff check exit: $LASTEXITCODE\"; .\\\\.venv\\\\Scripts\\\\python.exe -m ruff format --check .; Write-Host \"ruff format exit: $LASTEXITCODE\")",
|
|
14
|
+
"PowerShell(.\\\\.venv\\\\Scripts\\\\python.exe -m mypy src)",
|
|
15
|
+
"PowerShell(.\\\\.venv\\\\Scripts\\\\python.exe -m build 2>&1 | Select-Object -Last 20)",
|
|
16
|
+
"PowerShell(.\\\\.venv\\\\Scripts\\\\python.exe -m rook; Write-Host \"---\"; .\\\\.venv\\\\Scripts\\\\rook.exe; Write-Host \"---\"; Get-ChildItem dist)",
|
|
17
|
+
"PowerShell(git add *)",
|
|
18
|
+
"PowerShell(git commit *)",
|
|
19
|
+
"PowerShell(.\\\\.venv\\\\Scripts\\\\python.exe -m pip install -e \".[dev]\" 2>&1 | Select-Object -Last 30)",
|
|
20
|
+
"PowerShell(.\\\\.venv\\\\Scripts\\\\python.exe -m pytest -q 2>&1 | Select-Object -Last 80)",
|
|
21
|
+
"PowerShell(.\\\\.venv\\\\Scripts\\\\python.exe -m pytest -q 2>&1 | Select-Object -Last 60)",
|
|
22
|
+
"PowerShell(Remove-Item *)",
|
|
23
|
+
"PowerShell(.\\\\.venv\\\\Scripts\\\\python.exe -m ruff check .; Write-Host \"ruff check exit: $LASTEXITCODE\"; .\\\\.venv\\\\Scripts\\\\python.exe -m ruff format --check .; Write-Host \"ruff format exit: $LASTEXITCODE\"; .\\\\.venv\\\\Scripts\\\\python.exe -m mypy src)",
|
|
24
|
+
"PowerShell(.\\\\.venv\\\\Scripts\\\\python.exe -m pytest -q; Write-Host \"pytest exit: $LASTEXITCODE\"; .\\\\.venv\\\\Scripts\\\\python.exe -m ruff check .; .\\\\.venv\\\\Scripts\\\\python.exe -m ruff format --check .; .\\\\.venv\\\\Scripts\\\\python.exe -m mypy src)",
|
|
25
|
+
"PowerShell(.\\\\.venv\\\\Scripts\\\\python.exe -m pytest -q 2>&1 | Select-Object -Last 150)",
|
|
26
|
+
"PowerShell(.\\\\.venv\\\\Scripts\\\\python.exe -m ruff check .)",
|
|
27
|
+
"PowerShell(.\\\\.venv\\\\Scripts\\\\python.exe -m ruff check .; Write-Host \"check exit: $LASTEXITCODE\"; .\\\\.venv\\\\Scripts\\\\python.exe -m ruff format --check . 2>&1)",
|
|
28
|
+
"PowerShell(.\\\\.venv\\\\Scripts\\\\python.exe -m ruff format .; .\\\\.venv\\\\Scripts\\\\python.exe -m ruff check .; .\\\\.venv\\\\Scripts\\\\python.exe -m ruff format --check .)",
|
|
29
|
+
"PowerShell(.\\\\.venv\\\\Scripts\\\\python.exe -m pytest tests/test_widget_markup_safety.py -q 2>&1 | Select-Object -Last 60)",
|
|
30
|
+
"PowerShell(.\\\\.venv\\\\Scripts\\\\python.exe -m pytest -q 2>&1 | Select-Object -Last 200)",
|
|
31
|
+
"PowerShell(.\\\\.venv\\\\Scripts\\\\python.exe -m pytest -q 2>&1 | Select-Object -Last 100)",
|
|
32
|
+
"PowerShell(.\\\\.venv\\\\Scripts\\\\python.exe -m ruff check .; Write-Host \"check exit: $LASTEXITCODE\"; .\\\\.venv\\\\Scripts\\\\python.exe -m ruff format --check .)",
|
|
33
|
+
"PowerShell(.\\\\.venv\\\\Scripts\\\\python.exe -m ruff format .; .\\\\.venv\\\\Scripts\\\\python.exe -m ruff check .; .\\\\.venv\\\\Scripts\\\\python.exe -m ruff format --check .; .\\\\.venv\\\\Scripts\\\\python.exe -m mypy src)",
|
|
34
|
+
"PowerShell(.\\\\.venv\\\\Scripts\\\\python.exe -m pytest tests/test_task_creation_and_editing.py -q 2>&1 | Select-Object -Last 250)",
|
|
35
|
+
"PowerShell(.\\\\.venv\\\\Scripts\\\\python.exe -m pytest tests/test_task_creation_and_editing.py -q 2>&1 | Select-Object -Last 150)",
|
|
36
|
+
"PowerShell(.\\\\.venv\\\\Scripts\\\\python.exe -m ruff check .; Write-Host \"check exit: $LASTEXITCODE\"; .\\\\.venv\\\\Scripts\\\\python.exe -m ruff format --check .; .\\\\.venv\\\\Scripts\\\\python.exe -m mypy src)",
|
|
37
|
+
"PowerShell(.\\\\.venv\\\\Scripts\\\\python.exe -m pytest -q 2>&1 | Select-Object -Last 250)",
|
|
38
|
+
"PowerShell(.\\\\.venv\\\\Scripts\\\\python.exe -m mypy src; Write-Host \"mypy exit: $LASTEXITCODE\"; .\\\\.venv\\\\Scripts\\\\python.exe -m pytest -q 2>&1 | Select-Object -Last 60)",
|
|
39
|
+
"PowerShell(.\\\\.venv\\\\Scripts\\\\python.exe -m pytest tests/test_paths.py -q 2>&1 | Select-Object -Last 60)",
|
|
40
|
+
"PowerShell(.\\\\.venv\\\\Scripts\\\\python.exe -m pytest -q 2>&1 | Select-Object -Last 60; Write-Host \"---\"; .\\\\.venv\\\\Scripts\\\\python.exe -m ruff check .; .\\\\.venv\\\\Scripts\\\\python.exe -m ruff format --check .; .\\\\.venv\\\\Scripts\\\\python.exe -m mypy src)",
|
|
41
|
+
"PowerShell(.\\\\.venv\\\\Scripts\\\\python.exe -m pytest tests/test_app.py -q -k \"bold or scrollbar\" 2>&1 | Select-Object -Last 100)",
|
|
42
|
+
"PowerShell(.\\\\.venv\\\\Scripts\\\\python.exe -m pytest tests/test_app.py -q -k \"bold or scrollbar\" 2>&1 | Select-Object -Last 60)",
|
|
43
|
+
"PowerShell(.\\\\.venv\\\\Scripts\\\\python.exe -m pytest -q 2>&1 | Select-Object -Last 30; Write-Host \"---\"; .\\\\.venv\\\\Scripts\\\\python.exe -m mypy src)",
|
|
44
|
+
"PowerShell(.\\\\.venv\\\\Scripts\\\\python.exe -m pytest -q 2>&1 | Select-Object -Last 40; Write-Host \"---\"; .\\\\.venv\\\\Scripts\\\\python.exe -m ruff check .; .\\\\.venv\\\\Scripts\\\\python.exe -m ruff format --check .; .\\\\.venv\\\\Scripts\\\\python.exe -m mypy src)",
|
|
45
|
+
"PowerShell(.\\\\.venv\\\\Scripts\\\\python.exe -m pytest tests/test_task_creation_and_editing.py -q -k cursor 2>&1 | Select-Object -Last 60)",
|
|
46
|
+
"PowerShell(.\\\\.venv\\\\Scripts\\\\python.exe -m pytest -q 2>&1 | Select-Object -Last 40)",
|
|
47
|
+
"PowerShell(.\\\\.venv\\\\Scripts\\\\python.exe -m pytest tests/test_task_states.py -q 2>&1 | Select-Object -Last 60)",
|
|
48
|
+
"PowerShell(.\\\\.venv\\\\Scripts\\\\python.exe -m pytest tests/test_task_states.py -q 2>&1 | Select-Object -Last 200)",
|
|
49
|
+
"PowerShell(.\\\\.venv\\\\Scripts\\\\python.exe -m ruff format --check .)",
|
|
50
|
+
"PowerShell(.\\\\.venv\\\\Scripts\\\\python.exe -m mypy src; Write-Host \"mypy exit: $LASTEXITCODE\"; .\\\\.venv\\\\Scripts\\\\python.exe -m pytest -q 2>&1 | Select-Object -Last 40)",
|
|
51
|
+
"PowerShell(.\\\\.venv\\\\Scripts\\\\python.exe -m mypy src; Write-Host \"mypy exit: $LASTEXITCODE\")",
|
|
52
|
+
"PowerShell(.\\\\.venv\\\\Scripts\\\\python.exe -m pytest tests/test_undo.py tests/test_undo_manager.py tests/test_task_repository.py -q 2>&1 | Select-Object -Last 250)",
|
|
53
|
+
"PowerShell(.\\\\.venv\\\\Scripts\\\\python.exe -m pytest -q 2>&1 | Select-Object -Last 30)",
|
|
54
|
+
"PowerShell(.\\\\.venv\\\\Scripts\\\\python.exe -m pytest tests/test_rollover.py -q 2>&1 | Select-Object -Last 250)",
|
|
55
|
+
"PowerShell(.\\\\.venv\\\\Scripts\\\\python.exe -m ruff check --fix .)",
|
|
56
|
+
"PowerShell(.\\\\.venv\\\\Scripts\\\\python.exe -m ruff check .; Write-Host \"check exit: $LASTEXITCODE\"; .\\\\.venv\\\\Scripts\\\\python.exe -m ruff format .; .\\\\.venv\\\\Scripts\\\\python.exe -m ruff format --check .; .\\\\.venv\\\\Scripts\\\\python.exe -m mypy src)",
|
|
57
|
+
"PowerShell(.\\\\.venv\\\\Scripts\\\\python.exe -m pytest tests/test_rollover_app.py -q 2>&1 | Select-Object -Last 250)",
|
|
58
|
+
"PowerShell(.\\\\.venv\\\\Scripts\\\\python.exe -m pytest tests/test_rollover_app.py -q 2>&1 | Select-Object -Last 150)",
|
|
59
|
+
"PowerShell(.\\\\.venv\\\\Scripts\\\\python.exe -m mypy src; Write-Host \"---\"; .\\\\.venv\\\\Scripts\\\\python.exe -m pytest -q 2>&1 | Select-Object -Last 30)",
|
|
60
|
+
"PowerShell(jq *)",
|
|
61
|
+
"PowerShell(claude *)",
|
|
62
|
+
"PowerShell(Get-Content *)",
|
|
63
|
+
"Artifact"
|
|
64
|
+
]
|
|
65
|
+
}
|
|
66
|
+
}
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
{
|
|
2
|
+
"permissions": {
|
|
3
|
+
"allow": [
|
|
4
|
+
"PowerShell(\\(Get-Content \"C:\\\\Users\\\\janchawla\\\\rook\\\\DEVELOPMENT_GUIDE.md\" | Measure-Object -Line\\).Lines)",
|
|
5
|
+
"PowerShell(\\(Get-Content \"C:\\\\Users\\\\janchawla\\\\rook\\\\DEVELOPMENT_GUIDE.md\"\\).Count)",
|
|
6
|
+
"PowerShell(py *)",
|
|
7
|
+
"PowerShell(Get-Command *)",
|
|
8
|
+
"PowerShell(python3 --version; python3 -c \"import sys; print\\(sys.executable\\)\")",
|
|
9
|
+
"PowerShell(git config *)",
|
|
10
|
+
"PowerShell(python3 -m venv .venv; Write-Host \"exit code: $LASTEXITCODE\")",
|
|
11
|
+
"PowerShell(.\\\\.venv\\\\Scripts\\\\python.exe -m pip install --upgrade pip 2>&1 | Select-Object -Last 5; .\\\\.venv\\\\Scripts\\\\python.exe -m pip install -e \".[dev]\" 2>&1 | Select-Object -Last 40)",
|
|
12
|
+
"PowerShell(.\\\\.venv\\\\Scripts\\\\python.exe -m pytest -q)",
|
|
13
|
+
"PowerShell(.\\\\.venv\\\\Scripts\\\\python.exe -m ruff check .; Write-Host \"ruff check exit: $LASTEXITCODE\"; .\\\\.venv\\\\Scripts\\\\python.exe -m ruff format --check .; Write-Host \"ruff format exit: $LASTEXITCODE\")",
|
|
14
|
+
"PowerShell(.\\\\.venv\\\\Scripts\\\\python.exe -m mypy src)",
|
|
15
|
+
"PowerShell(.\\\\.venv\\\\Scripts\\\\python.exe -m build 2>&1 | Select-Object -Last 20)",
|
|
16
|
+
"PowerShell(.\\\\.venv\\\\Scripts\\\\python.exe -m rook; Write-Host \"---\"; .\\\\.venv\\\\Scripts\\\\rook.exe; Write-Host \"---\"; Get-ChildItem dist)",
|
|
17
|
+
"PowerShell(git add *)",
|
|
18
|
+
"PowerShell(git commit *)",
|
|
19
|
+
"PowerShell(.\\\\.venv\\\\Scripts\\\\python.exe -m pip install -e \".[dev]\" 2>&1 | Select-Object -Last 30)",
|
|
20
|
+
"PowerShell(.\\\\.venv\\\\Scripts\\\\python.exe -m pytest -q 2>&1 | Select-Object -Last 80)",
|
|
21
|
+
"PowerShell(.\\\\.venv\\\\Scripts\\\\python.exe -m pytest -q 2>&1 | Select-Object -Last 60)",
|
|
22
|
+
"PowerShell(Remove-Item *)",
|
|
23
|
+
"PowerShell(.\\\\.venv\\\\Scripts\\\\python.exe -m ruff check .; Write-Host \"ruff check exit: $LASTEXITCODE\"; .\\\\.venv\\\\Scripts\\\\python.exe -m ruff format --check .; Write-Host \"ruff format exit: $LASTEXITCODE\"; .\\\\.venv\\\\Scripts\\\\python.exe -m mypy src)",
|
|
24
|
+
"PowerShell(.\\\\.venv\\\\Scripts\\\\python.exe -m pytest -q; Write-Host \"pytest exit: $LASTEXITCODE\"; .\\\\.venv\\\\Scripts\\\\python.exe -m ruff check .; .\\\\.venv\\\\Scripts\\\\python.exe -m ruff format --check .; .\\\\.venv\\\\Scripts\\\\python.exe -m mypy src)",
|
|
25
|
+
"PowerShell(.\\\\.venv\\\\Scripts\\\\python.exe -m pytest -q 2>&1 | Select-Object -Last 150)",
|
|
26
|
+
"PowerShell(.\\\\.venv\\\\Scripts\\\\python.exe -m ruff check .)",
|
|
27
|
+
"PowerShell(.\\\\.venv\\\\Scripts\\\\python.exe -m ruff check .; Write-Host \"check exit: $LASTEXITCODE\"; .\\\\.venv\\\\Scripts\\\\python.exe -m ruff format --check . 2>&1)",
|
|
28
|
+
"PowerShell(.\\\\.venv\\\\Scripts\\\\python.exe -m ruff format .; .\\\\.venv\\\\Scripts\\\\python.exe -m ruff check .; .\\\\.venv\\\\Scripts\\\\python.exe -m ruff format --check .)",
|
|
29
|
+
"PowerShell(.\\\\.venv\\\\Scripts\\\\python.exe -m pytest tests/test_widget_markup_safety.py -q 2>&1 | Select-Object -Last 60)",
|
|
30
|
+
"PowerShell(.\\\\.venv\\\\Scripts\\\\python.exe -m pytest -q 2>&1 | Select-Object -Last 200)",
|
|
31
|
+
"PowerShell(.\\\\.venv\\\\Scripts\\\\python.exe -m pytest -q 2>&1 | Select-Object -Last 100)",
|
|
32
|
+
"PowerShell(.\\\\.venv\\\\Scripts\\\\python.exe -m ruff check .; Write-Host \"check exit: $LASTEXITCODE\"; .\\\\.venv\\\\Scripts\\\\python.exe -m ruff format --check .)",
|
|
33
|
+
"PowerShell(.\\\\.venv\\\\Scripts\\\\python.exe -m ruff format .; .\\\\.venv\\\\Scripts\\\\python.exe -m ruff check .; .\\\\.venv\\\\Scripts\\\\python.exe -m ruff format --check .; .\\\\.venv\\\\Scripts\\\\python.exe -m mypy src)",
|
|
34
|
+
"PowerShell(.\\\\.venv\\\\Scripts\\\\python.exe -m pytest tests/test_task_creation_and_editing.py -q 2>&1 | Select-Object -Last 250)",
|
|
35
|
+
"PowerShell(.\\\\.venv\\\\Scripts\\\\python.exe -m pytest tests/test_task_creation_and_editing.py -q 2>&1 | Select-Object -Last 150)",
|
|
36
|
+
"PowerShell(.\\\\.venv\\\\Scripts\\\\python.exe -m ruff check .; Write-Host \"check exit: $LASTEXITCODE\"; .\\\\.venv\\\\Scripts\\\\python.exe -m ruff format --check .; .\\\\.venv\\\\Scripts\\\\python.exe -m mypy src)",
|
|
37
|
+
"PowerShell(.\\\\.venv\\\\Scripts\\\\python.exe -m pytest -q 2>&1 | Select-Object -Last 250)",
|
|
38
|
+
"PowerShell(.\\\\.venv\\\\Scripts\\\\python.exe -m mypy src; Write-Host \"mypy exit: $LASTEXITCODE\"; .\\\\.venv\\\\Scripts\\\\python.exe -m pytest -q 2>&1 | Select-Object -Last 60)",
|
|
39
|
+
"PowerShell(.\\\\.venv\\\\Scripts\\\\python.exe -m pytest tests/test_paths.py -q 2>&1 | Select-Object -Last 60)",
|
|
40
|
+
"PowerShell(.\\\\.venv\\\\Scripts\\\\python.exe -m pytest -q 2>&1 | Select-Object -Last 60; Write-Host \"---\"; .\\\\.venv\\\\Scripts\\\\python.exe -m ruff check .; .\\\\.venv\\\\Scripts\\\\python.exe -m ruff format --check .; .\\\\.venv\\\\Scripts\\\\python.exe -m mypy src)",
|
|
41
|
+
"PowerShell(.\\\\.venv\\\\Scripts\\\\python.exe -m pytest tests/test_app.py -q -k \"bold or scrollbar\" 2>&1 | Select-Object -Last 100)",
|
|
42
|
+
"PowerShell(.\\\\.venv\\\\Scripts\\\\python.exe -m pytest tests/test_app.py -q -k \"bold or scrollbar\" 2>&1 | Select-Object -Last 60)",
|
|
43
|
+
"PowerShell(.\\\\.venv\\\\Scripts\\\\python.exe -m pytest -q 2>&1 | Select-Object -Last 30; Write-Host \"---\"; .\\\\.venv\\\\Scripts\\\\python.exe -m mypy src)",
|
|
44
|
+
"PowerShell(.\\\\.venv\\\\Scripts\\\\python.exe -m pytest -q 2>&1 | Select-Object -Last 40; Write-Host \"---\"; .\\\\.venv\\\\Scripts\\\\python.exe -m ruff check .; .\\\\.venv\\\\Scripts\\\\python.exe -m ruff format --check .; .\\\\.venv\\\\Scripts\\\\python.exe -m mypy src)",
|
|
45
|
+
"PowerShell(.\\\\.venv\\\\Scripts\\\\python.exe -m pytest tests/test_task_creation_and_editing.py -q -k cursor 2>&1 | Select-Object -Last 60)",
|
|
46
|
+
"PowerShell(.\\\\.venv\\\\Scripts\\\\python.exe -m pytest -q 2>&1 | Select-Object -Last 40)",
|
|
47
|
+
"PowerShell(.\\\\.venv\\\\Scripts\\\\python.exe -m pytest tests/test_task_states.py -q 2>&1 | Select-Object -Last 60)",
|
|
48
|
+
"PowerShell(.\\\\.venv\\\\Scripts\\\\python.exe -m pytest tests/test_task_states.py -q 2>&1 | Select-Object -Last 200)",
|
|
49
|
+
"PowerShell(.\\\\.venv\\\\Scripts\\\\python.exe -m ruff format --check .)",
|
|
50
|
+
"PowerShell(.\\\\.venv\\\\Scripts\\\\python.exe -m mypy src; Write-Host \"mypy exit: $LASTEXITCODE\"; .\\\\.venv\\\\Scripts\\\\python.exe -m pytest -q 2>&1 | Select-Object -Last 40)",
|
|
51
|
+
"PowerShell(.\\\\.venv\\\\Scripts\\\\python.exe -m mypy src; Write-Host \"mypy exit: $LASTEXITCODE\")",
|
|
52
|
+
"PowerShell(.\\\\.venv\\\\Scripts\\\\python.exe -m pytest tests/test_undo.py tests/test_undo_manager.py tests/test_task_repository.py -q 2>&1 | Select-Object -Last 250)",
|
|
53
|
+
"PowerShell(.\\\\.venv\\\\Scripts\\\\python.exe -m pytest -q 2>&1 | Select-Object -Last 30)",
|
|
54
|
+
"PowerShell(.\\\\.venv\\\\Scripts\\\\python.exe -m pytest tests/test_rollover.py -q 2>&1 | Select-Object -Last 250)",
|
|
55
|
+
"PowerShell(.\\\\.venv\\\\Scripts\\\\python.exe -m ruff check --fix .)",
|
|
56
|
+
"PowerShell(.\\\\.venv\\\\Scripts\\\\python.exe -m ruff check .; Write-Host \"check exit: $LASTEXITCODE\"; .\\\\.venv\\\\Scripts\\\\python.exe -m ruff format .; .\\\\.venv\\\\Scripts\\\\python.exe -m ruff format --check .; .\\\\.venv\\\\Scripts\\\\python.exe -m mypy src)",
|
|
57
|
+
"PowerShell(.\\\\.venv\\\\Scripts\\\\python.exe -m pytest tests/test_rollover_app.py -q 2>&1 | Select-Object -Last 250)",
|
|
58
|
+
"PowerShell(.\\\\.venv\\\\Scripts\\\\python.exe -m pytest tests/test_rollover_app.py -q 2>&1 | Select-Object -Last 150)",
|
|
59
|
+
"PowerShell(.\\\\.venv\\\\Scripts\\\\python.exe -m mypy src; Write-Host \"---\"; .\\\\.venv\\\\Scripts\\\\python.exe -m pytest -q 2>&1 | Select-Object -Last 30)",
|
|
60
|
+
"PowerShell(jq *)",
|
|
61
|
+
"PowerShell(claude *)",
|
|
62
|
+
"PowerShell(Get-Content *)",
|
|
63
|
+
"Artifact"
|
|
64
|
+
]
|
|
65
|
+
}
|
|
66
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
.venv/
|
|
2
|
+
__pycache__/
|
|
3
|
+
*.py[cod]
|
|
4
|
+
.pytest_cache/
|
|
5
|
+
.mypy_cache/
|
|
6
|
+
.ruff_cache/
|
|
7
|
+
.coverage
|
|
8
|
+
htmlcov/
|
|
9
|
+
dist/
|
|
10
|
+
build/
|
|
11
|
+
*.egg-info/
|
|
12
|
+
*.db
|
|
13
|
+
*.db-journal
|
|
14
|
+
*.db-wal
|
|
15
|
+
*.db-shm
|
|
16
|
+
*.sqlite
|
|
17
|
+
*.sqlite3
|
|
18
|
+
.env
|
|
19
|
+
.DS_Store
|
|
20
|
+
Thumbs.db
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
Copyright (c) 2026 Janvi Chawla. All Rights Reserved.
|
|
2
|
+
|
|
3
|
+
This software and its source code are proprietary and confidential.
|
|
4
|
+
No part of this software may be copied, modified, merged, distributed,
|
|
5
|
+
sublicensed, or used to create derivative works without explicit written
|
|
6
|
+
permission from the copyright owner.
|
|
7
|
+
|
|
8
|
+
You may install and use this software for personal, non-commercial purposes.
|
|
9
|
+
You may not redistribute it, repackage it, or incorporate it into another
|
|
10
|
+
product or service without permission.
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
# Rook ♖
|
|
2
|
+
|
|
3
|
+
A local, keyboard-first terminal journal for working through one day at a time.
|
|
4
|
+
|
|
5
|
+
```text
|
|
6
|
+
rook ♖ Today — Friday, July 24, 2026
|
|
7
|
+
⋆⁺₊ (。'▽'。)♡ ₊⁺⋆ "Showing up is the whole trick."
|
|
8
|
+
|
|
9
|
+
❯ • Finish the presentation
|
|
10
|
+
• Reply to Alex
|
|
11
|
+
> Read Chapter 3
|
|
12
|
+
× Submit the expense report
|
|
13
|
+
|
|
14
|
+
[n] new [e/Ent] edit [x] complete [>] migrate [d] delete [u] undo [a] archive [q] quit
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
Rook is inspired by the simplicity of a paper bullet journal:
|
|
18
|
+
|
|
19
|
+
- one active list: **Today**
|
|
20
|
+
- direct, in-place editing
|
|
21
|
+
- local SQLite storage
|
|
22
|
+
- read-only history
|
|
23
|
+
- no accounts, cloud sync, reminders, priorities, or telemetry
|
|
24
|
+
|
|
25
|
+
## Installation
|
|
26
|
+
|
|
27
|
+
Requires Python 3.10 or newer. Install with [uv](https://docs.astral.sh/uv/):
|
|
28
|
+
|
|
29
|
+
```powershell
|
|
30
|
+
uv tool install rook-cli
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
Then launch:
|
|
34
|
+
|
|
35
|
+
```powershell
|
|
36
|
+
rook
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
To upgrade later:
|
|
40
|
+
|
|
41
|
+
```powershell
|
|
42
|
+
uv tool upgrade rook-cli
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
## Keyboard reference
|
|
46
|
+
|
|
47
|
+
| Key | Action |
|
|
48
|
+
|-----|--------|
|
|
49
|
+
| `n` | New task |
|
|
50
|
+
| `e` or `Ent` | Edit selected task |
|
|
51
|
+
| `x` | Toggle complete |
|
|
52
|
+
| `>` | Toggle migrated |
|
|
53
|
+
| `d` | Soft-delete / permanently remove (press twice) |
|
|
54
|
+
| `u` | Undo last action |
|
|
55
|
+
| `a` | Open weekly archive |
|
|
56
|
+
| `↑` / `↓` | Move selection |
|
|
57
|
+
| `Esc` | Cancel edit |
|
|
58
|
+
| `q` | Quit |
|
|
59
|
+
|
|
60
|
+
## Data and privacy
|
|
61
|
+
|
|
62
|
+
Tasks are stored in a local SQLite database. Nothing leaves your machine.
|
|
63
|
+
|
|
64
|
+
| Platform | Location |
|
|
65
|
+
|----------|----------|
|
|
66
|
+
| Windows | `%LOCALAPPDATA%\Rook\data.sqlite3` |
|
|
67
|
+
| macOS | `~/Library/Application Support/Rook/data.sqlite3` |
|
|
68
|
+
| Linux | `~/.local/share/rook/data.sqlite3` |
|
|
69
|
+
|
|
70
|
+
To print the exact path on your system:
|
|
71
|
+
|
|
72
|
+
```powershell
|
|
73
|
+
rook --data-path
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
Uninstalling Rook does not delete the database.
|
|
77
|
+
|
|
78
|
+
## FAQ
|
|
79
|
+
|
|
80
|
+
**How do I change the archive week layout from Sun–Sat to Mon–Sun?**
|
|
81
|
+
|
|
82
|
+
There is no in-app setting yet. Update the value directly in the SQLite database.
|
|
83
|
+
Find the exact path with `rook --data-path`, or use the default:
|
|
84
|
+
|
|
85
|
+
```powershell
|
|
86
|
+
sqlite3 "$env:LOCALAPPDATA\Rook\data.sqlite3"
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
```sql
|
|
90
|
+
INSERT OR REPLACE INTO app_meta (key, value) VALUES ('week_start_day', 'monday');
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
To switch back to Sunday-start:
|
|
94
|
+
|
|
95
|
+
```sql
|
|
96
|
+
INSERT OR REPLACE INTO app_meta (key, value) VALUES ('week_start_day', 'sunday');
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
## License
|
|
100
|
+
|
|
101
|
+
Copyright (c) 2026 Janvi Chawla. All Rights Reserved.
|
|
102
|
+
|
|
103
|
+
Personal use permitted. No redistribution or derivative works without permission.
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["hatchling"]
|
|
3
|
+
build-backend = "hatchling.build"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "rook-cli"
|
|
7
|
+
dynamic = ["version"]
|
|
8
|
+
description = "A local, keyboard-first terminal daily journal."
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
license = "LicenseRef-Proprietary"
|
|
11
|
+
requires-python = ">=3.10"
|
|
12
|
+
authors = [
|
|
13
|
+
{ name = "Janvi Chawla" },
|
|
14
|
+
]
|
|
15
|
+
dependencies = [
|
|
16
|
+
"textual>=0.60",
|
|
17
|
+
]
|
|
18
|
+
|
|
19
|
+
[project.optional-dependencies]
|
|
20
|
+
dev = [
|
|
21
|
+
"pytest>=8.0",
|
|
22
|
+
"ruff>=0.6",
|
|
23
|
+
"mypy>=1.10",
|
|
24
|
+
"build>=1.2",
|
|
25
|
+
]
|
|
26
|
+
|
|
27
|
+
[project.urls]
|
|
28
|
+
Repository = "https://github.com/JanviChawla/rook"
|
|
29
|
+
|
|
30
|
+
[project.scripts]
|
|
31
|
+
rook = "rook.__main__:main"
|
|
32
|
+
|
|
33
|
+
[tool.hatch.version]
|
|
34
|
+
path = "src/rook/__init__.py"
|
|
35
|
+
|
|
36
|
+
[tool.hatch.build.targets.wheel]
|
|
37
|
+
packages = ["src/rook"]
|
|
38
|
+
|
|
39
|
+
[tool.ruff]
|
|
40
|
+
line-length = 100
|
|
41
|
+
target-version = "py310"
|
|
42
|
+
|
|
43
|
+
[tool.ruff.lint]
|
|
44
|
+
select = ["E", "F", "I", "UP", "B"]
|
|
45
|
+
|
|
46
|
+
[tool.mypy]
|
|
47
|
+
python_version = "3.10"
|
|
48
|
+
strict = true
|
|
49
|
+
|
|
50
|
+
[tool.pytest.ini_options]
|
|
51
|
+
testpaths = ["tests"]
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
__version__ = "0.2.0"
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import sys
|
|
2
|
+
|
|
3
|
+
from rook.app import RookApp
|
|
4
|
+
from rook.paths import default_database_path
|
|
5
|
+
from rook.persistence.database import connect
|
|
6
|
+
from rook.persistence.metadata import MetadataRepository
|
|
7
|
+
from rook.persistence.migrations import UnsupportedSchemaVersionError, migrate
|
|
8
|
+
from rook.persistence.tasks import TaskRepository
|
|
9
|
+
from rook.services.rollover import RolloverService
|
|
10
|
+
from rook.services.tasks import TaskService
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
def main() -> int:
|
|
14
|
+
if len(sys.argv) > 1 and sys.argv[1] == "--data-path":
|
|
15
|
+
print(default_database_path())
|
|
16
|
+
return 0
|
|
17
|
+
|
|
18
|
+
db_path = default_database_path()
|
|
19
|
+
connection = connect(db_path)
|
|
20
|
+
|
|
21
|
+
try:
|
|
22
|
+
migrate(connection)
|
|
23
|
+
except UnsupportedSchemaVersionError as error:
|
|
24
|
+
connection.close()
|
|
25
|
+
print(error)
|
|
26
|
+
print(f"Database file: {db_path}")
|
|
27
|
+
return 1
|
|
28
|
+
|
|
29
|
+
task_service = TaskService(TaskRepository(connection))
|
|
30
|
+
rollover_service = RolloverService(connection, MetadataRepository(connection))
|
|
31
|
+
|
|
32
|
+
# Section 16.8: rollover runs once at startup, before Today ever renders.
|
|
33
|
+
rollover_service.roll_forward_if_needed()
|
|
34
|
+
|
|
35
|
+
try:
|
|
36
|
+
RookApp(
|
|
37
|
+
task_service=task_service,
|
|
38
|
+
rollover_service=rollover_service,
|
|
39
|
+
connection=connection,
|
|
40
|
+
).run()
|
|
41
|
+
finally:
|
|
42
|
+
connection.close()
|
|
43
|
+
|
|
44
|
+
return 0
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
if __name__ == "__main__":
|
|
48
|
+
raise SystemExit(main())
|
|
@@ -0,0 +1,222 @@
|
|
|
1
|
+
import sqlite3
|
|
2
|
+
from collections.abc import Callable
|
|
3
|
+
from datetime import date
|
|
4
|
+
|
|
5
|
+
from textual.app import App, ComposeResult
|
|
6
|
+
from textual.binding import Binding
|
|
7
|
+
from textual.widgets import Static
|
|
8
|
+
|
|
9
|
+
from rook import branding
|
|
10
|
+
from rook.formatting import format_header_date
|
|
11
|
+
from rook.persistence.metadata import MetadataRepository
|
|
12
|
+
from rook.services.rollover import RolloverService
|
|
13
|
+
from rook.services.tasks import TaskService
|
|
14
|
+
from rook.services.undo import UndoManager
|
|
15
|
+
from rook.widgets.archive_screen import ArchiveScreen
|
|
16
|
+
from rook.widgets.shortcut_footer import ShortcutFooter
|
|
17
|
+
from rook.widgets.task_list import TaskListView
|
|
18
|
+
|
|
19
|
+
TodayProvider = Callable[[], date]
|
|
20
|
+
|
|
21
|
+
# Section 21.13 explicitly excludes anything more frequent than needed; a
|
|
22
|
+
# once-a-minute check is enough to notice a live midnight crossing without
|
|
23
|
+
# being a tight polling loop.
|
|
24
|
+
ROLLOVER_CHECK_INTERVAL_SECONDS = 60
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
class RookApp(App[None]):
|
|
28
|
+
"""The Rook terminal shell.
|
|
29
|
+
|
|
30
|
+
Phase 5 replaces the in-memory Task list with SQLite as the source of
|
|
31
|
+
truth, via an injected TaskService. Task state changes, Archive, and
|
|
32
|
+
Routines are still not implemented.
|
|
33
|
+
"""
|
|
34
|
+
|
|
35
|
+
CSS = """
|
|
36
|
+
Screen {
|
|
37
|
+
layout: vertical;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
#header, #mascot-quote, #spacer, #status {
|
|
41
|
+
height: 1;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
#header {
|
|
45
|
+
text-style: bold;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
#task-list {
|
|
49
|
+
height: 1fr;
|
|
50
|
+
/* The "ansi-dark" theme doesn't define scrollbar variables (only
|
|
51
|
+
* "ansi-light" happens to), so these fall back to Textual's fixed
|
|
52
|
+
* truecolor defaults - the mismatched, chunky bar reported after
|
|
53
|
+
* scrolling a long list. Set them directly to ANSI colors instead,
|
|
54
|
+
* and use a slimmer single-column bar (Section 11.1 "compact"). */
|
|
55
|
+
scrollbar-size-vertical: 1;
|
|
56
|
+
scrollbar-color: ansi_default;
|
|
57
|
+
scrollbar-color-hover: ansi_default;
|
|
58
|
+
scrollbar-color-active: ansi_default;
|
|
59
|
+
scrollbar-background: ansi_default;
|
|
60
|
+
scrollbar-background-hover: ansi_default;
|
|
61
|
+
scrollbar-background-active: ansi_default;
|
|
62
|
+
scrollbar-corner-color: ansi_default;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/* "ansi-dark" hardcodes the text-entry cursor to a solid reverse-video
|
|
66
|
+
* block in ansi_black on ansi_bright_white, which many customized
|
|
67
|
+
* terminal palettes remap to something unrelated to the terminal's
|
|
68
|
+
* actual foreground/background (reported as an unrelated light gray).
|
|
69
|
+
* Reversing the terminal's own default foreground instead keeps the
|
|
70
|
+
* filled-block look but in the user's own theme color. This is Rook's
|
|
71
|
+
* own simulated text cursor, not the terminal's hardware cursor - a
|
|
72
|
+
* full-screen app owning the whole display can't repurpose the
|
|
73
|
+
* terminal's native caret for a styled, multi-character-wide input. */
|
|
74
|
+
TaskLineInput > .input--cursor {
|
|
75
|
+
color: ansi_default;
|
|
76
|
+
text-style: reverse;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
#footer {
|
|
80
|
+
height: 1;
|
|
81
|
+
dock: bottom;
|
|
82
|
+
}
|
|
83
|
+
"""
|
|
84
|
+
|
|
85
|
+
BINDINGS = [
|
|
86
|
+
Binding("q", "quit", "Quit"),
|
|
87
|
+
Binding("up", "cursor_up", "Up", show=False),
|
|
88
|
+
Binding("down", "cursor_down", "Down", show=False),
|
|
89
|
+
Binding("n", "new_task", "New", show=False),
|
|
90
|
+
Binding("e", "edit_task", "Edit", show=False),
|
|
91
|
+
Binding("enter", "edit_task", "Edit", show=False),
|
|
92
|
+
Binding("x", "toggle_completed", "Complete", show=False),
|
|
93
|
+
Binding(">", "toggle_migrated", "Migrate", show=False),
|
|
94
|
+
Binding("d", "delete_or_remove", "Delete", show=False),
|
|
95
|
+
Binding("u", "undo", "Undo", show=False),
|
|
96
|
+
Binding("a", "archive", "Archive", show=False),
|
|
97
|
+
]
|
|
98
|
+
|
|
99
|
+
def __init__(
|
|
100
|
+
self,
|
|
101
|
+
today_provider: TodayProvider = date.today,
|
|
102
|
+
*,
|
|
103
|
+
task_service: TaskService,
|
|
104
|
+
rollover_service: RolloverService,
|
|
105
|
+
connection: sqlite3.Connection | None = None,
|
|
106
|
+
safe_symbols: bool = False,
|
|
107
|
+
) -> None:
|
|
108
|
+
super().__init__()
|
|
109
|
+
self._today_provider = today_provider
|
|
110
|
+
self._task_service = task_service
|
|
111
|
+
self._rollover_service = rollover_service
|
|
112
|
+
self._connection = connection
|
|
113
|
+
self._rollover_pending = False
|
|
114
|
+
# Session-scoped: owned here (not per-widget) so a later Routine
|
|
115
|
+
# phase can share the same single undo slot (Section 6.10).
|
|
116
|
+
self._undo_manager = UndoManager()
|
|
117
|
+
self._safe_symbols = safe_symbols
|
|
118
|
+
# Map foreground/background to the terminal's own ANSI defaults
|
|
119
|
+
# instead of Textual's fixed truecolor theme, so the app respects
|
|
120
|
+
# the user's existing terminal background (Section 11.9-11.10).
|
|
121
|
+
self.theme = "ansi-dark"
|
|
122
|
+
|
|
123
|
+
def _mascot_quote_text(self) -> str:
|
|
124
|
+
mascot, quote = branding.pick_for_date(self._today_provider())
|
|
125
|
+
return f'{mascot} "{quote}"'
|
|
126
|
+
|
|
127
|
+
def compose(self) -> ComposeResult:
|
|
128
|
+
mascot_quote_text = self._mascot_quote_text()
|
|
129
|
+
tasks = self._task_service.list_active_tasks()
|
|
130
|
+
|
|
131
|
+
yield Static(self._header_text(), id="header", markup=False)
|
|
132
|
+
yield Static(mascot_quote_text, id="mascot-quote", markup=False)
|
|
133
|
+
yield Static("", id="spacer")
|
|
134
|
+
yield TaskListView(
|
|
135
|
+
tasks,
|
|
136
|
+
task_service=self._task_service,
|
|
137
|
+
undo_manager=self._undo_manager,
|
|
138
|
+
safe_symbols=self._safe_symbols,
|
|
139
|
+
id="task-list",
|
|
140
|
+
)
|
|
141
|
+
yield Static("", id="status", markup=False)
|
|
142
|
+
yield ShortcutFooter(has_tasks=bool(tasks), id="footer")
|
|
143
|
+
|
|
144
|
+
def _header_text(self) -> str:
|
|
145
|
+
today = self._today_provider()
|
|
146
|
+
return f"{branding.DISPLAY_NAME.lower()} {branding.ICON} Today — {format_header_date(today)}"
|
|
147
|
+
|
|
148
|
+
def on_mount(self) -> None:
|
|
149
|
+
self.set_interval(ROLLOVER_CHECK_INTERVAL_SECONDS, self._check_for_new_day)
|
|
150
|
+
|
|
151
|
+
async def _check_for_new_day(self) -> None:
|
|
152
|
+
if self.query_one(TaskListView).is_editing:
|
|
153
|
+
# Section 18.12: defer while the user is actively typing;
|
|
154
|
+
# on_task_list_view_editing_changed runs it once they finish.
|
|
155
|
+
self._rollover_pending = True
|
|
156
|
+
return
|
|
157
|
+
await self._apply_rollover_if_needed()
|
|
158
|
+
|
|
159
|
+
async def _apply_rollover_if_needed(self) -> None:
|
|
160
|
+
try:
|
|
161
|
+
result = self._rollover_service.roll_forward_if_needed()
|
|
162
|
+
except Exception:
|
|
163
|
+
# A transient failure here must not crash a running session -
|
|
164
|
+
# Section 16.24's fatal-error handling is for startup, not a
|
|
165
|
+
# live background reconciliation. The next check retries.
|
|
166
|
+
return
|
|
167
|
+
|
|
168
|
+
if not result.changed:
|
|
169
|
+
return
|
|
170
|
+
|
|
171
|
+
self.query_one("#header", Static).update(self._header_text())
|
|
172
|
+
self.query_one("#mascot-quote", Static).update(self._mascot_quote_text())
|
|
173
|
+
tasks = self._task_service.list_active_tasks()
|
|
174
|
+
await self.query_one(TaskListView).reload(tasks)
|
|
175
|
+
self.query_one(ShortcutFooter).set_has_tasks(bool(tasks))
|
|
176
|
+
# Section 6.10: Day Rollover clears session undo after completing.
|
|
177
|
+
self._undo_manager.clear()
|
|
178
|
+
|
|
179
|
+
def action_cursor_up(self) -> None:
|
|
180
|
+
self.query_one(TaskListView).select_previous()
|
|
181
|
+
|
|
182
|
+
def action_cursor_down(self) -> None:
|
|
183
|
+
self.query_one(TaskListView).select_next()
|
|
184
|
+
|
|
185
|
+
async def action_new_task(self) -> None:
|
|
186
|
+
await self.query_one(TaskListView).begin_create()
|
|
187
|
+
|
|
188
|
+
async def action_edit_task(self) -> None:
|
|
189
|
+
await self.query_one(TaskListView).begin_edit()
|
|
190
|
+
|
|
191
|
+
async def action_toggle_completed(self) -> None:
|
|
192
|
+
await self.query_one(TaskListView).toggle_completed()
|
|
193
|
+
|
|
194
|
+
async def action_toggle_migrated(self) -> None:
|
|
195
|
+
await self.query_one(TaskListView).toggle_migrated()
|
|
196
|
+
|
|
197
|
+
async def action_delete_or_remove(self) -> None:
|
|
198
|
+
await self.query_one(TaskListView).delete_or_remove()
|
|
199
|
+
|
|
200
|
+
async def action_undo(self) -> None:
|
|
201
|
+
await self.query_one(TaskListView).undo()
|
|
202
|
+
|
|
203
|
+
def on_task_list_view_status_message(self, message: TaskListView.StatusMessage) -> None:
|
|
204
|
+
self.query_one("#status", Static).update(message.text)
|
|
205
|
+
|
|
206
|
+
async def on_task_list_view_editing_changed(self, message: TaskListView.EditingChanged) -> None:
|
|
207
|
+
self.query_one(ShortcutFooter).set_editing(message.editing)
|
|
208
|
+
self.query_one("#status", Static).update("")
|
|
209
|
+
if not message.editing and self._rollover_pending:
|
|
210
|
+
self._rollover_pending = False
|
|
211
|
+
await self._apply_rollover_if_needed()
|
|
212
|
+
|
|
213
|
+
def on_task_list_view_tasks_empty_changed(
|
|
214
|
+
self, message: TaskListView.TasksEmptyChanged
|
|
215
|
+
) -> None:
|
|
216
|
+
self.query_one(ShortcutFooter).set_has_tasks(message.has_tasks)
|
|
217
|
+
|
|
218
|
+
def action_archive(self) -> None:
|
|
219
|
+
if self._connection is None:
|
|
220
|
+
return
|
|
221
|
+
first_weekday = MetadataRepository(self._connection).get_week_start_day()
|
|
222
|
+
self.push_screen(ArchiveScreen(connection=self._connection, first_weekday=first_weekday))
|