rook-cli 0.2.1__tar.gz → 0.2.2__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.
Files changed (107) hide show
  1. {rook_cli-0.2.1 → rook_cli-0.2.2}/PKG-INFO +4 -2
  2. {rook_cli-0.2.1/.claude/worktrees/streamed-orbiting-llama → rook_cli-0.2.2}/README.md +98 -96
  3. rook_cli-0.2.2/src/rook/__init__.py +1 -0
  4. {rook_cli-0.2.1 → rook_cli-0.2.2}/src/rook/app.py +12 -0
  5. {rook_cli-0.2.1/.claude/worktrees/streamed-orbiting-llama → rook_cli-0.2.2}/src/rook/persistence/archive.py +4 -4
  6. {rook_cli-0.2.1 → rook_cli-0.2.2}/src/rook/services/rollover.py +17 -2
  7. {rook_cli-0.2.1 → rook_cli-0.2.2}/src/rook/symbols.py +3 -4
  8. {rook_cli-0.2.1/.claude/worktrees/streamed-orbiting-llama → rook_cli-0.2.2}/src/rook/widgets/archive_screen.py +9 -1
  9. {rook_cli-0.2.1 → rook_cli-0.2.2}/src/rook/widgets/task_row.py +2 -3
  10. {rook_cli-0.2.1/.claude/worktrees/streamed-orbiting-llama → rook_cli-0.2.2}/tests/test_app.py +1 -1
  11. {rook_cli-0.2.1 → rook_cli-0.2.2}/tests/test_rollover.py +3 -1
  12. {rook_cli-0.2.1 → rook_cli-0.2.2}/tests/test_rollover_app.py +1 -1
  13. {rook_cli-0.2.1 → rook_cli-0.2.2}/tests/test_symbols.py +1 -1
  14. rook_cli-0.2.1/.claude/worktrees/streamed-orbiting-llama/.claude/settings.local.json +0 -66
  15. rook_cli-0.2.1/.claude/worktrees/streamed-orbiting-llama/LICENSE +0 -10
  16. rook_cli-0.2.1/.claude/worktrees/streamed-orbiting-llama/src/rook/__init__.py +0 -1
  17. rook_cli-0.2.1/.claude/worktrees/streamed-orbiting-llama/src/rook/app.py +0 -222
  18. rook_cli-0.2.1/.claude/worktrees/streamed-orbiting-llama/src/rook/branding.py +0 -69
  19. rook_cli-0.2.1/.claude/worktrees/streamed-orbiting-llama/src/rook/domain/tasks.py +0 -55
  20. rook_cli-0.2.1/.claude/worktrees/streamed-orbiting-llama/src/rook/formatting.py +0 -10
  21. rook_cli-0.2.1/.claude/worktrees/streamed-orbiting-llama/src/rook/paths.py +0 -31
  22. rook_cli-0.2.1/.claude/worktrees/streamed-orbiting-llama/src/rook/persistence/database.py +0 -18
  23. rook_cli-0.2.1/.claude/worktrees/streamed-orbiting-llama/src/rook/persistence/migrations.py +0 -111
  24. rook_cli-0.2.1/.claude/worktrees/streamed-orbiting-llama/src/rook/persistence/tasks.py +0 -185
  25. rook_cli-0.2.1/.claude/worktrees/streamed-orbiting-llama/src/rook/services/rollover.py +0 -94
  26. rook_cli-0.2.1/.claude/worktrees/streamed-orbiting-llama/src/rook/services/tasks.py +0 -85
  27. rook_cli-0.2.1/.claude/worktrees/streamed-orbiting-llama/src/rook/services/undo.py +0 -72
  28. rook_cli-0.2.1/.claude/worktrees/streamed-orbiting-llama/src/rook/symbols.py +0 -40
  29. rook_cli-0.2.1/.claude/worktrees/streamed-orbiting-llama/src/rook/widgets/task_line_input.py +0 -44
  30. rook_cli-0.2.1/.claude/worktrees/streamed-orbiting-llama/src/rook/widgets/task_row.py +0 -155
  31. rook_cli-0.2.1/.claude/worktrees/streamed-orbiting-llama/tests/test_formatting.py +0 -11
  32. rook_cli-0.2.1/.claude/worktrees/streamed-orbiting-llama/tests/test_migrations.py +0 -52
  33. rook_cli-0.2.1/.claude/worktrees/streamed-orbiting-llama/tests/test_paths.py +0 -20
  34. rook_cli-0.2.1/.claude/worktrees/streamed-orbiting-llama/tests/test_persistence_failure.py +0 -47
  35. rook_cli-0.2.1/.claude/worktrees/streamed-orbiting-llama/tests/test_rollover.py +0 -257
  36. rook_cli-0.2.1/.claude/worktrees/streamed-orbiting-llama/tests/test_rollover_app.py +0 -104
  37. rook_cli-0.2.1/.claude/worktrees/streamed-orbiting-llama/tests/test_selection.py +0 -40
  38. rook_cli-0.2.1/.claude/worktrees/streamed-orbiting-llama/tests/test_shortcut_footer_selection.py +0 -26
  39. rook_cli-0.2.1/.claude/worktrees/streamed-orbiting-llama/tests/test_smoke.py +0 -5
  40. rook_cli-0.2.1/.claude/worktrees/streamed-orbiting-llama/tests/test_symbols.py +0 -30
  41. rook_cli-0.2.1/.claude/worktrees/streamed-orbiting-llama/tests/test_task_creation_and_editing.py +0 -430
  42. rook_cli-0.2.1/.claude/worktrees/streamed-orbiting-llama/tests/test_task_repository.py +0 -153
  43. rook_cli-0.2.1/.claude/worktrees/streamed-orbiting-llama/tests/test_task_row_rendering.py +0 -57
  44. rook_cli-0.2.1/.claude/worktrees/streamed-orbiting-llama/tests/test_task_service.py +0 -37
  45. rook_cli-0.2.1/.claude/worktrees/streamed-orbiting-llama/tests/test_task_states.py +0 -261
  46. rook_cli-0.2.1/.claude/worktrees/streamed-orbiting-llama/tests/test_undo.py +0 -245
  47. rook_cli-0.2.1/.claude/worktrees/streamed-orbiting-llama/tests/test_undo_manager.py +0 -34
  48. rook_cli-0.2.1/.claude/worktrees/streamed-orbiting-llama/tests/test_widget_markup_safety.py +0 -47
  49. rook_cli-0.2.1/.gitignore +0 -20
  50. rook_cli-0.2.1/README.md +0 -96
  51. rook_cli-0.2.1/pyproject.toml +0 -51
  52. rook_cli-0.2.1/src/rook/__init__.py +0 -1
  53. rook_cli-0.2.1/src/rook/__main__.py +0 -67
  54. rook_cli-0.2.1/src/rook/domain/__init__.py +0 -0
  55. rook_cli-0.2.1/src/rook/persistence/__init__.py +0 -0
  56. rook_cli-0.2.1/src/rook/persistence/archive.py +0 -72
  57. rook_cli-0.2.1/src/rook/persistence/metadata.py +0 -56
  58. rook_cli-0.2.1/src/rook/services/__init__.py +0 -0
  59. rook_cli-0.2.1/src/rook/widgets/__init__.py +0 -0
  60. rook_cli-0.2.1/src/rook/widgets/archive_screen.py +0 -162
  61. rook_cli-0.2.1/src/rook/widgets/shortcut_footer.py +0 -79
  62. rook_cli-0.2.1/src/rook/widgets/task_list.py +0 -415
  63. rook_cli-0.2.1/tests/support.py +0 -75
  64. rook_cli-0.2.1/tests/test_app.py +0 -369
  65. rook_cli-0.2.1/tests/test_archive_navigation.py +0 -188
  66. rook_cli-0.2.1/tests/test_archive_queries.py +0 -152
  67. {rook_cli-0.2.1 → rook_cli-0.2.2}/.claude/settings.local.json +0 -0
  68. {rook_cli-0.2.1/.claude/worktrees/streamed-orbiting-llama → rook_cli-0.2.2}/.gitignore +0 -0
  69. {rook_cli-0.2.1 → rook_cli-0.2.2}/DEVELOPMENT_GUIDE.md +0 -0
  70. {rook_cli-0.2.1 → rook_cli-0.2.2}/LICENSE +0 -0
  71. {rook_cli-0.2.1/.claude/worktrees/streamed-orbiting-llama → rook_cli-0.2.2}/pyproject.toml +0 -0
  72. {rook_cli-0.2.1/.claude/worktrees/streamed-orbiting-llama → rook_cli-0.2.2}/src/rook/__main__.py +0 -0
  73. {rook_cli-0.2.1 → rook_cli-0.2.2}/src/rook/branding.py +0 -0
  74. {rook_cli-0.2.1/.claude/worktrees/streamed-orbiting-llama → rook_cli-0.2.2}/src/rook/domain/__init__.py +0 -0
  75. {rook_cli-0.2.1 → rook_cli-0.2.2}/src/rook/domain/tasks.py +0 -0
  76. {rook_cli-0.2.1 → rook_cli-0.2.2}/src/rook/formatting.py +0 -0
  77. {rook_cli-0.2.1 → rook_cli-0.2.2}/src/rook/paths.py +0 -0
  78. {rook_cli-0.2.1/.claude/worktrees/streamed-orbiting-llama → rook_cli-0.2.2}/src/rook/persistence/__init__.py +0 -0
  79. {rook_cli-0.2.1 → rook_cli-0.2.2}/src/rook/persistence/database.py +0 -0
  80. {rook_cli-0.2.1/.claude/worktrees/streamed-orbiting-llama → rook_cli-0.2.2}/src/rook/persistence/metadata.py +0 -0
  81. {rook_cli-0.2.1 → rook_cli-0.2.2}/src/rook/persistence/migrations.py +0 -0
  82. {rook_cli-0.2.1 → rook_cli-0.2.2}/src/rook/persistence/tasks.py +0 -0
  83. {rook_cli-0.2.1/.claude/worktrees/streamed-orbiting-llama → rook_cli-0.2.2}/src/rook/services/__init__.py +0 -0
  84. {rook_cli-0.2.1 → rook_cli-0.2.2}/src/rook/services/tasks.py +0 -0
  85. {rook_cli-0.2.1 → rook_cli-0.2.2}/src/rook/services/undo.py +0 -0
  86. {rook_cli-0.2.1/.claude/worktrees/streamed-orbiting-llama → rook_cli-0.2.2}/src/rook/widgets/__init__.py +0 -0
  87. {rook_cli-0.2.1/.claude/worktrees/streamed-orbiting-llama → rook_cli-0.2.2}/src/rook/widgets/shortcut_footer.py +0 -0
  88. {rook_cli-0.2.1 → rook_cli-0.2.2}/src/rook/widgets/task_line_input.py +0 -0
  89. {rook_cli-0.2.1/.claude/worktrees/streamed-orbiting-llama → rook_cli-0.2.2}/src/rook/widgets/task_list.py +0 -0
  90. {rook_cli-0.2.1/.claude/worktrees/streamed-orbiting-llama → rook_cli-0.2.2}/tests/support.py +0 -0
  91. {rook_cli-0.2.1/.claude/worktrees/streamed-orbiting-llama → rook_cli-0.2.2}/tests/test_archive_navigation.py +0 -0
  92. {rook_cli-0.2.1/.claude/worktrees/streamed-orbiting-llama → rook_cli-0.2.2}/tests/test_archive_queries.py +0 -0
  93. {rook_cli-0.2.1 → rook_cli-0.2.2}/tests/test_formatting.py +0 -0
  94. {rook_cli-0.2.1 → rook_cli-0.2.2}/tests/test_migrations.py +0 -0
  95. {rook_cli-0.2.1 → rook_cli-0.2.2}/tests/test_paths.py +0 -0
  96. {rook_cli-0.2.1 → rook_cli-0.2.2}/tests/test_persistence_failure.py +0 -0
  97. {rook_cli-0.2.1 → rook_cli-0.2.2}/tests/test_selection.py +0 -0
  98. {rook_cli-0.2.1 → rook_cli-0.2.2}/tests/test_shortcut_footer_selection.py +0 -0
  99. {rook_cli-0.2.1 → rook_cli-0.2.2}/tests/test_smoke.py +0 -0
  100. {rook_cli-0.2.1 → rook_cli-0.2.2}/tests/test_task_creation_and_editing.py +0 -0
  101. {rook_cli-0.2.1 → rook_cli-0.2.2}/tests/test_task_repository.py +0 -0
  102. {rook_cli-0.2.1 → rook_cli-0.2.2}/tests/test_task_row_rendering.py +0 -0
  103. {rook_cli-0.2.1 → rook_cli-0.2.2}/tests/test_task_service.py +0 -0
  104. {rook_cli-0.2.1 → rook_cli-0.2.2}/tests/test_task_states.py +0 -0
  105. {rook_cli-0.2.1 → rook_cli-0.2.2}/tests/test_undo.py +0 -0
  106. {rook_cli-0.2.1 → rook_cli-0.2.2}/tests/test_undo_manager.py +0 -0
  107. {rook_cli-0.2.1 → rook_cli-0.2.2}/tests/test_widget_markup_safety.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: rook-cli
3
- Version: 0.2.1
3
+ Version: 0.2.2
4
4
  Summary: A local, keyboard-first terminal daily journal.
5
5
  Project-URL: Repository, https://github.com/JanviChawla/rook
6
6
  Author: Janvi Chawla
@@ -67,13 +67,15 @@ uv tool upgrade rook-cli
67
67
  | `e` or `Ent` | Edit selected task |
68
68
  | `x` | Toggle complete |
69
69
  | `>` | Toggle migrated |
70
- | `d` | Soft-delete / permanently remove (press twice) |
70
+ | `d` | Soft-delete (shows `~` and strikethrough) / permanently remove (press twice) |
71
71
  | `u` | Undo last action |
72
72
  | `a` | Open weekly archive |
73
73
  | `↑` / `↓` | Move selection |
74
74
  | `Esc` | Cancel edit |
75
75
  | `q` | Quit |
76
76
 
77
+ > **Mac note:** strikethrough on soft-deleted tasks requires a terminal that supports it. macOS Terminal.app does not; [iTerm2](https://iterm2.com), Alacritty, and kitty do. The `~` bullet still appears regardless of terminal.
78
+
77
79
  ## Data and privacy
78
80
 
79
81
  Tasks are stored in a local SQLite database. Nothing leaves your machine.
@@ -1,96 +1,98 @@
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
- ```powershell
83
- rook --week-start monday
84
- ```
85
-
86
- To switch back to Sunday-start:
87
-
88
- ```powershell
89
- rook --week-start sunday
90
- ```
91
-
92
- ## License
93
-
94
- Copyright (c) 2026 Janvi Chawla. All Rights Reserved.
95
-
96
- Personal use permitted. No redistribution or derivative works without permission.
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 (shows `~` and strikethrough) / 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
+ > **Mac note:** strikethrough on soft-deleted tasks requires a terminal that supports it. macOS Terminal.app does not; [iTerm2](https://iterm2.com), Alacritty, and kitty do. The `~` bullet still appears regardless of terminal.
61
+
62
+ ## Data and privacy
63
+
64
+ Tasks are stored in a local SQLite database. Nothing leaves your machine.
65
+
66
+ | Platform | Location |
67
+ |----------|----------|
68
+ | Windows | `%LOCALAPPDATA%\Rook\data.sqlite3` |
69
+ | macOS | `~/Library/Application Support/Rook/data.sqlite3` |
70
+ | Linux | `~/.local/share/rook/data.sqlite3` |
71
+
72
+ To print the exact path on your system:
73
+
74
+ ```powershell
75
+ rook --data-path
76
+ ```
77
+
78
+ Uninstalling Rook does not delete the database.
79
+
80
+ ## FAQ
81
+
82
+ **How do I change the archive week layout from Sun–Sat to Mon–Sun?**
83
+
84
+ ```powershell
85
+ rook --week-start monday
86
+ ```
87
+
88
+ To switch back to Sunday-start:
89
+
90
+ ```powershell
91
+ rook --week-start sunday
92
+ ```
93
+
94
+ ## License
95
+
96
+ Copyright (c) 2026 Janvi Chawla. All Rights Reserved.
97
+
98
+ Personal use permitted. No redistribution or derivative works without permission.
@@ -0,0 +1 @@
1
+ __version__ = "0.2.2"
@@ -4,6 +4,7 @@ from datetime import date
4
4
 
5
5
  from textual.app import App, ComposeResult
6
6
  from textual.binding import Binding
7
+ from textual.timer import Timer
7
8
  from textual.widgets import Static
8
9
 
9
10
  from rook import branding
@@ -115,6 +116,7 @@ class RookApp(App[None]):
115
116
  # phase can share the same single undo slot (Section 6.10).
116
117
  self._undo_manager = UndoManager()
117
118
  self._safe_symbols = safe_symbols
119
+ self._status_clear_timer: Timer | None = None
118
120
  # Map foreground/background to the terminal's own ANSI defaults
119
121
  # instead of Textual's fixed truecolor theme, so the app respects
120
122
  # the user's existing terminal background (Section 11.9-11.10).
@@ -202,10 +204,20 @@ class RookApp(App[None]):
202
204
 
203
205
  def on_task_list_view_status_message(self, message: TaskListView.StatusMessage) -> None:
204
206
  self.query_one("#status", Static).update(message.text)
207
+ if self._status_clear_timer is not None:
208
+ self._status_clear_timer.stop()
209
+ self._status_clear_timer = self.set_timer(4, self._clear_status)
210
+
211
+ def _clear_status(self) -> None:
212
+ self.query_one("#status", Static).update("")
213
+ self._status_clear_timer = None
205
214
 
206
215
  async def on_task_list_view_editing_changed(self, message: TaskListView.EditingChanged) -> None:
207
216
  self.query_one(ShortcutFooter).set_editing(message.editing)
208
217
  self.query_one("#status", Static).update("")
218
+ if self._status_clear_timer is not None:
219
+ self._status_clear_timer.stop()
220
+ self._status_clear_timer = None
209
221
  if not message.editing and self._rollover_pending:
210
222
  self._rollover_pending = False
211
223
  await self._apply_rollover_if_needed()
@@ -38,9 +38,9 @@ class ArchiveRepository:
38
38
  ) -> list[tuple[date, list[ArchivedTask]]]:
39
39
  """Archived tasks in [week_start, week_end_exclusive), grouped by day.
40
40
 
41
- Days are returned oldest-first. Tasks within each day follow their
42
- original archive_order. Only completed and deleted tasks appear
43
- (the schema constraint ensures no open/migrated tasks are archived).
41
+ Days are returned oldest-first. Tasks within each day are sorted
42
+ alphabetically (case-insensitive). Only completed and deleted tasks
43
+ appear (the schema constraint ensures no open/migrated tasks are archived).
44
44
  """
45
45
  rows = self._connection.execute(
46
46
  """
@@ -49,7 +49,7 @@ class ArchiveRepository:
49
49
  WHERE archived_date IS NOT NULL
50
50
  AND archived_date >= ?
51
51
  AND archived_date < ?
52
- ORDER BY archived_date ASC, archive_order ASC
52
+ ORDER BY archived_date ASC, lower(text) ASC, text ASC
53
53
  """,
54
54
  (week_start.isoformat(), week_end_exclusive.isoformat()),
55
55
  ).fetchall()
@@ -54,6 +54,7 @@ class RolloverService:
54
54
  return RolloverResult(changed=False)
55
55
 
56
56
  timestamp = self._now_provider().isoformat()
57
+ today_iso = today.isoformat()
57
58
  with self._connection:
58
59
  self._connection.execute(
59
60
  """
@@ -63,7 +64,21 @@ class RolloverService:
63
64
  AND state IN ('completed', 'deleted')
64
65
  AND state_date < ?
65
66
  """,
66
- (timestamp, today.isoformat()),
67
+ (timestamp, today_iso),
68
+ )
69
+
70
+ # Tasks marked Migrated on a previous day carry forward as Open
71
+ # tasks today — the migration was an intent recorded yesterday,
72
+ # and the new day is when that intent becomes an active task again.
73
+ self._connection.execute(
74
+ """
75
+ UPDATE tasks
76
+ SET state = 'open', state_date = ?, state_changed_at = ?, updated_at = ?
77
+ WHERE archived_date IS NULL
78
+ AND state = 'migrated'
79
+ AND state_date < ?
80
+ """,
81
+ (today_iso, timestamp, timestamp, today_iso),
67
82
  )
68
83
 
69
84
  # Section 15.12 step 3: renumber remaining active Tasks so
@@ -88,7 +103,7 @@ class RolloverService:
88
103
  INSERT INTO app_meta (key, value) VALUES ('last_processed_date', ?)
89
104
  ON CONFLICT(key) DO UPDATE SET value = excluded.value
90
105
  """,
91
- (today.isoformat(),),
106
+ (today_iso,),
92
107
  )
93
108
 
94
109
  return RolloverResult(changed=True)
@@ -25,12 +25,11 @@ SAFE = SymbolSet(open="*", completed="x", migrated=">", selected=">", deleted_fa
25
25
  def state_symbol(state: TaskState, symbols: SymbolSet, *, safe_mode: bool) -> str:
26
26
  """The glyph shown in the state-symbol column for a given Task state.
27
27
 
28
- A Deleted Task's preferred display retains its normal open bullet and
29
- relies on strikethrough styling to signal deletion (Section 11.5); the
30
- fallback instead replaces the symbol outright with ``deleted_fallback``.
28
+ A Deleted Task always shows the ``deleted_fallback`` symbol (``~``);
29
+ in preferred mode the text is also struck through (Section 11.5, 11.7).
31
30
  """
32
31
  if state is TaskState.DELETED:
33
- return symbols.deleted_fallback if safe_mode else symbols.open
32
+ return symbols.deleted_fallback
34
33
  if state is TaskState.OPEN:
35
34
  return symbols.open
36
35
  if state is TaskState.MIGRATED:
@@ -51,6 +51,14 @@ class ArchiveScreen(Screen[None]):
51
51
 
52
52
  ArchiveScreen #archive-scroll {
53
53
  height: 1fr;
54
+ scrollbar-size-vertical: 1;
55
+ scrollbar-color: ansi_default;
56
+ scrollbar-color-hover: ansi_default;
57
+ scrollbar-color-active: ansi_default;
58
+ scrollbar-background: ansi_default;
59
+ scrollbar-background-hover: ansi_default;
60
+ scrollbar-background-active: ansi_default;
61
+ scrollbar-corner-color: ansi_default;
54
62
  }
55
63
 
56
64
  ArchiveScreen #archive-footer {
@@ -114,7 +122,7 @@ class ArchiveScreen(Screen[None]):
114
122
  for i, (day, tasks) in enumerate(days):
115
123
  if i > 0:
116
124
  lines.append("")
117
- lines.append(f"{day:%A, %B} {day.day}")
125
+ lines.append(f"[bold]{day:%A, %B} {day.day}[/bold]")
118
126
  for task in tasks:
119
127
  safe_text = escape(task.text)
120
128
  if task.state == TaskState.COMPLETED:
@@ -16,9 +16,8 @@ def render_task_row_text(task: Task, *, selected: bool, width: int, safe_symbols
16
16
 
17
17
  Continuation lines of a wrapped Task align under the text rather than
18
18
  repeating the selection or state-symbol columns (Section 11.3). A
19
- Deleted Task keeps its normal bullet with strikethrough styling in the
20
- preferred mode, or the ``~`` fallback symbol with muted styling when
21
- ``safe_symbols`` is set (Section 11.5, 11.7). The selection column
19
+ Deleted Task always shows the ``~`` symbol; in preferred mode the text
20
+ is also struck through (Section 11.5, 11.7). The selection column
22
21
  shows the accent-styled cursor only on the selected row (Section 11.6).
23
22
  """
24
23
  symbols = SAFE if safe_symbols else PREFERRED
@@ -135,7 +135,7 @@ def test_mixed_state_tasks_render_expected_symbols(tmp_path) -> None:
135
135
  assert "• Open task" in rendered
136
136
  assert "> Migrated task" in rendered
137
137
  assert "× Completed task" in rendered
138
- assert " Deleted task" in rendered
138
+ assert "~ Deleted task" in rendered
139
139
 
140
140
  asyncio.run(scenario())
141
141
 
@@ -81,8 +81,10 @@ def test_open_and_migrated_carry_forward_completed_and_deleted_archive(tmp_path)
81
81
  assert result.changed is True
82
82
  remaining = tasks.list_active_tasks()
83
83
  assert [task.id for task in remaining] == [open_task.id, migrated_task.id]
84
+ # Both carry forward as Open — the migration intent from day1 is resolved
85
+ # into a fresh active task on day2.
84
86
  assert remaining[0].state == TaskState.OPEN
85
- assert remaining[1].state == TaskState.MIGRATED
87
+ assert remaining[1].state == TaskState.OPEN
86
88
 
87
89
 
88
90
  def test_relative_order_of_unresolved_tasks_is_preserved(tmp_path) -> None:
@@ -67,7 +67,7 @@ def test_background_check_applies_rollover_and_refreshes_today(tmp_path) -> None
67
67
  await app._check_for_new_day()
68
68
 
69
69
  assert [task.id for task in task_list._tasks] == [open_id]
70
- assert task_list._tasks[0].state == TaskState.MIGRATED
70
+ assert task_list._tasks[0].state == TaskState.OPEN
71
71
 
72
72
  header = app.query_one("#header", Static)
73
73
  assert format_header_date(_DAY2) in str(header.content)
@@ -10,7 +10,7 @@ from rook.symbols import PREFERRED, SAFE, state_symbol
10
10
  (TaskState.OPEN, "•"),
11
11
  (TaskState.MIGRATED, ">"),
12
12
  (TaskState.COMPLETED, "×"),
13
- (TaskState.DELETED, ""),
13
+ (TaskState.DELETED, "~"),
14
14
  ],
15
15
  )
16
16
  def test_preferred_symbols(state: TaskState, expected: str) -> None:
@@ -1,66 +0,0 @@
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
- }
@@ -1,10 +0,0 @@
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.
@@ -1 +0,0 @@
1
- __version__ = "0.2.1"