@krodak/clickup-cli 0.14.0 → 0.15.0
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.
- package/README.md +160 -485
- package/dist/index.js +258 -4
- package/package.json +1 -1
- package/skills/clickup-cli/SKILL.md +12 -1
package/README.md
CHANGED
|
@@ -8,547 +8,218 @@
|
|
|
8
8
|
[](https://github.com/krodak/clickup-cli/actions/workflows/ci.yml)
|
|
9
9
|
|
|
10
10
|
```bash
|
|
11
|
-
npm install -g @krodak/clickup-cli
|
|
12
|
-
cu init # walks you through API token + workspace setup
|
|
11
|
+
npm install -g @krodak/clickup-cli && cu init
|
|
13
12
|
```
|
|
14
13
|
|
|
15
|
-
|
|
14
|
+
## Talk to your agent
|
|
16
15
|
|
|
17
|
-
|
|
16
|
+
Install `cu`, install the skill file, and your agent works with ClickUp. No API knowledge needed.
|
|
18
17
|
|
|
19
|
-
|
|
18
|
+
> **"Read task abc123, do the work, then mark it in review and leave a comment with the commit hash."**
|
|
20
19
|
|
|
21
|
-
|
|
20
|
+
> **"What's my standup? What did I finish, what's in progress, what's overdue?"**
|
|
22
21
|
|
|
23
|
-
|
|
22
|
+
> **"Create a subtask under the initiative for the edge case we found."**
|
|
24
23
|
|
|
25
|
-
**
|
|
24
|
+
> **"Check my sprint and tell me what's behind schedule."**
|
|
26
25
|
|
|
27
|
-
|
|
26
|
+
> **"Update the description with your findings and flag blockers in a comment."**
|
|
28
27
|
|
|
29
|
-
|
|
30
|
-
claude --plugin-dir ./node_modules/@krodak/clickup-cli
|
|
31
|
-
```
|
|
32
|
-
|
|
33
|
-
Or copy the skill manually:
|
|
34
|
-
|
|
35
|
-
```bash
|
|
36
|
-
mkdir -p ~/.claude/skills/clickup
|
|
37
|
-
cp skills/clickup-cli/SKILL.md ~/.claude/skills/clickup/SKILL.md
|
|
38
|
-
```
|
|
39
|
-
|
|
40
|
-
Then reference it in your `CLAUDE.md` or project instructions.
|
|
41
|
-
|
|
42
|
-
**OpenCode:**
|
|
43
|
-
|
|
44
|
-
```bash
|
|
45
|
-
mkdir -p ~/.config/opencode/skills/clickup
|
|
46
|
-
cp skills/clickup-cli/SKILL.md ~/.config/opencode/skills/clickup/SKILL.md
|
|
47
|
-
```
|
|
48
|
-
|
|
49
|
-
**Codex / other agents:**
|
|
50
|
-
|
|
51
|
-
Copy the contents of `skills/clickup-cli/SKILL.md` into your system prompt or project instructions. It's a standalone markdown document.
|
|
52
|
-
|
|
53
|
-
### 2. Talk to your agent
|
|
54
|
-
|
|
55
|
-
Once the skill is installed, you just tell the agent what you need in plain language. It figures out which `cu` commands to run.
|
|
56
|
-
|
|
57
|
-
```
|
|
58
|
-
"Read the description of task <id>, do the work, then mark it in review and leave a comment with the commit hash."
|
|
59
|
-
|
|
60
|
-
"Check all subtasks under initiative <id> and improve their descriptions based on what's in the codebase."
|
|
61
|
-
|
|
62
|
-
"What's my standup summary? What did I finish yesterday, what's in progress, what's overdue?"
|
|
28
|
+
The agent reads the skill file, picks the right `cu` commands, and handles everything. You don't need to learn the CLI - the agent does.
|
|
63
29
|
|
|
64
|
-
|
|
30
|
+
## Setup
|
|
65
31
|
|
|
66
|
-
|
|
32
|
+
You need Node 22+ and a ClickUp personal API token (`pk_...` from [ClickUp Settings > Apps](https://app.clickup.com/settings/apps)).
|
|
67
33
|
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
You don't need to learn the CLI commands yourself. The agent handles it.
|
|
72
|
-
|
|
73
|
-
### Why a CLI and not MCP?
|
|
74
|
-
|
|
75
|
-
A CLI + skill file has fewer moving parts. No extra server process, no protocol layer. The agent already knows how to run shell commands - the skill file just teaches it which ones exist. This matches what Peter Steinberger and the OpenClaw project have found: for tool-use with coding agents, CLI + instructions tends to work better than MCP in practice.
|
|
76
|
-
|
|
77
|
-
### Scoped output
|
|
78
|
-
|
|
79
|
-
Most commands return only your tasks by default. `cu tasks`, `cu sprint`, `cu overdue`, `cu summary` all scope to what's assigned to you. `cu spaces --my` filters to spaces where you have tasks. This keeps output small and relevant - important when it's going into an agent's context window.
|
|
80
|
-
|
|
81
|
-
## Using from the terminal
|
|
82
|
-
|
|
83
|
-
When you run `cu` in a terminal directly, you get an interactive mode with tables and a task picker.
|
|
84
|
-
|
|
85
|
-
```bash
|
|
86
|
-
cu tasks # interactive table with checkbox picker
|
|
87
|
-
cu sprint # your sprint tasks, auto-detected
|
|
88
|
-
cu summary # standup helper: completed / in progress / overdue
|
|
89
|
-
cu overdue # tasks past their due date
|
|
90
|
-
cu open "login bug" # fuzzy search, opens in browser
|
|
91
|
-
cu update abc123 -s "done" # update status
|
|
92
|
-
cu assign abc123 --to me # assign yourself
|
|
93
|
-
```
|
|
34
|
+
<details open>
|
|
35
|
+
<summary> <img src="https://cdn.simpleicons.org/openai/999999" height="16" align="center"> <strong>OpenCode</strong></summary>
|
|
94
36
|
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
When output is piped (no TTY), all commands output **Markdown** by default - optimized for AI agent context windows. Pass `--json` to any command for JSON output. Set `CU_OUTPUT=json` environment variable to always get JSON when piped.
|
|
98
|
-
|
|
99
|
-
## Commands
|
|
100
|
-
|
|
101
|
-
31 commands total. All support `--help` for full flag details.
|
|
102
|
-
|
|
103
|
-
### `cu init`
|
|
104
|
-
|
|
105
|
-
First-time setup. Prompts for your API token, verifies it, auto-detects your workspace, and writes `~/.config/cu/config.json`.
|
|
37
|
+
**1. Install the CLI**
|
|
106
38
|
|
|
107
39
|
```bash
|
|
40
|
+
npm install -g @krodak/clickup-cli
|
|
108
41
|
cu init
|
|
109
42
|
```
|
|
110
43
|
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
List tasks assigned to me. By default shows all task types. Use `--type` to filter by task type.
|
|
114
|
-
|
|
115
|
-
```bash
|
|
116
|
-
cu tasks
|
|
117
|
-
cu tasks --status "in progress"
|
|
118
|
-
cu tasks --name "login"
|
|
119
|
-
cu tasks --type task # regular tasks only
|
|
120
|
-
cu tasks --type initiative # initiatives only
|
|
121
|
-
cu tasks --type "Bug" # custom task type by name
|
|
122
|
-
cu tasks --list <listId>
|
|
123
|
-
cu tasks --space <spaceId>
|
|
124
|
-
cu tasks --include-closed
|
|
125
|
-
cu tasks --json
|
|
126
|
-
```
|
|
127
|
-
|
|
128
|
-
### `cu sprint`
|
|
129
|
-
|
|
130
|
-
List my tasks in the currently active sprint (auto-detected from sprint folder date ranges).
|
|
131
|
-
|
|
132
|
-
```bash
|
|
133
|
-
cu sprint
|
|
134
|
-
cu sprint --status "in progress"
|
|
135
|
-
cu sprint --include-closed
|
|
136
|
-
cu sprint --json
|
|
137
|
-
```
|
|
138
|
-
|
|
139
|
-
### `cu sprints`
|
|
140
|
-
|
|
141
|
-
List all sprints across sprint folders. Marks the currently active sprint.
|
|
142
|
-
|
|
143
|
-
```bash
|
|
144
|
-
cu sprints
|
|
145
|
-
cu sprints --space "Engineering"
|
|
146
|
-
cu sprints --json
|
|
147
|
-
```
|
|
148
|
-
|
|
149
|
-
### `cu assigned`
|
|
150
|
-
|
|
151
|
-
All tasks assigned to me, grouped by pipeline stage (code review, in progress, to do, etc.).
|
|
152
|
-
|
|
153
|
-
```bash
|
|
154
|
-
cu assigned
|
|
155
|
-
cu assigned --status "in progress"
|
|
156
|
-
cu assigned --include-closed
|
|
157
|
-
cu assigned --json
|
|
158
|
-
```
|
|
159
|
-
|
|
160
|
-
### `cu inbox`
|
|
161
|
-
|
|
162
|
-
Tasks assigned to me that were recently updated, grouped by time period (today, yesterday, last 7 days, etc.). Default lookback is 30 days.
|
|
163
|
-
|
|
164
|
-
```bash
|
|
165
|
-
cu inbox
|
|
166
|
-
cu inbox --days 7
|
|
167
|
-
cu inbox --include-closed
|
|
168
|
-
cu inbox --json
|
|
169
|
-
```
|
|
170
|
-
|
|
171
|
-
### `cu task <id>`
|
|
172
|
-
|
|
173
|
-
Get task details including custom fields and checklists. Pretty summary in terminal, JSON when piped.
|
|
174
|
-
|
|
175
|
-
```bash
|
|
176
|
-
cu task abc123
|
|
177
|
-
cu task abc123 --json
|
|
178
|
-
```
|
|
179
|
-
|
|
180
|
-
**Note:** When piped, `cu task` outputs a structured Markdown summary of the task. For the full raw API response with all fields (custom fields, checklists, etc.), use `--json`.
|
|
181
|
-
|
|
182
|
-
### `cu subtasks <id>`
|
|
183
|
-
|
|
184
|
-
List subtasks of a task.
|
|
185
|
-
|
|
186
|
-
```bash
|
|
187
|
-
cu subtasks abc123
|
|
188
|
-
cu subtasks abc123 --status "in progress"
|
|
189
|
-
cu subtasks abc123 --name "auth"
|
|
190
|
-
cu subtasks abc123 --include-closed
|
|
191
|
-
cu subtasks abc123 --json
|
|
192
|
-
```
|
|
193
|
-
|
|
194
|
-
### `cu update <id>`
|
|
195
|
-
|
|
196
|
-
Update a task. Provide at least one option.
|
|
197
|
-
|
|
198
|
-
```bash
|
|
199
|
-
cu update abc123 -s "in progress"
|
|
200
|
-
cu update abc123 -n "New task name"
|
|
201
|
-
cu update abc123 -d "Updated description with **markdown**"
|
|
202
|
-
cu update abc123 --priority high
|
|
203
|
-
cu update abc123 --due-date 2025-03-15
|
|
204
|
-
cu update abc123 --assignee me
|
|
205
|
-
cu update abc123 --assignee 12345
|
|
206
|
-
cu update abc123 -n "New name" -s "done" --priority urgent
|
|
207
|
-
cu update abc123 --time-estimate 2h
|
|
208
|
-
cu update abc123 --parent parentTaskId # make it a subtask
|
|
209
|
-
cu update abc123 -s "in progress" --json
|
|
210
|
-
```
|
|
211
|
-
|
|
212
|
-
| Flag | Description |
|
|
213
|
-
| ---------------------------- | --------------------------------------------------------------------------- |
|
|
214
|
-
| `-n, --name <text>` | New task name |
|
|
215
|
-
| `-d, --description <text>` | New description (markdown supported) |
|
|
216
|
-
| `-s, --status <status>` | New status, supports fuzzy matching (e.g. `"prog"` matches `"in progress"`) |
|
|
217
|
-
| `--priority <level>` | Priority: `urgent`, `high`, `normal`, `low` (or 1-4) |
|
|
218
|
-
| `--due-date <date>` | Due date (`YYYY-MM-DD`) |
|
|
219
|
-
| `--time-estimate <duration>` | Time estimate (e.g. `"2h"`, `"30m"`, `"1h30m"`) |
|
|
220
|
-
| `--assignee <userId>` | Add assignee by user ID or `"me"` |
|
|
221
|
-
| `--parent <taskId>` | Set parent task (makes this a subtask) |
|
|
222
|
-
| `--json` | Force JSON output even in terminal |
|
|
223
|
-
|
|
224
|
-
### `cu create`
|
|
225
|
-
|
|
226
|
-
Create a new task. If `--parent` is given, list is auto-detected from the parent task.
|
|
227
|
-
|
|
228
|
-
```bash
|
|
229
|
-
cu create -n "Fix login bug" -l <listId>
|
|
230
|
-
cu create -n "Subtask name" -p <parentTaskId> # --list auto-detected
|
|
231
|
-
cu create -n "Task" -l <listId> -d "desc" -s "open"
|
|
232
|
-
cu create -n "Task" -l <listId> --priority high --due-date 2025-06-01
|
|
233
|
-
cu create -n "Task" -l <listId> --assignee me --tags "bug,frontend"
|
|
234
|
-
cu create -n "Initiative" -l <listId> --custom-item-id 1
|
|
235
|
-
cu create -n "Task" -l <listId> --time-estimate 2h
|
|
236
|
-
cu create -n "Fix bug" -l <listId> --json
|
|
237
|
-
```
|
|
238
|
-
|
|
239
|
-
| Flag | Required | Description |
|
|
240
|
-
| ---------------------------- | ---------------- | ---------------------------------------------------- |
|
|
241
|
-
| `-n, --name <name>` | yes | Task name |
|
|
242
|
-
| `-l, --list <listId>` | if no `--parent` | Target list ID |
|
|
243
|
-
| `-p, --parent <taskId>` | no | Parent task (list auto-detected) |
|
|
244
|
-
| `-d, --description <text>` | no | Description (markdown) |
|
|
245
|
-
| `-s, --status <status>` | no | Initial status |
|
|
246
|
-
| `--priority <level>` | no | Priority: `urgent`, `high`, `normal`, `low` (or 1-4) |
|
|
247
|
-
| `--due-date <date>` | no | Due date (`YYYY-MM-DD`) |
|
|
248
|
-
| `--time-estimate <duration>` | no | Time estimate (e.g. `"2h"`, `"30m"`, `"1h30m"`) |
|
|
249
|
-
| `--assignee <userId>` | no | Assignee by user ID or `"me"` |
|
|
250
|
-
| `--tags <tags>` | no | Comma-separated tag names |
|
|
251
|
-
| `--custom-item-id <id>` | no | Custom task type ID (e.g. for creating initiatives) |
|
|
252
|
-
| `--json` | no | Force JSON output even in terminal |
|
|
253
|
-
|
|
254
|
-
### `cu delete <id>`
|
|
255
|
-
|
|
256
|
-
Delete a task. **DESTRUCTIVE - cannot be undone.**
|
|
257
|
-
|
|
258
|
-
```bash
|
|
259
|
-
cu delete abc123
|
|
260
|
-
cu delete abc123 --confirm
|
|
261
|
-
cu delete abc123 --confirm --json
|
|
262
|
-
```
|
|
263
|
-
|
|
264
|
-
In TTY mode without `--confirm`: shows the task name and prompts for confirmation (default: No). In non-interactive/piped mode, `--confirm` is required.
|
|
265
|
-
|
|
266
|
-
| Flag | Description |
|
|
267
|
-
| ----------- | ----------------------------------------------------------- |
|
|
268
|
-
| `--confirm` | Skip confirmation prompt (required in non-interactive mode) |
|
|
269
|
-
| `--json` | Force JSON output |
|
|
270
|
-
|
|
271
|
-
### `cu field <id>`
|
|
272
|
-
|
|
273
|
-
Set or remove a custom field value. Field names are resolved case-insensitively; errors list available fields/options.
|
|
274
|
-
|
|
275
|
-
```bash
|
|
276
|
-
cu field abc123 --set "Priority Level" high
|
|
277
|
-
cu field abc123 --set "Story Points" 5
|
|
278
|
-
cu field abc123 --set "Approved" true
|
|
279
|
-
cu field abc123 --set "Category" "Bug Fix"
|
|
280
|
-
cu field abc123 --set "Due" 2025-06-01
|
|
281
|
-
cu field abc123 --set "Website" "https://example.com"
|
|
282
|
-
cu field abc123 --set "Contact" "user@example.com"
|
|
283
|
-
cu field abc123 --remove "Priority Level"
|
|
284
|
-
cu field abc123 --set "Points" 3 --remove "Old Field"
|
|
285
|
-
cu field abc123 --set "Points" 3 --json
|
|
286
|
-
```
|
|
287
|
-
|
|
288
|
-
| Flag | Description |
|
|
289
|
-
| -------------------------- | -------------------------------------------------------------------------------------------------------------------------------- |
|
|
290
|
-
| `--set "Field Name" <val>` | Set a custom field by name. Supports: text, number, checkbox (true/false), dropdown (option name), date (YYYY-MM-DD), url, email |
|
|
291
|
-
| `--remove "Field Name"` | Remove a custom field value |
|
|
292
|
-
| `--json` | Force JSON output |
|
|
293
|
-
|
|
294
|
-
Both `--set` and `--remove` can be used together in one invocation.
|
|
295
|
-
|
|
296
|
-
### `cu comment <id>`
|
|
297
|
-
|
|
298
|
-
Post a comment on a task.
|
|
299
|
-
|
|
300
|
-
```bash
|
|
301
|
-
cu comment abc123 -m "Addressed in PR #42"
|
|
302
|
-
cu comment abc123 -m "Done" --json
|
|
303
|
-
```
|
|
304
|
-
|
|
305
|
-
### `cu comments <id>`
|
|
306
|
-
|
|
307
|
-
List comments on a task. Formatted view in terminal, JSON when piped.
|
|
308
|
-
|
|
309
|
-
```bash
|
|
310
|
-
cu comments abc123
|
|
311
|
-
cu comments abc123 --json
|
|
312
|
-
```
|
|
313
|
-
|
|
314
|
-
### `cu comment-edit <commentId>`
|
|
315
|
-
|
|
316
|
-
Edit an existing comment on a task.
|
|
317
|
-
|
|
318
|
-
```bash
|
|
319
|
-
cu comment-edit <commentId> -m "Updated text"
|
|
320
|
-
cu comment-edit <commentId> -m "Fixed" --resolved
|
|
321
|
-
cu comment-edit <commentId> -m "Reopening" --unresolved
|
|
322
|
-
cu comment-edit <commentId> -m "Updated" --json
|
|
323
|
-
```
|
|
324
|
-
|
|
325
|
-
| Flag | Required | Description |
|
|
326
|
-
| --------------- | -------- | -------------------------- |
|
|
327
|
-
| `-m, --message` | yes | New comment text |
|
|
328
|
-
| `--resolved` | no | Mark comment as resolved |
|
|
329
|
-
| `--unresolved` | no | Mark comment as unresolved |
|
|
330
|
-
| `--json` | no | Force JSON output |
|
|
331
|
-
|
|
332
|
-
### `cu activity <id>`
|
|
333
|
-
|
|
334
|
-
View task details and comment history together. Combines `cu task` and `cu comments` into a single view.
|
|
335
|
-
|
|
336
|
-
```bash
|
|
337
|
-
cu activity abc123
|
|
338
|
-
cu activity abc123 --json
|
|
339
|
-
```
|
|
340
|
-
|
|
341
|
-
### `cu lists <spaceId>`
|
|
342
|
-
|
|
343
|
-
List all lists in a space, including lists inside folders. Useful for discovering list IDs needed by `--list` filter and `cu create -l`.
|
|
44
|
+
**2. Install the skill**
|
|
344
45
|
|
|
345
46
|
```bash
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
cu lists <spaceId> --json
|
|
349
|
-
```
|
|
350
|
-
|
|
351
|
-
| Flag | Description |
|
|
352
|
-
| ------------------ | ---------------------------------- |
|
|
353
|
-
| `--name <partial>` | Filter lists by partial name match |
|
|
354
|
-
| `--json` | Force JSON output |
|
|
355
|
-
|
|
356
|
-
### `cu spaces`
|
|
357
|
-
|
|
358
|
-
List spaces in your workspace. Useful for getting space IDs for the `--space` filter.
|
|
359
|
-
|
|
360
|
-
```bash
|
|
361
|
-
cu spaces
|
|
362
|
-
cu spaces --name "eng"
|
|
363
|
-
cu spaces --my
|
|
364
|
-
cu spaces --json
|
|
365
|
-
```
|
|
366
|
-
|
|
367
|
-
| Flag | Description |
|
|
368
|
-
| ------------------ | -------------------------------------------- |
|
|
369
|
-
| `--name <partial>` | Filter spaces by partial name match |
|
|
370
|
-
| `--my` | Show only spaces where I have assigned tasks |
|
|
371
|
-
| `--json` | Force JSON output |
|
|
372
|
-
|
|
373
|
-
### `cu open <query>`
|
|
374
|
-
|
|
375
|
-
Open a task in the browser. Accepts a task ID or partial name.
|
|
376
|
-
|
|
377
|
-
```bash
|
|
378
|
-
cu open abc123
|
|
379
|
-
cu open "login bug"
|
|
380
|
-
cu open abc123 --json
|
|
381
|
-
```
|
|
382
|
-
|
|
383
|
-
If the query matches multiple tasks by name, all matches are listed and the first is opened.
|
|
384
|
-
|
|
385
|
-
### `cu search <query>`
|
|
386
|
-
|
|
387
|
-
Search my tasks by name. Supports multi-word queries with case-insensitive matching. Status filter supports fuzzy matching.
|
|
388
|
-
|
|
389
|
-
```bash
|
|
390
|
-
cu search "login bug"
|
|
391
|
-
cu search auth
|
|
392
|
-
cu search "payment flow" --json
|
|
393
|
-
cu search auth --status "prog" # fuzzy matches "in progress"
|
|
394
|
-
cu search "old task" --include-closed
|
|
395
|
-
```
|
|
396
|
-
|
|
397
|
-
### `cu summary`
|
|
398
|
-
|
|
399
|
-
Daily standup helper. Shows tasks grouped into: recently completed, in progress, and overdue.
|
|
400
|
-
|
|
401
|
-
```bash
|
|
402
|
-
cu summary
|
|
403
|
-
cu summary --hours 48
|
|
404
|
-
cu summary --json
|
|
47
|
+
mkdir -p ~/.config/opencode/skills/clickup
|
|
48
|
+
cp $(npm root -g)/@krodak/clickup-cli/skills/clickup-cli/SKILL.md ~/.config/opencode/skills/clickup/SKILL.md
|
|
405
49
|
```
|
|
406
50
|
|
|
407
|
-
|
|
408
|
-
| ------------- | -------------------------------------------------- |
|
|
409
|
-
| `--hours <n>` | Lookback for recently completed tasks (default 24) |
|
|
410
|
-
| `--json` | Force JSON output |
|
|
51
|
+
</details>
|
|
411
52
|
|
|
412
|
-
|
|
53
|
+
<details>
|
|
54
|
+
<summary> <img src="https://cdn.simpleicons.org/anthropic/D97757" height="16" align="center"> <strong>Claude Code</strong></summary>
|
|
413
55
|
|
|
414
|
-
|
|
56
|
+
**1. Install the CLI**
|
|
415
57
|
|
|
416
58
|
```bash
|
|
417
|
-
|
|
418
|
-
cu
|
|
419
|
-
cu overdue --json
|
|
420
|
-
```
|
|
421
|
-
|
|
422
|
-
### `cu assign <id>`
|
|
423
|
-
|
|
424
|
-
Assign or unassign users from a task. Supports `me` as shorthand for your user ID.
|
|
425
|
-
|
|
426
|
-
```bash
|
|
427
|
-
cu assign abc123 --to 12345
|
|
428
|
-
cu assign abc123 --to me
|
|
429
|
-
cu assign abc123 --remove 12345
|
|
430
|
-
cu assign abc123 --to me --remove 67890
|
|
431
|
-
cu assign abc123 --to me --json
|
|
59
|
+
npm install -g @krodak/clickup-cli
|
|
60
|
+
cu init
|
|
432
61
|
```
|
|
433
62
|
|
|
434
|
-
|
|
435
|
-
| ------------------- | --------------------------------- |
|
|
436
|
-
| `--to <userId>` | Add assignee (user ID or `me`) |
|
|
437
|
-
| `--remove <userId>` | Remove assignee (user ID or `me`) |
|
|
438
|
-
| `--json` | Force JSON output |
|
|
439
|
-
|
|
440
|
-
### `cu depend <id>`
|
|
441
|
-
|
|
442
|
-
Add or remove task dependencies. Set a task as waiting on or blocking another task.
|
|
63
|
+
**2. Install the skill**
|
|
443
64
|
|
|
444
65
|
```bash
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
cu depend abc123 --on def456 --remove # remove the dependency
|
|
448
|
-
cu depend abc123 --blocks def456 --remove
|
|
449
|
-
cu depend abc123 --on def456 --json
|
|
66
|
+
mkdir -p ~/.claude/skills/clickup
|
|
67
|
+
cp $(npm root -g)/@krodak/clickup-cli/skills/clickup-cli/SKILL.md ~/.claude/skills/clickup/SKILL.md
|
|
450
68
|
```
|
|
451
69
|
|
|
452
|
-
|
|
453
|
-
| ------------------- | ------------------------------------------- |
|
|
454
|
-
| `--on <taskId>` | Task that this task depends on (waiting on) |
|
|
455
|
-
| `--blocks <taskId>` | Task that this task blocks |
|
|
456
|
-
| `--remove` | Remove the dependency instead of adding it |
|
|
457
|
-
| `--json` | Force JSON output |
|
|
458
|
-
|
|
459
|
-
### `cu move <id>`
|
|
460
|
-
|
|
461
|
-
Add or remove a task from a list. Tasks can belong to multiple lists in ClickUp.
|
|
70
|
+
Then reference it in your `CLAUDE.md` or project instructions.
|
|
462
71
|
|
|
463
|
-
|
|
464
|
-
cu move abc123 --to <listId> # add task to a list
|
|
465
|
-
cu move abc123 --remove <listId> # remove task from a list
|
|
466
|
-
cu move abc123 --to <newListId> --remove <oldListId> # move between lists
|
|
467
|
-
cu move abc123 --to <listId> --json
|
|
468
|
-
```
|
|
72
|
+
</details>
|
|
469
73
|
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
| `--to <listId>` | Add task to this list |
|
|
473
|
-
| `--remove <listId>` | Remove task from this list |
|
|
474
|
-
| `--json` | Force JSON output |
|
|
74
|
+
<details>
|
|
75
|
+
<summary> <img src="https://cdn.simpleicons.org/anthropic/D97757" height="16" align="center"> <strong>Claude Desktop</strong></summary>
|
|
475
76
|
|
|
476
|
-
|
|
77
|
+
Claude Desktop doesn't run CLI tools directly. Use it alongside a coding agent (Claude Code, OpenCode) that has `cu` installed, or run `cu` commands manually in your terminal.
|
|
477
78
|
|
|
478
|
-
|
|
79
|
+
**Install the CLI:**
|
|
479
80
|
|
|
480
81
|
```bash
|
|
481
|
-
|
|
482
|
-
cu
|
|
483
|
-
cu tag abc123 --remove "wontfix"
|
|
484
|
-
cu tag abc123 --add "bug" --remove "triage"
|
|
485
|
-
cu tag abc123 --add "bug" --json
|
|
82
|
+
npm install -g @krodak/clickup-cli
|
|
83
|
+
cu init
|
|
486
84
|
```
|
|
487
85
|
|
|
488
|
-
|
|
489
|
-
| ----------------- | ----------------------------------- |
|
|
490
|
-
| `--add <tags>` | Comma-separated tag names to add |
|
|
491
|
-
| `--remove <tags>` | Comma-separated tag names to remove |
|
|
492
|
-
| `--json` | Force JSON output |
|
|
493
|
-
|
|
494
|
-
### `cu checklist`
|
|
86
|
+
</details>
|
|
495
87
|
|
|
496
|
-
|
|
88
|
+
<details>
|
|
89
|
+
<summary> <img src="https://cdn.simpleicons.org/homebrew/FBB040" height="16" align="center"> <strong>Homebrew</strong></summary>
|
|
497
90
|
|
|
498
91
|
```bash
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
cu
|
|
502
|
-
cu checklist add-item <checklistId> "Run tests" # add an item
|
|
503
|
-
cu checklist edit-item <clId> <itemId> --resolved # mark item done
|
|
504
|
-
cu checklist delete-item <clId> <itemId> # remove an item
|
|
92
|
+
brew tap krodak/tap
|
|
93
|
+
brew install clickup-cli
|
|
94
|
+
cu init
|
|
505
95
|
```
|
|
506
96
|
|
|
507
|
-
|
|
508
|
-
| ------------- | -------------------------------- | --------------------- |
|
|
509
|
-
| `view` | `<taskId>` | Show all checklists |
|
|
510
|
-
| `create` | `<taskId> <name>` | Create a checklist |
|
|
511
|
-
| `delete` | `<checklistId>` | Delete a checklist |
|
|
512
|
-
| `add-item` | `<checklistId> <name>` | Add checklist item |
|
|
513
|
-
| `edit-item` | `<checklistId> <itemId> [flags]` | Edit checklist item |
|
|
514
|
-
| `delete-item` | `<checklistId> <itemId>` | Delete checklist item |
|
|
97
|
+
Then install the skill for your agent (see OpenCode or Claude Code sections above).
|
|
515
98
|
|
|
516
|
-
|
|
99
|
+
</details>
|
|
517
100
|
|
|
518
|
-
|
|
101
|
+
<details>
|
|
102
|
+
<summary> <img src="https://cdn.simpleicons.org/openai/999999" height="16" align="center"> <strong>Codex / Other agents</strong></summary>
|
|
519
103
|
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
Check authentication status. Validates your API token and shows your user info.
|
|
104
|
+
**1. Install the CLI**
|
|
523
105
|
|
|
524
106
|
```bash
|
|
525
|
-
|
|
526
|
-
cu
|
|
527
|
-
```
|
|
528
|
-
|
|
529
|
-
### `cu config`
|
|
530
|
-
|
|
531
|
-
Manage CLI configuration.
|
|
532
|
-
|
|
533
|
-
```bash
|
|
534
|
-
cu config get apiToken
|
|
535
|
-
cu config set teamId 12345
|
|
536
|
-
cu config path
|
|
107
|
+
npm install -g @krodak/clickup-cli
|
|
108
|
+
cu init
|
|
537
109
|
```
|
|
538
110
|
|
|
539
|
-
|
|
111
|
+
**2. Add the skill to your agent**
|
|
540
112
|
|
|
541
|
-
|
|
113
|
+
Copy `skills/clickup-cli/SKILL.md` into your agent's system prompt or project instructions. It's a standalone markdown document that teaches the agent all available commands.
|
|
542
114
|
|
|
543
|
-
|
|
115
|
+
</details>
|
|
544
116
|
|
|
545
|
-
|
|
546
|
-
eval "$(cu completion bash)" # Bash
|
|
547
|
-
eval "$(cu completion zsh)" # Zsh
|
|
548
|
-
cu completion fish > ~/.config/fish/completions/cu.fish # Fish
|
|
549
|
-
```
|
|
117
|
+
## Commands
|
|
550
118
|
|
|
551
|
-
|
|
119
|
+
36 commands total. [Full reference with examples and flags](docs/commands.md).
|
|
120
|
+
|
|
121
|
+
### Tasks
|
|
122
|
+
|
|
123
|
+
| Command | Description |
|
|
124
|
+
| --------------------- | ----------------------------------------------------------- |
|
|
125
|
+
| `cu tasks` | List my tasks (filter by status, name, type, list, space) |
|
|
126
|
+
| `cu task <id>` | Task details with custom fields and checklists |
|
|
127
|
+
| `cu subtasks <id>` | List subtasks of a task |
|
|
128
|
+
| `cu create` | Create a task or subtask |
|
|
129
|
+
| `cu update <id>` | Update task fields (status, name, priority, assignee, etc.) |
|
|
130
|
+
| `cu delete <id>` | Delete a task (requires confirmation) |
|
|
131
|
+
| `cu assign <id>` | Assign/unassign users |
|
|
132
|
+
| `cu depend <id>` | Add/remove task dependencies |
|
|
133
|
+
| `cu move <id>` | Add/remove task from lists |
|
|
134
|
+
| `cu open <query>` | Open task in browser by ID or name |
|
|
135
|
+
| `cu search <query>` | Search my tasks by name |
|
|
136
|
+
| _`cu duplicate <id>`_ | _Copy a task - coming soon_ |
|
|
137
|
+
| _`cu bulk`_ | _Bulk task operations - coming soon_ |
|
|
138
|
+
|
|
139
|
+
### Sprints & Planning
|
|
140
|
+
|
|
141
|
+
| Command | Description |
|
|
142
|
+
| ------------- | ----------------------------------------------- |
|
|
143
|
+
| `cu sprint` | My tasks in the active sprint (auto-detected) |
|
|
144
|
+
| `cu sprints` | List all sprints |
|
|
145
|
+
| `cu assigned` | All my tasks grouped by status |
|
|
146
|
+
| `cu summary` | Standup helper: completed, in progress, overdue |
|
|
147
|
+
| `cu overdue` | Tasks past their due date |
|
|
148
|
+
| `cu inbox` | Recently updated tasks |
|
|
149
|
+
|
|
150
|
+
### Comments
|
|
151
|
+
|
|
152
|
+
| Command | Description |
|
|
153
|
+
| -------------------------- | -------------------------------- |
|
|
154
|
+
| `cu comment <id>` | Post a comment on a task |
|
|
155
|
+
| `cu comments <id>` | List comments on a task |
|
|
156
|
+
| `cu comment-edit <id>` | Edit an existing comment |
|
|
157
|
+
| `cu activity <id>` | Task details + comments combined |
|
|
158
|
+
| _`cu comment-delete <id>`_ | _Delete a comment - coming soon_ |
|
|
159
|
+
|
|
160
|
+
### Custom Fields
|
|
161
|
+
|
|
162
|
+
| Command | Description |
|
|
163
|
+
| ---------------------- | ----------------------------------------------------------------------------------- |
|
|
164
|
+
| `cu field <id>` | Set/remove custom field values (text, number, dropdown, date, checkbox, url, email) |
|
|
165
|
+
| _`cu fields <listId>`_ | _List available custom fields for a list - coming soon_ |
|
|
166
|
+
|
|
167
|
+
### Checklists
|
|
168
|
+
|
|
169
|
+
| Command | Description |
|
|
170
|
+
| ---------------------------------------- | ------------------------------------------------ |
|
|
171
|
+
| `cu checklist view <id>` | View all checklists on a task |
|
|
172
|
+
| `cu checklist create <id> <name>` | Create a checklist |
|
|
173
|
+
| `cu checklist delete <id>` | Delete a checklist |
|
|
174
|
+
| `cu checklist add-item <id> <name>` | Add item to a checklist |
|
|
175
|
+
| `cu checklist edit-item <id> <itemId>` | Edit a checklist item (name, resolved, assignee) |
|
|
176
|
+
| `cu checklist delete-item <id> <itemId>` | Delete a checklist item |
|
|
177
|
+
|
|
178
|
+
### Tags
|
|
179
|
+
|
|
180
|
+
| Command | Description |
|
|
181
|
+
| --------------------- | --------------------------------------------------- |
|
|
182
|
+
| `cu tag <id>` | Add/remove tags on a task |
|
|
183
|
+
| _`cu tags <spaceId>`_ | _List/create/delete space-level tags - coming soon_ |
|
|
184
|
+
|
|
185
|
+
### Workspace
|
|
186
|
+
|
|
187
|
+
| Command | Description |
|
|
188
|
+
| ------------------------ | ----------------------------------------- |
|
|
189
|
+
| `cu spaces` | List workspace spaces |
|
|
190
|
+
| `cu lists <spaceId>` | Lists in a space (including folder lists) |
|
|
191
|
+
| `cu auth` | Check authentication status |
|
|
192
|
+
| _`cu folders <spaceId>`_ | _List folders in a space - coming soon_ |
|
|
193
|
+
| _`cu members`_ | _List workspace members - coming soon_ |
|
|
194
|
+
|
|
195
|
+
### Time Tracking
|
|
196
|
+
|
|
197
|
+
| Command | Description |
|
|
198
|
+
| ----------------------------- | ----------------------------------------------- |
|
|
199
|
+
| `cu time start <id>` | Start tracking time on a task |
|
|
200
|
+
| `cu time stop` | Stop the running timer |
|
|
201
|
+
| `cu time status` | Show the currently running timer |
|
|
202
|
+
| `cu time log <id> <duration>` | Log a manual time entry (e.g. "2h", "30m") |
|
|
203
|
+
| `cu time list` | List recent time entries (default: last 7 days) |
|
|
204
|
+
|
|
205
|
+
### Setup
|
|
206
|
+
|
|
207
|
+
| Command | Description |
|
|
208
|
+
| ----------------------- | --------------------------------- |
|
|
209
|
+
| `cu init` | First-time setup wizard |
|
|
210
|
+
| `cu config` | Get/set config values |
|
|
211
|
+
| `cu completion <shell>` | Shell completions (bash/zsh/fish) |
|
|
212
|
+
|
|
213
|
+
## Output Modes
|
|
214
|
+
|
|
215
|
+
| Context | Default | Override |
|
|
216
|
+
| -------------- | --------------------------- | ---------------------------- |
|
|
217
|
+
| Terminal (TTY) | Interactive tables + picker | `--json` |
|
|
218
|
+
| Piped (no TTY) | Markdown (optimized for AI) | `--json` or `CU_OUTPUT=json` |
|
|
219
|
+
|
|
220
|
+
Most commands scope to your assigned tasks by default - keeping output small and relevant for agent context windows.
|
|
221
|
+
|
|
222
|
+
## Configuration
|
|
552
223
|
|
|
553
224
|
### Config file
|
|
554
225
|
|
|
@@ -573,6 +244,10 @@ Environment variables override config file values:
|
|
|
573
244
|
|
|
574
245
|
When both are set, the config file is not required. Useful for CI/CD and containerized agents.
|
|
575
246
|
|
|
247
|
+
## Why a CLI and not MCP?
|
|
248
|
+
|
|
249
|
+
A CLI + skill file has fewer moving parts. No server process, no protocol layer. The agent already knows how to run shell commands - the skill file teaches it which ones exist. For tool-use with coding agents, CLI + instructions tends to work better than MCP in practice.
|
|
250
|
+
|
|
576
251
|
## Development
|
|
577
252
|
|
|
578
253
|
```bash
|
package/dist/index.js
CHANGED
|
@@ -120,6 +120,9 @@ var ClickUpClient = class {
|
|
|
120
120
|
async getSpaceWithStatuses(spaceId) {
|
|
121
121
|
return this.request(`/space/${spaceId}`);
|
|
122
122
|
}
|
|
123
|
+
async getListWithStatuses(listId) {
|
|
124
|
+
return this.request(`/list/${listId}`);
|
|
125
|
+
}
|
|
123
126
|
async getSpaces(teamId) {
|
|
124
127
|
const data = await this.request(`/team/${teamId}/space?archived=false`);
|
|
125
128
|
return data.spaces ?? [];
|
|
@@ -235,6 +238,63 @@ var ClickUpClient = class {
|
|
|
235
238
|
{ method: "DELETE" }
|
|
236
239
|
);
|
|
237
240
|
}
|
|
241
|
+
async startTimeEntry(teamId, taskId, description) {
|
|
242
|
+
const body = {
|
|
243
|
+
tid: taskId,
|
|
244
|
+
start: Date.now(),
|
|
245
|
+
duration: -1
|
|
246
|
+
};
|
|
247
|
+
if (description) body.description = description;
|
|
248
|
+
const data = await this.request(`/team/${teamId}/time_entries/start`, {
|
|
249
|
+
method: "POST",
|
|
250
|
+
body: JSON.stringify(body)
|
|
251
|
+
});
|
|
252
|
+
return data.data;
|
|
253
|
+
}
|
|
254
|
+
async stopTimeEntry(teamId) {
|
|
255
|
+
const data = await this.request(`/team/${teamId}/time_entries/stop`, {
|
|
256
|
+
method: "POST"
|
|
257
|
+
});
|
|
258
|
+
return data.data;
|
|
259
|
+
}
|
|
260
|
+
async getRunningTimeEntry(teamId) {
|
|
261
|
+
const data = await this.request(
|
|
262
|
+
`/team/${teamId}/time_entries/current`
|
|
263
|
+
);
|
|
264
|
+
return data.data ?? null;
|
|
265
|
+
}
|
|
266
|
+
async createTimeEntry(teamId, taskId, duration, opts) {
|
|
267
|
+
const start = opts?.start ?? Date.now() - duration;
|
|
268
|
+
const body = {
|
|
269
|
+
tid: taskId,
|
|
270
|
+
start,
|
|
271
|
+
duration
|
|
272
|
+
};
|
|
273
|
+
if (opts?.description) body.description = opts.description;
|
|
274
|
+
const data = await this.request(`/team/${teamId}/time_entries`, {
|
|
275
|
+
method: "POST",
|
|
276
|
+
body: JSON.stringify(body)
|
|
277
|
+
});
|
|
278
|
+
return data.data;
|
|
279
|
+
}
|
|
280
|
+
async getTimeEntries(teamId, opts) {
|
|
281
|
+
const params = new URLSearchParams();
|
|
282
|
+
if (opts?.startDate != null) params.set("start_date", String(opts.startDate));
|
|
283
|
+
if (opts?.endDate != null) params.set("end_date", String(opts.endDate));
|
|
284
|
+
const query = params.toString();
|
|
285
|
+
const url = `/team/${teamId}/time_entries${query ? `?${query}` : ""}`;
|
|
286
|
+
const data = await this.request(url);
|
|
287
|
+
const entries = data.data ?? [];
|
|
288
|
+
if (opts?.taskId) {
|
|
289
|
+
return entries.filter((e) => e.task?.id === opts.taskId);
|
|
290
|
+
}
|
|
291
|
+
return entries;
|
|
292
|
+
}
|
|
293
|
+
async deleteTimeEntry(teamId, timeEntryId) {
|
|
294
|
+
await this.request(`/team/${teamId}/time_entries/${timeEntryId}`, {
|
|
295
|
+
method: "DELETE"
|
|
296
|
+
});
|
|
297
|
+
}
|
|
238
298
|
};
|
|
239
299
|
|
|
240
300
|
// src/config.ts
|
|
@@ -865,9 +925,8 @@ function hasUpdateFields(options) {
|
|
|
865
925
|
}
|
|
866
926
|
async function resolveStatus(client, taskId, statusInput) {
|
|
867
927
|
const task = await client.getTask(taskId);
|
|
868
|
-
|
|
869
|
-
const
|
|
870
|
-
const available = space.statuses.map((s) => s.status);
|
|
928
|
+
const list = await client.getListWithStatuses(task.list.id);
|
|
929
|
+
const available = list.statuses.map((s) => s.status);
|
|
871
930
|
const matched = matchStatus(statusInput, available);
|
|
872
931
|
if (!matched) {
|
|
873
932
|
throw new Error(`No matching status for "${statusInput}". Available: ${available.join(", ")}`);
|
|
@@ -1749,7 +1808,7 @@ function bashCompletion() {
|
|
|
1749
1808
|
cword=$COMP_CWORD
|
|
1750
1809
|
fi
|
|
1751
1810
|
|
|
1752
|
-
local commands="init auth tasks task update create sprint sprints subtasks comment comment-edit comments activity lists spaces inbox assigned open search summary overdue assign depend move field delete tag checklist config completion"
|
|
1811
|
+
local commands="init auth tasks task update create sprint sprints subtasks comment comment-edit comments activity lists spaces inbox assigned open search summary overdue assign depend move field delete tag checklist time config completion"
|
|
1753
1812
|
|
|
1754
1813
|
if [[ $cword -eq 1 ]]; then
|
|
1755
1814
|
COMPREPLY=($(compgen -W "$commands --help --version" -- "$cur"))
|
|
@@ -1850,6 +1909,11 @@ function bashCompletion() {
|
|
|
1850
1909
|
COMPREPLY=($(compgen -W "view create delete add-item edit-item delete-item" -- "$cur"))
|
|
1851
1910
|
fi
|
|
1852
1911
|
;;
|
|
1912
|
+
time)
|
|
1913
|
+
if [[ $cword -eq 2 ]]; then
|
|
1914
|
+
COMPREPLY=($(compgen -W "start stop status log list" -- "$cur"))
|
|
1915
|
+
fi
|
|
1916
|
+
;;
|
|
1853
1917
|
comment-edit)
|
|
1854
1918
|
COMPREPLY=($(compgen -W "-m --message --resolved --unresolved --json" -- "$cur"))
|
|
1855
1919
|
;;
|
|
@@ -1906,6 +1970,7 @@ _cu() {
|
|
|
1906
1970
|
'delete:Delete a task'
|
|
1907
1971
|
'tag:Add or remove tags from a task'
|
|
1908
1972
|
'checklist:Manage checklists on a task'
|
|
1973
|
+
'time:Track time on tasks'
|
|
1909
1974
|
'comment-edit:Edit an existing comment'
|
|
1910
1975
|
'config:Manage CLI configuration'
|
|
1911
1976
|
'completion:Output shell completion script'
|
|
@@ -2142,6 +2207,53 @@ _cu() {
|
|
|
2142
2207
|
;;
|
|
2143
2208
|
esac
|
|
2144
2209
|
;;
|
|
2210
|
+
time)
|
|
2211
|
+
local -a time_cmds
|
|
2212
|
+
time_cmds=(
|
|
2213
|
+
'start:Start tracking time on a task'
|
|
2214
|
+
'stop:Stop the running timer'
|
|
2215
|
+
'status:Show the currently running timer'
|
|
2216
|
+
'log:Log a manual time entry'
|
|
2217
|
+
'list:List recent time entries'
|
|
2218
|
+
)
|
|
2219
|
+
_arguments -C \\
|
|
2220
|
+
'1:time command:->time_cmd' \\
|
|
2221
|
+
'*::time_arg:->time_args'
|
|
2222
|
+
case $state in
|
|
2223
|
+
time_cmd)
|
|
2224
|
+
_describe 'time command' time_cmds
|
|
2225
|
+
;;
|
|
2226
|
+
time_args)
|
|
2227
|
+
case $words[1] in
|
|
2228
|
+
start)
|
|
2229
|
+
_arguments \\
|
|
2230
|
+
'1:task_id:' \\
|
|
2231
|
+
'(-d --description)'{-d,--description}'[Description]:text:' \\
|
|
2232
|
+
'--json[Force JSON output]'
|
|
2233
|
+
;;
|
|
2234
|
+
stop)
|
|
2235
|
+
_arguments '--json[Force JSON output]'
|
|
2236
|
+
;;
|
|
2237
|
+
status)
|
|
2238
|
+
_arguments '--json[Force JSON output]'
|
|
2239
|
+
;;
|
|
2240
|
+
log)
|
|
2241
|
+
_arguments \\
|
|
2242
|
+
'1:task_id:' \\
|
|
2243
|
+
'2:duration:' \\
|
|
2244
|
+
'(-d --description)'{-d,--description}'[Description]:text:' \\
|
|
2245
|
+
'--json[Force JSON output]'
|
|
2246
|
+
;;
|
|
2247
|
+
list)
|
|
2248
|
+
_arguments \\
|
|
2249
|
+
'--days[Number of days to look back]:days:' \\
|
|
2250
|
+
'--task[Filter by task ID]:task_id:' \\
|
|
2251
|
+
'--json[Force JSON output]'
|
|
2252
|
+
;;
|
|
2253
|
+
esac
|
|
2254
|
+
;;
|
|
2255
|
+
esac
|
|
2256
|
+
;;
|
|
2145
2257
|
comment-edit)
|
|
2146
2258
|
_arguments \\
|
|
2147
2259
|
'1:comment_id:' \\
|
|
@@ -2217,6 +2329,7 @@ complete -c cu -n __fish_use_subcommand -a field -d 'Set or remove a custom fiel
|
|
|
2217
2329
|
complete -c cu -n __fish_use_subcommand -a delete -d 'Delete a task'
|
|
2218
2330
|
complete -c cu -n __fish_use_subcommand -a tag -d 'Add or remove tags from a task'
|
|
2219
2331
|
complete -c cu -n __fish_use_subcommand -a checklist -d 'Manage checklists on a task'
|
|
2332
|
+
complete -c cu -n __fish_use_subcommand -a time -d 'Track time on tasks'
|
|
2220
2333
|
complete -c cu -n __fish_use_subcommand -a comment-edit -d 'Edit an existing comment'
|
|
2221
2334
|
complete -c cu -n __fish_use_subcommand -a config -d 'Manage CLI configuration'
|
|
2222
2335
|
complete -c cu -n __fish_use_subcommand -a completion -d 'Output shell completion script'
|
|
@@ -2339,6 +2452,17 @@ complete -c cu -n '__fish_seen_subcommand_from edit-item' -l resolved -d 'Mark i
|
|
|
2339
2452
|
complete -c cu -n '__fish_seen_subcommand_from edit-item' -l unresolved -d 'Mark item as unresolved'
|
|
2340
2453
|
complete -c cu -n '__fish_seen_subcommand_from edit-item' -l assignee -d 'Assign user by ID'
|
|
2341
2454
|
|
|
2455
|
+
complete -c cu -n '__fish_seen_subcommand_from time; and not __fish_seen_subcommand_from start stop status log list' -a start -d 'Start tracking time on a task'
|
|
2456
|
+
complete -c cu -n '__fish_seen_subcommand_from time; and not __fish_seen_subcommand_from start stop status log list' -a stop -d 'Stop the running timer'
|
|
2457
|
+
complete -c cu -n '__fish_seen_subcommand_from time; and not __fish_seen_subcommand_from start stop status log list' -a status -d 'Show the currently running timer'
|
|
2458
|
+
complete -c cu -n '__fish_seen_subcommand_from time; and not __fish_seen_subcommand_from start stop status log list' -a log -d 'Log a manual time entry'
|
|
2459
|
+
complete -c cu -n '__fish_seen_subcommand_from time; and not __fish_seen_subcommand_from start stop status log list' -a list -d 'List recent time entries'
|
|
2460
|
+
complete -c cu -n '__fish_seen_subcommand_from start stop status log list; and __fish_seen_subcommand_from time' -l json -d 'Force JSON output'
|
|
2461
|
+
complete -c cu -n '__fish_seen_subcommand_from start; and __fish_seen_subcommand_from time' -s d -l description -d 'Description'
|
|
2462
|
+
complete -c cu -n '__fish_seen_subcommand_from log; and __fish_seen_subcommand_from time' -s d -l description -d 'Description'
|
|
2463
|
+
complete -c cu -n '__fish_seen_subcommand_from list; and __fish_seen_subcommand_from time' -l days -d 'Number of days to look back'
|
|
2464
|
+
complete -c cu -n '__fish_seen_subcommand_from list; and __fish_seen_subcommand_from time' -l task -d 'Filter by task ID'
|
|
2465
|
+
|
|
2342
2466
|
complete -c cu -n '__fish_seen_subcommand_from comment-edit' -s m -l message -d 'New comment text'
|
|
2343
2467
|
complete -c cu -n '__fish_seen_subcommand_from comment-edit' -l resolved -d 'Mark comment as resolved'
|
|
2344
2468
|
complete -c cu -n '__fish_seen_subcommand_from comment-edit' -l unresolved -d 'Mark comment as unresolved'
|
|
@@ -2651,6 +2775,71 @@ async function editComment(config, commentId, text, resolved) {
|
|
|
2651
2775
|
await client.updateComment(commentId, text, resolved);
|
|
2652
2776
|
}
|
|
2653
2777
|
|
|
2778
|
+
// src/commands/time.ts
|
|
2779
|
+
import chalk6 from "chalk";
|
|
2780
|
+
function formatDuration2(ms) {
|
|
2781
|
+
const totalMinutes = Math.round(Math.abs(ms) / 6e4);
|
|
2782
|
+
const hours = Math.floor(totalMinutes / 60);
|
|
2783
|
+
const minutes = totalMinutes % 60;
|
|
2784
|
+
if (hours > 0 && minutes > 0) return `${hours}h ${minutes}m`;
|
|
2785
|
+
if (hours > 0) return `${hours}h`;
|
|
2786
|
+
return `${minutes}m`;
|
|
2787
|
+
}
|
|
2788
|
+
function formatTimestamp2(ms) {
|
|
2789
|
+
return new Date(Number(ms)).toLocaleString("en-US", {
|
|
2790
|
+
month: "short",
|
|
2791
|
+
day: "numeric",
|
|
2792
|
+
hour: "numeric",
|
|
2793
|
+
minute: "2-digit"
|
|
2794
|
+
});
|
|
2795
|
+
}
|
|
2796
|
+
async function startTimer(config, taskId, description) {
|
|
2797
|
+
const client = new ClickUpClient(config);
|
|
2798
|
+
return client.startTimeEntry(config.teamId, taskId, description);
|
|
2799
|
+
}
|
|
2800
|
+
async function stopTimer(config) {
|
|
2801
|
+
const client = new ClickUpClient(config);
|
|
2802
|
+
return client.stopTimeEntry(config.teamId);
|
|
2803
|
+
}
|
|
2804
|
+
async function timerStatus(config) {
|
|
2805
|
+
const client = new ClickUpClient(config);
|
|
2806
|
+
return client.getRunningTimeEntry(config.teamId);
|
|
2807
|
+
}
|
|
2808
|
+
async function logTime(config, taskId, durationStr, description) {
|
|
2809
|
+
const client = new ClickUpClient(config);
|
|
2810
|
+
const duration = parseTimeEstimate(durationStr);
|
|
2811
|
+
return client.createTimeEntry(config.teamId, taskId, duration, { description });
|
|
2812
|
+
}
|
|
2813
|
+
async function listTimeEntries(config, opts) {
|
|
2814
|
+
const client = new ClickUpClient(config);
|
|
2815
|
+
const days = opts?.days ?? 7;
|
|
2816
|
+
const endDate = Date.now();
|
|
2817
|
+
const startDate = endDate - days * 24 * 60 * 60 * 1e3;
|
|
2818
|
+
return client.getTimeEntries(config.teamId, {
|
|
2819
|
+
startDate,
|
|
2820
|
+
endDate,
|
|
2821
|
+
taskId: opts?.taskId
|
|
2822
|
+
});
|
|
2823
|
+
}
|
|
2824
|
+
function formatTimeEntry(entry) {
|
|
2825
|
+
const lines = [];
|
|
2826
|
+
const taskName = entry.task?.name ?? "No task";
|
|
2827
|
+
const taskId = entry.task?.id ?? "";
|
|
2828
|
+
const isRunning = entry.duration < 0;
|
|
2829
|
+
const elapsed = isRunning ? Date.now() - Number(entry.start) : entry.duration;
|
|
2830
|
+
const durationStr = formatDuration2(elapsed);
|
|
2831
|
+
const status = isRunning ? chalk6.green("RUNNING") : "";
|
|
2832
|
+
lines.push(`${chalk6.bold(taskName)} ${chalk6.dim(taskId)} ${status}`);
|
|
2833
|
+
lines.push(
|
|
2834
|
+
` ${durationStr} - ${formatTimestamp2(entry.start)}${entry.description ? ` - ${entry.description}` : ""}`
|
|
2835
|
+
);
|
|
2836
|
+
return lines.join("\n");
|
|
2837
|
+
}
|
|
2838
|
+
function formatTimeEntries(entries) {
|
|
2839
|
+
if (entries.length === 0) return "No time entries";
|
|
2840
|
+
return entries.map(formatTimeEntry).join("\n");
|
|
2841
|
+
}
|
|
2842
|
+
|
|
2654
2843
|
// src/index.ts
|
|
2655
2844
|
var require2 = createRequire(import.meta.url);
|
|
2656
2845
|
var { version } = require2("../package.json");
|
|
@@ -3049,6 +3238,71 @@ checklistCmd.command("delete-item <checklistId> <checklistItemId>").description(
|
|
|
3049
3238
|
}
|
|
3050
3239
|
})
|
|
3051
3240
|
);
|
|
3241
|
+
var timeCmd = program.command("time").description("Track time on tasks");
|
|
3242
|
+
timeCmd.command("start <taskId>").description("Start tracking time on a task").option("-d, --description <text>", "Description for the time entry").option("--json", "Force JSON output even in terminal").action(
|
|
3243
|
+
wrapAction(async (taskId, opts) => {
|
|
3244
|
+
const config = loadConfig();
|
|
3245
|
+
const result = await startTimer(config, taskId, opts.description);
|
|
3246
|
+
if (shouldOutputJson(opts.json ?? false)) {
|
|
3247
|
+
console.log(JSON.stringify(result, null, 2));
|
|
3248
|
+
} else {
|
|
3249
|
+
const taskName = result.task?.name ?? taskId;
|
|
3250
|
+
console.log(`Started timer on "${taskName}"`);
|
|
3251
|
+
}
|
|
3252
|
+
})
|
|
3253
|
+
);
|
|
3254
|
+
timeCmd.command("stop").description("Stop the running timer").option("--json", "Force JSON output even in terminal").action(
|
|
3255
|
+
wrapAction(async (opts) => {
|
|
3256
|
+
const config = loadConfig();
|
|
3257
|
+
const result = await stopTimer(config);
|
|
3258
|
+
if (shouldOutputJson(opts.json ?? false)) {
|
|
3259
|
+
console.log(JSON.stringify(result, null, 2));
|
|
3260
|
+
} else {
|
|
3261
|
+
console.log(formatTimeEntry(result));
|
|
3262
|
+
}
|
|
3263
|
+
})
|
|
3264
|
+
);
|
|
3265
|
+
timeCmd.command("status").description("Show the currently running timer").option("--json", "Force JSON output even in terminal").action(
|
|
3266
|
+
wrapAction(async (opts) => {
|
|
3267
|
+
const config = loadConfig();
|
|
3268
|
+
const result = await timerStatus(config);
|
|
3269
|
+
if (shouldOutputJson(opts.json ?? false)) {
|
|
3270
|
+
console.log(JSON.stringify(result, null, 2));
|
|
3271
|
+
} else if (result) {
|
|
3272
|
+
console.log(formatTimeEntry(result));
|
|
3273
|
+
} else {
|
|
3274
|
+
console.log("No timer running");
|
|
3275
|
+
}
|
|
3276
|
+
})
|
|
3277
|
+
);
|
|
3278
|
+
timeCmd.command("log <taskId> <duration>").description('Log a manual time entry (e.g. "2h", "30m", "1h30m")').option("-d, --description <text>", "Description for the time entry").option("--json", "Force JSON output even in terminal").action(
|
|
3279
|
+
wrapAction(
|
|
3280
|
+
async (taskId, duration, opts) => {
|
|
3281
|
+
const config = loadConfig();
|
|
3282
|
+
const result = await logTime(config, taskId, duration, opts.description);
|
|
3283
|
+
if (shouldOutputJson(opts.json ?? false)) {
|
|
3284
|
+
console.log(JSON.stringify(result, null, 2));
|
|
3285
|
+
} else {
|
|
3286
|
+
console.log(`Logged ${duration} on task ${taskId}`);
|
|
3287
|
+
}
|
|
3288
|
+
}
|
|
3289
|
+
)
|
|
3290
|
+
);
|
|
3291
|
+
timeCmd.command("list").description("List recent time entries (default: last 7 days)").option("--days <n>", "Number of days to look back", "7").option("--task <taskId>", "Filter by task ID").option("--json", "Force JSON output even in terminal").action(
|
|
3292
|
+
wrapAction(async (opts) => {
|
|
3293
|
+
const config = loadConfig();
|
|
3294
|
+
const days = opts.days ? Number(opts.days) : 7;
|
|
3295
|
+
if (!Number.isFinite(days) || days <= 0) {
|
|
3296
|
+
throw new Error("--days must be a positive number");
|
|
3297
|
+
}
|
|
3298
|
+
const entries = await listTimeEntries(config, { days, taskId: opts.task });
|
|
3299
|
+
if (shouldOutputJson(opts.json ?? false)) {
|
|
3300
|
+
console.log(JSON.stringify(entries, null, 2));
|
|
3301
|
+
} else {
|
|
3302
|
+
console.log(formatTimeEntries(entries));
|
|
3303
|
+
}
|
|
3304
|
+
})
|
|
3305
|
+
);
|
|
3052
3306
|
var configCmd = program.command("config").description("Manage CLI configuration");
|
|
3053
3307
|
configCmd.command("get <key>").description("Print a config value").action(
|
|
3054
3308
|
wrapAction(async (key) => {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: clickup
|
|
3
|
-
description: 'Use when managing ClickUp tasks, sprints, or comments via the `cu` CLI tool. Triggers: task queries, status updates, sprint tracking, creating subtasks, posting comments, standup summaries, searching tasks, checking overdue items, assigning tasks, listing spaces and lists, opening tasks in browser, checking auth or config, setting custom fields, deleting tasks, managing tags, managing checklists, editing comments.'
|
|
3
|
+
description: 'Use when managing ClickUp tasks, sprints, or comments via the `cu` CLI tool. Triggers: task queries, status updates, sprint tracking, creating subtasks, posting comments, standup summaries, searching tasks, checking overdue items, assigning tasks, listing spaces and lists, opening tasks in browser, checking auth or config, setting custom fields, deleting tasks, managing tags, managing checklists, editing comments, time tracking.'
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
# ClickUp CLI (`cu`)
|
|
@@ -73,6 +73,11 @@ All commands support `--help` for full flag details.
|
|
|
73
73
|
| `cu checklist add-item <checklistId> <name> [--json]` | Add item to a checklist |
|
|
74
74
|
| `cu checklist edit-item <checklistId> <itemId> [--name n] [--resolved] [--unresolved] [--assignee id] [--json]` | Edit a checklist item |
|
|
75
75
|
| `cu checklist delete-item <checklistId> <itemId> [--json]` | Delete a checklist item |
|
|
76
|
+
| `cu time start <taskId> [-d desc] [--json]` | Start tracking time on a task |
|
|
77
|
+
| `cu time stop [--json]` | Stop the running timer |
|
|
78
|
+
| `cu time status [--json]` | Show currently running timer |
|
|
79
|
+
| `cu time log <taskId> <duration> [-d desc] [--json]` | Log manual time entry (e.g. "2h", "30m") |
|
|
80
|
+
| `cu time list [--days n] [--task id] [--json]` | List recent time entries |
|
|
76
81
|
| `cu config get <key>` / `cu config set <key> <value>` / `cu config path` | Manage CLI config |
|
|
77
82
|
| `cu completion <shell>` | Shell completions (bash/zsh/fish) |
|
|
78
83
|
|
|
@@ -106,6 +111,7 @@ All commands support `--help` for full flag details.
|
|
|
106
111
|
| `cu overdue` | Excludes closed tasks, sorted most overdue first |
|
|
107
112
|
| `cu open` | Tries task ID first, falls back to name search |
|
|
108
113
|
| `cu checklist` | Full CRUD for task checklists: view, create, delete, add-item, edit-item, delete-item |
|
|
114
|
+
| `cu time` | Track time: start/stop timer, log entries, list history. Duration format: "2h", "30m", "1h30m" |
|
|
109
115
|
| `cu comment-edit` | Edit comment text and resolution status |
|
|
110
116
|
| `cu task` | Shows custom fields and checklists in detail view |
|
|
111
117
|
| `cu lists` | Discovers list IDs needed for `--list` and `cu create -l` |
|
|
@@ -164,6 +170,11 @@ cu checklist create abc123def "QA Steps" # add checklist
|
|
|
164
170
|
cu checklist add-item <clId> "Run unit tests" # add item
|
|
165
171
|
cu checklist edit-item <clId> <itemId> --resolved # check off item
|
|
166
172
|
cu comment-edit <commentId> -m "Updated findings" # edit a comment
|
|
173
|
+
cu time start abc123def -d "Working on feature" # start timer
|
|
174
|
+
cu time status # check running timer
|
|
175
|
+
cu time stop # stop timer
|
|
176
|
+
cu time log abc123def 2h -d "Code review" # log manual entry
|
|
177
|
+
cu time list --days 7 # recent entries
|
|
167
178
|
cu delete abc123def --confirm # irreversible!
|
|
168
179
|
```
|
|
169
180
|
|