@krodak/clickup-cli 1.28.0 → 1.29.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.28.0",
4
+ "version": "1.29.0",
5
5
  "author": {
6
6
  "name": "Krzysztof Rodak"
7
7
  },
package/README.md CHANGED
@@ -185,8 +185,8 @@ Full CRUD for the core ClickUp workflow:
185
185
  | 🏃 **Sprints** | Auto-detect active sprint, `sprint:current` pseudo-ID for move/create, flexible date parsing, config override, favorite sprint folders |
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
- | 🏢 **Workspace** | Spaces, folders, lists (read + create + rename + from template), members, task types, templates |
189
- | 📎 **Attachments** | Upload files to tasks, shown in detail views |
188
+ | 🏢 **Workspace** | Spaces, folders, lists (full CRUD + rename + from template), members, task types, templates, plan |
189
+ | 📎 **Attachments** | Upload files to tasks, list task attachments, shown in detail views |
190
190
 
191
191
  [Full API coverage details](docs/api-coverage.md) | [Command reference](docs/commands.md)
192
192
 
package/dist/index.js CHANGED
@@ -445,6 +445,28 @@ var ClickUpClient = class {
445
445
  async deleteTask(taskId) {
446
446
  await this.request(this.taskPath(taskId), { method: "DELETE" });
447
447
  }
448
+ async deleteList(listId) {
449
+ await this.request(`/list/${listId}`, { method: "DELETE" });
450
+ }
451
+ async deleteFolder(folderId) {
452
+ await this.request(`/folder/${folderId}`, { method: "DELETE" });
453
+ }
454
+ async deleteSpace(spaceId) {
455
+ await this.request(`/space/${spaceId}`, { method: "DELETE" });
456
+ }
457
+ async getTaskMembers(taskId) {
458
+ const data = await this.request(this.taskPath(taskId, "/member"));
459
+ return readCollectionField(data, "members", "task members");
460
+ }
461
+ async getWorkspacePlan() {
462
+ return this.request(`/team/${this.teamId}/plan`);
463
+ }
464
+ async getTaskAttachments(taskId) {
465
+ const data = await this.requestV3(
466
+ `/workspaces/${this.teamId}/tasks/${taskId}/attachments`
467
+ );
468
+ return expectArrayField(data, "data", "task attachments");
469
+ }
448
470
  async addTagToTask(taskId, tagName) {
449
471
  await this.request(this.taskPath(taskId, `/tag/${encodeURIComponent(tagName)}`), {
450
472
  method: "POST"
@@ -3888,6 +3910,60 @@ var commandMetadata = [
3888
3910
  flags: ["--confirm", "--json"],
3889
3911
  quickReference: [{ section: "write", usage: "delete <taskId>", description: "Delete a task" }]
3890
3912
  },
3913
+ {
3914
+ name: "list-delete",
3915
+ description: "Delete a list (requires confirmation)",
3916
+ flags: ["--confirm", "--json"],
3917
+ quickReference: [
3918
+ { section: "write", usage: "list-delete <listId>", description: "Delete a list" }
3919
+ ]
3920
+ },
3921
+ {
3922
+ name: "folder-delete",
3923
+ description: "Delete a folder (requires confirmation)",
3924
+ flags: ["--confirm", "--json"],
3925
+ quickReference: [
3926
+ { section: "write", usage: "folder-delete <folderId>", description: "Delete a folder" }
3927
+ ]
3928
+ },
3929
+ {
3930
+ name: "space-delete",
3931
+ description: "Delete a space (requires confirmation)",
3932
+ flags: ["--confirm", "--json"],
3933
+ quickReference: [
3934
+ { section: "write", usage: "space-delete <spaceId>", description: "Delete a space" }
3935
+ ]
3936
+ },
3937
+ {
3938
+ name: "attachments",
3939
+ description: "List attachments on a task",
3940
+ flags: ["--json"],
3941
+ quickReference: [
3942
+ {
3943
+ section: "read",
3944
+ usage: "attachments <taskId>",
3945
+ description: "List attachments on a task"
3946
+ }
3947
+ ]
3948
+ },
3949
+ {
3950
+ name: "task-members",
3951
+ description: "List members with access to a task",
3952
+ flags: ["--json"],
3953
+ quickReference: [
3954
+ {
3955
+ section: "read",
3956
+ usage: "task-members <taskId>",
3957
+ description: "List members with access to a task"
3958
+ }
3959
+ ]
3960
+ },
3961
+ {
3962
+ name: "plan",
3963
+ description: "Show workspace plan",
3964
+ flags: ["--json"],
3965
+ quickReference: [{ section: "read", usage: "plan", description: "Show workspace plan" }]
3966
+ },
3891
3967
  {
3892
3968
  name: "tag",
3893
3969
  description: "Add or remove tags from a task",
@@ -6150,6 +6226,144 @@ async function deleteTaskCommand(config, taskId, opts) {
6150
6226
  return { taskId, deleted: true };
6151
6227
  }
6152
6228
 
6229
+ // src/commands/list-delete.ts
6230
+ async function deleteListCommand(config, listId, opts) {
6231
+ const client = new ClickUpClient(config);
6232
+ if (!opts.confirm) {
6233
+ if (!isTTY()) {
6234
+ throw new Error("Destructive operation requires --confirm flag in non-interactive mode");
6235
+ }
6236
+ const list = await client.getListWithStatuses(listId);
6237
+ const { confirm: confirm3 } = await import("@inquirer/prompts");
6238
+ const confirmed = await confirm3({
6239
+ message: `Delete list "${list.name}" (${listId})? This cannot be undone.`,
6240
+ default: false
6241
+ });
6242
+ if (!confirmed) {
6243
+ throw new Error("Cancelled");
6244
+ }
6245
+ }
6246
+ await client.deleteList(listId);
6247
+ return { listId, deleted: true };
6248
+ }
6249
+
6250
+ // src/commands/folder-delete.ts
6251
+ async function deleteFolderCommand(config, folderId, opts) {
6252
+ const client = new ClickUpClient(config);
6253
+ if (!opts.confirm) {
6254
+ if (!isTTY()) {
6255
+ throw new Error("Destructive operation requires --confirm flag in non-interactive mode");
6256
+ }
6257
+ const { confirm: confirm3 } = await import("@inquirer/prompts");
6258
+ const confirmed = await confirm3({
6259
+ message: `Delete folder ${folderId}? This cannot be undone.`,
6260
+ default: false
6261
+ });
6262
+ if (!confirmed) {
6263
+ throw new Error("Cancelled");
6264
+ }
6265
+ }
6266
+ await client.deleteFolder(folderId);
6267
+ return { folderId, deleted: true };
6268
+ }
6269
+
6270
+ // src/commands/space-delete.ts
6271
+ async function deleteSpaceCommand(config, spaceId, opts) {
6272
+ const client = new ClickUpClient(config);
6273
+ if (!opts.confirm) {
6274
+ if (!isTTY()) {
6275
+ throw new Error("Destructive operation requires --confirm flag in non-interactive mode");
6276
+ }
6277
+ const space = await client.getSpaceWithStatuses(spaceId);
6278
+ const { confirm: confirm3 } = await import("@inquirer/prompts");
6279
+ const confirmed = await confirm3({
6280
+ message: `Delete space "${space.name}" (${spaceId})? This cannot be undone.`,
6281
+ default: false
6282
+ });
6283
+ if (!confirmed) {
6284
+ throw new Error("Cancelled");
6285
+ }
6286
+ }
6287
+ await client.deleteSpace(spaceId);
6288
+ return { spaceId, deleted: true };
6289
+ }
6290
+
6291
+ // src/commands/attachments.ts
6292
+ function formatSize(size) {
6293
+ if (size < 1024) return `${size} B`;
6294
+ if (size < 1048576) return `${(size / 1024).toFixed(1)} KB`;
6295
+ return `${(size / 1048576).toFixed(1)} MB`;
6296
+ }
6297
+ var ATTACHMENT_COLUMNS = [
6298
+ { key: "title", label: "Title", maxWidth: 40 },
6299
+ { key: "extension", label: "Ext", maxWidth: 10 },
6300
+ { key: "size", label: "Size", maxWidth: 10 },
6301
+ { key: "date", label: "Date", maxWidth: 12 },
6302
+ { key: "url", label: "URL", maxWidth: 60 }
6303
+ ];
6304
+ function toRow(a) {
6305
+ return {
6306
+ title: a.title,
6307
+ extension: a.extension,
6308
+ size: formatSize(a.size),
6309
+ date: new Date(a.date_created).toLocaleDateString(),
6310
+ url: a.url
6311
+ };
6312
+ }
6313
+ async function listTaskAttachments(config, taskId) {
6314
+ const client = new ClickUpClient(config);
6315
+ return client.getTaskAttachments(taskId);
6316
+ }
6317
+ function formatAttachmentsTable(attachments) {
6318
+ if (attachments.length === 0) return "No attachments found";
6319
+ const rows = attachments.map(toRow);
6320
+ return formatTable(rows, ATTACHMENT_COLUMNS);
6321
+ }
6322
+ function formatAttachmentsMarkdown(attachments) {
6323
+ if (attachments.length === 0) return "No attachments found";
6324
+ return attachments.map((a) => `- **${a.title}** (${a.extension}, ${formatSize(a.size)}) \u2014 ${a.url}`).join("\n");
6325
+ }
6326
+
6327
+ // src/commands/task-members.ts
6328
+ var TASK_MEMBER_COLUMNS = [
6329
+ { key: "username", label: "Username", maxWidth: 25 },
6330
+ { key: "id", label: "ID", maxWidth: 15 },
6331
+ { key: "email", label: "Email", maxWidth: 40 }
6332
+ ];
6333
+ async function listTaskMembers(config, taskId) {
6334
+ const client = new ClickUpClient(config);
6335
+ return client.getTaskMembers(taskId);
6336
+ }
6337
+ function formatTaskMembers(members) {
6338
+ if (members.length === 0) return "No task members found";
6339
+ const rows = members.map((m) => ({
6340
+ username: m.username,
6341
+ id: String(m.id),
6342
+ email: m.email
6343
+ }));
6344
+ return formatTable(rows, TASK_MEMBER_COLUMNS);
6345
+ }
6346
+ function formatTaskMembersMarkdown(members) {
6347
+ if (members.length === 0) return "No task members found";
6348
+ return members.map((m) => `- **${m.username}** (${m.id}) - ${m.email}`).join("\n");
6349
+ }
6350
+
6351
+ // src/commands/plan.ts
6352
+ import chalk9 from "chalk";
6353
+ async function getWorkspacePlanCommand(config) {
6354
+ const client = new ClickUpClient(config);
6355
+ return client.getWorkspacePlan();
6356
+ }
6357
+ function formatPlan(plan) {
6358
+ return [
6359
+ `${chalk9.bold("Plan:")} ${plan.name}`,
6360
+ `${chalk9.bold("Plan ID:")} ${plan.plan_id}`
6361
+ ].join("\n");
6362
+ }
6363
+ function formatPlanMarkdown(plan) {
6364
+ return [`**Plan:** ${plan.name}`, `**Plan ID:** ${plan.plan_id}`].join("\n");
6365
+ }
6366
+
6153
6367
  // src/commands/archive.ts
6154
6368
  async function archiveTaskCommand(config, taskId, opts) {
6155
6369
  const client = new ClickUpClient(config);
@@ -6210,7 +6424,7 @@ async function manageTags(config, taskId, opts) {
6210
6424
  }
6211
6425
 
6212
6426
  // src/commands/checklist.ts
6213
- import chalk9 from "chalk";
6427
+ import chalk10 from "chalk";
6214
6428
  async function viewChecklists(config, taskId) {
6215
6429
  const client = new ClickUpClient(config);
6216
6430
  const task = await client.getTask(taskId);
@@ -6260,19 +6474,19 @@ function formatChecklists(checklists) {
6260
6474
  const lines = [];
6261
6475
  const renderItem = (item, depth) => {
6262
6476
  const indent = " ".repeat(depth + 1);
6263
- const check = item.resolved ? chalk9.green("[x]") : chalk9.dim("[ ]");
6264
- const name = item.resolved ? chalk9.dim(item.name) : item.name;
6265
- const assignee = item.assignee ? chalk9.dim(` @${item.assignee.username}`) : "";
6477
+ const check = item.resolved ? chalk10.green("[x]") : chalk10.dim("[ ]");
6478
+ const name = item.resolved ? chalk10.dim(item.name) : item.name;
6479
+ const assignee = item.assignee ? chalk10.dim(` @${item.assignee.username}`) : "";
6266
6480
  lines.push(`${indent}${check} ${name}${assignee}`);
6267
- lines.push(chalk9.dim(`${indent} item-id: ${item.id}`));
6481
+ lines.push(chalk10.dim(`${indent} item-id: ${item.id}`));
6268
6482
  for (const child of sortByOrder(item.children ?? [])) {
6269
6483
  renderItem(child, depth + 1);
6270
6484
  }
6271
6485
  };
6272
6486
  for (const cl of checklists) {
6273
6487
  const { total, resolved } = countItems(cl.items);
6274
- lines.push(chalk9.bold(`${cl.name} (${resolved}/${total})`));
6275
- lines.push(chalk9.dim(` ID: ${cl.id}`));
6488
+ lines.push(chalk10.bold(`${cl.name} (${resolved}/${total})`));
6489
+ lines.push(chalk10.dim(` ID: ${cl.id}`));
6276
6490
  for (const item of sortByOrder(cl.items)) renderItem(item, 0);
6277
6491
  }
6278
6492
  return lines.join("\n");
@@ -6338,7 +6552,7 @@ async function deleteCommentByTaskSelection(config, taskId, options) {
6338
6552
  }
6339
6553
 
6340
6554
  // src/commands/replies.ts
6341
- import chalk10 from "chalk";
6555
+ import chalk11 from "chalk";
6342
6556
  async function getReplies(config, commentId) {
6343
6557
  const client = new ClickUpClient(config);
6344
6558
  return client.getThreadedComments(commentId);
@@ -6354,7 +6568,7 @@ function formatReplies(replies) {
6354
6568
  return replies.map((r) => {
6355
6569
  const user = r.user?.username ?? "Unknown";
6356
6570
  const date = formatTimestamp(Number(r.date));
6357
- return `${chalk10.bold(user)} ${chalk10.dim(date)}
6571
+ return `${chalk11.bold(user)} ${chalk11.dim(date)}
6358
6572
  ${r.comment_text}`;
6359
6573
  }).join("\n\n");
6360
6574
  }
@@ -6417,7 +6631,7 @@ function formatDocsMarkdown(docs) {
6417
6631
  }
6418
6632
 
6419
6633
  // src/commands/doc.ts
6420
- import chalk11 from "chalk";
6634
+ import chalk12 from "chalk";
6421
6635
  async function getDocInfo(config, docId) {
6422
6636
  const client = new ClickUpClient(config);
6423
6637
  const [doc, pages] = await Promise.all([
@@ -6429,14 +6643,14 @@ async function getDocInfo(config, docId) {
6429
6643
  function formatDocInfo(doc, pages, indent = 0) {
6430
6644
  const lines = [];
6431
6645
  if (indent === 0) {
6432
- lines.push(`${chalk11.bold(doc.name)} ${chalk11.dim(doc.id)}`);
6646
+ lines.push(`${chalk12.bold(doc.name)} ${chalk12.dim(doc.id)}`);
6433
6647
  if (pages.length === 0) {
6434
6648
  lines.push(" (no pages)");
6435
6649
  }
6436
6650
  }
6437
6651
  for (const page of pages) {
6438
6652
  const prefix = " ".repeat(indent + 1);
6439
- lines.push(`${prefix}${page.name} ${chalk11.dim(page.id)}`);
6653
+ lines.push(`${prefix}${page.name} ${chalk12.dim(page.id)}`);
6440
6654
  if (page.pages && page.pages.length > 0) {
6441
6655
  lines.push(formatDocInfo(doc, page.pages, indent + 1));
6442
6656
  }
@@ -6515,7 +6729,7 @@ async function deleteDocPage(config, docId, pageId) {
6515
6729
  }
6516
6730
 
6517
6731
  // src/commands/folders.ts
6518
- import chalk12 from "chalk";
6732
+ import chalk13 from "chalk";
6519
6733
  async function listFolders(config, spaceId, nameFilter, archived) {
6520
6734
  const client = new ClickUpClient(config);
6521
6735
  const folders = await client.getFolders(spaceId, archived);
@@ -6534,9 +6748,9 @@ async function listFolders(config, spaceId, nameFilter, archived) {
6534
6748
  function formatFolders(folders) {
6535
6749
  if (folders.length === 0) return "No folders found";
6536
6750
  return folders.map((f) => {
6537
- const header = `${chalk12.bold(f.name)} ${chalk12.dim(f.id)}`;
6751
+ const header = `${chalk13.bold(f.name)} ${chalk13.dim(f.id)}`;
6538
6752
  if (f.lists.length === 0) return header;
6539
- const listLines = f.lists.map((l) => ` ${chalk12.dim(">")} ${l.name} ${chalk12.dim(l.id)}`);
6753
+ const listLines = f.lists.map((l) => ` ${chalk13.dim(">")} ${l.name} ${chalk13.dim(l.id)}`);
6540
6754
  return [header, ...listLines].join("\n");
6541
6755
  }).join("\n\n");
6542
6756
  }
@@ -6551,13 +6765,13 @@ function formatFoldersMarkdown(folders) {
6551
6765
  }
6552
6766
 
6553
6767
  // src/commands/time.ts
6554
- import chalk13 from "chalk";
6768
+ import chalk14 from "chalk";
6555
6769
  var TIME_COLUMNS = [
6556
6770
  { key: "task", label: "Task", maxWidth: 35 },
6557
6771
  { key: "duration", label: "Duration", maxWidth: 10 },
6558
6772
  { key: "date", label: "Date", maxWidth: 20 },
6559
6773
  { key: "description", label: "Description", maxWidth: 30 },
6560
- { key: "status", label: "", maxWidth: 10, format: (v) => v === "RUNNING" ? chalk13.green(v) : "" }
6774
+ { key: "status", label: "", maxWidth: 10, format: (v) => v === "RUNNING" ? chalk14.green(v) : "" }
6561
6775
  ];
6562
6776
  async function startTimer(config, taskId, description) {
6563
6777
  const client = new ClickUpClient(config);
@@ -6653,7 +6867,7 @@ function formatTimeEntriesMarkdown(entries) {
6653
6867
  }
6654
6868
 
6655
6869
  // src/commands/tags.ts
6656
- import chalk14 from "chalk";
6870
+ import chalk15 from "chalk";
6657
6871
  var TAG_COLUMNS = [
6658
6872
  { key: "name", label: "Name", maxWidth: 40 },
6659
6873
  { key: "fg", label: "FG", maxWidth: 10 },
@@ -6686,13 +6900,13 @@ function formatTags(tags) {
6686
6900
  if (tags.length === 0) return "No tags found";
6687
6901
  if (isTTY()) {
6688
6902
  const rows = tags.map((t) => ({
6689
- name: t.tag_bg ? chalk14.bgHex(t.tag_bg).hex(t.tag_fg || "#ffffff")(` ${t.name} `) : chalk14.bold(t.name),
6903
+ name: t.tag_bg ? chalk15.bgHex(t.tag_bg).hex(t.tag_fg || "#ffffff")(` ${t.name} `) : chalk15.bold(t.name),
6690
6904
  fg: t.tag_fg || "",
6691
6905
  bg: t.tag_bg || ""
6692
6906
  }));
6693
6907
  return formatTable(rows, TAG_COLUMNS);
6694
6908
  }
6695
- return tags.map((t) => chalk14.bold(t.name)).join(", ");
6909
+ return tags.map((t) => chalk15.bold(t.name)).join(", ");
6696
6910
  }
6697
6911
  function formatTagsMarkdown(tags) {
6698
6912
  if (tags.length === 0) return "No tags found";
@@ -6727,7 +6941,7 @@ function formatMembersMarkdown(members) {
6727
6941
  }
6728
6942
 
6729
6943
  // src/commands/fields.ts
6730
- import chalk15 from "chalk";
6944
+ import chalk16 from "chalk";
6731
6945
  var FIELD_COLUMNS = [
6732
6946
  { key: "id", label: "ID", maxWidth: 20 },
6733
6947
  { key: "name", label: "Name", maxWidth: 30 },
@@ -6736,7 +6950,7 @@ var FIELD_COLUMNS = [
6736
6950
  key: "required",
6737
6951
  label: "Required",
6738
6952
  maxWidth: 10,
6739
- format: (v) => v === "yes" ? chalk15.yellow(v) : chalk15.dim(v)
6953
+ format: (v) => v === "yes" ? chalk16.yellow(v) : chalk16.dim(v)
6740
6954
  },
6741
6955
  { key: "options", label: "Options", maxWidth: 40 }
6742
6956
  ];
@@ -6894,13 +7108,13 @@ async function bulkMove(config, listId, taskIds) {
6894
7108
  }
6895
7109
 
6896
7110
  // src/commands/goals.ts
6897
- import chalk16 from "chalk";
7111
+ import chalk17 from "chalk";
6898
7112
  function colorProgress(value) {
6899
7113
  const num = parseInt(value, 10);
6900
7114
  if (isNaN(num)) return value;
6901
- if (num >= 75) return chalk16.green(value);
6902
- if (num >= 25) return chalk16.yellow(value);
6903
- return chalk16.red(value);
7115
+ if (num >= 75) return chalk17.green(value);
7116
+ if (num >= 25) return chalk17.yellow(value);
7117
+ return chalk17.red(value);
6904
7118
  }
6905
7119
  var GOAL_COLUMNS = [
6906
7120
  { key: "id", label: "ID", maxWidth: 15 },
@@ -6994,14 +7208,14 @@ function formatKeyResultsMarkdown(keyResults) {
6994
7208
  }
6995
7209
 
6996
7210
  // src/commands/task-types.ts
6997
- import chalk17 from "chalk";
7211
+ import chalk18 from "chalk";
6998
7212
  async function listTaskTypes(config) {
6999
7213
  const client = new ClickUpClient(config);
7000
7214
  return client.getCustomTaskTypes(config.teamId);
7001
7215
  }
7002
7216
  function formatTaskTypes(types) {
7003
7217
  if (types.length === 0) return "No custom task types";
7004
- return types.map((t) => `${chalk17.bold(t.name)} ${chalk17.dim(`(${t.id})`)}`).join("\n");
7218
+ return types.map((t) => `${chalk18.bold(t.name)} ${chalk18.dim(`(${t.id})`)}`).join("\n");
7005
7219
  }
7006
7220
  function formatTaskTypesMarkdown(types) {
7007
7221
  if (types.length === 0) return "No custom task types";
@@ -7009,14 +7223,14 @@ function formatTaskTypesMarkdown(types) {
7009
7223
  }
7010
7224
 
7011
7225
  // src/commands/templates.ts
7012
- import chalk18 from "chalk";
7226
+ import chalk19 from "chalk";
7013
7227
  async function listTemplates(config) {
7014
7228
  const client = new ClickUpClient(config);
7015
7229
  return client.getTaskTemplates(config.teamId);
7016
7230
  }
7017
7231
  function formatTemplates(templates) {
7018
7232
  if (templates.length === 0) return "No task templates";
7019
- return templates.map((t) => `${chalk18.bold(t.name)} ${chalk18.dim(`(${t.id})`)}`).join("\n");
7233
+ return templates.map((t) => `${chalk19.bold(t.name)} ${chalk19.dim(`(${t.id})`)}`).join("\n");
7020
7234
  }
7021
7235
  function formatTemplatesMarkdown(templates) {
7022
7236
  if (templates.length === 0) return "No task templates";
@@ -7024,14 +7238,14 @@ function formatTemplatesMarkdown(templates) {
7024
7238
  }
7025
7239
 
7026
7240
  // src/commands/list-templates.ts
7027
- import chalk19 from "chalk";
7241
+ import chalk20 from "chalk";
7028
7242
  async function listListTemplates(config) {
7029
7243
  const client = new ClickUpClient(config);
7030
7244
  return client.getListTemplates(config.teamId);
7031
7245
  }
7032
7246
  function formatListTemplates(templates) {
7033
7247
  if (templates.length === 0) return "No list templates";
7034
- return templates.map((t) => `${chalk19.bold(t.name)} ${chalk19.dim(`(${t.id})`)}`).join("\n");
7248
+ return templates.map((t) => `${chalk20.bold(t.name)} ${chalk20.dim(`(${t.id})`)}`).join("\n");
7035
7249
  }
7036
7250
  function formatListTemplatesMarkdown(templates) {
7037
7251
  if (templates.length === 0) return "No list templates";
@@ -7039,14 +7253,14 @@ function formatListTemplatesMarkdown(templates) {
7039
7253
  }
7040
7254
 
7041
7255
  // src/commands/folder-templates.ts
7042
- import chalk20 from "chalk";
7256
+ import chalk21 from "chalk";
7043
7257
  async function listFolderTemplates(config) {
7044
7258
  const client = new ClickUpClient(config);
7045
7259
  return client.getFolderTemplates(config.teamId);
7046
7260
  }
7047
7261
  function formatFolderTemplates(templates) {
7048
7262
  if (templates.length === 0) return "No folder templates";
7049
- return templates.map((t) => `${chalk20.bold(t.name)} ${chalk20.dim(`(${t.id})`)}`).join("\n");
7263
+ return templates.map((t) => `${chalk21.bold(t.name)} ${chalk21.dim(`(${t.id})`)}`).join("\n");
7050
7264
  }
7051
7265
  function formatFolderTemplatesMarkdown(templates) {
7052
7266
  if (templates.length === 0) return "No folder templates";
@@ -7069,7 +7283,7 @@ async function createListFromTemplate(config, name, opts) {
7069
7283
  }
7070
7284
 
7071
7285
  // src/commands/views.ts
7072
- import chalk21 from "chalk";
7286
+ import chalk22 from "chalk";
7073
7287
  async function listViews(config, id, container = "list") {
7074
7288
  const client = new ClickUpClient(config);
7075
7289
  if (container === "space") return client.getSpaceViews(id);
@@ -7080,7 +7294,7 @@ async function listViews(config, id, container = "list") {
7080
7294
  }
7081
7295
  function formatViews(views) {
7082
7296
  if (views.length === 0) return "No views";
7083
- return views.map((v) => `${chalk21.bold(v.name)} ${chalk21.dim(`(${v.id})`)} ${chalk21.dim(v.type)}`).join("\n");
7297
+ return views.map((v) => `${chalk22.bold(v.name)} ${chalk22.dim(`(${v.id})`)} ${chalk22.dim(v.type)}`).join("\n");
7084
7298
  }
7085
7299
  function formatViewsMarkdown(views) {
7086
7300
  if (views.length === 0) return "No views";
@@ -7088,23 +7302,23 @@ function formatViewsMarkdown(views) {
7088
7302
  }
7089
7303
 
7090
7304
  // src/commands/chat.ts
7091
- import chalk22 from "chalk";
7305
+ import chalk23 from "chalk";
7092
7306
  function channelName(c) {
7093
7307
  return c.name || "DM";
7094
7308
  }
7095
7309
  function colorChannelType(type) {
7096
- if (type === "CHANNEL") return chalk22.cyan(type);
7097
- if (type === "DM") return chalk22.dim(type);
7098
- if (type === "GROUP_DM") return chalk22.blue(type);
7310
+ if (type === "CHANNEL") return chalk23.cyan(type);
7311
+ if (type === "DM") return chalk23.dim(type);
7312
+ if (type === "GROUP_DM") return chalk23.blue(type);
7099
7313
  return type;
7100
7314
  }
7101
7315
  function colorVisibility(v) {
7102
- if (v === "PUBLIC") return chalk22.green(v);
7103
- return chalk22.dim(v);
7316
+ if (v === "PUBLIC") return chalk23.green(v);
7317
+ return chalk23.dim(v);
7104
7318
  }
7105
7319
  var CHANNEL_COLUMNS = [
7106
- { key: "name", label: "Name", maxWidth: 40, format: (v) => chalk22.bold(v) },
7107
- { key: "id", label: "ID", maxWidth: 20, format: (v) => chalk22.dim(v) },
7320
+ { key: "name", label: "Name", maxWidth: 40, format: (v) => chalk23.bold(v) },
7321
+ { key: "id", label: "ID", maxWidth: 20, format: (v) => chalk23.dim(v) },
7108
7322
  { key: "type", label: "Type", maxWidth: 12, format: (v) => colorChannelType(v) },
7109
7323
  { key: "visibility", label: "Visibility", maxWidth: 10, format: (v) => colorVisibility(v) },
7110
7324
  { key: "topic", label: "Topic", maxWidth: 40 }
@@ -7129,26 +7343,26 @@ function formatChannelsMarkdown(channels) {
7129
7343
  }
7130
7344
  function formatChannelDetail(channel) {
7131
7345
  const lines = [];
7132
- lines.push(chalk22.bold.underline(channelName(channel)));
7346
+ lines.push(chalk23.bold.underline(channelName(channel)));
7133
7347
  lines.push("");
7134
7348
  const fields = [
7135
- ["ID", chalk22.dim(channel.id)],
7349
+ ["ID", chalk23.dim(channel.id)],
7136
7350
  ["Type", colorChannelType(channel.type)],
7137
7351
  ["Visibility", colorVisibility(channel.visibility)]
7138
7352
  ];
7139
7353
  if (channel.topic) fields.push(["Topic", channel.topic]);
7140
7354
  if (channel.description) fields.push(["Description", channel.description]);
7141
- fields.push(["Archived", channel.archived ? chalk22.yellow("Yes") : "No"]);
7355
+ fields.push(["Archived", channel.archived ? chalk23.yellow("Yes") : "No"]);
7142
7356
  fields.push(["Created", formatDate(channel.created_at)]);
7143
7357
  const maxLabel = Math.max(...fields.map(([k]) => k.length));
7144
7358
  for (const [label, value] of fields) {
7145
- lines.push(` ${chalk22.bold(label.padEnd(maxLabel + 1))} ${value}`);
7359
+ lines.push(` ${chalk23.bold(label.padEnd(maxLabel + 1))} ${value}`);
7146
7360
  }
7147
7361
  return lines.join("\n");
7148
7362
  }
7149
7363
  var CHAT_MEMBER_COLUMNS = [
7150
- { key: "name", label: "Name", maxWidth: 30, format: (v) => chalk22.bold(v) },
7151
- { key: "id", label: "ID", maxWidth: 15, format: (v) => chalk22.dim(v) },
7364
+ { key: "name", label: "Name", maxWidth: 30, format: (v) => chalk23.bold(v) },
7365
+ { key: "id", label: "ID", maxWidth: 15, format: (v) => chalk23.dim(v) },
7152
7366
  { key: "email", label: "Email", maxWidth: 40 },
7153
7367
  { key: "type", label: "Type", maxWidth: 12 }
7154
7368
  ];
@@ -7171,22 +7385,22 @@ function formatChatMembersMarkdown(members) {
7171
7385
  }
7172
7386
 
7173
7387
  // src/commands/chat-message.ts
7174
- import chalk23 from "chalk";
7175
- var separator = chalk23.dim("-".repeat(60));
7388
+ import chalk24 from "chalk";
7389
+ var separator = chalk24.dim("-".repeat(60));
7176
7390
  function formatMessages(messages) {
7177
7391
  if (messages.length === 0) return "No messages";
7178
7392
  const lines = [];
7179
7393
  for (let i = 0; i < messages.length; i++) {
7180
7394
  const msg = messages[i];
7181
7395
  if (i > 0) lines.push(separator);
7182
- const meta = [chalk23.bold(`@${msg.user_id}`), chalk23.dim(formatTimestamp(msg.date))];
7396
+ const meta = [chalk24.bold(`@${msg.user_id}`), chalk24.dim(formatTimestamp(msg.date))];
7183
7397
  if (msg.replies_count) {
7184
- meta.push(chalk23.dim(`${msg.replies_count} replies`));
7398
+ meta.push(chalk24.dim(`${msg.replies_count} replies`));
7185
7399
  }
7186
- meta.push(chalk23.dim(`(${msg.id})`));
7400
+ meta.push(chalk24.dim(`(${msg.id})`));
7187
7401
  lines.push(meta.join(" "));
7188
7402
  if (msg.type === "post" && msg.post_data?.title) {
7189
- lines.push(chalk23.cyan.bold(msg.post_data.title));
7403
+ lines.push(chalk24.cyan.bold(msg.post_data.title));
7190
7404
  }
7191
7405
  lines.push(msg.content);
7192
7406
  }
@@ -7205,7 +7419,7 @@ ${msg.content}`;
7205
7419
  }
7206
7420
 
7207
7421
  // src/commands/chat-reaction.ts
7208
- import chalk24 from "chalk";
7422
+ import chalk25 from "chalk";
7209
7423
  var EMOJI_MAP = {
7210
7424
  thumbsup: "\u{1F44D}",
7211
7425
  thumbsdown: "\u{1F44E}",
@@ -7244,8 +7458,8 @@ function formatReactions(reactions) {
7244
7458
  const lines = [];
7245
7459
  for (const [emoji, users] of groups) {
7246
7460
  const icon = emojiChar(emoji);
7247
- const userList = users.map((u) => chalk24.bold(`@${u}`)).join(", ");
7248
- lines.push(`${icon} ${chalk24.dim(emoji)} ${chalk24.dim(`(${users.length})`)} \u2014 ${userList}`);
7461
+ const userList = users.map((u) => chalk25.bold(`@${u}`)).join(", ");
7462
+ lines.push(`${icon} ${chalk25.dim(emoji)} ${chalk25.dim(`(${users.length})`)} \u2014 ${userList}`);
7249
7463
  }
7250
7464
  return lines.join("\n");
7251
7465
  }
@@ -7260,20 +7474,20 @@ function formatReactionsMarkdown(reactions) {
7260
7474
  }
7261
7475
 
7262
7476
  // src/commands/view.ts
7263
- import chalk25 from "chalk";
7477
+ import chalk26 from "chalk";
7264
7478
  async function getView(config, viewId) {
7265
7479
  const client = new ClickUpClient(config);
7266
7480
  return client.getView(viewId);
7267
7481
  }
7268
7482
  function formatView(view) {
7269
7483
  const lines = [];
7270
- lines.push(chalk25.bold.underline(view.name));
7484
+ lines.push(chalk26.bold.underline(view.name));
7271
7485
  lines.push("");
7272
- lines.push(` ${chalk25.bold("ID")} ${view.id}`);
7273
- lines.push(` ${chalk25.bold("Type")} ${view.type}`);
7274
- if (view.visibility) lines.push(` ${chalk25.bold("Visibility")} ${view.visibility}`);
7275
- if (view.date_created) lines.push(` ${chalk25.bold("Created")} ${formatDate(view.date_created)}`);
7276
- if (view.protected !== void 0) lines.push(` ${chalk25.bold("Protected")} ${view.protected}`);
7486
+ lines.push(` ${chalk26.bold("ID")} ${view.id}`);
7487
+ lines.push(` ${chalk26.bold("Type")} ${view.type}`);
7488
+ if (view.visibility) lines.push(` ${chalk26.bold("Visibility")} ${view.visibility}`);
7489
+ if (view.date_created) lines.push(` ${chalk26.bold("Created")} ${formatDate(view.date_created)}`);
7490
+ if (view.protected !== void 0) lines.push(` ${chalk26.bold("Protected")} ${view.protected}`);
7277
7491
  return lines.join("\n");
7278
7492
  }
7279
7493
  function formatViewMarkdown(view) {
@@ -8187,6 +8401,78 @@ function buildProgram(programName = basename(process.argv[1] ?? "cup")) {
8187
8401
  }
8188
8402
  })
8189
8403
  );
8404
+ program.command("list-delete <listId>").description("Delete a list (requires confirmation)").option("--confirm", "Skip confirmation prompt (required in non-interactive mode)").option("--json", "Force JSON output even in terminal").action(
8405
+ wrapAction(async (listId, opts) => {
8406
+ const config = loadConfig(getProfileName());
8407
+ const result = await deleteListCommand(config, listId, opts);
8408
+ if (shouldOutputJson(opts.json ?? false)) {
8409
+ console.log(JSON.stringify(result, null, 2));
8410
+ } else {
8411
+ console.log(`Deleted list ${result.listId}`);
8412
+ }
8413
+ })
8414
+ );
8415
+ program.command("folder-delete <folderId>").description("Delete a folder (requires confirmation)").option("--confirm", "Skip confirmation prompt (required in non-interactive mode)").option("--json", "Force JSON output even in terminal").action(
8416
+ wrapAction(async (folderId, opts) => {
8417
+ const config = loadConfig(getProfileName());
8418
+ const result = await deleteFolderCommand(config, folderId, opts);
8419
+ if (shouldOutputJson(opts.json ?? false)) {
8420
+ console.log(JSON.stringify(result, null, 2));
8421
+ } else {
8422
+ console.log(`Deleted folder ${result.folderId}`);
8423
+ }
8424
+ })
8425
+ );
8426
+ program.command("space-delete <spaceId>").description("Delete a space (requires confirmation)").option("--confirm", "Skip confirmation prompt (required in non-interactive mode)").option("--json", "Force JSON output even in terminal").action(
8427
+ wrapAction(async (spaceId, opts) => {
8428
+ const config = loadConfig(getProfileName());
8429
+ const result = await deleteSpaceCommand(config, spaceId, opts);
8430
+ if (shouldOutputJson(opts.json ?? false)) {
8431
+ console.log(JSON.stringify(result, null, 2));
8432
+ } else {
8433
+ console.log(`Deleted space ${result.spaceId}`);
8434
+ }
8435
+ })
8436
+ );
8437
+ program.command("attachments <taskId>").description("List attachments on a task").option("--json", "Force JSON output even in terminal").action(
8438
+ wrapAction(async (taskId, opts) => {
8439
+ const config = loadConfig(getProfileName());
8440
+ const attachments = await listTaskAttachments(config, taskId);
8441
+ if (shouldOutputJson(opts.json ?? false)) {
8442
+ console.log(JSON.stringify(attachments, null, 2));
8443
+ } else if (isTTY()) {
8444
+ console.log(formatAttachmentsTable(attachments));
8445
+ } else {
8446
+ console.log(formatAttachmentsMarkdown(attachments));
8447
+ }
8448
+ })
8449
+ );
8450
+ program.command("task-members <taskId>").description("List members with access to a task").option("--json", "Force JSON output even in terminal").action(
8451
+ wrapAction(async (taskId, opts) => {
8452
+ const config = loadConfig(getProfileName());
8453
+ const members = await listTaskMembers(config, taskId);
8454
+ if (shouldOutputJson(opts.json ?? false)) {
8455
+ console.log(JSON.stringify(members, null, 2));
8456
+ } else if (isTTY()) {
8457
+ console.log(formatTaskMembers(members));
8458
+ } else {
8459
+ console.log(formatTaskMembersMarkdown(members));
8460
+ }
8461
+ })
8462
+ );
8463
+ program.command("plan").description("Show workspace plan").option("--json", "Force JSON output even in terminal").action(
8464
+ wrapAction(async (opts) => {
8465
+ const config = loadConfig(getProfileName());
8466
+ const plan = await getWorkspacePlanCommand(config);
8467
+ if (shouldOutputJson(opts.json ?? false)) {
8468
+ console.log(JSON.stringify(plan, null, 2));
8469
+ } else if (isTTY()) {
8470
+ console.log(formatPlan(plan));
8471
+ } else {
8472
+ console.log(formatPlanMarkdown(plan));
8473
+ }
8474
+ })
8475
+ );
8190
8476
  program.command("archive <taskId>").description("Archive a task (or unarchive with --unarchive)").option("--unarchive", "Unarchive instead of archiving").option("--confirm", "Skip confirmation prompt (required in non-interactive mode)").option("--json", "Force JSON output even in terminal").action(
8191
8477
  wrapAction(
8192
8478
  async (taskId, opts) => {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@krodak/clickup-cli",
3
- "version": "1.28.0",
3
+ "version": "1.29.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.28.0
6
+ # ClickUp CLI (`cup`) - skill version 1.29.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.28.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.29.0, update with `npm install -g @krodak/clickup-cli` and refresh this skill with `cup skill`.
11
11
 
12
12
  ## Install & Configure
13
13
 
@@ -127,6 +127,9 @@ All commands support `--help` for full flag details. All commands support `--jso
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 fields <listId>` | Custom fields on a list (type, required, options) |
130
+ | `cup attachments <taskId>` | List attachments on a task (name, size, URL) |
131
+ | `cup task-members <taskId>` | List members with access to a task |
132
+ | `cup plan` | Show workspace plan and usage |
130
133
  | `cup tags <spaceId>` | Tags available in a space |
131
134
  | `cup goals` | Workspace goals with progress |
132
135
  | `cup key-results <goalId>` | Key results for a goal |
@@ -169,6 +172,9 @@ All commands support `--help` for full flag details. All commands support `--jso
169
172
  | `cup link <taskId> <linksTo> [--remove]` | Link/unlink tasks |
170
173
  | `cup attach <taskId> <filePath>` | Upload file attachment |
171
174
  | `cup delete <id> [--confirm]` | Delete task (DESTRUCTIVE) |
175
+ | `cup list-delete <listId> [--confirm]` | Delete list (DESTRUCTIVE, requires --confirm in non-interactive) |
176
+ | `cup folder-delete <folderId> [--confirm]` | Delete folder (DESTRUCTIVE, requires --confirm in non-interactive) |
177
+ | `cup space-delete <spaceId> [--confirm]` | Delete space (DESTRUCTIVE, requires --confirm in non-interactive) |
172
178
  | `cup duplicate <taskId>` | Duplicate a task |
173
179
  | `cup bulk status <status> <taskIds...>` | Bulk update status |
174
180
  | `cup bulk assign <taskIds...> [--to userId\|me] [--remove userId\|me]` | Bulk assign/unassign user from tasks |
@@ -282,7 +288,7 @@ When running in a terminal (not piped), task-listing commands (`cup tasks`, `cup
282
288
  - **Enter** to confirm and view details of selected tasks
283
289
  - After viewing details, prompted to open tasks in browser
284
290
 
285
- Other interactive prompts: sprint selection (when multiple match), workspace selection (`cup init`), agent selection (`cup skill`), destructive action confirmations (`cup delete`, `cup archive`, `cup view-delete`).
291
+ Other interactive prompts: sprint selection (when multiple match), workspace selection (`cup init`), agent selection (`cup skill`), destructive action confirmations (`cup delete`, `cup list-delete`, `cup folder-delete`, `cup space-delete`, `cup archive`, `cup view-delete`).
286
292
 
287
293
  When piped or called with `--json`, all commands output non-interactive markdown or JSON. Agents should always use `--json` for structured data or pipe for markdown.
288
294
 
@@ -420,4 +426,4 @@ cup summary --hours 48 # wider window
420
426
 
421
427
  ## DELETE SAFETY
422
428
 
423
- IMPORTANT: Always confirm with the user before running `cup delete`. This is a destructive, irreversible operation. Even when using `--confirm` flag, verify the task ID is correct with the user first.
429
+ IMPORTANT: Always confirm with the user before running `cup delete`, `cup list-delete`, `cup folder-delete`, or `cup space-delete`. These are destructive, irreversible operations. Even when using `--confirm` flag, verify the ID is correct with the user first.