diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..dfc69aa --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +# Ignore working scripts with secrets +/scripts/ \ No newline at end of file diff --git a/scripts/add-backlink-targets.sh b/scripts/add-backlink-targets.sh deleted file mode 100644 index 04439f4..0000000 --- a/scripts/add-backlink-targets.sh +++ /dev/null @@ -1,77 +0,0 @@ -#!/bin/bash -# Batch add 50 backlink targets to CRM -# Stage=Hold, strategy="Backlink outreach" - -WEBHOOK="https://n8n.derez.ai/webhook/456e0ca0-b3f2-485e-91ee-861dd0d1f051" -AUTH="KEY: 5UpKtvmMla2My8" - -add() { - local email="$1" name="$2" company="$3" history="$4" - curl -s -X POST "$WEBHOOK" \ - -H "$AUTH" \ - -H "Content-Type: application/json" \ - -d "{\"email\":\"$email\",\"Name\":\"$name\",\"Company\":\"$company\",\"Stage\":\"Hold\",\"strategy\":\"Backlink outreach\",\"category\":\"partner\",\"History\":\"$history\"}" - echo " → added $email" -} - -echo "=== AI DIRECTORIES ===" - -add "ph@producthunt-backlink.local" "Product Hunt" "Product Hunt" "Backlink target — AI tools directory. Type: directory. Site: producthunt.com. Submission: producthunt.com/posts/new. Submit derez.ai listing." -add "bl@betalist-backlink.local" "BetaList" "BetaList" "Backlink target — Early-stage startup directory. Type: directory. Site: betalist.com. Submission: betalist.com/submit. Submit derez.ai." -add "at@alternativeto-backlink.local" "AlternativeTo" "AlternativeTo" "Backlink target — Software alternative finder. Type: directory. Site: alternativeto.net. Submission: alternativeto.net/submit-software/. List derez.ai as alternative." -add "g2@g2-backlink.local" "G2" "G2" "Backlink target — Business software reviews. Type: directory. Site: g2.com. Submission: g2.com/products/new. Create listing." -add "ga@getapp-backlink.local" "GetApp" "GetApp" "Backlink target — Business software directory. Type: directory. Site: getapp.com. Submission: getapp.com/submit-software/. Submit derez.ai." -add "hello@theresanaiforthat.com" "There's An AI For That" "There's An AI For That" "Backlink target — AI tool database. Type: directory. Site: theresanaiforthat.com. Contact: hello@theresanaiforthat.com. Submission: theresanaiforthat.com/submit/." -add "hello@futurepedia.io" "Futurepedia" "Futurepedia" "Backlink target — AI tools directory. Type: directory. Site: futurepedia.io. Contact: hello@futurepedia.io. Submission: futurepedia.io/submit-tool." -add "ac@aicyclopedia-backlink.local" "AIcyclopedia" "AIcyclopedia" "Backlink target — AI tools encyclopedia. Type: directory. Site: aicyclopedia.com. Submission: aicyclopedia.com/submit." -add "atd@aitoolsdirectory-backlink.local" "AI Tools Directory" "AI Tools Directory" "Backlink target — AI tool listings. Type: directory. Site: aitoolsdirectory.com. Submission: aitoolsdirectory.com/submit." -add "tf@toolify-backlink.local" "Toolify.ai" "Toolify.ai" "Backlink target — AI tools ranking. Type: directory. Site: toolify.ai. Submission: toolify.ai/submit." -add "hello@saasaitools.com" "SaaS AI Tools" "SaaS AI Tools" "Backlink target — AI SaaS directory. Type: directory. Site: saasaitools.com. Contact: hello@saasaitools.com. Submission: saasaitools.com/submit." -add "atl@aitoolslist-backlink.local" "AI Tools List" "AI Tools List" "Backlink target — AI tool aggregator. Type: directory. Site: aitoolslist.com. Submission: aitoolslist.com/submit." -add "ia@insidr-backlink.local" "Insidr.ai" "Insidr.ai" "Backlink target — AI tools discovery. Type: directory. Site: insidr.ai. Submission: insidr.ai/submit-ai-tool/." -add "ath@aitoolhunt-backlink.local" "AI Tool Hunt" "AI Tool Hunt" "Backlink target — AI tool search engine. Type: directory. Site: aitoolhunt.com. Submission: aitoolhunt.com/submit." -add "team@openfuture.ai" "OpenFuture AI" "OpenFuture AI" "Backlink target — AI tools platform. Type: directory. Site: openfuture.ai. Contact: team@openfuture.ai. Submission: openfuture.ai/submit." - -echo "=== TECH BLOGS ===" - -add "hn@hackernoon-backlink.local" "HackerNoon" "HackerNoon" "Backlink target — Tech publication accepting guest posts. Type: blog. Site: hackernoon.com. Guest post: hackernoon.com/guest-post. Pitch agent hosting article." -add "dv@devto-backlink.local" "Dev.to" "Dev.to" "Backlink target — Developer community platform. Type: blog. Site: dev.to. Write: dev.to/write. Cross-post tutorial articles." -add "editors@towardsdatascience.com" "Towards Data Science" "Towards Data Science" "Backlink target — Medium AI/DS publication. Type: blog. Site: towardsdatascience.com. Contact: editors@towardsdatascience.com. Guest post: towardsdatascience.com/guest-post." -add "betterprogramming.medium@gmail.com" "Better Programming" "Better Programming" "Backlink target — Medium dev publication. Type: blog. Site: betterprogramming.pub. Contact: betterprogramming.medium@gmail.com." -add "editors@freecodecamp.org" "FreeCodeCamp" "FreeCodeCamp" "Backlink target — Learn-to-code platform. Type: blog. Site: freecodecamp.org. Contact: editors@freecodecamp.org. Publish: freecodecamp.org/news/publish." -add "editorial@smashingmagazine.com" "Smashing Magazine" "Smashing Magazine" "Backlink target — Web dev magazine. Type: blog. Site: smashingmagazine.com. Contact: editorial@smashingmagazine.com. Write-for-us: smashingmagazine.com/write-for-us." -add "ct@csstricks-backlink.local" "CSS-Tricks" "CSS-Tricks" "Backlink target — Web dev blog. Type: blog. Site: css-tricks.com. Guest post: css-tricks.com/guest-posting." -add "codeburstofficial@gmail.com" "Codeburst" "Codeburst" "Backlink target — Medium dev publication. Type: blog. Site: codeburst.io. Contact: codeburstofficial@gmail.com. Write-for-us: codeburst.io/write-for-us." -add "info@aitrends.com" "AI Trends" "AI Trends" "Backlink target — AI industry publication. Type: blog. Site: aitrends.com. Contact: info@aitrends.com." -add "kdnuggets1@gmail.com" "KDnuggets" "KDnuggets" "Backlink target — Data science/AI blog. Type: blog. Site: kdnuggets.com. Contact: kdnuggets1@gmail.com." -add "contact@analyticsvidhya.com" "Analytics Vidhya" "Analytics Vidhya" "Backlink target — AI/data science community. Type: blog. Site: analyticsvidhya.com. Contact: contact@analyticsvidhya.com." -add "editors@infoq.com" "InfoQ" "InfoQ" "Backlink target — Software dev news. Type: blog. Site: infoq.com. Contact: editors@infoq.com." -add "editors@dzone.com" "DZone" "DZone" "Backlink target — Developer community. Type: blog. Site: dzone.com. Contact: editors@dzone.com. Guest post: dzone.com/guest-post." -add "editorial@thenewstack.io" "The New Stack" "The New Stack" "Backlink target — Cloud/DevOps publication. Type: blog. Site: thenewstack.io. Contact: editorial@thenewstack.io." -add "towardsaiteam@gmail.com" "Towards AI" "Towards AI" "Backlink target — AI community publication. Type: blog. Site: towardsai.net. Contact: towardsaiteam@gmail.com." - -echo "=== YOUTUBE / NEWSLETTER ===" - -add "ns@nicksweeney-backlink.local" "Nick Sweeney" "Nick Sweeney YouTube" "Backlink target — AI/tech YouTube creator. Type: youtube. Channel: youtube.com/@nicksweeney. Covers AI agents and dev tools." -add "fs@fireship-backlink.local" "Fireship" "Fireship YouTube" "Backlink target — High-production dev tutorials. Type: youtube. Channel: youtube.com/@fireship. 2M+ subs. Covers AI code, dev tooling." -add "nr@nicholasrenotte-backlink.local" "Nicholas Renotte" "Nicholas Renotte YouTube" "Backlink target — AI/ML YouTube creator. Type: youtube. Channel: youtube.com/@nicholasrenotte. Covers AI development." -add "aj@aijason-backlink.local" "AI Jason" "AI Jason YouTube" "Backlink target — AI tools/productivity YouTuber. Type: youtube. Channel: youtube.com/@aijason. Reviews AI tools, agent demos." -add "sw@samwitteveen-backlink.local" "Sam Witteveen" "Sam Witteveen YouTube" "Backlink target — AI/ML YouTuber. Type: youtube. Channel: youtube.com/@samwitteveen. Covers LLMs, agents." -add "lc@1littlecoder-backlink.local" "1littlecoder" "1littlecoder YouTube" "Backlink target — AI coding/code generation YouTuber. Type: youtube. Channel: youtube.com/@1littlecoder." -add "aaa@allaboutai-backlink.local" "All About AI" "All About AI YouTube" "Backlink target — AI news/tools YouTube channel. Type: youtube. Channel: youtube.com/@allaboutai." -add "ae@aiexplained-backlink.local" "AI Explained" "AI Explained YouTube" "Backlink target — AI deep-dive YouTube channel. Type: youtube. Channel: youtube.com/@aiexplainedtv. Covers LLMs, agents." -add "lc@langchain-backlink.local" "LangChain" "LangChain YouTube" "Backlink target — Official LangChain channel. Type: youtube. Channel: youtube.com/@langchain. Covers agent frameworks." -add "n8n@n8n-backlink.local" "n8n" "n8n YouTube" "Backlink target — n8n official YouTube. Type: youtube. Channel: youtube.com/@n8n-io. Covers automation workflows, AI agents integration." -add "as@assemblyai-backlink.local" "AssemblyAI" "AssemblyAI YouTube" "Backlink target — AI API company YouTube. Type: youtube. Channel: youtube.com/@assemblyai. Covers AI/ML dev, speech." -add "mw@mckaywrigley-backlink.local" "Mckay Wrigley" "Mckay Wrigley YouTube" "Backlink target — AI coding/building YouTuber. Type: youtube. Channel: youtube.com/@mckaywrigley. Covers AI apps, agents." -add "mw@mattwolfe-backlink.local" "Matt Wolfe" "Matt Wolfe YouTube" "Backlink target — AI tools/reviews YouTuber. Type: youtube. Channel: youtube.com/@mattwolfeyt. 700K+ subs. Reviews AI tools." -add "tab@theaibreakdown-backlink.local" "The AI Breakdown" "The AI Breakdown Newsletter" "Backlink target — AI news newsletter. Type: newsletter. Site: theaibreakdown.com. Daily AI analysis." -add "lw@lastweekinai-backlink.local" "LastWeekInAI" "LastWeekInAI Newsletter" "Backlink target — Weekly AI roundup newsletter. Type: newsletter. Site: lastweekin.ai. Covers AI agent developments." -add "tn@theneuron-backlink.local" "The Neuron" "The Neuron Newsletter" "Backlink target — AI newsletter. Type: newsletter. Site: theneurondaily.com. Daily AI updates. High reach." -add "tr@therundown-backlink.local" "The Rundown AI" "The Rundown AI Newsletter" "Backlink target — Daily AI newsletter. Type: newsletter. Site: therundown.ai. 500K+ readers. Major reach." -add "ab@aibreakfast-backlink.local" "AI Breakfast" "AI Breakfast Newsletter" "Backlink target — AI tools newsletter. Type: newsletter. Site: aibreakfast.com. Covers new AI tools weekly." -add "bb@bensbites-backlink.local" "Ben's Bites" "Ben's Bites Newsletter" "Backlink target — Daily AI newsletter. Type: newsletter. Site: bensbites.com. Covers AI tools, agents, LLMs. 100K+ readers." -add "mw@mattwilliams-backlink.local" "Matt Williams" "Matt Williams YouTube" "Backlink target — AI dev YouTube creator. Type: youtube. Covers AI coding, agent building." - -echo "" -echo "=== ALL 50 ADDED ===" \ No newline at end of file diff --git a/scripts/check-plausible-email.py b/scripts/check-plausible-email.py deleted file mode 100755 index 5cb6ee0..0000000 --- a/scripts/check-plausible-email.py +++ /dev/null @@ -1,89 +0,0 @@ -#!/usr/bin/env python3 -"""Check for Plausible analytics email and output raw content for cron analysis.""" - -import json -import re -import subprocess -import sys -from datetime import datetime -from pathlib import Path - -HERE = Path(__file__).resolve().parent.parent -INSIGHTS_FILE = HERE / "data" / "insights.json" - - -def run_cmd(*args, timeout=30): - result = subprocess.run(args, capture_output=True, text=True, timeout=timeout) - if result.returncode != 0: - return None, result.stderr - return result.stdout, None - - -def find_plausible_email(): - """Find the latest Plausible-related email in inbox.""" - out, err = run_cmd("himalaya", "envelope", "list", "--page", "1", "--page-size", "30") - if not out: - return None, None - - best_id, best_subject = None, "" - current_id, current_subject = None, "" - for line in out.splitlines(): - # himalaya format: "ID | DATE | FROM | SUBJECT" - if "|" not in line: - continue - parts = [p.strip() for p in line.split("|")] - if len(parts) < 4: - continue - try: - current_id = int(parts[0]) - except ValueError: - continue - current_subject = parts[-1] if len(parts) >= 4 else "" - - subj_lower = current_subject.lower() - score = 0 - if "plausible" in subj_lower: - score += 10 - if "weekly" in subj_lower and ("report" in subj_lower or "analytics" in subj_lower or "stats" in subj_lower): - score += 5 - if "analytics" in subj_lower and "summary" in subj_lower: - score += 5 - if "site" in subj_lower and ("stats" in subj_lower or "report" in subj_lower): - score += 3 - - if score > 0 and score >= (10 if best_id is None else 0): - best_id = current_id - best_subject = current_subject - - return best_id, best_subject - - -def main(): - email_id, subject = find_plausible_email() - - if email_id is None: - print("No Plausible email found in inbox.", file=sys.stderr) - # Still update last_check timestamp - insights = {} - if INSIGHTS_FILE.exists(): - with open(INSIGHTS_FILE) as f: - insights = json.load(f) - insights["last_check"] = datetime.now().strftime("%Y-%m-%d %H:%M") - with open(INSIGHTS_FILE, "w") as f: - json.dump(insights, f, indent=2) - sys.exit(0) - - content, err = run_cmd("himalaya", "message", "read", str(email_id)) - if not content: - print(f"Failed to read email {email_id}: {err}", file=sys.stderr) - sys.exit(0) - - print(f"=== Plausible Email Found ===") - print(f"Subject: {subject}") - print(f"Email ID: {email_id}") - print(f"=== Full Content ===") - print(content[:6000]) - - -if __name__ == "__main__": - main() \ No newline at end of file diff --git a/scripts/update-dashboard.py b/scripts/update-dashboard.py deleted file mode 100755 index 6ea11d8..0000000 --- a/scripts/update-dashboard.py +++ /dev/null @@ -1,131 +0,0 @@ -#!/usr/bin/env python3 -"""Daily launch dashboard updater — runs at 03:00 PYST via cron. - -Reads data/launch-status.json, updates KPIs from live sources, -advances the day counter, sets today's actions to 'today' status, -and writes back. Designed to be quiet (stdout only on error) so cron -delivery stays clean. -""" - -import json -import os -import subprocess -import sys -from datetime import date, datetime, timezone, timedelta -from pathlib import Path - -HERE = Path(__file__).resolve().parent.parent # repo root (scripts/ is a subdir) -DATA_FILE = HERE / "data" / "launch-status.json" -TZ_OFFSET = timedelta(hours=-4) # PYST (America/Asuncion) - -# ── Day calculation ─────────────────────────────────────────────── -LAUNCH_START = date(2026, 6, 9) - -def current_day() -> int: - """Return 1–14 based on days since launch start.""" - today = date.today() - diff = (today - LAUNCH_START).days - return max(1, min(14, diff + 1)) - - -# ── KPI probes ──────────────────────────────────────────────────── - -def probe_signups() -> int: - """Read signups from the payment webhook log or n8n status.""" - # TODO: wire up to n8n.derez.ai/webhook endpoint for count - return 0 - - -def probe_visitors() -> int: - """Estimate landing page visitors via log analysis or a placeholder.""" - # TODO: integrate with analytics or server log parsing - return 0 - - -def probe_emails() -> int: - """Email list signups.""" - return 0 - - -def probe_backlinks() -> int: - """Check for new referring domains.""" - return 0 - - -def probe_influencers() -> int: - """Count confirmed influencer partnerships.""" - return 0 - - -def probe_testimonials() -> int: - """Count collected F&F testimonials.""" - return 0 - - -def probe_impressions() -> int: - """Google Search Console impressions (last 7 days).""" - return 0 - - -def probe_directory_listings() -> int: - """Count live directory listings (Product Hunt, BetaList, etc.).""" - return 0 - - -# ── Main update ─────────────────────────────────────────────────── - -def main(): - if not DATA_FILE.exists(): - print(f"ERROR: data file not found at {DATA_FILE}", file=sys.stderr) - sys.exit(1) - - with open(DATA_FILE) as f: - data = json.load(f) - - day = current_day() - - # Update KPIs with real probes - kpi_map = { - "signups": probe_signups, - "visitors": probe_visitors, - "emails": probe_emails, - "backlinks": probe_backlinks, - "influencers": probe_influencers, - "testimonials": probe_testimonials, - "impressions": probe_impressions, - "directory": probe_directory_listings, - } - - for kpi in data.get("kpis", []): - probe_fn = kpi_map.get(kpi["id"]) - if probe_fn: - try: - kpi["current"] = probe_fn() - except Exception as e: - print(f"WARN: probe failed for {kpi['id']}: {e}", file=sys.stderr) - - # Update day number - data["day"] = day - - # Mark today's actions as "today" if they're still pending - yesterday_actions = set() - for action in data.get("actions", []): - if action["day"] == day and action["status"] == "pending": - action["status"] = "today" - if action["status"] == "today": - yesterday_actions.add(action["action"]) - - # Timestamp - now = datetime.now(timezone.utc) - data["updated"] = now.strftime("%Y-%m-%dT%H:%M:%S") + "-04:00" - data["notes"] = f"Day {day} auto-update at {now.strftime('%H:%M')} UTC / {day}/14 complete." - - with open(DATA_FILE, "w") as f: - json.dump(data, f, indent=2) - - # Quiet success — no stdout so cron doesn't spam - sys.exit(0) - - -if __name__ == "__main__": - main() \ No newline at end of file