@krodak/clickup-cli 1.26.2 → 1.27.1

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.26.2",
4
+ "version": "1.27.1",
5
5
  "author": {
6
6
  "name": "Krzysztof Rodak"
7
7
  },
package/README.md CHANGED
@@ -175,6 +175,7 @@ Full CRUD for the core ClickUp workflow:
175
175
  | -------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
176
176
  | ✅ **Tasks** | Create, read, update, delete, duplicate, search, subtasks, assign, dependencies, links, multi-list, bulk operations (status, assign, due-date, tag, priority, field, move) |
177
177
  | 💬 **Comments** | Post, edit, delete by ID or by task scope for your own comments, threaded replies, notify all |
178
+ | 🗨️ **Chat** | List channels, send messages, replies, reactions, channel management |
178
179
  | 📄 **Docs** | List, read, create, edit, delete (v3 API) |
179
180
  | ⏱️ **Time Tracking** | Start/stop timer, log entries, list/update/delete history |
180
181
  | ☑️ **Checklists** | View, create, delete, add/edit/delete items |
package/dist/index.js CHANGED
@@ -837,6 +837,147 @@ var ClickUpClient = class {
837
837
  );
838
838
  return data.data;
839
839
  }
840
+ chatChannelsPath(suffix = "") {
841
+ return `/workspaces/${this.teamId}/chat/channels${suffix}`;
842
+ }
843
+ chatMessagesPath(suffix = "") {
844
+ return `/workspaces/${this.teamId}/chat/messages${suffix}`;
845
+ }
846
+ async getChatChannels(opts) {
847
+ const params = new URLSearchParams();
848
+ if (opts?.isFollower != null) params.set("is_follower", String(opts.isFollower));
849
+ if (opts?.includeClosed != null) params.set("include_closed", String(opts.includeClosed));
850
+ if (opts?.channelTypes) params.set("channel_types", opts.channelTypes);
851
+ if (opts?.limit != null) params.set("limit", String(opts.limit));
852
+ const query = params.toString();
853
+ const path = this.chatChannelsPath(query ? `?${query}` : "");
854
+ const data = await this.requestV3(path);
855
+ return expectArrayField(data, "data", "chat channels");
856
+ }
857
+ async getChatChannel(channelId) {
858
+ const data = await this.requestV3(this.chatChannelsPath(`/${channelId}`));
859
+ return expectRecordField(data, "data", "chat channel");
860
+ }
861
+ async createChatChannel(name, opts) {
862
+ const body = { name };
863
+ if (opts?.visibility) body.visibility = opts.visibility;
864
+ if (opts?.topic) body.topic = opts.topic;
865
+ if (opts?.userIds) body.user_ids = opts.userIds;
866
+ return this.requestV3(this.chatChannelsPath(), {
867
+ method: "POST",
868
+ body: JSON.stringify(body)
869
+ });
870
+ }
871
+ async createDirectMessage(userIds) {
872
+ const body = {};
873
+ if (userIds) body.user_ids = userIds;
874
+ return this.requestV3(this.chatChannelsPath("/direct_message"), {
875
+ method: "POST",
876
+ body: JSON.stringify(body)
877
+ });
878
+ }
879
+ async createLocationChannel(location, opts) {
880
+ const body = { location };
881
+ if (opts?.description) body.description = opts.description;
882
+ if (opts?.topic) body.topic = opts.topic;
883
+ if (opts?.visibility) body.visibility = opts.visibility;
884
+ if (opts?.userIds) body.user_ids = opts.userIds;
885
+ return this.requestV3(this.chatChannelsPath("/location"), {
886
+ method: "POST",
887
+ body: JSON.stringify(body)
888
+ });
889
+ }
890
+ async updateChatChannel(channelId, opts) {
891
+ return this.requestV3(this.chatChannelsPath(`/${channelId}`), {
892
+ method: "PATCH",
893
+ body: JSON.stringify(opts)
894
+ });
895
+ }
896
+ async deleteChatChannel(channelId) {
897
+ await this.requestV3(this.chatChannelsPath(`/${channelId}`), {
898
+ method: "DELETE"
899
+ });
900
+ }
901
+ async getChatChannelMembers(channelId, limit) {
902
+ const params = new URLSearchParams();
903
+ if (limit != null) params.set("limit", String(limit));
904
+ const query = params.toString();
905
+ const path = this.chatChannelsPath(`/${channelId}/members${query ? `?${query}` : ""}`);
906
+ const data = await this.requestV3(path);
907
+ return expectArrayField(data, "data", "chat channel members");
908
+ }
909
+ async getChatChannelFollowers(channelId, limit) {
910
+ const params = new URLSearchParams();
911
+ if (limit != null) params.set("limit", String(limit));
912
+ const query = params.toString();
913
+ const path = this.chatChannelsPath(`/${channelId}/followers${query ? `?${query}` : ""}`);
914
+ const data = await this.requestV3(path);
915
+ return expectArrayField(data, "data", "chat channel followers");
916
+ }
917
+ async getChatMessages(channelId, opts) {
918
+ const params = new URLSearchParams();
919
+ if (opts?.limit != null) params.set("limit", String(opts.limit));
920
+ const query = params.toString();
921
+ const path = this.chatChannelsPath(`/${channelId}/messages${query ? `?${query}` : ""}`);
922
+ const data = await this.requestV3(path);
923
+ return expectArrayField(data, "data", "chat messages");
924
+ }
925
+ async sendChatMessage(channelId, content, opts) {
926
+ const msgType = opts?.type ?? "message";
927
+ const body = {
928
+ type: msgType,
929
+ content,
930
+ content_format: "text/md"
931
+ };
932
+ if (opts?.postTitle) body.post_data = { title: opts.postTitle };
933
+ return this.requestV3(this.chatChannelsPath(`/${channelId}/messages`), {
934
+ method: "POST",
935
+ body: JSON.stringify(body)
936
+ });
937
+ }
938
+ async updateChatMessage(messageId, content) {
939
+ return this.requestV3(this.chatMessagesPath(`/${messageId}`), {
940
+ method: "PATCH",
941
+ body: JSON.stringify({ content, content_format: "text/md" })
942
+ });
943
+ }
944
+ async deleteChatMessage(messageId) {
945
+ await this.requestV3(this.chatMessagesPath(`/${messageId}`), {
946
+ method: "DELETE"
947
+ });
948
+ }
949
+ async getChatMessageReplies(messageId, opts) {
950
+ const params = new URLSearchParams();
951
+ if (opts?.limit != null) params.set("limit", String(opts.limit));
952
+ const query = params.toString();
953
+ const path = this.chatMessagesPath(`/${messageId}/replies${query ? `?${query}` : ""}`);
954
+ const data = await this.requestV3(path);
955
+ return expectArrayField(data, "data", "chat message replies");
956
+ }
957
+ async createChatMessageReply(messageId, content) {
958
+ return this.requestV3(this.chatMessagesPath(`/${messageId}/replies`), {
959
+ method: "POST",
960
+ body: JSON.stringify({ type: "message", content, content_format: "text/md" })
961
+ });
962
+ }
963
+ async getChatMessageReactions(messageId) {
964
+ const data = await this.requestV3(
965
+ this.chatMessagesPath(`/${messageId}/reactions`)
966
+ );
967
+ return expectArrayField(data, "data", "chat message reactions");
968
+ }
969
+ async createChatMessageReaction(messageId, emoji) {
970
+ return this.requestV3(this.chatMessagesPath(`/${messageId}/reactions`), {
971
+ method: "POST",
972
+ body: JSON.stringify({ reaction: emoji })
973
+ });
974
+ }
975
+ async deleteChatMessageReaction(messageId, emoji) {
976
+ await this.requestV3(
977
+ this.chatMessagesPath(`/${messageId}/reactions/${emoji}`),
978
+ { method: "DELETE" }
979
+ );
980
+ }
840
981
  };
841
982
 
842
983
  // src/config.ts
@@ -1700,12 +1841,12 @@ async function groupedTaskPicker(groups) {
1700
1841
  }
1701
1842
  async function showDetailsAndOpen(tasks, fetchTask) {
1702
1843
  if (tasks.length === 0) return;
1703
- const separator = chalk2.dim("\u2500".repeat(60));
1844
+ const separator2 = chalk2.dim("\u2500".repeat(60));
1704
1845
  for (let i = 0; i < tasks.length; i++) {
1705
1846
  const task = tasks[i];
1706
1847
  if (i > 0) {
1707
1848
  console.log("");
1708
- console.log(separator);
1849
+ console.log(separator2);
1709
1850
  }
1710
1851
  console.log("");
1711
1852
  if (fetchTask) {
@@ -2735,10 +2876,10 @@ function printComments(comments, forceJson) {
2735
2876
  console.log("No comments found.");
2736
2877
  return;
2737
2878
  }
2738
- const separator = chalk4.dim("-".repeat(60));
2879
+ const separator2 = chalk4.dim("-".repeat(60));
2739
2880
  for (let i = 0; i < comments.length; i++) {
2740
2881
  const c = comments[i];
2741
- if (i > 0) console.log(separator);
2882
+ if (i > 0) console.log(separator2);
2742
2883
  console.log(`${chalk4.bold(c.user)} ${chalk4.dim(formatTimestamp(c.date))}`);
2743
2884
  console.log(c.text);
2744
2885
  if (i < comments.length - 1) console.log("");
@@ -4253,6 +4394,89 @@ var commandMetadata = [
4253
4394
  { section: "read", usage: "favorite list", description: "List saved favorites" }
4254
4395
  ]
4255
4396
  },
4397
+ {
4398
+ name: "chat",
4399
+ description: "Chat channels and messaging",
4400
+ quickReference: [
4401
+ { section: "read", usage: "chat channels", description: "List chat channels you follow" },
4402
+ {
4403
+ section: "read",
4404
+ usage: "chat channel <channelId>",
4405
+ description: "Show channel details"
4406
+ },
4407
+ {
4408
+ section: "write",
4409
+ usage: "chat send <channelId>",
4410
+ description: "Send a message to a channel"
4411
+ },
4412
+ {
4413
+ section: "read",
4414
+ usage: "chat messages <channelId>",
4415
+ description: "List recent messages in a channel"
4416
+ },
4417
+ {
4418
+ section: "write",
4419
+ usage: "chat channel-create <name>",
4420
+ description: "Create a new chat channel"
4421
+ },
4422
+ { section: "write", usage: "chat dm <userIds...>", description: "Create or open a DM" },
4423
+ {
4424
+ section: "write",
4425
+ usage: "chat channel-update <channelId>",
4426
+ description: "Update a channel"
4427
+ },
4428
+ {
4429
+ section: "write",
4430
+ usage: "chat channel-delete <channelId>",
4431
+ description: "Delete a channel"
4432
+ },
4433
+ {
4434
+ section: "read",
4435
+ usage: "chat members <channelId>",
4436
+ description: "List channel members"
4437
+ },
4438
+ {
4439
+ section: "read",
4440
+ usage: "chat followers <channelId>",
4441
+ description: "List channel followers"
4442
+ },
4443
+ {
4444
+ section: "write",
4445
+ usage: "chat reply <messageId>",
4446
+ description: "Reply to a message"
4447
+ },
4448
+ {
4449
+ section: "read",
4450
+ usage: "chat replies <messageId>",
4451
+ description: "List replies to a message"
4452
+ },
4453
+ {
4454
+ section: "write",
4455
+ usage: "chat react <messageId>",
4456
+ description: "Add a reaction to a message"
4457
+ },
4458
+ {
4459
+ section: "write",
4460
+ usage: "chat unreact <messageId>",
4461
+ description: "Remove a reaction from a message"
4462
+ },
4463
+ {
4464
+ section: "read",
4465
+ usage: "chat reactions <messageId>",
4466
+ description: "List reactions on a message"
4467
+ },
4468
+ {
4469
+ section: "write",
4470
+ usage: "chat message-update <messageId>",
4471
+ description: "Edit a message"
4472
+ },
4473
+ {
4474
+ section: "write",
4475
+ usage: "chat message-delete <messageId>",
4476
+ description: "Delete a message"
4477
+ }
4478
+ ]
4479
+ },
4256
4480
  {
4257
4481
  name: "profile",
4258
4482
  description: "Manage profiles",
@@ -4324,7 +4548,8 @@ var bashSpecialCaseCommands = /* @__PURE__ */ new Set([
4324
4548
  "favorite",
4325
4549
  "config",
4326
4550
  "profile",
4327
- "completion"
4551
+ "completion",
4552
+ "chat"
4328
4553
  ]);
4329
4554
  function escapeSingleQuotes(value) {
4330
4555
  return value.replaceAll("'", "'\\''");
@@ -4447,6 +4672,11 @@ ${renderBashCommandCases()}
4447
4672
  esac
4448
4673
  fi
4449
4674
  ;;
4675
+ chat)
4676
+ if [[ $cword -eq 2 ]]; then
4677
+ COMPREPLY=($(compgen -W "channels channel send messages reply replies react unreact reactions channel-create dm channel-update channel-delete members followers message-update message-delete" -- "$cur"))
4678
+ fi
4679
+ ;;
4450
4680
  completion)
4451
4681
  COMPREPLY=($(compgen -W "bash zsh fish" -- "$cur"))
4452
4682
  ;;
@@ -5236,6 +5466,133 @@ ${renderZshTopLevelCommands(name)}
5236
5466
  ;;
5237
5467
  esac
5238
5468
  ;;
5469
+ chat)
5470
+ local -a chat_cmds
5471
+ chat_cmds=(
5472
+ 'channels:List chat channels'
5473
+ 'channel:Show channel details'
5474
+ 'send:Send a message to a channel'
5475
+ 'messages:List recent messages in a channel'
5476
+ 'reply:Reply to a message'
5477
+ 'replies:List replies to a message'
5478
+ 'react:Add a reaction to a message'
5479
+ 'unreact:Remove a reaction from a message'
5480
+ 'reactions:List reactions on a message'
5481
+ 'channel-create:Create a new chat channel'
5482
+ 'dm:Create or open a direct message'
5483
+ 'channel-update:Update a channel'
5484
+ 'channel-delete:Delete a channel'
5485
+ 'members:List channel members'
5486
+ 'followers:List channel followers'
5487
+ 'message-update:Edit a message'
5488
+ 'message-delete:Delete a message'
5489
+ )
5490
+ _arguments -C \\
5491
+ '1:chat command:->chat_cmd' \\
5492
+ '*::chat_arg:->chat_args'
5493
+ case $state in
5494
+ chat_cmd)
5495
+ _describe 'chat command' chat_cmds
5496
+ ;;
5497
+ chat_args)
5498
+ case $words[1] in
5499
+ channels)
5500
+ _arguments \\
5501
+ '--all[List all channels, not just followed]' \\
5502
+ '--type[Filter by type]:type:(channel dm group_dm)' \\
5503
+ '--json[Force JSON output]'
5504
+ ;;
5505
+ channel)
5506
+ _arguments '1:channel_id:' '--json[Force JSON output]'
5507
+ ;;
5508
+ send)
5509
+ _arguments \\
5510
+ '1:channel_id:' \\
5511
+ '(-m --message)'{-m,--message}'[Message content]:text:' \\
5512
+ '--post[Send as a post]' \\
5513
+ '--title[Post title]:text:' \\
5514
+ '--json[Force JSON output]'
5515
+ ;;
5516
+ messages)
5517
+ _arguments \\
5518
+ '1:channel_id:' \\
5519
+ '--limit[Max messages]:number:' \\
5520
+ '--json[Force JSON output]'
5521
+ ;;
5522
+ reply)
5523
+ _arguments \\
5524
+ '1:message_id:' \\
5525
+ '(-m --message)'{-m,--message}'[Reply content]:text:' \\
5526
+ '--json[Force JSON output]'
5527
+ ;;
5528
+ replies)
5529
+ _arguments \\
5530
+ '1:message_id:' \\
5531
+ '--limit[Max replies]:number:' \\
5532
+ '--json[Force JSON output]'
5533
+ ;;
5534
+ react)
5535
+ _arguments \\
5536
+ '1:message_id:' \\
5537
+ '--emoji[Emoji name]:emoji:' \\
5538
+ '--json[Force JSON output]'
5539
+ ;;
5540
+ unreact)
5541
+ _arguments \\
5542
+ '1:message_id:' \\
5543
+ '--emoji[Emoji name to remove]:emoji:' \\
5544
+ '--json[Force JSON output]'
5545
+ ;;
5546
+ reactions)
5547
+ _arguments '1:message_id:' '--json[Force JSON output]'
5548
+ ;;
5549
+ channel-create)
5550
+ _arguments \\
5551
+ '1:name:' \\
5552
+ '--private[Create as private channel]' \\
5553
+ '--topic[Channel topic]:text:' \\
5554
+ '--space[Create on a space]:space_id:' \\
5555
+ '--folder[Create on a folder]:folder_id:' \\
5556
+ '--list[Create on a list]:list_id:' \\
5557
+ '--json[Force JSON output]'
5558
+ ;;
5559
+ dm)
5560
+ _arguments '*:user_ids:' '--json[Force JSON output]'
5561
+ ;;
5562
+ channel-update)
5563
+ _arguments \\
5564
+ '1:channel_id:' \\
5565
+ '--name[New name]:text:' \\
5566
+ '--topic[New topic]:text:' \\
5567
+ '--description[New description]:text:' \\
5568
+ '--visibility[PUBLIC or PRIVATE]:visibility:(PUBLIC PRIVATE)' \\
5569
+ '--json[Force JSON output]'
5570
+ ;;
5571
+ channel-delete)
5572
+ _arguments \\
5573
+ '1:channel_id:' \\
5574
+ '--confirm[Skip confirmation prompt]' \\
5575
+ '--json[Force JSON output]'
5576
+ ;;
5577
+ members|followers)
5578
+ _arguments '1:channel_id:' '--json[Force JSON output]'
5579
+ ;;
5580
+ message-update)
5581
+ _arguments \\
5582
+ '1:message_id:' \\
5583
+ '(-m --message)'{-m,--message}'[New message content]:text:' \\
5584
+ '--json[Force JSON output]'
5585
+ ;;
5586
+ message-delete)
5587
+ _arguments \\
5588
+ '1:message_id:' \\
5589
+ '--confirm[Skip confirmation prompt]' \\
5590
+ '--json[Force JSON output]'
5591
+ ;;
5592
+ esac
5593
+ ;;
5594
+ esac
5595
+ ;;
5239
5596
  completion)
5240
5597
  _arguments '1:shell:(bash zsh fish)'
5241
5598
  ;;
@@ -5304,6 +5661,47 @@ complete -c ${name} -n '__fish_seen_subcommand_from assign; and __fish_seen_subc
5304
5661
  complete -c ${name} -n '__fish_seen_subcommand_from tag; and __fish_seen_subcommand_from bulk' -l add -d 'Add tag'
5305
5662
  complete -c ${name} -n '__fish_seen_subcommand_from tag; and __fish_seen_subcommand_from bulk' -l remove -d 'Remove tag'
5306
5663
 
5664
+ complete -c ${name} -n '__fish_seen_subcommand_from chat; and not __fish_seen_subcommand_from channels channel send messages reply replies react unreact reactions channel-create dm channel-update channel-delete members followers message-update message-delete' -a channels -d 'List chat channels'
5665
+ complete -c ${name} -n '__fish_seen_subcommand_from chat; and not __fish_seen_subcommand_from channels channel send messages reply replies react unreact reactions channel-create dm channel-update channel-delete members followers message-update message-delete' -a channel -d 'Show channel details'
5666
+ complete -c ${name} -n '__fish_seen_subcommand_from chat; and not __fish_seen_subcommand_from channels channel send messages reply replies react unreact reactions channel-create dm channel-update channel-delete members followers message-update message-delete' -a send -d 'Send a message to a channel'
5667
+ complete -c ${name} -n '__fish_seen_subcommand_from chat; and not __fish_seen_subcommand_from channels channel send messages reply replies react unreact reactions channel-create dm channel-update channel-delete members followers message-update message-delete' -a messages -d 'List recent messages'
5668
+ complete -c ${name} -n '__fish_seen_subcommand_from chat; and not __fish_seen_subcommand_from channels channel send messages reply replies react unreact reactions channel-create dm channel-update channel-delete members followers message-update message-delete' -a reply -d 'Reply to a message'
5669
+ complete -c ${name} -n '__fish_seen_subcommand_from chat; and not __fish_seen_subcommand_from channels channel send messages reply replies react unreact reactions channel-create dm channel-update channel-delete members followers message-update message-delete' -a replies -d 'List replies to a message'
5670
+ complete -c ${name} -n '__fish_seen_subcommand_from chat; and not __fish_seen_subcommand_from channels channel send messages reply replies react unreact reactions channel-create dm channel-update channel-delete members followers message-update message-delete' -a react -d 'Add a reaction'
5671
+ complete -c ${name} -n '__fish_seen_subcommand_from chat; and not __fish_seen_subcommand_from channels channel send messages reply replies react unreact reactions channel-create dm channel-update channel-delete members followers message-update message-delete' -a unreact -d 'Remove a reaction'
5672
+ complete -c ${name} -n '__fish_seen_subcommand_from chat; and not __fish_seen_subcommand_from channels channel send messages reply replies react unreact reactions channel-create dm channel-update channel-delete members followers message-update message-delete' -a reactions -d 'List reactions'
5673
+ complete -c ${name} -n '__fish_seen_subcommand_from chat; and not __fish_seen_subcommand_from channels channel send messages reply replies react unreact reactions channel-create dm channel-update channel-delete members followers message-update message-delete' -a channel-create -d 'Create a channel'
5674
+ complete -c ${name} -n '__fish_seen_subcommand_from chat; and not __fish_seen_subcommand_from channels channel send messages reply replies react unreact reactions channel-create dm channel-update channel-delete members followers message-update message-delete' -a dm -d 'Create or open a DM'
5675
+ complete -c ${name} -n '__fish_seen_subcommand_from chat; and not __fish_seen_subcommand_from channels channel send messages reply replies react unreact reactions channel-create dm channel-update channel-delete members followers message-update message-delete' -a channel-update -d 'Update a channel'
5676
+ complete -c ${name} -n '__fish_seen_subcommand_from chat; and not __fish_seen_subcommand_from channels channel send messages reply replies react unreact reactions channel-create dm channel-update channel-delete members followers message-update message-delete' -a channel-delete -d 'Delete a channel'
5677
+ complete -c ${name} -n '__fish_seen_subcommand_from chat; and not __fish_seen_subcommand_from channels channel send messages reply replies react unreact reactions channel-create dm channel-update channel-delete members followers message-update message-delete' -a members -d 'List channel members'
5678
+ complete -c ${name} -n '__fish_seen_subcommand_from chat; and not __fish_seen_subcommand_from channels channel send messages reply replies react unreact reactions channel-create dm channel-update channel-delete members followers message-update message-delete' -a followers -d 'List channel followers'
5679
+ complete -c ${name} -n '__fish_seen_subcommand_from chat; and not __fish_seen_subcommand_from channels channel send messages reply replies react unreact reactions channel-create dm channel-update channel-delete members followers message-update message-delete' -a message-update -d 'Edit a message'
5680
+ complete -c ${name} -n '__fish_seen_subcommand_from chat; and not __fish_seen_subcommand_from channels channel send messages reply replies react unreact reactions channel-create dm channel-update channel-delete members followers message-update message-delete' -a message-delete -d 'Delete a message'
5681
+ complete -c ${name} -n '__fish_seen_subcommand_from channels channel send messages reply replies react unreact reactions channel-create dm channel-update channel-delete members followers message-update message-delete; and __fish_seen_subcommand_from chat' -l json -d 'Force JSON output'
5682
+ complete -c ${name} -n '__fish_seen_subcommand_from channels; and __fish_seen_subcommand_from chat' -l all -d 'List all channels'
5683
+ complete -c ${name} -n '__fish_seen_subcommand_from channels; and __fish_seen_subcommand_from chat' -l type -d 'Filter by type'
5684
+ complete -c ${name} -n '__fish_seen_subcommand_from send; and __fish_seen_subcommand_from chat' -s m -l message -d 'Message content'
5685
+ complete -c ${name} -n '__fish_seen_subcommand_from send; and __fish_seen_subcommand_from chat' -l post -d 'Send as a post'
5686
+ complete -c ${name} -n '__fish_seen_subcommand_from send; and __fish_seen_subcommand_from chat' -l title -d 'Post title'
5687
+ complete -c ${name} -n '__fish_seen_subcommand_from messages; and __fish_seen_subcommand_from chat' -l limit -d 'Max messages'
5688
+ complete -c ${name} -n '__fish_seen_subcommand_from reply; and __fish_seen_subcommand_from chat' -s m -l message -d 'Reply content'
5689
+ complete -c ${name} -n '__fish_seen_subcommand_from replies; and __fish_seen_subcommand_from chat' -l limit -d 'Max replies'
5690
+ complete -c ${name} -n '__fish_seen_subcommand_from react; and __fish_seen_subcommand_from chat' -l emoji -d 'Emoji name'
5691
+ complete -c ${name} -n '__fish_seen_subcommand_from unreact; and __fish_seen_subcommand_from chat' -l emoji -d 'Emoji name to remove'
5692
+ complete -c ${name} -n '__fish_seen_subcommand_from channel-create; and __fish_seen_subcommand_from chat' -l private -d 'Create as private'
5693
+ complete -c ${name} -n '__fish_seen_subcommand_from channel-create; and __fish_seen_subcommand_from chat' -l topic -d 'Channel topic'
5694
+ complete -c ${name} -n '__fish_seen_subcommand_from channel-create; and __fish_seen_subcommand_from chat' -l space -d 'Create on a space'
5695
+ complete -c ${name} -n '__fish_seen_subcommand_from channel-create; and __fish_seen_subcommand_from chat' -l folder -d 'Create on a folder'
5696
+ complete -c ${name} -n '__fish_seen_subcommand_from channel-create; and __fish_seen_subcommand_from chat' -l list -d 'Create on a list'
5697
+ complete -c ${name} -n '__fish_seen_subcommand_from channel-update; and __fish_seen_subcommand_from chat' -l name -d 'New name'
5698
+ complete -c ${name} -n '__fish_seen_subcommand_from channel-update; and __fish_seen_subcommand_from chat' -l topic -d 'New topic'
5699
+ complete -c ${name} -n '__fish_seen_subcommand_from channel-update; and __fish_seen_subcommand_from chat' -l description -d 'New description'
5700
+ complete -c ${name} -n '__fish_seen_subcommand_from channel-update; and __fish_seen_subcommand_from chat' -l visibility -d 'PUBLIC or PRIVATE'
5701
+ complete -c ${name} -n '__fish_seen_subcommand_from channel-delete; and __fish_seen_subcommand_from chat' -l confirm -d 'Skip confirmation'
5702
+ complete -c ${name} -n '__fish_seen_subcommand_from message-update; and __fish_seen_subcommand_from chat' -s m -l message -d 'New message content'
5703
+ complete -c ${name} -n '__fish_seen_subcommand_from message-delete; and __fish_seen_subcommand_from chat' -l confirm -d 'Skip confirmation'
5704
+
5307
5705
  complete -c ${name} -n '__fish_seen_subcommand_from profile; and not __fish_seen_subcommand_from list add remove use' -a list -d 'List all profiles'
5308
5706
  complete -c ${name} -n '__fish_seen_subcommand_from profile; and not __fish_seen_subcommand_from list add remove use' -a add -d 'Add a new profile'
5309
5707
  complete -c ${name} -n '__fish_seen_subcommand_from profile; and not __fish_seen_subcommand_from list add remove use' -a remove -d 'Remove a profile'
@@ -6652,21 +7050,193 @@ function formatViewsMarkdown(views) {
6652
7050
  return views.map((v) => `- **${v.name}** (${v.id}) - ${v.type}`).join("\n");
6653
7051
  }
6654
7052
 
6655
- // src/commands/view.ts
7053
+ // src/commands/chat.ts
6656
7054
  import chalk22 from "chalk";
7055
+ function channelName(c) {
7056
+ return c.name || "DM";
7057
+ }
7058
+ function colorChannelType(type) {
7059
+ if (type === "CHANNEL") return chalk22.cyan(type);
7060
+ if (type === "DM") return chalk22.dim(type);
7061
+ if (type === "GROUP_DM") return chalk22.blue(type);
7062
+ return type;
7063
+ }
7064
+ function colorVisibility(v) {
7065
+ if (v === "PUBLIC") return chalk22.green(v);
7066
+ return chalk22.dim(v);
7067
+ }
7068
+ var CHANNEL_COLUMNS = [
7069
+ { key: "name", label: "Name", maxWidth: 40, format: (v) => chalk22.bold(v) },
7070
+ { key: "id", label: "ID", maxWidth: 20, format: (v) => chalk22.dim(v) },
7071
+ { key: "type", label: "Type", maxWidth: 12, format: (v) => colorChannelType(v) },
7072
+ { key: "visibility", label: "Visibility", maxWidth: 10, format: (v) => colorVisibility(v) },
7073
+ { key: "topic", label: "Topic", maxWidth: 40 }
7074
+ ];
7075
+ function formatChannelsTable(channels) {
7076
+ if (channels.length === 0) return "No channels found";
7077
+ const rows = channels.map((c) => ({
7078
+ id: c.id,
7079
+ name: channelName(c),
7080
+ type: c.type,
7081
+ visibility: c.visibility,
7082
+ topic: c.topic ?? ""
7083
+ }));
7084
+ return formatTable(rows, CHANNEL_COLUMNS);
7085
+ }
7086
+ function formatChannelsMarkdown(channels) {
7087
+ if (channels.length === 0) return "No channels found";
7088
+ return channels.map((c) => {
7089
+ const name = channelName(c);
7090
+ return `- **${name}** (${c.id}) \u2014 ${c.type}${c.topic ? `, ${c.topic}` : ""}`;
7091
+ }).join("\n");
7092
+ }
7093
+ function formatChannelDetail(channel) {
7094
+ const lines = [];
7095
+ lines.push(chalk22.bold.underline(channelName(channel)));
7096
+ lines.push("");
7097
+ const fields = [
7098
+ ["ID", chalk22.dim(channel.id)],
7099
+ ["Type", colorChannelType(channel.type)],
7100
+ ["Visibility", colorVisibility(channel.visibility)]
7101
+ ];
7102
+ if (channel.topic) fields.push(["Topic", channel.topic]);
7103
+ if (channel.description) fields.push(["Description", channel.description]);
7104
+ fields.push(["Archived", channel.archived ? chalk22.yellow("Yes") : "No"]);
7105
+ fields.push(["Created", formatDate(channel.created_at)]);
7106
+ const maxLabel = Math.max(...fields.map(([k]) => k.length));
7107
+ for (const [label, value] of fields) {
7108
+ lines.push(` ${chalk22.bold(label.padEnd(maxLabel + 1))} ${value}`);
7109
+ }
7110
+ return lines.join("\n");
7111
+ }
7112
+ var CHAT_MEMBER_COLUMNS = [
7113
+ { key: "name", label: "Name", maxWidth: 30, format: (v) => chalk22.bold(v) },
7114
+ { key: "id", label: "ID", maxWidth: 15, format: (v) => chalk22.dim(v) },
7115
+ { key: "email", label: "Email", maxWidth: 40 },
7116
+ { key: "type", label: "Type", maxWidth: 12 }
7117
+ ];
7118
+ function formatChatMembers(members) {
7119
+ if (members.length === 0) return "No members found";
7120
+ const rows = members.map((m) => ({
7121
+ name: m.user.username ?? m.user.name ?? m.user.id,
7122
+ id: m.user.id,
7123
+ email: m.user.email,
7124
+ type: m.type
7125
+ }));
7126
+ return formatTable(rows, CHAT_MEMBER_COLUMNS);
7127
+ }
7128
+ function formatChatMembersMarkdown(members) {
7129
+ if (members.length === 0) return "No members found";
7130
+ return members.map((m) => {
7131
+ const name = m.user.username ?? m.user.name ?? m.user.id;
7132
+ return `- **${name}** (${m.user.id}) \u2014 ${m.user.email}`;
7133
+ }).join("\n");
7134
+ }
7135
+
7136
+ // src/commands/chat-message.ts
7137
+ import chalk23 from "chalk";
7138
+ var separator = chalk23.dim("-".repeat(60));
7139
+ function formatMessages(messages) {
7140
+ if (messages.length === 0) return "No messages";
7141
+ const lines = [];
7142
+ for (let i = 0; i < messages.length; i++) {
7143
+ const msg = messages[i];
7144
+ if (i > 0) lines.push(separator);
7145
+ const meta = [chalk23.bold(`@${msg.user_id}`), chalk23.dim(formatTimestamp(msg.date))];
7146
+ if (msg.replies_count) {
7147
+ meta.push(chalk23.dim(`${msg.replies_count} replies`));
7148
+ }
7149
+ meta.push(chalk23.dim(`(${msg.id})`));
7150
+ lines.push(meta.join(" "));
7151
+ if (msg.type === "post" && msg.post_data?.title) {
7152
+ lines.push(chalk23.cyan.bold(msg.post_data.title));
7153
+ }
7154
+ lines.push(msg.content);
7155
+ }
7156
+ return lines.join("\n");
7157
+ }
7158
+ function formatMessagesMarkdown(messages) {
7159
+ if (messages.length === 0) return "No messages";
7160
+ return messages.map((msg) => {
7161
+ const date = new Date(msg.date).toISOString();
7162
+ const title = msg.type === "post" && msg.post_data?.title ? ` \u2014 **${msg.post_data.title}**` : "";
7163
+ return `### @${msg.user_id} (${msg.id})${title}
7164
+ _${date}_
7165
+
7166
+ ${msg.content}`;
7167
+ }).join("\n\n---\n\n");
7168
+ }
7169
+
7170
+ // src/commands/chat-reaction.ts
7171
+ import chalk24 from "chalk";
7172
+ var EMOJI_MAP = {
7173
+ thumbsup: "\u{1F44D}",
7174
+ thumbsdown: "\u{1F44E}",
7175
+ heart: "\u2764\uFE0F",
7176
+ fire: "\u{1F525}",
7177
+ eyes: "\u{1F440}",
7178
+ rocket: "\u{1F680}",
7179
+ tada: "\u{1F389}",
7180
+ check: "\u2705",
7181
+ x: "\u274C",
7182
+ warning: "\u26A0\uFE0F",
7183
+ laugh: "\u{1F602}",
7184
+ smile: "\u{1F60A}",
7185
+ thinking: "\u{1F914}",
7186
+ clap: "\u{1F44F}",
7187
+ pray: "\u{1F64F}",
7188
+ 100: "\u{1F4AF}",
7189
+ star: "\u2B50",
7190
+ wave: "\u{1F44B}"
7191
+ };
7192
+ function emojiChar(name) {
7193
+ return EMOJI_MAP[name] ?? `:${name}:`;
7194
+ }
7195
+ function groupByEmoji(reactions) {
7196
+ const groups = /* @__PURE__ */ new Map();
7197
+ for (const r of reactions) {
7198
+ const users = groups.get(r.reaction) ?? [];
7199
+ users.push(r.user_id);
7200
+ groups.set(r.reaction, users);
7201
+ }
7202
+ return groups;
7203
+ }
7204
+ function formatReactions(reactions) {
7205
+ if (reactions.length === 0) return "No reactions";
7206
+ const groups = groupByEmoji(reactions);
7207
+ const lines = [];
7208
+ for (const [emoji, users] of groups) {
7209
+ const icon = emojiChar(emoji);
7210
+ const userList = users.map((u) => chalk24.bold(`@${u}`)).join(", ");
7211
+ lines.push(`${icon} ${chalk24.dim(emoji)} ${chalk24.dim(`(${users.length})`)} \u2014 ${userList}`);
7212
+ }
7213
+ return lines.join("\n");
7214
+ }
7215
+ function formatReactionsMarkdown(reactions) {
7216
+ if (reactions.length === 0) return "No reactions";
7217
+ const groups = groupByEmoji(reactions);
7218
+ const lines = [];
7219
+ for (const [emoji, users] of groups) {
7220
+ lines.push(`- **:${emoji}:** ${users.join(", ")}`);
7221
+ }
7222
+ return lines.join("\n");
7223
+ }
7224
+
7225
+ // src/commands/view.ts
7226
+ import chalk25 from "chalk";
6657
7227
  async function getView(config, viewId) {
6658
7228
  const client = new ClickUpClient(config);
6659
7229
  return client.getView(viewId);
6660
7230
  }
6661
7231
  function formatView(view) {
6662
7232
  const lines = [];
6663
- lines.push(chalk22.bold.underline(view.name));
7233
+ lines.push(chalk25.bold.underline(view.name));
6664
7234
  lines.push("");
6665
- lines.push(` ${chalk22.bold("ID")} ${view.id}`);
6666
- lines.push(` ${chalk22.bold("Type")} ${view.type}`);
6667
- if (view.visibility) lines.push(` ${chalk22.bold("Visibility")} ${view.visibility}`);
6668
- if (view.date_created) lines.push(` ${chalk22.bold("Created")} ${formatDate(view.date_created)}`);
6669
- if (view.protected !== void 0) lines.push(` ${chalk22.bold("Protected")} ${view.protected}`);
7235
+ lines.push(` ${chalk25.bold("ID")} ${view.id}`);
7236
+ lines.push(` ${chalk25.bold("Type")} ${view.type}`);
7237
+ if (view.visibility) lines.push(` ${chalk25.bold("Visibility")} ${view.visibility}`);
7238
+ if (view.date_created) lines.push(` ${chalk25.bold("Created")} ${formatDate(view.date_created)}`);
7239
+ if (view.protected !== void 0) lines.push(` ${chalk25.bold("Protected")} ${view.protected}`);
6670
7240
  return lines.join("\n");
6671
7241
  }
6672
7242
  function formatViewMarkdown(view) {
@@ -8675,6 +9245,287 @@ function buildProgram(programName = basename(process.argv[1] ?? "cup")) {
8675
9245
  console.log(configPath2());
8676
9246
  })
8677
9247
  );
9248
+ const chatCmd = program.command("chat").description("Chat channels and messaging");
9249
+ chatCmd.command("channels").description("List chat channels you follow").option("--all", "List all channels, not just ones you follow").option("--type <type>", "Filter by type (channel, dm, group_dm)").option("--json", "Force JSON output even in terminal").action(
9250
+ wrapAction(async (opts) => {
9251
+ const config = loadConfig(getProfileName());
9252
+ const client = new ClickUpClient(config);
9253
+ const channels = await client.getChatChannels({
9254
+ isFollower: opts.all ? void 0 : true,
9255
+ channelTypes: opts.type
9256
+ });
9257
+ if (shouldOutputJson(opts.json ?? false)) {
9258
+ console.log(JSON.stringify(channels, null, 2));
9259
+ } else if (isTTY()) {
9260
+ console.log(formatChannelsTable(channels));
9261
+ } else {
9262
+ console.log(formatChannelsMarkdown(channels));
9263
+ }
9264
+ })
9265
+ );
9266
+ chatCmd.command("channel <channelId>").description("Show channel details").option("--json", "Force JSON output even in terminal").action(
9267
+ wrapAction(async (channelId, opts) => {
9268
+ const config = loadConfig(getProfileName());
9269
+ const client = new ClickUpClient(config);
9270
+ const channel = await client.getChatChannel(channelId);
9271
+ if (shouldOutputJson(opts.json ?? false)) {
9272
+ console.log(JSON.stringify(channel, null, 2));
9273
+ } else {
9274
+ console.log(formatChannelDetail(channel));
9275
+ }
9276
+ })
9277
+ );
9278
+ chatCmd.command("send <channelId>").description("Send a message to a channel").requiredOption("-m, --message <text>", "Message content (markdown supported)").option("--post", "Send as a post instead of a message").option("--title <title>", "Post title (requires --post)").option("--json", "Force JSON output even in terminal").action(
9279
+ wrapAction(
9280
+ async (channelId, opts) => {
9281
+ if (opts.title && !opts.post) {
9282
+ throw new Error("--title requires --post");
9283
+ }
9284
+ const config = loadConfig(getProfileName());
9285
+ const client = new ClickUpClient(config);
9286
+ const result = await client.sendChatMessage(channelId, opts.message, {
9287
+ type: opts.post ? "post" : "message",
9288
+ postTitle: opts.title
9289
+ });
9290
+ if (shouldOutputJson(opts.json ?? false)) {
9291
+ console.log(JSON.stringify(result, null, 2));
9292
+ } else {
9293
+ console.log(`Sent ${result.type} ${result.id} to channel ${channelId}`);
9294
+ }
9295
+ }
9296
+ )
9297
+ );
9298
+ chatCmd.command("messages <channelId>").description("List recent messages in a channel").option("--limit <n>", "Max messages to show (default: 25)").option("--json", "Force JSON output even in terminal").action(
9299
+ wrapAction(async (channelId, opts) => {
9300
+ const config = loadConfig(getProfileName());
9301
+ const client = new ClickUpClient(config);
9302
+ const limit = opts.limit ? Number(opts.limit) : 25;
9303
+ if (!Number.isFinite(limit) || limit <= 0) {
9304
+ throw new Error("--limit must be a positive number");
9305
+ }
9306
+ const messages = await client.getChatMessages(channelId, { limit });
9307
+ if (shouldOutputJson(opts.json ?? false)) {
9308
+ console.log(JSON.stringify(messages, null, 2));
9309
+ } else if (isTTY()) {
9310
+ console.log(formatMessages(messages));
9311
+ } else {
9312
+ console.log(formatMessagesMarkdown(messages));
9313
+ }
9314
+ })
9315
+ );
9316
+ chatCmd.command("channel-create <name>").description("Create a new chat channel").option("--private", "Create as private channel").option("--topic <topic>", "Channel topic").option("--space <spaceId>", "Create on a specific space").option("--folder <folderId>", "Create on a specific folder").option("--list <listId>", "Create on a specific list").option("--json", "Force JSON output even in terminal").action(
9317
+ wrapAction(
9318
+ async (name, opts) => {
9319
+ if (!name.trim()) throw new Error("Channel name cannot be empty");
9320
+ const config = loadConfig(getProfileName());
9321
+ const client = new ClickUpClient(config);
9322
+ let result;
9323
+ if (opts.space || opts.folder || opts.list) {
9324
+ const location = opts.space ? { id: opts.space, type: "space" } : opts.folder ? { id: opts.folder, type: "folder" } : { id: opts.list, type: "list" };
9325
+ result = await client.createLocationChannel(location, {
9326
+ topic: opts.topic,
9327
+ visibility: opts.private ? "PRIVATE" : void 0
9328
+ });
9329
+ } else {
9330
+ result = await client.createChatChannel(name, {
9331
+ visibility: opts.private ? "PRIVATE" : void 0,
9332
+ topic: opts.topic
9333
+ });
9334
+ }
9335
+ if (shouldOutputJson(opts.json ?? false)) {
9336
+ console.log(JSON.stringify(result, null, 2));
9337
+ } else {
9338
+ console.log(`Created channel "${result.name}" (${result.id})`);
9339
+ }
9340
+ }
9341
+ )
9342
+ );
9343
+ chatCmd.command("dm <userIds...>").description("Create or open a direct message").option("--json", "Force JSON output even in terminal").action(
9344
+ wrapAction(async (userIds, opts) => {
9345
+ const config = loadConfig(getProfileName());
9346
+ const client = new ClickUpClient(config);
9347
+ const result = await client.createDirectMessage(userIds);
9348
+ if (shouldOutputJson(opts.json ?? false)) {
9349
+ console.log(JSON.stringify(result, null, 2));
9350
+ } else {
9351
+ console.log(`DM channel: ${result.id}`);
9352
+ }
9353
+ })
9354
+ );
9355
+ chatCmd.command("channel-update <channelId>").description("Update a channel").option("--name <name>", "New name").option("--topic <topic>", "New topic").option("--description <desc>", "New description").option("--visibility <v>", "PUBLIC or PRIVATE").option("--json", "Force JSON output even in terminal").action(
9356
+ wrapAction(
9357
+ async (channelId, opts) => {
9358
+ const config = loadConfig(getProfileName());
9359
+ const client = new ClickUpClient(config);
9360
+ const result = await client.updateChatChannel(channelId, {
9361
+ name: opts.name,
9362
+ topic: opts.topic,
9363
+ description: opts.description,
9364
+ visibility: opts.visibility
9365
+ });
9366
+ if (shouldOutputJson(opts.json ?? false)) {
9367
+ console.log(JSON.stringify(result, null, 2));
9368
+ } else {
9369
+ console.log(`Updated channel "${result.name}" (${result.id})`);
9370
+ }
9371
+ }
9372
+ )
9373
+ );
9374
+ chatCmd.command("channel-delete <channelId>").description("Delete a channel").option("--confirm", "Skip confirmation prompt").option("--json", "Force JSON output even in terminal").action(
9375
+ wrapAction(async (channelId, opts) => {
9376
+ const config = loadConfig(getProfileName());
9377
+ const client = new ClickUpClient(config);
9378
+ if (!opts.confirm) {
9379
+ if (!isTTY()) {
9380
+ throw new Error("Destructive operation requires --confirm flag in non-interactive mode");
9381
+ }
9382
+ const channel = await client.getChatChannel(channelId);
9383
+ const { confirm: confirm3 } = await import("@inquirer/prompts");
9384
+ const confirmed = await confirm3({
9385
+ message: `Delete channel "${channel.name}"?`,
9386
+ default: false
9387
+ });
9388
+ if (!confirmed) throw new Error("Cancelled");
9389
+ }
9390
+ await client.deleteChatChannel(channelId);
9391
+ if (shouldOutputJson(opts.json ?? false)) {
9392
+ console.log(JSON.stringify({ success: true, channelId }, null, 2));
9393
+ } else {
9394
+ console.log(`Deleted channel ${channelId}`);
9395
+ }
9396
+ })
9397
+ );
9398
+ chatCmd.command("members <channelId>").description("List channel members").option("--json", "Force JSON output even in terminal").action(
9399
+ wrapAction(async (channelId, opts) => {
9400
+ const config = loadConfig(getProfileName());
9401
+ const client = new ClickUpClient(config);
9402
+ const members = await client.getChatChannelMembers(channelId);
9403
+ if (shouldOutputJson(opts.json ?? false)) {
9404
+ console.log(JSON.stringify(members, null, 2));
9405
+ } else if (isTTY()) {
9406
+ console.log(formatChatMembers(members));
9407
+ } else {
9408
+ console.log(formatChatMembersMarkdown(members));
9409
+ }
9410
+ })
9411
+ );
9412
+ chatCmd.command("followers <channelId>").description("List channel followers").option("--json", "Force JSON output even in terminal").action(
9413
+ wrapAction(async (channelId, opts) => {
9414
+ const config = loadConfig(getProfileName());
9415
+ const client = new ClickUpClient(config);
9416
+ const followers = await client.getChatChannelFollowers(channelId);
9417
+ if (shouldOutputJson(opts.json ?? false)) {
9418
+ console.log(JSON.stringify(followers, null, 2));
9419
+ } else if (isTTY()) {
9420
+ console.log(formatChatMembers(followers));
9421
+ } else {
9422
+ console.log(formatChatMembersMarkdown(followers));
9423
+ }
9424
+ })
9425
+ );
9426
+ chatCmd.command("reply <messageId>").description("Reply to a message").requiredOption("-m, --message <text>", "Reply content (markdown supported)").option("--json", "Force JSON output even in terminal").action(
9427
+ wrapAction(async (messageId, opts) => {
9428
+ const config = loadConfig(getProfileName());
9429
+ const client = new ClickUpClient(config);
9430
+ const result = await client.createChatMessageReply(messageId, opts.message);
9431
+ if (shouldOutputJson(opts.json ?? false)) {
9432
+ console.log(JSON.stringify(result, null, 2));
9433
+ } else {
9434
+ console.log(`Reply sent (id: ${result.id})`);
9435
+ }
9436
+ })
9437
+ );
9438
+ chatCmd.command("replies <messageId>").description("List replies to a message").option("--limit <n>", "Max replies (default: 50)").option("--json", "Force JSON output even in terminal").action(
9439
+ wrapAction(async (messageId, opts) => {
9440
+ const config = loadConfig(getProfileName());
9441
+ const client = new ClickUpClient(config);
9442
+ const limit = opts.limit ? Number(opts.limit) : void 0;
9443
+ if (opts.limit && (!Number.isFinite(limit) || (limit ?? 0) <= 0)) {
9444
+ throw new Error("--limit must be a positive number");
9445
+ }
9446
+ const replies = await client.getChatMessageReplies(messageId, { limit });
9447
+ if (shouldOutputJson(opts.json ?? false)) {
9448
+ console.log(JSON.stringify(replies, null, 2));
9449
+ } else if (isTTY()) {
9450
+ console.log(formatMessages(replies));
9451
+ } else {
9452
+ console.log(formatMessagesMarkdown(replies));
9453
+ }
9454
+ })
9455
+ );
9456
+ chatCmd.command("react <messageId>").description("Add a reaction to a message").requiredOption("--emoji <name>", 'Emoji name (e.g. "thumbsup", "heart")').option("--json", "Force JSON output even in terminal").action(
9457
+ wrapAction(async (messageId, opts) => {
9458
+ const config = loadConfig(getProfileName());
9459
+ const client = new ClickUpClient(config);
9460
+ const result = await client.createChatMessageReaction(messageId, opts.emoji);
9461
+ if (shouldOutputJson(opts.json ?? false)) {
9462
+ console.log(JSON.stringify(result, null, 2));
9463
+ } else {
9464
+ console.log(`Added :${opts.emoji}: reaction`);
9465
+ }
9466
+ })
9467
+ );
9468
+ chatCmd.command("unreact <messageId>").description("Remove a reaction from a message").requiredOption("--emoji <name>", "Emoji name to remove").option("--json", "Force JSON output even in terminal").action(
9469
+ wrapAction(async (messageId, opts) => {
9470
+ const config = loadConfig(getProfileName());
9471
+ const client = new ClickUpClient(config);
9472
+ await client.deleteChatMessageReaction(messageId, opts.emoji);
9473
+ if (shouldOutputJson(opts.json ?? false)) {
9474
+ console.log(JSON.stringify({ success: true, emoji: opts.emoji }, null, 2));
9475
+ } else {
9476
+ console.log(`Removed :${opts.emoji}: reaction`);
9477
+ }
9478
+ })
9479
+ );
9480
+ chatCmd.command("reactions <messageId>").description("List reactions on a message").option("--json", "Force JSON output even in terminal").action(
9481
+ wrapAction(async (messageId, opts) => {
9482
+ const config = loadConfig(getProfileName());
9483
+ const client = new ClickUpClient(config);
9484
+ const reactions = await client.getChatMessageReactions(messageId);
9485
+ if (shouldOutputJson(opts.json ?? false)) {
9486
+ console.log(JSON.stringify(reactions, null, 2));
9487
+ } else if (isTTY()) {
9488
+ console.log(formatReactions(reactions));
9489
+ } else {
9490
+ console.log(formatReactionsMarkdown(reactions));
9491
+ }
9492
+ })
9493
+ );
9494
+ chatCmd.command("message-update <messageId>").description("Edit a message").requiredOption("-m, --message <text>", "New message content").option("--json", "Force JSON output even in terminal").action(
9495
+ wrapAction(async (messageId, opts) => {
9496
+ const config = loadConfig(getProfileName());
9497
+ const client = new ClickUpClient(config);
9498
+ const result = await client.updateChatMessage(messageId, opts.message);
9499
+ if (shouldOutputJson(opts.json ?? false)) {
9500
+ console.log(JSON.stringify(result, null, 2));
9501
+ } else {
9502
+ console.log(`Message ${messageId} updated`);
9503
+ }
9504
+ })
9505
+ );
9506
+ chatCmd.command("message-delete <messageId>").description("Delete a message").option("--confirm", "Skip confirmation prompt").option("--json", "Force JSON output even in terminal").action(
9507
+ wrapAction(async (messageId, opts) => {
9508
+ const config = loadConfig(getProfileName());
9509
+ if (!opts.confirm) {
9510
+ if (!isTTY()) {
9511
+ throw new Error("Destructive operation requires --confirm flag in non-interactive mode");
9512
+ }
9513
+ const { confirm: confirm3 } = await import("@inquirer/prompts");
9514
+ const confirmed = await confirm3({
9515
+ message: `Delete message ${messageId}? This cannot be undone.`,
9516
+ default: false
9517
+ });
9518
+ if (!confirmed) throw new Error("Cancelled");
9519
+ }
9520
+ const client = new ClickUpClient(config);
9521
+ await client.deleteChatMessage(messageId);
9522
+ if (shouldOutputJson(opts.json ?? false)) {
9523
+ console.log(JSON.stringify({ success: true, id: messageId }, null, 2));
9524
+ } else {
9525
+ console.log(`Message ${messageId} deleted`);
9526
+ }
9527
+ })
9528
+ );
8678
9529
  program.command("completion <shell>").description("Output shell completion script (bash, zsh, fish)").action(
8679
9530
  wrapAction(async (shell) => {
8680
9531
  const script = generateCompletion(shell, programName);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@krodak/clickup-cli",
3
- "version": "1.26.2",
3
+ "version": "1.27.1",
4
4
  "description": "ClickUp CLI for AI agents and humans",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -3,11 +3,11 @@ name: clickup
3
3
  description: 'Use when managing ClickUp tasks, sprints, or comments via the `cup` CLI tool. Triggers: task queries, status updates, sprint tracking, creating subtasks, posting comments, threaded replies, 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, managing checklists, editing comments, task links, time tracking, attachments, file uploads, listing members, listing fields, duplicating tasks, bulk operations, goals, key results, saved filters, favorites.'
4
4
  ---
5
5
 
6
- # ClickUp CLI (`cup`) - skill version 1.26.2
6
+ # ClickUp CLI (`cup`) - skill version 1.27.1
7
7
 
8
8
  Reference for AI agents using the `cup` CLI tool. Covers task management, sprint tracking, comments, time tracking, custom fields, goals, docs, and project workflows.
9
9
 
10
- > **Version check:** Run `cup --version`. If your installed version is older than 1.26.2, update with `npm install -g @krodak/clickup-cli` and refresh this skill with `cup skill`.
10
+ > **Version check:** Run `cup --version`. If your installed version is older than 1.27.1, update with `npm install -g @krodak/clickup-cli` and refresh this skill with `cup skill`.
11
11
 
12
12
  ## Install & Configure
13
13
 
@@ -141,6 +141,13 @@ All commands support `--help` for full flag details. All commands support `--jso
141
141
  | `cup view <viewId>` | Get view details |
142
142
  | `cup open <query>` | Open task in browser by ID or name |
143
143
  | `cup auth` | Check authentication status |
144
+ | `cup chat channels [--all] [--type type]` | List chat channels |
145
+ | `cup chat channel <id>` | Show channel details |
146
+ | `cup chat messages <channelId> [--limit n]` | List channel messages |
147
+ | `cup chat members <channelId>` | List channel members |
148
+ | `cup chat followers <channelId>` | List channel followers |
149
+ | `cup chat replies <messageId>` | List message replies |
150
+ | `cup chat reactions <messageId>` | List reactions on a message |
144
151
 
145
152
  ### Write
146
153
 
@@ -207,6 +214,16 @@ All commands support `--help` for full flag details. All commands support `--jso
207
214
  | `cup view-create <listId> <name> -t <type> [--group-by field]` | Create a view on a list |
208
215
  | `cup view-update <viewId> [-n name] [--group-by field]` | Update a view |
209
216
  | `cup view-delete <viewId> [--confirm]` | Delete a view (DESTRUCTIVE) |
217
+ | `cup chat send <channelId> -m <text> [--post --title t]` | Send message to channel |
218
+ | `cup chat reply <messageId> -m <text>` | Reply to a message |
219
+ | `cup chat react <messageId> --emoji <name>` | Add reaction |
220
+ | `cup chat unreact <messageId> --emoji <name>` | Remove reaction |
221
+ | `cup chat channel-create <name> [--private] [--topic t]` | Create channel |
222
+ | `cup chat dm <userIds...>` | Create/open DM |
223
+ | `cup chat channel-update <id> [--name n] [--topic t]` | Update channel |
224
+ | `cup chat channel-delete <id> [--confirm]` | Delete channel |
225
+ | `cup chat message-update <messageId> -m <text>` | Edit message |
226
+ | `cup chat message-delete <messageId> [--confirm]` | Delete message |
210
227
  | `cup favorite add <type> <id> [alias] [-n name]` | Add a local favorite |
211
228
  | `cup favorite remove <alias>` | Remove a favorite |
212
229
  | `cup favorite list [--type t]` | List favorites (optionally filter by type) |