import { CLICKUP_COMMENT_SCHEMA } from "@automate.ax/integration-contracts/clickup" import * as z from "zod" import { defineAction } from "../../../automation/actions" import { CLICKUP_ACCOUNT, CLICKUP_ACCOUNT_REQUIREMENT, CLICKUP_ID_SCHEMA, CLICKUP_VOID_RESPONSE_SCHEMA, getClickUpApi, } from "./lib" const COMMENTS_RESPONSE_SCHEMA = z.object({ comments: CLICKUP_COMMENT_SCHEMA.array(), }) const COMMENT_PAGE_OUTPUT_SCHEMA = COMMENTS_RESPONSE_SCHEMA.extend({ pageInfo: z.object({ nextStart: z.string().optional(), nextStartId: z.string().optional(), }), }) const COMMENT_CREATED_SCHEMA = z.object({ date: z.number().int(), histId: z.string(), id: z.union([z.string(), z.number()]).transform(String), }) const COMMENT_WRITE_SCHEMA = z.object({ assignee: z.number().int().optional(), commentText: z.string().min(1), groupAssignee: CLICKUP_ID_SCHEMA.optional(), notifyAll: z.boolean().prefault(false), }) /** Lists task comments newest-first with ClickUp's paired cursor. */ export const listClickUpTaskComments = defineAction( "List ClickUp task comments", ) .describe("Lists task comments newest-first with paired cursor pagination.") .account(CLICKUP_ACCOUNT, CLICKUP_ACCOUNT_REQUIREMENT) .input( z .object({ start: z.string().regex(/^\d+$/).optional(), startId: CLICKUP_ID_SCHEMA.optional(), taskId: CLICKUP_ID_SCHEMA, }) .refine(({ start, startId }) => Boolean(start) === Boolean(startId), { message: "ClickUp comment pagination requires start and startId together.", }), ) .output(COMMENT_PAGE_OUTPUT_SCHEMA) .retry({ replaySafety: "safe" }) .handler(async ({ account, input }) => { const result = await getClickUpApi(account).request( `task/${input.taskId}/comment`, { query: { start: input.start, startId: input.startId }, responseSchema: COMMENTS_RESPONSE_SCHEMA, }, ) const last = result.comments.at(-1) return { comments: result.comments, pageInfo: { ...(last && { nextStart: last.date, nextStartId: last.id }), }, } }) /** Creates a comment on a ClickUp task. */ export const createClickUpTaskComment = defineAction( "Create ClickUp task comment", ) .describe("Creates a plain-text comment on a ClickUp task.") .account(CLICKUP_ACCOUNT, CLICKUP_ACCOUNT_REQUIREMENT) .input(COMMENT_WRITE_SCHEMA.extend({ taskId: CLICKUP_ID_SCHEMA })) .output(COMMENT_CREATED_SCHEMA) .retry({ replaySafety: "unsafe" }) .handler(async ({ account, input }) => { const { taskId, ...body } = input return getClickUpApi(account).request(`task/${taskId}/comment`, { body, method: "POST", responseSchema: COMMENT_CREATED_SCHEMA, }) }) /** Replaces a ClickUp comment and its assignment state. */ export const updateClickUpComment = defineAction("Update ClickUp comment") .describe("Replaces comment text, assignee, and resolved state.") .account(CLICKUP_ACCOUNT, CLICKUP_ACCOUNT_REQUIREMENT) .input( z.object({ assignee: z.number().int(), commentId: CLICKUP_ID_SCHEMA, commentText: z.string(), groupAssignee: z.number().int().optional(), resolved: z.boolean(), }), ) .retry({ replaySafety: "safe" }) .handler(async ({ account, input }) => { const { commentId, ...body } = input return getClickUpApi(account).request(`comment/${commentId}`, { body, method: "PUT", responseSchema: CLICKUP_VOID_RESPONSE_SCHEMA, }) }) /** Deletes a ClickUp comment. */ export const deleteClickUpComment = defineAction("Delete ClickUp comment") .describe("Deletes a ClickUp comment.") .account(CLICKUP_ACCOUNT, CLICKUP_ACCOUNT_REQUIREMENT) .input(z.object({ commentId: CLICKUP_ID_SCHEMA })) .retry({ replaySafety: "unsafe" }) .handler(async ({ account, input }) => getClickUpApi(account).request(`comment/${input.commentId}`, { method: "DELETE", responseSchema: CLICKUP_VOID_RESPONSE_SCHEMA, }), ) /** Lists replies to a ClickUp comment. */ export const listClickUpCommentReplies = defineAction( "List ClickUp comment replies", ) .describe("Lists threaded replies without repeating the parent comment.") .account(CLICKUP_ACCOUNT, CLICKUP_ACCOUNT_REQUIREMENT) .input(z.object({ commentId: CLICKUP_ID_SCHEMA })) .output(COMMENTS_RESPONSE_SCHEMA) .retry({ replaySafety: "safe" }) .handler(async ({ account, input }) => getClickUpApi(account).request(`comment/${input.commentId}/reply`, { responseSchema: COMMENTS_RESPONSE_SCHEMA, }), ) /** Creates a reply to a ClickUp comment. */ export const createClickUpCommentReply = defineAction( "Create ClickUp comment reply", ) .describe("Creates a threaded reply to a ClickUp comment.") .account(CLICKUP_ACCOUNT, CLICKUP_ACCOUNT_REQUIREMENT) .input(COMMENT_WRITE_SCHEMA.extend({ commentId: CLICKUP_ID_SCHEMA })) .retry({ replaySafety: "unsafe" }) .handler(async ({ account, input }) => { const { commentId, ...body } = input return getClickUpApi(account).request(`comment/${commentId}/reply`, { body, method: "POST", responseSchema: CLICKUP_VOID_RESPONSE_SCHEMA, }) })