@pgnio/helios-mcp 0.2.8 → 0.2.9
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/{chunk-V453JYRN.mjs → chunk-7TMDGB6C.mjs} +64 -31
- package/dist/{chunk-UHFLF3UG.mjs → chunk-LMZEWQVW.mjs} +62 -29
- package/dist/cli.js +40 -14
- package/dist/cli.mjs +1 -1
- package/dist/index.d.mts +15 -9
- package/dist/index.d.ts +15 -9
- package/dist/index.js +40 -14
- package/dist/index.mjs +1 -1
- package/docs/ai-agent-indicators/00_columns.txt +3 -1
- package/package.json +1 -1
- package/dist/chunk-52XY4KRG.mjs +0 -3038
- package/dist/chunk-7EDI4KLD.mjs +0 -3042
- package/dist/chunk-EIAUO3XE.mjs +0 -2955
- package/dist/chunk-NCF7ASJB.mjs +0 -2986
- package/dist/chunk-NWGWXYTS.mjs +0 -2964
- package/dist/chunk-UYCUR7QV.mjs +0 -2994
- package/dist/chunk-WLCFIWFP.mjs +0 -3048
- package/dist/chunk-XE6HRID3.mjs +0 -2992
|
@@ -2,6 +2,13 @@ var __defProp = Object.defineProperty;
|
|
|
2
2
|
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
|
3
3
|
var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
|
|
4
4
|
|
|
5
|
+
// ../../node_modules/.pnpm/tsup@8.5.1_jiti@2.6.1_postcss@8.5.6_tsx@4.20.6_typescript@5.9.3_yaml@2.8.2/node_modules/tsup/assets/esm_shims.js
|
|
6
|
+
import path from "path";
|
|
7
|
+
import { fileURLToPath } from "url";
|
|
8
|
+
var getFilename = () => fileURLToPath(import.meta.url);
|
|
9
|
+
var getDirname = () => path.dirname(getFilename());
|
|
10
|
+
var __dirname = /* @__PURE__ */ getDirname();
|
|
11
|
+
|
|
5
12
|
// ../agent/dist/index.mjs
|
|
6
13
|
import { z } from "zod";
|
|
7
14
|
import { z as z2 } from "zod";
|
|
@@ -116,19 +123,21 @@ var protectiveOrderKindSchema = z.enum(["STOP_LOSS", "TAKE_PROFIT"]);
|
|
|
116
123
|
var protectiveOrderSideSchema = z.enum(["BUY", "SELL"]);
|
|
117
124
|
var protectiveOrderPositionSideSchema = z.enum(["BOTH", "LONG", "SHORT"]);
|
|
118
125
|
var protectiveOrderSchema = z.object({
|
|
126
|
+
/** Helios's record id: what helios_positions_delete_tp_sl takes (the Hyperliquid order id works there too). */
|
|
119
127
|
id: z.string(),
|
|
120
|
-
|
|
121
|
-
|
|
128
|
+
/** The Hyperliquid order id (named after the retired Binance field). */
|
|
129
|
+
binanceOrderId: z.number().int().nonnegative().nullish(),
|
|
130
|
+
clientOrderId: z.string().nullish(),
|
|
122
131
|
symbol: z.string(),
|
|
123
132
|
side: protectiveOrderSideSchema,
|
|
124
|
-
positionSide: protectiveOrderPositionSideSchema,
|
|
133
|
+
positionSide: protectiveOrderPositionSideSchema.nullish().transform((value) => value ?? "BOTH"),
|
|
125
134
|
status: z.string(),
|
|
126
135
|
kind: protectiveOrderKindSchema,
|
|
127
|
-
groupId: z.string(),
|
|
128
|
-
stopPrice: z.string().
|
|
129
|
-
parentClientOrderId: z.string().
|
|
130
|
-
assetId: z.number().int().nonnegative().
|
|
131
|
-
createdAt: z.string().
|
|
136
|
+
groupId: z.string().nullish(),
|
|
137
|
+
stopPrice: z.union([z.string(), z.number()]).nullish().transform((value) => value == null ? value : String(value)),
|
|
138
|
+
parentClientOrderId: z.string().nullish(),
|
|
139
|
+
assetId: z.number().int().nonnegative().nullish(),
|
|
140
|
+
createdAt: z.string().nullish()
|
|
132
141
|
});
|
|
133
142
|
var hyperliquidPortfolioSnapshotSchema = z.object({
|
|
134
143
|
provider: z.literal("hyperliquid"),
|
|
@@ -137,6 +146,7 @@ var hyperliquidPortfolioSnapshotSchema = z.object({
|
|
|
137
146
|
totalMargin: z.number(),
|
|
138
147
|
unrealizedPnl: z.number(),
|
|
139
148
|
positions: z.array(openPositionSchema),
|
|
149
|
+
/** Unreadable entries are dropped (see readProtectiveOrders) rather than failing the read. */
|
|
140
150
|
protectiveOrders: z.array(protectiveOrderSchema)
|
|
141
151
|
});
|
|
142
152
|
var portfolioInputSchema = z.object({
|
|
@@ -331,6 +341,8 @@ var closePositionInputSchema = z.object({
|
|
|
331
341
|
});
|
|
332
342
|
var closePositionResultSchema = z.object({
|
|
333
343
|
status: z.literal("submitted"),
|
|
344
|
+
/** `no_position`: nothing was open on this coin, so no order was sent. Absent from older data-bridges. */
|
|
345
|
+
outcome: z.enum(["closed", "no_position"]).optional(),
|
|
334
346
|
provider: providerSchema.optional(),
|
|
335
347
|
symbol: z.string(),
|
|
336
348
|
mode: z.literal("FULL"),
|
|
@@ -442,10 +454,10 @@ var HeliosAgentAuthClient = class {
|
|
|
442
454
|
const parsed = agentRefreshInputSchema.parse({ refreshToken });
|
|
443
455
|
return this.post("/api/agents/auth/refresh", parsed, agentTokenResponseSchema);
|
|
444
456
|
}
|
|
445
|
-
async post(
|
|
457
|
+
async post(path4, body, schema) {
|
|
446
458
|
let response;
|
|
447
459
|
try {
|
|
448
|
-
response = await this.fetchImpl(`${this.baseUrl}${
|
|
460
|
+
response = await this.fetchImpl(`${this.baseUrl}${path4}`, {
|
|
449
461
|
method: "POST",
|
|
450
462
|
headers: {
|
|
451
463
|
Accept: "application/json",
|
|
@@ -521,7 +533,8 @@ var HeliosAgentDataBridgeClient = class {
|
|
|
521
533
|
}
|
|
522
534
|
return portfolioSnapshotSchema.parse({
|
|
523
535
|
...result,
|
|
524
|
-
provider: parsedInput.provider
|
|
536
|
+
provider: parsedInput.provider,
|
|
537
|
+
protectiveOrders: readProtectiveOrders(result.protectiveOrders)
|
|
525
538
|
});
|
|
526
539
|
}
|
|
527
540
|
async getLedgerFills(accessToken, input = {}) {
|
|
@@ -574,7 +587,7 @@ var HeliosAgentDataBridgeClient = class {
|
|
|
574
587
|
}
|
|
575
588
|
async closePosition(accessToken, input) {
|
|
576
589
|
const parsedInput = closePositionInputSchema.parse(input);
|
|
577
|
-
await this.request(
|
|
590
|
+
const payload = await this.request(
|
|
578
591
|
accessToken,
|
|
579
592
|
"positions.close",
|
|
580
593
|
{
|
|
@@ -585,8 +598,10 @@ var HeliosAgentDataBridgeClient = class {
|
|
|
585
598
|
},
|
|
586
599
|
"POST"
|
|
587
600
|
);
|
|
601
|
+
const outcome = this.tryUnwrapResult(payload)?.outcome;
|
|
588
602
|
return closePositionResultSchema.parse({
|
|
589
603
|
status: "submitted",
|
|
604
|
+
...outcome === "closed" || outcome === "no_position" ? { outcome } : {},
|
|
590
605
|
provider: parsedInput.provider,
|
|
591
606
|
symbol: parsedInput.symbol,
|
|
592
607
|
mode: "FULL",
|
|
@@ -684,6 +699,14 @@ var HeliosAgentDataBridgeClient = class {
|
|
|
684
699
|
});
|
|
685
700
|
}
|
|
686
701
|
}
|
|
702
|
+
/** The result of a mutation older data-bridges answer with nothing; null when there is none. */
|
|
703
|
+
tryUnwrapResult(payload) {
|
|
704
|
+
try {
|
|
705
|
+
return this.unwrapResult(payload) ?? null;
|
|
706
|
+
} catch {
|
|
707
|
+
return null;
|
|
708
|
+
}
|
|
709
|
+
}
|
|
687
710
|
unwrapResult(payload) {
|
|
688
711
|
if (!payload || typeof payload !== "object") {
|
|
689
712
|
throw new HeliosAgentApiError({
|
|
@@ -744,6 +767,13 @@ var HeliosAgentDataBridgeClient = class {
|
|
|
744
767
|
return envelope;
|
|
745
768
|
}
|
|
746
769
|
};
|
|
770
|
+
function readProtectiveOrders(value) {
|
|
771
|
+
if (!Array.isArray(value)) return [];
|
|
772
|
+
return value.flatMap((entry) => {
|
|
773
|
+
const parsed = protectiveOrderSchema.safeParse(entry);
|
|
774
|
+
return parsed.success ? [parsed.data] : [];
|
|
775
|
+
});
|
|
776
|
+
}
|
|
747
777
|
var DEFAULT_AGENT_REFRESH_WINDOW_MS = 60 * 1e3;
|
|
748
778
|
var agentConnectionStatusSchema = z3.enum([
|
|
749
779
|
"disconnected",
|
|
@@ -1181,8 +1211,8 @@ var HeliosAgentMcpAccountService = class {
|
|
|
1181
1211
|
};
|
|
1182
1212
|
|
|
1183
1213
|
// src/docs-service.ts
|
|
1184
|
-
import { readdirSync, readFileSync, statSync } from "fs";
|
|
1185
|
-
import
|
|
1214
|
+
import { existsSync, readdirSync, readFileSync, statSync } from "fs";
|
|
1215
|
+
import path2 from "path";
|
|
1186
1216
|
var HeliosAgentMcpDocsService = class {
|
|
1187
1217
|
constructor(options) {
|
|
1188
1218
|
__publicField(this, "docsRoot");
|
|
@@ -1197,9 +1227,12 @@ var HeliosAgentMcpDocsService = class {
|
|
|
1197
1227
|
}
|
|
1198
1228
|
async getDocument(input) {
|
|
1199
1229
|
const documentPath = resolveDocumentPath(this.docsRoot, input.path);
|
|
1230
|
+
if (!existsSync(documentPath) || !statSync(documentPath).isFile()) {
|
|
1231
|
+
throw new Error(`No document "${input.path}". helios_docs_get_index lists the documents.`);
|
|
1232
|
+
}
|
|
1200
1233
|
const body = readFileSync(documentPath, "utf8");
|
|
1201
1234
|
const stats = statSync(documentPath);
|
|
1202
|
-
const relativePath = toPosixPath(
|
|
1235
|
+
const relativePath = toPosixPath(path2.relative(this.docsRoot, documentPath));
|
|
1203
1236
|
return {
|
|
1204
1237
|
path: relativePath,
|
|
1205
1238
|
section: getDocumentSection(relativePath),
|
|
@@ -1211,7 +1244,7 @@ var HeliosAgentMcpDocsService = class {
|
|
|
1211
1244
|
readDocumentMetadata(documentPath) {
|
|
1212
1245
|
const body = readFileSync(documentPath, "utf8");
|
|
1213
1246
|
const stats = statSync(documentPath);
|
|
1214
|
-
const relativePath = toPosixPath(
|
|
1247
|
+
const relativePath = toPosixPath(path2.relative(this.docsRoot, documentPath));
|
|
1215
1248
|
return {
|
|
1216
1249
|
path: relativePath,
|
|
1217
1250
|
section: getDocumentSection(relativePath),
|
|
@@ -1221,7 +1254,7 @@ var HeliosAgentMcpDocsService = class {
|
|
|
1221
1254
|
}
|
|
1222
1255
|
};
|
|
1223
1256
|
function getDefaultHeliosAgentMcpDocsRoot() {
|
|
1224
|
-
return
|
|
1257
|
+
return path2.resolve(__dirname, "..", "docs");
|
|
1225
1258
|
}
|
|
1226
1259
|
function listDocumentPaths(root) {
|
|
1227
1260
|
return walk(root).filter((filePath) => filePath.endsWith(".txt")).sort((left, right) => left.localeCompare(right));
|
|
@@ -1230,7 +1263,7 @@ function walk(currentPath) {
|
|
|
1230
1263
|
const entries = readdirSync(currentPath, { withFileTypes: true });
|
|
1231
1264
|
const files = [];
|
|
1232
1265
|
for (const entry of entries) {
|
|
1233
|
-
const nextPath =
|
|
1266
|
+
const nextPath = path2.join(currentPath, entry.name);
|
|
1234
1267
|
if (entry.isDirectory()) {
|
|
1235
1268
|
files.push(...walk(nextPath));
|
|
1236
1269
|
continue;
|
|
@@ -1243,12 +1276,12 @@ function walk(currentPath) {
|
|
|
1243
1276
|
}
|
|
1244
1277
|
function resolveDocumentPath(root, relativeDocumentPath) {
|
|
1245
1278
|
const normalizedPath = relativeDocumentPath.replace(/\\/g, "/").replace(/^\/+/, "");
|
|
1246
|
-
const resolvedPath =
|
|
1247
|
-
const relativePath =
|
|
1279
|
+
const resolvedPath = path2.resolve(root, normalizedPath);
|
|
1280
|
+
const relativePath = path2.relative(root, resolvedPath);
|
|
1248
1281
|
if (!normalizedPath) {
|
|
1249
1282
|
throw new Error("Document path is required.");
|
|
1250
1283
|
}
|
|
1251
|
-
if (
|
|
1284
|
+
if (path2.isAbsolute(normalizedPath) || relativePath.startsWith("..") || path2.isAbsolute(relativePath)) {
|
|
1252
1285
|
throw new Error(`Document path "${relativeDocumentPath}" is outside the docs root.`);
|
|
1253
1286
|
}
|
|
1254
1287
|
if (!resolvedPath.endsWith(".txt")) {
|
|
@@ -1268,13 +1301,13 @@ function extractDocumentTitle(body, relativePath) {
|
|
|
1268
1301
|
}
|
|
1269
1302
|
return trimmed;
|
|
1270
1303
|
}
|
|
1271
|
-
return
|
|
1304
|
+
return path2.basename(relativePath, ".txt");
|
|
1272
1305
|
}
|
|
1273
1306
|
function getDocumentSection(relativePath) {
|
|
1274
1307
|
return relativePath.split("/")[0] ?? "docs";
|
|
1275
1308
|
}
|
|
1276
1309
|
function toPosixPath(value) {
|
|
1277
|
-
return value.split(
|
|
1310
|
+
return value.split(path2.sep).join("/");
|
|
1278
1311
|
}
|
|
1279
1312
|
|
|
1280
1313
|
// src/ledger-service.ts
|
|
@@ -1624,10 +1657,10 @@ var HeliosAgentMcpProviderService = class {
|
|
|
1624
1657
|
// src/session-store.ts
|
|
1625
1658
|
import { chmod, mkdir, readFile, rm, writeFile } from "fs/promises";
|
|
1626
1659
|
import { homedir } from "os";
|
|
1627
|
-
import
|
|
1660
|
+
import path3 from "path";
|
|
1628
1661
|
import { z as z4 } from "zod";
|
|
1629
1662
|
function getDefaultHeliosAgentMcpSessionPath() {
|
|
1630
|
-
return
|
|
1663
|
+
return path3.join(homedir(), ".helios-agent-mcp", "session.json");
|
|
1631
1664
|
}
|
|
1632
1665
|
var pendingAgentLoginSchema = z4.object({
|
|
1633
1666
|
status: z4.literal("pending"),
|
|
@@ -1748,7 +1781,7 @@ var FileAgentSessionStore = class {
|
|
|
1748
1781
|
}
|
|
1749
1782
|
}
|
|
1750
1783
|
async writeState(state) {
|
|
1751
|
-
await mkdir(
|
|
1784
|
+
await mkdir(path3.dirname(this.filePath), { recursive: true });
|
|
1752
1785
|
await writeFile(this.filePath, `${JSON.stringify(state, null, 2)}
|
|
1753
1786
|
`, { encoding: "utf8", mode: 384 });
|
|
1754
1787
|
await chmod(this.filePath, 384).catch(() => void 0);
|
|
@@ -2533,7 +2566,7 @@ function createHeliosAccountToolDefinitions(service) {
|
|
|
2533
2566
|
{
|
|
2534
2567
|
name: "helios_portfolio_get",
|
|
2535
2568
|
title: "Get Helios Portfolio",
|
|
2536
|
-
description: "Returns
|
|
2569
|
+
description: "Returns balances, open positions and their TP/SL (protectiveOrders, each with the id helios_positions_delete_tp_sl takes). Provider may be omitted if one is already pinned with helios_provider_set_active.",
|
|
2537
2570
|
inputSchema: providerSelectionInputSchema,
|
|
2538
2571
|
async execute(input) {
|
|
2539
2572
|
const result = portfolioToolOutputSchema.parse(await service.getPortfolio(input));
|
|
@@ -2629,7 +2662,7 @@ function createHeliosMarketToolDefinitions(service) {
|
|
|
2629
2662
|
{
|
|
2630
2663
|
name: "helios_market_get_snapshot",
|
|
2631
2664
|
title: "Get Helios Market Snapshot",
|
|
2632
|
-
description: "Returns a compact market snapshot for the selected, all, or explicitly requested symbols. By default: the top 50 coins by market cap with the main columns; name symbols to get other coins, pass fields for other columns.",
|
|
2665
|
+
description: "Returns a compact market snapshot for the selected, all, or explicitly requested symbols. By default: the top 50 coins by market cap with the main columns; name symbols to get other coins, pass fields for other columns. What each column means: helios_docs_get_document with path ai-agent-indicators/00_columns.txt (read it once).",
|
|
2633
2666
|
inputSchema: marketSnapshotInputSchema,
|
|
2634
2667
|
async execute(input) {
|
|
2635
2668
|
const result = marketSnapshotToolOutputSchema.parse(await service.getSnapshot(input));
|
|
@@ -2770,7 +2803,7 @@ function createHeliosTradingToolDefinitions(service) {
|
|
|
2770
2803
|
content: [
|
|
2771
2804
|
{
|
|
2772
2805
|
type: "text",
|
|
2773
|
-
text: result.status
|
|
2806
|
+
text: result.status !== "connected" ? result.message : result.closure.outcome === "no_position" ? `No open ${result.closure.symbol} position: nothing was closed and no order was sent.` : `Sent a market order closing the full ${result.closure.provider ?? input.provider ?? "hyperliquid"} ${result.closure.symbol} position. Check helios_positions_get_open to confirm.`
|
|
2774
2807
|
}
|
|
2775
2808
|
],
|
|
2776
2809
|
structuredContent: result.status === "connected" ? result : {
|
|
@@ -2804,7 +2837,7 @@ function createHeliosTradingToolDefinitions(service) {
|
|
|
2804
2837
|
{
|
|
2805
2838
|
name: "helios_positions_delete_tp_sl",
|
|
2806
2839
|
title: "Delete Helios TP/SL",
|
|
2807
|
-
description: "Deletes
|
|
2840
|
+
description: "Deletes a take-profit or stop-loss. orderId is the id from helios_portfolio_get protectiveOrders, or the Hyperliquid order id of the TP/SL. Provider may be omitted if one is already pinned with helios_provider_set_active.",
|
|
2808
2841
|
inputSchema: deleteTpSlInputSchema,
|
|
2809
2842
|
async execute(input) {
|
|
2810
2843
|
const result = deleteTpSlToolOutputSchema.parse(await service.deleteTpSl(input));
|
|
@@ -2897,7 +2930,7 @@ async function createHeliosAgentMcpServer(options) {
|
|
|
2897
2930
|
const { McpServer } = await import("@modelcontextprotocol/sdk/server/mcp.js");
|
|
2898
2931
|
const server = new McpServer({
|
|
2899
2932
|
name: "helios",
|
|
2900
|
-
version: "0.2.
|
|
2933
|
+
version: "0.2.9"
|
|
2901
2934
|
});
|
|
2902
2935
|
const sessionStore = options.sessionStore ?? new FileAgentSessionStore(options.sessionPath ?? getDefaultHeliosAgentMcpSessionPath());
|
|
2903
2936
|
const client = new HeliosAgentAuthClient({
|
|
@@ -2,6 +2,13 @@ var __defProp = Object.defineProperty;
|
|
|
2
2
|
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
|
3
3
|
var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
|
|
4
4
|
|
|
5
|
+
// ../../node_modules/.pnpm/tsup@8.5.1_jiti@2.6.1_postcss@8.5.6_tsx@4.20.6_typescript@5.9.3_yaml@2.8.2/node_modules/tsup/assets/esm_shims.js
|
|
6
|
+
import path from "path";
|
|
7
|
+
import { fileURLToPath } from "url";
|
|
8
|
+
var getFilename = () => fileURLToPath(import.meta.url);
|
|
9
|
+
var getDirname = () => path.dirname(getFilename());
|
|
10
|
+
var __dirname = /* @__PURE__ */ getDirname();
|
|
11
|
+
|
|
5
12
|
// ../agent/dist/index.mjs
|
|
6
13
|
import { z } from "zod";
|
|
7
14
|
import { z as z2 } from "zod";
|
|
@@ -116,19 +123,21 @@ var protectiveOrderKindSchema = z.enum(["STOP_LOSS", "TAKE_PROFIT"]);
|
|
|
116
123
|
var protectiveOrderSideSchema = z.enum(["BUY", "SELL"]);
|
|
117
124
|
var protectiveOrderPositionSideSchema = z.enum(["BOTH", "LONG", "SHORT"]);
|
|
118
125
|
var protectiveOrderSchema = z.object({
|
|
126
|
+
/** Helios's record id: what helios_positions_delete_tp_sl takes (the Hyperliquid order id works there too). */
|
|
119
127
|
id: z.string(),
|
|
120
|
-
|
|
121
|
-
|
|
128
|
+
/** The Hyperliquid order id (named after the retired Binance field). */
|
|
129
|
+
binanceOrderId: z.number().int().nonnegative().nullish(),
|
|
130
|
+
clientOrderId: z.string().nullish(),
|
|
122
131
|
symbol: z.string(),
|
|
123
132
|
side: protectiveOrderSideSchema,
|
|
124
|
-
positionSide: protectiveOrderPositionSideSchema,
|
|
133
|
+
positionSide: protectiveOrderPositionSideSchema.nullish().transform((value) => value ?? "BOTH"),
|
|
125
134
|
status: z.string(),
|
|
126
135
|
kind: protectiveOrderKindSchema,
|
|
127
|
-
groupId: z.string(),
|
|
128
|
-
stopPrice: z.string().
|
|
129
|
-
parentClientOrderId: z.string().
|
|
130
|
-
assetId: z.number().int().nonnegative().
|
|
131
|
-
createdAt: z.string().
|
|
136
|
+
groupId: z.string().nullish(),
|
|
137
|
+
stopPrice: z.union([z.string(), z.number()]).nullish().transform((value) => value == null ? value : String(value)),
|
|
138
|
+
parentClientOrderId: z.string().nullish(),
|
|
139
|
+
assetId: z.number().int().nonnegative().nullish(),
|
|
140
|
+
createdAt: z.string().nullish()
|
|
132
141
|
});
|
|
133
142
|
var hyperliquidPortfolioSnapshotSchema = z.object({
|
|
134
143
|
provider: z.literal("hyperliquid"),
|
|
@@ -137,6 +146,7 @@ var hyperliquidPortfolioSnapshotSchema = z.object({
|
|
|
137
146
|
totalMargin: z.number(),
|
|
138
147
|
unrealizedPnl: z.number(),
|
|
139
148
|
positions: z.array(openPositionSchema),
|
|
149
|
+
/** Unreadable entries are dropped (see readProtectiveOrders) rather than failing the read. */
|
|
140
150
|
protectiveOrders: z.array(protectiveOrderSchema)
|
|
141
151
|
});
|
|
142
152
|
var portfolioInputSchema = z.object({
|
|
@@ -331,6 +341,8 @@ var closePositionInputSchema = z.object({
|
|
|
331
341
|
});
|
|
332
342
|
var closePositionResultSchema = z.object({
|
|
333
343
|
status: z.literal("submitted"),
|
|
344
|
+
/** `no_position`: nothing was open on this coin, so no order was sent. Absent from older data-bridges. */
|
|
345
|
+
outcome: z.enum(["closed", "no_position"]).optional(),
|
|
334
346
|
provider: providerSchema.optional(),
|
|
335
347
|
symbol: z.string(),
|
|
336
348
|
mode: z.literal("FULL"),
|
|
@@ -442,10 +454,10 @@ var HeliosAgentAuthClient = class {
|
|
|
442
454
|
const parsed = agentRefreshInputSchema.parse({ refreshToken });
|
|
443
455
|
return this.post("/api/agents/auth/refresh", parsed, agentTokenResponseSchema);
|
|
444
456
|
}
|
|
445
|
-
async post(
|
|
457
|
+
async post(path4, body, schema) {
|
|
446
458
|
let response;
|
|
447
459
|
try {
|
|
448
|
-
response = await this.fetchImpl(`${this.baseUrl}${
|
|
460
|
+
response = await this.fetchImpl(`${this.baseUrl}${path4}`, {
|
|
449
461
|
method: "POST",
|
|
450
462
|
headers: {
|
|
451
463
|
Accept: "application/json",
|
|
@@ -521,7 +533,8 @@ var HeliosAgentDataBridgeClient = class {
|
|
|
521
533
|
}
|
|
522
534
|
return portfolioSnapshotSchema.parse({
|
|
523
535
|
...result,
|
|
524
|
-
provider: parsedInput.provider
|
|
536
|
+
provider: parsedInput.provider,
|
|
537
|
+
protectiveOrders: readProtectiveOrders(result.protectiveOrders)
|
|
525
538
|
});
|
|
526
539
|
}
|
|
527
540
|
async getLedgerFills(accessToken, input = {}) {
|
|
@@ -574,7 +587,7 @@ var HeliosAgentDataBridgeClient = class {
|
|
|
574
587
|
}
|
|
575
588
|
async closePosition(accessToken, input) {
|
|
576
589
|
const parsedInput = closePositionInputSchema.parse(input);
|
|
577
|
-
await this.request(
|
|
590
|
+
const payload = await this.request(
|
|
578
591
|
accessToken,
|
|
579
592
|
"positions.close",
|
|
580
593
|
{
|
|
@@ -585,8 +598,10 @@ var HeliosAgentDataBridgeClient = class {
|
|
|
585
598
|
},
|
|
586
599
|
"POST"
|
|
587
600
|
);
|
|
601
|
+
const outcome = this.tryUnwrapResult(payload)?.outcome;
|
|
588
602
|
return closePositionResultSchema.parse({
|
|
589
603
|
status: "submitted",
|
|
604
|
+
...outcome === "closed" || outcome === "no_position" ? { outcome } : {},
|
|
590
605
|
provider: parsedInput.provider,
|
|
591
606
|
symbol: parsedInput.symbol,
|
|
592
607
|
mode: "FULL",
|
|
@@ -684,6 +699,14 @@ var HeliosAgentDataBridgeClient = class {
|
|
|
684
699
|
});
|
|
685
700
|
}
|
|
686
701
|
}
|
|
702
|
+
/** The result of a mutation older data-bridges answer with nothing; null when there is none. */
|
|
703
|
+
tryUnwrapResult(payload) {
|
|
704
|
+
try {
|
|
705
|
+
return this.unwrapResult(payload) ?? null;
|
|
706
|
+
} catch {
|
|
707
|
+
return null;
|
|
708
|
+
}
|
|
709
|
+
}
|
|
687
710
|
unwrapResult(payload) {
|
|
688
711
|
if (!payload || typeof payload !== "object") {
|
|
689
712
|
throw new HeliosAgentApiError({
|
|
@@ -744,6 +767,13 @@ var HeliosAgentDataBridgeClient = class {
|
|
|
744
767
|
return envelope;
|
|
745
768
|
}
|
|
746
769
|
};
|
|
770
|
+
function readProtectiveOrders(value) {
|
|
771
|
+
if (!Array.isArray(value)) return [];
|
|
772
|
+
return value.flatMap((entry) => {
|
|
773
|
+
const parsed = protectiveOrderSchema.safeParse(entry);
|
|
774
|
+
return parsed.success ? [parsed.data] : [];
|
|
775
|
+
});
|
|
776
|
+
}
|
|
747
777
|
var DEFAULT_AGENT_REFRESH_WINDOW_MS = 60 * 1e3;
|
|
748
778
|
var agentConnectionStatusSchema = z3.enum([
|
|
749
779
|
"disconnected",
|
|
@@ -1181,8 +1211,8 @@ var HeliosAgentMcpAccountService = class {
|
|
|
1181
1211
|
};
|
|
1182
1212
|
|
|
1183
1213
|
// src/docs-service.ts
|
|
1184
|
-
import { readdirSync, readFileSync, statSync } from "fs";
|
|
1185
|
-
import
|
|
1214
|
+
import { existsSync, readdirSync, readFileSync, statSync } from "fs";
|
|
1215
|
+
import path2 from "path";
|
|
1186
1216
|
var HeliosAgentMcpDocsService = class {
|
|
1187
1217
|
constructor(options) {
|
|
1188
1218
|
__publicField(this, "docsRoot");
|
|
@@ -1197,9 +1227,12 @@ var HeliosAgentMcpDocsService = class {
|
|
|
1197
1227
|
}
|
|
1198
1228
|
async getDocument(input) {
|
|
1199
1229
|
const documentPath = resolveDocumentPath(this.docsRoot, input.path);
|
|
1230
|
+
if (!existsSync(documentPath) || !statSync(documentPath).isFile()) {
|
|
1231
|
+
throw new Error(`No document "${input.path}". helios_docs_get_index lists the documents.`);
|
|
1232
|
+
}
|
|
1200
1233
|
const body = readFileSync(documentPath, "utf8");
|
|
1201
1234
|
const stats = statSync(documentPath);
|
|
1202
|
-
const relativePath = toPosixPath(
|
|
1235
|
+
const relativePath = toPosixPath(path2.relative(this.docsRoot, documentPath));
|
|
1203
1236
|
return {
|
|
1204
1237
|
path: relativePath,
|
|
1205
1238
|
section: getDocumentSection(relativePath),
|
|
@@ -1211,7 +1244,7 @@ var HeliosAgentMcpDocsService = class {
|
|
|
1211
1244
|
readDocumentMetadata(documentPath) {
|
|
1212
1245
|
const body = readFileSync(documentPath, "utf8");
|
|
1213
1246
|
const stats = statSync(documentPath);
|
|
1214
|
-
const relativePath = toPosixPath(
|
|
1247
|
+
const relativePath = toPosixPath(path2.relative(this.docsRoot, documentPath));
|
|
1215
1248
|
return {
|
|
1216
1249
|
path: relativePath,
|
|
1217
1250
|
section: getDocumentSection(relativePath),
|
|
@@ -1221,7 +1254,7 @@ var HeliosAgentMcpDocsService = class {
|
|
|
1221
1254
|
}
|
|
1222
1255
|
};
|
|
1223
1256
|
function getDefaultHeliosAgentMcpDocsRoot() {
|
|
1224
|
-
return
|
|
1257
|
+
return path2.resolve(__dirname, "..", "docs");
|
|
1225
1258
|
}
|
|
1226
1259
|
function listDocumentPaths(root) {
|
|
1227
1260
|
return walk(root).filter((filePath) => filePath.endsWith(".txt")).sort((left, right) => left.localeCompare(right));
|
|
@@ -1230,7 +1263,7 @@ function walk(currentPath) {
|
|
|
1230
1263
|
const entries = readdirSync(currentPath, { withFileTypes: true });
|
|
1231
1264
|
const files = [];
|
|
1232
1265
|
for (const entry of entries) {
|
|
1233
|
-
const nextPath =
|
|
1266
|
+
const nextPath = path2.join(currentPath, entry.name);
|
|
1234
1267
|
if (entry.isDirectory()) {
|
|
1235
1268
|
files.push(...walk(nextPath));
|
|
1236
1269
|
continue;
|
|
@@ -1243,12 +1276,12 @@ function walk(currentPath) {
|
|
|
1243
1276
|
}
|
|
1244
1277
|
function resolveDocumentPath(root, relativeDocumentPath) {
|
|
1245
1278
|
const normalizedPath = relativeDocumentPath.replace(/\\/g, "/").replace(/^\/+/, "");
|
|
1246
|
-
const resolvedPath =
|
|
1247
|
-
const relativePath =
|
|
1279
|
+
const resolvedPath = path2.resolve(root, normalizedPath);
|
|
1280
|
+
const relativePath = path2.relative(root, resolvedPath);
|
|
1248
1281
|
if (!normalizedPath) {
|
|
1249
1282
|
throw new Error("Document path is required.");
|
|
1250
1283
|
}
|
|
1251
|
-
if (
|
|
1284
|
+
if (path2.isAbsolute(normalizedPath) || relativePath.startsWith("..") || path2.isAbsolute(relativePath)) {
|
|
1252
1285
|
throw new Error(`Document path "${relativeDocumentPath}" is outside the docs root.`);
|
|
1253
1286
|
}
|
|
1254
1287
|
if (!resolvedPath.endsWith(".txt")) {
|
|
@@ -1268,13 +1301,13 @@ function extractDocumentTitle(body, relativePath) {
|
|
|
1268
1301
|
}
|
|
1269
1302
|
return trimmed;
|
|
1270
1303
|
}
|
|
1271
|
-
return
|
|
1304
|
+
return path2.basename(relativePath, ".txt");
|
|
1272
1305
|
}
|
|
1273
1306
|
function getDocumentSection(relativePath) {
|
|
1274
1307
|
return relativePath.split("/")[0] ?? "docs";
|
|
1275
1308
|
}
|
|
1276
1309
|
function toPosixPath(value) {
|
|
1277
|
-
return value.split(
|
|
1310
|
+
return value.split(path2.sep).join("/");
|
|
1278
1311
|
}
|
|
1279
1312
|
|
|
1280
1313
|
// src/ledger-service.ts
|
|
@@ -1624,10 +1657,10 @@ var HeliosAgentMcpProviderService = class {
|
|
|
1624
1657
|
// src/session-store.ts
|
|
1625
1658
|
import { chmod, mkdir, readFile, rm, writeFile } from "fs/promises";
|
|
1626
1659
|
import { homedir } from "os";
|
|
1627
|
-
import
|
|
1660
|
+
import path3 from "path";
|
|
1628
1661
|
import { z as z4 } from "zod";
|
|
1629
1662
|
function getDefaultHeliosAgentMcpSessionPath() {
|
|
1630
|
-
return
|
|
1663
|
+
return path3.join(homedir(), ".helios-agent-mcp", "session.json");
|
|
1631
1664
|
}
|
|
1632
1665
|
var pendingAgentLoginSchema = z4.object({
|
|
1633
1666
|
status: z4.literal("pending"),
|
|
@@ -1748,7 +1781,7 @@ var FileAgentSessionStore = class {
|
|
|
1748
1781
|
}
|
|
1749
1782
|
}
|
|
1750
1783
|
async writeState(state) {
|
|
1751
|
-
await mkdir(
|
|
1784
|
+
await mkdir(path3.dirname(this.filePath), { recursive: true });
|
|
1752
1785
|
await writeFile(this.filePath, `${JSON.stringify(state, null, 2)}
|
|
1753
1786
|
`, { encoding: "utf8", mode: 384 });
|
|
1754
1787
|
await chmod(this.filePath, 384).catch(() => void 0);
|
|
@@ -2533,7 +2566,7 @@ function createHeliosAccountToolDefinitions(service) {
|
|
|
2533
2566
|
{
|
|
2534
2567
|
name: "helios_portfolio_get",
|
|
2535
2568
|
title: "Get Helios Portfolio",
|
|
2536
|
-
description: "Returns
|
|
2569
|
+
description: "Returns balances, open positions and their TP/SL (protectiveOrders, each with the id helios_positions_delete_tp_sl takes). Provider may be omitted if one is already pinned with helios_provider_set_active.",
|
|
2537
2570
|
inputSchema: providerSelectionInputSchema,
|
|
2538
2571
|
async execute(input) {
|
|
2539
2572
|
const result = portfolioToolOutputSchema.parse(await service.getPortfolio(input));
|
|
@@ -2770,7 +2803,7 @@ function createHeliosTradingToolDefinitions(service) {
|
|
|
2770
2803
|
content: [
|
|
2771
2804
|
{
|
|
2772
2805
|
type: "text",
|
|
2773
|
-
text: result.status
|
|
2806
|
+
text: result.status !== "connected" ? result.message : result.closure.outcome === "no_position" ? `No open ${result.closure.symbol} position: nothing was closed and no order was sent.` : `Sent a market order closing the full ${result.closure.provider ?? input.provider ?? "hyperliquid"} ${result.closure.symbol} position. Check helios_positions_get_open to confirm.`
|
|
2774
2807
|
}
|
|
2775
2808
|
],
|
|
2776
2809
|
structuredContent: result.status === "connected" ? result : {
|
|
@@ -2804,7 +2837,7 @@ function createHeliosTradingToolDefinitions(service) {
|
|
|
2804
2837
|
{
|
|
2805
2838
|
name: "helios_positions_delete_tp_sl",
|
|
2806
2839
|
title: "Delete Helios TP/SL",
|
|
2807
|
-
description: "Deletes
|
|
2840
|
+
description: "Deletes a take-profit or stop-loss. orderId is the id from helios_portfolio_get protectiveOrders, or the Hyperliquid order id of the TP/SL. Provider may be omitted if one is already pinned with helios_provider_set_active.",
|
|
2808
2841
|
inputSchema: deleteTpSlInputSchema,
|
|
2809
2842
|
async execute(input) {
|
|
2810
2843
|
const result = deleteTpSlToolOutputSchema.parse(await service.deleteTpSl(input));
|