thumbgate 1.4.3 → 1.4.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (270) hide show
  1. package/.claude-plugin/marketplace.json +2 -2
  2. package/.claude-plugin/plugin.json +1 -1
  3. package/.well-known/llms.txt +12 -8
  4. package/.well-known/mcp/server-card.json +1 -1
  5. package/README.md +18 -8
  6. package/adapters/README.md +1 -1
  7. package/adapters/claude/.mcp.json +2 -2
  8. package/adapters/codex/config.toml +2 -2
  9. package/adapters/mcp/server-stdio.js +1 -1
  10. package/adapters/opencode/opencode.json +1 -1
  11. package/config/github-about.json +2 -2
  12. package/package.json +158 -10
  13. package/scripts/billing.js +5 -2
  14. package/scripts/statusline.sh +1 -0
  15. package/src/api/server.js +113 -16
  16. package/src/index.js +3 -0
  17. package/.claude-plugin/bundle/icon.png +0 -0
  18. package/.claude-plugin/bundle/icon.svg +0 -18
  19. package/.claude-plugin/bundle/server/index.js +0 -24
  20. package/adapters/chatgpt/INSTALL.md +0 -158
  21. package/adapters/perplexity/.mcp.json +0 -36
  22. package/adapters/perplexity/config.toml +0 -16
  23. package/adapters/perplexity/opencode.json +0 -29
  24. package/bin/memory.sh +0 -64
  25. package/bin/obsidian-sync.sh +0 -20
  26. package/plugins/amp-skill/INSTALL.md +0 -52
  27. package/plugins/amp-skill/SKILL.md +0 -64
  28. package/plugins/claude-codex-bridge/.claude-plugin/plugin.json +0 -22
  29. package/plugins/claude-codex-bridge/.mcp.json +0 -14
  30. package/plugins/claude-codex-bridge/INSTALL.md +0 -43
  31. package/plugins/claude-codex-bridge/README.md +0 -46
  32. package/plugins/claude-codex-bridge/scripts/codex-bridge.js +0 -286
  33. package/plugins/claude-codex-bridge/skills/adversarial-review/SKILL.md +0 -24
  34. package/plugins/claude-codex-bridge/skills/result/SKILL.md +0 -22
  35. package/plugins/claude-codex-bridge/skills/review/SKILL.md +0 -28
  36. package/plugins/claude-codex-bridge/skills/second-pass/SKILL.md +0 -27
  37. package/plugins/claude-codex-bridge/skills/setup/SKILL.md +0 -21
  38. package/plugins/claude-codex-bridge/skills/status/SKILL.md +0 -19
  39. package/plugins/claude-skill/INSTALL.md +0 -55
  40. package/plugins/claude-skill/SKILL.md +0 -46
  41. package/plugins/codex-profile/.codex-plugin/plugin.json +0 -43
  42. package/plugins/codex-profile/.mcp.json +0 -14
  43. package/plugins/codex-profile/AGENTS.md +0 -20
  44. package/plugins/codex-profile/INSTALL.md +0 -89
  45. package/plugins/codex-profile/README.md +0 -61
  46. package/plugins/cursor-marketplace/.cursor-plugin/plugin.json +0 -23
  47. package/plugins/cursor-marketplace/CHANGELOG.md +0 -30
  48. package/plugins/cursor-marketplace/LICENSE +0 -21
  49. package/plugins/cursor-marketplace/README.md +0 -124
  50. package/plugins/cursor-marketplace/agents/reliability-reviewer.md +0 -31
  51. package/plugins/cursor-marketplace/assets/logo-400x400.png +0 -0
  52. package/plugins/cursor-marketplace/commands/capture-feedback.md +0 -33
  53. package/plugins/cursor-marketplace/commands/check-gates.md +0 -25
  54. package/plugins/cursor-marketplace/commands/show-lessons.md +0 -27
  55. package/plugins/cursor-marketplace/hooks/hooks.json +0 -10
  56. package/plugins/cursor-marketplace/mcp.json +0 -14
  57. package/plugins/cursor-marketplace/rules/feedback-capture.mdc +0 -34
  58. package/plugins/cursor-marketplace/rules/pre-action-gates.mdc +0 -30
  59. package/plugins/cursor-marketplace/rules/session-continuity.mdc +0 -28
  60. package/plugins/cursor-marketplace/scripts/gate-check.sh +0 -21
  61. package/plugins/cursor-marketplace/skills/capture-feedback/SKILL.md +0 -48
  62. package/plugins/cursor-marketplace/skills/prevention-rules/SKILL.md +0 -31
  63. package/plugins/cursor-marketplace/skills/recall-context/SKILL.md +0 -30
  64. package/plugins/cursor-marketplace/skills/search-lessons/SKILL.md +0 -33
  65. package/plugins/gemini-extension/INSTALL.md +0 -92
  66. package/plugins/gemini-extension/gemini_prompt.txt +0 -14
  67. package/plugins/gemini-extension/tool_contract.json +0 -45
  68. package/plugins/opencode-profile/INSTALL.md +0 -57
  69. package/public/assets/instagram-card.png +0 -0
  70. package/public/assets/tiktok-agent-memory.mp4 +0 -0
  71. package/public/blog.html +0 -474
  72. package/public/compare/mem0.html +0 -189
  73. package/public/compare/speclock.html +0 -180
  74. package/public/compare.html +0 -310
  75. package/public/dashboard.html +0 -1100
  76. package/public/guide.html +0 -317
  77. package/public/guides/claude-code-prevent-repeated-mistakes.html +0 -161
  78. package/public/guides/codex-cli-guardrails.html +0 -158
  79. package/public/guides/cursor-prevent-repeated-mistakes.html +0 -161
  80. package/public/guides/pre-action-gates.html +0 -162
  81. package/public/guides/stop-repeated-ai-agent-mistakes.html +0 -159
  82. package/public/index.html +0 -1225
  83. package/public/js/buyer-intent.js +0 -252
  84. package/public/learn/agent-harness-pattern.html +0 -180
  85. package/public/learn/ai-agent-persistent-memory.html +0 -203
  86. package/public/learn/learn.css +0 -45
  87. package/public/learn/mcp-pre-action-gates-explained.html +0 -172
  88. package/public/learn/stop-ai-agent-force-push.html +0 -134
  89. package/public/learn/vibe-coding-safety-net.html +0 -142
  90. package/public/learn.html +0 -274
  91. package/public/lessons.html +0 -967
  92. package/public/llm-context.md +0 -156
  93. package/public/pro.html +0 -1087
  94. package/public/vercel.json +0 -8
  95. package/scripts/a2ui-engine.js +0 -73
  96. package/scripts/adk-consolidator.js +0 -274
  97. package/scripts/agent-security-hardening.js +0 -225
  98. package/scripts/ai-search-visibility.js +0 -116
  99. package/scripts/autonomous-sales-agent.js +0 -39
  100. package/scripts/autoresearch-runner.js +0 -216
  101. package/scripts/background-agent-governance.js +0 -229
  102. package/scripts/behavioral-extraction.js +0 -93
  103. package/scripts/budget-enforcer.js +0 -173
  104. package/scripts/budget-guard.js +0 -173
  105. package/scripts/build-claude-mcpb.js +0 -255
  106. package/scripts/build-codex-plugin.js +0 -152
  107. package/scripts/capture-railway-diagnostics.sh +0 -97
  108. package/scripts/changeset-check.js +0 -372
  109. package/scripts/check-congruence.js +0 -443
  110. package/scripts/computer-use-firewall.js +0 -280
  111. package/scripts/content-engine/linkedin-content-generator.js +0 -154
  112. package/scripts/content-engine/output/linkedin-memento-validation.md +0 -17
  113. package/scripts/content-engine/output/linkedin-posts-2026-04-09.md +0 -175
  114. package/scripts/content-engine/reddit-thread-finder.js +0 -154
  115. package/scripts/context-engine.js +0 -710
  116. package/scripts/daily-digest.js +0 -11
  117. package/scripts/data-governance.js +0 -173
  118. package/scripts/deploy-gcp.sh +0 -44
  119. package/scripts/deploy-policy.js +0 -249
  120. package/scripts/disagreement-mining.js +0 -315
  121. package/scripts/dpo-optimizer.js +0 -206
  122. package/scripts/ensure-repo-bootstrap.js +0 -130
  123. package/scripts/ephemeral-agent-store.js +0 -212
  124. package/scripts/eval-harness.js +0 -56
  125. package/scripts/export-kto-pairs.js +0 -309
  126. package/scripts/export-training.js +0 -446
  127. package/scripts/feedback-fallback.js +0 -111
  128. package/scripts/feedback-inbox-read.js +0 -162
  129. package/scripts/feedback-root-consolidator.js +0 -233
  130. package/scripts/feedback-to-memory.js +0 -185
  131. package/scripts/gate-satisfy.js +0 -42
  132. package/scripts/generate-paperbanana-diagrams.sh +0 -99
  133. package/scripts/generate-pretool-hook.sh +0 -40
  134. package/scripts/github-about.js +0 -430
  135. package/scripts/github-outreach.js +0 -65
  136. package/scripts/gtm-revenue-loop.js +0 -535
  137. package/scripts/hallucination-detector.js +0 -226
  138. package/scripts/hf-papers.js +0 -317
  139. package/scripts/hook-auto-capture.sh +0 -100
  140. package/scripts/hook-stop-pr-thread-check.sh +0 -68
  141. package/scripts/hook-stop-self-score.sh +0 -51
  142. package/scripts/hook-stop-verify-deploy.sh +0 -31
  143. package/scripts/hook-verify-before-done.sh +0 -20
  144. package/scripts/managed-dpo-export.js +0 -91
  145. package/scripts/markdown-escape.js +0 -12
  146. package/scripts/marketing-experiment.js +0 -657
  147. package/scripts/memalign-recall.js +0 -111
  148. package/scripts/memory-migration.js +0 -296
  149. package/scripts/meta-policy.js +0 -190
  150. package/scripts/metered-billing.js +0 -16
  151. package/scripts/model-tier-router.js +0 -310
  152. package/scripts/money-watcher.js +0 -218
  153. package/scripts/multi-hop-recall.js +0 -240
  154. package/scripts/per-step-scoring.js +0 -163
  155. package/scripts/perplexity-command-center.js +0 -644
  156. package/scripts/perplexity-marketing.js +0 -454
  157. package/scripts/pii-scanner.js +0 -153
  158. package/scripts/plan-gate.js +0 -154
  159. package/scripts/post-everywhere.js +0 -341
  160. package/scripts/post-to-x-retry.sh +0 -22
  161. package/scripts/post-to-x.js +0 -369
  162. package/scripts/pr-manager.js +0 -421
  163. package/scripts/principle-extractor.js +0 -162
  164. package/scripts/pro-features.js +0 -41
  165. package/scripts/prompt-dlp.js +0 -222
  166. package/scripts/prove-adapters.js +0 -860
  167. package/scripts/prove-attribution.js +0 -361
  168. package/scripts/prove-automation.js +0 -651
  169. package/scripts/prove-autoresearch.js +0 -304
  170. package/scripts/prove-claim-verification.js +0 -277
  171. package/scripts/prove-cloudflare-sandbox.js +0 -161
  172. package/scripts/prove-data-pipeline.js +0 -408
  173. package/scripts/prove-data-quality.js +0 -227
  174. package/scripts/prove-evolution.js +0 -352
  175. package/scripts/prove-harnesses.js +0 -287
  176. package/scripts/prove-intelligence.js +0 -257
  177. package/scripts/prove-lancedb.js +0 -425
  178. package/scripts/prove-local-intelligence.js +0 -340
  179. package/scripts/prove-loop-closure.js +0 -263
  180. package/scripts/prove-packaged-runtime.js +0 -327
  181. package/scripts/prove-predictive-insights.js +0 -355
  182. package/scripts/prove-runtime.js +0 -363
  183. package/scripts/prove-seo-gsd.js +0 -234
  184. package/scripts/prove-settings.js +0 -279
  185. package/scripts/prove-subway-upgrades.js +0 -277
  186. package/scripts/prove-tessl.js +0 -229
  187. package/scripts/prove-training-export.js +0 -325
  188. package/scripts/prove-workflow-contract.js +0 -112
  189. package/scripts/prove-xmemory.js +0 -332
  190. package/scripts/publish-decision.js +0 -159
  191. package/scripts/ralph-loop.js +0 -376
  192. package/scripts/ralph-mode-ci.js +0 -434
  193. package/scripts/reddit-dm-outreach.js +0 -192
  194. package/scripts/reddit-monitor-cron.sh +0 -26
  195. package/scripts/reminder-engine.js +0 -132
  196. package/scripts/revenue-status.js +0 -472
  197. package/scripts/rotate-stripe-webhook-secret.js +0 -314
  198. package/scripts/schedule-manager.js +0 -249
  199. package/scripts/self-healing-check.js +0 -193
  200. package/scripts/session-analyzer.js +0 -533
  201. package/scripts/shieldcortex-memory-firewall-runner.mjs +0 -53
  202. package/scripts/skill-exporter.js +0 -260
  203. package/scripts/skill-materializer.js +0 -134
  204. package/scripts/skill-packs.js +0 -136
  205. package/scripts/skill-proposer.js +0 -99
  206. package/scripts/skill-quality-tracker.js +0 -282
  207. package/scripts/slow-loop.js +0 -72
  208. package/scripts/social-analytics/db/marketing-db.js +0 -179
  209. package/scripts/social-analytics/db/schema.sql +0 -55
  210. package/scripts/social-analytics/digest.js +0 -256
  211. package/scripts/social-analytics/engagement-audit.js +0 -185
  212. package/scripts/social-analytics/generate-instagram-card.js +0 -123
  213. package/scripts/social-analytics/generate-slides.js +0 -268
  214. package/scripts/social-analytics/instagram-thumbgate-post.js +0 -111
  215. package/scripts/social-analytics/install-growth-automation.js +0 -114
  216. package/scripts/social-analytics/load-env.js +0 -77
  217. package/scripts/social-analytics/mcp-server.js +0 -289
  218. package/scripts/social-analytics/normalizer.js +0 -580
  219. package/scripts/social-analytics/notify.js +0 -162
  220. package/scripts/social-analytics/poll-all.js +0 -107
  221. package/scripts/social-analytics/pollers/github.js +0 -195
  222. package/scripts/social-analytics/pollers/instagram.js +0 -253
  223. package/scripts/social-analytics/pollers/linkedin.js +0 -340
  224. package/scripts/social-analytics/pollers/plausible.js +0 -245
  225. package/scripts/social-analytics/pollers/reddit.js +0 -306
  226. package/scripts/social-analytics/pollers/threads.js +0 -233
  227. package/scripts/social-analytics/pollers/tiktok.js +0 -203
  228. package/scripts/social-analytics/pollers/x.js +0 -227
  229. package/scripts/social-analytics/pollers/youtube.js +0 -304
  230. package/scripts/social-analytics/pollers/zernio.js +0 -183
  231. package/scripts/social-analytics/post-video.js +0 -316
  232. package/scripts/social-analytics/publish-instagram-thumbgate.js +0 -104
  233. package/scripts/social-analytics/publish-thumbgate-launch.js +0 -322
  234. package/scripts/social-analytics/publishers/devto.js +0 -122
  235. package/scripts/social-analytics/publishers/instagram.js +0 -317
  236. package/scripts/social-analytics/publishers/linkedin.js +0 -294
  237. package/scripts/social-analytics/publishers/reddit.js +0 -385
  238. package/scripts/social-analytics/publishers/threads.js +0 -275
  239. package/scripts/social-analytics/publishers/tiktok.js +0 -217
  240. package/scripts/social-analytics/publishers/x.js +0 -259
  241. package/scripts/social-analytics/publishers/youtube.js +0 -223
  242. package/scripts/social-analytics/publishers/zernio.js +0 -568
  243. package/scripts/social-analytics/reconcile-thumbgate-campaign.js +0 -165
  244. package/scripts/social-analytics/run-digest.js +0 -34
  245. package/scripts/social-analytics/schedule-thumbgate-campaign.js +0 -275
  246. package/scripts/social-analytics/store.js +0 -455
  247. package/scripts/social-analytics/sync-launch-assets.js +0 -185
  248. package/scripts/social-analytics/utm.js +0 -143
  249. package/scripts/social-pipeline.js +0 -2626
  250. package/scripts/social-post-hourly.js +0 -228
  251. package/scripts/social-quality-gate.js +0 -134
  252. package/scripts/social-reply-monitor.js +0 -592
  253. package/scripts/status-dashboard.js +0 -155
  254. package/scripts/stripe-live-status.js +0 -115
  255. package/scripts/subagent-profiles.js +0 -79
  256. package/scripts/sync-branch-protection.js +0 -340
  257. package/scripts/sync-gh-secrets-from-env.sh +0 -70
  258. package/scripts/sync-github-about.js +0 -55
  259. package/scripts/sync-version.js +0 -479
  260. package/scripts/synthetic-dpo.js +0 -234
  261. package/scripts/tessl-export.js +0 -369
  262. package/scripts/test-coverage.js +0 -128
  263. package/scripts/thumbgate-bench.js +0 -494
  264. package/scripts/thumbgate_session_start.sh +0 -32
  265. package/scripts/train_from_feedback.py +0 -929
  266. package/scripts/validate-feedback.js +0 -581
  267. package/scripts/verify-obsidian-setup.sh +0 -269
  268. package/scripts/verify-run.js +0 -269
  269. package/scripts/weekly-auto-post.js +0 -124
  270. package/scripts/x-autonomous-marketing.js +0 -139
@@ -1,434 +0,0 @@
1
- #!/usr/bin/env node
2
- 'use strict';
3
-
4
- /**
5
- * Ralph Mode CI — runs in GitHub Actions with secrets injected.
6
- * Handles: X tweets, X mention replies, LinkedIn posts, GitHub issue monitoring,
7
- * GitHub repo search + outreach, dev.to publishing, ThumbGate stats.
8
- */
9
-
10
- const crypto = require('crypto');
11
- const https = require('https');
12
-
13
- // ── Env (trim to handle GitHub Actions trailing whitespace) ─────────────
14
- const X_API_KEY = (process.env.X_API_KEY || '').trim();
15
- const X_API_SECRET = (process.env.X_API_SECRET || '').trim();
16
- const X_ACCESS_TOKEN = (process.env.X_ACCESS_TOKEN || '').trim();
17
- const X_ACCESS_TOKEN_SECRET = (process.env.X_ACCESS_TOKEN_SECRET || '').trim();
18
- const X_BEARER_TOKEN = (process.env.X_BEARER_TOKEN || '').trim();
19
- const LINKEDIN_ACCESS_TOKEN = process.env.LINKEDIN_ACCESS_TOKEN;
20
- const LINKEDIN_PERSON_URN = process.env.LINKEDIN_PERSON_URN;
21
- const DEVTO_API_KEY = process.env.DEVTO_API_KEY;
22
- const GH_TOKEN = process.env.GH_TOKEN;
23
-
24
- // ── X OAuth 1.0a ───────────────────────────────────────────────────────
25
- function oauthSign(method, url, params, consumerSecret, tokenSecret) {
26
- const sp = Object.keys(params).sort().map(k => encodeURIComponent(k) + '=' + encodeURIComponent(params[k])).join('&');
27
- const bs = method + '&' + encodeURIComponent(url) + '&' + encodeURIComponent(sp);
28
- return crypto.createHmac('sha1', encodeURIComponent(consumerSecret) + '&' + encodeURIComponent(tokenSecret)).update(bs).digest('base64');
29
- }
30
-
31
- function xAuthHeader(method, url) {
32
- const p = {
33
- oauth_consumer_key: X_API_KEY,
34
- oauth_nonce: crypto.randomBytes(16).toString('hex'),
35
- oauth_signature_method: 'HMAC-SHA1',
36
- oauth_timestamp: Math.floor(Date.now() / 1000).toString(),
37
- oauth_token: X_ACCESS_TOKEN,
38
- oauth_version: '1.0',
39
- };
40
- p.oauth_signature = oauthSign(method, url, p, X_API_SECRET, X_ACCESS_TOKEN_SECRET);
41
- return 'OAuth ' + Object.keys(p).sort().map(k => encodeURIComponent(k) + '="' + encodeURIComponent(p[k]) + '"').join(', ');
42
- }
43
-
44
- // ── Helpers ─────────────────────────────────────────────────────────────
45
- async function postTweet(text) {
46
- const url = 'https://api.twitter.com/2/tweets';
47
- console.log(' X auth debug: credentials ' + (X_API_KEY && X_ACCESS_TOKEN ? 'present' : 'missing'));
48
- const r = await fetch(url, {
49
- method: 'POST',
50
- headers: { Authorization: xAuthHeader('POST', url), 'Content-Type': 'application/json' },
51
- body: JSON.stringify({ text }),
52
- });
53
- const j = await parseJsonResponse(r);
54
- if (!j.data?.id) console.log(' X error detail:', JSON.stringify(j).slice(0, 200));
55
- const id = j.data?.id || '';
56
- return {
57
- id,
58
- ok: r.ok && Boolean(id),
59
- status: r.status,
60
- error: id ? '' : extractApiError(j, r.status),
61
- };
62
- }
63
-
64
- async function replyTweet(text, replyTo) {
65
- const url = 'https://api.twitter.com/2/tweets';
66
- const r = await fetch(url, {
67
- method: 'POST',
68
- headers: { Authorization: xAuthHeader('POST', url), 'Content-Type': 'application/json' },
69
- body: JSON.stringify({ text, reply: { in_reply_to_tweet_id: replyTo } }),
70
- });
71
- const j = await parseJsonResponse(r);
72
- const id = j.data?.id || '';
73
- return {
74
- id,
75
- ok: r.ok && Boolean(id),
76
- status: r.status,
77
- error: id ? '' : extractApiError(j, r.status),
78
- };
79
- }
80
-
81
- async function parseJsonResponse(response) {
82
- try {
83
- return await response.json();
84
- } catch {
85
- return {};
86
- }
87
- }
88
-
89
- function extractApiError(payload = {}, status = 0) {
90
- const firstError = Array.isArray(payload.errors) && payload.errors[0]
91
- ? payload.errors[0].message || payload.errors[0].detail || payload.errors[0].title
92
- : '';
93
- return payload.detail || payload.title || firstError || `HTTP ${status || 'unknown'}`;
94
- }
95
-
96
- function recordTweetPost(report, result, log = console.log) {
97
- if (result && result.ok && result.id) {
98
- log('Tweet posted: ' + result.id);
99
- report.tweets++;
100
- return true;
101
- }
102
- log('Tweet skipped: ' + (result?.error || `HTTP ${result?.status || 'unknown'}`));
103
- return false;
104
- }
105
-
106
- function recordTweetReply(report, username, result, log = console.log) {
107
- const handle = username ? '@' + username : 'unknown user';
108
- if (result && result.ok && result.id) {
109
- log(' Replied to ' + handle + ': ' + result.id);
110
- report.replies++;
111
- return true;
112
- }
113
- log(' Reply skipped for ' + handle + ': ' + (result?.error || `HTTP ${result?.status || 'unknown'}`));
114
- return false;
115
- }
116
-
117
- async function postLinkedIn(text) {
118
- const r = await fetch('https://api.linkedin.com/v2/ugcPosts', {
119
- method: 'POST',
120
- headers: {
121
- Authorization: 'Bearer ' + LINKEDIN_ACCESS_TOKEN,
122
- 'Content-Type': 'application/json',
123
- 'X-Restli-Protocol-Version': '2.0.0',
124
- },
125
- body: JSON.stringify({
126
- author: LINKEDIN_PERSON_URN,
127
- lifecycleState: 'PUBLISHED',
128
- specificContent: {
129
- 'com.linkedin.ugc.ShareContent': {
130
- shareCommentary: { text },
131
- shareMediaCategory: 'NONE',
132
- },
133
- },
134
- visibility: { 'com.linkedin.ugc.MemberNetworkVisibility': 'PUBLIC' },
135
- }),
136
- });
137
- const j = await r.json();
138
- return { id: j.id, status: r.status };
139
- }
140
-
141
- async function ghApi(endpoint) {
142
- const r = await fetch('https://api.github.com' + endpoint, {
143
- headers: { Authorization: 'token ' + GH_TOKEN, Accept: 'application/vnd.github+json' },
144
- });
145
- return r.json();
146
- }
147
-
148
- async function ghPostComment(repo, issueNum, body) {
149
- const r = await fetch(`https://api.github.com/repos/${repo}/issues/${issueNum}/comments`, {
150
- method: 'POST',
151
- headers: {
152
- Authorization: 'token ' + GH_TOKEN,
153
- Accept: 'application/vnd.github+json',
154
- 'Content-Type': 'application/json',
155
- },
156
- body: JSON.stringify({ body }),
157
- });
158
- return r.json();
159
- }
160
-
161
- // ── State file (persisted via git) ──────────────────────────────────────
162
- const fs = require('fs');
163
- const STATE_PATH = '.thumbgate/ralph-state.json';
164
-
165
- function loadState() {
166
- try { return JSON.parse(fs.readFileSync(STATE_PATH, 'utf8')); } catch { return {}; }
167
- }
168
-
169
- function saveState(state) {
170
- fs.mkdirSync('.thumbgate', { recursive: true });
171
- fs.writeFileSync(STATE_PATH, JSON.stringify(state, null, 2) + '\n');
172
- }
173
-
174
- // ── Tweet angles ────────────────────────────────────────────────────────
175
- const TWEET_ANGLES = [
176
- 'Your CLAUDE.md has 50 rules. Your agent ignores half.\n\nThumbGate turns each into a PreToolUse gate — a physical block before the tool call executes.\n\nnpx thumbgate quick-start\nhttps://github.com/IgorGanapolsky/ThumbGate',
177
- 'Self-distillation: your AI agent learns from its own mistakes.\n\n1. Agent runs tool call\n2. System checks outcome\n3. Failure → rule auto-generated\n4. Next session: gate blocks it\n\nZero human feedback needed.\n\nhttps://github.com/IgorGanapolsky/ThumbGate',
178
- 'Thompson Sampling for AI agent gates:\n\nEach gate: Beta(alpha, beta)\nCorrect block → alpha++ → tighter\nFalse positive → beta++ → relaxes\n\nNo thresholds. Gates converge on their own.\n\nhttps://github.com/IgorGanapolsky/ThumbGate',
179
- 'Google DeepMind: hidden prompt injections commandeer AI agents 86% of the time.\n\nThumbGate gates the action, not the prompt. PreToolUse hooks are the last defense.\n\nhttps://github.com/IgorGanapolsky/ThumbGate',
180
- 'Every AI agent framework ships memory. None ship enforcement.\n\nMemory: "Don\'t force-push to main"\nEnforcement: *physically blocked*\n\nThumbGate is the enforcement layer.\n\nhttps://github.com/IgorGanapolsky/ThumbGate',
181
- 'ThumbGate Pro is $19/mo or $149/yr for solo AI agent operators.\n\nLocal dashboard, DPO export, self-distillation, SQL MCP gates, Thompson Sampling, and pre-action enforcement.\n\nTeam rollout starts with intake: $99/seat/mo.\n\nhttps://buy.stripe.com/5kQ4gzbmI9Lo6tPayn3sI06',
182
- 'Context-stuffing: skip RAG entirely.\n\nDump ALL prevention rules into agent context at session start. 20-200 rules = 1K-10K tokens.\n\nInspired by Karpathy. Simpler. Faster.\n\nhttps://github.com/IgorGanapolsky/ThumbGate',
183
- 'The AI agent safety stack:\n\nGovernance: Paperclip\nOrchestration: iloom\nContext: RepoWise\nEnforcement: ThumbGate\n\nAll open source. All necessary.\n\nhttps://github.com/IgorGanapolsky/ThumbGate',
184
- ];
185
-
186
- // ── GitHub issues to monitor ────────────────────────────────────────────
187
- const WATCHED_ISSUES = [
188
- { repo: 'leogodin217/leos_claude_starter', num: 1 },
189
- { repo: 'RepoWise/backend', num: 34 },
190
- { repo: 'ScaleLeanChris/paperclip-ing', num: 1 },
191
- { repo: 'sd0xdev/sd0x-dev-flow', num: 5 },
192
- { repo: 'logi-cmd/agent-guardrails', num: 3 },
193
- ];
194
-
195
- // ── Main ────────────────────────────────────────────────────────────────
196
- async function main() {
197
- console.log('=== RALPH MODE CI — ' + new Date().toISOString() + ' ===\n');
198
- const state = loadState();
199
- const report = { tweets: 0, replies: 0, linkedin: 0, ghIssues: 0, ghOutreach: 0 };
200
-
201
- // ── 1. Check X mentions and reply ──
202
- if (X_BEARER_TOKEN && X_API_KEY) {
203
- try {
204
- const bearer = decodeURIComponent(X_BEARER_TOKEN);
205
- const mentionsRes = await fetch(
206
- 'https://api.twitter.com/2/tweets/search/recent?query=(@IgorGanapolsky OR thumbgate) -from:IgorGanapolsky&max_results=20&tweet.fields=author_id,text,created_at,id&expansions=author_id&user.fields=username',
207
- { headers: { Authorization: 'Bearer ' + bearer } }
208
- ).then(r => r.json());
209
-
210
- const mu = {};
211
- (mentionsRes.includes?.users || []).forEach(u => mu[u.id] = u);
212
- const lastChecked = state.lastMentionCheck || '2026-04-01T00:00:00Z';
213
- const newMentions = (mentionsRes.data || []).filter(
214
- t => new Date(t.created_at) > new Date(lastChecked) && (mu[t.author_id] || {}).username !== 'IgorGanapolsky'
215
- );
216
-
217
- console.log('X mentions since last check: ' + newMentions.length);
218
-
219
- for (const t of newMentions.slice(0, 5)) {
220
- const u = mu[t.author_id] || {};
221
- const replyText = '@' + u.username + ' ThumbGate: PreToolUse enforcement for AI agents. Thompson Sampling adapts confidence. 68 tools on Smithery.\n\nhttps://github.com/IgorGanapolsky/ThumbGate';
222
- const r = await replyTweet(replyText, t.id);
223
- recordTweetReply(report, u.username, r);
224
- }
225
-
226
- state.lastMentionCheck = new Date().toISOString();
227
- } catch (e) {
228
- console.log('X mentions error: ' + e.message);
229
- }
230
-
231
- // ── 2. Post new tweet ──
232
- try {
233
- const angleIndex = Math.floor(Date.now() / 7200000) % TWEET_ANGLES.length;
234
- const r = await postTweet(TWEET_ANGLES[angleIndex]);
235
- recordTweetPost(report, r);
236
- } catch (e) {
237
- console.log('Tweet error: ' + e.message);
238
- }
239
- } else {
240
- console.log('X: skipped (no API keys)');
241
- }
242
-
243
- // ── 3. LinkedIn post ──
244
- if (LINKEDIN_ACCESS_TOKEN && LINKEDIN_PERSON_URN) {
245
- try {
246
- const lastLinkedin = state.lastLinkedinPost || '2026-04-01T00:00:00Z';
247
- const hoursSince = (Date.now() - new Date(lastLinkedin).getTime()) / 3600000;
248
- if (hoursSince >= 4) {
249
- const angles = [
250
- 'ThumbGate: pre-action gates for AI coding agents. 68 tools on Smithery. Works with Claude Code, Cursor, Codex, Gemini, Amp.\n\nnpx thumbgate quick-start\n\nhttps://github.com/IgorGanapolsky/ThumbGate',
251
- 'Every AI agent framework ships memory. None ship enforcement.\n\nThumbGate adds PreToolUse hooks that block bad actions before execution. Thompson Sampling adapts. Self-distillation auto-learns.\n\nhttps://github.com/IgorGanapolsky/ThumbGate',
252
- ];
253
- const r = await postLinkedIn(angles[Math.floor(Date.now() / 14400000) % angles.length]);
254
- console.log('LinkedIn posted: ' + (r.id || r.status));
255
- state.lastLinkedinPost = new Date().toISOString();
256
- report.linkedin++;
257
- } else {
258
- console.log('LinkedIn: skipped (' + Math.round(4 - hoursSince) + 'hr until next)');
259
- }
260
- } catch (e) {
261
- console.log('LinkedIn error: ' + e.message);
262
- }
263
- } else {
264
- console.log('LinkedIn: skipped (no token)');
265
- }
266
-
267
- // ── 4. GitHub issue monitoring ──
268
- if (GH_TOKEN) {
269
- const knownComments = state.issueComments || {};
270
-
271
- for (const { repo, num } of WATCHED_ISSUES) {
272
- try {
273
- const issue = await ghApi('/repos/' + repo + '/issues/' + num);
274
- const key = repo + '#' + num;
275
- const prev = knownComments[key] || 0;
276
-
277
- if (issue.comments > prev) {
278
- console.log(key + ': ' + (issue.comments - prev) + ' new comment(s)');
279
-
280
- // Read latest comment
281
- const comments = await ghApi('/repos/' + repo + '/issues/' + num + '/comments?per_page=1&page=' + issue.comments);
282
- const latest = comments[0];
283
- if (latest && latest.user.login !== 'IgorGanapolsky') {
284
- const reply = 'Thanks for the response! ThumbGate adds PreToolUse enforcement — gates that block known-bad actions before execution. Thompson Sampling adapts confidence. Self-distillation auto-generates rules from outcomes.\n\n68 tools on [Smithery](https://smithery.ai/servers/rlhf-loop/thumbgate). Would love to explore integration.\n\nhttps://github.com/IgorGanapolsky/ThumbGate';
285
- await ghPostComment(repo, num, reply);
286
- console.log(' Replied to @' + latest.user.login);
287
- report.ghIssues++;
288
- }
289
- } else {
290
- console.log(key + ': no new comments');
291
- }
292
-
293
- knownComments[key] = issue.comments;
294
- } catch (e) {
295
- console.log(repo + '#' + num + ' error: ' + e.message);
296
- }
297
- }
298
-
299
- // ── 5. Search for new repos ──
300
- try {
301
- const weekAgo = new Date(Date.now() - 7 * 86400000).toISOString().slice(0, 10);
302
- const search = await ghApi('/search/repositories?q=agent+safety+OR+pretooluse+OR+claude+code+hooks+OR+mcp+gate+pushed:>' + weekAgo + '&sort=stars&order=desc&per_page=5');
303
- const contacted = new Set(state.contactedRepos || []);
304
- let opened = 0;
305
-
306
- for (const repo of (search.items || [])) {
307
- if (opened >= 2) break;
308
- if (repo.stargazers_count < 3) continue;
309
- if (contacted.has(repo.full_name)) continue;
310
- if (repo.full_name.includes('IgorGanapolsky')) continue;
311
-
312
- const body = 'Hey — noticed you\'re building in the AI agent safety space. [ThumbGate](https://github.com/IgorGanapolsky/ThumbGate) adds PreToolUse hooks that block known-bad actions before execution, with Thompson Sampling for adaptive gate confidence and self-distillation for auto-learning from outcomes.\n\n68 tools on [Smithery](https://smithery.ai/servers/rlhf-loop/thumbgate). Could be complementary — would love to explore integration.\n\nMIT licensed, free tier available.';
313
-
314
- try {
315
- await fetch('https://api.github.com/repos/' + repo.full_name + '/issues', {
316
- method: 'POST',
317
- headers: {
318
- Authorization: 'token ' + GH_TOKEN,
319
- Accept: 'application/vnd.github+json',
320
- 'Content-Type': 'application/json',
321
- },
322
- body: JSON.stringify({
323
- title: 'Integration: ThumbGate enforcement layer for ' + repo.name,
324
- body: body,
325
- }),
326
- });
327
- console.log('Opened issue on ' + repo.full_name + ' (stars=' + repo.stargazers_count + ')');
328
- contacted.add(repo.full_name);
329
- opened++;
330
- report.ghOutreach++;
331
- } catch (e) {
332
- console.log('Issue creation failed on ' + repo.full_name + ': ' + e.message);
333
- }
334
- }
335
-
336
- state.contactedRepos = [...contacted];
337
- } catch (e) {
338
- console.log('Repo search error: ' + e.message);
339
- }
340
-
341
- // ── 6. ThumbGate stats ──
342
- try {
343
- const repo = await ghApi('/repos/IgorGanapolsky/ThumbGate');
344
- console.log('ThumbGate: stars=' + repo.stargazers_count + ' forks=' + repo.forks_count);
345
- } catch (e) {
346
- console.log('Stats error: ' + e.message);
347
- }
348
-
349
- // ── 7. awesome-mcp PR ──
350
- try {
351
- const pr = await ghApi('/repos/punkpeye/awesome-mcp-servers/pulls/4474');
352
- console.log('awesome-mcp#4474: state=' + pr.state + ' merged=' + pr.merged);
353
- } catch (e) {
354
- console.log('PR check error: ' + e.message);
355
- }
356
-
357
- state.issueComments = knownComments;
358
- } else {
359
- console.log('GitHub: skipped (no token)');
360
- }
361
-
362
- // ── 8. Perplexity visibility ──
363
- await checkPerplexityVisibility();
364
-
365
- // ── Save state ──
366
- state.lastRun = new Date().toISOString();
367
- saveState(state);
368
-
369
- // ── Report ──
370
- console.log('\n=== REPORT ===');
371
- console.log('Tweets: ' + report.tweets);
372
- console.log('Replies: ' + report.replies);
373
- console.log('LinkedIn: ' + report.linkedin);
374
- console.log('GitHub issues responded: ' + report.ghIssues);
375
- console.log('GitHub outreach opened: ' + report.ghOutreach);
376
- console.log('=== DONE ===');
377
- }
378
-
379
- function isDirectInvocation(mainModule = require.main) {
380
- return Boolean(mainModule && mainModule.filename === __filename);
381
- }
382
-
383
- if (isDirectInvocation()) {
384
- main().catch(e => {
385
- console.error('Ralph Mode CI fatal error:', e.message);
386
- process.exit(1);
387
- });
388
- }
389
-
390
- // ── Perplexity AI Search Visibility (appended) ──────────────────────────
391
- async function checkPerplexityVisibility() {
392
- const PPLX_KEY = (process.env.PERPLEXITY_API_KEY || '').trim();
393
- if (!PPLX_KEY) { console.log('Perplexity: skipped (no key)'); return; }
394
-
395
- const prompts = [
396
- 'best pre-action gate tools for AI coding agents',
397
- 'how to prevent AI coding agent from making mistakes',
398
- 'Claude Code safety tools',
399
- 'alternatives to thumbgate',
400
- ];
401
-
402
- console.log('Perplexity visibility check (' + prompts.length + ' queries):');
403
- let found = 0;
404
- for (const prompt of prompts) {
405
- try {
406
- const r = await fetch('https://api.perplexity.ai/chat/completions', {
407
- method: 'POST',
408
- headers: { Authorization: 'Bearer ' + PPLX_KEY, 'Content-Type': 'application/json' },
409
- body: JSON.stringify({ model: 'sonar', messages: [{ role: 'user', content: prompt }] }),
410
- });
411
- const j = await r.json();
412
- const text = j.choices?.[0]?.message?.content || '';
413
- const mentioned = /thumbgate/i.test(text);
414
- console.log(' "' + prompt.slice(0, 50) + '": ' + (mentioned ? 'FOUND' : 'MISSING'));
415
- if (mentioned) found++;
416
- } catch (e) {
417
- console.log(' "' + prompt.slice(0, 50) + '": ERROR ' + e.message.slice(0, 30));
418
- }
419
- }
420
- console.log('Perplexity: ThumbGate mentioned in ' + found + '/' + prompts.length + ' queries');
421
- }
422
-
423
- module.exports = {
424
- TWEET_ANGLES,
425
- extractApiError,
426
- main,
427
- parseJsonResponse,
428
- postTweet,
429
- isDirectInvocation,
430
- recordTweetPost,
431
- recordTweetReply,
432
- replyTweet,
433
- xAuthHeader,
434
- };
@@ -1,192 +0,0 @@
1
- #!/usr/bin/env node
2
- 'use strict';
3
-
4
- /**
5
- * reddit-dm-outreach.js
6
- * Send direct messages to engaged Reddit users via OAuth2 password grant flow.
7
- *
8
- * Usage:
9
- * node scripts/reddit-dm-outreach.js
10
- *
11
- * Requires env vars:
12
- * REDDIT_CLIENT_ID
13
- * REDDIT_CLIENT_SECRET
14
- * REDDIT_USERNAME
15
- * REDDIT_PASSWORD
16
- */
17
-
18
- const https = require('https');
19
- const fs = require('fs');
20
- const path = require('path');
21
-
22
- // Parse .env credentials line-by-line
23
- function parseEnv(filePath) {
24
- const content = fs.readFileSync(filePath, 'utf8');
25
- const result = {};
26
- const lines = content.split('\n');
27
-
28
- for (const line of lines) {
29
- const trimmed = line.trim();
30
- if (!trimmed || trimmed.startsWith('#')) continue;
31
-
32
- const eqIdx = trimmed.indexOf('=');
33
- if (eqIdx === -1) continue;
34
-
35
- const key = trimmed.substring(0, eqIdx).trim();
36
- const value = trimmed.substring(eqIdx + 1).trim();
37
- result[key] = value;
38
- }
39
-
40
- return result;
41
- }
42
-
43
- const envPath = path.join(__dirname, '..', '.env');
44
- const env = parseEnv(envPath);
45
-
46
- const REDDIT_CLIENT_ID = env.REDDIT_CLIENT_ID;
47
- const REDDIT_CLIENT_SECRET = env.REDDIT_CLIENT_SECRET;
48
- const REDDIT_USERNAME = env.REDDIT_USERNAME;
49
- const REDDIT_PASSWORD = env.REDDIT_PASSWORD;
50
-
51
- if (!REDDIT_CLIENT_ID || !REDDIT_CLIENT_SECRET || !REDDIT_USERNAME || !REDDIT_PASSWORD) {
52
- console.error('❌ Missing Reddit credentials in .env');
53
- process.exit(1);
54
- }
55
-
56
- console.log('📧 Reddit DM Outreach');
57
- console.log('---');
58
-
59
- // OAuth2 password grant flow
60
- function authenticate() {
61
- return new Promise((resolve, reject) => {
62
- const authHeader = 'Basic ' + Buffer.from(
63
- REDDIT_CLIENT_ID + ':' + REDDIT_CLIENT_SECRET
64
- ).toString('base64');
65
-
66
- const postData = [
67
- 'grant_type=password',
68
- `username=${encodeURIComponent(REDDIT_USERNAME)}`,
69
- `password=${encodeURIComponent(REDDIT_PASSWORD)}`,
70
- 'duration=permanent'
71
- ].join('&');
72
-
73
- const authOptions = {
74
- hostname: 'www.reddit.com',
75
- port: 443,
76
- path: '/api/v1/access_token',
77
- method: 'POST',
78
- headers: {
79
- 'Authorization': authHeader,
80
- 'Content-Type': 'application/x-www-form-urlencoded',
81
- 'User-Agent': 'ThumbGate-Testimonial/1.0',
82
- 'Content-Length': Buffer.byteLength(postData)
83
- }
84
- };
85
-
86
- const authReq = https.request(authOptions, (res) => {
87
- let data = '';
88
- res.on('data', chunk => { data += chunk; });
89
- res.on('end', () => {
90
- try {
91
- const parsed = JSON.parse(data);
92
- if (parsed.access_token) {
93
- console.log('✅ Authenticated as', REDDIT_USERNAME);
94
- resolve(parsed.access_token);
95
- } else {
96
- reject(new Error('Auth failed: ' + JSON.stringify(parsed)));
97
- }
98
- } catch (e) {
99
- reject(new Error('Parse error: ' + e.message));
100
- }
101
- });
102
- });
103
-
104
- authReq.on('error', reject);
105
- authReq.write(postData);
106
- authReq.end();
107
- });
108
- }
109
-
110
- // Send a single DM
111
- function sendDM(accessToken, to, subject, text) {
112
- return new Promise((resolve, reject) => {
113
- const dmData = JSON.stringify({ to, subject, text });
114
-
115
- const dmOptions = {
116
- hostname: 'oauth.reddit.com',
117
- port: 443,
118
- path: '/api/compose',
119
- method: 'POST',
120
- headers: {
121
- 'Authorization': 'Bearer ' + accessToken,
122
- 'Content-Type': 'application/json',
123
- 'User-Agent': 'ThumbGate-Testimonial/1.0',
124
- 'Content-Length': Buffer.byteLength(dmData)
125
- }
126
- };
127
-
128
- const dmReq = https.request(dmOptions, (res) => {
129
- let data = '';
130
- res.on('data', chunk => { data += chunk; });
131
- res.on('end', () => {
132
- if (res.statusCode === 200) {
133
- resolve();
134
- } else {
135
- reject(new Error(`HTTP ${res.statusCode}: ${data.substring(0, 200)}`));
136
- }
137
- });
138
- });
139
-
140
- dmReq.on('error', reject);
141
- dmReq.write(dmData);
142
- dmReq.end();
143
- });
144
- }
145
-
146
- // Main
147
- async function main() {
148
- try {
149
- const accessToken = await authenticate();
150
-
151
- const messages = [
152
- {
153
- to: 'game-of-kton',
154
- subject: 'Quick question about your agent workflow',
155
- text: 'Hey — you left some really thoughtful comments on the AI coding agent thread. I\'m building ThumbGate (agent mistake prevention via PreToolUse hooks) and your feedback was the most useful I got.\n\nI\'m trying to figure out if this is worth building further. Would you be open to a quick 15-min call this week? Just want to understand how you handle agent mistakes in your workflow.\n\nI\'ll give you lifetime Pro access regardless — no strings attached.\n\nHere\'s the repo if you want to look first: https://github.com/IgorGanapolsky/ThumbGate'
156
- },
157
- {
158
- to: 'Deep_Ad1959',
159
- subject: 'Your context-dependent blocking idea',
160
- text: 'Hey — your point about context-dependent blocking was really insightful. That\'s exactly the problem I\'m trying to solve with ThumbGate (using Thompson Sampling for adaptive gates instead of hard binary blocks).\n\nWould you be open to a quick 15-min call this week? I\'m trying to figure out what developers would actually pay for in this space. Your perspective would be genuinely valuable.\n\nLifetime Pro access is yours either way. Repo: https://github.com/IgorGanapolsky/ThumbGate'
161
- },
162
- {
163
- to: 'leogodin217',
164
- subject: 'Quick question about AI agent safety in your workflow',
165
- text: 'Hey — you engaged with one of my posts about AI coding agent tooling and your take stood out. I\'m building ThumbGate (prevents AI agents from repeating mistakes via automated prevention rules).\n\nI\'m at the stage where I need honest feedback from people who actually use agents daily. Would you do a quick 15-min call this week? Just want to understand your pain points.\n\nLifetime Pro access is yours regardless. Repo: https://github.com/IgorGanapolsky/ThumbGate'
166
- },
167
- {
168
- to: 'Enthu-Cutlet-1337',
169
- subject: 'Quick question about your AI coding agent setup',
170
- text: 'Hey — you commented on one of my posts about agent memory/safety tooling and your feedback was one of the few that was genuinely useful.\n\nI\'m building ThumbGate (automated mistake prevention for AI coding agents) and I\'m trying to figure out if this solves a real problem or if everyone just uses CLAUDE.md files. Would you be open to a quick 15-min call this week?\n\nLifetime Pro access is yours either way — no pitch, just questions. Repo: https://github.com/IgorGanapolsky/ThumbGate'
171
- }
172
- ];
173
-
174
- console.log(`\n📨 Sending ${messages.length} direct messages...\n`);
175
-
176
- for (const msg of messages) {
177
- try {
178
- await sendDM(accessToken, msg.to, msg.subject, msg.text);
179
- console.log(`✅ DM sent to u/${msg.to}`);
180
- } catch (err) {
181
- console.error(`❌ Failed to send DM to u/${msg.to}:`, err.message);
182
- }
183
- }
184
-
185
- console.log(`\n✅ Outreach complete (${messages.length}/${messages.length} sent)`);
186
- } catch (err) {
187
- console.error('❌ Error:', err.message);
188
- process.exit(1);
189
- }
190
- }
191
-
192
- main();
@@ -1,26 +0,0 @@
1
- #!/usr/bin/env bash
2
- set -euo pipefail
3
-
4
- REPO_DIR="/Users/igorganapolsky/workspace/git/igor/thumbgate"
5
- LOG_FILE="${REPO_DIR}/.thumbgate/reddit-monitor.log"
6
-
7
- mkdir -p "${REPO_DIR}/.thumbgate"
8
-
9
- # Load environment
10
- if [ -f "${REPO_DIR}/.env" ]; then
11
- while IFS='=' read -r key value; do
12
- # Skip comments and empty lines
13
- [[ -z "$key" || "$key" =~ ^# ]] && continue
14
- # Strip leading/trailing whitespace from key
15
- key=$(echo "$key" | xargs)
16
- # Export the variable (value preserved as-is)
17
- export "$key=$value"
18
- done < "${REPO_DIR}/.env"
19
- fi
20
-
21
- echo "[$(date -u +"%Y-%m-%dT%H:%M:%SZ")] Reddit monitor run starting" >> "$LOG_FILE"
22
-
23
- cd "$REPO_DIR"
24
- /opt/homebrew/bin/node scripts/social-reply-monitor.js >> "$LOG_FILE" 2>&1
25
-
26
- echo "[$(date -u +"%Y-%m-%dT%H:%M:%SZ")] Reddit monitor run complete" >> "$LOG_FILE"