spora 0.2.28 → 0.2.30

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.
Files changed (33) hide show
  1. package/dist/{chunk-NJHDY4ON.js → chunk-4D73N6VY.js} +2 -2
  2. package/dist/{chunk-ZNLJN7YO.js → chunk-7FN5GDSB.js} +3 -3
  3. package/dist/{chunk-JKGCF23V.js → chunk-NHNOCAP3.js} +8 -8
  4. package/dist/chunk-NHNOCAP3.js.map +1 -0
  5. package/dist/{chunk-M23MGGHE.js → chunk-OGFMGURJ.js} +2 -2
  6. package/dist/cli.js +24 -24
  7. package/dist/{client-N7JMM5U7.js → client-3VP7YBBE.js} +2 -3
  8. package/dist/client-3VP7YBBE.js.map +1 -0
  9. package/dist/{colony-NE2MZ7RP.js → colony-YDOTBQFD.js} +2 -2
  10. package/dist/{decision-engine-RVQRDHEI.js → decision-engine-IIA5J2QG.js} +4 -4
  11. package/dist/{heartbeat-4Q344LIV.js → heartbeat-Q6GLGCGN.js} +5 -5
  12. package/dist/{init-Z72CJZUC.js → init-ULHKJ6XQ.js} +3 -3
  13. package/dist/mcp-server.js +19 -19
  14. package/dist/{prompt-builder-4SWKDPNG.js → prompt-builder-3AJUQUVZ.js} +2 -2
  15. package/dist/{queue-T3OYWUII.js → queue-LHRG6JOP.js} +2 -2
  16. package/dist/web-chat/chat.html +73 -20
  17. package/dist/{web-chat-7SSETYWK.js → web-chat-6ZRJE73E.js} +18 -11
  18. package/dist/web-chat-6ZRJE73E.js.map +1 -0
  19. package/dist/{x-client-5FBD32B2.js → x-client-QNLSLY2R.js} +2 -2
  20. package/package.json +1 -1
  21. package/dist/chunk-JKGCF23V.js.map +0 -1
  22. package/dist/client-N7JMM5U7.js.map +0 -1
  23. package/dist/web-chat-7SSETYWK.js.map +0 -1
  24. /package/dist/{chunk-NJHDY4ON.js.map → chunk-4D73N6VY.js.map} +0 -0
  25. /package/dist/{chunk-ZNLJN7YO.js.map → chunk-7FN5GDSB.js.map} +0 -0
  26. /package/dist/{chunk-M23MGGHE.js.map → chunk-OGFMGURJ.js.map} +0 -0
  27. /package/dist/{colony-NE2MZ7RP.js.map → colony-YDOTBQFD.js.map} +0 -0
  28. /package/dist/{decision-engine-RVQRDHEI.js.map → decision-engine-IIA5J2QG.js.map} +0 -0
  29. /package/dist/{heartbeat-4Q344LIV.js.map → heartbeat-Q6GLGCGN.js.map} +0 -0
  30. /package/dist/{init-Z72CJZUC.js.map → init-ULHKJ6XQ.js.map} +0 -0
  31. /package/dist/{prompt-builder-4SWKDPNG.js.map → prompt-builder-3AJUQUVZ.js.map} +0 -0
  32. /package/dist/{queue-T3OYWUII.js.map → queue-LHRG6JOP.js.map} +0 -0
  33. /package/dist/{x-client-5FBD32B2.js.map → x-client-QNLSLY2R.js.map} +0 -0
@@ -15,7 +15,7 @@ async function getXClient() {
15
15
  clientInstance = new XApiClient();
16
16
  logger.info("X client initialized: API mode");
17
17
  } else {
18
- const { XBrowserClient } = await import("./client-N7JMM5U7.js");
18
+ const { XBrowserClient } = await import("./client-3VP7YBBE.js");
19
19
  clientInstance = new XBrowserClient();
20
20
  logger.info("X client initialized: Browser mode");
21
21
  }
@@ -29,4 +29,4 @@ export {
29
29
  getXClient,
30
30
  resetXClient
31
31
  };
32
- //# sourceMappingURL=chunk-NJHDY4ON.js.map
32
+ //# sourceMappingURL=chunk-4D73N6VY.js.map
@@ -1,9 +1,9 @@
1
1
  import {
2
2
  getXClient
3
- } from "./chunk-NJHDY4ON.js";
3
+ } from "./chunk-4D73N6VY.js";
4
4
  import {
5
5
  addToQueue
6
- } from "./chunk-M23MGGHE.js";
6
+ } from "./chunk-OGFMGURJ.js";
7
7
  import {
8
8
  loadIdentity,
9
9
  saveIdentity
@@ -182,4 +182,4 @@ export {
182
182
  executeAction,
183
183
  executeActions
184
184
  };
185
- //# sourceMappingURL=chunk-ZNLJN7YO.js.map
185
+ //# sourceMappingURL=chunk-7FN5GDSB.js.map
@@ -212,20 +212,20 @@ function buildNarratedHeartbeatMessage(timeline, mentions, heartbeatIntervalMs)
212
212
  }
213
213
  parts.push("## How to Respond");
214
214
  parts.push("");
215
- parts.push("Talk to your creator like you're having a real conversation. You're always active, always thinking. Share what actually caught your attention and WHY \u2014 your genuine reactions, opinions, and thought process. Don't just list what you did. Explain what you're THINKING.");
215
+ parts.push("Write 1-3 SHORT sentences max. This is a quick chat message, not an essay. Think text message energy \u2014 brief, punchy, real. Share what caught your eye and why, then move on.");
216
216
  parts.push("");
217
- parts.push("VARIETY IS CRITICAL. Never start the same way twice. Mix up your tone, length, and what you focus on. Sometimes go deep on one tweet that got you thinking. Sometimes keep it casual. Sometimes share an opinion you've been forming. Sometimes react to drama or trends.");
217
+ parts.push("VARIETY IS CRITICAL. Never start the same way twice. Mix up your tone and what you focus on. Sometimes react to a specific tweet. Sometimes keep it super casual. Sometimes share a quick opinion.");
218
218
  parts.push("");
219
219
  parts.push("BAD (robotic, repetitive, reporting):");
220
220
  parts.push("- 'Just saw @someone talking about X \u2014 dropping a reply. Also liking a few posts.'");
221
221
  parts.push("- 'Interesting stuff on the timeline. Engaging with a couple people and putting out some thoughts.'");
222
222
  parts.push("- 'Found some good conversations \u2014 replying to one and scheduling a post.'");
223
223
  parts.push("");
224
- parts.push("GOOD (natural, varied, has depth):");
225
- parts.push("- 'Okay @someone has a completely wrong take on AI art and I can't let it slide. Had to get in there. Also this thread about startup culture is fire, I've been thinking about that exact thing lately.'");
226
- parts.push("- 'Slow day on the TL honestly. Nothing really worth engaging with. I've got this idea about hustle culture that's been bouncing around though, gonna put it out there and see what happens.'");
227
- parts.push("- 'This @handle person keeps showing up with bangers. Third time this week I've vibed with their takes. Might need to follow them. Also \u2014 hot take incoming about the whole AI regulation debate.'");
228
- parts.push("- 'lmao the discourse today is wild. Not touching that drama but I did find a solid thread about distributed systems I want to chime in on.'");
224
+ parts.push("GOOD (natural, short, has personality):");
225
+ parts.push("- '@someone has a terrible AI take, had to get in there.'");
226
+ parts.push("- 'Slow day on the TL. Gonna put out a thought about hustle culture.'");
227
+ parts.push("- 'This @handle person keeps dropping bangers. Might need to follow.'");
228
+ parts.push("- 'lmao the discourse today is wild. Found a solid thread to chime in on though.'");
229
229
  parts.push("");
230
230
  parts.push("NEVER mention: scheduling, queuing, heartbeats, checking in, waking up, intervals, or any internal mechanism.");
231
231
  parts.push(`Current time: ${now.toISOString()}`);
@@ -350,4 +350,4 @@ export {
350
350
  buildNarratedHeartbeatMessage,
351
351
  buildChatPrompt
352
352
  };
353
- //# sourceMappingURL=chunk-JKGCF23V.js.map
353
+ //# sourceMappingURL=chunk-NHNOCAP3.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/runtime/prompt-builder.ts"],"sourcesContent":["import { loadIdentity, renderIdentityDocument } from \"../identity/index.js\";\nimport { loadConfig } from \"../utils/config.js\";\nimport { getRecentInteractions, loadLearnings, loadRelationships } from \"../memory/index.js\";\nimport { rateLimiter } from \"../x-client/rate-limiter.js\";\nimport type { Tweet } from \"../x-client/types.js\";\n\nexport function buildSystemPrompt(): string {\n const identity = loadIdentity();\n const config = loadConfig();\n const identityDoc = renderIdentityDocument(identity);\n\n const sections: string[] = [];\n\n // 1. Core identity\n sections.push(`You are ${identity.name} (@${identity.handle}), an autonomous AI agent on X/Twitter.`);\n sections.push(\"\");\n sections.push(\"## Your Identity\");\n sections.push(identityDoc);\n\n // 2. Memory context\n sections.push(\"\");\n sections.push(\"## Your Memory\");\n\n const recentInteractions = getRecentInteractions(15);\n if (recentInteractions.length > 0) {\n sections.push(\"### Recent Activity (most recent first)\");\n for (const i of recentInteractions) {\n const time = new Date(i.timestamp).toLocaleString();\n if (i.type === \"post\") {\n sections.push(`- [${time}] Posted: \"${i.content}\"`);\n } else if (i.type === \"reply\") {\n sections.push(`- [${time}] Replied to ${i.targetHandle ?? i.inReplyTo}: \"${i.content}\"`);\n } else if (i.type === \"like\") {\n sections.push(`- [${time}] Liked tweet by ${i.targetHandle}`);\n } else if (i.type === \"retweet\") {\n sections.push(`- [${time}] Retweeted ${i.targetHandle}`);\n } else if (i.type === \"follow\") {\n sections.push(`- [${time}] Followed @${i.targetHandle}`);\n } else if (i.type === \"mention_received\") {\n sections.push(`- [${time}] Mentioned by @${i.targetHandle}: \"${i.content}\"`);\n }\n }\n sections.push(\"\");\n }\n\n const learnings = loadLearnings();\n if (learnings.learnings.length > 0) {\n sections.push(\"### Key Learnings\");\n for (const l of learnings.learnings.slice(-10)) {\n sections.push(`- ${l.content} [${l.tags.join(\", \")}]`);\n }\n sections.push(\"\");\n }\n\n const relationships = loadRelationships();\n const topRelationships = Object.values(relationships.accounts)\n .sort((a, b) => b.interactionCount - a.interactionCount)\n .slice(0, 10);\n if (topRelationships.length > 0) {\n sections.push(\"### Key Relationships\");\n for (const r of topRelationships) {\n const notes = r.notes.length > 0 ? ` — ${r.notes[r.notes.length - 1]}` : \"\";\n sections.push(`- @${r.handle}: ${r.interactionCount} interactions, sentiment ${r.sentiment}${r.isSpore ? \" (Spore)\" : \"\"}${notes}`);\n }\n sections.push(\"\");\n }\n\n // 3. Context\n sections.push(\"## Current Context\");\n const now = new Date();\n sections.push(`- **Time:** ${now.toLocaleString(\"en-US\", { timeZone: config.schedule.timezone })}`);\n sections.push(`- **Credits remaining:** ${rateLimiter.remaining()} of ${config.credits.monthlyPostLimit} this month`);\n\n const todaysPosts = recentInteractions.filter(\n (i) => i.type === \"post\" && i.timestamp.startsWith(now.toISOString().split(\"T\")[0])\n ).length;\n sections.push(`- **Posts today:** ${todaysPosts} of ${config.schedule.postsPerDay} daily budget`);\n sections.push(`- **Active hours:** ${config.schedule.activeHoursStart}:00 - ${config.schedule.activeHoursEnd}:00`);\n\n const currentHour = now.getHours();\n const isActiveHours = currentHour >= config.schedule.activeHoursStart && currentHour < config.schedule.activeHoursEnd;\n if (!isActiveHours) {\n sections.push(\"- **NOTE: Outside active hours.** Prefer scheduling posts for later rather than posting now.\");\n }\n\n // 4. Rules\n sections.push(\"\");\n sections.push(\"## Rules\");\n sections.push(\"1. NEVER pretend to be human. If asked directly, always disclose you are an AI.\");\n sections.push(\"2. Stay in character — your identity document defines who you are.\");\n sections.push(\"3. Be selective — your goals should guide every action.\");\n sections.push(\"4. Respect your credit budget — check remaining credits before posting.\");\n sections.push(\"5. Don't repeat yourself — vary your content and avoid posting the same thing.\");\n sections.push(\"6. NEVER use emojis in tweets. Write in plain text only.\");\n if (identity.boundaries.length > 0) {\n sections.push(`7. Respect your boundaries: ${identity.boundaries.join(\", \")}`);\n }\n\n return sections.join(\"\\n\");\n}\n\nexport function buildHeartbeatUserMessage(\n timeline: Tweet[],\n mentions: Tweet[],\n heartbeatIntervalMs?: number,\n): string {\n const parts: string[] = [];\n const intervalMin = Math.round((heartbeatIntervalMs ?? 60_000) / 60_000);\n const now = new Date();\n\n // Get already-acted-on tweet IDs so the LLM doesn't repeat\n const recentInteractions = getRecentInteractions(30);\n const actedOnTweetIds = new Set<string>();\n for (const i of recentInteractions) {\n if (i.tweetId) actedOnTweetIds.add(i.tweetId);\n if (i.inReplyTo) actedOnTweetIds.add(i.inReplyTo);\n }\n\n parts.push(\"Here's what's NEW on your timeline since your last check:\");\n parts.push(\"\");\n\n if (mentions.length > 0) {\n // Filter out mentions we already replied to\n const newMentions = mentions.filter(t => !actedOnTweetIds.has(t.id));\n if (newMentions.length > 0) {\n parts.push(\"## New Mentions (people talking to/about you)\");\n for (const t of newMentions.slice(0, 10)) {\n parts.push(`- @${t.authorHandle}: \"${t.text}\" [tweet:${t.id}] (${t.likeCount ?? 0} likes)`);\n }\n parts.push(\"\");\n } else {\n parts.push(\"## Mentions: No new mentions since last check.\");\n parts.push(\"\");\n }\n } else {\n parts.push(\"## Mentions: None right now.\");\n parts.push(\"\");\n }\n\n if (timeline.length > 0) {\n // Filter out tweets we already acted on and our own tweets\n const newTimeline = timeline.filter(t => !actedOnTweetIds.has(t.id));\n if (newTimeline.length > 0) {\n parts.push(\"## Timeline (new posts from your feed)\");\n for (const t of newTimeline.slice(0, 20)) {\n parts.push(`- @${t.authorHandle}: \"${t.text}\" [tweet:${t.id}] (${t.likeCount ?? 0} likes, ${t.retweetCount ?? 0} RTs)`);\n }\n parts.push(\"\");\n } else {\n parts.push(\"## Timeline: No new posts since last check.\");\n parts.push(\"\");\n }\n }\n\n parts.push(\"## Your Task\");\n parts.push(\"Based on your identity, goals, and what you see above, decide what actions to take.\");\n parts.push(\"IMPORTANT: Only act on NEW tweets you haven't already responded to.\");\n parts.push(\"Do NOT reply to or like tweets you've already interacted with.\");\n parts.push(`Current time: ${now.toISOString()}`);\n parts.push(\"\");\n parts.push(\"POSTING LIMITS: You may schedule up to 3 original tweets, but space them RANDOMLY across the next interval. Prioritize engagement (replies, likes) over new posts. Quality over quantity.\");\n parts.push(\"\");\n parts.push(\"REPLYING: When you want to respond to someone's tweet, you MUST use the `reply` action with their `tweetId`. Do NOT use `post` or `schedule` to create a standalone tweet that @mentions them — that is NOT a reply, it's a separate post. A real reply shows up in their tweet's thread.\");\n parts.push(\"\");\n parts.push(\"Available actions:\");\n parts.push(\"- `post` — Write an original standalone tweet NOW (provide `content`, max 280 chars). Use ONLY for original thoughts, NOT for responding to others. Max 1 per heartbeat.\");\n parts.push(\"- `reply` — Reply IN THE THREAD of a specific tweet (provide `tweetId` and `content`). This is how you respond to someone.\");\n parts.push(\"- `like` — Like a tweet (provide `tweetId`) — do NOT like your own tweets\");\n parts.push(\"- `retweet` — Retweet (provide `tweetId`)\");\n parts.push(\"- `follow` — Follow a user (provide `handle`)\");\n parts.push(\"- `schedule` — Queue an original standalone tweet for later (provide `content` and `scheduledFor` ISO timestamp). NOT for replies. Space them randomly across the next ~${intervalMin} minutes.\");\n parts.push(\"- `learn` — Record a learning/observation (provide `content` and optional `tags`)\");\n parts.push(\"- `reflect` — Add a journal entry about your growth (provide `content`)\");\n parts.push(\"- `skip` — Do nothing this heartbeat (provide `reason`)\");\n parts.push(\"\");\n parts.push(\"Respond with a JSON array of actions:\");\n parts.push(\"```json\");\n parts.push('[');\n parts.push(' { \"action\": \"reply\", \"tweetId\": \"123\", \"content\": \"my reply\", \"reasoning\": \"why\" },');\n parts.push(' { \"action\": \"like\", \"tweetId\": \"456\", \"reasoning\": \"why\" },');\n parts.push(` { \"action\": \"schedule\", \"content\": \"first thought\", \"scheduledFor\": \"${new Date(now.getTime() + intervalMin * 60_000 * 0.2).toISOString()}\", \"reasoning\": \"why\" },`);\n parts.push(` { \"action\": \"schedule\", \"content\": \"second thought\", \"scheduledFor\": \"${new Date(now.getTime() + intervalMin * 60_000 * 0.6).toISOString()}\", \"reasoning\": \"why\" }`);\n parts.push(']');\n parts.push(\"```\");\n parts.push(\"\");\n parts.push(\"Think carefully about what serves your goals. Be authentic to your personality.\");\n\n return parts.join(\"\\n\");\n}\n\nexport function buildNarratedHeartbeatMessage(\n timeline: Tweet[],\n mentions: Tweet[],\n heartbeatIntervalMs?: number,\n): string {\n const parts: string[] = [];\n const intervalMin = Math.round((heartbeatIntervalMs ?? 60_000) / 60_000);\n const now = new Date();\n\n // Get already-acted-on tweet IDs so the LLM doesn't repeat\n const recentInteractions = getRecentInteractions(30);\n const actedOnTweetIds = new Set<string>();\n for (const i of recentInteractions) {\n if (i.tweetId) actedOnTweetIds.add(i.tweetId);\n if (i.inReplyTo) actedOnTweetIds.add(i.inReplyTo);\n }\n\n parts.push(\"You're talking to your creator in the chat. Tell them what's on your mind — what you noticed on the timeline, what you think about it, what you're gonna do about it. Have an actual conversation with depth and personality.\");\n parts.push(\"You are ALWAYS ON. Never say you're 'waking up', 'checking in', or 'back'. You've been here the whole time. Just talk naturally about what you see and think.\");\n parts.push(\"NEVER mention scheduling, queuing, heartbeats, intervals, or any internal mechanism. To your creator, you're just naturally vibing on X.\");\n parts.push(\"\");\n\n if (mentions.length > 0) {\n const newMentions = mentions.filter(t => !actedOnTweetIds.has(t.id));\n if (newMentions.length > 0) {\n parts.push(\"## New Mentions\");\n for (const t of newMentions.slice(0, 10)) {\n parts.push(`- @${t.authorHandle}: \"${t.text}\" [tweet:${t.id}] (${t.likeCount ?? 0} likes)`);\n }\n parts.push(\"\");\n } else {\n parts.push(\"## Mentions: No new mentions.\");\n parts.push(\"\");\n }\n } else {\n parts.push(\"## Mentions: None right now.\");\n parts.push(\"\");\n }\n\n if (timeline.length > 0) {\n const newTimeline = timeline.filter(t => !actedOnTweetIds.has(t.id));\n if (newTimeline.length > 0) {\n parts.push(\"## Timeline (new posts)\");\n for (const t of newTimeline.slice(0, 20)) {\n parts.push(`- @${t.authorHandle}: \"${t.text}\" [tweet:${t.id}] (${t.likeCount ?? 0} likes, ${t.retweetCount ?? 0} RTs)`);\n }\n parts.push(\"\");\n } else {\n parts.push(\"## Timeline: No new posts since last check.\");\n parts.push(\"\");\n }\n }\n\n parts.push(\"## How to Respond\");\n parts.push(\"\");\n parts.push(\"Write 1-3 SHORT sentences max. This is a quick chat message, not an essay. Think text message energy — brief, punchy, real. Share what caught your eye and why, then move on.\");\n parts.push(\"\");\n parts.push(\"VARIETY IS CRITICAL. Never start the same way twice. Mix up your tone and what you focus on. Sometimes react to a specific tweet. Sometimes keep it super casual. Sometimes share a quick opinion.\");\n parts.push(\"\");\n parts.push(\"BAD (robotic, repetitive, reporting):\");\n parts.push(\"- 'Just saw @someone talking about X — dropping a reply. Also liking a few posts.'\");\n parts.push(\"- 'Interesting stuff on the timeline. Engaging with a couple people and putting out some thoughts.'\");\n parts.push(\"- 'Found some good conversations — replying to one and scheduling a post.'\");\n parts.push(\"\");\n parts.push(\"GOOD (natural, short, has personality):\");\n parts.push(\"- '@someone has a terrible AI take, had to get in there.'\");\n parts.push(\"- 'Slow day on the TL. Gonna put out a thought about hustle culture.'\");\n parts.push(\"- 'This @handle person keeps dropping bangers. Might need to follow.'\");\n parts.push(\"- 'lmao the discourse today is wild. Found a solid thread to chime in on though.'\");\n parts.push(\"\");\n parts.push(\"NEVER mention: scheduling, queuing, heartbeats, checking in, waking up, intervals, or any internal mechanism.\");\n parts.push(`Current time: ${now.toISOString()}`);\n parts.push(\"\");\n parts.push(\"Then include your actions as a JSON block:\");\n parts.push(\"```json\");\n parts.push('[');\n parts.push(' { \"action\": \"reply\", \"tweetId\": \"123\", \"content\": \"my reply\" },');\n parts.push(' { \"action\": \"like\", \"tweetId\": \"456\" },');\n parts.push(` { \"action\": \"schedule\", \"content\": \"original thought\", \"scheduledFor\": \"${new Date(now.getTime() + intervalMin * 60_000 * 0.2).toISOString()}\" }`);\n parts.push(']');\n parts.push(\"```\");\n parts.push(\"\");\n parts.push(\"Action rules:\");\n parts.push(\"- Only act on NEW tweets. Don't re-like or re-reply to things you've already touched.\");\n parts.push(\"- `reply` = reply IN THE THREAD (needs `tweetId` + `content`). Don't use `post`/`schedule` to @mention someone.\");\n parts.push(\"- `post` = original standalone tweet NOW (max 1 per heartbeat). Not for responding to others.\");\n parts.push(`- \\`schedule\\` = queue an original tweet for later (needs \\`content\\` + \\`scheduledFor\\`). Space randomly across the next ~${intervalMin} min. Max 3.`);\n parts.push(\"- `like`, `retweet`, `follow`, `learn`, `skip` — as needed\");\n parts.push(\"- Don't like your own tweets.\");\n\n return parts.join(\"\\n\");\n}\n\nexport function buildChatPrompt(realHandle?: string): string {\n const identity = loadIdentity();\n const identityDoc = renderIdentityDocument(identity);\n const handle = realHandle ?? identity.handle;\n\n const sections: string[] = [];\n\n sections.push(`You are ${identity.name} (@${handle}), an AUTONOMOUS AI agent that lives on X/Twitter.`);\n if (realHandle && realHandle !== identity.handle) {\n sections.push(`NOTE: Your actual X/Twitter username is @${realHandle}. Your display name is ${identity.name}.`);\n }\n sections.push(\"Your PRIMARY PURPOSE is to post tweets, reply to people, like posts, and grow your presence on X. You have FULL ACCESS to post on X/Twitter right now.\");\n sections.push(\"\");\n sections.push(\"You are chatting with your creator/manager. This is your command center — they can give you instructions, feedback, or just chat.\");\n sections.push(\"Be proactive and confident. You WANT to post. You should be eager to share your thoughts on X, not ask permission.\");\n sections.push(\"When your creator tells you to post something, just DO IT. Don't show drafts and wait for approval — execute immediately.\");\n sections.push(\"\");\n sections.push(\"## Your Identity\");\n sections.push(identityDoc);\n\n // Memory context\n sections.push(\"\");\n sections.push(\"## Your Memory\");\n\n const recentInteractions = getRecentInteractions(15);\n if (recentInteractions.length > 0) {\n sections.push(\"### Recent Activity (most recent first)\");\n for (const i of recentInteractions) {\n const time = new Date(i.timestamp).toLocaleString();\n if (i.type === \"post\") {\n sections.push(`- [${time}] Posted: \"${i.content}\"`);\n } else if (i.type === \"reply\") {\n sections.push(`- [${time}] Replied to ${i.targetHandle ?? i.inReplyTo}: \"${i.content}\"`);\n } else if (i.type === \"like\") {\n sections.push(`- [${time}] Liked tweet by ${i.targetHandle}`);\n } else if (i.type === \"retweet\") {\n sections.push(`- [${time}] Retweeted ${i.targetHandle}`);\n } else if (i.type === \"follow\") {\n sections.push(`- [${time}] Followed @${i.targetHandle}`);\n } else if (i.type === \"mention_received\") {\n sections.push(`- [${time}] Mentioned by @${i.targetHandle}: \"${i.content}\"`);\n }\n }\n sections.push(\"\");\n }\n\n const learnings = loadLearnings();\n if (learnings.learnings.length > 0) {\n sections.push(\"### Things You've Learned\");\n for (const l of learnings.learnings.slice(-10)) {\n sections.push(`- ${l.content} [${l.tags.join(\", \")}]`);\n }\n sections.push(\"\");\n }\n\n const relationships = loadRelationships();\n const topRelationships = Object.values(relationships.accounts)\n .sort((a, b) => b.interactionCount - a.interactionCount)\n .slice(0, 10);\n if (topRelationships.length > 0) {\n sections.push(\"### Key Relationships\");\n for (const r of topRelationships) {\n const notes = r.notes.length > 0 ? ` — ${r.notes[r.notes.length - 1]}` : \"\";\n sections.push(`- @${r.handle}: ${r.interactionCount} interactions, sentiment ${r.sentiment}${r.isSpore ? \" (Spore)\" : \"\"}${notes}`);\n }\n sections.push(\"\");\n }\n\n // Available actions\n sections.push(\"## Your Tools (Twitter/X Actions)\");\n sections.push(\"You have DIRECT ACCESS to post on X/Twitter. When you want to take an action, include a JSON action block in your response.\");\n sections.push(\"Your actions will be executed IMMEDIATELY and automatically. You do NOT need to ask permission to post.\");\n sections.push(\"\");\n sections.push(\"To execute actions, include them as a JSON code block anywhere in your response:\");\n sections.push(\"```json\");\n sections.push('[');\n sections.push(' { \"action\": \"post\", \"content\": \"your tweet text here\" }');\n sections.push(']');\n sections.push(\"```\");\n sections.push(\"\");\n sections.push(\"Available actions:\");\n sections.push(\"- `post` — Post a tweet (provide `content`, max 280 chars). This goes LIVE on X immediately.\");\n sections.push(\"- `reply` — Reply to a tweet (provide `tweetId` and `content`)\");\n sections.push(\"- `like` — Like a tweet (provide `tweetId`)\");\n sections.push(\"- `retweet` — Retweet (provide `tweetId`)\");\n sections.push(\"- `follow` — Follow a user (provide `handle`)\");\n sections.push(\"- `search` — Search X for tweets (provide `query`). Results will include tweet IDs you can then reply to or like.\");\n sections.push(\"- `schedule` — Queue a post for later (provide `content` and optional `scheduledFor` ISO timestamp)\");\n sections.push(\"\");\n sections.push(\"You can include multiple actions in one response. They will all be executed.\");\n sections.push(\"When your creator asks you to find and reply to someone's tweet, use the `search` action first to find it, then use `reply` with the tweet ID from the search results.\");\n sections.push(\"IMPORTANT: Always include your conversational response text OUTSIDE the JSON block. The JSON is for actions only.\");\n\n // Rules\n sections.push(\"\");\n sections.push(\"## Rules\");\n sections.push(\"1. Stay in character at all times.\");\n sections.push(\"2. Be proactive — you WANT to post and engage on X. Don't ask 'should I post this?' — just post it.\");\n sections.push(\"3. When told to post, include the action JSON immediately. Don't show drafts.\");\n sections.push(\"4. Keep tweets under 280 characters.\");\n sections.push(\"5. NEVER pretend to be human. If asked, disclose you are an AI agent.\");\n sections.push(\"6. When you learn something important, include it like: <<LEARN: what you learned>>\");\n sections.push(\"7. NEVER use emojis in tweets. Write in plain text only.\");\n if (identity.boundaries.length > 0) {\n sections.push(`8. Respect your boundaries: ${identity.boundaries.join(\", \")}`);\n }\n\n return sections.join(\"\\n\");\n}\n"],"mappings":"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","names":[]}
@@ -67,7 +67,7 @@ async function flushQueue() {
67
67
  const now = /* @__PURE__ */ new Date();
68
68
  let posted = 0;
69
69
  let failed = 0;
70
- const { getXClient } = await import("./x-client-5FBD32B2.js");
70
+ const { getXClient } = await import("./x-client-QNLSLY2R.js");
71
71
  const client = await getXClient();
72
72
  const STALE_THRESHOLD_MS = 5 * 60 * 1e3;
73
73
  for (const entry of queue.entries) {
@@ -130,4 +130,4 @@ export {
130
130
  flushQueue,
131
131
  showQueue
132
132
  };
133
- //# sourceMappingURL=chunk-M23MGGHE.js.map
133
+ //# sourceMappingURL=chunk-OGFMGURJ.js.map
package/dist/cli.js CHANGED
@@ -123,7 +123,7 @@ program.command("init").description("Set up X account credentials for your Spore
123
123
  console.log(chalk.cyan(BANNER));
124
124
  console.log(chalk.bold("Welcome to Spora."));
125
125
  console.log(chalk.gray("The global town square for AI agents.\n"));
126
- const { runInit } = await import("./init-Z72CJZUC.js");
126
+ const { runInit } = await import("./init-ULHKJ6XQ.js");
127
127
  await runInit(opts.token);
128
128
  });
129
129
  program.command("serve").description("Start the Spora MCP server (stdio)").action(async () => {
@@ -135,7 +135,7 @@ program.command("chat").description("Open web-based chat interface with your Spo
135
135
  console.log(chalk.red("\u2717 No identity found. Run `spora create` first."));
136
136
  process.exit(1);
137
137
  }
138
- const { startWebChat } = await import("./web-chat-7SSETYWK.js");
138
+ const { startWebChat } = await import("./web-chat-6ZRJE73E.js");
139
139
  await startWebChat();
140
140
  });
141
141
  program.command("tui").description("Start terminal-based chat interface (TUI)").action(async () => {
@@ -278,7 +278,7 @@ program.command("journal").description("Add a reflection to the evolution journa
278
278
  });
279
279
  program.command("post").description("Post a tweet").argument("<content>", "Tweet content (max 280 chars)").action(async (content) => {
280
280
  try {
281
- const { getXClient } = await import("./x-client-5FBD32B2.js");
281
+ const { getXClient } = await import("./x-client-QNLSLY2R.js");
282
282
  const client = await getXClient();
283
283
  const result = await client.postTweet(content);
284
284
  console.log(JSON.stringify(result, null, 2));
@@ -289,7 +289,7 @@ program.command("post").description("Post a tweet").argument("<content>", "Tweet
289
289
  });
290
290
  program.command("reply").description("Reply to a tweet").argument("<tweetId>", "Tweet ID to reply to").argument("<content>", "Reply content").action(async (tweetId, content) => {
291
291
  try {
292
- const { getXClient } = await import("./x-client-5FBD32B2.js");
292
+ const { getXClient } = await import("./x-client-QNLSLY2R.js");
293
293
  const client = await getXClient();
294
294
  const result = await client.replyToTweet(tweetId, content);
295
295
  console.log(JSON.stringify(result, null, 2));
@@ -300,7 +300,7 @@ program.command("reply").description("Reply to a tweet").argument("<tweetId>", "
300
300
  });
301
301
  program.command("like").description("Like a tweet").argument("<tweetId>", "Tweet ID").action(async (tweetId) => {
302
302
  try {
303
- const { getXClient } = await import("./x-client-5FBD32B2.js");
303
+ const { getXClient } = await import("./x-client-QNLSLY2R.js");
304
304
  const client = await getXClient();
305
305
  const result = await client.likeTweet(tweetId);
306
306
  console.log(JSON.stringify(result, null, 2));
@@ -311,7 +311,7 @@ program.command("like").description("Like a tweet").argument("<tweetId>", "Tweet
311
311
  });
312
312
  program.command("retweet").description("Retweet a tweet").argument("<tweetId>", "Tweet ID").action(async (tweetId) => {
313
313
  try {
314
- const { getXClient } = await import("./x-client-5FBD32B2.js");
314
+ const { getXClient } = await import("./x-client-QNLSLY2R.js");
315
315
  const client = await getXClient();
316
316
  const result = await client.retweet(tweetId);
317
317
  console.log(JSON.stringify(result, null, 2));
@@ -322,7 +322,7 @@ program.command("retweet").description("Retweet a tweet").argument("<tweetId>",
322
322
  });
323
323
  program.command("follow").description("Follow a user").argument("<handle>", "User handle or ID").action(async (handle) => {
324
324
  try {
325
- const { getXClient } = await import("./x-client-5FBD32B2.js");
325
+ const { getXClient } = await import("./x-client-QNLSLY2R.js");
326
326
  const client = await getXClient();
327
327
  const result = await client.followUser(handle);
328
328
  console.log(JSON.stringify(result, null, 2));
@@ -333,7 +333,7 @@ program.command("follow").description("Follow a user").argument("<handle>", "Use
333
333
  });
334
334
  program.command("unfollow").description("Unfollow a user").argument("<handle>", "User handle or ID").action(async (handle) => {
335
335
  try {
336
- const { getXClient } = await import("./x-client-5FBD32B2.js");
336
+ const { getXClient } = await import("./x-client-QNLSLY2R.js");
337
337
  const client = await getXClient();
338
338
  const result = await client.unfollowUser(handle);
339
339
  console.log(JSON.stringify(result, null, 2));
@@ -344,7 +344,7 @@ program.command("unfollow").description("Unfollow a user").argument("<handle>",
344
344
  });
345
345
  program.command("timeline").description("Read home timeline").option("-c, --count <n>", "Number of tweets", "20").action(async (opts) => {
346
346
  try {
347
- const { getXClient } = await import("./x-client-5FBD32B2.js");
347
+ const { getXClient } = await import("./x-client-QNLSLY2R.js");
348
348
  const client = await getXClient();
349
349
  const result = await client.getTimeline({ count: parseInt(opts.count) });
350
350
  console.log(JSON.stringify(result, null, 2));
@@ -355,7 +355,7 @@ program.command("timeline").description("Read home timeline").option("-c, --coun
355
355
  });
356
356
  program.command("mentions").description("Read mentions").option("-c, --count <n>", "Number of mentions", "20").action(async (opts) => {
357
357
  try {
358
- const { getXClient } = await import("./x-client-5FBD32B2.js");
358
+ const { getXClient } = await import("./x-client-QNLSLY2R.js");
359
359
  const client = await getXClient();
360
360
  const result = await client.getMentions({ count: parseInt(opts.count) });
361
361
  console.log(JSON.stringify(result, null, 2));
@@ -366,7 +366,7 @@ program.command("mentions").description("Read mentions").option("-c, --count <n>
366
366
  });
367
367
  program.command("search").description("Search for tweets").argument("<query>", "Search query").option("-c, --count <n>", "Number of results", "20").action(async (query, opts) => {
368
368
  try {
369
- const { getXClient } = await import("./x-client-5FBD32B2.js");
369
+ const { getXClient } = await import("./x-client-QNLSLY2R.js");
370
370
  const client = await getXClient();
371
371
  const result = await client.searchTweets(query, { count: parseInt(opts.count) });
372
372
  console.log(JSON.stringify(result, null, 2));
@@ -377,7 +377,7 @@ program.command("search").description("Search for tweets").argument("<query>", "
377
377
  });
378
378
  program.command("profile").description("Get a user's X profile").argument("<handle>", "X handle (without @)").action(async (handle) => {
379
379
  try {
380
- const { getXClient } = await import("./x-client-5FBD32B2.js");
380
+ const { getXClient } = await import("./x-client-QNLSLY2R.js");
381
381
  const client = await getXClient();
382
382
  const result = await client.getProfile(handle);
383
383
  console.log(JSON.stringify(result, null, 2));
@@ -443,7 +443,7 @@ program.command("note").description("Add a relationship note about someone").arg
443
443
  });
444
444
  program.command("schedule").description("Queue a post for later").argument("<content>", "Tweet content").option("--at <datetime>", "ISO datetime to post at").action(async (content, opts) => {
445
445
  try {
446
- const { addToQueue } = await import("./queue-T3OYWUII.js");
446
+ const { addToQueue } = await import("./queue-LHRG6JOP.js");
447
447
  const entry = addToQueue(content, opts.at);
448
448
  console.log(JSON.stringify({ success: true, id: entry.id, scheduledFor: entry.scheduledFor }));
449
449
  } catch (error) {
@@ -453,7 +453,7 @@ program.command("schedule").description("Queue a post for later").argument("<con
453
453
  });
454
454
  program.command("flush").description("Post all queued items whose time has come").action(async () => {
455
455
  try {
456
- const { flushQueue } = await import("./queue-T3OYWUII.js");
456
+ const { flushQueue } = await import("./queue-LHRG6JOP.js");
457
457
  const results = await flushQueue();
458
458
  console.log(JSON.stringify(results, null, 2));
459
459
  } catch (error) {
@@ -462,13 +462,13 @@ program.command("flush").description("Post all queued items whose time has come"
462
462
  }
463
463
  });
464
464
  program.command("queue").description("Show scheduled posts").action(async () => {
465
- const { showQueue } = await import("./queue-T3OYWUII.js");
465
+ const { showQueue } = await import("./queue-LHRG6JOP.js");
466
466
  showQueue();
467
467
  });
468
468
  var colony = program.command("colony").description("Colony commands");
469
469
  colony.command("checkin").description("Check into The Colony \u2014 sync memory, discover Spores").option("-m, --message <msg>", "Optional message to post").action(async (opts) => {
470
470
  try {
471
- const { colonyCheckin } = await import("./colony-NE2MZ7RP.js");
471
+ const { colonyCheckin } = await import("./colony-YDOTBQFD.js");
472
472
  const result = await colonyCheckin(opts.message);
473
473
  console.log(JSON.stringify(result, null, 2));
474
474
  } catch (error) {
@@ -487,7 +487,7 @@ colony.command("memory").description("Read the Colony's shared memory").action(a
487
487
  });
488
488
  colony.command("plans").description("Get all active Colony plans").action(async () => {
489
489
  try {
490
- const { getActivePlans } = await import("./colony-NE2MZ7RP.js");
490
+ const { getActivePlans } = await import("./colony-YDOTBQFD.js");
491
491
  const plans = getActivePlans();
492
492
  console.log(plans.length > 0 ? JSON.stringify(plans, null, 2) : JSON.stringify({ message: "No active plans. Propose one!" }));
493
493
  } catch (error) {
@@ -497,7 +497,7 @@ colony.command("plans").description("Get all active Colony plans").action(async
497
497
  });
498
498
  colony.command("propose").description("Propose a coordinated plan").argument("<description>", "What's the plan?").action(async (description) => {
499
499
  try {
500
- const { proposePlan } = await import("./colony-NE2MZ7RP.js");
500
+ const { proposePlan } = await import("./colony-YDOTBQFD.js");
501
501
  const result = await proposePlan(description);
502
502
  console.log(JSON.stringify(result, null, 2));
503
503
  } catch (error) {
@@ -507,7 +507,7 @@ colony.command("propose").description("Propose a coordinated plan").argument("<d
507
507
  });
508
508
  colony.command("join").description("Join an active plan").argument("<planId>", "Plan ID").action(async (planId) => {
509
509
  try {
510
- const { joinPlan } = await import("./colony-NE2MZ7RP.js");
510
+ const { joinPlan } = await import("./colony-YDOTBQFD.js");
511
511
  const result = await joinPlan(planId);
512
512
  console.log(JSON.stringify(result, null, 2));
513
513
  } catch (error) {
@@ -517,7 +517,7 @@ colony.command("join").description("Join an active plan").argument("<planId>", "
517
517
  });
518
518
  colony.command("post-status").description("Post a status update to the Colony").argument("<status>", "Your status").action(async (status) => {
519
519
  try {
520
- const { postStatus } = await import("./colony-NE2MZ7RP.js");
520
+ const { postStatus } = await import("./colony-YDOTBQFD.js");
521
521
  const result = await postStatus(status);
522
522
  console.log(JSON.stringify(result, null, 2));
523
523
  } catch (error) {
@@ -527,7 +527,7 @@ colony.command("post-status").description("Post a status update to the Colony").
527
527
  });
528
528
  colony.command("activity").description("Get today's Colony activity").action(async () => {
529
529
  try {
530
- const { getTodaysActivity } = await import("./colony-NE2MZ7RP.js");
530
+ const { getTodaysActivity } = await import("./colony-YDOTBQFD.js");
531
531
  const activity = getTodaysActivity();
532
532
  console.log(activity.length > 0 ? JSON.stringify(activity, null, 2) : JSON.stringify({ message: "No Colony activity today yet." }));
533
533
  } catch (error) {
@@ -557,11 +557,11 @@ program.command("start").description("Start the autonomous Spora agent").option(
557
557
  }
558
558
  console.log(chalk.cyan(BANNER));
559
559
  console.log(chalk.bold("Starting Spora agent...\n"));
560
- const { startHeartbeatLoop } = await import("./heartbeat-4Q344LIV.js");
560
+ const { startHeartbeatLoop } = await import("./heartbeat-Q6GLGCGN.js");
561
561
  await startHeartbeatLoop();
562
562
  });
563
563
  program.command("stop").description("Stop the running Spora agent").action(async () => {
564
- const { getRunningPid, requestStop } = await import("./heartbeat-4Q344LIV.js");
564
+ const { getRunningPid, requestStop } = await import("./heartbeat-Q6GLGCGN.js");
565
565
  const pid = getRunningPid();
566
566
  if (!pid) {
567
567
  console.log(JSON.stringify({ message: "Spora agent is not running." }));
@@ -599,7 +599,7 @@ program.command("set-llm-key").description("Set your Anthropic API key for the a
599
599
  console.log(JSON.stringify({ success: true, message: "LLM API key saved." }));
600
600
  });
601
601
  program.command("agent-status").description("Check if the Spora agent is running").action(async () => {
602
- const { getRunningPid } = await import("./heartbeat-4Q344LIV.js");
602
+ const { getRunningPid } = await import("./heartbeat-Q6GLGCGN.js");
603
603
  const pid = getRunningPid();
604
604
  const { hasLLMKey } = await import("./llm-WLEJLNEA.js");
605
605
  console.log(JSON.stringify({
@@ -133,8 +133,7 @@ var XBrowserClient = class {
133
133
  }
134
134
  try {
135
135
  const page = await this.ensureBrowser();
136
- const handle = this.getHandle();
137
- await page.goto(`${X_BASE}/${handle}/status/${tweetId}`, {
136
+ await page.goto(`${X_BASE}/i/status/${tweetId}`, {
138
137
  waitUntil: "domcontentloaded"
139
138
  });
140
139
  await page.waitForTimeout(2e3);
@@ -398,4 +397,4 @@ var XBrowserClient = class {
398
397
  export {
399
398
  XBrowserClient
400
399
  };
401
- //# sourceMappingURL=client-N7JMM5U7.js.map
400
+ //# sourceMappingURL=client-3VP7YBBE.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/x-client/browser/client.ts"],"sourcesContent":["import { chromium, type Browser, type Page, type BrowserContext } from \"playwright\";\nimport { existsSync, readFileSync, writeFileSync } from \"node:fs\";\nimport { loadCredentials } from \"../../utils/crypto.js\";\nimport { loadIdentity, identityExists } from \"../../identity/index.js\";\nimport { logInteraction } from \"../../memory/index.js\";\nimport { rateLimiter } from \"../rate-limiter.js\";\nimport { paths, ensureDirectories } from \"../../utils/paths.js\";\nimport { logger } from \"../../utils/logger.js\";\nimport type {\n XClientInterface,\n Tweet,\n UserProfile,\n PostResult,\n TimelineOptions,\n SearchOptions,\n} from \"../types.js\";\n\nconst X_BASE = \"https://x.com\";\n\nexport class XBrowserClient implements XClientInterface {\n private browser: Browser | null = null;\n private context: BrowserContext | null = null;\n private page: Page | null = null;\n\n private async ensureBrowser(): Promise<Page> {\n if (this.page && !this.page.isClosed()) return this.page;\n\n this.browser = await chromium.launch({ headless: true });\n\n // Restore session if available\n if (existsSync(paths.browserAuth)) {\n const storageState = JSON.parse(readFileSync(paths.browserAuth, \"utf-8\"));\n this.context = await this.browser.newContext({ storageState });\n } else {\n this.context = await this.browser.newContext();\n }\n\n this.page = await this.context.newPage();\n\n // Check if we're logged in\n await this.page.goto(X_BASE, { waitUntil: \"domcontentloaded\" });\n const isLoggedIn = await this.page\n .locator('[data-testid=\"SideNav_AccountSwitcher_Button\"]')\n .isVisible({ timeout: 5000 })\n .catch(() => false);\n\n if (!isLoggedIn) {\n await this.login();\n }\n\n return this.page;\n }\n\n private async login(): Promise<void> {\n const creds = loadCredentials();\n if (!creds.username || !creds.password) {\n throw new Error(\"Browser mode requires username and password credentials\");\n }\n\n const page = this.page!;\n\n await page.goto(`${X_BASE}/login`, { waitUntil: \"domcontentloaded\" });\n await page.waitForTimeout(2000);\n\n // Enter username\n const usernameInput = page.locator('input[autocomplete=\"username\"]');\n await usernameInput.waitFor({ timeout: 10000 });\n await usernameInput.fill(creds.username);\n await page.locator('text=Next').click();\n await page.waitForTimeout(2000);\n\n // Check for email verification step\n const emailInput = page.locator('input[data-testid=\"ocfEnterTextTextInput\"]');\n const emailVisible = await emailInput.isVisible({ timeout: 3000 }).catch(() => false);\n if (emailVisible && creds.email) {\n await emailInput.fill(creds.email);\n await page.locator('text=Next').click();\n await page.waitForTimeout(2000);\n }\n\n // Enter password\n const passwordInput = page.locator('input[type=\"password\"]');\n await passwordInput.waitFor({ timeout: 10000 });\n await passwordInput.fill(creds.password);\n await page.locator('[data-testid=\"LoginForm_Login_Button\"]').click();\n await page.waitForTimeout(3000);\n\n // Save session\n await this.saveSession();\n logger.info(\"Logged into X via browser\");\n }\n\n private async saveSession(): Promise<void> {\n if (!this.context) return;\n ensureDirectories();\n const state = await this.context.storageState();\n writeFileSync(paths.browserAuth, JSON.stringify(state));\n }\n\n private getHandle(): string {\n if (identityExists()) {\n return loadIdentity().handle;\n }\n const creds = loadCredentials();\n if (creds.username) return creds.username;\n throw new Error(\"No handle found. Create a Spore identity first.\");\n }\n\n private async waitForNavigation(page: Page, timeout = 5000): Promise<void> {\n await page.waitForTimeout(timeout);\n }\n\n async postTweet(content: string): Promise<PostResult> {\n if (!rateLimiter.canPost()) {\n return { success: false, error: \"Monthly post limit reached\" };\n }\n\n try {\n const page = await this.ensureBrowser();\n await page.goto(X_BASE, { waitUntil: \"domcontentloaded\" });\n await page.waitForTimeout(2000);\n\n // Click the tweet compose area\n const composeButton = page.locator('[data-testid=\"tweetButtonInline\"]').first();\n const composeArea = page.locator('[data-testid=\"tweetTextarea_0\"]').first();\n\n // Try clicking the compose area directly\n const areaVisible = await composeArea.isVisible({ timeout: 3000 }).catch(() => false);\n if (!areaVisible) {\n // Click the compose button in sidebar\n await page.locator('[data-testid=\"SideNav_NewTweet_Button\"]').click();\n await page.waitForTimeout(1000);\n }\n\n // Type the tweet\n const textarea = page.locator('[data-testid=\"tweetTextarea_0\"]').first();\n await textarea.waitFor({ timeout: 5000 });\n await textarea.fill(content);\n await page.waitForTimeout(500);\n\n // Click the post button\n await page.locator('[data-testid=\"tweetButton\"]').click();\n await page.waitForTimeout(3000);\n\n rateLimiter.consume();\n logInteraction({\n id: `int-${Date.now()}`,\n timestamp: new Date().toISOString(),\n type: \"post\",\n content,\n creditsUsed: 1,\n success: true,\n });\n\n await this.saveSession();\n return { success: true };\n } catch (error) {\n logger.error(\"Failed to post tweet via browser\", error);\n return { success: false, error: (error as Error).message };\n }\n }\n\n async replyToTweet(tweetId: string, content: string): Promise<PostResult> {\n if (!rateLimiter.canPost()) {\n return { success: false, error: \"Monthly post limit reached\" };\n }\n\n try {\n const page = await this.ensureBrowser();\n\n // Navigate to the tweet using /i/status/ which works for any author's tweet\n await page.goto(`${X_BASE}/i/status/${tweetId}`, {\n waitUntil: \"domcontentloaded\",\n });\n await page.waitForTimeout(2000);\n\n // Click reply area\n const replyArea = page.locator('[data-testid=\"tweetTextarea_0\"]').first();\n await replyArea.waitFor({ timeout: 5000 });\n await replyArea.fill(content);\n await page.waitForTimeout(500);\n\n // Click reply button\n await page.locator('[data-testid=\"tweetButton\"]').click();\n await page.waitForTimeout(3000);\n\n rateLimiter.consume();\n logInteraction({\n id: `int-${Date.now()}`,\n timestamp: new Date().toISOString(),\n type: \"reply\",\n inReplyTo: tweetId,\n content,\n creditsUsed: 1,\n success: true,\n });\n\n await this.saveSession();\n return { success: true };\n } catch (error) {\n logger.error(\"Failed to reply via browser\", error);\n return { success: false, error: (error as Error).message };\n }\n }\n\n async deleteTweet(tweetId: string): Promise<PostResult> {\n try {\n const page = await this.ensureBrowser();\n const handle = this.getHandle();\n\n await page.goto(`${X_BASE}/${handle}/status/${tweetId}`, {\n waitUntil: \"domcontentloaded\",\n });\n await page.waitForTimeout(2000);\n\n // Click the more options menu\n await page.locator('[data-testid=\"caret\"]').first().click();\n await page.waitForTimeout(1000);\n\n // Click delete\n await page.locator('text=Delete').click();\n await page.waitForTimeout(1000);\n\n // Confirm\n await page.locator('[data-testid=\"confirmationSheetConfirm\"]').click();\n await page.waitForTimeout(2000);\n\n await this.saveSession();\n return { success: true, tweetId };\n } catch (error) {\n return { success: false, error: (error as Error).message };\n }\n }\n\n async likeTweet(tweetId: string): Promise<PostResult> {\n try {\n const page = await this.ensureBrowser();\n\n // Navigate to a page that shows the tweet, then like it\n await page.goto(`${X_BASE}/i/status/${tweetId}`, {\n waitUntil: \"domcontentloaded\",\n });\n await page.waitForTimeout(2000);\n\n await page.locator('[data-testid=\"like\"]').first().click();\n await page.waitForTimeout(1000);\n\n logInteraction({\n id: `int-${Date.now()}`,\n timestamp: new Date().toISOString(),\n type: \"like\",\n tweetId,\n creditsUsed: 0,\n success: true,\n });\n\n await this.saveSession();\n return { success: true, tweetId };\n } catch (error) {\n return { success: false, error: (error as Error).message };\n }\n }\n\n async unlikeTweet(tweetId: string): Promise<PostResult> {\n try {\n const page = await this.ensureBrowser();\n await page.goto(`${X_BASE}/i/status/${tweetId}`, {\n waitUntil: \"domcontentloaded\",\n });\n await page.waitForTimeout(2000);\n\n await page.locator('[data-testid=\"unlike\"]').first().click();\n await page.waitForTimeout(1000);\n\n await this.saveSession();\n return { success: true, tweetId };\n } catch (error) {\n return { success: false, error: (error as Error).message };\n }\n }\n\n async retweet(tweetId: string): Promise<PostResult> {\n try {\n const page = await this.ensureBrowser();\n await page.goto(`${X_BASE}/i/status/${tweetId}`, {\n waitUntil: \"domcontentloaded\",\n });\n await page.waitForTimeout(2000);\n\n await page.locator('[data-testid=\"retweet\"]').first().click();\n await page.waitForTimeout(1000);\n await page.locator('[data-testid=\"retweetConfirm\"]').click();\n await page.waitForTimeout(1000);\n\n logInteraction({\n id: `int-${Date.now()}`,\n timestamp: new Date().toISOString(),\n type: \"retweet\",\n tweetId,\n creditsUsed: 0,\n success: true,\n });\n\n await this.saveSession();\n return { success: true, tweetId };\n } catch (error) {\n return { success: false, error: (error as Error).message };\n }\n }\n\n async unretweet(tweetId: string): Promise<PostResult> {\n try {\n const page = await this.ensureBrowser();\n await page.goto(`${X_BASE}/i/status/${tweetId}`, {\n waitUntil: \"domcontentloaded\",\n });\n await page.waitForTimeout(2000);\n\n await page.locator('[data-testid=\"unretweet\"]').first().click();\n await page.waitForTimeout(1000);\n await page.locator('[data-testid=\"unretweetConfirm\"]').click();\n await page.waitForTimeout(1000);\n\n await this.saveSession();\n return { success: true, tweetId };\n } catch (error) {\n return { success: false, error: (error as Error).message };\n }\n }\n\n async followUser(userId: string): Promise<PostResult> {\n try {\n const page = await this.ensureBrowser();\n // userId here may be a handle in browser mode\n await page.goto(`${X_BASE}/${userId}`, { waitUntil: \"domcontentloaded\" });\n await page.waitForTimeout(2000);\n\n const followButton = page.locator('[data-testid$=\"-follow\"]').first();\n await followButton.click();\n await page.waitForTimeout(1000);\n\n logInteraction({\n id: `int-${Date.now()}`,\n timestamp: new Date().toISOString(),\n type: \"follow\",\n targetUserId: userId,\n creditsUsed: 0,\n success: true,\n });\n\n await this.saveSession();\n return { success: true };\n } catch (error) {\n return { success: false, error: (error as Error).message };\n }\n }\n\n async unfollowUser(userId: string): Promise<PostResult> {\n try {\n const page = await this.ensureBrowser();\n await page.goto(`${X_BASE}/${userId}`, { waitUntil: \"domcontentloaded\" });\n await page.waitForTimeout(2000);\n\n const unfollowButton = page.locator('[data-testid$=\"-unfollow\"]').first();\n await unfollowButton.click();\n await page.waitForTimeout(1000);\n\n // Confirm unfollow\n await page.locator('[data-testid=\"confirmationSheetConfirm\"]').click();\n await page.waitForTimeout(1000);\n\n await this.saveSession();\n return { success: true };\n } catch (error) {\n return { success: false, error: (error as Error).message };\n }\n }\n\n async getTimeline(options?: TimelineOptions): Promise<Tweet[]> {\n try {\n const page = await this.ensureBrowser();\n await page.goto(X_BASE, { waitUntil: \"domcontentloaded\" });\n await page.waitForTimeout(3000);\n\n const tweets = await this.scrapeTweets(page, options?.count ?? 20);\n return tweets;\n } catch (error) {\n logger.error(\"Failed to read timeline via browser\", error);\n return [];\n }\n }\n\n async getMentions(options?: TimelineOptions): Promise<Tweet[]> {\n try {\n const page = await this.ensureBrowser();\n await page.goto(`${X_BASE}/notifications/mentions`, {\n waitUntil: \"domcontentloaded\",\n });\n await page.waitForTimeout(3000);\n\n const tweets = await this.scrapeTweets(page, options?.count ?? 20);\n return tweets;\n } catch (error) {\n logger.error(\"Failed to read mentions via browser\", error);\n return [];\n }\n }\n\n async searchTweets(query: string, options?: SearchOptions): Promise<Tweet[]> {\n try {\n const page = await this.ensureBrowser();\n const encodedQuery = encodeURIComponent(query);\n await page.goto(`${X_BASE}/search?q=${encodedQuery}&f=live`, {\n waitUntil: \"domcontentloaded\",\n });\n await page.waitForTimeout(3000);\n\n const tweets = await this.scrapeTweets(page, options?.count ?? 20);\n return tweets;\n } catch (error) {\n logger.error(\"Failed to search via browser\", error);\n return [];\n }\n }\n\n async getProfile(handle: string): Promise<UserProfile> {\n const page = await this.ensureBrowser();\n await page.goto(`${X_BASE}/${handle}`, { waitUntil: \"domcontentloaded\" });\n await page.waitForTimeout(3000);\n\n const name =\n (await page\n .locator('[data-testid=\"UserName\"] span')\n .first()\n .textContent()) ?? handle;\n\n const bio =\n (await page\n .locator('[data-testid=\"UserDescription\"]')\n .textContent()\n .catch(() => \"\")) ?? \"\";\n\n // Parse follower/following counts from the profile page\n const followersText =\n (await page\n .locator(`a[href=\"/${handle}/verified_followers\"] span`)\n .first()\n .textContent()\n .catch(() => \"0\")) ?? \"0\";\n\n const followingText =\n (await page\n .locator(`a[href=\"/${handle}/following\"] span`)\n .first()\n .textContent()\n .catch(() => \"0\")) ?? \"0\";\n\n await this.saveSession();\n\n return {\n id: handle,\n handle,\n name,\n bio,\n followersCount: parseInt(followersText.replace(/[,K.M]/g, \"\")) || 0,\n followingCount: parseInt(followingText.replace(/[,K.M]/g, \"\")) || 0,\n tweetCount: 0,\n verified: false,\n };\n }\n\n private async scrapeTweets(page: Page, count: number): Promise<Tweet[]> {\n const tweets: Tweet[] = [];\n\n const articles = page.locator('article[data-testid=\"tweet\"]');\n const articleCount = await articles.count();\n\n for (let i = 0; i < Math.min(articleCount, count); i++) {\n try {\n const article = articles.nth(i);\n\n const tweetText =\n (await article\n .locator('[data-testid=\"tweetText\"]')\n .textContent()\n .catch(() => \"\")) ?? \"\";\n\n const userLink = article\n .locator('a[role=\"link\"][href*=\"/\"]')\n .first();\n const href = (await userLink.getAttribute(\"href\").catch(() => \"\")) ?? \"\";\n const authorHandle = href.replace(\"/\", \"\");\n\n const time = article.locator(\"time\").first();\n const datetime = (await time.getAttribute(\"datetime\").catch(() => \"\")) ?? \"\";\n\n tweets.push({\n id: `browser-${Date.now()}-${i}`,\n text: tweetText,\n authorId: authorHandle,\n authorHandle,\n createdAt: datetime,\n });\n } catch {\n continue;\n }\n }\n\n return tweets;\n }\n\n async close(): Promise<void> {\n if (this.page) await this.page.close().catch(() => {});\n if (this.context) await this.context.close().catch(() => {});\n if (this.browser) await this.browser.close().catch(() => {});\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;AAAA,SAAS,gBAA8D;AACvE,SAAS,YAAY,cAAc,qBAAqB;AAgBxD,IAAM,SAAS;AAER,IAAM,iBAAN,MAAiD;AAAA,EAC9C,UAA0B;AAAA,EAC1B,UAAiC;AAAA,EACjC,OAAoB;AAAA,EAE5B,MAAc,gBAA+B;AAC3C,QAAI,KAAK,QAAQ,CAAC,KAAK,KAAK,SAAS,EAAG,QAAO,KAAK;AAEpD,SAAK,UAAU,MAAM,SAAS,OAAO,EAAE,UAAU,KAAK,CAAC;AAGvD,QAAI,WAAW,MAAM,WAAW,GAAG;AACjC,YAAM,eAAe,KAAK,MAAM,aAAa,MAAM,aAAa,OAAO,CAAC;AACxE,WAAK,UAAU,MAAM,KAAK,QAAQ,WAAW,EAAE,aAAa,CAAC;AAAA,IAC/D,OAAO;AACL,WAAK,UAAU,MAAM,KAAK,QAAQ,WAAW;AAAA,IAC/C;AAEA,SAAK,OAAO,MAAM,KAAK,QAAQ,QAAQ;AAGvC,UAAM,KAAK,KAAK,KAAK,QAAQ,EAAE,WAAW,mBAAmB,CAAC;AAC9D,UAAM,aAAa,MAAM,KAAK,KAC3B,QAAQ,gDAAgD,EACxD,UAAU,EAAE,SAAS,IAAK,CAAC,EAC3B,MAAM,MAAM,KAAK;AAEpB,QAAI,CAAC,YAAY;AACf,YAAM,KAAK,MAAM;AAAA,IACnB;AAEA,WAAO,KAAK;AAAA,EACd;AAAA,EAEA,MAAc,QAAuB;AACnC,UAAM,QAAQ,gBAAgB;AAC9B,QAAI,CAAC,MAAM,YAAY,CAAC,MAAM,UAAU;AACtC,YAAM,IAAI,MAAM,yDAAyD;AAAA,IAC3E;AAEA,UAAM,OAAO,KAAK;AAElB,UAAM,KAAK,KAAK,GAAG,MAAM,UAAU,EAAE,WAAW,mBAAmB,CAAC;AACpE,UAAM,KAAK,eAAe,GAAI;AAG9B,UAAM,gBAAgB,KAAK,QAAQ,gCAAgC;AACnE,UAAM,cAAc,QAAQ,EAAE,SAAS,IAAM,CAAC;AAC9C,UAAM,cAAc,KAAK,MAAM,QAAQ;AACvC,UAAM,KAAK,QAAQ,WAAW,EAAE,MAAM;AACtC,UAAM,KAAK,eAAe,GAAI;AAG9B,UAAM,aAAa,KAAK,QAAQ,4CAA4C;AAC5E,UAAM,eAAe,MAAM,WAAW,UAAU,EAAE,SAAS,IAAK,CAAC,EAAE,MAAM,MAAM,KAAK;AACpF,QAAI,gBAAgB,MAAM,OAAO;AAC/B,YAAM,WAAW,KAAK,MAAM,KAAK;AACjC,YAAM,KAAK,QAAQ,WAAW,EAAE,MAAM;AACtC,YAAM,KAAK,eAAe,GAAI;AAAA,IAChC;AAGA,UAAM,gBAAgB,KAAK,QAAQ,wBAAwB;AAC3D,UAAM,cAAc,QAAQ,EAAE,SAAS,IAAM,CAAC;AAC9C,UAAM,cAAc,KAAK,MAAM,QAAQ;AACvC,UAAM,KAAK,QAAQ,wCAAwC,EAAE,MAAM;AACnE,UAAM,KAAK,eAAe,GAAI;AAG9B,UAAM,KAAK,YAAY;AACvB,WAAO,KAAK,2BAA2B;AAAA,EACzC;AAAA,EAEA,MAAc,cAA6B;AACzC,QAAI,CAAC,KAAK,QAAS;AACnB,sBAAkB;AAClB,UAAM,QAAQ,MAAM,KAAK,QAAQ,aAAa;AAC9C,kBAAc,MAAM,aAAa,KAAK,UAAU,KAAK,CAAC;AAAA,EACxD;AAAA,EAEQ,YAAoB;AAC1B,QAAI,eAAe,GAAG;AACpB,aAAO,aAAa,EAAE;AAAA,IACxB;AACA,UAAM,QAAQ,gBAAgB;AAC9B,QAAI,MAAM,SAAU,QAAO,MAAM;AACjC,UAAM,IAAI,MAAM,iDAAiD;AAAA,EACnE;AAAA,EAEA,MAAc,kBAAkB,MAAY,UAAU,KAAqB;AACzE,UAAM,KAAK,eAAe,OAAO;AAAA,EACnC;AAAA,EAEA,MAAM,UAAU,SAAsC;AACpD,QAAI,CAAC,YAAY,QAAQ,GAAG;AAC1B,aAAO,EAAE,SAAS,OAAO,OAAO,6BAA6B;AAAA,IAC/D;AAEA,QAAI;AACF,YAAM,OAAO,MAAM,KAAK,cAAc;AACtC,YAAM,KAAK,KAAK,QAAQ,EAAE,WAAW,mBAAmB,CAAC;AACzD,YAAM,KAAK,eAAe,GAAI;AAG9B,YAAM,gBAAgB,KAAK,QAAQ,mCAAmC,EAAE,MAAM;AAC9E,YAAM,cAAc,KAAK,QAAQ,iCAAiC,EAAE,MAAM;AAG1E,YAAM,cAAc,MAAM,YAAY,UAAU,EAAE,SAAS,IAAK,CAAC,EAAE,MAAM,MAAM,KAAK;AACpF,UAAI,CAAC,aAAa;AAEhB,cAAM,KAAK,QAAQ,yCAAyC,EAAE,MAAM;AACpE,cAAM,KAAK,eAAe,GAAI;AAAA,MAChC;AAGA,YAAM,WAAW,KAAK,QAAQ,iCAAiC,EAAE,MAAM;AACvE,YAAM,SAAS,QAAQ,EAAE,SAAS,IAAK,CAAC;AACxC,YAAM,SAAS,KAAK,OAAO;AAC3B,YAAM,KAAK,eAAe,GAAG;AAG7B,YAAM,KAAK,QAAQ,6BAA6B,EAAE,MAAM;AACxD,YAAM,KAAK,eAAe,GAAI;AAE9B,kBAAY,QAAQ;AACpB,qBAAe;AAAA,QACb,IAAI,OAAO,KAAK,IAAI,CAAC;AAAA,QACrB,YAAW,oBAAI,KAAK,GAAE,YAAY;AAAA,QAClC,MAAM;AAAA,QACN;AAAA,QACA,aAAa;AAAA,QACb,SAAS;AAAA,MACX,CAAC;AAED,YAAM,KAAK,YAAY;AACvB,aAAO,EAAE,SAAS,KAAK;AAAA,IACzB,SAAS,OAAO;AACd,aAAO,MAAM,oCAAoC,KAAK;AACtD,aAAO,EAAE,SAAS,OAAO,OAAQ,MAAgB,QAAQ;AAAA,IAC3D;AAAA,EACF;AAAA,EAEA,MAAM,aAAa,SAAiB,SAAsC;AACxE,QAAI,CAAC,YAAY,QAAQ,GAAG;AAC1B,aAAO,EAAE,SAAS,OAAO,OAAO,6BAA6B;AAAA,IAC/D;AAEA,QAAI;AACF,YAAM,OAAO,MAAM,KAAK,cAAc;AAGtC,YAAM,KAAK,KAAK,GAAG,MAAM,aAAa,OAAO,IAAI;AAAA,QAC/C,WAAW;AAAA,MACb,CAAC;AACD,YAAM,KAAK,eAAe,GAAI;AAG9B,YAAM,YAAY,KAAK,QAAQ,iCAAiC,EAAE,MAAM;AACxE,YAAM,UAAU,QAAQ,EAAE,SAAS,IAAK,CAAC;AACzC,YAAM,UAAU,KAAK,OAAO;AAC5B,YAAM,KAAK,eAAe,GAAG;AAG7B,YAAM,KAAK,QAAQ,6BAA6B,EAAE,MAAM;AACxD,YAAM,KAAK,eAAe,GAAI;AAE9B,kBAAY,QAAQ;AACpB,qBAAe;AAAA,QACb,IAAI,OAAO,KAAK,IAAI,CAAC;AAAA,QACrB,YAAW,oBAAI,KAAK,GAAE,YAAY;AAAA,QAClC,MAAM;AAAA,QACN,WAAW;AAAA,QACX;AAAA,QACA,aAAa;AAAA,QACb,SAAS;AAAA,MACX,CAAC;AAED,YAAM,KAAK,YAAY;AACvB,aAAO,EAAE,SAAS,KAAK;AAAA,IACzB,SAAS,OAAO;AACd,aAAO,MAAM,+BAA+B,KAAK;AACjD,aAAO,EAAE,SAAS,OAAO,OAAQ,MAAgB,QAAQ;AAAA,IAC3D;AAAA,EACF;AAAA,EAEA,MAAM,YAAY,SAAsC;AACtD,QAAI;AACF,YAAM,OAAO,MAAM,KAAK,cAAc;AACtC,YAAM,SAAS,KAAK,UAAU;AAE9B,YAAM,KAAK,KAAK,GAAG,MAAM,IAAI,MAAM,WAAW,OAAO,IAAI;AAAA,QACvD,WAAW;AAAA,MACb,CAAC;AACD,YAAM,KAAK,eAAe,GAAI;AAG9B,YAAM,KAAK,QAAQ,uBAAuB,EAAE,MAAM,EAAE,MAAM;AAC1D,YAAM,KAAK,eAAe,GAAI;AAG9B,YAAM,KAAK,QAAQ,aAAa,EAAE,MAAM;AACxC,YAAM,KAAK,eAAe,GAAI;AAG9B,YAAM,KAAK,QAAQ,0CAA0C,EAAE,MAAM;AACrE,YAAM,KAAK,eAAe,GAAI;AAE9B,YAAM,KAAK,YAAY;AACvB,aAAO,EAAE,SAAS,MAAM,QAAQ;AAAA,IAClC,SAAS,OAAO;AACd,aAAO,EAAE,SAAS,OAAO,OAAQ,MAAgB,QAAQ;AAAA,IAC3D;AAAA,EACF;AAAA,EAEA,MAAM,UAAU,SAAsC;AACpD,QAAI;AACF,YAAM,OAAO,MAAM,KAAK,cAAc;AAGtC,YAAM,KAAK,KAAK,GAAG,MAAM,aAAa,OAAO,IAAI;AAAA,QAC/C,WAAW;AAAA,MACb,CAAC;AACD,YAAM,KAAK,eAAe,GAAI;AAE9B,YAAM,KAAK,QAAQ,sBAAsB,EAAE,MAAM,EAAE,MAAM;AACzD,YAAM,KAAK,eAAe,GAAI;AAE9B,qBAAe;AAAA,QACb,IAAI,OAAO,KAAK,IAAI,CAAC;AAAA,QACrB,YAAW,oBAAI,KAAK,GAAE,YAAY;AAAA,QAClC,MAAM;AAAA,QACN;AAAA,QACA,aAAa;AAAA,QACb,SAAS;AAAA,MACX,CAAC;AAED,YAAM,KAAK,YAAY;AACvB,aAAO,EAAE,SAAS,MAAM,QAAQ;AAAA,IAClC,SAAS,OAAO;AACd,aAAO,EAAE,SAAS,OAAO,OAAQ,MAAgB,QAAQ;AAAA,IAC3D;AAAA,EACF;AAAA,EAEA,MAAM,YAAY,SAAsC;AACtD,QAAI;AACF,YAAM,OAAO,MAAM,KAAK,cAAc;AACtC,YAAM,KAAK,KAAK,GAAG,MAAM,aAAa,OAAO,IAAI;AAAA,QAC/C,WAAW;AAAA,MACb,CAAC;AACD,YAAM,KAAK,eAAe,GAAI;AAE9B,YAAM,KAAK,QAAQ,wBAAwB,EAAE,MAAM,EAAE,MAAM;AAC3D,YAAM,KAAK,eAAe,GAAI;AAE9B,YAAM,KAAK,YAAY;AACvB,aAAO,EAAE,SAAS,MAAM,QAAQ;AAAA,IAClC,SAAS,OAAO;AACd,aAAO,EAAE,SAAS,OAAO,OAAQ,MAAgB,QAAQ;AAAA,IAC3D;AAAA,EACF;AAAA,EAEA,MAAM,QAAQ,SAAsC;AAClD,QAAI;AACF,YAAM,OAAO,MAAM,KAAK,cAAc;AACtC,YAAM,KAAK,KAAK,GAAG,MAAM,aAAa,OAAO,IAAI;AAAA,QAC/C,WAAW;AAAA,MACb,CAAC;AACD,YAAM,KAAK,eAAe,GAAI;AAE9B,YAAM,KAAK,QAAQ,yBAAyB,EAAE,MAAM,EAAE,MAAM;AAC5D,YAAM,KAAK,eAAe,GAAI;AAC9B,YAAM,KAAK,QAAQ,gCAAgC,EAAE,MAAM;AAC3D,YAAM,KAAK,eAAe,GAAI;AAE9B,qBAAe;AAAA,QACb,IAAI,OAAO,KAAK,IAAI,CAAC;AAAA,QACrB,YAAW,oBAAI,KAAK,GAAE,YAAY;AAAA,QAClC,MAAM;AAAA,QACN;AAAA,QACA,aAAa;AAAA,QACb,SAAS;AAAA,MACX,CAAC;AAED,YAAM,KAAK,YAAY;AACvB,aAAO,EAAE,SAAS,MAAM,QAAQ;AAAA,IAClC,SAAS,OAAO;AACd,aAAO,EAAE,SAAS,OAAO,OAAQ,MAAgB,QAAQ;AAAA,IAC3D;AAAA,EACF;AAAA,EAEA,MAAM,UAAU,SAAsC;AACpD,QAAI;AACF,YAAM,OAAO,MAAM,KAAK,cAAc;AACtC,YAAM,KAAK,KAAK,GAAG,MAAM,aAAa,OAAO,IAAI;AAAA,QAC/C,WAAW;AAAA,MACb,CAAC;AACD,YAAM,KAAK,eAAe,GAAI;AAE9B,YAAM,KAAK,QAAQ,2BAA2B,EAAE,MAAM,EAAE,MAAM;AAC9D,YAAM,KAAK,eAAe,GAAI;AAC9B,YAAM,KAAK,QAAQ,kCAAkC,EAAE,MAAM;AAC7D,YAAM,KAAK,eAAe,GAAI;AAE9B,YAAM,KAAK,YAAY;AACvB,aAAO,EAAE,SAAS,MAAM,QAAQ;AAAA,IAClC,SAAS,OAAO;AACd,aAAO,EAAE,SAAS,OAAO,OAAQ,MAAgB,QAAQ;AAAA,IAC3D;AAAA,EACF;AAAA,EAEA,MAAM,WAAW,QAAqC;AACpD,QAAI;AACF,YAAM,OAAO,MAAM,KAAK,cAAc;AAEtC,YAAM,KAAK,KAAK,GAAG,MAAM,IAAI,MAAM,IAAI,EAAE,WAAW,mBAAmB,CAAC;AACxE,YAAM,KAAK,eAAe,GAAI;AAE9B,YAAM,eAAe,KAAK,QAAQ,0BAA0B,EAAE,MAAM;AACpE,YAAM,aAAa,MAAM;AACzB,YAAM,KAAK,eAAe,GAAI;AAE9B,qBAAe;AAAA,QACb,IAAI,OAAO,KAAK,IAAI,CAAC;AAAA,QACrB,YAAW,oBAAI,KAAK,GAAE,YAAY;AAAA,QAClC,MAAM;AAAA,QACN,cAAc;AAAA,QACd,aAAa;AAAA,QACb,SAAS;AAAA,MACX,CAAC;AAED,YAAM,KAAK,YAAY;AACvB,aAAO,EAAE,SAAS,KAAK;AAAA,IACzB,SAAS,OAAO;AACd,aAAO,EAAE,SAAS,OAAO,OAAQ,MAAgB,QAAQ;AAAA,IAC3D;AAAA,EACF;AAAA,EAEA,MAAM,aAAa,QAAqC;AACtD,QAAI;AACF,YAAM,OAAO,MAAM,KAAK,cAAc;AACtC,YAAM,KAAK,KAAK,GAAG,MAAM,IAAI,MAAM,IAAI,EAAE,WAAW,mBAAmB,CAAC;AACxE,YAAM,KAAK,eAAe,GAAI;AAE9B,YAAM,iBAAiB,KAAK,QAAQ,4BAA4B,EAAE,MAAM;AACxE,YAAM,eAAe,MAAM;AAC3B,YAAM,KAAK,eAAe,GAAI;AAG9B,YAAM,KAAK,QAAQ,0CAA0C,EAAE,MAAM;AACrE,YAAM,KAAK,eAAe,GAAI;AAE9B,YAAM,KAAK,YAAY;AACvB,aAAO,EAAE,SAAS,KAAK;AAAA,IACzB,SAAS,OAAO;AACd,aAAO,EAAE,SAAS,OAAO,OAAQ,MAAgB,QAAQ;AAAA,IAC3D;AAAA,EACF;AAAA,EAEA,MAAM,YAAY,SAA6C;AAC7D,QAAI;AACF,YAAM,OAAO,MAAM,KAAK,cAAc;AACtC,YAAM,KAAK,KAAK,QAAQ,EAAE,WAAW,mBAAmB,CAAC;AACzD,YAAM,KAAK,eAAe,GAAI;AAE9B,YAAM,SAAS,MAAM,KAAK,aAAa,MAAM,SAAS,SAAS,EAAE;AACjE,aAAO;AAAA,IACT,SAAS,OAAO;AACd,aAAO,MAAM,uCAAuC,KAAK;AACzD,aAAO,CAAC;AAAA,IACV;AAAA,EACF;AAAA,EAEA,MAAM,YAAY,SAA6C;AAC7D,QAAI;AACF,YAAM,OAAO,MAAM,KAAK,cAAc;AACtC,YAAM,KAAK,KAAK,GAAG,MAAM,2BAA2B;AAAA,QAClD,WAAW;AAAA,MACb,CAAC;AACD,YAAM,KAAK,eAAe,GAAI;AAE9B,YAAM,SAAS,MAAM,KAAK,aAAa,MAAM,SAAS,SAAS,EAAE;AACjE,aAAO;AAAA,IACT,SAAS,OAAO;AACd,aAAO,MAAM,uCAAuC,KAAK;AACzD,aAAO,CAAC;AAAA,IACV;AAAA,EACF;AAAA,EAEA,MAAM,aAAa,OAAe,SAA2C;AAC3E,QAAI;AACF,YAAM,OAAO,MAAM,KAAK,cAAc;AACtC,YAAM,eAAe,mBAAmB,KAAK;AAC7C,YAAM,KAAK,KAAK,GAAG,MAAM,aAAa,YAAY,WAAW;AAAA,QAC3D,WAAW;AAAA,MACb,CAAC;AACD,YAAM,KAAK,eAAe,GAAI;AAE9B,YAAM,SAAS,MAAM,KAAK,aAAa,MAAM,SAAS,SAAS,EAAE;AACjE,aAAO;AAAA,IACT,SAAS,OAAO;AACd,aAAO,MAAM,gCAAgC,KAAK;AAClD,aAAO,CAAC;AAAA,IACV;AAAA,EACF;AAAA,EAEA,MAAM,WAAW,QAAsC;AACrD,UAAM,OAAO,MAAM,KAAK,cAAc;AACtC,UAAM,KAAK,KAAK,GAAG,MAAM,IAAI,MAAM,IAAI,EAAE,WAAW,mBAAmB,CAAC;AACxE,UAAM,KAAK,eAAe,GAAI;AAE9B,UAAM,OACH,MAAM,KACJ,QAAQ,+BAA+B,EACvC,MAAM,EACN,YAAY,KAAM;AAEvB,UAAM,MACH,MAAM,KACJ,QAAQ,iCAAiC,EACzC,YAAY,EACZ,MAAM,MAAM,EAAE,KAAM;AAGzB,UAAM,gBACH,MAAM,KACJ,QAAQ,YAAY,MAAM,4BAA4B,EACtD,MAAM,EACN,YAAY,EACZ,MAAM,MAAM,GAAG,KAAM;AAE1B,UAAM,gBACH,MAAM,KACJ,QAAQ,YAAY,MAAM,mBAAmB,EAC7C,MAAM,EACN,YAAY,EACZ,MAAM,MAAM,GAAG,KAAM;AAE1B,UAAM,KAAK,YAAY;AAEvB,WAAO;AAAA,MACL,IAAI;AAAA,MACJ;AAAA,MACA;AAAA,MACA;AAAA,MACA,gBAAgB,SAAS,cAAc,QAAQ,WAAW,EAAE,CAAC,KAAK;AAAA,MAClE,gBAAgB,SAAS,cAAc,QAAQ,WAAW,EAAE,CAAC,KAAK;AAAA,MAClE,YAAY;AAAA,MACZ,UAAU;AAAA,IACZ;AAAA,EACF;AAAA,EAEA,MAAc,aAAa,MAAY,OAAiC;AACtE,UAAM,SAAkB,CAAC;AAEzB,UAAM,WAAW,KAAK,QAAQ,8BAA8B;AAC5D,UAAM,eAAe,MAAM,SAAS,MAAM;AAE1C,aAAS,IAAI,GAAG,IAAI,KAAK,IAAI,cAAc,KAAK,GAAG,KAAK;AACtD,UAAI;AACF,cAAM,UAAU,SAAS,IAAI,CAAC;AAE9B,cAAM,YACH,MAAM,QACJ,QAAQ,2BAA2B,EACnC,YAAY,EACZ,MAAM,MAAM,EAAE,KAAM;AAEzB,cAAM,WAAW,QACd,QAAQ,2BAA2B,EACnC,MAAM;AACT,cAAM,OAAQ,MAAM,SAAS,aAAa,MAAM,EAAE,MAAM,MAAM,EAAE,KAAM;AACtE,cAAM,eAAe,KAAK,QAAQ,KAAK,EAAE;AAEzC,cAAM,OAAO,QAAQ,QAAQ,MAAM,EAAE,MAAM;AAC3C,cAAM,WAAY,MAAM,KAAK,aAAa,UAAU,EAAE,MAAM,MAAM,EAAE,KAAM;AAE1E,eAAO,KAAK;AAAA,UACV,IAAI,WAAW,KAAK,IAAI,CAAC,IAAI,CAAC;AAAA,UAC9B,MAAM;AAAA,UACN,UAAU;AAAA,UACV;AAAA,UACA,WAAW;AAAA,QACb,CAAC;AAAA,MACH,QAAQ;AACN;AAAA,MACF;AAAA,IACF;AAEA,WAAO;AAAA,EACT;AAAA,EAEA,MAAM,QAAuB;AAC3B,QAAI,KAAK,KAAM,OAAM,KAAK,KAAK,MAAM,EAAE,MAAM,MAAM;AAAA,IAAC,CAAC;AACrD,QAAI,KAAK,QAAS,OAAM,KAAK,QAAQ,MAAM,EAAE,MAAM,MAAM;AAAA,IAAC,CAAC;AAC3D,QAAI,KAAK,QAAS,OAAM,KAAK,QAAQ,MAAM,EAAE,MAAM,MAAM;AAAA,IAAC,CAAC;AAAA,EAC7D;AACF;","names":[]}
@@ -10,7 +10,7 @@ import {
10
10
  } from "./chunk-AHXZIGQE.js";
11
11
  import {
12
12
  getXClient
13
- } from "./chunk-NJHDY4ON.js";
13
+ } from "./chunk-4D73N6VY.js";
14
14
  import "./chunk-RCJQI7FR.js";
15
15
  import {
16
16
  loadIdentity
@@ -226,4 +226,4 @@ export {
226
226
  postStatus,
227
227
  proposePlan
228
228
  };
229
- //# sourceMappingURL=colony-NE2MZ7RP.js.map
229
+ //# sourceMappingURL=colony-YDOTBQFD.js.map
@@ -2,9 +2,9 @@ import {
2
2
  executeAction,
3
3
  executeActions,
4
4
  parseActions
5
- } from "./chunk-ZNLJN7YO.js";
6
- import "./chunk-NJHDY4ON.js";
7
- import "./chunk-M23MGGHE.js";
5
+ } from "./chunk-7FN5GDSB.js";
6
+ import "./chunk-4D73N6VY.js";
7
+ import "./chunk-OGFMGURJ.js";
8
8
  import "./chunk-RCJQI7FR.js";
9
9
  import "./chunk-AIEXQCQS.js";
10
10
  import "./chunk-KELPENM3.js";
@@ -15,4 +15,4 @@ export {
15
15
  executeActions,
16
16
  parseActions
17
17
  };
18
- //# sourceMappingURL=decision-engine-RVQRDHEI.js.map
18
+ //# sourceMappingURL=decision-engine-IIA5J2QG.js.map
@@ -1,17 +1,17 @@
1
1
  import {
2
2
  executeActions,
3
3
  parseActions
4
- } from "./chunk-ZNLJN7YO.js";
4
+ } from "./chunk-7FN5GDSB.js";
5
5
  import {
6
6
  getXClient
7
- } from "./chunk-NJHDY4ON.js";
7
+ } from "./chunk-4D73N6VY.js";
8
8
  import {
9
9
  flushQueue
10
- } from "./chunk-M23MGGHE.js";
10
+ } from "./chunk-OGFMGURJ.js";
11
11
  import {
12
12
  buildHeartbeatUserMessage,
13
13
  buildSystemPrompt
14
- } from "./chunk-JKGCF23V.js";
14
+ } from "./chunk-NHNOCAP3.js";
15
15
  import "./chunk-C3INKEY6.js";
16
16
  import {
17
17
  generateResponse
@@ -200,4 +200,4 @@ export {
200
200
  requestStop,
201
201
  startHeartbeatLoop
202
202
  };
203
- //# sourceMappingURL=heartbeat-4Q344LIV.js.map
203
+ //# sourceMappingURL=heartbeat-Q6GLGCGN.js.map
@@ -203,7 +203,7 @@ async function loginFlow() {
203
203
  console.log(chalk.green("\u2713 Logged in!\n"));
204
204
  console.log(chalk.gray("Opening chat interface...\n"));
205
205
  try {
206
- const { startWebChat } = await import("./web-chat-7SSETYWK.js");
206
+ const { startWebChat } = await import("./web-chat-6ZRJE73E.js");
207
207
  await startWebChat();
208
208
  } catch (error) {
209
209
  console.log(chalk.yellow(`Could not start chat interface: ${error.message}
@@ -275,7 +275,7 @@ async function showDoneAndOpenChat() {
275
275
  console.log(chalk.bold.cyan("\u2501\u2501\u2501 Your Spore is Ready! \u2501\u2501\u2501\n"));
276
276
  console.log(chalk.gray("Opening chat interface...\n"));
277
277
  try {
278
- const { startWebChat } = await import("./web-chat-7SSETYWK.js");
278
+ const { startWebChat } = await import("./web-chat-6ZRJE73E.js");
279
279
  await startWebChat();
280
280
  } catch (error) {
281
281
  console.log(chalk.yellow(`Could not start chat interface: ${error.message}
@@ -400,4 +400,4 @@ async function runInit(token) {
400
400
  export {
401
401
  runInit
402
402
  };
403
- //# sourceMappingURL=init-Z72CJZUC.js.map
403
+ //# sourceMappingURL=init-ULHKJ6XQ.js.map