@krodak/clickup-cli 1.12.0 → 1.14.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.
@@ -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.12.0",
4
+ "version": "1.14.0",
5
5
  "author": {
6
6
  "name": "Krzysztof Rodak"
7
7
  },
package/dist/index.js CHANGED
@@ -1143,19 +1143,57 @@ function computeWidths(rows, columns) {
1143
1143
  function formatTable(rows, columns) {
1144
1144
  const widths = computeWidths(rows, columns);
1145
1145
  const header = columns.map((c, i) => cell(c.label, widths[i])).join(" ");
1146
- const divider = "-".repeat(header.replace(/\x1b\[[0-9;]*m/g, "").length);
1146
+ const divider = chalk.dim("-".repeat(header.replace(/\x1b\[[0-9;]*m/g, "").length));
1147
1147
  const lines = [chalk.bold(header), divider];
1148
1148
  for (const row of rows) {
1149
- lines.push(columns.map((c, i) => cell(String(row[c.key] ?? ""), widths[i])).join(" "));
1149
+ lines.push(
1150
+ columns.map((c, i) => {
1151
+ const raw = String(row[c.key] ?? "");
1152
+ const width = widths[i];
1153
+ const truncated = raw.length > width ? raw.slice(0, width - 1) + "\u2026" : raw;
1154
+ const padding = " ".repeat(Math.max(0, width - truncated.length));
1155
+ return c.format ? c.format(truncated, row) + padding : truncated + padding;
1156
+ }).join(" ")
1157
+ );
1150
1158
  }
1151
1159
  return lines.join("\n");
1152
1160
  }
1161
+ function colorStatus(status) {
1162
+ const lower = status.toLowerCase();
1163
+ if (lower.includes("done") || lower.includes("complete") || lower.includes("closed"))
1164
+ return chalk.green(status);
1165
+ if (lower.includes("progress") || lower.includes("review") || lower.includes("active"))
1166
+ return chalk.yellow(status);
1167
+ if (lower.includes("block") || lower.includes("stuck")) return chalk.red(status);
1168
+ return chalk.dim(status);
1169
+ }
1170
+ function colorPriority(priority) {
1171
+ const lower = priority.toLowerCase();
1172
+ if (lower === "urgent") return chalk.red(priority);
1173
+ if (lower === "high") return chalk.yellow(priority);
1174
+ if (lower === "normal") return priority;
1175
+ if (lower === "low") return chalk.dim(priority);
1176
+ return priority;
1177
+ }
1178
+ function colorDueDate(dateStr, rawTimestamp) {
1179
+ if (!dateStr) return dateStr;
1180
+ if (rawTimestamp) {
1181
+ const ts = Number(rawTimestamp);
1182
+ if (Number.isFinite(ts) && ts < Date.now()) return chalk.red(dateStr);
1183
+ }
1184
+ return dateStr;
1185
+ }
1153
1186
  var TASK_COLUMNS = [
1154
1187
  { key: "id", label: "ID" },
1155
1188
  { key: "name", label: "NAME", maxWidth: 60 },
1156
- { key: "status", label: "STATUS" },
1157
- { key: "priority", label: "PRIORITY" },
1158
- { key: "due_date", label: "DUE" },
1189
+ { key: "status", label: "STATUS", maxWidth: 20, format: (v) => colorStatus(v) },
1190
+ { key: "priority", label: "PRIORITY", maxWidth: 10, format: (v) => colorPriority(v) },
1191
+ {
1192
+ key: "due_date",
1193
+ label: "DUE",
1194
+ maxWidth: 15,
1195
+ format: (v, row) => v ? colorDueDate(v, row.dueRaw) : ""
1196
+ },
1159
1197
  { key: "list", label: "LIST" }
1160
1198
  ];
1161
1199
 
@@ -1369,16 +1407,16 @@ function formatTaskDetail(task) {
1369
1407
  lines.push("");
1370
1408
  const fields = [
1371
1409
  ["ID", task.id],
1372
- ["Status", task.status?.status],
1410
+ ["Status", task.status?.status ? colorStatus(task.status.status) : void 0],
1373
1411
  ["Type", typeLabel],
1374
1412
  ["List", task.list?.name],
1375
1413
  [
1376
1414
  "Assignees",
1377
1415
  task.assignees?.length ? task.assignees.map((a) => a.username).join(", ") : void 0
1378
1416
  ],
1379
- ["Priority", task.priority?.priority],
1417
+ ["Priority", task.priority?.priority ? colorPriority(task.priority.priority) : void 0],
1380
1418
  ["Start", task.start_date ? formatDate(task.start_date) : void 0],
1381
- ["Due", task.due_date ? formatDate(task.due_date) : void 0],
1419
+ ["Due", task.due_date ? colorDueDate(formatDate(task.due_date), task.due_date) : void 0],
1382
1420
  ["Estimate", task.time_estimate ? formatDuration(task.time_estimate) : void 0],
1383
1421
  ["Tracked", task.time_spent ? formatDuration(task.time_spent) : void 0],
1384
1422
  ["Tags", task.tags?.length ? task.tags.map((t) => t.name).join(", ") : void 0],
@@ -1444,8 +1482,9 @@ function formatTaskDetail(task) {
1444
1482
  function formatChoiceName(task) {
1445
1483
  const id = task.id.padEnd(12);
1446
1484
  const name = task.name.length > 50 ? task.name.slice(0, 49) + "\u2026" : task.name.padEnd(50);
1447
- const status = task.status;
1448
- return `${id} ${name} ${chalk2.dim(status)}`;
1485
+ const status = colorStatus(task.status);
1486
+ const priority = task.priority !== "none" ? colorPriority(task.priority) : "";
1487
+ return `${id} ${name} ${status}${priority ? " " + priority : ""}`;
1449
1488
  }
1450
1489
  async function interactiveTaskPicker(tasks) {
1451
1490
  if (tasks.length === 0) return [];
@@ -1541,6 +1580,7 @@ function summarize(task, typeMap) {
1541
1580
  task_type: resolveTaskType(task, typeMap ?? /* @__PURE__ */ new Map()),
1542
1581
  priority: task.priority?.priority ?? "none",
1543
1582
  due_date: formatDueDate(task.due_date),
1583
+ ...task.due_date ? { dueRaw: task.due_date } : {},
1544
1584
  list: task.list.name,
1545
1585
  url: task.url,
1546
1586
  ...task.parent ? { parent: task.parent } : {}
@@ -1994,9 +2034,15 @@ Using: ${sprintLists[sprintLists.length - 1].name}
1994
2034
  }
1995
2035
 
1996
2036
  // src/commands/sprints.ts
2037
+ import chalk3 from "chalk";
1997
2038
  var SPRINT_COLUMNS = [
1998
2039
  { key: "id", label: "ID" },
1999
- { key: "sprint", label: "SPRINT", maxWidth: 60 },
2040
+ {
2041
+ key: "sprint",
2042
+ label: "SPRINT",
2043
+ maxWidth: 60,
2044
+ format: (v, row) => row.active ? chalk3.green(v) : v
2045
+ },
2000
2046
  { key: "dates", label: "DATES" }
2001
2047
  ];
2002
2048
  function formatSprintDate(d) {
@@ -2067,7 +2113,8 @@ async function listSprints(config, opts = {}) {
2067
2113
  return {
2068
2114
  id: s.id,
2069
2115
  sprint: s.active ? `* ${s.name}` : s.name,
2070
- dates: dateStr
2116
+ dates: dateStr,
2117
+ active: s.active
2071
2118
  };
2072
2119
  });
2073
2120
  if (!isTTY()) {
@@ -2106,7 +2153,7 @@ async function postComment(config, taskId, text, notifyAll) {
2106
2153
  }
2107
2154
 
2108
2155
  // src/commands/comments.ts
2109
- import chalk3 from "chalk";
2156
+ import chalk4 from "chalk";
2110
2157
  async function fetchComments(config, taskId) {
2111
2158
  const client = new ClickUpClient(config);
2112
2159
  const comments = await client.getTaskComments(taskId);
@@ -2130,11 +2177,11 @@ function printComments(comments, forceJson) {
2130
2177
  console.log("No comments found.");
2131
2178
  return;
2132
2179
  }
2133
- const separator = chalk3.dim("-".repeat(60));
2180
+ const separator = chalk4.dim("-".repeat(60));
2134
2181
  for (let i = 0; i < comments.length; i++) {
2135
2182
  const c = comments[i];
2136
2183
  if (i > 0) console.log(separator);
2137
- console.log(`${chalk3.bold(c.user)} ${chalk3.dim(formatTimestamp(c.date))}`);
2184
+ console.log(`${chalk4.bold(c.user)} ${chalk4.dim(formatTimestamp(c.date))}`);
2138
2185
  console.log(c.text);
2139
2186
  if (i < comments.length - 1) console.log("");
2140
2187
  }
@@ -2444,6 +2491,7 @@ async function openTask(config, query, opts = {}) {
2444
2491
  }
2445
2492
 
2446
2493
  // src/commands/summary.ts
2494
+ import chalk5 from "chalk";
2447
2495
  var IN_PROGRESS_PATTERNS = ["in progress", "in review", "code review", "doing"];
2448
2496
  function isCompletedRecently(task, cutoff) {
2449
2497
  if (!isDoneStatus(task.status.status)) return false;
@@ -2479,9 +2527,16 @@ function categorizeTasks(tasks, hoursBack, typeMap) {
2479
2527
  }
2480
2528
  return { completed, inProgress, overdue };
2481
2529
  }
2530
+ function colorSectionLabel(label) {
2531
+ const lower = label.toLowerCase();
2532
+ if (lower.includes("completed")) return chalk5.green(label);
2533
+ if (lower.includes("progress")) return chalk5.yellow(label);
2534
+ if (lower.includes("overdue")) return chalk5.red(label);
2535
+ return label;
2536
+ }
2482
2537
  function printSection(label, tasks) {
2483
2538
  console.log(`
2484
- ${label} (${tasks.length})`);
2539
+ ${colorSectionLabel(label)} (${tasks.length})`);
2485
2540
  if (tasks.length === 0) {
2486
2541
  console.log(" None");
2487
2542
  } else {
@@ -2601,7 +2656,7 @@ async function assignTask(config, taskId, opts) {
2601
2656
  }
2602
2657
 
2603
2658
  // src/commands/activity.ts
2604
- import chalk4 from "chalk";
2659
+ import chalk6 from "chalk";
2605
2660
  async function fetchActivity(config, taskId) {
2606
2661
  const client = new ClickUpClient(config);
2607
2662
  const [task, rawComments] = await Promise.all([
@@ -2633,8 +2688,8 @@ ${commentsMd}`);
2633
2688
  }
2634
2689
  console.log(formatTaskDetail(result.task));
2635
2690
  console.log("");
2636
- console.log(chalk4.bold("Comments"));
2637
- console.log(chalk4.dim("-".repeat(60)));
2691
+ console.log(chalk6.bold("Comments"));
2692
+ console.log(chalk6.dim("-".repeat(60)));
2638
2693
  if (result.comments.length === 0) {
2639
2694
  console.log("No comments.");
2640
2695
  return;
@@ -2643,9 +2698,9 @@ ${commentsMd}`);
2643
2698
  const c = result.comments[i];
2644
2699
  if (i > 0) {
2645
2700
  console.log("");
2646
- console.log(chalk4.dim("-".repeat(60)));
2701
+ console.log(chalk6.dim("-".repeat(60)));
2647
2702
  }
2648
- console.log(`${chalk4.bold(c.user)} ${chalk4.dim(formatTimestamp(c.date))}`);
2703
+ console.log(`${chalk6.bold(c.user)} ${chalk6.dim(formatTimestamp(c.date))}`);
2649
2704
  console.log(c.text);
2650
2705
  }
2651
2706
  }
@@ -4548,7 +4603,7 @@ async function manageTags(config, taskId, opts) {
4548
4603
  }
4549
4604
 
4550
4605
  // src/commands/checklist.ts
4551
- import chalk5 from "chalk";
4606
+ import chalk7 from "chalk";
4552
4607
  async function viewChecklists(config, taskId) {
4553
4608
  const client = new ClickUpClient(config);
4554
4609
  const task = await client.getTask(taskId);
@@ -4581,13 +4636,14 @@ function formatChecklists(checklists) {
4581
4636
  const lines = [];
4582
4637
  for (const cl of checklists) {
4583
4638
  const resolved = cl.items.filter((i) => i.resolved).length;
4584
- lines.push(chalk5.bold(`${cl.name} (${resolved}/${cl.items.length})`));
4585
- lines.push(chalk5.dim(` ID: ${cl.id}`));
4639
+ lines.push(chalk7.bold(`${cl.name} (${resolved}/${cl.items.length})`));
4640
+ lines.push(chalk7.dim(` ID: ${cl.id}`));
4586
4641
  for (const item of cl.items) {
4587
- const check = item.resolved ? chalk5.green("[x]") : chalk5.dim("[ ]");
4588
- const assignee = item.assignee ? chalk5.dim(` @${item.assignee.username}`) : "";
4589
- lines.push(` ${check} ${item.name}${assignee}`);
4590
- lines.push(chalk5.dim(` item-id: ${item.id}`));
4642
+ const check = item.resolved ? chalk7.green("[x]") : chalk7.dim("[ ]");
4643
+ const name = item.resolved ? chalk7.dim(item.name) : item.name;
4644
+ const assignee = item.assignee ? chalk7.dim(` @${item.assignee.username}`) : "";
4645
+ lines.push(` ${check} ${name}${assignee}`);
4646
+ lines.push(chalk7.dim(` item-id: ${item.id}`));
4591
4647
  }
4592
4648
  }
4593
4649
  return lines.join("\n");
@@ -4618,7 +4674,7 @@ async function deleteComment(config, commentId) {
4618
4674
  }
4619
4675
 
4620
4676
  // src/commands/replies.ts
4621
- import chalk6 from "chalk";
4677
+ import chalk8 from "chalk";
4622
4678
  async function getReplies(config, commentId) {
4623
4679
  const client = new ClickUpClient(config);
4624
4680
  return client.getThreadedComments(commentId);
@@ -4633,7 +4689,7 @@ function formatReplies(replies) {
4633
4689
  return replies.map((r) => {
4634
4690
  const user = r.user?.username ?? "Unknown";
4635
4691
  const date = formatTimestamp(Number(r.date));
4636
- return `${chalk6.bold(user)} ${chalk6.dim(date)}
4692
+ return `${chalk8.bold(user)} ${chalk8.dim(date)}
4637
4693
  ${r.comment_text}`;
4638
4694
  }).join("\n\n");
4639
4695
  }
@@ -4672,7 +4728,10 @@ async function attachFile(config, taskId, filePath) {
4672
4728
  }
4673
4729
 
4674
4730
  // src/commands/docs.ts
4675
- import chalk7 from "chalk";
4731
+ var DOC_COLUMNS = [
4732
+ { key: "id", label: "ID", maxWidth: 15 },
4733
+ { key: "name", label: "Name", maxWidth: 60 }
4734
+ ];
4676
4735
  async function listDocs(config, query) {
4677
4736
  const client = new ClickUpClient(config);
4678
4737
  const docs = await client.getDocs(config.teamId);
@@ -4684,7 +4743,8 @@ async function listDocs(config, query) {
4684
4743
  }
4685
4744
  function formatDocs(docs) {
4686
4745
  if (docs.length === 0) return "No docs found";
4687
- return docs.map((d) => `${chalk7.bold(d.name)} ${chalk7.dim(d.id)}`).join("\n");
4746
+ const rows = docs.map((d) => ({ name: d.name, id: d.id }));
4747
+ return formatTable(rows, DOC_COLUMNS);
4688
4748
  }
4689
4749
  function formatDocsMarkdown(docs) {
4690
4750
  if (docs.length === 0) return "No docs found";
@@ -4692,7 +4752,7 @@ function formatDocsMarkdown(docs) {
4692
4752
  }
4693
4753
 
4694
4754
  // src/commands/doc.ts
4695
- import chalk8 from "chalk";
4755
+ import chalk9 from "chalk";
4696
4756
  async function getDocInfo(config, docId) {
4697
4757
  const client = new ClickUpClient(config);
4698
4758
  const [doc, pages] = await Promise.all([
@@ -4704,14 +4764,14 @@ async function getDocInfo(config, docId) {
4704
4764
  function formatDocInfo(doc, pages, indent = 0) {
4705
4765
  const lines = [];
4706
4766
  if (indent === 0) {
4707
- lines.push(`${chalk8.bold(doc.name)} ${chalk8.dim(doc.id)}`);
4767
+ lines.push(`${chalk9.bold(doc.name)} ${chalk9.dim(doc.id)}`);
4708
4768
  if (pages.length === 0) {
4709
4769
  lines.push(" (no pages)");
4710
4770
  }
4711
4771
  }
4712
4772
  for (const page of pages) {
4713
4773
  const prefix = " ".repeat(indent + 1);
4714
- lines.push(`${prefix}${page.name} ${chalk8.dim(page.id)}`);
4774
+ lines.push(`${prefix}${page.name} ${chalk9.dim(page.id)}`);
4715
4775
  if (page.pages && page.pages.length > 0) {
4716
4776
  lines.push(formatDocInfo(doc, page.pages, indent + 1));
4717
4777
  }
@@ -4790,7 +4850,7 @@ async function deleteDocPage(config, docId, pageId) {
4790
4850
  }
4791
4851
 
4792
4852
  // src/commands/folders.ts
4793
- import chalk9 from "chalk";
4853
+ import chalk10 from "chalk";
4794
4854
  async function listFolders(config, spaceId, nameFilter) {
4795
4855
  const client = new ClickUpClient(config);
4796
4856
  const folders = await client.getFolders(spaceId);
@@ -4809,9 +4869,9 @@ async function listFolders(config, spaceId, nameFilter) {
4809
4869
  function formatFolders(folders) {
4810
4870
  if (folders.length === 0) return "No folders found";
4811
4871
  return folders.map((f) => {
4812
- const header = `${chalk9.bold(f.name)} ${chalk9.dim(f.id)}`;
4872
+ const header = `${chalk10.bold(f.name)} ${chalk10.dim(f.id)}`;
4813
4873
  if (f.lists.length === 0) return header;
4814
- const listLines = f.lists.map((l) => ` ${l.name} ${chalk9.dim(l.id)}`);
4874
+ const listLines = f.lists.map((l) => ` ${chalk10.dim(">")} ${l.name} ${chalk10.dim(l.id)}`);
4815
4875
  return [header, ...listLines].join("\n");
4816
4876
  }).join("\n\n");
4817
4877
  }
@@ -4826,7 +4886,14 @@ function formatFoldersMarkdown(folders) {
4826
4886
  }
4827
4887
 
4828
4888
  // src/commands/time.ts
4829
- import chalk10 from "chalk";
4889
+ import chalk11 from "chalk";
4890
+ var TIME_COLUMNS = [
4891
+ { key: "task", label: "Task", maxWidth: 35 },
4892
+ { key: "duration", label: "Duration", maxWidth: 10 },
4893
+ { key: "date", label: "Date", maxWidth: 20 },
4894
+ { key: "description", label: "Description", maxWidth: 30 },
4895
+ { key: "status", label: "", maxWidth: 10, format: (v) => v === "RUNNING" ? chalk11.green(v) : "" }
4896
+ ];
4830
4897
  async function startTimer(config, taskId, description) {
4831
4898
  const client = new ClickUpClient(config);
4832
4899
  return client.startTimeEntry(config.teamId, taskId, description);
@@ -4870,22 +4937,33 @@ async function deleteTimeEntry(config, timeEntryId) {
4870
4937
  await client.deleteTimeEntry(config.teamId, timeEntryId);
4871
4938
  }
4872
4939
  function formatTimeEntry(entry) {
4873
- const lines = [];
4874
4940
  const taskName = entry.task?.name ?? "No task";
4875
- const taskId = entry.task?.id ?? "";
4876
4941
  const isRunning = entry.duration < 0;
4877
4942
  const elapsed = isRunning ? Date.now() - Number(entry.start) : entry.duration;
4878
- const durationStr = formatDuration(elapsed);
4879
- const status = isRunning ? chalk10.green("RUNNING") : "";
4880
- lines.push(`${chalk10.bold(taskName)} ${chalk10.dim(taskId)} ${status}`);
4881
- lines.push(
4882
- ` ${durationStr} - ${formatTimestamp(entry.start)}${entry.description ? ` - ${entry.description}` : ""}`
4883
- );
4884
- return lines.join("\n");
4943
+ const row = {
4944
+ task: taskName,
4945
+ duration: formatDuration(elapsed),
4946
+ date: formatTimestamp(entry.start),
4947
+ description: entry.description ?? "",
4948
+ status: isRunning ? "RUNNING" : ""
4949
+ };
4950
+ return formatTable([row], TIME_COLUMNS);
4885
4951
  }
4886
4952
  function formatTimeEntries(entries) {
4887
4953
  if (entries.length === 0) return "No time entries";
4888
- return entries.map(formatTimeEntry).join("\n");
4954
+ const rows = entries.map((entry) => {
4955
+ const taskName = entry.task?.name ?? "No task";
4956
+ const isRunning = entry.duration < 0;
4957
+ const elapsed = isRunning ? Date.now() - Number(entry.start) : entry.duration;
4958
+ return {
4959
+ task: taskName,
4960
+ duration: formatDuration(elapsed),
4961
+ date: formatTimestamp(entry.start),
4962
+ description: entry.description ?? "",
4963
+ status: isRunning ? "RUNNING" : ""
4964
+ };
4965
+ });
4966
+ return formatTable(rows, TIME_COLUMNS);
4889
4967
  }
4890
4968
  function formatTimeEntryMarkdown(entry) {
4891
4969
  const taskName = entry.task?.name ?? "No task";
@@ -4902,7 +4980,7 @@ function formatTimeEntriesMarkdown(entries) {
4902
4980
  }
4903
4981
 
4904
4982
  // src/commands/tags.ts
4905
- import chalk11 from "chalk";
4983
+ import chalk12 from "chalk";
4906
4984
  async function listSpaceTags(config, spaceId) {
4907
4985
  const client = new ClickUpClient(config);
4908
4986
  return client.getSpaceTags(spaceId);
@@ -4925,7 +5003,7 @@ async function updateSpaceTag(config, spaceId, tagName, updates) {
4925
5003
  }
4926
5004
  function formatTags(tags) {
4927
5005
  if (tags.length === 0) return "No tags found";
4928
- return tags.map((t) => chalk11.bold(t.name)).join(", ");
5006
+ return tags.map((t) => chalk12.bold(t.name)).join(", ");
4929
5007
  }
4930
5008
  function formatTagsMarkdown(tags) {
4931
5009
  if (tags.length === 0) return "No tags found";
@@ -4933,14 +5011,23 @@ function formatTagsMarkdown(tags) {
4933
5011
  }
4934
5012
 
4935
5013
  // src/commands/members.ts
4936
- import chalk12 from "chalk";
5014
+ var MEMBER_COLUMNS = [
5015
+ { key: "username", label: "Username", maxWidth: 25 },
5016
+ { key: "id", label: "ID", maxWidth: 15 },
5017
+ { key: "email", label: "Email", maxWidth: 40 }
5018
+ ];
4937
5019
  async function listMembers(config) {
4938
5020
  const client = new ClickUpClient(config);
4939
5021
  return client.getWorkspaceMembers(config.teamId);
4940
5022
  }
4941
5023
  function formatMembers(members) {
4942
5024
  if (members.length === 0) return "No members found";
4943
- return members.map((m) => `${chalk12.bold(m.username)} ${chalk12.dim(`(${m.id})`)} ${m.email}`).join("\n");
5025
+ const rows = members.map((m) => ({
5026
+ username: m.username,
5027
+ id: String(m.id),
5028
+ email: m.email
5029
+ }));
5030
+ return formatTable(rows, MEMBER_COLUMNS);
4944
5031
  }
4945
5032
  function formatMembersMarkdown(members) {
4946
5033
  if (members.length === 0) return "No members found";
@@ -4949,17 +5036,30 @@ function formatMembersMarkdown(members) {
4949
5036
 
4950
5037
  // src/commands/fields.ts
4951
5038
  import chalk13 from "chalk";
5039
+ var FIELD_COLUMNS = [
5040
+ { key: "name", label: "Name", maxWidth: 30 },
5041
+ { key: "type", label: "Type", maxWidth: 15 },
5042
+ {
5043
+ key: "required",
5044
+ label: "Required",
5045
+ maxWidth: 10,
5046
+ format: (v) => v === "yes" ? chalk13.yellow(v) : chalk13.dim(v)
5047
+ },
5048
+ { key: "options", label: "Options", maxWidth: 40 }
5049
+ ];
4952
5050
  async function listFields(config, listId) {
4953
5051
  const client = new ClickUpClient(config);
4954
5052
  return client.getListCustomFields(listId);
4955
5053
  }
4956
5054
  function formatFields(fields) {
4957
5055
  if (fields.length === 0) return "No custom fields";
4958
- return fields.map((f) => {
4959
- const options = f.type_config?.options?.map((o) => o.name).join(", ");
4960
- const optStr = options ? ` ${chalk13.dim(`[${options}]`)}` : "";
4961
- return `${chalk13.bold(f.name)} ${chalk13.dim(f.type)}${f.required ? chalk13.yellow(" (required)") : ""}${optStr}`;
4962
- }).join("\n");
5056
+ const rows = fields.map((f) => ({
5057
+ name: f.name,
5058
+ type: f.type,
5059
+ required: f.required ? "yes" : "no",
5060
+ options: f.type_config?.options?.map((o) => o.name).join(", ") ?? ""
5061
+ }));
5062
+ return formatTable(rows, FIELD_COLUMNS);
4963
5063
  }
4964
5064
  function formatFieldsMarkdown(fields) {
4965
5065
  if (fields.length === 0) return "No custom fields";
@@ -5003,6 +5103,25 @@ async function bulkUpdateStatus(config, taskIds, status) {
5003
5103
 
5004
5104
  // src/commands/goals.ts
5005
5105
  import chalk14 from "chalk";
5106
+ function colorProgress(value) {
5107
+ const num = parseInt(value, 10);
5108
+ if (isNaN(num)) return value;
5109
+ if (num >= 75) return chalk14.green(value);
5110
+ if (num >= 25) return chalk14.yellow(value);
5111
+ return chalk14.red(value);
5112
+ }
5113
+ var GOAL_COLUMNS = [
5114
+ { key: "id", label: "ID", maxWidth: 15 },
5115
+ { key: "name", label: "Name", maxWidth: 40 },
5116
+ { key: "progress", label: "Progress", maxWidth: 10, format: (v) => colorProgress(v) },
5117
+ { key: "owner", label: "Owner", maxWidth: 20 }
5118
+ ];
5119
+ var KEY_RESULT_COLUMNS = [
5120
+ { key: "id", label: "ID", maxWidth: 15 },
5121
+ { key: "name", label: "Name", maxWidth: 40 },
5122
+ { key: "progress", label: "Progress", maxWidth: 10, format: (v) => colorProgress(v) },
5123
+ { key: "current", label: "Current/Target", maxWidth: 15 }
5124
+ ];
5006
5125
  async function listGoals(config) {
5007
5126
  const client = new ClickUpClient(config);
5008
5127
  return client.getGoals(config.teamId);
@@ -5040,11 +5159,13 @@ async function updateKeyResult(config, keyResultId, updates) {
5040
5159
  }
5041
5160
  function formatGoals(goals) {
5042
5161
  if (goals.length === 0) return "No goals found";
5043
- return goals.map((g) => {
5044
- const pct = Math.round(g.percent_completed * 100);
5045
- const owner = g.owner ? ` ${chalk14.dim(`@${g.owner.username}`)}` : "";
5046
- return `${chalk14.bold(g.name)} ${chalk14.dim(`(${g.id})`)} ${chalk14.cyan(`${pct}%`)}${owner}`;
5047
- }).join("\n");
5162
+ const rows = goals.map((g) => ({
5163
+ name: g.name,
5164
+ id: g.id,
5165
+ progress: `${Math.round(g.percent_completed * 100)}%`,
5166
+ owner: g.owner ? `@${g.owner.username}` : ""
5167
+ }));
5168
+ return formatTable(rows, GOAL_COLUMNS);
5048
5169
  }
5049
5170
  function formatGoalsMarkdown(goals) {
5050
5171
  if (goals.length === 0) return "No goals found";
@@ -5056,10 +5177,13 @@ function formatGoalsMarkdown(goals) {
5056
5177
  }
5057
5178
  function formatKeyResults(keyResults) {
5058
5179
  if (keyResults.length === 0) return "No key results found";
5059
- return keyResults.map((kr) => {
5060
- const pct = Math.round(kr.percent_completed * 100);
5061
- return `${chalk14.bold(kr.name)} ${chalk14.dim(`(${kr.id})`)} ${chalk14.cyan(`${kr.steps_current}/${kr.steps_end}`)} ${chalk14.dim(`${pct}%`)}`;
5062
- }).join("\n");
5180
+ const rows = keyResults.map((kr) => ({
5181
+ name: kr.name,
5182
+ id: kr.id,
5183
+ progress: `${Math.round(kr.percent_completed * 100)}%`,
5184
+ current: `${kr.steps_current}/${kr.steps_end}`
5185
+ }));
5186
+ return formatTable(rows, KEY_RESULT_COLUMNS);
5063
5187
  }
5064
5188
  function formatKeyResultsMarkdown(keyResults) {
5065
5189
  if (keyResults.length === 0) return "No key results found";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@krodak/clickup-cli",
3
- "version": "1.12.0",
3
+ "version": "1.14.0",
4
4
  "description": "ClickUp CLI for AI agents and humans",
5
5
  "type": "module",
6
6
  "license": "MIT",