taskai-cli 1.0.0__tar.gz → 1.0.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.
- {taskai_cli-1.0.0 → taskai_cli-1.0.2}/.gitignore +4 -1
- {taskai_cli-1.0.0 → taskai_cli-1.0.2}/PKG-INFO +1 -1
- taskai_cli-1.0.2/migrations/_001_removing_lists.py +50 -0
- {taskai_cli-1.0.0 → taskai_cli-1.0.2}/pyproject.toml +1 -1
- {taskai_cli-1.0.0 → taskai_cli-1.0.2}/taskai/cli.py +78 -12
- {taskai_cli-1.0.0 → taskai_cli-1.0.2}/taskai/services/user_setup.py +4 -4
- {taskai_cli-1.0.0 → taskai_cli-1.0.2}/test/test_cli.py +20 -2
- {taskai_cli-1.0.0 → taskai_cli-1.0.2}/.github/workflows/publish-to-pypi.yml +0 -0
- {taskai_cli-1.0.0 → taskai_cli-1.0.2}/DEVLOG.md +0 -0
- {taskai_cli-1.0.0 → taskai_cli-1.0.2}/README.md +0 -0
- {taskai_cli-1.0.0 → taskai_cli-1.0.2}/docs/index.md +0 -0
- {taskai_cli-1.0.0 → taskai_cli-1.0.2}/migrations/convert_title_to_name.py +0 -0
- {taskai_cli-1.0.0 → taskai_cli-1.0.2}/mkdocs.yml +0 -0
- {taskai_cli-1.0.0 → taskai_cli-1.0.2}/taskai/config.py +0 -0
- {taskai_cli-1.0.0 → taskai_cli-1.0.2}/taskai/help_menu.py +0 -0
- {taskai_cli-1.0.0 → taskai_cli-1.0.2}/taskai/json_dir_database.py +0 -0
- {taskai_cli-1.0.0 → taskai_cli-1.0.2}/taskai/models.py +0 -0
- {taskai_cli-1.0.0 → taskai_cli-1.0.2}/taskai/services/ai.py +0 -0
- {taskai_cli-1.0.0 → taskai_cli-1.0.2}/taskai/services/repair_database.py +0 -0
- {taskai_cli-1.0.0 → taskai_cli-1.0.2}/taskai/views.py +0 -0
- {taskai_cli-1.0.0 → taskai_cli-1.0.2}/test/test_execution.py +0 -0
- {taskai_cli-1.0.0 → taskai_cli-1.0.2}/test/test_json_dir_database.py +0 -0
- {taskai_cli-1.0.0 → taskai_cli-1.0.2}/test/test_view.py +0 -0
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import argparse
|
|
2
|
+
import orjson as json
|
|
3
|
+
from taskai.models import TodoItem
|
|
4
|
+
|
|
5
|
+
def migrate(data):
|
|
6
|
+
if "TodoList" in data:
|
|
7
|
+
for k, record in data["TodoList"].items():
|
|
8
|
+
|
|
9
|
+
record["child_ids"] = record.pop("item_ids")
|
|
10
|
+
TodoItem(**record)
|
|
11
|
+
print(f"Converting {k} to Item")
|
|
12
|
+
data["TodoItem"][k] = record
|
|
13
|
+
data.pop("TodoList")
|
|
14
|
+
|
|
15
|
+
for k, record in data["TodoItem"].items():
|
|
16
|
+
|
|
17
|
+
if "title" in record:
|
|
18
|
+
print(f"converting title->name for {k}")
|
|
19
|
+
record["title"] = record["name"]
|
|
20
|
+
record.pop("title")
|
|
21
|
+
|
|
22
|
+
if "parent" in record:
|
|
23
|
+
print(f"converting parent->parent_id for {k}")
|
|
24
|
+
record["parent_id"] = record["parent"]
|
|
25
|
+
record.pop("parent")
|
|
26
|
+
|
|
27
|
+
if "child_ids" not in record:
|
|
28
|
+
print(f"Adding Child IDs {k}")
|
|
29
|
+
record["child_ids"] = []
|
|
30
|
+
|
|
31
|
+
try:
|
|
32
|
+
data["TodoItem"][k] = TodoItem(**record).model_dump()
|
|
33
|
+
except:
|
|
34
|
+
print("validation for {} failed".format(k))
|
|
35
|
+
import sys
|
|
36
|
+
sys.exit()
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
arg_parser = argparse.ArgumentParser()
|
|
40
|
+
arg_parser.add_argument("path", help="path to taskai root")
|
|
41
|
+
args = arg_parser.parse_args()
|
|
42
|
+
|
|
43
|
+
with open(args.path, "rb") as f:
|
|
44
|
+
data = json.loads(f.read())
|
|
45
|
+
|
|
46
|
+
migrate(data)
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
with open(args.path, "wb") as f:
|
|
50
|
+
f.write(json.dumps(data))
|
|
@@ -208,13 +208,45 @@ class Controller:
|
|
|
208
208
|
db.commit()
|
|
209
209
|
|
|
210
210
|
# utilities
|
|
211
|
+
def _parse_arg_string(arg_string: str) -> list[str]:
|
|
212
|
+
"""parses a string properly before dispatching it to the argument parser"""
|
|
213
|
+
|
|
214
|
+
# scan for quote characters
|
|
215
|
+
|
|
216
|
+
currently_enclosed = False
|
|
217
|
+
current_quote_char = None
|
|
218
|
+
quote_chars = ('"',"'")
|
|
219
|
+
buffer = ""
|
|
220
|
+
arg_parts = []
|
|
221
|
+
for c in arg_string:
|
|
222
|
+
if c == " ":
|
|
223
|
+
if currently_enclosed:
|
|
224
|
+
buffer += c
|
|
225
|
+
else:
|
|
226
|
+
arg_parts.append(buffer)
|
|
227
|
+
buffer = ""
|
|
228
|
+
elif c == current_quote_char:
|
|
229
|
+
currently_enclosed = False
|
|
230
|
+
current_quote_char = None
|
|
231
|
+
|
|
232
|
+
elif c in quote_chars and not currently_enclosed:
|
|
233
|
+
currently_enclosed = True
|
|
234
|
+
current_quote_char = c
|
|
235
|
+
else:
|
|
236
|
+
buffer += c
|
|
237
|
+
if buffer:
|
|
238
|
+
arg_parts.append(buffer)
|
|
239
|
+
return arg_parts
|
|
240
|
+
|
|
211
241
|
def _parse_remaining(remaining_args: list[str]) -> tuple[list, dict]:
|
|
212
242
|
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
243
|
+
# parse flags
|
|
244
|
+
|
|
245
|
+
#for i, _arg in enumerate(remaining_args):
|
|
246
|
+
# remaining_args[i] = _arg.replace(" ", "+-*/")
|
|
247
|
+
#remaining_args = " ".join(remaining_args).replace("="," ").split(" ")
|
|
248
|
+
#for i, _arg in enumerate(remaining_args):
|
|
249
|
+
# remaining_args[i] = _arg.replace("+-*/", " ")
|
|
218
250
|
|
|
219
251
|
# outputs
|
|
220
252
|
args = []
|
|
@@ -223,11 +255,16 @@ def _parse_remaining(remaining_args: list[str]) -> tuple[list, dict]:
|
|
|
223
255
|
while remaining_args:
|
|
224
256
|
next_arg = remaining_args.pop(0)
|
|
225
257
|
if next_arg.startswith("--"):
|
|
226
|
-
|
|
227
|
-
|
|
258
|
+
if "=" in next_arg:
|
|
259
|
+
key, value = next_arg.split("=")
|
|
260
|
+
kwargs[key] = value
|
|
261
|
+
else:
|
|
262
|
+
assert remaining_args, "kwarg specified with no value provided"
|
|
263
|
+
kwargs[next_arg[2:]] = remaining_args.pop(0)
|
|
228
264
|
else:
|
|
229
265
|
args.append(next_arg)
|
|
230
|
-
|
|
266
|
+
|
|
267
|
+
|
|
231
268
|
return args, kwargs
|
|
232
269
|
|
|
233
270
|
def _is_int(val: any) -> bool:
|
|
@@ -349,22 +386,51 @@ def interactive_program():
|
|
|
349
386
|
# builtins.print = console.print
|
|
350
387
|
|
|
351
388
|
response = ""
|
|
389
|
+
last_show_command = [("show", "all"), {}]
|
|
390
|
+
args = None
|
|
391
|
+
kwargs = None
|
|
392
|
+
|
|
352
393
|
_clear_screen()
|
|
353
394
|
while True:
|
|
354
395
|
|
|
355
396
|
try:
|
|
397
|
+
|
|
398
|
+
# render last show command
|
|
399
|
+
if last_show_command is not None:
|
|
400
|
+
try:
|
|
401
|
+
execute_commands(*last_show_command[0], **last_show_command[1])
|
|
402
|
+
except Exception as e:
|
|
403
|
+
print(e)
|
|
404
|
+
|
|
405
|
+
Console().rule()
|
|
406
|
+
|
|
407
|
+
# prompt user input
|
|
356
408
|
response = Prompt.ask("Type your commands:", default=response)
|
|
357
|
-
|
|
358
|
-
|
|
409
|
+
|
|
410
|
+
# parse commands
|
|
411
|
+
args_remaining = _parse_arg_string(response)
|
|
412
|
+
args, kwargs = _parse_remaining(args_remaining)
|
|
413
|
+
print("arg_string:", args_remaining)
|
|
414
|
+
print("args:", args)
|
|
415
|
+
print("kwargs:", kwargs)
|
|
359
416
|
if args[0] == "task":
|
|
360
417
|
args = args[1:]
|
|
361
|
-
|
|
418
|
+
|
|
419
|
+
# defer show
|
|
420
|
+
if args[0] == "show":
|
|
421
|
+
last_show_command = (args, kwargs)
|
|
422
|
+
return_code = 1
|
|
423
|
+
else:
|
|
424
|
+
return_code = execute_commands(*args, **kwargs)
|
|
425
|
+
|
|
426
|
+
_clear_screen()
|
|
362
427
|
if return_code == 0:
|
|
363
428
|
break
|
|
364
|
-
Console().rule()
|
|
365
429
|
|
|
366
430
|
except KeyboardInterrupt:
|
|
367
431
|
break
|
|
432
|
+
except Exception as e:
|
|
433
|
+
print(e)
|
|
368
434
|
|
|
369
435
|
_clear_screen()
|
|
370
436
|
sys.exit(1)
|
|
@@ -14,20 +14,20 @@ def user_setup_service(
|
|
|
14
14
|
db: JsonDirectoryDatabase
|
|
15
15
|
):
|
|
16
16
|
|
|
17
|
-
config = db.
|
|
17
|
+
config = db.get_config()
|
|
18
18
|
# setup gemini model
|
|
19
19
|
print("Beginning setup")
|
|
20
20
|
if "GEMINI_API_KEY" not in config:
|
|
21
21
|
api_key = _get_gemini_api_key()
|
|
22
22
|
if api_key:
|
|
23
|
-
|
|
23
|
+
db.update_config(GEMINI_API_KEY=api_key)
|
|
24
24
|
else:
|
|
25
25
|
print("gemini key already specified")
|
|
26
26
|
|
|
27
27
|
if "GEMINI_MODEL" not in config:
|
|
28
28
|
model = _select_gemini_model()
|
|
29
29
|
if model:
|
|
30
|
-
|
|
30
|
+
db.update_config(GEMINI_MODEL=model)
|
|
31
31
|
else:
|
|
32
32
|
print("gemini model already specified")
|
|
33
33
|
print("Setup complete! Use 'task config set|get|list' to interact with your configuration options")
|
|
@@ -60,4 +60,4 @@ if __name__ == "__main__":
|
|
|
60
60
|
".taskai/task_db", user=os.getenv("USER")
|
|
61
61
|
)
|
|
62
62
|
db.connect()
|
|
63
|
-
user_setup_service(db)
|
|
63
|
+
user_setup_service(db)
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
from taskai.json_dir_database import JsonDirectoryDatabase
|
|
2
|
+
from taskai.cli import _parse_arg_string
|
|
2
3
|
import os
|
|
3
4
|
import shutil
|
|
4
5
|
|
|
@@ -53,6 +54,23 @@ def test_run_commands():
|
|
|
53
54
|
finally:
|
|
54
55
|
_cleanup_db()
|
|
55
56
|
|
|
57
|
+
def test_args_parser():
|
|
58
|
+
|
|
59
|
+
def _assert_list_equal(l1, l2):
|
|
60
|
+
assert len(l1) == len(l2), f"{l1} length not equal to {l2} length"
|
|
61
|
+
assert all([thing1==thing2 for thing1, thing2 in zip(l1, l2)]), f"{l1} not equal to {l2}"
|
|
62
|
+
|
|
63
|
+
dataset = [
|
|
64
|
+
("show thing 1", ["show", "thing", "1"]),
|
|
65
|
+
("show 'this is a string' 2", ["show", "this is a string", "2"]),
|
|
66
|
+
("show https://url.com/thing?arg=1 hello there", ["show", "https://url.com/thing?arg=1", "hello", "there"])
|
|
67
|
+
]
|
|
68
|
+
|
|
69
|
+
for input, label in dataset:
|
|
70
|
+
output = _parse_arg_string(input)
|
|
71
|
+
_assert_list_equal(label, output)
|
|
72
|
+
|
|
73
|
+
|
|
56
74
|
|
|
57
75
|
def _cleanup_db():
|
|
58
76
|
os.chdir(CWD)
|
|
@@ -60,5 +78,5 @@ def _cleanup_db():
|
|
|
60
78
|
shutil.rmtree(TESTING_DIR)
|
|
61
79
|
|
|
62
80
|
if __name__ == "__main__":
|
|
63
|
-
|
|
64
|
-
test_run_commands()
|
|
81
|
+
test_args_parser()
|
|
82
|
+
# test_run_commands()
|
|
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
|