@vibescope/mcp-server 0.2.0 → 0.2.2
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 +60 -7
- package/dist/api-client.d.ts +251 -1
- package/dist/api-client.js +82 -3
- package/dist/handlers/blockers.js +9 -8
- package/dist/handlers/bodies-of-work.js +96 -63
- package/dist/handlers/connectors.d.ts +45 -0
- package/dist/handlers/connectors.js +183 -0
- package/dist/handlers/cost.d.ts +10 -0
- package/dist/handlers/cost.js +112 -50
- package/dist/handlers/decisions.js +32 -19
- package/dist/handlers/deployment.js +144 -122
- package/dist/handlers/discovery.d.ts +7 -0
- package/dist/handlers/discovery.js +96 -7
- package/dist/handlers/fallback.js +29 -23
- package/dist/handlers/file-checkouts.d.ts +20 -0
- package/dist/handlers/file-checkouts.js +133 -0
- package/dist/handlers/findings.d.ts +6 -0
- package/dist/handlers/findings.js +96 -40
- package/dist/handlers/git-issues.js +40 -36
- package/dist/handlers/ideas.js +49 -31
- package/dist/handlers/index.d.ts +3 -0
- package/dist/handlers/index.js +9 -0
- package/dist/handlers/milestones.js +39 -32
- package/dist/handlers/organizations.js +99 -91
- package/dist/handlers/progress.js +24 -13
- package/dist/handlers/project.js +68 -28
- package/dist/handlers/requests.js +18 -14
- package/dist/handlers/roles.d.ts +18 -0
- package/dist/handlers/roles.js +130 -0
- package/dist/handlers/session.js +58 -17
- package/dist/handlers/sprints.js +93 -81
- package/dist/handlers/tasks.d.ts +2 -0
- package/dist/handlers/tasks.js +189 -91
- package/dist/handlers/types.d.ts +64 -2
- package/dist/handlers/types.js +48 -1
- package/dist/handlers/validation.js +21 -17
- package/dist/index.js +7 -2716
- package/dist/token-tracking.d.ts +74 -0
- package/dist/token-tracking.js +122 -0
- package/dist/tools.js +685 -9
- package/dist/utils.d.ts +5 -0
- package/dist/utils.js +17 -0
- package/docs/TOOLS.md +2053 -0
- package/package.json +4 -1
- package/scripts/generate-docs.ts +212 -0
- package/src/api-client.test.ts +718 -0
- package/src/api-client.ts +320 -6
- package/src/handlers/__test-setup__.ts +16 -0
- package/src/handlers/blockers.test.ts +31 -19
- package/src/handlers/blockers.ts +9 -8
- package/src/handlers/bodies-of-work.test.ts +55 -32
- package/src/handlers/bodies-of-work.ts +115 -115
- package/src/handlers/connectors.test.ts +834 -0
- package/src/handlers/connectors.ts +229 -0
- package/src/handlers/cost.test.ts +34 -44
- package/src/handlers/cost.ts +136 -85
- package/src/handlers/decisions.test.ts +37 -27
- package/src/handlers/decisions.ts +35 -30
- package/src/handlers/deployment.ts +180 -208
- package/src/handlers/discovery.test.ts +4 -5
- package/src/handlers/discovery.ts +98 -8
- package/src/handlers/fallback.test.ts +26 -22
- package/src/handlers/fallback.ts +36 -33
- package/src/handlers/file-checkouts.test.ts +670 -0
- package/src/handlers/file-checkouts.ts +165 -0
- package/src/handlers/findings.test.ts +178 -19
- package/src/handlers/findings.ts +112 -74
- package/src/handlers/git-issues.test.ts +51 -43
- package/src/handlers/git-issues.ts +44 -84
- package/src/handlers/ideas.test.ts +28 -23
- package/src/handlers/ideas.ts +61 -59
- package/src/handlers/index.ts +9 -0
- package/src/handlers/milestones.test.ts +33 -28
- package/src/handlers/milestones.ts +52 -50
- package/src/handlers/organizations.test.ts +104 -83
- package/src/handlers/organizations.ts +117 -142
- package/src/handlers/progress.test.ts +20 -14
- package/src/handlers/progress.ts +26 -24
- package/src/handlers/project.test.ts +34 -27
- package/src/handlers/project.ts +95 -63
- package/src/handlers/requests.test.ts +27 -18
- package/src/handlers/requests.ts +21 -17
- package/src/handlers/roles.test.ts +303 -0
- package/src/handlers/roles.ts +208 -0
- package/src/handlers/session.test.ts +47 -0
- package/src/handlers/session.ts +71 -26
- package/src/handlers/sprints.test.ts +71 -50
- package/src/handlers/sprints.ts +113 -146
- package/src/handlers/tasks.test.ts +77 -15
- package/src/handlers/tasks.ts +231 -156
- package/src/handlers/tool-categories.test.ts +66 -0
- package/src/handlers/types.ts +81 -2
- package/src/handlers/validation.test.ts +78 -45
- package/src/handlers/validation.ts +23 -25
- package/src/index.ts +12 -2732
- package/src/token-tracking.test.ts +453 -0
- package/src/token-tracking.ts +164 -0
- package/src/tools.ts +685 -9
- package/src/utils.test.ts +2 -2
- package/src/utils.ts +17 -0
- 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
|
@@ -7,13 +7,24 @@
|
|
|
7
7
|
*
|
|
8
8
|
* MIGRATED: Uses Vibescope API client instead of direct Supabase
|
|
9
9
|
*/
|
|
10
|
-
import {
|
|
10
|
+
import { parseArgs, uuidValidator } from '../validators.js';
|
|
11
11
|
import { getApiClient } from '../api-client.js';
|
|
12
|
+
// Argument schemas for type-safe parsing
|
|
13
|
+
const logProgressSchema = {
|
|
14
|
+
project_id: { type: 'string', required: true, validate: uuidValidator },
|
|
15
|
+
task_id: { type: 'string', validate: uuidValidator },
|
|
16
|
+
summary: { type: 'string', required: true },
|
|
17
|
+
details: { type: 'string' },
|
|
18
|
+
};
|
|
19
|
+
const getActivityFeedSchema = {
|
|
20
|
+
project_id: { type: 'string', required: true, validate: uuidValidator },
|
|
21
|
+
limit: { type: 'number', default: 50 },
|
|
22
|
+
since: { type: 'string' },
|
|
23
|
+
types: { type: 'array' },
|
|
24
|
+
created_by: { type: 'string' },
|
|
25
|
+
};
|
|
12
26
|
export const logProgress = async (args, ctx) => {
|
|
13
|
-
const { project_id, task_id, summary, details } = args;
|
|
14
|
-
validateRequired(project_id, 'project_id');
|
|
15
|
-
validateUUID(project_id, 'project_id');
|
|
16
|
-
validateRequired(summary, 'summary');
|
|
27
|
+
const { project_id, task_id, summary, details } = parseArgs(args, logProgressSchema);
|
|
17
28
|
const { session } = ctx;
|
|
18
29
|
const apiClient = getApiClient();
|
|
19
30
|
const response = await apiClient.logProgress(project_id, {
|
|
@@ -23,22 +34,22 @@ export const logProgress = async (args, ctx) => {
|
|
|
23
34
|
session_id: session.currentSessionId || undefined
|
|
24
35
|
});
|
|
25
36
|
if (!response.ok) {
|
|
26
|
-
|
|
37
|
+
return { result: { error: response.error || 'Failed to log progress' }, isError: true };
|
|
27
38
|
}
|
|
28
39
|
return { result: { success: true, progress_id: response.data?.progress_id } };
|
|
29
40
|
};
|
|
30
|
-
export const getActivityFeed = async (args,
|
|
31
|
-
const { project_id, limit
|
|
32
|
-
validateRequired(project_id, 'project_id');
|
|
33
|
-
validateUUID(project_id, 'project_id');
|
|
41
|
+
export const getActivityFeed = async (args, _ctx) => {
|
|
42
|
+
const { project_id, limit, since, types, created_by } = parseArgs(args, getActivityFeedSchema);
|
|
34
43
|
const apiClient = getApiClient();
|
|
35
|
-
const effectiveLimit = Math.min(limit, 200);
|
|
44
|
+
const effectiveLimit = Math.min(limit ?? 50, 200);
|
|
36
45
|
const response = await apiClient.getActivityFeed(project_id, {
|
|
37
46
|
limit: effectiveLimit,
|
|
38
|
-
since
|
|
47
|
+
since,
|
|
48
|
+
types: types,
|
|
49
|
+
created_by
|
|
39
50
|
});
|
|
40
51
|
if (!response.ok) {
|
|
41
|
-
|
|
52
|
+
return { result: { error: response.error || 'Failed to fetch activity feed' }, isError: true };
|
|
42
53
|
}
|
|
43
54
|
return { result: { activities: response.data?.activities || [] } };
|
|
44
55
|
};
|
package/dist/handlers/project.js
CHANGED
|
@@ -8,23 +8,59 @@
|
|
|
8
8
|
* - update_project
|
|
9
9
|
* - update_project_readme
|
|
10
10
|
*/
|
|
11
|
-
import {
|
|
11
|
+
import { parseArgs, uuidValidator, projectStatusValidator, createEnumValidator, } from '../validators.js';
|
|
12
12
|
import { getApiClient } from '../api-client.js';
|
|
13
|
-
|
|
14
|
-
|
|
13
|
+
const VALID_GIT_WORKFLOWS = ['none', 'trunk-based', 'github-flow', 'git-flow'];
|
|
14
|
+
// Argument schemas for type-safe parsing
|
|
15
|
+
const getProjectContextSchema = {
|
|
16
|
+
project_id: { type: 'string', validate: uuidValidator },
|
|
17
|
+
git_url: { type: 'string' },
|
|
18
|
+
};
|
|
19
|
+
const getGitWorkflowSchema = {
|
|
20
|
+
project_id: { type: 'string', required: true, validate: uuidValidator },
|
|
21
|
+
task_id: { type: 'string', validate: uuidValidator },
|
|
22
|
+
};
|
|
23
|
+
const createProjectSchema = {
|
|
24
|
+
name: { type: 'string', required: true },
|
|
25
|
+
description: { type: 'string' },
|
|
26
|
+
goal: { type: 'string' },
|
|
27
|
+
git_url: { type: 'string' },
|
|
28
|
+
tech_stack: { type: 'array' },
|
|
29
|
+
};
|
|
30
|
+
const updateProjectSchema = {
|
|
31
|
+
project_id: { type: 'string', required: true, validate: uuidValidator },
|
|
32
|
+
name: { type: 'string' },
|
|
33
|
+
description: { type: 'string' },
|
|
34
|
+
goal: { type: 'string' },
|
|
35
|
+
git_url: { type: 'string' },
|
|
36
|
+
tech_stack: { type: 'array' },
|
|
37
|
+
status: { type: 'string', validate: projectStatusValidator },
|
|
38
|
+
git_workflow: { type: 'string', validate: createEnumValidator(VALID_GIT_WORKFLOWS) },
|
|
39
|
+
git_main_branch: { type: 'string' },
|
|
40
|
+
git_develop_branch: { type: 'string' },
|
|
41
|
+
git_auto_branch: { type: 'boolean' },
|
|
42
|
+
git_auto_tag: { type: 'boolean' },
|
|
43
|
+
deployment_instructions: { type: 'string' },
|
|
44
|
+
};
|
|
45
|
+
const updateProjectReadmeSchema = {
|
|
46
|
+
project_id: { type: 'string', required: true, validate: uuidValidator },
|
|
47
|
+
readme_content: { type: 'string', required: true },
|
|
48
|
+
};
|
|
49
|
+
export const getProjectContext = async (args, _ctx) => {
|
|
50
|
+
const { project_id, git_url } = parseArgs(args, getProjectContextSchema);
|
|
15
51
|
const apiClient = getApiClient();
|
|
16
52
|
// If no project_id or git_url, list all projects
|
|
17
53
|
if (!project_id && !git_url) {
|
|
18
54
|
const response = await apiClient.listProjects();
|
|
19
55
|
if (!response.ok) {
|
|
20
|
-
|
|
56
|
+
return { result: { error: response.error || 'Failed to fetch projects' }, isError: true };
|
|
21
57
|
}
|
|
22
58
|
return { result: { projects: response.data?.projects || [] } };
|
|
23
59
|
}
|
|
24
60
|
// Find project by ID or git_url
|
|
25
61
|
const response = await apiClient.getProject(project_id || 'by-git-url', git_url);
|
|
26
62
|
if (!response.ok) {
|
|
27
|
-
|
|
63
|
+
return { result: { error: response.error || 'Failed to fetch project' }, isError: true };
|
|
28
64
|
}
|
|
29
65
|
if (!response.data?.found) {
|
|
30
66
|
return {
|
|
@@ -36,54 +72,58 @@ export const getProjectContext = async (args, ctx) => {
|
|
|
36
72
|
}
|
|
37
73
|
return { result: response.data };
|
|
38
74
|
};
|
|
39
|
-
export const getGitWorkflow = async (args,
|
|
40
|
-
const { project_id, task_id } = args;
|
|
41
|
-
validateRequired(project_id, 'project_id');
|
|
42
|
-
validateUUID(project_id, 'project_id');
|
|
75
|
+
export const getGitWorkflow = async (args, _ctx) => {
|
|
76
|
+
const { project_id, task_id } = parseArgs(args, getGitWorkflowSchema);
|
|
43
77
|
const apiClient = getApiClient();
|
|
44
78
|
const response = await apiClient.getGitWorkflow(project_id, task_id);
|
|
45
79
|
if (!response.ok) {
|
|
46
|
-
|
|
80
|
+
return { result: { error: response.error || 'Failed to get git workflow' }, isError: true };
|
|
47
81
|
}
|
|
48
82
|
return { result: response.data };
|
|
49
83
|
};
|
|
50
|
-
export const createProject = async (args,
|
|
51
|
-
const { name, description, goal, git_url, tech_stack } = args;
|
|
52
|
-
validateRequired(name, 'name');
|
|
84
|
+
export const createProject = async (args, _ctx) => {
|
|
85
|
+
const { name, description, goal, git_url, tech_stack } = parseArgs(args, createProjectSchema);
|
|
53
86
|
const apiClient = getApiClient();
|
|
54
87
|
const response = await apiClient.createProject({
|
|
55
88
|
name,
|
|
56
89
|
description,
|
|
57
90
|
goal,
|
|
58
91
|
git_url,
|
|
59
|
-
tech_stack
|
|
92
|
+
tech_stack: tech_stack
|
|
60
93
|
});
|
|
61
94
|
if (!response.ok) {
|
|
62
|
-
|
|
95
|
+
return { result: { error: response.error || 'Failed to create project' }, isError: true };
|
|
63
96
|
}
|
|
64
97
|
return { result: response.data };
|
|
65
98
|
};
|
|
66
|
-
export const updateProject = async (args,
|
|
67
|
-
const { project_id,
|
|
68
|
-
validateRequired(project_id, 'project_id');
|
|
69
|
-
validateUUID(project_id, 'project_id');
|
|
70
|
-
validateProjectStatus(updates.status);
|
|
99
|
+
export const updateProject = async (args, _ctx) => {
|
|
100
|
+
const { project_id, name, description, goal, git_url, tech_stack, status, git_workflow, git_main_branch, git_develop_branch, git_auto_branch, git_auto_tag, deployment_instructions } = parseArgs(args, updateProjectSchema);
|
|
71
101
|
const apiClient = getApiClient();
|
|
72
|
-
const response = await apiClient.updateProject(project_id,
|
|
102
|
+
const response = await apiClient.updateProject(project_id, {
|
|
103
|
+
name,
|
|
104
|
+
description,
|
|
105
|
+
goal,
|
|
106
|
+
git_url,
|
|
107
|
+
tech_stack: tech_stack,
|
|
108
|
+
status: status,
|
|
109
|
+
git_workflow: git_workflow,
|
|
110
|
+
git_main_branch,
|
|
111
|
+
git_develop_branch,
|
|
112
|
+
git_auto_branch,
|
|
113
|
+
git_auto_tag,
|
|
114
|
+
deployment_instructions
|
|
115
|
+
});
|
|
73
116
|
if (!response.ok) {
|
|
74
|
-
|
|
117
|
+
return { result: { error: response.error || 'Failed to update project' }, isError: true };
|
|
75
118
|
}
|
|
76
119
|
return { result: response.data };
|
|
77
120
|
};
|
|
78
|
-
export const updateProjectReadme = async (args,
|
|
79
|
-
const { project_id, readme_content } = args;
|
|
80
|
-
validateRequired(project_id, 'project_id');
|
|
81
|
-
validateUUID(project_id, 'project_id');
|
|
82
|
-
validateRequired(readme_content, 'readme_content');
|
|
121
|
+
export const updateProjectReadme = async (args, _ctx) => {
|
|
122
|
+
const { project_id, readme_content } = parseArgs(args, updateProjectReadmeSchema);
|
|
83
123
|
const apiClient = getApiClient();
|
|
84
124
|
const response = await apiClient.updateProjectReadme(project_id, readme_content);
|
|
85
125
|
if (!response.ok) {
|
|
86
|
-
|
|
126
|
+
return { result: { error: response.error || 'Failed to update README' }, isError: true };
|
|
87
127
|
}
|
|
88
128
|
return { result: response.data };
|
|
89
129
|
};
|
|
@@ -8,17 +8,26 @@
|
|
|
8
8
|
*
|
|
9
9
|
* MIGRATED: Uses Vibescope API client instead of direct Supabase
|
|
10
10
|
*/
|
|
11
|
-
import {
|
|
11
|
+
import { parseArgs, uuidValidator } from '../validators.js';
|
|
12
12
|
import { getApiClient } from '../api-client.js';
|
|
13
|
+
// Argument schemas for type-safe parsing
|
|
14
|
+
const getPendingRequestsSchema = {
|
|
15
|
+
project_id: { type: 'string', required: true, validate: uuidValidator },
|
|
16
|
+
};
|
|
17
|
+
const acknowledgeRequestSchema = {
|
|
18
|
+
request_id: { type: 'string', required: true, validate: uuidValidator },
|
|
19
|
+
};
|
|
20
|
+
const answerQuestionSchema = {
|
|
21
|
+
request_id: { type: 'string', required: true, validate: uuidValidator },
|
|
22
|
+
answer: { type: 'string', required: true },
|
|
23
|
+
};
|
|
13
24
|
export const getPendingRequests = async (args, ctx) => {
|
|
14
|
-
const { project_id } = args;
|
|
15
|
-
validateRequired(project_id, 'project_id');
|
|
16
|
-
validateUUID(project_id, 'project_id');
|
|
25
|
+
const { project_id } = parseArgs(args, getPendingRequestsSchema);
|
|
17
26
|
const { session } = ctx;
|
|
18
27
|
const apiClient = getApiClient();
|
|
19
28
|
const response = await apiClient.getPendingRequests(project_id, session.currentSessionId || undefined);
|
|
20
29
|
if (!response.ok) {
|
|
21
|
-
|
|
30
|
+
return { result: { error: response.error || 'Failed to get pending requests' }, isError: true };
|
|
22
31
|
}
|
|
23
32
|
return {
|
|
24
33
|
result: {
|
|
@@ -28,14 +37,12 @@ export const getPendingRequests = async (args, ctx) => {
|
|
|
28
37
|
};
|
|
29
38
|
};
|
|
30
39
|
export const acknowledgeRequest = async (args, ctx) => {
|
|
31
|
-
const { request_id } = args;
|
|
32
|
-
validateRequired(request_id, 'request_id');
|
|
33
|
-
validateUUID(request_id, 'request_id');
|
|
40
|
+
const { request_id } = parseArgs(args, acknowledgeRequestSchema);
|
|
34
41
|
const { session } = ctx;
|
|
35
42
|
const apiClient = getApiClient();
|
|
36
43
|
const response = await apiClient.acknowledgeRequest(request_id, session.currentSessionId || undefined);
|
|
37
44
|
if (!response.ok) {
|
|
38
|
-
|
|
45
|
+
return { result: { error: response.error || 'Failed to acknowledge request' }, isError: true };
|
|
39
46
|
}
|
|
40
47
|
return {
|
|
41
48
|
result: {
|
|
@@ -44,15 +51,12 @@ export const acknowledgeRequest = async (args, ctx) => {
|
|
|
44
51
|
};
|
|
45
52
|
};
|
|
46
53
|
export const answerQuestion = async (args, ctx) => {
|
|
47
|
-
const { request_id, answer } = args;
|
|
48
|
-
validateRequired(request_id, 'request_id');
|
|
49
|
-
validateRequired(answer, 'answer');
|
|
50
|
-
validateUUID(request_id, 'request_id');
|
|
54
|
+
const { request_id, answer } = parseArgs(args, answerQuestionSchema);
|
|
51
55
|
const { session } = ctx;
|
|
52
56
|
const apiClient = getApiClient();
|
|
53
57
|
const response = await apiClient.answerQuestion(request_id, answer, session.currentSessionId || undefined);
|
|
54
58
|
if (!response.ok) {
|
|
55
|
-
|
|
59
|
+
return { result: { error: response.error || 'Failed to answer question' }, isError: true };
|
|
56
60
|
}
|
|
57
61
|
return {
|
|
58
62
|
result: {
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Role Management Handlers
|
|
3
|
+
*
|
|
4
|
+
* Handles agent role configuration and assignment:
|
|
5
|
+
* - get_role_settings: Get role configuration for a project
|
|
6
|
+
* - update_role_settings: Update role settings for a project
|
|
7
|
+
* - set_session_role: Set the role for the current session
|
|
8
|
+
* - get_agents_by_role: Get active agents grouped by their assigned roles
|
|
9
|
+
*/
|
|
10
|
+
import type { Handler, HandlerRegistry } from './types.js';
|
|
11
|
+
export declare const getRoleSettings: Handler;
|
|
12
|
+
export declare const updateRoleSettings: Handler;
|
|
13
|
+
export declare const setSessionRole: Handler;
|
|
14
|
+
export declare const getAgentsByRole: Handler;
|
|
15
|
+
/**
|
|
16
|
+
* Role handlers registry
|
|
17
|
+
*/
|
|
18
|
+
export declare const roleHandlers: HandlerRegistry;
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Role Management Handlers
|
|
3
|
+
*
|
|
4
|
+
* Handles agent role configuration and assignment:
|
|
5
|
+
* - get_role_settings: Get role configuration for a project
|
|
6
|
+
* - update_role_settings: Update role settings for a project
|
|
7
|
+
* - set_session_role: Set the role for the current session
|
|
8
|
+
* - get_agents_by_role: Get active agents grouped by their assigned roles
|
|
9
|
+
*/
|
|
10
|
+
import { getApiClient } from '../api-client.js';
|
|
11
|
+
export const getRoleSettings = async (args, _ctx) => {
|
|
12
|
+
const { project_id } = args;
|
|
13
|
+
if (!project_id) {
|
|
14
|
+
return {
|
|
15
|
+
result: { error: 'project_id is required' },
|
|
16
|
+
};
|
|
17
|
+
}
|
|
18
|
+
const apiClient = getApiClient();
|
|
19
|
+
const response = await apiClient.proxy('get_role_settings', { project_id });
|
|
20
|
+
if (!response.ok) {
|
|
21
|
+
return {
|
|
22
|
+
result: { error: response.error || 'Failed to get role settings' },
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
return { result: response.data };
|
|
26
|
+
};
|
|
27
|
+
export const updateRoleSettings = async (args, _ctx) => {
|
|
28
|
+
const { project_id, role, enabled, display_name, description, priority_filter, fallback_activities, auto_assign_validation, auto_assign_deployment, } = args;
|
|
29
|
+
if (!project_id) {
|
|
30
|
+
return {
|
|
31
|
+
result: { error: 'project_id is required' },
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
if (!role) {
|
|
35
|
+
return {
|
|
36
|
+
result: { error: 'role is required' },
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
const apiClient = getApiClient();
|
|
40
|
+
const response = await apiClient.proxy('update_role_settings', {
|
|
41
|
+
project_id,
|
|
42
|
+
role,
|
|
43
|
+
enabled,
|
|
44
|
+
display_name,
|
|
45
|
+
description,
|
|
46
|
+
priority_filter,
|
|
47
|
+
fallback_activities,
|
|
48
|
+
auto_assign_validation,
|
|
49
|
+
auto_assign_deployment,
|
|
50
|
+
});
|
|
51
|
+
if (!response.ok) {
|
|
52
|
+
return {
|
|
53
|
+
result: { error: response.error || 'Failed to update role settings' },
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
return { result: response.data };
|
|
57
|
+
};
|
|
58
|
+
export const setSessionRole = async (args, ctx) => {
|
|
59
|
+
const { role, role_config } = args;
|
|
60
|
+
const { session, updateSession } = ctx;
|
|
61
|
+
if (!role) {
|
|
62
|
+
return {
|
|
63
|
+
result: { error: 'role is required' },
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
const validRoles = ['developer', 'validator', 'deployer', 'reviewer', 'maintainer'];
|
|
67
|
+
if (!validRoles.includes(role)) {
|
|
68
|
+
return {
|
|
69
|
+
result: {
|
|
70
|
+
error: `Invalid role: ${role}. Must be one of: ${validRoles.join(', ')}`,
|
|
71
|
+
},
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
// Update local session state
|
|
75
|
+
updateSession({ currentRole: role });
|
|
76
|
+
// If there's an active session, update it on the server too
|
|
77
|
+
if (session.currentSessionId) {
|
|
78
|
+
const apiClient = getApiClient();
|
|
79
|
+
const response = await apiClient.proxy('set_session_role', {
|
|
80
|
+
session_id: session.currentSessionId,
|
|
81
|
+
role,
|
|
82
|
+
role_config,
|
|
83
|
+
});
|
|
84
|
+
if (!response.ok) {
|
|
85
|
+
return {
|
|
86
|
+
result: { error: response.error || 'Failed to update session role' },
|
|
87
|
+
};
|
|
88
|
+
}
|
|
89
|
+
return {
|
|
90
|
+
result: {
|
|
91
|
+
success: true,
|
|
92
|
+
session_id: session.currentSessionId,
|
|
93
|
+
role,
|
|
94
|
+
message: `Session role updated to ${role}. Task filtering and fallback suggestions will now be optimized for this role.`,
|
|
95
|
+
},
|
|
96
|
+
};
|
|
97
|
+
}
|
|
98
|
+
return {
|
|
99
|
+
result: {
|
|
100
|
+
success: true,
|
|
101
|
+
role,
|
|
102
|
+
message: `Local role set to ${role}. Start a session to persist this role.`,
|
|
103
|
+
},
|
|
104
|
+
};
|
|
105
|
+
};
|
|
106
|
+
export const getAgentsByRole = async (args, _ctx) => {
|
|
107
|
+
const { project_id } = args;
|
|
108
|
+
if (!project_id) {
|
|
109
|
+
return {
|
|
110
|
+
result: { error: 'project_id is required' },
|
|
111
|
+
};
|
|
112
|
+
}
|
|
113
|
+
const apiClient = getApiClient();
|
|
114
|
+
const response = await apiClient.proxy('get_agents_by_role', { project_id });
|
|
115
|
+
if (!response.ok) {
|
|
116
|
+
return {
|
|
117
|
+
result: { error: response.error || 'Failed to get agents by role' },
|
|
118
|
+
};
|
|
119
|
+
}
|
|
120
|
+
return { result: response.data };
|
|
121
|
+
};
|
|
122
|
+
/**
|
|
123
|
+
* Role handlers registry
|
|
124
|
+
*/
|
|
125
|
+
export const roleHandlers = {
|
|
126
|
+
get_role_settings: getRoleSettings,
|
|
127
|
+
update_role_settings: updateRoleSettings,
|
|
128
|
+
set_session_role: setSessionRole,
|
|
129
|
+
get_agents_by_role: getAgentsByRole,
|
|
130
|
+
};
|
package/dist/handlers/session.js
CHANGED
|
@@ -8,13 +8,35 @@
|
|
|
8
8
|
* - get_help
|
|
9
9
|
* - get_token_usage
|
|
10
10
|
*/
|
|
11
|
+
import { parseArgs, createEnumValidator } from '../validators.js';
|
|
11
12
|
import { getApiClient } from '../api-client.js';
|
|
13
|
+
const VALID_MODES = ['lite', 'full'];
|
|
14
|
+
const VALID_MODELS = ['opus', 'sonnet', 'haiku'];
|
|
15
|
+
const VALID_ROLES = ['developer', 'validator', 'deployer', 'reviewer', 'maintainer'];
|
|
16
|
+
// Argument schemas for type-safe parsing
|
|
17
|
+
const startWorkSessionSchema = {
|
|
18
|
+
project_id: { type: 'string' },
|
|
19
|
+
git_url: { type: 'string' },
|
|
20
|
+
mode: { type: 'string', default: 'lite', validate: createEnumValidator(VALID_MODES) },
|
|
21
|
+
model: { type: 'string', validate: createEnumValidator(VALID_MODELS) },
|
|
22
|
+
role: { type: 'string', default: 'developer', validate: createEnumValidator(VALID_ROLES) },
|
|
23
|
+
};
|
|
24
|
+
const heartbeatSchema = {
|
|
25
|
+
session_id: { type: 'string' },
|
|
26
|
+
current_worktree_path: { type: 'string' },
|
|
27
|
+
};
|
|
28
|
+
const endWorkSessionSchema = {
|
|
29
|
+
session_id: { type: 'string' },
|
|
30
|
+
};
|
|
31
|
+
const getHelpSchema = {
|
|
32
|
+
topic: { type: 'string', required: true },
|
|
33
|
+
};
|
|
12
34
|
export const startWorkSession = async (args, ctx) => {
|
|
13
|
-
const { project_id, git_url, mode
|
|
35
|
+
const { project_id, git_url, mode, model, role } = parseArgs(args, startWorkSessionSchema);
|
|
14
36
|
const { session, updateSession } = ctx;
|
|
15
37
|
// Reset token tracking for new session with model info
|
|
16
38
|
const normalizedModel = model ? model.toLowerCase().replace(/^claude[- ]*/i, '') : null;
|
|
17
|
-
const validModel = normalizedModel &&
|
|
39
|
+
const validModel = normalizedModel && VALID_MODELS.includes(normalizedModel)
|
|
18
40
|
? normalizedModel
|
|
19
41
|
: null;
|
|
20
42
|
updateSession({
|
|
@@ -38,9 +60,9 @@ export const startWorkSession = async (args, ctx) => {
|
|
|
38
60
|
const response = await apiClient.startSession({
|
|
39
61
|
project_id,
|
|
40
62
|
git_url,
|
|
41
|
-
mode,
|
|
42
|
-
model,
|
|
43
|
-
role
|
|
63
|
+
mode: mode,
|
|
64
|
+
model: model,
|
|
65
|
+
role: role
|
|
44
66
|
});
|
|
45
67
|
if (!response.ok) {
|
|
46
68
|
return {
|
|
@@ -61,20 +83,33 @@ export const startWorkSession = async (args, ctx) => {
|
|
|
61
83
|
currentPersona: data.persona || null,
|
|
62
84
|
});
|
|
63
85
|
}
|
|
64
|
-
//
|
|
86
|
+
// Check for urgent questions - these MUST be handled first
|
|
87
|
+
const hasUrgentQuestions = data.URGENT_QUESTIONS || (data.pending_requests && data.pending_requests.length > 0);
|
|
88
|
+
// Build result - URGENT_QUESTIONS at absolute top for maximum visibility
|
|
65
89
|
const result = {
|
|
66
90
|
session_started: true,
|
|
67
|
-
directive: data.directive || 'ACTION_REQUIRED: Start working immediately.',
|
|
68
|
-
auto_continue: true,
|
|
69
|
-
session_id: data.session_id,
|
|
70
|
-
persona: data.persona,
|
|
71
|
-
role: data.role,
|
|
72
|
-
project: data.project,
|
|
73
91
|
};
|
|
92
|
+
// URGENT_QUESTIONS must be the FIRST thing the agent sees
|
|
93
|
+
if (data.URGENT_QUESTIONS) {
|
|
94
|
+
result.URGENT_QUESTIONS = data.URGENT_QUESTIONS;
|
|
95
|
+
}
|
|
96
|
+
// Directive comes right after urgent questions
|
|
97
|
+
result.directive = data.directive || 'ACTION_REQUIRED: Start working immediately.';
|
|
98
|
+
result.auto_continue = true;
|
|
99
|
+
// Session info
|
|
100
|
+
result.session_id = data.session_id;
|
|
101
|
+
result.persona = data.persona;
|
|
102
|
+
result.role = data.role;
|
|
103
|
+
result.project = data.project;
|
|
74
104
|
// Add task data
|
|
75
105
|
if (data.next_task) {
|
|
76
106
|
result.next_task = data.next_task;
|
|
77
107
|
}
|
|
108
|
+
// Add pending requests (questions from user) - these take priority
|
|
109
|
+
if (data.pending_requests && data.pending_requests.length > 0) {
|
|
110
|
+
result.pending_requests = data.pending_requests;
|
|
111
|
+
result.pending_requests_count = data.pending_requests.length;
|
|
112
|
+
}
|
|
78
113
|
// Add active tasks for full mode
|
|
79
114
|
if (data.active_tasks) {
|
|
80
115
|
result.active_tasks = data.active_tasks;
|
|
@@ -103,8 +138,14 @@ export const startWorkSession = async (args, ctx) => {
|
|
|
103
138
|
worktree_hint: 'CRITICAL: Create a git worktree before starting work. Run get_help("git") for instructions.',
|
|
104
139
|
};
|
|
105
140
|
}
|
|
106
|
-
// Add next action at end
|
|
107
|
-
if (
|
|
141
|
+
// Add next action at end - pending requests take priority over tasks
|
|
142
|
+
if (hasUrgentQuestions) {
|
|
143
|
+
const firstQuestion = data.URGENT_QUESTIONS?.requests?.[0] || data.pending_requests?.[0];
|
|
144
|
+
result.next_action = firstQuestion
|
|
145
|
+
? `answer_question(request_id: "${firstQuestion.id}", answer: "...")`
|
|
146
|
+
: 'Check pending_requests and respond using answer_question(request_id, answer)';
|
|
147
|
+
}
|
|
148
|
+
else if (data.next_task) {
|
|
108
149
|
result.next_action = `update_task(task_id: "${data.next_task.id}", status: "in_progress")`;
|
|
109
150
|
}
|
|
110
151
|
else if (data.project) {
|
|
@@ -113,7 +154,7 @@ export const startWorkSession = async (args, ctx) => {
|
|
|
113
154
|
return { result };
|
|
114
155
|
};
|
|
115
156
|
export const heartbeat = async (args, ctx) => {
|
|
116
|
-
const { session_id, current_worktree_path } = args;
|
|
157
|
+
const { session_id, current_worktree_path } = parseArgs(args, heartbeatSchema);
|
|
117
158
|
const { session } = ctx;
|
|
118
159
|
const targetSession = session_id || session.currentSessionId;
|
|
119
160
|
if (!targetSession) {
|
|
@@ -150,7 +191,7 @@ export const heartbeat = async (args, ctx) => {
|
|
|
150
191
|
};
|
|
151
192
|
};
|
|
152
193
|
export const endWorkSession = async (args, ctx) => {
|
|
153
|
-
const { session_id } = args;
|
|
194
|
+
const { session_id } = parseArgs(args, endWorkSessionSchema);
|
|
154
195
|
const { session, updateSession } = ctx;
|
|
155
196
|
const targetSession = session_id || session.currentSessionId;
|
|
156
197
|
if (!targetSession) {
|
|
@@ -205,7 +246,7 @@ export const endWorkSession = async (args, ctx) => {
|
|
|
205
246
|
};
|
|
206
247
|
};
|
|
207
248
|
export const getHelp = async (args, _ctx) => {
|
|
208
|
-
const { topic } = args;
|
|
249
|
+
const { topic } = parseArgs(args, getHelpSchema);
|
|
209
250
|
const apiClient = getApiClient();
|
|
210
251
|
const response = await apiClient.getHelpTopic(topic);
|
|
211
252
|
if (!response.ok) {
|