@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.
- package/README.md +1 -1
- package/dist/api-client.d.ts +120 -2
- package/dist/api-client.js +51 -5
- package/dist/handlers/bodies-of-work.js +84 -50
- package/dist/handlers/cost.js +62 -54
- package/dist/handlers/decisions.js +29 -16
- package/dist/handlers/deployment.js +114 -107
- package/dist/handlers/discovery.d.ts +3 -0
- package/dist/handlers/discovery.js +55 -657
- package/dist/handlers/fallback.js +42 -28
- package/dist/handlers/file-checkouts.d.ts +18 -0
- package/dist/handlers/file-checkouts.js +101 -0
- package/dist/handlers/findings.d.ts +14 -1
- package/dist/handlers/findings.js +104 -28
- package/dist/handlers/git-issues.js +36 -32
- package/dist/handlers/ideas.js +44 -26
- package/dist/handlers/index.d.ts +2 -0
- package/dist/handlers/index.js +6 -0
- package/dist/handlers/milestones.js +34 -27
- package/dist/handlers/organizations.js +86 -78
- package/dist/handlers/progress.js +22 -11
- package/dist/handlers/project.js +62 -22
- package/dist/handlers/requests.js +15 -11
- package/dist/handlers/roles.d.ts +18 -0
- package/dist/handlers/roles.js +130 -0
- package/dist/handlers/session.js +52 -15
- package/dist/handlers/sprints.js +78 -65
- package/dist/handlers/tasks.js +135 -74
- package/dist/handlers/tool-docs.d.ts +4 -3
- package/dist/handlers/tool-docs.js +252 -5
- package/dist/handlers/validation.js +30 -14
- package/dist/index.js +25 -7
- package/dist/tools.js +417 -4
- package/package.json +1 -1
- package/src/api-client.ts +161 -8
- package/src/handlers/__test-setup__.ts +12 -0
- package/src/handlers/bodies-of-work.ts +127 -111
- package/src/handlers/cost.test.ts +34 -44
- package/src/handlers/cost.ts +77 -92
- package/src/handlers/decisions.test.ts +3 -2
- package/src/handlers/decisions.ts +32 -27
- package/src/handlers/deployment.ts +144 -190
- package/src/handlers/discovery.test.ts +4 -5
- package/src/handlers/discovery.ts +60 -746
- package/src/handlers/fallback.test.ts +78 -0
- package/src/handlers/fallback.ts +51 -38
- package/src/handlers/file-checkouts.test.ts +477 -0
- package/src/handlers/file-checkouts.ts +127 -0
- package/src/handlers/findings.test.ts +274 -2
- package/src/handlers/findings.ts +123 -57
- package/src/handlers/git-issues.ts +40 -80
- package/src/handlers/ideas.ts +56 -54
- package/src/handlers/index.ts +6 -0
- package/src/handlers/milestones.test.ts +1 -1
- package/src/handlers/milestones.ts +47 -45
- package/src/handlers/organizations.ts +104 -129
- package/src/handlers/progress.ts +24 -22
- package/src/handlers/project.ts +89 -57
- package/src/handlers/requests.ts +18 -14
- package/src/handlers/roles.test.ts +303 -0
- package/src/handlers/roles.ts +208 -0
- package/src/handlers/session.test.ts +37 -2
- package/src/handlers/session.ts +64 -21
- package/src/handlers/sprints.ts +114 -134
- package/src/handlers/tasks.test.ts +61 -0
- package/src/handlers/tasks.ts +170 -139
- package/src/handlers/tool-docs.ts +1024 -0
- package/src/handlers/validation.test.ts +53 -1
- package/src/handlers/validation.ts +32 -21
- package/src/index.ts +25 -7
- package/src/tools.ts +417 -4
- package/dist/config/tool-categories.d.ts +0 -31
- package/dist/config/tool-categories.js +0 -253
- package/dist/knowledge.d.ts +0 -6
- package/dist/knowledge.js +0 -218
- package/src/knowledge.ts +0 -230
package/README.md
CHANGED
|
@@ -13,7 +13,7 @@ Use directly in your MCP config without installing:
|
|
|
13
13
|
"mcpServers": {
|
|
14
14
|
"vibescope": {
|
|
15
15
|
"command": "npx",
|
|
16
|
-
"args": ["-y", "@vibescope/mcp-server"],
|
|
16
|
+
"args": ["-y", "-p", "@vibescope/mcp-server", "vibescope-mcp"],
|
|
17
17
|
"env": {
|
|
18
18
|
"VIBESCOPE_API_KEY": "your-api-key"
|
|
19
19
|
}
|
package/dist/api-client.d.ts
CHANGED
|
@@ -81,7 +81,9 @@ export declare class VibescopeApiClient {
|
|
|
81
81
|
};
|
|
82
82
|
error?: string;
|
|
83
83
|
}>>;
|
|
84
|
-
heartbeat(sessionId: string
|
|
84
|
+
heartbeat(sessionId: string, options?: {
|
|
85
|
+
current_worktree_path?: string | null;
|
|
86
|
+
}): Promise<ApiResponse<{
|
|
85
87
|
success: boolean;
|
|
86
88
|
session_id: string;
|
|
87
89
|
timestamp: string;
|
|
@@ -207,6 +209,7 @@ export declare class VibescopeApiClient {
|
|
|
207
209
|
estimated_minutes?: number;
|
|
208
210
|
blocking?: boolean;
|
|
209
211
|
session_id?: string;
|
|
212
|
+
task_type?: string;
|
|
210
213
|
}): Promise<ApiResponse<{
|
|
211
214
|
success: boolean;
|
|
212
215
|
task_id: string;
|
|
@@ -276,6 +279,20 @@ export declare class VibescopeApiClient {
|
|
|
276
279
|
}): Promise<ApiResponse<{
|
|
277
280
|
success: boolean;
|
|
278
281
|
task_id: string;
|
|
282
|
+
git_workflow?: {
|
|
283
|
+
workflow: string;
|
|
284
|
+
base_branch: string;
|
|
285
|
+
suggested_branch: string;
|
|
286
|
+
worktree_required: boolean;
|
|
287
|
+
};
|
|
288
|
+
worktree_setup?: {
|
|
289
|
+
message: string;
|
|
290
|
+
commands: string[];
|
|
291
|
+
worktree_path: string;
|
|
292
|
+
branch_name: string;
|
|
293
|
+
cleanup_command: string;
|
|
294
|
+
};
|
|
295
|
+
next_step?: string;
|
|
279
296
|
}>>;
|
|
280
297
|
completeTask(taskId: string, params: {
|
|
281
298
|
summary?: string;
|
|
@@ -297,6 +314,7 @@ export declare class VibescopeApiClient {
|
|
|
297
314
|
deployment?: string;
|
|
298
315
|
};
|
|
299
316
|
next_action: string;
|
|
317
|
+
warnings?: string[];
|
|
300
318
|
}>>;
|
|
301
319
|
deleteTask(taskId: string): Promise<ApiResponse<{
|
|
302
320
|
success: boolean;
|
|
@@ -358,7 +376,11 @@ export declare class VibescopeApiClient {
|
|
|
358
376
|
deleteBlocker(blockerId: string): Promise<ApiResponse<{
|
|
359
377
|
success: boolean;
|
|
360
378
|
}>>;
|
|
361
|
-
getDecisions(projectId: string
|
|
379
|
+
getDecisions(projectId: string, options?: {
|
|
380
|
+
limit?: number;
|
|
381
|
+
offset?: number;
|
|
382
|
+
search_query?: string;
|
|
383
|
+
}): Promise<ApiResponse<{
|
|
362
384
|
decisions: Array<{
|
|
363
385
|
id: string;
|
|
364
386
|
title: string;
|
|
@@ -434,6 +456,9 @@ export declare class VibescopeApiClient {
|
|
|
434
456
|
severity?: string;
|
|
435
457
|
status?: string;
|
|
436
458
|
limit?: number;
|
|
459
|
+
offset?: number;
|
|
460
|
+
search_query?: string;
|
|
461
|
+
summary_only?: boolean;
|
|
437
462
|
}): Promise<ApiResponse<{
|
|
438
463
|
findings: Array<{
|
|
439
464
|
id: string;
|
|
@@ -447,6 +472,14 @@ export declare class VibescopeApiClient {
|
|
|
447
472
|
resolution_note?: string;
|
|
448
473
|
created_at: string;
|
|
449
474
|
}>;
|
|
475
|
+
total_count?: number;
|
|
476
|
+
has_more?: boolean;
|
|
477
|
+
}>>;
|
|
478
|
+
getFindingsStats(projectId: string): Promise<ApiResponse<{
|
|
479
|
+
total: number;
|
|
480
|
+
by_status: Record<string, number>;
|
|
481
|
+
by_severity: Record<string, number>;
|
|
482
|
+
by_category: Record<string, number>;
|
|
450
483
|
}>>;
|
|
451
484
|
addFinding(projectId: string, params: {
|
|
452
485
|
title: string;
|
|
@@ -550,16 +583,33 @@ export declare class VibescopeApiClient {
|
|
|
550
583
|
validateTask(taskId: string, params: {
|
|
551
584
|
approved: boolean;
|
|
552
585
|
validation_notes?: string;
|
|
586
|
+
skip_pr_check?: boolean;
|
|
553
587
|
}, sessionId?: string): Promise<ApiResponse<{
|
|
554
588
|
success: boolean;
|
|
555
589
|
approved: boolean;
|
|
556
590
|
task_id: string;
|
|
557
591
|
message?: string;
|
|
592
|
+
workflow?: string;
|
|
558
593
|
}>>;
|
|
559
594
|
startFallbackActivity(projectId: string, activity: string, sessionId?: string): Promise<ApiResponse<{
|
|
560
595
|
success: boolean;
|
|
561
596
|
activity: string;
|
|
562
597
|
message: string;
|
|
598
|
+
git_workflow?: {
|
|
599
|
+
workflow: string;
|
|
600
|
+
base_branch: string;
|
|
601
|
+
worktree_recommended: boolean;
|
|
602
|
+
note: string;
|
|
603
|
+
};
|
|
604
|
+
worktree_setup?: {
|
|
605
|
+
message: string;
|
|
606
|
+
commands: string[];
|
|
607
|
+
worktree_path: string;
|
|
608
|
+
branch_name: string;
|
|
609
|
+
cleanup_command: string;
|
|
610
|
+
report_worktree: string;
|
|
611
|
+
};
|
|
612
|
+
next_step?: string;
|
|
563
613
|
}>>;
|
|
564
614
|
stopFallbackActivity(projectId: string, summary?: string, sessionId?: string): Promise<ApiResponse<{
|
|
565
615
|
success: boolean;
|
|
@@ -617,6 +667,8 @@ export declare class VibescopeApiClient {
|
|
|
617
667
|
getActivityFeed(projectId: string, params?: {
|
|
618
668
|
limit?: number;
|
|
619
669
|
since?: string;
|
|
670
|
+
types?: string[];
|
|
671
|
+
created_by?: string;
|
|
620
672
|
}): Promise<ApiResponse<{
|
|
621
673
|
activities: Array<{
|
|
622
674
|
type: string;
|
|
@@ -685,6 +737,7 @@ export declare class VibescopeApiClient {
|
|
|
685
737
|
success: boolean;
|
|
686
738
|
}>>;
|
|
687
739
|
queryKnowledgeBase(projectId: string, params?: {
|
|
740
|
+
scope?: 'summary' | 'detailed';
|
|
688
741
|
categories?: string[];
|
|
689
742
|
limit?: number;
|
|
690
743
|
search_query?: string;
|
|
@@ -694,22 +747,35 @@ export declare class VibescopeApiClient {
|
|
|
694
747
|
title: string;
|
|
695
748
|
category: string;
|
|
696
749
|
severity: string;
|
|
750
|
+
description?: string;
|
|
697
751
|
}>;
|
|
698
752
|
decisions?: Array<{
|
|
699
753
|
id: string;
|
|
700
754
|
title: string;
|
|
701
755
|
description: string;
|
|
756
|
+
rationale?: string;
|
|
702
757
|
}>;
|
|
703
758
|
completed_tasks?: Array<{
|
|
704
759
|
id: string;
|
|
705
760
|
title: string;
|
|
706
761
|
completed_at: string;
|
|
762
|
+
summary?: string;
|
|
707
763
|
}>;
|
|
708
764
|
resolved_blockers?: Array<{
|
|
709
765
|
id: string;
|
|
710
766
|
description: string;
|
|
711
767
|
resolution_note?: string;
|
|
712
768
|
}>;
|
|
769
|
+
progress?: Array<{
|
|
770
|
+
id: string;
|
|
771
|
+
summary: string;
|
|
772
|
+
details?: string;
|
|
773
|
+
}>;
|
|
774
|
+
qa?: Array<{
|
|
775
|
+
id: string;
|
|
776
|
+
question: string;
|
|
777
|
+
answer: string;
|
|
778
|
+
}>;
|
|
713
779
|
}>>;
|
|
714
780
|
syncSession(sessionId: string, params?: {
|
|
715
781
|
total_tokens?: number;
|
|
@@ -1023,6 +1089,7 @@ export declare class VibescopeApiClient {
|
|
|
1023
1089
|
file_path?: string;
|
|
1024
1090
|
stage?: string;
|
|
1025
1091
|
blocking?: boolean;
|
|
1092
|
+
recurring?: boolean;
|
|
1026
1093
|
}): Promise<ApiResponse<{
|
|
1027
1094
|
success: boolean;
|
|
1028
1095
|
requirement_id: string;
|
|
@@ -1108,6 +1175,57 @@ export declare class VibescopeApiClient {
|
|
|
1108
1175
|
success: boolean;
|
|
1109
1176
|
project_id: string;
|
|
1110
1177
|
}>>;
|
|
1178
|
+
getHelpTopic(slug: string): Promise<ApiResponse<{
|
|
1179
|
+
slug: string;
|
|
1180
|
+
title: string;
|
|
1181
|
+
content: string;
|
|
1182
|
+
} | null>>;
|
|
1183
|
+
getHelpTopics(): Promise<ApiResponse<Array<{
|
|
1184
|
+
slug: string;
|
|
1185
|
+
title: string;
|
|
1186
|
+
}>>>;
|
|
1187
|
+
checkoutFile(projectId: string, filePath: string, reason?: string, sessionId?: string): Promise<ApiResponse<{
|
|
1188
|
+
success: boolean;
|
|
1189
|
+
checkout_id: string;
|
|
1190
|
+
file_path: string;
|
|
1191
|
+
already_checked_out?: boolean;
|
|
1192
|
+
message: string;
|
|
1193
|
+
}>>;
|
|
1194
|
+
checkinFile(params: {
|
|
1195
|
+
checkout_id?: string;
|
|
1196
|
+
project_id?: string;
|
|
1197
|
+
file_path?: string;
|
|
1198
|
+
summary?: string;
|
|
1199
|
+
}, sessionId?: string): Promise<ApiResponse<{
|
|
1200
|
+
success: boolean;
|
|
1201
|
+
checkout_id: string;
|
|
1202
|
+
message: string;
|
|
1203
|
+
}>>;
|
|
1204
|
+
getFileCheckouts(projectId: string, options?: {
|
|
1205
|
+
status?: string;
|
|
1206
|
+
file_path?: string;
|
|
1207
|
+
limit?: number;
|
|
1208
|
+
}): Promise<ApiResponse<{
|
|
1209
|
+
checkouts: Array<{
|
|
1210
|
+
id: string;
|
|
1211
|
+
file_path: string;
|
|
1212
|
+
status: string;
|
|
1213
|
+
checked_out_at: string;
|
|
1214
|
+
checkout_reason?: string;
|
|
1215
|
+
checked_in_at?: string;
|
|
1216
|
+
checkin_summary?: string;
|
|
1217
|
+
checked_out_by?: string;
|
|
1218
|
+
}>;
|
|
1219
|
+
}>>;
|
|
1220
|
+
abandonCheckout(params: {
|
|
1221
|
+
checkout_id?: string;
|
|
1222
|
+
project_id?: string;
|
|
1223
|
+
file_path?: string;
|
|
1224
|
+
}): Promise<ApiResponse<{
|
|
1225
|
+
success: boolean;
|
|
1226
|
+
checkout_id: string;
|
|
1227
|
+
message: string;
|
|
1228
|
+
}>>;
|
|
1111
1229
|
}
|
|
1112
1230
|
export declare function getApiClient(): VibescopeApiClient;
|
|
1113
1231
|
export declare function initApiClient(config: ApiClientConfig): VibescopeApiClient;
|
package/dist/api-client.js
CHANGED
|
@@ -28,7 +28,8 @@ export class VibescopeApiClient {
|
|
|
28
28
|
return {
|
|
29
29
|
ok: false,
|
|
30
30
|
status: response.status,
|
|
31
|
-
error: data.error || `HTTP ${response.status}
|
|
31
|
+
error: data.error || `HTTP ${response.status}`,
|
|
32
|
+
data // Include full response data for additional error context
|
|
32
33
|
};
|
|
33
34
|
}
|
|
34
35
|
return {
|
|
@@ -55,9 +56,10 @@ export class VibescopeApiClient {
|
|
|
55
56
|
async startSession(params) {
|
|
56
57
|
return this.request('POST', '/api/mcp/sessions/start', params);
|
|
57
58
|
}
|
|
58
|
-
async heartbeat(sessionId) {
|
|
59
|
+
async heartbeat(sessionId, options) {
|
|
59
60
|
return this.request('POST', '/api/mcp/sessions/heartbeat', {
|
|
60
|
-
session_id: sessionId
|
|
61
|
+
session_id: sessionId,
|
|
62
|
+
...options
|
|
61
63
|
});
|
|
62
64
|
}
|
|
63
65
|
async endSession(sessionId) {
|
|
@@ -170,8 +172,8 @@ export class VibescopeApiClient {
|
|
|
170
172
|
// ============================================================================
|
|
171
173
|
// Decision endpoints
|
|
172
174
|
// ============================================================================
|
|
173
|
-
async getDecisions(projectId) {
|
|
174
|
-
return this.proxy('get_decisions', { project_id: projectId });
|
|
175
|
+
async getDecisions(projectId, options) {
|
|
176
|
+
return this.proxy('get_decisions', { project_id: projectId, ...options });
|
|
175
177
|
}
|
|
176
178
|
async logDecision(projectId, params, sessionId) {
|
|
177
179
|
return this.proxy('log_decision', {
|
|
@@ -221,6 +223,11 @@ export class VibescopeApiClient {
|
|
|
221
223
|
...params
|
|
222
224
|
});
|
|
223
225
|
}
|
|
226
|
+
async getFindingsStats(projectId) {
|
|
227
|
+
return this.proxy('get_findings_stats', {
|
|
228
|
+
project_id: projectId
|
|
229
|
+
});
|
|
230
|
+
}
|
|
224
231
|
async addFinding(projectId, params, sessionId) {
|
|
225
232
|
return this.proxy('add_finding', {
|
|
226
233
|
project_id: projectId,
|
|
@@ -679,6 +686,45 @@ export class VibescopeApiClient {
|
|
|
679
686
|
readme_content: readmeContent
|
|
680
687
|
});
|
|
681
688
|
}
|
|
689
|
+
// ============================================================================
|
|
690
|
+
// Help Topics (database-backed)
|
|
691
|
+
// ============================================================================
|
|
692
|
+
async getHelpTopic(slug) {
|
|
693
|
+
return this.proxy('get_help_topic', { slug });
|
|
694
|
+
}
|
|
695
|
+
async getHelpTopics() {
|
|
696
|
+
return this.proxy('get_help_topics', {});
|
|
697
|
+
}
|
|
698
|
+
// ============================================================================
|
|
699
|
+
// File Checkout endpoints (multi-agent coordination)
|
|
700
|
+
// ============================================================================
|
|
701
|
+
async checkoutFile(projectId, filePath, reason, sessionId) {
|
|
702
|
+
return this.proxy('checkout_file', {
|
|
703
|
+
project_id: projectId,
|
|
704
|
+
file_path: filePath,
|
|
705
|
+
reason
|
|
706
|
+
}, sessionId ? {
|
|
707
|
+
session_id: sessionId,
|
|
708
|
+
persona: null,
|
|
709
|
+
instance_id: ''
|
|
710
|
+
} : undefined);
|
|
711
|
+
}
|
|
712
|
+
async checkinFile(params, sessionId) {
|
|
713
|
+
return this.proxy('checkin_file', params, sessionId ? {
|
|
714
|
+
session_id: sessionId,
|
|
715
|
+
persona: null,
|
|
716
|
+
instance_id: ''
|
|
717
|
+
} : undefined);
|
|
718
|
+
}
|
|
719
|
+
async getFileCheckouts(projectId, options) {
|
|
720
|
+
return this.proxy('get_file_checkouts', {
|
|
721
|
+
project_id: projectId,
|
|
722
|
+
...options
|
|
723
|
+
});
|
|
724
|
+
}
|
|
725
|
+
async abandonCheckout(params) {
|
|
726
|
+
return this.proxy('abandon_checkout', params);
|
|
727
|
+
}
|
|
682
728
|
}
|
|
683
729
|
// Singleton instance
|
|
684
730
|
let apiClient = null;
|
|
@@ -17,13 +17,78 @@
|
|
|
17
17
|
*
|
|
18
18
|
* MIGRATED: Uses Vibescope API client instead of direct Supabase
|
|
19
19
|
*/
|
|
20
|
-
import {
|
|
20
|
+
import { parseArgs, uuidValidator, createEnumValidator } from '../validators.js';
|
|
21
21
|
import { getApiClient } from '../api-client.js';
|
|
22
|
+
const BODY_OF_WORK_STATUSES = ['draft', 'active', 'completed', 'cancelled'];
|
|
23
|
+
const TASK_PHASES = ['pre', 'core', 'post'];
|
|
24
|
+
const DEPLOY_ENVIRONMENTS = ['development', 'staging', 'production'];
|
|
25
|
+
const VERSION_BUMPS = ['patch', 'minor', 'major'];
|
|
26
|
+
const DEPLOY_TRIGGERS = ['all_completed', 'all_completed_validated'];
|
|
27
|
+
// ============================================================================
|
|
28
|
+
// Argument Schemas
|
|
29
|
+
// ============================================================================
|
|
30
|
+
const createBodyOfWorkSchema = {
|
|
31
|
+
project_id: { type: 'string', required: true, validate: uuidValidator },
|
|
32
|
+
title: { type: 'string', required: true },
|
|
33
|
+
description: { type: 'string' },
|
|
34
|
+
auto_deploy_on_completion: { type: 'boolean' },
|
|
35
|
+
deploy_environment: { type: 'string', validate: createEnumValidator(DEPLOY_ENVIRONMENTS) },
|
|
36
|
+
deploy_version_bump: { type: 'string', validate: createEnumValidator(VERSION_BUMPS) },
|
|
37
|
+
deploy_trigger: { type: 'string', validate: createEnumValidator(DEPLOY_TRIGGERS) },
|
|
38
|
+
};
|
|
39
|
+
const updateBodyOfWorkSchema = {
|
|
40
|
+
body_of_work_id: { type: 'string', required: true, validate: uuidValidator },
|
|
41
|
+
title: { type: 'string' },
|
|
42
|
+
description: { type: 'string' },
|
|
43
|
+
auto_deploy_on_completion: { type: 'boolean' },
|
|
44
|
+
deploy_environment: { type: 'string', validate: createEnumValidator(DEPLOY_ENVIRONMENTS) },
|
|
45
|
+
deploy_version_bump: { type: 'string', validate: createEnumValidator(VERSION_BUMPS) },
|
|
46
|
+
deploy_trigger: { type: 'string', validate: createEnumValidator(DEPLOY_TRIGGERS) },
|
|
47
|
+
};
|
|
48
|
+
const getBodyOfWorkSchema = {
|
|
49
|
+
body_of_work_id: { type: 'string', required: true, validate: uuidValidator },
|
|
50
|
+
summary_only: { type: 'boolean', default: false },
|
|
51
|
+
};
|
|
52
|
+
const getBodiesOfWorkSchema = {
|
|
53
|
+
project_id: { type: 'string', required: true, validate: uuidValidator },
|
|
54
|
+
status: { type: 'string', validate: createEnumValidator(BODY_OF_WORK_STATUSES) },
|
|
55
|
+
limit: { type: 'number', default: 50 },
|
|
56
|
+
offset: { type: 'number', default: 0 },
|
|
57
|
+
search_query: { type: 'string' },
|
|
58
|
+
};
|
|
59
|
+
const deleteBodyOfWorkSchema = {
|
|
60
|
+
body_of_work_id: { type: 'string', required: true, validate: uuidValidator },
|
|
61
|
+
};
|
|
62
|
+
const addTaskToBodyOfWorkSchema = {
|
|
63
|
+
body_of_work_id: { type: 'string', required: true, validate: uuidValidator },
|
|
64
|
+
task_id: { type: 'string', required: true, validate: uuidValidator },
|
|
65
|
+
phase: { type: 'string', validate: createEnumValidator(TASK_PHASES) },
|
|
66
|
+
order_index: { type: 'number' },
|
|
67
|
+
};
|
|
68
|
+
const removeTaskFromBodyOfWorkSchema = {
|
|
69
|
+
task_id: { type: 'string', required: true, validate: uuidValidator },
|
|
70
|
+
};
|
|
71
|
+
const activateBodyOfWorkSchema = {
|
|
72
|
+
body_of_work_id: { type: 'string', required: true, validate: uuidValidator },
|
|
73
|
+
};
|
|
74
|
+
const addTaskDependencySchema = {
|
|
75
|
+
body_of_work_id: { type: 'string', required: true, validate: uuidValidator },
|
|
76
|
+
task_id: { type: 'string', required: true, validate: uuidValidator },
|
|
77
|
+
depends_on_task_id: { type: 'string', required: true, validate: uuidValidator },
|
|
78
|
+
};
|
|
79
|
+
const removeTaskDependencySchema = {
|
|
80
|
+
task_id: { type: 'string', required: true, validate: uuidValidator },
|
|
81
|
+
depends_on_task_id: { type: 'string', required: true, validate: uuidValidator },
|
|
82
|
+
};
|
|
83
|
+
const getTaskDependenciesSchema = {
|
|
84
|
+
body_of_work_id: { type: 'string', validate: uuidValidator },
|
|
85
|
+
task_id: { type: 'string', validate: uuidValidator },
|
|
86
|
+
};
|
|
87
|
+
const getNextBodyOfWorkTaskSchema = {
|
|
88
|
+
body_of_work_id: { type: 'string', required: true, validate: uuidValidator },
|
|
89
|
+
};
|
|
22
90
|
export const createBodyOfWork = async (args, ctx) => {
|
|
23
|
-
const { project_id, title, description, auto_deploy_on_completion, deploy_environment, deploy_version_bump, deploy_trigger, } = args;
|
|
24
|
-
validateRequired(project_id, 'project_id');
|
|
25
|
-
validateUUID(project_id, 'project_id');
|
|
26
|
-
validateRequired(title, 'title');
|
|
91
|
+
const { project_id, title, description, auto_deploy_on_completion, deploy_environment, deploy_version_bump, deploy_trigger, } = parseArgs(args, createBodyOfWorkSchema);
|
|
27
92
|
const { session } = ctx;
|
|
28
93
|
const apiClient = getApiClient();
|
|
29
94
|
const response = await apiClient.proxy('create_body_of_work', {
|
|
@@ -53,9 +118,7 @@ export const createBodyOfWork = async (args, ctx) => {
|
|
|
53
118
|
};
|
|
54
119
|
};
|
|
55
120
|
export const updateBodyOfWork = async (args, ctx) => {
|
|
56
|
-
const { body_of_work_id, title, description, auto_deploy_on_completion, deploy_environment, deploy_version_bump, deploy_trigger, } = args;
|
|
57
|
-
validateRequired(body_of_work_id, 'body_of_work_id');
|
|
58
|
-
validateUUID(body_of_work_id, 'body_of_work_id');
|
|
121
|
+
const { body_of_work_id, title, description, auto_deploy_on_completion, deploy_environment, deploy_version_bump, deploy_trigger, } = parseArgs(args, updateBodyOfWorkSchema);
|
|
59
122
|
// Check if any updates provided
|
|
60
123
|
if (title === undefined && description === undefined && auto_deploy_on_completion === undefined &&
|
|
61
124
|
deploy_environment === undefined && deploy_version_bump === undefined && deploy_trigger === undefined) {
|
|
@@ -77,25 +140,22 @@ export const updateBodyOfWork = async (args, ctx) => {
|
|
|
77
140
|
return { result: { success: true, body_of_work_id } };
|
|
78
141
|
};
|
|
79
142
|
export const getBodyOfWork = async (args, ctx) => {
|
|
80
|
-
const { body_of_work_id } = args;
|
|
81
|
-
validateRequired(body_of_work_id, 'body_of_work_id');
|
|
82
|
-
validateUUID(body_of_work_id, 'body_of_work_id');
|
|
143
|
+
const { body_of_work_id, summary_only } = parseArgs(args, getBodyOfWorkSchema);
|
|
83
144
|
const apiClient = getApiClient();
|
|
84
|
-
|
|
145
|
+
// Response type varies based on summary_only
|
|
146
|
+
const response = await apiClient.proxy('get_body_of_work', { body_of_work_id, summary_only });
|
|
85
147
|
if (!response.ok) {
|
|
86
148
|
throw new Error(`Failed to get body of work: ${response.error}`);
|
|
87
149
|
}
|
|
88
150
|
return { result: response.data };
|
|
89
151
|
};
|
|
90
152
|
export const getBodiesOfWork = async (args, ctx) => {
|
|
91
|
-
const { project_id, status, limit
|
|
92
|
-
validateRequired(project_id, 'project_id');
|
|
93
|
-
validateUUID(project_id, 'project_id');
|
|
153
|
+
const { project_id, status, limit, offset, search_query } = parseArgs(args, getBodiesOfWorkSchema);
|
|
94
154
|
const apiClient = getApiClient();
|
|
95
155
|
const response = await apiClient.proxy('get_bodies_of_work', {
|
|
96
156
|
project_id,
|
|
97
157
|
status,
|
|
98
|
-
limit: Math.min(limit, 100),
|
|
158
|
+
limit: Math.min(limit ?? 50, 100),
|
|
99
159
|
offset,
|
|
100
160
|
search_query
|
|
101
161
|
});
|
|
@@ -105,9 +165,7 @@ export const getBodiesOfWork = async (args, ctx) => {
|
|
|
105
165
|
return { result: response.data };
|
|
106
166
|
};
|
|
107
167
|
export const deleteBodyOfWork = async (args, ctx) => {
|
|
108
|
-
const { body_of_work_id } = args;
|
|
109
|
-
validateRequired(body_of_work_id, 'body_of_work_id');
|
|
110
|
-
validateUUID(body_of_work_id, 'body_of_work_id');
|
|
168
|
+
const { body_of_work_id } = parseArgs(args, deleteBodyOfWorkSchema);
|
|
111
169
|
const apiClient = getApiClient();
|
|
112
170
|
const response = await apiClient.proxy('delete_body_of_work', {
|
|
113
171
|
body_of_work_id
|
|
@@ -118,11 +176,7 @@ export const deleteBodyOfWork = async (args, ctx) => {
|
|
|
118
176
|
return { result: { success: true, message: 'Body of work deleted. Tasks are preserved.' } };
|
|
119
177
|
};
|
|
120
178
|
export const addTaskToBodyOfWork = async (args, ctx) => {
|
|
121
|
-
const { body_of_work_id, task_id, phase, order_index } = args;
|
|
122
|
-
validateRequired(body_of_work_id, 'body_of_work_id');
|
|
123
|
-
validateUUID(body_of_work_id, 'body_of_work_id');
|
|
124
|
-
validateRequired(task_id, 'task_id');
|
|
125
|
-
validateUUID(task_id, 'task_id');
|
|
179
|
+
const { body_of_work_id, task_id, phase, order_index } = parseArgs(args, addTaskToBodyOfWorkSchema);
|
|
126
180
|
const apiClient = getApiClient();
|
|
127
181
|
const response = await apiClient.proxy('add_task_to_body_of_work', {
|
|
128
182
|
body_of_work_id,
|
|
@@ -136,9 +190,7 @@ export const addTaskToBodyOfWork = async (args, ctx) => {
|
|
|
136
190
|
return { result: response.data };
|
|
137
191
|
};
|
|
138
192
|
export const removeTaskFromBodyOfWork = async (args, ctx) => {
|
|
139
|
-
const { task_id } = args;
|
|
140
|
-
validateRequired(task_id, 'task_id');
|
|
141
|
-
validateUUID(task_id, 'task_id');
|
|
193
|
+
const { task_id } = parseArgs(args, removeTaskFromBodyOfWorkSchema);
|
|
142
194
|
const apiClient = getApiClient();
|
|
143
195
|
const response = await apiClient.proxy('remove_task_from_body_of_work', { task_id });
|
|
144
196
|
if (!response.ok) {
|
|
@@ -147,9 +199,7 @@ export const removeTaskFromBodyOfWork = async (args, ctx) => {
|
|
|
147
199
|
return { result: response.data };
|
|
148
200
|
};
|
|
149
201
|
export const activateBodyOfWork = async (args, ctx) => {
|
|
150
|
-
const { body_of_work_id } = args;
|
|
151
|
-
validateRequired(body_of_work_id, 'body_of_work_id');
|
|
152
|
-
validateUUID(body_of_work_id, 'body_of_work_id');
|
|
202
|
+
const { body_of_work_id } = parseArgs(args, activateBodyOfWorkSchema);
|
|
153
203
|
const apiClient = getApiClient();
|
|
154
204
|
const response = await apiClient.proxy('activate_body_of_work', { body_of_work_id });
|
|
155
205
|
if (!response.ok) {
|
|
@@ -158,13 +208,7 @@ export const activateBodyOfWork = async (args, ctx) => {
|
|
|
158
208
|
return { result: response.data };
|
|
159
209
|
};
|
|
160
210
|
export const addTaskDependency = async (args, ctx) => {
|
|
161
|
-
const { body_of_work_id, task_id, depends_on_task_id } = args;
|
|
162
|
-
validateRequired(body_of_work_id, 'body_of_work_id');
|
|
163
|
-
validateUUID(body_of_work_id, 'body_of_work_id');
|
|
164
|
-
validateRequired(task_id, 'task_id');
|
|
165
|
-
validateUUID(task_id, 'task_id');
|
|
166
|
-
validateRequired(depends_on_task_id, 'depends_on_task_id');
|
|
167
|
-
validateUUID(depends_on_task_id, 'depends_on_task_id');
|
|
211
|
+
const { body_of_work_id, task_id, depends_on_task_id } = parseArgs(args, addTaskDependencySchema);
|
|
168
212
|
if (task_id === depends_on_task_id) {
|
|
169
213
|
throw new Error('A task cannot depend on itself');
|
|
170
214
|
}
|
|
@@ -180,11 +224,7 @@ export const addTaskDependency = async (args, ctx) => {
|
|
|
180
224
|
return { result: response.data };
|
|
181
225
|
};
|
|
182
226
|
export const removeTaskDependency = async (args, ctx) => {
|
|
183
|
-
const { task_id, depends_on_task_id } = args;
|
|
184
|
-
validateRequired(task_id, 'task_id');
|
|
185
|
-
validateUUID(task_id, 'task_id');
|
|
186
|
-
validateRequired(depends_on_task_id, 'depends_on_task_id');
|
|
187
|
-
validateUUID(depends_on_task_id, 'depends_on_task_id');
|
|
227
|
+
const { task_id, depends_on_task_id } = parseArgs(args, removeTaskDependencySchema);
|
|
188
228
|
const apiClient = getApiClient();
|
|
189
229
|
const response = await apiClient.proxy('remove_task_dependency', {
|
|
190
230
|
task_id,
|
|
@@ -196,14 +236,10 @@ export const removeTaskDependency = async (args, ctx) => {
|
|
|
196
236
|
return { result: response.data };
|
|
197
237
|
};
|
|
198
238
|
export const getTaskDependencies = async (args, ctx) => {
|
|
199
|
-
const { body_of_work_id, task_id } = args;
|
|
239
|
+
const { body_of_work_id, task_id } = parseArgs(args, getTaskDependenciesSchema);
|
|
200
240
|
if (!body_of_work_id && !task_id) {
|
|
201
241
|
throw new Error('Either body_of_work_id or task_id is required');
|
|
202
242
|
}
|
|
203
|
-
if (body_of_work_id)
|
|
204
|
-
validateUUID(body_of_work_id, 'body_of_work_id');
|
|
205
|
-
if (task_id)
|
|
206
|
-
validateUUID(task_id, 'task_id');
|
|
207
243
|
const apiClient = getApiClient();
|
|
208
244
|
const response = await apiClient.proxy('get_task_dependencies', {
|
|
209
245
|
body_of_work_id,
|
|
@@ -215,9 +251,7 @@ export const getTaskDependencies = async (args, ctx) => {
|
|
|
215
251
|
return { result: response.data };
|
|
216
252
|
};
|
|
217
253
|
export const getNextBodyOfWorkTask = async (args, ctx) => {
|
|
218
|
-
const { body_of_work_id } = args;
|
|
219
|
-
validateRequired(body_of_work_id, 'body_of_work_id');
|
|
220
|
-
validateUUID(body_of_work_id, 'body_of_work_id');
|
|
254
|
+
const { body_of_work_id } = parseArgs(args, getNextBodyOfWorkTaskSchema);
|
|
221
255
|
const apiClient = getApiClient();
|
|
222
256
|
const response = await apiClient.proxy('get_next_body_of_work_task', { body_of_work_id });
|
|
223
257
|
if (!response.ok) {
|