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.
- {taskai_cli-1.0.2 → taskai_cli-1.1.3}/DEVLOG.md +23 -1
- {taskai_cli-1.0.2 → taskai_cli-1.1.3}/PKG-INFO +1 -1
- {taskai_cli-1.0.2 → taskai_cli-1.1.3}/pyproject.toml +1 -1
- {taskai_cli-1.0.2 → taskai_cli-1.1.3}/taskai/cli.py +33 -2
- {taskai_cli-1.0.2 → taskai_cli-1.1.3}/taskai/config.py +2 -2
- {taskai_cli-1.0.2 → taskai_cli-1.1.3}/taskai/models.py +1 -0
- {taskai_cli-1.0.2 → taskai_cli-1.1.3}/taskai/services/ai.py +4 -8
- taskai_cli-1.1.3/taskai/services/pomodoro.py +65 -0
- {taskai_cli-1.0.2 → taskai_cli-1.1.3}/.github/workflows/publish-to-pypi.yml +0 -0
- {taskai_cli-1.0.2 → taskai_cli-1.1.3}/.gitignore +0 -0
- {taskai_cli-1.0.2 → taskai_cli-1.1.3}/README.md +0 -0
- {taskai_cli-1.0.2 → taskai_cli-1.1.3}/docs/index.md +0 -0
- {taskai_cli-1.0.2 → taskai_cli-1.1.3}/migrations/_001_removing_lists.py +0 -0
- {taskai_cli-1.0.2 → taskai_cli-1.1.3}/migrations/convert_title_to_name.py +0 -0
- {taskai_cli-1.0.2 → taskai_cli-1.1.3}/mkdocs.yml +0 -0
- {taskai_cli-1.0.2 → taskai_cli-1.1.3}/taskai/help_menu.py +0 -0
- {taskai_cli-1.0.2 → taskai_cli-1.1.3}/taskai/json_dir_database.py +0 -0
- {taskai_cli-1.0.2 → taskai_cli-1.1.3}/taskai/services/repair_database.py +0 -0
- {taskai_cli-1.0.2 → taskai_cli-1.1.3}/taskai/services/user_setup.py +0 -0
- {taskai_cli-1.0.2 → taskai_cli-1.1.3}/taskai/views.py +0 -0
- {taskai_cli-1.0.2 → taskai_cli-1.1.3}/test/test_cli.py +0 -0
- {taskai_cli-1.0.2 → taskai_cli-1.1.3}/test/test_execution.py +0 -0
- {taskai_cli-1.0.2 → taskai_cli-1.1.3}/test/test_json_dir_database.py +0 -0
- {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
|
+
-
|
|
@@ -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,
|
|
10
|
+
def load_dict(cls, model):
|
|
11
11
|
"""loads values from a configuration"""
|
|
12
|
-
cls._data_store =
|
|
12
|
+
cls._data_store = model.model_dump()
|
|
13
13
|
|
|
14
14
|
@classmethod
|
|
15
15
|
def get(cls, key: str):
|
|
@@ -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.
|
|
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.
|
|
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.
|
|
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
|
|
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
|