@devpad/api 2.0.1 → 2.0.3

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/index.js CHANGED
@@ -1,6 +1,1587 @@
1
- import { ApiClient } from "./api-client";
2
- export { getUserFriendlyErrorMessage, parseZodErrors } from "./error-handlers";
3
- export { err, ok, wrap } from "./result";
4
- export { getTool, toolNames, tools } from "./tools";
5
- export { ApiClient };
6
- export default ApiClient;
1
+ import {
2
+ ArrayBufferedQueue,
3
+ save_config_request,
4
+ save_tags_request,
5
+ upsert_goal,
6
+ upsert_milestone,
7
+ upsert_project,
8
+ upsert_todo
9
+ } from "./chunk-INGCIUMX.js";
10
+
11
+ // src/errors.ts
12
+ var ApiError = class _ApiError extends Error {
13
+ constructor(message, options = {}) {
14
+ super(message);
15
+ this.name = "ApiError";
16
+ this.code = options.code ?? void 0;
17
+ this.statusCode = options.statusCode ?? void 0;
18
+ }
19
+ static fromResponse(response) {
20
+ return new _ApiError(`API request failed: ${response.statusText}`, {
21
+ statusCode: response.status
22
+ });
23
+ }
24
+ };
25
+ var AuthenticationError = class extends ApiError {
26
+ constructor(message = "Authentication failed") {
27
+ super(message, { code: "AUTHENTICATION_ERROR" });
28
+ }
29
+ };
30
+ var NetworkError = class extends ApiError {
31
+ constructor(message = "Network request failed") {
32
+ super(message, { code: "NETWORK_ERROR" });
33
+ }
34
+ };
35
+ var ValidationError = class extends ApiError {
36
+ constructor(message = "Validation failed") {
37
+ super(message, { code: "VALIDATION_ERROR" });
38
+ }
39
+ };
40
+
41
+ // src/error-handlers.ts
42
+ var HTTP_STATUS = {
43
+ OK: 200,
44
+ CREATED: 201,
45
+ NO_CONTENT: 204,
46
+ BAD_REQUEST: 400,
47
+ UNAUTHORIZED: 401,
48
+ FORBIDDEN: 403,
49
+ NOT_FOUND: 404,
50
+ INTERNAL_SERVER_ERROR: 500
51
+ };
52
+ function handleHttpResponse(response) {
53
+ switch (response.status) {
54
+ case HTTP_STATUS.UNAUTHORIZED:
55
+ throw new AuthenticationError("Invalid or expired API key");
56
+ case HTTP_STATUS.NOT_FOUND:
57
+ throw new ApiError("Resource not found", { statusCode: HTTP_STATUS.NOT_FOUND });
58
+ case HTTP_STATUS.BAD_REQUEST:
59
+ break;
60
+ default:
61
+ if (!response.ok) {
62
+ throw new ApiError(`Request failed: ${response.statusText}`, { statusCode: response.status });
63
+ }
64
+ }
65
+ }
66
+ async function handleResponseError(response) {
67
+ const errorText = await response.text();
68
+ const errorMessage = errorText || "Request failed";
69
+ let parsedError = null;
70
+ try {
71
+ parsedError = JSON.parse(errorText);
72
+ } catch {
73
+ }
74
+ if (response.status === HTTP_STATUS.BAD_REQUEST && parsedError?.error?.name === "ZodError") {
75
+ const zodErrorDetails = parsedError.error?.issues ? JSON.stringify(parsedError.error) : errorMessage;
76
+ throw new ValidationError(zodErrorDetails);
77
+ }
78
+ throw new ApiError(errorMessage, { statusCode: response.status });
79
+ }
80
+ function handleNetworkError(error) {
81
+ const message = error instanceof Error ? error.message : "Unknown network error";
82
+ throw new NetworkError(message);
83
+ }
84
+ function isApiError(error) {
85
+ return error instanceof ApiError;
86
+ }
87
+ function isAuthenticationError(error) {
88
+ return error instanceof AuthenticationError;
89
+ }
90
+ function isNetworkError(error) {
91
+ return error instanceof NetworkError;
92
+ }
93
+ function parseZodErrors(errorMessage) {
94
+ try {
95
+ let parsedError = null;
96
+ try {
97
+ parsedError = JSON.parse(errorMessage);
98
+ } catch {
99
+ const zodErrorMatch = errorMessage.match(/ZodError: (.+)/);
100
+ if (zodErrorMatch && zodErrorMatch[1]) {
101
+ try {
102
+ parsedError = JSON.parse(zodErrorMatch[1]);
103
+ } catch {
104
+ const issuesMatch = errorMessage.match(/issues:\s*(\[.*\])/s);
105
+ if (issuesMatch && issuesMatch[1]) {
106
+ try {
107
+ parsedError = { issues: JSON.parse(issuesMatch[1]) };
108
+ } catch {
109
+ }
110
+ }
111
+ }
112
+ }
113
+ }
114
+ if (parsedError?.issues && Array.isArray(parsedError.issues)) {
115
+ const friendlyMessages = parsedError.issues.map((issue) => {
116
+ const path = issue.path && issue.path.length > 0 ? issue.path.join(".") : "field";
117
+ const message = issue.message || "is invalid";
118
+ switch (issue.code) {
119
+ case "invalid_type":
120
+ return `${path} must be a ${issue.expected} (received ${issue.received})`;
121
+ case "too_small":
122
+ if (issue.type === "string") {
123
+ return `${path} must be at least ${issue.minimum} characters long`;
124
+ }
125
+ if (issue.type === "number") {
126
+ return `${path} must be at least ${issue.minimum}`;
127
+ }
128
+ return `${path} is too small`;
129
+ case "too_big":
130
+ if (issue.type === "string") {
131
+ return `${path} must be no more than ${issue.maximum} characters long`;
132
+ }
133
+ if (issue.type === "number") {
134
+ return `${path} must be no more than ${issue.maximum}`;
135
+ }
136
+ return `${path} is too large`;
137
+ case "invalid_string":
138
+ if (issue.validation === "email") {
139
+ return `${path} must be a valid email address`;
140
+ }
141
+ if (issue.validation === "url") {
142
+ return `${path} must be a valid URL`;
143
+ }
144
+ if (issue.validation === "uuid") {
145
+ return `${path} must be a valid UUID`;
146
+ }
147
+ return `${path} format is invalid`;
148
+ case "custom":
149
+ return `${path}: ${message}`;
150
+ default:
151
+ return `${path}: ${message}`;
152
+ }
153
+ });
154
+ if (friendlyMessages.length === 1) {
155
+ return friendlyMessages[0];
156
+ }
157
+ return `Validation failed:
158
+ \u2022 ${friendlyMessages.join("\n\u2022 ")}`;
159
+ }
160
+ } catch (e) {
161
+ console.debug("Failed to parse Zod error:", e);
162
+ }
163
+ return errorMessage;
164
+ }
165
+ function getUserFriendlyErrorMessage(error) {
166
+ if (isAuthenticationError(error)) {
167
+ return "Please check your API key and try again";
168
+ }
169
+ if (isNetworkError(error)) {
170
+ return "Network connection issue. Please try again";
171
+ }
172
+ if (isApiError(error)) {
173
+ if (error.statusCode === HTTP_STATUS.NOT_FOUND) {
174
+ return "The requested resource was not found";
175
+ }
176
+ if (error.statusCode === HTTP_STATUS.BAD_REQUEST) {
177
+ return "Invalid request. Please check your data";
178
+ }
179
+ if (error.code === "VALIDATION_ERROR" && error.message) {
180
+ return parseZodErrors(error.message);
181
+ }
182
+ return error.message || "An error occurred";
183
+ }
184
+ return "An unexpected error occurred";
185
+ }
186
+
187
+ // src/request.ts
188
+ var ApiClient = class {
189
+ constructor(options) {
190
+ this.category = "api";
191
+ this.auth_mode = options.auth_mode ?? (options.api_key?.startsWith("jwt:") ? "session" : "key");
192
+ if (this.auth_mode !== "cookie") {
193
+ if (!options.api_key) throw new Error("API key is required");
194
+ if (options.api_key.length < 10) throw new Error("API key is too short");
195
+ }
196
+ this.base_url = options.base_url;
197
+ this.api_key = options.api_key ?? "";
198
+ this.category = options.category || "api";
199
+ this.credentials = options.credentials;
200
+ this.default_headers = options.default_headers ?? {};
201
+ this.custom_fetch = options.custom_fetch;
202
+ this.request_history = new ArrayBufferedQueue(
203
+ options.max_history_size ?? 5
204
+ );
205
+ this.debug = options.debug ?? false;
206
+ }
207
+ buildUrl(path, query) {
208
+ const url = new URL(`${this.base_url}${path}`);
209
+ if (query) {
210
+ Object.entries(query).forEach(([key, value]) => {
211
+ if (value) url.searchParams.append(key, value);
212
+ });
213
+ }
214
+ return url.toString();
215
+ }
216
+ generateRequestId() {
217
+ return `${Date.now()}-${Math.random().toString(36).substring(2, 11)}`;
218
+ }
219
+ async request(path, options = {}) {
220
+ const { method = "GET", headers = {}, body, query } = options;
221
+ const url = this.buildUrl(path, query);
222
+ const requestId = this.generateRequestId();
223
+ const startTime = Date.now();
224
+ const timestamp = (/* @__PURE__ */ new Date()).toISOString();
225
+ if (this.debug) {
226
+ console.log(
227
+ `[DEBUG][${this.category}] ${method} ${path} [${requestId}]`,
228
+ { body, query }
229
+ );
230
+ }
231
+ const request_headers = {
232
+ "Content-Type": "application/json",
233
+ "X-Request-ID": requestId,
234
+ ...this.default_headers,
235
+ ...headers
236
+ };
237
+ if (this.auth_mode === "session") {
238
+ request_headers.Authorization = `Bearer jwt:${this.api_key.replace(/^jwt:/, "")}`;
239
+ } else if (this.auth_mode === "key") {
240
+ request_headers.Authorization = `Bearer ${this.api_key}`;
241
+ }
242
+ const historyEntry = {
243
+ timestamp,
244
+ method,
245
+ path,
246
+ options: { ...options, method },
247
+ url
248
+ };
249
+ try {
250
+ const fetchOptions = {
251
+ method,
252
+ headers: request_headers
253
+ };
254
+ if (body) {
255
+ fetchOptions.body = JSON.stringify(body);
256
+ }
257
+ if (this.credentials) {
258
+ fetchOptions.credentials = this.credentials;
259
+ } else if (this.auth_mode === "cookie") {
260
+ fetchOptions.credentials = "include";
261
+ }
262
+ const fetcher = this.custom_fetch ?? fetch;
263
+ const response = await fetcher(url, fetchOptions);
264
+ const duration = Date.now() - startTime;
265
+ historyEntry.status = response.status;
266
+ historyEntry.duration = duration;
267
+ if (!response.ok) {
268
+ if (this.debug) {
269
+ console.log(
270
+ `[ERROR][${this.category}] ${method} ${path} [${requestId}] failed`,
271
+ {
272
+ status: response.status,
273
+ duration: `${duration}ms`,
274
+ body,
275
+ query
276
+ }
277
+ );
278
+ }
279
+ try {
280
+ handleHttpResponse(response);
281
+ await handleResponseError(response);
282
+ } catch (error) {
283
+ const errorMessage = error instanceof Error ? error.message : "Request failed";
284
+ historyEntry.error = errorMessage;
285
+ this.request_history.add(historyEntry);
286
+ throw error;
287
+ }
288
+ }
289
+ this.request_history.add(historyEntry);
290
+ let result;
291
+ if (response.status === HTTP_STATUS.NO_CONTENT) {
292
+ result = void 0;
293
+ } else {
294
+ const text = await response.text();
295
+ if (!text || text.trim() === "" || text.trim() === "null") {
296
+ result = void 0;
297
+ } else {
298
+ try {
299
+ result = JSON.parse(text);
300
+ } catch (parseError) {
301
+ result = text;
302
+ }
303
+ }
304
+ }
305
+ if (this.debug) {
306
+ console.log(
307
+ `[INFO][${this.category}] ${method} ${path} [${requestId}] completed`,
308
+ {
309
+ status: response.status,
310
+ duration: `${duration}ms`
311
+ }
312
+ );
313
+ }
314
+ return result;
315
+ } catch (error) {
316
+ const duration = Date.now() - startTime;
317
+ if (this.debug) {
318
+ console.log(
319
+ `[ERROR][${this.category}] ${method} ${path} [${requestId}] failed`,
320
+ {
321
+ url,
322
+ duration: `${duration}ms`,
323
+ error: error instanceof Error ? error.message : String(error),
324
+ body,
325
+ query
326
+ }
327
+ );
328
+ }
329
+ if (error instanceof ApiError || error instanceof AuthenticationError) {
330
+ throw error;
331
+ }
332
+ historyEntry.duration = duration;
333
+ try {
334
+ handleNetworkError(error);
335
+ } catch (networkError) {
336
+ const errorMessage = networkError instanceof Error ? networkError.message : "Unknown network error";
337
+ historyEntry.error = errorMessage;
338
+ this.request_history.add(historyEntry);
339
+ throw networkError;
340
+ }
341
+ }
342
+ }
343
+ get(path, options = {}) {
344
+ return this.request(path, { ...options, method: "GET" });
345
+ }
346
+ post(path, options = {}) {
347
+ return this.request(path, { ...options, method: "POST" });
348
+ }
349
+ patch(path, options = {}) {
350
+ return this.request(path, { ...options, method: "PATCH" });
351
+ }
352
+ put(path, options = {}) {
353
+ return this.request(path, { ...options, method: "PUT" });
354
+ }
355
+ delete(path, options = {}) {
356
+ return this.request(path, { ...options, method: "DELETE" });
357
+ }
358
+ history() {
359
+ return this.request_history;
360
+ }
361
+ url() {
362
+ return this.base_url;
363
+ }
364
+ headers() {
365
+ const headers = {
366
+ "Content-Type": "application/json"
367
+ };
368
+ if (this.auth_mode === "session") {
369
+ headers.Authorization = `Bearer jwt:${this.api_key.replace(/^jwt:/, "")}`;
370
+ } else if (this.auth_mode === "key") {
371
+ headers["X-API-KEY"] = this.api_key;
372
+ }
373
+ return headers;
374
+ }
375
+ };
376
+
377
+ // src/result.ts
378
+ import { err, ok } from "@f0rbit/corpus";
379
+ function wrap(fn) {
380
+ return fn().then((data) => ok(data)).catch(
381
+ (error) => err({
382
+ message: error.message || "Unknown error",
383
+ code: error.code,
384
+ status_code: error.statusCode || error.status_code
385
+ })
386
+ );
387
+ }
388
+
389
+ // src/api-client.ts
390
+ var ApiClient2 = class {
391
+ constructor(options) {
392
+ /**
393
+ * Auth namespace with Result-wrapped operations
394
+ */
395
+ this.auth = {
396
+ session: () => wrap(
397
+ () => this.clients.auth_root.get("/auth/session")
398
+ ),
399
+ keys: {
400
+ list: () => wrap(() => this.clients.auth.get("/keys")),
401
+ create: (name) => wrap(
402
+ () => this.clients.auth.post("/keys", {
403
+ body: name ? { name } : {}
404
+ })
405
+ ),
406
+ revoke: (key_id) => wrap(
407
+ () => this.clients.auth.delete(
408
+ `/keys/${key_id}`
409
+ )
410
+ ),
411
+ remove: (key_id) => wrap(
412
+ () => this.clients.auth.delete(
413
+ `/keys/${key_id}`
414
+ )
415
+ )
416
+ }
417
+ };
418
+ /**
419
+ * Projects namespace with Result-wrapped operations
420
+ */
421
+ this.projects = {
422
+ /**
423
+ * List projects with optional filtering
424
+ */
425
+ list: (filters) => wrap(
426
+ () => this.clients.projects.get(
427
+ filters?.private === false ? "/projects/public" : "/projects"
428
+ )
429
+ ),
430
+ /**
431
+ * Get project map
432
+ */
433
+ map: async (filters) => wrap(async () => {
434
+ const result = await this.projects.list(filters);
435
+ if (!result.ok) throw new Error(result.error.message);
436
+ return result.value.reduce(
437
+ (acc, project) => {
438
+ acc[project.id] = project;
439
+ return acc;
440
+ },
441
+ {}
442
+ );
443
+ }),
444
+ /**
445
+ * Get project by ID
446
+ */
447
+ find: (id) => wrap(
448
+ () => this.clients.projects.get("/projects", { query: { id } })
449
+ ),
450
+ /**
451
+ * Get project by name
452
+ */
453
+ getByName: (name) => wrap(
454
+ () => this.clients.projects.get("/projects", { query: { name } })
455
+ ),
456
+ /**
457
+ * Get project by ID (throws if not found)
458
+ */
459
+ getById: (id) => wrap(
460
+ () => this.clients.projects.get("/projects", { query: { id } })
461
+ ),
462
+ /**
463
+ * Create a new project
464
+ */
465
+ create: (data) => wrap(
466
+ () => this.clients.projects.patch("/projects", { body: data })
467
+ ),
468
+ /**
469
+ * Update an existing project
470
+ */
471
+ update: async (idOrData, changes) => wrap(async () => {
472
+ if (typeof idOrData === "object" && idOrData.id) {
473
+ return this.clients.projects.patch("/projects", {
474
+ body: idOrData
475
+ });
476
+ }
477
+ const id = idOrData;
478
+ if (!changes) {
479
+ throw new Error("Changes parameter required for update");
480
+ }
481
+ const result = await this.projects.find(id);
482
+ if (!result.ok) throw new Error(result.error.message);
483
+ if (!result.value) throw new Error(`Project with id ${id} not found`);
484
+ const project = result.value;
485
+ const updateData = {
486
+ id: project.id,
487
+ project_id: project.project_id,
488
+ owner_id: project.owner_id,
489
+ name: project.name,
490
+ description: project.description,
491
+ specification: project.specification,
492
+ repo_url: project.repo_url,
493
+ repo_id: project.repo_id,
494
+ icon_url: project.icon_url,
495
+ status: project.status,
496
+ deleted: project.deleted,
497
+ link_url: project.link_url,
498
+ link_text: project.link_text,
499
+ visibility: project.visibility,
500
+ current_version: project.current_version,
501
+ ...changes
502
+ };
503
+ return this.clients.projects.patch("/projects", {
504
+ body: updateData
505
+ });
506
+ }),
507
+ /**
508
+ * Project configuration operations
509
+ */
510
+ config: {
511
+ /**
512
+ * Get project configuration
513
+ */
514
+ load: (project_id) => wrap(
515
+ () => this.clients.projects.get("/projects/config", {
516
+ query: { project_id }
517
+ })
518
+ ),
519
+ /**
520
+ * Save project configuration
521
+ */
522
+ save: (request) => wrap(
523
+ () => this.clients.projects.patch("/projects/save_config", {
524
+ body: request
525
+ })
526
+ )
527
+ },
528
+ /**
529
+ * Scanning operations
530
+ */
531
+ scan: {
532
+ /**
533
+ * Initiate a repository scan (returns stream)
534
+ */
535
+ initiate: async (project_id) => {
536
+ const response = await fetch(
537
+ `${this.clients.projects.url()}/projects/scan?project_id=${project_id}`,
538
+ {
539
+ method: "POST",
540
+ headers: this.clients.projects.headers()
541
+ }
542
+ );
543
+ if (!response.body) {
544
+ throw new Error("No response body");
545
+ }
546
+ const stream = response.body.pipeThrough(new TextDecoderStream());
547
+ return stream;
548
+ },
549
+ /**
550
+ * Get pending scan updates for a project
551
+ */
552
+ updates: (project_id) => wrap(
553
+ () => this.clients.projects.get("/projects/updates", { query: { project_id } }).then((response) => response.updates)
554
+ ),
555
+ /**
556
+ * Process scan results
557
+ */
558
+ update: (project_id, data) => wrap(
559
+ () => this.clients.projects.post("/projects/scan_status", {
560
+ query: { project_id },
561
+ body: data
562
+ })
563
+ )
564
+ },
565
+ /**
566
+ * Get project history
567
+ */
568
+ history: (project_id) => wrap(
569
+ () => this.clients.projects.get(`/projects/${project_id}/history`)
570
+ ),
571
+ /**
572
+ * Legacy methods (keeping for compatibility)
573
+ */
574
+ upsert: (data) => wrap(
575
+ () => this.clients.projects.patch("/projects", { body: data })
576
+ ),
577
+ /**
578
+ * Fetch project specification from GitHub
579
+ */
580
+ specification: (project_id) => wrap(
581
+ () => this.clients.projects.get("/projects/fetch_spec", {
582
+ query: { project_id }
583
+ })
584
+ ),
585
+ /**
586
+ * Delete project (soft delete)
587
+ */
588
+ deleteProject: (project) => wrap(
589
+ () => this.clients.projects.patch("/projects", {
590
+ body: { ...project, deleted: true }
591
+ })
592
+ )
593
+ };
594
+ /**
595
+ * Milestones namespace with Result-wrapped operations
596
+ */
597
+ this.milestones = {
598
+ /**
599
+ * List milestones for authenticated user
600
+ */
601
+ list: () => wrap(() => this.clients.milestones.get("/milestones")),
602
+ /**
603
+ * Get milestones by project ID
604
+ */
605
+ getByProject: (project_id) => wrap(
606
+ () => this.clients.milestones.get(
607
+ `/projects/${project_id}/milestones`
608
+ )
609
+ ),
610
+ /**
611
+ * Get milestone by ID
612
+ */
613
+ find: (id) => wrap(async () => {
614
+ try {
615
+ return await this.clients.milestones.get(`/milestones/${id}`);
616
+ } catch (error) {
617
+ return null;
618
+ }
619
+ }),
620
+ /**
621
+ * Create new milestone
622
+ */
623
+ create: (data) => wrap(
624
+ () => this.clients.milestones.post("/milestones", { body: data })
625
+ ),
626
+ /**
627
+ * Update milestone
628
+ */
629
+ update: async (id, data) => wrap(async () => {
630
+ const result = await this.milestones.find(id);
631
+ if (!result.ok) throw new Error(result.error.message);
632
+ if (!result.value) throw new Error(`Milestone with id ${id} not found`);
633
+ const milestone = result.value;
634
+ const updateData = {
635
+ id: milestone.id,
636
+ project_id: milestone.project_id,
637
+ name: data.name ?? milestone.name,
638
+ description: data.description ?? milestone.description,
639
+ target_time: data.target_time ?? milestone.target_time,
640
+ target_version: data.target_version ?? milestone.target_version
641
+ };
642
+ return this.clients.milestones.patch(`/milestones/${id}`, {
643
+ body: updateData
644
+ });
645
+ }),
646
+ /**
647
+ * Delete milestone (soft delete)
648
+ */
649
+ delete: (id) => wrap(
650
+ () => this.clients.milestones.delete(
651
+ `/milestones/${id}`
652
+ )
653
+ ),
654
+ /**
655
+ * Get goals for a milestone
656
+ */
657
+ goals: (id) => wrap(() => this.clients.milestones.get(`/milestones/${id}/goals`))
658
+ };
659
+ /**
660
+ * Goals namespace with Result-wrapped operations
661
+ */
662
+ this.goals = {
663
+ /**
664
+ * List goals for authenticated user
665
+ */
666
+ list: () => wrap(() => this.clients.goals.get("/goals")),
667
+ /**
668
+ * Get goal by ID
669
+ */
670
+ find: (id) => wrap(() => this.clients.goals.get(`/goals/${id}`)),
671
+ /**
672
+ * Create new goal
673
+ */
674
+ create: (data) => wrap(() => this.clients.goals.post("/goals", { body: data })),
675
+ /**
676
+ * Update goal
677
+ */
678
+ update: async (id, data) => wrap(async () => {
679
+ const result = await this.goals.find(id);
680
+ if (!result.ok) throw new Error(result.error.message);
681
+ if (!result.value) throw new Error(`Goal with id ${id} not found`);
682
+ const goal = result.value;
683
+ const updateData = {
684
+ id: goal.id,
685
+ milestone_id: goal.milestone_id,
686
+ name: data.name ?? goal.name,
687
+ description: data.description ?? goal.description,
688
+ target_time: data.target_time ?? goal.target_time
689
+ };
690
+ return this.clients.goals.patch(`/goals/${id}`, {
691
+ body: updateData
692
+ });
693
+ }),
694
+ /**
695
+ * Delete goal (soft delete)
696
+ */
697
+ delete: (id) => wrap(
698
+ () => this.clients.goals.delete(
699
+ `/goals/${id}`
700
+ )
701
+ )
702
+ };
703
+ /**
704
+ * Tasks namespace with Result-wrapped operations
705
+ */
706
+ this.tasks = {
707
+ /**
708
+ * List tasks with optional filtering
709
+ */
710
+ list: (filters) => wrap(() => {
711
+ const query = {};
712
+ if (filters?.project_id) query.project = filters.project_id;
713
+ if (filters?.tag_id) query.tag = filters.tag_id;
714
+ return this.clients.tasks.get(
715
+ "/tasks",
716
+ Object.keys(query).length > 0 ? { query } : {}
717
+ );
718
+ }),
719
+ /**
720
+ * Get task by ID
721
+ */
722
+ find: (id) => wrap(() => this.clients.tasks.get("/tasks", { query: { id } })),
723
+ /**
724
+ * Get tasks by project ID
725
+ */
726
+ getByProject: (project_id) => wrap(
727
+ () => this.clients.tasks.get(`/tasks`, {
728
+ query: { project: project_id }
729
+ })
730
+ ),
731
+ /**
732
+ * Create a new task
733
+ */
734
+ create: (data) => wrap(
735
+ () => this.clients.tasks.patch("/tasks", { body: data })
736
+ ),
737
+ /**
738
+ * Update an existing task
739
+ */
740
+ update: async (id, changes) => wrap(async () => {
741
+ const result = await this.tasks.find(id);
742
+ if (!result.ok) throw new Error(result.error.message);
743
+ if (!result.value) throw new Error(`Task with id ${id} not found`);
744
+ const task = result.value;
745
+ const updateData = {
746
+ id,
747
+ title: task.task.title,
748
+ summary: task.task.summary,
749
+ description: task.task.description,
750
+ progress: task.task.progress,
751
+ visibility: task.task.visibility,
752
+ start_time: task.task.start_time,
753
+ end_time: task.task.end_time,
754
+ priority: task.task.priority,
755
+ owner_id: task.task.owner_id,
756
+ project_id: task.task.project_id,
757
+ ...changes
758
+ };
759
+ return this.clients.tasks.patch("/tasks", {
760
+ body: updateData
761
+ });
762
+ }),
763
+ /**
764
+ * Upsert task (create or update)
765
+ */
766
+ upsert: (data) => wrap(
767
+ () => this.clients.tasks.patch("/tasks", { body: data })
768
+ ),
769
+ /**
770
+ * Save tags for tasks
771
+ */
772
+ saveTags: (data) => wrap(
773
+ () => this.clients.tasks.patch("/tasks/save_tags", { body: data })
774
+ ),
775
+ /**
776
+ * Delete task (soft delete)
777
+ */
778
+ deleteTask: (task) => wrap(
779
+ () => this.clients.tasks.patch("/tasks", {
780
+ body: { ...task.task, deleted: true }
781
+ })
782
+ ),
783
+ /**
784
+ * Task history operations
785
+ */
786
+ history: {
787
+ /**
788
+ * Get task history by task ID
789
+ */
790
+ get: (task_id) => wrap(
791
+ () => this.clients.tasks.get(`/tasks/history/${task_id}`)
792
+ )
793
+ }
794
+ };
795
+ /**
796
+ * Tags namespace with Result-wrapped operations
797
+ */
798
+ this.tags = {
799
+ /**
800
+ * List tags for authenticated user
801
+ */
802
+ list: () => wrap(() => this.clients.tags.get("/tags"))
803
+ };
804
+ /**
805
+ * GitHub namespace with Result-wrapped operations
806
+ */
807
+ this.github = {
808
+ /**
809
+ * List repositories for authenticated user
810
+ */
811
+ repos: () => wrap(() => this.clients.github.get("/repos")),
812
+ /**
813
+ * List branches for a GitHub repository
814
+ */
815
+ branches: (owner, repo) => wrap(
816
+ () => this.clients.github.get(`/repos/${owner}/${repo}/branches`)
817
+ )
818
+ };
819
+ this.blog = {
820
+ posts: {
821
+ list: (params) => wrap(() => {
822
+ const query = {};
823
+ if (params?.category) query.category = params.category;
824
+ if (params?.tag) query.tag = params.tag;
825
+ if (params?.project) query.project = params.project;
826
+ if (params?.status) query.status = params.status;
827
+ if (params?.archived !== void 0)
828
+ query.archived = String(params.archived);
829
+ if (params?.limit) query.limit = String(params.limit);
830
+ if (params?.offset !== void 0)
831
+ query.offset = String(params.offset);
832
+ if (params?.sort) query.sort = params.sort;
833
+ return this.clients.blog.get(
834
+ "/blog/posts",
835
+ Object.keys(query).length ? { query } : {}
836
+ );
837
+ }),
838
+ getBySlug: (slug) => wrap(() => this.clients.blog.get(`/blog/posts/${slug}`)),
839
+ create: (data) => wrap(() => this.clients.blog.post("/blog/posts", { body: data })),
840
+ update: (uuid, data) => wrap(
841
+ () => this.clients.blog.put(`/blog/posts/${uuid}`, { body: data })
842
+ ),
843
+ delete: (uuid) => wrap(
844
+ () => this.clients.blog.delete(`/blog/posts/${uuid}`)
845
+ ),
846
+ versions: (uuid) => wrap(
847
+ () => this.clients.blog.get(
848
+ `/blog/posts/${uuid}/versions`
849
+ )
850
+ ),
851
+ version: (uuid, hash) => wrap(
852
+ () => this.clients.blog.get(
853
+ `/blog/posts/${uuid}/version/${hash}`
854
+ )
855
+ ),
856
+ restore: (uuid, hash) => wrap(
857
+ () => this.clients.blog.post(`/blog/posts/${uuid}/restore/${hash}`)
858
+ )
859
+ },
860
+ tags: {
861
+ list: () => wrap(
862
+ () => this.clients.blog.get("/blog/tags")
863
+ ),
864
+ getForPost: (uuid) => wrap(
865
+ () => this.clients.blog.get(
866
+ `/blog/tags/posts/${uuid}/tags`
867
+ )
868
+ ),
869
+ setForPost: (uuid, tags) => wrap(
870
+ () => this.clients.blog.put(
871
+ `/blog/tags/posts/${uuid}/tags`,
872
+ { body: { tags } }
873
+ )
874
+ ),
875
+ addToPost: (uuid, tags) => wrap(
876
+ () => this.clients.blog.post(
877
+ `/blog/tags/posts/${uuid}/tags`,
878
+ { body: { tags } }
879
+ )
880
+ ),
881
+ removeFromPost: (uuid, tag) => wrap(
882
+ () => this.clients.blog.delete(
883
+ `/blog/tags/posts/${uuid}/tags/${tag}`
884
+ )
885
+ )
886
+ },
887
+ categories: {
888
+ tree: () => wrap(
889
+ () => this.clients.blog.get("/blog/categories")
890
+ ),
891
+ create: (data) => wrap(
892
+ () => this.clients.blog.post("/blog/categories", { body: data })
893
+ ),
894
+ update: (name, data) => wrap(
895
+ () => this.clients.blog.put(`/blog/categories/${name}`, {
896
+ body: data
897
+ })
898
+ ),
899
+ delete: (name) => wrap(() => this.clients.blog.delete(`/blog/categories/${name}`))
900
+ },
901
+ tokens: {
902
+ list: () => wrap(
903
+ () => this.clients.blog.get("/blog/tokens")
904
+ ),
905
+ create: (data) => wrap(
906
+ () => this.clients.blog.post("/blog/tokens", { body: data })
907
+ ),
908
+ update: (id, data) => wrap(
909
+ () => this.clients.blog.put(`/blog/tokens/${id}`, {
910
+ body: data
911
+ })
912
+ ),
913
+ delete: (id) => wrap(() => this.clients.blog.delete(`/blog/tokens/${id}`))
914
+ }
915
+ };
916
+ this.media = {
917
+ profiles: {
918
+ list: () => wrap(async () => {
919
+ const res = await this.clients.media.get(
920
+ "/profiles"
921
+ );
922
+ return res.profiles;
923
+ }),
924
+ create: (data) => wrap(
925
+ () => this.clients.media.post("/profiles", { body: data })
926
+ ),
927
+ get: (id) => wrap(() => this.clients.media.get(`/profiles/${id}`)),
928
+ update: (id, data) => wrap(
929
+ () => this.clients.media.patch(`/profiles/${id}`, { body: data })
930
+ ),
931
+ delete: (id) => wrap(
932
+ () => this.clients.media.delete(`/profiles/${id}`)
933
+ ),
934
+ filters: {
935
+ list: (profile_id) => wrap(async () => {
936
+ const res = await this.clients.media.get(`/profiles/${profile_id}/filters`);
937
+ return res.filters;
938
+ }),
939
+ add: (profile_id, data) => wrap(
940
+ () => this.clients.media.post(
941
+ `/profiles/${profile_id}/filters`,
942
+ { body: data }
943
+ )
944
+ ),
945
+ remove: (profile_id, filter_id) => wrap(
946
+ () => this.clients.media.delete(
947
+ `/profiles/${profile_id}/filters/${filter_id}`
948
+ )
949
+ )
950
+ },
951
+ timeline: (slug, params) => wrap(() => {
952
+ const query = {};
953
+ if (params?.limit) query.limit = String(params.limit);
954
+ if (params?.before) query.before = params.before;
955
+ return this.clients.media.get(
956
+ `/profiles/${slug}/timeline`,
957
+ Object.keys(query).length ? { query } : {}
958
+ );
959
+ })
960
+ },
961
+ connections: {
962
+ list: (profile_id, options) => wrap(async () => {
963
+ const query = { profile_id };
964
+ if (options?.include_settings) query.include_settings = "true";
965
+ const res = await this.clients.media.get(
966
+ "/connections",
967
+ { query }
968
+ );
969
+ return res.accounts;
970
+ }),
971
+ create: (data) => wrap(
972
+ () => this.clients.media.post("/connections", { body: data })
973
+ ),
974
+ delete: (account_id) => wrap(
975
+ () => this.clients.media.delete(
976
+ `/connections/${account_id}`
977
+ )
978
+ ),
979
+ refresh: (account_id) => wrap(
980
+ () => this.clients.media.post(`/connections/${account_id}/refresh`)
981
+ ),
982
+ refreshAll: () => wrap(() => this.clients.media.post("/connections/refresh-all")),
983
+ updateStatus: (account_id, is_active) => wrap(
984
+ () => this.clients.media.patch(`/connections/${account_id}`, {
985
+ body: { is_active }
986
+ })
987
+ ),
988
+ settings: {
989
+ get: (account_id) => wrap(
990
+ () => this.clients.media.get(
991
+ `/connections/${account_id}/settings`
992
+ )
993
+ ),
994
+ update: (account_id, settings) => wrap(
995
+ () => this.clients.media.put(`/connections/${account_id}/settings`, {
996
+ body: { settings }
997
+ })
998
+ )
999
+ },
1000
+ repos: (account_id) => wrap(async () => {
1001
+ const res = await this.clients.media.get(
1002
+ `/connections/${account_id}/repos`
1003
+ );
1004
+ return res.repos;
1005
+ }),
1006
+ subreddits: (account_id) => wrap(async () => {
1007
+ const res = await this.clients.media.get(`/connections/${account_id}/subreddits`);
1008
+ return res.subreddits;
1009
+ })
1010
+ },
1011
+ credentials: {
1012
+ check: (platform, profile_id) => wrap(
1013
+ () => this.clients.media.get(`/credentials/${platform}`, { query: { profile_id } })
1014
+ ),
1015
+ save: (platform, data) => wrap(
1016
+ () => this.clients.media.post(
1017
+ `/credentials/${platform}`,
1018
+ { body: data }
1019
+ )
1020
+ ),
1021
+ delete: (platform, profile_id) => wrap(
1022
+ () => this.clients.media.delete(
1023
+ `/credentials/${platform}`,
1024
+ { query: { profile_id } }
1025
+ )
1026
+ )
1027
+ },
1028
+ timeline: {
1029
+ get: (user_id, params) => wrap(() => {
1030
+ const query = {};
1031
+ if (params?.from) query.from = params.from;
1032
+ if (params?.to) query.to = params.to;
1033
+ return this.clients.media.get(
1034
+ `/timeline/${user_id}`,
1035
+ Object.keys(query).length ? { query } : {}
1036
+ );
1037
+ }),
1038
+ getRaw: (user_id, platform, account_id) => wrap(
1039
+ () => this.clients.media.get(`/timeline/${user_id}/raw/${platform}`, {
1040
+ query: { account_id }
1041
+ })
1042
+ )
1043
+ }
1044
+ };
1045
+ /**
1046
+ * User namespace with Result-wrapped operations
1047
+ */
1048
+ this.user = {
1049
+ /**
1050
+ * Get user activity history
1051
+ */
1052
+ history: () => wrap(() => this.clients.auth.get("/user/history")),
1053
+ /**
1054
+ * Update user preferences
1055
+ */
1056
+ preferences: (data) => wrap(
1057
+ () => this.clients.auth.patch("/user/preferences", { body: data })
1058
+ )
1059
+ };
1060
+ const base_url = options.base_url || "http://localhost:4321/api/v1";
1061
+ this._api_key = options.api_key ?? "";
1062
+ this._auth_mode = options.auth_mode ?? (options.api_key?.startsWith("jwt:") ? "session" : options.api_key ? "key" : "cookie");
1063
+ const clientOptions = {
1064
+ base_url,
1065
+ api_key: options.api_key,
1066
+ max_history_size: options.max_history_size,
1067
+ auth_mode: this._auth_mode,
1068
+ credentials: options.credentials,
1069
+ default_headers: options.default_headers,
1070
+ custom_fetch: options.custom_fetch
1071
+ };
1072
+ const auth_base_url = base_url.replace(/\/v1\/?$/, "");
1073
+ this.clients = {
1074
+ auth: new ApiClient({ ...clientOptions, category: "auth" }),
1075
+ auth_root: new ApiClient({
1076
+ ...clientOptions,
1077
+ base_url: auth_base_url,
1078
+ category: "auth"
1079
+ }),
1080
+ projects: new ApiClient({ ...clientOptions, category: "projects" }),
1081
+ tasks: new ApiClient({ ...clientOptions, category: "tasks" }),
1082
+ milestones: new ApiClient({ ...clientOptions, category: "milestones" }),
1083
+ goals: new ApiClient({ ...clientOptions, category: "goals" }),
1084
+ github: new ApiClient({ ...clientOptions, category: "github" }),
1085
+ tags: new ApiClient({ ...clientOptions, category: "tags" }),
1086
+ blog: new ApiClient({ ...clientOptions, category: "blog" }),
1087
+ media: new ApiClient({ ...clientOptions, category: "media" })
1088
+ };
1089
+ }
1090
+ /**
1091
+ * Get request history for debugging
1092
+ */
1093
+ history() {
1094
+ return this.clients.projects.history();
1095
+ }
1096
+ /**
1097
+ * Get the API key
1098
+ */
1099
+ getApiKey() {
1100
+ return this._api_key;
1101
+ }
1102
+ /**
1103
+ * Get the authentication mode
1104
+ */
1105
+ getAuthMode() {
1106
+ return this._auth_mode;
1107
+ }
1108
+ };
1109
+
1110
+ // src/tools.ts
1111
+ import { z } from "zod";
1112
+ function unwrap(result) {
1113
+ if (!result.ok) throw new Error(result.error?.message ?? "Unknown error");
1114
+ return result.value;
1115
+ }
1116
+ var project_filters = z.object({
1117
+ private: z.boolean().optional().describe("Include private projects (default: true)")
1118
+ });
1119
+ var project_by_id_or_name = z.object({
1120
+ id: z.string().optional().describe("Project ID"),
1121
+ name: z.string().optional().describe("Project name")
1122
+ }).refine((data) => data.id || data.name, {
1123
+ message: "Either 'id' or 'name' must be provided"
1124
+ });
1125
+ var task_filters = z.object({
1126
+ project_id: z.string().optional().describe("Filter by project ID"),
1127
+ tag_id: z.string().optional().describe("Filter by tag ID")
1128
+ });
1129
+ var task_by_id = z.object({
1130
+ id: z.string().describe("Task ID")
1131
+ });
1132
+ var milestone_filters = z.object({
1133
+ project_id: z.string().optional().describe("Filter by project ID")
1134
+ });
1135
+ var milestone_by_id = z.object({
1136
+ id: z.string().describe("Milestone ID")
1137
+ });
1138
+ var goal_by_id = z.object({
1139
+ id: z.string().describe("Goal ID")
1140
+ });
1141
+ var github_branches = z.object({
1142
+ owner: z.string().describe("Repository owner"),
1143
+ repo: z.string().describe("Repository name")
1144
+ });
1145
+ var tools = {
1146
+ // Projects
1147
+ devpad_projects_list: {
1148
+ name: "devpad_projects_list",
1149
+ description: "List all projects (or only public ones)",
1150
+ inputSchema: project_filters,
1151
+ execute: async (client, input) => unwrap(await client.projects.list(input))
1152
+ },
1153
+ devpad_projects_get: {
1154
+ name: "devpad_projects_get",
1155
+ description: "Get project by ID or name",
1156
+ inputSchema: project_by_id_or_name,
1157
+ execute: async (client, input) => unwrap(
1158
+ input.id ? await client.projects.getById(input.id) : await client.projects.getByName(input.name)
1159
+ )
1160
+ },
1161
+ devpad_projects_upsert: {
1162
+ name: "devpad_projects_upsert",
1163
+ description: "Create or update a project (set deleted=true to delete)",
1164
+ inputSchema: upsert_project,
1165
+ execute: async (client, input) => unwrap(await client.projects.upsert(input))
1166
+ },
1167
+ devpad_projects_config_save: {
1168
+ name: "devpad_projects_config_save",
1169
+ description: "Save project configuration",
1170
+ inputSchema: save_config_request,
1171
+ execute: async (client, input) => {
1172
+ unwrap(await client.projects.config.save(input));
1173
+ return { success: true };
1174
+ }
1175
+ },
1176
+ // Tasks
1177
+ devpad_tasks_list: {
1178
+ name: "devpad_tasks_list",
1179
+ description: "List tasks, optionally filtered by project or tag",
1180
+ inputSchema: task_filters,
1181
+ execute: async (client, input) => unwrap(await client.tasks.list(input))
1182
+ },
1183
+ devpad_tasks_get: {
1184
+ name: "devpad_tasks_get",
1185
+ description: "Get task by ID",
1186
+ inputSchema: task_by_id,
1187
+ execute: async (client, input) => unwrap(await client.tasks.find(input.id))
1188
+ },
1189
+ devpad_tasks_upsert: {
1190
+ name: "devpad_tasks_upsert",
1191
+ description: "Create or update a task (set deleted=true to delete)",
1192
+ inputSchema: upsert_todo,
1193
+ execute: async (client, input) => unwrap(await client.tasks.upsert(input))
1194
+ },
1195
+ devpad_tasks_save_tags: {
1196
+ name: "devpad_tasks_save_tags",
1197
+ description: "Save tags for tasks",
1198
+ inputSchema: save_tags_request,
1199
+ execute: async (client, input) => {
1200
+ unwrap(await client.tasks.saveTags(input));
1201
+ return { success: true };
1202
+ }
1203
+ },
1204
+ // Milestones
1205
+ devpad_milestones_list: {
1206
+ name: "devpad_milestones_list",
1207
+ description: "List milestones for authenticated user or by project",
1208
+ inputSchema: milestone_filters,
1209
+ execute: async (client, input) => unwrap(
1210
+ input.project_id ? await client.milestones.getByProject(input.project_id) : await client.milestones.list()
1211
+ )
1212
+ },
1213
+ devpad_milestones_get: {
1214
+ name: "devpad_milestones_get",
1215
+ description: "Get milestone by ID",
1216
+ inputSchema: milestone_by_id,
1217
+ execute: async (client, input) => unwrap(await client.milestones.find(input.id))
1218
+ },
1219
+ devpad_milestones_upsert: {
1220
+ name: "devpad_milestones_upsert",
1221
+ description: "Create or update a milestone",
1222
+ inputSchema: upsert_milestone,
1223
+ execute: async (client, input) => unwrap(
1224
+ input.id ? await client.milestones.update(input.id, {
1225
+ name: input.name,
1226
+ description: input.description,
1227
+ target_time: input.target_time,
1228
+ target_version: input.target_version
1229
+ }) : await client.milestones.create({
1230
+ project_id: input.project_id,
1231
+ name: input.name,
1232
+ description: input.description,
1233
+ target_time: input.target_time,
1234
+ target_version: input.target_version
1235
+ })
1236
+ )
1237
+ },
1238
+ // Goals
1239
+ devpad_goals_list: {
1240
+ name: "devpad_goals_list",
1241
+ description: "List goals for authenticated user",
1242
+ inputSchema: z.object({}),
1243
+ execute: async (client) => unwrap(await client.goals.list())
1244
+ },
1245
+ devpad_goals_get: {
1246
+ name: "devpad_goals_get",
1247
+ description: "Get goal by ID",
1248
+ inputSchema: goal_by_id,
1249
+ execute: async (client, input) => unwrap(await client.goals.find(input.id))
1250
+ },
1251
+ devpad_goals_upsert: {
1252
+ name: "devpad_goals_upsert",
1253
+ description: "Create or update a goal",
1254
+ inputSchema: upsert_goal,
1255
+ execute: async (client, input) => unwrap(
1256
+ input.id ? await client.goals.update(input.id, {
1257
+ name: input.name,
1258
+ description: input.description,
1259
+ target_time: input.target_time
1260
+ }) : await client.goals.create({
1261
+ milestone_id: input.milestone_id,
1262
+ name: input.name,
1263
+ description: input.description,
1264
+ target_time: input.target_time
1265
+ })
1266
+ )
1267
+ },
1268
+ // Tags
1269
+ devpad_tags_list: {
1270
+ name: "devpad_tags_list",
1271
+ description: "List tags for authenticated user",
1272
+ inputSchema: z.object({}),
1273
+ execute: async (client) => unwrap(await client.tags.list())
1274
+ },
1275
+ // GitHub integration
1276
+ devpad_github_repos: {
1277
+ name: "devpad_github_repos",
1278
+ description: "List GitHub repositories for authenticated user",
1279
+ inputSchema: z.object({}),
1280
+ execute: async (client) => unwrap(await client.github.repos())
1281
+ },
1282
+ devpad_github_branches: {
1283
+ name: "devpad_github_branches",
1284
+ description: "List branches for a GitHub repository",
1285
+ inputSchema: github_branches,
1286
+ execute: async (client, input) => unwrap(await client.github.branches(input.owner, input.repo))
1287
+ },
1288
+ // Additional project operations
1289
+ devpad_projects_delete: {
1290
+ name: "devpad_projects_delete",
1291
+ description: "Delete a project",
1292
+ inputSchema: z.object({
1293
+ id: z.string().describe("Project ID")
1294
+ }),
1295
+ execute: async (client, input) => {
1296
+ const project = unwrap(await client.projects.find(input.id));
1297
+ if (!project) throw new Error(`Project ${input.id} not found`);
1298
+ unwrap(await client.projects.deleteProject(project));
1299
+ return { success: true };
1300
+ }
1301
+ },
1302
+ devpad_projects_history: {
1303
+ name: "devpad_projects_history",
1304
+ description: "Get project history",
1305
+ inputSchema: z.object({
1306
+ project_id: z.string().describe("Project ID")
1307
+ }),
1308
+ execute: async (client, input) => unwrap(await client.projects.history(input.project_id))
1309
+ },
1310
+ devpad_projects_specification: {
1311
+ name: "devpad_projects_specification",
1312
+ description: "Fetch project specification from GitHub",
1313
+ inputSchema: z.object({
1314
+ project_id: z.string().describe("Project ID")
1315
+ }),
1316
+ execute: async (client, input) => unwrap(await client.projects.specification(input.project_id))
1317
+ },
1318
+ devpad_projects_config_load: {
1319
+ name: "devpad_projects_config_load",
1320
+ description: "Load project configuration",
1321
+ inputSchema: z.object({
1322
+ project_id: z.string().describe("Project ID")
1323
+ }),
1324
+ execute: async (client, input) => unwrap(await client.projects.config.load(input.project_id))
1325
+ },
1326
+ // Additional milestone operations
1327
+ devpad_milestones_delete: {
1328
+ name: "devpad_milestones_delete",
1329
+ description: "Delete a milestone",
1330
+ inputSchema: z.object({
1331
+ id: z.string().describe("Milestone ID")
1332
+ }),
1333
+ execute: async (client, input) => unwrap(await client.milestones.delete(input.id))
1334
+ },
1335
+ devpad_milestones_goals: {
1336
+ name: "devpad_milestones_goals",
1337
+ description: "Get goals for a milestone",
1338
+ inputSchema: z.object({
1339
+ id: z.string().describe("Milestone ID")
1340
+ }),
1341
+ execute: async (client, input) => unwrap(await client.milestones.goals(input.id))
1342
+ },
1343
+ // Additional goal operations
1344
+ devpad_goals_delete: {
1345
+ name: "devpad_goals_delete",
1346
+ description: "Delete a goal",
1347
+ inputSchema: z.object({
1348
+ id: z.string().describe("Goal ID")
1349
+ }),
1350
+ execute: async (client, input) => unwrap(await client.goals.delete(input.id))
1351
+ },
1352
+ // Additional task operations
1353
+ devpad_tasks_delete: {
1354
+ name: "devpad_tasks_delete",
1355
+ description: "Delete a task",
1356
+ inputSchema: z.object({
1357
+ id: z.string().describe("Task ID")
1358
+ }),
1359
+ execute: async (client, input) => {
1360
+ const task = unwrap(await client.tasks.find(input.id));
1361
+ if (!task) throw new Error(`Task ${input.id} not found`);
1362
+ unwrap(await client.tasks.deleteTask(task));
1363
+ return { success: true };
1364
+ }
1365
+ },
1366
+ devpad_tasks_history: {
1367
+ name: "devpad_tasks_history",
1368
+ description: "Get task history",
1369
+ inputSchema: z.object({
1370
+ task_id: z.string().describe("Task ID")
1371
+ }),
1372
+ execute: async (client, input) => unwrap(await client.tasks.history.get(input.task_id))
1373
+ },
1374
+ // User operations
1375
+ devpad_user_history: {
1376
+ name: "devpad_user_history",
1377
+ description: "Get user activity history",
1378
+ inputSchema: z.object({}),
1379
+ execute: async (client) => unwrap(await client.user.history())
1380
+ },
1381
+ devpad_user_preferences: {
1382
+ name: "devpad_user_preferences",
1383
+ description: "Update user preferences",
1384
+ inputSchema: z.object({
1385
+ id: z.string().describe("User ID"),
1386
+ task_view: z.enum(["list", "grid"]).describe("Task view preference")
1387
+ }),
1388
+ execute: async (client, input) => unwrap(await client.user.preferences(input))
1389
+ },
1390
+ devpad_blog_posts_list: {
1391
+ name: "devpad_blog_posts_list",
1392
+ description: "List blog posts with optional filters",
1393
+ inputSchema: z.object({
1394
+ category: z.string().optional().describe("Filter by category"),
1395
+ tag: z.string().optional().describe("Filter by tag"),
1396
+ project: z.string().optional().describe("Filter by project ID"),
1397
+ status: z.enum(["draft", "published"]).optional().describe("Filter by status"),
1398
+ archived: z.boolean().optional().describe("Filter by archived state"),
1399
+ limit: z.number().optional().describe("Max posts to return"),
1400
+ offset: z.number().optional().describe("Offset for pagination"),
1401
+ sort: z.string().optional().describe("Sort order")
1402
+ }),
1403
+ execute: async (client, input) => unwrap(await client.blog.posts.list(input))
1404
+ },
1405
+ devpad_blog_posts_get: {
1406
+ name: "devpad_blog_posts_get",
1407
+ description: "Get a blog post by slug",
1408
+ inputSchema: z.object({
1409
+ slug: z.string().describe("Post slug")
1410
+ }),
1411
+ execute: async (client, input) => unwrap(await client.blog.posts.getBySlug(input.slug))
1412
+ },
1413
+ devpad_blog_posts_create: {
1414
+ name: "devpad_blog_posts_create",
1415
+ description: "Create a new blog post",
1416
+ inputSchema: z.object({
1417
+ title: z.string().describe("Post title"),
1418
+ content: z.string().describe("Post content"),
1419
+ format: z.enum(["markdown", "html"]).describe("Content format"),
1420
+ slug: z.string().optional().describe("Custom slug"),
1421
+ category: z.string().optional().describe("Category name"),
1422
+ tags: z.array(z.string()).optional().describe("Tag names"),
1423
+ description: z.string().optional().describe("Post description"),
1424
+ publish_at: z.string().optional().describe("Scheduled publish date (ISO string)"),
1425
+ project_ids: z.array(z.string()).optional().describe("Associated project IDs"),
1426
+ archived: z.boolean().optional().describe("Whether post is archived")
1427
+ }),
1428
+ execute: async (client, input) => unwrap(await client.blog.posts.create(input))
1429
+ },
1430
+ devpad_blog_posts_update: {
1431
+ name: "devpad_blog_posts_update",
1432
+ description: "Update a blog post by UUID",
1433
+ inputSchema: z.object({
1434
+ uuid: z.string().describe("Post UUID"),
1435
+ title: z.string().optional().describe("Post title"),
1436
+ content: z.string().optional().describe("Post content"),
1437
+ format: z.enum(["markdown", "html"]).optional().describe("Content format"),
1438
+ slug: z.string().optional().describe("Custom slug"),
1439
+ category: z.string().optional().describe("Category name"),
1440
+ tags: z.array(z.string()).optional().describe("Tag names"),
1441
+ description: z.string().optional().describe("Post description"),
1442
+ publish_at: z.string().optional().describe("Scheduled publish date (ISO string)"),
1443
+ project_ids: z.array(z.string()).optional().describe("Associated project IDs"),
1444
+ archived: z.boolean().optional().describe("Whether post is archived")
1445
+ }),
1446
+ execute: async (client, input) => {
1447
+ const { uuid, ...data } = input;
1448
+ return unwrap(await client.blog.posts.update(uuid, data));
1449
+ }
1450
+ },
1451
+ devpad_blog_posts_delete: {
1452
+ name: "devpad_blog_posts_delete",
1453
+ description: "Delete a blog post by UUID",
1454
+ inputSchema: z.object({
1455
+ uuid: z.string().describe("Post UUID")
1456
+ }),
1457
+ execute: async (client, input) => unwrap(await client.blog.posts.delete(input.uuid))
1458
+ },
1459
+ devpad_blog_tags_list: {
1460
+ name: "devpad_blog_tags_list",
1461
+ description: "List all blog tags with post counts",
1462
+ inputSchema: z.object({}),
1463
+ execute: async (client) => unwrap(await client.blog.tags.list())
1464
+ },
1465
+ devpad_blog_categories_tree: {
1466
+ name: "devpad_blog_categories_tree",
1467
+ description: "Get the blog category tree",
1468
+ inputSchema: z.object({}),
1469
+ execute: async (client) => unwrap(await client.blog.categories.tree())
1470
+ },
1471
+ devpad_blog_categories_create: {
1472
+ name: "devpad_blog_categories_create",
1473
+ description: "Create a blog category",
1474
+ inputSchema: z.object({
1475
+ name: z.string().describe("Category name"),
1476
+ parent: z.string().optional().describe("Parent category name")
1477
+ }),
1478
+ execute: async (client, input) => unwrap(await client.blog.categories.create(input))
1479
+ },
1480
+ devpad_blog_tokens_list: {
1481
+ name: "devpad_blog_tokens_list",
1482
+ description: "List blog access tokens",
1483
+ inputSchema: z.object({}),
1484
+ execute: async (client) => unwrap(await client.blog.tokens.list())
1485
+ },
1486
+ devpad_blog_tokens_create: {
1487
+ name: "devpad_blog_tokens_create",
1488
+ description: "Create a blog access token",
1489
+ inputSchema: z.object({
1490
+ name: z.string().describe("Token name"),
1491
+ note: z.string().optional().describe("Optional note")
1492
+ }),
1493
+ execute: async (client, input) => unwrap(await client.blog.tokens.create(input))
1494
+ },
1495
+ devpad_media_profiles_list: {
1496
+ name: "devpad_media_profiles_list",
1497
+ description: "List media profiles",
1498
+ inputSchema: z.object({}),
1499
+ execute: async (client) => unwrap(await client.media.profiles.list())
1500
+ },
1501
+ devpad_media_profiles_create: {
1502
+ name: "devpad_media_profiles_create",
1503
+ description: "Create a media profile",
1504
+ inputSchema: z.object({
1505
+ name: z.string().describe("Profile name"),
1506
+ slug: z.string().describe("Profile slug")
1507
+ }),
1508
+ execute: async (client, input) => unwrap(await client.media.profiles.create(input))
1509
+ },
1510
+ devpad_media_profiles_get: {
1511
+ name: "devpad_media_profiles_get",
1512
+ description: "Get a media profile by ID",
1513
+ inputSchema: z.object({
1514
+ id: z.string().describe("Profile ID")
1515
+ }),
1516
+ execute: async (client, input) => unwrap(await client.media.profiles.get(input.id))
1517
+ },
1518
+ devpad_media_profiles_update: {
1519
+ name: "devpad_media_profiles_update",
1520
+ description: "Update a media profile by ID",
1521
+ inputSchema: z.object({
1522
+ id: z.string().describe("Profile ID"),
1523
+ name: z.string().optional().describe("Profile name"),
1524
+ slug: z.string().optional().describe("Profile slug")
1525
+ }),
1526
+ execute: async (client, input) => {
1527
+ const { id, ...data } = input;
1528
+ return unwrap(await client.media.profiles.update(id, data));
1529
+ }
1530
+ },
1531
+ devpad_media_profiles_delete: {
1532
+ name: "devpad_media_profiles_delete",
1533
+ description: "Delete a media profile by ID",
1534
+ inputSchema: z.object({
1535
+ id: z.string().describe("Profile ID")
1536
+ }),
1537
+ execute: async (client, input) => unwrap(await client.media.profiles.delete(input.id))
1538
+ },
1539
+ devpad_media_connections_list: {
1540
+ name: "devpad_media_connections_list",
1541
+ description: "List connections for a media profile",
1542
+ inputSchema: z.object({
1543
+ profile_id: z.string().describe("Profile ID")
1544
+ }),
1545
+ execute: async (client, input) => unwrap(await client.media.connections.list(input.profile_id))
1546
+ },
1547
+ devpad_media_connections_refresh: {
1548
+ name: "devpad_media_connections_refresh",
1549
+ description: "Refresh a media connection",
1550
+ inputSchema: z.object({
1551
+ account_id: z.string().describe("Account/connection ID")
1552
+ }),
1553
+ execute: async (client, input) => unwrap(await client.media.connections.refresh(input.account_id))
1554
+ },
1555
+ devpad_media_timeline_get: {
1556
+ name: "devpad_media_timeline_get",
1557
+ description: "Get media timeline for a user",
1558
+ inputSchema: z.object({
1559
+ user_id: z.string().describe("User ID"),
1560
+ from: z.string().optional().describe("Start date (ISO string)"),
1561
+ to: z.string().optional().describe("End date (ISO string)")
1562
+ }),
1563
+ execute: async (client, input) => {
1564
+ const { user_id, ...params } = input;
1565
+ return unwrap(await client.media.timeline.get(user_id, params));
1566
+ }
1567
+ }
1568
+ };
1569
+ var toolNames = Object.keys(tools);
1570
+ function getTool(name) {
1571
+ return tools[name];
1572
+ }
1573
+
1574
+ // src/index.ts
1575
+ var src_default = ApiClient2;
1576
+ export {
1577
+ ApiClient2 as ApiClient,
1578
+ src_default as default,
1579
+ err,
1580
+ getTool,
1581
+ getUserFriendlyErrorMessage,
1582
+ ok,
1583
+ parseZodErrors,
1584
+ toolNames,
1585
+ tools,
1586
+ wrap
1587
+ };