figmanage 1.0.1 → 1.2.0
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 +74 -59
- package/dist/cli/analytics.d.ts +3 -0
- package/dist/cli/analytics.js +48 -0
- package/dist/cli/branching.d.ts +3 -0
- package/dist/cli/branching.js +56 -0
- package/dist/cli/comments.d.ts +3 -0
- package/dist/cli/comments.js +86 -0
- package/dist/cli/completion.d.ts +7 -0
- package/dist/cli/completion.js +160 -0
- package/dist/cli/components.d.ts +3 -0
- package/dist/cli/components.js +82 -0
- package/dist/cli/compound-commands.d.ts +14 -0
- package/dist/cli/compound-commands.js +291 -0
- package/dist/cli/export.d.ts +3 -0
- package/dist/cli/export.js +51 -0
- package/dist/cli/files.d.ts +3 -0
- package/dist/cli/files.js +156 -0
- package/dist/cli/format.js +147 -2
- package/dist/cli/helpers.d.ts +7 -0
- package/dist/cli/helpers.js +43 -0
- package/dist/cli/index.js +68 -89
- package/dist/cli/libraries.d.ts +3 -0
- package/dist/cli/libraries.js +26 -0
- package/dist/cli/navigate.d.ts +3 -0
- package/dist/cli/navigate.js +192 -0
- package/dist/cli/org.d.ts +3 -0
- package/dist/cli/org.js +227 -0
- package/dist/cli/permissions.d.ts +3 -0
- package/dist/cli/permissions.js +133 -0
- package/dist/cli/projects.d.ts +3 -0
- package/dist/cli/projects.js +110 -0
- package/dist/cli/reading.d.ts +3 -0
- package/dist/cli/reading.js +51 -0
- package/dist/cli/teams.d.ts +3 -0
- package/dist/cli/teams.js +56 -0
- package/dist/cli/variables.d.ts +3 -0
- package/dist/cli/variables.js +80 -0
- package/dist/cli/versions.d.ts +3 -0
- package/dist/cli/versions.js +46 -0
- package/dist/cli/webhooks.d.ts +3 -0
- package/dist/cli/webhooks.js +100 -0
- package/dist/operations/analytics.d.ts +10 -0
- package/dist/operations/analytics.js +15 -0
- package/dist/operations/branching.d.ts +24 -0
- package/dist/operations/branching.js +41 -0
- package/dist/operations/comments.d.ts +43 -0
- package/dist/operations/comments.js +65 -0
- package/dist/operations/components.d.ts +24 -0
- package/dist/operations/components.js +30 -0
- package/dist/operations/compound-manager.d.ts +101 -0
- package/dist/operations/compound-manager.js +629 -0
- package/dist/operations/compound.d.ts +102 -0
- package/dist/operations/compound.js +595 -0
- package/dist/operations/export.d.ts +19 -0
- package/dist/operations/export.js +27 -0
- package/dist/operations/files.d.ts +55 -0
- package/dist/operations/files.js +89 -0
- package/dist/operations/libraries.d.ts +5 -0
- package/dist/operations/libraries.js +10 -0
- package/dist/operations/navigate.d.ts +99 -0
- package/dist/operations/navigate.js +266 -0
- package/dist/operations/org.d.ts +95 -0
- package/dist/operations/org.js +205 -0
- package/dist/operations/permissions.d.ts +59 -0
- package/dist/operations/permissions.js +112 -0
- package/dist/operations/projects.d.ts +29 -0
- package/dist/operations/projects.js +40 -0
- package/dist/operations/reading.d.ts +12 -0
- package/dist/operations/reading.js +20 -0
- package/dist/operations/teams.d.ts +17 -0
- package/dist/operations/teams.js +17 -0
- package/dist/operations/variables.d.ts +17 -0
- package/dist/operations/variables.js +39 -0
- package/dist/operations/versions.d.ts +23 -0
- package/dist/operations/versions.js +27 -0
- package/dist/operations/webhooks.d.ts +25 -0
- package/dist/operations/webhooks.js +38 -0
- package/dist/tools/analytics.js +6 -16
- package/dist/tools/branching.js +7 -36
- package/dist/tools/comments.js +9 -56
- package/dist/tools/components.js +7 -19
- package/dist/tools/compound-manager.js +21 -644
- package/dist/tools/compound.js +32 -566
- package/dist/tools/export.js +4 -23
- package/dist/tools/files.js +21 -68
- package/dist/tools/libraries.js +4 -11
- package/dist/tools/navigate.js +23 -246
- package/dist/tools/org.js +29 -245
- package/dist/tools/permissions.js +18 -97
- package/dist/tools/projects.js +8 -27
- package/dist/tools/reading.js +5 -15
- package/dist/tools/teams.js +8 -16
- package/dist/tools/variables.js +13 -30
- package/dist/tools/versions.js +6 -24
- package/dist/tools/webhooks.js +7 -24
- package/package.json +1 -1
- package/dist/cli/commands.d.ts +0 -47
- package/dist/cli/commands.js +0 -1204
package/dist/tools/org.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { z } from 'zod';
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
2
|
+
import { defineTool, toolResult, toolError, figmaId } from './register.js';
|
|
3
|
+
import { listAdmins, listOrgTeams, seatUsage, listTeamMembers, billingOverview, listInvoices, orgDomains, aiCreditUsage, exportMembers, listOrgMembers, contractRates, changeSeat, } from '../operations/org.js';
|
|
4
4
|
// -- list_admins --
|
|
5
5
|
defineTool({
|
|
6
6
|
toolset: 'org',
|
|
@@ -14,24 +14,8 @@ defineTool({
|
|
|
14
14
|
},
|
|
15
15
|
}, async ({ org_id, include_license_admins }) => {
|
|
16
16
|
try {
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
orgId = requireOrgId(config, org_id);
|
|
20
|
-
}
|
|
21
|
-
catch (e) {
|
|
22
|
-
return toolError(e.message);
|
|
23
|
-
}
|
|
24
|
-
const res = await internalClient(config).get(`/api/orgs/${orgId}/admins`, { params: { include_license_admins: include_license_admins ?? false } });
|
|
25
|
-
const admins = (res.data?.meta || []).map((a) => ({
|
|
26
|
-
user_id: a.user_id,
|
|
27
|
-
email: a.user?.email,
|
|
28
|
-
name: a.user?.handle,
|
|
29
|
-
permission: a.permission,
|
|
30
|
-
seat_type: a.active_seat_type?.key || null,
|
|
31
|
-
is_email_validated: a.is_email_validated,
|
|
32
|
-
license_admin: a.license_admin,
|
|
33
|
-
}));
|
|
34
|
-
return toolResult(JSON.stringify(admins, null, 2));
|
|
17
|
+
const result = await listAdmins(config, { org_id, include_license_admins });
|
|
18
|
+
return toolResult(JSON.stringify(result, null, 2));
|
|
35
19
|
}
|
|
36
20
|
catch (e) {
|
|
37
21
|
return toolError(`Failed to list admins: ${e.response?.status || e.message}`);
|
|
@@ -52,30 +36,8 @@ defineTool({
|
|
|
52
36
|
},
|
|
53
37
|
}, async ({ org_id, include_secret_teams }) => {
|
|
54
38
|
try {
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
orgId = requireOrgId(config, org_id);
|
|
58
|
-
}
|
|
59
|
-
catch (e) {
|
|
60
|
-
return toolError(e.message);
|
|
61
|
-
}
|
|
62
|
-
const res = await internalClient(config).get(`/api/orgs/${orgId}/teams`, {
|
|
63
|
-
params: {
|
|
64
|
-
include_member_count: true,
|
|
65
|
-
include_project_count: true,
|
|
66
|
-
include_top_members: true,
|
|
67
|
-
include_secret_teams: include_secret_teams ?? false,
|
|
68
|
-
},
|
|
69
|
-
});
|
|
70
|
-
const teams = res.data?.meta || res.data;
|
|
71
|
-
const mapped = (Array.isArray(teams) ? teams : []).map((t) => ({
|
|
72
|
-
id: String(t.id),
|
|
73
|
-
name: t.name,
|
|
74
|
-
member_count: t.member_count ?? null,
|
|
75
|
-
project_count: t.project_count ?? null,
|
|
76
|
-
access_level: t.access_level ?? null,
|
|
77
|
-
}));
|
|
78
|
-
return toolResult(JSON.stringify(mapped, null, 2));
|
|
39
|
+
const result = await listOrgTeams(config, { org_id, include_secret_teams });
|
|
40
|
+
return toolResult(JSON.stringify(result, null, 2));
|
|
79
41
|
}
|
|
80
42
|
catch (e) {
|
|
81
43
|
return toolError(`Failed to list org teams: ${e.response?.status || e.message}`);
|
|
@@ -96,18 +58,8 @@ defineTool({
|
|
|
96
58
|
},
|
|
97
59
|
}, async ({ org_id, search_query }) => {
|
|
98
60
|
try {
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
orgId = requireOrgId(config, org_id);
|
|
102
|
-
}
|
|
103
|
-
catch (e) {
|
|
104
|
-
return toolError(e.message);
|
|
105
|
-
}
|
|
106
|
-
const params = {};
|
|
107
|
-
if (search_query)
|
|
108
|
-
params.search_query = search_query;
|
|
109
|
-
const res = await internalClient(config).get(`/api/orgs/${orgId}/org_users/filter_counts`, { params });
|
|
110
|
-
return toolResult(JSON.stringify(res.data?.meta || res.data, null, 2));
|
|
61
|
+
const result = await seatUsage(config, { org_id, search_query });
|
|
62
|
+
return toolResult(JSON.stringify(result, null, 2));
|
|
111
63
|
}
|
|
112
64
|
catch (e) {
|
|
113
65
|
return toolError(`Failed to fetch seat usage: ${e.response?.status || e.message}`);
|
|
@@ -127,18 +79,8 @@ defineTool({
|
|
|
127
79
|
},
|
|
128
80
|
}, async ({ team_id }) => {
|
|
129
81
|
try {
|
|
130
|
-
const
|
|
131
|
-
|
|
132
|
-
id: m.id,
|
|
133
|
-
name: m.name,
|
|
134
|
-
email: m.email,
|
|
135
|
-
img_url: m.img_url,
|
|
136
|
-
last_active: m.last_active,
|
|
137
|
-
team_role: m.team_role?.level || null,
|
|
138
|
-
permission: m.team_user?.permission || null,
|
|
139
|
-
seat_type: m.seat_type || null,
|
|
140
|
-
}));
|
|
141
|
-
return toolResult(JSON.stringify(members, null, 2));
|
|
82
|
+
const result = await listTeamMembers(config, { team_id });
|
|
83
|
+
return toolResult(JSON.stringify(result, null, 2));
|
|
142
84
|
}
|
|
143
85
|
catch (e) {
|
|
144
86
|
return toolError(`Failed to list team members: ${e.response?.status || e.message}`);
|
|
@@ -158,17 +100,8 @@ defineTool({
|
|
|
158
100
|
},
|
|
159
101
|
}, async ({ org_id }) => {
|
|
160
102
|
try {
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
orgId = requireOrgId(config, org_id);
|
|
164
|
-
}
|
|
165
|
-
catch (e) {
|
|
166
|
-
return toolError(e.message);
|
|
167
|
-
}
|
|
168
|
-
const res = await internalClient(config).get(`/api/orgs/${orgId}/billing_data`);
|
|
169
|
-
const data = res.data?.meta || res.data;
|
|
170
|
-
const { shipping_address, ...billing } = data;
|
|
171
|
-
return toolResult(JSON.stringify(billing, null, 2));
|
|
103
|
+
const result = await billingOverview(config, { org_id });
|
|
104
|
+
return toolResult(JSON.stringify(result, null, 2));
|
|
172
105
|
}
|
|
173
106
|
catch (e) {
|
|
174
107
|
return toolError(`Failed to fetch billing overview: ${e.response?.status || e.message}`);
|
|
@@ -188,28 +121,8 @@ defineTool({
|
|
|
188
121
|
},
|
|
189
122
|
}, async ({ org_id }) => {
|
|
190
123
|
try {
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
orgId = requireOrgId(config, org_id);
|
|
194
|
-
}
|
|
195
|
-
catch (e) {
|
|
196
|
-
return toolError(e.message);
|
|
197
|
-
}
|
|
198
|
-
const client = internalClient(config);
|
|
199
|
-
const [openResult, upcomingResult] = await Promise.allSettled([
|
|
200
|
-
client.get(`/api/plans/organization/${orgId}/invoices/open`),
|
|
201
|
-
client.get(`/api/plans/organization/${orgId}/invoices/upcoming`),
|
|
202
|
-
]);
|
|
203
|
-
const response = {};
|
|
204
|
-
if (openResult.status === 'fulfilled')
|
|
205
|
-
response.open = openResult.value.data;
|
|
206
|
-
else
|
|
207
|
-
response.open_error = 'Failed to fetch open invoices';
|
|
208
|
-
if (upcomingResult.status === 'fulfilled')
|
|
209
|
-
response.upcoming = upcomingResult.value.data;
|
|
210
|
-
else
|
|
211
|
-
response.upcoming_error = 'Failed to fetch upcoming invoices';
|
|
212
|
-
return toolResult(JSON.stringify(response, null, 2));
|
|
124
|
+
const result = await listInvoices(config, { org_id });
|
|
125
|
+
return toolResult(JSON.stringify(result, null, 2));
|
|
213
126
|
}
|
|
214
127
|
catch (e) {
|
|
215
128
|
return toolError(`Failed to list invoices: ${e.response?.status || e.message}`);
|
|
@@ -229,28 +142,8 @@ defineTool({
|
|
|
229
142
|
},
|
|
230
143
|
}, async ({ org_id }) => {
|
|
231
144
|
try {
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
orgId = requireOrgId(config, org_id);
|
|
235
|
-
}
|
|
236
|
-
catch (e) {
|
|
237
|
-
return toolError(e.message);
|
|
238
|
-
}
|
|
239
|
-
const client = internalClient(config);
|
|
240
|
-
const [domainsResult, ssoResult] = await Promise.allSettled([
|
|
241
|
-
client.get(`/api/orgs/${orgId}/domains`),
|
|
242
|
-
client.get(`/api/org/${orgId}/org_saml_config`),
|
|
243
|
-
]);
|
|
244
|
-
const response = {};
|
|
245
|
-
if (domainsResult.status === 'fulfilled')
|
|
246
|
-
response.domains = domainsResult.value.data;
|
|
247
|
-
else
|
|
248
|
-
response.domains_error = 'Failed to fetch domains';
|
|
249
|
-
if (ssoResult.status === 'fulfilled')
|
|
250
|
-
response.sso = ssoResult.value.data;
|
|
251
|
-
else
|
|
252
|
-
response.sso_error = 'SSO config not available';
|
|
253
|
-
return toolResult(JSON.stringify(response, null, 2));
|
|
145
|
+
const result = await orgDomains(config, { org_id });
|
|
146
|
+
return toolResult(JSON.stringify(result, null, 2));
|
|
254
147
|
}
|
|
255
148
|
catch (e) {
|
|
256
149
|
return toolError(`Failed to fetch org domains: ${e.response?.status || e.message}`);
|
|
@@ -270,8 +163,8 @@ defineTool({
|
|
|
270
163
|
},
|
|
271
164
|
}, async ({ plan_id }) => {
|
|
272
165
|
try {
|
|
273
|
-
const
|
|
274
|
-
return toolResult(JSON.stringify(
|
|
166
|
+
const result = await aiCreditUsage(config, { plan_id });
|
|
167
|
+
return toolResult(JSON.stringify(result, null, 2));
|
|
275
168
|
}
|
|
276
169
|
catch (e) {
|
|
277
170
|
return toolError(`Failed to fetch AI credit usage: ${e.response?.status || e.message}`);
|
|
@@ -292,15 +185,8 @@ defineTool({
|
|
|
292
185
|
},
|
|
293
186
|
}, async ({ org_id }) => {
|
|
294
187
|
try {
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
orgId = requireOrgId(config, org_id);
|
|
298
|
-
}
|
|
299
|
-
catch (e) {
|
|
300
|
-
return toolError(e.message);
|
|
301
|
-
}
|
|
302
|
-
await internalClient(config).post(`/api/orgs/${orgId}/export_members`);
|
|
303
|
-
return toolResult('CSV export queued. It will be emailed to the org admin.');
|
|
188
|
+
const msg = await exportMembers(config, { org_id });
|
|
189
|
+
return toolResult(msg);
|
|
304
190
|
}
|
|
305
191
|
catch (e) {
|
|
306
192
|
return toolError(`Failed to export members: ${e.response?.status || e.message}`);
|
|
@@ -321,28 +207,8 @@ defineTool({
|
|
|
321
207
|
},
|
|
322
208
|
}, async ({ org_id, search_query }) => {
|
|
323
209
|
try {
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
orgId = requireOrgId(config, org_id);
|
|
327
|
-
}
|
|
328
|
-
catch (e) {
|
|
329
|
-
return toolError(e.message);
|
|
330
|
-
}
|
|
331
|
-
const params = {};
|
|
332
|
-
if (search_query)
|
|
333
|
-
params.search_query = search_query;
|
|
334
|
-
const res = await internalClient(config).get(`/api/v2/orgs/${orgId}/org_users`, { params });
|
|
335
|
-
const users = res.data?.meta?.users || res.data?.meta || res.data || [];
|
|
336
|
-
const members = (Array.isArray(users) ? users : []).map((m) => ({
|
|
337
|
-
org_user_id: String(m.id),
|
|
338
|
-
user_id: m.user_id,
|
|
339
|
-
email: m.user?.email,
|
|
340
|
-
name: m.user?.handle,
|
|
341
|
-
permission: m.permission,
|
|
342
|
-
seat_type: m.active_seat_type?.key || null,
|
|
343
|
-
last_active: m.last_seen || null,
|
|
344
|
-
}));
|
|
345
|
-
return toolResult(JSON.stringify(members, null, 2));
|
|
210
|
+
const result = await listOrgMembers(config, { org_id, search_query });
|
|
211
|
+
return toolResult(JSON.stringify(result, null, 2));
|
|
346
212
|
}
|
|
347
213
|
catch (e) {
|
|
348
214
|
return toolError(`Failed to list org members: ${e.response?.status || e.message}`);
|
|
@@ -362,24 +228,8 @@ defineTool({
|
|
|
362
228
|
},
|
|
363
229
|
}, async ({ org_id }) => {
|
|
364
230
|
try {
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
orgId = requireOrgId(config, org_id);
|
|
368
|
-
}
|
|
369
|
-
catch (e) {
|
|
370
|
-
return toolError(e.message);
|
|
371
|
-
}
|
|
372
|
-
const res = await internalClient(config).get(`/api/pricing/contract_rates`, { params: { plan_parent_id: orgId, plan_type: 'organization' } });
|
|
373
|
-
const seatProducts = new Set(['expert', 'developer', 'collaborator']);
|
|
374
|
-
const prices = res.data?.meta?.product_prices || [];
|
|
375
|
-
const rates = prices
|
|
376
|
-
.filter((r) => seatProducts.has(r.billable_product_key))
|
|
377
|
-
.map((r) => ({
|
|
378
|
-
product: r.billable_product_key,
|
|
379
|
-
monthly_cents: r.amount,
|
|
380
|
-
monthly_dollars: (r.amount / 100).toFixed(2),
|
|
381
|
-
}));
|
|
382
|
-
return toolResult(JSON.stringify(rates, null, 2));
|
|
231
|
+
const result = await contractRates(config, { org_id });
|
|
232
|
+
return toolResult(JSON.stringify(result, null, 2));
|
|
383
233
|
}
|
|
384
234
|
catch (e) {
|
|
385
235
|
return toolError(`Failed to fetch contract rates: ${e.response?.status || e.message}`);
|
|
@@ -388,29 +238,6 @@ defineTool({
|
|
|
388
238
|
},
|
|
389
239
|
});
|
|
390
240
|
// -- change_seat --
|
|
391
|
-
const SEAT_HIERARCHY = {
|
|
392
|
-
view: 0,
|
|
393
|
-
collab: 1,
|
|
394
|
-
dev: 2,
|
|
395
|
-
full: 3,
|
|
396
|
-
};
|
|
397
|
-
const SEAT_LABELS = {
|
|
398
|
-
view: 'Viewer (free)',
|
|
399
|
-
collab: 'Collaborator ($5/mo)',
|
|
400
|
-
dev: 'Developer ($25/mo)',
|
|
401
|
-
full: 'Full ($55/mo)',
|
|
402
|
-
};
|
|
403
|
-
const PAID_STATUSES = {
|
|
404
|
-
full: { expert: 'full' },
|
|
405
|
-
dev: { developer: 'full' },
|
|
406
|
-
collab: { collaborator: 'full' },
|
|
407
|
-
view: { collaborator: 'starter', developer: 'starter', expert: 'starter' },
|
|
408
|
-
};
|
|
409
|
-
const SEAT_KEY_TO_TYPE = {
|
|
410
|
-
expert: 'full',
|
|
411
|
-
developer: 'dev',
|
|
412
|
-
collaborator: 'collab',
|
|
413
|
-
};
|
|
414
241
|
defineTool({
|
|
415
242
|
toolset: 'org',
|
|
416
243
|
auth: 'cookie',
|
|
@@ -427,56 +254,13 @@ defineTool({
|
|
|
427
254
|
},
|
|
428
255
|
}, async ({ user_id, seat_type, org_id, confirm }) => {
|
|
429
256
|
try {
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
catch (e) {
|
|
435
|
-
return toolError(e.message);
|
|
436
|
-
}
|
|
437
|
-
const res = await internalClient(config).get(`/api/v2/orgs/${orgId}/org_users`, {
|
|
438
|
-
params: user_id.includes('@') ? { search_query: user_id } : {},
|
|
439
|
-
});
|
|
440
|
-
const users = res.data?.meta?.users || res.data?.meta || res.data || [];
|
|
441
|
-
const members = Array.isArray(users) ? users : [];
|
|
442
|
-
const member = members.find((m) => user_id.includes('@')
|
|
443
|
-
? m.user?.email === user_id
|
|
444
|
-
: String(m.user_id) === String(user_id));
|
|
445
|
-
if (!member)
|
|
446
|
-
return toolError(`User not found: ${user_id}`);
|
|
447
|
-
if (String(member.user_id) === String(config.userId)) {
|
|
448
|
-
return toolError('Cannot change your own seat type. Use the Figma admin panel.');
|
|
449
|
-
}
|
|
450
|
-
const currentKey = member.active_seat_type?.key || null;
|
|
451
|
-
const currentType = currentKey ? (SEAT_KEY_TO_TYPE[currentKey] || 'view') : 'view';
|
|
452
|
-
if (currentType === seat_type) {
|
|
453
|
-
return toolResult(`Already on ${SEAT_LABELS[seat_type]} seat. No change needed.`);
|
|
454
|
-
}
|
|
455
|
-
const isUpgrade = (SEAT_HIERARCHY[seat_type] ?? 0) > (SEAT_HIERARCHY[currentType] ?? 0);
|
|
456
|
-
if (isUpgrade && !confirm) {
|
|
457
|
-
return toolError(`Upgrading from ${SEAT_LABELS[currentType]} to ${SEAT_LABELS[seat_type]} will increase billing. ` +
|
|
458
|
-
`Set confirm: true to authorize.`);
|
|
459
|
-
}
|
|
460
|
-
await internalClient(config).put(`/api/orgs/${orgId}/org_users`, {
|
|
461
|
-
org_user_ids: [String(member.id)],
|
|
462
|
-
paid_statuses: PAID_STATUSES[seat_type],
|
|
463
|
-
entry_point: 'members_tab',
|
|
464
|
-
seat_increase_authorized: 'true',
|
|
465
|
-
seat_swap_intended: 'false',
|
|
466
|
-
latest_ou_update: member.updated_at,
|
|
467
|
-
showing_billing_groups: 'true',
|
|
468
|
-
}, {
|
|
469
|
-
'axios-retry': { retries: 0 },
|
|
470
|
-
});
|
|
471
|
-
return toolResult(JSON.stringify({
|
|
472
|
-
user: member.user?.handle || member.user?.email,
|
|
473
|
-
email: member.user?.email,
|
|
474
|
-
old_seat: SEAT_LABELS[currentType],
|
|
475
|
-
new_seat: SEAT_LABELS[seat_type],
|
|
476
|
-
}, null, 2));
|
|
257
|
+
const result = await changeSeat(config, { user_id, seat_type, org_id, confirm });
|
|
258
|
+
if (typeof result === 'string')
|
|
259
|
+
return toolResult(result);
|
|
260
|
+
return toolResult(JSON.stringify(result, null, 2));
|
|
477
261
|
}
|
|
478
262
|
catch (e) {
|
|
479
|
-
return toolError(`Failed to change seat: ${e.response
|
|
263
|
+
return toolError(e.response?.status ? `Failed to change seat: ${e.response.status}` : e.message);
|
|
480
264
|
}
|
|
481
265
|
});
|
|
482
266
|
},
|
|
@@ -1,16 +1,6 @@
|
|
|
1
1
|
import { z } from 'zod';
|
|
2
|
-
import { internalClient } from '../clients/internal-api.js';
|
|
3
2
|
import { defineTool, toolResult, toolError, figmaId } from './register.js';
|
|
4
|
-
|
|
5
|
-
const LEVEL_NAMES = { 999: 'owner', 300: 'editor', 100: 'viewer' };
|
|
6
|
-
function levelName(level) {
|
|
7
|
-
return LEVEL_NAMES[level] || `level:${level}`;
|
|
8
|
-
}
|
|
9
|
-
async function getRoles(config, resourceType, resourceId) {
|
|
10
|
-
const res = await internalClient(config).get(`/api/roles/${resourceType}/${resourceId}`);
|
|
11
|
-
const meta = res.data?.meta;
|
|
12
|
-
return Array.isArray(meta) ? meta : [];
|
|
13
|
-
}
|
|
3
|
+
import { getPermissions, setPermissions, share, revokeAccess, listRoleRequests, approveRoleRequest, denyRoleRequest, } from '../operations/permissions.js';
|
|
14
4
|
// -- get_permissions --
|
|
15
5
|
defineTool({
|
|
16
6
|
toolset: 'permissions',
|
|
@@ -24,17 +14,8 @@ defineTool({
|
|
|
24
14
|
},
|
|
25
15
|
}, async ({ resource_type, resource_id }) => {
|
|
26
16
|
try {
|
|
27
|
-
const
|
|
28
|
-
|
|
29
|
-
role_id: String(r.id),
|
|
30
|
-
user_id: r.user_id ? String(r.user_id) : undefined,
|
|
31
|
-
handle: r.user?.handle,
|
|
32
|
-
email: r.user?.email || r.pending_email,
|
|
33
|
-
role: levelName(r.level),
|
|
34
|
-
level: r.level,
|
|
35
|
-
pending: !!r.pending_email,
|
|
36
|
-
}));
|
|
37
|
-
return toolResult(JSON.stringify(users, null, 2));
|
|
17
|
+
const result = await getPermissions(config, { resource_type, resource_id });
|
|
18
|
+
return toolResult(JSON.stringify(result, null, 2));
|
|
38
19
|
}
|
|
39
20
|
catch (e) {
|
|
40
21
|
return toolError(`Failed to get permissions: ${e.response?.status || e.message}`);
|
|
@@ -58,17 +39,11 @@ defineTool({
|
|
|
58
39
|
},
|
|
59
40
|
}, async ({ resource_type, resource_id, user_id, role }) => {
|
|
60
41
|
try {
|
|
61
|
-
const
|
|
62
|
-
|
|
63
|
-
if (!target) {
|
|
64
|
-
return toolError(`User ${user_id} has no role on this ${resource_type}. Use share to invite them first.`);
|
|
65
|
-
}
|
|
66
|
-
const level = LEVEL_MAP[role];
|
|
67
|
-
await internalClient(config).put(`/api/roles/${target.id}`, { level });
|
|
68
|
-
return toolResult(`Set ${role} (level ${level}) for user ${user_id} on ${resource_type} ${resource_id}`);
|
|
42
|
+
const msg = await setPermissions(config, { resource_type, resource_id, user_id, role });
|
|
43
|
+
return toolResult(msg);
|
|
69
44
|
}
|
|
70
45
|
catch (e) {
|
|
71
|
-
return toolError(`Failed to set permissions: ${e.response
|
|
46
|
+
return toolError(e.response?.status ? `Failed to set permissions: ${e.response.status}` : e.message);
|
|
72
47
|
}
|
|
73
48
|
});
|
|
74
49
|
},
|
|
@@ -89,18 +64,10 @@ defineTool({
|
|
|
89
64
|
},
|
|
90
65
|
}, async ({ resource_type, resource_id, email, role }) => {
|
|
91
66
|
try {
|
|
92
|
-
const
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
emails: [email],
|
|
97
|
-
level,
|
|
98
|
-
});
|
|
99
|
-
const invites = res.data?.meta?.invites || [];
|
|
100
|
-
const roleId = invites[0]?.id;
|
|
101
|
-
let msg = `Invited ${email} as ${role || 'viewer'} on ${resource_type} ${resource_id}`;
|
|
102
|
-
if (roleId)
|
|
103
|
-
msg += ` (role_id: ${roleId})`;
|
|
67
|
+
const result = await share(config, { resource_type, resource_id, email, role });
|
|
68
|
+
let msg = `Invited ${result.email} as ${result.role} on ${result.resource_type} ${result.resource_id}`;
|
|
69
|
+
if (result.role_id)
|
|
70
|
+
msg += ` (role_id: ${result.role_id})`;
|
|
104
71
|
return toolResult(msg);
|
|
105
72
|
}
|
|
106
73
|
catch (e) {
|
|
@@ -125,16 +92,11 @@ defineTool({
|
|
|
125
92
|
},
|
|
126
93
|
}, async ({ resource_type, resource_id, user_id }) => {
|
|
127
94
|
try {
|
|
128
|
-
const
|
|
129
|
-
|
|
130
|
-
if (!target) {
|
|
131
|
-
return toolError(`User ${user_id} has no role on this ${resource_type}.`);
|
|
132
|
-
}
|
|
133
|
-
await internalClient(config).delete(`/api/roles/${target.id}`);
|
|
134
|
-
return toolResult(`Revoked access for user ${user_id} on ${resource_type} ${resource_id}`);
|
|
95
|
+
const msg = await revokeAccess(config, { resource_type, resource_id, user_id });
|
|
96
|
+
return toolResult(msg);
|
|
135
97
|
}
|
|
136
98
|
catch (e) {
|
|
137
|
-
return toolError(`Failed to revoke access: ${e.response
|
|
99
|
+
return toolError(e.response?.status ? `Failed to revoke access: ${e.response.status}` : e.message);
|
|
138
100
|
}
|
|
139
101
|
});
|
|
140
102
|
},
|
|
@@ -149,32 +111,8 @@ defineTool({
|
|
|
149
111
|
inputSchema: {},
|
|
150
112
|
}, async () => {
|
|
151
113
|
try {
|
|
152
|
-
const
|
|
153
|
-
|
|
154
|
-
});
|
|
155
|
-
const notifications = res.data?.meta || [];
|
|
156
|
-
const requests = (Array.isArray(notifications) ? notifications : [])
|
|
157
|
-
.filter((n) => n.notification_type === 'FileRoleRequestCreatedNotif')
|
|
158
|
-
.map((n) => {
|
|
159
|
-
const locals = n.notification?.locals || n.preferred_attachments?.[0]?.body || {};
|
|
160
|
-
// Extract from notification locals if available, otherwise parse from display text
|
|
161
|
-
const title = n.preferred_attachments?.[0]?.body?.title || [];
|
|
162
|
-
const subtitle = n.preferred_attachments?.[0]?.body?.subtitle || [];
|
|
163
|
-
const email = title[0]?.html_text?.replace(/<[^>]+>/g, '') || undefined;
|
|
164
|
-
const action = subtitle[0]?.html_text || undefined;
|
|
165
|
-
const fileName = subtitle[2]?.html_text || undefined;
|
|
166
|
-
const hasActions = !!n.preferred_attachments?.[0]?.actions;
|
|
167
|
-
return {
|
|
168
|
-
notification_id: n.notification_id,
|
|
169
|
-
email,
|
|
170
|
-
action,
|
|
171
|
-
file_name: fileName,
|
|
172
|
-
pending: hasActions,
|
|
173
|
-
is_unread: n.is_unread,
|
|
174
|
-
created_at: n.preferred_attachments?.[0]?.body?.created_at,
|
|
175
|
-
};
|
|
176
|
-
});
|
|
177
|
-
return toolResult(JSON.stringify(requests, null, 2));
|
|
114
|
+
const result = await listRoleRequests(config);
|
|
115
|
+
return toolResult(JSON.stringify(result, null, 2));
|
|
178
116
|
}
|
|
179
117
|
catch (e) {
|
|
180
118
|
return toolError(`Failed to list role requests: ${e.response?.status || e.message}`);
|
|
@@ -195,19 +133,7 @@ defineTool({
|
|
|
195
133
|
},
|
|
196
134
|
}, async ({ notification_id }) => {
|
|
197
135
|
try {
|
|
198
|
-
const
|
|
199
|
-
id: notification_id,
|
|
200
|
-
medium: 'web',
|
|
201
|
-
appVersion: '1',
|
|
202
|
-
clientType: 'web',
|
|
203
|
-
});
|
|
204
|
-
const notif = res.data?.meta?.notification;
|
|
205
|
-
const locals = notif?.locals || {};
|
|
206
|
-
let msg = `Approved access request ${notification_id}`;
|
|
207
|
-
if (locals.file_name)
|
|
208
|
-
msg += ` for ${locals.file_name}`;
|
|
209
|
-
if (locals.user_id)
|
|
210
|
-
msg += ` (user ${locals.user_id})`;
|
|
136
|
+
const msg = await approveRoleRequest(config, { notification_id });
|
|
211
137
|
return toolResult(msg);
|
|
212
138
|
}
|
|
213
139
|
catch (e) {
|
|
@@ -229,13 +155,8 @@ defineTool({
|
|
|
229
155
|
},
|
|
230
156
|
}, async ({ notification_id }) => {
|
|
231
157
|
try {
|
|
232
|
-
await
|
|
233
|
-
|
|
234
|
-
medium: 'web',
|
|
235
|
-
appVersion: '1',
|
|
236
|
-
clientType: 'web',
|
|
237
|
-
});
|
|
238
|
-
return toolResult(`Declined access request ${notification_id}`);
|
|
158
|
+
const msg = await denyRoleRequest(config, { notification_id });
|
|
159
|
+
return toolResult(msg);
|
|
239
160
|
}
|
|
240
161
|
catch (e) {
|
|
241
162
|
return toolError(`Failed to deny request: ${e.response?.status || e.message}`);
|
package/dist/tools/projects.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { z } from 'zod';
|
|
2
|
-
import { internalClient } from '../clients/internal-api.js';
|
|
3
2
|
import { defineTool, toolResult, toolError, figmaId } from './register.js';
|
|
3
|
+
import { createProject, renameProject, moveProject, trashProject, restoreProject, setProjectDescription, } from '../operations/projects.js';
|
|
4
4
|
// -- create_project --
|
|
5
5
|
defineTool({
|
|
6
6
|
toolset: 'projects',
|
|
@@ -15,19 +15,8 @@ defineTool({
|
|
|
15
15
|
},
|
|
16
16
|
}, async ({ team_id, name }) => {
|
|
17
17
|
try {
|
|
18
|
-
const
|
|
19
|
-
|
|
20
|
-
path: name,
|
|
21
|
-
sharing_audience_control: 'org_view',
|
|
22
|
-
team_access: 'team_edit',
|
|
23
|
-
});
|
|
24
|
-
const meta = res.data?.meta;
|
|
25
|
-
const p = Array.isArray(meta) ? meta[0] : (meta?.folder || meta || res.data);
|
|
26
|
-
return toolResult(JSON.stringify({
|
|
27
|
-
id: String(p.id),
|
|
28
|
-
name: p.name || p.path || name,
|
|
29
|
-
team_id,
|
|
30
|
-
}, null, 2));
|
|
18
|
+
const result = await createProject(config, { team_id, name });
|
|
19
|
+
return toolResult(JSON.stringify(result, null, 2));
|
|
31
20
|
}
|
|
32
21
|
catch (e) {
|
|
33
22
|
return toolError(`Failed to create project: ${e.response?.status || e.message}`);
|
|
@@ -49,10 +38,7 @@ defineTool({
|
|
|
49
38
|
},
|
|
50
39
|
}, async ({ project_id, name }) => {
|
|
51
40
|
try {
|
|
52
|
-
await
|
|
53
|
-
folder_id: project_id,
|
|
54
|
-
name,
|
|
55
|
-
});
|
|
41
|
+
await renameProject(config, { project_id, name });
|
|
56
42
|
return toolResult(`Renamed project ${project_id} to "${name}"`);
|
|
57
43
|
}
|
|
58
44
|
catch (e) {
|
|
@@ -75,10 +61,7 @@ defineTool({
|
|
|
75
61
|
},
|
|
76
62
|
}, async ({ project_id, destination_team_id }) => {
|
|
77
63
|
try {
|
|
78
|
-
await
|
|
79
|
-
folder_id: project_id,
|
|
80
|
-
team_id: destination_team_id,
|
|
81
|
-
});
|
|
64
|
+
await moveProject(config, { project_id, destination_team_id });
|
|
82
65
|
return toolResult(`Moved project ${project_id} to team ${destination_team_id}`);
|
|
83
66
|
}
|
|
84
67
|
catch (e) {
|
|
@@ -101,7 +84,7 @@ defineTool({
|
|
|
101
84
|
},
|
|
102
85
|
}, async ({ project_id }) => {
|
|
103
86
|
try {
|
|
104
|
-
await
|
|
87
|
+
await trashProject(config, { project_id });
|
|
105
88
|
return toolResult(`Trashed project ${project_id}`);
|
|
106
89
|
}
|
|
107
90
|
catch (e) {
|
|
@@ -123,7 +106,7 @@ defineTool({
|
|
|
123
106
|
},
|
|
124
107
|
}, async ({ project_id }) => {
|
|
125
108
|
try {
|
|
126
|
-
await
|
|
109
|
+
await restoreProject(config, { project_id });
|
|
127
110
|
return toolResult(`Restored project ${project_id}`);
|
|
128
111
|
}
|
|
129
112
|
catch (e) {
|
|
@@ -146,9 +129,7 @@ defineTool({
|
|
|
146
129
|
},
|
|
147
130
|
}, async ({ project_id, description }) => {
|
|
148
131
|
try {
|
|
149
|
-
await
|
|
150
|
-
description,
|
|
151
|
-
});
|
|
132
|
+
await setProjectDescription(config, { project_id, description });
|
|
152
133
|
return toolResult(`Updated description for project ${project_id}`);
|
|
153
134
|
}
|
|
154
135
|
catch (e) {
|
package/dist/tools/reading.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { z } from 'zod';
|
|
2
|
-
import { publicClient } from '../clients/public-api.js';
|
|
3
2
|
import { defineTool, toolResult, toolError, figmaId } from './register.js';
|
|
3
|
+
import { getFile, getNodes } from '../operations/reading.js';
|
|
4
4
|
// -- get_file --
|
|
5
5
|
defineTool({
|
|
6
6
|
toolset: 'reading',
|
|
@@ -15,13 +15,8 @@ defineTool({
|
|
|
15
15
|
},
|
|
16
16
|
}, async ({ file_key, depth, node_id }) => {
|
|
17
17
|
try {
|
|
18
|
-
const
|
|
19
|
-
|
|
20
|
-
params.depth = String(depth);
|
|
21
|
-
if (node_id)
|
|
22
|
-
params['node-id'] = node_id;
|
|
23
|
-
const res = await publicClient(config).get(`/v1/files/${file_key}`, { params });
|
|
24
|
-
return toolResult(JSON.stringify(res.data, null, 2));
|
|
18
|
+
const result = await getFile(config, { file_key, depth, node_id });
|
|
19
|
+
return toolResult(JSON.stringify(result, null, 2));
|
|
25
20
|
}
|
|
26
21
|
catch (e) {
|
|
27
22
|
return toolError(`Failed to get file: ${e.response?.status || e.message}`);
|
|
@@ -43,13 +38,8 @@ defineTool({
|
|
|
43
38
|
},
|
|
44
39
|
}, async ({ file_key, node_ids, depth }) => {
|
|
45
40
|
try {
|
|
46
|
-
const
|
|
47
|
-
|
|
48
|
-
};
|
|
49
|
-
if (depth !== undefined)
|
|
50
|
-
params.depth = String(depth);
|
|
51
|
-
const res = await publicClient(config).get(`/v1/files/${file_key}/nodes`, { params });
|
|
52
|
-
return toolResult(JSON.stringify(res.data, null, 2));
|
|
41
|
+
const result = await getNodes(config, { file_key, node_ids, depth });
|
|
42
|
+
return toolResult(JSON.stringify(result, null, 2));
|
|
53
43
|
}
|
|
54
44
|
catch (e) {
|
|
55
45
|
return toolError(`Failed to get nodes: ${e.response?.status || e.message}`);
|