@griffinwork40/clickup-mcp-server 1.1.4 → 1.1.5
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.
- package/dist/schemas.d.ts +33 -0
- package/dist/schemas.d.ts.map +1 -0
- package/dist/schemas.js +34 -0
- package/dist/schemas.js.map +1 -0
- package/dist/server.d.ts +10 -0
- package/dist/server.d.ts.map +1 -0
- package/dist/server.js +56 -0
- package/dist/server.js.map +1 -0
- package/dist/tools/comments.d.ts +10 -0
- package/dist/tools/comments.d.ts.map +1 -0
- package/dist/tools/comments.js +123 -0
- package/dist/tools/comments.js.map +1 -0
- package/dist/tools/custom-fields.d.ts +10 -0
- package/dist/tools/custom-fields.d.ts.map +1 -0
- package/dist/tools/custom-fields.js +68 -0
- package/dist/tools/custom-fields.js.map +1 -0
- package/dist/tools/hierarchy.d.ts +10 -0
- package/dist/tools/hierarchy.d.ts.map +1 -0
- package/dist/tools/hierarchy.js +188 -0
- package/dist/tools/hierarchy.js.map +1 -0
- package/dist/tools/index.d.ts +13 -0
- package/dist/tools/index.d.ts.map +1 -0
- package/dist/tools/index.js +13 -0
- package/dist/tools/index.js.map +1 -0
- package/dist/tools/lists.d.ts +10 -0
- package/dist/tools/lists.d.ts.map +1 -0
- package/dist/tools/lists.js +148 -0
- package/dist/tools/lists.js.map +1 -0
- package/dist/tools/tasks-analytics.d.ts +10 -0
- package/dist/tools/tasks-analytics.d.ts.map +1 -0
- package/dist/tools/tasks-analytics.js +160 -0
- package/dist/tools/tasks-analytics.js.map +1 -0
- package/dist/tools/tasks-get.d.ts +10 -0
- package/dist/tools/tasks-get.d.ts.map +1 -0
- package/dist/tools/tasks-get.js +209 -0
- package/dist/tools/tasks-get.js.map +1 -0
- package/dist/tools/tasks-read.d.ts +10 -0
- package/dist/tools/tasks-read.d.ts.map +1 -0
- package/dist/tools/tasks-read.js +379 -0
- package/dist/tools/tasks-read.js.map +1 -0
- package/dist/tools/tasks-search.d.ts +10 -0
- package/dist/tools/tasks-search.d.ts.map +1 -0
- package/dist/tools/tasks-search.js +176 -0
- package/dist/tools/tasks-search.js.map +1 -0
- package/dist/tools/tasks-write.d.ts +10 -0
- package/dist/tools/tasks-write.d.ts.map +1 -0
- package/dist/tools/tasks-write.js +232 -0
- package/dist/tools/tasks-write.js.map +1 -0
- package/dist/tools/time-tracking.d.ts +10 -0
- package/dist/tools/time-tracking.d.ts.map +1 -0
- package/dist/tools/time-tracking.js +180 -0
- package/dist/tools/time-tracking.js.map +1 -0
- package/dist/utils/api-client.d.ts +17 -0
- package/dist/utils/api-client.d.ts.map +1 -0
- package/dist/utils/api-client.js +77 -0
- package/dist/utils/api-client.js.map +1 -0
- package/dist/utils/csv-export.d.ts +29 -0
- package/dist/utils/csv-export.d.ts.map +1 -0
- package/dist/utils/csv-export.js +204 -0
- package/dist/utils/csv-export.js.map +1 -0
- package/dist/utils/custom-fields.d.ts +25 -0
- package/dist/utils/custom-fields.d.ts.map +1 -0
- package/dist/utils/custom-fields.js +132 -0
- package/dist/utils/custom-fields.js.map +1 -0
- package/dist/utils/data-processing.d.ts +10 -0
- package/dist/utils/data-processing.d.ts.map +1 -0
- package/dist/utils/data-processing.js +18 -0
- package/dist/utils/data-processing.js.map +1 -0
- package/dist/utils/formatters/base.d.ts +21 -0
- package/dist/utils/formatters/base.d.ts.map +1 -0
- package/dist/utils/formatters/base.js +30 -0
- package/dist/utils/formatters/base.js.map +1 -0
- package/dist/utils/formatters/entities.d.ts +34 -0
- package/dist/utils/formatters/entities.d.ts.map +1 -0
- package/dist/utils/formatters/entities.js +146 -0
- package/dist/utils/formatters/entities.js.map +1 -0
- package/dist/utils/formatters/index.d.ts +6 -0
- package/dist/utils/formatters/index.d.ts.map +1 -0
- package/dist/utils/formatters/index.js +6 -0
- package/dist/utils/formatters/index.js.map +1 -0
- package/dist/utils/index.d.ts +13 -0
- package/dist/utils/index.d.ts.map +1 -0
- package/dist/utils/index.js +21 -0
- package/dist/utils/index.js.map +1 -0
- package/dist/utils/task-analytics.d.ts +14 -0
- package/dist/utils/task-analytics.d.ts.map +1 -0
- package/dist/utils/task-analytics.js +67 -0
- package/dist/utils/task-analytics.js.map +1 -0
- package/dist/utils/task-counter.d.ts +24 -0
- package/dist/utils/task-counter.d.ts.map +1 -0
- package/dist/utils/task-counter.js +52 -0
- package/dist/utils/task-counter.js.map +1 -0
- package/dist/utils/truncation.d.ts +14 -0
- package/dist/utils/truncation.d.ts.map +1 -0
- package/dist/utils/truncation.js +124 -0
- package/dist/utils/truncation.js.map +1 -0
- package/package.json +5 -5
|
@@ -0,0 +1,204 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* CSV export utilities for ClickUp MCP server.
|
|
3
|
+
* Export tasks to CSV format with custom field support.
|
|
4
|
+
*/
|
|
5
|
+
import { MAX_LIMIT } from "../constants.js";
|
|
6
|
+
import { makeApiRequest } from "./api-client.js";
|
|
7
|
+
import { filterTasksByStatus } from "./task-analytics.js";
|
|
8
|
+
import { extractCustomFieldValue, getCustomField } from "./custom-fields.js";
|
|
9
|
+
/**
|
|
10
|
+
* Escape CSV fields to handle commas, quotes, and newlines
|
|
11
|
+
*/
|
|
12
|
+
export function escapeCSV(value) {
|
|
13
|
+
if (value === null || value === undefined)
|
|
14
|
+
return '';
|
|
15
|
+
const stringValue = String(value);
|
|
16
|
+
// If contains comma, quote, or newline, wrap in quotes and escape quotes
|
|
17
|
+
if (stringValue.includes(',') || stringValue.includes('"') || stringValue.includes('\n')) {
|
|
18
|
+
return `"${stringValue.replace(/"/g, '""')}"`;
|
|
19
|
+
}
|
|
20
|
+
return stringValue;
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Convert task to CSV row array
|
|
24
|
+
*/
|
|
25
|
+
export function taskToCSVRow(task, fieldOrder) {
|
|
26
|
+
const row = [];
|
|
27
|
+
for (const fieldName of fieldOrder) {
|
|
28
|
+
let value = '';
|
|
29
|
+
// Standard fields
|
|
30
|
+
if (fieldName === 'Task ID') {
|
|
31
|
+
value = task.id;
|
|
32
|
+
}
|
|
33
|
+
else if (fieldName === 'Name') {
|
|
34
|
+
value = task.name;
|
|
35
|
+
}
|
|
36
|
+
else if (fieldName === 'Status') {
|
|
37
|
+
value = task.status?.status || '';
|
|
38
|
+
}
|
|
39
|
+
else if (fieldName === 'Date Created') {
|
|
40
|
+
value = task.date_created ? new Date(parseInt(task.date_created)).toISOString() : '';
|
|
41
|
+
}
|
|
42
|
+
else if (fieldName === 'Date Updated') {
|
|
43
|
+
value = task.date_updated ? new Date(parseInt(task.date_updated)).toISOString() : '';
|
|
44
|
+
}
|
|
45
|
+
else if (fieldName === 'URL') {
|
|
46
|
+
value = task.url || '';
|
|
47
|
+
}
|
|
48
|
+
else if (fieldName === 'Assignees') {
|
|
49
|
+
value = task.assignees?.map(a => a.username || a.email).join('; ') || '';
|
|
50
|
+
}
|
|
51
|
+
else if (fieldName === 'Creator') {
|
|
52
|
+
value = task.creator?.username || task.creator?.email || '';
|
|
53
|
+
}
|
|
54
|
+
else if (fieldName === 'Due Date') {
|
|
55
|
+
value = task.due_date ? new Date(parseInt(task.due_date)).toISOString() : '';
|
|
56
|
+
}
|
|
57
|
+
else if (fieldName === 'Priority') {
|
|
58
|
+
value = task.priority?.priority || '';
|
|
59
|
+
}
|
|
60
|
+
else if (fieldName === 'Description') {
|
|
61
|
+
value = task.description || task.text_content || '';
|
|
62
|
+
}
|
|
63
|
+
else if (fieldName === 'Tags') {
|
|
64
|
+
value = task.tags?.map(t => t.name).join('; ') || '';
|
|
65
|
+
}
|
|
66
|
+
else if (fieldName === 'phone_number') {
|
|
67
|
+
// Combined phone number field for ElevenLabs compatibility
|
|
68
|
+
// First check if a real phone_number custom field exists
|
|
69
|
+
const realPhoneNumberField = task.custom_fields?.find(f => f.name === 'phone_number');
|
|
70
|
+
if (realPhoneNumberField && (realPhoneNumberField.value !== null && realPhoneNumberField.value !== undefined && realPhoneNumberField.value !== '')) {
|
|
71
|
+
// Use the real phone_number field value (already normalized)
|
|
72
|
+
value = extractCustomFieldValue(realPhoneNumberField);
|
|
73
|
+
}
|
|
74
|
+
else {
|
|
75
|
+
// No real phone_number field, use synthetic logic
|
|
76
|
+
// Priority: Personal Phone > Biz Phone number > first phone field found
|
|
77
|
+
const personalPhone = getCustomField(task, 'Personal Phone');
|
|
78
|
+
const bizPhone = getCustomField(task, 'Biz Phone number');
|
|
79
|
+
if (personalPhone) {
|
|
80
|
+
value = personalPhone;
|
|
81
|
+
}
|
|
82
|
+
else if (bizPhone) {
|
|
83
|
+
value = bizPhone;
|
|
84
|
+
}
|
|
85
|
+
else {
|
|
86
|
+
// Try to find any phone field
|
|
87
|
+
const phoneFields = task.custom_fields?.filter(f => f.type === 'phone' ||
|
|
88
|
+
f.type === 'phone_number' ||
|
|
89
|
+
(typeof f.name === 'string' && /phone/i.test(f.name))) || [];
|
|
90
|
+
if (phoneFields.length > 0) {
|
|
91
|
+
value = extractCustomFieldValue(phoneFields[0]);
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
else {
|
|
97
|
+
// Custom field
|
|
98
|
+
value = getCustomField(task, fieldName);
|
|
99
|
+
}
|
|
100
|
+
row.push(escapeCSV(value));
|
|
101
|
+
}
|
|
102
|
+
return row;
|
|
103
|
+
}
|
|
104
|
+
/**
|
|
105
|
+
* Export tasks to CSV format
|
|
106
|
+
*/
|
|
107
|
+
export async function exportTasksToCSV(listId, options = {}) {
|
|
108
|
+
const { archived = false, include_closed = false, statuses, custom_fields, include_standard_fields = true, add_phone_number_column = false } = options;
|
|
109
|
+
const limit = MAX_LIMIT;
|
|
110
|
+
let offset = 0;
|
|
111
|
+
let allTasks = [];
|
|
112
|
+
let hasMore = true;
|
|
113
|
+
// Step 1: Fetch all tasks with pagination
|
|
114
|
+
while (hasMore) {
|
|
115
|
+
const queryParams = {
|
|
116
|
+
archived,
|
|
117
|
+
include_closed,
|
|
118
|
+
page: Math.floor(offset / limit),
|
|
119
|
+
limit: limit // FIX: Actually send limit to API
|
|
120
|
+
};
|
|
121
|
+
try {
|
|
122
|
+
const data = await makeApiRequest(`list/${listId}/task`, "GET", undefined, queryParams);
|
|
123
|
+
const tasks = data.tasks || [];
|
|
124
|
+
allTasks.push(...tasks);
|
|
125
|
+
hasMore = tasks.length === limit;
|
|
126
|
+
offset += limit;
|
|
127
|
+
}
|
|
128
|
+
catch (error) {
|
|
129
|
+
throw error;
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
// Step 2: Filter by status if specified
|
|
133
|
+
if (statuses && statuses.length > 0) {
|
|
134
|
+
allTasks = filterTasksByStatus(allTasks, statuses);
|
|
135
|
+
}
|
|
136
|
+
if (allTasks.length === 0) {
|
|
137
|
+
return ''; // Return empty CSV if no tasks
|
|
138
|
+
}
|
|
139
|
+
// Note: The list endpoint already returns custom fields with values,
|
|
140
|
+
// so we don't need to fetch individual task details!
|
|
141
|
+
// Step 3: Build field order and headers
|
|
142
|
+
const standardFields = [
|
|
143
|
+
'Task ID',
|
|
144
|
+
'Name',
|
|
145
|
+
'Status',
|
|
146
|
+
'Date Created',
|
|
147
|
+
'Date Updated',
|
|
148
|
+
'URL',
|
|
149
|
+
'Assignees',
|
|
150
|
+
'Creator',
|
|
151
|
+
'Due Date',
|
|
152
|
+
'Priority',
|
|
153
|
+
'Description',
|
|
154
|
+
'Tags'
|
|
155
|
+
];
|
|
156
|
+
// Collect all custom field names from tasks
|
|
157
|
+
const allCustomFieldNames = new Set();
|
|
158
|
+
for (const task of allTasks) {
|
|
159
|
+
if (task.custom_fields) {
|
|
160
|
+
for (const field of task.custom_fields) {
|
|
161
|
+
allCustomFieldNames.add(field.name);
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
// Determine which custom fields to include
|
|
166
|
+
const customFieldsToInclude = custom_fields && custom_fields.length > 0
|
|
167
|
+
? custom_fields.filter(name => allCustomFieldNames.has(name))
|
|
168
|
+
: Array.from(allCustomFieldNames);
|
|
169
|
+
// Build field order
|
|
170
|
+
const fieldOrder = [];
|
|
171
|
+
if (include_standard_fields) {
|
|
172
|
+
fieldOrder.push(...standardFields);
|
|
173
|
+
}
|
|
174
|
+
fieldOrder.push(...customFieldsToInclude);
|
|
175
|
+
// Add phone_number column if requested (for ElevenLabs compatibility)
|
|
176
|
+
if (add_phone_number_column) {
|
|
177
|
+
// Check if phone_number already exists (e.g., as a real custom field)
|
|
178
|
+
const phoneNumberIdx = fieldOrder.indexOf('phone_number');
|
|
179
|
+
if (phoneNumberIdx === -1) {
|
|
180
|
+
// phone_number doesn't exist, add our synthetic one
|
|
181
|
+
// Find Email index to insert after it
|
|
182
|
+
const emailIdx = fieldOrder.indexOf('Email');
|
|
183
|
+
if (emailIdx >= 0) {
|
|
184
|
+
fieldOrder.splice(emailIdx + 1, 0, 'phone_number');
|
|
185
|
+
}
|
|
186
|
+
else {
|
|
187
|
+
// If no Email field, add at the end
|
|
188
|
+
fieldOrder.push('phone_number');
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
// If phone_number already exists, use the existing one (no duplicate needed)
|
|
192
|
+
}
|
|
193
|
+
// Step 4: Build CSV
|
|
194
|
+
const csvRows = [];
|
|
195
|
+
// Headers
|
|
196
|
+
csvRows.push(fieldOrder.map(escapeCSV).join(','));
|
|
197
|
+
// Data rows
|
|
198
|
+
for (const task of allTasks) {
|
|
199
|
+
const row = taskToCSVRow(task, fieldOrder);
|
|
200
|
+
csvRows.push(row.join(','));
|
|
201
|
+
}
|
|
202
|
+
return csvRows.join('\n');
|
|
203
|
+
}
|
|
204
|
+
//# sourceMappingURL=csv-export.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"csv-export.js","sourceRoot":"","sources":["../../src/utils/csv-export.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Custom field utilities for ClickUp MCP server.
|
|
3
|
+
* Handle custom field extraction and phone number normalization.
|
|
4
|
+
*/
|
|
5
|
+
import type { ClickUpTask, ClickUpCustomField } from "../types.js";
|
|
6
|
+
/**
|
|
7
|
+
* Normalize phone number to E.164 format
|
|
8
|
+
* E.164 format: ^\+?[1-9]\d{1,14}$
|
|
9
|
+
* Rules:
|
|
10
|
+
* - Optional + at the start
|
|
11
|
+
* - Must start with digit 1-9 (not 0)
|
|
12
|
+
* - Followed by 1-14 digits only
|
|
13
|
+
* - NO spaces, dashes, parentheses, dots, or other characters
|
|
14
|
+
* - NO extensions
|
|
15
|
+
*/
|
|
16
|
+
export declare function normalizePhoneToE164(phone: string | null | undefined): string;
|
|
17
|
+
/**
|
|
18
|
+
* Extract value from a custom field based on its type
|
|
19
|
+
*/
|
|
20
|
+
export declare function extractCustomFieldValue(field: ClickUpCustomField): string;
|
|
21
|
+
/**
|
|
22
|
+
* Get custom field value by name (prefers field with value if multiple exist)
|
|
23
|
+
*/
|
|
24
|
+
export declare function getCustomField(task: ClickUpTask, fieldName: string, preferredType?: string): string;
|
|
25
|
+
//# sourceMappingURL=custom-fields.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"custom-fields.d.ts","sourceRoot":"","sources":["../../src/utils/custom-fields.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAE,WAAW,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAC;AAEnE;;;;;;;;;GASG;AACH,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GAAG,MAAM,CA0D7E;AAED;;GAEG;AACH,wBAAgB,uBAAuB,CAAC,KAAK,EAAE,kBAAkB,GAAG,MAAM,CAgCzE;AAED;;GAEG;AACH,wBAAgB,cAAc,CAAC,IAAI,EAAE,WAAW,EAAE,SAAS,EAAE,MAAM,EAAE,aAAa,CAAC,EAAE,MAAM,GAAG,MAAM,CAoBnG"}
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Custom field utilities for ClickUp MCP server.
|
|
3
|
+
* Handle custom field extraction and phone number normalization.
|
|
4
|
+
*/
|
|
5
|
+
/**
|
|
6
|
+
* Normalize phone number to E.164 format
|
|
7
|
+
* E.164 format: ^\+?[1-9]\d{1,14}$
|
|
8
|
+
* Rules:
|
|
9
|
+
* - Optional + at the start
|
|
10
|
+
* - Must start with digit 1-9 (not 0)
|
|
11
|
+
* - Followed by 1-14 digits only
|
|
12
|
+
* - NO spaces, dashes, parentheses, dots, or other characters
|
|
13
|
+
* - NO extensions
|
|
14
|
+
*/
|
|
15
|
+
export function normalizePhoneToE164(phone) {
|
|
16
|
+
if (!phone)
|
|
17
|
+
return '';
|
|
18
|
+
let normalized = String(phone).trim();
|
|
19
|
+
if (!normalized)
|
|
20
|
+
return '';
|
|
21
|
+
// Remove extensions (x206, ext 123, extension 456, etc.)
|
|
22
|
+
// Match: x, ext, extension followed by optional space and digits
|
|
23
|
+
normalized = normalized.replace(/\s*(?:x|ext|extension)\s*\d+/i, '');
|
|
24
|
+
// Check if it starts with + (preserve it)
|
|
25
|
+
const hasPlus = normalized.startsWith('+');
|
|
26
|
+
if (hasPlus) {
|
|
27
|
+
normalized = normalized.substring(1);
|
|
28
|
+
}
|
|
29
|
+
// Remove all non-digit characters
|
|
30
|
+
normalized = normalized.replace(/\D/g, '');
|
|
31
|
+
// If empty after cleaning, return empty
|
|
32
|
+
if (!normalized)
|
|
33
|
+
return '';
|
|
34
|
+
// If number starts with 0, it's invalid for E.164 (must start with 1-9)
|
|
35
|
+
if (normalized.startsWith('0')) {
|
|
36
|
+
return '';
|
|
37
|
+
}
|
|
38
|
+
// Check if it already has a country code (starts with 1-9 and has 10+ digits)
|
|
39
|
+
// If it's 10 digits and starts with 1, assume it's US/Canada with country code
|
|
40
|
+
// If it's 10 digits and doesn't start with 1, assume it's missing country code
|
|
41
|
+
// If it's 11 digits and starts with 1, it already has country code
|
|
42
|
+
// If it's more than 11 digits, assume it already has country code
|
|
43
|
+
if (normalized.length === 10) {
|
|
44
|
+
// 10 digits without country code - add +1 for US/Canada
|
|
45
|
+
normalized = '1' + normalized;
|
|
46
|
+
}
|
|
47
|
+
else if (normalized.length === 11 && normalized.startsWith('1')) {
|
|
48
|
+
// Already has US/Canada country code
|
|
49
|
+
// Keep as is
|
|
50
|
+
}
|
|
51
|
+
else if (normalized.length < 10) {
|
|
52
|
+
// Too short to be a valid phone number
|
|
53
|
+
return '';
|
|
54
|
+
}
|
|
55
|
+
else if (normalized.length > 15) {
|
|
56
|
+
// Too long for E.164 (max 15 digits after country code)
|
|
57
|
+
return '';
|
|
58
|
+
}
|
|
59
|
+
// Add + prefix
|
|
60
|
+
normalized = '+' + normalized;
|
|
61
|
+
// Validate E.164 format: ^\+?[1-9]\d{1,14}$
|
|
62
|
+
// We already have the +, so check: [1-9]\d{1,14}
|
|
63
|
+
const e164Regex = /^\+[1-9]\d{1,14}$/;
|
|
64
|
+
if (!e164Regex.test(normalized)) {
|
|
65
|
+
return '';
|
|
66
|
+
}
|
|
67
|
+
return normalized;
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* Extract value from a custom field based on its type
|
|
71
|
+
*/
|
|
72
|
+
export function extractCustomFieldValue(field) {
|
|
73
|
+
if (!field || field.value === null || field.value === undefined || field.value === '')
|
|
74
|
+
return '';
|
|
75
|
+
// Check if this is a phone number field (by type or name)
|
|
76
|
+
const isPhoneField = field.type === 'phone' ||
|
|
77
|
+
field.type === 'phone_number' ||
|
|
78
|
+
(typeof field.name === 'string' && /phone/i.test(field.name));
|
|
79
|
+
// Handle different field types
|
|
80
|
+
if (field.type === 'email' || field.type === 'url' || field.type === 'text' || field.type === 'short_text') {
|
|
81
|
+
const value = String(field.value).trim();
|
|
82
|
+
// Normalize if it's a phone field
|
|
83
|
+
return isPhoneField ? normalizePhoneToE164(value) : value;
|
|
84
|
+
}
|
|
85
|
+
else if (field.type === 'phone' || field.type === 'phone_number') {
|
|
86
|
+
return normalizePhoneToE164(field.value);
|
|
87
|
+
}
|
|
88
|
+
else if (field.type === 'number' || field.type === 'currency') {
|
|
89
|
+
return String(field.value);
|
|
90
|
+
}
|
|
91
|
+
else if (field.type === 'date') {
|
|
92
|
+
return new Date(parseInt(field.value)).toISOString().split('T')[0];
|
|
93
|
+
}
|
|
94
|
+
else if (field.type === 'dropdown') {
|
|
95
|
+
return field.value?.label || field.value?.name || String(field.value || '');
|
|
96
|
+
}
|
|
97
|
+
else if (field.type === 'labels') {
|
|
98
|
+
return Array.isArray(field.value) ? field.value.map((v) => v.label || v.name || v).join('; ') : '';
|
|
99
|
+
}
|
|
100
|
+
else if (field.type === 'checklist') {
|
|
101
|
+
return Array.isArray(field.value) ? field.value.map((item) => item.name).join('; ') : '';
|
|
102
|
+
}
|
|
103
|
+
else if (field.type === 'checkbox') {
|
|
104
|
+
return field.value ? 'Yes' : 'No';
|
|
105
|
+
}
|
|
106
|
+
// Default: return trimmed string, normalize if it's a phone field
|
|
107
|
+
const value = String(field.value || '').trim();
|
|
108
|
+
return isPhoneField ? normalizePhoneToE164(value) : value;
|
|
109
|
+
}
|
|
110
|
+
/**
|
|
111
|
+
* Get custom field value by name (prefers field with value if multiple exist)
|
|
112
|
+
*/
|
|
113
|
+
export function getCustomField(task, fieldName, preferredType) {
|
|
114
|
+
if (!task.custom_fields)
|
|
115
|
+
return '';
|
|
116
|
+
// Find all fields with matching name
|
|
117
|
+
const matchingFields = task.custom_fields.filter(f => f.name === fieldName);
|
|
118
|
+
if (matchingFields.length === 0)
|
|
119
|
+
return '';
|
|
120
|
+
// If preferred type specified, try that first
|
|
121
|
+
if (preferredType) {
|
|
122
|
+
const typedField = matchingFields.find(f => f.type === preferredType && f.value);
|
|
123
|
+
if (typedField) {
|
|
124
|
+
return extractCustomFieldValue(typedField);
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
// Prefer field with a value
|
|
128
|
+
const fieldWithValue = matchingFields.find(f => f.value !== null && f.value !== undefined && f.value !== '');
|
|
129
|
+
const field = fieldWithValue || matchingFields[0];
|
|
130
|
+
return extractCustomFieldValue(field);
|
|
131
|
+
}
|
|
132
|
+
//# sourceMappingURL=custom-fields.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"custom-fields.js","sourceRoot":"","sources":["../../src/utils/custom-fields.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAIH;;;;;;;;;GASG;AACH,MAAM,UAAU,oBAAoB,CAAC,KAAgC;IACnE,IAAI,CAAC,KAAK;QAAE,OAAO,EAAE,CAAC;IAEtB,IAAI,UAAU,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC,IAAI,EAAE,CAAC;IACtC,IAAI,CAAC,UAAU;QAAE,OAAO,EAAE,CAAC;IAE3B,yDAAyD;IACzD,iEAAiE;IACjE,UAAU,GAAG,UAAU,CAAC,OAAO,CAAC,+BAA+B,EAAE,EAAE,CAAC,CAAC;IAErE,0CAA0C;IAC1C,MAAM,OAAO,GAAG,UAAU,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC;IAC3C,IAAI,OAAO,EAAE,CAAC;QACZ,UAAU,GAAG,UAAU,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC;IACvC,CAAC;IAED,kCAAkC;IAClC,UAAU,GAAG,UAAU,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;IAE3C,wCAAwC;IACxC,IAAI,CAAC,UAAU;QAAE,OAAO,EAAE,CAAC;IAE3B,wEAAwE;IACxE,IAAI,UAAU,CAAC,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC;QAC/B,OAAO,EAAE,CAAC;IACZ,CAAC;IAED,8EAA8E;IAC9E,+EAA+E;IAC/E,+EAA+E;IAC/E,mEAAmE;IACnE,kEAAkE;IAElE,IAAI,UAAU,CAAC,MAAM,KAAK,EAAE,EAAE,CAAC;QAC7B,wDAAwD;QACxD,UAAU,GAAG,GAAG,GAAG,UAAU,CAAC;IAChC,CAAC;SAAM,IAAI,UAAU,CAAC,MAAM,KAAK,EAAE,IAAI,UAAU,CAAC,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC;QAClE,qCAAqC;QACrC,aAAa;IACf,CAAC;SAAM,IAAI,UAAU,CAAC,MAAM,GAAG,EAAE,EAAE,CAAC;QAClC,uCAAuC;QACvC,OAAO,EAAE,CAAC;IACZ,CAAC;SAAM,IAAI,UAAU,CAAC,MAAM,GAAG,EAAE,EAAE,CAAC;QAClC,wDAAwD;QACxD,OAAO,EAAE,CAAC;IACZ,CAAC;IAED,eAAe;IACf,UAAU,GAAG,GAAG,GAAG,UAAU,CAAC;IAE9B,4CAA4C;IAC5C,iDAAiD;IACjD,MAAM,SAAS,GAAG,mBAAmB,CAAC;IACtC,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,UAAU,CAAC,EAAE,CAAC;QAChC,OAAO,EAAE,CAAC;IACZ,CAAC;IAED,OAAO,UAAU,CAAC;AACpB,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,uBAAuB,CAAC,KAAyB;IAC/D,IAAI,CAAC,KAAK,IAAI,KAAK,CAAC,KAAK,KAAK,IAAI,IAAI,KAAK,CAAC,KAAK,KAAK,SAAS,IAAI,KAAK,CAAC,KAAK,KAAK,EAAE;QAAE,OAAO,EAAE,CAAC;IAEjG,0DAA0D;IAC1D,MAAM,YAAY,GAAG,KAAK,CAAC,IAAI,KAAK,OAAO;QACtB,KAAK,CAAC,IAAI,KAAK,cAAc;QAC7B,CAAC,OAAO,KAAK,CAAC,IAAI,KAAK,QAAQ,IAAI,QAAQ,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC;IAEnF,+BAA+B;IAC/B,IAAI,KAAK,CAAC,IAAI,KAAK,OAAO,IAAI,KAAK,CAAC,IAAI,KAAK,KAAK,IAAI,KAAK,CAAC,IAAI,KAAK,MAAM,IAAI,KAAK,CAAC,IAAI,KAAK,YAAY,EAAE,CAAC;QAC3G,MAAM,KAAK,GAAG,MAAM,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,IAAI,EAAE,CAAC;QACzC,kCAAkC;QAClC,OAAO,YAAY,CAAC,CAAC,CAAC,oBAAoB,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC;IAC5D,CAAC;SAAM,IAAI,KAAK,CAAC,IAAI,KAAK,OAAO,IAAI,KAAK,CAAC,IAAI,KAAK,cAAc,EAAE,CAAC;QACnE,OAAO,oBAAoB,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;IAC3C,CAAC;SAAM,IAAI,KAAK,CAAC,IAAI,KAAK,QAAQ,IAAI,KAAK,CAAC,IAAI,KAAK,UAAU,EAAE,CAAC;QAChE,OAAO,MAAM,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;IAC7B,CAAC;SAAM,IAAI,KAAK,CAAC,IAAI,KAAK,MAAM,EAAE,CAAC;QACjC,OAAO,IAAI,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,WAAW,EAAE,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;IACrE,CAAC;SAAM,IAAI,KAAK,CAAC,IAAI,KAAK,UAAU,EAAE,CAAC;QACrC,OAAO,KAAK,CAAC,KAAK,EAAE,KAAK,IAAI,KAAK,CAAC,KAAK,EAAE,IAAI,IAAI,MAAM,CAAC,KAAK,CAAC,KAAK,IAAI,EAAE,CAAC,CAAC;IAC9E,CAAC;SAAM,IAAI,KAAK,CAAC,IAAI,KAAK,QAAQ,EAAE,CAAC;QACnC,OAAO,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAM,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,IAAI,CAAC,CAAC,IAAI,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;IAC1G,CAAC;SAAM,IAAI,KAAK,CAAC,IAAI,KAAK,WAAW,EAAE,CAAC;QACtC,OAAO,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,IAAS,EAAE,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;IAChG,CAAC;SAAM,IAAI,KAAK,CAAC,IAAI,KAAK,UAAU,EAAE,CAAC;QACrC,OAAO,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC;IACpC,CAAC;IAED,kEAAkE;IAClE,MAAM,KAAK,GAAG,MAAM,CAAC,KAAK,CAAC,KAAK,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC;IAC/C,OAAO,YAAY,CAAC,CAAC,CAAC,oBAAoB,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC;AAC5D,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,cAAc,CAAC,IAAiB,EAAE,SAAiB,EAAE,aAAsB;IACzF,IAAI,CAAC,IAAI,CAAC,aAAa;QAAE,OAAO,EAAE,CAAC;IAEnC,qCAAqC;IACrC,MAAM,cAAc,GAAG,IAAI,CAAC,aAAa,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,SAAS,CAAC,CAAC;IAC5E,IAAI,cAAc,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,EAAE,CAAC;IAE3C,8CAA8C;IAC9C,IAAI,aAAa,EAAE,CAAC;QAClB,MAAM,UAAU,GAAG,cAAc,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,aAAa,IAAI,CAAC,CAAC,KAAK,CAAC,CAAC;QACjF,IAAI,UAAU,EAAE,CAAC;YACf,OAAO,uBAAuB,CAAC,UAAU,CAAC,CAAC;QAC7C,CAAC;IACH,CAAC;IAED,4BAA4B;IAC5B,MAAM,cAAc,GAAG,cAAc,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,KAAK,KAAK,IAAI,IAAI,CAAC,CAAC,KAAK,KAAK,SAAS,IAAI,CAAC,CAAC,KAAK,KAAK,EAAE,CAAC,CAAC;IAC7G,MAAM,KAAK,GAAG,cAAc,IAAI,cAAc,CAAC,CAAC,CAAC,CAAC;IAElD,OAAO,uBAAuB,CAAC,KAAK,CAAC,CAAC;AACxC,CAAC"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Data processing utilities for ClickUp MCP server.
|
|
3
|
+
* Handle pagination and response metadata extraction.
|
|
4
|
+
*/
|
|
5
|
+
import type { PaginationInfo } from "../types.js";
|
|
6
|
+
/**
|
|
7
|
+
* Extract pagination information from response
|
|
8
|
+
*/
|
|
9
|
+
export declare function getPagination(total: number | undefined, count: number, offset: number, limit: number): PaginationInfo;
|
|
10
|
+
//# sourceMappingURL=data-processing.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"data-processing.d.ts","sourceRoot":"","sources":["../../src/utils/data-processing.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAElD;;GAEG;AACH,wBAAgB,aAAa,CAC3B,KAAK,EAAE,MAAM,GAAG,SAAS,EACzB,KAAK,EAAE,MAAM,EACb,MAAM,EAAE,MAAM,EACd,KAAK,EAAE,MAAM,GACZ,cAAc,CAUhB"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Data processing utilities for ClickUp MCP server.
|
|
3
|
+
* Handle pagination and response metadata extraction.
|
|
4
|
+
*/
|
|
5
|
+
/**
|
|
6
|
+
* Extract pagination information from response
|
|
7
|
+
*/
|
|
8
|
+
export function getPagination(total, count, offset, limit) {
|
|
9
|
+
const hasMore = total ? (offset + count < total) : count === limit;
|
|
10
|
+
return {
|
|
11
|
+
total,
|
|
12
|
+
count,
|
|
13
|
+
offset,
|
|
14
|
+
has_more: hasMore,
|
|
15
|
+
next_offset: hasMore ? offset + count : undefined
|
|
16
|
+
};
|
|
17
|
+
}
|
|
18
|
+
//# sourceMappingURL=data-processing.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"data-processing.js","sourceRoot":"","sources":["../../src/utils/data-processing.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAIH;;GAEG;AACH,MAAM,UAAU,aAAa,CAC3B,KAAyB,EACzB,KAAa,EACb,MAAc,EACd,KAAa;IAEb,MAAM,OAAO,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC,MAAM,GAAG,KAAK,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,KAAK,KAAK,CAAC;IAEnE,OAAO;QACL,KAAK;QACL,KAAK;QACL,MAAM;QACN,QAAQ,EAAE,OAAO;QACjB,WAAW,EAAE,OAAO,CAAC,CAAC,CAAC,MAAM,GAAG,KAAK,CAAC,CAAC,CAAC,SAAS;KAClD,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Base formatting utilities for ClickUp MCP server.
|
|
3
|
+
* Simple, reusable formatting primitives used by other formatters.
|
|
4
|
+
*/
|
|
5
|
+
import type { TruncationInfo } from "../../types.js";
|
|
6
|
+
/**
|
|
7
|
+
* Format a timestamp as human-readable date
|
|
8
|
+
*/
|
|
9
|
+
export declare function formatDate(timestamp: string | number | undefined): string;
|
|
10
|
+
/**
|
|
11
|
+
* Format priority value as human-readable string
|
|
12
|
+
*/
|
|
13
|
+
export declare function formatPriority(priority?: {
|
|
14
|
+
priority: string;
|
|
15
|
+
color: string;
|
|
16
|
+
}): string;
|
|
17
|
+
/**
|
|
18
|
+
* Format truncation information as text
|
|
19
|
+
*/
|
|
20
|
+
export declare function formatTruncationInfo(truncation: TruncationInfo | null): string;
|
|
21
|
+
//# sourceMappingURL=base.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"base.d.ts","sourceRoot":"","sources":["../../../src/utils/formatters/base.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;AAErD;;GAEG;AACH,wBAAgB,UAAU,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,GAAG,MAAM,CAKzE;AAED;;GAEG;AACH,wBAAgB,cAAc,CAAC,QAAQ,CAAC,EAAE;IAAE,QAAQ,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,GAAG,MAAM,CAGrF;AAED;;GAEG;AACH,wBAAgB,oBAAoB,CAAC,UAAU,EAAE,cAAc,GAAG,IAAI,GAAG,MAAM,CAI9E"}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Base formatting utilities for ClickUp MCP server.
|
|
3
|
+
* Simple, reusable formatting primitives used by other formatters.
|
|
4
|
+
*/
|
|
5
|
+
/**
|
|
6
|
+
* Format a timestamp as human-readable date
|
|
7
|
+
*/
|
|
8
|
+
export function formatDate(timestamp) {
|
|
9
|
+
if (!timestamp)
|
|
10
|
+
return "Not set";
|
|
11
|
+
const date = new Date(typeof timestamp === "string" ? parseInt(timestamp) : timestamp);
|
|
12
|
+
return date.toISOString().replace("T", " ").substring(0, 19) + " UTC";
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Format priority value as human-readable string
|
|
16
|
+
*/
|
|
17
|
+
export function formatPriority(priority) {
|
|
18
|
+
if (!priority)
|
|
19
|
+
return "None";
|
|
20
|
+
return priority.priority;
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Format truncation information as text
|
|
24
|
+
*/
|
|
25
|
+
export function formatTruncationInfo(truncation) {
|
|
26
|
+
if (!truncation)
|
|
27
|
+
return "";
|
|
28
|
+
return `\n\n---\n\u26a0\ufe0f ${truncation.truncation_message}`;
|
|
29
|
+
}
|
|
30
|
+
//# sourceMappingURL=base.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"base.js","sourceRoot":"","sources":["../../../src/utils/formatters/base.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAIH;;GAEG;AACH,MAAM,UAAU,UAAU,CAAC,SAAsC;IAC/D,IAAI,CAAC,SAAS;QAAE,OAAO,SAAS,CAAC;IAEjC,MAAM,IAAI,GAAG,IAAI,IAAI,CAAC,OAAO,SAAS,KAAK,QAAQ,CAAC,CAAC,CAAC,QAAQ,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC;IACvF,OAAO,IAAI,CAAC,WAAW,EAAE,CAAC,OAAO,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC,SAAS,CAAC,CAAC,EAAE,EAAE,CAAC,GAAG,MAAM,CAAC;AACxE,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,cAAc,CAAC,QAA8C;IAC3E,IAAI,CAAC,QAAQ;QAAE,OAAO,MAAM,CAAC;IAC7B,OAAO,QAAQ,CAAC,QAAQ,CAAC;AAC3B,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,oBAAoB,CAAC,UAAiC;IACpE,IAAI,CAAC,UAAU;QAAE,OAAO,EAAE,CAAC;IAE3B,OAAO,yBAAyB,UAAU,CAAC,kBAAkB,EAAE,CAAC;AAClE,CAAC"}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Entity formatters for ClickUp MCP server.
|
|
3
|
+
* Format ClickUp entities (tasks, lists, spaces, etc.) as markdown.
|
|
4
|
+
*/
|
|
5
|
+
import type { ClickUpTask, ClickUpList, ClickUpSpace, ClickUpFolder, ClickUpComment, ClickUpTimeEntry } from "../../types.js";
|
|
6
|
+
/**
|
|
7
|
+
* Format a task as markdown (full detail)
|
|
8
|
+
*/
|
|
9
|
+
export declare function formatTaskMarkdown(task: ClickUpTask): string;
|
|
10
|
+
/**
|
|
11
|
+
* Format a task as compact markdown (essential fields only)
|
|
12
|
+
*/
|
|
13
|
+
export declare function formatTaskCompact(task: ClickUpTask): string;
|
|
14
|
+
/**
|
|
15
|
+
* Format a list as markdown
|
|
16
|
+
*/
|
|
17
|
+
export declare function formatListMarkdown(list: ClickUpList): string;
|
|
18
|
+
/**
|
|
19
|
+
* Format a space as markdown
|
|
20
|
+
*/
|
|
21
|
+
export declare function formatSpaceMarkdown(space: ClickUpSpace): string;
|
|
22
|
+
/**
|
|
23
|
+
* Format a folder as markdown
|
|
24
|
+
*/
|
|
25
|
+
export declare function formatFolderMarkdown(folder: ClickUpFolder): string;
|
|
26
|
+
/**
|
|
27
|
+
* Format a comment as markdown
|
|
28
|
+
*/
|
|
29
|
+
export declare function formatCommentMarkdown(comment: ClickUpComment): string;
|
|
30
|
+
/**
|
|
31
|
+
* Format a time entry as markdown
|
|
32
|
+
*/
|
|
33
|
+
export declare function formatTimeEntryMarkdown(entry: ClickUpTimeEntry): string;
|
|
34
|
+
//# sourceMappingURL=entities.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"entities.d.ts","sourceRoot":"","sources":["../../../src/utils/formatters/entities.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EACV,WAAW,EACX,WAAW,EACX,YAAY,EACZ,aAAa,EACb,cAAc,EACd,gBAAgB,EACjB,MAAM,gBAAgB,CAAC;AAGxB;;GAEG;AACH,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,WAAW,GAAG,MAAM,CAkC5D;AAED;;GAEG;AACH,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,WAAW,GAAG,MAAM,CAM3D;AAED;;GAEG;AACH,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,WAAW,GAAG,MAAM,CAwB5D;AAED;;GAEG;AACH,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,YAAY,GAAG,MAAM,CAkB/D;AAED;;GAEG;AACH,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,aAAa,GAAG,MAAM,CAqBlE;AAED;;GAEG;AACH,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,cAAc,GAAG,MAAM,CAWrE;AAED;;GAEG;AACH,wBAAgB,uBAAuB,CAAC,KAAK,EAAE,gBAAgB,GAAG,MAAM,CA2BvE"}
|