@krodak/clickup-cli 1.14.0 → 1.14.2

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.14.0",
4
+ "version": "1.14.2",
5
5
  "author": {
6
6
  "name": "Krzysztof Rodak"
7
7
  },
package/dist/index.js CHANGED
@@ -1225,7 +1225,7 @@ function formatTasksMarkdown(tasks) {
1225
1225
  }
1226
1226
  function formatCommentsMarkdown(comments) {
1227
1227
  if (comments.length === 0) return "No comments found.";
1228
- return comments.map((c) => `**${c.user}** (${c.date})
1228
+ return comments.map((c) => `**${c.user}** (${formatDateISO(c.date)})
1229
1229
 
1230
1230
  ${c.text}`).join("\n\n---\n\n");
1231
1231
  }
@@ -1279,6 +1279,10 @@ function formatTaskDetailMarkdown(task) {
1279
1279
  task.time_spent != null && task.time_spent > 0 ? formatDuration(task.time_spent) : void 0
1280
1280
  ],
1281
1281
  ["Tags", task.tags && task.tags.length > 0 ? task.tags.map((t) => t.name).join(", ") : void 0],
1282
+ [
1283
+ "Lists",
1284
+ task.locations && task.locations.length > 0 ? task.locations.map((l) => l.name).join(", ") : void 0
1285
+ ],
1282
1286
  ["Created", task.date_created ? formatDateISO(task.date_created) : void 0],
1283
1287
  ["Updated", task.date_updated ? formatDateISO(task.date_updated) : void 0]
1284
1288
  ];
@@ -1420,6 +1424,7 @@ function formatTaskDetail(task) {
1420
1424
  ["Estimate", task.time_estimate ? formatDuration(task.time_estimate) : void 0],
1421
1425
  ["Tracked", task.time_spent ? formatDuration(task.time_spent) : void 0],
1422
1426
  ["Tags", task.tags?.length ? task.tags.map((t) => t.name).join(", ") : void 0],
1427
+ ["Lists", task.locations?.length ? task.locations.map((l) => l.name).join(", ") : void 0],
1423
1428
  ["Parent", task.parent || void 0],
1424
1429
  ["URL", task.url]
1425
1430
  ];
@@ -1708,6 +1713,9 @@ function parseTimeEstimate(value) {
1708
1713
  );
1709
1714
  }
1710
1715
  function buildUpdatePayload(opts) {
1716
+ if (opts.archive && opts.unarchive) {
1717
+ throw new Error("Cannot use --archive and --unarchive together");
1718
+ }
1711
1719
  const payload = {};
1712
1720
  if (opts.name !== void 0) {
1713
1721
  if (!opts.name.trim()) throw new Error("Task name cannot be empty");
@@ -1727,10 +1735,12 @@ function buildUpdatePayload(opts) {
1727
1735
  payload.time_estimate = parseTimeEstimate(opts.timeEstimate);
1728
1736
  }
1729
1737
  if (opts.parent !== void 0) payload.parent = opts.parent;
1738
+ if (opts.archive) payload.archived = true;
1739
+ if (opts.unarchive) payload.archived = false;
1730
1740
  return payload;
1731
1741
  }
1732
1742
  function hasUpdateFields(options) {
1733
- return options.name !== void 0 || options.description !== void 0 || options.markdown_content !== void 0 || options.status !== void 0 || options.priority !== void 0 || options.due_date !== void 0 || options.time_estimate !== void 0 || options.assignees !== void 0 || options.parent !== void 0;
1743
+ return options.name !== void 0 || options.description !== void 0 || options.markdown_content !== void 0 || options.status !== void 0 || options.priority !== void 0 || options.due_date !== void 0 || options.time_estimate !== void 0 || options.assignees !== void 0 || options.parent !== void 0 || options.archived !== void 0;
1734
1744
  }
1735
1745
  async function resolveStatus(client, taskId, statusInput) {
1736
1746
  const task = await client.getTask(taskId);
@@ -1749,7 +1759,7 @@ async function resolveStatus(client, taskId, statusInput) {
1749
1759
  async function updateTask(config, taskId, options) {
1750
1760
  if (!hasUpdateFields(options))
1751
1761
  throw new Error(
1752
- "Provide at least one of: --name, --description, --status, --priority, --due-date, --time-estimate, --assignee, --parent"
1762
+ "Provide at least one of: --name, --description, --status, --priority, --due-date, --time-estimate, --assignee, --parent, --archive, --unarchive"
1753
1763
  );
1754
1764
  const client = new ClickUpClient(config);
1755
1765
  if (options.status !== void 0) {
@@ -2758,6 +2768,8 @@ var commandMetadata = [
2758
2768
  "--time-estimate",
2759
2769
  "--assignee",
2760
2770
  "--parent",
2771
+ "--archive",
2772
+ "--unarchive",
2761
2773
  "--field",
2762
2774
  "--json"
2763
2775
  ],
@@ -3671,6 +3683,9 @@ ${renderZshTopLevelCommands(name)}
3671
3683
  '--time-estimate[Time estimate]:duration:' \\
3672
3684
  '--assignee[Add assignee]:user_id:' \\
3673
3685
  '--parent[Set parent task]:task_id:' \\
3686
+ '--archive[Archive the task]' \\
3687
+ '--unarchive[Unarchive the task]' \\
3688
+ '--field[Set custom field]:field_name_and_value:' \\
3674
3689
  '--json[Force JSON output]'
3675
3690
  ;;
3676
3691
  create)
@@ -3761,6 +3776,7 @@ ${renderZshTopLevelCommands(name)}
3761
3776
  '1:query:' \\
3762
3777
  '--status[Filter by status]:status:(open "in progress" "in review" done closed)' \\
3763
3778
  '--include-closed[Include done/closed tasks in search]' \\
3779
+ '--all[Search all workspace tasks, not just mine]' \\
3764
3780
  '--json[Force JSON output]'
3765
3781
  ;;
3766
3782
  summary)
@@ -3771,6 +3787,7 @@ ${renderZshTopLevelCommands(name)}
3771
3787
  overdue)
3772
3788
  _arguments \\
3773
3789
  '--include-closed[Include done/closed overdue tasks]' \\
3790
+ '--all[Check all workspace tasks, not just mine]' \\
3774
3791
  '--json[Force JSON output]'
3775
3792
  ;;
3776
3793
  assign)
@@ -4448,7 +4465,18 @@ async function moveTask(config, taskId, opts) {
4448
4465
  }
4449
4466
 
4450
4467
  // src/commands/field.ts
4451
- var SUPPORTED_TYPES = /* @__PURE__ */ new Set(["text", "number", "drop_down", "checkbox", "date", "url", "email"]);
4468
+ var SUPPORTED_TYPES = /* @__PURE__ */ new Set([
4469
+ "text",
4470
+ "short_text",
4471
+ "number",
4472
+ "currency",
4473
+ "phone",
4474
+ "drop_down",
4475
+ "checkbox",
4476
+ "date",
4477
+ "url",
4478
+ "email"
4479
+ ]);
4452
4480
  function findFieldByName(fields, name) {
4453
4481
  const lower = name.toLowerCase();
4454
4482
  const match = fields.find((f) => f.name.toLowerCase() === lower);
@@ -4662,9 +4690,12 @@ function formatChecklistsMarkdown(checklists) {
4662
4690
 
4663
4691
  // src/commands/comment-edit.ts
4664
4692
  async function editComment(config, commentId, text, resolved) {
4665
- if (!text.trim()) throw new Error("Comment text cannot be empty");
4693
+ if (text === void 0 && resolved === void 0) {
4694
+ throw new Error("Provide at least one of: --message, --resolved, --unresolved");
4695
+ }
4696
+ if (text !== void 0 && !text.trim()) throw new Error("Comment text cannot be empty");
4666
4697
  const client = new ClickUpClient(config);
4667
- await client.updateComment(commentId, text, resolved);
4698
+ await client.updateComment(commentId, text ?? "", resolved);
4668
4699
  }
4669
4700
 
4670
4701
  // src/commands/comment-delete.ts
@@ -4981,6 +5012,11 @@ function formatTimeEntriesMarkdown(entries) {
4981
5012
 
4982
5013
  // src/commands/tags.ts
4983
5014
  import chalk12 from "chalk";
5015
+ var TAG_COLUMNS = [
5016
+ { key: "name", label: "Name", maxWidth: 40 },
5017
+ { key: "fg", label: "FG", maxWidth: 10 },
5018
+ { key: "bg", label: "BG", maxWidth: 10 }
5019
+ ];
4984
5020
  async function listSpaceTags(config, spaceId) {
4985
5021
  const client = new ClickUpClient(config);
4986
5022
  return client.getSpaceTags(spaceId);
@@ -5003,11 +5039,22 @@ async function updateSpaceTag(config, spaceId, tagName, updates) {
5003
5039
  }
5004
5040
  function formatTags(tags) {
5005
5041
  if (tags.length === 0) return "No tags found";
5042
+ if (isTTY()) {
5043
+ const rows = tags.map((t) => ({
5044
+ name: t.tag_bg ? chalk12.bgHex(t.tag_bg).hex(t.tag_fg || "#ffffff")(` ${t.name} `) : chalk12.bold(t.name),
5045
+ fg: t.tag_fg || "",
5046
+ bg: t.tag_bg || ""
5047
+ }));
5048
+ return formatTable(rows, TAG_COLUMNS);
5049
+ }
5006
5050
  return tags.map((t) => chalk12.bold(t.name)).join(", ");
5007
5051
  }
5008
5052
  function formatTagsMarkdown(tags) {
5009
5053
  if (tags.length === 0) return "No tags found";
5010
- return tags.map((t) => `- ${t.name}`).join("\n");
5054
+ return tags.map((t) => {
5055
+ const colors = t.tag_bg ? ` (bg: ${t.tag_bg}${t.tag_fg ? `, fg: ${t.tag_fg}` : ""})` : "";
5056
+ return `- ${t.name}${colors}`;
5057
+ }).join("\n");
5011
5058
  }
5012
5059
 
5013
5060
  // src/commands/members.ts
@@ -5037,6 +5084,7 @@ function formatMembersMarkdown(members) {
5037
5084
  // src/commands/fields.ts
5038
5085
  import chalk13 from "chalk";
5039
5086
  var FIELD_COLUMNS = [
5087
+ { key: "id", label: "ID", maxWidth: 20 },
5040
5088
  { key: "name", label: "Name", maxWidth: 30 },
5041
5089
  { key: "type", label: "Type", maxWidth: 15 },
5042
5090
  {
@@ -5054,6 +5102,7 @@ async function listFields(config, listId) {
5054
5102
  function formatFields(fields) {
5055
5103
  if (fields.length === 0) return "No custom fields";
5056
5104
  const rows = fields.map((f) => ({
5105
+ id: f.id,
5057
5106
  name: f.name,
5058
5107
  type: f.type,
5059
5108
  required: f.required ? "yes" : "no",
@@ -5066,7 +5115,7 @@ function formatFieldsMarkdown(fields) {
5066
5115
  return fields.map((f) => {
5067
5116
  const options = f.type_config?.options?.map((o) => o.name).join(", ");
5068
5117
  const optStr = options ? ` [${options}]` : "";
5069
- return `- **${f.name}** (${f.type})${f.required ? " - required" : ""}${optStr}`;
5118
+ return `- **${f.name}** \`${f.id}\` (${f.type})${f.required ? " - required" : ""}${optStr}`;
5070
5119
  }).join("\n");
5071
5120
  }
5072
5121
 
@@ -5114,7 +5163,8 @@ var GOAL_COLUMNS = [
5114
5163
  { key: "id", label: "ID", maxWidth: 15 },
5115
5164
  { key: "name", label: "Name", maxWidth: 40 },
5116
5165
  { key: "progress", label: "Progress", maxWidth: 10, format: (v) => colorProgress(v) },
5117
- { key: "owner", label: "Owner", maxWidth: 20 }
5166
+ { key: "owner", label: "Owner", maxWidth: 20 },
5167
+ { key: "due_date", label: "Due", maxWidth: 12 }
5118
5168
  ];
5119
5169
  var KEY_RESULT_COLUMNS = [
5120
5170
  { key: "id", label: "ID", maxWidth: 15 },
@@ -5163,7 +5213,8 @@ function formatGoals(goals) {
5163
5213
  name: g.name,
5164
5214
  id: g.id,
5165
5215
  progress: `${Math.round(g.percent_completed * 100)}%`,
5166
- owner: g.owner ? `@${g.owner.username}` : ""
5216
+ owner: g.owner ? `@${g.owner.username}` : "",
5217
+ due_date: g.due_date ? formatDateISO(g.due_date) : ""
5167
5218
  }));
5168
5219
  return formatTable(rows, GOAL_COLUMNS);
5169
5220
  }
@@ -5172,7 +5223,8 @@ function formatGoalsMarkdown(goals) {
5172
5223
  return goals.map((g) => {
5173
5224
  const pct = Math.round(g.percent_completed * 100);
5174
5225
  const owner = g.owner ? ` - @${g.owner.username}` : "";
5175
- return `- **${g.name}** (${g.id}) - ${pct}%${owner}`;
5226
+ const due = g.due_date ? ` - due ${formatDateISO(g.due_date)}` : "";
5227
+ return `- **${g.name}** (${g.id}) - ${pct}%${owner}${due}`;
5176
5228
  }).join("\n");
5177
5229
  }
5178
5230
  function formatKeyResults(keyResults) {
@@ -5354,6 +5406,9 @@ var VALID_GROUP_BY_FIELDS2 = [
5354
5406
  "sprint"
5355
5407
  ];
5356
5408
  async function updateView(config, viewId, opts) {
5409
+ if (opts.name === void 0 && opts.groupBy === void 0) {
5410
+ throw new Error("Provide at least one of: --name, --group-by");
5411
+ }
5357
5412
  if (opts.name !== void 0 && !opts.name.trim()) {
5358
5413
  throw new Error("View name cannot be empty");
5359
5414
  }
@@ -5465,7 +5520,7 @@ function buildProgram(programName = basename(process.argv[1] ?? "cup")) {
5465
5520
  }
5466
5521
  })
5467
5522
  );
5468
- 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 or "me"').option("--parent <taskId>", "Set parent task (makes this a subtask)").option("--field <nameAndValue...>", 'Set custom field: --field "Name" value').option("--json", "Force JSON output even in terminal").action(
5523
+ 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 or "me"').option("--parent <taskId>", "Set parent task (makes this a subtask)").option("--archive", "Archive the task").option("--unarchive", "Unarchive the task").option("--field <nameAndValue...>", 'Set custom field: --field "Name" value').option("--json", "Force JSON output even in terminal").action(
5469
5524
  wrapAction(
5470
5525
  async (taskId, opts) => {
5471
5526
  const config = loadConfig(getProfileName());
@@ -5474,14 +5529,28 @@ function buildProgram(programName = basename(process.argv[1] ?? "cup")) {
5474
5529
  opts.assignee = String(await resolveAssigneeId(client, "me"));
5475
5530
  }
5476
5531
  const payload = buildUpdatePayload(opts);
5477
- const result = await updateTask(config, taskId, payload);
5478
- if (opts.field?.length) {
5479
- if (opts.field.length % 2 !== 0) {
5532
+ const hasFields = (opts.field?.length ?? 0) > 0;
5533
+ if (!hasFields && Object.keys(payload).length === 0) {
5534
+ throw new Error(
5535
+ "Provide at least one of: --name, --description, --status, --priority, --due-date, --time-estimate, --assignee, --parent, --archive, --unarchive, --field"
5536
+ );
5537
+ }
5538
+ let result;
5539
+ if (Object.keys(payload).length > 0) {
5540
+ result = await updateTask(config, taskId, payload);
5541
+ }
5542
+ if (hasFields) {
5543
+ if ((opts.field?.length ?? 0) % 2 !== 0) {
5480
5544
  throw new Error('--field requires pairs: --field "Name" value');
5481
5545
  }
5482
- for (let i = 0; i < opts.field.length; i += 2) {
5546
+ for (let i = 0; i < (opts.field?.length ?? 0); i += 2) {
5483
5547
  await setCustomField(config, taskId, { set: [opts.field[i], opts.field[i + 1]] });
5484
5548
  }
5549
+ if (!result) {
5550
+ const client = new ClickUpClient(config);
5551
+ const task = await client.getTask(taskId);
5552
+ result = { id: task.id, name: task.name };
5553
+ }
5485
5554
  }
5486
5555
  if (shouldOutputJson(opts.json ?? false)) {
5487
5556
  console.log(JSON.stringify(result, null, 2));
@@ -5557,7 +5626,7 @@ function buildProgram(programName = basename(process.argv[1] ?? "cup")) {
5557
5626
  printComments(comments, opts.json ?? false);
5558
5627
  })
5559
5628
  );
5560
- program.command("comment-edit <commentId>").description("Edit an existing comment").requiredOption("-m, --message <text>", "New comment text").option("--resolved", "Mark comment as resolved").option("--unresolved", "Mark comment as unresolved").option("--json", "Force JSON output even in terminal").action(
5629
+ program.command("comment-edit <commentId>").description("Edit an existing comment").option("-m, --message <text>", "New comment text").option("--resolved", "Mark comment as resolved").option("--unresolved", "Mark comment as unresolved").option("--json", "Force JSON output even in terminal").action(
5561
5630
  wrapAction(
5562
5631
  async (commentId, opts) => {
5563
5632
  const config = loadConfig(getProfileName());
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@krodak/clickup-cli",
3
- "version": "1.14.0",
3
+ "version": "1.14.2",
4
4
  "description": "ClickUp CLI for AI agents and humans",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -72,7 +72,7 @@ All commands support `--help` for full flag details. All commands support `--jso
72
72
  | Command | What it does |
73
73
  | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | -------------------------------------------- |
74
74
  | `cup create -n name [-l listId] [-p parentId] [-d desc] [-s status] [--priority p] [--due-date d] [--time-estimate t] [--assignee id\|me] [--tags t] [--custom-item-id n] [--template id]` | Create task |
75
- | `cup update <id> [-n name] [-d desc] [-s status] [--priority p] [--due-date d] [--time-estimate t] [--assignee id\|me] [--parent id] [--field "Name" val]` | Update task fields (including custom fields) |
75
+ | `cup update <id> [-n name] [-d desc] [-s status] [--priority p] [--due-date d] [--time-estimate t] [--assignee id\|me] [--parent id] [--archive] [--unarchive] [--field "Name" val]` | Update task fields (including custom fields) |
76
76
  | `cup comment <id> -m text [--notify-all]` | Post comment on task |
77
77
  | `cup comment-edit <commentId> -m text [--resolved] [--unresolved]` | Edit a comment |
78
78
  | `cup comment-delete <commentId>` | Delete a comment |