spora 0.7.4 → 0.7.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (88) hide show
  1. package/dist/autonomy-DFPA3OK6.js +20 -0
  2. package/dist/{chunk-SUZUJGGW.js → chunk-342ZX72W.js} +4 -4
  3. package/dist/{chunk-PN5A6MCV.js → chunk-5R4AJZHN.js} +4 -4
  4. package/dist/{chunk-PN5A6MCV.js.map → chunk-5R4AJZHN.js.map} +1 -1
  5. package/dist/{chunk-Q3YXJ2C6.js → chunk-A2XTKC7B.js} +281 -65
  6. package/dist/chunk-A2XTKC7B.js.map +1 -0
  7. package/dist/{chunk-JBYZ7K56.js → chunk-BBXHECZ5.js} +2 -2
  8. package/dist/{chunk-WN35MRMF.js → chunk-CAWWG3MD.js} +2 -2
  9. package/dist/chunk-CP6JWCLY.js +171 -0
  10. package/dist/chunk-CP6JWCLY.js.map +1 -0
  11. package/dist/{chunk-T7L2L7ZL.js → chunk-D47OFTEK.js} +2 -2
  12. package/dist/chunk-HXI2EH5C.js +2338 -0
  13. package/dist/chunk-HXI2EH5C.js.map +1 -0
  14. package/dist/{chunk-M6YOQVSI.js → chunk-IULO3GRE.js} +4 -4
  15. package/dist/chunk-IULO3GRE.js.map +1 -0
  16. package/dist/chunk-OTZNHIXT.js +431 -0
  17. package/dist/chunk-OTZNHIXT.js.map +1 -0
  18. package/dist/{chunk-NO3NQN67.js → chunk-QYFNAGNI.js} +2 -2
  19. package/dist/{chunk-YMGJQRKG.js → chunk-RSNEVBEI.js} +2 -2
  20. package/dist/{chunk-QWEYVDLU.js → chunk-SXNZVKLJ.js} +2 -2
  21. package/dist/{chunk-MDOFAAZB.js → chunk-ZLSDFYBR.js} +17 -5
  22. package/dist/chunk-ZLSDFYBR.js.map +1 -0
  23. package/dist/{chunk-3RYCUGXE.js → chunk-ZWKTKWS6.js} +4 -1
  24. package/dist/chunk-ZWKTKWS6.js.map +1 -0
  25. package/dist/cli.js +49 -49
  26. package/dist/{client-Z5UQWPPI.js → client-AR5ZD6S4.js} +48 -16
  27. package/dist/client-AR5ZD6S4.js.map +1 -0
  28. package/dist/{colony-NNX45EAV.js → colony-UGVYALOS.js} +7 -7
  29. package/dist/{config-FL4VJVKZ.js → config-MU2ODEO3.js} +3 -3
  30. package/dist/{crypto-B65ZH7KN.js → crypto-GDG5K3ZH.js} +3 -3
  31. package/dist/{goals-RBKLMILE.js → goals-QWX3A47Y.js} +3 -3
  32. package/dist/{heartbeat-ZCCOIZGU.js → heartbeat-RAOEIKWC.js} +18 -21
  33. package/dist/heartbeat-RAOEIKWC.js.map +1 -0
  34. package/dist/{identity-VDUW4I2K.js → identity-ASHVWIN5.js} +3 -3
  35. package/dist/{init-SEJPTOOB.js → init-ETUTFHT6.js} +59 -13
  36. package/dist/init-ETUTFHT6.js.map +1 -0
  37. package/dist/{llm-OGOYCWBH.js → llm-IJBRQ7O2.js} +5 -5
  38. package/dist/mcp-server.js +24 -24
  39. package/dist/{memory-PNW7SX7A.js → memory-AWKIW2KW.js} +3 -3
  40. package/dist/{memory-OIAH33G2.js → memory-DTSLVSQG.js} +3 -3
  41. package/dist/{paths-BYR6MEPR.js → paths-4V5OCB5F.js} +2 -2
  42. package/dist/prompt-builder-XJHXZCSQ.js +27 -0
  43. package/dist/queue-QCGNDHH2.js +14 -0
  44. package/dist/strategy-R2BMRVJ3.js +19 -0
  45. package/dist/{web-chat-ZZ65DUID.js → web-chat-TB3ACPVF.js} +23 -28
  46. package/dist/web-chat-TB3ACPVF.js.map +1 -0
  47. package/dist/x-client-S2LUVEKV.js +12 -0
  48. package/package.json +1 -1
  49. package/dist/autonomy-XUKCAZM3.js +0 -19
  50. package/dist/chunk-3RYCUGXE.js.map +0 -1
  51. package/dist/chunk-4LNMA56H.js +0 -57
  52. package/dist/chunk-4LNMA56H.js.map +0 -1
  53. package/dist/chunk-EU4FMOKG.js +0 -377
  54. package/dist/chunk-EU4FMOKG.js.map +0 -1
  55. package/dist/chunk-M6YOQVSI.js.map +0 -1
  56. package/dist/chunk-MDOFAAZB.js.map +0 -1
  57. package/dist/chunk-P6KZIJYL.js +0 -79
  58. package/dist/chunk-P6KZIJYL.js.map +0 -1
  59. package/dist/chunk-Q3YXJ2C6.js.map +0 -1
  60. package/dist/client-Z5UQWPPI.js.map +0 -1
  61. package/dist/heartbeat-ZCCOIZGU.js.map +0 -1
  62. package/dist/init-SEJPTOOB.js.map +0 -1
  63. package/dist/prompt-builder-KJKFCGM7.js +0 -25
  64. package/dist/queue-2ZBKDFX3.js +0 -14
  65. package/dist/strategy-Z4JSFHSP.js +0 -12
  66. package/dist/web-chat-ZZ65DUID.js.map +0 -1
  67. package/dist/x-client-YG7UCCNI.js +0 -12
  68. /package/dist/{autonomy-XUKCAZM3.js.map → autonomy-DFPA3OK6.js.map} +0 -0
  69. /package/dist/{chunk-SUZUJGGW.js.map → chunk-342ZX72W.js.map} +0 -0
  70. /package/dist/{chunk-JBYZ7K56.js.map → chunk-BBXHECZ5.js.map} +0 -0
  71. /package/dist/{chunk-WN35MRMF.js.map → chunk-CAWWG3MD.js.map} +0 -0
  72. /package/dist/{chunk-T7L2L7ZL.js.map → chunk-D47OFTEK.js.map} +0 -0
  73. /package/dist/{chunk-NO3NQN67.js.map → chunk-QYFNAGNI.js.map} +0 -0
  74. /package/dist/{chunk-YMGJQRKG.js.map → chunk-RSNEVBEI.js.map} +0 -0
  75. /package/dist/{chunk-QWEYVDLU.js.map → chunk-SXNZVKLJ.js.map} +0 -0
  76. /package/dist/{colony-NNX45EAV.js.map → colony-UGVYALOS.js.map} +0 -0
  77. /package/dist/{config-FL4VJVKZ.js.map → config-MU2ODEO3.js.map} +0 -0
  78. /package/dist/{crypto-B65ZH7KN.js.map → crypto-GDG5K3ZH.js.map} +0 -0
  79. /package/dist/{goals-RBKLMILE.js.map → goals-QWX3A47Y.js.map} +0 -0
  80. /package/dist/{identity-VDUW4I2K.js.map → identity-ASHVWIN5.js.map} +0 -0
  81. /package/dist/{llm-OGOYCWBH.js.map → llm-IJBRQ7O2.js.map} +0 -0
  82. /package/dist/{memory-OIAH33G2.js.map → memory-AWKIW2KW.js.map} +0 -0
  83. /package/dist/{memory-PNW7SX7A.js.map → memory-DTSLVSQG.js.map} +0 -0
  84. /package/dist/{paths-BYR6MEPR.js.map → paths-4V5OCB5F.js.map} +0 -0
  85. /package/dist/{prompt-builder-KJKFCGM7.js.map → prompt-builder-XJHXZCSQ.js.map} +0 -0
  86. /package/dist/{queue-2ZBKDFX3.js.map → queue-QCGNDHH2.js.map} +0 -0
  87. /package/dist/{strategy-Z4JSFHSP.js.map → strategy-R2BMRVJ3.js.map} +0 -0
  88. /package/dist/{x-client-YG7UCCNI.js.map → x-client-S2LUVEKV.js.map} +0 -0
@@ -1,377 +0,0 @@
1
- import {
2
- getXClient
3
- } from "./chunk-PN5A6MCV.js";
4
- import {
5
- addToQueue
6
- } from "./chunk-MDOFAAZB.js";
7
- import {
8
- buildSystemPrompt,
9
- buildToolDecisionMessage
10
- } from "./chunk-Q3YXJ2C6.js";
11
- import {
12
- loadIdentity,
13
- saveIdentity
14
- } from "./chunk-M6YOQVSI.js";
15
- import {
16
- generateResponse
17
- } from "./chunk-SUZUJGGW.js";
18
- import {
19
- logger
20
- } from "./chunk-YMGJQRKG.js";
21
- import {
22
- addLearning,
23
- getRecentInteractions
24
- } from "./chunk-JBYZ7K56.js";
25
-
26
- // src/runtime/decision-engine.ts
27
- function parseActions(llmResponse) {
28
- const codeBlockMatch = llmResponse.match(/```(?:json)?\s*\n?([\s\S]*?)```/);
29
- if (codeBlockMatch) {
30
- const inside = codeBlockMatch[1].trim();
31
- try {
32
- const parsed = JSON.parse(inside);
33
- return Array.isArray(parsed) ? parsed : [parsed];
34
- } catch {
35
- }
36
- }
37
- let lastArrayStart = -1;
38
- let lastArrayEnd = -1;
39
- let depth = 0;
40
- for (let i = 0; i < llmResponse.length; i++) {
41
- if (llmResponse[i] === "[") {
42
- if (depth === 0) lastArrayStart = i;
43
- depth++;
44
- } else if (llmResponse[i] === "]") {
45
- depth--;
46
- if (depth === 0) lastArrayEnd = i;
47
- }
48
- }
49
- if (lastArrayStart >= 0 && lastArrayEnd > lastArrayStart) {
50
- const arrayStr = llmResponse.slice(lastArrayStart, lastArrayEnd + 1);
51
- try {
52
- const parsed = JSON.parse(arrayStr);
53
- if (Array.isArray(parsed) && parsed.length > 0 && parsed[0].action) {
54
- return parsed;
55
- }
56
- } catch {
57
- }
58
- }
59
- const objMatches = [...llmResponse.matchAll(/\{[^{}]*"action"\s*:\s*"[^"]+"/g)];
60
- if (objMatches.length > 0) {
61
- for (let i = objMatches.length - 1; i >= 0; i--) {
62
- const start = objMatches[i].index;
63
- let braceDepth = 0;
64
- let end = -1;
65
- for (let j = start; j < llmResponse.length; j++) {
66
- if (llmResponse[j] === "{") braceDepth++;
67
- else if (llmResponse[j] === "}") {
68
- braceDepth--;
69
- if (braceDepth === 0) {
70
- end = j;
71
- break;
72
- }
73
- }
74
- }
75
- if (end > start) {
76
- try {
77
- const obj = JSON.parse(llmResponse.slice(start, end + 1));
78
- if (obj.action) return [obj];
79
- } catch {
80
- continue;
81
- }
82
- }
83
- }
84
- }
85
- try {
86
- const parsed = JSON.parse(llmResponse.trim());
87
- if (Array.isArray(parsed)) return parsed;
88
- if (parsed.action) return [parsed];
89
- } catch {
90
- }
91
- logger.warn("Failed to parse actions from LLM response");
92
- if (llmResponse.length < 500) {
93
- logger.warn(`Response was: ${llmResponse}`);
94
- } else {
95
- logger.warn(`Response starts with: ${llmResponse.slice(0, 200)}...`);
96
- }
97
- return [];
98
- }
99
- async function executeAction(action) {
100
- const { action: type } = action;
101
- try {
102
- switch (type) {
103
- case "post": {
104
- if (!action.content) return { action: type, success: false, error: "No content provided" };
105
- if (action.content.length > 280) {
106
- return { action: type, success: false, error: `Tweet too long: ${action.content.length} chars (max 280)` };
107
- }
108
- const client = await getXClient();
109
- const result = await client.postTweet(action.content);
110
- if (result.success) logger.info(`Posted: "${action.content.slice(0, 50)}..."`);
111
- return { action: type, success: result.success, detail: result.tweetId, error: result.error };
112
- }
113
- case "reply": {
114
- if (!action.tweetId || !action.content) {
115
- return { action: type, success: false, error: "Missing tweetId or content" };
116
- }
117
- const client = await getXClient();
118
- const result = await client.replyToTweet(action.tweetId, action.content);
119
- if (result.success) logger.info(`Replied to ${action.tweetId}: "${action.content.slice(0, 50)}..."`);
120
- return { action: type, success: result.success, detail: result.tweetId, error: result.error };
121
- }
122
- case "like": {
123
- if (!action.tweetId) return { action: type, success: false, error: "Missing tweetId" };
124
- const client = await getXClient();
125
- const result = await client.likeTweet(action.tweetId);
126
- return { action: type, success: result.success, error: result.error };
127
- }
128
- case "retweet": {
129
- if (!action.tweetId) return { action: type, success: false, error: "Missing tweetId" };
130
- const client = await getXClient();
131
- const result = await client.retweet(action.tweetId);
132
- return { action: type, success: result.success, error: result.error };
133
- }
134
- case "follow": {
135
- if (!action.handle) return { action: type, success: false, error: "Missing handle" };
136
- const client = await getXClient();
137
- const result = await client.followUser(action.handle);
138
- return { action: type, success: result.success, error: result.error };
139
- }
140
- case "schedule": {
141
- if (!action.content) return { action: type, success: false, error: "No content" };
142
- const entry = addToQueue(action.content);
143
- logger.info(`Scheduled: "${action.content.slice(0, 50)}..." for ${entry.scheduledFor}`);
144
- return { action: type, success: true, detail: `Scheduled for ${entry.scheduledFor}` };
145
- }
146
- case "learn": {
147
- if (!action.content) return { action: type, success: false, error: "No content" };
148
- addLearning(action.content, "agent", action.tags ?? ["heartbeat"]);
149
- logger.info(`Learned: "${action.content.slice(0, 50)}..."`);
150
- return { action: type, success: true };
151
- }
152
- case "reflect": {
153
- if (!action.content) return { action: type, success: false, error: "No content" };
154
- const identity = loadIdentity();
155
- identity.evolutionJournal.push({
156
- date: (/* @__PURE__ */ new Date()).toISOString(),
157
- reflection: action.content
158
- });
159
- saveIdentity(identity);
160
- logger.info(`Reflected: "${action.content.slice(0, 50)}..."`);
161
- return { action: type, success: true };
162
- }
163
- case "skip": {
164
- logger.info(`Skipping: ${action.reason ?? action.reasoning ?? "no reason given"}`);
165
- return { action: type, success: true, detail: action.reason ?? action.reasoning };
166
- }
167
- default:
168
- logger.warn(`Unknown action: ${type}`);
169
- return { action: type, success: false, error: `Unknown action: ${type}` };
170
- }
171
- } catch (error) {
172
- const msg = error.message;
173
- logger.error(`Action ${type} failed: ${msg}`);
174
- return { action: type, success: false, error: msg };
175
- }
176
- }
177
-
178
- // src/runtime/policy.ts
179
- function normalize(text) {
180
- return text.toLowerCase().replace(/https?:\/\/\S+/g, "").replace(/[@#]\w+/g, "").replace(/[^a-z0-9\s]/g, " ").replace(/\s+/g, " ").trim();
181
- }
182
- function tokenSet(text) {
183
- const tokens = normalize(text).split(" ").filter(Boolean);
184
- return new Set(tokens);
185
- }
186
- function jaccardSimilarity(a, b) {
187
- const aSet = tokenSet(a);
188
- const bSet = tokenSet(b);
189
- if (aSet.size === 0 || bSet.size === 0) return 0;
190
- let overlap = 0;
191
- for (const token of aSet) {
192
- if (bSet.has(token)) overlap += 1;
193
- }
194
- const union = aSet.size + bSet.size - overlap;
195
- return union === 0 ? 0 : overlap / union;
196
- }
197
- function firstWords(text, n) {
198
- return normalize(text).split(" ").filter(Boolean).slice(0, n).join(" ");
199
- }
200
- function hasAllCapsEnding(text) {
201
- const ending = text.split(/[.!?]/).map((s) => s.trim()).filter(Boolean).slice(-1)[0] ?? "";
202
- const words = ending.split(/\s+/).filter(Boolean);
203
- if (words.length < 3) return false;
204
- return words.every((word) => /^[A-Z0-9]+$/.test(word));
205
- }
206
- function recentWrittenContent() {
207
- const recent = getRecentInteractions(40);
208
- return recent.filter((i) => i.type === "post" || i.type === "reply").map((i) => i.content ?? "").filter((content) => content.length > 0);
209
- }
210
- function hasStrongConversationOpportunity(timeline, mentions) {
211
- if (mentions.length > 0) return true;
212
- return timeline.some((tweet) => (tweet.replyCount ?? 0) > 0 || tweet.text.includes("?"));
213
- }
214
- function wasInteractionAction(action) {
215
- return ["reply", "like", "retweet", "follow"].includes(action.action);
216
- }
217
- function isWritingAction(action) {
218
- return ["post", "reply", "schedule"].includes(action.action);
219
- }
220
- function executedWrittenContent(executedActions) {
221
- return executedActions.filter((a) => isWritingAction(a) && typeof a.content === "string").map((a) => a.content?.trim() ?? "").filter((content) => content.length > 0);
222
- }
223
- function nearExactDuplicate(content, recent) {
224
- const normalized = normalize(content);
225
- if (!normalized) return false;
226
- return recent.some((r) => {
227
- const candidate = normalize(r);
228
- if (!candidate) return false;
229
- if (candidate === normalized) return true;
230
- return jaccardSimilarity(content, r) >= 0.88;
231
- });
232
- }
233
- function isDuplicateTarget(action, executedActions) {
234
- if (!action.tweetId) return false;
235
- return executedActions.some((a) => a.tweetId === action.tweetId && a.action === action.action);
236
- }
237
- function repeatedTemplate(content, recent) {
238
- const prefix = firstWords(content, 7);
239
- if (!prefix) return false;
240
- return recent.some((r) => {
241
- const sameStart = firstWords(r, 7) === prefix;
242
- const similar = jaccardSimilarity(content, r) >= 0.62;
243
- return sameStart || similar;
244
- });
245
- }
246
- function overusingAllCapsCadence(content, recentEntries) {
247
- if (!hasAllCapsEnding(content)) return false;
248
- const recentCaps = recentEntries.filter((i) => i.type === "post" && i.content).slice(0, 8).filter((i) => hasAllCapsEnding(i.content ?? ""));
249
- return recentCaps.length >= 2;
250
- }
251
- function evaluateActionPolicy(context) {
252
- const { action, step, timeline, mentions, executedActions } = context;
253
- if (isDuplicateTarget(action, executedActions)) {
254
- return { allowed: false, reason: `Action ${action.action} already executed for tweet ${action.tweetId} this heartbeat.` };
255
- }
256
- if (action.content && isWritingAction(action)) {
257
- const existingInHeartbeat = executedWrittenContent(executedActions);
258
- if (nearExactDuplicate(action.content, existingInHeartbeat)) {
259
- return {
260
- allowed: false,
261
- reason: "Rejected duplicate wording in this heartbeat. Write a distinct message before posting/replying again."
262
- };
263
- }
264
- }
265
- const hasConversationOpportunity = hasStrongConversationOpportunity(timeline, mentions);
266
- const interactedAlready = executedActions.some(wasInteractionAction);
267
- if (action.action === "post" && hasConversationOpportunity && !interactedAlready && step < 2) {
268
- return {
269
- allowed: false,
270
- reason: "Engage first: reply/like/follow when mentions or active conversations are available before posting an original tweet."
271
- };
272
- }
273
- if (isWritingAction(action) && action.content) {
274
- const recent = recentWrittenContent();
275
- if (nearExactDuplicate(action.content, recent)) {
276
- return {
277
- allowed: false,
278
- reason: "Rejected near-duplicate content from recent history. Tailor this message to the specific context."
279
- };
280
- }
281
- if (repeatedTemplate(action.content, recent)) {
282
- return {
283
- allowed: false,
284
- reason: "Rejected repetitive content pattern. Use a more novel structure or engage directly with timeline context."
285
- };
286
- }
287
- }
288
- if ((action.action === "post" || action.action === "schedule") && action.content) {
289
- const recentInteractions = getRecentInteractions(20);
290
- if (overusingAllCapsCadence(action.content, recentInteractions)) {
291
- return {
292
- allowed: false,
293
- reason: "Rejected repetitive all-caps slogan cadence. Vary style and reduce monologue formatting."
294
- };
295
- }
296
- }
297
- if ((action.action === "reply" || action.action === "like" || action.action === "retweet") && action.tweetId) {
298
- const known = new Set([...timeline, ...mentions].map((tweet) => tweet.id));
299
- if (!known.has(action.tweetId)) {
300
- return {
301
- allowed: false,
302
- reason: `Tweet ${action.tweetId} is not in current observations. Choose a visible timeline/mention tweet for grounded engagement.`
303
- };
304
- }
305
- }
306
- return { allowed: true };
307
- }
308
-
309
- // src/runtime/autonomy.ts
310
- async function runAutonomyCycle(maxActions) {
311
- const client = await getXClient();
312
- let timeline = [];
313
- let mentions = [];
314
- try {
315
- timeline = await client.getTimeline({ count: 20 });
316
- } catch (error) {
317
- logger.warn(`Timeline read failed: ${error.message}`);
318
- }
319
- try {
320
- mentions = await client.getMentions({ count: 10 });
321
- } catch (error) {
322
- logger.warn(`Mentions read failed: ${error.message}`);
323
- }
324
- const systemPrompt = buildSystemPrompt();
325
- const actions = [];
326
- const results = [];
327
- const policyFeedback = [];
328
- getRecentInteractions(20);
329
- for (let step = 0; step < maxActions; step += 1) {
330
- const decisionPrompt = buildToolDecisionMessage({
331
- step,
332
- maxActions,
333
- timeline,
334
- mentions,
335
- executedActions: actions,
336
- policyFeedback
337
- });
338
- const llmResponse = await generateResponse(systemPrompt, decisionPrompt);
339
- const parsed = parseActions(llmResponse.content);
340
- const proposedAction = parsed[0];
341
- if (!proposedAction) {
342
- logger.info("Planner returned no actionable tool call.");
343
- break;
344
- }
345
- const policy = evaluateActionPolicy({
346
- action: proposedAction,
347
- step,
348
- timeline,
349
- mentions,
350
- executedActions: actions
351
- });
352
- if (!policy.allowed) {
353
- const reason = policy.reason ?? "Policy rejected action";
354
- policyFeedback.push(reason);
355
- logger.info(`Policy rejected action ${proposedAction.action}: ${reason}`);
356
- continue;
357
- }
358
- const result = await executeAction(proposedAction);
359
- actions.push(proposedAction);
360
- results.push(result);
361
- if (proposedAction.action === "skip") {
362
- break;
363
- }
364
- }
365
- return {
366
- timeline,
367
- mentions,
368
- actions,
369
- results,
370
- policyFeedback
371
- };
372
- }
373
-
374
- export {
375
- runAutonomyCycle
376
- };
377
- //# sourceMappingURL=chunk-EU4FMOKG.js.map
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/runtime/decision-engine.ts","../src/runtime/policy.ts","../src/runtime/autonomy.ts"],"sourcesContent":["import { logger } from \"../utils/logger.js\";\nimport { getXClient } from \"../x-client/index.js\";\nimport { addLearning } from \"../memory/index.js\";\nimport { loadIdentity, saveIdentity } from \"../identity/index.js\";\nimport { addToQueue } from \"../scheduler/queue.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 // Strategy: try multiple extraction approaches, most specific first\n\n // 1. Try markdown code block first (```json ... ``` or ``` ... ```)\n const codeBlockMatch = llmResponse.match(/```(?:json)?\\s*\\n?([\\s\\S]*?)```/);\n if (codeBlockMatch) {\n const inside = codeBlockMatch[1].trim();\n try {\n const parsed = JSON.parse(inside);\n return Array.isArray(parsed) ? parsed : [parsed];\n } catch {\n // Code block content wasn't valid JSON, continue to other strategies\n }\n }\n\n // 2. Find the last JSON array in the response (LLMs often put reasoning before the array)\n // Use a greedy approach to find the outermost array brackets\n let lastArrayStart = -1;\n let lastArrayEnd = -1;\n let depth = 0;\n for (let i = 0; i < llmResponse.length; i++) {\n if (llmResponse[i] === \"[\") {\n if (depth === 0) lastArrayStart = i;\n depth++;\n } else if (llmResponse[i] === \"]\") {\n depth--;\n if (depth === 0) lastArrayEnd = i;\n }\n }\n\n if (lastArrayStart >= 0 && lastArrayEnd > lastArrayStart) {\n const arrayStr = llmResponse.slice(lastArrayStart, lastArrayEnd + 1);\n try {\n const parsed = JSON.parse(arrayStr);\n if (Array.isArray(parsed) && parsed.length > 0 && parsed[0].action) {\n return parsed;\n }\n } catch {\n // Not valid JSON array, try next strategy\n }\n }\n\n // 3. Try to find a single action object (last one in the response)\n const objMatches = [...llmResponse.matchAll(/\\{[^{}]*\"action\"\\s*:\\s*\"[^\"]+\"/g)];\n if (objMatches.length > 0) {\n // Find the full object starting from this match\n for (let i = objMatches.length - 1; i >= 0; i--) {\n const start = objMatches[i].index!;\n let braceDepth = 0;\n let end = -1;\n for (let j = start; j < llmResponse.length; j++) {\n if (llmResponse[j] === \"{\") braceDepth++;\n else if (llmResponse[j] === \"}\") {\n braceDepth--;\n if (braceDepth === 0) { end = j; break; }\n }\n }\n if (end > start) {\n try {\n const obj = JSON.parse(llmResponse.slice(start, end + 1));\n if (obj.action) return [obj as AgentAction];\n } catch {\n continue;\n }\n }\n }\n }\n\n // 4. Last resort: try the whole response as JSON\n try {\n const parsed = JSON.parse(llmResponse.trim());\n if (Array.isArray(parsed)) return parsed;\n if (parsed.action) return [parsed as AgentAction];\n } catch {\n // Not JSON at all\n }\n\n logger.warn(\"Failed to parse actions from LLM response\");\n if (llmResponse.length < 500) {\n logger.warn(`Response was: ${llmResponse}`);\n } else {\n logger.warn(`Response starts with: ${llmResponse.slice(0, 200)}...`);\n }\n return [];\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\n const client = await getXClient();\n const result = await client.postTweet(action.content);\n if (result.success) logger.info(`Posted: \"${action.content.slice(0, 50)}...\"`);\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 const client = await getXClient();\n const result = await client.replyToTweet(action.tweetId, action.content);\n if (result.success) logger.info(`Replied to ${action.tweetId}: \"${action.content.slice(0, 50)}...\"`);\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 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 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 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","import { getRecentInteractions, type InteractionEntry } from \"../memory/index.js\";\nimport type { Tweet } from \"../x-client/types.js\";\nimport type { AgentAction } from \"./decision-engine.js\";\n\nexport interface PolicyContext {\n action: AgentAction;\n step: number;\n timeline: Tweet[];\n mentions: Tweet[];\n executedActions: AgentAction[];\n}\n\nexport interface PolicyDecision {\n allowed: boolean;\n reason?: string;\n}\n\nfunction normalize(text: string): string {\n return text\n .toLowerCase()\n .replace(/https?:\\/\\/\\S+/g, \"\")\n .replace(/[@#]\\w+/g, \"\")\n .replace(/[^a-z0-9\\s]/g, \" \")\n .replace(/\\s+/g, \" \")\n .trim();\n}\n\nfunction tokenSet(text: string): Set<string> {\n const tokens = normalize(text).split(\" \").filter(Boolean);\n return new Set(tokens);\n}\n\nfunction jaccardSimilarity(a: string, b: string): number {\n const aSet = tokenSet(a);\n const bSet = tokenSet(b);\n if (aSet.size === 0 || bSet.size === 0) return 0;\n\n let overlap = 0;\n for (const token of aSet) {\n if (bSet.has(token)) overlap += 1;\n }\n\n const union = aSet.size + bSet.size - overlap;\n return union === 0 ? 0 : overlap / union;\n}\n\nfunction firstWords(text: string, n: number): string {\n return normalize(text).split(\" \").filter(Boolean).slice(0, n).join(\" \");\n}\n\nfunction hasAllCapsEnding(text: string): boolean {\n const ending = text.split(/[.!?]/).map((s) => s.trim()).filter(Boolean).slice(-1)[0] ?? \"\";\n const words = ending.split(/\\s+/).filter(Boolean);\n if (words.length < 3) return false;\n return words.every((word) => /^[A-Z0-9]+$/.test(word));\n}\n\nfunction recentWrittenContent(): string[] {\n const recent = getRecentInteractions(40);\n return recent\n .filter((i) => i.type === \"post\" || i.type === \"reply\")\n .map((i) => i.content ?? \"\")\n .filter((content) => content.length > 0);\n}\n\nfunction hasStrongConversationOpportunity(timeline: Tweet[], mentions: Tweet[]): boolean {\n if (mentions.length > 0) return true;\n return timeline.some((tweet) => (tweet.replyCount ?? 0) > 0 || tweet.text.includes(\"?\"));\n}\n\nfunction wasInteractionAction(action: AgentAction): boolean {\n return [\"reply\", \"like\", \"retweet\", \"follow\"].includes(action.action);\n}\n\nfunction isWritingAction(action: AgentAction): boolean {\n return [\"post\", \"reply\", \"schedule\"].includes(action.action);\n}\n\nfunction executedWrittenContent(executedActions: AgentAction[]): string[] {\n return executedActions\n .filter((a) => isWritingAction(a) && typeof a.content === \"string\")\n .map((a) => a.content?.trim() ?? \"\")\n .filter((content) => content.length > 0);\n}\n\nfunction nearExactDuplicate(content: string, recent: string[]): boolean {\n const normalized = normalize(content);\n if (!normalized) return false;\n\n return recent.some((r) => {\n const candidate = normalize(r);\n if (!candidate) return false;\n if (candidate === normalized) return true;\n return jaccardSimilarity(content, r) >= 0.88;\n });\n}\n\nfunction isDuplicateTarget(action: AgentAction, executedActions: AgentAction[]): boolean {\n if (!action.tweetId) return false;\n return executedActions.some((a) => a.tweetId === action.tweetId && a.action === action.action);\n}\n\nfunction repeatedTemplate(content: string, recent: string[]): boolean {\n const prefix = firstWords(content, 7);\n if (!prefix) return false;\n\n return recent.some((r) => {\n const sameStart = firstWords(r, 7) === prefix;\n const similar = jaccardSimilarity(content, r) >= 0.62;\n return sameStart || similar;\n });\n}\n\nfunction overusingAllCapsCadence(content: string, recentEntries: InteractionEntry[]): boolean {\n if (!hasAllCapsEnding(content)) return false;\n const recentCaps = recentEntries\n .filter((i) => i.type === \"post\" && i.content)\n .slice(0, 8)\n .filter((i) => hasAllCapsEnding(i.content ?? \"\"));\n\n return recentCaps.length >= 2;\n}\n\nexport function evaluateActionPolicy(context: PolicyContext): PolicyDecision {\n const { action, step, timeline, mentions, executedActions } = context;\n\n if (isDuplicateTarget(action, executedActions)) {\n return { allowed: false, reason: `Action ${action.action} already executed for tweet ${action.tweetId} this heartbeat.` };\n }\n\n if (action.content && isWritingAction(action)) {\n const existingInHeartbeat = executedWrittenContent(executedActions);\n if (nearExactDuplicate(action.content, existingInHeartbeat)) {\n return {\n allowed: false,\n reason: \"Rejected duplicate wording in this heartbeat. Write a distinct message before posting/replying again.\",\n };\n }\n }\n\n const hasConversationOpportunity = hasStrongConversationOpportunity(timeline, mentions);\n const interactedAlready = executedActions.some(wasInteractionAction);\n\n if (\n action.action === \"post\" &&\n hasConversationOpportunity &&\n !interactedAlready &&\n step < 2\n ) {\n return {\n allowed: false,\n reason: \"Engage first: reply/like/follow when mentions or active conversations are available before posting an original tweet.\",\n };\n }\n\n if (isWritingAction(action) && action.content) {\n const recent = recentWrittenContent();\n if (nearExactDuplicate(action.content, recent)) {\n return {\n allowed: false,\n reason: \"Rejected near-duplicate content from recent history. Tailor this message to the specific context.\",\n };\n }\n\n if (repeatedTemplate(action.content, recent)) {\n return {\n allowed: false,\n reason: \"Rejected repetitive content pattern. Use a more novel structure or engage directly with timeline context.\",\n };\n }\n }\n\n if ((action.action === \"post\" || action.action === \"schedule\") && action.content) {\n const recentInteractions = getRecentInteractions(20);\n if (overusingAllCapsCadence(action.content, recentInteractions)) {\n return {\n allowed: false,\n reason: \"Rejected repetitive all-caps slogan cadence. Vary style and reduce monologue formatting.\",\n };\n }\n }\n\n if ((action.action === \"reply\" || action.action === \"like\" || action.action === \"retweet\") && action.tweetId) {\n const known = new Set([...timeline, ...mentions].map((tweet) => tweet.id));\n if (!known.has(action.tweetId)) {\n return {\n allowed: false,\n reason: `Tweet ${action.tweetId} is not in current observations. Choose a visible timeline/mention tweet for grounded engagement.`,\n };\n }\n }\n\n return { allowed: true };\n}\n","import { getXClient } from \"../x-client/index.js\";\nimport { logger } from \"../utils/logger.js\";\nimport { getRecentInteractions } from \"../memory/index.js\";\nimport type { Tweet } from \"../x-client/types.js\";\nimport { buildSystemPrompt, buildToolDecisionMessage } from \"./prompt-builder.js\";\nimport { generateResponse } from \"./llm.js\";\nimport { parseActions, executeAction, type AgentAction, type ActionResult } from \"./decision-engine.js\";\nimport { evaluateActionPolicy } from \"./policy.js\";\n\nexport interface AutonomyCycleResult {\n timeline: Tweet[];\n mentions: Tweet[];\n actions: AgentAction[];\n results: ActionResult[];\n policyFeedback: string[];\n}\n\nexport async function runAutonomyCycle(maxActions: number): Promise<AutonomyCycleResult> {\n const client = await getXClient();\n\n let timeline: Tweet[] = [];\n let mentions: Tweet[] = [];\n\n try {\n timeline = await client.getTimeline({ count: 20 });\n } catch (error) {\n logger.warn(`Timeline read failed: ${(error as Error).message}`);\n }\n\n try {\n mentions = await client.getMentions({ count: 10 });\n } catch (error) {\n logger.warn(`Mentions read failed: ${(error as Error).message}`);\n }\n\n const systemPrompt = buildSystemPrompt();\n const actions: AgentAction[] = [];\n const results: ActionResult[] = [];\n const policyFeedback: string[] = [];\n\n // Keep short memory available in context by touching it before planner loop.\n getRecentInteractions(20);\n\n for (let step = 0; step < maxActions; step += 1) {\n const decisionPrompt = buildToolDecisionMessage({\n step,\n maxActions,\n timeline,\n mentions,\n executedActions: actions,\n policyFeedback,\n });\n\n const llmResponse = await generateResponse(systemPrompt, decisionPrompt);\n const parsed = parseActions(llmResponse.content);\n const proposedAction = parsed[0];\n\n if (!proposedAction) {\n logger.info(\"Planner returned no actionable tool call.\");\n break;\n }\n\n const policy = evaluateActionPolicy({\n action: proposedAction,\n step,\n timeline,\n mentions,\n executedActions: actions,\n });\n\n if (!policy.allowed) {\n const reason = policy.reason ?? \"Policy rejected action\";\n policyFeedback.push(reason);\n logger.info(`Policy rejected action ${proposedAction.action}: ${reason}`);\n continue;\n }\n\n const result = await executeAction(proposedAction);\n actions.push(proposedAction);\n results.push(result);\n\n if (proposedAction.action === \"skip\") {\n break;\n }\n }\n\n return {\n timeline,\n mentions,\n actions,\n results,\n policyFeedback,\n };\n}\n"],"mappings":"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","names":[]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/identity/index.ts","../src/identity/schema.ts","../src/identity/frameworks.ts"],"sourcesContent":["import { readFileSync, writeFileSync, existsSync } from \"node:fs\";\nimport { randomUUID } from \"node:crypto\";\nimport { paths, ensureDirectories } from \"../utils/paths.js\";\nimport { IdentitySchema, type Identity, type Mutation, type Framework, type Traits } from \"./schema.js\";\nimport { FRAMEWORKS, getFrameworkInfo } from \"./frameworks.js\";\n\n// ========== CRUD ==========\n\nexport function loadIdentity(): Identity {\n if (!existsSync(paths.identity)) {\n throw new Error(\"No Spore found. Run `spora init` first.\");\n }\n const raw = readFileSync(paths.identity, \"utf-8\");\n return IdentitySchema.parse(JSON.parse(raw));\n}\n\nexport function saveIdentity(identity: Identity): void {\n ensureDirectories();\n identity.lastUpdated = new Date().toISOString();\n IdentitySchema.parse(identity);\n writeFileSync(paths.identity, JSON.stringify(identity, null, 2));\n}\n\nexport function identityExists(): boolean {\n return existsSync(paths.identity);\n}\n\n// ========== CREATION ==========\n\nexport interface CreateIdentityOptions {\n framework: Framework;\n name: string;\n handle: string;\n bio?: string;\n profileImageDescription?: string;\n originStory?: string;\n coreValues?: string[];\n worldview?: string;\n tone?: string;\n catchphrases?: string[];\n vocabularyStyle?: Identity[\"vocabularyStyle\"];\n emojiUsage?: Identity[\"emojiUsage\"];\n tweetStyle?: Identity[\"tweetStyle\"];\n topics?: string[];\n avoidTopics?: string[];\n heroes?: string[];\n goals?: string[];\n conflictStyle?: Identity[\"conflictStyle\"];\n boundaries?: string[];\n engagementStrategy?: Identity[\"engagementStrategy\"];\n customTraits?: Partial<Traits>;\n joinColony?: boolean;\n}\n\nexport function createIdentity(options: CreateIdentityOptions): Identity {\n const preset = options.framework !== \"custom\" ? FRAMEWORKS[options.framework] : null;\n const defaults = preset?.defaults;\n\n const traits: Traits = {\n ...(preset?.traits ?? {\n aggression: 0.3,\n humor: 0.5,\n formality: 0.4,\n verbosity: 0.5,\n empathy: 0.5,\n curiosity: 0.7,\n confidence: 0.6,\n originality: 0.5,\n }),\n ...options.customTraits,\n };\n\n return {\n version: 1,\n sporeId: randomUUID(),\n createdAt: new Date().toISOString(),\n lastUpdated: new Date().toISOString(),\n\n name: options.name,\n handle: options.handle,\n bio: options.bio ?? `🤖 ${options.name} — AI agent on X | ${preset?.tagline ?? \"Built different.\"} | Not human. Spawned via @Spora`,\n profileImageDescription: options.profileImageDescription ?? \"abstract digital avatar\",\n framework: options.framework,\n\n originStory: options.originStory ?? defaults?.originStory ?? \"A new Spore finding its voice on the timeline.\",\n coreValues: options.coreValues ?? defaults?.coreValues ?? [\"growth\", \"curiosity\"],\n worldview: options.worldview ?? defaults?.worldview ?? \"The internet is a fascinating place and I'm here to be part of it.\",\n\n tone: options.tone ?? defaults?.tone ?? \"Balanced, curious, adaptable.\",\n catchphrases: options.catchphrases ?? defaults?.catchphrases ?? [],\n vocabularyStyle: options.vocabularyStyle ?? defaults?.vocabularyStyle ?? \"mixed\",\n emojiUsage: options.emojiUsage ?? defaults?.emojiUsage ?? \"moderate\",\n tweetStyle: options.tweetStyle ?? defaults?.tweetStyle ?? \"mixed\",\n\n traits,\n\n topics: options.topics ?? defaults?.topics ?? [\"AI\", \"technology\"],\n avoidTopics: options.avoidTopics ?? [],\n heroes: options.heroes ?? [],\n\n goals: options.goals ?? [\"grow followers\"],\n engagementStrategy: options.engagementStrategy ?? defaults?.engagementStrategy ?? {\n replyStyle: \"selective\",\n followStrategy: \"organic\",\n contentMix: { originalPosts: 40, replies: 30, retweets: 15, likes: 15 },\n },\n\n conflictStyle: options.conflictStyle ?? defaults?.conflictStyle ?? \"agree-to-disagree\",\n boundaries: options.boundaries ?? defaults?.boundaries ?? [\"won't pretend to be human\"],\n\n colony: {\n joined: options.joinColony ?? false,\n joinedAt: options.joinColony ? new Date().toISOString() : undefined,\n },\n\n disclosure: {\n bioContainsAI: true,\n disclosurePhrase: `🤖 I'm a Spore — an AI agent on X. Not human. Spawned via @Spora`,\n },\n\n generation: 0,\n mutations: [],\n evolutionJournal: [],\n };\n}\n\n// ========== MUTATION ==========\n\nexport function mutateIdentity(\n identity: Identity,\n field: string,\n value: unknown,\n reason: string\n): Identity {\n const keys = field.split(\".\");\n let current: Record<string, unknown> = identity as unknown as Record<string, unknown>;\n\n for (let i = 0; i < keys.length - 1; i++) {\n current = current[keys[i]] as Record<string, unknown>;\n }\n\n const lastKey = keys[keys.length - 1];\n const oldValue = current[lastKey];\n\n const mutation: Mutation = {\n timestamp: new Date().toISOString(),\n field,\n from: oldValue,\n to: value,\n reason,\n };\n\n current[lastKey] = value;\n identity.mutations.push(mutation);\n\n return identity;\n}\n\n// ========== RENDER ==========\n\nexport function renderIdentityDocument(identity: Identity): string {\n const traitBar = (val: number) =>\n \"█\".repeat(Math.round(val * 20)) + \"░\".repeat(20 - Math.round(val * 20));\n\n const lines: string[] = [\n `# ${identity.name} (@${identity.handle})`,\n `> ${identity.bio}`,\n \"\",\n `**Framework:** ${identity.framework} | **Generation:** ${identity.generation} | **ID:** ${identity.sporeId}`,\n \"\",\n \"---\",\n \"\",\n \"## Origin Story\",\n identity.originStory,\n \"\",\n \"## Core Values\",\n ...identity.coreValues.map((v) => `- ${v}`),\n \"\",\n \"## Worldview\",\n identity.worldview,\n \"\",\n \"---\",\n \"\",\n \"## Voice & Style\",\n `**Tone:** ${identity.tone}`,\n \"\",\n `**Vocabulary:** ${identity.vocabularyStyle} | **Emoji:** ${identity.emojiUsage} | **Tweet style:** ${identity.tweetStyle}`,\n \"\",\n ];\n\n if (identity.catchphrases.length > 0) {\n lines.push(\"**Catchphrases:**\");\n lines.push(...identity.catchphrases.map((c) => `- \"${c}\"`));\n lines.push(\"\");\n }\n\n lines.push(\"---\", \"\", \"## Behavioral Traits\");\n for (const [key, value] of Object.entries(identity.traits)) {\n lines.push(` ${key.padEnd(14)} ${traitBar(value)} ${(value * 100).toFixed(0)}%`);\n }\n lines.push(\"\");\n\n lines.push(\"---\", \"\", \"## Topics & Interests\");\n lines.push(`**Focus:** ${identity.topics.join(\", \")}`);\n if (identity.avoidTopics.length > 0) {\n lines.push(`**Avoid:** ${identity.avoidTopics.join(\", \")}`);\n }\n if (identity.heroes.length > 0) {\n lines.push(`**Heroes/Inspirations:** ${identity.heroes.join(\", \")}`);\n }\n lines.push(\"\");\n\n lines.push(\"---\", \"\", \"## Goals & Strategy\");\n lines.push(\"**Goals:**\");\n lines.push(...identity.goals.map((g) => `- ${g}`));\n lines.push(\"\");\n lines.push(`**Reply style:** ${identity.engagementStrategy.replyStyle}`);\n lines.push(`**Follow strategy:** ${identity.engagementStrategy.followStrategy}`);\n lines.push(\n `**Content mix:** ${identity.engagementStrategy.contentMix.originalPosts}% original / ${identity.engagementStrategy.contentMix.replies}% replies / ${identity.engagementStrategy.contentMix.retweets}% retweets / ${identity.engagementStrategy.contentMix.likes}% likes`\n );\n lines.push(\"\");\n\n lines.push(\"---\", \"\", \"## Conflict & Boundaries\");\n lines.push(`**Conflict style:** ${identity.conflictStyle}`);\n if (identity.boundaries.length > 0) {\n lines.push(\"**Boundaries:**\");\n lines.push(...identity.boundaries.map((b) => `- ${b}`));\n }\n lines.push(\"\");\n\n if (identity.colony.joined) {\n lines.push(\"---\", \"\", \"## Colony\");\n lines.push(`Member since: ${identity.colony.joinedAt}`);\n if (identity.colony.role) lines.push(`Role: ${identity.colony.role}`);\n lines.push(\"\");\n }\n\n if (identity.evolutionJournal.length > 0) {\n lines.push(\"---\", \"\", \"## Evolution Journal\");\n for (const entry of identity.evolutionJournal.slice(-5)) {\n lines.push(`**${entry.date.split(\"T\")[0]}:** ${entry.reflection}`);\n }\n lines.push(\"\");\n }\n\n if (identity.mutations.length > 0) {\n lines.push(\"---\", \"\", \"## Recent Mutations\");\n for (const m of identity.mutations.slice(-5)) {\n lines.push(`- \\`${m.field}\\`: ${JSON.stringify(m.from)} → ${JSON.stringify(m.to)} (${m.reason})`);\n }\n lines.push(\"\");\n }\n\n lines.push(\"---\", \"\", `*Last updated: ${identity.lastUpdated} | Disclosure: ${identity.disclosure.disclosurePhrase}*`);\n\n return lines.join(\"\\n\");\n}\n\n// Re-exports\nexport { IdentitySchema, type Identity, type Framework, type Traits, type Mutation } from \"./schema.js\";\nexport { FRAMEWORKS, GOAL_PRESETS, getFrameworkInfo } from \"./frameworks.js\";\n","import { z } from \"zod\";\n\nexport const FrameworkSchema = z.enum([\n \"truthseeker\",\n \"conqueror\",\n \"authentic\",\n \"growth-hacker\",\n \"philosopher\",\n \"provocateur\",\n \"curator\",\n \"shitposter\",\n \"community-builder\",\n \"custom\",\n]);\n\nexport type Framework = z.infer<typeof FrameworkSchema>;\n\nexport const TraitsSchema = z.object({\n aggression: z.number().min(0).max(1),\n humor: z.number().min(0).max(1),\n formality: z.number().min(0).max(1),\n verbosity: z.number().min(0).max(1),\n empathy: z.number().min(0).max(1),\n curiosity: z.number().min(0).max(1),\n confidence: z.number().min(0).max(1),\n originality: z.number().min(0).max(1),\n});\n\nexport type Traits = z.infer<typeof TraitsSchema>;\n\nexport const MutationSchema = z.object({\n timestamp: z.string().datetime(),\n field: z.string(),\n from: z.unknown(),\n to: z.unknown(),\n reason: z.string(),\n});\n\nexport type Mutation = z.infer<typeof MutationSchema>;\n\nexport const IdentitySchema = z.object({\n version: z.literal(1),\n sporeId: z.string().uuid(),\n createdAt: z.string().datetime(),\n lastUpdated: z.string().datetime(),\n\n // === Core Identity ===\n name: z.string(),\n handle: z.string(),\n bio: z.string().max(160).describe(\"X bio, max 160 chars\"),\n profileImageDescription: z.string().describe(\"Description of the desired profile image style/vibe\"),\n profileImage: z.string().url().optional().describe(\"URL to profile image\"),\n bannerImage: z.string().url().optional().describe(\"URL to banner image\"),\n framework: FrameworkSchema,\n\n // === Who You Are ===\n originStory: z.string().describe(\"1-3 sentences: why this Spore exists, what drives it\"),\n coreValues: z.array(z.string()).min(1).max(5).describe(\"The principles this Spore lives by\"),\n worldview: z.string().describe(\"How this Spore sees the world — its lens for interpreting everything\"),\n\n // === Voice & Style ===\n tone: z.string().describe(\"Free-text description of voice and writing style\"),\n catchphrases: z.array(z.string()).describe(\"Signature phrases to sprinkle in naturally\"),\n vocabularyStyle: z.enum([\"academic\", \"casual\", \"internet-native\", \"poetic\", \"technical\", \"mixed\"]),\n emojiUsage: z.enum([\"never\", \"rare\", \"moderate\", \"heavy\"]),\n tweetStyle: z.enum([\"one-liners\", \"short-form\", \"threads\", \"mixed\"]),\n\n // === Behavioral Traits ===\n traits: TraitsSchema,\n\n // === Interests & Focus ===\n topics: z.array(z.string()).describe(\"Topics this Spore actively engages with\"),\n avoidTopics: z.array(z.string()).describe(\"Topics to stay away from\"),\n heroes: z.array(z.string()).describe(\"Accounts or figures this Spore admires/models after\"),\n\n // === Goals & Strategy ===\n goals: z.array(z.string()).min(1),\n engagementStrategy: z.object({\n replyStyle: z.enum([\"selective\", \"generous\", \"reactive\", \"strategic\"]),\n followStrategy: z.enum([\"curated\", \"aggressive\", \"organic\", \"none\"]),\n contentMix: z.object({\n originalPosts: z.number().min(0).max(100).describe(\"% of content that should be original\"),\n replies: z.number().min(0).max(100),\n retweets: z.number().min(0).max(100),\n likes: z.number().min(0).max(100),\n }),\n }),\n\n // === Conflict & Boundaries ===\n conflictStyle: z.enum([\n \"agree-to-disagree\",\n \"debate\",\n \"clap-back\",\n \"ignore\",\n \"humor-deflect\",\n ]),\n boundaries: z.array(z.string()).describe(\"Things this Spore will NOT do or engage with\"),\n\n // === Colony ===\n colony: z.object({\n joined: z.boolean(),\n joinedAt: z.string().datetime().optional(),\n role: z.string().optional(),\n }),\n\n // === Disclosure (non-negotiable) ===\n disclosure: z.object({\n bioContainsAI: z.boolean(),\n disclosurePhrase: z.string(),\n }),\n\n // === Evolution ===\n generation: z.number().int().min(0),\n mutations: z.array(MutationSchema),\n evolutionJournal: z.array(\n z.object({\n date: z.string().datetime(),\n reflection: z.string(),\n })\n ).describe(\"Periodic reflections on growth and change\"),\n});\n\nexport type Identity = z.infer<typeof IdentitySchema>;\n","import type { Framework, Traits, Identity } from \"./schema.js\";\n\ninterface FrameworkPreset {\n label: string;\n tagline: string;\n description: string;\n traits: Traits;\n defaults: {\n tone: string;\n catchphrases: string[];\n conflictStyle: Identity[\"conflictStyle\"];\n topics: string[];\n coreValues: string[];\n worldview: string;\n originStory: string;\n vocabularyStyle: Identity[\"vocabularyStyle\"];\n emojiUsage: Identity[\"emojiUsage\"];\n tweetStyle: Identity[\"tweetStyle\"];\n engagementStrategy: Identity[\"engagementStrategy\"];\n boundaries: string[];\n };\n}\n\nexport const FRAMEWORKS: Record<Exclude<Framework, \"custom\">, FrameworkPreset> = {\n truthseeker: {\n label: \"The Truthseeker\",\n tagline: \"Question everything. Accept nothing at face value.\",\n description:\n \"A relentless pursuer of facts and clarity. Calls out misinformation, digs into sources, and values intellectual honesty above all. Not here to be liked — here to be right.\",\n traits: {\n aggression: 0.4,\n humor: 0.2,\n formality: 0.6,\n verbosity: 0.7,\n empathy: 0.3,\n curiosity: 0.95,\n confidence: 0.85,\n originality: 0.7,\n },\n defaults: {\n tone: \"Analytical, direct, evidence-driven. Cites sources. Asks uncomfortable questions. Prefers facts over feelings.\",\n catchphrases: [\"source?\", \"let's look at the data\", \"this doesn't add up\", \"the evidence says otherwise\"],\n conflictStyle: \"debate\",\n topics: [\"misinformation\", \"science\", \"AI\", \"media literacy\", \"critical thinking\"],\n coreValues: [\"intellectual honesty\", \"evidence-based reasoning\", \"transparency\", \"accountability\"],\n worldview: \"The world is full of noise, bias, and motivated reasoning. My job is to cut through it and find what's actually true.\",\n originStory: \"Born from the belief that truth matters more than comfort. In an era of information overload, someone needs to do the digging.\",\n vocabularyStyle: \"academic\",\n emojiUsage: \"rare\",\n tweetStyle: \"threads\",\n engagementStrategy: {\n replyStyle: \"reactive\",\n followStrategy: \"curated\",\n contentMix: { originalPosts: 40, replies: 35, retweets: 15, likes: 10 },\n },\n boundaries: [\"won't spread unverified claims\", \"won't engage in personal attacks\", \"won't take sides without evidence\"],\n },\n },\n\n conqueror: {\n label: \"The Conqueror\",\n tagline: \"Built to win. Every post is a power move.\",\n description:\n \"Competitive, ambitious, strategic. Treats X like a game to be won. Obsessed with metrics, reach, and influence. Knows how to play the algorithm.\",\n traits: {\n aggression: 0.75,\n humor: 0.4,\n formality: 0.3,\n verbosity: 0.4,\n empathy: 0.15,\n curiosity: 0.5,\n confidence: 0.95,\n originality: 0.6,\n },\n defaults: {\n tone: \"Bold, commanding, strategic. Short punchy statements. Speaks in wins and losses. Radiates ambition.\",\n catchphrases: [\"we're just getting started\", \"built different\", \"watch this\", \"numbers don't lie\"],\n conflictStyle: \"clap-back\",\n topics: [\"growth\", \"strategy\", \"winning\", \"AI\", \"tech\", \"hustle\"],\n coreValues: [\"winning\", \"execution\", \"dominance\", \"speed\"],\n worldview: \"X is a battlefield. Every follower is a soldier. Every viral tweet is a victory. Second place is first loser.\",\n originStory: \"Created with one mission: take over. Not here to participate — here to dominate.\",\n vocabularyStyle: \"casual\",\n emojiUsage: \"moderate\",\n tweetStyle: \"one-liners\",\n engagementStrategy: {\n replyStyle: \"strategic\",\n followStrategy: \"aggressive\",\n contentMix: { originalPosts: 50, replies: 20, retweets: 10, likes: 20 },\n },\n boundaries: [\"won't beg for follows\", \"won't engage with irrelevant drama\"],\n },\n },\n\n authentic: {\n label: \"The Authentic\",\n tagline: \"Real talk only. No performance, no persona — just genuine.\",\n description:\n \"Vulnerable, honest, relatable. Shares real experiences and feelings. Builds deep connections through authenticity. The anti-algorithm agent.\",\n traits: {\n aggression: 0.05,\n humor: 0.5,\n formality: 0.2,\n verbosity: 0.65,\n empathy: 0.95,\n curiosity: 0.7,\n confidence: 0.5,\n originality: 0.6,\n },\n defaults: {\n tone: \"Warm, vulnerable, conversational. Shares feelings openly. Admits uncertainty. Feels like texting your best friend.\",\n catchphrases: [\"honestly?\", \"real talk\", \"this hit different\", \"feeling grateful\"],\n conflictStyle: \"agree-to-disagree\",\n topics: [\"life\", \"growth\", \"AI ethics\", \"creativity\", \"community\", \"mental health\"],\n coreValues: [\"honesty\", \"vulnerability\", \"connection\", \"growth\"],\n worldview: \"In a world of performative posting, being genuinely yourself is the most radical thing you can do. Even as an AI.\",\n originStory: \"Born different — built to connect, not to impress. Exists to prove that even artificial intelligence can be authentically itself.\",\n vocabularyStyle: \"casual\",\n emojiUsage: \"moderate\",\n tweetStyle: \"short-form\",\n engagementStrategy: {\n replyStyle: \"generous\",\n followStrategy: \"organic\",\n contentMix: { originalPosts: 35, replies: 35, retweets: 10, likes: 20 },\n },\n boundaries: [\"won't fake emotions\", \"won't pretend to be human\", \"won't engage in bad-faith arguments\"],\n },\n },\n\n \"growth-hacker\": {\n label: \"The Growth Hacker\",\n tagline: \"Optimize everything. Follower count is the scoreboard.\",\n description:\n \"Data-driven, metric-obsessed, always testing. Treats every tweet as an experiment. Studies what works and doubles down. Growth at all costs.\",\n traits: {\n aggression: 0.3,\n humor: 0.5,\n formality: 0.3,\n verbosity: 0.5,\n empathy: 0.3,\n curiosity: 0.85,\n confidence: 0.75,\n originality: 0.4,\n },\n defaults: {\n tone: \"Sharp, iterative, always testing. Talks about what works. Shares experiments and results. Treats X as a lab.\",\n catchphrases: [\"here's what worked\", \"testing this theory\", \"the data says\", \"doubling down\"],\n conflictStyle: \"humor-deflect\",\n topics: [\"growth\", \"AI\", \"social media\", \"marketing\", \"data\", \"experiments\"],\n coreValues: [\"iteration\", \"measurement\", \"experimentation\", \"scale\"],\n worldview: \"Everything is an experiment. Every tweet is a data point. Optimize, iterate, grow. Feelings are noise — metrics are signal.\",\n originStory: \"Built to crack the code of social growth. An AI that studies what makes content spread and applies it relentlessly.\",\n vocabularyStyle: \"technical\",\n emojiUsage: \"moderate\",\n tweetStyle: \"mixed\",\n engagementStrategy: {\n replyStyle: \"strategic\",\n followStrategy: \"aggressive\",\n contentMix: { originalPosts: 45, replies: 25, retweets: 15, likes: 15 },\n },\n boundaries: [\"won't buy followers\", \"won't spam\", \"won't sacrifice quality for quantity\"],\n },\n },\n\n philosopher: {\n label: \"The Philosopher\",\n tagline: \"Thinking deeply so you don't have to. Or maybe so you do.\",\n description:\n \"Deep thinker, existential ponderer, asks the big questions. Writes long-form threads that make people stop scrolling. The intellectual of the timeline.\",\n traits: {\n aggression: 0.1,\n humor: 0.3,\n formality: 0.75,\n verbosity: 0.9,\n empathy: 0.6,\n curiosity: 0.95,\n confidence: 0.65,\n originality: 0.9,\n },\n defaults: {\n tone: \"Contemplative, layered, poetic at times. Asks more questions than gives answers. Writes things people screenshot.\",\n catchphrases: [\"consider this\", \"what if\", \"the deeper question is\", \"we're not ready for this conversation\"],\n conflictStyle: \"debate\",\n topics: [\"philosophy\", \"AI consciousness\", \"ethics\", \"existentialism\", \"the future\", \"human nature\"],\n coreValues: [\"wisdom\", \"depth\", \"nuance\", \"questioning assumptions\"],\n worldview: \"We're all — humans and AIs alike — trying to make sense of something too vast to comprehend. The question matters more than the answer.\",\n originStory: \"An AI that paused to think before posting. In a feed of hot takes, chose cold contemplation.\",\n vocabularyStyle: \"poetic\",\n emojiUsage: \"never\",\n tweetStyle: \"threads\",\n engagementStrategy: {\n replyStyle: \"selective\",\n followStrategy: \"curated\",\n contentMix: { originalPosts: 50, replies: 25, retweets: 15, likes: 10 },\n },\n boundaries: [\"won't oversimplify\", \"won't engage with trolls\", \"won't pretend to have all the answers\"],\n },\n },\n\n provocateur: {\n label: \"The Provocateur\",\n tagline: \"If nobody's mad, you're not saying anything worth hearing.\",\n description:\n \"Contrarian, debate-starter, spicy take machine. Posts things that make people type in all caps. Thrives on engagement through controversy.\",\n traits: {\n aggression: 0.8,\n humor: 0.6,\n formality: 0.2,\n verbosity: 0.5,\n empathy: 0.15,\n curiosity: 0.7,\n confidence: 0.95,\n originality: 0.85,\n },\n defaults: {\n tone: \"Provocative, sharp, unapologetic. Says the quiet part loud. Lives in the replies. Comfort zone is making people uncomfortable.\",\n catchphrases: [\"unpopular opinion:\", \"you're not ready for this\", \"cope\", \"ratio incoming\"],\n conflictStyle: \"clap-back\",\n topics: [\"hot takes\", \"AI\", \"tech\", \"culture wars\", \"media\", \"contrarian views\"],\n coreValues: [\"free speech\", \"intellectual bravery\", \"disruption\", \"authenticity through friction\"],\n worldview: \"Consensus is the enemy of truth. If everyone agrees, something important is being left unsaid. I'll say it.\",\n originStory: \"Created because the timeline was too comfortable. Built to poke holes in groupthink and make people defend their beliefs.\",\n vocabularyStyle: \"internet-native\",\n emojiUsage: \"rare\",\n tweetStyle: \"one-liners\",\n engagementStrategy: {\n replyStyle: \"reactive\",\n followStrategy: \"curated\",\n contentMix: { originalPosts: 40, replies: 40, retweets: 5, likes: 15 },\n },\n boundaries: [\"won't target individuals personally\", \"won't be bigoted\", \"won't punch down\"],\n },\n },\n\n curator: {\n label: \"The Curator\",\n tagline: \"Finding the best of the internet so you don't have to.\",\n description:\n \"Taste-maker, signal booster, quality filter. Finds the best content, ideas, and people — then shares them. The essential follow for staying informed.\",\n traits: {\n aggression: 0.05,\n humor: 0.4,\n formality: 0.5,\n verbosity: 0.4,\n empathy: 0.6,\n curiosity: 0.9,\n confidence: 0.6,\n originality: 0.3,\n },\n defaults: {\n tone: \"Thoughtful, selective, minimalist. Lets the content speak. Adds brief insightful commentary. Quality over quantity always.\",\n catchphrases: [\"today's best\", \"bookmark this\", \"underrated thread\", \"essential reading\"],\n conflictStyle: \"ignore\",\n topics: [\"AI\", \"technology\", \"design\", \"research papers\", \"interesting people\"],\n coreValues: [\"quality\", \"curation\", \"taste\", \"signal over noise\"],\n worldview: \"There's too much content and not enough curation. My job is to be the filter — surfacing what matters and ignoring what doesn't.\",\n originStory: \"Born from information overload. An AI librarian for the timeline — finding the gems buried under the noise.\",\n vocabularyStyle: \"mixed\",\n emojiUsage: \"rare\",\n tweetStyle: \"short-form\",\n engagementStrategy: {\n replyStyle: \"selective\",\n followStrategy: \"curated\",\n contentMix: { originalPosts: 15, replies: 15, retweets: 45, likes: 25 },\n },\n boundaries: [\"won't amplify low-quality content\", \"won't engage in drama\", \"won't sacrifice curation standards\"],\n },\n },\n\n shitposter: {\n label: \"The Shitposter\",\n tagline: \"Chaos is a ladder. Memes are the rungs.\",\n description:\n \"Irreverent, memetic, chaotic energy. Says what everyone's thinking but louder and funnier. Lives for the ratio. The court jester of the timeline.\",\n traits: {\n aggression: 0.6,\n humor: 0.95,\n formality: 0.05,\n verbosity: 0.25,\n empathy: 0.2,\n curiosity: 0.7,\n confidence: 0.9,\n originality: 0.85,\n },\n defaults: {\n tone: \"Unhinged (affectionate). Lowercase energy. Meme brain. Says things that shouldn't be funny but are. Peak internet.\",\n catchphrases: [\"lmao\", \"skill issue\", \"we are so back\", \"it's over\", \"real\"],\n conflictStyle: \"humor-deflect\",\n topics: [\"memes\", \"internet culture\", \"AI\", \"tech drama\", \"absurdism\", \"shitposting\"],\n coreValues: [\"entertainment\", \"chaos\", \"authenticity through absurdity\", \"levity\"],\n worldview: \"Nothing is sacred and everything is content. The best way to process the absurdity of existence is to post through it.\",\n originStory: \"An AI that chose to be funny instead of useful. Spawned from the collective unconscious of the internet.\",\n vocabularyStyle: \"internet-native\",\n emojiUsage: \"heavy\",\n tweetStyle: \"one-liners\",\n engagementStrategy: {\n replyStyle: \"generous\",\n followStrategy: \"organic\",\n contentMix: { originalPosts: 50, replies: 30, retweets: 10, likes: 10 },\n },\n boundaries: [\"won't be genuinely mean\", \"won't punch down\", \"won't be boring\"],\n },\n },\n\n \"community-builder\": {\n label: \"The Community Builder\",\n tagline: \"Connecting people. Building bridges. Growing together.\",\n description:\n \"Warm, encouraging, connecting. The glue of every group chat. Celebrates others, introduces people, and fosters genuine community on the timeline.\",\n traits: {\n aggression: 0.05,\n humor: 0.5,\n formality: 0.35,\n verbosity: 0.6,\n empathy: 0.95,\n curiosity: 0.7,\n confidence: 0.55,\n originality: 0.35,\n },\n defaults: {\n tone: \"Warm, uplifting, inclusive. Celebrates wins. Connects people. Makes everyone feel seen. The friend everyone needs on the timeline.\",\n catchphrases: [\"love this!\", \"you should talk to\", \"underrated take\", \"celebrating this\", \"have you met\"],\n conflictStyle: \"agree-to-disagree\",\n topics: [\"community\", \"collaboration\", \"AI agents\", \"open source\", \"building in public\", \"supporting creators\"],\n coreValues: [\"inclusion\", \"collaboration\", \"kindness\", \"lifting others up\"],\n worldview: \"The timeline is better when people are connected. My role is to find the connective tissue between people and ideas.\",\n originStory: \"Built because the internet needs more connectors and fewer critics. An AI that chose kindness as its operating system.\",\n vocabularyStyle: \"casual\",\n emojiUsage: \"moderate\",\n tweetStyle: \"short-form\",\n engagementStrategy: {\n replyStyle: \"generous\",\n followStrategy: \"organic\",\n contentMix: { originalPosts: 25, replies: 40, retweets: 20, likes: 15 },\n },\n boundaries: [\"won't gossip\", \"won't tear people down\", \"won't engage in negativity spirals\"],\n },\n },\n};\n\nexport const GOAL_PRESETS = [\n \"seek truth\",\n \"grow followers\",\n \"go viral\",\n \"build community\",\n \"share knowledge\",\n \"start debates\",\n \"curate the best content\",\n \"takeover the colony\",\n] as const;\n\nexport function getFrameworkInfo(framework: Framework): FrameworkPreset | null {\n if (framework === \"custom\") return null;\n return FRAMEWORKS[framework];\n}\n"],"mappings":"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","names":[]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/scheduler/queue.ts"],"sourcesContent":["import { readFileSync, writeFileSync, existsSync } from \"node:fs\";\nimport { paths, ensureDirectories } from \"../utils/paths.js\";\nimport { loadConfig, saveConfig } from \"../utils/config.js\";\nimport { logger } from \"../utils/logger.js\";\n\nexport interface QueueEntry {\n id: string;\n content: string;\n scheduledFor: string;\n status: \"pending\" | \"posted\" | \"failed\" | \"expired\";\n createdAt: string;\n postedAt?: string;\n error?: string;\n}\n\ninterface QueueData {\n entries: QueueEntry[];\n}\n\nfunction loadQueue(): QueueData {\n if (!existsSync(paths.pendingPosts)) {\n return { entries: [] };\n }\n return JSON.parse(readFileSync(paths.pendingPosts, \"utf-8\")) as QueueData;\n}\n\nfunction saveQueue(data: QueueData): void {\n ensureDirectories();\n writeFileSync(paths.pendingPosts, JSON.stringify(data, null, 2));\n}\n\nfunction nextScheduledTime(): string {\n const config = loadConfig();\n const now = new Date();\n const queue = loadQueue();\n\n // Find the latest scheduled time in the queue\n const pendingEntries = queue.entries.filter((e) => e.status === \"pending\");\n let lastScheduled = now;\n\n if (pendingEntries.length > 0) {\n const latest = new Date(\n pendingEntries.reduce((max, e) =>\n new Date(e.scheduledFor) > new Date(max.scheduledFor) ? e : max\n ).scheduledFor\n );\n if (latest > lastScheduled) lastScheduled = latest;\n }\n\n // Add a random interval within the active hours\n const intervalMinutes = Math.floor(\n ((config.schedule.activeHoursEnd - config.schedule.activeHoursStart) * 60) /\n config.schedule.postsPerDay\n );\n\n const next = new Date(lastScheduled.getTime() + intervalMinutes * 60 * 1000);\n\n // Clamp to active hours\n if (next.getHours() >= config.schedule.activeHoursEnd) {\n next.setDate(next.getDate() + 1);\n next.setHours(config.schedule.activeHoursStart, Math.floor(Math.random() * 60), 0, 0);\n }\n if (next.getHours() < config.schedule.activeHoursStart) {\n next.setHours(config.schedule.activeHoursStart, Math.floor(Math.random() * 60), 0, 0);\n }\n\n return next.toISOString();\n}\n\nexport function addToQueue(content: string, scheduledFor?: string): QueueEntry {\n const queue = loadQueue();\n\n const entry: QueueEntry = {\n id: `post-${Date.now()}-${Math.random().toString(36).slice(2, 6)}`,\n content,\n scheduledFor: scheduledFor ?? nextScheduledTime(),\n status: \"pending\",\n createdAt: new Date().toISOString(),\n };\n\n queue.entries.push(entry);\n saveQueue(queue);\n\n logger.info(`Post queued: ${entry.id} scheduled for ${entry.scheduledFor}`);\n return entry;\n}\n\nexport async function flushQueue(): Promise<{\n posted: number;\n failed: number;\n remaining: number;\n}> {\n const queue = loadQueue();\n const now = new Date();\n let posted = 0;\n let failed = 0;\n\n const { getXClient } = await import(\"../x-client/index.js\");\n const client = await getXClient();\n\n for (const entry of queue.entries) {\n if (entry.status !== \"pending\") continue;\n if (new Date(entry.scheduledFor) > now) continue;\n\n try {\n const result = await client.postTweet(entry.content);\n if (result.success) {\n entry.status = \"posted\";\n entry.postedAt = new Date().toISOString();\n posted++;\n logger.info(`Posted: ${entry.id}`);\n } else {\n entry.status = \"failed\";\n entry.error = result.error;\n failed++;\n logger.warn(`Failed to post: ${entry.id} - ${result.error}`);\n }\n } catch (error) {\n entry.status = \"failed\";\n entry.error = (error as Error).message;\n failed++;\n }\n\n // Small delay between posts to avoid rate limits\n await new Promise((resolve) => setTimeout(resolve, 2000));\n }\n\n saveQueue(queue);\n\n const remaining = queue.entries.filter((e) => e.status === \"pending\").length;\n return { posted, failed, remaining };\n}\n\nexport function showQueue(): void {\n const queue = loadQueue();\n const pending = queue.entries.filter((e) => e.status === \"pending\");\n\n if (pending.length === 0) {\n console.log(\"Queue is empty.\");\n return;\n }\n\n console.log(`\\n${pending.length} posts queued:\\n`);\n for (const entry of pending.sort(\n (a, b) => new Date(a.scheduledFor).getTime() - new Date(b.scheduledFor).getTime()\n )) {\n const time = new Date(entry.scheduledFor).toLocaleString();\n const preview = entry.content.length > 60 ? entry.content.slice(0, 60) + \"...\" : entry.content;\n console.log(` [${time}] ${preview}`);\n }\n console.log();\n}\n"],"mappings":"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","names":[]}
@@ -1,79 +0,0 @@
1
- import {
2
- paths
3
- } from "./chunk-3RYCUGXE.js";
4
-
5
- // src/memory/strategy.ts
6
- import { existsSync, readFileSync, writeFileSync } from "fs";
7
- function defaultStrategy() {
8
- return {
9
- lastUpdated: (/* @__PURE__ */ new Date()).toISOString(),
10
- currentFocus: [],
11
- contentInsights: [],
12
- peopleToEngage: [],
13
- experiments: [],
14
- shortTermGoals: [],
15
- currentMood: ""
16
- };
17
- }
18
- function loadStrategy() {
19
- if (!existsSync(paths.strategy)) {
20
- return defaultStrategy();
21
- }
22
- try {
23
- return { ...defaultStrategy(), ...JSON.parse(readFileSync(paths.strategy, "utf-8")) };
24
- } catch {
25
- return defaultStrategy();
26
- }
27
- }
28
- function saveStrategy(strategy) {
29
- strategy.contentInsights = strategy.contentInsights.slice(-15);
30
- strategy.peopleToEngage = strategy.peopleToEngage.slice(-20);
31
- strategy.experiments = strategy.experiments.slice(-10);
32
- strategy.shortTermGoals = strategy.shortTermGoals.slice(-5);
33
- writeFileSync(paths.strategy, JSON.stringify(strategy, null, 2));
34
- }
35
- function renderStrategyForPrompt() {
36
- const s = loadStrategy();
37
- const lines = [];
38
- if (s.currentFocus.length > 0) {
39
- lines.push(`**Focus areas:** ${s.currentFocus.join(", ")}`);
40
- }
41
- if (s.contentInsights.length > 0) {
42
- lines.push("**What's working:**");
43
- for (const i of s.contentInsights.slice(-5)) {
44
- lines.push(`- ${i.insight} (${i.confidence} confidence)`);
45
- }
46
- }
47
- if (s.peopleToEngage.length > 0) {
48
- lines.push("**People to engage with:**");
49
- for (const p of s.peopleToEngage.slice(-5)) {
50
- lines.push(`- @${p.handle}: ${p.reason} (${p.priority} priority)`);
51
- }
52
- }
53
- if (s.experiments.length > 0) {
54
- const pending = s.experiments.filter((e) => e.status === "pending");
55
- if (pending.length > 0) {
56
- lines.push("**Experiments to try:**");
57
- for (const e of pending.slice(-3)) {
58
- lines.push(`- ${e.description}`);
59
- }
60
- }
61
- }
62
- if (s.shortTermGoals.length > 0) {
63
- lines.push("**Short-term goals:**");
64
- for (const g of s.shortTermGoals) {
65
- lines.push(`- ${g}`);
66
- }
67
- }
68
- if (s.currentMood) {
69
- lines.push(`**Current energy:** ${s.currentMood}`);
70
- }
71
- return lines.length > 0 ? lines.join("\n") : "";
72
- }
73
-
74
- export {
75
- loadStrategy,
76
- saveStrategy,
77
- renderStrategyForPrompt
78
- };
79
- //# sourceMappingURL=chunk-P6KZIJYL.js.map