figmanage 1.2.9 → 1.3.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (60) hide show
  1. package/README.md +10 -8
  2. package/dist/cli/analytics.js +3 -2
  3. package/dist/cli/branching.js +9 -3
  4. package/dist/cli/comments.js +10 -4
  5. package/dist/cli/components.js +21 -4
  6. package/dist/cli/compound-commands.js +13 -12
  7. package/dist/cli/export.js +3 -2
  8. package/dist/cli/files.js +14 -8
  9. package/dist/cli/helpers.d.ts +1 -0
  10. package/dist/cli/helpers.js +10 -0
  11. package/dist/cli/libraries.js +2 -1
  12. package/dist/cli/navigate.js +11 -10
  13. package/dist/cli/org.js +13 -12
  14. package/dist/cli/permissions.js +13 -7
  15. package/dist/cli/projects.js +12 -6
  16. package/dist/cli/reading.js +3 -2
  17. package/dist/cli/teams.js +9 -3
  18. package/dist/cli/variables.js +29 -7
  19. package/dist/cli/versions.js +3 -2
  20. package/dist/cli/webhooks.js +14 -4
  21. package/dist/helpers.d.ts +11 -0
  22. package/dist/helpers.js +41 -0
  23. package/dist/mcp.js +18 -6
  24. package/dist/operations/analytics.js +1 -1
  25. package/dist/operations/components.d.ts +8 -2
  26. package/dist/operations/components.js +4 -2
  27. package/dist/operations/compound-manager.js +8 -9
  28. package/dist/operations/compound.d.ts +3 -0
  29. package/dist/operations/compound.js +14 -8
  30. package/dist/operations/files.js +1 -1
  31. package/dist/operations/libraries.js +1 -1
  32. package/dist/operations/org.js +1 -1
  33. package/dist/operations/reading.js +2 -0
  34. package/dist/operations/teams.js +1 -1
  35. package/dist/operations/variables.js +11 -0
  36. package/dist/operations/webhooks.d.ts +4 -1
  37. package/dist/operations/webhooks.js +2 -1
  38. package/dist/tools/analytics.js +6 -5
  39. package/dist/tools/branching.js +7 -6
  40. package/dist/tools/comments.js +14 -9
  41. package/dist/tools/components.js +24 -15
  42. package/dist/tools/compound-manager.js +10 -7
  43. package/dist/tools/compound.js +34 -22
  44. package/dist/tools/export.js +6 -5
  45. package/dist/tools/files.js +13 -12
  46. package/dist/tools/libraries.js +6 -3
  47. package/dist/tools/navigate.js +29 -18
  48. package/dist/tools/org.js +25 -24
  49. package/dist/tools/permissions.js +14 -11
  50. package/dist/tools/projects.js +10 -9
  51. package/dist/tools/reading.js +11 -7
  52. package/dist/tools/register.d.ts +8 -2
  53. package/dist/tools/register.js +9 -14
  54. package/dist/tools/setup.d.ts +10 -0
  55. package/dist/tools/setup.js +181 -0
  56. package/dist/tools/teams.js +7 -6
  57. package/dist/tools/variables.js +12 -8
  58. package/dist/tools/versions.js +6 -5
  59. package/dist/tools/webhooks.js +15 -12
  60. package/package.json +1 -1
@@ -1,5 +1,6 @@
1
1
  import { z } from 'zod';
2
- import { defineTool, toolResult, toolError, figmaId } from './register.js';
2
+ import { defineTool, toolError, toolSummary, figmaId } from './register.js';
3
+ import { formatApiError } from '../helpers.js';
3
4
  import { fileSummary, workspaceOverview, openComments, cleanupStaleFiles, organizeProject, setupProjectStructure, seatOptimization, permissionAudit, branchCleanup, } from '../operations/compound.js';
4
5
  // -- file_summary --
5
6
  defineTool({
@@ -14,10 +15,10 @@ defineTool({
14
15
  }, async ({ file_key }) => {
15
16
  try {
16
17
  const result = await fileSummary(config, { file_key });
17
- return toolResult(JSON.stringify(result, null, 2));
18
+ return toolSummary(`${result.name}: ${result.pages?.length || 0} pages, ${result.component_count} components, ${result.unresolved_comment_count} unresolved comments.`, result);
18
19
  }
19
20
  catch (e) {
20
- return toolError(`Failed to summarize file: ${e.response?.status || e.message}`);
21
+ return toolError(`Failed to summarize file: ${formatApiError(e)}`);
21
22
  }
22
23
  });
23
24
  },
@@ -35,10 +36,11 @@ defineTool({
35
36
  }, async ({ org_id }) => {
36
37
  try {
37
38
  const result = await workspaceOverview(config, { org_id });
38
- return toolResult(JSON.stringify(result, null, 2));
39
+ const teamCount = result.teams?.length || 0;
40
+ return toolSummary(`${teamCount} team(s). Seats and billing included.`, result);
39
41
  }
40
42
  catch (e) {
41
- return toolError(`Failed to fetch workspace overview: ${e.response?.status || e.message}`);
43
+ return toolError(`Failed to fetch workspace overview: ${formatApiError(e)}`);
42
44
  }
43
45
  });
44
46
  },
@@ -56,10 +58,12 @@ defineTool({
56
58
  }, async ({ project_id }) => {
57
59
  try {
58
60
  const result = await openComments(config, { project_id });
59
- return toolResult(JSON.stringify(result, null, 2));
61
+ const total = result.total_unresolved || 0;
62
+ const fileCount = result.files?.length || 0;
63
+ return toolSummary(`${total} unresolved comment(s) across ${fileCount} file(s).`, result, 'Use post_comment with file_key and parent_id to reply.');
60
64
  }
61
65
  catch (e) {
62
- return toolError(`Failed to fetch open comments: ${e.response?.status || e.message}`);
66
+ return toolError(`Failed to fetch open comments: ${formatApiError(e)}`);
63
67
  }
64
68
  });
65
69
  },
@@ -72,7 +76,7 @@ defineTool({
72
76
  destructive: true,
73
77
  register(server, config) {
74
78
  server.registerTool('cleanup_stale_files', {
75
- description: 'Find files not modified in N days and optionally trash them. Defaults to dry run.',
79
+ description: 'Find files not modified in N days and optionally trash them. dry_run=true (default) previews which files would be trashed without trashing them. Set dry_run=false to execute.',
76
80
  inputSchema: {
77
81
  project_id: figmaId.describe('Project ID'),
78
82
  days_stale: z.number().optional().default(90).describe('Days since last modification (default: 90)'),
@@ -85,10 +89,12 @@ defineTool({
85
89
  days_stale: days_stale ?? 90,
86
90
  dry_run: rawDryRun ?? true,
87
91
  });
88
- return toolResult(JSON.stringify(result, null, 2));
92
+ const count = result.stale_files?.length || 0;
93
+ const action = result.dry_run ? `${count} stale file(s) found. Set dry_run=false to trash them.` : `Trashed ${result.trashed_count || 0} file(s).`;
94
+ return toolSummary(action, result);
89
95
  }
90
96
  catch (e) {
91
- return toolError(`Failed to cleanup stale files: ${e.response?.status || e.message}`);
97
+ return toolError(`Failed to cleanup stale files: ${formatApiError(e)}`);
92
98
  }
93
99
  });
94
100
  },
@@ -100,7 +106,7 @@ defineTool({
100
106
  mutates: true,
101
107
  register(server, config) {
102
108
  server.registerTool('organize_project', {
103
- description: 'Move multiple files into a target project in a single batch.',
109
+ description: 'Move files into a target project in a single batch. Files are moved (not copied) from their current project.',
104
110
  inputSchema: {
105
111
  file_keys: z.array(figmaId).min(1).describe('File keys to move'),
106
112
  target_project_id: figmaId.describe('Destination project ID'),
@@ -108,10 +114,10 @@ defineTool({
108
114
  }, async ({ file_keys, target_project_id }) => {
109
115
  try {
110
116
  const result = await organizeProject(config, { file_keys, target_project_id });
111
- return toolResult(JSON.stringify(result, null, 2));
117
+ return toolSummary(`Moved ${result.moved} file(s) to project ${result.target_project_id}.`, result);
112
118
  }
113
119
  catch (e) {
114
- return toolError(`Failed to organize project: ${e.response?.status || e.message}`);
120
+ return toolError(`Failed to organize project: ${formatApiError(e)}`);
115
121
  }
116
122
  });
117
123
  },
@@ -134,10 +140,10 @@ defineTool({
134
140
  }, async ({ team_id, projects }) => {
135
141
  try {
136
142
  const result = await setupProjectStructure(config, { team_id, projects });
137
- return toolResult(JSON.stringify(result, null, 2));
143
+ return toolSummary(`Created ${result.created?.length || 0} project(s).`, result);
138
144
  }
139
145
  catch (e) {
140
- return toolError(`Failed to setup project structure: ${e.response?.status || e.message}`);
146
+ return toolError(`Failed to setup project structure: ${formatApiError(e)}`);
141
147
  }
142
148
  });
143
149
  },
@@ -161,10 +167,13 @@ defineTool({
161
167
  days_inactive: days_inactive ?? 90,
162
168
  include_cost: include_cost ?? true,
163
169
  });
164
- return toolResult(JSON.stringify(result, null, 2));
170
+ const inactive = result.summary?.inactive_paid || 0;
171
+ const savingsCents = result.summary?.monthly_waste_cents || 0;
172
+ const savingsStr = savingsCents > 0 ? ` Potential savings: $${(savingsCents / 100).toFixed(2)}/mo.` : '';
173
+ return toolSummary(`${inactive} inactive paid seat(s).${savingsStr}`, result, 'Use change_seat to downgrade inactive users, or offboard_user for full removal.');
165
174
  }
166
175
  catch (e) {
167
- return toolError(`Failed to analyze seat optimization: ${e.response?.status || e.message}`);
176
+ return toolError(`Failed to analyze seat optimization: ${formatApiError(e)}`);
168
177
  }
169
178
  });
170
179
  },
@@ -190,10 +199,11 @@ defineTool({
190
199
  flag_external: flag_external ?? true,
191
200
  org_id,
192
201
  });
193
- return toolResult(JSON.stringify(result, null, 2));
202
+ const flagCount = result.flags?.length || 0;
203
+ return toolSummary(`${flagCount} issue(s) flagged.`, result, flagCount > 0 ? 'Use revoke_access or set_permissions to address flagged issues.' : undefined);
194
204
  }
195
205
  catch (e) {
196
- return toolError(`Failed to audit permissions: ${e.response?.status || e.message}`);
206
+ return toolError(`Failed to audit permissions: ${formatApiError(e)}`);
197
207
  }
198
208
  });
199
209
  },
@@ -206,7 +216,7 @@ defineTool({
206
216
  destructive: true,
207
217
  register(server, config) {
208
218
  server.registerTool('branch_cleanup', {
209
- description: 'Find stale branches across a project and optionally archive them. Defaults to dry run.',
219
+ description: 'Find stale branches across a project and optionally archive them. dry_run=true (default) previews which branches would be archived. Archives move branch files to trash (recoverable).',
210
220
  inputSchema: {
211
221
  project_id: figmaId.describe('Project ID'),
212
222
  days_stale: z.number().min(1).max(365).optional().default(60).describe('Days since last modification to flag as stale (default: 60)'),
@@ -219,10 +229,12 @@ defineTool({
219
229
  days_stale: days_stale ?? 60,
220
230
  dry_run: rawDryRun ?? true,
221
231
  });
222
- return toolResult(JSON.stringify(result, null, 2));
232
+ const stale = result.stale_branches?.length || 0;
233
+ const action = result.dry_run ? `${stale} stale branch(es) found. Set dry_run=false to archive.` : `Archived ${result.archived_count || 0} branch(es).`;
234
+ return toolSummary(action, result);
223
235
  }
224
236
  catch (e) {
225
- return toolError(`Failed to cleanup branches: ${e.response?.status || e.message}`);
237
+ return toolError(`Failed to cleanup branches: ${formatApiError(e)}`);
226
238
  }
227
239
  });
228
240
  },
@@ -1,5 +1,6 @@
1
1
  import { z } from 'zod';
2
- import { defineTool, toolResult, toolError, figmaId } from './register.js';
2
+ import { defineTool, toolResult, toolError, toolSummary, figmaId } from './register.js';
3
+ import { formatApiError } from '../helpers.js';
3
4
  import { exportNodes, getImageFills } from '../operations/export.js';
4
5
  // -- export_nodes --
5
6
  defineTool({
@@ -17,10 +18,10 @@ defineTool({
17
18
  }, async ({ file_key, node_ids, format, scale }) => {
18
19
  try {
19
20
  const result = await exportNodes(config, { file_key, node_ids, format, scale });
20
- return toolResult(JSON.stringify(result, null, 2));
21
+ return toolSummary(`Exported ${result.length} node(s). URLs valid ~14 days.`, result);
21
22
  }
22
23
  catch (e) {
23
- return toolError(`Failed to export nodes: ${e.response?.status || e.message}`);
24
+ return toolError(`Failed to export nodes: ${formatApiError(e)}`);
24
25
  }
25
26
  });
26
27
  },
@@ -40,10 +41,10 @@ defineTool({
40
41
  const results = await getImageFills(config, { file_key });
41
42
  if (results.length === 0)
42
43
  return toolResult('No image fills in this file.');
43
- return toolResult(JSON.stringify(results, null, 2));
44
+ return toolSummary(`${results.length} image fill(s).`, results);
44
45
  }
45
46
  catch (e) {
46
- return toolError(`Failed to get image fills: ${e.response?.status || e.message}`);
47
+ return toolError(`Failed to get image fills: ${formatApiError(e)}`);
47
48
  }
48
49
  });
49
50
  },
@@ -1,5 +1,6 @@
1
1
  import { z } from 'zod';
2
- import { defineTool, toolResult, toolError, figmaId } from './register.js';
2
+ import { defineTool, toolResult, toolError, toolSummary, figmaId } from './register.js';
3
+ import { formatApiError } from '../helpers.js';
3
4
  import { createFile, renameFile, moveFiles, duplicateFile, trashFiles, restoreFiles, favoriteFile, setLinkAccess, } from '../operations/files.js';
4
5
  // -- create_file --
5
6
  defineTool({
@@ -17,10 +18,10 @@ defineTool({
17
18
  }, async ({ project_id, editor_type, org_id }) => {
18
19
  try {
19
20
  const result = await createFile(config, { project_id, editor_type, org_id });
20
- return toolResult(JSON.stringify(result, null, 2));
21
+ return toolSummary(`Created ${result.editor_type || 'design'} file.`, result);
21
22
  }
22
23
  catch (e) {
23
- return toolError(`Failed to create file: ${e.response?.status || e.message}`);
24
+ return toolError(`Failed to create file: ${formatApiError(e)}`);
24
25
  }
25
26
  });
26
27
  },
@@ -43,7 +44,7 @@ defineTool({
43
44
  return toolResult(`Renamed to "${name}"`);
44
45
  }
45
46
  catch (e) {
46
- return toolError(`Failed to rename file: ${e.response?.status || e.message}`);
47
+ return toolError(`Failed to rename file: ${formatApiError(e)}`);
47
48
  }
48
49
  });
49
50
  },
@@ -69,7 +70,7 @@ defineTool({
69
70
  return toolResult(msg);
70
71
  }
71
72
  catch (e) {
72
- return toolError(`Failed to move files: ${e.response?.status || e.message}`);
73
+ return toolError(`Failed to move files: ${formatApiError(e)}`);
73
74
  }
74
75
  });
75
76
  },
@@ -89,10 +90,10 @@ defineTool({
89
90
  }, async ({ file_key, project_id }) => {
90
91
  try {
91
92
  const result = await duplicateFile(config, { file_key, project_id });
92
- return toolResult(JSON.stringify(result, null, 2));
93
+ return toolSummary(`Duplicated file.`, result);
93
94
  }
94
95
  catch (e) {
95
- return toolError(`Failed to duplicate file: ${e.response?.status || e.message}`);
96
+ return toolError(`Failed to duplicate file: ${formatApiError(e)}`);
96
97
  }
97
98
  });
98
99
  },
@@ -105,7 +106,7 @@ defineTool({
105
106
  destructive: true,
106
107
  register(server, config) {
107
108
  server.registerTool('trash_files', {
108
- description: 'Move files to trash. Supports batch operations.',
109
+ description: 'Move files to trash (recoverable via restore_files). Supports batch operations.',
109
110
  inputSchema: {
110
111
  file_keys: z.array(figmaId).min(1).describe('Array of file keys to trash'),
111
112
  },
@@ -115,7 +116,7 @@ defineTool({
115
116
  return toolResult(`Trashed ${result.succeeded} file(s)`);
116
117
  }
117
118
  catch (e) {
118
- return toolError(`Failed to trash files: ${e.response?.status || e.message}`);
119
+ return toolError(`Failed to trash files: ${formatApiError(e)}`);
119
120
  }
120
121
  });
121
122
  },
@@ -140,7 +141,7 @@ defineTool({
140
141
  return toolResult(msg);
141
142
  }
142
143
  catch (e) {
143
- return toolError(`Failed to restore files: ${e.response?.status || e.message}`);
144
+ return toolError(`Failed to restore files: ${formatApiError(e)}`);
144
145
  }
145
146
  });
146
147
  },
@@ -163,7 +164,7 @@ defineTool({
163
164
  return toolResult(`${result.favorited ? 'Favorited' : 'Unfavorited'} file ${file_key}`);
164
165
  }
165
166
  catch (e) {
166
- return toolError(`Failed to toggle favorite: ${e.response?.status || e.message}`);
167
+ return toolError(`Failed to toggle favorite: ${formatApiError(e)}`);
167
168
  }
168
169
  });
169
170
  },
@@ -186,7 +187,7 @@ defineTool({
186
187
  return toolResult(`Set link access to "${result.link_access}" on file ${file_key}`);
187
188
  }
188
189
  catch (e) {
189
- return toolError(`Failed to set link access: ${e.response?.status || e.message}`);
190
+ return toolError(`Failed to set link access: ${formatApiError(e)}`);
190
191
  }
191
192
  });
192
193
  },
@@ -1,4 +1,5 @@
1
- import { defineTool, toolResult, toolError, figmaId } from './register.js';
1
+ import { defineTool, toolResult, toolError, toolSummary, figmaId } from './register.js';
2
+ import { formatApiError } from '../helpers.js';
2
3
  import { listOrgLibraries } from '../operations/libraries.js';
3
4
  // -- list_org_libraries --
4
5
  defineTool({
@@ -13,10 +14,12 @@ defineTool({
13
14
  }, async ({ org_id }) => {
14
15
  try {
15
16
  const result = await listOrgLibraries(config, { org_id });
16
- return toolResult(JSON.stringify(result, null, 2));
17
+ if (result.length === 0)
18
+ return toolResult('No libraries found.');
19
+ return toolSummary(`${result.length} library/libraries.`, result, 'Use library_usage to see adoption metrics.');
17
20
  }
18
21
  catch (e) {
19
- return toolError(`Failed to list org libraries: ${e.response?.status || e.message}`);
22
+ return toolError(`Failed to list org libraries: ${formatApiError(e)}`);
20
23
  }
21
24
  });
22
25
  },
@@ -1,5 +1,6 @@
1
1
  import { z } from 'zod';
2
- import { defineTool, toolResult, toolError, figmaId } from './register.js';
2
+ import { defineTool, toolResult, toolError, toolSummary, figmaId } from './register.js';
3
+ import { formatApiError } from '../helpers.js';
3
4
  import { checkAuthStatus, listOrgs, switchOrg, listTeams, listProjects, listFiles, listRecentFiles, search, getFileInfo, listFavorites, } from '../operations/navigate.js';
4
5
  // -- check_auth --
5
6
  defineTool({
@@ -34,10 +35,10 @@ defineTool({
34
35
  if (orgs.length === 0) {
35
36
  return toolResult('No workspaces found. You may be on a free/starter plan.');
36
37
  }
37
- return toolResult(JSON.stringify(orgs, null, 2));
38
+ return toolSummary(`Found ${orgs.length} workspace(s).`, orgs, 'Use switch_org to change workspace, or list_teams to browse.');
38
39
  }
39
40
  catch (e) {
40
- return toolError(`Failed to list orgs: ${e.response?.status || e.message}`);
41
+ return toolError(`Failed to list orgs: ${formatApiError(e)}`);
41
42
  }
42
43
  });
43
44
  },
@@ -60,7 +61,7 @@ defineTool({
60
61
  return toolResult(`Switched workspace: ${result.previous} -> ${result.current.name} (${result.current.id})`);
61
62
  }
62
63
  catch (e) {
63
- return toolError(`Failed to switch org: ${e.response?.status || e.message}`);
64
+ return toolError(`Failed to switch org: ${formatApiError(e)}`);
64
65
  }
65
66
  });
66
67
  },
@@ -75,10 +76,12 @@ defineTool({
75
76
  }, async () => {
76
77
  try {
77
78
  const teams = await listTeams(config);
78
- return toolResult(JSON.stringify(teams, null, 2));
79
+ if (teams.length === 0)
80
+ return toolResult('No teams found.');
81
+ return toolSummary(`Found ${teams.length} team(s).`, teams, 'Use list_projects with a team_id to browse projects.');
79
82
  }
80
83
  catch (e) {
81
- return toolError(`Failed to list teams: ${e.response?.status || e.message}`);
84
+ return toolError(`Failed to list teams: ${formatApiError(e)}`);
82
85
  }
83
86
  });
84
87
  },
@@ -96,10 +99,12 @@ defineTool({
96
99
  }, async ({ team_id }) => {
97
100
  try {
98
101
  const projects = await listProjects(config, { team_id });
99
- return toolResult(JSON.stringify(projects, null, 2));
102
+ if (projects.length === 0)
103
+ return toolResult('No projects found.');
104
+ return toolSummary(`Found ${projects.length} project(s).`, projects, 'Use list_files with a project_id to see files.');
100
105
  }
101
106
  catch (e) {
102
- return toolError(`Failed to list projects: ${e.response?.status || e.message}`);
107
+ return toolError(`Failed to list projects: ${formatApiError(e)}`);
103
108
  }
104
109
  });
105
110
  },
@@ -119,10 +124,12 @@ defineTool({
119
124
  }, async ({ project_id, page_size, page_token }) => {
120
125
  try {
121
126
  const result = await listFiles(config, { project_id, page_size, page_token });
122
- return toolResult(JSON.stringify(result, null, 2));
127
+ const count = result.files.length;
128
+ const summary = `${count} file(s).` + (result.pagination?.has_more ? ' More pages available.' : '');
129
+ return toolSummary(summary, result, 'Use get_file_info or get_file for details.');
123
130
  }
124
131
  catch (e) {
125
- return toolError(`Failed to list files: ${e.response?.status || e.message}`);
132
+ return toolError(`Failed to list files: ${formatApiError(e)}`);
126
133
  }
127
134
  });
128
135
  },
@@ -137,10 +144,12 @@ defineTool({
137
144
  }, async () => {
138
145
  try {
139
146
  const files = await listRecentFiles(config);
140
- return toolResult(JSON.stringify(files, null, 2));
147
+ if (files.length === 0)
148
+ return toolResult('No recent files.');
149
+ return toolSummary(`${files.length} recently accessed file(s).`, files, 'Use get_file_info for details.');
141
150
  }
142
151
  catch (e) {
143
- return toolError(`Failed to list recent files: ${e.response?.status || e.message}`);
152
+ return toolError(`Failed to list recent files: ${formatApiError(e)}`);
144
153
  }
145
154
  });
146
155
  },
@@ -163,10 +172,10 @@ defineTool({
163
172
  if (results.length === 0) {
164
173
  return toolResult('No results. Try list_recent_files or browse via list_projects + list_files.');
165
174
  }
166
- return toolResult(JSON.stringify(results, null, 2));
175
+ return toolSummary(`Found ${results.length} result(s).`, results, 'Use get_file_info for file details.');
167
176
  }
168
177
  catch (e) {
169
- return toolError(`Search failed: ${e.response?.status || e.message}`);
178
+ return toolError(`Search failed: ${formatApiError(e)}`);
170
179
  }
171
180
  });
172
181
  },
@@ -184,10 +193,10 @@ defineTool({
184
193
  }, async ({ file_key }) => {
185
194
  try {
186
195
  const info = await getFileInfo(config, { file_key });
187
- return toolResult(JSON.stringify(info, null, 2));
196
+ return toolSummary(`${info.name} (${info.editor_type || 'design'})`, info);
188
197
  }
189
198
  catch (e) {
190
- return toolError(`Failed to get file info: ${e.response?.status || e.message}`);
199
+ return toolError(`Failed to get file info: ${formatApiError(e)}`);
191
200
  }
192
201
  });
193
202
  },
@@ -202,10 +211,12 @@ defineTool({
202
211
  }, async () => {
203
212
  try {
204
213
  const favorites = await listFavorites(config);
205
- return toolResult(JSON.stringify(favorites, null, 2));
214
+ if (favorites.length === 0)
215
+ return toolResult('No favorites found.');
216
+ return toolSummary(`${favorites.length} favorited file(s).`, favorites, 'Use get_file_info for details.');
206
217
  }
207
218
  catch (e) {
208
- return toolError(`Failed to list favorites: ${e.response?.status || e.message}`);
219
+ return toolError(`Failed to list favorites: ${formatApiError(e)}`);
209
220
  }
210
221
  });
211
222
  },
package/dist/tools/org.js CHANGED
@@ -1,5 +1,6 @@
1
1
  import { z } from 'zod';
2
- import { defineTool, toolResult, toolError, figmaId } from './register.js';
2
+ import { defineTool, toolResult, toolError, toolSummary, figmaId } from './register.js';
3
+ import { formatApiError } from '../helpers.js';
3
4
  import { listAdmins, listOrgTeams, seatUsage, listTeamMembers, billingOverview, listInvoices, orgDomains, aiCreditUsage, exportMembers, listOrgMembers, contractRates, changeSeat, } from '../operations/org.js';
4
5
  // -- list_admins --
5
6
  defineTool({
@@ -15,10 +16,10 @@ defineTool({
15
16
  }, async ({ org_id, include_license_admins }) => {
16
17
  try {
17
18
  const result = await listAdmins(config, { org_id, include_license_admins });
18
- return toolResult(JSON.stringify(result, null, 2));
19
+ return toolSummary(`${result.length} admin(s).`, result);
19
20
  }
20
21
  catch (e) {
21
- return toolError(`Failed to list admins: ${e.response?.status || e.message}`);
22
+ return toolError(`Failed to list admins: ${formatApiError(e)}`);
22
23
  }
23
24
  });
24
25
  },
@@ -37,10 +38,10 @@ defineTool({
37
38
  }, async ({ org_id, include_secret_teams }) => {
38
39
  try {
39
40
  const result = await listOrgTeams(config, { org_id, include_secret_teams });
40
- return toolResult(JSON.stringify(result, null, 2));
41
+ return toolSummary(`${result.length} team(s) in the org.`, result, 'Use list_team_members for member details.');
41
42
  }
42
43
  catch (e) {
43
- return toolError(`Failed to list org teams: ${e.response?.status || e.message}`);
44
+ return toolError(`Failed to list org teams: ${formatApiError(e)}`);
44
45
  }
45
46
  });
46
47
  },
@@ -59,10 +60,10 @@ defineTool({
59
60
  }, async ({ org_id, search_query }) => {
60
61
  try {
61
62
  const result = await seatUsage(config, { org_id, search_query });
62
- return toolResult(JSON.stringify(result, null, 2));
63
+ return toolSummary('Seat usage breakdown:', result);
63
64
  }
64
65
  catch (e) {
65
- return toolError(`Failed to fetch seat usage: ${e.response?.status || e.message}`);
66
+ return toolError(`Failed to fetch seat usage: ${formatApiError(e)}`);
66
67
  }
67
68
  });
68
69
  },
@@ -80,10 +81,10 @@ defineTool({
80
81
  }, async ({ team_id }) => {
81
82
  try {
82
83
  const result = await listTeamMembers(config, { team_id });
83
- return toolResult(JSON.stringify(result, null, 2));
84
+ return toolSummary(`${result.length} member(s).`, result);
84
85
  }
85
86
  catch (e) {
86
- return toolError(`Failed to list team members: ${e.response?.status || e.message}`);
87
+ return toolError(`Failed to list team members: ${formatApiError(e)}`);
87
88
  }
88
89
  });
89
90
  },
@@ -101,10 +102,10 @@ defineTool({
101
102
  }, async ({ org_id }) => {
102
103
  try {
103
104
  const result = await billingOverview(config, { org_id });
104
- return toolResult(JSON.stringify(result, null, 2));
105
+ return toolSummary('Billing overview:', result);
105
106
  }
106
107
  catch (e) {
107
- return toolError(`Failed to fetch billing overview: ${e.response?.status || e.message}`);
108
+ return toolError(`Failed to fetch billing overview: ${formatApiError(e)}`);
108
109
  }
109
110
  });
110
111
  },
@@ -122,10 +123,10 @@ defineTool({
122
123
  }, async ({ org_id }) => {
123
124
  try {
124
125
  const result = await listInvoices(config, { org_id });
125
- return toolResult(JSON.stringify(result, null, 2));
126
+ return toolSummary(`${result.length} invoice(s).`, result);
126
127
  }
127
128
  catch (e) {
128
- return toolError(`Failed to list invoices: ${e.response?.status || e.message}`);
129
+ return toolError(`Failed to list invoices: ${formatApiError(e)}`);
129
130
  }
130
131
  });
131
132
  },
@@ -143,10 +144,10 @@ defineTool({
143
144
  }, async ({ org_id }) => {
144
145
  try {
145
146
  const result = await orgDomains(config, { org_id });
146
- return toolResult(JSON.stringify(result, null, 2));
147
+ return toolSummary('Domain configuration:', result);
147
148
  }
148
149
  catch (e) {
149
- return toolError(`Failed to fetch org domains: ${e.response?.status || e.message}`);
150
+ return toolError(`Failed to fetch org domains: ${formatApiError(e)}`);
150
151
  }
151
152
  });
152
153
  },
@@ -164,10 +165,10 @@ defineTool({
164
165
  }, async ({ plan_id }) => {
165
166
  try {
166
167
  const result = await aiCreditUsage(config, { plan_id });
167
- return toolResult(JSON.stringify(result, null, 2));
168
+ return toolSummary('AI credit usage:', result);
168
169
  }
169
170
  catch (e) {
170
- return toolError(`Failed to fetch AI credit usage: ${e.response?.status || e.message}`);
171
+ return toolError(`Failed to fetch AI credit usage: ${formatApiError(e)}`);
171
172
  }
172
173
  });
173
174
  },
@@ -189,7 +190,7 @@ defineTool({
189
190
  return toolResult(msg);
190
191
  }
191
192
  catch (e) {
192
- return toolError(`Failed to export members: ${e.response?.status || e.message}`);
193
+ return toolError(`Failed to export members: ${formatApiError(e)}`);
193
194
  }
194
195
  });
195
196
  },
@@ -208,10 +209,10 @@ defineTool({
208
209
  }, async ({ org_id, search_query }) => {
209
210
  try {
210
211
  const result = await listOrgMembers(config, { org_id, search_query });
211
- return toolResult(JSON.stringify(result, null, 2));
212
+ return toolSummary(`${result.length} member(s).`, result, 'Use change_seat to modify seat types.');
212
213
  }
213
214
  catch (e) {
214
- return toolError(`Failed to list org members: ${e.response?.status || e.message}`);
215
+ return toolError(`Failed to list org members: ${formatApiError(e)}`);
215
216
  }
216
217
  });
217
218
  },
@@ -229,10 +230,10 @@ defineTool({
229
230
  }, async ({ org_id }) => {
230
231
  try {
231
232
  const result = await contractRates(config, { org_id });
232
- return toolResult(JSON.stringify(result, null, 2));
233
+ return toolSummary('Seat pricing:', result);
233
234
  }
234
235
  catch (e) {
235
- return toolError(`Failed to fetch contract rates: ${e.response?.status || e.message}`);
236
+ return toolError(`Failed to fetch contract rates: ${formatApiError(e)}`);
236
237
  }
237
238
  });
238
239
  },
@@ -257,10 +258,10 @@ defineTool({
257
258
  const result = await changeSeat(config, { user_id, seat_type, org_id, confirm });
258
259
  if (typeof result === 'string')
259
260
  return toolResult(result);
260
- return toolResult(JSON.stringify(result, null, 2));
261
+ return toolSummary('Seat change requires confirmation.', result);
261
262
  }
262
263
  catch (e) {
263
- return toolError(e.response?.status ? `Failed to change seat: ${e.response.status}` : e.message);
264
+ return toolError(`Failed to change seat: ${formatApiError(e)}`);
264
265
  }
265
266
  });
266
267
  },