@elizaos/plugin-bluesky 2.0.0-alpha.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,741 @@
1
+ var __defProp = Object.defineProperty;
2
+ var __getOwnPropNames = Object.getOwnPropertyNames;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
5
+ var __moduleCache = /* @__PURE__ */ new WeakMap;
6
+ var __toCommonJS = (from) => {
7
+ var entry = __moduleCache.get(from), desc;
8
+ if (entry)
9
+ return entry;
10
+ entry = __defProp({}, "__esModule", { value: true });
11
+ if (from && typeof from === "object" || typeof from === "function")
12
+ __getOwnPropNames(from).map((key) => !__hasOwnProp.call(entry, key) && __defProp(entry, key, {
13
+ get: () => from[key],
14
+ enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
15
+ }));
16
+ __moduleCache.set(from, entry);
17
+ return entry;
18
+ };
19
+ var __export = (target, all) => {
20
+ for (var name in all)
21
+ __defProp(target, name, {
22
+ get: all[name],
23
+ enumerable: true,
24
+ configurable: true,
25
+ set: (newValue) => all[name] = () => newValue
26
+ });
27
+ };
28
+
29
+ // index.node.ts
30
+ var exports_index_node = {};
31
+ __export(exports_index_node, {
32
+ default: () => typescript_default,
33
+ blueSkyPlugin: () => blueSkyPlugin,
34
+ BlueSkyService: () => BlueSkyService,
35
+ BlueSkyClient: () => BlueSkyClient
36
+ });
37
+ module.exports = __toCommonJS(exports_index_node);
38
+
39
+ // index.ts
40
+ var import_core6 = require("@elizaos/core");
41
+
42
+ // services/bluesky.ts
43
+ var import_core5 = require("@elizaos/core");
44
+
45
+ // client.ts
46
+ var import_api = require("@atproto/api");
47
+ var import_core = require("@elizaos/core");
48
+ var import_lru_cache = require("lru-cache");
49
+
50
+ // types/index.ts
51
+ var import_zod = require("zod");
52
+ var BLUESKY_SERVICE_URL = "https://bsky.social";
53
+ var BLUESKY_MAX_POST_LENGTH = 300;
54
+ var BLUESKY_POLL_INTERVAL = 60;
55
+ var BLUESKY_POST_INTERVAL_MIN = 1800;
56
+ var BLUESKY_POST_INTERVAL_MAX = 3600;
57
+ var BLUESKY_ACTION_INTERVAL = 120;
58
+ var BLUESKY_MAX_ACTIONS = 5;
59
+ var BLUESKY_CHAT_SERVICE_DID = "did:web:api.bsky.chat";
60
+ var BLUESKY_SERVICE_NAME = "bluesky";
61
+ var AT_PROTOCOL_HANDLE_REGEX = /^([a-zA-Z0-9]([a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?\.)+[a-zA-Z]([a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?$/;
62
+ var CACHE_TTL = {
63
+ PROFILE: 3600000,
64
+ TIMELINE: 300000,
65
+ POST: 1800000,
66
+ NOTIFICATIONS: 300000,
67
+ CONVERSATIONS: 300000
68
+ };
69
+ var CACHE_SIZE = {
70
+ PROFILE: 1000,
71
+ TIMELINE: 500,
72
+ POST: 1e4,
73
+ NOTIFICATIONS: 1000,
74
+ CONVERSATIONS: 100
75
+ };
76
+ var BlueSkyConfigSchema = import_zod.z.object({
77
+ handle: import_zod.z.string().regex(AT_PROTOCOL_HANDLE_REGEX, "Invalid handle format"),
78
+ password: import_zod.z.string().min(1),
79
+ service: import_zod.z.string().url().default(BLUESKY_SERVICE_URL),
80
+ dryRun: import_zod.z.boolean().default(false),
81
+ pollInterval: import_zod.z.number().positive().default(BLUESKY_POLL_INTERVAL),
82
+ enablePost: import_zod.z.boolean().default(true),
83
+ postIntervalMin: import_zod.z.number().positive().default(BLUESKY_POST_INTERVAL_MIN),
84
+ postIntervalMax: import_zod.z.number().positive().default(BLUESKY_POST_INTERVAL_MAX),
85
+ enableActionProcessing: import_zod.z.boolean().default(true),
86
+ actionInterval: import_zod.z.number().positive().default(BLUESKY_ACTION_INTERVAL),
87
+ postImmediately: import_zod.z.boolean().default(false),
88
+ maxActionsProcessing: import_zod.z.number().positive().default(BLUESKY_MAX_ACTIONS),
89
+ enableDMs: import_zod.z.boolean().default(true)
90
+ });
91
+
92
+ class BlueSkyError extends Error {
93
+ code;
94
+ status;
95
+ constructor(message, code, status) {
96
+ super(message);
97
+ this.code = code;
98
+ this.status = status;
99
+ this.name = "BlueSkyError";
100
+ }
101
+ }
102
+
103
+ // client.ts
104
+ function isPostView(item) {
105
+ return typeof item === "object" && item !== null && "uri" in item && "cid" in item && "author" in item && "record" in item && "indexedAt" in item && typeof item.uri === "string" && typeof item.cid === "string";
106
+ }
107
+ function adaptPostView(postView) {
108
+ const author = postView.author;
109
+ const record = postView.record;
110
+ return {
111
+ uri: postView.uri,
112
+ cid: postView.cid,
113
+ author: {
114
+ did: author.did,
115
+ handle: author.handle,
116
+ displayName: author.displayName,
117
+ description: author.description,
118
+ avatar: author.avatar,
119
+ banner: author.banner,
120
+ followersCount: author.followersCount,
121
+ followsCount: author.followsCount,
122
+ postsCount: author.postsCount,
123
+ indexedAt: author.indexedAt,
124
+ createdAt: author.createdAt
125
+ },
126
+ record: {
127
+ $type: record.$type ?? "app.bsky.feed.post",
128
+ text: record.text ?? "",
129
+ facets: record.facets,
130
+ embed: record.embed,
131
+ createdAt: record.createdAt ?? ""
132
+ },
133
+ embed: postView.embed,
134
+ replyCount: postView.replyCount,
135
+ repostCount: postView.repostCount,
136
+ likeCount: postView.likeCount,
137
+ quoteCount: postView.quoteCount,
138
+ indexedAt: postView.indexedAt
139
+ };
140
+ }
141
+
142
+ class BlueSkyClient {
143
+ config;
144
+ agent;
145
+ session = null;
146
+ profileCache;
147
+ constructor(config) {
148
+ this.config = config;
149
+ this.agent = new import_api.BskyAgent({ service: config.service });
150
+ this.profileCache = new import_lru_cache.LRUCache({
151
+ max: CACHE_SIZE.PROFILE,
152
+ ttl: CACHE_TTL.PROFILE
153
+ });
154
+ }
155
+ async authenticate() {
156
+ const response = await this.agent.login({
157
+ identifier: this.config.handle,
158
+ password: this.config.password
159
+ });
160
+ if (!response.success) {
161
+ throw new BlueSkyError("Authentication failed", "AUTH_FAILED");
162
+ }
163
+ this.session = {
164
+ did: response.data.did,
165
+ handle: response.data.handle,
166
+ email: response.data.email,
167
+ accessJwt: response.data.accessJwt,
168
+ refreshJwt: response.data.refreshJwt
169
+ };
170
+ import_core.logger.info(`Authenticated with BlueSky: ${this.session.handle}`);
171
+ return this.session;
172
+ }
173
+ getSession() {
174
+ return this.session;
175
+ }
176
+ async getProfile(handle) {
177
+ const cached = this.profileCache.get(handle);
178
+ if (cached)
179
+ return cached;
180
+ const response = await this.agent.getProfile({ actor: handle });
181
+ const profile = {
182
+ did: response.data.did,
183
+ handle: response.data.handle,
184
+ displayName: response.data.displayName,
185
+ description: response.data.description,
186
+ avatar: response.data.avatar,
187
+ banner: response.data.banner,
188
+ followersCount: response.data.followersCount,
189
+ followsCount: response.data.followsCount,
190
+ postsCount: response.data.postsCount,
191
+ indexedAt: response.data.indexedAt,
192
+ createdAt: response.data.createdAt
193
+ };
194
+ this.profileCache.set(handle, profile);
195
+ return profile;
196
+ }
197
+ async getTimeline(params = {}) {
198
+ const response = await this.agent.getTimeline({
199
+ algorithm: params.algorithm,
200
+ limit: params.limit ?? 50,
201
+ cursor: params.cursor
202
+ });
203
+ return {
204
+ cursor: response.data.cursor,
205
+ feed: response.data.feed.map((item) => ({
206
+ post: adaptPostView(item.post),
207
+ reply: item.reply && isPostView(item.reply.root) && isPostView(item.reply.parent) ? {
208
+ root: adaptPostView(item.reply.root),
209
+ parent: adaptPostView(item.reply.parent)
210
+ } : undefined,
211
+ reason: item.reason
212
+ }))
213
+ };
214
+ }
215
+ async sendPost(request) {
216
+ if (this.config.dryRun) {
217
+ import_core.logger.info(`Dry run: would create post with text: ${request.content.text}`);
218
+ return this.mockPost(request.content.text);
219
+ }
220
+ const rt = new import_api.RichText({ text: request.content.text });
221
+ await rt.detectFacets(this.agent);
222
+ const record = {
223
+ $type: "app.bsky.feed.post",
224
+ text: rt.text,
225
+ facets: rt.facets,
226
+ createdAt: new Date().toISOString()
227
+ };
228
+ if (request.replyTo) {
229
+ record.reply = { root: request.replyTo, parent: request.replyTo };
230
+ }
231
+ if (request.content.embed) {
232
+ record.embed = request.content.embed;
233
+ }
234
+ const response = await this.agent.post(record);
235
+ const thread = await this.agent.getPostThread({
236
+ uri: response.uri,
237
+ depth: 0
238
+ });
239
+ if (thread.data.thread.$type !== "app.bsky.feed.defs#threadViewPost") {
240
+ throw new BlueSkyError("Failed to retrieve created post", "POST_CREATE_FAILED");
241
+ }
242
+ const threadViewPost = thread.data.thread;
243
+ return adaptPostView(threadViewPost.post);
244
+ }
245
+ async deletePost(uri) {
246
+ if (this.config.dryRun) {
247
+ import_core.logger.info(`Dry run: would delete post: ${uri}`);
248
+ return;
249
+ }
250
+ await this.agent.deletePost(uri);
251
+ }
252
+ async likePost(uri, cid) {
253
+ if (this.config.dryRun) {
254
+ import_core.logger.info(`Dry run: would like post: ${uri}`);
255
+ return;
256
+ }
257
+ await this.agent.like(uri, cid);
258
+ }
259
+ async repost(uri, cid) {
260
+ if (this.config.dryRun) {
261
+ import_core.logger.info({ uri }, "Dry run: would repost");
262
+ return;
263
+ }
264
+ await this.agent.repost(uri, cid);
265
+ }
266
+ async getNotifications(limit = 50, cursor) {
267
+ const response = await this.agent.listNotifications({ limit, cursor });
268
+ return {
269
+ notifications: response.data.notifications,
270
+ cursor: response.data.cursor
271
+ };
272
+ }
273
+ async updateSeenNotifications() {
274
+ await this.agent.updateSeenNotifications();
275
+ }
276
+ async getConversations(limit = 50, cursor) {
277
+ const response = await this.agent.api.chat.bsky.convo.listConvos({ limit, cursor }, { headers: { "atproto-proxy": BLUESKY_CHAT_SERVICE_DID } });
278
+ return {
279
+ conversations: response.data.convos,
280
+ cursor: response.data.cursor
281
+ };
282
+ }
283
+ async getMessages(convoId, limit = 50, cursor) {
284
+ const response = await this.agent.api.chat.bsky.convo.getMessages({ convoId, limit, cursor }, { headers: { "atproto-proxy": BLUESKY_CHAT_SERVICE_DID } });
285
+ return {
286
+ messages: response.data.messages,
287
+ cursor: response.data.cursor
288
+ };
289
+ }
290
+ async sendMessage(request) {
291
+ if (this.config.dryRun) {
292
+ import_core.logger.info({ convoId: request.convoId }, "Dry run: would send message");
293
+ return this.mockMessage(request.message.text ?? "");
294
+ }
295
+ const response = await this.agent.api.chat.bsky.convo.sendMessage({
296
+ convoId: request.convoId,
297
+ message: { text: request.message.text ?? "" }
298
+ }, { headers: { "atproto-proxy": BLUESKY_CHAT_SERVICE_DID } });
299
+ return response.data;
300
+ }
301
+ async cleanup() {
302
+ this.profileCache.clear();
303
+ this.session = null;
304
+ }
305
+ mockPost(text) {
306
+ const now = new Date().toISOString();
307
+ return {
308
+ uri: `mock://post/${Date.now()}`,
309
+ cid: `mock-cid-${Date.now()}`,
310
+ author: {
311
+ did: this.session?.did ?? "did:plc:mock",
312
+ handle: this.session?.handle ?? "mock.handle"
313
+ },
314
+ record: { $type: "app.bsky.feed.post", text, createdAt: now },
315
+ indexedAt: now
316
+ };
317
+ }
318
+ mockMessage(text) {
319
+ return {
320
+ id: `mock-msg-${Date.now()}`,
321
+ rev: "1",
322
+ text,
323
+ sender: { did: this.session?.did ?? "did:plc:mock" },
324
+ sentAt: new Date().toISOString()
325
+ };
326
+ }
327
+ }
328
+
329
+ // managers/agent.ts
330
+ var import_core2 = require("@elizaos/core");
331
+
332
+ // utils/config.ts
333
+ function getApiKeyOptional(runtime, key) {
334
+ const value = runtime.getSetting(key);
335
+ return typeof value === "string" ? value : undefined;
336
+ }
337
+ function hasBlueSkyEnabled(runtime) {
338
+ const enabled = runtime.getSetting("BLUESKY_ENABLED");
339
+ if (enabled)
340
+ return String(enabled).toLowerCase() === "true";
341
+ return Boolean(runtime.getSetting("BLUESKY_HANDLE") && runtime.getSetting("BLUESKY_PASSWORD"));
342
+ }
343
+ function validateBlueSkyConfig(runtime) {
344
+ const result = BlueSkyConfigSchema.safeParse({
345
+ handle: String(runtime.getSetting("BLUESKY_HANDLE") ?? ""),
346
+ password: String(runtime.getSetting("BLUESKY_PASSWORD") ?? ""),
347
+ service: String(runtime.getSetting("BLUESKY_SERVICE") ?? BLUESKY_SERVICE_URL),
348
+ dryRun: runtime.getSetting("BLUESKY_DRY_RUN") === "true",
349
+ pollInterval: parseInt(String(runtime.getSetting("BLUESKY_POLL_INTERVAL") ?? ""), 10) || BLUESKY_POLL_INTERVAL,
350
+ enablePost: runtime.getSetting("BLUESKY_ENABLE_POSTING") !== "false",
351
+ postIntervalMin: parseInt(String(runtime.getSetting("BLUESKY_POST_INTERVAL_MIN") ?? ""), 10) || BLUESKY_POST_INTERVAL_MIN,
352
+ postIntervalMax: parseInt(String(runtime.getSetting("BLUESKY_POST_INTERVAL_MAX") ?? ""), 10) || BLUESKY_POST_INTERVAL_MAX,
353
+ enableActionProcessing: runtime.getSetting("BLUESKY_ENABLE_ACTION_PROCESSING") !== "false",
354
+ actionInterval: parseInt(String(runtime.getSetting("BLUESKY_ACTION_INTERVAL") ?? ""), 10) || BLUESKY_ACTION_INTERVAL,
355
+ postImmediately: runtime.getSetting("BLUESKY_POST_IMMEDIATELY") === "true",
356
+ maxActionsProcessing: parseInt(String(runtime.getSetting("BLUESKY_MAX_ACTIONS_PROCESSING") ?? ""), 10) || BLUESKY_MAX_ACTIONS,
357
+ enableDMs: runtime.getSetting("BLUESKY_ENABLE_DMS") !== "false"
358
+ });
359
+ if (!result.success) {
360
+ const errors = result.error.errors?.map((e) => `${e.path.join(".")}: ${e.message}`).join(", ") || result.error.toString();
361
+ throw new Error(`Invalid BlueSky configuration: ${errors}`);
362
+ }
363
+ return result.data;
364
+ }
365
+ function getPollInterval(runtime) {
366
+ const seconds = parseInt(String(runtime.getSetting("BLUESKY_POLL_INTERVAL") ?? ""), 10) || BLUESKY_POLL_INTERVAL;
367
+ return seconds * 1000;
368
+ }
369
+ function getActionInterval(runtime) {
370
+ const seconds = parseInt(String(runtime.getSetting("BLUESKY_ACTION_INTERVAL") ?? ""), 10) || BLUESKY_ACTION_INTERVAL;
371
+ return seconds * 1000;
372
+ }
373
+ function getMaxActionsProcessing(runtime) {
374
+ return parseInt(String(runtime.getSetting("BLUESKY_MAX_ACTIONS_PROCESSING") ?? ""), 10) || BLUESKY_MAX_ACTIONS;
375
+ }
376
+ function isPostingEnabled(runtime) {
377
+ return runtime.getSetting("BLUESKY_ENABLE_POSTING") !== "false";
378
+ }
379
+ function shouldPostImmediately(runtime) {
380
+ return runtime.getSetting("BLUESKY_POST_IMMEDIATELY") === "true";
381
+ }
382
+ function getPostIntervalRange(runtime) {
383
+ const min = parseInt(String(runtime.getSetting("BLUESKY_POST_INTERVAL_MIN") ?? ""), 10) || BLUESKY_POST_INTERVAL_MIN;
384
+ const max = parseInt(String(runtime.getSetting("BLUESKY_POST_INTERVAL_MAX") ?? ""), 10) || BLUESKY_POST_INTERVAL_MAX;
385
+ return { min: min * 1000, max: max * 1000 };
386
+ }
387
+
388
+ // managers/agent.ts
389
+ class BlueSkyAgentManager {
390
+ runtime;
391
+ config;
392
+ client;
393
+ pollTimer = null;
394
+ actionTimer = null;
395
+ postTimer = null;
396
+ running = false;
397
+ lastSeenAt = null;
398
+ constructor(runtime, config, client) {
399
+ this.runtime = runtime;
400
+ this.config = config;
401
+ this.client = client;
402
+ }
403
+ async start() {
404
+ if (this.running)
405
+ return;
406
+ await this.client.authenticate();
407
+ this.running = true;
408
+ this.startNotificationPolling();
409
+ if (this.config.enableActionProcessing) {
410
+ this.startActionProcessing();
411
+ }
412
+ if (isPostingEnabled(this.runtime)) {
413
+ this.startAutomatedPosting();
414
+ }
415
+ import_core2.logger.success({ agentId: this.runtime.agentId }, "BlueSky agent manager started");
416
+ }
417
+ async stop() {
418
+ this.running = false;
419
+ if (this.pollTimer)
420
+ clearInterval(this.pollTimer);
421
+ if (this.actionTimer)
422
+ clearInterval(this.actionTimer);
423
+ if (this.postTimer)
424
+ clearTimeout(this.postTimer);
425
+ this.pollTimer = null;
426
+ this.actionTimer = null;
427
+ this.postTimer = null;
428
+ await this.client.cleanup();
429
+ import_core2.logger.info({ agentId: this.runtime.agentId }, "BlueSky agent manager stopped");
430
+ }
431
+ startNotificationPolling() {
432
+ const interval = getPollInterval(this.runtime);
433
+ this.pollNotifications();
434
+ this.pollTimer = setInterval(() => this.pollNotifications(), interval);
435
+ }
436
+ async pollNotifications() {
437
+ if (!this.running)
438
+ return;
439
+ const { notifications } = await this.client.getNotifications(50);
440
+ if (notifications.length === 0)
441
+ return;
442
+ const newNotifications = this.lastSeenAt ? notifications.filter((n) => {
443
+ const lastSeen = this.lastSeenAt;
444
+ return lastSeen !== null && n.indexedAt > lastSeen;
445
+ }) : notifications;
446
+ if (newNotifications.length > 0) {
447
+ this.lastSeenAt = notifications[0].indexedAt;
448
+ for (const notification of newNotifications) {
449
+ this.emitNotificationEvent(notification);
450
+ }
451
+ await this.client.updateSeenNotifications();
452
+ }
453
+ }
454
+ emitNotificationEvent(notification) {
455
+ const eventMap = {
456
+ mention: "bluesky.mention_received",
457
+ reply: "bluesky.mention_received",
458
+ follow: "bluesky.follow_received",
459
+ like: "bluesky.like_received",
460
+ repost: "bluesky.repost_received",
461
+ quote: "bluesky.quote_received"
462
+ };
463
+ const event = eventMap[notification.reason];
464
+ if (event) {
465
+ const payload = {
466
+ runtime: this.runtime,
467
+ source: "bluesky",
468
+ notification
469
+ };
470
+ this.runtime.emitEvent(event, payload);
471
+ }
472
+ }
473
+ startActionProcessing() {
474
+ const interval = getActionInterval(this.runtime);
475
+ this.processActions();
476
+ this.actionTimer = setInterval(() => this.processActions(), interval);
477
+ }
478
+ async processActions() {
479
+ if (!this.running)
480
+ return;
481
+ const max = getMaxActionsProcessing(this.runtime);
482
+ const { notifications } = await this.client.getNotifications(max);
483
+ for (const notification of notifications) {
484
+ if (notification.reason === "mention" || notification.reason === "reply") {
485
+ const payload = {
486
+ runtime: this.runtime,
487
+ source: "bluesky",
488
+ notification
489
+ };
490
+ this.runtime.emitEvent("bluesky.should_respond", payload);
491
+ }
492
+ }
493
+ }
494
+ startAutomatedPosting() {
495
+ if (shouldPostImmediately(this.runtime)) {
496
+ this.createAutomatedPost();
497
+ }
498
+ this.scheduleNextPost();
499
+ }
500
+ scheduleNextPost() {
501
+ const { min, max } = getPostIntervalRange(this.runtime);
502
+ const interval = Math.random() * (max - min) + min;
503
+ this.postTimer = setTimeout(() => {
504
+ if (this.running) {
505
+ this.createAutomatedPost();
506
+ this.scheduleNextPost();
507
+ }
508
+ }, interval);
509
+ }
510
+ createAutomatedPost() {
511
+ const payload = {
512
+ runtime: this.runtime,
513
+ source: "bluesky",
514
+ automated: true
515
+ };
516
+ this.runtime.emitEvent("bluesky.create_post", payload);
517
+ }
518
+ }
519
+
520
+ // services/message.ts
521
+ var import_core3 = require("@elizaos/core");
522
+
523
+ // generated/prompts/typescript/prompts.ts
524
+ var generateDmTemplate = `Generate a friendly direct message response under 200 characters.`;
525
+ var generatePostTemplate = `Generate an engaging BlueSky post under {{maxLength}} characters.`;
526
+ var truncatePostTemplate = `Shorten to under {{maxLength}} characters: "{{text}}"`;
527
+
528
+ // services/message.ts
529
+ class BlueSkyMessageService {
530
+ client;
531
+ runtime;
532
+ static serviceType = "IMessageService";
533
+ constructor(client, runtime) {
534
+ this.client = client;
535
+ this.runtime = runtime;
536
+ }
537
+ async getMessages(convoId, limit = 50) {
538
+ const response = await this.client.getMessages(convoId, limit);
539
+ return response.messages;
540
+ }
541
+ async sendMessage(convoId, text) {
542
+ const messageText = text.trim() || await this.generateReply();
543
+ return this.client.sendMessage({ convoId, message: { text: messageText } });
544
+ }
545
+ async getConversations(limit = 50) {
546
+ const response = await this.client.getConversations(limit);
547
+ return response.conversations;
548
+ }
549
+ async generateReply() {
550
+ const prompt = import_core3.composePrompt({
551
+ state: {},
552
+ template: generateDmTemplate
553
+ });
554
+ const response = await this.runtime.useModel(import_core3.ModelType.TEXT_SMALL, {
555
+ prompt,
556
+ maxTokens: 50
557
+ });
558
+ return response;
559
+ }
560
+ }
561
+
562
+ // services/post.ts
563
+ var import_core4 = require("@elizaos/core");
564
+ class BlueSkyPostService {
565
+ client;
566
+ runtime;
567
+ static serviceType = "IPostService";
568
+ constructor(client, runtime) {
569
+ this.client = client;
570
+ this.runtime = runtime;
571
+ }
572
+ async getPosts(limit = 50, cursor) {
573
+ const response = await this.client.getTimeline({ limit, cursor });
574
+ return response.feed.map((item) => item.post);
575
+ }
576
+ async createPost(text, replyTo) {
577
+ let postText = text.trim() || await this.generateContent();
578
+ if (postText.length > BLUESKY_MAX_POST_LENGTH) {
579
+ postText = await this.truncate(postText);
580
+ }
581
+ const request = {
582
+ content: { text: postText },
583
+ replyTo
584
+ };
585
+ return this.client.sendPost(request);
586
+ }
587
+ async deletePost(uri) {
588
+ await this.client.deletePost(uri);
589
+ }
590
+ async generateContent() {
591
+ const prompt = import_core4.composePrompt({
592
+ state: {
593
+ maxLength: String(BLUESKY_MAX_POST_LENGTH)
594
+ },
595
+ template: generatePostTemplate
596
+ });
597
+ const response = await this.runtime.useModel(import_core4.ModelType.TEXT_SMALL, {
598
+ prompt,
599
+ maxTokens: 100
600
+ });
601
+ return response;
602
+ }
603
+ async truncate(text) {
604
+ const prompt = import_core4.composePrompt({
605
+ state: {
606
+ maxLength: String(BLUESKY_MAX_POST_LENGTH),
607
+ text
608
+ },
609
+ template: truncatePostTemplate
610
+ });
611
+ const response = await this.runtime.useModel(import_core4.ModelType.TEXT_SMALL, {
612
+ prompt,
613
+ maxTokens: 100
614
+ });
615
+ const truncated = response;
616
+ return truncated.length > BLUESKY_MAX_POST_LENGTH ? `${truncated.substring(0, BLUESKY_MAX_POST_LENGTH - 3)}...` : truncated;
617
+ }
618
+ }
619
+
620
+ // services/bluesky.ts
621
+ class BlueSkyService extends import_core5.Service {
622
+ static instance;
623
+ managers = new Map;
624
+ messageServices = new Map;
625
+ postServices = new Map;
626
+ static serviceType = BLUESKY_SERVICE_NAME;
627
+ capabilityDescription = "Send and receive messages on BlueSky";
628
+ static getInstance() {
629
+ BlueSkyService.instance ??= new BlueSkyService;
630
+ return BlueSkyService.instance;
631
+ }
632
+ static async start(runtime) {
633
+ const service = BlueSkyService.getInstance();
634
+ if (service.managers.has(runtime.agentId)) {
635
+ return service;
636
+ }
637
+ if (!hasBlueSkyEnabled(runtime)) {
638
+ return service;
639
+ }
640
+ const config = validateBlueSkyConfig(runtime);
641
+ const client = new BlueSkyClient({
642
+ service: config.service,
643
+ handle: config.handle,
644
+ password: config.password,
645
+ dryRun: config.dryRun
646
+ });
647
+ const manager = new BlueSkyAgentManager(runtime, config, client);
648
+ service.managers.set(runtime.agentId, manager);
649
+ service.messageServices.set(runtime.agentId, new BlueSkyMessageService(client, runtime));
650
+ service.postServices.set(runtime.agentId, new BlueSkyPostService(client, runtime));
651
+ await manager.start();
652
+ import_core5.logger.success({ agentId: runtime.agentId }, "BlueSky client started");
653
+ return service;
654
+ }
655
+ static async stop(runtime) {
656
+ const service = BlueSkyService.getInstance();
657
+ const manager = service.managers.get(runtime.agentId);
658
+ if (!manager)
659
+ return;
660
+ await manager.stop();
661
+ service.managers.delete(runtime.agentId);
662
+ service.messageServices.delete(runtime.agentId);
663
+ service.postServices.delete(runtime.agentId);
664
+ import_core5.logger.info({ agentId: runtime.agentId }, "BlueSky client stopped");
665
+ }
666
+ async stop() {
667
+ for (const manager of this.managers.values()) {
668
+ await BlueSkyService.stop(manager.runtime);
669
+ }
670
+ }
671
+ getMessageService(agentId) {
672
+ return this.messageServices.get(agentId);
673
+ }
674
+ getPostService(agentId) {
675
+ return this.postServices.get(agentId);
676
+ }
677
+ }
678
+
679
+ // index.ts
680
+ var pluginTests = [
681
+ {
682
+ name: "bluesky_plugin_tests",
683
+ tests: [
684
+ {
685
+ name: "bluesky_test_credentials_validation",
686
+ fn: async (runtime) => {
687
+ const handle = getApiKeyOptional(runtime, "BLUESKY_HANDLE");
688
+ const password = getApiKeyOptional(runtime, "BLUESKY_PASSWORD");
689
+ if (!handle || !password) {
690
+ throw new Error("BLUESKY_HANDLE and BLUESKY_PASSWORD are not configured");
691
+ }
692
+ import_core6.logger.log("BlueSky credentials are configured");
693
+ }
694
+ },
695
+ {
696
+ name: "bluesky_test_service_initialization",
697
+ fn: async (runtime) => {
698
+ const handle = getApiKeyOptional(runtime, "BLUESKY_HANDLE");
699
+ const password = getApiKeyOptional(runtime, "BLUESKY_PASSWORD");
700
+ if (!handle || !password) {
701
+ import_core6.logger.log("Skipping service initialization test - credentials not configured");
702
+ return;
703
+ }
704
+ const service = await BlueSkyService.start(runtime);
705
+ if (!service) {
706
+ throw new Error("Failed to initialize BlueSky service");
707
+ }
708
+ import_core6.logger.log("BlueSky service initialized successfully");
709
+ }
710
+ }
711
+ ]
712
+ }
713
+ ];
714
+ var blueSkyPlugin = {
715
+ name: "bluesky",
716
+ description: "BlueSky client plugin using AT Protocol for social interactions",
717
+ config: {
718
+ BLUESKY_HANDLE: process.env.BLUESKY_HANDLE ?? null,
719
+ BLUESKY_PASSWORD: process.env.BLUESKY_PASSWORD ?? null,
720
+ BLUESKY_SERVICE: process.env.BLUESKY_SERVICE ?? null,
721
+ BLUESKY_DRY_RUN: process.env.BLUESKY_DRY_RUN ?? null,
722
+ BLUESKY_POLL_INTERVAL: process.env.BLUESKY_POLL_INTERVAL ?? null,
723
+ BLUESKY_ENABLE_POSTING: process.env.BLUESKY_ENABLE_POSTING ?? null,
724
+ BLUESKY_ENABLE_DMS: process.env.BLUESKY_ENABLE_DMS ?? null,
725
+ BLUESKY_POST_INTERVAL_MIN: process.env.BLUESKY_POST_INTERVAL_MIN ?? null,
726
+ BLUESKY_POST_INTERVAL_MAX: process.env.BLUESKY_POST_INTERVAL_MAX ?? null,
727
+ BLUESKY_ENABLE_ACTION_PROCESSING: process.env.BLUESKY_ENABLE_ACTION_PROCESSING ?? null,
728
+ BLUESKY_ACTION_INTERVAL: process.env.BLUESKY_ACTION_INTERVAL ?? null,
729
+ BLUESKY_POST_IMMEDIATELY: process.env.BLUESKY_POST_IMMEDIATELY ?? null,
730
+ BLUESKY_MAX_ACTIONS_PROCESSING: process.env.BLUESKY_MAX_ACTIONS_PROCESSING ?? null,
731
+ BLUESKY_MAX_POST_LENGTH: process.env.BLUESKY_MAX_POST_LENGTH ?? null
732
+ },
733
+ async init(_config, _runtime) {
734
+ import_core6.logger.log("BlueSky plugin initialized");
735
+ },
736
+ services: [BlueSkyService],
737
+ tests: pluginTests
738
+ };
739
+ var typescript_default = blueSkyPlugin;
740
+
741
+ //# debugId=8563B0C8EA46B71664756E2164756E21