mirror of
https://github.com/logseq/logseq.git
synced 2026-05-17 09:22:21 +00:00
196 lines
11 KiB
Markdown
196 lines
11 KiB
Markdown
# Logseq CLI Task Subcommands Implementation Plan
|
|
|
|
Goal: Add task-oriented subcommands to the current `logseq-cli` command surface with `list task` and `upsert task`, where a task is any node tagged with `#Task` (`:logseq.class/Task`), including both blocks and pages.
|
|
|
|
Architecture: Reuse the existing `logseq-cli -> transport/invoke -> db-worker-node thread-api` flow, and keep command parsing/build/validation in CLI command namespaces with db read logic in db-worker helpers.
|
|
|
|
Architecture: Keep behavior aligned with current `list`/`upsert`/`remove` conventions, and avoid introducing a parallel command framework for tasks.
|
|
|
|
Tech Stack: ClojureScript, `babashka.cli`, `promesa`, Datascript pull/query, existing `apply-outliner-ops` mutation path in db-worker.
|
|
|
|
Related: Builds on [069-logseq-cli-search-subcommands.md](/Users/rcmerci/gh-repos/logseq/docs/agent-guide/069-logseq-cli-search-subcommands.md), [071-logseq-cli-search-content-option.md](/Users/rcmerci/gh-repos/logseq/docs/agent-guide/071-logseq-cli-search-content-option.md), and [docs/cli/logseq-cli.md](/Users/rcmerci/gh-repos/logseq/docs/cli/logseq-cli.md).
|
|
|
|
## Problem statement
|
|
|
|
Current CLI supports generic node operations (`list page/tag/property`, `upsert block/page/tag/property`, `remove block/page/tag/property`) but has no task-focused command path.
|
|
|
|
The product model already has built-in class `:logseq.class/Task` and task properties (`status`, `priority`, `deadline`, `scheduled`), so users currently need multiple generic commands or custom queries for common task workflows.
|
|
|
|
We need a first-class task command group that maps to existing implementation patterns and is script-friendly.
|
|
|
|
## Current baseline from implementation
|
|
|
|
`list` commands already expose pagination and sort contracts and depend on db-worker helper functions via `:thread-api/cli-list-*`.
|
|
|
|
`upsert block/page` already supports tag/property mutation via `--update-tags`, `--update-properties`, `--remove-tags`, and `--remove-properties`.
|
|
|
|
`remove` commands already implement robust selector validation, name/id disambiguation, and best-effort multi-id behavior for blocks.
|
|
|
|
Built-in class `:logseq.class/Task` exists and is treated as a tag class with task properties in db bootstrap.
|
|
|
|
## Command surface proposal (for discussion first)
|
|
|
|
This section is intentionally a proposal draft so we can converge on options before implementation.
|
|
|
|
### 1) `list task` options proposal
|
|
|
|
Recommended MVP options:
|
|
|
|
| Option | Type | Default | Notes |
|
|
| --- | --- | --- | --- |
|
|
| `--status` | status alias | none | Accept same aliases as current `upsert block --status` normalization. |
|
|
| `--priority` | `low|medium|high|urgent` | none | Task priority filter. |
|
|
| `--content` | string | none | Case-insensitive substring filter on `:block/title`. |
|
|
| `--fields` | csv | command default | Same pattern as existing `list` commands. |
|
|
| `--limit` | long | none | Same as existing `list`. |
|
|
| `--offset` | long | none | Same as existing `list`. |
|
|
| `--sort` | enum | `updated-at` | Proposed sort fields: `updated-at`, `created-at`, `title`, `status`, `priority`. |
|
|
| `--order` | `asc|desc` | `asc` | Same as existing `list`. |
|
|
|
|
Recommended default output fields:
|
|
|
|
`id,title,status,priority,scheduled,deadline,updated-at,created-at`.
|
|
|
|
Phase 2 optional filters:
|
|
|
|
`--scheduled-after`, `--scheduled-before`, `--deadline-after`, `--deadline-before`, and multi-status support.
|
|
|
|
### 2) `upsert task` options proposal
|
|
|
|
Recommended MVP options:
|
|
|
|
| Option | Type | Purpose |
|
|
| --- | --- | --- |
|
|
| `--id` | long | Update an existing node as task by db/id. |
|
|
| `--uuid` | uuid | Update an existing node as task by UUID. |
|
|
| `--page` | string | Upsert a page task by page name. |
|
|
| `--content` | string | Create a block task with content. |
|
|
| `--target-id` | long | Block create target selector. |
|
|
| `--target-uuid` | uuid | Block create target selector. |
|
|
| `--target-page` | string | Block create target selector. |
|
|
| `--pos` | `first-child|last-child|sibling` | Block create position control. |
|
|
| `--status` | status alias | Set `:logseq.property/status`. |
|
|
| `--priority` | enum | Set `:logseq.property/priority.*`. |
|
|
| `--update-properties` | edn map | Advanced property mutation. |
|
|
| `--remove-properties` | edn vector | Advanced property removal. |
|
|
| `--update-tags` | edn vector | Optional extra tags beyond `#Task`. |
|
|
| `--remove-tags` | edn vector | Optional tag removal with guardrails for `#Task`. |
|
|
|
|
Recommended semantics:
|
|
|
|
`upsert task` always ensures `:logseq.class/Task` tag exists on the target node.
|
|
|
|
When selector is `--id` or `--uuid`, command runs in update mode and converts non-task node into task by adding `:logseq.class/Task`.
|
|
|
|
When selector is `--page`, command upserts page and ensures task tag plus task properties.
|
|
|
|
When selector is `--content` and no id/page selector is provided, command creates block task and supports current block targeting options.
|
|
|
|
Key validation proposal:
|
|
|
|
Only one of `--id`, `--uuid`, `--page` is allowed.
|
|
|
|
`--content` and `--page` cannot be combined.
|
|
|
|
`--target-*` and `--pos` are only valid for block-create path.
|
|
|
|
Task removal strategy:
|
|
|
|
Do not add `remove task` in this scope.
|
|
|
|
Use existing `remove block` and `remove page` commands for deletion.
|
|
|
|
## Proposed architecture and files
|
|
|
|
Keep `list task` in list command flow and add db-worker helper method to avoid large query logic in CLI command layer.
|
|
|
|
Implement `upsert task` by reusing existing upsert/tag/property helper functions and `apply-outliner-ops` patterns.
|
|
|
|
Primary files to touch:
|
|
|
|
- [/Users/rcmerci/gh-repos/logseq/src/main/logseq/cli/command/list.cljs](/Users/rcmerci/gh-repos/logseq/src/main/logseq/cli/command/list.cljs)
|
|
- [/Users/rcmerci/gh-repos/logseq/src/main/logseq/cli/command/upsert.cljs](/Users/rcmerci/gh-repos/logseq/src/main/logseq/cli/command/upsert.cljs)
|
|
- [/Users/rcmerci/gh-repos/logseq/src/main/logseq/cli/commands.cljs](/Users/rcmerci/gh-repos/logseq/src/main/logseq/cli/commands.cljs)
|
|
- [/Users/rcmerci/gh-repos/logseq/src/main/logseq/cli/format.cljs](/Users/rcmerci/gh-repos/logseq/src/main/logseq/cli/format.cljs)
|
|
- [/Users/rcmerci/gh-repos/logseq/src/main/logseq/cli/common/db_worker.cljs](/Users/rcmerci/gh-repos/logseq/src/main/logseq/cli/common/db_worker.cljs)
|
|
- [/Users/rcmerci/gh-repos/logseq/src/main/frontend/worker/db_core.cljs](/Users/rcmerci/gh-repos/logseq/src/main/frontend/worker/db_core.cljs)
|
|
- [/Users/rcmerci/gh-repos/logseq/docs/cli/logseq-cli.md](/Users/rcmerci/gh-repos/logseq/docs/cli/logseq-cli.md)
|
|
- [/Users/rcmerci/gh-repos/logseq/cli-e2e/spec/non_sync_inventory.edn](/Users/rcmerci/gh-repos/logseq/cli-e2e/spec/non_sync_inventory.edn)
|
|
- [/Users/rcmerci/gh-repos/logseq/cli-e2e/spec/non_sync_cases.edn](/Users/rcmerci/gh-repos/logseq/cli-e2e/spec/non_sync_cases.edn)
|
|
|
|
## Testing Plan
|
|
|
|
I will follow @test-driven-development and add all failing tests before implementation code changes.
|
|
|
|
I will add parser and validation tests in [commands_test.cljs](/Users/rcmerci/gh-repos/logseq/src/test/logseq/cli/commands_test.cljs) for new command paths and option conflicts.
|
|
|
|
I will add command execution tests for new task logic in [upsert_test.cljs](/Users/rcmerci/gh-repos/logseq/src/test/logseq/cli/command/upsert_test.cljs) and existing remove/list test files, or create focused task command test namespaces if coverage becomes too broad.
|
|
|
|
I will add db-worker behavior tests for task listing in [db_worker_test.cljs](/Users/rcmerci/gh-repos/logseq/src/test/logseq/cli/common/db_worker_test.cljs).
|
|
|
|
I will add output formatting tests in [format_test.cljs](/Users/rcmerci/gh-repos/logseq/src/test/logseq/cli/format_test.cljs) for human/json/edn task command outputs.
|
|
|
|
I will extend CLI e2e inventory and non-sync cases for `list task` and `upsert task`.
|
|
|
|
I will run focused tests first and then run `bb dev:lint-and-test`.
|
|
|
|
NOTE: I will write *all* tests before I add any implementation behavior.
|
|
|
|
## Step-by-step implementation plan
|
|
|
|
1. Add command entries for `list task` and `upsert task` with proposed option specs and examples.
|
|
|
|
2. Wire new command keywords into parse-time validation in [commands.cljs](/Users/rcmerci/gh-repos/logseq/src/main/logseq/cli/commands.cljs).
|
|
|
|
3. Add build-action branches for new task commands and keep error codes aligned with existing style (`:missing-target`, `:invalid-options`, `:missing-page-name`).
|
|
|
|
4. Add execute branch wiring for new task command types in [commands.cljs](/Users/rcmerci/gh-repos/logseq/src/main/logseq/cli/commands.cljs).
|
|
|
|
5. Implement `list task` db-worker helper query in [db_worker.cljs](/Users/rcmerci/gh-repos/logseq/src/main/logseq/cli/common/db_worker.cljs) and expose it via new `:thread-api/cli-list-tasks` in [db_core.cljs](/Users/rcmerci/gh-repos/logseq/src/main/frontend/worker/db_core.cljs).
|
|
|
|
6. Implement `execute-list-task` in [list.cljs](/Users/rcmerci/gh-repos/logseq/src/main/logseq/cli/command/list.cljs) with existing sort/fields/offset/limit helpers.
|
|
|
|
7. Implement `build-task-action` and `execute-upsert-task` in [upsert.cljs](/Users/rcmerci/gh-repos/logseq/src/main/logseq/cli/command/upsert.cljs) by composing existing tag/property resolution utilities and task-specific normalization for status and priority.
|
|
|
|
8. Add `format` support for new command result shapes in [format.cljs](/Users/rcmerci/gh-repos/logseq/src/main/logseq/cli/format.cljs).
|
|
|
|
9. Update docs and CLI e2e coverage files once behavior is stable.
|
|
|
|
## Edge cases to cover explicitly
|
|
|
|
A target node can exist but not have `#Task`, and command should fail with explicit type-mismatch style error instead of silently mutating or deleting wrong entities.
|
|
|
|
Task pages and task blocks must both be supported for list and upsert.
|
|
|
|
`upsert task` status aliases should match current `upsert block --status` normalization so scripts can reuse existing values.
|
|
|
|
`--scheduled` and `--deadline` are explicitly out of MVP and should be handled later via dedicated options or via `--update-properties`.
|
|
|
|
`list task` sort behavior must stay stable with deterministic tie-breaker by `:db/id`, consistent with current list commands.
|
|
|
|
## Testing Details
|
|
|
|
I will verify parse/build/execute behavior at command layer and confirm db-worker helper output contracts without relying on ad hoc manual checks.
|
|
|
|
I will ensure tests assert behavior for both block task and page task paths, including conversion of non-task nodes during upsert when selector-based update is used.
|
|
|
|
I will include at least one e2e case that creates task via `upsert task` and lists it via `list task` in one flow.
|
|
|
|
## Implementation Details
|
|
|
|
- Keep task identity canonical as `:block/tags` containing `:logseq.class/Task`.
|
|
- Reuse existing normalization helpers for status and property parsing to minimize duplicate parsing logic.
|
|
- Prefer extending existing command namespaces over introducing a second task-only command framework.
|
|
- Reuse existing list formatting utilities with task-specific column mapping.
|
|
- Keep error code naming aligned with current conventions to avoid inconsistent CLI UX.
|
|
- Keep JSON namespaced key behavior unchanged by routing through existing formatter normalization.
|
|
- Ensure command help examples include both block and page task use cases.
|
|
- Keep cli-e2e inventory and docs in lockstep with final option names.
|
|
- Defer non-MVP filters (`deadline`/`scheduled` ranges, multi-status) and `upsert task` dedicated `--scheduled/--deadline` options.
|
|
|
|
## Question
|
|
|
|
No open questions.
|
|
|
|
---
|