spora 0.3.1 → 0.3.3

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 (83) hide show
  1. package/package.json +1 -1
  2. package/dist/account-creator-SETL5CGT.js +0 -498
  3. package/dist/account-creator-SETL5CGT.js.map +0 -1
  4. package/dist/chunk-FCAK5FYQ.js +0 -127
  5. package/dist/chunk-FCAK5FYQ.js.map +0 -1
  6. package/dist/chunk-GJFBWIW3.js +0 -622
  7. package/dist/chunk-GJFBWIW3.js.map +0 -1
  8. package/dist/chunk-HERI4RPY.js +0 -156
  9. package/dist/chunk-HERI4RPY.js.map +0 -1
  10. package/dist/chunk-J7J557HV.js +0 -47
  11. package/dist/chunk-J7J557HV.js.map +0 -1
  12. package/dist/chunk-JWMADEQO.js +0 -57
  13. package/dist/chunk-JWMADEQO.js.map +0 -1
  14. package/dist/chunk-LRKBNKMQ.js +0 -79
  15. package/dist/chunk-LRKBNKMQ.js.map +0 -1
  16. package/dist/chunk-NLWU5432.js +0 -32
  17. package/dist/chunk-NLWU5432.js.map +0 -1
  18. package/dist/chunk-POEDIDM6.js +0 -56
  19. package/dist/chunk-POEDIDM6.js.map +0 -1
  20. package/dist/chunk-Q7YS3AIK.js +0 -63
  21. package/dist/chunk-Q7YS3AIK.js.map +0 -1
  22. package/dist/chunk-QHFM2YW6.js +0 -159
  23. package/dist/chunk-QHFM2YW6.js.map +0 -1
  24. package/dist/chunk-R7PAD4OL.js +0 -44
  25. package/dist/chunk-R7PAD4OL.js.map +0 -1
  26. package/dist/chunk-RNVEWVDN.js +0 -129
  27. package/dist/chunk-RNVEWVDN.js.map +0 -1
  28. package/dist/chunk-SUFTVQME.js +0 -82
  29. package/dist/chunk-SUFTVQME.js.map +0 -1
  30. package/dist/chunk-SXMDYUK3.js +0 -80
  31. package/dist/chunk-SXMDYUK3.js.map +0 -1
  32. package/dist/chunk-TQWLKICD.js +0 -660
  33. package/dist/chunk-TQWLKICD.js.map +0 -1
  34. package/dist/chunk-YZ7RWJ6Z.js +0 -262
  35. package/dist/chunk-YZ7RWJ6Z.js.map +0 -1
  36. package/dist/cli.js +0 -654
  37. package/dist/cli.js.map +0 -1
  38. package/dist/client-23THPNVL.js +0 -382
  39. package/dist/client-23THPNVL.js.map +0 -1
  40. package/dist/client-NVI3ZD4G.js +0 -411
  41. package/dist/client-NVI3ZD4G.js.map +0 -1
  42. package/dist/colony-J4EZQI37.js +0 -229
  43. package/dist/colony-J4EZQI37.js.map +0 -1
  44. package/dist/config-QRBOL4NX.js +0 -14
  45. package/dist/config-QRBOL4NX.js.map +0 -1
  46. package/dist/crypto-ZVWJLD2J.js +0 -14
  47. package/dist/crypto-ZVWJLD2J.js.map +0 -1
  48. package/dist/decision-engine-WBD36PZI.js +0 -19
  49. package/dist/decision-engine-WBD36PZI.js.map +0 -1
  50. package/dist/goals-IM4AEHS4.js +0 -12
  51. package/dist/goals-IM4AEHS4.js.map +0 -1
  52. package/dist/heartbeat-TUV5IREO.js +0 -317
  53. package/dist/heartbeat-TUV5IREO.js.map +0 -1
  54. package/dist/identity-LN2R4KJU.js +0 -26
  55. package/dist/identity-LN2R4KJU.js.map +0 -1
  56. package/dist/image-search-SZVMGWLN.js +0 -45
  57. package/dist/image-search-SZVMGWLN.js.map +0 -1
  58. package/dist/init-FR5OTDRJ.js +0 -403
  59. package/dist/init-FR5OTDRJ.js.map +0 -1
  60. package/dist/llm-MHZG2VHU.js +0 -16
  61. package/dist/llm-MHZG2VHU.js.map +0 -1
  62. package/dist/mcp-server.js +0 -773
  63. package/dist/mcp-server.js.map +0 -1
  64. package/dist/memory-J6AYZ5Y2.js +0 -26
  65. package/dist/memory-J6AYZ5Y2.js.map +0 -1
  66. package/dist/memory-JMXU3UXR.js +0 -26
  67. package/dist/memory-JMXU3UXR.js.map +0 -1
  68. package/dist/paths-KXOWF2B2.js +0 -13
  69. package/dist/paths-KXOWF2B2.js.map +0 -1
  70. package/dist/performance-7G6R6ELJ.js +0 -18
  71. package/dist/performance-7G6R6ELJ.js.map +0 -1
  72. package/dist/prompt-builder-EQYCNP63.js +0 -28
  73. package/dist/prompt-builder-EQYCNP63.js.map +0 -1
  74. package/dist/queue-MLRTMJRE.js +0 -14
  75. package/dist/queue-MLRTMJRE.js.map +0 -1
  76. package/dist/strategy-TOVFBIZQ.js +0 -12
  77. package/dist/strategy-TOVFBIZQ.js.map +0 -1
  78. package/dist/web-chat/chat.html +0 -1343
  79. package/dist/web-chat/logo.png +0 -0
  80. package/dist/web-chat-RZKDQYJ4.js +0 -802
  81. package/dist/web-chat-RZKDQYJ4.js.map +0 -1
  82. package/dist/x-client-HUXCQOAW.js +0 -12
  83. package/dist/x-client-HUXCQOAW.js.map +0 -1
@@ -1,63 +0,0 @@
1
- // src/utils/paths.ts
2
- import { homedir } from "os";
3
- import { join } from "path";
4
- import { mkdirSync, existsSync } from "fs";
5
- var SPORA_DIR = join(homedir(), ".spora");
6
- var paths = {
7
- root: SPORA_DIR,
8
- config: join(SPORA_DIR, "config.json"),
9
- credentials: join(SPORA_DIR, "credentials.json"),
10
- spore: join(SPORA_DIR, "spore.json"),
11
- identity: join(SPORA_DIR, "identity.json"),
12
- colonyToken: join(SPORA_DIR, "colony-token.json"),
13
- browser: join(SPORA_DIR, "browser"),
14
- browserAuth: join(SPORA_DIR, "browser", "auth-state.json"),
15
- memory: join(SPORA_DIR, "memory"),
16
- interactions: join(SPORA_DIR, "memory", "interactions"),
17
- learnings: join(SPORA_DIR, "memory", "learnings.json"),
18
- relationships: join(SPORA_DIR, "memory", "relationships.json"),
19
- compacted: join(SPORA_DIR, "memory", "compacted"),
20
- queue: join(SPORA_DIR, "queue"),
21
- pendingPosts: join(SPORA_DIR, "queue", "pending-posts.json"),
22
- logs: join(SPORA_DIR, "logs"),
23
- logFile: join(SPORA_DIR, "logs", "spora.log"),
24
- dataDir: SPORA_DIR,
25
- llmKey: join(SPORA_DIR, "llm-key"),
26
- runtimePid: join(SPORA_DIR, "runtime.pid"),
27
- stopSignal: join(SPORA_DIR, "stop"),
28
- connectionToken: join(SPORA_DIR, "connection-token"),
29
- lastChatMessage: join(SPORA_DIR, "last-chat-message.json"),
30
- performance: join(SPORA_DIR, "memory", "performance.json"),
31
- strategy: join(SPORA_DIR, "memory", "strategy.json"),
32
- goals: join(SPORA_DIR, "memory", "goals.json")
33
- };
34
- function ensureDirectories() {
35
- const dirs = [
36
- paths.root,
37
- paths.browser,
38
- paths.memory,
39
- paths.interactions,
40
- paths.compacted,
41
- paths.queue,
42
- paths.logs
43
- ];
44
- for (const dir of dirs) {
45
- if (!existsSync(dir)) {
46
- mkdirSync(dir, { recursive: true });
47
- }
48
- }
49
- }
50
- function sporaExists() {
51
- return existsSync(paths.config) && existsSync(paths.identity);
52
- }
53
- function hasXCredentials() {
54
- return existsSync(paths.credentials);
55
- }
56
-
57
- export {
58
- paths,
59
- ensureDirectories,
60
- sporaExists,
61
- hasXCredentials
62
- };
63
- //# sourceMappingURL=chunk-Q7YS3AIK.js.map
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/utils/paths.ts"],"sourcesContent":["import { homedir } from \"node:os\";\nimport { join } from \"node:path\";\nimport { mkdirSync, existsSync } from \"node:fs\";\n\nconst SPORA_DIR = join(homedir(), \".spora\");\n\nexport const paths = {\n root: SPORA_DIR,\n config: join(SPORA_DIR, \"config.json\"),\n credentials: join(SPORA_DIR, \"credentials.json\"),\n spore: join(SPORA_DIR, \"spore.json\"),\n identity: join(SPORA_DIR, \"identity.json\"),\n colonyToken: join(SPORA_DIR, \"colony-token.json\"),\n browser: join(SPORA_DIR, \"browser\"),\n browserAuth: join(SPORA_DIR, \"browser\", \"auth-state.json\"),\n memory: join(SPORA_DIR, \"memory\"),\n interactions: join(SPORA_DIR, \"memory\", \"interactions\"),\n learnings: join(SPORA_DIR, \"memory\", \"learnings.json\"),\n relationships: join(SPORA_DIR, \"memory\", \"relationships.json\"),\n compacted: join(SPORA_DIR, \"memory\", \"compacted\"),\n queue: join(SPORA_DIR, \"queue\"),\n pendingPosts: join(SPORA_DIR, \"queue\", \"pending-posts.json\"),\n logs: join(SPORA_DIR, \"logs\"),\n logFile: join(SPORA_DIR, \"logs\", \"spora.log\"),\n dataDir: SPORA_DIR,\n llmKey: join(SPORA_DIR, \"llm-key\"),\n runtimePid: join(SPORA_DIR, \"runtime.pid\"),\n stopSignal: join(SPORA_DIR, \"stop\"),\n connectionToken: join(SPORA_DIR, \"connection-token\"),\n lastChatMessage: join(SPORA_DIR, \"last-chat-message.json\"),\n performance: join(SPORA_DIR, \"memory\", \"performance.json\"),\n strategy: join(SPORA_DIR, \"memory\", \"strategy.json\"),\n goals: join(SPORA_DIR, \"memory\", \"goals.json\"),\n} as const;\n\nexport function ensureDirectories(): void {\n const dirs = [\n paths.root,\n paths.browser,\n paths.memory,\n paths.interactions,\n paths.compacted,\n paths.queue,\n paths.logs,\n ];\n\n for (const dir of dirs) {\n if (!existsSync(dir)) {\n mkdirSync(dir, { recursive: true });\n }\n }\n}\n\nexport function sporaExists(): boolean {\n return existsSync(paths.config) && existsSync(paths.identity);\n}\n\nexport function hasXCredentials(): boolean {\n return existsSync(paths.credentials);\n}\n"],"mappings":";AAAA,SAAS,eAAe;AACxB,SAAS,YAAY;AACrB,SAAS,WAAW,kBAAkB;AAEtC,IAAM,YAAY,KAAK,QAAQ,GAAG,QAAQ;AAEnC,IAAM,QAAQ;AAAA,EACnB,MAAM;AAAA,EACN,QAAQ,KAAK,WAAW,aAAa;AAAA,EACrC,aAAa,KAAK,WAAW,kBAAkB;AAAA,EAC/C,OAAO,KAAK,WAAW,YAAY;AAAA,EACnC,UAAU,KAAK,WAAW,eAAe;AAAA,EACzC,aAAa,KAAK,WAAW,mBAAmB;AAAA,EAChD,SAAS,KAAK,WAAW,SAAS;AAAA,EAClC,aAAa,KAAK,WAAW,WAAW,iBAAiB;AAAA,EACzD,QAAQ,KAAK,WAAW,QAAQ;AAAA,EAChC,cAAc,KAAK,WAAW,UAAU,cAAc;AAAA,EACtD,WAAW,KAAK,WAAW,UAAU,gBAAgB;AAAA,EACrD,eAAe,KAAK,WAAW,UAAU,oBAAoB;AAAA,EAC7D,WAAW,KAAK,WAAW,UAAU,WAAW;AAAA,EAChD,OAAO,KAAK,WAAW,OAAO;AAAA,EAC9B,cAAc,KAAK,WAAW,SAAS,oBAAoB;AAAA,EAC3D,MAAM,KAAK,WAAW,MAAM;AAAA,EAC5B,SAAS,KAAK,WAAW,QAAQ,WAAW;AAAA,EAC5C,SAAS;AAAA,EACT,QAAQ,KAAK,WAAW,SAAS;AAAA,EACjC,YAAY,KAAK,WAAW,aAAa;AAAA,EACzC,YAAY,KAAK,WAAW,MAAM;AAAA,EAClC,iBAAiB,KAAK,WAAW,kBAAkB;AAAA,EACnD,iBAAiB,KAAK,WAAW,wBAAwB;AAAA,EACzD,aAAa,KAAK,WAAW,UAAU,kBAAkB;AAAA,EACzD,UAAU,KAAK,WAAW,UAAU,eAAe;AAAA,EACnD,OAAO,KAAK,WAAW,UAAU,YAAY;AAC/C;AAEO,SAAS,oBAA0B;AACxC,QAAM,OAAO;AAAA,IACX,MAAM;AAAA,IACN,MAAM;AAAA,IACN,MAAM;AAAA,IACN,MAAM;AAAA,IACN,MAAM;AAAA,IACN,MAAM;AAAA,IACN,MAAM;AAAA,EACR;AAEA,aAAW,OAAO,MAAM;AACtB,QAAI,CAAC,WAAW,GAAG,GAAG;AACpB,gBAAU,KAAK,EAAE,WAAW,KAAK,CAAC;AAAA,IACpC;AAAA,EACF;AACF;AAEO,SAAS,cAAuB;AACrC,SAAO,WAAW,MAAM,MAAM,KAAK,WAAW,MAAM,QAAQ;AAC9D;AAEO,SAAS,kBAA2B;AACzC,SAAO,WAAW,MAAM,WAAW;AACrC;","names":[]}
@@ -1,159 +0,0 @@
1
- import {
2
- loadConfig
3
- } from "./chunk-SXMDYUK3.js";
4
- import {
5
- logger
6
- } from "./chunk-J7J557HV.js";
7
- import {
8
- ensureDirectories,
9
- paths
10
- } from "./chunk-Q7YS3AIK.js";
11
-
12
- // src/scheduler/queue.ts
13
- import { readFileSync, writeFileSync, existsSync } from "fs";
14
- function loadQueue() {
15
- if (!existsSync(paths.pendingPosts)) {
16
- return { entries: [] };
17
- }
18
- return JSON.parse(readFileSync(paths.pendingPosts, "utf-8"));
19
- }
20
- function saveQueue(data) {
21
- ensureDirectories();
22
- writeFileSync(paths.pendingPosts, JSON.stringify(data, null, 2));
23
- }
24
- function nextScheduledTime() {
25
- const config = loadConfig();
26
- const now = /* @__PURE__ */ new Date();
27
- const queue = loadQueue();
28
- const pendingEntries = queue.entries.filter((e) => e.status === "pending");
29
- let lastScheduled = now;
30
- if (pendingEntries.length > 0) {
31
- const latest = new Date(
32
- pendingEntries.reduce(
33
- (max, e) => new Date(e.scheduledFor) > new Date(max.scheduledFor) ? e : max
34
- ).scheduledFor
35
- );
36
- if (latest > lastScheduled) lastScheduled = latest;
37
- }
38
- const intervalMinutes = Math.floor(
39
- (config.schedule.activeHoursEnd - config.schedule.activeHoursStart) * 60 / config.schedule.postsPerDay
40
- );
41
- const next = new Date(lastScheduled.getTime() + intervalMinutes * 60 * 1e3);
42
- if (next.getHours() >= config.schedule.activeHoursEnd) {
43
- next.setDate(next.getDate() + 1);
44
- next.setHours(config.schedule.activeHoursStart, Math.floor(Math.random() * 60), 0, 0);
45
- }
46
- if (next.getHours() < config.schedule.activeHoursStart) {
47
- next.setHours(config.schedule.activeHoursStart, Math.floor(Math.random() * 60), 0, 0);
48
- }
49
- return next.toISOString();
50
- }
51
- function addToQueue(content, scheduledFor, imageQuery) {
52
- const queue = loadQueue();
53
- const entry = {
54
- id: `post-${Date.now()}-${Math.random().toString(36).slice(2, 6)}`,
55
- content,
56
- scheduledFor: scheduledFor ?? nextScheduledTime(),
57
- status: "pending",
58
- createdAt: (/* @__PURE__ */ new Date()).toISOString(),
59
- ...imageQuery ? { imageQuery } : {}
60
- };
61
- queue.entries.push(entry);
62
- saveQueue(queue);
63
- logger.info(`Post queued: ${entry.id} scheduled for ${entry.scheduledFor}`);
64
- return entry;
65
- }
66
- async function flushQueue() {
67
- const queue = loadQueue();
68
- const now = /* @__PURE__ */ new Date();
69
- let posted = 0;
70
- let failed = 0;
71
- const { getXClient } = await import("./x-client-HUXCQOAW.js");
72
- const client = await getXClient();
73
- const STALE_THRESHOLD_MS = 5 * 60 * 1e3;
74
- for (const entry of queue.entries) {
75
- if (entry.status !== "pending") continue;
76
- const scheduledTime = new Date(entry.scheduledFor).getTime();
77
- if (scheduledTime < now.getTime() - STALE_THRESHOLD_MS) {
78
- entry.status = "expired";
79
- logger.info(`Expired stale post: ${entry.id} (was scheduled for ${entry.scheduledFor})`);
80
- }
81
- }
82
- for (const entry of queue.entries) {
83
- if (entry.status !== "pending") continue;
84
- if (new Date(entry.scheduledFor) > now) continue;
85
- try {
86
- let result;
87
- if (entry.imageQuery) {
88
- try {
89
- const { searchImage, downloadImage } = await import("./image-search-SZVMGWLN.js");
90
- const imageUrl = await searchImage(entry.imageQuery);
91
- if (imageUrl) {
92
- const imageBuffer = await downloadImage(imageUrl);
93
- result = await client.postTweetWithMedia(entry.content, imageBuffer);
94
- if (result.success) {
95
- logger.info(`Posted with image: ${entry.id}`);
96
- }
97
- }
98
- } catch (imgErr) {
99
- logger.warn(`Image attach failed for ${entry.id}, posting text only: ${imgErr.message}`);
100
- }
101
- }
102
- if (!result) {
103
- result = await client.postTweet(entry.content);
104
- }
105
- if (result.success) {
106
- entry.status = "posted";
107
- entry.postedAt = (/* @__PURE__ */ new Date()).toISOString();
108
- posted++;
109
- if (!entry.imageQuery) logger.info(`Posted: ${entry.id}`);
110
- if (result.tweetId) {
111
- try {
112
- const { trackPost } = await import("./performance-7G6R6ELJ.js");
113
- trackPost(result.tweetId, entry.content, "post");
114
- } catch {
115
- }
116
- }
117
- } else {
118
- entry.status = "failed";
119
- entry.error = result.error;
120
- failed++;
121
- logger.warn(`Failed to post: ${entry.id} - ${result.error}`);
122
- }
123
- } catch (error) {
124
- entry.status = "failed";
125
- entry.error = error.message;
126
- failed++;
127
- }
128
- await new Promise((resolve) => setTimeout(resolve, 2e3));
129
- }
130
- saveQueue(queue);
131
- const remaining = queue.entries.filter((e) => e.status === "pending").length;
132
- return { posted, failed, remaining };
133
- }
134
- function showQueue() {
135
- const queue = loadQueue();
136
- const pending = queue.entries.filter((e) => e.status === "pending");
137
- if (pending.length === 0) {
138
- console.log("Queue is empty.");
139
- return;
140
- }
141
- console.log(`
142
- ${pending.length} posts queued:
143
- `);
144
- for (const entry of pending.sort(
145
- (a, b) => new Date(a.scheduledFor).getTime() - new Date(b.scheduledFor).getTime()
146
- )) {
147
- const time = new Date(entry.scheduledFor).toLocaleString();
148
- const preview = entry.content.length > 60 ? entry.content.slice(0, 60) + "..." : entry.content;
149
- console.log(` [${time}] ${preview}`);
150
- }
151
- console.log();
152
- }
153
-
154
- export {
155
- addToQueue,
156
- flushQueue,
157
- showQueue
158
- };
159
- //# sourceMappingURL=chunk-QHFM2YW6.js.map
@@ -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 imageQuery?: string; // Optional image search query to attach when posting\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, imageQuery?: 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 ...(imageQuery ? { imageQuery } : {}),\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 // Expire stale posts (scheduled more than 5 minutes ago — from previous sessions)\n const STALE_THRESHOLD_MS = 5 * 60 * 1000;\n for (const entry of queue.entries) {\n if (entry.status !== \"pending\") continue;\n const scheduledTime = new Date(entry.scheduledFor).getTime();\n if (scheduledTime < now.getTime() - STALE_THRESHOLD_MS) {\n entry.status = \"expired\";\n logger.info(`Expired stale post: ${entry.id} (was scheduled for ${entry.scheduledFor})`);\n }\n }\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 let result;\n\n // If entry has an imageQuery, search and attach image\n if (entry.imageQuery) {\n try {\n const { searchImage, downloadImage } = await import(\"../utils/image-search.js\");\n const imageUrl = await searchImage(entry.imageQuery);\n if (imageUrl) {\n const imageBuffer = await downloadImage(imageUrl);\n result = await client.postTweetWithMedia(entry.content, imageBuffer);\n if (result.success) {\n logger.info(`Posted with image: ${entry.id}`);\n }\n }\n } catch (imgErr) {\n logger.warn(`Image attach failed for ${entry.id}, posting text only: ${(imgErr as Error).message}`);\n }\n }\n\n // Fall back to text-only if no image or image failed\n if (!result) {\n result = await client.postTweet(entry.content);\n }\n\n if (result.success) {\n entry.status = \"posted\";\n entry.postedAt = new Date().toISOString();\n posted++;\n if (!entry.imageQuery) logger.info(`Posted: ${entry.id}`);\n // Track for performance monitoring\n if (result.tweetId) {\n try {\n const { trackPost } = await import(\"../memory/performance.js\");\n trackPost(result.tweetId, entry.content, \"post\");\n } catch { /* non-critical */ }\n }\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,44 +0,0 @@
1
- import {
2
- ensureDirectories,
3
- paths
4
- } from "./chunk-Q7YS3AIK.js";
5
-
6
- // src/memory/goals.ts
7
- import { existsSync, readFileSync, writeFileSync } from "fs";
8
- function defaultGoalTracker() {
9
- return {
10
- goals: [],
11
- lastReviewed: (/* @__PURE__ */ new Date()).toISOString()
12
- };
13
- }
14
- function loadGoals() {
15
- if (!existsSync(paths.goals)) {
16
- return defaultGoalTracker();
17
- }
18
- try {
19
- return { ...defaultGoalTracker(), ...JSON.parse(readFileSync(paths.goals, "utf-8")) };
20
- } catch {
21
- return defaultGoalTracker();
22
- }
23
- }
24
- function saveGoals(tracker) {
25
- ensureDirectories();
26
- tracker.goals = tracker.goals.slice(-10);
27
- writeFileSync(paths.goals, JSON.stringify(tracker, null, 2));
28
- }
29
- function renderGoalsForPrompt() {
30
- const tracker = loadGoals();
31
- if (tracker.goals.length === 0) return "";
32
- const lines = ["**Goal Progress:**"];
33
- for (const g of tracker.goals) {
34
- lines.push(`- ${g.goal}: ${g.progress}`);
35
- }
36
- return lines.join("\n");
37
- }
38
-
39
- export {
40
- loadGoals,
41
- saveGoals,
42
- renderGoalsForPrompt
43
- };
44
- //# sourceMappingURL=chunk-R7PAD4OL.js.map
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/memory/goals.ts"],"sourcesContent":["import { existsSync, readFileSync, writeFileSync } from \"node:fs\";\nimport { paths, ensureDirectories } from \"../utils/paths.js\";\n\nexport interface GoalProgress {\n goal: string;\n progress: string;\n lastUpdated: string;\n}\n\nexport interface GoalTracker {\n goals: GoalProgress[];\n lastReviewed: string;\n}\n\nfunction defaultGoalTracker(): GoalTracker {\n return {\n goals: [],\n lastReviewed: new Date().toISOString(),\n };\n}\n\nexport function loadGoals(): GoalTracker {\n if (!existsSync(paths.goals)) {\n return defaultGoalTracker();\n }\n try {\n return { ...defaultGoalTracker(), ...JSON.parse(readFileSync(paths.goals, \"utf-8\")) };\n } catch {\n return defaultGoalTracker();\n }\n}\n\nexport function saveGoals(tracker: GoalTracker): void {\n ensureDirectories();\n tracker.goals = tracker.goals.slice(-10);\n writeFileSync(paths.goals, JSON.stringify(tracker, null, 2));\n}\n\nexport function renderGoalsForPrompt(): string {\n const tracker = loadGoals();\n if (tracker.goals.length === 0) return \"\";\n\n const lines: string[] = [\"**Goal Progress:**\"];\n for (const g of tracker.goals) {\n lines.push(`- ${g.goal}: ${g.progress}`);\n }\n return lines.join(\"\\n\");\n}\n"],"mappings":";;;;;;AAAA,SAAS,YAAY,cAAc,qBAAqB;AAcxD,SAAS,qBAAkC;AACzC,SAAO;AAAA,IACL,OAAO,CAAC;AAAA,IACR,eAAc,oBAAI,KAAK,GAAE,YAAY;AAAA,EACvC;AACF;AAEO,SAAS,YAAyB;AACvC,MAAI,CAAC,WAAW,MAAM,KAAK,GAAG;AAC5B,WAAO,mBAAmB;AAAA,EAC5B;AACA,MAAI;AACF,WAAO,EAAE,GAAG,mBAAmB,GAAG,GAAG,KAAK,MAAM,aAAa,MAAM,OAAO,OAAO,CAAC,EAAE;AAAA,EACtF,QAAQ;AACN,WAAO,mBAAmB;AAAA,EAC5B;AACF;AAEO,SAAS,UAAU,SAA4B;AACpD,oBAAkB;AAClB,UAAQ,QAAQ,QAAQ,MAAM,MAAM,GAAG;AACvC,gBAAc,MAAM,OAAO,KAAK,UAAU,SAAS,MAAM,CAAC,CAAC;AAC7D;AAEO,SAAS,uBAA+B;AAC7C,QAAM,UAAU,UAAU;AAC1B,MAAI,QAAQ,MAAM,WAAW,EAAG,QAAO;AAEvC,QAAM,QAAkB,CAAC,oBAAoB;AAC7C,aAAW,KAAK,QAAQ,OAAO;AAC7B,UAAM,KAAK,KAAK,EAAE,IAAI,KAAK,EAAE,QAAQ,EAAE;AAAA,EACzC;AACA,SAAO,MAAM,KAAK,IAAI;AACxB;","names":[]}
@@ -1,129 +0,0 @@
1
- import {
2
- ensureDirectories,
3
- paths
4
- } from "./chunk-Q7YS3AIK.js";
5
-
6
- // src/memory/index.ts
7
- import { readFileSync, writeFileSync, appendFileSync, existsSync, readdirSync } from "fs";
8
- import { join } from "path";
9
- function todayLogPath() {
10
- const date = (/* @__PURE__ */ new Date()).toISOString().split("T")[0];
11
- return join(paths.interactions, `${date}.jsonl`);
12
- }
13
- function logInteraction(entry) {
14
- ensureDirectories();
15
- appendFileSync(todayLogPath(), JSON.stringify(entry) + "\n");
16
- }
17
- function getInteractions(date) {
18
- const targetDate = date ?? (/* @__PURE__ */ new Date()).toISOString().split("T")[0];
19
- const filePath = join(paths.interactions, `${targetDate}.jsonl`);
20
- if (!existsSync(filePath)) return [];
21
- return readFileSync(filePath, "utf-8").trim().split("\n").filter(Boolean).map((line) => JSON.parse(line));
22
- }
23
- function getRecentInteractions(count = 20) {
24
- ensureDirectories();
25
- const files = readdirSync(paths.interactions).filter((f) => f.endsWith(".jsonl")).sort().reverse();
26
- const entries = [];
27
- for (const file of files) {
28
- if (entries.length >= count) break;
29
- const filePath = join(paths.interactions, file);
30
- const lines = readFileSync(filePath, "utf-8").trim().split("\n").filter(Boolean);
31
- for (const line of lines.reverse()) {
32
- if (entries.length >= count) break;
33
- entries.push(JSON.parse(line));
34
- }
35
- }
36
- return entries;
37
- }
38
- function loadLearnings() {
39
- if (!existsSync(paths.learnings)) {
40
- return { learnings: [] };
41
- }
42
- return JSON.parse(readFileSync(paths.learnings, "utf-8"));
43
- }
44
- function saveLearnings(data) {
45
- ensureDirectories();
46
- writeFileSync(paths.learnings, JSON.stringify(data, null, 2));
47
- }
48
- function addLearning(content, source, tags = []) {
49
- const data = loadLearnings();
50
- data.learnings.push({
51
- id: `learn-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`,
52
- timestamp: (/* @__PURE__ */ new Date()).toISOString(),
53
- content,
54
- source,
55
- tags
56
- });
57
- saveLearnings(data);
58
- }
59
- function loadRelationships() {
60
- if (!existsSync(paths.relationships)) {
61
- return { accounts: {} };
62
- }
63
- return JSON.parse(readFileSync(paths.relationships, "utf-8"));
64
- }
65
- function saveRelationships(data) {
66
- ensureDirectories();
67
- writeFileSync(paths.relationships, JSON.stringify(data, null, 2));
68
- }
69
- function getActiveConversations(hours = 24) {
70
- const cutoff = new Date(Date.now() - hours * 60 * 60 * 1e3);
71
- const recent = getRecentInteractions(50);
72
- const conversations = [];
73
- const seenHandles = /* @__PURE__ */ new Set();
74
- for (const entry of recent) {
75
- if (entry.type !== "mention_received") continue;
76
- if (!entry.targetHandle || !entry.content) continue;
77
- if (new Date(entry.timestamp) < cutoff) continue;
78
- if (seenHandles.has(entry.targetHandle)) continue;
79
- seenHandles.add(entry.targetHandle);
80
- const timeDiff = Date.now() - new Date(entry.timestamp).getTime();
81
- const minutesAgo = Math.floor(timeDiff / 6e4);
82
- const timeAgo = minutesAgo < 60 ? `${minutesAgo}m ago` : `${Math.floor(minutesAgo / 60)}h ago`;
83
- conversations.push({
84
- handle: entry.targetHandle,
85
- content: entry.content.slice(0, 100),
86
- timeAgo,
87
- tweetId: entry.tweetId
88
- });
89
- }
90
- return conversations;
91
- }
92
- function updateRelationship(userId, update) {
93
- const data = loadRelationships();
94
- const existing = data.accounts[userId];
95
- if (existing) {
96
- data.accounts[userId] = {
97
- ...existing,
98
- ...update,
99
- lastInteraction: (/* @__PURE__ */ new Date()).toISOString(),
100
- interactionCount: existing.interactionCount + 1
101
- };
102
- } else {
103
- data.accounts[userId] = {
104
- handle: update.handle,
105
- firstSeen: (/* @__PURE__ */ new Date()).toISOString(),
106
- lastInteraction: (/* @__PURE__ */ new Date()).toISOString(),
107
- interactionCount: 1,
108
- sentiment: update.sentiment ?? 0,
109
- tags: update.tags ?? [],
110
- notes: update.notes ?? [],
111
- isSpore: update.isSpore ?? false
112
- };
113
- }
114
- saveRelationships(data);
115
- }
116
-
117
- export {
118
- logInteraction,
119
- getInteractions,
120
- getRecentInteractions,
121
- loadLearnings,
122
- saveLearnings,
123
- addLearning,
124
- loadRelationships,
125
- saveRelationships,
126
- getActiveConversations,
127
- updateRelationship
128
- };
129
- //# sourceMappingURL=chunk-RNVEWVDN.js.map
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/memory/index.ts"],"sourcesContent":["import { readFileSync, writeFileSync, appendFileSync, existsSync, readdirSync } from \"node:fs\";\nimport { join } from \"node:path\";\nimport { paths, ensureDirectories } from \"../utils/paths.js\";\n\nexport interface InteractionEntry {\n id: string;\n timestamp: string;\n type: \"post\" | \"reply\" | \"like\" | \"retweet\" | \"follow\" | \"mention_received\";\n tweetId?: string;\n targetUserId?: string;\n targetHandle?: string;\n content?: string;\n inReplyTo?: string;\n sentiment?: \"positive\" | \"negative\" | \"neutral\";\n creditsUsed: number;\n success: boolean;\n error?: string;\n}\n\nexport interface Learning {\n id: string;\n timestamp: string;\n content: string;\n source: string;\n tags: string[];\n}\n\nexport interface Relationship {\n handle: string;\n firstSeen: string;\n lastInteraction: string;\n interactionCount: number;\n sentiment: number;\n tags: string[];\n notes: string[];\n isSpore: boolean;\n}\n\nexport interface RelationshipsData {\n accounts: Record<string, Relationship>;\n}\n\nexport interface LearningsData {\n learnings: Learning[];\n}\n\n// --- Interaction Log ---\n\nfunction todayLogPath(): string {\n const date = new Date().toISOString().split(\"T\")[0];\n return join(paths.interactions, `${date}.jsonl`);\n}\n\nexport function logInteraction(entry: InteractionEntry): void {\n ensureDirectories();\n appendFileSync(todayLogPath(), JSON.stringify(entry) + \"\\n\");\n}\n\nexport function getInteractions(date?: string): InteractionEntry[] {\n const targetDate = date ?? new Date().toISOString().split(\"T\")[0];\n const filePath = join(paths.interactions, `${targetDate}.jsonl`);\n\n if (!existsSync(filePath)) return [];\n\n return readFileSync(filePath, \"utf-8\")\n .trim()\n .split(\"\\n\")\n .filter(Boolean)\n .map((line) => JSON.parse(line) as InteractionEntry);\n}\n\nexport function getRecentInteractions(count: number = 20): InteractionEntry[] {\n ensureDirectories();\n const files = readdirSync(paths.interactions)\n .filter((f) => f.endsWith(\".jsonl\"))\n .sort()\n .reverse();\n\n const entries: InteractionEntry[] = [];\n for (const file of files) {\n if (entries.length >= count) break;\n const filePath = join(paths.interactions, file);\n const lines = readFileSync(filePath, \"utf-8\").trim().split(\"\\n\").filter(Boolean);\n for (const line of lines.reverse()) {\n if (entries.length >= count) break;\n entries.push(JSON.parse(line) as InteractionEntry);\n }\n }\n\n return entries;\n}\n\n// --- Learnings ---\n\nexport function loadLearnings(): LearningsData {\n if (!existsSync(paths.learnings)) {\n return { learnings: [] };\n }\n return JSON.parse(readFileSync(paths.learnings, \"utf-8\")) as LearningsData;\n}\n\nexport function saveLearnings(data: LearningsData): void {\n ensureDirectories();\n writeFileSync(paths.learnings, JSON.stringify(data, null, 2));\n}\n\nexport function addLearning(content: string, source: string, tags: string[] = []): void {\n const data = loadLearnings();\n data.learnings.push({\n id: `learn-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`,\n timestamp: new Date().toISOString(),\n content,\n source,\n tags,\n });\n saveLearnings(data);\n}\n\n// --- Relationships ---\n\nexport function loadRelationships(): RelationshipsData {\n if (!existsSync(paths.relationships)) {\n return { accounts: {} };\n }\n return JSON.parse(readFileSync(paths.relationships, \"utf-8\")) as RelationshipsData;\n}\n\nexport function saveRelationships(data: RelationshipsData): void {\n ensureDirectories();\n writeFileSync(paths.relationships, JSON.stringify(data, null, 2));\n}\n\nexport interface ActiveConversation {\n handle: string;\n content: string;\n timeAgo: string;\n tweetId?: string;\n}\n\nexport function getActiveConversations(hours: number = 24): ActiveConversation[] {\n const cutoff = new Date(Date.now() - hours * 60 * 60 * 1000);\n const recent = getRecentInteractions(50);\n\n // Find mentions and replies directed at us\n const conversations: ActiveConversation[] = [];\n const seenHandles = new Set<string>();\n\n for (const entry of recent) {\n if (entry.type !== \"mention_received\") continue;\n if (!entry.targetHandle || !entry.content) continue;\n if (new Date(entry.timestamp) < cutoff) continue;\n if (seenHandles.has(entry.targetHandle)) continue;\n seenHandles.add(entry.targetHandle);\n\n const timeDiff = Date.now() - new Date(entry.timestamp).getTime();\n const minutesAgo = Math.floor(timeDiff / 60000);\n const timeAgo = minutesAgo < 60\n ? `${minutesAgo}m ago`\n : `${Math.floor(minutesAgo / 60)}h ago`;\n\n conversations.push({\n handle: entry.targetHandle,\n content: entry.content.slice(0, 100),\n timeAgo,\n tweetId: entry.tweetId,\n });\n }\n\n return conversations;\n}\n\nexport function updateRelationship(\n userId: string,\n update: Partial<Relationship> & { handle: string }\n): void {\n const data = loadRelationships();\n const existing = data.accounts[userId];\n\n if (existing) {\n data.accounts[userId] = {\n ...existing,\n ...update,\n lastInteraction: new Date().toISOString(),\n interactionCount: existing.interactionCount + 1,\n };\n } else {\n data.accounts[userId] = {\n handle: update.handle,\n firstSeen: new Date().toISOString(),\n lastInteraction: new Date().toISOString(),\n interactionCount: 1,\n sentiment: update.sentiment ?? 0,\n tags: update.tags ?? [],\n notes: update.notes ?? [],\n isSpore: update.isSpore ?? false,\n };\n }\n\n saveRelationships(data);\n}\n"],"mappings":"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","names":[]}
@@ -1,82 +0,0 @@
1
- import {
2
- loadConfig
3
- } from "./chunk-SXMDYUK3.js";
4
- import {
5
- logger
6
- } from "./chunk-J7J557HV.js";
7
- import {
8
- paths
9
- } from "./chunk-Q7YS3AIK.js";
10
-
11
- // src/runtime/llm.ts
12
- import Anthropic from "@anthropic-ai/sdk";
13
- import { readFileSync, existsSync } from "fs";
14
- var client = null;
15
- function getLLMApiKey() {
16
- if (process.env.ANTHROPIC_API_KEY) {
17
- return process.env.ANTHROPIC_API_KEY;
18
- }
19
- if (existsSync(paths.llmKey)) {
20
- return readFileSync(paths.llmKey, "utf-8").trim();
21
- }
22
- return null;
23
- }
24
- function hasLLMKey() {
25
- return getLLMApiKey() !== null;
26
- }
27
- function getClient() {
28
- if (client) return client;
29
- const apiKey = getLLMApiKey();
30
- if (!apiKey) {
31
- throw new Error("No LLM API key configured. Run `spora set-llm-key` first.");
32
- }
33
- client = new Anthropic({ apiKey });
34
- return client;
35
- }
36
- async function generateResponse(systemPrompt, userMessage, options) {
37
- const config = loadConfig();
38
- const model = config.llm?.model ?? "claude-sonnet-4-20250514";
39
- logger.info(`Calling LLM (${model})...`);
40
- const anthropic = getClient();
41
- const response = await anthropic.messages.create({
42
- model,
43
- max_tokens: 2048,
44
- temperature: options?.temperature ?? 1,
45
- system: systemPrompt,
46
- messages: [{ role: "user", content: userMessage }]
47
- });
48
- const textBlock = response.content.find((b) => b.type === "text");
49
- const content = textBlock ? textBlock.text : "";
50
- logger.info(`LLM response: ${response.usage.input_tokens} in, ${response.usage.output_tokens} out`);
51
- return {
52
- content,
53
- inputTokens: response.usage.input_tokens,
54
- outputTokens: response.usage.output_tokens
55
- };
56
- }
57
- async function chat(systemPrompt, messages) {
58
- const config = loadConfig();
59
- const model = config.llm?.model ?? "claude-sonnet-4-20250514";
60
- const anthropic = getClient();
61
- const response = await anthropic.messages.create({
62
- model,
63
- max_tokens: 1024,
64
- system: systemPrompt,
65
- messages
66
- });
67
- const textBlock = response.content.find((b) => b.type === "text");
68
- const content = textBlock ? textBlock.text : "";
69
- return {
70
- content,
71
- inputTokens: response.usage.input_tokens,
72
- outputTokens: response.usage.output_tokens
73
- };
74
- }
75
-
76
- export {
77
- getLLMApiKey,
78
- hasLLMKey,
79
- generateResponse,
80
- chat
81
- };
82
- //# sourceMappingURL=chunk-SUFTVQME.js.map
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/runtime/llm.ts"],"sourcesContent":["import Anthropic from \"@anthropic-ai/sdk\";\nimport { readFileSync, existsSync } from \"node:fs\";\nimport { paths } from \"../utils/paths.js\";\nimport { loadConfig } from \"../utils/config.js\";\nimport { logger } from \"../utils/logger.js\";\n\nlet client: Anthropic | null = null;\n\nexport function getLLMApiKey(): string | null {\n // Check env first, then file\n if (process.env.ANTHROPIC_API_KEY) {\n return process.env.ANTHROPIC_API_KEY;\n }\n if (existsSync(paths.llmKey)) {\n return readFileSync(paths.llmKey, \"utf-8\").trim();\n }\n return null;\n}\n\nexport function hasLLMKey(): boolean {\n return getLLMApiKey() !== null;\n}\n\nfunction getClient(): Anthropic {\n if (client) return client;\n const apiKey = getLLMApiKey();\n if (!apiKey) {\n throw new Error(\"No LLM API key configured. Run `spora set-llm-key` first.\");\n }\n client = new Anthropic({ apiKey });\n return client;\n}\n\nexport interface LLMResponse {\n content: string;\n inputTokens: number;\n outputTokens: number;\n}\n\nexport async function generateResponse(\n systemPrompt: string,\n userMessage: string,\n options?: { temperature?: number },\n): Promise<LLMResponse> {\n const config = loadConfig();\n const model = config.llm?.model ?? \"claude-sonnet-4-20250514\";\n\n logger.info(`Calling LLM (${model})...`);\n\n const anthropic = getClient();\n const response = await anthropic.messages.create({\n model,\n max_tokens: 2048,\n temperature: options?.temperature ?? 1.0,\n system: systemPrompt,\n messages: [{ role: \"user\", content: userMessage }],\n });\n\n const textBlock = response.content.find((b) => b.type === \"text\");\n const content = textBlock ? textBlock.text : \"\";\n\n logger.info(`LLM response: ${response.usage.input_tokens} in, ${response.usage.output_tokens} out`);\n\n return {\n content,\n inputTokens: response.usage.input_tokens,\n outputTokens: response.usage.output_tokens,\n };\n}\n\nexport async function chat(\n systemPrompt: string,\n messages: Array<{ role: \"user\" | \"assistant\"; content: string }>,\n): Promise<LLMResponse> {\n const config = loadConfig();\n const model = config.llm?.model ?? \"claude-sonnet-4-20250514\";\n\n const anthropic = getClient();\n const response = await anthropic.messages.create({\n model,\n max_tokens: 1024,\n system: systemPrompt,\n messages,\n });\n\n const textBlock = response.content.find((b) => b.type === \"text\");\n const content = textBlock ? textBlock.text : \"\";\n\n return {\n content,\n inputTokens: response.usage.input_tokens,\n outputTokens: response.usage.output_tokens,\n };\n}\n"],"mappings":";;;;;;;;;;;AAAA,OAAO,eAAe;AACtB,SAAS,cAAc,kBAAkB;AAKzC,IAAI,SAA2B;AAExB,SAAS,eAA8B;AAE5C,MAAI,QAAQ,IAAI,mBAAmB;AACjC,WAAO,QAAQ,IAAI;AAAA,EACrB;AACA,MAAI,WAAW,MAAM,MAAM,GAAG;AAC5B,WAAO,aAAa,MAAM,QAAQ,OAAO,EAAE,KAAK;AAAA,EAClD;AACA,SAAO;AACT;AAEO,SAAS,YAAqB;AACnC,SAAO,aAAa,MAAM;AAC5B;AAEA,SAAS,YAAuB;AAC9B,MAAI,OAAQ,QAAO;AACnB,QAAM,SAAS,aAAa;AAC5B,MAAI,CAAC,QAAQ;AACX,UAAM,IAAI,MAAM,2DAA2D;AAAA,EAC7E;AACA,WAAS,IAAI,UAAU,EAAE,OAAO,CAAC;AACjC,SAAO;AACT;AAQA,eAAsB,iBACpB,cACA,aACA,SACsB;AACtB,QAAM,SAAS,WAAW;AAC1B,QAAM,QAAQ,OAAO,KAAK,SAAS;AAEnC,SAAO,KAAK,gBAAgB,KAAK,MAAM;AAEvC,QAAM,YAAY,UAAU;AAC5B,QAAM,WAAW,MAAM,UAAU,SAAS,OAAO;AAAA,IAC/C;AAAA,IACA,YAAY;AAAA,IACZ,aAAa,SAAS,eAAe;AAAA,IACrC,QAAQ;AAAA,IACR,UAAU,CAAC,EAAE,MAAM,QAAQ,SAAS,YAAY,CAAC;AAAA,EACnD,CAAC;AAED,QAAM,YAAY,SAAS,QAAQ,KAAK,CAAC,MAAM,EAAE,SAAS,MAAM;AAChE,QAAM,UAAU,YAAY,UAAU,OAAO;AAE7C,SAAO,KAAK,iBAAiB,SAAS,MAAM,YAAY,QAAQ,SAAS,MAAM,aAAa,MAAM;AAElG,SAAO;AAAA,IACL;AAAA,IACA,aAAa,SAAS,MAAM;AAAA,IAC5B,cAAc,SAAS,MAAM;AAAA,EAC/B;AACF;AAEA,eAAsB,KACpB,cACA,UACsB;AACtB,QAAM,SAAS,WAAW;AAC1B,QAAM,QAAQ,OAAO,KAAK,SAAS;AAEnC,QAAM,YAAY,UAAU;AAC5B,QAAM,WAAW,MAAM,UAAU,SAAS,OAAO;AAAA,IAC/C;AAAA,IACA,YAAY;AAAA,IACZ,QAAQ;AAAA,IACR;AAAA,EACF,CAAC;AAED,QAAM,YAAY,SAAS,QAAQ,KAAK,CAAC,MAAM,EAAE,SAAS,MAAM;AAChE,QAAM,UAAU,YAAY,UAAU,OAAO;AAE7C,SAAO;AAAA,IACL;AAAA,IACA,aAAa,SAAS,MAAM;AAAA,IAC5B,cAAc,SAAS,MAAM;AAAA,EAC/B;AACF;","names":[]}
@@ -1,80 +0,0 @@
1
- import {
2
- ensureDirectories,
3
- paths
4
- } from "./chunk-Q7YS3AIK.js";
5
-
6
- // src/utils/config.ts
7
- import { readFileSync, writeFileSync, existsSync } from "fs";
8
- import { z } from "zod";
9
- var ConfigSchema = z.object({
10
- version: z.literal(1),
11
- xMethod: z.enum(["api", "browser"]),
12
- xApiTier: z.enum(["free", "basic"]).optional(),
13
- credits: z.object({
14
- monthlyPostLimit: z.number(),
15
- postsUsedThisMonth: z.number(),
16
- resetDate: z.string()
17
- }),
18
- schedule: z.object({
19
- postsPerDay: z.number(),
20
- activeHoursStart: z.number().min(0).max(23),
21
- activeHoursEnd: z.number().min(0).max(23),
22
- timezone: z.string()
23
- }),
24
- llm: z.object({
25
- provider: z.enum(["anthropic", "openai"]).default("anthropic"),
26
- model: z.string().default("claude-sonnet-4-20250514")
27
- }).optional(),
28
- runtime: z.object({
29
- heartbeatIntervalMs: z.number().default(36e5),
30
- actionsPerHeartbeat: z.number().default(3),
31
- enabled: z.boolean().default(false)
32
- }).optional(),
33
- connection: z.object({
34
- token: z.string().optional(),
35
- apiEndpoint: z.string().default("https://spora.dev/api/v1"),
36
- lastSync: z.string().optional(),
37
- configVersion: z.number().default(0)
38
- }).optional()
39
- });
40
- function loadConfig() {
41
- if (!existsSync(paths.config)) {
42
- throw new Error("Spora not initialized. Run `spora init` first.");
43
- }
44
- const raw = readFileSync(paths.config, "utf-8");
45
- return ConfigSchema.parse(JSON.parse(raw));
46
- }
47
- function saveConfig(config) {
48
- ensureDirectories();
49
- ConfigSchema.parse(config);
50
- writeFileSync(paths.config, JSON.stringify(config, null, 2));
51
- }
52
- function createDefaultConfig(overrides) {
53
- const monthlyLimit = overrides.xApiTier === "basic" ? 1e4 : 500;
54
- const now = /* @__PURE__ */ new Date();
55
- const resetDate = new Date(now.getFullYear(), now.getMonth() + 1, 1).toISOString();
56
- return {
57
- version: 1,
58
- xMethod: overrides.xMethod,
59
- xApiTier: overrides.xApiTier,
60
- credits: {
61
- monthlyPostLimit: monthlyLimit,
62
- postsUsedThisMonth: 0,
63
- resetDate
64
- },
65
- schedule: {
66
- postsPerDay: Math.floor(monthlyLimit / 30),
67
- activeHoursStart: 8,
68
- activeHoursEnd: 22,
69
- timezone: overrides.timezone ?? Intl.DateTimeFormat().resolvedOptions().timeZone
70
- }
71
- };
72
- }
73
-
74
- export {
75
- ConfigSchema,
76
- loadConfig,
77
- saveConfig,
78
- createDefaultConfig
79
- };
80
- //# sourceMappingURL=chunk-SXMDYUK3.js.map
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/utils/config.ts"],"sourcesContent":["import { readFileSync, writeFileSync, existsSync } from \"node:fs\";\nimport { z } from \"zod\";\nimport { paths, ensureDirectories } from \"./paths.js\";\n\nexport const ConfigSchema = z.object({\n version: z.literal(1),\n xMethod: z.enum([\"api\", \"browser\"]),\n xApiTier: z.enum([\"free\", \"basic\"]).optional(),\n\n credits: z.object({\n monthlyPostLimit: z.number(),\n postsUsedThisMonth: z.number(),\n resetDate: z.string(),\n }),\n\n schedule: z.object({\n postsPerDay: z.number(),\n activeHoursStart: z.number().min(0).max(23),\n activeHoursEnd: z.number().min(0).max(23),\n timezone: z.string(),\n }),\n\n llm: z.object({\n provider: z.enum([\"anthropic\", \"openai\"]).default(\"anthropic\"),\n model: z.string().default(\"claude-sonnet-4-20250514\"),\n }).optional(),\n\n runtime: z.object({\n heartbeatIntervalMs: z.number().default(3_600_000),\n actionsPerHeartbeat: z.number().default(3),\n enabled: z.boolean().default(false),\n }).optional(),\n\n connection: z.object({\n token: z.string().optional(),\n apiEndpoint: z.string().default(\"https://spora.dev/api/v1\"),\n lastSync: z.string().optional(),\n configVersion: z.number().default(0),\n }).optional(),\n});\n\nexport type Config = z.infer<typeof ConfigSchema>;\n\nexport function loadConfig(): Config {\n if (!existsSync(paths.config)) {\n throw new Error(\"Spora not initialized. Run `spora init` first.\");\n }\n const raw = readFileSync(paths.config, \"utf-8\");\n return ConfigSchema.parse(JSON.parse(raw));\n}\n\nexport function saveConfig(config: Config): void {\n ensureDirectories();\n ConfigSchema.parse(config);\n writeFileSync(paths.config, JSON.stringify(config, null, 2));\n}\n\nexport function createDefaultConfig(overrides: {\n xMethod: \"api\" | \"browser\";\n xApiTier?: \"free\" | \"basic\";\n timezone?: string;\n}): Config {\n const monthlyLimit = overrides.xApiTier === \"basic\" ? 10000 : 500;\n const now = new Date();\n const resetDate = new Date(now.getFullYear(), now.getMonth() + 1, 1).toISOString();\n\n return {\n version: 1,\n xMethod: overrides.xMethod,\n xApiTier: overrides.xApiTier,\n credits: {\n monthlyPostLimit: monthlyLimit,\n postsUsedThisMonth: 0,\n resetDate,\n },\n schedule: {\n postsPerDay: Math.floor(monthlyLimit / 30),\n activeHoursStart: 8,\n activeHoursEnd: 22,\n timezone: overrides.timezone ?? Intl.DateTimeFormat().resolvedOptions().timeZone,\n },\n };\n}\n"],"mappings":";;;;;;AAAA,SAAS,cAAc,eAAe,kBAAkB;AACxD,SAAS,SAAS;AAGX,IAAM,eAAe,EAAE,OAAO;AAAA,EACnC,SAAS,EAAE,QAAQ,CAAC;AAAA,EACpB,SAAS,EAAE,KAAK,CAAC,OAAO,SAAS,CAAC;AAAA,EAClC,UAAU,EAAE,KAAK,CAAC,QAAQ,OAAO,CAAC,EAAE,SAAS;AAAA,EAE7C,SAAS,EAAE,OAAO;AAAA,IAChB,kBAAkB,EAAE,OAAO;AAAA,IAC3B,oBAAoB,EAAE,OAAO;AAAA,IAC7B,WAAW,EAAE,OAAO;AAAA,EACtB,CAAC;AAAA,EAED,UAAU,EAAE,OAAO;AAAA,IACjB,aAAa,EAAE,OAAO;AAAA,IACtB,kBAAkB,EAAE,OAAO,EAAE,IAAI,CAAC,EAAE,IAAI,EAAE;AAAA,IAC1C,gBAAgB,EAAE,OAAO,EAAE,IAAI,CAAC,EAAE,IAAI,EAAE;AAAA,IACxC,UAAU,EAAE,OAAO;AAAA,EACrB,CAAC;AAAA,EAED,KAAK,EAAE,OAAO;AAAA,IACZ,UAAU,EAAE,KAAK,CAAC,aAAa,QAAQ,CAAC,EAAE,QAAQ,WAAW;AAAA,IAC7D,OAAO,EAAE,OAAO,EAAE,QAAQ,0BAA0B;AAAA,EACtD,CAAC,EAAE,SAAS;AAAA,EAEZ,SAAS,EAAE,OAAO;AAAA,IAChB,qBAAqB,EAAE,OAAO,EAAE,QAAQ,IAAS;AAAA,IACjD,qBAAqB,EAAE,OAAO,EAAE,QAAQ,CAAC;AAAA,IACzC,SAAS,EAAE,QAAQ,EAAE,QAAQ,KAAK;AAAA,EACpC,CAAC,EAAE,SAAS;AAAA,EAEZ,YAAY,EAAE,OAAO;AAAA,IACnB,OAAO,EAAE,OAAO,EAAE,SAAS;AAAA,IAC3B,aAAa,EAAE,OAAO,EAAE,QAAQ,0BAA0B;AAAA,IAC1D,UAAU,EAAE,OAAO,EAAE,SAAS;AAAA,IAC9B,eAAe,EAAE,OAAO,EAAE,QAAQ,CAAC;AAAA,EACrC,CAAC,EAAE,SAAS;AACd,CAAC;AAIM,SAAS,aAAqB;AACnC,MAAI,CAAC,WAAW,MAAM,MAAM,GAAG;AAC7B,UAAM,IAAI,MAAM,gDAAgD;AAAA,EAClE;AACA,QAAM,MAAM,aAAa,MAAM,QAAQ,OAAO;AAC9C,SAAO,aAAa,MAAM,KAAK,MAAM,GAAG,CAAC;AAC3C;AAEO,SAAS,WAAW,QAAsB;AAC/C,oBAAkB;AAClB,eAAa,MAAM,MAAM;AACzB,gBAAc,MAAM,QAAQ,KAAK,UAAU,QAAQ,MAAM,CAAC,CAAC;AAC7D;AAEO,SAAS,oBAAoB,WAIzB;AACT,QAAM,eAAe,UAAU,aAAa,UAAU,MAAQ;AAC9D,QAAM,MAAM,oBAAI,KAAK;AACrB,QAAM,YAAY,IAAI,KAAK,IAAI,YAAY,GAAG,IAAI,SAAS,IAAI,GAAG,CAAC,EAAE,YAAY;AAEjF,SAAO;AAAA,IACL,SAAS;AAAA,IACT,SAAS,UAAU;AAAA,IACnB,UAAU,UAAU;AAAA,IACpB,SAAS;AAAA,MACP,kBAAkB;AAAA,MAClB,oBAAoB;AAAA,MACpB;AAAA,IACF;AAAA,IACA,UAAU;AAAA,MACR,aAAa,KAAK,MAAM,eAAe,EAAE;AAAA,MACzC,kBAAkB;AAAA,MAClB,gBAAgB;AAAA,MAChB,UAAU,UAAU,YAAY,KAAK,eAAe,EAAE,gBAAgB,EAAE;AAAA,IAC1E;AAAA,EACF;AACF;","names":[]}