@krodak/clickup-cli 1.21.1 → 1.22.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 +14 -3
- package/dist/index.js +308 -127
- package/package.json +1 -1
- package/skills/clickup-cli/SKILL.md +31 -30
|
@@ -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.22.1",
|
|
5
5
|
"author": {
|
|
6
6
|
"name": "Krzysztof Rodak"
|
|
7
7
|
},
|
package/README.md
CHANGED
|
@@ -16,13 +16,24 @@ npm install -g @krodak/clickup-cli && cup init
|
|
|
16
16
|
|
|
17
17
|
## For AI Agents
|
|
18
18
|
|
|
19
|
-
Paste this into any AI agent
|
|
19
|
+
Paste this into any AI agent (Claude Code, Codex, Cursor, OpenCode, etc.):
|
|
20
20
|
|
|
21
21
|
```
|
|
22
|
-
|
|
22
|
+
Install and configure the ClickUp CLI for me. Fetch the setup guide from:
|
|
23
|
+
https://raw.githubusercontent.com/krodak/clickup-cli/main/skills/clickup-cli/SKILL.md
|
|
24
|
+
|
|
25
|
+
Then walk me through installing the CLI, getting a ClickUp API token,
|
|
26
|
+
and running cup init. Finally, install the skill with `cup skill` so
|
|
27
|
+
you have persistent access to the full command reference.
|
|
23
28
|
```
|
|
24
29
|
|
|
25
|
-
|
|
30
|
+
The fetched SKILL.md contains everything the agent needs: install commands,
|
|
31
|
+
where to get a ClickUp API token, non-interactive setup with `cup init --token --team`,
|
|
32
|
+
and the complete command reference. After setup, the agent can run any `cup` command
|
|
33
|
+
to manage your tasks, sprints, comments, time tracking, and more.
|
|
34
|
+
|
|
35
|
+
**Already have the CLI installed?** Just run `cup skill` to install the agent skill to
|
|
36
|
+
all detected locations (see [Set up your agent](#set-up-your-agent) below).
|
|
26
37
|
|
|
27
38
|
## Talk to your agent
|
|
28
39
|
|
package/dist/index.js
CHANGED
|
@@ -286,8 +286,10 @@ var ClickUpClient = class {
|
|
|
286
286
|
body: JSON.stringify({ name, multiple_assignees: true })
|
|
287
287
|
});
|
|
288
288
|
}
|
|
289
|
-
async getSpaces(teamId) {
|
|
290
|
-
const data = await this.request(
|
|
289
|
+
async getSpaces(teamId, archived = false) {
|
|
290
|
+
const data = await this.request(
|
|
291
|
+
`/team/${teamId}/space?archived=${archived ? "true" : "false"}`
|
|
292
|
+
);
|
|
291
293
|
return readCollectionField(data, "spaces", "spaces");
|
|
292
294
|
}
|
|
293
295
|
async getCustomTaskTypes(teamId) {
|
|
@@ -324,18 +326,22 @@ var ClickUpClient = class {
|
|
|
324
326
|
body: JSON.stringify({ name })
|
|
325
327
|
});
|
|
326
328
|
}
|
|
327
|
-
async getLists(spaceId) {
|
|
328
|
-
const data = await this.request(
|
|
329
|
+
async getLists(spaceId, archived = false) {
|
|
330
|
+
const data = await this.request(
|
|
331
|
+
`/space/${spaceId}/list?archived=${archived ? "true" : "false"}`
|
|
332
|
+
);
|
|
329
333
|
return readCollectionField(data, "lists", "space lists");
|
|
330
334
|
}
|
|
331
|
-
async getFolders(spaceId) {
|
|
335
|
+
async getFolders(spaceId, archived = false) {
|
|
332
336
|
const data = await this.request(
|
|
333
|
-
`/space/${spaceId}/folder?archived
|
|
337
|
+
`/space/${spaceId}/folder?archived=${archived ? "true" : "false"}`
|
|
334
338
|
);
|
|
335
339
|
return readCollectionField(data, "folders", "space folders");
|
|
336
340
|
}
|
|
337
|
-
async getFolderLists(folderId) {
|
|
338
|
-
const data = await this.request(
|
|
341
|
+
async getFolderLists(folderId, archived = false) {
|
|
342
|
+
const data = await this.request(
|
|
343
|
+
`/folder/${folderId}/list?archived=${archived ? "true" : "false"}`
|
|
344
|
+
);
|
|
339
345
|
return readCollectionField(data, "lists", "folder lists");
|
|
340
346
|
}
|
|
341
347
|
async getListViews(listId) {
|
|
@@ -1015,7 +1021,9 @@ function loadConfig(profileName) {
|
|
|
1015
1021
|
if (envToken || envTeamId) {
|
|
1016
1022
|
throw new Error("Both CU_API_TOKEN and CU_TEAM_ID must be set, or run: cup init");
|
|
1017
1023
|
}
|
|
1018
|
-
throw new Error(
|
|
1024
|
+
throw new Error(
|
|
1025
|
+
"No ClickUp CLI configuration found.\n\nTo get started:\n cup init\n\nFor scripts or AI agents:\n cup init --token pk_YOUR_TOKEN --team YOUR_TEAM_ID\n\nGet your API token: https://app.clickup.com/settings/apps"
|
|
1026
|
+
);
|
|
1019
1027
|
}
|
|
1020
1028
|
const { parsed } = parseRawConfig(path);
|
|
1021
1029
|
if (isOldFormat(parsed)) {
|
|
@@ -1945,10 +1953,16 @@ function buildUpdatePayload(opts, timezone) {
|
|
|
1945
1953
|
}
|
|
1946
1954
|
if (opts.archive) payload.archived = true;
|
|
1947
1955
|
if (opts.unarchive) payload.archived = false;
|
|
1956
|
+
if (opts.type !== void 0) {
|
|
1957
|
+
const num = Number(opts.type);
|
|
1958
|
+
if (Number.isInteger(num) && num >= 0) {
|
|
1959
|
+
payload.custom_item_id = num;
|
|
1960
|
+
}
|
|
1961
|
+
}
|
|
1948
1962
|
return payload;
|
|
1949
1963
|
}
|
|
1950
1964
|
function hasUpdateFields(options) {
|
|
1951
|
-
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;
|
|
1965
|
+
return options.name !== void 0 || options.description !== void 0 || options.markdown_content !== void 0 || options.status !== void 0 || options.priority !== void 0 || options.due_date !== void 0 || options.start_date !== void 0 || options.time_estimate !== void 0 || options.assignees !== void 0 || options.parent !== void 0 || options.archived !== void 0 || options.custom_item_id !== void 0;
|
|
1952
1966
|
}
|
|
1953
1967
|
async function resolveStatus(client, taskId, statusInput) {
|
|
1954
1968
|
const task = await client.getTask(taskId);
|
|
@@ -1964,16 +1978,29 @@ async function resolveStatus(client, taskId, statusInput) {
|
|
|
1964
1978
|
}
|
|
1965
1979
|
return matched;
|
|
1966
1980
|
}
|
|
1967
|
-
async function
|
|
1968
|
-
|
|
1981
|
+
async function resolveTaskType2(client, teamId, typeInput) {
|
|
1982
|
+
const types = await client.getCustomTaskTypes(teamId);
|
|
1983
|
+
const lower = typeInput.toLowerCase();
|
|
1984
|
+
const match = types.find((t) => t.name.toLowerCase() === lower);
|
|
1985
|
+
if (!match) {
|
|
1986
|
+
const available = types.map((t) => `${t.name} (${String(t.id)})`).join(", ");
|
|
1987
|
+
throw new Error(`No matching task type for "${typeInput}". Available: ${available}`);
|
|
1988
|
+
}
|
|
1989
|
+
return match.id;
|
|
1990
|
+
}
|
|
1991
|
+
async function updateTask(config, taskId, options, typeInput) {
|
|
1992
|
+
if (!hasUpdateFields(options) && typeInput === void 0)
|
|
1969
1993
|
throw new Error(
|
|
1970
|
-
"Provide at least one of: --name, --description, --status, --priority, --due-date, --start-date, --time-estimate, --assignee, --remove-assignee, --parent, --detach, --archive, --unarchive"
|
|
1994
|
+
"Provide at least one of: --name, --description, --status, --priority, --due-date, --start-date, --time-estimate, --assignee, --remove-assignee, --parent, --detach, --archive, --unarchive, --type"
|
|
1971
1995
|
);
|
|
1972
1996
|
const client = new ClickUpClient(config);
|
|
1973
1997
|
const resolved = { ...options };
|
|
1974
1998
|
if (resolved.status !== void 0) {
|
|
1975
1999
|
resolved.status = await resolveStatus(client, taskId, resolved.status);
|
|
1976
2000
|
}
|
|
2001
|
+
if (resolved.custom_item_id === void 0 && typeInput !== void 0) {
|
|
2002
|
+
resolved.custom_item_id = await resolveTaskType2(client, config.teamId, typeInput);
|
|
2003
|
+
}
|
|
1977
2004
|
const task = await client.updateTask(taskId, resolved);
|
|
1978
2005
|
return { id: task.id, name: task.name };
|
|
1979
2006
|
}
|
|
@@ -2040,31 +2067,75 @@ async function getTask(config, taskId) {
|
|
|
2040
2067
|
// src/commands/init.ts
|
|
2041
2068
|
import { password, select, confirm as confirm2 } from "@inquirer/prompts";
|
|
2042
2069
|
import fs2 from "fs";
|
|
2070
|
+
var TOKEN_URL = "https://app.clickup.com/settings/apps";
|
|
2071
|
+
var TOKEN_HELP = `
|
|
2072
|
+
How to get a ClickUp API token:
|
|
2073
|
+
1. Open ${TOKEN_URL}
|
|
2074
|
+
2. Find the "API Token" section, click "Generate" (or copy the existing one)
|
|
2075
|
+
3. The token starts with "pk_"
|
|
2076
|
+
`;
|
|
2077
|
+
var NON_TTY_HELP = `cup init requires an interactive terminal.
|
|
2078
|
+
|
|
2079
|
+
For scripts, CI, or AI agents, use flags:
|
|
2080
|
+
cup init --token pk_YOUR_TOKEN --team YOUR_TEAM_ID
|
|
2081
|
+
|
|
2082
|
+
Or set environment variables:
|
|
2083
|
+
export CU_API_TOKEN=pk_YOUR_TOKEN
|
|
2084
|
+
export CU_TEAM_ID=YOUR_TEAM_ID
|
|
2085
|
+
${TOKEN_HELP}`;
|
|
2086
|
+
var NEXT_STEPS = `
|
|
2087
|
+
Next steps:
|
|
2088
|
+
cup auth # verify setup
|
|
2089
|
+
cup tasks # list your assigned tasks
|
|
2090
|
+
cup sprint # show current sprint
|
|
2091
|
+
cup --help # see all commands
|
|
2092
|
+
`;
|
|
2093
|
+
function validateTokenFormat(token) {
|
|
2094
|
+
if (!token.startsWith("pk_")) {
|
|
2095
|
+
throw new Error(
|
|
2096
|
+
`Invalid token format. Personal API tokens start with "pk_".
|
|
2097
|
+
${TOKEN_HELP}`
|
|
2098
|
+
);
|
|
2099
|
+
}
|
|
2100
|
+
}
|
|
2101
|
+
async function verifyToken(apiToken) {
|
|
2102
|
+
const client = new ClickUpClient({ apiToken });
|
|
2103
|
+
try {
|
|
2104
|
+
const me = await client.getMe();
|
|
2105
|
+
return me.username;
|
|
2106
|
+
} catch (err) {
|
|
2107
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
2108
|
+
throw new Error(
|
|
2109
|
+
`Token verification failed: ${msg}
|
|
2110
|
+
|
|
2111
|
+
Check the token is correct and not expired.
|
|
2112
|
+
${TOKEN_HELP}`,
|
|
2113
|
+
{ cause: err }
|
|
2114
|
+
);
|
|
2115
|
+
}
|
|
2116
|
+
}
|
|
2043
2117
|
async function runInitCommand(opts) {
|
|
2044
2118
|
if (opts?.token && opts?.team) {
|
|
2045
2119
|
const apiToken2 = opts.token.trim();
|
|
2046
|
-
|
|
2047
|
-
const
|
|
2048
|
-
let username2;
|
|
2049
|
-
try {
|
|
2050
|
-
const me = await client2.getMe();
|
|
2051
|
-
username2 = me.username;
|
|
2052
|
-
} catch (err) {
|
|
2053
|
-
throw new Error(`Invalid token: ${err instanceof Error ? err.message : String(err)}`, {
|
|
2054
|
-
cause: err
|
|
2055
|
-
});
|
|
2056
|
-
}
|
|
2120
|
+
validateTokenFormat(apiToken2);
|
|
2121
|
+
const username2 = await verifyToken(apiToken2);
|
|
2057
2122
|
process.stdout.write(`Authenticated as @${username2}
|
|
2058
2123
|
`);
|
|
2059
2124
|
writeConfig({ apiToken: apiToken2, teamId: opts.team });
|
|
2060
2125
|
process.stdout.write(`Config written to ${getConfigPath()}
|
|
2061
|
-
`);
|
|
2126
|
+
${NEXT_STEPS}`);
|
|
2062
2127
|
return;
|
|
2063
2128
|
}
|
|
2064
2129
|
if (opts?.token || opts?.team) {
|
|
2065
2130
|
throw new Error("Both --token and --team are required for non-interactive setup");
|
|
2066
2131
|
}
|
|
2132
|
+
if (!process.stdin.isTTY) {
|
|
2133
|
+
throw new Error(NON_TTY_HELP);
|
|
2134
|
+
}
|
|
2067
2135
|
const configPath3 = getConfigPath();
|
|
2136
|
+
process.stdout.write("\nWelcome to ClickUp CLI!\n");
|
|
2137
|
+
process.stdout.write(TOKEN_HELP);
|
|
2138
|
+
process.stdout.write("\n");
|
|
2068
2139
|
if (fs2.existsSync(configPath3)) {
|
|
2069
2140
|
const overwrite = await confirm2({
|
|
2070
2141
|
message: `Config already exists at ${configPath3}. Overwrite?`,
|
|
@@ -2075,20 +2146,14 @@ async function runInitCommand(opts) {
|
|
|
2075
2146
|
return;
|
|
2076
2147
|
}
|
|
2077
2148
|
}
|
|
2078
|
-
const apiToken = (await password({
|
|
2079
|
-
|
|
2080
|
-
|
|
2081
|
-
|
|
2082
|
-
|
|
2083
|
-
const me = await client.getMe();
|
|
2084
|
-
username = me.username;
|
|
2085
|
-
} catch (err) {
|
|
2086
|
-
throw new Error(`Invalid token: ${err instanceof Error ? err.message : String(err)}`, {
|
|
2087
|
-
cause: err
|
|
2088
|
-
});
|
|
2089
|
-
}
|
|
2149
|
+
const apiToken = (await password({
|
|
2150
|
+
message: "Paste your ClickUp API token (starts with pk_):"
|
|
2151
|
+
})).trim();
|
|
2152
|
+
validateTokenFormat(apiToken);
|
|
2153
|
+
const username = await verifyToken(apiToken);
|
|
2090
2154
|
process.stdout.write(`Authenticated as @${username}
|
|
2091
2155
|
`);
|
|
2156
|
+
const client = new ClickUpClient({ apiToken });
|
|
2092
2157
|
const teams = await client.getTeams();
|
|
2093
2158
|
if (teams.length === 0) throw new Error("No workspaces found for this token.");
|
|
2094
2159
|
let teamId;
|
|
@@ -2105,8 +2170,9 @@ async function runInitCommand(opts) {
|
|
|
2105
2170
|
});
|
|
2106
2171
|
}
|
|
2107
2172
|
writeConfig({ apiToken, teamId });
|
|
2108
|
-
process.stdout.write(`
|
|
2109
|
-
|
|
2173
|
+
process.stdout.write(`
|
|
2174
|
+
Config written to ${configPath3}
|
|
2175
|
+
${NEXT_STEPS}`);
|
|
2110
2176
|
}
|
|
2111
2177
|
|
|
2112
2178
|
// src/commands/sprint.ts
|
|
@@ -2502,12 +2568,14 @@ function printComments(comments, forceJson) {
|
|
|
2502
2568
|
async function fetchLists(config, spaceId, opts = {}) {
|
|
2503
2569
|
const client = new ClickUpClient(config);
|
|
2504
2570
|
const results = [];
|
|
2505
|
-
const folderlessLists = await client.getLists(spaceId);
|
|
2571
|
+
const folderlessLists = await client.getLists(spaceId, opts.archived);
|
|
2506
2572
|
for (const list of folderlessLists) {
|
|
2507
2573
|
results.push({ id: list.id, name: list.name, folder: "(none)" });
|
|
2508
2574
|
}
|
|
2509
|
-
const folders = await client.getFolders(spaceId);
|
|
2510
|
-
const folderListArrays = await Promise.all(
|
|
2575
|
+
const folders = await client.getFolders(spaceId, opts.archived);
|
|
2576
|
+
const folderListArrays = await Promise.all(
|
|
2577
|
+
folders.map((f) => client.getFolderLists(f.id, opts.archived))
|
|
2578
|
+
);
|
|
2511
2579
|
for (let i = 0; i < folders.length; i++) {
|
|
2512
2580
|
const folder = folders[i];
|
|
2513
2581
|
for (const list of folderListArrays[i]) {
|
|
@@ -2637,7 +2705,7 @@ async function printInbox(tasks, forceJson, config) {
|
|
|
2637
2705
|
// src/commands/spaces.ts
|
|
2638
2706
|
async function listSpaces(config, opts) {
|
|
2639
2707
|
const client = new ClickUpClient(config);
|
|
2640
|
-
let spaces = await client.getSpaces(config.teamId);
|
|
2708
|
+
let spaces = await client.getSpaces(config.teamId, opts.archived);
|
|
2641
2709
|
if (opts.name) {
|
|
2642
2710
|
const lower = opts.name.toLowerCase();
|
|
2643
2711
|
spaces = spaces.filter((s) => s.name.toLowerCase().includes(lower));
|
|
@@ -2949,6 +3017,9 @@ function configPath2() {
|
|
|
2949
3017
|
}
|
|
2950
3018
|
|
|
2951
3019
|
// src/commands/assign.ts
|
|
3020
|
+
function parseIdList(value) {
|
|
3021
|
+
return value.split(",").map((v) => v.trim()).filter((v) => v.length > 0);
|
|
3022
|
+
}
|
|
2952
3023
|
async function assignTask(config, taskId, opts) {
|
|
2953
3024
|
if (!opts.to && !opts.remove) {
|
|
2954
3025
|
throw new Error("Provide at least one of: --to, --remove");
|
|
@@ -2957,10 +3028,14 @@ async function assignTask(config, taskId, opts) {
|
|
|
2957
3028
|
const add = [];
|
|
2958
3029
|
const rem = [];
|
|
2959
3030
|
if (opts.to) {
|
|
2960
|
-
|
|
3031
|
+
for (const value of parseIdList(opts.to)) {
|
|
3032
|
+
add.push(await resolveAssigneeId(client, value));
|
|
3033
|
+
}
|
|
2961
3034
|
}
|
|
2962
3035
|
if (opts.remove) {
|
|
2963
|
-
|
|
3036
|
+
for (const value of parseIdList(opts.remove)) {
|
|
3037
|
+
rem.push(await resolveAssigneeId(client, value));
|
|
3038
|
+
}
|
|
2964
3039
|
}
|
|
2965
3040
|
return client.updateTask(taskId, {
|
|
2966
3041
|
assignees: {
|
|
@@ -3102,9 +3177,15 @@ function printTimeInStatus(result, forceJson) {
|
|
|
3102
3177
|
var commandMetadata = [
|
|
3103
3178
|
{
|
|
3104
3179
|
name: "init",
|
|
3105
|
-
description: "Set up cup for
|
|
3180
|
+
description: "Set up cup (interactive). Use --token and --team for non-interactive/agent setup",
|
|
3106
3181
|
flags: ["--token", "--team"],
|
|
3107
|
-
quickReference: [
|
|
3182
|
+
quickReference: [
|
|
3183
|
+
{
|
|
3184
|
+
section: "setup",
|
|
3185
|
+
usage: "init",
|
|
3186
|
+
description: "First-time setup (interactive, or use --token --team for agents)"
|
|
3187
|
+
}
|
|
3188
|
+
]
|
|
3108
3189
|
},
|
|
3109
3190
|
{
|
|
3110
3191
|
name: "auth",
|
|
@@ -3164,6 +3245,7 @@ var commandMetadata = [
|
|
|
3164
3245
|
"--detach",
|
|
3165
3246
|
"--archive",
|
|
3166
3247
|
"--unarchive",
|
|
3248
|
+
"--type",
|
|
3167
3249
|
"--field",
|
|
3168
3250
|
"--json"
|
|
3169
3251
|
],
|
|
@@ -3294,7 +3376,7 @@ var commandMetadata = [
|
|
|
3294
3376
|
{
|
|
3295
3377
|
name: "lists",
|
|
3296
3378
|
description: "List all lists in a space (including lists inside folders)",
|
|
3297
|
-
flags: ["--name", "--json"],
|
|
3379
|
+
flags: ["--name", "--archived", "--json"],
|
|
3298
3380
|
quickReference: [
|
|
3299
3381
|
{ section: "read", usage: "lists <spaceId>", description: "List all lists in a space" }
|
|
3300
3382
|
]
|
|
@@ -3302,7 +3384,7 @@ var commandMetadata = [
|
|
|
3302
3384
|
{
|
|
3303
3385
|
name: "spaces",
|
|
3304
3386
|
description: "List spaces in your workspace",
|
|
3305
|
-
flags: ["--name", "--my", "--json"],
|
|
3387
|
+
flags: ["--name", "--my", "--archived", "--json"],
|
|
3306
3388
|
quickReference: [{ section: "read", usage: "spaces", description: "List spaces in workspace" }]
|
|
3307
3389
|
},
|
|
3308
3390
|
{
|
|
@@ -3627,7 +3709,7 @@ var commandMetadata = [
|
|
|
3627
3709
|
{
|
|
3628
3710
|
name: "folders",
|
|
3629
3711
|
description: "List folders in a space (with their lists)",
|
|
3630
|
-
flags: ["--name", "--json"],
|
|
3712
|
+
flags: ["--name", "--archived", "--json"],
|
|
3631
3713
|
quickReference: [
|
|
3632
3714
|
{ section: "read", usage: "folders <spaceId>", description: "List folders in a space" }
|
|
3633
3715
|
]
|
|
@@ -3733,6 +3815,16 @@ var commandMetadata = [
|
|
|
3733
3815
|
section: "write",
|
|
3734
3816
|
usage: "bulk tag <tagName> <taskIds...>",
|
|
3735
3817
|
description: "Bulk add/remove tag"
|
|
3818
|
+
},
|
|
3819
|
+
{
|
|
3820
|
+
section: "write",
|
|
3821
|
+
usage: "bulk priority <taskIds...>",
|
|
3822
|
+
description: "Bulk set priority on tasks"
|
|
3823
|
+
},
|
|
3824
|
+
{
|
|
3825
|
+
section: "write",
|
|
3826
|
+
usage: "bulk field <taskIds...>",
|
|
3827
|
+
description: "Bulk set a custom field value on tasks"
|
|
3736
3828
|
}
|
|
3737
3829
|
]
|
|
3738
3830
|
},
|
|
@@ -3981,7 +4073,7 @@ function parseCommandFlags(flags = []) {
|
|
|
3981
4073
|
}
|
|
3982
4074
|
function commandDescription(command, programName = "cup") {
|
|
3983
4075
|
if (command.name === "init") {
|
|
3984
|
-
return `Set up ${programName} for
|
|
4076
|
+
return `Set up ${programName} (interactive). Use --token and --team for non-interactive/agent setup`;
|
|
3985
4077
|
}
|
|
3986
4078
|
return command.description;
|
|
3987
4079
|
}
|
|
@@ -5219,7 +5311,11 @@ var SUPPORTED_TYPES = /* @__PURE__ */ new Set([
|
|
|
5219
5311
|
"checkbox",
|
|
5220
5312
|
"date",
|
|
5221
5313
|
"url",
|
|
5222
|
-
"email"
|
|
5314
|
+
"email",
|
|
5315
|
+
"emoji",
|
|
5316
|
+
"manual_progress",
|
|
5317
|
+
"tasks",
|
|
5318
|
+
"users"
|
|
5223
5319
|
]);
|
|
5224
5320
|
function findFieldByName(fields, name) {
|
|
5225
5321
|
const lower = name.toLowerCase();
|
|
@@ -5284,6 +5380,30 @@ function parseFieldValue(field, rawValue) {
|
|
|
5284
5380
|
throw new Error(`Value "${rawValue}" is not a valid date (use YYYY-MM-DD)`);
|
|
5285
5381
|
return ms;
|
|
5286
5382
|
}
|
|
5383
|
+
case "emoji": {
|
|
5384
|
+
const n = Number(rawValue);
|
|
5385
|
+
if (!Number.isFinite(n) || n < 0 || n > 5) {
|
|
5386
|
+
throw new Error("Rating value must be a number between 0 and 5");
|
|
5387
|
+
}
|
|
5388
|
+
return n;
|
|
5389
|
+
}
|
|
5390
|
+
case "manual_progress": {
|
|
5391
|
+
const n = Number(rawValue);
|
|
5392
|
+
if (!Number.isFinite(n) || n < 0 || n > 100) {
|
|
5393
|
+
throw new Error("Progress value must be a number between 0 and 100");
|
|
5394
|
+
}
|
|
5395
|
+
return { current: n };
|
|
5396
|
+
}
|
|
5397
|
+
case "tasks": {
|
|
5398
|
+
const ids = rawValue.split(",").map((s) => s.trim()).filter(Boolean);
|
|
5399
|
+
if (ids.length === 0) throw new Error("Provide at least one task ID (comma-separated)");
|
|
5400
|
+
return { add: ids };
|
|
5401
|
+
}
|
|
5402
|
+
case "users": {
|
|
5403
|
+
const ids = rawValue.split(",").map((s) => s.trim()).filter(Boolean);
|
|
5404
|
+
if (ids.length === 0) throw new Error("Provide at least one user ID (comma-separated)");
|
|
5405
|
+
return { add: ids.map(Number) };
|
|
5406
|
+
}
|
|
5287
5407
|
default:
|
|
5288
5408
|
return rawValue;
|
|
5289
5409
|
}
|
|
@@ -5668,9 +5788,9 @@ async function deleteDocPage(config, docId, pageId) {
|
|
|
5668
5788
|
|
|
5669
5789
|
// src/commands/folders.ts
|
|
5670
5790
|
import chalk12 from "chalk";
|
|
5671
|
-
async function listFolders(config, spaceId, nameFilter) {
|
|
5791
|
+
async function listFolders(config, spaceId, nameFilter, archived) {
|
|
5672
5792
|
const client = new ClickUpClient(config);
|
|
5673
|
-
const folders = await client.getFolders(spaceId);
|
|
5793
|
+
const folders = await client.getFolders(spaceId, archived);
|
|
5674
5794
|
let filtered = folders;
|
|
5675
5795
|
if (nameFilter) {
|
|
5676
5796
|
const lower = nameFilter.toLowerCase();
|
|
@@ -5932,66 +6052,98 @@ async function duplicateTask(config, taskId) {
|
|
|
5932
6052
|
}
|
|
5933
6053
|
|
|
5934
6054
|
// src/commands/bulk.ts
|
|
5935
|
-
|
|
5936
|
-
|
|
6055
|
+
var BULK_CONCURRENCY = 5;
|
|
6056
|
+
async function runInBatches(items, concurrency, fn) {
|
|
6057
|
+
const results = [];
|
|
6058
|
+
for (let i = 0; i < items.length; i += concurrency) {
|
|
6059
|
+
const batch = items.slice(i, i + concurrency);
|
|
6060
|
+
const batchResults = await Promise.allSettled(batch.map(fn));
|
|
6061
|
+
batchResults.forEach((res, idx) => {
|
|
6062
|
+
const item = batch[idx];
|
|
6063
|
+
if (res.status === "fulfilled") {
|
|
6064
|
+
results.push({ item, result: res.value });
|
|
6065
|
+
} else {
|
|
6066
|
+
results.push({
|
|
6067
|
+
item,
|
|
6068
|
+
error: res.reason instanceof Error ? res.reason : new Error(String(res.reason))
|
|
6069
|
+
});
|
|
6070
|
+
}
|
|
6071
|
+
});
|
|
6072
|
+
}
|
|
6073
|
+
return results;
|
|
6074
|
+
}
|
|
6075
|
+
function toBulkResult(outcomes) {
|
|
5937
6076
|
const failed = [];
|
|
5938
|
-
for (const
|
|
5939
|
-
|
|
5940
|
-
|
|
5941
|
-
} catch (err) {
|
|
5942
|
-
const reason = err instanceof Error ? err.message : String(err);
|
|
5943
|
-
failed.push({ id, reason });
|
|
6077
|
+
for (const outcome of outcomes) {
|
|
6078
|
+
if (outcome.error) {
|
|
6079
|
+
failed.push({ id: outcome.item, reason: outcome.error.message });
|
|
5944
6080
|
}
|
|
5945
6081
|
}
|
|
5946
|
-
return { updated:
|
|
6082
|
+
return { updated: outcomes.length - failed.length, failed };
|
|
6083
|
+
}
|
|
6084
|
+
async function bulkUpdateStatus(config, taskIds, status) {
|
|
6085
|
+
const client = new ClickUpClient(config);
|
|
6086
|
+
const outcomes = await runInBatches(
|
|
6087
|
+
taskIds,
|
|
6088
|
+
BULK_CONCURRENCY,
|
|
6089
|
+
(id) => client.updateTask(id, { status })
|
|
6090
|
+
);
|
|
6091
|
+
return toBulkResult(outcomes);
|
|
5947
6092
|
}
|
|
5948
6093
|
async function bulkAssign(config, userIdOrMe, taskIds, action) {
|
|
5949
6094
|
const client = new ClickUpClient(config);
|
|
5950
6095
|
const numericId = await resolveAssigneeId(client, userIdOrMe);
|
|
5951
|
-
const
|
|
5952
|
-
|
|
5953
|
-
|
|
5954
|
-
|
|
5955
|
-
|
|
5956
|
-
|
|
5957
|
-
|
|
5958
|
-
const reason = err instanceof Error ? err.message : String(err);
|
|
5959
|
-
failed.push({ id, reason });
|
|
5960
|
-
}
|
|
5961
|
-
}
|
|
5962
|
-
return { updated: taskIds.length - failed.length, failed };
|
|
6096
|
+
const payload = action === "add" ? { assignees: { add: [numericId] } } : { assignees: { rem: [numericId] } };
|
|
6097
|
+
const outcomes = await runInBatches(
|
|
6098
|
+
taskIds,
|
|
6099
|
+
BULK_CONCURRENCY,
|
|
6100
|
+
(id) => client.updateTask(id, payload)
|
|
6101
|
+
);
|
|
6102
|
+
return toBulkResult(outcomes);
|
|
5963
6103
|
}
|
|
5964
6104
|
async function bulkDueDate(config, date, taskIds) {
|
|
5965
6105
|
const client = new ClickUpClient(config);
|
|
5966
6106
|
const timezone = await client.getUserTimezone();
|
|
5967
6107
|
const payload = date === "none" || date === "clear" ? { due_date: null } : { due_date: parseDueDate(date, timezone), due_date_time: false };
|
|
5968
|
-
const
|
|
5969
|
-
|
|
5970
|
-
|
|
5971
|
-
|
|
5972
|
-
|
|
5973
|
-
|
|
5974
|
-
failed.push({ id, reason });
|
|
5975
|
-
}
|
|
5976
|
-
}
|
|
5977
|
-
return { updated: taskIds.length - failed.length, failed };
|
|
6108
|
+
const outcomes = await runInBatches(
|
|
6109
|
+
taskIds,
|
|
6110
|
+
BULK_CONCURRENCY,
|
|
6111
|
+
(id) => client.updateTask(id, payload)
|
|
6112
|
+
);
|
|
6113
|
+
return toBulkResult(outcomes);
|
|
5978
6114
|
}
|
|
5979
6115
|
async function bulkTag(config, tagName, taskIds, action) {
|
|
5980
6116
|
const client = new ClickUpClient(config);
|
|
5981
|
-
const
|
|
5982
|
-
|
|
5983
|
-
|
|
5984
|
-
|
|
5985
|
-
|
|
5986
|
-
|
|
5987
|
-
|
|
5988
|
-
|
|
5989
|
-
|
|
5990
|
-
|
|
5991
|
-
|
|
5992
|
-
|
|
5993
|
-
|
|
5994
|
-
|
|
6117
|
+
const outcomes = await runInBatches(
|
|
6118
|
+
taskIds,
|
|
6119
|
+
BULK_CONCURRENCY,
|
|
6120
|
+
(id) => action === "add" ? client.addTagToTask(id, tagName) : client.removeTagFromTask(id, tagName)
|
|
6121
|
+
);
|
|
6122
|
+
return toBulkResult(outcomes);
|
|
6123
|
+
}
|
|
6124
|
+
async function bulkPriority(config, priorityValue, taskIds) {
|
|
6125
|
+
const priority = parsePriority(priorityValue);
|
|
6126
|
+
const client = new ClickUpClient(config);
|
|
6127
|
+
const outcomes = await runInBatches(
|
|
6128
|
+
taskIds,
|
|
6129
|
+
BULK_CONCURRENCY,
|
|
6130
|
+
(id) => client.updateTask(id, { priority })
|
|
6131
|
+
);
|
|
6132
|
+
return toBulkResult(outcomes);
|
|
6133
|
+
}
|
|
6134
|
+
async function bulkField(config, fieldName, rawValue, taskIds) {
|
|
6135
|
+
if (taskIds.length === 0) return { updated: 0, failed: [] };
|
|
6136
|
+
const client = new ClickUpClient(config);
|
|
6137
|
+
const firstTask = await client.getTask(taskIds[0]);
|
|
6138
|
+
const fields = firstTask.custom_fields ?? [];
|
|
6139
|
+
const field = findFieldByName(fields, fieldName);
|
|
6140
|
+
const parsed = parseFieldValue(field, rawValue);
|
|
6141
|
+
const outcomes = await runInBatches(
|
|
6142
|
+
taskIds,
|
|
6143
|
+
BULK_CONCURRENCY,
|
|
6144
|
+
(id) => client.setCustomFieldValue(id, field.id, parsed)
|
|
6145
|
+
);
|
|
6146
|
+
return toBulkResult(outcomes);
|
|
5995
6147
|
}
|
|
5996
6148
|
|
|
5997
6149
|
// src/commands/goals.ts
|
|
@@ -6494,7 +6646,9 @@ function buildProgram(programName = basename(process.argv[1] ?? "cup")) {
|
|
|
6494
6646
|
function getProfileName() {
|
|
6495
6647
|
return program.opts().profile;
|
|
6496
6648
|
}
|
|
6497
|
-
program.command("init").description(
|
|
6649
|
+
program.command("init").description(
|
|
6650
|
+
`Set up ${programName} (interactive). Use --token and --team for non-interactive/agent setup`
|
|
6651
|
+
).option("--token <token>", "API token (pk_...) for non-interactive setup").option("--team <teamId>", "Workspace/team ID for non-interactive setup").action(
|
|
6498
6652
|
wrapAction(async (opts) => {
|
|
6499
6653
|
await runInitCommand(opts);
|
|
6500
6654
|
})
|
|
@@ -6596,7 +6750,7 @@ function buildProgram(programName = basename(process.argv[1] ?? "cup")) {
|
|
|
6596
6750
|
).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(
|
|
6597
6751
|
"--time-estimate <duration>",
|
|
6598
6752
|
'Time estimate (e.g. "2h", "30m", "1h30m", "0" or "none" to clear)'
|
|
6599
|
-
).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(
|
|
6753
|
+
).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("--type <type>", "Change task type (name or custom_item_id)").option("--field <nameAndValue...>", 'Set custom field: --field "Name" value').option("--json", "Force JSON output even in terminal").action(
|
|
6600
6754
|
wrapAction(
|
|
6601
6755
|
async (taskId, opts) => {
|
|
6602
6756
|
const config = loadConfig(getProfileName());
|
|
@@ -6612,14 +6766,15 @@ function buildProgram(programName = basename(process.argv[1] ?? "cup")) {
|
|
|
6612
6766
|
]);
|
|
6613
6767
|
const payload = buildUpdatePayload(opts, timezone);
|
|
6614
6768
|
const hasFields = (opts.field?.length ?? 0) > 0;
|
|
6615
|
-
|
|
6769
|
+
const hasTypeName = opts.type !== void 0;
|
|
6770
|
+
if (!hasFields && !hasTypeName && Object.keys(payload).length === 0) {
|
|
6616
6771
|
throw new Error(
|
|
6617
|
-
"Provide at least one of: --name, --description, --status, --priority, --due-date, --time-estimate, --assignee, --remove-assignee, --parent, --archive, --unarchive, --field"
|
|
6772
|
+
"Provide at least one of: --name, --description, --status, --priority, --due-date, --time-estimate, --assignee, --remove-assignee, --parent, --archive, --unarchive, --type, --field"
|
|
6618
6773
|
);
|
|
6619
6774
|
}
|
|
6620
6775
|
let result;
|
|
6621
|
-
if (Object.keys(payload).length > 0) {
|
|
6622
|
-
result = await updateTask(config, taskId, payload);
|
|
6776
|
+
if (Object.keys(payload).length > 0 || hasTypeName) {
|
|
6777
|
+
result = await updateTask(config, taskId, payload, opts.type);
|
|
6623
6778
|
}
|
|
6624
6779
|
if (hasFields) {
|
|
6625
6780
|
if ((opts.field?.length ?? 0) % 2 !== 0) {
|
|
@@ -6804,18 +6959,25 @@ function buildProgram(programName = basename(process.argv[1] ?? "cup")) {
|
|
|
6804
6959
|
printTimeInStatus(result, opts.json ?? false);
|
|
6805
6960
|
})
|
|
6806
6961
|
);
|
|
6807
|
-
program.command("lists <spaceId>").description("List all lists in a space (including lists inside folders)").option("--name <partial>", "Filter by name (case-insensitive contains)").option("--json", "Force JSON output even in terminal").action(
|
|
6808
|
-
wrapAction(
|
|
6809
|
-
|
|
6810
|
-
|
|
6811
|
-
|
|
6812
|
-
|
|
6962
|
+
program.command("lists <spaceId>").description("List all lists in a space (including lists inside folders)").option("--name <partial>", "Filter by name (case-insensitive contains)").option("--archived", "Include only archived items (default: active items)").option("--json", "Force JSON output even in terminal").action(
|
|
6963
|
+
wrapAction(
|
|
6964
|
+
async (spaceId, opts) => {
|
|
6965
|
+
const config = loadConfig(getProfileName());
|
|
6966
|
+
const lists = await fetchLists(config, spaceId, {
|
|
6967
|
+
name: opts.name,
|
|
6968
|
+
archived: opts.archived
|
|
6969
|
+
});
|
|
6970
|
+
printLists(lists, opts.json ?? false);
|
|
6971
|
+
}
|
|
6972
|
+
)
|
|
6813
6973
|
);
|
|
6814
|
-
program.command("spaces").description("List spaces in your workspace").option("--name <partial>", "Filter spaces by name (case-insensitive contains)").option("--my", "Show only spaces where I have assigned tasks").option("--json", "Force JSON output even in terminal").action(
|
|
6815
|
-
wrapAction(
|
|
6816
|
-
|
|
6817
|
-
|
|
6818
|
-
|
|
6974
|
+
program.command("spaces").description("List spaces in your workspace").option("--name <partial>", "Filter spaces by name (case-insensitive contains)").option("--my", "Show only spaces where I have assigned tasks").option("--archived", "Include only archived items (default: active items)").option("--json", "Force JSON output even in terminal").action(
|
|
6975
|
+
wrapAction(
|
|
6976
|
+
async (opts) => {
|
|
6977
|
+
const config = loadConfig(getProfileName());
|
|
6978
|
+
await listSpaces(config, opts);
|
|
6979
|
+
}
|
|
6980
|
+
)
|
|
6819
6981
|
);
|
|
6820
6982
|
program.command("inbox").description("Recently updated tasks grouped by time period").option("--include-closed", "Include done/closed tasks").option("--json", "Force JSON output even in terminal").option("--days <n>", "Lookback period in days", "30").action(
|
|
6821
6983
|
wrapAction(async (opts) => {
|
|
@@ -7433,6 +7595,23 @@ function buildProgram(programName = basename(process.argv[1] ?? "cup")) {
|
|
|
7433
7595
|
}
|
|
7434
7596
|
)
|
|
7435
7597
|
);
|
|
7598
|
+
bulkCmd.command("priority <taskIds...>").description("Bulk set priority on tasks (urgent/high/normal/low or 1-4)").requiredOption("--to <priority>", "Priority to set (urgent, high, normal, low, or 1-4)").option("--json", "Force JSON output even in terminal").action(
|
|
7599
|
+
wrapAction(async (taskIds, opts) => {
|
|
7600
|
+
const config = loadConfig(getProfileName());
|
|
7601
|
+
const result = await bulkPriority(config, opts.to, taskIds);
|
|
7602
|
+
outputBulkResult(result, opts.json ?? false, `priority ${opts.to}`);
|
|
7603
|
+
})
|
|
7604
|
+
);
|
|
7605
|
+
bulkCmd.command("field <taskIds...>").description("Bulk set the same custom field value on tasks").requiredOption("--set <nameAndValue...>", 'Set field: --set "Field Name" value').option("--json", "Force JSON output even in terminal").action(
|
|
7606
|
+
wrapAction(async (taskIds, opts) => {
|
|
7607
|
+
if (opts.set.length !== 2) {
|
|
7608
|
+
throw new Error("--set requires exactly two arguments: field name and value");
|
|
7609
|
+
}
|
|
7610
|
+
const config = loadConfig(getProfileName());
|
|
7611
|
+
const result = await bulkField(config, opts.set[0], opts.set[1], taskIds);
|
|
7612
|
+
outputBulkResult(result, opts.json ?? false, `field "${opts.set[0]}"`);
|
|
7613
|
+
})
|
|
7614
|
+
);
|
|
7436
7615
|
program.command("goals").description("List goals in your workspace").option("--json", "Force JSON output even in terminal").action(
|
|
7437
7616
|
wrapAction(async (opts) => {
|
|
7438
7617
|
const config = loadConfig(getProfileName());
|
|
@@ -7602,18 +7781,20 @@ function buildProgram(programName = basename(process.argv[1] ?? "cup")) {
|
|
|
7602
7781
|
}
|
|
7603
7782
|
})
|
|
7604
7783
|
);
|
|
7605
|
-
program.command("folders <spaceId>").description("List folders in a space (with their lists)").option("--name <partial>", "Filter folders by partial name match").option("--json", "Force JSON output even in terminal").action(
|
|
7606
|
-
wrapAction(
|
|
7607
|
-
|
|
7608
|
-
|
|
7609
|
-
|
|
7610
|
-
|
|
7611
|
-
|
|
7612
|
-
|
|
7613
|
-
|
|
7614
|
-
|
|
7784
|
+
program.command("folders <spaceId>").description("List folders in a space (with their lists)").option("--name <partial>", "Filter folders by partial name match").option("--archived", "Include only archived items (default: active items)").option("--json", "Force JSON output even in terminal").action(
|
|
7785
|
+
wrapAction(
|
|
7786
|
+
async (spaceId, opts) => {
|
|
7787
|
+
const config = loadConfig(getProfileName());
|
|
7788
|
+
const folders = await listFolders(config, spaceId, opts.name, opts.archived);
|
|
7789
|
+
if (shouldOutputJson(opts.json ?? false)) {
|
|
7790
|
+
console.log(JSON.stringify(folders, null, 2));
|
|
7791
|
+
} else if (isTTY()) {
|
|
7792
|
+
console.log(formatFolders(folders));
|
|
7793
|
+
} else {
|
|
7794
|
+
console.log(formatFoldersMarkdown(folders));
|
|
7795
|
+
}
|
|
7615
7796
|
}
|
|
7616
|
-
|
|
7797
|
+
)
|
|
7617
7798
|
);
|
|
7618
7799
|
program.command("space-create <name>").description("Create a new space in your workspace").option("--json", "Force JSON output even in terminal").action(
|
|
7619
7800
|
wrapAction(async (name, opts) => {
|
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.22.0
|
|
7
7
|
|
|
8
|
-
Reference for AI agents using the `cup` CLI tool. Covers task management, sprint tracking, comments, and project workflows.
|
|
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.22.0, update with `npm install -g @krodak/clickup-cli` and refresh this skill with `cup skill`.
|
|
11
11
|
|
|
12
12
|
## Install & Configure
|
|
13
13
|
|
|
@@ -152,7 +152,7 @@ All commands support `--help` for full flag details. All commands support `--jso
|
|
|
152
152
|
| `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 |
|
|
153
153
|
| `cup replies <commentId>` | List threaded replies |
|
|
154
154
|
| `cup reply <commentId> -m text [--notify-all]` | Reply to a comment |
|
|
155
|
-
| `cup assign <id> [--to
|
|
155
|
+
| `cup assign <id> [--to ids\|me] [--remove ids\|me]` | Assign/unassign users (`--to`/`--remove` accept comma-separated IDs) |
|
|
156
156
|
| `cup depend <id> [--on taskId] [--blocks taskId] [--remove]` | Add/remove dependencies |
|
|
157
157
|
| `cup move <id> [--to listId\|sprint:current] [--remove listId]` | Add/remove task from lists (`--to` accepts `sprint:current`) |
|
|
158
158
|
| `cup field <id> [--set "Name" value] [--remove "Name"]` | Set/remove custom field values |
|
|
@@ -219,32 +219,32 @@ All commands support `--help` for full flag details. All commands support `--jso
|
|
|
219
219
|
|
|
220
220
|
## Flags & Conventions
|
|
221
221
|
|
|
222
|
-
| Topic | Detail
|
|
223
|
-
| ------------------------ |
|
|
224
|
-
| Task IDs | Native (`abc123def`) or custom (`PROJ-123`). Custom IDs auto-detected by `PREFIX-DIGITS` format
|
|
225
|
-
| `--status` | Fuzzy matching: exact > starts-with > contains. Prints match to stderr
|
|
226
|
-
| `--priority` | Names (`urgent`, `high`, `normal`, `low`) or numbers (1-4)
|
|
227
|
-
| `--due-date` | `YYYY-MM-DD` format
|
|
228
|
-
| `--assignee` | User ID or `me`
|
|
229
|
-
| `--tags` | Comma-separated (e.g. `--tags "bug,frontend"`)
|
|
230
|
-
| `--time-estimate` | Duration: `"2h"`, `"30m"`, `"1h30m"`, or raw milliseconds
|
|
231
|
-
| `--type` | `task` (regular) or custom type name/ID (e.g. `initiative`, `Bug`)
|
|
232
|
-
| `--custom-item-id` | Custom task type ID for `cup create` (find with `cup task-types`)
|
|
233
|
-
| `--space` | Partial name match or exact ID
|
|
234
|
-
| `--name` | Partial match, case-insensitive
|
|
235
|
-
| `--all` | Show all tasks in workspace, not just assigned to me. Available on `tasks`, `search`, `overdue`. Default: my tasks only (smaller output for agent context windows)
|
|
236
|
-
| `--include-closed` | Include closed/done tasks
|
|
237
|
-
| `--list` on create | Optional when `--parent` is given (auto-detected). Accepts `sprint:current` pseudo-ID
|
|
238
|
-
| `cup field --set` | Supports: text, number, checkbox (true/false), dropdown (option name), labels (comma-separated names), date (YYYY-MM-DD), url, email. Names resolved case-insensitively; errors list available fields/options |
|
|
239
|
-
| `cup field-create` | Use `--options "a,b,c"` for `drop_down` and `labels` types (required). Other types don't need `--options`
|
|
240
|
-
| `--field` filter | `--field "Name" value` on `tasks` and `search` requires `--list` to resolve field names to IDs
|
|
241
|
-
| `--due-before/after` | `YYYY-MM-DD` date filters for due date range
|
|
242
|
-
| `--created-before/after` | `YYYY-MM-DD` date filters for creation date range
|
|
243
|
-
| `cup sprint` | Auto-detects active sprint by folder name (sprint/iteration/cycle/scrum), parses multiple date formats. Override with `--folder <id>`, `cup config set sprintFolderId <id>`, or favorite a sprint folder
|
|
244
|
-
| `cup favorite` | Local-only favorites (not synced to ClickUp). Types: sprint-folder, space, list, folder, view, task. Favorited sprint-folders auto-used by sprint commands
|
|
245
|
-
| `cup link` | Both IDs must be the same type (both custom or both native)
|
|
246
|
-
| `cup delete` | DESTRUCTIVE. Requires `--confirm` in non-interactive mode. Cannot be undone
|
|
247
|
-
| Errors | stderr with exit code 1. Strict parsing - excess/unknown arguments rejected
|
|
222
|
+
| Topic | Detail |
|
|
223
|
+
| ------------------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
224
|
+
| Task IDs | Native (`abc123def`) or custom (`PROJ-123`). Custom IDs auto-detected by `PREFIX-DIGITS` format |
|
|
225
|
+
| `--status` | Fuzzy matching: exact > starts-with > contains. Prints match to stderr |
|
|
226
|
+
| `--priority` | Names (`urgent`, `high`, `normal`, `low`) or numbers (1-4) |
|
|
227
|
+
| `--due-date` | `YYYY-MM-DD` format |
|
|
228
|
+
| `--assignee` | User ID or `me` |
|
|
229
|
+
| `--tags` | Comma-separated (e.g. `--tags "bug,frontend"`) |
|
|
230
|
+
| `--time-estimate` | Duration: `"2h"`, `"30m"`, `"1h30m"`, or raw milliseconds |
|
|
231
|
+
| `--type` | `task` (regular) or custom type name/ID (e.g. `initiative`, `Bug`) |
|
|
232
|
+
| `--custom-item-id` | Custom task type ID for `cup create` (find with `cup task-types`) |
|
|
233
|
+
| `--space` | Partial name match or exact ID |
|
|
234
|
+
| `--name` | Partial match, case-insensitive |
|
|
235
|
+
| `--all` | Show all tasks in workspace, not just assigned to me. Available on `tasks`, `search`, `overdue`. Default: my tasks only (smaller output for agent context windows) |
|
|
236
|
+
| `--include-closed` | Include closed/done tasks |
|
|
237
|
+
| `--list` on create | Optional when `--parent` is given (auto-detected). Accepts `sprint:current` pseudo-ID |
|
|
238
|
+
| `cup field --set` | Supports: text, number, checkbox (true/false), dropdown (option name), labels (comma-separated names), date (YYYY-MM-DD), url, email, emoji/rating (0-5), manual_progress (0-100), tasks/relationship (comma-separated task IDs), users/people (comma-separated user IDs). Names resolved case-insensitively; errors list available fields/options |
|
|
239
|
+
| `cup field-create` | Use `--options "a,b,c"` for `drop_down` and `labels` types (required). Other types don't need `--options` |
|
|
240
|
+
| `--field` filter | `--field "Name" value` on `tasks` and `search` requires `--list` to resolve field names to IDs |
|
|
241
|
+
| `--due-before/after` | `YYYY-MM-DD` date filters for due date range |
|
|
242
|
+
| `--created-before/after` | `YYYY-MM-DD` date filters for creation date range |
|
|
243
|
+
| `cup sprint` | Auto-detects active sprint by folder name (sprint/iteration/cycle/scrum), parses multiple date formats. Override with `--folder <id>`, `cup config set sprintFolderId <id>`, or favorite a sprint folder |
|
|
244
|
+
| `cup favorite` | Local-only favorites (not synced to ClickUp). Types: sprint-folder, space, list, folder, view, task. Favorited sprint-folders auto-used by sprint commands |
|
|
245
|
+
| `cup link` | Both IDs must be the same type (both custom or both native) |
|
|
246
|
+
| `cup delete` | DESTRUCTIVE. Requires `--confirm` in non-interactive mode. Cannot be undone |
|
|
247
|
+
| Errors | stderr with exit code 1. Strict parsing - excess/unknown arguments rejected |
|
|
248
248
|
|
|
249
249
|
## Agent Workflow Examples
|
|
250
250
|
|
|
@@ -289,6 +289,7 @@ cup create -n "Bug fix" -l sprint:current # create in active sprint
|
|
|
289
289
|
cup create -n "Q3 Roadmap" -l <listId> --custom-item-id 1
|
|
290
290
|
cup comment abc123def -m "Completed in PR #42"
|
|
291
291
|
cup assign abc123def --to me
|
|
292
|
+
cup assign abc123def --to 12345,67890 # assign multiple users at once
|
|
292
293
|
cup depend task3 --on task2 # task3 waits for task2
|
|
293
294
|
cup move task1 --to list2 --remove list1
|
|
294
295
|
cup move task1 --to sprint:current # move to active sprint
|