@krodak/clickup-cli 1.32.0 → 1.33.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.32.0",
4
+ "version": "1.33.0",
5
5
  "author": {
6
6
  "name": "Krzysztof Rodak"
7
7
  },
package/README.md CHANGED
@@ -171,23 +171,23 @@ npx skills add https://github.com/krodak/clickup-cli
171
171
 
172
172
  Full CRUD for the core ClickUp workflow:
173
173
 
174
- | Area | Capabilities |
175
- | -------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
176
- | ✅ **Tasks** | Create, read, update, delete, duplicate, merge, search, subtasks, assign (users and groups), dependencies, links, multi-list, bulk operations (status, assign, due-date, tag, priority, field, move) |
177
- | 💬 **Comments** | Post, edit, delete by ID or by task scope for your own comments, threaded replies, notify all, list and view comments |
178
- | 🗨️ **Chat** | List channels, send messages, replies, reactions, channel management |
179
- | 📄 **Docs** | List, read, create, edit, delete (v3 API) |
180
- | ⏱️ **Time Tracking** | Start/stop timer, log entries, list/update/delete history, per-user time estimates |
181
- | ☑️ **Checklists** | View, create, delete, add/edit/delete items |
182
- | 🔧 **Custom Fields** | List, create, set, remove values (text, number, dropdown, labels, date, checkbox, url, email, rating, progress, relationship, people) |
183
- | 🏷️ **Tags** | Add/remove on tasks, space-level create/update/delete |
184
- | 🎯 **Goals & OKRs** | Goals CRUD, key results CRUD |
185
- | 🏃 **Sprints** | Auto-detect active sprint, `sprint:current` pseudo-ID for move/create, flexible date parsing, config override, favorite sprint folders |
186
- | ⭐ **Favorites** | Local favorites for quick access to sprint folders, spaces, lists, folders, views, tasks |
187
- | 👁️ **Views** | List, get, create, update, delete views on lists |
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 |
190
- | 📎 **Attachments** | Upload files to tasks, list task attachments, shown in detail views |
174
+ | Area | Capabilities |
175
+ | -------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
176
+ | ✅ **Tasks** | Create, read, update, delete, duplicate, merge, search, subtasks, assign (users and groups), dependencies, links, multi-list, bulk operations (status, assign, due-date, tag, priority, field, move) |
177
+ | 💬 **Comments** | Post, edit, delete by ID or by task scope for your own comments, threaded replies, notify all, real @mentions (flag or inline `<@id>` token, notifies the user), clickable rich links, list and view comments |
178
+ | 🗨️ **Chat** | List channels, send messages, replies, reactions, channel management |
179
+ | 📄 **Docs** | List, read, create, edit, delete (v3 API) |
180
+ | ⏱️ **Time Tracking** | Start/stop timer, log entries, list/update/delete history, per-user time estimates |
181
+ | ☑️ **Checklists** | View, create, delete, add/edit/delete items |
182
+ | 🔧 **Custom Fields** | List, create, set, remove values (text, number, dropdown, labels, date, checkbox, url, email, rating, progress, relationship, people) |
183
+ | 🏷️ **Tags** | Add/remove on tasks, space-level create/update/delete |
184
+ | 🎯 **Goals & OKRs** | Goals CRUD, key results CRUD |
185
+ | 🏃 **Sprints** | Auto-detect active sprint, `sprint:current` pseudo-ID for move/create, flexible date parsing, config override, favorite sprint folders |
186
+ | ⭐ **Favorites** | Local favorites for quick access to sprint folders, spaces, lists, folders, views, tasks |
187
+ | 👁️ **Views** | List, get, create, update, delete views on lists |
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 |
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)
193
193
 
package/dist/index.js CHANGED
@@ -1066,8 +1066,8 @@ var ClickUpClient = class {
1066
1066
  const data = await this.request(`/list/${listId}/comment`);
1067
1067
  return readCollectionField(data, "comments", "list comments");
1068
1068
  }
1069
- async postListComment(listId, commentText, notifyAll) {
1070
- const body = { comment_text: commentText };
1069
+ async postListComment(listId, commentText, notifyAll, richBlocks) {
1070
+ const body = richBlocks ? { comment: richBlocks } : { comment_text: commentText };
1071
1071
  if (notifyAll) body.notify_all = true;
1072
1072
  return this.request(`/list/${listId}/comment`, {
1073
1073
  method: "POST",
@@ -1078,8 +1078,8 @@ var ClickUpClient = class {
1078
1078
  const data = await this.request(`/view/${viewId}/comment`);
1079
1079
  return readCollectionField(data, "comments", "view comments");
1080
1080
  }
1081
- async postViewComment(viewId, commentText, notifyAll) {
1082
- const body = { comment_text: commentText };
1081
+ async postViewComment(viewId, commentText, notifyAll, richBlocks) {
1082
+ const body = richBlocks ? { comment: richBlocks } : { comment_text: commentText };
1083
1083
  if (notifyAll) body.notify_all = true;
1084
1084
  return this.request(`/view/${viewId}/comment`, {
1085
1085
  method: "POST",
@@ -2865,7 +2865,9 @@ function processInlineFormatting(text, lineAttrs) {
2865
2865
  { type: "bold", re: /\*{2}([^*]+)\*{2}/ },
2866
2866
  { type: "italic", re: /(?<!\*)\*(?!\*)([^*]+)(?<!\*)\*(?!\*)/ },
2867
2867
  { type: "strike", re: /~~([^~]+)~~/ },
2868
- { type: "link", re: /\[([^\]]+)\]\(([^)]+)\)/ }
2868
+ { type: "mention", re: /<@(\d+)>/ },
2869
+ { type: "link", re: /\[([^\]]+)\]\(([^)]+)\)/ },
2870
+ { type: "autolink", re: /(?<![([])(https?:\/\/[^\s<>]+)/ }
2869
2871
  ];
2870
2872
  for (const { type, re } of patterns) {
2871
2873
  const m = re.exec(remaining);
@@ -2913,6 +2915,15 @@ function processInlineFormatting(text, lineAttrs) {
2913
2915
  attributes: { ...lineAttrs, link: matchResult[2] }
2914
2916
  });
2915
2917
  break;
2918
+ case "autolink":
2919
+ blocks.push({
2920
+ text: innerText,
2921
+ attributes: { ...lineAttrs, link: innerText }
2922
+ });
2923
+ break;
2924
+ case "mention":
2925
+ blocks.push({ type: "tag", user: { id: Number(innerText) } });
2926
+ break;
2916
2927
  }
2917
2928
  remaining = remaining.slice(earliestIndex + matchResult[0].length);
2918
2929
  }
@@ -3015,10 +3026,42 @@ function markdownToCommentBlocks(markdown) {
3015
3026
  }
3016
3027
 
3017
3028
  // src/commands/comment.ts
3018
- async function postComment(config, taskId, text, notifyAll) {
3029
+ async function resolveMemberId(client, teamId, value) {
3030
+ if (/^\d+$/.test(value)) return Number(value);
3031
+ if (value === "me") return (await client.getMe()).id;
3032
+ const members = await client.getWorkspaceMembers(teamId);
3033
+ const match = members.find(
3034
+ (m) => m.email?.toLowerCase() === value.toLowerCase() || m.username?.toLowerCase() === value.toLowerCase()
3035
+ );
3036
+ if (match) return match.id;
3037
+ const available = members.map((m) => `${m.username} (${m.email})`).join(", ");
3038
+ throw new Error(`Member "${value}" not found. Available: ${available}`);
3039
+ }
3040
+ function createCachedMemberResolver(client, teamId) {
3041
+ let membersCache = null;
3042
+ const cachingClient = {
3043
+ getMe: () => client.getMe(),
3044
+ getWorkspaceMembers: async () => {
3045
+ if (membersCache === null) membersCache = await client.getWorkspaceMembers(teamId);
3046
+ return membersCache;
3047
+ }
3048
+ };
3049
+ return (value) => resolveMemberId(cachingClient, teamId, value);
3050
+ }
3051
+ function buildCommentBlocks(message, mentionIds) {
3052
+ const messageBlocks = markdownToCommentBlocks(message);
3053
+ if (mentionIds.length === 0) return messageBlocks;
3054
+ const mentionBlocks = [];
3055
+ for (const id of mentionIds) {
3056
+ mentionBlocks.push({ type: "tag", user: { id } });
3057
+ mentionBlocks.push({ text: " " });
3058
+ }
3059
+ return [...mentionBlocks, ...messageBlocks];
3060
+ }
3061
+ async function postComment(config, taskId, text, notifyAll, mentionIds) {
3019
3062
  if (!text.trim()) throw new Error("Comment text cannot be empty");
3020
3063
  const client = new ClickUpClient(config);
3021
- const blocks = markdownToCommentBlocks(text);
3064
+ const blocks = buildCommentBlocks(text, mentionIds ?? []);
3022
3065
  return client.postComment(taskId, text, notifyAll, blocks);
3023
3066
  }
3024
3067
 
@@ -3832,7 +3875,7 @@ var commandMetadata = [
3832
3875
  {
3833
3876
  name: "comment",
3834
3877
  description: "Post a comment on a task",
3835
- flags: ["-m", "--message", "--notify-all", "--json"],
3878
+ flags: ["-m", "--message", "--notify-all", "--mention", "--json"],
3836
3879
  quickReference: [
3837
3880
  { section: "write", usage: "comment <taskId>", description: "Post a comment on a task" }
3838
3881
  ]
@@ -3840,7 +3883,7 @@ var commandMetadata = [
3840
3883
  {
3841
3884
  name: "comment-edit",
3842
3885
  description: "Edit an existing comment",
3843
- flags: ["-m", "--message", "--resolved", "--unresolved", "--json"],
3886
+ flags: ["-m", "--message", "--resolved", "--unresolved", "--mention", "--json"],
3844
3887
  quickReference: [
3845
3888
  {
3846
3889
  section: "write",
@@ -3884,7 +3927,7 @@ var commandMetadata = [
3884
3927
  {
3885
3928
  name: "reply",
3886
3929
  description: "Reply to a comment",
3887
- flags: ["-m", "--message", "--notify-all", "--json"],
3930
+ flags: ["-m", "--message", "--notify-all", "--mention", "--json"],
3888
3931
  quickReference: [
3889
3932
  { section: "write", usage: "reply <commentId>", description: "Reply to a comment" }
3890
3933
  ]
@@ -4689,7 +4732,7 @@ var commandMetadata = [
4689
4732
  {
4690
4733
  name: "list-comment",
4691
4734
  description: "Post a comment on a list",
4692
- flags: ["-m", "--message", "--notify-all", "--json"],
4735
+ flags: ["-m", "--message", "--notify-all", "--mention", "--json"],
4693
4736
  quickReference: [
4694
4737
  {
4695
4738
  section: "write",
@@ -4713,7 +4756,7 @@ var commandMetadata = [
4713
4756
  {
4714
4757
  name: "view-comment",
4715
4758
  description: "Post a comment on a view",
4716
- flags: ["-m", "--message", "--notify-all", "--json"],
4759
+ flags: ["-m", "--message", "--notify-all", "--mention", "--json"],
4717
4760
  quickReference: [
4718
4761
  {
4719
4762
  section: "write",
@@ -5156,6 +5199,7 @@ ${renderZshTopLevelCommands(name)}
5156
5199
  '1:task_id:' \\
5157
5200
  '(-m --message)'{-m,--message}'[Comment text]:text:' \\
5158
5201
  '--notify-all[Notify all assignees]' \\
5202
+ '--mention[Mention a user (ID, email, username, or me)]:user:' \\
5159
5203
  '--json[Force JSON output]'
5160
5204
  ;;
5161
5205
  comments)
@@ -5390,6 +5434,7 @@ ${renderZshTopLevelCommands(name)}
5390
5434
  '(-m --message)'{-m,--message}'[New comment text]:text:' \\
5391
5435
  '--resolved[Mark comment as resolved]' \\
5392
5436
  '--unresolved[Mark comment as unresolved]' \\
5437
+ '--mention[Mention a user (ID, email, username, or me)]:user:' \\
5393
5438
  '--json[Force JSON output]'
5394
5439
  ;;
5395
5440
  comment-delete)
@@ -5410,6 +5455,7 @@ ${renderZshTopLevelCommands(name)}
5410
5455
  '1:comment_id:' \\
5411
5456
  '(-m --message)'{-m,--message}'[Reply text]:text:' \\
5412
5457
  '--notify-all[Notify all assignees]' \\
5458
+ '--mention[Mention a user (ID, email, username, or me)]:user:' \\
5413
5459
  '--json[Force JSON output]'
5414
5460
  ;;
5415
5461
  link)
@@ -6780,13 +6826,13 @@ function formatChecklistsMarkdown(checklists) {
6780
6826
  }
6781
6827
 
6782
6828
  // src/commands/comment-edit.ts
6783
- async function editComment(config, commentId, text, resolved) {
6829
+ async function editComment(config, commentId, text, resolved, mentionIds) {
6784
6830
  if (text === void 0 && resolved === void 0) {
6785
6831
  throw new Error("Provide at least one of: --message, --resolved, --unresolved");
6786
6832
  }
6787
6833
  if (text !== void 0 && !text.trim()) throw new Error("Comment text cannot be empty");
6788
6834
  const client = new ClickUpClient(config);
6789
- const blocks = text !== void 0 ? markdownToCommentBlocks(text) : void 0;
6835
+ const blocks = text !== void 0 ? buildCommentBlocks(text, mentionIds ?? []) : void 0;
6790
6836
  await client.updateComment(commentId, text ?? "", resolved, blocks);
6791
6837
  }
6792
6838
 
@@ -6827,10 +6873,10 @@ async function getReplies(config, commentId) {
6827
6873
  const client = new ClickUpClient(config);
6828
6874
  return client.getThreadedComments(commentId);
6829
6875
  }
6830
- async function createReply(config, commentId, text, notifyAll) {
6876
+ async function createReply(config, commentId, text, notifyAll, mentionIds) {
6831
6877
  if (!text.trim()) throw new Error("Reply text cannot be empty");
6832
6878
  const client = new ClickUpClient(config);
6833
- const blocks = markdownToCommentBlocks(text);
6879
+ const blocks = buildCommentBlocks(text, mentionIds ?? []);
6834
6880
  await client.createThreadedComment(commentId, text, notifyAll, blocks);
6835
6881
  }
6836
6882
  function formatReplies(replies) {
@@ -8272,10 +8318,11 @@ async function fetchListComments(config, listId) {
8272
8318
  text: c.comment_text
8273
8319
  }));
8274
8320
  }
8275
- async function postListCommentCommand(config, listId, text, notifyAll) {
8321
+ async function postListCommentCommand(config, listId, text, notifyAll, mentionIds) {
8276
8322
  if (!text.trim()) throw new Error("Comment text cannot be empty");
8277
8323
  const client = new ClickUpClient(config);
8278
- return client.postListComment(listId, text, notifyAll);
8324
+ const blocks = buildCommentBlocks(text, mentionIds ?? []);
8325
+ return client.postListComment(listId, text, notifyAll, blocks);
8279
8326
  }
8280
8327
 
8281
8328
  // src/commands/view-comments.ts
@@ -8289,10 +8336,11 @@ async function fetchViewComments(config, viewId) {
8289
8336
  text: c.comment_text
8290
8337
  }));
8291
8338
  }
8292
- async function postViewCommentCommand(config, viewId, text, notifyAll) {
8339
+ async function postViewCommentCommand(config, viewId, text, notifyAll, mentionIds) {
8293
8340
  if (!text.trim()) throw new Error("Comment text cannot be empty");
8294
8341
  const client = new ClickUpClient(config);
8295
- return client.postViewComment(viewId, text, notifyAll);
8342
+ const blocks = buildCommentBlocks(text, mentionIds ?? []);
8343
+ return client.postViewComment(viewId, text, notifyAll, blocks);
8296
8344
  }
8297
8345
 
8298
8346
  // src/index.ts
@@ -8316,6 +8364,18 @@ function parseOptionalNumberOption(value, optionName) {
8316
8364
  function splitCommaList(value) {
8317
8365
  return value.split(",").map((v) => v.trim()).filter((v) => v.length > 0);
8318
8366
  }
8367
+ function collect(value, previous) {
8368
+ return [...previous, value];
8369
+ }
8370
+ async function resolveMentions(client, teamId, mentions) {
8371
+ if (mentions.length === 0) return [];
8372
+ const resolve2 = createCachedMemberResolver(client, teamId);
8373
+ const ids = [];
8374
+ for (const mention of mentions) {
8375
+ ids.push(await resolve2(mention));
8376
+ }
8377
+ return ids;
8378
+ }
8319
8379
  function createCachedGroupResolver(client) {
8320
8380
  let cache = null;
8321
8381
  const cachingClient = {
@@ -8606,11 +8666,18 @@ function buildProgram(programName = basename(process.argv[1] ?? "cup")) {
8606
8666
  }
8607
8667
  )
8608
8668
  );
8609
- program.command("comment <taskId>").description("Post a comment on a task").requiredOption("-m, --message <text>", "Comment text").option("--notify-all", "Notify all assignees").option("--json", "Force JSON output even in terminal").action(
8669
+ program.command("comment <taskId>").description("Post a comment on a task").requiredOption("-m, --message <text>", "Comment text").option("--notify-all", "Notify all assignees").option(
8670
+ "--mention <user>",
8671
+ 'Mention a user (ID, email, username, or "me"). Repeatable.',
8672
+ collect,
8673
+ []
8674
+ ).option("--json", "Force JSON output even in terminal").action(
8610
8675
  wrapAction(
8611
8676
  async (taskId, opts) => {
8612
8677
  const config = loadConfig(getProfileName());
8613
- const result = await postComment(config, taskId, opts.message, opts.notifyAll);
8678
+ const client = new ClickUpClient(config);
8679
+ const mentionIds = await resolveMentions(client, config.teamId, opts.mention);
8680
+ const result = await postComment(config, taskId, opts.message, opts.notifyAll, mentionIds);
8614
8681
  if (shouldOutputJson(opts.json ?? false)) {
8615
8682
  console.log(JSON.stringify(result, null, 2));
8616
8683
  } else {
@@ -8626,14 +8693,21 @@ function buildProgram(programName = basename(process.argv[1] ?? "cup")) {
8626
8693
  printComments(comments, opts.json ?? false);
8627
8694
  })
8628
8695
  );
8629
- program.command("comment-edit <commentId>").description("Edit an existing comment").option("-m, --message <text>", "New comment text").option("--resolved", "Mark comment as resolved").option("--unresolved", "Mark comment as unresolved").option("--json", "Force JSON output even in terminal").action(
8696
+ program.command("comment-edit <commentId>").description("Edit an existing comment").option("-m, --message <text>", "New comment text").option("--resolved", "Mark comment as resolved").option("--unresolved", "Mark comment as unresolved").option(
8697
+ "--mention <user>",
8698
+ 'Mention a user (ID, email, username, or "me"). Repeatable.',
8699
+ collect,
8700
+ []
8701
+ ).option("--json", "Force JSON output even in terminal").action(
8630
8702
  wrapAction(
8631
8703
  async (commentId, opts) => {
8632
8704
  const config = loadConfig(getProfileName());
8633
8705
  let resolved;
8634
8706
  if (opts.resolved) resolved = true;
8635
8707
  if (opts.unresolved) resolved = false;
8636
- await editComment(config, commentId, opts.message, resolved);
8708
+ const client = new ClickUpClient(config);
8709
+ const mentionIds = await resolveMentions(client, config.teamId, opts.mention);
8710
+ await editComment(config, commentId, opts.message, resolved, mentionIds);
8637
8711
  if (shouldOutputJson(opts.json ?? false)) {
8638
8712
  console.log(JSON.stringify({ success: true, commentId }, null, 2));
8639
8713
  } else {
@@ -8692,11 +8766,18 @@ function buildProgram(programName = basename(process.argv[1] ?? "cup")) {
8692
8766
  }
8693
8767
  })
8694
8768
  );
8695
- program.command("reply <commentId>").description("Reply to a comment").requiredOption("-m, --message <text>", "Reply text").option("--notify-all", "Notify all assignees").option("--json", "Force JSON output even in terminal").action(
8769
+ program.command("reply <commentId>").description("Reply to a comment").requiredOption("-m, --message <text>", "Reply text").option("--notify-all", "Notify all assignees").option(
8770
+ "--mention <user>",
8771
+ 'Mention a user (ID, email, username, or "me"). Repeatable.',
8772
+ collect,
8773
+ []
8774
+ ).option("--json", "Force JSON output even in terminal").action(
8696
8775
  wrapAction(
8697
8776
  async (commentId, opts) => {
8698
8777
  const config = loadConfig(getProfileName());
8699
- await createReply(config, commentId, opts.message, opts.notifyAll);
8778
+ const client = new ClickUpClient(config);
8779
+ const mentionIds = await resolveMentions(client, config.teamId, opts.mention);
8780
+ await createReply(config, commentId, opts.message, opts.notifyAll, mentionIds);
8700
8781
  if (shouldOutputJson(opts.json ?? false)) {
8701
8782
  console.log(JSON.stringify({ success: true, commentId }, null, 2));
8702
8783
  } else {
@@ -10497,11 +10578,24 @@ function buildProgram(programName = basename(process.argv[1] ?? "cup")) {
10497
10578
  printComments(comments, opts.json ?? false);
10498
10579
  })
10499
10580
  );
10500
- program.command("list-comment <listId>").description("Post a comment on a list").requiredOption("-m, --message <text>", "Comment text").option("--notify-all", "Notify all assignees").option("--json", "Force JSON output even in terminal").action(
10581
+ program.command("list-comment <listId>").description("Post a comment on a list").requiredOption("-m, --message <text>", "Comment text").option("--notify-all", "Notify all assignees").option(
10582
+ "--mention <user>",
10583
+ 'Mention a user (ID, email, username, or "me"). Repeatable.',
10584
+ collect,
10585
+ []
10586
+ ).option("--json", "Force JSON output even in terminal").action(
10501
10587
  wrapAction(
10502
10588
  async (listId, opts) => {
10503
10589
  const config = loadConfig(getProfileName());
10504
- const result = await postListCommentCommand(config, listId, opts.message, opts.notifyAll);
10590
+ const client = new ClickUpClient(config);
10591
+ const mentionIds = await resolveMentions(client, config.teamId, opts.mention);
10592
+ const result = await postListCommentCommand(
10593
+ config,
10594
+ listId,
10595
+ opts.message,
10596
+ opts.notifyAll,
10597
+ mentionIds
10598
+ );
10505
10599
  if (shouldOutputJson(opts.json ?? false)) {
10506
10600
  console.log(JSON.stringify(result, null, 2));
10507
10601
  } else {
@@ -10517,11 +10611,24 @@ function buildProgram(programName = basename(process.argv[1] ?? "cup")) {
10517
10611
  printComments(comments, opts.json ?? false);
10518
10612
  })
10519
10613
  );
10520
- program.command("view-comment <viewId>").description("Post a comment on a view").requiredOption("-m, --message <text>", "Comment text").option("--notify-all", "Notify all assignees").option("--json", "Force JSON output even in terminal").action(
10614
+ program.command("view-comment <viewId>").description("Post a comment on a view").requiredOption("-m, --message <text>", "Comment text").option("--notify-all", "Notify all assignees").option(
10615
+ "--mention <user>",
10616
+ 'Mention a user (ID, email, username, or "me"). Repeatable.',
10617
+ collect,
10618
+ []
10619
+ ).option("--json", "Force JSON output even in terminal").action(
10521
10620
  wrapAction(
10522
10621
  async (viewId, opts) => {
10523
10622
  const config = loadConfig(getProfileName());
10524
- const result = await postViewCommentCommand(config, viewId, opts.message, opts.notifyAll);
10623
+ const client = new ClickUpClient(config);
10624
+ const mentionIds = await resolveMentions(client, config.teamId, opts.mention);
10625
+ const result = await postViewCommentCommand(
10626
+ config,
10627
+ viewId,
10628
+ opts.message,
10629
+ opts.notifyAll,
10630
+ mentionIds
10631
+ );
10525
10632
  if (shouldOutputJson(opts.json ?? false)) {
10526
10633
  console.log(JSON.stringify(result, null, 2));
10527
10634
  } else {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@krodak/clickup-cli",
3
- "version": "1.32.0",
3
+ "version": "1.33.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.32.0
6
+ # ClickUp CLI (`cup`) - skill version 1.33.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.32.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.33.0, update with `npm install -g @krodak/clickup-cli` and refresh this skill with `cup skill`.
11
11
 
12
12
  ## Install & Configure
13
13
 
@@ -163,11 +163,11 @@ All commands support `--help` for full flag details. All commands support `--jso
163
163
  | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
164
164
  | `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) |
165
165
  | `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) |
166
- | `cup comment <id> -m text [--notify-all]` | Post comment (markdown auto-converted to rich text) |
167
- | `cup comment-edit <commentId> -m text [--resolved] [--unresolved]` | Edit a comment (markdown auto-converted to rich text) |
166
+ | `cup comment <id> -m text [--notify-all] [--mention user]` | Post comment (markdown auto-converted to rich text; `--mention` for real @mentions, repeatable) |
167
+ | `cup comment-edit <commentId> -m text [--resolved] [--unresolved] [--mention user]` | Edit a comment (markdown auto-converted to rich text; `--mention` for real @mentions) |
168
168
  | `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 |
169
169
  | `cup replies <commentId>` | List threaded replies |
170
- | `cup reply <commentId> -m text [--notify-all]` | Reply to a comment (markdown auto-converted to rich text) |
170
+ | `cup reply <commentId> -m text [--notify-all] [--mention user]` | Reply to a comment (markdown auto-converted to rich text; `--mention` for real @mentions) |
171
171
  | `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) |
172
172
  | `cup depend <id> [--on taskId] [--blocks taskId] [--remove]` | Add/remove dependencies |
173
173
  | `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`. |
@@ -225,8 +225,8 @@ All commands support `--help` for full flag details. All commands support `--jso
225
225
  | `cup view-create <listId> <name> -t <type> [--group-by field]` | Create a view on a list |
226
226
  | `cup view-update <viewId> [-n name] [--group-by field]` | Update a view |
227
227
  | `cup view-delete <viewId> [--confirm]` | Delete a view (DESTRUCTIVE) |
228
- | `cup list-comment <listId> -m text [--notify-all]` | Post comment on a list |
229
- | `cup view-comment <viewId> -m text [--notify-all]` | Post comment on a view |
228
+ | `cup list-comment <listId> -m text [--notify-all] [--mention user]` | Post comment on a list (`--mention` for real @mentions) |
229
+ | `cup view-comment <viewId> -m text [--notify-all] [--mention user]` | Post comment on a view (`--mention` for real @mentions) |
230
230
  | `cup webhook create --url <url> --events <events> [--space\|--folder\|--list\|--task <id>]` | Create a webhook |
231
231
  | `cup webhook update <webhookId> [--url u] [--events e] [--status s]` | Update a webhook |
232
232
  | `cup webhook delete <webhookId> [--confirm]` | Delete a webhook (DESTRUCTIVE) |
@@ -289,6 +289,8 @@ All commands support `--help` for full flag details. All commands support `--jso
289
289
  | `cup delete` | DESTRUCTIVE. Requires `--confirm` in non-interactive mode. Cannot be undone |
290
290
  | Errors | stderr with exit code 1. Strict parsing - excess/unknown arguments rejected |
291
291
  | Description quoting | Use `$'...'` quoting for `-d` / `-m` values containing backticks or newlines: `-d $'Use \`init()\` first.\n\n- Step 1'`. Heredocs and double quotes strip backticks |
292
+ | `--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` |
293
+ | 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) |
292
294
 
293
295
  > **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.
294
296