npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@wotaso/seo-blog-admin-cli

v0.2.2

Published

Secure CLI for SEO Drafts agents, projects, and publishing integrations.

Readme

SEO Blog Admin CLI

Tenant-side and admin CLI for SEO Blog Admin publishing integrations.

Use it from tenant repositories without copying local JavaScript files:

npx --yes @wotaso/[email protected] init-static --site-slug example --site-origin https://example.com --content-dir src/content/blog
npx --yes @wotaso/[email protected] publish-static
npx --yes @wotaso/[email protected] publish-cms --cms wordpress

Scoped agent API

Automation agents should use revocable sda_live_ tokens and the fixed /api/v1/agent/v1 surface. Agent secrets are never accepted as command-line arguments or printed. Verify and store a token through stdin:

printf '%s' "$SEO_BLOG_AGENT_TOKEN" |
  npx --yes @wotaso/[email protected] agent login --token-stdin

npx --yes @wotaso/[email protected] agent status
npx --yes @wotaso/[email protected] agent projects list
npx --yes @wotaso/[email protected] agent posts list --status pending_review --site-slug example
npx --yes @wotaso/[email protected] agent posts get 00000000-0000-4000-8000-000000000000 \
  --body-offset 0 --body-limit 60000
npx --yes @wotaso/[email protected] agent projects refresh-links example \
  --max-posts 3 --max-links-per-post 3

Owners and admins first sign in with a mobile session, then manage least-privilege tokens. Newly created secrets are stored in the user config (0600) by default and are shown only as a prefix:

npx --yes @wotaso/[email protected] login-password \
  --email [email protected] --password-stdin

npx --yes @wotaso/[email protected] agent tokens create \
  --label "content-review-agent" \
  --scopes projects:read,posts:read,posts:write,posts:approve \
  --projects example \
  --expires-in-days 30

npx --yes @wotaso/[email protected] agent tokens list
npx --yes @wotaso/[email protected] agent tokens revoke 00000000-0000-4000-8000-000000000000

Write and review commands take a bounded JSON object from a file or stdin. Include the API-returned expectedContentVersion and expectedStateVersion for post mutations; project-context writes require expectedContextVersion. The CLI never retries mutations because the API does not promise idempotency:

npx --yes @wotaso/[email protected] agent posts update "$POST_ID" --input update.json
npx --yes @wotaso/[email protected] agent posts schedule "$POST_ID" --input schedule.json
npx --yes @wotaso/[email protected] agent posts approve "$POST_ID" --input approval.json
npx --yes @wotaso/[email protected] agent posts check-publish "$POST_ID" --input versions.json
npx --yes @wotaso/[email protected] agent opportunities generate-review-draft "$OPPORTUNITY_ID"

posts get returns at most one explicitly requested Markdown chunk. Continue with the returned nextBodyOffset until it is null; if contentVersion or stateVersion changes between chunks, discard the partial body and reload from offset 0.

Content edits and scheduling are separate operations. posts update rejects scheduledAt; posts schedule accepts only the two expected versions plus a timestamp or null. Approval likewise rejects scheduling fields, clears any pre-existing automation schedule, and requires the approved version to be scheduled afterward.

Available read surfaces include projects, posts and revisions, opportunities, insights, integration health, billing, and the current token’s audit events. Write scopes cover project context, post import/update, separately scoped scheduling and approval, review-state changes, publish-health checks, opportunities, and qualified draft generation.

agent projects refresh-links discovers only links between already verified live posts. It changes no public page directly: bounded same-URL revisions enter the normal review queue, preserve the prior live snapshot for decline/rollback, and publish only after explicit approval and scheduling.

Publisher config and egress safety

New seo-blog.config.json files contain "version": 1; legacy files without a version are read as version 1. Every field is runtime validated and unknown fields fail closed. Post slugs and locales are validated before path construction, writes must remain below the configured content/asset root, and existing symlinks are never traversed.

Repository config cannot freely choose a secret variable or an arbitrary CMS destination:

  • Provider credentials use fixed names such as WORDPRESS_APP_PASSWORD and WEBFLOW_TOKEN.
  • Additional names must be explicitly listed in SEO_BLOG_CMS_ALLOWED_SECRET_ENVS.
  • A CMS endpoint read from repo config must match SEO_BLOG_CMS_ALLOWED_HOSTS.
  • CMS responses, social-card downloads, and deployment confirmations have timeouts, response limits, bounded redirects, and private-address checks.
  • HTTPS is required. Loopback/private network, custom egress, custom secret names, and writes outside the current repository require explicit local environment opt-ins and are refused when CI=true or in GitHub Actions.

Local-only exceptions are SEO_BLOG_ALLOW_PRIVATE_NETWORK=true, SEO_BLOG_ALLOW_CUSTOM_EGRESS=true, SEO_BLOG_ALLOW_CUSTOM_SECRET_ENVS=true, and SEO_BLOG_ALLOW_OUTSIDE_WORKSPACE=true. Do not set them in shared runners.

Publisher health check

Run the check inside the tenant website repository:

SEO_BLOG_PUBLISH_TOKEN=... npx --yes @wotaso/[email protected] health

It validates the checked-in publisher config, tenant token, canonical project identity, output route, and the real daily runner. The generated GitHub Actions workflow runs this check before every publish pull. A manual local run is useful for diagnosis, but the project only receives a green daily-runner check after a successful CI heartbeat. The heartbeat expires after 36 hours, so a missing daily job becomes visible without creating a synthetic test post.

For a CMS or tenant server cron, invoke the same command from the scheduled environment:

SEO_BLOG_SCHEDULED=true npx --yes @wotaso/[email protected] health --mode cms

Provider credentials and the publish token remain in that runner's secret store. The command reports only whether expected environment variables exist, never their values.

For static hosts behind Cloudflare, publish-static writes a temporary publish-result manifest. Run cache revalidation only after the host deployment has started. The command waits for cache-busted article URLs to become reachable, purges only the article route variants plus the blog index and discovery files, and warms those URLs again:

SEO_BLOG_PUBLISH_TOKEN=... \
  npx --yes @wotaso/[email protected] cache-revalidate --if-configured

The preferred path uses the project’s Cloudflare OAuth connection and existing publisher token, so website repositories do not need Cloudflare credentials. --if-configured keeps publishing green until the project connection exists. A zone-scoped CLOUDFLARE_API_TOKEN plus CLOUDFLARE_ZONE_ID remains available as an advanced fallback. Neither path clears the full zone.

Admin/setup agents can log in and rotate a tenant-scoped publish token directly into GitHub Actions secrets:

npx --yes @wotaso/[email protected] login-password \
  --email [email protected] \
  --password-stdin

npx --yes @wotaso/[email protected] rotate-token flashes \
  --repo Wotaso/Flashes-Website

Projects can always be created and remain stored without consuming weekly capacity. Allocate exact weekly counts per language market; setting every count to zero pauses generation without deleting data:

npx --yes @wotaso/[email protected] create-project https://example.com
npx --yes @wotaso/[email protected] activate-project example
npx --yes @wotaso/[email protected] pause-project example
npx --yes @wotaso/[email protected] set-locales example --locales de-DE:DE,en-US:US
npx --yes @wotaso/[email protected] set-weekly-allocation example --allocation de-DE:DE=5,en-US:US=2
npx --yes @wotaso/[email protected] set-image-style example \
  --background-color '#0E1021' \
  --text-color '#F7F7F5' \
  --primary-color '#B6FF5C'

The image palette is project-scoped. Text and background must meet a 4.5:1 contrast ratio; generated hero images ask the image model itself to render one short article headline in these colors.

Free workspaces include two review-ready drafts per calendar month and one project. Paid workspaces choose one shared allowance from 1 to 30 posts or pages per week. The monthly price is EUR 13 for the core workspace, plus EUR 6 per weekly slot, plus EUR 4 per active project above the first.

Active-project capacity unlocks with the selected weekly allowance: 1–5 slots include one project, 6–9 include two, 10–14 include three, 15–19 include four, 20–24 include five, 25–29 include six, and 30 includes seven. Projects with no allocation stay paused. Content languages do not cost extra, but every generated language version uses one shared weekly slot.

Publish tokens belong only in CI, server-side jobs, or CMS secret stores. Do not place them in browser bundles, mobile apps, public files, or committed environment files.

Native CMS providers include WordPress, Webflow, Wix, Contentful, Sanity, Strapi, Ghost, Shopify, and HubSpot. Framer Server API publishing is available as beta on Node.js 22+.

FRAMER_API_KEY=... FRAMER_PROJECT_URL=... FRAMER_COLLECTION=Blog \
  npx --yes @wotaso/[email protected] publish-cms --cms framer

WIX_API_KEY=... WIX_SITE_ID=... WIX_MEMBER_ID=... \
  npx --yes @wotaso/[email protected] publish-cms --cms wix

Squarespace uses the reviewed Markdown/HTML export or signed-webhook path because its public APIs do not expose general blog-post publishing. Never store CMS credentials in seo-blog.config.json.