@vibescope/mcp-server 0.2.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 (65) hide show
  1. package/dist/api-client.d.ts +64 -1
  2. package/dist/api-client.js +34 -3
  3. package/dist/handlers/bodies-of-work.js +82 -49
  4. package/dist/handlers/cost.js +62 -54
  5. package/dist/handlers/decisions.js +29 -16
  6. package/dist/handlers/deployment.js +112 -106
  7. package/dist/handlers/discovery.js +35 -5
  8. package/dist/handlers/fallback.js +24 -19
  9. package/dist/handlers/file-checkouts.d.ts +18 -0
  10. package/dist/handlers/file-checkouts.js +101 -0
  11. package/dist/handlers/findings.d.ts +6 -0
  12. package/dist/handlers/findings.js +85 -30
  13. package/dist/handlers/git-issues.js +36 -32
  14. package/dist/handlers/ideas.js +44 -26
  15. package/dist/handlers/index.d.ts +2 -0
  16. package/dist/handlers/index.js +6 -0
  17. package/dist/handlers/milestones.js +34 -27
  18. package/dist/handlers/organizations.js +86 -78
  19. package/dist/handlers/progress.js +22 -11
  20. package/dist/handlers/project.js +62 -22
  21. package/dist/handlers/requests.js +15 -11
  22. package/dist/handlers/roles.d.ts +18 -0
  23. package/dist/handlers/roles.js +130 -0
  24. package/dist/handlers/session.js +30 -8
  25. package/dist/handlers/sprints.js +76 -64
  26. package/dist/handlers/tasks.js +113 -73
  27. package/dist/handlers/validation.js +18 -14
  28. package/dist/tools.js +387 -0
  29. package/package.json +1 -1
  30. package/src/api-client.ts +89 -6
  31. package/src/handlers/__test-setup__.ts +7 -0
  32. package/src/handlers/bodies-of-work.ts +101 -101
  33. package/src/handlers/cost.test.ts +34 -44
  34. package/src/handlers/cost.ts +77 -92
  35. package/src/handlers/decisions.test.ts +3 -2
  36. package/src/handlers/decisions.ts +32 -27
  37. package/src/handlers/deployment.ts +142 -190
  38. package/src/handlers/discovery.test.ts +4 -5
  39. package/src/handlers/discovery.ts +37 -6
  40. package/src/handlers/fallback.ts +31 -29
  41. package/src/handlers/file-checkouts.test.ts +477 -0
  42. package/src/handlers/file-checkouts.ts +127 -0
  43. package/src/handlers/findings.test.ts +145 -0
  44. package/src/handlers/findings.ts +101 -64
  45. package/src/handlers/git-issues.ts +40 -80
  46. package/src/handlers/ideas.ts +56 -54
  47. package/src/handlers/index.ts +6 -0
  48. package/src/handlers/milestones.test.ts +1 -1
  49. package/src/handlers/milestones.ts +47 -45
  50. package/src/handlers/organizations.ts +104 -129
  51. package/src/handlers/progress.ts +24 -22
  52. package/src/handlers/project.ts +89 -57
  53. package/src/handlers/requests.ts +18 -14
  54. package/src/handlers/roles.test.ts +303 -0
  55. package/src/handlers/roles.ts +208 -0
  56. package/src/handlers/session.ts +39 -17
  57. package/src/handlers/sprints.ts +96 -129
  58. package/src/handlers/tasks.ts +144 -138
  59. package/src/handlers/validation.test.ts +1 -1
  60. package/src/handlers/validation.ts +20 -22
  61. package/src/tools.ts +387 -0
  62. package/dist/config/tool-categories.d.ts +0 -31
  63. package/dist/config/tool-categories.js +0 -253
  64. package/dist/knowledge.d.ts +0 -6
  65. package/dist/knowledge.js +0 -218
@@ -12,22 +12,55 @@
12
12
  */
13
13
 
14
14
  import type { Handler, HandlerRegistry } from './types.js';
15
- import { validateRequired, validateUUID, validatePriority, validateEstimatedMinutes } from '../validators.js';
15
+ import {
16
+ parseArgs,
17
+ uuidValidator,
18
+ priorityValidator,
19
+ minutesValidator,
20
+ createEnumValidator,
21
+ } from '../validators.js';
16
22
  import { getApiClient } from '../api-client.js';
17
23
 
18
- type IdeaStatus = 'raw' | 'exploring' | 'planned' | 'in_development' | 'shipped';
24
+ const VALID_IDEA_STATUSES = ['raw', 'exploring', 'planned', 'in_development', 'shipped'] as const;
25
+ type IdeaStatus = typeof VALID_IDEA_STATUSES[number];
19
26
 
20
- export const addIdea: Handler = async (args, ctx) => {
21
- const { project_id, title, description, status } = args as {
22
- project_id: string;
23
- title: string;
24
- description?: string;
25
- status?: IdeaStatus;
26
- };
27
+ // Argument schemas for type-safe parsing
28
+ const addIdeaSchema = {
29
+ project_id: { type: 'string' as const, required: true as const, validate: uuidValidator },
30
+ title: { type: 'string' as const, required: true as const },
31
+ description: { type: 'string' as const },
32
+ status: { type: 'string' as const, validate: createEnumValidator(VALID_IDEA_STATUSES) },
33
+ };
34
+
35
+ const updateIdeaSchema = {
36
+ idea_id: { type: 'string' as const, required: true as const, validate: uuidValidator },
37
+ title: { type: 'string' as const },
38
+ description: { type: 'string' as const },
39
+ status: { type: 'string' as const, validate: createEnumValidator(VALID_IDEA_STATUSES) },
40
+ doc_url: { type: 'string' as const },
41
+ };
27
42
 
28
- validateRequired(project_id, 'project_id');
29
- validateUUID(project_id, 'project_id');
30
- validateRequired(title, 'title');
43
+ const getIdeasSchema = {
44
+ project_id: { type: 'string' as const, required: true as const, validate: uuidValidator },
45
+ status: { type: 'string' as const, validate: createEnumValidator(VALID_IDEA_STATUSES) },
46
+ limit: { type: 'number' as const, default: 50 },
47
+ offset: { type: 'number' as const, default: 0 },
48
+ search_query: { type: 'string' as const },
49
+ };
50
+
51
+ const deleteIdeaSchema = {
52
+ idea_id: { type: 'string' as const, required: true as const, validate: uuidValidator },
53
+ };
54
+
55
+ const convertIdeaToTaskSchema = {
56
+ idea_id: { type: 'string' as const, required: true as const, validate: uuidValidator },
57
+ priority: { type: 'number' as const, default: 3, validate: priorityValidator },
58
+ estimated_minutes: { type: 'number' as const, validate: minutesValidator },
59
+ update_status: { type: 'boolean' as const, default: true },
60
+ };
61
+
62
+ export const addIdea: Handler = async (args, ctx) => {
63
+ const { project_id, title, description, status } = parseArgs(args, addIdeaSchema);
31
64
 
32
65
  const { session } = ctx;
33
66
  const apiClient = getApiClient();
@@ -35,7 +68,7 @@ export const addIdea: Handler = async (args, ctx) => {
35
68
  const response = await apiClient.addIdea(project_id, {
36
69
  title,
37
70
  description,
38
- status
71
+ status: status as IdeaStatus | undefined
39
72
  }, session.currentSessionId || undefined);
40
73
 
41
74
  if (!response.ok) {
@@ -45,24 +78,15 @@ export const addIdea: Handler = async (args, ctx) => {
45
78
  return { result: { success: true, idea_id: response.data?.idea_id, title } };
46
79
  };
47
80
 
48
- export const updateIdea: Handler = async (args, ctx) => {
49
- const { idea_id, title, description, status, doc_url } = args as {
50
- idea_id: string;
51
- title?: string;
52
- description?: string;
53
- status?: IdeaStatus;
54
- doc_url?: string;
55
- };
56
-
57
- validateRequired(idea_id, 'idea_id');
58
- validateUUID(idea_id, 'idea_id');
81
+ export const updateIdea: Handler = async (args, _ctx) => {
82
+ const { idea_id, title, description, status, doc_url } = parseArgs(args, updateIdeaSchema);
59
83
 
60
84
  const apiClient = getApiClient();
61
85
 
62
86
  const response = await apiClient.updateIdea(idea_id, {
63
87
  title,
64
88
  description,
65
- status,
89
+ status: status as IdeaStatus | undefined,
66
90
  doc_url
67
91
  });
68
92
 
@@ -73,22 +97,13 @@ export const updateIdea: Handler = async (args, ctx) => {
73
97
  return { result: { success: true, idea_id } };
74
98
  };
75
99
 
76
- export const getIdeas: Handler = async (args, ctx) => {
77
- const { project_id, status, limit = 50, offset = 0, search_query } = args as {
78
- project_id: string;
79
- status?: IdeaStatus;
80
- limit?: number;
81
- offset?: number;
82
- search_query?: string;
83
- };
84
-
85
- validateRequired(project_id, 'project_id');
86
- validateUUID(project_id, 'project_id');
100
+ export const getIdeas: Handler = async (args, _ctx) => {
101
+ const { project_id, status, limit, offset, search_query } = parseArgs(args, getIdeasSchema);
87
102
 
88
103
  const apiClient = getApiClient();
89
104
 
90
105
  const response = await apiClient.getIdeas(project_id, {
91
- status,
106
+ status: status as IdeaStatus | undefined,
92
107
  limit,
93
108
  offset,
94
109
  search_query
@@ -105,11 +120,8 @@ export const getIdeas: Handler = async (args, ctx) => {
105
120
  };
106
121
  };
107
122
 
108
- export const deleteIdea: Handler = async (args, ctx) => {
109
- const { idea_id } = args as { idea_id: string };
110
-
111
- validateRequired(idea_id, 'idea_id');
112
- validateUUID(idea_id, 'idea_id');
123
+ export const deleteIdea: Handler = async (args, _ctx) => {
124
+ const { idea_id } = parseArgs(args, deleteIdeaSchema);
113
125
 
114
126
  const apiClient = getApiClient();
115
127
 
@@ -122,18 +134,8 @@ export const deleteIdea: Handler = async (args, ctx) => {
122
134
  return { result: { success: true } };
123
135
  };
124
136
 
125
- export const convertIdeaToTask: Handler = async (args, ctx) => {
126
- const { idea_id, priority = 3, estimated_minutes, update_status = true } = args as {
127
- idea_id: string;
128
- priority?: number;
129
- estimated_minutes?: number;
130
- update_status?: boolean;
131
- };
132
-
133
- validateRequired(idea_id, 'idea_id');
134
- validateUUID(idea_id, 'idea_id');
135
- validatePriority(priority);
136
- validateEstimatedMinutes(estimated_minutes);
137
+ export const convertIdeaToTask: Handler = async (args, _ctx) => {
138
+ const { idea_id, priority, estimated_minutes, update_status } = parseArgs(args, convertIdeaToTaskSchema);
137
139
 
138
140
  const apiClient = getApiClient();
139
141
 
@@ -25,6 +25,8 @@ export * from './organizations.js';
25
25
  export * from './cost.js';
26
26
  export * from './git-issues.js';
27
27
  export * from './sprints.js';
28
+ export * from './file-checkouts.js';
29
+ export * from './roles.js';
28
30
 
29
31
  import type { HandlerRegistry } from './types.js';
30
32
  import { milestoneHandlers } from './milestones.js';
@@ -46,6 +48,8 @@ import { organizationHandlers } from './organizations.js';
46
48
  import { costHandlers } from './cost.js';
47
49
  import { gitIssueHandlers } from './git-issues.js';
48
50
  import { sprintHandlers } from './sprints.js';
51
+ import { fileCheckoutHandlers } from './file-checkouts.js';
52
+ import { roleHandlers } from './roles.js';
49
53
 
50
54
  /**
51
55
  * Build the complete handler registry from all modules
@@ -71,5 +75,7 @@ export function buildHandlerRegistry(): HandlerRegistry {
71
75
  ...costHandlers,
72
76
  ...gitIssueHandlers,
73
77
  ...sprintHandlers,
78
+ ...fileCheckoutHandlers,
79
+ ...roleHandlers,
74
80
  };
75
81
  }
@@ -143,7 +143,7 @@ describe('updateMilestone', () => {
143
143
  milestone_id: '123e4567-e89b-12d3-a456-426614174000',
144
144
  status: 'invalid_status',
145
145
  }, ctx)
146
- ).rejects.toThrow('status must be pending, in_progress, or completed');
146
+ ).rejects.toThrow('Invalid status: "invalid_status"');
147
147
  });
148
148
 
149
149
  it('should update title successfully', async () => {
@@ -12,20 +12,47 @@
12
12
  */
13
13
 
14
14
  import type { Handler, HandlerRegistry } from './types.js';
15
- import { ValidationError, validateRequired, validateUUID } from '../validators.js';
15
+ import {
16
+ parseArgs,
17
+ uuidValidator,
18
+ createEnumValidator,
19
+ ValidationError,
20
+ } from '../validators.js';
16
21
  import { getApiClient } from '../api-client.js';
17
22
 
18
- export const addMilestone: Handler = async (args, ctx) => {
19
- const { task_id, title, description, order_index } = args as {
20
- task_id: string;
21
- title: string;
22
- description?: string;
23
- order_index?: number;
24
- };
23
+ const VALID_MILESTONE_STATUSES = ['pending', 'in_progress', 'completed'] as const;
24
+ type MilestoneStatus = typeof VALID_MILESTONE_STATUSES[number];
25
+
26
+ // Argument schemas for type-safe parsing
27
+ const addMilestoneSchema = {
28
+ task_id: { type: 'string' as const, required: true as const, validate: uuidValidator },
29
+ title: { type: 'string' as const, required: true as const },
30
+ description: { type: 'string' as const },
31
+ order_index: { type: 'number' as const },
32
+ };
33
+
34
+ const updateMilestoneSchema = {
35
+ milestone_id: { type: 'string' as const, required: true as const, validate: uuidValidator },
36
+ title: { type: 'string' as const },
37
+ description: { type: 'string' as const },
38
+ status: { type: 'string' as const, validate: createEnumValidator(VALID_MILESTONE_STATUSES) },
39
+ order_index: { type: 'number' as const },
40
+ };
41
+
42
+ const completeMilestoneSchema = {
43
+ milestone_id: { type: 'string' as const, required: true as const, validate: uuidValidator },
44
+ };
45
+
46
+ const deleteMilestoneSchema = {
47
+ milestone_id: { type: 'string' as const, required: true as const, validate: uuidValidator },
48
+ };
25
49
 
26
- validateRequired(task_id, 'task_id');
27
- validateUUID(task_id, 'task_id');
28
- validateRequired(title, 'title');
50
+ const getMilestonesSchema = {
51
+ task_id: { type: 'string' as const, required: true as const, validate: uuidValidator },
52
+ };
53
+
54
+ export const addMilestone: Handler = async (args, ctx) => {
55
+ const { task_id, title, description, order_index } = parseArgs(args, addMilestoneSchema);
29
56
 
30
57
  const { session } = ctx;
31
58
  const apiClient = getApiClient();
@@ -48,24 +75,8 @@ export const addMilestone: Handler = async (args, ctx) => {
48
75
  };
49
76
  };
50
77
 
51
- export const updateMilestone: Handler = async (args, ctx) => {
52
- const { milestone_id, title, description, status, order_index } = args as {
53
- milestone_id: string;
54
- title?: string;
55
- description?: string;
56
- status?: string;
57
- order_index?: number;
58
- };
59
-
60
- validateRequired(milestone_id, 'milestone_id');
61
- validateUUID(milestone_id, 'milestone_id');
62
-
63
- // Validate status if provided
64
- if (status !== undefined) {
65
- if (!['pending', 'in_progress', 'completed'].includes(status)) {
66
- throw new ValidationError('status must be pending, in_progress, or completed');
67
- }
68
- }
78
+ export const updateMilestone: Handler = async (args, _ctx) => {
79
+ const { milestone_id, title, description, status, order_index } = parseArgs(args, updateMilestoneSchema);
69
80
 
70
81
  // Check that at least one field is provided
71
82
  if (title === undefined && description === undefined && status === undefined && order_index === undefined) {
@@ -77,7 +88,7 @@ export const updateMilestone: Handler = async (args, ctx) => {
77
88
  const response = await apiClient.updateMilestone(milestone_id, {
78
89
  title,
79
90
  description,
80
- status: status as 'pending' | 'in_progress' | 'completed' | undefined,
91
+ status: status as MilestoneStatus | undefined,
81
92
  order_index
82
93
  });
83
94
 
@@ -93,11 +104,8 @@ export const updateMilestone: Handler = async (args, ctx) => {
93
104
  };
94
105
  };
95
106
 
96
- export const completeMilestone: Handler = async (args, ctx) => {
97
- const { milestone_id } = args as { milestone_id: string };
98
-
99
- validateRequired(milestone_id, 'milestone_id');
100
- validateUUID(milestone_id, 'milestone_id');
107
+ export const completeMilestone: Handler = async (args, _ctx) => {
108
+ const { milestone_id } = parseArgs(args, completeMilestoneSchema);
101
109
 
102
110
  const apiClient = getApiClient();
103
111
 
@@ -115,11 +123,8 @@ export const completeMilestone: Handler = async (args, ctx) => {
115
123
  };
116
124
  };
117
125
 
118
- export const deleteMilestone: Handler = async (args, ctx) => {
119
- const { milestone_id } = args as { milestone_id: string };
120
-
121
- validateRequired(milestone_id, 'milestone_id');
122
- validateUUID(milestone_id, 'milestone_id');
126
+ export const deleteMilestone: Handler = async (args, _ctx) => {
127
+ const { milestone_id } = parseArgs(args, deleteMilestoneSchema);
123
128
 
124
129
  const apiClient = getApiClient();
125
130
 
@@ -137,11 +142,8 @@ export const deleteMilestone: Handler = async (args, ctx) => {
137
142
  };
138
143
  };
139
144
 
140
- export const getMilestones: Handler = async (args, ctx) => {
141
- const { task_id } = args as { task_id: string };
142
-
143
- validateRequired(task_id, 'task_id');
144
- validateUUID(task_id, 'task_id');
145
+ export const getMilestones: Handler = async (args, _ctx) => {
146
+ const { task_id } = parseArgs(args, getMilestonesSchema);
145
147
 
146
148
  const apiClient = getApiClient();
147
149