@vibescope/mcp-server 0.2.0 → 0.2.2

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 (104) hide show
  1. package/README.md +60 -7
  2. package/dist/api-client.d.ts +251 -1
  3. package/dist/api-client.js +82 -3
  4. package/dist/handlers/blockers.js +9 -8
  5. package/dist/handlers/bodies-of-work.js +96 -63
  6. package/dist/handlers/connectors.d.ts +45 -0
  7. package/dist/handlers/connectors.js +183 -0
  8. package/dist/handlers/cost.d.ts +10 -0
  9. package/dist/handlers/cost.js +112 -50
  10. package/dist/handlers/decisions.js +32 -19
  11. package/dist/handlers/deployment.js +144 -122
  12. package/dist/handlers/discovery.d.ts +7 -0
  13. package/dist/handlers/discovery.js +96 -7
  14. package/dist/handlers/fallback.js +29 -23
  15. package/dist/handlers/file-checkouts.d.ts +20 -0
  16. package/dist/handlers/file-checkouts.js +133 -0
  17. package/dist/handlers/findings.d.ts +6 -0
  18. package/dist/handlers/findings.js +96 -40
  19. package/dist/handlers/git-issues.js +40 -36
  20. package/dist/handlers/ideas.js +49 -31
  21. package/dist/handlers/index.d.ts +3 -0
  22. package/dist/handlers/index.js +9 -0
  23. package/dist/handlers/milestones.js +39 -32
  24. package/dist/handlers/organizations.js +99 -91
  25. package/dist/handlers/progress.js +24 -13
  26. package/dist/handlers/project.js +68 -28
  27. package/dist/handlers/requests.js +18 -14
  28. package/dist/handlers/roles.d.ts +18 -0
  29. package/dist/handlers/roles.js +130 -0
  30. package/dist/handlers/session.js +58 -17
  31. package/dist/handlers/sprints.js +93 -81
  32. package/dist/handlers/tasks.d.ts +2 -0
  33. package/dist/handlers/tasks.js +189 -91
  34. package/dist/handlers/types.d.ts +64 -2
  35. package/dist/handlers/types.js +48 -1
  36. package/dist/handlers/validation.js +21 -17
  37. package/dist/index.js +7 -2716
  38. package/dist/token-tracking.d.ts +74 -0
  39. package/dist/token-tracking.js +122 -0
  40. package/dist/tools.js +685 -9
  41. package/dist/utils.d.ts +5 -0
  42. package/dist/utils.js +17 -0
  43. package/docs/TOOLS.md +2053 -0
  44. package/package.json +4 -1
  45. package/scripts/generate-docs.ts +212 -0
  46. package/src/api-client.test.ts +718 -0
  47. package/src/api-client.ts +320 -6
  48. package/src/handlers/__test-setup__.ts +16 -0
  49. package/src/handlers/blockers.test.ts +31 -19
  50. package/src/handlers/blockers.ts +9 -8
  51. package/src/handlers/bodies-of-work.test.ts +55 -32
  52. package/src/handlers/bodies-of-work.ts +115 -115
  53. package/src/handlers/connectors.test.ts +834 -0
  54. package/src/handlers/connectors.ts +229 -0
  55. package/src/handlers/cost.test.ts +34 -44
  56. package/src/handlers/cost.ts +136 -85
  57. package/src/handlers/decisions.test.ts +37 -27
  58. package/src/handlers/decisions.ts +35 -30
  59. package/src/handlers/deployment.ts +180 -208
  60. package/src/handlers/discovery.test.ts +4 -5
  61. package/src/handlers/discovery.ts +98 -8
  62. package/src/handlers/fallback.test.ts +26 -22
  63. package/src/handlers/fallback.ts +36 -33
  64. package/src/handlers/file-checkouts.test.ts +670 -0
  65. package/src/handlers/file-checkouts.ts +165 -0
  66. package/src/handlers/findings.test.ts +178 -19
  67. package/src/handlers/findings.ts +112 -74
  68. package/src/handlers/git-issues.test.ts +51 -43
  69. package/src/handlers/git-issues.ts +44 -84
  70. package/src/handlers/ideas.test.ts +28 -23
  71. package/src/handlers/ideas.ts +61 -59
  72. package/src/handlers/index.ts +9 -0
  73. package/src/handlers/milestones.test.ts +33 -28
  74. package/src/handlers/milestones.ts +52 -50
  75. package/src/handlers/organizations.test.ts +104 -83
  76. package/src/handlers/organizations.ts +117 -142
  77. package/src/handlers/progress.test.ts +20 -14
  78. package/src/handlers/progress.ts +26 -24
  79. package/src/handlers/project.test.ts +34 -27
  80. package/src/handlers/project.ts +95 -63
  81. package/src/handlers/requests.test.ts +27 -18
  82. package/src/handlers/requests.ts +21 -17
  83. package/src/handlers/roles.test.ts +303 -0
  84. package/src/handlers/roles.ts +208 -0
  85. package/src/handlers/session.test.ts +47 -0
  86. package/src/handlers/session.ts +71 -26
  87. package/src/handlers/sprints.test.ts +71 -50
  88. package/src/handlers/sprints.ts +113 -146
  89. package/src/handlers/tasks.test.ts +77 -15
  90. package/src/handlers/tasks.ts +231 -156
  91. package/src/handlers/tool-categories.test.ts +66 -0
  92. package/src/handlers/types.ts +81 -2
  93. package/src/handlers/validation.test.ts +78 -45
  94. package/src/handlers/validation.ts +23 -25
  95. package/src/index.ts +12 -2732
  96. package/src/token-tracking.test.ts +453 -0
  97. package/src/token-tracking.ts +164 -0
  98. package/src/tools.ts +685 -9
  99. package/src/utils.test.ts +2 -2
  100. package/src/utils.ts +17 -0
  101. package/dist/config/tool-categories.d.ts +0 -31
  102. package/dist/config/tool-categories.js +0 -253
  103. package/dist/knowledge.d.ts +0 -6
  104. package/dist/knowledge.js +0 -218
@@ -17,13 +17,78 @@
17
17
  *
18
18
  * MIGRATED: Uses Vibescope API client instead of direct Supabase
19
19
  */
20
- import { validateRequired, validateUUID } from '../validators.js';
20
+ import { parseArgs, uuidValidator, createEnumValidator } from '../validators.js';
21
21
  import { getApiClient } from '../api-client.js';
22
+ const BODY_OF_WORK_STATUSES = ['draft', 'active', 'completed', 'cancelled'];
23
+ const TASK_PHASES = ['pre', 'core', 'post'];
24
+ const DEPLOY_ENVIRONMENTS = ['development', 'staging', 'production'];
25
+ const VERSION_BUMPS = ['patch', 'minor', 'major'];
26
+ const DEPLOY_TRIGGERS = ['all_completed', 'all_completed_validated'];
27
+ // ============================================================================
28
+ // Argument Schemas
29
+ // ============================================================================
30
+ const createBodyOfWorkSchema = {
31
+ project_id: { type: 'string', required: true, validate: uuidValidator },
32
+ title: { type: 'string', required: true },
33
+ description: { type: 'string' },
34
+ auto_deploy_on_completion: { type: 'boolean' },
35
+ deploy_environment: { type: 'string', validate: createEnumValidator(DEPLOY_ENVIRONMENTS) },
36
+ deploy_version_bump: { type: 'string', validate: createEnumValidator(VERSION_BUMPS) },
37
+ deploy_trigger: { type: 'string', validate: createEnumValidator(DEPLOY_TRIGGERS) },
38
+ };
39
+ const updateBodyOfWorkSchema = {
40
+ body_of_work_id: { type: 'string', required: true, validate: uuidValidator },
41
+ title: { type: 'string' },
42
+ description: { type: 'string' },
43
+ auto_deploy_on_completion: { type: 'boolean' },
44
+ deploy_environment: { type: 'string', validate: createEnumValidator(DEPLOY_ENVIRONMENTS) },
45
+ deploy_version_bump: { type: 'string', validate: createEnumValidator(VERSION_BUMPS) },
46
+ deploy_trigger: { type: 'string', validate: createEnumValidator(DEPLOY_TRIGGERS) },
47
+ };
48
+ const getBodyOfWorkSchema = {
49
+ body_of_work_id: { type: 'string', required: true, validate: uuidValidator },
50
+ summary_only: { type: 'boolean', default: false },
51
+ };
52
+ const getBodiesOfWorkSchema = {
53
+ project_id: { type: 'string', required: true, validate: uuidValidator },
54
+ status: { type: 'string', validate: createEnumValidator(BODY_OF_WORK_STATUSES) },
55
+ limit: { type: 'number', default: 50 },
56
+ offset: { type: 'number', default: 0 },
57
+ search_query: { type: 'string' },
58
+ };
59
+ const deleteBodyOfWorkSchema = {
60
+ body_of_work_id: { type: 'string', required: true, validate: uuidValidator },
61
+ };
62
+ const addTaskToBodyOfWorkSchema = {
63
+ body_of_work_id: { type: 'string', required: true, validate: uuidValidator },
64
+ task_id: { type: 'string', required: true, validate: uuidValidator },
65
+ phase: { type: 'string', validate: createEnumValidator(TASK_PHASES) },
66
+ order_index: { type: 'number' },
67
+ };
68
+ const removeTaskFromBodyOfWorkSchema = {
69
+ task_id: { type: 'string', required: true, validate: uuidValidator },
70
+ };
71
+ const activateBodyOfWorkSchema = {
72
+ body_of_work_id: { type: 'string', required: true, validate: uuidValidator },
73
+ };
74
+ const addTaskDependencySchema = {
75
+ body_of_work_id: { type: 'string', required: true, validate: uuidValidator },
76
+ task_id: { type: 'string', required: true, validate: uuidValidator },
77
+ depends_on_task_id: { type: 'string', required: true, validate: uuidValidator },
78
+ };
79
+ const removeTaskDependencySchema = {
80
+ task_id: { type: 'string', required: true, validate: uuidValidator },
81
+ depends_on_task_id: { type: 'string', required: true, validate: uuidValidator },
82
+ };
83
+ const getTaskDependenciesSchema = {
84
+ body_of_work_id: { type: 'string', validate: uuidValidator },
85
+ task_id: { type: 'string', validate: uuidValidator },
86
+ };
87
+ const getNextBodyOfWorkTaskSchema = {
88
+ body_of_work_id: { type: 'string', required: true, validate: uuidValidator },
89
+ };
22
90
  export const createBodyOfWork = async (args, ctx) => {
23
- const { project_id, title, description, auto_deploy_on_completion, deploy_environment, deploy_version_bump, deploy_trigger, } = args;
24
- validateRequired(project_id, 'project_id');
25
- validateUUID(project_id, 'project_id');
26
- validateRequired(title, 'title');
91
+ const { project_id, title, description, auto_deploy_on_completion, deploy_environment, deploy_version_bump, deploy_trigger, } = parseArgs(args, createBodyOfWorkSchema);
27
92
  const { session } = ctx;
28
93
  const apiClient = getApiClient();
29
94
  const response = await apiClient.proxy('create_body_of_work', {
@@ -40,7 +105,7 @@ export const createBodyOfWork = async (args, ctx) => {
40
105
  instance_id: session.instanceId
41
106
  });
42
107
  if (!response.ok) {
43
- throw new Error(`Failed to create body of work: ${response.error}`);
108
+ return { result: { error: response.error || 'Failed to create body of work' }, isError: true };
44
109
  }
45
110
  return {
46
111
  result: {
@@ -53,9 +118,7 @@ export const createBodyOfWork = async (args, ctx) => {
53
118
  };
54
119
  };
55
120
  export const updateBodyOfWork = async (args, ctx) => {
56
- const { body_of_work_id, title, description, auto_deploy_on_completion, deploy_environment, deploy_version_bump, deploy_trigger, } = args;
57
- validateRequired(body_of_work_id, 'body_of_work_id');
58
- validateUUID(body_of_work_id, 'body_of_work_id');
121
+ const { body_of_work_id, title, description, auto_deploy_on_completion, deploy_environment, deploy_version_bump, deploy_trigger, } = parseArgs(args, updateBodyOfWorkSchema);
59
122
  // Check if any updates provided
60
123
  if (title === undefined && description === undefined && auto_deploy_on_completion === undefined &&
61
124
  deploy_environment === undefined && deploy_version_bump === undefined && deploy_trigger === undefined) {
@@ -72,58 +135,48 @@ export const updateBodyOfWork = async (args, ctx) => {
72
135
  deploy_trigger
73
136
  });
74
137
  if (!response.ok) {
75
- throw new Error(`Failed to update body of work: ${response.error}`);
138
+ return { result: { error: response.error || 'Failed to update body of work' }, isError: true };
76
139
  }
77
140
  return { result: { success: true, body_of_work_id } };
78
141
  };
79
142
  export const getBodyOfWork = async (args, ctx) => {
80
- const { body_of_work_id, summary_only = false } = args;
81
- validateRequired(body_of_work_id, 'body_of_work_id');
82
- validateUUID(body_of_work_id, 'body_of_work_id');
143
+ const { body_of_work_id, summary_only } = parseArgs(args, getBodyOfWorkSchema);
83
144
  const apiClient = getApiClient();
84
145
  // Response type varies based on summary_only
85
146
  const response = await apiClient.proxy('get_body_of_work', { body_of_work_id, summary_only });
86
147
  if (!response.ok) {
87
- throw new Error(`Failed to get body of work: ${response.error}`);
148
+ return { result: { error: response.error || 'Failed to get body of work' }, isError: true };
88
149
  }
89
150
  return { result: response.data };
90
151
  };
91
152
  export const getBodiesOfWork = async (args, ctx) => {
92
- const { project_id, status, limit = 50, offset = 0, search_query } = args;
93
- validateRequired(project_id, 'project_id');
94
- validateUUID(project_id, 'project_id');
153
+ const { project_id, status, limit, offset, search_query } = parseArgs(args, getBodiesOfWorkSchema);
95
154
  const apiClient = getApiClient();
96
155
  const response = await apiClient.proxy('get_bodies_of_work', {
97
156
  project_id,
98
157
  status,
99
- limit: Math.min(limit, 100),
158
+ limit: Math.min(limit ?? 50, 100),
100
159
  offset,
101
160
  search_query
102
161
  });
103
162
  if (!response.ok) {
104
- throw new Error(`Failed to fetch bodies of work: ${response.error}`);
163
+ return { result: { error: response.error || 'Failed to fetch bodies of work' }, isError: true };
105
164
  }
106
165
  return { result: response.data };
107
166
  };
108
167
  export const deleteBodyOfWork = async (args, ctx) => {
109
- const { body_of_work_id } = args;
110
- validateRequired(body_of_work_id, 'body_of_work_id');
111
- validateUUID(body_of_work_id, 'body_of_work_id');
168
+ const { body_of_work_id } = parseArgs(args, deleteBodyOfWorkSchema);
112
169
  const apiClient = getApiClient();
113
170
  const response = await apiClient.proxy('delete_body_of_work', {
114
171
  body_of_work_id
115
172
  });
116
173
  if (!response.ok) {
117
- throw new Error(`Failed to delete body of work: ${response.error}`);
174
+ return { result: { error: response.error || 'Failed to delete body of work' }, isError: true };
118
175
  }
119
176
  return { result: { success: true, message: 'Body of work deleted. Tasks are preserved.' } };
120
177
  };
121
178
  export const addTaskToBodyOfWork = async (args, ctx) => {
122
- const { body_of_work_id, task_id, phase, order_index } = args;
123
- validateRequired(body_of_work_id, 'body_of_work_id');
124
- validateUUID(body_of_work_id, 'body_of_work_id');
125
- validateRequired(task_id, 'task_id');
126
- validateUUID(task_id, 'task_id');
179
+ const { body_of_work_id, task_id, phase, order_index } = parseArgs(args, addTaskToBodyOfWorkSchema);
127
180
  const apiClient = getApiClient();
128
181
  const response = await apiClient.proxy('add_task_to_body_of_work', {
129
182
  body_of_work_id,
@@ -132,42 +185,32 @@ export const addTaskToBodyOfWork = async (args, ctx) => {
132
185
  order_index
133
186
  });
134
187
  if (!response.ok) {
135
- throw new Error(`Failed to add task to body of work: ${response.error}`);
188
+ return { result: { error: response.error || 'Failed to add task to body of work' }, isError: true };
136
189
  }
137
190
  return { result: response.data };
138
191
  };
139
192
  export const removeTaskFromBodyOfWork = async (args, ctx) => {
140
- const { task_id } = args;
141
- validateRequired(task_id, 'task_id');
142
- validateUUID(task_id, 'task_id');
193
+ const { task_id } = parseArgs(args, removeTaskFromBodyOfWorkSchema);
143
194
  const apiClient = getApiClient();
144
195
  const response = await apiClient.proxy('remove_task_from_body_of_work', { task_id });
145
196
  if (!response.ok) {
146
- throw new Error(`Failed to remove task from body of work: ${response.error}`);
197
+ return { result: { error: response.error || 'Failed to remove task from body of work' }, isError: true };
147
198
  }
148
199
  return { result: response.data };
149
200
  };
150
201
  export const activateBodyOfWork = async (args, ctx) => {
151
- const { body_of_work_id } = args;
152
- validateRequired(body_of_work_id, 'body_of_work_id');
153
- validateUUID(body_of_work_id, 'body_of_work_id');
202
+ const { body_of_work_id } = parseArgs(args, activateBodyOfWorkSchema);
154
203
  const apiClient = getApiClient();
155
204
  const response = await apiClient.proxy('activate_body_of_work', { body_of_work_id });
156
205
  if (!response.ok) {
157
- throw new Error(`Failed to activate body of work: ${response.error}`);
206
+ return { result: { error: response.error || 'Failed to activate body of work' }, isError: true };
158
207
  }
159
208
  return { result: response.data };
160
209
  };
161
210
  export const addTaskDependency = async (args, ctx) => {
162
- const { body_of_work_id, task_id, depends_on_task_id } = args;
163
- validateRequired(body_of_work_id, 'body_of_work_id');
164
- validateUUID(body_of_work_id, 'body_of_work_id');
165
- validateRequired(task_id, 'task_id');
166
- validateUUID(task_id, 'task_id');
167
- validateRequired(depends_on_task_id, 'depends_on_task_id');
168
- validateUUID(depends_on_task_id, 'depends_on_task_id');
211
+ const { body_of_work_id, task_id, depends_on_task_id } = parseArgs(args, addTaskDependencySchema);
169
212
  if (task_id === depends_on_task_id) {
170
- throw new Error('A task cannot depend on itself');
213
+ return { result: { error: 'A task cannot depend on itself' }, isError: true };
171
214
  }
172
215
  const apiClient = getApiClient();
173
216
  const response = await apiClient.proxy('add_task_dependency', {
@@ -176,53 +219,43 @@ export const addTaskDependency = async (args, ctx) => {
176
219
  depends_on_task_id
177
220
  });
178
221
  if (!response.ok) {
179
- throw new Error(`Failed to add task dependency: ${response.error}`);
222
+ return { result: { error: response.error || 'Failed to add task dependency' }, isError: true };
180
223
  }
181
224
  return { result: response.data };
182
225
  };
183
226
  export const removeTaskDependency = async (args, ctx) => {
184
- const { task_id, depends_on_task_id } = args;
185
- validateRequired(task_id, 'task_id');
186
- validateUUID(task_id, 'task_id');
187
- validateRequired(depends_on_task_id, 'depends_on_task_id');
188
- validateUUID(depends_on_task_id, 'depends_on_task_id');
227
+ const { task_id, depends_on_task_id } = parseArgs(args, removeTaskDependencySchema);
189
228
  const apiClient = getApiClient();
190
229
  const response = await apiClient.proxy('remove_task_dependency', {
191
230
  task_id,
192
231
  depends_on_task_id
193
232
  });
194
233
  if (!response.ok) {
195
- throw new Error(`Failed to remove task dependency: ${response.error}`);
234
+ return { result: { error: response.error || 'Failed to remove task dependency' }, isError: true };
196
235
  }
197
236
  return { result: response.data };
198
237
  };
199
238
  export const getTaskDependencies = async (args, ctx) => {
200
- const { body_of_work_id, task_id } = args;
239
+ const { body_of_work_id, task_id } = parseArgs(args, getTaskDependenciesSchema);
201
240
  if (!body_of_work_id && !task_id) {
202
- throw new Error('Either body_of_work_id or task_id is required');
241
+ return { result: { error: 'Either body_of_work_id or task_id is required' }, isError: true };
203
242
  }
204
- if (body_of_work_id)
205
- validateUUID(body_of_work_id, 'body_of_work_id');
206
- if (task_id)
207
- validateUUID(task_id, 'task_id');
208
243
  const apiClient = getApiClient();
209
244
  const response = await apiClient.proxy('get_task_dependencies', {
210
245
  body_of_work_id,
211
246
  task_id
212
247
  });
213
248
  if (!response.ok) {
214
- throw new Error(`Failed to fetch task dependencies: ${response.error}`);
249
+ return { result: { error: response.error || 'Failed to fetch task dependencies' }, isError: true };
215
250
  }
216
251
  return { result: response.data };
217
252
  };
218
253
  export const getNextBodyOfWorkTask = async (args, ctx) => {
219
- const { body_of_work_id } = args;
220
- validateRequired(body_of_work_id, 'body_of_work_id');
221
- validateUUID(body_of_work_id, 'body_of_work_id');
254
+ const { body_of_work_id } = parseArgs(args, getNextBodyOfWorkTaskSchema);
222
255
  const apiClient = getApiClient();
223
256
  const response = await apiClient.proxy('get_next_body_of_work_task', { body_of_work_id });
224
257
  if (!response.ok) {
225
- throw new Error(`Failed to get next body of work task: ${response.error}`);
258
+ return { result: { error: response.error || 'Failed to get next body of work task' }, isError: true };
226
259
  }
227
260
  return { result: response.data };
228
261
  };
@@ -0,0 +1,45 @@
1
+ /**
2
+ * Connectors Handlers
3
+ *
4
+ * Handles external integration management:
5
+ * - get_connectors
6
+ * - get_connector
7
+ * - add_connector
8
+ * - update_connector
9
+ * - delete_connector
10
+ * - test_connector
11
+ * - get_connector_events
12
+ */
13
+ import type { Handler, HandlerRegistry } from './types.js';
14
+ /**
15
+ * Get all connectors for a project
16
+ */
17
+ export declare const getConnectors: Handler;
18
+ /**
19
+ * Get a single connector with full details
20
+ */
21
+ export declare const getConnector: Handler;
22
+ /**
23
+ * Add a new connector
24
+ */
25
+ export declare const addConnector: Handler;
26
+ /**
27
+ * Update a connector
28
+ */
29
+ export declare const updateConnector: Handler;
30
+ /**
31
+ * Delete a connector
32
+ */
33
+ export declare const deleteConnector: Handler;
34
+ /**
35
+ * Test a connector by sending a test event
36
+ */
37
+ export declare const testConnector: Handler;
38
+ /**
39
+ * Get connector event history
40
+ */
41
+ export declare const getConnectorEvents: Handler;
42
+ /**
43
+ * Connectors handlers registry
44
+ */
45
+ export declare const connectorHandlers: HandlerRegistry;
@@ -0,0 +1,183 @@
1
+ /**
2
+ * Connectors Handlers
3
+ *
4
+ * Handles external integration management:
5
+ * - get_connectors
6
+ * - get_connector
7
+ * - add_connector
8
+ * - update_connector
9
+ * - delete_connector
10
+ * - test_connector
11
+ * - get_connector_events
12
+ */
13
+ import { success, error } from './types.js';
14
+ import { parseArgs, uuidValidator, createEnumValidator, } from '../validators.js';
15
+ import { getApiClient } from '../api-client.js';
16
+ // Valid connector types
17
+ const VALID_CONNECTOR_TYPES = ['webhook', 'slack', 'discord', 'github', 'custom'];
18
+ // Valid connector statuses
19
+ const VALID_CONNECTOR_STATUSES = ['active', 'disabled'];
20
+ // Valid event statuses
21
+ const VALID_EVENT_STATUSES = ['pending', 'sent', 'failed', 'retrying'];
22
+ // Argument schemas for type-safe parsing
23
+ const getConnectorsSchema = {
24
+ project_id: { type: 'string', required: true, validate: uuidValidator },
25
+ type: { type: 'string', validate: createEnumValidator(VALID_CONNECTOR_TYPES) },
26
+ status: { type: 'string', validate: createEnumValidator(VALID_CONNECTOR_STATUSES) },
27
+ limit: { type: 'number', default: 50 },
28
+ offset: { type: 'number', default: 0 },
29
+ };
30
+ const getConnectorSchema = {
31
+ connector_id: { type: 'string', required: true, validate: uuidValidator },
32
+ };
33
+ const addConnectorSchema = {
34
+ project_id: { type: 'string', required: true, validate: uuidValidator },
35
+ name: { type: 'string', required: true },
36
+ type: { type: 'string', required: true, validate: createEnumValidator(VALID_CONNECTOR_TYPES) },
37
+ description: { type: 'string' },
38
+ config: { type: 'object' },
39
+ events: { type: 'object' },
40
+ };
41
+ const updateConnectorSchema = {
42
+ connector_id: { type: 'string', required: true, validate: uuidValidator },
43
+ name: { type: 'string' },
44
+ description: { type: 'string' },
45
+ config: { type: 'object' },
46
+ events: { type: 'object' },
47
+ status: { type: 'string', validate: createEnumValidator(VALID_CONNECTOR_STATUSES) },
48
+ };
49
+ const deleteConnectorSchema = {
50
+ connector_id: { type: 'string', required: true, validate: uuidValidator },
51
+ };
52
+ const testConnectorSchema = {
53
+ connector_id: { type: 'string', required: true, validate: uuidValidator },
54
+ };
55
+ const getConnectorEventsSchema = {
56
+ connector_id: { type: 'string', validate: uuidValidator },
57
+ project_id: { type: 'string', validate: uuidValidator },
58
+ status: { type: 'string', validate: createEnumValidator(VALID_EVENT_STATUSES) },
59
+ limit: { type: 'number', default: 50 },
60
+ offset: { type: 'number', default: 0 },
61
+ };
62
+ /**
63
+ * Get all connectors for a project
64
+ */
65
+ export const getConnectors = async (args, _ctx) => {
66
+ const { project_id, type, status, limit, offset } = parseArgs(args, getConnectorsSchema);
67
+ const apiClient = getApiClient();
68
+ const response = await apiClient.getConnectors(project_id, {
69
+ type,
70
+ status,
71
+ limit,
72
+ offset
73
+ });
74
+ if (!response.ok) {
75
+ return error(response.error || 'Failed to fetch connectors');
76
+ }
77
+ return success(response.data);
78
+ };
79
+ /**
80
+ * Get a single connector with full details
81
+ */
82
+ export const getConnector = async (args, _ctx) => {
83
+ const { connector_id } = parseArgs(args, getConnectorSchema);
84
+ const apiClient = getApiClient();
85
+ const response = await apiClient.getConnector(connector_id);
86
+ if (!response.ok) {
87
+ return error(response.error || 'Failed to fetch connector');
88
+ }
89
+ return success(response.data);
90
+ };
91
+ /**
92
+ * Add a new connector
93
+ */
94
+ export const addConnector = async (args, _ctx) => {
95
+ const { project_id, name, type, description, config, events } = parseArgs(args, addConnectorSchema);
96
+ const apiClient = getApiClient();
97
+ const response = await apiClient.addConnector(project_id, {
98
+ name,
99
+ type,
100
+ description,
101
+ config: config,
102
+ events: events
103
+ });
104
+ if (!response.ok) {
105
+ return error(response.error || 'Failed to create connector');
106
+ }
107
+ return success(response.data);
108
+ };
109
+ /**
110
+ * Update a connector
111
+ */
112
+ export const updateConnector = async (args, _ctx) => {
113
+ const { connector_id, name, description, config, events, status } = parseArgs(args, updateConnectorSchema);
114
+ const apiClient = getApiClient();
115
+ const response = await apiClient.updateConnector(connector_id, {
116
+ name,
117
+ description,
118
+ config: config,
119
+ events: events,
120
+ status
121
+ });
122
+ if (!response.ok) {
123
+ return error(response.error || 'Failed to update connector');
124
+ }
125
+ return success(response.data);
126
+ };
127
+ /**
128
+ * Delete a connector
129
+ */
130
+ export const deleteConnector = async (args, _ctx) => {
131
+ const { connector_id } = parseArgs(args, deleteConnectorSchema);
132
+ const apiClient = getApiClient();
133
+ const response = await apiClient.deleteConnector(connector_id);
134
+ if (!response.ok) {
135
+ return error(response.error || 'Failed to delete connector');
136
+ }
137
+ return success(response.data);
138
+ };
139
+ /**
140
+ * Test a connector by sending a test event
141
+ */
142
+ export const testConnector = async (args, _ctx) => {
143
+ const { connector_id } = parseArgs(args, testConnectorSchema);
144
+ const apiClient = getApiClient();
145
+ const response = await apiClient.testConnector(connector_id);
146
+ if (!response.ok) {
147
+ return error(response.error || 'Failed to test connector');
148
+ }
149
+ return success(response.data);
150
+ };
151
+ /**
152
+ * Get connector event history
153
+ */
154
+ export const getConnectorEvents = async (args, _ctx) => {
155
+ const { connector_id, project_id, status, limit, offset } = parseArgs(args, getConnectorEventsSchema);
156
+ if (!connector_id && !project_id) {
157
+ return error('Either connector_id or project_id is required');
158
+ }
159
+ const apiClient = getApiClient();
160
+ const response = await apiClient.getConnectorEvents({
161
+ connector_id,
162
+ project_id,
163
+ status,
164
+ limit,
165
+ offset
166
+ });
167
+ if (!response.ok) {
168
+ return error(response.error || 'Failed to fetch connector events');
169
+ }
170
+ return success(response.data);
171
+ };
172
+ /**
173
+ * Connectors handlers registry
174
+ */
175
+ export const connectorHandlers = {
176
+ get_connectors: getConnectors,
177
+ get_connector: getConnector,
178
+ add_connector: addConnector,
179
+ update_connector: updateConnector,
180
+ delete_connector: deleteConnector,
181
+ test_connector: testConnector,
182
+ get_connector_events: getConnectorEvents,
183
+ };
@@ -8,6 +8,8 @@
8
8
  * - update_cost_alert
9
9
  * - delete_cost_alert
10
10
  * - get_task_costs
11
+ * - get_body_of_work_costs
12
+ * - get_sprint_costs
11
13
  */
12
14
  import type { Handler, HandlerRegistry } from './types.js';
13
15
  /**
@@ -34,6 +36,14 @@ export declare const deleteCostAlert: Handler;
34
36
  * Get task costs for a project
35
37
  */
36
38
  export declare const getTaskCosts: Handler;
39
+ /**
40
+ * Get body of work costs with phase breakdown
41
+ */
42
+ export declare const getBodyOfWorkCosts: Handler;
43
+ /**
44
+ * Get sprint costs with velocity metrics
45
+ */
46
+ export declare const getSprintCosts: Handler;
37
47
  /**
38
48
  * Cost handlers registry
39
49
  */