@krodak/clickup-cli 1.39.1 β†’ 1.41.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.
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "clickup-cli",
3
3
  "description": "ClickUp CLI skills for managing tasks, sprints, comments, checklists, custom fields, tags, and time tracking via the cup command",
4
- "version": "1.39.1",
4
+ "version": "1.41.0",
5
5
  "author": {
6
6
  "name": "Krzysztof Rodak"
7
7
  },
package/README.md CHANGED
@@ -186,7 +186,7 @@ Full CRUD for the core ClickUp workflow:
186
186
  | ⭐ **Favorites** | Local favorites for quick access to sprint folders, spaces, lists, folders, views, tasks |
187
187
  | πŸ‘οΈ **Views** | List, get, create, update, delete views on lists |
188
188
  | πŸ”— **Webhooks** | List, create, update, delete webhooks; scope to space, folder, list, or task |
189
- | 🏒 **Workspace** | Spaces, folders, lists (full CRUD + rename + from template), members, user groups, task types, templates, plan, shared hierarchy |
189
+ | 🏒 **Workspace** | Spaces, folders, lists (full CRUD + rename + from template; subfolder parent IDs in JSON), members, user groups, task types, templates, plan, shared hierarchy |
190
190
  | πŸ“Ž **Attachments** | Upload files to tasks, list task attachments, shown in detail views |
191
191
 
192
192
  [Full API coverage details](docs/api-coverage.md) | [Command reference](docs/commands.md)
package/dist/index.js CHANGED
@@ -2451,7 +2451,9 @@ async function createTask(config, options) {
2451
2451
  }
2452
2452
 
2453
2453
  // src/text-input.ts
2454
- import { readFileSync } from "fs";
2454
+ import { readFileSync, readSync } from "fs";
2455
+ var STDIN_TIMEOUT_MS = 3e4;
2456
+ var STDIN_RETRY_MS = 5;
2455
2457
  function resolveTextInput(args) {
2456
2458
  const { inline, file, inlineFlag, fileFlag } = args;
2457
2459
  if (inline !== void 0 && file !== void 0) {
@@ -2468,14 +2470,38 @@ function readTextFile(path, fileFlag) {
2468
2470
  throw new Error(`Cannot read ${fileFlag} "${path}": ${err.message}`, { cause: err });
2469
2471
  }
2470
2472
  }
2473
+ function sleepSync(ms) {
2474
+ Atomics.wait(new Int32Array(new SharedArrayBuffer(4)), 0, 0, ms);
2475
+ }
2471
2476
  function readStdin(fileFlag) {
2472
- try {
2473
- return readFileSync(0, "utf8");
2474
- } catch (err) {
2475
- throw new Error(`Failed to read ${fileFlag} from stdin: ${err.message}`, {
2476
- cause: err
2477
- });
2477
+ const chunks = [];
2478
+ const buffer = Buffer.alloc(64 * 1024);
2479
+ const deadline = Date.now() + STDIN_TIMEOUT_MS;
2480
+ for (; ; ) {
2481
+ let bytesRead;
2482
+ try {
2483
+ bytesRead = readSync(0, buffer, 0, buffer.length, null);
2484
+ } catch (err) {
2485
+ const code = err.code;
2486
+ if (code === "EAGAIN") {
2487
+ if (Date.now() > deadline) {
2488
+ throw new Error(
2489
+ `Timed out reading ${fileFlag} from stdin after ${STDIN_TIMEOUT_MS / 1e3}s. Pass a file path instead of "-" if no input is being piped.`,
2490
+ { cause: err }
2491
+ );
2492
+ }
2493
+ sleepSync(STDIN_RETRY_MS);
2494
+ continue;
2495
+ }
2496
+ if (code === "EOF") break;
2497
+ throw new Error(`Failed to read ${fileFlag} from stdin: ${err.message}`, {
2498
+ cause: err
2499
+ });
2500
+ }
2501
+ if (bytesRead === 0) break;
2502
+ chunks.push(Buffer.from(buffer.subarray(0, bytesRead)));
2478
2503
  }
2504
+ return Buffer.concat(chunks).toString("utf8");
2479
2505
  }
2480
2506
 
2481
2507
  // src/commands/get.ts
@@ -3982,7 +4008,15 @@ var commandMetadata = [
3982
4008
  {
3983
4009
  name: "comment-edit",
3984
4010
  description: "Edit an existing comment",
3985
- flags: ["-m", "--message", "--message-file", "--resolved", "--unresolved", "--mention", "--json"],
4011
+ flags: [
4012
+ "-m",
4013
+ "--message",
4014
+ "--message-file",
4015
+ "--resolved",
4016
+ "--unresolved",
4017
+ "--mention",
4018
+ "--json"
4019
+ ],
3986
4020
  quickReference: [
3987
4021
  {
3988
4022
  section: "write",
@@ -4193,7 +4227,7 @@ var commandMetadata = [
4193
4227
  {
4194
4228
  name: "field",
4195
4229
  description: "Set or remove a custom field value on a task",
4196
- flags: ["--set", "--remove", "--json"],
4230
+ flags: ["--set", "--value-file", "--remove", "--json"],
4197
4231
  quickReference: [
4198
4232
  {
4199
4233
  section: "write",
@@ -5430,6 +5464,7 @@ ${renderZshTopLevelCommands(name)}
5430
5464
  _arguments \\
5431
5465
  '1:task_id:' \\
5432
5466
  '--set[Set field name and value]:name_and_value:' \\
5467
+ '--value-file[Read the field value from a file (- for stdin)]:path:_files' \\
5433
5468
  '--remove[Remove field value by name]:field_name:' \\
5434
5469
  '--json[Force JSON output]'
5435
5470
  ;;
@@ -7270,7 +7305,12 @@ async function listFolders(config, spaceId, nameFilter, archived) {
7270
7305
  const results = [];
7271
7306
  for (const folder of filtered) {
7272
7307
  const lists = await client.getFolderLists(folder.id);
7273
- results.push({ id: folder.id, name: folder.name, lists });
7308
+ results.push({
7309
+ id: folder.id,
7310
+ name: folder.name,
7311
+ ...folder.parent_folder !== void 0 ? { parent_folder: folder.parent_folder } : {},
7312
+ lists
7313
+ });
7274
7314
  }
7275
7315
  return results;
7276
7316
  }
@@ -8643,6 +8683,27 @@ function splitCommaList(value) {
8643
8683
  function collect(value, previous) {
8644
8684
  return [...previous, value];
8645
8685
  }
8686
+ function resolveFieldSet(set, valueFile) {
8687
+ if (set.length > 2) {
8688
+ throw new Error("--set requires exactly two arguments: field name and value");
8689
+ }
8690
+ const name = set[0];
8691
+ if (name === void 0) {
8692
+ throw new Error("--set requires a field name");
8693
+ }
8694
+ const value = resolveTextInput({
8695
+ inline: set[1],
8696
+ file: valueFile,
8697
+ inlineFlag: "--set <value>",
8698
+ fileFlag: "--value-file"
8699
+ });
8700
+ if (value === void 0) {
8701
+ throw new Error(
8702
+ '--set requires a value: pass it inline (--set "Field Name" value) or use --value-file'
8703
+ );
8704
+ }
8705
+ return [name, value];
8706
+ }
8646
8707
  function resolveRequiredMessage(opts) {
8647
8708
  const message = resolveTextInput({
8648
8709
  inline: opts.message,
@@ -9344,16 +9405,18 @@ function buildProgram(programName = basename(process.argv[1] ?? "cup")) {
9344
9405
  }
9345
9406
  })
9346
9407
  );
9347
- program.command("field <taskId>").description("Set or remove a custom field value on a task").option("--set <nameAndValue...>", 'Set field: --set "Field Name" value').option("--remove <fieldName>", "Remove field value by name").option("--json", "Force JSON output even in terminal").action(
9408
+ program.command("field <taskId>").description("Set or remove a custom field value on a task").option("--set <nameAndValue...>", 'Set field: --set "Field Name" value').option(
9409
+ "--value-file <path>",
9410
+ 'Read the field value from a file ("-" for stdin); use with --set "Field Name". Avoids shell quoting'
9411
+ ).option("--remove <fieldName>", "Remove field value by name").option("--json", "Force JSON output even in terminal").action(
9348
9412
  wrapAction(
9349
9413
  async (taskId, opts) => {
9350
9414
  const config = loadConfig(getProfileName());
9351
9415
  const fieldOpts = {};
9352
9416
  if (opts.set) {
9353
- if (opts.set.length !== 2) {
9354
- throw new Error("--set requires exactly two arguments: field name and value");
9355
- }
9356
- fieldOpts.set = [opts.set[0], opts.set[1]];
9417
+ fieldOpts.set = resolveFieldSet(opts.set, opts.valueFile);
9418
+ } else if (opts.valueFile !== void 0) {
9419
+ throw new Error('--value-file requires --set "Field Name"');
9357
9420
  }
9358
9421
  if (opts.remove) {
9359
9422
  fieldOpts.remove = opts.remove;
@@ -9892,15 +9955,18 @@ function buildProgram(programName = basename(process.argv[1] ?? "cup")) {
9892
9955
  outputBulkResult(result, opts.json ?? false, `priority ${opts.to}`);
9893
9956
  })
9894
9957
  );
9895
- bulkCmd.command("field <taskIds...>").description("Bulk set the same custom field value on tasks").requiredOption("--set <nameAndValue...>", 'Set field: --set "Field Name" value').option("--json", "Force JSON output even in terminal").action(
9896
- wrapAction(async (taskIds, opts) => {
9897
- if (opts.set.length !== 2) {
9898
- throw new Error("--set requires exactly two arguments: field name and value");
9958
+ bulkCmd.command("field <taskIds...>").description("Bulk set the same custom field value on tasks").requiredOption("--set <nameAndValue...>", 'Set field: --set "Field Name" value').option(
9959
+ "--value-file <path>",
9960
+ 'Read the field value from a file ("-" for stdin); use with --set "Field Name"'
9961
+ ).option("--json", "Force JSON output even in terminal").action(
9962
+ wrapAction(
9963
+ async (taskIds, opts) => {
9964
+ const [fieldName, fieldValue] = resolveFieldSet(opts.set, opts.valueFile);
9965
+ const config = loadConfig(getProfileName());
9966
+ const result = await bulkField(config, fieldName, fieldValue, taskIds);
9967
+ outputBulkResult(result, opts.json ?? false, `field "${fieldName}"`);
9899
9968
  }
9900
- const config = loadConfig(getProfileName());
9901
- const result = await bulkField(config, opts.set[0], opts.set[1], taskIds);
9902
- outputBulkResult(result, opts.json ?? false, `field "${opts.set[0]}"`);
9903
- })
9969
+ )
9904
9970
  );
9905
9971
  bulkCmd.command("move <taskIds...>").description("Move multiple tasks to a single destination list").requiredOption("--to <listId>", "Destination list ID").option("--json", "Force JSON output even in terminal").action(
9906
9972
  wrapAction(async (taskIds, opts) => {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@krodak/clickup-cli",
3
- "version": "1.39.1",
3
+ "version": "1.41.0",
4
4
  "description": "ClickUp CLI for AI agents and humans",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -45,7 +45,7 @@
45
45
  },
46
46
  "dependencies": {
47
47
  "@inquirer/prompts": "^8.3.0",
48
- "chalk": "^5.6.2",
48
+ "chalk": "^6.0.0",
49
49
  "commander": "^15.0.0"
50
50
  },
51
51
  "engines": {
@@ -53,7 +53,7 @@
53
53
  },
54
54
  "devDependencies": {
55
55
  "@eslint/js": "^10.0.1",
56
- "@types/node": "^25.3.0",
56
+ "@types/node": "^26.1.1",
57
57
  "dotenv": "^17.3.1",
58
58
  "eslint": "^10.0.2",
59
59
  "eslint-config-prettier": "^10.1.8",
@@ -3,11 +3,11 @@ name: clickup
3
3
  description: 'Use when managing ClickUp tasks, sprints, or comments via the `cup` CLI tool. Triggers: task queries, status updates, sprint tracking, creating subtasks, posting comments, threaded replies, 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, task links, time tracking, attachments, file uploads, listing members, listing fields, duplicating tasks, bulk operations, goals, key results, saved filters, favorites.'
4
4
  ---
5
5
 
6
- # ClickUp CLI (`cup`) - skill version 1.39.1
6
+ # ClickUp CLI (`cup`) - skill version 1.41.0
7
7
 
8
8
  Reference for AI agents using the `cup` CLI tool. Covers task management, sprint tracking, comments, time tracking, custom fields, goals, docs, and project workflows.
9
9
 
10
- > **Version check:** Run `cup --version`. If your installed version is older than 1.39.1, update with `npm install -g @krodak/clickup-cli` and refresh this skill with `cup skill`.
10
+ > **Version check:** Run `cup --version`. If your installed version is older than 1.41.0, update with `npm install -g @krodak/clickup-cli` and refresh this skill with `cup skill`.
11
11
 
12
12
  ## Install & Configure
13
13
 
@@ -113,7 +113,7 @@ All commands support `--help` for full flag details. All commands support `--jso
113
113
  | `cup assigned [--status s] [--include-closed]` | All my tasks grouped by status |
114
114
  | `cup sprint [--status s] [--space nameOrId] [--folder id] [--include-closed]` | Tasks in active sprint (auto-detected) |
115
115
  | `cup sprints [--space nameOrId]` | List all sprints (marks active with \*) |
116
- | `cup search [query] [--status s] [--list id] [--space id] [--all] [--include-closed] [--assignee id\|me] [--tag t] [--due-before d] [--due-after d] [--created-after d] [--created-before d] [--field "Name" val]` | Search tasks by name, or list tasks filtered by flags when no query is given. `--all` for all assignees |
116
+ | `cup search [query] [--status s] [--list id] [--space id] [--all] [--include-closed] [--assignee id\|me] [--tag t] [--due-before d] [--due-after d] [--created-after d] [--created-before d] [--field "Name" val]` | Search tasks by name, or list tasks filtered by flags when no query is given. `--all` for all assignees |
117
117
  | `cup task <id>` | Single task details (custom fields, checklists, attachments, deps, links) |
118
118
  | `cup subtasks <id> [--status s] [--name q] [--include-closed]` | Subtasks of a task |
119
119
  | `cup comments <id>` | Comments on a task |
@@ -123,7 +123,7 @@ All commands support `--help` for full flag details. All commands support `--jso
123
123
  | `cup overdue [--all] [--include-closed]` | Tasks past due date (most overdue first) |
124
124
  | `cup spaces [--name partial] [--my] [--archived]` | List/filter workspace spaces |
125
125
  | `cup lists <spaceId> [--name partial] [--archived]` | Lists in a space (including folder lists) |
126
- | `cup folders <spaceId> [--name partial] [--archived]` | Folders in a space (with their lists) |
126
+ | `cup folders <spaceId> [--name partial] [--archived]` | Folders in a space (with their lists); JSON includes `parent_folder` for subfolders |
127
127
  | `cup time-in-status <id>` | Show how long a task has been in each status |
128
128
  | `cup members` | Workspace members (username, ID, email) |
129
129
  | `cup groups` | User groups/teams (handle, name, UUID, member count) for `--group-assignee` flags |
@@ -161,98 +161,98 @@ All commands support `--help` for full flag details. All commands support `--jso
161
161
 
162
162
  ### Write
163
163
 
164
- | Command | What it does |
165
- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
166
- | `cup create -n name [-l listId\|sprint:current] [-p parentId] [-d desc\|--description-file path] [-s status] [--priority p] [--due-date d] [--start-date d] [--time-estimate t] [--assignee id\|me] [--group-assignee uuid\|@handle,...] [--tags t] [--custom-item-id n] [--template id] [--field "Name" val]` | Create task (`--list` accepts `sprint:current`, `--field` sets custom fields inline; `--description-file` reads markdown from a file or `-` for stdin) |
167
- | `cup update <id> [-n name] [-d desc\|--description-file path] [-s status] [--priority p] [--due-date d\|none] [--start-date d] [--time-estimate t] [--assignee id\|me] [--remove-assignee id\|me] [--group-assignee uuid\|@handle] [--remove-group-assignee uuid\|@handle] [--parent id] [--archive] [--unarchive] [--type type] [--field "Name" val]` | Update task fields (`--description-file` reads markdown from a file or `-` for stdin) |
168
- | `cup comment <id> -m text\|--message-file path [--notify-all] [--mention user]` | Post comment (markdown auto-converted to rich text; `--message-file` reads from a file or `-` for stdin; `--mention` for real @mentions, repeatable) |
169
- | `cup comment-edit <commentId> -m text\|--message-file path [--resolved] [--unresolved] [--mention user]` | Edit a comment (markdown auto-converted to rich text; `--mention` for real @mentions) |
170
- | `cup comment-delete <commentId>` or `cup comment-delete --task <taskId> --mine [--match text]` | Delete a comment by ID or delete one of your task comments |
171
- | `cup replies <commentId>` | List threaded replies |
172
- | `cup reply <commentId> -m text\|--message-file path [--notify-all] [--mention user]` | Reply to a comment (markdown auto-converted to rich text; `--message-file` reads from a file or `-` for stdin; `--mention` for real @mentions) |
173
- | `cup assign <id> [--to ids\|me] [--remove ids\|me] [--group uuid\|@handle,...] [--remove-group uuid\|@handle,...]` | Assign/unassign users and groups (all flags accept comma-separated values) |
174
- | `cup depend <id> [--on taskId] [--blocks taskId] [--remove]` | Add/remove dependencies |
175
- | `cup move <id> [--to listId\|sprint:current] [--remove listId]` | Add/remove task from lists. **`--to` + `--remove` together changes the task's _home_ list** (uses v3 `home_list` endpoint with auto status mapping). `--to` alone adds multi-list membership. `--to` accepts `sprint:current`. |
176
- | `cup field <id> [--set "Name" value] [--remove "Name"]` | Set/remove custom field values |
177
- | `cup field-create <name> -t <type> [-d desc] [--options "a,b,c"] [--required] [--list id] [--lists id1,id2]` | Create a custom field β€” workspace-wide (default), on one list (`--list`), or bulk across lists (`--lists`, parallel, per-list reporting) |
178
- | `cup tag <id> [--add tags] [--remove tags]` | Add/remove tags on a task |
179
- | `cup link <taskId> <linksTo> [--remove]` | Link/unlink tasks |
180
- | `cup attach <taskId> <filePath>` | Upload file attachment |
181
- | `cup delete <id> [--confirm]` | Delete task (DESTRUCTIVE) |
182
- | `cup list-delete <listId> [--confirm]` | Delete list (DESTRUCTIVE, requires --confirm in non-interactive) |
183
- | `cup folder-delete <folderId> [--confirm]` | Delete folder (DESTRUCTIVE, requires --confirm in non-interactive) |
184
- | `cup space-delete <spaceId> [--confirm]` | Delete space (DESTRUCTIVE, requires --confirm in non-interactive) |
185
- | `cup duplicate <taskId>` | Duplicate a task |
186
- | `cup bulk status <status> <taskIds...>` | Bulk update status |
187
- | `cup bulk assign <taskIds...> [--to userId\|me] [--remove userId\|me]` | Bulk assign/unassign user from tasks |
188
- | `cup bulk due-date <date\|none\|clear> <taskIds...>` | Bulk set or clear due dates |
189
- | `cup bulk tag <tagName> <taskIds...> [--remove]` | Bulk add/remove tag from tasks |
190
- | `cup bulk priority <taskIds...> --to <priority>` | Bulk set priority on many tasks |
191
- | `cup bulk field <taskIds...> --set "Name" value` | Bulk set a custom field value |
192
- | `cup bulk move <taskIds...> --to <listId>` | Bulk move tasks to a destination list |
193
- | `cup checklist view <id>` | View checklists on a task |
194
- | `cup checklist create <id> <name>` | Create a checklist |
195
- | `cup checklist delete <checklistId>` | Delete a checklist |
196
- | `cup checklist add-item <checklistId> <name> [--parent itemId]` | Add item to checklist (nest under parent via `--parent`) |
197
- | `cup checklist edit-item <checklistId> <itemId> [--name n] [--resolved] [--unresolved] [--assignee id] [--parent itemId\|null]` | Edit checklist item (reparent with `--parent`, use `"null"` to unnest) |
198
- | `cup checklist delete-item <checklistId> <itemId>` | Delete checklist item |
199
- | `cup time start <taskId> [-d desc]` | Start timer |
200
- | `cup time stop` | Stop running timer |
201
- | `cup time status` | Show running timer |
202
- | `cup time log <taskId> <duration> [-d desc]` | Log manual entry (e.g. "2h", "30m") |
203
- | `cup time list [--days n] [--task id] [--all]` | List my recent time entries (--all for team) |
204
- | `cup time update <timeEntryId> [-d desc] [--duration dur]` | Update time entry |
205
- | `cup time delete <timeEntryId>` | Delete time entry |
206
- | `cup goal-create <name> [-d desc] [--color hex]` | Create a goal |
207
- | `cup goal-update <goalId> [-n name] [-d desc] [--color hex]` | Update a goal |
208
- | `cup goal-delete <goalId>` | Delete a goal |
209
- | `cup key-result-create <goalId> <name> [--type t] [--target n]` | Create key result |
210
- | `cup key-result-update <keyResultId> [--progress n] [--note text]` | Update key result |
211
- | `cup key-result-delete <keyResultId>` | Delete key result |
212
- | `cup doc-create <title> [-c content]` | Create a doc |
213
- | `cup doc-page-create <docId> <name> [-c content] [--parent-page pageId]` | Create doc page |
214
- | `cup doc-page-edit <docId> <pageId> [--name text] [-c content]` | Edit doc page |
215
- | `cup doc-delete <docId>` | Delete a doc |
216
- | `cup doc-page-delete <docId> <pageId>` | Delete doc page |
217
- | `cup space-create <name>` | Create a space |
218
- | `cup list-create <spaceId> <name> [--folder folderId] [--copy-statuses-from id]` | Create a list in a space or folder |
219
- | `cup folder-create <spaceId> <name>` | Create a folder in a space |
220
- | `cup list-rename <listId> <newName>` | Rename a list |
221
- | `cup folder-rename <folderId> <newName>` | Rename a folder |
222
- | `cup space-rename <spaceId> <newName>` | Rename a space |
223
- | `cup tag-create <spaceId> <name> [--fg color] [--bg color]` | Create space tag |
224
- | `cup tag-update <spaceId> <tagName> --name <newName> [--fg c] [--bg c]` | Update space tag |
225
- | `cup tag-delete <spaceId> <name>` | Delete space tag |
226
- | `cup list-from-template <name> --template <id> [--space id] [--folder id]` | Create list from template |
227
- | `cup view-create <listId> <name> -t <type> [--group-by field]` | Create a view on a list |
228
- | `cup view-update <viewId> [-n name] [--group-by field]` | Update a view |
229
- | `cup view-delete <viewId> [--confirm]` | Delete a view (DESTRUCTIVE) |
230
- | `cup list-comment <listId> -m text [--notify-all] [--mention user]` | Post comment on a list (`--mention` for real @mentions) |
231
- | `cup view-comment <viewId> -m text [--notify-all] [--mention user]` | Post comment on a view (`--mention` for real @mentions) |
232
- | `cup webhook create --url <url> --events <events> [--space\|--folder\|--list\|--task <id>]` | Create a webhook |
233
- | `cup webhook update <webhookId> [--url u] [--events e] [--status s]` | Update a webhook |
234
- | `cup webhook delete <webhookId> [--confirm]` | Delete a webhook (DESTRUCTIVE) |
235
- | `cup merge <sourceTaskId> <intoTaskId> [--confirm]` | Merge task into another (DESTRUCTIVE, source deleted) |
236
- | `cup time estimate-by-user <taskId> <userId> <duration> [--replace]` | Set per-user time estimate |
237
- | `cup chat send <channelId> -m <text> [--post --title t]` | Send message to channel |
238
- | `cup chat reply <messageId> -m <text>` | Reply to a message |
239
- | `cup chat react <messageId> --emoji <name>` | Add reaction |
240
- | `cup chat unreact <messageId> --emoji <name>` | Remove reaction |
241
- | `cup chat channel-create <name> [--private] [--topic t]` | Create channel |
242
- | `cup chat dm <userIds...>` | Create/open DM |
243
- | `cup chat channel-update <id> [--name n] [--topic t]` | Update channel |
244
- | `cup chat channel-delete <id> [--confirm]` | Delete channel |
245
- | `cup chat message-update <messageId> -m <text>` | Edit message |
246
- | `cup chat message-delete <messageId> [--confirm]` | Delete message |
247
- | `cup favorite add <type> <id> [alias] [-n name]` | Add a local favorite |
248
- | `cup favorite remove <alias>` | Remove a favorite |
249
- | `cup favorite list [--type t]` | List favorites (optionally filter by type) |
250
- | `cup profile list [--json]` | List all profiles |
251
- | `cup profile add <name>` | Add a new profile (interactive) |
252
- | `cup profile remove <name>` | Remove a profile |
253
- | `cup profile use <name>` | Set the default profile |
254
- | `cup config get <key>` / `set <key> <value>` / `path` | Manage config |
255
- | `cup completion <shell>` | Shell completions (bash/zsh/fish) |
164
+ | Command | What it does |
165
+ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
166
+ | `cup create -n name [-l listId\|sprint:current] [-p parentId] [-d desc\|--description-file path] [-s status] [--priority p] [--due-date d] [--start-date d] [--time-estimate t] [--assignee id\|me] [--group-assignee uuid\|@handle,...] [--tags t] [--custom-item-id n] [--template id] [--field "Name" val]` | Create task (`--list` accepts `sprint:current`, `--field` sets custom fields inline; `--description-file` reads markdown from a file or `-` for stdin) |
167
+ | `cup update <id> [-n name] [-d desc\|--description-file path] [-s status] [--priority p] [--due-date d\|none] [--start-date d] [--time-estimate t] [--assignee id\|me] [--remove-assignee id\|me] [--group-assignee uuid\|@handle] [--remove-group-assignee uuid\|@handle] [--parent id] [--archive] [--unarchive] [--type type] [--field "Name" val]` | Update task fields (`--description-file` reads markdown from a file or `-` for stdin) |
168
+ | `cup comment <id> -m text\|--message-file path [--notify-all] [--mention user]` | Post comment (markdown auto-converted to rich text; `--message-file` reads from a file or `-` for stdin; `--mention` for real @mentions, repeatable) |
169
+ | `cup comment-edit <commentId> -m text\|--message-file path [--resolved] [--unresolved] [--mention user]` | Edit a comment (markdown auto-converted to rich text; `--mention` for real @mentions) |
170
+ | `cup comment-delete <commentId>` or `cup comment-delete --task <taskId> --mine [--match text]` | Delete a comment by ID or delete one of your task comments |
171
+ | `cup replies <commentId>` | List threaded replies |
172
+ | `cup reply <commentId> -m text\|--message-file path [--notify-all] [--mention user]` | Reply to a comment (markdown auto-converted to rich text; `--message-file` reads from a file or `-` for stdin; `--mention` for real @mentions) |
173
+ | `cup assign <id> [--to ids\|me] [--remove ids\|me] [--group uuid\|@handle,...] [--remove-group uuid\|@handle,...]` | Assign/unassign users and groups (all flags accept comma-separated values) |
174
+ | `cup depend <id> [--on taskId] [--blocks taskId] [--remove]` | Add/remove dependencies |
175
+ | `cup move <id> [--to listId\|sprint:current] [--remove listId]` | Add/remove task from lists. **`--to` + `--remove` together changes the task's _home_ list** (uses v3 `home_list` endpoint with auto status mapping). `--to` alone adds multi-list membership. `--to` accepts `sprint:current`. |
176
+ | `cup field <id> [--set "Name" value\|--set "Name" --value-file path] [--remove "Name"]` | Set/remove custom field values (`--value-file` reads the value from a file or `-` for stdin; use for long/free-text values) |
177
+ | `cup field-create <name> -t <type> [-d desc] [--options "a,b,c"] [--required] [--list id] [--lists id1,id2]` | Create a custom field β€” workspace-wide (default), on one list (`--list`), or bulk across lists (`--lists`, parallel, per-list reporting) |
178
+ | `cup tag <id> [--add tags] [--remove tags]` | Add/remove tags on a task |
179
+ | `cup link <taskId> <linksTo> [--remove]` | Link/unlink tasks |
180
+ | `cup attach <taskId> <filePath>` | Upload file attachment |
181
+ | `cup delete <id> [--confirm]` | Delete task (DESTRUCTIVE) |
182
+ | `cup list-delete <listId> [--confirm]` | Delete list (DESTRUCTIVE, requires --confirm in non-interactive) |
183
+ | `cup folder-delete <folderId> [--confirm]` | Delete folder (DESTRUCTIVE, requires --confirm in non-interactive) |
184
+ | `cup space-delete <spaceId> [--confirm]` | Delete space (DESTRUCTIVE, requires --confirm in non-interactive) |
185
+ | `cup duplicate <taskId>` | Duplicate a task |
186
+ | `cup bulk status <status> <taskIds...>` | Bulk update status |
187
+ | `cup bulk assign <taskIds...> [--to userId\|me] [--remove userId\|me]` | Bulk assign/unassign user from tasks |
188
+ | `cup bulk due-date <date\|none\|clear> <taskIds...>` | Bulk set or clear due dates |
189
+ | `cup bulk tag <tagName> <taskIds...> [--remove]` | Bulk add/remove tag from tasks |
190
+ | `cup bulk priority <taskIds...> --to <priority>` | Bulk set priority on many tasks |
191
+ | `cup bulk field <taskIds...> --set "Name" value` | Bulk set a custom field value |
192
+ | `cup bulk move <taskIds...> --to <listId>` | Bulk move tasks to a destination list |
193
+ | `cup checklist view <id>` | View checklists on a task |
194
+ | `cup checklist create <id> <name>` | Create a checklist |
195
+ | `cup checklist delete <checklistId>` | Delete a checklist |
196
+ | `cup checklist add-item <checklistId> <name> [--parent itemId]` | Add item to checklist (nest under parent via `--parent`) |
197
+ | `cup checklist edit-item <checklistId> <itemId> [--name n] [--resolved] [--unresolved] [--assignee id] [--parent itemId\|null]` | Edit checklist item (reparent with `--parent`, use `"null"` to unnest) |
198
+ | `cup checklist delete-item <checklistId> <itemId>` | Delete checklist item |
199
+ | `cup time start <taskId> [-d desc]` | Start timer |
200
+ | `cup time stop` | Stop running timer |
201
+ | `cup time status` | Show running timer |
202
+ | `cup time log <taskId> <duration> [-d desc]` | Log manual entry (e.g. "2h", "30m") |
203
+ | `cup time list [--days n] [--task id] [--all]` | List my recent time entries (--all for team) |
204
+ | `cup time update <timeEntryId> [-d desc] [--duration dur]` | Update time entry |
205
+ | `cup time delete <timeEntryId>` | Delete time entry |
206
+ | `cup goal-create <name> [-d desc] [--color hex]` | Create a goal |
207
+ | `cup goal-update <goalId> [-n name] [-d desc] [--color hex]` | Update a goal |
208
+ | `cup goal-delete <goalId>` | Delete a goal |
209
+ | `cup key-result-create <goalId> <name> [--type t] [--target n]` | Create key result |
210
+ | `cup key-result-update <keyResultId> [--progress n] [--note text]` | Update key result |
211
+ | `cup key-result-delete <keyResultId>` | Delete key result |
212
+ | `cup doc-create <title> [-c content]` | Create a doc |
213
+ | `cup doc-page-create <docId> <name> [-c content] [--parent-page pageId]` | Create doc page |
214
+ | `cup doc-page-edit <docId> <pageId> [--name text] [-c content]` | Edit doc page |
215
+ | `cup doc-delete <docId>` | Delete a doc |
216
+ | `cup doc-page-delete <docId> <pageId>` | Delete doc page |
217
+ | `cup space-create <name>` | Create a space |
218
+ | `cup list-create <spaceId> <name> [--folder folderId] [--copy-statuses-from id]` | Create a list in a space or folder |
219
+ | `cup folder-create <spaceId> <name>` | Create a folder in a space |
220
+ | `cup list-rename <listId> <newName>` | Rename a list |
221
+ | `cup folder-rename <folderId> <newName>` | Rename a folder |
222
+ | `cup space-rename <spaceId> <newName>` | Rename a space |
223
+ | `cup tag-create <spaceId> <name> [--fg color] [--bg color]` | Create space tag |
224
+ | `cup tag-update <spaceId> <tagName> --name <newName> [--fg c] [--bg c]` | Update space tag |
225
+ | `cup tag-delete <spaceId> <name>` | Delete space tag |
226
+ | `cup list-from-template <name> --template <id> [--space id] [--folder id]` | Create list from template |
227
+ | `cup view-create <listId> <name> -t <type> [--group-by field]` | Create a view on a list |
228
+ | `cup view-update <viewId> [-n name] [--group-by field]` | Update a view |
229
+ | `cup view-delete <viewId> [--confirm]` | Delete a view (DESTRUCTIVE) |
230
+ | `cup list-comment <listId> -m text [--notify-all] [--mention user]` | Post comment on a list (`--mention` for real @mentions) |
231
+ | `cup view-comment <viewId> -m text [--notify-all] [--mention user]` | Post comment on a view (`--mention` for real @mentions) |
232
+ | `cup webhook create --url <url> --events <events> [--space\|--folder\|--list\|--task <id>]` | Create a webhook |
233
+ | `cup webhook update <webhookId> [--url u] [--events e] [--status s]` | Update a webhook |
234
+ | `cup webhook delete <webhookId> [--confirm]` | Delete a webhook (DESTRUCTIVE) |
235
+ | `cup merge <sourceTaskId> <intoTaskId> [--confirm]` | Merge task into another (DESTRUCTIVE, source deleted) |
236
+ | `cup time estimate-by-user <taskId> <userId> <duration> [--replace]` | Set per-user time estimate |
237
+ | `cup chat send <channelId> -m <text> [--post --title t]` | Send message to channel |
238
+ | `cup chat reply <messageId> -m <text>` | Reply to a message |
239
+ | `cup chat react <messageId> --emoji <name>` | Add reaction |
240
+ | `cup chat unreact <messageId> --emoji <name>` | Remove reaction |
241
+ | `cup chat channel-create <name> [--private] [--topic t]` | Create channel |
242
+ | `cup chat dm <userIds...>` | Create/open DM |
243
+ | `cup chat channel-update <id> [--name n] [--topic t]` | Update channel |
244
+ | `cup chat channel-delete <id> [--confirm]` | Delete channel |
245
+ | `cup chat message-update <messageId> -m <text>` | Edit message |
246
+ | `cup chat message-delete <messageId> [--confirm]` | Delete message |
247
+ | `cup favorite add <type> <id> [alias] [-n name]` | Add a local favorite |
248
+ | `cup favorite remove <alias>` | Remove a favorite |
249
+ | `cup favorite list [--type t]` | List favorites (optionally filter by type) |
250
+ | `cup profile list [--json]` | List all profiles |
251
+ | `cup profile add <name>` | Add a new profile (interactive) |
252
+ | `cup profile remove <name>` | Remove a profile |
253
+ | `cup profile use <name>` | Set the default profile |
254
+ | `cup config get <key>` / `set <key> <value>` / `path` | Manage config |
255
+ | `cup completion <shell>` | Shell completions (bash/zsh/fish) |
256
256
 
257
257
  ## Global Flags
258
258
 
@@ -263,38 +263,38 @@ All commands support `--help` for full flag details. All commands support `--jso
263
263
 
264
264
  ## Flags & Conventions
265
265
 
266
- | Topic | Detail |
267
- | ------------------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
268
- | Task IDs | Native (`abc123def`) or custom (`PROJ-123`). Custom IDs auto-detected by `PREFIX-DIGITS` format |
269
- | Task URLs | All commands that accept a task ID also accept full ClickUp URLs (`https://app.clickup.com/t/<id>` or `https://app.clickup.com/t/<workspace>/<id>`). The ID is auto-extracted |
270
- | View URLs | All commands that accept a view ID also accept full ClickUp view URLs (`https://app.clickup.com/<workspace>/v/<type>/<viewId>`). The ID is auto-extracted |
271
- | `--status` | Fuzzy matching: exact > starts-with > contains. Prints match to stderr |
272
- | `--priority` | Names (`urgent`, `high`, `normal`, `low`) or numbers (1-4) |
273
- | `--due-date` | `YYYY-MM-DD` (date only), `YYYY-MM-DDTHH:MM` (with time), or full ISO 8601 with offset. Time-of-day formats set `due_date_time: true` in ClickUp |
274
- | `--assignee` | User ID or `me` |
275
- | `--tags` | Comma-separated (e.g. `--tags "bug,frontend"`) |
276
- | `--time-estimate` | Duration: `"2h"`, `"30m"`, `"1h30m"`, or raw milliseconds |
277
- | `--type` | `task` (regular) or custom type name/ID (e.g. `initiative`, `Bug`) |
278
- | `--custom-item-id` | Custom task type ID for `cup create` (find with `cup task-types`) |
279
- | `--space` | Partial name match or exact ID |
280
- | `--name` | Partial match, case-insensitive |
281
- | `--all` | Show all tasks in workspace, not just assigned to me. Available on `tasks`, `search`, `overdue`. Default: my tasks only (smaller output for agent context windows) |
282
- | `--include-closed` | Include closed/done tasks |
283
- | `--list` on create | Optional when `--parent` is given (auto-detected). Accepts `sprint:current` pseudo-ID |
284
- | `cup field --set` | Supports: text, number, checkbox (true/false), dropdown (option name), labels (comma-separated names), date (YYYY-MM-DD), url, email, emoji/rating (0-5), manual_progress (0-100), tasks/relationship (comma-separated task IDs), users/people (comma-separated user IDs). Names resolved case-insensitively; errors list available fields/options |
285
- | `cup field-create` | Use `--options "a,b,c"` for `drop_down` and `labels` types (required). Other types don't need `--options` |
286
- | `--field` filter | `--field "Name" value` on `tasks` and `search` requires `--list` to resolve field names to IDs |
287
- | `--due-before/after` | `YYYY-MM-DD` date filters for due date range |
288
- | `--created-before/after` | `YYYY-MM-DD` date filters for creation date range |
289
- | `cup sprint` | Auto-detects active sprint by folder name (sprint/iteration/cycle/scrum), parses multiple date formats. Override with `--folder <id>`, `cup config set sprintFolderId <id>`, or favorite a sprint folder |
290
- | `cup favorite` | Local-only favorites (not synced to ClickUp). Types: sprint-folder, space, list, folder, view, task. Favorited sprint-folders auto-used by sprint commands |
291
- | `cup link` | Both IDs must be the same type (both custom or both native) |
292
- | `cup delete` | DESTRUCTIVE. Requires `--confirm` in non-interactive mode. Cannot be undone |
293
- | Errors | stderr with exit code 1. Strict parsing - excess/unknown arguments rejected |
294
- | Rate limiting | The client auto-retries on HTTP 429 and transient 5xx (502/503/504) with `Retry-After`-aware backoff (up to 3 retries). Retry warnings go to stderr. No action needed by callers |
295
- | Multiline markdown (`-d` / `-m`) | **Best for agents:** use `--description-file <path>` / `--message-file <path>` (or `-` for stdin) to bypass shell quoting entirely β€” see the multiline example below. For inline multiline, use a **quoted heredoc** `"$(cat <<'EOF' … EOF)"` β€” it preserves backticks, newlines, and apostrophes. **Footgun:** never split a `$'...'` string with `'\''` for an apostrophe β€” the tail drops back to normal single quotes and `\n` becomes literal text (e.g. `$'…team'\''s…\n## Goals'` breaks). Plain double quotes execute backticks as commands. |
296
- | `--mention <user>` | Real ClickUp @mention (notifies the user). Accepts ID, email, username, or `me`. Repeatable. Also: `<@userId>` inline token in `-m` for mid-sentence mentions. Bare `@Name` is NOT parsed (ambiguous). On `comment`, `reply`, `comment-edit`, `list-comment`, `view-comment` |
297
- | Comment links | In comment messages, bare URLs (`https://...`) and markdown links (`[text](url)`) both render as clickable links. Unfurled preview cards are not supported (web-UI only) |
266
+ | Topic | Detail |
267
+ | ----------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
268
+ | Task IDs | Native (`abc123def`) or custom (`PROJ-123`). Custom IDs auto-detected by `PREFIX-DIGITS` format |
269
+ | Task URLs | All commands that accept a task ID also accept full ClickUp URLs (`https://app.clickup.com/t/<id>` or `https://app.clickup.com/t/<workspace>/<id>`). The ID is auto-extracted |
270
+ | View URLs | All commands that accept a view ID also accept full ClickUp view URLs (`https://app.clickup.com/<workspace>/v/<type>/<viewId>`). The ID is auto-extracted |
271
+ | `--status` | Fuzzy matching: exact > starts-with > contains. Prints match to stderr |
272
+ | `--priority` | Names (`urgent`, `high`, `normal`, `low`) or numbers (1-4) |
273
+ | `--due-date` | `YYYY-MM-DD` (date only), `YYYY-MM-DDTHH:MM` (with time), or full ISO 8601 with offset. Time-of-day formats set `due_date_time: true` in ClickUp |
274
+ | `--assignee` | User ID or `me` |
275
+ | `--tags` | Comma-separated (e.g. `--tags "bug,frontend"`) |
276
+ | `--time-estimate` | Duration: `"2h"`, `"30m"`, `"1h30m"`, or raw milliseconds |
277
+ | `--type` | `task` (regular) or custom type name/ID (e.g. `initiative`, `Bug`) |
278
+ | `--custom-item-id` | Custom task type ID for `cup create` (find with `cup task-types`) |
279
+ | `--space` | Partial name match or exact ID |
280
+ | `--name` | Partial match, case-insensitive |
281
+ | `--all` | Show all tasks in workspace, not just assigned to me. Available on `tasks`, `search`, `overdue`. Default: my tasks only (smaller output for agent context windows) |
282
+ | `--include-closed` | Include closed/done tasks |
283
+ | `--list` on create | Optional when `--parent` is given (auto-detected). Accepts `sprint:current` pseudo-ID |
284
+ | `cup field --set` | Supports: text, number, checkbox (true/false), dropdown (option name), labels (comma-separated names), date (YYYY-MM-DD), url, email, emoji/rating (0-5), manual_progress (0-100), tasks/relationship (comma-separated task IDs), users/people (comma-separated user IDs). Names resolved case-insensitively; errors list available fields/options |
285
+ | `cup field-create` | Use `--options "a,b,c"` for `drop_down` and `labels` types (required). Other types don't need `--options` |
286
+ | `--field` filter | `--field "Name" value` on `tasks` and `search` requires `--list` to resolve field names to IDs |
287
+ | `--due-before/after` | `YYYY-MM-DD` date filters for due date range |
288
+ | `--created-before/after` | `YYYY-MM-DD` date filters for creation date range |
289
+ | `cup sprint` | Auto-detects active sprint by folder name (sprint/iteration/cycle/scrum), parses multiple date formats. Override with `--folder <id>`, `cup config set sprintFolderId <id>`, or favorite a sprint folder |
290
+ | `cup favorite` | Local-only favorites (not synced to ClickUp). Types: sprint-folder, space, list, folder, view, task. Favorited sprint-folders auto-used by sprint commands |
291
+ | `cup link` | Both IDs must be the same type (both custom or both native) |
292
+ | `cup delete` | DESTRUCTIVE. Requires `--confirm` in non-interactive mode. Cannot be undone |
293
+ | Errors | stderr with exit code 1. Strict parsing - excess/unknown arguments rejected |
294
+ | Rate limiting | The client auto-retries on HTTP 429 and transient 5xx (502/503/504) with `Retry-After`-aware backoff (up to 3 retries). Retry warnings go to stderr. No action needed by callers |
295
+ | Multiline markdown (`-d` / `-m` / field values) | **Best for agents:** use `--description-file <path>` / `--message-file <path>` / `--value-file <path>` (or `-` for stdin) to bypass shell quoting entirely β€” see the multiline example below. For inline multiline, use a **quoted heredoc** `"$(cat <<'EOF' … EOF)"` β€” it preserves backticks, newlines, and apostrophes. **Footgun:** never split a `$'...'` string with `'\''` for an apostrophe β€” the tail drops back to normal single quotes and `\n` becomes literal text (e.g. `$'…team'\''s…\n## Goals'` breaks). Plain double quotes execute backticks as commands. |
296
+ | `--mention <user>` | Real ClickUp @mention (notifies the user). Accepts ID, email, username, or `me`. Repeatable. Also: `<@userId>` inline token in `-m` for mid-sentence mentions. Bare `@Name` is NOT parsed (ambiguous). On `comment`, `reply`, `comment-edit`, `list-comment`, `view-comment` |
297
+ | Comment links | In comment messages, bare URLs (`https://...`) and markdown links (`[text](url)`) both render as clickable links. Unfurled preview cards are not supported (web-UI only) |
298
298
 
299
299
  > **Note:** `cup search`, `cup tasks`, `cup overdue`, and `cup assigned` default to tasks assigned to the current user. Use `--all` to include tasks assigned to others. This matters when searching for parent initiatives or team-wide items.
300
300
 
@@ -393,6 +393,7 @@ Agents produce structured markdown (headings, bullets, code, apostrophes). Shell
393
393
  cup create -n "Improve onboarding" -l <listId> --description-file /tmp/desc.md
394
394
  cup update <taskId> --description-file /tmp/desc.md
395
395
  cup comment <taskId> --message-file /tmp/comment.md
396
+ cup field <taskId> --set "Standup 4 - 6/25" --value-file /tmp/note.md
396
397
  # "-" reads stdin:
397
398
  printf '## Notes\n\nTeam'\''s update with `code`.' | cup update <taskId> --description-file -
398
399