@moly-mcp/lido 1.0.2 → 1.0.3

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/bin.js CHANGED
@@ -206,7 +206,7 @@ async function main() {
206
206
  case "setup": {
207
207
  const { cfg, terminalMode } = await runWizard();
208
208
  if (terminalMode) {
209
- const { startChatSession } = await import("./session-55BKKXQV.js");
209
+ const { startChatSession } = await import("./session-ZXWCIUKX.js");
210
210
  await startChatSession(cfg);
211
211
  } else {
212
212
  await startServer();
@@ -251,7 +251,7 @@ async function main() {
251
251
  if (!configExists()) {
252
252
  const { cfg, terminalMode } = await runWizard();
253
253
  if (terminalMode) {
254
- const { startChatSession } = await import("./session-55BKKXQV.js");
254
+ const { startChatSession } = await import("./session-ZXWCIUKX.js");
255
255
  await startChatSession(cfg);
256
256
  } else {
257
257
  await startServer();
@@ -20,6 +20,8 @@ import "./chunk-PIFEXJ56.js";
20
20
 
21
21
  // src/chat/session.ts
22
22
  import * as readline from "readline";
23
+ import * as fs from "fs";
24
+ import * as path from "path";
23
25
 
24
26
  // src/chat/providers.ts
25
27
  async function callAnthropic(apiKey, model, messages, tools) {
@@ -394,50 +396,86 @@ async function executeTool(name, args) {
394
396
  }
395
397
 
396
398
  // src/chat/session.ts
397
- var RESET = "\x1B[0m";
398
- var BOLD = "\x1B[1m";
399
- var DIM = "\x1B[2m";
400
- var CYAN = "\x1B[36m";
401
- var GREEN = "\x1B[32m";
402
- var YELLOW = "\x1B[33m";
403
- var BLUE = "\x1B[34m";
404
- var RED = "\x1B[31m";
405
- function print(text) {
399
+ var R = "\x1B[0m";
400
+ var B = "\x1B[1m";
401
+ var D = "\x1B[2m";
402
+ var CY = "\x1B[36m";
403
+ var GR = "\x1B[32m";
404
+ var YE = "\x1B[33m";
405
+ var BL = "\x1B[34m";
406
+ var RE = "\x1B[31m";
407
+ var MA = "\x1B[35m";
408
+ var LOGO = `
409
+ ${CY}${B} \u2588\u2588\u2588\u2557 \u2588\u2588\u2588\u2557 \u2588\u2588\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2557 \u2588\u2588\u2557 \u2588\u2588\u2557${R}
410
+ ${CY}${B} \u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2588\u2588\u2551\u2588\u2588\u2554\u2550\u2550\u2550\u2588\u2588\u2557\u2588\u2588\u2551 \u255A\u2588\u2588\u2557 \u2588\u2588\u2554\u255D${R}
411
+ ${CY}${B} \u2588\u2588\u2554\u2588\u2588\u2588\u2588\u2554\u2588\u2588\u2551\u2588\u2588\u2551 \u2588\u2588\u2551\u2588\u2588\u2551 \u255A\u2588\u2588\u2588\u2588\u2554\u255D ${R}
412
+ ${CY}${B} \u2588\u2588\u2551\u255A\u2588\u2588\u2554\u255D\u2588\u2588\u2551\u2588\u2588\u2551 \u2588\u2588\u2551\u2588\u2588\u2551 \u255A\u2588\u2588\u2554\u255D ${R}
413
+ ${CY}${B} \u2588\u2588\u2551 \u255A\u2550\u255D \u2588\u2588\u2551\u255A\u2588\u2588\u2588\u2588\u2588\u2588\u2554\u255D\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2557\u2588\u2588\u2551 ${R}
414
+ ${CY}${B} \u255A\u2550\u255D \u255A\u2550\u255D \u255A\u2550\u2550\u2550\u2550\u2550\u255D \u255A\u2550\u2550\u2550\u2550\u2550\u2550\u255D\u255A\u2550\u255D ${R}
415
+ ${D} powered by Lido \u2B21${R}
416
+ `;
417
+ function ln(text = "") {
406
418
  process.stdout.write(text + "\n");
407
419
  }
420
+ function saveTrade(toolName, args, result) {
421
+ try {
422
+ const tradesDir = path.join(process.cwd(), "trades");
423
+ if (!fs.existsSync(tradesDir)) fs.mkdirSync(tradesDir, { recursive: true });
424
+ const today = (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
425
+ const file = path.join(tradesDir, `${today}.jsonl`);
426
+ const record = JSON.stringify({
427
+ ts: (/* @__PURE__ */ new Date()).toISOString(),
428
+ tool: toolName,
429
+ args,
430
+ result: (() => {
431
+ try {
432
+ return JSON.parse(result);
433
+ } catch {
434
+ return result;
435
+ }
436
+ })()
437
+ });
438
+ fs.appendFileSync(file, record + "\n");
439
+ } catch {
440
+ }
441
+ }
408
442
  function printBanner(cfg) {
409
- const modeColor = cfg.mode === "simulation" ? YELLOW : RED;
410
- const modeLabel = cfg.mode === "simulation" ? "\u{1F7E1} SIMULATION" : "\u{1F534} LIVE";
411
- print("");
412
- print(`${BOLD}${CYAN} \u2B21 Moly Terminal${RESET} \u2014 Lido on ${cfg.network}`);
413
- print(`${DIM} ${modeColor}${modeLabel}${RESET}${DIM} \xB7 ${cfg.ai?.model ?? ""} \xB7 type "exit" to quit${RESET}`);
414
- print(`${DIM}${"\u2500".repeat(60)}${RESET}`);
415
- print("");
443
+ const modeLabel = cfg.mode === "simulation" ? `${YE}\u25CF SIMULATION${R}` : `${RE}\u25CF LIVE${R}`;
444
+ ln(LOGO);
445
+ ln(` ${modeLabel} ${D}${cfg.network} \xB7 ${cfg.ai?.model ?? ""}${R}`);
446
+ ln(` ${D}type "exit" to quit${R}`);
447
+ ln(` ${D}${"\u2500".repeat(48)}${R}`);
448
+ ln();
416
449
  }
450
+ var WRITE_TOOLS = /* @__PURE__ */ new Set([
451
+ "stake_eth",
452
+ "request_withdrawal",
453
+ "claim_withdrawals",
454
+ "wrap_steth",
455
+ "unwrap_wsteth",
456
+ "cast_vote"
457
+ ]);
417
458
  async function startChatSession(cfg) {
418
459
  if (!cfg.ai) {
419
- print(`${RED}No AI provider configured. Run: moly setup${RESET}`);
460
+ ln(`${RE}No AI provider configured. Run: moly setup${R}`);
420
461
  process.exit(1);
421
462
  }
422
463
  const { provider, apiKey, model } = cfg.ai;
423
464
  const messages = [
424
465
  {
425
466
  role: "user",
426
- content: `You are Moly, an AI assistant for interacting with Lido Finance on ${cfg.network}. Current mode: ${cfg.mode} (${cfg.mode === "simulation" ? "dry-run, nothing is broadcast" : "LIVE \u2014 real transactions"}). Help the user stake ETH, manage withdrawals, wrap/unwrap tokens, and participate in governance. Always confirm before executing live transactions. Be concise.`
467
+ content: `You are Moly, an AI assistant for Lido Finance on ${cfg.network}. Mode: ${cfg.mode} (${cfg.mode === "simulation" ? "dry-run, nothing broadcast" : "LIVE \u2014 real on-chain transactions"}). Help stake ETH, manage withdrawals, wrap/unwrap tokens, governance. Be concise. For live transactions always confirm with the user first.`
427
468
  },
428
469
  {
429
470
  role: "assistant",
430
- content: `Got it. I'm ready to help you interact with Lido on ${cfg.network} in ${cfg.mode} mode. What would you like to do?`
471
+ content: `Ready. I'm Moly on ${cfg.network} in ${cfg.mode} mode. What would you like to do?`
431
472
  }
432
473
  ];
433
474
  printBanner(cfg);
434
- const rl = readline.createInterface({
435
- input: process.stdin,
436
- output: process.stdout,
437
- terminal: true
438
- });
439
- const prompt = () => new Promise((resolve) => {
440
- rl.question(`${BOLD}${BLUE}you${RESET} \u203A `, resolve);
475
+ const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
476
+ const prompt = () => new Promise((resolve, reject) => {
477
+ rl.question(`${B}${BL}you${R} \u203A `, resolve);
478
+ rl.once("close", () => reject(new Error("closed")));
441
479
  });
442
480
  while (true) {
443
481
  let input;
@@ -447,43 +485,45 @@ async function startChatSession(cfg) {
447
485
  break;
448
486
  }
449
487
  if (!input) continue;
450
- if (input.toLowerCase() === "exit" || input.toLowerCase() === "quit") {
451
- print(`${DIM}Goodbye.${RESET}`);
488
+ if (input === "exit" || input === "quit") {
489
+ ln(`${D}Goodbye.${R}`);
452
490
  rl.close();
453
491
  process.exit(0);
454
492
  }
455
493
  messages.push({ role: "user", content: input });
456
494
  try {
457
495
  while (true) {
458
- process.stdout.write(`${DIM}thinking...${RESET}\r`);
496
+ ln(`${D} \u2699 thinking...${R}`);
459
497
  const response = await callAi(provider, apiKey, model, messages, TOOL_DEFS);
460
- process.stdout.write(" ".repeat(20) + "\r");
461
498
  messages.push(response.rawAssistantMessage);
462
499
  if (response.toolCalls.length > 0) {
463
500
  const toolResults = [];
464
501
  for (const tc of response.toolCalls) {
465
- print(`${DIM} \u2699 ${tc.name}(${JSON.stringify(tc.args)})${RESET}`);
502
+ ln(`${D} \u21B3 ${MA}${tc.name}${R}${D} ${JSON.stringify(tc.args)}${R}`);
466
503
  const result = await executeTool(tc.name, tc.args);
467
- print(`${DIM} \u21B3 ${result.slice(0, 200)}${result.length > 200 ? "\u2026" : ""}${RESET}`);
504
+ ln(`${D} ${result.slice(0, 300)}${result.length > 300 ? "\u2026" : ""}${R}`);
505
+ if (WRITE_TOOLS.has(tc.name)) {
506
+ saveTrade(tc.name, tc.args, result);
507
+ }
468
508
  toolResults.push(makeToolResultMessage(provider, tc.id, tc.name, result));
469
509
  }
470
510
  messages.push(...toolResults);
471
511
  if (response.text) {
472
- print(`
473
- ${BOLD}${GREEN}moly${RESET} \u203A ${response.text}
474
- `);
512
+ ln();
513
+ ln(`${B}${GR}moly${R} \u203A ${response.text}`);
514
+ ln();
475
515
  }
476
516
  continue;
477
517
  }
478
518
  if (response.text) {
479
- print(`
480
- ${BOLD}${GREEN}moly${RESET} \u203A ${response.text}
481
- `);
519
+ ln();
520
+ ln(`${B}${GR}moly${R} \u203A ${response.text}`);
521
+ ln();
482
522
  }
483
523
  break;
484
524
  }
485
525
  } catch (err) {
486
- print(`${RED}Error: ${err.message}${RESET}`);
526
+ ln(`${RE}Error: ${err.message}${R}`);
487
527
  messages.pop();
488
528
  }
489
529
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@moly-mcp/lido",
3
- "version": "1.0.2",
3
+ "version": "1.0.3",
4
4
  "description": "Lido MCP Server — stake, unstake, wrap, govern. Works with Claude Desktop, Cursor, Windsurf, and any MCP client.",
5
5
  "license": "MIT",
6
6
  "type": "module",