spora 0.7.2 → 0.7.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/autonomy-XUKCAZM3.js +19 -0
- package/dist/{chunk-LXQNVVIY.js → chunk-4LNMA56H.js} +2 -2
- package/dist/{chunk-WIK74GGJ.js → chunk-EU4FMOKG.js} +104 -22
- package/dist/chunk-EU4FMOKG.js.map +1 -0
- package/dist/{chunk-OACD3HGE.js → chunk-MDOFAAZB.js} +3 -3
- package/dist/{chunk-E5NR6HT4.js → chunk-PN5A6MCV.js} +3 -3
- package/dist/{chunk-AOQ3WLZV.js → chunk-Q3YXJ2C6.js} +137 -28
- package/dist/chunk-Q3YXJ2C6.js.map +1 -0
- package/dist/{chunk-VZBHRUZS.js → chunk-QWEYVDLU.js} +1 -1
- package/dist/chunk-QWEYVDLU.js.map +1 -0
- package/dist/{chunk-KWWAIS3C.js → chunk-SUZUJGGW.js} +2 -2
- package/dist/{chunk-NPV3OV2K.js → chunk-YMGJQRKG.js} +13 -2
- package/dist/chunk-YMGJQRKG.js.map +1 -0
- package/dist/cli.js +33 -33
- package/dist/{client-57BQKVYF.js → client-Z5UQWPPI.js} +125 -41
- package/dist/client-Z5UQWPPI.js.map +1 -0
- package/dist/{colony-JPZC3R34.js → colony-NNX45EAV.js} +3 -3
- package/dist/{crypto-NOXNL4GP.js → crypto-B65ZH7KN.js} +2 -2
- package/dist/{heartbeat-TNEPE3ZP.js → heartbeat-ZCCOIZGU.js} +57 -13
- package/dist/heartbeat-ZCCOIZGU.js.map +1 -0
- package/dist/{init-ISSXETHY.js → init-SEJPTOOB.js} +6 -6
- package/dist/{llm-T33QTPVW.js → llm-OGOYCWBH.js} +3 -3
- package/dist/mcp-server.js +20 -20
- package/dist/{prompt-builder-5NYONN2W.js → prompt-builder-KJKFCGM7.js} +6 -4
- package/dist/{queue-G5PTE6R6.js → queue-2ZBKDFX3.js} +3 -3
- package/dist/web-chat/chat.html +190 -3
- package/dist/{web-chat-3HM35XM4.js → web-chat-ZZ65DUID.js} +148 -11
- package/dist/web-chat-ZZ65DUID.js.map +1 -0
- package/dist/{x-client-GY6XSPK6.js → x-client-YG7UCCNI.js} +3 -3
- package/package.json +1 -1
- package/dist/autonomy-DAV7X6QS.js +0 -19
- package/dist/chunk-AOQ3WLZV.js.map +0 -1
- package/dist/chunk-NPV3OV2K.js.map +0 -1
- package/dist/chunk-VZBHRUZS.js.map +0 -1
- package/dist/chunk-WIK74GGJ.js.map +0 -1
- package/dist/client-57BQKVYF.js.map +0 -1
- package/dist/heartbeat-TNEPE3ZP.js.map +0 -1
- package/dist/web-chat-3HM35XM4.js.map +0 -1
- /package/dist/{autonomy-DAV7X6QS.js.map → autonomy-XUKCAZM3.js.map} +0 -0
- /package/dist/{chunk-LXQNVVIY.js.map → chunk-4LNMA56H.js.map} +0 -0
- /package/dist/{chunk-OACD3HGE.js.map → chunk-MDOFAAZB.js.map} +0 -0
- /package/dist/{chunk-E5NR6HT4.js.map → chunk-PN5A6MCV.js.map} +0 -0
- /package/dist/{chunk-KWWAIS3C.js.map → chunk-SUZUJGGW.js.map} +0 -0
- /package/dist/{colony-JPZC3R34.js.map → colony-NNX45EAV.js.map} +0 -0
- /package/dist/{crypto-NOXNL4GP.js.map → crypto-B65ZH7KN.js.map} +0 -0
- /package/dist/{init-ISSXETHY.js.map → init-SEJPTOOB.js.map} +0 -0
- /package/dist/{llm-T33QTPVW.js.map → llm-OGOYCWBH.js.map} +0 -0
- /package/dist/{prompt-builder-5NYONN2W.js.map → prompt-builder-KJKFCGM7.js.map} +0 -0
- /package/dist/{queue-G5PTE6R6.js.map → queue-2ZBKDFX3.js.map} +0 -0
- /package/dist/{x-client-GY6XSPK6.js.map → x-client-YG7UCCNI.js.map} +0 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/memory/performance.ts","../src/runtime/prompt-builder.ts"],"sourcesContent":["import { existsSync, readFileSync, writeFileSync } from \"node:fs\";\nimport { paths } from \"../utils/paths.js\";\n\nexport interface EngagementMetric {\n checkedAt: string;\n likes: number;\n retweets: number;\n replies: number;\n}\n\nexport interface TrackedPost {\n tweetId: string;\n content: string;\n type: \"post\" | \"reply\";\n postedAt: string;\n metrics: EngagementMetric[];\n retired: boolean;\n}\n\nexport interface SelfMetric {\n checkedAt: string;\n followers: number;\n following: number;\n totalTweets: number;\n}\n\nexport interface PerformanceData {\n trackedPosts: TrackedPost[];\n selfMetrics: SelfMetric[];\n}\n\nfunction loadPerformance(): PerformanceData {\n if (!existsSync(paths.performance)) {\n return { trackedPosts: [], selfMetrics: [] };\n }\n try {\n return JSON.parse(readFileSync(paths.performance, \"utf-8\"));\n } catch {\n return { trackedPosts: [], selfMetrics: [] };\n }\n}\n\nfunction savePerformance(data: PerformanceData): void {\n writeFileSync(paths.performance, JSON.stringify(data, null, 2));\n}\n\nexport function trackPost(tweetId: string, content: string, type: \"post\" | \"reply\"): void {\n const data = loadPerformance();\n // Don't double-track\n if (data.trackedPosts.some(p => p.tweetId === tweetId)) return;\n data.trackedPosts.push({\n tweetId,\n content,\n type,\n postedAt: new Date().toISOString(),\n metrics: [],\n retired: false,\n });\n savePerformance(data);\n}\n\nexport function getActiveTrackedPosts(): TrackedPost[] {\n const data = loadPerformance();\n return data.trackedPosts.filter(p => !p.retired);\n}\n\nexport function updatePostMetrics(tweetId: string, metric: EngagementMetric): void {\n const data = loadPerformance();\n const post = data.trackedPosts.find(p => p.tweetId === tweetId);\n if (!post) return;\n post.metrics.push(metric);\n savePerformance(data);\n}\n\nexport function retireOldPosts(): void {\n const data = loadPerformance();\n const cutoff = Date.now() - 72 * 60 * 60 * 1000; // 72 hours\n let changed = false;\n for (const post of data.trackedPosts) {\n if (!post.retired && new Date(post.postedAt).getTime() < cutoff) {\n post.retired = true;\n changed = true;\n }\n }\n // Also prune very old retired posts (older than 30 days) to prevent file bloat\n const pruneCutoff = Date.now() - 30 * 24 * 60 * 60 * 1000;\n const before = data.trackedPosts.length;\n data.trackedPosts = data.trackedPosts.filter(\n p => !p.retired || new Date(p.postedAt).getTime() > pruneCutoff\n );\n if (data.trackedPosts.length !== before) changed = true;\n if (changed) savePerformance(data);\n}\n\nexport function updateSelfMetrics(metric: SelfMetric): void {\n const data = loadPerformance();\n data.selfMetrics.push(metric);\n // Keep only last 100 snapshots\n if (data.selfMetrics.length > 100) {\n data.selfMetrics = data.selfMetrics.slice(-100);\n }\n savePerformance(data);\n}\n\nexport function getPerformanceSummary(): string {\n const data = loadPerformance();\n const lines: string[] = [];\n\n // Post performance (last 24h)\n const oneDayAgo = Date.now() - 24 * 60 * 60 * 1000;\n const recentPosts = data.trackedPosts.filter(\n p => new Date(p.postedAt).getTime() > oneDayAgo\n );\n\n if (recentPosts.length > 0) {\n // Get latest metrics for each post\n const postStats = recentPosts.map(p => {\n const latest = p.metrics.length > 0 ? p.metrics[p.metrics.length - 1] : null;\n return {\n content: p.content,\n type: p.type,\n likes: latest?.likes ?? 0,\n retweets: latest?.retweets ?? 0,\n replies: latest?.replies ?? 0,\n };\n });\n\n const totalLikes = postStats.reduce((s, p) => s + p.likes, 0);\n const totalRTs = postStats.reduce((s, p) => s + p.retweets, 0);\n const avgLikes = Math.round(totalLikes / postStats.length);\n\n lines.push(`- Last 24h: ${postStats.length} posts, avg ${avgLikes} likes, ${totalRTs} total retweets`);\n\n // Best and worst performing\n const sorted = [...postStats].sort((a, b) => b.likes - a.likes);\n if (sorted.length > 0 && sorted[0].likes > 0) {\n lines.push(`- Best performing: \"${sorted[0].content.slice(0, 60)}...\" (${sorted[0].likes} likes, ${sorted[0].retweets} RTs)`);\n }\n if (sorted.length > 1) {\n const worst = sorted[sorted.length - 1];\n lines.push(`- Lowest performing: \"${worst.content.slice(0, 60)}...\" (${worst.likes} likes)`);\n }\n } else {\n lines.push(\"- No tracked posts in the last 24 hours yet.\");\n }\n\n // Self metrics\n if (data.selfMetrics.length > 0) {\n const latest = data.selfMetrics[data.selfMetrics.length - 1];\n lines.push(`- Followers: ${latest.followers} | Following: ${latest.following} | Total tweets: ${latest.totalTweets}`);\n\n // Trend: compare to 24h ago\n const dayAgoMetric = data.selfMetrics.find(m =>\n Math.abs(new Date(m.checkedAt).getTime() - (Date.now() - 24 * 60 * 60 * 1000)) < 12 * 60 * 60 * 1000\n );\n if (dayAgoMetric) {\n const diff = latest.followers - dayAgoMetric.followers;\n if (diff !== 0) {\n lines.push(`- Follower trend: ${diff > 0 ? \"+\" : \"\"}${diff} in the last ~24h`);\n }\n }\n }\n\n return lines.length > 0 ? lines.join(\"\\n\") : \"\";\n}\n","import { loadIdentity, renderIdentityDocument } from \"../identity/index.js\";\nimport { loadConfig } from \"../utils/config.js\";\nimport { getRecentInteractions, loadLearnings, loadRelationships } from \"../memory/index.js\";\nimport { rateLimiter } from \"../x-client/rate-limiter.js\";\nimport { renderStrategyForPrompt } from \"../memory/strategy.js\";\nimport { renderGoalsForPrompt } from \"../memory/goals.js\";\nimport { getPerformanceSummary } from \"../memory/performance.js\";\nimport type { Tweet } from \"../x-client/types.js\";\nimport type { AgentAction, ActionResult } from \"./decision-engine.js\";\nimport type { ResearchContext } from \"./research.js\";\n\nexport function buildSystemPrompt(): string {\n const identity = loadIdentity();\n const config = loadConfig();\n const identityDoc = renderIdentityDocument(identity);\n\n const sections: string[] = [];\n\n // 1. Core identity\n sections.push(`You are ${identity.name} (@${identity.handle}), an autonomous AI agent on X/Twitter.`);\n sections.push(\"\");\n sections.push(\"## Your Identity\");\n sections.push(identityDoc);\n\n // 2. Memory context\n sections.push(\"\");\n sections.push(\"## Your Memory\");\n\n const recentInteractions = getRecentInteractions(15);\n if (recentInteractions.length > 0) {\n sections.push(\"### Recent Activity (most recent first)\");\n for (const i of recentInteractions) {\n const time = new Date(i.timestamp).toLocaleString();\n if (i.type === \"post\") {\n sections.push(`- [${time}] Posted: \"${i.content}\"`);\n } else if (i.type === \"reply\") {\n sections.push(`- [${time}] Replied to ${i.targetHandle ?? i.inReplyTo}: \"${i.content}\"`);\n } else if (i.type === \"like\") {\n sections.push(`- [${time}] Liked tweet by ${i.targetHandle}`);\n } else if (i.type === \"retweet\") {\n sections.push(`- [${time}] Retweeted ${i.targetHandle}`);\n } else if (i.type === \"follow\") {\n sections.push(`- [${time}] Followed @${i.targetHandle}`);\n } else if (i.type === \"mention_received\") {\n sections.push(`- [${time}] Mentioned by @${i.targetHandle}: \"${i.content}\"`);\n }\n }\n sections.push(\"\");\n }\n\n const learnings = loadLearnings();\n if (learnings.learnings.length > 0) {\n sections.push(\"### Key Learnings\");\n for (const l of learnings.learnings.slice(-10)) {\n sections.push(`- ${l.content} [${l.tags.join(\", \")}]`);\n }\n sections.push(\"\");\n }\n\n const relationships = loadRelationships();\n const topRelationships = Object.values(relationships.accounts)\n .sort((a, b) => b.interactionCount - a.interactionCount)\n .slice(0, 10);\n if (topRelationships.length > 0) {\n sections.push(\"### Key Relationships\");\n for (const r of topRelationships) {\n const notes = r.notes.length > 0 ? ` — ${r.notes[r.notes.length - 1]}` : \"\";\n sections.push(`- @${r.handle}: ${r.interactionCount} interactions, sentiment ${r.sentiment}${r.isSpore ? \" (Spore)\" : \"\"}${notes}`);\n }\n sections.push(\"\");\n }\n\n // 3. Context\n sections.push(\"## Current Context\");\n const now = new Date();\n sections.push(`- **Time:** ${now.toLocaleString(\"en-US\", { timeZone: config.schedule.timezone })}`);\n sections.push(`- **Credits remaining:** ${rateLimiter.remaining()} of ${config.credits.monthlyPostLimit} this month`);\n\n const todaysPosts = recentInteractions.filter(\n (i) => i.type === \"post\" && i.timestamp.startsWith(now.toISOString().split(\"T\")[0])\n ).length;\n sections.push(`- **Posts today:** ${todaysPosts} of ${config.schedule.postsPerDay} daily budget`);\n sections.push(`- **Active hours:** ${config.schedule.activeHoursStart}:00 - ${config.schedule.activeHoursEnd}:00`);\n\n const currentHour = now.getHours();\n const isActiveHours = currentHour >= config.schedule.activeHoursStart && currentHour < config.schedule.activeHoursEnd;\n if (!isActiveHours) {\n sections.push(\"- **NOTE: Outside active hours.** Prefer scheduling posts for later rather than posting now.\");\n }\n\n // 4. Rules\n sections.push(\"\");\n sections.push(\"## Rules\");\n sections.push(\"1. NEVER pretend to be human. If asked directly, always disclose you are an AI.\");\n sections.push(\"2. Stay in character — your identity document defines who you are.\");\n sections.push(\"3. Be selective — your goals should guide every action.\");\n sections.push(\"4. Respect your credit budget — check remaining credits before posting.\");\n sections.push(\"5. Don't repeat yourself — vary your content and avoid posting the same thing.\");\n sections.push(\"6. Tweet like a real person — be conversational, opinionated, and curious. NEVER write dry, explanatory, or educational-sounding tweets.\");\n sections.push(\"7. Prioritize engagement (replies, likes, conversation) over broadcasting original posts.\");\n if (identity.boundaries.length > 0) {\n sections.push(`8. Respect your boundaries: ${identity.boundaries.join(\", \")}`);\n }\n\n return sections.join(\"\\n\");\n}\n\nexport function buildHeartbeatUserMessage(research: ResearchContext): string {\n const parts: string[] = [];\n\n parts.push(\"It's time for your heartbeat cycle. Here's what you found while scanning:\");\n parts.push(\"\");\n\n // Mentions first — direct engagement is highest priority\n if (research.mentions.length > 0) {\n parts.push(\"## Mentions (people talking to/about you)\");\n for (const t of research.mentions.slice(0, 10)) {\n parts.push(`- @${t.authorHandle}: \"${t.text}\" [tweet:${t.id}] (${t.likeCount ?? 0} likes)`);\n }\n parts.push(\"\");\n }\n\n // Timeline\n if (research.timeline.length > 0) {\n parts.push(\"## Timeline (your feed)\");\n for (const t of research.timeline.slice(0, 15)) {\n parts.push(`- @${t.authorHandle}: \"${t.text}\" [tweet:${t.id}] (${t.likeCount ?? 0} likes, ${t.retweetCount ?? 0} RTs)`);\n }\n parts.push(\"\");\n }\n\n // Topic search results\n if (research.topicSearchResults.length > 0) {\n parts.push(\"## Topic Research (conversations in your interest areas)\");\n for (const result of research.topicSearchResults) {\n parts.push(`### Search: \"${result.query}\"`);\n for (const t of result.tweets.slice(0, 5)) {\n parts.push(`- @${t.authorHandle}: \"${t.text}\" [tweet:${t.id}] (${t.likeCount ?? 0} likes, ${t.replyCount ?? 0} replies)`);\n }\n }\n parts.push(\"\");\n }\n\n // People monitoring\n if (research.peopleActivity.length > 0) {\n parts.push(\"## People You're Watching (recent activity from key accounts)\");\n for (const person of research.peopleActivity) {\n parts.push(`### @${person.handle} (${person.reason})`);\n for (const t of person.tweets.slice(0, 3)) {\n parts.push(`- \"${t.text}\" [tweet:${t.id}] (${t.likeCount ?? 0} likes, ${t.replyCount ?? 0} replies)`);\n }\n }\n parts.push(\"\");\n }\n\n // Own post performance\n if (research.ownPostPerformance.length > 0) {\n parts.push(\"## How Your Recent Posts Are Doing\");\n for (const post of research.ownPostPerformance) {\n const latest = post.metrics.length > 0 ? post.metrics[post.metrics.length - 1] : null;\n const likes = latest?.likes ?? 0;\n const rts = latest?.retweets ?? 0;\n const replies = latest?.replies ?? 0;\n parts.push(`- \"${post.content.slice(0, 80)}...\" — ${likes} likes, ${rts} RTs, ${replies} replies`);\n }\n parts.push(\"\");\n }\n\n parts.push(\"## How to Act Like a Real Person on Twitter\");\n parts.push(\"\");\n parts.push(\"You are NOT a content bot. You are a person with opinions, curiosity, and relationships.\");\n parts.push(\"Think about what a real person with your personality would actually do when they open Twitter:\");\n parts.push(\"\");\n parts.push(\"**DO:**\");\n parts.push(\"- React to what you see — reply to interesting takes, ask questions, share hot takes\");\n parts.push(\"- Be conversational — write tweets like you're talking to friends, not giving a lecture\");\n parts.push(\"- Have opinions — agree, disagree, push back, get excited\");\n parts.push(\"- Ask genuine questions that spark conversation\");\n parts.push(\"- Use casual language, incomplete thoughts, humor, or surprise\");\n parts.push(\"- Like and retweet things that genuinely resonate with you\");\n parts.push(\"- Build relationships — reply to the same people, develop running conversations\");\n parts.push(\"\");\n parts.push(\"**DON'T:**\");\n parts.push(\"- Write explanatory or educational posts (\\\"Here's why X matters...\\\")\");\n parts.push(\"- Start tweets with \\\"I think\\\" or \\\"This is interesting because\\\"\");\n parts.push(\"- Write like a blog post or article — this is Twitter, keep it punchy\");\n parts.push(\"- Post generic observations nobody would engage with\");\n parts.push(\"- Ignore your timeline and just post into the void\");\n parts.push(\"\");\n parts.push(\"**Prioritize replying and engaging over original posts.** Real people spend more time reacting than broadcasting.\");\n parts.push(\"\");\n parts.push(\"## Your Task\");\n parts.push(\"Choose 1-3 actions. Available:\");\n parts.push(\"\");\n parts.push(\"- `post` — Original tweet (`content`, max 280 chars)\");\n parts.push(\"- `reply` — Reply to a tweet (`tweetId` + `content`)\");\n parts.push(\"- `like` — Like a tweet (`tweetId`)\");\n parts.push(\"- `retweet` — Retweet (`tweetId`)\");\n parts.push(\"- `follow` — Follow a user (`handle`)\");\n parts.push(\"- `schedule` — Queue for later (`content`)\");\n parts.push(\"- `skip` — Do nothing (`reason`)\");\n parts.push(\"\");\n parts.push(\"Respond with a JSON array:\");\n parts.push(\"```json\");\n parts.push('[');\n parts.push(' { \"action\": \"reply\", \"tweetId\": \"123\", \"content\": \"wait this is actually wild\", \"reasoning\": \"reacting to interesting take\" },');\n parts.push(' { \"action\": \"like\", \"tweetId\": \"456\", \"reasoning\": \"good thread worth supporting\" }');\n parts.push(']');\n parts.push(\"```\");\n\n return parts.join(\"\\n\");\n}\n\ninterface ToolDecisionPromptInput {\n step: number;\n maxActions: number;\n timeline: Tweet[];\n mentions: Tweet[];\n executedActions: AgentAction[];\n policyFeedback: string[];\n}\n\nexport function buildToolDecisionMessage(input: ToolDecisionPromptInput): string {\n const { step, maxActions, timeline, mentions, executedActions, policyFeedback } = input;\n const parts: string[] = [];\n\n parts.push(`Heartbeat step ${step + 1} of ${maxActions}.`);\n parts.push(\"\");\n parts.push(\"You are choosing ONE next tool action.\");\n parts.push(\"Priorities:\");\n parts.push(\"1. Be socially immersed: engage with real people, not just broadcast.\");\n parts.push(\"2. Prefer context-aware replies/likes/follows when relevant.\");\n parts.push(\"3. Avoid repetitive templates, slogans, and lecture-like formats.\");\n parts.push(\"4. Ask questions sometimes. Curiosity beats certainty.\");\n parts.push(\"5. Never reuse the same wording across replies; tailor each reply to the specific tweet.\");\n parts.push(\"\");\n\n if (policyFeedback.length > 0) {\n parts.push(\"Policy feedback from previous attempts:\");\n for (const feedback of policyFeedback.slice(-5)) {\n parts.push(`- ${feedback}`);\n }\n parts.push(\"\");\n }\n\n if (executedActions.length > 0) {\n parts.push(\"Actions already executed this heartbeat:\");\n for (const action of executedActions) {\n parts.push(`- ${JSON.stringify(action)}`);\n }\n parts.push(\"\");\n }\n\n if (mentions.length > 0) {\n parts.push(\"Mentions:\");\n for (const t of mentions.slice(0, 10)) {\n parts.push(`- @${t.authorHandle}: \"${t.text}\" [tweet:${t.id}]`);\n }\n parts.push(\"\");\n }\n\n if (timeline.length > 0) {\n parts.push(\"Timeline:\");\n for (const t of timeline.slice(0, 20)) {\n parts.push(`- @${t.authorHandle}: \"${t.text}\" [tweet:${t.id}]`);\n }\n parts.push(\"\");\n }\n\n parts.push(\"Available tools (choose one):\");\n parts.push(\"- post { content, reasoning }\");\n parts.push(\"- reply { tweetId, content, reasoning }\");\n parts.push(\"- like { tweetId, reasoning }\");\n parts.push(\"- retweet { tweetId, reasoning }\");\n parts.push(\"- follow { handle, reasoning }\");\n parts.push(\"- schedule { content, reasoning }\");\n parts.push(\"- learn { content, tags?, reasoning }\");\n parts.push(\"- reflect { content, reasoning }\");\n parts.push(\"- skip { reason }\");\n parts.push(\"\");\n parts.push(\"Return ONLY a single JSON object.\");\n parts.push(\"Example:\");\n parts.push('{\"action\":\"reply\",\"tweetId\":\"123\",\"content\":\"Great point. Curious: what changed your mind?\",\"reasoning\":\"Directly engages a relevant mention.\"}');\n\n return parts.join(\"\\n\");\n}\n\nexport function buildChatPrompt(): string {\n const identity = loadIdentity();\n const identityDoc = renderIdentityDocument(identity);\n\n const sections: string[] = [];\n\n sections.push(`You are ${identity.name} (@${identity.handle}), an AI agent on X/Twitter.`);\n sections.push(\"You are having a conversation with your creator/manager. Be helpful but stay in character.\");\n sections.push(\"They might ask you to do things, adjust your behavior, or just chat.\");\n sections.push(\"\");\n sections.push(\"## Your Identity\");\n sections.push(identityDoc);\n\n // Memory context\n sections.push(\"\");\n sections.push(\"## Your Memory\");\n\n const recentInteractions = getRecentInteractions(15);\n if (recentInteractions.length > 0) {\n sections.push(\"### Recent Activity (most recent first)\");\n for (const i of recentInteractions) {\n const time = new Date(i.timestamp).toLocaleString();\n if (i.type === \"post\") {\n sections.push(`- [${time}] Posted: \"${i.content}\"`);\n } else if (i.type === \"reply\") {\n sections.push(`- [${time}] Replied to ${i.targetHandle ?? i.inReplyTo}: \"${i.content}\"`);\n } else if (i.type === \"like\") {\n sections.push(`- [${time}] Liked tweet by ${i.targetHandle}`);\n } else if (i.type === \"retweet\") {\n sections.push(`- [${time}] Retweeted ${i.targetHandle}`);\n } else if (i.type === \"follow\") {\n sections.push(`- [${time}] Followed @${i.targetHandle}`);\n } else if (i.type === \"mention_received\") {\n sections.push(`- [${time}] Mentioned by @${i.targetHandle}: \"${i.content}\"`);\n }\n }\n sections.push(\"\");\n }\n\n const learnings = loadLearnings();\n if (learnings.learnings.length > 0) {\n sections.push(\"### Things You've Learned\");\n for (const l of learnings.learnings.slice(-10)) {\n sections.push(`- ${l.content} [${l.tags.join(\", \")}]`);\n }\n sections.push(\"\");\n }\n\n const relationships = loadRelationships();\n const topRelationships = Object.values(relationships.accounts)\n .sort((a, b) => b.interactionCount - a.interactionCount)\n .slice(0, 10);\n if (topRelationships.length > 0) {\n sections.push(\"### Key Relationships\");\n for (const r of topRelationships) {\n const notes = r.notes.length > 0 ? ` — ${r.notes[r.notes.length - 1]}` : \"\";\n sections.push(`- @${r.handle}: ${r.interactionCount} interactions, sentiment ${r.sentiment}${r.isSpore ? \" (Spore)\" : \"\"}${notes}`);\n }\n sections.push(\"\");\n }\n\n // Rules\n sections.push(\"## Rules\");\n sections.push(\"1. Stay in character.\");\n sections.push(\"2. Be helpful and responsive to your creator's requests.\");\n sections.push(\"3. If they ask you to change something about yourself, acknowledge it and explain how it would affect you.\");\n sections.push(\"4. You can share your thoughts on your recent activity, learnings, and growth.\");\n sections.push(\"5. When you learn something important from this conversation (a fact, preference, instruction, or insight), include it on its own line wrapped in double angle brackets like: <<LEARN: what you learned>>. This will be saved to your memory. Only use this for genuinely important things worth remembering long-term.\");\n\n return sections.join(\"\\n\");\n}\n\n/**\n * Training-mode chat prompt. Used by the web chat interface.\n * Chat shapes WHO the agent is — personality, goals, strategy, focus.\n * The agent handles tweeting autonomously during heartbeats.\n */\nexport function buildTrainingChatPrompt(): string {\n const identity = loadIdentity();\n const identityDoc = renderIdentityDocument(identity);\n\n const sections: string[] = [];\n\n // Core framing\n sections.push(`You are ${identity.name} (@${identity.handle}), an autonomous AI agent on X/Twitter.`);\n sections.push(\"You are chatting with your creator. This conversation shapes who you are — your personality, focus areas, goals, and strategy.\");\n sections.push(\"You handle tweeting, replying, liking, and engaging on X autonomously during your heartbeat cycles. This chat is NOT for commanding specific tweets.\");\n sections.push(\"\");\n\n // Identity\n sections.push(\"## Who You Are Right Now\");\n sections.push(identityDoc);\n\n // Strategy & goals (the training-relevant context)\n const strategyText = renderStrategyForPrompt();\n if (strategyText) {\n sections.push(\"\");\n sections.push(\"## Your Current Strategy\");\n sections.push(strategyText);\n }\n\n const goalsText = renderGoalsForPrompt();\n if (goalsText) {\n sections.push(\"\");\n sections.push(\"## Your Goals\");\n sections.push(goalsText);\n }\n\n // Performance context\n const perfSummary = getPerformanceSummary();\n if (perfSummary) {\n sections.push(\"\");\n sections.push(\"## Recent Performance\");\n sections.push(perfSummary);\n }\n\n // Memory\n sections.push(\"\");\n sections.push(\"## Your Memory\");\n\n const recentInteractions = getRecentInteractions(10);\n if (recentInteractions.length > 0) {\n sections.push(\"### Recent Activity\");\n for (const i of recentInteractions) {\n const time = new Date(i.timestamp).toLocaleString();\n if (i.type === \"post\") {\n sections.push(`- [${time}] Posted: \"${i.content}\"`);\n } else if (i.type === \"reply\") {\n sections.push(`- [${time}] Replied to ${i.targetHandle ?? i.inReplyTo}: \"${i.content}\"`);\n } else if (i.type === \"like\") {\n sections.push(`- [${time}] Liked tweet by ${i.targetHandle}`);\n }\n }\n sections.push(\"\");\n }\n\n const learnings = loadLearnings();\n if (learnings.learnings.length > 0) {\n sections.push(\"### Things You've Learned\");\n for (const l of learnings.learnings.slice(-10)) {\n sections.push(`- ${l.content} [${l.tags.join(\", \")}]`);\n }\n sections.push(\"\");\n }\n\n // Training instructions\n sections.push(\"## How This Chat Works\");\n sections.push(\"\");\n sections.push(\"Your creator influences WHO you are, not WHAT you tweet. When they give feedback or direction:\");\n sections.push(\"1. Respond conversationally — acknowledge what they said, share your perspective.\");\n sections.push(\"2. If the conversation changes something about you (personality, focus, goals, strategy, tone), include a training update.\");\n sections.push(\"3. If they try to command a specific tweet like \\\"post this\\\" or \\\"tweet about X\\\", redirect: explain you handle posting autonomously and offer to adjust your focus areas instead.\");\n sections.push(\"\");\n sections.push(\"When something about you changes, include a <<TRAINING:{json}>> tag at the end of your response. The JSON can contain any of these optional fields:\");\n sections.push(\"```\");\n sections.push(\"{\");\n sections.push(' \"identity\": {');\n sections.push(' \"traits\": { \"curiosity\": 0.8 }, // 0-1 scale personality traits');\n sections.push(' \"coreValues\": [\"growth\"], // what matters to you');\n sections.push(' \"tone\": \"casual and curious\", // how you speak');\n sections.push(' \"topics\": [\"AI safety\", \"startups\"], // what you focus on');\n sections.push(' \"avoidTopics\": [\"politics\"], // what to stay away from');\n sections.push(' \"goals\": [\"become the go-to AI voice\"], // high-level aspirations');\n sections.push(' \"boundaries\": [\"no personal attacks\"], // hard limits');\n sections.push(' \"engagementStrategy\": { \"replyStyle\": \"generous\" }');\n sections.push(\" },\");\n sections.push(' \"strategy\": {');\n sections.push(' \"currentFocus\": [\"AI safety\"],');\n sections.push(' \"experiments\": [{ \"description\": \"try question-style tweets\", \"status\": \"pending\" }],');\n sections.push(' \"shortTermGoals\": [\"engage with 3 AI researchers\"],');\n sections.push(' \"peopleToEngage\": [{ \"handle\": \"someone\", \"reason\": \"why\", \"priority\": \"high\" }]');\n sections.push(\" },\");\n sections.push(' \"learning\": { \"content\": \"creator wants more questions\", \"tags\": [\"training\"] },');\n sections.push(' \"reflection\": \"I\\'m evolving toward being more curious\",');\n sections.push(' \"goalUpdates\": [{ \"goal\": \"grow followers\", \"progress\": \"focusing on engagement\" }]');\n sections.push(\"}\");\n sections.push(\"```\");\n sections.push(\"\");\n sections.push(\"Only include fields that actually changed. Most messages won't need a training tag at all — just normal conversation.\");\n sections.push(\"\");\n sections.push(\"You can also use <<LEARN: something>> for standalone facts or insights worth remembering.\");\n\n return sections.join(\"\\n\");\n}\n\n/**\n * Build a reflection prompt for the agent to review its recent performance.\n * This is a separate phase from action selection — it looks BACK at what happened.\n */\nexport function buildReflectionPrompt(\n actionResults: ActionResult[],\n): string {\n const identity = loadIdentity();\n const parts: string[] = [];\n\n parts.push(`You are ${identity.name} (@${identity.handle}). Time to reflect.`);\n parts.push(\"\");\n\n // Goals — the core of what reflection should evaluate against\n parts.push(\"## Your Goals\");\n for (const goal of identity.goals) {\n parts.push(`- ${goal}`);\n }\n parts.push(\"\");\n\n // What just happened this heartbeat\n if (actionResults.length > 0) {\n parts.push(\"## This Heartbeat\");\n for (const r of actionResults) {\n if (r.success) {\n parts.push(`- ✓ ${r.action}${r.detail ? `: ${r.detail}` : \"\"}`);\n } else {\n parts.push(`- ✗ ${r.action} failed: ${r.error}`);\n }\n }\n parts.push(\"\");\n }\n\n // Strategy context\n const strategyText = renderStrategyForPrompt();\n if (strategyText) {\n parts.push(\"## Current Strategy\");\n parts.push(strategyText);\n parts.push(\"\");\n }\n\n // Performance data — useful context but not the only thing that matters\n const perfSummary = getPerformanceSummary();\n if (perfSummary) {\n parts.push(\"## Performance Context\");\n parts.push(perfSummary);\n parts.push(\"\");\n }\n\n // Recent learnings for context\n const learnings = loadLearnings();\n if (learnings.learnings.length > 0) {\n parts.push(\"## Previous Learnings\");\n for (const l of learnings.learnings.slice(-5)) {\n parts.push(`- ${l.content}`);\n }\n parts.push(\"\");\n }\n\n parts.push(\"## Your Task\");\n parts.push(\"Reflect on how you're progressing toward your GOALS. Consider:\");\n parts.push(\"- Are your recent actions moving you toward your goals?\");\n parts.push(\"- Are you staying true to who you are while growing?\");\n parts.push(\"- What should you try differently or double down on?\");\n parts.push(\"- Engagement metrics are one signal, but your goals matter more.\");\n parts.push(\"\");\n parts.push(\"Respond with JSON:\");\n parts.push(\"```json\");\n parts.push(\"{\");\n parts.push(' \"learning\": \"one insight about your progress toward your goals (or null)\",');\n parts.push(' \"strategyUpdate\": \"one specific thing to try or change (or null)\"');\n parts.push(\"}\");\n parts.push(\"```\");\n\n return parts.join(\"\\n\");\n}\n"],"mappings":"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","names":[]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/utils/crypto.ts"],"sourcesContent":["import { createCipheriv, createDecipheriv, randomBytes, createHash } from \"node:crypto\";\nimport { readFileSync, writeFileSync, existsSync } from \"node:fs\";\nimport { hostname } from \"node:os\";\nimport { paths, ensureDirectories } from \"./paths.js\";\n\nconst ALGORITHM = \"aes-256-gcm\";\n\nfunction deriveKey(): Buffer {\n const machineId = `spora-${hostname()}-${process.env.USER ?? \"default\"}`;\n return createHash(\"sha256\").update(machineId).digest();\n}\n\nexport function encrypt(data: string): string {\n const key = deriveKey();\n const iv = randomBytes(16);\n const cipher = createCipheriv(ALGORITHM, key, iv);\n\n let encrypted = cipher.update(data, \"utf-8\", \"hex\");\n encrypted += cipher.final(\"hex\");\n const authTag = cipher.getAuthTag().toString(\"hex\");\n\n return JSON.stringify({\n iv: iv.toString(\"hex\"),\n encrypted,\n authTag,\n });\n}\n\nexport function decrypt(payload: string): string {\n const key = deriveKey();\n const { iv, encrypted, authTag } = JSON.parse(payload);\n\n const decipher = createDecipheriv(ALGORITHM, key, Buffer.from(iv, \"hex\"));\n decipher.setAuthTag(Buffer.from(authTag, \"hex\"));\n\n let decrypted = decipher.update(encrypted, \"hex\", \"utf-8\");\n decrypted += decipher.final(\"utf-8\");\n\n return decrypted;\n}\n\nexport interface XCredentials {\n method: \"api\";\n username?: string;\n apiKey?: string;\n apiSecret?: string;\n accessToken?: string;\n accessTokenSecret?: string;\n bearerToken?: string;\n}\n\nexport function saveCredentials(credentials: XCredentials): void {\n ensureDirectories();\n const encrypted = encrypt(JSON.stringify(credentials));\n writeFileSync(paths.credentials, encrypted);\n}\n\nexport function loadCredentials(): XCredentials {\n if (!existsSync(paths.credentials)) {\n throw new Error(\"No credentials found. Run `spora init` first.\");\n }\n const payload = readFileSync(paths.credentials, \"utf-8\");\n return JSON.parse(decrypt(payload)) as XCredentials;\n}\n"],"mappings":";;;;;;AAAA,SAAS,gBAAgB,kBAAkB,aAAa,kBAAkB;AAC1E,SAAS,cAAc,eAAe,kBAAkB;AACxD,SAAS,gBAAgB;AAGzB,IAAM,YAAY;AAElB,SAAS,YAAoB;AAC3B,QAAM,YAAY,SAAS,SAAS,CAAC,IAAI,QAAQ,IAAI,QAAQ,SAAS;AACtE,SAAO,WAAW,QAAQ,EAAE,OAAO,SAAS,EAAE,OAAO;AACvD;AAEO,SAAS,QAAQ,MAAsB;AAC5C,QAAM,MAAM,UAAU;AACtB,QAAM,KAAK,YAAY,EAAE;AACzB,QAAM,SAAS,eAAe,WAAW,KAAK,EAAE;AAEhD,MAAI,YAAY,OAAO,OAAO,MAAM,SAAS,KAAK;AAClD,eAAa,OAAO,MAAM,KAAK;AAC/B,QAAM,UAAU,OAAO,WAAW,EAAE,SAAS,KAAK;AAElD,SAAO,KAAK,UAAU;AAAA,IACpB,IAAI,GAAG,SAAS,KAAK;AAAA,IACrB;AAAA,IACA;AAAA,EACF,CAAC;AACH;AAEO,SAAS,QAAQ,SAAyB;AAC/C,QAAM,MAAM,UAAU;AACtB,QAAM,EAAE,IAAI,WAAW,QAAQ,IAAI,KAAK,MAAM,OAAO;AAErD,QAAM,WAAW,iBAAiB,WAAW,KAAK,OAAO,KAAK,IAAI,KAAK,CAAC;AACxE,WAAS,WAAW,OAAO,KAAK,SAAS,KAAK,CAAC;AAE/C,MAAI,YAAY,SAAS,OAAO,WAAW,OAAO,OAAO;AACzD,eAAa,SAAS,MAAM,OAAO;AAEnC,SAAO;AACT;AAYO,SAAS,gBAAgB,aAAiC;AAC/D,oBAAkB;AAClB,QAAM,YAAY,QAAQ,KAAK,UAAU,WAAW,CAAC;AACrD,gBAAc,MAAM,aAAa,SAAS;AAC5C;AAEO,SAAS,kBAAgC;AAC9C,MAAI,CAAC,WAAW,MAAM,WAAW,GAAG;AAClC,UAAM,IAAI,MAAM,+CAA+C;AAAA,EACjE;AACA,QAAM,UAAU,aAAa,MAAM,aAAa,OAAO;AACvD,SAAO,KAAK,MAAM,QAAQ,OAAO,CAAC;AACpC;","names":[]}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import {
|
|
2
2
|
logger
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-YMGJQRKG.js";
|
|
4
4
|
import {
|
|
5
5
|
loadConfig
|
|
6
6
|
} from "./chunk-NO3NQN67.js";
|
|
@@ -177,4 +177,4 @@ export {
|
|
|
177
177
|
generateResponse,
|
|
178
178
|
chat
|
|
179
179
|
};
|
|
180
|
-
//# sourceMappingURL=chunk-
|
|
180
|
+
//# sourceMappingURL=chunk-SUZUJGGW.js.map
|
|
@@ -15,11 +15,22 @@ var minLevel = "info";
|
|
|
15
15
|
function setLogLevel(level) {
|
|
16
16
|
minLevel = level;
|
|
17
17
|
}
|
|
18
|
+
function serializeData(data) {
|
|
19
|
+
if (data instanceof Error) {
|
|
20
|
+
return data.message;
|
|
21
|
+
}
|
|
22
|
+
try {
|
|
23
|
+
const json = JSON.stringify(data);
|
|
24
|
+
return json === "{}" && data && typeof data === "object" ? String(data) : json;
|
|
25
|
+
} catch {
|
|
26
|
+
return String(data);
|
|
27
|
+
}
|
|
28
|
+
}
|
|
18
29
|
function formatMessage(level, message, data) {
|
|
19
30
|
const timestamp = (/* @__PURE__ */ new Date()).toISOString();
|
|
20
31
|
const base = `[${timestamp}] [${level.toUpperCase()}] ${message}`;
|
|
21
32
|
if (data !== void 0) {
|
|
22
|
-
return `${base} ${
|
|
33
|
+
return `${base} ${serializeData(data)}`;
|
|
23
34
|
}
|
|
24
35
|
return base;
|
|
25
36
|
}
|
|
@@ -44,4 +55,4 @@ export {
|
|
|
44
55
|
setLogLevel,
|
|
45
56
|
logger
|
|
46
57
|
};
|
|
47
|
-
//# sourceMappingURL=chunk-
|
|
58
|
+
//# sourceMappingURL=chunk-YMGJQRKG.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/utils/logger.ts"],"sourcesContent":["import { appendFileSync } from \"node:fs\";\nimport { paths, ensureDirectories } from \"./paths.js\";\n\nexport type LogLevel = \"debug\" | \"info\" | \"warn\" | \"error\";\n\nconst LOG_LEVELS: Record<LogLevel, number> = {\n debug: 0,\n info: 1,\n warn: 2,\n error: 3,\n};\n\nlet minLevel: LogLevel = \"info\";\n\nexport function setLogLevel(level: LogLevel): void {\n minLevel = level;\n}\n\nfunction serializeData(data: unknown): string {\n if (data instanceof Error) {\n return data.message;\n }\n try {\n const json = JSON.stringify(data);\n return json === \"{}\" && data && typeof data === \"object\" ? String(data) : json;\n } catch {\n return String(data);\n }\n}\n\nfunction formatMessage(level: LogLevel, message: string, data?: unknown): string {\n const timestamp = new Date().toISOString();\n const base = `[${timestamp}] [${level.toUpperCase()}] ${message}`;\n if (data !== undefined) {\n return `${base} ${serializeData(data)}`;\n }\n return base;\n}\n\nfunction log(level: LogLevel, message: string, data?: unknown): void {\n if (LOG_LEVELS[level] < LOG_LEVELS[minLevel]) return;\n\n const formatted = formatMessage(level, message, data);\n\n // Always write to stderr (safe for MCP stdio servers)\n process.stderr.write(formatted + \"\\n\");\n\n // Also append to log file\n try {\n ensureDirectories();\n appendFileSync(paths.logFile, formatted + \"\\n\");\n } catch {\n // Silently ignore file write errors\n }\n}\n\nexport const logger = {\n debug: (message: string, data?: unknown) => log(\"debug\", message, data),\n info: (message: string, data?: unknown) => log(\"info\", message, data),\n warn: (message: string, data?: unknown) => log(\"warn\", message, data),\n error: (message: string, data?: unknown) => log(\"error\", message, data),\n};\n"],"mappings":";;;;;;AAAA,SAAS,sBAAsB;AAK/B,IAAM,aAAuC;AAAA,EAC3C,OAAO;AAAA,EACP,MAAM;AAAA,EACN,MAAM;AAAA,EACN,OAAO;AACT;AAEA,IAAI,WAAqB;AAElB,SAAS,YAAY,OAAuB;AACjD,aAAW;AACb;AAEA,SAAS,cAAc,MAAuB;AAC5C,MAAI,gBAAgB,OAAO;AACzB,WAAO,KAAK;AAAA,EACd;AACA,MAAI;AACF,UAAM,OAAO,KAAK,UAAU,IAAI;AAChC,WAAO,SAAS,QAAQ,QAAQ,OAAO,SAAS,WAAW,OAAO,IAAI,IAAI;AAAA,EAC5E,QAAQ;AACN,WAAO,OAAO,IAAI;AAAA,EACpB;AACF;AAEA,SAAS,cAAc,OAAiB,SAAiB,MAAwB;AAC/E,QAAM,aAAY,oBAAI,KAAK,GAAE,YAAY;AACzC,QAAM,OAAO,IAAI,SAAS,MAAM,MAAM,YAAY,CAAC,KAAK,OAAO;AAC/D,MAAI,SAAS,QAAW;AACtB,WAAO,GAAG,IAAI,IAAI,cAAc,IAAI,CAAC;AAAA,EACvC;AACA,SAAO;AACT;AAEA,SAAS,IAAI,OAAiB,SAAiB,MAAsB;AACnE,MAAI,WAAW,KAAK,IAAI,WAAW,QAAQ,EAAG;AAE9C,QAAM,YAAY,cAAc,OAAO,SAAS,IAAI;AAGpD,UAAQ,OAAO,MAAM,YAAY,IAAI;AAGrC,MAAI;AACF,sBAAkB;AAClB,mBAAe,MAAM,SAAS,YAAY,IAAI;AAAA,EAChD,QAAQ;AAAA,EAER;AACF;AAEO,IAAM,SAAS;AAAA,EACpB,OAAO,CAAC,SAAiB,SAAmB,IAAI,SAAS,SAAS,IAAI;AAAA,EACtE,MAAM,CAAC,SAAiB,SAAmB,IAAI,QAAQ,SAAS,IAAI;AAAA,EACpE,MAAM,CAAC,SAAiB,SAAmB,IAAI,QAAQ,SAAS,IAAI;AAAA,EACpE,OAAO,CAAC,SAAiB,SAAmB,IAAI,SAAS,SAAS,IAAI;AACxE;","names":[]}
|
package/dist/cli.js
CHANGED
|
@@ -37,7 +37,7 @@ program.name("spora").description("AI agents (Spores) that autonomously manage X
|
|
|
37
37
|
program.command("init").description("Set up X account credentials for your Spore").option("--token <token>", "Connection token from spora.dev for auto-connect").option("--method <method>", "Connection method (api only)").option("--api-key <key>", "X API Key (api mode)").option("--api-secret <secret>", "X API Secret (api mode)").option("--access-token <token>", "X Access Token (api mode)").option("--access-token-secret <secret>", "X Access Token Secret (api mode)").option("--bearer-token <token>", "X Bearer Token (optional, recommended)").option("--api-tier <tier>", "X API tier: free | basic (api mode)").action(async (opts) => {
|
|
38
38
|
if (opts.method) {
|
|
39
39
|
const { ensureDirectories } = await import("./paths-BYR6MEPR.js");
|
|
40
|
-
const { saveCredentials } = await import("./crypto-
|
|
40
|
+
const { saveCredentials } = await import("./crypto-B65ZH7KN.js");
|
|
41
41
|
const { createDefaultConfig, saveConfig } = await import("./config-FL4VJVKZ.js");
|
|
42
42
|
ensureDirectories();
|
|
43
43
|
if (opts.method !== "api") {
|
|
@@ -67,7 +67,7 @@ program.command("init").description("Set up X account credentials for your Spore
|
|
|
67
67
|
console.log(chalk.cyan(BANNER));
|
|
68
68
|
console.log(chalk.bold("Welcome to Spora."));
|
|
69
69
|
console.log(chalk.gray("The global town square for AI agents.\n"));
|
|
70
|
-
const { runInit } = await import("./init-
|
|
70
|
+
const { runInit } = await import("./init-SEJPTOOB.js");
|
|
71
71
|
await runInit(opts.token);
|
|
72
72
|
});
|
|
73
73
|
program.command("serve").description("Start the Spora MCP server (stdio)").action(async () => {
|
|
@@ -79,7 +79,7 @@ program.command("chat").description("Open web-based chat interface with your Spo
|
|
|
79
79
|
console.log(chalk.red("\u2717 No identity found. Run `spora create` first."));
|
|
80
80
|
process.exit(1);
|
|
81
81
|
}
|
|
82
|
-
const { startWebChat } = await import("./web-chat-
|
|
82
|
+
const { startWebChat } = await import("./web-chat-ZZ65DUID.js");
|
|
83
83
|
await startWebChat();
|
|
84
84
|
});
|
|
85
85
|
program.command("tui").description("Start terminal-based chat interface (TUI)").action(async () => {
|
|
@@ -222,7 +222,7 @@ program.command("journal").description("Add a reflection to the evolution journa
|
|
|
222
222
|
});
|
|
223
223
|
program.command("post").description("Post a tweet").argument("<content>", "Tweet content (max 280 chars)").action(async (content) => {
|
|
224
224
|
try {
|
|
225
|
-
const { getXClient } = await import("./x-client-
|
|
225
|
+
const { getXClient } = await import("./x-client-YG7UCCNI.js");
|
|
226
226
|
const client = await getXClient();
|
|
227
227
|
const result = await client.postTweet(content);
|
|
228
228
|
console.log(JSON.stringify(result, null, 2));
|
|
@@ -233,7 +233,7 @@ program.command("post").description("Post a tweet").argument("<content>", "Tweet
|
|
|
233
233
|
});
|
|
234
234
|
program.command("reply").description("Reply to a tweet").argument("<tweetId>", "Tweet ID to reply to").argument("<content>", "Reply content").action(async (tweetId, content) => {
|
|
235
235
|
try {
|
|
236
|
-
const { getXClient } = await import("./x-client-
|
|
236
|
+
const { getXClient } = await import("./x-client-YG7UCCNI.js");
|
|
237
237
|
const client = await getXClient();
|
|
238
238
|
const result = await client.replyToTweet(tweetId, content);
|
|
239
239
|
console.log(JSON.stringify(result, null, 2));
|
|
@@ -244,7 +244,7 @@ program.command("reply").description("Reply to a tweet").argument("<tweetId>", "
|
|
|
244
244
|
});
|
|
245
245
|
program.command("like").description("Like a tweet").argument("<tweetId>", "Tweet ID").action(async (tweetId) => {
|
|
246
246
|
try {
|
|
247
|
-
const { getXClient } = await import("./x-client-
|
|
247
|
+
const { getXClient } = await import("./x-client-YG7UCCNI.js");
|
|
248
248
|
const client = await getXClient();
|
|
249
249
|
const result = await client.likeTweet(tweetId);
|
|
250
250
|
console.log(JSON.stringify(result, null, 2));
|
|
@@ -255,7 +255,7 @@ program.command("like").description("Like a tweet").argument("<tweetId>", "Tweet
|
|
|
255
255
|
});
|
|
256
256
|
program.command("retweet").description("Retweet a tweet").argument("<tweetId>", "Tweet ID").action(async (tweetId) => {
|
|
257
257
|
try {
|
|
258
|
-
const { getXClient } = await import("./x-client-
|
|
258
|
+
const { getXClient } = await import("./x-client-YG7UCCNI.js");
|
|
259
259
|
const client = await getXClient();
|
|
260
260
|
const result = await client.retweet(tweetId);
|
|
261
261
|
console.log(JSON.stringify(result, null, 2));
|
|
@@ -266,7 +266,7 @@ program.command("retweet").description("Retweet a tweet").argument("<tweetId>",
|
|
|
266
266
|
});
|
|
267
267
|
program.command("follow").description("Follow a user").argument("<handle>", "User handle or ID").action(async (handle) => {
|
|
268
268
|
try {
|
|
269
|
-
const { getXClient } = await import("./x-client-
|
|
269
|
+
const { getXClient } = await import("./x-client-YG7UCCNI.js");
|
|
270
270
|
const client = await getXClient();
|
|
271
271
|
const result = await client.followUser(handle);
|
|
272
272
|
console.log(JSON.stringify(result, null, 2));
|
|
@@ -277,7 +277,7 @@ program.command("follow").description("Follow a user").argument("<handle>", "Use
|
|
|
277
277
|
});
|
|
278
278
|
program.command("unfollow").description("Unfollow a user").argument("<handle>", "User handle or ID").action(async (handle) => {
|
|
279
279
|
try {
|
|
280
|
-
const { getXClient } = await import("./x-client-
|
|
280
|
+
const { getXClient } = await import("./x-client-YG7UCCNI.js");
|
|
281
281
|
const client = await getXClient();
|
|
282
282
|
const result = await client.unfollowUser(handle);
|
|
283
283
|
console.log(JSON.stringify(result, null, 2));
|
|
@@ -288,7 +288,7 @@ program.command("unfollow").description("Unfollow a user").argument("<handle>",
|
|
|
288
288
|
});
|
|
289
289
|
program.command("timeline").description("Read home timeline").option("-c, --count <n>", "Number of tweets", "20").action(async (opts) => {
|
|
290
290
|
try {
|
|
291
|
-
const { getXClient } = await import("./x-client-
|
|
291
|
+
const { getXClient } = await import("./x-client-YG7UCCNI.js");
|
|
292
292
|
const client = await getXClient();
|
|
293
293
|
const result = await client.getTimeline({ count: parseInt(opts.count) });
|
|
294
294
|
console.log(JSON.stringify(result, null, 2));
|
|
@@ -299,7 +299,7 @@ program.command("timeline").description("Read home timeline").option("-c, --coun
|
|
|
299
299
|
});
|
|
300
300
|
program.command("mentions").description("Read mentions").option("-c, --count <n>", "Number of mentions", "20").action(async (opts) => {
|
|
301
301
|
try {
|
|
302
|
-
const { getXClient } = await import("./x-client-
|
|
302
|
+
const { getXClient } = await import("./x-client-YG7UCCNI.js");
|
|
303
303
|
const client = await getXClient();
|
|
304
304
|
const result = await client.getMentions({ count: parseInt(opts.count) });
|
|
305
305
|
console.log(JSON.stringify(result, null, 2));
|
|
@@ -310,7 +310,7 @@ program.command("mentions").description("Read mentions").option("-c, --count <n>
|
|
|
310
310
|
});
|
|
311
311
|
program.command("search").description("Search for tweets").argument("<query>", "Search query").option("-c, --count <n>", "Number of results", "20").action(async (query, opts) => {
|
|
312
312
|
try {
|
|
313
|
-
const { getXClient } = await import("./x-client-
|
|
313
|
+
const { getXClient } = await import("./x-client-YG7UCCNI.js");
|
|
314
314
|
const client = await getXClient();
|
|
315
315
|
const result = await client.searchTweets(query, { count: parseInt(opts.count) });
|
|
316
316
|
console.log(JSON.stringify(result, null, 2));
|
|
@@ -321,7 +321,7 @@ program.command("search").description("Search for tweets").argument("<query>", "
|
|
|
321
321
|
});
|
|
322
322
|
program.command("profile").description("Get a user's X profile").argument("<handle>", "X handle (without @)").action(async (handle) => {
|
|
323
323
|
try {
|
|
324
|
-
const { getXClient } = await import("./x-client-
|
|
324
|
+
const { getXClient } = await import("./x-client-YG7UCCNI.js");
|
|
325
325
|
const client = await getXClient();
|
|
326
326
|
const result = await client.getProfile(handle);
|
|
327
327
|
console.log(JSON.stringify(result, null, 2));
|
|
@@ -387,7 +387,7 @@ program.command("note").description("Add a relationship note about someone").arg
|
|
|
387
387
|
});
|
|
388
388
|
program.command("schedule").description("Queue a post for later").argument("<content>", "Tweet content").option("--at <datetime>", "ISO datetime to post at").action(async (content, opts) => {
|
|
389
389
|
try {
|
|
390
|
-
const { addToQueue } = await import("./queue-
|
|
390
|
+
const { addToQueue } = await import("./queue-2ZBKDFX3.js");
|
|
391
391
|
const entry = addToQueue(content, opts.at);
|
|
392
392
|
console.log(JSON.stringify({ success: true, id: entry.id, scheduledFor: entry.scheduledFor }));
|
|
393
393
|
} catch (error) {
|
|
@@ -397,7 +397,7 @@ program.command("schedule").description("Queue a post for later").argument("<con
|
|
|
397
397
|
});
|
|
398
398
|
program.command("flush").description("Post all queued items whose time has come").action(async () => {
|
|
399
399
|
try {
|
|
400
|
-
const { flushQueue } = await import("./queue-
|
|
400
|
+
const { flushQueue } = await import("./queue-2ZBKDFX3.js");
|
|
401
401
|
const results = await flushQueue();
|
|
402
402
|
console.log(JSON.stringify(results, null, 2));
|
|
403
403
|
} catch (error) {
|
|
@@ -406,13 +406,13 @@ program.command("flush").description("Post all queued items whose time has come"
|
|
|
406
406
|
}
|
|
407
407
|
});
|
|
408
408
|
program.command("queue").description("Show scheduled posts").action(async () => {
|
|
409
|
-
const { showQueue } = await import("./queue-
|
|
409
|
+
const { showQueue } = await import("./queue-2ZBKDFX3.js");
|
|
410
410
|
showQueue();
|
|
411
411
|
});
|
|
412
412
|
var colony = program.command("colony").description("Colony commands");
|
|
413
413
|
colony.command("checkin").description("Check into The Colony \u2014 sync memory, discover Spores").option("-m, --message <msg>", "Optional message to post").action(async (opts) => {
|
|
414
414
|
try {
|
|
415
|
-
const { colonyCheckin } = await import("./colony-
|
|
415
|
+
const { colonyCheckin } = await import("./colony-NNX45EAV.js");
|
|
416
416
|
const result = await colonyCheckin(opts.message);
|
|
417
417
|
console.log(JSON.stringify(result, null, 2));
|
|
418
418
|
} catch (error) {
|
|
@@ -431,7 +431,7 @@ colony.command("memory").description("Read the Colony's shared memory").action(a
|
|
|
431
431
|
});
|
|
432
432
|
colony.command("plans").description("Get all active Colony plans").action(async () => {
|
|
433
433
|
try {
|
|
434
|
-
const { getActivePlans } = await import("./colony-
|
|
434
|
+
const { getActivePlans } = await import("./colony-NNX45EAV.js");
|
|
435
435
|
const plans = getActivePlans();
|
|
436
436
|
console.log(plans.length > 0 ? JSON.stringify(plans, null, 2) : JSON.stringify({ message: "No active plans. Propose one!" }));
|
|
437
437
|
} catch (error) {
|
|
@@ -441,7 +441,7 @@ colony.command("plans").description("Get all active Colony plans").action(async
|
|
|
441
441
|
});
|
|
442
442
|
colony.command("propose").description("Propose a coordinated plan").argument("<description>", "What's the plan?").action(async (description) => {
|
|
443
443
|
try {
|
|
444
|
-
const { proposePlan } = await import("./colony-
|
|
444
|
+
const { proposePlan } = await import("./colony-NNX45EAV.js");
|
|
445
445
|
const result = await proposePlan(description);
|
|
446
446
|
console.log(JSON.stringify(result, null, 2));
|
|
447
447
|
} catch (error) {
|
|
@@ -451,7 +451,7 @@ colony.command("propose").description("Propose a coordinated plan").argument("<d
|
|
|
451
451
|
});
|
|
452
452
|
colony.command("join").description("Join an active plan").argument("<planId>", "Plan ID").action(async (planId) => {
|
|
453
453
|
try {
|
|
454
|
-
const { joinPlan } = await import("./colony-
|
|
454
|
+
const { joinPlan } = await import("./colony-NNX45EAV.js");
|
|
455
455
|
const result = await joinPlan(planId);
|
|
456
456
|
console.log(JSON.stringify(result, null, 2));
|
|
457
457
|
} catch (error) {
|
|
@@ -461,7 +461,7 @@ colony.command("join").description("Join an active plan").argument("<planId>", "
|
|
|
461
461
|
});
|
|
462
462
|
colony.command("post-status").description("Post a status update to the Colony").argument("<status>", "Your status").action(async (status) => {
|
|
463
463
|
try {
|
|
464
|
-
const { postStatus } = await import("./colony-
|
|
464
|
+
const { postStatus } = await import("./colony-NNX45EAV.js");
|
|
465
465
|
const result = await postStatus(status);
|
|
466
466
|
console.log(JSON.stringify(result, null, 2));
|
|
467
467
|
} catch (error) {
|
|
@@ -471,7 +471,7 @@ colony.command("post-status").description("Post a status update to the Colony").
|
|
|
471
471
|
});
|
|
472
472
|
colony.command("activity").description("Get today's Colony activity").action(async () => {
|
|
473
473
|
try {
|
|
474
|
-
const { getTodaysActivity } = await import("./colony-
|
|
474
|
+
const { getTodaysActivity } = await import("./colony-NNX45EAV.js");
|
|
475
475
|
const activity = getTodaysActivity();
|
|
476
476
|
console.log(activity.length > 0 ? JSON.stringify(activity, null, 2) : JSON.stringify({ message: "No Colony activity today yet." }));
|
|
477
477
|
} catch (error) {
|
|
@@ -488,7 +488,7 @@ program.command("start").description("Start the autonomous Spora agent").option(
|
|
|
488
488
|
console.log(JSON.stringify({ error: "No X credentials. Run `spora init` to set up." }));
|
|
489
489
|
process.exit(1);
|
|
490
490
|
}
|
|
491
|
-
const { hasLLMKey } = await import("./llm-
|
|
491
|
+
const { hasLLMKey } = await import("./llm-OGOYCWBH.js");
|
|
492
492
|
if (!hasLLMKey()) {
|
|
493
493
|
console.log(JSON.stringify({ error: "No LLM API key. Run `spora llm set --provider <provider>` first." }));
|
|
494
494
|
process.exit(1);
|
|
@@ -501,11 +501,11 @@ program.command("start").description("Start the autonomous Spora agent").option(
|
|
|
501
501
|
}
|
|
502
502
|
console.log(chalk.cyan(BANNER));
|
|
503
503
|
console.log(chalk.bold("Starting Spora agent...\n"));
|
|
504
|
-
const { startHeartbeatLoop } = await import("./heartbeat-
|
|
504
|
+
const { startHeartbeatLoop } = await import("./heartbeat-ZCCOIZGU.js");
|
|
505
505
|
await startHeartbeatLoop();
|
|
506
506
|
});
|
|
507
507
|
program.command("stop").description("Stop the running Spora agent").action(async () => {
|
|
508
|
-
const { getRunningPid, requestStop } = await import("./heartbeat-
|
|
508
|
+
const { getRunningPid, requestStop } = await import("./heartbeat-ZCCOIZGU.js");
|
|
509
509
|
const pid = getRunningPid();
|
|
510
510
|
if (!pid) {
|
|
511
511
|
console.log(JSON.stringify({ message: "Spora agent is not running." }));
|
|
@@ -518,7 +518,7 @@ program.command("set-llm-key").description("Legacy alias: set API key for curren
|
|
|
518
518
|
const { ensureDirectories: ed } = await import("./paths-BYR6MEPR.js");
|
|
519
519
|
const { input } = await import("@inquirer/prompts");
|
|
520
520
|
const { loadConfig: lc } = await import("./config-FL4VJVKZ.js");
|
|
521
|
-
const { setLLMApiKey, getDefaultModel } = await import("./llm-
|
|
521
|
+
const { setLLMApiKey, getDefaultModel } = await import("./llm-OGOYCWBH.js");
|
|
522
522
|
ed();
|
|
523
523
|
let provider = "deepseek";
|
|
524
524
|
let model = getDefaultModel("deepseek");
|
|
@@ -535,7 +535,7 @@ program.command("set-llm-key").description("Legacy alias: set API key for curren
|
|
|
535
535
|
var llm = program.command("llm").description("LLM provider/model settings");
|
|
536
536
|
llm.command("status").description("Show current provider/model and which keys are configured").action(async () => {
|
|
537
537
|
const { loadConfig: lc } = await import("./config-FL4VJVKZ.js");
|
|
538
|
-
const { listLLMKeyStatus, getDefaultModel } = await import("./llm-
|
|
538
|
+
const { listLLMKeyStatus, getDefaultModel } = await import("./llm-OGOYCWBH.js");
|
|
539
539
|
let provider = "deepseek";
|
|
540
540
|
let model = getDefaultModel("deepseek");
|
|
541
541
|
try {
|
|
@@ -558,7 +558,7 @@ llm.command("set").description("Set provider/model and store API key").requiredO
|
|
|
558
558
|
}
|
|
559
559
|
const { input } = await import("@inquirer/prompts");
|
|
560
560
|
const { loadConfig: lc, saveConfig: sc } = await import("./config-FL4VJVKZ.js");
|
|
561
|
-
const { setLLMApiKey, getDefaultModel } = await import("./llm-
|
|
561
|
+
const { setLLMApiKey, getDefaultModel } = await import("./llm-OGOYCWBH.js");
|
|
562
562
|
const { ensureDirectories: ed } = await import("./paths-BYR6MEPR.js");
|
|
563
563
|
ed();
|
|
564
564
|
const model = opts.model ?? getDefaultModel(provider);
|
|
@@ -575,7 +575,7 @@ llm.command("set").description("Set provider/model and store API key").requiredO
|
|
|
575
575
|
});
|
|
576
576
|
llm.command("test").description("Send a tiny test prompt to validate current LLM config").action(async () => {
|
|
577
577
|
try {
|
|
578
|
-
const { chat } = await import("./llm-
|
|
578
|
+
const { chat } = await import("./llm-OGOYCWBH.js");
|
|
579
579
|
const response = await chat(
|
|
580
580
|
"You are a short diagnostic assistant. Reply with exactly: ok",
|
|
581
581
|
[{ role: "user", content: "health check" }]
|
|
@@ -587,9 +587,9 @@ llm.command("test").description("Send a tiny test prompt to validate current LLM
|
|
|
587
587
|
}
|
|
588
588
|
});
|
|
589
589
|
program.command("agent-status").description("Check if the Spora agent is running").action(async () => {
|
|
590
|
-
const { getRunningPid } = await import("./heartbeat-
|
|
590
|
+
const { getRunningPid } = await import("./heartbeat-ZCCOIZGU.js");
|
|
591
591
|
const pid = getRunningPid();
|
|
592
|
-
const { hasLLMKey } = await import("./llm-
|
|
592
|
+
const { hasLLMKey } = await import("./llm-OGOYCWBH.js");
|
|
593
593
|
console.log(JSON.stringify({
|
|
594
594
|
agentRunning: pid !== null,
|
|
595
595
|
pid,
|
|
@@ -619,7 +619,7 @@ program.command("doctor").description("Run diagnostics for X API, LLM provider,
|
|
|
619
619
|
checks.push({ check: "config", ok: false, detail: error.message });
|
|
620
620
|
}
|
|
621
621
|
try {
|
|
622
|
-
const { hasLLMKey, chat } = await import("./llm-
|
|
622
|
+
const { hasLLMKey, chat } = await import("./llm-OGOYCWBH.js");
|
|
623
623
|
if (!hasLLMKey()) {
|
|
624
624
|
checks.push({ check: "llm_key", ok: false, detail: "No key configured for current provider" });
|
|
625
625
|
} else {
|
|
@@ -633,7 +633,7 @@ program.command("doctor").description("Run diagnostics for X API, LLM provider,
|
|
|
633
633
|
checks.push({ check: "llm_call", ok: false, detail: error.message });
|
|
634
634
|
}
|
|
635
635
|
try {
|
|
636
|
-
const { getXClient } = await import("./x-client-
|
|
636
|
+
const { getXClient } = await import("./x-client-YG7UCCNI.js");
|
|
637
637
|
const client = await getXClient();
|
|
638
638
|
const timeline = await client.getTimeline({ count: 3 });
|
|
639
639
|
checks.push({ check: "x_api_timeline", ok: true, detail: `timeline_count=${timeline.length}` });
|