@adgine/geo-cli 1.2.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (115) hide show
  1. package/README.md +93 -0
  2. package/bin/adgine-geo.js +224 -0
  3. package/package.json +38 -0
  4. package/skills/.env.example +11 -0
  5. package/skills/README.md +247 -0
  6. package/skills/SKILL.md +117 -0
  7. package/skills/VERSION +1 -0
  8. package/skills/adgine-geo-aiagent/SKILL.md +200 -0
  9. package/skills/adgine-geo-aiagent/scripts/_client.py +341 -0
  10. package/skills/adgine-geo-aiagent/scripts/bot_traffic.py +278 -0
  11. package/skills/adgine-geo-aiagent/scripts/human_traffic.py +357 -0
  12. package/skills/adgine-geo-aiagent/scripts/page_analytics.py +317 -0
  13. package/skills/adgine-geo-aiagent/scripts/page_detail.py +273 -0
  14. package/skills/adgine-geo-analytics/API.md +89 -0
  15. package/skills/adgine-geo-analytics/SKILL.md +191 -0
  16. package/skills/adgine-geo-analytics/scripts/_client.py +341 -0
  17. package/skills/adgine-geo-analytics/scripts/get_overview.py +129 -0
  18. package/skills/adgine-geo-billing/SKILL.md +118 -0
  19. package/skills/adgine-geo-billing/scripts/_client.py +341 -0
  20. package/skills/adgine-geo-billing/scripts/get_credits.py +51 -0
  21. package/skills/adgine-geo-billing/scripts/get_credits_pricing.py +52 -0
  22. package/skills/adgine-geo-billing/scripts/get_subscription.py +48 -0
  23. package/skills/adgine-geo-billing/scripts/list_plans.py +66 -0
  24. package/skills/adgine-geo-brand/SKILL.md +193 -0
  25. package/skills/adgine-geo-brand/WORKFLOW.md +66 -0
  26. package/skills/adgine-geo-brand/scripts/_client.py +341 -0
  27. package/skills/adgine-geo-brand/scripts/generate_brand.py +95 -0
  28. package/skills/adgine-geo-brand/scripts/get_brand.py +67 -0
  29. package/skills/adgine-geo-brand/scripts/list_jobs.py +153 -0
  30. package/skills/adgine-geo-brand/scripts/update_brand.py +61 -0
  31. package/skills/adgine-geo-citation/SKILL.md +220 -0
  32. package/skills/adgine-geo-citation/scripts/_client.py +341 -0
  33. package/skills/adgine-geo-citation/scripts/create_tests.py +62 -0
  34. package/skills/adgine-geo-citation/scripts/get_aggregate.py +108 -0
  35. package/skills/adgine-geo-citation/scripts/get_results.py +179 -0
  36. package/skills/adgine-geo-content/SKILL.md +224 -0
  37. package/skills/adgine-geo-content/WORKFLOW.md +100 -0
  38. package/skills/adgine-geo-content/scripts/_client.py +341 -0
  39. package/skills/adgine-geo-content/scripts/generate_article.py +108 -0
  40. package/skills/adgine-geo-content/scripts/generate_outline.py +113 -0
  41. package/skills/adgine-geo-content/scripts/generate_titles.py +51 -0
  42. package/skills/adgine-geo-content/scripts/list_content.py +65 -0
  43. package/skills/adgine-geo-content/scripts/manage_content.py +90 -0
  44. package/skills/adgine-geo-content/scripts/manage_jobs.py +184 -0
  45. package/skills/adgine-geo-dashboard/SKILL.md +181 -0
  46. package/skills/adgine-geo-dashboard/scripts/_client.py +341 -0
  47. package/skills/adgine-geo-dashboard/scripts/check_integrations.py +139 -0
  48. package/skills/adgine-geo-dashboard/scripts/get_overview.py +155 -0
  49. package/skills/adgine-geo-dashboard/scripts/get_visibility_overview.py +93 -0
  50. package/skills/adgine-geo-docs/SKILL.md +60 -0
  51. package/skills/adgine-geo-domains/SKILL.md +223 -0
  52. package/skills/adgine-geo-domains/scripts/_client.py +341 -0
  53. package/skills/adgine-geo-domains/scripts/get_domain.py +75 -0
  54. package/skills/adgine-geo-domains/scripts/list_domains.py +66 -0
  55. package/skills/adgine-geo-domains/scripts/search_domains.py +85 -0
  56. package/skills/adgine-geo-integrations/SKILL.md +188 -0
  57. package/skills/adgine-geo-integrations/scripts/_client.py +341 -0
  58. package/skills/adgine-geo-integrations/scripts/cloudflare_connect.py +155 -0
  59. package/skills/adgine-geo-integrations/scripts/cloudflare_worker.py +212 -0
  60. package/skills/adgine-geo-integrations/scripts/ga4_data.py +192 -0
  61. package/skills/adgine-geo-integrations/scripts/ga4_setup.py +120 -0
  62. package/skills/adgine-geo-opportunities/SKILL.md +162 -0
  63. package/skills/adgine-geo-opportunities/scripts/_client.py +341 -0
  64. package/skills/adgine-geo-opportunities/scripts/get_opportunity.py +90 -0
  65. package/skills/adgine-geo-opportunities/scripts/list_opportunities.py +92 -0
  66. package/skills/adgine-geo-performance/SKILL.md +177 -0
  67. package/skills/adgine-geo-performance/scripts/_client.py +341 -0
  68. package/skills/adgine-geo-performance/scripts/analyze_page.py +100 -0
  69. package/skills/adgine-geo-projects/SKILL.md +279 -0
  70. package/skills/adgine-geo-projects/scripts/_client.py +341 -0
  71. package/skills/adgine-geo-projects/scripts/check_auth.py +45 -0
  72. package/skills/adgine-geo-projects/scripts/list_projects.py +47 -0
  73. package/skills/adgine-geo-projects/scripts/manage_competitors.py +122 -0
  74. package/skills/adgine-geo-projects/scripts/manage_project.py +88 -0
  75. package/skills/adgine-geo-saas/SKILL.md +144 -0
  76. package/skills/adgine-geo-saas/scripts/_client.py +341 -0
  77. package/skills/adgine-geo-saas/scripts/check_domain.py +43 -0
  78. package/skills/adgine-geo-saas/scripts/create_website.py +56 -0
  79. package/skills/adgine-geo-saas/scripts/get_task.py +94 -0
  80. package/skills/adgine-geo-site-audit/README.md +281 -0
  81. package/skills/adgine-geo-site-audit/SKILL.md +449 -0
  82. package/skills/adgine-geo-site-audit/requirements.txt +5 -0
  83. package/skills/adgine-geo-site-audit/scripts/_client.py +341 -0
  84. package/skills/adgine-geo-site-audit/scripts/_geo_notice.py +55 -0
  85. package/skills/adgine-geo-site-audit/scripts/export_skill_package.py +197 -0
  86. package/skills/adgine-geo-site-audit/scripts/geo_collect.py +2443 -0
  87. package/skills/adgine-geo-site-audit/scripts/geo_score.py +490 -0
  88. package/skills/adgine-geo-site-audit/scripts/geo_timing.py +399 -0
  89. package/skills/adgine-geo-site-audit/scripts/geo_visibility.py +718 -0
  90. package/skills/adgine-geo-site-audit/scripts/render_report_pdf.py +1502 -0
  91. package/skills/adgine-geo-topics/SKILL.md +232 -0
  92. package/skills/adgine-geo-topics/scripts/_client.py +341 -0
  93. package/skills/adgine-geo-topics/scripts/generate_prompts.py +140 -0
  94. package/skills/adgine-geo-topics/scripts/manage_prompts.py +153 -0
  95. package/skills/adgine-geo-topics/scripts/manage_topics.py +145 -0
  96. package/skills/adgine-geo-visibility/SKILL.md +168 -0
  97. package/skills/adgine-geo-visibility/scripts/_client.py +341 -0
  98. package/skills/adgine-geo-visibility/scripts/get_execution.py +151 -0
  99. package/skills/adgine-geo-visibility/scripts/get_matrix.py +111 -0
  100. package/skills/adgine-geo-visibility/scripts/get_prompt_metrics.py +104 -0
  101. package/skills/adgine-geo-visibility/scripts/get_topic_metrics.py +201 -0
  102. package/skills/adgine-geo-visibility/scripts/get_visibility.py +166 -0
  103. package/skills/adgine-geo-wordpress/SKILL.md +151 -0
  104. package/skills/adgine-geo-wordpress/scripts/_client.py +341 -0
  105. package/skills/adgine-geo-wordpress/scripts/list_publishable.py +62 -0
  106. package/skills/adgine-geo-wordpress/scripts/manage_credentials.py +139 -0
  107. package/skills/adgine-geo-wordpress/scripts/manage_publishes.py +108 -0
  108. package/skills/adgine-geo-wordpress/scripts/publish.py +79 -0
  109. package/skills/scripts/check_version.py +290 -0
  110. package/skills/setup.py +248 -0
  111. package/src/config.js +126 -0
  112. package/src/doctor.js +137 -0
  113. package/src/install.js +90 -0
  114. package/src/manifest.js +99 -0
  115. package/src/runner.js +159 -0
@@ -0,0 +1,449 @@
1
+ ---
2
+ name: adgine/geo-site-audit
3
+ description: Standalone GEO technical audit for arbitrary public URLs — crawls the
4
+ site locally, scores it against a 5-dimension 30-item GEO checklist, and exports
5
+ a PDF report. Does NOT require GEO_API_KEY. NOT for measuring whether AI platforms
6
+ actually cite your brand (use adgine-geo-citation for that). NOT for platform
7
+ project analytics (use adgine-geo-analytics / adgine-geo-visibility). Use when
8
+ the user wants a one-off structural/technical GEO audit of any public website,
9
+ GEO 评分, GEO 检测, audit a URL, 网站结构检测, 技术审计, or export a GEO PDF report.
10
+ ---
11
+
12
+ # Adgine GEO Site Audit
13
+
14
+ > 对任意公开网站执行新版 GEO(Generative Engine Optimization)审计。默认报告按评估表格输出 5 大项、30 个压缩检测项和 GEO 总分;AI 可见性/引用性采样是可选附加测试,不参与 GEO 总分。
15
+
16
+ ## 前置依赖(首次使用前必须执行)
17
+
18
+ 本 skill 不需要 GEO_API_KEY,但需要额外 Python 包。首次使用前运行:
19
+
20
+ ```bash
21
+ pip install -r adgine-geo-site-audit/requirements.txt
22
+ ```
23
+
24
+ 或手动安装核心依赖:
25
+
26
+ ```bash
27
+ pip install curl_cffi beautifulsoup4 lxml markdown reportlab
28
+ ```
29
+
30
+ > 如果脚本运行时报 `ImportError`,说明依赖未安装,请执行上述命令。
31
+
32
+ ---
33
+
34
+ ## 触发条件
35
+
36
+ 当用户说出以下意图时使用本 skill:
37
+ - “审计 xxx.com” / “检测 xxx.com” / “audit xxx.com”
38
+ - “GEO 检测” / “GEO audit” / “GEO 评分”
39
+ - “分析网站 SEO/GEO 状况” / “网站结构检测” / “技术审计”
40
+ - “导出 PDF” / “生成审计报告”
41
+
42
+ **⛔ 以下意图不属于本 skill,请路由到对应 skill:**
43
+ - “AI 有没有引用我” / “测试 AI 是否引用我的品牌” / “运行引用测试” → **adgine-geo-citation**
44
+ - “我的 AI 可见性得分” / “Visibility Score” / “Share of Voice” → **adgine-geo-visibility**
45
+ - “AI 爬虫来了多少次” / “哪些 AI bot 爬了我的网站” → **adgine-geo-aiagent**
46
+ - “某个页面的健康分” / “某个页面的 AI 优化状态” → **adgine-geo-performance**
47
+
48
+ **路由边界**:
49
+ - 本 skill 面向**任意公开 URL** 的一次性站点技术审计,无需平台账号,依赖 `scripts/geo_collect.py` 本地采集公开网页信号并打分。
50
+ - 本 skill 的「AI 可读性采样」是**结构层面检测**(页面内容是否对 AI 爬虫可读),不等于向 ChatGPT/Perplexity 发送 prompt 测试实际引用结果——后者请用 **adgine-geo-citation**。
51
+ - 平台项目、GA4/Cloudflare 集成、AI traffic、billing、WordPress 发布等 Adgine 产品内数据,应交给对应平台技能处理。
52
+
53
+ ## 执行流程
54
+
55
+ ### Step 1: 采集公开站点信号
56
+
57
+ 运行:
58
+
59
+ ```bash
60
+ python <SKILL_DIR>/scripts/geo_collect.py <URL> --max-subpages 20 --concurrency 6 --output <TEMP_DIR>/geo_audit_signals.json
61
+ ```
62
+
63
+ 若脚本依赖缺失,先安装:
64
+
65
+ ```bash
66
+ pip install -r adgine-geo-site-audit/requirements.txt
67
+ ```
68
+
69
+ **跨平台路径要求**:
70
+ - `<TEMP_DIR>` 使用 Python `tempfile.gettempdir()` 对应目录;macOS/Linux 通常是 `/tmp`,Windows 通常是 `%TEMP%`。
71
+ - Windows 命令行可使用 `py` 替代 `python`。
72
+
73
+ **抽样页面优先级**:
74
+ - 首页 / 规范入口由采集器单独抓取,不重复占用 sitemap 子页抽样名额。
75
+ - sitemap 存在时从 sitemap URL 中抽样;若 sitemap 不存在或没有可用页面 URL,则从首页同域链接中提取候选页再抽样。
76
+ - 子页抽样按 GEO 优先级选择:核心转化页、核心信任页、核心引用页、关键模板页、技术入口页、高风险验证页。
77
+ - 核心转化页包括 product、service、course、solution、feature、pricing、app-download、signup、活动页。
78
+ - 核心信任页包括 about、contact、company、support、privacy、terms、risk、security、regulatory、reviews。
79
+ - 核心引用页包括 guides、docs、help、FAQ、comparison、blog、glossary、resources、内容详情页。
80
+ - 关键模板页要求每种重要残余页面模板至少抽 1 个;fallback、synthetic 404、疑似污染 URL、bot blocked path 等高风险验证页最后补位。
81
+
82
+ ### Step 2: 读取采集结果
83
+
84
+ 读取 `<TEMP_DIR>/geo_audit_signals.json`,使用:
85
+ - `meta`: URL、domain、brand_query、采集时间、渲染方式、抽样页数、调试用阶段耗时
86
+ - `signals`: 程序化信号,按维度分组:
87
+ - D1: `d1_homepage_access`, `d1_robots`, `d1_sitemap`, `d1_ai_crawlers`, `d1_access_blocker`, `d1_indexability`, `d1_soft_404` 等
88
+ - D2: `d2_schema_coverage`, `d2_heading_structure`, `d2_information_architecture`, `d2_lang`, `d2_social_metadata` 等
89
+ - D3: `d3_brand_name`, `d3_trust_entries`, `d3_third_party`, `d3_knowledge_graph` 等
90
+ - D4: `d4_definition`, `d4_faq`, `d4_direct_answers`, `d4_comparison`, `d4_lists` 等
91
+ - D5: `d5_content_assets`(blog/资源/pricing/product 检测、转化页、外部平台), `d5_cta`(首页 CTA 关键词)
92
+ - `snippets`: 用于语义判断的正文片段、标题、schema、FAQ、案例、来源等
93
+ - `errors`: 采集错误
94
+
95
+ ### Step 2.5: 爬虫失败兜底
96
+
97
+ **触发条件**(任一即执行):
98
+ - `signals.d1_access_blocker.detected = true`
99
+ - 首页/robots/sitemap/llms.txt 返回 403/429
100
+ - 首页正文为安全验证页(Vercel/Cloudflare challenge 等)
101
+ - 首页正文极少且非目标网站真实内容
102
+
103
+ **兜底方式**:
104
+ 1. 必须优先尝试可用的外部/agent 搜索能力(WebFetch/浏览器/搜索引擎),查 `site:{domain} {brand}` 及核心页面
105
+ 2. 参考公开第三方平台(社媒、应用商店、监管资料、Wikipedia 等)补充语义判断
106
+ 3. 兜底来源标注"外部兜底信号",不伪装为 crawler 结果
107
+ 4. 无外部搜索能力时才说明"未执行"
108
+
109
+ **兜底约束**:
110
+ - D1(可达性/WAF/UA/robots/sitemap/indexability/渲染)以直接采集为准,兜底不更改
111
+ - D2-D5 参考外部兜底,写明证据来源
112
+ - 证据不足保留 WARN/FAIL/ERROR,不主观给 PASS
113
+ - 外部兜底信号不能把真实 crawler 阻断项改判为直接可达
114
+ - 不得输出“未使用外部搜索抵消 crawler 阻断”等无实质内容的占位说明
115
+
116
+ ### Step 3: 逐项判定 30 个压缩检测项
117
+
118
+ 检测项和权重的唯一事实源是 `scripts/geo_score.py` 中的 `DIMENSIONS` 配置。报告必须覆盖全部 30 项,不得用“核心发现”“主要问题”“...”替代明细表。
119
+
120
+ 5 大项如下:
121
+
122
+ | 评估维度 | 权重 | 子项数 | 评估重点 |
123
+ |---|---:|---:|---|
124
+ | 维度一:AI 可发现 | 25% | 7 | crawler 能否发现、访问、索引并抓取真实内容 |
125
+ | 维度二:AI 可理解 | 20% | 7 | 页面语义、结构、schema、多语言和元数据是否帮助机器理解 |
126
+ | 维度三:AI 可引用 | 20% | 5 | 内容是否可摘录、可回答、可验证、可作为 AI 答案来源 |
127
+ | 维度四:AI 可信任 | 20% | 5 | 品牌实体、信任页面、第三方验证和资质是否可靠 |
128
+ | 维度五:AI 可推荐 | 15% | 6 | 内容资产、意图覆盖、决策页和转化路径是否支持 AI 推荐 |
129
+
130
+ 状态必须使用:
131
+
132
+ | 状态 | 报告展示 | 系数 | 含义 |
133
+ |---|---|---:|---|
134
+ | PASS | ✅ PASS | 1.0 | 通过 |
135
+ | WARN | ⚠️ WARN | 逐项定义 | 待优化;每个压缩项按评估表中的待优化保留系数计分,常见为 20%、30%、40%、50%、60% |
136
+ | FAIL | ❌ FAIL | 0.0 | 不通过 |
137
+ | ERROR | 🔴 ERROR | 不计入分母 | 检测失败或证据不可得 |
138
+ | N/A | ➖ N/A | 不计入分母 | 业务模型不适用 |
139
+
140
+ 判定原则:
141
+ - 每个压缩项必须同时看 `score_rule`、`focus` 和 `detail`,不能只凭名称主观判定。
142
+ - 基础阻塞项优先看核心页/核心入口;若 1 个核心页或核心入口不通过,整项通常最高 `WARN`,若 2 个及以上不通过,整项通常 `FAIL`。
143
+ - 重要结构项可按页面平均,但核心页不通过时整项最高通常只能记 `WARN`。
144
+ - 增强项可按页面平均;确实不适用时用 `N/A`,不要用 `FAIL` 拉低总分。
145
+ - 证据不足时默认 `WARN`;关键证据缺失时不得给高分。
146
+
147
+ ### 特殊判定场景
148
+
149
+ #### 1.4 AI crawler 实际可访问性 — WAF/CDN 安全挑战阻断
150
+
151
+ 当 `signals.d1_ai_crawlers.all_waf_blocked` 为 `true` 时,表示采集器使用 Bot UA 的探测请求全部被 WAF/CDN 安全挑战拦截(如 Vercel `X-Vercel-Mitigated: challenge`、Cloudflare JS Challenge)。
152
+
153
+ **关键区分**:`curl_cffi` 探测工具仅模拟了 Bot UA 字符串,**不等于真实 AI 爬虫的行为**。真实的 Googlebot、GPTBot、ClaudeBot 等来自已验证 IP 范围、具备真实 TLS 指纹和行为模式,WAF 可能对其放行。因此探测被拦≠真实 AI 爬虫被拦。
154
+
155
+ - **判定**:该项判 **WARN**(存在 WAF 阻碍风险,但无证据确认 AI 爬虫不可达)。
156
+ - **note 必须包含**:
157
+ 1. WAF/CDN provider 名称(取自 `signals.d1_access_blocker.provider`)
158
+ 2. 探测结果:几个 Bot UA 被拦、返回什么状态码
159
+ 3. **必须写清**:`curl_cffi` 探测仅模拟了 Bot UA,不等于真实 AI 爬虫的行为结果
160
+ 4. 验证建议:在 Google Search Console / Bing Webmaster Tools 中确认真实爬虫的抓取状态
161
+ 5. 修复建议:将合法 AI 爬虫 UA 加入 WAF 白名单以消除风险
162
+
163
+ - **禁止**:仅凭探测被拦就直接断定"AI 爬虫完全无法抓取站点内容"或"AI 平台实际可达性为零"。
164
+ - **禁止**:将 1.4 的 WAF 风险扩散到 5.1——5.1 评估的是内容资产适配度而非物理可达性。
165
+
166
+ 当 `waf_blocked_count > 0` 但 `accessible_count > 0` 时(部分爬虫可达),该项通常也判 **WARN**。
167
+
168
+ 当 `all_waf_blocked` 为 `false` 且 `accessible_count` 为 0(非 WAF 原因导致的不可达),才判 **FAIL**。
169
+
170
+ #### 2.6 Schema 覆盖与实现质量 — @graph 格式 JSON-LD
171
+
172
+ `geo_collect.py` 已支持解析 `@graph` 包裹格式的 JSON-LD(Yoast SEO / RankMath / Next.js 常见输出)。判定时:
173
+
174
+ - **以 `signals.d2_schema_coverage.schema_types` 列表为准**,不要仅凭 `schema_type_count` 为 0 就下结论。
175
+ - 若 `schema_type_count > 0` 但关键类型缺失(如缺少 `WebSite`、`Article`/`BlogPosting`、`FAQPage`),按缺失程度判 **WARN**。
176
+ - 若 `schema_type_count == 0`(确认无任何 Schema),才判 **FAIL**。
177
+ - `has_website` 字段按 `"WebSite" in schema_types` 精确匹配;若察觉大小写变体以实际列表为准。
178
+
179
+ #### 5.1 平台适配与搜索意图覆盖 — 不得因 1.4 WAF 阻断而判 FAIL
180
+
181
+ 5.1 评估的是**站点是否具备适配 AI 平台(Google AI Overviews、ChatGPT、Perplexity 等)的内容资产与页面类型**(定义、比较、决策、操作、问题解决等意图覆盖),**不是物理可达性**。物理可达性已在 1.4 评估并通过跨维度封顶限制 D5。
182
+
183
+ - **禁止**:仅因 1.4 FAIL(AI crawler 被 WAF 拦截)就将 5.1 判为 FAIL。
184
+ - **正确做法**:基于 `signals.d2_information_architecture`、`signals.d4_*`(definition/comparison/faq/process)、外部兜底搜索等内容资产证据,独立评估内容适配度。若内容形态确实覆盖有限,判 WARN。
185
+
186
+ #### 5.3 首页导流与站内继续访问路径 — WAF 不影响子页抓取
187
+
188
+ 子页抽样使用 `DEFAULT_UA`(浏览器 UA + chrome impersonate),**不受 Bot UA 的 Vercel/Cloudflare WAF Challenge 影响**。若 `signals.d1_internal_discovery.internal_link_count > 0` 且页脚覆盖核心类别,不得以"WAF 限流未完整获取内链"为由降级。
189
+
190
+ #### 2.5 多语言表达一致性 — 需要实际信号证据
191
+
192
+ 判定依赖 `signals.d1_sitemap.has_hreflang` 和 `signals.d2_lang`(若可用)。如果采集信号显示 `has_hreflang: false` 且无多语言路径证据,默认判 **N/A**(单一语言站点,不适用)。仅当外部兜底搜索**确切发现**其他语言版本页面且与采集信号一致时,才可判 WARN 并明确标注证据来源。
193
+
194
+ ### Step 4: 计算 GEO 总分
195
+
196
+ 把每项判定整理为 assessment JSON,格式:
197
+
198
+ ```json
199
+ {
200
+ "items": {
201
+ "1.1": {"status": "PASS", "note": "HTTPS 可用,最终入口统一到 https://example.com/。"},
202
+ "1.2": {"status": "WARN", "note": "robots 可访问,但缺少 llms.txt。"}
203
+ }
204
+ }
205
+ ```
206
+
207
+ 运行:
208
+
209
+ ```bash
210
+ python <SKILL_DIR>/scripts/geo_score.py score <TEMP_DIR>/geo_assessment.json --output <TEMP_DIR>/geo_score_results.json --report <TEMP_DIR>/geo_score_report.md
211
+ ```
212
+
213
+ 评分公式:
214
+ - 单个大项得分 = `floor(Σ(检测项分值 × 判定系数) / Σ(有效检测项分值) × 100)`
215
+ - 总分 = `floor(Σ(大项得分 × 大项权重))`
216
+ - `WARN` 使用每个检测项自己的待优化系数,不使用统一 0.6。
217
+ - `ERROR` 和 `N/A` 从该大项分母剔除并归一化到 100,避免不适用项稀释或抬高结果。
218
+
219
+ 封顶规则:
220
+ - AI 可发现:若“AI crawler 实际可访问性 / 索引控制与可收录状态 / 错误页与模板回退风险”任一项 `FAIL`,该大项最高 55;两项及以上 `FAIL`,最高 35。
221
+ - AI 可引用:若“可直接摘录与回答能力 / 证据与事实支撑强度”任一项 `FAIL`,该大项最高 65;两项同时 `FAIL`,最高 45;再叠加“正文信息密度与可用性” `FAIL`,最高 35。
222
+ - AI 可信任:若“品牌主体与联系可验证性 / 合规与安全透明度”任一项 `FAIL`,该大项最高 55;两项同时 `FAIL`,最高 35。
223
+ - AI 可推荐:若“平台适配与搜索意图覆盖 / 主题权威与内容集群建设 / 转化承接页完备度”任一项 `FAIL`,该大项最高 60;两项及以上 `FAIL`,最高 45。
224
+ - 跨维度封顶:若“AI crawler 实际可访问性” `FAIL`,AI 可引用最高 70,AI 可推荐最高 65;若“错误页与模板回退风险” `FAIL`,AI 可理解最高 70,AI 可引用最高 65。
225
+ - 总分护栏:若 Sitemap 质量与污染(1.7)判定 `FAIL`(没有可用 sitemap),总分最高 10;若存在 1 个 P0 技术阻塞(AI crawler 被拦截、核心页误 noindex、核心内容集群 homepage fallback / 大量 soft-404),总分最高 70;若 2 个及以上同时存在,总分最高 62。
226
+ 封顶规则展示约定:
227
+ - 封顶规则仅保留在内部 JSON 数据(`caps` 数组)中供调试,**报告正文不向客户展示封顶命中信息**(避免向客户解释成本)。
228
+ - 触发总分封顶时,各维度展示分(`display_score`)按比例缩小,确保维度分值与总分一致、不产生违和感。
229
+ - `render_markdown_report()` 使用 `display_score` 而非原始 `score`;原始 `score` 保留在 JSON 供内部分析。
230
+ ### Step 4.5: 可选 AI 引用性/可见性采样测试
231
+
232
+ 仅当用户明确要求"增加引用性测试""AI 引用性采样""AI 可见性采样""测试品牌在 AI 回答中是否出现"等同类意图时执行。普通“审计/检测 URL”默认不执行,不在默认报告中输出空章节、未执行提示或功能提醒。默认报告不得输出 AI 可见性采样、AI 引用性测试相关章节;可选 AI 引用性/可见性采样章节不得出现在 GEO 总分表中。
233
+
234
+ 1. 生成品牌画像和 prompt set:
235
+
236
+ ```bash
237
+ python <SKILL_DIR>/scripts/geo_visibility.py prepare <TEMP_DIR>/geo_audit_signals.json --output <TEMP_DIR>/geo_visibility_plan.json
238
+ ```
239
+
240
+ 2. 读取 `geo_visibility_plan.json`:
241
+ - `brand_profile` 仅供父 agent 判定使用,不得传给回答子 agent。
242
+ - `prompts` 为 8-12 个可见性测试 prompt。
243
+ - `subagent_concurrency_limit` 固定为 5。
244
+ - `subagent_batches` 按最多 5 个 prompt 分批执行。
245
+
246
+ 3. 并行启动子 agent:
247
+ - 每个 prompt 一个子 agent,同时运行不得超过 5 个。
248
+ - 必须使用隔离上下文;如果工具支持 `fork_context=false`,必须设置。
249
+ - 子 agent 只接收对应 `subagent_tasks[prompt_id]`,不得接收 `brand_profile`、采集 JSON 或父 agent 结论。
250
+
251
+ 4. 如果当前运行环境没有子 agent 工具,不要用父 agent 串行自问自答冒充测试;参考章节写“当前环境不支持隔离子 agent,AI 可见性采样未执行”。
252
+
253
+ 5. 统计并生成可选报告章节:
254
+
255
+ ```bash
256
+ python <SKILL_DIR>/scripts/geo_visibility.py score <TEMP_DIR>/geo_visibility_plan.json <TEMP_DIR>/geo_visibility_answers.json --output <TEMP_DIR>/geo_visibility_results.json --report <TEMP_DIR>/geo_visibility_report.md
257
+ ```
258
+
259
+ 6. 将可选章节放在“优先改进建议”之前;该章节不得进入 GEO 总分表,不参与 5 大项 GEO 总分。
260
+
261
+ ### Step 5: 输出 Markdown 报告
262
+
263
+ 默认不做逐步骤 `mark` 打点,避免耗时统计本身拖慢工作流。所有产物生成后,只运行一次低侵入耗时汇总:
264
+
265
+ ```bash
266
+ python <SKILL_DIR>/scripts/geo_timing.py artifacts \
267
+ --label {domain} \
268
+ --collect-json <TEMP_DIR>/geo_audit_signals.json \
269
+ --score-json <TEMP_DIR>/geo_score_results.json \
270
+ --output <TEMP_DIR>/geo_audit_timing_summary.json \
271
+ --report <TEMP_DIR>/geo_audit_timing_summary.md
272
+ ```
273
+
274
+ 若本次明确执行了可选 AI 引用性/可见性采样测试,再追加 `--visibility-plan-json <TEMP_DIR>/geo_visibility_plan.json` 和 `--visibility-results-json <TEMP_DIR>/geo_visibility_results.json`。
275
+
276
+ 如果用户提供 UI 显示的总耗时,可额外加 `--ui-elapsed-seconds <seconds>`;否则 `total_workflow_seconds` 保持为空,只输出已知脚本耗时和附件明细。`geo_timing.py start/mark/attach` 只保留给深度调试,普通审计不要默认使用。
277
+
278
+ 报告结构必须为:
279
+
280
+ ```markdown
281
+ # GEO 审计报告: {domain}
282
+
283
+ **审计时间**: {fetched_at with timezone, never CST}
284
+ **目标 URL**: {url}
285
+ **渲染方式**: {render_method}
286
+ **抽样子页**: {sub_pages_requested} 页抽样,{sub_pages_fetched} 页成功
287
+
288
+ ## 兜底采集说明(仅触发时输出)
289
+
290
+ ## GEO 总分: {final_score}/100
291
+
292
+ | 评估维度 | 得分 | 权重 |
293
+ |---|---:|---:|
294
+ | 维度一:AI 可发现 | {score}/100 | 25% |
295
+ | 维度二:AI 可理解 | {score}/100 | 20% |
296
+ | 维度三:AI 可引用 | {score}/100 | 20% |
297
+ | 维度四:AI 可信任 | {score}/100 | 20% |
298
+ | 维度五:AI 可推荐 | {score}/100 | 15% |
299
+
300
+ ## 快速一图看懂
301
+
302
+ **必须调用 `show_widget` 工具输出此节,禁止用 Markdown 表格或纯文本代替。**
303
+
304
+ 调用 `show_widget`,参数如下:
305
+ - `title`: `geo_scorecard_{domain}`
306
+ - `loading_messages`: `["生成 GEO 雷达图..."]`
307
+ - `widget_code`: 输出下方 HTML,将占位符替换为实际数值:
308
+
309
+ ```html
310
+ <div style="font-family:system-ui,sans-serif;padding:16px;max-width:560px">
311
+ <h3 style="margin:0 0 12px;font-size:15px;color:var(--text-primary,#111)">快速一图看懂 — {domain}</h3>
312
+ <table style="width:100%;border-collapse:collapse;font-size:13px">
313
+ <thead>
314
+ <tr style="background:var(--surface-2,#f5f5f5)">
315
+ <th style="text-align:left;padding:6px 8px">维度</th>
316
+ <th style="text-align:center;padding:6px 8px">得分</th>
317
+ <th style="text-align:left;padding:6px 8px">亮点</th>
318
+ <th style="text-align:left;padding:6px 8px">短板</th>
319
+ </tr>
320
+ </thead>
321
+ <tbody>
322
+ <tr style="border-top:1px solid var(--border,#e0e0e0)">
323
+ <td style="padding:6px 8px">🔍 AI 可发现</td>
324
+ <td style="text-align:center;padding:6px 8px;font-weight:bold">{d1_score}</td>
325
+ <td style="padding:6px 8px;color:#555">{d1_highlight}</td>
326
+ <td style="padding:6px 8px;color:#e05">{d1_gap}</td>
327
+ </tr>
328
+ <tr style="border-top:1px solid var(--border,#e0e0e0)">
329
+ <td style="padding:6px 8px">🧠 AI 可理解</td>
330
+ <td style="text-align:center;padding:6px 8px;font-weight:bold">{d2_score}</td>
331
+ <td style="padding:6px 8px;color:#555">{d2_highlight}</td>
332
+ <td style="padding:6px 8px;color:#e05">{d2_gap}</td>
333
+ </tr>
334
+ <tr style="border-top:1px solid var(--border,#e0e0e0)">
335
+ <td style="padding:6px 8px">✏️ AI 可引用</td>
336
+ <td style="text-align:center;padding:6px 8px;font-weight:bold">{d3_score}</td>
337
+ <td style="padding:6px 8px;color:#555">{d3_highlight}</td>
338
+ <td style="padding:6px 8px;color:#e05">{d3_gap}</td>
339
+ </tr>
340
+ <tr style="border-top:1px solid var(--border,#e0e0e0)">
341
+ <td style="padding:6px 8px">🛡 AI 可信任</td>
342
+ <td style="text-align:center;padding:6px 8px;font-weight:bold">{d4_score}</td>
343
+ <td style="padding:6px 8px;color:#555">{d4_highlight}</td>
344
+ <td style="padding:6px 8px;color:#e05">{d4_gap}</td>
345
+ </tr>
346
+ <tr style="border-top:1px solid var(--border,#e0e0e0)">
347
+ <td style="padding:6px 8px">🚀 AI 可推荐</td>
348
+ <td style="text-align:center;padding:6px 8px;font-weight:bold">{d5_score}</td>
349
+ <td style="padding:6px 8px;color:#555">{d5_highlight}</td>
350
+ <td style="padding:6px 8px;color:#e05">{d5_gap}</td>
351
+ </tr>
352
+ </tbody>
353
+ </table>
354
+ <div style="margin-top:12px;padding:10px;background:var(--surface-2,#f9f9f9);border-radius:6px;font-size:13px">
355
+ <strong>一句话总结:</strong>{one_sentence_summary}
356
+ </div>
357
+ </div>
358
+ ```
359
+
360
+ 此 widget 中的所有 `{占位符}` 必须替换为本次审计的真实数据,不得保留原始占位符文本。
361
+
362
+ ## 关键结论
363
+
364
+ ## 维度一:AI 可发现 ({score}/100)
365
+
366
+ | # | 检测项 | 状态 | 说明 |
367
+ |---|---|---|---|
368
+ | 1.1 | 入口规范与可达性 | {status_badge} | {note} |
369
+
370
+ ...继续输出全部 30 项...
371
+
372
+ ## 优先改进建议
373
+
374
+ ## 报告说明
375
+
376
+ 需要我将本报告导出为 PDF 吗?回复“导出 PDF”即可。
377
+ ```
378
+
379
+ 硬性要求:
380
+ - 完整输出 5 大项 × 30 项明细表;没有可用 sitemap 时必须判定 `FAIL`
381
+ - **"快速一图看懂"节必须通过 `show_widget` 工具渲染 HTML widget,严禁用 Markdown 表格或纯文本输出该节**
382
+ - 禁止输出:AI 可见性采样章节(除非用户明确要求)、报告生成耗时、采集调度逻辑、`CST` 时区
383
+ - 报告正文暂不输出报告生成耗时(调试耗时见 meta.timings)
384
+ - 报告正文不要描述 URL 获取、sitemap 抽样、页面优先级或采集调度逻辑
385
+ - 每个 note 基于 `signals` / `snippets` / 兜底来源的具体证据;兜底采集列出直接失败证据和外部来源
386
+ - 优先改进建议按影响力列 Top 5,编号连续递增
387
+ - 时区必须为 Asia/Shanghai (UTC+08:00),禁止 CST
388
+ - 调试耗时记录在 meta.timings 中(含 meta.timings.notfound_probe_seconds 等字段),报告正文不输出
389
+
390
+ ### 报告说明固定文案
391
+
392
+ - 本次演示报告仅基于目标网站可公开访问的数据、搜索结果及第三方公开资料生成,不能替代接入后基于完整站点、渠道和历史数据的持续监测。
393
+ - 完整的持续监控、竞品对比、内容生成与优化建议等功能,可在 [adgine.ai](https://adgine.ai/) 注册后使用。
394
+ - [adgine.ai](https://adgine.ai/) 也提供一站式 GEO/AI 可见性代运营服务,帮助企业提升品牌在 AI 回答中的被发现、被引用和被推荐概率。
395
+
396
+ 需要我将本报告导出为 PDF 吗?回复“导出 PDF”即可。
397
+
398
+ ## PDF 导出流程
399
+
400
+ 用户确认导出 PDF 时:
401
+ 1. 不重新采集、不重新评分,除非用户明确要求重新检测。
402
+ 2. 将上一份完整 Markdown 报告原文写入 `<TEMP_DIR>/geo_audit_reports/{domain}-{timestamp}.md`。
403
+ 3. 运行:
404
+
405
+ ```bash
406
+ python <SKILL_DIR>/scripts/render_report_pdf.py <TEMP_DIR>/geo_audit_reports/{domain}-{timestamp}.md --output <TEMP_DIR>/geo_audit_reports/{domain}-{timestamp}.pdf --engine reportlab
407
+ ```
408
+
409
+ 4. 脚本默认使用 ReportLab 生成 PDF,不调用 Chrome/Playwright,避免后台 Agent 环境中浏览器启动失败。`render_report_pdf.py` 可用 `--timings-output` 参数导出 PDF 渲染耗时 JSON。
410
+ 5. 只有明确需要浏览器渲染时,才显式使用 `--engine playwright` 或 `--engine chrome`;若需要在当前 Python/pyenv 中安装 Playwright,可加 `--install-playwright`。
411
+ 6. PDF 渲染会自动过滤末尾“需要我将本报告导出为 PDF 吗?”交互提示。
412
+ 7. 调试 PDF 耗时时,添加 `--timings-output <TEMP_DIR>/geo_audit_pdf_timing.json`,再用 `geo_timing.py artifacts --pdf-timing-json <TEMP_DIR>/geo_audit_pdf_timing.json` 汇总。
413
+
414
+ ## 质量门槛
415
+
416
+ 交付前必须运行:
417
+
418
+ ```bash
419
+ python <SKILL_DIR>/scripts/geo_score.py validate
420
+ python -m unittest discover -s tests -p 'test_*.py'
421
+ ```
422
+
423
+ 报告自检必须确认:
424
+ - 总分表只有 5 个评分维度:AI 可发现、AI 可理解、AI 可引用、AI 可信任、AI 可推荐。
425
+ - 明细表合计 30 行检测项。
426
+ - 默认报告不包含 AI 可见性采样或 AI 引用性测试章节;若用户明确要求增加该测试,可选章节也不参与 GEO 总分。
427
+ - 报告正文不包含 `报告生成耗时`。
428
+ - PDF 中不包含末尾交互提示。
429
+
430
+ ---
431
+
432
+ ## Post-task recommendations
433
+
434
+ After a site audit, suggest next steps based on the audit findings:
435
+
436
+ | Audit result | → use skill (agent-internal) |
437
+ |---|---|
438
+ | Low GEO score (< 50) | Fix critical issues first, then 修复后重新审计 *(→ adgine-geo-site-audit)*|
439
+ | Crawlability issues found | 配置 Cloudflare Worker 追踪 AI 爬虫 *(→ adgine-geo-integrations)*|
440
+ | Content gaps identified | 针对缺失的内容类型生成 GEO 文章 *(→ adgine-geo-content)*|
441
+ | Schema / structure issues | Fix on site, then 逐页检查 AI 优化健康度 *(→ adgine-geo-performance)*|
442
+ | Audit completed (strong score) | 将网站注册到 GEO 平台,开始持续监控 *(→ adgine-geo-projects)*|
443
+ | Audit completed (any score) | 运行引用测试,验证 AI 平台实际引用情况 *(→ adgine-geo-citation)*|
444
+
445
+ **⚠️ Output rule:** Do NOT write skill names (e.g. `adgine-geo-xxx`) in user-facing suggestions. Each suggestion must be phrased as a natural-language prompt the user can copy and send directly to the agent.
446
+
447
+ > 💡 **建议下一步:**
448
+ > 1. **[行动标题]** — *"[可直接发送给 AI 的自然语言提示词]"*
449
+ > 2. **[行动标题]** — *"[可直接发送给 AI 的自然语言提示词]"*
@@ -0,0 +1,5 @@
1
+ curl_cffi>=0.7
2
+ beautifulsoup4>=4.11
3
+ lxml>=4.9
4
+ markdown>=3.6
5
+ reportlab>=4.2