@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,18 @@
1
+ /**
2
+ * Fallback Handlers
3
+ *
4
+ * Handles background activities when idle:
5
+ * - start_fallback_activity
6
+ * - stop_fallback_activity
7
+ * - get_activity_history
8
+ * - get_activity_schedules
9
+ */
10
+ import type { Handler, HandlerRegistry } from './types.js';
11
+ export declare const startFallbackActivity: Handler;
12
+ export declare const stopFallbackActivity: Handler;
13
+ export declare const getActivityHistory: Handler;
14
+ export declare const getActivitySchedules: Handler;
15
+ /**
16
+ * Fallback handlers registry
17
+ */
18
+ export declare const fallbackHandlers: HandlerRegistry;
@@ -0,0 +1,216 @@
1
+ /**
2
+ * Fallback Handlers
3
+ *
4
+ * Handles background activities when idle:
5
+ * - start_fallback_activity
6
+ * - stop_fallback_activity
7
+ * - get_activity_history
8
+ * - get_activity_schedules
9
+ */
10
+ import { validateRequired, validateUUID } from '../validators.js';
11
+ import { FALLBACK_ACTIVITIES } from '../utils.js';
12
+ const VALID_ACTIVITIES = [
13
+ 'feature_ideation',
14
+ 'code_review',
15
+ 'performance_audit',
16
+ 'ux_review',
17
+ 'cost_analysis',
18
+ 'security_review',
19
+ 'test_coverage',
20
+ 'documentation_review',
21
+ 'dependency_audit',
22
+ 'validate_completed_tasks',
23
+ ];
24
+ export const startFallbackActivity = async (args, ctx) => {
25
+ const { project_id, activity } = args;
26
+ validateRequired(project_id, 'project_id');
27
+ validateUUID(project_id, 'project_id');
28
+ validateRequired(activity, 'activity');
29
+ if (!VALID_ACTIVITIES.includes(activity)) {
30
+ throw new Error(`Invalid activity. Must be one of: ${VALID_ACTIVITIES.join(', ')}`);
31
+ }
32
+ const { supabase, session } = ctx;
33
+ const currentSessionId = session.currentSessionId;
34
+ // Update the current session's fallback activity
35
+ const { error: updateError } = await supabase
36
+ .from('agent_sessions')
37
+ .update({
38
+ current_fallback_activity: activity,
39
+ current_task_id: null, // Clear any task when starting fallback
40
+ status: 'active',
41
+ last_synced_at: new Date().toISOString(),
42
+ })
43
+ .eq('id', currentSessionId);
44
+ if (updateError)
45
+ throw updateError;
46
+ // Get the activity details for the response
47
+ const activityInfo = FALLBACK_ACTIVITIES.find((a) => a.activity === activity);
48
+ return {
49
+ result: {
50
+ success: true,
51
+ activity,
52
+ title: activityInfo?.title || activity,
53
+ description: activityInfo?.description || '',
54
+ prompt: activityInfo?.prompt || '',
55
+ message: `Started fallback activity: ${activityInfo?.title || activity}`,
56
+ },
57
+ };
58
+ };
59
+ export const stopFallbackActivity = async (args, ctx) => {
60
+ const { project_id, summary } = args;
61
+ validateRequired(project_id, 'project_id');
62
+ validateUUID(project_id, 'project_id');
63
+ const { supabase, session } = ctx;
64
+ const currentSessionId = session.currentSessionId;
65
+ // Get the current session's fallback activity before clearing it
66
+ const { data: sessionData, error: sessionError } = await supabase
67
+ .from('agent_sessions')
68
+ .select('current_fallback_activity')
69
+ .eq('id', currentSessionId)
70
+ .single();
71
+ if (sessionError)
72
+ throw sessionError;
73
+ const activityType = sessionData?.current_fallback_activity;
74
+ // Log the activity completion to history if there was an active activity
75
+ if (activityType) {
76
+ const completedAt = new Date().toISOString();
77
+ // Insert history record
78
+ await supabase.from('background_activity_history').insert({
79
+ project_id,
80
+ activity_type: activityType,
81
+ completed_at: completedAt,
82
+ completed_by_session_id: currentSessionId,
83
+ summary: summary || null,
84
+ });
85
+ // Update schedule if one exists for this activity
86
+ const { data: schedule } = await supabase
87
+ .from('background_activity_schedules')
88
+ .select('*')
89
+ .eq('project_id', project_id)
90
+ .eq('activity_type', activityType)
91
+ .eq('enabled', true)
92
+ .single();
93
+ if (schedule) {
94
+ let nextRunAt = null;
95
+ let enabled = true;
96
+ // Calculate next run time based on schedule type
97
+ const completedDate = new Date(completedAt);
98
+ switch (schedule.schedule_type) {
99
+ case 'once':
100
+ enabled = false;
101
+ break;
102
+ case 'daily':
103
+ completedDate.setDate(completedDate.getDate() + 1);
104
+ nextRunAt = completedDate.toISOString();
105
+ break;
106
+ case 'weekly':
107
+ completedDate.setDate(completedDate.getDate() + 7);
108
+ nextRunAt = completedDate.toISOString();
109
+ break;
110
+ case 'monthly':
111
+ completedDate.setDate(completedDate.getDate() + 30);
112
+ nextRunAt = completedDate.toISOString();
113
+ break;
114
+ }
115
+ await supabase
116
+ .from('background_activity_schedules')
117
+ .update({ next_run_at: nextRunAt, enabled })
118
+ .eq('id', schedule.id);
119
+ }
120
+ }
121
+ // Clear the current session's fallback activity
122
+ const { error: updateError } = await supabase
123
+ .from('agent_sessions')
124
+ .update({
125
+ current_fallback_activity: null,
126
+ status: 'idle',
127
+ last_synced_at: new Date().toISOString(),
128
+ })
129
+ .eq('id', currentSessionId);
130
+ if (updateError)
131
+ throw updateError;
132
+ return {
133
+ result: {
134
+ success: true,
135
+ message: activityType
136
+ ? `Fallback activity '${activityType}' completed and logged to history`
137
+ : 'Fallback activity stopped',
138
+ },
139
+ };
140
+ };
141
+ export const getActivityHistory = async (args, ctx) => {
142
+ const { project_id, activity_type, limit = 50 } = args;
143
+ validateRequired(project_id, 'project_id');
144
+ validateUUID(project_id, 'project_id');
145
+ const { supabase } = ctx;
146
+ let query = supabase
147
+ .from('background_activity_history')
148
+ .select(`
149
+ id,
150
+ activity_type,
151
+ completed_at,
152
+ completed_by_session_id,
153
+ summary,
154
+ created_at,
155
+ agent_sessions!completed_by_session_id (
156
+ agent_name
157
+ )
158
+ `)
159
+ .eq('project_id', project_id)
160
+ .order('completed_at', { ascending: false })
161
+ .limit(limit);
162
+ if (activity_type) {
163
+ query = query.eq('activity_type', activity_type);
164
+ }
165
+ const { data: history, error } = await query;
166
+ if (error)
167
+ throw error;
168
+ // Also get the most recent completion for each activity type
169
+ const latestByType = {};
170
+ for (const entry of history || []) {
171
+ if (!latestByType[entry.activity_type]) {
172
+ latestByType[entry.activity_type] = entry;
173
+ }
174
+ }
175
+ return {
176
+ result: {
177
+ history: history || [],
178
+ latest_by_type: latestByType,
179
+ count: history?.length || 0,
180
+ },
181
+ };
182
+ };
183
+ export const getActivitySchedules = async (args, ctx) => {
184
+ const { project_id } = args;
185
+ validateRequired(project_id, 'project_id');
186
+ validateUUID(project_id, 'project_id');
187
+ const { supabase } = ctx;
188
+ const { data: schedules, error } = await supabase
189
+ .from('background_activity_schedules')
190
+ .select('*')
191
+ .eq('project_id', project_id)
192
+ .order('activity_type');
193
+ if (error)
194
+ throw error;
195
+ // Identify which activities are "due" (next_run_at < now AND enabled)
196
+ const now = new Date();
197
+ const dueActivities = (schedules || [])
198
+ .filter((s) => s.enabled && s.next_run_at && new Date(s.next_run_at) < now)
199
+ .map((s) => s.activity_type);
200
+ return {
201
+ result: {
202
+ schedules: schedules || [],
203
+ due_activities: dueActivities,
204
+ count: schedules?.length || 0,
205
+ },
206
+ };
207
+ };
208
+ /**
209
+ * Fallback handlers registry
210
+ */
211
+ export const fallbackHandlers = {
212
+ start_fallback_activity: startFallbackActivity,
213
+ stop_fallback_activity: stopFallbackActivity,
214
+ get_activity_history: getActivityHistory,
215
+ get_activity_schedules: getActivitySchedules,
216
+ };
@@ -0,0 +1,18 @@
1
+ /**
2
+ * Findings Handlers
3
+ *
4
+ * Handles audit findings and knowledge base:
5
+ * - add_finding
6
+ * - get_findings
7
+ * - update_finding
8
+ * - delete_finding
9
+ */
10
+ import type { Handler, HandlerRegistry } from './types.js';
11
+ export declare const addFinding: Handler;
12
+ export declare const getFindings: Handler;
13
+ export declare const updateFinding: Handler;
14
+ export declare const deleteFinding: Handler;
15
+ /**
16
+ * Findings handlers registry
17
+ */
18
+ export declare const findingHandlers: HandlerRegistry;
@@ -0,0 +1,110 @@
1
+ /**
2
+ * Findings Handlers
3
+ *
4
+ * Handles audit findings and knowledge base:
5
+ * - add_finding
6
+ * - get_findings
7
+ * - update_finding
8
+ * - delete_finding
9
+ */
10
+ import { validateRequired, validateUUID } from '../validators.js';
11
+ export const addFinding = async (args, ctx) => {
12
+ const { project_id, category, title, description, severity, file_path, line_number, related_task_id } = args;
13
+ validateRequired(project_id, 'project_id');
14
+ validateUUID(project_id, 'project_id');
15
+ validateRequired(title, 'title');
16
+ if (related_task_id)
17
+ validateUUID(related_task_id, 'related_task_id');
18
+ const { supabase, session } = ctx;
19
+ const { data, error } = await supabase
20
+ .from('findings')
21
+ .insert({
22
+ project_id,
23
+ category: category || 'other',
24
+ title,
25
+ description: description || null,
26
+ severity: severity || 'info',
27
+ file_path: file_path || null,
28
+ line_number: line_number || null,
29
+ related_task_id: related_task_id || null,
30
+ created_by: 'agent',
31
+ created_by_session_id: session.currentSessionId,
32
+ })
33
+ .select('id')
34
+ .single();
35
+ if (error)
36
+ throw new Error(`Failed to add finding: ${error.message}`);
37
+ return { result: { success: true, finding_id: data.id, title } };
38
+ };
39
+ export const getFindings = async (args, ctx) => {
40
+ const { project_id, category, severity, status, limit } = args;
41
+ validateRequired(project_id, 'project_id');
42
+ validateUUID(project_id, 'project_id');
43
+ const { supabase } = ctx;
44
+ let query = supabase
45
+ .from('findings')
46
+ .select('id, title, category, severity, status, file_path, created_at')
47
+ .eq('project_id', project_id)
48
+ .order('created_at', { ascending: false })
49
+ .limit(limit || 50);
50
+ if (category)
51
+ query = query.eq('category', category);
52
+ if (severity)
53
+ query = query.eq('severity', severity);
54
+ if (status)
55
+ query = query.eq('status', status);
56
+ const { data, error } = await query;
57
+ if (error)
58
+ throw new Error(`Failed to get findings: ${error.message}`);
59
+ return { result: { findings: data } };
60
+ };
61
+ export const updateFinding = async (args, ctx) => {
62
+ const { finding_id, status, resolution_note, title, description, severity } = args;
63
+ validateRequired(finding_id, 'finding_id');
64
+ validateUUID(finding_id, 'finding_id');
65
+ const { supabase, session } = ctx;
66
+ const updates = { updated_at: new Date().toISOString() };
67
+ if (title)
68
+ updates.title = title;
69
+ if (description)
70
+ updates.description = description;
71
+ if (severity)
72
+ updates.severity = severity;
73
+ if (status) {
74
+ updates.status = status;
75
+ if (status === 'addressed' || status === 'dismissed' || status === 'wontfix') {
76
+ updates.addressed_at = new Date().toISOString();
77
+ updates.addressed_by_session_id = session.currentSessionId;
78
+ }
79
+ }
80
+ if (resolution_note)
81
+ updates.resolution_note = resolution_note;
82
+ const { error } = await supabase
83
+ .from('findings')
84
+ .update(updates)
85
+ .eq('id', finding_id);
86
+ if (error)
87
+ throw new Error(`Failed to update finding: ${error.message}`);
88
+ return { result: { success: true, finding_id } };
89
+ };
90
+ export const deleteFinding = async (args, ctx) => {
91
+ const { finding_id } = args;
92
+ validateRequired(finding_id, 'finding_id');
93
+ validateUUID(finding_id, 'finding_id');
94
+ const { error } = await ctx.supabase
95
+ .from('findings')
96
+ .delete()
97
+ .eq('id', finding_id);
98
+ if (error)
99
+ throw new Error(`Failed to delete finding: ${error.message}`);
100
+ return { result: { success: true } };
101
+ };
102
+ /**
103
+ * Findings handlers registry
104
+ */
105
+ export const findingHandlers = {
106
+ add_finding: addFinding,
107
+ get_findings: getFindings,
108
+ update_finding: updateFinding,
109
+ delete_finding: deleteFinding,
110
+ };
@@ -0,0 +1,22 @@
1
+ /**
2
+ * Git Issues Handlers
3
+ *
4
+ * Handles git-related issue tracking:
5
+ * - get_git_issues
6
+ * - create_git_issue
7
+ * - resolve_git_issue
8
+ * - dismiss_git_issue
9
+ */
10
+ import type { Handler, HandlerRegistry } from './types.js';
11
+ export declare const getGitIssues: Handler;
12
+ export declare const createGitIssue: Handler;
13
+ export declare const resolveGitIssue: Handler;
14
+ export declare const dismissGitIssue: Handler;
15
+ /**
16
+ * Auto-resolve git issues for a branch when it becomes mergeable
17
+ */
18
+ export declare function autoResolveGitIssuesForBranch(supabase: import('@supabase/supabase-js').SupabaseClient, projectId: string, branchName: string, sessionId: string | null): Promise<number>;
19
+ /**
20
+ * Git Issues handlers registry
21
+ */
22
+ export declare const gitIssuesHandlers: HandlerRegistry;
@@ -0,0 +1,247 @@
1
+ /**
2
+ * Git Issues Handlers
3
+ *
4
+ * Handles git-related issue tracking:
5
+ * - get_git_issues
6
+ * - create_git_issue
7
+ * - resolve_git_issue
8
+ * - dismiss_git_issue
9
+ */
10
+ import { validateRequired, validateUUID } from '../validators.js';
11
+ export const getGitIssues = async (args, ctx) => {
12
+ const { project_id, status = 'open', include_resolved = false } = args;
13
+ validateRequired(project_id, 'project_id');
14
+ validateUUID(project_id, 'project_id');
15
+ const { supabase } = ctx;
16
+ let query = supabase
17
+ .from('git_issues')
18
+ .select(`
19
+ id,
20
+ task_id,
21
+ issue_type,
22
+ severity,
23
+ branch_name,
24
+ pr_number,
25
+ pr_url,
26
+ target_branch,
27
+ conflicting_files,
28
+ error_message,
29
+ status,
30
+ created_at,
31
+ resolved_at,
32
+ auto_resolved,
33
+ resolution_note
34
+ `)
35
+ .eq('project_id', project_id)
36
+ .order('created_at', { ascending: false });
37
+ if (status !== 'all' && !include_resolved) {
38
+ query = query.eq('status', status);
39
+ }
40
+ const { data: issues, error } = await query.limit(50);
41
+ if (error)
42
+ throw new Error(`Failed to fetch git issues: ${error.message}`);
43
+ // Group by severity for summary
44
+ const summary = {
45
+ critical: 0,
46
+ high: 0,
47
+ medium: 0,
48
+ low: 0,
49
+ };
50
+ const openIssues = (issues || []).filter(i => i.status === 'open');
51
+ openIssues.forEach(issue => {
52
+ const sev = issue.severity;
53
+ if (sev in summary)
54
+ summary[sev]++;
55
+ });
56
+ return {
57
+ result: {
58
+ issues: issues || [],
59
+ open_count: openIssues.length,
60
+ severity_summary: summary,
61
+ has_critical: summary.critical > 0,
62
+ has_blocking: summary.critical > 0 || summary.high > 0,
63
+ },
64
+ };
65
+ };
66
+ export const createGitIssue = async (args, ctx) => {
67
+ const { project_id, task_id, issue_type, severity = 'medium', branch_name, pr_number, pr_url, target_branch, conflicting_files, error_message, } = args;
68
+ validateRequired(project_id, 'project_id');
69
+ validateUUID(project_id, 'project_id');
70
+ validateRequired(issue_type, 'issue_type');
71
+ const { supabase, session } = ctx;
72
+ // Check if similar issue already exists (avoid duplicates)
73
+ if (branch_name || pr_number) {
74
+ const { data: existing } = await supabase
75
+ .from('git_issues')
76
+ .select('id')
77
+ .eq('project_id', project_id)
78
+ .eq('status', 'open')
79
+ .eq('issue_type', issue_type)
80
+ .or(`branch_name.eq.${branch_name},pr_number.eq.${pr_number}`)
81
+ .limit(1)
82
+ .maybeSingle();
83
+ if (existing) {
84
+ return {
85
+ result: {
86
+ success: false,
87
+ already_exists: true,
88
+ existing_issue_id: existing.id,
89
+ message: 'A similar git issue already exists for this branch/PR',
90
+ },
91
+ };
92
+ }
93
+ }
94
+ const { data: issue, error } = await supabase
95
+ .from('git_issues')
96
+ .insert({
97
+ project_id,
98
+ task_id: task_id || null,
99
+ issue_type,
100
+ severity,
101
+ branch_name: branch_name || null,
102
+ pr_number: pr_number || null,
103
+ pr_url: pr_url || null,
104
+ target_branch: target_branch || null,
105
+ conflicting_files: conflicting_files || [],
106
+ error_message: error_message || null,
107
+ created_by: 'agent',
108
+ created_by_session_id: session.currentSessionId,
109
+ })
110
+ .select('id, issue_type, severity, branch_name, pr_number')
111
+ .single();
112
+ if (error)
113
+ throw new Error(`Failed to create git issue: ${error.message}`);
114
+ // Log progress
115
+ await supabase.from('progress_logs').insert({
116
+ project_id,
117
+ task_id: task_id || null,
118
+ summary: `Git issue created: ${issue_type} on ${branch_name || `PR #${pr_number}`}`,
119
+ details: error_message || null,
120
+ created_by: 'agent',
121
+ created_by_session_id: session.currentSessionId,
122
+ });
123
+ return {
124
+ result: {
125
+ success: true,
126
+ issue_id: issue.id,
127
+ issue_type: issue.issue_type,
128
+ severity: issue.severity,
129
+ branch: issue.branch_name,
130
+ pr_number: issue.pr_number,
131
+ },
132
+ };
133
+ };
134
+ export const resolveGitIssue = async (args, ctx) => {
135
+ const { issue_id, resolution_note, auto_resolved = false } = args;
136
+ validateRequired(issue_id, 'issue_id');
137
+ validateUUID(issue_id, 'issue_id');
138
+ const { supabase, session } = ctx;
139
+ // Get the issue first
140
+ const { data: issue, error: fetchError } = await supabase
141
+ .from('git_issues')
142
+ .select('id, project_id, task_id, issue_type, branch_name, pr_number, status')
143
+ .eq('id', issue_id)
144
+ .single();
145
+ if (fetchError || !issue)
146
+ throw new Error('Git issue not found');
147
+ if (issue.status !== 'open') {
148
+ return {
149
+ result: {
150
+ success: false,
151
+ error: `Issue is already ${issue.status}`,
152
+ },
153
+ };
154
+ }
155
+ const { error: updateError } = await supabase
156
+ .from('git_issues')
157
+ .update({
158
+ status: 'resolved',
159
+ resolved_at: new Date().toISOString(),
160
+ resolved_by_session_id: session.currentSessionId,
161
+ auto_resolved,
162
+ resolution_note: resolution_note || null,
163
+ })
164
+ .eq('id', issue_id);
165
+ if (updateError)
166
+ throw new Error(`Failed to resolve git issue: ${updateError.message}`);
167
+ // Log progress
168
+ await supabase.from('progress_logs').insert({
169
+ project_id: issue.project_id,
170
+ task_id: issue.task_id,
171
+ summary: `Git issue resolved: ${issue.issue_type} on ${issue.branch_name || `PR #${issue.pr_number}`}${auto_resolved ? ' (auto)' : ''}`,
172
+ details: resolution_note || null,
173
+ created_by: 'agent',
174
+ created_by_session_id: session.currentSessionId,
175
+ });
176
+ return {
177
+ result: {
178
+ success: true,
179
+ resolved_issue_id: issue_id,
180
+ auto_resolved,
181
+ },
182
+ };
183
+ };
184
+ export const dismissGitIssue = async (args, ctx) => {
185
+ const { issue_id, reason } = args;
186
+ validateRequired(issue_id, 'issue_id');
187
+ validateUUID(issue_id, 'issue_id');
188
+ const { supabase, session } = ctx;
189
+ const { error } = await supabase
190
+ .from('git_issues')
191
+ .update({
192
+ status: 'dismissed',
193
+ resolved_at: new Date().toISOString(),
194
+ resolved_by_session_id: session.currentSessionId,
195
+ resolution_note: reason || 'Dismissed',
196
+ })
197
+ .eq('id', issue_id);
198
+ if (error)
199
+ throw new Error(`Failed to dismiss git issue: ${error.message}`);
200
+ return {
201
+ result: {
202
+ success: true,
203
+ dismissed_issue_id: issue_id,
204
+ },
205
+ };
206
+ };
207
+ /**
208
+ * Auto-resolve git issues for a branch when it becomes mergeable
209
+ */
210
+ export async function autoResolveGitIssuesForBranch(supabase, projectId, branchName, sessionId) {
211
+ const { data: issues } = await supabase
212
+ .from('git_issues')
213
+ .select('id')
214
+ .eq('project_id', projectId)
215
+ .eq('branch_name', branchName)
216
+ .eq('status', 'open')
217
+ .in('issue_type', ['merge_conflict', 'rebase_needed']);
218
+ if (!issues || issues.length === 0)
219
+ return 0;
220
+ const { error } = await supabase
221
+ .from('git_issues')
222
+ .update({
223
+ status: 'resolved',
224
+ resolved_at: new Date().toISOString(),
225
+ resolved_by_session_id: sessionId,
226
+ auto_resolved: true,
227
+ resolution_note: 'Auto-resolved: branch is now mergeable',
228
+ })
229
+ .eq('project_id', projectId)
230
+ .eq('branch_name', branchName)
231
+ .eq('status', 'open')
232
+ .in('issue_type', ['merge_conflict', 'rebase_needed']);
233
+ if (error) {
234
+ console.error('Failed to auto-resolve git issues:', error);
235
+ return 0;
236
+ }
237
+ return issues.length;
238
+ }
239
+ /**
240
+ * Git Issues handlers registry
241
+ */
242
+ export const gitIssuesHandlers = {
243
+ get_git_issues: getGitIssues,
244
+ create_git_issue: createGitIssue,
245
+ resolve_git_issue: resolveGitIssue,
246
+ dismiss_git_issue: dismissGitIssue,
247
+ };
@@ -0,0 +1,19 @@
1
+ /**
2
+ * Ideas Handlers
3
+ *
4
+ * Handles feature ideas tracking:
5
+ * - add_idea
6
+ * - update_idea
7
+ * - get_ideas
8
+ * - delete_idea
9
+ */
10
+ import type { Handler, HandlerRegistry } from './types.js';
11
+ export declare const addIdea: Handler;
12
+ export declare const updateIdea: Handler;
13
+ export declare const getIdeas: Handler;
14
+ export declare const deleteIdea: Handler;
15
+ export declare const convertIdeaToTask: Handler;
16
+ /**
17
+ * Ideas handlers registry
18
+ */
19
+ export declare const ideaHandlers: HandlerRegistry;