From 0471edac1b46eb426c8bdd0a23a906991964dec0 Mon Sep 17 00:00:00 2001 From: Anthony Ettinger Date: Mon, 19 Oct 2026 07:52:49 +0000 Subject: [PATCH] feat(ads): one CrawlProof text_link frame above the footer Slot 71955dcb (active), on every public page via foot(). The site's CSP (nonce-only style-src, self-only img-src) would be inherited by ad.js's srcdoc creative, so this uses the script-free /api/ads/frame iframe: one frame-src https://crawlproof.com entry, no third-party JS. text_link is fluid, so it never crops on a phone. Also resyncs data/commands.json, which the daily drift check has flagged as stale since 2026-10-16. Co-Authored-By: Claude Opus 5.5 --- data/commands.json | 20 +++++++++++++++++++- public/style.css | 5 +++++ src/server.mjs | 2 +- src/site.mjs | 19 ++++++++++++++++++- test/site.test.mjs | 10 ++++++++++ 5 files changed, 53 insertions(+), 3 deletions(-) diff --git a/data/commands.json b/data/commands.json index cf2569a..0cfa540 100644 --- a/data/commands.json +++ b/data/commands.json @@ -25,6 +25,18 @@ "group": "engines", "summary": "launch an engine with its native defaults" }, + { + "name": "oneshot", + "aliases": [], + "group": "engines", + "summary": "run one prompt on one engine (CLI or API: zai, perplexity, fugu) and print the answer" + }, + { + "name": "hooks", + "aliases": [], + "group": "engines", + "summary": "fan-out prompt runner: a signed webhook in, one signed result per engine back out" + }, { "name": "herd", "aliases": [], @@ -49,6 +61,12 @@ "group": "runtime", "summary": "the OpenFleet sysop tool: open a fleet, cap it, see the tree, stop a swarm, read the ledger (PRD 0016)" }, + { + "name": "work", + "aliases": [], + "group": "runtime", + "summary": "a queue of tasks that carry their own verify command, drained by headless workers; you see only the inbox (PRD 0021)" + }, { "name": "handoff", "aliases": [], @@ -175,7 +193,7 @@ "name": "export", "aliases": [], "group": "account", - "summary": "operator only: export the app's users as CSV, optionally cleaned" + "summary": "operator only: export users as CSV (this app, or --all properties), optionally cleaned" }, { "name": "console", diff --git a/public/style.css b/public/style.css index bf0f8dc..530c51c 100644 --- a/public/style.css +++ b/public/style.css @@ -276,3 +276,8 @@ h1 { .prose .prose-list li { margin-bottom: 10px; } .prose .term { margin: 26px 0 28px; } @media (min-width: 900px) { .prose .term-wide { width: calc(100% + 160px); max-width: none; } } + +/* CrawlProof text_link frame above the footer: fluid, 40px, carries its own + "Sponsored" mark. */ +.cp-ad { margin-top: 40px; margin-bottom: 40px; } +.cp-ad iframe { display: block; width: 100%; height: 40px; border: 0; } diff --git a/src/server.mjs b/src/server.mjs index 2d93617..a7b8e7e 100644 --- a/src/server.mjs +++ b/src/server.mjs @@ -40,7 +40,7 @@ export function createApp() { 'Referrer-Policy': 'strict-origin-when-cross-origin', 'Strict-Transport-Security': 'max-age=31536000; includeSubDomains', 'Content-Security-Policy': - `default-src 'self'; script-src 'self' https://crawlproof.com; style-src 'self' 'nonce-${res.locals.nonce}'; img-src 'self' data:; font-src 'self'; connect-src 'self' https://crawlproof.com; object-src 'none'; base-uri 'none'; frame-ancestors 'none'; form-action 'self'`, + `default-src 'self'; script-src 'self' https://crawlproof.com; style-src 'self' 'nonce-${res.locals.nonce}'; img-src 'self' data:; font-src 'self'; connect-src 'self' https://crawlproof.com; frame-src https://crawlproof.com; object-src 'none'; base-uri 'none'; frame-ancestors 'none'; form-action 'self'`, 'Permissions-Policy': 'camera=(), microphone=(), geolocation=(), interest-cohort=()', }); next(); diff --git a/src/site.mjs b/src/site.mjs index ce046f3..a383c2d 100644 --- a/src/site.mjs +++ b/src/site.mjs @@ -87,8 +87,25 @@ ${extraHead}
`; } +// One CrawlProof ad unit (slot 71955dcb, https://crawlproof.com/ads/slots) on +// every public page, above the footer. This site's CSP allows no inline style +// and only 'self' images, and ad.js renders into a srcdoc iframe that would +// inherit that policy, so it uses the script-free cross-origin frame instead: +// one frame-src entry, no third-party JS, nothing written to localStorage. +// text_link is the only fluid format (40px at any width, its own "Sponsored" +// mark), so it never crops on a phone and needs no viewport measurement. +export const AD_SLOT = '71955dcb-8cb9-46fe-8df5-e870d973a8e2'; +export const AD_FRAME_SRC = `https://crawlproof.com/api/ads/frame?slot=${AD_SLOT}&format=text_link`; + +export function adUnit() { + return ``; +} + export function foot() { - return `
+ return `${adUnit()} +