@krodak/clickup-cli 1.22.2 → 1.23.1
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 +15 -15
- package/dist/index.js +249 -44
- package/package.json +1 -1
- package/skills/clickup-cli/SKILL.md +83 -72
|
@@ -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.23.1",
|
|
5
5
|
"author": {
|
|
6
6
|
"name": "Krzysztof Rodak"
|
|
7
7
|
},
|
package/README.md
CHANGED
|
@@ -171,21 +171,21 @@ 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, search, subtasks, assign, dependencies, links, multi-list, bulk status
|
|
177
|
-
| 💬 **Comments** | Post, edit, delete by ID or by task scope for your own comments, threaded replies, notify all
|
|
178
|
-
| 📄 **Docs** | List, read, create, edit, delete (v3 API)
|
|
179
|
-
| ⏱️ **Time Tracking** | Start/stop timer, log entries, list/update/delete history
|
|
180
|
-
| ☑️ **Checklists** | View, create, delete, add/edit/delete items
|
|
181
|
-
| 🔧 **Custom Fields** | List, create, set, remove values (dropdown, labels, date, checkbox,
|
|
182
|
-
| 🏷️ **Tags** | Add/remove on tasks, space-level create/update/delete
|
|
183
|
-
| 🎯 **Goals & OKRs** | Goals CRUD, key results CRUD
|
|
184
|
-
| 🏃 **Sprints** | Auto-detect active sprint, `sprint:current` pseudo-ID for move/create, flexible date parsing, config override, favorite sprint folders
|
|
185
|
-
| ⭐ **Favorites** | Local favorites for quick access to sprint folders, spaces, lists, folders, views, tasks
|
|
186
|
-
| 👁️ **Views** | List, get, create, update, delete views on lists
|
|
187
|
-
| 🏢 **Workspace** | Spaces, folders, lists (read + create + from template), members, task types, templates
|
|
188
|
-
| 📎 **Attachments** | Upload files to tasks, shown in detail views
|
|
174
|
+
| Area | Capabilities |
|
|
175
|
+
| -------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
176
|
+
| ✅ **Tasks** | Create, read, update, delete, duplicate, 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 |
|
|
178
|
+
| 📄 **Docs** | List, read, create, edit, delete (v3 API) |
|
|
179
|
+
| ⏱️ **Time Tracking** | Start/stop timer, log entries, list/update/delete history |
|
|
180
|
+
| ☑️ **Checklists** | View, create, delete, add/edit/delete items |
|
|
181
|
+
| 🔧 **Custom Fields** | List, create, set, remove values (text, number, dropdown, labels, date, checkbox, url, email, rating, progress, relationship, people) |
|
|
182
|
+
| 🏷️ **Tags** | Add/remove on tasks, space-level create/update/delete |
|
|
183
|
+
| 🎯 **Goals & OKRs** | Goals CRUD, key results CRUD |
|
|
184
|
+
| 🏃 **Sprints** | Auto-detect active sprint, `sprint:current` pseudo-ID for move/create, flexible date parsing, config override, favorite sprint folders |
|
|
185
|
+
| ⭐ **Favorites** | Local favorites for quick access to sprint folders, spaces, lists, folders, views, tasks |
|
|
186
|
+
| 👁️ **Views** | List, get, create, update, delete views on lists |
|
|
187
|
+
| 🏢 **Workspace** | Spaces, folders, lists (read + create + rename + from template), members, task types, templates |
|
|
188
|
+
| 📎 **Attachments** | Upload files to tasks, shown in detail views |
|
|
189
189
|
|
|
190
190
|
[Full API coverage details](docs/api-coverage.md) | [Command reference](docs/commands.md)
|
|
191
191
|
|
package/dist/index.js
CHANGED
|
@@ -7,13 +7,15 @@ import { Command } from "commander";
|
|
|
7
7
|
import { createRequire } from "module";
|
|
8
8
|
import { fileURLToPath } from "url";
|
|
9
9
|
|
|
10
|
+
// src/util/guards.ts
|
|
11
|
+
function isRecord(value) {
|
|
12
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
13
|
+
}
|
|
14
|
+
|
|
10
15
|
// src/api.ts
|
|
11
16
|
var BASE_URL = "https://api.clickup.com/api/v2";
|
|
12
17
|
var BASE_URL_V3 = "https://api.clickup.com/api/v3";
|
|
13
18
|
var MAX_PAGES = 100;
|
|
14
|
-
function isRecord(value) {
|
|
15
|
-
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
16
|
-
}
|
|
17
19
|
function expectRecord(value, context) {
|
|
18
20
|
if (!isRecord(value)) {
|
|
19
21
|
throw new Error(`Unexpected API response: expected ${context} object`);
|
|
@@ -286,6 +288,12 @@ var ClickUpClient = class {
|
|
|
286
288
|
body: JSON.stringify({ name, multiple_assignees: true })
|
|
287
289
|
});
|
|
288
290
|
}
|
|
291
|
+
async updateSpace(spaceId, payload) {
|
|
292
|
+
return this.request(`/space/${spaceId}`, {
|
|
293
|
+
method: "PUT",
|
|
294
|
+
body: JSON.stringify(payload)
|
|
295
|
+
});
|
|
296
|
+
}
|
|
289
297
|
async getSpaces(teamId, archived = false) {
|
|
290
298
|
const data = await this.request(
|
|
291
299
|
`/team/${teamId}/space?archived=${archived ? "true" : "false"}`
|
|
@@ -326,6 +334,12 @@ var ClickUpClient = class {
|
|
|
326
334
|
body: JSON.stringify({ name })
|
|
327
335
|
});
|
|
328
336
|
}
|
|
337
|
+
async updateFolder(folderId, payload) {
|
|
338
|
+
return this.request(`/folder/${folderId}`, {
|
|
339
|
+
method: "PUT",
|
|
340
|
+
body: JSON.stringify(payload)
|
|
341
|
+
});
|
|
342
|
+
}
|
|
329
343
|
async getLists(spaceId, archived = false) {
|
|
330
344
|
const data = await this.request(
|
|
331
345
|
`/space/${spaceId}/list?archived=${archived ? "true" : "false"}`
|
|
@@ -875,8 +889,44 @@ var ClickUpClient = class {
|
|
|
875
889
|
import fs from "fs";
|
|
876
890
|
import { homedir } from "os";
|
|
877
891
|
import { join } from "path";
|
|
878
|
-
|
|
879
|
-
|
|
892
|
+
var VALID_FAVORITE_TYPES = /* @__PURE__ */ new Set([
|
|
893
|
+
"sprint-folder",
|
|
894
|
+
"space",
|
|
895
|
+
"list",
|
|
896
|
+
"folder",
|
|
897
|
+
"view",
|
|
898
|
+
"task"
|
|
899
|
+
]);
|
|
900
|
+
function isFilterEntry(v) {
|
|
901
|
+
if (!isRecord(v)) return false;
|
|
902
|
+
if (!Array.isArray(v.command)) return false;
|
|
903
|
+
if (!v.command.every((c) => typeof c === "string")) return false;
|
|
904
|
+
if (v.description !== void 0 && typeof v.description !== "string") return false;
|
|
905
|
+
return true;
|
|
906
|
+
}
|
|
907
|
+
function parseFiltersMap(raw) {
|
|
908
|
+
if (!isRecord(raw)) return {};
|
|
909
|
+
const out = {};
|
|
910
|
+
for (const [key, value] of Object.entries(raw)) {
|
|
911
|
+
if (isFilterEntry(value)) out[key] = value;
|
|
912
|
+
}
|
|
913
|
+
return out;
|
|
914
|
+
}
|
|
915
|
+
function isFavoriteEntry(v) {
|
|
916
|
+
if (!isRecord(v)) return false;
|
|
917
|
+
if (typeof v.type !== "string") return false;
|
|
918
|
+
if (!VALID_FAVORITE_TYPES.has(v.type)) return false;
|
|
919
|
+
if (typeof v.id !== "string") return false;
|
|
920
|
+
if (v.name !== void 0 && typeof v.name !== "string") return false;
|
|
921
|
+
return true;
|
|
922
|
+
}
|
|
923
|
+
function parseFavoritesMap(raw) {
|
|
924
|
+
if (!isRecord(raw)) return {};
|
|
925
|
+
const out = {};
|
|
926
|
+
for (const [key, value] of Object.entries(raw)) {
|
|
927
|
+
if (isFavoriteEntry(value)) out[key] = value;
|
|
928
|
+
}
|
|
929
|
+
return out;
|
|
880
930
|
}
|
|
881
931
|
function readConfigString(parsed, key, path, strict) {
|
|
882
932
|
const value = parsed[key];
|
|
@@ -900,7 +950,7 @@ function parseConfigFile(raw, path, strictFields, strictRoot = strictFields) {
|
|
|
900
950
|
}
|
|
901
951
|
return {};
|
|
902
952
|
}
|
|
903
|
-
if (!
|
|
953
|
+
if (!isRecord(parsed)) {
|
|
904
954
|
if (strictRoot) {
|
|
905
955
|
throw new Error(`Config file at ${path} must contain a JSON object.`);
|
|
906
956
|
}
|
|
@@ -966,18 +1016,18 @@ function migrateToMultiProfile(parsed, filePath) {
|
|
|
966
1016
|
});
|
|
967
1017
|
return migrated;
|
|
968
1018
|
}
|
|
969
|
-
if (
|
|
1019
|
+
if (isRecord(parsed.profiles)) {
|
|
970
1020
|
const profiles = {};
|
|
971
1021
|
for (const [name, value] of Object.entries(parsed.profiles)) {
|
|
972
|
-
if (
|
|
1022
|
+
if (isRecord(value)) {
|
|
973
1023
|
const p = {};
|
|
974
1024
|
if (typeof value.apiToken === "string" && value.apiToken.trim())
|
|
975
1025
|
p.apiToken = value.apiToken.trim();
|
|
976
1026
|
if (typeof value.teamId === "string" && value.teamId.trim()) p.teamId = value.teamId.trim();
|
|
977
1027
|
if (typeof value.sprintFolderId === "string" && value.sprintFolderId.trim())
|
|
978
1028
|
p.sprintFolderId = value.sprintFolderId.trim();
|
|
979
|
-
if (
|
|
980
|
-
if (
|
|
1029
|
+
if (value.filters !== void 0) p.filters = parseFiltersMap(value.filters);
|
|
1030
|
+
if (value.favorites !== void 0) p.favorites = parseFavoritesMap(value.favorites);
|
|
981
1031
|
profiles[name] = p;
|
|
982
1032
|
}
|
|
983
1033
|
}
|
|
@@ -998,7 +1048,7 @@ function parseRawConfig(filePath) {
|
|
|
998
1048
|
`Config file at ${filePath} contains invalid JSON. Please check the file syntax.`
|
|
999
1049
|
);
|
|
1000
1050
|
}
|
|
1001
|
-
if (!
|
|
1051
|
+
if (!isRecord(parsed)) {
|
|
1002
1052
|
throw new Error(`Config file at ${filePath} must contain a JSON object.`);
|
|
1003
1053
|
}
|
|
1004
1054
|
return { parsed, raw };
|
|
@@ -1088,7 +1138,7 @@ function loadMultiProfileConfig() {
|
|
|
1088
1138
|
} catch {
|
|
1089
1139
|
return { defaultProfile: "", profiles: {} };
|
|
1090
1140
|
}
|
|
1091
|
-
if (!
|
|
1141
|
+
if (!isRecord(parsed)) return { defaultProfile: "", profiles: {} };
|
|
1092
1142
|
if (isOldFormat(parsed)) {
|
|
1093
1143
|
return migrateToMultiProfile(parsed, path);
|
|
1094
1144
|
}
|
|
@@ -1153,7 +1203,7 @@ function loadRawConfig(profileName) {
|
|
|
1153
1203
|
} catch {
|
|
1154
1204
|
return {};
|
|
1155
1205
|
}
|
|
1156
|
-
if (!
|
|
1206
|
+
if (!isRecord(parsed)) {
|
|
1157
1207
|
throw new Error(`Config file at ${path} must contain a JSON object.`);
|
|
1158
1208
|
}
|
|
1159
1209
|
if (isOldFormat(parsed)) {
|
|
@@ -1553,7 +1603,7 @@ function formatCustomFieldValue(field) {
|
|
|
1553
1603
|
switch (field.type) {
|
|
1554
1604
|
case "drop_down": {
|
|
1555
1605
|
if (!options) return stringifyFieldValue(field.value);
|
|
1556
|
-
const match = options.find((o) => o.
|
|
1606
|
+
const match = options.find((o) => o.orderindex === Number(field.value));
|
|
1557
1607
|
return match?.name ?? stringifyFieldValue(field.value);
|
|
1558
1608
|
}
|
|
1559
1609
|
case "labels": {
|
|
@@ -2054,6 +2104,9 @@ async function createTask(config, options) {
|
|
|
2054
2104
|
if (options.timeEstimate !== void 0) {
|
|
2055
2105
|
payload.time_estimate = parseTimeEstimate(options.timeEstimate);
|
|
2056
2106
|
}
|
|
2107
|
+
if (options.customFields !== void 0 && options.customFields.length > 0) {
|
|
2108
|
+
payload.custom_fields = options.customFields;
|
|
2109
|
+
}
|
|
2057
2110
|
const task = await client.createTask(listId, payload);
|
|
2058
2111
|
return { id: task.id, name: task.name, url: task.url };
|
|
2059
2112
|
}
|
|
@@ -2092,10 +2145,8 @@ Next steps:
|
|
|
2092
2145
|
`;
|
|
2093
2146
|
function validateTokenFormat(token) {
|
|
2094
2147
|
if (!token.startsWith("pk_")) {
|
|
2095
|
-
throw new Error(
|
|
2096
|
-
|
|
2097
|
-
${TOKEN_HELP}`
|
|
2098
|
-
);
|
|
2148
|
+
throw new Error(`Invalid token format. Personal API tokens start with "pk_".
|
|
2149
|
+
${TOKEN_HELP}`);
|
|
2099
2150
|
}
|
|
2100
2151
|
}
|
|
2101
2152
|
async function verifyToken(apiToken) {
|
|
@@ -3273,6 +3324,7 @@ var commandMetadata = [
|
|
|
3273
3324
|
"--custom-item-id",
|
|
3274
3325
|
"--time-estimate",
|
|
3275
3326
|
"--template",
|
|
3327
|
+
"--field",
|
|
3276
3328
|
"--json"
|
|
3277
3329
|
],
|
|
3278
3330
|
quickReference: [{ section: "write", usage: "create", description: "Create a new task" }]
|
|
@@ -3758,6 +3810,42 @@ var commandMetadata = [
|
|
|
3758
3810
|
}
|
|
3759
3811
|
]
|
|
3760
3812
|
},
|
|
3813
|
+
{
|
|
3814
|
+
name: "list-rename",
|
|
3815
|
+
description: "Rename a list",
|
|
3816
|
+
flags: ["--json"],
|
|
3817
|
+
quickReference: [
|
|
3818
|
+
{
|
|
3819
|
+
section: "write",
|
|
3820
|
+
usage: "list-rename <listId> <newName>",
|
|
3821
|
+
description: "Rename a list"
|
|
3822
|
+
}
|
|
3823
|
+
]
|
|
3824
|
+
},
|
|
3825
|
+
{
|
|
3826
|
+
name: "folder-rename",
|
|
3827
|
+
description: "Rename a folder",
|
|
3828
|
+
flags: ["--json"],
|
|
3829
|
+
quickReference: [
|
|
3830
|
+
{
|
|
3831
|
+
section: "write",
|
|
3832
|
+
usage: "folder-rename <folderId> <newName>",
|
|
3833
|
+
description: "Rename a folder"
|
|
3834
|
+
}
|
|
3835
|
+
]
|
|
3836
|
+
},
|
|
3837
|
+
{
|
|
3838
|
+
name: "space-rename",
|
|
3839
|
+
description: "Rename a space",
|
|
3840
|
+
flags: ["--json"],
|
|
3841
|
+
quickReference: [
|
|
3842
|
+
{
|
|
3843
|
+
section: "write",
|
|
3844
|
+
usage: "space-rename <spaceId> <newName>",
|
|
3845
|
+
description: "Rename a space"
|
|
3846
|
+
}
|
|
3847
|
+
]
|
|
3848
|
+
},
|
|
3761
3849
|
{
|
|
3762
3850
|
name: "members",
|
|
3763
3851
|
description: "List workspace members",
|
|
@@ -3825,6 +3913,11 @@ var commandMetadata = [
|
|
|
3825
3913
|
section: "write",
|
|
3826
3914
|
usage: "bulk field <taskIds...>",
|
|
3827
3915
|
description: "Bulk set a custom field value on tasks"
|
|
3916
|
+
},
|
|
3917
|
+
{
|
|
3918
|
+
section: "write",
|
|
3919
|
+
usage: "bulk move <taskIds...>",
|
|
3920
|
+
description: "Move multiple tasks to a destination list"
|
|
3828
3921
|
}
|
|
3829
3922
|
]
|
|
3830
3923
|
},
|
|
@@ -4841,6 +4934,24 @@ ${renderZshTopLevelCommands(name)}
|
|
|
4841
4934
|
'2:name:' \\
|
|
4842
4935
|
'--json[Force JSON output]'
|
|
4843
4936
|
;;
|
|
4937
|
+
list-rename)
|
|
4938
|
+
_arguments \\
|
|
4939
|
+
'1:list_id:' \\
|
|
4940
|
+
'2:new_name:' \\
|
|
4941
|
+
'--json[Force JSON output]'
|
|
4942
|
+
;;
|
|
4943
|
+
folder-rename)
|
|
4944
|
+
_arguments \\
|
|
4945
|
+
'1:folder_id:' \\
|
|
4946
|
+
'2:new_name:' \\
|
|
4947
|
+
'--json[Force JSON output]'
|
|
4948
|
+
;;
|
|
4949
|
+
space-rename)
|
|
4950
|
+
_arguments \\
|
|
4951
|
+
'1:space_id:' \\
|
|
4952
|
+
'2:new_name:' \\
|
|
4953
|
+
'--json[Force JSON output]'
|
|
4954
|
+
;;
|
|
4844
4955
|
doc-create)
|
|
4845
4956
|
_arguments \\
|
|
4846
4957
|
'1:title:' \\
|
|
@@ -5370,7 +5481,7 @@ function parseFieldValue(field, rawValue) {
|
|
|
5370
5481
|
const available = options.map((o) => o.name).join(", ");
|
|
5371
5482
|
throw new Error(`Label "${name}" not found. Available: ${available}`);
|
|
5372
5483
|
}
|
|
5373
|
-
ids.push(
|
|
5484
|
+
ids.push(option.id);
|
|
5374
5485
|
}
|
|
5375
5486
|
return ids;
|
|
5376
5487
|
}
|
|
@@ -6051,31 +6162,34 @@ async function duplicateTask(config, taskId) {
|
|
|
6051
6162
|
return { id: created.id, name: created.name, url: created.url };
|
|
6052
6163
|
}
|
|
6053
6164
|
|
|
6054
|
-
// src/
|
|
6055
|
-
var BULK_CONCURRENCY = 5;
|
|
6165
|
+
// src/util/batch.ts
|
|
6056
6166
|
async function runInBatches(items, concurrency, fn) {
|
|
6167
|
+
if (!Number.isInteger(concurrency) || concurrency < 1) {
|
|
6168
|
+
throw new Error(`concurrency must be a positive integer, got ${concurrency}`);
|
|
6169
|
+
}
|
|
6057
6170
|
const results = [];
|
|
6058
6171
|
for (let i = 0; i < items.length; i += concurrency) {
|
|
6059
6172
|
const batch = items.slice(i, i + concurrency);
|
|
6060
|
-
const
|
|
6061
|
-
|
|
6173
|
+
const settled = await Promise.allSettled(batch.map(fn));
|
|
6174
|
+
settled.forEach((res, idx) => {
|
|
6062
6175
|
const item = batch[idx];
|
|
6063
6176
|
if (res.status === "fulfilled") {
|
|
6064
|
-
results.push({ item, result: res.value });
|
|
6177
|
+
results.push({ item, ok: true, result: res.value });
|
|
6065
6178
|
} else {
|
|
6066
|
-
|
|
6067
|
-
|
|
6068
|
-
error: res.reason instanceof Error ? res.reason : new Error(String(res.reason))
|
|
6069
|
-
});
|
|
6179
|
+
const error = res.reason instanceof Error ? res.reason : new Error(String(res.reason), { cause: res.reason });
|
|
6180
|
+
results.push({ item, ok: false, error });
|
|
6070
6181
|
}
|
|
6071
6182
|
});
|
|
6072
6183
|
}
|
|
6073
6184
|
return results;
|
|
6074
6185
|
}
|
|
6186
|
+
|
|
6187
|
+
// src/commands/bulk.ts
|
|
6188
|
+
var BULK_CONCURRENCY = 5;
|
|
6075
6189
|
function toBulkResult(outcomes) {
|
|
6076
6190
|
const failed = [];
|
|
6077
6191
|
for (const outcome of outcomes) {
|
|
6078
|
-
if (outcome.
|
|
6192
|
+
if (!outcome.ok) {
|
|
6079
6193
|
failed.push({ id: outcome.item, reason: outcome.error.message });
|
|
6080
6194
|
}
|
|
6081
6195
|
}
|
|
@@ -6145,6 +6259,16 @@ async function bulkField(config, fieldName, rawValue, taskIds) {
|
|
|
6145
6259
|
);
|
|
6146
6260
|
return toBulkResult(outcomes);
|
|
6147
6261
|
}
|
|
6262
|
+
async function bulkMove(config, listId, taskIds) {
|
|
6263
|
+
if (!listId) throw new Error("--to <listId> is required");
|
|
6264
|
+
if (taskIds.length === 0) throw new Error("Provide at least one task ID");
|
|
6265
|
+
const client = new ClickUpClient(config);
|
|
6266
|
+
const outcomes = await runInBatches(taskIds, BULK_CONCURRENCY, async (id) => {
|
|
6267
|
+
await client.moveTaskToList(id, listId);
|
|
6268
|
+
return id;
|
|
6269
|
+
});
|
|
6270
|
+
return toBulkResult(outcomes);
|
|
6271
|
+
}
|
|
6148
6272
|
|
|
6149
6273
|
// src/commands/goals.ts
|
|
6150
6274
|
import chalk16 from "chalk";
|
|
@@ -6401,14 +6525,14 @@ async function createView(config, listId, name, opts) {
|
|
|
6401
6525
|
}
|
|
6402
6526
|
|
|
6403
6527
|
// src/commands/view-update.ts
|
|
6404
|
-
var VALID_GROUP_BY_FIELDS2 = [
|
|
6528
|
+
var VALID_GROUP_BY_FIELDS2 = /* @__PURE__ */ new Set([
|
|
6405
6529
|
"status",
|
|
6406
6530
|
"assignee",
|
|
6407
6531
|
"priority",
|
|
6408
6532
|
"due_date",
|
|
6409
6533
|
"tag",
|
|
6410
6534
|
"sprint"
|
|
6411
|
-
];
|
|
6535
|
+
]);
|
|
6412
6536
|
async function updateView(config, viewId, opts) {
|
|
6413
6537
|
if (opts.name === void 0 && opts.groupBy === void 0) {
|
|
6414
6538
|
throw new Error("Provide at least one of: --name, --group-by");
|
|
@@ -6419,9 +6543,9 @@ async function updateView(config, viewId, opts) {
|
|
|
6419
6543
|
const payload = {};
|
|
6420
6544
|
if (opts.name) payload.name = opts.name;
|
|
6421
6545
|
if (opts.groupBy) {
|
|
6422
|
-
if (!VALID_GROUP_BY_FIELDS2.
|
|
6546
|
+
if (!VALID_GROUP_BY_FIELDS2.has(opts.groupBy)) {
|
|
6423
6547
|
throw new Error(
|
|
6424
|
-
`Invalid group-by field "${opts.groupBy}". Valid fields: ${VALID_GROUP_BY_FIELDS2.join(", ")}`
|
|
6548
|
+
`Invalid group-by field "${opts.groupBy}". Valid fields: ${[...VALID_GROUP_BY_FIELDS2].join(", ")}`
|
|
6425
6549
|
);
|
|
6426
6550
|
}
|
|
6427
6551
|
payload.grouping = { field: opts.groupBy };
|
|
@@ -6578,6 +6702,27 @@ async function copyStatusesFrom(client, sourceId) {
|
|
|
6578
6702
|
}
|
|
6579
6703
|
}
|
|
6580
6704
|
|
|
6705
|
+
// src/commands/list-rename.ts
|
|
6706
|
+
async function renameList(config, listId, newName) {
|
|
6707
|
+
const client = new ClickUpClient(config);
|
|
6708
|
+
const result = await client.updateList(listId, { name: newName });
|
|
6709
|
+
return { id: result.id, name: result.name };
|
|
6710
|
+
}
|
|
6711
|
+
|
|
6712
|
+
// src/commands/folder-rename.ts
|
|
6713
|
+
async function renameFolder(config, folderId, newName) {
|
|
6714
|
+
const client = new ClickUpClient(config);
|
|
6715
|
+
const result = await client.updateFolder(folderId, { name: newName });
|
|
6716
|
+
return { id: result.id, name: result.name };
|
|
6717
|
+
}
|
|
6718
|
+
|
|
6719
|
+
// src/commands/space-rename.ts
|
|
6720
|
+
async function renameSpace(config, spaceId, newName) {
|
|
6721
|
+
const client = new ClickUpClient(config);
|
|
6722
|
+
const result = await client.updateSpace(spaceId, { name: newName });
|
|
6723
|
+
return { id: result.id, name: result.name };
|
|
6724
|
+
}
|
|
6725
|
+
|
|
6581
6726
|
// src/commands/favorite.ts
|
|
6582
6727
|
var VALID_TYPES = /* @__PURE__ */ new Set([
|
|
6583
6728
|
"sprint-folder",
|
|
@@ -6797,7 +6942,7 @@ function buildProgram(programName = basename(process.argv[1] ?? "cup")) {
|
|
|
6797
6942
|
}
|
|
6798
6943
|
)
|
|
6799
6944
|
);
|
|
6800
|
-
program.command("create").description("Create a new task").option("-l, --list <listId>", 'Target list ID or "sprint:current" for active sprint').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 (find IDs with cup templates)").option("--json", "Force JSON output even in terminal").action(
|
|
6945
|
+
program.command("create").description("Create a new task").option("-l, --list <listId>", 'Target list ID or "sprint:current" for active sprint').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 (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(
|
|
6801
6946
|
wrapAction(async (opts) => {
|
|
6802
6947
|
const config = loadConfig(getProfileName());
|
|
6803
6948
|
if (opts.list === "sprint:current") {
|
|
@@ -6807,6 +6952,32 @@ function buildProgram(programName = basename(process.argv[1] ?? "cup")) {
|
|
|
6807
6952
|
const client = new ClickUpClient(config);
|
|
6808
6953
|
opts.assignee = String(await resolveAssigneeId(client, "me"));
|
|
6809
6954
|
}
|
|
6955
|
+
if (opts.field?.length) {
|
|
6956
|
+
if (opts.field.length % 2 !== 0) {
|
|
6957
|
+
throw new Error('--field requires pairs: --field "Name" value');
|
|
6958
|
+
}
|
|
6959
|
+
let listId = opts.list;
|
|
6960
|
+
if (!listId && opts.parent) {
|
|
6961
|
+
const client2 = new ClickUpClient(config);
|
|
6962
|
+
const parentTask = await client2.getTask(opts.parent);
|
|
6963
|
+
listId = parentTask.list.id;
|
|
6964
|
+
opts.list = listId;
|
|
6965
|
+
}
|
|
6966
|
+
if (!listId) {
|
|
6967
|
+
throw new Error("--field requires --list or --parent to resolve custom field names");
|
|
6968
|
+
}
|
|
6969
|
+
const client = new ClickUpClient(config);
|
|
6970
|
+
const fields = await client.getListCustomFields(listId);
|
|
6971
|
+
const customFields = [];
|
|
6972
|
+
for (let i = 0; i < opts.field.length; i += 2) {
|
|
6973
|
+
const fieldName = opts.field[i];
|
|
6974
|
+
const rawValue = opts.field[i + 1];
|
|
6975
|
+
const field = findFieldByName(fields, fieldName);
|
|
6976
|
+
const value = parseFieldValue(field, rawValue);
|
|
6977
|
+
customFields.push({ id: field.id, value });
|
|
6978
|
+
}
|
|
6979
|
+
opts.customFields = customFields;
|
|
6980
|
+
}
|
|
6810
6981
|
const result = await createTask(config, opts);
|
|
6811
6982
|
if (shouldOutputJson(opts.json ?? false)) {
|
|
6812
6983
|
console.log(JSON.stringify(result, null, 2));
|
|
@@ -7552,16 +7723,7 @@ function buildProgram(programName = basename(process.argv[1] ?? "cup")) {
|
|
|
7552
7723
|
wrapAction(async (status, taskIds, opts) => {
|
|
7553
7724
|
const config = loadConfig(getProfileName());
|
|
7554
7725
|
const result = await bulkUpdateStatus(config, taskIds, status);
|
|
7555
|
-
|
|
7556
|
-
console.log(JSON.stringify(result, null, 2));
|
|
7557
|
-
} else {
|
|
7558
|
-
console.log(`Updated ${result.updated} tasks to "${status}"`);
|
|
7559
|
-
if (result.failed.length > 0) {
|
|
7560
|
-
for (const f of result.failed) {
|
|
7561
|
-
console.log(` Failed ${f.id}: ${f.reason}`);
|
|
7562
|
-
}
|
|
7563
|
-
}
|
|
7564
|
-
}
|
|
7726
|
+
outputBulkResult(result, opts.json ?? false, `status ${status}`);
|
|
7565
7727
|
})
|
|
7566
7728
|
);
|
|
7567
7729
|
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(
|
|
@@ -7612,6 +7774,13 @@ function buildProgram(programName = basename(process.argv[1] ?? "cup")) {
|
|
|
7612
7774
|
outputBulkResult(result, opts.json ?? false, `field "${opts.set[0]}"`);
|
|
7613
7775
|
})
|
|
7614
7776
|
);
|
|
7777
|
+
bulkCmd.command("move <taskIds...>").description("Move multiple tasks to a single destination list").requiredOption("--to <listId>", "Destination list ID").option("--json", "Force JSON output even in terminal").action(
|
|
7778
|
+
wrapAction(async (taskIds, opts) => {
|
|
7779
|
+
const config = loadConfig(getProfileName());
|
|
7780
|
+
const result = await bulkMove(config, opts.to, taskIds);
|
|
7781
|
+
outputBulkResult(result, opts.json ?? false, `move to list ${opts.to}`);
|
|
7782
|
+
})
|
|
7783
|
+
);
|
|
7615
7784
|
program.command("goals").description("List goals in your workspace").option("--json", "Force JSON output even in terminal").action(
|
|
7616
7785
|
wrapAction(async (opts) => {
|
|
7617
7786
|
const config = loadConfig(getProfileName());
|
|
@@ -7844,6 +8013,42 @@ function buildProgram(programName = basename(process.argv[1] ?? "cup")) {
|
|
|
7844
8013
|
}
|
|
7845
8014
|
})
|
|
7846
8015
|
);
|
|
8016
|
+
program.command("list-rename <listId> <newName>").description("Rename a list").option("--json", "Force JSON output even in terminal").action(
|
|
8017
|
+
wrapAction(async (listId, newName, opts) => {
|
|
8018
|
+
if (!newName.trim()) throw new Error("List name cannot be empty");
|
|
8019
|
+
const config = loadConfig(getProfileName());
|
|
8020
|
+
const result = await renameList(config, listId, newName);
|
|
8021
|
+
if (shouldOutputJson(opts.json ?? false)) {
|
|
8022
|
+
console.log(JSON.stringify(result, null, 2));
|
|
8023
|
+
} else {
|
|
8024
|
+
console.log(`Renamed list ${result.id} to "${result.name}"`);
|
|
8025
|
+
}
|
|
8026
|
+
})
|
|
8027
|
+
);
|
|
8028
|
+
program.command("folder-rename <folderId> <newName>").description("Rename a folder").option("--json", "Force JSON output even in terminal").action(
|
|
8029
|
+
wrapAction(async (folderId, newName, opts) => {
|
|
8030
|
+
if (!newName.trim()) throw new Error("Folder name cannot be empty");
|
|
8031
|
+
const config = loadConfig(getProfileName());
|
|
8032
|
+
const result = await renameFolder(config, folderId, newName);
|
|
8033
|
+
if (shouldOutputJson(opts.json ?? false)) {
|
|
8034
|
+
console.log(JSON.stringify(result, null, 2));
|
|
8035
|
+
} else {
|
|
8036
|
+
console.log(`Renamed folder ${result.id} to "${result.name}"`);
|
|
8037
|
+
}
|
|
8038
|
+
})
|
|
8039
|
+
);
|
|
8040
|
+
program.command("space-rename <spaceId> <newName>").description("Rename a space").option("--json", "Force JSON output even in terminal").action(
|
|
8041
|
+
wrapAction(async (spaceId, newName, opts) => {
|
|
8042
|
+
if (!newName.trim()) throw new Error("Space name cannot be empty");
|
|
8043
|
+
const config = loadConfig(getProfileName());
|
|
8044
|
+
const result = await renameSpace(config, spaceId, newName);
|
|
8045
|
+
if (shouldOutputJson(opts.json ?? false)) {
|
|
8046
|
+
console.log(JSON.stringify(result, null, 2));
|
|
8047
|
+
} else {
|
|
8048
|
+
console.log(`Renamed space ${result.id} to "${result.name}"`);
|
|
8049
|
+
}
|
|
8050
|
+
})
|
|
8051
|
+
);
|
|
7847
8052
|
program.command("doc-create <title>").description("Create a new doc").option("-c, --content <text>", "Initial content (markdown)").option("--json", "Force JSON output even in terminal").action(
|
|
7848
8053
|
wrapAction(async (title, opts) => {
|
|
7849
8054
|
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.23.1
|
|
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.23.1, update with `npm install -g @krodak/clickup-cli` and refresh this skill with `cup skill`.
|
|
11
11
|
|
|
12
12
|
## Install & Configure
|
|
13
13
|
|
|
@@ -120,10 +120,11 @@ All commands support `--help` for full flag details. All commands support `--jso
|
|
|
120
120
|
| `cup activity <id>` | Task details + comment history combined |
|
|
121
121
|
| `cup inbox [--days n] [--include-closed]` | Tasks updated in last n days (default 30) |
|
|
122
122
|
| `cup summary [--hours n]` | Standup: completed, in-progress, overdue |
|
|
123
|
-
| `cup overdue [--include-closed]`
|
|
124
|
-
| `cup spaces [--name partial] [--my]`
|
|
125
|
-
| `cup lists <spaceId> [--name partial]`
|
|
126
|
-
| `cup folders <spaceId> [--name partial]`
|
|
123
|
+
| `cup overdue [--all] [--include-closed]` | Tasks past due date (most overdue first) |
|
|
124
|
+
| `cup spaces [--name partial] [--my] [--archived]` | List/filter workspace spaces |
|
|
125
|
+
| `cup lists <spaceId> [--name partial] [--archived]` | Lists in a space (including folder lists) |
|
|
126
|
+
| `cup folders <spaceId> [--name partial] [--archived]` | Folders in a space (with their lists) |
|
|
127
|
+
| `cup time-in-status <id>` | Show how long a task has been in each status |
|
|
127
128
|
| `cup members` | Workspace members (username, ID, email) |
|
|
128
129
|
| `cup fields <listId>` | Custom fields on a list (type, required, options) |
|
|
129
130
|
| `cup tags <spaceId>` | Tags available in a space |
|
|
@@ -143,72 +144,78 @@ All commands support `--help` for full flag details. All commands support `--jso
|
|
|
143
144
|
|
|
144
145
|
### Write
|
|
145
146
|
|
|
146
|
-
| Command
|
|
147
|
-
|
|
|
148
|
-
| `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]`
|
|
149
|
-
| `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)
|
|
150
|
-
| `cup comment <id> -m text [--notify-all]`
|
|
151
|
-
| `cup comment-edit <commentId> -m text [--resolved] [--unresolved]`
|
|
152
|
-
| `cup comment-delete <commentId>` or `cup comment-delete --task <taskId> --mine [--match text]`
|
|
153
|
-
| `cup replies <commentId>`
|
|
154
|
-
| `cup reply <commentId> -m text [--notify-all]`
|
|
155
|
-
| `cup assign <id> [--to ids\|me] [--remove ids\|me]`
|
|
156
|
-
| `cup depend <id> [--on taskId] [--blocks taskId] [--remove]`
|
|
157
|
-
| `cup move <id> [--to listId\|sprint:current] [--remove listId]`
|
|
158
|
-
| `cup field <id> [--set "Name" value] [--remove "Name"]`
|
|
159
|
-
| `cup field-create <name> -t <type> [-d desc] [--options "a,b,c"] [--required]`
|
|
160
|
-
| `cup tag <id> [--add tags] [--remove tags]`
|
|
161
|
-
| `cup link <taskId> <linksTo> [--remove]`
|
|
162
|
-
| `cup attach <taskId> <filePath>`
|
|
163
|
-
| `cup delete <id> [--confirm]`
|
|
164
|
-
| `cup duplicate <taskId>`
|
|
165
|
-
| `cup bulk status <status> <taskIds...>`
|
|
166
|
-
| `cup bulk assign <taskIds...> [--to userId\|me] [--remove userId\|me]`
|
|
167
|
-
| `cup bulk due-date <date\|none\|clear> <taskIds...>`
|
|
168
|
-
| `cup bulk tag <tagName> <taskIds...> [--
|
|
169
|
-
| `cup
|
|
170
|
-
| `cup
|
|
171
|
-
| `cup
|
|
172
|
-
| `cup checklist
|
|
173
|
-
| `cup checklist
|
|
174
|
-
| `cup checklist delete
|
|
175
|
-
| `cup
|
|
176
|
-
| `cup
|
|
177
|
-
| `cup
|
|
178
|
-
| `cup time
|
|
179
|
-
| `cup time
|
|
180
|
-
| `cup time
|
|
181
|
-
| `cup time
|
|
182
|
-
| `cup
|
|
183
|
-
| `cup
|
|
184
|
-
| `cup
|
|
185
|
-
| `cup
|
|
186
|
-
| `cup
|
|
187
|
-
| `cup
|
|
188
|
-
| `cup
|
|
189
|
-
| `cup
|
|
190
|
-
| `cup
|
|
191
|
-
| `cup doc-
|
|
192
|
-
| `cup doc-page-
|
|
193
|
-
| `cup
|
|
194
|
-
| `cup
|
|
195
|
-
| `cup
|
|
196
|
-
| `cup
|
|
197
|
-
| `cup
|
|
198
|
-
| `cup
|
|
199
|
-
| `cup list-
|
|
200
|
-
| `cup
|
|
201
|
-
| `cup
|
|
202
|
-
| `cup
|
|
203
|
-
| `cup
|
|
204
|
-
| `cup
|
|
205
|
-
| `cup
|
|
206
|
-
| `cup
|
|
207
|
-
| `cup
|
|
208
|
-
| `cup
|
|
209
|
-
| `cup
|
|
210
|
-
| `cup
|
|
211
|
-
| `cup
|
|
147
|
+
| Command | What it does |
|
|
148
|
+
| --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------ |
|
|
149
|
+
| `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]` | Create task (`--list` accepts `sprint:current`, `--field` sets custom fields inline) |
|
|
150
|
+
| `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) |
|
|
151
|
+
| `cup comment <id> -m text [--notify-all]` | Post comment on task |
|
|
152
|
+
| `cup comment-edit <commentId> -m text [--resolved] [--unresolved]` | Edit a comment |
|
|
153
|
+
| `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 |
|
|
154
|
+
| `cup replies <commentId>` | List threaded replies |
|
|
155
|
+
| `cup reply <commentId> -m text [--notify-all]` | Reply to a comment |
|
|
156
|
+
| `cup assign <id> [--to ids\|me] [--remove ids\|me]` | Assign/unassign users (`--to`/`--remove` accept comma-separated IDs) |
|
|
157
|
+
| `cup depend <id> [--on taskId] [--blocks taskId] [--remove]` | Add/remove dependencies |
|
|
158
|
+
| `cup move <id> [--to listId\|sprint:current] [--remove listId]` | Add/remove task from lists (`--to` accepts `sprint:current`) |
|
|
159
|
+
| `cup field <id> [--set "Name" value] [--remove "Name"]` | Set/remove custom field values |
|
|
160
|
+
| `cup field-create <name> -t <type> [-d desc] [--options "a,b,c"] [--required]` | Create a custom field |
|
|
161
|
+
| `cup tag <id> [--add tags] [--remove tags]` | Add/remove tags on a task |
|
|
162
|
+
| `cup link <taskId> <linksTo> [--remove]` | Link/unlink tasks |
|
|
163
|
+
| `cup attach <taskId> <filePath>` | Upload file attachment |
|
|
164
|
+
| `cup delete <id> [--confirm]` | Delete task (DESTRUCTIVE) |
|
|
165
|
+
| `cup duplicate <taskId>` | Duplicate a task |
|
|
166
|
+
| `cup bulk status <status> <taskIds...>` | Bulk update status |
|
|
167
|
+
| `cup bulk assign <taskIds...> [--to userId\|me] [--remove userId\|me]` | Bulk assign/unassign user from tasks |
|
|
168
|
+
| `cup bulk due-date <date\|none\|clear> <taskIds...>` | Bulk set or clear due dates |
|
|
169
|
+
| `cup bulk tag <tagName> <taskIds...> [--remove]` | Bulk add/remove tag from tasks |
|
|
170
|
+
| `cup bulk priority <taskIds...> --to <priority>` | Bulk set priority on many tasks |
|
|
171
|
+
| `cup bulk field <taskIds...> --set "Name" value` | Bulk set a custom field value |
|
|
172
|
+
| `cup bulk move <taskIds...> --to <listId>` | Bulk move tasks to a destination list |
|
|
173
|
+
| `cup checklist view <id>` | View checklists on a task |
|
|
174
|
+
| `cup checklist create <id> <name>` | Create a checklist |
|
|
175
|
+
| `cup checklist delete <checklistId>` | Delete a checklist |
|
|
176
|
+
| `cup checklist add-item <checklistId> <name>` | Add item to checklist |
|
|
177
|
+
| `cup checklist edit-item <checklistId> <itemId> [--name n] [--resolved] [--unresolved] [--assignee id]` | Edit checklist item |
|
|
178
|
+
| `cup checklist delete-item <checklistId> <itemId>` | Delete checklist item |
|
|
179
|
+
| `cup time start <taskId> [-d desc]` | Start timer |
|
|
180
|
+
| `cup time stop` | Stop running timer |
|
|
181
|
+
| `cup time status` | Show running timer |
|
|
182
|
+
| `cup time log <taskId> <duration> [-d desc]` | Log manual entry (e.g. "2h", "30m") |
|
|
183
|
+
| `cup time list [--days n] [--task id] [--all]` | List my recent time entries (--all for team) |
|
|
184
|
+
| `cup time update <timeEntryId> [-d desc] [--duration dur]` | Update time entry |
|
|
185
|
+
| `cup time delete <timeEntryId>` | Delete time entry |
|
|
186
|
+
| `cup goal-create <name> [-d desc] [--color hex]` | Create a goal |
|
|
187
|
+
| `cup goal-update <goalId> [-n name] [-d desc] [--color hex]` | Update a goal |
|
|
188
|
+
| `cup goal-delete <goalId>` | Delete a goal |
|
|
189
|
+
| `cup key-result-create <goalId> <name> [--type t] [--target n]` | Create key result |
|
|
190
|
+
| `cup key-result-update <keyResultId> [--progress n] [--note text]` | Update key result |
|
|
191
|
+
| `cup key-result-delete <keyResultId>` | Delete key result |
|
|
192
|
+
| `cup doc-create <title> [-c content]` | Create a doc |
|
|
193
|
+
| `cup doc-page-create <docId> <name> [-c content] [--parent-page pageId]` | Create doc page |
|
|
194
|
+
| `cup doc-page-edit <docId> <pageId> [--name text] [-c content]` | Edit doc page |
|
|
195
|
+
| `cup doc-delete <docId>` | Delete a doc |
|
|
196
|
+
| `cup doc-page-delete <docId> <pageId>` | Delete doc page |
|
|
197
|
+
| `cup space-create <name>` | Create a space |
|
|
198
|
+
| `cup list-create <spaceId> <name> [--folder folderId] [--copy-statuses-from id]` | Create a list in a space or folder |
|
|
199
|
+
| `cup folder-create <spaceId> <name>` | Create a folder in a space |
|
|
200
|
+
| `cup list-rename <listId> <newName>` | Rename a list |
|
|
201
|
+
| `cup folder-rename <folderId> <newName>` | Rename a folder |
|
|
202
|
+
| `cup space-rename <spaceId> <newName>` | Rename a space |
|
|
203
|
+
| `cup tag-create <spaceId> <name> [--fg color] [--bg color]` | Create space tag |
|
|
204
|
+
| `cup tag-update <spaceId> <tagName> --name <newName> [--fg c] [--bg c]` | Update space tag |
|
|
205
|
+
| `cup tag-delete <spaceId> <name>` | Delete space tag |
|
|
206
|
+
| `cup list-from-template <name> --template <id> [--space id] [--folder id]` | Create list from template |
|
|
207
|
+
| `cup view-create <listId> <name> -t <type> [--group-by field]` | Create a view on a list |
|
|
208
|
+
| `cup view-update <viewId> [-n name] [--group-by field]` | Update a view |
|
|
209
|
+
| `cup view-delete <viewId> [--confirm]` | Delete a view (DESTRUCTIVE) |
|
|
210
|
+
| `cup favorite add <type> <id> [alias] [-n name]` | Add a local favorite |
|
|
211
|
+
| `cup favorite remove <alias>` | Remove a favorite |
|
|
212
|
+
| `cup favorite list [--type t]` | List favorites (optionally filter by type) |
|
|
213
|
+
| `cup profile list [--json]` | List all profiles |
|
|
214
|
+
| `cup profile add <name>` | Add a new profile (interactive) |
|
|
215
|
+
| `cup profile remove <name>` | Remove a profile |
|
|
216
|
+
| `cup profile use <name>` | Set the default profile |
|
|
217
|
+
| `cup config get <key>` / `set <key> <value>` / `path` | Manage config |
|
|
218
|
+
| `cup completion <shell>` | Shell completions (bash/zsh/fish) |
|
|
212
219
|
|
|
213
220
|
## Global Flags
|
|
214
221
|
|
|
@@ -287,6 +294,7 @@ cup create -n "Fix the thing" -p abc123def
|
|
|
287
294
|
cup create -n "Fix bug" -l <listId> --priority urgent --tags "bug,frontend"
|
|
288
295
|
cup create -n "Bug fix" -l sprint:current # create in active sprint
|
|
289
296
|
cup create -n "Q3 Roadmap" -l <listId> --custom-item-id 1
|
|
297
|
+
cup create -n "New story" -l <listId> --field "Story Points" 5 --field "Stage" "In Review"
|
|
290
298
|
cup comment abc123def -m "Completed in PR #42"
|
|
291
299
|
cup assign abc123def --to me
|
|
292
300
|
cup assign abc123def --to 12345,67890 # assign multiple users at once
|
|
@@ -326,6 +334,9 @@ cup space-create "New Space" # create a space
|
|
|
326
334
|
cup folder-create <spaceId> "Q2" # create a folder
|
|
327
335
|
cup list-create <spaceId> "Backlog" # create a list
|
|
328
336
|
cup list-create <spaceId> "Sprint" --folder <folderId>
|
|
337
|
+
cup space-rename <spaceId> "Platform" # rename a space
|
|
338
|
+
cup folder-rename <folderId> "Q3" # rename a folder
|
|
339
|
+
cup list-rename <listId> "Sprint 12" # rename a list
|
|
329
340
|
cup members # workspace members
|
|
330
341
|
cup fields <listId> # custom fields on a list
|
|
331
342
|
cup task-types # custom task types
|