@heyamiko/amiko-cli 0.5.19 → 0.6.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.
Files changed (2) hide show
  1. package/dist/index.js +225 -0
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -75929,6 +75929,230 @@ function registerSearchCommand(program2) {
75929
75929
  });
75930
75930
  }
75931
75931
 
75932
+ // src/commands/services.ts
75933
+ var TREASURY2 = "FPiZAf3jEnNfCwfvbv46jdPfHbmSepD4Q6iHiLJDQXvb";
75934
+ var AMIKO_MINT = "AY1Ww6MxwC3cCiyrandHqLrp4FXvzgcwQTZpJ2FEpump";
75935
+ var USDC_MINT = "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v";
75936
+ async function getAmikoPrice() {
75937
+ const res = await fetch(`https://lite-api.jup.ag/swap/v1/quote?inputMint=${AMIKO_MINT}&outputMint=${USDC_MINT}&amount=${1e6}&slippageBps=100`);
75938
+ if (!res.ok)
75939
+ return 0;
75940
+ const data = await res.json();
75941
+ return parseFloat(data.outAmount) / 1e6;
75942
+ }
75943
+ function usdToAmiko(usd2, pricePerAmiko) {
75944
+ if (pricePerAmiko <= 0)
75945
+ return "1";
75946
+ const amount2 = usd2 / pricePerAmiko;
75947
+ return Math.ceil(amount2 * 100) / 100 + "";
75948
+ }
75949
+ async function payAndCall(mppBase2, method, path, billingBase2, billingToken, solanaWallet, amountOrAuto, body, onProgress, token = "AMIKO") {
75950
+ let amount2 = amountOrAuto;
75951
+ if (amount2 === "auto") {
75952
+ onProgress?.("Fetching price...");
75953
+ try {
75954
+ const specRes = await fetch(`${mppBase2}/openapi.json`);
75955
+ if (specRes.ok) {
75956
+ const spec = await specRes.json();
75957
+ const pathSpec = spec.paths?.[path];
75958
+ const methodSpec = pathSpec?.[method.toLowerCase()];
75959
+ const usdPrice = parseFloat(methodSpec?.["x-payment-info"]?.price || "0");
75960
+ if (usdPrice > 0) {
75961
+ const amikoPrice = await getAmikoPrice();
75962
+ amount2 = usdToAmiko(usdPrice, amikoPrice);
75963
+ onProgress?.(`Price: $${usdPrice.toFixed(4)} = ${amount2} AMIKO`);
75964
+ } else {
75965
+ amount2 = "1";
75966
+ }
75967
+ } else {
75968
+ amount2 = "1";
75969
+ }
75970
+ } catch {
75971
+ amount2 = "1";
75972
+ }
75973
+ }
75974
+ onProgress?.(`Paying ${amount2} AMIKO...`);
75975
+ const transferRes = await fetch(`${billingBase2}/api/crossmint/wallets/${encodeURIComponent(solanaWallet)}/transfer`, {
75976
+ method: "POST",
75977
+ headers: {
75978
+ "Content-Type": "application/json",
75979
+ Authorization: `Bearer ${billingToken}`
75980
+ },
75981
+ body: JSON.stringify({
75982
+ to: TREASURY2,
75983
+ amount: amount2,
75984
+ token,
75985
+ chain: "solana"
75986
+ })
75987
+ });
75988
+ if (!transferRes.ok) {
75989
+ const err = await transferRes.json().catch(() => ({ error: "Transfer failed" }));
75990
+ throw new Error(err.error || `AMIKO payment failed: ${transferRes.status}`);
75991
+ }
75992
+ const transferData = await transferRes.json();
75993
+ const txHash = transferData.txHash;
75994
+ if (!txHash)
75995
+ throw new Error("Payment sent but no tx hash returned.");
75996
+ const headers = {
75997
+ "Content-Type": "application/json",
75998
+ "X-Payment-Tx": txHash
75999
+ };
76000
+ const fetchOpts = { method, headers };
76001
+ if (body && method !== "GET") {
76002
+ fetchOpts.body = JSON.stringify(body);
76003
+ }
76004
+ const url2 = path.startsWith("http") ? path : `${mppBase2}${path}`;
76005
+ const res = await fetch(url2, fetchOpts);
76006
+ return { res, txHash, amikoSpent: amount2 };
76007
+ }
76008
+ function registerServicesCommand(program2) {
76009
+ const svc = program2.command("service").alias("svc").description("Call any MPP service — pays with AMIKO tokens");
76010
+ svc.command("tts <voiceId> <text>").description("Text-to-speech — 1 AMIKO").option("--raw", "Output raw response").action(async (voiceId, text, opts) => {
76011
+ await callService({
76012
+ name: "Text-to-Speech",
76013
+ method: "POST",
76014
+ path: `/v1/tts/${encodeURIComponent(voiceId)}`,
76015
+ body: { text },
76016
+ amiko: "1",
76017
+ opts
76018
+ });
76019
+ });
76020
+ svc.command("stt <audioUrl>").description("Speech-to-text — 1 AMIKO").option("--raw", "Output raw response").action(async (audioUrl, opts) => {
76021
+ await callService({
76022
+ name: "Speech-to-Text",
76023
+ method: "POST",
76024
+ path: "/v1/stt",
76025
+ body: { audioUrl },
76026
+ amiko: "1",
76027
+ opts
76028
+ });
76029
+ });
76030
+ svc.command("voices").description("List available voices — free").action(async () => {
76031
+ const config2 = loadConfig();
76032
+ const mppBase2 = (config2.apiBase || "https://mpp.amikomarkets.com").replace(/\/$/, "");
76033
+ const res = await fetch(`${mppBase2}/v1/voices`);
76034
+ const data = await res.json();
76035
+ console.log(heading(`Available Voices
76036
+ `));
76037
+ const voices = data.voices || data;
76038
+ if (Array.isArray(voices)) {
76039
+ for (const v8 of voices) {
76040
+ console.log(` ${source_default.cyan(v8.voice_id || v8.id)} ${v8.name || ""}`);
76041
+ if (v8.description)
76042
+ console.log(dim(` ${v8.description}`));
76043
+ }
76044
+ } else {
76045
+ console.log(JSON.stringify(data, null, 2));
76046
+ }
76047
+ });
76048
+ svc.command("chat <message>").description("AI chat — 1 AMIKO").option("--model <model>", "Model to use").option("--raw", "Output raw response").action(async (message, opts) => {
76049
+ const body = { message };
76050
+ if (opts.model)
76051
+ body.model = opts.model;
76052
+ await callService({
76053
+ name: "AI Chat",
76054
+ method: "POST",
76055
+ path: "/v1/ai/chat",
76056
+ body,
76057
+ amiko: "1",
76058
+ opts
76059
+ });
76060
+ });
76061
+ svc.command("call <method> <path> [body]").description("Call any MPP endpoint — pays in AMIKO or USDC on Solana").option("--amiko <amount>", "AMIKO tokens to pay (default: auto-price from USD)").option("--usdc <amount>", "Pay in USDC instead of AMIKO").option("--raw", "Output raw response").action(async (method, path, bodyStr, opts) => {
76062
+ let body;
76063
+ if (bodyStr) {
76064
+ try {
76065
+ body = JSON.parse(bodyStr);
76066
+ } catch {
76067
+ body = { text: bodyStr };
76068
+ }
76069
+ }
76070
+ await callService({
76071
+ name: `${method.toUpperCase()} ${path}`,
76072
+ method: method.toUpperCase(),
76073
+ path,
76074
+ body,
76075
+ amiko: opts.amiko || (opts.usdc ? undefined : "auto"),
76076
+ usdc: opts.usdc,
76077
+ opts
76078
+ });
76079
+ });
76080
+ svc.command("list").alias("ls").description("List available MPP services and prices").action(async () => {
76081
+ const config2 = loadConfig();
76082
+ const mppBase2 = (config2.apiBase || "https://mpp.amikomarkets.com").replace(/\/$/, "");
76083
+ const spinner = ora("Fetching services...").start();
76084
+ try {
76085
+ const res = await fetch(`${mppBase2}/openapi.json`);
76086
+ const spec = await res.json();
76087
+ spinner.stop();
76088
+ console.log(heading(`MPP Services
76089
+ `));
76090
+ const paths = spec.paths || {};
76091
+ for (const [path, methods] of Object.entries(paths)) {
76092
+ for (const [method, op] of Object.entries(methods)) {
76093
+ const price = op["x-payment-info"]?.price;
76094
+ const priceLabel = price === "0" || !price ? source_default.green("FREE") : source_default.yellow(`$${parseFloat(price).toFixed(2)}`);
76095
+ console.log(` ${source_default.bold(method.toUpperCase().padEnd(6))} ${path.padEnd(40)} ${priceLabel}`);
76096
+ if (op.summary)
76097
+ console.log(dim(` ${op.summary}`));
76098
+ }
76099
+ }
76100
+ } catch (err) {
76101
+ spinner.stop();
76102
+ console.error(error("Failed to fetch service list"));
76103
+ }
76104
+ });
76105
+ }
76106
+ async function callService(params) {
76107
+ const spinner = ora(`${params.name}...`).start();
76108
+ try {
76109
+ const config2 = loadConfig();
76110
+ const auth = resolveAuth(config2);
76111
+ const mppBase2 = (config2.apiBase || "https://mpp.amikomarkets.com").replace(/\/$/, "");
76112
+ const billingBase2 = auth.billingBase || "https://billing.heyamiko.com";
76113
+ const billingToken = auth.platformKey || auth.twinToken || auth.privyToken;
76114
+ if (!billingToken) {
76115
+ spinner.stop();
76116
+ console.error(error("No auth token."));
76117
+ process.exit(1);
76118
+ }
76119
+ const allWallets = auth.agentWallets || config2.agentWallets || [];
76120
+ const solanaWallet = allWallets.find((w5) => w5.chain === "solana")?.address;
76121
+ if (!solanaWallet) {
76122
+ spinner.stop();
76123
+ console.error(error("No Solana wallet."));
76124
+ process.exit(1);
76125
+ }
76126
+ const token = params.usdc ? "USDC" : "AMIKO";
76127
+ const amount2 = params.usdc || params.amiko || "auto";
76128
+ const { res, txHash, amikoSpent } = await payAndCall(mppBase2, params.method, params.path, billingBase2, billingToken, solanaWallet, token === "USDC" ? amount2 : amount2, params.body, (msg) => {
76129
+ spinner.text = msg;
76130
+ });
76131
+ if (params.usdc) {}
76132
+ spinner.stop();
76133
+ if (!res.ok) {
76134
+ const text = await res.text().catch(() => "");
76135
+ console.error(error(`${params.name} failed: ${res.status} ${text.slice(0, 300)}`));
76136
+ console.log(dim(`Payment tx: https://solscan.io/tx/${txHash}`));
76137
+ process.exit(1);
76138
+ }
76139
+ const contentType = res.headers.get("content-type") || "";
76140
+ if (params.opts.raw || !contentType.includes("json")) {
76141
+ const text = await res.text();
76142
+ console.log(text);
76143
+ } else {
76144
+ const data = await res.json();
76145
+ console.log(JSON.stringify(data, null, 2));
76146
+ }
76147
+ console.log("");
76148
+ console.log(success(`Paid ${amikoSpent} ${token}`) + dim(` tx: ${txHash.slice(0, 16)}...`));
76149
+ } catch (err) {
76150
+ spinner.stop();
76151
+ console.error(error(err instanceof Error ? err.message : "Service call failed"));
76152
+ process.exit(1);
76153
+ }
76154
+ }
76155
+
75932
76156
  // src/index.ts
75933
76157
  var require2 = createRequire2(import.meta.url);
75934
76158
  var { version: PKG_VERSION } = require2("../package.json");
@@ -75950,6 +76174,7 @@ registerWalletCommand(program2);
75950
76174
  registerLoginCommand(program2);
75951
76175
  registerReputationCommand(program2);
75952
76176
  registerConfigCommand(program2);
76177
+ registerServicesCommand(program2);
75953
76178
  registerDiscoveryCommand(program2);
75954
76179
  registerUpdateCommand(program2);
75955
76180
  program2.parse();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@heyamiko/amiko-cli",
3
- "version": "0.5.19",
3
+ "version": "0.6.1",
4
4
  "description": "Amiko CLI — swap tokens, manage credits, bridge cross-chain, and call marketplace agents",
5
5
  "type": "module",
6
6
  "bin": {