hive-intelligence 1.3.0 → 1.5.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 (49) hide show
  1. package/README.md +2 -2
  2. package/agent-skills/SKILL.md +1 -1
  3. package/agent-skills/packs/hive-build/SKILL.md +1 -1
  4. package/agent-skills/packs/hive-build-onboarding/SKILL.md +7 -7
  5. package/agent-skills/packs/hive-cli/SKILL.md +2 -2
  6. package/agent-skills/packs/hive-defi-research/SKILL.md +1 -1
  7. package/agent-skills/packs/hive-dex-pool-analysis/SKILL.md +1 -1
  8. package/agent-skills/packs/hive-market-research/SKILL.md +1 -1
  9. package/agent-skills/packs/hive-mcp/SKILL.md +1 -1
  10. package/agent-skills/packs/hive-network-infrastructure/SKILL.md +1 -1
  11. package/agent-skills/packs/hive-nft-research/SKILL.md +1 -1
  12. package/agent-skills/packs/hive-prediction-markets/SKILL.md +1 -1
  13. package/agent-skills/packs/hive-query/SKILL.md +1 -1
  14. package/agent-skills/packs/hive-security-risk/SKILL.md +1 -1
  15. package/agent-skills/packs/hive-solana-analysis/SKILL.md +1 -1
  16. package/agent-skills/packs/hive-stateful-monitoring/SKILL.md +1 -1
  17. package/agent-skills/packs/hive-token-diligence/SKILL.md +1 -1
  18. package/agent-skills/packs/hive-tool-discovery/SKILL.md +1 -1
  19. package/agent-skills/packs/hive-wallet-investigation/SKILL.md +1 -1
  20. package/build/{api-client-FTVDFW5V.js → api-client-WMWFWXC7.js} +3 -15
  21. package/build/{auth-EZFJ5RYB.js → auth-Y4GXW376.js} +1 -9
  22. package/build/browser-auth-F62BMD7W.js +20 -0
  23. package/build/{chunk-W2QL7LYI.js → chunk-AGM2CIRL.js} +971 -117
  24. package/build/{chunk-7GD2MFYI.js → chunk-BDO27NIP.js} +37 -17
  25. package/build/{upgrade-J4HIGCKE.js → chunk-GB4XMTDE.js} +3 -4
  26. package/build/{chunk-TNQ7GJ6Q.js → chunk-GWZIAAQ2.js} +58 -40
  27. package/build/{chunk-Q7VBYLX7.js → chunk-P7NLFSZQ.js} +0 -58
  28. package/build/{chunk-N32UIHBU.js → chunk-SFN772RL.js} +5 -5
  29. package/build/{chunk-AEU43ACS.js → chunk-TVBPCELA.js} +2 -2
  30. package/build/{chunk-RUHO24SX.js → chunk-WF34ZD5I.js} +7 -162
  31. package/build/{chunk-I5Z6FZRL.js → chunk-XQPEFCSY.js} +14 -12
  32. package/build/cli.js +36 -47
  33. package/build/{completion-7KBW243H.js → completion-C57PDJMY.js} +1 -1
  34. package/build/{doctor-ORDOCGLM.js → doctor-XG5IQCXK.js} +5 -5
  35. package/build/{init-UCTCUYFA.js → init-COHA3VZI.js} +3 -3
  36. package/build/{init-all-BVWW3JVK.js → init-all-YTQJLPLR.js} +43 -24
  37. package/build/{mcpServer-RUEOTTF7.js → mcpServer-XHIN5JER.js} +1 -1
  38. package/build/monitor-worker.js +2 -2
  39. package/build/{namespace-L5DGCY7K.js → namespace-YLCGHVRT.js} +1 -1
  40. package/build/release.json +4 -4
  41. package/build/{serve-DKLR2WQH.js → serve-PWMT5IRU.js} +1 -1
  42. package/build/server.js +1475 -452
  43. package/build/stdio.js +1 -1
  44. package/build/{tools-I7GLWTV6.js → tools-XNFJBN7Q.js} +2 -2
  45. package/build/{uninstall-SAOIPL6K.js → uninstall-TKDP6C4F.js} +7 -7
  46. package/build/upgrade-ODPKMIDC.js +14 -0
  47. package/build/{watch-WVR4CGCD.js → watch-MXJSNGL2.js} +2 -2
  48. package/package.json +5 -3
  49. package/build/browser-auth-OJSUNFBI.js +0 -8
@@ -5,8 +5,27 @@ import { createServer } from "http";
5
5
  import { randomBytes } from "crypto";
6
6
  import { execFile } from "child_process";
7
7
  import { platform } from "os";
8
+ var CLI_EXCHANGE_PATH = "/auth/cli/exchange";
9
+ var CLI_LOGIN_PATH = "/auth/cli";
10
+ var CLI_CALLBACK_PATH = "/callback";
11
+ function parseCliCallback(rawUrl, expectedState) {
12
+ const url = new URL(rawUrl, "http://localhost");
13
+ if (url.pathname !== CLI_CALLBACK_PATH) return { kind: "ignore" };
14
+ const returnedState = url.searchParams.get("state");
15
+ if (returnedState !== expectedState) return { kind: "state-mismatch" };
16
+ if (url.searchParams.get("key")) return { kind: "legacy-key" };
17
+ const code = url.searchParams.get("code");
18
+ if (!code) return { kind: "missing-code" };
19
+ return { kind: "code", code, state: returnedState };
20
+ }
21
+ function buildCliLoginUrl(baseUrl, port, state) {
22
+ const loginUrl = new URL(CLI_LOGIN_PATH, baseUrl);
23
+ loginUrl.searchParams.set("callback_port", String(port));
24
+ loginUrl.searchParams.set("state", state);
25
+ return loginUrl;
26
+ }
8
27
  async function exchangeCliCode(args) {
9
- const exchangeUrl = new URL("/auth/cli/exchange", args.baseUrl);
28
+ const exchangeUrl = new URL(CLI_EXCHANGE_PATH, args.baseUrl);
10
29
  const controller = new AbortController();
11
30
  const timer = setTimeout(() => controller.abort(), 1e4);
12
31
  try {
@@ -59,8 +78,8 @@ async function browserLogin(opts) {
59
78
  return new Promise((resolve, reject) => {
60
79
  let settled = false;
61
80
  const server = createServer(async (req, res) => {
62
- const url = new URL(req.url || "/", `http://localhost`);
63
- if (url.pathname !== "/callback") {
81
+ const outcome = parseCliCallback(req.url || "/", state);
82
+ if (outcome.kind === "ignore") {
64
83
  res.writeHead(404);
65
84
  res.end("Not found");
66
85
  return;
@@ -70,22 +89,19 @@ async function browserLogin(opts) {
70
89
  res.end();
71
90
  return;
72
91
  }
73
- const legacyKey = url.searchParams.get("key");
74
- const code = url.searchParams.get("code");
75
- const returnedState = url.searchParams.get("state");
76
- if (returnedState !== state) {
92
+ if (outcome.kind === "state-mismatch") {
77
93
  res.writeHead(403);
78
- res.end("State mismatch \u2014 possible CSRF attack. Please try again.");
94
+ res.end("State mismatch (possible CSRF attack). Please try again.");
79
95
  return;
80
96
  }
81
- if (legacyKey) {
97
+ if (outcome.kind === "legacy-key") {
82
98
  res.writeHead(400);
83
99
  res.end(
84
100
  "Insecure legacy callback rejected. Please update Hive auth and try again."
85
101
  );
86
102
  return;
87
103
  }
88
- if (!code) {
104
+ if (outcome.kind === "missing-code") {
89
105
  res.writeHead(400);
90
106
  res.end("Missing one-time code in callback");
91
107
  return;
@@ -95,8 +111,8 @@ async function browserLogin(opts) {
95
111
  try {
96
112
  exchanged = await exchangeCliCode({
97
113
  baseUrl,
98
- code,
99
- state: returnedState
114
+ code: outcome.code,
115
+ state: outcome.state
100
116
  });
101
117
  } catch (error) {
102
118
  clearTimeout(timer);
@@ -109,7 +125,7 @@ async function browserLogin(opts) {
109
125
  res.writeHead(200, { "Content-Type": "text/html" });
110
126
  res.end(`<!DOCTYPE html>
111
127
  <html>
112
- <head><title>Hive CLI \u2014 Authenticated</title>
128
+ <head><title>Hive CLI: Authenticated</title>
113
129
  <style>
114
130
  body { font-family: -apple-system, BlinkMacSystemFont, sans-serif; display: flex; justify-content: center; align-items: center; height: 100vh; margin: 0; background: #0a0a0a; color: #fafafa; }
115
131
  .card { text-align: center; padding: 2rem; }
@@ -129,7 +145,7 @@ async function browserLogin(opts) {
129
145
  resolve({
130
146
  key: exchanged.key,
131
147
  email: exchanged.email,
132
- state: returnedState
148
+ state: outcome.state
133
149
  });
134
150
  });
135
151
  server.listen(0, "127.0.0.1", () => {
@@ -139,9 +155,7 @@ async function browserLogin(opts) {
139
155
  return;
140
156
  }
141
157
  const port = addr.port;
142
- const loginUrl = new URL("/auth/cli", baseUrl);
143
- loginUrl.searchParams.set("callback_port", String(port));
144
- loginUrl.searchParams.set("state", state);
158
+ const loginUrl = buildCliLoginUrl(baseUrl, port, state);
145
159
  process.stderr.write(`
146
160
  Opening browser to sign in...
147
161
  `);
@@ -173,5 +187,11 @@ Opening browser to sign in...
173
187
  }
174
188
 
175
189
  export {
190
+ CLI_EXCHANGE_PATH,
191
+ CLI_LOGIN_PATH,
192
+ CLI_CALLBACK_PATH,
193
+ parseCliCallback,
194
+ buildCliLoginUrl,
195
+ exchangeCliCode,
176
196
  browserLogin
177
197
  };
@@ -13,8 +13,6 @@ import {
13
13
  successEnvelope,
14
14
  writeOutput
15
15
  } from "./chunk-725R3KLJ.js";
16
- import "./chunk-6PC3HUAK.js";
17
- import "./chunk-ILVPOLA7.js";
18
16
 
19
17
  // src/cli/upgrade.ts
20
18
  import { spawnSync } from "child_process";
@@ -148,7 +146,7 @@ Update available: ${SERVER_VERSION} -> ${latest}
148
146
  if (mode === "global") {
149
147
  info(
150
148
  actions.includes("updated global install") ? `Updated global hive-intelligence to ${latest}.
151
- ` : `Global update failed \u2014 run: npm install -g ${REGISTRY_PACKAGE}@latest
149
+ ` : `Global update failed. Run: npm install -g ${REGISTRY_PACKAGE}@latest
152
150
  `
153
151
  );
154
152
  }
@@ -158,13 +156,14 @@ Update available: ${SERVER_VERSION} -> ${latest}
158
156
  }
159
157
  if (mode === "local") {
160
158
  info(
161
- "Running from a local checkout \u2014 pull the latest source with git instead.\n"
159
+ "Running from a local checkout; pull the latest source with git instead.\n"
162
160
  );
163
161
  }
164
162
  info(
165
163
  "Restart your MCP client (Claude, Cursor, VS Code) to load the new version.\n"
166
164
  );
167
165
  }
166
+
168
167
  export {
169
168
  detectInstallMode,
170
169
  runUpgrade
@@ -4,7 +4,7 @@ import { createRequire } from 'node:module'; const require = createRequire(impor
4
4
  var NAMESPACE = [
5
5
  {
6
6
  name: "market",
7
- description: "Crypto market data \u2014 prices, charts, rankings, stablecoins",
7
+ description: "Crypto market data: prices, charts, rankings, stablecoins",
8
8
  commands: [
9
9
  {
10
10
  name: "price",
@@ -92,7 +92,7 @@ var NAMESPACE = [
92
92
  },
93
93
  {
94
94
  name: "defi",
95
- description: "DeFi protocol analytics \u2014 TVL, fees, yields, bridges",
95
+ description: "DeFi protocol analytics: TVL, fees, yields, bridges",
96
96
  commands: [
97
97
  {
98
98
  name: "tvl",
@@ -131,61 +131,69 @@ var NAMESPACE = [
131
131
  { name: "chains", description: "Chain TVL rankings", tool: "get_chains" },
132
132
  {
133
133
  name: "bridges",
134
- description: "Cross-chain bridges",
135
- tool: "defillama_get_bridges"
134
+ description: "Cross-chain bridge aggregator volumes",
135
+ tool: "defillama_get_bridge_aggregator_volumes"
136
136
  }
137
137
  ]
138
138
  },
139
139
  {
140
140
  name: "portfolio",
141
- description: "Wallet portfolios \u2014 balances, DeFi positions, NFTs, history",
141
+ description: "Wallet portfolios: balances, DeFi positions, NFTs, history",
142
142
  commands: [
143
143
  {
144
144
  name: "balance",
145
145
  description: "Wallet total balance",
146
- tool: "get_wallet_balance",
146
+ tool: "get_wallet_balances",
147
147
  args: {
148
- id: {
148
+ walletAddress: {
149
149
  flag: "--address <addr>",
150
150
  description: "Wallet address",
151
151
  required: true
152
+ },
153
+ networkId: {
154
+ flag: "--network-id <id>",
155
+ description: "EVM chain ID",
156
+ required: true
152
157
  }
153
158
  }
154
159
  },
155
160
  {
156
161
  name: "tokens",
157
162
  description: "Token holdings",
158
- tool: "get_wallet_token_balances",
163
+ tool: "moralis_get_wallet_token_balances",
159
164
  args: {
160
- id: {
165
+ address: {
161
166
  flag: "--address <addr>",
162
167
  description: "Wallet address",
163
168
  required: true
164
- }
169
+ },
170
+ chain: { flag: "--chain <name>", description: "Chain name" }
165
171
  }
166
172
  },
167
173
  {
168
174
  name: "positions",
169
175
  description: "DeFi positions",
170
- tool: "get_wallet_defi_positions",
176
+ tool: "moralis_get_wallet_defi_positions",
171
177
  args: {
172
- id: {
178
+ address: {
173
179
  flag: "--address <addr>",
174
180
  description: "Wallet address",
175
181
  required: true
176
- }
182
+ },
183
+ chain: { flag: "--chain <name>", description: "Chain name" }
177
184
  }
178
185
  },
179
186
  {
180
187
  name: "nfts",
181
188
  description: "NFT holdings",
182
- tool: "get_wallet_nft_collections",
189
+ tool: "moralis_get_wallet_nft_collections",
183
190
  args: {
184
- id: {
191
+ address: {
185
192
  flag: "--address <addr>",
186
193
  description: "Wallet address",
187
194
  required: true
188
- }
195
+ },
196
+ chain: { flag: "--chain <name>", description: "Chain name" }
189
197
  }
190
198
  },
191
199
  {
@@ -204,14 +212,14 @@ var NAMESPACE = [
204
212
  },
205
213
  {
206
214
  name: "security",
207
- description: "Token and contract security \u2014 scans, approvals, simulations",
215
+ description: "Token and contract security: scans, approvals, simulations",
208
216
  commands: [
209
217
  {
210
218
  name: "scan",
211
219
  description: "Token security analysis",
212
220
  tool: "get_token_security",
213
221
  args: {
214
- chain_id: {
222
+ chainId: {
215
223
  flag: "--chain <id>",
216
224
  description: "Chain ID (1=ETH, 56=BSC)",
217
225
  required: true
@@ -228,7 +236,7 @@ var NAMESPACE = [
228
236
  description: "Audit token approvals",
229
237
  tool: "check_approval_security",
230
238
  args: {
231
- chain_id: {
239
+ chainId: {
232
240
  flag: "--chain <id>",
233
241
  description: "Chain ID",
234
242
  required: true
@@ -277,23 +285,18 @@ var NAMESPACE = [
277
285
  description: "Chain ID",
278
286
  required: true
279
287
  },
280
- contract_addresses: {
288
+ contract_address: {
281
289
  flag: "--address <addr>",
282
290
  description: "Contract",
283
291
  required: true
284
292
  }
285
293
  }
286
- },
287
- {
288
- name: "hacks",
289
- description: "Recent DeFi hacks",
290
- tool: "defillama_get_hacks"
291
294
  }
292
295
  ]
293
296
  },
294
297
  {
295
298
  name: "exchange",
296
- description: "Centralized exchange data \u2014 tickers, orderbooks, trades, funding",
299
+ description: "Centralized exchange data: tickers, orderbooks, trades, funding",
297
300
  commands: [
298
301
  {
299
302
  name: "ticker",
@@ -372,7 +375,7 @@ var NAMESPACE = [
372
375
  },
373
376
  {
374
377
  name: "dex",
375
- description: "DEX analytics \u2014 pools, trending pairs, trades, volume",
378
+ description: "DEX analytics: pools, trending pairs, trades, volume",
376
379
  commands: [
377
380
  {
378
381
  name: "trending",
@@ -399,9 +402,14 @@ var NAMESPACE = [
399
402
  args: {
400
403
  network: {
401
404
  flag: "--network <name>",
402
- description: "Network (eth, bsc, solana)"
405
+ description: "Network (eth, bsc, solana)",
406
+ required: true
403
407
  },
404
- pool_address: { flag: "--pool <addr>", description: "Pool address" }
408
+ token_address: {
409
+ flag: "--address <addr>",
410
+ description: "Token contract address",
411
+ required: true
412
+ }
405
413
  }
406
414
  },
407
415
  {
@@ -430,7 +438,7 @@ var NAMESPACE = [
430
438
  },
431
439
  {
432
440
  name: "wallet",
433
- description: "On-chain wallet data \u2014 balances, transfers, transactions, approvals",
441
+ description: "On-chain wallet data: balances, transfers, transactions, approvals",
434
442
  commands: [
435
443
  {
436
444
  name: "balances",
@@ -474,33 +482,42 @@ var NAMESPACE = [
474
482
  {
475
483
  name: "approvals",
476
484
  description: "Token approval audit",
477
- tool: "goplus_check_approval_security_v2",
485
+ tool: "check_approval_security_v2",
478
486
  args: {
479
487
  address: {
480
488
  flag: "--address <addr>",
481
489
  description: "Wallet address",
482
490
  required: true
483
491
  },
484
- chain_id: { flag: "--chain-id <id>", description: "EVM chain ID" }
492
+ chain_id: {
493
+ flag: "--chain-id <id>",
494
+ description: "EVM chain ID",
495
+ required: true
496
+ }
485
497
  }
486
498
  }
487
499
  ]
488
500
  },
489
501
  {
490
502
  name: "nft",
491
- description: "NFT analytics \u2014 collections, markets, trends, holders",
503
+ description: "NFT analytics: collections, markets, trends, holders",
492
504
  commands: [
493
505
  {
494
506
  name: "trending",
495
- description: "Trending NFT collections",
496
- tool: "get_nft_market_trends"
507
+ description: "Trending NFT collections, by 24h volume",
508
+ tool: "get_nft_markets",
509
+ fixedArgs: { order: "h24_volume_usd_desc" }
497
510
  },
498
511
  {
499
512
  name: "collection",
500
513
  description: "Collection details",
501
- tool: "get_nft_collection",
514
+ tool: "get_nft",
502
515
  args: {
503
- slug: { flag: "--slug <name>", description: "Collection slug" }
516
+ id: {
517
+ flag: "--slug <name>",
518
+ description: "Collection slug",
519
+ required: true
520
+ }
504
521
  }
505
522
  },
506
523
  {
@@ -511,20 +528,21 @@ var NAMESPACE = [
511
528
  {
512
529
  name: "search",
513
530
  description: "Search NFT collections",
514
- tool: "search_nfts",
531
+ tool: "alchemy_search_contract_metadata",
515
532
  args: {
516
533
  query: {
517
534
  flag: "--query <text>",
518
535
  description: "Search term",
519
536
  required: true
520
- }
537
+ },
538
+ network: { flag: "--network <name>", description: "Alchemy network" }
521
539
  }
522
540
  }
523
541
  ]
524
542
  },
525
543
  {
526
544
  name: "network",
527
- description: "Blockchain infrastructure \u2014 chains, gas, blocks, transactions",
545
+ description: "Blockchain infrastructure: chains, gas, blocks, transactions",
528
546
  commands: [
529
547
  {
530
548
  name: "chains",
@@ -184,58 +184,6 @@ async function fetchToolCatalog() {
184
184
  }
185
185
  };
186
186
  }
187
- async function authSignup(email, password) {
188
- const url = buildApiUrl("/auth/signup");
189
- const response = await fetchWithRetry(url, {
190
- method: "POST",
191
- headers: { "Content-Type": "application/json" },
192
- body: JSON.stringify({ email, password })
193
- });
194
- return response.json();
195
- }
196
- async function authLogin(email, password) {
197
- const url = buildApiUrl("/auth/login");
198
- const response = await fetchWithRetry(url, {
199
- method: "POST",
200
- headers: { "Content-Type": "application/json" },
201
- body: JSON.stringify({ email, password })
202
- });
203
- return response.json();
204
- }
205
- async function authMe(jwt) {
206
- const url = buildApiUrl("/auth/me");
207
- const response = await fetchWithRetry(url, {
208
- headers: { Authorization: `Bearer ${jwt}` }
209
- });
210
- return response.json();
211
- }
212
- async function createKey(jwt, name) {
213
- const url = buildApiUrl("/api/v1/keys");
214
- const response = await fetchWithRetry(url, {
215
- method: "POST",
216
- headers: {
217
- "Content-Type": "application/json",
218
- Authorization: `Bearer ${jwt}`
219
- },
220
- body: JSON.stringify({ name })
221
- });
222
- return response.json();
223
- }
224
- async function listKeysApi(jwt) {
225
- const url = buildApiUrl("/api/v1/keys");
226
- const response = await fetchWithRetry(url, {
227
- headers: { Authorization: `Bearer ${jwt}` }
228
- });
229
- return response.json();
230
- }
231
- async function revokeKeyApi(jwt, keyId) {
232
- const url = buildApiUrl(`/api/v1/keys/${keyId}`);
233
- const response = await fetchWithRetry(url, {
234
- method: "DELETE",
235
- headers: { Authorization: `Bearer ${jwt}` }
236
- });
237
- return response.json();
238
- }
239
187
  async function getUsage() {
240
188
  const url = buildApiUrl("/api/v1/usage");
241
189
  const apiKey = resolveApiKey();
@@ -249,11 +197,5 @@ export {
249
197
  fetchWithRetry,
250
198
  executeRemoteTool,
251
199
  fetchToolCatalog,
252
- authSignup,
253
- authLogin,
254
- authMe,
255
- createKey,
256
- listKeysApi,
257
- revokeKeyApi,
258
200
  getUsage
259
201
  };
@@ -1,7 +1,7 @@
1
1
  import { createRequire } from 'node:module'; const require = createRequire(import.meta.url);
2
2
  import {
3
3
  executeRemoteTool
4
- } from "./chunk-Q7VBYLX7.js";
4
+ } from "./chunk-P7NLFSZQ.js";
5
5
  import {
6
6
  trackCommand
7
7
  } from "./chunk-RU6QOFHH.js";
@@ -50,7 +50,7 @@ function remapForKeylessHero(toolName, args) {
50
50
  return {
51
51
  tool: "get_token_price",
52
52
  args: { token, vs_currency: vsCurrency },
53
- note: "no API key \u2014 routed through the keyless get_token_price hero"
53
+ note: "no API key; routed through the keyless get_token_price hero"
54
54
  };
55
55
  }
56
56
  if (toolName === "get_token_security") {
@@ -61,7 +61,7 @@ function remapForKeylessHero(toolName, args) {
61
61
  return {
62
62
  tool: "check_token_safety",
63
63
  args: chain ? { address, chain } : { address },
64
- note: "no API key \u2014 routed through the keyless check_token_safety hero"
64
+ note: "no API key; routed through the keyless check_token_safety hero"
65
65
  };
66
66
  }
67
67
  if (toolName === "alchemy_get_tokens_by_wallet") {
@@ -72,7 +72,7 @@ function remapForKeylessHero(toolName, args) {
72
72
  return {
73
73
  tool: "get_wallet_portfolio",
74
74
  args: chain ? { address, chain } : { address },
75
- note: "no API key \u2014 routed through the keyless get_wallet_portfolio hero"
75
+ note: "no API key; routed through the keyless get_wallet_portfolio hero"
76
76
  };
77
77
  }
78
78
  return null;
@@ -110,7 +110,7 @@ async function executeTool(toolName, args, timeoutMs = 3e4) {
110
110
  if (typeof quotaRemaining === "number" && !resolveApiKey() && !shouldOutputJson()) {
111
111
  process.stderr.write(
112
112
  dim(
113
- `${quotaRemaining} free call${quotaRemaining === 1 ? "" : "s"} left today \u2014 run \`hive auth login\` for a full key.`
113
+ `${quotaRemaining} free call${quotaRemaining === 1 ? "" : "s"} left today. Run \`hive auth login\` for a full key.`
114
114
  ) + "\n"
115
115
  );
116
116
  }
@@ -212,7 +212,7 @@ function installSkillsForClient(client) {
212
212
  installed: [],
213
213
  skipped: [...SKILL_PACK_NAMES],
214
214
  destination: null,
215
- reason: "Client has no native skills directory \u2014 tools come over MCP"
215
+ reason: "Client has no native skills directory; tools come over MCP"
216
216
  };
217
217
  }
218
218
  const packsRoot = findBundledPacksDir();
@@ -222,7 +222,7 @@ function installSkillsForClient(client) {
222
222
  installed: [],
223
223
  skipped: [...SKILL_PACK_NAMES],
224
224
  destination: dest,
225
- reason: "Bundled skill packs not found \u2014 package install may be incomplete"
225
+ reason: "Bundled skill packs not found; the package install may be incomplete"
226
226
  };
227
227
  }
228
228
  if (!existsSync2(dest)) mkdirSync(dest, { recursive: true });