@krodak/clickup-cli 0.9.1 → 0.10.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/README.md CHANGED
@@ -98,7 +98,7 @@ When output is piped (no TTY), all commands output **Markdown** by default - opt
98
98
 
99
99
  ## Commands
100
100
 
101
- 24 commands total. All support `--help` for full flag details.
101
+ 25 commands total. All support `--help` for full flag details.
102
102
 
103
103
  ### `cu init`
104
104
 
@@ -206,18 +206,20 @@ cu update abc123 --priority high
206
206
  cu update abc123 --due-date 2025-03-15
207
207
  cu update abc123 --assignee 12345
208
208
  cu update abc123 -n "New name" -s "done" --priority urgent
209
+ cu update abc123 --time-estimate 2h
209
210
  cu update abc123 -s "in progress" --json
210
211
  ```
211
212
 
212
- | Flag | Description |
213
- | -------------------------- | --------------------------------------------------------------------------- |
214
- | `-n, --name <text>` | New task name |
215
- | `-d, --description <text>` | New description (markdown supported) |
216
- | `-s, --status <status>` | New status, supports fuzzy matching (e.g. `"prog"` matches `"in progress"`) |
217
- | `--priority <level>` | Priority: `urgent`, `high`, `normal`, `low` (or 1-4) |
218
- | `--due-date <date>` | Due date (`YYYY-MM-DD`) |
219
- | `--assignee <userId>` | Add assignee by numeric user ID |
220
- | `--json` | Force JSON output even in terminal |
213
+ | Flag | Description |
214
+ | ---------------------------- | --------------------------------------------------------------------------- |
215
+ | `-n, --name <text>` | New task name |
216
+ | `-d, --description <text>` | New description (markdown supported) |
217
+ | `-s, --status <status>` | New status, supports fuzzy matching (e.g. `"prog"` matches `"in progress"`) |
218
+ | `--priority <level>` | Priority: `urgent`, `high`, `normal`, `low` (or 1-4) |
219
+ | `--due-date <date>` | Due date (`YYYY-MM-DD`) |
220
+ | `--time-estimate <duration>` | Time estimate (e.g. `"2h"`, `"30m"`, `"1h30m"`) |
221
+ | `--assignee <userId>` | Add assignee by numeric user ID |
222
+ | `--json` | Force JSON output even in terminal |
221
223
 
222
224
  ### `cu create`
223
225
 
@@ -229,21 +231,25 @@ cu create -n "Subtask name" -p <parentTaskId> # --list auto-detected
229
231
  cu create -n "Task" -l <listId> -d "desc" -s "open"
230
232
  cu create -n "Task" -l <listId> --priority high --due-date 2025-06-01
231
233
  cu create -n "Task" -l <listId> --assignee 12345 --tags "bug,frontend"
234
+ cu create -n "Initiative" -l <listId> --custom-item-id 1
235
+ cu create -n "Task" -l <listId> --time-estimate 2h
232
236
  cu create -n "Fix bug" -l <listId> --json
233
237
  ```
234
238
 
235
- | Flag | Required | Description |
236
- | -------------------------- | ---------------- | ---------------------------------------------------- |
237
- | `-n, --name <name>` | yes | Task name |
238
- | `-l, --list <listId>` | if no `--parent` | Target list ID |
239
- | `-p, --parent <taskId>` | no | Parent task (list auto-detected) |
240
- | `-d, --description <text>` | no | Description (markdown) |
241
- | `-s, --status <status>` | no | Initial status |
242
- | `--priority <level>` | no | Priority: `urgent`, `high`, `normal`, `low` (or 1-4) |
243
- | `--due-date <date>` | no | Due date (`YYYY-MM-DD`) |
244
- | `--assignee <userId>` | no | Assignee by numeric user ID |
245
- | `--tags <tags>` | no | Comma-separated tag names |
246
- | `--json` | no | Force JSON output even in terminal |
239
+ | Flag | Required | Description |
240
+ | ---------------------------- | ---------------- | ---------------------------------------------------- |
241
+ | `-n, --name <name>` | yes | Task name |
242
+ | `-l, --list <listId>` | if no `--parent` | Target list ID |
243
+ | `-p, --parent <taskId>` | no | Parent task (list auto-detected) |
244
+ | `-d, --description <text>` | no | Description (markdown) |
245
+ | `-s, --status <status>` | no | Initial status |
246
+ | `--priority <level>` | no | Priority: `urgent`, `high`, `normal`, `low` (or 1-4) |
247
+ | `--due-date <date>` | no | Due date (`YYYY-MM-DD`) |
248
+ | `--time-estimate <duration>` | no | Time estimate (e.g. `"2h"`, `"30m"`, `"1h30m"`) |
249
+ | `--assignee <userId>` | no | Assignee by numeric user ID |
250
+ | `--tags <tags>` | no | Comma-separated tag names |
251
+ | `--custom-item-id <id>` | no | Custom task type ID (for creating initiatives) |
252
+ | `--json` | no | Force JSON output even in terminal |
247
253
 
248
254
  ### `cu comment <id>`
249
255
 
@@ -368,6 +374,25 @@ cu assign abc123 --to me --json
368
374
  | `--remove <userId>` | Remove assignee (user ID or `me`) |
369
375
  | `--json` | Force JSON output |
370
376
 
377
+ ### `cu depend <id>`
378
+
379
+ Add or remove task dependencies. Set a task as waiting on or blocking another task.
380
+
381
+ ```bash
382
+ cu depend abc123 --on def456 # abc123 depends on (waits for) def456
383
+ cu depend abc123 --blocks def456 # abc123 blocks def456
384
+ cu depend abc123 --on def456 --remove # remove the dependency
385
+ cu depend abc123 --blocks def456 --remove
386
+ cu depend abc123 --on def456 --json
387
+ ```
388
+
389
+ | Flag | Description |
390
+ | ------------------- | ------------------------------------------- |
391
+ | `--on <taskId>` | Task that this task depends on (waiting on) |
392
+ | `--blocks <taskId>` | Task that this task blocks |
393
+ | `--remove` | Remove the dependency instead of adding it |
394
+ | `--json` | Force JSON output |
395
+
371
396
  ### `cu auth`
372
397
 
373
398
  Check authentication status. Validates your API token and shows your user info.
package/dist/index.js CHANGED
@@ -223,6 +223,23 @@ var ClickUpClient = class {
223
223
  async getViewTasks(viewId) {
224
224
  return this.paginate((page) => `/view/${viewId}/task?page=${page}`);
225
225
  }
226
+ async addDependency(taskId, opts) {
227
+ const body = {};
228
+ if (opts.dependsOn) body.depends_on = opts.dependsOn;
229
+ if (opts.dependencyOf) body.dependency_of = opts.dependencyOf;
230
+ await this.request(`/task/${taskId}/dependency`, {
231
+ method: "POST",
232
+ body: JSON.stringify(body)
233
+ });
234
+ }
235
+ async deleteDependency(taskId, opts) {
236
+ const params = new URLSearchParams();
237
+ if (opts.dependsOn) params.set("depends_on", opts.dependsOn);
238
+ if (opts.dependencyOf) params.set("dependency_of", opts.dependencyOf);
239
+ await this.request(`/task/${taskId}/dependency?${params.toString()}`, {
240
+ method: "DELETE"
241
+ });
242
+ }
226
243
  };
227
244
 
228
245
  // src/output.ts
@@ -680,6 +697,18 @@ function parseAssigneeId(value) {
680
697
  if (!Number.isInteger(id)) throw new Error("Assignee must be a numeric user ID");
681
698
  return id;
682
699
  }
700
+ function parseTimeEstimate(value) {
701
+ const pattern = /^(?:(\d+)h)?(?:(\d+)m)?$/i;
702
+ const match = value.match(pattern);
703
+ if (match && (match[1] || match[2])) {
704
+ const hours = Number(match[1] ?? 0);
705
+ const minutes = Number(match[2] ?? 0);
706
+ return (hours * 60 + minutes) * 60 * 1e3;
707
+ }
708
+ const ms = Number(value);
709
+ if (Number.isFinite(ms) && ms > 0) return ms;
710
+ throw new Error('Time estimate must be a duration (e.g. "2h", "30m", "1h30m") or milliseconds');
711
+ }
683
712
  function buildUpdatePayload(opts) {
684
713
  const payload = {};
685
714
  if (opts.name !== void 0) payload.name = opts.name;
@@ -693,10 +722,13 @@ function buildUpdatePayload(opts) {
693
722
  if (opts.assignee !== void 0) {
694
723
  payload.assignees = { add: [parseAssigneeId(opts.assignee)] };
695
724
  }
725
+ if (opts.timeEstimate !== void 0) {
726
+ payload.time_estimate = parseTimeEstimate(opts.timeEstimate);
727
+ }
696
728
  return payload;
697
729
  }
698
730
  function hasUpdateFields(options) {
699
- return options.name !== void 0 || options.description !== void 0 || options.status !== void 0 || options.priority !== void 0 || options.due_date !== void 0 || options.assignees !== void 0;
731
+ return options.name !== void 0 || options.description !== void 0 || options.status !== void 0 || options.priority !== void 0 || options.due_date !== void 0 || options.time_estimate !== void 0 || options.assignees !== void 0;
700
732
  }
701
733
  async function resolveStatus(client, taskId, statusInput) {
702
734
  const task = await client.getTask(taskId);
@@ -716,7 +748,7 @@ async function resolveStatus(client, taskId, statusInput) {
716
748
  async function updateTask(config, taskId, options) {
717
749
  if (!hasUpdateFields(options))
718
750
  throw new Error(
719
- "Provide at least one of: --name, --description, --status, --priority, --due-date, --assignee"
751
+ "Provide at least one of: --name, --description, --status, --priority, --due-date, --time-estimate, --assignee"
720
752
  );
721
753
  const client = new ClickUpClient(config);
722
754
  if (options.status !== void 0) {
@@ -756,6 +788,15 @@ async function createTask(config, options) {
756
788
  if (options.tags !== void 0) {
757
789
  payload.tags = options.tags.split(",").map((t) => t.trim());
758
790
  }
791
+ if (options.customItemId !== void 0) {
792
+ const id = Number(options.customItemId);
793
+ if (!Number.isInteger(id) || id < 0)
794
+ throw new Error("Custom item ID must be a non-negative integer");
795
+ payload.custom_item_id = id;
796
+ }
797
+ if (options.timeEstimate !== void 0) {
798
+ payload.time_estimate = parseTimeEstimate(options.timeEstimate);
799
+ }
759
800
  const task = await client.createTask(listId, payload);
760
801
  return { id: task.id, name: task.name, url: task.url };
761
802
  }
@@ -1979,6 +2020,31 @@ async function searchTasks(config, query, opts = {}) {
1979
2020
  return matched.map(summarize);
1980
2021
  }
1981
2022
 
2023
+ // src/commands/depend.ts
2024
+ async function manageDependency(config, taskId, opts) {
2025
+ if (!opts.on && !opts.blocks) {
2026
+ throw new Error("Provide --on <taskId> or --blocks <taskId>");
2027
+ }
2028
+ if (opts.on && opts.blocks) {
2029
+ throw new Error("Provide only one of --on or --blocks per invocation");
2030
+ }
2031
+ const client = new ClickUpClient(config);
2032
+ if (opts.remove) {
2033
+ await client.deleteDependency(taskId, {
2034
+ dependsOn: opts.on,
2035
+ dependencyOf: opts.blocks
2036
+ });
2037
+ if (opts.on) return `Removed dependency: ${taskId} no longer depends on ${opts.on}`;
2038
+ return `Removed dependency: ${taskId} no longer blocks ${opts.blocks}`;
2039
+ }
2040
+ await client.addDependency(taskId, {
2041
+ dependsOn: opts.on,
2042
+ dependencyOf: opts.blocks
2043
+ });
2044
+ if (opts.on) return `Added dependency: ${taskId} depends on ${opts.on}`;
2045
+ return `Added dependency: ${taskId} blocks ${opts.blocks}`;
2046
+ }
2047
+
1982
2048
  // src/index.ts
1983
2049
  var require2 = createRequire(import.meta.url);
1984
2050
  var { version } = require2("../package.json");
@@ -2050,7 +2116,7 @@ program.command("task <taskId>").description("Get task details").option("--json"
2050
2116
  }
2051
2117
  })
2052
2118
  );
2053
- program.command("update <taskId>").description("Update a task").option("-n, --name <text>", "New task name").option("-d, --description <text>", "New description (markdown supported)").option("-s, --status <status>", 'New status (e.g. "in progress", "done")').option("--priority <level>", "Priority: urgent, high, normal, low (or 1-4)").option("--due-date <date>", "Due date (YYYY-MM-DD)").option("--assignee <userId>", "Add assignee by user ID").option("--json", "Force JSON output even in terminal").action(
2119
+ program.command("update <taskId>").description("Update a task").option("-n, --name <text>", "New task name").option("-d, --description <text>", "New description (markdown supported)").option("-s, --status <status>", 'New status (e.g. "in progress", "done")').option("--priority <level>", "Priority: urgent, high, normal, low (or 1-4)").option("--due-date <date>", "Due date (YYYY-MM-DD)").option("--time-estimate <duration>", 'Time estimate (e.g. "2h", "30m", "1h30m")').option("--assignee <userId>", "Add assignee by user ID").option("--json", "Force JSON output even in terminal").action(
2054
2120
  wrapAction(async (taskId, opts) => {
2055
2121
  const config = loadConfig();
2056
2122
  const payload = buildUpdatePayload(opts);
@@ -2062,7 +2128,7 @@ program.command("update <taskId>").description("Update a task").option("-n, --na
2062
2128
  }
2063
2129
  })
2064
2130
  );
2065
- program.command("create").description("Create a new task").option("-l, --list <listId>", "Target list ID (auto-detected from --parent if omitted)").requiredOption("-n, --name <name>", "Task name").option("-d, --description <text>", "Task description").option("-p, --parent <taskId>", "Parent task ID (list auto-detected from parent)").option("-s, --status <status>", "Initial status").option("--priority <level>", "Priority: urgent, high, normal, low (or 1-4)").option("--due-date <date>", "Due date (YYYY-MM-DD)").option("--assignee <userId>", "Assignee user ID").option("--tags <tags>", "Comma-separated tag names").option("--json", "Force JSON output even in terminal").action(
2131
+ program.command("create").description("Create a new task").option("-l, --list <listId>", "Target list ID (auto-detected from --parent if omitted)").requiredOption("-n, --name <name>", "Task name").option("-d, --description <text>", "Task description").option("-p, --parent <taskId>", "Parent task ID (list auto-detected from parent)").option("-s, --status <status>", "Initial status").option("--priority <level>", "Priority: urgent, high, normal, low (or 1-4)").option("--due-date <date>", "Due date (YYYY-MM-DD)").option("--assignee <userId>", "Assignee user ID").option("--tags <tags>", "Comma-separated tag names").option("--custom-item-id <id>", "Custom task type ID (use to create initiatives)").option("--time-estimate <duration>", 'Time estimate (e.g. "2h", "30m", "1h30m")').option("--json", "Force JSON output even in terminal").action(
2066
2132
  wrapAction(async (opts) => {
2067
2133
  const config = loadConfig();
2068
2134
  const result = await createTask(config, opts);
@@ -2190,6 +2256,17 @@ program.command("assign <taskId>").description("Assign or unassign users from a
2190
2256
  }
2191
2257
  })
2192
2258
  );
2259
+ program.command("depend <taskId>").description("Add or remove task dependencies").option("--on <taskId>", "Task that this task depends on (waiting on)").option("--blocks <taskId>", "Task that this task blocks").option("--remove", "Remove the dependency instead of adding it").option("--json", "Force JSON output even in terminal").action(
2260
+ wrapAction(async (taskId, opts) => {
2261
+ const config = loadConfig();
2262
+ const message = await manageDependency(config, taskId, opts);
2263
+ if (shouldOutputJson(opts.json ?? false)) {
2264
+ console.log(JSON.stringify({ taskId, ...opts, message }, null, 2));
2265
+ } else {
2266
+ console.log(message);
2267
+ }
2268
+ })
2269
+ );
2193
2270
  var configCmd = program.command("config").description("Manage CLI configuration");
2194
2271
  configCmd.command("get <key>").description("Print a config value").action(
2195
2272
  wrapAction(async (key) => {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@krodak/clickup-cli",
3
- "version": "0.9.1",
3
+ "version": "0.10.0",
4
4
  "description": "ClickUp CLI for AI agents and humans",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -56,14 +56,15 @@ All commands support `--help` for full flag details.
56
56
 
57
57
  ### Write
58
58
 
59
- | Command | What it does |
60
- | ------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------- |
61
- | `cu update <id> [-n name] [-d desc] [-s status] [--priority p] [--due-date d] [--assignee id] [--json]` | Update task fields |
62
- | `cu create -n name [-l listId] [-p parentId] [-d desc] [-s status] [--priority p] [--due-date d] [--assignee id] [--tags t] [--json]` | Create task (list auto-detected from parent) |
63
- | `cu comment <id> -m text` | Post comment on task |
64
- | `cu assign <id> [--to userId\|me] [--remove userId\|me] [--json]` | Assign/unassign users |
65
- | `cu config get <key>` / `cu config set <key> <value>` / `cu config path` | Manage CLI config |
66
- | `cu completion <shell>` | Shell completions (bash/zsh/fish) |
59
+ | Command | What it does |
60
+ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | -------------------------------------------- |
61
+ | `cu update <id> [-n name] [-d desc] [-s status] [--priority p] [--due-date d] [--time-estimate t] [--assignee id] [--json]` | Update task fields |
62
+ | `cu create -n name [-l listId] [-p parentId] [-d desc] [-s status] [--priority p] [--due-date d] [--time-estimate t] [--assignee id] [--tags t] [--custom-item-id n] [--json]` | Create task (list auto-detected from parent) |
63
+ | `cu comment <id> -m text` | Post comment on task |
64
+ | `cu assign <id> [--to userId\|me] [--remove userId\|me] [--json]` | Assign/unassign users |
65
+ | `cu depend <id> [--on taskId] [--blocks taskId] [--remove] [--json]` | Add/remove task dependencies |
66
+ | `cu config get <key>` / `cu config set <key> <value>` / `cu config path` | Manage CLI config |
67
+ | `cu completion <shell>` | Shell completions (bash/zsh/fish) |
67
68
 
68
69
  ## Quick Reference
69
70
 
@@ -77,6 +78,9 @@ All commands support `--help` for full flag details.
77
78
  | `--due-date` | `YYYY-MM-DD` format |
78
79
  | `--assignee` | Numeric user ID (find via `cu task <id> --json`) |
79
80
  | `--tags` | Comma-separated (e.g. `--tags "bug,frontend"`) |
81
+ | `--time-estimate` | Duration format: `"2h"`, `"30m"`, `"1h30m"`, or raw milliseconds |
82
+ | `--custom-item-id` | Custom task type ID (e.g. `1` for initiative) |
83
+ | `--on` / `--blocks` | Task dependency direction (used with `cu depend`) |
80
84
  | `--space` | Partial name match or exact ID |
81
85
  | `--name` | Partial match, case-insensitive |
82
86
  | `--include-closed` | Include closed/done tasks (on `subtasks` and `assigned`) |
@@ -121,10 +125,14 @@ cu inbox --days 7 # recently updated
121
125
  ```bash
122
126
  cu update abc123def -s "done"
123
127
  cu update abc123def --priority high --due-date 2025-03-15
128
+ cu update abc123def --time-estimate 2h
124
129
  cu create -n "Fix the thing" -p abc123def
125
130
  cu create -n "Fix bug" -l <listId> --priority urgent --tags "bug,frontend"
131
+ cu create -n "Q3 Roadmap" -l <listId> --custom-item-id 1 # create initiative
126
132
  cu comment abc123def -m "Completed in PR #42"
127
133
  cu assign abc123def --to me
134
+ cu depend task3 --on task2 # task3 waits for task2
135
+ cu depend task1 --blocks task2 # task1 blocks task2
128
136
  ```
129
137
 
130
138
  ### Discover workspace structure