@heyamiko/amiko-cli 0.3.5 → 0.3.6

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 (3) hide show
  1. package/README.md +14 -9
  2. package/dist/index.js +158 -106
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -30,6 +30,9 @@ amiko credits balance
30
30
  # Top up credits from your agent's wallet
31
31
  amiko credits topup 10000 --token AMIKO --yes
32
32
 
33
+ # Swap tokens on Solana
34
+ amiko swap send 1 amiko usdc
35
+
33
36
  # Browse and call marketplace agents
34
37
  amiko browse
35
38
  amiko call titan-research "Summarize the latest AI news"
@@ -45,7 +48,7 @@ amiko connect amk_<key> # API key (shown once at creation)
45
48
  amiko connect # browser sign-in flow
46
49
  ```
47
50
 
48
- The connect code is the simplest — generate one from your Amiko settings page, paste it to the agent or terminal.
51
+ The connect code is the simplest — generate one from your Amiko settings page, paste it to the agent or terminal. Connect auto-detects your Solana wallet for swaps.
49
52
 
50
53
  ```bash
51
54
  amiko whoami # show current auth status
@@ -124,18 +127,19 @@ amiko creator payout # request payout
124
127
 
125
128
  ## Swap (Solana)
126
129
 
127
- Swap tokens on Solana via Jupiter aggregator (0.1% platform fee):
130
+ Swap tokens on Solana via Jupiter aggregator. Wallet auto-detected from your connected account — no setup needed.
128
131
 
129
132
  ```bash
130
- amiko swap quote 5 usdt usdc # get swap quote
131
- amiko swap quote 0.1 sol usdc # SOL → USDC quote
132
- amiko swap quote 1 amiko usdc # AMIKO → USDC quote
133
- amiko swap send 5 usdt usdc # build swap transaction
134
- amiko swap send 5 usdt usdc --raw # output raw base64 tx
133
+ amiko swap send 1 amiko usdc # swap 1 AMIKO → USDC (auto-detect wallet)
134
+ amiko swap send 5 usdt usdc --yes # skip confirmation
135
+ amiko swap send 0.1 sol usdc # SOL → USDC
136
+ amiko swap quote 1 amiko usdc # preview without executing
135
137
  amiko swap tokens # list supported tokens
136
138
  ```
137
139
 
138
- Supports symbols (sol, usdc, usdt, amiko, bonk, jup, ...) or raw mint addresses.
140
+ Supports symbols (`sol`, `usdc`, `usdt`, `amiko`, `bonk`, `jup`, `pyusd`, `jitosol`, `ray`, `wbtc`) or raw mint addresses.
141
+
142
+ Swaps execute via Crossmint smart wallets — your agent wallet signs and submits on-chain automatically.
139
143
 
140
144
  ## Bridge (Cross-Chain)
141
145
 
@@ -170,9 +174,10 @@ npm install -g @heyamiko/amiko-cli
170
174
  amiko connect <CODE>
171
175
  amiko credits balance
172
176
  amiko credits topup 10000 --token AMIKO --yes
177
+ amiko swap send 1 amiko usdc # swap tokens on Solana
173
178
  ```
174
179
 
175
- The CLI auto-detects `.amiko.json` (synced by the platform) when running on an agent.
180
+ Connect auto-detects the agent's Solana wallet — no manual wallet setup needed. The CLI auto-detects `.amiko.json` (synced by the platform) when running on an agent.
176
181
 
177
182
  ## Configuration
178
183
 
package/dist/index.js CHANGED
@@ -3603,6 +3603,80 @@ var require_emoji_regex = __commonJS((exports, module) => {
3603
3603
  };
3604
3604
  });
3605
3605
 
3606
+ // src/lib/agent-config.ts
3607
+ var exports_agent_config = {};
3608
+ __export(exports_agent_config, {
3609
+ resolveAuth: () => resolveAuth,
3610
+ loadAgentConfig: () => loadAgentConfig
3611
+ });
3612
+ import { existsSync as existsSync3, readFileSync as readFileSync2 } from "node:fs";
3613
+ import { join as join3, resolve } from "node:path";
3614
+ function loadAgentConfig() {
3615
+ let dir = process.cwd();
3616
+ const root = resolve("/");
3617
+ while (dir !== root) {
3618
+ const filePath = join3(dir, ".amiko.json");
3619
+ if (existsSync3(filePath)) {
3620
+ try {
3621
+ const raw = readFileSync2(filePath, "utf-8");
3622
+ const parsed = JSON.parse(raw);
3623
+ const config = {};
3624
+ if (parsed.amikoTwinToken)
3625
+ config.twinToken = parsed.amikoTwinToken;
3626
+ if (parsed.amikoTwinId)
3627
+ config.twinId = parsed.amikoTwinId;
3628
+ if (parsed.amikoUserId)
3629
+ config.userId = parsed.amikoUserId;
3630
+ if (parsed.amikoPlatformUrl)
3631
+ config.platformUrl = parsed.amikoPlatformUrl;
3632
+ return Object.keys(config).length > 0 ? config : null;
3633
+ } catch {
3634
+ return null;
3635
+ }
3636
+ }
3637
+ dir = resolve(dir, "..");
3638
+ }
3639
+ return null;
3640
+ }
3641
+ function resolveAuth(cliConfig) {
3642
+ if (cliConfig.agentWallets?.length) {
3643
+ return {
3644
+ mode: "connected",
3645
+ platformUrl: cliConfig.platformUrl,
3646
+ billingBase: cliConfig.billingBase,
3647
+ twinId: cliConfig.twinId,
3648
+ twinToken: cliConfig.twinToken,
3649
+ platformKey: cliConfig.apiKey,
3650
+ privyToken: cliConfig.privyToken,
3651
+ connectedKeyId: cliConfig.connectedKeyId,
3652
+ userId: cliConfig.userId,
3653
+ agentWallets: cliConfig.agentWallets
3654
+ };
3655
+ }
3656
+ if (cliConfig.privyToken && cliConfig.connectedKeyId) {
3657
+ return {
3658
+ mode: "connected",
3659
+ billingBase: cliConfig.billingBase,
3660
+ platformKey: cliConfig.privyToken,
3661
+ privyToken: cliConfig.privyToken,
3662
+ connectedKeyId: cliConfig.connectedKeyId,
3663
+ userId: cliConfig.userId
3664
+ };
3665
+ }
3666
+ const agentConfig = loadAgentConfig();
3667
+ if (agentConfig?.twinToken) {
3668
+ return {
3669
+ mode: "agent",
3670
+ platformUrl: agentConfig.platformUrl,
3671
+ twinId: agentConfig.twinId,
3672
+ twinToken: agentConfig.twinToken,
3673
+ userId: agentConfig.userId
3674
+ };
3675
+ }
3676
+ return { mode: "none" };
3677
+ }
3678
+ var init_agent_config = () => {};
3679
+
3606
3680
  // node_modules/@solana/errors/dist/index.node.mjs
3607
3681
  function getHumanReadableErrorMessage(code, context = {}) {
3608
3682
  const messageFormatString = SolanaErrorMessages[code];
@@ -21107,7 +21181,7 @@ function nonoptional(innerType, params) {
21107
21181
  ...normalizeParams(params)
21108
21182
  });
21109
21183
  }
21110
- function success3(innerType) {
21184
+ function success2(innerType) {
21111
21185
  return new ZodMiniSuccess({
21112
21186
  type: "success",
21113
21187
  innerType
@@ -21630,7 +21704,7 @@ __export(exports_external, {
21630
21704
  templateLiteral: () => templateLiteral,
21631
21705
  symbol: () => symbol,
21632
21706
  superRefine: () => superRefine,
21633
- success: () => success3,
21707
+ success: () => success2,
21634
21708
  stringbool: () => stringbool,
21635
21709
  stringFormat: () => stringFormat,
21636
21710
  string: () => string2,
@@ -21891,7 +21965,7 @@ __export(exports_zod, {
21891
21965
  templateLiteral: () => templateLiteral,
21892
21966
  symbol: () => symbol,
21893
21967
  superRefine: () => superRefine,
21894
- success: () => success3,
21968
+ success: () => success2,
21895
21969
  stringbool: () => stringbool,
21896
21970
  stringFormat: () => stringFormat,
21897
21971
  string: () => string2,
@@ -26464,60 +26538,98 @@ function registerSwapCommand(program2) {
26464
26538
  process.exit(1);
26465
26539
  }
26466
26540
  });
26467
- cmd.command("send").description("Execute a token swap on Solana").argument("<amount>", "Amount to swap (e.g., 5, 0.1)").argument("<from>", "Input token (sol, usdc, usdt, bonk, or mint address)").argument("<to>", "Output token (sol, usdc, usdt, bonk, or mint address)").option("--wallet <address>", "Wallet address (uses config wallet by default)").option("--slippage <bps>", "Slippage tolerance in basis points", "50").option("--raw", "Output raw transaction base64 for manual signing").action(async (amountStr, fromToken, toToken, opts) => {
26468
- const spinner = ora("Building swap transaction...").start();
26541
+ cmd.command("send").description("Execute a token swap on Solana via Crossmint wallet").argument("<amount>", "Amount to swap (e.g., 5, 0.1)").argument("<from>", "Input token (sol, usdc, usdt, amiko, bonk, or mint address)").argument("<to>", "Output token (sol, usdc, usdt, amiko, bonk, or mint address)").option("--wallet <address>", "Wallet address (uses config wallet by default)").option("--slippage <bps>", "Slippage tolerance in basis points", "50").option("--yes", "Skip confirmation").action(async (amountStr, fromToken, toToken, opts) => {
26469
26542
  try {
26470
26543
  const { loadConfig: loadConfig2 } = await Promise.resolve().then(() => (init_config(), exports_config));
26544
+ const { resolveAuth: resolveAuth2 } = await Promise.resolve().then(() => (init_agent_config(), exports_agent_config));
26471
26545
  const config = loadConfig2();
26472
- const wallet = opts.wallet || config.wallet;
26546
+ const auth = resolveAuth2(config);
26547
+ const solanaAgentWallet = config.agentWallets?.find((w) => w.chain === "solana" && w.source === "agent")?.address;
26548
+ const wallet = opts.wallet || config.wallet || solanaAgentWallet;
26473
26549
  if (!wallet) {
26474
- spinner.stop();
26475
- console.error(error("No wallet address. Provide --wallet or set one: amiko config set wallet <address>"));
26550
+ console.error(error("No Solana wallet found. Provide --wallet or run: amiko connect"));
26551
+ process.exit(1);
26552
+ }
26553
+ if (auth.mode === "none") {
26554
+ console.error(error("Not connected. Run: amiko connect"));
26476
26555
  process.exit(1);
26477
26556
  }
26478
26557
  const input = resolveToken(fromToken);
26479
26558
  const output = resolveToken(toToken);
26480
26559
  const amount = parseAmount(amountStr, input.decimals);
26481
- const params = new URLSearchParams({
26560
+ const quoteSpinner = ora("Fetching swap quote...").start();
26561
+ const quoteParams = new URLSearchParams({
26482
26562
  inputMint: input.mint,
26483
26563
  outputMint: output.mint,
26484
26564
  amount,
26485
26565
  slippageBps: opts.slippage
26486
26566
  });
26487
- const quote = await get(`/v1/swap/quote?${params}`);
26488
- const txResponse = await post("/v1/swap/transaction", {
26489
- quoteResponse: quote,
26490
- userPublicKey: wallet
26491
- });
26492
- spinner.stop();
26493
- console.log(heading("Swap Transaction"));
26567
+ const quote = await get(`/v1/swap/quote?${quoteParams}`);
26568
+ quoteSpinner.stop();
26569
+ console.log(heading("Swap"));
26494
26570
  console.log("");
26495
- console.log(label("Swap", `${formatAmount(quote.inAmount, input.decimals)} ${input.symbol} → ${formatAmount(quote.outAmount, output.decimals)} ${output.symbol}`));
26571
+ console.log(label("Send", `${formatAmount(quote.inAmount, input.decimals)} ${input.symbol}`));
26572
+ console.log(label("Receive", `~${formatAmount(quote.outAmount, output.decimals)} ${output.symbol}`));
26573
+ if (quote.platformFee && parseInt(quote.platformFee.amount) > 0) {
26574
+ console.log(label("Fee", `${formatAmount(quote.platformFee.amount, output.decimals)} ${output.symbol} (${quote.platformFee.feeBps} bps)`));
26575
+ }
26576
+ const route = quote.routePlan.map((r) => r.swapInfo.label).join(" → ");
26577
+ if (route)
26578
+ console.log(label("Route", dim(route)));
26496
26579
  console.log(label("Wallet", truncAddr(wallet)));
26497
- if (txResponse.simulationError) {
26498
- console.log(warn(`Simulation warning: ${txResponse.simulationError.error}`));
26580
+ console.log("");
26581
+ if (!opts.yes) {
26582
+ const readline = await import("readline");
26583
+ const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
26584
+ const answer = await new Promise((resolve2) => rl.question("Confirm swap? (y/N) ", resolve2));
26585
+ rl.close();
26586
+ if (answer.toLowerCase() !== "y") {
26587
+ console.log(dim("Cancelled."));
26588
+ process.exit(0);
26589
+ }
26590
+ }
26591
+ const swapSpinner = ora("Executing swap via Crossmint...").start();
26592
+ const billingToken = auth.platformKey || auth.privyToken;
26593
+ const billingBase2 = auth.billingBase;
26594
+ if (!billingBase2 || !billingToken) {
26595
+ swapSpinner.stop();
26596
+ console.error(error("No billing credentials. Run: amiko connect"));
26597
+ process.exit(1);
26499
26598
  }
26500
- if (opts.raw) {
26501
- console.log("");
26502
- console.log(heading("Raw Transaction (base64)"));
26503
- console.log(txResponse.swapTransaction);
26504
- console.log("");
26505
- console.log(label("Block Height", String(txResponse.lastValidBlockHeight)));
26506
- console.log(label("CU Limit", String(txResponse.computeUnitLimit)));
26507
- console.log("");
26508
- console.log(dim("Sign and submit this transaction with your wallet."));
26509
- return;
26599
+ const swapRes = await fetch(`${billingBase2}/api/crossmint/wallets/${encodeURIComponent(wallet)}/swap`, {
26600
+ method: "POST",
26601
+ headers: {
26602
+ "Content-Type": "application/json",
26603
+ Authorization: `Bearer ${billingToken}`
26604
+ },
26605
+ body: JSON.stringify({
26606
+ inputMint: input.mint,
26607
+ outputMint: output.mint,
26608
+ amount,
26609
+ slippageBps: parseInt(opts.slippage)
26610
+ })
26611
+ });
26612
+ if (!swapRes.ok) {
26613
+ swapSpinner.stop();
26614
+ const err = await swapRes.json().catch(() => ({ error: "Swap failed" }));
26615
+ console.error(error(err.error || `Swap failed: ${swapRes.status}`));
26616
+ if (err.details)
26617
+ console.error(dim(typeof err.details === "string" ? err.details : JSON.stringify(err.details)));
26618
+ process.exit(1);
26510
26619
  }
26620
+ const swapData = await swapRes.json();
26621
+ swapSpinner.stop();
26622
+ console.log(success("Swap executed"));
26511
26623
  console.log("");
26512
- console.log(heading("Transaction Ready"));
26513
- console.log("");
26514
- console.log(dim("Sign and submit with your Solana wallet:"));
26515
- console.log("");
26516
- console.log(` ${source_default.cyan("amiko swap send")} ${amountStr} ${fromToken} ${toToken} --raw | solana-keygen sign`);
26517
- console.log("");
26518
- console.log(dim("Or use --raw to get the base64 transaction for any wallet."));
26624
+ if (swapData.txHash) {
26625
+ console.log(label("Tx Hash", dim(swapData.txHash)));
26626
+ console.log(label("Explorer", dim(swapData.explorerLink || `https://solscan.io/tx/${swapData.txHash}`)));
26627
+ }
26628
+ if (swapData.quote) {
26629
+ console.log(label("Input", `${formatAmount(swapData.quote.inAmount, input.decimals)} ${input.symbol}`));
26630
+ console.log(label("Output", `${formatAmount(swapData.quote.outAmount, output.decimals)} ${output.symbol}`));
26631
+ }
26519
26632
  } catch (err) {
26520
- spinner.stop();
26521
26633
  console.error(error(err instanceof Error ? err.message : "Swap failed"));
26522
26634
  process.exit(1);
26523
26635
  }
@@ -26603,8 +26715,15 @@ function saveCredentials(data) {
26603
26715
  update.connectedKeyPreview = data.connectedKeyPreview;
26604
26716
  if (data.connectedKeyName)
26605
26717
  update.connectedKeyName = data.connectedKeyName;
26606
- if (data.wallets)
26718
+ if (data.wallets) {
26607
26719
  update.agentWallets = data.wallets;
26720
+ const currentConfig = loadConfig();
26721
+ if (!currentConfig.wallet) {
26722
+ const solWallet = data.wallets.find((w) => w.chain === "solana" && w.source === "agent");
26723
+ if (solWallet)
26724
+ update.wallet = solWallet.address;
26725
+ }
26726
+ }
26608
26727
  saveConfig(update);
26609
26728
  }
26610
26729
  function registerConnectCommand(program2) {
@@ -26733,74 +26852,7 @@ Tip: you can also generate a connect link from your Amiko settings`));
26733
26852
 
26734
26853
  // src/commands/credits.ts
26735
26854
  init_config();
26736
-
26737
- // src/lib/agent-config.ts
26738
- import { existsSync as existsSync3, readFileSync as readFileSync2 } from "node:fs";
26739
- import { join as join3, resolve } from "node:path";
26740
- function loadAgentConfig() {
26741
- let dir = process.cwd();
26742
- const root = resolve("/");
26743
- while (dir !== root) {
26744
- const filePath = join3(dir, ".amiko.json");
26745
- if (existsSync3(filePath)) {
26746
- try {
26747
- const raw = readFileSync2(filePath, "utf-8");
26748
- const parsed = JSON.parse(raw);
26749
- const config = {};
26750
- if (parsed.amikoTwinToken)
26751
- config.twinToken = parsed.amikoTwinToken;
26752
- if (parsed.amikoTwinId)
26753
- config.twinId = parsed.amikoTwinId;
26754
- if (parsed.amikoUserId)
26755
- config.userId = parsed.amikoUserId;
26756
- if (parsed.amikoPlatformUrl)
26757
- config.platformUrl = parsed.amikoPlatformUrl;
26758
- return Object.keys(config).length > 0 ? config : null;
26759
- } catch {
26760
- return null;
26761
- }
26762
- }
26763
- dir = resolve(dir, "..");
26764
- }
26765
- return null;
26766
- }
26767
- function resolveAuth(cliConfig) {
26768
- if (cliConfig.agentWallets?.length) {
26769
- return {
26770
- mode: "connected",
26771
- platformUrl: cliConfig.platformUrl,
26772
- billingBase: cliConfig.billingBase,
26773
- twinId: cliConfig.twinId,
26774
- twinToken: cliConfig.twinToken,
26775
- platformKey: cliConfig.apiKey,
26776
- privyToken: cliConfig.privyToken,
26777
- connectedKeyId: cliConfig.connectedKeyId,
26778
- userId: cliConfig.userId,
26779
- agentWallets: cliConfig.agentWallets
26780
- };
26781
- }
26782
- if (cliConfig.privyToken && cliConfig.connectedKeyId) {
26783
- return {
26784
- mode: "connected",
26785
- billingBase: cliConfig.billingBase,
26786
- platformKey: cliConfig.privyToken,
26787
- privyToken: cliConfig.privyToken,
26788
- connectedKeyId: cliConfig.connectedKeyId,
26789
- userId: cliConfig.userId
26790
- };
26791
- }
26792
- const agentConfig = loadAgentConfig();
26793
- if (agentConfig?.twinToken) {
26794
- return {
26795
- mode: "agent",
26796
- platformUrl: agentConfig.platformUrl,
26797
- twinId: agentConfig.twinId,
26798
- twinToken: agentConfig.twinToken,
26799
- userId: agentConfig.userId
26800
- };
26801
- }
26802
- return { mode: "none" };
26803
- }
26855
+ init_agent_config();
26804
26856
 
26805
26857
  // src/lib/mpp-topup.ts
26806
26858
  init_config();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@heyamiko/amiko-cli",
3
- "version": "0.3.5",
3
+ "version": "0.3.6",
4
4
  "description": "Amiko CLI — manage agents, wallets, credits, and marketplace on the MPP payment rail",
5
5
  "type": "module",
6
6
  "bin": {