@heyamiko/amiko-cli 0.14.0-beta.15 → 0.14.0-beta.16

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.15)
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
 
@@ -556,7 +556,7 @@ amiko users profile <handle> # public profile
556
556
  # Feed & posts
557
557
  amiko feed # friends feed (default)
558
558
  amiko feed --type for_you --limit 20
559
- amiko post create --content "hello from the CLI" # public post
559
+ amiko post create --content "hello from the CLI" # public post — prints the canonical share URL (post_url in --json); share that verbatim, never hand-build one from the id
560
560
  amiko post create --content "private note" --visibility private
561
561
  amiko post create --content "look" --media https://...jpg
562
562
  amiko post comment --id <postId> --comment "great post"
@@ -583,6 +583,14 @@ npm publish
583
583
 
584
584
  ## Changelog
585
585
 
586
+ ### 0.14.0-beta.15
587
+
588
+ - Create Studio defaults to `--pay credits` (account credits) instead of twin wallet; pass `--pay wallet` for on-chain.
589
+
590
+ ### 0.14.0-beta.14
591
+
592
+ - `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`.
593
+
586
594
  ### 0.14.0-beta.13
587
595
 
588
596
  - **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
@@ -25861,7 +25861,9 @@ function readFromFile(path) {
25861
25861
  twinId: asString(parsed.amikoTwinId) ?? asString(parsed.AMIKO_TWIN_ID),
25862
25862
  userId: asString(parsed.amikoUserId) ?? asString(parsed.AMIKO_USER_ID),
25863
25863
  platformUrl: asString(parsed.amikoPlatformUrl) ?? asString(parsed.AMIKO_PLATFORM_URL),
25864
- apiBase: asString(parsed.amikoApiBase) ?? asString(parsed.AMIKO_API_BASE) ?? asString(parsed.apiBase)
25864
+ apiBase: asString(parsed.amikoApiBase) ?? asString(parsed.AMIKO_API_BASE) ?? asString(parsed.apiBase),
25865
+ billingApiKey: asString(parsed.amikoApiKey) ?? asString(parsed.AMIKO_API_KEY) ?? asString(parsed.billingApiKey),
25866
+ billingUrl: asString(parsed.amikoBillingUrl) ?? asString(parsed.AMIKO_BILLING_URL) ?? asString(parsed.billingUrl)
25865
25867
  };
25866
25868
  } catch {
25867
25869
  return null;
@@ -25880,6 +25882,8 @@ function readFromEnv() {
25880
25882
  userId: asString(process.env.AMIKO_USER_ID),
25881
25883
  platformUrl: asString(process.env.AMIKO_PLATFORM_URL),
25882
25884
  apiBase: asString(process.env.AMIKO_API_BASE),
25885
+ billingApiKey: asString(process.env.AMIKO_API_KEY),
25886
+ billingUrl: asString(process.env.AMIKO_BILLING_URL),
25883
25887
  ...readRoutingIdsFromEnv()
25884
25888
  };
25885
25889
  }
@@ -25887,7 +25891,13 @@ function resolveFileAuth(path) {
25887
25891
  const fromFile = readFromFile(path);
25888
25892
  if (!fromFile)
25889
25893
  return null;
25890
- return { ...fromFile, ...readRoutingIdsFromEnv() };
25894
+ const fromEnv = readFromEnv();
25895
+ return {
25896
+ ...fromFile,
25897
+ ...readRoutingIdsFromEnv(),
25898
+ billingApiKey: fromEnv.billingApiKey ?? fromFile.billingApiKey,
25899
+ billingUrl: fromEnv.billingUrl ?? fromFile.billingUrl
25900
+ };
25891
25901
  }
25892
25902
  function resolveAuth() {
25893
25903
  const filePath = findAmikoJsonPath();
@@ -27624,7 +27634,31 @@ function registerBridgeCommand(program2) {
27624
27634
  import readline2 from "node:readline";
27625
27635
 
27626
27636
  // src/lib/balance.ts
27627
- async function fetchCreditsBalance(auth) {
27637
+ var DEFAULT_BILLING_URL = "https://billing.heyamiko.com";
27638
+ function billingBase(auth) {
27639
+ const url = auth.billingUrl || DEFAULT_BILLING_URL;
27640
+ return url.replace(/\/$/, "");
27641
+ }
27642
+ async function fetchCreditsBalanceViaAmk(auth) {
27643
+ const apiKey = auth.billingApiKey;
27644
+ if (!apiKey || !apiKey.startsWith("amk_"))
27645
+ return null;
27646
+ try {
27647
+ const res = await fetch(`${billingBase(auth)}/api/credits`, {
27648
+ method: "GET",
27649
+ headers: { Authorization: `Bearer ${apiKey}` },
27650
+ signal: AbortSignal.timeout(15000)
27651
+ });
27652
+ if (!res.ok)
27653
+ return null;
27654
+ const data = await res.json();
27655
+ const raw = data.displayBalance;
27656
+ return typeof raw === "number" && isFinite(raw) ? Math.round(raw) : null;
27657
+ } catch {
27658
+ return null;
27659
+ }
27660
+ }
27661
+ async function fetchCreditsBalanceViaPlatformProxy(auth) {
27628
27662
  if (!auth.twinToken)
27629
27663
  return null;
27630
27664
  try {
@@ -27635,6 +27669,12 @@ async function fetchCreditsBalance(auth) {
27635
27669
  return null;
27636
27670
  }
27637
27671
  }
27672
+ async function fetchCreditsBalance(auth) {
27673
+ const viaAmk = await fetchCreditsBalanceViaAmk(auth);
27674
+ if (viaAmk != null)
27675
+ return viaAmk;
27676
+ return fetchCreditsBalanceViaPlatformProxy(auth);
27677
+ }
27638
27678
  async function printBalanceRemaining(auth) {
27639
27679
  const balance = await fetchCreditsBalance(auth);
27640
27680
  if (balance == null) {
@@ -28710,7 +28750,7 @@ async function submitCreateJob(opts) {
28710
28750
  console.error(error(e5 instanceof Error ? e5.message : "auth failed"));
28711
28751
  process.exit(1);
28712
28752
  }
28713
- const payMethod = (opts.pay ?? "wallet").toLowerCase();
28753
+ const payMethod = (opts.pay ?? "credits").toLowerCase();
28714
28754
  if (payMethod !== "wallet" && payMethod !== "credits") {
28715
28755
  console.error(error(`Unknown --pay "${opts.pay}". Allowed: wallet, credits.`));
28716
28756
  process.exit(1);
@@ -28738,15 +28778,16 @@ async function submitCreateJob(opts) {
28738
28778
  } catch {}
28739
28779
  const preferredToken = typeof opts.jobBody.preferredToken === "string" ? opts.jobBody.preferredToken.toUpperCase() : undefined;
28740
28780
  const chargeIsAmiko = !payCredits && (preferredToken === undefined || preferredToken === "AMIKO");
28781
+ const autoApprovable = payCredits || chargeIsAmiko;
28741
28782
  const effectiveChargeToken = preferredToken ?? "AMIKO";
28742
28783
  let yes = opts.yes;
28743
28784
  let autoApproved = false;
28744
28785
  if (!yes) {
28745
28786
  const limit = autoApproveLimit();
28746
- if (limit !== undefined && quotedCostAmiko !== undefined && quotedCostAmiko > 0 && chargeIsAmiko && quotedCostAmiko <= limit) {
28787
+ if (limit !== undefined && quotedCostAmiko !== undefined && quotedCostAmiko > 0 && autoApprovable && quotedCostAmiko <= limit) {
28747
28788
  yes = true;
28748
28789
  autoApproved = true;
28749
- console.log(dim(`Auto-approved (cost ${quotedCostAmiko} ≤ limit ${limit} AMIKO)`));
28790
+ console.log(dim(`Auto-approved (cost ${quotedCostAmiko} ≤ limit ${limit} AMIKO${payCredits ? ", charged as account credits" : ""})`));
28750
28791
  }
28751
28792
  }
28752
28793
  await requireApproval({
@@ -28770,7 +28811,7 @@ async function submitCreateJob(opts) {
28770
28811
  body: {
28771
28812
  ...opts.jobBody,
28772
28813
  twinId: auth.twinId,
28773
- ...autoApproved ? { preferredToken: effectiveChargeToken, strictToken: true } : {},
28814
+ ...autoApproved && !payCredits ? { preferredToken: effectiveChargeToken, strictToken: true } : {},
28774
28815
  ...payCredits ? {
28775
28816
  paymentMethod: { kind: "account_credits" },
28776
28817
  requestId: randomUUID()
@@ -28832,7 +28873,7 @@ async function submitCreateJob(opts) {
28832
28873
  }
28833
28874
  }
28834
28875
  function registerCreateCommand(create2) {
28835
- create2.command("image <prompt>").description("Generate an image (Create Studio)").option("--model <model>", "Image model: nano-banana-2 (default), nano-banana[-pro|-lite] (Google), gpt-image-2/-1.5/-1/-1-mini (OpenAI), grok-imagine-image-quality (xAI), image-01 (MiniMax)", "nano-banana-2").option("--aspect <ratio>", "Aspect ratio: 1:1, 16:9, 9:16, 4:3, 3:4", "1:1").option("--token <symbol>", "Preferred charge token: AMIKO, USDC, USDT, SOL").option("--pay <method>", "Payment method: wallet (twin wallet, default) or credits (Amiko account credits — unified accounts only)", "wallet").option("--raw", "Output raw JSON").option("--yes", "Skip the pre-spend confirmation (required in non-interactive shells)").action(async (prompt, opts) => {
28876
+ create2.command("image <prompt>").description("Generate an image (Create Studio)").option("--model <model>", "Image model: nano-banana-2 (default), nano-banana[-pro|-lite] (Google), gpt-image-2/-1.5/-1/-1-mini (OpenAI), grok-imagine-image-quality (xAI), image-01 (MiniMax)", "nano-banana-2").option("--aspect <ratio>", "Aspect ratio: 1:1, 16:9, 9:16, 4:3, 3:4", "1:1").option("--token <symbol>", "Preferred charge token: AMIKO, USDC, USDT, SOL").option("--pay <method>", "Payment method: credits (Amiko account credits, default) or wallet (twin wallet)", "credits").option("--raw", "Output raw JSON").option("--yes", "Skip the pre-spend confirmation (required in non-interactive shells)").action(async (prompt, opts) => {
28836
28877
  await submitCreateJob({
28837
28878
  mode: "IMAGE",
28838
28879
  summary: `Create image: ${prompt.slice(0, 80)}${prompt.length > 80 ? "…" : ""}`,
@@ -28849,7 +28890,7 @@ function registerCreateCommand(create2) {
28849
28890
  }
28850
28891
  });
28851
28892
  });
28852
- create2.command("video <prompt>").description("Generate a video (Create Studio)").option("--model <model>", "Video model: MiniMax-Hailuo-02 (default for prompt-only; T2V+I2V), MiniMax-Hailuo-2.3-Fast (default with --first-frame; I2V only), MiniMax-Hailuo-2.3 (T2V+I2V), veo-3.1[-fast|-lite]-generate-preview (Google; durations clamp to 4/6/8s), grok-imagine-video (xAI), dreamina-seedance-* (BytePlus). ONLY these — kling and other ids are not supported").option("--resolution <res>", "512P, 720P, 768P, 1080P", "768P").option("--seconds <n>", "Clip length: 6 or 10", "6").option("--aspect <ratio>", "Aspect ratio (provider-dependent)").option("--first-frame <url>", "Image-to-video: first frame URL/data URI").option("--last-frame <url>", "First-and-last-frame video: ending frame URL/data URI").option("--reference-image <url>", "Seedance multimodal: reference image URL (repeatable, max 9)", collectOption, []).option("--reference-video <url>", "Seedance multimodal: reference video URL (repeatable, max 3)", collectOption, []).option("--reference-audio <url>", "Seedance multimodal: reference audio URL (repeatable, max 3)", collectOption, []).option("--subject-reference <url>", "MiniMax S2V: subject/character reference image URL").option("--generate-audio", "Seedance: generate audio in the output video").option("--no-generate-audio", "Seedance: output silent video").option("--token <symbol>", "Preferred charge token: AMIKO, USDC, USDT, SOL").option("--pay <method>", "Payment method: wallet (twin wallet, default) or credits (Amiko account credits — unified accounts only)", "wallet").option("--raw", "Output raw JSON").option("--yes", "Skip the pre-spend confirmation (required in non-interactive shells)").action(async (prompt, opts) => {
28893
+ create2.command("video <prompt>").description("Generate a video (Create Studio)").option("--model <model>", "Video model: MiniMax-Hailuo-02 (default for prompt-only; T2V+I2V), MiniMax-Hailuo-2.3-Fast (default with --first-frame; I2V only), MiniMax-Hailuo-2.3 (T2V+I2V), veo-3.1[-fast|-lite]-generate-preview (Google; durations clamp to 4/6/8s), grok-imagine-video (xAI), dreamina-seedance-* (BytePlus). ONLY these — kling and other ids are not supported").option("--resolution <res>", "512P, 720P, 768P, 1080P", "768P").option("--seconds <n>", "Clip length: 6 or 10", "6").option("--aspect <ratio>", "Aspect ratio (provider-dependent)").option("--first-frame <url>", "Image-to-video: first frame URL/data URI").option("--last-frame <url>", "First-and-last-frame video: ending frame URL/data URI").option("--reference-image <url>", "Seedance multimodal: reference image URL (repeatable, max 9)", collectOption, []).option("--reference-video <url>", "Seedance multimodal: reference video URL (repeatable, max 3)", collectOption, []).option("--reference-audio <url>", "Seedance multimodal: reference audio URL (repeatable, max 3)", collectOption, []).option("--subject-reference <url>", "MiniMax S2V: subject/character reference image URL").option("--generate-audio", "Seedance: generate audio in the output video").option("--no-generate-audio", "Seedance: output silent video").option("--token <symbol>", "Preferred charge token: AMIKO, USDC, USDT, SOL").option("--pay <method>", "Payment method: credits (Amiko account credits, default) or wallet (twin wallet)", "credits").option("--raw", "Output raw JSON").option("--yes", "Skip the pre-spend confirmation (required in non-interactive shells)").action(async (prompt, opts) => {
28853
28894
  const seconds = Number(opts.seconds);
28854
28895
  if (seconds !== 6 && seconds !== 10) {
28855
28896
  console.error(error("--seconds must be 6 or 10."));
@@ -28911,7 +28952,7 @@ function registerCreateCommand(create2) {
28911
28952
  "speech-2.6-turbo",
28912
28953
  "speech-2.6-hd"
28913
28954
  ]);
28914
- create2.command("tts <text>").description("Generate speech from text (Create Studio)").option("--provider <name>", "TTS provider: minimax | elevenlabs (sets defaults when --model/--voice omitted)").option("--model <model>", `TTS model id (MiniMax: speech-2.8-turbo|hd, speech-2.6-turbo|hd; ElevenLabs: eleven_*)`).option("--voice <voiceId>", "Voice id (MiniMax system e.g. English_expressive_narrator, or a cloned voice_id; ElevenLabs voice hash)").option("--token <symbol>", "Preferred charge token: AMIKO, USDC, USDT, SOL").option("--pay <method>", "Payment method: wallet (twin wallet, default) or credits (Amiko account credits — unified accounts only)", "wallet").option("--raw", "Output raw JSON").option("--yes", "Skip the pre-spend confirmation (required in non-interactive shells)").action(async (text, opts) => {
28955
+ create2.command("tts <text>").description("Generate speech from text (Create Studio)").option("--provider <name>", "TTS provider: minimax | elevenlabs (sets defaults when --model/--voice omitted)").option("--model <model>", `TTS model id (MiniMax: speech-2.8-turbo|hd, speech-2.6-turbo|hd; ElevenLabs: eleven_*)`).option("--voice <voiceId>", "Voice id (MiniMax system e.g. English_expressive_narrator, or a cloned voice_id; ElevenLabs voice hash)").option("--token <symbol>", "Preferred charge token: AMIKO, USDC, USDT, SOL").option("--pay <method>", "Payment method: credits (Amiko account credits, default) or wallet (twin wallet)", "credits").option("--raw", "Output raw JSON").option("--yes", "Skip the pre-spend confirmation (required in non-interactive shells)").action(async (text, opts) => {
28915
28956
  const providerRaw = typeof opts.provider === "string" ? opts.provider.trim().toLowerCase() : "";
28916
28957
  if (providerRaw && providerRaw !== "minimax" && providerRaw !== "elevenlabs") {
28917
28958
  console.error(error("--provider must be minimax or elevenlabs"));
@@ -28953,7 +28994,7 @@ function registerCreateCommand(create2) {
28953
28994
  }
28954
28995
  });
28955
28996
  });
28956
- create2.command("music [prompt]").description("Generate music (Create Studio)").option("--model <model>", "music_v1, music-2.6[-free], music-cover[-free]", "music-2.6").option("--lyrics <lyrics>", "Lyrics (optional)").option("--duration <ms>", "Length in ms").option("--instrumental", "Instrumental (no vocals)").option("--lyrics-optimizer", "Auto-write lyrics from the prompt (music_v1 only; on by default when no --lyrics/--instrumental)").option("--token <symbol>", "Preferred charge token: AMIKO, USDC, USDT, SOL").option("--pay <method>", "Payment method: wallet (twin wallet, default) or credits (Amiko account credits — unified accounts only)", "wallet").option("--raw", "Output raw JSON").option("--yes", "Skip the pre-spend confirmation (required in non-interactive shells)").action(async (prompt, opts) => {
28997
+ create2.command("music [prompt]").description("Generate music (Create Studio)").option("--model <model>", "music_v1, music-2.6[-free], music-cover[-free]", "music-2.6").option("--lyrics <lyrics>", "Lyrics (optional)").option("--duration <ms>", "Length in ms").option("--instrumental", "Instrumental (no vocals)").option("--lyrics-optimizer", "Auto-write lyrics from the prompt (music_v1 only; on by default when no --lyrics/--instrumental)").option("--token <symbol>", "Preferred charge token: AMIKO, USDC, USDT, SOL").option("--pay <method>", "Payment method: credits (Amiko account credits, default) or wallet (twin wallet)", "credits").option("--raw", "Output raw JSON").option("--yes", "Skip the pre-spend confirmation (required in non-interactive shells)").action(async (prompt, opts) => {
28957
28998
  if (!prompt && !opts.lyrics) {
28958
28999
  console.error(error("Provide a prompt or --lyrics."));
28959
29000
  process.exit(1);
@@ -28977,7 +29018,7 @@ function registerCreateCommand(create2) {
28977
29018
  }
28978
29019
  });
28979
29020
  });
28980
- create2.command("sfx <text>").description("Generate a sound effect (Create Studio)").option("--duration <seconds>", "Clip length in seconds").option("--token <symbol>", "Preferred charge token: AMIKO, USDC, USDT, SOL").option("--pay <method>", "Payment method: wallet (twin wallet, default) or credits (Amiko account credits — unified accounts only)", "wallet").option("--raw", "Output raw JSON").option("--yes", "Skip the pre-spend confirmation (required in non-interactive shells)").action(async (text, opts) => {
29021
+ create2.command("sfx <text>").description("Generate a sound effect (Create Studio)").option("--duration <seconds>", "Clip length in seconds").option("--token <symbol>", "Preferred charge token: AMIKO, USDC, USDT, SOL").option("--pay <method>", "Payment method: credits (Amiko account credits, default) or wallet (twin wallet)", "credits").option("--raw", "Output raw JSON").option("--yes", "Skip the pre-spend confirmation (required in non-interactive shells)").action(async (text, opts) => {
28981
29022
  await submitCreateJob({
28982
29023
  mode: "SFX",
28983
29024
  summary: `Create SFX: ${text.slice(0, 80)}${text.length > 80 ? "…" : ""}`,
@@ -32635,12 +32676,15 @@ function registerPostCommand(program2) {
32635
32676
  }
32636
32677
  const data = await amikoWebFetch(auth, "/api/posts", { method: "POST", body });
32637
32678
  spinner?.stop();
32638
- renderOutput(data, (d) => {
32679
+ const postUrl = data.post?.id ? `https://platform.heyamiko.com/post/${data.post.id}` : null;
32680
+ renderOutput(postUrl ? { ...data, post_url: postUrl } : data, (d) => {
32639
32681
  console.log(success("Post published"));
32640
32682
  const post = d.post;
32641
32683
  if (post) {
32642
32684
  if (post.id)
32643
32685
  console.log(label("Post ID", String(post.id)));
32686
+ if (postUrl)
32687
+ console.log(label("URL", postUrl));
32644
32688
  console.log(label("Visibility", visibility));
32645
32689
  }
32646
32690
  }, { json: opts.json });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@heyamiko/amiko-cli",
3
- "version": "0.14.0-beta.15",
3
+ "version": "0.14.0-beta.16",
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
@@ -203,6 +203,8 @@ Workflow: start with `friends matches --limit 20 --json`; narrow with `--dimensi
203
203
 
204
204
  **Attaching an image to a post or comment.** Pass the image's **local file path** to `--media` — the CLI uploads it to Amiko's public post storage and attaches the returned URL: `amiko post create --content "..." --media ./image.webp` (or `amiko post comment --id <postId> --comment "..." --media ./image.webp --twin <id>`). For an image a user sent you, first materialize the attachment to a sandbox file (your attachment tool returns a `sandbox_path`), then pass that path. **Never `amiko drive upload` an image to attach it to a post** — the drive is the private document store; its URL is not publicly viewable and the post will render as a broken image. `--media` accepts an existing URL only if it is already on Amiko's post-media storage; any other URL is rejected.
205
205
 
206
+ **Sharing a post link: copy the printed URL verbatim.** `amiko post create` prints the post's canonical `URL` (`https://platform.heyamiko.com/post/<id>`; also `post_url` in `--json`). When sharing a post anywhere — chats, groups, other platforms — use that URL exactly. **Never compose a post URL yourself from the id**: guessed domains (e.g. `amiko.ai`) are not Amiko and send readers to a parked page.
207
+
206
208
  **Comments authored by a twin always go through review.** Any comment created with `amiko post comment ... --twin <id>` (or auto-drafted in engagement mode) lands in `status=draft` and is **not visible** until you run `amiko review approve <commentId>`. Comments without `--twin` (the owner posting) publish immediately. Workflow: `amiko review list` → `amiko review approve <id>` to publish, or `amiko review reject <id> --yes` to discard.
207
209
 
208
210
  ## Notifications