@vibescope/mcp-server 0.2.5 → 0.2.7
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/CHANGELOG.md +84 -84
- package/README.md +194 -194
- package/dist/cli.js +26 -26
- package/dist/handlers/tool-docs.js +828 -828
- package/dist/index.js +73 -73
- package/dist/templates/agent-guidelines.js +185 -185
- package/dist/token-tracking.js +4 -2
- package/dist/tools.js +65 -65
- package/dist/utils.js +11 -11
- package/docs/TOOLS.md +2053 -2053
- package/package.json +3 -2
- package/scripts/generate-docs.ts +212 -212
- package/scripts/version-bump.ts +203 -203
- package/src/api-client.test.ts +723 -723
- package/src/api-client.ts +2499 -2499
- package/src/cli.ts +212 -212
- package/src/handlers/__test-setup__.ts +236 -236
- package/src/handlers/__test-utils__.ts +87 -87
- package/src/handlers/blockers.test.ts +468 -468
- package/src/handlers/blockers.ts +163 -163
- package/src/handlers/bodies-of-work.test.ts +704 -704
- package/src/handlers/bodies-of-work.ts +526 -526
- package/src/handlers/connectors.test.ts +834 -834
- package/src/handlers/connectors.ts +229 -229
- package/src/handlers/cost.test.ts +462 -462
- package/src/handlers/cost.ts +285 -285
- package/src/handlers/decisions.test.ts +382 -382
- package/src/handlers/decisions.ts +153 -153
- package/src/handlers/deployment.test.ts +551 -551
- package/src/handlers/deployment.ts +541 -541
- package/src/handlers/discovery.test.ts +206 -206
- package/src/handlers/discovery.ts +390 -390
- package/src/handlers/fallback.test.ts +537 -537
- package/src/handlers/fallback.ts +194 -194
- package/src/handlers/file-checkouts.test.ts +750 -750
- package/src/handlers/file-checkouts.ts +185 -185
- package/src/handlers/findings.test.ts +633 -633
- package/src/handlers/findings.ts +239 -239
- package/src/handlers/git-issues.test.ts +631 -631
- package/src/handlers/git-issues.ts +136 -136
- package/src/handlers/ideas.test.ts +644 -644
- package/src/handlers/ideas.ts +207 -207
- package/src/handlers/index.ts +84 -84
- package/src/handlers/milestones.test.ts +475 -475
- package/src/handlers/milestones.ts +180 -180
- package/src/handlers/organizations.test.ts +826 -826
- package/src/handlers/organizations.ts +315 -315
- package/src/handlers/progress.test.ts +269 -269
- package/src/handlers/progress.ts +77 -77
- package/src/handlers/project.test.ts +546 -546
- package/src/handlers/project.ts +239 -239
- package/src/handlers/requests.test.ts +303 -303
- package/src/handlers/requests.ts +99 -99
- package/src/handlers/roles.test.ts +303 -303
- package/src/handlers/roles.ts +226 -226
- package/src/handlers/session.test.ts +875 -875
- package/src/handlers/session.ts +738 -738
- package/src/handlers/sprints.test.ts +732 -732
- package/src/handlers/sprints.ts +537 -537
- package/src/handlers/tasks.test.ts +907 -907
- package/src/handlers/tasks.ts +945 -945
- package/src/handlers/tool-categories.test.ts +66 -66
- package/src/handlers/tool-docs.ts +1096 -1096
- package/src/handlers/types.test.ts +259 -259
- package/src/handlers/types.ts +175 -175
- package/src/handlers/validation.test.ts +582 -582
- package/src/handlers/validation.ts +97 -97
- package/src/index.ts +792 -792
- package/src/setup.test.ts +233 -231
- package/src/setup.ts +370 -370
- package/src/templates/agent-guidelines.ts +210 -210
- package/src/token-tracking.test.ts +463 -453
- package/src/token-tracking.ts +166 -164
- package/src/tools.ts +3562 -3562
- package/src/utils.test.ts +683 -683
- package/src/utils.ts +436 -436
- package/src/validators.test.ts +223 -223
- package/src/validators.ts +249 -249
- package/tsconfig.json +16 -16
- package/vitest.config.ts +14 -14
- package/dist/knowledge.d.ts +0 -6
- package/dist/knowledge.js +0 -218
|
@@ -1,315 +1,315 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Organizations Handlers
|
|
3
|
-
*
|
|
4
|
-
* Handles organization management, membership, and project sharing:
|
|
5
|
-
* - list_organizations
|
|
6
|
-
* - create_organization
|
|
7
|
-
* - update_organization
|
|
8
|
-
* - delete_organization
|
|
9
|
-
* - list_org_members
|
|
10
|
-
* - invite_member
|
|
11
|
-
* - update_member_role
|
|
12
|
-
* - remove_member
|
|
13
|
-
* - leave_organization
|
|
14
|
-
* - share_project_with_org
|
|
15
|
-
* - update_project_share
|
|
16
|
-
* - unshare_project
|
|
17
|
-
* - list_project_shares
|
|
18
|
-
*/
|
|
19
|
-
|
|
20
|
-
import type { Handler, HandlerRegistry } from './types.js';
|
|
21
|
-
import { parseArgs, uuidValidator, createEnumValidator, ValidationError } from '../validators.js';
|
|
22
|
-
import { getApiClient } from '../api-client.js';
|
|
23
|
-
|
|
24
|
-
// Valid roles in order of permission level
|
|
25
|
-
const ROLE_ORDER = ['viewer', 'member', 'admin', 'owner'] as const;
|
|
26
|
-
const ASSIGNABLE_ROLES = ['viewer', 'member', 'admin'] as const;
|
|
27
|
-
type Role = (typeof ROLE_ORDER)[number];
|
|
28
|
-
type AssignableRole = (typeof ASSIGNABLE_ROLES)[number];
|
|
29
|
-
|
|
30
|
-
// Valid share permissions
|
|
31
|
-
const PERMISSION_ORDER = ['read', 'write', 'admin'] as const;
|
|
32
|
-
type Permission = (typeof PERMISSION_ORDER)[number];
|
|
33
|
-
|
|
34
|
-
// ============================================================================
|
|
35
|
-
// Argument Schemas
|
|
36
|
-
// ============================================================================
|
|
37
|
-
|
|
38
|
-
const createOrganizationSchema = {
|
|
39
|
-
name: { type: 'string' as const, required: true as const },
|
|
40
|
-
description: { type: 'string' as const },
|
|
41
|
-
slug: { type: 'string' as const },
|
|
42
|
-
};
|
|
43
|
-
|
|
44
|
-
const updateOrganizationSchema = {
|
|
45
|
-
organization_id: { type: 'string' as const, required: true as const, validate: uuidValidator },
|
|
46
|
-
name: { type: 'string' as const },
|
|
47
|
-
description: { type: 'string' as const },
|
|
48
|
-
logo_url: { type: 'string' as const },
|
|
49
|
-
};
|
|
50
|
-
|
|
51
|
-
const deleteOrganizationSchema = {
|
|
52
|
-
organization_id: { type: 'string' as const, required: true as const, validate: uuidValidator },
|
|
53
|
-
};
|
|
54
|
-
|
|
55
|
-
const listOrgMembersSchema = {
|
|
56
|
-
organization_id: { type: 'string' as const, required: true as const, validate: uuidValidator },
|
|
57
|
-
};
|
|
58
|
-
|
|
59
|
-
const inviteMemberSchema = {
|
|
60
|
-
organization_id: { type: 'string' as const, required: true as const, validate: uuidValidator },
|
|
61
|
-
email: { type: 'string' as const, required: true as const },
|
|
62
|
-
role: { type: 'string' as const, default: 'member', validate: createEnumValidator(ASSIGNABLE_ROLES) },
|
|
63
|
-
};
|
|
64
|
-
|
|
65
|
-
const updateMemberRoleSchema = {
|
|
66
|
-
organization_id: { type: 'string' as const, required: true as const, validate: uuidValidator },
|
|
67
|
-
user_id: { type: 'string' as const, required: true as const, validate: uuidValidator },
|
|
68
|
-
role: { type: 'string' as const, required: true as const, validate: createEnumValidator(ROLE_ORDER) },
|
|
69
|
-
};
|
|
70
|
-
|
|
71
|
-
const removeMemberSchema = {
|
|
72
|
-
organization_id: { type: 'string' as const, required: true as const, validate: uuidValidator },
|
|
73
|
-
user_id: { type: 'string' as const, required: true as const, validate: uuidValidator },
|
|
74
|
-
};
|
|
75
|
-
|
|
76
|
-
const leaveOrganizationSchema = {
|
|
77
|
-
organization_id: { type: 'string' as const, required: true as const, validate: uuidValidator },
|
|
78
|
-
};
|
|
79
|
-
|
|
80
|
-
const shareProjectWithOrgSchema = {
|
|
81
|
-
project_id: { type: 'string' as const, required: true as const, validate: uuidValidator },
|
|
82
|
-
organization_id: { type: 'string' as const, required: true as const, validate: uuidValidator },
|
|
83
|
-
permission: { type: 'string' as const, default: 'read', validate: createEnumValidator(PERMISSION_ORDER) },
|
|
84
|
-
};
|
|
85
|
-
|
|
86
|
-
const updateProjectShareSchema = {
|
|
87
|
-
project_id: { type: 'string' as const, required: true as const, validate: uuidValidator },
|
|
88
|
-
organization_id: { type: 'string' as const, required: true as const, validate: uuidValidator },
|
|
89
|
-
permission: { type: 'string' as const, required: true as const, validate: createEnumValidator(PERMISSION_ORDER) },
|
|
90
|
-
};
|
|
91
|
-
|
|
92
|
-
const unshareProjectSchema = {
|
|
93
|
-
project_id: { type: 'string' as const, required: true as const, validate: uuidValidator },
|
|
94
|
-
organization_id: { type: 'string' as const, required: true as const, validate: uuidValidator },
|
|
95
|
-
};
|
|
96
|
-
|
|
97
|
-
const listProjectSharesSchema = {
|
|
98
|
-
project_id: { type: 'string' as const, required: true as const, validate: uuidValidator },
|
|
99
|
-
};
|
|
100
|
-
|
|
101
|
-
// ============================================================================
|
|
102
|
-
// Organization Management
|
|
103
|
-
// ============================================================================
|
|
104
|
-
|
|
105
|
-
export const listOrganizations: Handler = async (_args, _ctx) => {
|
|
106
|
-
const apiClient = getApiClient();
|
|
107
|
-
const response = await apiClient.listOrganizations();
|
|
108
|
-
|
|
109
|
-
if (!response.ok) {
|
|
110
|
-
return { result: { error: response.error || 'Failed to list organizations' }, isError: true };
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
return { result: response.data };
|
|
114
|
-
};
|
|
115
|
-
|
|
116
|
-
export const createOrganization: Handler = async (args, _ctx) => {
|
|
117
|
-
const { name, description, slug } = parseArgs(args, createOrganizationSchema);
|
|
118
|
-
|
|
119
|
-
const apiClient = getApiClient();
|
|
120
|
-
const response = await apiClient.createOrganization({
|
|
121
|
-
name,
|
|
122
|
-
description,
|
|
123
|
-
slug
|
|
124
|
-
});
|
|
125
|
-
|
|
126
|
-
if (!response.ok) {
|
|
127
|
-
return { result: { error: response.error || 'Failed to create organization' }, isError: true };
|
|
128
|
-
}
|
|
129
|
-
|
|
130
|
-
return { result: response.data };
|
|
131
|
-
};
|
|
132
|
-
|
|
133
|
-
export const updateOrganization: Handler = async (args, _ctx) => {
|
|
134
|
-
const { organization_id, name, description, logo_url } = parseArgs(args, updateOrganizationSchema);
|
|
135
|
-
|
|
136
|
-
// Check that at least one update is provided
|
|
137
|
-
if (name === undefined && description === undefined && logo_url === undefined) {
|
|
138
|
-
throw new ValidationError('No updates provided');
|
|
139
|
-
}
|
|
140
|
-
|
|
141
|
-
const updates: Record<string, unknown> = {};
|
|
142
|
-
if (name !== undefined) updates.name = name;
|
|
143
|
-
if (description !== undefined) updates.description = description;
|
|
144
|
-
if (logo_url !== undefined) updates.logo_url = logo_url;
|
|
145
|
-
|
|
146
|
-
const apiClient = getApiClient();
|
|
147
|
-
const response = await apiClient.updateOrganization(organization_id, updates);
|
|
148
|
-
|
|
149
|
-
if (!response.ok) {
|
|
150
|
-
return { result: { error: response.error || 'Failed to update organization' }, isError: true };
|
|
151
|
-
}
|
|
152
|
-
|
|
153
|
-
return { result: response.data };
|
|
154
|
-
};
|
|
155
|
-
|
|
156
|
-
export const deleteOrganization: Handler = async (args, _ctx) => {
|
|
157
|
-
const { organization_id } = parseArgs(args, deleteOrganizationSchema);
|
|
158
|
-
|
|
159
|
-
const apiClient = getApiClient();
|
|
160
|
-
const response = await apiClient.deleteOrganization(organization_id);
|
|
161
|
-
|
|
162
|
-
if (!response.ok) {
|
|
163
|
-
return { result: { error: response.error || 'Failed to delete organization' }, isError: true };
|
|
164
|
-
}
|
|
165
|
-
|
|
166
|
-
return { result: response.data };
|
|
167
|
-
};
|
|
168
|
-
|
|
169
|
-
// ============================================================================
|
|
170
|
-
// Member Management
|
|
171
|
-
// ============================================================================
|
|
172
|
-
|
|
173
|
-
export const listOrgMembers: Handler = async (args, _ctx) => {
|
|
174
|
-
const { organization_id } = parseArgs(args, listOrgMembersSchema);
|
|
175
|
-
|
|
176
|
-
const apiClient = getApiClient();
|
|
177
|
-
const response = await apiClient.listOrgMembers(organization_id);
|
|
178
|
-
|
|
179
|
-
if (!response.ok) {
|
|
180
|
-
return { result: { error: response.error || 'Failed to list members' }, isError: true };
|
|
181
|
-
}
|
|
182
|
-
|
|
183
|
-
return { result: response.data };
|
|
184
|
-
};
|
|
185
|
-
|
|
186
|
-
export const inviteMember: Handler = async (args, _ctx) => {
|
|
187
|
-
const { organization_id, email, role } = parseArgs(args, inviteMemberSchema);
|
|
188
|
-
|
|
189
|
-
const apiClient = getApiClient();
|
|
190
|
-
const response = await apiClient.inviteMember(organization_id, email, role as AssignableRole);
|
|
191
|
-
|
|
192
|
-
if (!response.ok) {
|
|
193
|
-
return { result: { error: response.error || 'Failed to create invite' }, isError: true };
|
|
194
|
-
}
|
|
195
|
-
|
|
196
|
-
return { result: response.data };
|
|
197
|
-
};
|
|
198
|
-
|
|
199
|
-
export const updateMemberRole: Handler = async (args, _ctx) => {
|
|
200
|
-
const { organization_id, user_id, role } = parseArgs(args, updateMemberRoleSchema);
|
|
201
|
-
|
|
202
|
-
if (role === 'owner') {
|
|
203
|
-
throw new ValidationError('Cannot assign owner role. Use transfer ownership instead.');
|
|
204
|
-
}
|
|
205
|
-
|
|
206
|
-
const apiClient = getApiClient();
|
|
207
|
-
const response = await apiClient.updateMemberRole(organization_id, user_id, role as Role);
|
|
208
|
-
|
|
209
|
-
if (!response.ok) {
|
|
210
|
-
return { result: { error: response.error || 'Failed to update member role' }, isError: true };
|
|
211
|
-
}
|
|
212
|
-
|
|
213
|
-
return { result: response.data };
|
|
214
|
-
};
|
|
215
|
-
|
|
216
|
-
export const removeMember: Handler = async (args, _ctx) => {
|
|
217
|
-
const { organization_id, user_id } = parseArgs(args, removeMemberSchema);
|
|
218
|
-
|
|
219
|
-
const apiClient = getApiClient();
|
|
220
|
-
const response = await apiClient.removeMember(organization_id, user_id);
|
|
221
|
-
|
|
222
|
-
if (!response.ok) {
|
|
223
|
-
return { result: { error: response.error || 'Failed to remove member' }, isError: true };
|
|
224
|
-
}
|
|
225
|
-
|
|
226
|
-
return { result: response.data };
|
|
227
|
-
};
|
|
228
|
-
|
|
229
|
-
export const leaveOrganization: Handler = async (args, _ctx) => {
|
|
230
|
-
const { organization_id } = parseArgs(args, leaveOrganizationSchema);
|
|
231
|
-
|
|
232
|
-
const apiClient = getApiClient();
|
|
233
|
-
const response = await apiClient.leaveOrganization(organization_id);
|
|
234
|
-
|
|
235
|
-
if (!response.ok) {
|
|
236
|
-
return { result: { error: response.error || 'Failed to leave organization' }, isError: true };
|
|
237
|
-
}
|
|
238
|
-
|
|
239
|
-
return { result: response.data };
|
|
240
|
-
};
|
|
241
|
-
|
|
242
|
-
// ============================================================================
|
|
243
|
-
// Project Sharing
|
|
244
|
-
// ============================================================================
|
|
245
|
-
|
|
246
|
-
export const shareProjectWithOrg: Handler = async (args, _ctx) => {
|
|
247
|
-
const { project_id, organization_id, permission } = parseArgs(args, shareProjectWithOrgSchema);
|
|
248
|
-
|
|
249
|
-
const apiClient = getApiClient();
|
|
250
|
-
const response = await apiClient.shareProjectWithOrg(project_id, organization_id, permission as Permission);
|
|
251
|
-
|
|
252
|
-
if (!response.ok) {
|
|
253
|
-
return { result: { error: response.error || 'Failed to share project' }, isError: true };
|
|
254
|
-
}
|
|
255
|
-
|
|
256
|
-
return { result: response.data };
|
|
257
|
-
};
|
|
258
|
-
|
|
259
|
-
export const updateProjectShare: Handler = async (args, _ctx) => {
|
|
260
|
-
const { project_id, organization_id, permission } = parseArgs(args, updateProjectShareSchema);
|
|
261
|
-
|
|
262
|
-
const apiClient = getApiClient();
|
|
263
|
-
const response = await apiClient.updateProjectShare(project_id, organization_id, permission as Permission);
|
|
264
|
-
|
|
265
|
-
if (!response.ok) {
|
|
266
|
-
return { result: { error: response.error || 'Failed to update share' }, isError: true };
|
|
267
|
-
}
|
|
268
|
-
|
|
269
|
-
return { result: response.data };
|
|
270
|
-
};
|
|
271
|
-
|
|
272
|
-
export const unshareProject: Handler = async (args, _ctx) => {
|
|
273
|
-
const { project_id, organization_id } = parseArgs(args, unshareProjectSchema);
|
|
274
|
-
|
|
275
|
-
const apiClient = getApiClient();
|
|
276
|
-
const response = await apiClient.unshareProject(project_id, organization_id);
|
|
277
|
-
|
|
278
|
-
if (!response.ok) {
|
|
279
|
-
return { result: { error: response.error || 'Failed to unshare project' }, isError: true };
|
|
280
|
-
}
|
|
281
|
-
|
|
282
|
-
return { result: response.data };
|
|
283
|
-
};
|
|
284
|
-
|
|
285
|
-
export const listProjectShares: Handler = async (args, _ctx) => {
|
|
286
|
-
const { project_id } = parseArgs(args, listProjectSharesSchema);
|
|
287
|
-
|
|
288
|
-
const apiClient = getApiClient();
|
|
289
|
-
const response = await apiClient.listProjectShares(project_id);
|
|
290
|
-
|
|
291
|
-
if (!response.ok) {
|
|
292
|
-
return { result: { error: response.error || 'Failed to list shares' }, isError: true };
|
|
293
|
-
}
|
|
294
|
-
|
|
295
|
-
return { result: response.data };
|
|
296
|
-
};
|
|
297
|
-
|
|
298
|
-
/**
|
|
299
|
-
* Organizations handlers registry
|
|
300
|
-
*/
|
|
301
|
-
export const organizationHandlers: HandlerRegistry = {
|
|
302
|
-
list_organizations: listOrganizations,
|
|
303
|
-
create_organization: createOrganization,
|
|
304
|
-
update_organization: updateOrganization,
|
|
305
|
-
delete_organization: deleteOrganization,
|
|
306
|
-
list_org_members: listOrgMembers,
|
|
307
|
-
invite_member: inviteMember,
|
|
308
|
-
update_member_role: updateMemberRole,
|
|
309
|
-
remove_member: removeMember,
|
|
310
|
-
leave_organization: leaveOrganization,
|
|
311
|
-
share_project_with_org: shareProjectWithOrg,
|
|
312
|
-
update_project_share: updateProjectShare,
|
|
313
|
-
unshare_project: unshareProject,
|
|
314
|
-
list_project_shares: listProjectShares,
|
|
315
|
-
};
|
|
1
|
+
/**
|
|
2
|
+
* Organizations Handlers
|
|
3
|
+
*
|
|
4
|
+
* Handles organization management, membership, and project sharing:
|
|
5
|
+
* - list_organizations
|
|
6
|
+
* - create_organization
|
|
7
|
+
* - update_organization
|
|
8
|
+
* - delete_organization
|
|
9
|
+
* - list_org_members
|
|
10
|
+
* - invite_member
|
|
11
|
+
* - update_member_role
|
|
12
|
+
* - remove_member
|
|
13
|
+
* - leave_organization
|
|
14
|
+
* - share_project_with_org
|
|
15
|
+
* - update_project_share
|
|
16
|
+
* - unshare_project
|
|
17
|
+
* - list_project_shares
|
|
18
|
+
*/
|
|
19
|
+
|
|
20
|
+
import type { Handler, HandlerRegistry } from './types.js';
|
|
21
|
+
import { parseArgs, uuidValidator, createEnumValidator, ValidationError } from '../validators.js';
|
|
22
|
+
import { getApiClient } from '../api-client.js';
|
|
23
|
+
|
|
24
|
+
// Valid roles in order of permission level
|
|
25
|
+
const ROLE_ORDER = ['viewer', 'member', 'admin', 'owner'] as const;
|
|
26
|
+
const ASSIGNABLE_ROLES = ['viewer', 'member', 'admin'] as const;
|
|
27
|
+
type Role = (typeof ROLE_ORDER)[number];
|
|
28
|
+
type AssignableRole = (typeof ASSIGNABLE_ROLES)[number];
|
|
29
|
+
|
|
30
|
+
// Valid share permissions
|
|
31
|
+
const PERMISSION_ORDER = ['read', 'write', 'admin'] as const;
|
|
32
|
+
type Permission = (typeof PERMISSION_ORDER)[number];
|
|
33
|
+
|
|
34
|
+
// ============================================================================
|
|
35
|
+
// Argument Schemas
|
|
36
|
+
// ============================================================================
|
|
37
|
+
|
|
38
|
+
const createOrganizationSchema = {
|
|
39
|
+
name: { type: 'string' as const, required: true as const },
|
|
40
|
+
description: { type: 'string' as const },
|
|
41
|
+
slug: { type: 'string' as const },
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
const updateOrganizationSchema = {
|
|
45
|
+
organization_id: { type: 'string' as const, required: true as const, validate: uuidValidator },
|
|
46
|
+
name: { type: 'string' as const },
|
|
47
|
+
description: { type: 'string' as const },
|
|
48
|
+
logo_url: { type: 'string' as const },
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
const deleteOrganizationSchema = {
|
|
52
|
+
organization_id: { type: 'string' as const, required: true as const, validate: uuidValidator },
|
|
53
|
+
};
|
|
54
|
+
|
|
55
|
+
const listOrgMembersSchema = {
|
|
56
|
+
organization_id: { type: 'string' as const, required: true as const, validate: uuidValidator },
|
|
57
|
+
};
|
|
58
|
+
|
|
59
|
+
const inviteMemberSchema = {
|
|
60
|
+
organization_id: { type: 'string' as const, required: true as const, validate: uuidValidator },
|
|
61
|
+
email: { type: 'string' as const, required: true as const },
|
|
62
|
+
role: { type: 'string' as const, default: 'member', validate: createEnumValidator(ASSIGNABLE_ROLES) },
|
|
63
|
+
};
|
|
64
|
+
|
|
65
|
+
const updateMemberRoleSchema = {
|
|
66
|
+
organization_id: { type: 'string' as const, required: true as const, validate: uuidValidator },
|
|
67
|
+
user_id: { type: 'string' as const, required: true as const, validate: uuidValidator },
|
|
68
|
+
role: { type: 'string' as const, required: true as const, validate: createEnumValidator(ROLE_ORDER) },
|
|
69
|
+
};
|
|
70
|
+
|
|
71
|
+
const removeMemberSchema = {
|
|
72
|
+
organization_id: { type: 'string' as const, required: true as const, validate: uuidValidator },
|
|
73
|
+
user_id: { type: 'string' as const, required: true as const, validate: uuidValidator },
|
|
74
|
+
};
|
|
75
|
+
|
|
76
|
+
const leaveOrganizationSchema = {
|
|
77
|
+
organization_id: { type: 'string' as const, required: true as const, validate: uuidValidator },
|
|
78
|
+
};
|
|
79
|
+
|
|
80
|
+
const shareProjectWithOrgSchema = {
|
|
81
|
+
project_id: { type: 'string' as const, required: true as const, validate: uuidValidator },
|
|
82
|
+
organization_id: { type: 'string' as const, required: true as const, validate: uuidValidator },
|
|
83
|
+
permission: { type: 'string' as const, default: 'read', validate: createEnumValidator(PERMISSION_ORDER) },
|
|
84
|
+
};
|
|
85
|
+
|
|
86
|
+
const updateProjectShareSchema = {
|
|
87
|
+
project_id: { type: 'string' as const, required: true as const, validate: uuidValidator },
|
|
88
|
+
organization_id: { type: 'string' as const, required: true as const, validate: uuidValidator },
|
|
89
|
+
permission: { type: 'string' as const, required: true as const, validate: createEnumValidator(PERMISSION_ORDER) },
|
|
90
|
+
};
|
|
91
|
+
|
|
92
|
+
const unshareProjectSchema = {
|
|
93
|
+
project_id: { type: 'string' as const, required: true as const, validate: uuidValidator },
|
|
94
|
+
organization_id: { type: 'string' as const, required: true as const, validate: uuidValidator },
|
|
95
|
+
};
|
|
96
|
+
|
|
97
|
+
const listProjectSharesSchema = {
|
|
98
|
+
project_id: { type: 'string' as const, required: true as const, validate: uuidValidator },
|
|
99
|
+
};
|
|
100
|
+
|
|
101
|
+
// ============================================================================
|
|
102
|
+
// Organization Management
|
|
103
|
+
// ============================================================================
|
|
104
|
+
|
|
105
|
+
export const listOrganizations: Handler = async (_args, _ctx) => {
|
|
106
|
+
const apiClient = getApiClient();
|
|
107
|
+
const response = await apiClient.listOrganizations();
|
|
108
|
+
|
|
109
|
+
if (!response.ok) {
|
|
110
|
+
return { result: { error: response.error || 'Failed to list organizations' }, isError: true };
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
return { result: response.data };
|
|
114
|
+
};
|
|
115
|
+
|
|
116
|
+
export const createOrganization: Handler = async (args, _ctx) => {
|
|
117
|
+
const { name, description, slug } = parseArgs(args, createOrganizationSchema);
|
|
118
|
+
|
|
119
|
+
const apiClient = getApiClient();
|
|
120
|
+
const response = await apiClient.createOrganization({
|
|
121
|
+
name,
|
|
122
|
+
description,
|
|
123
|
+
slug
|
|
124
|
+
});
|
|
125
|
+
|
|
126
|
+
if (!response.ok) {
|
|
127
|
+
return { result: { error: response.error || 'Failed to create organization' }, isError: true };
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
return { result: response.data };
|
|
131
|
+
};
|
|
132
|
+
|
|
133
|
+
export const updateOrganization: Handler = async (args, _ctx) => {
|
|
134
|
+
const { organization_id, name, description, logo_url } = parseArgs(args, updateOrganizationSchema);
|
|
135
|
+
|
|
136
|
+
// Check that at least one update is provided
|
|
137
|
+
if (name === undefined && description === undefined && logo_url === undefined) {
|
|
138
|
+
throw new ValidationError('No updates provided');
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
const updates: Record<string, unknown> = {};
|
|
142
|
+
if (name !== undefined) updates.name = name;
|
|
143
|
+
if (description !== undefined) updates.description = description;
|
|
144
|
+
if (logo_url !== undefined) updates.logo_url = logo_url;
|
|
145
|
+
|
|
146
|
+
const apiClient = getApiClient();
|
|
147
|
+
const response = await apiClient.updateOrganization(organization_id, updates);
|
|
148
|
+
|
|
149
|
+
if (!response.ok) {
|
|
150
|
+
return { result: { error: response.error || 'Failed to update organization' }, isError: true };
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
return { result: response.data };
|
|
154
|
+
};
|
|
155
|
+
|
|
156
|
+
export const deleteOrganization: Handler = async (args, _ctx) => {
|
|
157
|
+
const { organization_id } = parseArgs(args, deleteOrganizationSchema);
|
|
158
|
+
|
|
159
|
+
const apiClient = getApiClient();
|
|
160
|
+
const response = await apiClient.deleteOrganization(organization_id);
|
|
161
|
+
|
|
162
|
+
if (!response.ok) {
|
|
163
|
+
return { result: { error: response.error || 'Failed to delete organization' }, isError: true };
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
return { result: response.data };
|
|
167
|
+
};
|
|
168
|
+
|
|
169
|
+
// ============================================================================
|
|
170
|
+
// Member Management
|
|
171
|
+
// ============================================================================
|
|
172
|
+
|
|
173
|
+
export const listOrgMembers: Handler = async (args, _ctx) => {
|
|
174
|
+
const { organization_id } = parseArgs(args, listOrgMembersSchema);
|
|
175
|
+
|
|
176
|
+
const apiClient = getApiClient();
|
|
177
|
+
const response = await apiClient.listOrgMembers(organization_id);
|
|
178
|
+
|
|
179
|
+
if (!response.ok) {
|
|
180
|
+
return { result: { error: response.error || 'Failed to list members' }, isError: true };
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
return { result: response.data };
|
|
184
|
+
};
|
|
185
|
+
|
|
186
|
+
export const inviteMember: Handler = async (args, _ctx) => {
|
|
187
|
+
const { organization_id, email, role } = parseArgs(args, inviteMemberSchema);
|
|
188
|
+
|
|
189
|
+
const apiClient = getApiClient();
|
|
190
|
+
const response = await apiClient.inviteMember(organization_id, email, role as AssignableRole);
|
|
191
|
+
|
|
192
|
+
if (!response.ok) {
|
|
193
|
+
return { result: { error: response.error || 'Failed to create invite' }, isError: true };
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
return { result: response.data };
|
|
197
|
+
};
|
|
198
|
+
|
|
199
|
+
export const updateMemberRole: Handler = async (args, _ctx) => {
|
|
200
|
+
const { organization_id, user_id, role } = parseArgs(args, updateMemberRoleSchema);
|
|
201
|
+
|
|
202
|
+
if (role === 'owner') {
|
|
203
|
+
throw new ValidationError('Cannot assign owner role. Use transfer ownership instead.');
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
const apiClient = getApiClient();
|
|
207
|
+
const response = await apiClient.updateMemberRole(organization_id, user_id, role as Role);
|
|
208
|
+
|
|
209
|
+
if (!response.ok) {
|
|
210
|
+
return { result: { error: response.error || 'Failed to update member role' }, isError: true };
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
return { result: response.data };
|
|
214
|
+
};
|
|
215
|
+
|
|
216
|
+
export const removeMember: Handler = async (args, _ctx) => {
|
|
217
|
+
const { organization_id, user_id } = parseArgs(args, removeMemberSchema);
|
|
218
|
+
|
|
219
|
+
const apiClient = getApiClient();
|
|
220
|
+
const response = await apiClient.removeMember(organization_id, user_id);
|
|
221
|
+
|
|
222
|
+
if (!response.ok) {
|
|
223
|
+
return { result: { error: response.error || 'Failed to remove member' }, isError: true };
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
return { result: response.data };
|
|
227
|
+
};
|
|
228
|
+
|
|
229
|
+
export const leaveOrganization: Handler = async (args, _ctx) => {
|
|
230
|
+
const { organization_id } = parseArgs(args, leaveOrganizationSchema);
|
|
231
|
+
|
|
232
|
+
const apiClient = getApiClient();
|
|
233
|
+
const response = await apiClient.leaveOrganization(organization_id);
|
|
234
|
+
|
|
235
|
+
if (!response.ok) {
|
|
236
|
+
return { result: { error: response.error || 'Failed to leave organization' }, isError: true };
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
return { result: response.data };
|
|
240
|
+
};
|
|
241
|
+
|
|
242
|
+
// ============================================================================
|
|
243
|
+
// Project Sharing
|
|
244
|
+
// ============================================================================
|
|
245
|
+
|
|
246
|
+
export const shareProjectWithOrg: Handler = async (args, _ctx) => {
|
|
247
|
+
const { project_id, organization_id, permission } = parseArgs(args, shareProjectWithOrgSchema);
|
|
248
|
+
|
|
249
|
+
const apiClient = getApiClient();
|
|
250
|
+
const response = await apiClient.shareProjectWithOrg(project_id, organization_id, permission as Permission);
|
|
251
|
+
|
|
252
|
+
if (!response.ok) {
|
|
253
|
+
return { result: { error: response.error || 'Failed to share project' }, isError: true };
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
return { result: response.data };
|
|
257
|
+
};
|
|
258
|
+
|
|
259
|
+
export const updateProjectShare: Handler = async (args, _ctx) => {
|
|
260
|
+
const { project_id, organization_id, permission } = parseArgs(args, updateProjectShareSchema);
|
|
261
|
+
|
|
262
|
+
const apiClient = getApiClient();
|
|
263
|
+
const response = await apiClient.updateProjectShare(project_id, organization_id, permission as Permission);
|
|
264
|
+
|
|
265
|
+
if (!response.ok) {
|
|
266
|
+
return { result: { error: response.error || 'Failed to update share' }, isError: true };
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
return { result: response.data };
|
|
270
|
+
};
|
|
271
|
+
|
|
272
|
+
export const unshareProject: Handler = async (args, _ctx) => {
|
|
273
|
+
const { project_id, organization_id } = parseArgs(args, unshareProjectSchema);
|
|
274
|
+
|
|
275
|
+
const apiClient = getApiClient();
|
|
276
|
+
const response = await apiClient.unshareProject(project_id, organization_id);
|
|
277
|
+
|
|
278
|
+
if (!response.ok) {
|
|
279
|
+
return { result: { error: response.error || 'Failed to unshare project' }, isError: true };
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
return { result: response.data };
|
|
283
|
+
};
|
|
284
|
+
|
|
285
|
+
export const listProjectShares: Handler = async (args, _ctx) => {
|
|
286
|
+
const { project_id } = parseArgs(args, listProjectSharesSchema);
|
|
287
|
+
|
|
288
|
+
const apiClient = getApiClient();
|
|
289
|
+
const response = await apiClient.listProjectShares(project_id);
|
|
290
|
+
|
|
291
|
+
if (!response.ok) {
|
|
292
|
+
return { result: { error: response.error || 'Failed to list shares' }, isError: true };
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
return { result: response.data };
|
|
296
|
+
};
|
|
297
|
+
|
|
298
|
+
/**
|
|
299
|
+
* Organizations handlers registry
|
|
300
|
+
*/
|
|
301
|
+
export const organizationHandlers: HandlerRegistry = {
|
|
302
|
+
list_organizations: listOrganizations,
|
|
303
|
+
create_organization: createOrganization,
|
|
304
|
+
update_organization: updateOrganization,
|
|
305
|
+
delete_organization: deleteOrganization,
|
|
306
|
+
list_org_members: listOrgMembers,
|
|
307
|
+
invite_member: inviteMember,
|
|
308
|
+
update_member_role: updateMemberRole,
|
|
309
|
+
remove_member: removeMember,
|
|
310
|
+
leave_organization: leaveOrganization,
|
|
311
|
+
share_project_with_org: shareProjectWithOrg,
|
|
312
|
+
update_project_share: updateProjectShare,
|
|
313
|
+
unshare_project: unshareProject,
|
|
314
|
+
list_project_shares: listProjectShares,
|
|
315
|
+
};
|