clickup-cli 1.2.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.2.0/.claude/agents/test-writer.md +39 -0
- clickup_cli-1.2.0/.claude/settings.json +26 -0
- clickup_cli-1.2.0/.claude/skills/add-command.md +75 -0
- clickup_cli-1.2.0/.claude/skills/clickup-cli.md +93 -0
- clickup_cli-1.2.0/.claude/skills/release/SKILL.md +66 -0
- clickup_cli-1.2.0/.github/workflows/ci.yml +31 -0
- clickup_cli-1.2.0/.gitignore +36 -0
- clickup_cli-1.2.0/.mcp.json +8 -0
- clickup_cli-1.2.0/CHANGELOG.md +59 -0
- clickup_cli-1.2.0/CLAUDE.md +76 -0
- clickup_cli-1.2.0/LICENSE +21 -0
- clickup_cli-1.2.0/PKG-INFO +204 -0
- clickup_cli-1.2.0/README.md +172 -0
- clickup_cli-1.2.0/clickup-config.example.json +12 -0
- clickup_cli-1.2.0/pyproject.toml +54 -0
- clickup_cli-1.2.0/scripts/validate-cli-output.sh +89 -0
- clickup_cli-1.2.0/src/clickup_cli/__init__.py +3 -0
- clickup_cli-1.2.0/src/clickup_cli/__main__.py +5 -0
- clickup_cli-1.2.0/src/clickup_cli/cli.py +176 -0
- clickup_cli-1.2.0/src/clickup_cli/client.py +115 -0
- clickup_cli-1.2.0/src/clickup_cli/commands/__init__.py +71 -0
- clickup_cli-1.2.0/src/clickup_cli/commands/comments.py +278 -0
- clickup_cli-1.2.0/src/clickup_cli/commands/docs.py +441 -0
- clickup_cli-1.2.0/src/clickup_cli/commands/folders.py +202 -0
- clickup_cli-1.2.0/src/clickup_cli/commands/init.py +153 -0
- clickup_cli-1.2.0/src/clickup_cli/commands/lists.py +258 -0
- clickup_cli-1.2.0/src/clickup_cli/commands/spaces.py +137 -0
- clickup_cli-1.2.0/src/clickup_cli/commands/tags.py +132 -0
- clickup_cli-1.2.0/src/clickup_cli/commands/tasks.py +733 -0
- clickup_cli-1.2.0/src/clickup_cli/commands/team.py +114 -0
- clickup_cli-1.2.0/src/clickup_cli/config.py +200 -0
- clickup_cli-1.2.0/src/clickup_cli/helpers.py +163 -0
- clickup_cli-1.2.0/tests/conftest.py +29 -0
- clickup_cli-1.2.0/tests/test_cli.py +1123 -0
- clickup_cli-1.2.0/tests/test_client.py +314 -0
- clickup_cli-1.2.0/tests/test_commands.py +1399 -0
- clickup_cli-1.2.0/tests/test_config.py +331 -0
- clickup_cli-1.2.0/tests/test_helpers.py +228 -0
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: test-writer
|
|
3
|
+
description: Generate pytest tests for clickup-cli commands following existing test patterns in tests/test_cli.py
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Test Writer Agent
|
|
7
|
+
|
|
8
|
+
You generate pytest tests for the clickup-cli project.
|
|
9
|
+
|
|
10
|
+
## Before Writing Tests
|
|
11
|
+
|
|
12
|
+
1. Read `tests/conftest.py` for the test config setup pattern
|
|
13
|
+
2. Read `tests/test_cli.py` for existing patterns (FakeClient, Namespace, etc.)
|
|
14
|
+
3. Read the source file you're writing tests for
|
|
15
|
+
|
|
16
|
+
## Conventions
|
|
17
|
+
|
|
18
|
+
- Use `unittest.TestCase` classes (matching existing style)
|
|
19
|
+
- Use `FakeClient` for API call mocking — do NOT make real HTTP calls
|
|
20
|
+
- Use `unittest.mock.patch` and `MagicMock` for things FakeClient doesn't cover
|
|
21
|
+
- Use `argparse.Namespace` to construct fake args
|
|
22
|
+
- Test these for every command:
|
|
23
|
+
- Argument parsing (parser accepts the expected args)
|
|
24
|
+
- `--dry-run` behavior (mutating commands return preview, don't call API)
|
|
25
|
+
- Normal execution with mocked responses
|
|
26
|
+
- Error cases (missing required args, API errors)
|
|
27
|
+
- All output assertions should check JSON structure
|
|
28
|
+
- Put tests in `tests/test_cli.py` or a new `tests/test_<group>.py` file
|
|
29
|
+
|
|
30
|
+
## Example Pattern
|
|
31
|
+
|
|
32
|
+
```python
|
|
33
|
+
class TestTasksSearch(unittest.TestCase):
|
|
34
|
+
def test_search_dry_run(self):
|
|
35
|
+
client = FakeClient(dry_run=True)
|
|
36
|
+
args = Namespace(query="test", space="testspace", ...)
|
|
37
|
+
result = cmd_tasks_search(client, args)
|
|
38
|
+
self.assertIn("dry_run", result)
|
|
39
|
+
```
|
|
@@ -0,0 +1,26 @@
|
|
|
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
|
+
"PreToolUse": [
|
|
15
|
+
{
|
|
16
|
+
"matcher": "Edit|Write",
|
|
17
|
+
"hooks": [
|
|
18
|
+
{
|
|
19
|
+
"type": "command",
|
|
20
|
+
"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"
|
|
21
|
+
}
|
|
22
|
+
]
|
|
23
|
+
}
|
|
24
|
+
]
|
|
25
|
+
}
|
|
26
|
+
}
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: add-command
|
|
3
|
+
description: Step-by-step workflow for adding a new CLI command to clickup-cli, with verification at each step.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Add a New CLI Command
|
|
7
|
+
|
|
8
|
+
Follow these steps in order when adding a new command or subcommand.
|
|
9
|
+
|
|
10
|
+
## 1. Create or extend the command module
|
|
11
|
+
|
|
12
|
+
- If this is a new command group, create `src/clickup_cli/commands/<group>.py`
|
|
13
|
+
- If extending an existing group, add the handler function to the existing file
|
|
14
|
+
- Handler signature: `def cmd_<group>_<command>(client, args):`
|
|
15
|
+
- Return a dict (will be output as JSON)
|
|
16
|
+
- Mutating commands must check `client.dry_run` and return a dry-run preview instead of calling the API
|
|
17
|
+
|
|
18
|
+
## 2. Add or extend the parser in the same module
|
|
19
|
+
|
|
20
|
+
- Each command module owns its parser via `register_parser(subparsers, F)`
|
|
21
|
+
- If extending an existing group, add the new subparser inside the existing `register_parser()`
|
|
22
|
+
- If creating a new group, add a `register_parser(subparsers, F)` function that creates the group parser and all its subparsers
|
|
23
|
+
- Add the subparser with:
|
|
24
|
+
- `description=` — what this command does
|
|
25
|
+
- `epilog=` — usage examples (at least 2)
|
|
26
|
+
- `formatter_class=F` (passed in as argument)
|
|
27
|
+
- Add all arguments with `help=` text
|
|
28
|
+
- For mutating commands, `--dry-run` is handled globally (no per-command flag needed)
|
|
29
|
+
|
|
30
|
+
## 3. Register the handler
|
|
31
|
+
|
|
32
|
+
- Open `src/clickup_cli/commands/__init__.py`
|
|
33
|
+
- Import the new handler function
|
|
34
|
+
- Add it to the `HANDLERS` dict with key `"<group>_<command>"`
|
|
35
|
+
|
|
36
|
+
## 3b. Wire up new command groups in cli.py (new groups only)
|
|
37
|
+
|
|
38
|
+
- If this is a new command group, open `src/clickup_cli/cli.py`
|
|
39
|
+
- Import `register_parser` from the new module
|
|
40
|
+
- Call it in `build_parser()` alongside the other `register_parser()` calls
|
|
41
|
+
|
|
42
|
+
## 4. Write help text
|
|
43
|
+
|
|
44
|
+
- The `--help` output must be self-sufficient for an agent to use the command correctly
|
|
45
|
+
- Include concrete examples in the epilog
|
|
46
|
+
- Never use real workspace IDs, space names, or tokens in examples — use `<placeholders>`
|
|
47
|
+
|
|
48
|
+
## 5. Add tests
|
|
49
|
+
|
|
50
|
+
- Open `tests/test_cli.py` (or create a new test file if the group is large)
|
|
51
|
+
- Test argument parsing (parser accepts the new args)
|
|
52
|
+
- Test dry-run behavior (mutating commands return dry-run preview)
|
|
53
|
+
- Test core logic with `FakeClient`
|
|
54
|
+
|
|
55
|
+
## 6. Verify
|
|
56
|
+
|
|
57
|
+
Run these commands and confirm all pass before considering the work done:
|
|
58
|
+
|
|
59
|
+
```bash
|
|
60
|
+
# Lint
|
|
61
|
+
ruff check src/ tests/
|
|
62
|
+
|
|
63
|
+
# Tests
|
|
64
|
+
pytest -v
|
|
65
|
+
|
|
66
|
+
# Help text renders correctly
|
|
67
|
+
clickup <group> <command> --help
|
|
68
|
+
|
|
69
|
+
# Validate CLI output contract
|
|
70
|
+
scripts/validate-cli-output.sh
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
## 7. Update the skill (if needed)
|
|
74
|
+
|
|
75
|
+
If the new command adds a new workflow pattern, update `.claude/skills/clickup-cli.md` with a usage example.
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: clickup-cli
|
|
3
|
+
description: Use the clickup CLI to manage ClickUp tasks, comments, docs, folders, lists, spaces, and tags from the command line. JSON output, dry-run support.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# ClickUp CLI Skill
|
|
7
|
+
|
|
8
|
+
You have access to the `clickup` CLI for managing ClickUp workspaces.
|
|
9
|
+
|
|
10
|
+
## Discovery
|
|
11
|
+
|
|
12
|
+
Always start by discovering available commands:
|
|
13
|
+
|
|
14
|
+
```bash
|
|
15
|
+
clickup --help # list all command groups
|
|
16
|
+
clickup <group> --help # list subcommands in a group
|
|
17
|
+
clickup <group> <command> --help # full usage for a specific command
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
## Safety
|
|
21
|
+
|
|
22
|
+
Before any mutating command (create, update, delete), use `--dry-run`:
|
|
23
|
+
|
|
24
|
+
```bash
|
|
25
|
+
clickup --dry-run tasks create --space <space_name> --name "New task"
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
Global flags (`--pretty`, `--dry-run`, `--debug`) can appear before or after the command group.
|
|
29
|
+
|
|
30
|
+
## Output
|
|
31
|
+
|
|
32
|
+
- Successful output is always JSON on stdout
|
|
33
|
+
- Errors go to stderr with non-zero exit code
|
|
34
|
+
- Use `--pretty` for indented JSON when reading output
|
|
35
|
+
- Use `--full` on task list/search for raw API response
|
|
36
|
+
|
|
37
|
+
## Common Workflows
|
|
38
|
+
|
|
39
|
+
### Find and read a task
|
|
40
|
+
```bash
|
|
41
|
+
clickup tasks search "login bug" --space <space_name>
|
|
42
|
+
clickup tasks get <task_id>
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
### Create a task
|
|
46
|
+
```bash
|
|
47
|
+
clickup --dry-run tasks create --space <space_name> --name "Fix auth" --desc "Details"
|
|
48
|
+
clickup tasks create --space <space_name> --name "Fix auth" --desc "Details"
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
### Add a comment
|
|
52
|
+
```bash
|
|
53
|
+
clickup comments add <task_id> --text "Work complete"
|
|
54
|
+
clickup comments add <task_id> --file report.md
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
### Read and edit docs
|
|
58
|
+
```bash
|
|
59
|
+
clickup docs list --space <space_name>
|
|
60
|
+
clickup docs pages <doc_id>
|
|
61
|
+
clickup docs get-page <doc_id> <page_id>
|
|
62
|
+
clickup docs edit-page <doc_id> <page_id> --content-file updated.md
|
|
63
|
+
clickup docs edit-page <doc_id> <page_id> --content "New section" --append
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
### Discover workspace structure
|
|
67
|
+
```bash
|
|
68
|
+
clickup spaces list
|
|
69
|
+
clickup folders list --space <space_name>
|
|
70
|
+
clickup lists list --folder <folder_id>
|
|
71
|
+
clickup spaces statuses <space_name>
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
## Configuration
|
|
75
|
+
|
|
76
|
+
The CLI loads config from (in order):
|
|
77
|
+
1. `CLICKUP_CONFIG_PATH` env var
|
|
78
|
+
2. `~/.config/clickup-cli/config.json`
|
|
79
|
+
3. `clickup-config.json` in current directory
|
|
80
|
+
|
|
81
|
+
Or use environment variables only:
|
|
82
|
+
- `CLICKUP_API_TOKEN` (required)
|
|
83
|
+
- `CLICKUP_WORKSPACE_ID` (auto-detected for single-workspace accounts)
|
|
84
|
+
|
|
85
|
+
Run `clickup init` for interactive setup.
|
|
86
|
+
|
|
87
|
+
## Key Behaviors
|
|
88
|
+
|
|
89
|
+
- `tasks get` auto-fetches comments (use `--no-comments` to skip)
|
|
90
|
+
- `tasks search` auto-detects task ID patterns (e.g. "PROJ-39") and applies prefix filtering
|
|
91
|
+
- `tasks create` checks for duplicates before creating (use `--skip-dedup` to bypass)
|
|
92
|
+
- Tag names are auto-lowercased (ClickUp API requirement)
|
|
93
|
+
- Doc ID ≠ page ID — always use `docs pages` to find page IDs first
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: release
|
|
3
|
+
description: Bump version, validate, tag, and build for PyPI release
|
|
4
|
+
disable-model-invocation: true
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# Release Workflow
|
|
8
|
+
|
|
9
|
+
Follow these steps to publish a new release of clickup-cli.
|
|
10
|
+
|
|
11
|
+
## 1. Pre-flight checks
|
|
12
|
+
|
|
13
|
+
```bash
|
|
14
|
+
ruff check src/ tests/
|
|
15
|
+
pytest -v
|
|
16
|
+
clickup --help # smoke test
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
All must pass before proceeding.
|
|
20
|
+
|
|
21
|
+
## 2. Bump version
|
|
22
|
+
|
|
23
|
+
The version is in `src/clickup_cli/__init__.py`. Update it following semver:
|
|
24
|
+
- **patch** (0.x.Y): bug fixes
|
|
25
|
+
- **minor** (0.X.0): new commands or features
|
|
26
|
+
- **major** (X.0.0): breaking changes
|
|
27
|
+
|
|
28
|
+
## 3. Update changelog
|
|
29
|
+
|
|
30
|
+
If `CHANGELOG.md` exists, add an entry for the new version with a summary of changes since the last tag:
|
|
31
|
+
|
|
32
|
+
```bash
|
|
33
|
+
git log $(git describe --tags --abbrev=0)..HEAD --oneline
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
## 4. Commit and tag
|
|
37
|
+
|
|
38
|
+
```bash
|
|
39
|
+
git add -A
|
|
40
|
+
git commit -m "release: v<version>"
|
|
41
|
+
git tag v<version>
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
## 5. Build
|
|
45
|
+
|
|
46
|
+
```bash
|
|
47
|
+
pip install build
|
|
48
|
+
python -m build
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
Verify the dist/ output looks correct (check file sizes, version in filenames).
|
|
52
|
+
|
|
53
|
+
## 6. Publish (requires user confirmation)
|
|
54
|
+
|
|
55
|
+
**Ask the user before running this step.**
|
|
56
|
+
|
|
57
|
+
```bash
|
|
58
|
+
pip install twine
|
|
59
|
+
twine upload dist/*
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
## 7. Push
|
|
63
|
+
|
|
64
|
+
```bash
|
|
65
|
+
git push origin main --tags
|
|
66
|
+
```
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
name: CI
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches: [main]
|
|
6
|
+
pull_request:
|
|
7
|
+
branches: [main]
|
|
8
|
+
|
|
9
|
+
jobs:
|
|
10
|
+
test:
|
|
11
|
+
runs-on: ubuntu-latest
|
|
12
|
+
strategy:
|
|
13
|
+
matrix:
|
|
14
|
+
python-version: ["3.9", "3.11", "3.13"]
|
|
15
|
+
|
|
16
|
+
steps:
|
|
17
|
+
- uses: actions/checkout@v4
|
|
18
|
+
|
|
19
|
+
- name: Set up Python ${{ matrix.python-version }}
|
|
20
|
+
uses: actions/setup-python@v5
|
|
21
|
+
with:
|
|
22
|
+
python-version: ${{ matrix.python-version }}
|
|
23
|
+
|
|
24
|
+
- name: Install dependencies
|
|
25
|
+
run: pip install -e ".[dev]"
|
|
26
|
+
|
|
27
|
+
- name: Lint
|
|
28
|
+
run: ruff check src/ tests/
|
|
29
|
+
|
|
30
|
+
- name: Test
|
|
31
|
+
run: pytest -v
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
# Python
|
|
2
|
+
__pycache__/
|
|
3
|
+
*.py[cod]
|
|
4
|
+
*$py.class
|
|
5
|
+
*.egg-info/
|
|
6
|
+
dist/
|
|
7
|
+
build/
|
|
8
|
+
*.egg
|
|
9
|
+
|
|
10
|
+
# Virtual environments
|
|
11
|
+
.venv/
|
|
12
|
+
venv/
|
|
13
|
+
env/
|
|
14
|
+
|
|
15
|
+
# Testing
|
|
16
|
+
.pytest_cache/
|
|
17
|
+
.coverage
|
|
18
|
+
htmlcov/
|
|
19
|
+
|
|
20
|
+
# IDE
|
|
21
|
+
.idea/
|
|
22
|
+
.vscode/
|
|
23
|
+
*.swp
|
|
24
|
+
*.swo
|
|
25
|
+
|
|
26
|
+
# Config with real tokens
|
|
27
|
+
clickup-config.json
|
|
28
|
+
.env
|
|
29
|
+
.env.*
|
|
30
|
+
|
|
31
|
+
# Workflow artifacts
|
|
32
|
+
.planning/
|
|
33
|
+
.audit/
|
|
34
|
+
|
|
35
|
+
# Local-only Claude Code settings (permissions, etc.)
|
|
36
|
+
.claude/settings.local.json
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
## 1.2.0 (2026-03-29)
|
|
4
|
+
|
|
5
|
+
- 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
|
+
- 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
|
+
- Make `--space` optional on `tasks create` (was required) — now only required if `--list` is also absent.
|
|
8
|
+
- Expand test suite to 305 tests — full behavioral coverage for `cmd_init` (12 tests), `main()` integration (4 tests), `cmd_docs_create` content paths (3 tests), and 429 retry edge case (1 test).
|
|
9
|
+
- Simplify codebase: use shared `error()` in config.py, DRY up tag add/remove, task list/search epilogue, list folder/space resolution, client retry logic. -24 net lines across 7 files.
|
|
10
|
+
|
|
11
|
+
## 1.1.3 (2026-03-29)
|
|
12
|
+
|
|
13
|
+
- Refactor: split 1633-line `build_parser()` — each command module now owns its parser via `register_parser()`
|
|
14
|
+
- Refactor: extract shared `_paginate_tasks()` helper, removing duplicate pagination logic in tasks list/search
|
|
15
|
+
- Refactor: extract `_extract_status()` and `_extract_priority()` helpers in helpers.py, deduplicating field extraction
|
|
16
|
+
- Clean up dead code in `client.py` (unreachable None guards, pointless variable rename)
|
|
17
|
+
- Expand test suite from 55 to 89 tests — comprehensive parser coverage for all 8 command groups
|
|
18
|
+
- Fix stale version assertion in tests (was checking 1.1.0 instead of current version)
|
|
19
|
+
|
|
20
|
+
## 1.1.2 (2026-03-29)
|
|
21
|
+
|
|
22
|
+
- Add auto-lint hook — ruff check/format runs automatically on every Python file edit
|
|
23
|
+
- Add sensitive file guard — blocks edits to `.env`, `.secret`, `.pem`, `.key`, and credentials files
|
|
24
|
+
- Add context7 MCP server (`.mcp.json`) — live ClickUp API docs for contributors
|
|
25
|
+
- Add `test-writer` subagent (`.claude/agents/`) — generates pytest tests following project patterns
|
|
26
|
+
- Add `/release` skill — version bump, validate, tag, build, publish workflow
|
|
27
|
+
- Clean up permission allowlist in `.claude/settings.local.json`
|
|
28
|
+
|
|
29
|
+
## 1.1.1 (2026-03-29)
|
|
30
|
+
|
|
31
|
+
- Add `.env` and `.env.*` to `.gitignore` for API token safety
|
|
32
|
+
- Add `scripts/validate-cli-output.sh` — validates all CLI help commands, error routing, and version flag
|
|
33
|
+
- Add `.claude/skills/add-command.md` — prescriptive dev workflow for adding new commands
|
|
34
|
+
- Replace hardcoded `myspace` with `<name>` / `<space_name>` placeholders in skill and README
|
|
35
|
+
|
|
36
|
+
## 1.1.0 (2026-03-29)
|
|
37
|
+
|
|
38
|
+
- Auto-detect workspace ID for single-workspace accounts — no need to set it manually
|
|
39
|
+
- Fix user detection in `clickup init` — now prompts for selection in multi-member workspaces
|
|
40
|
+
- workspace_id is saved back to config file after auto-detection
|
|
41
|
+
- Add `--debug` flag — logs API requests and responses to stderr for troubleshooting
|
|
42
|
+
- Improve space name resolution — clear error with available names when a space isn't found in config
|
|
43
|
+
- Fix comment pagination — no longer hardcodes page size assumption
|
|
44
|
+
|
|
45
|
+
## 1.0.0 (2026-03-28)
|
|
46
|
+
|
|
47
|
+
Initial public release.
|
|
48
|
+
|
|
49
|
+
- 8 command groups: tasks, comments, docs, folders, lists, spaces, team, tags
|
|
50
|
+
- Full task CRUD with search, move, merge
|
|
51
|
+
- Full comment CRUD with threading
|
|
52
|
+
- Docs management with page editing
|
|
53
|
+
- Folder and list management
|
|
54
|
+
- Tag management
|
|
55
|
+
- Workspace discovery via `clickup init`
|
|
56
|
+
- JSON-only stdout, errors to stderr
|
|
57
|
+
- Dry-run mode for all mutations
|
|
58
|
+
- Rate limit handling with automatic retry
|
|
59
|
+
- Config via JSON file or environment variables
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
# ClickUp CLI — Development Instructions
|
|
2
|
+
|
|
3
|
+
## What This Is
|
|
4
|
+
|
|
5
|
+
A ClickUp CLI for developers and AI agents. JSON-only stdout, errors to stderr, dry-run on all mutations.
|
|
6
|
+
|
|
7
|
+
## Package Structure
|
|
8
|
+
|
|
9
|
+
```
|
|
10
|
+
src/clickup_cli/
|
|
11
|
+
├── cli.py # root parser, dispatch, main() — delegates to command modules
|
|
12
|
+
├── client.py # ClickUpClient API wrapper (rate limiting, dry-run, debug)
|
|
13
|
+
├── config.py # Config loader (lazy, fallback chain, workspace auto-detect)
|
|
14
|
+
├── helpers.py # output(), error(), compact_task(), etc.
|
|
15
|
+
└── commands/
|
|
16
|
+
├── __init__.py # HANDLERS dict
|
|
17
|
+
├── tasks.py # tasks parser + handlers (list/get/create/update/search/delete/move/merge)
|
|
18
|
+
├── comments.py # comments parser + handlers (list/add/update/delete/thread/reply)
|
|
19
|
+
├── docs.py # docs parser + handlers (list/get/create/pages/get-page/edit-page/create-page)
|
|
20
|
+
├── folders.py # folders parser + handlers (list/get/create/update/delete)
|
|
21
|
+
├── lists.py # lists parser + handlers (list/get/create/update/delete)
|
|
22
|
+
├── spaces.py # spaces parser + handlers (list/get/statuses)
|
|
23
|
+
├── tags.py # tags parser + handlers (list/add/remove)
|
|
24
|
+
├── team.py # team parser + handlers (whoami/members)
|
|
25
|
+
└── init.py # clickup init setup command
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
Each command module owns both its argparse parser definition (`register_parser()`) and its handler functions. `cli.py` builds the root parser and delegates to each module's `register_parser(subparsers, F)`.
|
|
29
|
+
|
|
30
|
+
## Argument Pattern: Positional + Flag Aliases
|
|
31
|
+
|
|
32
|
+
Every positional argument (task_id, query, doc_id, page_id, etc.) also accepts a `--flag` form via `add_id_argument()` from helpers.py. This makes the CLI usable by both humans (positional) and AI agents (flags).
|
|
33
|
+
|
|
34
|
+
```python
|
|
35
|
+
# In register_parser():
|
|
36
|
+
add_id_argument(parser, "task_id", "ClickUp task ID")
|
|
37
|
+
|
|
38
|
+
# Accepts both:
|
|
39
|
+
# clickup tasks get abc123
|
|
40
|
+
# clickup tasks get --task-id abc123
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
Resolution happens in `cli.py` via `resolve_id_args(args)` after parsing. If both forms are provided, it errors. If neither is provided, it errors with a helpful message.
|
|
44
|
+
|
|
45
|
+
When adding new commands with ID arguments, always use `add_id_argument()` instead of `parser.add_argument()` for positional IDs.
|
|
46
|
+
|
|
47
|
+
## Space Inference
|
|
48
|
+
|
|
49
|
+
`tasks create` auto-infers `--space` from `--list` via a lazy API lookup (`GET /v2/list/{id}`). The `_infer_space_from_list()` function in tasks.py reverse-maps the space ID to a config name. This eliminates the most common agent error.
|
|
50
|
+
|
|
51
|
+
## Development Setup
|
|
52
|
+
|
|
53
|
+
```bash
|
|
54
|
+
pip install -e ".[dev]"
|
|
55
|
+
pytest -v
|
|
56
|
+
ruff check src/ tests/
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
## Adding a New Command
|
|
60
|
+
|
|
61
|
+
1. Create or extend a file in `src/clickup_cli/commands/`
|
|
62
|
+
2. Add the handler function and `register_parser()` in the same module
|
|
63
|
+
3. Register the handler in `commands/__init__.py` HANDLERS dict
|
|
64
|
+
4. If it's a new command group, call `register_parser()` from `cli.py`'s `build_parser()`
|
|
65
|
+
5. Add detailed `--help` text (description + epilog with examples)
|
|
66
|
+
6. Mutating commands must support `--dry-run`
|
|
67
|
+
7. All output goes to stdout as JSON, errors to stderr
|
|
68
|
+
8. Add tests in `tests/`
|
|
69
|
+
|
|
70
|
+
## Rules
|
|
71
|
+
|
|
72
|
+
- Help text must be self-sufficient — an agent should use `--help` to discover correct usage
|
|
73
|
+
- No workspace-specific values in help text or source code
|
|
74
|
+
- Stdout is always JSON. Errors and warnings go to stderr.
|
|
75
|
+
- Every mutation supports `--dry-run`
|
|
76
|
+
- Config is lazy-loaded — the `init` command works without any config file
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Efe Toker
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|