gsc-cli 2.1.0 â 2.2.2
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.
- checksums.yaml +4 -4
- data/AUTH.md +4 -1
- data/README.md +448 -408
- data/bin/gsc +28067 -5661
- data/dist/gsc +29121 -5046
- data/lib/gsc/aio_hunter.rb +343 -0
- data/lib/gsc/answer_synthesizer.rb +157 -0
- data/lib/gsc/api.rb +53 -1
- data/lib/gsc/auth.rb +26 -0
- data/lib/gsc/brand_segmenter.rb +140 -0
- data/lib/gsc/cache_manager.rb +806 -0
- data/lib/gsc/cannibalization_analyzer.rb +141 -0
- data/lib/gsc/canonical_chains.rb +367 -0
- data/lib/gsc/citation_simulator.rb +339 -0
- data/lib/gsc/cli/aio_hunter.rb +154 -0
- data/lib/gsc/cli/analytics.rb +788 -0
- data/lib/gsc/cli/audit.rb +1976 -0
- data/lib/gsc/cli/base.rb +384 -0
- data/lib/gsc/cli/cache.rb +266 -0
- data/lib/gsc/cli/canonical.rb +223 -0
- data/lib/gsc/cli/citation_simulator.rb +152 -0
- data/lib/gsc/cli/dashboard.rb +354 -0
- data/lib/gsc/cli/doctor.rb +129 -0
- data/lib/gsc/cli/eeat.rb +125 -0
- data/lib/gsc/cli/ga4.rb +852 -0
- data/lib/gsc/cli/growth.rb +650 -0
- data/lib/gsc/cli/hreflang.rb +164 -0
- data/lib/gsc/cli/image_seo.rb +162 -0
- data/lib/gsc/cli/indexing.rb +458 -0
- data/lib/gsc/cli/intent_shift.rb +125 -0
- data/lib/gsc/cli/keyword_value.rb +134 -0
- data/lib/gsc/cli/keywords.rb +795 -0
- data/lib/gsc/cli/landing_roi.rb +308 -0
- data/lib/gsc/cli/low_ctr.rb +213 -0
- data/lib/gsc/cli/mobile_parity.rb +150 -0
- data/lib/gsc/cli/report.rb +100 -0
- data/lib/gsc/cli/rich_results.rb +172 -0
- data/lib/gsc/cli/schema_generate.rb +149 -0
- data/lib/gsc/cli/seasonal.rb +232 -0
- data/lib/gsc/cli/security.rb +153 -0
- data/lib/gsc/cli/setup.rb +1291 -0
- data/lib/gsc/cli/sitemap_tree.rb +143 -0
- data/lib/gsc/cli/skill_pack.rb +62 -0
- data/lib/gsc/cli/soft_404.rb +199 -0
- data/lib/gsc/cli/sparkline.rb +227 -0
- data/lib/gsc/cli/watchdog.rb +150 -0
- data/lib/gsc/cli/zombie_purger.rb +208 -0
- data/lib/gsc/cli.rb +707 -5265
- data/lib/gsc/cli_advanced.rb +987 -44
- data/lib/gsc/client.rb +17 -2
- data/lib/gsc/color.rb +16 -1
- data/lib/gsc/command_registry.rb +47 -9
- data/lib/gsc/config.rb +2 -2
- data/lib/gsc/ctr_curve.rb +115 -0
- data/lib/gsc/decay_predictor.rb +322 -0
- data/lib/gsc/doctor.rb +434 -0
- data/lib/gsc/eeat_auditor.rb +428 -0
- data/lib/gsc/entity_auditor.rb +229 -0
- data/lib/gsc/firewall_scanner.rb +733 -0
- data/lib/gsc/geo_auditor.rb +368 -0
- data/lib/gsc/google_trends.rb +8 -1
- data/lib/gsc/heading_validator.rb +283 -0
- data/lib/gsc/hreflang_validator.rb +412 -0
- data/lib/gsc/image_seo.rb +286 -0
- data/lib/gsc/indexing_queue.rb +179 -0
- data/lib/gsc/indexnow.rb +93 -0
- data/lib/gsc/intent_shift.rb +188 -0
- data/lib/gsc/internal_links.rb +153 -36
- data/lib/gsc/keyword_value.rb +191 -0
- data/lib/gsc/landing_roi.rb +195 -0
- data/lib/gsc/llms_generator.rb +343 -22
- data/lib/gsc/low_ctr_rewriter.rb +408 -0
- data/lib/gsc/mobile_parity.rb +222 -0
- data/lib/gsc/network_tracer.rb +8 -1
- data/lib/gsc/page_analyzer.rb +47 -7
- data/lib/gsc/prompts.rb +38 -29
- data/lib/gsc/questions_harvester.rb +178 -0
- data/lib/gsc/report_generator.rb +461 -0
- data/lib/gsc/rich_results.rb +388 -0
- data/lib/gsc/robots_checker.rb +46 -15
- data/lib/gsc/schema_generator.rb +788 -0
- data/lib/gsc/schema_validator.rb +36 -38
- data/lib/gsc/seasonal_predictor.rb +381 -0
- data/lib/gsc/security_scanner.rb +496 -0
- data/lib/gsc/serp_feature_detector.rb +359 -0
- data/lib/gsc/serp_preview.rb +108 -22
- data/lib/gsc/site_crawler.rb +113 -21
- data/lib/gsc/sitemap_loader.rb +15 -4
- data/lib/gsc/sitemap_tree.rb +301 -0
- data/lib/gsc/skill_pack.rb +195 -0
- data/lib/gsc/soft_404_analyzer.rb +385 -0
- data/lib/gsc/sparkline.rb +171 -0
- data/lib/gsc/speed_correlator.rb +416 -0
- data/lib/gsc/striking_playbook.rb +190 -0
- data/lib/gsc/title_optimizer.rb +420 -0
- data/lib/gsc/vault.rb +260 -0
- data/lib/gsc/version.rb +1 -1
- data/lib/gsc/watchdog.rb +235 -0
- data/lib/gsc/zombie_purger.rb +366 -0
- data/lib/gsc.rb +118 -0
- metadata +75 -1
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
# encoding: utf-8
|
|
2
|
+
# frozen_string_literal: true
|
|
3
|
+
|
|
4
|
+
require 'json'
|
|
5
|
+
require_relative 'base'
|
|
6
|
+
require_relative '../keyword_value'
|
|
7
|
+
require_relative '../color'
|
|
8
|
+
|
|
9
|
+
module GSC
|
|
10
|
+
class CLI
|
|
11
|
+
module KeywordValue
|
|
12
|
+
module_function
|
|
13
|
+
|
|
14
|
+
def run(command, target, extra, options, api = nil, site_url = nil, hostname = nil)
|
|
15
|
+
target_domain = target || hostname || (Config.default_domain rescue nil)
|
|
16
|
+
if target_domain.nil? || target_domain.to_s.strip.empty?
|
|
17
|
+
if options[:json]
|
|
18
|
+
puts JSON.pretty_generate({ error: 'Target domain required. Example: gsc kw-value mysite.com or gsc use mysite.com' })
|
|
19
|
+
else
|
|
20
|
+
puts Color.c("â Error: Target domain required. Example: gsc kw-value mysite.com or gsc use mysite.com", Color::RED, Color::BOLD)
|
|
21
|
+
end
|
|
22
|
+
return
|
|
23
|
+
end
|
|
24
|
+
target_domain = target_domain.sub(%r{^https?://}, '').sub(%r{/.*$}, '')
|
|
25
|
+
|
|
26
|
+
puts "đ° Modeling conversion-weighted keyword revenue matrix for #{Color.cyan(target_domain)}..." unless options[:json]
|
|
27
|
+
|
|
28
|
+
res = GSC::KeywordValue.analyze(options, api, target_domain)
|
|
29
|
+
|
|
30
|
+
if options[:json]
|
|
31
|
+
puts JSON.pretty_generate(res)
|
|
32
|
+
return
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
render_terminal(res, options)
|
|
36
|
+
|
|
37
|
+
if options[:csv]
|
|
38
|
+
export_csv(res, options[:csv])
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def render_terminal(res, options = {})
|
|
43
|
+
f = res[:financials]
|
|
44
|
+
p = res[:parameters]
|
|
45
|
+
|
|
46
|
+
puts "\n#{Color.bold("âââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââ")}"
|
|
47
|
+
puts "#{Color.bold("đ° CONVERSION-WEIGHTED KEYWORD VALUE & REVENUE UPSIDE MATRIX")}"
|
|
48
|
+
puts "#{Color.bold("âââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââ")}"
|
|
49
|
+
|
|
50
|
+
puts " âĸ Monitored Domain: #{Color.bold(res[:domain])}"
|
|
51
|
+
customized = options[:aov] || options[:conv_rate] || options[:margin]
|
|
52
|
+
param_label = customized ? Color.green("(Custom Model)") : Color.gray("(Defaults: override with --aov, --conv-rate, --margin)")
|
|
53
|
+
puts " âĸ Economic Parameters: AOV: $#{p[:aov]} | Conv Rate: #{p[:conversion_rate_pct]}% | Margin: #{p[:profit_margin_pct]}% #{param_label}"
|
|
54
|
+
puts " âĸ Current Monthly Organic Rev: #{Color.bold("$" + format_num(f[:current_monthly_revenue]))} ($#{format_num(f[:current_annual_run_rate])}/yr run rate)"
|
|
55
|
+
puts " âĸ Potential Top #{p[:target_position]} Monthly Revenue: #{Color.green("$" + format_num(f[:potential_monthly_revenue]))}"
|
|
56
|
+
puts " âĸ Unlocked Monthly Revenue Gap: #{Color.bold(Color.green("+$" + format_num(f[:unlocked_monthly_upside])))}/mo"
|
|
57
|
+
puts " âĸ Unlocked Annual Pipeline Upside: #{Color.bold(Color.green("+$" + format_num(f[:unlocked_annual_pipeline_upside])))}/yr"
|
|
58
|
+
puts "#{Color.bold("âââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââ")}\n"
|
|
59
|
+
|
|
60
|
+
if res[:keywords].empty?
|
|
61
|
+
puts " âšī¸ No Search Console query performance data found for #{res[:domain]}."
|
|
62
|
+
puts " Connect Google Search Console credentials via `gsc setup` or specify a verified property with `--domain <domain>`."
|
|
63
|
+
puts "\n#{Color.bold("âââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââ")}\n"
|
|
64
|
+
return
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
puts "#{Color.bold("TOP HIGH-ROI KEYWORD REVENUE OPPORTUNITIES:")}\n\n"
|
|
68
|
+
printf " %-30s %-7s %-8s %-12s %-12s %-14s %s\n", "Search Query", "Intent", "Pos", "Current Rev", "Top 3 Rev", "Monthly Upside", "Score"
|
|
69
|
+
puts " ---------------------------------------------------------------------------------------------------"
|
|
70
|
+
|
|
71
|
+
res[:keywords].each do |k|
|
|
72
|
+
q_str = k[:query].length > 28 ? "#{k[:query][0..25]}..." : k[:query]
|
|
73
|
+
intent_str = case k[:intent]
|
|
74
|
+
when :transactional then Color.green("BUY")
|
|
75
|
+
when :commercial then Color.cyan("COMM")
|
|
76
|
+
when :navigational then Color.yellow("NAV")
|
|
77
|
+
else "INFO"
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
upside_str = k[:monthly_revenue_upside] > 0 ? Color.green("+$" + format_num(k[:monthly_revenue_upside])) : "$0"
|
|
81
|
+
score_str = k[:value_score] >= 70 ? Color.green(k[:value_score].to_s) : k[:value_score].to_s
|
|
82
|
+
|
|
83
|
+
printf " %-30s %-7s Pos %-4s $%-11s $%-11s %-14s [ %s ]\n",
|
|
84
|
+
q_str,
|
|
85
|
+
intent_str,
|
|
86
|
+
k[:position],
|
|
87
|
+
format_num(k[:current_monthly_revenue]),
|
|
88
|
+
format_num(k[:potential_monthly_revenue]),
|
|
89
|
+
upside_str,
|
|
90
|
+
score_str
|
|
91
|
+
|
|
92
|
+
if k[:action] && k[:monthly_revenue_upside] > 50.0
|
|
93
|
+
puts " #{Color.yellow("âŗ")} #{k[:action]}"
|
|
94
|
+
end
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
puts "\n#{Color.bold("âââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââ")}"
|
|
98
|
+
puts "#{Color.bold("đĄ STRATEGIC EXECUTION ADVICE:")}"
|
|
99
|
+
puts " Focus engineering on Page-1 and Page-2 keywords with BUY intent. Even modest rank improvements"
|
|
100
|
+
puts " deliver compounding recurring pipeline without increasing paid ad acquisition costs."
|
|
101
|
+
puts "#{Color.bold("âââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââ")}\n"
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
def export_csv(res, file_path)
|
|
105
|
+
headers = %w[Query Intent Position Impressions Clicks CTR ConvRate CurrentOrders CurrentRevenue PotentialClicks PotentialRevenue MonthlyUpside AnnualUpside ValueScore StrategicAction]
|
|
106
|
+
rows = res[:keywords].map do |k|
|
|
107
|
+
[
|
|
108
|
+
k[:query],
|
|
109
|
+
k[:intent].to_s,
|
|
110
|
+
k[:position],
|
|
111
|
+
k[:impressions],
|
|
112
|
+
k[:clicks],
|
|
113
|
+
k[:ctr],
|
|
114
|
+
k[:effective_conv_rate],
|
|
115
|
+
k[:current_orders],
|
|
116
|
+
k[:current_monthly_revenue],
|
|
117
|
+
k[:potential_clicks],
|
|
118
|
+
k[:potential_monthly_revenue],
|
|
119
|
+
k[:monthly_revenue_upside],
|
|
120
|
+
k[:annual_revenue_upside],
|
|
121
|
+
k[:value_score],
|
|
122
|
+
k[:action]
|
|
123
|
+
]
|
|
124
|
+
end
|
|
125
|
+
Base.write_csv(file_path, headers, rows)
|
|
126
|
+
puts Color.cyan("đ Successfully exported keyword value matrix to #{file_path}")
|
|
127
|
+
end
|
|
128
|
+
|
|
129
|
+
def format_num(val)
|
|
130
|
+
val.to_s.reverse.gsub(/(\d{3})(?=\d)/, '\\1,').reverse
|
|
131
|
+
end
|
|
132
|
+
end
|
|
133
|
+
end
|
|
134
|
+
end
|