@studiometa/productive-mcp 0.7.0 → 0.8.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/dist/errors.d.ts +41 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/handlers/bookings.d.ts +1 -1
- package/dist/handlers/bookings.d.ts.map +1 -1
- package/dist/handlers/comments.d.ts +1 -1
- package/dist/handlers/comments.d.ts.map +1 -1
- package/dist/handlers/companies.d.ts +1 -1
- package/dist/handlers/companies.d.ts.map +1 -1
- package/dist/handlers/deals.d.ts +1 -1
- package/dist/handlers/deals.d.ts.map +1 -1
- package/dist/handlers/index.d.ts.map +1 -1
- package/dist/handlers/people.d.ts +1 -1
- package/dist/handlers/people.d.ts.map +1 -1
- package/dist/handlers/projects.d.ts +1 -1
- package/dist/handlers/projects.d.ts.map +1 -1
- package/dist/handlers/reports.d.ts +1 -1
- package/dist/handlers/reports.d.ts.map +1 -1
- package/dist/handlers/services.d.ts +1 -1
- package/dist/handlers/services.d.ts.map +1 -1
- package/dist/handlers/tasks.d.ts.map +1 -1
- package/dist/handlers/time.d.ts +1 -1
- package/dist/handlers/time.d.ts.map +1 -1
- package/dist/handlers/timers.d.ts.map +1 -1
- package/dist/handlers/utils.d.ts +12 -1
- package/dist/handlers/utils.d.ts.map +1 -1
- package/dist/handlers.js +1 -1
- package/dist/http.d.ts +1 -0
- package/dist/http.d.ts.map +1 -1
- package/dist/http.js +4 -3
- package/dist/http.js.map +1 -1
- package/dist/{index-B2DTeltj.js → index-D743zTS1.js} +196 -44
- package/dist/index-D743zTS1.js.map +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -2
- package/dist/index.js.map +1 -1
- package/dist/instructions.d.ts +11 -0
- package/dist/instructions.d.ts.map +1 -0
- package/dist/schema.d.ts +218 -0
- package/dist/schema.d.ts.map +1 -0
- package/dist/server.js +1 -1
- package/dist/stdio.js +1 -1
- package/dist/tools.d.ts +6 -0
- package/dist/tools.d.ts.map +1 -1
- package/dist/tools.js +21 -0
- package/dist/tools.js.map +1 -1
- package/dist/version-i2-GF6d1.js +21 -0
- package/dist/version-i2-GF6d1.js.map +1 -0
- package/package.json +13 -3
- package/skills/SKILL.md +330 -0
- package/dist/index-B2DTeltj.js.map +0 -1
- package/dist/version-B1rjMbl8.js +0 -5
- package/dist/version-B1rjMbl8.js.map +0 -1
|
@@ -1,4 +1,100 @@
|
|
|
1
1
|
import { formatBooking as formatBooking$1, formatListResponse as formatListResponse$1, formatDeal as formatDeal$1, formatTimer as formatTimer$1, formatComment as formatComment$1, formatCompany as formatCompany$1, formatPerson as formatPerson$1, formatService as formatService$1, formatTask as formatTask$1, formatTimeEntry as formatTimeEntry$1, formatProject as formatProject$1, ProductiveApi } from "@studiometa/productive-cli";
|
|
2
|
+
class UserInputError extends Error {
|
|
3
|
+
hints;
|
|
4
|
+
constructor(message, hints) {
|
|
5
|
+
super(message);
|
|
6
|
+
this.name = "UserInputError";
|
|
7
|
+
this.hints = hints;
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* Format error message with hints for LLM consumption
|
|
11
|
+
*/
|
|
12
|
+
toFormattedMessage() {
|
|
13
|
+
let msg = `**Input Error:** ${this.message}`;
|
|
14
|
+
if (this.hints && this.hints.length > 0) {
|
|
15
|
+
msg += "\n\n**Hints:**\n" + this.hints.map((h) => `- ${h}`).join("\n");
|
|
16
|
+
}
|
|
17
|
+
return msg;
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
const ErrorMessages = {
|
|
21
|
+
// Required field errors
|
|
22
|
+
missingId: (action) => new UserInputError(`id is required for ${action} action`, [
|
|
23
|
+
`Use action="list" first to find the resource ID`,
|
|
24
|
+
`Then use action="${action}" with the id parameter`
|
|
25
|
+
]),
|
|
26
|
+
missingRequiredFields: (resource, fields) => new UserInputError(
|
|
27
|
+
`${fields.join(", ")} ${fields.length === 1 ? "is" : "are"} required for creating ${resource}`,
|
|
28
|
+
[
|
|
29
|
+
`Provide all required fields: ${fields.join(", ")}`,
|
|
30
|
+
`Use action="help" for detailed documentation on ${resource}`
|
|
31
|
+
]
|
|
32
|
+
),
|
|
33
|
+
// Invalid action errors
|
|
34
|
+
invalidAction: (action, resource, validActions) => new UserInputError(`Invalid action "${action}" for ${resource}`, [
|
|
35
|
+
`Valid actions are: ${validActions.join(", ")}`,
|
|
36
|
+
`Use action="help" with resource="${resource}" for detailed documentation`
|
|
37
|
+
]),
|
|
38
|
+
// Unknown resource errors
|
|
39
|
+
unknownResource: (resource, validResources) => new UserInputError(`Unknown resource: ${resource}`, [
|
|
40
|
+
`Valid resources are: ${validResources.join(", ")}`,
|
|
41
|
+
`Use action="help" without a resource for an overview of all resources`
|
|
42
|
+
]),
|
|
43
|
+
// Report-specific errors
|
|
44
|
+
missingReportType: () => new UserInputError("report_type is required for reports", [
|
|
45
|
+
'Specify report_type parameter (e.g., "time_reports", "project_reports")',
|
|
46
|
+
'Use action="help" with resource="reports" for available report types'
|
|
47
|
+
]),
|
|
48
|
+
invalidReportType: (reportType, validTypes) => new UserInputError(`Invalid report_type: ${reportType}`, [
|
|
49
|
+
`Valid report types are: ${validTypes.join(", ")}`,
|
|
50
|
+
'Use action="help" with resource="reports" for detailed documentation'
|
|
51
|
+
]),
|
|
52
|
+
// Timer-specific errors
|
|
53
|
+
missingServiceForTimer: () => new UserInputError("service_id is required to start a timer", [
|
|
54
|
+
'First find a service using resource="services" action="list"',
|
|
55
|
+
"Then start the timer with the service_id"
|
|
56
|
+
]),
|
|
57
|
+
// People-specific errors
|
|
58
|
+
noUserIdConfigured: () => new UserInputError("User ID not configured", [
|
|
59
|
+
'The "me" action requires a user ID to be configured',
|
|
60
|
+
'Use action="list" to find people, or configure the user ID'
|
|
61
|
+
]),
|
|
62
|
+
// Comment-specific errors
|
|
63
|
+
missingCommentTarget: () => new UserInputError("A target is required for creating a comment", [
|
|
64
|
+
"Provide one of: task_id, deal_id, or company_id",
|
|
65
|
+
'Find targets using resource="tasks", "deals", or "companies" with action="list"'
|
|
66
|
+
]),
|
|
67
|
+
// Booking-specific errors
|
|
68
|
+
missingBookingTarget: () => new UserInputError("A service or event is required for creating a booking", [
|
|
69
|
+
"Provide either: service_id or event_id",
|
|
70
|
+
'Find services using resource="services" with action="list"'
|
|
71
|
+
]),
|
|
72
|
+
// API errors
|
|
73
|
+
apiError: (statusCode, message) => {
|
|
74
|
+
const hints = [];
|
|
75
|
+
if (statusCode === 401) {
|
|
76
|
+
hints.push("Check that your API token is valid and not expired");
|
|
77
|
+
hints.push("Verify the organization ID is correct");
|
|
78
|
+
} else if (statusCode === 403) {
|
|
79
|
+
hints.push("You may not have permission to access this resource");
|
|
80
|
+
hints.push("Check your API token permissions");
|
|
81
|
+
} else if (statusCode === 404) {
|
|
82
|
+
hints.push("The resource may not exist or you may not have access");
|
|
83
|
+
hints.push("Verify the resource ID is correct");
|
|
84
|
+
hints.push('Use action="list" to find valid resource IDs');
|
|
85
|
+
} else if (statusCode === 422) {
|
|
86
|
+
hints.push("The request data may be invalid");
|
|
87
|
+
hints.push("Check the field values and types");
|
|
88
|
+
hints.push('Use action="help" for field documentation');
|
|
89
|
+
} else if (statusCode >= 500) {
|
|
90
|
+
hints.push("This is a server error - try again later");
|
|
91
|
+
}
|
|
92
|
+
return new UserInputError(`API error (${statusCode}): ${message}`, hints);
|
|
93
|
+
}
|
|
94
|
+
};
|
|
95
|
+
function isUserInputError(error) {
|
|
96
|
+
return error instanceof UserInputError;
|
|
97
|
+
}
|
|
2
98
|
const MCP_FORMAT_OPTIONS = {
|
|
3
99
|
includeRelationshipIds: false,
|
|
4
100
|
includeTimestamps: false,
|
|
@@ -101,10 +197,23 @@ function jsonResult(data) {
|
|
|
101
197
|
}
|
|
102
198
|
function errorResult(message) {
|
|
103
199
|
return {
|
|
104
|
-
content: [{ type: "text", text:
|
|
200
|
+
content: [{ type: "text", text: `**Error:** ${message}` }],
|
|
105
201
|
isError: true
|
|
106
202
|
};
|
|
107
203
|
}
|
|
204
|
+
function inputErrorResult(error) {
|
|
205
|
+
return {
|
|
206
|
+
content: [{ type: "text", text: error.toFormattedMessage() }],
|
|
207
|
+
isError: true
|
|
208
|
+
};
|
|
209
|
+
}
|
|
210
|
+
function formatError(error) {
|
|
211
|
+
if (isUserInputError(error)) {
|
|
212
|
+
return inputErrorResult(error);
|
|
213
|
+
}
|
|
214
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
215
|
+
return errorResult(message);
|
|
216
|
+
}
|
|
108
217
|
function toStringFilter(filter) {
|
|
109
218
|
if (!filter) return void 0;
|
|
110
219
|
const result = {};
|
|
@@ -116,21 +225,24 @@ function toStringFilter(filter) {
|
|
|
116
225
|
return Object.keys(result).length > 0 ? result : void 0;
|
|
117
226
|
}
|
|
118
227
|
const DEFAULT_BOOKING_INCLUDE = ["person", "service"];
|
|
228
|
+
const VALID_ACTIONS$a = ["list", "get", "create", "update"];
|
|
119
229
|
async function handleBookings(action, args, ctx) {
|
|
120
230
|
const { api, formatOptions, filter, page, perPage, include: userInclude } = ctx;
|
|
121
231
|
const { id, person_id, service_id, event_id, started_on, ended_on, time, note } = args;
|
|
122
232
|
const include = userInclude?.length ? [.../* @__PURE__ */ new Set([...DEFAULT_BOOKING_INCLUDE, ...userInclude])] : DEFAULT_BOOKING_INCLUDE;
|
|
123
233
|
if (action === "get") {
|
|
124
|
-
if (!id) return
|
|
234
|
+
if (!id) return inputErrorResult(ErrorMessages.missingId("get"));
|
|
125
235
|
const result = await api.getBooking(id, { include });
|
|
126
236
|
return jsonResult(formatBooking(result.data, { ...formatOptions, included: result.included }));
|
|
127
237
|
}
|
|
128
238
|
if (action === "create") {
|
|
129
239
|
if (!person_id || !started_on || !ended_on) {
|
|
130
|
-
return
|
|
240
|
+
return inputErrorResult(
|
|
241
|
+
ErrorMessages.missingRequiredFields("booking", ["person_id", "started_on", "ended_on"])
|
|
242
|
+
);
|
|
131
243
|
}
|
|
132
244
|
if (!service_id && !event_id) {
|
|
133
|
-
return
|
|
245
|
+
return inputErrorResult(ErrorMessages.missingBookingTarget());
|
|
134
246
|
}
|
|
135
247
|
const result = await api.createBooking({
|
|
136
248
|
person_id,
|
|
@@ -144,7 +256,7 @@ async function handleBookings(action, args, ctx) {
|
|
|
144
256
|
return jsonResult({ success: true, ...formatBooking(result.data, formatOptions) });
|
|
145
257
|
}
|
|
146
258
|
if (action === "update") {
|
|
147
|
-
if (!id) return
|
|
259
|
+
if (!id) return inputErrorResult(ErrorMessages.missingId("update"));
|
|
148
260
|
const updateData = {};
|
|
149
261
|
if (started_on !== void 0) updateData.started_on = started_on;
|
|
150
262
|
if (ended_on !== void 0) updateData.ended_on = ended_on;
|
|
@@ -162,22 +274,23 @@ async function handleBookings(action, args, ctx) {
|
|
|
162
274
|
})
|
|
163
275
|
);
|
|
164
276
|
}
|
|
165
|
-
return
|
|
277
|
+
return inputErrorResult(ErrorMessages.invalidAction(action, "bookings", VALID_ACTIONS$a));
|
|
166
278
|
}
|
|
167
279
|
const DEFAULT_COMMENT_INCLUDE = ["creator"];
|
|
280
|
+
const VALID_ACTIONS$9 = ["list", "get", "create", "update"];
|
|
168
281
|
async function handleComments(action, args, ctx) {
|
|
169
282
|
const { api, formatOptions, filter, page, perPage, include: userInclude } = ctx;
|
|
170
283
|
const { id, body, task_id, deal_id, company_id } = args;
|
|
171
284
|
const include = userInclude?.length ? [.../* @__PURE__ */ new Set([...DEFAULT_COMMENT_INCLUDE, ...userInclude])] : DEFAULT_COMMENT_INCLUDE;
|
|
172
285
|
if (action === "get") {
|
|
173
|
-
if (!id) return
|
|
286
|
+
if (!id) return inputErrorResult(ErrorMessages.missingId("get"));
|
|
174
287
|
const result = await api.getComment(id, { include });
|
|
175
288
|
return jsonResult(formatComment(result.data, { ...formatOptions, included: result.included }));
|
|
176
289
|
}
|
|
177
290
|
if (action === "create") {
|
|
178
|
-
if (!body) return
|
|
291
|
+
if (!body) return inputErrorResult(ErrorMessages.missingRequiredFields("comment", ["body"]));
|
|
179
292
|
if (!task_id && !deal_id && !company_id) {
|
|
180
|
-
return
|
|
293
|
+
return inputErrorResult(ErrorMessages.missingCommentTarget());
|
|
181
294
|
}
|
|
182
295
|
const result = await api.createComment({
|
|
183
296
|
body,
|
|
@@ -188,8 +301,9 @@ async function handleComments(action, args, ctx) {
|
|
|
188
301
|
return jsonResult({ success: true, ...formatComment(result.data, formatOptions) });
|
|
189
302
|
}
|
|
190
303
|
if (action === "update") {
|
|
191
|
-
if (!id) return
|
|
192
|
-
if (!body)
|
|
304
|
+
if (!id) return inputErrorResult(ErrorMessages.missingId("update"));
|
|
305
|
+
if (!body)
|
|
306
|
+
return inputErrorResult(ErrorMessages.missingRequiredFields("comment update", ["body"]));
|
|
193
307
|
const result = await api.updateComment(id, { body });
|
|
194
308
|
return jsonResult({ success: true, ...formatComment(result.data, formatOptions) });
|
|
195
309
|
}
|
|
@@ -202,23 +316,24 @@ async function handleComments(action, args, ctx) {
|
|
|
202
316
|
})
|
|
203
317
|
);
|
|
204
318
|
}
|
|
205
|
-
return
|
|
319
|
+
return inputErrorResult(ErrorMessages.invalidAction(action, "comments", VALID_ACTIONS$9));
|
|
206
320
|
}
|
|
321
|
+
const VALID_ACTIONS$8 = ["list", "get", "create", "update"];
|
|
207
322
|
async function handleCompanies(action, args, ctx) {
|
|
208
323
|
const { api, formatOptions, filter, page, perPage } = ctx;
|
|
209
324
|
const { id, name } = args;
|
|
210
325
|
if (action === "get") {
|
|
211
|
-
if (!id) return
|
|
326
|
+
if (!id) return inputErrorResult(ErrorMessages.missingId("get"));
|
|
212
327
|
const result = await api.getCompany(id);
|
|
213
328
|
return jsonResult(formatCompany(result.data, formatOptions));
|
|
214
329
|
}
|
|
215
330
|
if (action === "create") {
|
|
216
|
-
if (!name) return
|
|
331
|
+
if (!name) return inputErrorResult(ErrorMessages.missingRequiredFields("company", ["name"]));
|
|
217
332
|
const result = await api.createCompany({ name });
|
|
218
333
|
return jsonResult({ success: true, ...formatCompany(result.data, formatOptions) });
|
|
219
334
|
}
|
|
220
335
|
if (action === "update") {
|
|
221
|
-
if (!id) return
|
|
336
|
+
if (!id) return inputErrorResult(ErrorMessages.missingId("update"));
|
|
222
337
|
const updateData = {};
|
|
223
338
|
if (name !== void 0) updateData.name = name;
|
|
224
339
|
const result = await api.updateCompany(id, updateData);
|
|
@@ -228,28 +343,29 @@ async function handleCompanies(action, args, ctx) {
|
|
|
228
343
|
const result = await api.getCompanies({ filter, page, perPage });
|
|
229
344
|
return jsonResult(formatListResponse(result.data, formatCompany, result.meta, formatOptions));
|
|
230
345
|
}
|
|
231
|
-
return
|
|
346
|
+
return inputErrorResult(ErrorMessages.invalidAction(action, "companies", VALID_ACTIONS$8));
|
|
232
347
|
}
|
|
233
348
|
const DEFAULT_DEAL_INCLUDE_GET = ["company", "deal_status", "responsible"];
|
|
234
349
|
const DEFAULT_DEAL_INCLUDE_LIST = ["company", "deal_status"];
|
|
350
|
+
const VALID_ACTIONS$7 = ["list", "get", "create", "update"];
|
|
235
351
|
async function handleDeals(action, args, ctx) {
|
|
236
352
|
const { api, formatOptions, filter, page, perPage, include: userInclude } = ctx;
|
|
237
353
|
const { id, name, company_id } = args;
|
|
238
354
|
if (action === "get") {
|
|
239
|
-
if (!id) return
|
|
355
|
+
if (!id) return inputErrorResult(ErrorMessages.missingId("get"));
|
|
240
356
|
const include = userInclude?.length ? [.../* @__PURE__ */ new Set([...DEFAULT_DEAL_INCLUDE_GET, ...userInclude])] : DEFAULT_DEAL_INCLUDE_GET;
|
|
241
357
|
const result = await api.getDeal(id, { include });
|
|
242
358
|
return jsonResult(formatDeal(result.data, { ...formatOptions, included: result.included }));
|
|
243
359
|
}
|
|
244
360
|
if (action === "create") {
|
|
245
361
|
if (!name || !company_id) {
|
|
246
|
-
return
|
|
362
|
+
return inputErrorResult(ErrorMessages.missingRequiredFields("deal", ["name", "company_id"]));
|
|
247
363
|
}
|
|
248
364
|
const result = await api.createDeal({ name, company_id });
|
|
249
365
|
return jsonResult({ success: true, ...formatDeal(result.data, formatOptions) });
|
|
250
366
|
}
|
|
251
367
|
if (action === "update") {
|
|
252
|
-
if (!id) return
|
|
368
|
+
if (!id) return inputErrorResult(ErrorMessages.missingId("update"));
|
|
253
369
|
const updateData = {};
|
|
254
370
|
if (name !== void 0) updateData.name = name;
|
|
255
371
|
const result = await api.updateDeal(id, updateData);
|
|
@@ -270,7 +386,7 @@ async function handleDeals(action, args, ctx) {
|
|
|
270
386
|
})
|
|
271
387
|
);
|
|
272
388
|
}
|
|
273
|
-
return
|
|
389
|
+
return inputErrorResult(ErrorMessages.invalidAction(action, "deals", VALID_ACTIONS$7));
|
|
274
390
|
}
|
|
275
391
|
const RESOURCE_HELP = {
|
|
276
392
|
projects: {
|
|
@@ -685,11 +801,12 @@ function handleHelpOverview() {
|
|
|
685
801
|
resources: overview
|
|
686
802
|
});
|
|
687
803
|
}
|
|
804
|
+
const VALID_ACTIONS$6 = ["list", "get", "me"];
|
|
688
805
|
async function handlePeople(action, args, ctx, credentials) {
|
|
689
806
|
const { api, formatOptions, filter, page, perPage } = ctx;
|
|
690
807
|
const { id } = args;
|
|
691
808
|
if (action === "get") {
|
|
692
|
-
if (!id) return
|
|
809
|
+
if (!id) return inputErrorResult(ErrorMessages.missingId("get"));
|
|
693
810
|
const result = await api.getPerson(id);
|
|
694
811
|
return jsonResult(formatPerson(result.data, formatOptions));
|
|
695
812
|
}
|
|
@@ -700,6 +817,7 @@ async function handlePeople(action, args, ctx, credentials) {
|
|
|
700
817
|
}
|
|
701
818
|
return jsonResult({
|
|
702
819
|
message: "User ID not configured. Set userId in credentials to use this action.",
|
|
820
|
+
hint: 'Use action="list" to find people, or configure the user ID in your credentials.',
|
|
703
821
|
organizationId: credentials.organizationId
|
|
704
822
|
});
|
|
705
823
|
}
|
|
@@ -707,13 +825,14 @@ async function handlePeople(action, args, ctx, credentials) {
|
|
|
707
825
|
const result = await api.getPeople({ filter, page, perPage });
|
|
708
826
|
return jsonResult(formatListResponse(result.data, formatPerson, result.meta, formatOptions));
|
|
709
827
|
}
|
|
710
|
-
return
|
|
828
|
+
return inputErrorResult(ErrorMessages.invalidAction(action, "people", VALID_ACTIONS$6));
|
|
711
829
|
}
|
|
830
|
+
const VALID_ACTIONS$5 = ["list", "get"];
|
|
712
831
|
async function handleProjects(action, args, ctx) {
|
|
713
832
|
const { api, formatOptions, filter, page, perPage } = ctx;
|
|
714
833
|
const { id } = args;
|
|
715
834
|
if (action === "get") {
|
|
716
|
-
if (!id) return
|
|
835
|
+
if (!id) return inputErrorResult(ErrorMessages.missingId("get"));
|
|
717
836
|
const result = await api.getProject(id);
|
|
718
837
|
return jsonResult(formatProject(result.data, formatOptions));
|
|
719
838
|
}
|
|
@@ -721,7 +840,7 @@ async function handleProjects(action, args, ctx) {
|
|
|
721
840
|
const result = await api.getProjects({ filter, page, perPage });
|
|
722
841
|
return jsonResult(formatListResponse(result.data, formatProject, result.meta, formatOptions));
|
|
723
842
|
}
|
|
724
|
-
return
|
|
843
|
+
return inputErrorResult(ErrorMessages.invalidAction(action, "projects", VALID_ACTIONS$5));
|
|
725
844
|
}
|
|
726
845
|
function formatReportData(data) {
|
|
727
846
|
return data.map((item) => {
|
|
@@ -746,19 +865,18 @@ const VALID_REPORT_TYPES = [
|
|
|
746
865
|
"deal_reports",
|
|
747
866
|
"timesheet_reports"
|
|
748
867
|
];
|
|
868
|
+
const VALID_ACTIONS$4 = ["get"];
|
|
749
869
|
async function handleReports(action, args, ctx) {
|
|
750
870
|
const { api, filter, page, perPage } = ctx;
|
|
751
871
|
const { report_type, group, from, to, person_id, project_id, company_id, deal_id, status } = args;
|
|
752
872
|
if (action !== "get") {
|
|
753
|
-
return
|
|
873
|
+
return inputErrorResult(ErrorMessages.invalidAction(action, "reports", VALID_ACTIONS$4));
|
|
754
874
|
}
|
|
755
875
|
if (!report_type) {
|
|
756
|
-
return
|
|
876
|
+
return inputErrorResult(ErrorMessages.missingReportType());
|
|
757
877
|
}
|
|
758
878
|
if (!VALID_REPORT_TYPES.includes(report_type)) {
|
|
759
|
-
return
|
|
760
|
-
`Invalid report_type "${report_type}". Valid types: ${VALID_REPORT_TYPES.join(", ")}`
|
|
761
|
-
);
|
|
879
|
+
return inputErrorResult(ErrorMessages.invalidReportType(report_type, VALID_REPORT_TYPES));
|
|
762
880
|
}
|
|
763
881
|
const reportFilter = { ...filter };
|
|
764
882
|
if (from) {
|
|
@@ -844,27 +962,31 @@ async function handleReports(action, args, ctx) {
|
|
|
844
962
|
meta: result.meta
|
|
845
963
|
});
|
|
846
964
|
}
|
|
965
|
+
const VALID_ACTIONS$3 = ["list"];
|
|
847
966
|
async function handleServices(action, _args, ctx) {
|
|
848
967
|
const { api, formatOptions, filter, page, perPage } = ctx;
|
|
849
968
|
if (action === "list") {
|
|
850
969
|
const result = await api.getServices({ filter, page, perPage });
|
|
851
970
|
return jsonResult(formatListResponse(result.data, formatService, result.meta, formatOptions));
|
|
852
971
|
}
|
|
853
|
-
return
|
|
972
|
+
return inputErrorResult(ErrorMessages.invalidAction(action, "services", VALID_ACTIONS$3));
|
|
854
973
|
}
|
|
855
974
|
const DEFAULT_TASK_INCLUDE = ["project", "project.company"];
|
|
975
|
+
const VALID_ACTIONS$2 = ["list", "get", "create", "update"];
|
|
856
976
|
async function handleTasks(action, args, ctx) {
|
|
857
977
|
const { api, formatOptions, filter, page, perPage, include: userInclude } = ctx;
|
|
858
978
|
const { id, title, project_id, task_list_id, description, assignee_id } = args;
|
|
859
979
|
const include = userInclude?.length ? [.../* @__PURE__ */ new Set([...DEFAULT_TASK_INCLUDE, ...userInclude])] : DEFAULT_TASK_INCLUDE;
|
|
860
980
|
if (action === "get") {
|
|
861
|
-
if (!id) return
|
|
981
|
+
if (!id) return inputErrorResult(ErrorMessages.missingId("get"));
|
|
862
982
|
const result = await api.getTask(id, { include });
|
|
863
983
|
return jsonResult(formatTask(result.data, { ...formatOptions, included: result.included }));
|
|
864
984
|
}
|
|
865
985
|
if (action === "create") {
|
|
866
986
|
if (!title || !project_id || !task_list_id) {
|
|
867
|
-
return
|
|
987
|
+
return inputErrorResult(
|
|
988
|
+
ErrorMessages.missingRequiredFields("task", ["title", "project_id", "task_list_id"])
|
|
989
|
+
);
|
|
868
990
|
}
|
|
869
991
|
const result = await api.createTask({
|
|
870
992
|
title,
|
|
@@ -876,7 +998,7 @@ async function handleTasks(action, args, ctx) {
|
|
|
876
998
|
return jsonResult({ success: true, ...formatTask(result.data, formatOptions) });
|
|
877
999
|
}
|
|
878
1000
|
if (action === "update") {
|
|
879
|
-
if (!id) return
|
|
1001
|
+
if (!id) return inputErrorResult(ErrorMessages.missingId("update"));
|
|
880
1002
|
const updateData = {};
|
|
881
1003
|
if (title !== void 0) updateData.title = title;
|
|
882
1004
|
if (description !== void 0) updateData.description = description;
|
|
@@ -893,19 +1015,27 @@ async function handleTasks(action, args, ctx) {
|
|
|
893
1015
|
})
|
|
894
1016
|
);
|
|
895
1017
|
}
|
|
896
|
-
return
|
|
1018
|
+
return inputErrorResult(ErrorMessages.invalidAction(action, "tasks", VALID_ACTIONS$2));
|
|
897
1019
|
}
|
|
1020
|
+
const VALID_ACTIONS$1 = ["list", "get", "create", "update"];
|
|
898
1021
|
async function handleTime(action, args, ctx) {
|
|
899
1022
|
const { api, formatOptions, filter, page, perPage } = ctx;
|
|
900
1023
|
const { id, person_id, service_id, task_id, time, date, note } = args;
|
|
901
1024
|
if (action === "get") {
|
|
902
|
-
if (!id) return
|
|
1025
|
+
if (!id) return inputErrorResult(ErrorMessages.missingId("get"));
|
|
903
1026
|
const result = await api.getTimeEntry(id);
|
|
904
1027
|
return jsonResult(formatTimeEntry(result.data, formatOptions));
|
|
905
1028
|
}
|
|
906
1029
|
if (action === "create") {
|
|
907
1030
|
if (!person_id || !service_id || !time || !date) {
|
|
908
|
-
return
|
|
1031
|
+
return inputErrorResult(
|
|
1032
|
+
ErrorMessages.missingRequiredFields("time entry", [
|
|
1033
|
+
"person_id",
|
|
1034
|
+
"service_id",
|
|
1035
|
+
"time",
|
|
1036
|
+
"date"
|
|
1037
|
+
])
|
|
1038
|
+
);
|
|
909
1039
|
}
|
|
910
1040
|
const result = await api.createTimeEntry({
|
|
911
1041
|
person_id,
|
|
@@ -918,7 +1048,7 @@ async function handleTime(action, args, ctx) {
|
|
|
918
1048
|
return jsonResult({ success: true, ...formatTimeEntry(result.data, formatOptions) });
|
|
919
1049
|
}
|
|
920
1050
|
if (action === "update") {
|
|
921
|
-
if (!id) return
|
|
1051
|
+
if (!id) return inputErrorResult(ErrorMessages.missingId("update"));
|
|
922
1052
|
const updateData = {};
|
|
923
1053
|
if (time !== void 0) updateData.time = time;
|
|
924
1054
|
if (date !== void 0) updateData.date = date;
|
|
@@ -930,25 +1060,26 @@ async function handleTime(action, args, ctx) {
|
|
|
930
1060
|
const result = await api.getTimeEntries({ filter, page, perPage });
|
|
931
1061
|
return jsonResult(formatListResponse(result.data, formatTimeEntry, result.meta, formatOptions));
|
|
932
1062
|
}
|
|
933
|
-
return
|
|
1063
|
+
return inputErrorResult(ErrorMessages.invalidAction(action, "time", VALID_ACTIONS$1));
|
|
934
1064
|
}
|
|
1065
|
+
const VALID_ACTIONS = ["list", "get", "start", "stop"];
|
|
935
1066
|
async function handleTimers(action, args, ctx) {
|
|
936
1067
|
const { api, formatOptions, filter, page, perPage, include } = ctx;
|
|
937
1068
|
const { id, service_id, time_entry_id } = args;
|
|
938
1069
|
if (action === "get") {
|
|
939
|
-
if (!id) return
|
|
1070
|
+
if (!id) return inputErrorResult(ErrorMessages.missingId("get"));
|
|
940
1071
|
const result = await api.getTimer(id, { include });
|
|
941
1072
|
return jsonResult(formatTimer(result.data));
|
|
942
1073
|
}
|
|
943
1074
|
if (action === "start" || action === "create") {
|
|
944
1075
|
if (!service_id && !time_entry_id) {
|
|
945
|
-
return
|
|
1076
|
+
return inputErrorResult(ErrorMessages.missingServiceForTimer());
|
|
946
1077
|
}
|
|
947
1078
|
const result = await api.startTimer({ service_id, time_entry_id });
|
|
948
1079
|
return jsonResult({ success: true, ...formatTimer(result.data) });
|
|
949
1080
|
}
|
|
950
1081
|
if (action === "stop") {
|
|
951
|
-
if (!id) return
|
|
1082
|
+
if (!id) return inputErrorResult(ErrorMessages.missingId("stop"));
|
|
952
1083
|
const result = await api.stopTimer(id);
|
|
953
1084
|
return jsonResult({ success: true, ...formatTimer(result.data) });
|
|
954
1085
|
}
|
|
@@ -956,8 +1087,21 @@ async function handleTimers(action, args, ctx) {
|
|
|
956
1087
|
const result = await api.getTimers({ filter, page, perPage, include });
|
|
957
1088
|
return jsonResult(formatListResponse(result.data, formatTimer, result.meta, formatOptions));
|
|
958
1089
|
}
|
|
959
|
-
return
|
|
1090
|
+
return inputErrorResult(ErrorMessages.invalidAction(action, "timers", VALID_ACTIONS));
|
|
960
1091
|
}
|
|
1092
|
+
const VALID_RESOURCES = [
|
|
1093
|
+
"projects",
|
|
1094
|
+
"time",
|
|
1095
|
+
"tasks",
|
|
1096
|
+
"services",
|
|
1097
|
+
"people",
|
|
1098
|
+
"companies",
|
|
1099
|
+
"comments",
|
|
1100
|
+
"timers",
|
|
1101
|
+
"deals",
|
|
1102
|
+
"bookings",
|
|
1103
|
+
"reports"
|
|
1104
|
+
];
|
|
961
1105
|
const DEFAULT_PER_PAGE = 20;
|
|
962
1106
|
async function executeToolWithCredentials(name, args, credentials) {
|
|
963
1107
|
const api = new ProductiveApi({
|
|
@@ -1012,14 +1156,22 @@ async function executeToolWithCredentials(name, args, credentials) {
|
|
|
1012
1156
|
case "reports":
|
|
1013
1157
|
return await handleReports(action, restArgs, ctx);
|
|
1014
1158
|
default:
|
|
1015
|
-
return
|
|
1159
|
+
return inputErrorResult(ErrorMessages.unknownResource(resource, VALID_RESOURCES));
|
|
1016
1160
|
}
|
|
1017
1161
|
} catch (error) {
|
|
1162
|
+
if (isUserInputError(error)) {
|
|
1163
|
+
return formatError(error);
|
|
1164
|
+
}
|
|
1018
1165
|
const message = error instanceof Error ? error.message : String(error);
|
|
1166
|
+
const statusMatch = message.match(/(\d{3})/);
|
|
1167
|
+
if (statusMatch) {
|
|
1168
|
+
const statusCode = Number.parseInt(statusMatch[1], 10);
|
|
1169
|
+
return inputErrorResult(ErrorMessages.apiError(statusCode, message));
|
|
1170
|
+
}
|
|
1019
1171
|
return errorResult(message);
|
|
1020
1172
|
}
|
|
1021
1173
|
}
|
|
1022
1174
|
export {
|
|
1023
1175
|
executeToolWithCredentials as e
|
|
1024
1176
|
};
|
|
1025
|
-
//# sourceMappingURL=index-
|
|
1177
|
+
//# sourceMappingURL=index-D743zTS1.js.map
|