gsc-cli 2.1.0 → 2.2.0

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 (100) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +410 -414
  3. data/bin/gsc +28067 -5661
  4. data/dist/gsc +29121 -5046
  5. data/lib/gsc/aio_hunter.rb +343 -0
  6. data/lib/gsc/answer_synthesizer.rb +157 -0
  7. data/lib/gsc/api.rb +53 -1
  8. data/lib/gsc/auth.rb +26 -0
  9. data/lib/gsc/brand_segmenter.rb +140 -0
  10. data/lib/gsc/cache_manager.rb +806 -0
  11. data/lib/gsc/cannibalization_analyzer.rb +141 -0
  12. data/lib/gsc/canonical_chains.rb +367 -0
  13. data/lib/gsc/citation_simulator.rb +339 -0
  14. data/lib/gsc/cli/aio_hunter.rb +154 -0
  15. data/lib/gsc/cli/analytics.rb +788 -0
  16. data/lib/gsc/cli/audit.rb +1976 -0
  17. data/lib/gsc/cli/base.rb +384 -0
  18. data/lib/gsc/cli/cache.rb +266 -0
  19. data/lib/gsc/cli/canonical.rb +223 -0
  20. data/lib/gsc/cli/citation_simulator.rb +152 -0
  21. data/lib/gsc/cli/dashboard.rb +354 -0
  22. data/lib/gsc/cli/doctor.rb +129 -0
  23. data/lib/gsc/cli/eeat.rb +125 -0
  24. data/lib/gsc/cli/ga4.rb +852 -0
  25. data/lib/gsc/cli/growth.rb +650 -0
  26. data/lib/gsc/cli/hreflang.rb +164 -0
  27. data/lib/gsc/cli/image_seo.rb +162 -0
  28. data/lib/gsc/cli/indexing.rb +458 -0
  29. data/lib/gsc/cli/intent_shift.rb +125 -0
  30. data/lib/gsc/cli/keyword_value.rb +134 -0
  31. data/lib/gsc/cli/keywords.rb +795 -0
  32. data/lib/gsc/cli/landing_roi.rb +308 -0
  33. data/lib/gsc/cli/low_ctr.rb +213 -0
  34. data/lib/gsc/cli/mobile_parity.rb +150 -0
  35. data/lib/gsc/cli/report.rb +100 -0
  36. data/lib/gsc/cli/rich_results.rb +172 -0
  37. data/lib/gsc/cli/schema_generate.rb +149 -0
  38. data/lib/gsc/cli/seasonal.rb +232 -0
  39. data/lib/gsc/cli/security.rb +153 -0
  40. data/lib/gsc/cli/setup.rb +1291 -0
  41. data/lib/gsc/cli/sitemap_tree.rb +143 -0
  42. data/lib/gsc/cli/skill_pack.rb +62 -0
  43. data/lib/gsc/cli/soft_404.rb +199 -0
  44. data/lib/gsc/cli/sparkline.rb +227 -0
  45. data/lib/gsc/cli/watchdog.rb +150 -0
  46. data/lib/gsc/cli/zombie_purger.rb +208 -0
  47. data/lib/gsc/cli.rb +707 -5265
  48. data/lib/gsc/cli_advanced.rb +987 -44
  49. data/lib/gsc/client.rb +17 -2
  50. data/lib/gsc/color.rb +16 -1
  51. data/lib/gsc/command_registry.rb +47 -9
  52. data/lib/gsc/config.rb +2 -2
  53. data/lib/gsc/ctr_curve.rb +115 -0
  54. data/lib/gsc/decay_predictor.rb +322 -0
  55. data/lib/gsc/doctor.rb +434 -0
  56. data/lib/gsc/eeat_auditor.rb +428 -0
  57. data/lib/gsc/entity_auditor.rb +229 -0
  58. data/lib/gsc/firewall_scanner.rb +733 -0
  59. data/lib/gsc/geo_auditor.rb +368 -0
  60. data/lib/gsc/google_trends.rb +8 -1
  61. data/lib/gsc/heading_validator.rb +283 -0
  62. data/lib/gsc/hreflang_validator.rb +412 -0
  63. data/lib/gsc/image_seo.rb +286 -0
  64. data/lib/gsc/indexing_queue.rb +179 -0
  65. data/lib/gsc/indexnow.rb +93 -0
  66. data/lib/gsc/intent_shift.rb +188 -0
  67. data/lib/gsc/internal_links.rb +153 -36
  68. data/lib/gsc/keyword_value.rb +191 -0
  69. data/lib/gsc/landing_roi.rb +195 -0
  70. data/lib/gsc/llms_generator.rb +343 -22
  71. data/lib/gsc/low_ctr_rewriter.rb +408 -0
  72. data/lib/gsc/mobile_parity.rb +222 -0
  73. data/lib/gsc/network_tracer.rb +8 -1
  74. data/lib/gsc/page_analyzer.rb +47 -7
  75. data/lib/gsc/prompts.rb +38 -29
  76. data/lib/gsc/questions_harvester.rb +178 -0
  77. data/lib/gsc/report_generator.rb +461 -0
  78. data/lib/gsc/rich_results.rb +388 -0
  79. data/lib/gsc/robots_checker.rb +46 -15
  80. data/lib/gsc/schema_generator.rb +788 -0
  81. data/lib/gsc/schema_validator.rb +36 -38
  82. data/lib/gsc/seasonal_predictor.rb +381 -0
  83. data/lib/gsc/security_scanner.rb +496 -0
  84. data/lib/gsc/serp_feature_detector.rb +359 -0
  85. data/lib/gsc/serp_preview.rb +108 -22
  86. data/lib/gsc/site_crawler.rb +113 -21
  87. data/lib/gsc/sitemap_loader.rb +15 -4
  88. data/lib/gsc/sitemap_tree.rb +301 -0
  89. data/lib/gsc/skill_pack.rb +195 -0
  90. data/lib/gsc/soft_404_analyzer.rb +385 -0
  91. data/lib/gsc/sparkline.rb +171 -0
  92. data/lib/gsc/speed_correlator.rb +416 -0
  93. data/lib/gsc/striking_playbook.rb +190 -0
  94. data/lib/gsc/title_optimizer.rb +420 -0
  95. data/lib/gsc/vault.rb +260 -0
  96. data/lib/gsc/version.rb +1 -1
  97. data/lib/gsc/watchdog.rb +235 -0
  98. data/lib/gsc/zombie_purger.rb +366 -0
  99. data/lib/gsc.rb +118 -0
  100. metadata +75 -1
@@ -76,9 +76,28 @@ module GSC
76
76
  canonical_url = extract_link_attr(doc, 'canonical', 'href')
77
77
  robots_meta = extract_meta_content(doc, 'name', 'robots')
78
78
 
79
- # 2. Detailed Headings Structure
80
- headings = extract_headings(doc)
81
- h1_list = headings.select { |h| h[:tag] == 'h1' }
79
+ # 2. Detailed Headings Structure & Hierarchy Depth
80
+ heading_audit = if defined?(HeadingValidator)
81
+ HeadingValidator.analyze(doc, target_keywords: title_raw)
82
+ else
83
+ h_list = extract_headings(doc)
84
+ h1_found = h_list.select { |h| h[:tag] == 'h1' }
85
+ {
86
+ score: h1_found.size == 1 ? 100 : 70,
87
+ grade: h1_found.size == 1 ? 'A' : 'C',
88
+ depth: h_list.map { |h| h[:tag][1].to_i }.max || 0,
89
+ count: h_list.size,
90
+ counts: h_list.group_by { |h| h[:tag] }.transform_values(&:size),
91
+ h1_count: h1_found.size,
92
+ empty_count: 0,
93
+ headings: h_list,
94
+ violations: [],
95
+ ascii_tree: '',
96
+ color_tree: ''
97
+ }
98
+ end
99
+ headings = heading_audit[:headings]
100
+ h1_list = headings.select { |h| h[:tag] == 'h1' && !h[:empty] }
82
101
 
83
102
  # 3. Images & Missing Alt Tags
84
103
  images_data = extract_images(doc)
@@ -123,8 +142,19 @@ module GSC
123
142
  issues << { level: :warn, type: :title, message: "Title > 568px width (~#{title_pixel_est}px, risks SERP truncation)" } if title_pixel_est > 568.0
124
143
  issues << { level: :warn, type: :meta, message: "Missing meta description" } if meta_desc.nil? || meta_desc.empty?
125
144
  issues << { level: :warn, type: :meta, message: "Meta description > 155 chars (#{meta_desc.length}c)" } if meta_desc && meta_desc.length > 155
126
- issues << { level: :error, type: :headings, message: "Missing <h1> tag (0 found)" } if h1_list.empty?
127
- issues << { level: :warn, type: :headings, message: "Multiple <h1> tags (#{h1_list.size} found)" } if h1_list.size > 1
145
+ if heading_audit[:violations] && !heading_audit[:violations].empty?
146
+ heading_audit[:violations].each do |v|
147
+ lvl = case v[:severity]
148
+ when :critical then :error
149
+ when :warning then :warn
150
+ else :info
151
+ end
152
+ issues << { level: lvl, type: :headings, message: v[:message] }
153
+ end
154
+ else
155
+ issues << { level: :error, type: :headings, message: "Missing <h1> tag (0 found)" } if h1_list.empty?
156
+ issues << { level: :warn, type: :headings, message: "Multiple <h1> tags (#{h1_list.size} found)" } if h1_list.size > 1
157
+ end
128
158
  issues << { level: :warn, type: :images, message: "#{images_data[:missing_alt_count]} images missing alt tags" } if images_data[:missing_alt_count] > 0
129
159
  issues << { level: :critical, type: :indexability, message: "Robots noindex tag detected (Blocking Googlebot)" } if noindex
130
160
 
@@ -155,13 +185,23 @@ module GSC
155
185
  self_referencing: canonical_url ? (canonical_url.chomp('/') == @url.chomp('/')) : false
156
186
  },
157
187
  headings: {
158
- count: headings.size,
159
- h1_count: h1_list.size,
188
+ count: heading_audit[:count],
189
+ h1_count: heading_audit[:h1_count],
190
+ score: heading_audit[:score],
191
+ grade: heading_audit[:grade],
192
+ depth: heading_audit[:depth],
193
+ counts: heading_audit[:counts],
194
+ empty_count: heading_audit[:empty_count],
195
+ violations: heading_audit[:violations],
196
+ ascii_tree: heading_audit[:ascii_tree],
197
+ color_tree: heading_audit[:color_tree],
198
+ keyword_analysis: heading_audit[:keyword_analysis],
160
199
  list: headings
161
200
  },
162
201
  images: images_data,
163
202
  links: links_data,
164
203
  schema: schemas,
204
+ structured_data: { schemas: schemas },
165
205
  social: { og: og_data, twitter: twitter_data },
166
206
  stats: { word_count: word_count, reading_time_mins: reading_time_mins },
167
207
  issues: issues
data/lib/gsc/prompts.rb CHANGED
@@ -11,7 +11,7 @@ module GSC
11
11
  title: 'The 360° Multi-Horizon Master SEO & Universal Keyword Audit',
12
12
  impact: 'Maximum Impact (Exhaustive 30d, 90d, 180d audit & action plan)',
13
13
  cli_command: 'gsc performance --days 180 --json',
14
- template: "Antigravity, perform an exhaustive 360° SEO, Universal Keyword, and Crawl Health Audit for {{domain}} across 30d, 90d, and 180d horizons.\n\nExecute the following commands with --json and save the final report to both an Antigravity Artifact and to docs/seo/master_audit_report.md:\n\n1. Macro Multi-Horizon Performance & Trends:\n - `gsc performance --days 30 --json`\n - `gsc performance --days 90 --json`\n - `gsc performance --days 180 --json`\n - `gsc decay --compare 28 --json`\n\n2. Universal Keyword Intelligence (Saved & Unsaved):\n - Check all saved snapshots: `gsc saved check 1 --json`\n - Unsaved live search queries: `gsc top-queries --days 180 --limit 500 -s imp --json`\n - Page 2 striking distance: `gsc opportunities --min-imp 5 --limit 100 --json`\n - CTR underperformers: `gsc underperformers --limit 50 --json`\n - Keyword cannibalization conflicts: `gsc cannibalization --json`\n\n3. Google Trends & Autocomplete Velocity:\n - `gsc trends \"{{seed}}\" --time 12m --json`\n - `gsc planner \"{{seed}}\" --json`\n\n4. Landing Pages, Post-Click GA4 Behavior & Crawl Budget:\n - Top traffic landing pages: `gsc top-pages --days 90 --limit 100 --json`\n - Organic bounce & engagement: `gsc ga4 --organic --days 30 --limit 100 --json`\n - SERP vs Bounce correlation: `gsc correlation --organic --json`\n - Sitemap crawl waste: `gsc zombies public/sitemap.xml --json`\n\nGenerate a Master Executive Report containing:\n1. Executive Growth Scorecard (Macro comparison: 30d vs 90d vs 180d clicks, impressions, CTR, pos).\n2. The Universal Keyword Opportunity Matrix (Ranking, Striking Distance, Untargeted Saved Keywords).\n3. Google Trends Seasonal Velocity & Rising Breakouts (+5000% queries).\n4. CTR Optimization Matrix (Title & meta rewrites for low-CTR pages).\n5. Post-Click Leak Audit (High organic impressions with high GA4 bounce).\n6. Technical & Zombie Crawl Waste cleanup plan.\n7. Prioritized 30-Day Sprint (P0, P1, P2 with exact file paths and code edits)."
14
+ template: "Perform an exhaustive 360° SEO, Universal Keyword, and Crawl Health Audit for {{domain}} across 30d, 90d, and 180d horizons.\n\nExecute the following commands with --json and save the final report to docs/seo/master_audit_report.md (and as an agent artifact if your environment supports artifacts):\n\n1. Macro Multi-Horizon Performance & Trends:\n - `gsc performance --days 30 --json`\n - `gsc performance --days 90 --json`\n - `gsc performance --days 180 --json`\n - `gsc decay --compare 28 --json`\n\n2. Universal Keyword Intelligence (Saved & Unsaved):\n - Check all saved snapshots: `gsc saved check 1 --json`\n - Unsaved live search queries: `gsc top-queries --days 180 --limit 500 -s imp --json`\n - Page 2 striking distance: `gsc opportunities --min-imp 5 --limit 100 --json`\n - CTR underperformers: `gsc underperformers --limit 50 --json`\n - Keyword cannibalization conflicts: `gsc cannibalization --json`\n\n3. Google Trends & Autocomplete Velocity:\n - `gsc trends \"{{seed}}\" --time 12m --json`\n - `gsc planner \"{{seed}}\" --json`\n\n4. Landing Pages, Post-Click GA4 Behavior & Crawl Budget:\n - Top traffic landing pages: `gsc top-pages --days 90 --limit 100 --json`\n - Organic bounce & engagement: `gsc ga4 --organic --days 30 --limit 100 --json`\n - SERP vs Bounce correlation: `gsc correlation --organic --json`\n - Sitemap crawl waste: `gsc zombies public/sitemap.xml --json`\n\nGenerate a Master Executive Report containing:\n1. Executive Growth Scorecard (Macro comparison: 30d vs 90d vs 180d clicks, impressions, CTR, pos).\n2. The Universal Keyword Opportunity Matrix (Ranking, Striking Distance, Untargeted Saved Keywords).\n3. Google Trends Seasonal Velocity & Rising Breakouts (+5000% queries).\n4. CTR Optimization Matrix (Title & meta rewrites for low-CTR pages).\n5. Post-Click Leak Audit (High organic impressions with high GA4 bounce).\n6. Technical & Zombie Crawl Waste cleanup plan.\n7. Prioritized 30-Day Sprint (P0, P1, P2 with exact file paths and code edits)."
15
15
  },
16
16
 
17
17
  # Category: Growth & Striking Distance Opportunities
@@ -22,7 +22,7 @@ module GSC
22
22
  title: 'The Page 2 Striking Distance Leap',
23
23
  impact: 'High Impact (Push Page 2 keywords to Top 3)',
24
24
  cli_command: 'gsc opportunities --min-imp 20 --json',
25
- template: 'Antigravity, run `gsc opportunities --min-imp 20 --json` for {{domain}}. Find the top 3 striking-distance queries (positions 8–18 with high impressions). For each query, locate its ranking page in our codebase, identify what content is missing compared to top SERP competitors, expand the page with a targeted FAQ and comparison table, and ping Google Indexing API via `gsc index <url>`.'
25
+ template: 'Run `gsc opportunities --min-imp 20 --json` for {{domain}}. Find the top 3 striking-distance queries (positions 8–18 with high impressions). For each query, locate its ranking page in our codebase, identify what content is missing compared to top SERP competitors, expand the page with a targeted FAQ and comparison table, and ping Google Indexing API via `gsc index <url>`.'
26
26
  },
27
27
  {
28
28
  id: 2,
@@ -31,7 +31,7 @@ module GSC
31
31
  title: 'The Untargeted Keyword Goldmine',
32
32
  impact: 'High Impact (Create high-intent new landing pages)',
33
33
  cli_command: 'gsc saved check 1 --json',
34
- template: 'Antigravity, inspect our saved keyword research with `gsc saved check 1 --json`. Identify the top 5 keywords with Opportunity Score > 65 that are currently flagged as 🚀 Untargeted. For each keyword, propose a dedicated landing page route, draft high-intent metadata, and generate a semantic content outline.'
34
+ template: 'Inspect our saved keyword research with `gsc saved check 1 --json`. Identify the top 5 keywords with Opportunity Score > 65 that are currently flagged as 🚀 Untargeted. For each keyword, propose a dedicated landing page route, draft high-intent metadata, and generate a semantic content outline.'
35
35
  },
36
36
  {
37
37
  id: 3,
@@ -40,7 +40,7 @@ module GSC
40
40
  title: '5-Year Google Trends Seasonal Surf',
41
41
  impact: 'Medium Impact (Catch seasonal breakout demand)',
42
42
  cli_command: 'gsc trends "{{seed}}" --time 5y --json',
43
- template: 'Antigravity, run `gsc trends "{{seed}}" --time 5y --json`. Identify the historical peak search months, extract all rising breakout queries (+5000%), and update our landing page headings and marketing banners to capture the upcoming seasonal search surge.'
43
+ template: 'Run `gsc trends "{{seed}}" --time 5y --json`. Identify the historical peak search months, extract all rising breakout queries (+5000%), and update our landing page headings and marketing banners to capture the upcoming seasonal search surge.'
44
44
  },
45
45
  {
46
46
  id: 4,
@@ -49,7 +49,7 @@ module GSC
49
49
  title: 'Long-Tail Autocomplete Multiplier',
50
50
  impact: 'Medium Impact (Target long-tail customer questions)',
51
51
  cli_command: 'gsc planner "{{seed}}" --limit 50 --json',
52
- template: 'Antigravity, run `gsc planner "{{seed}}" --limit 50 --json`. Group all discovered long-tail queries by search intent (Transactional vs Informational), and generate an interactive FAQ accordion component in our template addressing the top 5 customer questions.'
52
+ template: 'Run `gsc planner "{{seed}}" --limit 50 --json`. Group all discovered long-tail queries by search intent (Transactional vs Informational), and generate an interactive FAQ accordion component in our template addressing the top 5 customer questions.'
53
53
  },
54
54
 
55
55
  # Category: Conversion & Click-Through Rate (CTR)
@@ -60,7 +60,7 @@ module GSC
60
60
  title: 'The CTR Underperformer Double',
61
61
  impact: 'High Impact (Double organic clicks with 0 rank changes)',
62
62
  cli_command: 'gsc underperformers --limit 5 --json',
63
- template: 'Antigravity, run `gsc underperformers --limit 5 --json` for {{domain}}. For the page with the highest impressions but lowest CTR (<2%), read its current <title> and meta description in our codebase. Rewrite them applying the 50–60 character high-CTR formula (front-loading the exact query, adding bracketed hooks like [2026 Free Tool], and appending brand). Update the file and ping `gsc index <url>`.'
63
+ template: 'Run `gsc underperformers --limit 5 --json` for {{domain}}. For the page with the highest impressions but lowest CTR (<2%), read its current <title> and meta description in our codebase. Rewrite them applying the 50–60 character high-CTR formula (front-loading the exact query, adding bracketed hooks like [2026 Free Tool], and appending brand). Update the file and ping `gsc index <url>`.'
64
64
  },
65
65
  {
66
66
  id: 6,
@@ -69,7 +69,7 @@ module GSC
69
69
  title: 'Review & FAQ Rich Snippet Enabler',
70
70
  impact: 'High Impact (Win star ratings and expandable FAQs in SERP)',
71
71
  cli_command: 'gsc snippets --json',
72
- template: 'Antigravity, run `gsc snippets --json` on {{domain}} to check active search appearances. Then inspect our top traffic pages from `gsc top-pages --json` and inject valid Schema.org JSON-LD structured data (FAQPage or Product) so our Google SERP listings display star ratings and expandable FAQs.'
72
+ template: 'Run `gsc snippets --json` on {{domain}} to check active search appearances. Then inspect our top traffic pages from `gsc top-pages --json` and inject valid Schema.org JSON-LD structured data (FAQPage or Product) so our Google SERP listings display star ratings and expandable FAQs.'
73
73
  },
74
74
  {
75
75
  id: 7,
@@ -78,7 +78,7 @@ module GSC
78
78
  title: 'Headline & H1 Alignment Overhaul',
79
79
  impact: 'Medium Impact (Increase on-page conversion rate)',
80
80
  cli_command: 'gsc top-queries --limit 10 --json',
81
- template: 'Antigravity, find our top 3 visited landing pages using `gsc ga4 --organic --json`. Audit their <h1> display headings against our copywriting rules (ensure zero trailing periods, strong benefit promise, and strict alignment with high-volume search queries from `gsc top-queries`).'
81
+ template: 'Find our top 3 visited landing pages using `gsc ga4 --organic --json`. Audit their <h1> display headings against our copywriting rules (ensure zero trailing periods, strong benefit promise, and strict alignment with high-volume search queries from `gsc top-queries`).'
82
82
  },
83
83
  {
84
84
  id: 8,
@@ -87,7 +87,7 @@ module GSC
87
87
  title: 'Keyword Cannibalization Consolidator',
88
88
  impact: 'High Impact (Stop competing against your own pages)',
89
89
  cli_command: 'gsc cannibalization --json',
90
- template: 'Antigravity, run `gsc cannibalization --json` on {{domain}}. Detect any search queries where 2 or more of our URLs are competing against each other and splitting Google impressions. Recommend which URL should be the authoritative canonical, and add cross-linking or 301 redirects to consolidate ranking power.'
90
+ template: 'Run `gsc cannibalization --json` on {{domain}}. Detect any search queries where 2 or more of our URLs are competing against each other and splitting Google impressions. Recommend which URL should be the authoritative canonical, and add cross-linking or 301 redirects to consolidate ranking power.'
91
91
  },
92
92
 
93
93
  # Category: GA4 Behavioral, Ads & Conversion Analytics
@@ -98,7 +98,7 @@ module GSC
98
98
  title: 'High-Bounce Traffic Leak Plugger',
99
99
  impact: 'High Impact (Rescue lost visitors who bounce in <10s)',
100
100
  cli_command: 'gsc correlation --json',
101
- template: 'Antigravity, run `gsc correlation --json`. Correlate high-impression GSC search queries against GA4 bounce rates. Find search queries driving visitors who bounce in under 10 seconds. Audit the page\'s above-the-fold hero section and align the primary value proposition directly to user search intent.'
101
+ template: 'Run `gsc correlation --json`. Correlate high-impression GSC search queries against GA4 bounce rates. Find search queries driving visitors who bounce in under 10 seconds. Audit the page\'s above-the-fold hero section and align the primary value proposition directly to user search intent.'
102
102
  },
103
103
  {
104
104
  id: 10,
@@ -107,7 +107,7 @@ module GSC
107
107
  title: 'Real-Time Traffic Wave Monitor',
108
108
  impact: 'Medium Impact (Live visitor diagnostic & health check)',
109
109
  cli_command: 'gsc realtime --json',
110
- template: 'Antigravity, run `gsc realtime --json`. Check how many live visitors are currently on {{domain}}, which landing pages they are viewing, and verify that our conversion tracking and call-to-actions on those active pages are operating smoothly.'
110
+ template: 'Run `gsc realtime --json`. Check how many live visitors are currently on {{domain}}, which landing pages they are viewing, and verify that our conversion tracking and call-to-actions on those active pages are operating smoothly.'
111
111
  },
112
112
  {
113
113
  id: 11,
@@ -116,7 +116,7 @@ module GSC
116
116
  title: 'Google Ads & Organic Synergy Optimizer',
117
117
  impact: 'High Impact (Cut wasted ad spend where you rank #1 organically)',
118
118
  cli_command: 'gsc ads --json',
119
- template: 'Antigravity, run `gsc ads --json` and `gsc top-queries --json`. Identify expensive Google Ads keywords (high CPC) where our site already ranks in Top 3 organically, and suggest pausing those paid ads to save ad spend while doubling down on organic CTR.'
119
+ template: 'Run `gsc ads --json` and `gsc top-queries --json`. Identify expensive Google Ads keywords (high CPC) where our site already ranks in Top 3 organically, and suggest pausing those paid ads to save ad spend while doubling down on organic CTR.'
120
120
  },
121
121
  {
122
122
  id: 12,
@@ -125,7 +125,7 @@ module GSC
125
125
  title: 'Omni-Channel Attribution & Engagement Audit',
126
126
  impact: 'Medium Impact (Identify top converting traffic channels)',
127
127
  cli_command: 'gsc channels --days 30 --json',
128
- template: 'Antigravity, run `gsc channels --days 30 --json`. Compare organic search conversion rates against paid and direct traffic. Highlight which traffic channel has the highest customer engagement rate and recommend channel-specific landing page optimizations.'
128
+ template: 'Run `gsc channels --days 30 --json`. Compare organic search conversion rates against paid and direct traffic. Highlight which traffic channel has the highest customer engagement rate and recommend channel-specific landing page optimizations.'
129
129
  },
130
130
 
131
131
  # Category: Technical SEO, Crawl Health & Indexing
@@ -136,7 +136,7 @@ module GSC
136
136
  title: 'The 90-Day Zombie Page Purge',
137
137
  impact: 'High Impact (Reclaim crawl budget and prune dead weight)',
138
138
  cli_command: 'gsc zombies --json',
139
- template: 'Antigravity, run `gsc zombies --json` on our sitemap. Identify all low-quality or obsolete pages that have received 0 impressions in the last 90 days. Recommend whether to update them with fresh content or retire them with `gsc remove <url>` to protect crawl budget.'
139
+ template: 'Run `gsc zombies --json` on our sitemap. Identify all low-quality or obsolete pages that have received 0 impressions in the last 90 days. Recommend whether to update them with fresh content or retire them with `gsc remove <url>` to protect crawl budget.'
140
140
  },
141
141
  {
142
142
  id: 14,
@@ -145,7 +145,7 @@ module GSC
145
145
  title: 'Sitemap Coverage & Rapid Indexing Blitz',
146
146
  impact: 'High Impact (Force Googlebot to index queued pages)',
147
147
  cli_command: 'gsc inspect-sitemap https://{{domain}}/sitemap.xml --json',
148
- template: 'Antigravity, run `gsc inspect-sitemap https://{{domain}}/sitemap.xml --json`. Identify all URLs marked as "Discovered - currently not indexed" or "Crawled - currently not indexed". For any unindexed URL, batch ping Google Indexing API via `gsc index <url>` to accelerate indexing.'
148
+ template: 'Run `gsc inspect-sitemap https://{{domain}}/sitemap.xml --json`. Identify all URLs marked as "Discovered - currently not indexed" or "Crawled - currently not indexed". For any unindexed URL, batch ping Google Indexing API via `gsc index <url>` to accelerate indexing.'
149
149
  },
150
150
  {
151
151
  id: 15,
@@ -154,7 +154,7 @@ module GSC
154
154
  title: 'Ranking Decay Early Warning Detection',
155
155
  impact: 'High Impact (Arrest traffic loss before it accelerates)',
156
156
  cli_command: 'gsc decay --days 28 --json',
157
- template: 'Antigravity, run `gsc decay --days 28 --json`. Identify queries or pages experiencing period-over-period click or impression drops (>20%). Propose immediate content freshness updates and internal link boosts to reverse the decay.'
157
+ template: 'Run `gsc decay --days 28 --json`. Identify queries or pages experiencing period-over-period click or impression drops (>20%). Propose immediate content freshness updates and internal link boosts to reverse the decay.'
158
158
  },
159
159
  {
160
160
  id: 16,
@@ -163,7 +163,7 @@ module GSC
163
163
  title: 'Lost Query Resuscitation',
164
164
  impact: 'Medium Impact (Recover queries that fell out of Google)',
165
165
  cli_command: 'gsc decay --json',
166
- template: 'Antigravity, run `gsc decay --json` and filter by "lost". Find high-volume keywords that generated traffic last month but completely dropped off this month. Inspect the previous URL and restore missing topical sections.'
166
+ template: 'Run `gsc decay --json` and filter by "lost". Find high-volume keywords that generated traffic last month but completely dropped off this month. Inspect the previous URL and restore missing topical sections.'
167
167
  },
168
168
 
169
169
  # Category: Programmatic SEO & Scalable Architecture
@@ -174,7 +174,7 @@ module GSC
174
174
  title: 'Programmatic Landing Page Generator',
175
175
  impact: 'High Impact (Build 50+ data-driven landing pages)',
176
176
  cli_command: 'gsc saved check 1 --json',
177
- template: 'Antigravity, run `gsc saved check 1 --json`. Extract the top 10 untargeted city or feature keywords. Generate a reusable programmatic template that renders unique, value-dense content for each variation without creating duplicate content.'
177
+ template: 'Run `gsc saved check 1 --json`. Extract the top 10 untargeted city or feature keywords. Generate a reusable programmatic template that renders unique, value-dense content for each variation without creating duplicate content.'
178
178
  },
179
179
  {
180
180
  id: 18,
@@ -183,7 +183,7 @@ module GSC
183
183
  title: 'Competitor Gap Exploitation via Import',
184
184
  impact: 'High Impact (Steal competitor high-volume terms)',
185
185
  cli_command: 'gsc import clip --json',
186
- template: 'Antigravity, run `gsc import clip --json` using our latest competitor export from clipboard. Compare their highest volume keywords against our `gsc top-queries --json`. Identify the 5 most profitable keywords where our competitor ranks but we have zero presence.'
186
+ template: 'Run `gsc import clip --json` using our latest competitor export from clipboard. Compare their highest volume keywords against our `gsc top-queries --json`. Identify the 5 most profitable keywords where our competitor ranks but we have zero presence.'
187
187
  },
188
188
  {
189
189
  id: 19,
@@ -192,7 +192,7 @@ module GSC
192
192
  title: 'Zero-Click Search & AI Overview Winning Strategy',
193
193
  impact: 'High Impact (Win citations in Google AI Overviews)',
194
194
  cli_command: 'gsc top-queries -s imp --limit 20 --json',
195
- template: 'Antigravity, run `gsc top-queries -s imp --limit 20 --json`. Identify informational queries where Google shows AI Overviews or direct answer boxes. Structure our content with concise 40-word definitions, numbered steps, and comparison tables to win the AI Overview citation.'
195
+ template: 'Run `gsc top-queries -s imp --limit 20 --json`. Identify informational queries where Google shows AI Overviews or direct answer boxes. Structure our content with concise 40-word definitions, numbered steps, and comparison tables to win the AI Overview citation.'
196
196
  },
197
197
  {
198
198
  id: 20,
@@ -201,7 +201,7 @@ module GSC
201
201
  title: 'Mobile vs Desktop SERP Parity Audit',
202
202
  impact: 'Medium Impact (Fix mobile ranking discrepancies)',
203
203
  cli_command: 'gsc devices --json',
204
- template: 'Antigravity, run `gsc devices --json`. Compare Mobile CTR vs Desktop CTR for {{domain}}. If mobile CTR lags by more than 30%, inspect our mobile viewport layouts, tap target sizes, and above-the-fold content density.'
204
+ template: 'Run `gsc devices --json`. Compare Mobile CTR vs Desktop CTR for {{domain}}. If mobile CTR lags by more than 30%, inspect our mobile viewport layouts, tap target sizes, and above-the-fold content density.'
205
205
  },
206
206
 
207
207
  # Category: Executive Briefings & Daily Standups
@@ -212,7 +212,7 @@ module GSC
212
212
  title: '360° Executive SEO Health Briefing',
213
213
  impact: 'High Impact (Complete C-Suite progress report)',
214
214
  cli_command: 'gsc performance --days 30 --json',
215
- template: 'Antigravity, run `gsc performance --days 30 --json`, `gsc decay --json`, and `gsc opportunities --json`. Generate a markdown briefing summarizing: Total Clicks & Growth % MoM, Top 3 Emerging Keywords, Top 3 Striking-Distance Opportunities, and 3 Critical Action Items for this sprint.'
215
+ template: 'Run `gsc performance --days 30 --json`, `gsc decay --json`, and `gsc opportunities --json`. Generate a markdown briefing summarizing: Total Clicks & Growth % MoM, Top 3 Emerging Keywords, Top 3 Striking-Distance Opportunities, and 3 Critical Action Items for this sprint.'
216
216
  },
217
217
  {
218
218
  id: 22,
@@ -221,7 +221,7 @@ module GSC
221
221
  title: 'New Feature Launch Indexing Blitz',
222
222
  impact: 'High Impact (Index new releases within hours)',
223
223
  cli_command: 'gsc index {{url}} --json',
224
- template: 'Antigravity, I just launched a new feature/landing page at {{url}}. Inspect its metadata, verify Schema markup, confirm robots.txt accessibility, and immediately submit it to Google Indexing API via `gsc index {{url}}`.'
224
+ template: 'Inspect the metadata, verify Schema markup, confirm robots.txt accessibility, and immediately submit our newly launched page at {{url}} to Google Indexing API via `gsc index {{url}}`.'
225
225
  },
226
226
  {
227
227
  id: 23,
@@ -230,7 +230,7 @@ module GSC
230
230
  title: 'Geographic Market Expansion Diagnostic',
231
231
  impact: 'Medium Impact (Find international expansion markets)',
232
232
  cli_command: 'gsc countries --limit 20 --json',
233
- template: 'Antigravity, run `gsc countries --limit 20 --json` and `gsc cities --limit 20 --json`. Identify our top 3 international or regional markets outside our primary country. Check if localized currency, language, or shipping details are needed on those landing pages.'
233
+ template: 'Run `gsc countries --limit 20 --json` and `gsc cities --limit 20 --json`. Identify our top 3 international or regional markets outside our primary country. Check if localized currency, language, or shipping details are needed on those landing pages.'
234
234
  },
235
235
  {
236
236
  id: 24,
@@ -239,7 +239,7 @@ module GSC
239
239
  title: 'Title Tag Pixel Width & Truncation Audit',
240
240
  impact: 'Medium Impact (Prevent Google ... truncation on all pages)',
241
241
  cli_command: 'gsc top-pages --limit 25 --json',
242
- template: 'Antigravity, crawl our sitemap via `gsc inspect-sitemap --json`, extract all page <title> tags from our repository, and flag any titles under 40 characters (too short) or over 60 characters (truncated by Google with ...). Propose rewritten versions for all flagged titles.'
242
+ template: 'Crawl our sitemap via `gsc inspect-sitemap --json`, extract all page <title> tags from our repository, and flag any titles under 40 characters (too short) or over 60 characters (truncated by Google with ...). Propose rewritten versions for all flagged titles.'
243
243
  },
244
244
  {
245
245
  id: 25,
@@ -248,7 +248,16 @@ module GSC
248
248
  title: 'The Daily 5-Minute SEO Standup',
249
249
  impact: 'High Impact (Daily check of pulses, wins, and anomalies)',
250
250
  cli_command: 'gsc realtime --json',
251
- template: 'Antigravity, run `gsc realtime --json`, `gsc top-queries --limit 5 --json`, and `gsc decay --json`. Give me a 3-bullet standup: (1) Live visitors right now, (2) Yesterday\'s top performing search query, and (3) Any query that saw an unexpected drop requiring attention.'
251
+ template: 'Run `gsc realtime --json`, `gsc top-queries --limit 5 --json`, and `gsc decay --json`. Give me a 3-bullet standup: (1) Live visitors right now, (2) Yesterday\'s top performing search query, and (3) Any query that saw an unexpected drop requiring attention.'
252
+ },
253
+ {
254
+ id: 26,
255
+ category: 'growth',
256
+ category_name: '🚀 Growth & Striking Distance',
257
+ title: 'The Adaptive Question Engine & AI Overview Citation Radar',
258
+ impact: 'Maximum Impact (480d PAA harvest, AI Overview radar, answer synthesis & FAQ injection)',
259
+ cli_command: 'gsc questions-harvest -d {{domain}} --days 480 --synthesize --json',
260
+ template: "Execute an end-to-end autonomous Question Mining, AI Overview Citation Radar, and FAQ Schema Domination workflow for {{domain}}.\n\nStrip all hardcoded brand or niche assumptions—this playbook is 100% adaptive based on the live findings from {{domain}} and previous command outputs.\n\nExecute the following phased workflow step-by-step:\n\n### Phase 1: Deep Retrospective Search Console Harvest (480 Days)\n1. Run `gsc questions-harvest -d {{domain}} --days 480 --json` to uncover every question-intent query that {{domain}} has logged search impressions for across all historical search queries.\n2. Run `gsc strike -d {{domain}} --limit 15 --json` to detect high-impression striking distance queries ranking on Page 2 (Positions 4–20).\n3. From the harvested queries and striking distance results, identify:\n - The Top 3 High-Opportunity Questions (Positions 4–20, prime for rich snippets).\n - Any SERP Defense Questions (Positions 1–3, featured snippet holders).\n - The primary Landing Pages associated with these questions.\n\n### Phase 2: Adaptive Topic & Seed Extraction\n1. Analyze the keywords and questions identified in Phase 1 to dynamically extract the 2–3 core topical entities/themes representing the domain's primary products, services, or features.\n - For example: If queries mention pricing or api integration or security, extract \"pricing\", \"api integration\", etc. Do not assume or hardcode any topic.\n\n### Phase 3: Proactive Live Market Question Mining (People Also Ask & Suggest)\n1. For each core topical entity extracted in Phase 2, run:\n - `gsc questions \"<extracted_seed>\" --limit 20 --json`\n2. Classify discovered market queries into 4 conversion archetypes:\n - How-To / Implementation: Practical questions searchers ask when solving a problem.\n - Commercial Comparison: \"Best\", \"Vs\", \"Alternatives\" searches comparing solutions.\n - Policies & Rules: Compliance, eligibility, and configuration questions.\n - Cost & ROI: Pricing, \"worth it\", and value justification queries.\n\n### Phase 4: Google AI Overview (AIO) Citation Radar\n1. For the top 2 highest-impression queries from Phase 1 and Phase 3, run:\n - `gsc aio-hunter \"<target_query>\" --json`\n2. Analyze the radar telemetry:\n - Is Google displaying an AI Overview (AIO)?\n - What competitor domains does Google cite in the AIO carousel?\n - What specific information-gain statistics or factual bullets are missing from our content that Google is citing from others?\n\n### Phase 5: High-Citability Answer Synthesis & FAQ Schema\n1. Run `gsc questions-harvest -d {{domain}} --days 480 --synthesize --json` to automatically synthesize authoritative, 40–60 word Featured Snippet answers and schema.org FAQPage JSON-LD for our target pages.\n2. For any crucial PAA question discovered in Phase 3 not yet in our GSC logs, run:\n - `gsc answer \"<question>\" --brand {{domain}}`\n to synthesize a high-citability direct answer block with targeted information gain.\n\n### Phase 6: Codebase Integration & Instant Indexing\n1. Locate the source files in our local repository corresponding to the target landing page URLs (e.g. Markdown, HTML, Liquid, JSX/TSX, or Astro/Svelte templates).\n2. Insert an H2/H3 FAQ section containing the synthesized questions and authoritative answers.\n3. Embed the generated `<script type=\"application/ld+json\">` FAQPage schema into the page <head> or body.\n4. Notify Googlebot immediately of the enriched content by triggering:\n - `gsc index <target_url>`\n\nDeliver the final executive summary including:\n- Total questions harvested and new market questions discovered.\n- AI Overview radar assessment (AIO presence, cited competitors, citation strategy).\n- Exact file paths modified and diff of FAQ / schema additions.\n- Google Indexing API submission confirmations."
252
261
  }
253
262
  ].freeze
254
263
 
@@ -272,9 +281,9 @@ module GSC
272
281
  item = find(id)
273
282
  return nil unless item
274
283
 
275
- dom = domain || Config.default_domain || 'example.com'
276
- s = seed || 'moving boxes'
277
- u = url || "https://#{dom}"
284
+ dom = domain || Config.default_domain || '<your-domain.com>'
285
+ s = seed || '<target-keyword>'
286
+ u = url || (dom == '<your-domain.com>' ? '<target-url>' : "https://#{dom}")
278
287
 
279
288
  item[:template]
280
289
  .gsub('{{domain}}', dom)
@@ -0,0 +1,178 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'json'
4
+
5
+ module GSC
6
+ class QuestionsHarvester
7
+ QUESTION_WORDS = %w[
8
+ who what where when why how can does do did is are should which will would could
9
+ ].freeze
10
+
11
+ PHRASE_PATTERNS = [
12
+ /\b(difference between|vs|versus|compared to)\b/i,
13
+ /\b(best way to|how to|guide to|ways to|steps to)\b/i,
14
+ /\b(provider|providers|apps?|tools?|alternatives?|options?|solutions?)\s+(that|to|for|with)\b/i,
15
+ /\b(worth it|is it worth)\b/i,
16
+ /\b(pros and cons)\b/i,
17
+ /\?$/
18
+ ].freeze
19
+
20
+ def self.harvest(rows, min_imp: 1, filter_page: nil, brand: nil, synthesize: false)
21
+ # rows: Array of {"keys" => [query, page], "clicks" => n, "impressions" => n, "ctr" => f, "position" => f}
22
+ raw_questions = {}
23
+
24
+ rows.each do |r|
25
+ keys = r['keys'] || []
26
+ query = keys[0].to_s.strip
27
+ page = keys[1].to_s.strip
28
+
29
+ next if query.empty?
30
+ next if filter_page && !page.downcase.include?(filter_page.downcase)
31
+
32
+ q_lower = query.downcase
33
+ is_question = false
34
+ matched_type = nil
35
+
36
+ # Check question words as distinct tokens
37
+ QUESTION_WORDS.each do |w|
38
+ if q_lower =~ /\b#{w}\b/
39
+ is_question = true
40
+ matched_type ||= w.upcase
41
+ break
42
+ end
43
+ end
44
+
45
+ # Check phrase patterns
46
+ unless is_question
47
+ PHRASE_PATTERNS.each do |pat|
48
+ if q_lower =~ pat
49
+ is_question = true
50
+ matched_type = 'PHRASE'
51
+ break
52
+ end
53
+ end
54
+ end
55
+
56
+ next unless is_question
57
+
58
+ clicks = (r['clicks'] || 0).to_i
59
+ impressions = (r['impressions'] || 0).to_i
60
+ ctr = (r['ctr'] || 0.0).to_f
61
+ position = (r['position'] || 0.0).to_f.round(1)
62
+
63
+ next if impressions < min_imp
64
+
65
+ # Capitalize query nicely as question sentence
66
+ formatted_question = query.sub(/^[a-z]/, &:upcase)
67
+ formatted_question += '?' unless formatted_question.end_with?('?')
68
+
69
+ dedup_key = [formatted_question.downcase, page.downcase]
70
+
71
+ if raw_questions[dedup_key]
72
+ existing = raw_questions[dedup_key]
73
+ existing[:clicks] += clicks
74
+ existing[:impressions] += impressions
75
+ existing[:position] = [existing[:position], position].min
76
+ existing[:ctr] = existing[:impressions].positive? ? ((existing[:clicks].to_f / existing[:impressions]) * 100.0).round(2) : 0.0
77
+ existing[:tier] = classify_tier(existing[:position], existing[:impressions])
78
+ existing[:opportunity_score] = calculate_opportunity_score(existing[:impressions], existing[:position], existing[:clicks])
79
+ else
80
+ opp_tier = classify_tier(position, impressions)
81
+ score = calculate_opportunity_score(impressions, position, clicks)
82
+
83
+ raw_questions[dedup_key] = {
84
+ raw_query: query,
85
+ question: formatted_question,
86
+ type: matched_type,
87
+ page: page,
88
+ clicks: clicks,
89
+ impressions: impressions,
90
+ ctr: (ctr * 100).round(2),
91
+ position: position,
92
+ tier: opp_tier,
93
+ opportunity_score: score
94
+ }
95
+ end
96
+ end
97
+
98
+ # Sort: High opportunity first, then by impressions descending
99
+ sorted_questions = raw_questions.values.sort_by { |q| [-q[:opportunity_score], -q[:impressions]] }
100
+
101
+ # Group by page
102
+ by_page = Hash.new { |h, k| h[k] = [] }
103
+ sorted_questions.each do |q|
104
+ by_page[q[:page]] << q
105
+ end
106
+
107
+ {
108
+ total_questions_harvested: sorted_questions.size,
109
+ high_opportunity_count: sorted_questions.count { |q| q[:tier] == 'HIGH_OPPORTUNITY' },
110
+ defense_count: sorted_questions.count { |q| q[:tier] == 'SERP_DEFENSE' },
111
+ pages_covered: by_page.keys.size,
112
+ questions: sorted_questions,
113
+ grouped_by_page: by_page,
114
+ recommended_faq_schemas: generate_faq_schemas(by_page, brand: brand, synthesize: synthesize)
115
+ }
116
+ end
117
+
118
+ def self.classify_tier(position, impressions)
119
+ if position.between?(4.0, 20.0) && impressions >= 3
120
+ 'HIGH_OPPORTUNITY'
121
+ elsif position.between?(1.0, 3.9)
122
+ 'SERP_DEFENSE'
123
+ else
124
+ 'LONG_TAIL'
125
+ end
126
+ end
127
+
128
+ def self.calculate_opportunity_score(impressions, position, clicks)
129
+ # Weight: High impressions ranking in striking distance (pos 4-20) gets highest score
130
+ pos_factor = case position
131
+ when 4.0..10.0 then 3.0 # Page 1 striking distance (huge win potential)
132
+ when 11.0..20.0 then 2.0 # Page 2 striking distance
133
+ when 1.0..3.9 then 1.5 # Defend position 1-3
134
+ else 0.8
135
+ end
136
+
137
+ ((impressions * pos_factor) + (clicks * 5)).round(1)
138
+ end
139
+
140
+ def self.generate_faq_schemas(grouped_by_page, max_per_page: 5, brand: nil, synthesize: false)
141
+ schemas = {}
142
+
143
+ grouped_by_page.each do |page, q_list|
144
+ top_qs = q_list.first(max_per_page)
145
+ entities = top_qs.map do |q|
146
+ answer_text = if synthesize
147
+ begin
148
+ require_relative 'answer_synthesizer' unless defined?(GSC::AnswerSynthesizer)
149
+ res = GSC::AnswerSynthesizer.synthesize(q[:question], brand: brand)
150
+ res[:direct_answer]
151
+ rescue StandardError
152
+ "Authoritative answer explaining #{q[:question]} for #{page.sub(%r{^https?://[^/]+}, '')}."
153
+ end
154
+ else
155
+ "Detailed guidance answering \"#{q[:question]}\" for #{page.sub(%r{^https?://[^/]+}, '')}."
156
+ end
157
+
158
+ {
159
+ '@type' => 'Question',
160
+ 'name' => q[:question],
161
+ 'acceptedAnswer' => {
162
+ '@type' => 'Answer',
163
+ 'text' => answer_text
164
+ }
165
+ }
166
+ end
167
+
168
+ schemas[page] = {
169
+ '@context' => 'https://schema.org',
170
+ '@type' => 'FAQPage',
171
+ 'mainEntity' => entities
172
+ }
173
+ end
174
+
175
+ schemas
176
+ end
177
+ end
178
+ end