@krodak/clickup-cli 1.9.2 → 1.11.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.9.2",
4
+ "version": "1.11.0",
5
5
  "author": {
6
6
  "name": "Krzysztof Rodak"
7
7
  },
package/README.md CHANGED
@@ -154,7 +154,8 @@ Full CRUD for the core ClickUp workflow:
154
154
  | 🏷️ **Tags** | Add/remove on tasks, space-level create/update/delete |
155
155
  | 🎯 **Goals & OKRs** | Goals CRUD, key results CRUD |
156
156
  | 🏃 **Sprints** | Auto-detect active sprint, flexible date parsing, config override |
157
- | 🏢 **Workspace** | Spaces, folders, lists (read + create), members, task types, templates |
157
+ | 👁️ **Views** | List, get, create, update, delete views on lists |
158
+ | 🏢 **Workspace** | Spaces, folders, lists (read + create + from template), members, task types, templates |
158
159
  | 📎 **Attachments** | Upload files to tasks, shown in detail views |
159
160
 
160
161
  [Full API coverage details](docs/api-coverage.md) | [Command reference](docs/commands.md)
package/dist/index.js CHANGED
@@ -277,13 +277,56 @@ var ClickUpClient = class {
277
277
  return readCollectionField(data, "lists", "folder lists");
278
278
  }
279
279
  async getListViews(listId) {
280
- return this.request(
281
- `/list/${listId}/view`
282
- );
280
+ return this.request(`/list/${listId}/view`);
283
281
  }
284
282
  async getViewTasks(viewId) {
285
283
  return this.paginate((page) => `/view/${viewId}/task?page=${page}`);
286
284
  }
285
+ async getView(viewId) {
286
+ const data = await this.request(`/view/${viewId}`);
287
+ return data.view;
288
+ }
289
+ async createListView(listId, payload) {
290
+ const data = await this.request(`/list/${listId}/view`, {
291
+ method: "POST",
292
+ body: JSON.stringify(payload)
293
+ });
294
+ return data.view;
295
+ }
296
+ async updateView(viewId, payload) {
297
+ const data = await this.request(`/view/${viewId}`, {
298
+ method: "PUT",
299
+ body: JSON.stringify(payload)
300
+ });
301
+ return data.view;
302
+ }
303
+ async deleteView(viewId) {
304
+ await this.request(`/view/${viewId}`, { method: "DELETE" });
305
+ }
306
+ async getListTemplates(teamId) {
307
+ const data = await this.request(`/team/${teamId}/list_template`);
308
+ return readCollectionField(
309
+ data,
310
+ "templates",
311
+ "list templates"
312
+ );
313
+ }
314
+ async getFolderTemplates(teamId) {
315
+ const data = await this.request(
316
+ `/team/${teamId}/folder_template`
317
+ );
318
+ return readCollectionField(
319
+ data,
320
+ "templates",
321
+ "folder templates"
322
+ );
323
+ }
324
+ async createListFromTemplate(containerId, templateId, name, containerType) {
325
+ return this.request(
326
+ `/${containerType}/${containerId}/list_template/${templateId}`,
327
+ { method: "POST", body: JSON.stringify({ name }) }
328
+ );
329
+ }
287
330
  async addTaskToList(taskId, listId) {
288
331
  await this.request(`/list/${listId}/task/${taskId}`, { method: "POST" });
289
332
  }
@@ -1308,11 +1351,7 @@ function formatCustomFieldValue(field) {
1308
1351
  case "date": {
1309
1352
  const ts = Number(field.value);
1310
1353
  if (!Number.isFinite(ts)) return stringifyFieldValue(field.value);
1311
- return new Date(ts).toLocaleDateString("en-US", {
1312
- month: "short",
1313
- day: "numeric",
1314
- year: "numeric"
1315
- });
1354
+ return formatDate(String(ts));
1316
1355
  }
1317
1356
  case "checkbox":
1318
1357
  return field.value === true || field.value === "true" ? "Yes" : "No";
@@ -2840,6 +2879,14 @@ var commandMetadata = [
2840
2879
  { section: "read", usage: "overdue", description: "Tasks past their due date" }
2841
2880
  ]
2842
2881
  },
2882
+ {
2883
+ name: "archive",
2884
+ description: "Archive a task (or unarchive with --unarchive)",
2885
+ flags: ["--unarchive", "--confirm", "--json"],
2886
+ quickReference: [
2887
+ { section: "write", usage: "archive <taskId>", description: "Archive or unarchive a task" }
2888
+ ]
2889
+ },
2843
2890
  {
2844
2891
  name: "assign",
2845
2892
  description: "Assign or unassign users from a task",
@@ -3250,6 +3297,76 @@ var commandMetadata = [
3250
3297
  flags: ["--json"],
3251
3298
  quickReference: [{ section: "read", usage: "templates", description: "List task templates" }]
3252
3299
  },
3300
+ {
3301
+ name: "list-templates",
3302
+ description: "List list templates in your workspace",
3303
+ flags: ["--json"],
3304
+ quickReference: [
3305
+ { section: "read", usage: "list-templates", description: "List list templates" }
3306
+ ]
3307
+ },
3308
+ {
3309
+ name: "folder-templates",
3310
+ description: "List folder templates in your workspace",
3311
+ flags: ["--json"],
3312
+ quickReference: [
3313
+ { section: "read", usage: "folder-templates", description: "List folder templates" }
3314
+ ]
3315
+ },
3316
+ {
3317
+ name: "list-from-template",
3318
+ description: "Create a list from a list template",
3319
+ flags: ["--template", "--space", "--folder", "--json"],
3320
+ quickReference: [
3321
+ {
3322
+ section: "write",
3323
+ usage: "list-from-template <name>",
3324
+ description: "Create a list from a template"
3325
+ }
3326
+ ]
3327
+ },
3328
+ {
3329
+ name: "views",
3330
+ description: "List views on a list",
3331
+ flags: ["--json"],
3332
+ quickReference: [
3333
+ { section: "read", usage: "views <listId>", description: "List views on a list" }
3334
+ ]
3335
+ },
3336
+ {
3337
+ name: "view",
3338
+ description: "Get view details",
3339
+ flags: ["--json"],
3340
+ quickReference: [{ section: "read", usage: "view <viewId>", description: "Get view details" }]
3341
+ },
3342
+ {
3343
+ name: "view-create",
3344
+ description: "Create a view on a list",
3345
+ flags: ["-t", "--type", "--group-by", "--json"],
3346
+ quickReference: [
3347
+ {
3348
+ section: "write",
3349
+ usage: "view-create <listId> <name>",
3350
+ description: "Create a view on a list"
3351
+ }
3352
+ ]
3353
+ },
3354
+ {
3355
+ name: "view-update",
3356
+ description: "Update a view",
3357
+ flags: ["-n", "--name", "--group-by", "--json"],
3358
+ quickReference: [
3359
+ { section: "write", usage: "view-update <viewId>", description: "Update a view" }
3360
+ ]
3361
+ },
3362
+ {
3363
+ name: "view-delete",
3364
+ description: "Delete a view (requires confirmation)",
3365
+ flags: ["--confirm", "--json"],
3366
+ quickReference: [
3367
+ { section: "write", usage: "view-delete <viewId>", description: "Delete a view" }
3368
+ ]
3369
+ },
3253
3370
  {
3254
3371
  name: "profile",
3255
3372
  description: "Manage profiles",
@@ -3935,6 +4052,53 @@ ${renderZshTopLevelCommands(name)}
3935
4052
  _arguments \\
3936
4053
  '--json[Force JSON output]'
3937
4054
  ;;
4055
+ list-templates)
4056
+ _arguments \\
4057
+ '--json[Force JSON output]'
4058
+ ;;
4059
+ folder-templates)
4060
+ _arguments \\
4061
+ '--json[Force JSON output]'
4062
+ ;;
4063
+ list-from-template)
4064
+ _arguments \\
4065
+ '1:name:' \\
4066
+ '--template[Template ID]:template_id:' \\
4067
+ '--space[Create in this space]:space_id:' \\
4068
+ '--folder[Create in this folder]:folder_id:' \\
4069
+ '--json[Force JSON output]'
4070
+ ;;
4071
+ views)
4072
+ _arguments \\
4073
+ '1:list_id:' \\
4074
+ '--json[Force JSON output]'
4075
+ ;;
4076
+ view)
4077
+ _arguments \\
4078
+ '1:view_id:' \\
4079
+ '--json[Force JSON output]'
4080
+ ;;
4081
+ view-create)
4082
+ _arguments \\
4083
+ '1:list_id:' \\
4084
+ '2:name:' \\
4085
+ '(-t --type)'{-t,--type}'[View type]:type:(list board calendar gantt table timeline)' \\
4086
+ '--group-by[Group by field]:field:(status assignee priority due_date tag sprint)' \\
4087
+ '--json[Force JSON output]'
4088
+ ;;
4089
+ view-update)
4090
+ _arguments \\
4091
+ '1:view_id:' \\
4092
+ '(-n --name)'{-n,--name}'[New view name]:text:' \\
4093
+ '--group-by[Group by field]:field:(status assignee priority due_date tag sprint)' \\
4094
+ '--json[Force JSON output]'
4095
+ ;;
4096
+ view-delete)
4097
+ _arguments \\
4098
+ '1:view_id:' \\
4099
+ '--confirm[Skip confirmation prompt]' \\
4100
+ '--json[Force JSON output]'
4101
+ ;;
3938
4102
  folders)
3939
4103
  _arguments \\
3940
4104
  '1:space_id:' \\
@@ -4310,6 +4474,27 @@ async function deleteTaskCommand(config, taskId, opts) {
4310
4474
  return { taskId, deleted: true };
4311
4475
  }
4312
4476
 
4477
+ // src/commands/archive.ts
4478
+ async function archiveTaskCommand(config, taskId, opts) {
4479
+ const client = new ClickUpClient(config);
4480
+ if (!opts.confirm) {
4481
+ if (!isTTY()) {
4482
+ throw new Error(`Destructive operation requires --confirm flag in non-interactive mode`);
4483
+ }
4484
+ const task = await client.getTask(taskId);
4485
+ const { confirm: confirm3 } = await import("@inquirer/prompts");
4486
+ const confirmed = await confirm3({
4487
+ message: `${opts.unarchive ? "Unarchive" : "Archive"} task "${task.name}" (${task.id})?`,
4488
+ default: false
4489
+ });
4490
+ if (!confirmed) {
4491
+ throw new Error("Cancelled");
4492
+ }
4493
+ }
4494
+ await client.updateTask(taskId, { archived: !opts.unarchive });
4495
+ return { taskId, archived: !opts.unarchive };
4496
+ }
4497
+
4313
4498
  // src/commands/tag.ts
4314
4499
  function parseTags(input) {
4315
4500
  return input.split(",").map((t) => t.trim()).filter((t) => t.length > 0);
@@ -4900,6 +5085,175 @@ function formatTemplatesMarkdown(templates) {
4900
5085
  return templates.map((t) => `- **${t.name}** (${t.id})`).join("\n");
4901
5086
  }
4902
5087
 
5088
+ // src/commands/list-templates.ts
5089
+ import chalk17 from "chalk";
5090
+ async function listListTemplates(config) {
5091
+ const client = new ClickUpClient(config);
5092
+ return client.getListTemplates(config.teamId);
5093
+ }
5094
+ function formatListTemplates(templates) {
5095
+ if (templates.length === 0) return "No list templates";
5096
+ return templates.map((t) => `${chalk17.bold(t.name)} ${chalk17.dim(`(${t.id})`)}`).join("\n");
5097
+ }
5098
+ function formatListTemplatesMarkdown(templates) {
5099
+ if (templates.length === 0) return "No list templates";
5100
+ return templates.map((t) => `- **${t.name}** (${t.id})`).join("\n");
5101
+ }
5102
+
5103
+ // src/commands/folder-templates.ts
5104
+ import chalk18 from "chalk";
5105
+ async function listFolderTemplates(config) {
5106
+ const client = new ClickUpClient(config);
5107
+ return client.getFolderTemplates(config.teamId);
5108
+ }
5109
+ function formatFolderTemplates(templates) {
5110
+ if (templates.length === 0) return "No folder templates";
5111
+ return templates.map((t) => `${chalk18.bold(t.name)} ${chalk18.dim(`(${t.id})`)}`).join("\n");
5112
+ }
5113
+ function formatFolderTemplatesMarkdown(templates) {
5114
+ if (templates.length === 0) return "No folder templates";
5115
+ return templates.map((t) => `- **${t.name}** (${t.id})`).join("\n");
5116
+ }
5117
+
5118
+ // src/commands/list-from-template.ts
5119
+ async function createListFromTemplate(config, name, opts) {
5120
+ if (!name.trim()) throw new Error("List name cannot be empty");
5121
+ if (!opts.space && !opts.folder) {
5122
+ throw new Error("Provide --space or --folder to specify where to create the list");
5123
+ }
5124
+ if (opts.space && opts.folder) {
5125
+ throw new Error("Provide either --space or --folder, not both");
5126
+ }
5127
+ const client = new ClickUpClient(config);
5128
+ const containerType = opts.folder ? "folder" : "space";
5129
+ const containerId = opts.folder ?? opts.space;
5130
+ return client.createListFromTemplate(containerId, opts.template, name, containerType);
5131
+ }
5132
+
5133
+ // src/commands/views.ts
5134
+ import chalk19 from "chalk";
5135
+ async function listViews(config, listId) {
5136
+ const client = new ClickUpClient(config);
5137
+ const data = await client.getListViews(listId);
5138
+ return data.views;
5139
+ }
5140
+ function formatViews(views) {
5141
+ if (views.length === 0) return "No views";
5142
+ return views.map((v) => `${chalk19.bold(v.name)} ${chalk19.dim(`(${v.id})`)} ${chalk19.dim(v.type)}`).join("\n");
5143
+ }
5144
+ function formatViewsMarkdown(views) {
5145
+ if (views.length === 0) return "No views";
5146
+ return views.map((v) => `- **${v.name}** (${v.id}) - ${v.type}`).join("\n");
5147
+ }
5148
+
5149
+ // src/commands/view.ts
5150
+ import chalk20 from "chalk";
5151
+ async function getView(config, viewId) {
5152
+ const client = new ClickUpClient(config);
5153
+ return client.getView(viewId);
5154
+ }
5155
+ function formatView(view) {
5156
+ const lines = [];
5157
+ lines.push(chalk20.bold.underline(view.name));
5158
+ lines.push("");
5159
+ lines.push(` ${chalk20.bold("ID")} ${view.id}`);
5160
+ lines.push(` ${chalk20.bold("Type")} ${view.type}`);
5161
+ if (view.visibility) lines.push(` ${chalk20.bold("Visibility")} ${view.visibility}`);
5162
+ if (view.date_created) lines.push(` ${chalk20.bold("Created")} ${formatDate(view.date_created)}`);
5163
+ if (view.protected !== void 0) lines.push(` ${chalk20.bold("Protected")} ${view.protected}`);
5164
+ return lines.join("\n");
5165
+ }
5166
+ function formatViewMarkdown(view) {
5167
+ const lines = [];
5168
+ lines.push(`# ${view.name}`);
5169
+ lines.push("");
5170
+ lines.push(`- **ID:** ${view.id}`);
5171
+ lines.push(`- **Type:** ${view.type}`);
5172
+ if (view.visibility) lines.push(`- **Visibility:** ${view.visibility}`);
5173
+ if (view.date_created) lines.push(`- **Created:** ${formatDate(view.date_created)}`);
5174
+ if (view.protected !== void 0) lines.push(`- **Protected:** ${view.protected}`);
5175
+ return lines.join("\n");
5176
+ }
5177
+
5178
+ // src/commands/view-create.ts
5179
+ var VALID_VIEW_TYPES = ["list", "board", "calendar", "gantt", "table", "timeline"];
5180
+ var VALID_GROUP_BY_FIELDS = [
5181
+ "status",
5182
+ "assignee",
5183
+ "priority",
5184
+ "due_date",
5185
+ "tag",
5186
+ "sprint"
5187
+ ];
5188
+ async function createView(config, listId, name, opts) {
5189
+ if (!name.trim()) throw new Error("View name cannot be empty");
5190
+ if (!VALID_VIEW_TYPES.includes(opts.type)) {
5191
+ throw new Error(`Invalid view type "${opts.type}". Valid types: ${VALID_VIEW_TYPES.join(", ")}`);
5192
+ }
5193
+ const payload = {
5194
+ name,
5195
+ type: opts.type
5196
+ };
5197
+ if (opts.groupBy) {
5198
+ if (!VALID_GROUP_BY_FIELDS.includes(opts.groupBy)) {
5199
+ throw new Error(
5200
+ `Invalid group-by field "${opts.groupBy}". Valid fields: ${VALID_GROUP_BY_FIELDS.join(", ")}`
5201
+ );
5202
+ }
5203
+ payload.grouping = { field: opts.groupBy };
5204
+ }
5205
+ const client = new ClickUpClient(config);
5206
+ return client.createListView(listId, payload);
5207
+ }
5208
+
5209
+ // src/commands/view-update.ts
5210
+ var VALID_GROUP_BY_FIELDS2 = [
5211
+ "status",
5212
+ "assignee",
5213
+ "priority",
5214
+ "due_date",
5215
+ "tag",
5216
+ "sprint"
5217
+ ];
5218
+ async function updateView(config, viewId, opts) {
5219
+ if (opts.name !== void 0 && !opts.name.trim()) {
5220
+ throw new Error("View name cannot be empty");
5221
+ }
5222
+ const payload = {};
5223
+ if (opts.name) payload.name = opts.name;
5224
+ if (opts.groupBy) {
5225
+ if (!VALID_GROUP_BY_FIELDS2.includes(opts.groupBy)) {
5226
+ throw new Error(
5227
+ `Invalid group-by field "${opts.groupBy}". Valid fields: ${VALID_GROUP_BY_FIELDS2.join(", ")}`
5228
+ );
5229
+ }
5230
+ payload.grouping = { field: opts.groupBy };
5231
+ }
5232
+ const client = new ClickUpClient(config);
5233
+ return client.updateView(viewId, payload);
5234
+ }
5235
+
5236
+ // src/commands/view-delete.ts
5237
+ async function deleteViewCommand(config, viewId, opts) {
5238
+ const client = new ClickUpClient(config);
5239
+ if (!opts.confirm) {
5240
+ if (!isTTY()) {
5241
+ throw new Error("Destructive operation requires --confirm flag in non-interactive mode");
5242
+ }
5243
+ const view = await client.getView(viewId);
5244
+ const { confirm: confirm3 } = await import("@inquirer/prompts");
5245
+ const confirmed = await confirm3({
5246
+ message: `Delete view "${view.name}" (${viewId})? This cannot be undone.`,
5247
+ default: false
5248
+ });
5249
+ if (!confirmed) {
5250
+ throw new Error("Cancelled");
5251
+ }
5252
+ }
5253
+ await client.deleteView(viewId);
5254
+ return { viewId, deleted: true };
5255
+ }
5256
+
4903
5257
  // src/index.ts
4904
5258
  var require2 = createRequire(import.meta.url);
4905
5259
  var { version } = require2("../package.json");
@@ -5291,6 +5645,19 @@ function buildProgram(programName = basename(process.argv[1] ?? "cup")) {
5291
5645
  }
5292
5646
  })
5293
5647
  );
5648
+ program.command("archive <taskId>").description("Archive a task (or unarchive with --unarchive)").option("--unarchive", "Unarchive instead of archiving").option("--confirm", "Skip confirmation prompt (required in non-interactive mode)").option("--json", "Force JSON output even in terminal").action(
5649
+ wrapAction(
5650
+ async (taskId, opts) => {
5651
+ const config = loadConfig(getProfileName());
5652
+ const result = await archiveTaskCommand(config, taskId, opts);
5653
+ if (shouldOutputJson(opts.json ?? false)) {
5654
+ console.log(JSON.stringify(result, null, 2));
5655
+ } else {
5656
+ console.log(`${result.archived ? "Archived" : "Unarchived"} task ${result.taskId}`);
5657
+ }
5658
+ }
5659
+ )
5660
+ );
5294
5661
  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(
5295
5662
  wrapAction(
5296
5663
  async (taskId, opts) => {
@@ -5955,6 +6322,123 @@ function buildProgram(programName = basename(process.argv[1] ?? "cup")) {
5955
6322
  }
5956
6323
  })
5957
6324
  );
6325
+ program.command("list-templates").description("List list templates in your workspace").option("--json", "Force JSON output even in terminal").action(
6326
+ wrapAction(async (opts) => {
6327
+ const config = loadConfig(getProfileName());
6328
+ const templates = await listListTemplates(config);
6329
+ if (shouldOutputJson(opts.json ?? false)) {
6330
+ console.log(JSON.stringify(templates, null, 2));
6331
+ } else if (isTTY()) {
6332
+ console.log(formatListTemplates(templates));
6333
+ } else {
6334
+ console.log(formatListTemplatesMarkdown(templates));
6335
+ }
6336
+ })
6337
+ );
6338
+ program.command("folder-templates").description("List folder templates in your workspace").option("--json", "Force JSON output even in terminal").action(
6339
+ wrapAction(async (opts) => {
6340
+ const config = loadConfig(getProfileName());
6341
+ const templates = await listFolderTemplates(config);
6342
+ if (shouldOutputJson(opts.json ?? false)) {
6343
+ console.log(JSON.stringify(templates, null, 2));
6344
+ } else if (isTTY()) {
6345
+ console.log(formatFolderTemplates(templates));
6346
+ } else {
6347
+ console.log(formatFolderTemplatesMarkdown(templates));
6348
+ }
6349
+ })
6350
+ );
6351
+ program.command("list-from-template <name>").description("Create a list from a list template").requiredOption("--template <id>", "Template ID (find with list-templates)").option("--space <spaceId>", "Create in this space").option("--folder <folderId>", "Create in this folder").option("--json", "Force JSON output even in terminal").action(
6352
+ wrapAction(
6353
+ async (name, opts) => {
6354
+ const config = loadConfig(getProfileName());
6355
+ const result = await createListFromTemplate(config, name, opts);
6356
+ if (shouldOutputJson(opts.json ?? false)) {
6357
+ console.log(JSON.stringify(result, null, 2));
6358
+ } else {
6359
+ console.log(`Created list "${name}" (${result.id}) from template`);
6360
+ }
6361
+ }
6362
+ )
6363
+ );
6364
+ program.command("views <listId>").description("List views on a list").option("--json", "Force JSON output even in terminal").action(
6365
+ wrapAction(async (listId, opts) => {
6366
+ const config = loadConfig(getProfileName());
6367
+ const views = await listViews(config, listId);
6368
+ if (shouldOutputJson(opts.json ?? false)) {
6369
+ console.log(JSON.stringify(views, null, 2));
6370
+ } else if (isTTY()) {
6371
+ console.log(formatViews(views));
6372
+ } else {
6373
+ console.log(formatViewsMarkdown(views));
6374
+ }
6375
+ })
6376
+ );
6377
+ program.command("view <viewId>").description("Get view details").option("--json", "Force JSON output even in terminal").action(
6378
+ wrapAction(async (viewId, opts) => {
6379
+ const config = loadConfig(getProfileName());
6380
+ const view = await getView(config, viewId);
6381
+ if (shouldOutputJson(opts.json ?? false)) {
6382
+ console.log(JSON.stringify(view, null, 2));
6383
+ } else if (!isTTY()) {
6384
+ console.log(formatViewMarkdown(view));
6385
+ } else {
6386
+ console.log(formatView(view));
6387
+ }
6388
+ })
6389
+ );
6390
+ program.command("view-create <listId> <name>").description("Create a view on a list").requiredOption(
6391
+ "-t, --type <type>",
6392
+ "View type (list, board, calendar, gantt, table, timeline)"
6393
+ ).option(
6394
+ "--group-by <field>",
6395
+ "Group by field (status, assignee, priority, due_date, tag, sprint)"
6396
+ ).option("--json", "Force JSON output even in terminal").action(
6397
+ wrapAction(
6398
+ async (listId, name, opts) => {
6399
+ const config = loadConfig(getProfileName());
6400
+ const view = await createView(config, listId, name, {
6401
+ type: opts.type,
6402
+ groupBy: opts.groupBy
6403
+ });
6404
+ if (shouldOutputJson(opts.json ?? false)) {
6405
+ console.log(JSON.stringify(view, null, 2));
6406
+ } else {
6407
+ console.log(`Created view "${view.name}" (${view.id}) type: ${view.type}`);
6408
+ }
6409
+ }
6410
+ )
6411
+ );
6412
+ program.command("view-update <viewId>").description("Update a view").option("-n, --name <text>", "New view name").option(
6413
+ "--group-by <field>",
6414
+ "Group by field (status, assignee, priority, due_date, tag, sprint)"
6415
+ ).option("--json", "Force JSON output even in terminal").action(
6416
+ wrapAction(
6417
+ async (viewId, opts) => {
6418
+ const config = loadConfig(getProfileName());
6419
+ const view = await updateView(config, viewId, {
6420
+ name: opts.name,
6421
+ groupBy: opts.groupBy
6422
+ });
6423
+ if (shouldOutputJson(opts.json ?? false)) {
6424
+ console.log(JSON.stringify(view, null, 2));
6425
+ } else {
6426
+ console.log(`Updated view "${view.name}" (${view.id})`);
6427
+ }
6428
+ }
6429
+ )
6430
+ );
6431
+ program.command("view-delete <viewId>").description("Delete a view (requires confirmation)").option("--confirm", "Skip confirmation prompt (required in non-interactive mode)").option("--json", "Force JSON output even in terminal").action(
6432
+ wrapAction(async (viewId, opts) => {
6433
+ const config = loadConfig(getProfileName());
6434
+ const result = await deleteViewCommand(config, viewId, opts);
6435
+ if (shouldOutputJson(opts.json ?? false)) {
6436
+ console.log(JSON.stringify(result, null, 2));
6437
+ } else {
6438
+ console.log(`Deleted view ${result.viewId}`);
6439
+ }
6440
+ })
6441
+ );
5958
6442
  const profileCmd = program.command("profile").description("Manage profiles");
5959
6443
  profileCmd.command("list").description("List all profiles").option("--json", "Force JSON output even in terminal").action(
5960
6444
  wrapAction(async (opts) => {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@krodak/clickup-cli",
3
- "version": "1.9.2",
3
+ "version": "1.11.0",
4
4
  "description": "ClickUp CLI for AI agents and humans",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -60,6 +60,10 @@ All commands support `--help` for full flag details. All commands support `--jso
60
60
  | `cup doc-pages <docId>` | All pages in a doc with content |
61
61
  | `cup task-types` | Custom task types (for `--custom-item-id`) |
62
62
  | `cup templates` | Task templates (for `--template`) |
63
+ | `cup list-templates` | List templates (for `list-from-template`) |
64
+ | `cup folder-templates` | Folder templates |
65
+ | `cup views <listId>` | List views on a list |
66
+ | `cup view <viewId>` | Get view details |
63
67
  | `cup open <query>` | Open task in browser by ID or name |
64
68
  | `cup auth` | Check authentication status |
65
69
 
@@ -115,6 +119,10 @@ All commands support `--help` for full flag details. All commands support `--jso
115
119
  | `cup tag-create <spaceId> <name> [--fg color] [--bg color]` | Create space tag |
116
120
  | `cup tag-update <spaceId> <tagName> --name <newName> [--fg c] [--bg c]` | Update space tag |
117
121
  | `cup tag-delete <spaceId> <name>` | Delete space tag |
122
+ | `cup list-from-template <name> --template <id> [--space id] [--folder id]` | Create list from template |
123
+ | `cup view-create <listId> <name> -t <type> [--group-by field]` | Create a view on a list |
124
+ | `cup view-update <viewId> [-n name] [--group-by field]` | Update a view |
125
+ | `cup view-delete <viewId> [--confirm]` | Delete a view (DESTRUCTIVE) |
118
126
  | `cup profile list [--json]` | List all profiles |
119
127
  | `cup profile add <name>` | Add a new profile (interactive) |
120
128
  | `cup profile remove <name>` | Remove a profile |