thumbgate 0.9.10 → 0.9.11

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 (113) hide show
  1. package/.claude-plugin/README.md +2 -2
  2. package/.claude-plugin/marketplace.json +4 -2
  3. package/.claude-plugin/plugin.json +1 -1
  4. package/.well-known/mcp/server-card.json +1 -1
  5. package/README.md +115 -312
  6. package/adapters/README.md +1 -1
  7. package/adapters/claude/.mcp.json +2 -2
  8. package/adapters/codex/config.toml +4 -4
  9. package/adapters/mcp/server-stdio.js +61 -1
  10. package/adapters/opencode/opencode.json +4 -2
  11. package/bin/cli.js +156 -8
  12. package/bin/memory.sh +3 -3
  13. package/config/e2e-critical-flows.json +4 -0
  14. package/config/gates/default.json +74 -2
  15. package/config/github-about.json +1 -1
  16. package/config/mcp-allowlists.json +27 -0
  17. package/package.json +22 -5
  18. package/plugins/amp-skill/INSTALL.md +1 -0
  19. package/plugins/amp-skill/SKILL.md +1 -0
  20. package/plugins/claude-codex-bridge/.claude-plugin/plugin.json +1 -1
  21. package/plugins/claude-codex-bridge/.mcp.json +4 -2
  22. package/plugins/claude-skill/INSTALL.md +1 -0
  23. package/plugins/codex-profile/.codex-plugin/plugin.json +1 -1
  24. package/plugins/codex-profile/.mcp.json +4 -2
  25. package/plugins/codex-profile/INSTALL.md +1 -1
  26. package/plugins/codex-profile/README.md +1 -1
  27. package/plugins/cursor-marketplace/.cursor-plugin/plugin.json +1 -1
  28. package/plugins/cursor-marketplace/README.md +3 -3
  29. package/plugins/cursor-marketplace/mcp.json +3 -1
  30. package/plugins/cursor-marketplace/scripts/gate-check.sh +15 -5
  31. package/plugins/gemini-extension/INSTALL.md +3 -3
  32. package/plugins/opencode-profile/INSTALL.md +1 -1
  33. package/public/dashboard.html +15 -8
  34. package/public/index.html +125 -185
  35. package/public/js/buyer-intent.js +252 -0
  36. package/public/pro.html +1085 -0
  37. package/scripts/__pycache__/train_from_feedback.cpython-312.pyc +0 -0
  38. package/scripts/adk-consolidator.js +14 -2
  39. package/scripts/agent-readiness.js +3 -1
  40. package/scripts/agent-security-hardening.js +4 -4
  41. package/scripts/auto-promote-gates.js +2 -0
  42. package/scripts/auto-wire-hooks.js +105 -17
  43. package/scripts/behavioral-extraction.js +2 -6
  44. package/scripts/billing.js +107 -3
  45. package/scripts/budget-guard.js +2 -2
  46. package/scripts/build-metadata.js +14 -0
  47. package/scripts/context-engine.js +1 -0
  48. package/scripts/deploy-policy.js +3 -17
  49. package/scripts/dpo-optimizer.js +3 -6
  50. package/scripts/ensure-repo-bootstrap.js +129 -0
  51. package/scripts/export-dpo-pairs.js +2 -3
  52. package/scripts/export-kto-pairs.js +3 -4
  53. package/scripts/export-training.js +8 -6
  54. package/scripts/feedback-attribution.js +23 -11
  55. package/scripts/feedback-loop.js +40 -2
  56. package/scripts/feedback-to-rules.js +2 -1
  57. package/scripts/filesystem-search.js +3 -2
  58. package/scripts/gates-engine.js +760 -29
  59. package/scripts/generate-pretool-hook.sh +0 -0
  60. package/scripts/gtm-revenue-loop.js +20 -1
  61. package/scripts/hook-auto-capture.sh +8 -3
  62. package/scripts/hook-runtime.js +89 -0
  63. package/scripts/hook-stop-self-score.sh +3 -3
  64. package/scripts/hook-thumbgate-cache-updater.js +99 -38
  65. package/scripts/hosted-config.js +4 -16
  66. package/scripts/hybrid-feedback-context.js +54 -14
  67. package/scripts/install-mcp.js +13 -0
  68. package/scripts/intent-router.js +2 -2
  69. package/scripts/license.js +52 -14
  70. package/scripts/local-model-profile.js +3 -2
  71. package/scripts/mcp-config.js +68 -6
  72. package/scripts/meta-policy.js +4 -8
  73. package/scripts/money-watcher.js +166 -16
  74. package/scripts/obsidian-export.js +1 -0
  75. package/scripts/operational-integrity.js +480 -0
  76. package/scripts/post-everywhere.js +7 -12
  77. package/scripts/pr-manager.js +14 -11
  78. package/scripts/profile-router.js +2 -0
  79. package/scripts/prompt-dlp.js +1 -0
  80. package/scripts/publish-decision.js +10 -0
  81. package/scripts/published-cli.js +34 -0
  82. package/scripts/risk-scorer.js +3 -2
  83. package/scripts/rlhf_session_start.sh +32 -0
  84. package/scripts/skill-quality-tracker.js +3 -5
  85. package/scripts/social-analytics/db/social-analytics.db-shm +0 -0
  86. package/scripts/social-analytics/db/social-analytics.db-wal +0 -0
  87. package/scripts/social-analytics/engagement-audit.js +202 -0
  88. package/scripts/social-analytics/instagram-thumbgate-post.js +45 -7
  89. package/scripts/social-analytics/install-growth-automation.js +114 -0
  90. package/scripts/social-analytics/load-env.js +46 -0
  91. package/scripts/social-analytics/poll-all.js +3 -18
  92. package/scripts/social-analytics/pollers/zernio.js +3 -0
  93. package/scripts/social-analytics/publish-instagram-thumbgate.js +22 -3
  94. package/scripts/social-analytics/publish-thumbgate-launch.js +316 -0
  95. package/scripts/social-analytics/publishers/reddit.js +7 -12
  96. package/scripts/social-analytics/publishers/zernio.js +210 -22
  97. package/scripts/social-analytics/reconcile-thumbgate-campaign.js +165 -0
  98. package/scripts/social-analytics/schedule-thumbgate-campaign.js +275 -0
  99. package/scripts/social-analytics/sync-launch-assets.js +185 -0
  100. package/scripts/social-post-hourly.js +185 -0
  101. package/scripts/social-quality-gate.js +119 -3
  102. package/scripts/social-reply-monitor.js +148 -32
  103. package/scripts/statusline-cache-path.js +27 -0
  104. package/scripts/statusline-meta.js +22 -0
  105. package/scripts/statusline.sh +24 -32
  106. package/scripts/sync-version.js +11 -3
  107. package/scripts/test-coverage.js +20 -13
  108. package/scripts/tool-registry.js +97 -0
  109. package/scripts/train_from_feedback.py +32 -9
  110. package/scripts/validate-feedback.js +3 -2
  111. package/scripts/vector-store.js +2 -3
  112. package/scripts/verify-obsidian-setup.sh +3 -3
  113. package/src/api/server.js +281 -33
@@ -0,0 +1,252 @@
1
+ (function(global) {
2
+ var BUYER_EMAIL_STORAGE_KEY = 'thumbgateBuyerEmail';
3
+ var CHECKOUT_LINK_SELECTOR = 'a[href*="/checkout/pro"]';
4
+ var BUYER_EMAIL_SELECTOR = '[data-buyer-email]';
5
+
6
+ function normalizeBuyerEmail(value) {
7
+ return String(value || '').trim().toLowerCase();
8
+ }
9
+
10
+ function isValidBuyerEmail(value) {
11
+ return /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(normalizeBuyerEmail(value));
12
+ }
13
+
14
+ function getStorage() {
15
+ return global.localStorage && typeof global.localStorage.getItem === 'function'
16
+ ? global.localStorage
17
+ : null;
18
+ }
19
+
20
+ function getStoredBuyerEmail() {
21
+ var storage = getStorage();
22
+ if (!storage) {
23
+ return '';
24
+ }
25
+ try {
26
+ return normalizeBuyerEmail(storage.getItem(BUYER_EMAIL_STORAGE_KEY));
27
+ } catch (_error) {
28
+ return '';
29
+ }
30
+ }
31
+
32
+ function storeBuyerEmail(email) {
33
+ var storage = getStorage();
34
+ if (!storage) {
35
+ return false;
36
+ }
37
+ try {
38
+ storage.setItem(BUYER_EMAIL_STORAGE_KEY, normalizeBuyerEmail(email));
39
+ return true;
40
+ } catch (_error) {
41
+ return false;
42
+ }
43
+ }
44
+
45
+ function resolveCheckoutUrl(urlValue, email) {
46
+ var origin = global.location && global.location.origin
47
+ ? global.location.origin
48
+ : 'https://thumbgate.invalid';
49
+ var checkoutUrl = new URL(String(urlValue || '/checkout/pro'), origin);
50
+ if (checkoutUrl.origin !== origin || checkoutUrl.pathname !== '/checkout/pro') {
51
+ checkoutUrl = new URL('/checkout/pro', origin);
52
+ }
53
+ if (isValidBuyerEmail(email)) {
54
+ checkoutUrl.searchParams.set('customer_email', normalizeBuyerEmail(email));
55
+ } else {
56
+ checkoutUrl.searchParams.delete('customer_email');
57
+ }
58
+ return checkoutUrl;
59
+ }
60
+
61
+ function getCheckoutLinks(selector) {
62
+ if (!global.document || typeof global.document.querySelectorAll !== 'function') {
63
+ return [];
64
+ }
65
+ return Array.from(global.document.querySelectorAll(selector || CHECKOUT_LINK_SELECTOR));
66
+ }
67
+
68
+ function getBaseCheckoutHref(link) {
69
+ if (!link.dataset.baseHref) {
70
+ link.dataset.baseHref = link.getAttribute('href') || link.href || '/checkout/pro';
71
+ }
72
+ return link.dataset.baseHref;
73
+ }
74
+
75
+ function applyBuyerEmailToCheckoutLinks(email, selector) {
76
+ getCheckoutLinks(selector).forEach(function(link) {
77
+ link.href = resolveCheckoutUrl(getBaseCheckoutHref(link), email).toString();
78
+ });
79
+ }
80
+
81
+ function hydrateBuyerEmailInputs(email, selector) {
82
+ if (!global.document || typeof global.document.querySelectorAll !== 'function') {
83
+ return;
84
+ }
85
+ Array.from(global.document.querySelectorAll(selector || BUYER_EMAIL_SELECTOR)).forEach(function(input) {
86
+ if (!input.value) {
87
+ input.value = normalizeBuyerEmail(email);
88
+ }
89
+ });
90
+ }
91
+
92
+ function getNewsletterStatusElement(form) {
93
+ if (!form) {
94
+ return null;
95
+ }
96
+ return form.querySelector('[data-newsletter-status]')
97
+ || (form.parentElement ? form.parentElement.querySelector('[data-newsletter-status]') : null);
98
+ }
99
+
100
+ function setNewsletterStatus(form, message, ok) {
101
+ var statusEl = getNewsletterStatusElement(form);
102
+ if (!statusEl) {
103
+ return;
104
+ }
105
+ statusEl.textContent = message;
106
+ statusEl.style.color = ok ? 'var(--cyan)' : 'var(--red, #f87171)';
107
+ }
108
+
109
+ async function submitNewsletterSignup(email, form) {
110
+ var action = form && form.action ? form.action : '/api/newsletter';
111
+ var response = await fetch(action, {
112
+ method: 'POST',
113
+ headers: {
114
+ 'Content-Type': 'application/x-www-form-urlencoded',
115
+ Accept: 'application/json',
116
+ 'X-Requested-With': 'fetch',
117
+ },
118
+ body: new URLSearchParams({ email: normalizeBuyerEmail(email) }).toString(),
119
+ credentials: 'same-origin',
120
+ });
121
+ if (!response.ok) {
122
+ var errorMessage = 'Unable to save your email right now.';
123
+ try {
124
+ var errorBody = await response.json();
125
+ if (errorBody && errorBody.error) {
126
+ errorMessage = errorBody.error;
127
+ }
128
+ } catch (_error) {
129
+ // Keep the default error message when the response is not JSON.
130
+ }
131
+ throw new Error(errorMessage);
132
+ }
133
+ try {
134
+ return await response.json();
135
+ } catch (_error) {
136
+ return { accepted: true, duplicate: false };
137
+ }
138
+ }
139
+
140
+ function trackEvent(eventName, props) {
141
+ if (typeof global.plausible === 'function') {
142
+ global.plausible(eventName, { props: props || {} });
143
+ }
144
+ }
145
+
146
+ function getEmailFromInput(input) {
147
+ return normalizeBuyerEmail(input && input.value);
148
+ }
149
+
150
+ function initializeBuyerIntent(options) {
151
+ var settings = options || {};
152
+ var storedEmail = getStoredBuyerEmail();
153
+ if (storedEmail) {
154
+ hydrateBuyerEmailInputs(storedEmail, settings.emailSelector);
155
+ applyBuyerEmailToCheckoutLinks(storedEmail, settings.checkoutSelector);
156
+ }
157
+
158
+ if (!global.document || typeof global.document.querySelectorAll !== 'function') {
159
+ return;
160
+ }
161
+
162
+ Array.from(global.document.querySelectorAll(settings.formSelector || '[data-newsletter-form]')).forEach(function(form) {
163
+ form.addEventListener('submit', async function(event) {
164
+ event.preventDefault();
165
+ var input = form.querySelector(settings.formEmailSelector || 'input[name="email"]');
166
+ var email = getEmailFromInput(input);
167
+ if (!isValidBuyerEmail(email)) {
168
+ setNewsletterStatus(form, settings.invalidEmailMessage || 'Enter a valid work email.', false);
169
+ if (input) {
170
+ input.focus();
171
+ }
172
+ return;
173
+ }
174
+
175
+ storeBuyerEmail(email);
176
+ hydrateBuyerEmailInputs(email, settings.emailSelector);
177
+ applyBuyerEmailToCheckoutLinks(email, settings.checkoutSelector);
178
+
179
+ try {
180
+ var result = await submitNewsletterSignup(email, form);
181
+ var successMessage = result && result.duplicate
182
+ ? (settings.duplicateMessage || 'You are already on the list. Checkout on this device is now prefilled.')
183
+ : (settings.successMessage || 'Saved. We will keep checkout prefilled on this device.');
184
+ setNewsletterStatus(form, successMessage, true);
185
+ trackEvent('newsletter_signup', {
186
+ page: form.dataset.page || settings.page || 'homepage',
187
+ intent: form.dataset.intent || settings.intent || 'buyer_follow_up',
188
+ });
189
+ } catch (error) {
190
+ setNewsletterStatus(
191
+ form,
192
+ error && error.message ? error.message : 'Unable to save your email right now.',
193
+ false
194
+ );
195
+ }
196
+ });
197
+ });
198
+ }
199
+
200
+ function initializeEmailCheckoutButtons(options) {
201
+ var settings = options || {};
202
+ if (!global.document || typeof global.document.querySelectorAll !== 'function') {
203
+ return;
204
+ }
205
+
206
+ Array.from(global.document.querySelectorAll(settings.buttonSelector || '.btn-email-checkout')).forEach(function(button) {
207
+ button.addEventListener('click', async function() {
208
+ var form = button.closest('form');
209
+ var input = form ? form.querySelector(settings.formEmailSelector || 'input[name="email"]') : null;
210
+ var email = getEmailFromInput(input) || getStoredBuyerEmail();
211
+ if (!isValidBuyerEmail(email)) {
212
+ setNewsletterStatus(form, settings.invalidCheckoutMessage || 'Enter a valid work email before checkout.', false);
213
+ if (input) {
214
+ input.focus();
215
+ }
216
+ return;
217
+ }
218
+
219
+ storeBuyerEmail(email);
220
+ hydrateBuyerEmailInputs(email, settings.emailSelector);
221
+ applyBuyerEmailToCheckoutLinks(email, settings.checkoutSelector);
222
+ trackEvent(settings.eventName || 'pro_checkout_email_start', settings.eventProps || { page: 'pro', intent: 'checkout' });
223
+
224
+ try {
225
+ await submitNewsletterSignup(email, form);
226
+ } catch (_error) {
227
+ // Continue to checkout even if signup persistence fails.
228
+ }
229
+
230
+ var checkoutLink = global.document.querySelector(settings.checkoutLinkSelector || '.btn-pro-checkout');
231
+ if (checkoutLink) {
232
+ global.location.assign(checkoutLink.href);
233
+ }
234
+ });
235
+ });
236
+ }
237
+
238
+ global.ThumbGateBuyerIntent = {
239
+ normalizeBuyerEmail: normalizeBuyerEmail,
240
+ isValidBuyerEmail: isValidBuyerEmail,
241
+ getStoredBuyerEmail: getStoredBuyerEmail,
242
+ storeBuyerEmail: storeBuyerEmail,
243
+ resolveCheckoutUrl: resolveCheckoutUrl,
244
+ applyBuyerEmailToCheckoutLinks: applyBuyerEmailToCheckoutLinks,
245
+ hydrateBuyerEmailInputs: hydrateBuyerEmailInputs,
246
+ setNewsletterStatus: setNewsletterStatus,
247
+ submitNewsletterSignup: submitNewsletterSignup,
248
+ initializeBuyerIntent: initializeBuyerIntent,
249
+ initializeEmailCheckoutButtons: initializeEmailCheckoutButtons,
250
+ trackEvent: trackEvent,
251
+ };
252
+ })(globalThis);