@krodak/clickup-cli 1.14.2 → 1.16.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/dist/index.js +569 -65
- package/package.json +1 -1
- package/skills/clickup-cli/SKILL.md +79 -61
|
@@ -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.16.0",
|
|
5
5
|
"author": {
|
|
6
6
|
"name": "Krzysztof Rodak"
|
|
7
7
|
},
|
package/dist/index.js
CHANGED
|
@@ -258,6 +258,12 @@ var ClickUpClient = class {
|
|
|
258
258
|
body: JSON.stringify({ name })
|
|
259
259
|
});
|
|
260
260
|
}
|
|
261
|
+
async updateList(listId, payload) {
|
|
262
|
+
return this.request(`/list/${listId}`, {
|
|
263
|
+
method: "PUT",
|
|
264
|
+
body: JSON.stringify(payload)
|
|
265
|
+
});
|
|
266
|
+
}
|
|
261
267
|
async createFolder(spaceId, name) {
|
|
262
268
|
return this.request(`/space/${spaceId}/folder`, {
|
|
263
269
|
method: "POST",
|
|
@@ -281,6 +287,18 @@ var ClickUpClient = class {
|
|
|
281
287
|
async getListViews(listId) {
|
|
282
288
|
return this.request(`/list/${listId}/view`);
|
|
283
289
|
}
|
|
290
|
+
async getSpaceViews(spaceId) {
|
|
291
|
+
const data = await this.request(`/space/${spaceId}/view`);
|
|
292
|
+
return readCollectionField(data, "views", "views");
|
|
293
|
+
}
|
|
294
|
+
async getFolderViews(folderId) {
|
|
295
|
+
const data = await this.request(`/folder/${folderId}/view`);
|
|
296
|
+
return readCollectionField(data, "views", "views");
|
|
297
|
+
}
|
|
298
|
+
async getWorkspaceViews(teamId) {
|
|
299
|
+
const data = await this.request(`/team/${teamId}/view`);
|
|
300
|
+
return readCollectionField(data, "views", "views");
|
|
301
|
+
}
|
|
284
302
|
async getViewTasks(viewId) {
|
|
285
303
|
return this.paginate((page) => `/view/${viewId}/task?page=${page}`);
|
|
286
304
|
}
|
|
@@ -510,6 +528,9 @@ var ClickUpClient = class {
|
|
|
510
528
|
const params = new URLSearchParams();
|
|
511
529
|
if (opts?.startDate != null) params.set("start_date", String(opts.startDate));
|
|
512
530
|
if (opts?.endDate != null) params.set("end_date", String(opts.endDate));
|
|
531
|
+
if (opts?.spaceId) params.set("space_id", opts.spaceId);
|
|
532
|
+
if (opts?.listId) params.set("list_id", opts.listId);
|
|
533
|
+
if (opts?.assigneeId) params.set("assignee", opts.assigneeId);
|
|
513
534
|
const query = params.toString();
|
|
514
535
|
const url = `/team/${teamId}/time_entries${query ? `?${query}` : ""}`;
|
|
515
536
|
const data = await this.request(url);
|
|
@@ -877,6 +898,7 @@ function migrateToMultiProfile(parsed, filePath) {
|
|
|
877
898
|
if (typeof value.teamId === "string" && value.teamId.trim()) p.teamId = value.teamId.trim();
|
|
878
899
|
if (typeof value.sprintFolderId === "string" && value.sprintFolderId.trim())
|
|
879
900
|
p.sprintFolderId = value.sprintFolderId.trim();
|
|
901
|
+
if (isRecord2(value.filters)) p.filters = value.filters;
|
|
880
902
|
profiles[name] = p;
|
|
881
903
|
}
|
|
882
904
|
}
|
|
@@ -1064,6 +1086,33 @@ function getConfigPath() {
|
|
|
1064
1086
|
migrateFromLegacy();
|
|
1065
1087
|
return configPath();
|
|
1066
1088
|
}
|
|
1089
|
+
function getFilters(profileName) {
|
|
1090
|
+
const multi = loadMultiProfileConfig();
|
|
1091
|
+
const name = profileName ?? process.env.CU_PROFILE?.trim() ?? multi.defaultProfile;
|
|
1092
|
+
const profile = name ? multi.profiles[name] ?? {} : {};
|
|
1093
|
+
return profile.filters ?? {};
|
|
1094
|
+
}
|
|
1095
|
+
function saveFilter(name, entry, profileName) {
|
|
1096
|
+
const multi = loadMultiProfileConfig();
|
|
1097
|
+
const pName = profileName ?? process.env.CU_PROFILE?.trim() ?? multi.defaultProfile ?? "default";
|
|
1098
|
+
const profile = multi.profiles[pName] ?? {};
|
|
1099
|
+
const filters = { ...profile.filters ?? {}, [name]: entry };
|
|
1100
|
+
multi.profiles[pName] = { ...profile, filters };
|
|
1101
|
+
if (!multi.defaultProfile) multi.defaultProfile = pName;
|
|
1102
|
+
saveMultiProfileConfig(multi);
|
|
1103
|
+
}
|
|
1104
|
+
function deleteFilter(name, profileName) {
|
|
1105
|
+
const multi = loadMultiProfileConfig();
|
|
1106
|
+
const pName = profileName ?? process.env.CU_PROFILE?.trim() ?? multi.defaultProfile ?? "default";
|
|
1107
|
+
const profile = multi.profiles[pName] ?? {};
|
|
1108
|
+
const filters = { ...profile.filters ?? {} };
|
|
1109
|
+
if (!(name in filters)) {
|
|
1110
|
+
throw new Error(`Filter "${name}" not found.`);
|
|
1111
|
+
}
|
|
1112
|
+
delete filters[name];
|
|
1113
|
+
multi.profiles[pName] = { ...profile, filters };
|
|
1114
|
+
saveMultiProfileConfig(multi);
|
|
1115
|
+
}
|
|
1067
1116
|
function writeConfig(config, profileName) {
|
|
1068
1117
|
const multi = loadMultiProfileConfig();
|
|
1069
1118
|
const name = profileName || multi.defaultProfile || "default";
|
|
@@ -1716,6 +1765,9 @@ function buildUpdatePayload(opts) {
|
|
|
1716
1765
|
if (opts.archive && opts.unarchive) {
|
|
1717
1766
|
throw new Error("Cannot use --archive and --unarchive together");
|
|
1718
1767
|
}
|
|
1768
|
+
if (opts.parent !== void 0 && opts.detach) {
|
|
1769
|
+
throw new Error("Cannot use --parent and --detach together");
|
|
1770
|
+
}
|
|
1719
1771
|
const payload = {};
|
|
1720
1772
|
if (opts.name !== void 0) {
|
|
1721
1773
|
if (!opts.name.trim()) throw new Error("Task name cannot be empty");
|
|
@@ -1725,22 +1777,40 @@ function buildUpdatePayload(opts) {
|
|
|
1725
1777
|
if (opts.status !== void 0) payload.status = opts.status;
|
|
1726
1778
|
if (opts.priority !== void 0) payload.priority = parsePriority(opts.priority);
|
|
1727
1779
|
if (opts.dueDate !== void 0) {
|
|
1728
|
-
|
|
1729
|
-
|
|
1780
|
+
if (opts.dueDate === "none" || opts.dueDate === "clear") {
|
|
1781
|
+
payload.due_date = null;
|
|
1782
|
+
} else {
|
|
1783
|
+
payload.due_date = parseDueDate(opts.dueDate);
|
|
1784
|
+
payload.due_date_time = false;
|
|
1785
|
+
}
|
|
1786
|
+
}
|
|
1787
|
+
if (opts.startDate !== void 0) {
|
|
1788
|
+
payload.start_date = parseDueDate(opts.startDate);
|
|
1789
|
+
payload.start_date_time = false;
|
|
1730
1790
|
}
|
|
1731
|
-
if (opts.assignee !== void 0) {
|
|
1732
|
-
payload.assignees = {
|
|
1791
|
+
if (opts.assignee !== void 0 || opts.removeAssignee !== void 0) {
|
|
1792
|
+
payload.assignees = {};
|
|
1793
|
+
if (opts.assignee !== void 0) {
|
|
1794
|
+
payload.assignees.add = [parseAssigneeId(opts.assignee)];
|
|
1795
|
+
}
|
|
1796
|
+
if (opts.removeAssignee !== void 0) {
|
|
1797
|
+
payload.assignees.rem = [parseAssigneeId(opts.removeAssignee)];
|
|
1798
|
+
}
|
|
1733
1799
|
}
|
|
1734
1800
|
if (opts.timeEstimate !== void 0) {
|
|
1735
1801
|
payload.time_estimate = parseTimeEstimate(opts.timeEstimate);
|
|
1736
1802
|
}
|
|
1737
|
-
if (opts.
|
|
1803
|
+
if (opts.detach) {
|
|
1804
|
+
payload.parent = null;
|
|
1805
|
+
} else if (opts.parent !== void 0) {
|
|
1806
|
+
payload.parent = opts.parent;
|
|
1807
|
+
}
|
|
1738
1808
|
if (opts.archive) payload.archived = true;
|
|
1739
1809
|
if (opts.unarchive) payload.archived = false;
|
|
1740
1810
|
return payload;
|
|
1741
1811
|
}
|
|
1742
1812
|
function hasUpdateFields(options) {
|
|
1743
|
-
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.time_estimate !== void 0 || options.assignees !== void 0 || options.parent !== void 0 || options.archived !== void 0;
|
|
1813
|
+
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;
|
|
1744
1814
|
}
|
|
1745
1815
|
async function resolveStatus(client, taskId, statusInput) {
|
|
1746
1816
|
const task = await client.getTask(taskId);
|
|
@@ -1759,7 +1829,7 @@ async function resolveStatus(client, taskId, statusInput) {
|
|
|
1759
1829
|
async function updateTask(config, taskId, options) {
|
|
1760
1830
|
if (!hasUpdateFields(options))
|
|
1761
1831
|
throw new Error(
|
|
1762
|
-
"Provide at least one of: --name, --description, --status, --priority, --due-date, --time-estimate, --assignee, --parent, --archive, --unarchive"
|
|
1832
|
+
"Provide at least one of: --name, --description, --status, --priority, --due-date, --start-date, --time-estimate, --assignee, --remove-assignee, --parent, --detach, --archive, --unarchive"
|
|
1763
1833
|
);
|
|
1764
1834
|
const client = new ClickUpClient(config);
|
|
1765
1835
|
if (options.status !== void 0) {
|
|
@@ -1798,6 +1868,10 @@ async function createTask(config, options) {
|
|
|
1798
1868
|
payload.due_date = parseDueDate(options.dueDate);
|
|
1799
1869
|
payload.due_date_time = false;
|
|
1800
1870
|
}
|
|
1871
|
+
if (options.startDate !== void 0) {
|
|
1872
|
+
payload.start_date = parseDueDate(options.startDate);
|
|
1873
|
+
payload.start_date_time = false;
|
|
1874
|
+
}
|
|
1801
1875
|
if (options.assignee !== void 0) {
|
|
1802
1876
|
payload.assignees = [parseAssigneeId(options.assignee)];
|
|
1803
1877
|
}
|
|
@@ -2596,7 +2670,11 @@ async function fetchOverdueTasks(config, opts = {}) {
|
|
|
2596
2670
|
}
|
|
2597
2671
|
|
|
2598
2672
|
// src/commands/config.ts
|
|
2599
|
-
var VALID_KEYS = /* @__PURE__ */ new Set([
|
|
2673
|
+
var VALID_KEYS = /* @__PURE__ */ new Set([
|
|
2674
|
+
"apiToken",
|
|
2675
|
+
"teamId",
|
|
2676
|
+
"sprintFolderId"
|
|
2677
|
+
]);
|
|
2600
2678
|
function readStoredString(value) {
|
|
2601
2679
|
if (typeof value !== "string") return void 0;
|
|
2602
2680
|
const trimmed = value.trim();
|
|
@@ -2765,9 +2843,12 @@ var commandMetadata = [
|
|
|
2765
2843
|
"--status",
|
|
2766
2844
|
"--priority",
|
|
2767
2845
|
"--due-date",
|
|
2846
|
+
"--start-date",
|
|
2768
2847
|
"--time-estimate",
|
|
2769
2848
|
"--assignee",
|
|
2849
|
+
"--remove-assignee",
|
|
2770
2850
|
"--parent",
|
|
2851
|
+
"--detach",
|
|
2771
2852
|
"--archive",
|
|
2772
2853
|
"--unarchive",
|
|
2773
2854
|
"--field",
|
|
@@ -2791,6 +2872,7 @@ var commandMetadata = [
|
|
|
2791
2872
|
"--status",
|
|
2792
2873
|
"--priority",
|
|
2793
2874
|
"--due-date",
|
|
2875
|
+
"--start-date",
|
|
2794
2876
|
"--assignee",
|
|
2795
2877
|
"--tags",
|
|
2796
2878
|
"--custom-item-id",
|
|
@@ -3114,7 +3196,11 @@ var commandMetadata = [
|
|
|
3114
3196
|
usage: "time log <taskId> <duration>",
|
|
3115
3197
|
description: "Log a manual time entry"
|
|
3116
3198
|
},
|
|
3117
|
-
{
|
|
3199
|
+
{
|
|
3200
|
+
section: "write",
|
|
3201
|
+
usage: "time list",
|
|
3202
|
+
description: "List my recent time entries (--all for team)"
|
|
3203
|
+
},
|
|
3118
3204
|
{ section: "write", usage: "time update <timeEntryId>", description: "Update a time entry" },
|
|
3119
3205
|
{ section: "write", usage: "time delete <timeEntryId>", description: "Delete a time entry" }
|
|
3120
3206
|
]
|
|
@@ -3218,7 +3304,7 @@ var commandMetadata = [
|
|
|
3218
3304
|
{
|
|
3219
3305
|
name: "list-create",
|
|
3220
3306
|
description: "Create a new list in a space",
|
|
3221
|
-
flags: ["--folder", "--json"],
|
|
3307
|
+
flags: ["--folder", "--copy-statuses-from", "--json"],
|
|
3222
3308
|
quickReference: [
|
|
3223
3309
|
{
|
|
3224
3310
|
section: "write",
|
|
@@ -3281,6 +3367,21 @@ var commandMetadata = [
|
|
|
3281
3367
|
section: "write",
|
|
3282
3368
|
usage: "bulk status <status> <taskIds...>",
|
|
3283
3369
|
description: "Bulk update task status"
|
|
3370
|
+
},
|
|
3371
|
+
{
|
|
3372
|
+
section: "write",
|
|
3373
|
+
usage: "bulk assign <taskIds...>",
|
|
3374
|
+
description: "Bulk assign user to tasks"
|
|
3375
|
+
},
|
|
3376
|
+
{
|
|
3377
|
+
section: "write",
|
|
3378
|
+
usage: "bulk due-date <date> <taskIds...>",
|
|
3379
|
+
description: "Bulk set due date"
|
|
3380
|
+
},
|
|
3381
|
+
{
|
|
3382
|
+
section: "write",
|
|
3383
|
+
usage: "bulk tag <tagName> <taskIds...>",
|
|
3384
|
+
description: "Bulk add/remove tag"
|
|
3284
3385
|
}
|
|
3285
3386
|
]
|
|
3286
3387
|
},
|
|
@@ -3295,7 +3396,7 @@ var commandMetadata = [
|
|
|
3295
3396
|
{
|
|
3296
3397
|
name: "goal-create",
|
|
3297
3398
|
description: "Create a goal",
|
|
3298
|
-
flags: ["-d", "--description", "--color", "--json"],
|
|
3399
|
+
flags: ["-d", "--description", "--color", "--due-date", "--json"],
|
|
3299
3400
|
quickReference: [
|
|
3300
3401
|
{ section: "write", usage: "goal-create <name>", description: "Create a goal" }
|
|
3301
3402
|
]
|
|
@@ -3408,10 +3509,14 @@ var commandMetadata = [
|
|
|
3408
3509
|
},
|
|
3409
3510
|
{
|
|
3410
3511
|
name: "views",
|
|
3411
|
-
description: "List views on a list",
|
|
3412
|
-
flags: ["--json"],
|
|
3512
|
+
description: "List views on a list, space, folder, or workspace",
|
|
3513
|
+
flags: ["--space", "--folder", "--workspace", "--json"],
|
|
3413
3514
|
quickReference: [
|
|
3414
|
-
{
|
|
3515
|
+
{
|
|
3516
|
+
section: "read",
|
|
3517
|
+
usage: "views <id>",
|
|
3518
|
+
description: "List views on a list, space, folder, or workspace"
|
|
3519
|
+
}
|
|
3415
3520
|
]
|
|
3416
3521
|
},
|
|
3417
3522
|
{
|
|
@@ -3448,6 +3553,19 @@ var commandMetadata = [
|
|
|
3448
3553
|
{ section: "write", usage: "view-delete <viewId>", description: "Delete a view" }
|
|
3449
3554
|
]
|
|
3450
3555
|
},
|
|
3556
|
+
{
|
|
3557
|
+
name: "filter",
|
|
3558
|
+
description: "Manage saved command shortcuts",
|
|
3559
|
+
quickReference: [
|
|
3560
|
+
{
|
|
3561
|
+
section: "setup",
|
|
3562
|
+
usage: "filter save <name> [args...]",
|
|
3563
|
+
description: "Save a command shortcut"
|
|
3564
|
+
},
|
|
3565
|
+
{ section: "read", usage: "filter list", description: "List saved shortcuts" },
|
|
3566
|
+
{ section: "read", usage: "filter run <name>", description: "Run a saved shortcut" }
|
|
3567
|
+
]
|
|
3568
|
+
},
|
|
3451
3569
|
{
|
|
3452
3570
|
name: "profile",
|
|
3453
3571
|
description: "Manage profiles",
|
|
@@ -3515,6 +3633,7 @@ var bashSpecialCaseCommands = /* @__PURE__ */ new Set([
|
|
|
3515
3633
|
"checklist",
|
|
3516
3634
|
"time",
|
|
3517
3635
|
"bulk",
|
|
3636
|
+
"filter",
|
|
3518
3637
|
"config",
|
|
3519
3638
|
"profile",
|
|
3520
3639
|
"completion"
|
|
@@ -3608,7 +3727,7 @@ ${renderBashCommandCases()}
|
|
|
3608
3727
|
;;
|
|
3609
3728
|
bulk)
|
|
3610
3729
|
if [[ $cword -eq 2 ]]; then
|
|
3611
|
-
COMPREPLY=($(compgen -W "status" -- "$cur"))
|
|
3730
|
+
COMPREPLY=($(compgen -W "status assign due-date tag" -- "$cur"))
|
|
3612
3731
|
fi
|
|
3613
3732
|
;;
|
|
3614
3733
|
profile)
|
|
@@ -3679,10 +3798,13 @@ ${renderZshTopLevelCommands(name)}
|
|
|
3679
3798
|
'(-d --description)'{-d,--description}'[New description]:text:' \\
|
|
3680
3799
|
'(-s --status)'{-s,--status}'[New status]:status:(open "in progress" "in review" done closed)' \\
|
|
3681
3800
|
'--priority[Priority level]:priority:(urgent high normal low)' \\
|
|
3682
|
-
'--due-date[Due date]:date:' \\
|
|
3801
|
+
'--due-date[Due date (YYYY-MM-DD or "none" to clear)]:date:' \\
|
|
3802
|
+
'--start-date[Start date]:date:' \\
|
|
3683
3803
|
'--time-estimate[Time estimate]:duration:' \\
|
|
3684
3804
|
'--assignee[Add assignee]:user_id:' \\
|
|
3805
|
+
'--remove-assignee[Remove assignee]:user_id:' \\
|
|
3685
3806
|
'--parent[Set parent task]:task_id:' \\
|
|
3807
|
+
'--detach[Remove parent task]' \\
|
|
3686
3808
|
'--archive[Archive the task]' \\
|
|
3687
3809
|
'--unarchive[Unarchive the task]' \\
|
|
3688
3810
|
'--field[Set custom field]:field_name_and_value:' \\
|
|
@@ -4044,6 +4166,9 @@ ${renderZshTopLevelCommands(name)}
|
|
|
4044
4166
|
local -a bulk_cmds
|
|
4045
4167
|
bulk_cmds=(
|
|
4046
4168
|
'status:Update status of multiple tasks'
|
|
4169
|
+
'assign:Bulk assign or unassign a user from tasks'
|
|
4170
|
+
'due-date:Bulk set due date on tasks'
|
|
4171
|
+
'tag:Bulk add or remove a tag on tasks'
|
|
4047
4172
|
)
|
|
4048
4173
|
_arguments -C \\
|
|
4049
4174
|
'1:bulk command:->bulk_cmd' \\
|
|
@@ -4057,6 +4182,15 @@ ${renderZshTopLevelCommands(name)}
|
|
|
4057
4182
|
status)
|
|
4058
4183
|
_arguments '1:status:' '*:task_ids:' '--json[Force JSON output]'
|
|
4059
4184
|
;;
|
|
4185
|
+
assign)
|
|
4186
|
+
_arguments '*:task_ids:' '--to[Add user (ID or me)]:userId:' '--remove[Remove user (ID or me)]:userId:' '--json[Force JSON output]'
|
|
4187
|
+
;;
|
|
4188
|
+
due-date)
|
|
4189
|
+
_arguments '1:date:' '*:task_ids:' '--json[Force JSON output]'
|
|
4190
|
+
;;
|
|
4191
|
+
tag)
|
|
4192
|
+
_arguments '1:tagName:' '*:task_ids:' '--add[Add tag]' '--remove[Remove tag]' '--json[Force JSON output]'
|
|
4193
|
+
;;
|
|
4060
4194
|
esac
|
|
4061
4195
|
;;
|
|
4062
4196
|
esac
|
|
@@ -4201,6 +4335,7 @@ ${renderZshTopLevelCommands(name)}
|
|
|
4201
4335
|
'1:space_id:' \\
|
|
4202
4336
|
'2:name:' \\
|
|
4203
4337
|
'--folder[Create inside a folder]:folder_id:' \\
|
|
4338
|
+
'--copy-statuses-from[Copy statuses from list or space]:id:' \\
|
|
4204
4339
|
'--json[Force JSON output]'
|
|
4205
4340
|
;;
|
|
4206
4341
|
folder-create)
|
|
@@ -4231,6 +4366,50 @@ ${renderZshTopLevelCommands(name)}
|
|
|
4231
4366
|
'(-c --content)'{-c,--content}'[New page content]:text:' \\
|
|
4232
4367
|
'--json[Force JSON output]'
|
|
4233
4368
|
;;
|
|
4369
|
+
filter)
|
|
4370
|
+
local -a filter_cmds
|
|
4371
|
+
filter_cmds=(
|
|
4372
|
+
'save:Save a command shortcut'
|
|
4373
|
+
'run:Run a saved shortcut'
|
|
4374
|
+
'list:List saved shortcuts'
|
|
4375
|
+
'delete:Delete a saved shortcut'
|
|
4376
|
+
'show:Show details of a saved shortcut'
|
|
4377
|
+
)
|
|
4378
|
+
_arguments -C \\
|
|
4379
|
+
'1:filter command:->filter_cmd' \\
|
|
4380
|
+
'*::filter_arg:->filter_args'
|
|
4381
|
+
case $state in
|
|
4382
|
+
filter_cmd)
|
|
4383
|
+
_describe 'filter command' filter_cmds
|
|
4384
|
+
;;
|
|
4385
|
+
filter_args)
|
|
4386
|
+
case $words[1] in
|
|
4387
|
+
save)
|
|
4388
|
+
_arguments \\
|
|
4389
|
+
'1:name:' \\
|
|
4390
|
+
'*:command:' \\
|
|
4391
|
+
'(-d --description)'{-d,--description}'[Filter description]:text:' \\
|
|
4392
|
+
'--json[Force JSON output]'
|
|
4393
|
+
;;
|
|
4394
|
+
run)
|
|
4395
|
+
_arguments '1:name:'
|
|
4396
|
+
;;
|
|
4397
|
+
list)
|
|
4398
|
+
_arguments '--json[Force JSON output]'
|
|
4399
|
+
;;
|
|
4400
|
+
delete)
|
|
4401
|
+
_arguments '1:name:' '--json[Force JSON output]'
|
|
4402
|
+
;;
|
|
4403
|
+
show)
|
|
4404
|
+
_arguments '1:name:' '--json[Force JSON output]'
|
|
4405
|
+
;;
|
|
4406
|
+
*)
|
|
4407
|
+
_arguments '1:subcommand:(save run list delete show)'
|
|
4408
|
+
;;
|
|
4409
|
+
esac
|
|
4410
|
+
;;
|
|
4411
|
+
esac
|
|
4412
|
+
;;
|
|
4234
4413
|
profile)
|
|
4235
4414
|
local -a profile_cmds
|
|
4236
4415
|
profile_cmds=(
|
|
@@ -4335,8 +4514,15 @@ complete -c ${name} -n '__fish_seen_subcommand_from update; and __fish_seen_subc
|
|
|
4335
4514
|
|
|
4336
4515
|
complete -c ${name} -n '__fish_seen_subcommand_from attach' -F
|
|
4337
4516
|
|
|
4338
|
-
complete -c ${name} -n '__fish_seen_subcommand_from bulk; and not __fish_seen_subcommand_from status' -a status -d 'Update status of multiple tasks'
|
|
4339
|
-
complete -c ${name} -n '__fish_seen_subcommand_from
|
|
4517
|
+
complete -c ${name} -n '__fish_seen_subcommand_from bulk; and not __fish_seen_subcommand_from status assign due-date tag' -a status -d 'Update status of multiple tasks'
|
|
4518
|
+
complete -c ${name} -n '__fish_seen_subcommand_from bulk; and not __fish_seen_subcommand_from status assign due-date tag' -a assign -d 'Bulk assign or unassign a user from tasks'
|
|
4519
|
+
complete -c ${name} -n '__fish_seen_subcommand_from bulk; and not __fish_seen_subcommand_from status assign due-date tag' -a due-date -d 'Bulk set due date on tasks'
|
|
4520
|
+
complete -c ${name} -n '__fish_seen_subcommand_from bulk; and not __fish_seen_subcommand_from status assign due-date tag' -a tag -d 'Bulk add or remove a tag on tasks'
|
|
4521
|
+
complete -c ${name} -n '__fish_seen_subcommand_from status assign due-date tag; and __fish_seen_subcommand_from bulk' -l json -d 'Force JSON output'
|
|
4522
|
+
complete -c ${name} -n '__fish_seen_subcommand_from assign; and __fish_seen_subcommand_from bulk' -l to -d 'Add user (ID or me)'
|
|
4523
|
+
complete -c ${name} -n '__fish_seen_subcommand_from assign; and __fish_seen_subcommand_from bulk' -l remove -d 'Remove user (ID or me)'
|
|
4524
|
+
complete -c ${name} -n '__fish_seen_subcommand_from tag; and __fish_seen_subcommand_from bulk' -l add -d 'Add tag'
|
|
4525
|
+
complete -c ${name} -n '__fish_seen_subcommand_from tag; and __fish_seen_subcommand_from bulk' -l remove -d 'Remove tag'
|
|
4340
4526
|
|
|
4341
4527
|
complete -c ${name} -n '__fish_seen_subcommand_from profile; and not __fish_seen_subcommand_from list add remove use' -a list -d 'List all profiles'
|
|
4342
4528
|
complete -c ${name} -n '__fish_seen_subcommand_from profile; and not __fish_seen_subcommand_from list add remove use' -a add -d 'Add a new profile'
|
|
@@ -4350,6 +4536,14 @@ complete -c ${name} -n '__fish_seen_subcommand_from config; and not __fish_seen_
|
|
|
4350
4536
|
complete -c ${name} -n '__fish_seen_subcommand_from get set' -a 'apiToken teamId sprintFolderId' -d 'Config key'
|
|
4351
4537
|
|
|
4352
4538
|
complete -c ${name} -n '__fish_seen_subcommand_from completion' -a 'bash zsh fish' -d 'Shell type'
|
|
4539
|
+
|
|
4540
|
+
complete -c ${name} -n '__fish_seen_subcommand_from filter; and not __fish_seen_subcommand_from save run list delete show' -a save -d 'Save a command shortcut'
|
|
4541
|
+
complete -c ${name} -n '__fish_seen_subcommand_from filter; and not __fish_seen_subcommand_from save run list delete show' -a run -d 'Run a saved shortcut'
|
|
4542
|
+
complete -c ${name} -n '__fish_seen_subcommand_from filter; and not __fish_seen_subcommand_from save run list delete show' -a list -d 'List saved shortcuts'
|
|
4543
|
+
complete -c ${name} -n '__fish_seen_subcommand_from filter; and not __fish_seen_subcommand_from save run list delete show' -a delete -d 'Delete a saved shortcut'
|
|
4544
|
+
complete -c ${name} -n '__fish_seen_subcommand_from filter; and not __fish_seen_subcommand_from save run list delete show' -a show -d 'Show details of a saved shortcut'
|
|
4545
|
+
complete -c ${name} -n '__fish_seen_subcommand_from save run list delete show; and __fish_seen_subcommand_from filter' -l json -d 'Force JSON output'
|
|
4546
|
+
complete -c ${name} -n '__fish_seen_subcommand_from save; and __fish_seen_subcommand_from filter' -s d -l description -d 'Filter description'
|
|
4353
4547
|
`;
|
|
4354
4548
|
}
|
|
4355
4549
|
function generateCompletion(shell, name = "cup") {
|
|
@@ -4947,10 +5141,18 @@ async function listTimeEntries(config, opts) {
|
|
|
4947
5141
|
const days = opts?.days ?? 7;
|
|
4948
5142
|
const endDate = Date.now();
|
|
4949
5143
|
const startDate = endDate - days * 24 * 60 * 60 * 1e3;
|
|
5144
|
+
let assigneeId = opts?.assigneeId;
|
|
5145
|
+
if (!opts?.all && !assigneeId) {
|
|
5146
|
+
const me = await client.getMe();
|
|
5147
|
+
assigneeId = String(me.id);
|
|
5148
|
+
}
|
|
4950
5149
|
return client.getTimeEntries(config.teamId, {
|
|
4951
5150
|
startDate,
|
|
4952
5151
|
endDate,
|
|
4953
|
-
taskId: opts?.taskId
|
|
5152
|
+
taskId: opts?.taskId,
|
|
5153
|
+
spaceId: opts?.spaceId,
|
|
5154
|
+
listId: opts?.listId,
|
|
5155
|
+
assigneeId
|
|
4954
5156
|
});
|
|
4955
5157
|
}
|
|
4956
5158
|
async function updateTimeEntry(config, timeEntryId, opts) {
|
|
@@ -5030,9 +5232,12 @@ async function deleteSpaceTag(config, spaceId, tagName) {
|
|
|
5030
5232
|
await client.deleteSpaceTag(spaceId, tagName);
|
|
5031
5233
|
}
|
|
5032
5234
|
async function updateSpaceTag(config, spaceId, tagName, updates) {
|
|
5235
|
+
if (!updates.name && !updates.fg && !updates.bg) {
|
|
5236
|
+
throw new Error("Provide at least one of: --name, --fg, --bg");
|
|
5237
|
+
}
|
|
5033
5238
|
const client = new ClickUpClient(config);
|
|
5034
5239
|
await client.updateSpaceTag(spaceId, tagName, {
|
|
5035
|
-
name: updates.name,
|
|
5240
|
+
name: updates.name ?? tagName,
|
|
5036
5241
|
tag_fg: updates.fg,
|
|
5037
5242
|
tag_bg: updates.bg
|
|
5038
5243
|
});
|
|
@@ -5149,6 +5354,53 @@ async function bulkUpdateStatus(config, taskIds, status) {
|
|
|
5149
5354
|
}
|
|
5150
5355
|
return { updated: taskIds.length - failed.length, failed };
|
|
5151
5356
|
}
|
|
5357
|
+
async function bulkAssign(config, userIdOrMe, taskIds, action) {
|
|
5358
|
+
const client = new ClickUpClient(config);
|
|
5359
|
+
const numericId = await resolveAssigneeId(client, userIdOrMe);
|
|
5360
|
+
const failed = [];
|
|
5361
|
+
for (const id of taskIds) {
|
|
5362
|
+
try {
|
|
5363
|
+
await client.updateTask(id, {
|
|
5364
|
+
assignees: action === "add" ? { add: [numericId] } : { rem: [numericId] }
|
|
5365
|
+
});
|
|
5366
|
+
} catch (err) {
|
|
5367
|
+
const reason = err instanceof Error ? err.message : String(err);
|
|
5368
|
+
failed.push({ id, reason });
|
|
5369
|
+
}
|
|
5370
|
+
}
|
|
5371
|
+
return { updated: taskIds.length - failed.length, failed };
|
|
5372
|
+
}
|
|
5373
|
+
async function bulkDueDate(config, date, taskIds) {
|
|
5374
|
+
const client = new ClickUpClient(config);
|
|
5375
|
+
const payload = date === "none" || date === "clear" ? { due_date: null } : { due_date: parseDueDate(date), due_date_time: false };
|
|
5376
|
+
const failed = [];
|
|
5377
|
+
for (const id of taskIds) {
|
|
5378
|
+
try {
|
|
5379
|
+
await client.updateTask(id, payload);
|
|
5380
|
+
} catch (err) {
|
|
5381
|
+
const reason = err instanceof Error ? err.message : String(err);
|
|
5382
|
+
failed.push({ id, reason });
|
|
5383
|
+
}
|
|
5384
|
+
}
|
|
5385
|
+
return { updated: taskIds.length - failed.length, failed };
|
|
5386
|
+
}
|
|
5387
|
+
async function bulkTag(config, tagName, taskIds, action) {
|
|
5388
|
+
const client = new ClickUpClient(config);
|
|
5389
|
+
const failed = [];
|
|
5390
|
+
for (const id of taskIds) {
|
|
5391
|
+
try {
|
|
5392
|
+
if (action === "add") {
|
|
5393
|
+
await client.addTagToTask(id, tagName);
|
|
5394
|
+
} else {
|
|
5395
|
+
await client.removeTagFromTask(id, tagName);
|
|
5396
|
+
}
|
|
5397
|
+
} catch (err) {
|
|
5398
|
+
const reason = err instanceof Error ? err.message : String(err);
|
|
5399
|
+
failed.push({ id, reason });
|
|
5400
|
+
}
|
|
5401
|
+
}
|
|
5402
|
+
return { updated: taskIds.length - failed.length, failed };
|
|
5403
|
+
}
|
|
5152
5404
|
|
|
5153
5405
|
// src/commands/goals.ts
|
|
5154
5406
|
import chalk14 from "chalk";
|
|
@@ -5322,9 +5574,12 @@ async function createListFromTemplate(config, name, opts) {
|
|
|
5322
5574
|
|
|
5323
5575
|
// src/commands/views.ts
|
|
5324
5576
|
import chalk19 from "chalk";
|
|
5325
|
-
async function listViews(config,
|
|
5577
|
+
async function listViews(config, id, container = "list") {
|
|
5326
5578
|
const client = new ClickUpClient(config);
|
|
5327
|
-
|
|
5579
|
+
if (container === "space") return client.getSpaceViews(id);
|
|
5580
|
+
if (container === "folder") return client.getFolderViews(id);
|
|
5581
|
+
if (container === "workspace") return client.getWorkspaceViews(config.teamId);
|
|
5582
|
+
const data = await client.getListViews(id);
|
|
5328
5583
|
return data.views;
|
|
5329
5584
|
}
|
|
5330
5585
|
function formatViews(views) {
|
|
@@ -5447,6 +5702,117 @@ async function deleteViewCommand(config, viewId, opts) {
|
|
|
5447
5702
|
return { viewId, deleted: true };
|
|
5448
5703
|
}
|
|
5449
5704
|
|
|
5705
|
+
// src/commands/filter.ts
|
|
5706
|
+
import { spawnSync } from "child_process";
|
|
5707
|
+
var ALLOWED_FILTER_COMMANDS = /* @__PURE__ */ new Set([
|
|
5708
|
+
"tasks",
|
|
5709
|
+
"search",
|
|
5710
|
+
"sprint",
|
|
5711
|
+
"assigned",
|
|
5712
|
+
"overdue",
|
|
5713
|
+
"inbox",
|
|
5714
|
+
"summary",
|
|
5715
|
+
"views",
|
|
5716
|
+
"lists",
|
|
5717
|
+
"spaces",
|
|
5718
|
+
"folders",
|
|
5719
|
+
"members",
|
|
5720
|
+
"tags",
|
|
5721
|
+
"goals",
|
|
5722
|
+
"key-results",
|
|
5723
|
+
"task-types",
|
|
5724
|
+
"templates",
|
|
5725
|
+
"list-templates",
|
|
5726
|
+
"folder-templates",
|
|
5727
|
+
"docs"
|
|
5728
|
+
]);
|
|
5729
|
+
function isAllowedFilterCommand(tokens) {
|
|
5730
|
+
if (tokens.length === 0) return false;
|
|
5731
|
+
if (tokens[0] === "time" && tokens[1] === "list") return true;
|
|
5732
|
+
return ALLOWED_FILTER_COMMANDS.has(tokens[0]);
|
|
5733
|
+
}
|
|
5734
|
+
function runFilter(name, entry) {
|
|
5735
|
+
const result = spawnSync(process.execPath, [process.argv[1], ...entry.command], {
|
|
5736
|
+
stdio: "inherit"
|
|
5737
|
+
});
|
|
5738
|
+
if (result.error) throw result.error;
|
|
5739
|
+
if (result.status !== null && result.status !== 0) {
|
|
5740
|
+
process.exitCode = result.status;
|
|
5741
|
+
}
|
|
5742
|
+
}
|
|
5743
|
+
var FILTER_COLUMNS = [
|
|
5744
|
+
{ key: "name", label: "NAME", maxWidth: 30 },
|
|
5745
|
+
{ key: "command", label: "COMMAND", maxWidth: 60 },
|
|
5746
|
+
{ key: "description", label: "DESCRIPTION", maxWidth: 50 }
|
|
5747
|
+
];
|
|
5748
|
+
function formatFiltersTable(filters) {
|
|
5749
|
+
const entries = Object.entries(filters);
|
|
5750
|
+
if (entries.length === 0) return "No filters saved";
|
|
5751
|
+
const rows = entries.map(([name, entry]) => ({
|
|
5752
|
+
name,
|
|
5753
|
+
command: entry.command.join(" "),
|
|
5754
|
+
description: entry.description ?? ""
|
|
5755
|
+
}));
|
|
5756
|
+
return formatTable(rows, FILTER_COLUMNS);
|
|
5757
|
+
}
|
|
5758
|
+
function formatFiltersMarkdown(filters) {
|
|
5759
|
+
const entries = Object.entries(filters);
|
|
5760
|
+
if (entries.length === 0) return "No filters saved";
|
|
5761
|
+
const lines = ["| Name | Command | Description |", "| --- | --- | --- |"];
|
|
5762
|
+
for (const [name, entry] of entries) {
|
|
5763
|
+
const command = entry.command.join(" ");
|
|
5764
|
+
const description = entry.description ?? "";
|
|
5765
|
+
lines.push(`| ${name} | ${command} | ${description} |`);
|
|
5766
|
+
}
|
|
5767
|
+
return lines.join("\n");
|
|
5768
|
+
}
|
|
5769
|
+
function formatFilterDetail(name, entry) {
|
|
5770
|
+
if (isTTY()) {
|
|
5771
|
+
const lines2 = [`Name: ${name}`, `Command: ${entry.command.join(" ")}`];
|
|
5772
|
+
if (entry.description) lines2.push(`Description: ${entry.description}`);
|
|
5773
|
+
return lines2.join("\n");
|
|
5774
|
+
}
|
|
5775
|
+
const lines = [`**${name}**`, ``, `Command: \`${entry.command.join(" ")}\``];
|
|
5776
|
+
if (entry.description) lines.push(`Description: ${entry.description}`);
|
|
5777
|
+
return lines.join("\n");
|
|
5778
|
+
}
|
|
5779
|
+
|
|
5780
|
+
// src/commands/list-create.ts
|
|
5781
|
+
async function createListWithOptions(config, spaceId, name, opts) {
|
|
5782
|
+
const client = new ClickUpClient(config);
|
|
5783
|
+
let statuses;
|
|
5784
|
+
if (opts.copyStatusesFrom) {
|
|
5785
|
+
statuses = await copyStatusesFrom(client, opts.copyStatusesFrom);
|
|
5786
|
+
}
|
|
5787
|
+
const list = opts.folder ? await client.createFolderList(opts.folder, name) : await client.createList(spaceId, name);
|
|
5788
|
+
if (statuses) {
|
|
5789
|
+
await client.updateList(list.id, { statuses });
|
|
5790
|
+
}
|
|
5791
|
+
return {
|
|
5792
|
+
...list,
|
|
5793
|
+
...statuses ? { statusesCopied: statuses.length } : {}
|
|
5794
|
+
};
|
|
5795
|
+
}
|
|
5796
|
+
async function copyStatusesFrom(client, sourceId) {
|
|
5797
|
+
try {
|
|
5798
|
+
const list = await client.getListWithStatuses(sourceId);
|
|
5799
|
+
return list.statuses.map((s) => ({ status: s.status, color: s.color, type: s.type ?? "custom" }));
|
|
5800
|
+
} catch {
|
|
5801
|
+
try {
|
|
5802
|
+
const space = await client.getSpaceWithStatuses(sourceId);
|
|
5803
|
+
return space.statuses.map((s) => ({
|
|
5804
|
+
status: s.status,
|
|
5805
|
+
color: s.color,
|
|
5806
|
+
type: s.type ?? "custom"
|
|
5807
|
+
}));
|
|
5808
|
+
} catch {
|
|
5809
|
+
throw new Error(
|
|
5810
|
+
`Could not find a list or space with ID "${sourceId}". Check the ID and try again.`
|
|
5811
|
+
);
|
|
5812
|
+
}
|
|
5813
|
+
}
|
|
5814
|
+
}
|
|
5815
|
+
|
|
5450
5816
|
// src/index.ts
|
|
5451
5817
|
var require2 = createRequire(import.meta.url);
|
|
5452
5818
|
var { version } = require2("../package.json");
|
|
@@ -5520,7 +5886,7 @@ function buildProgram(programName = basename(process.argv[1] ?? "cup")) {
|
|
|
5520
5886
|
}
|
|
5521
5887
|
})
|
|
5522
5888
|
);
|
|
5523
|
-
program.command("update <taskId>").description("Update a task").option("-n, --name <text>", "New task name").option("-d, --description <text>", "New description (markdown supported)").option("-s, --status <status>", 'New status (e.g. "in progress", "done")').option("--priority <level>", "Priority: urgent, high, normal, low (or 1-4)").option("--due-date <date>",
|
|
5889
|
+
program.command("update <taskId>").description("Update a task").option("-n, --name <text>", "New task name").option("-d, --description <text>", "New description (markdown supported)").option("-s, --status <status>", 'New status (e.g. "in progress", "done")').option("--priority <level>", "Priority: urgent, high, normal, low (or 1-4)").option("--due-date <date>", 'Due date (YYYY-MM-DD, or "none"/"clear" to remove)').option("--start-date <date>", "Start date (YYYY-MM-DD)").option("--time-estimate <duration>", 'Time estimate (e.g. "2h", "30m", "1h30m")').option("--assignee <userId>", 'Add assignee by user ID or "me"').option("--remove-assignee <userId>", 'Remove assignee by user ID or "me"').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("--field <nameAndValue...>", 'Set custom field: --field "Name" value').option("--json", "Force JSON output even in terminal").action(
|
|
5524
5890
|
wrapAction(
|
|
5525
5891
|
async (taskId, opts) => {
|
|
5526
5892
|
const config = loadConfig(getProfileName());
|
|
@@ -5528,11 +5894,15 @@ function buildProgram(programName = basename(process.argv[1] ?? "cup")) {
|
|
|
5528
5894
|
const client = new ClickUpClient(config);
|
|
5529
5895
|
opts.assignee = String(await resolveAssigneeId(client, "me"));
|
|
5530
5896
|
}
|
|
5897
|
+
if (opts.removeAssignee === "me") {
|
|
5898
|
+
const client = new ClickUpClient(config);
|
|
5899
|
+
opts.removeAssignee = String(await resolveAssigneeId(client, "me"));
|
|
5900
|
+
}
|
|
5531
5901
|
const payload = buildUpdatePayload(opts);
|
|
5532
5902
|
const hasFields = (opts.field?.length ?? 0) > 0;
|
|
5533
5903
|
if (!hasFields && Object.keys(payload).length === 0) {
|
|
5534
5904
|
throw new Error(
|
|
5535
|
-
"Provide at least one of: --name, --description, --status, --priority, --due-date, --time-estimate, --assignee, --parent, --archive, --unarchive, --field"
|
|
5905
|
+
"Provide at least one of: --name, --description, --status, --priority, --due-date, --time-estimate, --assignee, --remove-assignee, --parent, --archive, --unarchive, --field"
|
|
5536
5906
|
);
|
|
5537
5907
|
}
|
|
5538
5908
|
let result;
|
|
@@ -5560,7 +5930,7 @@ function buildProgram(programName = basename(process.argv[1] ?? "cup")) {
|
|
|
5560
5930
|
}
|
|
5561
5931
|
)
|
|
5562
5932
|
);
|
|
5563
|
-
program.command("create").description("Create a new task").option("-l, --list <listId>", "Target list ID (auto-detected from --parent if omitted)").requiredOption("-n, --name <name>", "Task name").option("-d, --description <text>", "Task description (markdown supported)").option("-p, --parent <taskId>", "Parent task ID (list auto-detected from parent)").option("-s, --status <status>", "Initial status").option("--priority <level>", "Priority: urgent, high, normal, low (or 1-4)").option("--due-date <date>", "Due date (YYYY-MM-DD)").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").option("--json", "Force JSON output even in terminal").action(
|
|
5933
|
+
program.command("create").description("Create a new task").option("-l, --list <listId>", "Target list ID (auto-detected from --parent if omitted)").requiredOption("-n, --name <name>", "Task name").option("-d, --description <text>", "Task description (markdown supported)").option("-p, --parent <taskId>", "Parent task ID (list auto-detected from parent)").option("-s, --status <status>", "Initial status").option("--priority <level>", "Priority: urgent, high, normal, low (or 1-4)").option("--due-date <date>", "Due date (YYYY-MM-DD)").option("--start-date <date>", "Start date (YYYY-MM-DD)").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").option("--json", "Force JSON output even in terminal").action(
|
|
5564
5934
|
wrapAction(async (opts) => {
|
|
5565
5935
|
const config = loadConfig(getProfileName());
|
|
5566
5936
|
if (opts.assignee === "me") {
|
|
@@ -6028,22 +6398,31 @@ function buildProgram(programName = basename(process.argv[1] ?? "cup")) {
|
|
|
6028
6398
|
}
|
|
6029
6399
|
)
|
|
6030
6400
|
);
|
|
6031
|
-
timeCmd.command("list").description("List recent time entries (
|
|
6032
|
-
wrapAction(
|
|
6033
|
-
|
|
6034
|
-
|
|
6035
|
-
|
|
6036
|
-
|
|
6037
|
-
|
|
6038
|
-
|
|
6039
|
-
|
|
6040
|
-
|
|
6041
|
-
|
|
6042
|
-
|
|
6043
|
-
|
|
6044
|
-
|
|
6401
|
+
timeCmd.command("list").description("List my recent time entries (use --all for team entries)").option("--days <n>", "Number of days to look back", "7").option("--task <taskId>", "Filter by task ID").option("--space <spaceId>", "Filter by space ID").option("--list <listId>", "Filter by list ID").option("--assignee <userId>", "Filter by assignee user ID").option("--all", "Show all team entries (default: only mine)").option("--json", "Force JSON output even in terminal").action(
|
|
6402
|
+
wrapAction(
|
|
6403
|
+
async (opts) => {
|
|
6404
|
+
const config = loadConfig(getProfileName());
|
|
6405
|
+
const days = opts.days ? Number(opts.days) : 7;
|
|
6406
|
+
if (!Number.isFinite(days) || days <= 0) {
|
|
6407
|
+
throw new Error("--days must be a positive number");
|
|
6408
|
+
}
|
|
6409
|
+
const entries = await listTimeEntries(config, {
|
|
6410
|
+
days,
|
|
6411
|
+
taskId: opts.task,
|
|
6412
|
+
spaceId: opts.space,
|
|
6413
|
+
listId: opts.list,
|
|
6414
|
+
assigneeId: opts.assignee,
|
|
6415
|
+
all: opts.all
|
|
6416
|
+
});
|
|
6417
|
+
if (shouldOutputJson(opts.json ?? false)) {
|
|
6418
|
+
console.log(JSON.stringify(entries, null, 2));
|
|
6419
|
+
} else if (isTTY()) {
|
|
6420
|
+
console.log(formatTimeEntries(entries));
|
|
6421
|
+
} else {
|
|
6422
|
+
console.log(formatTimeEntriesMarkdown(entries));
|
|
6423
|
+
}
|
|
6045
6424
|
}
|
|
6046
|
-
|
|
6425
|
+
)
|
|
6047
6426
|
);
|
|
6048
6427
|
timeCmd.command("update <timeEntryId>").description("Update a time entry").option("-d, --description <text>", "New description").option("--duration <duration>", 'New duration (e.g. "2h", "30m")').option("--json", "Force JSON output even in terminal").action(
|
|
6049
6428
|
wrapAction(
|
|
@@ -6194,6 +6573,18 @@ function buildProgram(programName = basename(process.argv[1] ?? "cup")) {
|
|
|
6194
6573
|
}
|
|
6195
6574
|
})
|
|
6196
6575
|
);
|
|
6576
|
+
function outputBulkResult(result, forceJson, operation) {
|
|
6577
|
+
if (shouldOutputJson(forceJson)) {
|
|
6578
|
+
console.log(JSON.stringify(result, null, 2));
|
|
6579
|
+
} else {
|
|
6580
|
+
console.log(
|
|
6581
|
+
`${operation}: ${result.updated} updated${result.failed.length > 0 ? `, ${result.failed.length} failed` : ""}`
|
|
6582
|
+
);
|
|
6583
|
+
for (const f of result.failed) {
|
|
6584
|
+
console.error(` ${f.id}: ${f.reason}`);
|
|
6585
|
+
}
|
|
6586
|
+
}
|
|
6587
|
+
}
|
|
6197
6588
|
const bulkCmd = program.command("bulk").description("Bulk task operations");
|
|
6198
6589
|
bulkCmd.command("status <status> <taskIds...>").description("Update status of multiple tasks").option("--json", "Force JSON output even in terminal").action(
|
|
6199
6590
|
wrapAction(async (status, taskIds, opts) => {
|
|
@@ -6211,6 +6602,38 @@ function buildProgram(programName = basename(process.argv[1] ?? "cup")) {
|
|
|
6211
6602
|
}
|
|
6212
6603
|
})
|
|
6213
6604
|
);
|
|
6605
|
+
bulkCmd.command("assign <taskIds...>").description("Bulk assign or unassign a user from tasks").option("--to <userId>", 'Add this user (user ID or "me")').option("--remove <userId>", 'Remove this user (user ID or "me")').option("--json", "Force JSON output even in terminal").action(
|
|
6606
|
+
wrapAction(
|
|
6607
|
+
async (taskIds, opts) => {
|
|
6608
|
+
if (!opts.to && !opts.remove)
|
|
6609
|
+
throw new Error("Provide --to <userId> or --remove <userId>");
|
|
6610
|
+
if (opts.to && opts.remove) throw new Error("Cannot use --to and --remove together");
|
|
6611
|
+
const config = loadConfig(getProfileName());
|
|
6612
|
+
const userId = opts.to ?? opts.remove;
|
|
6613
|
+
const action = opts.remove ? "remove" : "add";
|
|
6614
|
+
const result = await bulkAssign(config, userId, taskIds, action);
|
|
6615
|
+
outputBulkResult(result, opts.json ?? false, `assign ${action}`);
|
|
6616
|
+
}
|
|
6617
|
+
)
|
|
6618
|
+
);
|
|
6619
|
+
bulkCmd.command("due-date <date> <taskIds...>").description('Bulk set due date on tasks (use "none" to clear)').option("--json", "Force JSON output even in terminal").action(
|
|
6620
|
+
wrapAction(async (date, taskIds, opts) => {
|
|
6621
|
+
const config = loadConfig(getProfileName());
|
|
6622
|
+
const result = await bulkDueDate(config, date, taskIds);
|
|
6623
|
+
outputBulkResult(result, opts.json ?? false, "due-date");
|
|
6624
|
+
})
|
|
6625
|
+
);
|
|
6626
|
+
bulkCmd.command("tag <tagName> <taskIds...>").description("Bulk add or remove a tag on tasks").option("--add", "Add tag (default)").option("--remove", "Remove tag instead of adding").option("--json", "Force JSON output even in terminal").action(
|
|
6627
|
+
wrapAction(
|
|
6628
|
+
async (tagName, taskIds, opts) => {
|
|
6629
|
+
if (opts.add && opts.remove) throw new Error("Cannot use --add and --remove together");
|
|
6630
|
+
const action = opts.remove ? "remove" : "add";
|
|
6631
|
+
const config = loadConfig(getProfileName());
|
|
6632
|
+
const result = await bulkTag(config, tagName, taskIds, action);
|
|
6633
|
+
outputBulkResult(result, opts.json ?? false, `tag ${action}`);
|
|
6634
|
+
}
|
|
6635
|
+
)
|
|
6636
|
+
);
|
|
6214
6637
|
program.command("goals").description("List goals in your workspace").option("--json", "Force JSON output even in terminal").action(
|
|
6215
6638
|
wrapAction(async (opts) => {
|
|
6216
6639
|
const config = loadConfig(getProfileName());
|
|
@@ -6224,13 +6647,14 @@ function buildProgram(programName = basename(process.argv[1] ?? "cup")) {
|
|
|
6224
6647
|
}
|
|
6225
6648
|
})
|
|
6226
6649
|
);
|
|
6227
|
-
program.command("goal-create <name>").description("Create a goal").option("-d, --description <text>", "Goal description").option("--color <hex>", "Goal color (hex)").option("--json", "Force JSON output even in terminal").action(
|
|
6650
|
+
program.command("goal-create <name>").description("Create a goal").option("-d, --description <text>", "Goal description").option("--color <hex>", "Goal color (hex)").option("--due-date <date>", "Due date (YYYY-MM-DD)").option("--json", "Force JSON output even in terminal").action(
|
|
6228
6651
|
wrapAction(
|
|
6229
6652
|
async (name, opts) => {
|
|
6230
6653
|
const config = loadConfig(getProfileName());
|
|
6231
6654
|
const goal = await createGoal(config, name, {
|
|
6232
6655
|
description: opts.description,
|
|
6233
|
-
color: opts.color
|
|
6656
|
+
color: opts.color,
|
|
6657
|
+
dueDate: opts.dueDate
|
|
6234
6658
|
});
|
|
6235
6659
|
if (shouldOutputJson(opts.json ?? false)) {
|
|
6236
6660
|
console.log(JSON.stringify(goal, null, 2));
|
|
@@ -6405,17 +6829,24 @@ function buildProgram(programName = basename(process.argv[1] ?? "cup")) {
|
|
|
6405
6829
|
}
|
|
6406
6830
|
})
|
|
6407
6831
|
);
|
|
6408
|
-
program.command("list-create <spaceId> <name>").description("Create a new list in a space").option("--folder <folderId>", "Create the list inside a folder").option("--json", "Force JSON output even in terminal").action(
|
|
6832
|
+
program.command("list-create <spaceId> <name>").description("Create a new list in a space").option("--folder <folderId>", "Create the list inside a folder").option("--copy-statuses-from <id>", "Copy status set from this list or space ID").option("--json", "Force JSON output even in terminal").action(
|
|
6409
6833
|
wrapAction(
|
|
6410
6834
|
async (spaceId, name, opts) => {
|
|
6411
6835
|
if (!name.trim()) throw new Error("List name cannot be empty");
|
|
6412
6836
|
const config = loadConfig(getProfileName());
|
|
6413
|
-
const
|
|
6414
|
-
|
|
6837
|
+
const result = await createListWithOptions(config, spaceId, name, {
|
|
6838
|
+
folder: opts.folder,
|
|
6839
|
+
copyStatusesFrom: opts.copyStatusesFrom
|
|
6840
|
+
});
|
|
6415
6841
|
if (shouldOutputJson(opts.json ?? false)) {
|
|
6416
|
-
console.log(JSON.stringify(
|
|
6842
|
+
console.log(JSON.stringify(result, null, 2));
|
|
6417
6843
|
} else {
|
|
6418
|
-
console.log(`Created list "${
|
|
6844
|
+
console.log(`Created list "${result.name}" (${result.id})`);
|
|
6845
|
+
if (result.statusesCopied) {
|
|
6846
|
+
console.log(
|
|
6847
|
+
` Copied ${result.statusesCopied} statuses from ${opts.copyStatusesFrom}`
|
|
6848
|
+
);
|
|
6849
|
+
}
|
|
6419
6850
|
}
|
|
6420
6851
|
}
|
|
6421
6852
|
)
|
|
@@ -6495,7 +6926,7 @@ function buildProgram(programName = basename(process.argv[1] ?? "cup")) {
|
|
|
6495
6926
|
}
|
|
6496
6927
|
})
|
|
6497
6928
|
);
|
|
6498
|
-
program.command("tag-update <spaceId> <tagName>").description("Update a tag in a space").
|
|
6929
|
+
program.command("tag-update <spaceId> <tagName>").description("Update a tag in a space").option("--name <newName>", "New tag name").option("--fg <color>", "New foreground color (hex)").option("--bg <color>", "New background color (hex)").option("--json", "Force JSON output even in terminal").action(
|
|
6499
6930
|
wrapAction(
|
|
6500
6931
|
async (spaceId, tagName, opts) => {
|
|
6501
6932
|
const config = loadConfig(getProfileName());
|
|
@@ -6504,16 +6935,15 @@ function buildProgram(programName = basename(process.argv[1] ?? "cup")) {
|
|
|
6504
6935
|
fg: opts.fg,
|
|
6505
6936
|
bg: opts.bg
|
|
6506
6937
|
});
|
|
6938
|
+
const newName = opts.name ?? tagName;
|
|
6507
6939
|
if (shouldOutputJson(opts.json ?? false)) {
|
|
6508
6940
|
console.log(
|
|
6509
|
-
JSON.stringify(
|
|
6510
|
-
{ success: true, spaceId, oldName: tagName, newName: opts.name },
|
|
6511
|
-
null,
|
|
6512
|
-
2
|
|
6513
|
-
)
|
|
6941
|
+
JSON.stringify({ success: true, spaceId, oldName: tagName, newName }, null, 2)
|
|
6514
6942
|
);
|
|
6515
|
-
} else {
|
|
6943
|
+
} else if (opts.name && opts.name !== tagName) {
|
|
6516
6944
|
console.log(`Renamed tag "${tagName}" to "${opts.name}" in space ${spaceId}`);
|
|
6945
|
+
} else {
|
|
6946
|
+
console.log(`Updated tag "${tagName}" in space ${spaceId}`);
|
|
6517
6947
|
}
|
|
6518
6948
|
}
|
|
6519
6949
|
)
|
|
@@ -6583,18 +7013,21 @@ function buildProgram(programName = basename(process.argv[1] ?? "cup")) {
|
|
|
6583
7013
|
}
|
|
6584
7014
|
)
|
|
6585
7015
|
);
|
|
6586
|
-
program.command("views <
|
|
6587
|
-
wrapAction(
|
|
6588
|
-
|
|
6589
|
-
|
|
6590
|
-
|
|
6591
|
-
|
|
6592
|
-
|
|
6593
|
-
|
|
6594
|
-
|
|
6595
|
-
|
|
7016
|
+
program.command("views <id>").description("List views on a list, space, folder, or workspace").option("--space", "Treat <id> as a space ID").option("--folder", "Treat <id> as a folder ID").option("--workspace", "List workspace-level views (ignores <id>)").option("--json", "Force JSON output even in terminal").action(
|
|
7017
|
+
wrapAction(
|
|
7018
|
+
async (id, opts) => {
|
|
7019
|
+
const config = loadConfig(getProfileName());
|
|
7020
|
+
const container = opts.workspace ? "workspace" : opts.space ? "space" : opts.folder ? "folder" : "list";
|
|
7021
|
+
const views = await listViews(config, id, container);
|
|
7022
|
+
if (shouldOutputJson(opts.json ?? false)) {
|
|
7023
|
+
console.log(JSON.stringify(views, null, 2));
|
|
7024
|
+
} else if (isTTY()) {
|
|
7025
|
+
console.log(formatViews(views));
|
|
7026
|
+
} else {
|
|
7027
|
+
console.log(formatViewsMarkdown(views));
|
|
7028
|
+
}
|
|
6596
7029
|
}
|
|
6597
|
-
|
|
7030
|
+
)
|
|
6598
7031
|
);
|
|
6599
7032
|
program.command("view <viewId>").description("Get view details").option("--json", "Force JSON output even in terminal").action(
|
|
6600
7033
|
wrapAction(async (viewId, opts) => {
|
|
@@ -6661,6 +7094,77 @@ function buildProgram(programName = basename(process.argv[1] ?? "cup")) {
|
|
|
6661
7094
|
}
|
|
6662
7095
|
})
|
|
6663
7096
|
);
|
|
7097
|
+
const filterCmd = program.command("filter").description("Manage saved command shortcuts");
|
|
7098
|
+
filterCmd.command("save <name> [args...]").description("Save a command shortcut").option("-d, --description <text>", "Description for this filter").option("--json", "Force JSON output even in terminal").action(
|
|
7099
|
+
wrapAction(
|
|
7100
|
+
async (name, args, opts) => {
|
|
7101
|
+
if (args.length === 0) {
|
|
7102
|
+
throw new Error(
|
|
7103
|
+
'Provide a command to save, e.g.: cup filter save my-sprint tasks --status "in progress"'
|
|
7104
|
+
);
|
|
7105
|
+
}
|
|
7106
|
+
if (!isAllowedFilterCommand(args)) {
|
|
7107
|
+
throw new Error(
|
|
7108
|
+
`Command "${args[0]}" is not allowed in saved filters. Allowed: tasks, search, sprint, assigned, overdue, inbox, summary, views, lists, spaces, folders, members, tags, goals, key-results, task-types, templates, list-templates, folder-templates, docs, time list`
|
|
7109
|
+
);
|
|
7110
|
+
}
|
|
7111
|
+
const entry = { command: args };
|
|
7112
|
+
if (opts.description) entry.description = opts.description;
|
|
7113
|
+
saveFilter(name, entry, getProfileName());
|
|
7114
|
+
if (shouldOutputJson(opts.json ?? false)) {
|
|
7115
|
+
console.log(JSON.stringify({ name, ...entry }, null, 2));
|
|
7116
|
+
} else {
|
|
7117
|
+
console.log(`Saved filter "${name}": ${args.join(" ")}`);
|
|
7118
|
+
}
|
|
7119
|
+
}
|
|
7120
|
+
)
|
|
7121
|
+
);
|
|
7122
|
+
filterCmd.command("run <name>").description("Run a saved command shortcut").action(
|
|
7123
|
+
wrapAction(async (name) => {
|
|
7124
|
+
const filters = getFilters(getProfileName());
|
|
7125
|
+
const entry = filters[name];
|
|
7126
|
+
if (!entry) {
|
|
7127
|
+
throw new Error(`Filter "${name}" not found. Use: cup filter list`);
|
|
7128
|
+
}
|
|
7129
|
+
runFilter(name, entry);
|
|
7130
|
+
})
|
|
7131
|
+
);
|
|
7132
|
+
filterCmd.command("list").description("List all saved command shortcuts").option("--json", "Force JSON output even in terminal").action(
|
|
7133
|
+
wrapAction(async (opts) => {
|
|
7134
|
+
const filters = getFilters(getProfileName());
|
|
7135
|
+
if (shouldOutputJson(opts.json ?? false)) {
|
|
7136
|
+
console.log(JSON.stringify(filters, null, 2));
|
|
7137
|
+
} else if (isTTY()) {
|
|
7138
|
+
console.log(formatFiltersTable(filters));
|
|
7139
|
+
} else {
|
|
7140
|
+
console.log(formatFiltersMarkdown(filters));
|
|
7141
|
+
}
|
|
7142
|
+
})
|
|
7143
|
+
);
|
|
7144
|
+
filterCmd.command("delete <name>").description("Delete a saved command shortcut").option("--json", "Force JSON output even in terminal").action(
|
|
7145
|
+
wrapAction(async (name, opts) => {
|
|
7146
|
+
deleteFilter(name, getProfileName());
|
|
7147
|
+
if (shouldOutputJson(opts.json ?? false)) {
|
|
7148
|
+
console.log(JSON.stringify({ success: true, name }, null, 2));
|
|
7149
|
+
} else {
|
|
7150
|
+
console.log(`Deleted filter "${name}"`);
|
|
7151
|
+
}
|
|
7152
|
+
})
|
|
7153
|
+
);
|
|
7154
|
+
filterCmd.command("show <name>").description("Show details of a saved command shortcut").option("--json", "Force JSON output even in terminal").action(
|
|
7155
|
+
wrapAction(async (name, opts) => {
|
|
7156
|
+
const filters = getFilters(getProfileName());
|
|
7157
|
+
const entry = filters[name];
|
|
7158
|
+
if (!entry) {
|
|
7159
|
+
throw new Error(`Filter "${name}" not found. Use: cup filter list`);
|
|
7160
|
+
}
|
|
7161
|
+
if (shouldOutputJson(opts.json ?? false)) {
|
|
7162
|
+
console.log(JSON.stringify({ name, ...entry }, null, 2));
|
|
7163
|
+
} else {
|
|
7164
|
+
console.log(formatFilterDetail(name, entry));
|
|
7165
|
+
}
|
|
7166
|
+
})
|
|
7167
|
+
);
|
|
6664
7168
|
const profileCmd = program.command("profile").description("Manage profiles");
|
|
6665
7169
|
profileCmd.command("list").description("List all profiles").option("--json", "Force JSON output even in terminal").action(
|
|
6666
7170
|
wrapAction(async (opts) => {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: clickup
|
|
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.'
|
|
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.'
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
# ClickUp CLI (`cup`)
|
|
@@ -15,6 +15,21 @@ Multiple profiles supported - use `cup profile add <name>` to create, `cup profi
|
|
|
15
15
|
|
|
16
16
|
Environment variables `CU_API_TOKEN` and `CU_TEAM_ID` override config file when both are set. `CU_PROFILE` selects a profile (overridden by `-p` flag).
|
|
17
17
|
|
|
18
|
+
## Saved Filters (Quick Shortcuts)
|
|
19
|
+
|
|
20
|
+
At the start of each session, run `cup filter list` to discover saved shortcuts for this workspace.
|
|
21
|
+
|
|
22
|
+
| Command | What it does |
|
|
23
|
+
| -------------------------------------------------- | ---------------------------------------------------------------- |
|
|
24
|
+
| `cup filter list [--json]` | List all saved shortcuts with commands and descriptions |
|
|
25
|
+
| `cup filter run <name>` | Execute a saved shortcut (identical to running the full command) |
|
|
26
|
+
| `cup filter save <name> <cmd> [args...] [-d desc]` | Save a command shortcut |
|
|
27
|
+
| `cup filter delete <name>` | Remove a shortcut |
|
|
28
|
+
| `cup filter show <name> [--json]` | Show a single shortcut's details |
|
|
29
|
+
|
|
30
|
+
Example: `cup filter save sprint-tasks tasks --status "in progress" --list l1 -d "Current sprint tasks"`
|
|
31
|
+
Then: `cup filter run sprint-tasks` is equivalent to `cup tasks --status "in progress" --list l1`
|
|
32
|
+
|
|
18
33
|
## Output Modes
|
|
19
34
|
|
|
20
35
|
| Context | Default output | Override |
|
|
@@ -69,66 +84,69 @@ All commands support `--help` for full flag details. All commands support `--jso
|
|
|
69
84
|
|
|
70
85
|
### Write
|
|
71
86
|
|
|
72
|
-
| Command
|
|
73
|
-
|
|
|
74
|
-
| `cup create -n name [-l listId] [-p parentId] [-d desc] [-s status] [--priority p] [--due-date d] [--time-estimate t] [--assignee id\|me] [--tags t] [--custom-item-id n] [--template id]`
|
|
75
|
-
| `cup update <id> [-n name] [-d desc] [-s status] [--priority p] [--due-date d] [--time-estimate t] [--assignee id\|me] [--parent id] [--archive] [--unarchive] [--field "Name" val]`
|
|
76
|
-
| `cup comment <id> -m text [--notify-all]`
|
|
77
|
-
| `cup comment-edit <commentId> -m text [--resolved] [--unresolved]`
|
|
78
|
-
| `cup comment-delete <commentId>`
|
|
79
|
-
| `cup replies <commentId>`
|
|
80
|
-
| `cup reply <commentId> -m text [--notify-all]`
|
|
81
|
-
| `cup assign <id> [--to userId\|me] [--remove userId\|me]`
|
|
82
|
-
| `cup depend <id> [--on taskId] [--blocks taskId] [--remove]`
|
|
83
|
-
| `cup move <id> [--to listId] [--remove listId]`
|
|
84
|
-
| `cup field <id> [--set "Name" value] [--remove "Name"]`
|
|
85
|
-
| `cup field-create <name> -t <type> [-d desc] [--options "a,b,c"] [--required]`
|
|
86
|
-
| `cup tag <id> [--add tags] [--remove tags]`
|
|
87
|
-
| `cup link <taskId> <linksTo> [--remove]`
|
|
88
|
-
| `cup attach <taskId> <filePath>`
|
|
89
|
-
| `cup delete <id> [--confirm]`
|
|
90
|
-
| `cup duplicate <taskId>`
|
|
91
|
-
| `cup bulk status <status> <taskIds...>`
|
|
92
|
-
| `cup
|
|
93
|
-
| `cup
|
|
94
|
-
| `cup
|
|
95
|
-
| `cup checklist
|
|
96
|
-
| `cup checklist
|
|
97
|
-
| `cup checklist delete
|
|
98
|
-
| `cup
|
|
99
|
-
| `cup
|
|
100
|
-
| `cup
|
|
101
|
-
| `cup time
|
|
102
|
-
| `cup time
|
|
103
|
-
| `cup time
|
|
104
|
-
| `cup time
|
|
105
|
-
| `cup
|
|
106
|
-
| `cup
|
|
107
|
-
| `cup
|
|
108
|
-
| `cup
|
|
109
|
-
| `cup
|
|
110
|
-
| `cup
|
|
111
|
-
| `cup
|
|
112
|
-
| `cup
|
|
113
|
-
| `cup
|
|
114
|
-
| `cup doc-
|
|
115
|
-
| `cup doc-page-
|
|
116
|
-
| `cup
|
|
117
|
-
| `cup
|
|
118
|
-
| `cup
|
|
119
|
-
| `cup
|
|
120
|
-
| `cup
|
|
121
|
-
| `cup
|
|
122
|
-
| `cup
|
|
123
|
-
| `cup
|
|
124
|
-
| `cup
|
|
125
|
-
| `cup
|
|
126
|
-
| `cup
|
|
127
|
-
| `cup
|
|
128
|
-
| `cup
|
|
129
|
-
| `cup profile
|
|
130
|
-
| `cup
|
|
131
|
-
| `cup
|
|
87
|
+
| Command | What it does |
|
|
88
|
+
| ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------- |
|
|
89
|
+
| `cup create -n name [-l listId] [-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]` | Create task |
|
|
90
|
+
| `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] [--field "Name" val]` | Update task fields (including custom fields) |
|
|
91
|
+
| `cup comment <id> -m text [--notify-all]` | Post comment on task |
|
|
92
|
+
| `cup comment-edit <commentId> -m text [--resolved] [--unresolved]` | Edit a comment |
|
|
93
|
+
| `cup comment-delete <commentId>` | Delete a comment |
|
|
94
|
+
| `cup replies <commentId>` | List threaded replies |
|
|
95
|
+
| `cup reply <commentId> -m text [--notify-all]` | Reply to a comment |
|
|
96
|
+
| `cup assign <id> [--to userId\|me] [--remove userId\|me]` | Assign/unassign users |
|
|
97
|
+
| `cup depend <id> [--on taskId] [--blocks taskId] [--remove]` | Add/remove dependencies |
|
|
98
|
+
| `cup move <id> [--to listId] [--remove listId]` | Add/remove task from lists |
|
|
99
|
+
| `cup field <id> [--set "Name" value] [--remove "Name"]` | Set/remove custom field values |
|
|
100
|
+
| `cup field-create <name> -t <type> [-d desc] [--options "a,b,c"] [--required]` | Create a custom field |
|
|
101
|
+
| `cup tag <id> [--add tags] [--remove tags]` | Add/remove tags on a task |
|
|
102
|
+
| `cup link <taskId> <linksTo> [--remove]` | Link/unlink tasks |
|
|
103
|
+
| `cup attach <taskId> <filePath>` | Upload file attachment |
|
|
104
|
+
| `cup delete <id> [--confirm]` | Delete task (DESTRUCTIVE) |
|
|
105
|
+
| `cup duplicate <taskId>` | Duplicate a task |
|
|
106
|
+
| `cup bulk status <status> <taskIds...>` | Bulk update status |
|
|
107
|
+
| `cup bulk assign <taskIds...> [--to userId\|me] [--remove userId\|me]` | Bulk assign/unassign user from tasks |
|
|
108
|
+
| `cup bulk due-date <date\|none\|clear> <taskIds...>` | Bulk set or clear due dates |
|
|
109
|
+
| `cup bulk tag <tagName> <taskIds...> [--add] [--remove]` | Bulk add/remove tag from tasks |
|
|
110
|
+
| `cup checklist view <id>` | View checklists on a task |
|
|
111
|
+
| `cup checklist create <id> <name>` | Create a checklist |
|
|
112
|
+
| `cup checklist delete <checklistId>` | Delete a checklist |
|
|
113
|
+
| `cup checklist add-item <checklistId> <name>` | Add item to checklist |
|
|
114
|
+
| `cup checklist edit-item <checklistId> <itemId> [--name n] [--resolved] [--unresolved] [--assignee id]` | Edit checklist item |
|
|
115
|
+
| `cup checklist delete-item <checklistId> <itemId>` | Delete checklist item |
|
|
116
|
+
| `cup time start <taskId> [-d desc]` | Start timer |
|
|
117
|
+
| `cup time stop` | Stop running timer |
|
|
118
|
+
| `cup time status` | Show running timer |
|
|
119
|
+
| `cup time log <taskId> <duration> [-d desc]` | Log manual entry (e.g. "2h", "30m") |
|
|
120
|
+
| `cup time list [--days n] [--task id] [--all]` | List my recent time entries (--all for team) |
|
|
121
|
+
| `cup time update <timeEntryId> [-d desc] [--duration dur]` | Update time entry |
|
|
122
|
+
| `cup time delete <timeEntryId>` | Delete time entry |
|
|
123
|
+
| `cup goal-create <name> [-d desc] [--color hex]` | Create a goal |
|
|
124
|
+
| `cup goal-update <goalId> [-n name] [-d desc] [--color hex]` | Update a goal |
|
|
125
|
+
| `cup goal-delete <goalId>` | Delete a goal |
|
|
126
|
+
| `cup key-result-create <goalId> <name> [--type t] [--target n]` | Create key result |
|
|
127
|
+
| `cup key-result-update <keyResultId> [--progress n] [--note text]` | Update key result |
|
|
128
|
+
| `cup key-result-delete <keyResultId>` | Delete key result |
|
|
129
|
+
| `cup doc-create <title> [-c content]` | Create a doc |
|
|
130
|
+
| `cup doc-page-create <docId> <name> [-c content] [--parent-page pageId]` | Create doc page |
|
|
131
|
+
| `cup doc-page-edit <docId> <pageId> [--name text] [-c content]` | Edit doc page |
|
|
132
|
+
| `cup doc-delete <docId>` | Delete a doc |
|
|
133
|
+
| `cup doc-page-delete <docId> <pageId>` | Delete doc page |
|
|
134
|
+
| `cup space-create <name>` | Create a space |
|
|
135
|
+
| `cup list-create <spaceId> <name> [--folder folderId] [--copy-statuses-from id]` | Create a list in a space or folder |
|
|
136
|
+
| `cup folder-create <spaceId> <name>` | Create a folder in a space |
|
|
137
|
+
| `cup tag-create <spaceId> <name> [--fg color] [--bg color]` | Create space tag |
|
|
138
|
+
| `cup tag-update <spaceId> <tagName> --name <newName> [--fg c] [--bg c]` | Update space tag |
|
|
139
|
+
| `cup tag-delete <spaceId> <name>` | Delete space tag |
|
|
140
|
+
| `cup list-from-template <name> --template <id> [--space id] [--folder id]` | Create list from template |
|
|
141
|
+
| `cup view-create <listId> <name> -t <type> [--group-by field]` | Create a view on a list |
|
|
142
|
+
| `cup view-update <viewId> [-n name] [--group-by field]` | Update a view |
|
|
143
|
+
| `cup view-delete <viewId> [--confirm]` | Delete a view (DESTRUCTIVE) |
|
|
144
|
+
| `cup profile list [--json]` | List all profiles |
|
|
145
|
+
| `cup profile add <name>` | Add a new profile (interactive) |
|
|
146
|
+
| `cup profile remove <name>` | Remove a profile |
|
|
147
|
+
| `cup profile use <name>` | Set the default profile |
|
|
148
|
+
| `cup config get <key>` / `set <key> <value>` / `path` | Manage config |
|
|
149
|
+
| `cup completion <shell>` | Shell completions (bash/zsh/fish) |
|
|
132
150
|
|
|
133
151
|
## Global Flags
|
|
134
152
|
|