@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
@@ -9,20 +9,55 @@
9
9
  * - delete_cost_alert
10
10
  * - get_task_costs
11
11
  */
12
+ import { parseArgs, uuidValidator, createEnumValidator, ValidationError } from '../validators.js';
12
13
  import { getApiClient } from '../api-client.js';
14
+ const VALID_PERIODS = ['daily', 'weekly', 'monthly'];
15
+ const VALID_ALERT_TYPES = ['warning', 'critical'];
16
+ // Argument schemas for type-safe parsing
17
+ const getCostSummarySchema = {
18
+ project_id: { type: 'string', required: true, validate: uuidValidator },
19
+ period: { type: 'string', default: 'daily', validate: createEnumValidator(VALID_PERIODS) },
20
+ limit: { type: 'number', default: 30 },
21
+ };
22
+ const getCostAlertsSchema = {
23
+ project_id: { type: 'string', validate: uuidValidator },
24
+ };
25
+ const addCostAlertSchema = {
26
+ project_id: { type: 'string', validate: uuidValidator },
27
+ threshold_amount: { type: 'number', required: true },
28
+ threshold_period: { type: 'string', required: true, validate: createEnumValidator(VALID_PERIODS) },
29
+ alert_type: { type: 'string', default: 'warning', validate: createEnumValidator(VALID_ALERT_TYPES) },
30
+ };
31
+ const updateCostAlertSchema = {
32
+ alert_id: { type: 'string', required: true, validate: uuidValidator },
33
+ threshold_amount: { type: 'number' },
34
+ threshold_period: { type: 'string', validate: createEnumValidator(VALID_PERIODS) },
35
+ alert_type: { type: 'string', validate: createEnumValidator(VALID_ALERT_TYPES) },
36
+ enabled: { type: 'boolean' },
37
+ };
38
+ const deleteCostAlertSchema = {
39
+ alert_id: { type: 'string', required: true, validate: uuidValidator },
40
+ };
41
+ const getTaskCostsSchema = {
42
+ project_id: { type: 'string', required: true, validate: uuidValidator },
43
+ limit: { type: 'number', default: 20 },
44
+ };
45
+ // Custom validator for positive numbers
46
+ function validatePositiveNumber(value, fieldName) {
47
+ if (value !== undefined && value <= 0) {
48
+ throw new ValidationError(`${fieldName} must be a positive number`, { field: fieldName });
49
+ }
50
+ }
13
51
  /**
14
52
  * Get cost summary for a project (daily, weekly, or monthly)
15
53
  */
16
- export const getCostSummary = async (args, ctx) => {
17
- const { project_id, period = 'daily', limit = 30 } = args;
18
- if (!project_id) {
19
- return {
20
- result: { error: 'project_id is required' },
21
- isError: true,
22
- };
23
- }
54
+ export const getCostSummary = async (args, _ctx) => {
55
+ const { project_id, period, limit } = parseArgs(args, getCostSummarySchema);
24
56
  const apiClient = getApiClient();
25
- const response = await apiClient.getCostSummary(project_id, { period, limit });
57
+ const response = await apiClient.getCostSummary(project_id, {
58
+ period: period,
59
+ limit
60
+ });
26
61
  if (!response.ok) {
27
62
  return {
28
63
  result: { error: response.error || 'Failed to get cost summary' },
@@ -34,8 +69,8 @@ export const getCostSummary = async (args, ctx) => {
34
69
  /**
35
70
  * Get cost alerts for the current user
36
71
  */
37
- export const getCostAlerts = async (args, ctx) => {
38
- const { project_id } = args;
72
+ export const getCostAlerts = async (args, _ctx) => {
73
+ const { project_id } = parseArgs(args, getCostAlertsSchema);
39
74
  const apiClient = getApiClient();
40
75
  const response = await apiClient.getCostAlerts();
41
76
  if (!response.ok) {
@@ -49,26 +84,16 @@ export const getCostAlerts = async (args, ctx) => {
49
84
  /**
50
85
  * Add a cost alert
51
86
  */
52
- export const addCostAlert = async (args, ctx) => {
53
- const { project_id, threshold_amount, threshold_period, alert_type = 'warning', } = args;
54
- if (!threshold_amount || threshold_amount <= 0) {
55
- return {
56
- result: { error: 'threshold_amount must be a positive number' },
57
- isError: true,
58
- };
59
- }
60
- if (!threshold_period || !['daily', 'weekly', 'monthly'].includes(threshold_period)) {
61
- return {
62
- result: { error: 'threshold_period must be "daily", "weekly", or "monthly"' },
63
- isError: true,
64
- };
65
- }
87
+ export const addCostAlert = async (args, _ctx) => {
88
+ const { project_id, threshold_amount, threshold_period, alert_type } = parseArgs(args, addCostAlertSchema);
89
+ // Additional validation for positive amount
90
+ validatePositiveNumber(threshold_amount, 'threshold_amount');
66
91
  const apiClient = getApiClient();
67
92
  const response = await apiClient.addCostAlert({
68
93
  project_id,
69
- threshold_amount,
70
- threshold_period,
71
- alert_type
94
+ threshold_amount: threshold_amount,
95
+ threshold_period: threshold_period,
96
+ alert_type: alert_type
72
97
  });
73
98
  if (!response.ok) {
74
99
  return {
@@ -81,11 +106,12 @@ export const addCostAlert = async (args, ctx) => {
81
106
  /**
82
107
  * Update a cost alert
83
108
  */
84
- export const updateCostAlert = async (args, ctx) => {
85
- const { alert_id, threshold_amount, threshold_period, alert_type, enabled, } = args;
86
- if (!alert_id) {
109
+ export const updateCostAlert = async (args, _ctx) => {
110
+ const { alert_id, threshold_amount, threshold_period, alert_type, enabled } = parseArgs(args, updateCostAlertSchema);
111
+ // Check that at least one update is provided
112
+ if (threshold_amount === undefined && threshold_period === undefined && alert_type === undefined && enabled === undefined) {
87
113
  return {
88
- result: { error: 'alert_id is required' },
114
+ result: { error: 'No updates provided' },
89
115
  isError: true,
90
116
  };
91
117
  }
@@ -98,12 +124,6 @@ export const updateCostAlert = async (args, ctx) => {
98
124
  updates.alert_type = alert_type;
99
125
  if (enabled !== undefined)
100
126
  updates.enabled = enabled;
101
- if (Object.keys(updates).length === 0) {
102
- return {
103
- result: { error: 'No updates provided' },
104
- isError: true,
105
- };
106
- }
107
127
  const apiClient = getApiClient();
108
128
  const response = await apiClient.updateCostAlert(alert_id, updates);
109
129
  if (!response.ok) {
@@ -117,14 +137,8 @@ export const updateCostAlert = async (args, ctx) => {
117
137
  /**
118
138
  * Delete a cost alert
119
139
  */
120
- export const deleteCostAlert = async (args, ctx) => {
121
- const { alert_id } = args;
122
- if (!alert_id) {
123
- return {
124
- result: { error: 'alert_id is required' },
125
- isError: true,
126
- };
127
- }
140
+ export const deleteCostAlert = async (args, _ctx) => {
141
+ const { alert_id } = parseArgs(args, deleteCostAlertSchema);
128
142
  const apiClient = getApiClient();
129
143
  const response = await apiClient.deleteCostAlert(alert_id);
130
144
  if (!response.ok) {
@@ -138,14 +152,8 @@ export const deleteCostAlert = async (args, ctx) => {
138
152
  /**
139
153
  * Get task costs for a project
140
154
  */
141
- export const getTaskCosts = async (args, ctx) => {
142
- const { project_id, limit = 20 } = args;
143
- if (!project_id) {
144
- return {
145
- result: { error: 'project_id is required' },
146
- isError: true,
147
- };
148
- }
155
+ export const getTaskCosts = async (args, _ctx) => {
156
+ const { project_id, limit } = parseArgs(args, getTaskCostsSchema);
149
157
  const apiClient = getApiClient();
150
158
  const response = await apiClient.getTaskCosts(project_id, limit);
151
159
  if (!response.ok) {
@@ -8,33 +8,48 @@
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 logDecisionSchema = {
15
+ project_id: { type: 'string', required: true, validate: uuidValidator },
16
+ title: { type: 'string', required: true },
17
+ description: { type: 'string', required: true },
18
+ rationale: { type: 'string' },
19
+ alternatives_considered: { type: 'array' },
20
+ };
21
+ const getDecisionsSchema = {
22
+ project_id: { type: 'string', required: true, validate: uuidValidator },
23
+ limit: { type: 'number', default: 50 },
24
+ offset: { type: 'number', default: 0 },
25
+ search_query: { type: 'string' },
26
+ };
27
+ const deleteDecisionSchema = {
28
+ decision_id: { type: 'string', required: true, validate: uuidValidator },
29
+ };
13
30
  export const logDecision = async (args, ctx) => {
14
- const { project_id, title, description, rationale, alternatives_considered } = args;
15
- validateRequired(project_id, 'project_id');
16
- validateUUID(project_id, 'project_id');
17
- validateRequired(title, 'title');
18
- validateRequired(description, 'description');
31
+ const { project_id, title, description, rationale, alternatives_considered } = parseArgs(args, logDecisionSchema);
19
32
  const { session } = ctx;
20
33
  const apiClient = getApiClient();
21
34
  const response = await apiClient.logDecision(project_id, {
22
35
  title,
23
36
  description,
24
37
  rationale,
25
- alternatives_considered
38
+ alternatives_considered: alternatives_considered
26
39
  }, session.currentSessionId || undefined);
27
40
  if (!response.ok) {
28
41
  throw new Error(`Failed to log decision: ${response.error}`);
29
42
  }
30
43
  return { result: { success: true, title, decision_id: response.data?.decision_id } };
31
44
  };
32
- export const getDecisions = async (args, ctx) => {
33
- const { project_id } = args;
34
- validateRequired(project_id, 'project_id');
35
- validateUUID(project_id, 'project_id');
45
+ export const getDecisions = async (args, _ctx) => {
46
+ const { project_id, limit, offset, search_query } = parseArgs(args, getDecisionsSchema);
36
47
  const apiClient = getApiClient();
37
- const response = await apiClient.getDecisions(project_id);
48
+ const response = await apiClient.getDecisions(project_id, {
49
+ limit,
50
+ offset,
51
+ search_query
52
+ });
38
53
  if (!response.ok) {
39
54
  throw new Error(`Failed to fetch decisions: ${response.error}`);
40
55
  }
@@ -44,10 +59,8 @@ export const getDecisions = async (args, ctx) => {
44
59
  },
45
60
  };
46
61
  };
47
- export const deleteDecision = async (args, ctx) => {
48
- const { decision_id } = args;
49
- validateRequired(decision_id, 'decision_id');
50
- validateUUID(decision_id, 'decision_id');
62
+ export const deleteDecision = async (args, _ctx) => {
63
+ const { decision_id } = parseArgs(args, deleteDecisionSchema);
51
64
  const apiClient = getApiClient();
52
65
  const response = await apiClient.deleteDecision(decision_id);
53
66
  if (!response.ok) {
@@ -13,21 +13,103 @@
13
13
  * - complete_deployment_requirement
14
14
  * - get_deployment_requirements
15
15
  */
16
- import { ValidationError, validateRequired, validateUUID, validateEnvironment, } from '../validators.js';
16
+ import { ValidationError, parseArgs, uuidValidator, createEnumValidator, } from '../validators.js';
17
17
  import { getApiClient } from '../api-client.js';
18
+ const ENVIRONMENTS = ['development', 'staging', 'production'];
19
+ const VERSION_BUMPS = ['patch', 'minor', 'major'];
20
+ const REQUIREMENT_TYPES = ['migration', 'env_var', 'config', 'manual', 'breaking_change', 'agent_task'];
21
+ const REQUIREMENT_STAGES = ['preparation', 'deployment', 'verification'];
22
+ const REQUIREMENT_STATUSES = ['pending', 'completed', 'converted_to_task', 'all'];
23
+ const SCHEDULE_TYPES = ['once', 'daily', 'weekly', 'monthly'];
24
+ // ============================================================================
25
+ // Argument Schemas
26
+ // ============================================================================
27
+ const requestDeploymentSchema = {
28
+ project_id: { type: 'string', required: true, validate: uuidValidator },
29
+ environment: { type: 'string', default: 'production', validate: createEnumValidator(ENVIRONMENTS) },
30
+ version_bump: { type: 'string', default: 'patch', validate: createEnumValidator(VERSION_BUMPS) },
31
+ notes: { type: 'string' },
32
+ git_ref: { type: 'string' },
33
+ };
34
+ const claimDeploymentValidationSchema = {
35
+ project_id: { type: 'string', required: true, validate: uuidValidator },
36
+ };
37
+ const reportValidationSchema = {
38
+ project_id: { type: 'string', required: true, validate: uuidValidator },
39
+ build_passed: { type: 'boolean', required: true },
40
+ tests_passed: { type: 'boolean' },
41
+ error_message: { type: 'string' },
42
+ };
43
+ const checkDeploymentStatusSchema = {
44
+ project_id: { type: 'string', required: true, validate: uuidValidator },
45
+ };
46
+ const startDeploymentSchema = {
47
+ project_id: { type: 'string', required: true, validate: uuidValidator },
48
+ };
49
+ const completeDeploymentSchema = {
50
+ project_id: { type: 'string', required: true, validate: uuidValidator },
51
+ success: { type: 'boolean', required: true },
52
+ summary: { type: 'string' },
53
+ };
54
+ const cancelDeploymentSchema = {
55
+ project_id: { type: 'string', required: true, validate: uuidValidator },
56
+ reason: { type: 'string' },
57
+ };
58
+ const addDeploymentRequirementSchema = {
59
+ project_id: { type: 'string', required: true, validate: uuidValidator },
60
+ type: { type: 'string', required: true, validate: createEnumValidator(REQUIREMENT_TYPES) },
61
+ title: { type: 'string', required: true },
62
+ description: { type: 'string' },
63
+ file_path: { type: 'string' },
64
+ stage: { type: 'string', default: 'preparation', validate: createEnumValidator(REQUIREMENT_STAGES) },
65
+ blocking: { type: 'boolean', default: false },
66
+ recurring: { type: 'boolean', default: false },
67
+ };
68
+ const completeDeploymentRequirementSchema = {
69
+ requirement_id: { type: 'string', required: true, validate: uuidValidator },
70
+ };
71
+ const getDeploymentRequirementsSchema = {
72
+ project_id: { type: 'string', required: true, validate: uuidValidator },
73
+ status: { type: 'string', default: 'pending', validate: createEnumValidator(REQUIREMENT_STATUSES) },
74
+ stage: { type: 'string', validate: createEnumValidator([...REQUIREMENT_STAGES, 'all']) },
75
+ };
76
+ const scheduleDeploymentSchema = {
77
+ project_id: { type: 'string', required: true, validate: uuidValidator },
78
+ environment: { type: 'string', default: 'production', validate: createEnumValidator(ENVIRONMENTS) },
79
+ version_bump: { type: 'string', default: 'patch', validate: createEnumValidator(VERSION_BUMPS) },
80
+ schedule_type: { type: 'string', default: 'once', validate: createEnumValidator(SCHEDULE_TYPES) },
81
+ scheduled_at: { type: 'string', required: true },
82
+ auto_trigger: { type: 'boolean', default: true },
83
+ notes: { type: 'string' },
84
+ git_ref: { type: 'string' },
85
+ };
86
+ const getScheduledDeploymentsSchema = {
87
+ project_id: { type: 'string', required: true, validate: uuidValidator },
88
+ include_disabled: { type: 'boolean', default: false },
89
+ };
90
+ const updateScheduledDeploymentSchema = {
91
+ schedule_id: { type: 'string', required: true, validate: uuidValidator },
92
+ environment: { type: 'string', validate: createEnumValidator(ENVIRONMENTS) },
93
+ version_bump: { type: 'string', validate: createEnumValidator(VERSION_BUMPS) },
94
+ schedule_type: { type: 'string', validate: createEnumValidator(SCHEDULE_TYPES) },
95
+ scheduled_at: { type: 'string' },
96
+ auto_trigger: { type: 'boolean' },
97
+ enabled: { type: 'boolean' },
98
+ notes: { type: 'string' },
99
+ git_ref: { type: 'string' },
100
+ };
101
+ const deleteScheduledDeploymentSchema = {
102
+ schedule_id: { type: 'string', required: true, validate: uuidValidator },
103
+ };
104
+ const triggerScheduledDeploymentSchema = {
105
+ schedule_id: { type: 'string', required: true, validate: uuidValidator },
106
+ };
107
+ const checkDueDeploymentsSchema = {
108
+ project_id: { type: 'string', required: true, validate: uuidValidator },
109
+ };
18
110
  export const requestDeployment = async (args, ctx) => {
19
- const { project_id, environment = 'production', version_bump = 'patch', notes, git_ref } = args;
111
+ const { project_id, environment, version_bump, notes, git_ref } = parseArgs(args, requestDeploymentSchema);
20
112
  const { session } = ctx;
21
- validateRequired(project_id, 'project_id');
22
- validateUUID(project_id, 'project_id');
23
- validateEnvironment(environment);
24
- if (version_bump && !['patch', 'minor', 'major'].includes(version_bump)) {
25
- throw new ValidationError('Invalid version_bump value', {
26
- field: 'version_bump',
27
- validValues: ['patch', 'minor', 'major'],
28
- hint: 'Must be one of: patch, minor, major',
29
- });
30
- }
31
113
  const apiClient = getApiClient();
32
114
  const response = await apiClient.requestDeployment(project_id, {
33
115
  environment,
@@ -41,10 +123,8 @@ export const requestDeployment = async (args, ctx) => {
41
123
  return { result: response.data };
42
124
  };
43
125
  export const claimDeploymentValidation = async (args, ctx) => {
44
- const { project_id } = args;
126
+ const { project_id } = parseArgs(args, claimDeploymentValidationSchema);
45
127
  const { session } = ctx;
46
- validateRequired(project_id, 'project_id');
47
- validateUUID(project_id, 'project_id');
48
128
  const apiClient = getApiClient();
49
129
  const response = await apiClient.claimDeploymentValidation(project_id, session.currentSessionId || undefined);
50
130
  if (!response.ok) {
@@ -53,16 +133,8 @@ export const claimDeploymentValidation = async (args, ctx) => {
53
133
  return { result: response.data };
54
134
  };
55
135
  export const reportValidation = async (args, ctx) => {
56
- const { project_id, build_passed, tests_passed, error_message } = args;
136
+ const { project_id, build_passed, tests_passed, error_message } = parseArgs(args, reportValidationSchema);
57
137
  const { session } = ctx;
58
- validateRequired(project_id, 'project_id');
59
- validateUUID(project_id, 'project_id');
60
- if (build_passed === undefined) {
61
- throw new ValidationError('build_passed is required', {
62
- field: 'build_passed',
63
- hint: 'Set to true if the build succeeded, false otherwise',
64
- });
65
- }
66
138
  const apiClient = getApiClient();
67
139
  const response = await apiClient.reportValidation(project_id, {
68
140
  build_passed,
@@ -75,9 +147,7 @@ export const reportValidation = async (args, ctx) => {
75
147
  return { result: response.data };
76
148
  };
77
149
  export const checkDeploymentStatus = async (args, ctx) => {
78
- const { project_id } = args;
79
- validateRequired(project_id, 'project_id');
80
- validateUUID(project_id, 'project_id');
150
+ const { project_id } = parseArgs(args, checkDeploymentStatusSchema);
81
151
  const apiClient = getApiClient();
82
152
  const response = await apiClient.checkDeploymentStatus(project_id);
83
153
  if (!response.ok) {
@@ -86,10 +156,8 @@ export const checkDeploymentStatus = async (args, ctx) => {
86
156
  return { result: response.data };
87
157
  };
88
158
  export const startDeployment = async (args, ctx) => {
89
- const { project_id } = args;
159
+ const { project_id } = parseArgs(args, startDeploymentSchema);
90
160
  const { session } = ctx;
91
- validateRequired(project_id, 'project_id');
92
- validateUUID(project_id, 'project_id');
93
161
  const apiClient = getApiClient();
94
162
  const response = await apiClient.startDeployment(project_id, session.currentSessionId || undefined);
95
163
  if (!response.ok) {
@@ -98,16 +166,8 @@ export const startDeployment = async (args, ctx) => {
98
166
  return { result: response.data };
99
167
  };
100
168
  export const completeDeployment = async (args, ctx) => {
101
- const { project_id, success, summary } = args;
169
+ const { project_id, success, summary } = parseArgs(args, completeDeploymentSchema);
102
170
  const { session } = ctx;
103
- validateRequired(project_id, 'project_id');
104
- validateUUID(project_id, 'project_id');
105
- if (success === undefined) {
106
- throw new ValidationError('success is required', {
107
- field: 'success',
108
- hint: 'Set to true if deployment succeeded, false otherwise',
109
- });
110
- }
111
171
  const apiClient = getApiClient();
112
172
  const response = await apiClient.completeDeployment(project_id, {
113
173
  success,
@@ -119,9 +179,7 @@ export const completeDeployment = async (args, ctx) => {
119
179
  return { result: response.data };
120
180
  };
121
181
  export const cancelDeployment = async (args, ctx) => {
122
- const { project_id, reason } = args;
123
- validateRequired(project_id, 'project_id');
124
- validateUUID(project_id, 'project_id');
182
+ const { project_id, reason } = parseArgs(args, cancelDeploymentSchema);
125
183
  const apiClient = getApiClient();
126
184
  const response = await apiClient.cancelDeployment(project_id, reason);
127
185
  if (!response.ok) {
@@ -130,19 +188,7 @@ export const cancelDeployment = async (args, ctx) => {
130
188
  return { result: response.data };
131
189
  };
132
190
  export const addDeploymentRequirement = async (args, ctx) => {
133
- const { project_id, type, title, description, file_path, stage = 'preparation', blocking = false } = args;
134
- validateRequired(project_id, 'project_id');
135
- validateUUID(project_id, 'project_id');
136
- validateRequired(type, 'type');
137
- validateRequired(title, 'title');
138
- const validTypes = ['migration', 'env_var', 'config', 'manual', 'breaking_change', 'agent_task'];
139
- if (!validTypes.includes(type)) {
140
- throw new ValidationError(`type must be one of: ${validTypes.join(', ')}`);
141
- }
142
- const validStages = ['preparation', 'deployment', 'verification'];
143
- if (!validStages.includes(stage)) {
144
- throw new ValidationError(`stage must be one of: ${validStages.join(', ')}`);
145
- }
191
+ const { project_id, type, title, description, file_path, stage, blocking, recurring } = parseArgs(args, addDeploymentRequirementSchema);
146
192
  const apiClient = getApiClient();
147
193
  const response = await apiClient.addDeploymentRequirement(project_id, {
148
194
  type: type,
@@ -150,7 +196,8 @@ export const addDeploymentRequirement = async (args, ctx) => {
150
196
  description,
151
197
  file_path,
152
198
  stage: stage,
153
- blocking
199
+ blocking,
200
+ recurring
154
201
  });
155
202
  if (!response.ok) {
156
203
  throw new Error(response.error || 'Failed to add deployment requirement');
@@ -158,9 +205,7 @@ export const addDeploymentRequirement = async (args, ctx) => {
158
205
  return { result: response.data };
159
206
  };
160
207
  export const completeDeploymentRequirement = async (args, ctx) => {
161
- const { requirement_id } = args;
162
- validateRequired(requirement_id, 'requirement_id');
163
- validateUUID(requirement_id, 'requirement_id');
208
+ const { requirement_id } = parseArgs(args, completeDeploymentRequirementSchema);
164
209
  const apiClient = getApiClient();
165
210
  const response = await apiClient.completeDeploymentRequirement(requirement_id);
166
211
  if (!response.ok) {
@@ -169,9 +214,7 @@ export const completeDeploymentRequirement = async (args, ctx) => {
169
214
  return { result: response.data };
170
215
  };
171
216
  export const getDeploymentRequirements = async (args, ctx) => {
172
- const { project_id, status = 'pending', stage } = args;
173
- validateRequired(project_id, 'project_id');
174
- validateUUID(project_id, 'project_id');
217
+ const { project_id, status, stage } = parseArgs(args, getDeploymentRequirementsSchema);
175
218
  const apiClient = getApiClient();
176
219
  const response = await apiClient.getDeploymentRequirements(project_id, {
177
220
  status: status,
@@ -186,23 +229,7 @@ export const getDeploymentRequirements = async (args, ctx) => {
186
229
  // Scheduled Deployments
187
230
  // ============================================================================
188
231
  export const scheduleDeployment = async (args, ctx) => {
189
- const { project_id, environment = 'production', version_bump = 'patch', schedule_type = 'once', scheduled_at, auto_trigger = true, notes, git_ref, } = args;
190
- validateRequired(project_id, 'project_id');
191
- validateUUID(project_id, 'project_id');
192
- validateRequired(scheduled_at, 'scheduled_at');
193
- validateEnvironment(environment);
194
- if (!['patch', 'minor', 'major'].includes(version_bump)) {
195
- throw new ValidationError('Invalid version_bump value', {
196
- field: 'version_bump',
197
- validValues: ['patch', 'minor', 'major'],
198
- });
199
- }
200
- if (!['once', 'daily', 'weekly', 'monthly'].includes(schedule_type)) {
201
- throw new ValidationError('Invalid schedule_type value', {
202
- field: 'schedule_type',
203
- validValues: ['once', 'daily', 'weekly', 'monthly'],
204
- });
205
- }
232
+ const { project_id, environment, version_bump, schedule_type, scheduled_at, auto_trigger, notes, git_ref, } = parseArgs(args, scheduleDeploymentSchema);
206
233
  // Parse and validate scheduled_at
207
234
  const scheduledDate = new Date(scheduled_at);
208
235
  if (isNaN(scheduledDate.getTime())) {
@@ -232,9 +259,7 @@ export const scheduleDeployment = async (args, ctx) => {
232
259
  return { result: response.data };
233
260
  };
234
261
  export const getScheduledDeployments = async (args, ctx) => {
235
- const { project_id, include_disabled = false } = args;
236
- validateRequired(project_id, 'project_id');
237
- validateUUID(project_id, 'project_id');
262
+ const { project_id, include_disabled } = parseArgs(args, getScheduledDeploymentsSchema);
238
263
  const apiClient = getApiClient();
239
264
  const response = await apiClient.getScheduledDeployments(project_id, include_disabled);
240
265
  if (!response.ok) {
@@ -243,26 +268,14 @@ export const getScheduledDeployments = async (args, ctx) => {
243
268
  return { result: response.data };
244
269
  };
245
270
  export const updateScheduledDeployment = async (args, ctx) => {
246
- const { schedule_id, environment, version_bump, schedule_type, scheduled_at, auto_trigger, enabled, notes, git_ref, } = args;
247
- validateRequired(schedule_id, 'schedule_id');
248
- validateUUID(schedule_id, 'schedule_id');
271
+ const { schedule_id, environment, version_bump, schedule_type, scheduled_at, auto_trigger, enabled, notes, git_ref, } = parseArgs(args, updateScheduledDeploymentSchema);
249
272
  const updates = {};
250
- if (environment !== undefined) {
251
- validateEnvironment(environment);
273
+ if (environment !== undefined)
252
274
  updates.environment = environment;
253
- }
254
- if (version_bump !== undefined) {
255
- if (!['patch', 'minor', 'major'].includes(version_bump)) {
256
- throw new ValidationError('Invalid version_bump value');
257
- }
275
+ if (version_bump !== undefined)
258
276
  updates.version_bump = version_bump;
259
- }
260
- if (schedule_type !== undefined) {
261
- if (!['once', 'daily', 'weekly', 'monthly'].includes(schedule_type)) {
262
- throw new ValidationError('Invalid schedule_type value');
263
- }
277
+ if (schedule_type !== undefined)
264
278
  updates.schedule_type = schedule_type;
265
- }
266
279
  if (scheduled_at !== undefined) {
267
280
  const scheduledDate = new Date(scheduled_at);
268
281
  if (isNaN(scheduledDate.getTime())) {
@@ -289,9 +302,7 @@ export const updateScheduledDeployment = async (args, ctx) => {
289
302
  return { result: response.data };
290
303
  };
291
304
  export const deleteScheduledDeployment = async (args, ctx) => {
292
- const { schedule_id } = args;
293
- validateRequired(schedule_id, 'schedule_id');
294
- validateUUID(schedule_id, 'schedule_id');
305
+ const { schedule_id } = parseArgs(args, deleteScheduledDeploymentSchema);
295
306
  const apiClient = getApiClient();
296
307
  const response = await apiClient.deleteScheduledDeployment(schedule_id);
297
308
  if (!response.ok) {
@@ -300,10 +311,8 @@ export const deleteScheduledDeployment = async (args, ctx) => {
300
311
  return { result: response.data };
301
312
  };
302
313
  export const triggerScheduledDeployment = async (args, ctx) => {
303
- const { schedule_id } = args;
314
+ const { schedule_id } = parseArgs(args, triggerScheduledDeploymentSchema);
304
315
  const { session } = ctx;
305
- validateRequired(schedule_id, 'schedule_id');
306
- validateUUID(schedule_id, 'schedule_id');
307
316
  const apiClient = getApiClient();
308
317
  const response = await apiClient.triggerScheduledDeployment(schedule_id, session.currentSessionId || undefined);
309
318
  if (!response.ok) {
@@ -312,9 +321,7 @@ export const triggerScheduledDeployment = async (args, ctx) => {
312
321
  return { result: response.data };
313
322
  };
314
323
  export const checkDueDeployments = async (args, ctx) => {
315
- const { project_id } = args;
316
- validateRequired(project_id, 'project_id');
317
- validateUUID(project_id, 'project_id');
324
+ const { project_id } = parseArgs(args, checkDueDeploymentsSchema);
318
325
  const apiClient = getApiClient();
319
326
  const response = await apiClient.checkDueDeployments(project_id);
320
327
  if (!response.ok) {
@@ -4,6 +4,9 @@
4
4
  * Handles tool discovery and documentation:
5
5
  * - discover_tools
6
6
  * - get_tool_info
7
+ *
8
+ * Note: Tool documentation is lazy-loaded from tool-docs.ts to save tokens.
9
+ * This saves ~8,000 tokens per schema load.
7
10
  */
8
11
  import type { Handler, HandlerRegistry } from './types.js';
9
12
  export declare const discoverTools: Handler;