← back to Cncp Domains
initial snapshot — gitify all builds (CLAUDE.md rule 2026-05-06)
161ada1e465b800406fe133e7ffb19b7a3dcc354 · 2026-05-06 10:20:41 -0700 · Steve
Files touched
A .gitignoreA logs/expiring-2026-05-05.mdA logs/expiring-2026-05-06.mdA logs/last-george.errA logs/last-george.jsonA scripts/expiring-soon.sh
Diff
commit 161ada1e465b800406fe133e7ffb19b7a3dcc354
Author: Steve <steve@designerwallcoverings.com>
Date: Wed May 6 10:20:41 2026 -0700
initial snapshot — gitify all builds (CLAUDE.md rule 2026-05-06)
---
.gitignore | 25 ++++++
logs/expiring-2026-05-05.md | 39 ++++++++++
logs/expiring-2026-05-06.md | 38 +++++++++
logs/last-george.err | 0
logs/last-george.json | 1 +
scripts/expiring-soon.sh | 182 ++++++++++++++++++++++++++++++++++++++++++++
6 files changed, 285 insertions(+)
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..9ae81e0
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,25 @@
+node_modules/
+.env
+.env.*
+!.env.example
+tmp/
+*.log
+.DS_Store
+dist/
+build/
+.next/
+.cache/
+.parcel-cache/
+coverage/
+__pycache__/
+*.pyc
+*.pyo
+.venv/
+venv/
+.pytest_cache/
+.ruff_cache/
+.idea/
+.vscode/
+*.swp
+.qodo/
+out/
diff --git a/logs/expiring-2026-05-05.md b/logs/expiring-2026-05-05.md
new file mode 100644
index 0000000..447e756
--- /dev/null
+++ b/logs/expiring-2026-05-05.md
@@ -0,0 +1,39 @@
+# CNCP domains expiring within 14 days
+
+_As of 2026-05-05 — 33 expiring (7 Keep, 25 Toss, 30 under 7d)_
+
+| Days Left | Domain | Registrar | Auto-Renew | Suggestion | Expires |
+|---:|---|---|---|---|---|
+| 0 | wallpapernashville.com | GoDaddy | OFF | Toss | 2026-05-05 |
+| 1 | commercialdesignreps.com | GoDaddy | ON | Toss | 2026-05-06 |
+| 1 | commercialsalesreps.com | GoDaddy | ON | Keep | 2026-05-06 |
+| 1 | designtradesalesreps.com | GoDaddy | ON | Keep | 2026-05-06 |
+| 1 | filthyrichliving.com | GoDaddy | OFF | Toss | 2026-05-06 |
+| 1 | flufears.org | GoDaddy | OFF | Toss | 2026-05-06 |
+| 1 | hospitalitydesignreps.com | GoDaddy | ON | Toss | 2026-05-06 |
+| 1 | hospitalitysalesreps.com | GoDaddy | ON | Keep | 2026-05-06 |
+| 1 | interiordesignreps.com | GoDaddy | ON | Keep | 2026-05-06 |
+| 1 | localsalesreps.com | GoDaddy | ON | Keep | 2026-05-06 |
+| 1 | showroomreps.com | GoDaddy | ON | Toss | 2026-05-06 |
+| 1 | showroomsalesreps.com | GoDaddy | ON | Toss | 2026-05-06 |
+| 1 | telesalesrep.com | GoDaddy | ON | Toss | 2026-05-06 |
+| ⚠ 3 | steveabramsdesigns.com | GoDaddy | OFF | Keep | 2026-05-08 |
+| 4 | blankstocklining.com | GoDaddy | OFF | Toss | 2026-05-09 |
+| ⚠ 4 | flockedwallpaper.com | GoDaddy | OFF | Keep | 2026-05-09 |
+| 4 | goldleafwallpaper.com | GoDaddy | unknown | - | 2026-05-09 |
+| 4 | hotelwallcoverings.com | GoDaddy | OFF | Toss | 2026-05-09 |
+| 4 | linenwallpaper.com | GoDaddy | OFF | Toss | 2026-05-09 |
+| 4 | madagascarwallpaper.com | GoDaddy | OFF | Toss | 2026-05-09 |
+| 4 | naturaltextilewallpaper.com | GoDaddy | OFF | Toss | 2026-05-09 |
+| 4 | raffiawallcoverings.com | GoDaddy | OFF | Toss | 2026-05-09 |
+| 4 | silkwallpaper.com | GoDaddy | OFF | Toss | 2026-05-09 |
+| 5 | 1970swallpaper.com | GoDaddy | OFF | Toss | 2026-05-10 |
+| 5 | wallpapercanada.com | GoDaddy | OFF | Toss | 2026-05-10 |
+| 6 | 1920swallpaper.com | GoDaddy | OFF | Toss | 2026-05-11 |
+| 6 | 1930swallpaper.com | GoDaddy | OFF | Toss | 2026-05-11 |
+| 6 | 1940swallpaper.com | GoDaddy | OFF | Toss | 2026-05-11 |
+| 6 | 1960swallpaper.com | GoDaddy | OFF | Toss | 2026-05-11 |
+| 6 | 1980swallpaper.com | GoDaddy | OFF | Toss | 2026-05-11 |
+| 7 | customdigitalwallcoverings.com | GoDaddy | OFF | Toss | 2026-05-12 |
+| 9 | sheltermagazines.com | GoDaddy | OFF | Toss | 2026-05-14 |
+| 12 | designerrepresentatives.com | GoDaddy | ON | Toss | 2026-05-17 |
diff --git a/logs/expiring-2026-05-06.md b/logs/expiring-2026-05-06.md
new file mode 100644
index 0000000..e946aa8
--- /dev/null
+++ b/logs/expiring-2026-05-06.md
@@ -0,0 +1,38 @@
+# CNCP domains expiring within 14 days
+
+_As of 2026-05-06 — 32 expiring (7 Keep, 24 Toss, 30 under 7d)_
+
+| Days Left | Domain | Registrar | Auto-Renew | Suggestion | Expires |
+|---:|---|---|---|---|---|
+| 0 | commercialdesignreps.com | GoDaddy | ON | Toss | 2026-05-06 |
+| 0 | commercialsalesreps.com | GoDaddy | ON | Keep | 2026-05-06 |
+| 0 | designtradesalesreps.com | GoDaddy | ON | Keep | 2026-05-06 |
+| 0 | filthyrichliving.com | GoDaddy | OFF | Toss | 2026-05-06 |
+| 0 | flufears.org | GoDaddy | OFF | Toss | 2026-05-06 |
+| 0 | hospitalitydesignreps.com | GoDaddy | ON | Toss | 2026-05-06 |
+| 0 | hospitalitysalesreps.com | GoDaddy | ON | Keep | 2026-05-06 |
+| 0 | interiordesignreps.com | GoDaddy | ON | Keep | 2026-05-06 |
+| 0 | localsalesreps.com | GoDaddy | ON | Keep | 2026-05-06 |
+| 0 | showroomreps.com | GoDaddy | ON | Toss | 2026-05-06 |
+| 0 | showroomsalesreps.com | GoDaddy | ON | Toss | 2026-05-06 |
+| 0 | telesalesrep.com | GoDaddy | ON | Toss | 2026-05-06 |
+| ⚠ 2 | steveabramsdesigns.com | GoDaddy | OFF | Keep | 2026-05-08 |
+| 3 | blankstocklining.com | GoDaddy | OFF | Toss | 2026-05-09 |
+| ⚠ 3 | flockedwallpaper.com | GoDaddy | OFF | Keep | 2026-05-09 |
+| 3 | goldleafwallpaper.com | GoDaddy | unknown | - | 2026-05-09 |
+| 3 | hotelwallcoverings.com | GoDaddy | OFF | Toss | 2026-05-09 |
+| 3 | linenwallpaper.com | GoDaddy | OFF | Toss | 2026-05-09 |
+| 3 | madagascarwallpaper.com | GoDaddy | OFF | Toss | 2026-05-09 |
+| 3 | naturaltextilewallpaper.com | GoDaddy | OFF | Toss | 2026-05-09 |
+| 3 | raffiawallcoverings.com | GoDaddy | OFF | Toss | 2026-05-09 |
+| 3 | silkwallpaper.com | GoDaddy | OFF | Toss | 2026-05-09 |
+| 4 | 1970swallpaper.com | GoDaddy | OFF | Toss | 2026-05-10 |
+| 4 | wallpapercanada.com | GoDaddy | OFF | Toss | 2026-05-10 |
+| 5 | 1920swallpaper.com | GoDaddy | OFF | Toss | 2026-05-11 |
+| 5 | 1930swallpaper.com | GoDaddy | OFF | Toss | 2026-05-11 |
+| 5 | 1940swallpaper.com | GoDaddy | OFF | Toss | 2026-05-11 |
+| 5 | 1960swallpaper.com | GoDaddy | OFF | Toss | 2026-05-11 |
+| 5 | 1980swallpaper.com | GoDaddy | OFF | Toss | 2026-05-11 |
+| 6 | customdigitalwallcoverings.com | GoDaddy | OFF | Toss | 2026-05-12 |
+| 8 | sheltermagazines.com | GoDaddy | OFF | Toss | 2026-05-14 |
+| 11 | designerrepresentatives.com | GoDaddy | ON | Toss | 2026-05-17 |
diff --git a/logs/last-george.err b/logs/last-george.err
new file mode 100644
index 0000000..e69de29
diff --git a/logs/last-george.json b/logs/last-george.json
new file mode 100644
index 0000000..126e748
--- /dev/null
+++ b/logs/last-george.json
@@ -0,0 +1 @@
+{"success":true,"messageId":"19dfe199e68e1abd","threadId":"19dfe199e68e1abd","account":"steve-office","source":"curl/8.7.1","inThread":false}
\ No newline at end of file
diff --git a/scripts/expiring-soon.sh b/scripts/expiring-soon.sh
new file mode 100755
index 0000000..ce6bc56
--- /dev/null
+++ b/scripts/expiring-soon.sh
@@ -0,0 +1,182 @@
+#!/usr/bin/env bash
+# expiring-soon.sh — alert Steve about CNCP domains expiring within 14 days.
+# - reads ~/cncp-starter/cncp-config.json
+# - filters domains with `expires` in the next 14 days from today
+# - posts an HTML email via George Gmail bridge (localhost:9850)
+# - on George failure, writes a markdown report to logs/ and exits 1
+# - silent exit 0 when nothing is expiring
+
+set -uo pipefail
+
+CONFIG="${HOME}/cncp-starter/cncp-config.json"
+PROJECT_DIR="${HOME}/Projects/cncp-domains"
+LOG_DIR="${PROJECT_DIR}/logs"
+GEORGE_URL="http://localhost:9850/api/send"
+GEORGE_AUTH="admin:DWSecure2024!"
+RECIPIENT="steveabramsdesigns@gmail.com"
+WINDOW_DAYS=14
+URGENT_DAYS=7
+DRY_RUN="${DRY_RUN:-0}"
+
+mkdir -p "${LOG_DIR}"
+
+if [[ ! -f "${CONFIG}" ]]; then
+ echo "[expiring-soon] config not found: ${CONFIG}" >&2
+ exit 1
+fi
+
+if ! command -v jq >/dev/null 2>&1; then
+ echo "[expiring-soon] jq is required" >&2
+ exit 1
+fi
+
+TODAY="$(date -I)"
+TODAY_EPOCH="$(date -j -f '%Y-%m-%d' "${TODAY}" +%s 2>/dev/null || date -d "${TODAY}" +%s)"
+
+# Build a JSON array of expiring domains, each with a `daysLeft` field.
+EXPIRING_JSON="$(
+ jq --arg today "${TODAY}" --argjson window "${WINDOW_DAYS}" '
+ def dayDiff(d):
+ ((d | strptime("%Y-%m-%d") | mktime) - ($today | strptime("%Y-%m-%d") | mktime)) / 86400 | floor;
+ [
+ .domains[]
+ | select(.expires != null and .expires != "")
+ | . + {daysLeft: dayDiff(.expires)}
+ | select(.daysLeft >= 0 and .daysLeft <= $window)
+ ]
+ | sort_by(.daysLeft)
+ ' "${CONFIG}"
+)"
+
+COUNT="$(echo "${EXPIRING_JSON}" | jq 'length')"
+
+if [[ "${COUNT}" -eq 0 ]]; then
+ # Nothing to alert about — silent exit per spec.
+ exit 0
+fi
+
+# ---------- build HTML body ----------
+HTML_TABLE="$(
+ echo "${EXPIRING_JSON}" | jq -r --argjson urgent "${URGENT_DAYS}" '
+ def autorenew(n):
+ if n == null then "unknown"
+ elif (n | test("(?i)Auto-renew:\\s*ON")) then "ON"
+ elif (n | test("(?i)Auto-renew:\\s*OFF")) then "OFF"
+ else "unknown"
+ end;
+ def keepish(s): (s // "" | ascii_downcase) | startswith("keep");
+ def warnRow(d):
+ d.daysLeft < $urgent
+ and autorenew(d.note) == "OFF"
+ and keepish(d.suggestion);
+ map(
+ "<tr style=\"background:" +
+ (if warnRow(.) then "#fee2e2" else (if (.daysLeft|tonumber) < 7 then "#fef3c7" else "#ffffff" end) end) +
+ ";\">" +
+ "<td style=\"padding:6px 10px;border:1px solid #e5e7eb;text-align:right;\">" +
+ (if warnRow(.) then "⚠ " else "" end) + (.daysLeft|tostring) +
+ "</td>" +
+ "<td style=\"padding:6px 10px;border:1px solid #e5e7eb;\"><b>" + (.name // "?") + "</b></td>" +
+ "<td style=\"padding:6px 10px;border:1px solid #e5e7eb;\">" + (.reg // "?") + "</td>" +
+ "<td style=\"padding:6px 10px;border:1px solid #e5e7eb;\">" + autorenew(.note) + "</td>" +
+ "<td style=\"padding:6px 10px;border:1px solid #e5e7eb;\">" + (.suggestion // "-") + "</td>" +
+ "<td style=\"padding:6px 10px;border:1px solid #e5e7eb;color:#555;\">" + (.expires // "") + "</td>" +
+ "</tr>"
+ ) | join("\n")
+ '
+)"
+
+KEEP_COUNT="$(echo "${EXPIRING_JSON}" | jq '[.[] | select((.suggestion // "" | ascii_downcase) | startswith("keep"))] | length')"
+TOSS_COUNT="$(echo "${EXPIRING_JSON}" | jq '[.[] | select((.suggestion // "" | ascii_downcase) | startswith("toss"))] | length')"
+URGENT_COUNT="$(echo "${EXPIRING_JSON}" | jq --argjson u "${URGENT_DAYS}" '[.[] | select(.daysLeft < $u)] | length')"
+
+REGISTRAR_BREAKDOWN="$(
+ echo "${EXPIRING_JSON}" | jq -r '
+ group_by(.reg // "Unknown")
+ | map("<li><b>" + (.[0].reg // "Unknown") + ":</b> " + (length|tostring) + "</li>")
+ | join("")
+ '
+)"
+
+HTML_BODY="$(cat <<HTMLEOF
+<html><body style="font-family:-apple-system,Segoe UI,Roboto,sans-serif;color:#111;">
+<h2 style="margin:0 0 8px;">CNCP domains expiring in the next ${WINDOW_DAYS} days</h2>
+<p style="margin:0 0 12px;color:#555;">As of ${TODAY} · <b>${COUNT}</b> expiring · <b>${KEEP_COUNT}</b> Keep · <b>${TOSS_COUNT}</b> Toss · <b>${URGENT_COUNT}</b> under ${URGENT_DAYS} days</p>
+<h3 style="margin:14px 0 6px;">By registrar</h3>
+<ul style="margin:0 0 12px 18px;">${REGISTRAR_BREAKDOWN}</ul>
+<table style="border-collapse:collapse;border:1px solid #e5e7eb;font-size:13px;min-width:640px;">
+<thead><tr style="background:#f3f4f6;">
+<th style="padding:6px 10px;border:1px solid #e5e7eb;text-align:right;">Days Left</th>
+<th style="padding:6px 10px;border:1px solid #e5e7eb;text-align:left;">Domain</th>
+<th style="padding:6px 10px;border:1px solid #e5e7eb;text-align:left;">Registrar</th>
+<th style="padding:6px 10px;border:1px solid #e5e7eb;text-align:left;">Auto-Renew</th>
+<th style="padding:6px 10px;border:1px solid #e5e7eb;text-align:left;">Suggestion</th>
+<th style="padding:6px 10px;border:1px solid #e5e7eb;text-align:left;">Expires</th>
+</tr></thead>
+<tbody>
+${HTML_TABLE}
+</tbody></table>
+<p style="margin:14px 0 0;color:#888;font-size:12px;">Red rows = under ${URGENT_DAYS} days, auto-renew OFF, suggestion = Keep. Yellow rows = under 7 days but lower urgency.</p>
+<p style="margin:6px 0 0;color:#888;font-size:12px;">Source: ~/cncp-starter/cncp-config.json · alert script: ~/Projects/cncp-domains/scripts/expiring-soon.sh</p>
+</body></html>
+HTMLEOF
+)"
+
+SUBJECT="CNCP domains expiring this week (${COUNT} in ${WINDOW_DAYS}d, ${URGENT_COUNT} urgent)"
+
+# ---------- markdown fallback (always written for audit) ----------
+LOG_FILE="${LOG_DIR}/expiring-${TODAY}.md"
+{
+ echo "# CNCP domains expiring within ${WINDOW_DAYS} days"
+ echo ""
+ echo "_As of ${TODAY} — ${COUNT} expiring (${KEEP_COUNT} Keep, ${TOSS_COUNT} Toss, ${URGENT_COUNT} under ${URGENT_DAYS}d)_"
+ echo ""
+ echo "| Days Left | Domain | Registrar | Auto-Renew | Suggestion | Expires |"
+ echo "|---:|---|---|---|---|---|"
+ echo "${EXPIRING_JSON}" | jq -r --argjson u "${URGENT_DAYS}" '
+ def autorenew(n):
+ if n == null then "unknown"
+ elif (n | test("(?i)Auto-renew:\\s*ON")) then "ON"
+ elif (n | test("(?i)Auto-renew:\\s*OFF")) then "OFF"
+ else "unknown"
+ end;
+ def keepish(s): (s // "" | ascii_downcase) | startswith("keep");
+ .[] | (
+ (if (.daysLeft < $u and autorenew(.note) == "OFF" and keepish(.suggestion)) then "⚠ " else "" end)
+ + (.daysLeft|tostring)
+ ) as $d
+ | "| " + $d + " | " + (.name // "?") + " | " + (.reg // "?") + " | " + autorenew(.note) + " | " + (.suggestion // "-") + " | " + (.expires // "") + " |"
+ '
+} > "${LOG_FILE}"
+
+# ---------- DRY RUN: never actually email ----------
+if [[ "${DRY_RUN}" == "1" ]]; then
+ echo "[expiring-soon] DRY RUN — would email ${RECIPIENT}"
+ echo "[expiring-soon] subject: ${SUBJECT}"
+ echo "[expiring-soon] markdown report: ${LOG_FILE}"
+ echo "[expiring-soon] expiring count: ${COUNT}"
+ echo "----- markdown table -----"
+ cat "${LOG_FILE}"
+ exit 0
+fi
+
+# ---------- POST to George ----------
+PAYLOAD="$(jq -nc \
+ --arg to "${RECIPIENT}" \
+ --arg subject "${SUBJECT}" \
+ --arg body "${HTML_BODY}" \
+ '{to:$to, subject:$subject, body:$body}')"
+
+HTTP_OUT="$(curl -sS -o "${LOG_DIR}/last-george.json" -w '%{http_code}' \
+ -X POST "${GEORGE_URL}" \
+ -u "${GEORGE_AUTH}" \
+ -H 'content-type: application/json' \
+ --data-binary "${PAYLOAD}" 2>>"${LOG_DIR}/last-george.err" || echo "000")"
+
+if [[ "${HTTP_OUT}" =~ ^2 ]]; then
+ echo "[expiring-soon] sent ${COUNT} expiring domains to ${RECIPIENT} (HTTP ${HTTP_OUT})"
+ exit 0
+fi
+
+echo "[expiring-soon] George send FAILED (HTTP ${HTTP_OUT}); markdown report kept at ${LOG_FILE}" >&2
+exit 1
(oldest)
·
back to Cncp Domains
·
snapshot: 8 file(s) changed, +6 new, ~2 modified 9d4555c →