@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
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
*
|
|
10
10
|
* MIGRATED: Uses Vibescope API client instead of direct Supabase
|
|
11
11
|
*/
|
|
12
|
-
import {
|
|
12
|
+
import { parseArgs, uuidValidator, createEnumValidator } from '../validators.js';
|
|
13
13
|
import { FALLBACK_ACTIVITIES } from '../utils.js';
|
|
14
14
|
import { getApiClient } from '../api-client.js';
|
|
15
15
|
const VALID_ACTIVITIES = [
|
|
@@ -24,14 +24,25 @@ const VALID_ACTIVITIES = [
|
|
|
24
24
|
'dependency_audit',
|
|
25
25
|
'validate_completed_tasks',
|
|
26
26
|
];
|
|
27
|
+
// Argument schemas for type-safe parsing
|
|
28
|
+
const startFallbackActivitySchema = {
|
|
29
|
+
project_id: { type: 'string', required: true, validate: uuidValidator },
|
|
30
|
+
activity: { type: 'string', required: true, validate: createEnumValidator(VALID_ACTIVITIES) },
|
|
31
|
+
};
|
|
32
|
+
const stopFallbackActivitySchema = {
|
|
33
|
+
project_id: { type: 'string', required: true, validate: uuidValidator },
|
|
34
|
+
summary: { type: 'string' },
|
|
35
|
+
};
|
|
36
|
+
const getActivityHistorySchema = {
|
|
37
|
+
project_id: { type: 'string', required: true, validate: uuidValidator },
|
|
38
|
+
activity_type: { type: 'string' },
|
|
39
|
+
limit: { type: 'number', default: 50 },
|
|
40
|
+
};
|
|
41
|
+
const getActivitySchedulesSchema = {
|
|
42
|
+
project_id: { type: 'string', required: true, validate: uuidValidator },
|
|
43
|
+
};
|
|
27
44
|
export const startFallbackActivity = async (args, ctx) => {
|
|
28
|
-
const { project_id, activity } = args;
|
|
29
|
-
validateRequired(project_id, 'project_id');
|
|
30
|
-
validateUUID(project_id, 'project_id');
|
|
31
|
-
validateRequired(activity, 'activity');
|
|
32
|
-
if (!VALID_ACTIVITIES.includes(activity)) {
|
|
33
|
-
throw new Error(`Invalid activity. Must be one of: ${VALID_ACTIVITIES.join(', ')}`);
|
|
34
|
-
}
|
|
45
|
+
const { project_id, activity } = parseArgs(args, startFallbackActivitySchema);
|
|
35
46
|
const { session } = ctx;
|
|
36
47
|
const apiClient = getApiClient();
|
|
37
48
|
const response = await apiClient.startFallbackActivity(project_id, activity, session.currentSessionId || undefined);
|
|
@@ -40,21 +51,28 @@ export const startFallbackActivity = async (args, ctx) => {
|
|
|
40
51
|
}
|
|
41
52
|
// Get the activity details for the response
|
|
42
53
|
const activityInfo = FALLBACK_ACTIVITIES.find((a) => a.activity === activity);
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
message: response.data?.message || `Started fallback activity: ${activityInfo?.title || activity}`,
|
|
51
|
-
},
|
|
54
|
+
const result = {
|
|
55
|
+
success: true,
|
|
56
|
+
activity,
|
|
57
|
+
title: activityInfo?.title || activity,
|
|
58
|
+
description: activityInfo?.description || '',
|
|
59
|
+
prompt: activityInfo?.prompt || '',
|
|
60
|
+
message: response.data?.message || `Started fallback activity: ${activityInfo?.title || activity}`,
|
|
52
61
|
};
|
|
62
|
+
// Pass through worktree guidance if provided
|
|
63
|
+
if (response.data?.git_workflow) {
|
|
64
|
+
result.git_workflow = response.data.git_workflow;
|
|
65
|
+
}
|
|
66
|
+
if (response.data?.worktree_setup) {
|
|
67
|
+
result.worktree_setup = response.data.worktree_setup;
|
|
68
|
+
}
|
|
69
|
+
if (response.data?.next_step) {
|
|
70
|
+
result.next_step = response.data.next_step;
|
|
71
|
+
}
|
|
72
|
+
return { result };
|
|
53
73
|
};
|
|
54
74
|
export const stopFallbackActivity = async (args, ctx) => {
|
|
55
|
-
const { project_id, summary } = args;
|
|
56
|
-
validateRequired(project_id, 'project_id');
|
|
57
|
-
validateUUID(project_id, 'project_id');
|
|
75
|
+
const { project_id, summary } = parseArgs(args, stopFallbackActivitySchema);
|
|
58
76
|
const { session } = ctx;
|
|
59
77
|
const apiClient = getApiClient();
|
|
60
78
|
const response = await apiClient.stopFallbackActivity(project_id, summary, session.currentSessionId || undefined);
|
|
@@ -68,10 +86,8 @@ export const stopFallbackActivity = async (args, ctx) => {
|
|
|
68
86
|
},
|
|
69
87
|
};
|
|
70
88
|
};
|
|
71
|
-
export const getActivityHistory = async (args,
|
|
72
|
-
const { project_id, activity_type, limit
|
|
73
|
-
validateRequired(project_id, 'project_id');
|
|
74
|
-
validateUUID(project_id, 'project_id');
|
|
89
|
+
export const getActivityHistory = async (args, _ctx) => {
|
|
90
|
+
const { project_id, activity_type, limit } = parseArgs(args, getActivityHistorySchema);
|
|
75
91
|
const apiClient = getApiClient();
|
|
76
92
|
// Use proxy for get_activity_history operation
|
|
77
93
|
const response = await apiClient.proxy('get_activity_history', {
|
|
@@ -90,10 +106,8 @@ export const getActivityHistory = async (args, ctx) => {
|
|
|
90
106
|
},
|
|
91
107
|
};
|
|
92
108
|
};
|
|
93
|
-
export const getActivitySchedules = async (args,
|
|
94
|
-
const { project_id } = args;
|
|
95
|
-
validateRequired(project_id, 'project_id');
|
|
96
|
-
validateUUID(project_id, 'project_id');
|
|
109
|
+
export const getActivitySchedules = async (args, _ctx) => {
|
|
110
|
+
const { project_id } = parseArgs(args, getActivitySchedulesSchema);
|
|
97
111
|
const apiClient = getApiClient();
|
|
98
112
|
// Use proxy for get_activity_schedules operation
|
|
99
113
|
const response = await apiClient.proxy('get_activity_schedules', {
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* File Checkouts Handlers
|
|
3
|
+
*
|
|
4
|
+
* Handles file checkout/checkin for multi-agent coordination:
|
|
5
|
+
* - checkout_file: Check out a file before editing
|
|
6
|
+
* - checkin_file: Check in a file after editing
|
|
7
|
+
* - get_file_checkouts: Get active checkouts for a project
|
|
8
|
+
* - abandon_checkout: Force release a checkout
|
|
9
|
+
*/
|
|
10
|
+
import type { Handler, HandlerRegistry } from './types.js';
|
|
11
|
+
export declare const checkoutFile: Handler;
|
|
12
|
+
export declare const checkinFile: Handler;
|
|
13
|
+
export declare const getFileCheckouts: Handler;
|
|
14
|
+
export declare const abandonCheckout: Handler;
|
|
15
|
+
/**
|
|
16
|
+
* File Checkouts handlers registry
|
|
17
|
+
*/
|
|
18
|
+
export declare const fileCheckoutHandlers: HandlerRegistry;
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* File Checkouts Handlers
|
|
3
|
+
*
|
|
4
|
+
* Handles file checkout/checkin for multi-agent coordination:
|
|
5
|
+
* - checkout_file: Check out a file before editing
|
|
6
|
+
* - checkin_file: Check in a file after editing
|
|
7
|
+
* - get_file_checkouts: Get active checkouts for a project
|
|
8
|
+
* - abandon_checkout: Force release a checkout
|
|
9
|
+
*/
|
|
10
|
+
import { parseArgs, uuidValidator, createEnumValidator } from '../validators.js';
|
|
11
|
+
import { getApiClient } from '../api-client.js';
|
|
12
|
+
const VALID_CHECKOUT_STATUSES = ['checked_out', 'checked_in', 'abandoned'];
|
|
13
|
+
// Argument schemas for type-safe parsing
|
|
14
|
+
const checkoutFileSchema = {
|
|
15
|
+
project_id: { type: 'string', required: true, validate: uuidValidator },
|
|
16
|
+
file_path: { type: 'string', required: true },
|
|
17
|
+
reason: { type: 'string' },
|
|
18
|
+
};
|
|
19
|
+
const checkinFileSchema = {
|
|
20
|
+
checkout_id: { type: 'string', validate: uuidValidator },
|
|
21
|
+
project_id: { type: 'string', validate: uuidValidator },
|
|
22
|
+
file_path: { type: 'string' },
|
|
23
|
+
summary: { type: 'string' },
|
|
24
|
+
};
|
|
25
|
+
const getFileCheckoutsSchema = {
|
|
26
|
+
project_id: { type: 'string', required: true, validate: uuidValidator },
|
|
27
|
+
status: { type: 'string', validate: createEnumValidator(VALID_CHECKOUT_STATUSES) },
|
|
28
|
+
file_path: { type: 'string' },
|
|
29
|
+
limit: { type: 'number', default: 50 },
|
|
30
|
+
};
|
|
31
|
+
const abandonCheckoutSchema = {
|
|
32
|
+
checkout_id: { type: 'string', validate: uuidValidator },
|
|
33
|
+
project_id: { type: 'string', validate: uuidValidator },
|
|
34
|
+
file_path: { type: 'string' },
|
|
35
|
+
};
|
|
36
|
+
export const checkoutFile = async (args, ctx) => {
|
|
37
|
+
const { project_id, file_path, reason } = parseArgs(args, checkoutFileSchema);
|
|
38
|
+
const apiClient = getApiClient();
|
|
39
|
+
const response = await apiClient.checkoutFile(project_id, file_path, reason, ctx.session.currentSessionId || undefined);
|
|
40
|
+
if (!response.ok) {
|
|
41
|
+
throw new Error(response.error || 'Failed to checkout file');
|
|
42
|
+
}
|
|
43
|
+
return { result: response.data };
|
|
44
|
+
};
|
|
45
|
+
export const checkinFile = async (args, ctx) => {
|
|
46
|
+
const { checkout_id, project_id, file_path, summary } = parseArgs(args, checkinFileSchema);
|
|
47
|
+
// Validate that either checkout_id or both project_id and file_path are provided
|
|
48
|
+
if (!checkout_id && (!project_id || !file_path)) {
|
|
49
|
+
throw new Error('Either checkout_id or both project_id and file_path are required');
|
|
50
|
+
}
|
|
51
|
+
const apiClient = getApiClient();
|
|
52
|
+
const response = await apiClient.checkinFile({
|
|
53
|
+
checkout_id,
|
|
54
|
+
project_id,
|
|
55
|
+
file_path,
|
|
56
|
+
summary
|
|
57
|
+
}, ctx.session.currentSessionId || undefined);
|
|
58
|
+
if (!response.ok) {
|
|
59
|
+
throw new Error(response.error || 'Failed to checkin file');
|
|
60
|
+
}
|
|
61
|
+
return { result: response.data };
|
|
62
|
+
};
|
|
63
|
+
export const getFileCheckouts = async (args, _ctx) => {
|
|
64
|
+
const { project_id, status, file_path, limit } = parseArgs(args, getFileCheckoutsSchema);
|
|
65
|
+
const apiClient = getApiClient();
|
|
66
|
+
const response = await apiClient.getFileCheckouts(project_id, {
|
|
67
|
+
status,
|
|
68
|
+
file_path,
|
|
69
|
+
limit
|
|
70
|
+
});
|
|
71
|
+
if (!response.ok) {
|
|
72
|
+
throw new Error(response.error || 'Failed to get file checkouts');
|
|
73
|
+
}
|
|
74
|
+
return { result: response.data };
|
|
75
|
+
};
|
|
76
|
+
export const abandonCheckout = async (args, _ctx) => {
|
|
77
|
+
const { checkout_id, project_id, file_path } = parseArgs(args, abandonCheckoutSchema);
|
|
78
|
+
// Validate that either checkout_id or both project_id and file_path are provided
|
|
79
|
+
if (!checkout_id && (!project_id || !file_path)) {
|
|
80
|
+
throw new Error('Either checkout_id or both project_id and file_path are required');
|
|
81
|
+
}
|
|
82
|
+
const apiClient = getApiClient();
|
|
83
|
+
const response = await apiClient.abandonCheckout({
|
|
84
|
+
checkout_id,
|
|
85
|
+
project_id,
|
|
86
|
+
file_path
|
|
87
|
+
});
|
|
88
|
+
if (!response.ok) {
|
|
89
|
+
throw new Error(response.error || 'Failed to abandon checkout');
|
|
90
|
+
}
|
|
91
|
+
return { result: response.data };
|
|
92
|
+
};
|
|
93
|
+
/**
|
|
94
|
+
* File Checkouts handlers registry
|
|
95
|
+
*/
|
|
96
|
+
export const fileCheckoutHandlers = {
|
|
97
|
+
checkout_file: checkoutFile,
|
|
98
|
+
checkin_file: checkinFile,
|
|
99
|
+
get_file_checkouts: getFileCheckouts,
|
|
100
|
+
abandon_checkout: abandonCheckout,
|
|
101
|
+
};
|
|
@@ -3,15 +3,28 @@
|
|
|
3
3
|
*
|
|
4
4
|
* Handles audit findings and knowledge base:
|
|
5
5
|
* - add_finding
|
|
6
|
-
* - get_findings
|
|
6
|
+
* - get_findings (supports summary_only for reduced tokens)
|
|
7
|
+
* - get_findings_stats (aggregate counts for minimal tokens)
|
|
7
8
|
* - update_finding
|
|
8
9
|
* - delete_finding
|
|
9
10
|
*/
|
|
10
11
|
import type { Handler, HandlerRegistry } from './types.js';
|
|
11
12
|
export declare const addFinding: Handler;
|
|
12
13
|
export declare const getFindings: Handler;
|
|
14
|
+
/**
|
|
15
|
+
* Get aggregate statistics about findings for a project.
|
|
16
|
+
* Returns counts by category, severity, and status without the actual finding data.
|
|
17
|
+
* This is much more token-efficient than get_findings for understanding the overall state.
|
|
18
|
+
*/
|
|
19
|
+
export declare const getFindingsStats: Handler;
|
|
13
20
|
export declare const updateFinding: Handler;
|
|
14
21
|
export declare const deleteFinding: Handler;
|
|
22
|
+
/**
|
|
23
|
+
* Query aggregated project knowledge in a single call.
|
|
24
|
+
* Returns findings, Q&A, decisions, completed tasks, and resolved blockers.
|
|
25
|
+
* Use this instead of multiple separate tool calls to reduce token usage.
|
|
26
|
+
*/
|
|
27
|
+
export declare const queryKnowledgeBase: Handler;
|
|
15
28
|
/**
|
|
16
29
|
* Findings handlers registry
|
|
17
30
|
*/
|
|
@@ -3,25 +3,67 @@
|
|
|
3
3
|
*
|
|
4
4
|
* Handles audit findings and knowledge base:
|
|
5
5
|
* - add_finding
|
|
6
|
-
* - get_findings
|
|
6
|
+
* - get_findings (supports summary_only for reduced tokens)
|
|
7
|
+
* - get_findings_stats (aggregate counts for minimal tokens)
|
|
7
8
|
* - update_finding
|
|
8
9
|
* - delete_finding
|
|
9
10
|
*/
|
|
10
|
-
import {
|
|
11
|
+
import { parseArgs, uuidValidator, createEnumValidator } from '../validators.js';
|
|
11
12
|
import { getApiClient } from '../api-client.js';
|
|
13
|
+
const VALID_FINDING_CATEGORIES = ['performance', 'security', 'code_quality', 'accessibility', 'documentation', 'architecture', 'testing', 'other'];
|
|
14
|
+
const VALID_FINDING_SEVERITIES = ['info', 'low', 'medium', 'high', 'critical'];
|
|
15
|
+
const VALID_FINDING_STATUSES = ['open', 'addressed', 'dismissed', 'wontfix'];
|
|
16
|
+
// Argument schemas for type-safe parsing
|
|
17
|
+
const addFindingSchema = {
|
|
18
|
+
project_id: { type: 'string', required: true, validate: uuidValidator },
|
|
19
|
+
title: { type: 'string', required: true },
|
|
20
|
+
description: { type: 'string' },
|
|
21
|
+
category: { type: 'string', validate: createEnumValidator(VALID_FINDING_CATEGORIES) },
|
|
22
|
+
severity: { type: 'string', validate: createEnumValidator(VALID_FINDING_SEVERITIES) },
|
|
23
|
+
file_path: { type: 'string' },
|
|
24
|
+
line_number: { type: 'number' },
|
|
25
|
+
related_task_id: { type: 'string', validate: uuidValidator },
|
|
26
|
+
};
|
|
27
|
+
const getFindingsSchema = {
|
|
28
|
+
project_id: { type: 'string', required: true, validate: uuidValidator },
|
|
29
|
+
category: { type: 'string', validate: createEnumValidator(VALID_FINDING_CATEGORIES) },
|
|
30
|
+
severity: { type: 'string', validate: createEnumValidator(VALID_FINDING_SEVERITIES) },
|
|
31
|
+
status: { type: 'string', validate: createEnumValidator(VALID_FINDING_STATUSES) },
|
|
32
|
+
limit: { type: 'number', default: 50 },
|
|
33
|
+
offset: { type: 'number', default: 0 },
|
|
34
|
+
search_query: { type: 'string' },
|
|
35
|
+
summary_only: { type: 'boolean', default: false },
|
|
36
|
+
};
|
|
37
|
+
const getFindingsStatsSchema = {
|
|
38
|
+
project_id: { type: 'string', required: true, validate: uuidValidator },
|
|
39
|
+
};
|
|
40
|
+
const updateFindingSchema = {
|
|
41
|
+
finding_id: { type: 'string', required: true, validate: uuidValidator },
|
|
42
|
+
title: { type: 'string' },
|
|
43
|
+
description: { type: 'string' },
|
|
44
|
+
severity: { type: 'string', validate: createEnumValidator(VALID_FINDING_SEVERITIES) },
|
|
45
|
+
status: { type: 'string', validate: createEnumValidator(VALID_FINDING_STATUSES) },
|
|
46
|
+
resolution_note: { type: 'string' },
|
|
47
|
+
};
|
|
48
|
+
const deleteFindingSchema = {
|
|
49
|
+
finding_id: { type: 'string', required: true, validate: uuidValidator },
|
|
50
|
+
};
|
|
51
|
+
const VALID_SCOPES = ['summary', 'detailed'];
|
|
52
|
+
const queryKnowledgeBaseSchema = {
|
|
53
|
+
project_id: { type: 'string', required: true, validate: uuidValidator },
|
|
54
|
+
scope: { type: 'string', default: 'summary', validate: createEnumValidator(VALID_SCOPES) },
|
|
55
|
+
categories: { type: 'array' },
|
|
56
|
+
limit: { type: 'number', default: 5 },
|
|
57
|
+
search_query: { type: 'string' },
|
|
58
|
+
};
|
|
12
59
|
export const addFinding = async (args, ctx) => {
|
|
13
|
-
const { project_id,
|
|
14
|
-
validateRequired(project_id, 'project_id');
|
|
15
|
-
validateUUID(project_id, 'project_id');
|
|
16
|
-
validateRequired(title, 'title');
|
|
17
|
-
if (related_task_id)
|
|
18
|
-
validateUUID(related_task_id, 'related_task_id');
|
|
60
|
+
const { project_id, title, description, category, severity, file_path, line_number, related_task_id } = parseArgs(args, addFindingSchema);
|
|
19
61
|
const apiClient = getApiClient();
|
|
20
62
|
const response = await apiClient.addFinding(project_id, {
|
|
21
63
|
title,
|
|
22
64
|
description,
|
|
23
|
-
category,
|
|
24
|
-
severity,
|
|
65
|
+
category: category,
|
|
66
|
+
severity: severity,
|
|
25
67
|
file_path,
|
|
26
68
|
line_number,
|
|
27
69
|
related_task_id
|
|
@@ -31,32 +73,45 @@ export const addFinding = async (args, ctx) => {
|
|
|
31
73
|
}
|
|
32
74
|
return { result: response.data };
|
|
33
75
|
};
|
|
34
|
-
export const getFindings = async (args,
|
|
35
|
-
const { project_id, category, severity, status, limit
|
|
36
|
-
validateRequired(project_id, 'project_id');
|
|
37
|
-
validateUUID(project_id, 'project_id');
|
|
76
|
+
export const getFindings = async (args, _ctx) => {
|
|
77
|
+
const { project_id, category, severity, status, limit, offset, search_query, summary_only } = parseArgs(args, getFindingsSchema);
|
|
38
78
|
const apiClient = getApiClient();
|
|
39
79
|
const response = await apiClient.getFindings(project_id, {
|
|
40
|
-
category,
|
|
41
|
-
severity,
|
|
42
|
-
status,
|
|
43
|
-
limit
|
|
80
|
+
category: category,
|
|
81
|
+
severity: severity,
|
|
82
|
+
status: status,
|
|
83
|
+
limit,
|
|
84
|
+
offset,
|
|
85
|
+
search_query,
|
|
86
|
+
summary_only
|
|
44
87
|
});
|
|
45
88
|
if (!response.ok) {
|
|
46
89
|
throw new Error(response.error || 'Failed to get findings');
|
|
47
90
|
}
|
|
48
91
|
return { result: response.data };
|
|
49
92
|
};
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
93
|
+
/**
|
|
94
|
+
* Get aggregate statistics about findings for a project.
|
|
95
|
+
* Returns counts by category, severity, and status without the actual finding data.
|
|
96
|
+
* This is much more token-efficient than get_findings for understanding the overall state.
|
|
97
|
+
*/
|
|
98
|
+
export const getFindingsStats = async (args, _ctx) => {
|
|
99
|
+
const { project_id } = parseArgs(args, getFindingsStatsSchema);
|
|
100
|
+
const apiClient = getApiClient();
|
|
101
|
+
const response = await apiClient.getFindingsStats(project_id);
|
|
102
|
+
if (!response.ok) {
|
|
103
|
+
throw new Error(response.error || 'Failed to get findings stats');
|
|
104
|
+
}
|
|
105
|
+
return { result: response.data };
|
|
106
|
+
};
|
|
107
|
+
export const updateFinding = async (args, _ctx) => {
|
|
108
|
+
const { finding_id, title, description, severity, status, resolution_note } = parseArgs(args, updateFindingSchema);
|
|
54
109
|
const apiClient = getApiClient();
|
|
55
110
|
const response = await apiClient.updateFinding(finding_id, {
|
|
56
111
|
title,
|
|
57
112
|
description,
|
|
58
|
-
severity,
|
|
59
|
-
status,
|
|
113
|
+
severity: severity,
|
|
114
|
+
status: status,
|
|
60
115
|
resolution_note
|
|
61
116
|
});
|
|
62
117
|
if (!response.ok) {
|
|
@@ -64,10 +119,8 @@ export const updateFinding = async (args, ctx) => {
|
|
|
64
119
|
}
|
|
65
120
|
return { result: response.data };
|
|
66
121
|
};
|
|
67
|
-
export const deleteFinding = async (args,
|
|
68
|
-
const { finding_id } = args;
|
|
69
|
-
validateRequired(finding_id, 'finding_id');
|
|
70
|
-
validateUUID(finding_id, 'finding_id');
|
|
122
|
+
export const deleteFinding = async (args, _ctx) => {
|
|
123
|
+
const { finding_id } = parseArgs(args, deleteFindingSchema);
|
|
71
124
|
const apiClient = getApiClient();
|
|
72
125
|
const response = await apiClient.deleteFinding(finding_id);
|
|
73
126
|
if (!response.ok) {
|
|
@@ -75,12 +128,35 @@ export const deleteFinding = async (args, ctx) => {
|
|
|
75
128
|
}
|
|
76
129
|
return { result: response.data };
|
|
77
130
|
};
|
|
131
|
+
/**
|
|
132
|
+
* Query aggregated project knowledge in a single call.
|
|
133
|
+
* Returns findings, Q&A, decisions, completed tasks, and resolved blockers.
|
|
134
|
+
* Use this instead of multiple separate tool calls to reduce token usage.
|
|
135
|
+
*/
|
|
136
|
+
export const queryKnowledgeBase = async (args, _ctx) => {
|
|
137
|
+
const { project_id, scope, categories, limit, search_query } = parseArgs(args, queryKnowledgeBaseSchema);
|
|
138
|
+
// Validate limit range
|
|
139
|
+
const effectiveLimit = Math.min(Math.max(1, limit ?? 5), 20);
|
|
140
|
+
const apiClient = getApiClient();
|
|
141
|
+
const response = await apiClient.queryKnowledgeBase(project_id, {
|
|
142
|
+
scope: scope,
|
|
143
|
+
categories: categories,
|
|
144
|
+
limit: effectiveLimit,
|
|
145
|
+
search_query
|
|
146
|
+
});
|
|
147
|
+
if (!response.ok) {
|
|
148
|
+
throw new Error(response.error || 'Failed to query knowledge base');
|
|
149
|
+
}
|
|
150
|
+
return { result: response.data };
|
|
151
|
+
};
|
|
78
152
|
/**
|
|
79
153
|
* Findings handlers registry
|
|
80
154
|
*/
|
|
81
155
|
export const findingHandlers = {
|
|
82
156
|
add_finding: addFinding,
|
|
83
157
|
get_findings: getFindings,
|
|
158
|
+
get_findings_stats: getFindingsStats,
|
|
84
159
|
update_finding: updateFinding,
|
|
85
160
|
delete_finding: deleteFinding,
|
|
161
|
+
query_knowledge_base: queryKnowledgeBase,
|
|
86
162
|
};
|
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
* - get_git_issues: List git issues for a project
|
|
8
8
|
* - delete_git_issue: Remove a git issue
|
|
9
9
|
*/
|
|
10
|
-
import {
|
|
10
|
+
import { parseArgs, uuidValidator, createEnumValidator } from '../validators.js';
|
|
11
11
|
import { getApiClient } from '../api-client.js';
|
|
12
12
|
const VALID_GIT_ISSUE_TYPES = [
|
|
13
13
|
'merge_conflict',
|
|
@@ -17,25 +17,41 @@ const VALID_GIT_ISSUE_TYPES = [
|
|
|
17
17
|
'pr_not_mergeable',
|
|
18
18
|
];
|
|
19
19
|
const VALID_GIT_ISSUE_STATUSES = ['open', 'resolved'];
|
|
20
|
+
// Argument schemas for type-safe parsing
|
|
21
|
+
const addGitIssueSchema = {
|
|
22
|
+
project_id: { type: 'string', required: true, validate: uuidValidator },
|
|
23
|
+
issue_type: { type: 'string', required: true, validate: createEnumValidator(VALID_GIT_ISSUE_TYPES) },
|
|
24
|
+
branch: { type: 'string', required: true },
|
|
25
|
+
target_branch: { type: 'string' },
|
|
26
|
+
pr_url: { type: 'string' },
|
|
27
|
+
conflicting_files: { type: 'array' },
|
|
28
|
+
error_message: { type: 'string' },
|
|
29
|
+
task_id: { type: 'string', validate: uuidValidator },
|
|
30
|
+
};
|
|
31
|
+
const resolveGitIssueSchema = {
|
|
32
|
+
git_issue_id: { type: 'string', required: true, validate: uuidValidator },
|
|
33
|
+
resolution_note: { type: 'string' },
|
|
34
|
+
auto_resolved: { type: 'boolean' },
|
|
35
|
+
};
|
|
36
|
+
const getGitIssuesSchema = {
|
|
37
|
+
project_id: { type: 'string', required: true, validate: uuidValidator },
|
|
38
|
+
status: { type: 'string', default: 'open', validate: createEnumValidator(VALID_GIT_ISSUE_STATUSES) },
|
|
39
|
+
issue_type: { type: 'string', validate: createEnumValidator(VALID_GIT_ISSUE_TYPES) },
|
|
40
|
+
branch: { type: 'string' },
|
|
41
|
+
limit: { type: 'number', default: 50 },
|
|
42
|
+
};
|
|
43
|
+
const deleteGitIssueSchema = {
|
|
44
|
+
git_issue_id: { type: 'string', required: true, validate: uuidValidator },
|
|
45
|
+
};
|
|
20
46
|
export const addGitIssue = async (args, ctx) => {
|
|
21
|
-
const { project_id, issue_type, branch, target_branch, pr_url, conflicting_files, error_message, task_id
|
|
22
|
-
validateRequired(project_id, 'project_id');
|
|
23
|
-
validateUUID(project_id, 'project_id');
|
|
24
|
-
validateRequired(issue_type, 'issue_type');
|
|
25
|
-
validateRequired(branch, 'branch');
|
|
26
|
-
if (!VALID_GIT_ISSUE_TYPES.includes(issue_type)) {
|
|
27
|
-
throw new Error(`Invalid issue_type. Valid types: ${VALID_GIT_ISSUE_TYPES.join(', ')}`);
|
|
28
|
-
}
|
|
29
|
-
if (task_id) {
|
|
30
|
-
validateUUID(task_id, 'task_id');
|
|
31
|
-
}
|
|
47
|
+
const { project_id, issue_type, branch, target_branch, pr_url, conflicting_files, error_message, task_id } = parseArgs(args, addGitIssueSchema);
|
|
32
48
|
const apiClient = getApiClient();
|
|
33
49
|
const response = await apiClient.addGitIssue(project_id, {
|
|
34
50
|
issue_type: issue_type,
|
|
35
51
|
branch,
|
|
36
52
|
target_branch,
|
|
37
53
|
pr_url,
|
|
38
|
-
conflicting_files,
|
|
54
|
+
conflicting_files: conflicting_files,
|
|
39
55
|
error_message,
|
|
40
56
|
task_id
|
|
41
57
|
}, ctx.session.currentSessionId || undefined);
|
|
@@ -45,9 +61,7 @@ export const addGitIssue = async (args, ctx) => {
|
|
|
45
61
|
return { result: response.data };
|
|
46
62
|
};
|
|
47
63
|
export const resolveGitIssue = async (args, ctx) => {
|
|
48
|
-
const { git_issue_id, resolution_note, auto_resolved } = args;
|
|
49
|
-
validateRequired(git_issue_id, 'git_issue_id');
|
|
50
|
-
validateUUID(git_issue_id, 'git_issue_id');
|
|
64
|
+
const { git_issue_id, resolution_note, auto_resolved } = parseArgs(args, resolveGitIssueSchema);
|
|
51
65
|
const apiClient = getApiClient();
|
|
52
66
|
const response = await apiClient.resolveGitIssue(git_issue_id, {
|
|
53
67
|
resolution_note,
|
|
@@ -58,20 +72,12 @@ export const resolveGitIssue = async (args, ctx) => {
|
|
|
58
72
|
}
|
|
59
73
|
return { result: response.data };
|
|
60
74
|
};
|
|
61
|
-
export const getGitIssues = async (args,
|
|
62
|
-
const { project_id, status
|
|
63
|
-
validateRequired(project_id, 'project_id');
|
|
64
|
-
validateUUID(project_id, 'project_id');
|
|
65
|
-
if (status && !VALID_GIT_ISSUE_STATUSES.includes(status)) {
|
|
66
|
-
throw new Error(`Invalid status. Valid statuses: ${VALID_GIT_ISSUE_STATUSES.join(', ')}`);
|
|
67
|
-
}
|
|
68
|
-
if (issue_type && !VALID_GIT_ISSUE_TYPES.includes(issue_type)) {
|
|
69
|
-
throw new Error(`Invalid issue_type. Valid types: ${VALID_GIT_ISSUE_TYPES.join(', ')}`);
|
|
70
|
-
}
|
|
75
|
+
export const getGitIssues = async (args, _ctx) => {
|
|
76
|
+
const { project_id, status, issue_type, branch, limit } = parseArgs(args, getGitIssuesSchema);
|
|
71
77
|
const apiClient = getApiClient();
|
|
72
78
|
const response = await apiClient.getGitIssues(project_id, {
|
|
73
|
-
status,
|
|
74
|
-
issue_type,
|
|
79
|
+
status: status,
|
|
80
|
+
issue_type: issue_type,
|
|
75
81
|
branch,
|
|
76
82
|
limit
|
|
77
83
|
});
|
|
@@ -80,10 +86,8 @@ export const getGitIssues = async (args, ctx) => {
|
|
|
80
86
|
}
|
|
81
87
|
return { result: response.data };
|
|
82
88
|
};
|
|
83
|
-
export const deleteGitIssue = async (args,
|
|
84
|
-
const { git_issue_id } = args;
|
|
85
|
-
validateRequired(git_issue_id, 'git_issue_id');
|
|
86
|
-
validateUUID(git_issue_id, 'git_issue_id');
|
|
89
|
+
export const deleteGitIssue = async (args, _ctx) => {
|
|
90
|
+
const { git_issue_id } = parseArgs(args, deleteGitIssueSchema);
|
|
87
91
|
const apiClient = getApiClient();
|
|
88
92
|
const response = await apiClient.deleteGitIssue(git_issue_id);
|
|
89
93
|
if (!response.ok) {
|
package/dist/handlers/ideas.js
CHANGED
|
@@ -10,34 +10,60 @@
|
|
|
10
10
|
*
|
|
11
11
|
* MIGRATED: Uses Vibescope API client instead of direct Supabase
|
|
12
12
|
*/
|
|
13
|
-
import {
|
|
13
|
+
import { parseArgs, uuidValidator, priorityValidator, minutesValidator, createEnumValidator, } from '../validators.js';
|
|
14
14
|
import { getApiClient } from '../api-client.js';
|
|
15
|
+
const VALID_IDEA_STATUSES = ['raw', 'exploring', 'planned', 'in_development', 'shipped'];
|
|
16
|
+
// Argument schemas for type-safe parsing
|
|
17
|
+
const addIdeaSchema = {
|
|
18
|
+
project_id: { type: 'string', required: true, validate: uuidValidator },
|
|
19
|
+
title: { type: 'string', required: true },
|
|
20
|
+
description: { type: 'string' },
|
|
21
|
+
status: { type: 'string', validate: createEnumValidator(VALID_IDEA_STATUSES) },
|
|
22
|
+
};
|
|
23
|
+
const updateIdeaSchema = {
|
|
24
|
+
idea_id: { type: 'string', required: true, validate: uuidValidator },
|
|
25
|
+
title: { type: 'string' },
|
|
26
|
+
description: { type: 'string' },
|
|
27
|
+
status: { type: 'string', validate: createEnumValidator(VALID_IDEA_STATUSES) },
|
|
28
|
+
doc_url: { type: 'string' },
|
|
29
|
+
};
|
|
30
|
+
const getIdeasSchema = {
|
|
31
|
+
project_id: { type: 'string', required: true, validate: uuidValidator },
|
|
32
|
+
status: { type: 'string', validate: createEnumValidator(VALID_IDEA_STATUSES) },
|
|
33
|
+
limit: { type: 'number', default: 50 },
|
|
34
|
+
offset: { type: 'number', default: 0 },
|
|
35
|
+
search_query: { type: 'string' },
|
|
36
|
+
};
|
|
37
|
+
const deleteIdeaSchema = {
|
|
38
|
+
idea_id: { type: 'string', required: true, validate: uuidValidator },
|
|
39
|
+
};
|
|
40
|
+
const convertIdeaToTaskSchema = {
|
|
41
|
+
idea_id: { type: 'string', required: true, validate: uuidValidator },
|
|
42
|
+
priority: { type: 'number', default: 3, validate: priorityValidator },
|
|
43
|
+
estimated_minutes: { type: 'number', validate: minutesValidator },
|
|
44
|
+
update_status: { type: 'boolean', default: true },
|
|
45
|
+
};
|
|
15
46
|
export const addIdea = async (args, ctx) => {
|
|
16
|
-
const { project_id, title, description, status } = args;
|
|
17
|
-
validateRequired(project_id, 'project_id');
|
|
18
|
-
validateUUID(project_id, 'project_id');
|
|
19
|
-
validateRequired(title, 'title');
|
|
47
|
+
const { project_id, title, description, status } = parseArgs(args, addIdeaSchema);
|
|
20
48
|
const { session } = ctx;
|
|
21
49
|
const apiClient = getApiClient();
|
|
22
50
|
const response = await apiClient.addIdea(project_id, {
|
|
23
51
|
title,
|
|
24
52
|
description,
|
|
25
|
-
status
|
|
53
|
+
status: status
|
|
26
54
|
}, session.currentSessionId || undefined);
|
|
27
55
|
if (!response.ok) {
|
|
28
56
|
throw new Error(`Failed to add idea: ${response.error}`);
|
|
29
57
|
}
|
|
30
58
|
return { result: { success: true, idea_id: response.data?.idea_id, title } };
|
|
31
59
|
};
|
|
32
|
-
export const updateIdea = async (args,
|
|
33
|
-
const { idea_id, title, description, status, doc_url } = args;
|
|
34
|
-
validateRequired(idea_id, 'idea_id');
|
|
35
|
-
validateUUID(idea_id, 'idea_id');
|
|
60
|
+
export const updateIdea = async (args, _ctx) => {
|
|
61
|
+
const { idea_id, title, description, status, doc_url } = parseArgs(args, updateIdeaSchema);
|
|
36
62
|
const apiClient = getApiClient();
|
|
37
63
|
const response = await apiClient.updateIdea(idea_id, {
|
|
38
64
|
title,
|
|
39
65
|
description,
|
|
40
|
-
status,
|
|
66
|
+
status: status,
|
|
41
67
|
doc_url
|
|
42
68
|
});
|
|
43
69
|
if (!response.ok) {
|
|
@@ -45,13 +71,11 @@ export const updateIdea = async (args, ctx) => {
|
|
|
45
71
|
}
|
|
46
72
|
return { result: { success: true, idea_id } };
|
|
47
73
|
};
|
|
48
|
-
export const getIdeas = async (args,
|
|
49
|
-
const { project_id, status, limit
|
|
50
|
-
validateRequired(project_id, 'project_id');
|
|
51
|
-
validateUUID(project_id, 'project_id');
|
|
74
|
+
export const getIdeas = async (args, _ctx) => {
|
|
75
|
+
const { project_id, status, limit, offset, search_query } = parseArgs(args, getIdeasSchema);
|
|
52
76
|
const apiClient = getApiClient();
|
|
53
77
|
const response = await apiClient.getIdeas(project_id, {
|
|
54
|
-
status,
|
|
78
|
+
status: status,
|
|
55
79
|
limit,
|
|
56
80
|
offset,
|
|
57
81
|
search_query
|
|
@@ -65,10 +89,8 @@ export const getIdeas = async (args, ctx) => {
|
|
|
65
89
|
},
|
|
66
90
|
};
|
|
67
91
|
};
|
|
68
|
-
export const deleteIdea = async (args,
|
|
69
|
-
const { idea_id } = args;
|
|
70
|
-
validateRequired(idea_id, 'idea_id');
|
|
71
|
-
validateUUID(idea_id, 'idea_id');
|
|
92
|
+
export const deleteIdea = async (args, _ctx) => {
|
|
93
|
+
const { idea_id } = parseArgs(args, deleteIdeaSchema);
|
|
72
94
|
const apiClient = getApiClient();
|
|
73
95
|
const response = await apiClient.deleteIdea(idea_id);
|
|
74
96
|
if (!response.ok) {
|
|
@@ -76,12 +98,8 @@ export const deleteIdea = async (args, ctx) => {
|
|
|
76
98
|
}
|
|
77
99
|
return { result: { success: true } };
|
|
78
100
|
};
|
|
79
|
-
export const convertIdeaToTask = async (args,
|
|
80
|
-
const { idea_id, priority
|
|
81
|
-
validateRequired(idea_id, 'idea_id');
|
|
82
|
-
validateUUID(idea_id, 'idea_id');
|
|
83
|
-
validatePriority(priority);
|
|
84
|
-
validateEstimatedMinutes(estimated_minutes);
|
|
101
|
+
export const convertIdeaToTask = async (args, _ctx) => {
|
|
102
|
+
const { idea_id, priority, estimated_minutes, update_status } = parseArgs(args, convertIdeaToTaskSchema);
|
|
85
103
|
const apiClient = getApiClient();
|
|
86
104
|
// Use proxy for convert_idea_to_task operation
|
|
87
105
|
const response = await apiClient.proxy('convert_idea_to_task', {
|