taskai-cli 0.1.5__tar.gz → 1.0.0__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 (27) hide show
  1. {taskai_cli-0.1.5 → taskai_cli-1.0.0}/DEVLOG.md +84 -1
  2. {taskai_cli-0.1.5 → taskai_cli-1.0.0}/PKG-INFO +4 -4
  3. {taskai_cli-0.1.5 → taskai_cli-1.0.0}/README.md +3 -3
  4. taskai_cli-1.0.0/migrations/convert_title_to_name.py +30 -0
  5. {taskai_cli-0.1.5 → taskai_cli-1.0.0}/pyproject.toml +1 -1
  6. {taskai_cli-0.1.5 → taskai_cli-1.0.0}/taskai/cli.py +102 -140
  7. {taskai_cli-0.1.5 → taskai_cli-1.0.0}/taskai/help_menu.py +3 -3
  8. taskai_cli-1.0.0/taskai/json_dir_database.py +252 -0
  9. taskai_cli-1.0.0/taskai/models.py +64 -0
  10. {taskai_cli-0.1.5 → taskai_cli-1.0.0}/taskai/services/ai.py +19 -12
  11. taskai_cli-1.0.0/taskai/services/repair_database.py +33 -0
  12. taskai_cli-1.0.0/taskai/views.py +104 -0
  13. taskai_cli-1.0.0/test/test_cli.py +64 -0
  14. taskai_cli-1.0.0/test/test_execution.py +12 -0
  15. taskai_cli-1.0.0/test/test_json_dir_database.py +97 -0
  16. taskai_cli-1.0.0/test/test_view.py +60 -0
  17. taskai_cli-0.1.5/taskai/json_dir_database.py +0 -204
  18. taskai_cli-0.1.5/taskai/models.py +0 -63
  19. taskai_cli-0.1.5/taskai/services/repair_database.py +0 -39
  20. taskai_cli-0.1.5/taskai/views.py +0 -94
  21. taskai_cli-0.1.5/test/test_json_dir_database.py +0 -80
  22. {taskai_cli-0.1.5 → taskai_cli-1.0.0}/.github/workflows/publish-to-pypi.yml +0 -0
  23. {taskai_cli-0.1.5 → taskai_cli-1.0.0}/.gitignore +0 -0
  24. {taskai_cli-0.1.5 → taskai_cli-1.0.0}/docs/index.md +0 -0
  25. {taskai_cli-0.1.5 → taskai_cli-1.0.0}/mkdocs.yml +0 -0
  26. {taskai_cli-0.1.5 → taskai_cli-1.0.0}/taskai/config.py +0 -0
  27. {taskai_cli-0.1.5 → taskai_cli-1.0.0}/taskai/services/user_setup.py +0 -0
@@ -1,3 +1,86 @@
1
+ # 6-20
2
+
3
+ Let's think critically about what i want this API to lookk like. How should be people be
4
+ using the CLI?
5
+
6
+
7
+ task create {name} {**kwargs} -> create an item
8
+ task add {parent_id} ... -> create an item as a child
9
+ task show all
10
+ task show {id}
11
+
12
+
13
+
14
+ # 6-19
15
+
16
+ Really this whole thing should just be a tree abstraction, and I should have a root node class
17
+ and just built a tree database with some attrs depending on the type
18
+
19
+ idk why i'm being a dipshit
20
+ But that's gonna be the next iteration
21
+
22
+ # 6-18
23
+
24
+ Everything is fucked up anyways lol so might as qweell make some decisions about
25
+ the best way to do the database
26
+
27
+
28
+
29
+ ```python
30
+ class DB:
31
+
32
+ def get_item(id: int) -> TodoItem:
33
+ def get_comment(id: int) -> Comment:
34
+ def get_config() -> CLIConfig:
35
+ def create_item(name: str, parent: Optional[TodoItem]=None, ...) -> str:
36
+ def create_comment(content: str, parent: TodoItem) -> str:
37
+ def delete_item(name: str) -> bool:
38
+ def delete_comment(name: str) -> bool:
39
+ def update_item(id_: int, kwargs) -> bool:
40
+ def update_comment(id_: int, kwargs) -> bool:
41
+ def update_config(kwargs) -> bool:
42
+
43
+ def connect():
44
+ pass
45
+ def commit():
46
+ pass
47
+ def validate():
48
+ pass
49
+
50
+ ```
51
+
52
+ Important factors:
53
+ - do i want to serialize/deserialize every record twice? probably not
54
+ - so let's make sure that everything is read-only
55
+
56
+ How do i want to handle parentage?
57
+ i could:
58
+ - do it at the client level i.e. make sure to call (add parent)
59
+ - do it at the db level i.e. on every create, update, and delete method, validate
60
+
61
+ Let's do it at the db level - i want the database to be responsible for ensuring data
62
+ validation so I don't have to worry about it when I'm writing code downstream
63
+
64
+
65
+ # 6-17
66
+
67
+ Alright I find myself needing to make some design decisions about hierarchical lists.
68
+
69
+ I could:
70
+ - differentiate between child items and child lists, and have items only be leaf nodes
71
+ pros:
72
+ cons:
73
+ - treat everything as a single "item" and simply due away with the concept of lists as a
74
+ separate data point
75
+ - still distinguish between the two but treat them all as child ids - useful for sorting
76
+
77
+ Looking at it, i see no good reason to distinguish between items and lists - it complicates the
78
+ code without adding any additional functionality. There is nothing that a list does that an item
79
+ can't do apart from be a container, and there's no reason why an item can't also be a container.
80
+
81
+ So let's just go ahead and implement that change.
82
+
83
+
1
84
  # 6-14
2
85
 
3
86
  Damn it's been a productive couple of weeks. App is deployed on PyPi and I'm starting to think
@@ -28,7 +111,7 @@ put would be as methods on the objects, i.e. "item.updateList()", etc.
28
111
  Alright so how are comments gonna look here:
29
112
 
30
113
  ```
31
- Title:
114
+ Name:
32
115
  Due By:
33
116
  Description:
34
117
  Depends On:
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: taskai-cli
3
- Version: 0.1.5
3
+ Version: 1.0.0
4
4
  Author-email: Alex Paskal <alexcpaskal@gmail.com>
5
5
  Requires-Python: >=3.12
6
6
  Requires-Dist: google-genai>=2.8
@@ -15,12 +15,12 @@ Welcome to Task AI - a command-line todo list with some extra ai features.
15
15
 
16
16
  Here's what you can do:
17
17
 
18
- - `task show all` --> show all of your lists and item titles, with their respective IDs prepended
18
+ - `task show all` --> show all of your lists and item names, with their respective IDs prepended
19
19
  - `task show {id or substring}` --> find the list or item matching your identifier and show it using its respective type's show command
20
- - `task show list {id or substring}` --> show the list and all of its item titles
20
+ - `task show list {id or substring}` --> show the list and all of its item names
21
21
  - `task show item {id}` --> show the associated item and all of its specified information
22
22
  - `task show items {id1},{id2},...,{idx}` --> show the associated items and all of their specified information
23
- - `task create item {list id or substring} {title} {**kwargs}` --> Create a new item for the associated list. Can specify kwargs as --optional cli arguments.
23
+ - `task create item {list id or substring} {name} {**kwargs}` --> Create a new item for the associated list. Can specify kwargs as --optional cli arguments.
24
24
  - `task create list {name}` --> create a new list by that name
25
25
  - `task delete {id}` --> deletes the list or item associated with that id
26
26
  - `task delete item {id}` --> deletes the item associated with that id
@@ -4,12 +4,12 @@ Welcome to Task AI - a command-line todo list with some extra ai features.
4
4
 
5
5
  Here's what you can do:
6
6
 
7
- - `task show all` --> show all of your lists and item titles, with their respective IDs prepended
7
+ - `task show all` --> show all of your lists and item names, with their respective IDs prepended
8
8
  - `task show {id or substring}` --> find the list or item matching your identifier and show it using its respective type's show command
9
- - `task show list {id or substring}` --> show the list and all of its item titles
9
+ - `task show list {id or substring}` --> show the list and all of its item names
10
10
  - `task show item {id}` --> show the associated item and all of its specified information
11
11
  - `task show items {id1},{id2},...,{idx}` --> show the associated items and all of their specified information
12
- - `task create item {list id or substring} {title} {**kwargs}` --> Create a new item for the associated list. Can specify kwargs as --optional cli arguments.
12
+ - `task create item {list id or substring} {name} {**kwargs}` --> Create a new item for the associated list. Can specify kwargs as --optional cli arguments.
13
13
  - `task create list {name}` --> create a new list by that name
14
14
  - `task delete {id}` --> deletes the list or item associated with that id
15
15
  - `task delete item {id}` --> deletes the item associated with that id
@@ -0,0 +1,30 @@
1
+ import argparse
2
+ import orjson as json
3
+
4
+
5
+ def convert_name_to_name(path):
6
+ with open(path, "rb") as f:
7
+ data = json.loads(f.read())
8
+
9
+ for k, record in data["TodoItem"].items():
10
+
11
+ if "name" in record:
12
+ print(f"migrating {k}")
13
+ record["name"] = record["name"]
14
+ record.pop("name")
15
+ elif "name" in record:
16
+ print(f"validated {k}")
17
+ else:
18
+ print(f"{k} is corrupted")
19
+
20
+ with open(path, "wb") as f:
21
+ f.write(json.dumps(data))
22
+
23
+
24
+ arg_parser = argparse.ArgumentParser()
25
+ arg_parser.add_argument("path", help="path to taskai root")
26
+ args = arg_parser.parse_args()
27
+
28
+
29
+ convert_name_to_name(args.path)
30
+
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "taskai-cli"
3
- version = "0.1.5"
3
+ version = "1.0.0"
4
4
  description = ""
5
5
  authors = [{name = "Alex Paskal", email = "alexcpaskal@gmail.com"}]
6
6
  readme = "README.md"
@@ -6,11 +6,12 @@ import builtins
6
6
  import fnmatch
7
7
  import sys
8
8
  import subprocess
9
+ import getpass
9
10
 
10
11
  # local
11
12
  from taskai.json_dir_database import JsonDirectoryDatabase
12
13
  from taskai.views import view_lists, view_item, view_items
13
- from taskai.models import Base, TodoItem, TodoList, Comment
14
+ from taskai.models import TodoItem, Comment
14
15
  from taskai.services.ai import ai_headstart_service, ai_natural_language_service
15
16
  from taskai.services.user_setup import user_setup_service
16
17
  from taskai.services.repair_database import repair_database_service
@@ -25,39 +26,46 @@ from rich.prompt import Prompt
25
26
 
26
27
  # config
27
28
  DB_PATH = ".taskai/task_db"
28
- USER = os.getenv("USER")
29
+ USER = os.getenv("USER") if sys.platform == "linux" else os.getenv('USERNAME')
29
30
  db = JsonDirectoryDatabase(
30
31
  DB_PATH,
31
- USER
32
+ USER,
32
33
  )
33
34
  db.connect()
34
- GlobalConfig.load_dict(db.config)
35
-
36
- og_help = builtins.help
37
- def new_help(*args, **kwargs):
38
- print(f"help: args: {args}, kwargs: {kwargs}")
39
- return og_help(*args, **kwargs)
40
- builtins.help = new_help
35
+ GlobalConfig.load_dict(db.get_config())
41
36
 
42
37
  class Controller:
43
38
 
44
39
  # utilities
45
- def _find_model_by_stringmatch(attr: str, pattern: str) -> TodoItem|TodoList|Comment|None:
40
+ def _find_model_by_stringmatch(attr: str, pattern: str) -> TodoItem|Comment|None:
46
41
 
47
42
  for record_type in [
48
- TodoList,
49
43
  TodoItem,
50
44
  Comment
51
45
  ]:
52
- batch_attrs = db.read_batch_attr(record_type, attr)
46
+ batch_attrs = db.get_item_batch_attr(attr)
53
47
  inside_out = {v: k for k, v in batch_attrs.items()} # TODO this is hacky
54
48
  results = fnmatch.filter(batch_attrs.values(), pattern)
55
49
  if results:
56
50
  id_ = inside_out[results[0]] # might be duplication
57
- return db.read(id_)
58
-
51
+ return db.get_item(id_)
59
52
  return None
60
53
 
54
+ def _parse_item_kwargs(kwargs):
55
+ for k, v in kwargs.copy().items():
56
+ if v is None:
57
+ continue
58
+ match k:
59
+ case "completed": kwargs["completed"] = bool(v)
60
+ case "due_by": kwargs["due_by"] = datetime.strptime(v, "%m-%d-%Y")
61
+ case "depends_on": kwargs["dependency_ids"] = v.split(",")
62
+ return kwargs
63
+
64
+ def _get_root_ids():
65
+ return [
66
+ item_id for item_id in db.get_item_ids()
67
+ if db.get_item_attr(item_id, "parent_id") is None
68
+ ]
61
69
 
62
70
  def _debug(args, kwargs):
63
71
  print("args:", args)
@@ -65,113 +73,69 @@ class Controller:
65
73
 
66
74
  # CRUD
67
75
  def show_all(show_done=True):
68
- view_lists(db, db.lists, show_done=show_done)
69
-
70
- def show_by_id(id_, show_done=True):
71
- if id_ in db.items:
72
- Controller.show_item(id_)
73
- elif id_ in db.lists:
74
- Controller.show_list(id_, show_done=show_done)
75
-
76
- def show_by_list_name(value: str, show_done=True):
76
+ view_lists(db, Controller._get_root_ids(), show_done=show_done)
77
+
78
+ def show_by_item_name(value: str, show_done=True):
77
79
  model = Controller._find_model_by_stringmatch("name", value)
78
- if isinstance(model, TodoList):
79
- Controller.show_list(model.id, show_done=show_done)
80
+ if model:
81
+ Controller.show_item(model.id, show_done=show_done)
80
82
  else:
81
- print(f"Could not find list matching pattern '{value}'")
82
-
83
- def show_list(list_id: int|str, show_done=True):
84
- view_lists(db, [list_id], show_done=show_done)
85
-
86
- def show_lists():
87
- view_lists(db, db.lists.keys(), show_items=False)
83
+ print(f"Could not find item matching pattern '{value}'")
88
84
 
89
- def show_item(item_id: int|str):
90
- view_item(db, item_id)
85
+ def show_item(item_id: int, **kwargs):
86
+ view_item(db, item_id, **kwargs)
91
87
 
92
- def show_items(item_ids: str):
88
+ def show_items(item_ids: str, **kwargs):
93
89
  item_ids = item_ids.split(",")
94
- view_items(db, item_ids)
90
+ view_items(db, item_ids, **kwargs)
95
91
 
96
92
  def show_examples():
97
93
  ...
98
94
  print("Not implemented yet")
99
95
 
100
- def create_list(name: str):
101
- list = TodoList(name=name)
102
- list_id = db.create(list)
103
- db.commit()
104
- print(f"Creating list {list_id} - {list.name}")
105
-
106
- def create_item(list_id: int|str, title: str, **kwargs):
107
- try:
108
- int(list_id)
109
- except ValueError:
110
- list_ = Controller._find_model_by_stringmatch("name", list_id)
111
- # TODO this should be just lists, not models
112
- list_id = list_.id
113
-
114
- item = TodoItem(title=title, list_id=list_id)
115
-
116
- for k, v in kwargs.items():
117
- if v is None:
118
- continue
119
- match k:
120
- case "completed": item.completed = bool(v)
121
- case "description": item.description = str(v)
122
- case "due_by": item.due_by = datetime.strptime(v, "%m-%d-%Y")
123
- case "parent": item.parent = str(v)
124
- case "priority": item.priority = int(v)
125
- case "depends_on": item.dependency_ids.extend(v.split(","))
126
- # TODO handle recurrence
127
- db.create(item)
96
+ def create_item(name: str, parent_id=None, **kwargs):
97
+ if parent_id is not None and not _is_int(parent_id):
98
+ parent = Controller._find_model_by_stringmatch("name", parent_id)
99
+ if not parent:
100
+ Controller.throw_error(f"Could not find parent by id '{parent_id}'")
101
+ return
102
+ parent_id = parent.id
103
+
104
+ kwargs = Controller._parse_item_kwargs(kwargs)
105
+ item_id = db.create_item(name=name, parent_id=parent_id, **kwargs)
106
+ print(f"Created item {item_id} - '{name}'")
128
107
  db.commit()
129
108
 
130
109
  def create_comment(item_id: int|str, content: str):
131
- comment = Comment(
132
- item_id=item_id,
133
- content=content
134
- )
135
- db.create(comment)
110
+ comment_id = db.create_comment(content=content, item_id=item_id)
111
+ print(f"Added comment {comment_id} to item {item_id} - '{content}'")
136
112
  db.commit()
137
113
 
138
114
  def update_item(item_id: int|str, **kwargs):
139
- item: TodoItem = db.read(item_id)
140
- for k, v in kwargs.items():
141
- if v is None:
142
- continue
143
- match k:
144
- case "title": item.title = str(v)
145
- case "list_id": item.list_id = str(v)
146
- case "completed": item.completed = bool(v)
147
- case "description": item.description = str(v)
148
- case "due_by": item.due_by = datetime.strptime(v, "%m-%d-%Y")
149
- case "parent": item.parent = str(v)
150
- case "priority": item.priority = int(v)
151
- # TODO handle recurrence
152
-
153
- db.update(item)
115
+ if not _is_int(item_id):
116
+ item_id = Controller._find_model_by_stringmatch("name", item_id)
117
+ db.update_item(item_id, **kwargs)
118
+ print(f"Updated item {item_id}")
154
119
  db.commit()
155
120
 
156
- def delete(id_: int|str):
157
- db.delete(id_)
121
+ def delete_item(id_: int|str):
122
+ db.delete_item(id_)
158
123
  db.commit()
159
- print(f"Deleted {id_}")
124
+ print(f"Deleted item {id_}")
160
125
 
161
- def delete_list_by_name(name: str):
162
- list_ = Controller._find_model_by_stringmatch("name", name)
163
- if list_:
164
- db.delete(list_.id)
126
+ def delete_item_by_name(name: str):
127
+ item = Controller._find_model_by_stringmatch("name", name)
128
+ if item:
129
+ db.delete_item(item.id)
165
130
  db.commit()
166
131
  else:
167
132
  Controller.throw_error("Cannot find list by name")
168
-
169
133
 
170
134
  def delete_completed():
171
- for item_id in db.items.copy():
172
- item: TodoItem = db.read(item_id)
135
+ for item_id in db.get_item_ids():
136
+ item: TodoItem = db.get_item(item_id)
173
137
  if item.completed:
174
- db.delete(item_id)
138
+ db.delete_item(item_id)
175
139
  db.commit()
176
140
 
177
141
  def ai_headstart(item_id: int|str):
@@ -185,21 +149,23 @@ class Controller:
185
149
 
186
150
  def throw_error(error_description: str, *args, **kwargs):
187
151
  print(f"[red]ERROR: {error_description}[/red]\nargs={args}\nkwargs={kwargs}")
152
+ import sys
153
+ sys.exit(-1)
188
154
 
189
155
  def get_config_value(key: str):
190
- print(db.get_config_value(key))
156
+ print(getattr(db.get_config(), key))
191
157
 
192
158
  def list_config():
193
159
  for k, v in db.get_config().model_dump().items():
194
160
  print(f"{k}={v}")
195
161
 
196
162
  def set_config_value(key: str, value: any):
197
- db.set_config_value(key, value)
163
+ db.update_config(**{key: value})
198
164
  db.commit()
199
165
  print(f"setting {key}={value}")
200
166
 
201
167
  def remove_config_value(key: str):
202
- db.config.pop(key)
168
+ db.update_config(**{key: None})
203
169
  db.commit()
204
170
 
205
171
  def run_setup_service():
@@ -208,30 +174,37 @@ class Controller:
208
174
  def repair_service():
209
175
  repair_database_service(db)
210
176
 
211
- def move_item(item_id: int|str, list_identifier: int|str):
212
-
213
- if item_id not in db.items:
214
- Controller.throw_error(f"Couldn't find items with id {item_id}")
215
- item: TodoItem = db.read(item_id)
177
+ def move_item(item_id: int|str, parent_identifier: int|str):
216
178
 
217
- if _is_int(list_identifier):
218
- new_list_: TodoList = db.read(list_identifier)
179
+ if _is_int(item_id):
180
+ item = db.get_item(item_id)
219
181
  else:
220
- new_list_: TodoList = Controller._find_model_by_stringmatch("name", list_identifier)
221
- if not new_list_:
222
- Controller.throw_error(f"Couldn't locate list by identifier {list_identifier}")
182
+ item = Controller._find_model_by_stringmatch("name", item_id)
223
183
 
224
- # update item
225
- item.list_id = new_list_.id
226
- db.update(item)
184
+ # remove from old parent
185
+ if item.parent_id is not None:
186
+ db.remove_child_from_parent(item.id, item.parent_id)
227
187
 
228
- db.commit()
188
+ # add to new parent
189
+ if _is_int(parent_identifier):
190
+ new_parent_id = parent_identifier
191
+ elif not parent_identifier: # anything evaluating to false
192
+ new_parent_id=None
193
+ else:
194
+ new_parent_id = Controller._find_model_by_stringmatch("name", parent_identifier).id
195
+
196
+ db.update_item(item.id, parent_id=new_parent_id)
197
+ if new_parent_id is not None:
198
+ db.add_child_to_parent(item.id, new_parent_id)
199
+
200
+
201
+ db.commit()
229
202
 
230
203
  def add_dependency(src_id: int|str, dst_id: int|str):
231
204
  """Adds a depedency src -> dst, meaning src depends on dst"""
232
- src: TodoItem = db.read(src_id)
233
- src.dependency_ids.append(dst_id)
234
- db.update(src)
205
+ dependency_ids = db.get_item_attr(src_id, "dependency_ids")
206
+ dependency_ids.append(dst_id)
207
+ db.update_item(src_id, dependency_ids=dependency_ids)
235
208
  db.commit()
236
209
 
237
210
  # utilities
@@ -289,33 +262,21 @@ def execute_commands(*args, **kwargs) -> int:
289
262
  case "show":
290
263
  match args[1]:
291
264
  case "all": Controller.show_all(*args[2:], **kwargs)
292
- case "list": Controller.show_list(*args[2:], **kwargs)
293
- case "lists": Controller.show_lists()
294
- case "item": Controller.show_item(*args[2:], **kwargs)
295
- case "items": Controller.show_item(*args[2:], **kwargs)
296
265
  case "examples": Controller.show_examples()
297
- case _ if _is_int(args[1]): Controller.show_by_id(*args[1:], **kwargs)
298
- case _: Controller.show_by_list_name(args[1], **kwargs)
266
+ case _ if _is_int(args[1]): Controller.show_item(*args[1:], **kwargs)
267
+ case _: Controller.show_by_item_name(args[1], **kwargs)
299
268
 
300
269
  case "create":
301
- match args[1]:
302
- case "item": Controller.create_item(*args[2:], **kwargs)
303
- case "list": Controller.create_list(*args[2:], **kwargs)
304
- case "comment": Controller.create_comment(*args[2:], **kwargs)
305
- case _: Controller.throw_error("uncrecognized create command", *args, **kwargs)
270
+ Controller.create_item(args[1], **kwargs)
306
271
 
307
272
  case "update":
308
- match args[1]:
309
- case _ if _is_int(args[1]): Controller.update_item(args[1], **kwargs)
310
- case _: Controller.throw_error("uncregnozed update command", *args, **kwargs)
311
-
273
+ Controller.update_item(args[1], **kwargs)
274
+
312
275
  case "delete" | "remove":
313
276
  match args[1]:
314
- case _ if _is_int(args[1]): Controller.delete(args[1])
315
- case "item": Controller.delete(args[2])
316
- case "list": Controller.delete(args[2])
277
+ case _ if _is_int(args[1]): Controller.delete_item(args[1])
317
278
  case "completed" | "done": Controller.delete_completed()
318
- case _: Controller.delete_list_by_name(args[1])
279
+ case _: Controller.delete_item_by_name(args[1])
319
280
 
320
281
  case "comment":
321
282
  match args[1]:
@@ -338,7 +299,9 @@ def execute_commands(*args, **kwargs) -> int:
338
299
  db.remove()
339
300
 
340
301
  case "add":
341
- Controller.create_item(*args[1:], **kwargs)
302
+ parent_identifier = args[1]
303
+ item_name = args[2]
304
+ Controller.create_item(item_name, parent_identifier, **kwargs)
342
305
 
343
306
  case "complete" | "done":
344
307
  match args[1]:
@@ -355,10 +318,8 @@ def execute_commands(*args, **kwargs) -> int:
355
318
  Controller.delete_completed()
356
319
 
357
320
  case "move":
358
- match args[1]:
359
- case _ if _is_int(args[1]): Controller.move_item(args[1], args[2])
360
- case _: Controller.throw_error("Unrecognized arguments", *args, **kwargs)
361
-
321
+ Controller.move_item(args[1], args[2])
322
+
362
323
  case "depend":
363
324
  src_id, dst_id = args[1:3]
364
325
  match (src_id, dst_id):
@@ -377,6 +338,7 @@ def execute_commands(*args, **kwargs) -> int:
377
338
 
378
339
 
379
340
  except Exception as e:
341
+ raise e
380
342
  Controller.throw_error(f"encountered exception '{e}'", *args, **kwargs)
381
343
 
382
344
  return 1
@@ -5,12 +5,12 @@ help_general = """
5
5
 
6
6
  Welcome to Task! Here's what you can do:
7
7
 
8
- 'task show all' --> show all of your lists and item titles, with their respective IDs prepended
8
+ 'task show all' --> show all of your lists and item names, with their respective IDs prepended
9
9
  'task show {id or substring}' --> find the list or item matching your identifier and show it using its respective type's show command
10
- 'task show list {id or substring}' --> show the list and all of its item titles
10
+ 'task show list {id or substring}' --> show the list and all of its item names
11
11
  'task show item {id}' --> show the associated item and all of its specified information
12
12
  'task show items {id1},{id2},...,{idx}' --> show the associated items and all of their specified information
13
- 'task create item {list id or substring} {title} {**kwargs}' --> Create a new item for the associated list. Can specify kwargs as --optional cli arguments.
13
+ 'task create item {list id or substring} {name} {**kwargs}' --> Create a new item for the associated list. Can specify kwargs as --optional cli arguments.
14
14
  'task create list {name}' --> create a new list by that name
15
15
  'task delete {id}' --> deletes the list or item associated with that id
16
16
  'task delete item {id}' --> deletes the item associated with that id