thumbgate 1.4.1 → 1.4.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (60) hide show
  1. package/.claude-plugin/README.md +45 -34
  2. package/.claude-plugin/marketplace.json +3 -3
  3. package/.claude-plugin/plugin.json +3 -3
  4. package/.well-known/llms.txt +1 -1
  5. package/.well-known/mcp/server-card.json +1 -1
  6. package/README.md +26 -2
  7. package/adapters/README.md +4 -1
  8. package/adapters/chatgpt/INSTALL.md +39 -19
  9. package/adapters/claude/.mcp.json +2 -2
  10. package/adapters/codex/config.toml +2 -2
  11. package/adapters/mcp/server-stdio.js +10 -4
  12. package/adapters/opencode/opencode.json +1 -1
  13. package/adapters/perplexity/.mcp.json +36 -0
  14. package/adapters/perplexity/config.toml +16 -0
  15. package/adapters/perplexity/opencode.json +29 -0
  16. package/bin/cli.js +246 -90
  17. package/config/mcp-allowlists.json +11 -3
  18. package/package.json +28 -13
  19. package/plugins/claude-codex-bridge/.claude-plugin/plugin.json +1 -1
  20. package/plugins/claude-codex-bridge/.mcp.json +1 -1
  21. package/plugins/codex-profile/.codex-plugin/plugin.json +1 -1
  22. package/plugins/codex-profile/.mcp.json +1 -1
  23. package/plugins/codex-profile/INSTALL.md +1 -1
  24. package/plugins/codex-profile/README.md +1 -1
  25. package/plugins/cursor-marketplace/.cursor-plugin/plugin.json +1 -1
  26. package/plugins/opencode-profile/INSTALL.md +1 -1
  27. package/public/index.html +121 -24
  28. package/public/llm-context.md +17 -1
  29. package/scripts/ai-search-visibility.js +10 -36
  30. package/scripts/audit-trail.js +25 -15
  31. package/scripts/auto-wire-hooks.js +127 -0
  32. package/scripts/cli-demo.js +102 -0
  33. package/scripts/cli-schema.js +285 -0
  34. package/scripts/cli-status.js +166 -0
  35. package/scripts/cross-encoder-reranker.js +235 -0
  36. package/scripts/explore-subcommands.js +277 -0
  37. package/scripts/explore.js +569 -0
  38. package/scripts/feedback-loop.js +20 -6
  39. package/scripts/lesson-inference.js +27 -2
  40. package/scripts/lesson-reranker.js +263 -0
  41. package/scripts/lesson-retrieval.js +34 -17
  42. package/scripts/lesson-search.js +69 -0
  43. package/scripts/perplexity-client.js +210 -0
  44. package/scripts/perplexity-command-center.js +644 -0
  45. package/scripts/perplexity-marketing.js +17 -29
  46. package/scripts/prove-packaged-runtime.js +5 -4
  47. package/scripts/ralph-mode-ci.js +122 -19
  48. package/scripts/reflector-agent.js +2 -2
  49. package/scripts/session-analyzer.js +533 -0
  50. package/scripts/social-analytics/db/marketing-db.js +179 -0
  51. package/scripts/social-analytics/db/schema.sql +23 -0
  52. package/scripts/social-analytics/generate-instagram-card.js +31 -5
  53. package/scripts/social-analytics/generate-slides.js +268 -0
  54. package/scripts/social-analytics/post-video.js +316 -0
  55. package/scripts/social-analytics/publishers/zernio.js +52 -23
  56. package/scripts/statusline-local-stats.js +3 -1
  57. package/scripts/statusline.sh +15 -10
  58. package/scripts/thumbgate-bench.js +494 -0
  59. package/src/api/server.js +65 -1
  60. package/scripts/social-analytics/db/analytics.sqlite +0 -0
package/src/api/server.js CHANGED
@@ -5,6 +5,37 @@ const fs = require('fs');
5
5
  const path = require('path');
6
6
  const pkg = require('../../package.json');
7
7
 
8
+ const POSTHOG_API_PATHS = new Set(['/capture', '/batch', '/decide', '/e', '/engage']);
9
+ const POSTHOG_INGEST_HOST = 'us.i.posthog.com';
10
+ const POSTHOG_STATIC_PATH_PREFIX = '/static/';
11
+
12
+ function getPosthogProxyPath(pathname) {
13
+ return pathname.slice('/ingest'.length) || '/';
14
+ }
15
+
16
+ function isExactOrChildPath(pathname, basePath) {
17
+ return pathname === basePath || pathname.startsWith(`${basePath}/`);
18
+ }
19
+
20
+ function isAllowedPosthogProxyPath(pathname) {
21
+ if (pathname === '/') return true;
22
+ if (pathname.startsWith(POSTHOG_STATIC_PATH_PREFIX)) return true;
23
+ return Array.from(POSTHOG_API_PATHS).some((basePath) => isExactOrChildPath(pathname, basePath));
24
+ }
25
+
26
+ function buildPosthogProxyRequestOptions(req, posthogPath, search) {
27
+ return {
28
+ protocol: 'https:',
29
+ hostname: POSTHOG_INGEST_HOST,
30
+ path: `${posthogPath}${search || ''}`,
31
+ method: req.method,
32
+ headers: {
33
+ ...req.headers,
34
+ host: POSTHOG_INGEST_HOST,
35
+ },
36
+ };
37
+ }
38
+
8
39
  const {
9
40
  captureFeedback,
10
41
  analyzeFeedback,
@@ -2354,6 +2385,29 @@ function createApiServer() {
2354
2385
  const requestFeedbackDir = requestFeedbackPaths.FEEDBACK_DIR;
2355
2386
  const requestSafeDataDir = getSafeDataDir(req, parsed);
2356
2387
 
2388
+ // PostHog reverse proxy -- bypasses ad blockers.
2389
+ // Only allow known PostHog API paths to prevent SSRF (CodeQL js/request-forgery).
2390
+ if (pathname.startsWith('/ingest')) {
2391
+ const posthogPath = getPosthogProxyPath(pathname);
2392
+ if (!isAllowedPosthogProxyPath(posthogPath)) {
2393
+ res.writeHead(403, { 'Content-Type': 'text/plain' });
2394
+ res.end('Forbidden');
2395
+ return;
2396
+ }
2397
+ let body = '';
2398
+ req.on('data', chunk => { body += chunk; });
2399
+ req.on('end', () => {
2400
+ const proxyReq = https.request(buildPosthogProxyRequestOptions(req, posthogPath, parsed.search), (proxyRes) => {
2401
+ res.writeHead(proxyRes.statusCode, proxyRes.headers);
2402
+ proxyRes.pipe(res);
2403
+ });
2404
+ proxyReq.on('error', () => { res.writeHead(502); res.end(); });
2405
+ if (body) proxyReq.write(body);
2406
+ proxyReq.end();
2407
+ });
2408
+ return;
2409
+ }
2410
+
2357
2411
  // Public MCP endpoint — responds to Smithery registry scanning and MCP initialize
2358
2412
  // The initialize handshake is unauthenticated; subsequent tool calls require Bearer auth
2359
2413
  if (pathname === '/mcp') {
@@ -3770,7 +3824,14 @@ async function addContext(){
3770
3824
  return;
3771
3825
  }
3772
3826
 
3773
- if (!isAuthorized(req, expectedApiKey)) {
3827
+ // Operator key is allowed to bypass the general admin gate for its dedicated endpoint
3828
+ const _reqToken = extractApiKey(req);
3829
+ const isOperatorBillingRequest = Boolean(expectedOperatorKey)
3830
+ && _reqToken === expectedOperatorKey
3831
+ && req.method === 'GET'
3832
+ && pathname === '/v1/billing/summary';
3833
+
3834
+ if (!isOperatorBillingRequest && !isAuthorized(req, expectedApiKey)) {
3774
3835
  sendProblem(res, {
3775
3836
  type: PROBLEM_TYPES.UNAUTHORIZED,
3776
3837
  title: 'Unauthorized',
@@ -5014,6 +5075,9 @@ module.exports = {
5014
5075
  startServer,
5015
5076
  __test__: {
5016
5077
  buildCheckoutFallbackUrl,
5078
+ buildPosthogProxyRequestOptions,
5079
+ getPosthogProxyPath,
5080
+ isAllowedPosthogProxyPath,
5017
5081
  renderSitemapXml,
5018
5082
  },
5019
5083
  };
File without changes