thumbgate 1.4.2 → 1.4.4
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.
- package/.claude-plugin/README.md +45 -34
- package/.claude-plugin/marketplace.json +3 -3
- package/.claude-plugin/plugin.json +3 -3
- package/.well-known/llms.txt +1 -1
- package/.well-known/mcp/server-card.json +1 -1
- package/README.md +26 -2
- package/adapters/README.md +4 -1
- package/adapters/claude/.mcp.json +2 -2
- package/adapters/codex/config.toml +2 -2
- package/adapters/mcp/server-stdio.js +10 -4
- package/adapters/opencode/opencode.json +1 -1
- package/bin/cli.js +246 -90
- package/config/mcp-allowlists.json +11 -3
- package/package.json +184 -21
- package/scripts/audit-trail.js +25 -15
- package/scripts/auto-wire-hooks.js +127 -0
- package/scripts/cli-demo.js +102 -0
- package/scripts/cli-schema.js +285 -0
- package/scripts/cli-status.js +166 -0
- package/scripts/cross-encoder-reranker.js +235 -0
- package/scripts/explore-subcommands.js +277 -0
- package/scripts/explore.js +569 -0
- package/scripts/feedback-loop.js +20 -6
- package/scripts/lesson-inference.js +7 -1
- package/scripts/lesson-reranker.js +263 -0
- package/scripts/lesson-retrieval.js +34 -17
- package/scripts/lesson-search.js +69 -0
- package/scripts/perplexity-client.js +210 -0
- package/scripts/reflector-agent.js +2 -2
- package/scripts/statusline-local-stats.js +3 -1
- package/scripts/statusline.sh +12 -11
- package/src/api/server.js +178 -17
- package/src/index.js +3 -0
- package/.claude-plugin/bundle/icon.png +0 -0
- package/.claude-plugin/bundle/icon.svg +0 -18
- package/.claude-plugin/bundle/server/index.js +0 -24
- package/adapters/chatgpt/INSTALL.md +0 -138
- package/bin/memory.sh +0 -64
- package/bin/obsidian-sync.sh +0 -20
- package/plugins/amp-skill/INSTALL.md +0 -52
- package/plugins/amp-skill/SKILL.md +0 -64
- package/plugins/claude-codex-bridge/.claude-plugin/plugin.json +0 -22
- package/plugins/claude-codex-bridge/.mcp.json +0 -14
- package/plugins/claude-codex-bridge/INSTALL.md +0 -43
- package/plugins/claude-codex-bridge/README.md +0 -46
- package/plugins/claude-codex-bridge/scripts/codex-bridge.js +0 -286
- package/plugins/claude-codex-bridge/skills/adversarial-review/SKILL.md +0 -24
- package/plugins/claude-codex-bridge/skills/result/SKILL.md +0 -22
- package/plugins/claude-codex-bridge/skills/review/SKILL.md +0 -28
- package/plugins/claude-codex-bridge/skills/second-pass/SKILL.md +0 -27
- package/plugins/claude-codex-bridge/skills/setup/SKILL.md +0 -21
- package/plugins/claude-codex-bridge/skills/status/SKILL.md +0 -19
- package/plugins/claude-skill/INSTALL.md +0 -55
- package/plugins/claude-skill/SKILL.md +0 -46
- package/plugins/codex-profile/.codex-plugin/plugin.json +0 -43
- package/plugins/codex-profile/.mcp.json +0 -14
- package/plugins/codex-profile/AGENTS.md +0 -20
- package/plugins/codex-profile/INSTALL.md +0 -89
- package/plugins/codex-profile/README.md +0 -61
- package/plugins/cursor-marketplace/.cursor-plugin/plugin.json +0 -23
- package/plugins/cursor-marketplace/CHANGELOG.md +0 -30
- package/plugins/cursor-marketplace/LICENSE +0 -21
- package/plugins/cursor-marketplace/README.md +0 -124
- package/plugins/cursor-marketplace/agents/reliability-reviewer.md +0 -31
- package/plugins/cursor-marketplace/assets/logo-400x400.png +0 -0
- package/plugins/cursor-marketplace/commands/capture-feedback.md +0 -33
- package/plugins/cursor-marketplace/commands/check-gates.md +0 -25
- package/plugins/cursor-marketplace/commands/show-lessons.md +0 -27
- package/plugins/cursor-marketplace/hooks/hooks.json +0 -10
- package/plugins/cursor-marketplace/mcp.json +0 -14
- package/plugins/cursor-marketplace/rules/feedback-capture.mdc +0 -34
- package/plugins/cursor-marketplace/rules/pre-action-gates.mdc +0 -30
- package/plugins/cursor-marketplace/rules/session-continuity.mdc +0 -28
- package/plugins/cursor-marketplace/scripts/gate-check.sh +0 -21
- package/plugins/cursor-marketplace/skills/capture-feedback/SKILL.md +0 -48
- package/plugins/cursor-marketplace/skills/prevention-rules/SKILL.md +0 -31
- package/plugins/cursor-marketplace/skills/recall-context/SKILL.md +0 -30
- package/plugins/cursor-marketplace/skills/search-lessons/SKILL.md +0 -33
- package/plugins/gemini-extension/INSTALL.md +0 -92
- package/plugins/gemini-extension/gemini_prompt.txt +0 -14
- package/plugins/gemini-extension/tool_contract.json +0 -45
- package/plugins/opencode-profile/INSTALL.md +0 -57
- package/public/assets/instagram-card.png +0 -0
- package/public/assets/tiktok-agent-memory.mp4 +0 -0
- package/public/blog.html +0 -474
- package/public/compare/mem0.html +0 -189
- package/public/compare/speclock.html +0 -180
- package/public/compare.html +0 -310
- package/public/dashboard.html +0 -1100
- package/public/guide.html +0 -317
- package/public/guides/claude-code-prevent-repeated-mistakes.html +0 -161
- package/public/guides/codex-cli-guardrails.html +0 -158
- package/public/guides/cursor-prevent-repeated-mistakes.html +0 -161
- package/public/guides/pre-action-gates.html +0 -162
- package/public/guides/stop-repeated-ai-agent-mistakes.html +0 -159
- package/public/index.html +0 -1128
- package/public/js/buyer-intent.js +0 -252
- package/public/learn/agent-harness-pattern.html +0 -180
- package/public/learn/ai-agent-persistent-memory.html +0 -203
- package/public/learn/learn.css +0 -45
- package/public/learn/mcp-pre-action-gates-explained.html +0 -172
- package/public/learn/stop-ai-agent-force-push.html +0 -134
- package/public/learn/vibe-coding-safety-net.html +0 -142
- package/public/learn.html +0 -274
- package/public/lessons.html +0 -967
- package/public/llm-context.md +0 -140
- package/public/pro.html +0 -1087
- package/public/vercel.json +0 -8
- package/scripts/a2ui-engine.js +0 -73
- package/scripts/adk-consolidator.js +0 -274
- package/scripts/agent-security-hardening.js +0 -225
- package/scripts/ai-search-visibility.js +0 -142
- package/scripts/autonomous-sales-agent.js +0 -39
- package/scripts/autoresearch-runner.js +0 -216
- package/scripts/background-agent-governance.js +0 -229
- package/scripts/behavioral-extraction.js +0 -93
- package/scripts/budget-enforcer.js +0 -173
- package/scripts/budget-guard.js +0 -173
- package/scripts/build-claude-mcpb.js +0 -255
- package/scripts/build-codex-plugin.js +0 -152
- package/scripts/capture-railway-diagnostics.sh +0 -97
- package/scripts/changeset-check.js +0 -372
- package/scripts/check-congruence.js +0 -443
- package/scripts/computer-use-firewall.js +0 -280
- package/scripts/content-engine/linkedin-content-generator.js +0 -154
- package/scripts/content-engine/output/linkedin-memento-validation.md +0 -17
- package/scripts/content-engine/output/linkedin-posts-2026-04-09.md +0 -175
- package/scripts/content-engine/reddit-thread-finder.js +0 -154
- package/scripts/context-engine.js +0 -710
- package/scripts/daily-digest.js +0 -11
- package/scripts/data-governance.js +0 -173
- package/scripts/deploy-gcp.sh +0 -44
- package/scripts/deploy-policy.js +0 -249
- package/scripts/disagreement-mining.js +0 -315
- package/scripts/dpo-optimizer.js +0 -206
- package/scripts/ensure-repo-bootstrap.js +0 -130
- package/scripts/ephemeral-agent-store.js +0 -212
- package/scripts/eval-harness.js +0 -56
- package/scripts/export-kto-pairs.js +0 -309
- package/scripts/export-training.js +0 -446
- package/scripts/feedback-fallback.js +0 -111
- package/scripts/feedback-inbox-read.js +0 -162
- package/scripts/feedback-root-consolidator.js +0 -233
- package/scripts/feedback-to-memory.js +0 -185
- package/scripts/gate-satisfy.js +0 -42
- package/scripts/generate-paperbanana-diagrams.sh +0 -99
- package/scripts/generate-pretool-hook.sh +0 -40
- package/scripts/github-about.js +0 -430
- package/scripts/github-outreach.js +0 -65
- package/scripts/gtm-revenue-loop.js +0 -535
- package/scripts/hallucination-detector.js +0 -226
- package/scripts/hf-papers.js +0 -317
- package/scripts/hook-auto-capture.sh +0 -100
- package/scripts/hook-stop-pr-thread-check.sh +0 -68
- package/scripts/hook-stop-self-score.sh +0 -51
- package/scripts/hook-stop-verify-deploy.sh +0 -31
- package/scripts/hook-verify-before-done.sh +0 -20
- package/scripts/managed-dpo-export.js +0 -91
- package/scripts/markdown-escape.js +0 -12
- package/scripts/marketing-experiment.js +0 -657
- package/scripts/memalign-recall.js +0 -111
- package/scripts/memory-migration.js +0 -296
- package/scripts/meta-policy.js +0 -190
- package/scripts/metered-billing.js +0 -16
- package/scripts/model-tier-router.js +0 -310
- package/scripts/money-watcher.js +0 -218
- package/scripts/multi-hop-recall.js +0 -240
- package/scripts/per-step-scoring.js +0 -163
- package/scripts/perplexity-marketing.js +0 -466
- package/scripts/pii-scanner.js +0 -153
- package/scripts/plan-gate.js +0 -154
- package/scripts/post-everywhere.js +0 -341
- package/scripts/post-to-x-retry.sh +0 -22
- package/scripts/post-to-x.js +0 -369
- package/scripts/pr-manager.js +0 -421
- package/scripts/principle-extractor.js +0 -162
- package/scripts/pro-features.js +0 -41
- package/scripts/prompt-dlp.js +0 -222
- package/scripts/prove-adapters.js +0 -860
- package/scripts/prove-attribution.js +0 -361
- package/scripts/prove-automation.js +0 -651
- package/scripts/prove-autoresearch.js +0 -304
- package/scripts/prove-claim-verification.js +0 -277
- package/scripts/prove-cloudflare-sandbox.js +0 -161
- package/scripts/prove-data-pipeline.js +0 -408
- package/scripts/prove-data-quality.js +0 -227
- package/scripts/prove-evolution.js +0 -352
- package/scripts/prove-harnesses.js +0 -287
- package/scripts/prove-intelligence.js +0 -257
- package/scripts/prove-lancedb.js +0 -425
- package/scripts/prove-local-intelligence.js +0 -340
- package/scripts/prove-loop-closure.js +0 -263
- package/scripts/prove-packaged-runtime.js +0 -326
- package/scripts/prove-predictive-insights.js +0 -355
- package/scripts/prove-runtime.js +0 -363
- package/scripts/prove-seo-gsd.js +0 -234
- package/scripts/prove-settings.js +0 -279
- package/scripts/prove-subway-upgrades.js +0 -277
- package/scripts/prove-tessl.js +0 -229
- package/scripts/prove-training-export.js +0 -325
- package/scripts/prove-workflow-contract.js +0 -112
- package/scripts/prove-xmemory.js +0 -332
- package/scripts/publish-decision.js +0 -159
- package/scripts/ralph-loop.js +0 -376
- package/scripts/ralph-mode-ci.js +0 -331
- package/scripts/reddit-dm-outreach.js +0 -192
- package/scripts/reddit-monitor-cron.sh +0 -26
- package/scripts/reminder-engine.js +0 -132
- package/scripts/revenue-status.js +0 -472
- package/scripts/rotate-stripe-webhook-secret.js +0 -314
- package/scripts/schedule-manager.js +0 -249
- package/scripts/self-healing-check.js +0 -193
- package/scripts/shieldcortex-memory-firewall-runner.mjs +0 -53
- package/scripts/skill-exporter.js +0 -260
- package/scripts/skill-materializer.js +0 -134
- package/scripts/skill-packs.js +0 -136
- package/scripts/skill-proposer.js +0 -99
- package/scripts/skill-quality-tracker.js +0 -282
- package/scripts/slow-loop.js +0 -72
- package/scripts/social-analytics/db/analytics.sqlite +0 -0
- package/scripts/social-analytics/db/schema.sql +0 -32
- package/scripts/social-analytics/digest.js +0 -256
- package/scripts/social-analytics/engagement-audit.js +0 -185
- package/scripts/social-analytics/generate-instagram-card.js +0 -97
- package/scripts/social-analytics/instagram-thumbgate-post.js +0 -111
- package/scripts/social-analytics/install-growth-automation.js +0 -114
- package/scripts/social-analytics/load-env.js +0 -77
- package/scripts/social-analytics/mcp-server.js +0 -289
- package/scripts/social-analytics/normalizer.js +0 -580
- package/scripts/social-analytics/notify.js +0 -162
- package/scripts/social-analytics/poll-all.js +0 -107
- package/scripts/social-analytics/pollers/github.js +0 -195
- package/scripts/social-analytics/pollers/instagram.js +0 -253
- package/scripts/social-analytics/pollers/linkedin.js +0 -340
- package/scripts/social-analytics/pollers/plausible.js +0 -245
- package/scripts/social-analytics/pollers/reddit.js +0 -306
- package/scripts/social-analytics/pollers/threads.js +0 -233
- package/scripts/social-analytics/pollers/tiktok.js +0 -203
- package/scripts/social-analytics/pollers/x.js +0 -227
- package/scripts/social-analytics/pollers/youtube.js +0 -304
- package/scripts/social-analytics/pollers/zernio.js +0 -183
- package/scripts/social-analytics/publish-instagram-thumbgate.js +0 -104
- package/scripts/social-analytics/publish-thumbgate-launch.js +0 -322
- package/scripts/social-analytics/publishers/devto.js +0 -122
- package/scripts/social-analytics/publishers/instagram.js +0 -317
- package/scripts/social-analytics/publishers/linkedin.js +0 -294
- package/scripts/social-analytics/publishers/reddit.js +0 -385
- package/scripts/social-analytics/publishers/threads.js +0 -275
- package/scripts/social-analytics/publishers/tiktok.js +0 -217
- package/scripts/social-analytics/publishers/x.js +0 -259
- package/scripts/social-analytics/publishers/youtube.js +0 -223
- package/scripts/social-analytics/publishers/zernio.js +0 -539
- package/scripts/social-analytics/reconcile-thumbgate-campaign.js +0 -165
- package/scripts/social-analytics/run-digest.js +0 -34
- package/scripts/social-analytics/schedule-thumbgate-campaign.js +0 -275
- package/scripts/social-analytics/store.js +0 -455
- package/scripts/social-analytics/sync-launch-assets.js +0 -185
- package/scripts/social-analytics/utm.js +0 -143
- package/scripts/social-pipeline.js +0 -2626
- package/scripts/social-post-hourly.js +0 -228
- package/scripts/social-quality-gate.js +0 -134
- package/scripts/social-reply-monitor.js +0 -592
- package/scripts/status-dashboard.js +0 -155
- package/scripts/stripe-live-status.js +0 -115
- package/scripts/subagent-profiles.js +0 -79
- package/scripts/sync-branch-protection.js +0 -340
- package/scripts/sync-gh-secrets-from-env.sh +0 -70
- package/scripts/sync-github-about.js +0 -55
- package/scripts/sync-version.js +0 -479
- package/scripts/synthetic-dpo.js +0 -234
- package/scripts/tessl-export.js +0 -369
- package/scripts/test-coverage.js +0 -128
- package/scripts/thumbgate_session_start.sh +0 -32
- package/scripts/train_from_feedback.py +0 -929
- package/scripts/validate-feedback.js +0 -581
- package/scripts/verify-obsidian-setup.sh +0 -269
- package/scripts/verify-run.js +0 -269
- package/scripts/weekly-auto-post.js +0 -124
- package/scripts/x-autonomous-marketing.js +0 -139
|
@@ -1,114 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
'use strict';
|
|
3
|
-
|
|
4
|
-
const path = require('node:path');
|
|
5
|
-
const scheduleManager = require('../schedule-manager');
|
|
6
|
-
|
|
7
|
-
const REPO_ROOT = path.resolve(__dirname, '..', '..');
|
|
8
|
-
const GROWTH_REPORT_DIR = path.join(REPO_ROOT, '.thumbgate', 'reports', 'gtm-revenue-loop');
|
|
9
|
-
|
|
10
|
-
function buildNodeEvalCommand(scriptPath, args = []) {
|
|
11
|
-
const absolutePath = path.resolve(scriptPath);
|
|
12
|
-
const serializedArgs = JSON.stringify(args);
|
|
13
|
-
return [
|
|
14
|
-
'const { spawnSync } = require(\'node:child_process\');',
|
|
15
|
-
`process.chdir(${JSON.stringify(REPO_ROOT)});`,
|
|
16
|
-
`const result = spawnSync(process.execPath, [${JSON.stringify(absolutePath)}, ...${serializedArgs}], {`,
|
|
17
|
-
' cwd: process.cwd(),',
|
|
18
|
-
' env: process.env,',
|
|
19
|
-
' stdio: \'inherit\',',
|
|
20
|
-
'});',
|
|
21
|
-
'if (result.error) throw result.error;',
|
|
22
|
-
'process.exit(typeof result.status === \'number\' ? result.status : 0);',
|
|
23
|
-
].join(' ');
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
function buildGrowthSchedules() {
|
|
27
|
-
return [
|
|
28
|
-
{
|
|
29
|
-
id: 'thumbgate-growth-schedule-campaign',
|
|
30
|
-
name: 'ThumbGate Growth Campaign Scheduler',
|
|
31
|
-
description: 'Schedules the next day of tracked Zernio launch posts.',
|
|
32
|
-
schedule: 'daily 21:15',
|
|
33
|
-
command: buildNodeEvalCommand(path.join(__dirname, 'schedule-thumbgate-campaign.js')),
|
|
34
|
-
workingDirectory: REPO_ROOT,
|
|
35
|
-
},
|
|
36
|
-
{
|
|
37
|
-
id: 'thumbgate-growth-poll-zernio',
|
|
38
|
-
name: 'ThumbGate Growth Poll Zernio',
|
|
39
|
-
description: 'Polls Zernio analytics into the local engagement store every hour.',
|
|
40
|
-
schedule: 'hourly',
|
|
41
|
-
command: buildNodeEvalCommand(path.join(__dirname, 'pollers', 'zernio.js')),
|
|
42
|
-
workingDirectory: REPO_ROOT,
|
|
43
|
-
},
|
|
44
|
-
{
|
|
45
|
-
id: 'thumbgate-growth-sync-launch-assets',
|
|
46
|
-
name: 'ThumbGate Growth Sync Launch Assets',
|
|
47
|
-
description: 'Syncs published and scheduled launch assets from Zernio into a durable local registry.',
|
|
48
|
-
schedule: 'hourly',
|
|
49
|
-
command: buildNodeEvalCommand(path.join(__dirname, 'sync-launch-assets.js')),
|
|
50
|
-
workingDirectory: REPO_ROOT,
|
|
51
|
-
},
|
|
52
|
-
{
|
|
53
|
-
id: 'thumbgate-growth-reply-monitor',
|
|
54
|
-
name: 'ThumbGate Growth Reply Monitor',
|
|
55
|
-
description: 'Checks social replies and posts supported follow-ups or drafts them for review.',
|
|
56
|
-
schedule: 'hourly',
|
|
57
|
-
command: buildNodeEvalCommand(path.join(REPO_ROOT, 'scripts', 'social-reply-monitor.js')),
|
|
58
|
-
workingDirectory: REPO_ROOT,
|
|
59
|
-
},
|
|
60
|
-
{
|
|
61
|
-
id: 'thumbgate-growth-money-watch',
|
|
62
|
-
name: 'ThumbGate Growth Money Watch',
|
|
63
|
-
description: 'Persists hourly commercial-change checks so the first paid event is captured immediately.',
|
|
64
|
-
schedule: 'hourly',
|
|
65
|
-
command: buildNodeEvalCommand(path.join(REPO_ROOT, 'scripts', 'money-watcher.js'), [
|
|
66
|
-
'--once',
|
|
67
|
-
]),
|
|
68
|
-
workingDirectory: REPO_ROOT,
|
|
69
|
-
},
|
|
70
|
-
{
|
|
71
|
-
id: 'thumbgate-growth-revenue-loop',
|
|
72
|
-
name: 'ThumbGate Growth Revenue Loop',
|
|
73
|
-
description: 'Refreshes the local-first target queue and outreach artifact for the first paid customers.',
|
|
74
|
-
schedule: 'daily 08:20',
|
|
75
|
-
command: buildNodeEvalCommand(path.join(REPO_ROOT, 'scripts', 'autonomous-sales-agent.js'), [
|
|
76
|
-
`--report-dir=${GROWTH_REPORT_DIR}`,
|
|
77
|
-
'--max-targets=8',
|
|
78
|
-
]),
|
|
79
|
-
workingDirectory: REPO_ROOT,
|
|
80
|
-
},
|
|
81
|
-
{
|
|
82
|
-
id: 'thumbgate-growth-social-digest',
|
|
83
|
-
name: 'ThumbGate Growth Social Digest',
|
|
84
|
-
description: 'Builds the daily social analytics digest after the day closes.',
|
|
85
|
-
schedule: 'daily 22:15',
|
|
86
|
-
command: buildNodeEvalCommand(path.join(__dirname, 'run-digest.js'), ['--days=7']),
|
|
87
|
-
workingDirectory: REPO_ROOT,
|
|
88
|
-
},
|
|
89
|
-
];
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
function installGrowthAutomation(manager = scheduleManager) {
|
|
93
|
-
const schedules = buildGrowthSchedules();
|
|
94
|
-
|
|
95
|
-
const installed = schedules.map((schedule) => manager.createSchedule(schedule));
|
|
96
|
-
return {
|
|
97
|
-
installed,
|
|
98
|
-
schedules: manager.listSchedules().filter((schedule) => schedule.id.startsWith('thumbgate-growth-')),
|
|
99
|
-
};
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
if (require.main === module) {
|
|
103
|
-
const result = installGrowthAutomation();
|
|
104
|
-
process.stdout.write(`${JSON.stringify(result, null, 2)}\n`);
|
|
105
|
-
if (result.installed.some((entry) => !entry.success)) {
|
|
106
|
-
process.exitCode = 1;
|
|
107
|
-
}
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
module.exports = {
|
|
111
|
-
buildNodeEvalCommand,
|
|
112
|
-
buildGrowthSchedules,
|
|
113
|
-
installGrowthAutomation,
|
|
114
|
-
};
|
|
@@ -1,77 +0,0 @@
|
|
|
1
|
-
'use strict';
|
|
2
|
-
|
|
3
|
-
const fs = require('node:fs');
|
|
4
|
-
const path = require('node:path');
|
|
5
|
-
let dotenv = null;
|
|
6
|
-
try {
|
|
7
|
-
dotenv = require('dotenv');
|
|
8
|
-
} catch (_) {
|
|
9
|
-
dotenv = null;
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
const DEFAULT_ENV_PATH = path.resolve(__dirname, '..', '..', '.env');
|
|
13
|
-
|
|
14
|
-
function resolveEnvPath(envPath = DEFAULT_ENV_PATH) {
|
|
15
|
-
return path.isAbsolute(envPath) ? envPath : path.resolve(process.cwd(), envPath);
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
function loadLocalEnv(options = {}) {
|
|
19
|
-
const resolvedPath = resolveEnvPath(options.envPath);
|
|
20
|
-
if (!fs.existsSync(resolvedPath)) {
|
|
21
|
-
return {
|
|
22
|
-
exists: false,
|
|
23
|
-
loadedKeys: [],
|
|
24
|
-
path: resolvedPath,
|
|
25
|
-
};
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
const source = fs.readFileSync(resolvedPath, 'utf8');
|
|
29
|
-
const parsed = dotenv ? dotenv.parse(source) : parseEnvFallback(source);
|
|
30
|
-
const loadedKeys = [];
|
|
31
|
-
const override = options.override === true;
|
|
32
|
-
|
|
33
|
-
for (const [key, value] of Object.entries(parsed)) {
|
|
34
|
-
if (!override && process.env[key] !== undefined) {
|
|
35
|
-
continue;
|
|
36
|
-
}
|
|
37
|
-
process.env[key] = value;
|
|
38
|
-
loadedKeys.push(key);
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
return {
|
|
42
|
-
exists: true,
|
|
43
|
-
loadedKeys,
|
|
44
|
-
path: resolvedPath,
|
|
45
|
-
};
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
function parseEnvFallback(source) {
|
|
49
|
-
const parsed = {};
|
|
50
|
-
for (const rawLine of String(source).split(/\r?\n/)) {
|
|
51
|
-
const line = rawLine.trim();
|
|
52
|
-
if (!line || line.startsWith('#')) {
|
|
53
|
-
continue;
|
|
54
|
-
}
|
|
55
|
-
const separatorIndex = line.indexOf('=');
|
|
56
|
-
if (separatorIndex <= 0) {
|
|
57
|
-
continue;
|
|
58
|
-
}
|
|
59
|
-
const key = line.slice(0, separatorIndex).trim();
|
|
60
|
-
let value = line.slice(separatorIndex + 1).trim();
|
|
61
|
-
if (
|
|
62
|
-
(value.startsWith('"') && value.endsWith('"')) ||
|
|
63
|
-
(value.startsWith("'") && value.endsWith("'"))
|
|
64
|
-
) {
|
|
65
|
-
value = value.slice(1, -1);
|
|
66
|
-
}
|
|
67
|
-
parsed[key] = value;
|
|
68
|
-
}
|
|
69
|
-
return parsed;
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
module.exports = {
|
|
73
|
-
DEFAULT_ENV_PATH,
|
|
74
|
-
loadLocalEnv,
|
|
75
|
-
parseEnvFallback,
|
|
76
|
-
resolveEnvPath,
|
|
77
|
-
};
|
|
@@ -1,289 +0,0 @@
|
|
|
1
|
-
'use strict';
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* MCP stdio server for social analytics.
|
|
5
|
-
*
|
|
6
|
-
* Exposes social metrics from SQLite as queryable tools for Claude.
|
|
7
|
-
* Uses a simple JSON-RPC 2.0 over stdio pattern — no external MCP SDK required.
|
|
8
|
-
*
|
|
9
|
-
* Protocol:
|
|
10
|
-
* - Reads newline-delimited JSON-RPC 2.0 requests from stdin.
|
|
11
|
-
* - Writes newline-delimited JSON-RPC 2.0 responses to stdout.
|
|
12
|
-
* - Supported methods: tools/list, tools/call
|
|
13
|
-
*/
|
|
14
|
-
|
|
15
|
-
const readline = require('readline');
|
|
16
|
-
|
|
17
|
-
const { initDb, queryMetrics, topContent, getFollowerHistory } = require('./store');
|
|
18
|
-
const { generateDigest } = require('./digest');
|
|
19
|
-
|
|
20
|
-
const VALID_PLATFORMS = ['instagram', 'tiktok', 'github', 'all'];
|
|
21
|
-
|
|
22
|
-
// Tool definitions exposed to Claude.
|
|
23
|
-
const TOOLS = [
|
|
24
|
-
{
|
|
25
|
-
name: 'query_social_metrics',
|
|
26
|
-
description:
|
|
27
|
-
'Returns aggregated engagement metrics from the social analytics database for the given platform and time window.',
|
|
28
|
-
inputSchema: {
|
|
29
|
-
type: 'object',
|
|
30
|
-
properties: {
|
|
31
|
-
platform: {
|
|
32
|
-
type: 'string',
|
|
33
|
-
enum: VALID_PLATFORMS,
|
|
34
|
-
description: 'Platform to query. Use "all" for all platforms combined.',
|
|
35
|
-
},
|
|
36
|
-
days: {
|
|
37
|
-
type: 'number',
|
|
38
|
-
description: 'Number of past days to include in the query.',
|
|
39
|
-
default: 7,
|
|
40
|
-
},
|
|
41
|
-
},
|
|
42
|
-
required: ['platform'],
|
|
43
|
-
},
|
|
44
|
-
},
|
|
45
|
-
{
|
|
46
|
-
name: 'top_social_content',
|
|
47
|
-
description:
|
|
48
|
-
'Returns top content items ranked by total engagement (likes + comments + shares + saves) over the past N days.',
|
|
49
|
-
inputSchema: {
|
|
50
|
-
type: 'object',
|
|
51
|
-
properties: {
|
|
52
|
-
days: {
|
|
53
|
-
type: 'number',
|
|
54
|
-
description: 'Number of past days to consider.',
|
|
55
|
-
default: 7,
|
|
56
|
-
},
|
|
57
|
-
limit: {
|
|
58
|
-
type: 'number',
|
|
59
|
-
description: 'Maximum number of results to return.',
|
|
60
|
-
default: 10,
|
|
61
|
-
},
|
|
62
|
-
},
|
|
63
|
-
required: [],
|
|
64
|
-
},
|
|
65
|
-
},
|
|
66
|
-
{
|
|
67
|
-
name: 'follower_growth',
|
|
68
|
-
description: 'Returns follower count snapshots for a platform over the past N days.',
|
|
69
|
-
inputSchema: {
|
|
70
|
-
type: 'object',
|
|
71
|
-
properties: {
|
|
72
|
-
platform: {
|
|
73
|
-
type: 'string',
|
|
74
|
-
enum: ['instagram', 'tiktok', 'github'],
|
|
75
|
-
description: 'Platform to query follower history for.',
|
|
76
|
-
},
|
|
77
|
-
days: {
|
|
78
|
-
type: 'number',
|
|
79
|
-
description: 'Number of past days to include.',
|
|
80
|
-
default: 7,
|
|
81
|
-
},
|
|
82
|
-
},
|
|
83
|
-
required: ['platform'],
|
|
84
|
-
},
|
|
85
|
-
},
|
|
86
|
-
{
|
|
87
|
-
name: 'social_digest',
|
|
88
|
-
description:
|
|
89
|
-
'Returns a full digest object summarising all social metrics, follower deltas, and top content for the past N days.',
|
|
90
|
-
inputSchema: {
|
|
91
|
-
type: 'object',
|
|
92
|
-
properties: {
|
|
93
|
-
days: {
|
|
94
|
-
type: 'number',
|
|
95
|
-
description: 'Number of past days to summarise.',
|
|
96
|
-
default: 7,
|
|
97
|
-
},
|
|
98
|
-
},
|
|
99
|
-
required: [],
|
|
100
|
-
},
|
|
101
|
-
},
|
|
102
|
-
];
|
|
103
|
-
|
|
104
|
-
/**
|
|
105
|
-
* Validates that a value is a positive integer (or coerces a numeric string).
|
|
106
|
-
*
|
|
107
|
-
* @param {*} value
|
|
108
|
-
* @param {number} defaultVal
|
|
109
|
-
* @returns {number}
|
|
110
|
-
*/
|
|
111
|
-
function asPositiveInt(value, defaultVal) {
|
|
112
|
-
const n = value == null ? defaultVal : Number(value);
|
|
113
|
-
if (!Number.isFinite(n) || n <= 0) {
|
|
114
|
-
throw new Error(`Expected a positive number, got: ${value}`);
|
|
115
|
-
}
|
|
116
|
-
return Math.floor(n);
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
/**
|
|
120
|
-
* Dispatches a tools/call request and returns the result payload.
|
|
121
|
-
*
|
|
122
|
-
* @param {import('better-sqlite3').Database} db
|
|
123
|
-
* @param {string} toolName
|
|
124
|
-
* @param {object} toolArgs
|
|
125
|
-
* @returns {object}
|
|
126
|
-
*/
|
|
127
|
-
function callTool(db, toolName, toolArgs) {
|
|
128
|
-
const args = toolArgs || {};
|
|
129
|
-
|
|
130
|
-
switch (toolName) {
|
|
131
|
-
case 'query_social_metrics': {
|
|
132
|
-
const platform = args.platform;
|
|
133
|
-
if (!VALID_PLATFORMS.includes(platform)) {
|
|
134
|
-
throw new Error(`Invalid platform "${platform}". Must be one of: ${VALID_PLATFORMS.join(', ')}`);
|
|
135
|
-
}
|
|
136
|
-
const days = asPositiveInt(args.days, 7);
|
|
137
|
-
const opts = platform === 'all' ? { days } : { platform, days };
|
|
138
|
-
const rows = queryMetrics(db, opts);
|
|
139
|
-
return { rows };
|
|
140
|
-
}
|
|
141
|
-
|
|
142
|
-
case 'top_social_content': {
|
|
143
|
-
const days = asPositiveInt(args.days, 7);
|
|
144
|
-
const limit = asPositiveInt(args.limit, 10);
|
|
145
|
-
const rows = topContent(db, { days, limit });
|
|
146
|
-
return { rows };
|
|
147
|
-
}
|
|
148
|
-
|
|
149
|
-
case 'follower_growth': {
|
|
150
|
-
const platform = args.platform;
|
|
151
|
-
if (!platform || !['instagram', 'tiktok', 'github'].includes(platform)) {
|
|
152
|
-
throw new Error(`Invalid platform "${platform}". Must be one of: instagram, tiktok, github`);
|
|
153
|
-
}
|
|
154
|
-
const days = asPositiveInt(args.days, 7);
|
|
155
|
-
const rows = getFollowerHistory(db, { platform, days });
|
|
156
|
-
return { rows };
|
|
157
|
-
}
|
|
158
|
-
|
|
159
|
-
case 'social_digest': {
|
|
160
|
-
const days = asPositiveInt(args.days, 7);
|
|
161
|
-
const digest = generateDigest(db, { days });
|
|
162
|
-
return digest;
|
|
163
|
-
}
|
|
164
|
-
|
|
165
|
-
default:
|
|
166
|
-
throw new Error(`Unknown tool: ${toolName}`);
|
|
167
|
-
}
|
|
168
|
-
}
|
|
169
|
-
|
|
170
|
-
/**
|
|
171
|
-
* Builds a JSON-RPC 2.0 success response.
|
|
172
|
-
*
|
|
173
|
-
* @param {string|number|null} id
|
|
174
|
-
* @param {*} result
|
|
175
|
-
* @returns {object}
|
|
176
|
-
*/
|
|
177
|
-
function successResponse(id, result) {
|
|
178
|
-
return { jsonrpc: '2.0', id, result };
|
|
179
|
-
}
|
|
180
|
-
|
|
181
|
-
/**
|
|
182
|
-
* Builds a JSON-RPC 2.0 error response.
|
|
183
|
-
*
|
|
184
|
-
* @param {string|number|null} id
|
|
185
|
-
* @param {number} code
|
|
186
|
-
* @param {string} message
|
|
187
|
-
* @returns {object}
|
|
188
|
-
*/
|
|
189
|
-
function errorResponse(id, code, message) {
|
|
190
|
-
return { jsonrpc: '2.0', id, error: { code, message } };
|
|
191
|
-
}
|
|
192
|
-
|
|
193
|
-
/**
|
|
194
|
-
* Handles a single parsed JSON-RPC request object and returns a response object.
|
|
195
|
-
*
|
|
196
|
-
* @param {import('better-sqlite3').Database} db
|
|
197
|
-
* @param {object} request
|
|
198
|
-
* @returns {object}
|
|
199
|
-
*/
|
|
200
|
-
function handleRequest(db, request) {
|
|
201
|
-
const { id = null, method, params } = request;
|
|
202
|
-
|
|
203
|
-
try {
|
|
204
|
-
if (method === 'tools/list') {
|
|
205
|
-
return successResponse(id, { tools: TOOLS });
|
|
206
|
-
}
|
|
207
|
-
|
|
208
|
-
if (method === 'tools/call') {
|
|
209
|
-
const { name: toolName, arguments: toolArgs } = params || {};
|
|
210
|
-
if (!toolName) {
|
|
211
|
-
return errorResponse(id, -32602, 'Missing required param: name');
|
|
212
|
-
}
|
|
213
|
-
const result = callTool(db, toolName, toolArgs);
|
|
214
|
-
return successResponse(id, {
|
|
215
|
-
content: [
|
|
216
|
-
{
|
|
217
|
-
type: 'text',
|
|
218
|
-
text: JSON.stringify(result, null, 2),
|
|
219
|
-
},
|
|
220
|
-
],
|
|
221
|
-
});
|
|
222
|
-
}
|
|
223
|
-
|
|
224
|
-
// Method not found.
|
|
225
|
-
return errorResponse(id, -32601, `Method not found: ${method}`);
|
|
226
|
-
} catch (err) {
|
|
227
|
-
return errorResponse(id, -32603, err.message);
|
|
228
|
-
}
|
|
229
|
-
}
|
|
230
|
-
|
|
231
|
-
/**
|
|
232
|
-
* Starts the MCP stdio server. Reads newline-delimited JSON from stdin,
|
|
233
|
-
* writes newline-delimited JSON to stdout.
|
|
234
|
-
*/
|
|
235
|
-
function startServer() {
|
|
236
|
-
const db = initDb();
|
|
237
|
-
|
|
238
|
-
const rl = readline.createInterface({
|
|
239
|
-
input: process.stdin,
|
|
240
|
-
output: null,
|
|
241
|
-
terminal: false,
|
|
242
|
-
});
|
|
243
|
-
|
|
244
|
-
process.stderr.write('[social-analytics mcp-server] Listening on stdin...\n');
|
|
245
|
-
|
|
246
|
-
rl.on('line', (line) => {
|
|
247
|
-
const trimmed = line.trim();
|
|
248
|
-
if (!trimmed) return;
|
|
249
|
-
|
|
250
|
-
let request;
|
|
251
|
-
try {
|
|
252
|
-
request = JSON.parse(trimmed);
|
|
253
|
-
} catch (_) {
|
|
254
|
-
const resp = errorResponse(null, -32700, 'Parse error: invalid JSON');
|
|
255
|
-
process.stdout.write(JSON.stringify(resp) + '\n');
|
|
256
|
-
return;
|
|
257
|
-
}
|
|
258
|
-
|
|
259
|
-
const response = handleRequest(db, request);
|
|
260
|
-
process.stdout.write(JSON.stringify(response) + '\n');
|
|
261
|
-
});
|
|
262
|
-
|
|
263
|
-
rl.on('close', () => {
|
|
264
|
-
db.close();
|
|
265
|
-
process.stderr.write('[social-analytics mcp-server] stdin closed, shutting down.\n');
|
|
266
|
-
});
|
|
267
|
-
|
|
268
|
-
process.on('SIGINT', () => {
|
|
269
|
-
db.close();
|
|
270
|
-
process.exit(0);
|
|
271
|
-
});
|
|
272
|
-
|
|
273
|
-
process.on('SIGTERM', () => {
|
|
274
|
-
db.close();
|
|
275
|
-
process.exit(0);
|
|
276
|
-
});
|
|
277
|
-
}
|
|
278
|
-
|
|
279
|
-
module.exports = {
|
|
280
|
-
TOOLS,
|
|
281
|
-
callTool,
|
|
282
|
-
handleRequest,
|
|
283
|
-
startServer,
|
|
284
|
-
};
|
|
285
|
-
|
|
286
|
-
// Run as main: start the stdio server.
|
|
287
|
-
if (require.main === module) {
|
|
288
|
-
startServer();
|
|
289
|
-
}
|