opentool 0.10.1 → 0.10.4
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/dist/adapters/hyperliquid/index.d.ts +98 -1
- package/dist/adapters/hyperliquid/index.js +266 -2
- package/dist/adapters/hyperliquid/index.js.map +1 -1
- package/dist/cli/index.d.ts +3 -4
- package/dist/cli/index.js +93 -78
- package/dist/cli/index.js.map +1 -1
- package/dist/index.d.ts +36 -5
- package/dist/index.js +733 -398
- package/dist/index.js.map +1 -1
- package/dist/payment-orkZA9se.d.ts +96 -0
- package/dist/{validate-BgNU5laL.d.ts → validate-DbhJ_r0Z.d.ts} +1 -1
- package/dist/x402/index.d.ts +2 -96
- package/dist/x402/index.js +157 -157
- package/dist/x402/index.js.map +1 -1
- package/package.json +1 -1
- package/templates/base/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import * as path6 from 'path';
|
|
2
|
-
import { fileURLToPath, pathToFileURL } from 'url';
|
|
3
1
|
import { Server } from '@modelcontextprotocol/sdk/server/index.js';
|
|
4
2
|
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
|
|
5
3
|
import { ListToolsRequestSchema, CallToolRequestSchema } from '@modelcontextprotocol/sdk/types.js';
|
|
6
|
-
import * as
|
|
4
|
+
import * as fs4 from 'fs';
|
|
5
|
+
import * as path5 from 'path';
|
|
6
|
+
import { fileURLToPath, pathToFileURL } from 'url';
|
|
7
7
|
import { zodToJsonSchema } from '@alcyone-labs/zod-to-json-schema';
|
|
8
8
|
import { z } from 'zod';
|
|
9
9
|
import { zeroAddress, createWalletClient, http, createPublicClient, parseUnits, encodeFunctionData, erc20Abi } from 'viem';
|
|
@@ -25,8 +25,6 @@ var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require
|
|
|
25
25
|
if (typeof require !== "undefined") return require.apply(this, arguments);
|
|
26
26
|
throw Error('Dynamic require of "' + x + '" is not supported');
|
|
27
27
|
});
|
|
28
|
-
var getFilename = () => fileURLToPath(import.meta.url);
|
|
29
|
-
var __filename$1 = /* @__PURE__ */ getFilename();
|
|
30
28
|
var X402_VERSION = 1;
|
|
31
29
|
var HEADER_X402 = "X-PAYMENT";
|
|
32
30
|
var HEADER_PAYMENT_RESPONSE = "X-PAYMENT-RESPONSE";
|
|
@@ -331,295 +329,8 @@ function ensureTrailingSlash(url) {
|
|
|
331
329
|
return url.endsWith("/") ? url : `${url}/`;
|
|
332
330
|
}
|
|
333
331
|
var PAYMENT_HEADERS = [HEADER_X402, HEADER_PAYMENT_RESPONSE];
|
|
334
|
-
var X402Client = class {
|
|
335
|
-
constructor(config) {
|
|
336
|
-
this.account = privateKeyToAccount(config.privateKey);
|
|
337
|
-
const chain = baseSepolia;
|
|
338
|
-
this.walletClient = createWalletClient({
|
|
339
|
-
account: this.account,
|
|
340
|
-
chain,
|
|
341
|
-
transport: http(config.rpcUrl)
|
|
342
|
-
});
|
|
343
|
-
}
|
|
344
|
-
async pay(request) {
|
|
345
|
-
try {
|
|
346
|
-
const initialResponse = await fetch(request.url, {
|
|
347
|
-
method: request.method ?? "POST",
|
|
348
|
-
headers: {
|
|
349
|
-
"Content-Type": "application/json",
|
|
350
|
-
...request.headers
|
|
351
|
-
},
|
|
352
|
-
...request.body ? { body: JSON.stringify(request.body) } : {}
|
|
353
|
-
});
|
|
354
|
-
if (initialResponse.status !== 402) {
|
|
355
|
-
return {
|
|
356
|
-
success: initialResponse.ok,
|
|
357
|
-
response: initialResponse
|
|
358
|
-
};
|
|
359
|
-
}
|
|
360
|
-
const paymentRequirements = await initialResponse.json();
|
|
361
|
-
const x402Requirements = paymentRequirements.x402?.accepts?.[0];
|
|
362
|
-
if (!x402Requirements) {
|
|
363
|
-
return {
|
|
364
|
-
success: false,
|
|
365
|
-
error: "No x402 payment requirements found in 402 response"
|
|
366
|
-
};
|
|
367
|
-
}
|
|
368
|
-
const authorization = await this.signTransferAuthorization({
|
|
369
|
-
from: this.account.address,
|
|
370
|
-
to: x402Requirements.payTo,
|
|
371
|
-
value: BigInt(x402Requirements.maxAmountRequired),
|
|
372
|
-
validAfter: BigInt(Math.floor(Date.now() / 1e3)),
|
|
373
|
-
validBefore: BigInt(Math.floor(Date.now() / 1e3) + 900),
|
|
374
|
-
// 15 min
|
|
375
|
-
nonce: `0x${Array.from(
|
|
376
|
-
{ length: 32 },
|
|
377
|
-
() => Math.floor(Math.random() * 256).toString(16).padStart(2, "0")
|
|
378
|
-
).join("")}`,
|
|
379
|
-
tokenAddress: x402Requirements.asset
|
|
380
|
-
});
|
|
381
|
-
const paymentProof = {
|
|
382
|
-
x402Version: 1,
|
|
383
|
-
scheme: x402Requirements.scheme,
|
|
384
|
-
network: x402Requirements.network,
|
|
385
|
-
correlationId: "",
|
|
386
|
-
payload: {
|
|
387
|
-
signature: authorization.signature,
|
|
388
|
-
authorization: {
|
|
389
|
-
from: authorization.from,
|
|
390
|
-
to: authorization.to,
|
|
391
|
-
value: authorization.value.toString(),
|
|
392
|
-
validAfter: authorization.validAfter.toString(),
|
|
393
|
-
validBefore: authorization.validBefore.toString(),
|
|
394
|
-
nonce: authorization.nonce
|
|
395
|
-
}
|
|
396
|
-
}
|
|
397
|
-
};
|
|
398
|
-
const paymentHeader = Buffer.from(JSON.stringify(paymentProof)).toString("base64");
|
|
399
|
-
const paidResponse = await fetch(request.url, {
|
|
400
|
-
method: request.method ?? "POST",
|
|
401
|
-
headers: {
|
|
402
|
-
"Content-Type": "application/json",
|
|
403
|
-
"X-PAYMENT": paymentHeader,
|
|
404
|
-
...request.headers
|
|
405
|
-
},
|
|
406
|
-
...request.body ? { body: JSON.stringify(request.body) } : {}
|
|
407
|
-
});
|
|
408
|
-
return {
|
|
409
|
-
success: paidResponse.ok,
|
|
410
|
-
response: paidResponse,
|
|
411
|
-
paymentDetails: {
|
|
412
|
-
amount: x402Requirements.maxAmountRequired,
|
|
413
|
-
currency: x402Requirements.extra?.currencyCode ?? "USDC",
|
|
414
|
-
network: x402Requirements.network,
|
|
415
|
-
signature: authorization.signature
|
|
416
|
-
}
|
|
417
|
-
};
|
|
418
|
-
} catch (error) {
|
|
419
|
-
return {
|
|
420
|
-
success: false,
|
|
421
|
-
error: error instanceof Error ? error.message : String(error)
|
|
422
|
-
};
|
|
423
|
-
}
|
|
424
|
-
}
|
|
425
|
-
async signTransferAuthorization(params) {
|
|
426
|
-
if (!this.walletClient.chain) {
|
|
427
|
-
throw new Error("Wallet client chain not configured");
|
|
428
|
-
}
|
|
429
|
-
const domain = {
|
|
430
|
-
name: "USD Coin",
|
|
431
|
-
version: "2",
|
|
432
|
-
chainId: this.walletClient.chain.id,
|
|
433
|
-
verifyingContract: params.tokenAddress
|
|
434
|
-
};
|
|
435
|
-
const types = {
|
|
436
|
-
TransferWithAuthorization: [
|
|
437
|
-
{ name: "from", type: "address" },
|
|
438
|
-
{ name: "to", type: "address" },
|
|
439
|
-
{ name: "value", type: "uint256" },
|
|
440
|
-
{ name: "validAfter", type: "uint256" },
|
|
441
|
-
{ name: "validBefore", type: "uint256" },
|
|
442
|
-
{ name: "nonce", type: "bytes32" }
|
|
443
|
-
]
|
|
444
|
-
};
|
|
445
|
-
const message = {
|
|
446
|
-
from: params.from,
|
|
447
|
-
to: params.to,
|
|
448
|
-
value: params.value,
|
|
449
|
-
validAfter: params.validAfter,
|
|
450
|
-
validBefore: params.validBefore,
|
|
451
|
-
nonce: params.nonce
|
|
452
|
-
};
|
|
453
|
-
const signature = await this.walletClient.signTypedData({
|
|
454
|
-
account: this.account,
|
|
455
|
-
domain,
|
|
456
|
-
types,
|
|
457
|
-
primaryType: "TransferWithAuthorization",
|
|
458
|
-
message
|
|
459
|
-
});
|
|
460
|
-
return {
|
|
461
|
-
signature,
|
|
462
|
-
from: params.from,
|
|
463
|
-
to: params.to,
|
|
464
|
-
value: params.value,
|
|
465
|
-
validAfter: params.validAfter,
|
|
466
|
-
validBefore: params.validBefore,
|
|
467
|
-
nonce: params.nonce
|
|
468
|
-
};
|
|
469
|
-
}
|
|
470
|
-
getAddress() {
|
|
471
|
-
return this.account.address;
|
|
472
|
-
}
|
|
473
|
-
};
|
|
474
|
-
async function payX402(config) {
|
|
475
|
-
const client = new X402Client({
|
|
476
|
-
privateKey: config.privateKey,
|
|
477
|
-
...config.rpcUrl ? { rpcUrl: config.rpcUrl } : {}
|
|
478
|
-
});
|
|
479
|
-
return client.pay({
|
|
480
|
-
url: config.url,
|
|
481
|
-
body: config.body
|
|
482
|
-
});
|
|
483
|
-
}
|
|
484
|
-
var X402BrowserClient = class {
|
|
485
|
-
constructor(config) {
|
|
486
|
-
this.walletClient = config.walletClient;
|
|
487
|
-
this.chainId = config.chainId;
|
|
488
|
-
}
|
|
489
|
-
async pay(request) {
|
|
490
|
-
try {
|
|
491
|
-
const initialResponse = await fetch(request.url, {
|
|
492
|
-
method: request.method ?? "POST",
|
|
493
|
-
headers: {
|
|
494
|
-
"Content-Type": "application/json",
|
|
495
|
-
...request.headers
|
|
496
|
-
},
|
|
497
|
-
...request.body ? { body: JSON.stringify(request.body) } : {}
|
|
498
|
-
});
|
|
499
|
-
if (initialResponse.status !== 402) {
|
|
500
|
-
return {
|
|
501
|
-
success: initialResponse.ok,
|
|
502
|
-
response: initialResponse
|
|
503
|
-
};
|
|
504
|
-
}
|
|
505
|
-
const paymentRequirements = await initialResponse.json();
|
|
506
|
-
const x402Requirements = paymentRequirements.x402?.accepts?.[0];
|
|
507
|
-
if (!x402Requirements) {
|
|
508
|
-
return {
|
|
509
|
-
success: false,
|
|
510
|
-
error: "No x402 payment requirements found in 402 response"
|
|
511
|
-
};
|
|
512
|
-
}
|
|
513
|
-
const account = this.walletClient.account;
|
|
514
|
-
if (!account) {
|
|
515
|
-
return {
|
|
516
|
-
success: false,
|
|
517
|
-
error: "No account connected to wallet"
|
|
518
|
-
};
|
|
519
|
-
}
|
|
520
|
-
const authorization = {
|
|
521
|
-
from: account.address,
|
|
522
|
-
to: x402Requirements.payTo,
|
|
523
|
-
value: BigInt(x402Requirements.maxAmountRequired),
|
|
524
|
-
validAfter: BigInt(Math.floor(Date.now() / 1e3)),
|
|
525
|
-
validBefore: BigInt(Math.floor(Date.now() / 1e3) + 900),
|
|
526
|
-
nonce: `0x${Array.from(
|
|
527
|
-
{ length: 32 },
|
|
528
|
-
() => Math.floor(Math.random() * 256).toString(16).padStart(2, "0")
|
|
529
|
-
).join("")}`
|
|
530
|
-
};
|
|
531
|
-
const signature = await this.signTransferAuthorization(
|
|
532
|
-
authorization,
|
|
533
|
-
x402Requirements.asset
|
|
534
|
-
);
|
|
535
|
-
const paymentProof = {
|
|
536
|
-
x402Version: 1,
|
|
537
|
-
scheme: x402Requirements.scheme,
|
|
538
|
-
network: x402Requirements.network,
|
|
539
|
-
correlationId: "",
|
|
540
|
-
payload: {
|
|
541
|
-
signature,
|
|
542
|
-
authorization: {
|
|
543
|
-
from: authorization.from,
|
|
544
|
-
to: authorization.to,
|
|
545
|
-
value: authorization.value.toString(),
|
|
546
|
-
validAfter: authorization.validAfter.toString(),
|
|
547
|
-
validBefore: authorization.validBefore.toString(),
|
|
548
|
-
nonce: authorization.nonce
|
|
549
|
-
}
|
|
550
|
-
}
|
|
551
|
-
};
|
|
552
|
-
const paymentHeader = btoa(JSON.stringify(paymentProof));
|
|
553
|
-
const paidResponse = await fetch(request.url, {
|
|
554
|
-
method: request.method ?? "POST",
|
|
555
|
-
headers: {
|
|
556
|
-
"Content-Type": "application/json",
|
|
557
|
-
"X-PAYMENT": paymentHeader,
|
|
558
|
-
...request.headers
|
|
559
|
-
},
|
|
560
|
-
...request.body ? { body: JSON.stringify(request.body) } : {}
|
|
561
|
-
});
|
|
562
|
-
return {
|
|
563
|
-
success: paidResponse.ok,
|
|
564
|
-
response: paidResponse,
|
|
565
|
-
paymentDetails: {
|
|
566
|
-
amount: x402Requirements.maxAmountRequired,
|
|
567
|
-
currency: x402Requirements.extra?.currencyCode ?? "USDC",
|
|
568
|
-
network: x402Requirements.network,
|
|
569
|
-
signature
|
|
570
|
-
}
|
|
571
|
-
};
|
|
572
|
-
} catch (error) {
|
|
573
|
-
return {
|
|
574
|
-
success: false,
|
|
575
|
-
error: error instanceof Error ? error.message : String(error)
|
|
576
|
-
};
|
|
577
|
-
}
|
|
578
|
-
}
|
|
579
|
-
async signTransferAuthorization(authorization, tokenAddress) {
|
|
580
|
-
const account = this.walletClient.account;
|
|
581
|
-
if (!account) {
|
|
582
|
-
throw new Error("No account connected to wallet");
|
|
583
|
-
}
|
|
584
|
-
const domain = {
|
|
585
|
-
name: "USD Coin",
|
|
586
|
-
version: "2",
|
|
587
|
-
chainId: this.chainId,
|
|
588
|
-
verifyingContract: tokenAddress
|
|
589
|
-
};
|
|
590
|
-
const types = {
|
|
591
|
-
TransferWithAuthorization: [
|
|
592
|
-
{ name: "from", type: "address" },
|
|
593
|
-
{ name: "to", type: "address" },
|
|
594
|
-
{ name: "value", type: "uint256" },
|
|
595
|
-
{ name: "validAfter", type: "uint256" },
|
|
596
|
-
{ name: "validBefore", type: "uint256" },
|
|
597
|
-
{ name: "nonce", type: "bytes32" }
|
|
598
|
-
]
|
|
599
|
-
};
|
|
600
|
-
const message = {
|
|
601
|
-
from: authorization.from,
|
|
602
|
-
to: authorization.to,
|
|
603
|
-
value: authorization.value,
|
|
604
|
-
validAfter: authorization.validAfter,
|
|
605
|
-
validBefore: authorization.validBefore,
|
|
606
|
-
nonce: authorization.nonce
|
|
607
|
-
};
|
|
608
|
-
return await this.walletClient.signTypedData({
|
|
609
|
-
account,
|
|
610
|
-
domain,
|
|
611
|
-
types,
|
|
612
|
-
primaryType: "TransferWithAuthorization",
|
|
613
|
-
message
|
|
614
|
-
});
|
|
615
|
-
}
|
|
616
|
-
};
|
|
617
|
-
async function payX402WithWallet(walletClient, chainId, request) {
|
|
618
|
-
const client = new X402BrowserClient({ walletClient, chainId });
|
|
619
|
-
return client.pay(request);
|
|
620
|
-
}
|
|
621
332
|
|
|
622
|
-
// src/x402/
|
|
333
|
+
// src/x402/payment.ts
|
|
623
334
|
var PAYMENT_CONTEXT_SYMBOL = /* @__PURE__ */ Symbol.for("opentool.x402.context");
|
|
624
335
|
var X402PaymentRequiredError = class extends Error {
|
|
625
336
|
constructor(response, verification) {
|
|
@@ -988,16 +699,16 @@ function buildAdapters(tools) {
|
|
|
988
699
|
}
|
|
989
700
|
async function loadToolsFromDirectory(metadataMap) {
|
|
990
701
|
const tools = [];
|
|
991
|
-
const toolsDir =
|
|
992
|
-
if (!
|
|
702
|
+
const toolsDir = path5.join(process.cwd(), "tools");
|
|
703
|
+
if (!fs4.existsSync(toolsDir)) {
|
|
993
704
|
return tools;
|
|
994
705
|
}
|
|
995
|
-
const files =
|
|
706
|
+
const files = fs4.readdirSync(toolsDir);
|
|
996
707
|
for (const file of files) {
|
|
997
708
|
if (!isSupportedToolFile(file)) {
|
|
998
709
|
continue;
|
|
999
710
|
}
|
|
1000
|
-
const toolPath =
|
|
711
|
+
const toolPath = path5.join(toolsDir, file);
|
|
1001
712
|
try {
|
|
1002
713
|
const exportsObject = __require(toolPath);
|
|
1003
714
|
const candidate = resolveModuleCandidate(exportsObject);
|
|
@@ -1061,12 +772,12 @@ async function loadToolsFromDirectory(metadataMap) {
|
|
|
1061
772
|
return tools;
|
|
1062
773
|
}
|
|
1063
774
|
function loadMetadata() {
|
|
1064
|
-
const metadataPath =
|
|
1065
|
-
if (!
|
|
775
|
+
const metadataPath = path5.join(process.cwd(), "metadata.json");
|
|
776
|
+
if (!fs4.existsSync(metadataPath)) {
|
|
1066
777
|
return null;
|
|
1067
778
|
}
|
|
1068
779
|
try {
|
|
1069
|
-
const contents =
|
|
780
|
+
const contents = fs4.readFileSync(metadataPath, "utf8");
|
|
1070
781
|
return JSON.parse(contents);
|
|
1071
782
|
} catch (error) {
|
|
1072
783
|
console.warn(`Failed to parse metadata.json: ${error}`);
|
|
@@ -1147,47 +858,334 @@ function normalizeInputSchema(schema) {
|
|
|
1147
858
|
}
|
|
1148
859
|
return clone;
|
|
1149
860
|
}
|
|
1150
|
-
function normalizeRuntimeMcpConfig(rawConfig) {
|
|
1151
|
-
if (isPlainObject(rawConfig) && rawConfig.enabled === true) {
|
|
1152
|
-
let normalizedMode;
|
|
1153
|
-
if (typeof rawConfig.mode === "string") {
|
|
1154
|
-
const candidate = rawConfig.mode.toLowerCase();
|
|
1155
|
-
if (candidate === "stdio" || candidate === "lambda" || candidate === "dual") {
|
|
1156
|
-
normalizedMode = candidate;
|
|
1157
|
-
} else {
|
|
1158
|
-
throw new Error('mcp.mode must be one of "stdio", "lambda", or "dual"');
|
|
861
|
+
function normalizeRuntimeMcpConfig(rawConfig) {
|
|
862
|
+
if (isPlainObject(rawConfig) && rawConfig.enabled === true) {
|
|
863
|
+
let normalizedMode;
|
|
864
|
+
if (typeof rawConfig.mode === "string") {
|
|
865
|
+
const candidate = rawConfig.mode.toLowerCase();
|
|
866
|
+
if (candidate === "stdio" || candidate === "lambda" || candidate === "dual") {
|
|
867
|
+
normalizedMode = candidate;
|
|
868
|
+
} else {
|
|
869
|
+
throw new Error('mcp.mode must be one of "stdio", "lambda", or "dual"');
|
|
870
|
+
}
|
|
871
|
+
}
|
|
872
|
+
const metadataOverrides = isPlainObject(rawConfig.metadataOverrides) ? rawConfig.metadataOverrides : void 0;
|
|
873
|
+
const config = { enabled: true };
|
|
874
|
+
if (normalizedMode) {
|
|
875
|
+
config.mode = normalizedMode;
|
|
876
|
+
}
|
|
877
|
+
if (typeof rawConfig.defaultMethod === "string") {
|
|
878
|
+
config.defaultMethod = rawConfig.defaultMethod.toUpperCase();
|
|
879
|
+
}
|
|
880
|
+
if (metadataOverrides) {
|
|
881
|
+
config.metadataOverrides = metadataOverrides;
|
|
882
|
+
}
|
|
883
|
+
return config;
|
|
884
|
+
}
|
|
885
|
+
return null;
|
|
886
|
+
}
|
|
887
|
+
function isPlainObject(value) {
|
|
888
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
889
|
+
}
|
|
890
|
+
function isMcpEnabled(tool) {
|
|
891
|
+
return Boolean(tool.mcpConfig?.enabled);
|
|
892
|
+
}
|
|
893
|
+
function resolveRuntimePath(value) {
|
|
894
|
+
if (value.startsWith("file://")) {
|
|
895
|
+
return fileURLToPath(value);
|
|
896
|
+
}
|
|
897
|
+
return path5.resolve(value);
|
|
898
|
+
}
|
|
899
|
+
|
|
900
|
+
// src/types/index.ts
|
|
901
|
+
var HTTP_METHODS2 = ["GET", "HEAD", "POST", "PUT", "DELETE", "PATCH", "OPTIONS"];
|
|
902
|
+
var X402Client = class {
|
|
903
|
+
constructor(config) {
|
|
904
|
+
this.account = privateKeyToAccount(config.privateKey);
|
|
905
|
+
const chain = baseSepolia;
|
|
906
|
+
this.walletClient = createWalletClient({
|
|
907
|
+
account: this.account,
|
|
908
|
+
chain,
|
|
909
|
+
transport: http(config.rpcUrl)
|
|
910
|
+
});
|
|
911
|
+
}
|
|
912
|
+
async pay(request) {
|
|
913
|
+
try {
|
|
914
|
+
const initialResponse = await fetch(request.url, {
|
|
915
|
+
method: request.method ?? "POST",
|
|
916
|
+
headers: {
|
|
917
|
+
"Content-Type": "application/json",
|
|
918
|
+
...request.headers
|
|
919
|
+
},
|
|
920
|
+
...request.body ? { body: JSON.stringify(request.body) } : {}
|
|
921
|
+
});
|
|
922
|
+
if (initialResponse.status !== 402) {
|
|
923
|
+
return {
|
|
924
|
+
success: initialResponse.ok,
|
|
925
|
+
response: initialResponse
|
|
926
|
+
};
|
|
927
|
+
}
|
|
928
|
+
const paymentRequirements = await initialResponse.json();
|
|
929
|
+
const x402Requirements = paymentRequirements.x402?.accepts?.[0];
|
|
930
|
+
if (!x402Requirements) {
|
|
931
|
+
return {
|
|
932
|
+
success: false,
|
|
933
|
+
error: "No x402 payment requirements found in 402 response"
|
|
934
|
+
};
|
|
935
|
+
}
|
|
936
|
+
const authorization = await this.signTransferAuthorization({
|
|
937
|
+
from: this.account.address,
|
|
938
|
+
to: x402Requirements.payTo,
|
|
939
|
+
value: BigInt(x402Requirements.maxAmountRequired),
|
|
940
|
+
validAfter: BigInt(Math.floor(Date.now() / 1e3)),
|
|
941
|
+
validBefore: BigInt(Math.floor(Date.now() / 1e3) + 900),
|
|
942
|
+
// 15 min
|
|
943
|
+
nonce: `0x${Array.from(
|
|
944
|
+
{ length: 32 },
|
|
945
|
+
() => Math.floor(Math.random() * 256).toString(16).padStart(2, "0")
|
|
946
|
+
).join("")}`,
|
|
947
|
+
tokenAddress: x402Requirements.asset
|
|
948
|
+
});
|
|
949
|
+
const paymentProof = {
|
|
950
|
+
x402Version: 1,
|
|
951
|
+
scheme: x402Requirements.scheme,
|
|
952
|
+
network: x402Requirements.network,
|
|
953
|
+
correlationId: "",
|
|
954
|
+
payload: {
|
|
955
|
+
signature: authorization.signature,
|
|
956
|
+
authorization: {
|
|
957
|
+
from: authorization.from,
|
|
958
|
+
to: authorization.to,
|
|
959
|
+
value: authorization.value.toString(),
|
|
960
|
+
validAfter: authorization.validAfter.toString(),
|
|
961
|
+
validBefore: authorization.validBefore.toString(),
|
|
962
|
+
nonce: authorization.nonce
|
|
963
|
+
}
|
|
964
|
+
}
|
|
965
|
+
};
|
|
966
|
+
const paymentHeader = Buffer.from(JSON.stringify(paymentProof)).toString("base64");
|
|
967
|
+
const paidResponse = await fetch(request.url, {
|
|
968
|
+
method: request.method ?? "POST",
|
|
969
|
+
headers: {
|
|
970
|
+
"Content-Type": "application/json",
|
|
971
|
+
"X-PAYMENT": paymentHeader,
|
|
972
|
+
...request.headers
|
|
973
|
+
},
|
|
974
|
+
...request.body ? { body: JSON.stringify(request.body) } : {}
|
|
975
|
+
});
|
|
976
|
+
return {
|
|
977
|
+
success: paidResponse.ok,
|
|
978
|
+
response: paidResponse,
|
|
979
|
+
paymentDetails: {
|
|
980
|
+
amount: x402Requirements.maxAmountRequired,
|
|
981
|
+
currency: x402Requirements.extra?.currencyCode ?? "USDC",
|
|
982
|
+
network: x402Requirements.network,
|
|
983
|
+
signature: authorization.signature
|
|
984
|
+
}
|
|
985
|
+
};
|
|
986
|
+
} catch (error) {
|
|
987
|
+
return {
|
|
988
|
+
success: false,
|
|
989
|
+
error: error instanceof Error ? error.message : String(error)
|
|
990
|
+
};
|
|
991
|
+
}
|
|
992
|
+
}
|
|
993
|
+
async signTransferAuthorization(params) {
|
|
994
|
+
if (!this.walletClient.chain) {
|
|
995
|
+
throw new Error("Wallet client chain not configured");
|
|
996
|
+
}
|
|
997
|
+
const domain = {
|
|
998
|
+
name: "USD Coin",
|
|
999
|
+
version: "2",
|
|
1000
|
+
chainId: this.walletClient.chain.id,
|
|
1001
|
+
verifyingContract: params.tokenAddress
|
|
1002
|
+
};
|
|
1003
|
+
const types = {
|
|
1004
|
+
TransferWithAuthorization: [
|
|
1005
|
+
{ name: "from", type: "address" },
|
|
1006
|
+
{ name: "to", type: "address" },
|
|
1007
|
+
{ name: "value", type: "uint256" },
|
|
1008
|
+
{ name: "validAfter", type: "uint256" },
|
|
1009
|
+
{ name: "validBefore", type: "uint256" },
|
|
1010
|
+
{ name: "nonce", type: "bytes32" }
|
|
1011
|
+
]
|
|
1012
|
+
};
|
|
1013
|
+
const message = {
|
|
1014
|
+
from: params.from,
|
|
1015
|
+
to: params.to,
|
|
1016
|
+
value: params.value,
|
|
1017
|
+
validAfter: params.validAfter,
|
|
1018
|
+
validBefore: params.validBefore,
|
|
1019
|
+
nonce: params.nonce
|
|
1020
|
+
};
|
|
1021
|
+
const signature = await this.walletClient.signTypedData({
|
|
1022
|
+
account: this.account,
|
|
1023
|
+
domain,
|
|
1024
|
+
types,
|
|
1025
|
+
primaryType: "TransferWithAuthorization",
|
|
1026
|
+
message
|
|
1027
|
+
});
|
|
1028
|
+
return {
|
|
1029
|
+
signature,
|
|
1030
|
+
from: params.from,
|
|
1031
|
+
to: params.to,
|
|
1032
|
+
value: params.value,
|
|
1033
|
+
validAfter: params.validAfter,
|
|
1034
|
+
validBefore: params.validBefore,
|
|
1035
|
+
nonce: params.nonce
|
|
1036
|
+
};
|
|
1037
|
+
}
|
|
1038
|
+
getAddress() {
|
|
1039
|
+
return this.account.address;
|
|
1040
|
+
}
|
|
1041
|
+
};
|
|
1042
|
+
async function payX402(config) {
|
|
1043
|
+
const client = new X402Client({
|
|
1044
|
+
privateKey: config.privateKey,
|
|
1045
|
+
...config.rpcUrl ? { rpcUrl: config.rpcUrl } : {}
|
|
1046
|
+
});
|
|
1047
|
+
return client.pay({
|
|
1048
|
+
url: config.url,
|
|
1049
|
+
body: config.body
|
|
1050
|
+
});
|
|
1051
|
+
}
|
|
1052
|
+
var X402BrowserClient = class {
|
|
1053
|
+
constructor(config) {
|
|
1054
|
+
this.walletClient = config.walletClient;
|
|
1055
|
+
this.chainId = config.chainId;
|
|
1056
|
+
}
|
|
1057
|
+
async pay(request) {
|
|
1058
|
+
try {
|
|
1059
|
+
const initialResponse = await fetch(request.url, {
|
|
1060
|
+
method: request.method ?? "POST",
|
|
1061
|
+
headers: {
|
|
1062
|
+
"Content-Type": "application/json",
|
|
1063
|
+
...request.headers
|
|
1064
|
+
},
|
|
1065
|
+
...request.body ? { body: JSON.stringify(request.body) } : {}
|
|
1066
|
+
});
|
|
1067
|
+
if (initialResponse.status !== 402) {
|
|
1068
|
+
return {
|
|
1069
|
+
success: initialResponse.ok,
|
|
1070
|
+
response: initialResponse
|
|
1071
|
+
};
|
|
1159
1072
|
}
|
|
1073
|
+
const paymentRequirements = await initialResponse.json();
|
|
1074
|
+
const x402Requirements = paymentRequirements.x402?.accepts?.[0];
|
|
1075
|
+
if (!x402Requirements) {
|
|
1076
|
+
return {
|
|
1077
|
+
success: false,
|
|
1078
|
+
error: "No x402 payment requirements found in 402 response"
|
|
1079
|
+
};
|
|
1080
|
+
}
|
|
1081
|
+
const account = this.walletClient.account;
|
|
1082
|
+
if (!account) {
|
|
1083
|
+
return {
|
|
1084
|
+
success: false,
|
|
1085
|
+
error: "No account connected to wallet"
|
|
1086
|
+
};
|
|
1087
|
+
}
|
|
1088
|
+
const authorization = {
|
|
1089
|
+
from: account.address,
|
|
1090
|
+
to: x402Requirements.payTo,
|
|
1091
|
+
value: BigInt(x402Requirements.maxAmountRequired),
|
|
1092
|
+
validAfter: BigInt(Math.floor(Date.now() / 1e3)),
|
|
1093
|
+
validBefore: BigInt(Math.floor(Date.now() / 1e3) + 900),
|
|
1094
|
+
nonce: `0x${Array.from(
|
|
1095
|
+
{ length: 32 },
|
|
1096
|
+
() => Math.floor(Math.random() * 256).toString(16).padStart(2, "0")
|
|
1097
|
+
).join("")}`
|
|
1098
|
+
};
|
|
1099
|
+
const signature = await this.signTransferAuthorization(
|
|
1100
|
+
authorization,
|
|
1101
|
+
x402Requirements.asset
|
|
1102
|
+
);
|
|
1103
|
+
const paymentProof = {
|
|
1104
|
+
x402Version: 1,
|
|
1105
|
+
scheme: x402Requirements.scheme,
|
|
1106
|
+
network: x402Requirements.network,
|
|
1107
|
+
correlationId: "",
|
|
1108
|
+
payload: {
|
|
1109
|
+
signature,
|
|
1110
|
+
authorization: {
|
|
1111
|
+
from: authorization.from,
|
|
1112
|
+
to: authorization.to,
|
|
1113
|
+
value: authorization.value.toString(),
|
|
1114
|
+
validAfter: authorization.validAfter.toString(),
|
|
1115
|
+
validBefore: authorization.validBefore.toString(),
|
|
1116
|
+
nonce: authorization.nonce
|
|
1117
|
+
}
|
|
1118
|
+
}
|
|
1119
|
+
};
|
|
1120
|
+
const paymentHeader = btoa(JSON.stringify(paymentProof));
|
|
1121
|
+
const paidResponse = await fetch(request.url, {
|
|
1122
|
+
method: request.method ?? "POST",
|
|
1123
|
+
headers: {
|
|
1124
|
+
"Content-Type": "application/json",
|
|
1125
|
+
"X-PAYMENT": paymentHeader,
|
|
1126
|
+
...request.headers
|
|
1127
|
+
},
|
|
1128
|
+
...request.body ? { body: JSON.stringify(request.body) } : {}
|
|
1129
|
+
});
|
|
1130
|
+
return {
|
|
1131
|
+
success: paidResponse.ok,
|
|
1132
|
+
response: paidResponse,
|
|
1133
|
+
paymentDetails: {
|
|
1134
|
+
amount: x402Requirements.maxAmountRequired,
|
|
1135
|
+
currency: x402Requirements.extra?.currencyCode ?? "USDC",
|
|
1136
|
+
network: x402Requirements.network,
|
|
1137
|
+
signature
|
|
1138
|
+
}
|
|
1139
|
+
};
|
|
1140
|
+
} catch (error) {
|
|
1141
|
+
return {
|
|
1142
|
+
success: false,
|
|
1143
|
+
error: error instanceof Error ? error.message : String(error)
|
|
1144
|
+
};
|
|
1160
1145
|
}
|
|
1161
|
-
const metadataOverrides = isPlainObject(rawConfig.metadataOverrides) ? rawConfig.metadataOverrides : void 0;
|
|
1162
|
-
const config = { enabled: true };
|
|
1163
|
-
if (normalizedMode) {
|
|
1164
|
-
config.mode = normalizedMode;
|
|
1165
|
-
}
|
|
1166
|
-
if (typeof rawConfig.defaultMethod === "string") {
|
|
1167
|
-
config.defaultMethod = rawConfig.defaultMethod.toUpperCase();
|
|
1168
|
-
}
|
|
1169
|
-
if (metadataOverrides) {
|
|
1170
|
-
config.metadataOverrides = metadataOverrides;
|
|
1171
|
-
}
|
|
1172
|
-
return config;
|
|
1173
1146
|
}
|
|
1174
|
-
|
|
1175
|
-
|
|
1176
|
-
|
|
1177
|
-
|
|
1178
|
-
}
|
|
1179
|
-
|
|
1180
|
-
|
|
1181
|
-
|
|
1182
|
-
|
|
1183
|
-
|
|
1184
|
-
|
|
1147
|
+
async signTransferAuthorization(authorization, tokenAddress) {
|
|
1148
|
+
const account = this.walletClient.account;
|
|
1149
|
+
if (!account) {
|
|
1150
|
+
throw new Error("No account connected to wallet");
|
|
1151
|
+
}
|
|
1152
|
+
const domain = {
|
|
1153
|
+
name: "USD Coin",
|
|
1154
|
+
version: "2",
|
|
1155
|
+
chainId: this.chainId,
|
|
1156
|
+
verifyingContract: tokenAddress
|
|
1157
|
+
};
|
|
1158
|
+
const types = {
|
|
1159
|
+
TransferWithAuthorization: [
|
|
1160
|
+
{ name: "from", type: "address" },
|
|
1161
|
+
{ name: "to", type: "address" },
|
|
1162
|
+
{ name: "value", type: "uint256" },
|
|
1163
|
+
{ name: "validAfter", type: "uint256" },
|
|
1164
|
+
{ name: "validBefore", type: "uint256" },
|
|
1165
|
+
{ name: "nonce", type: "bytes32" }
|
|
1166
|
+
]
|
|
1167
|
+
};
|
|
1168
|
+
const message = {
|
|
1169
|
+
from: authorization.from,
|
|
1170
|
+
to: authorization.to,
|
|
1171
|
+
value: authorization.value,
|
|
1172
|
+
validAfter: authorization.validAfter,
|
|
1173
|
+
validBefore: authorization.validBefore,
|
|
1174
|
+
nonce: authorization.nonce
|
|
1175
|
+
};
|
|
1176
|
+
return await this.walletClient.signTypedData({
|
|
1177
|
+
account,
|
|
1178
|
+
domain,
|
|
1179
|
+
types,
|
|
1180
|
+
primaryType: "TransferWithAuthorization",
|
|
1181
|
+
message
|
|
1182
|
+
});
|
|
1185
1183
|
}
|
|
1186
|
-
|
|
1184
|
+
};
|
|
1185
|
+
async function payX402WithWallet(walletClient, chainId, request) {
|
|
1186
|
+
const client = new X402BrowserClient({ walletClient, chainId });
|
|
1187
|
+
return client.pay(request);
|
|
1187
1188
|
}
|
|
1188
|
-
|
|
1189
|
-
// src/types/index.ts
|
|
1190
|
-
var HTTP_METHODS2 = ["GET", "HEAD", "POST", "PUT", "DELETE", "PATCH", "OPTIONS"];
|
|
1191
1189
|
var BASE_ALCHEMY_HOST = "https://base-mainnet.g.alchemy.com/v2/";
|
|
1192
1190
|
var ETHEREUM_ALCHEMY_HOST = "https://eth-mainnet.g.alchemy.com/v2/";
|
|
1193
1191
|
var BASE_SEPOLIA_ALCHEMY_HOST = "https://base-sepolia.g.alchemy.com/v2/";
|
|
@@ -1734,8 +1732,8 @@ async function store(input, options) {
|
|
|
1734
1732
|
);
|
|
1735
1733
|
}
|
|
1736
1734
|
const { baseUrl, apiKey, fetchFn } = resolveConfig(options);
|
|
1737
|
-
const
|
|
1738
|
-
const url = `${baseUrl}${
|
|
1735
|
+
const path7 = mode === "backtest" ? "/apps/backtests/tx" : "/apps/positions/tx";
|
|
1736
|
+
const url = `${baseUrl}${path7}`;
|
|
1739
1737
|
let response;
|
|
1740
1738
|
try {
|
|
1741
1739
|
response = await fetchFn(url, {
|
|
@@ -1775,8 +1773,8 @@ async function store(input, options) {
|
|
|
1775
1773
|
async function retrieve(params, options) {
|
|
1776
1774
|
const { baseUrl, apiKey, fetchFn } = resolveConfig(options);
|
|
1777
1775
|
const mode = params?.mode ?? "live";
|
|
1778
|
-
const
|
|
1779
|
-
const url = new URL(`${baseUrl}${
|
|
1776
|
+
const path7 = mode === "backtest" ? "/apps/backtests/tx" : "/apps/positions/tx";
|
|
1777
|
+
const url = new URL(`${baseUrl}${path7}`);
|
|
1780
1778
|
if (params?.source) url.searchParams.set("source", params.source);
|
|
1781
1779
|
if (params?.walletAddress) url.searchParams.set("walletAddress", params.walletAddress);
|
|
1782
1780
|
if (params?.symbol) url.searchParams.set("symbol", params.symbol);
|
|
@@ -3427,6 +3425,9 @@ function resolveHyperliquidPair(value) {
|
|
|
3427
3425
|
}
|
|
3428
3426
|
return null;
|
|
3429
3427
|
}
|
|
3428
|
+
function resolveHyperliquidLeverageMode(symbol) {
|
|
3429
|
+
return symbol.includes(":") ? "isolated" : "cross";
|
|
3430
|
+
}
|
|
3430
3431
|
function resolveHyperliquidProfileChain(environment) {
|
|
3431
3432
|
return environment === "testnet" ? "hyperliquid-testnet" : "hyperliquid";
|
|
3432
3433
|
}
|
|
@@ -3527,6 +3528,175 @@ function resolveHyperliquidSymbol(asset, override) {
|
|
|
3527
3528
|
const baseNoPair = base2.split("/")[0] ?? base2;
|
|
3528
3529
|
return baseNoPair.trim().toUpperCase();
|
|
3529
3530
|
}
|
|
3531
|
+
function resolveHyperliquidPerpSymbol(asset) {
|
|
3532
|
+
const raw = asset.trim();
|
|
3533
|
+
if (!raw) return raw;
|
|
3534
|
+
const dex = extractHyperliquidDex(raw);
|
|
3535
|
+
const base2 = normalizeHyperliquidBaseSymbol(raw) ?? raw.toUpperCase();
|
|
3536
|
+
return dex ? `${dex}:${base2}` : base2;
|
|
3537
|
+
}
|
|
3538
|
+
function resolveHyperliquidSpotSymbol(asset, defaultQuote = "USDC") {
|
|
3539
|
+
const quote = defaultQuote.trim().toUpperCase() || "USDC";
|
|
3540
|
+
const raw = asset.trim().toUpperCase();
|
|
3541
|
+
if (!raw) {
|
|
3542
|
+
return { symbol: raw, base: raw, quote };
|
|
3543
|
+
}
|
|
3544
|
+
const pair = resolveHyperliquidPair(raw);
|
|
3545
|
+
if (pair) {
|
|
3546
|
+
const [base3, pairQuote] = pair.split("/");
|
|
3547
|
+
return {
|
|
3548
|
+
symbol: pair,
|
|
3549
|
+
base: base3?.trim() ?? raw,
|
|
3550
|
+
quote: pairQuote?.trim() ?? quote
|
|
3551
|
+
};
|
|
3552
|
+
}
|
|
3553
|
+
const base2 = normalizeHyperliquidBaseSymbol(raw) ?? raw;
|
|
3554
|
+
return { symbol: `${base2}/${quote}`, base: base2, quote };
|
|
3555
|
+
}
|
|
3556
|
+
|
|
3557
|
+
// src/adapters/hyperliquid/strategy.ts
|
|
3558
|
+
function clampDcaWeight(value) {
|
|
3559
|
+
if (typeof value !== "number" || !Number.isFinite(value)) return 0;
|
|
3560
|
+
return Math.min(1e6, Math.max(0, value));
|
|
3561
|
+
}
|
|
3562
|
+
function resolveHyperliquidBudgetUsd(params) {
|
|
3563
|
+
const { config, accountValue } = params;
|
|
3564
|
+
if (config.allocationMode === "fixed") {
|
|
3565
|
+
const desiredUsd = config.amountUsd ?? 0;
|
|
3566
|
+
if (!Number.isFinite(desiredUsd) || desiredUsd <= 0) {
|
|
3567
|
+
throw new Error("fixed allocation requires amountUsd");
|
|
3568
|
+
}
|
|
3569
|
+
return desiredUsd;
|
|
3570
|
+
}
|
|
3571
|
+
if (!Number.isFinite(accountValue ?? Number.NaN)) {
|
|
3572
|
+
throw new Error("percent allocation requires accountValue");
|
|
3573
|
+
}
|
|
3574
|
+
const rawUsd = accountValue * (config.percentOfEquity / 100);
|
|
3575
|
+
const maxPercentUsd = accountValue * (config.maxPercentOfEquity / 100);
|
|
3576
|
+
return Math.min(rawUsd, maxPercentUsd);
|
|
3577
|
+
}
|
|
3578
|
+
function resolveHyperliquidDcaSymbolEntries(inputs, fallbackSymbol) {
|
|
3579
|
+
const entries = [];
|
|
3580
|
+
const values = Array.isArray(inputs) ? inputs : [];
|
|
3581
|
+
for (const input of values) {
|
|
3582
|
+
if (typeof input === "string") {
|
|
3583
|
+
const trimmed = input.trim();
|
|
3584
|
+
if (!trimmed) continue;
|
|
3585
|
+
const [rawSymbol, rawWeight] = trimmed.split(":");
|
|
3586
|
+
const symbol2 = rawSymbol?.trim();
|
|
3587
|
+
if (!symbol2) continue;
|
|
3588
|
+
const parsedWeight2 = typeof rawWeight === "string" && rawWeight.trim().length > 0 ? Number.parseFloat(rawWeight.trim()) : 1;
|
|
3589
|
+
const weight2 = Number.isFinite(parsedWeight2) && parsedWeight2 > 0 ? parsedWeight2 : 1;
|
|
3590
|
+
entries.push({ symbol: symbol2, weight: weight2 });
|
|
3591
|
+
continue;
|
|
3592
|
+
}
|
|
3593
|
+
if (!input || typeof input !== "object") continue;
|
|
3594
|
+
const symbol = input.symbol?.trim();
|
|
3595
|
+
if (!symbol) continue;
|
|
3596
|
+
const parsedWeight = typeof input.weight === "number" && Number.isFinite(input.weight) ? input.weight : 1;
|
|
3597
|
+
const weight = parsedWeight > 0 ? parsedWeight : 1;
|
|
3598
|
+
entries.push({ symbol, weight });
|
|
3599
|
+
}
|
|
3600
|
+
if (entries.length > 0) {
|
|
3601
|
+
return entries;
|
|
3602
|
+
}
|
|
3603
|
+
return [{ symbol: fallbackSymbol, weight: 1 }];
|
|
3604
|
+
}
|
|
3605
|
+
function normalizeHyperliquidDcaEntries(params) {
|
|
3606
|
+
const map = /* @__PURE__ */ new Map();
|
|
3607
|
+
const entries = Array.isArray(params.entries) ? params.entries : [];
|
|
3608
|
+
for (const entry of entries) {
|
|
3609
|
+
if (!entry || typeof entry !== "object") continue;
|
|
3610
|
+
const symbol = typeof entry.symbol === "string" ? entry.symbol.trim() : "";
|
|
3611
|
+
if (!symbol) continue;
|
|
3612
|
+
const key = symbol.toUpperCase();
|
|
3613
|
+
const weight = clampDcaWeight(entry.weight);
|
|
3614
|
+
if (weight <= 0) continue;
|
|
3615
|
+
const existing = map.get(key);
|
|
3616
|
+
if (existing) {
|
|
3617
|
+
existing.weight += weight;
|
|
3618
|
+
} else {
|
|
3619
|
+
map.set(key, { symbol, weight });
|
|
3620
|
+
}
|
|
3621
|
+
}
|
|
3622
|
+
if (map.size === 0) {
|
|
3623
|
+
map.set(params.fallbackSymbol.toUpperCase(), {
|
|
3624
|
+
symbol: params.fallbackSymbol,
|
|
3625
|
+
weight: 1
|
|
3626
|
+
});
|
|
3627
|
+
}
|
|
3628
|
+
const entriesList = Array.from(map.values());
|
|
3629
|
+
const totalWeight = entriesList.reduce((sum, entry) => sum + entry.weight, 0);
|
|
3630
|
+
if (!Number.isFinite(totalWeight) || totalWeight <= 0) {
|
|
3631
|
+
return [];
|
|
3632
|
+
}
|
|
3633
|
+
return entriesList.map((entry) => ({
|
|
3634
|
+
symbol: entry.symbol,
|
|
3635
|
+
weight: entry.weight,
|
|
3636
|
+
normalizedWeight: entry.weight / totalWeight
|
|
3637
|
+
}));
|
|
3638
|
+
}
|
|
3639
|
+
function resolveHyperliquidMaxPerRunUsd(targetNotionalUsd, hedgeRatio) {
|
|
3640
|
+
if (!Number.isFinite(targetNotionalUsd) || targetNotionalUsd <= 0) return 0;
|
|
3641
|
+
const ratio = Number.isFinite(hedgeRatio) && hedgeRatio > 0 ? hedgeRatio : 1;
|
|
3642
|
+
return Math.max(targetNotionalUsd, targetNotionalUsd * ratio);
|
|
3643
|
+
}
|
|
3644
|
+
function clampHyperliquidAbs(value, limit) {
|
|
3645
|
+
if (!Number.isFinite(value) || !Number.isFinite(limit) || limit <= 0) return 0;
|
|
3646
|
+
const capped = Math.min(Math.abs(value), limit);
|
|
3647
|
+
return Math.sign(value) * capped;
|
|
3648
|
+
}
|
|
3649
|
+
function resolveHyperliquidTargetSize(params) {
|
|
3650
|
+
const { config, execution, accountValue, currentPrice } = params;
|
|
3651
|
+
if (execution.size && Number.isFinite(execution.size)) {
|
|
3652
|
+
return { targetSize: execution.size, budgetUsd: execution.size * currentPrice };
|
|
3653
|
+
}
|
|
3654
|
+
if (config.allocationMode === "fixed") {
|
|
3655
|
+
const budgetUsd2 = resolveHyperliquidBudgetUsd({
|
|
3656
|
+
config,
|
|
3657
|
+
accountValue
|
|
3658
|
+
});
|
|
3659
|
+
return { targetSize: budgetUsd2 / currentPrice, budgetUsd: budgetUsd2 };
|
|
3660
|
+
}
|
|
3661
|
+
const budgetUsd = resolveHyperliquidBudgetUsd({
|
|
3662
|
+
config,
|
|
3663
|
+
accountValue
|
|
3664
|
+
});
|
|
3665
|
+
return { targetSize: budgetUsd / currentPrice, budgetUsd };
|
|
3666
|
+
}
|
|
3667
|
+
function planHyperliquidTrade(params) {
|
|
3668
|
+
const { signal, mode, currentSize, targetSize } = params;
|
|
3669
|
+
if (signal === "hold" || signal === "unknown") return null;
|
|
3670
|
+
if (signal === "buy") {
|
|
3671
|
+
const desired2 = mode === "long-short" ? targetSize : Math.max(targetSize, 0);
|
|
3672
|
+
const delta2 = desired2 - currentSize;
|
|
3673
|
+
if (delta2 <= 0) return null;
|
|
3674
|
+
return {
|
|
3675
|
+
side: "buy",
|
|
3676
|
+
size: delta2,
|
|
3677
|
+
reduceOnly: false,
|
|
3678
|
+
targetSize: desired2
|
|
3679
|
+
};
|
|
3680
|
+
}
|
|
3681
|
+
if (mode === "long-only") {
|
|
3682
|
+
if (currentSize <= 0) return null;
|
|
3683
|
+
return {
|
|
3684
|
+
side: "sell",
|
|
3685
|
+
size: currentSize,
|
|
3686
|
+
reduceOnly: true,
|
|
3687
|
+
targetSize: 0
|
|
3688
|
+
};
|
|
3689
|
+
}
|
|
3690
|
+
const desired = -Math.abs(targetSize);
|
|
3691
|
+
const delta = currentSize - desired;
|
|
3692
|
+
if (delta <= 0) return null;
|
|
3693
|
+
return {
|
|
3694
|
+
side: "sell",
|
|
3695
|
+
size: delta,
|
|
3696
|
+
reduceOnly: false,
|
|
3697
|
+
targetSize: desired
|
|
3698
|
+
};
|
|
3699
|
+
}
|
|
3530
3700
|
|
|
3531
3701
|
// src/adapters/hyperliquid/order-utils.ts
|
|
3532
3702
|
var MAX_HYPERLIQUID_PRICE_DECIMALS = 8;
|
|
@@ -3872,9 +4042,10 @@ function readHyperliquidSpotAccountValue(params) {
|
|
|
3872
4042
|
|
|
3873
4043
|
// src/adapters/hyperliquid/market-data.ts
|
|
3874
4044
|
var META_CACHE_TTL_MS = 5 * 60 * 1e3;
|
|
4045
|
+
var DEFAULT_OPENPOND_GATEWAY_URL = "https://gateway.openpond.dev";
|
|
3875
4046
|
var allMidsCache = /* @__PURE__ */ new Map();
|
|
3876
4047
|
function resolveGatewayBase(override) {
|
|
3877
|
-
const value = override ?? process.env.OPENPOND_GATEWAY_URL ??
|
|
4048
|
+
const value = override ?? process.env.OPENPOND_GATEWAY_URL ?? DEFAULT_OPENPOND_GATEWAY_URL;
|
|
3878
4049
|
if (typeof value !== "string") {
|
|
3879
4050
|
return null;
|
|
3880
4051
|
}
|
|
@@ -4043,6 +4214,25 @@ async function fetchHyperliquidBars(params) {
|
|
|
4043
4214
|
return typeof record.close === "number" && Number.isFinite(record.close) && typeof record.time === "number" && Number.isFinite(record.time);
|
|
4044
4215
|
});
|
|
4045
4216
|
}
|
|
4217
|
+
function normalizeHyperliquidIndicatorBars(bars) {
|
|
4218
|
+
return bars.filter(
|
|
4219
|
+
(bar) => bar && typeof bar === "object" && typeof bar.time === "number" && Number.isFinite(bar.time) && typeof bar.close === "number" && Number.isFinite(bar.close)
|
|
4220
|
+
).map((bar) => {
|
|
4221
|
+
const close = bar.close;
|
|
4222
|
+
const open = typeof bar.open === "number" && Number.isFinite(bar.open) ? bar.open : close;
|
|
4223
|
+
const high = typeof bar.high === "number" && Number.isFinite(bar.high) ? bar.high : close;
|
|
4224
|
+
const low = typeof bar.low === "number" && Number.isFinite(bar.low) ? bar.low : close;
|
|
4225
|
+
const volume = typeof bar.volume === "number" && Number.isFinite(bar.volume) ? bar.volume : 0;
|
|
4226
|
+
return {
|
|
4227
|
+
time: bar.time,
|
|
4228
|
+
open,
|
|
4229
|
+
high,
|
|
4230
|
+
low,
|
|
4231
|
+
close,
|
|
4232
|
+
volume
|
|
4233
|
+
};
|
|
4234
|
+
});
|
|
4235
|
+
}
|
|
4046
4236
|
async function fetchHyperliquidTickSize(params) {
|
|
4047
4237
|
return fetchHyperliquidTickSizeForCoin(params.environment, params.symbol);
|
|
4048
4238
|
}
|
|
@@ -4252,6 +4442,78 @@ var __hyperliquidMarketDataInternals = {
|
|
|
4252
4442
|
formatScaledInt
|
|
4253
4443
|
};
|
|
4254
4444
|
|
|
4445
|
+
// src/adapters/hyperliquid/utils.ts
|
|
4446
|
+
var DEFAULT_HYPERLIQUID_CADENCE_CRON = {
|
|
4447
|
+
daily: "0 8 * * *",
|
|
4448
|
+
hourly: "0 * * * *",
|
|
4449
|
+
weekly: "0 8 * * 1",
|
|
4450
|
+
"twice-weekly": "0 8 * * 1,4",
|
|
4451
|
+
monthly: "0 8 1 * *"
|
|
4452
|
+
};
|
|
4453
|
+
function parseHyperliquidJson(raw) {
|
|
4454
|
+
if (!raw) return null;
|
|
4455
|
+
try {
|
|
4456
|
+
return JSON.parse(raw);
|
|
4457
|
+
} catch {
|
|
4458
|
+
return null;
|
|
4459
|
+
}
|
|
4460
|
+
}
|
|
4461
|
+
function clampHyperliquidInt(value, min, max, fallback) {
|
|
4462
|
+
if (value == null) return fallback;
|
|
4463
|
+
if (typeof value === "string" && value.trim().length === 0) return fallback;
|
|
4464
|
+
const parsed = Number(value);
|
|
4465
|
+
if (!Number.isFinite(parsed)) return fallback;
|
|
4466
|
+
const numeric = Math.trunc(parsed);
|
|
4467
|
+
if (!Number.isFinite(numeric)) return fallback;
|
|
4468
|
+
return Math.min(max, Math.max(min, numeric));
|
|
4469
|
+
}
|
|
4470
|
+
function clampHyperliquidFloat(value, min, max, fallback) {
|
|
4471
|
+
if (value == null) return fallback;
|
|
4472
|
+
if (typeof value === "string" && value.trim().length === 0) return fallback;
|
|
4473
|
+
const numeric = Number(value);
|
|
4474
|
+
if (!Number.isFinite(numeric)) return fallback;
|
|
4475
|
+
return Math.min(max, Math.max(min, numeric));
|
|
4476
|
+
}
|
|
4477
|
+
function resolveHyperliquidScheduleEvery(input, options) {
|
|
4478
|
+
const min = options?.min ?? 1;
|
|
4479
|
+
const max = options?.max ?? 59;
|
|
4480
|
+
const fallback = options?.fallback ?? 1;
|
|
4481
|
+
return clampHyperliquidInt(input, min, max, fallback);
|
|
4482
|
+
}
|
|
4483
|
+
function resolveHyperliquidScheduleUnit(input, fallback = "hours") {
|
|
4484
|
+
if (input === "minutes") return "minutes";
|
|
4485
|
+
if (input === "hours") return "hours";
|
|
4486
|
+
return fallback;
|
|
4487
|
+
}
|
|
4488
|
+
function resolveHyperliquidIntervalCron(every, unit) {
|
|
4489
|
+
if (unit === "minutes") {
|
|
4490
|
+
return every === 1 ? "* * * * *" : `*/${every} * * * *`;
|
|
4491
|
+
}
|
|
4492
|
+
return every === 1 ? "0 * * * *" : `0 */${every} * * *`;
|
|
4493
|
+
}
|
|
4494
|
+
function resolveHyperliquidHourlyInterval(input, fallback = 1) {
|
|
4495
|
+
return clampHyperliquidInt(input, 1, 24, fallback);
|
|
4496
|
+
}
|
|
4497
|
+
function resolveHyperliquidCadenceCron(cadence, hourlyInterval, cadenceToCron = DEFAULT_HYPERLIQUID_CADENCE_CRON) {
|
|
4498
|
+
if (cadence !== "hourly") {
|
|
4499
|
+
return cadenceToCron[cadence];
|
|
4500
|
+
}
|
|
4501
|
+
const interval = resolveHyperliquidHourlyInterval(hourlyInterval, 1);
|
|
4502
|
+
return interval === 1 ? cadenceToCron.hourly : `0 */${interval} * * *`;
|
|
4503
|
+
}
|
|
4504
|
+
function resolveHyperliquidCadenceFromResolution(resolution) {
|
|
4505
|
+
if (resolution === "60") {
|
|
4506
|
+
return { cadence: "hourly", hourlyInterval: 1 };
|
|
4507
|
+
}
|
|
4508
|
+
if (resolution === "240") {
|
|
4509
|
+
return { cadence: "hourly", hourlyInterval: 4 };
|
|
4510
|
+
}
|
|
4511
|
+
if (resolution === "1W") {
|
|
4512
|
+
return { cadence: "weekly" };
|
|
4513
|
+
}
|
|
4514
|
+
return { cadence: "daily" };
|
|
4515
|
+
}
|
|
4516
|
+
|
|
4255
4517
|
// src/adapters/hyperliquid/index.ts
|
|
4256
4518
|
function assertPositiveDecimalInput(value, label) {
|
|
4257
4519
|
if (typeof value === "number") {
|
|
@@ -4803,9 +5065,9 @@ function parseOptionalDate(value) {
|
|
|
4803
5065
|
function buildHmacSignature(args) {
|
|
4804
5066
|
const timestamp2 = args.timestamp.toString();
|
|
4805
5067
|
const method = args.method.toUpperCase();
|
|
4806
|
-
const
|
|
5068
|
+
const path7 = args.path;
|
|
4807
5069
|
const body = args.body == null ? "" : typeof args.body === "string" ? args.body : JSON.stringify(args.body);
|
|
4808
|
-
const payload = `${timestamp2}${method}${
|
|
5070
|
+
const payload = `${timestamp2}${method}${path7}${body}`;
|
|
4809
5071
|
const key = Buffer.from(args.secret, "base64");
|
|
4810
5072
|
return createHmac("sha256", key).update(payload).digest("hex");
|
|
4811
5073
|
}
|
|
@@ -6158,9 +6420,9 @@ function assignIfDefined(target, key, value) {
|
|
|
6158
6420
|
target[key] = value;
|
|
6159
6421
|
}
|
|
6160
6422
|
}
|
|
6161
|
-
function buildUrl(baseUrl,
|
|
6423
|
+
function buildUrl(baseUrl, path7) {
|
|
6162
6424
|
const sanitizedBase = baseUrl.endsWith("/") ? baseUrl.slice(0, -1) : baseUrl;
|
|
6163
|
-
return `${sanitizedBase}${
|
|
6425
|
+
return `${sanitizedBase}${path7}`;
|
|
6164
6426
|
}
|
|
6165
6427
|
function createAbortBundle(upstreamSignal, timeoutMs) {
|
|
6166
6428
|
const controller = new AbortController();
|
|
@@ -6249,8 +6511,9 @@ function toAbortError(reason) {
|
|
|
6249
6511
|
}
|
|
6250
6512
|
return new AIAbortError(String(reason ?? "AI request aborted"));
|
|
6251
6513
|
}
|
|
6514
|
+
var BACKTEST_DECISION_MODE = "backtest_decisions";
|
|
6252
6515
|
var backtestDecisionRequestSchema = z.object({
|
|
6253
|
-
mode: z.literal(
|
|
6516
|
+
mode: z.literal(BACKTEST_DECISION_MODE),
|
|
6254
6517
|
source: z.string().min(1).optional(),
|
|
6255
6518
|
symbol: z.string().min(1).optional(),
|
|
6256
6519
|
lookbackDays: z.number().positive().optional(),
|
|
@@ -6312,6 +6575,57 @@ function estimateCountBack(params) {
|
|
|
6312
6575
|
}
|
|
6313
6576
|
return fallback;
|
|
6314
6577
|
}
|
|
6578
|
+
function resolveBacktestMode(value) {
|
|
6579
|
+
if (typeof value !== "string") return null;
|
|
6580
|
+
const normalized = value.trim().toLowerCase();
|
|
6581
|
+
return normalized === BACKTEST_DECISION_MODE ? BACKTEST_DECISION_MODE : null;
|
|
6582
|
+
}
|
|
6583
|
+
function resolveBacktestWindow(params) {
|
|
6584
|
+
const fromSeconds = parseTimeToSeconds(params.from) ?? parseTimeToSeconds(params.timeframeStart);
|
|
6585
|
+
const toSeconds = parseTimeToSeconds(params.to) ?? parseTimeToSeconds(params.timeframeEnd);
|
|
6586
|
+
const hasWindow = fromSeconds != null && toSeconds != null && Number.isFinite(fromSeconds) && Number.isFinite(toSeconds) && toSeconds > fromSeconds;
|
|
6587
|
+
const resolvedFrom = hasWindow ? fromSeconds : void 0;
|
|
6588
|
+
const resolvedTo = hasWindow ? toSeconds : void 0;
|
|
6589
|
+
const lookbackDays = typeof params.lookbackDays === "number" && Number.isFinite(params.lookbackDays) ? params.lookbackDays : void 0;
|
|
6590
|
+
const countBack = estimateCountBack({
|
|
6591
|
+
fallback: params.fallbackCountBack,
|
|
6592
|
+
resolution: params.resolution,
|
|
6593
|
+
...lookbackDays != null ? { lookbackDays } : {},
|
|
6594
|
+
...resolvedFrom != null ? { fromSeconds: resolvedFrom } : {},
|
|
6595
|
+
...resolvedTo != null ? { toSeconds: resolvedTo } : {},
|
|
6596
|
+
...typeof params.minCountBack === "number" ? { minCountBack: params.minCountBack } : {},
|
|
6597
|
+
...typeof params.bufferBars === "number" ? { bufferBars: params.bufferBars } : {}
|
|
6598
|
+
});
|
|
6599
|
+
return {
|
|
6600
|
+
...resolvedFrom != null ? { fromSeconds: resolvedFrom } : {},
|
|
6601
|
+
...resolvedTo != null ? { toSeconds: resolvedTo } : {},
|
|
6602
|
+
countBack
|
|
6603
|
+
};
|
|
6604
|
+
}
|
|
6605
|
+
function resolveBacktestAccountValueUsd(value) {
|
|
6606
|
+
if (typeof value === "number" && Number.isFinite(value) && value > 0) {
|
|
6607
|
+
return value;
|
|
6608
|
+
}
|
|
6609
|
+
if (typeof value === "string" && value.trim().length > 0) {
|
|
6610
|
+
const parsed = Number.parseFloat(value.trim());
|
|
6611
|
+
if (Number.isFinite(parsed) && parsed > 0) {
|
|
6612
|
+
return parsed;
|
|
6613
|
+
}
|
|
6614
|
+
}
|
|
6615
|
+
return void 0;
|
|
6616
|
+
}
|
|
6617
|
+
function buildBacktestDecisionSeriesInput(request) {
|
|
6618
|
+
const accountValueUsd = resolveBacktestAccountValueUsd(request.initialEquityUsd);
|
|
6619
|
+
return {
|
|
6620
|
+
...request.symbol ? { symbol: request.symbol } : {},
|
|
6621
|
+
...request.timeframeStart ? { timeframeStart: request.timeframeStart } : {},
|
|
6622
|
+
...request.timeframeEnd ? { timeframeEnd: request.timeframeEnd } : {},
|
|
6623
|
+
...request.from != null ? { from: request.from } : {},
|
|
6624
|
+
...request.to != null ? { to: request.to } : {},
|
|
6625
|
+
...request.lookbackDays != null ? { lookbackDays: request.lookbackDays } : {},
|
|
6626
|
+
...accountValueUsd != null ? { accountValueUsd } : {}
|
|
6627
|
+
};
|
|
6628
|
+
}
|
|
6315
6629
|
var METADATA_SPEC_VERSION = "1.1.0";
|
|
6316
6630
|
var McpAnnotationsSchema = z.object({
|
|
6317
6631
|
title: z.string().optional(),
|
|
@@ -6430,8 +6744,8 @@ var BuildMetadataSchema = z.object({
|
|
|
6430
6744
|
chains: z.array(z.union([z.string(), z.number()])).optional()
|
|
6431
6745
|
}).strict();
|
|
6432
6746
|
function resolveTsconfig(projectRoot) {
|
|
6433
|
-
const candidate =
|
|
6434
|
-
if (
|
|
6747
|
+
const candidate = path5.join(projectRoot, "tsconfig.json");
|
|
6748
|
+
if (fs4.existsSync(candidate)) {
|
|
6435
6749
|
return candidate;
|
|
6436
6750
|
}
|
|
6437
6751
|
return void 0;
|
|
@@ -6441,9 +6755,9 @@ async function transpileWithEsbuild(options) {
|
|
|
6441
6755
|
throw new Error("No entry points provided for esbuild transpilation");
|
|
6442
6756
|
}
|
|
6443
6757
|
const projectRoot = options.projectRoot;
|
|
6444
|
-
const tempBase = options.outDir ??
|
|
6445
|
-
if (!
|
|
6446
|
-
|
|
6758
|
+
const tempBase = options.outDir ?? fs4.mkdtempSync(path5.join(tmpdir(), "opentool-"));
|
|
6759
|
+
if (!fs4.existsSync(tempBase)) {
|
|
6760
|
+
fs4.mkdirSync(tempBase, { recursive: true });
|
|
6447
6761
|
}
|
|
6448
6762
|
const tsconfig = resolveTsconfig(projectRoot);
|
|
6449
6763
|
const buildOptions = {
|
|
@@ -6474,6 +6788,9 @@ async function transpileWithEsbuild(options) {
|
|
|
6474
6788
|
if (options.external && options.external.length > 0) {
|
|
6475
6789
|
buildOptions.external = options.external;
|
|
6476
6790
|
}
|
|
6791
|
+
if (options.nodePaths && options.nodePaths.length > 0) {
|
|
6792
|
+
buildOptions.nodePaths = options.nodePaths;
|
|
6793
|
+
}
|
|
6477
6794
|
if (options.outBase) {
|
|
6478
6795
|
buildOptions.outbase = options.outBase;
|
|
6479
6796
|
}
|
|
@@ -6485,25 +6802,25 @@ async function transpileWithEsbuild(options) {
|
|
|
6485
6802
|
}
|
|
6486
6803
|
await build(buildOptions);
|
|
6487
6804
|
if (options.format === "esm") {
|
|
6488
|
-
const packageJsonPath =
|
|
6489
|
-
if (!
|
|
6490
|
-
|
|
6805
|
+
const packageJsonPath = path5.join(tempBase, "package.json");
|
|
6806
|
+
if (!fs4.existsSync(packageJsonPath)) {
|
|
6807
|
+
fs4.writeFileSync(packageJsonPath, JSON.stringify({ type: "module" }), "utf8");
|
|
6491
6808
|
}
|
|
6492
6809
|
}
|
|
6493
6810
|
const cleanup = () => {
|
|
6494
6811
|
if (options.outDir) {
|
|
6495
6812
|
return;
|
|
6496
6813
|
}
|
|
6497
|
-
|
|
6814
|
+
fs4.rmSync(tempBase, { recursive: true, force: true });
|
|
6498
6815
|
};
|
|
6499
6816
|
return { outDir: tempBase, cleanup };
|
|
6500
6817
|
}
|
|
6501
6818
|
createRequire(
|
|
6502
|
-
typeof __filename
|
|
6819
|
+
typeof __filename !== "undefined" ? __filename : import.meta.url
|
|
6503
6820
|
);
|
|
6504
6821
|
function resolveCompiledPath(outDir, originalFile, extension = ".js") {
|
|
6505
|
-
const baseName =
|
|
6506
|
-
return
|
|
6822
|
+
const baseName = path5.basename(originalFile).replace(/\.[^.]+$/, "");
|
|
6823
|
+
return path5.join(outDir, `${baseName}${extension}`);
|
|
6507
6824
|
}
|
|
6508
6825
|
async function importFresh(modulePath) {
|
|
6509
6826
|
const fileUrl = pathToFileURL(modulePath).href;
|
|
@@ -6515,16 +6832,16 @@ async function importFresh(modulePath) {
|
|
|
6515
6832
|
// src/cli/shared/metadata.ts
|
|
6516
6833
|
var METADATA_ENTRY = "metadata.ts";
|
|
6517
6834
|
async function loadMetadata2(projectRoot) {
|
|
6518
|
-
const absPath =
|
|
6519
|
-
if (!
|
|
6835
|
+
const absPath = path5.join(projectRoot, METADATA_ENTRY);
|
|
6836
|
+
if (!fs4.existsSync(absPath)) {
|
|
6520
6837
|
return {
|
|
6521
6838
|
metadata: MetadataSchema.parse({}),
|
|
6522
6839
|
sourcePath: "smart defaults (metadata.ts missing)"
|
|
6523
6840
|
};
|
|
6524
6841
|
}
|
|
6525
|
-
const tempDir =
|
|
6526
|
-
if (
|
|
6527
|
-
|
|
6842
|
+
const tempDir = path5.join(projectRoot, ".opentool-temp");
|
|
6843
|
+
if (fs4.existsSync(tempDir)) {
|
|
6844
|
+
fs4.rmSync(tempDir, { recursive: true, force: true });
|
|
6528
6845
|
}
|
|
6529
6846
|
const { outDir, cleanup } = await transpileWithEsbuild({
|
|
6530
6847
|
entryPoints: [absPath],
|
|
@@ -6540,8 +6857,8 @@ async function loadMetadata2(projectRoot) {
|
|
|
6540
6857
|
return { metadata: parsed, sourcePath: absPath };
|
|
6541
6858
|
} finally {
|
|
6542
6859
|
cleanup();
|
|
6543
|
-
if (
|
|
6544
|
-
|
|
6860
|
+
if (fs4.existsSync(tempDir)) {
|
|
6861
|
+
fs4.rmSync(tempDir, { recursive: true, force: true });
|
|
6545
6862
|
}
|
|
6546
6863
|
}
|
|
6547
6864
|
}
|
|
@@ -6563,12 +6880,12 @@ function extractMetadataExport(moduleExports) {
|
|
|
6563
6880
|
return moduleExports;
|
|
6564
6881
|
}
|
|
6565
6882
|
function readPackageJson(projectRoot) {
|
|
6566
|
-
const packagePath =
|
|
6567
|
-
if (!
|
|
6883
|
+
const packagePath = path5.join(projectRoot, "package.json");
|
|
6884
|
+
if (!fs4.existsSync(packagePath)) {
|
|
6568
6885
|
return {};
|
|
6569
6886
|
}
|
|
6570
6887
|
try {
|
|
6571
|
-
const content =
|
|
6888
|
+
const content = fs4.readFileSync(packagePath, "utf8");
|
|
6572
6889
|
return JSON.parse(content);
|
|
6573
6890
|
} catch (error) {
|
|
6574
6891
|
throw new Error(`Failed to read package.json: ${error}`);
|
|
@@ -6579,7 +6896,7 @@ async function buildMetadataArtifact(options) {
|
|
|
6579
6896
|
const packageInfo = readPackageJson(projectRoot);
|
|
6580
6897
|
const { metadata: authored, sourcePath } = await loadMetadata2(projectRoot);
|
|
6581
6898
|
const defaultsApplied = [];
|
|
6582
|
-
const folderName =
|
|
6899
|
+
const folderName = path5.basename(projectRoot);
|
|
6583
6900
|
const name = resolveField(
|
|
6584
6901
|
"name",
|
|
6585
6902
|
authored.name,
|
|
@@ -6791,6 +7108,8 @@ function validateCronTokens(fields, context) {
|
|
|
6791
7108
|
|
|
6792
7109
|
// src/cli/validate.ts
|
|
6793
7110
|
var SUPPORTED_EXTENSIONS = [".ts", ".tsx", ".js", ".jsx", ".mjs", ".cjs"];
|
|
7111
|
+
var OPENTOOL_ROOT = path5.resolve(path5.dirname(fileURLToPath(import.meta.url)), "../..");
|
|
7112
|
+
var OPENTOOL_NODE_MODULES = path5.join(OPENTOOL_ROOT, "node_modules");
|
|
6794
7113
|
var MIN_TEMPLATE_CONFIG_VERSION = 2;
|
|
6795
7114
|
var TEMPLATE_PREVIEW_TITLE_MAX = 80;
|
|
6796
7115
|
var TEMPLATE_PREVIEW_SUBTITLE_MAX = 120;
|
|
@@ -6877,37 +7196,37 @@ function normalizeTemplatePreview(value, file, toolName, requirePreview) {
|
|
|
6877
7196
|
};
|
|
6878
7197
|
}
|
|
6879
7198
|
async function validateCommand(options) {
|
|
6880
|
-
console.log("\u{1F50D} Validating OpenTool
|
|
7199
|
+
console.log("\u{1F50D} Validating OpenTool project...");
|
|
6881
7200
|
try {
|
|
6882
|
-
const toolsDir =
|
|
6883
|
-
if (!
|
|
7201
|
+
const toolsDir = path5.resolve(options.input);
|
|
7202
|
+
if (!fs4.existsSync(toolsDir)) {
|
|
6884
7203
|
throw new Error(`Tools directory not found: ${toolsDir}`);
|
|
6885
7204
|
}
|
|
6886
|
-
const projectRoot =
|
|
7205
|
+
const projectRoot = path5.dirname(toolsDir);
|
|
6887
7206
|
const tools = await loadAndValidateTools(toolsDir, { projectRoot });
|
|
6888
7207
|
if (tools.length === 0) {
|
|
6889
|
-
throw new Error("No valid tools found -
|
|
7208
|
+
throw new Error("No valid tools found - validation aborted");
|
|
6890
7209
|
}
|
|
6891
7210
|
const { metadata, defaultsApplied, sourceMetadataPath } = await buildMetadataArtifact({
|
|
6892
7211
|
projectRoot,
|
|
6893
7212
|
tools
|
|
6894
7213
|
});
|
|
6895
7214
|
logMetadataSummary(metadata, defaultsApplied, sourceMetadataPath);
|
|
6896
|
-
console.log("\n\u2705
|
|
7215
|
+
console.log("\n\u2705 OpenTool validation passed!\n");
|
|
6897
7216
|
} catch (error) {
|
|
6898
|
-
console.error("\u274C
|
|
7217
|
+
console.error("\u274C OpenTool validation failed:", error);
|
|
6899
7218
|
process.exit(1);
|
|
6900
7219
|
}
|
|
6901
7220
|
}
|
|
6902
7221
|
async function loadAndValidateTools(toolsDir, options = {}) {
|
|
6903
|
-
const files =
|
|
7222
|
+
const files = fs4.readdirSync(toolsDir).filter((file) => SUPPORTED_EXTENSIONS.includes(path5.extname(file)));
|
|
6904
7223
|
if (files.length === 0) {
|
|
6905
7224
|
return [];
|
|
6906
7225
|
}
|
|
6907
|
-
const projectRoot = options.projectRoot ??
|
|
6908
|
-
const tempDir =
|
|
6909
|
-
if (
|
|
6910
|
-
|
|
7226
|
+
const projectRoot = options.projectRoot ?? path5.dirname(toolsDir);
|
|
7227
|
+
const tempDir = path5.join(toolsDir, ".opentool-temp");
|
|
7228
|
+
if (fs4.existsSync(tempDir)) {
|
|
7229
|
+
fs4.rmSync(tempDir, { recursive: true, force: true });
|
|
6911
7230
|
}
|
|
6912
7231
|
const kebabCase = /^[a-z0-9]+(?:-[a-z0-9]+)*\.[a-z]+$/;
|
|
6913
7232
|
for (const f of files) {
|
|
@@ -6915,20 +7234,23 @@ async function loadAndValidateTools(toolsDir, options = {}) {
|
|
|
6915
7234
|
throw new Error(`Tool filename must be kebab-case: ${f}`);
|
|
6916
7235
|
}
|
|
6917
7236
|
}
|
|
6918
|
-
const entryPoints = files.map((file) =>
|
|
7237
|
+
const entryPoints = files.map((file) => path5.join(toolsDir, file));
|
|
7238
|
+
const fallbackNodePaths = [OPENTOOL_NODE_MODULES].filter((dir) => fs4.existsSync(dir));
|
|
6919
7239
|
const { outDir, cleanup } = await transpileWithEsbuild({
|
|
6920
7240
|
entryPoints,
|
|
6921
7241
|
projectRoot,
|
|
6922
7242
|
format: "esm",
|
|
6923
7243
|
outDir: tempDir,
|
|
6924
7244
|
bundle: true,
|
|
6925
|
-
external: ["opentool", "opentool/*"]
|
|
7245
|
+
external: ["opentool", "opentool/*"],
|
|
7246
|
+
...fallbackNodePaths.length > 0 ? { nodePaths: fallbackNodePaths } : {}
|
|
6926
7247
|
});
|
|
6927
7248
|
const tools = [];
|
|
6928
7249
|
try {
|
|
7250
|
+
ensureLocalRuntimeLinks(tempDir);
|
|
6929
7251
|
for (const file of files) {
|
|
6930
7252
|
const compiledPath = resolveCompiledPath(outDir, file);
|
|
6931
|
-
if (!
|
|
7253
|
+
if (!fs4.existsSync(compiledPath)) {
|
|
6932
7254
|
throw new Error(`Failed to compile ${file}`);
|
|
6933
7255
|
}
|
|
6934
7256
|
const moduleExports = await importFresh(compiledPath);
|
|
@@ -7079,11 +7401,6 @@ async function loadAndValidateTools(toolsDir, options = {}) {
|
|
|
7079
7401
|
if (!schema) {
|
|
7080
7402
|
throw new Error(`${file}: POST tools must export a Zod schema as 'schema'`);
|
|
7081
7403
|
}
|
|
7082
|
-
if (schedule && typeof schedule.cron === "string") {
|
|
7083
|
-
throw new Error(
|
|
7084
|
-
`${file}: POST tools must not define profile.schedule; use GET + cron for scheduled tasks.`
|
|
7085
|
-
);
|
|
7086
|
-
}
|
|
7087
7404
|
}
|
|
7088
7405
|
const httpHandlers = [...httpHandlersRaw];
|
|
7089
7406
|
if (httpHandlers.length === 0) {
|
|
@@ -7131,7 +7448,7 @@ async function loadAndValidateTools(toolsDir, options = {}) {
|
|
|
7131
7448
|
httpHandlers,
|
|
7132
7449
|
mcpConfig: normalizeMcpConfig(toolModule.mcp, file),
|
|
7133
7450
|
filename: toBaseName(file),
|
|
7134
|
-
sourcePath:
|
|
7451
|
+
sourcePath: path5.join(toolsDir, file),
|
|
7135
7452
|
handler: async (params) => adapter(params),
|
|
7136
7453
|
payment: paymentExport ?? null,
|
|
7137
7454
|
schedule: normalizedSchedule,
|
|
@@ -7144,12 +7461,30 @@ async function loadAndValidateTools(toolsDir, options = {}) {
|
|
|
7144
7461
|
}
|
|
7145
7462
|
} finally {
|
|
7146
7463
|
cleanup();
|
|
7147
|
-
if (
|
|
7148
|
-
|
|
7464
|
+
if (fs4.existsSync(tempDir)) {
|
|
7465
|
+
fs4.rmSync(tempDir, { recursive: true, force: true });
|
|
7149
7466
|
}
|
|
7150
7467
|
}
|
|
7151
7468
|
return tools;
|
|
7152
7469
|
}
|
|
7470
|
+
function ensureLocalRuntimeLinks(tempDir) {
|
|
7471
|
+
const nodeModulesDir = path5.join(tempDir, "node_modules");
|
|
7472
|
+
fs4.mkdirSync(nodeModulesDir, { recursive: true });
|
|
7473
|
+
const packageLinks = [
|
|
7474
|
+
{ name: "opentool", target: OPENTOOL_ROOT },
|
|
7475
|
+
{ name: "zod", target: path5.join(OPENTOOL_NODE_MODULES, "zod") }
|
|
7476
|
+
];
|
|
7477
|
+
for (const { name, target } of packageLinks) {
|
|
7478
|
+
if (!fs4.existsSync(target)) {
|
|
7479
|
+
continue;
|
|
7480
|
+
}
|
|
7481
|
+
const linkPath = path5.join(nodeModulesDir, name);
|
|
7482
|
+
if (fs4.existsSync(linkPath)) {
|
|
7483
|
+
continue;
|
|
7484
|
+
}
|
|
7485
|
+
fs4.symlinkSync(target, linkPath, "junction");
|
|
7486
|
+
}
|
|
7487
|
+
}
|
|
7153
7488
|
function extractToolModule(exportsObject, filename) {
|
|
7154
7489
|
const candidates = [exportsObject, exportsObject?.default];
|
|
7155
7490
|
for (const candidate of candidates) {
|
|
@@ -7347,18 +7682,18 @@ async function generateMetadataCommand(options) {
|
|
|
7347
7682
|
}
|
|
7348
7683
|
}
|
|
7349
7684
|
async function generateMetadata(options) {
|
|
7350
|
-
const toolsDir =
|
|
7351
|
-
if (!
|
|
7685
|
+
const toolsDir = path5.resolve(options.input);
|
|
7686
|
+
if (!fs4.existsSync(toolsDir)) {
|
|
7352
7687
|
throw new Error(`Tools directory not found: ${toolsDir}`);
|
|
7353
7688
|
}
|
|
7354
|
-
const projectRoot =
|
|
7689
|
+
const projectRoot = path5.dirname(toolsDir);
|
|
7355
7690
|
const tools = await loadAndValidateTools(toolsDir, { projectRoot });
|
|
7356
7691
|
const { metadata, defaultsApplied } = await buildMetadataArtifact({
|
|
7357
7692
|
projectRoot,
|
|
7358
7693
|
tools
|
|
7359
7694
|
});
|
|
7360
|
-
const outputPath = options.output ?
|
|
7361
|
-
|
|
7695
|
+
const outputPath = options.output ? path5.resolve(options.output) : path5.join(projectRoot, "metadata.json");
|
|
7696
|
+
fs4.writeFileSync(outputPath, JSON.stringify(metadata, null, 2));
|
|
7362
7697
|
return {
|
|
7363
7698
|
metadata,
|
|
7364
7699
|
defaultsApplied,
|
|
@@ -7370,6 +7705,6 @@ function timestamp() {
|
|
|
7370
7705
|
return (/* @__PURE__ */ new Date()).toISOString().replace("T", " ").slice(0, 19);
|
|
7371
7706
|
}
|
|
7372
7707
|
|
|
7373
|
-
export { AIAbortError, AIError, AIFetchError, AIResponseError, DEFAULT_BASE_URL, DEFAULT_CHAIN, DEFAULT_FACILITATOR, DEFAULT_HYPERLIQUID_MARKET_SLIPPAGE_BPS, DEFAULT_MODEL, DEFAULT_TIMEOUT_MS, DEFAULT_TOKENS, HTTP_METHODS2 as HTTP_METHODS, HyperliquidApiError, HyperliquidBuilderApprovalError, HyperliquidExchangeClient, HyperliquidGuardError, HyperliquidInfoClient, HyperliquidTermsError, PAYMENT_HEADERS, POLYMARKET_CHAIN_ID, POLYMARKET_CLOB_AUTH_DOMAIN, POLYMARKET_CLOB_DOMAIN, POLYMARKET_ENDPOINTS, POLYMARKET_EXCHANGE_ADDRESSES, PolymarketApiError, PolymarketAuthError, PolymarketExchangeClient, PolymarketInfoClient, SUPPORTED_CURRENCIES, StoreError, WEBSEARCH_TOOL_DEFINITION, WEBSEARCH_TOOL_NAME, X402BrowserClient, X402Client, X402PaymentRequiredError, __hyperliquidInternals, __hyperliquidMarketDataInternals, approveHyperliquidBuilderFee, backtestDecisionRequestSchema, batchModifyHyperliquidOrders, buildHmacSignature, buildHyperliquidMarketIdentity, buildHyperliquidProfileAssets, buildHyperliquidSpotUsdPriceMap, buildL1Headers, buildL2Headers, buildPolymarketOrderAmounts, buildSignedOrderPayload, cancelAllHyperliquidOrders, cancelAllPolymarketOrders, cancelHyperliquidOrders, cancelHyperliquidOrdersByCloid, cancelHyperliquidTwapOrder, cancelMarketPolymarketOrders, cancelPolymarketOrder, cancelPolymarketOrders, chains, computeHyperliquidMarketIocLimitPrice, createAIClient, createDevServer, createHyperliquidSubAccount, createMcpAdapter, createMonotonicNonceFactory, createPolymarketApiKey, createStdioServer, defineX402Payment, depositToHyperliquidBridge, derivePolymarketApiKey, ensureTextContent, estimateCountBack, executeTool, extractHyperliquidDex, extractHyperliquidOrderIds, fetchHyperliquidAllMids, fetchHyperliquidAssetCtxs, fetchHyperliquidBars, fetchHyperliquidClearinghouseState, fetchHyperliquidFrontendOpenOrders, fetchHyperliquidHistoricalOrders, fetchHyperliquidMeta, fetchHyperliquidMetaAndAssetCtxs, fetchHyperliquidOpenOrders, fetchHyperliquidOrderStatus, fetchHyperliquidPerpMarketInfo, fetchHyperliquidPreTransferCheck, fetchHyperliquidSizeDecimals, fetchHyperliquidSpotAccountValue, fetchHyperliquidSpotAssetCtxs, fetchHyperliquidSpotClearinghouseState, fetchHyperliquidSpotMarketInfo, fetchHyperliquidSpotMeta, fetchHyperliquidSpotMetaAndAssetCtxs, fetchHyperliquidSpotTickSize, fetchHyperliquidSpotUsdPriceMap, fetchHyperliquidTickSize, fetchHyperliquidUserFills, fetchHyperliquidUserFillsByTime, fetchHyperliquidUserRateLimit, fetchPolymarketMarket, fetchPolymarketMarkets, fetchPolymarketMidpoint, fetchPolymarketOrderbook, fetchPolymarketPrice, fetchPolymarketPriceHistory, flattenMessageContent, formatHyperliquidMarketablePrice, formatHyperliquidOrderSize, formatHyperliquidPrice, formatHyperliquidSize, generateMetadata, generateMetadataCommand, generateText, getHyperliquidMaxBuilderFee, getModelConfig, getMyPerformance, getMyTools, getRpcUrl, getX402PaymentContext, isHyperliquidSpotSymbol, isStreamingSupported, isToolCallingSupported, listModels, loadAndValidateTools, modifyHyperliquidOrder, normalizeHyperliquidBaseSymbol, normalizeHyperliquidMetaSymbol, normalizeModelName, normalizeNumberArrayish, normalizeSpotTokenName2 as normalizeSpotTokenName, normalizeStringArrayish, parseSpotPairSymbol, parseTimeToSeconds, payX402, payX402WithWallet, placeHyperliquidOrder, placeHyperliquidTwapOrder, placePolymarketOrder, postAgentDigest, readHyperliquidAccountValue, readHyperliquidNumber, readHyperliquidPerpPosition, readHyperliquidPerpPositionSize, readHyperliquidSpotAccountValue, readHyperliquidSpotBalance, readHyperliquidSpotBalanceSize, recordHyperliquidBuilderApproval, recordHyperliquidTermsAcceptance, registry, requireX402Payment, reserveHyperliquidRequestWeight, resolutionToSeconds, resolveConfig2 as resolveConfig, resolveExchangeAddress, resolveHyperliquidAbstractionFromMode, resolveHyperliquidChain, resolveHyperliquidChainConfig, resolveHyperliquidErrorDetail, resolveHyperliquidOrderRef, resolveHyperliquidOrderSymbol, resolveHyperliquidPair, resolveHyperliquidProfileChain, resolveHyperliquidRpcEnvVar, resolveHyperliquidStoreNetwork, resolveHyperliquidSymbol, resolvePolymarketBaseUrl, resolveRuntimePath, resolveSpotMidCandidates, resolveSpotTokenCandidates, resolveToolset, responseToToolResponse, retrieve, roundHyperliquidPriceToTick, scheduleHyperliquidCancel, sendHyperliquidSpot, setHyperliquidAccountAbstractionMode, setHyperliquidDexAbstraction, setHyperliquidPortfolioMargin, store, streamText, tokens, transferHyperliquidSubAccount, updateHyperliquidIsolatedMargin, updateHyperliquidLeverage, validateCommand, wallet, walletToolkit, withX402Payment, withdrawFromHyperliquid };
|
|
7708
|
+
export { AIAbortError, AIError, AIFetchError, AIResponseError, BACKTEST_DECISION_MODE, DEFAULT_BASE_URL, DEFAULT_CHAIN, DEFAULT_FACILITATOR, DEFAULT_HYPERLIQUID_CADENCE_CRON, DEFAULT_HYPERLIQUID_MARKET_SLIPPAGE_BPS, DEFAULT_MODEL, DEFAULT_TIMEOUT_MS, DEFAULT_TOKENS, HTTP_METHODS2 as HTTP_METHODS, HyperliquidApiError, HyperliquidBuilderApprovalError, HyperliquidExchangeClient, HyperliquidGuardError, HyperliquidInfoClient, HyperliquidTermsError, PAYMENT_HEADERS, POLYMARKET_CHAIN_ID, POLYMARKET_CLOB_AUTH_DOMAIN, POLYMARKET_CLOB_DOMAIN, POLYMARKET_ENDPOINTS, POLYMARKET_EXCHANGE_ADDRESSES, PolymarketApiError, PolymarketAuthError, PolymarketExchangeClient, PolymarketInfoClient, SUPPORTED_CURRENCIES, StoreError, WEBSEARCH_TOOL_DEFINITION, WEBSEARCH_TOOL_NAME, X402BrowserClient, X402Client, X402PaymentRequiredError, __hyperliquidInternals, __hyperliquidMarketDataInternals, approveHyperliquidBuilderFee, backtestDecisionRequestSchema, batchModifyHyperliquidOrders, buildBacktestDecisionSeriesInput, buildHmacSignature, buildHyperliquidMarketIdentity, buildHyperliquidProfileAssets, buildHyperliquidSpotUsdPriceMap, buildL1Headers, buildL2Headers, buildPolymarketOrderAmounts, buildSignedOrderPayload, cancelAllHyperliquidOrders, cancelAllPolymarketOrders, cancelHyperliquidOrders, cancelHyperliquidOrdersByCloid, cancelHyperliquidTwapOrder, cancelMarketPolymarketOrders, cancelPolymarketOrder, cancelPolymarketOrders, chains, clampHyperliquidAbs, clampHyperliquidFloat, clampHyperliquidInt, computeHyperliquidMarketIocLimitPrice, createAIClient, createDevServer, createHyperliquidSubAccount, createMcpAdapter, createMonotonicNonceFactory, createPolymarketApiKey, createStdioServer, defineX402Payment, depositToHyperliquidBridge, derivePolymarketApiKey, ensureTextContent, estimateCountBack, executeTool, extractHyperliquidDex, extractHyperliquidOrderIds, fetchHyperliquidAllMids, fetchHyperliquidAssetCtxs, fetchHyperliquidBars, fetchHyperliquidClearinghouseState, fetchHyperliquidFrontendOpenOrders, fetchHyperliquidHistoricalOrders, fetchHyperliquidMeta, fetchHyperliquidMetaAndAssetCtxs, fetchHyperliquidOpenOrders, fetchHyperliquidOrderStatus, fetchHyperliquidPerpMarketInfo, fetchHyperliquidPreTransferCheck, fetchHyperliquidSizeDecimals, fetchHyperliquidSpotAccountValue, fetchHyperliquidSpotAssetCtxs, fetchHyperliquidSpotClearinghouseState, fetchHyperliquidSpotMarketInfo, fetchHyperliquidSpotMeta, fetchHyperliquidSpotMetaAndAssetCtxs, fetchHyperliquidSpotTickSize, fetchHyperliquidSpotUsdPriceMap, fetchHyperliquidTickSize, fetchHyperliquidUserFills, fetchHyperliquidUserFillsByTime, fetchHyperliquidUserRateLimit, fetchPolymarketMarket, fetchPolymarketMarkets, fetchPolymarketMidpoint, fetchPolymarketOrderbook, fetchPolymarketPrice, fetchPolymarketPriceHistory, flattenMessageContent, formatHyperliquidMarketablePrice, formatHyperliquidOrderSize, formatHyperliquidPrice, formatHyperliquidSize, generateMetadata, generateMetadataCommand, generateText, getHyperliquidMaxBuilderFee, getModelConfig, getMyPerformance, getMyTools, getRpcUrl, getX402PaymentContext, isHyperliquidSpotSymbol, isStreamingSupported, isToolCallingSupported, listModels, loadAndValidateTools, modifyHyperliquidOrder, normalizeHyperliquidBaseSymbol, normalizeHyperliquidDcaEntries, normalizeHyperliquidIndicatorBars, normalizeHyperliquidMetaSymbol, normalizeModelName, normalizeNumberArrayish, normalizeSpotTokenName2 as normalizeSpotTokenName, normalizeStringArrayish, parseHyperliquidJson, parseSpotPairSymbol, parseTimeToSeconds, payX402, payX402WithWallet, placeHyperliquidOrder, placeHyperliquidTwapOrder, placePolymarketOrder, planHyperliquidTrade, postAgentDigest, readHyperliquidAccountValue, readHyperliquidNumber, readHyperliquidPerpPosition, readHyperliquidPerpPositionSize, readHyperliquidSpotAccountValue, readHyperliquidSpotBalance, readHyperliquidSpotBalanceSize, recordHyperliquidBuilderApproval, recordHyperliquidTermsAcceptance, registry, requireX402Payment, reserveHyperliquidRequestWeight, resolutionToSeconds, resolveBacktestAccountValueUsd, resolveBacktestMode, resolveBacktestWindow, resolveConfig2 as resolveConfig, resolveExchangeAddress, resolveHyperliquidAbstractionFromMode, resolveHyperliquidBudgetUsd, resolveHyperliquidCadenceCron, resolveHyperliquidCadenceFromResolution, resolveHyperliquidChain, resolveHyperliquidChainConfig, resolveHyperliquidDcaSymbolEntries, resolveHyperliquidErrorDetail, resolveHyperliquidHourlyInterval, resolveHyperliquidIntervalCron, resolveHyperliquidLeverageMode, resolveHyperliquidMaxPerRunUsd, resolveHyperliquidOrderRef, resolveHyperliquidOrderSymbol, resolveHyperliquidPair, resolveHyperliquidPerpSymbol, resolveHyperliquidProfileChain, resolveHyperliquidRpcEnvVar, resolveHyperliquidScheduleEvery, resolveHyperliquidScheduleUnit, resolveHyperliquidSpotSymbol, resolveHyperliquidStoreNetwork, resolveHyperliquidSymbol, resolveHyperliquidTargetSize, resolvePolymarketBaseUrl, resolveRuntimePath, resolveSpotMidCandidates, resolveSpotTokenCandidates, resolveToolset, responseToToolResponse, retrieve, roundHyperliquidPriceToTick, scheduleHyperliquidCancel, sendHyperliquidSpot, setHyperliquidAccountAbstractionMode, setHyperliquidDexAbstraction, setHyperliquidPortfolioMargin, store, streamText, tokens, transferHyperliquidSubAccount, updateHyperliquidIsolatedMargin, updateHyperliquidLeverage, validateCommand, wallet, walletToolkit, withX402Payment, withdrawFromHyperliquid };
|
|
7374
7709
|
//# sourceMappingURL=index.js.map
|
|
7375
7710
|
//# sourceMappingURL=index.js.map
|