hive-intelligence 1.8.0 → 1.9.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/agent-skills/packs/hive/SKILL.md +10 -8
- package/agent-skills/packs/hive-mcp/SKILL.md +5 -4
- package/build/{chunk-HWV3XFXH.js → chunk-MVO6LL3H.js} +50 -5
- package/build/{chunk-ORJIFYF4.js → chunk-WQE3B64R.js} +26 -1
- package/build/cli.js +5 -5
- package/build/{doctor-5HAAZU4R.js → doctor-O2OQX6EX.js} +1 -1
- package/build/{mcpServer-LNRRWXSV.js → mcpServer-FXQPSDDC.js} +1 -1
- package/build/monitor-worker.js +50 -5
- package/build/release.json +4 -4
- package/build/{serve-MOP4WYH6.js → serve-BCKB6DMI.js} +1 -1
- package/build/server.js +129 -13
- package/build/stdio.js +1 -1
- package/package.json +1 -1
|
@@ -16,9 +16,9 @@ through one MCP server and one CLI, and every answer carries a receipt:
|
|
|
16
16
|
provider, fetch time, cache state, runtime status, and digests of the input
|
|
17
17
|
and result. Three things Hive has that most crypto data tools do not:
|
|
18
18
|
|
|
19
|
-
- **History that venues no longer serve.** Perp funding settlements
|
|
20
|
-
|
|
21
|
-
|
|
19
|
+
- **History that venues no longer serve.** Perp funding settlements for one
|
|
20
|
+
coin across up to 33 CEX and DEX venues since 2023-11, plus basis, open
|
|
21
|
+
interest and liquidations since 2025 and long/short ratios since 2026-03.
|
|
22
22
|
- **Cross-venue views.** One call compares funding or basis across venues
|
|
23
23
|
instead of one exchange at a time.
|
|
24
24
|
- **Provenance you can cite.** The `_hive` block on every material response
|
|
@@ -237,13 +237,15 @@ and probability claims are yours and must be labeled as such.
|
|
|
237
237
|
|
|
238
238
|
Discovery tools are free; every other tool costs one credit. Keyed lanes debit
|
|
239
239
|
only after validation and client resolution, so a validation error or a
|
|
240
|
-
missing provider key costs 0 and a call that
|
|
241
|
-
|
|
242
|
-
material request
|
|
240
|
+
missing provider key costs 0, and a call that fails after the debit is
|
|
241
|
+
refunded, so only a call that succeeds costs 1. The keyless lane takes one
|
|
242
|
+
allowance call per material request and gives it back when the call fails.
|
|
243
|
+
`report_feedback` is free on every lane.
|
|
243
244
|
|
|
244
245
|
Every material response says what it cost: `credit_cost` (0 or 1),
|
|
245
|
-
`credits_used` (what was
|
|
246
|
-
integer, `null` when unlimited, absent when the lane
|
|
246
|
+
`credits_used` (what the call cost, 0 when a failed call was refunded), and
|
|
247
|
+
`credits_remaining` (an integer, `null` when unlimited, absent when the lane
|
|
248
|
+
has no notion of it).
|
|
247
249
|
Do not print the balance on every call; mention it when it is low or when the
|
|
248
250
|
user asks.
|
|
249
251
|
|
|
@@ -27,10 +27,11 @@ file path and shape vary per client.
|
|
|
27
27
|
interactive path is live.
|
|
28
28
|
- **Cost** — discovery tools are free; every other tool costs one credit.
|
|
29
29
|
Keyed lanes debit only after validation and client resolution, so a
|
|
30
|
-
validation error or missing provider key costs 0 and a call that
|
|
31
|
-
|
|
32
|
-
allowance call per material request
|
|
33
|
-
reports `credit_cost`,
|
|
30
|
+
validation error or missing provider key costs 0, and a call that fails
|
|
31
|
+
after the debit is refunded, so only a call that succeeds costs 1. The
|
|
32
|
+
keyless lane takes one allowance call per material request and gives it back
|
|
33
|
+
when the call fails. Every material response reports `credit_cost`,
|
|
34
|
+
`credits_used`, and `credits_remaining`.
|
|
34
35
|
|
|
35
36
|
After hosted OAuth activation, interactive MCP setup does not require the user
|
|
36
37
|
to create or paste an API key. Route to `hive-build-onboarding` for direct CLI,
|
|
@@ -49029,7 +49029,14 @@ function getArchiveClient() {
|
|
|
49029
49029
|
// src/tools/archive/api.ts
|
|
49030
49030
|
var DEFAULT_LIMIT2 = 100;
|
|
49031
49031
|
var MAX_LIMIT2 = 500;
|
|
49032
|
-
var
|
|
49032
|
+
var ARCHIVE_SINCE = {
|
|
49033
|
+
funding: "2023-11",
|
|
49034
|
+
open_interest: "2025-04",
|
|
49035
|
+
basis: "2025-03",
|
|
49036
|
+
long_short: "2026-03",
|
|
49037
|
+
liquidations: "2025-04"
|
|
49038
|
+
};
|
|
49039
|
+
var ARCHIVE_SINCE_NOTE = `archive since ${ARCHIVE_SINCE.funding}`;
|
|
49033
49040
|
var QUERY_TIMEOUT_MS = 1e4;
|
|
49034
49041
|
var VENUE_SCAN_MAX_STEPS = 64;
|
|
49035
49042
|
var COVERAGE_CACHE_TTL_MS = 10 * 60 * 1e3;
|
|
@@ -49323,7 +49330,7 @@ function historyHandler(toolName, dataset, options) {
|
|
|
49323
49330
|
dataset: spec.table,
|
|
49324
49331
|
runtime_status: "ok",
|
|
49325
49332
|
fetched_at: (/* @__PURE__ */ new Date()).toISOString(),
|
|
49326
|
-
note: options?.extraNote ?
|
|
49333
|
+
note: options?.extraNote ? `archive since ${ARCHIVE_SINCE[dataset]}. ${options.extraNote}` : `archive since ${ARCHIVE_SINCE[dataset]}`,
|
|
49327
49334
|
filters,
|
|
49328
49335
|
order: `${spec.tsColumn} desc`,
|
|
49329
49336
|
returnedCount: mapped.length,
|
|
@@ -54132,7 +54139,7 @@ var PROVIDER_CATALOG = [
|
|
|
54132
54139
|
id: "archive",
|
|
54133
54140
|
name: "Hive Archive",
|
|
54134
54141
|
prefix: "archive_",
|
|
54135
|
-
type: "Cross-venue crypto derivatives history
|
|
54142
|
+
type: "Cross-venue crypto derivatives history from Hive's own archive store: funding-rate settlements across 33 CEX+DEX venues since 2023-11, basis since 2025-03, open interest and liquidations since 2025-04, and long/short ratio since 2026-03",
|
|
54136
54143
|
clientStrategy: "internal",
|
|
54137
54144
|
credentialRequirement: {
|
|
54138
54145
|
label: "SHARPE_ARCHIVE_SUPABASE_URL and SHARPE_ARCHIVE_SUPABASE_SERVICE_ROLE_KEY",
|
|
@@ -55266,7 +55273,7 @@ var ToolRegistry = [
|
|
|
55266
55273
|
{
|
|
55267
55274
|
category: "Market Data and Price",
|
|
55268
55275
|
name: "get_market_and_price_endpoints",
|
|
55269
|
-
description: "Endpoints to retrieve real-time and historical cryptocurrency prices, market caps, trading volumes, OHLC data, global market statistics, supported currencies, basic market performance metrics across different timeframes and asset platforms, stablecoin market analytics, stablecoin price tracking, comprehensive stablecoin market cap data across multiple chains, centralized exchange (CEX) trading data including real-time tickers, order books, recent trades, candlestick charts, best bid/ask prices, CEX exchange metadata and volume charts, derivatives pricing (index, mark, and premium), perpetual futures funding rates, leverage tiers, options trading analytics, and available trading markets/currencies across major exchanges. Provider guide: Use coingecko tools for market-wide price data. Use ccxt_ tools for CEX trading data. Use alchemy_ tools for supported token price reads and EVM gas data. Use archive_ tools for cross-venue derivatives HISTORY
|
|
55276
|
+
description: "Endpoints to retrieve real-time and historical cryptocurrency prices, market caps, trading volumes, OHLC data, global market statistics, supported currencies, basic market performance metrics across different timeframes and asset platforms, stablecoin market analytics, stablecoin price tracking, comprehensive stablecoin market cap data across multiple chains, centralized exchange (CEX) trading data including real-time tickers, order books, recent trades, candlestick charts, best bid/ask prices, CEX exchange metadata and volume charts, derivatives pricing (index, mark, and premium), perpetual futures funding rates, leverage tiers, options trading analytics, and available trading markets/currencies across major exchanges. Provider guide: Use coingecko tools for market-wide price data. Use ccxt_ tools for CEX trading data. Use alchemy_ tools for supported token price reads and EVM gas data. Use archive_ tools for cross-venue derivatives HISTORY: funding settlements since 2023-11; open interest, basis, long/short ratio and liquidations over shorter windows (archive_get_coverage gives exact depth).",
|
|
55270
55277
|
tools: [
|
|
55271
55278
|
"get_coins_index",
|
|
55272
55279
|
"get_coins_market_data",
|
|
@@ -57665,6 +57672,27 @@ function createHiveExecutionMetadata(endpoint, durationMs, runtimeStatus, source
|
|
|
57665
57672
|
function unchargedCredit(context) {
|
|
57666
57673
|
return context.creditCost === void 0 ? {} : { creditCost: context.creditCost, creditsUsed: 0 };
|
|
57667
57674
|
}
|
|
57675
|
+
var FAILED_CALL_REFUND_WARNING = "This call failed, so the credit it used was refunded.";
|
|
57676
|
+
async function refundFailedCall(billing, toolName, runtimeStatus, warnings) {
|
|
57677
|
+
if (!billing?.refund || billing.credits_used <= 0) return billing;
|
|
57678
|
+
try {
|
|
57679
|
+
const outcome = await billing.refund({ toolName, runtimeStatus });
|
|
57680
|
+
if (!outcome.refunded) return billing;
|
|
57681
|
+
warnings.push(FAILED_CALL_REFUND_WARNING);
|
|
57682
|
+
return {
|
|
57683
|
+
...billing,
|
|
57684
|
+
credits_used: 0,
|
|
57685
|
+
...outcome.creditsRemaining !== void 0 && {
|
|
57686
|
+
credits_remaining: outcome.creditsRemaining
|
|
57687
|
+
}
|
|
57688
|
+
};
|
|
57689
|
+
} catch (error) {
|
|
57690
|
+
secureLogger.error("Credit refund for a failed call failed", error, {
|
|
57691
|
+
toolName
|
|
57692
|
+
});
|
|
57693
|
+
return billing;
|
|
57694
|
+
}
|
|
57695
|
+
}
|
|
57668
57696
|
function chargedCredit(context, billing) {
|
|
57669
57697
|
if (context.creditCost === void 0 && !billing) return {};
|
|
57670
57698
|
return {
|
|
@@ -58261,6 +58289,14 @@ async function executeEndpoint(endpoint, args, context) {
|
|
|
58261
58289
|
);
|
|
58262
58290
|
}
|
|
58263
58291
|
}
|
|
58292
|
+
if (normalized.isError) {
|
|
58293
|
+
billing = await refundFailedCall(
|
|
58294
|
+
billing,
|
|
58295
|
+
endpoint.tool.name,
|
|
58296
|
+
runtimeStatus,
|
|
58297
|
+
guardWarnings
|
|
58298
|
+
);
|
|
58299
|
+
}
|
|
58264
58300
|
const durationMs = Date.now() - start;
|
|
58265
58301
|
const hive = createHiveExecutionMetadata(
|
|
58266
58302
|
endpoint,
|
|
@@ -58340,12 +58376,21 @@ async function executeEndpoint(endpoint, args, context) {
|
|
|
58340
58376
|
endpoint.tool.name,
|
|
58341
58377
|
args
|
|
58342
58378
|
);
|
|
58379
|
+
const thrownWarnings = [
|
|
58380
|
+
"Tool execution threw before returning a provider result."
|
|
58381
|
+
];
|
|
58382
|
+
billing = await refundFailedCall(
|
|
58383
|
+
billing,
|
|
58384
|
+
endpoint.tool.name,
|
|
58385
|
+
runtimeStatus,
|
|
58386
|
+
thrownWarnings
|
|
58387
|
+
);
|
|
58343
58388
|
const hive = createHiveExecutionMetadata(
|
|
58344
58389
|
endpoint,
|
|
58345
58390
|
durationMs,
|
|
58346
58391
|
runtimeStatus,
|
|
58347
58392
|
"unavailable",
|
|
58348
|
-
|
|
58393
|
+
thrownWarnings,
|
|
58349
58394
|
void 0,
|
|
58350
58395
|
{
|
|
58351
58396
|
input: args ?? {},
|
|
@@ -7,7 +7,7 @@ import {
|
|
|
7
7
|
getSupabaseAdmin,
|
|
8
8
|
resolveEndpoint,
|
|
9
9
|
secureLogger
|
|
10
|
-
} from "./chunk-
|
|
10
|
+
} from "./chunk-MVO6LL3H.js";
|
|
11
11
|
|
|
12
12
|
// src/services/wallet-service.ts
|
|
13
13
|
async function consumeCredits(args) {
|
|
@@ -34,6 +34,29 @@ async function consumeCredits(args) {
|
|
|
34
34
|
cycleEnd: row.cycle_end ?? null
|
|
35
35
|
};
|
|
36
36
|
}
|
|
37
|
+
async function refundCredits(args) {
|
|
38
|
+
const { userId, debitIdempotencyKey, detail } = args;
|
|
39
|
+
const { data, error } = await getSupabaseAdmin().rpc("refund_credits", {
|
|
40
|
+
p_user_id: userId,
|
|
41
|
+
p_debit_idempotency_key: debitIdempotencyKey,
|
|
42
|
+
p_detail: detail ?? {}
|
|
43
|
+
});
|
|
44
|
+
if (error) {
|
|
45
|
+
secureLogger.error("refund_credits RPC failed", error, { userId });
|
|
46
|
+
throw new Error(`refund_credits failed: ${error.message}`);
|
|
47
|
+
}
|
|
48
|
+
const row = Array.isArray(data) ? data[0] : data;
|
|
49
|
+
if (!row) {
|
|
50
|
+
throw new Error("refund_credits returned no row");
|
|
51
|
+
}
|
|
52
|
+
return {
|
|
53
|
+
code: row.code,
|
|
54
|
+
balance: row.balance ?? null
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
function refundSettled(code) {
|
|
58
|
+
return code === "ok" || code === "unlimited" || code === "already_refunded";
|
|
59
|
+
}
|
|
37
60
|
async function ensureWallet(userId, planId) {
|
|
38
61
|
const { error } = await getSupabaseAdmin().rpc("ensure_wallet", {
|
|
39
62
|
p_user_id: userId,
|
|
@@ -175,6 +198,8 @@ async function executeToolByName(toolName, args, options) {
|
|
|
175
198
|
|
|
176
199
|
export {
|
|
177
200
|
consumeCredits,
|
|
201
|
+
refundCredits,
|
|
202
|
+
refundSettled,
|
|
178
203
|
ensureWallet,
|
|
179
204
|
getWalletStatus,
|
|
180
205
|
applyPlanChange,
|
package/build/cli.js
CHANGED
|
@@ -3453,7 +3453,7 @@ program2.hook("preAction", (thisCommand) => {
|
|
|
3453
3453
|
setCliFlags({ apiKey: opts.apiKey, noRetry: opts.retry === false });
|
|
3454
3454
|
});
|
|
3455
3455
|
program2.action(async () => {
|
|
3456
|
-
const { startStdio } = await import("./serve-
|
|
3456
|
+
const { startStdio } = await import("./serve-BCKB6DMI.js");
|
|
3457
3457
|
await startStdio(program2.opts().envFile);
|
|
3458
3458
|
});
|
|
3459
3459
|
program2.command("serve").description("Start the MCP server").option("--http", "Start HTTP server instead of stdio").option("--port <number>", "HTTP server port", "8080").action(async (opts) => {
|
|
@@ -3466,10 +3466,10 @@ program2.command("serve").description("Start the MCP server").option("--http", "
|
|
|
3466
3466
|
);
|
|
3467
3467
|
process.exit(ExitCode.INVALID_ARGS);
|
|
3468
3468
|
}
|
|
3469
|
-
const { startHttp } = await import("./serve-
|
|
3469
|
+
const { startHttp } = await import("./serve-BCKB6DMI.js");
|
|
3470
3470
|
await startHttp(port, program2.opts().envFile);
|
|
3471
3471
|
} else {
|
|
3472
|
-
const { startStdio } = await import("./serve-
|
|
3472
|
+
const { startStdio } = await import("./serve-BCKB6DMI.js");
|
|
3473
3473
|
await startStdio(program2.opts().envFile);
|
|
3474
3474
|
}
|
|
3475
3475
|
});
|
|
@@ -3734,7 +3734,7 @@ program2.command("feedback <message>").description(
|
|
|
3734
3734
|
await runFeedback(message, { tool: opts.tool, receipt: opts.receipt });
|
|
3735
3735
|
});
|
|
3736
3736
|
program2.command("doctor").description("Diagnose environment and server connectivity").option("--probe", "Run live API probes (slower)").action(async (opts) => {
|
|
3737
|
-
const { runDoctor } = await import("./doctor-
|
|
3737
|
+
const { runDoctor } = await import("./doctor-O2OQX6EX.js");
|
|
3738
3738
|
await runDoctor(opts);
|
|
3739
3739
|
});
|
|
3740
3740
|
program2.command("upgrade").description("Update Hive to the latest published version").action(async () => {
|
|
@@ -3782,7 +3782,7 @@ program2.command("usage").description("Show your API usage and plan limits").act
|
|
|
3782
3782
|
await runUsage();
|
|
3783
3783
|
});
|
|
3784
3784
|
program2.command("status").description("Quick health and version check").action(async () => {
|
|
3785
|
-
const { runStatus } = await import("./doctor-
|
|
3785
|
+
const { runStatus } = await import("./doctor-O2OQX6EX.js");
|
|
3786
3786
|
await runStatus();
|
|
3787
3787
|
});
|
|
3788
3788
|
program2.command("open [target]").description("Open Hive dashboard, docs, status, or GitHub in browser").action(async (target) => {
|
|
@@ -240,7 +240,7 @@ ${fails === 0 ? "All checks passed" : `${fails} issues found`}${warns ? ` (${war
|
|
|
240
240
|
if (fails > 0) process.exit(1);
|
|
241
241
|
}
|
|
242
242
|
async function runStatus() {
|
|
243
|
-
const { SERVER_VERSION } = await import("./mcpServer-
|
|
243
|
+
const { SERVER_VERSION } = await import("./mcpServer-FXQPSDDC.js");
|
|
244
244
|
const { resolveApiKey, resolveApiUrl } = await import("./config-dir-2QLA5PXD.js");
|
|
245
245
|
const { getActiveProfile, maskKey } = await import("./auth-6XVL5CE3.js");
|
|
246
246
|
const apiUrl = resolveApiUrl();
|
package/build/monitor-worker.js
CHANGED
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
import { createRequire } from 'node:module'; const require = createRequire(import.meta.url);
|
|
2
2
|
import {
|
|
3
3
|
consumeCredits,
|
|
4
|
-
executeToolByName
|
|
5
|
-
|
|
4
|
+
executeToolByName,
|
|
5
|
+
refundCredits,
|
|
6
|
+
refundSettled
|
|
7
|
+
} from "./chunk-WQE3B64R.js";
|
|
6
8
|
import {
|
|
7
9
|
HyperliquidAPI,
|
|
8
10
|
MIN_MONITOR_CADENCE_MS,
|
|
@@ -15,7 +17,7 @@ import {
|
|
|
15
17
|
monitorCadenceIntervalMs,
|
|
16
18
|
runScheduledHealthCanaries,
|
|
17
19
|
secureLogger
|
|
18
|
-
} from "./chunk-
|
|
20
|
+
} from "./chunk-MVO6LL3H.js";
|
|
19
21
|
import "./chunk-4QDGA6GP.js";
|
|
20
22
|
import "./chunk-EPF36Q3Z.js";
|
|
21
23
|
import "./chunk-ZXKFJQDE.js";
|
|
@@ -640,6 +642,29 @@ async function defaultConsumeCredit(args) {
|
|
|
640
642
|
requestId: args.runId
|
|
641
643
|
});
|
|
642
644
|
}
|
|
645
|
+
async function defaultRefundCredit(args) {
|
|
646
|
+
const refund = await refundCredits({
|
|
647
|
+
userId: args.userId,
|
|
648
|
+
debitIdempotencyKey: `monitor-run:${args.runId}`,
|
|
649
|
+
detail: { monitor_run: args.runId, reason: args.reason }
|
|
650
|
+
});
|
|
651
|
+
return refundSettled(refund.code);
|
|
652
|
+
}
|
|
653
|
+
async function refundMonitorRunCredit(args) {
|
|
654
|
+
try {
|
|
655
|
+
return await args.refundCredit({
|
|
656
|
+
userId: args.monitor.user_id,
|
|
657
|
+
runId: args.runId,
|
|
658
|
+
reason: args.reason
|
|
659
|
+
});
|
|
660
|
+
} catch (error) {
|
|
661
|
+
secureLogger.error("Monitor run credit refund failed", error, {
|
|
662
|
+
monitorId: args.monitor.id,
|
|
663
|
+
runId: args.runId
|
|
664
|
+
});
|
|
665
|
+
return false;
|
|
666
|
+
}
|
|
667
|
+
}
|
|
643
668
|
async function debitMonitorRunCredit(args) {
|
|
644
669
|
try {
|
|
645
670
|
const debit = await args.consumeCredit({
|
|
@@ -976,6 +1001,7 @@ async function processMonitor(monitor, options) {
|
|
|
976
1001
|
});
|
|
977
1002
|
const completedAt = options.now.toISOString();
|
|
978
1003
|
const nextRunAt = computeNextRunAt(monitor.cadence, options.now);
|
|
1004
|
+
let charged = false;
|
|
979
1005
|
try {
|
|
980
1006
|
const debit = await debitMonitorRunCredit({
|
|
981
1007
|
monitor,
|
|
@@ -1007,6 +1033,7 @@ async function processMonitor(monitor, options) {
|
|
|
1007
1033
|
alerts: 0
|
|
1008
1034
|
};
|
|
1009
1035
|
}
|
|
1036
|
+
charged = true;
|
|
1010
1037
|
const previous = await options.store.getLatestSnapshot(monitor.id);
|
|
1011
1038
|
const workflow = await executeMonitorWorkflow(
|
|
1012
1039
|
monitor,
|
|
@@ -1101,6 +1128,13 @@ async function processMonitor(monitor, options) {
|
|
|
1101
1128
|
});
|
|
1102
1129
|
observations++;
|
|
1103
1130
|
}
|
|
1131
|
+
const everyCallFailed = workflow.toolCalls.length > 0 && workflow.failedCalls.length === workflow.toolCalls.length;
|
|
1132
|
+
const creditRefunded = everyCallFailed ? await refundMonitorRunCredit({
|
|
1133
|
+
monitor,
|
|
1134
|
+
runId: run.id,
|
|
1135
|
+
reason: "every tool call failed",
|
|
1136
|
+
refundCredit: options.refundCredit
|
|
1137
|
+
}) : false;
|
|
1104
1138
|
await options.store.finishRun({
|
|
1105
1139
|
runId: run.id,
|
|
1106
1140
|
status: "completed",
|
|
@@ -1109,7 +1143,8 @@ async function processMonitor(monitor, options) {
|
|
|
1109
1143
|
metadata: {
|
|
1110
1144
|
fingerprint: workflow.fingerprint,
|
|
1111
1145
|
failed_call_count: workflow.failedCalls.length,
|
|
1112
|
-
rule_evaluation_count: ruleEvaluations.length
|
|
1146
|
+
rule_evaluation_count: ruleEvaluations.length,
|
|
1147
|
+
...creditRefunded && { credit_refunded: true }
|
|
1113
1148
|
}
|
|
1114
1149
|
});
|
|
1115
1150
|
await options.store.releaseMonitor({
|
|
@@ -1129,6 +1164,14 @@ async function processMonitor(monitor, options) {
|
|
|
1129
1164
|
};
|
|
1130
1165
|
} catch (error) {
|
|
1131
1166
|
const message = error instanceof Error ? error.message : String(error);
|
|
1167
|
+
if (charged) {
|
|
1168
|
+
await refundMonitorRunCredit({
|
|
1169
|
+
monitor,
|
|
1170
|
+
runId: run.id,
|
|
1171
|
+
reason: "run failed",
|
|
1172
|
+
refundCredit: options.refundCredit
|
|
1173
|
+
});
|
|
1174
|
+
}
|
|
1132
1175
|
await options.store.finishRun({
|
|
1133
1176
|
runId: run.id,
|
|
1134
1177
|
status: "failed",
|
|
@@ -1165,6 +1208,7 @@ async function runDueMonitors(options = {}) {
|
|
|
1165
1208
|
const now = options.now ?? /* @__PURE__ */ new Date();
|
|
1166
1209
|
const executeTool = options.executeTool ?? executeToolByName;
|
|
1167
1210
|
const consumeCredit = options.consumeCredit ?? defaultConsumeCredit;
|
|
1211
|
+
const refundCredit = options.refundCredit ?? defaultRefundCredit;
|
|
1168
1212
|
const source = options.source ?? "scheduled";
|
|
1169
1213
|
const claimed = await store.claimDueMonitors({
|
|
1170
1214
|
batchSize,
|
|
@@ -1191,7 +1235,8 @@ async function runDueMonitors(options = {}) {
|
|
|
1191
1235
|
now,
|
|
1192
1236
|
source,
|
|
1193
1237
|
executeTool,
|
|
1194
|
-
consumeCredit
|
|
1238
|
+
consumeCredit,
|
|
1239
|
+
refundCredit
|
|
1195
1240
|
})
|
|
1196
1241
|
);
|
|
1197
1242
|
}
|
package/build/release.json
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
{
|
|
2
2
|
"package": "hive-intelligence",
|
|
3
|
-
"version": "1.
|
|
4
|
-
"buildSha": "
|
|
5
|
-
"imageDigest": "sha256:
|
|
3
|
+
"version": "1.9.0",
|
|
4
|
+
"buildSha": "b157f6642120d33dd3c241c366731f0174a56902",
|
|
5
|
+
"imageDigest": "sha256:103576df07830e955af1f472dc39b365862c8b5a6965d2a944be363ea4e8b976",
|
|
6
6
|
"deployedUrl": "https://mcp.hiveintelligence.xyz",
|
|
7
|
-
"manifest": "https://raw.githubusercontent.com/hive-intel/hive-sdk/v1.
|
|
7
|
+
"manifest": "https://raw.githubusercontent.com/hive-intel/hive-sdk/v1.9.0/releases/v1.9.0.json"
|
|
8
8
|
}
|
|
@@ -7,7 +7,7 @@ async function startStdio(envFile) {
|
|
|
7
7
|
dotenv.config({ path: envFile || ".env", quiet: true });
|
|
8
8
|
console.log = (...args) => console.error("[LOG]", ...args);
|
|
9
9
|
const { StdioServerTransport } = await import("@modelcontextprotocol/sdk/server/stdio.js");
|
|
10
|
-
const { createHiveMcpServer, SERVER_NAME, SERVER_VERSION } = await import("./mcpServer-
|
|
10
|
+
const { createHiveMcpServer, SERVER_NAME, SERVER_VERSION } = await import("./mcpServer-FXQPSDDC.js");
|
|
11
11
|
const { getPendingUpdateVersion } = await import("./update-check-36QU6PKA.js");
|
|
12
12
|
const transport = new StdioServerTransport();
|
|
13
13
|
const pendingUpdate = getPendingUpdateVersion();
|
package/build/server.js
CHANGED
|
@@ -5,8 +5,10 @@ import {
|
|
|
5
5
|
consumeCredits,
|
|
6
6
|
ensureWallet,
|
|
7
7
|
executeToolByName,
|
|
8
|
-
getWalletStatus
|
|
9
|
-
|
|
8
|
+
getWalletStatus,
|
|
9
|
+
refundCredits,
|
|
10
|
+
refundSettled
|
|
11
|
+
} from "./chunk-WQE3B64R.js";
|
|
10
12
|
import {
|
|
11
13
|
CategoryEndpoints,
|
|
12
14
|
HERO_TOOL_NAMES,
|
|
@@ -102,7 +104,7 @@ import {
|
|
|
102
104
|
validateEndpointArgs,
|
|
103
105
|
verifyApiKey,
|
|
104
106
|
waitForRedisAvailability
|
|
105
|
-
} from "./chunk-
|
|
107
|
+
} from "./chunk-MVO6LL3H.js";
|
|
106
108
|
import {
|
|
107
109
|
HIVE_AGENT_SKILLS
|
|
108
110
|
} from "./chunk-4QDGA6GP.js";
|
|
@@ -2598,10 +2600,11 @@ async function debitApiKeyCreditForExecution(req, res) {
|
|
|
2598
2600
|
const result = authReq.unkeyResult;
|
|
2599
2601
|
if (!result || !authReq.userId) return;
|
|
2600
2602
|
try {
|
|
2603
|
+
const idempotencyKey = authReq.creditDebitIdempotencyKey ?? randomUUID();
|
|
2601
2604
|
const consumeResult = await consumeCredits({
|
|
2602
2605
|
userId: authReq.userId,
|
|
2603
2606
|
cost: REQUEST_COST,
|
|
2604
|
-
idempotencyKey
|
|
2607
|
+
idempotencyKey,
|
|
2605
2608
|
requestId: req.requestId,
|
|
2606
2609
|
keyId: authReq.unkeyKeyId
|
|
2607
2610
|
});
|
|
@@ -2627,6 +2630,7 @@ async function debitApiKeyCreditForExecution(req, res) {
|
|
|
2627
2630
|
};
|
|
2628
2631
|
}
|
|
2629
2632
|
authReq.quotaRemaining = consumeResult.balance ?? void 0;
|
|
2633
|
+
authReq.creditDebitedKey = idempotencyKey;
|
|
2630
2634
|
authReq.idempotencyExecutionStarted = true;
|
|
2631
2635
|
res.setHeader(
|
|
2632
2636
|
"X-Quota-Remaining",
|
|
@@ -5556,6 +5560,23 @@ async function consumeAnonMaterialQuota(ipHash, overrides = {}) {
|
|
|
5556
5560
|
return { allowed: false, reason: "unavailable" };
|
|
5557
5561
|
}
|
|
5558
5562
|
}
|
|
5563
|
+
async function refundAnonMaterialQuota(ipHash) {
|
|
5564
|
+
try {
|
|
5565
|
+
if (!isSupabaseConfigured()) return void 0;
|
|
5566
|
+
const { data, error } = await getSupabaseAdmin().rpc(
|
|
5567
|
+
"refund_anon_daily_quota",
|
|
5568
|
+
{ p_ip_hash: ipHash, p_ip_limit: getAnonDailyMaterialCap() }
|
|
5569
|
+
);
|
|
5570
|
+
if (error) throw new Error(error.message);
|
|
5571
|
+
const row = Array.isArray(data) ? data[0] : data;
|
|
5572
|
+
return typeof row?.remaining === "number" ? row.remaining : void 0;
|
|
5573
|
+
} catch (err) {
|
|
5574
|
+
secureLogger.warn("Anonymous quota refund failed", {
|
|
5575
|
+
error: err instanceof Error ? err.message : String(err)
|
|
5576
|
+
});
|
|
5577
|
+
return void 0;
|
|
5578
|
+
}
|
|
5579
|
+
}
|
|
5559
5580
|
|
|
5560
5581
|
// src/serverCard.ts
|
|
5561
5582
|
function buildServerCard() {
|
|
@@ -6925,10 +6946,11 @@ function buildMcpQuotaExhaustedCopy(args) {
|
|
|
6925
6946
|
}
|
|
6926
6947
|
async function debitMcpCredits(args) {
|
|
6927
6948
|
try {
|
|
6949
|
+
const idempotencyKey = randomUUID4();
|
|
6928
6950
|
const debit = await consumeCredits({
|
|
6929
6951
|
userId: args.userId,
|
|
6930
6952
|
cost: 1,
|
|
6931
|
-
idempotencyKey
|
|
6953
|
+
idempotencyKey,
|
|
6932
6954
|
requestId: args.requestId,
|
|
6933
6955
|
keyId: args.keyId
|
|
6934
6956
|
});
|
|
@@ -6952,7 +6974,7 @@ async function debitMcpCredits(args) {
|
|
|
6952
6974
|
rateLimited: true
|
|
6953
6975
|
};
|
|
6954
6976
|
}
|
|
6955
|
-
return { ok: true, balance: debit.balance };
|
|
6977
|
+
return { ok: true, balance: debit.balance, idempotencyKey };
|
|
6956
6978
|
} catch (err) {
|
|
6957
6979
|
secureLogger.warn("MCP consume_credits debit failed", {
|
|
6958
6980
|
error: err instanceof Error ? err.message : String(err)
|
|
@@ -6963,6 +6985,32 @@ async function debitMcpCredits(args) {
|
|
|
6963
6985
|
};
|
|
6964
6986
|
}
|
|
6965
6987
|
}
|
|
6988
|
+
async function refundKeyedCredit(res, args) {
|
|
6989
|
+
const refund = await refundCredits({
|
|
6990
|
+
userId: args.userId,
|
|
6991
|
+
debitIdempotencyKey: args.debitIdempotencyKey,
|
|
6992
|
+
detail: {
|
|
6993
|
+
tool: args.toolName,
|
|
6994
|
+
runtime_status: args.runtimeStatus,
|
|
6995
|
+
transport: args.transport
|
|
6996
|
+
}
|
|
6997
|
+
});
|
|
6998
|
+
if (!refundSettled(refund.code)) return { refunded: false };
|
|
6999
|
+
if (!res.headersSent) {
|
|
7000
|
+
res.setHeader(
|
|
7001
|
+
"X-Quota-Remaining",
|
|
7002
|
+
refund.balance === null ? "unlimited" : String(refund.balance)
|
|
7003
|
+
);
|
|
7004
|
+
}
|
|
7005
|
+
return { refunded: true, creditsRemaining: refund.balance };
|
|
7006
|
+
}
|
|
7007
|
+
async function refundAnonCall(res, ipHash) {
|
|
7008
|
+
const remaining = await refundAnonMaterialQuota(ipHash);
|
|
7009
|
+
if (remaining !== void 0 && !res.headersSent) {
|
|
7010
|
+
res.setHeader("X-Quota-Remaining", String(remaining));
|
|
7011
|
+
}
|
|
7012
|
+
return remaining;
|
|
7013
|
+
}
|
|
6966
7014
|
function extractApiKey(req) {
|
|
6967
7015
|
return req.headers["x-api-key"] ?? (req.headers.authorization?.startsWith("Bearer ") ? req.headers.authorization.slice(7) : void 0);
|
|
6968
7016
|
}
|
|
@@ -7412,10 +7460,10 @@ function createStatelessMcpHandler(scope) {
|
|
|
7412
7460
|
if (!auth.ok && !mcpCredentialPresented(req)) {
|
|
7413
7461
|
const decision = await authorizeAnonymousMcpRequest(req);
|
|
7414
7462
|
if (decision.kind === "allow") {
|
|
7463
|
+
const ipHash = anonymousIpHash(ipRateLimitKeyFromRequest(req));
|
|
7415
7464
|
anonymousLane = {
|
|
7416
|
-
principalRaw: `anon:${
|
|
7417
|
-
|
|
7418
|
-
)}`,
|
|
7465
|
+
principalRaw: `anon:${ipHash}`,
|
|
7466
|
+
ipHash,
|
|
7419
7467
|
materialGranted: decision.materialGranted,
|
|
7420
7468
|
quotaRemaining: decision.quotaRemaining
|
|
7421
7469
|
};
|
|
@@ -7641,6 +7689,8 @@ function createStatelessMcpHandler(scope) {
|
|
|
7641
7689
|
clientName: resolveMcpClientName(req, body),
|
|
7642
7690
|
isInternal: isMonitorSecretRequest(req)
|
|
7643
7691
|
};
|
|
7692
|
+
let anonCallHeld = anonymousLane?.materialGranted === true;
|
|
7693
|
+
let anonCallBilled = false;
|
|
7644
7694
|
const server = createHiveMcpServer(scope, {
|
|
7645
7695
|
requestId: req.requestId,
|
|
7646
7696
|
analytics,
|
|
@@ -7698,6 +7748,7 @@ function createStatelessMcpHandler(scope) {
|
|
|
7698
7748
|
beforeToolExecution: keyedAuth?.userId ? async (executedToolName) => {
|
|
7699
7749
|
const creditCost = getMcpCreditCost(executedToolName);
|
|
7700
7750
|
let keyedBalance;
|
|
7751
|
+
let debitKey;
|
|
7701
7752
|
res.setHeader("X-Hive-Credit-Cost", String(creditCost));
|
|
7702
7753
|
if (creditCost > 0) {
|
|
7703
7754
|
const debit = await debitMcpCredits({
|
|
@@ -7741,10 +7792,22 @@ function createStatelessMcpHandler(scope) {
|
|
|
7741
7792
|
debit.balance === null ? "unlimited" : String(debit.balance)
|
|
7742
7793
|
);
|
|
7743
7794
|
keyedBalance = debit.balance;
|
|
7795
|
+
debitKey = debit.idempotencyKey;
|
|
7744
7796
|
}
|
|
7797
|
+
const refund = debitKey ? (reason) => refundKeyedCredit(res, {
|
|
7798
|
+
userId: keyedAuth.userId,
|
|
7799
|
+
debitIdempotencyKey: debitKey,
|
|
7800
|
+
toolName: reason.toolName,
|
|
7801
|
+
runtimeStatus: reason.runtimeStatus,
|
|
7802
|
+
transport: "mcp"
|
|
7803
|
+
}) : void 0;
|
|
7745
7804
|
if (subjectContext) {
|
|
7746
7805
|
const materialized = await materializeSubjectContext(subjectContext);
|
|
7747
7806
|
if (!materialized.ok) {
|
|
7807
|
+
await refund?.({
|
|
7808
|
+
toolName: executedToolName,
|
|
7809
|
+
runtimeStatus: "failing"
|
|
7810
|
+
}).catch(() => void 0);
|
|
7748
7811
|
return {
|
|
7749
7812
|
type: materialized.status === 403 ? "authentication_error" : "internal_error",
|
|
7750
7813
|
code: materialized.code,
|
|
@@ -7768,7 +7831,8 @@ function createStatelessMcpHandler(scope) {
|
|
|
7768
7831
|
return {
|
|
7769
7832
|
type: "billing",
|
|
7770
7833
|
credits_used: creditCost,
|
|
7771
|
-
...creditCost > 0 && { credits_remaining: keyedBalance }
|
|
7834
|
+
...creditCost > 0 && { credits_remaining: keyedBalance },
|
|
7835
|
+
...refund && { refund }
|
|
7772
7836
|
};
|
|
7773
7837
|
} : anonymousLane ? async (executedToolName) => {
|
|
7774
7838
|
const creditCost = getMcpCreditCost(executedToolName);
|
|
@@ -7790,10 +7854,36 @@ function createStatelessMcpHandler(scope) {
|
|
|
7790
7854
|
runtimeStatus: "failing"
|
|
7791
7855
|
};
|
|
7792
7856
|
}
|
|
7857
|
+
if (!anonCallHeld) {
|
|
7858
|
+
const quota = await consumeAnonMaterialQuota(
|
|
7859
|
+
anonymousLane.ipHash
|
|
7860
|
+
);
|
|
7861
|
+
if (!quota.allowed) {
|
|
7862
|
+
return {
|
|
7863
|
+
type: "rate_limit_error",
|
|
7864
|
+
code: "ANON_QUOTA_EXCEEDED",
|
|
7865
|
+
message: ANON_QUOTA_EXHAUSTED_MESSAGE,
|
|
7866
|
+
runtimeStatus: "rate_limited"
|
|
7867
|
+
};
|
|
7868
|
+
}
|
|
7869
|
+
anonCallHeld = true;
|
|
7870
|
+
anonymousLane.quotaRemaining = quota.remaining;
|
|
7871
|
+
}
|
|
7872
|
+
anonCallBilled = true;
|
|
7793
7873
|
return {
|
|
7794
7874
|
type: "billing",
|
|
7795
7875
|
credits_used: creditCost,
|
|
7796
|
-
credits_remaining: anonymousLane.quotaRemaining ?? null
|
|
7876
|
+
credits_remaining: anonymousLane.quotaRemaining ?? null,
|
|
7877
|
+
refund: async () => {
|
|
7878
|
+
const remaining = await refundAnonCall(
|
|
7879
|
+
res,
|
|
7880
|
+
anonymousLane.ipHash
|
|
7881
|
+
);
|
|
7882
|
+
if (remaining === void 0) return { refunded: false };
|
|
7883
|
+
anonCallHeld = false;
|
|
7884
|
+
anonymousLane.quotaRemaining = remaining;
|
|
7885
|
+
return { refunded: true, creditsRemaining: remaining };
|
|
7886
|
+
}
|
|
7797
7887
|
};
|
|
7798
7888
|
} : void 0
|
|
7799
7889
|
}).getServer();
|
|
@@ -7820,6 +7910,10 @@ function createStatelessMcpHandler(scope) {
|
|
|
7820
7910
|
() => transport.handleRequest(req, res, body)
|
|
7821
7911
|
)
|
|
7822
7912
|
);
|
|
7913
|
+
if (anonymousLane && anonCallHeld && !anonCallBilled) {
|
|
7914
|
+
anonCallHeld = false;
|
|
7915
|
+
await refundAnonCall(res, anonymousLane.ipHash);
|
|
7916
|
+
}
|
|
7823
7917
|
secureLogger.debug("MCP request completed", {
|
|
7824
7918
|
sessionId: sessionCorrelationId,
|
|
7825
7919
|
scope: scope.kind === "root" ? "root" : `category:${scope.category}`
|
|
@@ -8341,6 +8435,7 @@ var anonymousHeroExecuteMiddleware = asyncHandler(
|
|
|
8341
8435
|
return;
|
|
8342
8436
|
}
|
|
8343
8437
|
res.setHeader("X-Quota-Remaining", String(quota.remaining));
|
|
8438
|
+
let refundAttempted = false;
|
|
8344
8439
|
const result = await executeEndpoint(heroEndpoint, body?.args ?? {}, {
|
|
8345
8440
|
transport: "rest",
|
|
8346
8441
|
requestId: req.requestId,
|
|
@@ -8349,7 +8444,12 @@ var anonymousHeroExecuteMiddleware = asyncHandler(
|
|
|
8349
8444
|
beforeExecution: async () => ({
|
|
8350
8445
|
type: "billing",
|
|
8351
8446
|
credits_used: getMcpCreditCost(toolName),
|
|
8352
|
-
credits_remaining: quota.remaining
|
|
8447
|
+
credits_remaining: quota.remaining,
|
|
8448
|
+
refund: async () => {
|
|
8449
|
+
refundAttempted = true;
|
|
8450
|
+
const remaining = await refundAnonCall(res, ipHash);
|
|
8451
|
+
return remaining === void 0 ? { refunded: false } : { refunded: true, creditsRemaining: remaining };
|
|
8452
|
+
}
|
|
8353
8453
|
}),
|
|
8354
8454
|
analytics: {
|
|
8355
8455
|
principalRaw: `anon:${ipHash}`,
|
|
@@ -8358,6 +8458,9 @@ var anonymousHeroExecuteMiddleware = asyncHandler(
|
|
|
8358
8458
|
isInternal: isMonitorSecretRequest(req)
|
|
8359
8459
|
}
|
|
8360
8460
|
});
|
|
8461
|
+
if (!result.ok && !refundAttempted) {
|
|
8462
|
+
await refundAnonCall(res, ipHash);
|
|
8463
|
+
}
|
|
8361
8464
|
const meta = buildRestExecutionMeta(
|
|
8362
8465
|
toolName,
|
|
8363
8466
|
result.durationMs,
|
|
@@ -8413,6 +8516,14 @@ app.post(
|
|
|
8413
8516
|
const endpointArgs = authReq.resolvedRestToolArgs ?? { ...args ?? {} };
|
|
8414
8517
|
const keyedBeforeExecution = async (endpoint) => {
|
|
8415
8518
|
const blocked = await debitApiKeyCreditForExecution(req, res);
|
|
8519
|
+
const debitKey = authReq.creditDebitedKey;
|
|
8520
|
+
const refund = debitKey && authReq.userId ? (reason) => refundKeyedCredit(res, {
|
|
8521
|
+
userId: authReq.userId,
|
|
8522
|
+
debitIdempotencyKey: debitKey,
|
|
8523
|
+
toolName: reason.toolName,
|
|
8524
|
+
runtimeStatus: reason.runtimeStatus,
|
|
8525
|
+
transport: "rest"
|
|
8526
|
+
}) : void 0;
|
|
8416
8527
|
if (blocked) {
|
|
8417
8528
|
if (blocked.code === "QUOTA_EXCEEDED") {
|
|
8418
8529
|
recordPaywall(req, {
|
|
@@ -8431,6 +8542,10 @@ app.post(
|
|
|
8431
8542
|
authReq.hiveSubjectContext
|
|
8432
8543
|
);
|
|
8433
8544
|
if (!materialized.ok) {
|
|
8545
|
+
await refund?.({
|
|
8546
|
+
toolName: endpoint.tool.name,
|
|
8547
|
+
runtimeStatus: "failing"
|
|
8548
|
+
}).catch(() => void 0);
|
|
8434
8549
|
return {
|
|
8435
8550
|
type: materialized.status === 403 ? "authentication_error" : "internal_error",
|
|
8436
8551
|
code: materialized.code,
|
|
@@ -8458,7 +8573,8 @@ app.post(
|
|
|
8458
8573
|
credits_used: creditCost,
|
|
8459
8574
|
...creditCost > 0 && remainingHeader !== void 0 && {
|
|
8460
8575
|
credits_remaining: String(remainingHeader) === "unlimited" ? null : Number(remainingHeader)
|
|
8461
|
-
}
|
|
8576
|
+
},
|
|
8577
|
+
...refund && { refund }
|
|
8462
8578
|
};
|
|
8463
8579
|
};
|
|
8464
8580
|
const heroEndpoint = HERO_TOOL_NAMES.has(executionToolName) ? getRestHeroEndpoint(executionToolName) : void 0;
|
package/build/stdio.js
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "hive-intelligence",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.9.0",
|
|
4
4
|
"description": "Evidence-backed crypto due diligence for AI agents, with sources, freshness, and a runtime receipt on every call.",
|
|
5
5
|
"mcpName": "xyz.hiveintelligence/mcp",
|
|
6
6
|
"type": "module",
|