rook-cli 0.2.0__py3-none-any.whl

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.
@@ -0,0 +1,155 @@
1
+ import textwrap
2
+
3
+ from rich.text import Text
4
+ from textual import events
5
+ from textual.app import ComposeResult
6
+ from textual.widget import Widget
7
+ from textual.widgets import Static
8
+
9
+ from rook.domain.tasks import Task, TaskState
10
+ from rook.symbols import PREFERRED, PREFIX_WIDTH, SAFE, state_symbol
11
+ from rook.widgets.task_line_input import TaskLineInput
12
+
13
+
14
+ def render_task_row_text(task: Task, *, selected: bool, width: int, safe_symbols: bool) -> Text:
15
+ """Build one Task row as a Rich Text.
16
+
17
+ Continuation lines of a wrapped Task align under the text rather than
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
22
+ shows the accent-styled cursor only on the selected row (Section 11.6).
23
+ """
24
+ symbols = SAFE if safe_symbols else PREFERRED
25
+ body_width = max(width - PREFIX_WIDTH, 1)
26
+
27
+ symbol = state_symbol(task.state, symbols, safe_mode=safe_symbols)
28
+ cursor = symbols.selected if selected else " "
29
+ prefix = f"{cursor} {symbol} "
30
+ wrapped_lines = textwrap.wrap(
31
+ task.text,
32
+ width=body_width,
33
+ break_long_words=False,
34
+ break_on_hyphens=False,
35
+ ) or [""]
36
+
37
+ row = Text(prefix + wrapped_lines[0])
38
+ for continuation in wrapped_lines[1:]:
39
+ row.append("\n" + " " * PREFIX_WIDTH + continuation)
40
+
41
+ if task.state is TaskState.OPEN:
42
+ row.stylize("bold", len(prefix))
43
+ if task.state is TaskState.DELETED and not safe_symbols:
44
+ row.stylize("strike", len(prefix))
45
+
46
+ if selected:
47
+ row.stylize("bold", 0, 1)
48
+
49
+ return row
50
+
51
+
52
+ class TaskRow(Widget):
53
+ """One Task row within the scrollable Today task list.
54
+
55
+ Normally renders as read-only text via ``render_task_row_text``
56
+ (unchanged from Phase 2/3). While ``editing`` is True, it instead
57
+ composes a small prefix plus a live ``TaskLineInput`` in place of
58
+ that text - creation and editing happen directly on the row, never
59
+ in a separate dialog (Section 2.5).
60
+ """
61
+
62
+ DEFAULT_CSS = """
63
+ TaskRow {
64
+ height: auto;
65
+ }
66
+ TaskRow.-editing {
67
+ layout: horizontal;
68
+ height: 1;
69
+ }
70
+ TaskRow.-editing .task-row-prefix {
71
+ width: 4;
72
+ height: 1;
73
+ }
74
+ TaskRow.-editing TaskLineInput {
75
+ width: 1fr;
76
+ height: 1;
77
+ }
78
+ """
79
+
80
+ def __init__(
81
+ self,
82
+ item: Task,
83
+ *,
84
+ selected: bool = False,
85
+ safe_symbols: bool = False,
86
+ editing: bool = False,
87
+ edit_value: str = "",
88
+ id: str | None = None,
89
+ ) -> None:
90
+ # Note: "item" (not "task") because Widget already reserves the
91
+ # read-only "task" property for its own backing asyncio Task.
92
+ super().__init__(id=id)
93
+ self.item = item
94
+ self.selected = selected
95
+ self._safe_symbols = safe_symbols
96
+ self.editing = editing
97
+ self._edit_value = edit_value
98
+ if editing:
99
+ self.add_class("-editing")
100
+
101
+ def compose(self) -> ComposeResult:
102
+ if self.editing:
103
+ symbols = SAFE if self._safe_symbols else PREFERRED
104
+ cursor = symbols.selected if self.selected else " "
105
+ symbol = state_symbol(self.item.state, symbols, safe_mode=self._safe_symbols)
106
+ # markup=False: the prefix is fixed chrome, never user text.
107
+ yield Static(f"{cursor} {symbol} ", classes="task-row-prefix", markup=False)
108
+ yield TaskLineInput(
109
+ self._edit_value,
110
+ compact=True,
111
+ select_on_focus=False,
112
+ max_length=1000,
113
+ )
114
+ else:
115
+ # markup=False: Task text must never be interpreted as Rich
116
+ # console markup, so a task literally containing "[bold]"
117
+ # renders unchanged.
118
+ yield Static(markup=False)
119
+
120
+ def on_mount(self) -> None:
121
+ if self.editing:
122
+ editor = self.query_one(TaskLineInput)
123
+ editor.cursor_position = len(editor.value)
124
+ editor.focus()
125
+ else:
126
+ self._refresh_display()
127
+
128
+ def on_resize(self, event: events.Resize) -> None:
129
+ if not self.editing:
130
+ self._refresh_display()
131
+
132
+ def set_selected(self, selected: bool) -> None:
133
+ if self.selected != selected:
134
+ self.selected = selected
135
+ if not self.editing:
136
+ self._refresh_display()
137
+
138
+ def set_item(self, item: Task) -> None:
139
+ """Redraw after the underlying Task's state or text changed
140
+ (Section 8), without needing the whole list to recompose."""
141
+ self.item = item
142
+ if not self.editing:
143
+ self._refresh_display()
144
+
145
+ def _refresh_display(self) -> None:
146
+ width = self.size.width or 80
147
+ display = self.query_one(Static)
148
+ display.update(
149
+ render_task_row_text(
150
+ self.item,
151
+ selected=self.selected,
152
+ width=width,
153
+ safe_symbols=self._safe_symbols,
154
+ )
155
+ )
@@ -0,0 +1,120 @@
1
+ Metadata-Version: 2.4
2
+ Name: rook-cli
3
+ Version: 0.2.0
4
+ Summary: A local, keyboard-first terminal daily journal.
5
+ Project-URL: Repository, https://github.com/JanviChawla/rook
6
+ Author: Janvi Chawla
7
+ License-Expression: LicenseRef-Proprietary
8
+ License-File: LICENSE
9
+ Requires-Python: >=3.10
10
+ Requires-Dist: textual>=0.60
11
+ Provides-Extra: dev
12
+ Requires-Dist: build>=1.2; extra == 'dev'
13
+ Requires-Dist: mypy>=1.10; extra == 'dev'
14
+ Requires-Dist: pytest>=8.0; extra == 'dev'
15
+ Requires-Dist: ruff>=0.6; extra == 'dev'
16
+ Description-Content-Type: text/markdown
17
+
18
+ # Rook ♖
19
+
20
+ A local, keyboard-first terminal journal for working through one day at a time.
21
+
22
+ ```text
23
+ rook ♖ Today — Friday, July 24, 2026
24
+ ⋆⁺₊ (。'▽'。)♡ ₊⁺⋆ "Showing up is the whole trick."
25
+
26
+ ❯ • Finish the presentation
27
+ • Reply to Alex
28
+ > Read Chapter 3
29
+ × Submit the expense report
30
+
31
+ [n] new [e/Ent] edit [x] complete [>] migrate [d] delete [u] undo [a] archive [q] quit
32
+ ```
33
+
34
+ Rook is inspired by the simplicity of a paper bullet journal:
35
+
36
+ - one active list: **Today**
37
+ - direct, in-place editing
38
+ - local SQLite storage
39
+ - read-only history
40
+ - no accounts, cloud sync, reminders, priorities, or telemetry
41
+
42
+ ## Installation
43
+
44
+ Requires Python 3.10 or newer. Install with [uv](https://docs.astral.sh/uv/):
45
+
46
+ ```powershell
47
+ uv tool install rook-cli
48
+ ```
49
+
50
+ Then launch:
51
+
52
+ ```powershell
53
+ rook
54
+ ```
55
+
56
+ To upgrade later:
57
+
58
+ ```powershell
59
+ uv tool upgrade rook-cli
60
+ ```
61
+
62
+ ## Keyboard reference
63
+
64
+ | Key | Action |
65
+ |-----|--------|
66
+ | `n` | New task |
67
+ | `e` or `Ent` | Edit selected task |
68
+ | `x` | Toggle complete |
69
+ | `>` | Toggle migrated |
70
+ | `d` | Soft-delete / permanently remove (press twice) |
71
+ | `u` | Undo last action |
72
+ | `a` | Open weekly archive |
73
+ | `↑` / `↓` | Move selection |
74
+ | `Esc` | Cancel edit |
75
+ | `q` | Quit |
76
+
77
+ ## Data and privacy
78
+
79
+ Tasks are stored in a local SQLite database. Nothing leaves your machine.
80
+
81
+ | Platform | Location |
82
+ |----------|----------|
83
+ | Windows | `%LOCALAPPDATA%\Rook\data.sqlite3` |
84
+ | macOS | `~/Library/Application Support/Rook/data.sqlite3` |
85
+ | Linux | `~/.local/share/rook/data.sqlite3` |
86
+
87
+ To print the exact path on your system:
88
+
89
+ ```powershell
90
+ rook --data-path
91
+ ```
92
+
93
+ Uninstalling Rook does not delete the database.
94
+
95
+ ## FAQ
96
+
97
+ **How do I change the archive week layout from Sun–Sat to Mon–Sun?**
98
+
99
+ There is no in-app setting yet. Update the value directly in the SQLite database.
100
+ Find the exact path with `rook --data-path`, or use the default:
101
+
102
+ ```powershell
103
+ sqlite3 "$env:LOCALAPPDATA\Rook\data.sqlite3"
104
+ ```
105
+
106
+ ```sql
107
+ INSERT OR REPLACE INTO app_meta (key, value) VALUES ('week_start_day', 'monday');
108
+ ```
109
+
110
+ To switch back to Sunday-start:
111
+
112
+ ```sql
113
+ INSERT OR REPLACE INTO app_meta (key, value) VALUES ('week_start_day', 'sunday');
114
+ ```
115
+
116
+ ## License
117
+
118
+ Copyright (c) 2026 Janvi Chawla. All Rights Reserved.
119
+
120
+ Personal use permitted. No redistribution or derivative works without permission.
@@ -0,0 +1,30 @@
1
+ rook/__init__.py,sha256=0D6srYi9ejPUnwpjVmDoJB-oMuBqPSiP50LPRoM8G0I,23
2
+ rook/__main__.py,sha256=iVul5IrHqK5RiTO2Htt6yLUJ92l7kHrJUB6b63_-Rv4,1411
3
+ rook/app.py,sha256=0J4vO22P9Axqc50Ra4GolAU23587Lm6Jkr1hJ0kRsTQ,8973
4
+ rook/branding.py,sha256=jqHqrJzmmmzEmcbLJQa07M6rUk-g0V_RP3TJ5fE4-Bc,2479
5
+ rook/formatting.py,sha256=OIcSerLfzdxRYPJrseNKD1aSXgfBcHfPSY6BSDL196M,338
6
+ rook/paths.py,sha256=amhsfZdeV3vgtuwD9SWT7f-NGan2xk1Y5tKpqkSZRK4,953
7
+ rook/symbols.py,sha256=qJRU-C9LBTpXy-KMvr2y9aakFNu60Lnoe92_GKd6KW8,1449
8
+ rook/domain/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
9
+ rook/domain/tasks.py,sha256=qxEj1FSIFJhUfXL_PYal528hW4kljnvWTHYfwNeMQIc,1588
10
+ rook/persistence/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
11
+ rook/persistence/archive.py,sha256=6F8NuA4n5BerfbyDa2umAxqecwMIy5wsjrGwp4eQwS4,2562
12
+ rook/persistence/database.py,sha256=O4ZkVqmUIRUI14D0H1iDeXslug2Mi82U57O3KpXL8zQ,669
13
+ rook/persistence/metadata.py,sha256=EbOy3Q_QvbyZj-9km6t0AVoa4R2ZWlOvypn9Mld3ZHs,2200
14
+ rook/persistence/migrations.py,sha256=94mwuMLoke39wuqx5fQY4B28T_UCQN4wk07rXVSfKhI,3625
15
+ rook/persistence/tasks.py,sha256=TE5qogIDjlwZB-Oh7R_BODKlsxOOJKAQsZt_kWEEymc,7215
16
+ rook/services/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
17
+ rook/services/rollover.py,sha256=q4PmSowmAibrdGPaUdg0G4HGu073V7szy9QtAa6Cu3s,3478
18
+ rook/services/tasks.py,sha256=gDJk94WIg-7DLqVrKmGO8_gvJ-0rJzXqc6UjVsF1zNo,3140
19
+ rook/services/undo.py,sha256=yq13HVwA_ihCbzMFzklkKSZWH5puzCZYXAaCtJGLrMg,1897
20
+ rook/widgets/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
21
+ rook/widgets/archive_screen.py,sha256=hXLqBke0lGFBlle3psk9vsd_3SesGN6xbsBXIQsXQcc,5773
22
+ rook/widgets/shortcut_footer.py,sha256=7lzJksCcE5CBLsLnuVhiPrbaWVtZSMAYOuFbtIz8HKc,2675
23
+ rook/widgets/task_line_input.py,sha256=-5vK5lCrLX4QdowZmb0P_tDtZpxZCmrAgmTGo4OASeM,1548
24
+ rook/widgets/task_list.py,sha256=seBkSUINidmLswjUrswWMyA5Q9S9-N6Af9ofg2zNUr8,16047
25
+ rook/widgets/task_row.py,sha256=CPhVjaJ32PrNkuPRiCbivuc3wlJNAxAu2yB5XNoHNSg,5309
26
+ rook_cli-0.2.0.dist-info/METADATA,sha256=ikY98Six7uPvmAMwOb8KUJ8yV1fZWf-bFVWhPmacTHo,2885
27
+ rook_cli-0.2.0.dist-info/WHEEL,sha256=lCkmxWfQsSc9CfIClYeavTdQeEX2toPqufh9gI35EQA,87
28
+ rook_cli-0.2.0.dist-info/entry_points.txt,sha256=b_8aSSokv9p5H5RQayv0BlgjAxjK2ajC2TdbeSWIKq4,44
29
+ rook_cli-0.2.0.dist-info/licenses/LICENSE,sha256=a4j6fArfSspsaiIjtzTzoCSO9GBR3sHD8KQxdSu29eQ,505
30
+ rook_cli-0.2.0.dist-info/RECORD,,
@@ -0,0 +1,4 @@
1
+ Wheel-Version: 1.0
2
+ Generator: hatchling 1.31.0
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any
@@ -0,0 +1,2 @@
1
+ [console_scripts]
2
+ rook = rook.__main__:main
@@ -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.