// CIL[BEGIN chunk_id="custom_workbench_add_comment_module_header_1784572423" type="module_header" identity="module_header" parent="none"] // CIL[DOC-MACRO purpose="Add a comment to a Workbench work item, creating the timeline thread if one does not exist"] // CIL[DOC-RESPONSIBILITY responsibility="Find or create a workbench timeline thread for the item and create a message record through admin-data"] // CIL[DOC-CONTEXT module="workbench.functions.custom_workbench-add-comment" layer="function" related_files="[\"custom/apps/workbench/pages/work/WorkItemDetailPage.tsx\", \".framework/functions/admin-data.ts\"]"] // CIL[DOC-CONTRACT inputs="item_id (UUID), content (string)" outputs="{ thread_id, message_id }" errors="missing_item_id_or_content, thread_creation_failed, message_creation_failed" side_effects="creates threads and messages records through admin-data"] // CIL[DOC-MICRO logic_summary="Validates input, finds an existing timeline thread by target_id, creates one through admin-data if missing, then creates a message record through admin-data" notable_decisions=["Reuses the first existing thread for the work item to avoid duplicate timeline threads", "Thread and message creation route through the generic admin-data create handler"]"] // CIL[DOC-CONFIDENCE pass="first" score="0.9" flags="none"] // CIL[DOC-STABILITY stability="experimental"] // CIL[DOC-AUDIENCE audience="developer"] import { createHandler } from './_shared/middleware' import { create as adminCreate, list as adminList } from './admin-data' // CIL[END chunk_id="custom_workbench_add_comment_module_header_1784572423"] // CIL[BEGIN chunk_id="custom_workbench_add_comment_request_1784572423" type="interface" identity="AddCommentRequest" parent="none"] interface AddCommentRequest { item_id: string; content: string } // CIL[END chunk_id="custom_workbench_add_comment_request_1784572423"] // CIL[BEGIN chunk_id="custom_workbench_add_comment_findorcreatethread_1784572423" type="function" identity="findOrCreateTimelineThread" parent="none"] async function findOrCreateTimelineThread(ctx: any, itemId: string): Promise { const existing = await adminList({ ...ctx, query: { ...(ctx.query || {}), entity: 'threads', target_id: itemId, target_type: 'items', limit: '1' } } as any, {}) const existingId = Array.isArray(existing) ? existing[0]?.id : (existing as any)?.data?.[0]?.id if (existingId) return existingId const thread = await adminCreate(ctx, { entity: 'threads', type_slug: 'eng_ticket_thread', target_id: itemId, target_type: 'items', title: 'Workbench timeline', } as any) return (thread as any)?.id ?? (thread as any)?.data?.id ?? null } // CIL[END chunk_id="custom_workbench_add_comment_findorcreatethread_1784572423"] // CIL[BEGIN chunk_id="custom_workbench_add_comment_addcomment_1784572423" type="function" identity="addComment" parent="none"] export const addComment = createHandler(async (ctx, body) => { const { item_id, content } = (body || {}) as AddCommentRequest if (!item_id || !content?.trim()) { const e: any = new Error('item_id and content are required') e.statusCode = 400 throw e } const threadId = await findOrCreateTimelineThread(ctx, item_id) if (!threadId) { const e: any = new Error('Failed to create or resolve timeline thread') e.statusCode = 500 throw e } const message = await adminCreate(ctx, { entity: 'messages', type_slug: 'eng_ticket_comment', thread_id: threadId, content: content.trim(), } as any) const messageId = (message as any)?.id ?? (message as any)?.data?.id return { thread_id: threadId, message_id: messageId } }) // CIL[END chunk_id="custom_workbench_add_comment_addcomment_1784572423"]