@circleback/cli 1.1.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 CHANGED
@@ -1,6 +1,6 @@
1
1
  # Circleback CLI
2
2
 
3
- Search and access your meetings, transcripts, emails, calendar events, and more from the terminal, and manage your action items, tags, and meeting access.
3
+ Search and access your meetings, transcripts, emails, calendar events, and more from the terminal, and manage your action items, tags, folders, and meeting access.
4
4
 
5
5
  ## Installation
6
6
 
@@ -67,6 +67,12 @@ cb meetings --json
67
67
  | `cb tags create <name>` | Create a tag |
68
68
  | `cb tags update <id>` | Update a tag |
69
69
  | `cb tags delete <id>` | Delete a tag |
70
+ | `cb folders` | List folders |
71
+ | `cb folders read <ids...>` | Read folders |
72
+ | `cb folders create <name>` | Create a folder |
73
+ | `cb folders update <id>` | Update a folder |
74
+ | `cb folders delete <id>` | Delete a folder |
75
+ | `cb folders share <id>` | Share a folder |
70
76
 
71
77
  Run `cb --help` or `cb <command> --help` for full usage details.
72
78
 
@@ -117,7 +123,9 @@ For stateless automation, set `CIRCLEBACK_API_KEY` instead of logging in:
117
123
  CIRCLEBACK_API_KEY=cb_your_api_key cb meetings --json
118
124
  ```
119
125
 
120
- Changing meetings, action items, tags, or sharing permissions needs write access. Browser logins from before v0.5.0 don't include it, so run `cb auth login` again; read-only API keys can't make changes.
126
+ Changing meetings, action items, tags, folders, or sharing permissions needs write access. Browser logins from before v0.5.0 don't include it, so run `cb auth login` again; read-only API keys can't make changes.
127
+
128
+ An API key limited to one folder only reaches that folder's meetings, transcripts, and action items, so `cb --help` lists just the commands it can run.
121
129
 
122
130
  `CIRCLEBACK_API_KEY` takes precedence over stored credentials. Unset it before running `cb auth login`; `cb auth logout` cannot clear an environment variable from your shell.
123
131
 
@@ -1,6 +1,7 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.getCredentialSnapshot = exports.getLoginStatus = exports.getEnvironmentApiKey = void 0;
3
+ exports.getCredentialSnapshot = exports.getCredentialFingerprint = exports.getLoginStatus = exports.getEnvironmentApiKey = void 0;
4
+ const node_crypto_1 = require("node:crypto");
4
5
  const node_util_1 = require("node:util");
5
6
  const zod_1 = require("zod");
6
7
  const constants_1 = require("../constants");
@@ -79,6 +80,18 @@ const requireCredentials = () => {
79
80
  }
80
81
  return { type: types_1.CredentialType.OAuth, tokens: storedCredentials };
81
82
  };
83
+ const getCredentialFingerprint = () => {
84
+ try {
85
+ const credentials = requireCredentials();
86
+ return credentials.type === types_1.CredentialType.ApiKey
87
+ ? (0, node_crypto_1.createHash)('sha256').update(credentials.apiKey).digest('hex')
88
+ : types_1.CredentialType.OAuth;
89
+ }
90
+ catch {
91
+ return;
92
+ }
93
+ };
94
+ exports.getCredentialFingerprint = getCredentialFingerprint;
82
95
  const getCredentialSnapshot = async () => {
83
96
  const credentials = requireCredentials();
84
97
  if (credentials.type === types_1.CredentialType.OAuth) {
@@ -1,11 +1,15 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.callTool = void 0;
3
+ exports.listTools = exports.callTool = void 0;
4
4
  const zod_1 = require("zod");
5
5
  const constants_1 = require("../constants");
6
6
  const types_1 = require("../types");
7
7
  const credentials_1 = require("../auth/credentials");
8
+ const tokenStorage_1 = require("../auth/tokenStorage");
9
+ const value_1 = require("../helpers/value");
8
10
  const TOOLS_CALL_METHOD = 'tools/call';
11
+ const TOOLS_LIST_METHOD = 'tools/list';
12
+ const TOOLS_LIST_TIMEOUT_MILLISECONDS = 3_000;
9
13
  const errorResponseSchema = zod_1.z.object({
10
14
  error: zod_1.z.string().optional(),
11
15
  message: zod_1.z.string().optional(),
@@ -32,12 +36,13 @@ const HTTP_ERROR_MESSAGES = {
32
36
  404: 'Resource not found.',
33
37
  429: 'Rate limit exceeded. Please try again later.',
34
38
  };
35
- const sendRequest = async (method, params, accessToken) => fetch(`${constants_1.BASE_URL}/api/mcp`, {
39
+ const sendRequest = async (method, params, accessToken, signal) => fetch(`${constants_1.BASE_URL}/api/mcp`, {
36
40
  method: 'POST',
41
+ signal,
37
42
  headers: {
38
43
  'Content-Type': 'application/json',
39
44
  Accept: 'application/json, text/event-stream',
40
- Authorization: `Bearer ${accessToken}`,
45
+ ...((0, value_1.isPresent)(accessToken) && { Authorization: `Bearer ${accessToken}` }),
41
46
  [constants_1.CLIENT_VERSION_HEADER]: constants_1.CLIENT_VERSION,
42
47
  },
43
48
  body: JSON.stringify({
@@ -136,8 +141,32 @@ const callTool = async (toolName, toolArguments) => {
136
141
  const message = serverMessage ||
137
142
  fallback ||
138
143
  `Request failed with status ${response.status}.`;
139
- throw new Error(response.status === 403 ? `${message} ${WRITE_ACCESS_HINT}` : message);
144
+ throw new Error(response.status === 403 && message.includes('insufficient scope')
145
+ ? `${message} ${WRITE_ACCESS_HINT}`
146
+ : message);
140
147
  }
141
148
  return parseResponse(response);
142
149
  };
143
150
  exports.callTool = callTool;
151
+ const listTools = async () => {
152
+ const bearerCredential = (0, credentials_1.getEnvironmentApiKey)() || (0, tokenStorage_1.loadCredentials)()
153
+ ? (await (0, credentials_1.getCredentialSnapshot)()).bearerCredential
154
+ : undefined;
155
+ const response = await sendRequest(TOOLS_LIST_METHOD, {}, bearerCredential, AbortSignal.timeout(TOOLS_LIST_TIMEOUT_MILLISECONDS));
156
+ if (!response.ok)
157
+ throw new Error(await extractErrorMessage(response));
158
+ const text = await response.text();
159
+ const body = response.headers
160
+ .get('content-type')
161
+ ?.includes('text/event-stream')
162
+ ? text
163
+ .split('\n')
164
+ .find((line) => line.startsWith('data: '))
165
+ ?.slice(6)
166
+ : text;
167
+ return Object.fromEntries(types_1.ToolListResponseSchema.parse(JSON.parse(body ?? '')).result.tools.map(({ name, inputSchema }) => [
168
+ name,
169
+ Object.keys(inputSchema.properties ?? {}),
170
+ ]));
171
+ };
172
+ exports.listTools = listTools;
@@ -12,6 +12,7 @@ const oauth_1 = require("../auth/oauth");
12
12
  const tokenStorage_1 = require("../auth/tokenStorage");
13
13
  const constants_1 = require("../constants");
14
14
  const output_1 = require("../helpers/output");
15
+ const toolList_1 = require("../helpers/toolList");
15
16
  const types_1 = require("../types");
16
17
  const loginCommand = new commander_1.Command('login')
17
18
  .description('Log in to Circleback.')
@@ -33,11 +34,13 @@ const loginCommand = new commander_1.Command('login')
33
34
  const apiKey = await (0, apiKey_1.promptForApiKey)();
34
35
  await (0, apiKey_1.validateApiKey)(apiKey);
35
36
  (0, tokenStorage_1.saveCredentials)({ type: types_1.CredentialType.ApiKey, apiKey });
37
+ await (0, toolList_1.refreshToolList)();
36
38
  (0, output_1.printText)('Logged in with your API key.', output_1.TextType.Success);
37
39
  return;
38
40
  }
39
41
  (0, output_1.printText)('Opening your browser to log in…', output_1.TextType.Default);
40
42
  await (0, oauth_1.login)();
43
+ await (0, toolList_1.refreshToolList)();
41
44
  (0, output_1.printText)('Logged in successfully.', output_1.TextType.Success);
42
45
  }
43
46
  catch (error) {
@@ -48,9 +51,11 @@ const loginCommand = new commander_1.Command('login')
48
51
  });
49
52
  const logoutCommand = new commander_1.Command('logout')
50
53
  .description('Sign out on this device.')
51
- .action(() => {
54
+ .action(async () => {
52
55
  const environmentApiKey = (0, credentials_1.getEnvironmentApiKey)();
53
56
  const didClearCredentials = (0, tokenStorage_1.clearCredentials)();
57
+ if (didClearCredentials)
58
+ await (0, toolList_1.refreshToolList)();
54
59
  if (!didClearCredentials) {
55
60
  if (environmentApiKey) {
56
61
  (0, output_1.printText)(`No saved login to clear. ${constants_1.API_KEY_ENVIRONMENT_VARIABLE} is still active.`, output_1.TextType.Warning);
@@ -0,0 +1,113 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.shareFolderCommand = exports.deleteFolderCommand = exports.updateFolderCommand = exports.createFolderCommand = exports.readFoldersCommand = exports.listFoldersCommand = void 0;
4
+ const commander_1 = require("commander");
5
+ const command_1 = require("../helpers/command");
6
+ const parse_1 = require("../helpers/parse");
7
+ const tag_1 = require("../helpers/tag");
8
+ const value_1 = require("../helpers/value");
9
+ const types_1 = require("../types");
10
+ exports.listFoldersCommand = (0, command_1.defineToolCommand)(new commander_1.Command('list').description('List folders.'), types_1.ToolName.ListFolders, () => ({}));
11
+ exports.readFoldersCommand = (0, command_1.defineToolCommand)(new commander_1.Command('read')
12
+ .description('Read folders with their members, teams, and rules.')
13
+ .argument('<ids...>', 'Folder IDs (max 20)'), types_1.ToolName.ReadFolders, (folderIds) => ({ intent: 'Reading folders.', folderIds }));
14
+ exports.createFolderCommand = (0, command_1.defineToolCommand)(new commander_1.Command('create')
15
+ .description('Create a folder.')
16
+ .argument('<name>', 'Folder name')
17
+ .requiredOption('--workspace <id>', 'Workspace ID')
18
+ .option('--private', 'Only show the folder to its members')
19
+ .option('--icon <icon>', 'Set the icon')
20
+ .addOption((0, tag_1.createColorOption)())
21
+ .option('--rules <json>', 'Set the rules (ruleGroups JSON)'), types_1.ToolName.CreateFolder, (name, options) => ({
22
+ name,
23
+ workspaceId: (0, parse_1.parseIntOption)(options.workspace, '--workspace'),
24
+ ...(options.private && { visibility: 'Private' }),
25
+ ...((0, value_1.isPresent)(options.icon) && { icon: options.icon }),
26
+ ...((0, value_1.isPresent)(options.color) && { color: (0, tag_1.getTagColor)(options.color) }),
27
+ ...((0, value_1.isPresent)(options.rules) && {
28
+ ruleGroups: (0, parse_1.parseJsonOption)(options.rules, '--rules'),
29
+ }),
30
+ }));
31
+ exports.updateFolderCommand = (0, command_1.defineToolCommand)(new commander_1.Command('update')
32
+ .description('Update a folder. Each option replaces the current value when provided.')
33
+ .argument('<id>', 'Folder ID')
34
+ .option('--name <name>', 'Update the name')
35
+ .option('--description <description>', 'Update the description, or "" to remove it')
36
+ .option('--icon <icon>', 'Update the icon, or "" to remove it')
37
+ .addOption(new commander_1.Option('--color <color>', 'Update the display color, or "" for the default').choices([...tag_1.TAG_COLOR_NAMES, '']))
38
+ .addOption(new commander_1.Option('--visibility <visibility>', 'Set who can find it').choices([
39
+ 'Closed',
40
+ 'Private',
41
+ ]))
42
+ .option('--rules <json>', 'Replace the rules (ruleGroups JSON, or "[]" to remove all)'), types_1.ToolName.UpdateFolder, (folderId, options) => {
43
+ if (!Object.values(options).some(value_1.isPresent)) {
44
+ throw new Error('Provide at least one field to update.');
45
+ }
46
+ const { rules, color, description, icon, ...fields } = options;
47
+ return {
48
+ folderId,
49
+ ...fields,
50
+ description: description === '' ? null : description,
51
+ icon: icon === '' ? null : icon,
52
+ color: color === '' ? null : (0, tag_1.getTagColor)(color),
53
+ ...((0, value_1.isPresent)(rules) && {
54
+ ruleGroups: (0, parse_1.parseJsonOption)(rules, '--rules'),
55
+ }),
56
+ };
57
+ });
58
+ exports.deleteFolderCommand = (0, command_1.defineToolCommand)(new commander_1.Command('delete')
59
+ .description('Delete a folder.')
60
+ .argument('<id>', 'Folder ID'), types_1.ToolName.DeleteFolder, (folderId) => ({ folderId }));
61
+ exports.shareFolderCommand = (0, command_1.defineToolCommand)(new commander_1.Command('share')
62
+ .description('Share a folder, change access, or remove access.')
63
+ .argument('<id>', 'Folder ID')
64
+ .option('--email <emails>', 'Share with email addresses (comma-separated)')
65
+ .option('--profile <ids>', 'Share with people (comma-separated)')
66
+ .option('--team <ids>', 'Share with teams (comma-separated)')
67
+ .option('--workspace <ids>', 'Share with workspaces (comma-separated)')
68
+ .addOption(new commander_1.Option('--access <access>', "Set access to the folder's meetings, or none").choices([...Object.values(types_1.ShareableMeetingAccess), 'none']))
69
+ .option('--contributor', 'Let them add meetings')
70
+ .option('--no-contributor', 'Stop them adding meetings')
71
+ .option('--owner', 'Let people manage the folder')
72
+ .option('--no-owner', 'Stop people managing the folder')
73
+ .option('--remove', 'Remove them from the folder'), types_1.ToolName.ShareFolder, (folderId, options) => {
74
+ if ((0, value_1.isPresent)(options.owner) && (options.team || options.workspace)) {
75
+ throw new Error('--owner only applies to --email and --profile.');
76
+ }
77
+ const grant = {
78
+ ...((0, value_1.isPresent)(options.access) && {
79
+ access: options.access === 'none' ? null : options.access,
80
+ }),
81
+ ...((0, value_1.isPresent)(options.contributor) && {
82
+ isContributor: options.contributor,
83
+ }),
84
+ ...(options.remove && { remove: true }),
85
+ };
86
+ const personGrant = {
87
+ ...grant,
88
+ ...((0, value_1.isPresent)(options.owner) && { isOwner: options.owner }),
89
+ };
90
+ const parseIds = (value, label) => value ? (0, parse_1.parseNumericIds)(value, label) : [];
91
+ const shares = [
92
+ ...(options.email?.split(',') ?? []).map((email) => ({
93
+ email: email.trim(),
94
+ ...personGrant,
95
+ })),
96
+ ...parseIds(options.profile, 'profile ID').map((profileId) => ({
97
+ profileId,
98
+ ...personGrant,
99
+ })),
100
+ ...parseIds(options.team, 'team ID').map((teamId) => ({
101
+ teamId,
102
+ ...grant,
103
+ })),
104
+ ...parseIds(options.workspace, 'workspace ID').map((workspaceId) => ({
105
+ workspaceId,
106
+ ...grant,
107
+ })),
108
+ ];
109
+ if (shares.length === 0) {
110
+ throw new Error('Set at least one of --email, --profile, --team, or --workspace.');
111
+ }
112
+ return { folderId, shares };
113
+ });
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.updateMeetingCommand = exports.shareMeetingCommand = exports.readMeetingsCommand = exports.searchMeetingsCommand = void 0;
3
+ exports.createUpdateMeetingCommand = exports.shareMeetingCommand = exports.readMeetingsCommand = exports.createSearchMeetingsCommand = void 0;
4
4
  const commander_1 = require("commander");
5
5
  const constants_1 = require("../constants");
6
6
  const command_1 = require("../helpers/command");
@@ -10,30 +10,37 @@ const tag_1 = require("../helpers/tag");
10
10
  const value_1 = require("../helpers/value");
11
11
  const types_1 = require("../types");
12
12
  const DEFAULT_MEETINGS_SEARCH_LAST_DAYS = 7;
13
- exports.searchMeetingsCommand = (0, command_1.defineToolCommand)(new commander_1.Command('search')
14
- .description('Search meetings.')
15
- .argument('[search]', 'Search term')
16
- .option('-p, --page <index>', constants_1.PAGE_OPTION_DESCRIPTION, '0')
17
- .option('--last <days>', 'Show meetings from the last N days')
18
- .option('--from <date>', constants_1.START_DATE_OPTION_DESCRIPTION)
19
- .option('--to <date>', constants_1.END_DATE_OPTION_DESCRIPTION)
20
- .option('--tags <tags>', constants_1.TAGS_OPTION_DESCRIPTION)
21
- .option('--profiles <ids>', constants_1.PROFILES_OPTION_DESCRIPTION)
22
- .option('--domains <domains>', constants_1.DOMAINS_OPTION_DESCRIPTION), types_1.ToolName.SearchMeetings, async (query, options) => ({
23
- intent: query ?? 'Listing recent meetings.',
24
- pageIndex: (0, parse_1.parseIntOption)(options.page, '--page'),
25
- searchTerm: query,
26
- startDate: (0, date_1.getStartDate)(options) ??
27
- (query
28
- ? undefined
29
- : (0, date_1.getStartDateFromDaysAgo)(DEFAULT_MEETINGS_SEARCH_LAST_DAYS)),
30
- endDate: options.to || undefined,
31
- tags: options.tags ? await (0, tag_1.resolveTagValues)(options.tags) : undefined,
32
- profiles: options.profiles
33
- ? (0, parse_1.parseNumericIds)(options.profiles, 'profile ID')
34
- : undefined,
35
- domains: options.domains ? options.domains.split(',') : undefined,
36
- }));
13
+ const createSearchMeetingsCommand = ({ canFilterByFolder, }) => {
14
+ const command = new commander_1.Command('search')
15
+ .description('Search meetings.')
16
+ .argument('[search]', 'Search term')
17
+ .option('-p, --page <index>', constants_1.PAGE_OPTION_DESCRIPTION, '0')
18
+ .option('--last <days>', 'Show meetings from the last N days')
19
+ .option('--from <date>', constants_1.START_DATE_OPTION_DESCRIPTION)
20
+ .option('--to <date>', constants_1.END_DATE_OPTION_DESCRIPTION)
21
+ .option('--tags <tags>', constants_1.TAGS_OPTION_DESCRIPTION)
22
+ .option('--profiles <ids>', constants_1.PROFILES_OPTION_DESCRIPTION)
23
+ .option('--domains <domains>', constants_1.DOMAINS_OPTION_DESCRIPTION);
24
+ return (0, command_1.defineToolCommand)(canFilterByFolder
25
+ ? command.option('--folder <id>', constants_1.FOLDER_OPTION_DESCRIPTION)
26
+ : command, types_1.ToolName.SearchMeetings, async (query, options) => ({
27
+ intent: query ?? 'Listing recent meetings.',
28
+ pageIndex: (0, parse_1.parseIntOption)(options.page, '--page'),
29
+ searchTerm: query,
30
+ startDate: (0, date_1.getStartDate)(options) ??
31
+ (query || options.folder
32
+ ? undefined
33
+ : (0, date_1.getStartDateFromDaysAgo)(DEFAULT_MEETINGS_SEARCH_LAST_DAYS)),
34
+ endDate: options.to || undefined,
35
+ tags: options.tags ? await (0, tag_1.resolveTagValues)(options.tags) : undefined,
36
+ profiles: options.profiles
37
+ ? (0, parse_1.parseNumericIds)(options.profiles, 'profile ID')
38
+ : undefined,
39
+ domains: options.domains ? options.domains.split(',') : undefined,
40
+ folderId: options.folder,
41
+ }));
42
+ };
43
+ exports.createSearchMeetingsCommand = createSearchMeetingsCommand;
37
44
  exports.readMeetingsCommand = (0, command_1.defineToolCommand)(new commander_1.Command('read')
38
45
  .description('Get detailed meeting information.')
39
46
  .argument('<ids...>', `Meeting IDs (max ${constants_1.MAX_READ_MEETING_IDENTIFIERS})`), types_1.ToolName.ReadMeetings, (ids) => {
@@ -99,19 +106,30 @@ exports.shareMeetingCommand = (0, command_1.defineToolCommand)(new commander_1.C
99
106
  ],
100
107
  };
101
108
  });
102
- exports.updateMeetingCommand = (0, command_1.defineToolCommand)(new commander_1.Command('update')
103
- .description('Update a meeting. Each option replaces the current value when provided.')
104
- .argument('<id>', 'Meeting ID')
105
- .option('--name <name>', 'Update the meeting name')
106
- .option('--notes <notes>', 'Update the meeting notes (supports Markdown)')
107
- .option('--private-notes <notes>', constants_1.PRIVATE_NOTES_UPDATE_OPTION_DESCRIPTION)
108
- .option('--tags <tags>', constants_1.TAGS_UPDATE_OPTION_DESCRIPTION), types_1.ToolName.UpdateMeeting, async (meetingId, { tags, ...fields }) => {
109
- if (!(0, value_1.isPresent)(tags) && !Object.values(fields).some(value_1.isPresent)) {
110
- throw new Error('Provide at least one field to update.');
111
- }
112
- return {
113
- meetingId,
114
- ...fields,
115
- ...((0, value_1.isPresent)(tags) && { tagIds: await (0, tag_1.resolveTagValues)(tags) }),
116
- };
117
- });
109
+ const createUpdateMeetingCommand = ({ canSetFolders, }) => {
110
+ const command = new commander_1.Command('update')
111
+ .description('Update a meeting. Each option replaces the current value when provided.')
112
+ .argument('<id>', 'Meeting ID')
113
+ .option('--name <name>', 'Update the meeting name')
114
+ .option('--notes <notes>', 'Update the meeting notes (supports Markdown)')
115
+ .option('--private-notes <notes>', constants_1.PRIVATE_NOTES_UPDATE_OPTION_DESCRIPTION)
116
+ .option('--tags <tags>', constants_1.TAGS_UPDATE_OPTION_DESCRIPTION);
117
+ return (0, command_1.defineToolCommand)(canSetFolders
118
+ ? command.option('--folders <ids>', constants_1.FOLDERS_UPDATE_OPTION_DESCRIPTION)
119
+ : command, types_1.ToolName.UpdateMeeting, async (meetingId, { tags, folders, ...fields }) => {
120
+ if (!(0, value_1.isPresent)(tags) &&
121
+ !(0, value_1.isPresent)(folders) &&
122
+ !Object.values(fields).some(value_1.isPresent)) {
123
+ throw new Error('Provide at least one field to update.');
124
+ }
125
+ return {
126
+ meetingId,
127
+ ...fields,
128
+ ...((0, value_1.isPresent)(tags) && { tagIds: await (0, tag_1.resolveTagValues)(tags) }),
129
+ ...((0, value_1.isPresent)(folders) && {
130
+ folderIds: folders.split(',').filter(Boolean),
131
+ }),
132
+ };
133
+ });
134
+ };
135
+ exports.createUpdateMeetingCommand = createUpdateMeetingCommand;
@@ -7,6 +7,7 @@ const auth_1 = require("./auth");
7
7
  const calendar_1 = require("./calendar");
8
8
  const companies_1 = require("./companies");
9
9
  const emails_1 = require("./emails");
10
+ const folders_1 = require("./folders");
10
11
  const meetings_1 = require("./meetings");
11
12
  const profiles_1 = require("./profiles");
12
13
  const support_1 = require("./support");
@@ -14,15 +15,31 @@ const tags_1 = require("./tags");
14
15
  const teams_1 = require("./teams");
15
16
  const transcripts_1 = require("./transcripts");
16
17
  const update_1 = require("./update");
18
+ const command_1 = require("../helpers/command");
19
+ const toolList_1 = require("../helpers/toolList");
20
+ const value_1 = require("../helpers/value");
21
+ const types_1 = require("../types");
17
22
  const standaloneCommands = [auth_1.authCommand, update_1.updateCommand];
18
- const commandGroups = [
23
+ const getCommandGroups = (toolList) => [
19
24
  {
20
25
  name: 'meetings',
21
26
  description: 'Find, read, update, and share meetings.',
22
27
  subcommands: [
23
- meetings_1.searchMeetingsCommand,
28
+ (0, meetings_1.createSearchMeetingsCommand)({
29
+ canFilterByFolder: (0, toolList_1.hasToolProperty)({
30
+ toolList,
31
+ toolName: types_1.ToolName.SearchMeetings,
32
+ property: 'folderId',
33
+ }),
34
+ }),
24
35
  meetings_1.readMeetingsCommand,
25
- meetings_1.updateMeetingCommand,
36
+ (0, meetings_1.createUpdateMeetingCommand)({
37
+ canSetFolders: (0, toolList_1.hasToolProperty)({
38
+ toolList,
39
+ toolName: types_1.ToolName.UpdateMeeting,
40
+ property: 'folderIds',
41
+ }),
42
+ }),
26
43
  meetings_1.shareMeetingCommand,
27
44
  ],
28
45
  },
@@ -61,6 +78,18 @@ const commandGroups = [
61
78
  description: 'List your workspace and teams.',
62
79
  subcommands: [teams_1.listTeamsCommand],
63
80
  },
81
+ {
82
+ name: 'folders',
83
+ description: 'List, manage, and share folders.',
84
+ subcommands: [
85
+ folders_1.listFoldersCommand,
86
+ folders_1.readFoldersCommand,
87
+ folders_1.createFolderCommand,
88
+ folders_1.updateFolderCommand,
89
+ folders_1.deleteFolderCommand,
90
+ folders_1.shareFolderCommand,
91
+ ],
92
+ },
64
93
  {
65
94
  name: 'action-items',
66
95
  description: 'Search, create, update, and delete action items.',
@@ -83,8 +112,16 @@ const commandGroups = [
83
112
  },
84
113
  ];
85
114
  const buildCommandGroup = (definition) => definition.subcommands.reduce((group, command, index) => group.addCommand(command, index === 0 ? { isDefault: true } : undefined), new commander_1.Command(definition.name).description(definition.description));
86
- const getAllCommands = () => [
115
+ const getAllCommands = (toolList) => [
87
116
  ...standaloneCommands,
88
- ...commandGroups.map(buildCommandGroup),
117
+ ...(0, value_1.filterMap)(getCommandGroups(toolList), (group) => {
118
+ const subcommands = group.subcommands.filter((command) => {
119
+ const toolName = (0, command_1.getCommandToolName)(command);
120
+ return (!(0, value_1.isPresent)(toolName) || !toolList || Object.hasOwn(toolList, toolName));
121
+ });
122
+ return subcommands.length > 0
123
+ ? buildCommandGroup({ ...group, subcommands })
124
+ : undefined;
125
+ }),
89
126
  ];
90
127
  exports.getAllCommands = getAllCommands;
@@ -4,37 +4,25 @@ exports.deleteTagCommand = exports.updateTagCommand = exports.createTagCommand =
4
4
  const commander_1 = require("commander");
5
5
  const command_1 = require("../helpers/command");
6
6
  const parse_1 = require("../helpers/parse");
7
+ const tag_1 = require("../helpers/tag");
7
8
  const value_1 = require("../helpers/value");
8
9
  const types_1 = require("../types");
9
- const createColorOption = () => new commander_1.Option('--color <color>', 'Set the display color').choices([
10
- 'neutral',
11
- 'red',
12
- 'rose',
13
- 'orange',
14
- 'amber',
15
- 'emerald',
16
- 'sky',
17
- 'blue',
18
- 'indigo',
19
- 'purple',
20
- ]);
21
- const getTagColor = (color) => color ? `bg-tag-${color}` : undefined;
22
10
  exports.listTagsCommand = (0, command_1.defineToolCommand)(new commander_1.Command('list').description('List all tags.'), types_1.ToolName.ListTags, () => ({ intent: 'Listing all tags.' }));
23
11
  exports.createTagCommand = (0, command_1.defineToolCommand)(new commander_1.Command('create')
24
12
  .description('Create a tag.')
25
13
  .argument('<name>', 'Tag name')
26
14
  .option('--description <description>', 'Set the description')
27
- .addOption(createColorOption()), types_1.ToolName.CreateTag, (name, options) => ({
15
+ .addOption((0, tag_1.createColorOption)()), types_1.ToolName.CreateTag, (name, options) => ({
28
16
  name,
29
17
  description: options.description,
30
- color: getTagColor(options.color),
18
+ color: (0, tag_1.getTagColor)(options.color),
31
19
  }));
32
20
  exports.updateTagCommand = (0, command_1.defineToolCommand)(new commander_1.Command('update')
33
21
  .description('Update a tag.')
34
22
  .argument('<id>', 'Tag ID')
35
23
  .option('--name <name>', 'Set the name')
36
24
  .option('--description <description>', 'Set the description')
37
- .addOption(createColorOption()), types_1.ToolName.UpdateTag, (identifier, options) => {
25
+ .addOption((0, tag_1.createColorOption)()), types_1.ToolName.UpdateTag, (identifier, options) => {
38
26
  if (!Object.values(options).some(value_1.isPresent)) {
39
27
  throw new Error('Provide at least one field to update.');
40
28
  }
@@ -42,7 +30,7 @@ exports.updateTagCommand = (0, command_1.defineToolCommand)(new commander_1.Comm
42
30
  tagId: (0, parse_1.parseIntOption)(identifier, 'id'),
43
31
  name: options.name,
44
32
  description: options.description,
45
- color: getTagColor(options.color),
33
+ color: (0, tag_1.getTagColor)(options.color),
46
34
  };
47
35
  });
48
36
  exports.deleteTagCommand = (0, command_1.defineToolCommand)(new commander_1.Command('delete').description('Delete a tag.').argument('<id>', 'Tag ID'), types_1.ToolName.DeleteTag, (identifier) => ({ tagId: (0, parse_1.parseIntOption)(identifier, 'id') }));
package/dist/constants.js CHANGED
@@ -3,7 +3,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
3
3
  return (mod && mod.__esModule) ? mod : { "default": mod };
4
4
  };
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
- exports.DOMAINS_OPTION_DESCRIPTION = exports.PROFILES_OPTION_DESCRIPTION = exports.PRIVATE_NOTES_UPDATE_OPTION_DESCRIPTION = exports.TAGS_UPDATE_OPTION_DESCRIPTION = exports.TAGS_OPTION_DESCRIPTION = exports.END_DATE_OPTION_DESCRIPTION = exports.START_DATE_OPTION_DESCRIPTION = exports.PAGE_OPTION_DESCRIPTION = exports.UNASSIGNED_ACTION_ITEM_ASSIGNEE_LABEL = exports.DEFAULT_MEETING_NAME = exports.MAX_READ_MEETING_IDENTIFIERS = exports.CALLBACK_TIMEOUT_MILLISECONDS = exports.OAUTH_SCOPE = exports.TOKENS_FILE = exports.CONFIG_DIRECTORY = exports.ASCII_LOGO = exports.SECONDARY_COLOR = exports.BRAND_COLOR = exports.API_KEY_SETTINGS_URL = exports.API_KEY_ENVIRONMENT_VARIABLE = exports.API_KEY_PREFIX = exports.CLIENT_VERSION_HEADER = exports.CLIENT_VERSION = exports.CLIENT_PACKAGE_NAME = exports.CLIENT_NAME = exports.BASE_URL = void 0;
6
+ exports.FOLDERS_UPDATE_OPTION_DESCRIPTION = exports.FOLDER_OPTION_DESCRIPTION = exports.DOMAINS_OPTION_DESCRIPTION = exports.PROFILES_OPTION_DESCRIPTION = exports.PRIVATE_NOTES_UPDATE_OPTION_DESCRIPTION = exports.TAGS_UPDATE_OPTION_DESCRIPTION = exports.TAGS_OPTION_DESCRIPTION = exports.END_DATE_OPTION_DESCRIPTION = exports.START_DATE_OPTION_DESCRIPTION = exports.PAGE_OPTION_DESCRIPTION = exports.UNASSIGNED_ACTION_ITEM_ASSIGNEE_LABEL = exports.DEFAULT_MEETING_NAME = exports.MAX_READ_MEETING_IDENTIFIERS = exports.CALLBACK_TIMEOUT_MILLISECONDS = exports.OAUTH_SCOPE = exports.TOKENS_FILE = exports.CONFIG_DIRECTORY = exports.ASCII_LOGO = exports.SECONDARY_COLOR = exports.BRAND_COLOR = exports.API_KEY_SETTINGS_URL = exports.API_KEY_ENVIRONMENT_VARIABLE = exports.API_KEY_PREFIX = exports.CLIENT_VERSION_HEADER = exports.CLIENT_VERSION = exports.CLIENT_PACKAGE_NAME = exports.CLIENT_NAME = exports.BASE_URL = void 0;
7
7
  const node_fs_1 = __importDefault(require("node:fs"));
8
8
  const node_path_1 = __importDefault(require("node:path"));
9
9
  const node_os_1 = __importDefault(require("node:os"));
@@ -56,3 +56,5 @@ exports.TAGS_UPDATE_OPTION_DESCRIPTION = 'Update the tags (comma-separated names
56
56
  exports.PRIVATE_NOTES_UPDATE_OPTION_DESCRIPTION = 'Update your private notes (supports Markdown)';
57
57
  exports.PROFILES_OPTION_DESCRIPTION = 'Comma-separated profile IDs';
58
58
  exports.DOMAINS_OPTION_DESCRIPTION = 'Comma-separated domains';
59
+ exports.FOLDER_OPTION_DESCRIPTION = 'Folder ID';
60
+ exports.FOLDERS_UPDATE_OPTION_DESCRIPTION = 'Update the folders (comma-separated IDs, or "" to remove all)';
@@ -1,19 +1,25 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.defineToolCommand = void 0;
3
+ exports.defineToolCommand = exports.getCommandToolName = void 0;
4
4
  const jsonRpc_1 = require("../client/jsonRpc");
5
5
  const error_1 = require("./error");
6
6
  const formatter_1 = require("./formatter");
7
7
  const output_1 = require("./output");
8
- const defineToolCommand = (command, toolName, getArguments) => command.action(async (...args) => {
9
- try {
10
- const result = await (0, jsonRpc_1.callTool)(toolName, await getArguments(...args));
11
- (0, formatter_1.formatOutput)(toolName, result, Boolean(command.optsWithGlobals().json));
12
- }
13
- catch (error) {
14
- const message = error instanceof Error ? error.message : `${toolName} failed.`;
15
- (0, output_1.printText)((0, error_1.formatMcpError)(message) ?? message, output_1.TextType.Error);
16
- process.exit(1);
17
- }
18
- });
8
+ const commandToolNames = new WeakMap();
9
+ const getCommandToolName = (command) => commandToolNames.get(command);
10
+ exports.getCommandToolName = getCommandToolName;
11
+ const defineToolCommand = (command, toolName, getArguments) => {
12
+ commandToolNames.set(command, toolName);
13
+ return command.action(async (...args) => {
14
+ try {
15
+ const result = await (0, jsonRpc_1.callTool)(toolName, await getArguments(...args));
16
+ (0, formatter_1.formatOutput)(toolName, result, Boolean(command.optsWithGlobals().json));
17
+ }
18
+ catch (error) {
19
+ const message = error instanceof Error ? error.message : `${toolName} failed.`;
20
+ (0, output_1.printText)((0, error_1.formatMcpError)(message) ?? message, output_1.TextType.Error);
21
+ process.exit(1);
22
+ }
23
+ });
24
+ };
19
25
  exports.defineToolCommand = defineToolCommand;
@@ -27,20 +27,20 @@ const formatTagChange = (verb, data) => {
27
27
  const { id, name } = result.data;
28
28
  return `${verb} tag ${id}: ${name}`;
29
29
  };
30
- const MeetingShareChangeSchema = zod_1.z.object({
30
+ const ShareChangeSchema = zod_1.z.object({
31
31
  id: zod_1.z.string(),
32
32
  name: zod_1.z.string().nullable(),
33
33
  errors: zod_1.z
34
34
  .array(zod_1.z.object({ index: zod_1.z.number(), error: zod_1.z.string() }))
35
35
  .optional(),
36
36
  });
37
- const formatMeetingShareChange = (data) => {
38
- const result = MeetingShareChangeSchema.safeParse(data);
37
+ const formatShareChange = (kind, data) => {
38
+ const result = ShareChangeSchema.safeParse(data);
39
39
  if (!result.success)
40
40
  return;
41
41
  const { id, name, errors = [] } = result.data;
42
42
  return [
43
- `Updated sharing for meeting ${id}${name ? `: ${name}` : ''}`,
43
+ `Updated sharing for ${kind} ${id}${name ? `: ${name}` : ''}`,
44
44
  ...errors.map(({ index, error }) => `Could not share target ${index + 1}: ${error}`),
45
45
  ].join('\n');
46
46
  };
@@ -59,7 +59,9 @@ const formatForTool = (toolName, data) => {
59
59
  case types_1.ToolName.DeleteTag:
60
60
  return formatTagChange('Deleted', data);
61
61
  case types_1.ToolName.ShareMeeting:
62
- return formatMeetingShareChange(data);
62
+ return formatShareChange('meeting', data);
63
+ case types_1.ToolName.ShareFolder:
64
+ return formatShareChange('folder', data);
63
65
  }
64
66
  if (!Array.isArray(data))
65
67
  return;
@@ -87,6 +89,11 @@ const formatForTool = (toolName, data) => {
87
89
  case types_1.ToolName.ListTags:
88
90
  return (0, table_1.formatTags)(data);
89
91
  case types_1.ToolName.ListTeams:
92
+ case types_1.ToolName.ListFolders:
93
+ case types_1.ToolName.ReadFolders:
94
+ case types_1.ToolName.CreateFolder:
95
+ case types_1.ToolName.UpdateFolder:
96
+ case types_1.ToolName.DeleteFolder:
90
97
  case types_1.ToolName.UpdateMeeting:
91
98
  case types_1.ToolName.UpdateCalendarEvent:
92
99
  return;
@@ -98,6 +105,10 @@ const formatForTool = (toolName, data) => {
98
105
  };
99
106
  const formatOutput = (toolName, rawText, jsonMode) => {
100
107
  const parsed = (0, parse_1.extractAndValidateObjectFromString)(rawText, zod_1.z.json());
108
+ const isPartialShare = (toolName === types_1.ToolName.ShareMeeting || toolName === types_1.ToolName.ShareFolder) &&
109
+ (ShareChangeSchema.safeParse(parsed).data?.errors?.length ?? 0) > 0;
110
+ if (isPartialShare)
111
+ process.exitCode = 1;
101
112
  if (jsonMode) {
102
113
  (0, output_1.printText)(stringify(parsed), output_1.TextType.Default);
103
114
  return;
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.validateReadMeetingIdentifierLimit = exports.validateMeetingIdentifiers = exports.parseNumericIds = exports.parseOptionalIntOption = exports.parseIntOption = exports.extractAndValidateObjectFromString = void 0;
3
+ exports.validateReadMeetingIdentifierLimit = exports.validateMeetingIdentifiers = exports.parseNumericIds = exports.parseOptionalIntOption = exports.parseJsonOption = exports.parseIntOption = exports.extractAndValidateObjectFromString = void 0;
4
4
  const zod_1 = require("zod");
5
5
  const constants_1 = require("../constants");
6
6
  const output_1 = require("./output");
@@ -29,6 +29,16 @@ const parseIntOption = (value, flagName) => {
29
29
  return result.data;
30
30
  };
31
31
  exports.parseIntOption = parseIntOption;
32
+ const parseJsonOption = (value, flagName) => {
33
+ try {
34
+ return JSON.parse(value);
35
+ }
36
+ catch {
37
+ (0, output_1.printText)(`Invalid JSON for ${flagName}.`, output_1.TextType.Error);
38
+ process.exit(1);
39
+ }
40
+ };
41
+ exports.parseJsonOption = parseJsonOption;
32
42
  const parseOptionalIntOption = (value, flagName) => (value ? (0, exports.parseIntOption)(value, flagName) : undefined);
33
43
  exports.parseOptionalIntOption = parseOptionalIntOption;
34
44
  const parseNumericIds = (value, label) => {
@@ -1,11 +1,28 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.resolveTagValues = void 0;
3
+ exports.resolveTagValues = exports.getTagColor = exports.createColorOption = exports.TAG_COLOR_NAMES = void 0;
4
+ const commander_1 = require("commander");
4
5
  const zod_1 = require("zod");
5
6
  const jsonRpc_1 = require("../client/jsonRpc");
6
7
  const output_1 = require("./output");
7
8
  const parse_1 = require("./parse");
8
9
  const types_1 = require("../types");
10
+ exports.TAG_COLOR_NAMES = [
11
+ 'neutral',
12
+ 'red',
13
+ 'rose',
14
+ 'orange',
15
+ 'amber',
16
+ 'emerald',
17
+ 'sky',
18
+ 'blue',
19
+ 'indigo',
20
+ 'purple',
21
+ ];
22
+ const createColorOption = () => new commander_1.Option('--color <color>', 'Set the display color').choices(exports.TAG_COLOR_NAMES);
23
+ exports.createColorOption = createColorOption;
24
+ const getTagColor = (color) => color ? `bg-tag-${color}` : undefined;
25
+ exports.getTagColor = getTagColor;
9
26
  const tagItemSchema = zod_1.z.object({
10
27
  id: zod_1.z.number(),
11
28
  name: zod_1.z.string(),
@@ -0,0 +1,44 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.hasToolProperty = exports.refreshToolList = exports.readCachedToolList = void 0;
7
+ const node_fs_1 = __importDefault(require("node:fs"));
8
+ const node_path_1 = __importDefault(require("node:path"));
9
+ const credentials_1 = require("../auth/credentials");
10
+ const jsonRpc_1 = require("../client/jsonRpc");
11
+ const constants_1 = require("../constants");
12
+ const types_1 = require("../types");
13
+ const CACHE_FILE = node_path_1.default.join(constants_1.CONFIG_DIRECTORY, 'tool-list.json');
14
+ const REFRESH_INTERVAL_MILLISECONDS = 60 * 60 * 1000; // 1 hour
15
+ const readCachedToolList = () => {
16
+ try {
17
+ const { tools, checkedAt, credential } = types_1.ToolListCacheSchema.parse(JSON.parse(node_fs_1.default.readFileSync(CACHE_FILE, 'utf-8')));
18
+ if (credential !== (0, credentials_1.getCredentialFingerprint)())
19
+ return { isStale: true };
20
+ return {
21
+ toolList: tools,
22
+ isStale: Date.now() - checkedAt >= REFRESH_INTERVAL_MILLISECONDS,
23
+ };
24
+ }
25
+ catch {
26
+ return { isStale: true };
27
+ }
28
+ };
29
+ exports.readCachedToolList = readCachedToolList;
30
+ const refreshToolList = async () => {
31
+ try {
32
+ const credential = (0, credentials_1.getCredentialFingerprint)();
33
+ const tools = await (0, jsonRpc_1.listTools)();
34
+ node_fs_1.default.mkdirSync(constants_1.CONFIG_DIRECTORY, { recursive: true, mode: 0o700 });
35
+ node_fs_1.default.writeFileSync(CACHE_FILE, JSON.stringify({ tools, checkedAt: Date.now(), credential }), { mode: 0o600 });
36
+ return tools;
37
+ }
38
+ catch {
39
+ return;
40
+ }
41
+ };
42
+ exports.refreshToolList = refreshToolList;
43
+ const hasToolProperty = ({ toolList, toolName, property, }) => !toolList || toolList[toolName]?.includes(property) === true;
44
+ exports.hasToolProperty = hasToolProperty;
@@ -1,5 +1,10 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.isPresent = void 0;
3
+ exports.filterMap = exports.isPresent = void 0;
4
4
  const isPresent = (value) => value !== null && value !== undefined;
5
5
  exports.isPresent = isPresent;
6
+ const filterMap = (array, mappingFunction) => array.flatMap((value, index) => {
7
+ const mapped = mappingFunction(value, index);
8
+ return (0, exports.isPresent)(mapped) ? [mapped] : [];
9
+ });
10
+ exports.filterMap = filterMap;
package/dist/index.js CHANGED
@@ -8,9 +8,16 @@ const constants_1 = require("./constants");
8
8
  const help_1 = require("./helpers/help");
9
9
  const output_1 = require("./helpers/output");
10
10
  const style_1 = require("./helpers/style");
11
+ const toolList_1 = require("./helpers/toolList");
11
12
  const update_1 = require("./helpers/update");
13
+ const value_1 = require("./helpers/value");
12
14
  const program = new commander_1.Command();
13
15
  const updateCheck = (0, update_1.getUpdateCheckResult)(constants_1.CLIENT_PACKAGE_NAME);
16
+ const isRootHelp = process.argv
17
+ .slice(2)
18
+ .every((argument) => ['--help', '-h', '--json', 'help', '--'].includes(argument));
19
+ const cachedToolList = (0, toolList_1.readCachedToolList)();
20
+ const toolListRefresh = isRootHelp || cachedToolList.isStale ? (0, toolList_1.refreshToolList)() : undefined;
14
21
  const configureCommandOutput = (command) => {
15
22
  command.helpOption('-h, --help', 'Display help for command');
16
23
  if (command.commands.length > 0) {
@@ -28,8 +35,6 @@ program
28
35
  .version(constants_1.CLIENT_VERSION, '-V, --version', 'Output the version number')
29
36
  .option('--json', 'Output raw JSON instead of formatted text')
30
37
  .exitOverride();
31
- (0, registry_1.getAllCommands)().reduce((p, command) => p.addCommand(command), program);
32
- configureCommandOutput(program);
33
38
  program.hook('postAction', async (_thisCommand, actionCommand) => {
34
39
  if (actionCommand.name() === 'update')
35
40
  return;
@@ -39,11 +44,13 @@ program.hook('postAction', async (_thisCommand, actionCommand) => {
39
44
  catch { }
40
45
  });
41
46
  const run = async () => {
42
- const isRootHelp = process.argv
43
- .slice(2)
44
- .every((argument) => ['--help', '-h', '--json', 'help', '--'].includes(argument));
45
- if (isRootHelp) {
46
- const loginStatus = await (0, credentials_1.getLoginStatus)();
47
+ const [loginStatus, refreshedToolList] = await Promise.all([
48
+ isRootHelp ? (0, credentials_1.getLoginStatus)() : undefined,
49
+ toolListRefresh,
50
+ ]);
51
+ (0, registry_1.getAllCommands)(refreshedToolList ?? cachedToolList.toolList).reduce((p, command) => p.addCommand(command), program);
52
+ configureCommandOutput(program);
53
+ if ((0, value_1.isPresent)(loginStatus)) {
47
54
  program
48
55
  .addHelpText('before', () => (0, style_1.formatWelcomeBanner)(process.stdout.columns ?? 80, loginStatus))
49
56
  .addHelpText('before', [
package/dist/types.js CHANGED
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.isJsonRpcResponse = exports.jsonRpcResultSchema = exports.isOAuthTokenResponse = exports.isStoredApiKey = exports.parseStoredCredentials = exports.ShareableMeetingAccess = exports.ActionItemStatus = exports.ToolName = exports.CredentialSource = exports.CredentialType = void 0;
3
+ exports.isJsonRpcResponse = exports.jsonRpcResultSchema = exports.isOAuthTokenResponse = exports.isStoredApiKey = exports.parseStoredCredentials = exports.ShareableMeetingAccess = exports.ActionItemStatus = exports.ToolName = exports.ToolListCacheSchema = exports.ToolListResponseSchema = exports.CredentialSource = exports.CredentialType = void 0;
4
4
  const zod_1 = require("zod");
5
5
  var CredentialType;
6
6
  (function (CredentialType) {
@@ -12,6 +12,21 @@ var CredentialSource;
12
12
  CredentialSource["Environment"] = "environment";
13
13
  CredentialSource["Stored"] = "stored";
14
14
  })(CredentialSource || (exports.CredentialSource = CredentialSource = {}));
15
+ exports.ToolListResponseSchema = zod_1.z.object({
16
+ result: zod_1.z.object({
17
+ tools: zod_1.z.array(zod_1.z.object({
18
+ name: zod_1.z.string(),
19
+ inputSchema: zod_1.z.object({
20
+ properties: zod_1.z.record(zod_1.z.string(), zod_1.z.unknown()).optional(),
21
+ }),
22
+ })),
23
+ }),
24
+ });
25
+ exports.ToolListCacheSchema = zod_1.z.object({
26
+ tools: zod_1.z.record(zod_1.z.string(), zod_1.z.array(zod_1.z.string())),
27
+ checkedAt: zod_1.z.number(),
28
+ credential: zod_1.z.string().optional(),
29
+ });
15
30
  var ToolName;
16
31
  (function (ToolName) {
17
32
  ToolName["SearchMeetings"] = "SearchMeetings";
@@ -26,12 +41,18 @@ var ToolName;
26
41
  ToolName["SearchActionItems"] = "SearchActionItems";
27
42
  ToolName["ListTags"] = "ListTags";
28
43
  ToolName["ListTeams"] = "ListTeams";
44
+ ToolName["ListFolders"] = "ListFolders";
45
+ ToolName["ReadFolders"] = "ReadFolders";
29
46
  ToolName["CreateActionItem"] = "CreateActionItem";
30
47
  ToolName["UpdateActionItem"] = "UpdateActionItem";
31
48
  ToolName["DeleteActionItem"] = "DeleteActionItem";
32
49
  ToolName["CreateTag"] = "CreateTag";
33
50
  ToolName["UpdateTag"] = "UpdateTag";
34
51
  ToolName["DeleteTag"] = "DeleteTag";
52
+ ToolName["CreateFolder"] = "CreateFolder";
53
+ ToolName["UpdateFolder"] = "UpdateFolder";
54
+ ToolName["DeleteFolder"] = "DeleteFolder";
55
+ ToolName["ShareFolder"] = "ShareFolder";
35
56
  ToolName["ShareMeeting"] = "ShareMeeting";
36
57
  ToolName["UpdateMeeting"] = "UpdateMeeting";
37
58
  ToolName["UpdateCalendarEvent"] = "UpdateCalendarEvent";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@circleback/cli",
3
- "version": "1.1.1",
3
+ "version": "1.2.0",
4
4
  "description": "Circleback CLI. Search and access meetings, emails, calendar events, and more.",
5
5
  "license": "MIT",
6
6
  "author": "Circleback <support@circleback.ai> (https://circleback.ai)",