taskai-cli 1.0.2__tar.gz → 1.1.3__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 (24) hide show
  1. {taskai_cli-1.0.2 → taskai_cli-1.1.3}/DEVLOG.md +23 -1
  2. {taskai_cli-1.0.2 → taskai_cli-1.1.3}/PKG-INFO +1 -1
  3. {taskai_cli-1.0.2 → taskai_cli-1.1.3}/pyproject.toml +1 -1
  4. {taskai_cli-1.0.2 → taskai_cli-1.1.3}/taskai/cli.py +33 -2
  5. {taskai_cli-1.0.2 → taskai_cli-1.1.3}/taskai/config.py +2 -2
  6. {taskai_cli-1.0.2 → taskai_cli-1.1.3}/taskai/models.py +1 -0
  7. {taskai_cli-1.0.2 → taskai_cli-1.1.3}/taskai/services/ai.py +4 -8
  8. taskai_cli-1.1.3/taskai/services/pomodoro.py +65 -0
  9. {taskai_cli-1.0.2 → taskai_cli-1.1.3}/.github/workflows/publish-to-pypi.yml +0 -0
  10. {taskai_cli-1.0.2 → taskai_cli-1.1.3}/.gitignore +0 -0
  11. {taskai_cli-1.0.2 → taskai_cli-1.1.3}/README.md +0 -0
  12. {taskai_cli-1.0.2 → taskai_cli-1.1.3}/docs/index.md +0 -0
  13. {taskai_cli-1.0.2 → taskai_cli-1.1.3}/migrations/_001_removing_lists.py +0 -0
  14. {taskai_cli-1.0.2 → taskai_cli-1.1.3}/migrations/convert_title_to_name.py +0 -0
  15. {taskai_cli-1.0.2 → taskai_cli-1.1.3}/mkdocs.yml +0 -0
  16. {taskai_cli-1.0.2 → taskai_cli-1.1.3}/taskai/help_menu.py +0 -0
  17. {taskai_cli-1.0.2 → taskai_cli-1.1.3}/taskai/json_dir_database.py +0 -0
  18. {taskai_cli-1.0.2 → taskai_cli-1.1.3}/taskai/services/repair_database.py +0 -0
  19. {taskai_cli-1.0.2 → taskai_cli-1.1.3}/taskai/services/user_setup.py +0 -0
  20. {taskai_cli-1.0.2 → taskai_cli-1.1.3}/taskai/views.py +0 -0
  21. {taskai_cli-1.0.2 → taskai_cli-1.1.3}/test/test_cli.py +0 -0
  22. {taskai_cli-1.0.2 → taskai_cli-1.1.3}/test/test_execution.py +0 -0
  23. {taskai_cli-1.0.2 → taskai_cli-1.1.3}/test/test_json_dir_database.py +0 -0
  24. {taskai_cli-1.0.2 → taskai_cli-1.1.3}/test/test_view.py +0 -0
@@ -1,3 +1,25 @@
1
+ # 6-25
2
+
3
+ Alright let's start to think a bit about how I want to handle the pomo service.
4
+
5
+ task pomo 25 3
6
+
7
+
8
+ Let's start with spawning the timer, and then we can worry about logging and shit.
9
+
10
+ Pomo should spawn a process and write a log to a database. The process
11
+ should continuously monitor that log and see "am I active?"
12
+ - if so, it keeps running
13
+ - if not, we prompt the user for what they want to do?
14
+ - rest/reset/cancel
15
+ do I need this to be serialized even? maybe not if I'm just starting - we can start pomo in another thread (or just the same thread)
16
+
17
+ Yeah let's honestly not even worry about the multiprocessing part of it right now.
18
+
19
+ Let's just enter a loop and count down, while I keep clearing the screen
20
+
21
+ I need to figure out how to make it play a bell or have a screen pop up (if it's running in the background)
22
+
1
23
  # 6-20
2
24
 
3
25
  Let's think critically about what i want this API to lookk like. How should be people be
@@ -365,4 +387,4 @@ Pages:
365
387
  - Comments
366
388
  - Text CLI
367
389
  - Dockerize
368
- -
390
+ -
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: taskai-cli
3
- Version: 1.0.2
3
+ Version: 1.1.3
4
4
  Author-email: Alex Paskal <alexcpaskal@gmail.com>
5
5
  Requires-Python: >=3.12
6
6
  Requires-Dist: google-genai>=2.8
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "taskai-cli"
3
- version = "1.0.2"
3
+ version = "1.1.3"
4
4
  description = ""
5
5
  authors = [{name = "Alex Paskal", email = "alexcpaskal@gmail.com"}]
6
6
  readme = "README.md"
@@ -15,6 +15,7 @@ from taskai.models import TodoItem, Comment
15
15
  from taskai.services.ai import ai_headstart_service, ai_natural_language_service
16
16
  from taskai.services.user_setup import user_setup_service
17
17
  from taskai.services.repair_database import repair_database_service
18
+ from taskai.services.pomodoro import pomodoro_service
18
19
  from taskai.help_menu import help_menu
19
20
  from taskai.config import GlobalConfig
20
21
 
@@ -207,6 +208,30 @@ class Controller:
207
208
  db.update_item(src_id, dependency_ids=dependency_ids)
208
209
  db.commit()
209
210
 
211
+ def reorder(id1: int, id2: int, position: str):
212
+ if position not in ("before", "after"):
213
+ Controller.throw_error("position must be one of before, after")
214
+
215
+ child1 = db.get_item(id1)
216
+ parent = db.get_item(child1.parent_id)
217
+ if parent is None:
218
+ Controller.throw_error("Cannot reorder root items")
219
+
220
+
221
+ new_child_ids = []
222
+ for child_id in parent.child_ids:
223
+ if child_id == id1:
224
+ continue
225
+ if child_id == id2:
226
+ new_child_ids.extend(
227
+ [id1, id2] if position == "before" else [id2, id1]
228
+ )
229
+ continue
230
+ new_child_ids.append(child_id)
231
+ db.update_item(parent.id, child_ids=new_child_ids)
232
+ db.commit()
233
+
234
+
210
235
  # utilities
211
236
  def _parse_arg_string(arg_string: str) -> list[str]:
212
237
  """parses a string properly before dispatching it to the argument parser"""
@@ -308,7 +333,10 @@ def execute_commands(*args, **kwargs) -> int:
308
333
 
309
334
  case "update":
310
335
  Controller.update_item(args[1], **kwargs)
311
-
336
+
337
+ case "reorder":
338
+ Controller.reorder(int(args[1]), int(args[3]), args[2])
339
+
312
340
  case "delete" | "remove":
313
341
  match args[1]:
314
342
  case _ if _is_int(args[1]): Controller.delete_item(args[1])
@@ -362,7 +390,10 @@ def execute_commands(*args, **kwargs) -> int:
362
390
  match (src_id, dst_id):
363
391
  case _ if _is_int(src_id) and _is_int(dst_id): Controller.add_dependency(src_id, dst_id)
364
392
  case _: Controller.throw_error("Invalid arrow argument, must be one of (->, <-)")
365
-
393
+
394
+ case "pomo":
395
+ pomodoro_service(int(args[1]), int(args[2]))
396
+
366
397
  # developer use
367
398
  case "db":
368
399
  import orjson as json
@@ -7,9 +7,9 @@ class GlobalConfig:
7
7
  _data_store: dict[str, any]
8
8
 
9
9
  @classmethod
10
- def load_dict(cls, d: dict):
10
+ def load_dict(cls, model):
11
11
  """loads values from a configuration"""
12
- cls._data_store = d
12
+ cls._data_store = model.model_dump()
13
13
 
14
14
  @classmethod
15
15
  def get(cls, key: str):
@@ -44,6 +44,7 @@ class TodoItem(Base):
44
44
  recurs_every: Optional[list[timedelta]] = None
45
45
  recurs_until: Optional[datetime] = None
46
46
  recur_keep_incomplete: bool = False
47
+ status: str|bool = None
47
48
 
48
49
 
49
50
  class Comment(Base):
@@ -30,8 +30,7 @@ def ai_headstart_service(
30
30
  - Parse and return its response
31
31
  """
32
32
 
33
-
34
- item:TodoItem = db.read(item_id)
33
+ item:TodoItem = db.get_item(item_id)
35
34
 
36
35
 
37
36
  from google import genai
@@ -67,11 +66,8 @@ task name: {item.name}
67
66
 
68
67
  prompt += f"\ntask comments:"
69
68
  for comment_id in item.comment_ids:
70
- comment: Comment = db.read(comment_id)
69
+ comment: Comment = db.get_comment(comment_id)
71
70
  prompt += f"\n\t- {comment.content}"
72
-
73
- # return "Survey says go fuck yourself"
74
-
75
71
  # query model
76
72
  client = genai.Client(api_key=api_key)
77
73
  response = client.models.generate_content(
@@ -101,7 +97,7 @@ def ai_natural_language_service(
101
97
  _visited_set = {}
102
98
 
103
99
  def _add_info(item_id, level=0):
104
- item: TodoItem = db.read(id_)
100
+ item: TodoItem = db.get_item(id_)
105
101
  user_info.append(" "*level + f"{item.id} {item.name}")
106
102
  _visited_set.add(item_id)
107
103
  if item.child_ids:
@@ -109,7 +105,7 @@ def ai_natural_language_service(
109
105
  _add_info(child_id, level+1)
110
106
 
111
107
 
112
- for id_ in db.items:
108
+ for id_ in db.get_item_ids():
113
109
  if id_ not in _visited_set:
114
110
  _add_info(id_)
115
111
 
@@ -0,0 +1,65 @@
1
+ from taskai.json_dir_database import JsonDirectoryDatabase
2
+ import datetime
3
+ import time
4
+ from rich import print
5
+ from rich.console import Console
6
+
7
+ def pomodoro_service(
8
+ minutes_on: int,
9
+ minutes_off: int
10
+ ):
11
+
12
+ # STATES
13
+ end_time = datetime.datetime.now()
14
+
15
+ try:
16
+
17
+ state = "ready"
18
+ history = []
19
+ console = Console()
20
+ while True:
21
+ if state == "ready":
22
+ prompt = "Press enter to begin ..."
23
+ input(prompt)
24
+ history.append(f"Starting Pomo for {minutes_on} minutes")
25
+ now = datetime.datetime.now()
26
+ end_time = now + datetime.timedelta(minutes=minutes_on)
27
+ #end_time = now + datetime.timedelta(seconds=5)
28
+ state = "running"
29
+ elif state == "running":
30
+ now = datetime.datetime.now()
31
+ if now < end_time:
32
+ diff = end_time - now
33
+ message = f"{diff.seconds // 60}:{str(diff.seconds % 60).zfill(2)} to go"
34
+ if history[-1].endswith("to go"):
35
+ history.pop()
36
+ history.append(message)
37
+ time.sleep(0.995)
38
+ else:
39
+ state = "done"
40
+ if state == "done":
41
+ history.append("All Finished! Taking rest now")
42
+ state = "resting"
43
+ end_time = datetime.datetime.now() + datetime.timedelta(minutes=minutes_off)
44
+ #end_time = now + datetime.timedelta(seconds=5)
45
+ if state == "resting":
46
+ now = datetime.datetime.now()
47
+ if now < end_time:
48
+ diff = end_time - now
49
+ message = f"{diff.seconds // 60}:{str(diff.seconds % 60).zfill(2)} to go"
50
+ if history[-1].endswith("to go"):
51
+ history.pop()
52
+ history.append(message)
53
+ time.sleep(0.995)
54
+ else:
55
+ state = "ready"
56
+
57
+ console.clear()
58
+ for val in history:
59
+ console.print(val)
60
+ except KeyboardInterrupt:
61
+ return
62
+
63
+
64
+
65
+
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes