@gitscrum-studio/mcp-server 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (119) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +250 -0
  3. package/dist/auth/DeviceAuthenticator.d.ts +51 -0
  4. package/dist/auth/DeviceAuthenticator.d.ts.map +1 -0
  5. package/dist/auth/DeviceAuthenticator.js +89 -0
  6. package/dist/auth/DeviceAuthenticator.js.map +1 -0
  7. package/dist/auth/RateLimiter.d.ts +58 -0
  8. package/dist/auth/RateLimiter.d.ts.map +1 -0
  9. package/dist/auth/RateLimiter.js +181 -0
  10. package/dist/auth/RateLimiter.js.map +1 -0
  11. package/dist/auth/TokenManager.d.ts +62 -0
  12. package/dist/auth/TokenManager.d.ts.map +1 -0
  13. package/dist/auth/TokenManager.js +164 -0
  14. package/dist/auth/TokenManager.js.map +1 -0
  15. package/dist/client/GitScrumClient.d.ts +1002 -0
  16. package/dist/client/GitScrumClient.d.ts.map +1 -0
  17. package/dist/client/GitScrumClient.js +1835 -0
  18. package/dist/client/GitScrumClient.js.map +1 -0
  19. package/dist/context/ActiveContext.d.ts +79 -0
  20. package/dist/context/ActiveContext.d.ts.map +1 -0
  21. package/dist/context/ActiveContext.js +151 -0
  22. package/dist/context/ActiveContext.js.map +1 -0
  23. package/dist/index.d.ts +15 -0
  24. package/dist/index.d.ts.map +1 -0
  25. package/dist/index.js +152 -0
  26. package/dist/index.js.map +1 -0
  27. package/dist/tools/activity.d.ts +12 -0
  28. package/dist/tools/activity.d.ts.map +1 -0
  29. package/dist/tools/activity.js +106 -0
  30. package/dist/tools/activity.js.map +1 -0
  31. package/dist/tools/analytics.d.ts +11 -0
  32. package/dist/tools/analytics.d.ts.map +1 -0
  33. package/dist/tools/analytics.js +117 -0
  34. package/dist/tools/analytics.js.map +1 -0
  35. package/dist/tools/auth.d.ts +17 -0
  36. package/dist/tools/auth.d.ts.map +1 -0
  37. package/dist/tools/auth.js +173 -0
  38. package/dist/tools/auth.js.map +1 -0
  39. package/dist/tools/budget.d.ts +12 -0
  40. package/dist/tools/budget.d.ts.map +1 -0
  41. package/dist/tools/budget.js +109 -0
  42. package/dist/tools/budget.js.map +1 -0
  43. package/dist/tools/clientflow.d.ts +12 -0
  44. package/dist/tools/clientflow.d.ts.map +1 -0
  45. package/dist/tools/clientflow.js +476 -0
  46. package/dist/tools/clientflow.js.map +1 -0
  47. package/dist/tools/comments.d.ts +11 -0
  48. package/dist/tools/comments.d.ts.map +1 -0
  49. package/dist/tools/comments.js +99 -0
  50. package/dist/tools/comments.js.map +1 -0
  51. package/dist/tools/discussions.d.ts +12 -0
  52. package/dist/tools/discussions.d.ts.map +1 -0
  53. package/dist/tools/discussions.js +200 -0
  54. package/dist/tools/discussions.js.map +1 -0
  55. package/dist/tools/epics.d.ts +11 -0
  56. package/dist/tools/epics.d.ts.map +1 -0
  57. package/dist/tools/epics.js +122 -0
  58. package/dist/tools/epics.js.map +1 -0
  59. package/dist/tools/labels.d.ts +11 -0
  60. package/dist/tools/labels.d.ts.map +1 -0
  61. package/dist/tools/labels.js +138 -0
  62. package/dist/tools/labels.js.map +1 -0
  63. package/dist/tools/notes.d.ts +11 -0
  64. package/dist/tools/notes.d.ts.map +1 -0
  65. package/dist/tools/notes.js +201 -0
  66. package/dist/tools/notes.js.map +1 -0
  67. package/dist/tools/projects.d.ts +12 -0
  68. package/dist/tools/projects.d.ts.map +1 -0
  69. package/dist/tools/projects.js +272 -0
  70. package/dist/tools/projects.js.map +1 -0
  71. package/dist/tools/search.d.ts +17 -0
  72. package/dist/tools/search.d.ts.map +1 -0
  73. package/dist/tools/search.js +56 -0
  74. package/dist/tools/search.js.map +1 -0
  75. package/dist/tools/shared/actionHandler.d.ts +67 -0
  76. package/dist/tools/shared/actionHandler.d.ts.map +1 -0
  77. package/dist/tools/shared/actionHandler.js +98 -0
  78. package/dist/tools/shared/actionHandler.js.map +1 -0
  79. package/dist/tools/shared/initModules.d.ts +6 -0
  80. package/dist/tools/shared/initModules.d.ts.map +1 -0
  81. package/dist/tools/shared/initModules.js +166 -0
  82. package/dist/tools/shared/initModules.js.map +1 -0
  83. package/dist/tools/shared/toolRegistry.d.ts +45 -0
  84. package/dist/tools/shared/toolRegistry.d.ts.map +1 -0
  85. package/dist/tools/shared/toolRegistry.js +59 -0
  86. package/dist/tools/shared/toolRegistry.js.map +1 -0
  87. package/dist/tools/sprints.d.ts +11 -0
  88. package/dist/tools/sprints.d.ts.map +1 -0
  89. package/dist/tools/sprints.js +271 -0
  90. package/dist/tools/sprints.js.map +1 -0
  91. package/dist/tools/standup.d.ts +11 -0
  92. package/dist/tools/standup.d.ts.map +1 -0
  93. package/dist/tools/standup.js +89 -0
  94. package/dist/tools/standup.js.map +1 -0
  95. package/dist/tools/taskTypes.d.ts +11 -0
  96. package/dist/tools/taskTypes.d.ts.map +1 -0
  97. package/dist/tools/taskTypes.js +132 -0
  98. package/dist/tools/taskTypes.js.map +1 -0
  99. package/dist/tools/tasks.d.ts +12 -0
  100. package/dist/tools/tasks.d.ts.map +1 -0
  101. package/dist/tools/tasks.js +470 -0
  102. package/dist/tools/tasks.js.map +1 -0
  103. package/dist/tools/timeTracking.d.ts +11 -0
  104. package/dist/tools/timeTracking.d.ts.map +1 -0
  105. package/dist/tools/timeTracking.js +174 -0
  106. package/dist/tools/timeTracking.js.map +1 -0
  107. package/dist/tools/userStories.d.ts +11 -0
  108. package/dist/tools/userStories.d.ts.map +1 -0
  109. package/dist/tools/userStories.js +166 -0
  110. package/dist/tools/userStories.js.map +1 -0
  111. package/dist/tools/wiki.d.ts +11 -0
  112. package/dist/tools/wiki.d.ts.map +1 -0
  113. package/dist/tools/wiki.js +154 -0
  114. package/dist/tools/wiki.js.map +1 -0
  115. package/dist/tools/workflows.d.ts +11 -0
  116. package/dist/tools/workflows.d.ts.map +1 -0
  117. package/dist/tools/workflows.js +144 -0
  118. package/dist/tools/workflows.js.map +1 -0
  119. package/package.json +89 -0
@@ -0,0 +1,1835 @@
1
+ /**
2
+ * GitScrum API Client
3
+ *
4
+ * HTTP client for communicating with the GitScrum REST API.
5
+ * Provides type-safe methods for all GitScrum resources including
6
+ * tasks, projects, sprints, time tracking, and ClientFlow CRM.
7
+ *
8
+ * Features:
9
+ * - JWT authentication with secure token storage
10
+ * - Comprehensive error handling with user-friendly messages
11
+ * - Rate limiting and retry logic
12
+ * - Full TypeScript support
13
+ *
14
+ * @module @gitscrum-studio/mcp-server/client
15
+ * @author GitScrum <hello@gitscrum.com>
16
+ * @license MIT
17
+ */
18
+ import { TokenManager } from "../auth/TokenManager.js";
19
+ export class GitScrumClient {
20
+ baseUrl;
21
+ token;
22
+ tokenManager;
23
+ constructor() {
24
+ this.baseUrl = process.env.GITSCRUM_API_URL || "https://services.gitscrum.com";
25
+ this.tokenManager = new TokenManager();
26
+ // Try to get token from environment or saved file
27
+ this.token = this.tokenManager.getToken() || "";
28
+ if (!this.token) {
29
+ console.error("Warning: No authentication token found. Use auth_login tool to authenticate.");
30
+ }
31
+ }
32
+ /**
33
+ * Set the authentication token
34
+ */
35
+ setToken(token) {
36
+ this.token = token;
37
+ }
38
+ /**
39
+ * Check if client is authenticated
40
+ */
41
+ isAuthenticated() {
42
+ return !!this.token;
43
+ }
44
+ /**
45
+ * Logout and invalidate token
46
+ */
47
+ async logout() {
48
+ if (this.token) {
49
+ try {
50
+ await this.post("auth/logout", {});
51
+ }
52
+ catch {
53
+ // Ignore errors during logout
54
+ }
55
+ }
56
+ this.token = "";
57
+ }
58
+ /**
59
+ * Make an authenticated request to the GitScrum API
60
+ */
61
+ async request(endpoint, options = {}) {
62
+ const url = `${this.baseUrl}/${endpoint.replace(/^\//, "")}`;
63
+ const response = await fetch(url, {
64
+ ...options,
65
+ headers: {
66
+ Authorization: `Bearer ${this.token}`,
67
+ Accept: "application/json",
68
+ "Content-Type": "application/json",
69
+ "X-Client-Type": "mcp",
70
+ "X-Client-Source": "mcp-server",
71
+ ...options.headers,
72
+ },
73
+ });
74
+ if (!response.ok) {
75
+ const errorData = (await response.json().catch(() => ({})));
76
+ const errorMessage = errorData.message || `API Error: ${response.status}`;
77
+ // Handle 400 Bad Request - validation or invalid input
78
+ if (response.status === 400) {
79
+ throw new Error(`Invalid request: ${errorMessage}`);
80
+ }
81
+ // Handle 401 Unauthorized - authentication issue
82
+ if (response.status === 401) {
83
+ throw new Error("Session expired. Authentication required. Use login to reconnect.");
84
+ }
85
+ // Handle 403 Forbidden
86
+ if (response.status === 403) {
87
+ throw new Error(`Access denied: ${errorMessage}`);
88
+ }
89
+ // Handle 404 Not Found
90
+ if (response.status === 404) {
91
+ throw new Error("Resource not found or was deleted.");
92
+ }
93
+ // Handle 409 Conflict - resource conflict (e.g., duplicate, pending operation)
94
+ if (response.status === 409) {
95
+ throw new Error(`Conflict: ${errorMessage}`);
96
+ }
97
+ // Handle 422 Unprocessable Entity - validation errors
98
+ if (response.status === 422) {
99
+ throw new Error(JSON.stringify({
100
+ error: "validation_failed",
101
+ message: errorMessage,
102
+ validation_errors: errorData.errors
103
+ }));
104
+ }
105
+ // Handle 429 Too Many Requests - MCP rate limit exceeded
106
+ if (response.status === 429) {
107
+ throw new Error(JSON.stringify({
108
+ error: "rate_limit_exceeded",
109
+ limit: response.headers.get("X-MCP-RateLimit-Limit"),
110
+ remaining: response.headers.get("X-MCP-RateLimit-Remaining"),
111
+ reset: response.headers.get("X-MCP-RateLimit-Reset"),
112
+ upgrade_url: "https://gitscrum.com/pricing"
113
+ }));
114
+ }
115
+ // Handle 500+ Server Errors
116
+ if (response.status >= 500) {
117
+ throw new Error(`Server error: ${errorMessage}`);
118
+ }
119
+ throw new Error(errorMessage);
120
+ }
121
+ return (await response.json());
122
+ }
123
+ /**
124
+ * GET request helper
125
+ */
126
+ async get(endpoint, params) {
127
+ let url = endpoint;
128
+ if (params) {
129
+ const searchParams = new URLSearchParams();
130
+ for (const [key, value] of Object.entries(params)) {
131
+ if (value !== undefined && value !== null) {
132
+ searchParams.append(key, String(value));
133
+ }
134
+ }
135
+ const queryString = searchParams.toString();
136
+ if (queryString) {
137
+ url += `?${queryString}`;
138
+ }
139
+ }
140
+ return this.request(url, { method: "GET" });
141
+ }
142
+ /**
143
+ * POST request helper
144
+ */
145
+ async post(endpoint, body) {
146
+ return this.request(endpoint, {
147
+ method: "POST",
148
+ body: body ? JSON.stringify(body) : undefined,
149
+ });
150
+ }
151
+ /**
152
+ * PUT request helper
153
+ */
154
+ async put(endpoint, body) {
155
+ return this.request(endpoint, {
156
+ method: "PUT",
157
+ body: body ? JSON.stringify(body) : undefined,
158
+ });
159
+ }
160
+ /**
161
+ * DELETE request helper
162
+ */
163
+ async delete(endpoint) {
164
+ return this.request(endpoint, { method: "DELETE" });
165
+ }
166
+ // ============================================================================
167
+ // AUTH / USER
168
+ // ============================================================================
169
+ /**
170
+ * Get current authenticated user
171
+ */
172
+ async getMe() {
173
+ const response = await this.post("auth/me");
174
+ return response.data;
175
+ }
176
+ // ============================================================================
177
+ // WORKSPACES (Companies)
178
+ // ============================================================================
179
+ /**
180
+ * Get all workspaces the user has access to (with pagination metadata)
181
+ * Uses the new /workspaces endpoint with proper pagination
182
+ */
183
+ async getWorkspaces(options) {
184
+ const params = {};
185
+ if (options?.perPage)
186
+ params.per_page = options.perPage;
187
+ if (options?.page)
188
+ params.page = options.page;
189
+ if (options?.search)
190
+ params.search = options.search;
191
+ const response = await this.get("workspaces", params);
192
+ return response;
193
+ }
194
+ /**
195
+ * Find workspace by name and return slug
196
+ * Searches workspaces by name and returns the first match with its slug
197
+ */
198
+ async findWorkspaceByName(name) {
199
+ const response = await this.getWorkspaces({ search: name, perPage: 5 });
200
+ const workspaces = response.data;
201
+ if (!workspaces || workspaces.length === 0) {
202
+ return null;
203
+ }
204
+ // Return exact match if found, otherwise first result
205
+ const exactMatch = workspaces.find(w => w.name.toLowerCase() === name.toLowerCase());
206
+ return exactMatch || workspaces[0];
207
+ }
208
+ /**
209
+ * Get workspace details
210
+ */
211
+ async getWorkspace(slug) {
212
+ const response = await this.get(`workspaces/${slug}`);
213
+ return response.data;
214
+ }
215
+ /**
216
+ * Get workspace statistics
217
+ */
218
+ async getWorkspaceStats(companySlug) {
219
+ const response = await this.get(`workspaces/${companySlug}/stats`);
220
+ return response.data;
221
+ }
222
+ // ============================================================================
223
+ // PROJECTS
224
+ // ============================================================================
225
+ /**
226
+ * Create a new project in a workspace
227
+ */
228
+ async createProject(companySlug, data) {
229
+ const response = await this.post(`projects?company_slug=${companySlug}`, data);
230
+ return {
231
+ project_slug: response.data.slug,
232
+ name: response.data.name,
233
+ };
234
+ }
235
+ /**
236
+ * Get all projects in a workspace (with pagination metadata)
237
+ */
238
+ async getProjects(companySlug, options) {
239
+ const params = {
240
+ company_slug: companySlug,
241
+ per_page: options?.perPage ?? 100,
242
+ };
243
+ if (options?.status) {
244
+ params.status = options.status;
245
+ }
246
+ const response = await this.get("projects", params);
247
+ return response;
248
+ }
249
+ /**
250
+ * Find project by name within a workspace and return slug info
251
+ * Uses search endpoint to find project by name
252
+ */
253
+ async findProjectByName(name, companySlug) {
254
+ const results = await this.search(name, {
255
+ company_slug: companySlug,
256
+ categories: 'projects',
257
+ limit: 5,
258
+ });
259
+ const projects = results?.projects?.items;
260
+ if (!projects || projects.length === 0) {
261
+ return null;
262
+ }
263
+ // Parse route to extract slugs: "/{company_slug}/projects/{project_slug}"
264
+ const parseRoute = (route) => {
265
+ const match = route.match(/^\/([^/]+)\/projects\/([^/]+)$/);
266
+ if (match) {
267
+ return { company_slug: match[1], project_slug: match[2] };
268
+ }
269
+ return null;
270
+ };
271
+ // Find exact match first
272
+ const exactMatch = projects.find(p => p.title.toLowerCase() === name.toLowerCase());
273
+ const project = exactMatch || projects[0];
274
+ const slugs = parseRoute(project.route);
275
+ if (!slugs) {
276
+ return null;
277
+ }
278
+ return {
279
+ project_slug: slugs.project_slug,
280
+ company_slug: slugs.company_slug,
281
+ name: project.title,
282
+ workspace_slug: companySlug || slugs.company_slug,
283
+ };
284
+ }
285
+ /**
286
+ * Get project details
287
+ */
288
+ async getProject(projectSlug, companySlug) {
289
+ const response = await this.get(`projects/${projectSlug}`, {
290
+ company_slug: companySlug,
291
+ });
292
+ return response.data;
293
+ }
294
+ /**
295
+ * Get project workflows/statuses (Kanban columns)
296
+ */
297
+ async getProjectWorkflows(projectSlug, companySlug) {
298
+ const response = await this.get("project-templates/workflow", {
299
+ project_slug: projectSlug,
300
+ company_slug: companySlug,
301
+ });
302
+ return response.data;
303
+ }
304
+ /**
305
+ * Create a new workflow/column in a project Kanban board
306
+ */
307
+ async createWorkflow(projectSlug, companySlug, data) {
308
+ const response = await this.post(`projects-workflows/?company_slug=${companySlug}&project_slug=${projectSlug}`, data);
309
+ return response.data;
310
+ }
311
+ /**
312
+ * Update an existing workflow/column
313
+ */
314
+ async updateWorkflow(workflowId, companySlug, projectSlug, data) {
315
+ await this.put(`projects-workflows/${workflowId}/?company_slug=${companySlug}&project_slug=${projectSlug}`, data);
316
+ }
317
+ /**
318
+ * Get project task types
319
+ */
320
+ async getProjectTypes(projectSlug, companySlug) {
321
+ const response = await this.get("project-templates/type", {
322
+ project_slug: projectSlug,
323
+ company_slug: companySlug,
324
+ });
325
+ return response.data;
326
+ }
327
+ /**
328
+ * Get project efforts/priorities
329
+ */
330
+ async getProjectEfforts(projectSlug, companySlug) {
331
+ const response = await this.get("project-templates/effort", {
332
+ project_slug: projectSlug,
333
+ company_slug: companySlug,
334
+ });
335
+ return response.data;
336
+ }
337
+ /**
338
+ * Get project labels
339
+ */
340
+ async getProjectLabels(projectSlug, companySlug) {
341
+ const response = await this.get("task-labels", {
342
+ project_slug: projectSlug,
343
+ company_slug: companySlug,
344
+ });
345
+ return response.data;
346
+ }
347
+ /**
348
+ * Get project members/assignees
349
+ * Returns usernames that can be assigned to tasks
350
+ */
351
+ async getProjectMembers(projectSlug, companySlug) {
352
+ // Returns direct array of assignees with uuid, name, username, avatar
353
+ const response = await this.get(`project-members/${projectSlug}/assignees`, {
354
+ company_slug: companySlug,
355
+ });
356
+ return response;
357
+ }
358
+ /**
359
+ * Get project statistics
360
+ */
361
+ async getProjectStats(projectSlug, companySlug) {
362
+ const response = await this.get(`projects/${projectSlug}/stats`, {
363
+ company_slug: companySlug,
364
+ });
365
+ return response.data;
366
+ }
367
+ // ============================================================================
368
+ // TASKS
369
+ // ============================================================================
370
+ /**
371
+ * Get all tasks assigned to current user across all workspaces (with pagination metadata)
372
+ */
373
+ async getMyTasks(perPage = 100) {
374
+ const response = await this.get("tasks/all-workspaces", {
375
+ per_page: perPage,
376
+ });
377
+ return response;
378
+ }
379
+ /**
380
+ * Get user notifications (mentions, assignments, updates)
381
+ */
382
+ async getNotifications() {
383
+ const response = await this.get("feeds/notifications");
384
+ return response.data || [];
385
+ }
386
+ /**
387
+ * Get unread notification count
388
+ */
389
+ async getNotificationCount() {
390
+ const response = await this.get("feeds/notifications/count");
391
+ return response.data || 0;
392
+ }
393
+ /**
394
+ * Get today's tasks for current user (with pagination metadata)
395
+ */
396
+ async getTodayTasks(limit = 50) {
397
+ const response = await this.get("tasks/my-today", {
398
+ limit,
399
+ });
400
+ return response;
401
+ }
402
+ /**
403
+ * Get task details by UUID
404
+ */
405
+ async getTask(uuid) {
406
+ const response = await this.get(`tasks/${uuid}`);
407
+ return response.data;
408
+ }
409
+ /**
410
+ * Get tasks in a project (with pagination metadata)
411
+ */
412
+ async getProjectTasks(projectSlug, companySlug, perPage = 100) {
413
+ const response = await this.get("tasks", {
414
+ project_slug: projectSlug,
415
+ company_slug: companySlug,
416
+ per_page: perPage,
417
+ });
418
+ return response;
419
+ }
420
+ /**
421
+ * Advanced task search with comprehensive filters
422
+ * Supports filtering by workflow (status/column), labels, types, efforts, sprints, user stories,
423
+ * date ranges, assignees, flags (blocker, bug, unassigned), and text search.
424
+ */
425
+ async searchTasks(projectSlug, companySlug, filters = {}) {
426
+ const params = {
427
+ project_slug: projectSlug,
428
+ company_slug: companySlug,
429
+ per_page: filters.per_page || 50,
430
+ };
431
+ if (filters.page)
432
+ params.page = filters.page;
433
+ if (filters.title)
434
+ params.title = filters.title;
435
+ if (filters.description)
436
+ params.description = filters.description;
437
+ if (filters.number)
438
+ params.number = filters.number;
439
+ if (filters.status)
440
+ params.status = filters.status;
441
+ if (filters.users)
442
+ params.users = filters.users;
443
+ if (filters.start_date)
444
+ params.start_date = filters.start_date;
445
+ if (filters.due_date)
446
+ params.due_date = filters.due_date;
447
+ if (filters.created_at)
448
+ params.created_at = filters.created_at;
449
+ if (filters.closed_at)
450
+ params.closed_at = filters.closed_at;
451
+ if (filters.is_blocker)
452
+ params.is_blocker = 1;
453
+ if (filters.is_bug)
454
+ params.is_bug = 1;
455
+ if (filters.unassigned)
456
+ params.unassigned = 1;
457
+ if (filters.is_archived)
458
+ params.is_archived = 1;
459
+ if (filters.workflow)
460
+ params.workflows = filters.workflow;
461
+ if (filters.labels)
462
+ params.labels = filters.labels;
463
+ if (filters.type)
464
+ params.types = filters.type;
465
+ if (filters.effort)
466
+ params.efforts = filters.effort;
467
+ if (filters.sprint)
468
+ params.sprints = filters.sprint;
469
+ if (filters.user_story)
470
+ params.user_stories = filters.user_story;
471
+ return this.get("tasks", params);
472
+ }
473
+ /**
474
+ * Create a new task
475
+ *
476
+ * @param data - Task creation data
477
+ * @param data.title - Task title (required)
478
+ * @param data.project_slug - Project slug (required)
479
+ * @param data.company_slug - Workspace slug (required)
480
+ * @param data.description - Task description
481
+ * @param data.workflow_id - Workflow/status ID (use project_get_workflows to discover)
482
+ * @param data.effort_id - Effort/priority ID (use project_get_efforts to discover)
483
+ * @param data.type_id - Task type ID (use project_get_types to discover)
484
+ * @param data.usernames - Array of usernames to assign (use project_get_members to discover)
485
+ * @param data.label_ids - Array of label IDs (use project_get_labels to discover)
486
+ * @param data.board_id - Board UUID (from project boards)
487
+ * @param data.due_date - Due date (YYYY-MM-DD)
488
+ * @param data.start_date - Start date (YYYY-MM-DD)
489
+ * @param data.estimated_minutes - Time estimate in minutes
490
+ * @param data.sprint_slug - Sprint slug to add task to
491
+ * @param data.user_story_slug - User story slug
492
+ * @param data.parent_id - Parent task UUID for subtasks
493
+ */
494
+ async createTask(data) {
495
+ const response = await this.post("tasks", data);
496
+ return response.data;
497
+ }
498
+ /**
499
+ * Update a task
500
+ */
501
+ async updateTask(uuid, data) {
502
+ const response = await this.put(`tasks/${uuid}`, data);
503
+ return response.data;
504
+ }
505
+ /**
506
+ * Complete a task
507
+ */
508
+ async completeTask(uuid) {
509
+ const response = await this.put(`tasks/${uuid}/complete`, {});
510
+ return response;
511
+ }
512
+ /**
513
+ * Get sub-tasks
514
+ */
515
+ async getSubTasks(taskUuid) {
516
+ const response = await this.get(`tasks/${taskUuid}/sub-tasks`);
517
+ return response.data;
518
+ }
519
+ // ============================================================================
520
+ // SPRINTS
521
+ // ============================================================================
522
+ /**
523
+ * Get sprints in a project (with pagination metadata)
524
+ */
525
+ async getSprints(projectSlug, companySlug) {
526
+ const response = await this.get("sprints", {
527
+ project_slug: projectSlug,
528
+ company_slug: companySlug,
529
+ });
530
+ return response;
531
+ }
532
+ /**
533
+ * Get all sprints across workspaces (with pagination metadata)
534
+ */
535
+ async getAllSprints() {
536
+ const response = await this.get("sprints/all-workspaces");
537
+ return response;
538
+ }
539
+ /**
540
+ * Get sprint details
541
+ */
542
+ async getSprint(slug, projectSlug, companySlug) {
543
+ const response = await this.get(`sprints/${slug}`, {
544
+ project_slug: projectSlug,
545
+ company_slug: companySlug,
546
+ });
547
+ return response.data;
548
+ }
549
+ /**
550
+ * Get sprint KPIs
551
+ */
552
+ async getSprintKPIs(slug, projectSlug, companySlug) {
553
+ const response = await this.get(`sprints/${slug}/kpis`, {
554
+ project_slug: projectSlug,
555
+ company_slug: companySlug,
556
+ });
557
+ return response.data;
558
+ }
559
+ /**
560
+ * Create a new sprint
561
+ */
562
+ async createSprint(projectSlug, companySlug, data) {
563
+ const response = await this.post(`sprints?company_slug=${companySlug}&project_slug=${projectSlug}`, data);
564
+ return response.data;
565
+ }
566
+ /**
567
+ * Update an existing sprint
568
+ */
569
+ async updateSprint(slug, projectSlug, companySlug, data) {
570
+ await this.put(`sprints/${slug}?company_slug=${companySlug}&project_slug=${projectSlug}`, data);
571
+ }
572
+ // ============================================================================
573
+ // TIME TRACKING
574
+ // ============================================================================
575
+ /**
576
+ * Get active timer
577
+ */
578
+ async getActiveTimer(companySlug) {
579
+ const params = {};
580
+ if (companySlug)
581
+ params.company_slug = companySlug;
582
+ const response = await this.get("time-trackings/active", params);
583
+ return response.data;
584
+ }
585
+ /**
586
+ * Start timer for a task
587
+ */
588
+ async startTimer(taskUuid, description) {
589
+ const response = await this.post("time-trackings", {
590
+ task_uuid: taskUuid,
591
+ work_description: description,
592
+ });
593
+ return response.data;
594
+ }
595
+ /**
596
+ * Stop timer
597
+ *
598
+ * @param timeTrackingId - ID of the time tracker to stop
599
+ */
600
+ async stopTimer(timeTrackingId) {
601
+ const response = await this.put(`time-trackings/${timeTrackingId}`, {
602
+ end: new Date().toISOString(),
603
+ });
604
+ return response.data;
605
+ }
606
+ /**
607
+ * Get time logs for a project
608
+ */
609
+ async getTimeLogs(projectSlug, companySlug) {
610
+ const response = await this.get("time-trackings", {
611
+ project_slug: projectSlug,
612
+ company_slug: companySlug,
613
+ });
614
+ return response.data;
615
+ }
616
+ // ============================================================================
617
+ // USER STORIES
618
+ // ============================================================================
619
+ /**
620
+ * Get user stories in a project (with pagination metadata)
621
+ */
622
+ async getUserStories(projectSlug, companySlug) {
623
+ const response = await this.get("user-stories", {
624
+ project_slug: projectSlug,
625
+ company_slug: companySlug,
626
+ });
627
+ return response;
628
+ }
629
+ /**
630
+ * Get user story details
631
+ */
632
+ async getUserStory(slug, projectSlug, companySlug) {
633
+ const response = await this.get(`user-stories/${slug}`, {
634
+ project_slug: projectSlug,
635
+ company_slug: companySlug,
636
+ });
637
+ return response.data;
638
+ }
639
+ /**
640
+ * Create user story
641
+ */
642
+ async createUserStory(data) {
643
+ const response = await this.post("user-stories", data);
644
+ return response.data;
645
+ }
646
+ /**
647
+ * Update user story
648
+ */
649
+ async updateUserStory(slug, data) {
650
+ const response = await this.put(`user-stories/${slug}`, data);
651
+ return response;
652
+ }
653
+ // ============================================================================
654
+ // WIKI
655
+ // ============================================================================
656
+ /**
657
+ * Get wiki pages in a project
658
+ */
659
+ async getWikiPages(projectSlug, companySlug) {
660
+ const response = await this.get("wiki/pages", {
661
+ project_slug: projectSlug,
662
+ company_slug: companySlug,
663
+ });
664
+ return response.data;
665
+ }
666
+ /**
667
+ * Get wiki page content
668
+ */
669
+ async getWikiPage(uuid, projectSlug, companySlug) {
670
+ const response = await this.get(`wiki/pages/${uuid}`, {
671
+ project_slug: projectSlug,
672
+ company_slug: companySlug,
673
+ });
674
+ return response.data;
675
+ }
676
+ /**
677
+ * Create wiki page
678
+ */
679
+ async createWikiPage(data) {
680
+ const response = await this.post("wiki/pages", data);
681
+ return response.data;
682
+ }
683
+ /**
684
+ * Update wiki page
685
+ */
686
+ async updateWikiPage(uuid, projectSlug, companySlug, data) {
687
+ const response = await this.put(`wiki/pages/${uuid}`, {
688
+ ...data,
689
+ project_slug: projectSlug,
690
+ company_slug: companySlug,
691
+ });
692
+ return response.data;
693
+ }
694
+ // ============================================================================
695
+ // SEARCH
696
+ // ============================================================================
697
+ /**
698
+ * Global search across all entities
699
+ *
700
+ * @param query - Search query string (min 2 chars)
701
+ * @param options - Search options
702
+ * @param options.company_slug - Optional workspace to search in (searches all if omitted)
703
+ * @param options.categories - Comma-separated categories: tasks,projects,user_stories,sprints,wiki,notes
704
+ * @param options.limit - Max results per category (default 5)
705
+ */
706
+ async search(query, options) {
707
+ const params = {
708
+ q: query,
709
+ };
710
+ if (options?.company_slug) {
711
+ params.company_slug = options.company_slug;
712
+ }
713
+ if (options?.categories) {
714
+ params.categories = options.categories;
715
+ }
716
+ if (options?.limit) {
717
+ params.limit = options.limit;
718
+ }
719
+ const response = await this.get("search", params);
720
+ return response.data;
721
+ }
722
+ // ============================================================================
723
+ // NOTEVAULT - NOTES
724
+ // ============================================================================
725
+ /**
726
+ * Get all notes for the current user
727
+ */
728
+ async getNotes(companySlug, options) {
729
+ const params = {};
730
+ if (companySlug)
731
+ params.company_slug = companySlug;
732
+ if (options?.folder_uuid)
733
+ params.folder_uuid = options.folder_uuid;
734
+ if (options?.color)
735
+ params.color = options.color;
736
+ if (options?.search)
737
+ params.search = options.search;
738
+ const response = await this.get("notes", params);
739
+ return response.data;
740
+ }
741
+ /**
742
+ * Get a specific note by UUID
743
+ */
744
+ async getNote(uuid, companySlug) {
745
+ const params = {};
746
+ if (companySlug)
747
+ params.company_slug = companySlug;
748
+ const response = await this.get(`notes/${uuid}`, params);
749
+ return response.data;
750
+ }
751
+ /**
752
+ * Create a new note
753
+ */
754
+ async createNote(data) {
755
+ const response = await this.post("notes", data);
756
+ return response.data;
757
+ }
758
+ /**
759
+ * Update an existing note
760
+ */
761
+ async updateNote(uuid, data) {
762
+ const response = await this.put(`notes/${uuid}`, data);
763
+ return response.data;
764
+ }
765
+ /**
766
+ * Toggle note sharing (enable/disable public link)
767
+ */
768
+ async toggleNoteShare(uuid) {
769
+ const response = await this.put(`notes/${uuid}/share/toggle`, {});
770
+ return response.data;
771
+ }
772
+ /**
773
+ * Get note revision history
774
+ */
775
+ async getNoteRevisions(uuid, companySlug) {
776
+ const response = await this.get(`notes/${uuid}/revisions`, {
777
+ company_slug: companySlug,
778
+ });
779
+ return response.data;
780
+ }
781
+ // ============================================================================
782
+ // NOTEVAULT - FOLDERS
783
+ // ============================================================================
784
+ /**
785
+ * Get all note folders
786
+ */
787
+ async getNoteFolders(companySlug) {
788
+ const response = await this.get("note-folders", {
789
+ company_slug: companySlug,
790
+ });
791
+ return response.data;
792
+ }
793
+ /**
794
+ * Create a new note folder
795
+ */
796
+ async createNoteFolder(data) {
797
+ const response = await this.post("note-folders", data);
798
+ return response.data;
799
+ }
800
+ /**
801
+ * Update a note folder
802
+ */
803
+ async updateNoteFolder(uuid, data) {
804
+ const response = await this.put(`note-folders/${uuid}`, data);
805
+ return response.data;
806
+ }
807
+ /**
808
+ * Move a note to a folder
809
+ */
810
+ async moveNoteToFolder(noteUuid, folderUuid) {
811
+ const response = await this.post("note-folders/move-note", {
812
+ note_uuid: noteUuid,
813
+ folder_uuid: folderUuid,
814
+ });
815
+ return response;
816
+ }
817
+ // ============================================================================
818
+ // CLIENTFLOW - CLIENTS
819
+ // ============================================================================
820
+ /**
821
+ * Get all clients
822
+ */
823
+ async getClients(companySlug) {
824
+ const response = await this.get("contact-companies/clients", {
825
+ company_slug: companySlug,
826
+ });
827
+ return response.data;
828
+ }
829
+ /**
830
+ * Get client details
831
+ */
832
+ async getClient(uuid, companySlug) {
833
+ const response = await this.get(`contact-companies/${uuid}`, {
834
+ company_slug: companySlug,
835
+ });
836
+ return response.data;
837
+ }
838
+ /**
839
+ * Get client statistics
840
+ */
841
+ async getClientStats(uuid, companySlug) {
842
+ const response = await this.get(`contact-companies/${uuid}/stats`, {
843
+ company_slug: companySlug,
844
+ });
845
+ return response.data;
846
+ }
847
+ /**
848
+ * Create a new client
849
+ */
850
+ async createClient(data) {
851
+ const response = await this.post("contact-companies", data);
852
+ return response.data;
853
+ }
854
+ /**
855
+ * Update a client
856
+ */
857
+ async updateClient(uuid, data) {
858
+ const response = await this.put(`contact-companies/${uuid}`, data);
859
+ return response.data;
860
+ }
861
+ // ============================================================================
862
+ // CLIENTFLOW - INVOICES
863
+ // ============================================================================
864
+ /**
865
+ * Get all invoices
866
+ */
867
+ async getInvoices(companySlug, options) {
868
+ const response = await this.get("company-invoices", {
869
+ company_slug: companySlug,
870
+ ...options,
871
+ });
872
+ return response.data;
873
+ }
874
+ /**
875
+ * Get invoice details
876
+ */
877
+ async getInvoice(uuid, companySlug) {
878
+ const response = await this.get(`company-invoices/${uuid}`, {
879
+ company_slug: companySlug,
880
+ });
881
+ return response.data;
882
+ }
883
+ /**
884
+ * Get invoice statistics
885
+ */
886
+ async getInvoiceStats(companySlug) {
887
+ const response = await this.get("company-invoices/stats", {
888
+ company_slug: companySlug,
889
+ });
890
+ return response.data;
891
+ }
892
+ /**
893
+ * Create an invoice
894
+ */
895
+ async createInvoice(data) {
896
+ const response = await this.post("company-invoices", data);
897
+ return response.data;
898
+ }
899
+ /**
900
+ * Update an invoice
901
+ */
902
+ async updateInvoice(uuid, data) {
903
+ const response = await this.put(`company-invoices/${uuid}`, data);
904
+ return response.data;
905
+ }
906
+ /**
907
+ * Issue/publish an invoice
908
+ */
909
+ async issueInvoice(uuid) {
910
+ const response = await this.post(`company-invoices/${uuid}/issue`, {});
911
+ return response.data;
912
+ }
913
+ /**
914
+ * Send invoice to client
915
+ */
916
+ async sendInvoice(uuid) {
917
+ const response = await this.post(`company-invoices/${uuid}/send`, {});
918
+ return response.data;
919
+ }
920
+ /**
921
+ * Mark invoice as paid
922
+ */
923
+ async markInvoicePaid(uuid) {
924
+ const response = await this.post(`company-invoices/${uuid}/paid`, {});
925
+ return response.data;
926
+ }
927
+ // ============================================================================
928
+ // CLIENTFLOW - PROPOSALS
929
+ // ============================================================================
930
+ /**
931
+ * Get all proposals
932
+ */
933
+ async getProposals(companySlug, options) {
934
+ const response = await this.get("proposals", {
935
+ company_slug: companySlug,
936
+ ...options,
937
+ });
938
+ return response.data;
939
+ }
940
+ /**
941
+ * Get proposal details
942
+ */
943
+ async getProposal(uuid, companySlug) {
944
+ const response = await this.get(`proposals/${uuid}`, {
945
+ company_slug: companySlug,
946
+ });
947
+ return response.data;
948
+ }
949
+ /**
950
+ * Get proposal statistics
951
+ */
952
+ async getProposalStats(companySlug) {
953
+ const response = await this.get("proposals/stats", {
954
+ company_slug: companySlug,
955
+ });
956
+ return response.data;
957
+ }
958
+ /**
959
+ * Create a proposal
960
+ */
961
+ async createProposal(data) {
962
+ const response = await this.post("proposals", data);
963
+ return response.data;
964
+ }
965
+ /**
966
+ * Update a proposal
967
+ */
968
+ async updateProposal(uuid, data) {
969
+ const response = await this.put(`proposals/${uuid}`, data);
970
+ return response.data;
971
+ }
972
+ /**
973
+ * Send proposal to client
974
+ */
975
+ async sendProposal(uuid) {
976
+ const response = await this.post(`proposals/${uuid}/send`, {});
977
+ return response.data;
978
+ }
979
+ /**
980
+ * Approve a proposal
981
+ */
982
+ async approveProposal(uuid) {
983
+ const response = await this.post(`proposals/${uuid}/approve`, {});
984
+ return response.data;
985
+ }
986
+ /**
987
+ * Reject a proposal
988
+ */
989
+ async rejectProposal(uuid, reason) {
990
+ const response = await this.post(`proposals/${uuid}/reject`, { reason });
991
+ return response.data;
992
+ }
993
+ /**
994
+ * Convert proposal to project
995
+ */
996
+ async convertProposalToProject(uuid) {
997
+ const response = await this.post(`proposals/${uuid}/convert-to-project`, {});
998
+ return response.data;
999
+ }
1000
+ // ============================================================================
1001
+ // CLIENTFLOW - DASHBOARD
1002
+ // ============================================================================
1003
+ /**
1004
+ * Get ClientFlow dashboard overview
1005
+ */
1006
+ async getClientFlowOverview(companySlug) {
1007
+ const response = await this.get("client-flow/dashboard/overview", {
1008
+ company_slug: companySlug,
1009
+ });
1010
+ return response.data;
1011
+ }
1012
+ /**
1013
+ * Get revenue pipeline
1014
+ */
1015
+ async getRevenuePipeline(companySlug) {
1016
+ const response = await this.get("client-flow/dashboard/revenue-pipeline", {
1017
+ company_slug: companySlug,
1018
+ });
1019
+ return response.data;
1020
+ }
1021
+ /**
1022
+ * Get clients at risk
1023
+ */
1024
+ async getClientsAtRisk(companySlug) {
1025
+ const response = await this.get("client-flow/dashboard/clients-at-risk", {
1026
+ company_slug: companySlug,
1027
+ });
1028
+ return response.data;
1029
+ }
1030
+ /**
1031
+ * Get pending approvals
1032
+ */
1033
+ async getPendingApprovals(companySlug) {
1034
+ const response = await this.get("client-flow/dashboard/pending-approvals", {
1035
+ company_slug: companySlug,
1036
+ });
1037
+ return response.data;
1038
+ }
1039
+ /**
1040
+ * Get projects health
1041
+ */
1042
+ async getProjectsHealth(companySlug) {
1043
+ const response = await this.get("client-flow/dashboard/projects-health", {
1044
+ company_slug: companySlug,
1045
+ });
1046
+ return response.data;
1047
+ }
1048
+ /**
1049
+ * Get actionable insights
1050
+ */
1051
+ async getActionableInsights(companySlug) {
1052
+ const response = await this.get("client-flow/dashboard/insights", {
1053
+ company_slug: companySlug,
1054
+ });
1055
+ return response.data;
1056
+ }
1057
+ /**
1058
+ * Get client leaderboard
1059
+ */
1060
+ async getClientLeaderboard(companySlug) {
1061
+ const response = await this.get("client-flow/dashboard/leaderboard", {
1062
+ company_slug: companySlug,
1063
+ });
1064
+ return response.data;
1065
+ }
1066
+ /**
1067
+ * Get analytics
1068
+ */
1069
+ async getClientFlowAnalytics(companySlug) {
1070
+ const response = await this.get("client-flow/dashboard/analytics", {
1071
+ company_slug: companySlug,
1072
+ });
1073
+ return response.data;
1074
+ }
1075
+ // ============================================================================
1076
+ // CLIENTFLOW - CROSS-WORKSPACE (all workspaces owned by the user)
1077
+ // ============================================================================
1078
+ /**
1079
+ * Get invoices overview across all workspaces
1080
+ */
1081
+ async getCrossWorkspaceInvoices(perPage, page) {
1082
+ const params = {};
1083
+ if (perPage)
1084
+ params.per_page = perPage;
1085
+ if (page)
1086
+ params.page = page;
1087
+ const response = await this.get("client-flow/all-workspaces/invoices", params);
1088
+ return response;
1089
+ }
1090
+ /**
1091
+ * Get proposals overview across all workspaces
1092
+ */
1093
+ async getCrossWorkspaceProposals(perPage, page) {
1094
+ const params = {};
1095
+ if (perPage)
1096
+ params.per_page = perPage;
1097
+ if (page)
1098
+ params.page = page;
1099
+ const response = await this.get("client-flow/all-workspaces/proposals", params);
1100
+ return response;
1101
+ }
1102
+ /**
1103
+ * Get clients overview across all workspaces
1104
+ */
1105
+ async getCrossWorkspaceClients(perPage, page) {
1106
+ const params = {};
1107
+ if (perPage)
1108
+ params.per_page = perPage;
1109
+ if (page)
1110
+ params.page = page;
1111
+ const response = await this.get("client-flow/all-workspaces/clients", params);
1112
+ return response;
1113
+ }
1114
+ /**
1115
+ * Get change requests overview across all workspaces
1116
+ */
1117
+ async getCrossWorkspaceChangeRequests(perPage, page) {
1118
+ const params = {};
1119
+ if (perPage)
1120
+ params.per_page = perPage;
1121
+ if (page)
1122
+ params.page = page;
1123
+ const response = await this.get("client-flow/all-workspaces/change-requests", params);
1124
+ return response;
1125
+ }
1126
+ // ============================================
1127
+ // LABEL MANAGEMENT
1128
+ // ============================================
1129
+ /**
1130
+ * Get all labels in a workspace
1131
+ */
1132
+ async getWorkspaceLabels(companySlug) {
1133
+ const response = await this.get("projects-labels", {
1134
+ company_slug: companySlug,
1135
+ });
1136
+ return response.data;
1137
+ }
1138
+ /**
1139
+ * Create a new label in the workspace
1140
+ */
1141
+ async createLabel(companySlug, data) {
1142
+ const response = await this.post(`projects-labels?company_slug=${companySlug}`, data);
1143
+ return response.data;
1144
+ }
1145
+ /**
1146
+ * Update a label
1147
+ */
1148
+ async updateLabel(labelSlug, companySlug, data) {
1149
+ await this.put(`projects-labels/${labelSlug}?company_slug=${companySlug}`, data);
1150
+ }
1151
+ /**
1152
+ * Attach a label to a project
1153
+ */
1154
+ async attachLabelToProject(labelSlug, projectSlug, companySlug) {
1155
+ await this.post(`projects-labels/${labelSlug}/attach?company_slug=${companySlug}&project_slug=${projectSlug}`, {
1156
+ slug: labelSlug,
1157
+ });
1158
+ }
1159
+ /**
1160
+ * Detach a label from a project
1161
+ */
1162
+ async detachLabelFromProject(labelSlug, projectSlug, companySlug) {
1163
+ await this.delete(`projects-labels/${labelSlug}/detach?company_slug=${companySlug}&project_slug=${projectSlug}`);
1164
+ }
1165
+ /**
1166
+ * Toggle a label on a task
1167
+ */
1168
+ async toggleLabelOnTask(taskUuid, labelSlug, projectSlug, companySlug) {
1169
+ const response = await this.post(`task-labels/${labelSlug}/toggle?company_slug=${companySlug}&project_slug=${projectSlug}&task_uuid=${taskUuid}`, {});
1170
+ return response;
1171
+ }
1172
+ // ============================================
1173
+ // TASK TYPE MANAGEMENT
1174
+ // ============================================
1175
+ /**
1176
+ * Create a new task type
1177
+ */
1178
+ async createTaskType(projectSlug, companySlug, data) {
1179
+ const response = await this.post(`project-templates/type?company_slug=${companySlug}&project_slug=${projectSlug}`, {
1180
+ ...data,
1181
+ type: "issues",
1182
+ });
1183
+ return response;
1184
+ }
1185
+ /**
1186
+ * Update a task type
1187
+ */
1188
+ async updateTaskType(typeId, projectSlug, companySlug, data) {
1189
+ await this.put(`project-templates/type/${typeId}?company_slug=${companySlug}&project_slug=${projectSlug}`, data);
1190
+ }
1191
+ /**
1192
+ * Assign a type to a task
1193
+ */
1194
+ async assignTypeToTask(taskUuid, typeId, projectSlug, companySlug) {
1195
+ const response = await this.put(`tasks/${taskUuid}?company_slug=${companySlug}&project_slug=${projectSlug}`, {
1196
+ config_issue_type_id: typeId,
1197
+ });
1198
+ return response.data;
1199
+ }
1200
+ // ============================================================================
1201
+ // STANDUP / DAILY
1202
+ // ============================================================================
1203
+ /**
1204
+ * Get team standup summary - completed yesterday, in progress, blocked, time tracked
1205
+ */
1206
+ async getStandupSummary(companySlug, projectSlug) {
1207
+ const params = { company_slug: companySlug };
1208
+ if (projectSlug)
1209
+ params.project_slug = projectSlug;
1210
+ const response = await this.get("companies/standup/summary", params);
1211
+ return response.data;
1212
+ }
1213
+ /**
1214
+ * Get tasks completed on a specific date (yesterday by default)
1215
+ */
1216
+ async getStandupCompletedYesterday(companySlug, projectSlug, date) {
1217
+ const params = { company_slug: companySlug };
1218
+ if (projectSlug)
1219
+ params.project_slug = projectSlug;
1220
+ if (date)
1221
+ params.date = date;
1222
+ const response = await this.get("companies/standup/completed-yesterday", params);
1223
+ return response.data;
1224
+ }
1225
+ /**
1226
+ * Get active blockers - tasks that are currently blocked
1227
+ */
1228
+ async getStandupBlockers(companySlug, projectSlug) {
1229
+ const params = { company_slug: companySlug };
1230
+ if (projectSlug)
1231
+ params.project_slug = projectSlug;
1232
+ const response = await this.get("companies/standup/blockers", params);
1233
+ return response.data;
1234
+ }
1235
+ /**
1236
+ * Get team status - current status of each team member with their active tasks
1237
+ */
1238
+ async getStandupTeamStatus(companySlug, projectSlug) {
1239
+ const params = { company_slug: companySlug };
1240
+ if (projectSlug)
1241
+ params.project_slug = projectSlug;
1242
+ const response = await this.get("companies/standup/team-status", params);
1243
+ return response.data;
1244
+ }
1245
+ /**
1246
+ * Get stuck tasks - tasks in progress for longer than expected
1247
+ */
1248
+ async getStandupStuckTasks(companySlug, projectSlug) {
1249
+ const params = { company_slug: companySlug };
1250
+ if (projectSlug)
1251
+ params.project_slug = projectSlug;
1252
+ const response = await this.get("companies/standup/stuck-tasks", params);
1253
+ return response.data;
1254
+ }
1255
+ /**
1256
+ * Get weekly digest - summary of the week's activity
1257
+ */
1258
+ async getStandupWeeklyDigest(companySlug, projectSlug) {
1259
+ const params = { company_slug: companySlug };
1260
+ if (projectSlug)
1261
+ params.project_slug = projectSlug;
1262
+ const response = await this.get("companies/standup/weekly-digest", params);
1263
+ return response.data;
1264
+ }
1265
+ /**
1266
+ * Get contributors stats - team member contributions over time
1267
+ */
1268
+ async getStandupContributors(companySlug, projectSlug, period) {
1269
+ const params = { company_slug: companySlug };
1270
+ if (projectSlug)
1271
+ params.project_slug = projectSlug;
1272
+ if (period)
1273
+ params.period = period;
1274
+ const response = await this.get("companies/standup/contributors", params);
1275
+ return response.data;
1276
+ }
1277
+ // ============================================================================
1278
+ // COMMENTS
1279
+ // ============================================================================
1280
+ /**
1281
+ * Get comments for a task
1282
+ */
1283
+ async getTaskComments(taskUuid, companySlug, projectSlug) {
1284
+ const response = await this.get("comments", {
1285
+ commentable_id: taskUuid,
1286
+ commentable_type: "issues",
1287
+ company_slug: companySlug,
1288
+ project_slug: projectSlug,
1289
+ });
1290
+ return response.data;
1291
+ }
1292
+ /**
1293
+ * Add a comment to a task
1294
+ */
1295
+ async addTaskComment(taskUuid, text, companySlug, projectSlug) {
1296
+ const response = await this.post(`comments?company_slug=${companySlug}&project_slug=${projectSlug}`, {
1297
+ commentable_id: taskUuid,
1298
+ commentable_type: "issues",
1299
+ comment_text: text,
1300
+ });
1301
+ return response.data;
1302
+ }
1303
+ /**
1304
+ * Update a comment
1305
+ */
1306
+ async updateComment(commentId, text) {
1307
+ await this.put(`comments/${commentId}`, { comment_text: text });
1308
+ }
1309
+ // ============================================================================
1310
+ // ANALYTICS / MANAGER DASHBOARD
1311
+ // ============================================================================
1312
+ /**
1313
+ * Get manager pulse - real-time workspace health metrics
1314
+ */
1315
+ async getManagerPulse(companySlug, view, period) {
1316
+ const params = { company_slug: companySlug };
1317
+ if (view)
1318
+ params.view = view;
1319
+ if (period)
1320
+ params.period = period;
1321
+ const response = await this.get("companies/manager-dashboard/pulse", params);
1322
+ return response.data;
1323
+ }
1324
+ /**
1325
+ * Get manager risks - risk detection and analysis
1326
+ */
1327
+ async getManagerRisks(companySlug, filter, severity) {
1328
+ const params = { company_slug: companySlug };
1329
+ if (filter)
1330
+ params.filter = filter;
1331
+ if (severity)
1332
+ params.severity = severity;
1333
+ const response = await this.get("companies/manager-dashboard/risks", params);
1334
+ return response.data;
1335
+ }
1336
+ /**
1337
+ * Get cumulative flow report - daily snapshot of tasks by status
1338
+ */
1339
+ async getReportsCumulativeFlow(companySlug, days) {
1340
+ const params = { company_slug: companySlug };
1341
+ if (days)
1342
+ params.days = days;
1343
+ const response = await this.get("companies/reports/cumulative-flow", params);
1344
+ return response.data;
1345
+ }
1346
+ /**
1347
+ * Get project age report - project age vs completion percentage
1348
+ */
1349
+ async getReportsProjectAge(companySlug) {
1350
+ const response = await this.get("companies/reports/project-age", {
1351
+ company_slug: companySlug,
1352
+ });
1353
+ return response.data;
1354
+ }
1355
+ /**
1356
+ * Get weekly activity report - activity by project over last 5 weeks
1357
+ */
1358
+ async getReportsWeeklyActivity(companySlug) {
1359
+ const response = await this.get("companies/reports/weekly-activity", {
1360
+ company_slug: companySlug,
1361
+ });
1362
+ return response.data;
1363
+ }
1364
+ // ============================================================================
1365
+ // USER STORIES - CROSS-WORKSPACE
1366
+ // ============================================================================
1367
+ /**
1368
+ * Get all user stories across all workspaces
1369
+ */
1370
+ async getAllWorkspacesUserStories(perPage, page) {
1371
+ const params = {};
1372
+ if (perPage)
1373
+ params.per_page = perPage;
1374
+ if (page)
1375
+ params.page = page;
1376
+ const response = await this.get("user-stories/all-workspaces", params);
1377
+ return response;
1378
+ }
1379
+ // ============================================================================
1380
+ // SPRINT - STATS / REPORTS / PROGRESS / METRICS
1381
+ // ============================================================================
1382
+ /**
1383
+ * Get sprint statistics
1384
+ */
1385
+ async getSprintStats(slug, projectSlug, companySlug) {
1386
+ const response = await this.get(`sprints/${slug}/stats`, {
1387
+ project_slug: projectSlug,
1388
+ company_slug: companySlug,
1389
+ });
1390
+ return response.data;
1391
+ }
1392
+ /**
1393
+ * Get sprint reports (burndown, burnup, performance, etc.)
1394
+ */
1395
+ async getSprintReports(slug, projectSlug, companySlug, options) {
1396
+ const params = {
1397
+ project_slug: projectSlug,
1398
+ company_slug: companySlug,
1399
+ };
1400
+ if (options?.resource)
1401
+ params.resource = options.resource;
1402
+ if (options?.report_task)
1403
+ params.report_task = options.report_task;
1404
+ const response = await this.get(`sprints/${slug}/reports`, params);
1405
+ return response.data;
1406
+ }
1407
+ /**
1408
+ * Get sprint progress
1409
+ */
1410
+ async getSprintProgress(slug, projectSlug, companySlug) {
1411
+ const response = await this.get(`sprints/${slug}/progress`, {
1412
+ project_slug: projectSlug,
1413
+ company_slug: companySlug,
1414
+ });
1415
+ return response.data;
1416
+ }
1417
+ /**
1418
+ * Get sprint metrics
1419
+ */
1420
+ async getSprintMetrics(slug, projectSlug, companySlug) {
1421
+ const response = await this.get(`sprints/${slug}/metrics`, {
1422
+ project_slug: projectSlug,
1423
+ company_slug: companySlug,
1424
+ });
1425
+ return response.data;
1426
+ }
1427
+ // ============================================================================
1428
+ // TASK - BY CODE / DUPLICATE / MOVE
1429
+ // ============================================================================
1430
+ /**
1431
+ * Get task by code (e.g., PROJ-123)
1432
+ */
1433
+ async getTaskByCode(taskCode, projectSlug, companySlug) {
1434
+ const response = await this.get(`tasks/by-code/${taskCode}`, {
1435
+ project_slug: projectSlug,
1436
+ company_slug: companySlug,
1437
+ });
1438
+ return response.data;
1439
+ }
1440
+ /**
1441
+ * Duplicate a task
1442
+ */
1443
+ async duplicateTask(taskUuid, projectSlug, companySlug, workflowId) {
1444
+ const body = {};
1445
+ if (workflowId)
1446
+ body.config_workflow_id = workflowId;
1447
+ const response = await this.post(`tasks/${taskUuid}/duplicate?company_slug=${companySlug}&project_slug=${projectSlug}`, body);
1448
+ return response.data;
1449
+ }
1450
+ /**
1451
+ * Move a task to another project
1452
+ */
1453
+ async moveTask(taskUuid, projectSlug, companySlug, newProjectSlug, newWorkflowId) {
1454
+ const response = await this.post(`tasks/${taskUuid}/move?company_slug=${companySlug}&project_slug=${projectSlug}`, { new_project_slug: newProjectSlug, new_workflow_id: newWorkflowId });
1455
+ return response;
1456
+ }
1457
+ // ============================================================================
1458
+ // WIKI - SEARCH
1459
+ // ============================================================================
1460
+ /**
1461
+ * Search wiki pages
1462
+ */
1463
+ async searchWikiPages(projectSlug, companySlug, query, limit) {
1464
+ const params = {
1465
+ project_slug: projectSlug,
1466
+ company_slug: companySlug,
1467
+ q: query,
1468
+ };
1469
+ if (limit)
1470
+ params.limit = limit;
1471
+ const response = await this.get("wiki/pages/search", params);
1472
+ return response.data;
1473
+ }
1474
+ // ============================================================================
1475
+ // TIME TRACKING - ANALYTICS
1476
+ // ============================================================================
1477
+ /**
1478
+ * Get time tracking analytics
1479
+ */
1480
+ async getTimeTrackingAnalytics(companySlug, options) {
1481
+ const params = { company_slug: companySlug };
1482
+ if (options?.project_slug)
1483
+ params.project_slug = options.project_slug;
1484
+ if (options?.period)
1485
+ params.period = options.period;
1486
+ if (options?.start)
1487
+ params.start = options.start;
1488
+ if (options?.end)
1489
+ params.end = options.end;
1490
+ if (options?.users)
1491
+ params.users = options.users;
1492
+ const response = await this.get("time-trackings/analytics", params);
1493
+ return response.data;
1494
+ }
1495
+ /**
1496
+ * Get time tracking team stats
1497
+ */
1498
+ async getTimeTrackingTeam(companySlug, options) {
1499
+ const params = { company_slug: companySlug };
1500
+ if (options?.project_slug)
1501
+ params.project_slug = options.project_slug;
1502
+ if (options?.period)
1503
+ params.period = options.period;
1504
+ const response = await this.get("time-trackings/team", params);
1505
+ return response.data;
1506
+ }
1507
+ /**
1508
+ * Get time tracking reports
1509
+ */
1510
+ async getTimeTrackingReports(companySlug, options) {
1511
+ const params = { company_slug: companySlug };
1512
+ if (options?.project_slug)
1513
+ params.project_slug = options.project_slug;
1514
+ if (options?.period)
1515
+ params.period = options.period;
1516
+ if (options?.report_type)
1517
+ params.report_type = options.report_type;
1518
+ if (options?.hourly_rate)
1519
+ params.hourly_rate = options.hourly_rate;
1520
+ const response = await this.get("time-trackings/reports", params);
1521
+ return response.data;
1522
+ }
1523
+ /**
1524
+ * Get time tracking productivity
1525
+ */
1526
+ async getTimeTrackingProductivity(companySlug, options) {
1527
+ const params = { company_slug: companySlug };
1528
+ if (options?.project_slug)
1529
+ params.project_slug = options.project_slug;
1530
+ if (options?.period)
1531
+ params.period = options.period;
1532
+ const response = await this.get("time-trackings/productivity", params);
1533
+ return response.data;
1534
+ }
1535
+ /**
1536
+ * Get time tracking timeline
1537
+ */
1538
+ async getTimeTrackingTimeline(companySlug, options) {
1539
+ const params = { company_slug: companySlug };
1540
+ if (options?.project_slug)
1541
+ params.project_slug = options.project_slug;
1542
+ if (options?.period)
1543
+ params.period = options.period;
1544
+ const response = await this.get("time-trackings/timeline", params);
1545
+ return response.data;
1546
+ }
1547
+ // ============================================================================
1548
+ // MANAGER DASHBOARD - ADDITIONAL REPORTS
1549
+ // ============================================================================
1550
+ /**
1551
+ * Get manager dashboard overview
1552
+ */
1553
+ async getManagerOverview(companySlug) {
1554
+ const response = await this.get("companies/manager-dashboard/overview", {
1555
+ company_slug: companySlug,
1556
+ });
1557
+ return response.data;
1558
+ }
1559
+ /**
1560
+ * Get manager dashboard health
1561
+ */
1562
+ async getManagerHealth(companySlug) {
1563
+ const response = await this.get("companies/manager-dashboard/health", {
1564
+ company_slug: companySlug,
1565
+ });
1566
+ return response.data;
1567
+ }
1568
+ /**
1569
+ * Get manager dashboard blockers
1570
+ */
1571
+ async getManagerBlockers(companySlug) {
1572
+ const response = await this.get("companies/manager-dashboard/blockers", {
1573
+ company_slug: companySlug,
1574
+ });
1575
+ return response.data;
1576
+ }
1577
+ /**
1578
+ * Get manager command center
1579
+ */
1580
+ async getManagerCommandCenter(companySlug) {
1581
+ const response = await this.get("companies/manager-dashboard/command-center", {
1582
+ company_slug: companySlug,
1583
+ });
1584
+ return response.data;
1585
+ }
1586
+ /**
1587
+ * Get manager dashboard time entries
1588
+ */
1589
+ async getManagerTimeEntries(companySlug, filter) {
1590
+ const params = { company_slug: companySlug };
1591
+ if (filter)
1592
+ params.filter = filter;
1593
+ const response = await this.get("companies/manager-dashboard/time-entries", params);
1594
+ return response.data;
1595
+ }
1596
+ // ============================================================================
1597
+ // DISCUSSIONS
1598
+ // ============================================================================
1599
+ /**
1600
+ * Get all discussions across all workspaces
1601
+ */
1602
+ async getAllDiscussions() {
1603
+ const response = await this.get("discussions/all");
1604
+ return response.data;
1605
+ }
1606
+ /**
1607
+ * Get global unread count across all workspaces
1608
+ */
1609
+ async getDiscussionGlobalUnreadCount() {
1610
+ const response = await this.get("discussions/global-unread-count");
1611
+ return response.data;
1612
+ }
1613
+ /**
1614
+ * Get channels in a project
1615
+ */
1616
+ async getDiscussionChannels(projectSlug, companySlug, includeArchived) {
1617
+ const params = {
1618
+ project_slug: projectSlug,
1619
+ company_slug: companySlug,
1620
+ };
1621
+ if (includeArchived)
1622
+ params.include_archived = includeArchived;
1623
+ const response = await this.get("discussions/channels", params);
1624
+ return response.data;
1625
+ }
1626
+ /**
1627
+ * Get a single channel
1628
+ */
1629
+ async getDiscussionChannel(uuid) {
1630
+ const response = await this.get(`discussions/channels/${uuid}`);
1631
+ return response.data;
1632
+ }
1633
+ /**
1634
+ * Create a discussion channel
1635
+ */
1636
+ async createDiscussionChannel(data) {
1637
+ const response = await this.post("discussions/channels", data);
1638
+ return response.data;
1639
+ }
1640
+ /**
1641
+ * Update a discussion channel
1642
+ */
1643
+ async updateDiscussionChannel(uuid, data) {
1644
+ const response = await this.put(`discussions/channels/${uuid}`, data);
1645
+ return response.data;
1646
+ }
1647
+ /**
1648
+ * Get messages in a channel (cursor-based pagination)
1649
+ */
1650
+ async getDiscussionMessages(channelUuid, options) {
1651
+ const params = {};
1652
+ if (options?.before_id)
1653
+ params.before_id = options.before_id;
1654
+ if (options?.after_id)
1655
+ params.after_id = options.after_id;
1656
+ if (options?.limit)
1657
+ params.limit = options.limit;
1658
+ const response = await this.get(`discussions/channels/${channelUuid}/messages`, params);
1659
+ return response;
1660
+ }
1661
+ /**
1662
+ * Send a message in a channel
1663
+ */
1664
+ async sendDiscussionMessage(channelUuid, data) {
1665
+ const response = await this.post(`discussions/channels/${channelUuid}/messages`, data);
1666
+ return response.data;
1667
+ }
1668
+ /**
1669
+ * Search messages in a channel
1670
+ */
1671
+ async searchDiscussionMessages(channelUuid, query, limit) {
1672
+ const params = { q: query };
1673
+ if (limit)
1674
+ params.limit = limit;
1675
+ const response = await this.get(`discussions/channels/${channelUuid}/search`, params);
1676
+ return response.data;
1677
+ }
1678
+ /**
1679
+ * Get unread count for a project
1680
+ */
1681
+ async getDiscussionUnreadCount(projectSlug, companySlug) {
1682
+ const response = await this.get("discussions/unread-count", {
1683
+ project_slug: projectSlug,
1684
+ company_slug: companySlug,
1685
+ });
1686
+ return response.data;
1687
+ }
1688
+ /**
1689
+ * Mark a channel as read
1690
+ */
1691
+ async markDiscussionChannelRead(channelUuid) {
1692
+ const response = await this.post(`discussions/channels/${channelUuid}/read`, {});
1693
+ return response;
1694
+ }
1695
+ // ============================================================================
1696
+ // ACTIVITY FEED
1697
+ // ============================================================================
1698
+ /**
1699
+ * Get user's activity feed
1700
+ */
1701
+ async getActivityFeed() {
1702
+ const response = await this.get("feeds");
1703
+ return response;
1704
+ }
1705
+ /**
1706
+ * Get activity feed for a specific user
1707
+ */
1708
+ async getActivityFeedByUser(username) {
1709
+ const response = await this.get(`feeds/user/${username}`);
1710
+ return response;
1711
+ }
1712
+ /**
1713
+ * Get notification feed
1714
+ */
1715
+ async getNotificationFeed() {
1716
+ const response = await this.get("feeds/notifications");
1717
+ return response;
1718
+ }
1719
+ /**
1720
+ * Get activities by context (company, project, sprint, etc.)
1721
+ */
1722
+ async getActivities(options) {
1723
+ const params = {};
1724
+ if (options.from_context)
1725
+ params.from_context = options.from_context;
1726
+ if (options.company_slug)
1727
+ params.company_slug = options.company_slug;
1728
+ if (options.project_slug)
1729
+ params.project_slug = options.project_slug;
1730
+ if (options.sprint_slug)
1731
+ params.sprint_slug = options.sprint_slug;
1732
+ if (options.uuid)
1733
+ params.uuid = options.uuid;
1734
+ const response = await this.get("activities", params);
1735
+ return response.data;
1736
+ }
1737
+ /**
1738
+ * Get workflow history for a task
1739
+ */
1740
+ async getTaskWorkflowHistory(taskUuid) {
1741
+ const response = await this.get(`activities/task/${taskUuid}/workflow`);
1742
+ return response.data;
1743
+ }
1744
+ // ============================================================================
1745
+ // BUDGET
1746
+ // ============================================================================
1747
+ /**
1748
+ * Get projects at budget risk
1749
+ */
1750
+ async getBudgetProjectsAtRisk(companySlug) {
1751
+ const response = await this.get("budget/projects-at-risk", {
1752
+ company_slug: companySlug,
1753
+ });
1754
+ return response.data;
1755
+ }
1756
+ /**
1757
+ * Get project budget overview
1758
+ */
1759
+ async getBudgetOverview(projectUuid, options) {
1760
+ const params = {};
1761
+ if (options?.start_date)
1762
+ params.start_date = options.start_date;
1763
+ if (options?.end_date)
1764
+ params.end_date = options.end_date;
1765
+ if (options?.user_ids)
1766
+ params.user_ids = options.user_ids;
1767
+ if (options?.status)
1768
+ params.status = options.status;
1769
+ const response = await this.get(`projects/${projectUuid}/budget/overview`, params);
1770
+ return response.data;
1771
+ }
1772
+ /**
1773
+ * Get project budget consumption
1774
+ */
1775
+ async getBudgetConsumption(projectUuid) {
1776
+ const response = await this.get(`projects/${projectUuid}/budget/consumption`);
1777
+ return response.data;
1778
+ }
1779
+ /**
1780
+ * Get project budget burn-down
1781
+ */
1782
+ async getBudgetBurnDown(projectUuid, options) {
1783
+ const params = {};
1784
+ if (options?.start_date)
1785
+ params.start_date = options.start_date;
1786
+ if (options?.end_date)
1787
+ params.end_date = options.end_date;
1788
+ const response = await this.get(`projects/${projectUuid}/budget/burn-down`, params);
1789
+ return response.data;
1790
+ }
1791
+ /**
1792
+ * Get budget alerts for a project
1793
+ */
1794
+ async getBudgetAlerts(projectUuid) {
1795
+ const response = await this.get(`projects/${projectUuid}/budget/alerts`);
1796
+ return response.data;
1797
+ }
1798
+ /**
1799
+ * Get budget events for a project
1800
+ */
1801
+ async getBudgetEvents(projectUuid, limit) {
1802
+ const params = {};
1803
+ if (limit)
1804
+ params.limit = limit;
1805
+ const response = await this.get(`projects/${projectUuid}/budget/events`, params);
1806
+ return response.data;
1807
+ }
1808
+ // ============================================================================
1809
+ // EPICS
1810
+ // ============================================================================
1811
+ /**
1812
+ * Get all epics in a project
1813
+ */
1814
+ async getEpics(projectSlug, companySlug) {
1815
+ const response = await this.get("user-story-epics", {
1816
+ project_slug: projectSlug,
1817
+ company_slug: companySlug,
1818
+ });
1819
+ return response.data;
1820
+ }
1821
+ /**
1822
+ * Create a new epic
1823
+ */
1824
+ async createEpic(projectSlug, companySlug, data) {
1825
+ const response = await this.post(`user-story-epics?company_slug=${companySlug}&project_slug=${projectSlug}`, data);
1826
+ return response;
1827
+ }
1828
+ /**
1829
+ * Update an epic
1830
+ */
1831
+ async updateEpic(epicUuid, projectSlug, companySlug, data) {
1832
+ await this.put(`user-story-epics/${epicUuid}?company_slug=${companySlug}&project_slug=${projectSlug}`, data);
1833
+ }
1834
+ }
1835
+ //# sourceMappingURL=GitScrumClient.js.map