@circleback/cli 0.4.1 → 0.5.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 +27 -17
- package/dist/client/jsonRpc.js +4 -2
- package/dist/commands/actionItems.js +32 -1
- package/dist/commands/registry.js +7 -2
- package/dist/constants.js +1 -1
- package/dist/helpers/formatter.js +20 -0
- package/dist/types.js +9 -1
- package/package.json +1 -1
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.
|
|
3
|
+
Search and access your meetings, transcripts, emails, calendar events, and more from the terminal, and manage your action items.
|
|
4
4
|
|
|
5
5
|
## Installation
|
|
6
6
|
|
|
@@ -31,27 +31,35 @@ cb transcripts "pricing discussion"
|
|
|
31
31
|
# Search emails
|
|
32
32
|
cb emails "from:alice@example.com after:2026-01-01"
|
|
33
33
|
|
|
34
|
+
# Mark an action item done
|
|
35
|
+
cb action-items update 123 --status DONE
|
|
36
|
+
|
|
34
37
|
# Get raw JSON for scripting
|
|
35
38
|
cb meetings --json
|
|
36
39
|
```
|
|
37
40
|
|
|
38
41
|
## Commands
|
|
39
42
|
|
|
40
|
-
| Command
|
|
41
|
-
|
|
|
42
|
-
| `cb auth login`
|
|
43
|
-
| `cb auth login --api-key`
|
|
44
|
-
| `cb auth logout`
|
|
45
|
-
| `cb update`
|
|
46
|
-
| `cb meetings [search]`
|
|
47
|
-
| `cb meetings read <ids...>`
|
|
48
|
-
| `cb transcripts <search>`
|
|
49
|
-
| `cb transcripts read <ids...>`
|
|
50
|
-
| `cb calendar`
|
|
51
|
-
| `cb people <names...>`
|
|
52
|
-
| `cb companies <terms...>`
|
|
53
|
-
| `cb emails [search]`
|
|
54
|
-
| `cb support [search]`
|
|
43
|
+
| Command | Description |
|
|
44
|
+
| -------------------------------- | --------------------------------------------------------------- |
|
|
45
|
+
| `cb auth login` | Log in to Circleback with your browser |
|
|
46
|
+
| `cb auth login --api-key` | Log in with an API key |
|
|
47
|
+
| `cb auth logout` | Sign out on this device |
|
|
48
|
+
| `cb update` | Update CLI to the latest version |
|
|
49
|
+
| `cb meetings [search]` | Search meetings |
|
|
50
|
+
| `cb meetings read <ids...>` | Read detailed meeting info, notes, and action items (max 50) |
|
|
51
|
+
| `cb transcripts <search>` | Search transcript content |
|
|
52
|
+
| `cb transcripts read <ids...>` | Read full transcripts (max 50) |
|
|
53
|
+
| `cb calendar` | Search calendar events |
|
|
54
|
+
| `cb people <names...>` | Search people by name |
|
|
55
|
+
| `cb companies <terms...>` | Search companies by name or domain |
|
|
56
|
+
| `cb emails [search]` | Search connected email accounts |
|
|
57
|
+
| `cb support [search]` | Search Circleback support articles |
|
|
58
|
+
| `cb action-items [search]` | Search action items |
|
|
59
|
+
| `cb action-items create <title>` | Create an action item |
|
|
60
|
+
| `cb action-items update <id>` | Update an action item's title, description, status, or assignee |
|
|
61
|
+
| `cb action-items delete <id>` | Delete an action item |
|
|
62
|
+
| `cb tags` | List tags |
|
|
55
63
|
|
|
56
64
|
Run `cb --help` or `cb <command> --help` for full usage details.
|
|
57
65
|
|
|
@@ -102,6 +110,8 @@ For stateless automation, set `CIRCLEBACK_API_KEY` instead of logging in:
|
|
|
102
110
|
CIRCLEBACK_API_KEY=cb_your_api_key cb meetings --json
|
|
103
111
|
```
|
|
104
112
|
|
|
113
|
+
Creating, updating, and deleting action items needs write access. Browser logins from before v0.5.0 only granted read access, so run `cb auth login` again; read-only API keys can't make changes.
|
|
114
|
+
|
|
105
115
|
`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.
|
|
106
116
|
|
|
107
117
|
## Agents
|
|
@@ -117,4 +127,4 @@ The CLI is designed to work well with AI agents and tool-use systems:
|
|
|
117
127
|
## Links
|
|
118
128
|
|
|
119
129
|
- [Circleback](https://circleback.ai)
|
|
120
|
-
- [Support](https://
|
|
130
|
+
- [Support](https://circleback.ai/docs/support)
|
package/dist/client/jsonRpc.js
CHANGED
|
@@ -25,6 +25,7 @@ const extractErrorMessage = async (response) => {
|
|
|
25
25
|
return text;
|
|
26
26
|
}
|
|
27
27
|
};
|
|
28
|
+
const WRITE_ACCESS_HINT = 'Run `circleback auth login` again or use a write-enabled API key.';
|
|
28
29
|
const HTTP_ERROR_MESSAGES = {
|
|
29
30
|
401: 'Authentication expired. Run `circleback auth login` to re-authenticate.',
|
|
30
31
|
403: 'Permission denied.',
|
|
@@ -132,9 +133,10 @@ const callTool = async (toolName, toolArguments) => {
|
|
|
132
133
|
if (!response.ok) {
|
|
133
134
|
const fallback = HTTP_ERROR_MESSAGES[response.status];
|
|
134
135
|
const serverMessage = await extractErrorMessage(response);
|
|
135
|
-
|
|
136
|
+
const message = serverMessage ||
|
|
136
137
|
fallback ||
|
|
137
|
-
`Request failed with status ${response.status}
|
|
138
|
+
`Request failed with status ${response.status}.`;
|
|
139
|
+
throw new Error(response.status === 403 ? `${message} ${WRITE_ACCESS_HINT}` : message);
|
|
138
140
|
}
|
|
139
141
|
return parseResponse(response);
|
|
140
142
|
};
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.searchActionItemsCommand = void 0;
|
|
3
|
+
exports.deleteActionItemCommand = exports.updateActionItemCommand = exports.createActionItemCommand = exports.searchActionItemsCommand = void 0;
|
|
4
4
|
const commander_1 = require("commander");
|
|
5
5
|
const constants_1 = require("../constants");
|
|
6
6
|
const command_1 = require("../helpers/command");
|
|
@@ -31,3 +31,34 @@ exports.searchActionItemsCommand = (0, command_1.defineToolCommand)(new commande
|
|
|
31
31
|
tags: options.tags ? await (0, tag_1.resolveTagValues)(options.tags) : undefined,
|
|
32
32
|
assigneeProfileId: (0, parse_1.parseOptionalIntOption)(options.assignee, '--assignee'),
|
|
33
33
|
}));
|
|
34
|
+
exports.createActionItemCommand = (0, command_1.defineToolCommand)(new commander_1.Command('create')
|
|
35
|
+
.description('Create an action item.')
|
|
36
|
+
.argument('<title>', 'Action item title')
|
|
37
|
+
.option('--description <description>', 'Set the description')
|
|
38
|
+
.option('--assignee <id>', 'Assign to a profile ID'), types_1.ToolName.CreateActionItem, (title, options) => ({
|
|
39
|
+
title,
|
|
40
|
+
description: options.description,
|
|
41
|
+
assigneeProfileId: (0, parse_1.parseOptionalIntOption)(options.assignee, '--assignee'),
|
|
42
|
+
}));
|
|
43
|
+
exports.updateActionItemCommand = (0, command_1.defineToolCommand)(new commander_1.Command('update')
|
|
44
|
+
.description('Update an action item.')
|
|
45
|
+
.argument('<id>', 'Action item ID')
|
|
46
|
+
.option('--title <title>', 'Set the title')
|
|
47
|
+
.option('--description <description>', 'Set the description')
|
|
48
|
+
.addOption(new commander_1.Option('--status <status>', 'Set completion status').choices(Object.values(types_1.ActionItemStatus)))
|
|
49
|
+
.option('--assignee <id|none>', 'Set or remove the assignee'), types_1.ToolName.UpdateActionItem, (identifier, { assignee, ...fields }) => {
|
|
50
|
+
if (assignee === undefined &&
|
|
51
|
+
!Object.values(fields).some((value) => value !== undefined)) {
|
|
52
|
+
throw new Error('Provide at least one field to update.');
|
|
53
|
+
}
|
|
54
|
+
return {
|
|
55
|
+
actionItemId: (0, parse_1.parseIntOption)(identifier, 'id'),
|
|
56
|
+
...fields,
|
|
57
|
+
...(assignee !== undefined && {
|
|
58
|
+
assigneeProfileId: assignee === 'none' ? null : (0, parse_1.parseIntOption)(assignee, '--assignee'),
|
|
59
|
+
}),
|
|
60
|
+
};
|
|
61
|
+
});
|
|
62
|
+
exports.deleteActionItemCommand = (0, command_1.defineToolCommand)(new commander_1.Command('delete')
|
|
63
|
+
.description('Delete an action item.')
|
|
64
|
+
.argument('<id>', 'Action item ID'), types_1.ToolName.DeleteActionItem, (identifier) => ({ actionItemId: (0, parse_1.parseIntOption)(identifier, 'id') }));
|
|
@@ -52,8 +52,13 @@ const commandGroups = [
|
|
|
52
52
|
},
|
|
53
53
|
{
|
|
54
54
|
name: 'action-items',
|
|
55
|
-
description: 'Search action items.',
|
|
56
|
-
subcommands: [
|
|
55
|
+
description: 'Search, create, update, and delete action items.',
|
|
56
|
+
subcommands: [
|
|
57
|
+
actionItems_1.searchActionItemsCommand,
|
|
58
|
+
actionItems_1.createActionItemCommand,
|
|
59
|
+
actionItems_1.updateActionItemCommand,
|
|
60
|
+
actionItems_1.deleteActionItemCommand,
|
|
61
|
+
],
|
|
57
62
|
},
|
|
58
63
|
{
|
|
59
64
|
name: 'tags',
|
package/dist/constants.js
CHANGED
|
@@ -43,7 +43,7 @@ exports.ASCII_LOGO = `
|
|
|
43
43
|
============= +++++`;
|
|
44
44
|
exports.CONFIG_DIRECTORY = node_path_1.default.join(node_os_1.default.homedir(), '.config', 'circleback');
|
|
45
45
|
exports.TOKENS_FILE = node_path_1.default.join(exports.CONFIG_DIRECTORY, 'tokens.json');
|
|
46
|
-
exports.OAUTH_SCOPE = 'user';
|
|
46
|
+
exports.OAUTH_SCOPE = 'user user:write';
|
|
47
47
|
exports.CALLBACK_TIMEOUT_MILLISECONDS = 120_000;
|
|
48
48
|
exports.MAX_READ_MEETING_IDENTIFIERS = 50;
|
|
49
49
|
exports.DEFAULT_MEETING_NAME = 'New meeting';
|
|
@@ -7,7 +7,27 @@ const output_1 = require("./output");
|
|
|
7
7
|
const zod_1 = require("zod");
|
|
8
8
|
const types_1 = require("../types");
|
|
9
9
|
const stringify = (value) => typeof value === 'string' ? value : JSON.stringify(value, null, 2);
|
|
10
|
+
const ActionItemChangeSchema = zod_1.z.object({
|
|
11
|
+
id: zod_1.z.number(),
|
|
12
|
+
title: zod_1.z.string(),
|
|
13
|
+
status: zod_1.z.string(),
|
|
14
|
+
});
|
|
15
|
+
const formatActionItemChange = (verb, data) => {
|
|
16
|
+
const result = ActionItemChangeSchema.safeParse(data);
|
|
17
|
+
if (!result.success)
|
|
18
|
+
return;
|
|
19
|
+
const { id, title, status } = result.data;
|
|
20
|
+
return `${verb} action item ${id}: ${title} (${status})`;
|
|
21
|
+
};
|
|
10
22
|
const formatForTool = (toolName, data) => {
|
|
23
|
+
switch (toolName) {
|
|
24
|
+
case types_1.ToolName.CreateActionItem:
|
|
25
|
+
return formatActionItemChange('Created', data);
|
|
26
|
+
case types_1.ToolName.UpdateActionItem:
|
|
27
|
+
return formatActionItemChange('Updated', data);
|
|
28
|
+
case types_1.ToolName.DeleteActionItem:
|
|
29
|
+
return formatActionItemChange('Deleted', data);
|
|
30
|
+
}
|
|
11
31
|
if (!Array.isArray(data))
|
|
12
32
|
return;
|
|
13
33
|
switch (toolName) {
|
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.ToolName = exports.CredentialSource = exports.CredentialType = void 0;
|
|
3
|
+
exports.isJsonRpcResponse = exports.jsonRpcResultSchema = exports.isOAuthTokenResponse = exports.isStoredApiKey = exports.parseStoredCredentials = exports.ActionItemStatus = exports.ToolName = exports.CredentialSource = exports.CredentialType = void 0;
|
|
4
4
|
const zod_1 = require("zod");
|
|
5
5
|
var CredentialType;
|
|
6
6
|
(function (CredentialType) {
|
|
@@ -25,7 +25,15 @@ var ToolName;
|
|
|
25
25
|
ToolName["SearchEmails"] = "SearchEmails";
|
|
26
26
|
ToolName["SearchActionItems"] = "SearchActionItems";
|
|
27
27
|
ToolName["ListTags"] = "ListTags";
|
|
28
|
+
ToolName["CreateActionItem"] = "CreateActionItem";
|
|
29
|
+
ToolName["UpdateActionItem"] = "UpdateActionItem";
|
|
30
|
+
ToolName["DeleteActionItem"] = "DeleteActionItem";
|
|
28
31
|
})(ToolName || (exports.ToolName = ToolName = {}));
|
|
32
|
+
var ActionItemStatus;
|
|
33
|
+
(function (ActionItemStatus) {
|
|
34
|
+
ActionItemStatus["Pending"] = "PENDING";
|
|
35
|
+
ActionItemStatus["Done"] = "DONE";
|
|
36
|
+
})(ActionItemStatus || (exports.ActionItemStatus = ActionItemStatus = {}));
|
|
29
37
|
const storedTokensSchema = zod_1.z.object({
|
|
30
38
|
accessToken: zod_1.z.string(),
|
|
31
39
|
refreshToken: zod_1.z.string(),
|
package/package.json
CHANGED