@krodak/clickup-cli 0.12.3 → 0.13.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
- 27 commands total. All support `--help` for full flag details.
101
+ 30 commands total. All support `--help` for full flag details.
102
102
 
103
103
  ### `cu init`
104
104
 
@@ -261,6 +261,48 @@ cu create -n "Fix bug" -l <listId> --json
261
261
  | `--custom-item-id <id>` | no | Custom task type ID (for creating initiatives) |
262
262
  | `--json` | no | Force JSON output even in terminal |
263
263
 
264
+ ### `cu delete <id>`
265
+
266
+ Delete a task. **DESTRUCTIVE - cannot be undone.**
267
+
268
+ ```bash
269
+ cu delete abc123
270
+ cu delete abc123 --confirm
271
+ cu delete abc123 --confirm --json
272
+ ```
273
+
274
+ In TTY mode without `--confirm`: shows the task name and prompts for confirmation (default: No). In non-interactive/piped mode, `--confirm` is required.
275
+
276
+ | Flag | Description |
277
+ | ----------- | ----------------------------------------------------------- |
278
+ | `--confirm` | Skip confirmation prompt (required in non-interactive mode) |
279
+ | `--json` | Force JSON output |
280
+
281
+ ### `cu field <id>`
282
+
283
+ Set or remove a custom field value. Field names are resolved case-insensitively; errors list available fields/options.
284
+
285
+ ```bash
286
+ cu field abc123 --set "Priority Level" high
287
+ cu field abc123 --set "Story Points" 5
288
+ cu field abc123 --set "Approved" true
289
+ cu field abc123 --set "Category" "Bug Fix"
290
+ cu field abc123 --set "Due" 2025-06-01
291
+ cu field abc123 --set "Website" "https://example.com"
292
+ cu field abc123 --set "Contact" "user@example.com"
293
+ cu field abc123 --remove "Priority Level"
294
+ cu field abc123 --set "Points" 3 --remove "Old Field"
295
+ cu field abc123 --set "Points" 3 --json
296
+ ```
297
+
298
+ | Flag | Description |
299
+ | -------------------------- | -------------------------------------------------------------------------------------------------------------------------------- |
300
+ | `--set "Field Name" <val>` | Set a custom field by name. Supports: text, number, checkbox (true/false), dropdown (option name), date (YYYY-MM-DD), url, email |
301
+ | `--remove "Field Name"` | Remove a custom field value |
302
+ | `--json` | Force JSON output |
303
+
304
+ Both `--set` and `--remove` can be used together in one invocation.
305
+
264
306
  ### `cu comment <id>`
265
307
 
266
308
  Post a comment on a task.
@@ -423,6 +465,24 @@ cu move abc123 --to <listId> --json
423
465
  | `--remove <listId>` | Remove task from this list |
424
466
  | `--json` | Force JSON output |
425
467
 
468
+ ### `cu tag <id>`
469
+
470
+ Add or remove tags on a task. Both `--add` and `--remove` can be used together.
471
+
472
+ ```bash
473
+ cu tag abc123 --add "bug"
474
+ cu tag abc123 --add "bug,frontend,urgent"
475
+ cu tag abc123 --remove "wontfix"
476
+ cu tag abc123 --add "bug" --remove "triage"
477
+ cu tag abc123 --add "bug" --json
478
+ ```
479
+
480
+ | Flag | Description |
481
+ | ----------------- | ----------------------------------- |
482
+ | `--add <tags>` | Comma-separated tag names to add |
483
+ | `--remove <tags>` | Comma-separated tag names to remove |
484
+ | `--json` | Force JSON output |
485
+
426
486
  ### `cu auth`
427
487
 
428
488
  Check authentication status. Validates your API token and shows your user info.
package/dist/index.js CHANGED
@@ -218,6 +218,24 @@ var ClickUpClient = class {
218
218
  async removeTaskFromList(taskId, listId) {
219
219
  await this.request(`/list/${listId}/task/${taskId}`, { method: "DELETE" });
220
220
  }
221
+ async setCustomFieldValue(taskId, fieldId, value) {
222
+ await this.request(`/task/${taskId}/field/${fieldId}`, {
223
+ method: "POST",
224
+ body: JSON.stringify({ value })
225
+ });
226
+ }
227
+ async removeCustomFieldValue(taskId, fieldId) {
228
+ await this.request(`/task/${taskId}/field/${fieldId}`, { method: "DELETE" });
229
+ }
230
+ async deleteTask(taskId) {
231
+ await this.request(`/task/${taskId}`, { method: "DELETE" });
232
+ }
233
+ async addTagToTask(taskId, tagName) {
234
+ await this.request(`/task/${taskId}/tag/${encodeURIComponent(tagName)}`, { method: "POST" });
235
+ }
236
+ async removeTagFromTask(taskId, tagName) {
237
+ await this.request(`/task/${taskId}/tag/${encodeURIComponent(tagName)}`, { method: "DELETE" });
238
+ }
221
239
  async addDependency(taskId, opts) {
222
240
  const body = {};
223
241
  if (opts.dependsOn) body.depends_on = opts.dependsOn;
@@ -1615,7 +1633,7 @@ function bashCompletion() {
1615
1633
  cword=$COMP_CWORD
1616
1634
  fi
1617
1635
 
1618
- local commands="init auth tasks initiatives task update create sprint sprints subtasks comment comments activity lists spaces inbox assigned open search summary overdue assign depend move config completion"
1636
+ local commands="init auth tasks initiatives task update create sprint sprints subtasks comment comments activity lists spaces inbox assigned open search summary overdue assign depend move field delete tag config completion"
1619
1637
 
1620
1638
  if [[ $cword -eq 1 ]]; then
1621
1639
  COMPREPLY=($(compgen -W "$commands --help --version" -- "$cur"))
@@ -1702,6 +1720,15 @@ function bashCompletion() {
1702
1720
  move)
1703
1721
  COMPREPLY=($(compgen -W "--to --remove --json" -- "$cur"))
1704
1722
  ;;
1723
+ field)
1724
+ COMPREPLY=($(compgen -W "--set --remove --json" -- "$cur"))
1725
+ ;;
1726
+ delete)
1727
+ COMPREPLY=($(compgen -W "--confirm --json" -- "$cur"))
1728
+ ;;
1729
+ tag)
1730
+ COMPREPLY=($(compgen -W "--add --remove --json" -- "$cur"))
1731
+ ;;
1705
1732
  config)
1706
1733
  if [[ $cword -eq 2 ]]; then
1707
1734
  COMPREPLY=($(compgen -W "get set path" -- "$cur"))
@@ -1752,6 +1779,9 @@ _cu() {
1752
1779
  'assign:Assign or unassign users from a task'
1753
1780
  'depend:Add or remove task dependencies'
1754
1781
  'move:Add or remove a task from a list'
1782
+ 'field:Set or remove a custom field value on a task'
1783
+ 'delete:Delete a task'
1784
+ 'tag:Add or remove tags from a task'
1755
1785
  'config:Manage CLI configuration'
1756
1786
  'completion:Output shell completion script'
1757
1787
  )
@@ -1918,6 +1948,26 @@ _cu() {
1918
1948
  '--remove[Remove task from this list]:list_id:' \\
1919
1949
  '--json[Force JSON output]'
1920
1950
  ;;
1951
+ field)
1952
+ _arguments \\
1953
+ '1:task_id:' \\
1954
+ '--set[Set field name and value]:name_and_value:' \\
1955
+ '--remove[Remove field value by name]:field_name:' \\
1956
+ '--json[Force JSON output]'
1957
+ ;;
1958
+ delete)
1959
+ _arguments \\
1960
+ '1:task_id:' \\
1961
+ '--confirm[Skip confirmation prompt]' \\
1962
+ '--json[Force JSON output]'
1963
+ ;;
1964
+ tag)
1965
+ _arguments \\
1966
+ '1:task_id:' \\
1967
+ '--add[Comma-separated tag names to add]:tags:' \\
1968
+ '--remove[Comma-separated tag names to remove]:tags:' \\
1969
+ '--json[Force JSON output]'
1970
+ ;;
1921
1971
  config)
1922
1972
  local -a config_cmds
1923
1973
  config_cmds=(
@@ -1982,6 +2032,9 @@ complete -c cu -n __fish_use_subcommand -a overdue -d 'List tasks that are past
1982
2032
  complete -c cu -n __fish_use_subcommand -a assign -d 'Assign or unassign users from a task'
1983
2033
  complete -c cu -n __fish_use_subcommand -a depend -d 'Add or remove task dependencies'
1984
2034
  complete -c cu -n __fish_use_subcommand -a move -d 'Add or remove a task from a list'
2035
+ complete -c cu -n __fish_use_subcommand -a field -d 'Set or remove a custom field value on a task'
2036
+ complete -c cu -n __fish_use_subcommand -a delete -d 'Delete a task'
2037
+ complete -c cu -n __fish_use_subcommand -a tag -d 'Add or remove tags from a task'
1985
2038
  complete -c cu -n __fish_use_subcommand -a config -d 'Manage CLI configuration'
1986
2039
  complete -c cu -n __fish_use_subcommand -a completion -d 'Output shell completion script'
1987
2040
 
@@ -2079,6 +2132,17 @@ complete -c cu -n '__fish_seen_subcommand_from move' -l to -d 'Add task to this
2079
2132
  complete -c cu -n '__fish_seen_subcommand_from move' -l remove -d 'Remove task from this list'
2080
2133
  complete -c cu -n '__fish_seen_subcommand_from move' -l json -d 'Force JSON output'
2081
2134
 
2135
+ complete -c cu -n '__fish_seen_subcommand_from field' -l set -d 'Set field name and value'
2136
+ complete -c cu -n '__fish_seen_subcommand_from field' -l remove -d 'Remove field value by name'
2137
+ complete -c cu -n '__fish_seen_subcommand_from field' -l json -d 'Force JSON output'
2138
+
2139
+ complete -c cu -n '__fish_seen_subcommand_from delete' -l confirm -d 'Skip confirmation prompt'
2140
+ complete -c cu -n '__fish_seen_subcommand_from delete' -l json -d 'Force JSON output'
2141
+
2142
+ complete -c cu -n '__fish_seen_subcommand_from tag' -l add -d 'Comma-separated tag names to add'
2143
+ complete -c cu -n '__fish_seen_subcommand_from tag' -l remove -d 'Comma-separated tag names to remove'
2144
+ complete -c cu -n '__fish_seen_subcommand_from tag' -l json -d 'Force JSON output'
2145
+
2082
2146
  complete -c cu -n '__fish_seen_subcommand_from config; and not __fish_seen_subcommand_from get set path' -a get -d 'Print a config value'
2083
2147
  complete -c cu -n '__fish_seen_subcommand_from config; and not __fish_seen_subcommand_from get set path' -a set -d 'Set a config value'
2084
2148
  complete -c cu -n '__fish_seen_subcommand_from config; and not __fish_seen_subcommand_from get set path' -a path -d 'Print config file path'
@@ -2197,6 +2261,140 @@ async function moveTask(config, taskId, opts) {
2197
2261
  return messages.join("; ");
2198
2262
  }
2199
2263
 
2264
+ // src/commands/field.ts
2265
+ var SUPPORTED_TYPES = /* @__PURE__ */ new Set(["text", "number", "drop_down", "checkbox", "date", "url", "email"]);
2266
+ function findFieldByName(fields, name) {
2267
+ const lower = name.toLowerCase();
2268
+ const match = fields.find((f) => f.name.toLowerCase() === lower);
2269
+ if (!match) {
2270
+ const available = fields.map((f) => f.name).join(", ");
2271
+ throw new Error(`Field "${name}" not found. Available fields: ${available}`);
2272
+ }
2273
+ return match;
2274
+ }
2275
+ function parseFieldValue(field, rawValue) {
2276
+ if (!SUPPORTED_TYPES.has(field.type)) {
2277
+ throw new Error(
2278
+ `Field type "${field.type}" is not supported. Supported types: ${[...SUPPORTED_TYPES].join(", ")}`
2279
+ );
2280
+ }
2281
+ switch (field.type) {
2282
+ case "number": {
2283
+ const n = Number(rawValue);
2284
+ if (!Number.isFinite(n)) throw new Error(`Value "${rawValue}" is not a valid numeric value`);
2285
+ return n;
2286
+ }
2287
+ case "checkbox":
2288
+ if (rawValue !== "true" && rawValue !== "false") {
2289
+ throw new Error('Checkbox value must be "true" or "false"');
2290
+ }
2291
+ return rawValue === "true";
2292
+ case "drop_down": {
2293
+ const options = field.type_config?.options;
2294
+ if (!options?.length) throw new Error("Dropdown field has no configured options");
2295
+ const lower = rawValue.toLowerCase();
2296
+ const option = options.find((o) => o.name.toLowerCase() === lower);
2297
+ if (!option) {
2298
+ const available = options.map((o) => o.name).join(", ");
2299
+ throw new Error(`Option "${rawValue}" not found. Available options: ${available}`);
2300
+ }
2301
+ if (option.orderindex === void 0) {
2302
+ throw new Error(`Dropdown option "${option.name}" has no orderindex`);
2303
+ }
2304
+ return option.orderindex;
2305
+ }
2306
+ case "date": {
2307
+ const ms = new Date(rawValue).getTime();
2308
+ if (!Number.isFinite(ms))
2309
+ throw new Error(`Value "${rawValue}" is not a valid date (use YYYY-MM-DD)`);
2310
+ return ms;
2311
+ }
2312
+ default:
2313
+ return rawValue;
2314
+ }
2315
+ }
2316
+ async function setCustomField(config, taskId, opts) {
2317
+ if (!opts.set && !opts.remove) {
2318
+ throw new Error("Provide at least one of: --set, --remove");
2319
+ }
2320
+ const client = new ClickUpClient(config);
2321
+ const task = await client.getTask(taskId);
2322
+ const fields = task.custom_fields ?? [];
2323
+ const results = [];
2324
+ if (opts.set) {
2325
+ const [fieldName, rawValue] = opts.set;
2326
+ const field = findFieldByName(fields, fieldName);
2327
+ const parsed = parseFieldValue(field, rawValue);
2328
+ await client.setCustomFieldValue(taskId, field.id, parsed);
2329
+ results.push({ taskId, field: field.name, action: "set", value: parsed });
2330
+ }
2331
+ if (opts.remove) {
2332
+ const field = findFieldByName(fields, opts.remove);
2333
+ await client.removeCustomFieldValue(taskId, field.id);
2334
+ results.push({ taskId, field: field.name, action: "removed" });
2335
+ }
2336
+ return { results };
2337
+ }
2338
+
2339
+ // src/commands/delete.ts
2340
+ async function deleteTaskCommand(config, taskId, opts) {
2341
+ const client = new ClickUpClient(config);
2342
+ if (!opts.confirm) {
2343
+ if (!isTTY()) {
2344
+ throw new Error("Destructive operation requires --confirm flag in non-interactive mode");
2345
+ }
2346
+ const task = await client.getTask(taskId);
2347
+ const { confirm: confirm3 } = await import("@inquirer/prompts");
2348
+ const confirmed = await confirm3({
2349
+ message: `Delete task "${task.name}" (${task.id})? This cannot be undone.`,
2350
+ default: false
2351
+ });
2352
+ if (!confirmed) {
2353
+ throw new Error("Cancelled");
2354
+ }
2355
+ }
2356
+ await client.deleteTask(taskId);
2357
+ return { taskId, deleted: true };
2358
+ }
2359
+
2360
+ // src/commands/tag.ts
2361
+ function parseTags(input) {
2362
+ return input.split(",").map((t) => t.trim()).filter((t) => t.length > 0);
2363
+ }
2364
+ async function manageTags(config, taskId, opts) {
2365
+ if (!opts.add && !opts.remove) {
2366
+ throw new Error("Provide at least one of: --add, --remove");
2367
+ }
2368
+ const client = new ClickUpClient(config);
2369
+ const added = [];
2370
+ const removed = [];
2371
+ if (opts.add) {
2372
+ const tags = parseTags(opts.add);
2373
+ for (const tag of tags) {
2374
+ await client.addTagToTask(taskId, tag);
2375
+ added.push(tag);
2376
+ }
2377
+ }
2378
+ if (opts.remove) {
2379
+ const tags = parseTags(opts.remove);
2380
+ try {
2381
+ for (const tag of tags) {
2382
+ await client.removeTagFromTask(taskId, tag);
2383
+ removed.push(tag);
2384
+ }
2385
+ } catch (err) {
2386
+ if (added.length > 0) {
2387
+ const reason = err instanceof Error ? err.message : String(err);
2388
+ throw new Error(`Added tags: ${added.join(", ")}; but failed to remove: ${reason}`, {
2389
+ cause: err
2390
+ });
2391
+ }
2392
+ throw err;
2393
+ }
2394
+ }
2395
+ return { taskId, added, removed };
2396
+ }
2397
+
2200
2398
  // src/index.ts
2201
2399
  var require2 = createRequire(import.meta.url);
2202
2400
  var { version } = require2("../package.json");
@@ -2452,6 +2650,60 @@ program.command("move <taskId>").description("Add or remove a task from a list")
2452
2650
  }
2453
2651
  })
2454
2652
  );
2653
+ program.command("field <taskId>").description("Set or remove a custom field value on a task").option("--set <nameAndValue...>", 'Set field: --set "Field Name" value').option("--remove <fieldName>", "Remove field value by name").option("--json", "Force JSON output even in terminal").action(
2654
+ wrapAction(
2655
+ async (taskId, opts) => {
2656
+ const config = loadConfig();
2657
+ const fieldOpts = {};
2658
+ if (opts.set) {
2659
+ if (opts.set.length !== 2) {
2660
+ throw new Error("--set requires exactly two arguments: field name and value");
2661
+ }
2662
+ fieldOpts.set = [opts.set[0], opts.set[1]];
2663
+ }
2664
+ if (opts.remove) {
2665
+ fieldOpts.remove = opts.remove;
2666
+ }
2667
+ const { results } = await setCustomField(config, taskId, fieldOpts);
2668
+ if (shouldOutputJson(opts.json ?? false)) {
2669
+ console.log(JSON.stringify(results, null, 2));
2670
+ } else {
2671
+ for (const r of results) {
2672
+ if (r.action === "set") {
2673
+ console.log(`Set "${r.field}" to ${JSON.stringify(r.value)} on ${r.taskId}`);
2674
+ } else {
2675
+ console.log(`Removed "${r.field}" from ${r.taskId}`);
2676
+ }
2677
+ }
2678
+ }
2679
+ }
2680
+ )
2681
+ );
2682
+ program.command("delete <taskId>").description("Delete a task (requires confirmation)").option("--confirm", "Skip confirmation prompt (required in non-interactive mode)").option("--json", "Force JSON output even in terminal").action(
2683
+ wrapAction(async (taskId, opts) => {
2684
+ const config = loadConfig();
2685
+ const result = await deleteTaskCommand(config, taskId, opts);
2686
+ if (shouldOutputJson(opts.json ?? false)) {
2687
+ console.log(JSON.stringify(result, null, 2));
2688
+ } else {
2689
+ console.log(`Deleted task ${result.taskId}`);
2690
+ }
2691
+ })
2692
+ );
2693
+ program.command("tag <taskId>").description("Add or remove tags from a task").option("--add <tags>", "Comma-separated tag names to add").option("--remove <tags>", "Comma-separated tag names to remove").option("--json", "Force JSON output even in terminal").action(
2694
+ wrapAction(async (taskId, opts) => {
2695
+ const config = loadConfig();
2696
+ const result = await manageTags(config, taskId, opts);
2697
+ if (shouldOutputJson(opts.json ?? false)) {
2698
+ console.log(JSON.stringify(result, null, 2));
2699
+ } else {
2700
+ const parts = [];
2701
+ if (result.added.length > 0) parts.push(`Added tags: ${result.added.join(", ")}`);
2702
+ if (result.removed.length > 0) parts.push(`Removed tags: ${result.removed.join(", ")}`);
2703
+ console.log(parts.join("; "));
2704
+ }
2705
+ })
2706
+ );
2455
2707
  var configCmd = program.command("config").description("Manage CLI configuration");
2456
2708
  configCmd.command("get <key>").description("Print a config value").action(
2457
2709
  wrapAction(async (key) => {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@krodak/clickup-cli",
3
- "version": "0.12.3",
3
+ "version": "0.13.0",
4
4
  "description": "ClickUp CLI for AI agents and humans",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: clickup
3
- description: 'Use when managing ClickUp tasks, initiatives, sprints, or comments via the `cu` CLI tool. Triggers: task queries, status updates, sprint tracking, creating subtasks, posting comments, standup summaries, searching tasks, checking overdue items, assigning tasks, listing spaces and lists, opening tasks in browser, checking auth or config.'
3
+ description: 'Use when managing ClickUp tasks, initiatives, sprints, or comments via the `cu` CLI tool. Triggers: task queries, status updates, sprint tracking, creating subtasks, posting comments, 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.'
4
4
  ---
5
5
 
6
6
  # ClickUp CLI (`cu`)
@@ -64,38 +64,45 @@ All commands support `--help` for full flag details.
64
64
  | `cu assign <id> [--to userId\|me] [--remove userId\|me] [--json]` | Assign/unassign users |
65
65
  | `cu depend <id> [--on taskId] [--blocks taskId] [--remove] [--json]` | Add/remove task dependencies |
66
66
  | `cu move <id> [--to listId] [--remove listId] [--json]` | Add/remove task from lists |
67
+ | `cu field <id> [--set "Name" value] [--remove "Name"] [--json]` | Set/remove custom field values |
68
+ | `cu delete <id> [--confirm] [--json]` | Delete a task (DESTRUCTIVE, irreversible) |
69
+ | `cu tag <id> [--add tags] [--remove tags] [--json]` | Add/remove tags on a task |
67
70
  | `cu config get <key>` / `cu config set <key> <value>` / `cu config path` | Manage CLI config |
68
71
  | `cu completion <shell>` | Shell completions (bash/zsh/fish) |
69
72
 
70
73
  ## Quick Reference
71
74
 
72
- | Topic | Detail |
73
- | ------------------- | --------------------------------------------------------------------------------------------------------------------- |
74
- | Task IDs | Stable alphanumeric strings (e.g. `abc123def`) |
75
- | Initiatives | Detected via `custom_item_id !== 0` |
76
- | `--list` on create | Optional when `--parent` is given (auto-detected) |
77
- | `--status` | Fuzzy matching: exact > starts-with > contains. Prints match to stderr. |
78
- | `--priority` | Names (`urgent`, `high`, `normal`, `low`) or numbers (1-4) |
79
- | `--due-date` | `YYYY-MM-DD` format |
80
- | `--assignee` | Numeric user ID (find via `cu task <id> --json`) |
81
- | `--tags` | Comma-separated (e.g. `--tags "bug,frontend"`) |
82
- | `--time-estimate` | Duration format: `"2h"`, `"30m"`, `"1h30m"`, or raw milliseconds |
83
- | `--custom-item-id` | Custom task type ID (e.g. `1` for initiative) |
84
- | `--on` / `--blocks` | Task dependency direction (used with `cu depend`) |
85
- | `--to` / `--remove` | List ID to add/remove task (used with `cu move`) |
86
- | `--space` | Partial name match or exact ID |
87
- | `--name` | Partial match, case-insensitive |
88
- | `--include-closed` | Include closed/done tasks (on `tasks`, `initiatives`, `assigned`, `subtasks`, `sprint`, `search`, `inbox`, `overdue`) |
89
- | `cu assign --to me` | Shorthand for your own user ID |
90
- | `cu search` | Matches all query words against task name, case-insensitive |
91
- | `cu sprint` | Auto-detects active sprint via view API and date range parsing |
92
- | `cu summary` | Categories: completed (done/complete/closed within N hours), in progress, overdue |
93
- | `cu overdue` | Excludes closed tasks, sorted most overdue first |
94
- | `cu open` | Tries task ID first, falls back to name search |
95
- | `cu task` | Shows custom fields in detail view |
96
- | `cu lists` | Discovers list IDs needed for `--list` and `cu create -l` |
97
- | Errors | stderr with exit code 1 |
98
- | Parsing | Strict - excess/unknown arguments rejected |
75
+ | Topic | Detail |
76
+ | ----------------------- | --------------------------------------------------------------------------------------------------------------------- |
77
+ | Task IDs | Stable alphanumeric strings (e.g. `abc123def`) |
78
+ | Initiatives | Detected via `custom_item_id !== 0` |
79
+ | `--list` on create | Optional when `--parent` is given (auto-detected) |
80
+ | `--status` | Fuzzy matching: exact > starts-with > contains. Prints match to stderr. |
81
+ | `--priority` | Names (`urgent`, `high`, `normal`, `low`) or numbers (1-4) |
82
+ | `--due-date` | `YYYY-MM-DD` format |
83
+ | `--assignee` | Numeric user ID (find via `cu task <id> --json`) |
84
+ | `--tags` | Comma-separated (e.g. `--tags "bug,frontend"`) |
85
+ | `--time-estimate` | Duration format: `"2h"`, `"30m"`, `"1h30m"`, or raw milliseconds |
86
+ | `--custom-item-id` | Custom task type ID (e.g. `1` for initiative) |
87
+ | `--on` / `--blocks` | Task dependency direction (used with `cu depend`) |
88
+ | `--to` / `--remove` | List ID to add/remove task (used with `cu move`) |
89
+ | `cu field --set` | Supports: text, number, checkbox (true/false), dropdown (option name), date (YYYY-MM-DD), url, email |
90
+ | `cu field` | Field names resolved case-insensitively; errors list available fields/options |
91
+ | `cu delete` | DESTRUCTIVE. Requires `--confirm` in non-interactive mode. Cannot be undone |
92
+ | `cu tag --add/--remove` | Comma-separated tag names (e.g. `--add "bug,frontend"`) |
93
+ | `--space` | Partial name match or exact ID |
94
+ | `--name` | Partial match, case-insensitive |
95
+ | `--include-closed` | Include closed/done tasks (on `tasks`, `initiatives`, `assigned`, `subtasks`, `sprint`, `search`, `inbox`, `overdue`) |
96
+ | `cu assign --to me` | Shorthand for your own user ID |
97
+ | `cu search` | Matches all query words against task name, case-insensitive |
98
+ | `cu sprint` | Auto-detects active sprint via view API and date range parsing |
99
+ | `cu summary` | Categories: completed (done/complete/closed within N hours), in progress, overdue |
100
+ | `cu overdue` | Excludes closed tasks, sorted most overdue first |
101
+ | `cu open` | Tries task ID first, falls back to name search |
102
+ | `cu task` | Shows custom fields in detail view |
103
+ | `cu lists` | Discovers list IDs needed for `--list` and `cu create -l` |
104
+ | Errors | stderr with exit code 1 |
105
+ | Parsing | Strict - excess/unknown arguments rejected |
99
106
 
100
107
  ## Agent Workflow Examples
101
108
 
@@ -137,6 +144,12 @@ cu assign abc123def --to me
137
144
  cu depend task3 --on task2 # task3 waits for task2
138
145
  cu depend task1 --blocks task2 # task1 blocks task2
139
146
  cu move task1 --to list2 --remove list1 # move between lists
147
+ cu field abc123def --set "Story Points" 5
148
+ cu field abc123def --set "Category" "Bug Fix"
149
+ cu field abc123def --remove "Old Field"
150
+ cu tag abc123def --add "bug,frontend"
151
+ cu tag abc123def --remove "triage"
152
+ cu delete abc123def --confirm # irreversible!
140
153
  ```
141
154
 
142
155
  ### Discover workspace structure
@@ -155,3 +168,7 @@ cu auth # verify token works
155
168
  cu summary # completed / in progress / overdue
156
169
  cu summary --hours 48 # wider window
157
170
  ```
171
+
172
+ ## DELETE SAFETY
173
+
174
+ IMPORTANT: Always confirm with the user before running `cu delete`. This is a destructive, irreversible operation. Even when using `--confirm` flag, verify the task ID is correct with the user first.