@vibescope/mcp-server 0.1.0 → 0.2.1

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 (76) hide show
  1. package/README.md +1 -1
  2. package/dist/api-client.d.ts +120 -2
  3. package/dist/api-client.js +51 -5
  4. package/dist/handlers/bodies-of-work.js +84 -50
  5. package/dist/handlers/cost.js +62 -54
  6. package/dist/handlers/decisions.js +29 -16
  7. package/dist/handlers/deployment.js +114 -107
  8. package/dist/handlers/discovery.d.ts +3 -0
  9. package/dist/handlers/discovery.js +55 -657
  10. package/dist/handlers/fallback.js +42 -28
  11. package/dist/handlers/file-checkouts.d.ts +18 -0
  12. package/dist/handlers/file-checkouts.js +101 -0
  13. package/dist/handlers/findings.d.ts +14 -1
  14. package/dist/handlers/findings.js +104 -28
  15. package/dist/handlers/git-issues.js +36 -32
  16. package/dist/handlers/ideas.js +44 -26
  17. package/dist/handlers/index.d.ts +2 -0
  18. package/dist/handlers/index.js +6 -0
  19. package/dist/handlers/milestones.js +34 -27
  20. package/dist/handlers/organizations.js +86 -78
  21. package/dist/handlers/progress.js +22 -11
  22. package/dist/handlers/project.js +62 -22
  23. package/dist/handlers/requests.js +15 -11
  24. package/dist/handlers/roles.d.ts +18 -0
  25. package/dist/handlers/roles.js +130 -0
  26. package/dist/handlers/session.js +52 -15
  27. package/dist/handlers/sprints.js +78 -65
  28. package/dist/handlers/tasks.js +135 -74
  29. package/dist/handlers/tool-docs.d.ts +4 -3
  30. package/dist/handlers/tool-docs.js +252 -5
  31. package/dist/handlers/validation.js +30 -14
  32. package/dist/index.js +25 -7
  33. package/dist/tools.js +417 -4
  34. package/package.json +1 -1
  35. package/src/api-client.ts +161 -8
  36. package/src/handlers/__test-setup__.ts +12 -0
  37. package/src/handlers/bodies-of-work.ts +127 -111
  38. package/src/handlers/cost.test.ts +34 -44
  39. package/src/handlers/cost.ts +77 -92
  40. package/src/handlers/decisions.test.ts +3 -2
  41. package/src/handlers/decisions.ts +32 -27
  42. package/src/handlers/deployment.ts +144 -190
  43. package/src/handlers/discovery.test.ts +4 -5
  44. package/src/handlers/discovery.ts +60 -746
  45. package/src/handlers/fallback.test.ts +78 -0
  46. package/src/handlers/fallback.ts +51 -38
  47. package/src/handlers/file-checkouts.test.ts +477 -0
  48. package/src/handlers/file-checkouts.ts +127 -0
  49. package/src/handlers/findings.test.ts +274 -2
  50. package/src/handlers/findings.ts +123 -57
  51. package/src/handlers/git-issues.ts +40 -80
  52. package/src/handlers/ideas.ts +56 -54
  53. package/src/handlers/index.ts +6 -0
  54. package/src/handlers/milestones.test.ts +1 -1
  55. package/src/handlers/milestones.ts +47 -45
  56. package/src/handlers/organizations.ts +104 -129
  57. package/src/handlers/progress.ts +24 -22
  58. package/src/handlers/project.ts +89 -57
  59. package/src/handlers/requests.ts +18 -14
  60. package/src/handlers/roles.test.ts +303 -0
  61. package/src/handlers/roles.ts +208 -0
  62. package/src/handlers/session.test.ts +37 -2
  63. package/src/handlers/session.ts +64 -21
  64. package/src/handlers/sprints.ts +114 -134
  65. package/src/handlers/tasks.test.ts +61 -0
  66. package/src/handlers/tasks.ts +170 -139
  67. package/src/handlers/tool-docs.ts +1024 -0
  68. package/src/handlers/validation.test.ts +53 -1
  69. package/src/handlers/validation.ts +32 -21
  70. package/src/index.ts +25 -7
  71. package/src/tools.ts +417 -4
  72. package/dist/config/tool-categories.d.ts +0 -31
  73. package/dist/config/tool-categories.js +0 -253
  74. package/dist/knowledge.d.ts +0 -6
  75. package/dist/knowledge.js +0 -218
  76. package/src/knowledge.ts +0 -230
@@ -24,6 +24,8 @@ export * from './organizations.js';
24
24
  export * from './cost.js';
25
25
  export * from './git-issues.js';
26
26
  export * from './sprints.js';
27
+ export * from './file-checkouts.js';
28
+ export * from './roles.js';
27
29
  import type { HandlerRegistry } from './types.js';
28
30
  /**
29
31
  * Build the complete handler registry from all modules
@@ -24,6 +24,8 @@ export * from './organizations.js';
24
24
  export * from './cost.js';
25
25
  export * from './git-issues.js';
26
26
  export * from './sprints.js';
27
+ export * from './file-checkouts.js';
28
+ export * from './roles.js';
27
29
  import { milestoneHandlers } from './milestones.js';
28
30
  import { sessionHandlers } from './session.js';
29
31
  import { ideaHandlers } from './ideas.js';
@@ -43,6 +45,8 @@ import { organizationHandlers } from './organizations.js';
43
45
  import { costHandlers } from './cost.js';
44
46
  import { gitIssueHandlers } from './git-issues.js';
45
47
  import { sprintHandlers } from './sprints.js';
48
+ import { fileCheckoutHandlers } from './file-checkouts.js';
49
+ import { roleHandlers } from './roles.js';
46
50
  /**
47
51
  * Build the complete handler registry from all modules
48
52
  */
@@ -67,5 +71,7 @@ export function buildHandlerRegistry() {
67
71
  ...costHandlers,
68
72
  ...gitIssueHandlers,
69
73
  ...sprintHandlers,
74
+ ...fileCheckoutHandlers,
75
+ ...roleHandlers,
70
76
  };
71
77
  }
@@ -10,13 +10,34 @@
10
10
  *
11
11
  * MIGRATED: Uses Vibescope API client instead of direct Supabase
12
12
  */
13
- import { ValidationError, validateRequired, validateUUID } from '../validators.js';
13
+ import { parseArgs, uuidValidator, createEnumValidator, ValidationError, } from '../validators.js';
14
14
  import { getApiClient } from '../api-client.js';
15
+ const VALID_MILESTONE_STATUSES = ['pending', 'in_progress', 'completed'];
16
+ // Argument schemas for type-safe parsing
17
+ const addMilestoneSchema = {
18
+ task_id: { type: 'string', required: true, validate: uuidValidator },
19
+ title: { type: 'string', required: true },
20
+ description: { type: 'string' },
21
+ order_index: { type: 'number' },
22
+ };
23
+ const updateMilestoneSchema = {
24
+ milestone_id: { type: 'string', required: true, validate: uuidValidator },
25
+ title: { type: 'string' },
26
+ description: { type: 'string' },
27
+ status: { type: 'string', validate: createEnumValidator(VALID_MILESTONE_STATUSES) },
28
+ order_index: { type: 'number' },
29
+ };
30
+ const completeMilestoneSchema = {
31
+ milestone_id: { type: 'string', required: true, validate: uuidValidator },
32
+ };
33
+ const deleteMilestoneSchema = {
34
+ milestone_id: { type: 'string', required: true, validate: uuidValidator },
35
+ };
36
+ const getMilestonesSchema = {
37
+ task_id: { type: 'string', required: true, validate: uuidValidator },
38
+ };
15
39
  export const addMilestone = async (args, ctx) => {
16
- const { task_id, title, description, order_index } = args;
17
- validateRequired(task_id, 'task_id');
18
- validateUUID(task_id, 'task_id');
19
- validateRequired(title, 'title');
40
+ const { task_id, title, description, order_index } = parseArgs(args, addMilestoneSchema);
20
41
  const { session } = ctx;
21
42
  const apiClient = getApiClient();
22
43
  const response = await apiClient.addMilestone(task_id, {
@@ -34,16 +55,8 @@ export const addMilestone = async (args, ctx) => {
34
55
  },
35
56
  };
36
57
  };
37
- export const updateMilestone = async (args, ctx) => {
38
- const { milestone_id, title, description, status, order_index } = args;
39
- validateRequired(milestone_id, 'milestone_id');
40
- validateUUID(milestone_id, 'milestone_id');
41
- // Validate status if provided
42
- if (status !== undefined) {
43
- if (!['pending', 'in_progress', 'completed'].includes(status)) {
44
- throw new ValidationError('status must be pending, in_progress, or completed');
45
- }
46
- }
58
+ export const updateMilestone = async (args, _ctx) => {
59
+ const { milestone_id, title, description, status, order_index } = parseArgs(args, updateMilestoneSchema);
47
60
  // Check that at least one field is provided
48
61
  if (title === undefined && description === undefined && status === undefined && order_index === undefined) {
49
62
  throw new ValidationError('At least one field to update is required');
@@ -65,10 +78,8 @@ export const updateMilestone = async (args, ctx) => {
65
78
  },
66
79
  };
67
80
  };
68
- export const completeMilestone = async (args, ctx) => {
69
- const { milestone_id } = args;
70
- validateRequired(milestone_id, 'milestone_id');
71
- validateUUID(milestone_id, 'milestone_id');
81
+ export const completeMilestone = async (args, _ctx) => {
82
+ const { milestone_id } = parseArgs(args, completeMilestoneSchema);
72
83
  const apiClient = getApiClient();
73
84
  const response = await apiClient.completeMilestone(milestone_id);
74
85
  if (!response.ok) {
@@ -81,10 +92,8 @@ export const completeMilestone = async (args, ctx) => {
81
92
  },
82
93
  };
83
94
  };
84
- export const deleteMilestone = async (args, ctx) => {
85
- const { milestone_id } = args;
86
- validateRequired(milestone_id, 'milestone_id');
87
- validateUUID(milestone_id, 'milestone_id');
95
+ export const deleteMilestone = async (args, _ctx) => {
96
+ const { milestone_id } = parseArgs(args, deleteMilestoneSchema);
88
97
  const apiClient = getApiClient();
89
98
  const response = await apiClient.deleteMilestone(milestone_id);
90
99
  if (!response.ok) {
@@ -97,10 +106,8 @@ export const deleteMilestone = async (args, ctx) => {
97
106
  },
98
107
  };
99
108
  };
100
- export const getMilestones = async (args, ctx) => {
101
- const { task_id } = args;
102
- validateRequired(task_id, 'task_id');
103
- validateUUID(task_id, 'task_id');
109
+ export const getMilestones = async (args, _ctx) => {
110
+ const { task_id } = parseArgs(args, getMilestonesSchema);
104
111
  const apiClient = getApiClient();
105
112
  const response = await apiClient.getMilestones(task_id);
106
113
  if (!response.ok) {
@@ -16,16 +16,71 @@
16
16
  * - unshare_project
17
17
  * - list_project_shares
18
18
  */
19
- import { validateRequired, validateUUID } from '../validators.js';
19
+ import { parseArgs, uuidValidator, createEnumValidator, ValidationError } from '../validators.js';
20
20
  import { getApiClient } from '../api-client.js';
21
21
  // Valid roles in order of permission level
22
22
  const ROLE_ORDER = ['viewer', 'member', 'admin', 'owner'];
23
+ const ASSIGNABLE_ROLES = ['viewer', 'member', 'admin'];
23
24
  // Valid share permissions
24
25
  const PERMISSION_ORDER = ['read', 'write', 'admin'];
25
26
  // ============================================================================
27
+ // Argument Schemas
28
+ // ============================================================================
29
+ const createOrganizationSchema = {
30
+ name: { type: 'string', required: true },
31
+ description: { type: 'string' },
32
+ slug: { type: 'string' },
33
+ };
34
+ const updateOrganizationSchema = {
35
+ organization_id: { type: 'string', required: true, validate: uuidValidator },
36
+ name: { type: 'string' },
37
+ description: { type: 'string' },
38
+ logo_url: { type: 'string' },
39
+ };
40
+ const deleteOrganizationSchema = {
41
+ organization_id: { type: 'string', required: true, validate: uuidValidator },
42
+ };
43
+ const listOrgMembersSchema = {
44
+ organization_id: { type: 'string', required: true, validate: uuidValidator },
45
+ };
46
+ const inviteMemberSchema = {
47
+ organization_id: { type: 'string', required: true, validate: uuidValidator },
48
+ email: { type: 'string', required: true },
49
+ role: { type: 'string', default: 'member', validate: createEnumValidator(ASSIGNABLE_ROLES) },
50
+ };
51
+ const updateMemberRoleSchema = {
52
+ organization_id: { type: 'string', required: true, validate: uuidValidator },
53
+ user_id: { type: 'string', required: true, validate: uuidValidator },
54
+ role: { type: 'string', required: true, validate: createEnumValidator(ROLE_ORDER) },
55
+ };
56
+ const removeMemberSchema = {
57
+ organization_id: { type: 'string', required: true, validate: uuidValidator },
58
+ user_id: { type: 'string', required: true, validate: uuidValidator },
59
+ };
60
+ const leaveOrganizationSchema = {
61
+ organization_id: { type: 'string', required: true, validate: uuidValidator },
62
+ };
63
+ const shareProjectWithOrgSchema = {
64
+ project_id: { type: 'string', required: true, validate: uuidValidator },
65
+ organization_id: { type: 'string', required: true, validate: uuidValidator },
66
+ permission: { type: 'string', default: 'read', validate: createEnumValidator(PERMISSION_ORDER) },
67
+ };
68
+ const updateProjectShareSchema = {
69
+ project_id: { type: 'string', required: true, validate: uuidValidator },
70
+ organization_id: { type: 'string', required: true, validate: uuidValidator },
71
+ permission: { type: 'string', required: true, validate: createEnumValidator(PERMISSION_ORDER) },
72
+ };
73
+ const unshareProjectSchema = {
74
+ project_id: { type: 'string', required: true, validate: uuidValidator },
75
+ organization_id: { type: 'string', required: true, validate: uuidValidator },
76
+ };
77
+ const listProjectSharesSchema = {
78
+ project_id: { type: 'string', required: true, validate: uuidValidator },
79
+ };
80
+ // ============================================================================
26
81
  // Organization Management
27
82
  // ============================================================================
28
- export const listOrganizations = async (_args, ctx) => {
83
+ export const listOrganizations = async (_args, _ctx) => {
29
84
  const apiClient = getApiClient();
30
85
  const response = await apiClient.listOrganizations();
31
86
  if (!response.ok) {
@@ -33,9 +88,8 @@ export const listOrganizations = async (_args, ctx) => {
33
88
  }
34
89
  return { result: response.data };
35
90
  };
36
- export const createOrganization = async (args, ctx) => {
37
- const { name, description, slug } = args;
38
- validateRequired(name, 'name');
91
+ export const createOrganization = async (args, _ctx) => {
92
+ const { name, description, slug } = parseArgs(args, createOrganizationSchema);
39
93
  const apiClient = getApiClient();
40
94
  const response = await apiClient.createOrganization({
41
95
  name,
@@ -47,10 +101,12 @@ export const createOrganization = async (args, ctx) => {
47
101
  }
48
102
  return { result: response.data };
49
103
  };
50
- export const updateOrganization = async (args, ctx) => {
51
- const { organization_id, name, description, logo_url } = args;
52
- validateRequired(organization_id, 'organization_id');
53
- validateUUID(organization_id, 'organization_id');
104
+ export const updateOrganization = async (args, _ctx) => {
105
+ const { organization_id, name, description, logo_url } = parseArgs(args, updateOrganizationSchema);
106
+ // Check that at least one update is provided
107
+ if (name === undefined && description === undefined && logo_url === undefined) {
108
+ throw new ValidationError('No updates provided');
109
+ }
54
110
  const updates = {};
55
111
  if (name !== undefined)
56
112
  updates.name = name;
@@ -58,9 +114,6 @@ export const updateOrganization = async (args, ctx) => {
58
114
  updates.description = description;
59
115
  if (logo_url !== undefined)
60
116
  updates.logo_url = logo_url;
61
- if (Object.keys(updates).length === 0) {
62
- throw new Error('No updates provided');
63
- }
64
117
  const apiClient = getApiClient();
65
118
  const response = await apiClient.updateOrganization(organization_id, updates);
66
119
  if (!response.ok) {
@@ -68,10 +121,8 @@ export const updateOrganization = async (args, ctx) => {
68
121
  }
69
122
  return { result: response.data };
70
123
  };
71
- export const deleteOrganization = async (args, ctx) => {
72
- const { organization_id } = args;
73
- validateRequired(organization_id, 'organization_id');
74
- validateUUID(organization_id, 'organization_id');
124
+ export const deleteOrganization = async (args, _ctx) => {
125
+ const { organization_id } = parseArgs(args, deleteOrganizationSchema);
75
126
  const apiClient = getApiClient();
76
127
  const response = await apiClient.deleteOrganization(organization_id);
77
128
  if (!response.ok) {
@@ -82,10 +133,8 @@ export const deleteOrganization = async (args, ctx) => {
82
133
  // ============================================================================
83
134
  // Member Management
84
135
  // ============================================================================
85
- export const listOrgMembers = async (args, ctx) => {
86
- const { organization_id } = args;
87
- validateRequired(organization_id, 'organization_id');
88
- validateUUID(organization_id, 'organization_id');
136
+ export const listOrgMembers = async (args, _ctx) => {
137
+ const { organization_id } = parseArgs(args, listOrgMembersSchema);
89
138
  const apiClient = getApiClient();
90
139
  const response = await apiClient.listOrgMembers(organization_id);
91
140
  if (!response.ok) {
@@ -93,14 +142,8 @@ export const listOrgMembers = async (args, ctx) => {
93
142
  }
94
143
  return { result: response.data };
95
144
  };
96
- export const inviteMember = async (args, ctx) => {
97
- const { organization_id, email, role = 'member' } = args;
98
- validateRequired(organization_id, 'organization_id');
99
- validateRequired(email, 'email');
100
- validateUUID(organization_id, 'organization_id');
101
- if (!['admin', 'member', 'viewer'].includes(role)) {
102
- throw new Error('Invalid role. Must be admin, member, or viewer.');
103
- }
145
+ export const inviteMember = async (args, _ctx) => {
146
+ const { organization_id, email, role } = parseArgs(args, inviteMemberSchema);
104
147
  const apiClient = getApiClient();
105
148
  const response = await apiClient.inviteMember(organization_id, email, role);
106
149
  if (!response.ok) {
@@ -108,18 +151,10 @@ export const inviteMember = async (args, ctx) => {
108
151
  }
109
152
  return { result: response.data };
110
153
  };
111
- export const updateMemberRole = async (args, ctx) => {
112
- const { organization_id, user_id, role } = args;
113
- validateRequired(organization_id, 'organization_id');
114
- validateRequired(user_id, 'user_id');
115
- validateRequired(role, 'role');
116
- validateUUID(organization_id, 'organization_id');
117
- validateUUID(user_id, 'user_id');
118
- if (!ROLE_ORDER.includes(role)) {
119
- throw new Error(`Invalid role. Must be one of: ${ROLE_ORDER.join(', ')}`);
120
- }
154
+ export const updateMemberRole = async (args, _ctx) => {
155
+ const { organization_id, user_id, role } = parseArgs(args, updateMemberRoleSchema);
121
156
  if (role === 'owner') {
122
- throw new Error('Cannot assign owner role. Use transfer ownership instead.');
157
+ throw new ValidationError('Cannot assign owner role. Use transfer ownership instead.');
123
158
  }
124
159
  const apiClient = getApiClient();
125
160
  const response = await apiClient.updateMemberRole(organization_id, user_id, role);
@@ -128,12 +163,8 @@ export const updateMemberRole = async (args, ctx) => {
128
163
  }
129
164
  return { result: response.data };
130
165
  };
131
- export const removeMember = async (args, ctx) => {
132
- const { organization_id, user_id } = args;
133
- validateRequired(organization_id, 'organization_id');
134
- validateRequired(user_id, 'user_id');
135
- validateUUID(organization_id, 'organization_id');
136
- validateUUID(user_id, 'user_id');
166
+ export const removeMember = async (args, _ctx) => {
167
+ const { organization_id, user_id } = parseArgs(args, removeMemberSchema);
137
168
  const apiClient = getApiClient();
138
169
  const response = await apiClient.removeMember(organization_id, user_id);
139
170
  if (!response.ok) {
@@ -141,10 +172,8 @@ export const removeMember = async (args, ctx) => {
141
172
  }
142
173
  return { result: response.data };
143
174
  };
144
- export const leaveOrganization = async (args, ctx) => {
145
- const { organization_id } = args;
146
- validateRequired(organization_id, 'organization_id');
147
- validateUUID(organization_id, 'organization_id');
175
+ export const leaveOrganization = async (args, _ctx) => {
176
+ const { organization_id } = parseArgs(args, leaveOrganizationSchema);
148
177
  const apiClient = getApiClient();
149
178
  const response = await apiClient.leaveOrganization(organization_id);
150
179
  if (!response.ok) {
@@ -155,15 +184,8 @@ export const leaveOrganization = async (args, ctx) => {
155
184
  // ============================================================================
156
185
  // Project Sharing
157
186
  // ============================================================================
158
- export const shareProjectWithOrg = async (args, ctx) => {
159
- const { project_id, organization_id, permission = 'read' } = args;
160
- validateRequired(project_id, 'project_id');
161
- validateRequired(organization_id, 'organization_id');
162
- validateUUID(project_id, 'project_id');
163
- validateUUID(organization_id, 'organization_id');
164
- if (!PERMISSION_ORDER.includes(permission)) {
165
- throw new Error(`Invalid permission. Must be one of: ${PERMISSION_ORDER.join(', ')}`);
166
- }
187
+ export const shareProjectWithOrg = async (args, _ctx) => {
188
+ const { project_id, organization_id, permission } = parseArgs(args, shareProjectWithOrgSchema);
167
189
  const apiClient = getApiClient();
168
190
  const response = await apiClient.shareProjectWithOrg(project_id, organization_id, permission);
169
191
  if (!response.ok) {
@@ -171,16 +193,8 @@ export const shareProjectWithOrg = async (args, ctx) => {
171
193
  }
172
194
  return { result: response.data };
173
195
  };
174
- export const updateProjectShare = async (args, ctx) => {
175
- const { project_id, organization_id, permission } = args;
176
- validateRequired(project_id, 'project_id');
177
- validateRequired(organization_id, 'organization_id');
178
- validateRequired(permission, 'permission');
179
- validateUUID(project_id, 'project_id');
180
- validateUUID(organization_id, 'organization_id');
181
- if (!PERMISSION_ORDER.includes(permission)) {
182
- throw new Error(`Invalid permission. Must be one of: ${PERMISSION_ORDER.join(', ')}`);
183
- }
196
+ export const updateProjectShare = async (args, _ctx) => {
197
+ const { project_id, organization_id, permission } = parseArgs(args, updateProjectShareSchema);
184
198
  const apiClient = getApiClient();
185
199
  const response = await apiClient.updateProjectShare(project_id, organization_id, permission);
186
200
  if (!response.ok) {
@@ -188,12 +202,8 @@ export const updateProjectShare = async (args, ctx) => {
188
202
  }
189
203
  return { result: response.data };
190
204
  };
191
- export const unshareProject = async (args, ctx) => {
192
- const { project_id, organization_id } = args;
193
- validateRequired(project_id, 'project_id');
194
- validateRequired(organization_id, 'organization_id');
195
- validateUUID(project_id, 'project_id');
196
- validateUUID(organization_id, 'organization_id');
205
+ export const unshareProject = async (args, _ctx) => {
206
+ const { project_id, organization_id } = parseArgs(args, unshareProjectSchema);
197
207
  const apiClient = getApiClient();
198
208
  const response = await apiClient.unshareProject(project_id, organization_id);
199
209
  if (!response.ok) {
@@ -201,10 +211,8 @@ export const unshareProject = async (args, ctx) => {
201
211
  }
202
212
  return { result: response.data };
203
213
  };
204
- export const listProjectShares = async (args, ctx) => {
205
- const { project_id } = args;
206
- validateRequired(project_id, 'project_id');
207
- validateUUID(project_id, 'project_id');
214
+ export const listProjectShares = async (args, _ctx) => {
215
+ const { project_id } = parseArgs(args, listProjectSharesSchema);
208
216
  const apiClient = getApiClient();
209
217
  const response = await apiClient.listProjectShares(project_id);
210
218
  if (!response.ok) {
@@ -7,13 +7,24 @@
7
7
  *
8
8
  * MIGRATED: Uses Vibescope API client instead of direct Supabase
9
9
  */
10
- import { validateRequired, validateUUID } from '../validators.js';
10
+ import { parseArgs, uuidValidator } from '../validators.js';
11
11
  import { getApiClient } from '../api-client.js';
12
+ // Argument schemas for type-safe parsing
13
+ const logProgressSchema = {
14
+ project_id: { type: 'string', required: true, validate: uuidValidator },
15
+ task_id: { type: 'string', validate: uuidValidator },
16
+ summary: { type: 'string', required: true },
17
+ details: { type: 'string' },
18
+ };
19
+ const getActivityFeedSchema = {
20
+ project_id: { type: 'string', required: true, validate: uuidValidator },
21
+ limit: { type: 'number', default: 50 },
22
+ since: { type: 'string' },
23
+ types: { type: 'array' },
24
+ created_by: { type: 'string' },
25
+ };
12
26
  export const logProgress = async (args, ctx) => {
13
- const { project_id, task_id, summary, details } = args;
14
- validateRequired(project_id, 'project_id');
15
- validateUUID(project_id, 'project_id');
16
- validateRequired(summary, 'summary');
27
+ const { project_id, task_id, summary, details } = parseArgs(args, logProgressSchema);
17
28
  const { session } = ctx;
18
29
  const apiClient = getApiClient();
19
30
  const response = await apiClient.logProgress(project_id, {
@@ -27,15 +38,15 @@ export const logProgress = async (args, ctx) => {
27
38
  }
28
39
  return { result: { success: true, progress_id: response.data?.progress_id } };
29
40
  };
30
- export const getActivityFeed = async (args, ctx) => {
31
- const { project_id, limit = 50, since } = args;
32
- validateRequired(project_id, 'project_id');
33
- validateUUID(project_id, 'project_id');
41
+ export const getActivityFeed = async (args, _ctx) => {
42
+ const { project_id, limit, since, types, created_by } = parseArgs(args, getActivityFeedSchema);
34
43
  const apiClient = getApiClient();
35
- const effectiveLimit = Math.min(limit, 200);
44
+ const effectiveLimit = Math.min(limit ?? 50, 200);
36
45
  const response = await apiClient.getActivityFeed(project_id, {
37
46
  limit: effectiveLimit,
38
- since
47
+ since,
48
+ types: types,
49
+ created_by
39
50
  });
40
51
  if (!response.ok) {
41
52
  throw new Error(`Failed to fetch activity feed: ${response.error}`);
@@ -8,10 +8,46 @@
8
8
  * - update_project
9
9
  * - update_project_readme
10
10
  */
11
- import { validateRequired, validateUUID, validateProjectStatus } from '../validators.js';
11
+ import { parseArgs, uuidValidator, projectStatusValidator, createEnumValidator, } from '../validators.js';
12
12
  import { getApiClient } from '../api-client.js';
13
- export const getProjectContext = async (args, ctx) => {
14
- const { project_id, git_url } = args;
13
+ const VALID_GIT_WORKFLOWS = ['none', 'trunk-based', 'github-flow', 'git-flow'];
14
+ // Argument schemas for type-safe parsing
15
+ const getProjectContextSchema = {
16
+ project_id: { type: 'string', validate: uuidValidator },
17
+ git_url: { type: 'string' },
18
+ };
19
+ const getGitWorkflowSchema = {
20
+ project_id: { type: 'string', required: true, validate: uuidValidator },
21
+ task_id: { type: 'string', validate: uuidValidator },
22
+ };
23
+ const createProjectSchema = {
24
+ name: { type: 'string', required: true },
25
+ description: { type: 'string' },
26
+ goal: { type: 'string' },
27
+ git_url: { type: 'string' },
28
+ tech_stack: { type: 'array' },
29
+ };
30
+ const updateProjectSchema = {
31
+ project_id: { type: 'string', required: true, validate: uuidValidator },
32
+ name: { type: 'string' },
33
+ description: { type: 'string' },
34
+ goal: { type: 'string' },
35
+ git_url: { type: 'string' },
36
+ tech_stack: { type: 'array' },
37
+ status: { type: 'string', validate: projectStatusValidator },
38
+ git_workflow: { type: 'string', validate: createEnumValidator(VALID_GIT_WORKFLOWS) },
39
+ git_main_branch: { type: 'string' },
40
+ git_develop_branch: { type: 'string' },
41
+ git_auto_branch: { type: 'boolean' },
42
+ git_auto_tag: { type: 'boolean' },
43
+ deployment_instructions: { type: 'string' },
44
+ };
45
+ const updateProjectReadmeSchema = {
46
+ project_id: { type: 'string', required: true, validate: uuidValidator },
47
+ readme_content: { type: 'string', required: true },
48
+ };
49
+ export const getProjectContext = async (args, _ctx) => {
50
+ const { project_id, git_url } = parseArgs(args, getProjectContextSchema);
15
51
  const apiClient = getApiClient();
16
52
  // If no project_id or git_url, list all projects
17
53
  if (!project_id && !git_url) {
@@ -36,10 +72,8 @@ export const getProjectContext = async (args, ctx) => {
36
72
  }
37
73
  return { result: response.data };
38
74
  };
39
- export const getGitWorkflow = async (args, ctx) => {
40
- const { project_id, task_id } = args;
41
- validateRequired(project_id, 'project_id');
42
- validateUUID(project_id, 'project_id');
75
+ export const getGitWorkflow = async (args, _ctx) => {
76
+ const { project_id, task_id } = parseArgs(args, getGitWorkflowSchema);
43
77
  const apiClient = getApiClient();
44
78
  const response = await apiClient.getGitWorkflow(project_id, task_id);
45
79
  if (!response.ok) {
@@ -47,39 +81,45 @@ export const getGitWorkflow = async (args, ctx) => {
47
81
  }
48
82
  return { result: response.data };
49
83
  };
50
- export const createProject = async (args, ctx) => {
51
- const { name, description, goal, git_url, tech_stack } = args;
52
- validateRequired(name, 'name');
84
+ export const createProject = async (args, _ctx) => {
85
+ const { name, description, goal, git_url, tech_stack } = parseArgs(args, createProjectSchema);
53
86
  const apiClient = getApiClient();
54
87
  const response = await apiClient.createProject({
55
88
  name,
56
89
  description,
57
90
  goal,
58
91
  git_url,
59
- tech_stack
92
+ tech_stack: tech_stack
60
93
  });
61
94
  if (!response.ok) {
62
95
  throw new Error(response.error || 'Failed to create project');
63
96
  }
64
97
  return { result: response.data };
65
98
  };
66
- export const updateProject = async (args, ctx) => {
67
- const { project_id, ...updates } = args;
68
- validateRequired(project_id, 'project_id');
69
- validateUUID(project_id, 'project_id');
70
- validateProjectStatus(updates.status);
99
+ export const updateProject = async (args, _ctx) => {
100
+ const { project_id, name, description, goal, git_url, tech_stack, status, git_workflow, git_main_branch, git_develop_branch, git_auto_branch, git_auto_tag, deployment_instructions } = parseArgs(args, updateProjectSchema);
71
101
  const apiClient = getApiClient();
72
- const response = await apiClient.updateProject(project_id, updates);
102
+ const response = await apiClient.updateProject(project_id, {
103
+ name,
104
+ description,
105
+ goal,
106
+ git_url,
107
+ tech_stack: tech_stack,
108
+ status: status,
109
+ git_workflow: git_workflow,
110
+ git_main_branch,
111
+ git_develop_branch,
112
+ git_auto_branch,
113
+ git_auto_tag,
114
+ deployment_instructions
115
+ });
73
116
  if (!response.ok) {
74
117
  throw new Error(response.error || 'Failed to update project');
75
118
  }
76
119
  return { result: response.data };
77
120
  };
78
- export const updateProjectReadme = async (args, ctx) => {
79
- const { project_id, readme_content } = args;
80
- validateRequired(project_id, 'project_id');
81
- validateUUID(project_id, 'project_id');
82
- validateRequired(readme_content, 'readme_content');
121
+ export const updateProjectReadme = async (args, _ctx) => {
122
+ const { project_id, readme_content } = parseArgs(args, updateProjectReadmeSchema);
83
123
  const apiClient = getApiClient();
84
124
  const response = await apiClient.updateProjectReadme(project_id, readme_content);
85
125
  if (!response.ok) {
@@ -8,12 +8,21 @@
8
8
  *
9
9
  * MIGRATED: Uses Vibescope API client instead of direct Supabase
10
10
  */
11
- import { validateRequired, validateUUID } from '../validators.js';
11
+ import { parseArgs, uuidValidator } from '../validators.js';
12
12
  import { getApiClient } from '../api-client.js';
13
+ // Argument schemas for type-safe parsing
14
+ const getPendingRequestsSchema = {
15
+ project_id: { type: 'string', required: true, validate: uuidValidator },
16
+ };
17
+ const acknowledgeRequestSchema = {
18
+ request_id: { type: 'string', required: true, validate: uuidValidator },
19
+ };
20
+ const answerQuestionSchema = {
21
+ request_id: { type: 'string', required: true, validate: uuidValidator },
22
+ answer: { type: 'string', required: true },
23
+ };
13
24
  export const getPendingRequests = async (args, ctx) => {
14
- const { project_id } = args;
15
- validateRequired(project_id, 'project_id');
16
- validateUUID(project_id, 'project_id');
25
+ const { project_id } = parseArgs(args, getPendingRequestsSchema);
17
26
  const { session } = ctx;
18
27
  const apiClient = getApiClient();
19
28
  const response = await apiClient.getPendingRequests(project_id, session.currentSessionId || undefined);
@@ -28,9 +37,7 @@ export const getPendingRequests = async (args, ctx) => {
28
37
  };
29
38
  };
30
39
  export const acknowledgeRequest = async (args, ctx) => {
31
- const { request_id } = args;
32
- validateRequired(request_id, 'request_id');
33
- validateUUID(request_id, 'request_id');
40
+ const { request_id } = parseArgs(args, acknowledgeRequestSchema);
34
41
  const { session } = ctx;
35
42
  const apiClient = getApiClient();
36
43
  const response = await apiClient.acknowledgeRequest(request_id, session.currentSessionId || undefined);
@@ -44,10 +51,7 @@ export const acknowledgeRequest = async (args, ctx) => {
44
51
  };
45
52
  };
46
53
  export const answerQuestion = async (args, ctx) => {
47
- const { request_id, answer } = args;
48
- validateRequired(request_id, 'request_id');
49
- validateRequired(answer, 'answer');
50
- validateUUID(request_id, 'request_id');
54
+ const { request_id, answer } = parseArgs(args, answerQuestionSchema);
51
55
  const { session } = ctx;
52
56
  const apiClient = getApiClient();
53
57
  const response = await apiClient.answerQuestion(request_id, answer, session.currentSessionId || undefined);
@@ -0,0 +1,18 @@
1
+ /**
2
+ * Role Management Handlers
3
+ *
4
+ * Handles agent role configuration and assignment:
5
+ * - get_role_settings: Get role configuration for a project
6
+ * - update_role_settings: Update role settings for a project
7
+ * - set_session_role: Set the role for the current session
8
+ * - get_agents_by_role: Get active agents grouped by their assigned roles
9
+ */
10
+ import type { Handler, HandlerRegistry } from './types.js';
11
+ export declare const getRoleSettings: Handler;
12
+ export declare const updateRoleSettings: Handler;
13
+ export declare const setSessionRole: Handler;
14
+ export declare const getAgentsByRole: Handler;
15
+ /**
16
+ * Role handlers registry
17
+ */
18
+ export declare const roleHandlers: HandlerRegistry;