Open-Source Cold Email & Warmup Platform
Warmbly 是开源的冷邮件平台:温暖您的邮箱、发送活动、并对每条回复进行分流。可在我们的云端运行,也可自行托管整套系统。
AI 翻译
Others give you a score. AgentScope shows why AI agents don't buy from your WooCommerce store, fixes it with your approval, and proves it with real AI-referred orders.
翻译准备中
营销GitHub @mehdilammm在线运营者未确认
试用过了吗? 点一下就好,无需登录。
尚未收集仓库信息。
尚未检测到更新。GitHub 发布版本后会显示在这里。
制作者的介绍仅有上面的一句话。 更多详情请阅读仓库 README。 仓库 README ↗
正在加载完整 README。
查看完整 README ↗Checks whether WooCommerce stores are ready for AI shopping agents. Loop: evidence → specific fix → rescan → history.
Stack: Next.js (App Router, TypeScript), Supabase (Auth + Postgres), Vercel.
npm install.env.example to .env.local and fill it in:
NEXT_PUBLIC_SUPABASE_URL, NEXT_PUBLIC_SUPABASE_PUBLISHABLE_KEY (public)SUPABASE_SERVICE_ROLE_KEY (server only)ADMIN_EMAILS (optional): who may open /api/healthnpm run devOn Vercel, set the same variables. /api/health (signed in) shows whether each is set and whether the service role key works, without showing values. In Supabase Auth → URL Configuration, add the site URL and <site>/auth/confirm as a redirect URL.
stores: owned by the user, written with the user's session (RLS).store_credentials keeps only the Vault secret ids and a key hint. They are written and read through save_store_credentials / get_store_credentials (security definer, executable only by the service role). Never sent to the browser. If saving fails, the new store is removed.POST /api/stores/:id/scan: checks ownership, reads published products from /wp-json/wc/v3/products (100 per page, up to 50 pages) and the variations of variable products, applies lib/rules.ts, and saves the scan and findings with the service role./wc/v3/settings/products and /advanced, basis observed) and are checked against the public /wp/v2/pages list. WooCommerce does not expose the Privacy or Returns page setting to API keys, so those are found by title or address among published pages (basis heuristic). When the key or site does not allow a read, the finding has basis unavailable with the reason; nothing is guessed.connection_status becomes connected, or error with connection_error./api/stores/:id/report.csv, formula-injection safe) and scan history.type:product_id). States: new, ongoing (in the previous complete scan), recurred (seen earlier but not in the previous scan). resolved is shown on the findings page: in the previous scan, gone now.npm test: product rules, store pages, connection status, CSV, history and URL testsnpm run typecheck, npm run buildMigrations live in supabase/migrations.
lib/feed.ts): product data against the required fields of OpenAI's product feed
(spec): title, description, url, brand, availability,
seller_name, currency; GTIN check digit; low note when there is neither GTIN nor MPN. Image and price come from the product rules.lib/access.ts): home page and two product pages loaded as a browser and as GPTBot, OAI-SearchBot, ChatGPT-User,
ClaudeBot and PerplexityBot (10 requests, one at a time). User agent only, so findings are heuristic.lib/robots.ts, lib/structured-data.ts): robots.txt per bot and Sitemap line, JSON-LD Product compared
with the API, llms.txt as information only./api/ingest/traffic, lib/traffic.ts): signed daily totals from the agentscope-core plugin
(wordpress/agentscope-core/, v1.1.0; zip at public/downloads/agentscope-core-1.1.0.zip).vercel.json, /api/cron/weekly-scans): runs daily, scans stores whose last complete scan is 7+ days old,
at most one scheduled scan per store per day. Needs CRON_SECRET in Vercel.lib/email.ts renders the weekly email as text. Nothing sends it until a provider is chosen. Options (check current prices):
| Provider | Free tier | Paid |
|---|---|---|
| Resend | 3,000 emails/month, 100/day | from about $20/month |
| Brevo | 300 emails/day | from about $9/month |
| Postmark | 100 emails/month | from about $15/month |
| Amazon SES | none after the first year | about $0.10 per 1,000 emails, more setup |
All need a verified sending domain (DNS records).
visibility_prompts, owner-managed with RLS). "Suggest 5 questions" builds them from the
store's biggest product categories and country; nothing is saved until the user ticks them.lib/gemini.ts, default gemini-3.5-flash-lite, override with
GEMINI_MODEL), one at a time, 25 s timeout, one retry on 429/5xx. Google Search grounding is off: it is not in the
free tier for this model and is billed per search on paid tiers.visibility_runs.visibility_results) with: mentioned or not (text match), rank in the answer's list,
other shops named and links. Shop names come from a second small structured-output request to the same model
(EXTRACTION_SCHEMA), filtered for labels; if it fails, a text heuristic is used (extraction column says which).
Tokens of both requests are counted. Labelled "Gemini API answer, not the Gemini app"./check lets anyone check a store's public side; reports live at /check/<random id> for 30 days. /bot explains
AgentScopeBot and how to block it.
AgentScopeBot/1.0, header
X-AgentScope-Check: 1; if robots.txt blocks AgentScopeBot, only robots.txt is read.public_reports, public_scan_limits, public_gemini_usage: server only (RLS, no policies).shopify_waitlist, server only, nothing sent).Request order in the public check (the 10-request limit drops the last ones first): robots.txt → home page → Shopify /products.json or a product sitemap → product page 1 → GPTBot → ClaudeBot → PerplexityBot → OAI-SearchBot → llms.txt → product page 2. A same-site redirect on the first request (example.com → www.example.com) is learned and later requests go straight to the final host. Anything not requested is "not checked: request limit" (unavailable), never a finding, and the report lists every step with its result.
Product data on product pages: JSON-LD Product or ProductGroup (variants via hasVariant, lowest price), @graph, arrays, several scripts, AggregateOffer (lowPrice) and ImageObject; products inside ItemList are ignored. A product whose fields cannot be read is "could not parse" (unavailable), not "incomplete". The price shown is read only from the main product area (installment / "per month" amounts, cart, banners and recommendations ignored), else og:price:amount; unknown otherwise. On Shopify, the JSON-LD price is compared with the /products.json price of the same handle when available.
lib/mistral.ts: chat completions, default mistral-medium-latest (override MISTRAL_MODEL), one request at a time,
one retry on 429/5xx. Docs: https://docs.mistral.ai/api, structured output:
https://docs.mistral.ai/capabilities/structured_output/customresponse_format: json_schema; if that fails, Gemini does. visibility_results.engine,
model, extractor and requests record who answered, who extracted and the requests used. A refused key or an
exhausted free plan stops the Mistral lane; Gemini continues and Mistral rows say why.public_mistral_usage budget). Labelled "Mistral API answer, not the Le Chat app".Retry-After (2 s if missing, max 10 s) and retries once; the wait is shown in the report. A 429 on Mistral's
extraction falls back to Gemini extraction. Separate serverless instances have separate queues./product/ page: one request to the public Store API
/wp-json/wc/store/v1/products?per_page=10 (price 0, sale not lower, no images, short description). The first
permalink is checked for JSON-LD and its price compared with the Store API. 401/404 = not available, no finding.MISTRAL_ENABLED=true (the free plan does not activate API keys). The UI says
"Not connected: requires a paid Mistral plan" and no request is sent.lib/task-models.ts: internal tasks only (reading names out of answers, the topic of the general question in /check).
Chain: Groq (openai/gpt-oss-20b, GROQ_MODEL) → NVIDIA build.nvidia.com (openai/gpt-oss-20b; meta/llama-3.1-8b-instruct is end of life,
NVIDIA_MODEL, testing-use key, fallback only) → Gemini → heuristic. Each: 20 s timeout, one retry on 429 with
Retry-After, invalid JSON or failed validation moves on. GROQ_ENABLED / NVIDIA_ENABLED (default true) turn
each off; turn NVIDIA off before paying customers.visibility_results.extractor accepts groq and nvidia (migration 20261022090000_task_model_extractor.sql).json_validate_failed (gpt-oss sometimes drops a required field): the failed_generation text is checked by
our own validation instead of being thrown away. A 404/410 model answer says "Set GROQ_MODEL/NVIDIA_MODEL" and the
chain moves on.lib/profile.ts, AI Visibility → Brand profile): for each Gemini answer that names someone, the task
chain (Groq → NVIDIA → Gemini) reads the tone (positive / neutral / negative), a short description and the features
given to the store and to each named competitor. "Mentioned" stays the text match; competitors must be names the
extraction found; features are kept only when their words are in the answer. Stored in visibility_results.profile.lib/share-of-voice.ts, AI Visibility → Share of voice): per weekly run, "named in X of Y
questions" for the store and every name the Gemini answers give instead, a ranking, and the history run by run.
Questions without an answer are counted apart. No score.lib/question-suggest.ts): up to 30 best-selling products (name, price, categories) from the
WooCommerce API → the task chain writes 15 shopper questions (buy, compare, "best X for Y", "where to buy X") in
English, French or Arabic, without the store's name. The user ticks and edits them before saving. Fallback:
category templates, labelled HEURISTIC.lib/workspace.ts, Settings → Workspaces): a workspace holds stores and members (owner / admin
/ viewer). Existing stores were moved into their owner's personal workspace. RLS: members read everything of their
workspaces' stores; owners and admins add, change, run and delete; viewers only read. Role helpers live in the
non-exposed private schema. Invites are single-use links valid 7 days (only a SHA-256 of the token is stored; an
optional email must match on accept). Keys and traffic tokens stay under the store's creator, server-only.lib/grounding.ts, AI Visibility → Citations): with GEMINI_GROUNDING_ENABLED=true (default false) the
questions go to Gemini with the google_search tool; groundingMetadata (sources, domains, which part of the answer
relied on which source, the searches, Google's search suggestions) is stored per answer. The page shows the most
cited domains, whether the store's site is among them, and which named competitors have citations. Hard cap in code:
1000 grounded requests per month app-wide (grounding_reserve), far below the 5,000 free grounded prompts per month
of Gemini 3 models (paid tier only; then $14 per 1,000: https://ai.google.dev/gemini-api/docs/pricing). Above the cap
questions are asked without Google Search.GEMINI_GROUNDING_MODEL (default gemini-2.5-flash; Flash-Lite
has no grounding on the free tier); everything else stays on GEMINI_MODEL. Caps: 50 per day and 1000 per month
app-wide (). If Google refuses grounding (free tier, 400, 403, 429), the reason is stored
word for word, Citations show UNAVAILABLE with it, and the question is asked again without grounding.lib/site.ts: product name, site URL, contact email (placeholder) and legal date in one place.lib/plans.ts: Free / Pro ($29) / Agency ($49) with their limits, used by /pricing (and later by enforcement).
Paid plans collect a waitlist (plan_waitlist, server only, RLS without policies)./ is a landing page for visitors (signed-in users go to /stores); /pricing, /terms, /privacy are public.
Sign up needs the "I agree to the Terms and the Privacy Policy" box./downloads/agentscope-core-1.2.1.zip): "Clear test data" can be repeated and can clear one
chosen day (UTC), with the same confirmation.lib/seo.ts): title template and meta description, Open Graph and Twitter card with a generated image
(app/opengraph-image.tsx), canonical URLs, /sitemap.xml (public pages only), /robots.txt (AI bots named and
allowed on public pages; the app, API and invites kept out), SoftwareApplication JSON-LD on / with the real plan
prices and no rating or reviews.node scripts/build-plugin.mjs builds public/downloads/agentscope-core-<v>.zip
and writes lib/plugin-release.json (version, SHA-256, changelog); /api/plugin/latest serves it publicly.
agentscope-core 1.3.0 checks that endpoint once a day (no store data sent), shows the update in WordPress and
verifies the zip's SHA-256 before installing. readme.txt follows the WordPress.org format with an External
services section; for a WordPress.org build, leave includes/class-agsc-updater.php out of the zip.grounding_reserve_cappedALTER POLICY ... false, migration 20261022141000); DROP needs an
interactive confirmation the migration tool could not get./api/health shows grounding.enabled, the flag as read, the model and today's / this month's usage.
"Re-run with citations (test)" (workspace owner, grounding on): skips the weekly wait, at most 3 runs per store a
day, grounding caps still apply, stored as a normal run.wordpress/agentscope-core, download /downloads/agentscope-core-1.1.0.zip): every
AgentScope request to a store (full scan, including the bot user agents, and /check) carries X-AgentScope-Check
(lib/check-header.ts): v1.<ts>.<HMAC-SHA256(connection token, "agentscope-check.<ts>")> when the store has a
traffic connection, else 1. The plugin skips those requests; with a token it accepts only fresh signed values.
The app connection is built into the plugin's Settings (connection code, Connect, Send now, last send), and
"Clear test data" sets pre-1.1.0 totals to 0 after confirmation and resends them. Rebuild the zip with
cd wordpress && zip -rqX ../public/downloads/agentscope-core-1.1.0.zip agentscope-core./downloads/agentscope-core-1.2.0.zip): burst detection (HEURISTIC, class-agsc-burst.php).
Within 60 seconds, 3+ different AI sources, or 5+ AI bot requests with 3+ bot names, are recorded as
likely-checker-tool (the burst's earlier requests are moved too). The plugin and the app's AI Traffic page show
them apart ("Probably an SEO/GEO checker tool, not real AI traffic") and leave them out of the main numbers.