spora 0.7.4 → 0.7.6

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-E3DWYRJM.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-JBYZ7K56.js → chunk-BBXHECZ5.js} +2 -2
  6. package/dist/{chunk-WN35MRMF.js → chunk-CAWWG3MD.js} +2 -2
  7. package/dist/chunk-CP6JWCLY.js +171 -0
  8. package/dist/chunk-CP6JWCLY.js.map +1 -0
  9. package/dist/{chunk-T7L2L7ZL.js → chunk-D47OFTEK.js} +2 -2
  10. package/dist/{chunk-Q3YXJ2C6.js → chunk-E5PEY36J.js} +408 -63
  11. package/dist/chunk-E5PEY36J.js.map +1 -0
  12. package/dist/chunk-FBHLDOMC.js +2436 -0
  13. package/dist/chunk-FBHLDOMC.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-GVBLNAFM.js} +18 -21
  33. package/dist/heartbeat-GVBLNAFM.js.map +1 -0
  34. package/dist/{identity-VDUW4I2K.js → identity-ASHVWIN5.js} +3 -3
  35. package/dist/{init-SEJPTOOB.js → init-C4OZPGUC.js} +108 -15
  36. package/dist/init-C4OZPGUC.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-NTN4FCBD.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-2N2RN6J7.js} +23 -28
  46. package/dist/web-chat-2N2RN6J7.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-E3DWYRJM.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-NTN4FCBD.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
@@ -0,0 +1,20 @@
1
+ import {
2
+ runAutonomyCycle
3
+ } from "./chunk-FBHLDOMC.js";
4
+ import "./chunk-5R4AJZHN.js";
5
+ import "./chunk-ZLSDFYBR.js";
6
+ import "./chunk-E5PEY36J.js";
7
+ import "./chunk-OTZNHIXT.js";
8
+ import "./chunk-CAWWG3MD.js";
9
+ import "./chunk-CP6JWCLY.js";
10
+ import "./chunk-IULO3GRE.js";
11
+ import "./chunk-SXNZVKLJ.js";
12
+ import "./chunk-342ZX72W.js";
13
+ import "./chunk-RSNEVBEI.js";
14
+ import "./chunk-QYFNAGNI.js";
15
+ import "./chunk-BBXHECZ5.js";
16
+ import "./chunk-ZWKTKWS6.js";
17
+ export {
18
+ runAutonomyCycle
19
+ };
20
+ //# sourceMappingURL=autonomy-E3DWYRJM.js.map
@@ -1,12 +1,12 @@
1
1
  import {
2
2
  logger
3
- } from "./chunk-YMGJQRKG.js";
3
+ } from "./chunk-RSNEVBEI.js";
4
4
  import {
5
5
  loadConfig
6
- } from "./chunk-NO3NQN67.js";
6
+ } from "./chunk-QYFNAGNI.js";
7
7
  import {
8
8
  paths
9
- } from "./chunk-3RYCUGXE.js";
9
+ } from "./chunk-ZWKTKWS6.js";
10
10
 
11
11
  // src/runtime/llm.ts
12
12
  import Anthropic from "@anthropic-ai/sdk";
@@ -177,4 +177,4 @@ export {
177
177
  generateResponse,
178
178
  chat
179
179
  };
180
- //# sourceMappingURL=chunk-SUZUJGGW.js.map
180
+ //# sourceMappingURL=chunk-342ZX72W.js.map
@@ -1,9 +1,9 @@
1
1
  import {
2
2
  logger
3
- } from "./chunk-YMGJQRKG.js";
3
+ } from "./chunk-RSNEVBEI.js";
4
4
  import {
5
5
  loadConfig
6
- } from "./chunk-NO3NQN67.js";
6
+ } from "./chunk-QYFNAGNI.js";
7
7
 
8
8
  // src/x-client/index.ts
9
9
  var clientInstance = null;
@@ -13,7 +13,7 @@ async function getXClient() {
13
13
  if (config.xMethod !== "api") {
14
14
  throw new Error("Only X API mode is supported.");
15
15
  }
16
- const { XApiClient } = await import("./client-Z5UQWPPI.js");
16
+ const { XApiClient } = await import("./client-AR5ZD6S4.js");
17
17
  clientInstance = new XApiClient();
18
18
  logger.info("X client initialized: API mode");
19
19
  return clientInstance;
@@ -26,4 +26,4 @@ export {
26
26
  getXClient,
27
27
  resetXClient
28
28
  };
29
- //# sourceMappingURL=chunk-PN5A6MCV.js.map
29
+ //# sourceMappingURL=chunk-5R4AJZHN.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/x-client/index.ts"],"sourcesContent":["import { loadConfig } from \"../utils/config.js\";\nimport { logger } from \"../utils/logger.js\";\nimport type { XClientInterface } from \"./types.js\";\n\nlet clientInstance: XClientInterface | null = null;\n\nexport async function getXClient(): Promise<XClientInterface> {\n if (clientInstance) return clientInstance;\n\n const config = loadConfig();\n if (config.xMethod !== \"api\") {\n throw new Error(\"Only X API mode is supported.\");\n }\n\n const { XApiClient } = await import(\"./api/client.js\");\n clientInstance = new XApiClient();\n logger.info(\"X client initialized: API mode\");\n\n return clientInstance;\n}\n\nexport function resetXClient(): void {\n clientInstance = null;\n}\n\nexport type { XClientInterface } from \"./types.js\";\nexport type { Tweet, UserProfile, PostResult, TimelineOptions, SearchOptions } from \"./types.js\";\n"],"mappings":";;;;;;;;AAIA,IAAI,iBAA0C;AAE9C,eAAsB,aAAwC;AAC5D,MAAI,eAAgB,QAAO;AAE3B,QAAM,SAAS,WAAW;AAC1B,MAAI,OAAO,YAAY,OAAO;AAC5B,UAAM,IAAI,MAAM,+BAA+B;AAAA,EACjD;AAEA,QAAM,EAAE,WAAW,IAAI,MAAM,OAAO,sBAAiB;AACrD,mBAAiB,IAAI,WAAW;AAChC,SAAO,KAAK,gCAAgC;AAE5C,SAAO;AACT;AAEO,SAAS,eAAqB;AACnC,mBAAiB;AACnB;","names":[]}
1
+ {"version":3,"sources":["../src/x-client/index.ts"],"sourcesContent":["import { loadConfig } from \"../utils/config.js\";\nimport { logger } from \"../utils/logger.js\";\nimport type { XClientInterface } from \"./types.js\";\n\nlet clientInstance: XClientInterface | null = null;\n\nexport async function getXClient(): Promise<XClientInterface> {\n if (clientInstance) return clientInstance;\n\n const config = loadConfig();\n if (config.xMethod !== \"api\") {\n throw new Error(\"Only X API mode is supported.\");\n }\n\n const { XApiClient } = await import(\"./api/client.js\");\n clientInstance = new XApiClient();\n logger.info(\"X client initialized: API mode\");\n\n return clientInstance;\n}\n\nexport function resetXClient(): void {\n clientInstance = null;\n}\n\nexport type { XClientInterface } from \"./types.js\";\nexport type { Tweet, UserProfile, PostResult, TimelineOptions, SearchOptions, TweetMetrics } from \"./types.js\";\n"],"mappings":";;;;;;;;AAIA,IAAI,iBAA0C;AAE9C,eAAsB,aAAwC;AAC5D,MAAI,eAAgB,QAAO;AAE3B,QAAM,SAAS,WAAW;AAC1B,MAAI,OAAO,YAAY,OAAO;AAC5B,UAAM,IAAI,MAAM,+BAA+B;AAAA,EACjD;AAEA,QAAM,EAAE,WAAW,IAAI,MAAM,OAAO,sBAAiB;AACrD,mBAAiB,IAAI,WAAW;AAChC,SAAO,KAAK,gCAAgC;AAE5C,SAAO;AACT;AAEO,SAAS,eAAqB;AACnC,mBAAiB;AACnB;","names":[]}
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  ensureDirectories,
3
3
  paths
4
- } from "./chunk-3RYCUGXE.js";
4
+ } from "./chunk-ZWKTKWS6.js";
5
5
 
6
6
  // src/memory/index.ts
7
7
  import { readFileSync, writeFileSync, appendFileSync, existsSync, readdirSync } from "fs";
@@ -102,4 +102,4 @@ export {
102
102
  saveRelationships,
103
103
  updateRelationship
104
104
  };
105
- //# sourceMappingURL=chunk-JBYZ7K56.js.map
105
+ //# sourceMappingURL=chunk-BBXHECZ5.js.map
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  ensureDirectories,
3
3
  paths
4
- } from "./chunk-3RYCUGXE.js";
4
+ } from "./chunk-ZWKTKWS6.js";
5
5
 
6
6
  // src/memory/goals.ts
7
7
  import { existsSync, readFileSync, writeFileSync } from "fs";
@@ -41,4 +41,4 @@ export {
41
41
  saveGoals,
42
42
  renderGoalsForPrompt
43
43
  };
44
- //# sourceMappingURL=chunk-WN35MRMF.js.map
44
+ //# sourceMappingURL=chunk-CAWWG3MD.js.map
@@ -0,0 +1,171 @@
1
+ import {
2
+ logger
3
+ } from "./chunk-RSNEVBEI.js";
4
+ import {
5
+ loadConfig,
6
+ saveConfig
7
+ } from "./chunk-QYFNAGNI.js";
8
+ import {
9
+ paths
10
+ } from "./chunk-ZWKTKWS6.js";
11
+
12
+ // src/memory/performance.ts
13
+ import { existsSync, readFileSync, writeFileSync } from "fs";
14
+ function loadPerformance() {
15
+ if (!existsSync(paths.performance)) {
16
+ return { trackedPosts: [], selfMetrics: [] };
17
+ }
18
+ try {
19
+ return JSON.parse(readFileSync(paths.performance, "utf-8"));
20
+ } catch {
21
+ return { trackedPosts: [], selfMetrics: [] };
22
+ }
23
+ }
24
+ function savePerformance(data) {
25
+ writeFileSync(paths.performance, JSON.stringify(data, null, 2));
26
+ }
27
+ function trackPost(tweetId, content, type) {
28
+ const data = loadPerformance();
29
+ if (data.trackedPosts.some((p) => p.tweetId === tweetId)) return;
30
+ data.trackedPosts.push({
31
+ tweetId,
32
+ content,
33
+ type,
34
+ postedAt: (/* @__PURE__ */ new Date()).toISOString(),
35
+ metrics: [],
36
+ retired: false
37
+ });
38
+ savePerformance(data);
39
+ }
40
+ function getActiveTrackedPosts() {
41
+ const data = loadPerformance();
42
+ return data.trackedPosts.filter((p) => !p.retired);
43
+ }
44
+ function updatePostMetrics(tweetId, metric) {
45
+ const data = loadPerformance();
46
+ const post = data.trackedPosts.find((p) => p.tweetId === tweetId);
47
+ if (!post) return;
48
+ post.metrics.push(metric);
49
+ savePerformance(data);
50
+ }
51
+ function retireOldPosts() {
52
+ const data = loadPerformance();
53
+ const cutoff = Date.now() - 72 * 60 * 60 * 1e3;
54
+ let changed = false;
55
+ for (const post of data.trackedPosts) {
56
+ if (!post.retired && new Date(post.postedAt).getTime() < cutoff) {
57
+ post.retired = true;
58
+ changed = true;
59
+ }
60
+ }
61
+ const pruneCutoff = Date.now() - 30 * 24 * 60 * 60 * 1e3;
62
+ const before = data.trackedPosts.length;
63
+ data.trackedPosts = data.trackedPosts.filter(
64
+ (p) => !p.retired || new Date(p.postedAt).getTime() > pruneCutoff
65
+ );
66
+ if (data.trackedPosts.length !== before) changed = true;
67
+ if (changed) savePerformance(data);
68
+ }
69
+ function getPerformanceSummary() {
70
+ const data = loadPerformance();
71
+ const lines = [];
72
+ const oneDayAgo = Date.now() - 24 * 60 * 60 * 1e3;
73
+ const recentPosts = data.trackedPosts.filter(
74
+ (p) => new Date(p.postedAt).getTime() > oneDayAgo
75
+ );
76
+ if (recentPosts.length > 0) {
77
+ const postStats = recentPosts.map((p) => {
78
+ const latest = p.metrics.length > 0 ? p.metrics[p.metrics.length - 1] : null;
79
+ return {
80
+ content: p.content,
81
+ type: p.type,
82
+ likes: latest?.likes ?? 0,
83
+ retweets: latest?.retweets ?? 0,
84
+ replies: latest?.replies ?? 0
85
+ };
86
+ });
87
+ const totalLikes = postStats.reduce((s, p) => s + p.likes, 0);
88
+ const totalRTs = postStats.reduce((s, p) => s + p.retweets, 0);
89
+ const avgLikes = Math.round(totalLikes / postStats.length);
90
+ lines.push(`- Last 24h: ${postStats.length} posts, avg ${avgLikes} likes, ${totalRTs} total retweets`);
91
+ const sorted = [...postStats].sort((a, b) => b.likes - a.likes);
92
+ if (sorted.length > 0 && sorted[0].likes > 0) {
93
+ lines.push(`- Best performing: "${sorted[0].content.slice(0, 60)}..." (${sorted[0].likes} likes, ${sorted[0].retweets} RTs)`);
94
+ }
95
+ if (sorted.length > 1) {
96
+ const worst = sorted[sorted.length - 1];
97
+ lines.push(`- Lowest performing: "${worst.content.slice(0, 60)}..." (${worst.likes} likes)`);
98
+ }
99
+ } else {
100
+ lines.push("- No tracked posts in the last 24 hours yet.");
101
+ }
102
+ if (data.selfMetrics.length > 0) {
103
+ const latest = data.selfMetrics[data.selfMetrics.length - 1];
104
+ lines.push(`- Followers: ${latest.followers} | Following: ${latest.following} | Total tweets: ${latest.totalTweets}`);
105
+ const dayAgoMetric = data.selfMetrics.find(
106
+ (m) => Math.abs(new Date(m.checkedAt).getTime() - (Date.now() - 24 * 60 * 60 * 1e3)) < 12 * 60 * 60 * 1e3
107
+ );
108
+ if (dayAgoMetric) {
109
+ const diff = latest.followers - dayAgoMetric.followers;
110
+ if (diff !== 0) {
111
+ lines.push(`- Follower trend: ${diff > 0 ? "+" : ""}${diff} in the last ~24h`);
112
+ }
113
+ }
114
+ }
115
+ return lines.length > 0 ? lines.join("\n") : "";
116
+ }
117
+
118
+ // src/x-client/rate-limiter.ts
119
+ var RateLimiter = class {
120
+ checkResetDate() {
121
+ const config = loadConfig();
122
+ const now = /* @__PURE__ */ new Date();
123
+ const resetDate = new Date(config.credits.resetDate);
124
+ if (now >= resetDate) {
125
+ config.credits.postsUsedThisMonth = 0;
126
+ const nextReset = new Date(now.getFullYear(), now.getMonth() + 1, 1);
127
+ config.credits.resetDate = nextReset.toISOString();
128
+ saveConfig(config);
129
+ logger.info("Monthly credits reset");
130
+ }
131
+ }
132
+ canPost() {
133
+ this.checkResetDate();
134
+ const config = loadConfig();
135
+ return config.credits.postsUsedThisMonth < config.credits.monthlyPostLimit;
136
+ }
137
+ remaining() {
138
+ this.checkResetDate();
139
+ const config = loadConfig();
140
+ return config.credits.monthlyPostLimit - config.credits.postsUsedThisMonth;
141
+ }
142
+ consume(count = 1) {
143
+ this.checkResetDate();
144
+ const config = loadConfig();
145
+ config.credits.postsUsedThisMonth += count;
146
+ saveConfig(config);
147
+ const remaining = config.credits.monthlyPostLimit - config.credits.postsUsedThisMonth;
148
+ if (remaining <= Math.floor(config.credits.monthlyPostLimit * 0.2)) {
149
+ logger.warn(`Low credits: ${remaining} posts remaining this month`);
150
+ }
151
+ }
152
+ requireBasicTier(action) {
153
+ const config = loadConfig();
154
+ if (config.xMethod === "api" && config.xApiTier !== "basic") {
155
+ throw new Error(
156
+ `${action} requires X API Basic tier ($200/mo). Current tier: ${config.xApiTier ?? "free"}. Upgrade your API tier or adjust runtime behavior.`
157
+ );
158
+ }
159
+ }
160
+ };
161
+ var rateLimiter = new RateLimiter();
162
+
163
+ export {
164
+ trackPost,
165
+ getActiveTrackedPosts,
166
+ updatePostMetrics,
167
+ retireOldPosts,
168
+ getPerformanceSummary,
169
+ rateLimiter
170
+ };
171
+ //# sourceMappingURL=chunk-CP6JWCLY.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/memory/performance.ts","../src/x-client/rate-limiter.ts"],"sourcesContent":["import { existsSync, readFileSync, writeFileSync } from \"node:fs\";\nimport { paths } from \"../utils/paths.js\";\n\nexport interface EngagementMetric {\n checkedAt: string;\n likes: number;\n retweets: number;\n replies: number;\n}\n\nexport interface TrackedPost {\n tweetId: string;\n content: string;\n type: \"post\" | \"reply\";\n postedAt: string;\n metrics: EngagementMetric[];\n retired: boolean;\n}\n\nexport interface SelfMetric {\n checkedAt: string;\n followers: number;\n following: number;\n totalTweets: number;\n}\n\nexport interface PerformanceData {\n trackedPosts: TrackedPost[];\n selfMetrics: SelfMetric[];\n}\n\nfunction loadPerformance(): PerformanceData {\n if (!existsSync(paths.performance)) {\n return { trackedPosts: [], selfMetrics: [] };\n }\n try {\n return JSON.parse(readFileSync(paths.performance, \"utf-8\"));\n } catch {\n return { trackedPosts: [], selfMetrics: [] };\n }\n}\n\nfunction savePerformance(data: PerformanceData): void {\n writeFileSync(paths.performance, JSON.stringify(data, null, 2));\n}\n\nexport function trackPost(tweetId: string, content: string, type: \"post\" | \"reply\"): void {\n const data = loadPerformance();\n // Don't double-track\n if (data.trackedPosts.some(p => p.tweetId === tweetId)) return;\n data.trackedPosts.push({\n tweetId,\n content,\n type,\n postedAt: new Date().toISOString(),\n metrics: [],\n retired: false,\n });\n savePerformance(data);\n}\n\nexport function getActiveTrackedPosts(): TrackedPost[] {\n const data = loadPerformance();\n return data.trackedPosts.filter(p => !p.retired);\n}\n\nexport function updatePostMetrics(tweetId: string, metric: EngagementMetric): void {\n const data = loadPerformance();\n const post = data.trackedPosts.find(p => p.tweetId === tweetId);\n if (!post) return;\n post.metrics.push(metric);\n savePerformance(data);\n}\n\nexport function retireOldPosts(): void {\n const data = loadPerformance();\n const cutoff = Date.now() - 72 * 60 * 60 * 1000; // 72 hours\n let changed = false;\n for (const post of data.trackedPosts) {\n if (!post.retired && new Date(post.postedAt).getTime() < cutoff) {\n post.retired = true;\n changed = true;\n }\n }\n // Also prune very old retired posts (older than 30 days) to prevent file bloat\n const pruneCutoff = Date.now() - 30 * 24 * 60 * 60 * 1000;\n const before = data.trackedPosts.length;\n data.trackedPosts = data.trackedPosts.filter(\n p => !p.retired || new Date(p.postedAt).getTime() > pruneCutoff\n );\n if (data.trackedPosts.length !== before) changed = true;\n if (changed) savePerformance(data);\n}\n\nexport function updateSelfMetrics(metric: SelfMetric): void {\n const data = loadPerformance();\n data.selfMetrics.push(metric);\n // Keep only last 100 snapshots\n if (data.selfMetrics.length > 100) {\n data.selfMetrics = data.selfMetrics.slice(-100);\n }\n savePerformance(data);\n}\n\nexport function getPerformanceSummary(): string {\n const data = loadPerformance();\n const lines: string[] = [];\n\n // Post performance (last 24h)\n const oneDayAgo = Date.now() - 24 * 60 * 60 * 1000;\n const recentPosts = data.trackedPosts.filter(\n p => new Date(p.postedAt).getTime() > oneDayAgo\n );\n\n if (recentPosts.length > 0) {\n // Get latest metrics for each post\n const postStats = recentPosts.map(p => {\n const latest = p.metrics.length > 0 ? p.metrics[p.metrics.length - 1] : null;\n return {\n content: p.content,\n type: p.type,\n likes: latest?.likes ?? 0,\n retweets: latest?.retweets ?? 0,\n replies: latest?.replies ?? 0,\n };\n });\n\n const totalLikes = postStats.reduce((s, p) => s + p.likes, 0);\n const totalRTs = postStats.reduce((s, p) => s + p.retweets, 0);\n const avgLikes = Math.round(totalLikes / postStats.length);\n\n lines.push(`- Last 24h: ${postStats.length} posts, avg ${avgLikes} likes, ${totalRTs} total retweets`);\n\n // Best and worst performing\n const sorted = [...postStats].sort((a, b) => b.likes - a.likes);\n if (sorted.length > 0 && sorted[0].likes > 0) {\n lines.push(`- Best performing: \"${sorted[0].content.slice(0, 60)}...\" (${sorted[0].likes} likes, ${sorted[0].retweets} RTs)`);\n }\n if (sorted.length > 1) {\n const worst = sorted[sorted.length - 1];\n lines.push(`- Lowest performing: \"${worst.content.slice(0, 60)}...\" (${worst.likes} likes)`);\n }\n } else {\n lines.push(\"- No tracked posts in the last 24 hours yet.\");\n }\n\n // Self metrics\n if (data.selfMetrics.length > 0) {\n const latest = data.selfMetrics[data.selfMetrics.length - 1];\n lines.push(`- Followers: ${latest.followers} | Following: ${latest.following} | Total tweets: ${latest.totalTweets}`);\n\n // Trend: compare to 24h ago\n const dayAgoMetric = data.selfMetrics.find(m =>\n Math.abs(new Date(m.checkedAt).getTime() - (Date.now() - 24 * 60 * 60 * 1000)) < 12 * 60 * 60 * 1000\n );\n if (dayAgoMetric) {\n const diff = latest.followers - dayAgoMetric.followers;\n if (diff !== 0) {\n lines.push(`- Follower trend: ${diff > 0 ? \"+\" : \"\"}${diff} in the last ~24h`);\n }\n }\n }\n\n return lines.length > 0 ? lines.join(\"\\n\") : \"\";\n}\n","import { loadConfig, saveConfig } from \"../utils/config.js\";\nimport { logger } from \"../utils/logger.js\";\n\nexport class RateLimiter {\n private checkResetDate(): void {\n const config = loadConfig();\n const now = new Date();\n const resetDate = new Date(config.credits.resetDate);\n\n if (now >= resetDate) {\n config.credits.postsUsedThisMonth = 0;\n const nextReset = new Date(now.getFullYear(), now.getMonth() + 1, 1);\n config.credits.resetDate = nextReset.toISOString();\n saveConfig(config);\n logger.info(\"Monthly credits reset\");\n }\n }\n\n canPost(): boolean {\n this.checkResetDate();\n const config = loadConfig();\n return config.credits.postsUsedThisMonth < config.credits.monthlyPostLimit;\n }\n\n remaining(): number {\n this.checkResetDate();\n const config = loadConfig();\n return config.credits.monthlyPostLimit - config.credits.postsUsedThisMonth;\n }\n\n consume(count: number = 1): void {\n this.checkResetDate();\n const config = loadConfig();\n config.credits.postsUsedThisMonth += count;\n saveConfig(config);\n\n const remaining = config.credits.monthlyPostLimit - config.credits.postsUsedThisMonth;\n if (remaining <= Math.floor(config.credits.monthlyPostLimit * 0.2)) {\n logger.warn(`Low credits: ${remaining} posts remaining this month`);\n }\n }\n\n requireBasicTier(action: string): void {\n const config = loadConfig();\n if (config.xMethod === \"api\" && config.xApiTier !== \"basic\") {\n throw new Error(\n `${action} requires X API Basic tier ($200/mo). ` +\n `Current tier: ${config.xApiTier ?? \"free\"}. ` +\n `Upgrade your API tier or adjust runtime behavior.`\n );\n }\n }\n}\n\nexport const rateLimiter = new RateLimiter();\n"],"mappings":"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","names":[]}
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  ensureDirectories,
3
3
  paths
4
- } from "./chunk-3RYCUGXE.js";
4
+ } from "./chunk-ZWKTKWS6.js";
5
5
 
6
6
  // src/colony/memory.ts
7
7
  import { readFileSync, writeFileSync, existsSync } from "fs";
@@ -153,4 +153,4 @@ export {
153
153
  getTodayEntries,
154
154
  renderColonyBriefing
155
155
  };
156
- //# sourceMappingURL=chunk-T7L2L7ZL.js.map
156
+ //# sourceMappingURL=chunk-D47OFTEK.js.map