@krodak/clickup-cli 1.30.0 → 1.31.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 +234 -60
- package/package.json +1 -1
- package/skills/clickup-cli/SKILL.md +100 -94
|
@@ -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.31.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, 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, 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, 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
|
@@ -658,6 +658,10 @@ var ClickUpClient = class {
|
|
|
658
658
|
).find((t) => t.id === teamId);
|
|
659
659
|
return team?.members?.map((m) => m.user) ?? [];
|
|
660
660
|
}
|
|
661
|
+
async getGroups() {
|
|
662
|
+
const data = await this.request(`/group?team_id=${this.teamId}`);
|
|
663
|
+
return readCollectionField(data, "groups", "groups");
|
|
664
|
+
}
|
|
661
665
|
async deleteTimeEntry(teamId, timeEntryId) {
|
|
662
666
|
await this.request(`/team/${teamId}/time_entries/${timeEntryId}`, {
|
|
663
667
|
method: "DELETE"
|
|
@@ -1748,6 +1752,8 @@ function formatAssignConfirmation(taskId, opts) {
|
|
|
1748
1752
|
const parts = [];
|
|
1749
1753
|
if (opts.to) parts.push(`Assigned ${opts.to} to ${taskId}`);
|
|
1750
1754
|
if (opts.remove) parts.push(`Removed ${opts.remove} from ${taskId}`);
|
|
1755
|
+
if (opts.group) parts.push(`Assigned group ${opts.group} to ${taskId}`);
|
|
1756
|
+
if (opts.removeGroup) parts.push(`Removed group ${opts.removeGroup} from ${taskId}`);
|
|
1751
1757
|
return parts.join("; ");
|
|
1752
1758
|
}
|
|
1753
1759
|
|
|
@@ -2160,6 +2166,16 @@ async function resolveAssigneeId(client, value) {
|
|
|
2160
2166
|
}
|
|
2161
2167
|
return parseAssigneeId(value);
|
|
2162
2168
|
}
|
|
2169
|
+
var UUID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
2170
|
+
async function resolveGroupId(client, value) {
|
|
2171
|
+
if (UUID_RE.test(value)) return value;
|
|
2172
|
+
const handle = value.startsWith("@") ? value.slice(1) : value;
|
|
2173
|
+
const groups = await client.getGroups();
|
|
2174
|
+
const match = groups.find((g) => g.handle.toLowerCase() === handle.toLowerCase());
|
|
2175
|
+
if (match) return match.id;
|
|
2176
|
+
const available = groups.map((g) => `@${g.handle}`).join(", ") || "(none)";
|
|
2177
|
+
throw new Error(`Group "${value}" not found. Available: ${available}`);
|
|
2178
|
+
}
|
|
2163
2179
|
function parseTimeEstimate(value) {
|
|
2164
2180
|
if (value === "0" || value.toLowerCase() === "none" || value === "") return 0;
|
|
2165
2181
|
const pattern = /^(?:(\d+)h)?(?:(\d+)m)?$/i;
|
|
@@ -2213,6 +2229,14 @@ function buildUpdatePayload(opts, timezone) {
|
|
|
2213
2229
|
payload.assignees.rem = [parseAssigneeId(opts.removeAssignee)];
|
|
2214
2230
|
}
|
|
2215
2231
|
}
|
|
2232
|
+
const addGroups = opts.groupAssigneeIds ?? [];
|
|
2233
|
+
const remGroups = opts.removeGroupAssigneeIds ?? [];
|
|
2234
|
+
if (addGroups.length > 0 || remGroups.length > 0) {
|
|
2235
|
+
payload.group_assignees = {
|
|
2236
|
+
...addGroups.length > 0 ? { add: addGroups } : {},
|
|
2237
|
+
...remGroups.length > 0 ? { rem: remGroups } : {}
|
|
2238
|
+
};
|
|
2239
|
+
}
|
|
2216
2240
|
if (opts.timeEstimate !== void 0) {
|
|
2217
2241
|
payload.time_estimate = parseTimeEstimate(opts.timeEstimate);
|
|
2218
2242
|
}
|
|
@@ -2232,7 +2256,7 @@ function buildUpdatePayload(opts, timezone) {
|
|
|
2232
2256
|
return payload;
|
|
2233
2257
|
}
|
|
2234
2258
|
function hasUpdateFields(options) {
|
|
2235
|
-
return options.name !== void 0 || options.description !== void 0 || options.markdown_content !== void 0 || options.status !== void 0 || options.priority !== void 0 || options.due_date !== void 0 || options.start_date !== void 0 || options.time_estimate !== void 0 || options.assignees !== void 0 || options.parent !== void 0 || options.archived !== void 0 || options.custom_item_id !== void 0;
|
|
2259
|
+
return options.name !== void 0 || options.description !== void 0 || options.markdown_content !== void 0 || options.status !== void 0 || options.priority !== void 0 || options.due_date !== void 0 || options.start_date !== void 0 || options.time_estimate !== void 0 || options.assignees !== void 0 || options.group_assignees !== void 0 || options.parent !== void 0 || options.archived !== void 0 || options.custom_item_id !== void 0;
|
|
2236
2260
|
}
|
|
2237
2261
|
async function resolveStatus(client, taskId, statusInput) {
|
|
2238
2262
|
const task = await client.getTask(taskId);
|
|
@@ -2261,7 +2285,7 @@ async function resolveTaskType2(client, teamId, typeInput) {
|
|
|
2261
2285
|
async function updateTask(config, taskId, options, typeInput) {
|
|
2262
2286
|
if (!hasUpdateFields(options) && typeInput === void 0)
|
|
2263
2287
|
throw new Error(
|
|
2264
|
-
"Provide at least one of: --name, --description, --status, --priority, --due-date, --start-date, --time-estimate, --assignee, --remove-assignee, --parent, --detach, --archive, --unarchive, --type"
|
|
2288
|
+
"Provide at least one of: --name, --description, --status, --priority, --due-date, --start-date, --time-estimate, --assignee, --remove-assignee, --group-assignee, --remove-group-assignee, --parent, --detach, --archive, --unarchive, --type"
|
|
2265
2289
|
);
|
|
2266
2290
|
const client = new ClickUpClient(config);
|
|
2267
2291
|
const resolved = { ...options };
|
|
@@ -2314,6 +2338,9 @@ async function createTask(config, options) {
|
|
|
2314
2338
|
if (options.assignee !== void 0) {
|
|
2315
2339
|
payload.assignees = [parseAssigneeId(options.assignee)];
|
|
2316
2340
|
}
|
|
2341
|
+
if (options.groupAssigneeIds !== void 0 && options.groupAssigneeIds.length > 0) {
|
|
2342
|
+
payload.group_assignees = options.groupAssigneeIds;
|
|
2343
|
+
}
|
|
2317
2344
|
if (options.tags !== void 0) {
|
|
2318
2345
|
payload.tags = options.tags.split(",").map((t) => t.trim());
|
|
2319
2346
|
}
|
|
@@ -3466,13 +3493,26 @@ function configPath2() {
|
|
|
3466
3493
|
function parseIdList(value) {
|
|
3467
3494
|
return value.split(",").map((v) => v.trim()).filter((v) => v.length > 0);
|
|
3468
3495
|
}
|
|
3496
|
+
function createGroupCache(client) {
|
|
3497
|
+
let cache = null;
|
|
3498
|
+
const cachingClient = {
|
|
3499
|
+
getGroups: async () => {
|
|
3500
|
+
if (cache === null) cache = await client.getGroups();
|
|
3501
|
+
return cache;
|
|
3502
|
+
}
|
|
3503
|
+
};
|
|
3504
|
+
return (value) => resolveGroupId(cachingClient, value);
|
|
3505
|
+
}
|
|
3469
3506
|
async function assignTask(config, taskId, opts) {
|
|
3470
|
-
if (!opts.to && !opts.remove) {
|
|
3471
|
-
throw new Error("Provide at least one of: --to, --remove");
|
|
3507
|
+
if (!opts.to && !opts.remove && !opts.group && !opts.removeGroup) {
|
|
3508
|
+
throw new Error("Provide at least one of: --to, --remove, --group, --remove-group");
|
|
3472
3509
|
}
|
|
3473
3510
|
const client = new ClickUpClient(config);
|
|
3511
|
+
const resolveGroup = createGroupCache(client);
|
|
3474
3512
|
const add = [];
|
|
3475
3513
|
const rem = [];
|
|
3514
|
+
const groupAdd = [];
|
|
3515
|
+
const groupRem = [];
|
|
3476
3516
|
if (opts.to) {
|
|
3477
3517
|
for (const value of parseIdList(opts.to)) {
|
|
3478
3518
|
add.push(await resolveAssigneeId(client, value));
|
|
@@ -3483,12 +3523,30 @@ async function assignTask(config, taskId, opts) {
|
|
|
3483
3523
|
rem.push(await resolveAssigneeId(client, value));
|
|
3484
3524
|
}
|
|
3485
3525
|
}
|
|
3486
|
-
|
|
3487
|
-
|
|
3526
|
+
if (opts.group) {
|
|
3527
|
+
for (const value of parseIdList(opts.group)) {
|
|
3528
|
+
groupAdd.push(await resolveGroup(value));
|
|
3529
|
+
}
|
|
3530
|
+
}
|
|
3531
|
+
if (opts.removeGroup) {
|
|
3532
|
+
for (const value of parseIdList(opts.removeGroup)) {
|
|
3533
|
+
groupRem.push(await resolveGroup(value));
|
|
3534
|
+
}
|
|
3535
|
+
}
|
|
3536
|
+
const payload = {};
|
|
3537
|
+
if (add.length > 0 || rem.length > 0) {
|
|
3538
|
+
payload.assignees = {
|
|
3488
3539
|
...add.length > 0 ? { add } : {},
|
|
3489
3540
|
...rem.length > 0 ? { rem } : {}
|
|
3490
|
-
}
|
|
3491
|
-
}
|
|
3541
|
+
};
|
|
3542
|
+
}
|
|
3543
|
+
if (groupAdd.length > 0 || groupRem.length > 0) {
|
|
3544
|
+
payload.group_assignees = {
|
|
3545
|
+
...groupAdd.length > 0 ? { add: groupAdd } : {},
|
|
3546
|
+
...groupRem.length > 0 ? { rem: groupRem } : {}
|
|
3547
|
+
};
|
|
3548
|
+
}
|
|
3549
|
+
return client.updateTask(taskId, payload);
|
|
3492
3550
|
}
|
|
3493
3551
|
|
|
3494
3552
|
// src/commands/activity.ts
|
|
@@ -3687,6 +3745,8 @@ var commandMetadata = [
|
|
|
3687
3745
|
"--time-estimate",
|
|
3688
3746
|
"--assignee",
|
|
3689
3747
|
"--remove-assignee",
|
|
3748
|
+
"--group-assignee",
|
|
3749
|
+
"--remove-group-assignee",
|
|
3690
3750
|
"--parent",
|
|
3691
3751
|
"--detach",
|
|
3692
3752
|
"--archive",
|
|
@@ -3715,6 +3775,7 @@ var commandMetadata = [
|
|
|
3715
3775
|
"--due-date",
|
|
3716
3776
|
"--start-date",
|
|
3717
3777
|
"--assignee",
|
|
3778
|
+
"--group-assignee",
|
|
3718
3779
|
"--tags",
|
|
3719
3780
|
"--custom-item-id",
|
|
3720
3781
|
"--time-estimate",
|
|
@@ -3912,10 +3973,14 @@ var commandMetadata = [
|
|
|
3912
3973
|
},
|
|
3913
3974
|
{
|
|
3914
3975
|
name: "assign",
|
|
3915
|
-
description: "Assign or unassign users from a task",
|
|
3916
|
-
flags: ["--to", "--remove", "--json"],
|
|
3976
|
+
description: "Assign or unassign users and groups from a task",
|
|
3977
|
+
flags: ["--to", "--remove", "--group", "--remove-group", "--json"],
|
|
3917
3978
|
quickReference: [
|
|
3918
|
-
{
|
|
3979
|
+
{
|
|
3980
|
+
section: "write",
|
|
3981
|
+
usage: "assign <taskId>",
|
|
3982
|
+
description: "Assign or unassign users and groups"
|
|
3983
|
+
}
|
|
3919
3984
|
]
|
|
3920
3985
|
},
|
|
3921
3986
|
{
|
|
@@ -4310,6 +4375,18 @@ var commandMetadata = [
|
|
|
4310
4375
|
flags: ["--json"],
|
|
4311
4376
|
quickReference: [{ section: "read", usage: "members", description: "List workspace members" }]
|
|
4312
4377
|
},
|
|
4378
|
+
{
|
|
4379
|
+
name: "groups",
|
|
4380
|
+
description: "List user groups (teams) in your workspace",
|
|
4381
|
+
flags: ["--json"],
|
|
4382
|
+
quickReference: [
|
|
4383
|
+
{
|
|
4384
|
+
section: "read",
|
|
4385
|
+
usage: "groups",
|
|
4386
|
+
description: "List user groups (teams) in your workspace"
|
|
4387
|
+
}
|
|
4388
|
+
]
|
|
4389
|
+
},
|
|
4313
4390
|
{
|
|
4314
4391
|
name: "fields",
|
|
4315
4392
|
description: "List custom fields for a list",
|
|
@@ -7102,6 +7179,36 @@ function formatMembersMarkdown(members) {
|
|
|
7102
7179
|
return members.map((m) => `- **${m.username}** (${m.id}) - ${m.email}`).join("\n");
|
|
7103
7180
|
}
|
|
7104
7181
|
|
|
7182
|
+
// src/commands/groups.ts
|
|
7183
|
+
var GROUP_COLUMNS = [
|
|
7184
|
+
{ key: "handle", label: "Handle", maxWidth: 25 },
|
|
7185
|
+
{ key: "name", label: "Name", maxWidth: 30 },
|
|
7186
|
+
{ key: "id", label: "ID", maxWidth: 38 },
|
|
7187
|
+
{ key: "members", label: "Members", maxWidth: 8 }
|
|
7188
|
+
];
|
|
7189
|
+
async function listGroups(config) {
|
|
7190
|
+
const client = new ClickUpClient(config);
|
|
7191
|
+
return client.getGroups();
|
|
7192
|
+
}
|
|
7193
|
+
function formatGroupsTable(groups) {
|
|
7194
|
+
if (groups.length === 0) return "No groups found";
|
|
7195
|
+
const rows = groups.map((g) => ({
|
|
7196
|
+
handle: g.handle,
|
|
7197
|
+
name: g.name,
|
|
7198
|
+
id: g.id,
|
|
7199
|
+
members: String(g.members?.length ?? 0)
|
|
7200
|
+
}));
|
|
7201
|
+
return formatTable(rows, GROUP_COLUMNS);
|
|
7202
|
+
}
|
|
7203
|
+
function formatGroupsMarkdown(groups) {
|
|
7204
|
+
if (groups.length === 0) return "No groups found";
|
|
7205
|
+
return groups.map((g) => {
|
|
7206
|
+
const count = g.members?.length ?? 0;
|
|
7207
|
+
const label = count === 1 ? "1 member" : `${count} members`;
|
|
7208
|
+
return `- **@${g.handle}** ${g.name} (${g.id}) - ${label}`;
|
|
7209
|
+
}).join("\n");
|
|
7210
|
+
}
|
|
7211
|
+
|
|
7105
7212
|
// src/commands/fields.ts
|
|
7106
7213
|
import chalk16 from "chalk";
|
|
7107
7214
|
var FIELD_COLUMNS = [
|
|
@@ -8172,6 +8279,19 @@ function parseOptionalNumberOption(value, optionName) {
|
|
|
8172
8279
|
}
|
|
8173
8280
|
return parsed;
|
|
8174
8281
|
}
|
|
8282
|
+
function splitCommaList(value) {
|
|
8283
|
+
return value.split(",").map((v) => v.trim()).filter((v) => v.length > 0);
|
|
8284
|
+
}
|
|
8285
|
+
function createCachedGroupResolver(client) {
|
|
8286
|
+
let cache = null;
|
|
8287
|
+
const cachingClient = {
|
|
8288
|
+
getGroups: async () => {
|
|
8289
|
+
if (cache === null) cache = await client.getGroups();
|
|
8290
|
+
return cache;
|
|
8291
|
+
}
|
|
8292
|
+
};
|
|
8293
|
+
return (value) => resolveGroupId(cachingClient, value);
|
|
8294
|
+
}
|
|
8175
8295
|
function buildProgram(programName = basename(process.argv[1] ?? "cup")) {
|
|
8176
8296
|
const program = new Command();
|
|
8177
8297
|
program.name(programName).description("ClickUp CLI for AI agents").version(version).allowExcessArguments(false).option("-p, --profile <name>", "Use a specific profile");
|
|
@@ -8292,7 +8412,13 @@ function buildProgram(programName = basename(process.argv[1] ?? "cup")) {
|
|
|
8292
8412
|
).option(
|
|
8293
8413
|
"--time-estimate <duration>",
|
|
8294
8414
|
'Time estimate (e.g. "2h", "30m", "1h30m", "0" or "none" to clear)'
|
|
8295
|
-
).option("--assignee <userId>", 'Add assignee by user ID or "me"').option("--remove-assignee <userId>", 'Remove assignee by user ID or "me"').option(
|
|
8415
|
+
).option("--assignee <userId>", 'Add assignee by user ID or "me"').option("--remove-assignee <userId>", 'Remove assignee by user ID or "me"').option(
|
|
8416
|
+
"--group-assignee <groupIds...>",
|
|
8417
|
+
"Add group assignee (UUID or @handle, can repeat or comma-separated)"
|
|
8418
|
+
).option(
|
|
8419
|
+
"--remove-group-assignee <groupIds...>",
|
|
8420
|
+
"Remove group assignee (UUID or @handle, can repeat or comma-separated)"
|
|
8421
|
+
).option("--parent <taskId>", "Set parent task (makes this a subtask)").option("--detach", "Remove parent task (promote subtask to top-level)").option("--archive", "Archive the task").option("--unarchive", "Unarchive the task").option("--type <type>", "Change task type (name or custom_item_id)").option("--field <nameAndValue...>", 'Set custom field: --field "Name" value').option("--json", "Force JSON output even in terminal").action(
|
|
8296
8422
|
wrapAction(
|
|
8297
8423
|
async (taskId, opts) => {
|
|
8298
8424
|
const config = loadConfig(getProfileName());
|
|
@@ -8306,12 +8432,25 @@ function buildProgram(programName = basename(process.argv[1] ?? "cup")) {
|
|
|
8306
8432
|
opts.removeAssignee = String(id);
|
|
8307
8433
|
}) : Promise.resolve()
|
|
8308
8434
|
]);
|
|
8435
|
+
const groupAddRaw = (opts.groupAssignee ?? []).flatMap(splitCommaList);
|
|
8436
|
+
const groupRemRaw = (opts.removeGroupAssignee ?? []).flatMap(splitCommaList);
|
|
8437
|
+
if (groupAddRaw.length > 0 || groupRemRaw.length > 0) {
|
|
8438
|
+
const resolveGroup = createCachedGroupResolver(client);
|
|
8439
|
+
opts.groupAssigneeIds = [];
|
|
8440
|
+
for (const value of groupAddRaw) {
|
|
8441
|
+
opts.groupAssigneeIds.push(await resolveGroup(value));
|
|
8442
|
+
}
|
|
8443
|
+
opts.removeGroupAssigneeIds = [];
|
|
8444
|
+
for (const value of groupRemRaw) {
|
|
8445
|
+
opts.removeGroupAssigneeIds.push(await resolveGroup(value));
|
|
8446
|
+
}
|
|
8447
|
+
}
|
|
8309
8448
|
const payload = buildUpdatePayload(opts, timezone);
|
|
8310
8449
|
const hasFields = (opts.field?.length ?? 0) > 0;
|
|
8311
8450
|
const hasTypeName = opts.type !== void 0;
|
|
8312
8451
|
if (!hasFields && !hasTypeName && Object.keys(payload).length === 0) {
|
|
8313
8452
|
throw new Error(
|
|
8314
|
-
"Provide at least one of: --name, --description, --status, --priority, --due-date, --time-estimate, --assignee, --remove-assignee, --parent, --archive, --unarchive, --type, --field"
|
|
8453
|
+
"Provide at least one of: --name, --description, --status, --priority, --due-date, --time-estimate, --assignee, --remove-assignee, --group-assignee, --remove-group-assignee, --parent, --archive, --unarchive, --type, --field"
|
|
8315
8454
|
);
|
|
8316
8455
|
}
|
|
8317
8456
|
let result;
|
|
@@ -8345,49 +8484,62 @@ function buildProgram(programName = basename(process.argv[1] ?? "cup")) {
|
|
|
8345
8484
|
).option(
|
|
8346
8485
|
"--start-date <date>",
|
|
8347
8486
|
"Start date (YYYY-MM-DD, YYYY-MM-DDTHH:MM[:SS], or full ISO 8601 with offset)"
|
|
8348
|
-
).option("--assignee <userId>", 'Assignee user ID or "me"').option("--tags <tags>", "Comma-separated tag names").option("--custom-item-id <id>", "Custom task type ID (use to create initiatives)").option("--time-estimate <duration>", 'Time estimate (e.g. "2h", "30m", "1h30m")').option("--template <id>", "Create from a task template (find IDs with cup templates)").option("--field <nameAndValue...>", 'Set custom field: --field "Name" value (can repeat)').option("--json", "Force JSON output even in terminal").action(
|
|
8349
|
-
wrapAction(
|
|
8350
|
-
|
|
8351
|
-
|
|
8352
|
-
opts.list
|
|
8353
|
-
|
|
8354
|
-
if (opts.assignee === "me") {
|
|
8355
|
-
const client = new ClickUpClient(config);
|
|
8356
|
-
opts.assignee = String(await resolveAssigneeId(client, "me"));
|
|
8357
|
-
}
|
|
8358
|
-
if (opts.field?.length) {
|
|
8359
|
-
if (opts.field.length % 2 !== 0) {
|
|
8360
|
-
throw new Error('--field requires pairs: --field "Name" value');
|
|
8487
|
+
).option("--assignee <userId>", 'Assignee user ID or "me"').option("--group-assignee <groupIds>", "Group assignees (UUID or @handle, comma-separated)").option("--tags <tags>", "Comma-separated tag names").option("--custom-item-id <id>", "Custom task type ID (use to create initiatives)").option("--time-estimate <duration>", 'Time estimate (e.g. "2h", "30m", "1h30m")').option("--template <id>", "Create from a task template (find IDs with cup templates)").option("--field <nameAndValue...>", 'Set custom field: --field "Name" value (can repeat)').option("--json", "Force JSON output even in terminal").action(
|
|
8488
|
+
wrapAction(
|
|
8489
|
+
async (opts) => {
|
|
8490
|
+
const config = loadConfig(getProfileName());
|
|
8491
|
+
if (opts.list === "sprint:current") {
|
|
8492
|
+
opts.list = await resolveActiveSprintListId(config);
|
|
8361
8493
|
}
|
|
8362
|
-
|
|
8363
|
-
|
|
8364
|
-
|
|
8365
|
-
const parentTask = await client2.getTask(opts.parent);
|
|
8366
|
-
listId = parentTask.list.id;
|
|
8367
|
-
opts.list = listId;
|
|
8494
|
+
if (opts.assignee === "me") {
|
|
8495
|
+
const client = new ClickUpClient(config);
|
|
8496
|
+
opts.assignee = String(await resolveAssigneeId(client, "me"));
|
|
8368
8497
|
}
|
|
8369
|
-
if (
|
|
8370
|
-
|
|
8498
|
+
if (opts.groupAssignee !== void 0) {
|
|
8499
|
+
const rawList = splitCommaList(opts.groupAssignee);
|
|
8500
|
+
if (rawList.length > 0) {
|
|
8501
|
+
const client = new ClickUpClient(config);
|
|
8502
|
+
const resolveGroup = createCachedGroupResolver(client);
|
|
8503
|
+
opts.groupAssigneeIds = [];
|
|
8504
|
+
for (const value of rawList) {
|
|
8505
|
+
opts.groupAssigneeIds.push(await resolveGroup(value));
|
|
8506
|
+
}
|
|
8507
|
+
}
|
|
8371
8508
|
}
|
|
8372
|
-
|
|
8373
|
-
|
|
8374
|
-
|
|
8375
|
-
|
|
8376
|
-
|
|
8377
|
-
|
|
8378
|
-
|
|
8379
|
-
|
|
8380
|
-
|
|
8509
|
+
if (opts.field?.length) {
|
|
8510
|
+
if (opts.field.length % 2 !== 0) {
|
|
8511
|
+
throw new Error('--field requires pairs: --field "Name" value');
|
|
8512
|
+
}
|
|
8513
|
+
let listId = opts.list;
|
|
8514
|
+
if (!listId && opts.parent) {
|
|
8515
|
+
const client2 = new ClickUpClient(config);
|
|
8516
|
+
const parentTask = await client2.getTask(opts.parent);
|
|
8517
|
+
listId = parentTask.list.id;
|
|
8518
|
+
opts.list = listId;
|
|
8519
|
+
}
|
|
8520
|
+
if (!listId) {
|
|
8521
|
+
throw new Error("--field requires --list or --parent to resolve custom field names");
|
|
8522
|
+
}
|
|
8523
|
+
const client = new ClickUpClient(config);
|
|
8524
|
+
const fields = await client.getListCustomFields(listId);
|
|
8525
|
+
const customFields = [];
|
|
8526
|
+
for (let i = 0; i < opts.field.length; i += 2) {
|
|
8527
|
+
const fieldName = opts.field[i];
|
|
8528
|
+
const rawValue = opts.field[i + 1];
|
|
8529
|
+
const field = findFieldByName(fields, fieldName);
|
|
8530
|
+
const value = parseFieldValue(field, rawValue);
|
|
8531
|
+
customFields.push({ id: field.id, value });
|
|
8532
|
+
}
|
|
8533
|
+
opts.customFields = customFields;
|
|
8534
|
+
}
|
|
8535
|
+
const result = await createTask(config, opts);
|
|
8536
|
+
if (shouldOutputJson(opts.json ?? false)) {
|
|
8537
|
+
console.log(JSON.stringify(result, null, 2));
|
|
8538
|
+
} else {
|
|
8539
|
+
console.log(formatCreateConfirmation(result.id, result.name, result.url));
|
|
8381
8540
|
}
|
|
8382
|
-
opts.customFields = customFields;
|
|
8383
|
-
}
|
|
8384
|
-
const result = await createTask(config, opts);
|
|
8385
|
-
if (shouldOutputJson(opts.json ?? false)) {
|
|
8386
|
-
console.log(JSON.stringify(result, null, 2));
|
|
8387
|
-
} else {
|
|
8388
|
-
console.log(formatCreateConfirmation(result.id, result.name, result.url));
|
|
8389
8541
|
}
|
|
8390
|
-
|
|
8542
|
+
)
|
|
8391
8543
|
);
|
|
8392
8544
|
program.command("sprint").description("List my tasks in the current active sprint (auto-detected)").option("--status <status>", "Filter by status").option("--space <nameOrId>", "Narrow sprint search to a specific space (partial name or ID)").option("--folder <folderId>", "Sprint folder ID (overrides config and auto-detection)").option("--include-closed", "Include done/closed tasks").option("--json", "Force JSON output even in terminal").action(
|
|
8393
8545
|
wrapAction(
|
|
@@ -8664,16 +8816,25 @@ function buildProgram(programName = basename(process.argv[1] ?? "cup")) {
|
|
|
8664
8816
|
await printTasks(tasks, opts.json ?? false, config);
|
|
8665
8817
|
})
|
|
8666
8818
|
);
|
|
8667
|
-
program.command("assign <taskId>").description("Assign or unassign users from a task").option("--to <userId>", 'Add assignee (user ID or "me")').option("--remove <userId>", 'Remove assignee (user ID or "me")').option("--json", "Force JSON output even in terminal").action(
|
|
8668
|
-
wrapAction(
|
|
8669
|
-
|
|
8670
|
-
|
|
8671
|
-
|
|
8672
|
-
|
|
8673
|
-
|
|
8674
|
-
|
|
8819
|
+
program.command("assign <taskId>").description("Assign or unassign users and groups from a task").option("--to <userId>", 'Add assignee (user ID or "me", comma-separated)').option("--remove <userId>", 'Remove assignee (user ID or "me", comma-separated)').option("--group <groupIds>", "Add group assignee (UUID or @handle, comma-separated)").option("--remove-group <groupIds>", "Remove group assignee (UUID or @handle, comma-separated)").option("--json", "Force JSON output even in terminal").action(
|
|
8820
|
+
wrapAction(
|
|
8821
|
+
async (taskId, opts) => {
|
|
8822
|
+
const config = loadConfig(getProfileName());
|
|
8823
|
+
const result = await assignTask(config, taskId, opts);
|
|
8824
|
+
if (shouldOutputJson(opts.json ?? false)) {
|
|
8825
|
+
console.log(JSON.stringify(result, null, 2));
|
|
8826
|
+
} else {
|
|
8827
|
+
console.log(
|
|
8828
|
+
formatAssignConfirmation(taskId, {
|
|
8829
|
+
to: opts.to,
|
|
8830
|
+
remove: opts.remove,
|
|
8831
|
+
group: opts.group,
|
|
8832
|
+
removeGroup: opts.removeGroup
|
|
8833
|
+
})
|
|
8834
|
+
);
|
|
8835
|
+
}
|
|
8675
8836
|
}
|
|
8676
|
-
|
|
8837
|
+
)
|
|
8677
8838
|
);
|
|
8678
8839
|
program.command("depend <taskId>").description("Add or remove task dependencies").option("--on <taskId>", "Task that this task depends on (waiting on)").option("--blocks <taskId>", "Task that this task blocks").option("--remove", "Remove the dependency instead of adding it").option("--json", "Force JSON output even in terminal").action(
|
|
8679
8840
|
wrapAction(async (taskId, opts) => {
|
|
@@ -9125,6 +9286,19 @@ function buildProgram(programName = basename(process.argv[1] ?? "cup")) {
|
|
|
9125
9286
|
}
|
|
9126
9287
|
})
|
|
9127
9288
|
);
|
|
9289
|
+
program.command("groups").description("List user groups (teams) in your workspace").option("--json", "Force JSON output even in terminal").action(
|
|
9290
|
+
wrapAction(async (opts) => {
|
|
9291
|
+
const config = loadConfig(getProfileName());
|
|
9292
|
+
const groups = await listGroups(config);
|
|
9293
|
+
if (shouldOutputJson(opts.json ?? false)) {
|
|
9294
|
+
console.log(JSON.stringify(groups, null, 2));
|
|
9295
|
+
} else if (isTTY()) {
|
|
9296
|
+
console.log(formatGroupsTable(groups));
|
|
9297
|
+
} else {
|
|
9298
|
+
console.log(formatGroupsMarkdown(groups));
|
|
9299
|
+
}
|
|
9300
|
+
})
|
|
9301
|
+
);
|
|
9128
9302
|
program.command("fields <listId>").description("List custom fields for a list").option("--json", "Force JSON output even in terminal").action(
|
|
9129
9303
|
wrapAction(async (listId, opts) => {
|
|
9130
9304
|
const config = loadConfig(getProfileName());
|
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.31.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.31.0, update with `npm install -g @krodak/clickup-cli` and refresh this skill with `cup skill`.
|
|
11
11
|
|
|
12
12
|
## Install & Configure
|
|
13
13
|
|
|
@@ -126,6 +126,7 @@ All commands support `--help` for full flag details. All commands support `--jso
|
|
|
126
126
|
| `cup folders <spaceId> [--name partial] [--archived]` | Folders in a space (with their lists) |
|
|
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
|
+
| `cup groups` | User groups/teams (handle, name, UUID, member count) for `--group-assignee` flags |
|
|
129
130
|
| `cup fields <listId>` | Custom fields on a list (type, required, options) |
|
|
130
131
|
| `cup attachments <taskId>` | List attachments on a task (name, size, URL) |
|
|
131
132
|
| `cup task-members <taskId>` | List members with access to a task |
|
|
@@ -158,98 +159,98 @@ All commands support `--help` for full flag details. All commands support `--jso
|
|
|
158
159
|
|
|
159
160
|
### Write
|
|
160
161
|
|
|
161
|
-
| Command
|
|
162
|
-
|
|
|
163
|
-
| `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] [--tags t] [--custom-item-id n] [--template id] [--field "Name" val]`
|
|
164
|
-
| `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] [--parent id] [--detach] [--archive] [--unarchive] [--type type] [--field "Name" val]` | Update task fields (including custom fields)
|
|
165
|
-
| `cup comment <id> -m text [--notify-all]`
|
|
166
|
-
| `cup comment-edit <commentId> -m text [--resolved] [--unresolved]`
|
|
167
|
-
| `cup comment-delete <commentId>` or `cup comment-delete --task <taskId> --mine [--match text]`
|
|
168
|
-
| `cup replies <commentId>`
|
|
169
|
-
| `cup reply <commentId> -m text [--notify-all]`
|
|
170
|
-
| `cup assign <id> [--to ids\|me] [--remove ids\|me]`
|
|
171
|
-
| `cup depend <id> [--on taskId] [--blocks taskId] [--remove]`
|
|
172
|
-
| `cup move <id> [--to listId\|sprint:current] [--remove listId]`
|
|
173
|
-
| `cup field <id> [--set "Name" value] [--remove "Name"]`
|
|
174
|
-
| `cup field-create <name> -t <type> [-d desc] [--options "a,b,c"] [--required]`
|
|
175
|
-
| `cup tag <id> [--add tags] [--remove tags]`
|
|
176
|
-
| `cup link <taskId> <linksTo> [--remove]`
|
|
177
|
-
| `cup attach <taskId> <filePath>`
|
|
178
|
-
| `cup delete <id> [--confirm]`
|
|
179
|
-
| `cup list-delete <listId> [--confirm]`
|
|
180
|
-
| `cup folder-delete <folderId> [--confirm]`
|
|
181
|
-
| `cup space-delete <spaceId> [--confirm]`
|
|
182
|
-
| `cup duplicate <taskId>`
|
|
183
|
-
| `cup bulk status <status> <taskIds...>`
|
|
184
|
-
| `cup bulk assign <taskIds...> [--to userId\|me] [--remove userId\|me]`
|
|
185
|
-
| `cup bulk due-date <date\|none\|clear> <taskIds...>`
|
|
186
|
-
| `cup bulk tag <tagName> <taskIds...> [--remove]`
|
|
187
|
-
| `cup bulk priority <taskIds...> --to <priority>`
|
|
188
|
-
| `cup bulk field <taskIds...> --set "Name" value`
|
|
189
|
-
| `cup bulk move <taskIds...> --to <listId>`
|
|
190
|
-
| `cup checklist view <id>`
|
|
191
|
-
| `cup checklist create <id> <name>`
|
|
192
|
-
| `cup checklist delete <checklistId>`
|
|
193
|
-
| `cup checklist add-item <checklistId> <name> [--parent itemId]`
|
|
194
|
-
| `cup checklist edit-item <checklistId> <itemId> [--name n] [--resolved] [--unresolved] [--assignee id] [--parent itemId\|null]`
|
|
195
|
-
| `cup checklist delete-item <checklistId> <itemId>`
|
|
196
|
-
| `cup time start <taskId> [-d desc]`
|
|
197
|
-
| `cup time stop`
|
|
198
|
-
| `cup time status`
|
|
199
|
-
| `cup time log <taskId> <duration> [-d desc]`
|
|
200
|
-
| `cup time list [--days n] [--task id] [--all]`
|
|
201
|
-
| `cup time update <timeEntryId> [-d desc] [--duration dur]`
|
|
202
|
-
| `cup time delete <timeEntryId>`
|
|
203
|
-
| `cup goal-create <name> [-d desc] [--color hex]`
|
|
204
|
-
| `cup goal-update <goalId> [-n name] [-d desc] [--color hex]`
|
|
205
|
-
| `cup goal-delete <goalId>`
|
|
206
|
-
| `cup key-result-create <goalId> <name> [--type t] [--target n]`
|
|
207
|
-
| `cup key-result-update <keyResultId> [--progress n] [--note text]`
|
|
208
|
-
| `cup key-result-delete <keyResultId>`
|
|
209
|
-
| `cup doc-create <title> [-c content]`
|
|
210
|
-
| `cup doc-page-create <docId> <name> [-c content] [--parent-page pageId]`
|
|
211
|
-
| `cup doc-page-edit <docId> <pageId> [--name text] [-c content]`
|
|
212
|
-
| `cup doc-delete <docId>`
|
|
213
|
-
| `cup doc-page-delete <docId> <pageId>`
|
|
214
|
-
| `cup space-create <name>`
|
|
215
|
-
| `cup list-create <spaceId> <name> [--folder folderId] [--copy-statuses-from id]`
|
|
216
|
-
| `cup folder-create <spaceId> <name>`
|
|
217
|
-
| `cup list-rename <listId> <newName>`
|
|
218
|
-
| `cup folder-rename <folderId> <newName>`
|
|
219
|
-
| `cup space-rename <spaceId> <newName>`
|
|
220
|
-
| `cup tag-create <spaceId> <name> [--fg color] [--bg color]`
|
|
221
|
-
| `cup tag-update <spaceId> <tagName> --name <newName> [--fg c] [--bg c]`
|
|
222
|
-
| `cup tag-delete <spaceId> <name>`
|
|
223
|
-
| `cup list-from-template <name> --template <id> [--space id] [--folder id]`
|
|
224
|
-
| `cup view-create <listId> <name> -t <type> [--group-by field]`
|
|
225
|
-
| `cup view-update <viewId> [-n name] [--group-by field]`
|
|
226
|
-
| `cup view-delete <viewId> [--confirm]`
|
|
227
|
-
| `cup list-comment <listId> -m text [--notify-all]`
|
|
228
|
-
| `cup view-comment <viewId> -m text [--notify-all]`
|
|
229
|
-
| `cup webhook create --url <url> --events <events> [--space\|--folder\|--list\|--task <id>]`
|
|
230
|
-
| `cup webhook update <webhookId> [--url u] [--events e] [--status s]`
|
|
231
|
-
| `cup webhook delete <webhookId> [--confirm]`
|
|
232
|
-
| `cup merge <sourceTaskId> <intoTaskId> [--confirm]`
|
|
233
|
-
| `cup time estimate-by-user <taskId> <userId> <duration> [--replace]`
|
|
234
|
-
| `cup chat send <channelId> -m <text> [--post --title t]`
|
|
235
|
-
| `cup chat reply <messageId> -m <text>`
|
|
236
|
-
| `cup chat react <messageId> --emoji <name>`
|
|
237
|
-
| `cup chat unreact <messageId> --emoji <name>`
|
|
238
|
-
| `cup chat channel-create <name> [--private] [--topic t]`
|
|
239
|
-
| `cup chat dm <userIds...>`
|
|
240
|
-
| `cup chat channel-update <id> [--name n] [--topic t]`
|
|
241
|
-
| `cup chat channel-delete <id> [--confirm]`
|
|
242
|
-
| `cup chat message-update <messageId> -m <text>`
|
|
243
|
-
| `cup chat message-delete <messageId> [--confirm]`
|
|
244
|
-
| `cup favorite add <type> <id> [alias] [-n name]`
|
|
245
|
-
| `cup favorite remove <alias>`
|
|
246
|
-
| `cup favorite list [--type t]`
|
|
247
|
-
| `cup profile list [--json]`
|
|
248
|
-
| `cup profile add <name>`
|
|
249
|
-
| `cup profile remove <name>`
|
|
250
|
-
| `cup profile use <name>`
|
|
251
|
-
| `cup config get <key>` / `set <key> <value>` / `path`
|
|
252
|
-
| `cup completion <shell>`
|
|
162
|
+
| Command | What it does |
|
|
163
|
+
| ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------ |
|
|
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
|
+
| `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) |
|
|
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
|
+
| `cup replies <commentId>` | List threaded replies |
|
|
170
|
+
| `cup reply <commentId> -m text [--notify-all]` | Reply to a comment (markdown auto-converted to rich text) |
|
|
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
|
+
| `cup depend <id> [--on taskId] [--blocks taskId] [--remove]` | Add/remove dependencies |
|
|
173
|
+
| `cup move <id> [--to listId\|sprint:current] [--remove listId]` | Add/remove task from lists (`--to` accepts `sprint:current`) |
|
|
174
|
+
| `cup field <id> [--set "Name" value] [--remove "Name"]` | Set/remove custom field values |
|
|
175
|
+
| `cup field-create <name> -t <type> [-d desc] [--options "a,b,c"] [--required]` | Create a custom field |
|
|
176
|
+
| `cup tag <id> [--add tags] [--remove tags]` | Add/remove tags on a task |
|
|
177
|
+
| `cup link <taskId> <linksTo> [--remove]` | Link/unlink tasks |
|
|
178
|
+
| `cup attach <taskId> <filePath>` | Upload file attachment |
|
|
179
|
+
| `cup delete <id> [--confirm]` | Delete task (DESTRUCTIVE) |
|
|
180
|
+
| `cup list-delete <listId> [--confirm]` | Delete list (DESTRUCTIVE, requires --confirm in non-interactive) |
|
|
181
|
+
| `cup folder-delete <folderId> [--confirm]` | Delete folder (DESTRUCTIVE, requires --confirm in non-interactive) |
|
|
182
|
+
| `cup space-delete <spaceId> [--confirm]` | Delete space (DESTRUCTIVE, requires --confirm in non-interactive) |
|
|
183
|
+
| `cup duplicate <taskId>` | Duplicate a task |
|
|
184
|
+
| `cup bulk status <status> <taskIds...>` | Bulk update status |
|
|
185
|
+
| `cup bulk assign <taskIds...> [--to userId\|me] [--remove userId\|me]` | Bulk assign/unassign user from tasks |
|
|
186
|
+
| `cup bulk due-date <date\|none\|clear> <taskIds...>` | Bulk set or clear due dates |
|
|
187
|
+
| `cup bulk tag <tagName> <taskIds...> [--remove]` | Bulk add/remove tag from tasks |
|
|
188
|
+
| `cup bulk priority <taskIds...> --to <priority>` | Bulk set priority on many tasks |
|
|
189
|
+
| `cup bulk field <taskIds...> --set "Name" value` | Bulk set a custom field value |
|
|
190
|
+
| `cup bulk move <taskIds...> --to <listId>` | Bulk move tasks to a destination list |
|
|
191
|
+
| `cup checklist view <id>` | View checklists on a task |
|
|
192
|
+
| `cup checklist create <id> <name>` | Create a checklist |
|
|
193
|
+
| `cup checklist delete <checklistId>` | Delete a checklist |
|
|
194
|
+
| `cup checklist add-item <checklistId> <name> [--parent itemId]` | Add item to checklist (nest under parent via `--parent`) |
|
|
195
|
+
| `cup checklist edit-item <checklistId> <itemId> [--name n] [--resolved] [--unresolved] [--assignee id] [--parent itemId\|null]` | Edit checklist item (reparent with `--parent`, use `"null"` to unnest) |
|
|
196
|
+
| `cup checklist delete-item <checklistId> <itemId>` | Delete checklist item |
|
|
197
|
+
| `cup time start <taskId> [-d desc]` | Start timer |
|
|
198
|
+
| `cup time stop` | Stop running timer |
|
|
199
|
+
| `cup time status` | Show running timer |
|
|
200
|
+
| `cup time log <taskId> <duration> [-d desc]` | Log manual entry (e.g. "2h", "30m") |
|
|
201
|
+
| `cup time list [--days n] [--task id] [--all]` | List my recent time entries (--all for team) |
|
|
202
|
+
| `cup time update <timeEntryId> [-d desc] [--duration dur]` | Update time entry |
|
|
203
|
+
| `cup time delete <timeEntryId>` | Delete time entry |
|
|
204
|
+
| `cup goal-create <name> [-d desc] [--color hex]` | Create a goal |
|
|
205
|
+
| `cup goal-update <goalId> [-n name] [-d desc] [--color hex]` | Update a goal |
|
|
206
|
+
| `cup goal-delete <goalId>` | Delete a goal |
|
|
207
|
+
| `cup key-result-create <goalId> <name> [--type t] [--target n]` | Create key result |
|
|
208
|
+
| `cup key-result-update <keyResultId> [--progress n] [--note text]` | Update key result |
|
|
209
|
+
| `cup key-result-delete <keyResultId>` | Delete key result |
|
|
210
|
+
| `cup doc-create <title> [-c content]` | Create a doc |
|
|
211
|
+
| `cup doc-page-create <docId> <name> [-c content] [--parent-page pageId]` | Create doc page |
|
|
212
|
+
| `cup doc-page-edit <docId> <pageId> [--name text] [-c content]` | Edit doc page |
|
|
213
|
+
| `cup doc-delete <docId>` | Delete a doc |
|
|
214
|
+
| `cup doc-page-delete <docId> <pageId>` | Delete doc page |
|
|
215
|
+
| `cup space-create <name>` | Create a space |
|
|
216
|
+
| `cup list-create <spaceId> <name> [--folder folderId] [--copy-statuses-from id]` | Create a list in a space or folder |
|
|
217
|
+
| `cup folder-create <spaceId> <name>` | Create a folder in a space |
|
|
218
|
+
| `cup list-rename <listId> <newName>` | Rename a list |
|
|
219
|
+
| `cup folder-rename <folderId> <newName>` | Rename a folder |
|
|
220
|
+
| `cup space-rename <spaceId> <newName>` | Rename a space |
|
|
221
|
+
| `cup tag-create <spaceId> <name> [--fg color] [--bg color]` | Create space tag |
|
|
222
|
+
| `cup tag-update <spaceId> <tagName> --name <newName> [--fg c] [--bg c]` | Update space tag |
|
|
223
|
+
| `cup tag-delete <spaceId> <name>` | Delete space tag |
|
|
224
|
+
| `cup list-from-template <name> --template <id> [--space id] [--folder id]` | Create list from template |
|
|
225
|
+
| `cup view-create <listId> <name> -t <type> [--group-by field]` | Create a view on a list |
|
|
226
|
+
| `cup view-update <viewId> [-n name] [--group-by field]` | Update a view |
|
|
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 |
|
|
230
|
+
| `cup webhook create --url <url> --events <events> [--space\|--folder\|--list\|--task <id>]` | Create a webhook |
|
|
231
|
+
| `cup webhook update <webhookId> [--url u] [--events e] [--status s]` | Update a webhook |
|
|
232
|
+
| `cup webhook delete <webhookId> [--confirm]` | Delete a webhook (DESTRUCTIVE) |
|
|
233
|
+
| `cup merge <sourceTaskId> <intoTaskId> [--confirm]` | Merge task into another (DESTRUCTIVE, source deleted) |
|
|
234
|
+
| `cup time estimate-by-user <taskId> <userId> <duration> [--replace]` | Set per-user time estimate |
|
|
235
|
+
| `cup chat send <channelId> -m <text> [--post --title t]` | Send message to channel |
|
|
236
|
+
| `cup chat reply <messageId> -m <text>` | Reply to a message |
|
|
237
|
+
| `cup chat react <messageId> --emoji <name>` | Add reaction |
|
|
238
|
+
| `cup chat unreact <messageId> --emoji <name>` | Remove reaction |
|
|
239
|
+
| `cup chat channel-create <name> [--private] [--topic t]` | Create channel |
|
|
240
|
+
| `cup chat dm <userIds...>` | Create/open DM |
|
|
241
|
+
| `cup chat channel-update <id> [--name n] [--topic t]` | Update channel |
|
|
242
|
+
| `cup chat channel-delete <id> [--confirm]` | Delete channel |
|
|
243
|
+
| `cup chat message-update <messageId> -m <text>` | Edit message |
|
|
244
|
+
| `cup chat message-delete <messageId> [--confirm]` | Delete message |
|
|
245
|
+
| `cup favorite add <type> <id> [alias] [-n name]` | Add a local favorite |
|
|
246
|
+
| `cup favorite remove <alias>` | Remove a favorite |
|
|
247
|
+
| `cup favorite list [--type t]` | List favorites (optionally filter by type) |
|
|
248
|
+
| `cup profile list [--json]` | List all profiles |
|
|
249
|
+
| `cup profile add <name>` | Add a new profile (interactive) |
|
|
250
|
+
| `cup profile remove <name>` | Remove a profile |
|
|
251
|
+
| `cup profile use <name>` | Set the default profile |
|
|
252
|
+
| `cup config get <key>` / `set <key> <value>` / `path` | Manage config |
|
|
253
|
+
| `cup completion <shell>` | Shell completions (bash/zsh/fish) |
|
|
253
254
|
|
|
254
255
|
## Global Flags
|
|
255
256
|
|
|
@@ -351,6 +352,10 @@ cup comment abc123def -m "Completed in PR #42"
|
|
|
351
352
|
cup comment abc123def -m "## Results\n\n**Passed**: 15/15\n- Unit tests\n- Integration"
|
|
352
353
|
cup assign abc123def --to me
|
|
353
354
|
cup assign abc123def --to 12345,67890 # assign multiple users at once
|
|
355
|
+
cup assign abc123def --group @mobile-team # assign a user group (find handles with `cup groups`)
|
|
356
|
+
cup assign abc123def --to me --group @backend # assign self and a group together
|
|
357
|
+
cup update abc123def --group-assignee @mobile-team # group assignment via update
|
|
358
|
+
cup update abc123def --remove-group-assignee @backend
|
|
354
359
|
cup depend task3 --on task2 # task3 waits for task2
|
|
355
360
|
cup move task1 --to list2 --remove list1
|
|
356
361
|
cup move task1 --to sprint:current # move to active sprint
|
|
@@ -393,6 +398,7 @@ cup space-rename <spaceId> "Platform" # rename a space
|
|
|
393
398
|
cup folder-rename <folderId> "Q3" # rename a folder
|
|
394
399
|
cup list-rename <listId> "Sprint 12" # rename a list
|
|
395
400
|
cup members # workspace members
|
|
401
|
+
cup groups # user groups/teams (for --group-assignee)
|
|
396
402
|
cup fields <listId> # custom fields on a list
|
|
397
403
|
cup task-types # custom task types
|
|
398
404
|
cup templates # task templates
|