@todoist/comms-mcp 0.0.0-stage → 11.0.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/LICENSE +21 -0
- package/README.md +208 -2
- package/dist/comms-tool.d.ts +14 -0
- package/dist/comms-tool.js +1 -0
- package/dist/index.d.ts +1324 -0
- package/dist/index.js +55 -0
- package/dist/main.d.ts +2 -0
- package/dist/main.js +24 -0
- package/dist/mcp-helpers.d.ts +17 -0
- package/dist/mcp-helpers.js +40 -0
- package/dist/mcp-server.d.ts +10 -0
- package/dist/mcp-server.js +78 -0
- package/dist/tool-registry.d.ts +3 -0
- package/dist/tool-registry.js +49 -0
- package/dist/tools/build-link.d.ts +63 -0
- package/dist/tools/build-link.js +93 -0
- package/dist/tools/channel-output.d.ts +19 -0
- package/dist/tools/channel-output.js +47 -0
- package/dist/tools/create-channel.d.ts +55 -0
- package/dist/tools/create-channel.js +44 -0
- package/dist/tools/create-conversation.d.ts +49 -0
- package/dist/tools/create-conversation.js +75 -0
- package/dist/tools/create-thread.d.ts +67 -0
- package/dist/tools/create-thread.js +126 -0
- package/dist/tools/delete-object.d.ts +44 -0
- package/dist/tools/delete-object.js +84 -0
- package/dist/tools/fetch-inbox.d.ts +91 -0
- package/dist/tools/fetch-inbox.js +227 -0
- package/dist/tools/get-groups.d.ts +62 -0
- package/dist/tools/get-groups.js +116 -0
- package/dist/tools/get-mentions.d.ts +97 -0
- package/dist/tools/get-mentions.js +126 -0
- package/dist/tools/get-users.d.ts +58 -0
- package/dist/tools/get-users.js +107 -0
- package/dist/tools/get-workspaces.d.ts +61 -0
- package/dist/tools/get-workspaces.js +120 -0
- package/dist/tools/list-channels.d.ts +47 -0
- package/dist/tools/list-channels.js +89 -0
- package/dist/tools/list-conversations.d.ts +66 -0
- package/dist/tools/list-conversations.js +212 -0
- package/dist/tools/load-conversation.d.ts +92 -0
- package/dist/tools/load-conversation.js +128 -0
- package/dist/tools/load-thread.d.ts +127 -0
- package/dist/tools/load-thread.js +175 -0
- package/dist/tools/mark-done.d.ts +111 -0
- package/dist/tools/mark-done.js +275 -0
- package/dist/tools/mark-read.d.ts +73 -0
- package/dist/tools/mark-read.js +214 -0
- package/dist/tools/react.d.ts +59 -0
- package/dist/tools/react.js +97 -0
- package/dist/tools/reply.d.ts +69 -0
- package/dist/tools/reply.js +122 -0
- package/dist/tools/search-content.d.ts +103 -0
- package/dist/tools/search-content.js +138 -0
- package/dist/tools/update-channel.d.ts +53 -0
- package/dist/tools/update-channel.js +45 -0
- package/dist/tools/update-object.d.ts +52 -0
- package/dist/tools/update-object.js +161 -0
- package/dist/tools/update-user-info.d.ts +55 -0
- package/dist/tools/update-user-info.js +270 -0
- package/dist/tools/user-info.d.ts +32 -0
- package/dist/tools/user-info.js +16 -0
- package/dist/tools/user-output.d.ts +9 -0
- package/dist/tools/user-output.js +28 -0
- package/dist/usage-tracking.d.ts +23 -0
- package/dist/usage-tracking.js +41 -0
- package/dist/utils/attachments.d.ts +24 -0
- package/dist/utils/attachments.js +57 -0
- package/dist/utils/concurrency.d.ts +20 -0
- package/dist/utils/concurrency.js +24 -0
- package/dist/utils/constants.d.ts +5 -0
- package/dist/utils/constants.js +5 -0
- package/dist/utils/degrade.d.ts +81 -0
- package/dist/utils/degrade.js +149 -0
- package/dist/utils/output-schemas.d.ts +1283 -0
- package/dist/utils/output-schemas.js +657 -0
- package/dist/utils/read-position.d.ts +21 -0
- package/dist/utils/read-position.js +37 -0
- package/dist/utils/search-results.d.ts +36 -0
- package/dist/utils/search-results.js +82 -0
- package/dist/utils/target-types.d.ts +114 -0
- package/dist/utils/target-types.js +58 -0
- package/dist/utils/test-helpers.d.ts +95 -0
- package/dist/utils/test-helpers.js +231 -0
- package/dist/utils/tool-names.d.ts +25 -0
- package/dist/utils/tool-names.js +25 -0
- package/dist/utils/url-helpers.d.ts +3 -0
- package/dist/utils/url-helpers.js +10 -0
- package/dist/utils/user-status.d.ts +8 -0
- package/dist/utils/user-status.js +33 -0
- package/dist/utils/validate-comms-token.d.ts +13 -0
- package/dist/utils/validate-comms-token.js +22 -0
- package/package.json +86 -5
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import { degradeAllWithLog, resolveUsersWithLog } from '../utils/degrade.js';
|
|
3
|
+
import { SearchContentOutputSchema } from '../utils/output-schemas.js';
|
|
4
|
+
import { toRawSearchResults, toSearchResultItems } from '../utils/search-results.js';
|
|
5
|
+
import { ToolNames } from '../utils/tool-names.js';
|
|
6
|
+
const ArgsSchema = {
|
|
7
|
+
query: z.string().min(1).describe('The search query string.'),
|
|
8
|
+
workspaceId: z.number().describe('The workspace ID to search in.'),
|
|
9
|
+
channelIds: z.array(z.string()).optional().describe('Filter by channel IDs.'),
|
|
10
|
+
authorIds: z.array(z.number()).optional().describe('Filter by author user IDs.'),
|
|
11
|
+
mentionSelf: z.boolean().optional().describe('Filter by mentions of current user.'),
|
|
12
|
+
dateFrom: z.string().optional().describe('Start date for filtering (YYYY-MM-DD).'),
|
|
13
|
+
dateTo: z.string().optional().describe('End date for filtering (YYYY-MM-DD).'),
|
|
14
|
+
limit: z
|
|
15
|
+
.number()
|
|
16
|
+
.int()
|
|
17
|
+
.min(1)
|
|
18
|
+
.max(100)
|
|
19
|
+
.optional()
|
|
20
|
+
.default(50)
|
|
21
|
+
.describe('Maximum number of results to return.'),
|
|
22
|
+
cursor: z.string().optional().describe('Cursor for pagination.'),
|
|
23
|
+
};
|
|
24
|
+
const searchContent = {
|
|
25
|
+
name: ToolNames.SEARCH_CONTENT,
|
|
26
|
+
description: 'Search across a workspace for threads, comments, and messages. Supports filtering by channels, authors, dates, and mentions.',
|
|
27
|
+
parameters: ArgsSchema,
|
|
28
|
+
outputSchema: SearchContentOutputSchema.shape,
|
|
29
|
+
annotations: { readOnlyHint: true, destructiveHint: false, idempotentHint: true },
|
|
30
|
+
async execute(args, client) {
|
|
31
|
+
const { query, workspaceId, channelIds, authorIds, mentionSelf, dateFrom, dateTo, limit, cursor, } = args;
|
|
32
|
+
// Perform global workspace search
|
|
33
|
+
const response = await client.search.search({
|
|
34
|
+
query,
|
|
35
|
+
workspaceId,
|
|
36
|
+
channelIds,
|
|
37
|
+
authorIds,
|
|
38
|
+
mentionSelf,
|
|
39
|
+
dateFrom,
|
|
40
|
+
dateTo,
|
|
41
|
+
limit,
|
|
42
|
+
cursor,
|
|
43
|
+
});
|
|
44
|
+
const results = toRawSearchResults(response.items, 'search-content');
|
|
45
|
+
const hasMore = response.hasMore;
|
|
46
|
+
const responseCursor = response.nextCursorMark;
|
|
47
|
+
// Initialize lookup maps
|
|
48
|
+
const userLookup = {};
|
|
49
|
+
let channelLookup = {};
|
|
50
|
+
// Only fetch user and channel info if there are results
|
|
51
|
+
if (results.length > 0) {
|
|
52
|
+
// Collect unique user IDs and channel IDs
|
|
53
|
+
const userIds = new Set();
|
|
54
|
+
const channelIdSet = new Set();
|
|
55
|
+
for (const result of results) {
|
|
56
|
+
userIds.add(result.creatorId);
|
|
57
|
+
if (result.type === 'thread' && result.channelId) {
|
|
58
|
+
channelIdSet.add(result.channelId);
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
// Fetch all users and channels in parallel
|
|
62
|
+
const uniqueUserIds = Array.from(userIds);
|
|
63
|
+
const uniqueChannelIds = Array.from(channelIdSet);
|
|
64
|
+
const [users, channels] = await Promise.all([
|
|
65
|
+
resolveUsersWithLog(client, ToolNames.SEARCH_CONTENT, 'failed to resolve result author', workspaceId, uniqueUserIds),
|
|
66
|
+
degradeAllWithLog(ToolNames.SEARCH_CONTENT, 'failed to resolve channel', uniqueChannelIds, (id) => client.channels.getChannel(id)),
|
|
67
|
+
]);
|
|
68
|
+
for (const [id, user] of users) {
|
|
69
|
+
userLookup[id] = user.fullName;
|
|
70
|
+
}
|
|
71
|
+
channelLookup = channels.reduce((acc, channel) => {
|
|
72
|
+
if (channel)
|
|
73
|
+
acc[channel.id] = channel.name;
|
|
74
|
+
return acc;
|
|
75
|
+
}, {});
|
|
76
|
+
}
|
|
77
|
+
// Build text content
|
|
78
|
+
const lines = [`# Search Results for "${query}"`, ''];
|
|
79
|
+
lines.push(`**Search Scope:** Workspace ${workspaceId}`);
|
|
80
|
+
lines.push(`**Results Found:** ${results.length}`);
|
|
81
|
+
lines.push(`**More Available:** ${hasMore ? 'Yes' : 'No'}`);
|
|
82
|
+
lines.push('');
|
|
83
|
+
if (results.length === 0) {
|
|
84
|
+
lines.push('_No results found_');
|
|
85
|
+
}
|
|
86
|
+
else {
|
|
87
|
+
lines.push('## Results');
|
|
88
|
+
lines.push('');
|
|
89
|
+
for (const result of results) {
|
|
90
|
+
const date = result.created.split('T')[0];
|
|
91
|
+
const typeLabel = result.type.charAt(0).toUpperCase() + result.type.slice(1);
|
|
92
|
+
const creatorName = userLookup[result.creatorId];
|
|
93
|
+
lines.push(`### ${typeLabel} ${result.id}`);
|
|
94
|
+
lines.push(`**Created:** ${date} | **Creator:** ${creatorName} (${result.creatorId})`);
|
|
95
|
+
if (result.type === 'thread') {
|
|
96
|
+
lines.push(`**Thread:** ${result.threadId}`);
|
|
97
|
+
if (result.commentId) {
|
|
98
|
+
lines.push(`**Comment:** ${result.commentId}`);
|
|
99
|
+
}
|
|
100
|
+
if (result.channelId) {
|
|
101
|
+
const channelName = channelLookup[result.channelId];
|
|
102
|
+
lines.push(`**Channel:** ${channelName} (${result.channelId})`);
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
else {
|
|
106
|
+
lines.push(`**Conversation:** ${result.conversationId}`);
|
|
107
|
+
lines.push(`**Message:** ${result.messageId}`);
|
|
108
|
+
}
|
|
109
|
+
lines.push('');
|
|
110
|
+
// Truncate long content
|
|
111
|
+
const contentPreview = result.content.length > 200
|
|
112
|
+
? `${result.content.substring(0, 200)}...`
|
|
113
|
+
: result.content;
|
|
114
|
+
lines.push(contentPreview);
|
|
115
|
+
lines.push('');
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
if (hasMore) {
|
|
119
|
+
lines.push('## Next Steps');
|
|
120
|
+
lines.push('');
|
|
121
|
+
lines.push('More results available. Use the cursor to fetch the next page.');
|
|
122
|
+
}
|
|
123
|
+
const structuredContent = {
|
|
124
|
+
type: 'search_results',
|
|
125
|
+
query,
|
|
126
|
+
workspaceId,
|
|
127
|
+
results: toSearchResultItems(results, { workspaceId, userLookup, channelLookup }),
|
|
128
|
+
totalResults: results.length,
|
|
129
|
+
hasMore,
|
|
130
|
+
cursor: responseCursor,
|
|
131
|
+
};
|
|
132
|
+
return {
|
|
133
|
+
textContent: lines.join('\n'),
|
|
134
|
+
structuredContent,
|
|
135
|
+
};
|
|
136
|
+
},
|
|
137
|
+
};
|
|
138
|
+
export { searchContent };
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
declare const updateChannel: {
|
|
3
|
+
name: "update-channel";
|
|
4
|
+
description: string;
|
|
5
|
+
parameters: {
|
|
6
|
+
channelId: z.ZodString;
|
|
7
|
+
name: z.ZodOptional<z.ZodString>;
|
|
8
|
+
description: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
|
9
|
+
public: z.ZodOptional<z.ZodBoolean>;
|
|
10
|
+
};
|
|
11
|
+
outputSchema: {
|
|
12
|
+
name: z.ZodString;
|
|
13
|
+
description: z.ZodOptional<z.ZodString>;
|
|
14
|
+
public: z.ZodBoolean;
|
|
15
|
+
archived: z.ZodBoolean;
|
|
16
|
+
created: z.ZodString;
|
|
17
|
+
channelUrl: z.ZodString;
|
|
18
|
+
type: z.ZodLiteral<"update_channel_result">;
|
|
19
|
+
success: z.ZodBoolean;
|
|
20
|
+
channelId: z.ZodString;
|
|
21
|
+
workspaceId: z.ZodNumber;
|
|
22
|
+
creator: z.ZodNumber;
|
|
23
|
+
userIds: z.ZodOptional<z.ZodArray<z.ZodNumber>>;
|
|
24
|
+
};
|
|
25
|
+
annotations: {
|
|
26
|
+
readOnlyHint: false;
|
|
27
|
+
destructiveHint: false;
|
|
28
|
+
idempotentHint: true;
|
|
29
|
+
};
|
|
30
|
+
execute(args: {
|
|
31
|
+
channelId: string;
|
|
32
|
+
name?: string | undefined;
|
|
33
|
+
description?: string | null | undefined;
|
|
34
|
+
public?: boolean | undefined;
|
|
35
|
+
}, client: import("@doist/comms-sdk").CommsApi): Promise<{
|
|
36
|
+
textContent: string;
|
|
37
|
+
structuredContent: {
|
|
38
|
+
name: string;
|
|
39
|
+
public: boolean;
|
|
40
|
+
archived: boolean;
|
|
41
|
+
created: string;
|
|
42
|
+
channelUrl: string;
|
|
43
|
+
type: "update_channel_result";
|
|
44
|
+
success: boolean;
|
|
45
|
+
channelId: string;
|
|
46
|
+
workspaceId: number;
|
|
47
|
+
creator: number;
|
|
48
|
+
description?: string | undefined;
|
|
49
|
+
userIds?: number[] | undefined;
|
|
50
|
+
};
|
|
51
|
+
}>;
|
|
52
|
+
};
|
|
53
|
+
export { updateChannel };
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import { UpdateChannelOutputSchema } from '../utils/output-schemas.js';
|
|
3
|
+
import { ToolNames } from '../utils/tool-names.js';
|
|
4
|
+
import { getChannelMutationData, getChannelMutationText } from './channel-output.js';
|
|
5
|
+
const ArgsSchema = {
|
|
6
|
+
channelId: z.string().describe('The channel ID to update.'),
|
|
7
|
+
name: z.string().min(1).optional().describe('Optional new channel name.'),
|
|
8
|
+
description: z
|
|
9
|
+
.string()
|
|
10
|
+
.nullable()
|
|
11
|
+
.optional()
|
|
12
|
+
.describe('Optional new channel description. Pass null to clear the description.'),
|
|
13
|
+
public: z.boolean().optional().describe('Optional visibility update for the channel.'),
|
|
14
|
+
};
|
|
15
|
+
const updateChannel = {
|
|
16
|
+
name: ToolNames.UPDATE_CHANNEL,
|
|
17
|
+
description: 'Update a workspace channel. Pass channelId and at least one of name, description, or public. Pass description: null to clear the description.',
|
|
18
|
+
parameters: ArgsSchema,
|
|
19
|
+
outputSchema: UpdateChannelOutputSchema.shape,
|
|
20
|
+
annotations: { readOnlyHint: false, destructiveHint: false, idempotentHint: true },
|
|
21
|
+
async execute(args, client) {
|
|
22
|
+
const { channelId, name, description, public: isPublic } = args;
|
|
23
|
+
if (name === undefined && description === undefined && isPublic === undefined) {
|
|
24
|
+
throw new Error('At least one of `name`, `description`, or `public` must be provided.');
|
|
25
|
+
}
|
|
26
|
+
const updateArgs = {
|
|
27
|
+
id: channelId,
|
|
28
|
+
...(name !== undefined ? { name } : {}),
|
|
29
|
+
...(description !== undefined ? { description } : {}),
|
|
30
|
+
...(isPublic !== undefined ? { public: isPublic } : {}),
|
|
31
|
+
};
|
|
32
|
+
// The endpoint supports partial updates, but the SDK type currently requires `name`.
|
|
33
|
+
const channel = await client.channels.updateChannel(updateArgs);
|
|
34
|
+
const structuredContent = {
|
|
35
|
+
type: 'update_channel_result',
|
|
36
|
+
success: true,
|
|
37
|
+
...getChannelMutationData(channel),
|
|
38
|
+
};
|
|
39
|
+
return {
|
|
40
|
+
textContent: getChannelMutationText('Channel Updated', channel),
|
|
41
|
+
structuredContent,
|
|
42
|
+
};
|
|
43
|
+
},
|
|
44
|
+
};
|
|
45
|
+
export { updateChannel };
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { type CommsApi } from '@doist/comms-sdk';
|
|
2
|
+
import { z } from 'zod';
|
|
3
|
+
import { type UpdateObjectStructured } from '../utils/output-schemas.js';
|
|
4
|
+
declare const updateObject: {
|
|
5
|
+
name: "update-object";
|
|
6
|
+
description: string;
|
|
7
|
+
parameters: {
|
|
8
|
+
targetType: z.ZodEnum<{
|
|
9
|
+
thread: "thread";
|
|
10
|
+
comment: "comment";
|
|
11
|
+
message: "message";
|
|
12
|
+
}>;
|
|
13
|
+
targetId: z.ZodString;
|
|
14
|
+
content: z.ZodOptional<z.ZodString>;
|
|
15
|
+
title: z.ZodOptional<z.ZodString>;
|
|
16
|
+
};
|
|
17
|
+
outputSchema: {
|
|
18
|
+
type: z.ZodEnum<{
|
|
19
|
+
update_thread_result: "update_thread_result";
|
|
20
|
+
update_comment_result: "update_comment_result";
|
|
21
|
+
update_message_result: "update_message_result";
|
|
22
|
+
}>;
|
|
23
|
+
success: z.ZodBoolean;
|
|
24
|
+
content: z.ZodString;
|
|
25
|
+
workspaceId: z.ZodNumber;
|
|
26
|
+
lastEdited: z.ZodOptional<z.ZodString>;
|
|
27
|
+
threadId: z.ZodOptional<z.ZodString>;
|
|
28
|
+
title: z.ZodOptional<z.ZodString>;
|
|
29
|
+
channelId: z.ZodOptional<z.ZodString>;
|
|
30
|
+
threadUrl: z.ZodOptional<z.ZodString>;
|
|
31
|
+
commentId: z.ZodOptional<z.ZodString>;
|
|
32
|
+
commentUrl: z.ZodOptional<z.ZodString>;
|
|
33
|
+
messageId: z.ZodOptional<z.ZodString>;
|
|
34
|
+
conversationId: z.ZodOptional<z.ZodString>;
|
|
35
|
+
messageUrl: z.ZodOptional<z.ZodString>;
|
|
36
|
+
};
|
|
37
|
+
annotations: {
|
|
38
|
+
readOnlyHint: false;
|
|
39
|
+
destructiveHint: false;
|
|
40
|
+
idempotentHint: true;
|
|
41
|
+
};
|
|
42
|
+
execute(args: {
|
|
43
|
+
targetType: "thread" | "comment" | "message";
|
|
44
|
+
targetId: string;
|
|
45
|
+
content?: string | undefined;
|
|
46
|
+
title?: string | undefined;
|
|
47
|
+
}, client: CommsApi): Promise<{
|
|
48
|
+
textContent: string;
|
|
49
|
+
structuredContent: UpdateObjectStructured;
|
|
50
|
+
}>;
|
|
51
|
+
};
|
|
52
|
+
export { updateObject };
|
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
import { getFullCommsURL } from '@doist/comms-sdk';
|
|
2
|
+
import { z } from 'zod';
|
|
3
|
+
import { UpdateObjectOutputSchema, } from '../utils/output-schemas.js';
|
|
4
|
+
import { UpdateTargetTypeSchema } from '../utils/target-types.js';
|
|
5
|
+
import { ToolNames } from '../utils/tool-names.js';
|
|
6
|
+
const ArgsSchema = {
|
|
7
|
+
targetType: UpdateTargetTypeSchema.describe('The type of object to update: thread, comment, or message.'),
|
|
8
|
+
targetId: z
|
|
9
|
+
.string()
|
|
10
|
+
.describe('The ID of the thread, comment, or conversation message to update.'),
|
|
11
|
+
content: z
|
|
12
|
+
.string()
|
|
13
|
+
.min(1)
|
|
14
|
+
.optional()
|
|
15
|
+
.describe('The new content/body. Required for comments and messages; for threads, optional if title is provided. Markdown. Mention people with the link syntax [Name](comms-mention://USER_ID) — e.g. [Afzal](comms-mention://29367677) — never @Name or [[Name|id]], which post as literal text. Do not put "@" in the label; the client adds it. Groups use [Name](comms-group-mention://GROUP_ID), channels [#name](comms-channel://CHANNEL_ID), threads [Title](comms-thread://THREAD_ID). Resolve IDs with get-users/get-groups/list-channels first. Preserve any existing mention links you are not deliberately changing — rewriting them as plain text drops the mention. Editing sends no notifications: this tool has no recipients/groups/notifyAudience, so a mention added here is rendering only.'),
|
|
16
|
+
title: z
|
|
17
|
+
.string()
|
|
18
|
+
.min(1)
|
|
19
|
+
.optional()
|
|
20
|
+
.describe('The new title. Only valid when targetType is "thread".'),
|
|
21
|
+
};
|
|
22
|
+
async function updateThreadBranch(args, client) {
|
|
23
|
+
const { targetId, title, content } = args;
|
|
24
|
+
if (title === undefined && content === undefined) {
|
|
25
|
+
throw new Error('At least one of `title` or `content` must be provided.');
|
|
26
|
+
}
|
|
27
|
+
const thread = await client.threads.updateThread({ id: targetId, title, content });
|
|
28
|
+
const threadUrl = thread.url ??
|
|
29
|
+
getFullCommsURL({
|
|
30
|
+
workspaceId: thread.workspaceId,
|
|
31
|
+
channelId: thread.channelId,
|
|
32
|
+
threadId: thread.id,
|
|
33
|
+
});
|
|
34
|
+
const lastEdited = thread.lastEdited ? thread.lastEdited.toISOString() : undefined;
|
|
35
|
+
const lines = [
|
|
36
|
+
`# Thread Updated`,
|
|
37
|
+
'',
|
|
38
|
+
`**Title:** ${thread.title}`,
|
|
39
|
+
`**Thread ID:** ${thread.id}`,
|
|
40
|
+
`**Channel ID:** ${thread.channelId}`,
|
|
41
|
+
...(lastEdited ? [`**Last Edited:** ${lastEdited}`] : []),
|
|
42
|
+
`**URL:** ${threadUrl}`,
|
|
43
|
+
'',
|
|
44
|
+
'## Content',
|
|
45
|
+
'',
|
|
46
|
+
thread.content,
|
|
47
|
+
];
|
|
48
|
+
const structuredContent = {
|
|
49
|
+
type: 'update_thread_result',
|
|
50
|
+
success: true,
|
|
51
|
+
threadId: thread.id,
|
|
52
|
+
title: thread.title,
|
|
53
|
+
channelId: thread.channelId,
|
|
54
|
+
workspaceId: thread.workspaceId,
|
|
55
|
+
content: thread.content,
|
|
56
|
+
threadUrl,
|
|
57
|
+
lastEdited,
|
|
58
|
+
};
|
|
59
|
+
return { textContent: lines.join('\n'), structuredContent };
|
|
60
|
+
}
|
|
61
|
+
async function updateCommentBranch(args, client) {
|
|
62
|
+
const { targetId, content } = args;
|
|
63
|
+
if (content === undefined) {
|
|
64
|
+
throw new Error('`content` is required when targetType is "comment".');
|
|
65
|
+
}
|
|
66
|
+
const comment = await client.comments.updateComment({ id: targetId, content });
|
|
67
|
+
const commentUrl = comment.url ??
|
|
68
|
+
getFullCommsURL({
|
|
69
|
+
workspaceId: comment.workspaceId,
|
|
70
|
+
channelId: comment.channelId,
|
|
71
|
+
threadId: comment.threadId,
|
|
72
|
+
commentId: comment.id,
|
|
73
|
+
});
|
|
74
|
+
const lastEdited = comment.lastEdited ? comment.lastEdited.toISOString() : undefined;
|
|
75
|
+
const lines = [
|
|
76
|
+
`# Comment Updated`,
|
|
77
|
+
'',
|
|
78
|
+
`**Comment ID:** ${comment.id}`,
|
|
79
|
+
`**Thread ID:** ${comment.threadId}`,
|
|
80
|
+
`**Channel ID:** ${comment.channelId}`,
|
|
81
|
+
...(lastEdited ? [`**Last Edited:** ${lastEdited}`] : []),
|
|
82
|
+
`**URL:** ${commentUrl}`,
|
|
83
|
+
'',
|
|
84
|
+
'## Content',
|
|
85
|
+
'',
|
|
86
|
+
comment.content,
|
|
87
|
+
];
|
|
88
|
+
const structuredContent = {
|
|
89
|
+
type: 'update_comment_result',
|
|
90
|
+
success: true,
|
|
91
|
+
commentId: comment.id,
|
|
92
|
+
threadId: comment.threadId,
|
|
93
|
+
channelId: comment.channelId,
|
|
94
|
+
workspaceId: comment.workspaceId,
|
|
95
|
+
content: comment.content,
|
|
96
|
+
commentUrl,
|
|
97
|
+
lastEdited,
|
|
98
|
+
};
|
|
99
|
+
return { textContent: lines.join('\n'), structuredContent };
|
|
100
|
+
}
|
|
101
|
+
async function updateMessageBranch(args, client) {
|
|
102
|
+
const { targetId, content } = args;
|
|
103
|
+
if (content === undefined) {
|
|
104
|
+
throw new Error('`content` is required when targetType is "message".');
|
|
105
|
+
}
|
|
106
|
+
const message = await client.conversationMessages.updateMessage({ id: targetId, content });
|
|
107
|
+
const messageUrl = message.url ??
|
|
108
|
+
getFullCommsURL({
|
|
109
|
+
workspaceId: message.workspaceId,
|
|
110
|
+
conversationId: message.conversationId,
|
|
111
|
+
messageId: message.id,
|
|
112
|
+
});
|
|
113
|
+
const lastEdited = message.lastEdited ? message.lastEdited.toISOString() : undefined;
|
|
114
|
+
const lines = [
|
|
115
|
+
`# Message Updated`,
|
|
116
|
+
'',
|
|
117
|
+
`**Message ID:** ${message.id}`,
|
|
118
|
+
`**Conversation ID:** ${message.conversationId}`,
|
|
119
|
+
`**Workspace ID:** ${message.workspaceId}`,
|
|
120
|
+
...(lastEdited ? [`**Last Edited:** ${lastEdited}`] : []),
|
|
121
|
+
`**URL:** ${messageUrl}`,
|
|
122
|
+
'',
|
|
123
|
+
'## Content',
|
|
124
|
+
'',
|
|
125
|
+
message.content,
|
|
126
|
+
];
|
|
127
|
+
const structuredContent = {
|
|
128
|
+
type: 'update_message_result',
|
|
129
|
+
success: true,
|
|
130
|
+
messageId: message.id,
|
|
131
|
+
conversationId: message.conversationId,
|
|
132
|
+
workspaceId: message.workspaceId,
|
|
133
|
+
content: message.content,
|
|
134
|
+
messageUrl,
|
|
135
|
+
lastEdited,
|
|
136
|
+
};
|
|
137
|
+
return { textContent: lines.join('\n'), structuredContent };
|
|
138
|
+
}
|
|
139
|
+
const updateObject = {
|
|
140
|
+
name: ToolNames.UPDATE_OBJECT,
|
|
141
|
+
description: 'Update an existing Comms object. `targetType: "thread"` updates a thread\'s title and/or body; `"comment"` updates a thread comment\'s body; `"message"` updates a direct/group conversation message\'s body. Always pass `targetId`. `content` is required for `"comment"` and `"message"`; for `"thread"` it is optional as long as `title` is provided (i.e. a thread can be renamed without re-sending the body). `title` is only valid when `targetType` is `"thread"`.',
|
|
142
|
+
parameters: ArgsSchema,
|
|
143
|
+
outputSchema: UpdateObjectOutputSchema.shape,
|
|
144
|
+
annotations: { readOnlyHint: false, destructiveHint: false, idempotentHint: true },
|
|
145
|
+
async execute(args, client) {
|
|
146
|
+
const { targetType, title } = args;
|
|
147
|
+
if (targetType !== 'thread' && title !== undefined) {
|
|
148
|
+
throw new Error('`title` is only valid when targetType is "thread".');
|
|
149
|
+
}
|
|
150
|
+
const branch = targetType === 'thread'
|
|
151
|
+
? await updateThreadBranch(args, client)
|
|
152
|
+
: targetType === 'comment'
|
|
153
|
+
? await updateCommentBranch(args, client)
|
|
154
|
+
: await updateMessageBranch(args, client);
|
|
155
|
+
return {
|
|
156
|
+
textContent: branch.textContent,
|
|
157
|
+
structuredContent: branch.structuredContent,
|
|
158
|
+
};
|
|
159
|
+
},
|
|
160
|
+
};
|
|
161
|
+
export { updateObject };
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import { type CommsApi } from '@doist/comms-sdk';
|
|
2
|
+
import { z } from 'zod';
|
|
3
|
+
declare const updateUserInfo: {
|
|
4
|
+
name: "update-user-info";
|
|
5
|
+
description: string;
|
|
6
|
+
parameters: {
|
|
7
|
+
name: z.ZodOptional<z.ZodString>;
|
|
8
|
+
timezone: z.ZodOptional<z.ZodString>;
|
|
9
|
+
lang: z.ZodOptional<z.ZodString>;
|
|
10
|
+
status: z.ZodOptional<z.ZodNullable<z.ZodObject<{
|
|
11
|
+
message: z.ZodString;
|
|
12
|
+
emoji: z.ZodOptional<z.ZodString>;
|
|
13
|
+
activeUntil: z.ZodOptional<z.ZodString>;
|
|
14
|
+
pauseNotifications: z.ZodOptional<z.ZodBoolean>;
|
|
15
|
+
pauseActivity: z.ZodOptional<z.ZodBoolean>;
|
|
16
|
+
}, z.core.$strip>>>;
|
|
17
|
+
};
|
|
18
|
+
outputSchema: {
|
|
19
|
+
type: z.ZodLiteral<"user_info">;
|
|
20
|
+
userId: z.ZodNumber;
|
|
21
|
+
name: z.ZodString;
|
|
22
|
+
shortName: z.ZodString;
|
|
23
|
+
email: z.ZodString;
|
|
24
|
+
timezone: z.ZodString;
|
|
25
|
+
lang: z.ZodString;
|
|
26
|
+
status: z.ZodOptional<z.ZodObject<{
|
|
27
|
+
message: z.ZodString;
|
|
28
|
+
emoji: z.ZodOptional<z.ZodString>;
|
|
29
|
+
activeUntil: z.ZodOptional<z.ZodString>;
|
|
30
|
+
pauseNotifications: z.ZodBoolean;
|
|
31
|
+
pauseActivity: z.ZodBoolean;
|
|
32
|
+
}, z.core.$strip>>;
|
|
33
|
+
};
|
|
34
|
+
annotations: {
|
|
35
|
+
readOnlyHint: false;
|
|
36
|
+
destructiveHint: true;
|
|
37
|
+
idempotentHint: true;
|
|
38
|
+
};
|
|
39
|
+
execute(args: {
|
|
40
|
+
name?: string | undefined;
|
|
41
|
+
timezone?: string | undefined;
|
|
42
|
+
lang?: string | undefined;
|
|
43
|
+
status?: {
|
|
44
|
+
message: string;
|
|
45
|
+
emoji?: string | undefined;
|
|
46
|
+
activeUntil?: string | undefined;
|
|
47
|
+
pauseNotifications?: boolean | undefined;
|
|
48
|
+
pauseActivity?: boolean | undefined;
|
|
49
|
+
} | null | undefined;
|
|
50
|
+
}, client: CommsApi): Promise<{
|
|
51
|
+
textContent: string;
|
|
52
|
+
structuredContent: import("./user-output.js").UserInfoStructured;
|
|
53
|
+
}>;
|
|
54
|
+
};
|
|
55
|
+
export { updateUserInfo };
|