hive-intelligence 0.1.1 → 0.3.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 (84) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +112 -77
  3. package/bin/hive.js +25 -0
  4. package/build/alias-INGXWFCG.js +41 -0
  5. package/build/alias-INGXWFCG.js.map +1 -0
  6. package/build/auth-PVT4GTAD.js +233 -0
  7. package/build/auth-PVT4GTAD.js.map +1 -0
  8. package/build/cache-US4LSZPI.js +52 -0
  9. package/build/cache-US4LSZPI.js.map +1 -0
  10. package/build/chunk-FAFUYZQS.js +280 -0
  11. package/build/chunk-FAFUYZQS.js.map +1 -0
  12. package/build/chunk-IWBWPHYY.js +212 -0
  13. package/build/chunk-IWBWPHYY.js.map +1 -0
  14. package/build/chunk-LBTLYTZS.js +115 -0
  15. package/build/chunk-LBTLYTZS.js.map +1 -0
  16. package/build/chunk-N43VRMVB.js +3108 -0
  17. package/build/chunk-N43VRMVB.js.map +1 -0
  18. package/build/chunk-NEKSTV6P.js +911 -0
  19. package/build/chunk-NEKSTV6P.js.map +1 -0
  20. package/build/chunk-OK3LSM73.js +22 -0
  21. package/build/chunk-OK3LSM73.js.map +1 -0
  22. package/build/chunk-QMRVH5ZP.js +44 -0
  23. package/build/chunk-QMRVH5ZP.js.map +1 -0
  24. package/build/chunk-WKVZVQTG.js +66 -0
  25. package/build/chunk-WKVZVQTG.js.map +1 -0
  26. package/build/chunk-XQJ6PB2L.js +95 -0
  27. package/build/chunk-XQJ6PB2L.js.map +1 -0
  28. package/build/cli.js +3858 -0
  29. package/build/cli.js.map +1 -0
  30. package/build/completion-N35TWBLT.js +274 -0
  31. package/build/completion-N35TWBLT.js.map +1 -0
  32. package/build/config-2VDB2ZHE.js +100 -0
  33. package/build/config-2VDB2ZHE.js.map +1 -0
  34. package/build/config-dir-IEOID7Q6.js +31 -0
  35. package/build/config-dir-IEOID7Q6.js.map +1 -0
  36. package/build/doctor-GYP6IHPP.js +231 -0
  37. package/build/doctor-GYP6IHPP.js.map +1 -0
  38. package/build/errors-HRGXEUZR.js +17 -0
  39. package/build/errors-HRGXEUZR.js.map +1 -0
  40. package/build/format-4OIUGZKY.js +43 -0
  41. package/build/format-4OIUGZKY.js.map +1 -0
  42. package/build/init-YOJK6CH2.js +102 -0
  43. package/build/init-YOJK6CH2.js.map +1 -0
  44. package/build/namespace-GWTS6U6J.js +13 -0
  45. package/build/namespace-GWTS6U6J.js.map +1 -0
  46. package/build/open-FUXYIHFO.js +37 -0
  47. package/build/open-FUXYIHFO.js.map +1 -0
  48. package/build/output-6TJ3JTZ7.js +41 -0
  49. package/build/output-6TJ3JTZ7.js.map +1 -0
  50. package/build/server.js +14763 -0
  51. package/build/server.js.map +1 -0
  52. package/build/telemetry-KNWMQURH.js +18 -0
  53. package/build/telemetry-KNWMQURH.js.map +1 -0
  54. package/build/tools-4W3GGCUC.js +178 -0
  55. package/build/tools-4W3GGCUC.js.map +1 -0
  56. package/build/version-3TZ3U4IR.js +9 -0
  57. package/build/version-3TZ3U4IR.js.map +1 -0
  58. package/build/watch-P2QWGFYV.js +67 -0
  59. package/build/watch-P2QWGFYV.js.map +1 -0
  60. package/package.json +56 -15
  61. package/.env,example +0 -1
  62. package/dist/client.d.ts +0 -7
  63. package/dist/client.js +0 -52
  64. package/dist/errors.d.ts +0 -7
  65. package/dist/errors.js +0 -15
  66. package/dist/index.d.ts +0 -3
  67. package/dist/index.js +0 -20
  68. package/dist/types.d.ts +0 -19
  69. package/dist/types.js +0 -2
  70. package/example.ts +0 -35
  71. package/jest.config.js +0 -7
  72. package/src/client.js +0 -52
  73. package/src/client.ts +0 -42
  74. package/src/errors.js +0 -15
  75. package/src/errors.ts +0 -11
  76. package/src/index.js +0 -20
  77. package/src/index.ts +0 -5
  78. package/src/types.js +0 -2
  79. package/src/types.ts +0 -21
  80. package/tests/client.test.js +0 -28
  81. package/tests/client.test.ts +0 -18
  82. package/tests/hive.test.js +0 -69
  83. package/tests/hive.test.ts +0 -63
  84. package/tsconfig.json +0 -117
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 Hive Intelligence
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md CHANGED
@@ -1,77 +1,112 @@
1
- # 🧠 Hive Intelligence TypeScript SDK
2
-
3
- The Hive Intelligence SDK lets you integrate real-time crypto and Web3 intelligence into your JavaScript or TypeScript apps using simple prompt or chat-style inputs.
4
-
5
- ## 🚀 Installation
6
-
7
- Using npm:
8
-
9
- ```bash
10
- npm install hive-intelligence
11
- ```
12
-
13
- Or using yarn:
14
-
15
- ```bash
16
- yarn add hive-intelligence
17
- ```
18
-
19
- ## 🔑 Setup
20
- Set your Hive API key as an environment variable:
21
-
22
- ```bash
23
- export HIVE_API_KEY=your_api_key_here
24
- ```
25
-
26
- ## 🧪 Example Usage
27
-
28
- ```ts
29
- import { HiveSearchClient } from 'hive-intelligence';
30
- import { HiveSearchRequest, HiveSearchMessage, HiveSearchResponse} from 'hive-intelligence';
31
-
32
- // Get API key from env
33
- const apiKey = process.env.HIVE_API_KEY;
34
- if (!apiKey) {
35
- throw new Error('Please set the HIVE_API_KEY environment variable');
36
- }
37
-
38
- // Initialize client
39
- const client = new HiveSearchClient(apiKey);
40
-
41
- // 🟡 Example 1: Prompt-based query
42
- const promptRequest: HiveSearchRequest = {
43
- prompt: 'What is the current price of Ethereum?'
44
- };
45
-
46
- client.search(promptRequest).then((response: HiveSearchResponse) => {
47
- console.log('Prompt Response:', response);
48
- }).catch(console.error);
49
-
50
- // 🟢 Example 2: Chat-style query
51
- const chatRequest: HiveSearchRequest = {
52
- messages: [
53
- { role: 'user', content: 'Price of' },
54
- { role: 'assistant', content: 'Price of what?' },
55
- { role: 'user', content: 'BTC' }
56
- ]
57
- };
58
-
59
- client.search(chatRequest).then((response: HiveSearchResponse) => {
60
- console.log('Chat Response:', response);
61
- }).catch(console.error);
62
- ```
63
-
64
- ## 📘 Request Options
65
- * `prompt`: Plaintext question or query
66
- * `messages`: Array of `{ role, content }` for chat
67
- * Optional parameters:
68
- * `temperature`: (e.g. 0.7) randomness of response
69
- * `top_k`: max tokens considered
70
- * `top_p`: nucleus sampling
71
- * `include_data_sources`: show source info
72
-
73
- ## ❗ Error Handling
74
- On error, the SDK throws `HiveSearchAPIError` with:
75
- * `status`: HTTP status code
76
- * `statusText`: status message
77
- * `body`: full API response
1
+ # Hive Intelligence MCP Server
2
+
3
+ A Model Context Protocol (MCP) server providing comprehensive cryptocurrency, Web3, and financial market analytics through intelligent tool orchestration.
4
+
5
+ ## Overview
6
+
7
+ Hive Intelligence MCP Server enables AI assistants to access a wide range of cryptocurrency, DeFi, Web3, equities, forex, and macroeconomic analytics through a unified MCP interface. The server provides both dynamic and category-specific access to **351 specialized tools** across **14 analytics categories**, powered by data from CoinGecko, LunarCrush, DefiLlama, GeckoTerminal, Codex, DeBank, GoPlus, GoldRush, CCXT, Finnhub, FRED, and more.
8
+
9
+ ### Analytics Categories
10
+
11
+ | # | Category | Tools | Description |
12
+ |---|----------|-------|-------------|
13
+ | 1 | **Market Data & Price** | 83 | Real-time/historical prices, OHLCV, market caps, stablecoins, CEX trading data, derivatives, funding rates, options |
14
+ | 2 | **On-Chain DEX & Pool** | 44 | DEX pools, liquidity, trending pairs, OHLCV, trader stats, volume analytics, cross-chain bridges |
15
+ | 3 | **Portfolio & Wallet** | 38 | Wallet balances, transaction history, DeFi positions, multi-chain portfolio tracking, Bitcoin wallets |
16
+ | 4 | **Token & Contract** | 27 | Token metadata, holder distributions, contract analysis, treasury tracking, transaction forensics |
17
+ | 5 | **DeFi Protocol** | 23 | TVL data, protocol fees, yield farming, chain metrics, treasuries, raises, emissions |
18
+ | 6 | **NFT Analytics** | 37 | Collection data, market charts, liquidity pools, holder analysis, cross-chain NFT tracking |
19
+ | 7 | **Security & Risk** | 20 | Token security, honeypot detection, phishing detection, rugpull analysis, approval auditing |
20
+ | 8 | **Network & Infrastructure** | 24 | Network health, gas prices, block data, event logs, chain statuses, address resolution |
21
+ | 9 | **Search & Discovery** | 10 | Coin search, trending analysis, categories, token discovery, exchange listings |
22
+ | 10 | **Social & Sentiment** | 17 | Social analytics, influencer tracking, news aggregation, Galaxy Score, AltRank |
23
+ | 11 | **Stocks & Equities** | 8 | Real-time quotes, historical candles, company profiles, analyst recommendations |
24
+ | 12 | **Forex & Commodities** | 4 | Forex rates, currency pair candles, commodity prices (gold, silver, platinum) |
25
+ | 13 | **Economic Indicators** | 13 | GDP, CPI, fed rate, treasury yields, unemployment, S&P 500, FRED time series |
26
+ | 14 | **Alternative Data** | 5 | Insider trading, sentiment scores, earnings calendar, IPO calendar |
27
+
28
+ ### Data Providers
29
+
30
+ - **CoinGecko** - Market data, coin metadata, exchanges, NFTs, derivatives
31
+ - **LunarCrush** - Social sentiment, Galaxy Score, AltRank, influencer tracking
32
+ - **DefiLlama** - TVL, protocol fees, yields, stablecoins, bridges, treasuries, hacks
33
+ - **GeckoTerminal** - On-chain DEX pools, OHLCV, trades, trending pairs
34
+ - **Codex** - Token pairs, liquidity, trader analytics, chart data, wallet filtering
35
+ - **DeBank** - EVM wallet portfolios, DeFi positions, protocol analytics, token info
36
+ - **GoPlus** - Token/NFT security, honeypot detection, phishing, rugpull analysis
37
+ - **GoldRush (Covalent)** - 100+ chain coverage, token balances, transactions, NFTs, Bitcoin
38
+ - **CCXT** - CEX trading data, order books, OHLCV, funding rates, derivatives
39
+ - **Finnhub** - Stock quotes, company profiles, forex, commodities, insider trading
40
+ - **FRED** - 800,000+ economic time series, GDP, CPI, interest rates
41
+
42
+ ## Installation
43
+
44
+ ```bash
45
+ # Install dependencies
46
+ npm install
47
+
48
+ # Build the server
49
+ npm run build
50
+
51
+ # Start the server
52
+ npm start
53
+ ```
54
+
55
+ ### MCP Client Configuration
56
+
57
+ Add to your MCP client configuration:
58
+
59
+ ```json
60
+ {
61
+ "mcpServers": {
62
+ "hive": {
63
+ "command": "npx",
64
+ "args": ["-y", "mcp-hive"]
65
+ }
66
+ }
67
+ }
68
+ ```
69
+
70
+ ## Usage
71
+
72
+ ### Claude Desktop Configuration
73
+
74
+ Add to your Claude Desktop configuration file:
75
+
76
+ **Windows**: `%APPDATA%\Claude\claude_desktop_config.json`
77
+ **macOS**: `~/Library/Application Support/Claude/claude_desktop_config.json`
78
+
79
+ ```json
80
+ {
81
+ "mcpServers": {
82
+ "hive-mcp": {
83
+ "command": "npx",
84
+ "args": ["-y", "mcp-hive"]
85
+ }
86
+ }
87
+ }
88
+ ```
89
+
90
+ ## Development
91
+
92
+ ### Building
93
+
94
+ ```bash
95
+ # Development build
96
+ npm run build
97
+
98
+ # Production build with executable permissions
99
+ npm run prepare
100
+ ```
101
+
102
+ ### Testing
103
+
104
+ ```bash
105
+ # Use MCP inspector for testing
106
+ npm run inspector
107
+ ```
108
+ ---
109
+
110
+ ## Remote MCP Server
111
+ Checkout the guide to use Hive's remote MCP server:
112
+ https://hiveintelligence.xyz/crypto-mcp
package/bin/hive.js ADDED
@@ -0,0 +1,25 @@
1
+ #!/usr/bin/env node
2
+
3
+ const major = parseInt(process.versions.node.split(".")[0], 10);
4
+ if (major < 20) {
5
+ process.stderr.write(
6
+ `Error: hive requires Node.js 20 or later (found ${process.versions.node}).\n`,
7
+ );
8
+ process.exit(1);
9
+ }
10
+
11
+ import { dirname, join } from "node:path";
12
+ import { fileURLToPath } from "node:url";
13
+ import { existsSync } from "node:fs";
14
+
15
+ const __dirname = dirname(fileURLToPath(import.meta.url));
16
+ const cliPath = join(__dirname, "..", "build", "cli.js");
17
+
18
+ if (!existsSync(cliPath)) {
19
+ process.stderr.write(
20
+ "Error: build/cli.js not found. Run `npm run build` first.\n",
21
+ );
22
+ process.exit(1);
23
+ }
24
+
25
+ await import(cliPath);
@@ -0,0 +1,41 @@
1
+ import { createRequire } from 'node:module'; const require = createRequire(import.meta.url);
2
+ import {
3
+ ensureConfigDir,
4
+ getConfig,
5
+ saveConfig
6
+ } from "./chunk-XQJ6PB2L.js";
7
+ import "./chunk-QMRVH5ZP.js";
8
+
9
+ // src/cli/alias.ts
10
+ function getAliases() {
11
+ return getConfig().aliases ?? {};
12
+ }
13
+ function setAlias(name, command) {
14
+ ensureConfigDir();
15
+ const config = getConfig();
16
+ config.aliases = { ...config.aliases, [name]: command };
17
+ saveConfig(config);
18
+ }
19
+ function removeAlias(name) {
20
+ const config = getConfig();
21
+ const { [name]: _, ...rest } = config.aliases;
22
+ config.aliases = rest;
23
+ saveConfig(config);
24
+ }
25
+ function expandAlias(argv) {
26
+ if (argv.length < 3) return argv;
27
+ const aliases = getAliases();
28
+ const candidate = argv[2];
29
+ const expansion = aliases[candidate];
30
+ if (!expansion) return argv;
31
+ const expandedParts = expansion.split(/\s+/);
32
+ const trailing = argv.slice(3);
33
+ return [argv[0], argv[1], ...expandedParts, ...trailing];
34
+ }
35
+ export {
36
+ expandAlias,
37
+ getAliases,
38
+ removeAlias,
39
+ setAlias
40
+ };
41
+ //# sourceMappingURL=alias-INGXWFCG.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/cli/alias.ts"],"sourcesContent":["import { getConfig, saveConfig, ensureConfigDir } from \"./config-dir.js\";\n\nexport function getAliases(): Record<string, string> {\n return getConfig().aliases ?? {};\n}\n\nexport function setAlias(name: string, command: string): void {\n ensureConfigDir();\n const config = getConfig();\n config.aliases = { ...config.aliases, [name]: command };\n saveConfig(config);\n}\n\nexport function removeAlias(name: string): void {\n const config = getConfig();\n const { [name]: _, ...rest } = config.aliases;\n config.aliases = rest;\n saveConfig(config);\n}\n\n/**\n * If argv[2] matches an alias, expand it in-place.\n * Extra flags after the alias are appended.\n * Returns a new argv array (never mutates the original).\n */\nexport function expandAlias(argv: string[]): string[] {\n if (argv.length < 3) return argv;\n const aliases = getAliases();\n const candidate = argv[2];\n const expansion = aliases[candidate];\n if (!expansion) return argv;\n const expandedParts = expansion.split(/\\s+/);\n const trailing = argv.slice(3);\n return [argv[0], argv[1], ...expandedParts, ...trailing];\n}\n"],"mappings":";;;;;;;;;AAEO,SAAS,aAAqC;AACnD,SAAO,UAAU,EAAE,WAAW,CAAC;AACjC;AAEO,SAAS,SAAS,MAAc,SAAuB;AAC5D,kBAAgB;AAChB,QAAM,SAAS,UAAU;AACzB,SAAO,UAAU,EAAE,GAAG,OAAO,SAAS,CAAC,IAAI,GAAG,QAAQ;AACtD,aAAW,MAAM;AACnB;AAEO,SAAS,YAAY,MAAoB;AAC9C,QAAM,SAAS,UAAU;AACzB,QAAM,EAAE,CAAC,IAAI,GAAG,GAAG,GAAG,KAAK,IAAI,OAAO;AACtC,SAAO,UAAU;AACjB,aAAW,MAAM;AACnB;AAOO,SAAS,YAAY,MAA0B;AACpD,MAAI,KAAK,SAAS,EAAG,QAAO;AAC5B,QAAM,UAAU,WAAW;AAC3B,QAAM,YAAY,KAAK,CAAC;AACxB,QAAM,YAAY,QAAQ,SAAS;AACnC,MAAI,CAAC,UAAW,QAAO;AACvB,QAAM,gBAAgB,UAAU,MAAM,KAAK;AAC3C,QAAM,WAAW,KAAK,MAAM,CAAC;AAC7B,SAAO,CAAC,KAAK,CAAC,GAAG,KAAK,CAAC,GAAG,GAAG,eAAe,GAAG,QAAQ;AACzD;","names":[]}
@@ -0,0 +1,233 @@
1
+ import { createRequire } from 'node:module'; const require = createRequire(import.meta.url);
2
+ import {
3
+ ensureConfigDir,
4
+ getConfig,
5
+ getCredentials,
6
+ saveConfig,
7
+ saveCredentials
8
+ } from "./chunk-XQJ6PB2L.js";
9
+ import "./chunk-QMRVH5ZP.js";
10
+
11
+ // src/cli/auth.ts
12
+ import { createInterface } from "readline";
13
+ function maskKey(key) {
14
+ if (!key) return "(empty)";
15
+ const visible = Math.min(8, key.length - 1);
16
+ return key.slice(0, visible) + "...";
17
+ }
18
+ function saveProfile(name, apiKey, apiUrl) {
19
+ ensureConfigDir();
20
+ const creds = getCredentials();
21
+ creds.profiles[name] = {
22
+ apiKey,
23
+ apiUrl,
24
+ createdAt: (/* @__PURE__ */ new Date()).toISOString()
25
+ };
26
+ saveCredentials(creds);
27
+ const config = getConfig();
28
+ config.activeProfile = name;
29
+ saveConfig(config);
30
+ }
31
+ function removeProfile(name) {
32
+ const creds = getCredentials();
33
+ delete creds.profiles[name];
34
+ saveCredentials(creds);
35
+ const config = getConfig();
36
+ if (config.activeProfile === name) {
37
+ const remaining = Object.keys(creds.profiles);
38
+ config.activeProfile = remaining[0] ?? "default";
39
+ saveConfig(config);
40
+ }
41
+ }
42
+ function getActiveProfile() {
43
+ const config = getConfig();
44
+ const creds = getCredentials();
45
+ const profile = creds.profiles[config.activeProfile];
46
+ if (!profile) return null;
47
+ return { name: config.activeProfile, ...profile, isActive: true };
48
+ }
49
+ function listProfiles() {
50
+ const config = getConfig();
51
+ const creds = getCredentials();
52
+ return Object.entries(creds.profiles).map(([name, p]) => ({
53
+ name,
54
+ ...p,
55
+ isActive: name === config.activeProfile
56
+ }));
57
+ }
58
+ function switchProfile(name) {
59
+ const creds = getCredentials();
60
+ if (!creds.profiles[name]) {
61
+ throw new Error(`Profile "${name}" not found`);
62
+ }
63
+ const config = getConfig();
64
+ config.activeProfile = name;
65
+ saveConfig(config);
66
+ }
67
+ var ask = (rl, q) => new Promise((resolve) => rl.question(q, resolve));
68
+ function askSecret(prompt) {
69
+ if (!process.stdin.isTTY) {
70
+ const rl = createInterface({
71
+ input: process.stdin,
72
+ output: process.stderr
73
+ });
74
+ return new Promise(
75
+ (resolve) => rl.question(prompt, (ans) => {
76
+ rl.close();
77
+ resolve(ans);
78
+ })
79
+ );
80
+ }
81
+ return new Promise((resolve) => {
82
+ process.stderr.write(prompt);
83
+ const chunks = [];
84
+ const stdin = process.stdin;
85
+ const wasRaw = stdin.isRaw;
86
+ if (typeof stdin.setRawMode === "function") {
87
+ stdin.setRawMode(true);
88
+ }
89
+ stdin.resume();
90
+ stdin.setEncoding("utf-8");
91
+ const onData = (ch) => {
92
+ const c = ch.toString();
93
+ if (c === "\n" || c === "\r" || c === "") {
94
+ stdin.removeListener("data", onData);
95
+ if (typeof stdin.setRawMode === "function") {
96
+ stdin.setRawMode(wasRaw ?? false);
97
+ }
98
+ stdin.pause();
99
+ process.stderr.write("\n");
100
+ resolve(chunks.join(""));
101
+ } else if (c === "") {
102
+ process.exit(130);
103
+ } else if (c === "\x7F" || c === "\b") {
104
+ if (chunks.length > 0) {
105
+ chunks.pop();
106
+ process.stderr.write("\b \b");
107
+ }
108
+ } else {
109
+ chunks.push(c);
110
+ process.stderr.write("*");
111
+ }
112
+ };
113
+ stdin.on("data", onData);
114
+ });
115
+ }
116
+ async function runLogin(opts) {
117
+ const profileName = opts.profile ?? "default";
118
+ process.stderr.write(`
119
+ Hive CLI \u2014 Login (profile: ${profileName})
120
+
121
+ `);
122
+ const keyInput = await askSecret("API Key: ");
123
+ const apiKey = keyInput.trim();
124
+ if (!apiKey) {
125
+ process.stderr.write("No API key provided. Aborting.\n");
126
+ process.exit(1);
127
+ }
128
+ const rl = createInterface({ input: process.stdin, output: process.stderr });
129
+ const urlInput = await ask(
130
+ rl,
131
+ `API URL [https://mcp.hiveintelligence.xyz]: `
132
+ );
133
+ rl.close();
134
+ const apiUrl = urlInput.trim() || "https://mcp.hiveintelligence.xyz";
135
+ process.stderr.write(`
136
+ Validating against ${apiUrl}...
137
+ `);
138
+ try {
139
+ const controller = new AbortController();
140
+ const timer = setTimeout(() => controller.abort(), 1e4);
141
+ const resp = await fetch(`${apiUrl}/ping`, {
142
+ headers: { Authorization: `Bearer ${apiKey}` },
143
+ signal: controller.signal
144
+ });
145
+ clearTimeout(timer);
146
+ if (resp.ok) {
147
+ process.stderr.write("Key validated successfully.\n");
148
+ } else if (resp.status === 401 || resp.status === 403) {
149
+ process.stderr.write(
150
+ `Warning: Server returned ${resp.status} \u2014 key may be invalid.
151
+ `
152
+ );
153
+ } else {
154
+ process.stderr.write(`Warning: Server returned ${resp.status}.
155
+ `);
156
+ }
157
+ } catch {
158
+ process.stderr.write("Warning: Could not reach server \u2014 saving anyway.\n");
159
+ }
160
+ saveProfile(profileName, apiKey, apiUrl);
161
+ process.stderr.write(
162
+ `
163
+ Profile "${profileName}" saved. Key: ${maskKey(apiKey)}
164
+ `
165
+ );
166
+ }
167
+ async function runLogout() {
168
+ const config = getConfig();
169
+ const profile = config.activeProfile;
170
+ removeProfile(profile);
171
+ process.stderr.write(`Logged out of profile "${profile}".
172
+ `);
173
+ }
174
+ async function runWhoami() {
175
+ const profile = getActiveProfile();
176
+ if (!profile) {
177
+ process.stderr.write("Not logged in. Run: hive-mcp auth login\n");
178
+ return;
179
+ }
180
+ process.stderr.write(
181
+ `
182
+ Profile: ${profile.name}${profile.isActive ? " (active)" : ""}
183
+ `
184
+ );
185
+ process.stderr.write(`API Key: ${maskKey(profile.apiKey)}
186
+ `);
187
+ process.stderr.write(`API URL: ${profile.apiUrl}
188
+ `);
189
+ process.stderr.write(`Created: ${profile.createdAt}
190
+
191
+ `);
192
+ }
193
+ async function runProfiles() {
194
+ const profiles = listProfiles();
195
+ if (profiles.length === 0) {
196
+ process.stderr.write("No profiles configured. Run: hive-mcp auth login\n");
197
+ return;
198
+ }
199
+ for (const p of profiles) {
200
+ const marker = p.isActive ? " *" : "";
201
+ process.stderr.write(
202
+ ` ${p.name}${marker} ${maskKey(p.apiKey)} ${p.apiUrl}
203
+ `
204
+ );
205
+ }
206
+ process.stderr.write("\n");
207
+ }
208
+ async function runSwitch(name) {
209
+ try {
210
+ switchProfile(name);
211
+ process.stderr.write(`Switched to profile "${name}".
212
+ `);
213
+ } catch (err) {
214
+ process.stderr.write(
215
+ (err instanceof Error ? err.message : String(err)) + "\n"
216
+ );
217
+ process.exit(1);
218
+ }
219
+ }
220
+ export {
221
+ getActiveProfile,
222
+ listProfiles,
223
+ maskKey,
224
+ removeProfile,
225
+ runLogin,
226
+ runLogout,
227
+ runProfiles,
228
+ runSwitch,
229
+ runWhoami,
230
+ saveProfile,
231
+ switchProfile
232
+ };
233
+ //# sourceMappingURL=auth-PVT4GTAD.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/cli/auth.ts"],"sourcesContent":["import { createInterface } from \"node:readline\";\nimport {\n ensureConfigDir,\n getConfig,\n saveConfig,\n getCredentials,\n saveCredentials,\n} from \"./config-dir.js\";\n\ninterface ProfileInfo {\n name: string;\n apiKey: string;\n apiUrl: string;\n createdAt: string;\n isActive: boolean;\n}\n\nexport function maskKey(key: string): string {\n if (!key) return \"(empty)\";\n const visible = Math.min(8, key.length - 1);\n return key.slice(0, visible) + \"...\";\n}\n\nexport function saveProfile(\n name: string,\n apiKey: string,\n apiUrl: string,\n): void {\n ensureConfigDir();\n const creds = getCredentials();\n creds.profiles[name] = {\n apiKey,\n apiUrl,\n createdAt: new Date().toISOString(),\n };\n saveCredentials(creds);\n const config = getConfig();\n config.activeProfile = name;\n saveConfig(config);\n}\n\nexport function removeProfile(name: string): void {\n const creds = getCredentials();\n delete creds.profiles[name];\n saveCredentials(creds);\n const config = getConfig();\n if (config.activeProfile === name) {\n const remaining = Object.keys(creds.profiles);\n config.activeProfile = remaining[0] ?? \"default\";\n saveConfig(config);\n }\n}\n\nexport function getActiveProfile(): ProfileInfo | null {\n const config = getConfig();\n const creds = getCredentials();\n const profile = creds.profiles[config.activeProfile];\n if (!profile) return null;\n return { name: config.activeProfile, ...profile, isActive: true };\n}\n\nexport function listProfiles(): ProfileInfo[] {\n const config = getConfig();\n const creds = getCredentials();\n return Object.entries(creds.profiles).map(([name, p]) => ({\n name,\n ...p,\n isActive: name === config.activeProfile,\n }));\n}\n\nexport function switchProfile(name: string): void {\n const creds = getCredentials();\n if (!creds.profiles[name]) {\n throw new Error(`Profile \"${name}\" not found`);\n }\n const config = getConfig();\n config.activeProfile = name;\n saveConfig(config);\n}\n\nconst ask = (\n rl: ReturnType<typeof createInterface>,\n q: string,\n): Promise<string> => new Promise((resolve) => rl.question(q, resolve));\n\n/** Prompt for sensitive input with echo suppressed (shows asterisks) */\nfunction askSecret(prompt: string): Promise<string> {\n // Non-TTY: fall back to regular readline (no masking possible)\n if (!process.stdin.isTTY) {\n const rl = createInterface({\n input: process.stdin,\n output: process.stderr,\n });\n return new Promise((resolve) =>\n rl.question(prompt, (ans) => {\n rl.close();\n resolve(ans);\n }),\n );\n }\n\n return new Promise((resolve) => {\n process.stderr.write(prompt);\n const chunks: string[] = [];\n const stdin = process.stdin;\n const wasRaw = stdin.isRaw;\n\n if (typeof stdin.setRawMode === \"function\") {\n stdin.setRawMode(true);\n }\n stdin.resume();\n stdin.setEncoding(\"utf-8\");\n\n const onData = (ch: string) => {\n const c = ch.toString();\n if (c === \"\\n\" || c === \"\\r\" || c === \"\\u0004\") {\n stdin.removeListener(\"data\", onData);\n if (typeof stdin.setRawMode === \"function\") {\n stdin.setRawMode(wasRaw ?? false);\n }\n stdin.pause();\n process.stderr.write(\"\\n\");\n resolve(chunks.join(\"\"));\n } else if (c === \"\\u0003\") {\n // Ctrl+C\n process.exit(130);\n } else if (c === \"\\u007f\" || c === \"\\b\") {\n // Backspace\n if (chunks.length > 0) {\n chunks.pop();\n process.stderr.write(\"\\b \\b\");\n }\n } else {\n chunks.push(c);\n process.stderr.write(\"*\");\n }\n };\n\n stdin.on(\"data\", onData);\n });\n}\n\nexport async function runLogin(opts: { profile?: string }): Promise<void> {\n const profileName = opts.profile ?? \"default\";\n process.stderr.write(`\\nHive CLI — Login (profile: ${profileName})\\n\\n`);\n\n const keyInput = await askSecret(\"API Key: \");\n const apiKey = keyInput.trim();\n if (!apiKey) {\n process.stderr.write(\"No API key provided. Aborting.\\n\");\n process.exit(1);\n }\n\n const rl = createInterface({ input: process.stdin, output: process.stderr });\n const urlInput = await ask(\n rl,\n `API URL [https://mcp.hiveintelligence.xyz]: `,\n );\n rl.close();\n const apiUrl =\n urlInput.trim() ||\n \"https://mcp.hiveintelligence.xyz\";\n\n process.stderr.write(`\\nValidating against ${apiUrl}...\\n`);\n try {\n const controller = new AbortController();\n const timer = setTimeout(() => controller.abort(), 10000);\n const resp = await fetch(`${apiUrl}/ping`, {\n headers: { Authorization: `Bearer ${apiKey}` },\n signal: controller.signal,\n });\n clearTimeout(timer);\n if (resp.ok) {\n process.stderr.write(\"Key validated successfully.\\n\");\n } else if (resp.status === 401 || resp.status === 403) {\n process.stderr.write(\n `Warning: Server returned ${resp.status} — key may be invalid.\\n`,\n );\n } else {\n process.stderr.write(`Warning: Server returned ${resp.status}.\\n`);\n }\n } catch {\n process.stderr.write(\"Warning: Could not reach server — saving anyway.\\n\");\n }\n\n saveProfile(profileName, apiKey, apiUrl);\n process.stderr.write(\n `\\nProfile \"${profileName}\" saved. Key: ${maskKey(apiKey)}\\n`,\n );\n}\n\nexport async function runLogout(): Promise<void> {\n const config = getConfig();\n const profile = config.activeProfile;\n removeProfile(profile);\n process.stderr.write(`Logged out of profile \"${profile}\".\\n`);\n}\n\nexport async function runWhoami(): Promise<void> {\n const profile = getActiveProfile();\n if (!profile) {\n process.stderr.write(\"Not logged in. Run: hive-mcp auth login\\n\");\n return;\n }\n process.stderr.write(\n `\\nProfile: ${profile.name}${profile.isActive ? \" (active)\" : \"\"}\\n`,\n );\n process.stderr.write(`API Key: ${maskKey(profile.apiKey)}\\n`);\n process.stderr.write(`API URL: ${profile.apiUrl}\\n`);\n process.stderr.write(`Created: ${profile.createdAt}\\n\\n`);\n}\n\nexport async function runProfiles(): Promise<void> {\n const profiles = listProfiles();\n if (profiles.length === 0) {\n process.stderr.write(\"No profiles configured. Run: hive-mcp auth login\\n\");\n return;\n }\n for (const p of profiles) {\n const marker = p.isActive ? \" *\" : \"\";\n process.stderr.write(\n ` ${p.name}${marker} ${maskKey(p.apiKey)} ${p.apiUrl}\\n`,\n );\n }\n process.stderr.write(\"\\n\");\n}\n\nexport async function runSwitch(name: string): Promise<void> {\n try {\n switchProfile(name);\n process.stderr.write(`Switched to profile \"${name}\".\\n`);\n } catch (err) {\n process.stderr.write(\n (err instanceof Error ? err.message : String(err)) + \"\\n\",\n );\n process.exit(1);\n }\n}\n"],"mappings":"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","names":[]}
@@ -0,0 +1,52 @@
1
+ import { createRequire } from 'node:module'; const require = createRequire(import.meta.url);
2
+ import {
3
+ ensureConfigDir,
4
+ getConfigDir,
5
+ readJsonFile,
6
+ writeJsonFile
7
+ } from "./chunk-XQJ6PB2L.js";
8
+ import "./chunk-QMRVH5ZP.js";
9
+
10
+ // src/cli/cache.ts
11
+ import { existsSync, unlinkSync } from "fs";
12
+ import { join } from "path";
13
+ var DEFAULT_TTL_MS = 3e5;
14
+ function getCachePath() {
15
+ return join(getConfigDir(), "cache", "tools.json");
16
+ }
17
+ function getTtlMs() {
18
+ const envTtl = process.env.HIVE_CACHE_TTL_MS;
19
+ if (envTtl) {
20
+ const parsed = parseInt(envTtl, 10);
21
+ if (!isNaN(parsed) && parsed > 0) return parsed;
22
+ }
23
+ return DEFAULT_TTL_MS;
24
+ }
25
+ function getCachedTools() {
26
+ const path = getCachePath();
27
+ const entry = readJsonFile(path);
28
+ if (!entry || !entry.fetchedAt || !Array.isArray(entry.data)) return null;
29
+ const age = Date.now() - new Date(entry.fetchedAt).getTime();
30
+ if (age > getTtlMs()) return null;
31
+ return entry.data;
32
+ }
33
+ function setCachedTools(data) {
34
+ ensureConfigDir();
35
+ const entry = {
36
+ fetchedAt: (/* @__PURE__ */ new Date()).toISOString(),
37
+ data
38
+ };
39
+ writeJsonFile(getCachePath(), entry);
40
+ }
41
+ function clearCache() {
42
+ const path = getCachePath();
43
+ if (existsSync(path)) unlinkSync(path);
44
+ const updatePath = join(getConfigDir(), "cache", "update-check.json");
45
+ if (existsSync(updatePath)) unlinkSync(updatePath);
46
+ }
47
+ export {
48
+ clearCache,
49
+ getCachedTools,
50
+ setCachedTools
51
+ };
52
+ //# sourceMappingURL=cache-US4LSZPI.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/cli/cache.ts"],"sourcesContent":["import { existsSync, unlinkSync } from \"node:fs\";\nimport { join } from \"node:path\";\nimport {\n getConfigDir,\n ensureConfigDir,\n readJsonFile,\n writeJsonFile,\n} from \"./config-dir.js\";\n\nconst DEFAULT_TTL_MS = 300_000; // 5 minutes\n\ninterface CacheEntry {\n fetchedAt: string;\n data: unknown[];\n}\n\nfunction getCachePath(): string {\n return join(getConfigDir(), \"cache\", \"tools.json\");\n}\n\nfunction getTtlMs(): number {\n const envTtl = process.env.HIVE_CACHE_TTL_MS;\n if (envTtl) {\n const parsed = parseInt(envTtl, 10);\n if (!isNaN(parsed) && parsed > 0) return parsed;\n }\n return DEFAULT_TTL_MS;\n}\n\nexport function getCachedTools(): unknown[] | null {\n const path = getCachePath();\n const entry = readJsonFile<CacheEntry>(path);\n if (!entry || !entry.fetchedAt || !Array.isArray(entry.data)) return null;\n\n const age = Date.now() - new Date(entry.fetchedAt).getTime();\n if (age > getTtlMs()) return null;\n\n return entry.data;\n}\n\nexport function setCachedTools(data: unknown[]): void {\n ensureConfigDir();\n const entry: CacheEntry = {\n fetchedAt: new Date().toISOString(),\n data,\n };\n writeJsonFile(getCachePath(), entry);\n}\n\nexport function clearCache(): void {\n const path = getCachePath();\n if (existsSync(path)) unlinkSync(path);\n const updatePath = join(getConfigDir(), \"cache\", \"update-check.json\");\n if (existsSync(updatePath)) unlinkSync(updatePath);\n}\n"],"mappings":";;;;;;;;;;AAAA,SAAS,YAAY,kBAAkB;AACvC,SAAS,YAAY;AAQrB,IAAM,iBAAiB;AAOvB,SAAS,eAAuB;AAC9B,SAAO,KAAK,aAAa,GAAG,SAAS,YAAY;AACnD;AAEA,SAAS,WAAmB;AAC1B,QAAM,SAAS,QAAQ,IAAI;AAC3B,MAAI,QAAQ;AACV,UAAM,SAAS,SAAS,QAAQ,EAAE;AAClC,QAAI,CAAC,MAAM,MAAM,KAAK,SAAS,EAAG,QAAO;AAAA,EAC3C;AACA,SAAO;AACT;AAEO,SAAS,iBAAmC;AACjD,QAAM,OAAO,aAAa;AAC1B,QAAM,QAAQ,aAAyB,IAAI;AAC3C,MAAI,CAAC,SAAS,CAAC,MAAM,aAAa,CAAC,MAAM,QAAQ,MAAM,IAAI,EAAG,QAAO;AAErE,QAAM,MAAM,KAAK,IAAI,IAAI,IAAI,KAAK,MAAM,SAAS,EAAE,QAAQ;AAC3D,MAAI,MAAM,SAAS,EAAG,QAAO;AAE7B,SAAO,MAAM;AACf;AAEO,SAAS,eAAe,MAAuB;AACpD,kBAAgB;AAChB,QAAM,QAAoB;AAAA,IACxB,YAAW,oBAAI,KAAK,GAAE,YAAY;AAAA,IAClC;AAAA,EACF;AACA,gBAAc,aAAa,GAAG,KAAK;AACrC;AAEO,SAAS,aAAmB;AACjC,QAAM,OAAO,aAAa;AAC1B,MAAI,WAAW,IAAI,EAAG,YAAW,IAAI;AACrC,QAAM,aAAa,KAAK,aAAa,GAAG,SAAS,mBAAmB;AACpE,MAAI,WAAW,UAAU,EAAG,YAAW,UAAU;AACnD;","names":[]}