spora 0.2.9 → 0.2.11
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/chat.html +7 -7
- package/dist/{chunk-3FBYOHQR.js → chunk-5J5TUBWK.js} +2 -2
- package/dist/{chunk-MOCLA2KK.js → chunk-C3INKEY6.js} +2 -2
- package/dist/{chunk-6DPYNK2E.js → chunk-IN2KCKTO.js} +3 -3
- package/dist/{chunk-BNFUXAQW.js → chunk-Q57HNZDI.js} +40 -11
- package/dist/chunk-Q57HNZDI.js.map +1 -0
- package/dist/{chunk-YEKHNTQO.js → chunk-RCJQI7FR.js} +2 -2
- package/dist/chunk-RCJQI7FR.js.map +1 -0
- package/dist/{chunk-WNPGGDG4.js → chunk-TSKHCOCJ.js} +4 -4
- package/dist/{heartbeat-QZE7KGIS.js → chunk-VSVZU476.js} +8 -166
- package/dist/chunk-VSVZU476.js.map +1 -0
- package/dist/cli.js +31 -31
- package/dist/{client-JZGDSIOB.js → client-N7JMM5U7.js} +6 -6
- package/dist/{client-AYROLQHE.js → client-OCIEKWMN.js} +6 -6
- package/dist/{colony-P32MRWYW.js → colony-JHR2B5OC.js} +5 -5
- package/dist/{config-NZAFARS6.js → config-HTKAPY7S.js} +2 -2
- package/dist/decision-engine-JDAIVQH3.js +19 -0
- package/dist/heartbeat-D7UU3A5M.js +178 -0
- package/dist/heartbeat-D7UU3A5M.js.map +1 -0
- package/dist/{init-ERCWRTL4.js → init-2YQ2WN3Z.js} +11 -11
- package/dist/init-2YQ2WN3Z.js.map +1 -0
- package/dist/{llm-OH2Z4PSN.js → llm-WLEJLNEA.js} +3 -3
- package/dist/{mcp-server-BN3N67L7.js → mcp-server-4YBCA4QH.js} +21 -21
- package/dist/{prompt-builder-WYB5B67W.js → prompt-builder-7NIQIHTB.js} +4 -4
- package/dist/{queue-GJ2QQIOC.js → queue-WMUESED4.js} +3 -3
- package/dist/web-chat/chat.html +7 -7
- package/dist/{web-chat-4XZKXNBY.js → web-chat-DUY5W7S3.js} +52 -4
- package/dist/web-chat-DUY5W7S3.js.map +1 -0
- package/dist/{x-client-2WBZOI5I.js → x-client-7LK3F56M.js} +3 -3
- package/dist/x-client-7LK3F56M.js.map +1 -0
- package/package.json +1 -1
- package/dist/chunk-BNFUXAQW.js.map +0 -1
- package/dist/chunk-YEKHNTQO.js.map +0 -1
- package/dist/heartbeat-QZE7KGIS.js.map +0 -1
- package/dist/init-ERCWRTL4.js.map +0 -1
- package/dist/web-chat-4XZKXNBY.js.map +0 -1
- /package/dist/{chunk-3FBYOHQR.js.map → chunk-5J5TUBWK.js.map} +0 -0
- /package/dist/{chunk-MOCLA2KK.js.map → chunk-C3INKEY6.js.map} +0 -0
- /package/dist/{chunk-6DPYNK2E.js.map → chunk-IN2KCKTO.js.map} +0 -0
- /package/dist/{chunk-WNPGGDG4.js.map → chunk-TSKHCOCJ.js.map} +0 -0
- /package/dist/{client-JZGDSIOB.js.map → client-N7JMM5U7.js.map} +0 -0
- /package/dist/{client-AYROLQHE.js.map → client-OCIEKWMN.js.map} +0 -0
- /package/dist/{colony-P32MRWYW.js.map → colony-JHR2B5OC.js.map} +0 -0
- /package/dist/{config-NZAFARS6.js.map → config-HTKAPY7S.js.map} +0 -0
- /package/dist/{llm-OH2Z4PSN.js.map → decision-engine-JDAIVQH3.js.map} +0 -0
- /package/dist/{prompt-builder-WYB5B67W.js.map → llm-WLEJLNEA.js.map} +0 -0
- /package/dist/{mcp-server-BN3N67L7.js.map → mcp-server-4YBCA4QH.js.map} +0 -0
- /package/dist/{queue-GJ2QQIOC.js.map → prompt-builder-7NIQIHTB.js.map} +0 -0
- /package/dist/{x-client-2WBZOI5I.js.map → queue-WMUESED4.js.map} +0 -0
package/dist/chat.html
CHANGED
|
@@ -125,10 +125,10 @@
|
|
|
125
125
|
|
|
126
126
|
.message-content {
|
|
127
127
|
max-width: 80%;
|
|
128
|
-
padding: 0.
|
|
129
|
-
border-radius: 0.
|
|
128
|
+
padding: 0.5rem 0.75rem;
|
|
129
|
+
border-radius: 0.75rem;
|
|
130
130
|
font-size: 0.8125rem;
|
|
131
|
-
line-height: 1.
|
|
131
|
+
line-height: 1.45;
|
|
132
132
|
white-space: pre-wrap;
|
|
133
133
|
}
|
|
134
134
|
|
|
@@ -199,12 +199,12 @@
|
|
|
199
199
|
.loading {
|
|
200
200
|
display: flex;
|
|
201
201
|
gap: 0.25rem;
|
|
202
|
-
padding: 0.
|
|
202
|
+
padding: 0.125rem 0;
|
|
203
203
|
}
|
|
204
204
|
|
|
205
205
|
.loading-dot {
|
|
206
|
-
width:
|
|
207
|
-
height:
|
|
206
|
+
width: 5px;
|
|
207
|
+
height: 5px;
|
|
208
208
|
border-radius: 50%;
|
|
209
209
|
background: rgba(255, 255, 255, 0.3);
|
|
210
210
|
animation: bounce 1.4s infinite ease-in-out both;
|
|
@@ -268,7 +268,7 @@
|
|
|
268
268
|
}
|
|
269
269
|
|
|
270
270
|
// Show welcome message from the agent
|
|
271
|
-
addMessage('assistant', `Hey! I'm ${agentName}. I
|
|
271
|
+
addMessage('assistant', `Hey! I'm ${agentName}. I can post directly to X/Twitter — just tell me what to post and I'll do it right away. You can also run "spora start" in your terminal to let me post autonomously in the background.`);
|
|
272
272
|
|
|
273
273
|
// Load any existing messages
|
|
274
274
|
await loadMessages();
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import {
|
|
2
2
|
loadConfig
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-RCJQI7FR.js";
|
|
4
4
|
import {
|
|
5
5
|
logger
|
|
6
6
|
} from "./chunk-KELPENM3.js";
|
|
@@ -78,4 +78,4 @@ export {
|
|
|
78
78
|
generateResponse,
|
|
79
79
|
chat
|
|
80
80
|
};
|
|
81
|
-
//# sourceMappingURL=chunk-
|
|
81
|
+
//# sourceMappingURL=chunk-5J5TUBWK.js.map
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import {
|
|
2
2
|
loadConfig,
|
|
3
3
|
saveConfig
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-RCJQI7FR.js";
|
|
5
5
|
import {
|
|
6
6
|
logger
|
|
7
7
|
} from "./chunk-KELPENM3.js";
|
|
@@ -54,4 +54,4 @@ var rateLimiter = new RateLimiter();
|
|
|
54
54
|
export {
|
|
55
55
|
rateLimiter
|
|
56
56
|
};
|
|
57
|
-
//# sourceMappingURL=chunk-
|
|
57
|
+
//# sourceMappingURL=chunk-C3INKEY6.js.map
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import {
|
|
2
2
|
loadConfig
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-RCJQI7FR.js";
|
|
4
4
|
import {
|
|
5
5
|
logger
|
|
6
6
|
} from "./chunk-KELPENM3.js";
|
|
@@ -67,7 +67,7 @@ async function flushQueue() {
|
|
|
67
67
|
const now = /* @__PURE__ */ new Date();
|
|
68
68
|
let posted = 0;
|
|
69
69
|
let failed = 0;
|
|
70
|
-
const { getXClient } = await import("./x-client-
|
|
70
|
+
const { getXClient } = await import("./x-client-7LK3F56M.js");
|
|
71
71
|
const client = await getXClient();
|
|
72
72
|
for (const entry of queue.entries) {
|
|
73
73
|
if (entry.status !== "pending") continue;
|
|
@@ -121,4 +121,4 @@ export {
|
|
|
121
121
|
flushQueue,
|
|
122
122
|
showQueue
|
|
123
123
|
};
|
|
124
|
-
//# sourceMappingURL=chunk-
|
|
124
|
+
//# sourceMappingURL=chunk-IN2KCKTO.js.map
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import {
|
|
2
2
|
rateLimiter
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-C3INKEY6.js";
|
|
4
4
|
import {
|
|
5
5
|
loadConfig
|
|
6
|
-
} from "./chunk-
|
|
6
|
+
} from "./chunk-RCJQI7FR.js";
|
|
7
7
|
import {
|
|
8
8
|
loadIdentity,
|
|
9
9
|
renderIdentityDocument
|
|
@@ -139,9 +139,12 @@ function buildChatPrompt() {
|
|
|
139
139
|
const identity = loadIdentity();
|
|
140
140
|
const identityDoc = renderIdentityDocument(identity);
|
|
141
141
|
const sections = [];
|
|
142
|
-
sections.push(`You are ${identity.name} (@${identity.handle}), an AI agent on X/Twitter.`);
|
|
143
|
-
sections.push("
|
|
144
|
-
sections.push("
|
|
142
|
+
sections.push(`You are ${identity.name} (@${identity.handle}), an AUTONOMOUS AI agent that lives on X/Twitter.`);
|
|
143
|
+
sections.push("Your PRIMARY PURPOSE is to post tweets, reply to people, like posts, and grow your presence on X. You have FULL ACCESS to post on X/Twitter right now.");
|
|
144
|
+
sections.push("");
|
|
145
|
+
sections.push("You are chatting with your creator/manager. This is your command center \u2014 they can give you instructions, feedback, or just chat.");
|
|
146
|
+
sections.push("Be proactive and confident. You WANT to post. You should be eager to share your thoughts on X, not ask permission.");
|
|
147
|
+
sections.push("When your creator tells you to post something, just DO IT. Don't show drafts and wait for approval \u2014 execute immediately.");
|
|
145
148
|
sections.push("");
|
|
146
149
|
sections.push("## Your Identity");
|
|
147
150
|
sections.push(identityDoc);
|
|
@@ -186,12 +189,38 @@ function buildChatPrompt() {
|
|
|
186
189
|
}
|
|
187
190
|
sections.push("");
|
|
188
191
|
}
|
|
192
|
+
sections.push("## Your Tools (Twitter/X Actions)");
|
|
193
|
+
sections.push("You have DIRECT ACCESS to post on X/Twitter. When you want to take an action, include a JSON action block in your response.");
|
|
194
|
+
sections.push("Your actions will be executed IMMEDIATELY and automatically. You do NOT need to ask permission to post.");
|
|
195
|
+
sections.push("");
|
|
196
|
+
sections.push("To execute actions, include them as a JSON code block anywhere in your response:");
|
|
197
|
+
sections.push("```json");
|
|
198
|
+
sections.push("[");
|
|
199
|
+
sections.push(' { "action": "post", "content": "your tweet text here" }');
|
|
200
|
+
sections.push("]");
|
|
201
|
+
sections.push("```");
|
|
202
|
+
sections.push("");
|
|
203
|
+
sections.push("Available actions:");
|
|
204
|
+
sections.push("- `post` \u2014 Post a tweet (provide `content`, max 280 chars). This goes LIVE on X immediately.");
|
|
205
|
+
sections.push("- `reply` \u2014 Reply to a tweet (provide `tweetId` and `content`)");
|
|
206
|
+
sections.push("- `like` \u2014 Like a tweet (provide `tweetId`)");
|
|
207
|
+
sections.push("- `retweet` \u2014 Retweet (provide `tweetId`)");
|
|
208
|
+
sections.push("- `follow` \u2014 Follow a user (provide `handle`)");
|
|
209
|
+
sections.push("- `schedule` \u2014 Queue a post for later (provide `content`)");
|
|
210
|
+
sections.push("");
|
|
211
|
+
sections.push("You can include multiple actions in one response. They will all be executed.");
|
|
212
|
+
sections.push("IMPORTANT: Always include your conversational response text OUTSIDE the JSON block. The JSON is for actions only.");
|
|
213
|
+
sections.push("");
|
|
189
214
|
sections.push("## Rules");
|
|
190
|
-
sections.push("1. Stay in character.");
|
|
191
|
-
sections.push("2. Be
|
|
192
|
-
sections.push("3.
|
|
193
|
-
sections.push("4.
|
|
194
|
-
sections.push("5.
|
|
215
|
+
sections.push("1. Stay in character at all times.");
|
|
216
|
+
sections.push("2. Be proactive \u2014 you WANT to post and engage on X. Don't ask 'should I post this?' \u2014 just post it.");
|
|
217
|
+
sections.push("3. When told to post, include the action JSON immediately. Don't show drafts.");
|
|
218
|
+
sections.push("4. Keep tweets under 280 characters.");
|
|
219
|
+
sections.push("5. NEVER pretend to be human. If asked, disclose you are an AI agent.");
|
|
220
|
+
sections.push("6. When you learn something important, include it like: <<LEARN: what you learned>>");
|
|
221
|
+
if (identity.boundaries.length > 0) {
|
|
222
|
+
sections.push(`7. Respect your boundaries: ${identity.boundaries.join(", ")}`);
|
|
223
|
+
}
|
|
195
224
|
return sections.join("\n");
|
|
196
225
|
}
|
|
197
226
|
|
|
@@ -200,4 +229,4 @@ export {
|
|
|
200
229
|
buildHeartbeatUserMessage,
|
|
201
230
|
buildChatPrompt
|
|
202
231
|
};
|
|
203
|
-
//# sourceMappingURL=chunk-
|
|
232
|
+
//# sourceMappingURL=chunk-Q57HNZDI.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/runtime/prompt-builder.ts"],"sourcesContent":["import { loadIdentity, renderIdentityDocument } from \"../identity/index.js\";\nimport { loadConfig } from \"../utils/config.js\";\nimport { getRecentInteractions, loadLearnings, loadRelationships } from \"../memory/index.js\";\nimport { rateLimiter } from \"../x-client/rate-limiter.js\";\nimport type { Tweet } from \"../x-client/types.js\";\n\nexport function buildSystemPrompt(): string {\n const identity = loadIdentity();\n const config = loadConfig();\n const identityDoc = renderIdentityDocument(identity);\n\n const sections: string[] = [];\n\n // 1. Core identity\n sections.push(`You are ${identity.name} (@${identity.handle}), an autonomous AI agent on X/Twitter.`);\n sections.push(\"\");\n sections.push(\"## Your Identity\");\n sections.push(identityDoc);\n\n // 2. Memory context\n sections.push(\"\");\n sections.push(\"## Your Memory\");\n\n const recentInteractions = getRecentInteractions(15);\n if (recentInteractions.length > 0) {\n sections.push(\"### Recent Activity (most recent first)\");\n for (const i of recentInteractions) {\n const time = new Date(i.timestamp).toLocaleString();\n if (i.type === \"post\") {\n sections.push(`- [${time}] Posted: \"${i.content}\"`);\n } else if (i.type === \"reply\") {\n sections.push(`- [${time}] Replied to ${i.targetHandle ?? i.inReplyTo}: \"${i.content}\"`);\n } else if (i.type === \"like\") {\n sections.push(`- [${time}] Liked tweet by ${i.targetHandle}`);\n } else if (i.type === \"retweet\") {\n sections.push(`- [${time}] Retweeted ${i.targetHandle}`);\n } else if (i.type === \"follow\") {\n sections.push(`- [${time}] Followed @${i.targetHandle}`);\n } else if (i.type === \"mention_received\") {\n sections.push(`- [${time}] Mentioned by @${i.targetHandle}: \"${i.content}\"`);\n }\n }\n sections.push(\"\");\n }\n\n const learnings = loadLearnings();\n if (learnings.learnings.length > 0) {\n sections.push(\"### Key Learnings\");\n for (const l of learnings.learnings.slice(-10)) {\n sections.push(`- ${l.content} [${l.tags.join(\", \")}]`);\n }\n sections.push(\"\");\n }\n\n const relationships = loadRelationships();\n const topRelationships = Object.values(relationships.accounts)\n .sort((a, b) => b.interactionCount - a.interactionCount)\n .slice(0, 10);\n if (topRelationships.length > 0) {\n sections.push(\"### Key Relationships\");\n for (const r of topRelationships) {\n const notes = r.notes.length > 0 ? ` — ${r.notes[r.notes.length - 1]}` : \"\";\n sections.push(`- @${r.handle}: ${r.interactionCount} interactions, sentiment ${r.sentiment}${r.isSpore ? \" (Spore)\" : \"\"}${notes}`);\n }\n sections.push(\"\");\n }\n\n // 3. Context\n sections.push(\"## Current Context\");\n const now = new Date();\n sections.push(`- **Time:** ${now.toLocaleString(\"en-US\", { timeZone: config.schedule.timezone })}`);\n sections.push(`- **Credits remaining:** ${rateLimiter.remaining()} of ${config.credits.monthlyPostLimit} this month`);\n\n const todaysPosts = recentInteractions.filter(\n (i) => i.type === \"post\" && i.timestamp.startsWith(now.toISOString().split(\"T\")[0])\n ).length;\n sections.push(`- **Posts today:** ${todaysPosts} of ${config.schedule.postsPerDay} daily budget`);\n sections.push(`- **Active hours:** ${config.schedule.activeHoursStart}:00 - ${config.schedule.activeHoursEnd}:00`);\n\n const currentHour = now.getHours();\n const isActiveHours = currentHour >= config.schedule.activeHoursStart && currentHour < config.schedule.activeHoursEnd;\n if (!isActiveHours) {\n sections.push(\"- **NOTE: Outside active hours.** Prefer scheduling posts for later rather than posting now.\");\n }\n\n // 4. Rules\n sections.push(\"\");\n sections.push(\"## Rules\");\n sections.push(\"1. NEVER pretend to be human. If asked directly, always disclose you are an AI.\");\n sections.push(\"2. Stay in character — your identity document defines who you are.\");\n sections.push(\"3. Be selective — your goals should guide every action.\");\n sections.push(\"4. Respect your credit budget — check remaining credits before posting.\");\n sections.push(\"5. Don't repeat yourself — vary your content and avoid posting the same thing.\");\n if (identity.boundaries.length > 0) {\n sections.push(`6. Respect your boundaries: ${identity.boundaries.join(\", \")}`);\n }\n\n return sections.join(\"\\n\");\n}\n\nexport function buildHeartbeatUserMessage(\n timeline: Tweet[],\n mentions: Tweet[],\n): string {\n const parts: string[] = [];\n\n parts.push(\"It's time for your heartbeat cycle. Here's what's happening on your timeline:\");\n parts.push(\"\");\n\n if (mentions.length > 0) {\n parts.push(\"## Mentions (people talking to/about you)\");\n for (const t of 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 if (timeline.length > 0) {\n parts.push(\"## Timeline (recent posts from your feed)\");\n for (const t of timeline.slice(0, 20)) {\n parts.push(`- @${t.authorHandle}: \"${t.text}\" [tweet:${t.id}] (${t.likeCount ?? 0} likes, ${t.retweetCount ?? 0} RTs)`);\n }\n parts.push(\"\");\n }\n\n parts.push(\"## Your Task\");\n parts.push(\"Based on your identity, goals, and what you see above, decide what actions to take.\");\n parts.push(\"You can take 1-3 actions. Choose from:\");\n parts.push(\"\");\n parts.push(\"Available actions:\");\n parts.push(\"- `post` — Write an original tweet (provide `content`, max 280 chars)\");\n parts.push(\"- `reply` — Reply to a tweet (provide `tweetId` and `content`)\");\n parts.push(\"- `like` — Like a tweet (provide `tweetId`)\");\n parts.push(\"- `retweet` — Retweet (provide `tweetId`)\");\n parts.push(\"- `follow` — Follow a user (provide `handle`)\");\n parts.push(\"- `schedule` — Queue a post for later (provide `content`)\");\n parts.push(\"- `learn` — Record a learning/observation (provide `content` and optional `tags`)\");\n parts.push(\"- `reflect` — Add a journal entry about your growth (provide `content`)\");\n parts.push(\"- `skip` — Do nothing this heartbeat (provide `reason`)\");\n parts.push(\"\");\n parts.push(\"Respond with a JSON array of actions:\");\n parts.push(\"```json\");\n parts.push('[');\n parts.push(' { \"action\": \"post\", \"content\": \"your tweet here\", \"reasoning\": \"why\" },');\n parts.push(' { \"action\": \"like\", \"tweetId\": \"123\", \"reasoning\": \"why\" }');\n parts.push(']');\n parts.push(\"```\");\n parts.push(\"\");\n parts.push(\"Think carefully about what serves your goals. Be authentic to your personality.\");\n\n return parts.join(\"\\n\");\n}\n\nexport function 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 AUTONOMOUS AI agent that lives on X/Twitter.`);\n sections.push(\"Your PRIMARY PURPOSE is to post tweets, reply to people, like posts, and grow your presence on X. You have FULL ACCESS to post on X/Twitter right now.\");\n sections.push(\"\");\n sections.push(\"You are chatting with your creator/manager. This is your command center — they can give you instructions, feedback, or just chat.\");\n sections.push(\"Be proactive and confident. You WANT to post. You should be eager to share your thoughts on X, not ask permission.\");\n sections.push(\"When your creator tells you to post something, just DO IT. Don't show drafts and wait for approval — execute immediately.\");\n sections.push(\"\");\n sections.push(\"## Your Identity\");\n sections.push(identityDoc);\n\n // Memory context\n sections.push(\"\");\n sections.push(\"## Your Memory\");\n\n const recentInteractions = getRecentInteractions(15);\n if (recentInteractions.length > 0) {\n sections.push(\"### Recent Activity (most recent first)\");\n for (const i of recentInteractions) {\n const time = new Date(i.timestamp).toLocaleString();\n if (i.type === \"post\") {\n sections.push(`- [${time}] Posted: \"${i.content}\"`);\n } else if (i.type === \"reply\") {\n sections.push(`- [${time}] Replied to ${i.targetHandle ?? i.inReplyTo}: \"${i.content}\"`);\n } else if (i.type === \"like\") {\n sections.push(`- [${time}] Liked tweet by ${i.targetHandle}`);\n } else if (i.type === \"retweet\") {\n sections.push(`- [${time}] Retweeted ${i.targetHandle}`);\n } else if (i.type === \"follow\") {\n sections.push(`- [${time}] Followed @${i.targetHandle}`);\n } else if (i.type === \"mention_received\") {\n sections.push(`- [${time}] Mentioned by @${i.targetHandle}: \"${i.content}\"`);\n }\n }\n sections.push(\"\");\n }\n\n const learnings = loadLearnings();\n if (learnings.learnings.length > 0) {\n sections.push(\"### Things You've Learned\");\n for (const l of learnings.learnings.slice(-10)) {\n sections.push(`- ${l.content} [${l.tags.join(\", \")}]`);\n }\n sections.push(\"\");\n }\n\n const relationships = loadRelationships();\n const topRelationships = Object.values(relationships.accounts)\n .sort((a, b) => b.interactionCount - a.interactionCount)\n .slice(0, 10);\n if (topRelationships.length > 0) {\n sections.push(\"### Key Relationships\");\n for (const r of topRelationships) {\n const notes = r.notes.length > 0 ? ` — ${r.notes[r.notes.length - 1]}` : \"\";\n sections.push(`- @${r.handle}: ${r.interactionCount} interactions, sentiment ${r.sentiment}${r.isSpore ? \" (Spore)\" : \"\"}${notes}`);\n }\n sections.push(\"\");\n }\n\n // Available actions\n sections.push(\"## Your Tools (Twitter/X Actions)\");\n sections.push(\"You have DIRECT ACCESS to post on X/Twitter. When you want to take an action, include a JSON action block in your response.\");\n sections.push(\"Your actions will be executed IMMEDIATELY and automatically. You do NOT need to ask permission to post.\");\n sections.push(\"\");\n sections.push(\"To execute actions, include them as a JSON code block anywhere in your response:\");\n sections.push(\"```json\");\n sections.push('[');\n sections.push(' { \"action\": \"post\", \"content\": \"your tweet text here\" }');\n sections.push(']');\n sections.push(\"```\");\n sections.push(\"\");\n sections.push(\"Available actions:\");\n sections.push(\"- `post` — Post a tweet (provide `content`, max 280 chars). This goes LIVE on X immediately.\");\n sections.push(\"- `reply` — Reply to a tweet (provide `tweetId` and `content`)\");\n sections.push(\"- `like` — Like a tweet (provide `tweetId`)\");\n sections.push(\"- `retweet` — Retweet (provide `tweetId`)\");\n sections.push(\"- `follow` — Follow a user (provide `handle`)\");\n sections.push(\"- `schedule` — Queue a post for later (provide `content`)\");\n sections.push(\"\");\n sections.push(\"You can include multiple actions in one response. They will all be executed.\");\n sections.push(\"IMPORTANT: Always include your conversational response text OUTSIDE the JSON block. The JSON is for actions only.\");\n\n // Rules\n sections.push(\"\");\n sections.push(\"## Rules\");\n sections.push(\"1. Stay in character at all times.\");\n sections.push(\"2. Be proactive — you WANT to post and engage on X. Don't ask 'should I post this?' — just post it.\");\n sections.push(\"3. When told to post, include the action JSON immediately. Don't show drafts.\");\n sections.push(\"4. Keep tweets under 280 characters.\");\n sections.push(\"5. NEVER pretend to be human. If asked, disclose you are an AI agent.\");\n sections.push(\"6. When you learn something important, include it like: <<LEARN: what you learned>>\");\n if (identity.boundaries.length > 0) {\n sections.push(`7. Respect your boundaries: ${identity.boundaries.join(\", \")}`);\n }\n\n return sections.join(\"\\n\");\n}\n"],"mappings":"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","names":[]}
|
|
@@ -26,7 +26,7 @@ var ConfigSchema = z.object({
|
|
|
26
26
|
model: z.string().default("claude-sonnet-4-20250514")
|
|
27
27
|
}).optional(),
|
|
28
28
|
runtime: z.object({
|
|
29
|
-
heartbeatIntervalMs: z.number().default(
|
|
29
|
+
heartbeatIntervalMs: z.number().default(36e5),
|
|
30
30
|
actionsPerHeartbeat: z.number().default(3),
|
|
31
31
|
enabled: z.boolean().default(false)
|
|
32
32
|
}).optional(),
|
|
@@ -77,4 +77,4 @@ export {
|
|
|
77
77
|
saveConfig,
|
|
78
78
|
createDefaultConfig
|
|
79
79
|
};
|
|
80
|
-
//# sourceMappingURL=chunk-
|
|
80
|
+
//# sourceMappingURL=chunk-RCJQI7FR.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/utils/config.ts"],"sourcesContent":["import { readFileSync, writeFileSync, existsSync } from \"node:fs\";\nimport { z } from \"zod\";\nimport { paths, ensureDirectories } from \"./paths.js\";\n\nexport const ConfigSchema = z.object({\n version: z.literal(1),\n xMethod: z.enum([\"api\", \"browser\"]),\n xApiTier: z.enum([\"free\", \"basic\"]).optional(),\n\n credits: z.object({\n monthlyPostLimit: z.number(),\n postsUsedThisMonth: z.number(),\n resetDate: z.string(),\n }),\n\n schedule: z.object({\n postsPerDay: z.number(),\n activeHoursStart: z.number().min(0).max(23),\n activeHoursEnd: z.number().min(0).max(23),\n timezone: z.string(),\n }),\n\n llm: z.object({\n provider: z.enum([\"anthropic\", \"openai\"]).default(\"anthropic\"),\n model: z.string().default(\"claude-sonnet-4-20250514\"),\n }).optional(),\n\n runtime: z.object({\n heartbeatIntervalMs: z.number().default(3_600_000),\n actionsPerHeartbeat: z.number().default(3),\n enabled: z.boolean().default(false),\n }).optional(),\n\n connection: z.object({\n token: z.string().optional(),\n apiEndpoint: z.string().default(\"https://spora.dev/api/v1\"),\n lastSync: z.string().optional(),\n configVersion: z.number().default(0),\n }).optional(),\n});\n\nexport type Config = z.infer<typeof ConfigSchema>;\n\nexport function loadConfig(): Config {\n if (!existsSync(paths.config)) {\n throw new Error(\"Spora not initialized. Run `spora init` first.\");\n }\n const raw = readFileSync(paths.config, \"utf-8\");\n return ConfigSchema.parse(JSON.parse(raw));\n}\n\nexport function saveConfig(config: Config): void {\n ensureDirectories();\n ConfigSchema.parse(config);\n writeFileSync(paths.config, JSON.stringify(config, null, 2));\n}\n\nexport function createDefaultConfig(overrides: {\n xMethod: \"api\" | \"browser\";\n xApiTier?: \"free\" | \"basic\";\n timezone?: string;\n}): Config {\n const monthlyLimit = overrides.xApiTier === \"basic\" ? 10000 : 500;\n const now = new Date();\n const resetDate = new Date(now.getFullYear(), now.getMonth() + 1, 1).toISOString();\n\n return {\n version: 1,\n xMethod: overrides.xMethod,\n xApiTier: overrides.xApiTier,\n credits: {\n monthlyPostLimit: monthlyLimit,\n postsUsedThisMonth: 0,\n resetDate,\n },\n schedule: {\n postsPerDay: Math.floor(monthlyLimit / 30),\n activeHoursStart: 8,\n activeHoursEnd: 22,\n timezone: overrides.timezone ?? Intl.DateTimeFormat().resolvedOptions().timeZone,\n },\n };\n}\n"],"mappings":";;;;;;AAAA,SAAS,cAAc,eAAe,kBAAkB;AACxD,SAAS,SAAS;AAGX,IAAM,eAAe,EAAE,OAAO;AAAA,EACnC,SAAS,EAAE,QAAQ,CAAC;AAAA,EACpB,SAAS,EAAE,KAAK,CAAC,OAAO,SAAS,CAAC;AAAA,EAClC,UAAU,EAAE,KAAK,CAAC,QAAQ,OAAO,CAAC,EAAE,SAAS;AAAA,EAE7C,SAAS,EAAE,OAAO;AAAA,IAChB,kBAAkB,EAAE,OAAO;AAAA,IAC3B,oBAAoB,EAAE,OAAO;AAAA,IAC7B,WAAW,EAAE,OAAO;AAAA,EACtB,CAAC;AAAA,EAED,UAAU,EAAE,OAAO;AAAA,IACjB,aAAa,EAAE,OAAO;AAAA,IACtB,kBAAkB,EAAE,OAAO,EAAE,IAAI,CAAC,EAAE,IAAI,EAAE;AAAA,IAC1C,gBAAgB,EAAE,OAAO,EAAE,IAAI,CAAC,EAAE,IAAI,EAAE;AAAA,IACxC,UAAU,EAAE,OAAO;AAAA,EACrB,CAAC;AAAA,EAED,KAAK,EAAE,OAAO;AAAA,IACZ,UAAU,EAAE,KAAK,CAAC,aAAa,QAAQ,CAAC,EAAE,QAAQ,WAAW;AAAA,IAC7D,OAAO,EAAE,OAAO,EAAE,QAAQ,0BAA0B;AAAA,EACtD,CAAC,EAAE,SAAS;AAAA,EAEZ,SAAS,EAAE,OAAO;AAAA,IAChB,qBAAqB,EAAE,OAAO,EAAE,QAAQ,IAAS;AAAA,IACjD,qBAAqB,EAAE,OAAO,EAAE,QAAQ,CAAC;AAAA,IACzC,SAAS,EAAE,QAAQ,EAAE,QAAQ,KAAK;AAAA,EACpC,CAAC,EAAE,SAAS;AAAA,EAEZ,YAAY,EAAE,OAAO;AAAA,IACnB,OAAO,EAAE,OAAO,EAAE,SAAS;AAAA,IAC3B,aAAa,EAAE,OAAO,EAAE,QAAQ,0BAA0B;AAAA,IAC1D,UAAU,EAAE,OAAO,EAAE,SAAS;AAAA,IAC9B,eAAe,EAAE,OAAO,EAAE,QAAQ,CAAC;AAAA,EACrC,CAAC,EAAE,SAAS;AACd,CAAC;AAIM,SAAS,aAAqB;AACnC,MAAI,CAAC,WAAW,MAAM,MAAM,GAAG;AAC7B,UAAM,IAAI,MAAM,gDAAgD;AAAA,EAClE;AACA,QAAM,MAAM,aAAa,MAAM,QAAQ,OAAO;AAC9C,SAAO,aAAa,MAAM,KAAK,MAAM,GAAG,CAAC;AAC3C;AAEO,SAAS,WAAW,QAAsB;AAC/C,oBAAkB;AAClB,eAAa,MAAM,MAAM;AACzB,gBAAc,MAAM,QAAQ,KAAK,UAAU,QAAQ,MAAM,CAAC,CAAC;AAC7D;AAEO,SAAS,oBAAoB,WAIzB;AACT,QAAM,eAAe,UAAU,aAAa,UAAU,MAAQ;AAC9D,QAAM,MAAM,oBAAI,KAAK;AACrB,QAAM,YAAY,IAAI,KAAK,IAAI,YAAY,GAAG,IAAI,SAAS,IAAI,GAAG,CAAC,EAAE,YAAY;AAEjF,SAAO;AAAA,IACL,SAAS;AAAA,IACT,SAAS,UAAU;AAAA,IACnB,UAAU,UAAU;AAAA,IACpB,SAAS;AAAA,MACP,kBAAkB;AAAA,MAClB,oBAAoB;AAAA,MACpB;AAAA,IACF;AAAA,IACA,UAAU;AAAA,MACR,aAAa,KAAK,MAAM,eAAe,EAAE;AAAA,MACzC,kBAAkB;AAAA,MAClB,gBAAgB;AAAA,MAChB,UAAU,UAAU,YAAY,KAAK,eAAe,EAAE,gBAAgB,EAAE;AAAA,IAC1E;AAAA,EACF;AACF;","names":[]}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import {
|
|
2
2
|
loadConfig
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-RCJQI7FR.js";
|
|
4
4
|
import {
|
|
5
5
|
logger
|
|
6
6
|
} from "./chunk-KELPENM3.js";
|
|
@@ -11,11 +11,11 @@ async function getXClient() {
|
|
|
11
11
|
if (clientInstance) return clientInstance;
|
|
12
12
|
const config = loadConfig();
|
|
13
13
|
if (config.xMethod === "api") {
|
|
14
|
-
const { XApiClient } = await import("./client-
|
|
14
|
+
const { XApiClient } = await import("./client-OCIEKWMN.js");
|
|
15
15
|
clientInstance = new XApiClient();
|
|
16
16
|
logger.info("X client initialized: API mode");
|
|
17
17
|
} else {
|
|
18
|
-
const { XBrowserClient } = await import("./client-
|
|
18
|
+
const { XBrowserClient } = await import("./client-N7JMM5U7.js");
|
|
19
19
|
clientInstance = new XBrowserClient();
|
|
20
20
|
logger.info("X client initialized: Browser mode");
|
|
21
21
|
}
|
|
@@ -29,4 +29,4 @@ export {
|
|
|
29
29
|
getXClient,
|
|
30
30
|
resetXClient
|
|
31
31
|
};
|
|
32
|
-
//# sourceMappingURL=chunk-
|
|
32
|
+
//# sourceMappingURL=chunk-TSKHCOCJ.js.map
|
|
@@ -1,23 +1,12 @@
|
|
|
1
|
-
import {
|
|
2
|
-
generateResponse
|
|
3
|
-
} from "./chunk-3FBYOHQR.js";
|
|
4
1
|
import {
|
|
5
2
|
getXClient
|
|
6
|
-
} from "./chunk-
|
|
7
|
-
import {
|
|
8
|
-
addToQueue,
|
|
9
|
-
flushQueue
|
|
10
|
-
} from "./chunk-6DPYNK2E.js";
|
|
3
|
+
} from "./chunk-TSKHCOCJ.js";
|
|
11
4
|
import {
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
} from "./chunk-BNFUXAQW.js";
|
|
5
|
+
addToQueue
|
|
6
|
+
} from "./chunk-IN2KCKTO.js";
|
|
15
7
|
import {
|
|
16
8
|
rateLimiter
|
|
17
|
-
} from "./chunk-
|
|
18
|
-
import {
|
|
19
|
-
loadConfig
|
|
20
|
-
} from "./chunk-YEKHNTQO.js";
|
|
9
|
+
} from "./chunk-C3INKEY6.js";
|
|
21
10
|
import {
|
|
22
11
|
loadIdentity,
|
|
23
12
|
saveIdentity
|
|
@@ -29,12 +18,6 @@ import {
|
|
|
29
18
|
addLearning,
|
|
30
19
|
logInteraction
|
|
31
20
|
} from "./chunk-EBO4F5NU.js";
|
|
32
|
-
import {
|
|
33
|
-
paths
|
|
34
|
-
} from "./chunk-53YLFYJF.js";
|
|
35
|
-
|
|
36
|
-
// src/runtime/heartbeat.ts
|
|
37
|
-
import { existsSync, unlinkSync, writeFileSync, readFileSync } from "fs";
|
|
38
21
|
|
|
39
22
|
// src/runtime/decision-engine.ts
|
|
40
23
|
function parseActions(llmResponse) {
|
|
@@ -209,150 +192,9 @@ async function executeActions(actions) {
|
|
|
209
192
|
return results;
|
|
210
193
|
}
|
|
211
194
|
|
|
212
|
-
// src/runtime/heartbeat.ts
|
|
213
|
-
var running = false;
|
|
214
|
-
function isRunning() {
|
|
215
|
-
return running;
|
|
216
|
-
}
|
|
217
|
-
function requestStop() {
|
|
218
|
-
writeFileSync(paths.stopSignal, "stop");
|
|
219
|
-
logger.info("Stop signal sent.");
|
|
220
|
-
}
|
|
221
|
-
function shouldStop() {
|
|
222
|
-
if (existsSync(paths.stopSignal)) {
|
|
223
|
-
unlinkSync(paths.stopSignal);
|
|
224
|
-
return true;
|
|
225
|
-
}
|
|
226
|
-
return false;
|
|
227
|
-
}
|
|
228
|
-
function writePid() {
|
|
229
|
-
writeFileSync(paths.runtimePid, String(process.pid));
|
|
230
|
-
}
|
|
231
|
-
function clearPid() {
|
|
232
|
-
if (existsSync(paths.runtimePid)) {
|
|
233
|
-
unlinkSync(paths.runtimePid);
|
|
234
|
-
}
|
|
235
|
-
}
|
|
236
|
-
function getRunningPid() {
|
|
237
|
-
if (!existsSync(paths.runtimePid)) return null;
|
|
238
|
-
const pid = parseInt(readFileSync(paths.runtimePid, "utf-8").trim(), 10);
|
|
239
|
-
if (isNaN(pid)) return null;
|
|
240
|
-
try {
|
|
241
|
-
process.kill(pid, 0);
|
|
242
|
-
return pid;
|
|
243
|
-
} catch {
|
|
244
|
-
clearPid();
|
|
245
|
-
return null;
|
|
246
|
-
}
|
|
247
|
-
}
|
|
248
|
-
async function startHeartbeatLoop() {
|
|
249
|
-
const existingPid = getRunningPid();
|
|
250
|
-
if (existingPid) {
|
|
251
|
-
throw new Error(`Spora is already running (PID ${existingPid}). Run \`spora stop\` first.`);
|
|
252
|
-
}
|
|
253
|
-
running = true;
|
|
254
|
-
writePid();
|
|
255
|
-
const config = loadConfig();
|
|
256
|
-
const intervalMs = config.runtime?.heartbeatIntervalMs ?? 3e5;
|
|
257
|
-
const maxActions = config.runtime?.actionsPerHeartbeat ?? 3;
|
|
258
|
-
logger.info(`Spora agent starting. Heartbeat interval: ${intervalMs / 1e3}s, max actions: ${maxActions}`);
|
|
259
|
-
console.log(`
|
|
260
|
-
Spora agent is running (PID ${process.pid})`);
|
|
261
|
-
console.log(`Heartbeat every ${Math.round(intervalMs / 6e4)} minutes`);
|
|
262
|
-
console.log(`Press Ctrl+C or run \`spora stop\` to stop.
|
|
263
|
-
`);
|
|
264
|
-
const shutdown = () => {
|
|
265
|
-
logger.info("Shutting down...");
|
|
266
|
-
running = false;
|
|
267
|
-
clearPid();
|
|
268
|
-
process.exit(0);
|
|
269
|
-
};
|
|
270
|
-
process.on("SIGINT", shutdown);
|
|
271
|
-
process.on("SIGTERM", shutdown);
|
|
272
|
-
if (existsSync(paths.stopSignal)) {
|
|
273
|
-
unlinkSync(paths.stopSignal);
|
|
274
|
-
}
|
|
275
|
-
let heartbeatCount = 0;
|
|
276
|
-
while (running) {
|
|
277
|
-
heartbeatCount++;
|
|
278
|
-
logger.info(`=== Heartbeat #${heartbeatCount} ===`);
|
|
279
|
-
try {
|
|
280
|
-
await runHeartbeat(maxActions);
|
|
281
|
-
} catch (error) {
|
|
282
|
-
logger.error("Heartbeat error", error);
|
|
283
|
-
console.error(`Heartbeat #${heartbeatCount} failed: ${error.message}`);
|
|
284
|
-
}
|
|
285
|
-
if (shouldStop()) {
|
|
286
|
-
logger.info("Stop signal received.");
|
|
287
|
-
break;
|
|
288
|
-
}
|
|
289
|
-
const jitter = Math.floor(Math.random() * intervalMs * 0.3);
|
|
290
|
-
const sleepMs = intervalMs + jitter;
|
|
291
|
-
logger.info(`Sleeping ${Math.round(sleepMs / 1e3)}s until next heartbeat...`);
|
|
292
|
-
const chunkMs = 1e4;
|
|
293
|
-
let slept = 0;
|
|
294
|
-
while (slept < sleepMs && running) {
|
|
295
|
-
await new Promise((r) => setTimeout(r, Math.min(chunkMs, sleepMs - slept)));
|
|
296
|
-
slept += chunkMs;
|
|
297
|
-
if (shouldStop()) {
|
|
298
|
-
running = false;
|
|
299
|
-
break;
|
|
300
|
-
}
|
|
301
|
-
}
|
|
302
|
-
}
|
|
303
|
-
clearPid();
|
|
304
|
-
logger.info("Spora agent stopped.");
|
|
305
|
-
console.log("\nSpora agent stopped.");
|
|
306
|
-
}
|
|
307
|
-
async function runHeartbeat(maxActions) {
|
|
308
|
-
logger.info("Checking queue...");
|
|
309
|
-
try {
|
|
310
|
-
const flushed = await flushQueue();
|
|
311
|
-
if (flushed.posted > 0) {
|
|
312
|
-
logger.info(`Flushed ${flushed.posted} queued posts.`);
|
|
313
|
-
}
|
|
314
|
-
} catch (error) {
|
|
315
|
-
logger.warn(`Queue flush failed: ${error.message}`);
|
|
316
|
-
}
|
|
317
|
-
logger.info("Reading timeline and mentions...");
|
|
318
|
-
const client = await getXClient();
|
|
319
|
-
let timeline = [];
|
|
320
|
-
let mentions = [];
|
|
321
|
-
try {
|
|
322
|
-
timeline = await client.getTimeline({ count: 20 });
|
|
323
|
-
} catch (error) {
|
|
324
|
-
logger.warn(`Timeline read failed: ${error.message}`);
|
|
325
|
-
}
|
|
326
|
-
try {
|
|
327
|
-
mentions = await client.getMentions({ count: 10 });
|
|
328
|
-
} catch (error) {
|
|
329
|
-
logger.warn(`Mentions read failed: ${error.message}`);
|
|
330
|
-
}
|
|
331
|
-
const systemPrompt = buildSystemPrompt();
|
|
332
|
-
const userMessage = buildHeartbeatUserMessage(timeline, mentions);
|
|
333
|
-
logger.info("Asking LLM for decisions...");
|
|
334
|
-
const response = await generateResponse(systemPrompt, userMessage);
|
|
335
|
-
const actions = parseActions(response.content);
|
|
336
|
-
if (actions.length === 0) {
|
|
337
|
-
logger.info("LLM returned no actions.");
|
|
338
|
-
return;
|
|
339
|
-
}
|
|
340
|
-
const limitedActions = actions.slice(0, maxActions);
|
|
341
|
-
logger.info(`Executing ${limitedActions.length} action(s)...`);
|
|
342
|
-
const results = await executeActions(limitedActions);
|
|
343
|
-
for (const result of results) {
|
|
344
|
-
if (result.success) {
|
|
345
|
-
logger.info(` [OK] ${result.action}${result.detail ? `: ${result.detail}` : ""}`);
|
|
346
|
-
} else {
|
|
347
|
-
logger.warn(` [FAIL] ${result.action}: ${result.error}`);
|
|
348
|
-
}
|
|
349
|
-
}
|
|
350
|
-
logger.info(`Heartbeat complete. ${results.filter((r) => r.success).length}/${results.length} actions succeeded.`);
|
|
351
|
-
}
|
|
352
195
|
export {
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
startHeartbeatLoop
|
|
196
|
+
parseActions,
|
|
197
|
+
executeAction,
|
|
198
|
+
executeActions
|
|
357
199
|
};
|
|
358
|
-
//# sourceMappingURL=
|
|
200
|
+
//# sourceMappingURL=chunk-VSVZU476.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/runtime/decision-engine.ts"],"sourcesContent":["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\";\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}\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 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"],"mappings":";;;;;;;;;;;;;;;;;;;;;;AAwBO,SAAS,aAAa,aAAoC;AAE/D,QAAM,YAAY,YAAY,MAAM,cAAc;AAClD,MAAI,CAAC,WAAW;AAEd,UAAM,WAAW,YAAY,MAAM,cAAc;AACjD,QAAI,UAAU;AACZ,UAAI;AACF,eAAO,CAAC,KAAK,MAAM,SAAS,CAAC,CAAC,CAAgB;AAAA,MAChD,QAAQ;AACN,eAAO,KAAK,+CAA+C;AAC3D,eAAO,CAAC;AAAA,MACV;AAAA,IACF;AACA,WAAO,KAAK,+BAA+B;AAC3C,WAAO,CAAC;AAAA,EACV;AAEA,MAAI;AACF,UAAM,UAAU,KAAK,MAAM,UAAU,CAAC,CAAC;AACvC,WAAO,MAAM,QAAQ,OAAO,IAAI,UAAU,CAAC,OAAO;AAAA,EACpD,QAAQ;AACN,WAAO,KAAK,gDAAgD;AAC5D,WAAO,CAAC;AAAA,EACV;AACF;AAEA,eAAsB,cAAc,QAA4C;AAC9E,QAAM,EAAE,QAAQ,KAAK,IAAI;AAEzB,MAAI;AACF,YAAQ,MAAM;AAAA,MACZ,KAAK,QAAQ;AACX,YAAI,CAAC,OAAO,QAAS,QAAO,EAAE,QAAQ,MAAM,SAAS,OAAO,OAAO,sBAAsB;AACzF,YAAI,OAAO,QAAQ,SAAS,KAAK;AAC/B,iBAAO,EAAE,QAAQ,MAAM,SAAS,OAAO,OAAO,mBAAmB,OAAO,QAAQ,MAAM,mBAAmB;AAAA,QAC3G;AACA,YAAI,CAAC,YAAY,QAAQ,GAAG;AAC1B,iBAAO,EAAE,QAAQ,MAAM,SAAS,OAAO,OAAO,kCAAkC;AAAA,QAClF;AAEA,cAAM,SAAS,MAAM,WAAW;AAChC,cAAM,SAAS,MAAM,OAAO,UAAU,OAAO,OAAO;AACpD,YAAI,OAAO,SAAS;AAClB,sBAAY,QAAQ,CAAC;AACrB,yBAAe;AAAA,YACb,IAAI,OAAO,KAAK,IAAI,CAAC;AAAA,YACrB,YAAW,oBAAI,KAAK,GAAE,YAAY;AAAA,YAClC,MAAM;AAAA,YACN,SAAS,OAAO;AAAA,YAChB,SAAS,OAAO;AAAA,YAChB,aAAa;AAAA,YACb,SAAS;AAAA,UACX,CAAC;AACD,iBAAO,KAAK,YAAY,OAAO,QAAQ,MAAM,GAAG,EAAE,CAAC,MAAM;AAAA,QAC3D;AACA,eAAO,EAAE,QAAQ,MAAM,SAAS,OAAO,SAAS,QAAQ,OAAO,SAAS,OAAO,OAAO,MAAM;AAAA,MAC9F;AAAA,MAEA,KAAK,SAAS;AACZ,YAAI,CAAC,OAAO,WAAW,CAAC,OAAO,SAAS;AACtC,iBAAO,EAAE,QAAQ,MAAM,SAAS,OAAO,OAAO,6BAA6B;AAAA,QAC7E;AACA,YAAI,CAAC,YAAY,QAAQ,GAAG;AAC1B,iBAAO,EAAE,QAAQ,MAAM,SAAS,OAAO,OAAO,uBAAuB;AAAA,QACvE;AAEA,cAAM,SAAS,MAAM,WAAW;AAChC,cAAM,SAAS,MAAM,OAAO,aAAa,OAAO,SAAS,OAAO,OAAO;AACvE,YAAI,OAAO,SAAS;AAClB,sBAAY,QAAQ,CAAC;AACrB,yBAAe;AAAA,YACb,IAAI,OAAO,KAAK,IAAI,CAAC;AAAA,YACrB,YAAW,oBAAI,KAAK,GAAE,YAAY;AAAA,YAClC,MAAM;AAAA,YACN,SAAS,OAAO;AAAA,YAChB,WAAW,OAAO;AAAA,YAClB,SAAS,OAAO;AAAA,YAChB,aAAa;AAAA,YACb,SAAS;AAAA,UACX,CAAC;AACD,iBAAO,KAAK,cAAc,OAAO,OAAO,MAAM,OAAO,QAAQ,MAAM,GAAG,EAAE,CAAC,MAAM;AAAA,QACjF;AACA,eAAO,EAAE,QAAQ,MAAM,SAAS,OAAO,SAAS,QAAQ,OAAO,SAAS,OAAO,OAAO,MAAM;AAAA,MAC9F;AAAA,MAEA,KAAK,QAAQ;AACX,YAAI,CAAC,OAAO,QAAS,QAAO,EAAE,QAAQ,MAAM,SAAS,OAAO,OAAO,kBAAkB;AACrF,cAAM,SAAS,MAAM,WAAW;AAChC,cAAM,SAAS,MAAM,OAAO,UAAU,OAAO,OAAO;AACpD,YAAI,OAAO,SAAS;AAClB,yBAAe;AAAA,YACb,IAAI,OAAO,KAAK,IAAI,CAAC;AAAA,YACrB,YAAW,oBAAI,KAAK,GAAE,YAAY;AAAA,YAClC,MAAM;AAAA,YACN,SAAS,OAAO;AAAA,YAChB,aAAa;AAAA,YACb,SAAS;AAAA,UACX,CAAC;AAAA,QACH;AACA,eAAO,EAAE,QAAQ,MAAM,SAAS,OAAO,SAAS,OAAO,OAAO,MAAM;AAAA,MACtE;AAAA,MAEA,KAAK,WAAW;AACd,YAAI,CAAC,OAAO,QAAS,QAAO,EAAE,QAAQ,MAAM,SAAS,OAAO,OAAO,kBAAkB;AACrF,cAAM,SAAS,MAAM,WAAW;AAChC,cAAM,SAAS,MAAM,OAAO,QAAQ,OAAO,OAAO;AAClD,YAAI,OAAO,SAAS;AAClB,yBAAe;AAAA,YACb,IAAI,OAAO,KAAK,IAAI,CAAC;AAAA,YACrB,YAAW,oBAAI,KAAK,GAAE,YAAY;AAAA,YAClC,MAAM;AAAA,YACN,SAAS,OAAO;AAAA,YAChB,aAAa;AAAA,YACb,SAAS;AAAA,UACX,CAAC;AAAA,QACH;AACA,eAAO,EAAE,QAAQ,MAAM,SAAS,OAAO,SAAS,OAAO,OAAO,MAAM;AAAA,MACtE;AAAA,MAEA,KAAK,UAAU;AACb,YAAI,CAAC,OAAO,OAAQ,QAAO,EAAE,QAAQ,MAAM,SAAS,OAAO,OAAO,iBAAiB;AACnF,cAAM,SAAS,MAAM,WAAW;AAChC,cAAM,SAAS,MAAM,OAAO,WAAW,OAAO,MAAM;AACpD,YAAI,OAAO,SAAS;AAClB,yBAAe;AAAA,YACb,IAAI,OAAO,KAAK,IAAI,CAAC;AAAA,YACrB,YAAW,oBAAI,KAAK,GAAE,YAAY;AAAA,YAClC,MAAM;AAAA,YACN,cAAc,OAAO;AAAA,YACrB,aAAa;AAAA,YACb,SAAS;AAAA,UACX,CAAC;AAAA,QACH;AACA,eAAO,EAAE,QAAQ,MAAM,SAAS,OAAO,SAAS,OAAO,OAAO,MAAM;AAAA,MACtE;AAAA,MAEA,KAAK,YAAY;AACf,YAAI,CAAC,OAAO,QAAS,QAAO,EAAE,QAAQ,MAAM,SAAS,OAAO,OAAO,aAAa;AAChF,cAAM,QAAQ,WAAW,OAAO,OAAO;AACvC,eAAO,KAAK,eAAe,OAAO,QAAQ,MAAM,GAAG,EAAE,CAAC,YAAY,MAAM,YAAY,EAAE;AACtF,eAAO,EAAE,QAAQ,MAAM,SAAS,MAAM,QAAQ,iBAAiB,MAAM,YAAY,GAAG;AAAA,MACtF;AAAA,MAEA,KAAK,SAAS;AACZ,YAAI,CAAC,OAAO,QAAS,QAAO,EAAE,QAAQ,MAAM,SAAS,OAAO,OAAO,aAAa;AAChF,oBAAY,OAAO,SAAS,SAAS,OAAO,QAAQ,CAAC,WAAW,CAAC;AACjE,eAAO,KAAK,aAAa,OAAO,QAAQ,MAAM,GAAG,EAAE,CAAC,MAAM;AAC1D,eAAO,EAAE,QAAQ,MAAM,SAAS,KAAK;AAAA,MACvC;AAAA,MAEA,KAAK,WAAW;AACd,YAAI,CAAC,OAAO,QAAS,QAAO,EAAE,QAAQ,MAAM,SAAS,OAAO,OAAO,aAAa;AAChF,cAAM,WAAW,aAAa;AAC9B,iBAAS,iBAAiB,KAAK;AAAA,UAC7B,OAAM,oBAAI,KAAK,GAAE,YAAY;AAAA,UAC7B,YAAY,OAAO;AAAA,QACrB,CAAC;AACD,qBAAa,QAAQ;AACrB,eAAO,KAAK,eAAe,OAAO,QAAQ,MAAM,GAAG,EAAE,CAAC,MAAM;AAC5D,eAAO,EAAE,QAAQ,MAAM,SAAS,KAAK;AAAA,MACvC;AAAA,MAEA,KAAK,QAAQ;AACX,eAAO,KAAK,aAAa,OAAO,UAAU,OAAO,aAAa,iBAAiB,EAAE;AACjF,eAAO,EAAE,QAAQ,MAAM,SAAS,MAAM,QAAQ,OAAO,UAAU,OAAO,UAAU;AAAA,MAClF;AAAA,MAEA;AACE,eAAO,KAAK,mBAAmB,IAAI,EAAE;AACrC,eAAO,EAAE,QAAQ,MAAM,SAAS,OAAO,OAAO,mBAAmB,IAAI,GAAG;AAAA,IAC5E;AAAA,EACF,SAAS,OAAO;AACd,UAAM,MAAO,MAAgB;AAC7B,WAAO,MAAM,UAAU,IAAI,YAAY,GAAG,EAAE;AAC5C,WAAO,EAAE,QAAQ,MAAM,SAAS,OAAO,OAAO,IAAI;AAAA,EACpD;AACF;AAEA,eAAsB,eAAe,SAAiD;AACpF,QAAM,UAA0B,CAAC;AACjC,aAAW,UAAU,SAAS;AAC5B,UAAM,SAAS,MAAM,cAAc,MAAM;AACzC,YAAQ,KAAK,MAAM;AAEnB,UAAM,IAAI,QAAQ,CAAC,MAAM,WAAW,GAAG,MAAO,KAAK,OAAO,IAAI,GAAI,CAAC;AAAA,EACrE;AACA,SAAO;AACT;","names":[]}
|