@codegame.dev/careerflow-mcp 1.1.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.
Files changed (47) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +398 -0
  3. package/dist/client.js +110 -0
  4. package/dist/client.js.map +1 -0
  5. package/dist/config.js +37 -0
  6. package/dist/config.js.map +1 -0
  7. package/dist/helpers.js +192 -0
  8. package/dist/helpers.js.map +1 -0
  9. package/dist/index.js +194 -0
  10. package/dist/index.js.map +1 -0
  11. package/dist/setup.js +296 -0
  12. package/dist/setup.js.map +1 -0
  13. package/dist/tools/admin.js +232 -0
  14. package/dist/tools/admin.js.map +1 -0
  15. package/dist/tools/benefit-funds.js +243 -0
  16. package/dist/tools/benefit-funds.js.map +1 -0
  17. package/dist/tools/chat-extra.js +172 -0
  18. package/dist/tools/chat-extra.js.map +1 -0
  19. package/dist/tools/chat.js +125 -0
  20. package/dist/tools/chat.js.map +1 -0
  21. package/dist/tools/cms.js +145 -0
  22. package/dist/tools/cms.js.map +1 -0
  23. package/dist/tools/crm-admin.js +269 -0
  24. package/dist/tools/crm-admin.js.map +1 -0
  25. package/dist/tools/crm.js +632 -0
  26. package/dist/tools/crm.js.map +1 -0
  27. package/dist/tools/dev-tickets.js +94 -0
  28. package/dist/tools/dev-tickets.js.map +1 -0
  29. package/dist/tools/forms.js +105 -0
  30. package/dist/tools/forms.js.map +1 -0
  31. package/dist/tools/hr.js +517 -0
  32. package/dist/tools/hr.js.map +1 -0
  33. package/dist/tools/kanban-extra.js +403 -0
  34. package/dist/tools/kanban-extra.js.map +1 -0
  35. package/dist/tools/misc.js +159 -0
  36. package/dist/tools/misc.js.map +1 -0
  37. package/dist/tools/projects.js +138 -0
  38. package/dist/tools/projects.js.map +1 -0
  39. package/dist/tools/tasks.js +342 -0
  40. package/dist/tools/tasks.js.map +1 -0
  41. package/dist/tools/time.js +129 -0
  42. package/dist/tools/time.js.map +1 -0
  43. package/dist/tools/workplace.js +110 -0
  44. package/dist/tools/workplace.js.map +1 -0
  45. package/dist/tools/workspace.js +199 -0
  46. package/dist/tools/workspace.js.map +1 -0
  47. package/package.json +61 -0
@@ -0,0 +1,138 @@
1
+ import { z } from "zod";
2
+ import { companyIdSchema, resolveCompanyId, safeHandler, textResult } from "../helpers.js";
3
+ /**
4
+ * Project administration tools: creating and configuring projects, and
5
+ * managing who belongs to them. Everyday task tools already resolve
6
+ * project/board ids via list_projects/list_boards — these are for changing the
7
+ * projects themselves.
8
+ */
9
+ export function registerProjectTools(server, client) {
10
+ server.registerTool("create_project", {
11
+ title: "Create a project",
12
+ description: "Create a project. 'special' projects carry a due date and completion/late bonuses; " +
13
+ "'normal' projects don't.",
14
+ inputSchema: {
15
+ company_id: companyIdSchema,
16
+ name: z.string().min(1),
17
+ description: z.string().optional(),
18
+ type: z.enum(["normal", "special"]).optional().default("normal"),
19
+ due_date: z.string().optional().describe("Only meaningful for type 'special'."),
20
+ completion_bonus: z.number().optional(),
21
+ late_penalty: z.number().optional(),
22
+ priority: z.enum(["low", "medium", "high", "urgent"]).optional().default("medium"),
23
+ allow_editor_create_tasks: z.boolean().optional(),
24
+ is_manager: z.boolean().optional().describe("Add the caller as the project's manager immediately.")
25
+ }
26
+ }, safeHandler(async (args) => {
27
+ const companyId = resolveCompanyId(client, args.company_id);
28
+ const response = await client.post("projects/create", {
29
+ company_id: companyId,
30
+ name: args.name,
31
+ description: args.description,
32
+ type: args.type,
33
+ due_date: args.due_date,
34
+ completion_bonus: args.completion_bonus,
35
+ late_penalty: args.late_penalty,
36
+ priority: args.priority,
37
+ allow_editor_create_tasks: args.allow_editor_create_tasks,
38
+ is_manager: args.is_manager
39
+ });
40
+ return textResult({ created: true, project: response.data });
41
+ }));
42
+ server.registerTool("update_project", {
43
+ title: "Update a project",
44
+ description: "Change a project's name, description, or (for 'special' projects) its due date and bonuses.",
45
+ inputSchema: {
46
+ company_id: companyIdSchema,
47
+ project_id: z.number().int(),
48
+ name: z.string().min(1).optional(),
49
+ description: z.string().optional(),
50
+ due_date: z.string().optional(),
51
+ completion_bonus: z.number().optional(),
52
+ late_penalty: z.number().optional(),
53
+ priority: z.enum(["low", "medium", "high", "urgent"]).optional(),
54
+ allow_editor_create_tasks: z.boolean().optional()
55
+ }
56
+ }, safeHandler(async (args) => {
57
+ const companyId = resolveCompanyId(client, args.company_id);
58
+ const response = await client.post("projects/edit", {
59
+ company_id: companyId,
60
+ id: args.project_id,
61
+ name: args.name,
62
+ description: args.description,
63
+ due_date: args.due_date,
64
+ completion_bonus: args.completion_bonus,
65
+ late_penalty: args.late_penalty,
66
+ priority: args.priority,
67
+ allow_editor_create_tasks: args.allow_editor_create_tasks
68
+ });
69
+ return textResult({ updated: true, project: response.data });
70
+ }));
71
+ server.registerTool("archive_project", {
72
+ title: "Archive or restore a project",
73
+ description: "Archive a project, or restore a previously archived one. Personal/inbox projects cannot be archived.",
74
+ inputSchema: {
75
+ company_id: companyIdSchema,
76
+ project_id: z.number().int(),
77
+ restore: z.boolean().optional().default(false)
78
+ }
79
+ }, safeHandler(async (args) => {
80
+ const companyId = resolveCompanyId(client, args.company_id);
81
+ const path = args.restore ? `projects/restore/${args.project_id}` : `projects/delete/${args.project_id}`;
82
+ await client.post(path, { company_id: companyId });
83
+ return textResult({ project_id: args.project_id, archived: !args.restore });
84
+ }));
85
+ server.registerTool("project_stats", {
86
+ title: "Get project statistics",
87
+ description: "Task-count breakdowns for a project: by board, due date, member, label, and priority.",
88
+ inputSchema: { company_id: companyIdSchema, project_id: z.number().int() }
89
+ }, safeHandler(async (args) => {
90
+ const companyId = resolveCompanyId(client, args.company_id);
91
+ const response = await client.get("projects/stats", {
92
+ company_id: companyId,
93
+ project_id: args.project_id
94
+ });
95
+ return textResult(response.data);
96
+ }));
97
+ server.registerTool("invite_project_member", {
98
+ title: "Invite or update a project member",
99
+ description: "Add a user to a project (or change their access level). Access levels: visitor (read-only), " +
100
+ "editor (can create/edit tasks), manager (full control). Omitting access removes the member.",
101
+ inputSchema: {
102
+ company_id: companyIdSchema,
103
+ project_id: z.number().int(),
104
+ user_id: z.number().int(),
105
+ access: z.enum(["visitor", "editor", "manager"]).optional().describe("Omit to remove the member."),
106
+ comment: z.string().optional()
107
+ }
108
+ }, safeHandler(async (args) => {
109
+ const companyId = resolveCompanyId(client, args.company_id);
110
+ const response = await client.post("projects/users/edit", {
111
+ company_id: companyId,
112
+ project_id: args.project_id,
113
+ user_id: args.user_id,
114
+ request_type: "intra-company",
115
+ type: args.access,
116
+ comment: args.comment
117
+ });
118
+ return textResult({ project_id: args.project_id, user_id: args.user_id, project_users: response.data });
119
+ }));
120
+ server.registerTool("authorize_project_member", {
121
+ title: "Accept or reject a project membership request",
122
+ description: "Approve or deny a pending request to join a project.",
123
+ inputSchema: {
124
+ company_id: companyIdSchema,
125
+ project_user_id: z.number().int(),
126
+ status: z.enum(["accepted", "rejected"])
127
+ }
128
+ }, safeHandler(async (args) => {
129
+ const companyId = resolveCompanyId(client, args.company_id);
130
+ const response = await client.post("projects/users/authorize", {
131
+ company_id: companyId,
132
+ project_user_id: args.project_user_id,
133
+ status: args.status
134
+ });
135
+ return textResult({ updated: true, project_user: response.data });
136
+ }));
137
+ }
138
+ //# sourceMappingURL=projects.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"projects.js","sourceRoot":"","sources":["../../src/tools/projects.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,342 @@
1
+ import { z } from "zod";
2
+ import { boolParam, companyIdSchema, extractList, currentUserId, fetchTask, mergeTaskEdit, resolveCompanyId, safeHandler, summariseTask, textResult } from "../helpers.js";
3
+ const prioritySchema = z.enum(["low", "medium", "high", "urgent"]);
4
+ /**
5
+ * Task tools — the day-to-day surface for staff and supervisors.
6
+ *
7
+ * Every write goes through the same REST endpoints the web app uses, so the
8
+ * caller's existing project role still decides what actually succeeds; these
9
+ * tools add no privilege of their own.
10
+ */
11
+ export function registerTaskTools(server, client) {
12
+ server.registerTool("list_my_tasks", {
13
+ title: "List my tasks",
14
+ description: "List tasks assigned to the authenticated user. Use this for 'what am I working on', " +
15
+ "'what's due', or 'what's overdue'. Returns open tasks by default.",
16
+ inputSchema: {
17
+ company_id: companyIdSchema,
18
+ project_id: z.number().int().optional().describe("Restrict to one project."),
19
+ is_completed: z
20
+ .boolean()
21
+ .optional()
22
+ .describe("Filter by completion. Omit to return both open and completed tasks."),
23
+ is_overdue: z.boolean().optional().describe("Only tasks past their due date."),
24
+ search: z.string().optional().describe("Free-text match on the task title."),
25
+ limit: z.number().int().min(1).max(50).optional().default(20),
26
+ page: z.number().int().min(1).optional().default(1),
27
+ order_by: z.enum(["created", "updated", "num", "global_num"]).optional().default("updated"),
28
+ direction: z.enum(["asc", "desc"]).optional().default("desc")
29
+ }
30
+ }, safeHandler(async (args) => {
31
+ const companyId = resolveCompanyId(client, args.company_id);
32
+ const myId = await currentUserId(client);
33
+ const response = await client.get("kanbans/tasks/search", {
34
+ company_id: companyId,
35
+ member_id: myId,
36
+ project_id: args.project_id,
37
+ is_completed: boolParam(args.is_completed),
38
+ is_overdue: boolParam(args.is_overdue),
39
+ search: args.search,
40
+ limit: args.limit,
41
+ page: args.page,
42
+ order_by: args.order_by,
43
+ direction: args.direction
44
+ });
45
+ const { items: tasks, total } = extractList(response.data, "tasks");
46
+ return textResult({ count: total ?? tasks.length, tasks: tasks.map(summariseTask) });
47
+ }));
48
+ server.registerTool("search_tasks", {
49
+ title: "Search tasks",
50
+ description: "Search tasks across a company or project, optionally filtered by assignee or supervisor. " +
51
+ "Supervisors use member_id to see one report's work, or supervisor_id to see a whole team's.",
52
+ inputSchema: {
53
+ company_id: companyIdSchema,
54
+ project_id: z.number().int().optional(),
55
+ member_id: z.number().int().optional().describe("Only tasks assigned to this user id."),
56
+ supervisor_id: z
57
+ .number()
58
+ .int()
59
+ .optional()
60
+ .describe("Tasks belonging to everyone reporting to this supervisor id."),
61
+ search: z.string().optional(),
62
+ is_completed: z.boolean().optional(),
63
+ is_overdue: z.boolean().optional(),
64
+ review_status: z
65
+ .enum(["pending", "accepted"])
66
+ .optional()
67
+ .describe("Filter by review state; 'pending' finds work awaiting a supervisor's review."),
68
+ from_date: z.string().optional().describe("Lower date bound, YYYY-MM-DD."),
69
+ to_date: z.string().optional().describe("Upper date bound, YYYY-MM-DD."),
70
+ date_target: z
71
+ .enum(["created", "updated", "completion_date", "member_date"])
72
+ .optional()
73
+ .describe("Which date the from/to bounds apply to."),
74
+ limit: z.number().int().min(1).max(50).optional().default(20),
75
+ page: z.number().int().min(1).optional().default(1),
76
+ order_by: z.enum(["created", "updated", "num", "global_num"]).optional().default("updated"),
77
+ direction: z.enum(["asc", "desc"]).optional().default("desc")
78
+ }
79
+ }, safeHandler(async (args) => {
80
+ const companyId = resolveCompanyId(client, args.company_id);
81
+ const response = await client.get("kanbans/tasks/search", {
82
+ company_id: companyId,
83
+ project_id: args.project_id,
84
+ member_id: args.member_id,
85
+ supervisor_id: args.supervisor_id,
86
+ search: args.search,
87
+ is_completed: boolParam(args.is_completed),
88
+ is_overdue: boolParam(args.is_overdue),
89
+ review_status: args.review_status,
90
+ from_date: args.from_date,
91
+ to_date: args.to_date,
92
+ date_target: args.date_target,
93
+ limit: args.limit,
94
+ page: args.page,
95
+ order_by: args.order_by,
96
+ direction: args.direction
97
+ });
98
+ const { items: tasks, total } = extractList(response.data, "tasks");
99
+ return textResult({ count: total ?? tasks.length, tasks: tasks.map(summariseTask) });
100
+ }));
101
+ server.registerTool("get_task", {
102
+ title: "Get a task",
103
+ description: "Fetch one task in full by its id, including members, labels and checklists.",
104
+ inputSchema: {
105
+ company_id: companyIdSchema,
106
+ task_id: z.number().int().describe("The task id.")
107
+ }
108
+ }, safeHandler(async (args) => {
109
+ const companyId = resolveCompanyId(client, args.company_id);
110
+ const task = await fetchTask(client, companyId, args.task_id);
111
+ return textResult(summariseTask(task));
112
+ }));
113
+ server.registerTool("create_task", {
114
+ title: "Create a task",
115
+ description: "Create a task on a board. Requires the project and board ids — use list_projects and " +
116
+ "list_boards first when they are not already known.",
117
+ inputSchema: {
118
+ company_id: companyIdSchema,
119
+ project_id: z.number().int(),
120
+ board_id: z.number().int().describe("The board (column) the task is created in."),
121
+ title: z.string().min(1),
122
+ description: z.string().optional(),
123
+ assigned_user_id: z
124
+ .number()
125
+ .int()
126
+ .optional()
127
+ .describe("User to assign. Must already be an accepted member of the project."),
128
+ priority: prioritySchema.optional().default("medium"),
129
+ start_date: z.string().optional().describe("YYYY-MM-DD HH:MM:SS"),
130
+ due_date: z.string().optional().describe("YYYY-MM-DD HH:MM:SS"),
131
+ time_estimate_minutes: z.number().int().min(0).max(3600).optional()
132
+ }
133
+ }, safeHandler(async (args) => {
134
+ const companyId = resolveCompanyId(client, args.company_id);
135
+ const response = await client.post("kanbans/tasks/create", {
136
+ company_id: companyId,
137
+ project_id: args.project_id,
138
+ board_id: args.board_id,
139
+ title: args.title,
140
+ description: args.description,
141
+ assigned_user_id: args.assigned_user_id,
142
+ priority: args.priority,
143
+ start_date: args.start_date,
144
+ due_date: args.due_date,
145
+ time_estimate_minutes: args.time_estimate_minutes
146
+ });
147
+ const task = response.data?.task;
148
+ return textResult({
149
+ created: true,
150
+ task: task ? summariseTask(task) : undefined
151
+ });
152
+ }));
153
+ server.registerTool("update_task", {
154
+ title: "Update a task",
155
+ description: "Change fields on an existing task. Only the fields passed are altered — the task is read " +
156
+ "first and unmentioned fields keep their current values.",
157
+ inputSchema: {
158
+ company_id: companyIdSchema,
159
+ task_id: z.number().int(),
160
+ title: z.string().min(1).optional(),
161
+ description: z.string().optional(),
162
+ priority: prioritySchema.optional(),
163
+ start_date: z.string().nullable().optional().describe("YYYY-MM-DD HH:MM:SS, or null to clear."),
164
+ due_date: z.string().nullable().optional().describe("YYYY-MM-DD HH:MM:SS, or null to clear."),
165
+ time_estimate_minutes: z.number().int().min(0).nullable().optional()
166
+ }
167
+ }, safeHandler(async (args) => {
168
+ const companyId = resolveCompanyId(client, args.company_id);
169
+ const current = await fetchTask(client, companyId, args.task_id);
170
+ const body = mergeTaskEdit(current, companyId, {
171
+ title: args.title,
172
+ description: args.description,
173
+ priority: args.priority,
174
+ start_date: args.start_date,
175
+ due_date: args.due_date,
176
+ time_estimate_minutes: args.time_estimate_minutes
177
+ });
178
+ const response = await client.post("kanbans/tasks/edit", body);
179
+ const task = response.data?.task;
180
+ return textResult({ updated: true, task: task ? summariseTask(task) : undefined });
181
+ }));
182
+ server.registerTool("complete_task", {
183
+ title: "Complete or reopen a task",
184
+ description: "Mark a task complete, or reopen it with completed=false. Other fields are preserved.",
185
+ inputSchema: {
186
+ company_id: companyIdSchema,
187
+ task_id: z.number().int(),
188
+ completed: z.boolean().optional().default(true)
189
+ }
190
+ }, safeHandler(async (args) => {
191
+ const companyId = resolveCompanyId(client, args.company_id);
192
+ const current = await fetchTask(client, companyId, args.task_id);
193
+ const body = mergeTaskEdit(current, companyId, {
194
+ is_completed: boolParam(args.completed ?? true)
195
+ });
196
+ await client.post("kanbans/tasks/edit", body);
197
+ return textResult({
198
+ task_id: args.task_id,
199
+ is_completed: args.completed ?? true,
200
+ title: current.title
201
+ });
202
+ }));
203
+ server.registerTool("assign_task", {
204
+ title: "Assign or unassign a task member",
205
+ description: "Add or remove a member on a task. The user must already be an accepted member of the " +
206
+ "task's project.",
207
+ inputSchema: {
208
+ company_id: companyIdSchema,
209
+ task_id: z.number().int(),
210
+ user_id: z.number().int().describe("The user to assign or unassign."),
211
+ assign: z.boolean().optional().default(true).describe("true adds the member, false removes them.")
212
+ }
213
+ }, safeHandler(async (args) => {
214
+ const companyId = resolveCompanyId(client, args.company_id);
215
+ const task = await fetchTask(client, companyId, args.task_id);
216
+ await client.post("kanbans/tasks/edit-member", {
217
+ company_id: companyId,
218
+ project_id: task.project_id,
219
+ board_id: task.board_id,
220
+ task_id: args.task_id,
221
+ user_id: args.user_id,
222
+ add: boolParam(args.assign ?? true)
223
+ });
224
+ return textResult({
225
+ task_id: args.task_id,
226
+ user_id: args.user_id,
227
+ assigned: args.assign ?? true
228
+ });
229
+ }));
230
+ server.registerTool("move_task", {
231
+ title: "Move a task to another board",
232
+ description: "Move a task to a different board (column), optionally in a different project — the usual " +
233
+ "way to advance work through a workflow.",
234
+ inputSchema: {
235
+ company_id: companyIdSchema,
236
+ task_id: z.number().int(),
237
+ destination_board_id: z.number().int(),
238
+ destination_project_id: z.number().int().optional().describe("Defaults to the task's current project.")
239
+ }
240
+ }, safeHandler(async (args) => {
241
+ const companyId = resolveCompanyId(client, args.company_id);
242
+ const task = await fetchTask(client, companyId, args.task_id);
243
+ await client.post("kanbans/tasks/move", {
244
+ company_id: companyId,
245
+ source_project_id: task.project_id,
246
+ source_board_id: task.board_id,
247
+ task_id: args.task_id,
248
+ destination_project_id: args.destination_project_id ?? task.project_id,
249
+ destination_board_id: args.destination_board_id,
250
+ // appended to the end of the destination board; the API renumbers
251
+ // the column afterwards, so a large sentinel is the documented way
252
+ // to say "put it last" without reading the board's current order
253
+ destination_num: 999999,
254
+ destination_global_num: 999999
255
+ });
256
+ return textResult({
257
+ task_id: args.task_id,
258
+ moved_to_board: args.destination_board_id,
259
+ title: task.title
260
+ });
261
+ }));
262
+ server.registerTool("review_task", {
263
+ title: "Review a task",
264
+ description: "Supervisor action: accept a completed task and score it 0-5, or send it back by setting " +
265
+ "review_status to 'pending'.",
266
+ inputSchema: {
267
+ company_id: companyIdSchema,
268
+ task_id: z.number().int(),
269
+ review_status: z.enum(["pending", "accepted"]),
270
+ review_score: z.number().min(0).max(5).describe("Score from 0 to 5.")
271
+ }
272
+ }, safeHandler(async (args) => {
273
+ const companyId = resolveCompanyId(client, args.company_id);
274
+ const task = await fetchTask(client, companyId, args.task_id);
275
+ await client.post("kanbans/tasks/review", {
276
+ company_id: companyId,
277
+ project_id: task.project_id,
278
+ board_id: task.board_id,
279
+ task_id: args.task_id,
280
+ review_status: args.review_status,
281
+ review_score: args.review_score
282
+ });
283
+ return textResult({
284
+ task_id: args.task_id,
285
+ review_status: args.review_status,
286
+ review_score: args.review_score
287
+ });
288
+ }));
289
+ server.registerTool("list_task_comments", {
290
+ title: "List task comments",
291
+ description: "Read the comment thread on a task.",
292
+ inputSchema: {
293
+ company_id: companyIdSchema,
294
+ task_id: z.number().int(),
295
+ limit: z.number().int().min(1).max(50).optional().default(20),
296
+ page: z.number().int().min(1).optional().default(1)
297
+ }
298
+ }, safeHandler(async (args) => {
299
+ const companyId = resolveCompanyId(client, args.company_id);
300
+ const task = await fetchTask(client, companyId, args.task_id);
301
+ const response = await client.get("kanbans/tasks/comments/search", {
302
+ company_id: companyId,
303
+ project_id: task.project_id,
304
+ board_id: task.board_id,
305
+ task_id: args.task_id,
306
+ limit: args.limit,
307
+ page: args.page
308
+ });
309
+ const { items: comments, total } = extractList(response.data, "task_comments");
310
+ return textResult({
311
+ count: total ?? comments.length,
312
+ comments: comments.map((c) => ({
313
+ id: c.id,
314
+ content: c.content,
315
+ user_id: c.user_id,
316
+ author: [c.firstname, c.lastname].filter(Boolean).join(" ") || undefined,
317
+ created: c.created
318
+ }))
319
+ });
320
+ }));
321
+ server.registerTool("add_task_comment", {
322
+ title: "Comment on a task",
323
+ description: "Post a comment to a task's thread.",
324
+ inputSchema: {
325
+ company_id: companyIdSchema,
326
+ task_id: z.number().int(),
327
+ content: z.string().min(1).describe("The comment body.")
328
+ }
329
+ }, safeHandler(async (args) => {
330
+ const companyId = resolveCompanyId(client, args.company_id);
331
+ const task = await fetchTask(client, companyId, args.task_id);
332
+ await client.post("kanbans/tasks/comments/add", {
333
+ company_id: companyId,
334
+ project_id: task.project_id,
335
+ board_id: task.board_id,
336
+ task_id: args.task_id,
337
+ content: args.content
338
+ });
339
+ return textResult({ task_id: args.task_id, commented: true });
340
+ }));
341
+ }
342
+ //# sourceMappingURL=tasks.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tasks.js","sourceRoot":"","sources":["../../src/tools/tasks.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,129 @@
1
+ import { z } from "zod";
2
+ import { companyIdSchema, currentUserId, extractList, fetchTask, resolveCompanyId, safeHandler, textResult } from "../helpers.js";
3
+ const userIdSchema = z.number().int().optional().describe("Whose time this is. Defaults to the authenticated user.");
4
+ /** The API expects local-time "YYYY-MM-DD HH:MM:SS", not an ISO-8601 string. */
5
+ function formatApiDate(date) {
6
+ const pad = (n) => String(n).padStart(2, "0");
7
+ return (`${date.getFullYear()}-${pad(date.getMonth() + 1)}-${pad(date.getDate())} ` +
8
+ `${pad(date.getHours())}:${pad(date.getMinutes())}:${pad(date.getSeconds())}`);
9
+ }
10
+ /**
11
+ * Time-tracking tools.
12
+ *
13
+ * Timers and manual entries both belong to the calling user; the API takes the
14
+ * user from the token, so none of these tools accept a user id.
15
+ */
16
+ export function registerTimeTools(server, client) {
17
+ server.registerTool("start_timer", {
18
+ title: "Start a task timer",
19
+ description: "Start tracking time against a task for the authenticated user.",
20
+ inputSchema: {
21
+ company_id: companyIdSchema,
22
+ task_id: z.number().int(),
23
+ user_id: userIdSchema
24
+ }
25
+ }, safeHandler(async (args) => {
26
+ const companyId = resolveCompanyId(client, args.company_id);
27
+ const task = await fetchTask(client, companyId, args.task_id);
28
+ await client.post("kanbans/tasks/times/start-timer", {
29
+ company_id: companyId,
30
+ project_id: task.project_id,
31
+ board_id: task.board_id,
32
+ task_id: args.task_id,
33
+ user_id: args.user_id ?? (await currentUserId(client))
34
+ });
35
+ return textResult({ task_id: args.task_id, title: task.title, timer: "started" });
36
+ }));
37
+ server.registerTool("stop_timer", {
38
+ title: "Stop a task timer",
39
+ description: "Stop the running timer on a task and record the elapsed time.",
40
+ inputSchema: {
41
+ company_id: companyIdSchema,
42
+ task_id: z.number().int(),
43
+ user_id: userIdSchema
44
+ }
45
+ }, safeHandler(async (args) => {
46
+ const companyId = resolveCompanyId(client, args.company_id);
47
+ const task = await fetchTask(client, companyId, args.task_id);
48
+ await client.post("kanbans/tasks/times/stop-timer", {
49
+ company_id: companyId,
50
+ project_id: task.project_id,
51
+ board_id: task.board_id,
52
+ task_id: args.task_id,
53
+ user_id: args.user_id ?? (await currentUserId(client))
54
+ });
55
+ return textResult({ task_id: args.task_id, title: task.title, timer: "stopped" });
56
+ }));
57
+ server.registerTool("log_time", {
58
+ title: "Log time on a task",
59
+ description: "Record a block of time already spent on a task, for work done away from a running timer.",
60
+ inputSchema: {
61
+ company_id: companyIdSchema,
62
+ task_id: z.number().int(),
63
+ duration_minutes: z.number().int().min(1).describe("Minutes spent."),
64
+ date: z.string().optional().describe("When the work happened, YYYY-MM-DD HH:MM:SS. Defaults to now."),
65
+ comment: z.string().optional().describe("What the time was spent on."),
66
+ user_id: userIdSchema
67
+ }
68
+ }, safeHandler(async (args) => {
69
+ const companyId = resolveCompanyId(client, args.company_id);
70
+ const task = await fetchTask(client, companyId, args.task_id);
71
+ await client.post("kanbans/tasks/times/add", {
72
+ company_id: companyId,
73
+ project_id: task.project_id,
74
+ board_id: task.board_id,
75
+ task_id: args.task_id,
76
+ user_id: args.user_id ?? (await currentUserId(client)),
77
+ duration_minutes: args.duration_minutes,
78
+ // the endpoint requires a date; "when it happened" defaults to now so
79
+ // a caller logging time they just spent does not have to supply one
80
+ date: args.date ?? formatApiDate(new Date()),
81
+ comment: args.comment
82
+ });
83
+ return textResult({
84
+ task_id: args.task_id,
85
+ title: task.title,
86
+ logged_minutes: args.duration_minutes
87
+ });
88
+ }));
89
+ server.registerTool("list_task_time", {
90
+ title: "List time entries on a task",
91
+ description: "Show the time entries recorded against a task, and who logged them.",
92
+ inputSchema: {
93
+ company_id: companyIdSchema,
94
+ task_id: z.number().int(),
95
+ from_date: z.string().optional().describe("Lower bound, YYYY-MM-DD."),
96
+ to_date: z.string().optional().describe("Upper bound, YYYY-MM-DD."),
97
+ limit: z.number().int().min(1).max(50).optional().default(25),
98
+ page: z.number().int().min(1).optional().default(1)
99
+ }
100
+ }, safeHandler(async (args) => {
101
+ const companyId = resolveCompanyId(client, args.company_id);
102
+ const task = await fetchTask(client, companyId, args.task_id);
103
+ const response = await client.get("kanbans/tasks/times/search", {
104
+ company_id: companyId,
105
+ project_id: task.project_id,
106
+ board_id: task.board_id,
107
+ task_id: args.task_id,
108
+ from_date: args.from_date,
109
+ to_date: args.to_date,
110
+ limit: args.limit,
111
+ page: args.page
112
+ });
113
+ const { items: times, total } = extractList(response.data, "task_times");
114
+ return textResult({
115
+ count: total ?? times.length,
116
+ total_minutes: times.reduce((sum, t) => sum + (Number(t.duration_minutes) || 0), 0),
117
+ entries: times.map((t) => ({
118
+ id: t.id,
119
+ user_id: t.user_id,
120
+ user: [t.firstname, t.lastname].filter(Boolean).join(" ") || undefined,
121
+ duration_minutes: t.duration_minutes,
122
+ date: t.date,
123
+ comment: t.comment || undefined,
124
+ status: t.status || undefined
125
+ }))
126
+ });
127
+ }));
128
+ }
129
+ //# sourceMappingURL=time.js.map