@vibescope/mcp-server 0.0.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 (170) hide show
  1. package/README.md +98 -0
  2. package/dist/cli.d.ts +34 -0
  3. package/dist/cli.js +356 -0
  4. package/dist/cli.test.d.ts +1 -0
  5. package/dist/cli.test.js +367 -0
  6. package/dist/handlers/__test-utils__.d.ts +72 -0
  7. package/dist/handlers/__test-utils__.js +176 -0
  8. package/dist/handlers/blockers.d.ts +18 -0
  9. package/dist/handlers/blockers.js +81 -0
  10. package/dist/handlers/bodies-of-work.d.ts +34 -0
  11. package/dist/handlers/bodies-of-work.js +614 -0
  12. package/dist/handlers/checkouts.d.ts +37 -0
  13. package/dist/handlers/checkouts.js +377 -0
  14. package/dist/handlers/cost.d.ts +39 -0
  15. package/dist/handlers/cost.js +247 -0
  16. package/dist/handlers/decisions.d.ts +16 -0
  17. package/dist/handlers/decisions.js +64 -0
  18. package/dist/handlers/deployment.d.ts +36 -0
  19. package/dist/handlers/deployment.js +1062 -0
  20. package/dist/handlers/discovery.d.ts +14 -0
  21. package/dist/handlers/discovery.js +870 -0
  22. package/dist/handlers/fallback.d.ts +18 -0
  23. package/dist/handlers/fallback.js +216 -0
  24. package/dist/handlers/findings.d.ts +18 -0
  25. package/dist/handlers/findings.js +110 -0
  26. package/dist/handlers/git-issues.d.ts +22 -0
  27. package/dist/handlers/git-issues.js +247 -0
  28. package/dist/handlers/ideas.d.ts +19 -0
  29. package/dist/handlers/ideas.js +188 -0
  30. package/dist/handlers/index.d.ts +29 -0
  31. package/dist/handlers/index.js +65 -0
  32. package/dist/handlers/knowledge-query.d.ts +22 -0
  33. package/dist/handlers/knowledge-query.js +253 -0
  34. package/dist/handlers/knowledge.d.ts +12 -0
  35. package/dist/handlers/knowledge.js +108 -0
  36. package/dist/handlers/milestones.d.ts +20 -0
  37. package/dist/handlers/milestones.js +179 -0
  38. package/dist/handlers/organizations.d.ts +36 -0
  39. package/dist/handlers/organizations.js +428 -0
  40. package/dist/handlers/progress.d.ts +14 -0
  41. package/dist/handlers/progress.js +149 -0
  42. package/dist/handlers/project.d.ts +20 -0
  43. package/dist/handlers/project.js +278 -0
  44. package/dist/handlers/requests.d.ts +16 -0
  45. package/dist/handlers/requests.js +131 -0
  46. package/dist/handlers/roles.d.ts +30 -0
  47. package/dist/handlers/roles.js +281 -0
  48. package/dist/handlers/session.d.ts +20 -0
  49. package/dist/handlers/session.js +791 -0
  50. package/dist/handlers/tasks.d.ts +52 -0
  51. package/dist/handlers/tasks.js +1111 -0
  52. package/dist/handlers/tasks.test.d.ts +1 -0
  53. package/dist/handlers/tasks.test.js +431 -0
  54. package/dist/handlers/types.d.ts +94 -0
  55. package/dist/handlers/types.js +1 -0
  56. package/dist/handlers/validation.d.ts +16 -0
  57. package/dist/handlers/validation.js +188 -0
  58. package/dist/index.d.ts +2 -0
  59. package/dist/index.js +2707 -0
  60. package/dist/knowledge.d.ts +6 -0
  61. package/dist/knowledge.js +121 -0
  62. package/dist/tools.d.ts +2 -0
  63. package/dist/tools.js +2498 -0
  64. package/dist/utils.d.ts +149 -0
  65. package/dist/utils.js +317 -0
  66. package/dist/utils.test.d.ts +1 -0
  67. package/dist/utils.test.js +532 -0
  68. package/dist/validators.d.ts +35 -0
  69. package/dist/validators.js +111 -0
  70. package/dist/validators.test.d.ts +1 -0
  71. package/dist/validators.test.js +176 -0
  72. package/package.json +44 -0
  73. package/src/cli.test.ts +442 -0
  74. package/src/cli.ts +439 -0
  75. package/src/handlers/__test-utils__.ts +217 -0
  76. package/src/handlers/blockers.test.ts +390 -0
  77. package/src/handlers/blockers.ts +110 -0
  78. package/src/handlers/bodies-of-work.test.ts +1276 -0
  79. package/src/handlers/bodies-of-work.ts +783 -0
  80. package/src/handlers/cost.test.ts +436 -0
  81. package/src/handlers/cost.ts +322 -0
  82. package/src/handlers/decisions.test.ts +401 -0
  83. package/src/handlers/decisions.ts +86 -0
  84. package/src/handlers/deployment.test.ts +516 -0
  85. package/src/handlers/deployment.ts +1289 -0
  86. package/src/handlers/discovery.test.ts +254 -0
  87. package/src/handlers/discovery.ts +969 -0
  88. package/src/handlers/fallback.test.ts +687 -0
  89. package/src/handlers/fallback.ts +260 -0
  90. package/src/handlers/findings.test.ts +565 -0
  91. package/src/handlers/findings.ts +153 -0
  92. package/src/handlers/ideas.test.ts +753 -0
  93. package/src/handlers/ideas.ts +247 -0
  94. package/src/handlers/index.ts +69 -0
  95. package/src/handlers/milestones.test.ts +584 -0
  96. package/src/handlers/milestones.ts +217 -0
  97. package/src/handlers/organizations.test.ts +997 -0
  98. package/src/handlers/organizations.ts +550 -0
  99. package/src/handlers/progress.test.ts +369 -0
  100. package/src/handlers/progress.ts +188 -0
  101. package/src/handlers/project.test.ts +562 -0
  102. package/src/handlers/project.ts +352 -0
  103. package/src/handlers/requests.test.ts +531 -0
  104. package/src/handlers/requests.ts +150 -0
  105. package/src/handlers/session.test.ts +459 -0
  106. package/src/handlers/session.ts +912 -0
  107. package/src/handlers/tasks.test.ts +602 -0
  108. package/src/handlers/tasks.ts +1393 -0
  109. package/src/handlers/types.ts +88 -0
  110. package/src/handlers/validation.test.ts +880 -0
  111. package/src/handlers/validation.ts +223 -0
  112. package/src/index.ts +3205 -0
  113. package/src/knowledge.ts +132 -0
  114. package/src/tmpclaude-0078-cwd +1 -0
  115. package/src/tmpclaude-0ee1-cwd +1 -0
  116. package/src/tmpclaude-2dd5-cwd +1 -0
  117. package/src/tmpclaude-344c-cwd +1 -0
  118. package/src/tmpclaude-3860-cwd +1 -0
  119. package/src/tmpclaude-4b63-cwd +1 -0
  120. package/src/tmpclaude-5c73-cwd +1 -0
  121. package/src/tmpclaude-5ee3-cwd +1 -0
  122. package/src/tmpclaude-6795-cwd +1 -0
  123. package/src/tmpclaude-709e-cwd +1 -0
  124. package/src/tmpclaude-9839-cwd +1 -0
  125. package/src/tmpclaude-d829-cwd +1 -0
  126. package/src/tmpclaude-e072-cwd +1 -0
  127. package/src/tmpclaude-f6ee-cwd +1 -0
  128. package/src/utils.test.ts +681 -0
  129. package/src/utils.ts +375 -0
  130. package/src/validators.test.ts +223 -0
  131. package/src/validators.ts +122 -0
  132. package/tmpclaude-0439-cwd +1 -0
  133. package/tmpclaude-132f-cwd +1 -0
  134. package/tmpclaude-15bb-cwd +1 -0
  135. package/tmpclaude-165a-cwd +1 -0
  136. package/tmpclaude-1ba9-cwd +1 -0
  137. package/tmpclaude-21a3-cwd +1 -0
  138. package/tmpclaude-2a38-cwd +1 -0
  139. package/tmpclaude-2adf-cwd +1 -0
  140. package/tmpclaude-2f56-cwd +1 -0
  141. package/tmpclaude-3626-cwd +1 -0
  142. package/tmpclaude-3727-cwd +1 -0
  143. package/tmpclaude-40bc-cwd +1 -0
  144. package/tmpclaude-436f-cwd +1 -0
  145. package/tmpclaude-4783-cwd +1 -0
  146. package/tmpclaude-4b6d-cwd +1 -0
  147. package/tmpclaude-4ba4-cwd +1 -0
  148. package/tmpclaude-51e6-cwd +1 -0
  149. package/tmpclaude-5ecf-cwd +1 -0
  150. package/tmpclaude-6f97-cwd +1 -0
  151. package/tmpclaude-7fb2-cwd +1 -0
  152. package/tmpclaude-825c-cwd +1 -0
  153. package/tmpclaude-8baf-cwd +1 -0
  154. package/tmpclaude-8d9f-cwd +1 -0
  155. package/tmpclaude-975c-cwd +1 -0
  156. package/tmpclaude-9983-cwd +1 -0
  157. package/tmpclaude-a045-cwd +1 -0
  158. package/tmpclaude-ac4a-cwd +1 -0
  159. package/tmpclaude-b593-cwd +1 -0
  160. package/tmpclaude-b891-cwd +1 -0
  161. package/tmpclaude-c032-cwd +1 -0
  162. package/tmpclaude-cf43-cwd +1 -0
  163. package/tmpclaude-d040-cwd +1 -0
  164. package/tmpclaude-dcdd-cwd +1 -0
  165. package/tmpclaude-dcee-cwd +1 -0
  166. package/tmpclaude-e16b-cwd +1 -0
  167. package/tmpclaude-ecd2-cwd +1 -0
  168. package/tmpclaude-f48d-cwd +1 -0
  169. package/tsconfig.json +16 -0
  170. package/vitest.config.ts +13 -0
@@ -0,0 +1,281 @@
1
+ /**
2
+ * Role Handlers
3
+ *
4
+ * Manages agent roles for specialized work:
5
+ * - get_role_settings: Get role configuration for a project
6
+ * - update_role_settings: Update role settings
7
+ * - set_session_role: Change the current session's role
8
+ * - get_agents_by_role: Get active agents grouped by role
9
+ */
10
+ import { validateUUID, validateRequired } from '../validators.js';
11
+ // Valid agent roles - must match AgentRole type in types.ts and database enum
12
+ const VALID_ROLES = ['developer', 'validator', 'deployer', 'reviewer', 'maintainer'];
13
+ function isValidRole(role) {
14
+ return VALID_ROLES.includes(role);
15
+ }
16
+ /**
17
+ * Verify the user owns or has access to the project
18
+ * This is needed because MCP server uses service_role which bypasses RLS
19
+ */
20
+ async function verifyProjectAccess(ctx, projectId) {
21
+ const { supabase, auth } = ctx;
22
+ // Check if user owns the project
23
+ const { data: ownedProject } = await supabase
24
+ .from('projects')
25
+ .select('id')
26
+ .eq('id', projectId)
27
+ .eq('user_id', auth.userId)
28
+ .single();
29
+ if (ownedProject)
30
+ return;
31
+ // Check if project is shared with user's organization (for org-scoped keys)
32
+ if (auth.scope === 'organization' && auth.organizationId) {
33
+ const { data: sharedProject } = await supabase
34
+ .from('project_shares')
35
+ .select('project_id')
36
+ .eq('project_id', projectId)
37
+ .eq('organization_id', auth.organizationId)
38
+ .single();
39
+ if (sharedProject)
40
+ return;
41
+ }
42
+ throw new Error('Project not found or access denied');
43
+ }
44
+ /**
45
+ * Get role settings for a project
46
+ */
47
+ export const getRoleSettings = async (args, ctx) => {
48
+ const { project_id } = args;
49
+ const { supabase } = ctx;
50
+ validateRequired(project_id, 'project_id');
51
+ validateUUID(project_id, 'project_id');
52
+ // Verify user has access to this project
53
+ await verifyProjectAccess(ctx, project_id);
54
+ const { data: settings, error } = await supabase
55
+ .from('project_role_settings')
56
+ .select('*')
57
+ .eq('project_id', project_id)
58
+ .order('role');
59
+ if (error) {
60
+ throw new Error(`Failed to get role settings: ${error.message}`);
61
+ }
62
+ // If no settings exist, return defaults
63
+ if (!settings || settings.length === 0) {
64
+ return {
65
+ result: {
66
+ project_id,
67
+ settings: VALID_ROLES.map(role => ({
68
+ role,
69
+ enabled: true,
70
+ display_name: role.charAt(0).toUpperCase() + role.slice(1),
71
+ description: getRoleDescription(role),
72
+ })),
73
+ note: 'Using default settings. Call update_role_settings to customize.',
74
+ },
75
+ };
76
+ }
77
+ return {
78
+ result: {
79
+ project_id,
80
+ settings,
81
+ },
82
+ };
83
+ };
84
+ function getRoleDescription(role) {
85
+ const descriptions = {
86
+ developer: 'General development work, picks up any available task',
87
+ validator: 'Focuses on validating completed tasks',
88
+ deployer: 'Handles deployment coordination and monitoring',
89
+ reviewer: 'Code review and quality checks',
90
+ maintainer: 'Task management, git orchestration, housekeeping',
91
+ };
92
+ return descriptions[role];
93
+ }
94
+ /**
95
+ * Update role settings for a project
96
+ */
97
+ export const updateRoleSettings = async (args, ctx) => {
98
+ const { project_id, role, enabled, display_name, description, priority_filter, fallback_activities, auto_assign_validation, auto_assign_deployment, } = args;
99
+ const { supabase } = ctx;
100
+ validateRequired(project_id, 'project_id');
101
+ validateUUID(project_id, 'project_id');
102
+ validateRequired(role, 'role');
103
+ if (!isValidRole(role)) {
104
+ throw new Error(`Invalid role: ${role}. Valid roles: ${VALID_ROLES.join(', ')}`);
105
+ }
106
+ // Verify user has access to this project
107
+ await verifyProjectAccess(ctx, project_id);
108
+ const updates = {
109
+ updated_at: new Date().toISOString(),
110
+ };
111
+ if (enabled !== undefined)
112
+ updates.enabled = enabled;
113
+ if (display_name !== undefined)
114
+ updates.display_name = display_name;
115
+ if (description !== undefined)
116
+ updates.description = description;
117
+ if (priority_filter !== undefined)
118
+ updates.priority_filter = priority_filter;
119
+ if (fallback_activities !== undefined)
120
+ updates.fallback_activities = fallback_activities;
121
+ if (auto_assign_validation !== undefined)
122
+ updates.auto_assign_validation = auto_assign_validation;
123
+ if (auto_assign_deployment !== undefined)
124
+ updates.auto_assign_deployment = auto_assign_deployment;
125
+ // Upsert the role settings
126
+ const { data, error } = await supabase
127
+ .from('project_role_settings')
128
+ .upsert({
129
+ project_id,
130
+ role,
131
+ ...updates,
132
+ }, {
133
+ onConflict: 'project_id,role',
134
+ })
135
+ .select()
136
+ .single();
137
+ if (error) {
138
+ throw new Error(`Failed to update role settings: ${error.message}`);
139
+ }
140
+ return {
141
+ result: {
142
+ success: true,
143
+ settings: data,
144
+ },
145
+ };
146
+ };
147
+ /**
148
+ * Set the current session's role
149
+ */
150
+ export const setSessionRole = async (args, ctx) => {
151
+ const { role, role_config } = args;
152
+ const { supabase, session, updateSession } = ctx;
153
+ validateRequired(role, 'role');
154
+ if (!isValidRole(role)) {
155
+ throw new Error(`Invalid role: ${role}. Valid roles: ${VALID_ROLES.join(', ')}`);
156
+ }
157
+ const sessionId = session.currentSessionId;
158
+ if (!sessionId) {
159
+ throw new Error('No active session. Call start_work_session first.');
160
+ }
161
+ const updates = {
162
+ role,
163
+ updated_at: new Date().toISOString(),
164
+ };
165
+ // Allow role_config for custom configurations (e.g., maintainer with specific focus areas)
166
+ if (role_config) {
167
+ updates.role_config = role_config;
168
+ }
169
+ const { error } = await supabase
170
+ .from('agent_sessions')
171
+ .update(updates)
172
+ .eq('id', sessionId);
173
+ if (error) {
174
+ throw new Error(`Failed to set role: ${error.message}`);
175
+ }
176
+ // Update session state
177
+ updateSession({ currentRole: role });
178
+ // Get role-specific guidance
179
+ const guidance = getRoleGuidance(role);
180
+ return {
181
+ result: {
182
+ success: true,
183
+ role,
184
+ persona: session.currentPersona,
185
+ guidance,
186
+ },
187
+ };
188
+ };
189
+ function getRoleGuidance(role) {
190
+ const guidance = {
191
+ developer: 'Focus on implementing features and fixing bugs. Use get_next_task to find work.',
192
+ validator: 'Prioritize validation tasks. Use get_tasks_awaiting_validation to find completed tasks to review.',
193
+ deployer: 'Monitor deployment status with check_deployment_status. Handle deployment requests and coordination.',
194
+ reviewer: 'Run code reviews using code_review fallback activity. Check for security and quality issues.',
195
+ maintainer: 'Handle task management, git orchestration. Run performance_audit, dependency_audit when idle.',
196
+ };
197
+ return guidance[role];
198
+ }
199
+ /**
200
+ * Get active agents grouped by role
201
+ */
202
+ export const getAgentsByRole = async (args, ctx) => {
203
+ const { project_id } = args;
204
+ const { supabase } = ctx;
205
+ validateRequired(project_id, 'project_id');
206
+ validateUUID(project_id, 'project_id');
207
+ // Verify user has access to this project
208
+ await verifyProjectAccess(ctx, project_id);
209
+ const { data: agents, error } = await supabase
210
+ .from('agent_sessions')
211
+ .select(`
212
+ id,
213
+ agent_name,
214
+ role,
215
+ status,
216
+ current_task_id,
217
+ last_synced_at,
218
+ role_config
219
+ `)
220
+ .eq('project_id', project_id)
221
+ .neq('status', 'disconnected')
222
+ .gte('last_synced_at', new Date(Date.now() - 5 * 60 * 1000).toISOString());
223
+ if (error) {
224
+ throw new Error(`Failed to get agents: ${error.message}`);
225
+ }
226
+ // Group by role
227
+ const byRole = {};
228
+ for (const agent of agents || []) {
229
+ const role = agent.role || 'developer';
230
+ if (!byRole[role]) {
231
+ byRole[role] = [];
232
+ }
233
+ byRole[role].push(agent);
234
+ }
235
+ // Get current task titles
236
+ const taskIds = (agents || [])
237
+ .map(a => a.current_task_id)
238
+ .filter((id) => !!id);
239
+ let taskTitles = {};
240
+ if (taskIds.length > 0) {
241
+ const { data: tasks } = await supabase
242
+ .from('tasks')
243
+ .select('id, title')
244
+ .in('id', taskIds);
245
+ taskTitles = (tasks || []).reduce((acc, t) => {
246
+ acc[t.id] = t.title;
247
+ return acc;
248
+ }, {});
249
+ }
250
+ // Enrich agents with task titles
251
+ const enrichedByRole = {};
252
+ for (const [role, roleAgents] of Object.entries(byRole)) {
253
+ enrichedByRole[role] = roleAgents.map(agent => ({
254
+ id: agent.id,
255
+ agent_name: agent.agent_name,
256
+ role: agent.role || 'developer',
257
+ status: agent.status,
258
+ current_task: agent.current_task_id
259
+ ? { id: agent.current_task_id, title: taskTitles[agent.current_task_id] || 'Unknown' }
260
+ : null,
261
+ last_synced_at: agent.last_synced_at,
262
+ }));
263
+ }
264
+ return {
265
+ result: {
266
+ project_id,
267
+ total_agents: agents?.length || 0,
268
+ by_role: enrichedByRole,
269
+ available_roles: VALID_ROLES,
270
+ },
271
+ };
272
+ };
273
+ /**
274
+ * Role handlers registry
275
+ */
276
+ export const roleHandlers = {
277
+ get_role_settings: getRoleSettings,
278
+ update_role_settings: updateRoleSettings,
279
+ set_session_role: setSessionRole,
280
+ get_agents_by_role: getAgentsByRole,
281
+ };
@@ -0,0 +1,20 @@
1
+ /**
2
+ * Session Handlers
3
+ *
4
+ * Handles agent session lifecycle:
5
+ * - start_work_session
6
+ * - heartbeat
7
+ * - end_work_session
8
+ * - get_help
9
+ * - get_token_usage
10
+ */
11
+ import type { Handler, HandlerRegistry } from './types.js';
12
+ export declare const startWorkSession: Handler;
13
+ export declare const heartbeat: Handler;
14
+ export declare const endWorkSession: Handler;
15
+ export declare const getHelp: Handler;
16
+ export declare const getTokenUsage: Handler;
17
+ /**
18
+ * Session handlers registry
19
+ */
20
+ export declare const sessionHandlers: HandlerRegistry;