clickup-cli 1.2.0__tar.gz → 1.4.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.
- clickup_cli-1.4.0/.claude/agents/api-compatibility-checker.md +39 -0
- clickup_cli-1.4.0/.claude/settings.json +44 -0
- clickup_cli-1.4.0/.claude/skills/changelog/SKILL.md +48 -0
- clickup_cli-1.4.0/.claude/skills/validate-output/SKILL.md +43 -0
- {clickup_cli-1.2.0 → clickup_cli-1.4.0}/CHANGELOG.md +20 -0
- {clickup_cli-1.2.0 → clickup_cli-1.4.0}/CLAUDE.md +40 -0
- clickup_cli-1.4.0/CONTRIBUTING.md +54 -0
- {clickup_cli-1.2.0 → clickup_cli-1.4.0}/PKG-INFO +6 -7
- {clickup_cli-1.2.0 → clickup_cli-1.4.0}/README.md +5 -6
- {clickup_cli-1.2.0 → clickup_cli-1.4.0}/clickup-config.example.json +1 -5
- {clickup_cli-1.2.0 → clickup_cli-1.4.0}/src/clickup_cli/__init__.py +1 -1
- {clickup_cli-1.2.0 → clickup_cli-1.4.0}/src/clickup_cli/client.py +2 -2
- {clickup_cli-1.2.0 → clickup_cli-1.4.0}/src/clickup_cli/commands/__init__.py +2 -0
- {clickup_cli-1.2.0 → clickup_cli-1.4.0}/src/clickup_cli/commands/folders.py +4 -2
- {clickup_cli-1.2.0 → clickup_cli-1.4.0}/src/clickup_cli/commands/init.py +0 -4
- {clickup_cli-1.2.0 → clickup_cli-1.4.0}/src/clickup_cli/commands/lists.py +12 -4
- {clickup_cli-1.2.0 → clickup_cli-1.4.0}/src/clickup_cli/commands/tasks.py +383 -86
- {clickup_cli-1.2.0 → clickup_cli-1.4.0}/src/clickup_cli/config.py +0 -4
- {clickup_cli-1.2.0 → clickup_cli-1.4.0}/src/clickup_cli/helpers.py +27 -6
- {clickup_cli-1.2.0 → clickup_cli-1.4.0}/tests/conftest.py +2 -6
- {clickup_cli-1.2.0 → clickup_cli-1.4.0}/tests/test_cli.py +49 -94
- {clickup_cli-1.2.0 → clickup_cli-1.4.0}/tests/test_commands.py +407 -72
- {clickup_cli-1.2.0 → clickup_cli-1.4.0}/tests/test_config.py +0 -17
- {clickup_cli-1.2.0 → clickup_cli-1.4.0}/tests/test_helpers.py +51 -3
- clickup_cli-1.2.0/.claude/settings.json +0 -26
- {clickup_cli-1.2.0 → clickup_cli-1.4.0}/.claude/agents/test-writer.md +0 -0
- {clickup_cli-1.2.0 → clickup_cli-1.4.0}/.claude/skills/add-command.md +0 -0
- {clickup_cli-1.2.0 → clickup_cli-1.4.0}/.claude/skills/clickup-cli.md +0 -0
- {clickup_cli-1.2.0 → clickup_cli-1.4.0}/.claude/skills/release/SKILL.md +0 -0
- {clickup_cli-1.2.0 → clickup_cli-1.4.0}/.github/workflows/ci.yml +0 -0
- {clickup_cli-1.2.0 → clickup_cli-1.4.0}/.gitignore +0 -0
- {clickup_cli-1.2.0 → clickup_cli-1.4.0}/.mcp.json +0 -0
- {clickup_cli-1.2.0 → clickup_cli-1.4.0}/LICENSE +0 -0
- {clickup_cli-1.2.0 → clickup_cli-1.4.0}/pyproject.toml +0 -0
- {clickup_cli-1.2.0 → clickup_cli-1.4.0}/scripts/validate-cli-output.sh +0 -0
- {clickup_cli-1.2.0 → clickup_cli-1.4.0}/src/clickup_cli/__main__.py +0 -0
- {clickup_cli-1.2.0 → clickup_cli-1.4.0}/src/clickup_cli/cli.py +0 -0
- {clickup_cli-1.2.0 → clickup_cli-1.4.0}/src/clickup_cli/commands/comments.py +0 -0
- {clickup_cli-1.2.0 → clickup_cli-1.4.0}/src/clickup_cli/commands/docs.py +0 -0
- {clickup_cli-1.2.0 → clickup_cli-1.4.0}/src/clickup_cli/commands/spaces.py +0 -0
- {clickup_cli-1.2.0 → clickup_cli-1.4.0}/src/clickup_cli/commands/tags.py +0 -0
- {clickup_cli-1.2.0 → clickup_cli-1.4.0}/src/clickup_cli/commands/team.py +0 -0
- {clickup_cli-1.2.0 → clickup_cli-1.4.0}/tests/test_client.py +0 -0
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: api-compatibility-checker
|
|
3
|
+
description: Cross-reference CLI endpoint usage against ClickUp API docs to flag deprecated or changed endpoints
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# API Compatibility Checker
|
|
7
|
+
|
|
8
|
+
You verify that the ClickUp CLI's API endpoint usage is current and compatible.
|
|
9
|
+
|
|
10
|
+
## Steps
|
|
11
|
+
|
|
12
|
+
1. Read `src/clickup_cli/client.py` to extract all API endpoints used (URL patterns in requests calls).
|
|
13
|
+
|
|
14
|
+
2. Read each command file in `src/clickup_cli/commands/` to find any direct endpoint references.
|
|
15
|
+
|
|
16
|
+
3. Build a list of all endpoints used, grouped by API version (v2 vs v3).
|
|
17
|
+
|
|
18
|
+
4. For each endpoint, check the current ClickUp API documentation to verify:
|
|
19
|
+
- The endpoint still exists
|
|
20
|
+
- The HTTP method matches
|
|
21
|
+
- Required parameters haven't changed
|
|
22
|
+
- Response format is consistent with what the CLI expects
|
|
23
|
+
|
|
24
|
+
5. Report findings:
|
|
25
|
+
- **OK** — endpoint verified as current
|
|
26
|
+
- **WARNING** — endpoint exists but has changes (new required params, deprecated fields)
|
|
27
|
+
- **BREAKING** — endpoint removed or fundamentally changed
|
|
28
|
+
|
|
29
|
+
## Output
|
|
30
|
+
|
|
31
|
+
Return a JSON summary:
|
|
32
|
+
```json
|
|
33
|
+
{
|
|
34
|
+
"total_endpoints": 0,
|
|
35
|
+
"ok": 0,
|
|
36
|
+
"warnings": [],
|
|
37
|
+
"breaking": []
|
|
38
|
+
}
|
|
39
|
+
```
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
{
|
|
2
|
+
"hooks": {
|
|
3
|
+
"PostToolUse": [
|
|
4
|
+
{
|
|
5
|
+
"matcher": "Edit|Write",
|
|
6
|
+
"hooks": [
|
|
7
|
+
{
|
|
8
|
+
"type": "command",
|
|
9
|
+
"command": "filepath=\"$TOOL_INPUT_FILE_PATH$TOOL_INPUT_file_path\"; if echo \"$filepath\" | grep -qE '\\.py$'; then ruff check --fix --quiet \"$filepath\" 2>/dev/null; ruff format --quiet \"$filepath\" 2>/dev/null; fi; true"
|
|
10
|
+
}
|
|
11
|
+
]
|
|
12
|
+
},
|
|
13
|
+
{
|
|
14
|
+
"matcher": "Edit|Write",
|
|
15
|
+
"hooks": [
|
|
16
|
+
{
|
|
17
|
+
"type": "command",
|
|
18
|
+
"command": "filepath=\"$TOOL_INPUT_FILE_PATH$TOOL_INPUT_file_path\"; if echo \"$filepath\" | grep -qE 'src/clickup_cli/commands/[a-z]+\\.py$'; then python -m pytest tests/test_commands.py -x -q --tb=short 2>&1 | tail -5; elif echo \"$filepath\" | grep -qE 'src/clickup_cli/(cli|helpers|config|client)\\.py$'; then mod=$(basename \"$filepath\" .py); if [ -f \"tests/test_${mod}.py\" ]; then python -m pytest \"tests/test_${mod}.py\" -x -q --tb=short 2>&1 | tail -5; fi; fi; true"
|
|
19
|
+
}
|
|
20
|
+
]
|
|
21
|
+
}
|
|
22
|
+
],
|
|
23
|
+
"PreToolUse": [
|
|
24
|
+
{
|
|
25
|
+
"matcher": "Edit|Write",
|
|
26
|
+
"hooks": [
|
|
27
|
+
{
|
|
28
|
+
"type": "command",
|
|
29
|
+
"command": "filepath=\"$TOOL_INPUT_FILE_PATH$TOOL_INPUT_file_path\"; if echo \"$filepath\" | grep -qE '\\.(env|secret|pem|key)$|credentials'; then echo 'BLOCKED: refusing to edit sensitive file'; exit 1; fi"
|
|
30
|
+
}
|
|
31
|
+
]
|
|
32
|
+
},
|
|
33
|
+
{
|
|
34
|
+
"matcher": "Edit|Write",
|
|
35
|
+
"hooks": [
|
|
36
|
+
{
|
|
37
|
+
"type": "command",
|
|
38
|
+
"command": "filepath=\"$TOOL_INPUT_FILE_PATH$TOOL_INPUT_file_path\"; if echo \"$filepath\" | grep -qE 'pyproject\\.toml$'; then echo 'BLOCKED: pyproject.toml edit requires explicit approval'; exit 1; fi"
|
|
39
|
+
}
|
|
40
|
+
]
|
|
41
|
+
}
|
|
42
|
+
]
|
|
43
|
+
}
|
|
44
|
+
}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: changelog
|
|
3
|
+
description: Generate release notes from git log since last tag, categorized by commit type
|
|
4
|
+
disable-model-invocation: true
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# Generate Changelog Entry
|
|
8
|
+
|
|
9
|
+
Generate a categorized changelog entry for the next release.
|
|
10
|
+
|
|
11
|
+
## Steps
|
|
12
|
+
|
|
13
|
+
1. Find the last release tag:
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
git describe --tags --abbrev=0 2>/dev/null || echo "none"
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
2. Get all commits since that tag (or all commits if no tag exists):
|
|
20
|
+
|
|
21
|
+
```bash
|
|
22
|
+
git log $(git describe --tags --abbrev=0 2>/dev/null)..HEAD --oneline 2>/dev/null || git log --oneline
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
3. Categorize commits by their prefix:
|
|
26
|
+
- **Added** — `feat:`, `add:`
|
|
27
|
+
- **Changed** — `refactor:`, `update:`, `improve:`
|
|
28
|
+
- **Fixed** — `fix:`, `bugfix:`
|
|
29
|
+
- **Testing** — `test:`
|
|
30
|
+
- **Docs** — `docs:`
|
|
31
|
+
- **Other** — everything else
|
|
32
|
+
|
|
33
|
+
4. Draft a markdown changelog entry:
|
|
34
|
+
|
|
35
|
+
```markdown
|
|
36
|
+
## [vX.Y.Z] - YYYY-MM-DD
|
|
37
|
+
|
|
38
|
+
### Added
|
|
39
|
+
- Description of new features
|
|
40
|
+
|
|
41
|
+
### Changed
|
|
42
|
+
- Description of changes
|
|
43
|
+
|
|
44
|
+
### Fixed
|
|
45
|
+
- Description of bug fixes
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
5. Present the draft for review. Do not write to any file until the user approves.
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: validate-output
|
|
3
|
+
description: Verify the CLI's JSON-only stdout contract across all commands. Run after adding new commands or modifying output logic.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Validate CLI Output Contract
|
|
7
|
+
|
|
8
|
+
Verify that every CLI command produces valid JSON on stdout and errors on stderr.
|
|
9
|
+
|
|
10
|
+
## Steps
|
|
11
|
+
|
|
12
|
+
1. Get all command groups and subcommands:
|
|
13
|
+
|
|
14
|
+
```bash
|
|
15
|
+
clickup --help 2>/dev/null
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
2. For each command group, get its subcommands:
|
|
19
|
+
|
|
20
|
+
```bash
|
|
21
|
+
clickup <group> --help 2>/dev/null
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
3. For each subcommand that supports `--dry-run`, run it with dummy arguments and `--dry-run`:
|
|
25
|
+
|
|
26
|
+
```bash
|
|
27
|
+
clickup --dry-run <group> <subcommand> <required-args> 2>/dev/null
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
4. Validate that stdout is valid JSON by piping through `python3 -c "import sys,json; json.load(sys.stdin)"`.
|
|
31
|
+
|
|
32
|
+
5. For read-only commands (list, get, search), run with `--help` and verify the help text renders without errors.
|
|
33
|
+
|
|
34
|
+
6. Report results as a summary:
|
|
35
|
+
- Total commands checked
|
|
36
|
+
- Commands producing valid JSON
|
|
37
|
+
- Commands with issues (list each with the error)
|
|
38
|
+
|
|
39
|
+
## What Counts as a Failure
|
|
40
|
+
|
|
41
|
+
- Any stdout output that is not valid JSON
|
|
42
|
+
- Any command that crashes (non-zero exit without stderr message)
|
|
43
|
+
- Help text that fails to render
|
|
@@ -1,7 +1,27 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 1.4.0 (2026-04-11)
|
|
4
|
+
|
|
5
|
+
- **`tasks update` now handles tags, assignees, and custom fields.** Five new repeatable flags: `--add-assignee` / `--remove-assignee` (packed into the PUT body), `--add-tag` / `--remove-tag` (issues one POST/DELETE per tag), and `--custom-field FIELD_ID=VALUE` (issues one POST per field). When no PUT body is needed, the task is re-fetched at the end so the returned JSON always reflects final state. `--dry-run` returns a structured plan with no API calls.
|
|
6
|
+
- **New `tasks depend` subcommand group** — `add`, `remove`, and `list` for task dependencies. Direction is required and mutually exclusive: `--depends-on OTHER` (this task waits on OTHER) or `--depended-on-by OTHER` (OTHER waits on this). `list` partitions the task's `dependencies` array into both directions from the target task's point of view.
|
|
7
|
+
- **`tasks list` and `tasks search` accept `--include-archived`.** Since ClickUp's `archived` param is a filter (returns only archived), the flag issues a second paginated request with `archived=true` and merges the results. Default behavior unchanged.
|
|
8
|
+
- **Raw numeric IDs accepted on all name-lookup flags.** `--space` / `--folder` on folders, lists, spaces, and tasks commands now transparently accept raw ClickUp IDs alongside config aliases. On tasks commands, raw space IDs resolve via a one-call API lookup to the first folderless list in that space. Help metavars updated to `SPACE_NAME_OR_ID` for discoverability. Case-sensitive alias matching is unchanged — `Personal` vs `personal` remains a deliberate error.
|
|
9
|
+
- **Fix: `tasks create` no longer leaks `hint: inferred --space` to stderr.** Same fix applied to `tasks search`'s auto name-prefix hint. Both are deterministic from inputs and the JSON response — the hints were informational noise that broke `2>&1 | jq` pipes.
|
|
10
|
+
- **Fix: `tasks create` is now truly neutral.** The v1.3.0 release advertised neutral defaults but still read `default_tags` from the config file and applied it silently. Removed `default_tags` from the config schema entirely; stale entries in existing configs are now ignored.
|
|
11
|
+
- **Fix: `tasks list --full` returns a consistent status shape.** Compact mode already flattened status to a string, but `--full` passed raw API shapes through — sometimes dict, sometimes string. Now `--full` always returns status as a dict (`{status, color, type, orderindex}`), upgrading string statuses with null metadata.
|
|
12
|
+
- **Client: `delete_v2` accepts an optional `params` kwarg** to forward query parameters (needed for the dependency remove endpoint).
|
|
13
|
+
- Test suite: 305 → 332 tests. Added coverage for stderr contract, archived pagination, status-shape normalization, raw-ID lookups, expanded update paths, and dependency CRUD.
|
|
14
|
+
|
|
15
|
+
## 1.3.0 (2026-04-10)
|
|
16
|
+
|
|
17
|
+
- Add `--tag` filter on `tasks list` (API-level, repeatable, auto-lowercased) and `tasks search` (client-side filter).
|
|
18
|
+
- Remove opinionated `tasks create` defaults: no auto-assignee, no auto-priority, no auto-tags unless explicitly passed. (Note: `default_tags` config field was not fully removed until 1.4.0.)
|
|
19
|
+
- Explicit `--assign <user_id>` flag for `tasks create` when you do want to assign.
|
|
20
|
+
|
|
3
21
|
## 1.2.0 (2026-03-29)
|
|
4
22
|
|
|
23
|
+
**First PyPI release** — `pip install clickup-cli`
|
|
24
|
+
|
|
5
25
|
- Accept flag aliases for all positional arguments — agents can now use `--task-id`, `--query`, `--doc-id`, `--page-id`, `--folder-id`, `--list-id`, `--comment-id`, `--space` instead of positional args. Both forms work; positional args are unchanged for backwards compatibility.
|
|
6
26
|
- Auto-infer `--space` from `--list` on `tasks create` — when `--list` is provided without `--space`, the CLI fetches the list metadata via API to resolve its parent space automatically. Eliminates the most common agent error (12+ failures in 3 days).
|
|
7
27
|
- Make `--space` optional on `tasks create` (was required) — now only required if `--list` is also absent.
|
|
@@ -54,8 +54,27 @@ When adding new commands with ID arguments, always use `add_id_argument()` inste
|
|
|
54
54
|
pip install -e ".[dev]"
|
|
55
55
|
pytest -v
|
|
56
56
|
ruff check src/ tests/
|
|
57
|
+
scripts/validate-cli-output.sh # verify JSON stdout contract
|
|
57
58
|
```
|
|
58
59
|
|
|
60
|
+
## Test Structure
|
|
61
|
+
|
|
62
|
+
```
|
|
63
|
+
tests/
|
|
64
|
+
├── conftest.py # test config setup (runs at import time, before clickup_cli loads)
|
|
65
|
+
├── test_cli.py # argument parsing, dispatch, global flags, resolve_id_args
|
|
66
|
+
├── test_client.py # ClickUpClient: rate limiting, dry-run, debug mode, HTTP methods
|
|
67
|
+
├── test_commands.py # all command handlers: tasks, comments, docs, folders, lists, spaces, tags, team
|
|
68
|
+
├── test_config.py # config loading: file, env vars, fallback chain, workspace auto-detect
|
|
69
|
+
└── test_helpers.py # output/error helpers, compact_task, add_id_argument, fetch_all_comments pagination
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
305 tests, all using `unittest.TestCase` + `FakeClient` pattern (no real HTTP calls).
|
|
73
|
+
|
|
74
|
+
## CI
|
|
75
|
+
|
|
76
|
+
GitHub Actions (`ci.yml`): lint + test on Python 3.9, 3.11, 3.13. Runs on push to main and PRs.
|
|
77
|
+
|
|
59
78
|
## Adding a New Command
|
|
60
79
|
|
|
61
80
|
1. Create or extend a file in `src/clickup_cli/commands/`
|
|
@@ -74,3 +93,24 @@ ruff check src/ tests/
|
|
|
74
93
|
- Stdout is always JSON. Errors and warnings go to stderr.
|
|
75
94
|
- Every mutation supports `--dry-run`
|
|
76
95
|
- Config is lazy-loaded — the `init` command works without any config file
|
|
96
|
+
|
|
97
|
+
## Automations
|
|
98
|
+
|
|
99
|
+
Hooks, skills, and subagents in `.claude/`:
|
|
100
|
+
|
|
101
|
+
**Hooks** (`settings.json`):
|
|
102
|
+
- PostToolUse: ruff auto-lint/format on `.py` edits
|
|
103
|
+
- PostToolUse: auto-run affected test file on source edits
|
|
104
|
+
- PreToolUse: block `.env`/`.pem`/`.key`/credentials edits
|
|
105
|
+
- PreToolUse: block `pyproject.toml` edits (requires explicit approval)
|
|
106
|
+
|
|
107
|
+
**Skills** (`skills/`):
|
|
108
|
+
- `add-command` — step-by-step workflow for adding new CLI commands
|
|
109
|
+
- `clickup-cli` — usage guide for the CLI itself
|
|
110
|
+
- `release` — version bump, build, PyPI publish workflow
|
|
111
|
+
- `validate-output` — verify JSON stdout contract across all commands
|
|
112
|
+
- `changelog` — generate categorized release notes from git log
|
|
113
|
+
|
|
114
|
+
**Subagents** (`agents/`):
|
|
115
|
+
- `test-writer` — generate pytest tests following existing patterns
|
|
116
|
+
- `api-compatibility-checker` — cross-ref CLI endpoints against ClickUp API docs
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
# Contributing
|
|
2
|
+
|
|
3
|
+
Thanks for your interest in clickup-cli.
|
|
4
|
+
|
|
5
|
+
## Getting Started
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
git clone https://github.com/efetoker/clickup-cli.git
|
|
9
|
+
cd clickup-cli
|
|
10
|
+
pip install -e ".[dev]"
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
## Running Tests
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
pytest -v
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
All tests must pass before submitting a PR.
|
|
20
|
+
|
|
21
|
+
## Linting
|
|
22
|
+
|
|
23
|
+
```bash
|
|
24
|
+
ruff check src/ tests/
|
|
25
|
+
ruff format src/ tests/
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
## Guidelines
|
|
29
|
+
|
|
30
|
+
- **JSON stdout, errors to stderr** — all commands follow this convention
|
|
31
|
+
- **Dry-run on mutations** — every mutating command must support `--dry-run`
|
|
32
|
+
- **Help text is documentation** — `--help` should be self-sufficient for discovering usage
|
|
33
|
+
- **No workspace-specific values** — help text and source must not contain hardcoded workspace IDs, space names, or user data
|
|
34
|
+
- **Tests required** — new commands need test coverage in `tests/`
|
|
35
|
+
|
|
36
|
+
## Adding a New Command
|
|
37
|
+
|
|
38
|
+
1. Create or extend a file in `src/clickup_cli/commands/`
|
|
39
|
+
2. Implement `register_parser()` and handler functions in the same module
|
|
40
|
+
3. Register the handler in `commands/__init__.py`
|
|
41
|
+
4. Use `add_id_argument()` from `helpers.py` for positional ID arguments (provides both positional and `--flag` forms)
|
|
42
|
+
5. Add `--help` text with description and usage examples
|
|
43
|
+
6. Add tests in `tests/`
|
|
44
|
+
|
|
45
|
+
## Submitting Changes
|
|
46
|
+
|
|
47
|
+
1. Fork the repo and create a feature branch
|
|
48
|
+
2. Make your changes with tests
|
|
49
|
+
3. Run `pytest -v` and `ruff check src/ tests/`
|
|
50
|
+
4. Open a PR with a clear description of what changed and why
|
|
51
|
+
|
|
52
|
+
## License
|
|
53
|
+
|
|
54
|
+
By contributing, you agree that your contributions will be licensed under the MIT License.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: clickup-cli
|
|
3
|
-
Version: 1.
|
|
3
|
+
Version: 1.4.0
|
|
4
4
|
Summary: The missing ClickUp CLI. Built for developers and AI agents.
|
|
5
5
|
Project-URL: Homepage, https://github.com/efetoker/clickup-cli
|
|
6
6
|
Project-URL: Repository, https://github.com/efetoker/clickup-cli
|
|
@@ -32,6 +32,10 @@ Description-Content-Type: text/markdown
|
|
|
32
32
|
|
|
33
33
|
# clickup-cli
|
|
34
34
|
|
|
35
|
+
[](https://pypi.org/project/clickup-cli/)
|
|
36
|
+
[](https://pypi.org/project/clickup-cli/)
|
|
37
|
+
[](LICENSE)
|
|
38
|
+
|
|
35
39
|
The missing ClickUp CLI. Built for developers and AI agents.
|
|
36
40
|
|
|
37
41
|
There's no official ClickUp CLI. If you're a developer who lives in the terminal, or an AI agent that needs structured data from ClickUp, this fills the gap. JSON stdout, errors to stderr, dry-run on every mutation.
|
|
@@ -127,7 +131,6 @@ clickup tasks list --space <name> --pretty
|
|
|
127
131
|
- **`tasks create`** auto-infers `--space` from `--list` via API lookup. You can omit `--space` if `--list` is provided.
|
|
128
132
|
- **`tasks get`** auto-fetches comments and appends them to the output. Use `--no-comments` to skip.
|
|
129
133
|
- **`tasks search`** auto-detects task ID patterns like `PROJ-39` and applies prefix filtering.
|
|
130
|
-
- **`tasks create`** checks for duplicates before creating. Use `--skip-dedup` to bypass.
|
|
131
134
|
- **`docs edit-page --append`** reads the current page content, appends your new content, and sends one update.
|
|
132
135
|
- **Tag names** are auto-lowercased (ClickUp API stores them lowercase regardless of UI display).
|
|
133
136
|
- **Doc ID ≠ page ID.** Always use `docs pages <doc_id>` to discover page IDs before using `get-page` or `edit-page`.
|
|
@@ -145,11 +148,7 @@ clickup tasks list --space <name> --pretty
|
|
|
145
148
|
"user_id": "67890",
|
|
146
149
|
"spaces": {
|
|
147
150
|
"myspace": {"space_id": "111", "list_id": "222"}
|
|
148
|
-
}
|
|
149
|
-
"default_tags": [],
|
|
150
|
-
"draft_tag": "draft",
|
|
151
|
-
"good_as_is_tag": "good as is",
|
|
152
|
-
"default_priority": 4
|
|
151
|
+
}
|
|
153
152
|
}
|
|
154
153
|
```
|
|
155
154
|
|
|
@@ -1,5 +1,9 @@
|
|
|
1
1
|
# clickup-cli
|
|
2
2
|
|
|
3
|
+
[](https://pypi.org/project/clickup-cli/)
|
|
4
|
+
[](https://pypi.org/project/clickup-cli/)
|
|
5
|
+
[](LICENSE)
|
|
6
|
+
|
|
3
7
|
The missing ClickUp CLI. Built for developers and AI agents.
|
|
4
8
|
|
|
5
9
|
There's no official ClickUp CLI. If you're a developer who lives in the terminal, or an AI agent that needs structured data from ClickUp, this fills the gap. JSON stdout, errors to stderr, dry-run on every mutation.
|
|
@@ -95,7 +99,6 @@ clickup tasks list --space <name> --pretty
|
|
|
95
99
|
- **`tasks create`** auto-infers `--space` from `--list` via API lookup. You can omit `--space` if `--list` is provided.
|
|
96
100
|
- **`tasks get`** auto-fetches comments and appends them to the output. Use `--no-comments` to skip.
|
|
97
101
|
- **`tasks search`** auto-detects task ID patterns like `PROJ-39` and applies prefix filtering.
|
|
98
|
-
- **`tasks create`** checks for duplicates before creating. Use `--skip-dedup` to bypass.
|
|
99
102
|
- **`docs edit-page --append`** reads the current page content, appends your new content, and sends one update.
|
|
100
103
|
- **Tag names** are auto-lowercased (ClickUp API stores them lowercase regardless of UI display).
|
|
101
104
|
- **Doc ID ≠ page ID.** Always use `docs pages <doc_id>` to discover page IDs before using `get-page` or `edit-page`.
|
|
@@ -113,11 +116,7 @@ clickup tasks list --space <name> --pretty
|
|
|
113
116
|
"user_id": "67890",
|
|
114
117
|
"spaces": {
|
|
115
118
|
"myspace": {"space_id": "111", "list_id": "222"}
|
|
116
|
-
}
|
|
117
|
-
"default_tags": [],
|
|
118
|
-
"draft_tag": "draft",
|
|
119
|
-
"good_as_is_tag": "good as is",
|
|
120
|
-
"default_priority": 4
|
|
119
|
+
}
|
|
121
120
|
}
|
|
122
121
|
```
|
|
123
122
|
|
|
@@ -100,8 +100,8 @@ class ClickUpClient:
|
|
|
100
100
|
def put_v2(self, path, data=None):
|
|
101
101
|
return self._request("PUT", f"{self.BASE_V2}{path}", json=data)
|
|
102
102
|
|
|
103
|
-
def delete_v2(self, path):
|
|
104
|
-
return self._request("DELETE", f"{self.BASE_V2}{path}")
|
|
103
|
+
def delete_v2(self, path, params=None):
|
|
104
|
+
return self._request("DELETE", f"{self.BASE_V2}{path}", params=params)
|
|
105
105
|
|
|
106
106
|
def get_v3(self, path, params=None, allow_dry_run=False):
|
|
107
107
|
return self._request(
|
|
@@ -4,6 +4,7 @@ from .tasks import (
|
|
|
4
4
|
cmd_tasks_list, cmd_tasks_get, cmd_tasks_create,
|
|
5
5
|
cmd_tasks_update, cmd_tasks_search,
|
|
6
6
|
cmd_tasks_delete, cmd_tasks_move, cmd_tasks_merge,
|
|
7
|
+
cmd_tasks_depend,
|
|
7
8
|
)
|
|
8
9
|
from .comments import (
|
|
9
10
|
cmd_comments_list, cmd_comments_add,
|
|
@@ -37,6 +38,7 @@ HANDLERS = {
|
|
|
37
38
|
"tasks_delete": cmd_tasks_delete,
|
|
38
39
|
"tasks_move": cmd_tasks_move,
|
|
39
40
|
"tasks_merge": cmd_tasks_merge,
|
|
41
|
+
"tasks_depend": cmd_tasks_depend,
|
|
40
42
|
"comments_list": cmd_comments_list,
|
|
41
43
|
"comments_add": cmd_comments_add,
|
|
42
44
|
"comments_update": cmd_comments_update,
|
|
@@ -55,9 +55,10 @@ examples:
|
|
|
55
55
|
)
|
|
56
56
|
fl.add_argument(
|
|
57
57
|
"--space",
|
|
58
|
+
metavar="SPACE_NAME_OR_ID",
|
|
58
59
|
required=True,
|
|
59
60
|
type=str,
|
|
60
|
-
help="Space name (from config) or raw space ID",
|
|
61
|
+
help="Space name (from config) or raw ClickUp space ID",
|
|
61
62
|
)
|
|
62
63
|
|
|
63
64
|
# folders get
|
|
@@ -101,9 +102,10 @@ examples:
|
|
|
101
102
|
)
|
|
102
103
|
fc.add_argument(
|
|
103
104
|
"--space",
|
|
105
|
+
metavar="SPACE_NAME_OR_ID",
|
|
104
106
|
required=True,
|
|
105
107
|
type=str,
|
|
106
|
-
help="Space name (from config) or raw space ID",
|
|
108
|
+
help="Space name (from config) or raw ClickUp space ID",
|
|
107
109
|
)
|
|
108
110
|
fc.add_argument("--name", required=True, help="Folder name (required)")
|
|
109
111
|
|
|
@@ -61,12 +61,16 @@ notes:
|
|
|
61
61
|
)
|
|
62
62
|
ll_target = ll.add_mutually_exclusive_group(required=True)
|
|
63
63
|
ll_target.add_argument(
|
|
64
|
-
"--folder",
|
|
64
|
+
"--folder",
|
|
65
|
+
metavar="FOLDER_ID",
|
|
66
|
+
type=str,
|
|
67
|
+
help="Raw ClickUp folder ID — list all lists inside this folder",
|
|
65
68
|
)
|
|
66
69
|
ll_target.add_argument(
|
|
67
70
|
"--space",
|
|
71
|
+
metavar="SPACE_NAME_OR_ID",
|
|
68
72
|
type=str,
|
|
69
|
-
help="Space name or ID — list folderless lists
|
|
73
|
+
help="Space name (from config) or raw ClickUp space ID — list folderless lists",
|
|
70
74
|
)
|
|
71
75
|
|
|
72
76
|
# lists get
|
|
@@ -119,12 +123,16 @@ notes:
|
|
|
119
123
|
)
|
|
120
124
|
lc_target = lc.add_mutually_exclusive_group(required=True)
|
|
121
125
|
lc_target.add_argument(
|
|
122
|
-
"--folder",
|
|
126
|
+
"--folder",
|
|
127
|
+
metavar="FOLDER_ID",
|
|
128
|
+
type=str,
|
|
129
|
+
help="Raw ClickUp folder ID — create list inside this folder",
|
|
123
130
|
)
|
|
124
131
|
lc_target.add_argument(
|
|
125
132
|
"--space",
|
|
133
|
+
metavar="SPACE_NAME_OR_ID",
|
|
126
134
|
type=str,
|
|
127
|
-
help="Space name or ID —
|
|
135
|
+
help="Space name (from config) or raw ClickUp space ID — folderless list",
|
|
128
136
|
)
|
|
129
137
|
lc.add_argument("--name", required=True, help="List name (required)")
|
|
130
138
|
lc.add_argument("--content", type=str, help="List description/content")
|