taskai-cli 1.6.2__tar.gz → 1.6.5__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 (51) hide show
  1. {taskai_cli-1.6.2 → taskai_cli-1.6.5}/DEVLOG.md +84 -0
  2. {taskai_cli-1.6.2 → taskai_cli-1.6.5}/DEVPLAN.md +206 -39
  3. {taskai_cli-1.6.2 → taskai_cli-1.6.5}/PKG-INFO +66 -27
  4. taskai_cli-1.6.5/README.md +163 -0
  5. taskai_cli-1.6.5/TRIAGE.md +135 -0
  6. taskai_cli-1.6.5/docs/.gitignore +6 -0
  7. taskai_cli-1.6.5/docs/_static/.gitkeep +0 -0
  8. taskai_cli-1.6.5/docs/ai-integration.md +87 -0
  9. taskai_cli-1.6.5/docs/browser-mode.md +29 -0
  10. taskai_cli-1.6.5/docs/commands.md +8 -0
  11. taskai_cli-1.6.5/docs/conf.py +117 -0
  12. taskai_cli-1.6.5/docs/configuration.md +32 -0
  13. taskai_cli-1.6.5/docs/getting-started.md +135 -0
  14. taskai_cli-1.6.5/docs/index.md +50 -0
  15. taskai_cli-1.6.5/docs/interactive-mode.md +23 -0
  16. taskai_cli-1.6.5/docs/item-data.md +40 -0
  17. taskai_cli-1.6.5/docs/managing-the-tree.md +72 -0
  18. taskai_cli-1.6.5/docs/requirements.txt +6 -0
  19. {taskai_cli-1.6.2 → taskai_cli-1.6.5}/pyproject.toml +1 -1
  20. {taskai_cli-1.6.2 → taskai_cli-1.6.5}/taskai/browser.py +3 -2
  21. {taskai_cli-1.6.2 → taskai_cli-1.6.5}/taskai/cli.py +97 -53
  22. taskai_cli-1.6.5/taskai/errors.py +9 -0
  23. taskai_cli-1.6.5/taskai/help_menu.py +114 -0
  24. {taskai_cli-1.6.2 → taskai_cli-1.6.5}/taskai/json_dir_database.py +13 -0
  25. {taskai_cli-1.6.2 → taskai_cli-1.6.5}/taskai/models.py +1 -1
  26. {taskai_cli-1.6.2 → taskai_cli-1.6.5}/taskai/services/ai.py +6 -7
  27. taskai_cli-1.6.5/taskai/services/repair_database.py +50 -0
  28. {taskai_cli-1.6.2 → taskai_cli-1.6.5}/taskai/static/canvas.js +222 -18
  29. {taskai_cli-1.6.2 → taskai_cli-1.6.5}/taskai/static/console.js +93 -2
  30. {taskai_cli-1.6.2 → taskai_cli-1.6.5}/taskai/static/editpanel.js +11 -9
  31. {taskai_cli-1.6.2 → taskai_cli-1.6.5}/taskai/views.py +0 -30
  32. taskai_cli-1.6.2/README.md +0 -124
  33. taskai_cli-1.6.2/docs/conf.py +0 -12
  34. taskai_cli-1.6.2/docs/index.rst +0 -8
  35. taskai_cli-1.6.2/docs/requirements.txt +0 -3
  36. taskai_cli-1.6.2/taskai/help_menu.py +0 -70
  37. taskai_cli-1.6.2/taskai/services/repair_database.py +0 -33
  38. {taskai_cli-1.6.2 → taskai_cli-1.6.5}/.github/workflows/publish-to-pypi.yml +0 -0
  39. {taskai_cli-1.6.2 → taskai_cli-1.6.5}/.gitignore +0 -0
  40. {taskai_cli-1.6.2 → taskai_cli-1.6.5}/.readthedocs.yaml +0 -0
  41. {taskai_cli-1.6.2 → taskai_cli-1.6.5}/scripts/bump_version.py +0 -0
  42. {taskai_cli-1.6.2 → taskai_cli-1.6.5}/taskai/config.py +0 -0
  43. {taskai_cli-1.6.2 → taskai_cli-1.6.5}/taskai/llm_models.py +0 -0
  44. {taskai_cli-1.6.2 → taskai_cli-1.6.5}/taskai/services/pomodoro.py +0 -0
  45. {taskai_cli-1.6.2 → taskai_cli-1.6.5}/taskai/services/user_setup.py +0 -0
  46. {taskai_cli-1.6.2 → taskai_cli-1.6.5}/taskai/static/index.html +0 -0
  47. {taskai_cli-1.6.2 → taskai_cli-1.6.5}/taskai/static/style.css +0 -0
  48. {taskai_cli-1.6.2 → taskai_cli-1.6.5}/test/test_cli.py +0 -0
  49. {taskai_cli-1.6.2 → taskai_cli-1.6.5}/test/test_execution.py +0 -0
  50. {taskai_cli-1.6.2 → taskai_cli-1.6.5}/test/test_json_dir_database.py +0 -0
  51. {taskai_cli-1.6.2 → taskai_cli-1.6.5}/test/test_view.py +0 -0
@@ -1,3 +1,87 @@
1
+ # 9-3
2
+
3
+ Browser session — console-driven navigation and selection, mostly beyond the
4
+ original Phase 1 scope (DEVPLAN 1.7 has the durable version):
5
+
6
+ - Synthetic invisible root node (`canvas.js`, `rootNode` / `"__root__"`) —
7
+ never drawn or hit-tested, sits above the real roots as the nav anchor and
8
+ the "whole tree / nothing specific" selection. `selectedNode` is now never
9
+ null: defaults to `rootNode`, and an empty-canvas click selects it.
10
+ - `show all` / bare `show` — client-side console command: refetch `/api/tree`,
11
+ select the root, `fitAll()` (eases the view out until the whole forest fits
12
+ with padding). `show <id|name>` selects + focuses the resolved node without
13
+ opening the edit panel (that's `edit <id|name>`).
14
+ - Tree navigation — `navigate(direction)` + `up`/`down`/`left`/`right` console
15
+ commands. Nodes got a `parent` back-ref; walks up/down/across siblings,
16
+ wraps on both axes. Each move acts like `show <target>`.
17
+ - `.` as a standalone console token → selected node's id (`resolveDotRefs`),
18
+ so `update . --priority 3`, `done .`, `edit .` work. Leaves `a.md` / `3.5`
19
+ alone; errors if nothing real is selected.
20
+ - `hide edit` console command → `closeEditPanel()`, complements `edit <id>`.
21
+ - Up-arrow console history (was the last open Phase 1.6 item) — done earlier
22
+ (`commandHistory` in `console.js`), just now checked off in DEVPLAN.
23
+
24
+ CLI (not browser): added `task undone <id>`, and made recursion on
25
+ `complete`/`done` an opt-in `-r` / `-recursive` flag instead of always-on.
26
+ Resynced the docs for it — `help_menu.py` (`help_general` + `help_examples`,
27
+ which is also the AI's command reference) and the hand-written mentions in
28
+ `docs/getting-started.md` / `docs/item-data.md`. `docs/commands.md` is a
29
+ `literalinclude` of generated help text, so it tracks automatically.
30
+
31
+ Fixed the long-standing `update_item` quirk: it now calls
32
+ `_parse_item_kwargs` before `db.update_item` (like `create_item` does), so
33
+ `update <id> --due_by MM-DD-YYYY` no longer throws. Extended
34
+ `_parse_item_kwargs` in the same pass — maps `depends_on` (`"1,2,3"`) to
35
+ `dependency_ids`, and guarded the `due_by` branch with `isinstance(v, str)`
36
+ so it's idempotent for the recursive re-parse. Edit panel's Due by /
37
+ Depends on fields round-trip now.
38
+
39
+ ---
40
+
41
+ # 8-29
42
+
43
+ Worked the TRIAGE backlog, then built out the docs.
44
+
45
+ TRIAGE fixes:
46
+ - **Critical:** `_find_model_by_stringmatch` inverted `{id: name}` -> `{name:
47
+ id}`, silently collapsing duplicate names to one arbitrary id (so
48
+ update/delete-by-name could hit the wrong item). Now collects every
49
+ fnmatch hit; one resolves, zero -> `None`, 2+ -> `throw_error` listing the
50
+ ids. Also gave `throw_error` a `verbose` flag so it stops dumping
51
+ `args=/kwargs=` on every error.
52
+ - Added `task unlink {parent} {item}` (mirrors `add_link`).
53
+ - Stripped the dead `for record_type in [TodoItem, Comment]` loop in
54
+ `_find_model_by_stringmatch` and the now-unused `Comment` import.
55
+ - `show_examples()` now prints a real `help_examples` string (via `task
56
+ examples`); removed the redundant `task show examples` branch.
57
+
58
+ Browser: soft links (`linked_ids`) now render as "shadow" nodes — a ghost
59
+ copy of the linked item as an extra child under the linking node (~0.92
60
+ alpha, flat, dashed grey border, italic, `↗` glyph, real id). Edge to it is
61
+ dashed grey with a gradient stroke that goes transparent inside either node.
62
+ Selecting/editing a shadow acts on the real item (`itemForNode` -> `realId`).
63
+
64
+ Docs: README synced with `execute_commands` and given a `task setup`
65
+ walkthrough + Web UI section; `help_menu.py` gained `task browser` / `task
66
+ help` and lost its stale "requires id, not name" grouping (everything takes
67
+ id-or-name now). Then turned `docs/` into a real Read the Docs site — Sphinx
68
+ + MyST + Furo, dynamic version, a `builder-inited` hook that dumps
69
+ `help_general` and the provider table to git-ignored `_generated/` files so
70
+ the reference pages can't drift. Pages (all `.md`): index (gif placeholder +
71
+ feature bullets), getting-started, configuration, managing-the-tree,
72
+ item-data, interactive-mode, browser-mode, ai-integration, commands. No
73
+ caveats/notes in user pages — gaps went to TRIAGE (`dependency_ids`
74
+ unreachable from the CLI; interactive-REPL staleness).
75
+
76
+ DEVPLAN: added Phases 4-7 (browser improvements: comments, big description
77
+ editor, keyboard shortcuts + left panel; CLI view expansion + config keys;
78
+ comprehensive testing; advertising).
79
+
80
+ Still open in TRIAGE: multi-word unquoted input (design-blocked), `task
81
+ browser` `[port]`, the two gaps above.
82
+
83
+ ---
84
+
1
85
  # 8-22
2
86
 
3
87
  Found and fixed a real bug from the `litellm` migration earlier today: it
@@ -45,9 +45,11 @@ testing — don't `nuke` it.
45
45
  (methods intentionally take no `self` — called as `Controller.foo(...)`, not
46
46
  instantiated) holds all the CRUD/business logic. `execute_commands(*args,
47
47
  **kwargs)` is one big `match` statement mapping subcommands (`show`,
48
- `create`, `add`, `update`, `move`, `rename`, `delete`, `complete`/`done`,
49
- `comment`, `depend`, `link`, `reorder`, `clear`, `status`, `config`, `ai`,
50
- `pomo`, `repair`, `nuke`, `browser`, ...) to `Controller` calls. There's a
48
+ `create`, `add`, `update`, `move`, `rename`, `delete`,
49
+ `complete`/`done`/`undone`, `comment`, `link`, `reorder`, `clear`,
50
+ `status`, `config`, `ai`, `pomo`, `repair`, `nuke`, `browser`, ...) to
51
+ `Controller` calls. `complete`/`done`/`undone` take an opt-in `-r` /
52
+ `-recursive` flag to apply down the subtree. There's a
51
53
  hand-rolled arg/kwarg parser (`_parse_arg_string`, `_parse_remaining`)
52
54
  instead of `argparse`. `interactive_program()` is the REPL entered when
53
55
  `task` runs with no arguments. The module connects to the database and loads
@@ -57,7 +59,7 @@ is why `taskai/browser.py` reuses `from taskai.cli import db` rather than
57
59
  opening a second connection.
58
60
 
59
61
  **Views.** [taskai/views.py](taskai/views.py): Rich-based tree rendering
60
- (`view_lists`, `view_item`, `view_items`), display format configurable via
62
+ (`view_lists`, `view_item`), display format configurable via
61
63
  `DISPLAY_STRING`/`DISPLAY_COLORS`.
62
64
 
63
65
  **AI services.** [taskai/services/ai.py](taskai/services/ai.py):
@@ -90,20 +92,26 @@ unless you're told to fix them):**
90
92
  name-only-duplicate methods (`show_by_item_name`, `delete_item_by_name`)
91
93
  and several inline `_is_int(...)` dispatch branches in `execute_commands`
92
94
  were deleted outright rather than kept alongside the id path.
93
- - `task show <id1>,<id2>,...` is documented in the README but
95
+ - ~~`task show <id1>,<id2>,...` is documented in the README but
94
96
  `execute_commands`'s `show` case never dispatches to
95
- `Controller.show_items`/`view_items` — there's no wired path to it.
96
- - `Controller.update_item` never calls `Controller._parse_item_kwargs`
97
- (`create_item` does) before handing kwargs to `db.update_item`. Confirmed
98
- effects: `update <id> --due_by MM-DD-YYYY` throws a pydantic validation
99
- error (the string never gets converted to a `datetime`, unlike on
100
- `create`), and `update <id> --depends_on 1,2` silently no-ops (never
101
- remapped to the model's real `dependency_ids` field, so pydantic just
102
- drops it as an unrecognized extra key — no error, no effect). Every other
103
- field (`name`, `description`, `status`, `priority`, `completed`) updates
104
- correctly. The edit panel (1.5) and console both go through `update` and
105
- will hit this. Likely fix: add the same
106
- `kwargs = Controller._parse_item_kwargs(kwargs)` call `create_item` makes.
97
+ `Controller.show_items`/`view_items` — there's no wired path to it.~~
98
+ Removed rather than wired up — `Controller.show_items` and `view_items`
99
+ are gone (CLI audit, see DEVLOG); `task show` only ever takes one target
100
+ now.
101
+ - ~~`Controller.update_item` never calls `Controller._parse_item_kwargs`
102
+ (`create_item` does) before handing kwargs to `db.update_item`, so
103
+ `update <id> --due_by MM-DD-YYYY` threw a pydantic validation error and
104
+ `update <id> --depends_on 1,2` silently no-op'd.~~ **Fixed.**
105
+ `update_item` now runs `kwargs = Controller._parse_item_kwargs(kwargs)`
106
+ before `db.update_item`, same as `create_item`. `_parse_item_kwargs` was
107
+ extended in the same pass: it now also maps the CLI-facing `depends_on`
108
+ (a comma-separated id string, `"1,2,3"`) to the model's real
109
+ `dependency_ids: list[int]` — so `create --depends_on ...` works now too,
110
+ not just `update` — and its `due_by` branch is guarded with
111
+ `isinstance(v, str)` so the helper is idempotent (safe for the
112
+ already-parsed kwargs `update_item`'s `recursive=True` branch passes back
113
+ down). Edit panel's **Due by** and **Depends on** fields now round-trip
114
+ end to end.
107
115
  - **Sync is one-directional: CLI → browser only, not the reverse.**
108
116
  `GET /api/tree` (`browser.py`) reloads from disk (`db.flush()`) on every
109
117
  call, and `canvas.js` refetches on window focus, so browser-side views
@@ -250,10 +258,25 @@ stdlib `http.server` — no new dependency, consistent with "less code."
250
258
 
251
259
  ### 1.4 — DAG view (v2: full graph + interaction)
252
260
 
253
- - [ ] Draw `dependency_ids` and `linked_ids` as a second edge style (dashed
254
- / different color) layered on top of the tree edges — this is what
255
- makes it a DAG rather than just a tree view. Still open — only
256
- parent/child tree edges render today.
261
+ - [~] **`linked_ids` done as "shadow" nodes; `dependency_ids` still
262
+ deferred to 2.0.** A soft link renders as a lightweight *ghost copy*
263
+ of the linked item, placed as an extra child under the linking node
264
+ (`buildShadowNode` in `canvas.js` — non-recursing, carries `realId`
265
+ back to the true item; `buildTree` appends one per `linked_ids`
266
+ entry). It's styled subtly apart from a real placement: ~0.92 alpha,
267
+ no drop shadow, dashed grey border, italic label, an `↗` glyph
268
+ top-right (the one colour accent), and it shows the linked item's
269
+ real id rather than the synthetic shadow id. The parent→shadow edge
270
+ is dashed and uncoloured — grey, the dash pattern alone distinguishes
271
+ it from the solid tree edges — and drawn with a gradient stroke that
272
+ goes fully transparent inside either node's square so it never
273
+ crosses node content (`drawLinkEdges`); solid-edge drawing
274
+ (`drawLines`) skips shadow children. Selecting or editing a shadow
275
+ acts on the real item (`itemForNode` resolves `realId`), so the edit
276
+ panel and `update` commands hit the true record. `dependency_ids` edges are still not drawn — and `task
277
+ depend` was itself removed from the CLI in an earlier audit pass, so
278
+ there's no dependency data being created right now anyway; revisit
279
+ both together in 2.0.
257
280
  - [x] Pan (drag) and zoom (wheel) — done via canvas context transforms
258
281
  (`ctx.translate`/`ctx.scale` + a `view` state object), not SVG
259
282
  `viewBox`, same toolchain reasoning as above. Zoom keeps the point
@@ -268,6 +291,8 @@ stdlib `http.server` — no new dependency, consistent with "less code."
268
291
  break after any mutation). Drawn with the same accent-blue
269
292
  border/thicker stroke as hover. This is exactly the state 1.5's edit
270
293
  menu piggybacks off — not edge highlighting yet, just the node.
294
+ (Later, in 1.7: `selectedNode` became **never-null** — an empty
295
+ selection is now the synthetic `rootNode`, not `null`.)
271
296
  - [x] Color/style nodes by `completed` — soft green fill + border (see
272
297
  `STYLE.colors.nodeFill/BorderDone`), not strike-through/dim like the
273
298
  CLI. `status` ended up as a small orange text label in the node's
@@ -316,9 +341,9 @@ add new visual knobs there, not inline in `draw()`.
316
341
 
317
342
  While wiring this up, confirmed against a throwaway test item (created and
318
343
  deleted, not real data): `name`/`description`/`priority`/`completed` all
319
- update correctly end to end. `due_by` and `depends_on` hit the
320
- `update_item`/`_parse_item_kwargs` bug documented above — left unfixed on
321
- purpose, current call.
344
+ update correctly end to end. `due_by` and `depends_on` originally hit the
345
+ `update_item`/`_parse_item_kwargs` bug documented above — **now fixed** (see
346
+ that entry), so all seven fields round-trip.
322
347
 
323
348
  ### 1.6 — Console
324
349
 
@@ -333,13 +358,58 @@ purpose, current call.
333
358
  response already carries the fresh tree. Also handles the `focus`
334
359
  field `show` commands return: calls `focusOnNode` on that id instead
335
360
  of expecting text output.
336
- - [ ] Up-arrow history — still open, not done.
337
-
338
- At the end of Phase 1: dependency/link edges (1.4) and up-arrow console
339
- history (1.6) are the only pieces left open. The DAG, edit panel, and
340
- console all funnel through one `/api/command` endpoint and one `/api/tree`
341
- read, as planned — that's the "less code" payoff of routing everything
342
- through the existing `Controller`.
361
+ - [x] Up-arrow history — done (`console.js`). `commandHistory` array, every
362
+ submitted line pushed on; `ArrowUp`/`ArrowDown` walk it, an index at
363
+ `length` meaning "not currently browsing history", and `ArrowDown`
364
+ past the end restores an empty input.
365
+
366
+ At the end of Phase 1: the whole 1.1–1.6 checklist is done
367
+ (dependency/link edges (1.4) deferred to 2.0, see above). The DAG, edit
368
+ panel, and console all funnel through one `/api/command` endpoint and one
369
+ `/api/tree` read, as planned — that's the "less code" payoff of routing
370
+ everything through the existing `Controller`. Console-driven canvas
371
+ navigation then grew past the original Phase 1 scope — see 1.7.
372
+
373
+ ### 1.7 — Console-driven navigation & selection (post-plan, beyond original scope)
374
+
375
+ Grew out of Phase 1's console + selection machinery; none of this was in
376
+ the original checklist.
377
+
378
+ - [x] **Synthetic invisible root node** (`canvas.js`, `rootNode` /
379
+ `"__root__"`). Never added to `nodes`, so never drawn, hit-tested, or
380
+ bordered. It's the nav anchor above the real root items and the
381
+ "nothing specific / the whole tree" selection. `selectedNode` is now
382
+ **never null** — it defaults to `rootNode`, and a click on empty
383
+ canvas selects `rootNode` rather than clearing the selection.
384
+ `applyTree` re-parents it over the freshly-built roots and parks it
385
+ one `ySpacing` above them on every refresh.
386
+ - [x] **`show all` / bare `show`** (console, client-side). Refetches
387
+ `/api/tree`, selects the synthetic root, and calls `fitAll()` — eases
388
+ the view out until every real node fits on screen with padding,
389
+ clamped to `STYLE.zoom` bounds.
390
+ - [x] **`show <id|name>`** (console, client-side). POSTs the command,
391
+ applies the returned tree, then selects + `focusOnNode`s the resolved
392
+ node. Deliberately does *not* open the edit panel — that's
393
+ `edit <id|name>`, mirroring the canvas's single-click vs. double-click
394
+ split.
395
+ - [x] **Tree navigation** — `navigate(direction)` in `canvas.js`, wired to
396
+ `up` / `down` / `left` / `right` console commands. Nodes carry a
397
+ `parent` back-reference (set in `buildTree` / `applyTree`) so the walk
398
+ goes up as well as down: `down` → first child, `up` → parent,
399
+ `left`/`right` → previous/next sibling. Wraps on both axes — past the
400
+ last sibling loops to the first; `down` past the deepest leaf and `up`
401
+ from `rootNode` loop between the top and the deepest first-child leaf.
402
+ Each move behaves like a `show <target>` (select + ease/zoom; `fitAll`
403
+ when the target is `rootNode`).
404
+ - [x] **`.` = the selected node** (`resolveDotRefs` in `console.js`). A bare
405
+ `.` token in any console command is swapped for `selectedNode.id`
406
+ before dispatch, so `update . --priority 3`, `done .`, `edit .` act on
407
+ the current selection. Only matches a standalone `.` (whitespace or
408
+ string end on both sides), so `a.md` / `3.5` are untouched; errors if
409
+ `.` is used with nothing real selected.
410
+ - [x] **`hide edit`** (console) → `closeEditPanel()` in `editpanel.js`,
411
+ collapsing the right panel and restoring canvas width. Complements the
412
+ existing `edit <id|name>` that opens it.
343
413
 
344
414
  ---
345
415
 
@@ -459,7 +529,10 @@ like Flash-Lite.
459
529
  - [x] Updated README's Config section to match the new `AI_MODEL`
460
530
  `provider/model` shape and point at `task setup`.
461
531
 
462
- ### 2.4 — `task ai agent <prompt>` (later — real tool-calling loop)
532
+ ### 2.4 — `task ai agent <prompt>` (deferred to 2.0 — real tool-calling loop)
533
+
534
+ **Deferred to 2.0.** Out of scope for the current polish pass; revisit as
535
+ part of the larger 2.0 rework rather than squeezing it in here.
463
536
 
464
537
  A separate entry point, not a replacement for `task ai`. `task ai <prompt>`
465
538
  stays the fast, ungated, one-shot-plan-and-execute path from 2.1-2.3;
@@ -501,15 +574,109 @@ Re-scope this section before starting 2.4.
501
574
  `editmenu.js`) and delete anything exploratory left over from getting
502
575
  the DAG layout working. Still no bundler — just multiple `<script>`
503
576
  tags loaded in order.
504
- - [ ] **Minimalist docs.** A short "Web UI" section in the README (how to
505
- run `task web`, one screenshot) covers most of it; only split into a
506
- separate `docs/` page if the README starts feeling long. Keep the
507
- "less code" principle applied to prose too — this doesn't need to be
508
- exhaustive.
577
+ - [~] **Docs.** README is synced with `execute_commands` (command list,
578
+ `task ai` flags, Web UI section, `task setup` walkthrough);
579
+ `help_menu.py` lists `task browser` / `task help`, and its stale
580
+ "requires id, not name" grouping was corrected (every item-taking
581
+ command resolves id-or-name via `_resolve_item` now). Grew past a
582
+ README-only scope into a proper Read the Docs site under `docs/`
583
+ (Sphinx + MyST + Furo).
584
+ **Built:** `conf.py` rebuilt (dynamic version from pyproject, Furo,
585
+ copybutton, sphinx-design; a `builder-inited` hook dumps `help_general`
586
+ and the `PROVIDER_ENV_VARS` table to git-ignored files under
587
+ `docs/_generated/` so the reference/config content can't drift from
588
+ source). Pages, all `.md`: `index` (gif placeholder + "what you can
589
+ do" + toctree), `getting-started`, `configuration`,
590
+ `managing-the-tree`, `item-data`, `interactive-mode`, `browser-mode`,
591
+ `ai-integration`, `commands` (`literalinclude` of the generated help
592
+ text). No "notes"/caveats in any user page — gaps go to TRIAGE
593
+ instead. README links to the site.
594
+ **Still open:** replace `docs/_static/demo.gif` placeholder with a real
595
+ recording; confirm the RTD project slug (assumed `taskai` in `conf.py`
596
+ `html_baseurl` + README); explanation/architecture pages; polish
597
+ (screenshots for browser-mode, custom 404, OpenGraph cards, CI
598
+ `linkcheck`, tested examples, changelog).
599
+ - [x] **`help_menu.py` drift from `execute_commands`.** The CLI gained
600
+ `task undone <id>` and an opt-in `-r` / `-recursive` flag on
601
+ `complete` / `done` (recursion used to be unconditional). Resynced:
602
+ `help_general` and `help_examples` in `help_menu.py` (also the AI's
603
+ verbatim command reference), plus the two hand-written mentions in
604
+ `docs/getting-started.md` and `docs/item-data.md`. `docs/commands.md`
605
+ needs no edit — it `literalinclude`s the `builder-inited`-generated
606
+ dump of `help_general`.
509
607
  - [ ] **UX pass.** Empty/loading state for the DAG when a user has no tasks
510
608
  yet (currently the app would just render nothing); a keyboard shortcut
511
609
  to toggle the console (e.g. backtick); consistent spacing/typography
512
- in `style.css`; visual legend distinguishing tree edges from
513
- dependency/link edges.
610
+ in `style.css`. (Edge legend dropped — depended on 1.4's dependency/
611
+ link edges, now deferred to 2.0.)
514
612
  - [ ] Re-check the Phase 0 fixes are still holding once the web UI is
515
613
  exercising more command paths than the CLI alone did.
614
+
615
+ ---
616
+
617
+ ## Phase 4 — Browser view improvements
618
+
619
+ Builds on Phase 1's canvas / edit panel / console. Still plain HTML/CSS/JS, no
620
+ framework, everything routed through the existing `/api/tree` + `/api/command`
621
+ endpoints.
622
+
623
+ - [ ] **Show comments.** Items carry `comment_ids` but the browser never
624
+ surfaces them. Render an item's comments in the edit panel — read-only
625
+ list at minimum; adding one posts `comment <id> <text>` through
626
+ `/api/command` like every other field. Consider a comment-count
627
+ affordance on the canvas node itself.
628
+ - [ ] **Much larger description editor.** The `description` field in the edit
629
+ panel is a small single-line-ish input today. Make it a real multi-line
630
+ textarea that dominates the panel (large fixed height or auto-grow), so
631
+ the panel is usable for actual note-taking — likely widen the panel
632
+ itself while a node is selected.
633
+ - [ ] **Keyboard shortcuts + a shortcuts panel.** Add real key bindings
634
+ (toggle console, toggle edit panel, complete / delete the selected
635
+ node, deselect, focus a search box, zoom/pan, …) and a **left-hand
636
+ panel listing them**, mirroring the right-hand edit panel and
637
+ collapsible the same way. Follow the existing `STYLE` object +
638
+ collapsible-panel machinery (`setRightPanelWidth`); this adds a left
639
+ equivalent. Supersedes the single console-toggle shortcut noted in
640
+ Phase 3's UX pass.
641
+
642
+ ---
643
+
644
+ ## Phase 5 — CLI view
645
+
646
+ - [ ] **Expand what `task show` renders, and its options.** Exact scope TBD —
647
+ needs a working session with Alex to pin down. Candidates: filter by
648
+ status / priority / completion, depth limits, flat vs. tree layout,
649
+ sort order, inline comments / links, format and colour toggles. Prompt
650
+ before implementing.
651
+ - [ ] **New view-settings config keys.** Extend `CLIConfig` (today just
652
+ `DISPLAY_STRING` / `DISPLAY_COLORS`) with keys backing whatever the
653
+ expanded view supports; document them in `docs/configuration.md` and
654
+ `help_menu.py` alongside the existing ones.
655
+
656
+ ---
657
+
658
+ ## Phase 6 — Comprehensive testing & bugfixing
659
+
660
+ - [ ] **Broaden the test suite.** Currently 7 tests across `test_cli.py` /
661
+ `test_execution.py` / `test_json_dir_database.py` / `test_view.py`.
662
+ Cover every `execute_commands` branch, id/name resolution (including
663
+ the multi-match error path), `_parse_item_kwargs`, the browser
664
+ endpoints (`/api/tree`, `/api/command`), and the AI command-execution
665
+ loop with a mocked LLM.
666
+ - [ ] **Fix what the tests surface**, and clear the still-open TRIAGE items
667
+ as they come up (multi-word unquoted input, `task browser` `[port]`,
668
+ `dependency_ids` reachability, interactive-REPL staleness).
669
+ - [ ] **Wire CI.** `pytest` on every PR, plus `sphinx-build -W` +
670
+ `linkcheck` for the docs.
671
+
672
+ ---
673
+
674
+ ## Phase 7 — Advertising
675
+
676
+ - [ ] Get the docs site live: confirm the Read the Docs slug, record the
677
+ `docs/_static/demo.gif` terminal demo.
678
+ - [ ] Polish the PyPI listing — `pyproject.toml` has an empty `description`
679
+ and no keywords / classifiers / project URLs.
680
+ - [ ] Write a short "show and tell" (what it is, the everything-is-an-item
681
+ model, the AI layer, the canvas view) built around the gif, and decide
682
+ on channels (Show HN, r/commandline, r/productivity, GitHub topics).
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: taskai-cli
3
- Version: 1.6.2
3
+ Version: 1.6.5
4
4
  Author-email: Alex Paskal <alexcpaskal@gmail.com>
5
5
  Requires-Python: >=3.12
6
6
  Requires-Dist: fastapi>=0.141.1
@@ -15,6 +15,8 @@ Description-Content-Type: text/markdown
15
15
 
16
16
  A command-line task manager with AI features.
17
17
 
18
+ 📖 **Full documentation:** <https://taskai.readthedocs.io>
19
+
18
20
  ```bash
19
21
  pip install taskai-cli
20
22
  ```
@@ -32,10 +34,11 @@ task setup
32
34
 
33
35
  ```
34
36
  task interactive mode
37
+ task help show every command
38
+ task examples worked command sequences for common workflows
35
39
 
36
40
  task show all show everything
37
41
  task show <id|name> show a specific item
38
- task show <id1>,<id2>,... show multiple items
39
42
 
40
43
  task create <name> create a top-level item
41
44
  task add <parent> <name> add a child item
@@ -44,27 +47,31 @@ task rename <id> <new name> rename an item
44
47
  task move <item> <new parent> reparent an item
45
48
  task complete <id> mark complete (recursive)
46
49
  task delete <id|name> delete by id or name
47
- task delete completed delete all completed items
50
+ task clear delete all completed items
48
51
  task clear <parent> delete completed under a parent
49
52
 
50
53
  task comment <id> <text> add a comment
51
- task depend <src_id> <dst_id> src depends on dst
52
- task link <parent> <item> soft-link two items
54
+ task link <parent> <item> soft-link an item under a second parent
55
+ task unlink <parent> <item> remove a soft-link
53
56
  task reorder <id1> before|after <id2>
54
57
 
55
58
  task status <id> <text> set a status string
56
59
  task pomo <on_mins> <off_mins> pomodoro timer
57
60
 
58
61
  task ai <prompt> natural language → commands
62
+ --context <path[,path...]> fold file contents into the prompt
63
+ --reasoning <level> model thinking effort: minimal|low|medium|high|disable|none
59
64
  task ai headstart <id> AI suggests next step, saved as comment
60
65
 
66
+ task browser launch the web UI (see below)
67
+
61
68
  task config show list current config
62
69
  task config set <key> <value> set a config value
63
70
  task config get <key> get a config value
64
71
  task config pop <key> remove a config value
65
72
 
66
73
  task repair repair the database
67
- task nuke delete all data
74
+ task nuke delete all data (asks to confirm)
68
75
  ```
69
76
 
70
77
  ### Item fields
@@ -78,44 +85,68 @@ Pass any of these as `--field value` to `create`, `add`, or `update`:
78
85
  | `priority` | integer | `--priority 2` |
79
86
  | `status` | string | `--status "in progress"` |
80
87
  | `completed` | bool | `--completed true` |
81
- | `depends_on` | comma-separated ids | `--depends_on 3,7` |
82
88
 
83
89
  ---
84
90
 
85
91
  ## Config
86
92
 
87
- AI features require a model, set as a `provider/model` string (via [litellm](https://github.com/BerriAI/litellm)),
88
- plus that provider's credentials set as environment variables (e.g. `GEMINI_API_KEY`, `OPENAI_API_KEY`).
89
- `task setup` will walk you through picking a provider and model and tell you which env vars it needs.
93
+ AI features need a model. `task setup` walks you through choosing a provider
94
+ and model, then tells you which environment variable(s) to set:
95
+
96
+ ```text
97
+ $ task setup
98
+ Beginning setup
99
+ 1. openai
100
+ 2. anthropic
101
+ 3. gemini
102
+ 4. vertex_ai
103
+ 5. groq
104
+ ...
105
+ 20. ollama
106
+
107
+ Select a provider (number or name): 3
108
+ 1. gemini-3.7-flash
109
+ 2. gemini-3.1-pro-preview
110
+ 3. gemini-3.6-flash
111
+ 4. gemini-3.5-flash-lite
112
+ 5. gemini-2.5-pro
113
+
114
+ Select a model for 'gemini' (number or name): 1
115
+ Storing: gemini/gemini-3.7-flash
116
+ Make sure these environment variables are set:
117
+ GEMINI_API_KEY
118
+ Setup complete! Use 'task config set|get|list' to interact with your configuration options
119
+ ```
120
+
121
+ Either prompt also accepts free-typed text, so you can pick a model newer than
122
+ the built-in menu.
123
+
124
+ Or set it directly — a `provider/model` string, using
125
+ [litellm](https://github.com/BerriAI/litellm)'s naming:
90
126
 
91
127
  ```bash
92
- task config set AI_MODEL gemini/gemini-2.0-flash
128
+ task config set AI_MODEL <provider>/<model> # e.g. gemini/gemini-3.7-flash
93
129
  ```
94
130
 
95
131
  ---
96
132
 
97
- ## Example
133
+ ## Web UI
98
134
 
99
- ```
100
- task create "Today"
101
- task add "Today" "Morning run"
102
- task add "Today" "Review pull requests" --status "blocked"
103
- task add "Today" "Call dentist" --due_by 08-02-2026
104
- task show "Today"
105
- task complete 4
106
- task show "Today"
107
- task exit
135
+ ```bash
136
+ task browser
108
137
  ```
109
138
 
110
- Or:
139
+ Launches a local web server with a canvas view of your item tree:
111
140
 
112
- ```bash
113
- task ai "add a task called 'Reply to Alex' under Today, and mark the dentist task as done"
114
- ```
141
+ - **pan / zoom** the graph; completed items are tinted green, and soft-links
142
+ (`task link`) show as dashed "shadow" copies under their host item
143
+ - **click a node** to open an edit panel — each field writes back immediately,
144
+ there's no save button
145
+ - **console** at the bottom for typing raw `task` commands against the same data
115
146
 
116
147
  ---
117
148
 
118
- ## Another Example
149
+ ## Examples
119
150
 
120
151
  ```bash
121
152
  task create "Launch website"
@@ -134,4 +165,12 @@ task ai headstart 3
134
165
  # mark something done and clean up
135
166
  task complete 2
136
167
  task clear "Launch website"
137
- ```
168
+ ```
169
+
170
+ Or drive it entirely from a prompt:
171
+
172
+ ```bash
173
+ task ai "add a task called 'Reply to Alex' under Launch website, and mark the hosting task as done"
174
+ ```
175
+
176
+ Run `task examples` for more worked sequences.