jott-cli 0.7.0__tar.gz → 0.7.1__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.
- {jott_cli-0.7.0/jott_cli.egg-info → jott_cli-0.7.1}/PKG-INFO +1 -1
- {jott_cli-0.7.0 → jott_cli-0.7.1}/jot/__init__.py +1 -1
- {jott_cli-0.7.0 → jott_cli-0.7.1}/jot/_dispatch_mixin.py +2 -1
- {jott_cli-0.7.0 → jott_cli-0.7.1}/jot/app.py +1 -1
- {jott_cli-0.7.0 → jott_cli-0.7.1}/jot/commands/_claude_mixin.py +10 -0
- {jott_cli-0.7.0 → jott_cli-0.7.1}/jot/commands/_core_mixin.py +3 -15
- {jott_cli-0.7.0 → jott_cli-0.7.1}/jot/commands/_notes_mixin.py +6 -1
- {jott_cli-0.7.0 → jott_cli-0.7.1}/jot/ui/display_footer.py +0 -3
- jott_cli-0.7.1/jot/ui/display_help.py +282 -0
- {jott_cli-0.7.0 → jott_cli-0.7.1/jott_cli.egg-info}/PKG-INFO +1 -1
- {jott_cli-0.7.0 → jott_cli-0.7.1}/pyproject.toml +1 -1
- {jott_cli-0.7.0 → jott_cli-0.7.1}/tests/test_command_handler.py +5 -3
- jott_cli-0.7.0/jot/ui/display_help.py +0 -233
- {jott_cli-0.7.0 → jott_cli-0.7.1}/LICENSE +0 -0
- {jott_cli-0.7.0 → jott_cli-0.7.1}/README.md +0 -0
- {jott_cli-0.7.0 → jott_cli-0.7.1}/jot/_app_navigation_mixin.py +0 -0
- {jott_cli-0.7.0 → jott_cli-0.7.1}/jot/categories/__init__.py +0 -0
- {jott_cli-0.7.0 → jott_cli-0.7.1}/jot/categories/config.py +0 -0
- {jott_cli-0.7.0 → jott_cli-0.7.1}/jot/categories/manager.py +0 -0
- {jott_cli-0.7.0 → jott_cli-0.7.1}/jot/categories/templates.py +0 -0
- {jott_cli-0.7.0 → jott_cli-0.7.1}/jot/cli/__init__.py +0 -0
- {jott_cli-0.7.0 → jott_cli-0.7.1}/jot/cli/archive.py +0 -0
- {jott_cli-0.7.0 → jott_cli-0.7.1}/jot/cli/config.py +0 -0
- {jott_cli-0.7.0 → jott_cli-0.7.1}/jot/cli/views.py +0 -0
- {jott_cli-0.7.0 → jott_cli-0.7.1}/jot/commands/__init__.py +0 -0
- {jott_cli-0.7.0 → jott_cli-0.7.1}/jot/commands/_ai_analysis_mixin.py +0 -0
- {jott_cli-0.7.0 → jott_cli-0.7.1}/jot/commands/_ai_suggest_mixin.py +0 -0
- {jott_cli-0.7.0 → jott_cli-0.7.1}/jot/commands/_audio_timer_mixin.py +0 -0
- {jott_cli-0.7.0 → jott_cli-0.7.1}/jot/commands/_bulk_mixin.py +0 -0
- {jott_cli-0.7.0 → jott_cli-0.7.1}/jot/commands/_context_mixin.py +0 -0
- {jott_cli-0.7.0 → jott_cli-0.7.1}/jot/commands/_gcal_mixin.py +0 -0
- {jott_cli-0.7.0 → jott_cli-0.7.1}/jot/commands/_github_mixin.py +0 -0
- {jott_cli-0.7.0 → jott_cli-0.7.1}/jot/commands/_metadata_mixin.py +0 -0
- {jott_cli-0.7.0 → jott_cli-0.7.1}/jot/commands/_transfer_mixin.py +0 -0
- {jott_cli-0.7.0 → jott_cli-0.7.1}/jot/commands/_web_clipboard_mixin.py +0 -0
- {jott_cli-0.7.0 → jott_cli-0.7.1}/jot/commands/handler.py +0 -0
- {jott_cli-0.7.0 → jott_cli-0.7.1}/jot/core/__init__.py +0 -0
- {jott_cli-0.7.0 → jott_cli-0.7.1}/jot/core/_age_backlog_mixin.py +0 -0
- {jott_cli-0.7.0 → jott_cli-0.7.1}/jot/core/_compress_mixin.py +0 -0
- {jott_cli-0.7.0 → jott_cli-0.7.1}/jot/core/_crud_mixin.py +0 -0
- {jott_cli-0.7.0 → jott_cli-0.7.1}/jot/core/_delete_mixin.py +0 -0
- {jott_cli-0.7.0 → jott_cli-0.7.1}/jot/core/_export_mixin.py +0 -0
- {jott_cli-0.7.0 → jott_cli-0.7.1}/jot/core/_id_migration_mixin.py +0 -0
- {jott_cli-0.7.0 → jott_cli-0.7.1}/jot/core/_metadata_mixin.py +0 -0
- {jott_cli-0.7.0 → jott_cli-0.7.1}/jot/core/_navigation_mixin.py +0 -0
- {jott_cli-0.7.0 → jott_cli-0.7.1}/jot/core/_persistence_mixin.py +0 -0
- {jott_cli-0.7.0 → jott_cli-0.7.1}/jot/core/_subtask_mixin.py +0 -0
- {jott_cli-0.7.0 → jott_cli-0.7.1}/jot/core/archive_manager.py +0 -0
- {jott_cli-0.7.0 → jott_cli-0.7.1}/jot/core/constants.py +0 -0
- {jott_cli-0.7.0 → jott_cli-0.7.1}/jot/core/id_manager.py +0 -0
- {jott_cli-0.7.0 → jott_cli-0.7.1}/jot/core/task_manager.py +0 -0
- {jott_cli-0.7.0 → jott_cli-0.7.1}/jot/integrations/__init__.py +0 -0
- {jott_cli-0.7.0 → jott_cli-0.7.1}/jot/integrations/gcal/__init__.py +0 -0
- {jott_cli-0.7.0 → jott_cli-0.7.1}/jot/integrations/gcal/account_manager.py +0 -0
- {jott_cli-0.7.0 → jott_cli-0.7.1}/jot/integrations/gcal/auth.py +0 -0
- {jott_cli-0.7.0 → jott_cli-0.7.1}/jot/integrations/gcal/events.py +0 -0
- {jott_cli-0.7.0 → jott_cli-0.7.1}/jot/integrations/github/__init__.py +0 -0
- {jott_cli-0.7.0 → jott_cli-0.7.1}/jot/integrations/github/issues.py +0 -0
- {jott_cli-0.7.0 → jott_cli-0.7.1}/jot/integrations/keywords/__init__.py +0 -0
- {jott_cli-0.7.0 → jott_cli-0.7.1}/jot/integrations/keywords/_config_mixin.py +0 -0
- {jott_cli-0.7.0 → jott_cli-0.7.1}/jot/integrations/keywords/_handlers_mixin.py +0 -0
- {jott_cli-0.7.0 → jott_cli-0.7.1}/jot/integrations/keywords/handler.py +0 -0
- {jott_cli-0.7.0 → jott_cli-0.7.1}/jot/mcp/__init__.py +0 -0
- {jott_cli-0.7.0 → jott_cli-0.7.1}/jot/mcp/handlers.py +0 -0
- {jott_cli-0.7.0 → jott_cli-0.7.1}/jot/mcp/schemas.py +0 -0
- {jott_cli-0.7.0 → jott_cli-0.7.1}/jot/mcp/server.py +0 -0
- {jott_cli-0.7.0 → jott_cli-0.7.1}/jot/projects/__init__.py +0 -0
- {jott_cli-0.7.0 → jott_cli-0.7.1}/jot/projects/backup.py +0 -0
- {jott_cli-0.7.0 → jott_cli-0.7.1}/jot/projects/registry.py +0 -0
- {jott_cli-0.7.0 → jott_cli-0.7.1}/jot/ui/__init__.py +0 -0
- {jott_cli-0.7.0 → jott_cli-0.7.1}/jot/ui/display.py +0 -0
- {jott_cli-0.7.0 → jott_cli-0.7.1}/jot/ui/display_archive.py +0 -0
- {jott_cli-0.7.0 → jott_cli-0.7.1}/jot/ui/display_projects.py +0 -0
- {jott_cli-0.7.0 → jott_cli-0.7.1}/jot/ui/display_tasks.py +0 -0
- {jott_cli-0.7.0 → jott_cli-0.7.1}/jot/ui/formatting.py +0 -0
- {jott_cli-0.7.0 → jott_cli-0.7.1}/jot/ui/input.py +0 -0
- {jott_cli-0.7.0 → jott_cli-0.7.1}/jot/ui/picker.py +0 -0
- {jott_cli-0.7.0 → jott_cli-0.7.1}/jot/ui/rendering.py +0 -0
- {jott_cli-0.7.0 → jott_cli-0.7.1}/jot/ui/styles.py +0 -0
- {jott_cli-0.7.0 → jott_cli-0.7.1}/jot/utils/__init__.py +0 -0
- {jott_cli-0.7.0 → jott_cli-0.7.1}/jot/utils/date_utils.py +0 -0
- {jott_cli-0.7.0 → jott_cli-0.7.1}/jot/utils/text_utils.py +0 -0
- {jott_cli-0.7.0 → jott_cli-0.7.1}/jot/utils/validation.py +0 -0
- {jott_cli-0.7.0 → jott_cli-0.7.1}/jott_cli.egg-info/SOURCES.txt +0 -0
- {jott_cli-0.7.0 → jott_cli-0.7.1}/jott_cli.egg-info/dependency_links.txt +0 -0
- {jott_cli-0.7.0 → jott_cli-0.7.1}/jott_cli.egg-info/entry_points.txt +0 -0
- {jott_cli-0.7.0 → jott_cli-0.7.1}/jott_cli.egg-info/requires.txt +0 -0
- {jott_cli-0.7.0 → jott_cli-0.7.1}/jott_cli.egg-info/top_level.txt +0 -0
- {jott_cli-0.7.0 → jott_cli-0.7.1}/setup.cfg +0 -0
- {jott_cli-0.7.0 → jott_cli-0.7.1}/setup.py +0 -0
- {jott_cli-0.7.0 → jott_cli-0.7.1}/tests/test_dispatch.py +0 -0
- {jott_cli-0.7.0 → jott_cli-0.7.1}/tests/test_edit_edge_cases.py +0 -0
- {jott_cli-0.7.0 → jott_cli-0.7.1}/tests/test_fuzzy_search.py +0 -0
- {jott_cli-0.7.0 → jott_cli-0.7.1}/tests/test_gcal_notes.py +0 -0
- {jott_cli-0.7.0 → jott_cli-0.7.1}/tests/test_github.py +0 -0
- {jott_cli-0.7.0 → jott_cli-0.7.1}/tests/test_highlight.py +0 -0
- {jott_cli-0.7.0 → jott_cli-0.7.1}/tests/test_input.py +0 -0
- {jott_cli-0.7.0 → jott_cli-0.7.1}/tests/test_jot.py +0 -0
- {jott_cli-0.7.0 → jott_cli-0.7.1}/tests/test_picker.py +0 -0
- {jott_cli-0.7.0 → jott_cli-0.7.1}/tests/test_styles.py +0 -0
- {jott_cli-0.7.0 → jott_cli-0.7.1}/tests/test_subtask_notes.py +0 -0
- {jott_cli-0.7.0 → jott_cli-0.7.1}/tests/test_terminal_wrap.py +0 -0
- {jott_cli-0.7.0 → jott_cli-0.7.1}/tests/test_today_filter.py +0 -0
- {jott_cli-0.7.0 → jott_cli-0.7.1}/tests/test_transfer_subtasks.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: jott-cli
|
|
3
|
-
Version: 0.7.
|
|
3
|
+
Version: 0.7.1
|
|
4
4
|
Summary: Feature-rich interactive CLI task manager with AI integration, calendar sync, and keyword automation
|
|
5
5
|
Author-email: Scott Anderson <sonander@gmail.com>
|
|
6
6
|
Maintainer-email: Scott Anderson <sonander@gmail.com>
|
|
@@ -7,7 +7,7 @@ import importlib.util
|
|
|
7
7
|
import os
|
|
8
8
|
from pathlib import Path
|
|
9
9
|
|
|
10
|
-
__version__ = "0.7.
|
|
10
|
+
__version__ = "0.7.1"
|
|
11
11
|
|
|
12
12
|
# When building Sphinx docs, skip the dynamic import bridge and heavy deps.
|
|
13
13
|
# Set JOT_SPHINX_BUILD=1 in docs/sphinx/conf.py before importing jot.
|
|
@@ -37,7 +37,7 @@ class AppState:
|
|
|
37
37
|
sort_by_day: bool = False
|
|
38
38
|
show_today_only: bool = False
|
|
39
39
|
include_archived_in_search: bool = True
|
|
40
|
-
show_shortcuts: bool = False
|
|
40
|
+
show_shortcuts: bool = False # deprecated; kept for API compat
|
|
41
41
|
show_notes_inline: bool = False
|
|
42
42
|
running: bool = True
|
|
43
43
|
selected_tasks: set = field(default_factory=set)
|
|
@@ -8,6 +8,15 @@ from datetime import datetime
|
|
|
8
8
|
|
|
9
9
|
from jot.ui.styles import RESET, CYAN, DIM
|
|
10
10
|
|
|
11
|
+
_ORG_OUTPUT_INSTRUCTION = (
|
|
12
|
+
"\n\nIMPORTANT: Format your entire response as org-mode markup:\n"
|
|
13
|
+
"- Code blocks: #+begin_src <lang>\n...\n#+end_src\n"
|
|
14
|
+
"- Inline code: ~symbol~ or =literal=\n"
|
|
15
|
+
"- File references: [[relative/path/to/file][filename.ext]]\n"
|
|
16
|
+
"- Headings: * ** *** etc.\n"
|
|
17
|
+
"Do NOT use markdown backticks or markdown headings."
|
|
18
|
+
)
|
|
19
|
+
|
|
11
20
|
|
|
12
21
|
class ClaudeMixin:
|
|
13
22
|
"""Launch Claude Code in a new tmux window with current task."""
|
|
@@ -209,6 +218,7 @@ class ClaudeMixin:
|
|
|
209
218
|
f"Existing notes:\n{existing_notes}")
|
|
210
219
|
else:
|
|
211
220
|
prompt = task_text
|
|
221
|
+
prompt += _ORG_OUTPUT_INSTRUCTION
|
|
212
222
|
|
|
213
223
|
cmd = [
|
|
214
224
|
'claude', '-p', '--model', 'sonnet',
|
|
@@ -277,21 +277,9 @@ class CoreMixin:
|
|
|
277
277
|
|
|
278
278
|
@staticmethod
|
|
279
279
|
def help():
|
|
280
|
-
"""Show help
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
M Move r Refresh h Help q Quit
|
|
284
|
-
|
|
285
|
-
Navigation: ↑/Ctrl+p Up ↓/Ctrl+n Down Shift+↑ Move up Shift+↓ Move down
|
|
286
|
-
|
|
287
|
-
Quick-Add: .? Shortcuts .f Notes .n Edit notes .j Agent task
|
|
288
|
-
.z Project .l Categories .w Day .x Status
|
|
289
|
-
Ctrl+R Register Ctrl+T Transfer .m Move Ctrl+X Quit
|
|
290
|
-
|
|
291
|
-
Command Mode (ESC): r Refresh
|
|
292
|
-
|
|
293
|
-
Tip: Press '.' to start a leader chord. Press '.?' for full shortcuts.
|
|
294
|
-
Full CLI docs: jott --help""")
|
|
280
|
+
"""Show help modal with all keyboard shortcuts."""
|
|
281
|
+
from jot.ui.display_help import help_modal
|
|
282
|
+
help_modal()
|
|
295
283
|
return True
|
|
296
284
|
|
|
297
285
|
def toggle_caps(self):
|
|
@@ -4,6 +4,7 @@ import os
|
|
|
4
4
|
import shlex
|
|
5
5
|
import subprocess
|
|
6
6
|
import tempfile
|
|
7
|
+
from pathlib import Path
|
|
7
8
|
|
|
8
9
|
from jot.ui.styles import RESET, DIM, CYAN, YELLOW
|
|
9
10
|
|
|
@@ -77,7 +78,11 @@ class NotesMixin:
|
|
|
77
78
|
file_extension = self.get_notes_file_extension(editor)
|
|
78
79
|
is_org_mode = file_extension == '.org'
|
|
79
80
|
|
|
80
|
-
|
|
81
|
+
work_dir = getattr(self.task_manager, 'project_dir', None) or Path.cwd()
|
|
82
|
+
with tempfile.NamedTemporaryFile(
|
|
83
|
+
mode='w+', suffix=file_extension, delete=False,
|
|
84
|
+
dir=work_dir
|
|
85
|
+
) as tf:
|
|
81
86
|
temp_file = tf.name
|
|
82
87
|
if is_org_mode:
|
|
83
88
|
tf.write(f"#+TITLE: Notes for task: {task_text}\n")
|
|
@@ -35,9 +35,6 @@ def _render_quick_add(input_buffer, show_shortcuts):
|
|
|
35
35
|
f"commands | {BOLD}Shift+V{RESET}: multi-select | "
|
|
36
36
|
f"{BOLD}.?{RESET}: shortcuts"
|
|
37
37
|
)
|
|
38
|
-
if show_shortcuts:
|
|
39
|
-
from jot.ui.display_help import display_categorized_shortcuts
|
|
40
|
-
display_categorized_shortcuts()
|
|
41
38
|
print(f"→ {input_buffer}█", end='')
|
|
42
39
|
|
|
43
40
|
|
|
@@ -0,0 +1,282 @@
|
|
|
1
|
+
"""Display functions for help and keyboard shortcuts."""
|
|
2
|
+
|
|
3
|
+
import shutil
|
|
4
|
+
import sys
|
|
5
|
+
|
|
6
|
+
from jot.ui.input import get_key
|
|
7
|
+
from jot.ui.rendering import buffered_output
|
|
8
|
+
from jot.ui.styles import RESET, BOLD, DIM, CYAN, GREEN, YELLOW, get_terminal_width
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
# ── Shortcut data ──────────────────────────────────────────────────────
|
|
12
|
+
|
|
13
|
+
SHORTCUTS = {
|
|
14
|
+
"Navigation": [
|
|
15
|
+
("↑/↓", "Navigate tasks"),
|
|
16
|
+
("Tab", "Cycle through categories"),
|
|
17
|
+
("Ctrl+F", "Fuzzy search tasks"),
|
|
18
|
+
(".z", "Switch project"),
|
|
19
|
+
("Ctrl+C", "Switch category"),
|
|
20
|
+
(".l", "Toggle all categories view"),
|
|
21
|
+
],
|
|
22
|
+
"Task Management": [
|
|
23
|
+
("Enter", "Add task"),
|
|
24
|
+
("Ctrl+E", "Edit current task"),
|
|
25
|
+
("c", "Mark current task"),
|
|
26
|
+
("d", "Delete task"),
|
|
27
|
+
(".d", "Duplicate task"),
|
|
28
|
+
("t", "Toggle task done"),
|
|
29
|
+
("a", "Archive task"),
|
|
30
|
+
(".a", "Toggle archive view"),
|
|
31
|
+
("m", "Move to different category"),
|
|
32
|
+
(".m", "Move task to another project"),
|
|
33
|
+
(".k", "Copy task to another project"),
|
|
34
|
+
("Ctrl+T", "Transfer to category"),
|
|
35
|
+
("Ctrl+↑/↓", "Reorder tasks"),
|
|
36
|
+
("=", "Sort by priority"),
|
|
37
|
+
],
|
|
38
|
+
"Task Details": [
|
|
39
|
+
("n", "Add/edit notes"),
|
|
40
|
+
(".n", "Edit task notes"),
|
|
41
|
+
(".f", "Toggle inline notes display"),
|
|
42
|
+
("p", "Toggle priority cycle"),
|
|
43
|
+
(".h", "Set priority to high"),
|
|
44
|
+
(".x", "Set task status"),
|
|
45
|
+
(".w", "Assign day to task"),
|
|
46
|
+
(".o", "Toggle day sorting"),
|
|
47
|
+
(".y", "Toggle today filter"),
|
|
48
|
+
(".u", "Toggle ALL CAPS"),
|
|
49
|
+
("Ctrl+D", "Mark current as done"),
|
|
50
|
+
(".j", "Mark as agent task"),
|
|
51
|
+
("*", "Highlight color picker"),
|
|
52
|
+
("~", "Quick highlight toggle"),
|
|
53
|
+
("Ctrl+L", "Assign parent (link subtask)"),
|
|
54
|
+
],
|
|
55
|
+
"Claude Code": [
|
|
56
|
+
(".A", "Ask Claude (read-only, writes to notes)"),
|
|
57
|
+
(".X", "Execute Claude (edit permissions)"),
|
|
58
|
+
(".C", "Launch Claude Code with task (tmux)"),
|
|
59
|
+
(".v", "Send task to local Claude session"),
|
|
60
|
+
(".V", "Send task to any Claude session"),
|
|
61
|
+
],
|
|
62
|
+
"Export & Import": [
|
|
63
|
+
(".e", "Execute keyword action"),
|
|
64
|
+
(".b", "Priority timer"),
|
|
65
|
+
(".G", "Export to Google Calendar"),
|
|
66
|
+
(".i", "Import from Google Calendar"),
|
|
67
|
+
(".c", "Copy task to clipboard"),
|
|
68
|
+
("Ctrl+U", "Open URLs in task"),
|
|
69
|
+
("Shift+1", "Fix duplicate task IDs"),
|
|
70
|
+
("Shift+4", "AI task suggestion"),
|
|
71
|
+
],
|
|
72
|
+
"GitHub": [
|
|
73
|
+
(".I", "Import issues from GitHub"),
|
|
74
|
+
(".H", "Export task as GitHub issue"),
|
|
75
|
+
(".D", "Close linked GitHub issue"),
|
|
76
|
+
],
|
|
77
|
+
"System": [
|
|
78
|
+
(".?", "Toggle this help"),
|
|
79
|
+
("r", "Refresh display"),
|
|
80
|
+
("Ctrl+R", "Register current project"),
|
|
81
|
+
("q/Ctrl+X", "Quit"),
|
|
82
|
+
("Esc", "Exit mode / Quit"),
|
|
83
|
+
],
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
|
|
87
|
+
def _get_terminal_height():
|
|
88
|
+
"""Return current terminal height, defaulting to 24."""
|
|
89
|
+
try:
|
|
90
|
+
return shutil.get_terminal_size().lines
|
|
91
|
+
except (ValueError, OSError):
|
|
92
|
+
return 24
|
|
93
|
+
|
|
94
|
+
|
|
95
|
+
# ── Build lines for the modal ──────────────────────────────────────────
|
|
96
|
+
|
|
97
|
+
def _build_help_lines():
|
|
98
|
+
"""Build a list of (line_string, is_header) tuples for the modal body."""
|
|
99
|
+
lines = []
|
|
100
|
+
first = True
|
|
101
|
+
for category, items in SHORTCUTS.items():
|
|
102
|
+
if not first:
|
|
103
|
+
lines.append(("", False))
|
|
104
|
+
first = False
|
|
105
|
+
lines.append((category, True))
|
|
106
|
+
for key, desc in items:
|
|
107
|
+
lines.append((f" {YELLOW}{key:<12}{RESET} {desc}", False))
|
|
108
|
+
return lines
|
|
109
|
+
|
|
110
|
+
|
|
111
|
+
# ── Modal rendering ────────────────────────────────────────────────────
|
|
112
|
+
|
|
113
|
+
def help_modal():
|
|
114
|
+
"""Show a centered, scrollable help modal. Blocks until dismissed.
|
|
115
|
+
|
|
116
|
+
Controls:
|
|
117
|
+
↑/↓ or j/k Scroll one line
|
|
118
|
+
PgUp/PgDn Scroll one page
|
|
119
|
+
Home/End Jump to top/bottom
|
|
120
|
+
ESC/q/? Dismiss
|
|
121
|
+
"""
|
|
122
|
+
lines = _build_help_lines()
|
|
123
|
+
scroll = 0
|
|
124
|
+
|
|
125
|
+
while True:
|
|
126
|
+
term_w = get_terminal_width()
|
|
127
|
+
term_h = _get_terminal_height()
|
|
128
|
+
|
|
129
|
+
# Box dimensions: 70% width, 85% height, centered
|
|
130
|
+
box_w = max(40, min(int(term_w * 0.70), term_w - 4))
|
|
131
|
+
box_h = max(10, min(int(term_h * 0.85), term_h - 2))
|
|
132
|
+
inner_w = box_w - 4 # 2 border + 2 padding
|
|
133
|
+
visible_rows = box_h - 4 # top border + title + bottom border + footer
|
|
134
|
+
|
|
135
|
+
max_scroll = max(0, len(lines) - visible_rows)
|
|
136
|
+
scroll = max(0, min(scroll, max_scroll))
|
|
137
|
+
|
|
138
|
+
# Centering offsets
|
|
139
|
+
pad_left = (term_w - box_w) // 2
|
|
140
|
+
pad_top = (term_h - box_h) // 2
|
|
141
|
+
margin = " " * pad_left
|
|
142
|
+
|
|
143
|
+
with buffered_output():
|
|
144
|
+
sys.stdout.write('\033[?25l\033[H\033[J') # hide cursor, clear
|
|
145
|
+
|
|
146
|
+
# Top padding
|
|
147
|
+
for _ in range(pad_top):
|
|
148
|
+
sys.stdout.write('\n')
|
|
149
|
+
|
|
150
|
+
# Top border
|
|
151
|
+
title = " Keybindings "
|
|
152
|
+
side = box_w - 2 - len(title)
|
|
153
|
+
left_bar = side // 2
|
|
154
|
+
right_bar = side - left_bar
|
|
155
|
+
sys.stdout.write(
|
|
156
|
+
f"{margin}{CYAN}┌{'─' * left_bar}{BOLD}{title}"
|
|
157
|
+
f"{RESET}{CYAN}{'─' * right_bar}┐{RESET}\n"
|
|
158
|
+
)
|
|
159
|
+
|
|
160
|
+
# Scroll indicator
|
|
161
|
+
if max_scroll > 0:
|
|
162
|
+
pct = int(scroll / max_scroll * 100) if max_scroll else 0
|
|
163
|
+
scroll_info = f" {scroll + 1}-{min(scroll + visible_rows, len(lines))}/{len(lines)} "
|
|
164
|
+
else:
|
|
165
|
+
scroll_info = ""
|
|
166
|
+
|
|
167
|
+
# Visible content rows
|
|
168
|
+
window = lines[scroll:scroll + visible_rows]
|
|
169
|
+
for i, (line_text, is_header) in enumerate(window):
|
|
170
|
+
if is_header:
|
|
171
|
+
content = f"{CYAN}{BOLD}{line_text}{RESET}"
|
|
172
|
+
else:
|
|
173
|
+
content = line_text
|
|
174
|
+
|
|
175
|
+
# Pad content to fill the box width (strip ANSI for measuring)
|
|
176
|
+
from jot.ui.styles import visible_len
|
|
177
|
+
vis = visible_len(content)
|
|
178
|
+
pad = max(0, inner_w - vis)
|
|
179
|
+
sys.stdout.write(
|
|
180
|
+
f"{margin}{CYAN}│{RESET} {content}{' ' * pad} "
|
|
181
|
+
f"{CYAN}│{RESET}\n"
|
|
182
|
+
)
|
|
183
|
+
|
|
184
|
+
# Fill remaining rows if content is shorter than visible area
|
|
185
|
+
for _ in range(visible_rows - len(window)):
|
|
186
|
+
sys.stdout.write(
|
|
187
|
+
f"{margin}{CYAN}│{RESET} {' ' * inner_w} "
|
|
188
|
+
f"{CYAN}│{RESET}\n"
|
|
189
|
+
)
|
|
190
|
+
|
|
191
|
+
# Footer row (scroll hints)
|
|
192
|
+
if max_scroll > 0:
|
|
193
|
+
hint = f"{DIM}j/k scroll q/ESC close{RESET} {DIM}{scroll_info}{RESET}"
|
|
194
|
+
else:
|
|
195
|
+
hint = f"{DIM}q/ESC close{RESET}"
|
|
196
|
+
hint_vis = visible_len(hint)
|
|
197
|
+
hint_pad = max(0, inner_w - hint_vis)
|
|
198
|
+
sys.stdout.write(
|
|
199
|
+
f"{margin}{CYAN}│{RESET} {hint}{' ' * hint_pad} "
|
|
200
|
+
f"{CYAN}│{RESET}\n"
|
|
201
|
+
)
|
|
202
|
+
|
|
203
|
+
# Bottom border
|
|
204
|
+
sys.stdout.write(
|
|
205
|
+
f"{margin}{CYAN}└{'─' * (box_w - 2)}┘{RESET}\n"
|
|
206
|
+
)
|
|
207
|
+
|
|
208
|
+
# Wait for input
|
|
209
|
+
key = get_key()
|
|
210
|
+
if key is None:
|
|
211
|
+
continue
|
|
212
|
+
|
|
213
|
+
# Scroll keys first — must precede dismiss check so arrow
|
|
214
|
+
# keys scroll instead of being swallowed by ESC handling.
|
|
215
|
+
if key in ('UP', 'k'):
|
|
216
|
+
scroll = max(0, scroll - 1)
|
|
217
|
+
continue
|
|
218
|
+
if key in ('DOWN', 'j'):
|
|
219
|
+
scroll = min(max_scroll, scroll + 1)
|
|
220
|
+
continue
|
|
221
|
+
|
|
222
|
+
# Dismiss keys
|
|
223
|
+
if key in ('\x1b', 'q', '?', '\r', '\n'):
|
|
224
|
+
break
|
|
225
|
+
if key == 'SHIFT_UP':
|
|
226
|
+
scroll = max(0, scroll - visible_rows)
|
|
227
|
+
continue
|
|
228
|
+
if key == 'SHIFT_DOWN':
|
|
229
|
+
scroll = min(max_scroll, scroll + visible_rows)
|
|
230
|
+
continue
|
|
231
|
+
if key == 'g':
|
|
232
|
+
scroll = 0
|
|
233
|
+
continue
|
|
234
|
+
if key == 'G':
|
|
235
|
+
scroll = max_scroll
|
|
236
|
+
continue
|
|
237
|
+
|
|
238
|
+
sys.stdout.write('\033[?25h')
|
|
239
|
+
sys.stdout.flush()
|
|
240
|
+
|
|
241
|
+
|
|
242
|
+
# ── Legacy functions (kept for CLI --help and tests) ───────────────────
|
|
243
|
+
|
|
244
|
+
def display_categorized_shortcuts():
|
|
245
|
+
"""Display keyboard shortcuts organized by category (non-modal)."""
|
|
246
|
+
w = get_terminal_width()
|
|
247
|
+
print(f"\n{BOLD}Keyboard Shortcuts{RESET}")
|
|
248
|
+
print("=" * w)
|
|
249
|
+
|
|
250
|
+
for category, items in SHORTCUTS.items():
|
|
251
|
+
print(f"\n{CYAN}{category}:{RESET}")
|
|
252
|
+
for key, description in items:
|
|
253
|
+
print(f" {YELLOW}{key:15}{RESET} {description}")
|
|
254
|
+
|
|
255
|
+
print("\n" + "=" * w + "\n")
|
|
256
|
+
|
|
257
|
+
|
|
258
|
+
def display_help():
|
|
259
|
+
"""Display comprehensive help information."""
|
|
260
|
+
help_text = f"""
|
|
261
|
+
{BOLD}Jott - Simple Interactive Task List{RESET}
|
|
262
|
+
{DIM}Version 0.7.1{RESET}
|
|
263
|
+
|
|
264
|
+
{BOLD}BASIC USAGE:{RESET}
|
|
265
|
+
jott Start interactive task manager (current project)
|
|
266
|
+
jott -c <category> Start in specific category
|
|
267
|
+
jott --category <cat> Start in specific category (long form)
|
|
268
|
+
jott --global Start with global tasks
|
|
269
|
+
jott -h / --help Show this help message
|
|
270
|
+
|
|
271
|
+
{BOLD}PROJECT MANAGEMENT:{RESET}
|
|
272
|
+
jott --all-projects Show tasks from all registered projects
|
|
273
|
+
jott --list-projects List all registered projects
|
|
274
|
+
jott --register <name> <path> Register a new project
|
|
275
|
+
jott --unregister <name> Remove project from registry
|
|
276
|
+
jott --refresh Refresh project registry (auto-discover)
|
|
277
|
+
jott --fix-duplicates Fix duplicate task IDs in current directory
|
|
278
|
+
|
|
279
|
+
For keyboard shortcuts, press {CYAN}.?{RESET} inside the interactive TUI.
|
|
280
|
+
|
|
281
|
+
{DIM}For more info: https://github.com/son1112/jot{RESET}"""
|
|
282
|
+
print(help_text)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: jott-cli
|
|
3
|
-
Version: 0.7.
|
|
3
|
+
Version: 0.7.1
|
|
4
4
|
Summary: Feature-rich interactive CLI task manager with AI integration, calendar sync, and keyword automation
|
|
5
5
|
Author-email: Scott Anderson <sonander@gmail.com>
|
|
6
6
|
Maintainer-email: Scott Anderson <sonander@gmail.com>
|
|
@@ -7,7 +7,7 @@ include = ["jot", "jot.*"]
|
|
|
7
7
|
|
|
8
8
|
[project]
|
|
9
9
|
name = "jott-cli"
|
|
10
|
-
version = "0.7.
|
|
10
|
+
version = "0.7.1"
|
|
11
11
|
description = "Feature-rich interactive CLI task manager with AI integration, calendar sync, and keyword automation"
|
|
12
12
|
readme = {file = "README.md", content-type = "text/markdown"}
|
|
13
13
|
requires-python = ">=3.6"
|
|
@@ -46,13 +46,15 @@ class TestCommandHandlerBasics:
|
|
|
46
46
|
assert len(tm.tasks) == initial_count + 1
|
|
47
47
|
|
|
48
48
|
def test_help(self):
|
|
49
|
-
"""Test help
|
|
49
|
+
"""Test help opens modal and returns True"""
|
|
50
50
|
with tempfile.TemporaryDirectory() as tmpdir:
|
|
51
51
|
tm = TaskManager(directory=Path(tmpdir))
|
|
52
52
|
handler = CommandHandler(tm)
|
|
53
53
|
|
|
54
|
-
#
|
|
55
|
-
|
|
54
|
+
# Mock help_modal to skip the interactive modal
|
|
55
|
+
help_mod = sys.modules['jot.ui.display_help']
|
|
56
|
+
with patch.object(help_mod, 'help_modal'):
|
|
57
|
+
result = handler.help()
|
|
56
58
|
|
|
57
59
|
assert result is True
|
|
58
60
|
|
|
@@ -1,233 +0,0 @@
|
|
|
1
|
-
"""Display functions for help and keyboard shortcuts."""
|
|
2
|
-
|
|
3
|
-
from jot.ui.styles import RESET, BOLD, DIM, CYAN, GREEN, YELLOW, get_terminal_width
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
def display_categorized_shortcuts():
|
|
7
|
-
"""Display keyboard shortcuts organized by category."""
|
|
8
|
-
shortcuts = {
|
|
9
|
-
"Navigation": [
|
|
10
|
-
("↑/↓", "Navigate tasks"),
|
|
11
|
-
("Tab", "Cycle through categories"),
|
|
12
|
-
("Ctrl+F", "Fuzzy search tasks"),
|
|
13
|
-
(".z", "Switch project"),
|
|
14
|
-
("Ctrl+C", "Switch category"),
|
|
15
|
-
(".l", "Toggle all categories view"),
|
|
16
|
-
],
|
|
17
|
-
"Task Management": [
|
|
18
|
-
("Enter", "Add task"),
|
|
19
|
-
("Ctrl+E", "Edit current task"),
|
|
20
|
-
("c", "Mark current task"),
|
|
21
|
-
("d", "Delete task"),
|
|
22
|
-
(".d", "Duplicate task"),
|
|
23
|
-
("t", "Toggle task done"),
|
|
24
|
-
("a", "Archive task"),
|
|
25
|
-
(".a", "Toggle archive view"),
|
|
26
|
-
("m", "Move to different category"),
|
|
27
|
-
(".m", "Move task to another project"),
|
|
28
|
-
(".k", "Copy task to another project"),
|
|
29
|
-
("Ctrl+T", "Transfer to category"),
|
|
30
|
-
("Ctrl+↑/↓", "Reorder tasks"),
|
|
31
|
-
("=", "Sort by priority"),
|
|
32
|
-
],
|
|
33
|
-
"Task Details": [
|
|
34
|
-
("n", "Add/edit notes"),
|
|
35
|
-
(".n", "Edit task notes"),
|
|
36
|
-
(".f", "Toggle inline notes display"),
|
|
37
|
-
("p", "Toggle priority cycle"),
|
|
38
|
-
(".h", "Set priority to high"),
|
|
39
|
-
("=", "Sort by priority"),
|
|
40
|
-
(".x", "Set task status"),
|
|
41
|
-
(".w", "Assign day to task"),
|
|
42
|
-
(".o", "Toggle day sorting"),
|
|
43
|
-
(".y", "Toggle today filter"),
|
|
44
|
-
(".u", "Toggle ALL CAPS"),
|
|
45
|
-
("Ctrl+D", "Mark current as done"),
|
|
46
|
-
(".j", "Mark as agent task"),
|
|
47
|
-
("*", "Highlight color picker"),
|
|
48
|
-
("~", "Quick highlight toggle"),
|
|
49
|
-
("Ctrl+L", "Assign parent (link subtask)"),
|
|
50
|
-
],
|
|
51
|
-
"Analysis & Export": [
|
|
52
|
-
("Shift+1", "Fix duplicate task IDs"),
|
|
53
|
-
("Shift+4", "AI task suggestion"),
|
|
54
|
-
(".A", "Ask Claude (read-only, writes to notes)"),
|
|
55
|
-
(".X", "Execute Claude (edit permissions, uses notes)"),
|
|
56
|
-
(".C", "Launch Claude Code with task"),
|
|
57
|
-
(".v", "Send task to local Claude session"),
|
|
58
|
-
(".V", "Send task to any Claude session"),
|
|
59
|
-
(".e", "Execute keyword action"),
|
|
60
|
-
(".b", "Priority timer"),
|
|
61
|
-
(".G", "Export to Google Calendar"),
|
|
62
|
-
(".i", "Import from Google Calendar"),
|
|
63
|
-
(".c", "Copy task to clipboard"),
|
|
64
|
-
("Ctrl+U", "Open URLs in task"),
|
|
65
|
-
],
|
|
66
|
-
"GitHub": [
|
|
67
|
-
(".I", "Import issues from GitHub"),
|
|
68
|
-
(".H", "Export task as GitHub issue"),
|
|
69
|
-
(".D", "Close linked GitHub issue"),
|
|
70
|
-
],
|
|
71
|
-
"System": [
|
|
72
|
-
("h/.?", "Show this help"),
|
|
73
|
-
("r", "Refresh display"),
|
|
74
|
-
("Ctrl+R", "Register current project"),
|
|
75
|
-
("q", "Quit"),
|
|
76
|
-
("Ctrl+X", "Quit"),
|
|
77
|
-
("Esc", "Exit mode / Quit"),
|
|
78
|
-
],
|
|
79
|
-
"Fuzzy Search": [
|
|
80
|
-
("Ctrl+A", "Toggle archived tasks in search"),
|
|
81
|
-
],
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
w = get_terminal_width()
|
|
85
|
-
print(f"\n{BOLD}Keyboard Shortcuts{RESET}")
|
|
86
|
-
print("=" * w)
|
|
87
|
-
|
|
88
|
-
for category, items in shortcuts.items():
|
|
89
|
-
print(f"\n{CYAN}{category}:{RESET}")
|
|
90
|
-
for key, description in items:
|
|
91
|
-
print(f" {YELLOW}{key:15}{RESET} {description}")
|
|
92
|
-
|
|
93
|
-
print("\n" + "=" * w + "\n")
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
def display_help():
|
|
97
|
-
"""Display comprehensive help information."""
|
|
98
|
-
help_text = f"""
|
|
99
|
-
{BOLD}Jott - Simple Interactive Task List{RESET}
|
|
100
|
-
{DIM}Version 0.7.0{RESET}
|
|
101
|
-
|
|
102
|
-
{BOLD}BASIC USAGE:{RESET}
|
|
103
|
-
jott Start interactive task manager (current project)
|
|
104
|
-
jott -c <category> Start in specific category
|
|
105
|
-
jott --category <cat> Start in specific category (long form)
|
|
106
|
-
jott --global Start with global tasks
|
|
107
|
-
jott -h / --help Show this help message
|
|
108
|
-
|
|
109
|
-
{BOLD}PROJECT MANAGEMENT:{RESET}
|
|
110
|
-
jott --all-projects Show tasks from all registered projects
|
|
111
|
-
jott --list-projects List all registered projects
|
|
112
|
-
jott --register <name> <path> Register a new project
|
|
113
|
-
jott --unregister <name> Remove project from registry
|
|
114
|
-
jott --refresh Refresh project registry (auto-discover)
|
|
115
|
-
jott --fix-duplicates Fix duplicate task IDs in current directory
|
|
116
|
-
|
|
117
|
-
{BOLD}NAVIGATION:{RESET}
|
|
118
|
-
{CYAN}↑/↓{RESET} Navigate through tasks
|
|
119
|
-
{CYAN}Tab{RESET} Cycle through categories
|
|
120
|
-
{CYAN}Ctrl+F{RESET} Fuzzy search tasks
|
|
121
|
-
{CYAN}.z{RESET} Switch between projects
|
|
122
|
-
{CYAN}Ctrl+C{RESET} Switch between categories
|
|
123
|
-
{CYAN}.l{RESET} Toggle all categories view
|
|
124
|
-
|
|
125
|
-
{BOLD}TASK MANAGEMENT:{RESET}
|
|
126
|
-
{CYAN}Type + Enter{RESET} Add new task
|
|
127
|
-
{CYAN}Ctrl+E{RESET} Edit current task text
|
|
128
|
-
{CYAN}c{RESET} Mark task as current
|
|
129
|
-
{CYAN}d{RESET} Delete selected task
|
|
130
|
-
{CYAN}.d{RESET} Duplicate current task
|
|
131
|
-
{CYAN}t{RESET} Toggle task done/undone
|
|
132
|
-
{CYAN}a{RESET} Archive task (mark as done/canceled)
|
|
133
|
-
{CYAN}.a{RESET} Toggle archive view
|
|
134
|
-
{CYAN}m{RESET} Move task to different category
|
|
135
|
-
{CYAN}.m{RESET} Move task to another project
|
|
136
|
-
{CYAN}.k{RESET} Copy task to another project
|
|
137
|
-
{CYAN}Ctrl+T{RESET} Transfer task to category
|
|
138
|
-
{CYAN}Ctrl+↑/↓{RESET} Reorder tasks
|
|
139
|
-
{CYAN}={RESET} Sort by priority
|
|
140
|
-
|
|
141
|
-
{BOLD}TASK DETAILS:{RESET}
|
|
142
|
-
{CYAN}n{RESET} Add/edit task notes (opens editor)
|
|
143
|
-
{CYAN}.n{RESET} Edit task notes
|
|
144
|
-
{CYAN}.f{RESET} Toggle inline notes display
|
|
145
|
-
{CYAN}p{RESET} Toggle task priority cycle
|
|
146
|
-
{CYAN}.h{RESET} Set priority to high
|
|
147
|
-
{CYAN}.x{RESET} Set task status (todo/in-progress/blocked/done)
|
|
148
|
-
{CYAN}.w{RESET} Assign day to task
|
|
149
|
-
{CYAN}.o{RESET} Toggle day sorting
|
|
150
|
-
{CYAN}.y{RESET} Toggle today filter
|
|
151
|
-
{CYAN}.u{RESET} Toggle ALL CAPS
|
|
152
|
-
{CYAN}Ctrl+D{RESET} Mark current task as done
|
|
153
|
-
{CYAN}.j{RESET} Mark task for agent/AI assistance
|
|
154
|
-
{CYAN}*{RESET} Highlight color picker (6 colors)
|
|
155
|
-
{CYAN}~{RESET} Quick highlight toggle (default color)
|
|
156
|
-
{CYAN}Ctrl+L{RESET} Assign parent task (subtask link)
|
|
157
|
-
|
|
158
|
-
{BOLD}KEYWORDS:{RESET}
|
|
159
|
-
Keywords trigger automatic actions when added to task text:
|
|
160
|
-
|
|
161
|
-
{YELLOW}bullet:{RESET} task Start bullet priority timer
|
|
162
|
-
{YELLOW}gcal:{RESET} task Export to Google Calendar
|
|
163
|
-
{YELLOW}ai:{RESET} task Mark for AI/agent assistance
|
|
164
|
-
{YELLOW}analyze:{RESET} task Create analysis plan with Claude Code
|
|
165
|
-
{YELLOW}remind:{RESET} task Set system notification (.e)
|
|
166
|
-
|
|
167
|
-
Configure keywords in ~/.jot-keywords.json
|
|
168
|
-
|
|
169
|
-
{BOLD}CATEGORIES:{RESET}
|
|
170
|
-
Categories organize tasks within projects:
|
|
171
|
-
• Local categories: Project-specific (max 10 per project)
|
|
172
|
-
• Global categories: Cross-project tasks (max 10 global)
|
|
173
|
-
• Default: Tasks without a category
|
|
174
|
-
|
|
175
|
-
{CYAN}jott -c backend{RESET} Start in "backend" category
|
|
176
|
-
{CYAN}Tab{RESET} Cycle through categories
|
|
177
|
-
{CYAN}Ctrl+C{RESET} Create/switch categories interactively
|
|
178
|
-
{CYAN}m{RESET} Move task between categories
|
|
179
|
-
|
|
180
|
-
{BOLD}PROJECTS:{RESET}
|
|
181
|
-
Multi-project support with auto-discovery:
|
|
182
|
-
• Auto-discovers projects in ~/projects/
|
|
183
|
-
• Each project has its own .jot.json
|
|
184
|
-
• Switch projects with {CYAN}.z{RESET} or {CYAN}jott -p <name>{RESET}
|
|
185
|
-
|
|
186
|
-
{BOLD}ANALYSIS & EXPORT:{RESET}
|
|
187
|
-
{CYAN}Shift+1{RESET} Fix duplicate task IDs
|
|
188
|
-
{CYAN}Shift+4{RESET} AI task suggestion
|
|
189
|
-
{CYAN}.A{RESET} Ask Claude (read-only, writes to task notes)
|
|
190
|
-
{CYAN}.X{RESET} Execute Claude (edit permissions, uses notes)
|
|
191
|
-
{CYAN}.C{RESET} Launch Claude Code with current task (tmux)
|
|
192
|
-
{CYAN}.v{RESET} Send task to local Claude session
|
|
193
|
-
{CYAN}.V{RESET} Send task to any Claude session (picker)
|
|
194
|
-
{CYAN}.e{RESET} Execute keyword action for task
|
|
195
|
-
{CYAN}.b{RESET} Priority timer
|
|
196
|
-
{CYAN}.G{RESET} Export to Google Calendar
|
|
197
|
-
{CYAN}.i{RESET} Import tasks from Google Calendar
|
|
198
|
-
{CYAN}.c{RESET} Copy task text to clipboard
|
|
199
|
-
{CYAN}Ctrl+U{RESET} Open URLs found in task text
|
|
200
|
-
|
|
201
|
-
{BOLD}GITHUB:{RESET}
|
|
202
|
-
{CYAN}.I{RESET} Import issues from GitHub
|
|
203
|
-
{CYAN}.H{RESET} Export current task as GitHub issue
|
|
204
|
-
{CYAN}.D{RESET} Close linked GitHub issue
|
|
205
|
-
|
|
206
|
-
{BOLD}FUZZY SEARCH:{RESET}
|
|
207
|
-
{CYAN}Ctrl+F{RESET} Enter fuzzy search mode
|
|
208
|
-
{CYAN}Ctrl+A{RESET} Toggle archived tasks in search results
|
|
209
|
-
{CYAN}↑/↓{RESET} Navigate results
|
|
210
|
-
{CYAN}Enter{RESET} Select task
|
|
211
|
-
{CYAN}Esc{RESET} Exit search
|
|
212
|
-
|
|
213
|
-
{BOLD}SYSTEM:{RESET}
|
|
214
|
-
{CYAN}h or .?{RESET} Show keyboard shortcuts
|
|
215
|
-
{CYAN}r{RESET} Refresh display
|
|
216
|
-
{CYAN}Ctrl+R{RESET} Register current project in registry
|
|
217
|
-
{CYAN}q{RESET} Quit
|
|
218
|
-
{CYAN}Ctrl+X{RESET} Quit
|
|
219
|
-
{CYAN}Esc{RESET} Exit current mode / Quit
|
|
220
|
-
|
|
221
|
-
{BOLD}FILES:{RESET}
|
|
222
|
-
{GREEN}.jot.json{RESET} Task storage (per project)
|
|
223
|
-
{GREEN}~/.jot-categories/<name>.json{RESET} Global category tasks
|
|
224
|
-
{GREEN}~/.jot-keywords.json{RESET} Keyword configuration
|
|
225
|
-
{GREEN}~/.jot-project-registry.json{RESET} Project discovery cache
|
|
226
|
-
|
|
227
|
-
{BOLD}CONFIGURATION:{RESET}
|
|
228
|
-
• Edit ~/.jot-keywords.json to customize keyword actions
|
|
229
|
-
• Category colors: Edit category config (Ctrl+C)
|
|
230
|
-
• Global vs local: Use -g flag or create global categories
|
|
231
|
-
|
|
232
|
-
{DIM}For more info: https://github.com/your-repo/jot{RESET}"""
|
|
233
|
-
print(help_text)
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|