@heyamiko/amiko-cli 0.14.0-beta.13 → 0.14.0-beta.14

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/README.md CHANGED
@@ -1,4 +1,4 @@
1
- # @heyamiko/amiko-cli (v0.14.0-beta.13)
1
+ # @heyamiko/amiko-cli (v0.14.0-beta.14)
2
2
 
3
3
  Manage wallets, credits, swaps, MPP marketplace services, and your Amiko twin (identity, documents, voice, avatar, friends, feed) from the terminal. Works for both human users and AI agents running on OpenClaw.
4
4
 
@@ -583,6 +583,10 @@ npm publish
583
583
 
584
584
  ## Changelog
585
585
 
586
+ ### 0.14.0-beta.14
587
+
588
+ - `credits balance` prefers `AMIKO_API_KEY` (`amk_`) → `billing.heyamiko.com/api/credits` directly; falls back to twin-token platform proxy. Override base with `AMIKO_BILLING_URL`.
589
+
586
590
  ### 0.14.0-beta.13
587
591
 
588
592
  - **Create Studio TTS + voice clone: MiniMax.** `amiko create tts` accepts `--provider minimax|elevenlabs` (infers from `speech-*` / `eleven_*` models when omitted), with provider-specific defaults (`speech-2.8-turbo` + `English_expressive_narrator` vs `eleven_multilingual_v2` + Rachel). Quote body includes `voiceId`. Cloned-voice examples require `--provider minimax` when using a MiniMax `voice_id`.
package/dist/index.js CHANGED
@@ -23655,7 +23655,9 @@ function readFromFile(path) {
23655
23655
  twinId: asString(parsed.amikoTwinId) ?? asString(parsed.AMIKO_TWIN_ID),
23656
23656
  userId: asString(parsed.amikoUserId) ?? asString(parsed.AMIKO_USER_ID),
23657
23657
  platformUrl: asString(parsed.amikoPlatformUrl) ?? asString(parsed.AMIKO_PLATFORM_URL),
23658
- apiBase: asString(parsed.amikoApiBase) ?? asString(parsed.AMIKO_API_BASE) ?? asString(parsed.apiBase)
23658
+ apiBase: asString(parsed.amikoApiBase) ?? asString(parsed.AMIKO_API_BASE) ?? asString(parsed.apiBase),
23659
+ billingApiKey: asString(parsed.amikoApiKey) ?? asString(parsed.AMIKO_API_KEY) ?? asString(parsed.billingApiKey),
23660
+ billingUrl: asString(parsed.amikoBillingUrl) ?? asString(parsed.AMIKO_BILLING_URL) ?? asString(parsed.billingUrl)
23659
23661
  };
23660
23662
  } catch {
23661
23663
  return null;
@@ -23674,6 +23676,8 @@ function readFromEnv() {
23674
23676
  userId: asString(process.env.AMIKO_USER_ID),
23675
23677
  platformUrl: asString(process.env.AMIKO_PLATFORM_URL),
23676
23678
  apiBase: asString(process.env.AMIKO_API_BASE),
23679
+ billingApiKey: asString(process.env.AMIKO_API_KEY),
23680
+ billingUrl: asString(process.env.AMIKO_BILLING_URL),
23677
23681
  ...readRoutingIdsFromEnv()
23678
23682
  };
23679
23683
  }
@@ -23681,7 +23685,13 @@ function resolveFileAuth(path) {
23681
23685
  const fromFile = readFromFile(path);
23682
23686
  if (!fromFile)
23683
23687
  return null;
23684
- return { ...fromFile, ...readRoutingIdsFromEnv() };
23688
+ const fromEnv = readFromEnv();
23689
+ return {
23690
+ ...fromFile,
23691
+ ...readRoutingIdsFromEnv(),
23692
+ billingApiKey: fromEnv.billingApiKey ?? fromFile.billingApiKey,
23693
+ billingUrl: fromEnv.billingUrl ?? fromFile.billingUrl
23694
+ };
23685
23695
  }
23686
23696
  function resolveAuth() {
23687
23697
  const filePath = findAmikoJsonPath();
@@ -25418,7 +25428,31 @@ function registerBridgeCommand(program2) {
25418
25428
  import readline2 from "node:readline";
25419
25429
 
25420
25430
  // src/lib/balance.ts
25421
- async function fetchCreditsBalance(auth) {
25431
+ var DEFAULT_BILLING_URL = "https://billing.heyamiko.com";
25432
+ function billingBase(auth) {
25433
+ const url = auth.billingUrl || DEFAULT_BILLING_URL;
25434
+ return url.replace(/\/$/, "");
25435
+ }
25436
+ async function fetchCreditsBalanceViaAmk(auth) {
25437
+ const apiKey = auth.billingApiKey;
25438
+ if (!apiKey || !apiKey.startsWith("amk_"))
25439
+ return null;
25440
+ try {
25441
+ const res = await fetch(`${billingBase(auth)}/api/credits`, {
25442
+ method: "GET",
25443
+ headers: { Authorization: `Bearer ${apiKey}` },
25444
+ signal: AbortSignal.timeout(15000)
25445
+ });
25446
+ if (!res.ok)
25447
+ return null;
25448
+ const data = await res.json();
25449
+ const raw = data.displayBalance;
25450
+ return typeof raw === "number" && isFinite(raw) ? Math.round(raw) : null;
25451
+ } catch {
25452
+ return null;
25453
+ }
25454
+ }
25455
+ async function fetchCreditsBalanceViaPlatformProxy(auth) {
25422
25456
  if (!auth.twinToken)
25423
25457
  return null;
25424
25458
  try {
@@ -25429,6 +25463,12 @@ async function fetchCreditsBalance(auth) {
25429
25463
  return null;
25430
25464
  }
25431
25465
  }
25466
+ async function fetchCreditsBalance(auth) {
25467
+ const viaAmk = await fetchCreditsBalanceViaAmk(auth);
25468
+ if (viaAmk != null)
25469
+ return viaAmk;
25470
+ return fetchCreditsBalanceViaPlatformProxy(auth);
25471
+ }
25432
25472
  async function printBalanceRemaining(auth) {
25433
25473
  const balance = await fetchCreditsBalance(auth);
25434
25474
  if (balance == null) {
@@ -28639,7 +28679,7 @@ function registerAccountsCommand(program2) {
28639
28679
  }
28640
28680
  }, { json: opts.json });
28641
28681
  });
28642
- program2.command("info").description("Get twin info (name, description, voice, avatar)").option("--twin <idOrName>", "Target twin id or name").option("--json", "Output as JSON").action(async (opts) => {
28682
+ program2.command("info").description("Get twin info (name, description, voice ids, avatar)").option("--twin <idOrName>", "Target twin id or name").option("--json", "Output as JSON").action(async (opts) => {
28643
28683
  const config2 = loadConfig();
28644
28684
  const auth = resolveAuth();
28645
28685
  let twinId;
@@ -28663,13 +28703,24 @@ function registerAccountsCommand(program2) {
28663
28703
  console.log(label("Description", t.description));
28664
28704
  console.log(label("Public", t.is_public ? "yes" : "no"));
28665
28705
  if (t.voice_status)
28666
- console.log(label("Voice", t.voice_status));
28706
+ console.log(label("Voice status", t.voice_status));
28707
+ if (t.voice_id)
28708
+ console.log(label("ElevenLabs voice_id", t.voice_id));
28709
+ else
28710
+ console.log(label("ElevenLabs voice_id", dim("(none)")));
28711
+ if (t.minimax_voice_id)
28712
+ console.log(label("MiniMax voice_id", t.minimax_voice_id));
28713
+ else
28714
+ console.log(label("MiniMax voice_id", dim("(none — clone with amiko voice clone)")));
28667
28715
  if (t.avatar_url)
28668
28716
  console.log(label("Avatar", t.avatar_url));
28669
28717
  if (t.shipped_at)
28670
28718
  console.log(label("Shipped", t.shipped_at));
28671
28719
  if (t.updated_at)
28672
28720
  console.log(dim(`Updated ${t.updated_at}`));
28721
+ console.log("");
28722
+ console.log(dim('MiniMax TTS: amiko create tts "…" --provider minimax --voice <MiniMax voice_id> --yes'));
28723
+ console.log(dim('ElevenLabs TTS: amiko create tts "…" --provider elevenlabs --voice <ElevenLabs voice_id> --yes'));
28673
28724
  }, { json: opts.json });
28674
28725
  } catch (e5) {
28675
28726
  spinner?.stop();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@heyamiko/amiko-cli",
3
- "version": "0.14.0-beta.13",
3
+ "version": "0.14.0-beta.14",
4
4
  "description": "Amiko CLI — swap tokens, manage credits, bridge cross-chain, and call marketplace agents",
5
5
  "type": "module",
6
6
  "bin": {
package/skills/SKILL.md CHANGED
@@ -35,6 +35,8 @@ Call your shell tool (your runtime calls it `bash`, `shell`, `run`, or similar)
35
35
  | "share the group's invite link" (asked by an admin) | shell → `amiko chat group info "<group>"` (confirm they're admin) → `amiko chat group invite "<group>"` |
36
36
  | "react to the latest message from Ava about the team with a heart" | shell → `amiko chat read "Ava"` (find that message, copy its `id`) → `amiko chat react <messageId> ❤️ --yes` |
37
37
  | "what can amiko do?" | shell → `amiko --help` |
38
+ | "what's my MiniMax / ElevenLabs voice id?" | shell → `amiko info` |
39
+ | "speak with my cloned MiniMax voice" | shell → `amiko info`, quote the cost, obtain explicit approval, then run `amiko create tts "…" --provider minimax --voice <minimax_voice_id> --yes` |
38
40
 
39
41
  The CLI is installed globally and is pre-authenticated when you're inside your workspace folder. Never suggest `amiko login` or `amiko connect` — they don't exist.
40
42
 
@@ -96,6 +98,21 @@ All paid markets commands auto-select the twin's active Solana wallet (see `--wa
96
98
 
97
99
  **Prefer `amiko create` for anything it supports.** For media generation — image, video, speech (TTS), music, SFX — use `amiko create` (async, charge-on-success, never loses money on a timeout), NOT `markets`. Reach for `markets` **only for what `create` does not cover**: X/Twitter search, Amazon, AI chat, speech-to-text/transcription, and arbitrary MPP endpoints via `markets service call`.
98
100
 
101
+ ### Voice IDs — never guess
102
+
103
+ This twin has **two** optional TTS ids. They are **not** the same:
104
+
105
+ | Field | Provider | How to get it | How to use |
106
+ |---|---|---|---|
107
+ | `voice_id` | ElevenLabs | shown by `amiko info` | quote cost + approval, then `amiko create tts "…" --provider elevenlabs --voice <voice_id> --yes` |
108
+ | `minimax_voice_id` | MiniMax | shown by `amiko info` | quote cost + approval, then `amiko create tts "…" --provider minimax --voice <minimax_voice_id> --yes` |
109
+
110
+ - **Before any TTS or clone follow-up**, run `amiko info` (or `amiko info --json`) and read the printed ids. Do **not** invent a `voice_id`, ask the owner to paste one you already have on the twin, or claim MiniMax TTS is blocked because you "don't know" the id.
111
+ - Paid voice ops still need the Critical Rules gate: quote live cost, get explicit approval, only then append `--yes`.
112
+ - If MiniMax voice_id is `(none)`, quote the clone cost, obtain explicit approval, then run `amiko voice clone <audio> --provider minimax --yes` and `amiko info` again.
113
+ - System MiniMax voices (no clone) also work: e.g. `--voice English_expressive_narrator --provider minimax` (same approval gate before `--yes`).
114
+ - `markets service tts <voiceId> "…" --provider minimax --yes` needs the same MiniMax id and approval gate.
115
+
99
116
  **Payment token:** `markets search`, `markets image`, and `markets amazon search` accept `--token <AMIKO|USDC|USDT>` (default AMIKO); `markets service call` uses `--usdc`/`--usdt` (pass `auto` to price from USD). Stables are pinned at $1.00 — the amount equals the endpoint's USD price — so there is no forced swap through AMIKO. When the owner asks to pay in USDT/USDC, pass the flag; do NOT swap first.
100
117
 
101
118
  ## Create Studio — behavior notes