@krodak/clickup-cli 1.16.2 → 1.18.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude-plugin/plugin.json +1 -1
- package/README.md +24 -25
- package/dist/index.js +315 -51
- package/package.json +1 -1
- package/skills/clickup-cli/SKILL.md +66 -56
|
@@ -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.18.0",
|
|
5
5
|
"author": {
|
|
6
6
|
"name": "Krzysztof Rodak"
|
|
7
7
|
},
|
package/README.md
CHANGED
|
@@ -73,9 +73,18 @@ cup init
|
|
|
73
73
|
|
|
74
74
|
## Set up your agent
|
|
75
75
|
|
|
76
|
-
The package includes a [skill file](https://agentskills.io) that teaches agents all available commands
|
|
76
|
+
The package includes a [skill file](https://agentskills.io) that teaches agents all available commands. Install it with:
|
|
77
77
|
|
|
78
|
-
|
|
78
|
+
```bash
|
|
79
|
+
cup skill
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
This detects which agents you have (Claude Code, Codex, OpenCode) and installs the skill to the right locations. Run it again after updating `cup` to refresh the skill.
|
|
83
|
+
|
|
84
|
+
<details>
|
|
85
|
+
<summary>Manual install options</summary>
|
|
86
|
+
|
|
87
|
+
<details>
|
|
79
88
|
<summary> <img src="https://img.shields.io/badge/Claude_Code-D97757?logo=anthropic&logoColor=white" height="18" align="center"> <strong>Claude Code</strong></summary>
|
|
80
89
|
|
|
81
90
|
**Install as a [plugin](https://docs.anthropic.com/en/docs/claude-code/plugins)** (recommended):
|
|
@@ -84,14 +93,10 @@ The package includes a [skill file](https://agentskills.io) that teaches agents
|
|
|
84
93
|
claude plugin add $(npm root -g)/@krodak/clickup-cli
|
|
85
94
|
```
|
|
86
95
|
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
**Or install as a personal skill** (no namespace prefix):
|
|
96
|
+
**Or as a personal skill:**
|
|
90
97
|
|
|
91
98
|
```bash
|
|
92
|
-
|
|
93
|
-
mkdir -p ~/.claude/skills/clickup
|
|
94
|
-
cp "$SKILL/SKILL.md" ~/.claude/skills/clickup/SKILL.md
|
|
99
|
+
cup skill --path ~/.claude/skills/clickup/SKILL.md
|
|
95
100
|
```
|
|
96
101
|
|
|
97
102
|
</details>
|
|
@@ -99,35 +104,23 @@ cp "$SKILL/SKILL.md" ~/.claude/skills/clickup/SKILL.md
|
|
|
99
104
|
<details>
|
|
100
105
|
<summary> <img src="https://img.shields.io/badge/Codex-412991?logo=openai&logoColor=white" height="18" align="center"> <strong>Codex</strong></summary>
|
|
101
106
|
|
|
102
|
-
Codex supports [agent skills](https://developers.openai.com/codex/skills) across CLI, IDE extension, and web. Skills use the same `SKILL.md` format with YAML frontmatter.
|
|
103
|
-
|
|
104
|
-
**Install as a user skill** (available across all your projects):
|
|
105
|
-
|
|
106
107
|
```bash
|
|
107
|
-
|
|
108
|
-
mkdir -p ~/.agents/skills/clickup
|
|
109
|
-
cp "$SKILL/SKILL.md" ~/.agents/skills/clickup/SKILL.md
|
|
108
|
+
cup skill --path ~/.agents/skills/clickup/SKILL.md
|
|
110
109
|
```
|
|
111
110
|
|
|
112
|
-
|
|
111
|
+
Or for a project-level skill:
|
|
113
112
|
|
|
114
113
|
```bash
|
|
115
|
-
|
|
116
|
-
mkdir -p .agents/skills/clickup
|
|
117
|
-
cp "$SKILL/SKILL.md" .agents/skills/clickup/SKILL.md
|
|
114
|
+
cup skill --path .agents/skills/clickup/SKILL.md
|
|
118
115
|
```
|
|
119
116
|
|
|
120
|
-
You can also use the built-in installer: `$skill-installer clickup`
|
|
121
|
-
|
|
122
117
|
</details>
|
|
123
118
|
|
|
124
119
|
<details>
|
|
125
120
|
<summary> <img src="https://img.shields.io/badge/OpenCode-24292e?logoColor=white" height="18" align="center"> <strong>OpenCode</strong></summary>
|
|
126
121
|
|
|
127
122
|
```bash
|
|
128
|
-
|
|
129
|
-
mkdir -p ~/.config/opencode/skills/clickup
|
|
130
|
-
cp "$SKILL/SKILL.md" ~/.config/opencode/skills/clickup/SKILL.md
|
|
123
|
+
cup skill --path ~/.config/opencode/skills/clickup/SKILL.md
|
|
131
124
|
```
|
|
132
125
|
|
|
133
126
|
</details>
|
|
@@ -135,7 +128,13 @@ cp "$SKILL/SKILL.md" ~/.config/opencode/skills/clickup/SKILL.md
|
|
|
135
128
|
<details>
|
|
136
129
|
<summary> <strong>Other agents</strong></summary>
|
|
137
130
|
|
|
138
|
-
|
|
131
|
+
```bash
|
|
132
|
+
cup skill --print > SKILL.md # output skill content to a file
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
Or copy `skills/clickup-cli/SKILL.md` into your agent's skill directory or `AGENTS.md`.
|
|
136
|
+
|
|
137
|
+
</details>
|
|
139
138
|
|
|
140
139
|
</details>
|
|
141
140
|
|
package/dist/index.js
CHANGED
|
@@ -5,7 +5,7 @@ import { realpathSync } from "fs";
|
|
|
5
5
|
import { basename, resolve } from "path";
|
|
6
6
|
import { Command } from "commander";
|
|
7
7
|
import { createRequire } from "module";
|
|
8
|
-
import { fileURLToPath } from "url";
|
|
8
|
+
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
9
9
|
|
|
10
10
|
// src/api.ts
|
|
11
11
|
var BASE_URL = "https://api.clickup.com/api/v2";
|
|
@@ -176,9 +176,22 @@ var ClickUpClient = class {
|
|
|
176
176
|
const me = await this.getMe();
|
|
177
177
|
baseParams.append("assignees[]", String(me.id));
|
|
178
178
|
}
|
|
179
|
+
if (filters.assignees) {
|
|
180
|
+
for (const id of filters.assignees) baseParams.append("assignees[]", String(id));
|
|
181
|
+
}
|
|
179
182
|
for (const s of filters.statuses ?? []) baseParams.append("statuses[]", s);
|
|
180
183
|
for (const id of filters.listIds ?? []) baseParams.append("list_ids[]", id);
|
|
181
184
|
for (const id of filters.spaceIds ?? []) baseParams.append("space_ids[]", id);
|
|
185
|
+
for (const tag of filters.tags ?? []) baseParams.append("tags[]", tag);
|
|
186
|
+
if (filters.dueDateGt) baseParams.set("due_date_gt", String(filters.dueDateGt));
|
|
187
|
+
if (filters.dueDateLt) baseParams.set("due_date_lt", String(filters.dueDateLt));
|
|
188
|
+
if (filters.dateCreatedGt) baseParams.set("date_created_gt", String(filters.dateCreatedGt));
|
|
189
|
+
if (filters.dateCreatedLt) baseParams.set("date_created_lt", String(filters.dateCreatedLt));
|
|
190
|
+
if (filters.dateUpdatedGt) baseParams.set("date_updated_gt", String(filters.dateUpdatedGt));
|
|
191
|
+
if (filters.dateUpdatedLt) baseParams.set("date_updated_lt", String(filters.dateUpdatedLt));
|
|
192
|
+
if (filters.customFields?.length) {
|
|
193
|
+
baseParams.set("custom_fields", JSON.stringify(filters.customFields));
|
|
194
|
+
}
|
|
182
195
|
return this.paginate((page) => {
|
|
183
196
|
const params = new URLSearchParams(baseParams);
|
|
184
197
|
params.set("page", String(page));
|
|
@@ -2855,6 +2868,13 @@ var commandMetadata = [
|
|
|
2855
2868
|
"--type",
|
|
2856
2869
|
"--all",
|
|
2857
2870
|
"--include-closed",
|
|
2871
|
+
"--assignee",
|
|
2872
|
+
"--tag",
|
|
2873
|
+
"--due-before",
|
|
2874
|
+
"--due-after",
|
|
2875
|
+
"--created-after",
|
|
2876
|
+
"--created-before",
|
|
2877
|
+
"--field",
|
|
2858
2878
|
"--json"
|
|
2859
2879
|
],
|
|
2860
2880
|
quickReference: [
|
|
@@ -3059,7 +3079,21 @@ var commandMetadata = [
|
|
|
3059
3079
|
{
|
|
3060
3080
|
name: "search",
|
|
3061
3081
|
description: "Search my tasks by name (use --all for all tasks)",
|
|
3062
|
-
flags: [
|
|
3082
|
+
flags: [
|
|
3083
|
+
"--status",
|
|
3084
|
+
"--list",
|
|
3085
|
+
"--space",
|
|
3086
|
+
"--all",
|
|
3087
|
+
"--include-closed",
|
|
3088
|
+
"--assignee",
|
|
3089
|
+
"--tag",
|
|
3090
|
+
"--due-before",
|
|
3091
|
+
"--due-after",
|
|
3092
|
+
"--created-after",
|
|
3093
|
+
"--created-before",
|
|
3094
|
+
"--field",
|
|
3095
|
+
"--json"
|
|
3096
|
+
],
|
|
3063
3097
|
quickReference: [
|
|
3064
3098
|
{ section: "read", usage: "search <query>", description: "Search my tasks by name" }
|
|
3065
3099
|
]
|
|
@@ -3329,6 +3363,18 @@ var commandMetadata = [
|
|
|
3329
3363
|
{ section: "read", usage: "folders <spaceId>", description: "List folders in a space" }
|
|
3330
3364
|
]
|
|
3331
3365
|
},
|
|
3366
|
+
{
|
|
3367
|
+
name: "skill",
|
|
3368
|
+
description: "Install the agent skill file for your coding agents",
|
|
3369
|
+
flags: ["--print", "--path"],
|
|
3370
|
+
quickReference: [
|
|
3371
|
+
{
|
|
3372
|
+
section: "setup",
|
|
3373
|
+
usage: "skill",
|
|
3374
|
+
description: "Install skill for your agents"
|
|
3375
|
+
}
|
|
3376
|
+
]
|
|
3377
|
+
},
|
|
3332
3378
|
{
|
|
3333
3379
|
name: "space-create",
|
|
3334
3380
|
description: "Create a new space in your workspace",
|
|
@@ -3819,7 +3865,15 @@ ${renderZshTopLevelCommands(name)}
|
|
|
3819
3865
|
'--space[Filter by space ID]:space_id:' \\
|
|
3820
3866
|
'--name[Filter by name]:query:' \\
|
|
3821
3867
|
'--type[Filter by task type]:type:' \\
|
|
3868
|
+
'--all[Include all tasks, not just mine]' \\
|
|
3822
3869
|
'--include-closed[Include done/closed tasks]' \\
|
|
3870
|
+
'--assignee[Filter by assignee]:user_id:' \\
|
|
3871
|
+
'--tag[Filter by tag name]:tag:' \\
|
|
3872
|
+
'--due-before[Tasks due before date]:date:' \\
|
|
3873
|
+
'--due-after[Tasks due after date]:date:' \\
|
|
3874
|
+
'--created-after[Tasks created after date]:date:' \\
|
|
3875
|
+
'--created-before[Tasks created before date]:date:' \\
|
|
3876
|
+
'--field[Filter by custom field]:field_name_and_value:' \\
|
|
3823
3877
|
'--json[Force JSON output]'
|
|
3824
3878
|
;;
|
|
3825
3879
|
task)
|
|
@@ -3933,8 +3987,17 @@ ${renderZshTopLevelCommands(name)}
|
|
|
3933
3987
|
_arguments \\
|
|
3934
3988
|
'1:query:' \\
|
|
3935
3989
|
'--status[Filter by status]:status:(open "in progress" "in review" done closed)' \\
|
|
3936
|
-
'--
|
|
3990
|
+
'--list[Filter by list ID]:list_id:' \\
|
|
3991
|
+
'--space[Filter by space ID]:space_id:' \\
|
|
3937
3992
|
'--all[Search all workspace tasks, not just mine]' \\
|
|
3993
|
+
'--include-closed[Include done/closed tasks in search]' \\
|
|
3994
|
+
'--assignee[Filter by assignee]:user_id:' \\
|
|
3995
|
+
'--tag[Filter by tag name]:tag:' \\
|
|
3996
|
+
'--due-before[Tasks due before date]:date:' \\
|
|
3997
|
+
'--due-after[Tasks due after date]:date:' \\
|
|
3998
|
+
'--created-after[Tasks created after date]:date:' \\
|
|
3999
|
+
'--created-before[Tasks created before date]:date:' \\
|
|
4000
|
+
'--field[Filter by custom field]:field_name_and_value:' \\
|
|
3938
4001
|
'--json[Force JSON output]'
|
|
3939
4002
|
;;
|
|
3940
4003
|
summary)
|
|
@@ -4603,6 +4666,81 @@ function generateCompletion(shell, name = "cup") {
|
|
|
4603
4666
|
}
|
|
4604
4667
|
}
|
|
4605
4668
|
|
|
4669
|
+
// src/commands/skill.ts
|
|
4670
|
+
import { readFileSync, mkdirSync, copyFileSync, existsSync } from "fs";
|
|
4671
|
+
import { join as join2, dirname } from "path";
|
|
4672
|
+
import { fileURLToPath } from "url";
|
|
4673
|
+
import { homedir as homedir2 } from "os";
|
|
4674
|
+
import chalk7 from "chalk";
|
|
4675
|
+
function skillPath() {
|
|
4676
|
+
const thisFile = fileURLToPath(import.meta.url);
|
|
4677
|
+
return join2(dirname(thisFile), "..", "..", "skills", "clickup-cli", "SKILL.md");
|
|
4678
|
+
}
|
|
4679
|
+
function printSkill() {
|
|
4680
|
+
return readFileSync(skillPath(), "utf-8");
|
|
4681
|
+
}
|
|
4682
|
+
function getAgentTargets() {
|
|
4683
|
+
const home = homedir2();
|
|
4684
|
+
const targets = [
|
|
4685
|
+
{ name: "Claude Code", dir: join2(home, ".claude", "skills", "clickup") },
|
|
4686
|
+
{ name: "Codex", dir: join2(home, ".agents", "skills", "clickup") },
|
|
4687
|
+
{ name: "OpenCode", dir: join2(home, ".config", "opencode", "skills", "clickup") }
|
|
4688
|
+
];
|
|
4689
|
+
return targets.map((t) => ({
|
|
4690
|
+
...t,
|
|
4691
|
+
detected: existsSync(dirname(t.dir))
|
|
4692
|
+
}));
|
|
4693
|
+
}
|
|
4694
|
+
async function installSkillInteractive() {
|
|
4695
|
+
const targets = getAgentTargets();
|
|
4696
|
+
const source = skillPath();
|
|
4697
|
+
const installed = [];
|
|
4698
|
+
if (isTTY()) {
|
|
4699
|
+
const { checkbox: checkbox2 } = await import("@inquirer/prompts");
|
|
4700
|
+
const preselected = targets.filter((t) => t.detected).map((t) => t.name);
|
|
4701
|
+
const selected = await checkbox2({
|
|
4702
|
+
message: "Install skill for which agents?",
|
|
4703
|
+
choices: targets.map((t) => ({
|
|
4704
|
+
name: `${t.name}${t.detected ? chalk7.dim(" (detected)") : ""}`,
|
|
4705
|
+
value: t.name,
|
|
4706
|
+
checked: t.detected
|
|
4707
|
+
}))
|
|
4708
|
+
});
|
|
4709
|
+
if (selected.length === 0) {
|
|
4710
|
+
throw new Error("No agents selected");
|
|
4711
|
+
}
|
|
4712
|
+
for (const name of selected) {
|
|
4713
|
+
const target = targets.find((t) => t.name === name);
|
|
4714
|
+
if (!existsSync(target.dir)) mkdirSync(target.dir, { recursive: true });
|
|
4715
|
+
const dest = join2(target.dir, "SKILL.md");
|
|
4716
|
+
copyFileSync(source, dest);
|
|
4717
|
+
installed.push(`${target.name}: ${dest}`);
|
|
4718
|
+
}
|
|
4719
|
+
} else {
|
|
4720
|
+
for (const target of targets.filter((t) => t.detected)) {
|
|
4721
|
+
if (!existsSync(target.dir)) mkdirSync(target.dir, { recursive: true });
|
|
4722
|
+
const dest = join2(target.dir, "SKILL.md");
|
|
4723
|
+
copyFileSync(source, dest);
|
|
4724
|
+
installed.push(`${target.name}: ${dest}`);
|
|
4725
|
+
}
|
|
4726
|
+
if (installed.length === 0) {
|
|
4727
|
+
const fallback = targets[0];
|
|
4728
|
+
mkdirSync(fallback.dir, { recursive: true });
|
|
4729
|
+
const dest = join2(fallback.dir, "SKILL.md");
|
|
4730
|
+
copyFileSync(source, dest);
|
|
4731
|
+
installed.push(`${fallback.name}: ${dest}`);
|
|
4732
|
+
}
|
|
4733
|
+
}
|
|
4734
|
+
return installed;
|
|
4735
|
+
}
|
|
4736
|
+
function installSkillTo(path) {
|
|
4737
|
+
const source = skillPath();
|
|
4738
|
+
const dir = dirname(path);
|
|
4739
|
+
if (!existsSync(dir)) mkdirSync(dir, { recursive: true });
|
|
4740
|
+
copyFileSync(source, path);
|
|
4741
|
+
return path;
|
|
4742
|
+
}
|
|
4743
|
+
|
|
4606
4744
|
// src/commands/auth.ts
|
|
4607
4745
|
async function checkAuth(config) {
|
|
4608
4746
|
const client = new ClickUpClient(config);
|
|
@@ -4623,7 +4761,19 @@ async function searchTasks(config, query, opts = {}) {
|
|
|
4623
4761
|
}
|
|
4624
4762
|
const client = new ClickUpClient(config);
|
|
4625
4763
|
const [allTasks, customTypes] = await Promise.all([
|
|
4626
|
-
client.getMyTasks(config.teamId, {
|
|
4764
|
+
client.getMyTasks(config.teamId, {
|
|
4765
|
+
all: opts.all,
|
|
4766
|
+
includeClosed: opts.includeClosed,
|
|
4767
|
+
listIds: opts.listIds,
|
|
4768
|
+
spaceIds: opts.spaceIds,
|
|
4769
|
+
assignees: opts.assignees,
|
|
4770
|
+
tags: opts.tags,
|
|
4771
|
+
dueDateGt: opts.dueDateGt,
|
|
4772
|
+
dueDateLt: opts.dueDateLt,
|
|
4773
|
+
dateCreatedGt: opts.dateCreatedGt,
|
|
4774
|
+
dateCreatedLt: opts.dateCreatedLt,
|
|
4775
|
+
customFields: opts.customFields
|
|
4776
|
+
}),
|
|
4627
4777
|
client.getCustomTaskTypes(config.teamId)
|
|
4628
4778
|
]);
|
|
4629
4779
|
const typeMap = buildTypeMap(customTypes);
|
|
@@ -4869,7 +5019,7 @@ async function manageTags(config, taskId, opts) {
|
|
|
4869
5019
|
}
|
|
4870
5020
|
|
|
4871
5021
|
// src/commands/checklist.ts
|
|
4872
|
-
import
|
|
5022
|
+
import chalk8 from "chalk";
|
|
4873
5023
|
async function viewChecklists(config, taskId) {
|
|
4874
5024
|
const client = new ClickUpClient(config);
|
|
4875
5025
|
const task = await client.getTask(taskId);
|
|
@@ -4902,14 +5052,14 @@ function formatChecklists(checklists) {
|
|
|
4902
5052
|
const lines = [];
|
|
4903
5053
|
for (const cl of checklists) {
|
|
4904
5054
|
const resolved = cl.items.filter((i) => i.resolved).length;
|
|
4905
|
-
lines.push(
|
|
4906
|
-
lines.push(
|
|
5055
|
+
lines.push(chalk8.bold(`${cl.name} (${resolved}/${cl.items.length})`));
|
|
5056
|
+
lines.push(chalk8.dim(` ID: ${cl.id}`));
|
|
4907
5057
|
for (const item of cl.items) {
|
|
4908
|
-
const check = item.resolved ?
|
|
4909
|
-
const name = item.resolved ?
|
|
4910
|
-
const assignee = item.assignee ?
|
|
5058
|
+
const check = item.resolved ? chalk8.green("[x]") : chalk8.dim("[ ]");
|
|
5059
|
+
const name = item.resolved ? chalk8.dim(item.name) : item.name;
|
|
5060
|
+
const assignee = item.assignee ? chalk8.dim(` @${item.assignee.username}`) : "";
|
|
4911
5061
|
lines.push(` ${check} ${name}${assignee}`);
|
|
4912
|
-
lines.push(
|
|
5062
|
+
lines.push(chalk8.dim(` item-id: ${item.id}`));
|
|
4913
5063
|
}
|
|
4914
5064
|
}
|
|
4915
5065
|
return lines.join("\n");
|
|
@@ -4943,7 +5093,7 @@ async function deleteComment(config, commentId) {
|
|
|
4943
5093
|
}
|
|
4944
5094
|
|
|
4945
5095
|
// src/commands/replies.ts
|
|
4946
|
-
import
|
|
5096
|
+
import chalk9 from "chalk";
|
|
4947
5097
|
async function getReplies(config, commentId) {
|
|
4948
5098
|
const client = new ClickUpClient(config);
|
|
4949
5099
|
return client.getThreadedComments(commentId);
|
|
@@ -4958,7 +5108,7 @@ function formatReplies(replies) {
|
|
|
4958
5108
|
return replies.map((r) => {
|
|
4959
5109
|
const user = r.user?.username ?? "Unknown";
|
|
4960
5110
|
const date = formatTimestamp(Number(r.date));
|
|
4961
|
-
return `${
|
|
5111
|
+
return `${chalk9.bold(user)} ${chalk9.dim(date)}
|
|
4962
5112
|
${r.comment_text}`;
|
|
4963
5113
|
}).join("\n\n");
|
|
4964
5114
|
}
|
|
@@ -5021,7 +5171,7 @@ function formatDocsMarkdown(docs) {
|
|
|
5021
5171
|
}
|
|
5022
5172
|
|
|
5023
5173
|
// src/commands/doc.ts
|
|
5024
|
-
import
|
|
5174
|
+
import chalk10 from "chalk";
|
|
5025
5175
|
async function getDocInfo(config, docId) {
|
|
5026
5176
|
const client = new ClickUpClient(config);
|
|
5027
5177
|
const [doc, pages] = await Promise.all([
|
|
@@ -5033,14 +5183,14 @@ async function getDocInfo(config, docId) {
|
|
|
5033
5183
|
function formatDocInfo(doc, pages, indent = 0) {
|
|
5034
5184
|
const lines = [];
|
|
5035
5185
|
if (indent === 0) {
|
|
5036
|
-
lines.push(`${
|
|
5186
|
+
lines.push(`${chalk10.bold(doc.name)} ${chalk10.dim(doc.id)}`);
|
|
5037
5187
|
if (pages.length === 0) {
|
|
5038
5188
|
lines.push(" (no pages)");
|
|
5039
5189
|
}
|
|
5040
5190
|
}
|
|
5041
5191
|
for (const page of pages) {
|
|
5042
5192
|
const prefix = " ".repeat(indent + 1);
|
|
5043
|
-
lines.push(`${prefix}${page.name} ${
|
|
5193
|
+
lines.push(`${prefix}${page.name} ${chalk10.dim(page.id)}`);
|
|
5044
5194
|
if (page.pages && page.pages.length > 0) {
|
|
5045
5195
|
lines.push(formatDocInfo(doc, page.pages, indent + 1));
|
|
5046
5196
|
}
|
|
@@ -5119,7 +5269,7 @@ async function deleteDocPage(config, docId, pageId) {
|
|
|
5119
5269
|
}
|
|
5120
5270
|
|
|
5121
5271
|
// src/commands/folders.ts
|
|
5122
|
-
import
|
|
5272
|
+
import chalk11 from "chalk";
|
|
5123
5273
|
async function listFolders(config, spaceId, nameFilter) {
|
|
5124
5274
|
const client = new ClickUpClient(config);
|
|
5125
5275
|
const folders = await client.getFolders(spaceId);
|
|
@@ -5138,9 +5288,9 @@ async function listFolders(config, spaceId, nameFilter) {
|
|
|
5138
5288
|
function formatFolders(folders) {
|
|
5139
5289
|
if (folders.length === 0) return "No folders found";
|
|
5140
5290
|
return folders.map((f) => {
|
|
5141
|
-
const header = `${
|
|
5291
|
+
const header = `${chalk11.bold(f.name)} ${chalk11.dim(f.id)}`;
|
|
5142
5292
|
if (f.lists.length === 0) return header;
|
|
5143
|
-
const listLines = f.lists.map((l) => ` ${
|
|
5293
|
+
const listLines = f.lists.map((l) => ` ${chalk11.dim(">")} ${l.name} ${chalk11.dim(l.id)}`);
|
|
5144
5294
|
return [header, ...listLines].join("\n");
|
|
5145
5295
|
}).join("\n\n");
|
|
5146
5296
|
}
|
|
@@ -5155,13 +5305,13 @@ function formatFoldersMarkdown(folders) {
|
|
|
5155
5305
|
}
|
|
5156
5306
|
|
|
5157
5307
|
// src/commands/time.ts
|
|
5158
|
-
import
|
|
5308
|
+
import chalk12 from "chalk";
|
|
5159
5309
|
var TIME_COLUMNS = [
|
|
5160
5310
|
{ key: "task", label: "Task", maxWidth: 35 },
|
|
5161
5311
|
{ key: "duration", label: "Duration", maxWidth: 10 },
|
|
5162
5312
|
{ key: "date", label: "Date", maxWidth: 20 },
|
|
5163
5313
|
{ key: "description", label: "Description", maxWidth: 30 },
|
|
5164
|
-
{ key: "status", label: "", maxWidth: 10, format: (v) => v === "RUNNING" ?
|
|
5314
|
+
{ key: "status", label: "", maxWidth: 10, format: (v) => v === "RUNNING" ? chalk12.green(v) : "" }
|
|
5165
5315
|
];
|
|
5166
5316
|
async function startTimer(config, taskId, description) {
|
|
5167
5317
|
const client = new ClickUpClient(config);
|
|
@@ -5257,7 +5407,7 @@ function formatTimeEntriesMarkdown(entries) {
|
|
|
5257
5407
|
}
|
|
5258
5408
|
|
|
5259
5409
|
// src/commands/tags.ts
|
|
5260
|
-
import
|
|
5410
|
+
import chalk13 from "chalk";
|
|
5261
5411
|
var TAG_COLUMNS = [
|
|
5262
5412
|
{ key: "name", label: "Name", maxWidth: 40 },
|
|
5263
5413
|
{ key: "fg", label: "FG", maxWidth: 10 },
|
|
@@ -5290,13 +5440,13 @@ function formatTags(tags) {
|
|
|
5290
5440
|
if (tags.length === 0) return "No tags found";
|
|
5291
5441
|
if (isTTY()) {
|
|
5292
5442
|
const rows = tags.map((t) => ({
|
|
5293
|
-
name: t.tag_bg ?
|
|
5443
|
+
name: t.tag_bg ? chalk13.bgHex(t.tag_bg).hex(t.tag_fg || "#ffffff")(` ${t.name} `) : chalk13.bold(t.name),
|
|
5294
5444
|
fg: t.tag_fg || "",
|
|
5295
5445
|
bg: t.tag_bg || ""
|
|
5296
5446
|
}));
|
|
5297
5447
|
return formatTable(rows, TAG_COLUMNS);
|
|
5298
5448
|
}
|
|
5299
|
-
return tags.map((t) =>
|
|
5449
|
+
return tags.map((t) => chalk13.bold(t.name)).join(", ");
|
|
5300
5450
|
}
|
|
5301
5451
|
function formatTagsMarkdown(tags) {
|
|
5302
5452
|
if (tags.length === 0) return "No tags found";
|
|
@@ -5331,7 +5481,7 @@ function formatMembersMarkdown(members) {
|
|
|
5331
5481
|
}
|
|
5332
5482
|
|
|
5333
5483
|
// src/commands/fields.ts
|
|
5334
|
-
import
|
|
5484
|
+
import chalk14 from "chalk";
|
|
5335
5485
|
var FIELD_COLUMNS = [
|
|
5336
5486
|
{ key: "id", label: "ID", maxWidth: 20 },
|
|
5337
5487
|
{ key: "name", label: "Name", maxWidth: 30 },
|
|
@@ -5340,7 +5490,7 @@ var FIELD_COLUMNS = [
|
|
|
5340
5490
|
key: "required",
|
|
5341
5491
|
label: "Required",
|
|
5342
5492
|
maxWidth: 10,
|
|
5343
|
-
format: (v) => v === "yes" ?
|
|
5493
|
+
format: (v) => v === "yes" ? chalk14.yellow(v) : chalk14.dim(v)
|
|
5344
5494
|
},
|
|
5345
5495
|
{ key: "options", label: "Options", maxWidth: 40 }
|
|
5346
5496
|
];
|
|
@@ -5447,13 +5597,13 @@ async function bulkTag(config, tagName, taskIds, action) {
|
|
|
5447
5597
|
}
|
|
5448
5598
|
|
|
5449
5599
|
// src/commands/goals.ts
|
|
5450
|
-
import
|
|
5600
|
+
import chalk15 from "chalk";
|
|
5451
5601
|
function colorProgress(value) {
|
|
5452
5602
|
const num = parseInt(value, 10);
|
|
5453
5603
|
if (isNaN(num)) return value;
|
|
5454
|
-
if (num >= 75) return
|
|
5455
|
-
if (num >= 25) return
|
|
5456
|
-
return
|
|
5604
|
+
if (num >= 75) return chalk15.green(value);
|
|
5605
|
+
if (num >= 25) return chalk15.yellow(value);
|
|
5606
|
+
return chalk15.red(value);
|
|
5457
5607
|
}
|
|
5458
5608
|
var GOAL_COLUMNS = [
|
|
5459
5609
|
{ key: "id", label: "ID", maxWidth: 15 },
|
|
@@ -5547,14 +5697,14 @@ function formatKeyResultsMarkdown(keyResults) {
|
|
|
5547
5697
|
}
|
|
5548
5698
|
|
|
5549
5699
|
// src/commands/task-types.ts
|
|
5550
|
-
import
|
|
5700
|
+
import chalk16 from "chalk";
|
|
5551
5701
|
async function listTaskTypes(config) {
|
|
5552
5702
|
const client = new ClickUpClient(config);
|
|
5553
5703
|
return client.getCustomTaskTypes(config.teamId);
|
|
5554
5704
|
}
|
|
5555
5705
|
function formatTaskTypes(types) {
|
|
5556
5706
|
if (types.length === 0) return "No custom task types";
|
|
5557
|
-
return types.map((t) => `${
|
|
5707
|
+
return types.map((t) => `${chalk16.bold(t.name)} ${chalk16.dim(`(${t.id})`)}`).join("\n");
|
|
5558
5708
|
}
|
|
5559
5709
|
function formatTaskTypesMarkdown(types) {
|
|
5560
5710
|
if (types.length === 0) return "No custom task types";
|
|
@@ -5562,14 +5712,14 @@ function formatTaskTypesMarkdown(types) {
|
|
|
5562
5712
|
}
|
|
5563
5713
|
|
|
5564
5714
|
// src/commands/templates.ts
|
|
5565
|
-
import
|
|
5715
|
+
import chalk17 from "chalk";
|
|
5566
5716
|
async function listTemplates(config) {
|
|
5567
5717
|
const client = new ClickUpClient(config);
|
|
5568
5718
|
return client.getTaskTemplates(config.teamId);
|
|
5569
5719
|
}
|
|
5570
5720
|
function formatTemplates(templates) {
|
|
5571
5721
|
if (templates.length === 0) return "No task templates";
|
|
5572
|
-
return templates.map((t) => `${
|
|
5722
|
+
return templates.map((t) => `${chalk17.bold(t.name)} ${chalk17.dim(`(${t.id})`)}`).join("\n");
|
|
5573
5723
|
}
|
|
5574
5724
|
function formatTemplatesMarkdown(templates) {
|
|
5575
5725
|
if (templates.length === 0) return "No task templates";
|
|
@@ -5577,14 +5727,14 @@ function formatTemplatesMarkdown(templates) {
|
|
|
5577
5727
|
}
|
|
5578
5728
|
|
|
5579
5729
|
// src/commands/list-templates.ts
|
|
5580
|
-
import
|
|
5730
|
+
import chalk18 from "chalk";
|
|
5581
5731
|
async function listListTemplates(config) {
|
|
5582
5732
|
const client = new ClickUpClient(config);
|
|
5583
5733
|
return client.getListTemplates(config.teamId);
|
|
5584
5734
|
}
|
|
5585
5735
|
function formatListTemplates(templates) {
|
|
5586
5736
|
if (templates.length === 0) return "No list templates";
|
|
5587
|
-
return templates.map((t) => `${
|
|
5737
|
+
return templates.map((t) => `${chalk18.bold(t.name)} ${chalk18.dim(`(${t.id})`)}`).join("\n");
|
|
5588
5738
|
}
|
|
5589
5739
|
function formatListTemplatesMarkdown(templates) {
|
|
5590
5740
|
if (templates.length === 0) return "No list templates";
|
|
@@ -5592,14 +5742,14 @@ function formatListTemplatesMarkdown(templates) {
|
|
|
5592
5742
|
}
|
|
5593
5743
|
|
|
5594
5744
|
// src/commands/folder-templates.ts
|
|
5595
|
-
import
|
|
5745
|
+
import chalk19 from "chalk";
|
|
5596
5746
|
async function listFolderTemplates(config) {
|
|
5597
5747
|
const client = new ClickUpClient(config);
|
|
5598
5748
|
return client.getFolderTemplates(config.teamId);
|
|
5599
5749
|
}
|
|
5600
5750
|
function formatFolderTemplates(templates) {
|
|
5601
5751
|
if (templates.length === 0) return "No folder templates";
|
|
5602
|
-
return templates.map((t) => `${
|
|
5752
|
+
return templates.map((t) => `${chalk19.bold(t.name)} ${chalk19.dim(`(${t.id})`)}`).join("\n");
|
|
5603
5753
|
}
|
|
5604
5754
|
function formatFolderTemplatesMarkdown(templates) {
|
|
5605
5755
|
if (templates.length === 0) return "No folder templates";
|
|
@@ -5622,7 +5772,7 @@ async function createListFromTemplate(config, name, opts) {
|
|
|
5622
5772
|
}
|
|
5623
5773
|
|
|
5624
5774
|
// src/commands/views.ts
|
|
5625
|
-
import
|
|
5775
|
+
import chalk20 from "chalk";
|
|
5626
5776
|
async function listViews(config, id, container = "list") {
|
|
5627
5777
|
const client = new ClickUpClient(config);
|
|
5628
5778
|
if (container === "space") return client.getSpaceViews(id);
|
|
@@ -5633,7 +5783,7 @@ async function listViews(config, id, container = "list") {
|
|
|
5633
5783
|
}
|
|
5634
5784
|
function formatViews(views) {
|
|
5635
5785
|
if (views.length === 0) return "No views";
|
|
5636
|
-
return views.map((v) => `${
|
|
5786
|
+
return views.map((v) => `${chalk20.bold(v.name)} ${chalk20.dim(`(${v.id})`)} ${chalk20.dim(v.type)}`).join("\n");
|
|
5637
5787
|
}
|
|
5638
5788
|
function formatViewsMarkdown(views) {
|
|
5639
5789
|
if (views.length === 0) return "No views";
|
|
@@ -5641,20 +5791,20 @@ function formatViewsMarkdown(views) {
|
|
|
5641
5791
|
}
|
|
5642
5792
|
|
|
5643
5793
|
// src/commands/view.ts
|
|
5644
|
-
import
|
|
5794
|
+
import chalk21 from "chalk";
|
|
5645
5795
|
async function getView(config, viewId) {
|
|
5646
5796
|
const client = new ClickUpClient(config);
|
|
5647
5797
|
return client.getView(viewId);
|
|
5648
5798
|
}
|
|
5649
5799
|
function formatView(view) {
|
|
5650
5800
|
const lines = [];
|
|
5651
|
-
lines.push(
|
|
5801
|
+
lines.push(chalk21.bold.underline(view.name));
|
|
5652
5802
|
lines.push("");
|
|
5653
|
-
lines.push(` ${
|
|
5654
|
-
lines.push(` ${
|
|
5655
|
-
if (view.visibility) lines.push(` ${
|
|
5656
|
-
if (view.date_created) lines.push(` ${
|
|
5657
|
-
if (view.protected !== void 0) lines.push(` ${
|
|
5803
|
+
lines.push(` ${chalk21.bold("ID")} ${view.id}`);
|
|
5804
|
+
lines.push(` ${chalk21.bold("Type")} ${view.type}`);
|
|
5805
|
+
if (view.visibility) lines.push(` ${chalk21.bold("Visibility")} ${view.visibility}`);
|
|
5806
|
+
if (view.date_created) lines.push(` ${chalk21.bold("Created")} ${formatDate(view.date_created)}`);
|
|
5807
|
+
if (view.protected !== void 0) lines.push(` ${chalk21.bold("Protected")} ${view.protected}`);
|
|
5658
5808
|
return lines.join("\n");
|
|
5659
5809
|
}
|
|
5660
5810
|
function formatViewMarkdown(view) {
|
|
@@ -5923,9 +6073,49 @@ function buildProgram(programName = basename(process.argv[1] ?? "cup")) {
|
|
|
5923
6073
|
program.command("tasks").description("List tasks assigned to me (use --all for all tasks)").option("--status <status>", 'Filter by status (e.g. "in progress")').option("--list <listId>", "Filter by list ID").option("--space <spaceId>", "Filter by space ID").option("--name <partial>", "Filter by name (case-insensitive contains)").option(
|
|
5924
6074
|
"--type <type>",
|
|
5925
6075
|
'Filter by task type (e.g. "task", "initiative", or custom type name/ID)'
|
|
5926
|
-
).option("--all", "Include all tasks, not just mine").option("--include-closed", "Include done/closed tasks").option("--json", "Force JSON output even in terminal").action(
|
|
6076
|
+
).option("--all", "Include all tasks, not just mine").option("--include-closed", "Include done/closed tasks").option("--assignee <userId>", 'Filter by assignee (user ID or "me")').option("--tag <tag>", "Filter by tag name").option("--due-before <date>", "Tasks due before date (YYYY-MM-DD)").option("--due-after <date>", "Tasks due after date (YYYY-MM-DD)").option("--created-after <date>", "Tasks created after date (YYYY-MM-DD)").option("--created-before <date>", "Tasks created before date (YYYY-MM-DD)").option("--field <nameAndValue...>", 'Filter by custom field: --field "Name" value').option("--json", "Force JSON output even in terminal").action(
|
|
5927
6077
|
wrapAction(async (opts) => {
|
|
5928
6078
|
const config = loadConfig(getProfileName());
|
|
6079
|
+
let assigneeIds;
|
|
6080
|
+
if (opts.assignee) {
|
|
6081
|
+
if (opts.assignee === "me") {
|
|
6082
|
+
const client = new ClickUpClient(config);
|
|
6083
|
+
const me = await client.getMe();
|
|
6084
|
+
assigneeIds = [me.id];
|
|
6085
|
+
} else {
|
|
6086
|
+
assigneeIds = [Number(opts.assignee)];
|
|
6087
|
+
}
|
|
6088
|
+
}
|
|
6089
|
+
const parseDateFilter = (d) => {
|
|
6090
|
+
const parts = d.split("-");
|
|
6091
|
+
return new Date(Number(parts[0]), Number(parts[1]) - 1, Number(parts[2])).getTime();
|
|
6092
|
+
};
|
|
6093
|
+
let customFields;
|
|
6094
|
+
if (opts.field?.length) {
|
|
6095
|
+
if (opts.field.length % 2 !== 0) {
|
|
6096
|
+
throw new Error('--field requires pairs: --field "Name" value');
|
|
6097
|
+
}
|
|
6098
|
+
if (!opts.list) {
|
|
6099
|
+
throw new Error("--field filtering requires --list to resolve field names");
|
|
6100
|
+
}
|
|
6101
|
+
const client = new ClickUpClient(config);
|
|
6102
|
+
const fields = await client.getListCustomFields(opts.list);
|
|
6103
|
+
customFields = [];
|
|
6104
|
+
for (let i = 0; i < opts.field.length; i += 2) {
|
|
6105
|
+
const fieldName = opts.field[i];
|
|
6106
|
+
const fieldValue = opts.field[i + 1];
|
|
6107
|
+
const match = fields.find((f) => f.name.toLowerCase() === fieldName.toLowerCase());
|
|
6108
|
+
if (!match) {
|
|
6109
|
+
const available = fields.map((f) => f.name).join(", ");
|
|
6110
|
+
throw new Error(`Field "${fieldName}" not found. Available: ${available}`);
|
|
6111
|
+
}
|
|
6112
|
+
customFields.push({
|
|
6113
|
+
field_id: match.id,
|
|
6114
|
+
operator: "=",
|
|
6115
|
+
value: fieldValue
|
|
6116
|
+
});
|
|
6117
|
+
}
|
|
6118
|
+
}
|
|
5929
6119
|
const tasks = await fetchMyTasks(config, {
|
|
5930
6120
|
typeFilter: opts.type,
|
|
5931
6121
|
statuses: opts.status ? [opts.status] : void 0,
|
|
@@ -5933,6 +6123,13 @@ function buildProgram(programName = basename(process.argv[1] ?? "cup")) {
|
|
|
5933
6123
|
spaceIds: opts.space ? [opts.space] : void 0,
|
|
5934
6124
|
name: opts.name,
|
|
5935
6125
|
all: opts.all,
|
|
6126
|
+
assignees: assigneeIds,
|
|
6127
|
+
tags: opts.tag ? [opts.tag] : void 0,
|
|
6128
|
+
dueDateLt: opts.dueBefore ? parseDateFilter(opts.dueBefore) : void 0,
|
|
6129
|
+
dueDateGt: opts.dueAfter ? parseDateFilter(opts.dueAfter) : void 0,
|
|
6130
|
+
dateCreatedGt: opts.createdAfter ? parseDateFilter(opts.createdAfter) : void 0,
|
|
6131
|
+
dateCreatedLt: opts.createdBefore ? parseDateFilter(opts.createdBefore) : void 0,
|
|
6132
|
+
customFields,
|
|
5936
6133
|
includeClosed: opts.includeClosed
|
|
5937
6134
|
});
|
|
5938
6135
|
await printTasks(tasks, opts.json ?? false, config);
|
|
@@ -6159,14 +6356,63 @@ function buildProgram(programName = basename(process.argv[1] ?? "cup")) {
|
|
|
6159
6356
|
await openTask(config, query, opts);
|
|
6160
6357
|
})
|
|
6161
6358
|
);
|
|
6162
|
-
program.command("search <query>").description("Search my tasks by name (use --all for all tasks)").option("--status <status>", "Filter by status").option("--all", "Search all tasks, not just mine").option("--include-closed", "Include done/closed tasks in search").option("--json", "Force JSON output even in terminal").action(
|
|
6359
|
+
program.command("search <query>").description("Search my tasks by name (use --all for all tasks)").option("--status <status>", "Filter by status").option("--list <listId>", "Filter by list ID").option("--space <spaceId>", "Filter by space ID").option("--all", "Search all tasks, not just mine").option("--include-closed", "Include done/closed tasks in search").option("--assignee <userId>", 'Filter by assignee (user ID or "me")').option("--tag <tag>", "Filter by tag name").option("--due-before <date>", "Tasks due before date (YYYY-MM-DD)").option("--due-after <date>", "Tasks due after date (YYYY-MM-DD)").option("--created-after <date>", "Tasks created after date (YYYY-MM-DD)").option("--created-before <date>", "Tasks created before date (YYYY-MM-DD)").option("--field <nameAndValue...>", 'Filter by custom field: --field "Name" value').option("--json", "Force JSON output even in terminal").action(
|
|
6163
6360
|
wrapAction(
|
|
6164
6361
|
async (query, opts) => {
|
|
6165
6362
|
const config = loadConfig(getProfileName());
|
|
6363
|
+
let assigneeIds;
|
|
6364
|
+
if (opts.assignee) {
|
|
6365
|
+
if (opts.assignee === "me") {
|
|
6366
|
+
const client = new ClickUpClient(config);
|
|
6367
|
+
const me = await client.getMe();
|
|
6368
|
+
assigneeIds = [me.id];
|
|
6369
|
+
} else {
|
|
6370
|
+
assigneeIds = [Number(opts.assignee)];
|
|
6371
|
+
}
|
|
6372
|
+
}
|
|
6373
|
+
const parseDateFilter = (d) => {
|
|
6374
|
+
const parts = d.split("-");
|
|
6375
|
+
return new Date(Number(parts[0]), Number(parts[1]) - 1, Number(parts[2])).getTime();
|
|
6376
|
+
};
|
|
6377
|
+
let customFields;
|
|
6378
|
+
if (opts.field?.length) {
|
|
6379
|
+
if (opts.field.length % 2 !== 0) {
|
|
6380
|
+
throw new Error('--field requires pairs: --field "Name" value');
|
|
6381
|
+
}
|
|
6382
|
+
if (!opts.list) {
|
|
6383
|
+
throw new Error("--field filtering requires --list to resolve field names");
|
|
6384
|
+
}
|
|
6385
|
+
const client = new ClickUpClient(config);
|
|
6386
|
+
const fields = await client.getListCustomFields(opts.list);
|
|
6387
|
+
customFields = [];
|
|
6388
|
+
for (let i = 0; i < opts.field.length; i += 2) {
|
|
6389
|
+
const fieldName = opts.field[i];
|
|
6390
|
+
const fieldValue = opts.field[i + 1];
|
|
6391
|
+
const match = fields.find((f) => f.name.toLowerCase() === fieldName.toLowerCase());
|
|
6392
|
+
if (!match) {
|
|
6393
|
+
const available = fields.map((f) => f.name).join(", ");
|
|
6394
|
+
throw new Error(`Field "${fieldName}" not found. Available: ${available}`);
|
|
6395
|
+
}
|
|
6396
|
+
customFields.push({
|
|
6397
|
+
field_id: match.id,
|
|
6398
|
+
operator: "=",
|
|
6399
|
+
value: fieldValue
|
|
6400
|
+
});
|
|
6401
|
+
}
|
|
6402
|
+
}
|
|
6166
6403
|
const tasks = await searchTasks(config, query, {
|
|
6167
6404
|
status: opts.status,
|
|
6168
6405
|
all: opts.all,
|
|
6169
|
-
includeClosed: opts.includeClosed
|
|
6406
|
+
includeClosed: opts.includeClosed,
|
|
6407
|
+
listIds: opts.list ? [opts.list] : void 0,
|
|
6408
|
+
spaceIds: opts.space ? [opts.space] : void 0,
|
|
6409
|
+
assignees: assigneeIds,
|
|
6410
|
+
tags: opts.tag ? [opts.tag] : void 0,
|
|
6411
|
+
dueDateLt: opts.dueBefore ? parseDateFilter(opts.dueBefore) : void 0,
|
|
6412
|
+
dueDateGt: opts.dueAfter ? parseDateFilter(opts.dueAfter) : void 0,
|
|
6413
|
+
dateCreatedGt: opts.createdAfter ? parseDateFilter(opts.createdAfter) : void 0,
|
|
6414
|
+
dateCreatedLt: opts.createdBefore ? parseDateFilter(opts.createdBefore) : void 0,
|
|
6415
|
+
customFields
|
|
6170
6416
|
});
|
|
6171
6417
|
await printTasks(tasks, opts.json ?? false, config);
|
|
6172
6418
|
}
|
|
@@ -7312,6 +7558,24 @@ function buildProgram(programName = basename(process.argv[1] ?? "cup")) {
|
|
|
7312
7558
|
process.stdout.write(script);
|
|
7313
7559
|
})
|
|
7314
7560
|
);
|
|
7561
|
+
program.command("skill").description("Install the agent skill file for your coding agents").option("--print", "Print the skill file content instead of installing").option("--path <path>", "Install to a specific path").action(
|
|
7562
|
+
wrapAction(async (opts) => {
|
|
7563
|
+
if (opts.print) {
|
|
7564
|
+
process.stdout.write(printSkill());
|
|
7565
|
+
return;
|
|
7566
|
+
}
|
|
7567
|
+
if (opts.path) {
|
|
7568
|
+
const dest = installSkillTo(opts.path);
|
|
7569
|
+
console.log(`Installed to ${dest}`);
|
|
7570
|
+
return;
|
|
7571
|
+
}
|
|
7572
|
+
const installed = await installSkillInteractive();
|
|
7573
|
+
console.log("");
|
|
7574
|
+
for (const entry of installed) {
|
|
7575
|
+
console.log(` Installed: ${entry}`);
|
|
7576
|
+
}
|
|
7577
|
+
})
|
|
7578
|
+
);
|
|
7315
7579
|
return program;
|
|
7316
7580
|
}
|
|
7317
7581
|
async function run(argv = process.argv) {
|
|
@@ -7325,7 +7589,7 @@ process.on("SIGINT", () => {
|
|
|
7325
7589
|
});
|
|
7326
7590
|
function checkDirectExecution() {
|
|
7327
7591
|
try {
|
|
7328
|
-
return process.argv[1] !== void 0 &&
|
|
7592
|
+
return process.argv[1] !== void 0 && fileURLToPath2(import.meta.url) === realpathSync(resolve(process.argv[1]));
|
|
7329
7593
|
} catch {
|
|
7330
7594
|
return false;
|
|
7331
7595
|
}
|
package/package.json
CHANGED
|
@@ -3,10 +3,12 @@ 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.'
|
|
4
4
|
---
|
|
5
5
|
|
|
6
|
-
# ClickUp CLI (`cup`)
|
|
6
|
+
# ClickUp CLI (`cup`) - skill version 1.17.0
|
|
7
7
|
|
|
8
8
|
Reference for AI agents using the `cup` CLI tool. Covers task management, sprint tracking, comments, and project workflows.
|
|
9
9
|
|
|
10
|
+
> **Version check:** Run `cup --version`. If your installed version is older than 1.18.0, update with `npm install -g @krodak/clickup-cli` and refresh this skill with `cup skill`.
|
|
11
|
+
|
|
10
12
|
## Setup
|
|
11
13
|
|
|
12
14
|
Config at `~/.config/cup/config.json` with named profiles. Each profile has `apiToken` and `teamId`. Optional: `sprintFolderId` to pin sprint detection to a specific folder. Run `cup init` to set up interactively.
|
|
@@ -48,39 +50,39 @@ All commands support `--help` for full flag details. All commands support `--jso
|
|
|
48
50
|
|
|
49
51
|
### Read
|
|
50
52
|
|
|
51
|
-
| Command
|
|
52
|
-
|
|
|
53
|
-
| `cup tasks [--status s] [--name q] [--type t] [--list id] [--space id] [--all] [--include-closed]` | My tasks (filter by status, name, type, list, space). `--all` for all tasks in workspace |
|
|
54
|
-
| `cup assigned [--status s] [--include-closed]`
|
|
55
|
-
| `cup sprint [--status s] [--space nameOrId] [--folder id] [--include-closed]`
|
|
56
|
-
| `cup sprints [--space nameOrId]`
|
|
57
|
-
| `cup search <query> [--status s] [--all] [--include-closed]`
|
|
58
|
-
| `cup task <id>`
|
|
59
|
-
| `cup subtasks <id> [--status s] [--name q] [--include-closed]`
|
|
60
|
-
| `cup comments <id>`
|
|
61
|
-
| `cup activity <id>`
|
|
62
|
-
| `cup inbox [--days n] [--include-closed]`
|
|
63
|
-
| `cup summary [--hours n]`
|
|
64
|
-
| `cup overdue [--include-closed]`
|
|
65
|
-
| `cup spaces [--name partial] [--my]`
|
|
66
|
-
| `cup lists <spaceId> [--name partial]`
|
|
67
|
-
| `cup folders <spaceId> [--name partial]`
|
|
68
|
-
| `cup members`
|
|
69
|
-
| `cup fields <listId>`
|
|
70
|
-
| `cup tags <spaceId>`
|
|
71
|
-
| `cup goals`
|
|
72
|
-
| `cup key-results <goalId>`
|
|
73
|
-
| `cup docs [query]`
|
|
74
|
-
| `cup doc <docId> [pageId]`
|
|
75
|
-
| `cup doc-pages <docId>`
|
|
76
|
-
| `cup task-types`
|
|
77
|
-
| `cup templates`
|
|
78
|
-
| `cup list-templates`
|
|
79
|
-
| `cup folder-templates`
|
|
80
|
-
| `cup views <listId>`
|
|
81
|
-
| `cup view <viewId>`
|
|
82
|
-
| `cup open <query>`
|
|
83
|
-
| `cup auth`
|
|
53
|
+
| Command | What it returns |
|
|
54
|
+
| ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------- |
|
|
55
|
+
| `cup tasks [--status s] [--name q] [--type t] [--list id] [--space id] [--all] [--include-closed] [--assignee id\|me] [--tag t] [--due-before d] [--due-after d] [--created-after d] [--created-before d] [--field "Name" val]` | My tasks (filter by status, name, type, list, space, assignee, tag, dates, custom fields). `--all` for all tasks in workspace |
|
|
56
|
+
| `cup assigned [--status s] [--include-closed]` | All my tasks grouped by status |
|
|
57
|
+
| `cup sprint [--status s] [--space nameOrId] [--folder id] [--include-closed]` | Tasks in active sprint (auto-detected) |
|
|
58
|
+
| `cup sprints [--space nameOrId]` | List all sprints (marks active with \*) |
|
|
59
|
+
| `cup search <query> [--status s] [--list id] [--space id] [--all] [--include-closed] [--assignee id\|me] [--tag t] [--due-before d] [--due-after d] [--created-after d] [--created-before d] [--field "Name" val]` | Search my tasks by name. `--all` for all tasks |
|
|
60
|
+
| `cup task <id>` | Single task details (custom fields, checklists, attachments, deps, links) |
|
|
61
|
+
| `cup subtasks <id> [--status s] [--name q] [--include-closed]` | Subtasks of a task |
|
|
62
|
+
| `cup comments <id>` | Comments on a task |
|
|
63
|
+
| `cup activity <id>` | Task details + comment history combined |
|
|
64
|
+
| `cup inbox [--days n] [--include-closed]` | Tasks updated in last n days (default 30) |
|
|
65
|
+
| `cup summary [--hours n]` | Standup: completed, in-progress, overdue |
|
|
66
|
+
| `cup overdue [--include-closed]` | Tasks past due date (most overdue first) |
|
|
67
|
+
| `cup spaces [--name partial] [--my]` | List/filter workspace spaces |
|
|
68
|
+
| `cup lists <spaceId> [--name partial]` | Lists in a space (including folder lists) |
|
|
69
|
+
| `cup folders <spaceId> [--name partial]` | Folders in a space (with their lists) |
|
|
70
|
+
| `cup members` | Workspace members (username, ID, email) |
|
|
71
|
+
| `cup fields <listId>` | Custom fields on a list (type, required, options) |
|
|
72
|
+
| `cup tags <spaceId>` | Tags available in a space |
|
|
73
|
+
| `cup goals` | Workspace goals with progress |
|
|
74
|
+
| `cup key-results <goalId>` | Key results for a goal |
|
|
75
|
+
| `cup docs [query]` | Workspace docs (optionally filter by name) |
|
|
76
|
+
| `cup doc <docId> [pageId]` | Doc metadata + page tree, or a specific page |
|
|
77
|
+
| `cup doc-pages <docId>` | All pages in a doc with content |
|
|
78
|
+
| `cup task-types` | Custom task types (for `--custom-item-id`) |
|
|
79
|
+
| `cup templates` | Task templates (for `--template`) |
|
|
80
|
+
| `cup list-templates` | List templates (for `list-from-template`) |
|
|
81
|
+
| `cup folder-templates` | Folder templates |
|
|
82
|
+
| `cup views <listId>` | List views on a list |
|
|
83
|
+
| `cup view <viewId>` | Get view details |
|
|
84
|
+
| `cup open <query>` | Open task in browser by ID or name |
|
|
85
|
+
| `cup auth` | Check authentication status |
|
|
84
86
|
|
|
85
87
|
### Write
|
|
86
88
|
|
|
@@ -157,28 +159,31 @@ All commands support `--help` for full flag details. All commands support `--jso
|
|
|
157
159
|
|
|
158
160
|
## Flags & Conventions
|
|
159
161
|
|
|
160
|
-
| Topic
|
|
161
|
-
|
|
|
162
|
-
| Task IDs
|
|
163
|
-
| `--status`
|
|
164
|
-
| `--priority`
|
|
165
|
-
| `--due-date`
|
|
166
|
-
| `--assignee`
|
|
167
|
-
| `--tags`
|
|
168
|
-
| `--time-estimate`
|
|
169
|
-
| `--type`
|
|
170
|
-
| `--custom-item-id`
|
|
171
|
-
| `--space`
|
|
172
|
-
| `--name`
|
|
173
|
-
| `--all`
|
|
174
|
-
| `--include-closed`
|
|
175
|
-
| `--list` on create
|
|
176
|
-
| `cup field --set`
|
|
177
|
-
| `cup field-create`
|
|
178
|
-
| `
|
|
179
|
-
| `
|
|
180
|
-
| `
|
|
181
|
-
|
|
|
162
|
+
| Topic | Detail |
|
|
163
|
+
| ------------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
164
|
+
| Task IDs | Native (`abc123def`) or custom (`PROJ-123`). Custom IDs auto-detected by `PREFIX-DIGITS` format |
|
|
165
|
+
| `--status` | Fuzzy matching: exact > starts-with > contains. Prints match to stderr |
|
|
166
|
+
| `--priority` | Names (`urgent`, `high`, `normal`, `low`) or numbers (1-4) |
|
|
167
|
+
| `--due-date` | `YYYY-MM-DD` format |
|
|
168
|
+
| `--assignee` | User ID or `me` |
|
|
169
|
+
| `--tags` | Comma-separated (e.g. `--tags "bug,frontend"`) |
|
|
170
|
+
| `--time-estimate` | Duration: `"2h"`, `"30m"`, `"1h30m"`, or raw milliseconds |
|
|
171
|
+
| `--type` | `task` (regular) or custom type name/ID (e.g. `initiative`, `Bug`) |
|
|
172
|
+
| `--custom-item-id` | Custom task type ID for `cup create` (find with `cup task-types`) |
|
|
173
|
+
| `--space` | Partial name match or exact ID |
|
|
174
|
+
| `--name` | Partial match, case-insensitive |
|
|
175
|
+
| `--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) |
|
|
176
|
+
| `--include-closed` | Include closed/done tasks |
|
|
177
|
+
| `--list` on create | Optional when `--parent` is given (auto-detected) |
|
|
178
|
+
| `cup field --set` | Supports: text, number, checkbox (true/false), dropdown (option name), date (YYYY-MM-DD), url, email. Names resolved case-insensitively; errors list available fields/options |
|
|
179
|
+
| `cup field-create` | Use `--options "a,b,c"` for `drop_down` and `labels` types (required). Other types don't need `--options` |
|
|
180
|
+
| `--field` filter | `--field "Name" value` on `tasks` and `search` requires `--list` to resolve field names to IDs |
|
|
181
|
+
| `--due-before/after` | `YYYY-MM-DD` date filters for due date range |
|
|
182
|
+
| `--created-before/after` | `YYYY-MM-DD` date filters for creation date range |
|
|
183
|
+
| `cup sprint` | Auto-detects active sprint by folder name (sprint/iteration/cycle/scrum), parses multiple date formats. Override with `--folder <id>` or `cup config set sprintFolderId <id>` |
|
|
184
|
+
| `cup link` | Both IDs must be the same type (both custom or both native) |
|
|
185
|
+
| `cup delete` | DESTRUCTIVE. Requires `--confirm` in non-interactive mode. Cannot be undone |
|
|
186
|
+
| Errors | stderr with exit code 1. Strict parsing - excess/unknown arguments rejected |
|
|
182
187
|
|
|
183
188
|
## Agent Workflow Examples
|
|
184
189
|
|
|
@@ -199,8 +204,13 @@ cup tasks --status "in progress" # by status
|
|
|
199
204
|
cup tasks --name "login" # by partial name
|
|
200
205
|
cup tasks --type initiative # initiatives only
|
|
201
206
|
cup tasks --list 12345 --all # all tasks in list, not just mine
|
|
207
|
+
cup tasks --tag "bug" --status "to do" # by tag and status
|
|
208
|
+
cup tasks --list 123 --field "Sprint" "Week 1" # by custom field
|
|
209
|
+
cup tasks --due-before 2026-04-01 # due before a date
|
|
210
|
+
cup tasks --assignee me --created-after 2026-03-01 # my tasks created recently
|
|
202
211
|
cup search "payment flow" # multi-word search
|
|
203
212
|
cup search auth --status "prog" # fuzzy status match
|
|
213
|
+
cup search "auth" --list 123 --space 456 # search within list and space
|
|
204
214
|
cup sprint # current sprint
|
|
205
215
|
cup assigned # all my tasks by status
|
|
206
216
|
cup overdue # past due date
|