@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
@@ -18,16 +18,105 @@
18
18
 
19
19
  import type { Handler, HandlerRegistry } from './types.js';
20
20
  import {
21
- validateRequired,
22
- validateUUID,
23
- validateTaskStatus,
24
- validatePriority,
25
- validateProgressPercentage,
26
- validateEstimatedMinutes,
21
+ parseArgs,
22
+ uuidValidator,
23
+ taskStatusValidator,
24
+ priorityValidator,
25
+ progressValidator,
26
+ minutesValidator,
27
+ createEnumValidator,
27
28
  ValidationError,
28
29
  } from '../validators.js';
29
30
  import { getApiClient } from '../api-client.js';
30
31
 
32
+ // Valid task types
33
+ const VALID_TASK_TYPES = [
34
+ 'frontend', 'backend', 'database', 'feature', 'bugfix',
35
+ 'design', 'mcp', 'testing', 'docs', 'infra', 'other'
36
+ ] as const;
37
+
38
+ // ============================================================================
39
+ // Argument Schemas
40
+ // ============================================================================
41
+
42
+ const getTasksSchema = {
43
+ project_id: { type: 'string' as const, required: true as const, validate: uuidValidator },
44
+ status: { type: 'string' as const, validate: taskStatusValidator },
45
+ limit: { type: 'number' as const, default: 50 },
46
+ offset: { type: 'number' as const, default: 0 },
47
+ search_query: { type: 'string' as const },
48
+ include_subtasks: { type: 'boolean' as const, default: false },
49
+ include_metadata: { type: 'boolean' as const, default: false },
50
+ };
51
+
52
+ const getNextTaskSchema = {
53
+ project_id: { type: 'string' as const, required: true as const, validate: uuidValidator },
54
+ };
55
+
56
+ const addTaskSchema = {
57
+ project_id: { type: 'string' as const, required: true as const, validate: uuidValidator },
58
+ title: { type: 'string' as const, required: true as const },
59
+ description: { type: 'string' as const },
60
+ priority: { type: 'number' as const, default: 3, validate: priorityValidator },
61
+ estimated_minutes: { type: 'number' as const, validate: minutesValidator },
62
+ blocking: { type: 'boolean' as const, default: false },
63
+ task_type: { type: 'string' as const, validate: createEnumValidator(VALID_TASK_TYPES) },
64
+ };
65
+
66
+ const updateTaskSchema = {
67
+ task_id: { type: 'string' as const, required: true as const, validate: uuidValidator },
68
+ title: { type: 'string' as const },
69
+ description: { type: 'string' as const },
70
+ priority: { type: 'number' as const, validate: priorityValidator },
71
+ status: { type: 'string' as const, validate: taskStatusValidator },
72
+ progress_percentage: { type: 'number' as const, validate: progressValidator },
73
+ progress_note: { type: 'string' as const },
74
+ estimated_minutes: { type: 'number' as const, validate: minutesValidator },
75
+ git_branch: { type: 'string' as const },
76
+ task_type: { type: 'string' as const, validate: createEnumValidator(VALID_TASK_TYPES) },
77
+ };
78
+
79
+ const completeTaskSchema = {
80
+ task_id: { type: 'string' as const, required: true as const, validate: uuidValidator },
81
+ summary: { type: 'string' as const },
82
+ };
83
+
84
+ const deleteTaskSchema = {
85
+ task_id: { type: 'string' as const, required: true as const, validate: uuidValidator },
86
+ };
87
+
88
+ const addTaskReferenceSchema = {
89
+ task_id: { type: 'string' as const, required: true as const, validate: uuidValidator },
90
+ url: { type: 'string' as const, required: true as const },
91
+ label: { type: 'string' as const },
92
+ };
93
+
94
+ const removeTaskReferenceSchema = {
95
+ task_id: { type: 'string' as const, required: true as const, validate: uuidValidator },
96
+ url: { type: 'string' as const, required: true as const },
97
+ };
98
+
99
+ const batchUpdateTasksSchema = {
100
+ updates: { type: 'array' as const, required: true as const },
101
+ };
102
+
103
+ const batchCompleteTasksSchema = {
104
+ completions: { type: 'array' as const, required: true as const },
105
+ };
106
+
107
+ const addSubtaskSchema = {
108
+ parent_task_id: { type: 'string' as const, required: true as const, validate: uuidValidator },
109
+ title: { type: 'string' as const, required: true as const },
110
+ description: { type: 'string' as const },
111
+ priority: { type: 'number' as const, validate: priorityValidator },
112
+ estimated_minutes: { type: 'number' as const, validate: minutesValidator },
113
+ };
114
+
115
+ const getSubtasksSchema = {
116
+ parent_task_id: { type: 'string' as const, required: true as const, validate: uuidValidator },
117
+ status: { type: 'string' as const, validate: taskStatusValidator },
118
+ };
119
+
31
120
  // ============================================================================
32
121
  // Git workflow helpers (used by complete_task response)
33
122
  // ============================================================================
@@ -126,24 +215,12 @@ export function getValidationApprovedGitInstructions(
126
215
  // ============================================================================
127
216
 
128
217
  export const getTasks: Handler = async (args, ctx) => {
129
- const { project_id, status, limit = 50, offset = 0, search_query, include_subtasks = false, include_metadata = false } = args as {
130
- project_id: string;
131
- status?: string;
132
- limit?: number;
133
- offset?: number;
134
- search_query?: string;
135
- include_subtasks?: boolean;
136
- include_metadata?: boolean; // When true, returns all task fields; when false (default), only id/title/priority/status
137
- };
138
-
139
- validateRequired(project_id, 'project_id');
140
- validateUUID(project_id, 'project_id');
141
- validateTaskStatus(status);
218
+ const { project_id, status, limit, offset, search_query, include_subtasks, include_metadata } = parseArgs(args, getTasksSchema);
142
219
 
143
220
  const api = getApiClient();
144
221
  const response = await api.getTasks(project_id, {
145
222
  status,
146
- limit: Math.min(limit, 200),
223
+ limit: Math.min(limit ?? 50, 200),
147
224
  offset,
148
225
  include_subtasks,
149
226
  search_query,
@@ -164,10 +241,7 @@ export const getTasks: Handler = async (args, ctx) => {
164
241
  };
165
242
 
166
243
  export const getNextTask: Handler = async (args, ctx) => {
167
- const { project_id } = args as { project_id: string };
168
-
169
- validateRequired(project_id, 'project_id');
170
- validateUUID(project_id, 'project_id');
244
+ const { project_id } = parseArgs(args, getNextTaskSchema);
171
245
 
172
246
  const api = getApiClient();
173
247
  const response = await api.getNextTask(project_id, ctx.session.currentSessionId || undefined);
@@ -211,21 +285,7 @@ export const getNextTask: Handler = async (args, ctx) => {
211
285
  };
212
286
 
213
287
  export const addTask: Handler = async (args, ctx) => {
214
- const { project_id, title, description, priority = 3, estimated_minutes, blocking = false, task_type } = args as {
215
- project_id: string;
216
- title: string;
217
- description?: string;
218
- priority?: number;
219
- estimated_minutes?: number;
220
- blocking?: boolean;
221
- task_type?: string;
222
- };
223
-
224
- validateRequired(project_id, 'project_id');
225
- validateRequired(title, 'title');
226
- validateUUID(project_id, 'project_id');
227
- validatePriority(priority);
228
- validateEstimatedMinutes(estimated_minutes);
288
+ const { project_id, title, description, priority, estimated_minutes, blocking, task_type } = parseArgs(args, addTaskSchema);
229
289
 
230
290
  const api = getApiClient();
231
291
  const response = await api.createTask(project_id, {
@@ -235,6 +295,7 @@ export const addTask: Handler = async (args, ctx) => {
235
295
  estimated_minutes,
236
296
  blocking,
237
297
  session_id: ctx.session.currentSessionId || undefined,
298
+ task_type,
238
299
  });
239
300
 
240
301
  if (!response.ok) {
@@ -257,25 +318,8 @@ export const addTask: Handler = async (args, ctx) => {
257
318
  };
258
319
 
259
320
  export const updateTask: Handler = async (args, ctx) => {
260
- const { task_id, progress_note, ...updates } = args as {
261
- task_id: string;
262
- title?: string;
263
- description?: string;
264
- priority?: number;
265
- status?: string;
266
- progress_percentage?: number;
267
- progress_note?: string;
268
- estimated_minutes?: number;
269
- git_branch?: string;
270
- task_type?: string;
271
- };
272
-
273
- validateRequired(task_id, 'task_id');
274
- validateUUID(task_id, 'task_id');
275
- validateTaskStatus(updates.status);
276
- validatePriority(updates.priority);
277
- validateProgressPercentage(updates.progress_percentage);
278
- validateEstimatedMinutes(updates.estimated_minutes);
321
+ const { task_id, title, description, priority, status, progress_percentage, progress_note, estimated_minutes, git_branch, task_type } = parseArgs(args, updateTaskSchema);
322
+ const updates = { title, description, priority, status, progress_percentage, estimated_minutes, git_branch, task_type };
279
323
 
280
324
  const api = getApiClient();
281
325
  const response = await api.updateTask(task_id, {
@@ -310,6 +354,16 @@ export const updateTask: Handler = async (args, ctx) => {
310
354
  },
311
355
  };
312
356
  }
357
+ if (response.error?.includes('branch_conflict')) {
358
+ return {
359
+ result: {
360
+ error: 'branch_conflict',
361
+ message: response.error,
362
+ conflicting_task_id: (response.data as { conflicting_task_id?: string })?.conflicting_task_id,
363
+ conflicting_task_title: (response.data as { conflicting_task_title?: string })?.conflicting_task_title,
364
+ },
365
+ };
366
+ }
313
367
  throw new Error(`Failed to update task: ${response.error}`);
314
368
  }
315
369
 
@@ -337,13 +391,7 @@ export const updateTask: Handler = async (args, ctx) => {
337
391
  };
338
392
 
339
393
  export const completeTask: Handler = async (args, ctx) => {
340
- const { task_id, summary } = args as {
341
- task_id: string;
342
- summary?: string;
343
- };
344
-
345
- validateRequired(task_id, 'task_id');
346
- validateUUID(task_id, 'task_id');
394
+ const { task_id, summary } = parseArgs(args, completeTaskSchema);
347
395
 
348
396
  const api = getApiClient();
349
397
  const response = await api.completeTask(task_id, {
@@ -386,10 +434,7 @@ export const completeTask: Handler = async (args, ctx) => {
386
434
  };
387
435
 
388
436
  export const deleteTask: Handler = async (args, ctx) => {
389
- const { task_id } = args as { task_id: string };
390
-
391
- validateRequired(task_id, 'task_id');
392
- validateUUID(task_id, 'task_id');
437
+ const { task_id } = parseArgs(args, deleteTaskSchema);
393
438
 
394
439
  const api = getApiClient();
395
440
  const response = await api.deleteTask(task_id);
@@ -402,11 +447,7 @@ export const deleteTask: Handler = async (args, ctx) => {
402
447
  };
403
448
 
404
449
  export const addTaskReference: Handler = async (args, ctx) => {
405
- const { task_id, url, label } = args as { task_id: string; url: string; label?: string };
406
-
407
- validateRequired(task_id, 'task_id');
408
- validateUUID(task_id, 'task_id');
409
- validateRequired(url, 'url');
450
+ const { task_id, url, label } = parseArgs(args, addTaskReferenceSchema);
410
451
 
411
452
  const api = getApiClient();
412
453
  const response = await api.addTaskReference(task_id, url, label);
@@ -427,11 +468,7 @@ export const addTaskReference: Handler = async (args, ctx) => {
427
468
  };
428
469
 
429
470
  export const removeTaskReference: Handler = async (args, ctx) => {
430
- const { task_id, url } = args as { task_id: string; url: string };
431
-
432
- validateRequired(task_id, 'task_id');
433
- validateUUID(task_id, 'task_id');
434
- validateRequired(url, 'url');
471
+ const { task_id, url } = parseArgs(args, removeTaskReferenceSchema);
435
472
 
436
473
  const api = getApiClient();
437
474
  const response = await api.removeTaskReference(task_id, url);
@@ -447,41 +484,33 @@ export const removeTaskReference: Handler = async (args, ctx) => {
447
484
  };
448
485
 
449
486
  export const batchUpdateTasks: Handler = async (args, ctx) => {
450
- const { updates } = args as {
451
- updates: Array<{
452
- task_id: string;
453
- status?: string;
454
- progress_percentage?: number;
455
- progress_note?: string;
456
- priority?: number;
457
- }>;
458
- };
487
+ const { updates } = parseArgs(args, batchUpdateTasksSchema);
488
+
489
+ const typedUpdates = updates as Array<{
490
+ task_id: string;
491
+ status?: string;
492
+ progress_percentage?: number;
493
+ progress_note?: string;
494
+ priority?: number;
495
+ }>;
459
496
 
460
- if (!updates || !Array.isArray(updates) || updates.length === 0) {
497
+ if (!Array.isArray(typedUpdates) || typedUpdates.length === 0) {
461
498
  throw new ValidationError('updates must be a non-empty array', {
462
499
  field: 'updates',
463
500
  hint: 'Provide an array of task updates with at least one item',
464
501
  });
465
502
  }
466
503
 
467
- if (updates.length > 50) {
504
+ if (typedUpdates.length > 50) {
468
505
  throw new ValidationError('Too many updates. Maximum is 50 per batch.', {
469
506
  field: 'updates',
470
507
  hint: 'Split your updates into smaller batches',
471
508
  });
472
509
  }
473
510
 
474
- // Validate all inputs first
475
- for (const update of updates) {
476
- validateRequired(update.task_id, 'task_id');
477
- validateUUID(update.task_id, 'task_id');
478
- validateTaskStatus(update.status);
479
- validatePriority(update.priority);
480
- validateProgressPercentage(update.progress_percentage);
481
- }
482
-
511
+ // Individual item validation happens at API level
483
512
  const api = getApiClient();
484
- const response = await api.batchUpdateTasks(updates);
513
+ const response = await api.batchUpdateTasks(typedUpdates);
485
514
 
486
515
  if (!response.ok) {
487
516
  throw new Error(`Failed to batch update tasks: ${response.error}`);
@@ -490,42 +519,38 @@ export const batchUpdateTasks: Handler = async (args, ctx) => {
490
519
  return {
491
520
  result: {
492
521
  success: response.data?.success || false,
493
- total: updates.length,
522
+ total: typedUpdates.length,
494
523
  succeeded: response.data?.updated_count || 0,
495
524
  },
496
525
  };
497
526
  };
498
527
 
499
528
  export const batchCompleteTasks: Handler = async (args, ctx) => {
500
- const { completions } = args as {
501
- completions: Array<{
502
- task_id: string;
503
- summary?: string;
504
- }>;
505
- };
529
+ const { completions } = parseArgs(args, batchCompleteTasksSchema);
506
530
 
507
- if (!completions || !Array.isArray(completions) || completions.length === 0) {
531
+ const typedCompletions = completions as Array<{
532
+ task_id: string;
533
+ summary?: string;
534
+ }>;
535
+
536
+ if (!Array.isArray(typedCompletions) || typedCompletions.length === 0) {
508
537
  throw new ValidationError('completions must be a non-empty array', {
509
538
  field: 'completions',
510
539
  hint: 'Provide an array of task completions with at least one item',
511
540
  });
512
541
  }
513
542
 
514
- if (completions.length > 50) {
543
+ if (typedCompletions.length > 50) {
515
544
  throw new ValidationError('Too many completions. Maximum is 50 per batch.', {
516
545
  field: 'completions',
517
546
  hint: 'Split your completions into smaller batches',
518
547
  });
519
548
  }
520
549
 
521
- // Validate all inputs first
522
- for (const completion of completions) {
523
- validateRequired(completion.task_id, 'task_id');
524
- validateUUID(completion.task_id, 'task_id');
525
- }
550
+ // Individual item validation happens at API level
526
551
 
527
552
  const api = getApiClient();
528
- const response = await api.batchCompleteTasks(completions);
553
+ const response = await api.batchCompleteTasks(typedCompletions);
529
554
 
530
555
  if (!response.ok) {
531
556
  throw new Error(`Failed to batch complete tasks: ${response.error}`);
@@ -535,9 +560,9 @@ export const batchCompleteTasks: Handler = async (args, ctx) => {
535
560
  return {
536
561
  result: {
537
562
  success: data?.success || false,
538
- total: completions.length,
563
+ total: typedCompletions.length,
539
564
  succeeded: data?.completed_count || 0,
540
- failed: completions.length - (data?.completed_count || 0),
565
+ failed: typedCompletions.length - (data?.completed_count || 0),
541
566
  next_task: data?.next_task,
542
567
  },
543
568
  };
@@ -548,19 +573,7 @@ export const batchCompleteTasks: Handler = async (args, ctx) => {
548
573
  // ============================================================================
549
574
 
550
575
  export const addSubtask: Handler = async (args, ctx) => {
551
- const { parent_task_id, title, description, priority, estimated_minutes } = args as {
552
- parent_task_id: string;
553
- title: string;
554
- description?: string;
555
- priority?: number;
556
- estimated_minutes?: number;
557
- };
558
-
559
- validateRequired(parent_task_id, 'parent_task_id');
560
- validateUUID(parent_task_id, 'parent_task_id');
561
- validateRequired(title, 'title');
562
- if (priority !== undefined) validatePriority(priority);
563
- if (estimated_minutes !== undefined) validateEstimatedMinutes(estimated_minutes);
576
+ const { parent_task_id, title, description, priority, estimated_minutes } = parseArgs(args, addSubtaskSchema);
564
577
 
565
578
  const api = getApiClient();
566
579
  const response = await api.addSubtask(parent_task_id, {
@@ -593,14 +606,7 @@ export const addSubtask: Handler = async (args, ctx) => {
593
606
  };
594
607
 
595
608
  export const getSubtasks: Handler = async (args, ctx) => {
596
- const { parent_task_id, status } = args as {
597
- parent_task_id: string;
598
- status?: string;
599
- };
600
-
601
- validateRequired(parent_task_id, 'parent_task_id');
602
- validateUUID(parent_task_id, 'parent_task_id');
603
- if (status) validateTaskStatus(status);
609
+ const { parent_task_id, status } = parseArgs(args, getSubtasksSchema);
604
610
 
605
611
  const api = getApiClient();
606
612
  const response = await api.getSubtasks(parent_task_id, status);
@@ -309,7 +309,7 @@ describe('validateTask', () => {
309
309
 
310
310
  await expect(
311
311
  validateTask({ task_id: VALID_UUID }, ctx)
312
- ).rejects.toThrow('approved is required');
312
+ ).rejects.toThrow('Missing required field: approved');
313
313
  });
314
314
 
315
315
  it('should throw error when task not found', async () => {
@@ -8,14 +8,27 @@
8
8
  */
9
9
 
10
10
  import type { Handler, HandlerRegistry } from './types.js';
11
- import { validateRequired, validateUUID } from '../validators.js';
11
+ import { parseArgs, uuidValidator } from '../validators.js';
12
12
  import { getApiClient } from '../api-client.js';
13
13
 
14
- export const getTasksAwaitingValidation: Handler = async (args, ctx) => {
15
- const { project_id } = args as { project_id: string };
14
+ // Argument schemas for type-safe parsing
15
+ const getTasksAwaitingValidationSchema = {
16
+ project_id: { type: 'string' as const, required: true as const, validate: uuidValidator },
17
+ };
18
+
19
+ const claimValidationSchema = {
20
+ task_id: { type: 'string' as const, required: true as const, validate: uuidValidator },
21
+ };
16
22
 
17
- validateRequired(project_id, 'project_id');
18
- validateUUID(project_id, 'project_id');
23
+ const validateTaskSchema = {
24
+ task_id: { type: 'string' as const, required: true as const, validate: uuidValidator },
25
+ approved: { type: 'boolean' as const, required: true as const },
26
+ validation_notes: { type: 'string' as const },
27
+ skip_pr_check: { type: 'boolean' as const },
28
+ };
29
+
30
+ export const getTasksAwaitingValidation: Handler = async (args, _ctx) => {
31
+ const { project_id } = parseArgs(args, getTasksAwaitingValidationSchema);
19
32
 
20
33
  const apiClient = getApiClient();
21
34
  const response = await apiClient.getTasksAwaitingValidation(project_id);
@@ -28,10 +41,7 @@ export const getTasksAwaitingValidation: Handler = async (args, ctx) => {
28
41
  };
29
42
 
30
43
  export const claimValidation: Handler = async (args, ctx) => {
31
- const { task_id } = args as { task_id: string };
32
-
33
- validateRequired(task_id, 'task_id');
34
- validateUUID(task_id, 'task_id');
44
+ const { task_id } = parseArgs(args, claimValidationSchema);
35
45
 
36
46
  const { session } = ctx;
37
47
  const currentSessionId = session.currentSessionId;
@@ -47,19 +57,7 @@ export const claimValidation: Handler = async (args, ctx) => {
47
57
  };
48
58
 
49
59
  export const validateTask: Handler = async (args, ctx) => {
50
- const { task_id, validation_notes, approved, skip_pr_check } = args as {
51
- task_id: string;
52
- validation_notes?: string;
53
- approved: boolean;
54
- skip_pr_check?: boolean;
55
- };
56
-
57
- validateRequired(task_id, 'task_id');
58
- validateUUID(task_id, 'task_id');
59
-
60
- if (approved === undefined) {
61
- throw new Error('approved is required');
62
- }
60
+ const { task_id, approved, validation_notes, skip_pr_check } = parseArgs(args, validateTaskSchema);
63
61
 
64
62
  const { session } = ctx;
65
63
  const currentSessionId = session.currentSessionId;