spora 0.3.2 → 0.3.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (102) hide show
  1. package/dist/{account-creator-SETL5CGT.js → account-creator-AABUY2JU.js} +5 -5
  2. package/dist/{chunk-Q7YS3AIK.js → chunk-6KCIAMHL.js} +5 -6
  3. package/dist/chunk-6KCIAMHL.js.map +1 -0
  4. package/dist/{chunk-HERI4RPY.js → chunk-A6R5ZGK6.js} +2 -2
  5. package/dist/{chunk-QHFM2YW6.js → chunk-B6VI6L4D.js} +9 -44
  6. package/dist/chunk-B6VI6L4D.js.map +1 -0
  7. package/dist/{chunk-GJFBWIW3.js → chunk-FTFTB5Y5.js} +2 -2
  8. package/dist/{chunk-SXMDYUK3.js → chunk-GMSK775L.js} +29 -6
  9. package/dist/chunk-GMSK775L.js.map +1 -0
  10. package/dist/{chunk-POEDIDM6.js → chunk-H62HH5ZI.js} +2 -2
  11. package/dist/{chunk-NLWU5432.js → chunk-KQ37VL54.js} +5 -5
  12. package/dist/{chunk-JWMADEQO.js → chunk-ML4EMUZC.js} +3 -3
  13. package/dist/chunk-N5TBL3NY.js +86 -0
  14. package/dist/chunk-N5TBL3NY.js.map +1 -0
  15. package/dist/chunk-PNZ3XK2N.js +358 -0
  16. package/dist/chunk-PNZ3XK2N.js.map +1 -0
  17. package/dist/{chunk-J7J557HV.js → chunk-UCCAF2ZO.js} +2 -2
  18. package/dist/{chunk-RNVEWVDN.js → chunk-V6ZNR2SI.js} +2 -26
  19. package/dist/chunk-V6ZNR2SI.js.map +1 -0
  20. package/dist/cli.js +46 -46
  21. package/dist/cli.js.map +1 -1
  22. package/dist/{client-NVI3ZD4G.js → client-BGLXHLID.js} +10 -20
  23. package/dist/client-BGLXHLID.js.map +1 -0
  24. package/dist/client-TWYR2IIQ.js +373 -0
  25. package/dist/client-TWYR2IIQ.js.map +1 -0
  26. package/dist/{colony-J4EZQI37.js → colony-JVBCMZTK.js} +7 -7
  27. package/dist/{config-QRBOL4NX.js → config-5EPXA325.js} +3 -3
  28. package/dist/{crypto-ZVWJLD2J.js → crypto-HS4CGS4A.js} +3 -3
  29. package/dist/heartbeat-B2CZKMUF.js +901 -0
  30. package/dist/heartbeat-B2CZKMUF.js.map +1 -0
  31. package/dist/{identity-LN2R4KJU.js → identity-6CXRCXJQ.js} +3 -3
  32. package/dist/{init-ANGLSI2L.js → init-KXNLBFMG.js} +21 -21
  33. package/dist/init-KXNLBFMG.js.map +1 -0
  34. package/dist/llm-CUCO24K7.js +16 -0
  35. package/dist/mcp-server.js +24 -24
  36. package/dist/{memory-JMXU3UXR.js → memory-2OI3JXY2.js} +3 -3
  37. package/dist/{memory-J6AYZ5Y2.js → memory-LPU2I6NI.js} +3 -5
  38. package/dist/{paths-KXOWF2B2.js → paths-Q4TJEOMQ.js} +2 -2
  39. package/dist/prompt-builder-VHGZFBL6.js +19 -0
  40. package/dist/queue-LNBQWMFX.js +14 -0
  41. package/dist/web-chat/chat.html +38 -958
  42. package/dist/web-chat-DHHJTGFZ.js +253 -0
  43. package/dist/web-chat-DHHJTGFZ.js.map +1 -0
  44. package/dist/x-client-W5IB7XOM.js +12 -0
  45. package/package.json +2 -1
  46. package/dist/chunk-DFSYD45Q.js +0 -665
  47. package/dist/chunk-DFSYD45Q.js.map +0 -1
  48. package/dist/chunk-FCAK5FYQ.js +0 -127
  49. package/dist/chunk-FCAK5FYQ.js.map +0 -1
  50. package/dist/chunk-LRKBNKMQ.js +0 -79
  51. package/dist/chunk-LRKBNKMQ.js.map +0 -1
  52. package/dist/chunk-Q7YS3AIK.js.map +0 -1
  53. package/dist/chunk-QHFM2YW6.js.map +0 -1
  54. package/dist/chunk-R7PAD4OL.js +0 -44
  55. package/dist/chunk-R7PAD4OL.js.map +0 -1
  56. package/dist/chunk-RNVEWVDN.js.map +0 -1
  57. package/dist/chunk-SUFTVQME.js +0 -82
  58. package/dist/chunk-SUFTVQME.js.map +0 -1
  59. package/dist/chunk-SXMDYUK3.js.map +0 -1
  60. package/dist/chunk-YZ7RWJ6Z.js +0 -262
  61. package/dist/chunk-YZ7RWJ6Z.js.map +0 -1
  62. package/dist/client-23THPNVL.js +0 -382
  63. package/dist/client-23THPNVL.js.map +0 -1
  64. package/dist/client-NVI3ZD4G.js.map +0 -1
  65. package/dist/decision-engine-WBD36PZI.js +0 -19
  66. package/dist/goals-IM4AEHS4.js +0 -12
  67. package/dist/heartbeat-35HVB5PB.js +0 -317
  68. package/dist/heartbeat-35HVB5PB.js.map +0 -1
  69. package/dist/image-search-SZVMGWLN.js +0 -45
  70. package/dist/image-search-SZVMGWLN.js.map +0 -1
  71. package/dist/init-ANGLSI2L.js.map +0 -1
  72. package/dist/llm-MHZG2VHU.js +0 -16
  73. package/dist/performance-7G6R6ELJ.js +0 -18
  74. package/dist/prompt-builder-NSU4IFPB.js +0 -28
  75. package/dist/prompt-builder-NSU4IFPB.js.map +0 -1
  76. package/dist/queue-MLRTMJRE.js +0 -14
  77. package/dist/queue-MLRTMJRE.js.map +0 -1
  78. package/dist/strategy-TOVFBIZQ.js +0 -12
  79. package/dist/strategy-TOVFBIZQ.js.map +0 -1
  80. package/dist/web-chat/logo.png +0 -0
  81. package/dist/web-chat-N2AYUWT7.js +0 -802
  82. package/dist/web-chat-N2AYUWT7.js.map +0 -1
  83. package/dist/x-client-HUXCQOAW.js +0 -12
  84. package/dist/x-client-HUXCQOAW.js.map +0 -1
  85. /package/dist/{account-creator-SETL5CGT.js.map → account-creator-AABUY2JU.js.map} +0 -0
  86. /package/dist/{chunk-HERI4RPY.js.map → chunk-A6R5ZGK6.js.map} +0 -0
  87. /package/dist/{chunk-GJFBWIW3.js.map → chunk-FTFTB5Y5.js.map} +0 -0
  88. /package/dist/{chunk-POEDIDM6.js.map → chunk-H62HH5ZI.js.map} +0 -0
  89. /package/dist/{chunk-NLWU5432.js.map → chunk-KQ37VL54.js.map} +0 -0
  90. /package/dist/{chunk-JWMADEQO.js.map → chunk-ML4EMUZC.js.map} +0 -0
  91. /package/dist/{chunk-J7J557HV.js.map → chunk-UCCAF2ZO.js.map} +0 -0
  92. /package/dist/{colony-J4EZQI37.js.map → colony-JVBCMZTK.js.map} +0 -0
  93. /package/dist/{config-QRBOL4NX.js.map → config-5EPXA325.js.map} +0 -0
  94. /package/dist/{crypto-ZVWJLD2J.js.map → crypto-HS4CGS4A.js.map} +0 -0
  95. /package/dist/{decision-engine-WBD36PZI.js.map → identity-6CXRCXJQ.js.map} +0 -0
  96. /package/dist/{goals-IM4AEHS4.js.map → llm-CUCO24K7.js.map} +0 -0
  97. /package/dist/{identity-LN2R4KJU.js.map → memory-2OI3JXY2.js.map} +0 -0
  98. /package/dist/{llm-MHZG2VHU.js.map → memory-LPU2I6NI.js.map} +0 -0
  99. /package/dist/{memory-J6AYZ5Y2.js.map → paths-Q4TJEOMQ.js.map} +0 -0
  100. /package/dist/{memory-JMXU3UXR.js.map → prompt-builder-VHGZFBL6.js.map} +0 -0
  101. /package/dist/{paths-KXOWF2B2.js.map → queue-LNBQWMFX.js.map} +0 -0
  102. /package/dist/{performance-7G6R6ELJ.js.map → x-client-W5IB7XOM.js.map} +0 -0
@@ -1,802 +0,0 @@
1
- import {
2
- loadIdentity
3
- } from "./chunk-GJFBWIW3.js";
4
- import {
5
- paths
6
- } from "./chunk-Q7YS3AIK.js";
7
-
8
- // src/web-chat/server.ts
9
- import http from "http";
10
- import { URL } from "url";
11
- import { readFileSync, writeFileSync, existsSync } from "fs";
12
- import { join, dirname } from "path";
13
- import { fileURLToPath } from "url";
14
- var __filename = fileURLToPath(import.meta.url);
15
- var __dirname = dirname(__filename);
16
- var WebChatServer = class {
17
- server = null;
18
- port;
19
- messages = [];
20
- onUserMessage;
21
- onHeartbeatChange;
22
- identity;
23
- sleepState = {
24
- sleeping: false,
25
- wakeAt: null,
26
- intervalMs: 6e4
27
- };
28
- memoryStats = {
29
- learnings: 0,
30
- relationships: 0,
31
- interactions: 0
32
- };
33
- constructor(port = 3737) {
34
- this.port = port;
35
- }
36
- setIdentity(identity) {
37
- this.identity = identity;
38
- }
39
- setMessageHandler(handler) {
40
- this.onUserMessage = handler;
41
- }
42
- setHeartbeatChangeHandler(handler) {
43
- this.onHeartbeatChange = handler;
44
- }
45
- setSleeping(wakeAt) {
46
- this.sleepState.sleeping = true;
47
- this.sleepState.wakeAt = wakeAt;
48
- }
49
- setAwake() {
50
- this.sleepState.sleeping = false;
51
- this.sleepState.wakeAt = null;
52
- }
53
- getSleepState() {
54
- return { ...this.sleepState };
55
- }
56
- setHeartbeatInterval(intervalMs) {
57
- this.sleepState.intervalMs = intervalMs;
58
- }
59
- getHeartbeatInterval() {
60
- return this.sleepState.intervalMs;
61
- }
62
- setMemoryStats(stats) {
63
- this.memoryStats = stats;
64
- }
65
- async start() {
66
- return new Promise((resolve, reject) => {
67
- this.server = http.createServer(async (req, res) => {
68
- const url = new URL(req.url || "/", `http://${req.headers.host}`);
69
- res.setHeader("Access-Control-Allow-Origin", "*");
70
- res.setHeader("Access-Control-Allow-Methods", "GET, POST, OPTIONS");
71
- res.setHeader("Access-Control-Allow-Headers", "Content-Type");
72
- if (req.method === "OPTIONS") {
73
- res.writeHead(200);
74
- res.end();
75
- return;
76
- }
77
- if (url.pathname === "/" || url.pathname === "/index.html") {
78
- try {
79
- const possiblePaths = [
80
- join(__dirname, "web-chat", "chat.html"),
81
- join(__dirname, "chat.html"),
82
- join(__dirname, "..", "web-chat", "chat.html"),
83
- join(__dirname, "..", "src", "web-chat", "chat.html")
84
- ];
85
- let html = null;
86
- for (const p of possiblePaths) {
87
- try {
88
- html = readFileSync(p, "utf-8");
89
- break;
90
- } catch {
91
- continue;
92
- }
93
- }
94
- if (html) {
95
- res.writeHead(200, { "Content-Type": "text/html" });
96
- res.end(html);
97
- } else {
98
- console.error("Could not find chat.html in any of:", possiblePaths);
99
- res.writeHead(500);
100
- res.end("Error: Could not find chat.html");
101
- }
102
- } catch (error) {
103
- res.writeHead(500);
104
- res.end("Error loading chat interface");
105
- }
106
- return;
107
- }
108
- if (url.pathname === "/logo.png") {
109
- try {
110
- const logoPaths = [
111
- join(__dirname, "web-chat", "logo.png"),
112
- join(__dirname, "logo.png"),
113
- join(__dirname, "..", "web-chat", "logo.png"),
114
- join(__dirname, "..", "src", "web-chat", "logo.png")
115
- ];
116
- let logoData = null;
117
- for (const p of logoPaths) {
118
- try {
119
- logoData = readFileSync(p);
120
- break;
121
- } catch {
122
- continue;
123
- }
124
- }
125
- if (logoData) {
126
- res.writeHead(200, { "Content-Type": "image/png", "Cache-Control": "public, max-age=86400" });
127
- res.end(logoData);
128
- } else {
129
- res.writeHead(404);
130
- res.end("Logo not found");
131
- }
132
- } catch {
133
- res.writeHead(404);
134
- res.end("Logo not found");
135
- }
136
- return;
137
- }
138
- if (url.pathname === "/api/identity" && req.method === "GET") {
139
- res.writeHead(200, { "Content-Type": "application/json" });
140
- res.end(JSON.stringify({ identity: this.identity || null }));
141
- return;
142
- }
143
- if (url.pathname === "/api/messages" && req.method === "GET") {
144
- const since = url.searchParams.get("since");
145
- if (since) {
146
- const sinceTs = parseInt(since, 10);
147
- const newMessages = this.messages.filter((m) => m.timestamp > sinceTs);
148
- res.writeHead(200, { "Content-Type": "application/json" });
149
- res.end(JSON.stringify({ messages: newMessages }));
150
- } else {
151
- res.writeHead(200, { "Content-Type": "application/json" });
152
- res.end(JSON.stringify({ messages: this.messages }));
153
- }
154
- return;
155
- }
156
- if (url.pathname === "/api/message" && req.method === "POST") {
157
- let body = "";
158
- req.on("data", (chunk) => {
159
- body += chunk.toString();
160
- });
161
- req.on("end", async () => {
162
- try {
163
- const { message } = JSON.parse(body);
164
- this.messages.push({
165
- role: "user",
166
- content: message,
167
- timestamp: Date.now()
168
- });
169
- if (this.onUserMessage) {
170
- const response = await this.onUserMessage(message);
171
- this.messages.push({
172
- role: "assistant",
173
- content: response,
174
- timestamp: Date.now()
175
- });
176
- this.saveLastAssistantMessage(response);
177
- res.writeHead(200, { "Content-Type": "application/json" });
178
- res.end(JSON.stringify({ success: true, response }));
179
- } else {
180
- res.writeHead(500, { "Content-Type": "application/json" });
181
- res.end(JSON.stringify({ error: "No message handler configured" }));
182
- }
183
- } catch (error) {
184
- res.writeHead(400, { "Content-Type": "application/json" });
185
- res.end(JSON.stringify({ error: "Invalid request" }));
186
- }
187
- });
188
- return;
189
- }
190
- if (url.pathname === "/api/memory-stats" && req.method === "GET") {
191
- res.writeHead(200, { "Content-Type": "application/json" });
192
- res.end(JSON.stringify(this.memoryStats));
193
- return;
194
- }
195
- if (url.pathname === "/api/last-message" && req.method === "GET") {
196
- try {
197
- if (existsSync(paths.lastChatMessage)) {
198
- const data = readFileSync(paths.lastChatMessage, "utf-8");
199
- res.writeHead(200, { "Content-Type": "application/json" });
200
- res.end(data);
201
- } else {
202
- res.writeHead(200, { "Content-Type": "application/json" });
203
- res.end(JSON.stringify({ content: null }));
204
- }
205
- } catch {
206
- res.writeHead(200, { "Content-Type": "application/json" });
207
- res.end(JSON.stringify({ content: null }));
208
- }
209
- return;
210
- }
211
- if (url.pathname === "/api/sleep-state" && req.method === "GET") {
212
- res.writeHead(200, { "Content-Type": "application/json" });
213
- res.end(JSON.stringify(this.sleepState));
214
- return;
215
- }
216
- if (url.pathname === "/api/config/heartbeat" && req.method === "POST") {
217
- let body = "";
218
- req.on("data", (chunk) => {
219
- body += chunk.toString();
220
- });
221
- req.on("end", () => {
222
- try {
223
- const { intervalMs } = JSON.parse(body);
224
- if (typeof intervalMs === "number" && intervalMs >= 6e4) {
225
- this.sleepState.intervalMs = intervalMs;
226
- if (this.onHeartbeatChange) {
227
- this.onHeartbeatChange(intervalMs);
228
- }
229
- res.writeHead(200, { "Content-Type": "application/json" });
230
- res.end(JSON.stringify({ success: true, intervalMs }));
231
- } else {
232
- res.writeHead(400, { "Content-Type": "application/json" });
233
- res.end(JSON.stringify({ error: "Invalid interval" }));
234
- }
235
- } catch {
236
- res.writeHead(400, { "Content-Type": "application/json" });
237
- res.end(JSON.stringify({ error: "Invalid request" }));
238
- }
239
- });
240
- return;
241
- }
242
- res.writeHead(404);
243
- res.end("Not found");
244
- });
245
- this.server.listen(this.port, () => {
246
- const url = `http://localhost:${this.port}`;
247
- resolve(url);
248
- });
249
- this.server.on("error", (error) => {
250
- if (error.code === "EADDRINUSE") {
251
- this.port++;
252
- this.server?.close();
253
- this.start().then(resolve).catch(reject);
254
- } else {
255
- reject(error);
256
- }
257
- });
258
- });
259
- }
260
- /**
261
- * Push a message into the chat from the server side (used by heartbeat narration)
262
- */
263
- pushMessage(role, content) {
264
- this.messages.push({ role, content, timestamp: Date.now() });
265
- if (role === "assistant") {
266
- this.saveLastAssistantMessage(content);
267
- }
268
- }
269
- /**
270
- * Persist the last assistant message to disk so it survives restarts
271
- */
272
- saveLastAssistantMessage(content) {
273
- try {
274
- writeFileSync(paths.lastChatMessage, JSON.stringify({ content, timestamp: Date.now() }));
275
- } catch {
276
- }
277
- }
278
- getMessageCount() {
279
- return this.messages.length;
280
- }
281
- stop() {
282
- if (this.server) {
283
- this.server.close();
284
- this.server = null;
285
- }
286
- }
287
- };
288
-
289
- // src/web-chat/index.ts
290
- import { execSync } from "child_process";
291
- import chalk from "chalk";
292
- async function extractAndSaveLearnings(responseText) {
293
- const learnPattern = /<<LEARN:\s*(.+?)>>/g;
294
- const matches = [...responseText.matchAll(learnPattern)];
295
- if (matches.length > 0) {
296
- const { addLearning } = await import("./memory-J6AYZ5Y2.js");
297
- for (const match of matches) {
298
- const learning = match[1].trim();
299
- addLearning(learning, "web-chat", ["chat", "creator-interaction"]);
300
- console.log(chalk.dim(` [Memory] Saved learning: ${learning}`));
301
- }
302
- }
303
- return responseText.replace(/<<LEARN:\s*.+?>>/g, "").trim();
304
- }
305
- async function extractAndApplyTraining(responseText) {
306
- const trainingPattern = /<<TRAINING:([\s\S]*?)>>/g;
307
- const matches = [...responseText.matchAll(trainingPattern)];
308
- for (const match of matches) {
309
- try {
310
- const update = JSON.parse(match[1]);
311
- if (update.identity) {
312
- const { loadIdentity: loadIdentity2, saveIdentity, mutateIdentity } = await import("./identity-LN2R4KJU.js");
313
- let identity = loadIdentity2();
314
- if (update.identity.traits) {
315
- for (const [trait, value] of Object.entries(update.identity.traits)) {
316
- if (typeof value === "number" && value >= 0 && value <= 1) {
317
- identity = mutateIdentity(identity, `traits.${trait}`, value, "training-chat");
318
- console.log(chalk.dim(` [Training] ${trait}: ${(value * 100).toFixed(0)}%`));
319
- }
320
- }
321
- }
322
- const arrayFields = ["coreValues", "catchphrases", "topics", "avoidTopics", "heroes", "goals", "boundaries"];
323
- for (const field of arrayFields) {
324
- if (update.identity[field] && Array.isArray(update.identity[field])) {
325
- identity = mutateIdentity(identity, field, update.identity[field], "training-chat");
326
- console.log(chalk.dim(` [Training] ${field} updated`));
327
- }
328
- }
329
- const stringFields = ["worldview", "tone", "bio", "originStory"];
330
- for (const field of stringFields) {
331
- if (typeof update.identity[field] === "string") {
332
- identity = mutateIdentity(identity, field, update.identity[field], "training-chat");
333
- console.log(chalk.dim(` [Training] ${field} updated`));
334
- }
335
- }
336
- const enumFields = ["vocabularyStyle", "emojiUsage", "tweetStyle", "conflictStyle"];
337
- for (const field of enumFields) {
338
- if (typeof update.identity[field] === "string") {
339
- identity = mutateIdentity(identity, field, update.identity[field], "training-chat");
340
- console.log(chalk.dim(` [Training] ${field} \u2192 ${update.identity[field]}`));
341
- }
342
- }
343
- if (update.identity.engagementStrategy) {
344
- const es = update.identity.engagementStrategy;
345
- if (es.replyStyle) identity = mutateIdentity(identity, "engagementStrategy.replyStyle", es.replyStyle, "training-chat");
346
- if (es.followStrategy) identity = mutateIdentity(identity, "engagementStrategy.followStrategy", es.followStrategy, "training-chat");
347
- if (es.contentMix) {
348
- const merged = { ...identity.engagementStrategy.contentMix, ...es.contentMix };
349
- identity = mutateIdentity(identity, "engagementStrategy.contentMix", merged, "training-chat");
350
- }
351
- console.log(chalk.dim(` [Training] engagement strategy updated`));
352
- }
353
- try {
354
- saveIdentity(identity);
355
- console.log(chalk.green(` [Training] Identity saved.`));
356
- } catch (err) {
357
- console.log(chalk.red(` [Training] Identity save failed: ${err.message}`));
358
- }
359
- }
360
- if (update.strategy) {
361
- const { loadStrategy, saveStrategy } = await import("./strategy-TOVFBIZQ.js");
362
- const strategy = loadStrategy();
363
- if (update.strategy.currentFocus) strategy.currentFocus = update.strategy.currentFocus;
364
- if (update.strategy.shortTermGoals) strategy.shortTermGoals = update.strategy.shortTermGoals;
365
- if (update.strategy.currentMood) strategy.currentMood = update.strategy.currentMood;
366
- if (update.strategy.contentInsights) strategy.contentInsights.push(...update.strategy.contentInsights);
367
- if (update.strategy.experiments) strategy.experiments.push(...update.strategy.experiments);
368
- if (update.strategy.peopleToEngage) strategy.peopleToEngage.push(...update.strategy.peopleToEngage);
369
- strategy.lastUpdated = (/* @__PURE__ */ new Date()).toISOString();
370
- saveStrategy(strategy);
371
- console.log(chalk.green(` [Training] Strategy updated.`));
372
- }
373
- if (update.learning?.content) {
374
- const { addLearning } = await import("./memory-J6AYZ5Y2.js");
375
- addLearning(update.learning.content, "training-chat", update.learning.tags ?? ["training"]);
376
- console.log(chalk.dim(` [Training] Learning: "${update.learning.content.slice(0, 50)}..."`));
377
- }
378
- if (update.reflection) {
379
- const { loadIdentity: loadId, saveIdentity: saveId } = await import("./identity-LN2R4KJU.js");
380
- const id = loadId();
381
- id.evolutionJournal.push({ date: (/* @__PURE__ */ new Date()).toISOString(), reflection: update.reflection });
382
- saveId(id);
383
- console.log(chalk.dim(` [Training] Journal entry added.`));
384
- }
385
- if (update.goalUpdates?.length > 0) {
386
- const { loadGoals, saveGoals } = await import("./goals-IM4AEHS4.js");
387
- const tracker = loadGoals();
388
- for (const gu of update.goalUpdates) {
389
- const existing = tracker.goals.find((g) => g.goal === gu.goal);
390
- if (existing) {
391
- existing.progress = gu.progress;
392
- existing.lastUpdated = (/* @__PURE__ */ new Date()).toISOString();
393
- } else {
394
- tracker.goals.push({ goal: gu.goal, progress: gu.progress, lastUpdated: (/* @__PURE__ */ new Date()).toISOString() });
395
- }
396
- }
397
- tracker.lastReviewed = (/* @__PURE__ */ new Date()).toISOString();
398
- saveGoals(tracker);
399
- console.log(chalk.dim(` [Training] Goals updated.`));
400
- }
401
- } catch (err) {
402
- console.log(chalk.red(` [Training] Failed to parse/apply training: ${err.message}`));
403
- }
404
- }
405
- return responseText.replace(/<<TRAINING:[\s\S]*?>>/g, "").trim().replace(/\n{3,}/g, "\n\n");
406
- }
407
- async function logChatInteraction(userMessage, agentResponse) {
408
- const { logInteraction } = await import("./memory-J6AYZ5Y2.js");
409
- logInteraction({
410
- id: `chat-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`,
411
- timestamp: (/* @__PURE__ */ new Date()).toISOString(),
412
- type: "reply",
413
- content: agentResponse.slice(0, 200),
414
- targetHandle: "creator",
415
- creditsUsed: 0,
416
- success: true
417
- });
418
- }
419
- async function startWebChat() {
420
- const identity = loadIdentity();
421
- const server = new WebChatServer();
422
- server.setIdentity({
423
- name: identity.name,
424
- handle: identity.handle,
425
- bio: identity.bio,
426
- profileImage: identity.profileImage,
427
- createdAt: identity.createdAt
428
- });
429
- let realHandle;
430
- try {
431
- const { hasXCredentials } = await import("./paths-KXOWF2B2.js");
432
- if (hasXCredentials()) {
433
- const { getXClient } = await import("./x-client-HUXCQOAW.js");
434
- const client = await getXClient();
435
- if ("getAuthenticatedHandle" in client) {
436
- realHandle = await client.getAuthenticatedHandle();
437
- console.log(chalk.dim(` [Auth] Real Twitter handle: @${realHandle}`));
438
- server.setIdentity({
439
- name: identity.name,
440
- handle: realHandle,
441
- bio: identity.bio,
442
- profileImage: identity.profileImage,
443
- createdAt: identity.createdAt
444
- });
445
- }
446
- }
447
- } catch (err) {
448
- console.log(chalk.dim(` [Auth] Could not resolve real handle: ${err.message}`));
449
- }
450
- const chatHistory = [];
451
- let systemPrompt = null;
452
- let messageCount = 0;
453
- server.setMessageHandler(async (message) => {
454
- try {
455
- const sleepBefore = server.getSleepState();
456
- const remainingMs = sleepBefore.sleeping && sleepBefore.wakeAt ? Math.max(0, sleepBefore.wakeAt - Date.now()) : 0;
457
- server.setAwake();
458
- if (!systemPrompt || messageCount % 10 === 0) {
459
- const { buildTrainingChatPrompt } = await import("./prompt-builder-NSU4IFPB.js");
460
- systemPrompt = buildTrainingChatPrompt(realHandle);
461
- }
462
- messageCount++;
463
- const { hasLLMKey, chat: chatLLM } = await import("./llm-MHZG2VHU.js");
464
- if (!hasLLMKey()) {
465
- return "I can't respond right now - no API key configured. Run `spora set-llm-key` to set one up.";
466
- }
467
- chatHistory.push({ role: "user", content: message });
468
- const response = await chatLLM(systemPrompt, chatHistory);
469
- const trainedText = await extractAndApplyTraining(response.content);
470
- const cleanResponse = await extractAndSaveLearnings(trainedText);
471
- chatHistory.push({ role: "assistant", content: cleanResponse });
472
- logChatInteraction(message, cleanResponse).catch(
473
- (err) => console.error(chalk.dim(" [Memory] Failed to log interaction:"), err)
474
- );
475
- if (remainingMs > 1e4) {
476
- server.setSleeping(Date.now() + remainingMs);
477
- }
478
- return cleanResponse;
479
- } catch (error) {
480
- console.error("Chat error:", error);
481
- return `Sorry, I ran into an issue: ${error.message}`;
482
- }
483
- });
484
- refreshMemoryStats(server).catch(() => {
485
- });
486
- const url = await server.start();
487
- console.log(chalk.green(`
488
- \u2713 Chat interface started at ${chalk.bold(url)}
489
- `));
490
- console.log(chalk.dim(`Press Ctrl+C to stop the server
491
- `));
492
- openBrowser(url);
493
- startNarratedHeartbeat(server).catch(
494
- (err) => console.error(chalk.red("Heartbeat failed to start:"), err)
495
- );
496
- process.on("SIGINT", () => {
497
- console.log(chalk.yellow("\n\nStopping chat server..."));
498
- heartbeatRunning = false;
499
- server.stop();
500
- process.exit(0);
501
- });
502
- return server;
503
- }
504
- async function refreshMemoryStats(server) {
505
- try {
506
- const { loadLearnings, loadRelationships, getRecentInteractions } = await import("./memory-J6AYZ5Y2.js");
507
- const learnings = loadLearnings().learnings.length;
508
- const relationships = Object.keys(loadRelationships().accounts).length;
509
- const interactions = getRecentInteractions(1e3).length;
510
- server.setMemoryStats({ learnings, relationships, interactions });
511
- } catch {
512
- }
513
- }
514
- var heartbeatRunning = false;
515
- var lastMentionsSinceId;
516
- async function startNarratedHeartbeat(server) {
517
- const { loadConfig } = await import("./config-QRBOL4NX.js");
518
- const { hasLLMKey, generateResponse } = await import("./llm-MHZG2VHU.js");
519
- const { hasXCredentials } = await import("./paths-KXOWF2B2.js");
520
- if (!hasLLMKey()) {
521
- console.log(chalk.dim(" [Heartbeat] No LLM key \u2014 heartbeat disabled."));
522
- return;
523
- }
524
- if (!hasXCredentials()) {
525
- console.log(chalk.dim(" [Heartbeat] No X credentials \u2014 heartbeat disabled."));
526
- return;
527
- }
528
- const config = loadConfig();
529
- let intervalMs = config.runtime?.heartbeatIntervalMs ?? 6e4;
530
- const maxActions = config.runtime?.actionsPerHeartbeat ?? 10;
531
- server.setHeartbeatInterval(intervalMs);
532
- server.setHeartbeatChangeHandler((newIntervalMs) => {
533
- intervalMs = newIntervalMs;
534
- console.log(chalk.cyan(` [Heartbeat] Interval changed to ${Math.round(newIntervalMs / 1e3)}s`));
535
- import("./config-QRBOL4NX.js").then(({ loadConfig: reloadConfig, saveConfig }) => {
536
- const cfg = reloadConfig();
537
- if (!cfg.runtime) cfg.runtime = {};
538
- cfg.runtime.heartbeatIntervalMs = newIntervalMs;
539
- saveConfig(cfg);
540
- }).catch(() => {
541
- });
542
- });
543
- heartbeatRunning = true;
544
- let heartbeatCount = 0;
545
- console.log(chalk.cyan(` [Heartbeat] Running every ${Math.round(intervalMs / 1e3)}s
546
- `));
547
- while (heartbeatRunning) {
548
- heartbeatCount++;
549
- console.log(chalk.cyan(` [Heartbeat] #${heartbeatCount} starting...`));
550
- server.setAwake();
551
- await refreshMemoryStats(server);
552
- try {
553
- await runNarratedHeartbeat(server, maxActions, intervalMs, heartbeatCount);
554
- } catch (error) {
555
- console.error(chalk.red(` [Heartbeat] #${heartbeatCount} failed:`), error.message);
556
- }
557
- const jitter = Math.floor(Math.random() * intervalMs * 0.2);
558
- const sleepMs = intervalMs + jitter;
559
- console.log(chalk.dim(` [Heartbeat] Sleeping ${Math.round(sleepMs / 1e3)}s...`));
560
- server.setSleeping(Date.now() + sleepMs);
561
- let slept = 0;
562
- while (slept < sleepMs && heartbeatRunning) {
563
- await new Promise((r) => setTimeout(r, Math.min(1e4, sleepMs - slept)));
564
- slept += 1e4;
565
- try {
566
- const { flushQueue } = await import("./queue-MLRTMJRE.js");
567
- const flushed = await flushQueue();
568
- if (flushed.posted > 0) {
569
- console.log(chalk.green(` [Queue] Posted ${flushed.posted} scheduled tweet(s)`));
570
- }
571
- } catch {
572
- }
573
- }
574
- server.setAwake();
575
- }
576
- }
577
- async function runNarratedHeartbeat(server, maxActions, intervalMs, heartbeatCount = 1) {
578
- const { getXClient } = await import("./x-client-HUXCQOAW.js");
579
- const { buildSystemPrompt, buildNarratedHeartbeatMessage, buildReflectionPrompt, parseReflection } = await import("./prompt-builder-NSU4IFPB.js");
580
- const { generateResponse } = await import("./llm-MHZG2VHU.js");
581
- const { parseActions, executeActions } = await import("./decision-engine-WBD36PZI.js");
582
- const { flushQueue } = await import("./queue-MLRTMJRE.js");
583
- const { retireOldPosts, getActiveTrackedPosts, updatePostMetrics, updateSelfMetrics, getPerformanceSummary } = await import("./performance-7G6R6ELJ.js");
584
- const { loadStrategy, saveStrategy } = await import("./strategy-TOVFBIZQ.js");
585
- const { addLearning } = await import("./memory-J6AYZ5Y2.js");
586
- const { loadIdentity: loadId } = await import("./identity-LN2R4KJU.js");
587
- try {
588
- const flushed = await flushQueue();
589
- if (flushed.posted > 0) {
590
- console.log(chalk.green(` [Queue] Flushed ${flushed.posted} scheduled tweet(s)`));
591
- }
592
- } catch {
593
- }
594
- const client = await getXClient();
595
- let ownHandle;
596
- if ("getAuthenticatedHandle" in client) {
597
- try {
598
- ownHandle = await client.getAuthenticatedHandle();
599
- } catch {
600
- }
601
- }
602
- try {
603
- retireOldPosts();
604
- const activePosts = getActiveTrackedPosts();
605
- for (const post of activePosts.slice(0, 5)) {
606
- try {
607
- const tweet = await client.getTweet(post.tweetId);
608
- if (tweet) {
609
- updatePostMetrics(post.tweetId, {
610
- checkedAt: (/* @__PURE__ */ new Date()).toISOString(),
611
- likes: tweet.likeCount ?? 0,
612
- retweets: tweet.retweetCount ?? 0,
613
- replies: tweet.replyCount ?? 0
614
- });
615
- }
616
- } catch {
617
- }
618
- await new Promise((r) => setTimeout(r, 1e3));
619
- }
620
- } catch (error) {
621
- console.log(chalk.dim(` [Heartbeat] Performance check failed: ${error.message}`));
622
- }
623
- if (heartbeatCount % 6 === 1) {
624
- try {
625
- const handle = ownHandle ?? loadId().handle;
626
- const profile = await client.getProfile(handle);
627
- updateSelfMetrics({
628
- checkedAt: (/* @__PURE__ */ new Date()).toISOString(),
629
- followers: profile.followersCount,
630
- following: profile.followingCount,
631
- totalTweets: profile.tweetCount
632
- });
633
- console.log(chalk.dim(` [Heartbeat] Self: ${profile.followersCount} followers`));
634
- } catch (error) {
635
- console.log(chalk.dim(` [Heartbeat] Self-check failed: ${error.message}`));
636
- }
637
- }
638
- let timeline = [];
639
- let mentions = [];
640
- try {
641
- timeline = await client.getTimeline({ count: 20 });
642
- if (ownHandle) {
643
- timeline = timeline.filter((t) => t.authorHandle.toLowerCase() !== ownHandle.toLowerCase());
644
- }
645
- } catch (error) {
646
- console.log(chalk.dim(` [Heartbeat] Timeline read failed: ${error.message}`));
647
- }
648
- try {
649
- mentions = await client.getMentions({ count: 10, sinceId: lastMentionsSinceId });
650
- if (mentions.length > 0) {
651
- lastMentionsSinceId = mentions[0].id;
652
- }
653
- } catch (error) {
654
- console.log(chalk.dim(` [Heartbeat] Mentions read failed: ${error.message}`));
655
- }
656
- let discoveryResults = [];
657
- if (heartbeatCount % 4 === 0) {
658
- try {
659
- const identity = loadId();
660
- const strategy = loadStrategy();
661
- const allTopics = [...identity.topics, ...strategy.currentFocus ?? []];
662
- if (allTopics.length > 0) {
663
- const topic = allTopics[Math.floor(Math.random() * allTopics.length)];
664
- discoveryResults = await client.searchTweets(topic, { count: 10 });
665
- if (ownHandle) {
666
- discoveryResults = discoveryResults.filter((t) => t.authorHandle.toLowerCase() !== ownHandle.toLowerCase());
667
- }
668
- console.log(chalk.dim(` [Heartbeat] Discovery for "${topic}": ${discoveryResults.length} results`));
669
- }
670
- } catch (error) {
671
- console.log(chalk.dim(` [Heartbeat] Discovery failed: ${error.message}`));
672
- }
673
- }
674
- const systemPrompt = buildSystemPrompt();
675
- const userMessage = buildNarratedHeartbeatMessage(timeline, mentions, intervalMs, discoveryResults);
676
- const response = await generateResponse(systemPrompt, userMessage, { temperature: 0.95 });
677
- let narration = response.content.replace(/```json\s*[\s\S]*?```/g, "").replace(/\n{3,}/g, "\n\n").trim();
678
- const actions = parseActions(response.content);
679
- const validTweetIds = /* @__PURE__ */ new Set();
680
- for (const t of timeline) validTweetIds.add(t.id);
681
- for (const t of mentions) validTweetIds.add(t.id);
682
- for (const t of discoveryResults) validTweetIds.add(t.id);
683
- const validatedActions = actions.filter((a) => {
684
- if (a.tweetId) {
685
- const cleanId = a.tweetId.replace(/^tweet:/i, "").trim();
686
- if (!validTweetIds.has(cleanId)) {
687
- console.log(chalk.yellow(` [Heartbeat] Rejected ${a.action}: tweet ID ${cleanId} not in timeline/mentions (likely hallucinated)`));
688
- return false;
689
- }
690
- }
691
- return true;
692
- });
693
- const limitedActions = validatedActions.slice(0, maxActions);
694
- const tweetMap = /* @__PURE__ */ new Map();
695
- for (const t of timeline) tweetMap.set(t.id, t);
696
- for (const t of mentions) tweetMap.set(t.id, t);
697
- for (const t of discoveryResults) tweetMap.set(t.id, t);
698
- let results = [];
699
- if (limitedActions.length > 0) {
700
- results = await executeActions(limitedActions, tweetMap);
701
- const visibleResults = [];
702
- for (let i = 0; i < results.length; i++) {
703
- const r = results[i];
704
- const action = limitedActions[i];
705
- const detail = r.detail ? ` (${r.detail})` : "";
706
- if (r.action === "schedule") {
707
- console.log(chalk.dim(` [Heartbeat] ${r.action}: ${r.success ? "queued" : r.error}${detail}`));
708
- } else if (r.success) {
709
- if ((r.action === "post" || r.action === "reply") && r.content) {
710
- const tweetData = JSON.stringify({ action: r.action, tweetId: r.detail ?? null, content: r.content });
711
- visibleResults.push(`<<TWEET:${tweetData}>>`);
712
- console.log(chalk.green(` [Heartbeat] ${r.action}: success (tweet preview)`));
713
- } else if (r.action === "like" && action?.tweetId) {
714
- const tweet = tweetMap.get(action.tweetId.replace(/^tweet:/i, "").trim());
715
- if (tweet) {
716
- const likeData = JSON.stringify({ authorHandle: tweet.authorHandle, text: tweet.text });
717
- visibleResults.push(`<<LIKE:${likeData}>>`);
718
- }
719
- console.log(chalk.green(` [Heartbeat] like: @${tweet?.authorHandle ?? "unknown"}`));
720
- } else if (r.action === "retweet" && action?.tweetId) {
721
- const tweet = tweetMap.get(action.tweetId.replace(/^tweet:/i, "").trim());
722
- if (tweet) {
723
- const rtData = JSON.stringify({ authorHandle: tweet.authorHandle, text: tweet.text });
724
- visibleResults.push(`<<RETWEET:${rtData}>>`);
725
- }
726
- console.log(chalk.green(` [Heartbeat] retweet: @${tweet?.authorHandle ?? "unknown"}`));
727
- } else if (r.action === "follow" && action?.handle) {
728
- const followData = JSON.stringify({ handle: action.handle });
729
- visibleResults.push(`<<FOLLOW:${followData}>>`);
730
- console.log(chalk.green(` [Heartbeat] follow: @${action.handle}`));
731
- } else {
732
- console.log(chalk.green(` [Heartbeat] ${r.action}: success${detail}`));
733
- }
734
- } else {
735
- console.log(chalk.red(` [Heartbeat] ${r.action}: ${r.error}`));
736
- }
737
- }
738
- let fullMessage = narration || "";
739
- if (visibleResults.length > 0) {
740
- fullMessage += (fullMessage ? "\n\n" : "") + visibleResults.join("\n");
741
- }
742
- if (fullMessage) {
743
- server.pushMessage("assistant", fullMessage);
744
- }
745
- } else if (narration) {
746
- server.pushMessage("assistant", narration);
747
- }
748
- try {
749
- const perfSummary = getPerformanceSummary();
750
- const currentStrategy = loadStrategy();
751
- const reflectPrompt = buildReflectionPrompt(results, perfSummary, currentStrategy);
752
- const reflection = await generateResponse(systemPrompt, reflectPrompt, { temperature: 0.7 });
753
- const reflectionData = parseReflection(reflection.content);
754
- if (reflectionData.learning) {
755
- addLearning(reflectionData.learning, "reflection", ["auto-reflect"]);
756
- console.log(chalk.dim(` [Heartbeat] Reflection: "${reflectionData.learning.slice(0, 60)}..."`));
757
- }
758
- if (reflectionData.strategyUpdate) {
759
- const updated = { ...currentStrategy, ...reflectionData.strategyUpdate, lastUpdated: (/* @__PURE__ */ new Date()).toISOString() };
760
- saveStrategy(updated);
761
- console.log(chalk.dim(` [Heartbeat] Strategy updated.`));
762
- }
763
- } catch (error) {
764
- console.log(chalk.dim(` [Heartbeat] Reflection failed: ${error.message}`));
765
- }
766
- console.log(chalk.cyan(` [Heartbeat] Complete.`));
767
- }
768
- function openBrowser(url) {
769
- const platform = process.platform;
770
- try {
771
- if (platform === "darwin") {
772
- try {
773
- execSync(`open -na "Google Chrome" --args --app="${url}" --window-size=420,620`, { stdio: "ignore" });
774
- } catch {
775
- try {
776
- execSync(`open -na "Brave Browser" --args --app="${url}" --window-size=420,620`, { stdio: "ignore" });
777
- } catch {
778
- execSync(`open "${url}"`, { stdio: "ignore" });
779
- }
780
- }
781
- } else if (platform === "win32") {
782
- try {
783
- execSync(`start chrome --app="${url}" --window-size=420,620`, { stdio: "ignore" });
784
- } catch {
785
- execSync(`start "" "${url}"`, { stdio: "ignore" });
786
- }
787
- } else {
788
- try {
789
- execSync(`google-chrome --app="${url}" --window-size=420,620`, { stdio: "ignore" });
790
- } catch {
791
- execSync(`xdg-open "${url}"`, { stdio: "ignore" });
792
- }
793
- }
794
- } catch (error) {
795
- console.log(chalk.dim(`(Couldn't open browser automatically - please visit ${url} manually)`));
796
- }
797
- }
798
- export {
799
- openBrowser,
800
- startWebChat
801
- };
802
- //# sourceMappingURL=web-chat-N2AYUWT7.js.map