@krodak/clickup-cli 1.36.0 → 1.38.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.36.0",
4
+ "version": "1.38.0",
5
5
  "author": {
6
6
  "name": "Krzysztof Rodak"
7
7
  },
package/dist/index.js CHANGED
@@ -74,6 +74,10 @@ function normalizeTaskId(input) {
74
74
  const match = /^https?:\/\/app\.clickup\.com\/t\/(?:[^/?#]+\/)?([^/?#]+)/.exec(input.trim());
75
75
  return match ? match[1] : input;
76
76
  }
77
+ function normalizeViewId(input) {
78
+ const match = /^https?:\/\/app\.clickup\.com\/[^/]+\/v\/[^/]+\/([^/?#]+)/.exec(input.trim());
79
+ return match ? match[1] : input;
80
+ }
77
81
  var ClickUpClient = class {
78
82
  apiToken;
79
83
  teamId;
@@ -394,10 +398,12 @@ var ClickUpClient = class {
394
398
  return readCollectionField(data, "views", "views");
395
399
  }
396
400
  async getViewTasks(viewId) {
397
- return this.paginate((page) => `/view/${viewId}/task?page=${page}`);
401
+ const id = normalizeViewId(viewId);
402
+ return this.paginate((page) => `/view/${id}/task?page=${page}`);
398
403
  }
399
404
  async getView(viewId) {
400
- const data = await this.request(`/view/${viewId}`);
405
+ const id = normalizeViewId(viewId);
406
+ const data = await this.request(`/view/${id}`);
401
407
  return expectRecordField(data, "view", "view");
402
408
  }
403
409
  async createListView(listId, payload) {
@@ -408,14 +414,16 @@ var ClickUpClient = class {
408
414
  return expectRecordField(data, "view", "view");
409
415
  }
410
416
  async updateView(viewId, payload) {
411
- const data = await this.request(`/view/${viewId}`, {
417
+ const id = normalizeViewId(viewId);
418
+ const data = await this.request(`/view/${id}`, {
412
419
  method: "PUT",
413
420
  body: JSON.stringify(payload)
414
421
  });
415
422
  return expectRecordField(data, "view", "view");
416
423
  }
417
424
  async deleteView(viewId) {
418
- await this.request(`/view/${viewId}`, { method: "DELETE" });
425
+ const id = normalizeViewId(viewId);
426
+ await this.request(`/view/${id}`, { method: "DELETE" });
419
427
  }
420
428
  async getListTemplates(teamId) {
421
429
  const data = await this.request(`/team/${teamId}/list_template`);
@@ -1113,13 +1121,15 @@ var ClickUpClient = class {
1113
1121
  });
1114
1122
  }
1115
1123
  async getViewComments(viewId) {
1116
- const data = await this.request(`/view/${viewId}/comment`);
1124
+ const id = normalizeViewId(viewId);
1125
+ const data = await this.request(`/view/${id}/comment`);
1117
1126
  return readCollectionField(data, "comments", "view comments");
1118
1127
  }
1119
1128
  async postViewComment(viewId, commentText, notifyAll, richBlocks) {
1129
+ const id = normalizeViewId(viewId);
1120
1130
  const body = richBlocks ? { comment: richBlocks } : { comment_text: commentText };
1121
1131
  if (notifyAll) body.notify_all = true;
1122
- return this.request(`/view/${viewId}/comment`, {
1132
+ return this.request(`/view/${id}/comment`, {
1123
1133
  method: "POST",
1124
1134
  body: JSON.stringify(body)
1125
1135
  });
@@ -2253,9 +2263,6 @@ function buildUpdatePayload(opts, timezone) {
2253
2263
  if (opts.archive && opts.unarchive) {
2254
2264
  throw new Error("Cannot use --archive and --unarchive together");
2255
2265
  }
2256
- if (opts.parent !== void 0 && opts.detach) {
2257
- throw new Error("Cannot use --parent and --detach together");
2258
- }
2259
2266
  const payload = {};
2260
2267
  if (opts.name !== void 0) {
2261
2268
  if (!opts.name.trim()) throw new Error("Task name cannot be empty");
@@ -2298,9 +2305,7 @@ function buildUpdatePayload(opts, timezone) {
2298
2305
  if (opts.timeEstimate !== void 0) {
2299
2306
  payload.time_estimate = parseTimeEstimate(opts.timeEstimate);
2300
2307
  }
2301
- if (opts.detach) {
2302
- payload.parent = null;
2303
- } else if (opts.parent !== void 0) {
2308
+ if (opts.parent !== void 0) {
2304
2309
  payload.parent = opts.parent;
2305
2310
  }
2306
2311
  if (opts.archive) payload.archived = true;
@@ -2343,7 +2348,7 @@ async function resolveTaskType2(client, teamId, typeInput) {
2343
2348
  async function updateTask(config, taskId, options, typeInput) {
2344
2349
  if (!hasUpdateFields(options) && typeInput === void 0)
2345
2350
  throw new Error(
2346
- "Provide at least one of: --name, --description, --status, --priority, --due-date, --start-date, --time-estimate, --assignee, --remove-assignee, --group-assignee, --remove-group-assignee, --parent, --detach, --archive, --unarchive, --type"
2351
+ "Provide at least one of: --name, --description, --status, --priority, --due-date, --start-date, --time-estimate, --assignee, --remove-assignee, --group-assignee, --remove-group-assignee, --parent, --archive, --unarchive, --type"
2347
2352
  );
2348
2353
  const client = new ClickUpClient(config);
2349
2354
  const resolved = { ...options };
@@ -3849,7 +3854,6 @@ var commandMetadata = [
3849
3854
  "--group-assignee",
3850
3855
  "--remove-group-assignee",
3851
3856
  "--parent",
3852
- "--detach",
3853
3857
  "--archive",
3854
3858
  "--unarchive",
3855
3859
  "--type",
@@ -4719,6 +4723,14 @@ var commandMetadata = [
4719
4723
  flags: ["--json"],
4720
4724
  quickReference: [{ section: "read", usage: "view <viewId>", description: "Get view details" }]
4721
4725
  },
4726
+ {
4727
+ name: "view-tasks",
4728
+ description: "List tasks in a view",
4729
+ flags: ["--me", "--json"],
4730
+ quickReference: [
4731
+ { section: "read", usage: "view-tasks <viewId>", description: "List tasks in a view" }
4732
+ ]
4733
+ },
4722
4734
  {
4723
4735
  name: "view-create",
4724
4736
  description: "Create a view on a list",
@@ -5211,7 +5223,6 @@ ${renderZshTopLevelCommands(name)}
5211
5223
  '--assignee[Add assignee]:user_id:' \\
5212
5224
  '--remove-assignee[Remove assignee]:user_id:' \\
5213
5225
  '--parent[Set parent task]:task_id:' \\
5214
- '--detach[Remove parent task]' \\
5215
5226
  '--archive[Archive the task]' \\
5216
5227
  '--unarchive[Unarchive the task]' \\
5217
5228
  '--field[Set custom field]:field_name_and_value:' \\
@@ -7538,7 +7549,9 @@ async function duplicateTask(config, taskId) {
7538
7549
  const created = await client.createTask(task.list.id, {
7539
7550
  name: `${task.name} (copy)`,
7540
7551
  description: task.description,
7541
- markdown_content: task.markdown_content,
7552
+ // getTask requests include_markdown_description=true, so the source markdown
7553
+ // lives in markdown_description (markdown_content is always null on read).
7554
+ markdown_content: task.markdown_description ?? task.description,
7542
7555
  priority: task.priority ? parsePriority(task.priority.priority.toLowerCase()) : void 0,
7543
7556
  tags: task.tags?.map((t) => t.name),
7544
7557
  time_estimate: task.time_estimate ?? void 0
@@ -8033,6 +8046,22 @@ function formatViewMarkdown(view) {
8033
8046
  return lines.join("\n");
8034
8047
  }
8035
8048
 
8049
+ // src/commands/view-tasks.ts
8050
+ async function listViewTasks(config, viewId, opts) {
8051
+ const client = new ClickUpClient(config);
8052
+ const [tasks, customTypes] = await Promise.all([
8053
+ client.getViewTasks(viewId),
8054
+ client.getCustomTaskTypes(config.teamId)
8055
+ ]);
8056
+ const typeMap = buildTypeMap(customTypes);
8057
+ let filtered = tasks;
8058
+ if (opts.me) {
8059
+ const me = await client.getMe();
8060
+ filtered = tasks.filter((t) => t.assignees.some((a) => Number(a.id) === me.id));
8061
+ }
8062
+ return filtered.map((t) => summarize(t, typeMap));
8063
+ }
8064
+
8036
8065
  // src/commands/view-create.ts
8037
8066
  var VALID_VIEW_TYPES = ["list", "board", "calendar", "gantt", "table", "timeline"];
8038
8067
  var VALID_GROUP_BY_FIELDS = [
@@ -8694,7 +8723,7 @@ function buildProgram(programName = basename(process.argv[1] ?? "cup")) {
8694
8723
  ).option(
8695
8724
  "--remove-group-assignee <groupIds...>",
8696
8725
  "Remove group assignee (UUID or @handle, can repeat or comma-separated)"
8697
- ).option("--parent <taskId>", "Set parent task (makes this a subtask)").option("--detach", "Remove parent task (promote subtask to top-level)").option("--archive", "Archive the task").option("--unarchive", "Unarchive the task").option("--type <type>", "Change task type (name or custom_item_id)").option("--field <nameAndValue...>", 'Set custom field: --field "Name" value').option("--json", "Force JSON output even in terminal").action(
8726
+ ).option("--parent <taskId>", "Set parent task (makes this a subtask)").option("--archive", "Archive the task").option("--unarchive", "Unarchive the task").option("--type <type>", "Change task type (name or custom_item_id)").option("--field <nameAndValue...>", 'Set custom field: --field "Name" value').option("--json", "Force JSON output even in terminal").action(
8698
8727
  wrapAction(
8699
8728
  async (taskId, opts) => {
8700
8729
  const config = loadConfig(getProfileName());
@@ -10208,6 +10237,13 @@ function buildProgram(programName = basename(process.argv[1] ?? "cup")) {
10208
10237
  }
10209
10238
  })
10210
10239
  );
10240
+ program.command("view-tasks <viewId>").description("List tasks in a view").option("--me", "Only tasks assigned to the current user").option("--json", "Force JSON output even in terminal").action(
10241
+ wrapAction(async (viewId, opts) => {
10242
+ const config = loadConfig(getProfileName());
10243
+ const tasks = await listViewTasks(config, viewId, { me: opts.me });
10244
+ await printTasks(tasks, opts.json ?? false, config);
10245
+ })
10246
+ );
10211
10247
  program.command("view-create <listId> <name>").description("Create a view on a list").requiredOption(
10212
10248
  "-t, --type <type>",
10213
10249
  "View type (list, board, calendar, gantt, table, timeline)"
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@krodak/clickup-cli",
3
- "version": "1.36.0",
3
+ "version": "1.38.0",
4
4
  "description": "ClickUp CLI for AI agents and humans",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -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.36.0
6
+ # ClickUp CLI (`cup`) - skill version 1.38.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.36.0, 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.38.0, update with `npm install -g @krodak/clickup-cli` and refresh this skill with `cup skill`.
11
11
 
12
12
  ## Install & Configure
13
13
 
@@ -144,6 +144,7 @@ All commands support `--help` for full flag details. All commands support `--jso
144
144
  | `cup folder-templates` | Folder templates |
145
145
  | `cup views <listId>` | List views on a list |
146
146
  | `cup view <viewId>` | Get view details |
147
+ | `cup view-tasks <viewId> [--me]` | List tasks in a view (`--me` filters to you) |
147
148
  | `cup open <query>` | Open task in browser by ID or name |
148
149
  | `cup auth` | Check authentication status |
149
150
  | `cup list-comments <listId>` | Comments on a list |
@@ -163,7 +164,7 @@ All commands support `--help` for full flag details. All commands support `--jso
163
164
  | Command | What it does |
164
165
  | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
165
166
  | `cup create -n name [-l listId\|sprint:current] [-p parentId] [-d desc] [-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) |
166
- | `cup update <id> [-n name] [-d desc] [-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] [--detach] [--archive] [--unarchive] [--type type] [--field "Name" val]` | Update task fields (including custom fields and group assignees) |
167
+ | `cup update <id> [-n name] [-d desc] [-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 (including custom fields and group assignees) |
167
168
  | `cup comment <id> -m text [--notify-all] [--mention user]` | Post comment (markdown auto-converted to rich text; `--mention` for real @mentions, repeatable) |
168
169
  | `cup comment-edit <commentId> -m text [--resolved] [--unresolved] [--mention user]` | Edit a comment (markdown auto-converted to rich text; `--mention` for real @mentions) |
169
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 |
@@ -266,6 +267,7 @@ All commands support `--help` for full flag details. All commands support `--jso
266
267
  | ------------------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
267
268
  | Task IDs | Native (`abc123def`) or custom (`PROJ-123`). Custom IDs auto-detected by `PREFIX-DIGITS` format |
268
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 |
269
271
  | `--status` | Fuzzy matching: exact > starts-with > contains. Prints match to stderr |
270
272
  | `--priority` | Names (`urgent`, `high`, `normal`, `low`) or numbers (1-4) |
271
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 |