@krodak/clickup-cli 1.32.0 → 1.34.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude-plugin/plugin.json +1 -1
- package/README.md +17 -17
- package/dist/index.js +168 -34
- package/package.json +1 -1
- package/skills/clickup-cli/SKILL.md +10 -7
|
@@ -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.
|
|
4
|
+
"version": "1.34.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
|
@@ -97,10 +97,38 @@ var ClickUpClient = class {
|
|
|
97
97
|
}
|
|
98
98
|
return "";
|
|
99
99
|
}
|
|
100
|
+
sleep(ms) {
|
|
101
|
+
return new Promise((resolve2) => setTimeout(resolve2, ms));
|
|
102
|
+
}
|
|
103
|
+
retryDelayMs(res, attempt) {
|
|
104
|
+
const retryAfter = res.headers.get("retry-after");
|
|
105
|
+
if (retryAfter) {
|
|
106
|
+
const seconds = Number(retryAfter);
|
|
107
|
+
if (Number.isFinite(seconds) && seconds > 0) {
|
|
108
|
+
return Math.min(seconds, 60) * 1e3;
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
return Math.min(2 ** (attempt - 1) * 1e3, 6e4);
|
|
112
|
+
}
|
|
113
|
+
async fetchWithRetry(url, init) {
|
|
114
|
+
const maxRetries = 3;
|
|
115
|
+
let attempt = 0;
|
|
116
|
+
for (; ; ) {
|
|
117
|
+
const res = await fetch(url, { ...init, signal: AbortSignal.timeout(3e4) });
|
|
118
|
+
const retryable = res.status === 429 || res.status === 502 || res.status === 503 || res.status === 504;
|
|
119
|
+
if (!retryable || attempt >= maxRetries) return res;
|
|
120
|
+
attempt++;
|
|
121
|
+
const delayMs = this.retryDelayMs(res, attempt);
|
|
122
|
+
process.stderr.write(
|
|
123
|
+
`Rate limited (${res.status}). Retrying in ${Math.round(delayMs / 1e3)}s... (attempt ${attempt}/${maxRetries})
|
|
124
|
+
`
|
|
125
|
+
);
|
|
126
|
+
await this.sleep(delayMs);
|
|
127
|
+
}
|
|
128
|
+
}
|
|
100
129
|
async _fetch(baseUrl, path, options = {}) {
|
|
101
|
-
const res = await
|
|
130
|
+
const res = await this.fetchWithRetry(`${baseUrl}${path}`, {
|
|
102
131
|
...options,
|
|
103
|
-
signal: AbortSignal.timeout(3e4),
|
|
104
132
|
headers: {
|
|
105
133
|
Authorization: this.apiToken,
|
|
106
134
|
...options.body ? { "Content-Type": "application/json" } : {},
|
|
@@ -134,8 +162,7 @@ var ClickUpClient = class {
|
|
|
134
162
|
return this._fetch(BASE_URL_V3, path, options);
|
|
135
163
|
}
|
|
136
164
|
async requestV3Array(path) {
|
|
137
|
-
const res = await
|
|
138
|
-
signal: AbortSignal.timeout(3e4),
|
|
165
|
+
const res = await this.fetchWithRetry(`${BASE_URL_V3}${path}`, {
|
|
139
166
|
headers: { Authorization: this.apiToken }
|
|
140
167
|
});
|
|
141
168
|
if (res.status === 204 || res.headers.get("content-length") === "0") {
|
|
@@ -1066,8 +1093,8 @@ var ClickUpClient = class {
|
|
|
1066
1093
|
const data = await this.request(`/list/${listId}/comment`);
|
|
1067
1094
|
return readCollectionField(data, "comments", "list comments");
|
|
1068
1095
|
}
|
|
1069
|
-
async postListComment(listId, commentText, notifyAll) {
|
|
1070
|
-
const body = { comment_text: commentText };
|
|
1096
|
+
async postListComment(listId, commentText, notifyAll, richBlocks) {
|
|
1097
|
+
const body = richBlocks ? { comment: richBlocks } : { comment_text: commentText };
|
|
1071
1098
|
if (notifyAll) body.notify_all = true;
|
|
1072
1099
|
return this.request(`/list/${listId}/comment`, {
|
|
1073
1100
|
method: "POST",
|
|
@@ -1078,8 +1105,8 @@ var ClickUpClient = class {
|
|
|
1078
1105
|
const data = await this.request(`/view/${viewId}/comment`);
|
|
1079
1106
|
return readCollectionField(data, "comments", "view comments");
|
|
1080
1107
|
}
|
|
1081
|
-
async postViewComment(viewId, commentText, notifyAll) {
|
|
1082
|
-
const body = { comment_text: commentText };
|
|
1108
|
+
async postViewComment(viewId, commentText, notifyAll, richBlocks) {
|
|
1109
|
+
const body = richBlocks ? { comment: richBlocks } : { comment_text: commentText };
|
|
1083
1110
|
if (notifyAll) body.notify_all = true;
|
|
1084
1111
|
return this.request(`/view/${viewId}/comment`, {
|
|
1085
1112
|
method: "POST",
|
|
@@ -2865,7 +2892,9 @@ function processInlineFormatting(text, lineAttrs) {
|
|
|
2865
2892
|
{ type: "bold", re: /\*{2}([^*]+)\*{2}/ },
|
|
2866
2893
|
{ type: "italic", re: /(?<!\*)\*(?!\*)([^*]+)(?<!\*)\*(?!\*)/ },
|
|
2867
2894
|
{ type: "strike", re: /~~([^~]+)~~/ },
|
|
2868
|
-
{ type: "
|
|
2895
|
+
{ type: "mention", re: /<@(\d+)>/ },
|
|
2896
|
+
{ type: "link", re: /\[([^\]]+)\]\(([^)]+)\)/ },
|
|
2897
|
+
{ type: "autolink", re: /(?<![([])(https?:\/\/[^\s<>]+)/ }
|
|
2869
2898
|
];
|
|
2870
2899
|
for (const { type, re } of patterns) {
|
|
2871
2900
|
const m = re.exec(remaining);
|
|
@@ -2913,6 +2942,15 @@ function processInlineFormatting(text, lineAttrs) {
|
|
|
2913
2942
|
attributes: { ...lineAttrs, link: matchResult[2] }
|
|
2914
2943
|
});
|
|
2915
2944
|
break;
|
|
2945
|
+
case "autolink":
|
|
2946
|
+
blocks.push({
|
|
2947
|
+
text: innerText,
|
|
2948
|
+
attributes: { ...lineAttrs, link: innerText }
|
|
2949
|
+
});
|
|
2950
|
+
break;
|
|
2951
|
+
case "mention":
|
|
2952
|
+
blocks.push({ type: "tag", user: { id: Number(innerText) } });
|
|
2953
|
+
break;
|
|
2916
2954
|
}
|
|
2917
2955
|
remaining = remaining.slice(earliestIndex + matchResult[0].length);
|
|
2918
2956
|
}
|
|
@@ -3015,10 +3053,42 @@ function markdownToCommentBlocks(markdown) {
|
|
|
3015
3053
|
}
|
|
3016
3054
|
|
|
3017
3055
|
// src/commands/comment.ts
|
|
3018
|
-
async function
|
|
3056
|
+
async function resolveMemberId(client, teamId, value) {
|
|
3057
|
+
if (/^\d+$/.test(value)) return Number(value);
|
|
3058
|
+
if (value === "me") return (await client.getMe()).id;
|
|
3059
|
+
const members = await client.getWorkspaceMembers(teamId);
|
|
3060
|
+
const match = members.find(
|
|
3061
|
+
(m) => m.email?.toLowerCase() === value.toLowerCase() || m.username?.toLowerCase() === value.toLowerCase()
|
|
3062
|
+
);
|
|
3063
|
+
if (match) return match.id;
|
|
3064
|
+
const available = members.map((m) => `${m.username} (${m.email})`).join(", ");
|
|
3065
|
+
throw new Error(`Member "${value}" not found. Available: ${available}`);
|
|
3066
|
+
}
|
|
3067
|
+
function createCachedMemberResolver(client, teamId) {
|
|
3068
|
+
let membersCache = null;
|
|
3069
|
+
const cachingClient = {
|
|
3070
|
+
getMe: () => client.getMe(),
|
|
3071
|
+
getWorkspaceMembers: async () => {
|
|
3072
|
+
if (membersCache === null) membersCache = await client.getWorkspaceMembers(teamId);
|
|
3073
|
+
return membersCache;
|
|
3074
|
+
}
|
|
3075
|
+
};
|
|
3076
|
+
return (value) => resolveMemberId(cachingClient, teamId, value);
|
|
3077
|
+
}
|
|
3078
|
+
function buildCommentBlocks(message, mentionIds) {
|
|
3079
|
+
const messageBlocks = markdownToCommentBlocks(message);
|
|
3080
|
+
if (mentionIds.length === 0) return messageBlocks;
|
|
3081
|
+
const mentionBlocks = [];
|
|
3082
|
+
for (const id of mentionIds) {
|
|
3083
|
+
mentionBlocks.push({ type: "tag", user: { id } });
|
|
3084
|
+
mentionBlocks.push({ text: " " });
|
|
3085
|
+
}
|
|
3086
|
+
return [...mentionBlocks, ...messageBlocks];
|
|
3087
|
+
}
|
|
3088
|
+
async function postComment(config, taskId, text, notifyAll, mentionIds) {
|
|
3019
3089
|
if (!text.trim()) throw new Error("Comment text cannot be empty");
|
|
3020
3090
|
const client = new ClickUpClient(config);
|
|
3021
|
-
const blocks =
|
|
3091
|
+
const blocks = buildCommentBlocks(text, mentionIds ?? []);
|
|
3022
3092
|
return client.postComment(taskId, text, notifyAll, blocks);
|
|
3023
3093
|
}
|
|
3024
3094
|
|
|
@@ -3832,7 +3902,7 @@ var commandMetadata = [
|
|
|
3832
3902
|
{
|
|
3833
3903
|
name: "comment",
|
|
3834
3904
|
description: "Post a comment on a task",
|
|
3835
|
-
flags: ["-m", "--message", "--notify-all", "--json"],
|
|
3905
|
+
flags: ["-m", "--message", "--notify-all", "--mention", "--json"],
|
|
3836
3906
|
quickReference: [
|
|
3837
3907
|
{ section: "write", usage: "comment <taskId>", description: "Post a comment on a task" }
|
|
3838
3908
|
]
|
|
@@ -3840,7 +3910,7 @@ var commandMetadata = [
|
|
|
3840
3910
|
{
|
|
3841
3911
|
name: "comment-edit",
|
|
3842
3912
|
description: "Edit an existing comment",
|
|
3843
|
-
flags: ["-m", "--message", "--resolved", "--unresolved", "--json"],
|
|
3913
|
+
flags: ["-m", "--message", "--resolved", "--unresolved", "--mention", "--json"],
|
|
3844
3914
|
quickReference: [
|
|
3845
3915
|
{
|
|
3846
3916
|
section: "write",
|
|
@@ -3884,7 +3954,7 @@ var commandMetadata = [
|
|
|
3884
3954
|
{
|
|
3885
3955
|
name: "reply",
|
|
3886
3956
|
description: "Reply to a comment",
|
|
3887
|
-
flags: ["-m", "--message", "--notify-all", "--json"],
|
|
3957
|
+
flags: ["-m", "--message", "--notify-all", "--mention", "--json"],
|
|
3888
3958
|
quickReference: [
|
|
3889
3959
|
{ section: "write", usage: "reply <commentId>", description: "Reply to a comment" }
|
|
3890
3960
|
]
|
|
@@ -4689,7 +4759,7 @@ var commandMetadata = [
|
|
|
4689
4759
|
{
|
|
4690
4760
|
name: "list-comment",
|
|
4691
4761
|
description: "Post a comment on a list",
|
|
4692
|
-
flags: ["-m", "--message", "--notify-all", "--json"],
|
|
4762
|
+
flags: ["-m", "--message", "--notify-all", "--mention", "--json"],
|
|
4693
4763
|
quickReference: [
|
|
4694
4764
|
{
|
|
4695
4765
|
section: "write",
|
|
@@ -4713,7 +4783,7 @@ var commandMetadata = [
|
|
|
4713
4783
|
{
|
|
4714
4784
|
name: "view-comment",
|
|
4715
4785
|
description: "Post a comment on a view",
|
|
4716
|
-
flags: ["-m", "--message", "--notify-all", "--json"],
|
|
4786
|
+
flags: ["-m", "--message", "--notify-all", "--mention", "--json"],
|
|
4717
4787
|
quickReference: [
|
|
4718
4788
|
{
|
|
4719
4789
|
section: "write",
|
|
@@ -5156,6 +5226,7 @@ ${renderZshTopLevelCommands(name)}
|
|
|
5156
5226
|
'1:task_id:' \\
|
|
5157
5227
|
'(-m --message)'{-m,--message}'[Comment text]:text:' \\
|
|
5158
5228
|
'--notify-all[Notify all assignees]' \\
|
|
5229
|
+
'--mention[Mention a user (ID, email, username, or me)]:user:' \\
|
|
5159
5230
|
'--json[Force JSON output]'
|
|
5160
5231
|
;;
|
|
5161
5232
|
comments)
|
|
@@ -5390,6 +5461,7 @@ ${renderZshTopLevelCommands(name)}
|
|
|
5390
5461
|
'(-m --message)'{-m,--message}'[New comment text]:text:' \\
|
|
5391
5462
|
'--resolved[Mark comment as resolved]' \\
|
|
5392
5463
|
'--unresolved[Mark comment as unresolved]' \\
|
|
5464
|
+
'--mention[Mention a user (ID, email, username, or me)]:user:' \\
|
|
5393
5465
|
'--json[Force JSON output]'
|
|
5394
5466
|
;;
|
|
5395
5467
|
comment-delete)
|
|
@@ -5410,6 +5482,7 @@ ${renderZshTopLevelCommands(name)}
|
|
|
5410
5482
|
'1:comment_id:' \\
|
|
5411
5483
|
'(-m --message)'{-m,--message}'[Reply text]:text:' \\
|
|
5412
5484
|
'--notify-all[Notify all assignees]' \\
|
|
5485
|
+
'--mention[Mention a user (ID, email, username, or me)]:user:' \\
|
|
5413
5486
|
'--json[Force JSON output]'
|
|
5414
5487
|
;;
|
|
5415
5488
|
link)
|
|
@@ -6780,13 +6853,13 @@ function formatChecklistsMarkdown(checklists) {
|
|
|
6780
6853
|
}
|
|
6781
6854
|
|
|
6782
6855
|
// src/commands/comment-edit.ts
|
|
6783
|
-
async function editComment(config, commentId, text, resolved) {
|
|
6856
|
+
async function editComment(config, commentId, text, resolved, mentionIds) {
|
|
6784
6857
|
if (text === void 0 && resolved === void 0) {
|
|
6785
6858
|
throw new Error("Provide at least one of: --message, --resolved, --unresolved");
|
|
6786
6859
|
}
|
|
6787
6860
|
if (text !== void 0 && !text.trim()) throw new Error("Comment text cannot be empty");
|
|
6788
6861
|
const client = new ClickUpClient(config);
|
|
6789
|
-
const blocks = text !== void 0 ?
|
|
6862
|
+
const blocks = text !== void 0 ? buildCommentBlocks(text, mentionIds ?? []) : void 0;
|
|
6790
6863
|
await client.updateComment(commentId, text ?? "", resolved, blocks);
|
|
6791
6864
|
}
|
|
6792
6865
|
|
|
@@ -6827,10 +6900,10 @@ async function getReplies(config, commentId) {
|
|
|
6827
6900
|
const client = new ClickUpClient(config);
|
|
6828
6901
|
return client.getThreadedComments(commentId);
|
|
6829
6902
|
}
|
|
6830
|
-
async function createReply(config, commentId, text, notifyAll) {
|
|
6903
|
+
async function createReply(config, commentId, text, notifyAll, mentionIds) {
|
|
6831
6904
|
if (!text.trim()) throw new Error("Reply text cannot be empty");
|
|
6832
6905
|
const client = new ClickUpClient(config);
|
|
6833
|
-
const blocks =
|
|
6906
|
+
const blocks = buildCommentBlocks(text, mentionIds ?? []);
|
|
6834
6907
|
await client.createThreadedComment(commentId, text, notifyAll, blocks);
|
|
6835
6908
|
}
|
|
6836
6909
|
function formatReplies(replies) {
|
|
@@ -8272,10 +8345,11 @@ async function fetchListComments(config, listId) {
|
|
|
8272
8345
|
text: c.comment_text
|
|
8273
8346
|
}));
|
|
8274
8347
|
}
|
|
8275
|
-
async function postListCommentCommand(config, listId, text, notifyAll) {
|
|
8348
|
+
async function postListCommentCommand(config, listId, text, notifyAll, mentionIds) {
|
|
8276
8349
|
if (!text.trim()) throw new Error("Comment text cannot be empty");
|
|
8277
8350
|
const client = new ClickUpClient(config);
|
|
8278
|
-
|
|
8351
|
+
const blocks = buildCommentBlocks(text, mentionIds ?? []);
|
|
8352
|
+
return client.postListComment(listId, text, notifyAll, blocks);
|
|
8279
8353
|
}
|
|
8280
8354
|
|
|
8281
8355
|
// src/commands/view-comments.ts
|
|
@@ -8289,10 +8363,11 @@ async function fetchViewComments(config, viewId) {
|
|
|
8289
8363
|
text: c.comment_text
|
|
8290
8364
|
}));
|
|
8291
8365
|
}
|
|
8292
|
-
async function postViewCommentCommand(config, viewId, text, notifyAll) {
|
|
8366
|
+
async function postViewCommentCommand(config, viewId, text, notifyAll, mentionIds) {
|
|
8293
8367
|
if (!text.trim()) throw new Error("Comment text cannot be empty");
|
|
8294
8368
|
const client = new ClickUpClient(config);
|
|
8295
|
-
|
|
8369
|
+
const blocks = buildCommentBlocks(text, mentionIds ?? []);
|
|
8370
|
+
return client.postViewComment(viewId, text, notifyAll, blocks);
|
|
8296
8371
|
}
|
|
8297
8372
|
|
|
8298
8373
|
// src/index.ts
|
|
@@ -8316,6 +8391,18 @@ function parseOptionalNumberOption(value, optionName) {
|
|
|
8316
8391
|
function splitCommaList(value) {
|
|
8317
8392
|
return value.split(",").map((v) => v.trim()).filter((v) => v.length > 0);
|
|
8318
8393
|
}
|
|
8394
|
+
function collect(value, previous) {
|
|
8395
|
+
return [...previous, value];
|
|
8396
|
+
}
|
|
8397
|
+
async function resolveMentions(client, teamId, mentions) {
|
|
8398
|
+
if (mentions.length === 0) return [];
|
|
8399
|
+
const resolve2 = createCachedMemberResolver(client, teamId);
|
|
8400
|
+
const ids = [];
|
|
8401
|
+
for (const mention of mentions) {
|
|
8402
|
+
ids.push(await resolve2(mention));
|
|
8403
|
+
}
|
|
8404
|
+
return ids;
|
|
8405
|
+
}
|
|
8319
8406
|
function createCachedGroupResolver(client) {
|
|
8320
8407
|
let cache = null;
|
|
8321
8408
|
const cachingClient = {
|
|
@@ -8606,11 +8693,18 @@ function buildProgram(programName = basename(process.argv[1] ?? "cup")) {
|
|
|
8606
8693
|
}
|
|
8607
8694
|
)
|
|
8608
8695
|
);
|
|
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(
|
|
8696
|
+
program.command("comment <taskId>").description("Post a comment on a task").requiredOption("-m, --message <text>", "Comment text").option("--notify-all", "Notify all assignees").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(
|
|
8610
8702
|
wrapAction(
|
|
8611
8703
|
async (taskId, opts) => {
|
|
8612
8704
|
const config = loadConfig(getProfileName());
|
|
8613
|
-
const
|
|
8705
|
+
const client = new ClickUpClient(config);
|
|
8706
|
+
const mentionIds = await resolveMentions(client, config.teamId, opts.mention);
|
|
8707
|
+
const result = await postComment(config, taskId, opts.message, opts.notifyAll, mentionIds);
|
|
8614
8708
|
if (shouldOutputJson(opts.json ?? false)) {
|
|
8615
8709
|
console.log(JSON.stringify(result, null, 2));
|
|
8616
8710
|
} else {
|
|
@@ -8626,14 +8720,21 @@ function buildProgram(programName = basename(process.argv[1] ?? "cup")) {
|
|
|
8626
8720
|
printComments(comments, opts.json ?? false);
|
|
8627
8721
|
})
|
|
8628
8722
|
);
|
|
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(
|
|
8723
|
+
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(
|
|
8724
|
+
"--mention <user>",
|
|
8725
|
+
'Mention a user (ID, email, username, or "me"). Repeatable.',
|
|
8726
|
+
collect,
|
|
8727
|
+
[]
|
|
8728
|
+
).option("--json", "Force JSON output even in terminal").action(
|
|
8630
8729
|
wrapAction(
|
|
8631
8730
|
async (commentId, opts) => {
|
|
8632
8731
|
const config = loadConfig(getProfileName());
|
|
8633
8732
|
let resolved;
|
|
8634
8733
|
if (opts.resolved) resolved = true;
|
|
8635
8734
|
if (opts.unresolved) resolved = false;
|
|
8636
|
-
|
|
8735
|
+
const client = new ClickUpClient(config);
|
|
8736
|
+
const mentionIds = await resolveMentions(client, config.teamId, opts.mention);
|
|
8737
|
+
await editComment(config, commentId, opts.message, resolved, mentionIds);
|
|
8637
8738
|
if (shouldOutputJson(opts.json ?? false)) {
|
|
8638
8739
|
console.log(JSON.stringify({ success: true, commentId }, null, 2));
|
|
8639
8740
|
} else {
|
|
@@ -8692,11 +8793,18 @@ function buildProgram(programName = basename(process.argv[1] ?? "cup")) {
|
|
|
8692
8793
|
}
|
|
8693
8794
|
})
|
|
8694
8795
|
);
|
|
8695
|
-
program.command("reply <commentId>").description("Reply to a comment").requiredOption("-m, --message <text>", "Reply text").option("--notify-all", "Notify all assignees").option(
|
|
8796
|
+
program.command("reply <commentId>").description("Reply to a comment").requiredOption("-m, --message <text>", "Reply text").option("--notify-all", "Notify all assignees").option(
|
|
8797
|
+
"--mention <user>",
|
|
8798
|
+
'Mention a user (ID, email, username, or "me"). Repeatable.',
|
|
8799
|
+
collect,
|
|
8800
|
+
[]
|
|
8801
|
+
).option("--json", "Force JSON output even in terminal").action(
|
|
8696
8802
|
wrapAction(
|
|
8697
8803
|
async (commentId, opts) => {
|
|
8698
8804
|
const config = loadConfig(getProfileName());
|
|
8699
|
-
|
|
8805
|
+
const client = new ClickUpClient(config);
|
|
8806
|
+
const mentionIds = await resolveMentions(client, config.teamId, opts.mention);
|
|
8807
|
+
await createReply(config, commentId, opts.message, opts.notifyAll, mentionIds);
|
|
8700
8808
|
if (shouldOutputJson(opts.json ?? false)) {
|
|
8701
8809
|
console.log(JSON.stringify({ success: true, commentId }, null, 2));
|
|
8702
8810
|
} else {
|
|
@@ -10497,11 +10605,24 @@ function buildProgram(programName = basename(process.argv[1] ?? "cup")) {
|
|
|
10497
10605
|
printComments(comments, opts.json ?? false);
|
|
10498
10606
|
})
|
|
10499
10607
|
);
|
|
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(
|
|
10608
|
+
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(
|
|
10609
|
+
"--mention <user>",
|
|
10610
|
+
'Mention a user (ID, email, username, or "me"). Repeatable.',
|
|
10611
|
+
collect,
|
|
10612
|
+
[]
|
|
10613
|
+
).option("--json", "Force JSON output even in terminal").action(
|
|
10501
10614
|
wrapAction(
|
|
10502
10615
|
async (listId, opts) => {
|
|
10503
10616
|
const config = loadConfig(getProfileName());
|
|
10504
|
-
const
|
|
10617
|
+
const client = new ClickUpClient(config);
|
|
10618
|
+
const mentionIds = await resolveMentions(client, config.teamId, opts.mention);
|
|
10619
|
+
const result = await postListCommentCommand(
|
|
10620
|
+
config,
|
|
10621
|
+
listId,
|
|
10622
|
+
opts.message,
|
|
10623
|
+
opts.notifyAll,
|
|
10624
|
+
mentionIds
|
|
10625
|
+
);
|
|
10505
10626
|
if (shouldOutputJson(opts.json ?? false)) {
|
|
10506
10627
|
console.log(JSON.stringify(result, null, 2));
|
|
10507
10628
|
} else {
|
|
@@ -10517,11 +10638,24 @@ function buildProgram(programName = basename(process.argv[1] ?? "cup")) {
|
|
|
10517
10638
|
printComments(comments, opts.json ?? false);
|
|
10518
10639
|
})
|
|
10519
10640
|
);
|
|
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(
|
|
10641
|
+
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(
|
|
10642
|
+
"--mention <user>",
|
|
10643
|
+
'Mention a user (ID, email, username, or "me"). Repeatable.',
|
|
10644
|
+
collect,
|
|
10645
|
+
[]
|
|
10646
|
+
).option("--json", "Force JSON output even in terminal").action(
|
|
10521
10647
|
wrapAction(
|
|
10522
10648
|
async (viewId, opts) => {
|
|
10523
10649
|
const config = loadConfig(getProfileName());
|
|
10524
|
-
const
|
|
10650
|
+
const client = new ClickUpClient(config);
|
|
10651
|
+
const mentionIds = await resolveMentions(client, config.teamId, opts.mention);
|
|
10652
|
+
const result = await postViewCommentCommand(
|
|
10653
|
+
config,
|
|
10654
|
+
viewId,
|
|
10655
|
+
opts.message,
|
|
10656
|
+
opts.notifyAll,
|
|
10657
|
+
mentionIds
|
|
10658
|
+
);
|
|
10525
10659
|
if (shouldOutputJson(opts.json ?? false)) {
|
|
10526
10660
|
console.log(JSON.stringify(result, null, 2));
|
|
10527
10661
|
} else {
|
package/package.json
CHANGED
|
@@ -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.
|
|
6
|
+
# ClickUp CLI (`cup`) - skill version 1.34.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.
|
|
10
|
+
> **Version check:** Run `cup --version`. If your installed version is older than 1.34.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]`
|
|
167
|
-
| `cup comment-edit <commentId> -m text [--resolved] [--unresolved]`
|
|
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]`
|
|
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]`
|
|
229
|
-
| `cup view-comment <viewId> -m text [--notify-all]`
|
|
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) |
|
|
@@ -288,7 +288,10 @@ All commands support `--help` for full flag details. All commands support `--jso
|
|
|
288
288
|
| `cup link` | Both IDs must be the same type (both custom or both native) |
|
|
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
|
+
| 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 |
|
|
291
292
|
| 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 |
|
|
293
|
+
| `--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` |
|
|
294
|
+
| 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
295
|
|
|
293
296
|
> **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
297
|
|