@alanse/clickup-multi-mcp-server 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/Dockerfile +38 -0
- package/LICENSE +21 -0
- package/README.md +470 -0
- package/build/config.js +237 -0
- package/build/index.js +87 -0
- package/build/logger.js +163 -0
- package/build/middleware/security.js +231 -0
- package/build/server.js +288 -0
- package/build/services/clickup/base.js +432 -0
- package/build/services/clickup/bulk.js +180 -0
- package/build/services/clickup/document.js +159 -0
- package/build/services/clickup/folder.js +136 -0
- package/build/services/clickup/index.js +76 -0
- package/build/services/clickup/list.js +191 -0
- package/build/services/clickup/tag.js +239 -0
- package/build/services/clickup/task/index.js +32 -0
- package/build/services/clickup/task/task-attachments.js +105 -0
- package/build/services/clickup/task/task-comments.js +114 -0
- package/build/services/clickup/task/task-core.js +604 -0
- package/build/services/clickup/task/task-custom-fields.js +107 -0
- package/build/services/clickup/task/task-search.js +986 -0
- package/build/services/clickup/task/task-service.js +104 -0
- package/build/services/clickup/task/task-tags.js +113 -0
- package/build/services/clickup/time.js +244 -0
- package/build/services/clickup/types.js +33 -0
- package/build/services/clickup/workspace.js +397 -0
- package/build/services/shared.js +61 -0
- package/build/sse_server.js +277 -0
- package/build/tools/documents.js +489 -0
- package/build/tools/folder.js +331 -0
- package/build/tools/index.js +16 -0
- package/build/tools/list.js +428 -0
- package/build/tools/member.js +106 -0
- package/build/tools/tag.js +833 -0
- package/build/tools/task/attachments.js +357 -0
- package/build/tools/task/attachments.types.js +9 -0
- package/build/tools/task/bulk-operations.js +338 -0
- package/build/tools/task/handlers.js +919 -0
- package/build/tools/task/index.js +30 -0
- package/build/tools/task/main.js +233 -0
- package/build/tools/task/single-operations.js +469 -0
- package/build/tools/task/time-tracking.js +575 -0
- package/build/tools/task/utilities.js +310 -0
- package/build/tools/task/workspace-operations.js +258 -0
- package/build/tools/tool-enhancer.js +37 -0
- package/build/tools/utils.js +12 -0
- package/build/tools/workspace-helper.js +44 -0
- package/build/tools/workspace.js +73 -0
- package/build/utils/color-processor.js +183 -0
- package/build/utils/concurrency-utils.js +248 -0
- package/build/utils/date-utils.js +542 -0
- package/build/utils/resolver-utils.js +135 -0
- package/build/utils/sponsor-service.js +93 -0
- package/build/utils/token-utils.js +49 -0
- package/package.json +77 -0
- package/smithery.yaml +23 -0
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SPDX-FileCopyrightText: © 2025 Talib Kareem <taazkareem@icloud.com>
|
|
3
|
+
* SPDX-License-Identifier: MIT
|
|
4
|
+
*
|
|
5
|
+
* ClickUp Task Service
|
|
6
|
+
*
|
|
7
|
+
* Complete task service combining all task-related functionality
|
|
8
|
+
*
|
|
9
|
+
* REFACTORED: Now uses composition instead of linear inheritance.
|
|
10
|
+
* Extends TaskServiceCore and composes other services as properties.
|
|
11
|
+
*/
|
|
12
|
+
import { TaskServiceCore } from './task-core.js';
|
|
13
|
+
import { TaskServiceSearch } from './task-search.js';
|
|
14
|
+
import { TaskServiceAttachments } from './task-attachments.js';
|
|
15
|
+
import { TaskServiceComments } from './task-comments.js';
|
|
16
|
+
import { TaskServiceTags } from './task-tags.js';
|
|
17
|
+
import { TaskServiceCustomFields } from './task-custom-fields.js';
|
|
18
|
+
/**
|
|
19
|
+
* Complete TaskService combining all task-related functionality
|
|
20
|
+
*
|
|
21
|
+
* This service uses composition to provide access to all task operations
|
|
22
|
+
* while maintaining clean separation of concerns and eliminating artificial
|
|
23
|
+
* dependencies between service modules.
|
|
24
|
+
*/
|
|
25
|
+
export class TaskService extends TaskServiceCore {
|
|
26
|
+
constructor(apiKey, teamId, baseUrl, workspaceService) {
|
|
27
|
+
super(apiKey, teamId, baseUrl, workspaceService);
|
|
28
|
+
this.logOperation('constructor', { initialized: true });
|
|
29
|
+
// Initialize composed services with core as dependency
|
|
30
|
+
this.search = new TaskServiceSearch(this);
|
|
31
|
+
this.attachments = new TaskServiceAttachments(this);
|
|
32
|
+
this.comments = new TaskServiceComments(this);
|
|
33
|
+
this.tags = new TaskServiceTags(this);
|
|
34
|
+
this.customFields = new TaskServiceCustomFields(this);
|
|
35
|
+
}
|
|
36
|
+
// ===== DELEGATED SEARCH METHODS =====
|
|
37
|
+
async findTaskByName(listId, taskName) {
|
|
38
|
+
return this.search.findTaskByName(listId, taskName);
|
|
39
|
+
}
|
|
40
|
+
async getWorkspaceTasks(filters = {}) {
|
|
41
|
+
return this.search.getWorkspaceTasks(filters);
|
|
42
|
+
}
|
|
43
|
+
async getTaskSummaries(filters = {}) {
|
|
44
|
+
return this.search.getTaskSummaries(filters);
|
|
45
|
+
}
|
|
46
|
+
async getListViews(listId) {
|
|
47
|
+
return this.search.getListViews(listId);
|
|
48
|
+
}
|
|
49
|
+
async getTasksFromView(viewId, filters = {}) {
|
|
50
|
+
return this.search.getTasksFromView(viewId, filters);
|
|
51
|
+
}
|
|
52
|
+
async getTaskDetails(filters = {}) {
|
|
53
|
+
return this.search.getTaskDetails(filters);
|
|
54
|
+
}
|
|
55
|
+
async updateTaskByName(listId, taskName, updateData) {
|
|
56
|
+
return this.search.updateTaskByName(listId, taskName, updateData);
|
|
57
|
+
}
|
|
58
|
+
async findTaskByNameGlobally(taskName) {
|
|
59
|
+
return this.search.findTaskByNameGlobally(taskName);
|
|
60
|
+
}
|
|
61
|
+
async findTasks(params) {
|
|
62
|
+
return this.search.findTasks(params);
|
|
63
|
+
}
|
|
64
|
+
// ===== DELEGATED ATTACHMENT METHODS =====
|
|
65
|
+
async uploadTaskAttachment(taskId, fileData, fileName) {
|
|
66
|
+
return this.attachments.uploadTaskAttachment(taskId, fileData, fileName);
|
|
67
|
+
}
|
|
68
|
+
async uploadTaskAttachmentFromUrl(taskId, fileUrl, fileName, authHeader) {
|
|
69
|
+
return this.attachments.uploadTaskAttachmentFromUrl(taskId, fileUrl, fileName, authHeader);
|
|
70
|
+
}
|
|
71
|
+
// ===== DELEGATED COMMENT METHODS =====
|
|
72
|
+
async getTaskComments(taskId, start, startId) {
|
|
73
|
+
return this.comments.getTaskComments(taskId, start, startId);
|
|
74
|
+
}
|
|
75
|
+
async createTaskComment(taskId, commentText, notifyAll, assignee) {
|
|
76
|
+
return this.comments.createTaskComment(taskId, commentText, notifyAll, assignee);
|
|
77
|
+
}
|
|
78
|
+
// ===== DELEGATED TAG METHODS =====
|
|
79
|
+
async addTagToTask(taskId, tagName) {
|
|
80
|
+
return this.tags.addTagToTask(taskId, tagName);
|
|
81
|
+
}
|
|
82
|
+
async removeTagFromTask(taskId, tagName) {
|
|
83
|
+
return this.tags.removeTagFromTask(taskId, tagName);
|
|
84
|
+
}
|
|
85
|
+
async getTaskTags(taskId) {
|
|
86
|
+
return this.tags.getTaskTags(taskId);
|
|
87
|
+
}
|
|
88
|
+
async updateTaskTags(taskId, tagNames) {
|
|
89
|
+
return this.tags.updateTaskTags(taskId, tagNames);
|
|
90
|
+
}
|
|
91
|
+
// ===== DELEGATED CUSTOM FIELD METHODS =====
|
|
92
|
+
async setCustomFieldValue(taskId, fieldId, value) {
|
|
93
|
+
return this.customFields.setCustomFieldValue(taskId, fieldId, value);
|
|
94
|
+
}
|
|
95
|
+
async setCustomFieldValues(taskId, customFields) {
|
|
96
|
+
return this.customFields.setCustomFieldValues(taskId, customFields);
|
|
97
|
+
}
|
|
98
|
+
async getCustomFieldValues(taskId) {
|
|
99
|
+
return this.customFields.getCustomFieldValues(taskId);
|
|
100
|
+
}
|
|
101
|
+
async getCustomFieldValue(taskId, fieldId) {
|
|
102
|
+
return this.customFields.getCustomFieldValue(taskId, fieldId);
|
|
103
|
+
}
|
|
104
|
+
}
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SPDX-FileCopyrightText: © 2025 Talib Kareem <taazkareem@icloud.com>
|
|
3
|
+
* SPDX-License-Identifier: MIT
|
|
4
|
+
*
|
|
5
|
+
* ClickUp Task Service - Tags Module
|
|
6
|
+
*
|
|
7
|
+
* Handles tag operations for ClickUp tasks, including:
|
|
8
|
+
* - Adding tags to a task
|
|
9
|
+
* - Removing tags from a task
|
|
10
|
+
*
|
|
11
|
+
* REFACTORED: Now uses composition instead of inheritance.
|
|
12
|
+
* Only depends on TaskServiceCore for getTask() and base functionality.
|
|
13
|
+
*/
|
|
14
|
+
/**
|
|
15
|
+
* Tags functionality for the TaskService
|
|
16
|
+
*
|
|
17
|
+
* This service handles all tag-related operations for ClickUp tasks.
|
|
18
|
+
* It uses composition to access core functionality instead of inheritance.
|
|
19
|
+
*/
|
|
20
|
+
export class TaskServiceTags {
|
|
21
|
+
constructor(core) {
|
|
22
|
+
this.core = core;
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Add a tag to a task
|
|
26
|
+
*
|
|
27
|
+
* @param taskId ID of the task
|
|
28
|
+
* @param tagName Name of the tag to add
|
|
29
|
+
* @returns Success response
|
|
30
|
+
*/
|
|
31
|
+
async addTagToTask(taskId, tagName) {
|
|
32
|
+
this.core.logOperation('addTagToTask', { taskId, tagName });
|
|
33
|
+
try {
|
|
34
|
+
const payload = {
|
|
35
|
+
tag_name: tagName,
|
|
36
|
+
};
|
|
37
|
+
await this.core.makeRequest(async () => {
|
|
38
|
+
return await this.core.client.post(`/task/${taskId}/tag/${encodeURIComponent(tagName)}`, payload);
|
|
39
|
+
});
|
|
40
|
+
return true;
|
|
41
|
+
}
|
|
42
|
+
catch (error) {
|
|
43
|
+
throw this.core.handleError(error, `Failed to add tag "${tagName}" to task`);
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Remove a tag from a task
|
|
48
|
+
*
|
|
49
|
+
* @param taskId ID of the task
|
|
50
|
+
* @param tagName Name of the tag to remove
|
|
51
|
+
* @returns Success response
|
|
52
|
+
*/
|
|
53
|
+
async removeTagFromTask(taskId, tagName) {
|
|
54
|
+
this.core.logOperation('removeTagFromTask', { taskId, tagName });
|
|
55
|
+
try {
|
|
56
|
+
await this.core.makeRequest(async () => {
|
|
57
|
+
return await this.core.client.delete(`/task/${taskId}/tag/${encodeURIComponent(tagName)}`);
|
|
58
|
+
});
|
|
59
|
+
return true;
|
|
60
|
+
}
|
|
61
|
+
catch (error) {
|
|
62
|
+
throw this.core.handleError(error, `Failed to remove tag "${tagName}" from task`);
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* Get all tags for a task
|
|
67
|
+
*
|
|
68
|
+
* @param taskId ID of the task
|
|
69
|
+
* @returns Array of task tags
|
|
70
|
+
*/
|
|
71
|
+
async getTaskTags(taskId) {
|
|
72
|
+
this.core.logOperation('getTaskTags', { taskId });
|
|
73
|
+
try {
|
|
74
|
+
// We need to fetch the full task to get its tags
|
|
75
|
+
const task = await this.core.getTask(taskId);
|
|
76
|
+
return task.tags || [];
|
|
77
|
+
}
|
|
78
|
+
catch (error) {
|
|
79
|
+
throw this.core.handleError(error, 'Failed to get task tags');
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* Update all tags for a task (replaces existing tags)
|
|
84
|
+
*
|
|
85
|
+
* @param taskId ID of the task
|
|
86
|
+
* @param tagNames Array of tag names to set
|
|
87
|
+
* @returns Success response
|
|
88
|
+
*/
|
|
89
|
+
async updateTaskTags(taskId, tagNames) {
|
|
90
|
+
this.core.logOperation('updateTaskTags', { taskId, tagNames });
|
|
91
|
+
try {
|
|
92
|
+
// First get existing tags
|
|
93
|
+
const existingTags = await this.getTaskTags(taskId);
|
|
94
|
+
const existingTagNames = existingTags.map(tag => tag.name);
|
|
95
|
+
// Remove tags that shouldn't be there
|
|
96
|
+
for (const tagName of existingTagNames) {
|
|
97
|
+
if (!tagNames.includes(tagName)) {
|
|
98
|
+
await this.removeTagFromTask(taskId, tagName);
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
// Add new tags
|
|
102
|
+
for (const tagName of tagNames) {
|
|
103
|
+
if (!existingTagNames.includes(tagName)) {
|
|
104
|
+
await this.addTagToTask(taskId, tagName);
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
return true;
|
|
108
|
+
}
|
|
109
|
+
catch (error) {
|
|
110
|
+
throw this.core.handleError(error, 'Failed to update task tags');
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
}
|
|
@@ -0,0 +1,244 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SPDX-FileCopyrightText: © 2025 Talib Kareem <taazkareem@icloud.com>
|
|
3
|
+
* SPDX-License-Identifier: MIT
|
|
4
|
+
*
|
|
5
|
+
* Time tracking service for ClickUp tasks
|
|
6
|
+
*
|
|
7
|
+
* This service provides methods to manage time tracking for ClickUp tasks:
|
|
8
|
+
* - Get time entries for a task
|
|
9
|
+
* - Start time tracking on a task
|
|
10
|
+
* - Stop time tracking on a task
|
|
11
|
+
* - Add a manual time entry
|
|
12
|
+
* - Delete a time entry
|
|
13
|
+
*/
|
|
14
|
+
import { BaseClickUpService, ErrorCode, ClickUpServiceError } from './base.js';
|
|
15
|
+
/**
|
|
16
|
+
* Time tracking service for ClickUp
|
|
17
|
+
*/
|
|
18
|
+
export class TimeTrackingService extends BaseClickUpService {
|
|
19
|
+
/**
|
|
20
|
+
* Get all time entries for a task
|
|
21
|
+
* @param taskId ID of the task
|
|
22
|
+
* @param startDate Optional start date filter (Unix timestamp in milliseconds)
|
|
23
|
+
* @param endDate Optional end date filter (Unix timestamp in milliseconds)
|
|
24
|
+
* @returns List of time entries
|
|
25
|
+
*/
|
|
26
|
+
async getTimeEntries(taskId, startDate, endDate) {
|
|
27
|
+
try {
|
|
28
|
+
this.logOperation('getTimeEntries', { taskId, startDate, endDate });
|
|
29
|
+
// Build query parameters
|
|
30
|
+
let query = {};
|
|
31
|
+
if (startDate)
|
|
32
|
+
query.start_date = startDate;
|
|
33
|
+
if (endDate)
|
|
34
|
+
query.end_date = endDate;
|
|
35
|
+
const path = `/task/${taskId}/time`;
|
|
36
|
+
this.traceRequest('GET', path, query);
|
|
37
|
+
const response = await this.makeRequest(() => this.client.get(path, {
|
|
38
|
+
params: query
|
|
39
|
+
}));
|
|
40
|
+
return {
|
|
41
|
+
success: true,
|
|
42
|
+
data: response.data.data
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
catch (error) {
|
|
46
|
+
if (error instanceof ClickUpServiceError) {
|
|
47
|
+
return {
|
|
48
|
+
success: false,
|
|
49
|
+
error: {
|
|
50
|
+
message: error.message,
|
|
51
|
+
code: error.code,
|
|
52
|
+
details: error.data
|
|
53
|
+
}
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
return {
|
|
57
|
+
success: false,
|
|
58
|
+
error: {
|
|
59
|
+
message: `Failed to get time entries: ${error.message}`,
|
|
60
|
+
code: ErrorCode.UNKNOWN
|
|
61
|
+
}
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* Start time tracking on a task
|
|
67
|
+
* @param data Task ID and optional parameters
|
|
68
|
+
* @returns The created time entry
|
|
69
|
+
*/
|
|
70
|
+
async startTimeTracking(data) {
|
|
71
|
+
try {
|
|
72
|
+
this.logOperation('startTimeTracking', { taskId: data.tid });
|
|
73
|
+
const path = `/team/${this.teamId}/time_entries/start`;
|
|
74
|
+
this.traceRequest('POST', path, data);
|
|
75
|
+
const response = await this.makeRequest(() => this.client.post(path, data));
|
|
76
|
+
return {
|
|
77
|
+
success: true,
|
|
78
|
+
data: response.data.data
|
|
79
|
+
};
|
|
80
|
+
}
|
|
81
|
+
catch (error) {
|
|
82
|
+
if (error instanceof ClickUpServiceError) {
|
|
83
|
+
return {
|
|
84
|
+
success: false,
|
|
85
|
+
error: {
|
|
86
|
+
message: error.message,
|
|
87
|
+
code: error.code,
|
|
88
|
+
details: error.data
|
|
89
|
+
}
|
|
90
|
+
};
|
|
91
|
+
}
|
|
92
|
+
return {
|
|
93
|
+
success: false,
|
|
94
|
+
error: {
|
|
95
|
+
message: `Failed to start time tracking: ${error.message}`,
|
|
96
|
+
code: ErrorCode.UNKNOWN
|
|
97
|
+
}
|
|
98
|
+
};
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
/**
|
|
102
|
+
* Stop the currently running time tracker
|
|
103
|
+
* @param data Optional parameters for the stopped time entry
|
|
104
|
+
* @returns The completed time entry
|
|
105
|
+
*/
|
|
106
|
+
async stopTimeTracking(data) {
|
|
107
|
+
try {
|
|
108
|
+
this.logOperation('stopTimeTracking', {});
|
|
109
|
+
const path = `/team/${this.teamId}/time_entries/stop`;
|
|
110
|
+
this.traceRequest('POST', path, data || {});
|
|
111
|
+
const response = await this.makeRequest(() => this.client.post(path, data || {}));
|
|
112
|
+
return {
|
|
113
|
+
success: true,
|
|
114
|
+
data: response.data.data
|
|
115
|
+
};
|
|
116
|
+
}
|
|
117
|
+
catch (error) {
|
|
118
|
+
if (error instanceof ClickUpServiceError) {
|
|
119
|
+
return {
|
|
120
|
+
success: false,
|
|
121
|
+
error: {
|
|
122
|
+
message: error.message,
|
|
123
|
+
code: error.code,
|
|
124
|
+
details: error.data
|
|
125
|
+
}
|
|
126
|
+
};
|
|
127
|
+
}
|
|
128
|
+
return {
|
|
129
|
+
success: false,
|
|
130
|
+
error: {
|
|
131
|
+
message: `Failed to stop time tracking: ${error.message}`,
|
|
132
|
+
code: ErrorCode.UNKNOWN
|
|
133
|
+
}
|
|
134
|
+
};
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
/**
|
|
138
|
+
* Add a manual time entry to a task
|
|
139
|
+
* @param data Time entry data including task ID, start time, and duration
|
|
140
|
+
* @returns The created time entry
|
|
141
|
+
*/
|
|
142
|
+
async addTimeEntry(data) {
|
|
143
|
+
try {
|
|
144
|
+
this.logOperation('addTimeEntry', { taskId: data.tid, duration: data.duration });
|
|
145
|
+
const path = `/team/${this.teamId}/time_entries`;
|
|
146
|
+
this.traceRequest('POST', path, data);
|
|
147
|
+
const response = await this.makeRequest(() => this.client.post(path, data));
|
|
148
|
+
return {
|
|
149
|
+
success: true,
|
|
150
|
+
data: response.data.data
|
|
151
|
+
};
|
|
152
|
+
}
|
|
153
|
+
catch (error) {
|
|
154
|
+
if (error instanceof ClickUpServiceError) {
|
|
155
|
+
return {
|
|
156
|
+
success: false,
|
|
157
|
+
error: {
|
|
158
|
+
message: error.message,
|
|
159
|
+
code: error.code,
|
|
160
|
+
details: error.data
|
|
161
|
+
}
|
|
162
|
+
};
|
|
163
|
+
}
|
|
164
|
+
return {
|
|
165
|
+
success: false,
|
|
166
|
+
error: {
|
|
167
|
+
message: `Failed to add time entry: ${error.message}`,
|
|
168
|
+
code: ErrorCode.UNKNOWN
|
|
169
|
+
}
|
|
170
|
+
};
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
/**
|
|
174
|
+
* Delete a time entry
|
|
175
|
+
* @param timeEntryId ID of the time entry to delete
|
|
176
|
+
* @returns Success response
|
|
177
|
+
*/
|
|
178
|
+
async deleteTimeEntry(timeEntryId) {
|
|
179
|
+
try {
|
|
180
|
+
this.logOperation('deleteTimeEntry', { timeEntryId });
|
|
181
|
+
const path = `/team/${this.teamId}/time_entries/${timeEntryId}`;
|
|
182
|
+
this.traceRequest('DELETE', path);
|
|
183
|
+
await this.makeRequest(() => this.client.delete(path));
|
|
184
|
+
return {
|
|
185
|
+
success: true,
|
|
186
|
+
data: true
|
|
187
|
+
};
|
|
188
|
+
}
|
|
189
|
+
catch (error) {
|
|
190
|
+
if (error instanceof ClickUpServiceError) {
|
|
191
|
+
return {
|
|
192
|
+
success: false,
|
|
193
|
+
error: {
|
|
194
|
+
message: error.message,
|
|
195
|
+
code: error.code,
|
|
196
|
+
details: error.data
|
|
197
|
+
}
|
|
198
|
+
};
|
|
199
|
+
}
|
|
200
|
+
return {
|
|
201
|
+
success: false,
|
|
202
|
+
error: {
|
|
203
|
+
message: `Failed to delete time entry: ${error.message}`,
|
|
204
|
+
code: ErrorCode.UNKNOWN
|
|
205
|
+
}
|
|
206
|
+
};
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
/**
|
|
210
|
+
* Get currently running time entry for the user
|
|
211
|
+
* @returns The currently running time entry or null if no timer is running
|
|
212
|
+
*/
|
|
213
|
+
async getCurrentTimeEntry() {
|
|
214
|
+
try {
|
|
215
|
+
this.logOperation('getCurrentTimeEntry', {});
|
|
216
|
+
const path = `/team/${this.teamId}/time_entries/current`;
|
|
217
|
+
this.traceRequest('GET', path);
|
|
218
|
+
const response = await this.makeRequest(() => this.client.get(path));
|
|
219
|
+
return {
|
|
220
|
+
success: true,
|
|
221
|
+
data: response.data.data
|
|
222
|
+
};
|
|
223
|
+
}
|
|
224
|
+
catch (error) {
|
|
225
|
+
if (error instanceof ClickUpServiceError) {
|
|
226
|
+
return {
|
|
227
|
+
success: false,
|
|
228
|
+
error: {
|
|
229
|
+
message: error.message,
|
|
230
|
+
code: error.code,
|
|
231
|
+
details: error.data
|
|
232
|
+
}
|
|
233
|
+
};
|
|
234
|
+
}
|
|
235
|
+
return {
|
|
236
|
+
success: false,
|
|
237
|
+
error: {
|
|
238
|
+
message: `Failed to get current time entry: ${error.message}`,
|
|
239
|
+
code: ErrorCode.UNKNOWN
|
|
240
|
+
}
|
|
241
|
+
};
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SPDX-FileCopyrightText: © 2025 Talib Kareem <taazkareem@icloud.com>
|
|
3
|
+
* SPDX-License-Identifier: MIT
|
|
4
|
+
*
|
|
5
|
+
* Common type definitions for ClickUp API entities
|
|
6
|
+
*/
|
|
7
|
+
// Helper function to validate and convert priority values
|
|
8
|
+
export function toTaskPriority(value) {
|
|
9
|
+
if (value === null)
|
|
10
|
+
return null;
|
|
11
|
+
if (value === undefined)
|
|
12
|
+
return undefined;
|
|
13
|
+
if (value === "null")
|
|
14
|
+
return null;
|
|
15
|
+
// Convert string to number if needed
|
|
16
|
+
const numValue = typeof value === 'string' ? parseInt(value, 10) : value;
|
|
17
|
+
// Validate it's a valid priority number
|
|
18
|
+
if (typeof numValue === 'number' && !isNaN(numValue) && [1, 2, 3, 4].includes(numValue)) {
|
|
19
|
+
return numValue;
|
|
20
|
+
}
|
|
21
|
+
return undefined;
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* ClickUp parent container types
|
|
25
|
+
*/
|
|
26
|
+
export var ClickUpParentType;
|
|
27
|
+
(function (ClickUpParentType) {
|
|
28
|
+
ClickUpParentType[ClickUpParentType["Space"] = 4] = "Space";
|
|
29
|
+
ClickUpParentType[ClickUpParentType["Folder"] = 5] = "Folder";
|
|
30
|
+
ClickUpParentType[ClickUpParentType["List"] = 6] = "List";
|
|
31
|
+
ClickUpParentType[ClickUpParentType["All"] = 7] = "All";
|
|
32
|
+
ClickUpParentType[ClickUpParentType["Workspace"] = 12] = "Workspace";
|
|
33
|
+
})(ClickUpParentType || (ClickUpParentType = {}));
|