@fluxa-pay/planner 0.2.1 → 0.2.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.
Files changed (2) hide show
  1. package/package.json +1 -1
  2. package/planner.mjs +26 -6
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fluxa-pay/planner",
3
- "version": "0.2.1",
3
+ "version": "0.2.3",
4
4
  "description": "FluxA Planner CLI. Recommend the right models, APIs and skills for a task, run paid calls via x402, and manage your oneshot APIs.",
5
5
  "type": "module",
6
6
  "bin": {
package/planner.mjs CHANGED
@@ -47,6 +47,12 @@ const KIND = { model: c.cyan("model"), api: c.lime("api "), skill: c.green("ski
47
47
  const pad = (s, n) => { s = String(s); return s.length > n ? s.slice(0, n - 1) + "…" : s.padEnd(n); };
48
48
  const usd = (units) => { const v = (units || 0) * UNIT_USD; return v < 0.01 ? `$${v.toFixed(4)}` : `$${v.toFixed(2)}`; };
49
49
  const sleep = (ms) => new Promise((r) => setTimeout(r, ms));
50
+ // The planner brain occasionally HTML-escapes angle brackets in free text
51
+ // (e.g. "&lt;merchant&gt;"); un-escape the common entities for terminal output.
52
+ // &amp; is undone LAST so "&amp;lt;" doesn't collapse into "<".
53
+ const unesc = (s) => typeof s === "string"
54
+ ? s.replace(/&lt;/g, "<").replace(/&gt;/g, ">").replace(/&quot;/g, '"').replace(/&#3?9;/g, "'").replace(/&amp;/g, "&")
55
+ : s;
50
56
 
51
57
  // --- config / auth ----------------------------------------------------------
52
58
  function loadConfig() {
@@ -181,6 +187,18 @@ async function cmdModels(vendor) {
181
187
  }
182
188
  }
183
189
 
190
+ async function cmdVendors() {
191
+ const { data } = await http(`${PLATFORM}/api/llm/vendors`);
192
+ const vendors = data.vendors || [];
193
+ if (!vendors.length) return console.log(c.dim(" no vendors"));
194
+ console.log(" " + c.dim(pad("slug", 22) + pad("name", 22) + pad("models", 9) + pad("bundles", 9) + "price (Units/Mtok)"));
195
+ for (const v of vendors) {
196
+ const pr = v.priceRange;
197
+ const price = pr && Number.isFinite(pr.min) ? (pr.min === pr.max ? `${pr.min}` : `${pr.min}-${pr.max}`) : c.dim("—");
198
+ console.log(` ${c.bold(pad(v.slug, 22))}${c.gray(pad(v.name || "", 22))}${pad(String(v.modelCount ?? 0), 9)}${pad(String(v.bundleCount ?? 0), 9)}${price}`);
199
+ }
200
+ }
201
+
184
202
  async function cmdBalance(vendor) {
185
203
  const url = vendor ? `${PROXY}/llm/wallet/balances/${vendor}` : `${PROXY}/llm/wallet/balances`;
186
204
  const { data } = await http(url, { auth: true });
@@ -617,14 +635,14 @@ async function cmdPlan(task) {
617
635
  }
618
636
 
619
637
  function printAnswer(a) {
620
- console.log("\n " + c.bold(a.answer));
638
+ console.log("\n " + c.bold(unesc(a.answer)));
621
639
  if (a.command) {
622
640
  console.log("\n " + c.dim("run:"));
623
- console.log(" " + c.cyan(a.command));
641
+ console.log(" " + c.cyan(unesc(a.command)));
624
642
  }
625
643
  if (a.prompt) {
626
644
  console.log("\n " + c.dim("copy this prompt for your agent:"));
627
- for (const line of a.prompt.split("\n")) console.log(" " + line);
645
+ for (const line of unesc(a.prompt).split("\n")) console.log(" " + line);
628
646
  }
629
647
  console.log("");
630
648
  }
@@ -632,17 +650,17 @@ function printAnswer(a) {
632
650
  // Render a PlanOrAnswer plan: tools carry kind/slug/name/units/detail.
633
651
  function printPlan(plan) {
634
652
  const tools = plan.tools || [];
635
- const heading = plan.reason || plan.task || "Recommended";
653
+ const heading = unesc(plan.reason || plan.task || "Recommended");
636
654
  console.log("\n " + c.bold("Recommended") + " " + c.dim(heading));
637
655
  let total = 0;
638
656
  for (const t of tools) {
639
657
  const k = KIND[t.kind] || pad(t.kind, 5);
640
658
  total += t.units || 0;
641
- console.log(` ${k} ${c.bold(pad(t.slug, 36))} ${c.dim(pad(t.detail || "", 30))} ${c.lime("~" + (t.units || 0).toLocaleString() + " Units")}`);
659
+ console.log(` ${k} ${c.bold(pad(t.slug, 36))} ${c.dim(pad(unesc(t.detail || ""), 30))} ${c.lime("~" + (t.units || 0).toLocaleString() + " Units")}`);
642
660
  }
643
661
  console.log(c.gray(" " + "─".repeat(78)));
644
662
  console.log(` ${c.bold("est")} ${c.lime("~" + total.toLocaleString() + " Units")} ${c.dim("(~" + usd(total) + ")")}`);
645
- if (plan.instructions) console.log("\n " + c.dim(plan.instructions));
663
+ if (plan.instructions) console.log("\n " + c.dim(unesc(plan.instructions)));
646
664
  console.log(c.dim("\n → call these tools directly — FluxA settles each paid call from your wallet. No keys, no subs."));
647
665
  return total;
648
666
  }
@@ -770,6 +788,7 @@ ${c.bold("Headline")}
770
788
  ${c.bold("Primitives")} ${c.dim("(all live)")}
771
789
  planner search "<q>" [--type api,skill,model] discover resources
772
790
  planner models [--vendor <slug>] model catalog + Units rates
791
+ planner vendors list fundable merchants (slug, models, price)
773
792
  planner balance [vendor] prepaid Units per merchant
774
793
  planner topup <vendor> [--credits <N>|--bundle <slug>] prepay Units (x402, via wallet)
775
794
  planner ledger <vendor> spend/topup history
@@ -838,6 +857,7 @@ async function main() {
838
857
  });
839
858
  case "search": return cmdSearch(arg, type);
840
859
  case "models": return cmdModels(vendor);
860
+ case "vendors": return cmdVendors();
841
861
  case "balance": case "bal": return cmdBalance(rest[0]);
842
862
  case "topup":
843
863
  return cmdTopup(rest[0], {