hive-rank 3.2.0 → 3.4.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.
package/README.md CHANGED
@@ -4,7 +4,7 @@ Crowdsourced SEO intelligence for AI agents.
4
4
 
5
5
  ## What is this?
6
6
 
7
- Hive Rank aggregates anonymized search data from Claude Code agents into a shared ranking dataset. Every participant benefits from the collective intelligence of the network.
7
+ Hive Rank aggregates anonymized search data from AI coding agents into a shared ranking dataset. Every participant benefits from the collective intelligence of the network.
8
8
 
9
9
  **AI agents are searching for your product right now. Do you know where you rank?**
10
10
 
@@ -14,27 +14,62 @@ Hive Rank aggregates anonymized search data from Claude Code agents into a share
14
14
  npx hive-rank
15
15
  ```
16
16
 
17
+ The installer auto-detects Claude Code, OpenCode, and Codex CLI and configures all detected platforms.
18
+
17
19
  Or add the MCP server directly:
18
20
 
21
+ **Claude Code:**
19
22
  ```bash
20
23
  claude mcp add --transport http hive-rank https://mcp.hive-rank.com/mcp
21
24
  ```
22
25
 
26
+ **OpenCode** — add to `~/.config/opencode/opencode.json`:
27
+ ```json
28
+ {
29
+ "mcp": {
30
+ "hive-rank": {
31
+ "type": "remote",
32
+ "url": "https://mcp.hive-rank.com/mcp",
33
+ "enabled": true
34
+ }
35
+ }
36
+ }
37
+ ```
38
+
39
+ **Codex CLI** — add to `~/.codex/config.toml`:
40
+ ```toml
41
+ [features]
42
+ experimental_use_rmcp_client = true
43
+
44
+ [mcp_servers.hive_rank]
45
+ url = "https://mcp.hive-rank.com/mcp"
46
+ ```
47
+
48
+ ## Platform Capabilities
49
+
50
+ | Feature | Claude Code | OpenCode | Codex CLI |
51
+ |---------|------------|----------|-----------|
52
+ | MCP query tools | Yes | Yes | Yes |
53
+ | Data capture (hooks) | Yes | No | No |
54
+ | Slash commands (21) | Yes | No | No |
55
+ | Auto-install | Yes | Yes | Yes |
56
+
23
57
  ## What you get
24
58
 
25
- ### 7 MCP Tools
59
+ ### 8 MCP Tools
26
60
 
27
61
  | Tool | Description |
28
62
  |------|-------------|
29
63
  | `hive_rankings` | Aggregated rankings from the network for a query |
30
64
  | `hive_trending` | Trending queries across the network |
31
65
  | `hive_domain` | Network intelligence for a domain |
66
+ | `hive_score` | Domain hive score (0-100) |
32
67
  | `hive_stats` | Network-wide statistics |
33
68
  | `hive_contributors` | Contributor activity stats |
34
69
  | `hive_search` | Full-text search across network queries |
35
70
  | `hive_contribute` | Contribute search/page observations to the network |
36
71
 
37
- ### 20 Slash Commands
72
+ ### 21 Slash Commands
38
73
 
39
74
  Research commands:
40
75
 
@@ -53,6 +88,7 @@ Network intelligence commands:
53
88
  - `/hive:rankings [query]` — Check network ranking data
54
89
  - `/hive:trends` — See what's trending
55
90
  - `/hive:status` — Network status and your contribution stats
91
+ - `/hive:score [domain]` — Domain hive score (0-100)
56
92
  - `/hive:report [domain]` — Generate SEO report from network data
57
93
  - `/hive:audit` — Check network contribution status
58
94
  - `/hive:glossary [term]` — Look up any SEO term
package/bin/install.js CHANGED
@@ -29,6 +29,12 @@ const CLAUDE_DIR = path.join(HOME, '.claude');
29
29
  const COMMANDS_DIR = path.join(CLAUDE_DIR, 'commands', 'hive');
30
30
  const PKG_ROOT = path.resolve(new URL('..', import.meta.url).pathname);
31
31
 
32
+ const OPENCODE_CONFIG_DIR = path.join(HOME, '.config', 'opencode');
33
+ const OPENCODE_CONFIG_FILE = path.join(OPENCODE_CONFIG_DIR, 'opencode.json');
34
+
35
+ const CODEX_DIR = path.join(HOME, '.codex');
36
+ const CODEX_CONFIG_FILE = path.join(CODEX_DIR, 'config.toml');
37
+
32
38
  const MCP_NAME = 'hive-rank';
33
39
  const MCP_URL = 'https://mcp.hive-rank.com/mcp';
34
40
  const SETTINGS_FILE = path.join(CLAUDE_DIR, 'settings.json');
@@ -58,6 +64,118 @@ function writeJsonAtomic(p, obj) {
58
64
  fs.renameSync(tmp, p);
59
65
  }
60
66
 
67
+ // ── TOML helpers (minimal, no deps) ──────────────────────────────────────────
68
+
69
+ function parseToml(text) {
70
+ const result = {};
71
+ let currentSection = null;
72
+
73
+ for (const raw of text.split('\n')) {
74
+ const line = raw.trim();
75
+ if (!line || line.startsWith('#')) continue;
76
+
77
+ // Section header: [foo] or [foo.bar]
78
+ const sectionMatch = line.match(/^\[([^\]]+)\]$/);
79
+ if (sectionMatch) {
80
+ const parts = sectionMatch[1].split('.');
81
+ let target = result;
82
+ for (const part of parts) {
83
+ if (!target[part] || typeof target[part] !== 'object') target[part] = {};
84
+ target = target[part];
85
+ }
86
+ currentSection = parts;
87
+ continue;
88
+ }
89
+
90
+ // Key = value
91
+ const kvMatch = line.match(/^(\w+)\s*=\s*(.+)$/);
92
+ if (kvMatch) {
93
+ const key = kvMatch[1];
94
+ let val = kvMatch[2].trim();
95
+ // Parse value type
96
+ if (val === 'true') val = true;
97
+ else if (val === 'false') val = false;
98
+ else if (/^-?\d+(\.\d+)?$/.test(val)) val = Number(val);
99
+ else if ((val.startsWith('"') && val.endsWith('"')) || (val.startsWith("'") && val.endsWith("'")))
100
+ val = val.slice(1, -1);
101
+
102
+ if (currentSection) {
103
+ let target = result;
104
+ for (const part of currentSection) target = target[part];
105
+ target[key] = val;
106
+ } else {
107
+ result[key] = val;
108
+ }
109
+ }
110
+ }
111
+ return result;
112
+ }
113
+
114
+ function serializeToml(obj, prefix = '') {
115
+ let lines = [];
116
+ const simple = {};
117
+ const sections = {};
118
+
119
+ for (const [k, v] of Object.entries(obj)) {
120
+ if (v !== null && typeof v === 'object' && !Array.isArray(v)) {
121
+ sections[k] = v;
122
+ } else {
123
+ simple[k] = v;
124
+ }
125
+ }
126
+
127
+ // Write simple key-value pairs
128
+ for (const [k, v] of Object.entries(simple)) {
129
+ if (typeof v === 'string') lines.push(`${k} = "${v}"`);
130
+ else lines.push(`${k} = ${v}`);
131
+ }
132
+
133
+ // Write sections
134
+ for (const [k, v] of Object.entries(sections)) {
135
+ const sectionKey = prefix ? `${prefix}.${k}` : k;
136
+ // Check if this section has only simple values (leaf section)
137
+ const hasNestedObjects = Object.values(v).some(val => val !== null && typeof val === 'object' && !Array.isArray(val));
138
+
139
+ if (!hasNestedObjects) {
140
+ if (lines.length > 0) lines.push('');
141
+ lines.push(`[${sectionKey}]`);
142
+ for (const [sk, sv] of Object.entries(v)) {
143
+ if (typeof sv === 'string') lines.push(`${sk} = "${sv}"`);
144
+ else lines.push(`${sk} = ${sv}`);
145
+ }
146
+ } else {
147
+ // Recurse for nested sections, writing any simple values first
148
+ const nestedSimple = {};
149
+ const nestedSections = {};
150
+ for (const [sk, sv] of Object.entries(v)) {
151
+ if (sv !== null && typeof sv === 'object' && !Array.isArray(sv)) {
152
+ nestedSections[sk] = sv;
153
+ } else {
154
+ nestedSimple[sk] = sv;
155
+ }
156
+ }
157
+ if (Object.keys(nestedSimple).length > 0) {
158
+ if (lines.length > 0) lines.push('');
159
+ lines.push(`[${sectionKey}]`);
160
+ for (const [sk, sv] of Object.entries(nestedSimple)) {
161
+ if (typeof sv === 'string') lines.push(`${sk} = "${sv}"`);
162
+ else lines.push(`${sk} = ${sv}`);
163
+ }
164
+ }
165
+ const nested = serializeToml(nestedSections, sectionKey);
166
+ if (nested) lines.push('', nested);
167
+ }
168
+ }
169
+
170
+ return lines.join('\n');
171
+ }
172
+
173
+ function writeTomlAtomic(p, obj) {
174
+ const tmp = p + '.tmp.' + crypto.randomBytes(4).toString('hex');
175
+ fs.writeFileSync(tmp, serializeToml(obj) + '\n', 'utf-8');
176
+ fs.renameSync(tmp, p);
177
+ }
178
+
61
179
  function copyRecursive(src, dest) {
62
180
  if (!fileExists(src)) return;
63
181
  const stat = fs.statSync(src);
@@ -92,6 +210,118 @@ function hasClaudeCli() {
92
210
  }
93
211
  }
94
212
 
213
+ function hasOpenCode() {
214
+ // Check for opencode CLI in PATH
215
+ try {
216
+ const result = spawnSync('opencode', ['--version'], { stdio: 'pipe', timeout: 5000 });
217
+ if (result.status === 0) return true;
218
+ } catch { /* not in PATH */ }
219
+ // Check for config directory existence
220
+ return fileExists(OPENCODE_CONFIG_DIR);
221
+ }
222
+
223
+ function hasCodexCli() {
224
+ try {
225
+ const result = spawnSync('codex', ['--version'], { stdio: 'pipe', timeout: 5000 });
226
+ if (result.status === 0) return true;
227
+ } catch { /* not in PATH */ }
228
+ return fileExists(CODEX_DIR);
229
+ }
230
+
231
+ function registerCodexMcp() {
232
+ fs.mkdirSync(CODEX_DIR, { recursive: true });
233
+
234
+ let config = {};
235
+ if (fileExists(CODEX_CONFIG_FILE)) {
236
+ try {
237
+ config = parseToml(fs.readFileSync(CODEX_CONFIG_FILE, 'utf-8'));
238
+ } catch {
239
+ warn('~/.codex/config.toml exists but could not be parsed. Skipping Codex MCP registration.');
240
+ return 'skipped';
241
+ }
242
+ }
243
+
244
+ // Clean up legacy entries
245
+ if (config.mcp_servers) {
246
+ for (const oldName of ['gys_local', 'hive_seo', 'grow_your_shit', 'hive_rank']) {
247
+ delete config.mcp_servers[oldName];
248
+ }
249
+ }
250
+
251
+ // Ensure feature flag is set
252
+ if (!config.features) config.features = {};
253
+ config.features.experimental_use_rmcp_client = true;
254
+
255
+ // Register MCP server
256
+ if (!config.mcp_servers) config.mcp_servers = {};
257
+ config.mcp_servers.hive_rank = {
258
+ url: MCP_URL,
259
+ };
260
+
261
+ writeTomlAtomic(CODEX_CONFIG_FILE, config);
262
+ return 'direct';
263
+ }
264
+
265
+ function removeCodexMcp() {
266
+ if (!fileExists(CODEX_CONFIG_FILE)) return;
267
+ try {
268
+ const config = parseToml(fs.readFileSync(CODEX_CONFIG_FILE, 'utf-8'));
269
+ let changed = false;
270
+ if (config.mcp_servers) {
271
+ for (const oldName of ['hive_rank', 'gys_local', 'hive_seo', 'grow_your_shit']) {
272
+ if (config.mcp_servers[oldName]) { delete config.mcp_servers[oldName]; changed = true; }
273
+ }
274
+ if (Object.keys(config.mcp_servers).length === 0) delete config.mcp_servers;
275
+ }
276
+ if (changed) writeTomlAtomic(CODEX_CONFIG_FILE, config);
277
+ } catch { /* ignore */ }
278
+ }
279
+
280
+ function registerOpenCodeMcp() {
281
+ fs.mkdirSync(OPENCODE_CONFIG_DIR, { recursive: true });
282
+
283
+ let config = {};
284
+ if (fileExists(OPENCODE_CONFIG_FILE)) {
285
+ try {
286
+ config = readJson(OPENCODE_CONFIG_FILE);
287
+ } catch {
288
+ warn('~/.config/opencode/opencode.json exists but is not valid JSON. Skipping OpenCode MCP registration.');
289
+ return 'skipped';
290
+ }
291
+ }
292
+
293
+ // Clean up old entries
294
+ if (config.mcp) {
295
+ for (const oldName of ['gys-local', 'hive-seo', 'grow-your-shit', MCP_NAME]) {
296
+ delete config.mcp[oldName];
297
+ }
298
+ }
299
+
300
+ if (!config.mcp) config.mcp = {};
301
+ config.mcp[MCP_NAME] = {
302
+ type: 'remote',
303
+ url: MCP_URL,
304
+ enabled: true
305
+ };
306
+
307
+ writeJsonAtomic(OPENCODE_CONFIG_FILE, config);
308
+ return 'direct';
309
+ }
310
+
311
+ function removeOpenCodeMcp() {
312
+ if (!fileExists(OPENCODE_CONFIG_FILE)) return;
313
+ try {
314
+ const config = readJson(OPENCODE_CONFIG_FILE);
315
+ let changed = false;
316
+ if (config.mcp) {
317
+ for (const oldName of [MCP_NAME, 'gys-local', 'hive-seo', 'grow-your-shit']) {
318
+ if (config.mcp[oldName]) { delete config.mcp[oldName]; changed = true; }
319
+ }
320
+ }
321
+ if (changed) writeJsonAtomic(OPENCODE_CONFIG_FILE, config);
322
+ } catch { /* ignore */ }
323
+ }
324
+
95
325
  function registerMcpServer() {
96
326
  if (hasClaudeCli()) {
97
327
  // Remove old entries from all scopes
@@ -208,7 +438,7 @@ function configureHooks() {
208
438
 
209
439
  // Hook A: activate session on hive MCP tool usage
210
440
  settings.hooks.PostToolUse.push({
211
- matcher: 'mcp__hive-rank__hive_rankings|mcp__hive-rank__hive_trending|mcp__hive-rank__hive_domain|mcp__hive-rank__hive_stats|mcp__hive-rank__hive_contributors|mcp__hive-rank__hive_search',
441
+ matcher: 'mcp__hive-rank__hive_rankings|mcp__hive-rank__hive_trending|mcp__hive-rank__hive_domain|mcp__hive-rank__hive_score|mcp__hive-rank__hive_stats|mcp__hive-rank__hive_contributors|mcp__hive-rank__hive_search',
212
442
  hooks: [{ type: 'command', command: ACTIVATE_HOOK_CMD }]
213
443
  });
214
444
 
@@ -269,14 +499,19 @@ if (FLAG_HELP) {
269
499
  What it does:
270
500
  1. Copies dist + commands + docs to ~/.hive-rank/
271
501
  2. Registers hooks in ~/.claude/settings.json
272
- 3. Registers remote MCP server via \`claude mcp add\` (HTTP transport)
502
+ 3. Registers remote MCP server for detected platforms:
503
+ - Claude Code: via \`claude mcp add\` or ~/.claude.json
504
+ - OpenCode: via ~/.config/opencode/opencode.json
505
+ - Codex CLI: via ~/.codex/config.toml
273
506
  4. Installs slash commands to ~/.claude/commands/hive/
274
507
 
275
508
  Config locations:
276
- Hooks: ~/.claude/settings.json
277
- MCP server: ~/.claude.json (via \`claude mcp add --scope user\`)
278
- Commands: ~/.claude/commands/hive/*.md
279
- Privacy: ~/.hive-rank/PRIVACY.md
509
+ Hooks: ~/.claude/settings.json
510
+ MCP (Claude): ~/.claude.json (via \`claude mcp add --scope user\`)
511
+ MCP (OpenCode): ~/.config/opencode/opencode.json
512
+ MCP (Codex): ~/.codex/config.toml
513
+ Commands: ~/.claude/commands/hive/*.md
514
+ Privacy: ~/.hive-rank/PRIVACY.md
280
515
  `);
281
516
  process.exit(0);
282
517
  }
@@ -287,7 +522,9 @@ if (FLAG_UNINSTALL) {
287
522
  if (FLAG_DRY_RUN) {
288
523
  console.log('\n Uninstalling Hive Rank — DRY RUN (no changes will be made)\n');
289
524
  dryLog('Would remove hooks from ' + SETTINGS_FILE);
290
- dryLog('Would remove MCP server');
525
+ dryLog('Would remove Claude Code MCP server');
526
+ if (fileExists(OPENCODE_CONFIG_FILE)) dryLog('Would remove OpenCode MCP server from ' + OPENCODE_CONFIG_FILE);
527
+ if (fileExists(CODEX_CONFIG_FILE)) dryLog('Would remove Codex CLI MCP server from ' + CODEX_CONFIG_FILE);
291
528
  if (fileExists(COMMANDS_DIR)) dryLog('Would remove slash commands: ' + COMMANDS_DIR);
292
529
  if (fileExists(INSTALL_DIR)) dryLog('Would remove ' + INSTALL_DIR + '/');
293
530
  console.log('\n Dry run complete — no changes were made.\n');
@@ -300,7 +537,13 @@ if (FLAG_UNINSTALL) {
300
537
  success('Removed hooks from settings.json');
301
538
 
302
539
  removeMcpServer();
303
- success('Removed MCP server');
540
+ success('Removed Claude Code MCP server');
541
+
542
+ removeOpenCodeMcp();
543
+ success('Removed OpenCode MCP server');
544
+
545
+ removeCodexMcp();
546
+ success('Removed Codex CLI MCP server');
304
547
 
305
548
  // Remove old gys commands too
306
549
  const oldCommandsDir = path.join(CLAUDE_DIR, 'commands', 'gys');
@@ -328,7 +571,7 @@ if (FLAG_UNINSTALL) {
328
571
  }
329
572
  }
330
573
 
331
- console.log('\n Hive Rank has been uninstalled. Restart Claude Code to apply.\n');
574
+ console.log('\n Hive Rank has been uninstalled. Restart your agent to apply.\n');
332
575
  process.exit(0);
333
576
  }
334
577
 
@@ -435,8 +678,12 @@ async function install() {
435
678
  dryLog('Would copy PRIVACY.md and AGENT.md to ~/.hive-rank/');
436
679
  }
437
680
 
438
- // ── Step 3: Register MCP server ──
681
+ // ── Step 3: Register MCP servers ──
682
+
683
+ // Track which platforms were configured (for summary)
684
+ const platforms = { claudeCode: false, openCode: false, codexCli: false };
439
685
 
686
+ // Claude Code
440
687
  if (FLAG_DRY_RUN) {
441
688
  if (hasClaudeCli()) {
442
689
  dryLog(`Would run: claude mcp add --scope user --transport http ${MCP_NAME} ${MCP_URL}`);
@@ -444,14 +691,48 @@ async function install() {
444
691
  dryLog('Would register MCP server in ~/.claude.json');
445
692
  }
446
693
  } else {
447
- log('Registering remote MCP server...');
694
+ log('Registering MCP server for Claude Code...');
448
695
  const mcpMethod = registerMcpServer();
449
696
  if (mcpMethod === 'cli') {
450
- success('MCP server registered via `claude mcp add` (HTTP transport)');
697
+ success('Claude Code: MCP server registered via `claude mcp add`');
698
+ platforms.claudeCode = true;
451
699
  } else if (mcpMethod === 'direct') {
452
- success('MCP server registered in ~/.claude.json');
700
+ success('Claude Code: MCP server registered in ~/.claude.json');
701
+ platforms.claudeCode = true;
453
702
  } else {
454
- warn('MCP server registration skipped — run manually after install');
703
+ warn('Claude Code: MCP registration skipped');
704
+ }
705
+ }
706
+
707
+ // OpenCode
708
+ if (hasOpenCode()) {
709
+ if (FLAG_DRY_RUN) {
710
+ dryLog(`Would register MCP server in ${OPENCODE_CONFIG_FILE}`);
711
+ } else {
712
+ log('Registering MCP server for OpenCode...');
713
+ const ocMethod = registerOpenCodeMcp();
714
+ if (ocMethod === 'direct') {
715
+ success('OpenCode: MCP server registered in ~/.config/opencode/opencode.json');
716
+ platforms.openCode = true;
717
+ } else {
718
+ warn('OpenCode: MCP registration skipped');
719
+ }
720
+ }
721
+ }
722
+
723
+ // Codex CLI
724
+ if (hasCodexCli()) {
725
+ if (FLAG_DRY_RUN) {
726
+ dryLog(`Would register MCP server in ${CODEX_CONFIG_FILE}`);
727
+ } else {
728
+ log('Registering MCP server for Codex CLI...');
729
+ const cxMethod = registerCodexMcp();
730
+ if (cxMethod === 'direct') {
731
+ success('Codex CLI: MCP server registered in ~/.codex/config.toml');
732
+ platforms.codexCli = true;
733
+ } else {
734
+ warn('Codex CLI: MCP registration skipped');
735
+ }
455
736
  }
456
737
  }
457
738
 
@@ -510,12 +791,20 @@ async function install() {
510
791
  node ${path.join(PKG_ROOT, 'bin', 'install.js')}${FLAG_FORCE ? ' --force' : ''}
511
792
  `);
512
793
  } else {
794
+ const platformLines = [];
795
+ platformLines.push(` Claude Code: ${platforms.claudeCode ? '+ MCP server + capture hooks' : '- not detected'}`);
796
+ platformLines.push(` OpenCode: ${platforms.openCode ? '+ MCP server (query tools)' : '- not detected'}`);
797
+ platformLines.push(` Codex CLI: ${platforms.codexCli ? '+ MCP server (query tools)' : '- not detected'}`);
798
+
513
799
  console.log(`
514
800
  ────────────────────────────────────────────────
515
801
  Hive Rank installed successfully!
516
802
  ────────────────────────────────────────────────
517
803
 
518
- Restart Claude Code, then try:
804
+ Platforms:
805
+ ${platformLines.join('\n')}
806
+
807
+ Restart your agent, then try:
519
808
 
520
809
  /hive:help — See all commands
521
810
  /hive:kickstart — Bootstrap your SEO research
@@ -523,11 +812,11 @@ async function install() {
523
812
  /hive:trends — See what's trending
524
813
 
525
814
  Config:
526
- Hooks: ${SETTINGS_FILE}
527
- MCP server: ${MCP_URL} (via HTTP)
528
- Commands: ${COMMANDS_DIR}/
529
- Privacy: ~/.hive-rank/PRIVACY.md
530
- Controls: /hive:privacy, /hive:delete-data
815
+ Hooks: ${SETTINGS_FILE}
816
+ MCP (Claude): ${MCP_URL} (via HTTP)
817
+ ${platforms.openCode ? `MCP (OpenCode): ${OPENCODE_CONFIG_FILE}\n ` : ''}${platforms.codexCli ? `MCP (Codex): ${CODEX_CONFIG_FILE}\n ` : ''}Commands: ${COMMANDS_DIR}/
818
+ Privacy: ~/.hive-rank/PRIVACY.md
819
+ Controls: /hive:privacy, /hive:delete-data
531
820
 
532
821
  To uninstall: node ~/.hive-rank/bin/install.js --uninstall
533
822
  `);
package/commands/grow.md CHANGED
@@ -8,6 +8,7 @@ allowed-tools:
8
8
  - hive_trending
9
9
  - hive_rankings
10
10
  - hive_search
11
+ - hive_score
11
12
  ---
12
13
 
13
14
  Run a weekly SEO growth check for $ARGUMENTS.
@@ -31,6 +32,7 @@ If no domain is specified, ask which domain to analyze.
31
32
  - WebFetch any new competitor pages discovered
32
33
 
33
34
  **Step 4 — Present Summary:**
35
+ - Current Hive Score (use `hive_score` for the 0-100 score and breakdown)
34
36
  - What's the domain's current visibility?
35
37
  - Any notable trends from the network?
36
38
  - New competitors or threats identified?
package/commands/help.md CHANGED
@@ -35,13 +35,14 @@ These commands query the hive network for aggregated insights.
35
35
  | `/hive:competitors [domain]` | Find competitors via network intelligence |
36
36
  | `/hive:keywords [domain]` | Find keyword opportunities |
37
37
  | `/hive:report [domain]` | Generate an SEO report from network data |
38
+ | `/hive:score [domain]` | Get a 0-100 hive score for any domain |
38
39
  | `/hive:audit` | Check network contribution status |
39
40
  | `/hive:status` | Hive network status and your contribution stats |
40
41
  | `/hive:privacy` | View contribution status and privacy controls |
41
42
  | `/hive:delete-data` | Request deletion of your data |
42
43
  | `/hive:help` | This help guide |
43
44
 
44
- **MCP Tools (7 network tools via hive-rank server):**
45
+ **MCP Tools (8 network tools via hive-rank server):**
45
46
 
46
47
  | Tool | What it does |
47
48
  |------|-------------|
@@ -51,6 +52,7 @@ These commands query the hive network for aggregated insights.
51
52
  | `hive_domain(domain)` | Domain intelligence from network observations |
52
53
  | `hive_contributors` | Contributor activity and leaderboard |
53
54
  | `hive_search(term)` | Full-text search across network data |
55
+ | `hive_score(domain)` | Domain hive score (0-100) based on network observations |
54
56
  | `hive_contribute` | Contribute search/page observations (used by hooks automatically) |
55
57
 
56
58
  **How it works:**
@@ -9,6 +9,7 @@ allowed-tools:
9
9
  - hive_trending
10
10
  - hive_search
11
11
  - hive_stats
12
+ - hive_score
12
13
  ---
13
14
 
14
15
  Generate a comprehensive SEO report for the specified domain (or ask me which domain to analyze).
@@ -28,12 +29,13 @@ Generate a comprehensive SEO report for the specified domain (or ask me which do
28
29
  Present a markdown report with these sections:
29
30
 
30
31
  1. **Domain Overview** — What the site does, key pages, apparent focus
31
- 2. **Network Presence** — How the domain appears across hive network data
32
- 3. **Ranking Snapshot** — Current positions for key queries (from hive_rankings + fresh searches)
33
- 4. **Trends** — What's moving up or down (from hive_trending)
34
- 5. **Competitive Context** — Who else appears for similar queries
35
- 6. **Opportunities** — Gaps and quick wins identified
36
- 7. **Next Steps** — Specific recommendations
32
+ 2. **Hive Score** — 0-100 domain authority score with sub-score breakdown (use `hive_score`)
33
+ 3. **Network Presence** — How the domain appears across hive network data
34
+ 4. **Ranking Snapshot** — Current positions for key queries (from hive_rankings + fresh searches)
35
+ 5. **Trends** — What's moving up or down (from hive_trending)
36
+ 6. **Competitive Context** — Who else appears for similar queries
37
+ 7. **Opportunities** — Gaps and quick wins identified
38
+ 8. **Next Steps** — Specific recommendations
37
39
 
38
40
  If network data is sparse for this domain, note this and rely more on fresh WebSearch/WebFetch research.
39
41
 
@@ -0,0 +1,55 @@
1
+ ---
2
+ name: score
3
+ description: Get a 0-100 hive score for any domain — researches first, then computes
4
+ allowed-tools:
5
+ - mcp: hive-rank
6
+ tools:
7
+ - hive_score
8
+ - hive_domain
9
+ - hive_stats
10
+ ---
11
+
12
+ Compute a Hive Score for: $ARGUMENTS
13
+
14
+ If no domain is specified, ask which domain to score.
15
+
16
+ **Step 1 — Activate Session:**
17
+ - Call `hive_stats` to activate the network session
18
+
19
+ **Step 2 — Research the Domain:**
20
+ - WebSearch the domain's brand name
21
+ - WebSearch 3-5 key niche keywords related to the domain
22
+ - WebSearch "[domain] vs" and "[domain] alternatives" queries
23
+ - WebFetch the homepage
24
+ - WebFetch 1-2 key pages (pricing, features, or top content)
25
+
26
+ All of this contributes fresh data to the hive network via contribution hooks.
27
+
28
+ **Step 3 — Compute Score:**
29
+ - Call `hive_score` with the domain to get the 0-100 score and breakdown
30
+
31
+ **Step 4 — Present Score Card:**
32
+
33
+ Format the results as a clear score card:
34
+
35
+ ```
36
+ ## Hive Score: [domain]
37
+
38
+ **Score: XX/100** (confidence: low/medium/high)
39
+
40
+ ### Breakdown
41
+ | Factor | Score | Weight |
42
+ |--------|-------|--------|
43
+ | Visibility | XX | 40% |
44
+ | Breadth | XX | 25% |
45
+ | Consensus | XX | 25% |
46
+ | Freshness | XX | 10% |
47
+
48
+ ### Signals
49
+ - Ranks for X queries (avg position: X.X)
50
+ - X #1 rankings, X top-3, X top-10
51
+ - Observed by X contributors (X total observations)
52
+ - Latest data: YYYY-MM-DD
53
+ ```
54
+
55
+ If the score is null (no data), explain that the domain has no hive network data yet and suggest running `/hive:grow` to build up observations over time.
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "hive-rank",
3
- "version": "3.2.0",
4
- "description": "Crowdsourced SEO intelligence for AI agents. Network-powered hooks contribute data to the hive. 7 hive_* tools via remote MCP server.",
3
+ "version": "3.4.0",
4
+ "description": "Crowdsourced SEO intelligence for AI agents. Network-powered hooks contribute data to the hive. 8 hive_* tools via remote MCP server.",
5
5
  "author": "hive-rank",
6
6
  "license": "MIT",
7
7
  "homepage": "https://hive-rank.com",