@krodak/clickup-cli 1.6.0 → 1.6.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.
@@ -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.6.0",
4
+ "version": "1.6.1",
5
5
  "author": {
6
6
  "name": "Krzysztof Rodak"
7
7
  },
package/README.md CHANGED
@@ -1,18 +1,19 @@
1
- # cup - ClickUp CLI
2
-
3
- > A ClickUp CLI built for AI agents that also works well for humans. Outputs Markdown when piped (optimized for AI context windows), interactive tables when run in a terminal.
4
-
5
- [![npm](https://img.shields.io/npm/v/@krodak/clickup-cli)](https://www.npmjs.com/package/@krodak/clickup-cli)
6
- [![node](https://img.shields.io/node/v/@krodak/clickup-cli)](https://nodejs.org)
7
- [![license](https://img.shields.io/npm/l/@krodak/clickup-cli)](./LICENSE)
8
- [![CI](https://github.com/krodak/clickup-cli/actions/workflows/ci.yml/badge.svg)](https://github.com/krodak/clickup-cli/actions/workflows/ci.yml)
1
+ <p align="center">
2
+ <img src="banner.png" alt="cup - ClickUp CLI for AI agents (and humans)" width="100%">
3
+ </p>
4
+
5
+ <p align="center">
6
+ <a href="https://www.npmjs.com/package/@krodak/clickup-cli"><img src="https://img.shields.io/npm/v/@krodak/clickup-cli" alt="npm"></a>
7
+ <a href="https://nodejs.org"><img src="https://img.shields.io/node/v/@krodak/clickup-cli" alt="node"></a>
8
+ <a href="./LICENSE"><img src="https://img.shields.io/npm/l/@krodak/clickup-cli" alt="license"></a>
9
+ <a href="https://github.com/krodak/clickup-cli/actions/workflows/ci.yml"><img src="https://github.com/krodak/clickup-cli/actions/workflows/ci.yml/badge.svg" alt="CI"></a>
10
+ <a href="https://github.com/krodak/homebrew-tap"><img src="https://img.shields.io/badge/homebrew-tap-FBB040?logo=homebrew&logoColor=black" alt="homebrew"></a>
11
+ </p>
9
12
 
10
13
  ```bash
11
14
  npm install -g @krodak/clickup-cli && cup init
12
15
  ```
13
16
 
14
- `cup` is the binary name. The previous `cu` name was retired in v0.21.0 to avoid conflict with the Unix [cu(1)](<https://en.wikipedia.org/wiki/Cu_(Unix_utility)>) utility.
15
-
16
17
  ## Talk to your agent
17
18
 
18
19
  Install the CLI, add the skill file to your agent, and it works with ClickUp. No API knowledge needed.
@@ -29,6 +30,18 @@ Install the CLI, add the skill file to your agent, and it works with ClickUp. No
29
30
 
30
31
  The agent reads the skill file, picks the right `cup` commands, and handles everything. You don't need to learn the CLI - the agent does.
31
32
 
33
+ ### Agent mode
34
+
35
+ When piped (no TTY), output is Markdown optimized for AI context windows. Pass `--json` for structured data.
36
+
37
+ ![Agent Mode - markdown and JSON output](demos/agent-mode.gif)
38
+
39
+ ### Terminal mode
40
+
41
+ In a terminal, you get interactive tables with colors. Most commands scope to your assigned tasks by default.
42
+
43
+ ![TTY Mode - interactive tables and detail views](demos/tty-mode.gif)
44
+
32
45
  ## Why a CLI and not MCP?
33
46
 
34
47
  A CLI + skill file has fewer moving parts. No server process, no protocol layer. The agent already knows how to run shell commands - the skill file teaches it which ones exist. For tool-use with coding agents, CLI + instructions tends to work better than MCP in practice.
@@ -130,39 +143,22 @@ The skill file follows the [Agent Skills](https://agentskills.io) open standard.
130
143
 
131
144
  Full CRUD for the core ClickUp workflow:
132
145
 
133
- **Tasks** - create, read, update, delete, duplicate, search, subtasks, assign, dependencies, links, multi-list, bulk status updates
134
-
135
- **Comments** - post, edit, delete, threaded replies, notify all
136
-
137
- **Docs** - list, read, create, edit, delete (v3 API)
138
-
139
- **Time Tracking** - start/stop timer, log entries, list/update/delete history
140
-
141
- **Checklists** - view, create, delete, add/edit/delete items
142
-
143
- **Custom Fields** - list, set, remove values (dropdown, date, checkbox, text, etc.)
144
-
145
- **Tags** - add/remove on tasks, space-level create/update/delete
146
-
147
- **Goals & OKRs** - goals CRUD, key results CRUD
148
-
149
- **Sprints** - auto-detect active sprint, flexible date parsing, config override
150
-
151
- **Workspace** - spaces, folders, lists, members, task types, templates
152
-
153
- **Attachments** - upload files to tasks, shown in detail views
146
+ | Area | Capabilities |
147
+ | -------------------- | ----------------------------------------------------------------------------------------------------------------------- |
148
+ | ✅ **Tasks** | Create, read, update, delete, duplicate, search, subtasks, assign, dependencies, links, multi-list, bulk status updates |
149
+ | 💬 **Comments** | Post, edit, delete, threaded replies, notify all |
150
+ | 📄 **Docs** | List, read, create, edit, delete (v3 API) |
151
+ | ⏱️ **Time Tracking** | Start/stop timer, log entries, list/update/delete history |
152
+ | ☑️ **Checklists** | View, create, delete, add/edit/delete items |
153
+ | 🔧 **Custom Fields** | List, set, remove values (dropdown, date, checkbox, text, etc.) |
154
+ | 🏷️ **Tags** | Add/remove on tasks, space-level create/update/delete |
155
+ | 🎯 **Goals & OKRs** | Goals CRUD, key results CRUD |
156
+ | 🏃 **Sprints** | Auto-detect active sprint, flexible date parsing, config override |
157
+ | 🏢 **Workspace** | Spaces, folders, lists, members, task types, templates |
158
+ | 📎 **Attachments** | Upload files to tasks, shown in detail views |
154
159
 
155
160
  [Full API coverage details](docs/api-coverage.md) | [Command reference](docs/commands.md)
156
161
 
157
- ## Output Modes
158
-
159
- | Context | Default | Override |
160
- | -------------- | --------------------------- | ---------------------------- |
161
- | Terminal (TTY) | Interactive tables + picker | `--json` |
162
- | Piped (no TTY) | Markdown (optimized for AI) | `--json` or `CU_OUTPUT=json` |
163
-
164
- Most commands scope to your assigned tasks by default - keeping output small and relevant for agent context windows.
165
-
166
162
  ## Configuration
167
163
 
168
164
  ### Profiles
@@ -213,23 +209,6 @@ Environment variables override config file values:
213
209
 
214
210
  When both `CU_API_TOKEN` and `CU_TEAM_ID` are set, the config file is not required. Useful for CI/CD and containerized agents.
215
211
 
216
- ## Custom Task IDs
217
-
218
- ClickUp workspaces can configure custom task IDs with a prefix per space (e.g., `PROJ-123`, `DEV-42`). The CLI detects these automatically - any ID matching the `PREFIX-DIGITS` format (uppercase letters, hyphen, digits) is treated as a custom task ID.
219
-
220
- All commands that accept task IDs work with both native IDs and custom IDs:
221
-
222
- ```bash
223
- cup task PROJ-123
224
- cup update DEV-42 --status done
225
- cup comment PROJ-456 -m "Fixed in latest commit"
226
- cup subtasks DEV-100
227
- ```
228
-
229
- Custom ID resolution uses the `teamId` from your config, which is required (`cup init` sets it up).
230
-
231
- **Task links with custom IDs:** The `cup link` command passes both task IDs in a single API request. When both IDs are custom, this works correctly. However, mixing custom and native IDs in a single link command may not work as expected because the ClickUp API applies the `custom_task_ids` flag to all IDs in the request.
232
-
233
212
  ## Development
234
213
 
235
214
  ```bash
package/dist/index.js CHANGED
@@ -100,6 +100,12 @@ var ClickUpClient = class {
100
100
  ...options.headers
101
101
  }
102
102
  });
103
+ if (res.status === 204 || res.headers.get("content-length") === "0") {
104
+ if (!res.ok) {
105
+ throw new Error(`ClickUp API error ${res.status}: ${res.statusText}`);
106
+ }
107
+ return {};
108
+ }
103
109
  let parsed;
104
110
  try {
105
111
  parsed = await res.json();
@@ -1567,7 +1573,10 @@ function parseTimeEstimate(value) {
1567
1573
  }
1568
1574
  function buildUpdatePayload(opts) {
1569
1575
  const payload = {};
1570
- if (opts.name !== void 0) payload.name = opts.name;
1576
+ if (opts.name !== void 0) {
1577
+ if (!opts.name.trim()) throw new Error("Task name cannot be empty");
1578
+ payload.name = opts.name;
1579
+ }
1571
1580
  if (opts.description !== void 0) payload.markdown_content = opts.description;
1572
1581
  if (opts.status !== void 0) payload.status = opts.status;
1573
1582
  if (opts.priority !== void 0) payload.priority = parsePriority(opts.priority);
@@ -1616,6 +1625,7 @@ async function updateTask(config, taskId, options) {
1616
1625
 
1617
1626
  // src/commands/create.ts
1618
1627
  async function createTask(config, options) {
1628
+ if (!options.name.trim()) throw new Error("Task name cannot be empty");
1619
1629
  const client = new ClickUpClient(config);
1620
1630
  let listId = options.list;
1621
1631
  if (!listId && options.parent) {
@@ -4772,7 +4782,7 @@ function wrapAction(fn) {
4772
4782
  return async (...args) => {
4773
4783
  await fn(...args).catch((err) => {
4774
4784
  console.error(err instanceof Error ? err.message : String(err));
4775
- process.exit(1);
4785
+ process.exitCode = 1;
4776
4786
  });
4777
4787
  };
4778
4788
  }
@@ -5822,14 +5832,16 @@ async function run(argv = process.argv) {
5822
5832
  }
5823
5833
  process.on("SIGINT", () => {
5824
5834
  process.stderr.write("\nInterrupted\n");
5825
- process.exit(130);
5835
+ process.exitCode = 130;
5826
5836
  });
5827
- var isDirectExecution = false;
5828
- try {
5829
- isDirectExecution = process.argv[1] !== void 0 && fileURLToPath(import.meta.url) === realpathSync(resolve(process.argv[1]));
5830
- } catch {
5831
- isDirectExecution = false;
5837
+ function checkDirectExecution() {
5838
+ try {
5839
+ return process.argv[1] !== void 0 && fileURLToPath(import.meta.url) === realpathSync(resolve(process.argv[1]));
5840
+ } catch {
5841
+ return false;
5842
+ }
5832
5843
  }
5844
+ var isDirectExecution = checkDirectExecution();
5833
5845
  if (isDirectExecution) {
5834
5846
  await run();
5835
5847
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@krodak/clickup-cli",
3
- "version": "1.6.0",
3
+ "version": "1.6.1",
4
4
  "description": "ClickUp CLI for AI agents and humans",
5
5
  "type": "module",
6
6
  "license": "MIT",