@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 +10 -2
- package/dist/index.js +57 -13
- package/package.json +1 -1
- package/skills/SKILL.md +2 -0
package/README.md
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
# @heyamiko/amiko-cli (v0.14.0-beta.
|
|
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
|
-
|
|
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
|
-
|
|
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 ?? "
|
|
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 &&
|
|
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:
|
|
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:
|
|
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:
|
|
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:
|
|
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:
|
|
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
|
-
|
|
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
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
|