@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/src/api-client.ts
CHANGED
|
@@ -47,7 +47,8 @@ export class VibescopeApiClient {
|
|
|
47
47
|
return {
|
|
48
48
|
ok: false,
|
|
49
49
|
status: response.status,
|
|
50
|
-
error: data.error || `HTTP ${response.status}
|
|
50
|
+
error: data.error || `HTTP ${response.status}`,
|
|
51
|
+
data // Include full response data for additional error context
|
|
51
52
|
};
|
|
52
53
|
}
|
|
53
54
|
|
|
@@ -137,13 +138,16 @@ export class VibescopeApiClient {
|
|
|
137
138
|
return this.request('POST', '/api/mcp/sessions/start', params);
|
|
138
139
|
}
|
|
139
140
|
|
|
140
|
-
async heartbeat(sessionId: string
|
|
141
|
+
async heartbeat(sessionId: string, options?: {
|
|
142
|
+
current_worktree_path?: string | null;
|
|
143
|
+
}): Promise<ApiResponse<{
|
|
141
144
|
success: boolean;
|
|
142
145
|
session_id: string;
|
|
143
146
|
timestamp: string;
|
|
144
147
|
}>> {
|
|
145
148
|
return this.request('POST', '/api/mcp/sessions/heartbeat', {
|
|
146
|
-
session_id: sessionId
|
|
149
|
+
session_id: sessionId,
|
|
150
|
+
...options
|
|
147
151
|
});
|
|
148
152
|
}
|
|
149
153
|
|
|
@@ -303,6 +307,7 @@ export class VibescopeApiClient {
|
|
|
303
307
|
estimated_minutes?: number;
|
|
304
308
|
blocking?: boolean;
|
|
305
309
|
session_id?: string;
|
|
310
|
+
task_type?: string;
|
|
306
311
|
}): Promise<ApiResponse<{
|
|
307
312
|
success: boolean;
|
|
308
313
|
task_id: string;
|
|
@@ -381,6 +386,20 @@ export class VibescopeApiClient {
|
|
|
381
386
|
}): Promise<ApiResponse<{
|
|
382
387
|
success: boolean;
|
|
383
388
|
task_id: string;
|
|
389
|
+
git_workflow?: {
|
|
390
|
+
workflow: string;
|
|
391
|
+
base_branch: string;
|
|
392
|
+
suggested_branch: string;
|
|
393
|
+
worktree_required: boolean;
|
|
394
|
+
};
|
|
395
|
+
worktree_setup?: {
|
|
396
|
+
message: string;
|
|
397
|
+
commands: string[];
|
|
398
|
+
worktree_path: string;
|
|
399
|
+
branch_name: string;
|
|
400
|
+
cleanup_command: string;
|
|
401
|
+
};
|
|
402
|
+
next_step?: string;
|
|
384
403
|
}>> {
|
|
385
404
|
return this.request('PATCH', `/api/mcp/tasks/${taskId}`, updates);
|
|
386
405
|
}
|
|
@@ -405,6 +424,7 @@ export class VibescopeApiClient {
|
|
|
405
424
|
deployment?: string;
|
|
406
425
|
};
|
|
407
426
|
next_action: string;
|
|
427
|
+
warnings?: string[];
|
|
408
428
|
}>> {
|
|
409
429
|
return this.request('POST', `/api/mcp/tasks/${taskId}/complete`, params);
|
|
410
430
|
}
|
|
@@ -521,7 +541,11 @@ export class VibescopeApiClient {
|
|
|
521
541
|
// ============================================================================
|
|
522
542
|
// Decision endpoints
|
|
523
543
|
// ============================================================================
|
|
524
|
-
async getDecisions(projectId: string
|
|
544
|
+
async getDecisions(projectId: string, options?: {
|
|
545
|
+
limit?: number;
|
|
546
|
+
offset?: number;
|
|
547
|
+
search_query?: string;
|
|
548
|
+
}): Promise<ApiResponse<{
|
|
525
549
|
decisions: Array<{
|
|
526
550
|
id: string;
|
|
527
551
|
title: string;
|
|
@@ -531,7 +555,7 @@ export class VibescopeApiClient {
|
|
|
531
555
|
created_at: string;
|
|
532
556
|
}>;
|
|
533
557
|
}>> {
|
|
534
|
-
return this.proxy('get_decisions', { project_id: projectId });
|
|
558
|
+
return this.proxy('get_decisions', { project_id: projectId, ...options });
|
|
535
559
|
}
|
|
536
560
|
|
|
537
561
|
async logDecision(projectId: string, params: {
|
|
@@ -642,6 +666,9 @@ export class VibescopeApiClient {
|
|
|
642
666
|
severity?: string;
|
|
643
667
|
status?: string;
|
|
644
668
|
limit?: number;
|
|
669
|
+
offset?: number;
|
|
670
|
+
search_query?: string;
|
|
671
|
+
summary_only?: boolean;
|
|
645
672
|
}): Promise<ApiResponse<{
|
|
646
673
|
findings: Array<{
|
|
647
674
|
id: string;
|
|
@@ -655,6 +682,8 @@ export class VibescopeApiClient {
|
|
|
655
682
|
resolution_note?: string;
|
|
656
683
|
created_at: string;
|
|
657
684
|
}>;
|
|
685
|
+
total_count?: number;
|
|
686
|
+
has_more?: boolean;
|
|
658
687
|
}>> {
|
|
659
688
|
return this.proxy('get_findings', {
|
|
660
689
|
project_id: projectId,
|
|
@@ -662,6 +691,17 @@ export class VibescopeApiClient {
|
|
|
662
691
|
});
|
|
663
692
|
}
|
|
664
693
|
|
|
694
|
+
async getFindingsStats(projectId: string): Promise<ApiResponse<{
|
|
695
|
+
total: number;
|
|
696
|
+
by_status: Record<string, number>;
|
|
697
|
+
by_severity: Record<string, number>;
|
|
698
|
+
by_category: Record<string, number>;
|
|
699
|
+
}>> {
|
|
700
|
+
return this.proxy('get_findings_stats', {
|
|
701
|
+
project_id: projectId
|
|
702
|
+
});
|
|
703
|
+
}
|
|
704
|
+
|
|
665
705
|
async addFinding(projectId: string, params: {
|
|
666
706
|
title: string;
|
|
667
707
|
description?: string;
|
|
@@ -839,11 +879,13 @@ export class VibescopeApiClient {
|
|
|
839
879
|
async validateTask(taskId: string, params: {
|
|
840
880
|
approved: boolean;
|
|
841
881
|
validation_notes?: string;
|
|
882
|
+
skip_pr_check?: boolean;
|
|
842
883
|
}, sessionId?: string): Promise<ApiResponse<{
|
|
843
884
|
success: boolean;
|
|
844
885
|
approved: boolean;
|
|
845
886
|
task_id: string;
|
|
846
887
|
message?: string;
|
|
888
|
+
workflow?: string;
|
|
847
889
|
}>> {
|
|
848
890
|
return this.proxy('validate_task', {
|
|
849
891
|
task_id: taskId,
|
|
@@ -858,6 +900,21 @@ export class VibescopeApiClient {
|
|
|
858
900
|
success: boolean;
|
|
859
901
|
activity: string;
|
|
860
902
|
message: string;
|
|
903
|
+
git_workflow?: {
|
|
904
|
+
workflow: string;
|
|
905
|
+
base_branch: string;
|
|
906
|
+
worktree_recommended: boolean;
|
|
907
|
+
note: string;
|
|
908
|
+
};
|
|
909
|
+
worktree_setup?: {
|
|
910
|
+
message: string;
|
|
911
|
+
commands: string[];
|
|
912
|
+
worktree_path: string;
|
|
913
|
+
branch_name: string;
|
|
914
|
+
cleanup_command: string;
|
|
915
|
+
report_worktree: string;
|
|
916
|
+
};
|
|
917
|
+
next_step?: string;
|
|
861
918
|
}>> {
|
|
862
919
|
return this.proxy('start_fallback_activity', {
|
|
863
920
|
project_id: projectId,
|
|
@@ -954,6 +1011,8 @@ export class VibescopeApiClient {
|
|
|
954
1011
|
async getActivityFeed(projectId: string, params?: {
|
|
955
1012
|
limit?: number;
|
|
956
1013
|
since?: string;
|
|
1014
|
+
types?: string[];
|
|
1015
|
+
created_by?: string;
|
|
957
1016
|
}): Promise<ApiResponse<{
|
|
958
1017
|
activities: Array<{
|
|
959
1018
|
type: string;
|
|
@@ -1088,14 +1147,17 @@ export class VibescopeApiClient {
|
|
|
1088
1147
|
// Knowledge base endpoint
|
|
1089
1148
|
// ============================================================================
|
|
1090
1149
|
async queryKnowledgeBase(projectId: string, params?: {
|
|
1150
|
+
scope?: 'summary' | 'detailed';
|
|
1091
1151
|
categories?: string[];
|
|
1092
1152
|
limit?: number;
|
|
1093
1153
|
search_query?: string;
|
|
1094
1154
|
}): Promise<ApiResponse<{
|
|
1095
|
-
findings?: Array<{ id: string; title: string; category: string; severity: string }>;
|
|
1096
|
-
decisions?: Array<{ id: string; title: string; description: string }>;
|
|
1097
|
-
completed_tasks?: Array<{ id: string; title: string; completed_at: string }>;
|
|
1155
|
+
findings?: Array<{ id: string; title: string; category: string; severity: string; description?: string }>;
|
|
1156
|
+
decisions?: Array<{ id: string; title: string; description: string; rationale?: string }>;
|
|
1157
|
+
completed_tasks?: Array<{ id: string; title: string; completed_at: string; summary?: string }>;
|
|
1098
1158
|
resolved_blockers?: Array<{ id: string; description: string; resolution_note?: string }>;
|
|
1159
|
+
progress?: Array<{ id: string; summary: string; details?: string }>;
|
|
1160
|
+
qa?: Array<{ id: string; question: string; answer: string }>;
|
|
1099
1161
|
}>> {
|
|
1100
1162
|
return this.proxy('query_knowledge_base', {
|
|
1101
1163
|
project_id: projectId,
|
|
@@ -1591,6 +1653,7 @@ export class VibescopeApiClient {
|
|
|
1591
1653
|
file_path?: string;
|
|
1592
1654
|
stage?: string;
|
|
1593
1655
|
blocking?: boolean;
|
|
1656
|
+
recurring?: boolean;
|
|
1594
1657
|
}): Promise<ApiResponse<{
|
|
1595
1658
|
success: boolean;
|
|
1596
1659
|
requirement_id: string;
|
|
@@ -1730,6 +1793,96 @@ export class VibescopeApiClient {
|
|
|
1730
1793
|
readme_content: readmeContent
|
|
1731
1794
|
});
|
|
1732
1795
|
}
|
|
1796
|
+
|
|
1797
|
+
// ============================================================================
|
|
1798
|
+
// Help Topics (database-backed)
|
|
1799
|
+
// ============================================================================
|
|
1800
|
+
async getHelpTopic(slug: string): Promise<ApiResponse<{
|
|
1801
|
+
slug: string;
|
|
1802
|
+
title: string;
|
|
1803
|
+
content: string;
|
|
1804
|
+
} | null>> {
|
|
1805
|
+
return this.proxy('get_help_topic', { slug });
|
|
1806
|
+
}
|
|
1807
|
+
|
|
1808
|
+
async getHelpTopics(): Promise<ApiResponse<Array<{
|
|
1809
|
+
slug: string;
|
|
1810
|
+
title: string;
|
|
1811
|
+
}>>> {
|
|
1812
|
+
return this.proxy('get_help_topics', {});
|
|
1813
|
+
}
|
|
1814
|
+
|
|
1815
|
+
// ============================================================================
|
|
1816
|
+
// File Checkout endpoints (multi-agent coordination)
|
|
1817
|
+
// ============================================================================
|
|
1818
|
+
async checkoutFile(projectId: string, filePath: string, reason?: string, sessionId?: string): Promise<ApiResponse<{
|
|
1819
|
+
success: boolean;
|
|
1820
|
+
checkout_id: string;
|
|
1821
|
+
file_path: string;
|
|
1822
|
+
already_checked_out?: boolean;
|
|
1823
|
+
message: string;
|
|
1824
|
+
}>> {
|
|
1825
|
+
return this.proxy('checkout_file', {
|
|
1826
|
+
project_id: projectId,
|
|
1827
|
+
file_path: filePath,
|
|
1828
|
+
reason
|
|
1829
|
+
}, sessionId ? {
|
|
1830
|
+
session_id: sessionId,
|
|
1831
|
+
persona: null,
|
|
1832
|
+
instance_id: ''
|
|
1833
|
+
} : undefined);
|
|
1834
|
+
}
|
|
1835
|
+
|
|
1836
|
+
async checkinFile(params: {
|
|
1837
|
+
checkout_id?: string;
|
|
1838
|
+
project_id?: string;
|
|
1839
|
+
file_path?: string;
|
|
1840
|
+
summary?: string;
|
|
1841
|
+
}, sessionId?: string): Promise<ApiResponse<{
|
|
1842
|
+
success: boolean;
|
|
1843
|
+
checkout_id: string;
|
|
1844
|
+
message: string;
|
|
1845
|
+
}>> {
|
|
1846
|
+
return this.proxy('checkin_file', params, sessionId ? {
|
|
1847
|
+
session_id: sessionId,
|
|
1848
|
+
persona: null,
|
|
1849
|
+
instance_id: ''
|
|
1850
|
+
} : undefined);
|
|
1851
|
+
}
|
|
1852
|
+
|
|
1853
|
+
async getFileCheckouts(projectId: string, options?: {
|
|
1854
|
+
status?: string;
|
|
1855
|
+
file_path?: string;
|
|
1856
|
+
limit?: number;
|
|
1857
|
+
}): Promise<ApiResponse<{
|
|
1858
|
+
checkouts: Array<{
|
|
1859
|
+
id: string;
|
|
1860
|
+
file_path: string;
|
|
1861
|
+
status: string;
|
|
1862
|
+
checked_out_at: string;
|
|
1863
|
+
checkout_reason?: string;
|
|
1864
|
+
checked_in_at?: string;
|
|
1865
|
+
checkin_summary?: string;
|
|
1866
|
+
checked_out_by?: string;
|
|
1867
|
+
}>;
|
|
1868
|
+
}>> {
|
|
1869
|
+
return this.proxy('get_file_checkouts', {
|
|
1870
|
+
project_id: projectId,
|
|
1871
|
+
...options
|
|
1872
|
+
});
|
|
1873
|
+
}
|
|
1874
|
+
|
|
1875
|
+
async abandonCheckout(params: {
|
|
1876
|
+
checkout_id?: string;
|
|
1877
|
+
project_id?: string;
|
|
1878
|
+
file_path?: string;
|
|
1879
|
+
}): Promise<ApiResponse<{
|
|
1880
|
+
success: boolean;
|
|
1881
|
+
checkout_id: string;
|
|
1882
|
+
message: string;
|
|
1883
|
+
}>> {
|
|
1884
|
+
return this.proxy('abandon_checkout', params);
|
|
1885
|
+
}
|
|
1733
1886
|
}
|
|
1734
1887
|
|
|
1735
1888
|
// Singleton instance
|
|
@@ -77,8 +77,10 @@ export const mockApiClient = {
|
|
|
77
77
|
// Findings
|
|
78
78
|
addFinding: vi.fn(),
|
|
79
79
|
getFindings: vi.fn(),
|
|
80
|
+
getFindingsStats: vi.fn(),
|
|
80
81
|
updateFinding: vi.fn(),
|
|
81
82
|
deleteFinding: vi.fn(),
|
|
83
|
+
queryKnowledgeBase: vi.fn(),
|
|
82
84
|
|
|
83
85
|
// Requests
|
|
84
86
|
getPendingRequests: vi.fn(),
|
|
@@ -164,6 +166,16 @@ export const mockApiClient = {
|
|
|
164
166
|
claimValidation: vi.fn(),
|
|
165
167
|
validateTask: vi.fn(),
|
|
166
168
|
|
|
169
|
+
// Help Topics
|
|
170
|
+
getHelpTopic: vi.fn(),
|
|
171
|
+
getHelpTopics: vi.fn(),
|
|
172
|
+
|
|
173
|
+
// File Checkouts
|
|
174
|
+
checkoutFile: vi.fn(),
|
|
175
|
+
checkinFile: vi.fn(),
|
|
176
|
+
getFileCheckouts: vi.fn(),
|
|
177
|
+
abandonCheckout: vi.fn(),
|
|
178
|
+
|
|
167
179
|
// Proxy (generic)
|
|
168
180
|
proxy: vi.fn(),
|
|
169
181
|
};
|
|
@@ -19,14 +19,96 @@
|
|
|
19
19
|
*/
|
|
20
20
|
|
|
21
21
|
import type { Handler, HandlerRegistry } from './types.js';
|
|
22
|
-
import {
|
|
22
|
+
import { parseArgs, uuidValidator, createEnumValidator } from '../validators.js';
|
|
23
23
|
import { getApiClient } from '../api-client.js';
|
|
24
24
|
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
25
|
+
const BODY_OF_WORK_STATUSES = ['draft', 'active', 'completed', 'cancelled'] as const;
|
|
26
|
+
const TASK_PHASES = ['pre', 'core', 'post'] as const;
|
|
27
|
+
const DEPLOY_ENVIRONMENTS = ['development', 'staging', 'production'] as const;
|
|
28
|
+
const VERSION_BUMPS = ['patch', 'minor', 'major'] as const;
|
|
29
|
+
const DEPLOY_TRIGGERS = ['all_completed', 'all_completed_validated'] as const;
|
|
30
|
+
|
|
31
|
+
type BodyOfWorkStatus = typeof BODY_OF_WORK_STATUSES[number];
|
|
32
|
+
type TaskPhase = typeof TASK_PHASES[number];
|
|
33
|
+
type DeployEnvironment = typeof DEPLOY_ENVIRONMENTS[number];
|
|
34
|
+
type VersionBump = typeof VERSION_BUMPS[number];
|
|
35
|
+
type DeployTrigger = typeof DEPLOY_TRIGGERS[number];
|
|
36
|
+
|
|
37
|
+
// ============================================================================
|
|
38
|
+
// Argument Schemas
|
|
39
|
+
// ============================================================================
|
|
40
|
+
|
|
41
|
+
const createBodyOfWorkSchema = {
|
|
42
|
+
project_id: { type: 'string' as const, required: true as const, validate: uuidValidator },
|
|
43
|
+
title: { type: 'string' as const, required: true as const },
|
|
44
|
+
description: { type: 'string' as const },
|
|
45
|
+
auto_deploy_on_completion: { type: 'boolean' as const },
|
|
46
|
+
deploy_environment: { type: 'string' as const, validate: createEnumValidator(DEPLOY_ENVIRONMENTS) },
|
|
47
|
+
deploy_version_bump: { type: 'string' as const, validate: createEnumValidator(VERSION_BUMPS) },
|
|
48
|
+
deploy_trigger: { type: 'string' as const, validate: createEnumValidator(DEPLOY_TRIGGERS) },
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
const updateBodyOfWorkSchema = {
|
|
52
|
+
body_of_work_id: { type: 'string' as const, required: true as const, validate: uuidValidator },
|
|
53
|
+
title: { type: 'string' as const },
|
|
54
|
+
description: { type: 'string' as const },
|
|
55
|
+
auto_deploy_on_completion: { type: 'boolean' as const },
|
|
56
|
+
deploy_environment: { type: 'string' as const, validate: createEnumValidator(DEPLOY_ENVIRONMENTS) },
|
|
57
|
+
deploy_version_bump: { type: 'string' as const, validate: createEnumValidator(VERSION_BUMPS) },
|
|
58
|
+
deploy_trigger: { type: 'string' as const, validate: createEnumValidator(DEPLOY_TRIGGERS) },
|
|
59
|
+
};
|
|
60
|
+
|
|
61
|
+
const getBodyOfWorkSchema = {
|
|
62
|
+
body_of_work_id: { type: 'string' as const, required: true as const, validate: uuidValidator },
|
|
63
|
+
summary_only: { type: 'boolean' as const, default: false },
|
|
64
|
+
};
|
|
65
|
+
|
|
66
|
+
const getBodiesOfWorkSchema = {
|
|
67
|
+
project_id: { type: 'string' as const, required: true as const, validate: uuidValidator },
|
|
68
|
+
status: { type: 'string' as const, validate: createEnumValidator(BODY_OF_WORK_STATUSES) },
|
|
69
|
+
limit: { type: 'number' as const, default: 50 },
|
|
70
|
+
offset: { type: 'number' as const, default: 0 },
|
|
71
|
+
search_query: { type: 'string' as const },
|
|
72
|
+
};
|
|
73
|
+
|
|
74
|
+
const deleteBodyOfWorkSchema = {
|
|
75
|
+
body_of_work_id: { type: 'string' as const, required: true as const, validate: uuidValidator },
|
|
76
|
+
};
|
|
77
|
+
|
|
78
|
+
const addTaskToBodyOfWorkSchema = {
|
|
79
|
+
body_of_work_id: { type: 'string' as const, required: true as const, validate: uuidValidator },
|
|
80
|
+
task_id: { type: 'string' as const, required: true as const, validate: uuidValidator },
|
|
81
|
+
phase: { type: 'string' as const, validate: createEnumValidator(TASK_PHASES) },
|
|
82
|
+
order_index: { type: 'number' as const },
|
|
83
|
+
};
|
|
84
|
+
|
|
85
|
+
const removeTaskFromBodyOfWorkSchema = {
|
|
86
|
+
task_id: { type: 'string' as const, required: true as const, validate: uuidValidator },
|
|
87
|
+
};
|
|
88
|
+
|
|
89
|
+
const activateBodyOfWorkSchema = {
|
|
90
|
+
body_of_work_id: { type: 'string' as const, required: true as const, validate: uuidValidator },
|
|
91
|
+
};
|
|
92
|
+
|
|
93
|
+
const addTaskDependencySchema = {
|
|
94
|
+
body_of_work_id: { type: 'string' as const, required: true as const, validate: uuidValidator },
|
|
95
|
+
task_id: { type: 'string' as const, required: true as const, validate: uuidValidator },
|
|
96
|
+
depends_on_task_id: { type: 'string' as const, required: true as const, validate: uuidValidator },
|
|
97
|
+
};
|
|
98
|
+
|
|
99
|
+
const removeTaskDependencySchema = {
|
|
100
|
+
task_id: { type: 'string' as const, required: true as const, validate: uuidValidator },
|
|
101
|
+
depends_on_task_id: { type: 'string' as const, required: true as const, validate: uuidValidator },
|
|
102
|
+
};
|
|
103
|
+
|
|
104
|
+
const getTaskDependenciesSchema = {
|
|
105
|
+
body_of_work_id: { type: 'string' as const, validate: uuidValidator },
|
|
106
|
+
task_id: { type: 'string' as const, validate: uuidValidator },
|
|
107
|
+
};
|
|
108
|
+
|
|
109
|
+
const getNextBodyOfWorkTaskSchema = {
|
|
110
|
+
body_of_work_id: { type: 'string' as const, required: true as const, validate: uuidValidator },
|
|
111
|
+
};
|
|
30
112
|
|
|
31
113
|
export const createBodyOfWork: Handler = async (args, ctx) => {
|
|
32
114
|
const {
|
|
@@ -37,19 +119,7 @@ export const createBodyOfWork: Handler = async (args, ctx) => {
|
|
|
37
119
|
deploy_environment,
|
|
38
120
|
deploy_version_bump,
|
|
39
121
|
deploy_trigger,
|
|
40
|
-
} = args
|
|
41
|
-
project_id: string;
|
|
42
|
-
title: string;
|
|
43
|
-
description?: string;
|
|
44
|
-
auto_deploy_on_completion?: boolean;
|
|
45
|
-
deploy_environment?: DeployEnvironment;
|
|
46
|
-
deploy_version_bump?: VersionBump;
|
|
47
|
-
deploy_trigger?: DeployTrigger;
|
|
48
|
-
};
|
|
49
|
-
|
|
50
|
-
validateRequired(project_id, 'project_id');
|
|
51
|
-
validateUUID(project_id, 'project_id');
|
|
52
|
-
validateRequired(title, 'title');
|
|
122
|
+
} = parseArgs(args, createBodyOfWorkSchema);
|
|
53
123
|
|
|
54
124
|
const { session } = ctx;
|
|
55
125
|
const apiClient = getApiClient();
|
|
@@ -95,18 +165,7 @@ export const updateBodyOfWork: Handler = async (args, ctx) => {
|
|
|
95
165
|
deploy_environment,
|
|
96
166
|
deploy_version_bump,
|
|
97
167
|
deploy_trigger,
|
|
98
|
-
} = args
|
|
99
|
-
body_of_work_id: string;
|
|
100
|
-
title?: string;
|
|
101
|
-
description?: string;
|
|
102
|
-
auto_deploy_on_completion?: boolean;
|
|
103
|
-
deploy_environment?: DeployEnvironment;
|
|
104
|
-
deploy_version_bump?: VersionBump;
|
|
105
|
-
deploy_trigger?: DeployTrigger;
|
|
106
|
-
};
|
|
107
|
-
|
|
108
|
-
validateRequired(body_of_work_id, 'body_of_work_id');
|
|
109
|
-
validateUUID(body_of_work_id, 'body_of_work_id');
|
|
168
|
+
} = parseArgs(args, updateBodyOfWorkSchema);
|
|
110
169
|
|
|
111
170
|
// Check if any updates provided
|
|
112
171
|
if (title === undefined && description === undefined && auto_deploy_on_completion === undefined &&
|
|
@@ -134,24 +193,37 @@ export const updateBodyOfWork: Handler = async (args, ctx) => {
|
|
|
134
193
|
};
|
|
135
194
|
|
|
136
195
|
export const getBodyOfWork: Handler = async (args, ctx) => {
|
|
137
|
-
const { body_of_work_id } = args
|
|
138
|
-
|
|
139
|
-
validateRequired(body_of_work_id, 'body_of_work_id');
|
|
140
|
-
validateUUID(body_of_work_id, 'body_of_work_id');
|
|
196
|
+
const { body_of_work_id, summary_only } = parseArgs(args, getBodyOfWorkSchema);
|
|
141
197
|
|
|
142
198
|
const apiClient = getApiClient();
|
|
143
199
|
|
|
200
|
+
// Response type varies based on summary_only
|
|
144
201
|
const response = await apiClient.proxy<{
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
202
|
+
body_of_work: {
|
|
203
|
+
id: string;
|
|
204
|
+
title: string;
|
|
205
|
+
description?: string;
|
|
206
|
+
status: string;
|
|
207
|
+
progress_percentage: number;
|
|
208
|
+
};
|
|
209
|
+
// Full response includes tasks grouped by phase
|
|
210
|
+
tasks?: {
|
|
211
|
+
pre: unknown[];
|
|
212
|
+
core: unknown[];
|
|
213
|
+
post: unknown[];
|
|
214
|
+
};
|
|
215
|
+
// Summary response includes counts and next task
|
|
216
|
+
task_counts?: {
|
|
217
|
+
pre: { total: number; completed: number };
|
|
218
|
+
core: { total: number; completed: number };
|
|
219
|
+
post: { total: number; completed: number };
|
|
220
|
+
total: number;
|
|
221
|
+
completed: number;
|
|
222
|
+
in_progress: number;
|
|
223
|
+
};
|
|
224
|
+
current_task?: { id: string; title: string } | null;
|
|
225
|
+
next_task?: { id: string; title: string; priority: number } | null;
|
|
226
|
+
}>('get_body_of_work', { body_of_work_id, summary_only });
|
|
155
227
|
|
|
156
228
|
if (!response.ok) {
|
|
157
229
|
throw new Error(`Failed to get body of work: ${response.error}`);
|
|
@@ -161,16 +233,7 @@ export const getBodyOfWork: Handler = async (args, ctx) => {
|
|
|
161
233
|
};
|
|
162
234
|
|
|
163
235
|
export const getBodiesOfWork: Handler = async (args, ctx) => {
|
|
164
|
-
const { project_id, status, limit
|
|
165
|
-
project_id: string;
|
|
166
|
-
status?: BodyOfWorkStatus;
|
|
167
|
-
limit?: number;
|
|
168
|
-
offset?: number;
|
|
169
|
-
search_query?: string;
|
|
170
|
-
};
|
|
171
|
-
|
|
172
|
-
validateRequired(project_id, 'project_id');
|
|
173
|
-
validateUUID(project_id, 'project_id');
|
|
236
|
+
const { project_id, status, limit, offset, search_query } = parseArgs(args, getBodiesOfWorkSchema);
|
|
174
237
|
|
|
175
238
|
const apiClient = getApiClient();
|
|
176
239
|
|
|
@@ -192,7 +255,7 @@ export const getBodiesOfWork: Handler = async (args, ctx) => {
|
|
|
192
255
|
}>('get_bodies_of_work', {
|
|
193
256
|
project_id,
|
|
194
257
|
status,
|
|
195
|
-
limit: Math.min(limit, 100),
|
|
258
|
+
limit: Math.min(limit ?? 50, 100),
|
|
196
259
|
offset,
|
|
197
260
|
search_query
|
|
198
261
|
});
|
|
@@ -205,10 +268,7 @@ export const getBodiesOfWork: Handler = async (args, ctx) => {
|
|
|
205
268
|
};
|
|
206
269
|
|
|
207
270
|
export const deleteBodyOfWork: Handler = async (args, ctx) => {
|
|
208
|
-
const { body_of_work_id } = args
|
|
209
|
-
|
|
210
|
-
validateRequired(body_of_work_id, 'body_of_work_id');
|
|
211
|
-
validateUUID(body_of_work_id, 'body_of_work_id');
|
|
271
|
+
const { body_of_work_id } = parseArgs(args, deleteBodyOfWorkSchema);
|
|
212
272
|
|
|
213
273
|
const apiClient = getApiClient();
|
|
214
274
|
|
|
@@ -224,17 +284,7 @@ export const deleteBodyOfWork: Handler = async (args, ctx) => {
|
|
|
224
284
|
};
|
|
225
285
|
|
|
226
286
|
export const addTaskToBodyOfWork: Handler = async (args, ctx) => {
|
|
227
|
-
const { body_of_work_id, task_id, phase, order_index } = args
|
|
228
|
-
body_of_work_id: string;
|
|
229
|
-
task_id: string;
|
|
230
|
-
phase?: TaskPhase;
|
|
231
|
-
order_index?: number;
|
|
232
|
-
};
|
|
233
|
-
|
|
234
|
-
validateRequired(body_of_work_id, 'body_of_work_id');
|
|
235
|
-
validateUUID(body_of_work_id, 'body_of_work_id');
|
|
236
|
-
validateRequired(task_id, 'task_id');
|
|
237
|
-
validateUUID(task_id, 'task_id');
|
|
287
|
+
const { body_of_work_id, task_id, phase, order_index } = parseArgs(args, addTaskToBodyOfWorkSchema);
|
|
238
288
|
|
|
239
289
|
const apiClient = getApiClient();
|
|
240
290
|
|
|
@@ -259,10 +309,7 @@ export const addTaskToBodyOfWork: Handler = async (args, ctx) => {
|
|
|
259
309
|
};
|
|
260
310
|
|
|
261
311
|
export const removeTaskFromBodyOfWork: Handler = async (args, ctx) => {
|
|
262
|
-
const { task_id } = args
|
|
263
|
-
|
|
264
|
-
validateRequired(task_id, 'task_id');
|
|
265
|
-
validateUUID(task_id, 'task_id');
|
|
312
|
+
const { task_id } = parseArgs(args, removeTaskFromBodyOfWorkSchema);
|
|
266
313
|
|
|
267
314
|
const apiClient = getApiClient();
|
|
268
315
|
|
|
@@ -280,10 +327,7 @@ export const removeTaskFromBodyOfWork: Handler = async (args, ctx) => {
|
|
|
280
327
|
};
|
|
281
328
|
|
|
282
329
|
export const activateBodyOfWork: Handler = async (args, ctx) => {
|
|
283
|
-
const { body_of_work_id } = args
|
|
284
|
-
|
|
285
|
-
validateRequired(body_of_work_id, 'body_of_work_id');
|
|
286
|
-
validateUUID(body_of_work_id, 'body_of_work_id');
|
|
330
|
+
const { body_of_work_id } = parseArgs(args, activateBodyOfWorkSchema);
|
|
287
331
|
|
|
288
332
|
const apiClient = getApiClient();
|
|
289
333
|
|
|
@@ -303,18 +347,7 @@ export const activateBodyOfWork: Handler = async (args, ctx) => {
|
|
|
303
347
|
};
|
|
304
348
|
|
|
305
349
|
export const addTaskDependency: Handler = async (args, ctx) => {
|
|
306
|
-
const { body_of_work_id, task_id, depends_on_task_id } = args
|
|
307
|
-
body_of_work_id: string;
|
|
308
|
-
task_id: string;
|
|
309
|
-
depends_on_task_id: string;
|
|
310
|
-
};
|
|
311
|
-
|
|
312
|
-
validateRequired(body_of_work_id, 'body_of_work_id');
|
|
313
|
-
validateUUID(body_of_work_id, 'body_of_work_id');
|
|
314
|
-
validateRequired(task_id, 'task_id');
|
|
315
|
-
validateUUID(task_id, 'task_id');
|
|
316
|
-
validateRequired(depends_on_task_id, 'depends_on_task_id');
|
|
317
|
-
validateUUID(depends_on_task_id, 'depends_on_task_id');
|
|
350
|
+
const { body_of_work_id, task_id, depends_on_task_id } = parseArgs(args, addTaskDependencySchema);
|
|
318
351
|
|
|
319
352
|
if (task_id === depends_on_task_id) {
|
|
320
353
|
throw new Error('A task cannot depend on itself');
|
|
@@ -342,15 +375,7 @@ export const addTaskDependency: Handler = async (args, ctx) => {
|
|
|
342
375
|
};
|
|
343
376
|
|
|
344
377
|
export const removeTaskDependency: Handler = async (args, ctx) => {
|
|
345
|
-
const { task_id, depends_on_task_id } = args
|
|
346
|
-
task_id: string;
|
|
347
|
-
depends_on_task_id: string;
|
|
348
|
-
};
|
|
349
|
-
|
|
350
|
-
validateRequired(task_id, 'task_id');
|
|
351
|
-
validateUUID(task_id, 'task_id');
|
|
352
|
-
validateRequired(depends_on_task_id, 'depends_on_task_id');
|
|
353
|
-
validateUUID(depends_on_task_id, 'depends_on_task_id');
|
|
378
|
+
const { task_id, depends_on_task_id } = parseArgs(args, removeTaskDependencySchema);
|
|
354
379
|
|
|
355
380
|
const apiClient = getApiClient();
|
|
356
381
|
|
|
@@ -371,18 +396,12 @@ export const removeTaskDependency: Handler = async (args, ctx) => {
|
|
|
371
396
|
};
|
|
372
397
|
|
|
373
398
|
export const getTaskDependencies: Handler = async (args, ctx) => {
|
|
374
|
-
const { body_of_work_id, task_id } = args
|
|
375
|
-
body_of_work_id?: string;
|
|
376
|
-
task_id?: string;
|
|
377
|
-
};
|
|
399
|
+
const { body_of_work_id, task_id } = parseArgs(args, getTaskDependenciesSchema);
|
|
378
400
|
|
|
379
401
|
if (!body_of_work_id && !task_id) {
|
|
380
402
|
throw new Error('Either body_of_work_id or task_id is required');
|
|
381
403
|
}
|
|
382
404
|
|
|
383
|
-
if (body_of_work_id) validateUUID(body_of_work_id, 'body_of_work_id');
|
|
384
|
-
if (task_id) validateUUID(task_id, 'task_id');
|
|
385
|
-
|
|
386
405
|
const apiClient = getApiClient();
|
|
387
406
|
|
|
388
407
|
const response = await apiClient.proxy<{
|
|
@@ -405,10 +424,7 @@ export const getTaskDependencies: Handler = async (args, ctx) => {
|
|
|
405
424
|
};
|
|
406
425
|
|
|
407
426
|
export const getNextBodyOfWorkTask: Handler = async (args, ctx) => {
|
|
408
|
-
const { body_of_work_id } = args
|
|
409
|
-
|
|
410
|
-
validateRequired(body_of_work_id, 'body_of_work_id');
|
|
411
|
-
validateUUID(body_of_work_id, 'body_of_work_id');
|
|
427
|
+
const { body_of_work_id } = parseArgs(args, getNextBodyOfWorkTaskSchema);
|
|
412
428
|
|
|
413
429
|
const apiClient = getApiClient();
|
|
414
430
|
|