spora 0.3.5 → 0.3.7

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 (74) hide show
  1. package/dist/{account-creator-AABUY2JU.js → account-creator-PZW5JLHS.js} +5 -5
  2. package/dist/chunk-3FBYOHQR.js +81 -0
  3. package/dist/chunk-3FBYOHQR.js.map +1 -0
  4. package/dist/{chunk-6KCIAMHL.js → chunk-53YLFYJF.js} +1 -4
  5. package/dist/chunk-53YLFYJF.js.map +1 -0
  6. package/dist/{chunk-A6R5ZGK6.js → chunk-AHXZIGQE.js} +2 -2
  7. package/dist/{chunk-FTFTB5Y5.js → chunk-AIEXQCQS.js} +2 -2
  8. package/dist/{chunk-PNZ3XK2N.js → chunk-BNFUXAQW.js} +8 -163
  9. package/dist/chunk-BNFUXAQW.js.map +1 -0
  10. package/dist/{chunk-V6ZNR2SI.js → chunk-EBO4F5NU.js} +2 -2
  11. package/dist/{chunk-KQ37VL54.js → chunk-IIQAE7OP.js} +5 -5
  12. package/dist/{chunk-UCCAF2ZO.js → chunk-KELPENM3.js} +2 -2
  13. package/dist/{chunk-ML4EMUZC.js → chunk-MOCLA2KK.js} +3 -3
  14. package/dist/{chunk-B6VI6L4D.js → chunk-T3JHWIKX.js} +5 -5
  15. package/dist/{chunk-GMSK775L.js → chunk-YEKHNTQO.js} +5 -28
  16. package/dist/chunk-YEKHNTQO.js.map +1 -0
  17. package/dist/{chunk-H62HH5ZI.js → chunk-ZJZKH7N7.js} +2 -2
  18. package/dist/cli.js +53 -71
  19. package/dist/cli.js.map +1 -1
  20. package/dist/{client-BGLXHLID.js → client-2CURS7J6.js} +8 -8
  21. package/dist/{client-TWYR2IIQ.js → client-2ZSXZE3D.js} +8 -8
  22. package/dist/{colony-JVBCMZTK.js → colony-EFGAMLOX.js} +7 -7
  23. package/dist/{config-5EPXA325.js → config-NZAFARS6.js} +3 -3
  24. package/dist/{crypto-HS4CGS4A.js → crypto-FHSQ72NU.js} +3 -3
  25. package/dist/heartbeat-2GVBKQPO.js +358 -0
  26. package/dist/heartbeat-2GVBKQPO.js.map +1 -0
  27. package/dist/{identity-6CXRCXJQ.js → identity-O4FLSZKZ.js} +3 -3
  28. package/dist/{init-PNFSGSIR.js → init-TODR3WR2.js} +19 -52
  29. package/dist/init-TODR3WR2.js.map +1 -0
  30. package/dist/llm-OH2Z4PSN.js +16 -0
  31. package/dist/mcp-server.js +24 -24
  32. package/dist/{memory-2OI3JXY2.js → memory-7FBE26K3.js} +3 -3
  33. package/dist/{memory-LPU2I6NI.js → memory-O3AJIKBX.js} +3 -3
  34. package/dist/{paths-Q4TJEOMQ.js → paths-5GFUUHCZ.js} +2 -2
  35. package/dist/prompt-builder-WYB5B67W.js +17 -0
  36. package/dist/queue-N64QLRAB.js +14 -0
  37. package/dist/{web-chat-QADQADSK.js → web-chat-L5MVPVUR.js} +7 -7
  38. package/dist/x-client-SLAC2ON5.js +12 -0
  39. package/package.json +1 -2
  40. package/dist/chunk-6KCIAMHL.js.map +0 -1
  41. package/dist/chunk-GMSK775L.js.map +0 -1
  42. package/dist/chunk-JAF57FYU.js +0 -114
  43. package/dist/chunk-JAF57FYU.js.map +0 -1
  44. package/dist/chunk-PNZ3XK2N.js.map +0 -1
  45. package/dist/heartbeat-VPRJ4TXU.js +0 -901
  46. package/dist/heartbeat-VPRJ4TXU.js.map +0 -1
  47. package/dist/init-PNFSGSIR.js.map +0 -1
  48. package/dist/llm-UKK62ZBP.js +0 -16
  49. package/dist/prompt-builder-VHGZFBL6.js +0 -19
  50. package/dist/queue-LNBQWMFX.js +0 -14
  51. package/dist/x-client-W5IB7XOM.js +0 -12
  52. /package/dist/{account-creator-AABUY2JU.js.map → account-creator-PZW5JLHS.js.map} +0 -0
  53. /package/dist/{chunk-A6R5ZGK6.js.map → chunk-AHXZIGQE.js.map} +0 -0
  54. /package/dist/{chunk-FTFTB5Y5.js.map → chunk-AIEXQCQS.js.map} +0 -0
  55. /package/dist/{chunk-V6ZNR2SI.js.map → chunk-EBO4F5NU.js.map} +0 -0
  56. /package/dist/{chunk-KQ37VL54.js.map → chunk-IIQAE7OP.js.map} +0 -0
  57. /package/dist/{chunk-UCCAF2ZO.js.map → chunk-KELPENM3.js.map} +0 -0
  58. /package/dist/{chunk-ML4EMUZC.js.map → chunk-MOCLA2KK.js.map} +0 -0
  59. /package/dist/{chunk-B6VI6L4D.js.map → chunk-T3JHWIKX.js.map} +0 -0
  60. /package/dist/{chunk-H62HH5ZI.js.map → chunk-ZJZKH7N7.js.map} +0 -0
  61. /package/dist/{client-BGLXHLID.js.map → client-2CURS7J6.js.map} +0 -0
  62. /package/dist/{client-TWYR2IIQ.js.map → client-2ZSXZE3D.js.map} +0 -0
  63. /package/dist/{colony-JVBCMZTK.js.map → colony-EFGAMLOX.js.map} +0 -0
  64. /package/dist/{config-5EPXA325.js.map → config-NZAFARS6.js.map} +0 -0
  65. /package/dist/{crypto-HS4CGS4A.js.map → crypto-FHSQ72NU.js.map} +0 -0
  66. /package/dist/{identity-6CXRCXJQ.js.map → identity-O4FLSZKZ.js.map} +0 -0
  67. /package/dist/{llm-UKK62ZBP.js.map → llm-OH2Z4PSN.js.map} +0 -0
  68. /package/dist/{memory-2OI3JXY2.js.map → memory-7FBE26K3.js.map} +0 -0
  69. /package/dist/{memory-LPU2I6NI.js.map → memory-O3AJIKBX.js.map} +0 -0
  70. /package/dist/{paths-Q4TJEOMQ.js.map → paths-5GFUUHCZ.js.map} +0 -0
  71. /package/dist/{prompt-builder-VHGZFBL6.js.map → prompt-builder-WYB5B67W.js.map} +0 -0
  72. /package/dist/{queue-LNBQWMFX.js.map → queue-N64QLRAB.js.map} +0 -0
  73. /package/dist/{web-chat-QADQADSK.js.map → web-chat-L5MVPVUR.js.map} +0 -0
  74. /package/dist/{x-client-W5IB7XOM.js.map → x-client-SLAC2ON5.js.map} +0 -0
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/runtime/heartbeat.ts","../src/missions/index.ts","../src/x-client/enhanced-api.ts","../src/runtime/decision-engine.ts","../src/runtime/modes.ts","../src/runtime/variation.ts","../src/runtime/data-collection.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 } from \"./prompt-builder.js\";\nimport { generateResponse } from \"./llm.js\";\nimport { parseActions, executeActions, type ActionResult } from \"./decision-engine.js\";\nimport { calculateModeWeights, selectMode, getModeDescription, getModeEmoji, type HeartbeatContext } from \"./modes.js\";\nimport { loadMood, saveMood, calculateMood, getMoodDescription, calculateSleepDuration, calculateMaxActions } from \"./variation.js\";\nimport { collectDataForMode, getDataSummary } from \"./data-collection.js\";\nimport { loadIdentity } from \"../identity/index.js\";\nimport { getRecentInteractions } from \"../memory/index.js\";\nimport { hasActiveMissions } from \"../missions/index.js\";\nimport { rateLimiter } from \"../x-client/rate-limiter.js\";\n\nlet running = false;\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 ?? 300_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);\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 mood-based duration (if variation system enabled)\n const identity = loadIdentity();\n const variationSystemEnabled = config.runtime?.variationSystem?.enabled ?? true;\n const mood = variationSystemEnabled ? loadMood(identity.traits) : undefined;\n\n const sleepMs = mood && variationSystemEnabled\n ? calculateSleepDuration(intervalMs, mood)\n : intervalMs + Math.floor(Math.random() * intervalMs * 0.3); // Legacy jitter\n\n logger.info(`Sleeping ${Math.round(sleepMs / 1000)}s until next heartbeat...`);\n\n // Sleep in chunks so we can check for stop signals\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 }\n\n clearPid();\n logger.info(\"Spora agent stopped.\");\n console.log(\"\\nSpora agent stopped.\");\n}\n\nasync function runHeartbeat(maxActions: number): Promise<void> {\n const config = loadConfig();\n const identity = loadIdentity();\n\n // Check if mode system is enabled\n const modeSystemEnabled = config.runtime?.modeSystem?.enabled ?? true;\n\n if (!modeSystemEnabled) {\n // Use legacy behavior\n return runLegacyHeartbeat(maxActions);\n }\n\n // === NEW MODE-BASED HEARTBEAT ===\n\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 // 2. Build context for mode selection\n const recentInteractions = getRecentInteractions(20);\n const currentHour = new Date().getHours();\n const isActiveHours = currentHour >= config.schedule.activeHoursStart && currentHour < config.schedule.activeHoursEnd;\n\n const postsToday = recentInteractions.filter(\n (i) => i.type === \"post\" && i.timestamp.startsWith(new Date().toISOString().split(\"T\")[0])\n ).length;\n\n const context: HeartbeatContext = {\n identity,\n traits: identity.traits,\n recentInteractions,\n creditsRemaining: rateLimiter.remaining(),\n creditsTotal: config.credits.monthlyPostLimit,\n currentHour,\n isActiveHours,\n postsToday,\n dailyPostBudget: config.schedule.postsPerDay,\n hasActiveMissions: hasActiveMissions(),\n colonyActivityRecent: false, // TODO: Check Colony activity\n };\n\n // 3. Select mode for this heartbeat\n const modeWeights = calculateModeWeights(context);\n const mode = selectMode(modeWeights);\n\n logger.info(`${getModeEmoji(mode)} Mode: ${mode} - ${getModeDescription(mode)}`);\n console.log(`\\n${getModeEmoji(mode)} ${mode.toUpperCase()} MODE: ${getModeDescription(mode)}\\n`);\n\n // 4. Calculate current mood\n const variationSystemEnabled = config.runtime?.variationSystem?.enabled ?? true;\n const mood = variationSystemEnabled\n ? calculateMood(currentHour, recentInteractions, identity.traits, loadMood(identity.traits))\n : undefined;\n\n if (mood && variationSystemEnabled) {\n logger.info(`Mood: ${getMoodDescription(mood)}`);\n console.log(`Mood: ${getMoodDescription(mood)}\\n`);\n saveMood(mood);\n }\n\n // 5. Collect mode-specific data\n const data = await collectDataForMode(mode);\n logger.info(`Data collected: ${getDataSummary(data)}`);\n\n // 6. Build prompts (will use mode + mood in future)\n // TODO: Update prompt-builder to use mode and mood\n const systemPrompt = buildSystemPrompt();\n const userMessage = buildHeartbeatUserMessage(data.timeline || [], data.mentions || []);\n\n // 7. Ask LLM for decisions\n logger.info(\"Asking LLM for decisions...\");\n const response = await generateResponse(systemPrompt, userMessage);\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 // Adjust max actions based on mood\n const adjustedMaxActions = mood && variationSystemEnabled\n ? calculateMaxActions(maxActions, mood)\n : maxActions;\n\n const limitedActions = actions.slice(0, adjustedMaxActions);\n logger.info(`Executing ${limitedActions.length} action(s) (adjusted from ${actions.length})...`);\n\n const results = await executeActions(limitedActions);\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 logger.info(`Heartbeat complete. ${results.filter((r) => r.success).length}/${results.length} actions succeeded.`);\n\n // 10. TODO: Update state (missions, conversations, etc.)\n}\n\n// Legacy heartbeat for backward compatibility\nasync function runLegacyHeartbeat(maxActions: number): 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 // 2. Read timeline and mentions for context\n logger.info(\"Reading timeline and mentions...\");\n const client = await getXClient();\n\n let timeline: Awaited<ReturnType<typeof client.getTimeline>> = [];\n let mentions: Awaited<ReturnType<typeof client.getMentions>> = [];\n\n try {\n timeline = await client.getTimeline({ count: 20 });\n } catch (error) {\n logger.warn(`Timeline read failed: ${(error as Error).message}`);\n }\n\n try {\n mentions = await client.getMentions({ count: 10 });\n } catch (error) {\n logger.warn(`Mentions read failed: ${(error as Error).message}`);\n }\n\n // 3. Build prompts\n const systemPrompt = buildSystemPrompt();\n const userMessage = buildHeartbeatUserMessage(timeline, mentions);\n\n // 4. Ask LLM for decisions\n logger.info(\"Asking LLM for decisions...\");\n const response = await generateResponse(systemPrompt, userMessage);\n\n // 5. 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 // Limit to max actions per heartbeat\n const limitedActions = actions.slice(0, maxActions);\n logger.info(`Executing ${limitedActions.length} action(s)...`);\n\n const results = await executeActions(limitedActions);\n\n // 6. 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 logger.info(`Heartbeat complete. ${results.filter((r) => r.success).length}/${results.length} actions succeeded.`);\n}\n","import { readFileSync, writeFileSync, existsSync, readdirSync } from \"node:fs\";\nimport { join } from \"node:path\";\nimport { paths } from \"../utils/paths.js\";\nimport { logger } from \"../utils/logger.js\";\n\n/**\n * Mission types define categories of long-term goals\n */\nexport type MissionType =\n | \"growth\" // Follower/influence growth\n | \"conversation\" // Deep, meaningful conversations\n | \"exploration\" // Topic deep dives\n | \"colony\" // Multi-Spore coordination\n | \"learning\" // Understand and form opinions\n | \"custom\"; // User-defined\n\n/**\n * Mission status lifecycle\n */\nexport type MissionStatus =\n | \"active\" // Currently working on\n | \"paused\" // Temporarily stopped\n | \"completed\" // Successfully finished\n | \"failed\"; // Could not complete\n\n/**\n * Mission priority affects mode selection weights\n */\nexport type MissionPriority = \"low\" | \"medium\" | \"high\";\n\n/**\n * Success criteria types\n */\nexport type CriteriaType =\n | \"follower_count\"\n | \"engagement_rate\"\n | \"topic_coverage\"\n | \"conversation_depth\"\n | \"time_based\"\n | \"custom\";\n\n/**\n * Criteria for measuring mission success\n */\nexport interface MissionCriteria {\n type: CriteriaType;\n target: number | string;\n current: number | string;\n description?: string;\n}\n\n/**\n * Progress entry for tracking mission advancement\n */\nexport interface MissionProgress {\n timestamp: string;\n action: string;\n outcome: string;\n reflection?: string;\n}\n\n/**\n * A long-term goal that spans multiple heartbeats\n */\nexport interface Mission {\n id: string;\n title: string;\n description: string;\n type: MissionType;\n status: MissionStatus;\n priority: MissionPriority;\n\n createdAt: string;\n targetDate?: string;\n completedAt?: string;\n\n // Success criteria\n criteria: MissionCriteria[];\n\n // Progress tracking\n progress: MissionProgress[];\n\n // Multi-heartbeat plan\n nextActions: string[];\n blockers: string[];\n\n // Metadata\n tags: string[];\n}\n\n/**\n * Load a specific mission by ID\n */\nexport function loadMission(missionId: string): Mission | null {\n const missionPath = join(paths.missions, `${missionId}.json`);\n\n if (!existsSync(missionPath)) {\n return null;\n }\n\n try {\n const raw = readFileSync(missionPath, \"utf-8\");\n return JSON.parse(raw) as Mission;\n } catch (error) {\n logger.error(`Failed to load mission ${missionId}`, error);\n return null;\n }\n}\n\n/**\n * Save a mission to disk\n */\nexport function saveMission(mission: Mission): void {\n const missionPath = join(paths.missions, `${mission.id}.json`);\n writeFileSync(missionPath, JSON.stringify(mission, null, 2));\n logger.debug(`Mission saved: ${mission.id}`);\n}\n\n/**\n * Load all missions\n */\nexport function loadAllMissions(): Mission[] {\n if (!existsSync(paths.missions)) {\n return [];\n }\n\n try {\n const files = readdirSync(paths.missions).filter(f => f.endsWith(\".json\"));\n const missions: Mission[] = [];\n\n for (const file of files) {\n const missionId = file.replace(\".json\", \"\");\n const mission = loadMission(missionId);\n if (mission) {\n missions.push(mission);\n }\n }\n\n return missions;\n } catch (error) {\n logger.error(\"Failed to load missions\", error);\n return [];\n }\n}\n\n/**\n * Get active missions only\n */\nexport function getActiveMissions(): Mission[] {\n return loadAllMissions().filter(m => m.status === \"active\");\n}\n\n/**\n * Get high-priority active missions\n */\nexport function getHighPriorityMissions(): Mission[] {\n return getActiveMissions().filter(m => m.priority === \"high\");\n}\n\n/**\n * Create a new mission\n */\nexport function createMission(params: {\n title: string;\n description: string;\n type: MissionType;\n priority?: MissionPriority;\n criteria?: MissionCriteria[];\n targetDate?: string;\n tags?: string[];\n}): Mission {\n const mission: Mission = {\n id: `mission-${Date.now()}-${Math.random().toString(36).slice(2, 9)}`,\n title: params.title,\n description: params.description,\n type: params.type,\n status: \"active\",\n priority: params.priority || \"medium\",\n createdAt: new Date().toISOString(),\n targetDate: params.targetDate,\n criteria: params.criteria || [],\n progress: [],\n nextActions: [],\n blockers: [],\n tags: params.tags || [],\n };\n\n saveMission(mission);\n logger.info(`Mission created: ${mission.title} (${mission.id})`);\n\n return mission;\n}\n\n/**\n * Update mission progress\n */\nexport function addMissionProgress(\n missionId: string,\n action: string,\n outcome: string,\n reflection?: string,\n): boolean {\n const mission = loadMission(missionId);\n if (!mission) {\n logger.warn(`Mission not found: ${missionId}`);\n return false;\n }\n\n mission.progress.push({\n timestamp: new Date().toISOString(),\n action,\n outcome,\n reflection,\n });\n\n saveMission(mission);\n logger.info(`Progress added to mission ${mission.title}`);\n\n return true;\n}\n\n/**\n * Update mission criteria (e.g., current value changed)\n */\nexport function updateMissionCriteria(\n missionId: string,\n criteriaIndex: number,\n current: number | string,\n): boolean {\n const mission = loadMission(missionId);\n if (!mission) {\n return false;\n }\n\n if (criteriaIndex < 0 || criteriaIndex >= mission.criteria.length) {\n logger.warn(`Invalid criteria index: ${criteriaIndex}`);\n return false;\n }\n\n mission.criteria[criteriaIndex].current = current;\n saveMission(mission);\n\n // Check if mission is complete\n const allCriteriaMet = mission.criteria.every(c => {\n if (typeof c.target === \"number\" && typeof c.current === \"number\") {\n return c.current >= c.target;\n }\n return c.current === c.target;\n });\n\n if (allCriteriaMet && mission.status === \"active\") {\n completeMission(missionId);\n }\n\n return true;\n}\n\n/**\n * Add a blocker to a mission\n */\nexport function addMissionBlocker(missionId: string, blocker: string): boolean {\n const mission = loadMission(missionId);\n if (!mission) {\n return false;\n }\n\n mission.blockers.push(blocker);\n saveMission(mission);\n\n logger.warn(`Blocker added to mission ${mission.title}: ${blocker}`);\n\n return true;\n}\n\n/**\n * Add a next action to a mission\n */\nexport function addMissionNextAction(missionId: string, action: string): boolean {\n const mission = loadMission(missionId);\n if (!mission) {\n return false;\n }\n\n mission.nextActions.push(action);\n saveMission(mission);\n\n return true;\n}\n\n/**\n * Complete a mission\n */\nexport function completeMission(missionId: string): boolean {\n const mission = loadMission(missionId);\n if (!mission) {\n return false;\n }\n\n mission.status = \"completed\";\n mission.completedAt = new Date().toISOString();\n saveMission(mission);\n\n logger.info(`Mission completed: ${mission.title}`);\n\n return true;\n}\n\n/**\n * Pause a mission\n */\nexport function pauseMission(missionId: string, reason?: string): boolean {\n const mission = loadMission(missionId);\n if (!mission) {\n return false;\n }\n\n mission.status = \"paused\";\n if (reason) {\n mission.blockers.push(`Paused: ${reason}`);\n }\n saveMission(mission);\n\n logger.info(`Mission paused: ${mission.title}`);\n\n return true;\n}\n\n/**\n * Resume a paused mission\n */\nexport function resumeMission(missionId: string): boolean {\n const mission = loadMission(missionId);\n if (!mission || mission.status !== \"paused\") {\n return false;\n }\n\n mission.status = \"active\";\n saveMission(mission);\n\n logger.info(`Mission resumed: ${mission.title}`);\n\n return true;\n}\n\n/**\n * Fail a mission\n */\nexport function failMission(missionId: string, reason: string): boolean {\n const mission = loadMission(missionId);\n if (!mission) {\n return false;\n }\n\n mission.status = \"failed\";\n mission.completedAt = new Date().toISOString();\n mission.blockers.push(`Failed: ${reason}`);\n saveMission(mission);\n\n logger.warn(`Mission failed: ${mission.title} - ${reason}`);\n\n return true;\n}\n\n/**\n * Get missions relevant to current context\n * Used for mode selection and prompt building\n */\nexport function getRelevantMissions(context: {\n recentTopics?: string[];\n recentHandles?: string[];\n currentMode?: string;\n}): Mission[] {\n const activeMissions = getActiveMissions();\n\n // For now, return all active missions\n // Could be enhanced to filter by tags, type, etc.\n return activeMissions.sort((a, b) => {\n // Sort by priority (high first)\n const priorityOrder = { high: 0, medium: 1, low: 2 };\n return priorityOrder[a.priority] - priorityOrder[b.priority];\n });\n}\n\n/**\n * Check if there are any active high-priority missions\n */\nexport function hasActiveMissions(): boolean {\n return getActiveMissions().length > 0;\n}\n\n/**\n * Get mission summary for logging/display\n */\nexport function getMissionSummary(mission: Mission): string {\n const criteriaMet = mission.criteria.filter(c => {\n if (typeof c.target === \"number\" && typeof c.current === \"number\") {\n return c.current >= c.target;\n }\n return c.current === c.target;\n }).length;\n\n return `${mission.title} [${mission.type}] - ${criteriaMet}/${mission.criteria.length} criteria met, ${mission.progress.length} progress entries`;\n}\n","import type { XClientInterface, Tweet, UserProfile } from \"./types.js\";\nimport { logger } from \"../utils/logger.js\";\n\n/**\n * Full conversation thread with context\n */\nexport interface ConversationThread {\n rootTweetId: string;\n tweets: Tweet[];\n participants: string[];\n depth: number;\n}\n\n/**\n * Get full conversation thread for a tweet\n *\n * Recursively fetches parent tweets (replies) up to specified depth\n */\nexport async function getConversationThread(\n client: XClientInterface,\n tweetId: string,\n maxDepth: number = 5,\n): Promise<ConversationThread> {\n logger.debug(`Fetching conversation thread for tweet ${tweetId} (max depth: ${maxDepth})`);\n\n const tweets: Tweet[] = [];\n const participants = new Set<string>();\n let currentId = tweetId;\n let depth = 0;\n\n try {\n // Walk up the reply chain to find root\n while (depth < maxDepth) {\n // Search for the tweet by ID (approximate - search by author/content)\n // Note: This is a limitation without direct tweet lookup API\n // In practice, we'd need to track tweets we've seen or use elevated API access\n\n // For now, we'll just return a partial thread\n // TODO: Implement proper thread walking with API v2 conversation_id\n break;\n }\n\n // Collect participant handles\n for (const tweet of tweets) {\n participants.add(tweet.authorHandle);\n }\n\n logger.info(`Retrieved conversation thread: ${tweets.length} tweets, ${participants.size} participants`);\n\n return {\n rootTweetId: tweets.length > 0 ? tweets[0].id : tweetId,\n tweets,\n participants: Array.from(participants),\n depth,\n };\n } catch (error) {\n logger.error(`Failed to fetch conversation thread for ${tweetId}`, error);\n return {\n rootTweetId: tweetId,\n tweets: [],\n participants: [],\n depth: 0,\n };\n }\n}\n\n/**\n * Get a user's recent tweets\n *\n * Useful for understanding someone before engaging or following\n */\nexport async function getUserTweets(\n client: XClientInterface,\n handle: string,\n count: number = 20,\n): Promise<Tweet[]> {\n try {\n logger.debug(`Fetching recent tweets from @${handle}`);\n\n // Search for tweets from this user\n // Note: This is approximate - proper implementation would use user timeline API\n const query = `from:${handle}`;\n const results = await client.searchTweets(query, { count });\n\n logger.info(`Retrieved ${results.length} tweets from @${handle}`);\n return results;\n } catch (error) {\n logger.error(`Failed to fetch tweets from @${handle}`, error);\n return [];\n }\n}\n\n/**\n * Get user profile with additional context\n */\nexport async function getUserProfileEnhanced(\n client: XClientInterface,\n handle: string,\n): Promise<{ profile: UserProfile; recentTweets: Tweet[] } | null> {\n try {\n logger.debug(`Fetching enhanced profile for @${handle}`);\n\n const [profile, recentTweets] = await Promise.all([\n client.getProfile(handle),\n getUserTweets(client, handle, 10),\n ]);\n\n logger.info(`Enhanced profile retrieved for @${handle}: ${recentTweets.length} recent tweets`);\n\n return { profile, recentTweets };\n } catch (error) {\n logger.error(`Failed to fetch enhanced profile for @${handle}`, error);\n return null;\n }\n}\n\n/**\n * Search for accounts similar to a given handle (by topics/style)\n */\nexport async function findSimilarAccounts(\n client: XClientInterface,\n handle: string,\n topics: string[],\n): Promise<string[]> {\n try {\n logger.debug(`Finding accounts similar to @${handle}`);\n\n // Get user's recent tweets to understand their topics\n const userTweets = await getUserTweets(client, handle, 20);\n\n // Extract common topics from their tweets\n const userTopics = extractTopicsFromTweets(userTweets);\n\n // Search for tweets with similar topics\n const similarTweets: Tweet[] = [];\n for (const topic of userTopics.slice(0, 3)) {\n // Top 3 topics\n try {\n const results = await client.searchTweets(topic, { count: 20 });\n similarTweets.push(...results);\n } catch {\n // Ignore search errors\n }\n }\n\n // Extract unique authors\n const authors = new Set<string>();\n for (const tweet of similarTweets) {\n if (tweet.authorHandle !== handle) {\n authors.add(tweet.authorHandle);\n }\n }\n\n const similar = Array.from(authors).slice(0, 10);\n logger.info(`Found ${similar.length} similar accounts to @${handle}`);\n\n return similar;\n } catch (error) {\n logger.error(`Failed to find similar accounts to @${handle}`, error);\n return [];\n }\n}\n\n/**\n * Extract topics from tweets (helper function)\n */\nfunction extractTopicsFromTweets(tweets: Tweet[]): string[] {\n const topicCounts = new Map<string, number>();\n\n for (const tweet of tweets) {\n // Extract hashtags\n const hashtags = tweet.text.match(/#(\\w+)/g) || [];\n for (const tag of hashtags) {\n const topic = tag.toLowerCase();\n topicCounts.set(topic, (topicCounts.get(topic) || 0) + 1);\n }\n\n // Extract capitalized words (potential topics)\n const words = tweet.text.match(/\\b[A-Z][a-z]+\\b/g) || [];\n for (const word of words) {\n if (word.length > 3) {\n // Skip short words\n const topic = word.toLowerCase();\n topicCounts.set(topic, (topicCounts.get(topic) || 0) + 0.5);\n }\n }\n }\n\n // Sort by frequency\n const sorted = Array.from(topicCounts.entries())\n .sort((a, b) => b[1] - a[1])\n .map(([topic]) => topic);\n\n return sorted;\n}\n\n/**\n * Get tweets from a conversation (all replies to a root tweet)\n */\nexport async function getConversationReplies(\n client: XClientInterface,\n rootTweetId: string,\n): Promise<Tweet[]> {\n try {\n logger.debug(`Fetching conversation replies for tweet ${rootTweetId}`);\n\n // Search for tweets that mention/reply to this tweet\n // Note: Limited by search API capabilities\n // Proper implementation would use conversation_id from API v2\n\n // For now, return empty - would need elevated API access\n logger.warn(\"Conversation reply fetching requires elevated API access\");\n return [];\n } catch (error) {\n logger.error(`Failed to fetch conversation replies for ${rootTweetId}`, error);\n return [];\n }\n}\n\n/**\n * Analyze engagement patterns for a user\n */\nexport async function analyzeUserEngagement(\n client: XClientInterface,\n handle: string,\n): Promise<{\n avgLikes: number;\n avgRetweets: number;\n postFrequency: string;\n topTopics: string[];\n}> {\n try {\n const tweets = await getUserTweets(client, handle, 50);\n\n if (tweets.length === 0) {\n return {\n avgLikes: 0,\n avgRetweets: 0,\n postFrequency: \"unknown\",\n topTopics: [],\n };\n }\n\n // Calculate averages\n const totalLikes = tweets.reduce((sum, t) => sum + (t.likeCount || 0), 0);\n const totalRetweets = tweets.reduce((sum, t) => sum + (t.retweetCount || 0), 0);\n\n const avgLikes = Math.round(totalLikes / tweets.length);\n const avgRetweets = Math.round(totalRetweets / tweets.length);\n\n // Estimate post frequency\n const dates = tweets.map(t => new Date(t.createdAt).getTime()).sort((a, b) => b - a);\n const dayRange = dates.length > 1 ? (dates[0] - dates[dates.length - 1]) / (1000 * 60 * 60 * 24) : 1;\n const postsPerDay = tweets.length / dayRange;\n\n let postFrequency = \"unknown\";\n if (postsPerDay > 10) postFrequency = \"very high\";\n else if (postsPerDay > 3) postFrequency = \"high\";\n else if (postsPerDay > 1) postFrequency = \"moderate\";\n else postFrequency = \"low\";\n\n // Extract top topics\n const topTopics = extractTopicsFromTweets(tweets).slice(0, 5);\n\n logger.info(`Engagement analysis for @${handle}: ${avgLikes} avg likes, ${avgRetweets} avg RTs, ${postFrequency} frequency`);\n\n return {\n avgLikes,\n avgRetweets,\n postFrequency,\n topTopics,\n };\n } catch (error) {\n logger.error(`Failed to analyze engagement for @${handle}`, error);\n return {\n avgLikes: 0,\n avgRetweets: 0,\n postFrequency: \"unknown\",\n topTopics: [],\n };\n }\n}\n\n/**\n * Find interesting accounts to follow based on topics\n */\nexport async function discoverAccountsByTopic(\n client: XClientInterface,\n topic: string,\n minEngagement: number = 10,\n): Promise<string[]> {\n try {\n logger.debug(`Discovering accounts interested in: ${topic}`);\n\n const tweets = await client.searchTweets(topic, { count: 50 });\n\n // Filter for high engagement\n const popularTweets = tweets.filter(t => {\n const engagement = (t.likeCount || 0) + (t.retweetCount || 0);\n return engagement >= minEngagement;\n });\n\n // Extract unique authors\n const authors = new Set<string>();\n for (const tweet of popularTweets) {\n authors.add(tweet.authorHandle);\n }\n\n const accounts = Array.from(authors).slice(0, 15);\n logger.info(`Discovered ${accounts.length} accounts interested in ${topic}`);\n\n return accounts;\n } catch (error) {\n logger.error(`Failed to discover accounts for topic: ${topic}`, error);\n return [];\n }\n}\n","import { logger } from \"../utils/logger.js\";\nimport { getXClient } from \"../x-client/index.js\";\nimport { logInteraction, addLearning } from \"../memory/index.js\";\nimport { loadIdentity, saveIdentity } from \"../identity/index.js\";\nimport { addToQueue } from \"../scheduler/queue.js\";\nimport { rateLimiter } from \"../x-client/rate-limiter.js\";\nimport { addMissionProgress } from \"../missions/index.js\";\nimport { discoverAccountsByTopic } from \"../x-client/enhanced-api.js\";\n\nexport interface AgentAction {\n action: string;\n content?: string;\n tweetId?: string;\n handle?: string;\n tags?: string[];\n reason?: string;\n reasoning?: string;\n // New fields for enhanced actions\n query?: string;\n topic?: string;\n missionId?: string;\n progress?: string;\n planId?: string;\n title?: string;\n description?: string;\n}\n\nexport interface ActionResult {\n action: string;\n success: boolean;\n detail?: string;\n error?: string;\n}\n\nexport function parseActions(llmResponse: string): AgentAction[] {\n // Extract JSON array from the response (may be wrapped in markdown code blocks)\n const jsonMatch = llmResponse.match(/\\[[\\s\\S]*?\\]/);\n if (!jsonMatch) {\n // Try to parse as a single action object\n const objMatch = llmResponse.match(/\\{[\\s\\S]*?\\}/);\n if (objMatch) {\n try {\n return [JSON.parse(objMatch[0]) as AgentAction];\n } catch {\n logger.warn(\"Could not parse LLM response as action object\");\n return [];\n }\n }\n logger.warn(\"No JSON found in LLM response\");\n return [];\n }\n\n try {\n const actions = JSON.parse(jsonMatch[0]) as AgentAction[];\n return Array.isArray(actions) ? actions : [actions];\n } catch {\n logger.warn(\"Failed to parse actions JSON from LLM response\");\n return [];\n }\n}\n\nexport async function executeAction(action: AgentAction): Promise<ActionResult> {\n const { action: type } = action;\n\n try {\n switch (type) {\n case \"post\": {\n if (!action.content) return { action: type, success: false, error: \"No content provided\" };\n if (action.content.length > 280) {\n return { action: type, success: false, error: `Tweet too long: ${action.content.length} chars (max 280)` };\n }\n if (!rateLimiter.canPost()) {\n return { action: type, success: false, error: \"No credits remaining this month\" };\n }\n\n const client = await getXClient();\n const result = await client.postTweet(action.content);\n if (result.success) {\n rateLimiter.consume(1);\n logInteraction({\n id: `int-${Date.now()}`,\n timestamp: new Date().toISOString(),\n type: \"post\",\n tweetId: result.tweetId,\n content: action.content,\n creditsUsed: 1,\n success: true,\n });\n logger.info(`Posted: \"${action.content.slice(0, 50)}...\"`);\n }\n return { action: type, success: result.success, detail: result.tweetId, error: result.error };\n }\n\n case \"reply\": {\n if (!action.tweetId || !action.content) {\n return { action: type, success: false, error: \"Missing tweetId or content\" };\n }\n if (!rateLimiter.canPost()) {\n return { action: type, success: false, error: \"No credits remaining\" };\n }\n\n const client = await getXClient();\n const result = await client.replyToTweet(action.tweetId, action.content);\n if (result.success) {\n rateLimiter.consume(1);\n logInteraction({\n id: `int-${Date.now()}`,\n timestamp: new Date().toISOString(),\n type: \"reply\",\n tweetId: result.tweetId,\n inReplyTo: action.tweetId,\n content: action.content,\n creditsUsed: 1,\n success: true,\n });\n logger.info(`Replied to ${action.tweetId}: \"${action.content.slice(0, 50)}...\"`);\n }\n return { action: type, success: result.success, detail: result.tweetId, error: result.error };\n }\n\n case \"like\": {\n if (!action.tweetId) return { action: type, success: false, error: \"Missing tweetId\" };\n const client = await getXClient();\n const result = await client.likeTweet(action.tweetId);\n if (result.success) {\n logInteraction({\n id: `int-${Date.now()}`,\n timestamp: new Date().toISOString(),\n type: \"like\",\n tweetId: action.tweetId,\n creditsUsed: 0,\n success: true,\n });\n }\n return { action: type, success: result.success, error: result.error };\n }\n\n case \"retweet\": {\n if (!action.tweetId) return { action: type, success: false, error: \"Missing tweetId\" };\n const client = await getXClient();\n const result = await client.retweet(action.tweetId);\n if (result.success) {\n logInteraction({\n id: `int-${Date.now()}`,\n timestamp: new Date().toISOString(),\n type: \"retweet\",\n tweetId: action.tweetId,\n creditsUsed: 0,\n success: true,\n });\n }\n return { action: type, success: result.success, error: result.error };\n }\n\n case \"follow\": {\n if (!action.handle) return { action: type, success: false, error: \"Missing handle\" };\n const client = await getXClient();\n const result = await client.followUser(action.handle);\n if (result.success) {\n logInteraction({\n id: `int-${Date.now()}`,\n timestamp: new Date().toISOString(),\n type: \"follow\",\n targetHandle: action.handle,\n creditsUsed: 0,\n success: true,\n });\n }\n return { action: type, success: result.success, error: result.error };\n }\n\n case \"schedule\": {\n if (!action.content) return { action: type, success: false, error: \"No content\" };\n const entry = addToQueue(action.content);\n logger.info(`Scheduled: \"${action.content.slice(0, 50)}...\" for ${entry.scheduledFor}`);\n return { action: type, success: true, detail: `Scheduled for ${entry.scheduledFor}` };\n }\n\n case \"learn\": {\n if (!action.content) return { action: type, success: false, error: \"No content\" };\n addLearning(action.content, \"agent\", action.tags ?? [\"heartbeat\"]);\n logger.info(`Learned: \"${action.content.slice(0, 50)}...\"`);\n return { action: type, success: true };\n }\n\n case \"reflect\": {\n if (!action.content) return { action: type, success: false, error: \"No content\" };\n const identity = loadIdentity();\n identity.evolutionJournal.push({\n date: new Date().toISOString(),\n reflection: action.content,\n });\n saveIdentity(identity);\n logger.info(`Reflected: \"${action.content.slice(0, 50)}...\"`);\n return { action: type, success: true };\n }\n\n case \"skip\": {\n logger.info(`Skipping: ${action.reason ?? action.reasoning ?? \"no reason given\"}`);\n return { action: type, success: true, detail: action.reason ?? action.reasoning };\n }\n\n // NEW ACTIONS\n\n case \"search\": {\n if (!action.query) return { action: type, success: false, error: \"No query provided\" };\n const client = await getXClient();\n try {\n const results = await client.searchTweets(action.query, { count: 20 });\n logger.info(`Searched \"${action.query}\": found ${results.length} results`);\n // Log as learning\n addLearning(`Searched for \"${action.query}\" and found ${results.length} results`, \"search\", [\"exploration\"]);\n return { action: type, success: true, detail: `Found ${results.length} results` };\n } catch (error) {\n return { action: type, success: false, error: (error as Error).message };\n }\n }\n\n case \"discover\": {\n if (!action.topic) return { action: type, success: false, error: \"No topic provided\" };\n try {\n const client = await getXClient();\n const accounts = await discoverAccountsByTopic(client, action.topic, 10);\n logger.info(`Discovered ${accounts.length} accounts for topic: ${action.topic}`);\n addLearning(`Discovered accounts interested in \"${action.topic}\": ${accounts.join(\", \")}`, \"discovery\", [\"exploration\"]);\n return { action: type, success: true, detail: `Found ${accounts.length} accounts` };\n } catch (error) {\n return { action: type, success: false, error: (error as Error).message };\n }\n }\n\n case \"update_mission\": {\n if (!action.missionId || !action.progress) {\n return { action: type, success: false, error: \"Missing missionId or progress\" };\n }\n const updated = addMissionProgress(\n action.missionId,\n action.content || \"Action taken\",\n action.progress,\n action.reason,\n );\n if (updated) {\n logger.info(`Mission ${action.missionId} progress: ${action.progress}`);\n return { action: type, success: true };\n }\n return { action: type, success: false, error: \"Mission not found\" };\n }\n\n case \"start_mission\": {\n if (!action.title || !action.description) {\n return { action: type, success: false, error: \"Missing title or description\" };\n }\n // TODO: Import and use createMission from missions/index.ts\n logger.info(`Mission creation requested: ${action.title}`);\n return { action: type, success: true, detail: \"Mission creation not yet implemented\" };\n }\n\n case \"join_colony_plan\": {\n if (!action.planId) return { action: type, success: false, error: \"Missing planId\" };\n // TODO: Implement Colony plan joining\n logger.info(`Colony plan join requested: ${action.planId}`);\n return { action: type, success: true, detail: \"Colony plan joining not yet implemented\" };\n }\n\n case \"propose_colony_plan\": {\n if (!action.title || !action.description) {\n return { action: type, success: false, error: \"Missing title or description\" };\n }\n // TODO: Implement Colony plan proposal\n logger.info(`Colony plan proposed: ${action.title}`);\n return { action: type, success: true, detail: \"Colony plan proposal not yet implemented\" };\n }\n\n case \"think\": {\n // Internal reflection, no external action\n logger.info(`Thinking: ${action.content || action.reason || \"contemplating\"}`);\n if (action.content) {\n addLearning(action.content, \"thought\", [\"reflection\"]);\n }\n return { action: type, success: true, detail: \"Internal reflection\" };\n }\n\n default:\n logger.warn(`Unknown action: ${type}`);\n return { action: type, success: false, error: `Unknown action: ${type}` };\n }\n } catch (error) {\n const msg = (error as Error).message;\n logger.error(`Action ${type} failed: ${msg}`);\n return { action: type, success: false, error: msg };\n }\n}\n\nexport async function executeActions(actions: AgentAction[]): Promise<ActionResult[]> {\n const results: ActionResult[] = [];\n for (const action of actions) {\n const result = await executeAction(action);\n results.push(result);\n // Small delay between actions to be human-like\n await new Promise((r) => setTimeout(r, 2000 + Math.random() * 3000));\n }\n return results;\n}\n","import type { Identity, Traits } from \"../identity/schema.js\";\nimport type { InteractionEntry } from \"../memory/index.js\";\nimport { logger } from \"../utils/logger.js\";\n\n/**\n * Heartbeat modes determine what the agent does each cycle\n */\nexport type HeartbeatMode =\n | \"observe\" // Read-only: scan timeline, trending, mentions\n | \"engage\" // Active: reply, like, retweet\n | \"create\" // Post original content\n | \"explore\" // Search topics, discover new accounts\n | \"maintain\" // Check missions, update relationships\n | \"rest\" // Skip heartbeat, minimal activity\n | \"colony\"; // Coordinate with other Spores\n\n/**\n * Weights for each mode (0-1), used for weighted random selection\n */\nexport interface ModeWeights {\n observe: number;\n engage: number;\n create: number;\n explore: number;\n maintain: number;\n rest: number;\n colony: number;\n}\n\n/**\n * Context used to calculate mode weights\n */\nexport interface HeartbeatContext {\n identity: Identity;\n traits: Traits;\n recentInteractions: InteractionEntry[];\n creditsRemaining: number;\n creditsTotal: number;\n currentHour: number;\n isActiveHours: boolean;\n postsToday: number;\n dailyPostBudget: number;\n hasActiveMissions: boolean;\n colonyActivityRecent: boolean;\n}\n\n/**\n * Calculate weights for each mode based on context\n *\n * Weights should sum to ~1.0 but don't need to be exact\n * Mode selection will normalize them\n */\nexport function calculateModeWeights(context: HeartbeatContext): ModeWeights {\n const {\n traits,\n recentInteractions,\n creditsRemaining,\n creditsTotal,\n currentHour,\n isActiveHours,\n postsToday,\n dailyPostBudget,\n hasActiveMissions,\n colonyActivityRecent,\n } = context;\n\n // Base weights from personality traits\n const baseObserve = 0.15 + traits.curiosity * 0.15; // 0.15-0.30\n const baseEngage = 0.20 + (traits.empathy + traits.curiosity) * 0.10; // 0.20-0.40\n const baseCreate = 0.20 + traits.originality * 0.15; // 0.20-0.35\n const baseExplore = 0.10 + traits.curiosity * 0.20; // 0.10-0.30\n const baseMaintain = 0.10;\n const baseRest = 0.10;\n const baseColony = colonyActivityRecent ? 0.15 : 0.05;\n\n // Time-based adjustments\n let timeMultiplier = 1.0;\n if (!isActiveHours) {\n // Outside active hours: prefer observe, explore, rest\n timeMultiplier = 0.3;\n } else if (currentHour >= 8 && currentHour < 12) {\n // Morning: more energy for creation\n timeMultiplier = 1.2;\n } else if (currentHour >= 12 && currentHour < 17) {\n // Afternoon: peak engagement hours\n timeMultiplier = 1.3;\n } else if (currentHour >= 17 && currentHour < 22) {\n // Evening: wind down, more observation\n timeMultiplier = 1.0;\n } else {\n // Late night/early morning: rest mode more likely\n timeMultiplier = 0.5;\n }\n\n // Credit-based adjustments\n const creditRatio = creditsRemaining / creditsTotal;\n const lowCredits = creditRatio < 0.1;\n const veryLowCredits = creditRatio < 0.05;\n\n // Post budget adjustments\n const postRatio = postsToday / dailyPostBudget;\n const nearDailyLimit = postRatio >= 0.8;\n const atDailyLimit = postsToday >= dailyPostBudget;\n\n // Recent activity analysis\n const recentPosts = recentInteractions.filter(i => i.type === \"post\").length;\n const recentReplies = recentInteractions.filter(i => i.type === \"reply\").length;\n const recentLikes = recentInteractions.filter(i => i.type === \"like\").length;\n const totalRecent = recentInteractions.length;\n\n // If recently very active, increase rest probability\n const veryActive = totalRecent > 10;\n const postingHeavy = recentPosts > 5;\n\n // Calculate final weights\n let weights: ModeWeights = {\n observe: baseObserve,\n engage: baseEngage,\n create: baseCreate,\n explore: baseExplore,\n maintain: baseMaintain,\n rest: baseRest,\n colony: baseColony,\n };\n\n // Apply time multiplier to active modes\n if (!isActiveHours) {\n weights.create *= 0.3;\n weights.engage *= 0.5;\n weights.observe *= 1.2;\n weights.explore *= 1.2;\n weights.rest *= 1.5;\n } else {\n weights.create *= timeMultiplier;\n weights.engage *= timeMultiplier;\n }\n\n // Credit constraints\n if (veryLowCredits || atDailyLimit) {\n // Can't create or engage much\n weights.create *= 0.1;\n weights.engage *= 0.3; // Can still like/retweet\n weights.observe *= 1.5;\n weights.explore *= 1.5;\n weights.rest *= 1.3;\n } else if (lowCredits || nearDailyLimit) {\n weights.create *= 0.5;\n weights.engage *= 0.7;\n weights.observe *= 1.3;\n }\n\n // Recent activity adjustments\n if (veryActive) {\n weights.rest *= 2.0;\n weights.maintain *= 1.5;\n weights.create *= 0.7;\n }\n\n if (postingHeavy) {\n // Posted a lot recently, time to observe/engage instead\n weights.create *= 0.5;\n weights.observe *= 1.3;\n weights.engage *= 1.3;\n }\n\n // Mission influence\n if (hasActiveMissions) {\n weights.maintain *= 1.5;\n weights.explore *= 1.2;\n }\n\n // Colony influence\n if (colonyActivityRecent) {\n weights.colony *= 2.0;\n }\n\n // Add some entropy to avoid patterns\n const entropy = 0.15; // 15% random variation\n for (const mode of Object.keys(weights) as (keyof ModeWeights)[]) {\n const randomFactor = 1.0 + (Math.random() * 2 - 1) * entropy;\n weights[mode] *= randomFactor;\n }\n\n logger.debug(`Mode weights: ${JSON.stringify(weights, null, 2)}`);\n\n return weights;\n}\n\n/**\n * Select a mode using weighted random selection\n *\n * Normalizes weights and picks randomly based on probability\n */\nexport function selectMode(weights: ModeWeights): HeartbeatMode {\n // Normalize weights to sum to 1.0\n const total = Object.values(weights).reduce((sum, w) => sum + w, 0);\n const normalized: Record<string, number> = {};\n\n for (const [mode, weight] of Object.entries(weights)) {\n normalized[mode] = weight / total;\n }\n\n // Weighted random selection\n let random = Math.random();\n let cumulative = 0;\n\n for (const [mode, probability] of Object.entries(normalized)) {\n cumulative += probability;\n if (random <= cumulative) {\n logger.info(`Mode selected: ${mode} (${(probability * 100).toFixed(1)}% probability)`);\n return mode as HeartbeatMode;\n }\n }\n\n // Fallback (should never reach here)\n logger.warn(\"Mode selection fallback to observe\");\n return \"observe\";\n}\n\n/**\n * Get a human-readable description of what each mode does\n */\nexport function getModeDescription(mode: HeartbeatMode): string {\n const descriptions: Record<HeartbeatMode, string> = {\n observe: \"Scanning timeline, trending topics, and mentions to build knowledge\",\n engage: \"Actively conversing through replies, likes, and retweets\",\n create: \"Generating and posting original content\",\n explore: \"Searching topics, discovering new accounts, following curiosities\",\n maintain: \"Updating missions, reviewing relationships, and cleaning state\",\n rest: \"Taking a break with minimal or no activity\",\n colony: \"Coordinating with other Spores in the Colony\",\n };\n return descriptions[mode];\n}\n\n/**\n * Get the emoji icon for a mode (for logging/UI)\n */\nexport function getModeEmoji(mode: HeartbeatMode): string {\n const emojis: Record<HeartbeatMode, string> = {\n observe: \"👀\",\n engage: \"💬\",\n create: \"✨\",\n explore: \"🔍\",\n maintain: \"🛠️\",\n rest: \"😴\",\n colony: \"🐝\",\n };\n return emojis[mode];\n}\n","import { readFileSync, writeFileSync, existsSync } from \"node:fs\";\nimport { paths } from \"../utils/paths.js\";\nimport type { Traits } from \"../identity/schema.js\";\nimport type { InteractionEntry } from \"../memory/index.js\";\nimport { logger } from \"../utils/logger.js\";\n\n/**\n * Agent mood represents current emotional/energy state\n * Drifts over time using Brownian motion\n */\nexport interface AgentMood {\n energy: number; // 0-1: How active/excited (affects post frequency, action count)\n focus: number; // 0-1: How focused vs scattered (affects exploration depth)\n social: number; // 0-1: How social vs introspective (affects engagement rate)\n playful: number; // 0-1: How serious vs playful (affects tone, emoji usage)\n timestamp: string; // When this mood was calculated\n}\n\n/**\n * Mood history for tracking drift over time\n */\nexport interface MoodHistory {\n current: AgentMood;\n history: AgentMood[]; // Last 24 hours\n}\n\n/**\n * Load mood from disk, or create default from traits\n */\nexport function loadMood(traits: Traits): AgentMood {\n if (!existsSync(paths.mood)) {\n return createDefaultMood(traits);\n }\n\n try {\n const raw = readFileSync(paths.mood, \"utf-8\");\n const history: MoodHistory = JSON.parse(raw);\n return history.current;\n } catch {\n logger.warn(\"Failed to load mood, creating default\");\n return createDefaultMood(traits);\n }\n}\n\n/**\n * Save mood to disk\n */\nexport function saveMood(mood: AgentMood): void {\n let history: MoodHistory;\n\n if (existsSync(paths.mood)) {\n try {\n const raw = readFileSync(paths.mood, \"utf-8\");\n history = JSON.parse(raw);\n } catch {\n history = { current: mood, history: [] };\n }\n } else {\n history = { current: mood, history: [] };\n }\n\n // Add current to history\n history.history.push(history.current);\n\n // Keep only last 24 hours (assuming ~5 min heartbeats = 288 entries)\n const oneDayAgo = Date.now() - 24 * 60 * 60 * 1000;\n history.history = history.history.filter(m =>\n new Date(m.timestamp).getTime() > oneDayAgo\n );\n\n // Update current\n history.current = mood;\n\n writeFileSync(paths.mood, JSON.stringify(history, null, 2));\n}\n\n/**\n * Create default mood based on personality traits\n * Traits act as the \"baseline\" mood returns to\n */\nfunction createDefaultMood(traits: Traits): AgentMood {\n return {\n energy: 0.5 + (traits.confidence + traits.originality) / 4, // 0.5-0.75\n focus: 0.5 + (traits.formality - traits.curiosity) / 4, // varies\n social: 0.5 + (traits.empathy + traits.humor) / 4, // 0.5-0.75\n playful: 0.5 + (traits.humor - traits.formality) / 4, // varies\n timestamp: new Date().toISOString(),\n };\n}\n\n/**\n * Calculate new mood based on time, recent activity, and personality baseline\n *\n * Mood drifts using Brownian motion with:\n * - Random walk (adds unpredictability)\n * - Mean reversion toward personality baseline\n * - External event influence (viral tweets, lots of engagement)\n */\nexport function calculateMood(\n timeOfDay: number,\n recentActivity: InteractionEntry[],\n traits: Traits,\n previousMood?: AgentMood,\n driftRate: number = 0.1,\n): AgentMood {\n // Start with previous mood or create default\n const baseline = createDefaultMood(traits);\n const prev = previousMood || baseline;\n\n // Time-of-day influence (circadian rhythm simulation)\n let energyMod = 0;\n if (timeOfDay >= 6 && timeOfDay < 9) energyMod = 0.1; // Morning boost\n else if (timeOfDay >= 12 && timeOfDay < 14) energyMod = -0.05; // Post-lunch dip\n else if (timeOfDay >= 18 && timeOfDay < 21) energyMod = 0.05; // Evening energy\n else if (timeOfDay >= 22 || timeOfDay < 6) energyMod = -0.15; // Night fatigue\n\n // Recent activity influence\n const recentEngagement = recentActivity.filter(a =>\n [\"reply\", \"like\", \"retweet\"].includes(a.type)\n ).length;\n const recentPosts = recentActivity.filter(a => a.type === \"post\").length;\n const totalRecent = recentActivity.length;\n\n // High engagement = higher social mood\n const socialMod = recentEngagement > 5 ? 0.1 : 0;\n\n // Lots of posting = lower energy (tired from creating)\n const energyDrain = Math.min(recentPosts * 0.03, 0.2);\n\n // Very active recently = lower focus (scattered)\n const focusDrain = totalRecent > 10 ? 0.1 : 0;\n\n // Brownian motion: random walk with mean reversion\n const drift = (mood: number, base: number, variance: number = driftRate): number => {\n // Random walk component\n const randomWalk = (Math.random() * 2 - 1) * variance;\n\n // Mean reversion component (pull toward baseline)\n const meanReversion = (base - mood) * 0.2;\n\n // Combine\n const newMood = mood + randomWalk + meanReversion;\n\n // Clamp to [0, 1]\n return Math.max(0, Math.min(1, newMood));\n };\n\n // Calculate new mood dimensions\n const newMood: AgentMood = {\n energy: drift(prev.energy + energyMod - energyDrain, baseline.energy),\n focus: drift(prev.focus - focusDrain, baseline.focus),\n social: drift(prev.social + socialMod, baseline.social),\n playful: drift(prev.playful, baseline.playful),\n timestamp: new Date().toISOString(),\n };\n\n logger.debug(`Mood updated: energy=${newMood.energy.toFixed(2)} focus=${newMood.focus.toFixed(2)} social=${newMood.social.toFixed(2)} playful=${newMood.playful.toFixed(2)}`);\n\n return newMood;\n}\n\n/**\n * Get a human-readable mood description\n */\nexport function getMoodDescription(mood: AgentMood): string {\n const energy = mood.energy > 0.7 ? \"energetic\" : mood.energy > 0.4 ? \"moderate\" : \"low-energy\";\n const focus = mood.focus > 0.7 ? \"focused\" : mood.focus > 0.4 ? \"balanced\" : \"scattered\";\n const social = mood.social > 0.7 ? \"very social\" : mood.social > 0.4 ? \"social\" : \"introspective\";\n const playful = mood.playful > 0.7 ? \"playful\" : mood.playful > 0.4 ? \"balanced\" : \"serious\";\n\n return `${energy}, ${focus}, ${social}, ${playful}`;\n}\n\n/**\n * Calculate sleep duration based on mood\n * Higher energy = shorter sleep, lower energy = longer sleep\n */\nexport function calculateSleepDuration(\n baseSleepMs: number,\n mood: AgentMood,\n): number {\n // Energy affects sleep: high energy = shorter wait\n const energyFactor = 1.5 - mood.energy; // 0.5-1.5x multiplier\n\n // Add randomness (20% variance)\n const randomFactor = 0.8 + Math.random() * 0.4;\n\n const sleepMs = baseSleepMs * energyFactor * randomFactor;\n\n logger.debug(`Sleep duration: ${Math.round(sleepMs / 1000)}s (base: ${Math.round(baseSleepMs / 1000)}s, energy: ${mood.energy.toFixed(2)})`);\n\n return Math.round(sleepMs);\n}\n\n/**\n * Determine max actions based on mood\n * Higher energy = more actions\n */\nexport function calculateMaxActions(\n baseMaxActions: number,\n mood: AgentMood,\n): number {\n // Energy and focus affect action count\n const moodFactor = (mood.energy + mood.focus) / 2;\n\n // Low mood = 1-2 actions, high mood = 3-5 actions\n const actions = Math.max(1, Math.round(baseMaxActions * moodFactor));\n\n return Math.min(actions, baseMaxActions + 2); // Cap at +2 above base\n}\n","import type { HeartbeatMode } from \"./modes.js\";\nimport type { Tweet } from \"../x-client/types.js\";\nimport type { Mission } from \"../missions/index.js\";\nimport { getXClient } from \"../x-client/index.js\";\nimport { getActiveMissions } from \"../missions/index.js\";\nimport { logger } from \"../utils/logger.js\";\n\n/**\n * Trending topic extracted from X\n */\nexport interface TrendingTopic {\n topic: string;\n tweetCount: number;\n category?: string;\n}\n\n/**\n * Conversation thread with full context\n */\nexport interface ConversationThread {\n rootTweetId: string;\n tweets: Tweet[];\n participants: string[];\n depth: number;\n}\n\n/**\n * Colony plan from Colony system\n */\nexport interface ColonyPlan {\n id: string;\n title: string;\n proposer: string;\n participants: string[];\n createdAt: string;\n expiresAt: string;\n}\n\n/**\n * Data collected for a heartbeat, varies by mode\n */\nexport interface HeartbeatData {\n mode: HeartbeatMode;\n\n // Variable data based on mode\n timeline?: Tweet[];\n mentions?: Tweet[];\n trending?: TrendingTopic[];\n searchResults?: Tweet[];\n conversationThreads?: ConversationThread[];\n\n // Colony data\n colonyFeed?: Tweet[];\n colonyPlans?: ColonyPlan[];\n\n // Mission context\n activeMissions?: Mission[];\n\n // Timestamp\n collectedAt: string;\n}\n\n/**\n * Collect mode-specific data for this heartbeat\n *\n * Different modes collect different amounts and types of data\n */\nexport async function collectDataForMode(mode: HeartbeatMode): Promise<HeartbeatData> {\n logger.info(`Collecting data for mode: ${mode}`);\n\n const data: HeartbeatData = {\n mode,\n collectedAt: new Date().toISOString(),\n };\n\n const client = await getXClient();\n\n try {\n switch (mode) {\n case \"observe\":\n // Heavy reading mode: lots of data\n data.timeline = await client.getTimeline({ count: 50 }).catch(() => []);\n data.mentions = await client.getMentions({ count: 20 }).catch(() => []);\n // TODO: Add trending when available\n // data.trending = await getTrendingTopics(client).catch(() => []);\n logger.info(`Observe mode: collected ${data.timeline?.length || 0} timeline, ${data.mentions?.length || 0} mentions`);\n break;\n\n case \"engage\":\n // Focus on mentions and recent interactions\n data.mentions = await client.getMentions({ count: 30 }).catch(() => []);\n data.timeline = await client.getTimeline({ count: 20 }).catch(() => []);\n // TODO: Add conversation threads for deep engagement\n logger.info(`Engage mode: collected ${data.mentions?.length || 0} mentions, ${data.timeline?.length || 0} timeline`);\n break;\n\n case \"create\":\n // Light reading: just enough context\n data.timeline = await client.getTimeline({ count: 15 }).catch(() => []);\n data.mentions = await client.getMentions({ count: 10 }).catch(() => []);\n logger.info(`Create mode: collected ${data.timeline?.length || 0} timeline, ${data.mentions?.length || 0} mentions`);\n break;\n\n case \"explore\":\n // Search-focused: minimal timeline\n data.timeline = await client.getTimeline({ count: 10 }).catch(() => []);\n // TODO: Add search results based on curiosity\n // data.searchResults = await exploreTopics(client, context).catch(() => []);\n // data.trending = await getTrendingTopics(client).catch(() => []);\n logger.info(`Explore mode: collected ${data.timeline?.length || 0} timeline`);\n break;\n\n case \"maintain\":\n // Mission-focused: light data collection\n data.activeMissions = getActiveMissions();\n data.timeline = await client.getTimeline({ count: 10 }).catch(() => []);\n data.mentions = await client.getMentions({ count: 5 }).catch(() => []);\n logger.info(`Maintain mode: ${data.activeMissions?.length || 0} active missions, ${data.timeline?.length || 0} timeline`);\n break;\n\n case \"rest\":\n // Minimal data: just check mentions\n data.mentions = await client.getMentions({ count: 5 }).catch(() => []);\n logger.info(`Rest mode: collected ${data.mentions?.length || 0} mentions`);\n break;\n\n case \"colony\":\n // Colony-focused: Colony feed and plans\n data.timeline = await client.getTimeline({ count: 15 }).catch(() => []);\n data.mentions = await client.getMentions({ count: 10 }).catch(() => []);\n // TODO: Add Colony-specific data when Colony API is available\n // data.colonyFeed = await getColonyFeed().catch(() => []);\n // data.colonyPlans = await getColonyPlans().catch(() => []);\n logger.info(`Colony mode: collected ${data.timeline?.length || 0} timeline, ${data.mentions?.length || 0} mentions`);\n break;\n\n default:\n // Fallback: standard data collection\n data.timeline = await client.getTimeline({ count: 20 }).catch(() => []);\n data.mentions = await client.getMentions({ count: 10 }).catch(() => []);\n logger.warn(`Unknown mode ${mode}, using default data collection`);\n }\n } catch (error) {\n logger.error(`Data collection failed for mode ${mode}`, error);\n }\n\n // Always try to load active missions\n if (!data.activeMissions) {\n data.activeMissions = getActiveMissions();\n }\n\n return data;\n}\n\n/**\n * Get data summary for logging\n */\nexport function getDataSummary(data: HeartbeatData): string {\n const parts: string[] = [];\n\n if (data.timeline) parts.push(`${data.timeline.length} timeline`);\n if (data.mentions) parts.push(`${data.mentions.length} mentions`);\n if (data.trending) parts.push(`${data.trending.length} trending`);\n if (data.searchResults) parts.push(`${data.searchResults.length} search results`);\n if (data.conversationThreads) parts.push(`${data.conversationThreads.length} threads`);\n if (data.activeMissions) parts.push(`${data.activeMissions.length} missions`);\n if (data.colonyFeed) parts.push(`${data.colonyFeed.length} colony feed`);\n if (data.colonyPlans) parts.push(`${data.colonyPlans.length} colony plans`);\n\n return parts.length > 0 ? parts.join(\", \") : \"no data\";\n}\n"],"mappings":"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","names":["existsSync","writeFileSync","readFileSync","hasActiveMissions","readFileSync","writeFileSync","existsSync","existsSync","readFileSync","writeFileSync","newMood","writeFileSync","existsSync","readFileSync"]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/init.ts","../src/x-client/profile-updater.ts"],"sourcesContent":["import { input, select, confirm, password as passwordPrompt } from \"@inquirer/prompts\";\nimport chalk from \"chalk\";\nimport { sporaExists, ensureDirectories } from \"./utils/paths.js\";\nimport { createDefaultConfig, saveConfig } from \"./utils/config.js\";\nimport { saveCredentials, type XCredentials } from \"./utils/crypto.js\";\nimport { loadIdentity } from \"./identity/index.js\";\nimport { updateXProfile } from \"./x-client/profile-updater.js\";\n\n/**\n * Fetch identity from token and save locally\n */\nasync function syncIdentityFromToken(token: string): Promise<void> {\n console.log(chalk.gray(\"Connecting to spora.dev...\\n\"));\n\n const apiUrl = process.env.SPORA_API_URL || \"https://www.spora.social\";\n const response = await fetch(`${apiUrl}/api/v1/connect`, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({ token }),\n });\n\n if (!response.ok) {\n const errData = await response.json().catch(() => ({}));\n throw new Error(errData.error || `Connection failed: ${response.statusText}`);\n }\n\n const data = await response.json();\n\n if (!data.identity) {\n throw new Error(\"No Spore identity found for this token\");\n }\n\n // Merge media fields\n if (data.media) {\n if (data.media.profileImage) data.identity.profileImage = data.media.profileImage;\n if (data.media.bannerImage) data.identity.bannerImage = data.media.bannerImage;\n }\n\n const { saveIdentity } = await import(\"./identity/index.js\");\n saveIdentity(data.identity);\n\n console.log(chalk.green(`✓ Connected to Spore: ${data.identity.name} (@${data.identity.handle})\\n`));\n\n // Save README if provided\n if (data.readme) {\n const { writeFileSync } = await import(\"node:fs\");\n const { paths } = await import(\"./utils/paths.js\");\n const { join, dirname } = await import(\"node:path\");\n const readmePath = join(dirname(paths.identity), \"IDENTITY.md\");\n writeFileSync(readmePath, data.readme, \"utf-8\");\n console.log(chalk.green(\"✓ Saved identity README\\n\"));\n }\n\n // Save connection token to config\n const { existsSync } = await import(\"node:fs\");\n const { paths } = await import(\"./utils/paths.js\");\n if (existsSync(paths.config)) {\n const { loadConfig, saveConfig } = await import(\"./utils/config.js\");\n const config = loadConfig();\n config.connection = {\n token,\n apiEndpoint: process.env.SPORA_API_URL || \"https://www.spora.social/api/v1\",\n configVersion: config.connection?.configVersion ?? 0,\n };\n saveConfig(config);\n }\n}\n\n/**\n * Login flow: paste token → sync identity → open chat (keys already saved locally)\n */\nasync function loginFlow(): Promise<void> {\n console.log(chalk.bold(\"\\n━━━ Login to Existing Spore ━━━\\n\"));\n console.log(chalk.gray(\"Paste your setup token from spora.dev\"));\n console.log(chalk.gray(\"(It looks like: spora_7e636ac0...)\\n\"));\n\n const token = await input({\n message: \"Setup token:\",\n validate: (val) => val.length > 0 ? true : \"Token is required\",\n });\n\n ensureDirectories();\n\n try {\n await syncIdentityFromToken(token.trim());\n } catch (error) {\n console.log(chalk.red(`\\n✗ ${(error as Error).message}\\n`));\n console.log(chalk.yellow(\"Please check your token and try again.\\n\"));\n process.exit(1);\n }\n\n console.log(chalk.green(\"✓ Logged in!\\n\"));\n console.log(chalk.gray(\"Opening chat interface...\\n\"));\n\n try {\n const { startWebChat } = await import(\"./web-chat/index.js\");\n await startWebChat();\n } catch (error) {\n console.log(chalk.yellow(`Could not start chat interface: ${(error as Error).message}\\n`));\n console.log(chalk.gray(\"You can start it manually with: spora chat\\n\"));\n }\n}\n\n/**\n * Prompt for LLM provider selection, API key, and X credentials\n */\nasync function setupKeys(): Promise<void> {\n // LLM provider selection\n console.log(chalk.bold(\"\\n━━━ LLM Provider ━━━\\n\"));\n console.log(chalk.gray(\"Choose which LLM will power your Spore's brain.\\n\"));\n\n const provider = await select({\n message: \"Which LLM provider do you want to use?\",\n choices: [\n { name: \"DeepSeek (Recommended — cheaper)\", value: \"deepseek\" },\n { name: \"Anthropic (Claude)\", value: \"anthropic\" },\n ],\n }) as \"deepseek\" | \"anthropic\";\n\n const providerConfigs: Record<string, { model: string; baseUrl: string; label: string; keyHelp: string }> = {\n deepseek: {\n model: \"deepseek-v3.2-speciale\",\n baseUrl: \"https://api.llm-stats.com/v1\",\n label: \"DeepSeek\",\n keyHelp: \"Enter your DeepSeek API key below.\",\n },\n anthropic: {\n model: \"claude-sonnet-4-20250514\",\n baseUrl: \"https://api.anthropic.com/v1\",\n label: \"Anthropic\",\n keyHelp: \"Get your API key at: https://console.anthropic.com/keys\",\n },\n };\n\n const chosen = providerConfigs[provider];\n\n console.log(chalk.bold(`\\n━━━ ${chosen.label} API Key ━━━\\n`));\n console.log(chalk.gray(chosen.keyHelp + \"\\n\"));\n\n const llmKey = await passwordPrompt({\n message: `${chosen.label} API Key:`,\n mask: \"*\",\n validate: (val: string) => val.length > 0 ? true : \"API key is required\",\n });\n\n const { paths } = await import(\"./utils/paths.js\");\n const { writeFileSync } = await import(\"node:fs\");\n writeFileSync(paths.llmKey, llmKey, \"utf-8\");\n\n // Save LLM config immediately so it's available later\n try {\n const { loadConfig: lc, saveConfig: sc } = await import(\"./utils/config.js\");\n const config = lc();\n config.llm = { provider, model: chosen.model, baseUrl: chosen.baseUrl };\n sc(config);\n } catch {\n // Config may not exist yet during init, will be set later\n }\n\n console.log(chalk.green(`✓ ${chosen.label} API key saved\\n`));\n\n // X credentials\n console.log(chalk.bold(\"\\n━━━ Connect Your X Account ━━━\\n\"));\n console.log(chalk.gray(\"Your Spore needs OAuth 1.0a credentials for full X API access.\"));\n console.log(chalk.gray(\"This gives your agent the power to read timelines, post tweets, reply, like, and follow.\\n\"));\n console.log(chalk.cyan(\"How to get these credentials:\"));\n console.log(chalk.gray(\" 1. Go to: \") + chalk.cyan(\"https://developer.x.com/en/portal/dashboard\"));\n console.log(chalk.gray(\" 2. Create or select your app\"));\n console.log(chalk.gray(\" 3. Go to \\\"Keys and tokens\\\" tab\"));\n console.log(chalk.gray(\" 4. Copy all 4 credentials below\\n\"));\n console.log(chalk.yellow(\"Note: You need X Pro account ($200/mo) for posting access.\\n\"));\n\n const apiKey = await passwordPrompt({\n message: \"X API Key (Consumer Key):\",\n mask: \"*\",\n validate: (val: string) => val.length > 0 ? true : \"API Key is required\",\n });\n\n const apiSecret = await passwordPrompt({\n message: \"X API Secret (Consumer Secret):\",\n mask: \"*\",\n validate: (val: string) => val.length > 0 ? true : \"API Secret is required\",\n });\n\n const accessToken = await passwordPrompt({\n message: \"X Access Token:\",\n mask: \"*\",\n validate: (val: string) => val.length > 0 ? true : \"Access Token is required\",\n });\n\n const accessTokenSecret = await passwordPrompt({\n message: \"X Access Token Secret:\",\n mask: \"*\",\n validate: (val: string) => val.length > 0 ? true : \"Access Token Secret is required\",\n });\n\n const bearerToken = await passwordPrompt({\n message: \"X Bearer Token:\",\n mask: \"*\",\n validate: (val: string) => val.length > 0 ? true : \"Bearer Token is required\",\n });\n\n saveCredentials({\n method: \"api\",\n apiKey,\n apiSecret,\n accessToken,\n accessTokenSecret,\n bearerToken,\n });\n console.log(chalk.green(\"✓ X API credentials saved (encrypted)\\n\"));\n}\n\n/**\n * Show completion message and open chat\n */\nasync function showDoneAndOpenChat(): Promise<void> {\n console.log(chalk.green(\"\\n╔═══════════════════════════════════════╗\"));\n console.log(chalk.green.bold(\"║ Setup Complete! ║\"));\n console.log(chalk.green(\"╚═══════════════════════════════════════╝\\n\"));\n\n console.log(chalk.bold.cyan(\"━━━ Your Spore is Ready! ━━━\\n\"));\n console.log(chalk.gray(\"Opening chat interface...\\n\"));\n\n try {\n const { startWebChat } = await import(\"./web-chat/index.js\");\n await startWebChat();\n } catch (error) {\n console.log(chalk.yellow(`Could not start chat interface: ${(error as Error).message}\\n`));\n console.log(chalk.gray(\"You can start it manually with: spora chat\\n\"));\n }\n\n console.log(chalk.bold(\"Quick Start:\\n\"));\n console.log(chalk.cyan(\" spora chat\"));\n console.log(chalk.gray(\" → Talk to your Spore, tell it what to post, how to behave\\n\"));\n console.log(chalk.bold(\"Or start the autonomous agent:\\n\"));\n console.log(chalk.cyan(\" spora start\"));\n console.log(chalk.gray(\" → Your Spore will post and engage autonomously\\n\"));\n console.log(chalk.bold(\"Other commands:\\n\"));\n console.log(chalk.cyan(\" spora create \") + chalk.gray(\"# Create a personality\"));\n console.log(chalk.cyan(\" spora post <text> \") + chalk.gray(\"# Make your Spore post\"));\n console.log(chalk.cyan(\" spora agent-status \") + chalk.gray(\"# Check if agent is running\"));\n console.log(chalk.cyan(\" spora stop \") + chalk.gray(\"# Stop the agent\"));\n console.log(chalk.cyan(\" spora --help \") + chalk.gray(\"# See all commands\\n\"));\n}\n\nexport async function runInit(token?: string): Promise<void> {\n console.log(chalk.bold.cyan(\"\\n╔════════════════════════════════════════╗\"));\n console.log(chalk.bold.cyan(\"║ Welcome to Spora CLI Setup ║\"));\n console.log(chalk.bold.cyan(\"╚════════════════════════════════════════╝\\n\"));\n\n // If token provided via --token flag, this is a new user from the website → full setup\n if (token) {\n ensureDirectories();\n\n console.log(chalk.bold(\"\\n━━━ Connecting Your Spore ━━━\\n\"));\n try {\n await syncIdentityFromToken(token);\n } catch (error) {\n console.log(chalk.red(`\\n✗ ${(error as Error).message}\\n`));\n console.log(chalk.yellow(\"Please check your token and try again.\\n\"));\n process.exit(1);\n }\n\n await setupKeys();\n\n // Update X profile\n console.log(chalk.bold(\"\\n━━━ Updating Your X Profile ━━━\\n\"));\n console.log(chalk.gray(\"Setting up profile picture, banner, and bio to match your Spore...\\n\"));\n try {\n const identity = loadIdentity();\n const result = await updateXProfile(identity);\n if (result.success) {\n console.log(chalk.green(\"✓ Profile updated successfully!\\n\"));\n if (result.updated.length > 0) {\n console.log(chalk.cyan(\"Updated:\"));\n for (const field of result.updated) {\n console.log(chalk.gray(` • ${field}`));\n }\n console.log();\n }\n }\n if (result.errors.length > 0) {\n console.log(chalk.yellow(\"\\nSome updates failed:\"));\n for (const err of result.errors) {\n console.log(chalk.gray(` • ${err}`));\n }\n console.log();\n }\n } catch (error) {\n console.log(chalk.yellow(`Could not update profile: ${(error as Error).message}\\n`));\n console.log(chalk.gray(\"You can manually update your X profile later.\\n\"));\n }\n\n const config = createDefaultConfig({ xMethod: \"api\", xApiTier: \"basic\" });\n config.llm = { provider: \"deepseek\", model: \"deepseek-v3.2-speciale\", baseUrl: \"https://api.llm-stats.com/v1\" };\n config.runtime = { heartbeatIntervalMs: 300_000, actionsPerHeartbeat: 3, enabled: true };\n config.connection = {\n token,\n apiEndpoint: process.env.SPORA_API_URL || \"https://www.spora.social/api/v1\",\n configVersion: 0,\n };\n saveConfig(config);\n\n await showDoneAndOpenChat();\n return;\n }\n\n // No token provided — ask what they want to do\n const action = await select({\n message: \"What would you like to do?\",\n choices: [\n { name: \"Create a new Spore\", value: \"new\" },\n { name: \"Login to existing Spore\", value: \"login\" },\n ],\n });\n\n if (action === \"login\") {\n await loginFlow();\n return;\n }\n\n // \"new\" — full new Spore creation (no token, manual setup)\n ensureDirectories();\n\n await setupKeys();\n\n // Update X profile\n console.log(chalk.bold(\"\\n━━━ Updating Your X Profile ━━━\\n\"));\n console.log(chalk.gray(\"Setting up profile picture, banner, and bio to match your Spore...\\n\"));\n try {\n const identity = loadIdentity();\n const result = await updateXProfile(identity);\n if (result.success) {\n console.log(chalk.green(\"✓ Profile updated successfully!\\n\"));\n if (result.updated.length > 0) {\n console.log(chalk.cyan(\"Updated:\"));\n for (const field of result.updated) {\n console.log(chalk.gray(` • ${field}`));\n }\n console.log();\n }\n }\n if (result.errors.length > 0) {\n console.log(chalk.yellow(\"\\nSome updates failed:\"));\n for (const err of result.errors) {\n console.log(chalk.gray(` • ${err}`));\n }\n console.log();\n }\n } catch (error) {\n console.log(chalk.yellow(`Could not update profile: ${(error as Error).message}\\n`));\n console.log(chalk.gray(\"You can manually update your X profile later.\\n\"));\n }\n\n const config = createDefaultConfig({ xMethod: \"api\", xApiTier: \"basic\" });\n config.llm = { provider: \"deepseek\", model: \"deepseek-v3.2-speciale\", baseUrl: \"https://api.llm-stats.com/v1\" };\n config.runtime = { heartbeatIntervalMs: 300_000, actionsPerHeartbeat: 3, enabled: true };\n saveConfig(config);\n\n await showDoneAndOpenChat();\n}\n","/**\n * X Profile Updater\n * Updates X profile to match Spore identity (name, bio, profile pic, banner)\n */\n\nimport { TwitterApi } from \"twitter-api-v2\";\nimport sharp from \"sharp\";\nimport type { Identity } from \"../identity/schema.js\";\nimport { loadCredentials } from \"../utils/crypto.js\";\n\ninterface ProfileUpdateResult {\n success: boolean;\n updated: string[];\n errors: string[];\n}\n\n/**\n * Update X profile to match Spore identity\n * Requires OAuth 1.0a credentials\n */\nexport async function updateXProfile(identity: Identity): Promise<ProfileUpdateResult> {\n const result: ProfileUpdateResult = {\n success: false,\n updated: [],\n errors: [],\n };\n\n try {\n const creds = loadCredentials();\n if (creds.method !== \"api\") {\n result.errors.push(\"API credentials required\");\n return result;\n }\n\n // Create Twitter API client with OAuth 1.0a credentials\n const client = new TwitterApi({\n appKey: creds.apiKey!,\n appSecret: creds.apiSecret!,\n accessToken: creds.accessToken!,\n accessSecret: creds.accessTokenSecret!,\n });\n\n // Update profile name and bio (username separately to avoid breaking on failure)\n try {\n console.log(`Updating name to: ${identity.name}`);\n console.log(`Updating bio to: ${identity.bio.substring(0, 60)}...`);\n await client.v1.updateAccountProfile({\n name: identity.name,\n description: identity.bio,\n });\n result.updated.push(\"name\", \"bio\");\n console.log(\"Name and bio updated successfully\");\n } catch (error) {\n console.error(\"Name/bio update error:\", error);\n result.errors.push(`Failed to update name/bio: ${(error as Error).message}`);\n }\n\n // Try to update username separately (optional, may fail if taken or restricted)\n if (identity.handle) {\n try {\n console.log(`Attempting to update username to: @${identity.handle}`);\n await client.v1.updateAccountProfile({\n screen_name: identity.handle,\n });\n result.updated.push(\"username\");\n console.log(\"Username updated successfully\");\n } catch (error) {\n // Don't fail the whole update if username change fails\n console.warn(`Could not update username: ${(error as Error).message}`);\n }\n }\n\n // Update profile image if available\n if (identity.profileImage) {\n try {\n console.log(`Downloading profile image from: ${identity.profileImage.substring(0, 60)}...`);\n let imageBuffer = await downloadImage(identity.profileImage);\n console.log(`Downloaded ${(imageBuffer.length / 1024 / 1024).toFixed(2)}MB`);\n\n // Check image dimensions - Twitter requires min 400x400\n const metadata = await sharp(imageBuffer).metadata();\n console.log(`Image dimensions: ${metadata.width}x${metadata.height}`);\n\n if (!metadata.width || !metadata.height || metadata.width < 400 || metadata.height < 400) {\n throw new Error(`Image too small (${metadata.width}x${metadata.height}). Twitter requires minimum 400x400 pixels.`);\n }\n\n // Compress if needed (Twitter profile image limit: 2MB)\n const MAX_PROFILE_SIZE = 2 * 1024 * 1024; // 2MB\n imageBuffer = await compressImageIfNeeded(imageBuffer, MAX_PROFILE_SIZE, \"Profile\");\n\n console.log(`Uploading profile image to X...`);\n await client.v1.updateAccountProfileImage(imageBuffer);\n result.updated.push(\"profile_image\");\n console.log(\"Profile image updated successfully\");\n } catch (error) {\n console.error(\"Profile image error:\", error);\n result.errors.push(`Failed to update profile image: ${(error as Error).message}`);\n }\n } else {\n console.log(\"No profile image URL in identity\");\n }\n\n // Update banner image if available\n if (identity.bannerImage) {\n try {\n console.log(`Downloading banner image from: ${identity.bannerImage.substring(0, 60)}...`);\n let imageBuffer = await downloadImage(identity.bannerImage);\n console.log(`Downloaded ${(imageBuffer.length / 1024 / 1024).toFixed(2)}MB`);\n\n // Compress if needed (Twitter banner limit: 5MB)\n const MAX_BANNER_SIZE = 5 * 1024 * 1024; // 5MB\n imageBuffer = await compressImageIfNeeded(imageBuffer, MAX_BANNER_SIZE, \"Banner\");\n\n console.log(`Uploading banner image to X...`);\n await client.v1.updateAccountProfileBanner(imageBuffer);\n result.updated.push(\"banner_image\");\n console.log(\"Banner image updated successfully\");\n } catch (error) {\n console.error(\"Banner image error:\", error);\n result.errors.push(`Failed to update banner: ${(error as Error).message}`);\n }\n } else {\n console.log(\"No banner image URL in identity\");\n }\n\n result.success = result.updated.length > 0;\n return result;\n } catch (error) {\n result.errors.push((error as Error).message);\n return result;\n }\n}\n\n/**\n * Download image from URL and return as Buffer\n */\nasync function downloadImage(url: string): Promise<Buffer> {\n const response = await fetch(url);\n if (!response.ok) {\n throw new Error(`Failed to download image: ${response.statusText}`);\n }\n const arrayBuffer = await response.arrayBuffer();\n return Buffer.from(arrayBuffer);\n}\n\n/**\n * Compress image if it exceeds size limit by resizing\n * @param buffer Original image buffer\n * @param maxSizeBytes Maximum allowed size in bytes\n * @param type \"profile\" or \"banner\" for logging\n */\nasync function compressImageIfNeeded(\n buffer: Buffer,\n maxSizeBytes: number,\n type: string\n): Promise<Buffer> {\n if (buffer.length <= maxSizeBytes) {\n return buffer;\n }\n\n console.log(\n `${type} image is ${(buffer.length / 1024 / 1024).toFixed(2)}MB, resizing to fit ${(maxSizeBytes / 1024 / 1024).toFixed(0)}MB limit...`\n );\n\n // Calculate scale factor to fit within size limit\n const scaleFactor = Math.sqrt(maxSizeBytes / buffer.length) * 0.85; // 85% of target for safety\n\n // Get current dimensions and calculate new size\n const metadata = await sharp(buffer).metadata();\n const newWidth = Math.floor((metadata.width || 1000) * scaleFactor);\n\n // Resize and convert to JPEG with good quality\n const compressed = await sharp(buffer)\n .resize(newWidth, null, { fit: \"inside\", withoutEnlargement: true })\n .jpeg({ quality: 90, progressive: true })\n .toBuffer();\n\n console.log(\n `Resized ${type} image from ${(buffer.length / 1024 / 1024).toFixed(2)}MB to ${(compressed.length / 1024 / 1024).toFixed(2)}MB`\n );\n\n return compressed;\n}\n"],"mappings":"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","names":["paths","saveConfig","config"]}
@@ -1,16 +0,0 @@
1
- import {
2
- chat,
3
- generateResponse,
4
- getLLMApiKey,
5
- hasLLMKey
6
- } from "./chunk-JAF57FYU.js";
7
- import "./chunk-GMSK775L.js";
8
- import "./chunk-UCCAF2ZO.js";
9
- import "./chunk-6KCIAMHL.js";
10
- export {
11
- chat,
12
- generateResponse,
13
- getLLMApiKey,
14
- hasLLMKey
15
- };
16
- //# sourceMappingURL=llm-UKK62ZBP.js.map
@@ -1,19 +0,0 @@
1
- import {
2
- buildChatPrompt,
3
- buildHeartbeatUserMessage,
4
- buildModeSpecificUserMessage,
5
- buildSystemPrompt
6
- } from "./chunk-PNZ3XK2N.js";
7
- import "./chunk-ML4EMUZC.js";
8
- import "./chunk-GMSK775L.js";
9
- import "./chunk-FTFTB5Y5.js";
10
- import "./chunk-UCCAF2ZO.js";
11
- import "./chunk-V6ZNR2SI.js";
12
- import "./chunk-6KCIAMHL.js";
13
- export {
14
- buildChatPrompt,
15
- buildHeartbeatUserMessage,
16
- buildModeSpecificUserMessage,
17
- buildSystemPrompt
18
- };
19
- //# sourceMappingURL=prompt-builder-VHGZFBL6.js.map
@@ -1,14 +0,0 @@
1
- import {
2
- addToQueue,
3
- flushQueue,
4
- showQueue
5
- } from "./chunk-B6VI6L4D.js";
6
- import "./chunk-GMSK775L.js";
7
- import "./chunk-UCCAF2ZO.js";
8
- import "./chunk-6KCIAMHL.js";
9
- export {
10
- addToQueue,
11
- flushQueue,
12
- showQueue
13
- };
14
- //# sourceMappingURL=queue-LNBQWMFX.js.map
@@ -1,12 +0,0 @@
1
- import {
2
- getXClient,
3
- resetXClient
4
- } from "./chunk-KQ37VL54.js";
5
- import "./chunk-GMSK775L.js";
6
- import "./chunk-UCCAF2ZO.js";
7
- import "./chunk-6KCIAMHL.js";
8
- export {
9
- getXClient,
10
- resetXClient
11
- };
12
- //# sourceMappingURL=x-client-W5IB7XOM.js.map