@opentweet/mcp-server 1.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/README.md +99 -0
- package/dist/api-client.d.ts +102 -0
- package/dist/api-client.d.ts.map +1 -0
- package/dist/api-client.js +125 -0
- package/dist/api-client.js.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +44 -0
- package/dist/index.js.map +1 -0
- package/dist/prompts/index.d.ts +3 -0
- package/dist/prompts/index.d.ts.map +1 -0
- package/dist/prompts/index.js +93 -0
- package/dist/prompts/index.js.map +1 -0
- package/dist/resources/index.d.ts +4 -0
- package/dist/resources/index.d.ts.map +1 -0
- package/dist/resources/index.js +55 -0
- package/dist/resources/index.js.map +1 -0
- package/dist/tools/account.d.ts +4 -0
- package/dist/tools/account.d.ts.map +1 -0
- package/dist/tools/account.js +38 -0
- package/dist/tools/account.js.map +1 -0
- package/dist/tools/analytics.d.ts +4 -0
- package/dist/tools/analytics.d.ts.map +1 -0
- package/dist/tools/analytics.js +100 -0
- package/dist/tools/analytics.js.map +1 -0
- package/dist/tools/media.d.ts +4 -0
- package/dist/tools/media.d.ts.map +1 -0
- package/dist/tools/media.js +47 -0
- package/dist/tools/media.js.map +1 -0
- package/dist/tools/posts.d.ts +4 -0
- package/dist/tools/posts.d.ts.map +1 -0
- package/dist/tools/posts.js +194 -0
- package/dist/tools/posts.js.map +1 -0
- package/dist/tools/scheduling.d.ts +4 -0
- package/dist/tools/scheduling.d.ts.map +1 -0
- package/dist/tools/scheduling.js +52 -0
- package/dist/tools/scheduling.js.map +1 -0
- package/dist/types.d.ts +104 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +2 -0
- package/dist/types.js.map +1 -0
- package/package.json +52 -0
package/README.md
ADDED
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
# @opentweet/mcp-server
|
|
2
|
+
|
|
3
|
+
MCP server for [OpenTweet](https://opentweet.io) — manage your Twitter/X presence from Claude, Cursor, or any AI assistant.
|
|
4
|
+
|
|
5
|
+
## Quick Start
|
|
6
|
+
|
|
7
|
+
### 1. Get an API Key
|
|
8
|
+
|
|
9
|
+
Sign up at [opentweet.io](https://opentweet.io) and create an API key from the [Developer Dashboard](https://opentweet.io/developer).
|
|
10
|
+
|
|
11
|
+
### 2. Configure Your AI Client
|
|
12
|
+
|
|
13
|
+
Add to your Claude Desktop config (`~/Library/Application Support/Claude/claude_desktop_config.json`):
|
|
14
|
+
|
|
15
|
+
```json
|
|
16
|
+
{
|
|
17
|
+
"mcpServers": {
|
|
18
|
+
"opentweet": {
|
|
19
|
+
"command": "npx",
|
|
20
|
+
"args": ["-y", "@opentweet/mcp-server"],
|
|
21
|
+
"env": {
|
|
22
|
+
"OPENTWEET_API_KEY": "ot_your_key_here"
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
For **Claude Code**:
|
|
30
|
+
```bash
|
|
31
|
+
claude mcp add opentweet -- npx -y @opentweet/mcp-server
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
### 3. Start Using
|
|
35
|
+
|
|
36
|
+
Ask your AI assistant:
|
|
37
|
+
- "Schedule a tweet about React performance for tomorrow at 9am"
|
|
38
|
+
- "Show me my posting streak and analytics"
|
|
39
|
+
- "Create a 5-tweet thread about TypeScript tips"
|
|
40
|
+
- "What are my best posting times?"
|
|
41
|
+
|
|
42
|
+
## Tools
|
|
43
|
+
|
|
44
|
+
| Tool | Description |
|
|
45
|
+
|------|-------------|
|
|
46
|
+
| `opentweet_create_tweet` | Create a tweet (draft, scheduled, or publish now) |
|
|
47
|
+
| `opentweet_create_thread` | Create a multi-tweet thread (2-25 tweets) |
|
|
48
|
+
| `opentweet_list_tweets` | List tweets with status filters and pagination |
|
|
49
|
+
| `opentweet_get_tweet` | Get full details of a specific tweet |
|
|
50
|
+
| `opentweet_update_tweet` | Edit tweet text, category, schedule, or media |
|
|
51
|
+
| `opentweet_delete_tweet` | Delete a tweet |
|
|
52
|
+
| `opentweet_publish_tweet` | Publish a draft/scheduled tweet immediately to X |
|
|
53
|
+
| `opentweet_batch_schedule` | Schedule up to 50 tweets at once |
|
|
54
|
+
| `opentweet_get_analytics` | Get posting stats, streaks, trends, engagement |
|
|
55
|
+
| `opentweet_get_followers` | Get follower growth data over time |
|
|
56
|
+
| `opentweet_get_account` | Get account status, subscription, and limits |
|
|
57
|
+
| `opentweet_upload_media` | Upload images/videos for use in tweets |
|
|
58
|
+
|
|
59
|
+
## Resources
|
|
60
|
+
|
|
61
|
+
| URI | Description |
|
|
62
|
+
|-----|-------------|
|
|
63
|
+
| `opentweet://account` | Account status and limits |
|
|
64
|
+
| `opentweet://posts/scheduled` | Currently scheduled tweets |
|
|
65
|
+
| `opentweet://posts/drafts` | Draft tweets |
|
|
66
|
+
| `opentweet://analytics/summary` | Analytics overview |
|
|
67
|
+
|
|
68
|
+
## Prompts
|
|
69
|
+
|
|
70
|
+
| Name | Description |
|
|
71
|
+
|------|-------------|
|
|
72
|
+
| `weekly_content_plan` | Generate a week of tweet content |
|
|
73
|
+
| `review_and_schedule_drafts` | Review drafts and suggest scheduling |
|
|
74
|
+
| `content_from_url` | Generate tweets from a URL or topic |
|
|
75
|
+
| `performance_review` | Analyze performance and get suggestions |
|
|
76
|
+
|
|
77
|
+
## Requirements
|
|
78
|
+
|
|
79
|
+
- Node.js 18+
|
|
80
|
+
- OpenTweet account with API key ([get one here](https://opentweet.io/developer))
|
|
81
|
+
- Connected X/Twitter account in OpenTweet
|
|
82
|
+
|
|
83
|
+
## Environment Variables
|
|
84
|
+
|
|
85
|
+
| Variable | Required | Description |
|
|
86
|
+
|----------|----------|-------------|
|
|
87
|
+
| `OPENTWEET_API_KEY` | Yes | Your OpenTweet API key (starts with `ot_`) |
|
|
88
|
+
| `OPENTWEET_BASE_URL` | No | API base URL (default: `https://opentweet.io`) |
|
|
89
|
+
|
|
90
|
+
## Links
|
|
91
|
+
|
|
92
|
+
- [OpenTweet](https://opentweet.io)
|
|
93
|
+
- [MCP Server Feature Page](https://opentweet.io/mcp)
|
|
94
|
+
- [Developer Dashboard](https://opentweet.io/developer)
|
|
95
|
+
- [API Documentation](https://opentweet.io/developer)
|
|
96
|
+
|
|
97
|
+
## License
|
|
98
|
+
|
|
99
|
+
MIT
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
import type { OpenTweetConfig, PaginatedResponse, Post, AccountStatus, AnalyticsOverview, UploadResponse } from './types.js';
|
|
2
|
+
export declare class OpenTweetClient {
|
|
3
|
+
private apiKey;
|
|
4
|
+
private baseUrl;
|
|
5
|
+
constructor(config: OpenTweetConfig);
|
|
6
|
+
private request;
|
|
7
|
+
listPosts(params?: {
|
|
8
|
+
status?: string;
|
|
9
|
+
page?: number;
|
|
10
|
+
limit?: number;
|
|
11
|
+
}): Promise<PaginatedResponse<Post>>;
|
|
12
|
+
getPost(id: string): Promise<Post>;
|
|
13
|
+
createPost(data: {
|
|
14
|
+
text: string;
|
|
15
|
+
category?: string;
|
|
16
|
+
scheduled_date?: string;
|
|
17
|
+
is_thread?: boolean;
|
|
18
|
+
thread_tweets?: string[];
|
|
19
|
+
media_urls?: string[];
|
|
20
|
+
thread_media?: string[][];
|
|
21
|
+
community_id?: string;
|
|
22
|
+
share_with_followers?: boolean;
|
|
23
|
+
publish_now?: boolean;
|
|
24
|
+
}): Promise<{
|
|
25
|
+
success: boolean;
|
|
26
|
+
count: number;
|
|
27
|
+
posts: Post[];
|
|
28
|
+
message?: string;
|
|
29
|
+
}>;
|
|
30
|
+
createBatchPosts(posts: Array<{
|
|
31
|
+
text: string;
|
|
32
|
+
category?: string;
|
|
33
|
+
scheduled_date?: string;
|
|
34
|
+
is_thread?: boolean;
|
|
35
|
+
thread_tweets?: string[];
|
|
36
|
+
media_urls?: string[];
|
|
37
|
+
}>): Promise<{
|
|
38
|
+
success: boolean;
|
|
39
|
+
count: number;
|
|
40
|
+
posts: Post[];
|
|
41
|
+
}>;
|
|
42
|
+
updatePost(id: string, data: {
|
|
43
|
+
text?: string;
|
|
44
|
+
category?: string;
|
|
45
|
+
scheduled_date?: string | null;
|
|
46
|
+
is_thread?: boolean;
|
|
47
|
+
thread_tweets?: string[];
|
|
48
|
+
media_urls?: string[];
|
|
49
|
+
thread_media?: string[][];
|
|
50
|
+
community_id?: string;
|
|
51
|
+
share_with_followers?: boolean;
|
|
52
|
+
}): Promise<Post>;
|
|
53
|
+
deletePost(id: string): Promise<{
|
|
54
|
+
success: boolean;
|
|
55
|
+
message: string;
|
|
56
|
+
}>;
|
|
57
|
+
schedulePost(id: string, scheduledDate: string): Promise<{
|
|
58
|
+
success: boolean;
|
|
59
|
+
id: string;
|
|
60
|
+
text: string;
|
|
61
|
+
scheduled_date: string;
|
|
62
|
+
message: string;
|
|
63
|
+
}>;
|
|
64
|
+
publishPost(id: string): Promise<{
|
|
65
|
+
success: boolean;
|
|
66
|
+
id: string;
|
|
67
|
+
text: string;
|
|
68
|
+
x_post_id: string;
|
|
69
|
+
posted_date: string;
|
|
70
|
+
message: string;
|
|
71
|
+
}>;
|
|
72
|
+
batchSchedule(schedules: Array<{
|
|
73
|
+
post_id: string;
|
|
74
|
+
scheduled_date: string;
|
|
75
|
+
}>, communityId?: string, shareWithFollowers?: boolean): Promise<{
|
|
76
|
+
success: boolean;
|
|
77
|
+
message: string;
|
|
78
|
+
scheduled: Array<{
|
|
79
|
+
id: string;
|
|
80
|
+
text: string;
|
|
81
|
+
scheduled_date: string;
|
|
82
|
+
}>;
|
|
83
|
+
errors?: Array<{
|
|
84
|
+
post_id: string;
|
|
85
|
+
error: string;
|
|
86
|
+
}>;
|
|
87
|
+
}>;
|
|
88
|
+
getAccountStatus(): Promise<AccountStatus>;
|
|
89
|
+
getAnalyticsOverview(): Promise<AnalyticsOverview>;
|
|
90
|
+
getTweetAnalytics(params?: {
|
|
91
|
+
period?: string;
|
|
92
|
+
sort_by?: string;
|
|
93
|
+
limit?: number;
|
|
94
|
+
}): Promise<Record<string, unknown>>;
|
|
95
|
+
getBestTimes(): Promise<Record<string, unknown>>;
|
|
96
|
+
getFollowerGrowth(params?: {
|
|
97
|
+
days?: number;
|
|
98
|
+
}): Promise<Record<string, unknown>>;
|
|
99
|
+
getGrowthSummary(): Promise<Record<string, unknown>>;
|
|
100
|
+
uploadMedia(fileBuffer: Buffer, fileName: string, mimeType: string): Promise<UploadResponse>;
|
|
101
|
+
}
|
|
102
|
+
//# sourceMappingURL=api-client.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"api-client.d.ts","sourceRoot":"","sources":["../src/api-client.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
export class OpenTweetClient {
|
|
2
|
+
apiKey;
|
|
3
|
+
baseUrl;
|
|
4
|
+
constructor(config) {
|
|
5
|
+
this.apiKey = config.apiKey;
|
|
6
|
+
this.baseUrl = config.baseUrl.replace(/\/$/, '');
|
|
7
|
+
}
|
|
8
|
+
async request(method, path, body, isFormData) {
|
|
9
|
+
const url = `${this.baseUrl}/api/v1${path}`;
|
|
10
|
+
const headers = {
|
|
11
|
+
'Authorization': `Bearer ${this.apiKey}`,
|
|
12
|
+
};
|
|
13
|
+
if (!isFormData) {
|
|
14
|
+
headers['Content-Type'] = 'application/json';
|
|
15
|
+
}
|
|
16
|
+
const response = await fetch(url, {
|
|
17
|
+
method,
|
|
18
|
+
headers,
|
|
19
|
+
body: body && !isFormData ? JSON.stringify(body) : body,
|
|
20
|
+
});
|
|
21
|
+
const data = await response.json();
|
|
22
|
+
if (!response.ok) {
|
|
23
|
+
const errorMessage = data.error || `API error: ${response.status}`;
|
|
24
|
+
const details = data.details
|
|
25
|
+
? Array.isArray(data.details)
|
|
26
|
+
? data.details.join('; ')
|
|
27
|
+
: data.details
|
|
28
|
+
: '';
|
|
29
|
+
throw new Error(details ? `${errorMessage} — ${details}` : errorMessage);
|
|
30
|
+
}
|
|
31
|
+
return data;
|
|
32
|
+
}
|
|
33
|
+
// Posts
|
|
34
|
+
async listPosts(params = {}) {
|
|
35
|
+
const searchParams = new URLSearchParams();
|
|
36
|
+
if (params.status)
|
|
37
|
+
searchParams.set('status', params.status);
|
|
38
|
+
if (params.page)
|
|
39
|
+
searchParams.set('page', String(params.page));
|
|
40
|
+
if (params.limit)
|
|
41
|
+
searchParams.set('limit', String(params.limit));
|
|
42
|
+
const qs = searchParams.toString();
|
|
43
|
+
return this.request('GET', `/posts${qs ? `?${qs}` : ''}`);
|
|
44
|
+
}
|
|
45
|
+
async getPost(id) {
|
|
46
|
+
return this.request('GET', `/posts/${id}`);
|
|
47
|
+
}
|
|
48
|
+
async createPost(data) {
|
|
49
|
+
return this.request('POST', '/posts', data);
|
|
50
|
+
}
|
|
51
|
+
async createBatchPosts(posts) {
|
|
52
|
+
return this.request('POST', '/posts', { posts });
|
|
53
|
+
}
|
|
54
|
+
async updatePost(id, data) {
|
|
55
|
+
return this.request('PUT', `/posts/${id}`, data);
|
|
56
|
+
}
|
|
57
|
+
async deletePost(id) {
|
|
58
|
+
return this.request('DELETE', `/posts/${id}`);
|
|
59
|
+
}
|
|
60
|
+
async schedulePost(id, scheduledDate) {
|
|
61
|
+
return this.request('POST', `/posts/${id}/schedule`, { scheduled_date: scheduledDate });
|
|
62
|
+
}
|
|
63
|
+
async publishPost(id) {
|
|
64
|
+
return this.request('POST', `/posts/${id}/publish`);
|
|
65
|
+
}
|
|
66
|
+
async batchSchedule(schedules, communityId, shareWithFollowers) {
|
|
67
|
+
return this.request('POST', '/posts/batch-schedule', {
|
|
68
|
+
schedules,
|
|
69
|
+
community_id: communityId,
|
|
70
|
+
share_with_followers: shareWithFollowers,
|
|
71
|
+
});
|
|
72
|
+
}
|
|
73
|
+
// Account
|
|
74
|
+
async getAccountStatus() {
|
|
75
|
+
return this.request('GET', '/me');
|
|
76
|
+
}
|
|
77
|
+
// Analytics
|
|
78
|
+
async getAnalyticsOverview() {
|
|
79
|
+
return this.request('GET', '/analytics/overview');
|
|
80
|
+
}
|
|
81
|
+
async getTweetAnalytics(params = {}) {
|
|
82
|
+
const searchParams = new URLSearchParams();
|
|
83
|
+
if (params.period)
|
|
84
|
+
searchParams.set('period', params.period);
|
|
85
|
+
if (params.sort_by)
|
|
86
|
+
searchParams.set('sort_by', params.sort_by);
|
|
87
|
+
if (params.limit)
|
|
88
|
+
searchParams.set('limit', String(params.limit));
|
|
89
|
+
const qs = searchParams.toString();
|
|
90
|
+
return this.request('GET', `/analytics/tweets${qs ? `?${qs}` : ''}`);
|
|
91
|
+
}
|
|
92
|
+
async getBestTimes() {
|
|
93
|
+
return this.request('GET', '/analytics/best-times');
|
|
94
|
+
}
|
|
95
|
+
async getFollowerGrowth(params = {}) {
|
|
96
|
+
const searchParams = new URLSearchParams();
|
|
97
|
+
if (params.days)
|
|
98
|
+
searchParams.set('days', String(params.days));
|
|
99
|
+
const qs = searchParams.toString();
|
|
100
|
+
return this.request('GET', `/analytics/followers${qs ? `?${qs}` : ''}`);
|
|
101
|
+
}
|
|
102
|
+
async getGrowthSummary() {
|
|
103
|
+
return this.request('GET', '/analytics/growth');
|
|
104
|
+
}
|
|
105
|
+
// Upload
|
|
106
|
+
async uploadMedia(fileBuffer, fileName, mimeType) {
|
|
107
|
+
const formData = new FormData();
|
|
108
|
+
const blob = new Blob([new Uint8Array(fileBuffer)], { type: mimeType });
|
|
109
|
+
formData.append('file', blob, fileName);
|
|
110
|
+
const url = `${this.baseUrl}/api/v1/upload`;
|
|
111
|
+
const response = await fetch(url, {
|
|
112
|
+
method: 'POST',
|
|
113
|
+
headers: {
|
|
114
|
+
'Authorization': `Bearer ${this.apiKey}`,
|
|
115
|
+
},
|
|
116
|
+
body: formData,
|
|
117
|
+
});
|
|
118
|
+
const data = await response.json();
|
|
119
|
+
if (!response.ok) {
|
|
120
|
+
throw new Error(data.error || `Upload failed: ${response.status}`);
|
|
121
|
+
}
|
|
122
|
+
return data;
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
//# sourceMappingURL=api-client.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"api-client.js","sourceRoot":"","sources":["../src/api-client.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":""}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
3
|
+
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
|
|
4
|
+
import { OpenTweetClient } from './api-client.js';
|
|
5
|
+
import { registerPostTools } from './tools/posts.js';
|
|
6
|
+
import { registerSchedulingTools } from './tools/scheduling.js';
|
|
7
|
+
import { registerAnalyticsTools } from './tools/analytics.js';
|
|
8
|
+
import { registerAccountTools } from './tools/account.js';
|
|
9
|
+
import { registerMediaTools } from './tools/media.js';
|
|
10
|
+
import { registerResources } from './resources/index.js';
|
|
11
|
+
import { registerPrompts } from './prompts/index.js';
|
|
12
|
+
const API_KEY = process.env.OPENTWEET_API_KEY;
|
|
13
|
+
const BASE_URL = process.env.OPENTWEET_BASE_URL || 'https://opentweet.io';
|
|
14
|
+
if (!API_KEY) {
|
|
15
|
+
console.error('Error: OPENTWEET_API_KEY environment variable is required.');
|
|
16
|
+
console.error('');
|
|
17
|
+
console.error('Get your API key from: https://opentweet.io/developer');
|
|
18
|
+
console.error('');
|
|
19
|
+
console.error('Set it in your MCP client config:');
|
|
20
|
+
console.error(' "env": { "OPENTWEET_API_KEY": "ot_your_key_here" }');
|
|
21
|
+
process.exit(1);
|
|
22
|
+
}
|
|
23
|
+
const client = new OpenTweetClient({
|
|
24
|
+
apiKey: API_KEY,
|
|
25
|
+
baseUrl: BASE_URL,
|
|
26
|
+
});
|
|
27
|
+
const server = new McpServer({
|
|
28
|
+
name: 'opentweet',
|
|
29
|
+
version: '1.0.0',
|
|
30
|
+
});
|
|
31
|
+
// Register all tools
|
|
32
|
+
registerPostTools(server, client);
|
|
33
|
+
registerSchedulingTools(server, client);
|
|
34
|
+
registerAnalyticsTools(server, client);
|
|
35
|
+
registerAccountTools(server, client);
|
|
36
|
+
registerMediaTools(server, client);
|
|
37
|
+
// Register resources
|
|
38
|
+
registerResources(server, client);
|
|
39
|
+
// Register prompts
|
|
40
|
+
registerPrompts(server);
|
|
41
|
+
// Start server with stdio transport
|
|
42
|
+
const transport = new StdioServerTransport();
|
|
43
|
+
await server.connect(transport);
|
|
44
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAEA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AACpE,OAAO,EAAE,oBAAoB,EAAE,MAAM,2CAA2C,CAAC;AACjF,OAAO,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAC;AAClD,OAAO,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AACrD,OAAO,EAAE,uBAAuB,EAAE,MAAM,uBAAuB,CAAC;AAChE,OAAO,EAAE,sBAAsB,EAAE,MAAM,sBAAsB,CAAC;AAC9D,OAAO,EAAE,oBAAoB,EAAE,MAAM,oBAAoB,CAAC;AAC1D,OAAO,EAAE,kBAAkB,EAAE,MAAM,kBAAkB,CAAC;AACtD,OAAO,EAAE,iBAAiB,EAAE,MAAM,sBAAsB,CAAC;AACzD,OAAO,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAC;AAErD,MAAM,OAAO,GAAG,OAAO,CAAC,GAAG,CAAC,iBAAiB,CAAC;AAC9C,MAAM,QAAQ,GAAG,OAAO,CAAC,GAAG,CAAC,kBAAkB,IAAI,sBAAsB,CAAC;AAE1E,IAAI,CAAC,OAAO,EAAE,CAAC;IACb,OAAO,CAAC,KAAK,CAAC,4DAA4D,CAAC,CAAC;IAC5E,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;IAClB,OAAO,CAAC,KAAK,CAAC,uDAAuD,CAAC,CAAC;IACvE,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;IAClB,OAAO,CAAC,KAAK,CAAC,mCAAmC,CAAC,CAAC;IACnD,OAAO,CAAC,KAAK,CAAC,sDAAsD,CAAC,CAAC;IACtE,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC;AAED,MAAM,MAAM,GAAG,IAAI,eAAe,CAAC;IACjC,MAAM,EAAE,OAAO;IACf,OAAO,EAAE,QAAQ;CAClB,CAAC,CAAC;AAEH,MAAM,MAAM,GAAG,IAAI,SAAS,CAAC;IAC3B,IAAI,EAAE,WAAW;IACjB,OAAO,EAAE,OAAO;CACjB,CAAC,CAAC;AAEH,qBAAqB;AACrB,iBAAiB,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;AAClC,uBAAuB,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;AACxC,sBAAsB,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;AACvC,oBAAoB,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;AACrC,kBAAkB,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;AAEnC,qBAAqB;AACrB,iBAAiB,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;AAElC,mBAAmB;AACnB,eAAe,CAAC,MAAM,CAAC,CAAC;AAExB,oCAAoC;AACpC,MAAM,SAAS,GAAG,IAAI,oBAAoB,EAAE,CAAC;AAC7C,MAAM,MAAM,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/prompts/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAGpE,wBAAgB,eAAe,CAAC,MAAM,EAAE,SAAS,QAiHhD"}
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
export function registerPrompts(server) {
|
|
3
|
+
server.prompt('weekly_content_plan', 'Generate a week of tweet content based on topics and preferences', {
|
|
4
|
+
topics: z.string().describe('Comma-separated topics to tweet about (e.g. "AI, startups, product launches")'),
|
|
5
|
+
tone: z.enum(['professional', 'casual', 'humorous', 'inspirational', 'technical']).optional()
|
|
6
|
+
.describe('Desired tone for the tweets'),
|
|
7
|
+
tweets_per_day: z.string().optional().describe('Number of tweets per day (default "2")'),
|
|
8
|
+
}, ({ topics, tone = 'professional', tweets_per_day = '2' }) => ({
|
|
9
|
+
messages: [{
|
|
10
|
+
role: 'user',
|
|
11
|
+
content: {
|
|
12
|
+
type: 'text',
|
|
13
|
+
text: `Create a weekly content plan for X/Twitter.
|
|
14
|
+
|
|
15
|
+
Topics: ${topics}
|
|
16
|
+
Tone: ${tone}
|
|
17
|
+
Tweets per day: ${tweets_per_day}
|
|
18
|
+
|
|
19
|
+
For each day (Monday through Sunday), generate ${tweets_per_day} tweet(s). Each tweet should:
|
|
20
|
+
- Be under 280 characters
|
|
21
|
+
- Be engaging and encourage interaction
|
|
22
|
+
- Include a mix of content types (insights, questions, tips, stories)
|
|
23
|
+
- Be relevant to the topics listed
|
|
24
|
+
|
|
25
|
+
After generating the tweets, use the opentweet_create_tweet tool to save each one as a draft with an appropriate category. Then I can review and schedule them.
|
|
26
|
+
|
|
27
|
+
Format each tweet clearly with the day and tweet number.`,
|
|
28
|
+
},
|
|
29
|
+
}],
|
|
30
|
+
}));
|
|
31
|
+
server.prompt('review_and_schedule_drafts', 'Review your current drafts and suggest optimal scheduling times', {}, () => ({
|
|
32
|
+
messages: [{
|
|
33
|
+
role: 'user',
|
|
34
|
+
content: {
|
|
35
|
+
type: 'text',
|
|
36
|
+
text: `Please help me review and schedule my draft tweets.
|
|
37
|
+
|
|
38
|
+
1. First, use opentweet_list_tweets with status "draft" to see all my drafts
|
|
39
|
+
2. Then use opentweet_get_analytics with type "best_times" to find my optimal posting times
|
|
40
|
+
3. Review each draft for quality - suggest any improvements
|
|
41
|
+
4. Propose a schedule that spreads the tweets across the next few days at optimal times
|
|
42
|
+
5. After I approve, use opentweet_batch_schedule to schedule them all
|
|
43
|
+
|
|
44
|
+
Show me the drafts and your recommended schedule before taking action.`,
|
|
45
|
+
},
|
|
46
|
+
}],
|
|
47
|
+
}));
|
|
48
|
+
server.prompt('content_from_url', 'Generate tweets from a URL/article/topic', {
|
|
49
|
+
source: z.string().describe('URL, article title, or topic to generate tweets about'),
|
|
50
|
+
count: z.string().optional().describe('Number of tweets to generate (default "5")'),
|
|
51
|
+
style: z.string().optional().describe('Additional style instructions (e.g. "include statistics", "ask questions")'),
|
|
52
|
+
}, ({ source, count = '5', style }) => ({
|
|
53
|
+
messages: [{
|
|
54
|
+
role: 'user',
|
|
55
|
+
content: {
|
|
56
|
+
type: 'text',
|
|
57
|
+
text: `Generate ${count} engaging tweets about: ${source}
|
|
58
|
+
|
|
59
|
+
${style ? `Style: ${style}\n` : ''}
|
|
60
|
+
Each tweet should:
|
|
61
|
+
- Be under 280 characters
|
|
62
|
+
- Have a unique angle or perspective
|
|
63
|
+
- Be engaging and shareable
|
|
64
|
+
- Include relevant hashtags where appropriate
|
|
65
|
+
|
|
66
|
+
After generating them, use opentweet_create_tweet to save each as a draft so I can review and schedule them.`,
|
|
67
|
+
},
|
|
68
|
+
}],
|
|
69
|
+
}));
|
|
70
|
+
server.prompt('performance_review', 'Analyze your recent tweet performance and get improvement suggestions', {}, () => ({
|
|
71
|
+
messages: [{
|
|
72
|
+
role: 'user',
|
|
73
|
+
content: {
|
|
74
|
+
type: 'text',
|
|
75
|
+
text: `Analyze my Twitter/X performance and give me actionable suggestions.
|
|
76
|
+
|
|
77
|
+
1. Use opentweet_get_analytics with type "overview" to get my posting stats and streaks
|
|
78
|
+
2. Use opentweet_get_analytics with type "best_times" to see optimal posting times
|
|
79
|
+
3. Use opentweet_get_analytics with type "tweets" to see per-tweet engagement (if available)
|
|
80
|
+
4. Use opentweet_get_followers to check follower growth trends
|
|
81
|
+
|
|
82
|
+
Based on the data, tell me:
|
|
83
|
+
- How consistent am I with posting?
|
|
84
|
+
- What categories/topics perform best?
|
|
85
|
+
- Am I posting at optimal times?
|
|
86
|
+
- What's my streak status and how can I maintain it?
|
|
87
|
+
- Specific actionable tips to improve engagement
|
|
88
|
+
- Any concerning trends I should address`,
|
|
89
|
+
},
|
|
90
|
+
}],
|
|
91
|
+
}));
|
|
92
|
+
}
|
|
93
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/prompts/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,MAAM,UAAU,eAAe,CAAC,MAAiB;IAC/C,MAAM,CAAC,MAAM,CACX,qBAAqB,EACrB,kEAAkE,EAClE;QACE,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,+EAA+E,CAAC;QAC5G,IAAI,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,cAAc,EAAE,QAAQ,EAAE,UAAU,EAAE,eAAe,EAAE,WAAW,CAAC,CAAC,CAAC,QAAQ,EAAE;aAC1F,QAAQ,CAAC,6BAA6B,CAAC;QAC1C,cAAc,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,wCAAwC,CAAC;KACzF,EACD,CAAC,EAAE,MAAM,EAAE,IAAI,GAAG,cAAc,EAAE,cAAc,GAAG,GAAG,EAAE,EAAE,EAAE,CAAC,CAAC;QAC5D,QAAQ,EAAE,CAAC;gBACT,IAAI,EAAE,MAAe;gBACrB,OAAO,EAAE;oBACP,IAAI,EAAE,MAAe;oBACrB,IAAI,EAAE;;UAEN,MAAM;QACR,IAAI;kBACM,cAAc;;iDAEiB,cAAc;;;;;;;;yDAQN;iBAChD;aACF,CAAC;KACH,CAAC,CACH,CAAC;IAEF,MAAM,CAAC,MAAM,CACX,4BAA4B,EAC5B,iEAAiE,EACjE,EAAE,EACF,GAAG,EAAE,CAAC,CAAC;QACL,QAAQ,EAAE,CAAC;gBACT,IAAI,EAAE,MAAe;gBACrB,OAAO,EAAE;oBACP,IAAI,EAAE,MAAe;oBACrB,IAAI,EAAE;;;;;;;;uEAQuD;iBAC9D;aACF,CAAC;KACH,CAAC,CACH,CAAC;IAEF,MAAM,CAAC,MAAM,CACX,kBAAkB,EAClB,0CAA0C,EAC1C;QACE,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,uDAAuD,CAAC;QACpF,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,4CAA4C,CAAC;QACnF,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,4EAA4E,CAAC;KACpH,EACD,CAAC,EAAE,MAAM,EAAE,KAAK,GAAG,GAAG,EAAE,KAAK,EAAE,EAAE,EAAE,CAAC,CAAC;QACnC,QAAQ,EAAE,CAAC;gBACT,IAAI,EAAE,MAAe;gBACrB,OAAO,EAAE;oBACP,IAAI,EAAE,MAAe;oBACrB,IAAI,EAAE,YAAY,KAAK,2BAA2B,MAAM;;EAEhE,KAAK,CAAC,CAAC,CAAC,UAAU,KAAK,IAAI,CAAC,CAAC,CAAC,EAAE;;;;;;;6GAO2E;iBACpG;aACF,CAAC;KACH,CAAC,CACH,CAAC;IAEF,MAAM,CAAC,MAAM,CACX,oBAAoB,EACpB,uEAAuE,EACvE,EAAE,EACF,GAAG,EAAE,CAAC,CAAC;QACL,QAAQ,EAAE,CAAC;gBACT,IAAI,EAAE,MAAe;gBACrB,OAAO,EAAE;oBACP,IAAI,EAAE,MAAe;oBACrB,IAAI,EAAE;;;;;;;;;;;;;yCAayB;iBAChC;aACF,CAAC;KACH,CAAC,CACH,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/resources/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AACpE,OAAO,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAC;AAEnD,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,eAAe,QA4E3E"}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
export function registerResources(server, client) {
|
|
2
|
+
server.resource('account-status', 'opentweet://account', {
|
|
3
|
+
description: 'Your OpenTweet account status: subscription plan, daily limits, and post counts',
|
|
4
|
+
mimeType: 'application/json',
|
|
5
|
+
}, async () => {
|
|
6
|
+
const data = await client.getAccountStatus();
|
|
7
|
+
return {
|
|
8
|
+
contents: [{
|
|
9
|
+
uri: 'opentweet://account',
|
|
10
|
+
mimeType: 'application/json',
|
|
11
|
+
text: JSON.stringify(data, null, 2),
|
|
12
|
+
}],
|
|
13
|
+
};
|
|
14
|
+
});
|
|
15
|
+
server.resource('scheduled-tweets', 'opentweet://posts/scheduled', {
|
|
16
|
+
description: 'All your currently scheduled tweets (upcoming posts waiting to be published)',
|
|
17
|
+
mimeType: 'application/json',
|
|
18
|
+
}, async () => {
|
|
19
|
+
const data = await client.listPosts({ status: 'scheduled', limit: 100 });
|
|
20
|
+
return {
|
|
21
|
+
contents: [{
|
|
22
|
+
uri: 'opentweet://posts/scheduled',
|
|
23
|
+
mimeType: 'application/json',
|
|
24
|
+
text: JSON.stringify(data, null, 2),
|
|
25
|
+
}],
|
|
26
|
+
};
|
|
27
|
+
});
|
|
28
|
+
server.resource('draft-tweets', 'opentweet://posts/drafts', {
|
|
29
|
+
description: 'All your draft tweets (saved but not yet scheduled)',
|
|
30
|
+
mimeType: 'application/json',
|
|
31
|
+
}, async () => {
|
|
32
|
+
const data = await client.listPosts({ status: 'draft', limit: 100 });
|
|
33
|
+
return {
|
|
34
|
+
contents: [{
|
|
35
|
+
uri: 'opentweet://posts/drafts',
|
|
36
|
+
mimeType: 'application/json',
|
|
37
|
+
text: JSON.stringify(data, null, 2),
|
|
38
|
+
}],
|
|
39
|
+
};
|
|
40
|
+
});
|
|
41
|
+
server.resource('analytics-summary', 'opentweet://analytics/summary', {
|
|
42
|
+
description: 'Your posting analytics: stats, streaks, trends, and category breakdown',
|
|
43
|
+
mimeType: 'application/json',
|
|
44
|
+
}, async () => {
|
|
45
|
+
const data = await client.getAnalyticsOverview();
|
|
46
|
+
return {
|
|
47
|
+
contents: [{
|
|
48
|
+
uri: 'opentweet://analytics/summary',
|
|
49
|
+
mimeType: 'application/json',
|
|
50
|
+
text: JSON.stringify(data, null, 2),
|
|
51
|
+
}],
|
|
52
|
+
};
|
|
53
|
+
});
|
|
54
|
+
}
|
|
55
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/resources/index.ts"],"names":[],"mappings":"AAGA,MAAM,UAAU,iBAAiB,CAAC,MAAiB,EAAE,MAAuB;IAC1E,MAAM,CAAC,QAAQ,CACb,gBAAgB,EAChB,qBAAqB,EACrB;QACE,WAAW,EAAE,iFAAiF;QAC9F,QAAQ,EAAE,kBAAkB;KAC7B,EACD,KAAK,IAAI,EAAE;QACT,MAAM,IAAI,GAAG,MAAM,MAAM,CAAC,gBAAgB,EAAE,CAAC;QAC7C,OAAO;YACL,QAAQ,EAAE,CAAC;oBACT,GAAG,EAAE,qBAAqB;oBAC1B,QAAQ,EAAE,kBAAkB;oBAC5B,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC;iBACpC,CAAC;SACH,CAAC;IACJ,CAAC,CACF,CAAC;IAEF,MAAM,CAAC,QAAQ,CACb,kBAAkB,EAClB,6BAA6B,EAC7B;QACE,WAAW,EAAE,8EAA8E;QAC3F,QAAQ,EAAE,kBAAkB;KAC7B,EACD,KAAK,IAAI,EAAE;QACT,MAAM,IAAI,GAAG,MAAM,MAAM,CAAC,SAAS,CAAC,EAAE,MAAM,EAAE,WAAW,EAAE,KAAK,EAAE,GAAG,EAAE,CAAC,CAAC;QACzE,OAAO;YACL,QAAQ,EAAE,CAAC;oBACT,GAAG,EAAE,6BAA6B;oBAClC,QAAQ,EAAE,kBAAkB;oBAC5B,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC;iBACpC,CAAC;SACH,CAAC;IACJ,CAAC,CACF,CAAC;IAEF,MAAM,CAAC,QAAQ,CACb,cAAc,EACd,0BAA0B,EAC1B;QACE,WAAW,EAAE,qDAAqD;QAClE,QAAQ,EAAE,kBAAkB;KAC7B,EACD,KAAK,IAAI,EAAE;QACT,MAAM,IAAI,GAAG,MAAM,MAAM,CAAC,SAAS,CAAC,EAAE,MAAM,EAAE,OAAO,EAAE,KAAK,EAAE,GAAG,EAAE,CAAC,CAAC;QACrE,OAAO;YACL,QAAQ,EAAE,CAAC;oBACT,GAAG,EAAE,0BAA0B;oBAC/B,QAAQ,EAAE,kBAAkB;oBAC5B,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC;iBACpC,CAAC;SACH,CAAC;IACJ,CAAC,CACF,CAAC;IAEF,MAAM,CAAC,QAAQ,CACb,mBAAmB,EACnB,+BAA+B,EAC/B;QACE,WAAW,EAAE,wEAAwE;QACrF,QAAQ,EAAE,kBAAkB;KAC7B,EACD,KAAK,IAAI,EAAE;QACT,MAAM,IAAI,GAAG,MAAM,MAAM,CAAC,oBAAoB,EAAE,CAAC;QACjD,OAAO;YACL,QAAQ,EAAE,CAAC;oBACT,GAAG,EAAE,+BAA+B;oBACpC,QAAQ,EAAE,kBAAkB;oBAC5B,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC;iBACpC,CAAC;SACH,CAAC;IACJ,CAAC,CACF,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"account.d.ts","sourceRoot":"","sources":["../../src/tools/account.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AACpE,OAAO,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAC;AAEnD,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,eAAe,QA4C9E"}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
export function registerAccountTools(server, client) {
|
|
2
|
+
server.tool('opentweet_get_account', 'Get your OpenTweet account status including subscription plan, daily posting limits, and post counts.', {}, async () => {
|
|
3
|
+
try {
|
|
4
|
+
const data = await client.getAccountStatus();
|
|
5
|
+
const { subscription: sub, limits, stats } = data;
|
|
6
|
+
let text = `OpenTweet Account Status\n\n`;
|
|
7
|
+
text += `Subscription:\n`;
|
|
8
|
+
text += ` Status: ${sub.status}\n`;
|
|
9
|
+
text += ` Has access: ${sub.has_access ? 'Yes' : 'No'}\n`;
|
|
10
|
+
if (sub.is_trialing) {
|
|
11
|
+
text += ` Trial: Active (ends ${sub.trial_ends_at})\n`;
|
|
12
|
+
}
|
|
13
|
+
if (sub.current_period_ends_at) {
|
|
14
|
+
text += ` Current period ends: ${sub.current_period_ends_at}\n`;
|
|
15
|
+
}
|
|
16
|
+
if (limits) {
|
|
17
|
+
text += `\nDaily Limits:\n`;
|
|
18
|
+
text += ` Can post: ${limits.can_post ? 'Yes' : 'No'}\n`;
|
|
19
|
+
text += ` Posted today: ${limits.posts_published_today}\n`;
|
|
20
|
+
text += ` Remaining today: ${limits.remaining_posts_today}\n`;
|
|
21
|
+
text += ` Daily limit: ${limits.daily_limit}\n`;
|
|
22
|
+
}
|
|
23
|
+
text += `\nPost Counts:\n`;
|
|
24
|
+
text += ` Total: ${stats.total_posts}\n`;
|
|
25
|
+
text += ` Scheduled: ${stats.scheduled_posts}\n`;
|
|
26
|
+
text += ` Posted: ${stats.posted_posts}\n`;
|
|
27
|
+
text += ` Drafts: ${stats.draft_posts}`;
|
|
28
|
+
return { content: [{ type: 'text', text }] };
|
|
29
|
+
}
|
|
30
|
+
catch (error) {
|
|
31
|
+
return {
|
|
32
|
+
content: [{ type: 'text', text: `Error: ${error.message}` }],
|
|
33
|
+
isError: true,
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
});
|
|
37
|
+
}
|
|
38
|
+
//# sourceMappingURL=account.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"account.js","sourceRoot":"","sources":["../../src/tools/account.ts"],"names":[],"mappings":"AAGA,MAAM,UAAU,oBAAoB,CAAC,MAAiB,EAAE,MAAuB;IAC7E,MAAM,CAAC,IAAI,CACT,uBAAuB,EACvB,uGAAuG,EACvG,EAAE,EACF,KAAK,IAAI,EAAE;QACT,IAAI,CAAC;YACH,MAAM,IAAI,GAAG,MAAM,MAAM,CAAC,gBAAgB,EAAE,CAAC;YAC7C,MAAM,EAAE,YAAY,EAAE,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,GAAG,IAAI,CAAC;YAElD,IAAI,IAAI,GAAG,8BAA8B,CAAC;YAC1C,IAAI,IAAI,iBAAiB,CAAC;YAC1B,IAAI,IAAI,aAAa,GAAG,CAAC,MAAM,IAAI,CAAC;YACpC,IAAI,IAAI,iBAAiB,GAAG,CAAC,UAAU,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,IAAI,CAAC;YAC3D,IAAI,GAAG,CAAC,WAAW,EAAE,CAAC;gBACpB,IAAI,IAAI,yBAAyB,GAAG,CAAC,aAAa,KAAK,CAAC;YAC1D,CAAC;YACD,IAAI,GAAG,CAAC,sBAAsB,EAAE,CAAC;gBAC/B,IAAI,IAAI,0BAA0B,GAAG,CAAC,sBAAsB,IAAI,CAAC;YACnE,CAAC;YAED,IAAI,MAAM,EAAE,CAAC;gBACX,IAAI,IAAI,mBAAmB,CAAC;gBAC5B,IAAI,IAAI,eAAe,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,IAAI,CAAC;gBAC1D,IAAI,IAAI,mBAAmB,MAAM,CAAC,qBAAqB,IAAI,CAAC;gBAC5D,IAAI,IAAI,sBAAsB,MAAM,CAAC,qBAAqB,IAAI,CAAC;gBAC/D,IAAI,IAAI,kBAAkB,MAAM,CAAC,WAAW,IAAI,CAAC;YACnD,CAAC;YAED,IAAI,IAAI,kBAAkB,CAAC;YAC3B,IAAI,IAAI,YAAY,KAAK,CAAC,WAAW,IAAI,CAAC;YAC1C,IAAI,IAAI,gBAAgB,KAAK,CAAC,eAAe,IAAI,CAAC;YAClD,IAAI,IAAI,aAAa,KAAK,CAAC,YAAY,IAAI,CAAC;YAC5C,IAAI,IAAI,aAAa,KAAK,CAAC,WAAW,EAAE,CAAC;YAEzC,OAAO,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAe,EAAE,IAAI,EAAE,CAAC,EAAE,CAAC;QACxD,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,OAAO;gBACL,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAe,EAAE,IAAI,EAAE,UAAW,KAAe,CAAC,OAAO,EAAE,EAAE,CAAC;gBAChF,OAAO,EAAE,IAAI;aACd,CAAC;QACJ,CAAC;IACH,CAAC,CACF,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"analytics.d.ts","sourceRoot":"","sources":["../../src/tools/analytics.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAEpE,OAAO,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAC;AAEnD,wBAAgB,sBAAsB,CAAC,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,eAAe,QA+GhF"}
|