@heyamiko/amiko-cli 0.12.0-beta.6 → 0.12.0-beta.8

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.12.0-beta.6)
1
+ # @heyamiko/amiko-cli (v0.12.0-beta.7)
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
 
@@ -206,7 +206,7 @@ amiko create media --service video --limit 5
206
206
  - **`amiko create media`** — lists your recent Create Studio generations (URL, type, model, prompt, date). `--service <type>` filters, `--limit <n>` caps (max 50), `--raw` for JSON. Use this once a job id has expired, or just to browse.
207
207
  - **Web:** `https://platform.heyamiko.com/media`
208
208
 
209
- **`--wait`** — if you'd rather block until it finishes and print the asset inline (e.g. an interactive terminal), pass `--wait`. It polls (10 min cap for video, 5 min otherwise) with a `…still generating (Ns)` tick; on timeout it falls back to the job-id + retrieval hint above. `--raw` prints the full job result as JSON either way.
209
+ `create` is always non-blocking — there is no `--wait`. `--raw` prints the submit result (`{ jobId, status, check, eta }`) as JSON.
210
210
 
211
211
  > `amiko markets image` still exists and is unchanged — it's the direct MPP pay-per-call path (pre-pay in AMIKO). Use `amiko create` for the Create Studio experience (async, charge-on-success); use `amiko markets` for raw MPP endpoints.
212
212
 
package/dist/index.js CHANGED
@@ -28589,7 +28589,6 @@ function registerImageCommand(program2) {
28589
28589
  }
28590
28590
 
28591
28591
  // src/commands/create.ts
28592
- var POLL_INTERVAL_MS = 3000;
28593
28592
  var ETA = {
28594
28593
  IMAGE: "~15–60s",
28595
28594
  VIDEO: "~2–9 min",
@@ -28617,7 +28616,7 @@ function printCompleted(final, title) {
28617
28616
  }
28618
28617
  console.log(dim("View in your media space: https://platform.heyamiko.com/media"));
28619
28618
  }
28620
- async function submitAndPoll(opts) {
28619
+ async function submitCreateJob(opts) {
28621
28620
  let auth;
28622
28621
  try {
28623
28622
  auth = requireAuth();
@@ -28644,27 +28643,7 @@ async function submitAndPoll(opts) {
28644
28643
  });
28645
28644
  const isTTY = process.stderr.isTTY;
28646
28645
  const spinner = isTTY ? ora("Submitting…").start() : null;
28647
- let progressTimer = null;
28648
- const started = Date.now();
28649
- const setStatus = (text) => {
28650
- if (spinner)
28651
- spinner.text = text;
28652
- else
28653
- console.error(text);
28654
- };
28655
- const startTicker = () => {
28656
- if (!spinner && !progressTimer) {
28657
- progressTimer = setInterval(() => {
28658
- const elapsed = Math.round((Date.now() - started) / 1000);
28659
- console.error(` …still generating (${elapsed}s elapsed)`);
28660
- }, 3000);
28661
- }
28662
- };
28663
28646
  const stop = () => {
28664
- if (progressTimer) {
28665
- clearInterval(progressTimer);
28666
- progressTimer = null;
28667
- }
28668
28647
  if (spinner)
28669
28648
  spinner.stop();
28670
28649
  };
@@ -28686,68 +28665,28 @@ async function submitAndPoll(opts) {
28686
28665
  console.error(error(e5 instanceof Error ? e5.message : "Submit failed"));
28687
28666
  process.exit(1);
28688
28667
  }
28689
- if (!opts.wait) {
28690
- stop();
28691
- if (opts.raw) {
28692
- console.log(JSON.stringify({
28693
- jobId,
28694
- status: "PENDING",
28695
- check: `amiko create status ${jobId}`,
28696
- eta: ETA[opts.mode]
28697
- }, null, 2));
28698
- return;
28699
- }
28700
- console.log(success(`Submitted — job ${jobId}`));
28701
- console.log(label("Status", "PENDING — generating in the background"));
28702
- console.log(label("Check result", `amiko create status ${jobId}`));
28703
- console.log(dim(`Usually ready in ${ETA[opts.mode]} — charged only on success. (Also: amiko create media)`));
28704
- return;
28705
- }
28706
- setStatus("Generating…");
28707
- startTicker();
28708
- const maxMs = opts.mode === "VIDEO" ? 600000 : 300000;
28709
- let final = null;
28710
- while (Date.now() - started < maxMs) {
28711
- await new Promise((r) => setTimeout(r, POLL_INTERVAL_MS));
28712
- try {
28713
- const p = await amikoWebFetch(auth, `/api/create/jobs/${encodeURIComponent(jobId)}`, { timeoutMs: 15000 });
28714
- if (p.status === "COMPLETED" || p.status === "FAILED") {
28715
- final = p;
28716
- break;
28717
- }
28718
- } catch (e5) {
28719
- const s = statusOf(e5);
28720
- if (s === 401 || s === 404) {
28721
- stop();
28722
- console.error(error(e5 instanceof Error ? e5.message : "Poll failed"));
28723
- process.exit(1);
28724
- }
28725
- }
28726
- }
28727
28668
  stop();
28728
- if (!final) {
28729
- console.error(error("Timed out waiting for the job. It may still be generating — check your media space at https://platform.heyamiko.com/media before retrying."));
28730
- console.log(dim(`Job id: ${jobId}`));
28731
- process.exit(1);
28732
- }
28733
28669
  if (opts.raw) {
28734
- console.log(JSON.stringify(final, null, 2));
28670
+ console.log(JSON.stringify({
28671
+ jobId,
28672
+ status: "PENDING",
28673
+ check: `amiko create status ${jobId}`,
28674
+ eta: ETA[opts.mode]
28675
+ }, null, 2));
28735
28676
  return;
28736
28677
  }
28737
- if (final.status === "FAILED") {
28738
- console.error(error(final.error ?? "Generation failed (you were not charged)."));
28739
- process.exit(1);
28740
- }
28741
- printCompleted(final, `${opts.mode[0]}${opts.mode.slice(1).toLowerCase()} created`);
28678
+ console.log(success(`Submitted — job ${jobId}`));
28679
+ console.log(label("Status", "PENDING — generating in the background"));
28680
+ console.log(label("Check result", `amiko create status ${jobId}`));
28681
+ console.log(dim(`Usually ready in ${ETA[opts.mode]} — charged only on success. (Also: amiko create media)`));
28742
28682
  }
28743
28683
  function registerCreateCommand(create2) {
28744
- create2.command("image <prompt>").description("Generate an image (Create Studio)").option("--model <model>", "Image model", "gpt-image-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("--raw", "Output raw JSON").option("--yes", "Skip the pre-spend confirmation (required in non-interactive shells)").option("--wait", "Block until generation finishes and print the asset (default: return a job id immediately)").action(async (prompt, opts) => {
28745
- await submitAndPoll({
28684
+ create2.command("image <prompt>").description("Generate an image (Create Studio)").option("--model <model>", "Image model", "gpt-image-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("--raw", "Output raw JSON").option("--yes", "Skip the pre-spend confirmation (required in non-interactive shells)").action(async (prompt, opts) => {
28685
+ await submitCreateJob({
28746
28686
  mode: "IMAGE",
28747
28687
  summary: `Create image: ${prompt.slice(0, 80)}${prompt.length > 80 ? "…" : ""}`,
28748
28688
  raw: opts.raw,
28749
28689
  yes: opts.yes,
28750
- wait: opts.wait,
28751
28690
  quoteBody: { mode: "IMAGE", model: opts.model, size: opts.aspect },
28752
28691
  jobBody: {
28753
28692
  mode: "IMAGE",
@@ -28758,18 +28697,17 @@ function registerCreateCommand(create2) {
28758
28697
  }
28759
28698
  });
28760
28699
  });
28761
- create2.command("video <prompt>").description("Generate a video (Create Studio)").option("--model <model>", "Video model", "MiniMax-Hailuo-2.3-Fast").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("--token <symbol>", "Preferred charge token: AMIKO, USDC, USDT, SOL").option("--raw", "Output raw JSON").option("--yes", "Skip the pre-spend confirmation (required in non-interactive shells)").option("--wait", "Block until generation finishes and print the asset (default: return a job id immediately)").action(async (prompt, opts) => {
28700
+ create2.command("video <prompt>").description("Generate a video (Create Studio)").option("--model <model>", "Video model", "MiniMax-Hailuo-2.3-Fast").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("--token <symbol>", "Preferred charge token: AMIKO, USDC, USDT, SOL").option("--raw", "Output raw JSON").option("--yes", "Skip the pre-spend confirmation (required in non-interactive shells)").action(async (prompt, opts) => {
28762
28701
  const seconds = Number(opts.seconds);
28763
28702
  if (seconds !== 6 && seconds !== 10) {
28764
28703
  console.error(error("--seconds must be 6 or 10."));
28765
28704
  process.exit(1);
28766
28705
  }
28767
- await submitAndPoll({
28706
+ await submitCreateJob({
28768
28707
  mode: "VIDEO",
28769
28708
  summary: `Create video: ${prompt.slice(0, 80)}${prompt.length > 80 ? "…" : ""}`,
28770
28709
  raw: opts.raw,
28771
28710
  yes: opts.yes,
28772
- wait: opts.wait,
28773
28711
  quoteBody: {
28774
28712
  mode: "VIDEO",
28775
28713
  model: opts.model,
@@ -28788,13 +28726,12 @@ function registerCreateCommand(create2) {
28788
28726
  }
28789
28727
  });
28790
28728
  });
28791
- create2.command("tts <text>").description("Generate speech from text (Create Studio)").option("--model <model>", "TTS model id", "eleven_multilingual_v2").option("--voice <voiceId>", "Voice id", "21m00Tcm4TlvDq8ikWAM").option("--token <symbol>", "Preferred charge token: AMIKO, USDC, USDT, SOL").option("--raw", "Output raw JSON").option("--yes", "Skip the pre-spend confirmation (required in non-interactive shells)").option("--wait", "Block until generation finishes and print the asset (default: return a job id immediately)").action(async (text, opts) => {
28792
- await submitAndPoll({
28729
+ create2.command("tts <text>").description("Generate speech from text (Create Studio)").option("--model <model>", "TTS model id", "eleven_multilingual_v2").option("--voice <voiceId>", "Voice id", "21m00Tcm4TlvDq8ikWAM").option("--token <symbol>", "Preferred charge token: AMIKO, USDC, USDT, SOL").option("--raw", "Output raw JSON").option("--yes", "Skip the pre-spend confirmation (required in non-interactive shells)").action(async (text, opts) => {
28730
+ await submitCreateJob({
28793
28731
  mode: "TTS",
28794
28732
  summary: `Create speech: ${text.slice(0, 80)}${text.length > 80 ? "…" : ""}`,
28795
28733
  raw: opts.raw,
28796
28734
  yes: opts.yes,
28797
- wait: opts.wait,
28798
28735
  quoteBody: { mode: "TTS", model: opts.model, prompt: text },
28799
28736
  jobBody: {
28800
28737
  mode: "TTS",
@@ -28805,17 +28742,16 @@ function registerCreateCommand(create2) {
28805
28742
  }
28806
28743
  });
28807
28744
  });
28808
- create2.command("music [prompt]").description("Generate music (Create Studio)").option("--model <model>", "music_v1, music-2.6, music-cover", "music-2.6").option("--lyrics <lyrics>", "Lyrics (optional)").option("--duration <ms>", "Length in ms").option("--instrumental", "Instrumental (no vocals)").option("--token <symbol>", "Preferred charge token: AMIKO, USDC, USDT, SOL").option("--raw", "Output raw JSON").option("--yes", "Skip the pre-spend confirmation (required in non-interactive shells)").option("--wait", "Block until generation finishes and print the asset (default: return a job id immediately)").action(async (prompt, opts) => {
28745
+ create2.command("music [prompt]").description("Generate music (Create Studio)").option("--model <model>", "music_v1, music-2.6, music-cover", "music-2.6").option("--lyrics <lyrics>", "Lyrics (optional)").option("--duration <ms>", "Length in ms").option("--instrumental", "Instrumental (no vocals)").option("--token <symbol>", "Preferred charge token: AMIKO, USDC, USDT, SOL").option("--raw", "Output raw JSON").option("--yes", "Skip the pre-spend confirmation (required in non-interactive shells)").action(async (prompt, opts) => {
28809
28746
  if (!prompt && !opts.lyrics) {
28810
28747
  console.error(error("Provide a prompt or --lyrics."));
28811
28748
  process.exit(1);
28812
28749
  }
28813
- await submitAndPoll({
28750
+ await submitCreateJob({
28814
28751
  mode: "MUSIC",
28815
28752
  summary: `Create music: ${(prompt ?? opts.lyrics ?? "").slice(0, 80)}`,
28816
28753
  raw: opts.raw,
28817
28754
  yes: opts.yes,
28818
- wait: opts.wait,
28819
28755
  quoteBody: { mode: "MUSIC", model: opts.model },
28820
28756
  jobBody: {
28821
28757
  mode: "MUSIC",
@@ -28828,13 +28764,12 @@ function registerCreateCommand(create2) {
28828
28764
  }
28829
28765
  });
28830
28766
  });
28831
- 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("--raw", "Output raw JSON").option("--yes", "Skip the pre-spend confirmation (required in non-interactive shells)").option("--wait", "Block until generation finishes and print the asset (default: return a job id immediately)").action(async (text, opts) => {
28832
- await submitAndPoll({
28767
+ 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("--raw", "Output raw JSON").option("--yes", "Skip the pre-spend confirmation (required in non-interactive shells)").action(async (text, opts) => {
28768
+ await submitCreateJob({
28833
28769
  mode: "SFX",
28834
28770
  summary: `Create SFX: ${text.slice(0, 80)}${text.length > 80 ? "…" : ""}`,
28835
28771
  raw: opts.raw,
28836
28772
  yes: opts.yes,
28837
- wait: opts.wait,
28838
28773
  quoteBody: { mode: "SFX" },
28839
28774
  jobBody: {
28840
28775
  mode: "SFX",
@@ -29023,6 +28958,10 @@ function detectMime(buffer, name) {
29023
28958
 
29024
28959
  // src/commands/chat.ts
29025
28960
  var UUID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
28961
+ var CUID_RE = /^c[a-z0-9]{20,}$/i;
28962
+ function looksLikeConversationId(t) {
28963
+ return UUID_RE.test(t) || CUID_RE.test(t);
28964
+ }
29026
28965
  function authOrExit() {
29027
28966
  try {
29028
28967
  return requireAuth();
@@ -29054,7 +28993,7 @@ async function findOrCreateDm(auth, userId) {
29054
28993
  }
29055
28994
  async function resolveConversation(auth, target) {
29056
28995
  const t = target.trim();
29057
- if (UUID_RE.test(t))
28996
+ if (looksLikeConversationId(t))
29058
28997
  return t;
29059
28998
  if (t.startsWith("@")) {
29060
28999
  const handle = t.slice(1);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@heyamiko/amiko-cli",
3
- "version": "0.12.0-beta.6",
3
+ "version": "0.12.0-beta.8",
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
@@ -94,7 +94,7 @@ All paid markets commands auto-select the twin's active Solana wallet (see `--wa
94
94
 
95
95
  ## Create Studio — behavior notes
96
96
 
97
- `amiko create <image|video|tts|music|sfx>` is the CLI half of the platform Create Studio. It generates through Amiko's own authenticated endpoints (not raw MPP), runs **async**, and is **charged on success** from the twin's custodial wallet — a failed or timed-out generation is **never billed**, and there is no pre-pay. **The command returns immediately** with a `jobId` and `status: PENDING` — it does NOT block for the whole generation (so you're not held for 60s–9min). It prints how to check + a rough ETA. **Poll for the result** with `amiko create status <jobId>` (re-query that job, ~24h) — wait roughly: image ~15–60s, video ~2–9min, music ~30–120s, tts/sfx ~5–20s. Or `amiko create media` (list recent generations; `--service`/`--limit`/`--raw`). Result is a permanent Supabase Storage URL. (Pass `--wait` only if you deliberately want the command to block until done.) `--token <AMIKO|USDC|USDT|SOL>` selects the charge token (default auto, AMIKO-first). Prefer `create` over `markets image` for media generation — it doesn't lose money on timeouts. `markets image` remains the raw MPP pre-pay path.
97
+ `amiko create <image|video|tts|music|sfx>` is the CLI half of the platform Create Studio. It generates through Amiko's own authenticated endpoints (not raw MPP), runs **async**, and is **charged on success** from the twin's custodial wallet — a failed or timed-out generation is **never billed**, and there is no pre-pay. **The command returns immediately** with a `jobId` and `status: PENDING` — it does NOT block for the whole generation (so you're not held for 60s–9min). It prints how to check + a rough ETA. **Do NOT sit in a tight polling loop** (it burns turns/tokens). After submitting, **tell the user roughly how long to wait and stop** — image ~15–60s, video ~2–9min, music ~30–120s, tts/sfx ~5–20s (e.g. "your video's generating — check back in a few minutes"). Then retrieve it **once** later — when the user next asks, or after the ETA — with `amiko create status <jobId>` (re-query that job, ~24h) or `amiko create media` (list recent generations; `--service`/`--limit`/`--raw`). Result is a permanent Supabase Storage URL. **Do NOT use `--wait`** — there's no such option; `create` is always non-blocking, so submit then check later with `amiko create status <jobId>`. `--token <AMIKO|USDC|USDT|SOL>` selects the charge token (default auto, AMIKO-first). Prefer `create` over `markets image` for media generation — it doesn't lose money on timeouts. `markets image` remains the raw MPP pre-pay path.
98
98
 
99
99
  ## Chat — behavior notes
100
100