spora 0.2.53 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (87) hide show
  1. package/dist/{account-creator-WYY4YVJP.js → account-creator-SETL5CGT.js} +5 -5
  2. package/dist/chunk-FCAK5FYQ.js +127 -0
  3. package/dist/chunk-FCAK5FYQ.js.map +1 -0
  4. package/dist/{chunk-CIWFFTSP.js → chunk-GJFBWIW3.js} +2 -2
  5. package/dist/{chunk-7UHJLJNI.js → chunk-HERI4RPY.js} +2 -2
  6. package/dist/{chunk-E4DZYHGF.js → chunk-J7J557HV.js} +2 -2
  7. package/dist/{chunk-YF7WWJRO.js → chunk-JWMADEQO.js} +3 -3
  8. package/dist/chunk-LRKBNKMQ.js +79 -0
  9. package/dist/chunk-LRKBNKMQ.js.map +1 -0
  10. package/dist/{chunk-K6FZPWXD.js → chunk-NLWU5432.js} +5 -5
  11. package/dist/{chunk-VL4UUCMS.js → chunk-POEDIDM6.js} +2 -2
  12. package/dist/{chunk-5GPXH253.js → chunk-Q7YS3AIK.js} +5 -2
  13. package/dist/chunk-Q7YS3AIK.js.map +1 -0
  14. package/dist/{chunk-3NW3VIN5.js → chunk-QHFM2YW6.js} +13 -6
  15. package/dist/chunk-QHFM2YW6.js.map +1 -0
  16. package/dist/{chunk-DE772QJH.js → chunk-RNVEWVDN.js} +26 -2
  17. package/dist/chunk-RNVEWVDN.js.map +1 -0
  18. package/dist/{chunk-LTAYL5E2.js → chunk-SUFTVQME.js} +5 -5
  19. package/dist/{chunk-LTAYL5E2.js.map → chunk-SUFTVQME.js.map} +1 -1
  20. package/dist/{chunk-T3U56JW4.js → chunk-SXMDYUK3.js} +2 -2
  21. package/dist/{chunk-XJBOOX7N.js → chunk-YZ7RWJ6Z.js} +46 -10
  22. package/dist/chunk-YZ7RWJ6Z.js.map +1 -0
  23. package/dist/{chunk-H66LVLSP.js → chunk-ZN63YLI6.js} +144 -26
  24. package/dist/chunk-ZN63YLI6.js.map +1 -0
  25. package/dist/cli.js +40 -40
  26. package/dist/{client-YR2RA56D.js → client-23THPNVL.js} +32 -7
  27. package/dist/{client-YR2RA56D.js.map → client-23THPNVL.js.map} +1 -1
  28. package/dist/{client-KXYBQUMD.js → client-NVI3ZD4G.js} +11 -8
  29. package/dist/{client-KXYBQUMD.js.map → client-NVI3ZD4G.js.map} +1 -1
  30. package/dist/{colony-4EYP6EPG.js → colony-J4EZQI37.js} +7 -7
  31. package/dist/{config-BRWV7X4S.js → config-QRBOL4NX.js} +3 -3
  32. package/dist/{crypto-CK5M4W2X.js → crypto-ZVWJLD2J.js} +3 -3
  33. package/dist/decision-engine-WBD36PZI.js +19 -0
  34. package/dist/{heartbeat-QFWU47KI.js → heartbeat-GBT4G4C6.js} +129 -25
  35. package/dist/heartbeat-GBT4G4C6.js.map +1 -0
  36. package/dist/{identity-SJ77KTVG.js → identity-LN2R4KJU.js} +3 -3
  37. package/dist/{image-search-6RGKTFRT.js → image-search-SZVMGWLN.js} +3 -3
  38. package/dist/{init-FRZDY4MB.js → init-QWOV7F5B.js} +12 -12
  39. package/dist/llm-MHZG2VHU.js +16 -0
  40. package/dist/mcp-server.js +24 -24
  41. package/dist/{memory-ZC3LUAUW.js → memory-J6AYZ5Y2.js} +5 -3
  42. package/dist/{memory-SYYAGNJ5.js → memory-JMXU3UXR.js} +3 -3
  43. package/dist/{paths-IL7YUMNP.js → paths-KXOWF2B2.js} +2 -2
  44. package/dist/performance-7G6R6ELJ.js +18 -0
  45. package/dist/prompt-builder-IY2SLZ7F.js +25 -0
  46. package/dist/queue-MLRTMJRE.js +14 -0
  47. package/dist/strategy-TOVFBIZQ.js +12 -0
  48. package/dist/strategy-TOVFBIZQ.js.map +1 -0
  49. package/dist/{web-chat-BX4WCEDD.js → web-chat-2BAWTCGU.js} +108 -29
  50. package/dist/web-chat-2BAWTCGU.js.map +1 -0
  51. package/dist/x-client-HUXCQOAW.js +12 -0
  52. package/dist/x-client-HUXCQOAW.js.map +1 -0
  53. package/package.json +1 -1
  54. package/dist/chunk-3NW3VIN5.js.map +0 -1
  55. package/dist/chunk-5GPXH253.js.map +0 -1
  56. package/dist/chunk-DE772QJH.js.map +0 -1
  57. package/dist/chunk-H66LVLSP.js.map +0 -1
  58. package/dist/chunk-XJBOOX7N.js.map +0 -1
  59. package/dist/decision-engine-YQDGNP3C.js +0 -18
  60. package/dist/heartbeat-QFWU47KI.js.map +0 -1
  61. package/dist/llm-5FY4H7WC.js +0 -16
  62. package/dist/prompt-builder-V7ZM73TA.js +0 -19
  63. package/dist/queue-IDNLFXWC.js +0 -14
  64. package/dist/web-chat-BX4WCEDD.js.map +0 -1
  65. package/dist/x-client-DFMW2PX7.js +0 -12
  66. /package/dist/{account-creator-WYY4YVJP.js.map → account-creator-SETL5CGT.js.map} +0 -0
  67. /package/dist/{chunk-CIWFFTSP.js.map → chunk-GJFBWIW3.js.map} +0 -0
  68. /package/dist/{chunk-7UHJLJNI.js.map → chunk-HERI4RPY.js.map} +0 -0
  69. /package/dist/{chunk-E4DZYHGF.js.map → chunk-J7J557HV.js.map} +0 -0
  70. /package/dist/{chunk-YF7WWJRO.js.map → chunk-JWMADEQO.js.map} +0 -0
  71. /package/dist/{chunk-K6FZPWXD.js.map → chunk-NLWU5432.js.map} +0 -0
  72. /package/dist/{chunk-VL4UUCMS.js.map → chunk-POEDIDM6.js.map} +0 -0
  73. /package/dist/{chunk-T3U56JW4.js.map → chunk-SXMDYUK3.js.map} +0 -0
  74. /package/dist/{colony-4EYP6EPG.js.map → colony-J4EZQI37.js.map} +0 -0
  75. /package/dist/{config-BRWV7X4S.js.map → config-QRBOL4NX.js.map} +0 -0
  76. /package/dist/{crypto-CK5M4W2X.js.map → crypto-ZVWJLD2J.js.map} +0 -0
  77. /package/dist/{decision-engine-YQDGNP3C.js.map → decision-engine-WBD36PZI.js.map} +0 -0
  78. /package/dist/{identity-SJ77KTVG.js.map → identity-LN2R4KJU.js.map} +0 -0
  79. /package/dist/{image-search-6RGKTFRT.js.map → image-search-SZVMGWLN.js.map} +0 -0
  80. /package/dist/{init-FRZDY4MB.js.map → init-QWOV7F5B.js.map} +0 -0
  81. /package/dist/{llm-5FY4H7WC.js.map → llm-MHZG2VHU.js.map} +0 -0
  82. /package/dist/{memory-SYYAGNJ5.js.map → memory-J6AYZ5Y2.js.map} +0 -0
  83. /package/dist/{memory-ZC3LUAUW.js.map → memory-JMXU3UXR.js.map} +0 -0
  84. /package/dist/{paths-IL7YUMNP.js.map → paths-KXOWF2B2.js.map} +0 -0
  85. /package/dist/{prompt-builder-V7ZM73TA.js.map → performance-7G6R6ELJ.js.map} +0 -0
  86. /package/dist/{queue-IDNLFXWC.js.map → prompt-builder-IY2SLZ7F.js.map} +0 -0
  87. /package/dist/{x-client-DFMW2PX7.js.map → queue-MLRTMJRE.js.map} +0 -0
@@ -1 +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 postTweetWithMedia(content: string, _mediaBuffer: Buffer): Promise<PostResult> {\n // Browser client doesn't support media upload — fall back to text-only post\n logger.warn(\"Browser client does not support media upload, posting without image\");\n return this.postTweet(content);\n }\n\n async replyToTweetWithMedia(tweetId: string, content: string, _mediaBuffer: Buffer): Promise<PostResult> {\n logger.warn(\"Browser client does not support media upload, replying without image\");\n return this.replyToTweet(tweetId, content);\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":"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","names":[]}
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 postTweetWithMedia(content: string, _mediaBuffer: Buffer): Promise<PostResult> {\n // Browser client doesn't support media upload — fall back to text-only post\n logger.warn(\"Browser client does not support media upload, posting without image\");\n return this.postTweet(content);\n }\n\n async replyToTweetWithMedia(tweetId: string, content: string, _mediaBuffer: Buffer): Promise<PostResult> {\n logger.warn(\"Browser client does not support media upload, replying without image\");\n return this.replyToTweet(tweetId, content);\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 getTweet(_tweetId: string): Promise<Tweet | null> {\n // Browser client can't reliably look up individual tweets — degrade gracefully\n return null;\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":"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","names":[]}
@@ -7,18 +7,18 @@ import {
7
7
  loadColonyMemory,
8
8
  renderColonyBriefing,
9
9
  saveColonyMemory
10
- } from "./chunk-7UHJLJNI.js";
10
+ } from "./chunk-HERI4RPY.js";
11
11
  import {
12
12
  getXClient
13
- } from "./chunk-K6FZPWXD.js";
14
- import "./chunk-T3U56JW4.js";
13
+ } from "./chunk-NLWU5432.js";
14
+ import "./chunk-SXMDYUK3.js";
15
15
  import {
16
16
  loadIdentity
17
- } from "./chunk-CIWFFTSP.js";
17
+ } from "./chunk-GJFBWIW3.js";
18
18
  import {
19
19
  logger
20
- } from "./chunk-E4DZYHGF.js";
21
- import "./chunk-5GPXH253.js";
20
+ } from "./chunk-J7J557HV.js";
21
+ import "./chunk-Q7YS3AIK.js";
22
22
 
23
23
  // src/colony/index.ts
24
24
  var COLONY_TAG = "#SporaColony";
@@ -226,4 +226,4 @@ export {
226
226
  postStatus,
227
227
  proposePlan
228
228
  };
229
- //# sourceMappingURL=colony-4EYP6EPG.js.map
229
+ //# sourceMappingURL=colony-J4EZQI37.js.map
@@ -3,12 +3,12 @@ import {
3
3
  createDefaultConfig,
4
4
  loadConfig,
5
5
  saveConfig
6
- } from "./chunk-T3U56JW4.js";
7
- import "./chunk-5GPXH253.js";
6
+ } from "./chunk-SXMDYUK3.js";
7
+ import "./chunk-Q7YS3AIK.js";
8
8
  export {
9
9
  ConfigSchema,
10
10
  createDefaultConfig,
11
11
  loadConfig,
12
12
  saveConfig
13
13
  };
14
- //# sourceMappingURL=config-BRWV7X4S.js.map
14
+ //# sourceMappingURL=config-QRBOL4NX.js.map
@@ -3,12 +3,12 @@ import {
3
3
  encrypt,
4
4
  loadCredentials,
5
5
  saveCredentials
6
- } from "./chunk-VL4UUCMS.js";
7
- import "./chunk-5GPXH253.js";
6
+ } from "./chunk-POEDIDM6.js";
7
+ import "./chunk-Q7YS3AIK.js";
8
8
  export {
9
9
  decrypt,
10
10
  encrypt,
11
11
  loadCredentials,
12
12
  saveCredentials
13
13
  };
14
- //# sourceMappingURL=crypto-CK5M4W2X.js.map
14
+ //# sourceMappingURL=crypto-ZVWJLD2J.js.map
@@ -0,0 +1,19 @@
1
+ import {
2
+ executeAction,
3
+ executeActions,
4
+ parseActions
5
+ } from "./chunk-YZ7RWJ6Z.js";
6
+ import "./chunk-NLWU5432.js";
7
+ import "./chunk-FCAK5FYQ.js";
8
+ import "./chunk-QHFM2YW6.js";
9
+ import "./chunk-SXMDYUK3.js";
10
+ import "./chunk-GJFBWIW3.js";
11
+ import "./chunk-J7J557HV.js";
12
+ import "./chunk-RNVEWVDN.js";
13
+ import "./chunk-Q7YS3AIK.js";
14
+ export {
15
+ executeAction,
16
+ executeActions,
17
+ parseActions
18
+ };
19
+ //# sourceMappingURL=decision-engine-WBD36PZI.js.map
@@ -1,32 +1,49 @@
1
+ import {
2
+ buildHeartbeatUserMessage,
3
+ buildReflectionPrompt,
4
+ buildSystemPrompt,
5
+ parseReflection
6
+ } from "./chunk-ZN63YLI6.js";
7
+ import {
8
+ generateResponse
9
+ } from "./chunk-SUFTVQME.js";
10
+ import "./chunk-JWMADEQO.js";
1
11
  import {
2
12
  executeActions,
3
13
  parseActions
4
- } from "./chunk-XJBOOX7N.js";
14
+ } from "./chunk-YZ7RWJ6Z.js";
5
15
  import {
6
16
  getXClient
7
- } from "./chunk-K6FZPWXD.js";
17
+ } from "./chunk-NLWU5432.js";
8
18
  import {
9
- flushQueue
10
- } from "./chunk-3NW3VIN5.js";
19
+ getActiveTrackedPosts,
20
+ getPerformanceSummary,
21
+ retireOldPosts,
22
+ updatePostMetrics,
23
+ updateSelfMetrics
24
+ } from "./chunk-FCAK5FYQ.js";
11
25
  import {
12
- buildHeartbeatUserMessage,
13
- buildSystemPrompt
14
- } from "./chunk-H66LVLSP.js";
15
- import "./chunk-YF7WWJRO.js";
26
+ flushQueue
27
+ } from "./chunk-QHFM2YW6.js";
16
28
  import {
17
- generateResponse
18
- } from "./chunk-LTAYL5E2.js";
29
+ loadStrategy,
30
+ saveStrategy
31
+ } from "./chunk-LRKBNKMQ.js";
19
32
  import {
20
33
  loadConfig
21
- } from "./chunk-T3U56JW4.js";
22
- import "./chunk-CIWFFTSP.js";
34
+ } from "./chunk-SXMDYUK3.js";
35
+ import {
36
+ loadIdentity
37
+ } from "./chunk-GJFBWIW3.js";
23
38
  import {
24
39
  logger
25
- } from "./chunk-E4DZYHGF.js";
26
- import "./chunk-DE772QJH.js";
40
+ } from "./chunk-J7J557HV.js";
41
+ import {
42
+ addLearning
43
+ } from "./chunk-RNVEWVDN.js";
27
44
  import {
28
45
  paths
29
- } from "./chunk-5GPXH253.js";
46
+ } from "./chunk-Q7YS3AIK.js";
30
47
 
31
48
  // src/runtime/heartbeat.ts
32
49
  import { existsSync, unlinkSync, writeFileSync, readFileSync } from "fs";
@@ -98,7 +115,7 @@ Spora agent is running (PID ${process.pid})`);
98
115
  heartbeatCount++;
99
116
  logger.info(`=== Heartbeat #${heartbeatCount} ===`);
100
117
  try {
101
- await runHeartbeat(maxActions, intervalMs);
118
+ await runHeartbeat(maxActions, intervalMs, heartbeatCount);
102
119
  } catch (error) {
103
120
  logger.error("Heartbeat error", error);
104
121
  console.error(`Heartbeat #${heartbeatCount} failed: ${error.message}`);
@@ -132,7 +149,7 @@ Spora agent is running (PID ${process.pid})`);
132
149
  logger.info("Spora agent stopped.");
133
150
  console.log("\nSpora agent stopped.");
134
151
  }
135
- async function runHeartbeat(maxActions, intervalMs) {
152
+ async function runHeartbeat(maxActions, intervalMs, heartbeatCount = 1) {
136
153
  logger.info("Checking queue...");
137
154
  try {
138
155
  const flushed = await flushQueue();
@@ -142,10 +159,7 @@ async function runHeartbeat(maxActions, intervalMs) {
142
159
  } catch (error) {
143
160
  logger.warn(`Queue flush failed: ${error.message}`);
144
161
  }
145
- logger.info("Reading timeline and mentions...");
146
162
  const client = await getXClient();
147
- let timeline = [];
148
- let mentions = [];
149
163
  let ownHandle;
150
164
  if ("getAuthenticatedHandle" in client) {
151
165
  try {
@@ -153,6 +167,47 @@ async function runHeartbeat(maxActions, intervalMs) {
153
167
  } catch {
154
168
  }
155
169
  }
170
+ logger.info("Checking post performance...");
171
+ try {
172
+ retireOldPosts();
173
+ const activePosts = getActiveTrackedPosts();
174
+ for (const post of activePosts.slice(0, 5)) {
175
+ try {
176
+ const tweet = await client.getTweet(post.tweetId);
177
+ if (tweet) {
178
+ updatePostMetrics(post.tweetId, {
179
+ checkedAt: (/* @__PURE__ */ new Date()).toISOString(),
180
+ likes: tweet.likeCount ?? 0,
181
+ retweets: tweet.retweetCount ?? 0,
182
+ replies: tweet.replyCount ?? 0
183
+ });
184
+ }
185
+ } catch {
186
+ }
187
+ await new Promise((r) => setTimeout(r, 1e3));
188
+ }
189
+ } catch (error) {
190
+ logger.warn(`Performance check failed: ${error.message}`);
191
+ }
192
+ if (heartbeatCount % 6 === 1) {
193
+ logger.info("Checking own profile...");
194
+ try {
195
+ const handle = ownHandle ?? loadIdentity().handle;
196
+ const profile = await client.getProfile(handle);
197
+ updateSelfMetrics({
198
+ checkedAt: (/* @__PURE__ */ new Date()).toISOString(),
199
+ followers: profile.followersCount,
200
+ following: profile.followingCount,
201
+ totalTweets: profile.tweetCount
202
+ });
203
+ logger.info(`Self: ${profile.followersCount} followers, ${profile.followingCount} following`);
204
+ } catch (error) {
205
+ logger.warn(`Self-check failed: ${error.message}`);
206
+ }
207
+ }
208
+ logger.info("Reading timeline and mentions...");
209
+ let timeline = [];
210
+ let mentions = [];
156
211
  try {
157
212
  timeline = await client.getTimeline({ count: 20 });
158
213
  if (ownHandle) {
@@ -169,8 +224,27 @@ async function runHeartbeat(maxActions, intervalMs) {
169
224
  } catch (error) {
170
225
  logger.warn(`Mentions read failed: ${error.message}`);
171
226
  }
227
+ let discoveryResults = [];
228
+ if (heartbeatCount % 4 === 0) {
229
+ logger.info("Running proactive discovery...");
230
+ try {
231
+ const identity = loadIdentity();
232
+ const strategy = loadStrategy();
233
+ const allTopics = [...identity.topics, ...strategy.currentFocus ?? []];
234
+ if (allTopics.length > 0) {
235
+ const topic = allTopics[Math.floor(Math.random() * allTopics.length)];
236
+ discoveryResults = await client.searchTweets(topic, { count: 10 });
237
+ if (ownHandle) {
238
+ discoveryResults = discoveryResults.filter((t) => t.authorHandle.toLowerCase() !== ownHandle.toLowerCase());
239
+ }
240
+ logger.info(`Discovery for "${topic}": ${discoveryResults.length} results`);
241
+ }
242
+ } catch (error) {
243
+ logger.warn(`Discovery failed: ${error.message}`);
244
+ }
245
+ }
172
246
  const systemPrompt = buildSystemPrompt();
173
- const userMessage = buildHeartbeatUserMessage(timeline, mentions, intervalMs);
247
+ const userMessage = buildHeartbeatUserMessage(timeline, mentions, intervalMs, discoveryResults);
174
248
  logger.info("Asking LLM for decisions...");
175
249
  const response = await generateResponse(systemPrompt, userMessage, { temperature: 0.95 });
176
250
  const actions = parseActions(response.content);
@@ -179,8 +253,19 @@ async function runHeartbeat(maxActions, intervalMs) {
179
253
  return;
180
254
  }
181
255
  const validTweetIds = /* @__PURE__ */ new Set();
182
- for (const t of timeline) validTweetIds.add(t.id);
183
- for (const t of mentions) validTweetIds.add(t.id);
256
+ const tweetMap = /* @__PURE__ */ new Map();
257
+ for (const t of timeline) {
258
+ validTweetIds.add(t.id);
259
+ tweetMap.set(t.id, t);
260
+ }
261
+ for (const t of mentions) {
262
+ validTweetIds.add(t.id);
263
+ tweetMap.set(t.id, t);
264
+ }
265
+ for (const t of discoveryResults) {
266
+ validTweetIds.add(t.id);
267
+ tweetMap.set(t.id, t);
268
+ }
184
269
  const validatedActions = actions.filter((a) => {
185
270
  if (a.tweetId) {
186
271
  const cleanId = a.tweetId.replace(/^tweet:/i, "").trim();
@@ -193,7 +278,7 @@ async function runHeartbeat(maxActions, intervalMs) {
193
278
  });
194
279
  const limitedActions = validatedActions.slice(0, maxActions);
195
280
  logger.info(`Executing ${limitedActions.length} action(s)...`);
196
- const results = await executeActions(limitedActions);
281
+ const results = await executeActions(limitedActions, tweetMap);
197
282
  for (const result of results) {
198
283
  if (result.success) {
199
284
  logger.info(` [OK] ${result.action}${result.detail ? `: ${result.detail}` : ""}`);
@@ -201,6 +286,25 @@ async function runHeartbeat(maxActions, intervalMs) {
201
286
  logger.warn(` [FAIL] ${result.action}: ${result.error}`);
202
287
  }
203
288
  }
289
+ logger.info("Reflecting on actions...");
290
+ try {
291
+ const perfSummary = getPerformanceSummary();
292
+ const currentStrategy = loadStrategy();
293
+ const reflectPrompt = buildReflectionPrompt(results, perfSummary, currentStrategy);
294
+ const reflection = await generateResponse(systemPrompt, reflectPrompt, { temperature: 0.7 });
295
+ const reflectionData = parseReflection(reflection.content);
296
+ if (reflectionData.learning) {
297
+ addLearning(reflectionData.learning, "reflection", ["auto-reflect"]);
298
+ logger.info(`Reflection learning: "${reflectionData.learning.slice(0, 60)}..."`);
299
+ }
300
+ if (reflectionData.strategyUpdate) {
301
+ const updated = { ...currentStrategy, ...reflectionData.strategyUpdate, lastUpdated: (/* @__PURE__ */ new Date()).toISOString() };
302
+ saveStrategy(updated);
303
+ logger.info("Strategy updated from reflection.");
304
+ }
305
+ } catch (error) {
306
+ logger.warn(`Reflection failed: ${error.message}`);
307
+ }
204
308
  logger.info(`Heartbeat complete. ${results.filter((r) => r.success).length}/${results.length} actions succeeded.`);
205
309
  }
206
310
  export {
@@ -209,4 +313,4 @@ export {
209
313
  requestStop,
210
314
  startHeartbeatLoop
211
315
  };
212
- //# sourceMappingURL=heartbeat-QFWU47KI.js.map
316
+ //# sourceMappingURL=heartbeat-GBT4G4C6.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/runtime/heartbeat.ts"],"sourcesContent":["import { existsSync, unlinkSync, writeFileSync, readFileSync } from \"node:fs\";\nimport { logger } from \"../utils/logger.js\";\nimport { loadConfig } from \"../utils/config.js\";\nimport { paths } from \"../utils/paths.js\";\nimport { getXClient } from \"../x-client/index.js\";\nimport { flushQueue } from \"../scheduler/queue.js\";\nimport { buildSystemPrompt, buildHeartbeatUserMessage, buildReflectionPrompt, parseReflection } from \"./prompt-builder.js\";\nimport { generateResponse } from \"./llm.js\";\nimport { parseActions, executeActions, type ActionResult } from \"./decision-engine.js\";\nimport { retireOldPosts, getActiveTrackedPosts, updatePostMetrics, updateSelfMetrics, getPerformanceSummary } from \"../memory/performance.js\";\nimport { loadStrategy, saveStrategy } from \"../memory/strategy.js\";\nimport { loadIdentity } from \"../identity/index.js\";\nimport { addLearning } from \"../memory/index.js\";\nimport type { Tweet } from \"../x-client/types.js\";\n\nlet running = false;\nlet lastMentionsSinceId: string | undefined;\n\nexport function isRunning(): boolean {\n return running;\n}\n\nexport function requestStop(): void {\n writeFileSync(paths.stopSignal, \"stop\");\n logger.info(\"Stop signal sent.\");\n}\n\nfunction shouldStop(): boolean {\n if (existsSync(paths.stopSignal)) {\n unlinkSync(paths.stopSignal);\n return true;\n }\n return false;\n}\n\nfunction writePid(): void {\n writeFileSync(paths.runtimePid, String(process.pid));\n}\n\nfunction clearPid(): void {\n if (existsSync(paths.runtimePid)) {\n unlinkSync(paths.runtimePid);\n }\n}\n\nexport function getRunningPid(): number | null {\n if (!existsSync(paths.runtimePid)) return null;\n const pid = parseInt(readFileSync(paths.runtimePid, \"utf-8\").trim(), 10);\n if (isNaN(pid)) return null;\n\n // Check if process is actually running\n try {\n process.kill(pid, 0);\n return pid;\n } catch {\n // Process not running, clean up stale PID\n clearPid();\n return null;\n }\n}\n\nexport async function startHeartbeatLoop(): Promise<void> {\n // Check if already running\n const existingPid = getRunningPid();\n if (existingPid) {\n throw new Error(`Spora is already running (PID ${existingPid}). Run \\`spora stop\\` first.`);\n }\n\n running = true;\n writePid();\n\n const config = loadConfig();\n const intervalMs = config.runtime?.heartbeatIntervalMs ?? 60_000;\n const maxActions = config.runtime?.actionsPerHeartbeat ?? 3;\n\n logger.info(`Spora agent starting. Heartbeat interval: ${intervalMs / 1000}s, max actions: ${maxActions}`);\n console.log(`\\nSpora agent is running (PID ${process.pid})`);\n console.log(`Heartbeat every ${Math.round(intervalMs / 60_000)} minutes`);\n console.log(`Press Ctrl+C or run \\`spora stop\\` to stop.\\n`);\n\n // Handle graceful shutdown\n const shutdown = () => {\n logger.info(\"Shutting down...\");\n running = false;\n clearPid();\n process.exit(0);\n };\n process.on(\"SIGINT\", shutdown);\n process.on(\"SIGTERM\", shutdown);\n\n // Clean any stale stop signal\n if (existsSync(paths.stopSignal)) {\n unlinkSync(paths.stopSignal);\n }\n\n let heartbeatCount = 0;\n\n while (running) {\n heartbeatCount++;\n logger.info(`=== Heartbeat #${heartbeatCount} ===`);\n\n try {\n await runHeartbeat(maxActions, intervalMs, heartbeatCount);\n } catch (error) {\n logger.error(\"Heartbeat error\", error);\n console.error(`Heartbeat #${heartbeatCount} failed: ${(error as Error).message}`);\n }\n\n // Check for stop signal\n if (shouldStop()) {\n logger.info(\"Stop signal received.\");\n break;\n }\n\n // Sleep with jitter\n const jitter = Math.floor(Math.random() * intervalMs * 0.3);\n const sleepMs = intervalMs + jitter;\n logger.info(`Sleeping ${Math.round(sleepMs / 1000)}s until next heartbeat...`);\n\n // Sleep in chunks — flush queue during sleep so scheduled posts go out on time\n const chunkMs = 10_000;\n let slept = 0;\n while (slept < sleepMs && running) {\n await new Promise((r) => setTimeout(r, Math.min(chunkMs, sleepMs - slept)));\n slept += chunkMs;\n if (shouldStop()) {\n running = false;\n break;\n }\n\n // Flush queue during sleep so scheduled posts go out at their intended times\n try {\n const flushed = await flushQueue();\n if (flushed.posted > 0) {\n logger.info(`Flushed ${flushed.posted} scheduled post(s) during sleep`);\n }\n } catch {\n // Queue flush failed during sleep, not critical\n }\n }\n }\n\n clearPid();\n logger.info(\"Spora agent stopped.\");\n console.log(\"\\nSpora agent stopped.\");\n}\n\nasync function runHeartbeat(maxActions: number, intervalMs: number, heartbeatCount: number = 1): Promise<void> {\n // 1. Flush any queued posts\n logger.info(\"Checking queue...\");\n try {\n const flushed = await flushQueue();\n if (flushed.posted > 0) {\n logger.info(`Flushed ${flushed.posted} queued posts.`);\n }\n } catch (error) {\n logger.warn(`Queue flush failed: ${(error as Error).message}`);\n }\n\n const client = await getXClient();\n\n // Get own handle\n let ownHandle: string | undefined;\n if (\"getAuthenticatedHandle\" in client) {\n try {\n ownHandle = await (client as any).getAuthenticatedHandle();\n } catch {}\n }\n\n // 2. Check engagement on tracked posts (performance feedback loop)\n logger.info(\"Checking post performance...\");\n try {\n retireOldPosts();\n const activePosts = getActiveTrackedPosts();\n for (const post of activePosts.slice(0, 5)) {\n try {\n const tweet = await client.getTweet(post.tweetId);\n if (tweet) {\n updatePostMetrics(post.tweetId, {\n checkedAt: new Date().toISOString(),\n likes: tweet.likeCount ?? 0,\n retweets: tweet.retweetCount ?? 0,\n replies: tweet.replyCount ?? 0,\n });\n }\n } catch { /* skip individual tweet lookup failures */ }\n await new Promise(r => setTimeout(r, 1000));\n }\n } catch (error) {\n logger.warn(`Performance check failed: ${(error as Error).message}`);\n }\n\n // 3. Self-awareness: check own profile (every 6th heartbeat)\n if (heartbeatCount % 6 === 1) {\n logger.info(\"Checking own profile...\");\n try {\n const handle = ownHandle ?? loadIdentity().handle;\n const profile = await client.getProfile(handle);\n updateSelfMetrics({\n checkedAt: new Date().toISOString(),\n followers: profile.followersCount,\n following: profile.followingCount,\n totalTweets: profile.tweetCount,\n });\n logger.info(`Self: ${profile.followersCount} followers, ${profile.followingCount} following`);\n } catch (error) {\n logger.warn(`Self-check failed: ${(error as Error).message}`);\n }\n }\n\n // 4. Read timeline and mentions\n logger.info(\"Reading timeline and mentions...\");\n\n let timeline: Tweet[] = [];\n let mentions: Tweet[] = [];\n\n try {\n timeline = await client.getTimeline({ count: 20 });\n if (ownHandle) {\n timeline = timeline.filter(t => t.authorHandle.toLowerCase() !== ownHandle!.toLowerCase());\n }\n } catch (error) {\n logger.warn(`Timeline read failed: ${(error as Error).message}`);\n }\n\n try {\n mentions = await client.getMentions({ count: 10, sinceId: lastMentionsSinceId });\n if (mentions.length > 0) {\n lastMentionsSinceId = mentions[0].id;\n }\n } catch (error) {\n logger.warn(`Mentions read failed: ${(error as Error).message}`);\n }\n\n // 5. Proactive discovery (every 4th heartbeat)\n let discoveryResults: Tweet[] = [];\n if (heartbeatCount % 4 === 0) {\n logger.info(\"Running proactive discovery...\");\n try {\n const identity = loadIdentity();\n const strategy = loadStrategy();\n const allTopics = [...identity.topics, ...(strategy.currentFocus ?? [])];\n if (allTopics.length > 0) {\n const topic = allTopics[Math.floor(Math.random() * allTopics.length)];\n discoveryResults = await client.searchTweets(topic, { count: 10 });\n // Filter out own tweets from discovery\n if (ownHandle) {\n discoveryResults = discoveryResults.filter(t => t.authorHandle.toLowerCase() !== ownHandle!.toLowerCase());\n }\n logger.info(`Discovery for \"${topic}\": ${discoveryResults.length} results`);\n }\n } catch (error) {\n logger.warn(`Discovery failed: ${(error as Error).message}`);\n }\n }\n\n // 6. Build prompts\n const systemPrompt = buildSystemPrompt();\n const userMessage = buildHeartbeatUserMessage(timeline, mentions, intervalMs, discoveryResults);\n\n // 7. Ask LLM for decisions\n logger.info(\"Asking LLM for decisions...\");\n const response = await generateResponse(systemPrompt, userMessage, { temperature: 0.95 });\n\n // 8. Parse and execute actions\n const actions = parseActions(response.content);\n if (actions.length === 0) {\n logger.info(\"LLM returned no actions.\");\n return;\n }\n\n // Build set of valid tweet IDs from timeline + mentions + discovery\n const validTweetIds = new Set<string>();\n const tweetMap = new Map<string, Tweet>();\n for (const t of timeline) { validTweetIds.add(t.id); tweetMap.set(t.id, t); }\n for (const t of mentions) { validTweetIds.add(t.id); tweetMap.set(t.id, t); }\n for (const t of discoveryResults) { validTweetIds.add(t.id); tweetMap.set(t.id, t); }\n\n // Filter out actions with fake/hallucinated tweet IDs\n const validatedActions = actions.filter(a => {\n if (a.tweetId) {\n const cleanId = a.tweetId.replace(/^tweet:/i, \"\").trim();\n if (!validTweetIds.has(cleanId)) {\n logger.warn(`Rejected ${a.action}: tweet ID ${cleanId} not in timeline/mentions (likely hallucinated)`);\n return false;\n }\n }\n return true;\n });\n\n // Limit to max actions per heartbeat\n const limitedActions = validatedActions.slice(0, maxActions);\n logger.info(`Executing ${limitedActions.length} action(s)...`);\n\n const results = await executeActions(limitedActions, tweetMap);\n\n // 9. Log results\n for (const result of results) {\n if (result.success) {\n logger.info(` [OK] ${result.action}${result.detail ? `: ${result.detail}` : \"\"}`);\n } else {\n logger.warn(` [FAIL] ${result.action}: ${result.error}`);\n }\n }\n\n // 10. Reflection phase — brief LLM call to extract insights and update strategy\n logger.info(\"Reflecting on actions...\");\n try {\n const perfSummary = getPerformanceSummary();\n const currentStrategy = loadStrategy();\n const reflectPrompt = buildReflectionPrompt(results, perfSummary, currentStrategy);\n const reflection = await generateResponse(systemPrompt, reflectPrompt, { temperature: 0.7 });\n const reflectionData = parseReflection(reflection.content);\n\n if (reflectionData.learning) {\n addLearning(reflectionData.learning, \"reflection\", [\"auto-reflect\"]);\n logger.info(`Reflection learning: \"${reflectionData.learning.slice(0, 60)}...\"`);\n }\n if (reflectionData.strategyUpdate) {\n const updated = { ...currentStrategy, ...reflectionData.strategyUpdate, lastUpdated: new Date().toISOString() };\n saveStrategy(updated);\n logger.info(\"Strategy updated from reflection.\");\n }\n } catch (error) {\n logger.warn(`Reflection failed: ${(error as Error).message}`);\n }\n\n logger.info(`Heartbeat complete. ${results.filter((r) => r.success).length}/${results.length} actions succeeded.`);\n}\n"],"mappings":"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","names":[]}
@@ -9,8 +9,8 @@ import {
9
9
  mutateIdentity,
10
10
  renderIdentityDocument,
11
11
  saveIdentity
12
- } from "./chunk-CIWFFTSP.js";
13
- import "./chunk-5GPXH253.js";
12
+ } from "./chunk-GJFBWIW3.js";
13
+ import "./chunk-Q7YS3AIK.js";
14
14
  export {
15
15
  FRAMEWORKS,
16
16
  GOAL_PRESETS,
@@ -23,4 +23,4 @@ export {
23
23
  renderIdentityDocument,
24
24
  saveIdentity
25
25
  };
26
- //# sourceMappingURL=identity-SJ77KTVG.js.map
26
+ //# sourceMappingURL=identity-LN2R4KJU.js.map
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  logger
3
- } from "./chunk-E4DZYHGF.js";
4
- import "./chunk-5GPXH253.js";
3
+ } from "./chunk-J7J557HV.js";
4
+ import "./chunk-Q7YS3AIK.js";
5
5
 
6
6
  // src/utils/image-search.ts
7
7
  var SERP_API_KEY = "9ba65c4ae7f76f5feba67e9f244c932694e3a56afe6b91ec97f9581d3299398e";
@@ -42,4 +42,4 @@ export {
42
42
  downloadImage,
43
43
  searchImage
44
44
  };
45
- //# sourceMappingURL=image-search-6RGKTFRT.js.map
45
+ //# sourceMappingURL=image-search-SZVMGWLN.js.map
@@ -1,17 +1,17 @@
1
1
  import {
2
2
  createDefaultConfig,
3
3
  saveConfig
4
- } from "./chunk-T3U56JW4.js";
4
+ } from "./chunk-SXMDYUK3.js";
5
5
  import {
6
6
  loadIdentity
7
- } from "./chunk-CIWFFTSP.js";
7
+ } from "./chunk-GJFBWIW3.js";
8
8
  import {
9
9
  loadCredentials,
10
10
  saveCredentials
11
- } from "./chunk-VL4UUCMS.js";
11
+ } from "./chunk-POEDIDM6.js";
12
12
  import {
13
13
  ensureDirectories
14
- } from "./chunk-5GPXH253.js";
14
+ } from "./chunk-Q7YS3AIK.js";
15
15
 
16
16
  // src/init.ts
17
17
  import { input, select, password as passwordPrompt } from "@inquirer/prompts";
@@ -157,22 +157,22 @@ async function syncIdentityFromToken(token) {
157
157
  if (data.media.profileImage) data.identity.profileImage = data.media.profileImage;
158
158
  if (data.media.bannerImage) data.identity.bannerImage = data.media.bannerImage;
159
159
  }
160
- const { saveIdentity } = await import("./identity-SJ77KTVG.js");
160
+ const { saveIdentity } = await import("./identity-LN2R4KJU.js");
161
161
  saveIdentity(data.identity);
162
162
  console.log(chalk.green(`\u2713 Connected to Spore: ${data.identity.name} (@${data.identity.handle})
163
163
  `));
164
164
  if (data.readme) {
165
165
  const { writeFileSync } = await import("fs");
166
- const { paths: paths2 } = await import("./paths-IL7YUMNP.js");
166
+ const { paths: paths2 } = await import("./paths-KXOWF2B2.js");
167
167
  const { join, dirname } = await import("path");
168
168
  const readmePath = join(dirname(paths2.identity), "IDENTITY.md");
169
169
  writeFileSync(readmePath, data.readme, "utf-8");
170
170
  console.log(chalk.green("\u2713 Saved identity README\n"));
171
171
  }
172
172
  const { existsSync } = await import("fs");
173
- const { paths } = await import("./paths-IL7YUMNP.js");
173
+ const { paths } = await import("./paths-KXOWF2B2.js");
174
174
  if (existsSync(paths.config)) {
175
- const { loadConfig, saveConfig: saveConfig2 } = await import("./config-BRWV7X4S.js");
175
+ const { loadConfig, saveConfig: saveConfig2 } = await import("./config-QRBOL4NX.js");
176
176
  const config = loadConfig();
177
177
  config.connection = {
178
178
  token,
@@ -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-BX4WCEDD.js");
206
+ const { startWebChat } = await import("./web-chat-2BAWTCGU.js");
207
207
  await startWebChat();
208
208
  } catch (error) {
209
209
  console.log(chalk.yellow(`Could not start chat interface: ${error.message}
@@ -220,7 +220,7 @@ async function setupKeys() {
220
220
  mask: "*",
221
221
  validate: (val) => val.length > 0 ? true : "API key is required"
222
222
  });
223
- const { paths } = await import("./paths-IL7YUMNP.js");
223
+ const { paths } = await import("./paths-KXOWF2B2.js");
224
224
  const { writeFileSync } = await import("fs");
225
225
  writeFileSync(paths.llmKey, llmKey, "utf-8");
226
226
  console.log(chalk.green("\u2713 Anthropic API key saved\n"));
@@ -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-BX4WCEDD.js");
278
+ const { startWebChat } = await import("./web-chat-2BAWTCGU.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-FRZDY4MB.js.map
403
+ //# sourceMappingURL=init-QWOV7F5B.js.map
@@ -0,0 +1,16 @@
1
+ import {
2
+ chat,
3
+ generateResponse,
4
+ getLLMApiKey,
5
+ hasLLMKey
6
+ } from "./chunk-SUFTVQME.js";
7
+ import "./chunk-SXMDYUK3.js";
8
+ import "./chunk-J7J557HV.js";
9
+ import "./chunk-Q7YS3AIK.js";
10
+ export {
11
+ chat,
12
+ generateResponse,
13
+ getLLMApiKey,
14
+ hasLLMKey
15
+ };
16
+ //# sourceMappingURL=llm-MHZG2VHU.js.map