adaria-ai 0.1.0

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 (337) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +21 -0
  3. package/apps.example.yaml +65 -0
  4. package/dist/agent/audit.d.ts +16 -0
  5. package/dist/agent/audit.d.ts.map +1 -0
  6. package/dist/agent/audit.js +42 -0
  7. package/dist/agent/audit.js.map +1 -0
  8. package/dist/agent/claude.d.ts +62 -0
  9. package/dist/agent/claude.d.ts.map +1 -0
  10. package/dist/agent/claude.js +297 -0
  11. package/dist/agent/claude.js.map +1 -0
  12. package/dist/agent/conversation-summary.d.ts +29 -0
  13. package/dist/agent/conversation-summary.d.ts.map +1 -0
  14. package/dist/agent/conversation-summary.js +221 -0
  15. package/dist/agent/conversation-summary.js.map +1 -0
  16. package/dist/agent/core.d.ts +81 -0
  17. package/dist/agent/core.d.ts.map +1 -0
  18. package/dist/agent/core.js +527 -0
  19. package/dist/agent/core.js.map +1 -0
  20. package/dist/agent/mcp-launcher.d.ts +42 -0
  21. package/dist/agent/mcp-launcher.d.ts.map +1 -0
  22. package/dist/agent/mcp-launcher.js +38 -0
  23. package/dist/agent/mcp-launcher.js.map +1 -0
  24. package/dist/agent/mcp-manager.d.ts +81 -0
  25. package/dist/agent/mcp-manager.d.ts.map +1 -0
  26. package/dist/agent/mcp-manager.js +136 -0
  27. package/dist/agent/mcp-manager.js.map +1 -0
  28. package/dist/agent/memory.d.ts +10 -0
  29. package/dist/agent/memory.d.ts.map +1 -0
  30. package/dist/agent/memory.js +95 -0
  31. package/dist/agent/memory.js.map +1 -0
  32. package/dist/agent/safety.d.ts +45 -0
  33. package/dist/agent/safety.d.ts.map +1 -0
  34. package/dist/agent/safety.js +71 -0
  35. package/dist/agent/safety.js.map +1 -0
  36. package/dist/agent/session.d.ts +27 -0
  37. package/dist/agent/session.d.ts.map +1 -0
  38. package/dist/agent/session.js +124 -0
  39. package/dist/agent/session.js.map +1 -0
  40. package/dist/agent/tool-descriptions.d.ts +8 -0
  41. package/dist/agent/tool-descriptions.d.ts.map +1 -0
  42. package/dist/agent/tool-descriptions.js +26 -0
  43. package/dist/agent/tool-descriptions.js.map +1 -0
  44. package/dist/cli/analyze.d.ts +8 -0
  45. package/dist/cli/analyze.d.ts.map +1 -0
  46. package/dist/cli/analyze.js +114 -0
  47. package/dist/cli/analyze.js.map +1 -0
  48. package/dist/cli/daemon.d.ts +2 -0
  49. package/dist/cli/daemon.d.ts.map +1 -0
  50. package/dist/cli/daemon.js +91 -0
  51. package/dist/cli/daemon.js.map +1 -0
  52. package/dist/cli/doctor.d.ts +2 -0
  53. package/dist/cli/doctor.d.ts.map +1 -0
  54. package/dist/cli/doctor.js +198 -0
  55. package/dist/cli/doctor.js.map +1 -0
  56. package/dist/cli/init.d.ts +3 -0
  57. package/dist/cli/init.d.ts.map +1 -0
  58. package/dist/cli/init.js +459 -0
  59. package/dist/cli/init.js.map +1 -0
  60. package/dist/cli/logs.d.ts +4 -0
  61. package/dist/cli/logs.d.ts.map +1 -0
  62. package/dist/cli/logs.js +50 -0
  63. package/dist/cli/logs.js.map +1 -0
  64. package/dist/cli/monitor-cmd.d.ts +11 -0
  65. package/dist/cli/monitor-cmd.d.ts.map +1 -0
  66. package/dist/cli/monitor-cmd.js +59 -0
  67. package/dist/cli/monitor-cmd.js.map +1 -0
  68. package/dist/cli/start.d.ts +11 -0
  69. package/dist/cli/start.d.ts.map +1 -0
  70. package/dist/cli/start.js +103 -0
  71. package/dist/cli/start.js.map +1 -0
  72. package/dist/cli/status.d.ts +9 -0
  73. package/dist/cli/status.d.ts.map +1 -0
  74. package/dist/cli/status.js +49 -0
  75. package/dist/cli/status.js.map +1 -0
  76. package/dist/cli/stop.d.ts +2 -0
  77. package/dist/cli/stop.d.ts.map +1 -0
  78. package/dist/cli/stop.js +34 -0
  79. package/dist/cli/stop.js.map +1 -0
  80. package/dist/collectors/appstore.d.ts +51 -0
  81. package/dist/collectors/appstore.d.ts.map +1 -0
  82. package/dist/collectors/appstore.js +166 -0
  83. package/dist/collectors/appstore.js.map +1 -0
  84. package/dist/collectors/arden-tts.d.ts +60 -0
  85. package/dist/collectors/arden-tts.d.ts.map +1 -0
  86. package/dist/collectors/arden-tts.js +83 -0
  87. package/dist/collectors/arden-tts.js.map +1 -0
  88. package/dist/collectors/asomobile.d.ts +37 -0
  89. package/dist/collectors/asomobile.d.ts.map +1 -0
  90. package/dist/collectors/asomobile.js +88 -0
  91. package/dist/collectors/asomobile.js.map +1 -0
  92. package/dist/collectors/eodin-blog.d.ts +90 -0
  93. package/dist/collectors/eodin-blog.d.ts.map +1 -0
  94. package/dist/collectors/eodin-blog.js +238 -0
  95. package/dist/collectors/eodin-blog.js.map +1 -0
  96. package/dist/collectors/eodin-sdk.d.ts +60 -0
  97. package/dist/collectors/eodin-sdk.d.ts.map +1 -0
  98. package/dist/collectors/eodin-sdk.js +112 -0
  99. package/dist/collectors/eodin-sdk.js.map +1 -0
  100. package/dist/collectors/fridgify-recipes.d.ts +65 -0
  101. package/dist/collectors/fridgify-recipes.d.ts.map +1 -0
  102. package/dist/collectors/fridgify-recipes.js +111 -0
  103. package/dist/collectors/fridgify-recipes.js.map +1 -0
  104. package/dist/collectors/playstore.d.ts +46 -0
  105. package/dist/collectors/playstore.d.ts.map +1 -0
  106. package/dist/collectors/playstore.js +140 -0
  107. package/dist/collectors/playstore.js.map +1 -0
  108. package/dist/collectors/youtube.d.ts +44 -0
  109. package/dist/collectors/youtube.d.ts.map +1 -0
  110. package/dist/collectors/youtube.js +107 -0
  111. package/dist/collectors/youtube.js.map +1 -0
  112. package/dist/config/apps-schema.d.ts +94 -0
  113. package/dist/config/apps-schema.d.ts.map +1 -0
  114. package/dist/config/apps-schema.js +66 -0
  115. package/dist/config/apps-schema.js.map +1 -0
  116. package/dist/config/keychain.d.ts +14 -0
  117. package/dist/config/keychain.d.ts.map +1 -0
  118. package/dist/config/keychain.js +89 -0
  119. package/dist/config/keychain.js.map +1 -0
  120. package/dist/config/load-apps.d.ts +16 -0
  121. package/dist/config/load-apps.d.ts.map +1 -0
  122. package/dist/config/load-apps.js +38 -0
  123. package/dist/config/load-apps.js.map +1 -0
  124. package/dist/config/schema.d.ts +306 -0
  125. package/dist/config/schema.d.ts.map +1 -0
  126. package/dist/config/schema.js +220 -0
  127. package/dist/config/schema.js.map +1 -0
  128. package/dist/config/store.d.ts +38 -0
  129. package/dist/config/store.d.ts.map +1 -0
  130. package/dist/config/store.js +180 -0
  131. package/dist/config/store.js.map +1 -0
  132. package/dist/db/queries.d.ts +304 -0
  133. package/dist/db/queries.d.ts.map +1 -0
  134. package/dist/db/queries.js +327 -0
  135. package/dist/db/queries.js.map +1 -0
  136. package/dist/db/schema.d.ts +15 -0
  137. package/dist/db/schema.d.ts.map +1 -0
  138. package/dist/db/schema.js +252 -0
  139. package/dist/db/schema.js.map +1 -0
  140. package/dist/index.d.ts +3 -0
  141. package/dist/index.d.ts.map +1 -0
  142. package/dist/index.js +86 -0
  143. package/dist/index.js.map +1 -0
  144. package/dist/messenger/adapter.d.ts +63 -0
  145. package/dist/messenger/adapter.d.ts.map +1 -0
  146. package/dist/messenger/adapter.js +7 -0
  147. package/dist/messenger/adapter.js.map +1 -0
  148. package/dist/messenger/factory.d.ts +12 -0
  149. package/dist/messenger/factory.d.ts.map +1 -0
  150. package/dist/messenger/factory.js +9 -0
  151. package/dist/messenger/factory.js.map +1 -0
  152. package/dist/messenger/slack.d.ts +30 -0
  153. package/dist/messenger/slack.d.ts.map +1 -0
  154. package/dist/messenger/slack.js +309 -0
  155. package/dist/messenger/slack.js.map +1 -0
  156. package/dist/messenger/split.d.ts +17 -0
  157. package/dist/messenger/split.d.ts.map +1 -0
  158. package/dist/messenger/split.js +56 -0
  159. package/dist/messenger/split.js.map +1 -0
  160. package/dist/orchestrator/dashboard.d.ts +67 -0
  161. package/dist/orchestrator/dashboard.d.ts.map +1 -0
  162. package/dist/orchestrator/dashboard.js +113 -0
  163. package/dist/orchestrator/dashboard.js.map +1 -0
  164. package/dist/orchestrator/monitor.d.ts +37 -0
  165. package/dist/orchestrator/monitor.d.ts.map +1 -0
  166. package/dist/orchestrator/monitor.js +236 -0
  167. package/dist/orchestrator/monitor.js.map +1 -0
  168. package/dist/orchestrator/types.d.ts +82 -0
  169. package/dist/orchestrator/types.d.ts.map +1 -0
  170. package/dist/orchestrator/types.js +12 -0
  171. package/dist/orchestrator/types.js.map +1 -0
  172. package/dist/orchestrator/weekly.d.ts +66 -0
  173. package/dist/orchestrator/weekly.d.ts.map +1 -0
  174. package/dist/orchestrator/weekly.js +376 -0
  175. package/dist/orchestrator/weekly.js.map +1 -0
  176. package/dist/prompts/loader.d.ts +18 -0
  177. package/dist/prompts/loader.d.ts.map +1 -0
  178. package/dist/prompts/loader.js +28 -0
  179. package/dist/prompts/loader.js.map +1 -0
  180. package/dist/security/auth.d.ts +14 -0
  181. package/dist/security/auth.d.ts.map +1 -0
  182. package/dist/security/auth.js +14 -0
  183. package/dist/security/auth.js.map +1 -0
  184. package/dist/security/prompt-guard.d.ts +21 -0
  185. package/dist/security/prompt-guard.d.ts.map +1 -0
  186. package/dist/security/prompt-guard.js +54 -0
  187. package/dist/security/prompt-guard.js.map +1 -0
  188. package/dist/skills/aso.d.ts +60 -0
  189. package/dist/skills/aso.d.ts.map +1 -0
  190. package/dist/skills/aso.js +322 -0
  191. package/dist/skills/aso.js.map +1 -0
  192. package/dist/skills/content.d.ts +25 -0
  193. package/dist/skills/content.d.ts.map +1 -0
  194. package/dist/skills/content.js +90 -0
  195. package/dist/skills/content.js.map +1 -0
  196. package/dist/skills/index.d.ts +65 -0
  197. package/dist/skills/index.d.ts.map +1 -0
  198. package/dist/skills/index.js +90 -0
  199. package/dist/skills/index.js.map +1 -0
  200. package/dist/skills/onboarding.d.ts +58 -0
  201. package/dist/skills/onboarding.d.ts.map +1 -0
  202. package/dist/skills/onboarding.js +274 -0
  203. package/dist/skills/onboarding.js.map +1 -0
  204. package/dist/skills/registry.d.ts +24 -0
  205. package/dist/skills/registry.d.ts.map +1 -0
  206. package/dist/skills/registry.js +66 -0
  207. package/dist/skills/registry.js.map +1 -0
  208. package/dist/skills/review.d.ts +33 -0
  209. package/dist/skills/review.d.ts.map +1 -0
  210. package/dist/skills/review.js +236 -0
  211. package/dist/skills/review.js.map +1 -0
  212. package/dist/skills/sdk-request.d.ts +30 -0
  213. package/dist/skills/sdk-request.d.ts.map +1 -0
  214. package/dist/skills/sdk-request.js +72 -0
  215. package/dist/skills/sdk-request.js.map +1 -0
  216. package/dist/skills/seo-blog.d.ts +64 -0
  217. package/dist/skills/seo-blog.d.ts.map +1 -0
  218. package/dist/skills/seo-blog.js +268 -0
  219. package/dist/skills/seo-blog.js.map +1 -0
  220. package/dist/skills/short-form.d.ts +28 -0
  221. package/dist/skills/short-form.d.ts.map +1 -0
  222. package/dist/skills/short-form.js +121 -0
  223. package/dist/skills/short-form.js.map +1 -0
  224. package/dist/skills/social-publish.d.ts +32 -0
  225. package/dist/skills/social-publish.d.ts.map +1 -0
  226. package/dist/skills/social-publish.js +133 -0
  227. package/dist/skills/social-publish.js.map +1 -0
  228. package/dist/social/base.d.ts +47 -0
  229. package/dist/social/base.d.ts.map +1 -0
  230. package/dist/social/base.js +26 -0
  231. package/dist/social/base.js.map +1 -0
  232. package/dist/social/facebook.d.ts +27 -0
  233. package/dist/social/facebook.d.ts.map +1 -0
  234. package/dist/social/facebook.js +166 -0
  235. package/dist/social/facebook.js.map +1 -0
  236. package/dist/social/factory.d.ts +26 -0
  237. package/dist/social/factory.d.ts.map +1 -0
  238. package/dist/social/factory.js +32 -0
  239. package/dist/social/factory.js.map +1 -0
  240. package/dist/social/linkedin.d.ts +26 -0
  241. package/dist/social/linkedin.d.ts.map +1 -0
  242. package/dist/social/linkedin.js +190 -0
  243. package/dist/social/linkedin.js.map +1 -0
  244. package/dist/social/threads.d.ts +21 -0
  245. package/dist/social/threads.d.ts.map +1 -0
  246. package/dist/social/threads.js +122 -0
  247. package/dist/social/threads.js.map +1 -0
  248. package/dist/social/tiktok.d.ts +23 -0
  249. package/dist/social/tiktok.d.ts.map +1 -0
  250. package/dist/social/tiktok.js +110 -0
  251. package/dist/social/tiktok.js.map +1 -0
  252. package/dist/social/twitter.d.ts +30 -0
  253. package/dist/social/twitter.d.ts.map +1 -0
  254. package/dist/social/twitter.js +189 -0
  255. package/dist/social/twitter.js.map +1 -0
  256. package/dist/social/youtube.d.ts +21 -0
  257. package/dist/social/youtube.d.ts.map +1 -0
  258. package/dist/social/youtube.js +108 -0
  259. package/dist/social/youtube.js.map +1 -0
  260. package/dist/tools/app-info.d.ts +7 -0
  261. package/dist/tools/app-info.d.ts.map +1 -0
  262. package/dist/tools/app-info.js +53 -0
  263. package/dist/tools/app-info.js.map +1 -0
  264. package/dist/tools/collector-fetch.d.ts +11 -0
  265. package/dist/tools/collector-fetch.d.ts.map +1 -0
  266. package/dist/tools/collector-fetch.js +101 -0
  267. package/dist/tools/collector-fetch.js.map +1 -0
  268. package/dist/tools/db-query.d.ts +29 -0
  269. package/dist/tools/db-query.d.ts.map +1 -0
  270. package/dist/tools/db-query.js +159 -0
  271. package/dist/tools/db-query.js.map +1 -0
  272. package/dist/tools/skill-result.d.ts +8 -0
  273. package/dist/tools/skill-result.d.ts.map +1 -0
  274. package/dist/tools/skill-result.js +63 -0
  275. package/dist/tools/skill-result.js.map +1 -0
  276. package/dist/tools/tool-host.d.ts +12 -0
  277. package/dist/tools/tool-host.d.ts.map +1 -0
  278. package/dist/tools/tool-host.js +124 -0
  279. package/dist/tools/tool-host.js.map +1 -0
  280. package/dist/types/collectors.d.ts +198 -0
  281. package/dist/types/collectors.d.ts.map +1 -0
  282. package/dist/types/collectors.js +28 -0
  283. package/dist/types/collectors.js.map +1 -0
  284. package/dist/types/skill.d.ts +60 -0
  285. package/dist/types/skill.d.ts.map +1 -0
  286. package/dist/types/skill.js +9 -0
  287. package/dist/types/skill.js.map +1 -0
  288. package/dist/utils/circuit-breaker.d.ts +26 -0
  289. package/dist/utils/circuit-breaker.d.ts.map +1 -0
  290. package/dist/utils/circuit-breaker.js +67 -0
  291. package/dist/utils/circuit-breaker.js.map +1 -0
  292. package/dist/utils/errors.d.ts +44 -0
  293. package/dist/utils/errors.d.ts.map +1 -0
  294. package/dist/utils/errors.js +75 -0
  295. package/dist/utils/errors.js.map +1 -0
  296. package/dist/utils/escape.d.ts +11 -0
  297. package/dist/utils/escape.d.ts.map +1 -0
  298. package/dist/utils/escape.js +19 -0
  299. package/dist/utils/escape.js.map +1 -0
  300. package/dist/utils/logger.d.ts +19 -0
  301. package/dist/utils/logger.d.ts.map +1 -0
  302. package/dist/utils/logger.js +93 -0
  303. package/dist/utils/logger.js.map +1 -0
  304. package/dist/utils/parse-json.d.ts +13 -0
  305. package/dist/utils/parse-json.d.ts.map +1 -0
  306. package/dist/utils/parse-json.js +61 -0
  307. package/dist/utils/parse-json.js.map +1 -0
  308. package/dist/utils/paths.d.ts +14 -0
  309. package/dist/utils/paths.d.ts.map +1 -0
  310. package/dist/utils/paths.js +19 -0
  311. package/dist/utils/paths.js.map +1 -0
  312. package/dist/utils/rate-limiter.d.ts +20 -0
  313. package/dist/utils/rate-limiter.d.ts.map +1 -0
  314. package/dist/utils/rate-limiter.js +47 -0
  315. package/dist/utils/rate-limiter.js.map +1 -0
  316. package/dist/utils/retry.d.ts +26 -0
  317. package/dist/utils/retry.d.ts.map +1 -0
  318. package/dist/utils/retry.js +61 -0
  319. package/dist/utils/retry.js.map +1 -0
  320. package/launchd/.gitkeep +0 -0
  321. package/launchd/com.adaria-ai.daemon.plist.template +62 -0
  322. package/launchd/com.adaria-ai.monitor.plist.template +41 -0
  323. package/launchd/com.adaria-ai.weekly.plist.template +43 -0
  324. package/package.json +72 -0
  325. package/prompts/aso-description.md +44 -0
  326. package/prompts/aso-inapp-events.md +20 -0
  327. package/prompts/aso-metadata.md +34 -0
  328. package/prompts/aso-screenshots.md +20 -0
  329. package/prompts/onboarding-hypotheses.md +38 -0
  330. package/prompts/onboarding-review-timing.md +24 -0
  331. package/prompts/review-clustering.md +19 -0
  332. package/prompts/review-replies.md +18 -0
  333. package/prompts/review-sentiment.md +16 -0
  334. package/prompts/seo-blog-fridgify-recipe.md +116 -0
  335. package/prompts/seo-blog.md +69 -0
  336. package/prompts/short-form-ideas.md +50 -0
  337. package/prompts/social-publish.md +46 -0
@@ -0,0 +1,122 @@
1
+ /**
2
+ * Threads client — Meta Threads API.
3
+ *
4
+ * Uses the two-step container → publish flow. Images require creating
5
+ * an image container first, then publishing it.
6
+ */
7
+ import { isDryRun, dryRunResult, } from "./base.js";
8
+ import * as logger from "../utils/logger.js";
9
+ const BASE_URL = "https://graph.threads.net/v1.0";
10
+ const MAX_CHARS = 500;
11
+ export class ThreadsClient {
12
+ config;
13
+ platform = "threads";
14
+ constructor(config) {
15
+ this.config = config;
16
+ }
17
+ async post(content) {
18
+ if (isDryRun()) {
19
+ logger.info(`[threads] DRY_RUN: would post: ${content.text.slice(0, 100)}`);
20
+ return dryRunResult("threads", content);
21
+ }
22
+ const text = this.buildText(content);
23
+ const validation = this.validateContent(text);
24
+ if (!validation.valid) {
25
+ return {
26
+ success: false,
27
+ platform: "threads",
28
+ error: validation.issues.join("; "),
29
+ };
30
+ }
31
+ try {
32
+ // Step 1: Create media container
33
+ const containerParams = {
34
+ text,
35
+ media_type: content.imageUrl ? "IMAGE" : "TEXT",
36
+ access_token: this.config.accessToken,
37
+ };
38
+ if (content.imageUrl) {
39
+ containerParams["image_url"] = content.imageUrl;
40
+ }
41
+ const containerResponse = await fetch(`${BASE_URL}/${this.config.userId}/threads`, {
42
+ method: "POST",
43
+ headers: { "Content-Type": "application/x-www-form-urlencoded" },
44
+ body: new URLSearchParams(containerParams),
45
+ });
46
+ if (!containerResponse.ok) {
47
+ const err = await containerResponse.text();
48
+ throw new Error(`Container creation failed: ${err}`);
49
+ }
50
+ const container = (await containerResponse.json());
51
+ if (!container.id)
52
+ throw new Error("No container ID returned");
53
+ // Step 2: Publish
54
+ const publishResponse = await fetch(`${BASE_URL}/${this.config.userId}/threads_publish`, {
55
+ method: "POST",
56
+ headers: { "Content-Type": "application/x-www-form-urlencoded" },
57
+ body: new URLSearchParams({
58
+ creation_id: container.id,
59
+ access_token: this.config.accessToken,
60
+ }),
61
+ });
62
+ if (!publishResponse.ok) {
63
+ const err = await publishResponse.text();
64
+ throw new Error(`Publish failed: ${err}`);
65
+ }
66
+ const result = (await publishResponse.json());
67
+ return {
68
+ success: true,
69
+ platform: "threads",
70
+ postId: result.id,
71
+ postUrl: result.id
72
+ ? `https://www.threads.net/post/${result.id}`
73
+ : undefined,
74
+ postedAt: new Date().toISOString(),
75
+ };
76
+ }
77
+ catch (err) {
78
+ const msg = err instanceof Error ? err.message : String(err);
79
+ logger.error(`[threads] Post failed: ${msg}`);
80
+ return { success: false, platform: "threads", error: msg };
81
+ }
82
+ }
83
+ validateContent(text) {
84
+ const issues = [];
85
+ const suggestions = [];
86
+ if (!text.trim()) {
87
+ issues.push("Text is empty");
88
+ return { valid: false, characterCount: 0, issues, suggestions };
89
+ }
90
+ if (text.length > MAX_CHARS) {
91
+ issues.push(`Text exceeds ${String(MAX_CHARS)} characters (${String(text.length)})`);
92
+ }
93
+ return {
94
+ valid: issues.length === 0,
95
+ characterCount: text.length,
96
+ issues,
97
+ suggestions,
98
+ };
99
+ }
100
+ async deletePost(postId) {
101
+ if (isDryRun()) {
102
+ logger.info(`[threads] DRY_RUN: would delete post ${postId}`);
103
+ return true;
104
+ }
105
+ try {
106
+ const response = await fetch(`${BASE_URL}/${postId}?access_token=${encodeURIComponent(this.config.accessToken)}`, { method: "DELETE" });
107
+ return response.ok;
108
+ }
109
+ catch {
110
+ return false;
111
+ }
112
+ }
113
+ buildText(content) {
114
+ let text = content.text;
115
+ if (content.hashtags?.length) {
116
+ const tags = content.hashtags.map((t) => t.startsWith("#") ? t : `#${t}`);
117
+ text = `${text}\n\n${tags.join(" ")}`;
118
+ }
119
+ return text;
120
+ }
121
+ }
122
+ //# sourceMappingURL=threads.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"threads.js","sourceRoot":"","sources":["../../src/social/threads.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,23 @@
1
+ /**
2
+ * TikTok client — Content Posting API.
3
+ *
4
+ * NOTE: TikTok's Content Posting API requires app review before
5
+ * production access. This client is implemented but may be blocked
6
+ * by the review process. Gate via apps.yaml feature flag.
7
+ */
8
+ import { type SocialClient, type SocialPostContent, type SocialPostResult, type ValidationResult } from "./base.js";
9
+ export interface TikTokConfig {
10
+ clientKey: string;
11
+ clientSecret: string;
12
+ accessToken: string;
13
+ }
14
+ export declare class TikTokClient implements SocialClient {
15
+ private readonly config;
16
+ readonly platform: "tiktok";
17
+ constructor(config: TikTokConfig);
18
+ post(content: SocialPostContent): Promise<SocialPostResult>;
19
+ validateContent(text: string): ValidationResult;
20
+ deletePost(_postId: string): Promise<boolean>;
21
+ private buildText;
22
+ }
23
+ //# sourceMappingURL=tiktok.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tiktok.d.ts","sourceRoot":"","sources":["../../src/social/tiktok.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EACL,KAAK,YAAY,EACjB,KAAK,iBAAiB,EACtB,KAAK,gBAAgB,EACrB,KAAK,gBAAgB,EAGtB,MAAM,WAAW,CAAC;AAMnB,MAAM,WAAW,YAAY;IAC3B,SAAS,EAAE,MAAM,CAAC;IAClB,YAAY,EAAE,MAAM,CAAC;IACrB,WAAW,EAAE,MAAM,CAAC;CACrB;AAED,qBAAa,YAAa,YAAW,YAAY;IAGnC,OAAO,CAAC,QAAQ,CAAC,MAAM;IAFnC,QAAQ,CAAC,QAAQ,EAAG,QAAQ,CAAU;gBAET,MAAM,EAAE,YAAY;IAE3C,IAAI,CAAC,OAAO,EAAE,iBAAiB,GAAG,OAAO,CAAC,gBAAgB,CAAC;IAwEjE,eAAe,CAAC,IAAI,EAAE,MAAM,GAAG,gBAAgB;IAqB/C,UAAU,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAM7C,OAAO,CAAC,SAAS;CAUlB"}
@@ -0,0 +1,110 @@
1
+ /**
2
+ * TikTok client — Content Posting API.
3
+ *
4
+ * NOTE: TikTok's Content Posting API requires app review before
5
+ * production access. This client is implemented but may be blocked
6
+ * by the review process. Gate via apps.yaml feature flag.
7
+ */
8
+ import { isDryRun, dryRunResult, } from "./base.js";
9
+ import * as logger from "../utils/logger.js";
10
+ const BASE_URL = "https://open.tiktokapis.com/v2";
11
+ const MAX_CHARS = 2200;
12
+ export class TikTokClient {
13
+ config;
14
+ platform = "tiktok";
15
+ constructor(config) {
16
+ this.config = config;
17
+ }
18
+ async post(content) {
19
+ if (isDryRun()) {
20
+ logger.info(`[tiktok] DRY_RUN: would post: ${content.text.slice(0, 100)}`);
21
+ return dryRunResult("tiktok", content);
22
+ }
23
+ const text = this.buildText(content);
24
+ const validation = this.validateContent(text);
25
+ if (!validation.valid) {
26
+ return {
27
+ success: false,
28
+ platform: "tiktok",
29
+ error: validation.issues.join("; "),
30
+ };
31
+ }
32
+ if (!content.imageUrl) {
33
+ return {
34
+ success: false,
35
+ platform: "tiktok",
36
+ error: "TikTok requires an image or video for posting",
37
+ };
38
+ }
39
+ try {
40
+ // Step 1: Initialize photo upload
41
+ const initResponse = await fetch(`${BASE_URL}/post/publish/inbox/video/init/`, {
42
+ method: "POST",
43
+ headers: {
44
+ Authorization: `Bearer ${this.config.accessToken}`,
45
+ "Content-Type": "application/json",
46
+ },
47
+ body: JSON.stringify({
48
+ post_info: {
49
+ title: text,
50
+ privacy_level: "PUBLIC_TO_EVERYONE",
51
+ disable_comment: false,
52
+ auto_add_music: true,
53
+ },
54
+ source_info: {
55
+ source: "PULL_FROM_URL",
56
+ photo_cover_index: 0,
57
+ photo_images: [content.imageUrl],
58
+ },
59
+ }),
60
+ });
61
+ if (!initResponse.ok) {
62
+ const err = await initResponse.text();
63
+ throw new Error(`TikTok post init failed: ${err}`);
64
+ }
65
+ const result = (await initResponse.json());
66
+ return {
67
+ success: true,
68
+ platform: "tiktok",
69
+ postId: result.data?.publish_id,
70
+ postedAt: new Date().toISOString(),
71
+ };
72
+ }
73
+ catch (err) {
74
+ const msg = err instanceof Error ? err.message : String(err);
75
+ logger.error(`[tiktok] Post failed: ${msg}`);
76
+ return { success: false, platform: "tiktok", error: msg };
77
+ }
78
+ }
79
+ validateContent(text) {
80
+ const issues = [];
81
+ const suggestions = [];
82
+ if (!text.trim()) {
83
+ issues.push("Text is empty");
84
+ return { valid: false, characterCount: 0, issues, suggestions };
85
+ }
86
+ if (text.length > MAX_CHARS) {
87
+ issues.push(`Caption exceeds ${String(MAX_CHARS)} characters (${String(text.length)})`);
88
+ }
89
+ return {
90
+ valid: issues.length === 0,
91
+ characterCount: text.length,
92
+ issues,
93
+ suggestions,
94
+ };
95
+ }
96
+ deletePost(_postId) {
97
+ // TikTok Content Posting API does not support deletion
98
+ logger.info("[tiktok] Post deletion not supported via API");
99
+ return Promise.resolve(false);
100
+ }
101
+ buildText(content) {
102
+ let text = content.text;
103
+ if (content.hashtags?.length) {
104
+ const tags = content.hashtags.map((t) => t.startsWith("#") ? t : `#${t}`);
105
+ text = `${text} ${tags.join(" ")}`;
106
+ }
107
+ return text;
108
+ }
109
+ }
110
+ //# sourceMappingURL=tiktok.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tiktok.js","sourceRoot":"","sources":["../../src/social/tiktok.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,30 @@
1
+ /**
2
+ * Twitter/X client — API v2 for posting, v1.1 for media upload.
3
+ *
4
+ * Ported from linkgo `ai-service/src/social/twitter_client.py` patterns.
5
+ * Uses raw fetch instead of tweepy (no Python SDK equivalent in TS).
6
+ * OAuth 1.0a headers are constructed manually for v1.1 media uploads.
7
+ */
8
+ import { type SocialClient, type SocialPostContent, type SocialPostResult, type ValidationResult } from "./base.js";
9
+ export interface TwitterConfig {
10
+ apiKey: string;
11
+ apiSecret: string;
12
+ accessToken: string;
13
+ accessTokenSecret: string;
14
+ }
15
+ export declare class TwitterClient implements SocialClient {
16
+ private readonly config;
17
+ readonly platform: "twitter";
18
+ constructor(config: TwitterConfig);
19
+ post(content: SocialPostContent): Promise<SocialPostResult>;
20
+ validateContent(text: string): ValidationResult;
21
+ deletePost(postId: string): Promise<boolean>;
22
+ private buildText;
23
+ private uploadMedia;
24
+ private v2Request;
25
+ /**
26
+ * Build OAuth 1.0a Authorization header.
27
+ */
28
+ private buildOAuth1Headers;
29
+ }
30
+ //# sourceMappingURL=twitter.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"twitter.d.ts","sourceRoot":"","sources":["../../src/social/twitter.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAGH,OAAO,EACL,KAAK,YAAY,EACjB,KAAK,iBAAiB,EACtB,KAAK,gBAAgB,EACrB,KAAK,gBAAgB,EAGtB,MAAM,WAAW,CAAC;AAOnB,MAAM,WAAW,aAAa;IAC5B,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,MAAM,CAAC;IAClB,WAAW,EAAE,MAAM,CAAC;IACpB,iBAAiB,EAAE,MAAM,CAAC;CAC3B;AAED,qBAAa,aAAc,YAAW,YAAY;IAGpC,OAAO,CAAC,QAAQ,CAAC,MAAM;IAFnC,QAAQ,CAAC,QAAQ,EAAG,SAAS,CAAU;gBAEV,MAAM,EAAE,aAAa;IAE5C,IAAI,CAAC,OAAO,EAAE,iBAAiB,GAAG,OAAO,CAAC,gBAAgB,CAAC;IA8CjE,eAAe,CAAC,IAAI,EAAE,MAAM,GAAG,gBAAgB;IAwBzC,UAAU,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAalD,OAAO,CAAC,SAAS;YAWH,WAAW;YA6CX,SAAS;IAyBvB;;OAEG;IACH,OAAO,CAAC,kBAAkB;CAuC3B"}
@@ -0,0 +1,189 @@
1
+ /**
2
+ * Twitter/X client — API v2 for posting, v1.1 for media upload.
3
+ *
4
+ * Ported from linkgo `ai-service/src/social/twitter_client.py` patterns.
5
+ * Uses raw fetch instead of tweepy (no Python SDK equivalent in TS).
6
+ * OAuth 1.0a headers are constructed manually for v1.1 media uploads.
7
+ */
8
+ import crypto from "node:crypto";
9
+ import { isDryRun, dryRunResult, } from "./base.js";
10
+ import * as logger from "../utils/logger.js";
11
+ const MAX_CHARS = 280;
12
+ const TCO_URL_LENGTH = 23;
13
+ const URL_REGEX = /https?:\/\/[^\s]+/g;
14
+ export class TwitterClient {
15
+ config;
16
+ platform = "twitter";
17
+ constructor(config) {
18
+ this.config = config;
19
+ }
20
+ async post(content) {
21
+ if (isDryRun()) {
22
+ logger.info(`[twitter] DRY_RUN: would post: ${content.text.slice(0, 100)}`);
23
+ return dryRunResult("twitter", content);
24
+ }
25
+ const text = this.buildText(content);
26
+ const validation = this.validateContent(text);
27
+ if (!validation.valid) {
28
+ return {
29
+ success: false,
30
+ platform: "twitter",
31
+ error: validation.issues.join("; "),
32
+ };
33
+ }
34
+ try {
35
+ const body = { text };
36
+ // Upload image if provided
37
+ if (content.imageUrl) {
38
+ const mediaId = await this.uploadMedia(content.imageUrl);
39
+ if (mediaId) {
40
+ body["media"] = { media_ids: [mediaId] };
41
+ }
42
+ }
43
+ const response = await this.v2Request("POST", "/tweets", body);
44
+ const postId = response?.data?.id;
45
+ return {
46
+ success: true,
47
+ platform: "twitter",
48
+ postId,
49
+ postUrl: postId
50
+ ? `https://twitter.com/i/status/${postId}`
51
+ : undefined,
52
+ postedAt: new Date().toISOString(),
53
+ };
54
+ }
55
+ catch (err) {
56
+ const msg = err instanceof Error ? err.message : String(err);
57
+ logger.error(`[twitter] Post failed: ${msg}`);
58
+ return { success: false, platform: "twitter", error: msg };
59
+ }
60
+ }
61
+ validateContent(text) {
62
+ const issues = [];
63
+ const suggestions = [];
64
+ if (!text.trim()) {
65
+ issues.push("Text is empty");
66
+ return { valid: false, characterCount: 0, issues, suggestions };
67
+ }
68
+ // URLs count as 23 chars (t.co shortening)
69
+ const effectiveLength = text.replace(URL_REGEX, "x".repeat(TCO_URL_LENGTH)).length;
70
+ if (effectiveLength > MAX_CHARS) {
71
+ issues.push(`Text exceeds ${String(MAX_CHARS)} characters (effective: ${String(effectiveLength)})`);
72
+ }
73
+ return {
74
+ valid: issues.length === 0,
75
+ characterCount: effectiveLength,
76
+ issues,
77
+ suggestions,
78
+ };
79
+ }
80
+ async deletePost(postId) {
81
+ if (isDryRun()) {
82
+ logger.info(`[twitter] DRY_RUN: would delete post ${postId}`);
83
+ return true;
84
+ }
85
+ try {
86
+ await this.v2Request("DELETE", `/tweets/${postId}`);
87
+ return true;
88
+ }
89
+ catch {
90
+ return false;
91
+ }
92
+ }
93
+ buildText(content) {
94
+ let text = content.text;
95
+ if (content.hashtags?.length) {
96
+ const tags = content.hashtags.map((t) => t.startsWith("#") ? t : `#${t}`);
97
+ text = `${text}\n\n${tags.join(" ")}`;
98
+ }
99
+ return text;
100
+ }
101
+ async uploadMedia(imageUrl) {
102
+ try {
103
+ // Download image
104
+ const imgResponse = await fetch(imageUrl);
105
+ if (!imgResponse.ok)
106
+ return null;
107
+ const buffer = Buffer.from(await imgResponse.arrayBuffer());
108
+ // Build OAuth 1.0a headers for v1.1 media upload
109
+ const uploadUrl = "https://upload.twitter.com/1.1/media/upload.json";
110
+ const boundary = `----FormBoundary${crypto.randomUUID().replace(/-/g, "")}`;
111
+ const bodyParts = [
112
+ `--${boundary}\r\n`,
113
+ 'Content-Disposition: form-data; name="media_data"\r\n\r\n',
114
+ buffer.toString("base64"),
115
+ `\r\n--${boundary}--\r\n`,
116
+ ];
117
+ const bodyBuffer = Buffer.from(bodyParts.join(""));
118
+ const oauthHeaders = this.buildOAuth1Headers("POST", uploadUrl);
119
+ const response = await fetch(uploadUrl, {
120
+ method: "POST",
121
+ headers: {
122
+ ...oauthHeaders,
123
+ "Content-Type": `multipart/form-data; boundary=${boundary}`,
124
+ },
125
+ body: bodyBuffer,
126
+ });
127
+ if (!response.ok) {
128
+ logger.error(`[twitter] Media upload failed: ${String(response.status)}`);
129
+ return null;
130
+ }
131
+ const result = (await response.json());
132
+ return result.media_id_string ?? null;
133
+ }
134
+ catch (err) {
135
+ logger.error(`[twitter] Media upload error: ${err instanceof Error ? err.message : String(err)}`);
136
+ return null;
137
+ }
138
+ }
139
+ async v2Request(method, path, body) {
140
+ const url = `https://api.twitter.com/2${path}`;
141
+ const oauthHeaders = this.buildOAuth1Headers(method, url);
142
+ const response = await fetch(url, {
143
+ method,
144
+ headers: {
145
+ ...oauthHeaders,
146
+ "Content-Type": "application/json",
147
+ },
148
+ ...(body ? { body: JSON.stringify(body) } : {}),
149
+ });
150
+ if (!response.ok) {
151
+ const text = await response.text();
152
+ throw new Error(`Twitter API ${String(response.status)}: ${text}`);
153
+ }
154
+ return response.json();
155
+ }
156
+ /**
157
+ * Build OAuth 1.0a Authorization header.
158
+ */
159
+ buildOAuth1Headers(method, url) {
160
+ const timestamp = Math.floor(Date.now() / 1000).toString();
161
+ const nonce = crypto.randomUUID().replace(/-/g, "");
162
+ const params = {
163
+ oauth_consumer_key: this.config.apiKey,
164
+ oauth_nonce: nonce,
165
+ oauth_signature_method: "HMAC-SHA1",
166
+ oauth_timestamp: timestamp,
167
+ oauth_token: this.config.accessToken,
168
+ oauth_version: "1.0",
169
+ };
170
+ // Build signature base string
171
+ const sortedParams = Object.keys(params)
172
+ .sort()
173
+ .map((k) => `${encodeURIComponent(k)}=${encodeURIComponent(params[k])}`)
174
+ .join("&");
175
+ const baseString = `${method.toUpperCase()}&${encodeURIComponent(url)}&${encodeURIComponent(sortedParams)}`;
176
+ const signingKey = `${encodeURIComponent(this.config.apiSecret)}&${encodeURIComponent(this.config.accessTokenSecret)}`;
177
+ const signature = crypto
178
+ .createHmac("sha1", signingKey)
179
+ .update(baseString)
180
+ .digest("base64");
181
+ params["oauth_signature"] = signature;
182
+ const header = Object.keys(params)
183
+ .sort()
184
+ .map((k) => `${encodeURIComponent(k)}="${encodeURIComponent(params[k])}"`)
185
+ .join(", ");
186
+ return { Authorization: `OAuth ${header}` };
187
+ }
188
+ }
189
+ //# sourceMappingURL=twitter.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"twitter.js","sourceRoot":"","sources":["../../src/social/twitter.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,21 @@
1
+ /**
2
+ * YouTube client — Data API v3, community posts.
3
+ *
4
+ * Posts community updates to a YouTube channel. Image upload via
5
+ * the Activities API or direct community post endpoint.
6
+ */
7
+ import { type SocialClient, type SocialPostContent, type SocialPostResult, type ValidationResult } from "./base.js";
8
+ export interface YouTubeConfig {
9
+ accessToken: string;
10
+ channelId: string;
11
+ }
12
+ export declare class YouTubeClient implements SocialClient {
13
+ private readonly config;
14
+ readonly platform: "youtube";
15
+ constructor(config: YouTubeConfig);
16
+ post(content: SocialPostContent): Promise<SocialPostResult>;
17
+ validateContent(text: string): ValidationResult;
18
+ deletePost(_postId: string): Promise<boolean>;
19
+ private buildText;
20
+ }
21
+ //# sourceMappingURL=youtube.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"youtube.d.ts","sourceRoot":"","sources":["../../src/social/youtube.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EACL,KAAK,YAAY,EACjB,KAAK,iBAAiB,EACtB,KAAK,gBAAgB,EACrB,KAAK,gBAAgB,EAGtB,MAAM,WAAW,CAAC;AAKnB,MAAM,WAAW,aAAa;IAC5B,WAAW,EAAE,MAAM,CAAC;IACpB,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,qBAAa,aAAc,YAAW,YAAY;IAGpC,OAAO,CAAC,QAAQ,CAAC,MAAM;IAFnC,QAAQ,CAAC,QAAQ,EAAG,SAAS,CAAU;gBAEV,MAAM,EAAE,aAAa;IAE5C,IAAI,CAAC,OAAO,EAAE,iBAAiB,GAAG,OAAO,CAAC,gBAAgB,CAAC;IAqEjE,eAAe,CAAC,IAAI,EAAE,MAAM,GAAG,gBAAgB;IAqB/C,UAAU,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAM7C,OAAO,CAAC,SAAS;CAUlB"}
@@ -0,0 +1,108 @@
1
+ /**
2
+ * YouTube client — Data API v3, community posts.
3
+ *
4
+ * Posts community updates to a YouTube channel. Image upload via
5
+ * the Activities API or direct community post endpoint.
6
+ */
7
+ import { isDryRun, dryRunResult, } from "./base.js";
8
+ import * as logger from "../utils/logger.js";
9
+ const MAX_CHARS = 5000;
10
+ export class YouTubeClient {
11
+ config;
12
+ platform = "youtube";
13
+ constructor(config) {
14
+ this.config = config;
15
+ }
16
+ async post(content) {
17
+ if (isDryRun()) {
18
+ logger.info(`[youtube] DRY_RUN: would post: ${content.text.slice(0, 100)}`);
19
+ return dryRunResult("youtube", content);
20
+ }
21
+ const text = this.buildText(content);
22
+ const validation = this.validateContent(text);
23
+ if (!validation.valid) {
24
+ return {
25
+ success: false,
26
+ platform: "youtube",
27
+ error: validation.issues.join("; "),
28
+ };
29
+ }
30
+ try {
31
+ // YouTube Data API v3 — create a community post (activities.insert)
32
+ // Note: Community posts require channel membership and the API
33
+ // endpoint may be limited. Using the bulletin type.
34
+ const response = await fetch("https://www.googleapis.com/youtube/v3/activities?part=snippet,contentDetails", {
35
+ method: "POST",
36
+ headers: {
37
+ Authorization: `Bearer ${this.config.accessToken}`,
38
+ "Content-Type": "application/json",
39
+ },
40
+ body: JSON.stringify({
41
+ snippet: {
42
+ channelId: this.config.channelId,
43
+ description: text,
44
+ type: "bulletin",
45
+ },
46
+ contentDetails: {
47
+ bulletin: {
48
+ resourceId: {
49
+ kind: "youtube#channel",
50
+ channelId: this.config.channelId,
51
+ },
52
+ },
53
+ },
54
+ }),
55
+ });
56
+ if (!response.ok) {
57
+ const err = await response.text();
58
+ throw new Error(`YouTube API ${String(response.status)}: ${err}`);
59
+ }
60
+ const result = (await response.json());
61
+ return {
62
+ success: true,
63
+ platform: "youtube",
64
+ postId: result.id,
65
+ postUrl: result.id
66
+ ? `https://www.youtube.com/post/${result.id}`
67
+ : undefined,
68
+ postedAt: new Date().toISOString(),
69
+ };
70
+ }
71
+ catch (err) {
72
+ const msg = err instanceof Error ? err.message : String(err);
73
+ logger.error(`[youtube] Post failed: ${msg}`);
74
+ return { success: false, platform: "youtube", error: msg };
75
+ }
76
+ }
77
+ validateContent(text) {
78
+ const issues = [];
79
+ const suggestions = [];
80
+ if (!text.trim()) {
81
+ issues.push("Text is empty");
82
+ return { valid: false, characterCount: 0, issues, suggestions };
83
+ }
84
+ if (text.length > MAX_CHARS) {
85
+ issues.push(`Text exceeds ${String(MAX_CHARS)} characters (${String(text.length)})`);
86
+ }
87
+ return {
88
+ valid: issues.length === 0,
89
+ characterCount: text.length,
90
+ issues,
91
+ suggestions,
92
+ };
93
+ }
94
+ deletePost(_postId) {
95
+ // Community posts cannot be deleted via the Data API v3
96
+ logger.info("[youtube] Community post deletion not supported via API");
97
+ return Promise.resolve(false);
98
+ }
99
+ buildText(content) {
100
+ let text = content.text;
101
+ if (content.hashtags?.length) {
102
+ const tags = content.hashtags.map((t) => t.startsWith("#") ? t : `#${t}`);
103
+ text = `${text}\n\n${tags.join(" ")}`;
104
+ }
105
+ return text;
106
+ }
107
+ }
108
+ //# sourceMappingURL=youtube.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"youtube.js","sourceRoot":"","sources":["../../src/social/youtube.ts"],"names":[],"mappings":"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"}