Skip to content

Add Ghost platform detection and capture cleanup - #481

Open
pmaiorana wants to merge 4 commits into
mainfrom
feat/ghost-adapter
Open

pmaiorana wants to merge 4 commits into
mainfrom
feat/ghost-adapter

Conversation

@pmaiorana

@pmaiorana pmaiorana commented Sep 30, 2026 •

Copy link
Copy Markdown
Contributor

Summary

Adds Ghost as a supported platform: it recognizes Ghost sites, and cleans Ghost-only pieces out of the copy.

How Ghost sites are recognized

  • A *.ghost.io address, or the ghost-fastly header that Ghost's hosting sends.
  • For self-hosted sites: the "Ghost" generator tag, or Ghost's member and search scripts.
  • As a last resort: /ghost/ redirecting to a *.ghost.io admin.

Ghost's image paths and editor class names are not used as signals. Sites that only pull content from Ghost (a Next.js front end, for example) use them too, and those pages aren't Ghost-built.

What changes in the copy

  • The "Powered by Ghost" / "Published with Ghost" footer credit is removed.
  • Ghost's members popup and search are removed. The floating Subscribe button was a frame of the live site, so the copy kept loading the source.
  • Sign in, Subscribe and Share buttons stay, but their links point to #. They only worked with Ghost's servers.

It also teaches the shared credit remover the phrase "Published with", which is how some Ghost themes word the credit.

Testing

  • 14 real Ghost sites, hosted and self-hosted: all recognized. A headless Ghost site (buffer.com/resources) and non-Ghost sites are not.
  • Credit removal tested against four real theme footers.
  • Full capture of demo.ghost.io: credit gone, post text intact, no frames of the live site. compare's link checks pass on all 32 pages.
  • compare still reports animation differences and a YouTube embed loading YouTube. Those aren't specific to this adapter.
  • npx vitest run and tsc --noEmit pass.

🤖 Generated with Claude Code

pmaiorana and others added 3 commits September 29, 2026 17:26
Thin adapter on the Platform API: Ghost-owned detection signals, the
default discovery (Ghost serves a standard sitemap index), and removal of
the "Powered by / Published with Ghost" footer credit.

Signals (verified on 14 live Ghost sites):
- URL: *.ghost.io (Ghost(Pro) subdomains).
- Header: ghost-fastly (Ghost(Pro) CDN).
- Source: Ghost generator meta; Portal / Search assets from
  cdn.jsdelivr.net/ghost/ (self-hosted installs).
- Probe: /ghost/ redirecting to <site>.ghost.io/ghost (Ghost(Pro) custom
  domains with a stripped theme head).
/content/images/ and Koenig kg-* classes are deliberately not signals:
headless front ends reading Ghost's Content API emit them too.

Cleanup uses only the link-based credit rule. The shared plain-text rule
scans <body>, and on demo.ghost.io/design/ it deleted "created with Ghost"
from post prose ("new sites are created with Ghost's friendly theme").

The shared credit phrase list gains "published with", Ghost's own
phrasing (aftermath.site).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Portal's floating "Subscribe" trigger is an iframe whose src is the live
site, so the captured copy framed the source origin (compare: "copy
requested demo.ghost.io, cdn.jsdelivr.net, storage.ghost.io"). Portal and
Sodo Search render into #ghost-portal-root / #sodo-search-root at runtime
and can't work without Ghost's members/search APIs.

Verified on a full demo.ghost.io capture: neither root remains, and those
external requests are gone from compare.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Theme Sign in / Subscribe / Share controls link to Portal hash routes
(#/portal/signup, #/portal/signin, #/share) that only resolve while Portal
runs against Ghost's members API. In the copy they pointed at anchors that
don't exist, failing compare's self-consistency check on every route.

Before serialize, same-site links into those routes become href="#": the
control keeps its place and styling, only the dead action goes (the same
treatment the pipeline gives javascript: links). Links to other sites and
ordinary in-page anchors are untouched.

demo.ghost.io: self-consistency findings 93 -> 0 across 32 routes.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

@chubes4 chubes4 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reviewed Ghost detection, builtin registration, provider-qualified credit cleanup and same-origin Portal/Share neutralization with their positive/negative browser tests. The adapter uses the existing generic discovery and cleanup contracts, preserves owner content and external links, and has a green exact-head package/build/test CI run plus the documented real Ghost corpus capture. No whole-site animation/YouTube parity claim is inferred. AI assistance: OpenAI gpt-6.1-sol via OpenCode performed source/CI review under Chris Huber’s batch-shipping authorization.

@chubes4

chubes4 commented Oct 6, 2026

Copy link
Copy Markdown
Contributor

Integrated current main preserving both Ghost and Substack detector tests. Main now identifies the headless fixture by its explicit Next.js header: the assertion proves Next.js adapter selection and separately proves Ghost content without that header stays unknown. All 96 focused detection/cleanup/browser checks pass; TypeScript build and installed/relocated package workflows pass. A local full-suite attempt exceeded the 20-minute bound and reported a portable-motion failure; full hosted exact-head CI must pass before landing. Release-owned dist is unchanged from main. AI assistance: OpenAI gpt-6.1-sol via OpenCode reviewed, integrated and verified the update.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants