taskai-cli 1.9.0__tar.gz → 1.9.26__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.9.26/.github/workflows/test.yml +43 -0
- taskai_cli-1.9.26/CHANGELOG.md +110 -0
- taskai_cli-1.9.26/PHASE_1_RELEASE.md +344 -0
- {taskai_cli-1.9.0 → taskai_cli-1.9.26}/PKG-INFO +1 -1
- taskai_cli-1.9.26/docs/_static/demo-script.md +39 -0
- taskai_cli-1.9.26/docs/browser-mode.md +71 -0
- {taskai_cli-1.9.0 → taskai_cli-1.9.26}/docs/conf.py +2 -3
- {taskai_cli-1.9.0 → taskai_cli-1.9.26}/docs/index.md +4 -2
- {taskai_cli-1.9.0 → taskai_cli-1.9.26}/pyproject.toml +1 -1
- {taskai_cli-1.9.0 → taskai_cli-1.9.26}/taskai/browser.py +21 -1
- {taskai_cli-1.9.0 → taskai_cli-1.9.26}/taskai/cli.py +6 -5
- taskai_cli-1.9.26/taskai/dates.py +47 -0
- {taskai_cli-1.9.0 → taskai_cli-1.9.26}/taskai/filters.py +2 -4
- {taskai_cli-1.9.0 → taskai_cli-1.9.26}/taskai/help_menu.py +4 -2
- {taskai_cli-1.9.0 → taskai_cli-1.9.26}/taskai/models.py +5 -0
- {taskai_cli-1.9.0 → taskai_cli-1.9.26}/taskai/static/camera.js +11 -6
- {taskai_cli-1.9.0 → taskai_cli-1.9.26}/taskai/static/canvas.js +70 -4
- {taskai_cli-1.9.0 → taskai_cli-1.9.26}/taskai/static/config.js +22 -5
- {taskai_cli-1.9.0 → taskai_cli-1.9.26}/taskai/static/console.js +4 -1
- {taskai_cli-1.9.0 → taskai_cli-1.9.26}/taskai/static/editpanel.js +4 -0
- {taskai_cli-1.9.0 → taskai_cli-1.9.26}/taskai/static/graph.js +40 -15
- taskai_cli-1.9.26/taskai/static/navigation.js +83 -0
- {taskai_cli-1.9.0 → taskai_cli-1.9.26}/taskai/static/render.js +38 -1
- {taskai_cli-1.9.0 → taskai_cli-1.9.26}/taskai/static/shortcuts.js +59 -19
- {taskai_cli-1.9.0 → taskai_cli-1.9.26}/taskai/static/style.css +54 -43
- taskai_cli-1.9.26/test/test_chains.py +311 -0
- {taskai_cli-1.9.0 → taskai_cli-1.9.26}/test/test_cli.py +45 -0
- taskai_cli-1.9.0/docs/browser-mode.md +0 -51
- taskai_cli-1.9.0/taskai/static/navigation.js +0 -44
- {taskai_cli-1.9.0 → taskai_cli-1.9.26}/.github/workflows/publish-to-pypi.yml +0 -0
- {taskai_cli-1.9.0 → taskai_cli-1.9.26}/.gitignore +0 -0
- {taskai_cli-1.9.0 → taskai_cli-1.9.26}/.readthedocs.yaml +0 -0
- {taskai_cli-1.9.0 → taskai_cli-1.9.26}/DEVLOG.md +0 -0
- {taskai_cli-1.9.0 → taskai_cli-1.9.26}/DEVPLAN.md +0 -0
- {taskai_cli-1.9.0 → taskai_cli-1.9.26}/README.md +0 -0
- {taskai_cli-1.9.0 → taskai_cli-1.9.26}/TRIAGE.md +0 -0
- {taskai_cli-1.9.0 → taskai_cli-1.9.26}/docs/.gitignore +0 -0
- {taskai_cli-1.9.0 → taskai_cli-1.9.26}/docs/_static/.gitkeep +0 -0
- {taskai_cli-1.9.0 → taskai_cli-1.9.26}/docs/ai-integration.md +0 -0
- {taskai_cli-1.9.0 → taskai_cli-1.9.26}/docs/commands.md +0 -0
- {taskai_cli-1.9.0 → taskai_cli-1.9.26}/docs/configuration.md +0 -0
- {taskai_cli-1.9.0 → taskai_cli-1.9.26}/docs/getting-started.md +0 -0
- {taskai_cli-1.9.0 → taskai_cli-1.9.26}/docs/interactive-mode.md +0 -0
- {taskai_cli-1.9.0 → taskai_cli-1.9.26}/docs/item-data.md +0 -0
- {taskai_cli-1.9.0 → taskai_cli-1.9.26}/docs/managing-the-tree.md +0 -0
- {taskai_cli-1.9.0 → taskai_cli-1.9.26}/docs/requirements.txt +0 -0
- {taskai_cli-1.9.0 → taskai_cli-1.9.26}/scripts/bump_version.py +0 -0
- {taskai_cli-1.9.0 → taskai_cli-1.9.26}/taskai/config.py +0 -0
- {taskai_cli-1.9.0 → taskai_cli-1.9.26}/taskai/errors.py +0 -0
- {taskai_cli-1.9.0 → taskai_cli-1.9.26}/taskai/json_dir_database.py +0 -0
- {taskai_cli-1.9.0 → taskai_cli-1.9.26}/taskai/llm_models.py +0 -0
- {taskai_cli-1.9.0 → taskai_cli-1.9.26}/taskai/services/ai.py +0 -0
- {taskai_cli-1.9.0 → taskai_cli-1.9.26}/taskai/services/pomodoro.py +0 -0
- {taskai_cli-1.9.0 → taskai_cli-1.9.26}/taskai/services/repair_database.py +0 -0
- {taskai_cli-1.9.0 → taskai_cli-1.9.26}/taskai/services/user_setup.py +0 -0
- {taskai_cli-1.9.0 → taskai_cli-1.9.26}/taskai/static/index.html +0 -0
- {taskai_cli-1.9.0 → taskai_cli-1.9.26}/taskai/views.py +0 -0
- {taskai_cli-1.9.0 → taskai_cli-1.9.26}/test/test_execution.py +0 -0
- {taskai_cli-1.9.0 → taskai_cli-1.9.26}/test/test_json_dir_database.py +0 -0
- {taskai_cli-1.9.0 → taskai_cli-1.9.26}/test/test_view.py +0 -0
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
name: Tests
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
pull_request:
|
|
6
|
+
|
|
7
|
+
jobs:
|
|
8
|
+
pytest:
|
|
9
|
+
name: pytest
|
|
10
|
+
runs-on: ubuntu-latest
|
|
11
|
+
steps:
|
|
12
|
+
- uses: actions/checkout@v6
|
|
13
|
+
- name: Set up Python
|
|
14
|
+
uses: actions/setup-python@v6
|
|
15
|
+
with:
|
|
16
|
+
python-version: "3.12"
|
|
17
|
+
- name: Install
|
|
18
|
+
run: |
|
|
19
|
+
python -m pip install --upgrade pip
|
|
20
|
+
pip install -e .
|
|
21
|
+
pip install pytest
|
|
22
|
+
- name: Run tests
|
|
23
|
+
run: python -m pytest -q
|
|
24
|
+
|
|
25
|
+
docs:
|
|
26
|
+
name: docs (build + linkcheck)
|
|
27
|
+
runs-on: ubuntu-latest
|
|
28
|
+
steps:
|
|
29
|
+
- uses: actions/checkout@v6
|
|
30
|
+
- name: Set up Python
|
|
31
|
+
uses: actions/setup-python@v6
|
|
32
|
+
with:
|
|
33
|
+
python-version: "3.12"
|
|
34
|
+
- name: Install docs dependencies
|
|
35
|
+
run: pip install -r docs/requirements.txt
|
|
36
|
+
# -W: warnings fail the build - this currently includes the known
|
|
37
|
+
# docs/_static/demo.gif placeholder (see PHASE_1_RELEASE.md), so this
|
|
38
|
+
# job is red until that's swapped for a real recording. Intentional:
|
|
39
|
+
# a known, tracked gap is exactly what this check should catch.
|
|
40
|
+
- name: Build docs (warnings as errors)
|
|
41
|
+
run: sphinx-build -b html -W docs docs/_build/html
|
|
42
|
+
- name: Check external links
|
|
43
|
+
run: sphinx-build -b linkcheck docs docs/_build/linkcheck
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
Notable changes, newest first. Loosely follows [Keep a
|
|
4
|
+
Changelog](https://keepachangelog.com/); dates are UTC, from the commit
|
|
5
|
+
history. Versions before 1.6.6 predate this file and aren't reconstructed
|
|
6
|
+
here in detail — see `DEVLOG.md` for the full engineering history back to
|
|
7
|
+
the project's start.
|
|
8
|
+
|
|
9
|
+
## [Unreleased]
|
|
10
|
+
|
|
11
|
+
The v1 release polish pass — see `PHASE_1_RELEASE.md` for the full working
|
|
12
|
+
list this is drawn from.
|
|
13
|
+
|
|
14
|
+
### Added
|
|
15
|
+
- Per-item DAG node color override (`color` field), and per-status-string
|
|
16
|
+
color mapping via `task config set STATUS_COLORS=...`
|
|
17
|
+
- `due_by` shown directly on DAG nodes
|
|
18
|
+
- `task browser [port]`
|
|
19
|
+
- Multiple accepted `due_by` formats (ISO, `MM/DD/YYYY`, `Dec 31, 2026`,
|
|
20
|
+
etc.) and the relative keywords `today`/`tomorrow`, both when setting a
|
|
21
|
+
value and in filters (`task show 'due_by=today'`)
|
|
22
|
+
- Configuration now reaches the browser (`GET /api/style`) — the
|
|
23
|
+
foundation the node-color and status-color features above build on
|
|
24
|
+
- Up/down arrows fall back to walking a chain when there's no real tree
|
|
25
|
+
relationship in that direction, instead of dead-ending
|
|
26
|
+
- DAG empty-state message when there are no items yet
|
|
27
|
+
- Test coverage for the chain feature (previously had none)
|
|
28
|
+
- CI: `pytest` and a docs build/linkcheck on every push and PR
|
|
29
|
+
|
|
30
|
+
### Changed
|
|
31
|
+
- **DAG orientation flipped:** the tree now grows rightward with siblings
|
|
32
|
+
stacking downward (previously grew downward with siblings spread
|
|
33
|
+
right) — arrow-key directions rotated to match
|
|
34
|
+
- Deleting the selected node in the browser now restores the previously
|
|
35
|
+
selected node instead of always jumping to the whole-tree view
|
|
36
|
+
- `task next` now focuses the node it just created in the browser
|
|
37
|
+
|
|
38
|
+
### Fixed
|
|
39
|
+
- Unquoted multi-word input across `create`/`add`/`rename` no longer
|
|
40
|
+
silently truncates
|
|
41
|
+
|
|
42
|
+
## [1.9.0] - 2026-09-14
|
|
43
|
+
|
|
44
|
+
Chain data integrity and a full CLI command surface for chains
|
|
45
|
+
(`is_chain_head`/`prev_chain_id`/`next_chain_id` and the DAG rendering for
|
|
46
|
+
them shipped in the browser work below this).
|
|
47
|
+
|
|
48
|
+
### Added
|
|
49
|
+
- `task chain <prev> <node>` — link two existing items into a chain,
|
|
50
|
+
popping `node` off its current parent first if it has one
|
|
51
|
+
- `task unchain <node>` — detach an item from its chain without deleting
|
|
52
|
+
it; it becomes a child of the chain's head's parent
|
|
53
|
+
- `task delete <id> -chain` — delete an entire chain in one shot, from
|
|
54
|
+
whichever link you target
|
|
55
|
+
- `task clear` now reaches items chained off the thing being cleared, not
|
|
56
|
+
just its direct children
|
|
57
|
+
|
|
58
|
+
### Fixed
|
|
59
|
+
- Deleting a chain's head used to orphan the rest of the chain (the
|
|
60
|
+
parent's `child_ids` kept pointing at the deleted id)
|
|
61
|
+
- `task show all` no longer lists every non-head chain member as a
|
|
62
|
+
spurious top-level item
|
|
63
|
+
- Linking an item already mid-chain into a different chain no longer
|
|
64
|
+
corrupts both
|
|
65
|
+
|
|
66
|
+
### Removed
|
|
67
|
+
- The stored `is_chain_head` field — it's derived now
|
|
68
|
+
(`prev_chain_id is None and next_chain_id is not None`), removing a
|
|
69
|
+
class of "forgot to update the flag" bugs
|
|
70
|
+
|
|
71
|
+
## [1.8.1] - 2026-09-10
|
|
72
|
+
|
|
73
|
+
### Fixed
|
|
74
|
+
- Zoom behavior in the browser DAG
|
|
75
|
+
- `show` filters persisting correctly through a delete
|
|
76
|
+
- Edit panel focus handling, including an `Esc`-related focus bug
|
|
77
|
+
- Assorted minor browser UX fixes
|
|
78
|
+
|
|
79
|
+
## [1.8.0] - 2026-09-09
|
|
80
|
+
|
|
81
|
+
### Added
|
|
82
|
+
- Attribute filters for `task show` (`task show 'priority>=2'
|
|
83
|
+
'due_by<10-01-2026'`), in both the CLI and the browser
|
|
84
|
+
|
|
85
|
+
## [1.7.1] - 2026-09-09
|
|
86
|
+
|
|
87
|
+
### Added
|
|
88
|
+
- Per-parent "last visited child" memory for `down` navigation in the
|
|
89
|
+
browser DAG
|
|
90
|
+
|
|
91
|
+
### Changed
|
|
92
|
+
- Left/right navigation no longer wraps within a parent's direct
|
|
93
|
+
children - it steps across the whole depth level instead
|
|
94
|
+
- `Esc` no longer moves the camera
|
|
95
|
+
|
|
96
|
+
### Fixed
|
|
97
|
+
- Up/down navigation no longer wraps around at the top/bottom of the tree
|
|
98
|
+
- Various edit-panel interaction bugs
|
|
99
|
+
|
|
100
|
+
## [1.7.0] - 2026-09-03
|
|
101
|
+
|
|
102
|
+
### Added
|
|
103
|
+
- Keyboard shortcuts and a shortcuts reference panel in the browser
|
|
104
|
+
|
|
105
|
+
## [1.6.6] and earlier
|
|
106
|
+
|
|
107
|
+
Everything from the initial CLI (tree-structured items, no separate
|
|
108
|
+
"lists" concept), through the AI layer's migration to `litellm`, to the
|
|
109
|
+
first browser DAG view (canvas rendering, pan/zoom, the edit panel, and
|
|
110
|
+
the command console). See `DEVLOG.md` for the detailed history.
|
|
@@ -0,0 +1,344 @@
|
|
|
1
|
+
# Phase 1 Release — Punch List
|
|
2
|
+
|
|
3
|
+
All the major features for v1 are done (browser DAG with chains, `task ai`
|
|
4
|
+
on `litellm`, filters, comments, keyboard shortcuts, the chain CLI). This is
|
|
5
|
+
what's left before cutting the release — pulled from the open items in
|
|
6
|
+
[DEVPLAN.md](DEVPLAN.md) and [TRIAGE.md](TRIAGE.md) plus new scope Alex
|
|
7
|
+
added directly to this list, filtered down to what's actually in scope for
|
|
8
|
+
"ready to ship v1," not the longer-term roadmap. Real new features
|
|
9
|
+
(dependency edges in the DAG, `task ai agent`, a fully expanded `task show`
|
|
10
|
+
view) are called out at the bottom as explicitly **not** v1 — they're
|
|
11
|
+
staying in DEVPLAN/TRIAGE, not duplicated here.
|
|
12
|
+
|
|
13
|
+
---
|
|
14
|
+
|
|
15
|
+
## Small polish
|
|
16
|
+
|
|
17
|
+
- [x] **`task browser` has no `[port]` override.** (TRIAGE / Low)
|
|
18
|
+
`Controller.browser_service` hardcodes uvicorn's default port.
|
|
19
|
+
Original DEVPLAN scoping (1.1) called for `task web [port]`; small,
|
|
20
|
+
contained fix. `task browser {port}`, defaults to 8000.
|
|
21
|
+
- [x] **DAG empty/loading state.** (DEVPLAN Phase 3) A user with no tasks
|
|
22
|
+
yet just sees a blank canvas — no "nothing here yet" state. Drawn in
|
|
23
|
+
screen space (stays centered regardless of pan/zoom) whenever
|
|
24
|
+
`graph.nodes.length === 0` — covers both "still loading" and
|
|
25
|
+
"genuinely empty" with one message rather than adding a separate
|
|
26
|
+
loading-flag/spinner for what's normally a near-instant local fetch.
|
|
27
|
+
- [x] **`style.css` spacing/typography consistency pass.** (DEVPLAN Phase 3)
|
|
28
|
+
Never done; low effort, worth a once-over before screenshots go in
|
|
29
|
+
the docs/listing. Pulled the repeated color/font literals (border,
|
|
30
|
+
muted/primary/label text, accent blue, input background, both font
|
|
31
|
+
stacks — each duplicated 2-9x) into `:root` custom properties;
|
|
32
|
+
normalized the one real inconsistency found, an odd `12.5px` body
|
|
33
|
+
text size next to `13px` used everywhere else for the same kind of
|
|
34
|
+
text. Deliberately left spacing/radius values (8/10/6/5px) alone —
|
|
35
|
+
those read as intentionally graduated by element scale, not
|
|
36
|
+
erroneous, and I can't visually verify a change without screenshots.
|
|
37
|
+
- [x] **Re-check the Phase 0 fixes are still holding.** (DEVPLAN Phase 3)
|
|
38
|
+
Written when the web UI was new; now that chains + the new CLI
|
|
39
|
+
surface exercise a lot more of `execute_commands`, worth a quick
|
|
40
|
+
re-pass rather than assuming. All 5 confirmed intact via source
|
|
41
|
+
inspection: `ai_prompt` (not the raw prompt) is what's sent to the
|
|
42
|
+
LLM; `_add_info`'s visited-set bug stays fixed; the parsed command
|
|
43
|
+
list from `task ai` is actually executed
|
|
44
|
+
(`services/ai.py`'s loop over `execute_commands`); `execute_commands`'s
|
|
45
|
+
except block has no `raise e` ahead of the friendly `throw_error`
|
|
46
|
+
path; `views.py` no longer calls the nonexistent `db.read`/`db.items`.
|
|
47
|
+
No live LLM call made (didn't want to spend API quota for this) —
|
|
48
|
+
everything else checked statically.
|
|
49
|
+
- [x] **Delete should shift focus intelligently, not just to the root.**
|
|
50
|
+
After deleting the selected node, restore selection to whatever was
|
|
51
|
+
focused *before* it (needs at least a one-deep "previously selected"
|
|
52
|
+
memory, since `state.selectedNode` today just gets re-resolved to
|
|
53
|
+
`rootNode` once the deleted id no longer exists in the fresh graph)
|
|
54
|
+
— fall back to the synthetic root only if there's nothing to return
|
|
55
|
+
to. `state.previousSelectedId` (canvas.js), updated by `selectNode`
|
|
56
|
+
any time the selection actually changes — so this falls out of the
|
|
57
|
+
same general mechanism for every navigation, not something
|
|
58
|
+
delete-specific.
|
|
59
|
+
- [x] **`next` should focus the node it just created.** Today, running
|
|
60
|
+
`next <prev> <name>` through the console applies the fresh tree but
|
|
61
|
+
doesn't select/focus anything — you have to go find it. `show`
|
|
62
|
+
already gets special server-side `focus`-id handling in
|
|
63
|
+
`POST /api/command` (`taskai/browser.py`); extending that same
|
|
64
|
+
`focus` response to `next` (the newly-appended item's id) is the
|
|
65
|
+
consistent way to do this, rather than a client-side before/after-id
|
|
66
|
+
diff like `addNodeAndEdit`'s shortcut does for `a`. Server-side:
|
|
67
|
+
diffs `db.get_item_ids()` before/after running `next` through
|
|
68
|
+
`execute_commands`. Found and fixed a related inconsistency in
|
|
69
|
+
passing: the console's *generic* command fallback (any command not
|
|
70
|
+
specially handled, like `next` typed directly) was already reading
|
|
71
|
+
`data.focus` and moving the camera, but never actually calling
|
|
72
|
+
`selectNode` — so it centered on the new node without selecting it
|
|
73
|
+
(edit panel wouldn't update, arrow nav wouldn't be relative to it).
|
|
74
|
+
Fixed to call both.
|
|
75
|
+
- [x] **Show `due_by` on the node itself.** `render.js`'s `drawNode` draws
|
|
76
|
+
id (top-left) and `status` (top-right) already; add `due_by`
|
|
77
|
+
somewhere on the card (needs a spot picked that doesn't collide with
|
|
78
|
+
the wrapped label or the status text). Landed bottom-right,
|
|
79
|
+
compact `MM/DD`. Had to add `due_by` to `graph.js`'s node object too
|
|
80
|
+
— it wasn't being copied from the API payload at all.
|
|
81
|
+
|
|
82
|
+
## New features for v1
|
|
83
|
+
|
|
84
|
+
- [x] **Configuration needs to actually reach the browser.** `STYLE` in
|
|
85
|
+
`config.js` is hardcoded JS — the file's own header comment already
|
|
86
|
+
says "this will eventually be served by a backend endpoint (e.g.
|
|
87
|
+
`GET /api/style`)." This is the foundational piece the next two items
|
|
88
|
+
ride on: a config surface (new `CLIConfig` keys, most likely) that
|
|
89
|
+
the browser reads at load, rather than everything being a compile-time
|
|
90
|
+
JS constant. New `GET /api/style` (`browser.py`) returns the raw
|
|
91
|
+
`CLIConfig.model_dump()` unprocessed — no new endpoint needed every
|
|
92
|
+
time a renderer-relevant key gets added later, interpreting it is
|
|
93
|
+
each consumer's own job. Frontend: `canvas.js`'s new `loadConfig()`
|
|
94
|
+
fetches it into `STYLE.serverConfig` before the first tree load
|
|
95
|
+
(`loadConfig().then(loadTree)`, so config is guaranteed to be in
|
|
96
|
+
place before the first real render); `config.js` seeds
|
|
97
|
+
`STYLE.serverConfig = {}` so nothing has to null-check before that
|
|
98
|
+
resolves. Verified: `curl /api/style` against a live instance
|
|
99
|
+
returns the real `CLIConfig` JSON. No visible UI change from this
|
|
100
|
+
commit alone by design — nothing reads `serverConfig` yet, the next
|
|
101
|
+
item is the first real consumer.
|
|
102
|
+
- [x] **Node render color as an item attribute.** A per-item color override
|
|
103
|
+
(new `TodoItem` field, or reuse an existing free-form one) that
|
|
104
|
+
`render.js`'s `drawNode` checks before falling back to the
|
|
105
|
+
completed/default fill — lets a user color-code specific nodes
|
|
106
|
+
directly rather than only via `completed`/`status`. New `TodoItem.
|
|
107
|
+
color: Optional[str]` (any CSS color string), threaded through
|
|
108
|
+
`graph.js`'s node object and checked in `drawNode` before the
|
|
109
|
+
completed/default fill logic. Edit panel gets a plain text field
|
|
110
|
+
(deliberately not a native `<input type="color">` — that widget can
|
|
111
|
+
never represent "unset," always some valid hex color; an empty
|
|
112
|
+
string here correctly falls back to the default via JS truthiness,
|
|
113
|
+
no special-case handling needed anywhere). Verified end to end:
|
|
114
|
+
created an item with `--color`, confirmed it in the live `/api/tree`
|
|
115
|
+
payload, cleared it back to `""` and confirmed the model round-trips
|
|
116
|
+
that correctly.
|
|
117
|
+
- [x] **Status-string → color mapping, defined in config.** e.g.
|
|
118
|
+
`RUNNING=green, BLOCKED=red` as a new `CLIConfig` key (config-key
|
|
119
|
+
naming and exact syntax TBD — something in the spirit of the existing
|
|
120
|
+
`DISPLAY_STRING`/`DISPLAY_COLORS` pair). Right now every non-empty
|
|
121
|
+
`status` renders the same fixed orange in the DAG (`STYLE.colors.
|
|
122
|
+
statusText`) regardless of its value; this makes that configurable
|
|
123
|
+
per status string. Depends on the config-to-browser item above.
|
|
124
|
+
New `CLIConfig.STATUS_COLORS: str = ""`, comma-separated
|
|
125
|
+
`STATUS=color` pairs (e.g. `"RUNNING=green,BLOCKED=red"`) — settable
|
|
126
|
+
with the existing generic `task config set STATUS_COLORS ...`, no new
|
|
127
|
+
command needed. `render.js`'s new `parseStatusColors` parses it once
|
|
128
|
+
into `STYLE.statusColors` (in `canvas.js`'s `loadConfig`); `drawNode`
|
|
129
|
+
looks up the node's exact `status` string there before falling back
|
|
130
|
+
to the fixed `statusText` color. Verified: unit-tested the parser
|
|
131
|
+
(whitespace, multiple pairs, empty/undefined input) and round-tripped
|
|
132
|
+
a real value through `task config set` → `GET /api/style` against a
|
|
133
|
+
live instance.
|
|
134
|
+
- [x] **Chain-aware up/down arrows when there's no conflicting tree
|
|
135
|
+
relationship.** Currently arrows are pure tree nav and `f`/`b` are
|
|
136
|
+
the only way to walk a chain (deliberate split — see DEVPLAN 1.8,
|
|
137
|
+
worked out after hitting the "is c1 a chain head or a tree parent"
|
|
138
|
+
ambiguity). Refinement: a chain member's real children and its chain
|
|
139
|
+
successor/predecessor are mutually exclusive to check *per
|
|
140
|
+
direction*, so there's no actual ambiguity in the cases below —
|
|
141
|
+
- `down`: if the node has real children, behave exactly as today
|
|
142
|
+
(descend into them). **Only if it has none**, fall back to
|
|
143
|
+
`chainNext` instead of dead-ending.
|
|
144
|
+
- `up`: if the node has a tree parent, behave exactly as today.
|
|
145
|
+
**Only if it doesn't** (true for every non-head chain member,
|
|
146
|
+
which never has one), fall back to `chainPrev`.
|
|
147
|
+
This only changes behavior in the "otherwise a dead end" case — a
|
|
148
|
+
node with both a real child and a chain link (e.g. a chain head with
|
|
149
|
+
its own children) keeps today's behavior exactly, `f`/`b` still work
|
|
150
|
+
everywhere unchanged. Verified against 7 cases covering both
|
|
151
|
+
fallbacks, both non-fallback (unchanged) paths, and the true dead end
|
|
152
|
+
(tail, down).
|
|
153
|
+
- [x] **Transpose the DAG's coordinate axes: growth goes right, spread goes
|
|
154
|
+
down** (today: growth down, spread right). Affects `measure`/`place`
|
|
155
|
+
in `graph.js` — swap which recursion axis feeds `marginX +
|
|
156
|
+
...*xSpacing` vs. `marginY + ...*ySpacing` in `place()`, done
|
|
157
|
+
consistently for both the classic tree layout and the chain layout
|
|
158
|
+
(a chain currently drawn "straight down, children to the right"
|
|
159
|
+
would become "straight right, children downward" — same relationship,
|
|
160
|
+
rotated). **Open question to settle when this is picked up:** should
|
|
161
|
+
the arrow-key mapping rotate with it (right arrow = descend, down
|
|
162
|
+
arrow = next sibling) so the keys still feel spatially consistent
|
|
163
|
+
with what's on screen? Leaning yes, but worth confirming rather than
|
|
164
|
+
assuming. **Went with yes.** Turned out to be a genuinely small,
|
|
165
|
+
contained change: `place()`'s two recursion parameters were already
|
|
166
|
+
abstract ("spread" and "growth" in grid units) — every call site
|
|
167
|
+
below the top two lines passes them straight through unchanged, so
|
|
168
|
+
the *entire* orientation is decided in exactly those two lines
|
|
169
|
+
(renamed the parameters from `x`/`y` to `spread`/`growth` so that's
|
|
170
|
+
obvious on read, not just true by convention). Also had to fix:
|
|
171
|
+
`treeGap`'s unit conversion (was dividing by `xSpacing`, needs
|
|
172
|
+
`ySpacing` now that it's a spread-axis gap); the synthetic
|
|
173
|
+
`rootNode`'s position (was "above the roots," now "before them along
|
|
174
|
+
growth," centered on spread); `focusOnNode`'s off-center bias
|
|
175
|
+
(renamed `STYLE.zoom.focusYRatio` → `focusGrowthRatio`, moved from Y
|
|
176
|
+
to X); and `navigation.js`'s depth-level grouping for left/right
|
|
177
|
+
(was "shared y sorted by x," now "shared x sorted by y"). Console
|
|
178
|
+
text commands (`up`/`down`/`left`/`right`) and `f`/`b` keep their
|
|
179
|
+
original *structural* meaning unchanged (typing "down" always means
|
|
180
|
+
"my child," regardless of screen orientation) — only the *physical*
|
|
181
|
+
arrow-key → structural-direction mapping in `shortcuts.js` rotates
|
|
182
|
+
(`ArrowRight`→"down", `ArrowLeft`→"up", `ArrowDown`→"right",
|
|
183
|
+
`ArrowUp`→"left"). `Shift`+arrow panning stays tied to the actual
|
|
184
|
+
screen direction, untouched. Verified: rebuilt the graph from real
|
|
185
|
+
chain data and confirmed growth increases along X while chain
|
|
186
|
+
members/side-children/siblings spread along Y; confirmed
|
|
187
|
+
`navigateGraph`'s rotated depth-level stepping against that same
|
|
188
|
+
layout; confirmed every static file still serves against a live
|
|
189
|
+
`task browser` instance.
|
|
190
|
+
- [x] **Smarter `due_by` parsing.** Two related asks:
|
|
191
|
+
- **Format inference.** `_parse_item_kwargs` (`cli.py`) currently
|
|
192
|
+
hard-requires `MM-DD-YYYY` (`datetime.strptime(v, "%m-%d-%Y")`) —
|
|
193
|
+
anything else throws. Accept common formats without the user
|
|
194
|
+
needing to know the exact one (ISO `YYYY-MM-DD`, `MM/DD/YYYY`,
|
|
195
|
+
`Dec 31 2026`, etc.) — likely a small ordered list of formats tried
|
|
196
|
+
in turn, or a light date-parsing library if one's already
|
|
197
|
+
available/acceptable to add as a dependency.
|
|
198
|
+
- **Relative keywords.** `due_by=today` / `due_by=tomorrow` (that's
|
|
199
|
+
filter syntax — `taskai/filters.py`'s `due_by<op>value` — so this
|
|
200
|
+
reads as primarily a filters ask: `task show 'due_by<today'` etc.
|
|
201
|
+
Worth deciding at implementation time whether the same keywords
|
|
202
|
+
should also work on the *setting* path — `--due_by tomorrow` on
|
|
203
|
+
`create`/`add`/`update`/`next` — since both go through date
|
|
204
|
+
parsing but currently via different code (`filters.py` vs.
|
|
205
|
+
`_parse_item_kwargs`) and only one was explicitly asked for.
|
|
206
|
+
**Resolved: did both, via one shared helper.** New
|
|
207
|
+
[taskai/dates.py](taskai/dates.py), `parse_date_value(raw)` — tries a
|
|
208
|
+
list of formats (`MM-DD-YYYY`, ISO, `MM/DD/YYYY`, `MM/DD/YY`, and
|
|
209
|
+
`Month D[,] YYYY` in long/short-month variants) then falls back to
|
|
210
|
+
`today`/`tomorrow` (case-insensitive). Used by *both*
|
|
211
|
+
`_parse_item_kwargs`'s `due_by` branch (`cli.py`) and
|
|
212
|
+
`filters.py`'s `_coerce` for `due_by`/`created_on` — so
|
|
213
|
+
`--due_by tomorrow` on `create`/`add`/`update`/`next` and
|
|
214
|
+
`task show 'due_by=today'` both work, not just one. Verified: the 7
|
|
215
|
+
existing tests still pass; unit-checked every format + both
|
|
216
|
+
keywords + a bad-input error path directly; end-to-end through the
|
|
217
|
+
real CLI (`create --due_by 2026-12-25`, `update --due_by tomorrow`,
|
|
218
|
+
`show 'due_by=tomorrow'` all resolved and matched correctly).
|
|
219
|
+
`help_menu.py` updated in both spots (item-fields table and the
|
|
220
|
+
filter example line).
|
|
221
|
+
|
|
222
|
+
## Docs
|
|
223
|
+
|
|
224
|
+
- [~] Replace `docs/_static/demo.gif` placeholder with a real recording —
|
|
225
|
+
referenced from `index.md` and the README. Can't record the actual
|
|
226
|
+
gif (needs a real screen capture), but wrote the exact recording
|
|
227
|
+
script — `docs/_static/demo-script.md` (a production note, not a
|
|
228
|
+
published page; `_static/` is copied as-is, never parsed) — with the
|
|
229
|
+
precise commands to run, why each one's included, and what to skip.
|
|
230
|
+
Still needs someone to actually record it.
|
|
231
|
+
- [x] Confirm the Read the Docs project slug (`conf.py`'s `html_baseurl` +
|
|
232
|
+
README currently assume `taskai`). Confirmed live: fetched
|
|
233
|
+
`https://taskai.readthedocs.io/` and it resolves to the real project
|
|
234
|
+
(v1.9.0, right author, right content) — not a 404, not someone else's
|
|
235
|
+
docs. Removed the "needs confirmation" note in `conf.py`.
|
|
236
|
+
- [~] Screenshots for browser-mode docs. Can't capture real screenshots
|
|
237
|
+
(no browser automation available here), but added the exact shot
|
|
238
|
+
list inline in `docs/browser-mode.md` as HTML comments right where
|
|
239
|
+
each image belongs (matching `index.md`'s existing placeholder
|
|
240
|
+
pattern) — what each one should show and why, not just "add a
|
|
241
|
+
screenshot here." Updated the surrounding text in passing: it didn't
|
|
242
|
+
mention chains, the new per-item `color` field, or `due_by` display
|
|
243
|
+
at all, all real gaps now that those features exist. Still needs
|
|
244
|
+
someone to actually capture and drop in the images.
|
|
245
|
+
- [x] `help_menu.py`/README are current as of the chain work (Phase 8) —
|
|
246
|
+
spot-check the RTD site's generated pages didn't drift now that
|
|
247
|
+
`help_general` has a new "Chains:" section (`docs/commands.md`
|
|
248
|
+
`literalinclude`s it automatically, but worth a build-and-look). Ran
|
|
249
|
+
`sphinx-build -b html docs docs/_build/html`: builds clean (1
|
|
250
|
+
pre-existing warning, the known `demo.gif` placeholder — unrelated),
|
|
251
|
+
and the built `commands.html` correctly includes the full "Chains:"
|
|
252
|
+
section verbatim. Nothing needed fixing.
|
|
253
|
+
- [~] Lower priority, nice-to-have if time allows: explanation/architecture
|
|
254
|
+
pages, custom 404, OpenGraph cards, CI `linkcheck`, a changelog. CI
|
|
255
|
+
`linkcheck` is done (wired into the new CI job above). Added
|
|
256
|
+
[CHANGELOG.md](CHANGELOG.md) — an `Unreleased` section for
|
|
257
|
+
everything in this punch list plus dated entries for 1.9.0 back to
|
|
258
|
+
1.6.6, built from the actual version-bump commits and what changed
|
|
259
|
+
between them. Left the rest (architecture pages, custom 404, OG
|
|
260
|
+
cards) genuinely deferred — each is either a real content-writing
|
|
261
|
+
effort in its own right or needs an asset I can't produce, and none
|
|
262
|
+
were called out as blocking.
|
|
263
|
+
|
|
264
|
+
## Testing
|
|
265
|
+
|
|
266
|
+
- [x] **Zero test coverage for the chain feature.** The most structurally
|
|
267
|
+
risky thing shipping in this release (`next`/`chain`/`unchain`,
|
|
268
|
+
`delete -chain`, chain-aware `clear`, the `insert_node_into_chain` /
|
|
269
|
+
`remove_node_from_chain` / `delete_chain` DB methods) currently has no
|
|
270
|
+
tests at all — worth prioritizing over the general suite-broadening
|
|
271
|
+
below given how much subtle pointer-juggling is in that code path.
|
|
272
|
+
New [test/test_chains.py](test/test_chains.py), 12 DB-layer tests
|
|
273
|
+
covering insert (builds exactly one head; detaches a node already
|
|
274
|
+
mid-chain before re-splicing it elsewhere, verifying *both* chains
|
|
275
|
+
end up clean; pops a node off a real tree parent; inserting into the
|
|
276
|
+
middle of an existing chain), remove (middle-link relink; tail
|
|
277
|
+
shortening; head removal both standalone — the old head legitimately
|
|
278
|
+
stays put, matching what `unchain` needs — and via `delete_item`,
|
|
279
|
+
where it doesn't, which is the actual regression test for the
|
|
280
|
+
chain-head-deletion bug; the length-2-chain collapse edge case), and
|
|
281
|
+
`delete_chain`/`delete_item` interplay (full cascade + parent
|
|
282
|
+
detachment; a chain nested under a deleted parent takes its
|
|
283
|
+
real-children cascade path too; a plain mid-chain `delete` still
|
|
284
|
+
behaves like a linked-list splice). Also added a CLI-dispatch smoke
|
|
285
|
+
test to `test_cli.py` (`test_run_chain_commands`) exercising
|
|
286
|
+
`next`/`chain`/`unchain`/`delete -chain` end to end through the real
|
|
287
|
+
`execute_commands` path, matching the existing suite's
|
|
288
|
+
subprocess-based style. **Found one real bug writing these**, caught
|
|
289
|
+
by the test suite itself: my first draft of the head-removal test
|
|
290
|
+
called `remove_node_from_chain` directly and asserted the old head
|
|
291
|
+
was gone from the parent's children — wrong assertion, not a code
|
|
292
|
+
bug (that function alone never deletes anything, `delete_item` does,
|
|
293
|
+
by calling `remove_child_from_parent` *before* it) — but chasing it
|
|
294
|
+
down is exactly the kind of thing this coverage was for. All 20 tests
|
|
295
|
+
pass (7 pre-existing + 13 new).
|
|
296
|
+
- [ ] Broaden the general test suite (DEVPLAN Phase 6) — currently 7 tests
|
|
297
|
+
total across `test_cli.py`/`test_execution.py`/
|
|
298
|
+
`test_json_dir_database.py`/`test_view.py`. Lower priority than the
|
|
299
|
+
chain coverage above for a v1 cutoff specifically. **Deliberately
|
|
300
|
+
left for last and not started** — this is genuinely open-ended
|
|
301
|
+
(DEVPLAN Phase 6 scopes it as "every `execute_commands` branch,
|
|
302
|
+
id/name resolution, `_parse_item_kwargs`, the browser endpoints,
|
|
303
|
+
the AI command-execution loop with a mocked LLM"), it was already
|
|
304
|
+
explicitly the lowest priority item on this whole list, and
|
|
305
|
+
everything else got done first. A real next session, not a
|
|
306
|
+
last-minute partial pass tacked onto this one.
|
|
307
|
+
- [x] Wire CI (`pytest` on every PR, `sphinx-build -W` + `linkcheck` for
|
|
308
|
+
docs) — nice-to-have, fine to slip past v1 if time is tight. New
|
|
309
|
+
`.github/workflows/test.yml`, two jobs on `push`/`pull_request`:
|
|
310
|
+
`pytest` (installs the package + pytest, runs the suite) and `docs`
|
|
311
|
+
(`sphinx-build -b html -W` then `-b linkcheck`). **Heads up: the docs
|
|
312
|
+
job will start out red** — `-W` treats warnings as errors, and the
|
|
313
|
+
known `demo.gif` placeholder (see Docs section below) is currently
|
|
314
|
+
the one warning in the build. That's intentional, not a bug in the
|
|
315
|
+
workflow — confirmed locally that plain `sphinx-build -b html`
|
|
316
|
+
reports exactly that one warning and `-W` correctly turns it into a
|
|
317
|
+
failure. Didn't touch the existing `publish-to-pypi.yml` or any repo
|
|
318
|
+
branch-protection settings (whether this becomes a required check is
|
|
319
|
+
a repo-settings call, not something in the workflow file).
|
|
320
|
+
|
|
321
|
+
---
|
|
322
|
+
|
|
323
|
+
## Explicitly NOT v1 (stays in DEVPLAN/TRIAGE, not duplicated here)
|
|
324
|
+
|
|
325
|
+
- **`dependency_ids`** — Alex's call: drop this from v1 scope entirely,
|
|
326
|
+
revisit as a Phase 2 issue (whether that means wiring up `depend`/
|
|
327
|
+
`undepend` or actually removing the dead field stays an open question for
|
|
328
|
+
then, not now).
|
|
329
|
+
- **`task show` — light polish only for v1, full expansion later.**
|
|
330
|
+
DEVPLAN Phase 5 already flags the expanded view (depth limits, flat vs.
|
|
331
|
+
tree, sort order, color toggles) as needing a scoping session; Alex
|
|
332
|
+
confirmed: keep v1's touch light, scope the bigger version collaboratively
|
|
333
|
+
when picked up.
|
|
334
|
+
- Dependency edges in the browser DAG, and a real `depend`/`undepend` UI —
|
|
335
|
+
deferred to "2.0" in DEVPLAN 1.4/2.4 (same field as above).
|
|
336
|
+
- `task ai agent <prompt>` (real tool-calling loop, gated destructive
|
|
337
|
+
actions) — deferred to "2.0" in DEVPLAN 2.4.
|
|
338
|
+
- Advertising/launch prep (DEVPLAN Phase 7) — a separate workstream from
|
|
339
|
+
code readiness, not a polish/bugfix item.
|
|
340
|
+
- DEVPLAN Phase 1.1's originally-planned stdlib `http.server` + `task web
|
|
341
|
+
[port]` module is stale — the real implementation is FastAPI + uvicorn via
|
|
342
|
+
`taskai/browser.py`, built out completely under 1.2–1.8. Not a real to-do;
|
|
343
|
+
DEVPLAN should probably strike that subsection out rather than leave it
|
|
344
|
+
looking open.
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
# demo.gif recording script
|
|
2
|
+
|
|
3
|
+
Production note for whoever records `docs/_static/demo.gif` — not a
|
|
4
|
+
published page (this directory is Sphinx's static-asset folder, copied
|
|
5
|
+
as-is, never parsed as content). Delete this file once the real gif is in
|
|
6
|
+
place and this is no longer needed.
|
|
7
|
+
|
|
8
|
+
**Target:** ~20-30s, terminal only (a separate, shorter browser-mode clip
|
|
9
|
+
can live on its own if wanted — this one is the CLI). Readable font size,
|
|
10
|
+
nothing that requires the viewer to have already read the docs.
|
|
11
|
+
|
|
12
|
+
Run this in a scratch directory with a fresh `.taskai/task_db` (`task nuke`
|
|
13
|
+
first if reusing one, or just start somewhere new) so item ids are small
|
|
14
|
+
and the tree is uncluttered.
|
|
15
|
+
|
|
16
|
+
```bash
|
|
17
|
+
task create "Launch blog"
|
|
18
|
+
task add "Launch blog" "Write outline" --priority 1 --due_by tomorrow
|
|
19
|
+
task next "Write outline" "Draft intro"
|
|
20
|
+
task show all
|
|
21
|
+
task done "Write outline"
|
|
22
|
+
task ai "add a task under Launch blog to buy a domain"
|
|
23
|
+
task show all
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
What this covers, in order:
|
|
27
|
+
1. `create`/`add` — the everything-is-an-item tree, with a couple of fields
|
|
28
|
+
set (`--priority`, `--due_by tomorrow` — also shows off the relative
|
|
29
|
+
date keyword)
|
|
30
|
+
2. `next` — chains, the newest major feature, right after the tree basics
|
|
31
|
+
3. `show all` — the Rich-rendered tree, chain included (rendered inline
|
|
32
|
+
with the bold down-arrow between chain links)
|
|
33
|
+
4. `done` — quick, satisfying, worth the second of screen time
|
|
34
|
+
5. `task ai` — the natural-language layer actually creating something,
|
|
35
|
+
then a final `show all` so the viewer sees its result land in the tree
|
|
36
|
+
|
|
37
|
+
Skip `task browser` here — screen-recording a pannable/zoomable canvas
|
|
38
|
+
doesn't compress well as a small looping gif, and it already gets its own
|
|
39
|
+
screenshots (see the placeholders in `docs/browser-mode.md`).
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
# Browser mode
|
|
2
|
+
|
|
3
|
+
```bash
|
|
4
|
+
task browser
|
|
5
|
+
```
|
|
6
|
+
|
|
7
|
+
This starts a local web server and serves a visual view of your task tree.
|
|
8
|
+
|
|
9
|
+
## The canvas
|
|
10
|
+
|
|
11
|
+
The whole tree is drawn as connected cards. Drag to pan, scroll to zoom.
|
|
12
|
+
Double-click a card to center on it and open its edit panel.
|
|
13
|
+
|
|
14
|
+
<!-- screenshot: a tree with a few branches AND a chain (task next), wide
|
|
15
|
+
enough to show a plain parent/child branch, a chain rendered as its
|
|
16
|
+
straight bold-arrow line with real children fanned off to its side, and
|
|
17
|
+
at least one soft link (dashed ghost card) all in the same shot -->
|
|
18
|
+
|
|
19
|
+
- **Completed** items are tinted green.
|
|
20
|
+
- **`status`** text appears in the top corner of a card (or the color set by
|
|
21
|
+
`STATUS_COLORS` in config, if one's configured for that status).
|
|
22
|
+
- **`due_by`**, if set, appears in the bottom corner.
|
|
23
|
+
- **Soft links** (`task link`) are drawn as a dashed copy of the linked item
|
|
24
|
+
under its host, distinct from the solid parent/child connectors.
|
|
25
|
+
- **Chains** (`task next`/`task chain`) render as a straight bold arrow; a
|
|
26
|
+
chain link's own real children fan out to its side rather than centering
|
|
27
|
+
below it.
|
|
28
|
+
|
|
29
|
+
## The edit panel
|
|
30
|
+
|
|
31
|
+
Click a card to select it; double-click it, or press `e`, to open the edit
|
|
32
|
+
panel on the right. It has a field for the name, description, status, color,
|
|
33
|
+
priority, due date, and completion, plus a comment feed. Changes are saved as
|
|
34
|
+
you make them — there is no save button. In a single-line field, `Enter`
|
|
35
|
+
commits the change and leaves the field.
|
|
36
|
+
|
|
37
|
+
<!-- screenshot: the edit panel open on a card with most fields filled in
|
|
38
|
+
(including a couple of comments, to show the feed) -->
|
|
39
|
+
|
|
40
|
+
## The console
|
|
41
|
+
|
|
42
|
+
The panel at the bottom takes raw `task` commands and runs them against the
|
|
43
|
+
same data, printing their output and refreshing the canvas. Anything you can
|
|
44
|
+
type on the command line works here.
|
|
45
|
+
|
|
46
|
+
<!-- screenshot: the console expanded with a few example commands and their
|
|
47
|
+
output already in the scrollback -->
|
|
48
|
+
|
|
49
|
+
Filtering sticks: after `show 'priority>=2'` the canvas shows only the matches
|
|
50
|
+
(and their parents), and it stays scoped that way as you edit and delete —
|
|
51
|
+
until `show all` clears it.
|
|
52
|
+
|
|
53
|
+
## Keyboard
|
|
54
|
+
|
|
55
|
+
Press `?` for the full list in the app. The essentials:
|
|
56
|
+
|
|
57
|
+
| Key | Action |
|
|
58
|
+
|---|---|
|
|
59
|
+
| arrows | move the selection through the tree |
|
|
60
|
+
| `Ctrl`+`↑` / `↓` | jump out of / into a chain member's subtree (`↑`/`↓` walk the chain itself) |
|
|
61
|
+
| `Shift`+arrows | pan the view |
|
|
62
|
+
| `+` / `-` / `0` | zoom in / out / fit |
|
|
63
|
+
| `t` | flip the layout between growing down and growing right |
|
|
64
|
+
| `e` | toggle the edit panel |
|
|
65
|
+
| `` ` `` | focus / close the console |
|
|
66
|
+
| `a` | add a child of the selected card and name it |
|
|
67
|
+
| `c` | create a new top-level card and name it |
|
|
68
|
+
| `n` | add the next card in the selected card's chain and name it |
|
|
69
|
+
| `d` | toggle done on the selected card |
|
|
70
|
+
| `Delete` | delete the selected card |
|
|
71
|
+
| `Esc` | leave a field, then close the panel, then (with every panel closed) show the whole tree |
|
|
@@ -66,9 +66,8 @@ exclude_patterns = ["_build", "_generated", "Thumbs.db", ".DS_Store"]
|
|
|
66
66
|
|
|
67
67
|
html_theme = "furo"
|
|
68
68
|
html_title = f"taskai {release}"
|
|
69
|
-
#
|
|
70
|
-
#
|
|
71
|
-
# canonical URL itself; this is just the site root.
|
|
69
|
+
# confirmed live at this slug (also referenced in the README). Read the
|
|
70
|
+
# Docs sets the per-version canonical URL itself; this is just the site root.
|
|
72
71
|
html_baseurl = "https://taskai.readthedocs.io/"
|
|
73
72
|
html_static_path = ["_static"]
|
|
74
73
|
|
|
@@ -4,8 +4,10 @@ A command-line task manager with AI features.
|
|
|
4
4
|
|
|
5
5
|

|
|
6
6
|
|
|
7
|
-
<!-- demo.gif: record a short terminal session
|
|
8
|
-
|
|
7
|
+
<!-- demo.gif: record a short terminal session and drop it at
|
|
8
|
+
docs/_static/demo.gif. Full shot list + exact commands in
|
|
9
|
+
docs/_static/demo-script.md (not a published page - a production note
|
|
10
|
+
for whoever records this). -->
|
|
9
11
|
|
|
10
12
|
## What you can do
|
|
11
13
|
|