@vultisig/cli 4.0.0 → 4.0.1

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/CHANGELOG.md CHANGED
@@ -1,5 +1,14 @@
1
1
  # @vultisig/cli
2
2
 
3
+ ## 4.0.1
4
+
5
+ ### Patch Changes
6
+
7
+ - [#1561](https://github.com/vultisig/vultisig-sdk/pull/1561) [`38be8ef`](https://github.com/vultisig/vultisig-sdk/commit/38be8eff97b061d241c7ac1c1616b48115fbb974) Thanks [@NeOMakinG](https://github.com/NeOMakinG)! - Render `yield_opportunities` and `polymarket_markets` agent surfaces as prose instead of leaking raw `{"surface":...}` JSON into the terminal. The CLI only advertised `balance_summary`/`turn_outcome` in `supported_surfaces`, so any other surface fell back to the backend's legacy verbatim-echo path. Adds parsers, prose renderers, and a legacy-echo fallback for both surfaces, mirroring the existing `balance_summary` handling, and wires them through the TUI, pipe mode, and `agent ask`.
8
+
9
+ - Updated dependencies [[`3767033`](https://github.com/vultisig/vultisig-sdk/commit/3767033f51804f3fff5088098c767280577bd4a4), [`68df301`](https://github.com/vultisig/vultisig-sdk/commit/68df301134b8000187a11cf92b9427e8200d4623)]:
10
+ - @vultisig/sdk@4.0.1
11
+
3
12
  ## 4.0.0
4
13
 
5
14
  ### Minor Changes
package/dist/index.js CHANGED
@@ -10129,6 +10129,8 @@ var AskInterface = class {
10129
10129
  toolCalls = [];
10130
10130
  transactions = [];
10131
10131
  cards = [];
10132
+ yieldCards = [];
10133
+ polymarketCards = [];
10132
10134
  warnings = [];
10133
10135
  outcome;
10134
10136
  error;
@@ -10181,6 +10183,12 @@ var AskInterface = class {
10181
10183
  onBalanceSummary: (card) => {
10182
10184
  this.cards.push(card);
10183
10185
  },
10186
+ onYieldOpportunities: (card) => {
10187
+ this.yieldCards.push(card);
10188
+ },
10189
+ onPolymarketMarkets: (card) => {
10190
+ this.polymarketCards.push(card);
10191
+ },
10184
10192
  onTurnOutcome: (outcome) => {
10185
10193
  this.outcome = outcome;
10186
10194
  },
@@ -10239,6 +10247,8 @@ var AskInterface = class {
10239
10247
  this.toolCalls = [];
10240
10248
  this.transactions = [];
10241
10249
  this.cards = [];
10250
+ this.yieldCards = [];
10251
+ this.polymarketCards = [];
10242
10252
  this.warnings = [];
10243
10253
  this.outcome = void 0;
10244
10254
  this.error = void 0;
@@ -10262,6 +10272,8 @@ var AskInterface = class {
10262
10272
  toolCalls: this.toolCalls,
10263
10273
  transactions: this.transactions,
10264
10274
  cards: this.cards,
10275
+ yieldCards: this.yieldCards,
10276
+ polymarketCards: this.polymarketCards,
10265
10277
  warnings: this.warnings,
10266
10278
  error: this.error,
10267
10279
  ...this.outcome ? { outcome: this.outcome } : {}
@@ -10326,7 +10338,12 @@ async function authenticateVault(client, vault, password, maxAttempts = 3) {
10326
10338
 
10327
10339
  // src/agent/cards.ts
10328
10340
  import chalk8 from "chalk";
10329
- var CLI_SUPPORTED_SURFACES = ["balance_summary", "turn_outcome"];
10341
+ var CLI_SUPPORTED_SURFACES = [
10342
+ "balance_summary",
10343
+ "turn_outcome",
10344
+ "yield_opportunities",
10345
+ "polymarket_markets"
10346
+ ];
10330
10347
  function parseTurnOutcome(raw) {
10331
10348
  if (!raw || typeof raw !== "object") return null;
10332
10349
  const kind = raw.kind;
@@ -10474,6 +10491,142 @@ function renderBalanceSummaryCard(card) {
10474
10491
  }
10475
10492
  return lines.join("\n");
10476
10493
  }
10494
+ function parseYieldOpportunity(v) {
10495
+ if (!v || typeof v !== "object") return null;
10496
+ const o = v;
10497
+ const id = asString(o.id);
10498
+ const symbol = asString(o.token) || asString(o.symbol);
10499
+ const chain = asString(o.network) || asString(o.chain);
10500
+ if (!symbol) return null;
10501
+ const opportunity = { id, chain, symbol };
10502
+ const apy = o.apy;
10503
+ if (typeof apy === "number" && Number.isFinite(apy)) {
10504
+ opportunity.apy = `${apy.toFixed(2)}%`;
10505
+ } else if (typeof apy === "string" && apy) {
10506
+ opportunity.apy = stripControlChars(apy);
10507
+ }
10508
+ const provider = asString(o.provider);
10509
+ if (provider) opportunity.provider = provider;
10510
+ const type = asString(o.type);
10511
+ if (type) opportunity.type = type;
10512
+ return opportunity;
10513
+ }
10514
+ function parseYieldOpportunitiesEnvelope(value) {
10515
+ if (!value || typeof value !== "object") return null;
10516
+ const o = value;
10517
+ if (o.surface !== "yield_opportunities") return null;
10518
+ const raw = Array.isArray(o.opportunities) ? o.opportunities : Array.isArray(o.data) ? o.data : [];
10519
+ const opportunities = raw.map(parseYieldOpportunity).filter((y) => y !== null);
10520
+ if (opportunities.length === 0) return null;
10521
+ const card = { surface: "yield_opportunities", opportunities };
10522
+ const title = asString(o.title);
10523
+ if (title) card.title = title;
10524
+ return card;
10525
+ }
10526
+ function renderYieldOpportunitiesCard(card) {
10527
+ const lines = [chalk8.bold(` ${card.title || "Yield opportunities"}`)];
10528
+ for (const opp of card.opportunities) {
10529
+ const label = opp.symbol || opp.id || "opportunity";
10530
+ const apyCol = opp.apy ? chalk8.green(` ${opp.apy} APY`) : "";
10531
+ const chainCol = opp.chain ? chalk8.gray(` (${opp.chain})`) : "";
10532
+ const providerCol = opp.provider ? chalk8.gray(` via ${opp.provider}`) : "";
10533
+ lines.push(` ${chalk8.bold(label)}${apyCol}${chainCol}${providerCol}`);
10534
+ }
10535
+ return lines.join("\n");
10536
+ }
10537
+ function extractYieldOpportunitiesFromText(content) {
10538
+ return extractSurfaceFromText(content, "yield_opportunities", parseYieldOpportunitiesEnvelope);
10539
+ }
10540
+ function formatProbability(v) {
10541
+ if (typeof v !== "number" || !Number.isFinite(v)) return void 0;
10542
+ if (v <= 0 || v >= 1) return void 0;
10543
+ return `${Math.round(v * 100)}%`;
10544
+ }
10545
+ function buildPolymarketOutcomes(o) {
10546
+ const yesPrice = formatProbability(o.yesPrice);
10547
+ const noPrice = formatProbability(o.noPrice);
10548
+ const topOutcome = asString(o.topOutcome);
10549
+ if (topOutcome) {
10550
+ const outcome = { name: topOutcome };
10551
+ if (yesPrice) outcome.price = yesPrice;
10552
+ return [outcome];
10553
+ }
10554
+ const outcomes = [];
10555
+ if (yesPrice) outcomes.push({ name: "YES", price: yesPrice });
10556
+ if (noPrice) outcomes.push({ name: "NO", price: noPrice });
10557
+ return outcomes;
10558
+ }
10559
+ function parsePolymarketMarket(v) {
10560
+ if (!v || typeof v !== "object") return null;
10561
+ const o = v;
10562
+ const question = asString(o.question) || asString(o.title);
10563
+ if (!question) return null;
10564
+ const id = asString(o.id) || asString(o.slug);
10565
+ const outcomes = buildPolymarketOutcomes(o);
10566
+ const market = { id, question, outcomes };
10567
+ const volume24h = o.volume24h;
10568
+ if (typeof volume24h === "number" && Number.isFinite(volume24h)) {
10569
+ market.volume = formatUsd(volume24h);
10570
+ } else if (typeof volume24h === "string" && volume24h) {
10571
+ market.volume = stripControlChars(volume24h);
10572
+ }
10573
+ const endDate = asString(o.endDate) || asString(o.end_date);
10574
+ if (endDate) market.endDate = endDate;
10575
+ return market;
10576
+ }
10577
+ function parsePolymarketMarketsEnvelope(value) {
10578
+ if (!value || typeof value !== "object") return null;
10579
+ const o = value;
10580
+ if (o.surface !== "polymarket_markets") return null;
10581
+ const raw = Array.isArray(o.markets) ? o.markets : Array.isArray(o.data) ? o.data : [];
10582
+ const markets = raw.map(parsePolymarketMarket).filter((m) => m !== null);
10583
+ if (markets.length === 0) return null;
10584
+ const card = { surface: "polymarket_markets", markets };
10585
+ const title = asString(o.title);
10586
+ if (title) card.title = title;
10587
+ const subtitle = asString(o.subtitle);
10588
+ if (subtitle) card.subtitle = subtitle;
10589
+ return card;
10590
+ }
10591
+ function renderPolymarketMarketsCard(card) {
10592
+ const lines = [chalk8.bold(` ${card.title || "Polymarket markets"}`)];
10593
+ if (card.subtitle) lines.push(chalk8.gray(` ${card.subtitle}`));
10594
+ for (const market of card.markets) {
10595
+ const metaBits = [market.volume ? `${market.volume} vol` : "", market.endDate ? `ends ${market.endDate}` : ""].filter(Boolean).join(", ");
10596
+ lines.push(` ${chalk8.bold(market.question)}${metaBits ? chalk8.gray(` (${metaBits})`) : ""}`);
10597
+ for (const outcome of market.outcomes) {
10598
+ const priceCol = outcome.price ? chalk8.gray(` ${outcome.price}`) : "";
10599
+ lines.push(` ${outcome.name}${priceCol}`);
10600
+ }
10601
+ }
10602
+ return lines.join("\n");
10603
+ }
10604
+ function extractPolymarketMarketsFromText(content) {
10605
+ return extractSurfaceFromText(content, "polymarket_markets", parsePolymarketMarketsEnvelope);
10606
+ }
10607
+ function extractSurfaceFromText(content, surfaceKey, parser) {
10608
+ if (!content || !content.includes(surfaceKey)) return null;
10609
+ if (content.length > 2e5) return null;
10610
+ for (let i = content.indexOf("{"); i !== -1; i = content.indexOf("{", i + 1)) {
10611
+ const end = matchBrace(content, i);
10612
+ if (end === -1) break;
10613
+ const blob = content.slice(i, end + 1);
10614
+ if (!blob.includes(surfaceKey)) continue;
10615
+ let parsed;
10616
+ try {
10617
+ parsed = JSON.parse(blob);
10618
+ } catch {
10619
+ continue;
10620
+ }
10621
+ const card = parser(parsed);
10622
+ if (!card) continue;
10623
+ const before = content.slice(0, i).replace(/```(?:json)?\s*$/i, "");
10624
+ const after = content.slice(end + 1).replace(/^\s*```/, "");
10625
+ const remainingText = (before + after).trim();
10626
+ return { card, remainingText };
10627
+ }
10628
+ return null;
10629
+ }
10477
10630
 
10478
10631
  // src/agent/client.ts
10479
10632
  import { randomUUID } from "node:crypto";
@@ -12833,6 +12986,16 @@ var AgentClient = class {
12833
12986
  callbacks.onBalanceSummary?.(card);
12834
12987
  break;
12835
12988
  }
12989
+ case "yield_opportunities": {
12990
+ const card = v1Data ?? parsed.data ?? parsed;
12991
+ callbacks.onYieldOpportunities?.(card);
12992
+ break;
12993
+ }
12994
+ case "polymarket_markets": {
12995
+ const card = v1Data ?? parsed.data ?? parsed;
12996
+ callbacks.onPolymarketMarkets?.(card);
12997
+ break;
12998
+ }
12836
12999
  case "turn_outcome": {
12837
13000
  const outcome = parseTurnOutcome(v1Data ?? parsed.data ?? parsed);
12838
13001
  if (outcome) callbacks.onTurnOutcome?.(outcome);
@@ -13029,6 +13192,10 @@ var AgentClient = class {
13029
13192
  return "suggestions";
13030
13193
  case "data-balance_summary":
13031
13194
  return "balance_summary";
13195
+ case "data-yield_opportunities":
13196
+ return "yield_opportunities";
13197
+ case "data-polymarket_markets":
13198
+ return "polymarket_markets";
13032
13199
  case "data-turn_outcome":
13033
13200
  return "turn_outcome";
13034
13201
  case "data-message":
@@ -13451,6 +13618,12 @@ var PipeInterface = class {
13451
13618
  onBalanceSummary: (card) => {
13452
13619
  this.emit({ type: "balance_summary", card });
13453
13620
  },
13621
+ onYieldOpportunities: (card) => {
13622
+ this.emit({ type: "yield_opportunities", card });
13623
+ },
13624
+ onPolymarketMarkets: (card) => {
13625
+ this.emit({ type: "polymarket_markets", card });
13626
+ },
13454
13627
  onSuggestions: (suggestions) => {
13455
13628
  this.emit({ type: "suggestions", suggestions });
13456
13629
  },
@@ -14067,6 +14240,8 @@ var AgentSession = class {
14067
14240
  }
14068
14241
  let toolOutputCandidate = null;
14069
14242
  let balanceCardRendered = false;
14243
+ let yieldCardRendered = false;
14244
+ let polymarketCardRendered = false;
14070
14245
  const pendingDispatches = [];
14071
14246
  let dispatchChain = Promise.resolve();
14072
14247
  const callbacks = {
@@ -14104,6 +14279,20 @@ var AgentSession = class {
14104
14279
  ui.onBalanceSummary?.(card);
14105
14280
  }
14106
14281
  },
14282
+ onYieldOpportunities: (raw) => {
14283
+ const card = parseYieldOpportunitiesEnvelope(raw);
14284
+ if (card) {
14285
+ yieldCardRendered = true;
14286
+ ui.onYieldOpportunities?.(card);
14287
+ }
14288
+ },
14289
+ onPolymarketMarkets: (raw) => {
14290
+ const card = parsePolymarketMarketsEnvelope(raw);
14291
+ if (card) {
14292
+ polymarketCardRendered = true;
14293
+ ui.onPolymarketMarkets?.(card);
14294
+ }
14295
+ },
14107
14296
  onTurnOutcome: (outcome) => {
14108
14297
  ui.onTurnOutcome?.(outcome);
14109
14298
  },
@@ -14145,6 +14334,8 @@ var AgentSession = class {
14145
14334
  let displayText = stripLeakedToolCallTags(responseText);
14146
14335
  if (displayText) {
14147
14336
  displayText = this.renderEchoedBalanceCard(displayText, balanceCardRendered, ui);
14337
+ displayText = this.renderEchoedYieldOpportunitiesCard(displayText, yieldCardRendered, ui);
14338
+ displayText = this.renderEchoedPolymarketMarketsCard(displayText, polymarketCardRendered, ui);
14148
14339
  }
14149
14340
  if (displayText) {
14150
14341
  ui.onAssistantMessage(displayText);
@@ -14410,6 +14601,32 @@ var AgentSession = class {
14410
14601
  }
14411
14602
  return extracted.remainingText;
14412
14603
  }
14604
+ /**
14605
+ * Legacy-path fallback for echoed yield_opportunities cards (rj3p). Mirrors
14606
+ * {@link renderEchoedBalanceCard} — strips a verbatim-echoed envelope from
14607
+ * the displayed text and renders it, unless the typed SSE part already fired.
14608
+ */
14609
+ renderEchoedYieldOpportunitiesCard(displayText, alreadyRendered, ui) {
14610
+ const extracted = extractYieldOpportunitiesFromText(displayText);
14611
+ if (!extracted) return displayText;
14612
+ if (!alreadyRendered) {
14613
+ ui.onYieldOpportunities?.(extracted.card);
14614
+ }
14615
+ return extracted.remainingText;
14616
+ }
14617
+ /**
14618
+ * Legacy-path fallback for echoed polymarket_markets cards (rj3p). Mirrors
14619
+ * {@link renderEchoedBalanceCard} — strips a verbatim-echoed envelope from
14620
+ * the displayed text and renders it, unless the typed SSE part already fired.
14621
+ */
14622
+ renderEchoedPolymarketMarketsCard(displayText, alreadyRendered, ui) {
14623
+ const extracted = extractPolymarketMarketsFromText(displayText);
14624
+ if (!extracted) return displayText;
14625
+ if (!alreadyRendered) {
14626
+ ui.onPolymarketMarkets?.(extracted.card);
14627
+ }
14628
+ return extracted.remainingText;
14629
+ }
14413
14630
  /**
14414
14631
  * Wrap a per-tool dispatch with the password-prompt gate (for tools in
14415
14632
  * {@link PASSWORD_REQUIRED_TOOLS}) and `ui.onToolCall` /
@@ -14740,6 +14957,22 @@ var ChatTUI = class {
14740
14957
  this.currentStreamText = "";
14741
14958
  console.log(renderBalanceSummaryCard(card));
14742
14959
  },
14960
+ onYieldOpportunities: (card) => {
14961
+ if (this.isStreaming) {
14962
+ process.stdout.write("\n");
14963
+ this.isStreaming = false;
14964
+ }
14965
+ this.currentStreamText = "";
14966
+ console.log(renderYieldOpportunitiesCard(card));
14967
+ },
14968
+ onPolymarketMarkets: (card) => {
14969
+ if (this.isStreaming) {
14970
+ process.stdout.write("\n");
14971
+ this.isStreaming = false;
14972
+ }
14973
+ this.currentStreamText = "";
14974
+ console.log(renderPolymarketMarketsCard(card));
14975
+ },
14743
14976
  onSuggestions: (suggestions) => {
14744
14977
  if (suggestions.length > 0) {
14745
14978
  console.log(chalk9.gray(" Suggestions:"));
@@ -15111,6 +15344,16 @@ function outputAskHuman(result, confirmationRequired, proposed) {
15111
15344
  for (const card of result.cards) {
15112
15345
  process.stdout.write(`
15113
15346
  ${renderBalanceSummaryCard(card)}
15347
+ `);
15348
+ }
15349
+ for (const card of result.yieldCards) {
15350
+ process.stdout.write(`
15351
+ ${renderYieldOpportunitiesCard(card)}
15352
+ `);
15353
+ }
15354
+ for (const card of result.polymarketCards) {
15355
+ process.stdout.write(`
15356
+ ${renderPolymarketMarketsCard(card)}
15114
15357
  `);
15115
15358
  }
15116
15359
  if (result.response) {
@@ -15142,6 +15385,8 @@ function outputAskSuccess(wantsJson, result, conversationId) {
15142
15385
  tool_calls: result.toolCalls,
15143
15386
  transactions: result.transactions,
15144
15387
  ...result.cards.length > 0 ? { cards: result.cards } : {},
15388
+ ...result.yieldCards.length > 0 ? { yield_cards: result.yieldCards } : {},
15389
+ ...result.polymarketCards.length > 0 ? { polymarket_cards: result.polymarketCards } : {},
15145
15390
  ...result.warnings.length > 0 ? { warnings: result.warnings } : {},
15146
15391
  // a2a-02: the typed turn ending (success | blocked | refusal | error) at
15147
15392
  // `data.outcome` — the same relative slot as on the error envelope. Present
@@ -15345,7 +15590,7 @@ var cachedVersion = null;
15345
15590
  function getVersion() {
15346
15591
  if (cachedVersion) return cachedVersion;
15347
15592
  if (true) {
15348
- cachedVersion = "4.0.0";
15593
+ cachedVersion = "4.0.1";
15349
15594
  return cachedVersion;
15350
15595
  }
15351
15596
  try {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vultisig/cli",
3
- "version": "4.0.0",
3
+ "version": "4.0.1",
4
4
  "description": "The self-custody MPC wallet CLI for AI coding agents (Claude Code, Cursor, OpenCode). Natural-language agent mode, 36+ chains, DKLS23 threshold signatures. Seedless.",
5
5
  "type": "module",
6
6
  "bin": {
@@ -76,7 +76,7 @@
76
76
  "@vultisig/client-shared": "^0.3.2",
77
77
  "@vultisig/core-chain": "^2.31.0",
78
78
  "@vultisig/rujira": "^59.0.0",
79
- "@vultisig/sdk": "^4.0.0",
79
+ "@vultisig/sdk": "^4.0.1",
80
80
  "chalk": "^5.6.2",
81
81
  "cli-table3": "^0.6.5",
82
82
  "commander": "^15.0.0",